diff options
Diffstat (limited to 'drivers')
875 files changed, 62003 insertions, 41605 deletions
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index feab124d8e05..cbfc81579c9a 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -194,7 +194,7 @@ int acpi_bus_set_power(acpi_handle handle, int state) if (!device->flags.power_manageable) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n", - device->dev.kobj.name)); + kobject_name(&device->dev.kobj))); return -ENODEV; } /* diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 1e8287b4f40c..1f6fb38de017 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -276,21 +276,12 @@ static void acpi_timer_check_state(int state, struct acpi_processor *pr, static void acpi_propagate_timer_broadcast(struct acpi_processor *pr) { -#ifdef CONFIG_GENERIC_CLOCKEVENTS unsigned long reason; reason = pr->power.timer_broadcast_on_state < INT_MAX ? CLOCK_EVT_NOTIFY_BROADCAST_ON : CLOCK_EVT_NOTIFY_BROADCAST_OFF; clockevents_notify(reason, &pr->id); -#else - cpumask_t mask = cpumask_of_cpu(pr->id); - - if (pr->power.timer_broadcast_on_state < INT_MAX) - on_each_cpu(switch_APIC_timer_to_ipi, &mask, 1, 1); - else - on_each_cpu(switch_ipi_to_APIC_timer, &mask, 1, 1); -#endif } /* Power(C) State timer broadcast control */ @@ -298,8 +289,6 @@ static void acpi_state_timer_broadcast(struct acpi_processor *pr, struct acpi_processor_cx *cx, int broadcast) { -#ifdef CONFIG_GENERIC_CLOCKEVENTS - int state = cx - pr->power.states; if (state >= pr->power.timer_broadcast_on_state) { @@ -309,7 +298,6 @@ static void acpi_state_timer_broadcast(struct acpi_processor *pr, CLOCK_EVT_NOTIFY_BROADCAST_EXIT; clockevents_notify(reason, &pr->id); } -#endif } #else diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 64620d668742..5b4d462117cf 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -319,16 +319,18 @@ static int acpi_bus_match(struct device *dev, struct device_driver *drv) return !acpi_match_device_ids(acpi_dev, acpi_drv->ids); } -static int acpi_device_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env) { struct acpi_device *acpi_dev = to_acpi_device(dev); + int len; - strcpy(buffer, "MODALIAS="); - if (create_modalias(acpi_dev, buffer + 9, buffer_size - 9) > 0) { - envp[0] = buffer; - envp[1] = NULL; - } + if (add_uevent_var(env, "MODALIAS=")) + return -ENOMEM; + len = create_modalias(acpi_dev, &env->buf[env->buflen - 1], + sizeof(env->buf) - env->buflen); + if (len >= (sizeof(env->buf) - env->buflen)) + return -ENOMEM; + env->buflen += len; return 0; } diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c index 13369b45563f..a736ef7bdee4 100644 --- a/drivers/acpi/toshiba_acpi.c +++ b/drivers/acpi/toshiba_acpi.c @@ -362,7 +362,7 @@ static unsigned long write_video(const char *buffer, unsigned long count) int crt_out = -1; int tv_out = -1; u32 hci_result; - int video_out; + u32 video_out; /* scan expression. Multiple expressions may be delimited with ; * diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index d05891f16282..b8a2095cb5ee 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -316,7 +316,7 @@ static int acpi_video_output_get(struct output_device *od) { unsigned long state; struct acpi_video_device *vd = - (struct acpi_video_device *)class_get_devdata(&od->class_dev); + (struct acpi_video_device *)dev_get_drvdata(&od->dev); acpi_video_device_get_state(vd, &state); return (int)state; } @@ -325,7 +325,7 @@ static int acpi_video_output_set(struct output_device *od) { unsigned long state = od->request_state; struct acpi_video_device *vd= - (struct acpi_video_device *)class_get_devdata(&od->class_dev); + (struct acpi_video_device *)dev_get_drvdata(&od->dev); return acpi_video_device_set_state(vd, state); } diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index 268e301775fc..6b94fb7be5f2 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -44,15 +44,12 @@ static int amba_match(struct device *dev, struct device_driver *drv) } #ifdef CONFIG_HOTPLUG -static int amba_uevent(struct device *dev, char **envp, int nr_env, char *buf, int bufsz) +static int amba_uevent(struct device *dev, struct kobj_uevent_env *env) { struct amba_device *pcdev = to_amba_device(dev); - int retval = 0, i = 0, len = 0; + int retval = 0; - retval = add_uevent_var(envp, nr_env, &i, - buf, bufsz, &len, - "AMBA_ID=%08x", pcdev->periphid); - envp[i] = NULL; + retval = add_uevent_var(env, "AMBA_ID=%08x", pcdev->periphid); return retval; } #else diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index d8046a113c37..33f5eb038773 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -173,6 +173,15 @@ config SATA_INIC162X help This option enables support for Initio 162x Serial ATA. +config PATA_ACPI + tristate "ACPI firmware driver for PATA" + depends on ATA_ACPI + help + This option enables an ACPI method driver which drives + motherboard PATA controller interfaces through the ACPI + firmware in the BIOS. This driver can sometimes handle + otherwise unsupported hardware. + config PATA_ALI tristate "ALi PATA support (Experimental)" depends on PCI && EXPERIMENTAL @@ -192,16 +201,25 @@ config PATA_AMD If unsure, say N. config PATA_ARTOP - tristate "ARTOP 6210/6260 PATA support (Experimental)" - depends on PCI && EXPERIMENTAL + tristate "ARTOP 6210/6260 PATA support" + depends on PCI help This option enables support for ARTOP PATA controllers. If unsure, say N. +config PATA_AT32 + tristate "Atmel AVR32 PATA support (Experimental)" + depends on AVR32 && PLATFORM_AT32AP && EXPERIMENTAL + help + This option enables support for the IDE devices on the + Atmel AT32AP platform. + + If unsure, say N. + config PATA_ATIIXP - tristate "ATI PATA support (Experimental)" - depends on PCI && EXPERIMENTAL + tristate "ATI PATA support" + depends on PCI help This option enables support for the ATI ATA interfaces found on the many ATI chipsets. @@ -219,8 +237,8 @@ config PATA_CMD640_PCI If unsure, say N. config PATA_CMD64X - tristate "CMD64x PATA support (Very Experimental)" - depends on PCI&& EXPERIMENTAL + tristate "CMD64x PATA support" + depends on PCI help This option enables support for the CMD64x series chips except for the CMD640. @@ -254,6 +272,15 @@ config PATA_CS5535 If unsure, say N. +config PATA_CS5536 + tristate "CS5536 PATA support (Experimental)" + depends on PCI && X86 && !X86_64 && EXPERIMENTAL + help + This option enables support for the AMD CS5536 + companion chip used with the Geode LX processor family. + + If unsure, say N. + config PATA_CYPRESS tristate "Cypress CY82C693 PATA support (Very Experimental)" depends on PCI && EXPERIMENTAL @@ -282,8 +309,8 @@ config ATA_GENERIC If unsure, say N. config PATA_HPT366 - tristate "HPT 366/368 PATA support (Experimental)" - depends on PCI && EXPERIMENTAL + tristate "HPT 366/368 PATA support" + depends on PCI help This option enables support for the HPT 366 and 368 PATA controllers via the new ATA layer. @@ -432,6 +459,15 @@ config PATA_NS87410 If unsure, say N. +config PATA_NS87415 + tristate "Nat Semi NS87415 PATA support (Experimental)" + depends on PCI && EXPERIMENTAL + help + This option enables support for the National Semiconductor + NS87415 PCI-IDE controller. + + If unsure, say N. + config PATA_OPTI tristate "OPTI621/6215 PATA support (Very Experimental)" depends on PCI && EXPERIMENTAL @@ -596,4 +632,20 @@ config PATA_SCC If unsure, say N. +config PATA_BF54X + tristate "Blackfin 54x ATAPI support" + depends on BF542 || BF548 || BF549 + help + This option enables support for the built-in ATAPI controller on + Blackfin 54x family chips. + + If unsure, say N. + +config PATA_BF54X_DMA + bool "DMA mode" + depends on PATA_BF54X + default y + help + Enable DMA mode for Blackfin ATAPI controller. + endif # ATA diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 8149c68ac2c7..6bdc307649e6 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -21,12 +21,14 @@ obj-$(CONFIG_PDC_ADMA) += pdc_adma.o obj-$(CONFIG_PATA_ALI) += pata_ali.o obj-$(CONFIG_PATA_AMD) += pata_amd.o obj-$(CONFIG_PATA_ARTOP) += pata_artop.o +obj-$(CONFIG_PATA_AT32) += pata_at32.o obj-$(CONFIG_PATA_ATIIXP) += pata_atiixp.o obj-$(CONFIG_PATA_CMD640_PCI) += pata_cmd640.o obj-$(CONFIG_PATA_CMD64X) += pata_cmd64x.o obj-$(CONFIG_PATA_CS5520) += pata_cs5520.o obj-$(CONFIG_PATA_CS5530) += pata_cs5530.o obj-$(CONFIG_PATA_CS5535) += pata_cs5535.o +obj-$(CONFIG_PATA_CS5536) += pata_cs5536.o obj-$(CONFIG_PATA_CYPRESS) += pata_cypress.o obj-$(CONFIG_PATA_EFAR) += pata_efar.o obj-$(CONFIG_PATA_HPT366) += pata_hpt366.o @@ -39,6 +41,7 @@ obj-$(CONFIG_PATA_IT8213) += pata_it8213.o obj-$(CONFIG_PATA_JMICRON) += pata_jmicron.o obj-$(CONFIG_PATA_NETCELL) += pata_netcell.o obj-$(CONFIG_PATA_NS87410) += pata_ns87410.o +obj-$(CONFIG_PATA_NS87415) += pata_ns87415.o obj-$(CONFIG_PATA_OPTI) += pata_opti.o obj-$(CONFIG_PATA_OPTIDMA) += pata_optidma.o obj-$(CONFIG_PATA_MPC52xx) += pata_mpc52xx.o @@ -61,12 +64,16 @@ 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_BF54X) += pata_bf54x.o obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o obj-$(CONFIG_PATA_ICSIDE) += pata_icside.o +# Should be last but two libata driver +obj-$(CONFIG_PATA_ACPI) += pata_acpi.o # Should be last but one libata driver obj-$(CONFIG_ATA_GENERIC) += ata_generic.o # Should be last libata driver obj-$(CONFIG_PATA_LEGACY) += pata_legacy.o -libata-objs := libata-core.o libata-scsi.o libata-sff.o libata-eh.o +libata-objs := libata-core.o libata-scsi.o libata-sff.o libata-eh.o \ + libata-pmp.o libata-$(CONFIG_ATA_ACPI) += libata-acpi.o diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index c16820325d7b..10bc3f64c453 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.3" +#define DRV_VERSION "3.0" enum { @@ -77,11 +77,10 @@ enum { RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */ board_ahci = 0, - board_ahci_pi = 1, - board_ahci_vt8251 = 2, - board_ahci_ign_iferr = 3, - board_ahci_sb600 = 4, - board_ahci_mv = 5, + board_ahci_vt8251 = 1, + board_ahci_ign_iferr = 2, + board_ahci_sb600 = 3, + board_ahci_mv = 4, /* global controller registers */ HOST_CAP = 0x00, /* host capabilities */ @@ -97,6 +96,7 @@ enum { /* HOST_CAP bits */ HOST_CAP_SSC = (1 << 14), /* Slumber capable */ + HOST_CAP_PMP = (1 << 17), /* Port Multiplier support */ HOST_CAP_CLO = (1 << 24), /* Command List Override support */ HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */ HOST_CAP_SNTF = (1 << 29), /* SNotification register */ @@ -144,7 +144,8 @@ enum { PORT_IRQ_IF_ERR | PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY | - PORT_IRQ_UNK_FIS, + PORT_IRQ_UNK_FIS | + PORT_IRQ_BAD_PMP, PORT_IRQ_ERROR = PORT_IRQ_FREEZE | PORT_IRQ_TF_ERR | PORT_IRQ_HBUS_DATA_ERR, @@ -154,6 +155,7 @@ enum { /* PORT_CMD bits */ PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */ + PORT_CMD_PMP = (1 << 17), /* PMP attached */ PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */ PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */ PORT_CMD_FIS_RX = (1 << 4), /* Enable FIS receive DMA engine */ @@ -167,19 +169,22 @@ enum { PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */ PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */ + /* hpriv->flags bits */ + AHCI_HFLAG_NO_NCQ = (1 << 0), + AHCI_HFLAG_IGN_IRQ_IF_ERR = (1 << 1), /* ignore IRQ_IF_ERR */ + AHCI_HFLAG_IGN_SERR_INTERNAL = (1 << 2), /* ignore SERR_INTERNAL */ + AHCI_HFLAG_32BIT_ONLY = (1 << 3), /* force 32bit */ + AHCI_HFLAG_MV_PATA = (1 << 4), /* PATA port */ + AHCI_HFLAG_NO_MSI = (1 << 5), /* no PCI MSI */ + AHCI_HFLAG_NO_PMP = (1 << 6), /* no PMP */ + /* ap->flags bits */ - AHCI_FLAG_NO_NCQ = (1 << 24), - AHCI_FLAG_IGN_IRQ_IF_ERR = (1 << 25), /* ignore IRQ_IF_ERR */ - AHCI_FLAG_HONOR_PI = (1 << 26), /* honor PORTS_IMPL */ - AHCI_FLAG_IGN_SERR_INTERNAL = (1 << 27), /* ignore SERR_INTERNAL */ - AHCI_FLAG_32BIT_ONLY = (1 << 28), /* force 32bit */ - AHCI_FLAG_MV_PATA = (1 << 29), /* PATA port */ - AHCI_FLAG_NO_MSI = (1 << 30), /* no PCI MSI */ + AHCI_FLAG_NO_HOTPLUG = (1 << 24), /* ignore PxSERR.DIAG.N */ AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | - ATA_FLAG_SKIP_D2H_BSY | - ATA_FLAG_ACPI_SATA, + ATA_FLAG_ACPI_SATA | ATA_FLAG_AN, + AHCI_LFLAG_COMMON = ATA_LFLAG_SKIP_D2H_BSY, }; struct ahci_cmd_hdr { @@ -198,6 +203,7 @@ struct ahci_sg { }; struct ahci_host_priv { + unsigned int flags; /* AHCI_HFLAG_* */ u32 cap; /* cap to use */ u32 port_map; /* port map to use */ u32 saved_cap; /* saved initial cap */ @@ -205,6 +211,7 @@ struct ahci_host_priv { }; struct ahci_port_priv { + struct ata_link *active_link; struct ahci_cmd_hdr *cmd_slot; dma_addr_t cmd_slot_dma; void *cmd_tbl; @@ -215,6 +222,7 @@ struct ahci_port_priv { unsigned int ncq_saw_d2h:1; unsigned int ncq_saw_dmas:1; unsigned int ncq_saw_sdb:1; + u32 intr_mask; /* interrupts to enable */ }; static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); @@ -229,6 +237,8 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc); static u8 ahci_check_status(struct ata_port *ap); static void ahci_freeze(struct ata_port *ap); static void ahci_thaw(struct ata_port *ap); +static void ahci_pmp_attach(struct ata_port *ap); +static void ahci_pmp_detach(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); @@ -262,20 +272,17 @@ static struct scsi_host_template ahci_sht = { }; static const struct ata_port_operations ahci_ops = { - .port_disable = ata_port_disable, - .check_status = ahci_check_status, .check_altstatus = ahci_check_status, .dev_select = ata_noop_dev_select, .tf_read = ahci_tf_read, + .qc_defer = sata_pmp_qc_defer_cmd_switch, .qc_prep = ahci_qc_prep, .qc_issue = ahci_qc_issue, .irq_clear = ahci_irq_clear, - .irq_on = ata_dummy_irq_on, - .irq_ack = ata_dummy_irq_ack, .scr_read = ahci_scr_read, .scr_write = ahci_scr_write, @@ -286,6 +293,9 @@ static const struct ata_port_operations ahci_ops = { .error_handler = ahci_error_handler, .post_internal_cmd = ahci_post_internal_cmd, + .pmp_attach = ahci_pmp_attach, + .pmp_detach = ahci_pmp_detach, + #ifdef CONFIG_PM .port_suspend = ahci_port_suspend, .port_resume = ahci_port_resume, @@ -296,20 +306,17 @@ static const struct ata_port_operations ahci_ops = { }; static const struct ata_port_operations ahci_vt8251_ops = { - .port_disable = ata_port_disable, - .check_status = ahci_check_status, .check_altstatus = ahci_check_status, .dev_select = ata_noop_dev_select, .tf_read = ahci_tf_read, + .qc_defer = sata_pmp_qc_defer_cmd_switch, .qc_prep = ahci_qc_prep, .qc_issue = ahci_qc_issue, .irq_clear = ahci_irq_clear, - .irq_on = ata_dummy_irq_on, - .irq_ack = ata_dummy_irq_ack, .scr_read = ahci_scr_read, .scr_write = ahci_scr_write, @@ -320,6 +327,9 @@ static const struct ata_port_operations ahci_vt8251_ops = { .error_handler = ahci_vt8251_error_handler, .post_internal_cmd = ahci_post_internal_cmd, + .pmp_attach = ahci_pmp_attach, + .pmp_detach = ahci_pmp_detach, + #ifdef CONFIG_PM .port_suspend = ahci_port_suspend, .port_resume = ahci_port_resume, @@ -329,53 +339,52 @@ static const struct ata_port_operations ahci_vt8251_ops = { .port_stop = ahci_port_stop, }; +#define AHCI_HFLAGS(flags) .private_data = (void *)(flags) + static const struct ata_port_info ahci_port_info[] = { /* board_ahci */ { .flags = AHCI_FLAG_COMMON, - .pio_mask = 0x1f, /* pio0-4 */ - .udma_mask = ATA_UDMA6, - .port_ops = &ahci_ops, - }, - /* board_ahci_pi */ - { - .flags = AHCI_FLAG_COMMON | AHCI_FLAG_HONOR_PI, + .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, }, /* board_ahci_vt8251 */ { - .flags = AHCI_FLAG_COMMON | ATA_FLAG_HRST_TO_RESUME | - AHCI_FLAG_NO_NCQ, + AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP), + .flags = AHCI_FLAG_COMMON, + .link_flags = AHCI_LFLAG_COMMON | ATA_LFLAG_HRST_TO_RESUME, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &ahci_vt8251_ops, }, /* board_ahci_ign_iferr */ { - .flags = AHCI_FLAG_COMMON | AHCI_FLAG_IGN_IRQ_IF_ERR, + AHCI_HFLAGS (AHCI_HFLAG_IGN_IRQ_IF_ERR), + .flags = AHCI_FLAG_COMMON, + .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, }, /* board_ahci_sb600 */ { - .flags = AHCI_FLAG_COMMON | - AHCI_FLAG_IGN_SERR_INTERNAL | - AHCI_FLAG_32BIT_ONLY, + AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL | + AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_PMP), + .flags = AHCI_FLAG_COMMON, + .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, }, /* board_ahci_mv */ { - .sht = &ahci_sht, + AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI | + AHCI_HFLAG_MV_PATA), .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | - ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_HONOR_PI | - AHCI_FLAG_NO_NCQ | AHCI_FLAG_NO_MSI | - AHCI_FLAG_MV_PATA, + ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA, + .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, @@ -394,23 +403,25 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */ { PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */ { PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */ - { PCI_VDEVICE(INTEL, 0x2821), board_ahci_pi }, /* ICH8 */ - { PCI_VDEVICE(INTEL, 0x2822), board_ahci_pi }, /* ICH8 */ - { PCI_VDEVICE(INTEL, 0x2824), board_ahci_pi }, /* ICH8 */ - { PCI_VDEVICE(INTEL, 0x2829), board_ahci_pi }, /* ICH8M */ - { PCI_VDEVICE(INTEL, 0x282a), board_ahci_pi }, /* ICH8M */ - { PCI_VDEVICE(INTEL, 0x2922), board_ahci_pi }, /* ICH9 */ - { PCI_VDEVICE(INTEL, 0x2923), board_ahci_pi }, /* ICH9 */ - { PCI_VDEVICE(INTEL, 0x2924), board_ahci_pi }, /* ICH9 */ - { PCI_VDEVICE(INTEL, 0x2925), board_ahci_pi }, /* ICH9 */ - { PCI_VDEVICE(INTEL, 0x2927), board_ahci_pi }, /* ICH9 */ - { 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 */ + { PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */ + { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */ + { PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */ + { PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */ + { PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */ + { PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */ + { PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */ + { PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */ + { PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */ + { PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */ + { PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x292c), board_ahci }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */ + { PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */ + { PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */ /* 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, @@ -474,6 +485,14 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci }, /* MCP77 */ { PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci }, /* MCP77 */ { PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci }, /* MCP77 */ + { PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci }, /* MCP79 */ + { PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci }, /* MCP79 */ + { PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci }, /* MCP79 */ + { PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci }, /* MCP79 */ + { PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci }, /* MCP79 */ + { PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci }, /* MCP79 */ + { PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci }, /* MCP79 */ + { PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci }, /* MCP79 */ /* SiS */ { PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */ @@ -524,7 +543,6 @@ static inline void __iomem *ahci_port_base(struct ata_port *ap) /** * ahci_save_initial_config - Save and fixup initial config values * @pdev: target PCI device - * @pi: associated ATA port info * @hpriv: host private area to store config values * * Some registers containing configuration info might be setup by @@ -538,7 +556,6 @@ static inline void __iomem *ahci_port_base(struct ata_port *ap) * None. */ static void ahci_save_initial_config(struct pci_dev *pdev, - const struct ata_port_info *pi, struct ahci_host_priv *hpriv) { void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR]; @@ -552,26 +569,22 @@ static void ahci_save_initial_config(struct pci_dev *pdev, hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL); /* some chips have errata preventing 64bit use */ - if ((cap & HOST_CAP_64) && (pi->flags & AHCI_FLAG_32BIT_ONLY)) { + if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) { dev_printk(KERN_INFO, &pdev->dev, "controller can't do 64bit DMA, forcing 32bit\n"); cap &= ~HOST_CAP_64; } - if ((cap & HOST_CAP_NCQ) && (pi->flags & AHCI_FLAG_NO_NCQ)) { + if ((cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_NO_NCQ)) { dev_printk(KERN_INFO, &pdev->dev, "controller can't do NCQ, turning off CAP_NCQ\n"); cap &= ~HOST_CAP_NCQ; } - /* fixup zero port_map */ - if (!port_map) { - port_map = (1 << ahci_nr_ports(cap)) - 1; - dev_printk(KERN_WARNING, &pdev->dev, - "PORTS_IMPL is zero, forcing 0x%x\n", port_map); - - /* write the fixed up value to the PI register */ - hpriv->saved_port_map = port_map; + if ((cap && HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) { + dev_printk(KERN_INFO, &pdev->dev, + "controller can't do PMP, turning off CAP_PMP\n"); + cap &= ~HOST_CAP_PMP; } /* @@ -579,7 +592,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev, * is asserted through the standard AHCI port * presence register, as bit 4 (counting from 0) */ - if (pi->flags & AHCI_FLAG_MV_PATA) { + if (hpriv->flags & AHCI_HFLAG_MV_PATA) { dev_printk(KERN_ERR, &pdev->dev, "MV_AHCI HACK: port_map %x -> %x\n", hpriv->port_map, @@ -589,7 +602,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev, } /* cross check port_map and cap.n_ports */ - if (pi->flags & AHCI_FLAG_HONOR_PI) { + if (port_map) { u32 tmp_port_map = port_map; int n_ports = ahci_nr_ports(cap); @@ -600,17 +613,26 @@ static void ahci_save_initial_config(struct pci_dev *pdev, } } - /* Whine if inconsistent. No need to update cap. - * port_map is used to determine number of ports. + /* If n_ports and port_map are inconsistent, whine and + * clear port_map and let it be generated from n_ports. */ - if (n_ports || tmp_port_map) + if (n_ports || tmp_port_map) { dev_printk(KERN_WARNING, &pdev->dev, "nr_ports (%u) and implemented port map " - "(0x%x) don't match\n", + "(0x%x) don't match, using nr_ports\n", ahci_nr_ports(cap), port_map); - } else { - /* fabricate port_map from cap.nr_ports */ + port_map = 0; + } + } + + /* fabricate port_map from cap.nr_ports */ + if (!port_map) { port_map = (1 << ahci_nr_ports(cap)) - 1; + dev_printk(KERN_WARNING, &pdev->dev, + "forcing PORTS_IMPL to 0x%x\n", port_map); + + /* write the fixed up value to the PI register */ + hpriv->saved_port_map = port_map; } /* record values to use during operation */ @@ -836,8 +858,14 @@ static int ahci_reset_controller(struct ata_host *host) void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; u32 tmp; - /* global controller reset */ + /* we must be in AHCI mode, before using anything + * AHCI-specific, such as HOST_RESET. + */ tmp = readl(mmio + HOST_CTL); + if (!(tmp & HOST_AHCI_EN)) + writel(tmp | HOST_AHCI_EN, mmio + HOST_CTL); + + /* global controller reset */ if ((tmp & HOST_RESET) == 0) { writel(tmp | HOST_RESET, mmio + HOST_CTL); readl(mmio + HOST_CTL); /* flush */ @@ -904,13 +932,14 @@ static void ahci_port_init(struct pci_dev *pdev, struct ata_port *ap, static void ahci_init_controller(struct ata_host *host) { + struct ahci_host_priv *hpriv = host->private_data; struct pci_dev *pdev = to_pci_dev(host->dev); void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; int i; void __iomem *port_mmio; u32 tmp; - if (host->ports[0]->flags & AHCI_FLAG_MV_PATA) { + if (hpriv->flags & AHCI_HFLAG_MV_PATA) { port_mmio = __ahci_port_base(host, 4); writel(0, port_mmio + PORT_IRQ_MASK); @@ -1042,9 +1071,10 @@ static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp, return 0; } -static int ahci_do_softreset(struct ata_port *ap, unsigned int *class, +static int ahci_do_softreset(struct ata_link *link, unsigned int *class, int pmp, unsigned long deadline) { + struct ata_port *ap = link->ap; const char *reason = NULL; unsigned long now, msecs; struct ata_taskfile tf; @@ -1052,7 +1082,7 @@ static int ahci_do_softreset(struct ata_port *ap, unsigned int *class, DPRINTK("ENTER\n"); - if (ata_port_offline(ap)) { + if (ata_link_offline(link)) { DPRINTK("PHY reports no device\n"); *class = ATA_DEV_NONE; return 0; @@ -1061,10 +1091,10 @@ static int ahci_do_softreset(struct ata_port *ap, unsigned int *class, /* prepare for SRST (AHCI-1.1 10.4.1) */ rc = ahci_kick_engine(ap, 1); if (rc) - ata_port_printk(ap, KERN_WARNING, + ata_link_printk(link, KERN_WARNING, "failed to reset engine (errno=%d)", rc); - ata_tf_init(ap->device, &tf); + ata_tf_init(link->device, &tf); /* issue the first D2H Register FIS */ msecs = 0; @@ -1109,19 +1139,25 @@ static int ahci_do_softreset(struct ata_port *ap, unsigned int *class, return 0; fail: - ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason); + ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason); return rc; } -static int ahci_softreset(struct ata_port *ap, unsigned int *class, +static int ahci_softreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { - return ahci_do_softreset(ap, class, 0, deadline); + int pmp = 0; + + if (link->ap->flags & ATA_FLAG_PMP) + pmp = SATA_PMP_CTRL_PORT; + + return ahci_do_softreset(link, class, pmp, deadline); } -static int ahci_hardreset(struct ata_port *ap, unsigned int *class, +static int ahci_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { + struct ata_port *ap = link->ap; struct ahci_port_priv *pp = ap->private_data; u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; struct ata_taskfile tf; @@ -1132,26 +1168,27 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class, ahci_stop_engine(ap); /* clear D2H reception area to properly wait for D2H FIS */ - ata_tf_init(ap->device, &tf); + ata_tf_init(link->device, &tf); tf.command = 0x80; ata_tf_to_fis(&tf, 0, 0, d2h_fis); - rc = sata_std_hardreset(ap, class, deadline); + rc = sata_std_hardreset(link, class, deadline); ahci_start_engine(ap); - if (rc == 0 && ata_port_online(ap)) + if (rc == 0 && ata_link_online(link)) *class = ahci_dev_classify(ap); - if (*class == ATA_DEV_UNKNOWN) + if (rc != -EAGAIN && *class == ATA_DEV_UNKNOWN) *class = ATA_DEV_NONE; DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); return rc; } -static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class, +static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { + struct ata_port *ap = link->ap; u32 serror; int rc; @@ -1159,7 +1196,7 @@ static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class, ahci_stop_engine(ap); - rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->eh_context), + rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context), deadline); /* vt8251 needs SError cleared for the port to operate */ @@ -1176,12 +1213,13 @@ static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class, return rc ?: -EAGAIN; } -static void ahci_postreset(struct ata_port *ap, unsigned int *class) +static void ahci_postreset(struct ata_link *link, unsigned int *class) { + struct ata_port *ap = link->ap; void __iomem *port_mmio = ahci_port_base(ap); u32 new_tmp, tmp; - ata_std_postreset(ap, class); + ata_std_postreset(link, class); /* Make sure port's ATAPI bit is set appropriately */ new_tmp = tmp = readl(port_mmio + PORT_CMD); @@ -1195,6 +1233,12 @@ static void ahci_postreset(struct ata_port *ap, unsigned int *class) } } +static int ahci_pmp_softreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + return ahci_do_softreset(link, class, link->pmp, deadline); +} + static u8 ahci_check_status(struct ata_port *ap) { void __iomem *mmio = ap->ioaddr.cmd_addr; @@ -1253,7 +1297,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc) */ cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ; - ata_tf_to_fis(&qc->tf, 0, 1, cmd_tbl); + ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl); if (is_atapi) { memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32); memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len); @@ -1266,7 +1310,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc) /* * Fill in command slot information. */ - opts = cmd_fis_len | n_elem << 16; + opts = cmd_fis_len | n_elem << 16 | (qc->dev->link->pmp << 12); if (qc->tf.flags & ATA_TFLAG_WRITE) opts |= AHCI_CMD_WRITE; if (is_atapi) @@ -1277,66 +1321,87 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc) static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) { + struct ahci_host_priv *hpriv = ap->host->private_data; struct ahci_port_priv *pp = ap->private_data; - struct ata_eh_info *ehi = &ap->eh_info; - unsigned int err_mask = 0, action = 0; - struct ata_queued_cmd *qc; + struct ata_eh_info *host_ehi = &ap->link.eh_info; + struct ata_link *link = NULL; + struct ata_queued_cmd *active_qc; + struct ata_eh_info *active_ehi; u32 serror; - ata_ehi_clear_desc(ehi); + /* determine active link */ + ata_port_for_each_link(link, ap) + if (ata_link_active(link)) + break; + if (!link) + link = &ap->link; + + active_qc = ata_qc_from_tag(ap, link->active_tag); + active_ehi = &link->eh_info; + + /* record irq stat */ + ata_ehi_clear_desc(host_ehi); + ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat); /* AHCI needs SError cleared; otherwise, it might lock up */ ahci_scr_read(ap, SCR_ERROR, &serror); ahci_scr_write(ap, SCR_ERROR, serror); - - /* analyze @irq_stat */ - ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat); + host_ehi->serror |= serror; /* some controllers set IRQ_IF_ERR on device errors, ignore it */ - if (ap->flags & AHCI_FLAG_IGN_IRQ_IF_ERR) + if (hpriv->flags & AHCI_HFLAG_IGN_IRQ_IF_ERR) irq_stat &= ~PORT_IRQ_IF_ERR; if (irq_stat & PORT_IRQ_TF_ERR) { - err_mask |= AC_ERR_DEV; - if (ap->flags & AHCI_FLAG_IGN_SERR_INTERNAL) - serror &= ~SERR_INTERNAL; + /* If qc is active, charge it; otherwise, the active + * link. There's no active qc on NCQ errors. It will + * be determined by EH by reading log page 10h. + */ + if (active_qc) + active_qc->err_mask |= AC_ERR_DEV; + else + active_ehi->err_mask |= AC_ERR_DEV; + + if (hpriv->flags & AHCI_HFLAG_IGN_SERR_INTERNAL) + host_ehi->serror &= ~SERR_INTERNAL; + } + + if (irq_stat & PORT_IRQ_UNK_FIS) { + u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK); + + active_ehi->err_mask |= AC_ERR_HSM; + active_ehi->action |= ATA_EH_SOFTRESET; + ata_ehi_push_desc(active_ehi, + "unknown FIS %08x %08x %08x %08x" , + unk[0], unk[1], unk[2], unk[3]); + } + + if (ap->nr_pmp_links && (irq_stat & PORT_IRQ_BAD_PMP)) { + active_ehi->err_mask |= AC_ERR_HSM; + active_ehi->action |= ATA_EH_SOFTRESET; + ata_ehi_push_desc(active_ehi, "incorrect PMP"); } if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) { - err_mask |= AC_ERR_HOST_BUS; - action |= ATA_EH_SOFTRESET; + host_ehi->err_mask |= AC_ERR_HOST_BUS; + host_ehi->action |= ATA_EH_SOFTRESET; + ata_ehi_push_desc(host_ehi, "host bus error"); } if (irq_stat & PORT_IRQ_IF_ERR) { - err_mask |= AC_ERR_ATA_BUS; - action |= ATA_EH_SOFTRESET; - ata_ehi_push_desc(ehi, "interface fatal error"); + host_ehi->err_mask |= AC_ERR_ATA_BUS; + host_ehi->action |= ATA_EH_SOFTRESET; + ata_ehi_push_desc(host_ehi, "interface fatal error"); } if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) { - ata_ehi_hotplugged(ehi); - ata_ehi_push_desc(ehi, "%s", irq_stat & PORT_IRQ_CONNECT ? + ata_ehi_hotplugged(host_ehi); + ata_ehi_push_desc(host_ehi, "%s", + irq_stat & PORT_IRQ_CONNECT ? "connection status changed" : "PHY RDY changed"); } - if (irq_stat & PORT_IRQ_UNK_FIS) { - u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK); - - err_mask |= AC_ERR_HSM; - action |= ATA_EH_SOFTRESET; - ata_ehi_push_desc(ehi, "unknown FIS %08x %08x %08x %08x", - unk[0], unk[1], unk[2], unk[3]); - } - /* okay, let's hand over to EH */ - ehi->serror |= serror; - ehi->action |= action; - - qc = ata_qc_from_tag(ap, ap->active_tag); - if (qc) - qc->err_mask |= err_mask; - else - ehi->err_mask |= err_mask; if (irq_stat & PORT_IRQ_FREEZE) ata_port_freeze(ap); @@ -1347,25 +1412,64 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) static void ahci_port_intr(struct ata_port *ap) { void __iomem *port_mmio = ap->ioaddr.cmd_addr; - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; struct ahci_port_priv *pp = ap->private_data; + struct ahci_host_priv *hpriv = ap->host->private_data; + int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING); u32 status, qc_active; int rc, known_irq = 0; status = readl(port_mmio + PORT_IRQ_STAT); writel(status, port_mmio + PORT_IRQ_STAT); + /* ignore BAD_PMP while resetting */ + if (unlikely(resetting)) + status &= ~PORT_IRQ_BAD_PMP; + if (unlikely(status & PORT_IRQ_ERROR)) { ahci_error_intr(ap, status); return; } - if (ap->sactive) + if (status & PORT_IRQ_SDB_FIS) { + /* If SNotification is available, leave notification + * handling to sata_async_notification(). If not, + * emulate it by snooping SDB FIS RX area. + * + * Snooping FIS RX area is probably cheaper than + * poking SNotification but some constrollers which + * implement SNotification, ICH9 for example, don't + * store AN SDB FIS into receive area. + */ + if (hpriv->cap & HOST_CAP_SNTF) + sata_async_notification(ap); + else { + /* If the 'N' bit in word 0 of the FIS is set, + * we just received asynchronous notification. + * Tell libata about it. + */ + const __le32 *f = pp->rx_fis + RX_FIS_SDB; + u32 f0 = le32_to_cpu(f[0]); + + if (f0 & (1 << 15)) + sata_async_notification(ap); + } + } + + /* pp->active_link is valid iff any command is in flight */ + if (ap->qc_active && pp->active_link->sactive) qc_active = readl(port_mmio + PORT_SCR_ACT); else qc_active = readl(port_mmio + PORT_CMD_ISSUE); rc = ata_qc_complete_multiple(ap, qc_active, NULL); + + /* If resetting, spurious or invalid completions are expected, + * return unconditionally. + */ + if (resetting) + return; + if (rc > 0) return; if (rc < 0) { @@ -1380,7 +1484,7 @@ static void ahci_port_intr(struct ata_port *ap) /* if !NCQ, ignore. No modern ATA device has broken HSM * implementation for non-NCQ commands. */ - if (!ap->sactive) + if (!ap->link.sactive) return; if (status & PORT_IRQ_D2H_REG_FIS) { @@ -1433,7 +1537,7 @@ static void ahci_port_intr(struct ata_port *ap) if (!known_irq) ata_port_printk(ap, KERN_INFO, "spurious interrupt " "(irq_stat 0x%x active_tag 0x%x sactive 0x%x)\n", - status, ap->active_tag, ap->sactive); + status, ap->link.active_tag, ap->link.sactive); } static void ahci_irq_clear(struct ata_port *ap) @@ -1498,6 +1602,13 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; void __iomem *port_mmio = ahci_port_base(ap); + struct ahci_port_priv *pp = ap->private_data; + + /* Keep track of the currently active link. It will be used + * in completion path to determine whether NCQ phase is in + * progress. + */ + pp->active_link = qc->dev->link; if (qc->tf.protocol == ATA_PROT_NCQ) writel(1 << qc->tag, port_mmio + PORT_SCR_ACT); @@ -1520,6 +1631,7 @@ static void ahci_thaw(struct ata_port *ap) void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; void __iomem *port_mmio = ahci_port_base(ap); u32 tmp; + struct ahci_port_priv *pp = ap->private_data; /* clear IRQ */ tmp = readl(port_mmio + PORT_IRQ_STAT); @@ -1527,7 +1639,7 @@ static void ahci_thaw(struct ata_port *ap) writel(1 << ap->port_no, mmio + HOST_IRQ_STAT); /* turn IRQ back on */ - writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK); + writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); } static void ahci_error_handler(struct ata_port *ap) @@ -1539,8 +1651,10 @@ static void ahci_error_handler(struct ata_port *ap) } /* perform recovery */ - ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_hardreset, - ahci_postreset); + sata_pmp_do_eh(ap, ata_std_prereset, ahci_softreset, + ahci_hardreset, ahci_postreset, + sata_pmp_std_prereset, ahci_pmp_softreset, + sata_pmp_std_hardreset, sata_pmp_std_postreset); } static void ahci_vt8251_error_handler(struct ata_port *ap) @@ -1565,11 +1679,44 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) ahci_kick_engine(ap, 1); } +static void ahci_pmp_attach(struct ata_port *ap) +{ + void __iomem *port_mmio = ahci_port_base(ap); + struct ahci_port_priv *pp = ap->private_data; + u32 cmd; + + cmd = readl(port_mmio + PORT_CMD); + cmd |= PORT_CMD_PMP; + writel(cmd, port_mmio + PORT_CMD); + + pp->intr_mask |= PORT_IRQ_BAD_PMP; + writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); +} + +static void ahci_pmp_detach(struct ata_port *ap) +{ + void __iomem *port_mmio = ahci_port_base(ap); + struct ahci_port_priv *pp = ap->private_data; + u32 cmd; + + cmd = readl(port_mmio + PORT_CMD); + cmd &= ~PORT_CMD_PMP; + writel(cmd, port_mmio + PORT_CMD); + + pp->intr_mask &= ~PORT_IRQ_BAD_PMP; + writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); +} + static int ahci_port_resume(struct ata_port *ap) { ahci_power_up(ap); ahci_start_port(ap); + if (ap->nr_pmp_links) + ahci_pmp_attach(ap); + else + ahci_pmp_detach(ap); + return 0; } @@ -1681,6 +1828,12 @@ static int ahci_port_start(struct ata_port *ap) pp->cmd_tbl = mem; pp->cmd_tbl_dma = mem_dma; + /* + * Save off initial list of interrupts to be enabled. + * This could be changed later + */ + pp->intr_mask = DEF_PORT_IRQ; + ap->private_data = pp; /* engage engines, captain */ @@ -1830,20 +1983,24 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; - if ((pi.flags & AHCI_FLAG_NO_MSI) || pci_enable_msi(pdev)) - pci_intx(pdev, 1); - hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); if (!hpriv) return -ENOMEM; + hpriv->flags |= (unsigned long)pi.private_data; + + if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev)) + pci_intx(pdev, 1); /* save initial config */ - ahci_save_initial_config(pdev, &pi, hpriv); + ahci_save_initial_config(pdev, hpriv); /* prepare host */ if (hpriv->cap & HOST_CAP_NCQ) pi.flags |= ATA_FLAG_NCQ; + if (hpriv->cap & HOST_CAP_PMP) + pi.flags |= ATA_FLAG_PMP; + host = ata_host_alloc_pinfo(&pdev->dev, ppi, fls(hpriv->port_map)); if (!host) return -ENOMEM; @@ -1854,6 +2011,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) struct ata_port *ap = host->ports[i]; void __iomem *port_mmio = ahci_port_base(ap); + ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar"); + ata_port_pbar_desc(ap, AHCI_PCI_BAR, + 0x100 + ap->port_no * 0x80, "port"); + /* standard SATA port setup */ if (hpriv->port_map & (1 << i)) ap->ioaddr.cmd_addr = port_mmio; diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index 945466954724..90329982bef7 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -34,7 +34,7 @@ /** * generic_set_mode - mode setting - * @ap: interface to set up + * @link: link to set up * @unused: returned device on error * * Use a non standard set_mode function. We don't want to be tuned. @@ -43,24 +43,24 @@ * and respect them. */ -static int generic_set_mode(struct ata_port *ap, struct ata_device **unused) +static int generic_set_mode(struct ata_link *link, struct ata_device **unused) { + struct ata_port *ap = link->ap; int dma_enabled = 0; - int i; + struct ata_device *dev; /* Bits 5 and 6 indicate if DMA is active on master/slave */ if (ap->ioaddr.bmdma_addr) dma_enabled = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; + ata_link_for_each_dev(dev, link) { if (ata_dev_enabled(dev)) { /* We don't really care */ dev->pio_mode = XFER_PIO_0; dev->dma_mode = XFER_MW_DMA_0; /* 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))) { + if (dma_enabled & (1 << (5 + dev->devno))) { ata_id_to_dma_mode(dev, XFER_MW_DMA_0); dev->flags &= ~ATA_DFLAG_PIO; } else { @@ -95,7 +95,6 @@ static struct scsi_host_template generic_sht = { static struct ata_port_operations generic_port_ops = { .set_mode = generic_set_mode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -121,9 +120,8 @@ static struct ata_port_operations generic_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int all_generic_ide; /* Set to claim all devices */ diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 92c2d5082bef..3c6f43e381f4 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -123,7 +123,6 @@ enum { ich_pata_33 = 1, /* ICH up to UDMA 33 only */ ich_pata_66 = 2, /* ICH up to 66 Mhz */ ich_pata_100 = 3, /* ICH up to UDMA 100 */ - ich_pata_133 = 4, /* ICH up to UDMA 133 */ ich5_sata = 5, ich6_sata = 6, ich6_sata_ahci = 7, @@ -131,6 +130,7 @@ enum { ich8_sata_ahci = 9, piix_pata_mwdma = 10, /* PIIX3 MWDMA only */ tolapai_sata_ahci = 11, + ich9_2port_sata = 12, /* constants for mapping table */ P0 = 0, /* port 0 */ @@ -199,7 +199,7 @@ static const struct pci_device_id piix_pci_tbl[] = { { 0x8086, 0x24CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, { 0x8086, 0x24CB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, /* Intel ICH5 */ - { 0x8086, 0x24DB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_133 }, + { 0x8086, 0x24DB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, /* C-ICH (i810E2) */ { 0x8086, 0x245B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, /* ESB (855GME/875P + 6300ESB) UDMA 100 */ @@ -207,7 +207,7 @@ static const struct pci_device_id piix_pci_tbl[] = { /* ICH6 (and 6) (i915) UDMA 100 */ { 0x8086, 0x266F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, /* ICH7/7-R (i945, i975) UDMA 100*/ - { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_133 }, + { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, { 0x8086, 0x269E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, /* ICH8 Mobile PATA Controller */ { 0x8086, 0x2850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, @@ -239,19 +239,19 @@ static const struct pci_device_id piix_pci_tbl[] = { /* SATA Controller 1 IDE (ICH8) */ { 0x8086, 0x2820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, /* SATA Controller 2 IDE (ICH8) */ - { 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, + { 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_2port_sata }, /* Mobile SATA Controller IDE (ICH8M) */ { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, /* SATA Controller IDE (ICH9) */ { 0x8086, 0x2920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, /* SATA Controller IDE (ICH9) */ - { 0x8086, 0x2921, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, + { 0x8086, 0x2921, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_2port_sata }, /* SATA Controller IDE (ICH9) */ - { 0x8086, 0x2926, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, + { 0x8086, 0x2926, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_2port_sata }, /* SATA Controller IDE (ICH9M) */ - { 0x8086, 0x2928, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, + { 0x8086, 0x2928, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_2port_sata }, /* SATA Controller IDE (ICH9M) */ - { 0x8086, 0x292d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, + { 0x8086, 0x292d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_2port_sata }, /* SATA Controller IDE (ICH9M) */ { 0x8086, 0x292e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, /* SATA Controller IDE (Tolapai) */ @@ -290,7 +290,6 @@ static struct scsi_host_template piix_sht = { }; static const struct ata_port_operations piix_pata_ops = { - .port_disable = ata_port_disable, .set_piomode = piix_set_piomode, .set_dmamode = piix_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -318,13 +317,11 @@ static const struct ata_port_operations piix_pata_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; static const struct ata_port_operations ich_pata_ops = { - .port_disable = ata_port_disable, .set_piomode = piix_set_piomode, .set_dmamode = ich_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -352,14 +349,11 @@ static const struct ata_port_operations ich_pata_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; static const struct ata_port_operations piix_sata_ops = { - .port_disable = ata_port_disable, - .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -382,7 +376,6 @@ static const struct ata_port_operations piix_sata_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -445,15 +438,27 @@ static const struct piix_map_db ich8_map_db = { }; static const struct piix_map_db tolapai_map_db = { - .mask = 0x3, - .port_enable = 0x3, - .map = { - /* PM PS SM SS MAP */ - { P0, NA, P1, NA }, /* 00b */ - { RV, RV, RV, RV }, /* 01b */ - { RV, RV, RV, RV }, /* 10b */ - { RV, RV, RV, RV }, - }, + .mask = 0x3, + .port_enable = 0x3, + .map = { + /* PM PS SM SS MAP */ + { P0, NA, P1, NA }, /* 00b */ + { RV, RV, RV, RV }, /* 01b */ + { RV, RV, RV, RV }, /* 10b */ + { RV, RV, RV, RV }, + }, +}; + +static const struct piix_map_db ich9_2port_map_db = { + .mask = 0x3, + .port_enable = 0x3, + .map = { + /* PM PS SM SS MAP */ + { P0, NA, P1, NA }, /* 00b */ + { RV, RV, RV, RV }, /* 01b */ + { RV, RV, RV, RV }, /* 10b */ + { RV, RV, RV, RV }, + }, }; static const struct piix_map_db *piix_map_db_table[] = { @@ -463,10 +468,11 @@ static const struct piix_map_db *piix_map_db_table[] = { [ich6m_sata_ahci] = &ich6m_map_db, [ich8_sata_ahci] = &ich8_map_db, [tolapai_sata_ahci] = &tolapai_map_db, + [ich9_2port_sata] = &ich9_2port_map_db, }; static struct ata_port_info piix_port_info[] = { - /* piix_pata_33: 0: PIIX4 at 33MHz */ + [piix_pata_33] = /* PIIX4 at 33MHz */ { .sht = &piix_sht, .flags = PIIX_PATA_FLAGS, @@ -476,7 +482,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &piix_pata_ops, }, - /* ich_pata_33: 1 ICH0 - ICH at 33Mhz*/ + [ich_pata_33] = /* ICH0 - ICH at 33Mhz*/ { .sht = &piix_sht, .flags = PIIX_PATA_FLAGS, @@ -485,7 +491,8 @@ static struct ata_port_info piix_port_info[] = { .udma_mask = ATA_UDMA2, /* UDMA33 */ .port_ops = &ich_pata_ops, }, - /* ich_pata_66: 2 ICH controllers up to 66MHz */ + + [ich_pata_66] = /* ICH controllers up to 66MHz */ { .sht = &piix_sht, .flags = PIIX_PATA_FLAGS, @@ -495,7 +502,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &ich_pata_ops, }, - /* ich_pata_100: 3 */ + [ich_pata_100] = { .sht = &piix_sht, .flags = PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR, @@ -505,17 +512,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &ich_pata_ops, }, - /* ich_pata_133: 4 ICH with full UDMA6 */ - { - .sht = &piix_sht, - .flags = PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR, - .pio_mask = 0x1f, /* pio 0-4 */ - .mwdma_mask = 0x06, /* Check: maybe 0x07 */ - .udma_mask = ATA_UDMA6, /* UDMA133 */ - .port_ops = &ich_pata_ops, - }, - - /* ich5_sata: 5 */ + [ich5_sata] = { .sht = &piix_sht, .flags = PIIX_SATA_FLAGS, @@ -525,7 +522,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &piix_sata_ops, }, - /* ich6_sata: 6 */ + [ich6_sata] = { .sht = &piix_sht, .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR, @@ -535,7 +532,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &piix_sata_ops, }, - /* ich6_sata_ahci: 7 */ + [ich6_sata_ahci] = { .sht = &piix_sht, .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | @@ -546,7 +543,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &piix_sata_ops, }, - /* ich6m_sata_ahci: 8 */ + [ich6m_sata_ahci] = { .sht = &piix_sht, .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | @@ -557,7 +554,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &piix_sata_ops, }, - /* ich8_sata_ahci: 9 */ + [ich8_sata_ahci] = { .sht = &piix_sht, .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | @@ -568,7 +565,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &piix_sata_ops, }, - /* piix_pata_mwdma: 10: PIIX3 MWDMA only */ + [piix_pata_mwdma] = /* PIIX3 MWDMA only */ { .sht = &piix_sht, .flags = PIIX_PATA_FLAGS, @@ -577,7 +574,18 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &piix_pata_ops, }, - /* tolapai_sata_ahci: 11: */ + [tolapai_sata_ahci] = + { + .sht = &piix_sht, + .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | + PIIX_FLAG_AHCI, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = ATA_UDMA6, + .port_ops = &piix_sata_ops, + }, + + [ich9_2port_sata] = { .sht = &piix_sht, .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | @@ -615,6 +623,7 @@ static const struct ich_laptop ich_laptop[] = { { 0x27DF, 0x0005, 0x0280 }, /* ICH7 on Acer 5602WLMi */ { 0x27DF, 0x1025, 0x0110 }, /* ICH7 on Acer 3682WLMi */ { 0x27DF, 0x1043, 0x1267 }, /* ICH7 on Asus W5F */ + { 0x27DF, 0x103C, 0x30A1 }, /* ICH7 on HP Compaq nc2400 */ { 0x24CA, 0x1025, 0x0061 }, /* ICH4 on ACER Aspire 2023WLMi */ /* end marker */ { 0, } @@ -657,19 +666,20 @@ static int ich_pata_cable_detect(struct ata_port *ap) /** * piix_pata_prereset - prereset for PATA host controller - * @ap: Target port + * @link: Target link * @deadline: deadline jiffies for the operation * * LOCKING: * None (inherited from caller). */ -static int piix_pata_prereset(struct ata_port *ap, unsigned long deadline) +static int piix_pata_prereset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } static void piix_pata_error_handler(struct ata_port *ap) @@ -1137,7 +1147,7 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev, const struct piix_map_db *map_db) { struct piix_host_priv *hpriv = pinfo[0].private_data; - const unsigned int *map; + const int *map; int i, invalid_map = 0; u8 map_value; diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index c059f78ad944..3f7533589041 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -14,6 +14,7 @@ #include <linux/acpi.h> #include <linux/libata.h> #include <linux/pci.h> +#include <scsi/scsi_device.h> #include "libata.h" #include <acpi/acpi_bus.h> @@ -40,11 +41,40 @@ static int is_pci_dev(struct device *dev) return (dev->bus == &pci_bus_type); } -static void ata_acpi_associate_sata_port(struct ata_port *ap) +/** + * ata_acpi_associate_sata_port - associate SATA port with ACPI objects + * @ap: target SATA port + * + * Look up ACPI objects associated with @ap and initialize acpi_handle + * fields of @ap, the port and devices accordingly. + * + * LOCKING: + * EH context. + * + * RETURNS: + * 0 on success, -errno on failure. + */ +void ata_acpi_associate_sata_port(struct ata_port *ap) { - acpi_integer adr = SATA_ADR(ap->port_no, NO_PORT_MULT); + WARN_ON(!(ap->flags & ATA_FLAG_ACPI_SATA)); + + if (!ap->nr_pmp_links) { + acpi_integer adr = SATA_ADR(ap->port_no, NO_PORT_MULT); + + ap->link.device->acpi_handle = + acpi_get_child(ap->host->acpi_handle, adr); + } else { + struct ata_link *link; + + ap->link.device->acpi_handle = NULL; - ap->device->acpi_handle = acpi_get_child(ap->host->acpi_handle, adr); + ata_port_for_each_link(link, ap) { + acpi_integer adr = SATA_ADR(ap->port_no, link->pmp); + + link->device->acpi_handle = + acpi_get_child(ap->host->acpi_handle, adr); + } + } } static void ata_acpi_associate_ide_port(struct ata_port *ap) @@ -60,12 +90,53 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap) max_devices++; for (i = 0; i < max_devices; i++) { - struct ata_device *dev = &ap->device[i]; + struct ata_device *dev = &ap->link.device[i]; dev->acpi_handle = acpi_get_child(ap->acpi_handle, i); } } +static void ata_acpi_handle_hotplug (struct ata_port *ap, struct kobject *kobj, + u32 event) +{ + char event_string[12]; + char *envp[] = { event_string, NULL }; + struct ata_eh_info *ehi = &ap->link.eh_info; + + if (event == 0 || event == 1) { + unsigned long flags; + spin_lock_irqsave(ap->lock, flags); + ata_ehi_clear_desc(ehi); + ata_ehi_push_desc(ehi, "ACPI event"); + ata_ehi_hotplugged(ehi); + ata_port_freeze(ap); + spin_unlock_irqrestore(ap->lock, flags); + } + + if (kobj) { + sprintf(event_string, "BAY_EVENT=%d", event); + kobject_uevent_env(kobj, KOBJ_CHANGE, envp); + } +} + +static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data) +{ + struct ata_device *dev = data; + struct kobject *kobj = NULL; + + if (dev->sdev) + kobj = &dev->sdev->sdev_gendev.kobj; + + ata_acpi_handle_hotplug (dev->link->ap, kobj, event); +} + +static void ata_acpi_ap_notify(acpi_handle handle, u32 event, void *data) +{ + struct ata_port *ap = data; + + ata_acpi_handle_hotplug (ap, &ap->dev->kobj, event); +} + /** * ata_acpi_associate - associate ATA host with ACPI objects * @host: target ATA host @@ -81,7 +152,7 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap) */ void ata_acpi_associate(struct ata_host *host) { - int i; + int i, j; if (!is_pci_dev(host->dev) || libata_noacpi) return; @@ -97,6 +168,22 @@ void ata_acpi_associate(struct ata_host *host) ata_acpi_associate_sata_port(ap); else ata_acpi_associate_ide_port(ap); + + if (ap->acpi_handle) + acpi_install_notify_handler (ap->acpi_handle, + ACPI_SYSTEM_NOTIFY, + ata_acpi_ap_notify, + ap); + + for (j = 0; j < ata_link_max_devices(&ap->link); j++) { + struct ata_device *dev = &ap->link.device[j]; + + if (dev->acpi_handle) + acpi_install_notify_handler (dev->acpi_handle, + ACPI_SYSTEM_NOTIFY, + ata_acpi_dev_notify, + dev); + } } } @@ -113,7 +200,7 @@ void ata_acpi_associate(struct ata_host *host) * RETURNS: * 0 on success, -ENOENT if _GTM doesn't exist, -errno on failure. */ -static int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm) +int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm) { struct acpi_buffer output = { .length = ACPI_ALLOCATE_BUFFER }; union acpi_object *out_obj; @@ -157,6 +244,8 @@ static int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm) return rc; } +EXPORT_SYMBOL_GPL(ata_acpi_gtm); + /** * ata_acpi_stm - execute _STM * @ap: target ATA port @@ -170,7 +259,7 @@ static int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm) * RETURNS: * 0 on success, -ENOENT if _STM doesn't exist, -errno on failure. */ -static int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm) +int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm) { acpi_status status; struct acpi_object_list input; @@ -182,10 +271,10 @@ static int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm) /* Buffers for id may need byteswapping ? */ in_params[1].type = ACPI_TYPE_BUFFER; in_params[1].buffer.length = 512; - in_params[1].buffer.pointer = (u8 *)ap->device[0].id; + in_params[1].buffer.pointer = (u8 *)ap->link.device[0].id; in_params[2].type = ACPI_TYPE_BUFFER; in_params[2].buffer.length = 512; - in_params[2].buffer.pointer = (u8 *)ap->device[1].id; + in_params[2].buffer.pointer = (u8 *)ap->link.device[1].id; input.count = 3; input.pointer = in_params; @@ -202,6 +291,8 @@ static int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm) return 0; } +EXPORT_SYMBOL_GPL(ata_acpi_stm); + /** * ata_dev_get_GTF - get the drive bootup default taskfile settings * @dev: target ATA device @@ -226,7 +317,7 @@ static int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm) static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf, void **ptr_to_free) { - struct ata_port *ap = dev->ap; + struct ata_port *ap = dev->link->ap; acpi_status status; struct acpi_buffer output; union acpi_object *out_obj; @@ -296,6 +387,44 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf, } /** + * ata_acpi_cbl_80wire - Check for 80 wire cable + * @ap: Port to check + * + * Return 1 if the ACPI mode data for this port indicates the BIOS selected + * an 80wire mode. + */ + +int ata_acpi_cbl_80wire(struct ata_port *ap) +{ + struct ata_acpi_gtm gtm; + int valid = 0; + + /* No _GTM data, no information */ + if (ata_acpi_gtm(ap, >m) < 0) + return 0; + + /* Split timing, DMA enabled */ + if ((gtm.flags & 0x11) == 0x11 && gtm.drive[0].dma < 55) + valid |= 1; + if ((gtm.flags & 0x14) == 0x14 && gtm.drive[1].dma < 55) + valid |= 2; + /* Shared timing, DMA enabled */ + if ((gtm.flags & 0x11) == 0x01 && gtm.drive[0].dma < 55) + valid |= 1; + if ((gtm.flags & 0x14) == 0x04 && gtm.drive[0].dma < 55) + valid |= 2; + + /* Drive check */ + if ((valid & 1) && ata_dev_enabled(&ap->link.device[0])) + return 1; + if ((valid & 2) && ata_dev_enabled(&ap->link.device[1])) + return 1; + return 0; +} + +EXPORT_SYMBOL_GPL(ata_acpi_cbl_80wire); + +/** * taskfile_load_raw - send taskfile registers to host controller * @dev: target ATA device * @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7) @@ -320,7 +449,7 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf, static int taskfile_load_raw(struct ata_device *dev, const struct ata_acpi_gtf *gtf) { - struct ata_port *ap = dev->ap; + struct ata_port *ap = dev->link->ap; struct ata_taskfile tf, rtf; unsigned int err_mask; @@ -349,7 +478,7 @@ static int taskfile_load_raw(struct ata_device *dev, tf.lbal, tf.lbam, tf.lbah, tf.device); rtf = tf; - err_mask = ata_exec_internal(dev, &rtf, NULL, DMA_NONE, NULL, 0); + err_mask = ata_exec_internal(dev, &rtf, NULL, DMA_NONE, NULL, 0, 0); if (err_mask) { ata_dev_printk(dev, KERN_ERR, "ACPI cmd %02x/%02x:%02x:%02x:%02x:%02x:%02x failed " @@ -424,7 +553,7 @@ static int ata_acpi_exec_tfs(struct ata_device *dev) */ static int ata_acpi_push_id(struct ata_device *dev) { - struct ata_port *ap = dev->ap; + struct ata_port *ap = dev->link->ap; int err; acpi_status status; struct acpi_object_list input; @@ -508,7 +637,7 @@ int ata_acpi_on_suspend(struct ata_port *ap) */ void ata_acpi_on_resume(struct ata_port *ap) { - int i; + struct ata_device *dev; if (ap->acpi_handle && (ap->pflags & ATA_PFLAG_GTM_VALID)) { BUG_ON(ap->flags & ATA_FLAG_ACPI_SATA); @@ -518,8 +647,8 @@ void ata_acpi_on_resume(struct ata_port *ap) } /* schedule _GTF */ - for (i = 0; i < ATA_MAX_DEVICES; i++) - ap->device[i].flags |= ATA_DFLAG_ACPI_PENDING; + ata_link_for_each_dev(dev, &ap->link) + dev->flags |= ATA_DFLAG_ACPI_PENDING; } /** @@ -538,8 +667,8 @@ void ata_acpi_on_resume(struct ata_port *ap) */ int ata_acpi_on_devcfg(struct ata_device *dev) { - struct ata_port *ap = dev->ap; - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_port *ap = dev->link->ap; + struct ata_eh_context *ehc = &ap->link.eh_context; int acpi_sata = ap->flags & ATA_FLAG_ACPI_SATA; int rc; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 772be09b4689..68699b3e7998 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -59,8 +59,6 @@ #include "libata.h" -#define DRV_VERSION "2.21" /* must be exactly four chars */ - /* debounce timing parameters in msecs { interval, duration, timeout } */ const unsigned long sata_deb_timing_normal[] = { 5, 100, 2000 }; @@ -70,6 +68,7 @@ const unsigned long sata_deb_timing_long[] = { 100, 2000, 5000 }; static unsigned int ata_dev_init_params(struct ata_device *dev, u16 heads, u16 sectors); static unsigned int ata_dev_set_xfermode(struct ata_device *dev); +static unsigned int ata_dev_set_AN(struct ata_device *dev, u8 enable); static void ata_dev_xfermask(struct ata_device *dev); static unsigned long ata_dev_blacklisted(const struct ata_device *dev); @@ -86,6 +85,10 @@ int atapi_dmadir = 0; module_param(atapi_dmadir, int, 0444); MODULE_PARM_DESC(atapi_dmadir, "Enable ATAPI DMADIR bridge support (0=off, 1=on)"); +int atapi_passthru16 = 1; +module_param(atapi_passthru16, int, 0444); +MODULE_PARM_DESC(atapi_passthru16, "Enable ATA_16 passthru for ATAPI devices; on by default (0=off, 1=on)"); + int libata_fua = 0; module_param_named(fua, libata_fua, int, 0444); MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)"); @@ -94,13 +97,17 @@ static int ata_ignore_hpa = 0; module_param_named(ignore_hpa, ata_ignore_hpa, int, 0644); MODULE_PARM_DESC(ignore_hpa, "Ignore HPA limit (0=keep BIOS limits, 1=ignore limits, using full disk)"); +static int libata_dma_mask = ATA_DMA_MASK_ATA|ATA_DMA_MASK_ATAPI|ATA_DMA_MASK_CFA; +module_param_named(dma, libata_dma_mask, int, 0444); +MODULE_PARM_DESC(dma, "DMA enable/disable (0x1==ATA, 0x2==ATAPI, 0x4==CF)"); + static int ata_probe_timeout = ATA_TMOUT_INTERNAL / HZ; module_param(ata_probe_timeout, int, 0444); MODULE_PARM_DESC(ata_probe_timeout, "Set ATA probing timeout (seconds)"); -int libata_noacpi = 1; +int libata_noacpi = 0; module_param_named(noacpi, libata_noacpi, int, 0444); -MODULE_PARM_DESC(noacpi, "Disables the use of ACPI in suspend/resume when set"); +MODULE_PARM_DESC(noacpi, "Disables the use of ACPI in probe/suspend/resume when set"); MODULE_AUTHOR("Jeff Garzik"); MODULE_DESCRIPTION("Library module for ATA devices"); @@ -235,7 +242,7 @@ static int ata_rwcmd_protocol(struct ata_taskfile *tf, struct ata_device *dev) if (dev->flags & ATA_DFLAG_PIO) { tf->protocol = ATA_PROT_PIO; index = dev->multi_count ? 0 : 8; - } else if (lba48 && (dev->ap->flags & ATA_FLAG_PIO_LBA48)) { + } else if (lba48 && (dev->link->ap->flags & ATA_FLAG_PIO_LBA48)) { /* Unable to use DMA due to host limitation */ tf->protocol = ATA_PROT_PIO; index = dev->multi_count ? 0 : 8; @@ -604,7 +611,7 @@ static const char *sata_spd_string(unsigned int spd) void ata_dev_disable(struct ata_device *dev) { if (ata_dev_enabled(dev)) { - if (ata_msg_drv(dev->ap)) + if (ata_msg_drv(dev->link->ap)) ata_dev_printk(dev, KERN_WARNING, "disabled\n"); ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO0 | ATA_DNXFER_QUIET); @@ -667,37 +674,57 @@ static unsigned int ata_devchk(struct ata_port *ap, unsigned int device) * None. * * RETURNS: - * Device type, %ATA_DEV_ATA, %ATA_DEV_ATAPI, or %ATA_DEV_UNKNOWN - * the event of failure. + * Device type, %ATA_DEV_ATA, %ATA_DEV_ATAPI, %ATA_DEV_PMP or + * %ATA_DEV_UNKNOWN the event of failure. */ - unsigned int ata_dev_classify(const struct ata_taskfile *tf) { /* Apple's open source Darwin code hints that some devices only * put a proper signature into the LBA mid/high registers, * So, we only check those. It's sufficient for uniqueness. + * + * ATA/ATAPI-7 (d1532v1r1: Feb. 19, 2003) specified separate + * signatures for ATA and ATAPI devices attached on SerialATA, + * 0x3c/0xc3 and 0x69/0x96 respectively. However, SerialATA + * spec has never mentioned about using different signatures + * for ATA/ATAPI devices. Then, Serial ATA II: Port + * Multiplier specification began to use 0x69/0x96 to identify + * port multpliers and 0x3c/0xc3 to identify SEMB device. + * ATA/ATAPI-7 dropped descriptions about 0x3c/0xc3 and + * 0x69/0x96 shortly and described them as reserved for + * SerialATA. + * + * We follow the current spec and consider that 0x69/0x96 + * identifies a port multiplier and 0x3c/0xc3 a SEMB device. */ - - if (((tf->lbam == 0) && (tf->lbah == 0)) || - ((tf->lbam == 0x3c) && (tf->lbah == 0xc3))) { + if ((tf->lbam == 0) && (tf->lbah == 0)) { DPRINTK("found ATA device by sig\n"); return ATA_DEV_ATA; } - if (((tf->lbam == 0x14) && (tf->lbah == 0xeb)) || - ((tf->lbam == 0x69) && (tf->lbah == 0x96))) { + if ((tf->lbam == 0x14) && (tf->lbah == 0xeb)) { DPRINTK("found ATAPI device by sig\n"); return ATA_DEV_ATAPI; } + if ((tf->lbam == 0x69) && (tf->lbah == 0x96)) { + DPRINTK("found PMP device by sig\n"); + return ATA_DEV_PMP; + } + + if ((tf->lbam == 0x3c) && (tf->lbah == 0xc3)) { + printk("ata: SEMB device ignored\n"); + return ATA_DEV_SEMB_UNSUP; /* not yet */ + } + DPRINTK("unknown device\n"); return ATA_DEV_UNKNOWN; } /** * ata_dev_try_classify - Parse returned ATA device signature - * @ap: ATA channel to examine - * @device: Device to examine (starting at zero) + * @dev: ATA device to classify (starting at zero) + * @present: device seems present * @r_err: Value of error register on completion * * After an event -- SRST, E.D.D., or SATA COMRESET -- occurs, @@ -715,15 +742,15 @@ unsigned int ata_dev_classify(const struct ata_taskfile *tf) * RETURNS: * Device type - %ATA_DEV_ATA, %ATA_DEV_ATAPI or %ATA_DEV_NONE. */ - -unsigned int -ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err) +unsigned int ata_dev_try_classify(struct ata_device *dev, int present, + u8 *r_err) { + struct ata_port *ap = dev->link->ap; struct ata_taskfile tf; unsigned int class; u8 err; - ap->ops->dev_select(ap, device); + ap->ops->dev_select(ap, dev->devno); memset(&tf, 0, sizeof(tf)); @@ -733,12 +760,12 @@ ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err) *r_err = err; /* see if device passed diags: if master then continue and warn later */ - if (err == 0 && device == 0) + if (err == 0 && dev->devno == 0) /* diagnostic fail : do nothing _YET_ */ - ap->device[device].horkage |= ATA_HORKAGE_DIAGNOSTIC; + dev->horkage |= ATA_HORKAGE_DIAGNOSTIC; else if (err == 1) /* do nothing */ ; - else if ((device == 0) && (err == 0x81)) + else if ((dev->devno == 0) && (err == 0x81)) /* do nothing */ ; else return ATA_DEV_NONE; @@ -746,10 +773,20 @@ ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err) /* determine if device is ATA or ATAPI */ class = ata_dev_classify(&tf); - if (class == ATA_DEV_UNKNOWN) - return ATA_DEV_NONE; - if ((class == ATA_DEV_ATA) && (ata_chk_status(ap) == 0)) - return ATA_DEV_NONE; + if (class == ATA_DEV_UNKNOWN) { + /* If the device failed diagnostic, it's likely to + * have reported incorrect device signature too. + * Assume ATA device if the device seems present but + * device signature is invalid with diagnostic + * failure. + */ + if (present && (dev->horkage & ATA_HORKAGE_DIAGNOSTIC)) + class = ATA_DEV_ATA; + else + class = ATA_DEV_NONE; + } else if ((class == ATA_DEV_ATA) && (ata_chk_status(ap) == 0)) + class = ATA_DEV_NONE; + return class; } @@ -816,6 +853,21 @@ void ata_id_c_string(const u16 *id, unsigned char *s, *p = '\0'; } +static u64 ata_id_n_sectors(const u16 *id) +{ + if (ata_id_has_lba(id)) { + if (ata_id_has_lba48(id)) + return ata_id_u64(id, 100); + else + return ata_id_u32(id, 60); + } else { + if (ata_id_current_chs_valid(id)) + return ata_id_u32(id, 57); + else + return id[1] * id[3] * id[6]; + } +} + static u64 ata_tf_to_lba48(struct ata_taskfile *tf) { u64 sectors = 0; @@ -843,129 +895,110 @@ static u64 ata_tf_to_lba(struct ata_taskfile *tf) } /** - * ata_read_native_max_address_ext - LBA48 native max query - * @dev: Device to query + * ata_read_native_max_address - Read native max address + * @dev: target device + * @max_sectors: out parameter for the result native max address * - * Perform an LBA48 size query upon the device in question. Return the - * actual LBA48 size or zero if the command fails. - */ - -static u64 ata_read_native_max_address_ext(struct ata_device *dev) -{ - unsigned int err; - struct ata_taskfile tf; - - ata_tf_init(dev, &tf); - - tf.command = ATA_CMD_READ_NATIVE_MAX_EXT; - tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | ATA_TFLAG_ISADDR; - tf.protocol |= ATA_PROT_NODATA; - tf.device |= 0x40; - - err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); - if (err) - return 0; - - return ata_tf_to_lba48(&tf); -} - -/** - * ata_read_native_max_address - LBA28 native max query - * @dev: Device to query + * Perform an LBA48 or LBA28 native size query upon the device in + * question. * - * Performa an LBA28 size query upon the device in question. Return the - * actual LBA28 size or zero if the command fails. + * RETURNS: + * 0 on success, -EACCES if command is aborted by the drive. + * -EIO on other errors. */ - -static u64 ata_read_native_max_address(struct ata_device *dev) +static int ata_read_native_max_address(struct ata_device *dev, u64 *max_sectors) { - unsigned int err; + unsigned int err_mask; struct ata_taskfile tf; + int lba48 = ata_id_has_lba48(dev->id); ata_tf_init(dev, &tf); - tf.command = ATA_CMD_READ_NATIVE_MAX; + /* always clear all address registers */ tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR; + + if (lba48) { + tf.command = ATA_CMD_READ_NATIVE_MAX_EXT; + tf.flags |= ATA_TFLAG_LBA48; + } else + tf.command = ATA_CMD_READ_NATIVE_MAX; + tf.protocol |= ATA_PROT_NODATA; - tf.device |= 0x40; + tf.device |= ATA_LBA; - err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); - if (err) - return 0; + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); + if (err_mask) { + ata_dev_printk(dev, KERN_WARNING, "failed to read native " + "max address (err_mask=0x%x)\n", err_mask); + if (err_mask == AC_ERR_DEV && (tf.feature & ATA_ABORTED)) + return -EACCES; + return -EIO; + } - return ata_tf_to_lba(&tf); + if (lba48) + *max_sectors = ata_tf_to_lba48(&tf); + else + *max_sectors = ata_tf_to_lba(&tf); + if (dev->horkage & ATA_HORKAGE_HPA_SIZE) + (*max_sectors)--; + return 0; } /** - * ata_set_native_max_address_ext - LBA48 native max set - * @dev: Device to query + * ata_set_max_sectors - Set max sectors + * @dev: target device * @new_sectors: new max sectors value to set for the device * - * Perform an LBA48 size set max upon the device in question. Return the - * actual LBA48 size or zero if the command fails. + * Set max sectors of @dev to @new_sectors. + * + * RETURNS: + * 0 on success, -EACCES if command is aborted or denied (due to + * previous non-volatile SET_MAX) by the drive. -EIO on other + * errors. */ - -static u64 ata_set_native_max_address_ext(struct ata_device *dev, u64 new_sectors) +static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors) { - unsigned int err; + unsigned int err_mask; struct ata_taskfile tf; + int lba48 = ata_id_has_lba48(dev->id); new_sectors--; ata_tf_init(dev, &tf); - tf.command = ATA_CMD_SET_MAX_EXT; - tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | ATA_TFLAG_ISADDR; - tf.protocol |= ATA_PROT_NODATA; - tf.device |= 0x40; - - tf.lbal = (new_sectors >> 0) & 0xff; - tf.lbam = (new_sectors >> 8) & 0xff; - tf.lbah = (new_sectors >> 16) & 0xff; - - tf.hob_lbal = (new_sectors >> 24) & 0xff; - tf.hob_lbam = (new_sectors >> 32) & 0xff; - tf.hob_lbah = (new_sectors >> 40) & 0xff; - - err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); - if (err) - return 0; - - return ata_tf_to_lba48(&tf); -} - -/** - * ata_set_native_max_address - LBA28 native max set - * @dev: Device to query - * @new_sectors: new max sectors value to set for the device - * - * Perform an LBA28 size set max upon the device in question. Return the - * actual LBA28 size or zero if the command fails. - */ + tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR; -static u64 ata_set_native_max_address(struct ata_device *dev, u64 new_sectors) -{ - unsigned int err; - struct ata_taskfile tf; + if (lba48) { + tf.command = ATA_CMD_SET_MAX_EXT; + tf.flags |= ATA_TFLAG_LBA48; - new_sectors--; + tf.hob_lbal = (new_sectors >> 24) & 0xff; + tf.hob_lbam = (new_sectors >> 32) & 0xff; + tf.hob_lbah = (new_sectors >> 40) & 0xff; + } else { + tf.command = ATA_CMD_SET_MAX; - ata_tf_init(dev, &tf); + tf.device |= (new_sectors >> 24) & 0xf; + } - tf.command = ATA_CMD_SET_MAX; - tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR; tf.protocol |= ATA_PROT_NODATA; + tf.device |= ATA_LBA; tf.lbal = (new_sectors >> 0) & 0xff; tf.lbam = (new_sectors >> 8) & 0xff; tf.lbah = (new_sectors >> 16) & 0xff; - tf.device |= ((new_sectors >> 24) & 0x0f) | 0x40; - err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); - if (err) - return 0; + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); + if (err_mask) { + ata_dev_printk(dev, KERN_WARNING, "failed to set " + "max address (err_mask=0x%x)\n", err_mask); + if (err_mask == AC_ERR_DEV && + (tf.feature & (ATA_ABORTED | ATA_IDNF))) + return -EACCES; + return -EIO; + } - return ata_tf_to_lba(&tf); + return 0; } /** @@ -975,60 +1008,93 @@ static u64 ata_set_native_max_address(struct ata_device *dev, u64 new_sectors) * Read the size of an LBA28 or LBA48 disk with HPA features and resize * it if required to the full size of the media. The caller must check * the drive has the HPA feature set enabled. + * + * RETURNS: + * 0 on success, -errno on failure. */ - -static u64 ata_hpa_resize(struct ata_device *dev) +static int ata_hpa_resize(struct ata_device *dev) { - u64 sectors = dev->n_sectors; - u64 hpa_sectors; + struct ata_eh_context *ehc = &dev->link->eh_context; + int print_info = ehc->i.flags & ATA_EHI_PRINTINFO; + u64 sectors = ata_id_n_sectors(dev->id); + u64 native_sectors; + int rc; - if (ata_id_has_lba48(dev->id)) - hpa_sectors = ata_read_native_max_address_ext(dev); - else - hpa_sectors = ata_read_native_max_address(dev); + /* do we need to do it? */ + if (dev->class != ATA_DEV_ATA || + !ata_id_has_lba(dev->id) || !ata_id_hpa_enabled(dev->id) || + (dev->horkage & ATA_HORKAGE_BROKEN_HPA)) + return 0; - if (hpa_sectors > sectors) { - ata_dev_printk(dev, KERN_INFO, - "Host Protected Area detected:\n" - "\tcurrent size: %lld sectors\n" - "\tnative size: %lld sectors\n", - (long long)sectors, (long long)hpa_sectors); - - if (ata_ignore_hpa) { - if (ata_id_has_lba48(dev->id)) - hpa_sectors = ata_set_native_max_address_ext(dev, hpa_sectors); - else - hpa_sectors = ata_set_native_max_address(dev, - hpa_sectors); - - if (hpa_sectors) { - ata_dev_printk(dev, KERN_INFO, "native size " - "increased to %lld sectors\n", - (long long)hpa_sectors); - return hpa_sectors; - } + /* read native max address */ + rc = ata_read_native_max_address(dev, &native_sectors); + if (rc) { + /* If HPA isn't going to be unlocked, skip HPA + * resizing from the next try. + */ + if (!ata_ignore_hpa) { + ata_dev_printk(dev, KERN_WARNING, "HPA support seems " + "broken, will skip HPA handling\n"); + dev->horkage |= ATA_HORKAGE_BROKEN_HPA; + + /* we can continue if device aborted the command */ + if (rc == -EACCES) + rc = 0; } - } else if (hpa_sectors < sectors) - ata_dev_printk(dev, KERN_WARNING, "%s 1: hpa sectors (%lld) " - "is smaller than sectors (%lld)\n", __FUNCTION__, - (long long)hpa_sectors, (long long)sectors); - return sectors; -} + return rc; + } -static u64 ata_id_n_sectors(const u16 *id) -{ - if (ata_id_has_lba(id)) { - if (ata_id_has_lba48(id)) - return ata_id_u64(id, 100); - else - return ata_id_u32(id, 60); - } else { - if (ata_id_current_chs_valid(id)) - return ata_id_u32(id, 57); - else - return id[1] * id[3] * id[6]; + /* nothing to do? */ + if (native_sectors <= sectors || !ata_ignore_hpa) { + if (!print_info || native_sectors == sectors) + return 0; + + if (native_sectors > sectors) + ata_dev_printk(dev, KERN_INFO, + "HPA detected: current %llu, native %llu\n", + (unsigned long long)sectors, + (unsigned long long)native_sectors); + else if (native_sectors < sectors) + ata_dev_printk(dev, KERN_WARNING, + "native sectors (%llu) is smaller than " + "sectors (%llu)\n", + (unsigned long long)native_sectors, + (unsigned long long)sectors); + return 0; + } + + /* let's unlock HPA */ + rc = ata_set_max_sectors(dev, native_sectors); + if (rc == -EACCES) { + /* if device aborted the command, skip HPA resizing */ + ata_dev_printk(dev, KERN_WARNING, "device aborted resize " + "(%llu -> %llu), skipping HPA handling\n", + (unsigned long long)sectors, + (unsigned long long)native_sectors); + dev->horkage |= ATA_HORKAGE_BROKEN_HPA; + return 0; + } else if (rc) + return rc; + + /* re-read IDENTIFY data */ + rc = ata_dev_reread_id(dev, 0); + if (rc) { + ata_dev_printk(dev, KERN_ERR, "failed to re-read IDENTIFY " + "data after HPA resizing\n"); + return rc; } + + if (print_info) { + u64 new_sectors = ata_id_n_sectors(dev->id); + ata_dev_printk(dev, KERN_INFO, + "HPA unlocked: %llu -> %llu, native %llu\n", + (unsigned long long)sectors, + (unsigned long long)new_sectors, + (unsigned long long)native_sectors); + } + + return 0; } /** @@ -1150,7 +1216,7 @@ void ata_dev_select(struct ata_port *ap, unsigned int device, ap->ops->dev_select(ap, device); if (wait) { - if (can_sleep && ap->device[device].class == ATA_DEV_ATAPI) + if (can_sleep && ap->link.device[device].class == ATA_DEV_ATAPI) msleep(150); ata_wait_idle(ap); } @@ -1328,6 +1394,7 @@ static void ata_qc_complete_internal(struct ata_queued_cmd *qc) * @dma_dir: Data tranfer direction of the command * @sg: sg list for the data buffer of the command * @n_elem: Number of sg entries + * @timeout: Timeout in msecs (0 for default) * * Executes libata internal command with timeout. @tf contains * command on entry and result on return. Timeout and error @@ -1344,13 +1411,15 @@ static void ata_qc_complete_internal(struct ata_queued_cmd *qc) unsigned ata_exec_internal_sg(struct ata_device *dev, struct ata_taskfile *tf, const u8 *cdb, int dma_dir, struct scatterlist *sg, - unsigned int n_elem) + unsigned int n_elem, unsigned long timeout) { - struct ata_port *ap = dev->ap; + struct ata_link *link = dev->link; + struct ata_port *ap = link->ap; u8 command = tf->command; struct ata_queued_cmd *qc; unsigned int tag, preempted_tag; u32 preempted_sactive, preempted_qc_active; + int preempted_nr_active_links; DECLARE_COMPLETION_ONSTACK(wait); unsigned long flags; unsigned int err_mask; @@ -1386,12 +1455,14 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, qc->dev = dev; ata_qc_reinit(qc); - preempted_tag = ap->active_tag; - preempted_sactive = ap->sactive; + preempted_tag = link->active_tag; + preempted_sactive = link->sactive; preempted_qc_active = ap->qc_active; - ap->active_tag = ATA_TAG_POISON; - ap->sactive = 0; + preempted_nr_active_links = ap->nr_active_links; + link->active_tag = ATA_TAG_POISON; + link->sactive = 0; ap->qc_active = 0; + ap->nr_active_links = 0; /* prepare & issue qc */ qc->tf = *tf; @@ -1416,7 +1487,10 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, spin_unlock_irqrestore(ap->lock, flags); - rc = wait_for_completion_timeout(&wait, ata_probe_timeout); + if (!timeout) + timeout = ata_probe_timeout * 1000 / HZ; + + rc = wait_for_completion_timeout(&wait, msecs_to_jiffies(timeout)); ata_port_flush_task(ap); @@ -1467,9 +1541,10 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, err_mask = qc->err_mask; ata_qc_free(qc); - ap->active_tag = preempted_tag; - ap->sactive = preempted_sactive; + link->active_tag = preempted_tag; + link->sactive = preempted_sactive; ap->qc_active = preempted_qc_active; + ap->nr_active_links = preempted_nr_active_links; /* XXX - Some LLDDs (sata_mv) disable port on command failure. * Until those drivers are fixed, we detect the condition @@ -1500,6 +1575,7 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, * @dma_dir: Data tranfer direction of the command * @buf: Data buffer of the command * @buflen: Length of data buffer + * @timeout: Timeout in msecs (0 for default) * * Wrapper around ata_exec_internal_sg() which takes simple * buffer instead of sg list. @@ -1512,7 +1588,8 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, */ unsigned ata_exec_internal(struct ata_device *dev, struct ata_taskfile *tf, const u8 *cdb, - int dma_dir, void *buf, unsigned int buflen) + int dma_dir, void *buf, unsigned int buflen, + unsigned long timeout) { struct scatterlist *psg = NULL, sg; unsigned int n_elem = 0; @@ -1524,7 +1601,8 @@ unsigned ata_exec_internal(struct ata_device *dev, n_elem++; } - return ata_exec_internal_sg(dev, tf, cdb, dma_dir, psg, n_elem); + return ata_exec_internal_sg(dev, tf, cdb, dma_dir, psg, n_elem, + timeout); } /** @@ -1551,7 +1629,7 @@ unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd) tf.flags |= ATA_TFLAG_DEVICE; tf.protocol = ATA_PROT_NODATA; - return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); + return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); } /** @@ -1566,7 +1644,7 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev) { /* Controller doesn't support IORDY. Probably a pointless check as the caller should know this */ - if (adev->ap->flags & ATA_FLAG_NO_IORDY) + if (adev->link->ap->flags & ATA_FLAG_NO_IORDY) return 0; /* PIO3 and higher it is mandatory */ if (adev->pio_mode > XFER_PIO_2) @@ -1613,6 +1691,9 @@ static u32 ata_pio_mask_no_iordy(const struct ata_device *adev) * devices. This function also issues ATA_CMD_INIT_DEV_PARAMS * for pre-ATA4 drives. * + * FIXME: ATA_CMD_ID_ATA is optional for early drives and right + * now we abort if we hit that case. + * * LOCKING: * Kernel thread context (may sleep) * @@ -1622,7 +1703,7 @@ static u32 ata_pio_mask_no_iordy(const struct ata_device *adev) int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, unsigned int flags, u16 *id) { - struct ata_port *ap = dev->ap; + struct ata_port *ap = dev->link->ap; unsigned int class = *p_class; struct ata_taskfile tf; unsigned int err_mask = 0; @@ -1663,7 +1744,7 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, tf.flags |= ATA_TFLAG_POLLING; err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, - id, sizeof(id[0]) * ATA_ID_WORDS); + id, sizeof(id[0]) * ATA_ID_WORDS, 0); if (err_mask) { if (err_mask & AC_ERR_NODEV_HINT) { DPRINTK("ata%u.%d: NODEV after polling detection\n", @@ -1722,7 +1803,8 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, tf.feature = SETFEATURES_SPINUP; tf.protocol = ATA_PROT_NODATA; tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); + err_mask = ata_exec_internal(dev, &tf, NULL, + DMA_NONE, NULL, 0, 0); if (err_mask && id[2] != 0x738c) { rc = -EIO; reason = "SPINUP failed"; @@ -1740,10 +1822,13 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, /* * The exact sequence expected by certain pre-ATA4 drives is: * SRST RESET - * IDENTIFY - * INITIALIZE DEVICE PARAMETERS + * IDENTIFY (optional in early ATA) + * INITIALIZE DEVICE PARAMETERS (later IDE and ATA) * anything else.. * Some drives were very specific about that exact sequence. + * + * Note that ATA4 says lba is mandatory so the second check + * shoud never trigger. */ if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) { err_mask = ata_dev_init_params(dev, id[3], id[6]); @@ -1774,13 +1859,14 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, static inline u8 ata_dev_knobble(struct ata_device *dev) { - return ((dev->ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id))); + struct ata_port *ap = dev->link->ap; + return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id))); } static void ata_dev_config_ncq(struct ata_device *dev, char *desc, size_t desc_sz) { - struct ata_port *ap = dev->ap; + struct ata_port *ap = dev->link->ap; int hdepth = 0, ddepth = ata_id_queue_depth(dev->id); if (!ata_id_has_ncq(dev->id)) { @@ -1817,8 +1903,8 @@ static void ata_dev_config_ncq(struct ata_device *dev, */ int ata_dev_configure(struct ata_device *dev) { - struct ata_port *ap = dev->ap; - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_port *ap = dev->link->ap; + struct ata_eh_context *ehc = &dev->link->eh_context; int print_info = ehc->i.flags & ATA_EHI_PRINTINFO; const u16 *id = dev->id; unsigned int xfer_mask; @@ -1844,6 +1930,11 @@ int ata_dev_configure(struct ata_device *dev) if (rc) return rc; + /* massage HPA, do it early as it might change IDENTIFY data */ + rc = ata_hpa_resize(dev); + if (rc) + return rc; + /* print device capabilities */ if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, @@ -1911,10 +2002,6 @@ int ata_dev_configure(struct ata_device *dev) dev->flags |= ATA_DFLAG_FLUSH_EXT; } - if (!(dev->horkage & ATA_HORKAGE_BROKEN_HPA) && - ata_id_hpa_enabled(dev->id)) - dev->n_sectors = ata_hpa_resize(dev); - /* config NCQ */ ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc)); @@ -1963,7 +2050,9 @@ int ata_dev_configure(struct ata_device *dev) /* ATAPI-specific feature tests */ else if (dev->class == ATA_DEV_ATAPI) { - char *cdb_intr_string = ""; + const char *cdb_intr_string = ""; + const char *atapi_an_string = ""; + u32 sntf; rc = atapi_cdb_len(id); if ((rc < 12) || (rc > ATAPI_CDB_LEN)) { @@ -1975,6 +2064,28 @@ int ata_dev_configure(struct ata_device *dev) } dev->cdb_len = (unsigned int) rc; + /* Enable ATAPI AN if both the host and device have + * the support. If PMP is attached, SNTF is required + * to enable ATAPI AN to discern between PHY status + * changed notifications and ATAPI ANs. + */ + if ((ap->flags & ATA_FLAG_AN) && ata_id_has_atapi_AN(id) && + (!ap->nr_pmp_links || + sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf) == 0)) { + unsigned int err_mask; + + /* issue SET feature command to turn this on */ + err_mask = ata_dev_set_AN(dev, SETFEATURES_SATA_ENABLE); + if (err_mask) + ata_dev_printk(dev, KERN_ERR, + "failed to enable ATAPI AN " + "(err_mask=0x%x)\n", err_mask); + else { + dev->flags |= ATA_DFLAG_AN; + atapi_an_string = ", ATAPI AN"; + } + } + if (ata_id_cdb_intr(dev->id)) { dev->flags |= ATA_DFLAG_CDB_INTR; cdb_intr_string = ", CDB intr"; @@ -1983,10 +2094,10 @@ int ata_dev_configure(struct ata_device *dev) /* print device info to dmesg */ if (ata_msg_drv(ap) && print_info) ata_dev_printk(dev, KERN_INFO, - "ATAPI: %s, %s, max %s%s\n", + "ATAPI: %s, %s, max %s%s%s\n", modelbuf, fwrevbuf, ata_mode_string(xfer_mask), - cdb_intr_string); + cdb_intr_string, atapi_an_string); } /* determine max_sectors */ @@ -2103,21 +2214,19 @@ int ata_bus_probe(struct ata_port *ap) { unsigned int classes[ATA_MAX_DEVICES]; int tries[ATA_MAX_DEVICES]; - int i, rc; + int rc; struct ata_device *dev; ata_port_probe(ap); - for (i = 0; i < ATA_MAX_DEVICES; i++) - tries[i] = ATA_PROBE_MAX_TRIES; + ata_link_for_each_dev(dev, &ap->link) + tries[dev->devno] = ATA_PROBE_MAX_TRIES; retry: /* reset and determine device classes */ ap->ops->phy_reset(ap); - for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->device[i]; - + ata_link_for_each_dev(dev, &ap->link) { if (!(ap->flags & ATA_FLAG_DISABLED) && dev->class != ATA_DEV_UNKNOWN) classes[dev->devno] = dev->class; @@ -2132,18 +2241,16 @@ int ata_bus_probe(struct ata_port *ap) /* after the reset the device state is PIO 0 and the controller state is undefined. Record the mode */ - for (i = 0; i < ATA_MAX_DEVICES; i++) - ap->device[i].pio_mode = XFER_PIO_0; + ata_link_for_each_dev(dev, &ap->link) + dev->pio_mode = XFER_PIO_0; /* 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]) - dev->class = classes[i]; + ata_link_for_each_dev(dev, &ap->link) { + if (tries[dev->devno]) + dev->class = classes[dev->devno]; if (!ata_dev_enabled(dev)) continue; @@ -2158,33 +2265,42 @@ int ata_bus_probe(struct ata_port *ap) if (ap->ops->cable_detect) ap->cbl = ap->ops->cable_detect(ap); + /* We may have SATA bridge glue hiding here irrespective of the + reported cable types and sensed types */ + ata_link_for_each_dev(dev, &ap->link) { + if (!ata_dev_enabled(dev)) + continue; + /* SATA drives indicate we have a bridge. We don't know which + end of the link the bridge is which is a problem */ + if (ata_id_is_sata(dev->id)) + ap->cbl = ATA_CBL_SATA; + } + /* 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]; + ata_link_for_each_dev(dev, &ap->link) { if (!ata_dev_enabled(dev)) continue; - ap->eh_context.i.flags |= ATA_EHI_PRINTINFO; + ap->link.eh_context.i.flags |= ATA_EHI_PRINTINFO; rc = ata_dev_configure(dev); - ap->eh_context.i.flags &= ~ATA_EHI_PRINTINFO; + ap->link.eh_context.i.flags &= ~ATA_EHI_PRINTINFO; if (rc) goto fail; } /* configure transfer mode */ - rc = ata_set_mode(ap, &dev); + rc = ata_set_mode(&ap->link, &dev); if (rc) goto fail; - for (i = 0; i < ATA_MAX_DEVICES; i++) - if (ata_dev_enabled(&ap->device[i])) + ata_link_for_each_dev(dev, &ap->link) + if (ata_dev_enabled(dev)) return 0; /* no device present, disable port */ ata_port_disable(ap); - ap->ops->port_disable(ap); return -ENODEV; fail: @@ -2204,7 +2320,7 @@ int ata_bus_probe(struct ata_port *ap) /* This is the last chance, better to slow * down than lose it. */ - sata_down_spd_limit(ap); + sata_down_spd_limit(&ap->link); ata_down_xfermask_limit(dev, ATA_DNXFER_PIO); } } @@ -2233,28 +2349,28 @@ void ata_port_probe(struct ata_port *ap) /** * sata_print_link_status - Print SATA link status - * @ap: SATA port to printk link status about + * @link: SATA link to printk link status about * * This function prints link speed and status of a SATA link. * * LOCKING: * None. */ -void sata_print_link_status(struct ata_port *ap) +void sata_print_link_status(struct ata_link *link) { u32 sstatus, scontrol, tmp; - if (sata_scr_read(ap, SCR_STATUS, &sstatus)) + if (sata_scr_read(link, SCR_STATUS, &sstatus)) return; - sata_scr_read(ap, SCR_CONTROL, &scontrol); + sata_scr_read(link, SCR_CONTROL, &scontrol); - if (ata_port_online(ap)) { + if (ata_link_online(link)) { tmp = (sstatus >> 4) & 0xf; - ata_port_printk(ap, KERN_INFO, + ata_link_printk(link, KERN_INFO, "SATA link up %s (SStatus %X SControl %X)\n", sata_spd_string(tmp), sstatus, scontrol); } else { - ata_port_printk(ap, KERN_INFO, + ata_link_printk(link, KERN_INFO, "SATA link down (SStatus %X SControl %X)\n", sstatus, scontrol); } @@ -2274,32 +2390,33 @@ void sata_print_link_status(struct ata_port *ap) */ void __sata_phy_reset(struct ata_port *ap) { - u32 sstatus; + struct ata_link *link = &ap->link; unsigned long timeout = jiffies + (HZ * 5); + u32 sstatus; if (ap->flags & ATA_FLAG_SATA_RESET) { /* issue phy wake/reset */ - sata_scr_write_flush(ap, SCR_CONTROL, 0x301); + sata_scr_write_flush(link, SCR_CONTROL, 0x301); /* Couldn't find anything in SATA I/II specs, but * AHCI-1.1 10.4.2 says at least 1 ms. */ mdelay(1); } /* phy wake/clear reset */ - sata_scr_write_flush(ap, SCR_CONTROL, 0x300); + sata_scr_write_flush(link, SCR_CONTROL, 0x300); /* wait for phy to become ready, if necessary */ do { msleep(200); - sata_scr_read(ap, SCR_STATUS, &sstatus); + sata_scr_read(link, SCR_STATUS, &sstatus); if ((sstatus & 0xf) != 1) break; } while (time_before(jiffies, timeout)); /* print link status */ - sata_print_link_status(ap); + sata_print_link_status(link); /* TODO: phy layer with polling, timeouts, etc. */ - if (!ata_port_offline(ap)) + if (!ata_link_offline(link)) ata_port_probe(ap); else ata_port_disable(ap); @@ -2344,8 +2461,8 @@ void sata_phy_reset(struct ata_port *ap) struct ata_device *ata_dev_pair(struct ata_device *adev) { - struct ata_port *ap = adev->ap; - struct ata_device *pair = &ap->device[1 - adev->devno]; + struct ata_link *link = adev->link; + struct ata_device *pair = &link->device[1 - adev->devno]; if (!ata_dev_enabled(pair)) return NULL; return pair; @@ -2366,16 +2483,16 @@ struct ata_device *ata_dev_pair(struct ata_device *adev) void ata_port_disable(struct ata_port *ap) { - ap->device[0].class = ATA_DEV_NONE; - ap->device[1].class = ATA_DEV_NONE; + ap->link.device[0].class = ATA_DEV_NONE; + ap->link.device[1].class = ATA_DEV_NONE; ap->flags |= ATA_FLAG_DISABLED; } /** * sata_down_spd_limit - adjust SATA spd limit downward - * @ap: Port to adjust SATA spd limit for + * @link: Link to adjust SATA spd limit for * - * Adjust SATA spd limit of @ap downward. Note that this + * Adjust SATA spd limit of @link downward. Note that this * function only adjusts the limit. The change must be applied * using sata_set_spd(). * @@ -2385,24 +2502,24 @@ void ata_port_disable(struct ata_port *ap) * RETURNS: * 0 on success, negative errno on failure */ -int sata_down_spd_limit(struct ata_port *ap) +int sata_down_spd_limit(struct ata_link *link) { u32 sstatus, spd, mask; int rc, highbit; - if (!sata_scr_valid(ap)) + if (!sata_scr_valid(link)) return -EOPNOTSUPP; /* If SCR can be read, use it to determine the current SPD. - * If not, use cached value in ap->sata_spd. + * If not, use cached value in link->sata_spd. */ - rc = sata_scr_read(ap, SCR_STATUS, &sstatus); + rc = sata_scr_read(link, SCR_STATUS, &sstatus); if (rc == 0) spd = (sstatus >> 4) & 0xf; else - spd = ap->sata_spd; + spd = link->sata_spd; - mask = ap->sata_spd_limit; + mask = link->sata_spd_limit; if (mask <= 1) return -EINVAL; @@ -2422,22 +2539,22 @@ int sata_down_spd_limit(struct ata_port *ap) if (!mask) return -EINVAL; - ap->sata_spd_limit = mask; + link->sata_spd_limit = mask; - ata_port_printk(ap, KERN_WARNING, "limiting SATA link speed to %s\n", + ata_link_printk(link, KERN_WARNING, "limiting SATA link speed to %s\n", sata_spd_string(fls(mask))); return 0; } -static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol) +static int __sata_set_spd_needed(struct ata_link *link, u32 *scontrol) { u32 spd, limit; - if (ap->sata_spd_limit == UINT_MAX) + if (link->sata_spd_limit == UINT_MAX) limit = 0; else - limit = fls(ap->sata_spd_limit); + limit = fls(link->sata_spd_limit); spd = (*scontrol >> 4) & 0xf; *scontrol = (*scontrol & ~0xf0) | ((limit & 0xf) << 4); @@ -2447,10 +2564,10 @@ static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol) /** * sata_set_spd_needed - is SATA spd configuration needed - * @ap: Port in question + * @link: Link in question * * Test whether the spd limit in SControl matches - * @ap->sata_spd_limit. This function is used to determine + * @link->sata_spd_limit. This function is used to determine * whether hardreset is necessary to apply SATA spd * configuration. * @@ -2460,21 +2577,21 @@ static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol) * RETURNS: * 1 if SATA spd configuration is needed, 0 otherwise. */ -int sata_set_spd_needed(struct ata_port *ap) +int sata_set_spd_needed(struct ata_link *link) { u32 scontrol; - if (sata_scr_read(ap, SCR_CONTROL, &scontrol)) + if (sata_scr_read(link, SCR_CONTROL, &scontrol)) return 0; - return __sata_set_spd_needed(ap, &scontrol); + return __sata_set_spd_needed(link, &scontrol); } /** * sata_set_spd - set SATA spd according to spd limit - * @ap: Port to set SATA spd for + * @link: Link to set SATA spd for * - * Set SATA spd of @ap according to sata_spd_limit. + * Set SATA spd of @link according to sata_spd_limit. * * LOCKING: * Inherited from caller. @@ -2483,18 +2600,18 @@ int sata_set_spd_needed(struct ata_port *ap) * 0 if spd doesn't need to be changed, 1 if spd has been * changed. Negative errno if SCR registers are inaccessible. */ -int sata_set_spd(struct ata_port *ap) +int sata_set_spd(struct ata_link *link) { u32 scontrol; int rc; - if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol))) + if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol))) return rc; - if (!__sata_set_spd_needed(ap, &scontrol)) + if (!__sata_set_spd_needed(link, &scontrol)) return 0; - if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol))) + if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol))) return rc; return 1; @@ -2749,7 +2866,7 @@ int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel) static int ata_dev_set_mode(struct ata_device *dev) { - struct ata_eh_context *ehc = &dev->ap->eh_context; + struct ata_eh_context *ehc = &dev->link->eh_context; unsigned int err_mask; int rc; @@ -2761,7 +2878,11 @@ static int ata_dev_set_mode(struct ata_device *dev) /* Old CFA may refuse this command, which is just fine */ if (dev->xfer_shift == ATA_SHIFT_PIO && ata_id_is_cfa(dev->id)) err_mask &= ~AC_ERR_DEV; - + /* Some very old devices and some bad newer ones fail any kind of + SET_XFERMODE request but support PIO0-2 timings and no IORDY */ + if (dev->xfer_shift == ATA_SHIFT_PIO && !ata_id_has_iordy(dev->id) && + dev->pio_mode <= XFER_PIO_2) + err_mask &= ~AC_ERR_DEV; if (err_mask) { ata_dev_printk(dev, KERN_ERR, "failed to set xfermode " "(err_mask=0x%x)\n", err_mask); @@ -2769,7 +2890,7 @@ static int ata_dev_set_mode(struct ata_device *dev) } ehc->i.flags |= ATA_EHI_POST_SETMODE; - rc = ata_dev_revalidate(dev, 0); + rc = ata_dev_revalidate(dev, ATA_DEV_UNKNOWN, 0); ehc->i.flags &= ~ATA_EHI_POST_SETMODE; if (rc) return rc; @@ -2784,7 +2905,7 @@ static int ata_dev_set_mode(struct ata_device *dev) /** * ata_do_set_mode - Program timings and issue SET FEATURES - XFER - * @ap: port on which timings will be programmed + * @link: link on which timings will be programmed * @r_failed_dev: out paramter for failed device * * Standard implementation of the function used to tune and set @@ -2799,25 +2920,36 @@ static int ata_dev_set_mode(struct ata_device *dev) * 0 on success, negative errno otherwise */ -int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) +int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) { + struct ata_port *ap = link->ap; struct ata_device *dev; - int i, rc = 0, used_dma = 0, found = 0; - + int rc = 0, used_dma = 0, found = 0; /* step 1: calculate xfer_mask */ - for (i = 0; i < ATA_MAX_DEVICES; i++) { + ata_link_for_each_dev(dev, link) { unsigned int pio_mask, dma_mask; - - dev = &ap->device[i]; + unsigned int mode_mask; if (!ata_dev_enabled(dev)) continue; + mode_mask = ATA_DMA_MASK_ATA; + if (dev->class == ATA_DEV_ATAPI) + mode_mask = ATA_DMA_MASK_ATAPI; + else if (ata_id_is_cfa(dev->id)) + mode_mask = ATA_DMA_MASK_CFA; + ata_dev_xfermask(dev); pio_mask = ata_pack_xfermask(dev->pio_mask, 0, 0); dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask); + + if (libata_dma_mask & mode_mask) + dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask); + else + dma_mask = 0; + dev->pio_mode = ata_xfer_mask2mode(pio_mask); dev->dma_mode = ata_xfer_mask2mode(dma_mask); @@ -2829,8 +2961,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) goto out; /* step 2: always set host PIO timings */ - for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->device[i]; + ata_link_for_each_dev(dev, link) { if (!ata_dev_enabled(dev)) continue; @@ -2847,9 +2978,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) } /* step 3: set host DMA timings */ - for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->device[i]; - + ata_link_for_each_dev(dev, link) { if (!ata_dev_enabled(dev) || !dev->dma_mode) continue; @@ -2860,9 +2989,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) } /* step 4: update devices' xfer mode */ - for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->device[i]; - + ata_link_for_each_dev(dev, link) { /* don't update suspended devices' xfer mode */ if (!ata_dev_enabled(dev)) continue; @@ -2886,7 +3013,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) /** * ata_set_mode - Program timings and issue SET FEATURES - XFER - * @ap: port on which timings will be programmed + * @link: link on which timings will be programmed * @r_failed_dev: out paramter for failed device * * Set ATA device disk transfer mode (PIO3, UDMA6, etc.). If @@ -2899,12 +3026,14 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) * RETURNS: * 0 on success, negative errno otherwise */ -int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) +int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) { + struct ata_port *ap = link->ap; + /* has private set_mode? */ if (ap->ops->set_mode) - return ap->ops->set_mode(ap, r_failed_dev); - return ata_do_set_mode(ap, r_failed_dev); + return ap->ops->set_mode(link, r_failed_dev); + return ata_do_set_mode(link, r_failed_dev); } /** @@ -3007,7 +3136,7 @@ int ata_wait_ready(struct ata_port *ap, unsigned long deadline) if (!(status & ATA_BUSY)) return 0; - if (!ata_port_online(ap) && status == 0xff) + if (!ata_link_online(&ap->link) && status == 0xff) return -ENODEV; if (time_after(now, deadline)) return -EBUSY; @@ -3088,6 +3217,8 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask, unsigned long deadline) { struct ata_ioports *ioaddr = &ap->ioaddr; + struct ata_device *dev; + int i = 0; DPRINTK("ata%u: bus reset via SRST\n", ap->print_id); @@ -3098,6 +3229,25 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask, udelay(20); /* FIXME: flush */ iowrite8(ap->ctl, ioaddr->ctl_addr); + /* If we issued an SRST then an ATA drive (not ATAPI) + * may have changed configuration and be in PIO0 timing. If + * we did a hard reset (or are coming from power on) this is + * true for ATA or ATAPI. Until we've set a suitable controller + * mode we should not touch the bus as we may be talking too fast. + */ + + ata_link_for_each_dev(dev, &ap->link) + dev->pio_mode = XFER_PIO_0; + + /* If the controller has a pio mode setup function then use + it to set the chipset to rights. Don't touch the DMA setup + as that will be dealt with when revalidating */ + if (ap->ops->set_piomode) { + ata_link_for_each_dev(dev, &ap->link) + if (devmask & (1 << i++)) + ap->ops->set_piomode(ap, dev); + } + /* 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 @@ -3142,6 +3292,7 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask, void ata_bus_reset(struct ata_port *ap) { + struct ata_device *device = ap->link.device; struct ata_ioports *ioaddr = &ap->ioaddr; unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS; u8 err; @@ -3177,19 +3328,19 @@ void ata_bus_reset(struct ata_port *ap) /* * determine by signature whether we have ATA or ATAPI devices */ - ap->device[0].class = ata_dev_try_classify(ap, 0, &err); + device[0].class = ata_dev_try_classify(&device[0], dev0, &err); if ((slave_possible) && (err != 0x81)) - ap->device[1].class = ata_dev_try_classify(ap, 1, &err); + device[1].class = ata_dev_try_classify(&device[1], dev1, &err); /* is double-select really necessary? */ - if (ap->device[1].class != ATA_DEV_NONE) + if (device[1].class != ATA_DEV_NONE) ap->ops->dev_select(ap, 1); - if (ap->device[0].class != ATA_DEV_NONE) + if (device[0].class != ATA_DEV_NONE) ap->ops->dev_select(ap, 0); /* if no devices were detected, disable this port */ - if ((ap->device[0].class == ATA_DEV_NONE) && - (ap->device[1].class == ATA_DEV_NONE)) + if ((device[0].class == ATA_DEV_NONE) && + (device[1].class == ATA_DEV_NONE)) goto err_out; if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) { @@ -3202,18 +3353,18 @@ void ata_bus_reset(struct ata_port *ap) err_out: ata_port_printk(ap, KERN_ERR, "disabling port\n"); - ap->ops->port_disable(ap); + ata_port_disable(ap); DPRINTK("EXIT\n"); } /** - * sata_phy_debounce - debounce SATA phy status - * @ap: ATA port to debounce SATA phy status for + * sata_link_debounce - debounce SATA phy status + * @link: ATA link to debounce SATA phy status for * @params: timing parameters { interval, duratinon, timeout } in msec * @deadline: deadline jiffies for the operation * - * Make sure SStatus of @ap reaches stable state, determined by +* Make sure SStatus of @link reaches stable state, determined by * holding the same value where DET is not 1 for @duration polled * every @interval, before @timeout. Timeout constraints the * beginning of the stable state. Because DET gets stuck at 1 on @@ -3229,8 +3380,8 @@ err_out: * RETURNS: * 0 on success, -errno on failure. */ -int sata_phy_debounce(struct ata_port *ap, const unsigned long *params, - unsigned long deadline) +int sata_link_debounce(struct ata_link *link, const unsigned long *params, + unsigned long deadline) { unsigned long interval_msec = params[0]; unsigned long duration = msecs_to_jiffies(params[1]); @@ -3242,7 +3393,7 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params, if (time_before(t, deadline)) deadline = t; - if ((rc = sata_scr_read(ap, SCR_STATUS, &cur))) + if ((rc = sata_scr_read(link, SCR_STATUS, &cur))) return rc; cur &= 0xf; @@ -3251,7 +3402,7 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params, while (1) { msleep(interval_msec); - if ((rc = sata_scr_read(ap, SCR_STATUS, &cur))) + if ((rc = sata_scr_read(link, SCR_STATUS, &cur))) return rc; cur &= 0xf; @@ -3277,12 +3428,12 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params, } /** - * sata_phy_resume - resume SATA phy - * @ap: ATA port to resume SATA phy for + * sata_link_resume - resume SATA link + * @link: ATA link to resume SATA * @params: timing parameters { interval, duratinon, timeout } in msec * @deadline: deadline jiffies for the operation * - * Resume SATA phy of @ap and debounce it. + * Resume SATA phy @link and debounce it. * * LOCKING: * Kernel thread context (may sleep) @@ -3290,18 +3441,18 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params, * RETURNS: * 0 on success, -errno on failure. */ -int sata_phy_resume(struct ata_port *ap, const unsigned long *params, - unsigned long deadline) +int sata_link_resume(struct ata_link *link, const unsigned long *params, + unsigned long deadline) { u32 scontrol; int rc; - if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol))) + if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol))) return rc; scontrol = (scontrol & 0x0f0) | 0x300; - if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol))) + if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol))) return rc; /* Some PHYs react badly if SStatus is pounded immediately @@ -3309,15 +3460,15 @@ int sata_phy_resume(struct ata_port *ap, const unsigned long *params, */ msleep(200); - return sata_phy_debounce(ap, params, deadline); + return sata_link_debounce(link, params, deadline); } /** * ata_std_prereset - prepare for reset - * @ap: ATA port to be reset + * @link: ATA link to be reset * @deadline: deadline jiffies for the operation * - * @ap is about to be reset. Initialize it. Failure from + * @link is about to be reset. Initialize it. Failure from * prereset makes libata abort whole reset sequence and give up * that port, so prereset should be best-effort. It does its * best to prepare for reset sequence but if things go wrong, it @@ -3329,37 +3480,44 @@ int sata_phy_resume(struct ata_port *ap, const unsigned long *params, * RETURNS: * 0 on success, -errno otherwise. */ -int ata_std_prereset(struct ata_port *ap, unsigned long deadline) +int ata_std_prereset(struct ata_link *link, unsigned long deadline) { - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_port *ap = link->ap; + struct ata_eh_context *ehc = &link->eh_context; const unsigned long *timing = sata_ehc_deb_timing(ehc); int rc; /* handle link resume */ if ((ehc->i.flags & ATA_EHI_RESUME_LINK) && - (ap->flags & ATA_FLAG_HRST_TO_RESUME)) + (link->flags & ATA_LFLAG_HRST_TO_RESUME)) + ehc->i.action |= ATA_EH_HARDRESET; + + /* Some PMPs don't work with only SRST, force hardreset if PMP + * is supported. + */ + if (ap->flags & ATA_FLAG_PMP) ehc->i.action |= ATA_EH_HARDRESET; /* if we're about to do hardreset, nothing more to do */ if (ehc->i.action & ATA_EH_HARDRESET) return 0; - /* if SATA, resume phy */ + /* if SATA, resume link */ if (ap->flags & ATA_FLAG_SATA) { - rc = sata_phy_resume(ap, timing, deadline); + rc = sata_link_resume(link, timing, deadline); /* whine about phy resume failure but proceed */ if (rc && rc != -EOPNOTSUPP) - ata_port_printk(ap, KERN_WARNING, "failed to resume " + ata_link_printk(link, KERN_WARNING, "failed to resume " "link for reset (errno=%d)\n", rc); } /* Wait for !BSY if the controller can wait for the first D2H * Reg FIS and we don't know that no device is attached. */ - if (!(ap->flags & ATA_FLAG_SKIP_D2H_BSY) && !ata_port_offline(ap)) { + if (!(link->flags & ATA_LFLAG_SKIP_D2H_BSY) && !ata_link_offline(link)) { rc = ata_wait_ready(ap, deadline); if (rc && rc != -ENODEV) { - ata_port_printk(ap, KERN_WARNING, "device not ready " + ata_link_printk(link, KERN_WARNING, "device not ready " "(errno=%d), forcing hardreset\n", rc); ehc->i.action |= ATA_EH_HARDRESET; } @@ -3370,7 +3528,7 @@ int ata_std_prereset(struct ata_port *ap, unsigned long deadline) /** * ata_std_softreset - reset host port via ATA SRST - * @ap: port to reset + * @link: ATA link to reset * @classes: resulting classes of attached devices * @deadline: deadline jiffies for the operation * @@ -3382,9 +3540,10 @@ int ata_std_prereset(struct ata_port *ap, unsigned long deadline) * RETURNS: * 0 on success, -errno otherwise. */ -int ata_std_softreset(struct ata_port *ap, unsigned int *classes, +int ata_std_softreset(struct ata_link *link, unsigned int *classes, unsigned long deadline) { + struct ata_port *ap = link->ap; unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS; unsigned int devmask = 0; int rc; @@ -3392,7 +3551,7 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes, DPRINTK("ENTER\n"); - if (ata_port_offline(ap)) { + if (ata_link_offline(link)) { classes[0] = ATA_DEV_NONE; goto out; } @@ -3410,15 +3569,17 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes, DPRINTK("about to softreset, devmask=%x\n", devmask); rc = ata_bus_softreset(ap, devmask, deadline); /* if link is occupied, -ENODEV too is an error */ - if (rc && (rc != -ENODEV || sata_scr_valid(ap))) { - ata_port_printk(ap, KERN_ERR, "SRST failed (errno=%d)\n", rc); + if (rc && (rc != -ENODEV || sata_scr_valid(link))) { + ata_link_printk(link, KERN_ERR, "SRST failed (errno=%d)\n", rc); return rc; } /* determine by signature whether we have ATA or ATAPI devices */ - classes[0] = ata_dev_try_classify(ap, 0, &err); + classes[0] = ata_dev_try_classify(&link->device[0], + devmask & (1 << 0), &err); if (slave_possible && err != 0x81) - classes[1] = ata_dev_try_classify(ap, 1, &err); + classes[1] = ata_dev_try_classify(&link->device[1], + devmask & (1 << 1), &err); out: DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]); @@ -3426,12 +3587,12 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes, } /** - * sata_port_hardreset - reset port via SATA phy reset - * @ap: port to reset + * sata_link_hardreset - reset link via SATA phy reset + * @link: link to reset * @timing: timing parameters { interval, duratinon, timeout } in msec * @deadline: deadline jiffies for the operation * - * SATA phy-reset host port using DET bits of SControl register. + * SATA phy-reset @link using DET bits of SControl register. * * LOCKING: * Kernel thread context (may sleep) @@ -3439,7 +3600,7 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes, * RETURNS: * 0 on success, -errno otherwise. */ -int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing, +int sata_link_hardreset(struct ata_link *link, const unsigned long *timing, unsigned long deadline) { u32 scontrol; @@ -3447,30 +3608,30 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing, DPRINTK("ENTER\n"); - if (sata_set_spd_needed(ap)) { + if (sata_set_spd_needed(link)) { /* SATA spec says nothing about how to reconfigure * spd. To be on the safe side, turn off phy during * reconfiguration. This works for at least ICH7 AHCI * and Sil3124. */ - if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol))) + if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol))) goto out; scontrol = (scontrol & 0x0f0) | 0x304; - if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol))) + if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol))) goto out; - sata_set_spd(ap); + sata_set_spd(link); } /* issue phy wake/reset */ - if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol))) + if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol))) goto out; scontrol = (scontrol & 0x0f0) | 0x301; - if ((rc = sata_scr_write_flush(ap, SCR_CONTROL, scontrol))) + if ((rc = sata_scr_write_flush(link, SCR_CONTROL, scontrol))) goto out; /* Couldn't find anything in SATA I/II specs, but AHCI-1.1 @@ -3478,8 +3639,8 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing, */ msleep(1); - /* bring phy back */ - rc = sata_phy_resume(ap, timing, deadline); + /* bring link back */ + rc = sata_link_resume(link, timing, deadline); out: DPRINTK("EXIT, rc=%d\n", rc); return rc; @@ -3487,7 +3648,7 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing, /** * sata_std_hardreset - reset host port via SATA phy reset - * @ap: port to reset + * @link: link to reset * @class: resulting class of attached device * @deadline: deadline jiffies for the operation * @@ -3500,24 +3661,25 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing, * RETURNS: * 0 on success, -errno otherwise. */ -int sata_std_hardreset(struct ata_port *ap, unsigned int *class, +int sata_std_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { - const unsigned long *timing = sata_ehc_deb_timing(&ap->eh_context); + struct ata_port *ap = link->ap; + const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); int rc; DPRINTK("ENTER\n"); /* do hardreset */ - rc = sata_port_hardreset(ap, timing, deadline); + rc = sata_link_hardreset(link, timing, deadline); if (rc) { - ata_port_printk(ap, KERN_ERR, + ata_link_printk(link, KERN_ERR, "COMRESET failed (errno=%d)\n", rc); return rc; } /* TODO: phy layer with polling, timeouts, etc. */ - if (ata_port_offline(ap)) { + if (ata_link_offline(link)) { *class = ATA_DEV_NONE; DPRINTK("EXIT, link offline\n"); return 0; @@ -3526,17 +3688,27 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class, /* wait a while before checking status, see SRST for more info */ msleep(150); + /* If PMP is supported, we have to do follow-up SRST. Note + * that some PMPs don't send D2H Reg FIS after hardreset at + * all if the first port is empty. Wait for it just for a + * second and request follow-up SRST. + */ + if (ap->flags & ATA_FLAG_PMP) { + ata_wait_ready(ap, jiffies + HZ); + return -EAGAIN; + } + rc = ata_wait_ready(ap, deadline); /* link occupied, -ENODEV too is an error */ if (rc) { - ata_port_printk(ap, KERN_ERR, + ata_link_printk(link, KERN_ERR, "COMRESET failed (errno=%d)\n", rc); return rc; } ap->ops->dev_select(ap, 0); /* probably unnecessary */ - *class = ata_dev_try_classify(ap, 0, NULL); + *class = ata_dev_try_classify(link->device, 1, NULL); DPRINTK("EXIT, class=%u\n", *class); return 0; @@ -3544,7 +3716,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class, /** * ata_std_postreset - standard postreset callback - * @ap: the target ata_port + * @link: the target ata_link * @classes: classes of attached devices * * This function is invoked after a successful reset. Note that @@ -3554,18 +3726,19 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class, * LOCKING: * Kernel thread context (may sleep) */ -void ata_std_postreset(struct ata_port *ap, unsigned int *classes) +void ata_std_postreset(struct ata_link *link, unsigned int *classes) { + struct ata_port *ap = link->ap; u32 serror; DPRINTK("ENTER\n"); /* print link status */ - sata_print_link_status(ap); + sata_print_link_status(link); /* clear SError */ - if (sata_scr_read(ap, SCR_ERROR, &serror) == 0) - sata_scr_write(ap, SCR_ERROR, serror); + if (sata_scr_read(link, SCR_ERROR, &serror) == 0) + sata_scr_write(link, SCR_ERROR, serror); /* is double-select really necessary? */ if (classes[0] != ATA_DEV_NONE) @@ -3652,7 +3825,7 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class, int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags) { unsigned int class = dev->class; - u16 *id = (void *)dev->ap->sector_buf; + u16 *id = (void *)dev->link->ap->sector_buf; int rc; /* read ID data */ @@ -3671,6 +3844,7 @@ int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags) /** * ata_dev_revalidate - Revalidate ATA device * @dev: device to revalidate + * @new_class: new class code * @readid_flags: read ID flags * * Re-read IDENTIFY page, make sure @dev is still attached to the @@ -3682,7 +3856,8 @@ int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags) * RETURNS: * 0 on success, negative errno otherwise */ -int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags) +int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class, + unsigned int readid_flags) { u64 n_sectors = dev->n_sectors; int rc; @@ -3690,6 +3865,15 @@ int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags) if (!ata_dev_enabled(dev)) return -ENODEV; + /* fail early if !ATA && !ATAPI to avoid issuing [P]IDENTIFY to PMP */ + if (ata_class_enabled(new_class) && + new_class != ATA_DEV_ATA && new_class != ATA_DEV_ATAPI) { + ata_dev_printk(dev, KERN_INFO, "class mismatch %u != %u\n", + dev->class, new_class); + rc = -ENODEV; + goto fail; + } + /* re-read ID */ rc = ata_dev_reread_id(dev, readid_flags); if (rc) @@ -3763,6 +3947,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "IOMEGA ZIP 250 ATAPI", NULL, ATA_HORKAGE_NODMA }, /* temporary fix */ { "IOMEGA ZIP 250 ATAPI Floppy", NULL, ATA_HORKAGE_NODMA }, + /* Odd clown on sil3726/4726 PMPs */ + { "Config Disk", NULL, ATA_HORKAGE_NODMA | + ATA_HORKAGE_SKIP_PM }, /* Weird ATAPI devices */ { "TORiSAN DVD-ROM DRD-N216", NULL, ATA_HORKAGE_MAX_SEC_128 }, @@ -3775,16 +3962,12 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { /* http://thread.gmane.org/gmane.linux.ide/14907 */ { "FUJITSU MHT2060BH", NULL, ATA_HORKAGE_NONCQ }, /* NCQ is broken */ - { "Maxtor 6L250S0", "BANC1G10", ATA_HORKAGE_NONCQ }, - { "Maxtor 6B200M0", "BANC1BM0", ATA_HORKAGE_NONCQ }, - { "Maxtor 6B200M0", "BANC1B10", ATA_HORKAGE_NONCQ }, - { "Maxtor 7B250S0", "BANC1B70", ATA_HORKAGE_NONCQ, }, - { "Maxtor 7B300S0", "BANC1B70", ATA_HORKAGE_NONCQ }, + { "Maxtor *", "BANC*", ATA_HORKAGE_NONCQ }, { "Maxtor 7V300F0", "VA111630", ATA_HORKAGE_NONCQ }, - { "HITACHI HDS7250SASUN500G 0621KTAWSD", "K2AOAJ0AHITACHI", - ATA_HORKAGE_NONCQ }, - /* NCQ hard hangs device under heavier load, needs hard power cycle */ - { "Maxtor 6B250S0", "BANC1B70", ATA_HORKAGE_NONCQ }, + { "HITACHI HDS7250SASUN500G*", NULL, ATA_HORKAGE_NONCQ }, + { "HITACHI HDS7225SBSUN250G*", NULL, ATA_HORKAGE_NONCQ }, + { "ST380817AS", "3.42", ATA_HORKAGE_NONCQ }, + /* Blacklist entries taken from Silicon Image 3124/3132 Windows driver .inf file - also several Linux problem reports */ { "HTS541060G9SA00", "MB3OC60D", ATA_HORKAGE_NONCQ, }, @@ -3793,11 +3976,17 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { /* Drives which do spurious command completion */ { "HTS541680J9SA00", "SB2IC7EP", ATA_HORKAGE_NONCQ, }, { "HTS541612J9SA00", "SBDIC7JP", ATA_HORKAGE_NONCQ, }, + { "HDT722516DLA380", "V43OA96A", ATA_HORKAGE_NONCQ, }, { "Hitachi HTS541616J9SA00", "SB4OC70P", ATA_HORKAGE_NONCQ, }, { "WDC WD740ADFD-00NLR1", NULL, ATA_HORKAGE_NONCQ, }, + { "WDC WD3200AAJS-00RYA0", "12.01B01", ATA_HORKAGE_NONCQ, }, { "FUJITSU MHV2080BH", "00840028", ATA_HORKAGE_NONCQ, }, + { "ST9120822AS", "3.CLF", ATA_HORKAGE_NONCQ, }, { "ST9160821AS", "3.CLF", ATA_HORKAGE_NONCQ, }, - { "ST3160812AS", "3.AD", ATA_HORKAGE_NONCQ, }, + { "ST9160821AS", "3.ALD", ATA_HORKAGE_NONCQ, }, + { "ST9160821AS", "3.CCD", ATA_HORKAGE_NONCQ, }, + { "ST3160812AS", "3.ADJ", ATA_HORKAGE_NONCQ, }, + { "ST980813AS", "3.ADB", ATA_HORKAGE_NONCQ, }, { "SAMSUNG HD401LJ", "ZZ100-15", ATA_HORKAGE_NONCQ, }, /* devices which puke on READ_NATIVE_MAX */ @@ -3806,10 +3995,37 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "WDC WD2500JD-00HBB0", "WD-WMAL71490727", ATA_HORKAGE_BROKEN_HPA }, { "MAXTOR 6L080L4", "A93.0500", ATA_HORKAGE_BROKEN_HPA }, + /* Devices which report 1 sector over size HPA */ + { "ST340823A", NULL, ATA_HORKAGE_HPA_SIZE, }, + { "ST320413A", NULL, ATA_HORKAGE_HPA_SIZE, }, + /* End Marker */ { } }; +int strn_pattern_cmp(const char *patt, const char *name, int wildchar) +{ + const char *p; + int len; + + /* + * check for trailing wildcard: *\0 + */ + p = strchr(patt, wildchar); + if (p && ((*(p + 1)) == 0)) + len = p - patt; + else { + len = strlen(name); + if (!len) { + if (!*patt) + return 0; + return -1; + } + } + + return strncmp(patt, name, len); +} + static unsigned long ata_dev_blacklisted(const struct ata_device *dev) { unsigned char model_num[ATA_ID_PROD_LEN + 1]; @@ -3820,10 +4036,10 @@ static unsigned long ata_dev_blacklisted(const struct ata_device *dev) ata_id_c_string(dev->id, model_rev, ATA_ID_FW_REV, sizeof(model_rev)); while (ad->model_num) { - if (!strcmp(ad->model_num, model_num)) { + if (!strn_pattern_cmp(ad->model_num, model_num, '*')) { if (ad->model_rev == NULL) return ad->horkage; - if (!strcmp(ad->model_rev, model_rev)) + if (!strn_pattern_cmp(ad->model_rev, model_rev, '*')) return ad->horkage; } ad++; @@ -3837,7 +4053,7 @@ static int ata_dma_blacklisted(const struct ata_device *dev) * DMA blacklist those ATAPI devices with CDB-intr (and use PIO) * if the LLDD handles only interrupts in the HSM_ST_LAST state. */ - if ((dev->ap->flags & ATA_FLAG_PIO_POLLING) && + if ((dev->link->ap->flags & ATA_FLAG_PIO_POLLING) && (dev->flags & ATA_DFLAG_CDB_INTR)) return 1; return (dev->horkage & ATA_HORKAGE_NODMA) ? 1 : 0; @@ -3857,7 +4073,8 @@ static int ata_dma_blacklisted(const struct ata_device *dev) */ static void ata_dev_xfermask(struct ata_device *dev) { - struct ata_port *ap = dev->ap; + struct ata_link *link = dev->link; + struct ata_port *ap = link->ap; struct ata_host *host = ap->host; unsigned long xfer_mask; @@ -3955,7 +4172,43 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev) tf.protocol = ATA_PROT_NODATA; tf.nsect = dev->xfer_mode; - err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); + + DPRINTK("EXIT, err_mask=%x\n", err_mask); + return err_mask; +} + +/** + * ata_dev_set_AN - Issue SET FEATURES - SATA FEATURES + * @dev: Device to which command will be sent + * @enable: Whether to enable or disable the feature + * + * Issue SET FEATURES - SATA FEATURES command to device @dev + * on port @ap with sector count set to indicate Asynchronous + * Notification feature + * + * LOCKING: + * PCI/etc. bus probe sem. + * + * RETURNS: + * 0 on success, AC_ERR_* mask otherwise. + */ +static unsigned int ata_dev_set_AN(struct ata_device *dev, u8 enable) +{ + struct ata_taskfile tf; + unsigned int err_mask; + + /* set up set-features taskfile */ + DPRINTK("set features - SATA features\n"); + + ata_tf_init(dev, &tf); + tf.command = ATA_CMD_SET_FEATURES; + tf.feature = enable; + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.protocol = ATA_PROT_NODATA; + tf.nsect = SATA_AN; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); DPRINTK("EXIT, err_mask=%x\n", err_mask); return err_mask; @@ -3993,7 +4246,7 @@ static unsigned int ata_dev_init_params(struct ata_device *dev, tf.nsect = sectors; tf.device |= (heads - 1) & 0x0f; /* max head = num. of heads - 1 */ - err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); /* A clean abort indicates an original or just out of spec drive and we should continue as we issue the setup based on the drive reported working geometry */ @@ -4207,6 +4460,36 @@ int ata_check_atapi_dma(struct ata_queued_cmd *qc) } /** + * ata_std_qc_defer - Check whether a qc needs to be deferred + * @qc: ATA command in question + * + * Non-NCQ commands cannot run with any other command, NCQ or + * not. As upper layer only knows the queue depth, we are + * responsible for maintaining exclusion. This function checks + * whether a new command @qc can be issued. + * + * LOCKING: + * spin_lock_irqsave(host lock) + * + * RETURNS: + * ATA_DEFER_* if deferring is needed, 0 otherwise. + */ +int ata_std_qc_defer(struct ata_queued_cmd *qc) +{ + struct ata_link *link = qc->dev->link; + + if (qc->tf.protocol == ATA_PROT_NCQ) { + if (!ata_tag_valid(link->active_tag)) + return 0; + } else { + if (!ata_tag_valid(link->active_tag) && !link->sactive) + return 0; + } + + return ATA_DEFER_LINK; +} + +/** * ata_qc_prep - Prepare taskfile for submission * @qc: Metadata associated with taskfile to be prepared * @@ -4482,7 +4765,7 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words) void ata_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data) { - struct ata_port *ap = adev->ap; + struct ata_port *ap = adev->link->ap; unsigned int words = buflen >> 1; /* Transfer multiple of 2 bytes */ @@ -4611,6 +4894,8 @@ static void ata_pio_sectors(struct ata_queued_cmd *qc) ata_pio_sector(qc); } else ata_pio_sector(qc); + + ata_altstatus(qc->ap); /* flush */ } /** @@ -4785,6 +5070,7 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc) VPRINTK("ata%u: xfering %d bytes\n", ap->print_id, bytes); __atapi_pio_bytes(qc, bytes); + ata_altstatus(ap); /* flush */ return; @@ -4956,7 +5242,6 @@ fsm_start: */ ap->hsm_task_state = HSM_ST; ata_pio_sectors(qc); - ata_altstatus(ap); /* flush */ } else /* send CDB */ atapi_send_cdb(ap, qc); @@ -5037,7 +5322,6 @@ fsm_start: if (!(qc->tf.flags & ATA_TFLAG_WRITE)) { ata_pio_sectors(qc); - ata_altstatus(ap); status = ata_wait_idle(ap); } @@ -5057,13 +5341,11 @@ fsm_start: if (ap->hsm_task_state == HSM_ST_LAST && (!(qc->tf.flags & ATA_TFLAG_WRITE))) { /* all data read */ - ata_altstatus(ap); status = ata_wait_idle(ap); goto fsm_start; } } - ata_altstatus(ap); /* flush */ poll_next = 1; break; @@ -5188,7 +5470,7 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap) struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev) { - struct ata_port *ap = dev->ap; + struct ata_port *ap = dev->link->ap; struct ata_queued_cmd *qc; qc = ata_qc_new(ap); @@ -5231,6 +5513,7 @@ void ata_qc_free(struct ata_queued_cmd *qc) void __ata_qc_complete(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; + struct ata_link *link = qc->dev->link; WARN_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */ WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE)); @@ -5239,10 +5522,19 @@ void __ata_qc_complete(struct ata_queued_cmd *qc) ata_sg_clean(qc); /* command should be marked inactive atomically with qc completion */ - if (qc->tf.protocol == ATA_PROT_NCQ) - ap->sactive &= ~(1 << qc->tag); - else - ap->active_tag = ATA_TAG_POISON; + if (qc->tf.protocol == ATA_PROT_NCQ) { + link->sactive &= ~(1 << qc->tag); + if (!link->sactive) + ap->nr_active_links--; + } else { + link->active_tag = ATA_TAG_POISON; + ap->nr_active_links--; + } + + /* clear exclusive status */ + if (unlikely(qc->flags & ATA_QCFLAG_CLEAR_EXCL && + ap->excl_link == link)) + ap->excl_link = NULL; /* atapi: mark qc as inactive to prevent the interrupt handler * from completing the command twice later, before the error handler @@ -5411,19 +5703,25 @@ static inline int ata_should_dma_map(struct ata_queued_cmd *qc) void ata_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; + struct ata_link *link = qc->dev->link; /* Make sure only one non-NCQ command is outstanding. The * check is skipped for old EH because it reuses active qc to * request ATAPI sense. */ - WARN_ON(ap->ops->error_handler && ata_tag_valid(ap->active_tag)); + WARN_ON(ap->ops->error_handler && ata_tag_valid(link->active_tag)); if (qc->tf.protocol == ATA_PROT_NCQ) { - WARN_ON(ap->sactive & (1 << qc->tag)); - ap->sactive |= 1 << qc->tag; + WARN_ON(link->sactive & (1 << qc->tag)); + + if (!link->sactive) + ap->nr_active_links++; + link->sactive |= 1 << qc->tag; } else { - WARN_ON(ap->sactive); - ap->active_tag = qc->tag; + WARN_ON(link->sactive); + + ap->nr_active_links++; + link->active_tag = qc->tag; } qc->flags |= ATA_QCFLAG_ACTIVE; @@ -5606,7 +5904,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) inline unsigned int ata_host_intr (struct ata_port *ap, struct ata_queued_cmd *qc) { - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; u8 status, host_stat = 0; VPRINTK("ata%u: protocol %d task_state %d\n", @@ -5680,7 +5978,8 @@ idle_irq: #ifdef ATA_IRQ_TRAP if ((ap->stats.idle_irq % 1000) == 0) { - ap->ops->irq_ack(ap, 0); /* debug trap */ + ata_chk_status(ap); + ap->ops->irq_clear(ap); ata_port_printk(ap, KERN_WARNING, "irq trap\n"); return 1; } @@ -5721,7 +6020,7 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance) !(ap->flags & ATA_FLAG_DISABLED)) { struct ata_queued_cmd *qc; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) && (qc->flags & ATA_QCFLAG_ACTIVE)) handled |= ata_host_intr(ap, qc); @@ -5735,9 +6034,9 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance) /** * sata_scr_valid - test whether SCRs are accessible - * @ap: ATA port to test SCR accessibility for + * @link: ATA link to test SCR accessibility for * - * Test whether SCRs are accessible for @ap. + * Test whether SCRs are accessible for @link. * * LOCKING: * None. @@ -5745,60 +6044,74 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance) * RETURNS: * 1 if SCRs are accessible, 0 otherwise. */ -int sata_scr_valid(struct ata_port *ap) +int sata_scr_valid(struct ata_link *link) { + struct ata_port *ap = link->ap; + return (ap->flags & ATA_FLAG_SATA) && ap->ops->scr_read; } /** * sata_scr_read - read SCR register of the specified port - * @ap: ATA port to read SCR for + * @link: ATA link to read SCR for * @reg: SCR to read * @val: Place to store read value * - * Read SCR register @reg of @ap into *@val. This function is - * guaranteed to succeed if the cable type of the port is SATA - * and the port implements ->scr_read. + * Read SCR register @reg of @link into *@val. This function is + * guaranteed to succeed if @link is ap->link, the cable type of + * the port is SATA and the port implements ->scr_read. * * LOCKING: - * None. + * None if @link is ap->link. Kernel thread context otherwise. * * RETURNS: * 0 on success, negative errno on failure. */ -int sata_scr_read(struct ata_port *ap, int reg, u32 *val) +int sata_scr_read(struct ata_link *link, int reg, u32 *val) { - if (sata_scr_valid(ap)) - return ap->ops->scr_read(ap, reg, val); - return -EOPNOTSUPP; + if (ata_is_host_link(link)) { + struct ata_port *ap = link->ap; + + if (sata_scr_valid(link)) + return ap->ops->scr_read(ap, reg, val); + return -EOPNOTSUPP; + } + + return sata_pmp_scr_read(link, reg, val); } /** * sata_scr_write - write SCR register of the specified port - * @ap: ATA port to write SCR for + * @link: ATA link to write SCR for * @reg: SCR to write * @val: value to write * - * Write @val to SCR register @reg of @ap. This function is - * guaranteed to succeed if the cable type of the port is SATA - * and the port implements ->scr_read. + * Write @val to SCR register @reg of @link. This function is + * guaranteed to succeed if @link is ap->link, the cable type of + * the port is SATA and the port implements ->scr_read. * * LOCKING: - * None. + * None if @link is ap->link. Kernel thread context otherwise. * * RETURNS: * 0 on success, negative errno on failure. */ -int sata_scr_write(struct ata_port *ap, int reg, u32 val) +int sata_scr_write(struct ata_link *link, int reg, u32 val) { - if (sata_scr_valid(ap)) - return ap->ops->scr_write(ap, reg, val); - return -EOPNOTSUPP; + if (ata_is_host_link(link)) { + struct ata_port *ap = link->ap; + + if (sata_scr_valid(link)) + return ap->ops->scr_write(ap, reg, val); + return -EOPNOTSUPP; + } + + return sata_pmp_scr_write(link, reg, val); } /** * sata_scr_write_flush - write SCR register of the specified port and flush - * @ap: ATA port to write SCR for + * @link: ATA link to write SCR for * @reg: SCR to write * @val: value to write * @@ -5806,31 +6119,36 @@ int sata_scr_write(struct ata_port *ap, int reg, u32 val) * function performs flush after writing to the register. * * LOCKING: - * None. + * None if @link is ap->link. Kernel thread context otherwise. * * RETURNS: * 0 on success, negative errno on failure. */ -int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val) +int sata_scr_write_flush(struct ata_link *link, int reg, u32 val) { - int rc; + if (ata_is_host_link(link)) { + struct ata_port *ap = link->ap; + int rc; - if (sata_scr_valid(ap)) { - rc = ap->ops->scr_write(ap, reg, val); - if (rc == 0) - rc = ap->ops->scr_read(ap, reg, &val); - return rc; + if (sata_scr_valid(link)) { + rc = ap->ops->scr_write(ap, reg, val); + if (rc == 0) + rc = ap->ops->scr_read(ap, reg, &val); + return rc; + } + return -EOPNOTSUPP; } - return -EOPNOTSUPP; + + return sata_pmp_scr_write(link, reg, val); } /** - * ata_port_online - test whether the given port is online - * @ap: ATA port to test + * ata_link_online - test whether the given link is online + * @link: ATA link to test * - * Test whether @ap is online. Note that this function returns 0 - * if online status of @ap cannot be obtained, so - * ata_port_online(ap) != !ata_port_offline(ap). + * Test whether @link is online. Note that this function returns + * 0 if online status of @link cannot be obtained, so + * ata_link_online(link) != !ata_link_offline(link). * * LOCKING: * None. @@ -5838,22 +6156,23 @@ int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val) * RETURNS: * 1 if the port online status is available and online. */ -int ata_port_online(struct ata_port *ap) +int ata_link_online(struct ata_link *link) { u32 sstatus; - if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) == 0x3) + if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0 && + (sstatus & 0xf) == 0x3) return 1; return 0; } /** - * ata_port_offline - test whether the given port is offline - * @ap: ATA port to test + * ata_link_offline - test whether the given link is offline + * @link: ATA link to test * - * Test whether @ap is offline. Note that this function returns - * 0 if offline status of @ap cannot be obtained, so - * ata_port_online(ap) != !ata_port_offline(ap). + * Test whether @link is offline. Note that this function + * returns 0 if offline status of @link cannot be obtained, so + * ata_link_online(link) != !ata_link_offline(link). * * LOCKING: * None. @@ -5861,11 +6180,12 @@ int ata_port_online(struct ata_port *ap) * RETURNS: * 1 if the port offline status is available and offline. */ -int ata_port_offline(struct ata_port *ap) +int ata_link_offline(struct ata_link *link) { u32 sstatus; - if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) != 0x3) + if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0 && + (sstatus & 0xf) != 0x3) return 1; return 0; } @@ -5883,6 +6203,10 @@ int ata_flush_cache(struct ata_device *dev) else cmd = ATA_CMD_FLUSH; + /* This is wrong. On a failed flush we get back the LBA of the lost + sector and we should (assuming it wasn't aborted as unknown) issue + a further flush command to continue the writeback until it + does not error */ err_mask = ata_do_simple_cmd(dev, cmd); if (err_mask) { ata_dev_printk(dev, KERN_ERR, "failed to flush cache\n"); @@ -5902,6 +6226,7 @@ static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg, for (i = 0; i < host->n_ports; i++) { struct ata_port *ap = host->ports[i]; + struct ata_link *link; /* Previous resume operation might still be in * progress. Wait for PM_PENDING to clear. @@ -5921,8 +6246,10 @@ static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg, } ap->pflags |= ATA_PFLAG_PM_PENDING; - ap->eh_info.action |= action; - ap->eh_info.flags |= ehi_flags; + __ata_port_for_each_link(link, ap) { + link->eh_info.action |= action; + link->eh_info.flags |= ehi_flags; + } ata_port_schedule_eh(ap); @@ -6026,12 +6353,13 @@ int ata_port_start(struct ata_port *ap) */ void ata_dev_init(struct ata_device *dev) { - struct ata_port *ap = dev->ap; + struct ata_link *link = dev->link; + struct ata_port *ap = link->ap; unsigned long flags; /* SATA spd limit is bound to the first device */ - ap->sata_spd_limit = ap->hw_sata_spd_limit; - ap->sata_spd = 0; + link->sata_spd_limit = link->hw_sata_spd_limit; + link->sata_spd = 0; /* High bits of dev->flags are used to record warm plug * requests which occur asynchronously. Synchronize using @@ -6050,6 +6378,70 @@ void ata_dev_init(struct ata_device *dev) } /** + * ata_link_init - Initialize an ata_link structure + * @ap: ATA port link is attached to + * @link: Link structure to initialize + * @pmp: Port multiplier port number + * + * Initialize @link. + * + * LOCKING: + * Kernel thread context (may sleep) + */ +void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp) +{ + int i; + + /* clear everything except for devices */ + memset(link, 0, offsetof(struct ata_link, device[0])); + + link->ap = ap; + link->pmp = pmp; + link->active_tag = ATA_TAG_POISON; + link->hw_sata_spd_limit = UINT_MAX; + + /* can't use iterator, ap isn't initialized yet */ + for (i = 0; i < ATA_MAX_DEVICES; i++) { + struct ata_device *dev = &link->device[i]; + + dev->link = link; + dev->devno = dev - link->device; + ata_dev_init(dev); + } +} + +/** + * sata_link_init_spd - Initialize link->sata_spd_limit + * @link: Link to configure sata_spd_limit for + * + * Initialize @link->[hw_]sata_spd_limit to the currently + * configured value. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +int sata_link_init_spd(struct ata_link *link) +{ + u32 scontrol, spd; + int rc; + + rc = sata_scr_read(link, SCR_CONTROL, &scontrol); + if (rc) + return rc; + + spd = (scontrol >> 4) & 0xf; + if (spd) + link->hw_sata_spd_limit &= (1 << spd) - 1; + + link->sata_spd_limit = link->hw_sata_spd_limit; + + return 0; +} + +/** * ata_port_alloc - allocate and initialize basic ATA port resources * @host: ATA host this allocated port belongs to * @@ -6064,7 +6456,6 @@ void ata_dev_init(struct ata_device *dev) struct ata_port *ata_port_alloc(struct ata_host *host) { struct ata_port *ap; - unsigned int i; DPRINTK("ENTER\n"); @@ -6079,9 +6470,6 @@ struct ata_port *ata_port_alloc(struct ata_host *host) ap->ctl = ATA_DEVCTL_OBS; ap->host = host; ap->dev = host->dev; - - ap->hw_sata_spd_limit = UINT_MAX; - ap->active_tag = ATA_TAG_POISON; ap->last_ctl = 0xFF; #if defined(ATA_VERBOSE_DEBUG) @@ -6104,12 +6492,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host) ap->cbl = ATA_CBL_NONE; - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; - dev->ap = ap; - dev->devno = i; - ata_dev_init(dev); - } + ata_link_init(ap, &ap->link, 0); #ifdef ATA_IRQ_TRAP ap->stats.unhandled_irq = 1; @@ -6145,6 +6528,7 @@ static void ata_host_release(struct device *gendev, void *res) if (ap->scsi_host) scsi_host_put(ap->scsi_host); + kfree(ap->pmp_link); kfree(ap); host->ports[i] = NULL; } @@ -6255,6 +6639,7 @@ struct ata_host *ata_host_alloc_pinfo(struct device *dev, ap->mwdma_mask = pi->mwdma_mask; ap->udma_mask = pi->udma_mask; ap->flags |= pi->flags; + ap->link.flags |= pi->link_flags; ap->ops = pi->port_ops; if (!host->ops && (pi->port_ops != &ata_dummy_port_ops)) @@ -6390,8 +6775,6 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) /* set cable, sata_spd_limit and report */ for (i = 0; i < host->n_ports; i++) { struct ata_port *ap = host->ports[i]; - int irq_line; - u32 scontrol; unsigned long xfer_mask; /* set SATA cable type if still unset */ @@ -6399,32 +6782,20 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) ap->cbl = ATA_CBL_SATA; /* init sata_spd_limit to the current value */ - if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) { - int spd = (scontrol >> 4) & 0xf; - if (spd) - ap->hw_sata_spd_limit &= (1 << spd) - 1; - } - ap->sata_spd_limit = ap->hw_sata_spd_limit; - - /* report the secondary IRQ for second channel legacy */ - irq_line = host->irq; - if (i == 1 && host->irq2) - irq_line = host->irq2; + sata_link_init_spd(&ap->link); + /* print per-port info to dmesg */ xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask, ap->udma_mask); - /* print per-port info to dmesg */ - if (!ata_port_is_dummy(ap)) - ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%p " - "ctl 0x%p bmdma 0x%p irq %d\n", + if (!ata_port_is_dummy(ap)) { + ata_port_printk(ap, KERN_INFO, + "%cATA max %s %s\n", (ap->flags & ATA_FLAG_SATA) ? 'S' : 'P', ata_mode_string(xfer_mask), - ap->ioaddr.cmd_addr, - ap->ioaddr.ctl_addr, - ap->ioaddr.bmdma_addr, - irq_line); - else + ap->link.eh_info.desc); + ata_ehi_clear_desc(&ap->link.eh_info); + } else ata_port_printk(ap, KERN_INFO, "DUMMY\n"); } @@ -6436,7 +6807,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) /* probe */ if (ap->ops->error_handler) { - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; unsigned long flags; ata_port_probe(ap); @@ -6444,7 +6815,8 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) /* kick EH for boot probing */ spin_lock_irqsave(ap->lock, flags); - ehi->probe_mask = (1 << ATA_MAX_DEVICES) - 1; + ehi->probe_mask = + (1 << ata_link_max_devices(&ap->link)) - 1; ehi->action |= ATA_EH_SOFTRESET; ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET; @@ -6506,7 +6878,7 @@ int ata_host_activate(struct ata_host *host, int irq, irq_handler_t irq_handler, unsigned long irq_flags, struct scsi_host_template *sht) { - int rc; + int i, rc; rc = ata_host_start(host); if (rc) @@ -6517,8 +6889,8 @@ int ata_host_activate(struct ata_host *host, int irq, if (rc) return rc; - /* Used to print device info at probe */ - host->irq = irq; + for (i = 0; i < host->n_ports; i++) + ata_port_desc(host->ports[i], "irq %d", irq); rc = ata_host_register(host, sht); /* if failed, just free the IRQ and leave ports alone */ @@ -6542,7 +6914,8 @@ int ata_host_activate(struct ata_host *host, int irq, void ata_port_detach(struct ata_port *ap) { unsigned long flags; - int i; + struct ata_link *link; + struct ata_device *dev; if (!ap->ops->error_handler) goto skip_eh; @@ -6559,8 +6932,10 @@ void ata_port_detach(struct ata_port *ap) */ spin_lock_irqsave(ap->lock, flags); - for (i = 0; i < ATA_MAX_DEVICES; i++) - ata_dev_disable(&ap->device[i]); + ata_port_for_each_link(link, ap) { + ata_link_for_each_dev(dev, link) + ata_dev_disable(dev); + } spin_unlock_irqrestore(ap->lock, flags); @@ -6639,7 +7014,7 @@ void ata_std_ports(struct ata_ioports *ioaddr) */ void ata_pci_remove_one(struct pci_dev *pdev) { - struct device *dev = pci_dev_to_dev(pdev); + struct device *dev = &pdev->dev; struct ata_host *host = dev_get_drvdata(dev); ata_host_detach(host); @@ -6847,7 +7222,6 @@ static unsigned int ata_dummy_qc_issue(struct ata_queued_cmd *qc) } const struct ata_port_operations ata_dummy_port_ops = { - .port_disable = ata_port_disable, .check_status = ata_dummy_check_status, .check_altstatus = ata_dummy_check_status, .dev_select = ata_noop_dev_select, @@ -6909,6 +7283,7 @@ EXPORT_SYMBOL_GPL(ata_interrupt); EXPORT_SYMBOL_GPL(ata_do_set_mode); EXPORT_SYMBOL_GPL(ata_data_xfer); EXPORT_SYMBOL_GPL(ata_data_xfer_noirq); +EXPORT_SYMBOL_GPL(ata_std_qc_defer); EXPORT_SYMBOL_GPL(ata_qc_prep); EXPORT_SYMBOL_GPL(ata_dumb_qc_prep); EXPORT_SYMBOL_GPL(ata_noop_qc_prep); @@ -6925,14 +7300,14 @@ 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); +EXPORT_SYMBOL_GPL(sata_link_debounce); +EXPORT_SYMBOL_GPL(sata_link_resume); EXPORT_SYMBOL_GPL(sata_phy_reset); EXPORT_SYMBOL_GPL(__sata_phy_reset); EXPORT_SYMBOL_GPL(ata_bus_reset); EXPORT_SYMBOL_GPL(ata_std_prereset); EXPORT_SYMBOL_GPL(ata_std_softreset); -EXPORT_SYMBOL_GPL(sata_port_hardreset); +EXPORT_SYMBOL_GPL(sata_link_hardreset); EXPORT_SYMBOL_GPL(sata_std_hardreset); EXPORT_SYMBOL_GPL(ata_std_postreset); EXPORT_SYMBOL_GPL(ata_dev_classify); @@ -6953,8 +7328,8 @@ EXPORT_SYMBOL_GPL(sata_scr_valid); EXPORT_SYMBOL_GPL(sata_scr_read); EXPORT_SYMBOL_GPL(sata_scr_write); EXPORT_SYMBOL_GPL(sata_scr_write_flush); -EXPORT_SYMBOL_GPL(ata_port_online); -EXPORT_SYMBOL_GPL(ata_port_offline); +EXPORT_SYMBOL_GPL(ata_link_online); +EXPORT_SYMBOL_GPL(ata_link_offline); #ifdef CONFIG_PM EXPORT_SYMBOL_GPL(ata_host_suspend); EXPORT_SYMBOL_GPL(ata_host_resume); @@ -6985,22 +7360,31 @@ EXPORT_SYMBOL_GPL(ata_pci_default_filter); EXPORT_SYMBOL_GPL(ata_pci_clear_simplex); #endif /* CONFIG_PCI */ +EXPORT_SYMBOL_GPL(sata_pmp_qc_defer_cmd_switch); +EXPORT_SYMBOL_GPL(sata_pmp_std_prereset); +EXPORT_SYMBOL_GPL(sata_pmp_std_hardreset); +EXPORT_SYMBOL_GPL(sata_pmp_std_postreset); +EXPORT_SYMBOL_GPL(sata_pmp_do_eh); + EXPORT_SYMBOL_GPL(__ata_ehi_push_desc); EXPORT_SYMBOL_GPL(ata_ehi_push_desc); EXPORT_SYMBOL_GPL(ata_ehi_clear_desc); +EXPORT_SYMBOL_GPL(ata_port_desc); +#ifdef CONFIG_PCI +EXPORT_SYMBOL_GPL(ata_port_pbar_desc); +#endif /* CONFIG_PCI */ EXPORT_SYMBOL_GPL(ata_eng_timeout); EXPORT_SYMBOL_GPL(ata_port_schedule_eh); +EXPORT_SYMBOL_GPL(ata_link_abort); EXPORT_SYMBOL_GPL(ata_port_abort); EXPORT_SYMBOL_GPL(ata_port_freeze); +EXPORT_SYMBOL_GPL(sata_async_notification); EXPORT_SYMBOL_GPL(ata_eh_freeze_port); EXPORT_SYMBOL_GPL(ata_eh_thaw_port); EXPORT_SYMBOL_GPL(ata_eh_qc_complete); EXPORT_SYMBOL_GPL(ata_eh_qc_retry); EXPORT_SYMBOL_GPL(ata_do_eh); 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); EXPORT_SYMBOL_GPL(ata_cable_40wire); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index ac6ceed4bb60..2eaa39fc65d0 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -33,6 +33,7 @@ */ #include <linux/kernel.h> +#include <linux/pci.h> #include <scsi/scsi.h> #include <scsi/scsi_host.h> #include <scsi/scsi_eh.h> @@ -74,7 +75,6 @@ static const unsigned long ata_eh_reset_timeouts[] = { }; 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); @@ -151,6 +151,73 @@ void ata_ehi_clear_desc(struct ata_eh_info *ehi) ehi->desc_len = 0; } +/** + * ata_port_desc - append port description + * @ap: target ATA port + * @fmt: printf format string + * + * Format string according to @fmt and append it to port + * description. If port description is not empty, " " is added + * in-between. This function is to be used while initializing + * ata_host. The description is printed on host registration. + * + * LOCKING: + * None. + */ +void ata_port_desc(struct ata_port *ap, const char *fmt, ...) +{ + va_list args; + + WARN_ON(!(ap->pflags & ATA_PFLAG_INITIALIZING)); + + if (ap->link.eh_info.desc_len) + __ata_ehi_push_desc(&ap->link.eh_info, " "); + + va_start(args, fmt); + __ata_ehi_pushv_desc(&ap->link.eh_info, fmt, args); + va_end(args); +} + +#ifdef CONFIG_PCI + +/** + * ata_port_pbar_desc - append PCI BAR description + * @ap: target ATA port + * @bar: target PCI BAR + * @offset: offset into PCI BAR + * @name: name of the area + * + * If @offset is negative, this function formats a string which + * contains the name, address, size and type of the BAR and + * appends it to the port description. If @offset is zero or + * positive, only name and offsetted address is appended. + * + * LOCKING: + * None. + */ +void ata_port_pbar_desc(struct ata_port *ap, int bar, ssize_t offset, + const char *name) +{ + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + char *type = ""; + unsigned long long start, len; + + if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) + type = "m"; + else if (pci_resource_flags(pdev, bar) & IORESOURCE_IO) + type = "i"; + + start = (unsigned long long)pci_resource_start(pdev, bar); + len = (unsigned long long)pci_resource_len(pdev, bar); + + if (offset < 0) + ata_port_desc(ap, "%s %s%llu@0x%llx", name, type, len, start); + else + ata_port_desc(ap, "%s 0x%llx", name, start + offset); +} + +#endif /* CONFIG_PCI */ + static void ata_ering_record(struct ata_ering *ering, int is_io, unsigned int err_mask) { @@ -195,28 +262,29 @@ static int ata_ering_map(struct ata_ering *ering, static unsigned int ata_eh_dev_action(struct ata_device *dev) { - struct ata_eh_context *ehc = &dev->ap->eh_context; + struct ata_eh_context *ehc = &dev->link->eh_context; return ehc->i.action | ehc->i.dev_action[dev->devno]; } -static void ata_eh_clear_action(struct ata_device *dev, +static void ata_eh_clear_action(struct ata_link *link, struct ata_device *dev, struct ata_eh_info *ehi, unsigned int action) { - int i; + struct ata_device *tdev; if (!dev) { ehi->action &= ~action; - for (i = 0; i < ATA_MAX_DEVICES; i++) - ehi->dev_action[i] &= ~action; + ata_link_for_each_dev(tdev, link) + ehi->dev_action[tdev->devno] &= ~action; } else { /* doesn't make sense for port-wide EH actions */ WARN_ON(!(action & ATA_EH_PERDEV_MASK)); /* break ehi->action into ehi->dev_action */ if (ehi->action & action) { - for (i = 0; i < ATA_MAX_DEVICES; i++) - ehi->dev_action[i] |= ehi->action & action; + ata_link_for_each_dev(tdev, link) + ehi->dev_action[tdev->devno] |= + ehi->action & action; ehi->action &= ~action; } @@ -261,7 +329,7 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd) ret = EH_HANDLED; spin_lock_irqsave(ap->lock, flags); - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc) { WARN_ON(qc->scsicmd != cmd); qc->flags |= ATA_QCFLAG_EH_SCHEDULED; @@ -290,7 +358,7 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd) void ata_scsi_error(struct Scsi_Host *host) { struct ata_port *ap = ata_shost_to_port(host); - int i, repeat_cnt = ATA_EH_MAX_REPEAT; + int i; unsigned long flags; DPRINTK("ENTER\n"); @@ -356,12 +424,17 @@ void ata_scsi_error(struct Scsi_Host *host) __ata_port_freeze(ap); spin_unlock_irqrestore(ap->lock, flags); + + /* initialize eh_tries */ + ap->eh_tries = ATA_EH_MAX_TRIES; } else spin_unlock_wait(ap->lock); repeat: /* invoke error handler */ if (ap->ops->error_handler) { + struct ata_link *link; + /* kill fast drain timer */ del_timer_sync(&ap->fastdrain_timer); @@ -371,12 +444,15 @@ void ata_scsi_error(struct Scsi_Host *host) /* fetch & clear EH info */ spin_lock_irqsave(ap->lock, flags); - memset(&ap->eh_context, 0, sizeof(ap->eh_context)); - ap->eh_context.i = ap->eh_info; - memset(&ap->eh_info, 0, sizeof(ap->eh_info)); + __ata_port_for_each_link(link, ap) { + memset(&link->eh_context, 0, sizeof(link->eh_context)); + link->eh_context.i = link->eh_info; + memset(&link->eh_info, 0, sizeof(link->eh_info)); + } ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS; ap->pflags &= ~ATA_PFLAG_EH_PENDING; + ap->excl_link = NULL; /* don't maintain exclusion over EH */ spin_unlock_irqrestore(ap->lock, flags); @@ -396,20 +472,18 @@ void ata_scsi_error(struct Scsi_Host *host) spin_lock_irqsave(ap->lock, flags); if (ap->pflags & ATA_PFLAG_EH_PENDING) { - if (--repeat_cnt) { - ata_port_printk(ap, KERN_INFO, - "EH pending after completion, " - "repeating EH (cnt=%d)\n", repeat_cnt); + if (--ap->eh_tries) { spin_unlock_irqrestore(ap->lock, flags); goto repeat; } ata_port_printk(ap, KERN_ERR, "EH pending after %d " - "tries, giving up\n", ATA_EH_MAX_REPEAT); + "tries, giving up\n", ATA_EH_MAX_TRIES); ap->pflags &= ~ATA_PFLAG_EH_PENDING; } /* this run is complete, make sure EH info is clear */ - memset(&ap->eh_info, 0, sizeof(ap->eh_info)); + __ata_port_for_each_link(link, ap) + memset(&link->eh_info, 0, sizeof(link->eh_info)); /* Clear host_eh_scheduled while holding ap->lock such * that if exception occurs after this point but @@ -420,7 +494,7 @@ void ata_scsi_error(struct Scsi_Host *host) spin_unlock_irqrestore(ap->lock, flags); } else { - WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL); + WARN_ON(ata_qc_from_tag(ap, ap->link.active_tag) == NULL); ap->ops->eng_timeout(ap); } @@ -575,7 +649,7 @@ void ata_eng_timeout(struct ata_port *ap) { DPRINTK("ENTER\n"); - ata_qc_timeout(ata_qc_from_tag(ap, ap->active_tag)); + ata_qc_timeout(ata_qc_from_tag(ap, ap->link.active_tag)); DPRINTK("EXIT\n"); } @@ -718,19 +792,7 @@ void ata_port_schedule_eh(struct ata_port *ap) DPRINTK("port EH scheduled\n"); } -/** - * ata_port_abort - abort all qc's on the port - * @ap: ATA port to abort qc's for - * - * Abort all active qc's of @ap and schedule EH. - * - * LOCKING: - * spin_lock_irqsave(host lock) - * - * RETURNS: - * Number of aborted qc's. - */ -int ata_port_abort(struct ata_port *ap) +static int ata_do_link_abort(struct ata_port *ap, struct ata_link *link) { int tag, nr_aborted = 0; @@ -742,7 +804,7 @@ int ata_port_abort(struct ata_port *ap) for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag); - if (qc) { + if (qc && (!link || qc->dev->link == link)) { qc->flags |= ATA_QCFLAG_FAILED; ata_qc_complete(qc); nr_aborted++; @@ -756,6 +818,40 @@ int ata_port_abort(struct ata_port *ap) } /** + * ata_link_abort - abort all qc's on the link + * @link: ATA link to abort qc's for + * + * Abort all active qc's active on @link and schedule EH. + * + * LOCKING: + * spin_lock_irqsave(host lock) + * + * RETURNS: + * Number of aborted qc's. + */ +int ata_link_abort(struct ata_link *link) +{ + return ata_do_link_abort(link->ap, link); +} + +/** + * ata_port_abort - abort all qc's on the port + * @ap: ATA port to abort qc's for + * + * Abort all active qc's of @ap and schedule EH. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + * + * RETURNS: + * Number of aborted qc's. + */ +int ata_port_abort(struct ata_port *ap) +{ + return ata_do_link_abort(ap, NULL); +} + +/** * __ata_port_freeze - freeze port * @ap: ATA port to freeze * @@ -810,6 +906,79 @@ int ata_port_freeze(struct ata_port *ap) } /** + * sata_async_notification - SATA async notification handler + * @ap: ATA port where async notification is received + * + * Handler to be called when async notification via SDB FIS is + * received. This function schedules EH if necessary. + * + * LOCKING: + * spin_lock_irqsave(host lock) + * + * RETURNS: + * 1 if EH is scheduled, 0 otherwise. + */ +int sata_async_notification(struct ata_port *ap) +{ + u32 sntf; + int rc; + + if (!(ap->flags & ATA_FLAG_AN)) + return 0; + + rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf); + if (rc == 0) + sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf); + + if (!ap->nr_pmp_links || rc) { + /* PMP is not attached or SNTF is not available */ + if (!ap->nr_pmp_links) { + /* PMP is not attached. Check whether ATAPI + * AN is configured. If so, notify media + * change. + */ + struct ata_device *dev = ap->link.device; + + if ((dev->class == ATA_DEV_ATAPI) && + (dev->flags & ATA_DFLAG_AN)) + ata_scsi_media_change_notify(dev); + return 0; + } else { + /* PMP is attached but SNTF is not available. + * ATAPI async media change notification is + * not used. The PMP must be reporting PHY + * status change, schedule EH. + */ + ata_port_schedule_eh(ap); + return 1; + } + } else { + /* PMP is attached and SNTF is available */ + struct ata_link *link; + + /* check and notify ATAPI AN */ + ata_port_for_each_link(link, ap) { + if (!(sntf & (1 << link->pmp))) + continue; + + if ((link->device->class == ATA_DEV_ATAPI) && + (link->device->flags & ATA_DFLAG_AN)) + ata_scsi_media_change_notify(link->device); + } + + /* If PMP is reporting that PHY status of some + * downstream ports has changed, schedule EH. + */ + if (sntf & (1 << SATA_PMP_CTRL_PORT)) { + ata_port_schedule_eh(ap); + return 1; + } + + return 0; + } +} + +/** * ata_eh_freeze_port - EH helper to freeze port * @ap: ATA port to freeze * @@ -920,9 +1089,10 @@ void ata_eh_qc_retry(struct ata_queued_cmd *qc) * LOCKING: * None. */ -static void ata_eh_detach_dev(struct ata_device *dev) +void ata_eh_detach_dev(struct ata_device *dev) { - struct ata_port *ap = dev->ap; + struct ata_link *link = dev->link; + struct ata_port *ap = link->ap; unsigned long flags; ata_dev_disable(dev); @@ -937,31 +1107,32 @@ static void ata_eh_detach_dev(struct ata_device *dev) } /* clear per-dev EH actions */ - ata_eh_clear_action(dev, &ap->eh_info, ATA_EH_PERDEV_MASK); - ata_eh_clear_action(dev, &ap->eh_context.i, ATA_EH_PERDEV_MASK); + ata_eh_clear_action(link, dev, &link->eh_info, ATA_EH_PERDEV_MASK); + ata_eh_clear_action(link, dev, &link->eh_context.i, ATA_EH_PERDEV_MASK); spin_unlock_irqrestore(ap->lock, flags); } /** * ata_eh_about_to_do - about to perform eh_action - * @ap: target ATA port + * @link: target ATA link * @dev: target ATA dev for per-dev action (can be NULL) * @action: action about to be performed * * Called just before performing EH actions to clear related bits - * in @ap->eh_info such that eh actions are not unnecessarily + * in @link->eh_info such that eh actions are not unnecessarily * repeated. * * LOCKING: * None. */ -static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev, - unsigned int action) +void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev, + unsigned int action) { + struct ata_port *ap = link->ap; + struct ata_eh_info *ehi = &link->eh_info; + struct ata_eh_context *ehc = &link->eh_context; unsigned long flags; - struct ata_eh_info *ehi = &ap->eh_info; - struct ata_eh_context *ehc = &ap->eh_context; spin_lock_irqsave(ap->lock, flags); @@ -978,7 +1149,7 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev, ehi->flags &= ~ATA_EHI_RESET_MODIFIER_MASK; } - ata_eh_clear_action(dev, ehi, action); + ata_eh_clear_action(link, dev, ehi, action); if (!(ehc->i.flags & ATA_EHI_QUIET)) ap->pflags |= ATA_PFLAG_RECOVERED; @@ -988,26 +1159,28 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev, /** * ata_eh_done - EH action complete - * @ap: target ATA port +* @ap: target ATA port * @dev: target ATA dev for per-dev action (can be NULL) * @action: action just completed * * Called right after performing EH actions to clear related bits - * in @ap->eh_context. + * in @link->eh_context. * * LOCKING: * None. */ -static void ata_eh_done(struct ata_port *ap, struct ata_device *dev, - unsigned int action) +void ata_eh_done(struct ata_link *link, struct ata_device *dev, + unsigned int action) { + struct ata_eh_context *ehc = &link->eh_context; + /* if reset is complete, clear all reset actions & reset modifier */ if (action & ATA_EH_RESET_MASK) { action |= ATA_EH_RESET_MASK; - ap->eh_context.i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK; + ehc->i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK; } - ata_eh_clear_action(dev, &ap->eh_context.i, action); + ata_eh_clear_action(link, dev, &ehc->i, action); } /** @@ -1077,7 +1250,7 @@ static unsigned int ata_read_log_page(struct ata_device *dev, tf.protocol = ATA_PROT_PIO; err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, - buf, sectors * ATA_SECT_SIZE); + buf, sectors * ATA_SECT_SIZE, 0); DPRINTK("EXIT, err_mask=%x\n", err_mask); return err_mask; @@ -1101,7 +1274,7 @@ static unsigned int ata_read_log_page(struct ata_device *dev, static int ata_eh_read_log_10h(struct ata_device *dev, int *tag, struct ata_taskfile *tf) { - u8 *buf = dev->ap->sector_buf; + u8 *buf = dev->link->ap->sector_buf; unsigned int err_mask; u8 csum; int i; @@ -1155,7 +1328,7 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc) { struct ata_device *dev = qc->dev; unsigned char *sense_buf = qc->scsicmd->sense_buffer; - struct ata_port *ap = dev->ap; + struct ata_port *ap = dev->link->ap; struct ata_taskfile tf; u8 cdb[ATAPI_CDB_LEN]; @@ -1191,12 +1364,12 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc) } return ata_exec_internal(dev, &tf, cdb, DMA_FROM_DEVICE, - sense_buf, SCSI_SENSE_BUFFERSIZE); + sense_buf, SCSI_SENSE_BUFFERSIZE, 0); } /** * ata_eh_analyze_serror - analyze SError for a failed port - * @ap: ATA port to analyze SError for + * @link: ATA link to analyze SError for * * Analyze SError if available and further determine cause of * failure. @@ -1204,11 +1377,12 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc) * LOCKING: * None. */ -static void ata_eh_analyze_serror(struct ata_port *ap) +static void ata_eh_analyze_serror(struct ata_link *link) { - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_eh_context *ehc = &link->eh_context; u32 serror = ehc->i.serror; unsigned int err_mask = 0, action = 0; + u32 hotplug_mask; if (serror & SERR_PERSISTENT) { err_mask |= AC_ERR_ATA_BUS; @@ -1227,7 +1401,20 @@ static void ata_eh_analyze_serror(struct ata_port *ap) err_mask |= AC_ERR_SYSTEM; action |= ATA_EH_HARDRESET; } - if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG)) + + /* Determine whether a hotplug event has occurred. Both + * SError.N/X are considered hotplug events for enabled or + * host links. For disabled PMP links, only N bit is + * considered as X bit is left at 1 for link plugging. + */ + hotplug_mask = 0; + + if (!(link->flags & ATA_LFLAG_DISABLED) || ata_is_host_link(link)) + hotplug_mask = SERR_PHYRDY_CHG | SERR_DEV_XCHG; + else + hotplug_mask = SERR_PHYRDY_CHG; + + if (serror & hotplug_mask) ata_ehi_hotplugged(&ehc->i); ehc->i.err_mask |= err_mask; @@ -1236,7 +1423,7 @@ static void ata_eh_analyze_serror(struct ata_port *ap) /** * ata_eh_analyze_ncq_error - analyze NCQ error - * @ap: ATA port to analyze NCQ error for + * @link: ATA link to analyze NCQ error for * * Read log page 10h, determine the offending qc and acquire * error status TF. For NCQ device errors, all LLDDs have to do @@ -1246,10 +1433,11 @@ static void ata_eh_analyze_serror(struct ata_port *ap) * LOCKING: * Kernel thread context (may sleep). */ -static void ata_eh_analyze_ncq_error(struct ata_port *ap) +static void ata_eh_analyze_ncq_error(struct ata_link *link) { - struct ata_eh_context *ehc = &ap->eh_context; - struct ata_device *dev = ap->device; + struct ata_port *ap = link->ap; + struct ata_eh_context *ehc = &link->eh_context; + struct ata_device *dev = link->device; struct ata_queued_cmd *qc; struct ata_taskfile tf; int tag, rc; @@ -1259,7 +1447,7 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap) return; /* is it NCQ device error? */ - if (!ap->sactive || !(ehc->i.err_mask & AC_ERR_DEV)) + if (!link->sactive || !(ehc->i.err_mask & AC_ERR_DEV)) return; /* has LLDD analyzed already? */ @@ -1276,13 +1464,13 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap) /* okay, this error is ours */ rc = ata_eh_read_log_10h(dev, &tag, &tf); if (rc) { - ata_port_printk(ap, KERN_ERR, "failed to read log page 10h " + ata_link_printk(link, KERN_ERR, "failed to read log page 10h " "(errno=%d)\n", rc); return; } - if (!(ap->sactive & (1 << tag))) { - ata_port_printk(ap, KERN_ERR, "log page 10h reported " + if (!(link->sactive & (1 << tag))) { + ata_link_printk(link, KERN_ERR, "log page 10h reported " "inactive tag %d\n", tag); return; } @@ -1497,7 +1685,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io, /* speed down? */ if (verdict & ATA_EH_SPDN_SPEED_DOWN) { /* speed down SATA link speed if possible */ - if (sata_down_spd_limit(dev->ap) == 0) { + if (sata_down_spd_limit(dev->link) == 0) { action |= ATA_EH_HARDRESET; goto done; } @@ -1528,7 +1716,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io, * 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->link->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; @@ -1545,19 +1733,20 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io, } /** - * ata_eh_autopsy - analyze error and determine recovery action - * @ap: ATA port to perform autopsy on + * ata_eh_link_autopsy - analyze error and determine recovery action + * @link: host link to perform autopsy on * - * Analyze why @ap failed and determine which recovery action is - * needed. This function also sets more detailed AC_ERR_* values - * and fills sense data for ATAPI CHECK SENSE. + * Analyze why @link failed and determine which recovery actions + * are needed. This function also sets more detailed AC_ERR_* + * values and fills sense data for ATAPI CHECK SENSE. * * LOCKING: * Kernel thread context (may sleep). */ -static void ata_eh_autopsy(struct ata_port *ap) +static void ata_eh_link_autopsy(struct ata_link *link) { - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_port *ap = link->ap; + struct ata_eh_context *ehc = &link->eh_context; unsigned int all_err_mask = 0; int tag, is_io = 0; u32 serror; @@ -1569,10 +1758,10 @@ static void ata_eh_autopsy(struct ata_port *ap) return; /* obtain and analyze SError */ - rc = sata_scr_read(ap, SCR_ERROR, &serror); + rc = sata_scr_read(link, SCR_ERROR, &serror); if (rc == 0) { ehc->i.serror |= serror; - ata_eh_analyze_serror(ap); + ata_eh_analyze_serror(link); } else if (rc != -EOPNOTSUPP) { /* SError read failed, force hardreset and probing */ ata_ehi_schedule_probe(&ehc->i); @@ -1581,7 +1770,7 @@ static void ata_eh_autopsy(struct ata_port *ap) } /* analyze NCQ failure */ - ata_eh_analyze_ncq_error(ap); + ata_eh_analyze_ncq_error(link); /* any real error trumps AC_ERR_OTHER */ if (ehc->i.err_mask & ~AC_ERR_OTHER) @@ -1592,7 +1781,7 @@ static void ata_eh_autopsy(struct ata_port *ap) for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); - if (!(qc->flags & ATA_QCFLAG_FAILED)) + if (!(qc->flags & ATA_QCFLAG_FAILED) || qc->dev->link != link) continue; /* inherit upper level err_mask */ @@ -1646,20 +1835,43 @@ static void ata_eh_autopsy(struct ata_port *ap) } /** - * ata_eh_report - report error handling to user - * @ap: ATA port EH is going on + * ata_eh_autopsy - analyze error and determine recovery action + * @ap: host port to perform autopsy on + * + * Analyze all links of @ap and determine why they failed and + * which recovery actions are needed. + * + * LOCKING: + * Kernel thread context (may sleep). + */ +void ata_eh_autopsy(struct ata_port *ap) +{ + struct ata_link *link; + + __ata_port_for_each_link(link, ap) + ata_eh_link_autopsy(link); +} + +/** + * ata_eh_link_report - report error handling to user + * @link: ATA link EH is going on * * Report EH to user. * * LOCKING: * None. */ -static void ata_eh_report(struct ata_port *ap) +static void ata_eh_link_report(struct ata_link *link) { - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_port *ap = link->ap; + struct ata_eh_context *ehc = &link->eh_context; const char *frozen, *desc; + char tries_buf[6]; int tag, nr_failed = 0; + if (ehc->i.flags & ATA_EHI_QUIET) + return; + desc = NULL; if (ehc->i.desc[0] != '\0') desc = ehc->i.desc; @@ -1667,7 +1879,7 @@ static void ata_eh_report(struct ata_port *ap) for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); - if (!(qc->flags & ATA_QCFLAG_FAILED)) + if (!(qc->flags & ATA_QCFLAG_FAILED) || qc->dev->link != link) continue; if (qc->flags & ATA_QCFLAG_SENSE_VALID && !qc->err_mask) continue; @@ -1682,22 +1894,48 @@ static void ata_eh_report(struct ata_port *ap) if (ap->pflags & ATA_PFLAG_FROZEN) frozen = " frozen"; + memset(tries_buf, 0, sizeof(tries_buf)); + if (ap->eh_tries < ATA_EH_MAX_TRIES) + snprintf(tries_buf, sizeof(tries_buf) - 1, " t%d", + ap->eh_tries); + if (ehc->i.dev) { ata_dev_printk(ehc->i.dev, KERN_ERR, "exception Emask 0x%x " - "SAct 0x%x SErr 0x%x action 0x%x%s\n", - ehc->i.err_mask, ap->sactive, ehc->i.serror, - ehc->i.action, frozen); + "SAct 0x%x SErr 0x%x action 0x%x%s%s\n", + ehc->i.err_mask, link->sactive, ehc->i.serror, + ehc->i.action, frozen, tries_buf); if (desc) ata_dev_printk(ehc->i.dev, KERN_ERR, "%s\n", desc); } else { - ata_port_printk(ap, KERN_ERR, "exception Emask 0x%x " - "SAct 0x%x SErr 0x%x action 0x%x%s\n", - ehc->i.err_mask, ap->sactive, ehc->i.serror, - ehc->i.action, frozen); + ata_link_printk(link, KERN_ERR, "exception Emask 0x%x " + "SAct 0x%x SErr 0x%x action 0x%x%s%s\n", + ehc->i.err_mask, link->sactive, ehc->i.serror, + ehc->i.action, frozen, tries_buf); if (desc) - ata_port_printk(ap, KERN_ERR, "%s\n", desc); + ata_link_printk(link, KERN_ERR, "%s\n", desc); } + if (ehc->i.serror) + ata_port_printk(ap, KERN_ERR, + "SError: { %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s}\n", + ehc->i.serror & SERR_DATA_RECOVERED ? "RecovData " : "", + ehc->i.serror & SERR_COMM_RECOVERED ? "RecovComm " : "", + ehc->i.serror & SERR_DATA ? "UnrecovData " : "", + ehc->i.serror & SERR_PERSISTENT ? "Persist " : "", + ehc->i.serror & SERR_PROTOCOL ? "Proto " : "", + ehc->i.serror & SERR_INTERNAL ? "HostInt " : "", + ehc->i.serror & SERR_PHYRDY_CHG ? "PHYRdyChg " : "", + ehc->i.serror & SERR_PHY_INT_ERR ? "PHYInt " : "", + ehc->i.serror & SERR_COMM_WAKE ? "CommWake " : "", + ehc->i.serror & SERR_10B_8B_ERR ? "10B8B " : "", + ehc->i.serror & SERR_DISPARITY ? "Dispar " : "", + ehc->i.serror & SERR_CRC ? "BadCRC " : "", + ehc->i.serror & SERR_HANDSHAKE ? "Handshk " : "", + ehc->i.serror & SERR_LINK_SEQ_ERR ? "LinkSeq " : "", + ehc->i.serror & SERR_TRANS_ST_ERROR ? "TrStaTrns " : "", + ehc->i.serror & SERR_UNRECOG_FIS ? "UnrecFIS " : "", + ehc->i.serror & SERR_DEV_XCHG ? "DevExch " : "" ); + for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { static const char *dma_str[] = { [DMA_BIDIRECTIONAL] = "bidi", @@ -1708,7 +1946,8 @@ static void ata_eh_report(struct ata_port *ap) struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); struct ata_taskfile *cmd = &qc->tf, *res = &qc->result_tf; - if (!(qc->flags & ATA_QCFLAG_FAILED) || !qc->err_mask) + if (!(qc->flags & ATA_QCFLAG_FAILED) || + qc->dev->link != link || !qc->err_mask) continue; ata_dev_printk(qc->dev, KERN_ERR, @@ -1728,18 +1967,60 @@ static void ata_eh_report(struct ata_port *ap) res->hob_lbal, res->hob_lbam, res->hob_lbah, res->device, qc->err_mask, ata_err_string(qc->err_mask), qc->err_mask & AC_ERR_NCQ ? " <F>" : ""); + + if (res->command & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ | + ATA_ERR) ) { + if (res->command & ATA_BUSY) + ata_dev_printk(qc->dev, KERN_ERR, + "status: { Busy }\n" ); + else + ata_dev_printk(qc->dev, KERN_ERR, + "status: { %s%s%s%s}\n", + res->command & ATA_DRDY ? "DRDY " : "", + res->command & ATA_DF ? "DF " : "", + res->command & ATA_DRQ ? "DRQ " : "", + res->command & ATA_ERR ? "ERR " : "" ); + } + + if (cmd->command != ATA_CMD_PACKET && + (res->feature & (ATA_ICRC | ATA_UNC | ATA_IDNF | + ATA_ABORTED))) + ata_dev_printk(qc->dev, KERN_ERR, + "error: { %s%s%s%s}\n", + res->feature & ATA_ICRC ? "ICRC " : "", + res->feature & ATA_UNC ? "UNC " : "", + res->feature & ATA_IDNF ? "IDNF " : "", + res->feature & ATA_ABORTED ? "ABRT " : "" ); } } -static int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset, +/** + * ata_eh_report - report error handling to user + * @ap: ATA port to report EH about + * + * Report EH to user. + * + * LOCKING: + * None. + */ +void ata_eh_report(struct ata_port *ap) +{ + struct ata_link *link; + + __ata_port_for_each_link(link, ap) + ata_eh_link_report(link); +} + +static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset, unsigned int *classes, unsigned long deadline) { - int i, rc; + struct ata_device *dev; + int rc; - for (i = 0; i < ATA_MAX_DEVICES; i++) - classes[i] = ATA_DEV_UNKNOWN; + ata_link_for_each_dev(dev, link) + classes[dev->devno] = ATA_DEV_UNKNOWN; - rc = reset(ap, classes, deadline); + rc = reset(link, classes, deadline); if (rc) return rc; @@ -1747,71 +2028,87 @@ static int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset, * is complete and convert all ATA_DEV_UNKNOWN to * ATA_DEV_NONE. */ - for (i = 0; i < ATA_MAX_DEVICES; i++) - if (classes[i] != ATA_DEV_UNKNOWN) + ata_link_for_each_dev(dev, link) + if (classes[dev->devno] != ATA_DEV_UNKNOWN) break; - if (i < ATA_MAX_DEVICES) - for (i = 0; i < ATA_MAX_DEVICES; i++) - if (classes[i] == ATA_DEV_UNKNOWN) - classes[i] = ATA_DEV_NONE; + if (dev) { + ata_link_for_each_dev(dev, link) { + if (classes[dev->devno] == ATA_DEV_UNKNOWN) + classes[dev->devno] = ATA_DEV_NONE; + } + } return 0; } -static int ata_eh_followup_srst_needed(int rc, int classify, +static int ata_eh_followup_srst_needed(struct ata_link *link, + int rc, int classify, const unsigned int *classes) { + if (link->flags & ATA_LFLAG_NO_SRST) + return 0; if (rc == -EAGAIN) return 1; if (rc != 0) return 0; - if (classify && classes[0] == ATA_DEV_UNKNOWN) + if ((link->ap->flags & ATA_FLAG_PMP) && ata_is_host_link(link)) + return 1; + if (classify && !(link->flags & ATA_LFLAG_ASSUME_CLASS) && + classes[0] == ATA_DEV_UNKNOWN) return 1; return 0; } -static int ata_eh_reset(struct ata_port *ap, int classify, - ata_prereset_fn_t prereset, ata_reset_fn_t softreset, - ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) +int ata_eh_reset(struct ata_link *link, int classify, + ata_prereset_fn_t prereset, ata_reset_fn_t softreset, + ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) { - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_port *ap = link->ap; + struct ata_eh_context *ehc = &link->eh_context; unsigned int *classes = ehc->classes; int verbose = !(ehc->i.flags & ATA_EHI_QUIET); int try = 0; + struct ata_device *dev; unsigned long deadline; unsigned int action; ata_reset_fn_t reset; - int i, rc; + unsigned long flags; + int rc; /* about to reset */ - ata_eh_about_to_do(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK); + spin_lock_irqsave(ap->lock, flags); + ap->pflags |= ATA_PFLAG_RESETTING; + spin_unlock_irqrestore(ap->lock, flags); + + ata_eh_about_to_do(link, NULL, ehc->i.action & ATA_EH_RESET_MASK); /* Determine which reset to use and record in ehc->i.action. * prereset() may examine and modify it. */ action = ehc->i.action; ehc->i.action &= ~ATA_EH_RESET_MASK; - if (softreset && (!hardreset || (!sata_set_spd_needed(ap) && + if (softreset && (!hardreset || (!(link->flags & ATA_LFLAG_NO_SRST) && + !sata_set_spd_needed(link) && !(action & ATA_EH_HARDRESET)))) ehc->i.action |= ATA_EH_SOFTRESET; else ehc->i.action |= ATA_EH_HARDRESET; if (prereset) { - rc = prereset(ap, jiffies + ATA_EH_PRERESET_TIMEOUT); + rc = prereset(link, jiffies + ATA_EH_PRERESET_TIMEOUT); if (rc) { if (rc == -ENOENT) { - ata_port_printk(ap, KERN_DEBUG, + ata_link_printk(link, KERN_DEBUG, "port disabled. ignoring.\n"); - ap->eh_context.i.action &= ~ATA_EH_RESET_MASK; + ehc->i.action &= ~ATA_EH_RESET_MASK; - for (i = 0; i < ATA_MAX_DEVICES; i++) - classes[i] = ATA_DEV_NONE; + ata_link_for_each_dev(dev, link) + classes[dev->devno] = ATA_DEV_NONE; rc = 0; } else - ata_port_printk(ap, KERN_ERR, + ata_link_printk(link, KERN_ERR, "prereset failed (errno=%d)\n", rc); goto out; } @@ -1824,8 +2121,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify, reset = softreset; else { /* prereset told us not to reset, bang classes and return */ - for (i = 0; i < ATA_MAX_DEVICES; i++) - classes[i] = ATA_DEV_NONE; + ata_link_for_each_dev(dev, link) + classes[dev->devno] = ATA_DEV_NONE; rc = 0; goto out; } @@ -1843,7 +2140,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, /* shut up during boot probing */ if (verbose) - ata_port_printk(ap, KERN_INFO, "%s resetting port\n", + ata_link_printk(link, KERN_INFO, "%s resetting link\n", reset == softreset ? "soft" : "hard"); /* mark that this EH session started with reset */ @@ -1852,49 +2149,54 @@ static int ata_eh_reset(struct ata_port *ap, int classify, else ehc->i.flags |= ATA_EHI_DID_SOFTRESET; - rc = ata_do_reset(ap, reset, classes, deadline); + rc = ata_do_reset(link, reset, classes, deadline); if (reset == hardreset && - ata_eh_followup_srst_needed(rc, classify, classes)) { + ata_eh_followup_srst_needed(link, rc, classify, classes)) { /* okay, let's do follow-up softreset */ reset = softreset; if (!reset) { - ata_port_printk(ap, KERN_ERR, + ata_link_printk(link, KERN_ERR, "follow-up softreset required " "but no softreset avaliable\n"); rc = -EINVAL; goto out; } - ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK); - rc = ata_do_reset(ap, reset, classes, deadline); + ata_eh_about_to_do(link, NULL, ATA_EH_RESET_MASK); + rc = ata_do_reset(link, reset, classes, deadline); - if (rc == 0 && classify && - classes[0] == ATA_DEV_UNKNOWN) { - ata_port_printk(ap, KERN_ERR, + if (rc == 0 && classify && classes[0] == ATA_DEV_UNKNOWN && + !(link->flags & ATA_LFLAG_ASSUME_CLASS)) { + ata_link_printk(link, KERN_ERR, "classification failed\n"); rc = -EINVAL; goto out; } } - if (rc && try < ARRAY_SIZE(ata_eh_reset_timeouts)) { + /* if we skipped follow-up srst, clear rc */ + if (rc == -EAGAIN) + rc = 0; + + if (rc && rc != -ERESTART && try < ARRAY_SIZE(ata_eh_reset_timeouts)) { unsigned long now = jiffies; if (time_before(now, deadline)) { unsigned long delta = deadline - jiffies; - ata_port_printk(ap, KERN_WARNING, "reset failed " + ata_link_printk(link, KERN_WARNING, "reset failed " "(errno=%d), retrying in %u secs\n", rc, (jiffies_to_msecs(delta) + 999) / 1000); - schedule_timeout_uninterruptible(delta); + while (delta) + delta = schedule_timeout_uninterruptible(delta); } if (rc == -EPIPE || try == ARRAY_SIZE(ata_eh_reset_timeouts) - 1) - sata_down_spd_limit(ap); + sata_down_spd_limit(link); if (hardreset) reset = hardreset; goto retry; @@ -1903,37 +2205,56 @@ static int ata_eh_reset(struct ata_port *ap, int classify, if (rc == 0) { u32 sstatus; - /* After the reset, the device state is PIO 0 and the - * controller state is undefined. Record the mode. - */ - for (i = 0; i < ATA_MAX_DEVICES; i++) - ap->device[i].pio_mode = XFER_PIO_0; + ata_link_for_each_dev(dev, link) { + /* After the reset, the device state is PIO 0 + * and the controller state is undefined. + * Record the mode. + */ + dev->pio_mode = XFER_PIO_0; + + if (ata_link_offline(link)) + continue; + + /* apply class override and convert UNKNOWN to NONE */ + if (link->flags & ATA_LFLAG_ASSUME_ATA) + classes[dev->devno] = ATA_DEV_ATA; + else if (link->flags & ATA_LFLAG_ASSUME_SEMB) + classes[dev->devno] = ATA_DEV_SEMB_UNSUP; /* not yet */ + else if (classes[dev->devno] == ATA_DEV_UNKNOWN) + classes[dev->devno] = ATA_DEV_NONE; + } /* record current link speed */ - if (sata_scr_read(ap, SCR_STATUS, &sstatus) == 0) - ap->sata_spd = (sstatus >> 4) & 0xf; + if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0) + link->sata_spd = (sstatus >> 4) & 0xf; if (postreset) - postreset(ap, classes); + postreset(link, classes); /* reset successful, schedule revalidation */ - ata_eh_done(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK); + ata_eh_done(link, NULL, ehc->i.action & ATA_EH_RESET_MASK); ehc->i.action |= ATA_EH_REVALIDATE; } out: /* clear hotplug flag */ ehc->i.flags &= ~ATA_EHI_HOTPLUGGED; + + spin_lock_irqsave(ap->lock, flags); + ap->pflags &= ~ATA_PFLAG_RESETTING; + spin_unlock_irqrestore(ap->lock, flags); + return rc; } -static int ata_eh_revalidate_and_attach(struct ata_port *ap, +static int ata_eh_revalidate_and_attach(struct ata_link *link, struct ata_device **r_failed_dev) { - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_port *ap = link->ap; + struct ata_eh_context *ehc = &link->eh_context; struct ata_device *dev; unsigned int new_mask = 0; unsigned long flags; - int i, rc = 0; + int rc = 0; DPRINTK("ENTER\n"); @@ -1941,27 +2262,28 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, * be done backwards such that PDIAG- is released by the slave * device before the master device is identified. */ - for (i = ATA_MAX_DEVICES - 1; i >= 0; i--) { - unsigned int action, readid_flags = 0; - - dev = &ap->device[i]; - action = ata_eh_dev_action(dev); + ata_link_for_each_dev_reverse(dev, link) { + unsigned int action = ata_eh_dev_action(dev); + unsigned int readid_flags = 0; if (ehc->i.flags & ATA_EHI_DID_RESET) readid_flags |= ATA_READID_POSTRESET; if ((action & ATA_EH_REVALIDATE) && ata_dev_enabled(dev)) { - if (ata_port_offline(ap)) { + WARN_ON(dev->class == ATA_DEV_PMP); + + if (ata_link_offline(link)) { rc = -EIO; goto err; } - ata_eh_about_to_do(ap, dev, ATA_EH_REVALIDATE); - rc = ata_dev_revalidate(dev, readid_flags); + ata_eh_about_to_do(link, dev, ATA_EH_REVALIDATE); + rc = ata_dev_revalidate(dev, ehc->classes[dev->devno], + readid_flags); if (rc) goto err; - ata_eh_done(ap, dev, ATA_EH_REVALIDATE); + ata_eh_done(link, dev, ATA_EH_REVALIDATE); /* Configuration may have changed, reconfigure * transfer mode. @@ -1975,11 +2297,14 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, ata_class_enabled(ehc->classes[dev->devno])) { dev->class = ehc->classes[dev->devno]; - rc = ata_dev_read_id(dev, &dev->class, readid_flags, - dev->id); + if (dev->class == ATA_DEV_PMP) + rc = sata_pmp_attach(dev); + else + rc = ata_dev_read_id(dev, &dev->class, + readid_flags, dev->id); switch (rc) { case 0: - new_mask |= 1 << i; + new_mask |= 1 << dev->devno; break; case -ENOENT: /* IDENTIFY was issued to non-existent @@ -1997,16 +2322,16 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, } /* PDIAG- should have been released, ask cable type if post-reset */ - if ((ehc->i.flags & ATA_EHI_DID_RESET) && ap->ops->cable_detect) + if (ata_is_host_link(link) && ap->ops->cable_detect && + (ehc->i.flags & ATA_EHI_DID_RESET)) ap->cbl = ap->ops->cable_detect(ap); /* Configure new devices forward such that user doesn't see * device detection messages backwards. */ - for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->device[i]; - - if (!(new_mask & (1 << i))) + ata_link_for_each_dev(dev, link) { + if (!(new_mask & (1 << dev->devno)) || + dev->class == ATA_DEV_PMP) continue; ehc->i.flags |= ATA_EHI_PRINTINFO; @@ -2031,40 +2356,44 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, return rc; } -static int ata_port_nr_enabled(struct ata_port *ap) +static int ata_link_nr_enabled(struct ata_link *link) { - int i, cnt = 0; + struct ata_device *dev; + int cnt = 0; - for (i = 0; i < ATA_MAX_DEVICES; i++) - if (ata_dev_enabled(&ap->device[i])) + ata_link_for_each_dev(dev, link) + if (ata_dev_enabled(dev)) cnt++; return cnt; } -static int ata_port_nr_vacant(struct ata_port *ap) +static int ata_link_nr_vacant(struct ata_link *link) { - int i, cnt = 0; + struct ata_device *dev; + int cnt = 0; - for (i = 0; i < ATA_MAX_DEVICES; i++) - if (ap->device[i].class == ATA_DEV_UNKNOWN) + ata_link_for_each_dev(dev, link) + if (dev->class == ATA_DEV_UNKNOWN) cnt++; return cnt; } -static int ata_eh_skip_recovery(struct ata_port *ap) +static int ata_eh_skip_recovery(struct ata_link *link) { - struct ata_eh_context *ehc = &ap->eh_context; - int i; + struct ata_eh_context *ehc = &link->eh_context; + struct ata_device *dev; + + /* skip disabled links */ + if (link->flags & ATA_LFLAG_DISABLED) + return 1; /* thaw frozen port, resume link and recover failed devices */ - if ((ap->pflags & ATA_PFLAG_FROZEN) || - (ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_port_nr_enabled(ap)) + if ((link->ap->pflags & ATA_PFLAG_FROZEN) || + (ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_link_nr_enabled(link)) return 0; /* skip if class codes for all vacant slots are ATA_DEV_NONE */ - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; - + ata_link_for_each_dev(dev, link) { if (dev->class == ATA_DEV_UNKNOWN && ehc->classes[dev->devno] != ATA_DEV_NONE) return 0; @@ -2073,10 +2402,9 @@ static int ata_eh_skip_recovery(struct ata_port *ap) return 1; } -static void ata_eh_handle_dev_fail(struct ata_device *dev, int err) +static int ata_eh_handle_dev_fail(struct ata_device *dev, int err) { - struct ata_port *ap = dev->ap; - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_eh_context *ehc = &dev->link->eh_context; ehc->tries[dev->devno]--; @@ -2092,7 +2420,7 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err) /* This is the last chance, better to slow * down than lose it. */ - sata_down_spd_limit(ap); + sata_down_spd_limit(dev->link); ata_down_xfermask_limit(dev, ATA_DNXFER_PIO); } } @@ -2102,7 +2430,7 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err) ata_dev_disable(dev); /* detach if offline */ - if (ata_port_offline(ap)) + if (ata_link_offline(dev->link)) ata_eh_detach_dev(dev); /* probe if requested */ @@ -2115,12 +2443,16 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err) ehc->did_probe_mask |= (1 << dev->devno); ehc->i.action |= ATA_EH_SOFTRESET; } + + return 1; } else { /* soft didn't work? be haaaaard */ if (ehc->i.flags & ATA_EHI_DID_RESET) ehc->i.action |= ATA_EH_HARDRESET; else ehc->i.action |= ATA_EH_SOFTRESET; + + return 0; } } @@ -2131,12 +2463,13 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err) * @softreset: softreset method (can be NULL) * @hardreset: hardreset method (can be NULL) * @postreset: postreset method (can be NULL) + * @r_failed_link: out parameter for failed link * * This is the alpha and omega, eum and yang, heart and soul of * libata exception handling. On entry, actions required to - * recover the port and hotplug requests are recorded in - * eh_context. This function executes all the operations with - * appropriate retrials and fallbacks to resurrect failed + * recover each link and hotplug requests are recorded in the + * link's eh_context. This function executes all the operations + * with appropriate retrials and fallbacks to resurrect failed * devices, detach goners and greet newcomers. * * LOCKING: @@ -2145,104 +2478,171 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err) * RETURNS: * 0 on success, -errno on failure. */ -static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, - ata_reset_fn_t softreset, ata_reset_fn_t hardreset, - ata_postreset_fn_t postreset) +int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, + ata_reset_fn_t softreset, ata_reset_fn_t hardreset, + ata_postreset_fn_t postreset, + struct ata_link **r_failed_link) { - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_link *link; struct ata_device *dev; - int i, rc; + int nr_failed_devs, nr_disabled_devs; + int reset, rc; + unsigned long flags; DPRINTK("ENTER\n"); /* prep for recovery */ - for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->device[i]; - - ehc->tries[dev->devno] = ATA_EH_DEV_TRIES; - - /* collect port action mask recorded in dev actions */ - ehc->i.action |= ehc->i.dev_action[i] & ~ATA_EH_PERDEV_MASK; - ehc->i.dev_action[i] &= ATA_EH_PERDEV_MASK; - - /* process hotplug request */ - if (dev->flags & ATA_DFLAG_DETACH) - ata_eh_detach_dev(dev); + ata_port_for_each_link(link, ap) { + struct ata_eh_context *ehc = &link->eh_context; + + /* re-enable link? */ + if (ehc->i.action & ATA_EH_ENABLE_LINK) { + ata_eh_about_to_do(link, NULL, ATA_EH_ENABLE_LINK); + spin_lock_irqsave(ap->lock, flags); + link->flags &= ~ATA_LFLAG_DISABLED; + spin_unlock_irqrestore(ap->lock, flags); + ata_eh_done(link, NULL, ATA_EH_ENABLE_LINK); + } - if (!ata_dev_enabled(dev) && - ((ehc->i.probe_mask & (1 << dev->devno)) && - !(ehc->did_probe_mask & (1 << dev->devno)))) { - ata_eh_detach_dev(dev); - ata_dev_init(dev); - ehc->did_probe_mask |= (1 << dev->devno); - ehc->i.action |= ATA_EH_SOFTRESET; + ata_link_for_each_dev(dev, link) { + if (link->flags & ATA_LFLAG_NO_RETRY) + ehc->tries[dev->devno] = 1; + else + ehc->tries[dev->devno] = ATA_EH_DEV_TRIES; + + /* collect port action mask recorded in dev actions */ + ehc->i.action |= ehc->i.dev_action[dev->devno] & + ~ATA_EH_PERDEV_MASK; + ehc->i.dev_action[dev->devno] &= ATA_EH_PERDEV_MASK; + + /* process hotplug request */ + if (dev->flags & ATA_DFLAG_DETACH) + ata_eh_detach_dev(dev); + + if (!ata_dev_enabled(dev) && + ((ehc->i.probe_mask & (1 << dev->devno)) && + !(ehc->did_probe_mask & (1 << dev->devno)))) { + ata_eh_detach_dev(dev); + ata_dev_init(dev); + ehc->did_probe_mask |= (1 << dev->devno); + ehc->i.action |= ATA_EH_SOFTRESET; + } } } retry: rc = 0; + nr_failed_devs = 0; + nr_disabled_devs = 0; + reset = 0; /* if UNLOADING, finish immediately */ if (ap->pflags & ATA_PFLAG_UNLOADING) goto out; - /* skip EH if possible. */ - if (ata_eh_skip_recovery(ap)) - ehc->i.action = 0; + /* prep for EH */ + ata_port_for_each_link(link, ap) { + struct ata_eh_context *ehc = &link->eh_context; - for (i = 0; i < ATA_MAX_DEVICES; i++) - ehc->classes[i] = ATA_DEV_UNKNOWN; + /* skip EH if possible. */ + if (ata_eh_skip_recovery(link)) + ehc->i.action = 0; - /* reset */ - if (ehc->i.action & ATA_EH_RESET_MASK) { - ata_eh_freeze_port(ap); + /* do we need to reset? */ + if (ehc->i.action & ATA_EH_RESET_MASK) + reset = 1; - rc = ata_eh_reset(ap, ata_port_nr_vacant(ap), prereset, - softreset, hardreset, postreset); - if (rc) { - ata_port_printk(ap, KERN_ERR, - "reset failed, giving up\n"); - goto out; + ata_link_for_each_dev(dev, link) + ehc->classes[dev->devno] = ATA_DEV_UNKNOWN; + } + + /* reset */ + if (reset) { + /* if PMP is attached, this function only deals with + * downstream links, port should stay thawed. + */ + if (!ap->nr_pmp_links) + ata_eh_freeze_port(ap); + + ata_port_for_each_link(link, ap) { + struct ata_eh_context *ehc = &link->eh_context; + + if (!(ehc->i.action & ATA_EH_RESET_MASK)) + continue; + + rc = ata_eh_reset(link, ata_link_nr_vacant(link), + prereset, softreset, hardreset, + postreset); + if (rc) { + ata_link_printk(link, KERN_ERR, + "reset failed, giving up\n"); + goto out; + } } - ata_eh_thaw_port(ap); + if (!ap->nr_pmp_links) + ata_eh_thaw_port(ap); } - /* revalidate existing devices and attach new ones */ - rc = ata_eh_revalidate_and_attach(ap, &dev); - if (rc) - goto dev_fail; + /* the rest */ + ata_port_for_each_link(link, ap) { + struct ata_eh_context *ehc = &link->eh_context; - /* configure transfer mode if necessary */ - if (ehc->i.flags & ATA_EHI_SETMODE) { - rc = ata_set_mode(ap, &dev); + /* revalidate existing devices and attach new ones */ + rc = ata_eh_revalidate_and_attach(link, &dev); if (rc) goto dev_fail; - ehc->i.flags &= ~ATA_EHI_SETMODE; - } - goto out; + /* if PMP got attached, return, pmp EH will take care of it */ + if (link->device->class == ATA_DEV_PMP) { + ehc->i.action = 0; + return 0; + } - dev_fail: - ata_eh_handle_dev_fail(dev, rc); + /* configure transfer mode if necessary */ + if (ehc->i.flags & ATA_EHI_SETMODE) { + rc = ata_set_mode(link, &dev); + if (rc) + goto dev_fail; + ehc->i.flags &= ~ATA_EHI_SETMODE; + } - if (ata_port_nr_enabled(ap)) { - ata_port_printk(ap, KERN_WARNING, "failed to recover some " - "devices, retrying in 5 secs\n"); - ssleep(5); - } else { - /* no device left, repeat fast */ - msleep(500); + /* this link is okay now */ + ehc->i.flags = 0; + continue; + + dev_fail: + nr_failed_devs++; + if (ata_eh_handle_dev_fail(dev, rc)) + nr_disabled_devs++; + + if (ap->pflags & ATA_PFLAG_FROZEN) { + /* PMP reset requires working host port. + * Can't retry if it's frozen. + */ + if (ap->nr_pmp_links) + goto out; + break; + } } - goto retry; + if (nr_failed_devs) { + if (nr_failed_devs != nr_disabled_devs) { + ata_port_printk(ap, KERN_WARNING, "failed to recover " + "some devices, retrying in 5 secs\n"); + ssleep(5); + } else { + /* no device left to recover, repeat fast */ + msleep(500); + } - out: - if (rc) { - for (i = 0; i < ATA_MAX_DEVICES; i++) - ata_dev_disable(&ap->device[i]); + goto retry; } + out: + if (rc && r_failed_link) + *r_failed_link = link; + DPRINTK("EXIT, rc=%d\n", rc); return rc; } @@ -2257,7 +2657,7 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, * LOCKING: * None. */ -static void ata_eh_finish(struct ata_port *ap) +void ata_eh_finish(struct ata_port *ap) { int tag; @@ -2287,6 +2687,10 @@ static void ata_eh_finish(struct ata_port *ap) } } } + + /* make sure nr_active_links is zero after EH */ + WARN_ON(ap->nr_active_links); + ap->nr_active_links = 0; } /** @@ -2306,9 +2710,19 @@ void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) { + struct ata_device *dev; + int rc; + ata_eh_autopsy(ap); ata_eh_report(ap); - ata_eh_recover(ap, prereset, softreset, hardreset, postreset); + + rc = ata_eh_recover(ap, prereset, softreset, hardreset, postreset, + NULL); + if (rc) { + ata_link_for_each_dev(dev, &ap->link) + ata_dev_disable(dev); + } + ata_eh_finish(ap); } diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c new file mode 100644 index 000000000000..c0c4dbcde091 --- /dev/null +++ b/drivers/ata/libata-pmp.c @@ -0,0 +1,1191 @@ +/* + * libata-pmp.c - libata port multiplier support + * + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007 Tejun Heo <teheo@suse.de> + * + * This file is released under the GPLv2. + */ + +#include <linux/kernel.h> +#include <linux/libata.h> +#include "libata.h" + +/** + * sata_pmp_read - read PMP register + * @link: link to read PMP register for + * @reg: register to read + * @r_val: resulting value + * + * Read PMP register. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, AC_ERR_* mask on failure. + */ +static unsigned int sata_pmp_read(struct ata_link *link, int reg, u32 *r_val) +{ + struct ata_port *ap = link->ap; + struct ata_device *pmp_dev = ap->link.device; + struct ata_taskfile tf; + unsigned int err_mask; + + ata_tf_init(pmp_dev, &tf); + tf.command = ATA_CMD_PMP_READ; + tf.protocol = ATA_PROT_NODATA; + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.feature = reg; + tf.device = link->pmp; + + err_mask = ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0, + SATA_PMP_SCR_TIMEOUT); + if (err_mask) + return err_mask; + + *r_val = tf.nsect | tf.lbal << 8 | tf.lbam << 16 | tf.lbah << 24; + return 0; +} + +/** + * sata_pmp_write - write PMP register + * @link: link to write PMP register for + * @reg: register to write + * @r_val: value to write + * + * Write PMP register. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, AC_ERR_* mask on failure. + */ +static unsigned int sata_pmp_write(struct ata_link *link, int reg, u32 val) +{ + struct ata_port *ap = link->ap; + struct ata_device *pmp_dev = ap->link.device; + struct ata_taskfile tf; + + ata_tf_init(pmp_dev, &tf); + tf.command = ATA_CMD_PMP_WRITE; + tf.protocol = ATA_PROT_NODATA; + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.feature = reg; + tf.device = link->pmp; + tf.nsect = val & 0xff; + tf.lbal = (val >> 8) & 0xff; + tf.lbam = (val >> 16) & 0xff; + tf.lbah = (val >> 24) & 0xff; + + return ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0, + SATA_PMP_SCR_TIMEOUT); +} + +/** + * sata_pmp_qc_defer_cmd_switch - qc_defer for command switching PMP + * @qc: ATA command in question + * + * A host which has command switching PMP support cannot issue + * commands to multiple links simultaneously. + * + * LOCKING: + * spin_lock_irqsave(host lock) + * + * RETURNS: + * ATA_DEFER_* if deferring is needed, 0 otherwise. + */ +int sata_pmp_qc_defer_cmd_switch(struct ata_queued_cmd *qc) +{ + struct ata_link *link = qc->dev->link; + struct ata_port *ap = link->ap; + + if (ap->excl_link == NULL || ap->excl_link == link) { + if (ap->nr_active_links == 0 || ata_link_active(link)) { + qc->flags |= ATA_QCFLAG_CLEAR_EXCL; + return ata_std_qc_defer(qc); + } + + ap->excl_link = link; + } + + return ATA_DEFER_PORT; +} + +/** + * sata_pmp_scr_read - read PSCR + * @link: ATA link to read PSCR for + * @reg: PSCR to read + * @r_val: resulting value + * + * Read PSCR @reg into @r_val for @link, to be called from + * ata_scr_read(). + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *r_val) +{ + unsigned int err_mask; + + if (reg > SATA_PMP_PSCR_CONTROL) + return -EINVAL; + + err_mask = sata_pmp_read(link, reg, r_val); + if (err_mask) { + ata_link_printk(link, KERN_WARNING, "failed to read SCR %d " + "(Emask=0x%x)\n", reg, err_mask); + return -EIO; + } + return 0; +} + +/** + * sata_pmp_scr_write - write PSCR + * @link: ATA link to write PSCR for + * @reg: PSCR to write + * @val: value to be written + * + * Write @val to PSCR @reg for @link, to be called from + * ata_scr_write() and ata_scr_write_flush(). + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val) +{ + unsigned int err_mask; + + if (reg > SATA_PMP_PSCR_CONTROL) + return -EINVAL; + + err_mask = sata_pmp_write(link, reg, val); + if (err_mask) { + ata_link_printk(link, KERN_WARNING, "failed to write SCR %d " + "(Emask=0x%x)\n", reg, err_mask); + return -EIO; + } + return 0; +} + +/** + * sata_pmp_std_prereset - prepare PMP link for reset + * @link: link to be reset + * @deadline: deadline jiffies for the operation + * + * @link is about to be reset. Initialize it. + * + * LOCKING: + * Kernel thread context (may sleep) + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +int sata_pmp_std_prereset(struct ata_link *link, unsigned long deadline) +{ + struct ata_eh_context *ehc = &link->eh_context; + const unsigned long *timing = sata_ehc_deb_timing(ehc); + int rc; + + /* force HRST? */ + if (link->flags & ATA_LFLAG_NO_SRST) + ehc->i.action |= ATA_EH_HARDRESET; + + /* handle link resume */ + if ((ehc->i.flags & ATA_EHI_RESUME_LINK) && + (link->flags & ATA_LFLAG_HRST_TO_RESUME)) + ehc->i.action |= ATA_EH_HARDRESET; + + /* if we're about to do hardreset, nothing more to do */ + if (ehc->i.action & ATA_EH_HARDRESET) + return 0; + + /* resume link */ + rc = sata_link_resume(link, timing, deadline); + if (rc) { + /* phy resume failed */ + ata_link_printk(link, KERN_WARNING, "failed to resume link " + "for reset (errno=%d)\n", rc); + return rc; + } + + /* clear SError bits including .X which blocks the port when set */ + rc = sata_scr_write(link, SCR_ERROR, 0xffffffff); + if (rc) { + ata_link_printk(link, KERN_ERR, + "failed to clear SError (errno=%d)\n", rc); + return rc; + } + + return 0; +} + +/** + * sata_pmp_std_hardreset - standard hardreset method for PMP link + * @link: link to be reset + * @class: resulting class of attached device + * @deadline: deadline jiffies for the operation + * + * Hardreset PMP port @link. Note that this function doesn't + * wait for BSY clearance. There simply isn't a generic way to + * wait the event. Instead, this function return -EAGAIN thus + * telling libata-EH to followup with softreset. + * + * LOCKING: + * Kernel thread context (may sleep) + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +int sata_pmp_std_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); + u32 tmp; + int rc; + + DPRINTK("ENTER\n"); + + /* do hardreset */ + rc = sata_link_hardreset(link, timing, deadline); + if (rc) { + ata_link_printk(link, KERN_ERR, + "COMRESET failed (errno=%d)\n", rc); + goto out; + } + + /* clear SError bits including .X which blocks the port when set */ + rc = sata_scr_write(link, SCR_ERROR, 0xffffffff); + if (rc) { + ata_link_printk(link, KERN_ERR, "failed to clear SError " + "during hardreset (errno=%d)\n", rc); + goto out; + } + + /* if device is present, follow up with srst to wait for !BSY */ + if (ata_link_online(link)) + rc = -EAGAIN; + out: + /* if SCR isn't accessible, we need to reset the PMP */ + if (rc && rc != -EAGAIN && sata_scr_read(link, SCR_STATUS, &tmp)) + rc = -ERESTART; + + DPRINTK("EXIT, rc=%d\n", rc); + return rc; +} + +/** + * ata_std_postreset - standard postreset method for PMP link + * @link: the target ata_link + * @classes: classes of attached devices + * + * This function is invoked after a successful reset. Note that + * the device might have been reset more than once using + * different reset methods before postreset is invoked. + * + * LOCKING: + * Kernel thread context (may sleep) + */ +void sata_pmp_std_postreset(struct ata_link *link, unsigned int *class) +{ + u32 serror; + + DPRINTK("ENTER\n"); + + /* clear SError */ + if (sata_scr_read(link, SCR_ERROR, &serror) == 0) + sata_scr_write(link, SCR_ERROR, serror); + + /* print link status */ + sata_print_link_status(link); + + DPRINTK("EXIT\n"); +} + +/** + * sata_pmp_read_gscr - read GSCR block of SATA PMP + * @dev: PMP device + * @gscr: buffer to read GSCR block into + * + * Read selected PMP GSCRs from the PMP at @dev. This will serve + * as configuration and identification info for the PMP. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +static int sata_pmp_read_gscr(struct ata_device *dev, u32 *gscr) +{ + static const int gscr_to_read[] = { 0, 1, 2, 32, 33, 64, 96 }; + int i; + + for (i = 0; i < ARRAY_SIZE(gscr_to_read); i++) { + int reg = gscr_to_read[i]; + unsigned int err_mask; + + err_mask = sata_pmp_read(dev->link, reg, &gscr[reg]); + if (err_mask) { + ata_dev_printk(dev, KERN_ERR, "failed to read PMP " + "GSCR[%d] (Emask=0x%x)\n", reg, err_mask); + return -EIO; + } + } + + return 0; +} + +static const char *sata_pmp_spec_rev_str(const u32 *gscr) +{ + u32 rev = gscr[SATA_PMP_GSCR_REV]; + + if (rev & (1 << 2)) + return "1.1"; + if (rev & (1 << 1)) + return "1.0"; + return "<unknown>"; +} + +static int sata_pmp_configure(struct ata_device *dev, int print_info) +{ + struct ata_port *ap = dev->link->ap; + u32 *gscr = dev->gscr; + unsigned int err_mask = 0; + const char *reason; + int nr_ports, rc; + + nr_ports = sata_pmp_gscr_ports(gscr); + + if (nr_ports <= 0 || nr_ports > SATA_PMP_MAX_PORTS) { + rc = -EINVAL; + reason = "invalid nr_ports"; + goto fail; + } + + if ((ap->flags & ATA_FLAG_AN) && + (gscr[SATA_PMP_GSCR_FEAT] & SATA_PMP_FEAT_NOTIFY)) + dev->flags |= ATA_DFLAG_AN; + + /* monitor SERR_PHYRDY_CHG on fan-out ports */ + err_mask = sata_pmp_write(dev->link, SATA_PMP_GSCR_ERROR_EN, + SERR_PHYRDY_CHG); + if (err_mask) { + rc = -EIO; + reason = "failed to write GSCR_ERROR_EN"; + goto fail; + } + + /* turn off notification till fan-out ports are reset and configured */ + if (gscr[SATA_PMP_GSCR_FEAT_EN] & SATA_PMP_FEAT_NOTIFY) { + gscr[SATA_PMP_GSCR_FEAT_EN] &= ~SATA_PMP_FEAT_NOTIFY; + + err_mask = sata_pmp_write(dev->link, SATA_PMP_GSCR_FEAT_EN, + gscr[SATA_PMP_GSCR_FEAT_EN]); + if (err_mask) { + rc = -EIO; + reason = "failed to write GSCR_FEAT_EN"; + goto fail; + } + } + + if (print_info) { + ata_dev_printk(dev, KERN_INFO, "Port Multiplier %s, " + "0x%04x:0x%04x r%d, %d ports, feat 0x%x/0x%x\n", + sata_pmp_spec_rev_str(gscr), + sata_pmp_gscr_vendor(gscr), + sata_pmp_gscr_devid(gscr), + sata_pmp_gscr_rev(gscr), + nr_ports, gscr[SATA_PMP_GSCR_FEAT_EN], + gscr[SATA_PMP_GSCR_FEAT]); + + if (!(dev->flags & ATA_DFLAG_AN)) + ata_dev_printk(dev, KERN_INFO, + "Asynchronous notification not supported, " + "hotplug won't\n work on fan-out " + "ports. Use warm-plug instead.\n"); + } + + return 0; + + fail: + ata_dev_printk(dev, KERN_ERR, + "failed to configure Port Multiplier (%s, Emask=0x%x)\n", + reason, err_mask); + return rc; +} + +static int sata_pmp_init_links(struct ata_port *ap, int nr_ports) +{ + struct ata_link *pmp_link = ap->pmp_link; + int i; + + if (!pmp_link) { + pmp_link = kzalloc(sizeof(pmp_link[0]) * SATA_PMP_MAX_PORTS, + GFP_NOIO); + if (!pmp_link) + return -ENOMEM; + + for (i = 0; i < SATA_PMP_MAX_PORTS; i++) + ata_link_init(ap, &pmp_link[i], i); + + ap->pmp_link = pmp_link; + } + + for (i = 0; i < nr_ports; i++) { + struct ata_link *link = &pmp_link[i]; + struct ata_eh_context *ehc = &link->eh_context; + + link->flags = 0; + ehc->i.probe_mask |= 1; + ehc->i.action |= ATA_EH_SOFTRESET; + ehc->i.flags |= ATA_EHI_RESUME_LINK; + } + + return 0; +} + +static void sata_pmp_quirks(struct ata_port *ap) +{ + u32 *gscr = ap->link.device->gscr; + u16 vendor = sata_pmp_gscr_vendor(gscr); + u16 devid = sata_pmp_gscr_devid(gscr); + struct ata_link *link; + + if (vendor == 0x1095 && devid == 0x3726) { + /* sil3726 quirks */ + ata_port_for_each_link(link, ap) { + /* SError.N need a kick in the ass to get working */ + link->flags |= ATA_LFLAG_HRST_TO_RESUME; + + /* class code report is unreliable */ + if (link->pmp < 5) + link->flags |= ATA_LFLAG_ASSUME_ATA; + + /* port 5 is for SEMB device and it doesn't like SRST */ + if (link->pmp == 5) + link->flags |= ATA_LFLAG_NO_SRST | + ATA_LFLAG_ASSUME_SEMB; + } + } else if (vendor == 0x1095 && devid == 0x4723) { + /* sil4723 quirks */ + ata_port_for_each_link(link, ap) { + /* SError.N need a kick in the ass to get working */ + link->flags |= ATA_LFLAG_HRST_TO_RESUME; + + /* class code report is unreliable */ + if (link->pmp < 2) + link->flags |= ATA_LFLAG_ASSUME_ATA; + + /* the config device at port 2 locks up on SRST */ + if (link->pmp == 2) + link->flags |= ATA_LFLAG_NO_SRST | + ATA_LFLAG_ASSUME_ATA; + } + } else if (vendor == 0x1095 && devid == 0x4726) { + /* sil4726 quirks */ + ata_port_for_each_link(link, ap) { + /* SError.N need a kick in the ass to get working */ + link->flags |= ATA_LFLAG_HRST_TO_RESUME; + + /* class code report is unreliable */ + if (link->pmp < 5) + link->flags |= ATA_LFLAG_ASSUME_ATA; + + /* The config device, which can be either at + * port 0 or 5, locks up on SRST. + */ + if (link->pmp == 0 || link->pmp == 5) + link->flags |= ATA_LFLAG_NO_SRST | + ATA_LFLAG_ASSUME_ATA; + + /* Port 6 is for SEMB device which doesn't + * like SRST either. + */ + if (link->pmp == 6) + link->flags |= ATA_LFLAG_NO_SRST | + ATA_LFLAG_ASSUME_SEMB; + } + } else if (vendor == 0x1095 && (devid == 0x5723 || devid == 0x5733 || + devid == 0x5734 || devid == 0x5744)) { + /* sil5723/5744 quirks */ + + /* sil5723/5744 has either two or three downstream + * ports depending on operation mode. The last port + * is empty if any actual IO device is available or + * occupied by a pseudo configuration device + * otherwise. Don't try hard to recover it. + */ + ap->pmp_link[ap->nr_pmp_links - 1].flags |= ATA_LFLAG_NO_RETRY; + } else if (vendor == 0x11ab && devid == 0x4140) { + /* Marvell 88SM4140 quirks. Fan-out ports require PHY + * reset to work; other than that, it behaves very + * nicely. + */ + ata_port_for_each_link(link, ap) + link->flags |= ATA_LFLAG_HRST_TO_RESUME; + } +} + +/** + * sata_pmp_attach - attach a SATA PMP device + * @dev: SATA PMP device to attach + * + * Configure and attach SATA PMP device @dev. This function is + * also responsible for allocating and initializing PMP links. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +int sata_pmp_attach(struct ata_device *dev) +{ + struct ata_link *link = dev->link; + struct ata_port *ap = link->ap; + unsigned long flags; + struct ata_link *tlink; + int rc; + + /* is it hanging off the right place? */ + if (!(ap->flags & ATA_FLAG_PMP)) { + ata_dev_printk(dev, KERN_ERR, + "host does not support Port Multiplier\n"); + return -EINVAL; + } + + if (!ata_is_host_link(link)) { + ata_dev_printk(dev, KERN_ERR, + "Port Multipliers cannot be nested\n"); + return -EINVAL; + } + + if (dev->devno) { + ata_dev_printk(dev, KERN_ERR, + "Port Multiplier must be the first device\n"); + return -EINVAL; + } + + WARN_ON(link->pmp != 0); + link->pmp = SATA_PMP_CTRL_PORT; + + /* read GSCR block */ + rc = sata_pmp_read_gscr(dev, dev->gscr); + if (rc) + goto fail; + + /* config PMP */ + rc = sata_pmp_configure(dev, 1); + if (rc) + goto fail; + + rc = sata_pmp_init_links(ap, sata_pmp_gscr_ports(dev->gscr)); + if (rc) { + ata_dev_printk(dev, KERN_INFO, + "failed to initialize PMP links\n"); + goto fail; + } + + /* attach it */ + spin_lock_irqsave(ap->lock, flags); + WARN_ON(ap->nr_pmp_links); + ap->nr_pmp_links = sata_pmp_gscr_ports(dev->gscr); + spin_unlock_irqrestore(ap->lock, flags); + + sata_pmp_quirks(ap); + + if (ap->ops->pmp_attach) + ap->ops->pmp_attach(ap); + + ata_port_for_each_link(tlink, ap) + sata_link_init_spd(tlink); + + ata_acpi_associate_sata_port(ap); + + return 0; + + fail: + link->pmp = 0; + return rc; +} + +/** + * sata_pmp_detach - detach a SATA PMP device + * @dev: SATA PMP device to detach + * + * Detach SATA PMP device @dev. This function is also + * responsible for deconfiguring PMP links. + * + * LOCKING: + * Kernel thread context (may sleep). + */ +static void sata_pmp_detach(struct ata_device *dev) +{ + struct ata_link *link = dev->link; + struct ata_port *ap = link->ap; + struct ata_link *tlink; + unsigned long flags; + + ata_dev_printk(dev, KERN_INFO, "Port Multiplier detaching\n"); + + WARN_ON(!ata_is_host_link(link) || dev->devno || + link->pmp != SATA_PMP_CTRL_PORT); + + if (ap->ops->pmp_detach) + ap->ops->pmp_detach(ap); + + ata_port_for_each_link(tlink, ap) + ata_eh_detach_dev(tlink->device); + + spin_lock_irqsave(ap->lock, flags); + ap->nr_pmp_links = 0; + link->pmp = 0; + spin_unlock_irqrestore(ap->lock, flags); + + ata_acpi_associate_sata_port(ap); +} + +/** + * sata_pmp_same_pmp - does new GSCR matches the configured PMP? + * @dev: PMP device to compare against + * @new_gscr: GSCR block of the new device + * + * Compare @new_gscr against @dev and determine whether @dev is + * the PMP described by @new_gscr. + * + * LOCKING: + * None. + * + * RETURNS: + * 1 if @dev matches @new_gscr, 0 otherwise. + */ +static int sata_pmp_same_pmp(struct ata_device *dev, const u32 *new_gscr) +{ + const u32 *old_gscr = dev->gscr; + u16 old_vendor, new_vendor, old_devid, new_devid; + int old_nr_ports, new_nr_ports; + + old_vendor = sata_pmp_gscr_vendor(old_gscr); + new_vendor = sata_pmp_gscr_vendor(new_gscr); + old_devid = sata_pmp_gscr_devid(old_gscr); + new_devid = sata_pmp_gscr_devid(new_gscr); + old_nr_ports = sata_pmp_gscr_ports(old_gscr); + new_nr_ports = sata_pmp_gscr_ports(new_gscr); + + if (old_vendor != new_vendor) { + ata_dev_printk(dev, KERN_INFO, "Port Multiplier " + "vendor mismatch '0x%x' != '0x%x'\n", + old_vendor, new_vendor); + return 0; + } + + if (old_devid != new_devid) { + ata_dev_printk(dev, KERN_INFO, "Port Multiplier " + "device ID mismatch '0x%x' != '0x%x'\n", + old_devid, new_devid); + return 0; + } + + if (old_nr_ports != new_nr_ports) { + ata_dev_printk(dev, KERN_INFO, "Port Multiplier " + "nr_ports mismatch '0x%x' != '0x%x'\n", + old_nr_ports, new_nr_ports); + return 0; + } + + return 1; +} + +/** + * sata_pmp_revalidate - revalidate SATA PMP + * @dev: PMP device to revalidate + * @new_class: new class code + * + * Re-read GSCR block and make sure @dev is still attached to the + * port and properly configured. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +static int sata_pmp_revalidate(struct ata_device *dev, unsigned int new_class) +{ + struct ata_link *link = dev->link; + struct ata_port *ap = link->ap; + u32 *gscr = (void *)ap->sector_buf; + int rc; + + DPRINTK("ENTER\n"); + + ata_eh_about_to_do(link, NULL, ATA_EH_REVALIDATE); + + if (!ata_dev_enabled(dev)) { + rc = -ENODEV; + goto fail; + } + + /* wrong class? */ + if (ata_class_enabled(new_class) && new_class != ATA_DEV_PMP) { + rc = -ENODEV; + goto fail; + } + + /* read GSCR */ + rc = sata_pmp_read_gscr(dev, gscr); + if (rc) + goto fail; + + /* is the pmp still there? */ + if (!sata_pmp_same_pmp(dev, gscr)) { + rc = -ENODEV; + goto fail; + } + + memcpy(dev->gscr, gscr, sizeof(gscr[0]) * SATA_PMP_GSCR_DWORDS); + + rc = sata_pmp_configure(dev, 0); + if (rc) + goto fail; + + ata_eh_done(link, NULL, ATA_EH_REVALIDATE); + + DPRINTK("EXIT, rc=0\n"); + return 0; + + fail: + ata_dev_printk(dev, KERN_ERR, + "PMP revalidation failed (errno=%d)\n", rc); + DPRINTK("EXIT, rc=%d\n", rc); + return rc; +} + +/** + * sata_pmp_revalidate_quick - revalidate SATA PMP quickly + * @dev: PMP device to revalidate + * + * Make sure the attached PMP is accessible. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +static int sata_pmp_revalidate_quick(struct ata_device *dev) +{ + unsigned int err_mask; + u32 prod_id; + + err_mask = sata_pmp_read(dev->link, SATA_PMP_GSCR_PROD_ID, &prod_id); + if (err_mask) { + ata_dev_printk(dev, KERN_ERR, "failed to read PMP product ID " + "(Emask=0x%x)\n", err_mask); + return -EIO; + } + + if (prod_id != dev->gscr[SATA_PMP_GSCR_PROD_ID]) { + ata_dev_printk(dev, KERN_ERR, "PMP product ID mismatch\n"); + /* something weird is going on, request full PMP recovery */ + return -EIO; + } + + return 0; +} + +/** + * sata_pmp_eh_recover_pmp - recover PMP + * @ap: ATA port PMP is attached to + * @prereset: prereset method (can be NULL) + * @softreset: softreset method + * @hardreset: hardreset method + * @postreset: postreset method (can be NULL) + * + * Recover PMP attached to @ap. Recovery procedure is somewhat + * similar to that of ata_eh_recover() except that reset should + * always be performed in hard->soft sequence and recovery + * failure results in PMP detachment. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +static int sata_pmp_eh_recover_pmp(struct ata_port *ap, + ata_prereset_fn_t prereset, ata_reset_fn_t softreset, + ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) +{ + struct ata_link *link = &ap->link; + struct ata_eh_context *ehc = &link->eh_context; + struct ata_device *dev = link->device; + int tries = ATA_EH_PMP_TRIES; + int detach = 0, rc = 0; + int reval_failed = 0; + + DPRINTK("ENTER\n"); + + if (dev->flags & ATA_DFLAG_DETACH) { + detach = 1; + goto fail; + } + + retry: + ehc->classes[0] = ATA_DEV_UNKNOWN; + + if (ehc->i.action & ATA_EH_RESET_MASK) { + struct ata_link *tlink; + + ata_eh_freeze_port(ap); + + /* reset */ + ehc->i.action = ATA_EH_HARDRESET; + rc = ata_eh_reset(link, 0, prereset, softreset, hardreset, + postreset); + if (rc) { + ata_link_printk(link, KERN_ERR, + "failed to reset PMP, giving up\n"); + goto fail; + } + + ata_eh_thaw_port(ap); + + /* PMP is reset, SErrors cannot be trusted, scan all */ + ata_port_for_each_link(tlink, ap) + ata_ehi_schedule_probe(&tlink->eh_context.i); + } + + /* If revalidation is requested, revalidate and reconfigure; + * otherwise, do quick revalidation. + */ + if (ehc->i.action & ATA_EH_REVALIDATE) + rc = sata_pmp_revalidate(dev, ehc->classes[0]); + else + rc = sata_pmp_revalidate_quick(dev); + + if (rc) { + tries--; + + if (rc == -ENODEV) { + ehc->i.probe_mask |= 1; + detach = 1; + /* give it just two more chances */ + tries = min(tries, 2); + } + + if (tries) { + int sleep = ehc->i.flags & ATA_EHI_DID_RESET; + + /* consecutive revalidation failures? speed down */ + if (reval_failed) + sata_down_spd_limit(link); + else + reval_failed = 1; + + ata_dev_printk(dev, KERN_WARNING, + "retrying hardreset%s\n", + sleep ? " in 5 secs" : ""); + if (sleep) + ssleep(5); + ehc->i.action |= ATA_EH_HARDRESET; + goto retry; + } else { + ata_dev_printk(dev, KERN_ERR, "failed to recover PMP " + "after %d tries, giving up\n", + ATA_EH_PMP_TRIES); + goto fail; + } + } + + /* okay, PMP resurrected */ + ehc->i.flags = 0; + + DPRINTK("EXIT, rc=0\n"); + return 0; + + fail: + sata_pmp_detach(dev); + if (detach) + ata_eh_detach_dev(dev); + else + ata_dev_disable(dev); + + DPRINTK("EXIT, rc=%d\n", rc); + return rc; +} + +static int sata_pmp_eh_handle_disabled_links(struct ata_port *ap) +{ + struct ata_link *link; + unsigned long flags; + int rc; + + spin_lock_irqsave(ap->lock, flags); + + ata_port_for_each_link(link, ap) { + if (!(link->flags & ATA_LFLAG_DISABLED)) + continue; + + spin_unlock_irqrestore(ap->lock, flags); + + /* Some PMPs require hardreset sequence to get + * SError.N working. + */ + if ((link->flags & ATA_LFLAG_HRST_TO_RESUME) && + (link->eh_context.i.flags & ATA_EHI_RESUME_LINK)) + sata_link_hardreset(link, sata_deb_timing_normal, + jiffies + ATA_TMOUT_INTERNAL_QUICK); + + /* unconditionally clear SError.N */ + rc = sata_scr_write(link, SCR_ERROR, SERR_PHYRDY_CHG); + if (rc) { + ata_link_printk(link, KERN_ERR, "failed to clear " + "SError.N (errno=%d)\n", rc); + return rc; + } + + spin_lock_irqsave(ap->lock, flags); + } + + spin_unlock_irqrestore(ap->lock, flags); + + return 0; +} + +static int sata_pmp_handle_link_fail(struct ata_link *link, int *link_tries) +{ + struct ata_port *ap = link->ap; + unsigned long flags; + + if (link_tries[link->pmp] && --link_tries[link->pmp]) + return 1; + + /* disable this link */ + if (!(link->flags & ATA_LFLAG_DISABLED)) { + ata_link_printk(link, KERN_WARNING, + "failed to recover link after %d tries, disabling\n", + ATA_EH_PMP_LINK_TRIES); + + spin_lock_irqsave(ap->lock, flags); + link->flags |= ATA_LFLAG_DISABLED; + spin_unlock_irqrestore(ap->lock, flags); + } + + ata_dev_disable(link->device); + link->eh_context.i.action = 0; + + return 0; +} + +/** + * sata_pmp_eh_recover - recover PMP-enabled port + * @ap: ATA port to recover + * @prereset: prereset method (can be NULL) + * @softreset: softreset method + * @hardreset: hardreset method + * @postreset: postreset method (can be NULL) + * @pmp_prereset: PMP prereset method (can be NULL) + * @pmp_softreset: PMP softreset method (can be NULL) + * @pmp_hardreset: PMP hardreset method (can be NULL) + * @pmp_postreset: PMP postreset method (can be NULL) + * + * Drive EH recovery operation for PMP enabled port @ap. This + * function recovers host and PMP ports with proper retrials and + * fallbacks. Actual recovery operations are performed using + * ata_eh_recover() and sata_pmp_eh_recover_pmp(). + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +static int sata_pmp_eh_recover(struct ata_port *ap, + ata_prereset_fn_t prereset, ata_reset_fn_t softreset, + ata_reset_fn_t hardreset, ata_postreset_fn_t postreset, + ata_prereset_fn_t pmp_prereset, ata_reset_fn_t pmp_softreset, + ata_reset_fn_t pmp_hardreset, ata_postreset_fn_t pmp_postreset) +{ + int pmp_tries, link_tries[SATA_PMP_MAX_PORTS]; + struct ata_link *pmp_link = &ap->link; + struct ata_device *pmp_dev = pmp_link->device; + struct ata_eh_context *pmp_ehc = &pmp_link->eh_context; + struct ata_link *link; + struct ata_device *dev; + unsigned int err_mask; + u32 gscr_error, sntf; + int cnt, rc; + + pmp_tries = ATA_EH_PMP_TRIES; + ata_port_for_each_link(link, ap) + link_tries[link->pmp] = ATA_EH_PMP_LINK_TRIES; + + retry: + /* PMP attached? */ + if (!ap->nr_pmp_links) { + rc = ata_eh_recover(ap, prereset, softreset, hardreset, + postreset, NULL); + if (rc) { + ata_link_for_each_dev(dev, &ap->link) + ata_dev_disable(dev); + return rc; + } + + if (pmp_dev->class != ATA_DEV_PMP) + return 0; + + /* new PMP online */ + ata_port_for_each_link(link, ap) + link_tries[link->pmp] = ATA_EH_PMP_LINK_TRIES; + + /* fall through */ + } + + /* recover pmp */ + rc = sata_pmp_eh_recover_pmp(ap, prereset, softreset, hardreset, + postreset); + if (rc) + goto pmp_fail; + + /* handle disabled links */ + rc = sata_pmp_eh_handle_disabled_links(ap); + if (rc) + goto pmp_fail; + + /* recover links */ + rc = ata_eh_recover(ap, pmp_prereset, pmp_softreset, pmp_hardreset, + pmp_postreset, &link); + if (rc) + goto link_fail; + + /* Connection status might have changed while resetting other + * links, check SATA_PMP_GSCR_ERROR before returning. + */ + + /* clear SNotification */ + rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf); + if (rc == 0) + sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf); + + /* enable notification */ + if (pmp_dev->flags & ATA_DFLAG_AN) { + pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY; + + err_mask = sata_pmp_write(pmp_dev->link, SATA_PMP_GSCR_FEAT_EN, + pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN]); + if (err_mask) { + ata_dev_printk(pmp_dev, KERN_ERR, "failed to write " + "PMP_FEAT_EN (Emask=0x%x)\n", err_mask); + rc = -EIO; + goto pmp_fail; + } + } + + /* check GSCR_ERROR */ + err_mask = sata_pmp_read(pmp_link, SATA_PMP_GSCR_ERROR, &gscr_error); + if (err_mask) { + ata_dev_printk(pmp_dev, KERN_ERR, "failed to read " + "PMP_GSCR_ERROR (Emask=0x%x)\n", err_mask); + rc = -EIO; + goto pmp_fail; + } + + cnt = 0; + ata_port_for_each_link(link, ap) { + if (!(gscr_error & (1 << link->pmp))) + continue; + + if (sata_pmp_handle_link_fail(link, link_tries)) { + ata_ehi_hotplugged(&link->eh_context.i); + cnt++; + } else { + ata_link_printk(link, KERN_WARNING, + "PHY status changed but maxed out on retries, " + "giving up\n"); + ata_link_printk(link, KERN_WARNING, + "Manully issue scan to resume this link\n"); + } + } + + if (cnt) { + ata_port_printk(ap, KERN_INFO, "PMP SError.N set for some " + "ports, repeating recovery\n"); + goto retry; + } + + return 0; + + link_fail: + if (sata_pmp_handle_link_fail(link, link_tries)) { + pmp_ehc->i.action |= ATA_EH_HARDRESET; + goto retry; + } + + /* fall through */ + pmp_fail: + /* Control always ends up here after detaching PMP. Shut up + * and return if we're unloading. + */ + if (ap->pflags & ATA_PFLAG_UNLOADING) + return rc; + + if (!ap->nr_pmp_links) + goto retry; + + if (--pmp_tries) { + ata_port_printk(ap, KERN_WARNING, + "failed to recover PMP, retrying in 5 secs\n"); + pmp_ehc->i.action |= ATA_EH_HARDRESET; + ssleep(5); + goto retry; + } + + ata_port_printk(ap, KERN_ERR, + "failed to recover PMP after %d tries, giving up\n", + ATA_EH_PMP_TRIES); + sata_pmp_detach(pmp_dev); + ata_dev_disable(pmp_dev); + + return rc; +} + +/** + * sata_pmp_do_eh - do standard error handling for PMP-enabled host + * @ap: host port to handle error for + * @prereset: prereset method (can be NULL) + * @softreset: softreset method + * @hardreset: hardreset method + * @postreset: postreset method (can be NULL) + * @pmp_prereset: PMP prereset method (can be NULL) + * @pmp_softreset: PMP softreset method (can be NULL) + * @pmp_hardreset: PMP hardreset method (can be NULL) + * @pmp_postreset: PMP postreset method (can be NULL) + * + * Perform standard error handling sequence for PMP-enabled host + * @ap. + * + * LOCKING: + * Kernel thread context (may sleep). + */ +void sata_pmp_do_eh(struct ata_port *ap, + ata_prereset_fn_t prereset, ata_reset_fn_t softreset, + ata_reset_fn_t hardreset, ata_postreset_fn_t postreset, + ata_prereset_fn_t pmp_prereset, ata_reset_fn_t pmp_softreset, + ata_reset_fn_t pmp_hardreset, ata_postreset_fn_t pmp_postreset) +{ + ata_eh_autopsy(ap); + ata_eh_report(ap); + sata_pmp_eh_recover(ap, prereset, softreset, hardreset, postreset, + pmp_prereset, pmp_softreset, pmp_hardreset, + pmp_postreset); + ata_eh_finish(ap); +} diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index e83647651b31..d63c81ed084f 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -71,11 +71,10 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, #define ALL_SUB_MPAGES 0xff -static const u8 def_rw_recovery_mpage[] = { +static const u8 def_rw_recovery_mpage[RW_RECOVERY_MPAGE_LEN] = { RW_RECOVERY_MPAGE, RW_RECOVERY_MPAGE_LEN - 2, - (1 << 7) | /* AWRE, sat-r06 say it shall be 0 */ - (1 << 6), /* ARRE (auto read reallocation) */ + (1 << 7), /* AWRE */ 0, /* read retry count */ 0, 0, 0, 0, 0, /* write retry count */ @@ -450,13 +449,8 @@ static struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev, qc->scsicmd = cmd; qc->scsidone = done; - if (cmd->use_sg) { - qc->__sg = (struct scatterlist *) cmd->request_buffer; - qc->n_elem = cmd->use_sg; - } else if (cmd->request_bufflen) { - qc->__sg = &qc->sgent; - qc->n_elem = 1; - } + qc->__sg = scsi_sglist(cmd); + qc->n_elem = scsi_sg_count(cmd); } else { cmd->result = (DID_OK << 16) | (QUEUE_FULL << 1); done(cmd); @@ -755,6 +749,13 @@ static void ata_scsi_sdev_config(struct scsi_device *sdev) { sdev->use_10_for_rw = 1; sdev->use_10_for_ms = 1; + + /* Schedule policy is determined by ->qc_defer() callback and + * it needs to see every deferred qc. Set dev_blocked to 1 to + * prevent SCSI midlayer from automatically deferring + * requests. + */ + sdev->max_device_blocked = 1; } static void ata_scsi_dev_config(struct scsi_device *sdev, @@ -943,6 +944,13 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc) goto invalid_fld; /* LOEJ bit set not supported */ if (((cdb[4] >> 4) & 0xf) != 0) goto invalid_fld; /* power conditions not supported */ + + if (qc->dev->horkage & ATA_HORKAGE_SKIP_PM) { + /* the device lacks PM support, finish without doing anything */ + scmd->result = SAM_STAT_GOOD; + return 1; + } + if (cdb[4] & 0x1) { tf->nsect = 1; /* 1 sector, lba=0 */ @@ -1355,6 +1363,7 @@ nothing_to_do: static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; + struct ata_eh_info *ehi = &qc->dev->link->eh_info; struct scsi_cmnd *cmd = qc->scsicmd; u8 *cdb = cmd->cmnd; int need_sense = (qc->err_mask != 0); @@ -1368,14 +1377,14 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) case ATA_CMD_SET_FEATURES: if ((qc->tf.feature == SETFEATURES_WC_ON) || (qc->tf.feature == SETFEATURES_WC_OFF)) { - ap->eh_info.action |= ATA_EH_REVALIDATE; + ehi->action |= ATA_EH_REVALIDATE; ata_port_schedule_eh(ap); } break; case ATA_CMD_INIT_DEV_PARAMS: /* CHS translation changed */ case ATA_CMD_SET_MULTI: /* multi_count changed */ - ap->eh_info.action |= ATA_EH_REVALIDATE; + ehi->action |= ATA_EH_REVALIDATE; ata_port_schedule_eh(ap); break; } @@ -1422,37 +1431,6 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) } /** - * ata_scmd_need_defer - Check whether we need to defer scmd - * @dev: ATA device to which the command is addressed - * @is_io: Is the command IO (and thus possibly NCQ)? - * - * NCQ and non-NCQ commands cannot run together. As upper layer - * only knows the queue depth, we are responsible for maintaining - * exclusion. This function checks whether a new command can be - * issued to @dev. - * - * LOCKING: - * spin_lock_irqsave(host lock) - * - * RETURNS: - * 1 if deferring is needed, 0 otherwise. - */ -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 (is_ncq) { - if (!ata_tag_valid(ap->active_tag)) - return 0; - } else { - if (!ata_tag_valid(ap->active_tag) && !ap->sactive) - return 0; - } - return 1; -} - -/** * ata_scsi_translate - Translate then issue SCSI command to ATA device * @dev: ATA device to which the command is addressed * @cmd: SCSI command to execute @@ -1483,14 +1461,12 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), ata_xlat_func_t xlat_func) { + struct ata_port *ap = dev->link->ap; struct ata_queued_cmd *qc; - int is_io = xlat_func == ata_scsi_rw_xlat; + int rc; VPRINTK("ENTER\n"); - if (unlikely(ata_scmd_need_defer(dev, is_io))) - goto defer; - qc = ata_scsi_qc_new(dev, cmd, done); if (!qc) goto err_mem; @@ -1498,17 +1474,13 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd, /* data is present; dma-map it */ if (cmd->sc_data_direction == DMA_FROM_DEVICE || cmd->sc_data_direction == DMA_TO_DEVICE) { - if (unlikely(cmd->request_bufflen < 1)) { + if (unlikely(scsi_bufflen(cmd) < 1)) { ata_dev_printk(dev, KERN_WARNING, "WARNING: zero len r/w req\n"); goto err_did; } - if (cmd->use_sg) - ata_sg_init(qc, cmd->request_buffer, cmd->use_sg); - else - ata_sg_init_one(qc, cmd->request_buffer, - cmd->request_bufflen); + ata_sg_init(qc, scsi_sglist(cmd), scsi_sg_count(cmd)); qc->dma_dir = cmd->sc_data_direction; } @@ -1518,6 +1490,11 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd, if (xlat_func(qc)) goto early_finish; + if (ap->ops->qc_defer) { + if ((rc = ap->ops->qc_defer(qc))) + goto defer; + } + /* select device, send command to hardware */ ata_qc_issue(qc); @@ -1539,8 +1516,12 @@ err_mem: return 0; defer: + ata_qc_free(qc); DPRINTK("EXIT - defer\n"); - return SCSI_MLQUEUE_DEVICE_BUSY; + if (rc == ATA_DEFER_LINK) + return SCSI_MLQUEUE_DEVICE_BUSY; + else + return SCSI_MLQUEUE_HOST_BUSY; } /** @@ -1562,15 +1543,14 @@ static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out) u8 *buf; unsigned int buflen; - if (cmd->use_sg) { - struct scatterlist *sg; + struct scatterlist *sg = scsi_sglist(cmd); - sg = (struct scatterlist *) cmd->request_buffer; + if (sg) { buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset; buflen = sg->length; } else { - buf = cmd->request_buffer; - buflen = cmd->request_bufflen; + buf = NULL; + buflen = 0; } *buf_out = buf; @@ -1590,12 +1570,9 @@ static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out) static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf) { - if (cmd->use_sg) { - struct scatterlist *sg; - - sg = (struct scatterlist *) cmd->request_buffer; + struct scatterlist *sg = scsi_sglist(cmd); + if (sg) kunmap_atomic(buf - sg->offset, KM_IRQ0); - } } /** @@ -1817,6 +1794,62 @@ unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf, } /** + * ata_scsiop_inq_89 - Simulate INQUIRY VPD page 89, ATA info + * @args: device IDENTIFY data / SCSI command of interest. + * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. + * @buflen: Response buffer length. + * + * Yields SAT-specified ATA VPD page. + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ + +unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf, + unsigned int buflen) +{ + u8 pbuf[60]; + struct ata_taskfile tf; + unsigned int i; + + if (!buflen) + return 0; + + memset(&pbuf, 0, sizeof(pbuf)); + memset(&tf, 0, sizeof(tf)); + + pbuf[1] = 0x89; /* our page code */ + pbuf[2] = (0x238 >> 8); /* page size fixed at 238h */ + pbuf[3] = (0x238 & 0xff); + + memcpy(&pbuf[8], "linux ", 8); + memcpy(&pbuf[16], "libata ", 16); + memcpy(&pbuf[32], DRV_VERSION, 4); + ata_id_string(args->id, &pbuf[32], ATA_ID_FW_REV, 4); + + /* we don't store the ATA device signature, so we fake it */ + + tf.command = ATA_DRDY; /* really, this is Status reg */ + tf.lbal = 0x1; + tf.nsect = 0x1; + + ata_tf_to_fis(&tf, 0, 1, &pbuf[36]); /* TODO: PMP? */ + pbuf[36] = 0x34; /* force D2H Reg FIS (34h) */ + + pbuf[56] = ATA_CMD_ID_ATA; + + i = min(buflen, 60U); + memcpy(rbuf, &pbuf[0], i); + buflen -= i; + + if (!buflen) + return 0; + + memcpy(&rbuf[60], &args->id[0], min(buflen, 512U)); + return 0; +} + +/** * ata_scsiop_noop - Command handler that simply returns success. * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. @@ -2273,8 +2306,8 @@ static void atapi_request_sense(struct ata_queued_cmd *qc) qc->tf.feature |= ATAPI_PKT_DMA; } else { qc->tf.protocol = ATA_PROT_ATAPI; - qc->tf.lbam = (8 * 1024) & 0xff; - qc->tf.lbah = (8 * 1024) >> 8; + qc->tf.lbam = SCSI_SENSE_BUFFERSIZE; + qc->tf.lbah = 0; } qc->nbytes = SCSI_SENSE_BUFFERSIZE; @@ -2383,6 +2416,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc) struct ata_device *dev = qc->dev; int using_pio = (dev->flags & ATA_DFLAG_PIO); int nodata = (scmd->sc_data_direction == DMA_NONE); + unsigned int nbytes; memset(qc->cdb, 0, dev->cdb_len); memcpy(qc->cdb, scmd->cmnd, scmd->cmd_len); @@ -2396,20 +2430,26 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc) } qc->tf.command = ATA_CMD_PACKET; - qc->nbytes = scmd->request_bufflen; + qc->nbytes = scsi_bufflen(scmd); /* check whether ATAPI DMA is safe */ if (!using_pio && ata_check_atapi_dma(qc)) using_pio = 1; + /* Some controller variants snoop this value for Packet transfers + to do state machine and FIFO management. Thus we want to set it + properly, and for DMA where it is effectively meaningless */ + nbytes = min(qc->nbytes, (unsigned int)63 * 1024); + + qc->tf.lbam = (nbytes & 0xFF); + qc->tf.lbah = (nbytes >> 8); + if (using_pio || nodata) { /* no data, or PIO data xfer */ if (nodata) qc->tf.protocol = ATA_PROT_ATAPI_NODATA; else qc->tf.protocol = ATA_PROT_ATAPI; - qc->tf.lbam = (8 * 1024) & 0xff; - qc->tf.lbah = (8 * 1024) >> 8; } else { /* DMA data xfer */ qc->tf.protocol = ATA_PROT_ATAPI_DMA; @@ -2420,24 +2460,42 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc) qc->tf.feature |= ATAPI_DMADIR; } + + /* FIXME: We need to translate 0x05 READ_BLOCK_LIMITS to a MODE_SENSE + as ATAPI tape drives don't get this right otherwise */ return 0; } -static struct ata_device * ata_find_dev(struct ata_port *ap, int id) +static struct ata_device * ata_find_dev(struct ata_port *ap, int devno) { - if (likely(id < ATA_MAX_DEVICES)) - return &ap->device[id]; + if (ap->nr_pmp_links == 0) { + if (likely(devno < ata_link_max_devices(&ap->link))) + return &ap->link.device[devno]; + } else { + if (likely(devno < ap->nr_pmp_links)) + return &ap->pmp_link[devno].device[0]; + } + return NULL; } static struct ata_device * __ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev) { + int devno; + /* skip commands not addressed to targets we simulate */ - if (unlikely(scsidev->channel || scsidev->lun)) - return NULL; + if (ap->nr_pmp_links == 0) { + if (unlikely(scsidev->channel || scsidev->lun)) + return NULL; + devno = scsidev->id; + } else { + if (unlikely(scsidev->id || scsidev->lun)) + return NULL; + devno = scsidev->channel; + } - return ata_find_dev(ap, scsidev->id); + return ata_find_dev(ap, devno); } /** @@ -2458,7 +2516,7 @@ static int ata_scsi_dev_enabled(struct ata_device *dev) if (unlikely(!ata_dev_enabled(dev))) return 0; - if (!atapi_enabled || (dev->ap->flags & ATA_FLAG_NO_ATAPI)) { + if (!atapi_enabled || (dev->link->ap->flags & ATA_FLAG_NO_ATAPI)) { if (unlikely(dev->class == ATA_DEV_ATAPI)) { ata_dev_printk(dev, KERN_WARNING, "WARNING: ATAPI is %s, device ignored.\n", @@ -2631,7 +2689,7 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) case ATA_CMD_WRITE_LONG_ONCE: if (tf->protocol != ATA_PROT_PIO || tf->nsect != 1) goto invalid_fld; - qc->sect_size = scmd->request_bufflen; + qc->sect_size = scsi_bufflen(scmd); } /* @@ -2661,7 +2719,7 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) * TODO: find out if we need to do more here to * cover scatter/gather case. */ - qc->nbytes = scmd->request_bufflen; + qc->nbytes = scsi_bufflen(scmd); /* request result TF */ qc->flags |= ATA_QCFLAG_RESULT_TF; @@ -2746,28 +2804,48 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *), struct ata_device *dev) { + u8 scsi_op = scmd->cmnd[0]; + ata_xlat_func_t xlat_func; int rc = 0; - if (unlikely(!scmd->cmd_len || scmd->cmd_len > dev->cdb_len)) { - DPRINTK("bad CDB len=%u, max=%u\n", - scmd->cmd_len, dev->cdb_len); - scmd->result = DID_ERROR << 16; - done(scmd); - return 0; - } - if (dev->class == ATA_DEV_ATA) { - ata_xlat_func_t xlat_func = ata_get_xlat_func(dev, - scmd->cmnd[0]); + if (unlikely(!scmd->cmd_len || scmd->cmd_len > dev->cdb_len)) + goto bad_cdb_len; - if (xlat_func) - rc = ata_scsi_translate(dev, scmd, done, xlat_func); - else - ata_scsi_simulate(dev, scmd, done); - } else - rc = ata_scsi_translate(dev, scmd, done, atapi_xlat); + xlat_func = ata_get_xlat_func(dev, scsi_op); + } else { + if (unlikely(!scmd->cmd_len)) + goto bad_cdb_len; + + xlat_func = NULL; + if (likely((scsi_op != ATA_16) || !atapi_passthru16)) { + /* relay SCSI command to ATAPI device */ + if (unlikely(scmd->cmd_len > dev->cdb_len)) + goto bad_cdb_len; + + xlat_func = atapi_xlat; + } else { + /* ATA_16 passthru, treat as an ATA command */ + if (unlikely(scmd->cmd_len > 16)) + goto bad_cdb_len; + + xlat_func = ata_get_xlat_func(dev, scsi_op); + } + } + + if (xlat_func) + rc = ata_scsi_translate(dev, scmd, done, xlat_func); + else + ata_scsi_simulate(dev, scmd, done); return rc; + + bad_cdb_len: + DPRINTK("bad CDB len=%u, scsi_op=0x%02x, max=%u\n", + scmd->cmd_len, scsi_op, dev->cdb_len); + scmd->result = DID_ERROR << 16; + done(scmd); + return 0; } /** @@ -2835,6 +2913,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, { struct ata_scsi_args args; const u8 *scsicmd = cmd->cmnd; + u8 tmp8; args.dev = dev; args.id = dev->id; @@ -2842,15 +2921,9 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, args.done = done; switch(scsicmd[0]) { - /* no-op's, complete with success */ - case SYNCHRONIZE_CACHE: - case REZERO_UNIT: - case SEEK_6: - case SEEK_10: - case TEST_UNIT_READY: - case FORMAT_UNIT: /* FIXME: correct? */ - case SEND_DIAGNOSTIC: /* FIXME: correct? */ - ata_scsi_rbuf_fill(&args, ata_scsiop_noop); + /* TODO: worth improving? */ + case FORMAT_UNIT: + ata_scsi_invalid_field(cmd, done); break; case INQUIRY: @@ -2858,14 +2931,23 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, ata_scsi_invalid_field(cmd, done); else if ((scsicmd[1] & 1) == 0) /* is EVPD clear? */ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std); - else if (scsicmd[2] == 0x00) + else switch (scsicmd[2]) { + case 0x00: ata_scsi_rbuf_fill(&args, ata_scsiop_inq_00); - else if (scsicmd[2] == 0x80) + break; + case 0x80: ata_scsi_rbuf_fill(&args, ata_scsiop_inq_80); - else if (scsicmd[2] == 0x83) + break; + case 0x83: ata_scsi_rbuf_fill(&args, ata_scsiop_inq_83); - else + break; + case 0x89: + ata_scsi_rbuf_fill(&args, ata_scsiop_inq_89); + break; + default: ata_scsi_invalid_field(cmd, done); + break; + } break; case MODE_SENSE: @@ -2893,8 +2975,33 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, ata_scsi_rbuf_fill(&args, ata_scsiop_report_luns); break; - /* mandatory commands we haven't implemented yet */ case REQUEST_SENSE: + ata_scsi_set_sense(cmd, 0, 0, 0); + cmd->result = (DRIVER_SENSE << 24); + done(cmd); + break; + + /* if we reach this, then writeback caching is disabled, + * turning this into a no-op. + */ + case SYNCHRONIZE_CACHE: + /* fall through */ + + /* no-op's, complete with success */ + case REZERO_UNIT: + case SEEK_6: + case SEEK_10: + case TEST_UNIT_READY: + ata_scsi_rbuf_fill(&args, ata_scsiop_noop); + break; + + case SEND_DIAGNOSTIC: + tmp8 = scsicmd[1] & ~(1 << 3); + if ((tmp8 == 0x4) && (!scsicmd[3]) && (!scsicmd[4])) + ata_scsi_rbuf_fill(&args, ata_scsiop_noop); + else + ata_scsi_invalid_field(cmd, done); + break; /* all other commands */ default: @@ -2928,6 +3035,13 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht) shost->max_channel = 1; shost->max_cmd_len = 16; + /* Schedule policy is determined by ->qc_defer() + * callback and it needs to see every deferred qc. + * Set host_blocked to 1 to prevent SCSI midlayer from + * automatically deferring requests. + */ + shost->max_host_blocked = 1; + rc = scsi_add_host(ap->scsi_host, ap->host->dev); if (rc) goto err_add; @@ -2951,25 +3065,32 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync) { int tries = 5; struct ata_device *last_failed_dev = NULL; + struct ata_link *link; struct ata_device *dev; - unsigned int i; if (ap->flags & ATA_FLAG_DISABLED) return; repeat: - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct scsi_device *sdev; + ata_port_for_each_link(link, ap) { + ata_link_for_each_dev(dev, link) { + struct scsi_device *sdev; + int channel = 0, id = 0; - dev = &ap->device[i]; + if (!ata_dev_enabled(dev) || dev->sdev) + continue; - if (!ata_dev_enabled(dev) || dev->sdev) - continue; + if (ata_is_host_link(link)) + id = dev->devno; + else + channel = link->pmp; - sdev = __scsi_add_device(ap->scsi_host, 0, i, 0, NULL); - if (!IS_ERR(sdev)) { - dev->sdev = sdev; - scsi_device_put(sdev); + sdev = __scsi_add_device(ap->scsi_host, channel, id, 0, + NULL); + if (!IS_ERR(sdev)) { + dev->sdev = sdev; + scsi_device_put(sdev); + } } } @@ -2977,12 +3098,14 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync) * failure occurred, scan would have failed silently. Check * whether all devices are attached. */ - for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->device[i]; - if (ata_dev_enabled(dev) && !dev->sdev) - break; + ata_port_for_each_link(link, ap) { + ata_link_for_each_dev(dev, link) { + if (ata_dev_enabled(dev) && !dev->sdev) + goto exit_loop; + } } - if (i == ATA_MAX_DEVICES) + exit_loop: + if (!link) return; /* we're missing some SCSI devices */ @@ -3049,7 +3172,7 @@ int ata_scsi_offline_dev(struct ata_device *dev) */ static void ata_scsi_remove_dev(struct ata_device *dev) { - struct ata_port *ap = dev->ap; + struct ata_port *ap = dev->link->ap; struct scsi_device *sdev; unsigned long flags; @@ -3096,6 +3219,43 @@ static void ata_scsi_remove_dev(struct ata_device *dev) } } +static void ata_scsi_handle_link_detach(struct ata_link *link) +{ + struct ata_port *ap = link->ap; + struct ata_device *dev; + + ata_link_for_each_dev(dev, link) { + unsigned long flags; + + if (!(dev->flags & ATA_DFLAG_DETACHED)) + continue; + + spin_lock_irqsave(ap->lock, flags); + dev->flags &= ~ATA_DFLAG_DETACHED; + spin_unlock_irqrestore(ap->lock, flags); + + ata_scsi_remove_dev(dev); + } +} + +/** + * ata_scsi_media_change_notify - send media change event + * @atadev: Pointer to the disk device with media change event + * + * Tell the block layer to send a media change notification + * event. + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ +void ata_scsi_media_change_notify(struct ata_device *dev) +{ +#ifdef OTHER_AN_PATCHES_HAVE_BEEN_APPLIED + if (dev->sdev) + scsi_device_event_notify(dev->sdev, SDEV_MEDIA_CHANGE); +#endif +} + /** * ata_scsi_hotplug - SCSI part of hotplug * @work: Pointer to ATA port to perform SCSI hotplug on @@ -3121,20 +3281,14 @@ void ata_scsi_hotplug(struct work_struct *work) DPRINTK("ENTER\n"); - /* unplug detached devices */ - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; - unsigned long flags; - - if (!(dev->flags & ATA_DFLAG_DETACHED)) - continue; - - spin_lock_irqsave(ap->lock, flags); - dev->flags &= ~ATA_DFLAG_DETACHED; - spin_unlock_irqrestore(ap->lock, flags); - - ata_scsi_remove_dev(dev); - } + /* Unplug detached devices. We cannot use link iterator here + * because PMP links have to be scanned even if PMP is + * currently not attached. Iterate manually. + */ + ata_scsi_handle_link_detach(&ap->link); + if (ap->pmp_link) + for (i = 0; i < SATA_PMP_MAX_PORTS; i++) + ata_scsi_handle_link_detach(&ap->pmp_link[i]); /* scan for new ones */ ata_scsi_scan_host(ap, 0); @@ -3163,27 +3317,42 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, { struct ata_port *ap = ata_shost_to_port(shost); unsigned long flags; - int rc = 0; + int devno, rc = 0; if (!ap->ops->error_handler) return -EOPNOTSUPP; - if ((channel != SCAN_WILD_CARD && channel != 0) || - (lun != SCAN_WILD_CARD && lun != 0)) + if (lun != SCAN_WILD_CARD && lun) return -EINVAL; + if (ap->nr_pmp_links == 0) { + if (channel != SCAN_WILD_CARD && channel) + return -EINVAL; + devno = id; + } else { + if (id != SCAN_WILD_CARD && id) + return -EINVAL; + devno = channel; + } + spin_lock_irqsave(ap->lock, flags); - if (id == SCAN_WILD_CARD) { - ap->eh_info.probe_mask |= (1 << ATA_MAX_DEVICES) - 1; - ap->eh_info.action |= ATA_EH_SOFTRESET; + if (devno == SCAN_WILD_CARD) { + struct ata_link *link; + + ata_port_for_each_link(link, ap) { + struct ata_eh_info *ehi = &link->eh_info; + ehi->probe_mask |= (1 << ata_link_max_devices(link)) - 1; + ehi->action |= ATA_EH_SOFTRESET; + } } else { - struct ata_device *dev = ata_find_dev(ap, id); + struct ata_device *dev = ata_find_dev(ap, devno); if (dev) { - ap->eh_info.probe_mask |= 1 << dev->devno; - ap->eh_info.action |= ATA_EH_SOFTRESET; - ap->eh_info.flags |= ATA_EHI_RESUME_LINK; + struct ata_eh_info *ehi = &dev->link->eh_info; + ehi->probe_mask |= 1 << dev->devno; + ehi->action |= ATA_EH_SOFTRESET; + ehi->flags |= ATA_EHI_RESUME_LINK; } else rc = -EINVAL; } @@ -3214,24 +3383,26 @@ void ata_scsi_dev_rescan(struct work_struct *work) { struct ata_port *ap = container_of(work, struct ata_port, scsi_rescan_task); + struct ata_link *link; + struct ata_device *dev; unsigned long flags; - unsigned int i; spin_lock_irqsave(ap->lock, flags); - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; - struct scsi_device *sdev = dev->sdev; + ata_port_for_each_link(link, ap) { + ata_link_for_each_dev(dev, link) { + struct scsi_device *sdev = dev->sdev; - if (!ata_dev_enabled(dev) || !sdev) - continue; - if (scsi_device_get(sdev)) - continue; + if (!ata_dev_enabled(dev) || !sdev) + continue; + if (scsi_device_get(sdev)) + continue; - spin_unlock_irqrestore(ap->lock, flags); - scsi_rescan_device(&(sdev->sdev_gendev)); - scsi_device_put(sdev); - spin_lock_irqsave(ap->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); + scsi_rescan_device(&(sdev->sdev_gendev)); + scsi_device_put(sdev); + spin_lock_irqsave(ap->lock, flags); + } } spin_unlock_irqrestore(ap->lock, flags); @@ -3359,7 +3530,7 @@ EXPORT_SYMBOL_GPL(ata_sas_port_destroy); int ata_sas_slave_configure(struct scsi_device *sdev, struct ata_port *ap) { ata_scsi_sdev_config(sdev); - ata_scsi_dev_config(sdev, ap->device); + ata_scsi_dev_config(sdev, ap->link.device); return 0; } EXPORT_SYMBOL_GPL(ata_sas_slave_configure); @@ -3382,8 +3553,8 @@ int ata_sas_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), ata_scsi_dump_cdb(ap, cmd); - if (likely(ata_scsi_dev_enabled(ap->device))) - rc = __ata_scsi_queuecmd(cmd, done, ap->device); + if (likely(ata_scsi_dev_enabled(ap->link.device))) + rc = __ata_scsi_queuecmd(cmd, done, ap->link.device); else { cmd->result = (DID_BAD_TARGET << 16); done(cmd); diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 8023167bbbeb..026439e05afe 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -64,46 +64,6 @@ u8 ata_irq_on(struct ata_port *ap) return tmp; } -u8 ata_dummy_irq_on (struct ata_port *ap) { return 0; } - -/** - * ata_irq_ack - Acknowledge a device interrupt. - * @ap: Port on which interrupts are enabled. - * - * Wait up to 10 ms for legacy IDE device to become idle (BUSY - * or BUSY+DRQ clear). Obtain dma status and port status from - * device. Clear the interrupt. Return port status. - * - * LOCKING: - */ - -u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq) -{ - unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY; - u8 host_stat = 0, post_stat = 0, 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); - - if (ap->ioaddr.bmdma_addr) { - /* get controller status; clear intr, err bits */ - host_stat = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - iowrite8(host_stat | ATA_DMA_INTR | ATA_DMA_ERR, - ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - - post_stat = ioread8(ap->ioaddr.bmdma_addr + ATA_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; -} - -u8 ata_dummy_irq_ack(struct ata_port *ap, unsigned int chk_drq) { return 0; } - /** * ata_tf_load - send taskfile registers to host controller * @ap: Port to which output is sent @@ -445,7 +405,7 @@ void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset, unsigned long flags; int thaw = 0; - qc = __ata_qc_from_tag(ap, ap->active_tag); + qc = __ata_qc_from_tag(ap, ap->link.active_tag); if (qc && !(qc->flags & ATA_QCFLAG_FAILED)) qc = NULL; @@ -500,7 +460,7 @@ void ata_bmdma_error_handler(struct ata_port *ap) ata_reset_fn_t hardreset; hardreset = NULL; - if (sata_scr_valid(ap)) + if (sata_scr_valid(&ap->link)) hardreset = sata_std_hardreset; ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, hardreset, @@ -607,6 +567,9 @@ int ata_pci_init_bmdma(struct ata_host *host) if ((!(ap->flags & ATA_FLAG_IGN_SIMPLEX)) && (ioread8(bmdma + 2) & 0x80)) host->flags |= ATA_HOST_SIMPLEX; + + ata_port_desc(ap, "bmdma 0x%llx", + (unsigned long long)pci_resource_start(pdev, 4) + 8 * i); } return 0; @@ -674,6 +637,10 @@ int ata_pci_init_sff_host(struct ata_host *host) ((unsigned long)iomap[base + 1] | ATA_PCI_CTL_OFS); ata_std_ports(&ap->ioaddr); + ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx", + (unsigned long long)pci_resource_start(pdev, base), + (unsigned long long)pci_resource_start(pdev, base + 1)); + mask |= 1 << i; } @@ -844,24 +811,30 @@ int ata_pci_init_one(struct pci_dev *pdev, IRQF_SHARED, DRV_NAME, host); if (rc) goto err_out; - host->irq = pdev->irq; + + ata_port_desc(host->ports[0], "irq %d", pdev->irq); + ata_port_desc(host->ports[1], "irq %d", pdev->irq); } else { if (!ata_port_is_dummy(host->ports[0])) { - host->irq = ATA_PRIMARY_IRQ(pdev); - rc = devm_request_irq(dev, host->irq, + rc = devm_request_irq(dev, ATA_PRIMARY_IRQ(pdev), pi->port_ops->irq_handler, IRQF_SHARED, DRV_NAME, host); if (rc) goto err_out; + + ata_port_desc(host->ports[0], "irq %d", + ATA_PRIMARY_IRQ(pdev)); } if (!ata_port_is_dummy(host->ports[1])) { - host->irq2 = ATA_SECONDARY_IRQ(pdev); - rc = devm_request_irq(dev, host->irq2, + rc = devm_request_irq(dev, ATA_SECONDARY_IRQ(pdev), pi->port_ops->irq_handler, IRQF_SHARED, DRV_NAME, host); if (rc) goto err_out; + + ata_port_desc(host->ports[1], "irq %d", + ATA_SECONDARY_IRQ(pdev)); } } @@ -909,7 +882,7 @@ unsigned long ata_pci_default_filter(struct ata_device *adev, unsigned long xfer /* Filter out DMA modes if the device has been configured by the BIOS as PIO only */ - if (adev->ap->ioaddr.bmdma_addr == 0) + if (adev->link->ap->ioaddr.bmdma_addr == 0) xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA); return xfer_mask; } diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 564cd234c805..90df58a3edc9 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -29,6 +29,7 @@ #define __LIBATA_H__ #define DRV_NAME "libata" +#define DRV_VERSION "3.00" /* must be exactly four chars */ struct ata_scsi_args { struct ata_device *dev; @@ -56,6 +57,7 @@ extern unsigned int ata_print_id; extern struct workqueue_struct *ata_aux_wq; extern int atapi_enabled; extern int atapi_dmadir; +extern int atapi_passthru16; extern int libata_fua; extern int libata_noacpi; extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev); @@ -67,21 +69,23 @@ extern void ata_dev_disable(struct ata_device *dev); extern void ata_port_flush_task(struct ata_port *ap); extern unsigned ata_exec_internal(struct ata_device *dev, struct ata_taskfile *tf, const u8 *cdb, - int dma_dir, void *buf, unsigned int buflen); + int dma_dir, void *buf, unsigned int buflen, + unsigned long timeout); extern unsigned ata_exec_internal_sg(struct ata_device *dev, struct ata_taskfile *tf, const u8 *cdb, int dma_dir, struct scatterlist *sg, - unsigned int n_elem); + unsigned int n_elem, unsigned long timeout); extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd); extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, unsigned int flags, u16 *id); extern int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags); -extern int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags); +extern int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class, + unsigned int readid_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 sata_down_spd_limit(struct ata_link *link); +extern int sata_set_spd_needed(struct ata_link *link); 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 int ata_set_mode(struct ata_link *link, 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); extern void ata_qc_issue(struct ata_queued_cmd *qc); @@ -92,17 +96,21 @@ extern void ata_dev_select(struct ata_port *ap, unsigned int device, extern void swap_buf_le16(u16 *buf, unsigned int buf_words); extern int ata_flush_cache(struct ata_device *dev); extern void ata_dev_init(struct ata_device *dev); +extern void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp); +extern int sata_link_init_spd(struct ata_link *link); extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg); extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg); extern struct ata_port *ata_port_alloc(struct ata_host *host); /* libata-acpi.c */ #ifdef CONFIG_ATA_ACPI +extern void ata_acpi_associate_sata_port(struct ata_port *ap); extern void ata_acpi_associate(struct ata_host *host); extern int ata_acpi_on_suspend(struct ata_port *ap); extern void ata_acpi_on_resume(struct ata_port *ap); extern int ata_acpi_on_devcfg(struct ata_device *adev); #else +static inline void ata_acpi_associate_sata_port(struct ata_port *ap) { } static inline void ata_acpi_associate(struct ata_host *host) { } static inline int ata_acpi_on_suspend(struct ata_port *ap) { return 0; } static inline void ata_acpi_on_resume(struct ata_port *ap) { } @@ -114,6 +122,7 @@ extern int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht); extern void ata_scsi_scan_host(struct ata_port *ap, int sync); extern int ata_scsi_offline_dev(struct ata_device *dev); +extern void ata_scsi_media_change_notify(struct ata_device *dev); extern void ata_scsi_hotplug(struct work_struct *work); extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen); @@ -147,12 +156,32 @@ extern void ata_schedule_scsi_eh(struct Scsi_Host *shost); extern void ata_scsi_dev_rescan(struct work_struct *work); extern int ata_bus_probe(struct ata_port *ap); +/* libata-pmp.c */ +extern int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *val); +extern int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val); +extern int sata_pmp_attach(struct ata_device *dev); + /* libata-eh.c */ extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd); extern void ata_scsi_error(struct Scsi_Host *host); extern void ata_port_wait_eh(struct ata_port *ap); extern void ata_eh_fastdrain_timerfn(unsigned long arg); extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc); +extern void ata_eh_detach_dev(struct ata_device *dev); +extern void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev, + unsigned int action); +extern void ata_eh_done(struct ata_link *link, struct ata_device *dev, + unsigned int action); +extern void ata_eh_autopsy(struct ata_port *ap); +extern void ata_eh_report(struct ata_port *ap); +extern int ata_eh_reset(struct ata_link *link, int classify, + ata_prereset_fn_t prereset, ata_reset_fn_t softreset, + ata_reset_fn_t hardreset, ata_postreset_fn_t postreset); +extern int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, + ata_reset_fn_t softreset, ata_reset_fn_t hardreset, + ata_postreset_fn_t postreset, + struct ata_link **r_failed_disk); +extern void ata_eh_finish(struct ata_port *ap); /* libata-sff.c */ extern u8 ata_irq_on(struct ata_port *ap); diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c new file mode 100644 index 000000000000..5d3920f6fd69 --- /dev/null +++ b/drivers/ata/pata_acpi.c @@ -0,0 +1,395 @@ +/* + * ACPI PATA driver + * + * (c) 2007 Red Hat <alan@redhat.com> + */ + +#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 <acpi/acpi_bus.h> +#include <acpi/acnames.h> +#include <acpi/acnamesp.h> +#include <acpi/acparser.h> +#include <acpi/acexcep.h> +#include <acpi/acmacros.h> +#include <acpi/actypes.h> + +#include <linux/libata.h> +#include <linux/ata.h> + +#define DRV_NAME "pata_acpi" +#define DRV_VERSION "0.2.3" + +struct pata_acpi { + struct ata_acpi_gtm gtm; + void *last; + unsigned long mask[2]; +}; + +/** + * pacpi_pre_reset - check for 40/80 pin + * @ap: Port + * @deadline: deadline jiffies for the operation + * + * Perform the PATA port setup we need. + */ + +static int pacpi_pre_reset(struct ata_link *link, unsigned long deadline) +{ + struct ata_port *ap = link->ap; + struct pata_acpi *acpi = ap->private_data; + if (ap->acpi_handle == NULL || ata_acpi_gtm(ap, &acpi->gtm) < 0) + return -ENODEV; + + return ata_std_prereset(link, deadline); +} + +/** + * pacpi_cable_detect - cable type detection + * @ap: port to detect + * + * Perform device specific cable detection + */ + +static int pacpi_cable_detect(struct ata_port *ap) +{ + struct pata_acpi *acpi = ap->private_data; + + if ((acpi->mask[0] | acpi->mask[1]) & (0xF8 << ATA_SHIFT_UDMA)) + return ATA_CBL_PATA80; + else + return ATA_CBL_PATA40; +} + +/** + * pacpi_error_handler - Setup and error handler + * @ap: Port to handle + * + * LOCKING: + * None (inherited from caller). + */ + +static void pacpi_error_handler(struct ata_port *ap) +{ + return ata_bmdma_drive_eh(ap, pacpi_pre_reset, ata_std_softreset, + NULL, ata_std_postreset); +} + +/* Welcome to ACPI, bring a bucket */ +static const unsigned int pio_cycle[7] = { + 600, 383, 240, 180, 120, 100, 80 +}; +static const unsigned int mwdma_cycle[5] = { + 480, 150, 120, 100, 80 +}; +static const unsigned int udma_cycle[7] = { + 120, 80, 60, 45, 30, 20, 15 +}; + +/** + * pacpi_discover_modes - filter non ACPI modes + * @adev: ATA device + * @mask: proposed modes + * + * Try the modes available and see which ones the ACPI method will + * set up sensibly. From this we get a mask of ACPI modes we can use + */ + +static unsigned long pacpi_discover_modes(struct ata_port *ap, struct ata_device *adev) +{ + int unit = adev->devno; + struct pata_acpi *acpi = ap->private_data; + int i; + u32 t; + unsigned long mask = (0x7f << ATA_SHIFT_UDMA) | (0x7 << ATA_SHIFT_MWDMA) | (0x1F << ATA_SHIFT_PIO); + + struct ata_acpi_gtm probe; + + probe = acpi->gtm; + + /* We always use the 0 slot for crap hardware */ + if (!(probe.flags & 0x10)) + unit = 0; + + ata_acpi_gtm(ap, &probe); + + /* Start by scanning for PIO modes */ + for (i = 0; i < 7; i++) { + t = probe.drive[unit].pio; + if (t <= pio_cycle[i]) { + mask |= (2 << (ATA_SHIFT_PIO + i)) - 1; + break; + } + } + + /* See if we have MWDMA or UDMA data. We don't bother with MWDMA + if UDMA is availabe as this means the BIOS set UDMA and our + error changedown if it works is UDMA to PIO anyway */ + if (probe.flags & (1 << (2 * unit))) { + /* MWDMA */ + for (i = 0; i < 5; i++) { + t = probe.drive[unit].dma; + if (t <= mwdma_cycle[i]) { + mask |= (2 << (ATA_SHIFT_MWDMA + i)) - 1; + break; + } + } + } else { + /* UDMA */ + for (i = 0; i < 7; i++) { + t = probe.drive[unit].dma; + if (t <= udma_cycle[i]) { + mask |= (2 << (ATA_SHIFT_UDMA + i)) - 1; + break; + } + } + } + if (mask & (0xF8 << ATA_SHIFT_UDMA)) + ap->cbl = ATA_CBL_PATA80; + return mask; +} + +/** + * pacpi_mode_filter - mode filter for ACPI + * @adev: device + * @mask: mask of valid modes + * + * Filter the valid mode list according to our own specific rules, in + * this case the list of discovered valid modes obtained by ACPI probing + */ + +static unsigned long pacpi_mode_filter(struct ata_device *adev, unsigned long mask) +{ + struct pata_acpi *acpi = adev->link->ap->private_data; + return ata_pci_default_filter(adev, mask & acpi->mask[adev->devno]); +} + +/** + * pacpi_set_piomode - set initial PIO mode data + * @ap: ATA interface + * @adev: ATA device + */ + +static void pacpi_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + int unit = adev->devno; + struct pata_acpi *acpi = ap->private_data; + + if(!(acpi->gtm.flags & 0x10)) + unit = 0; + + /* Now stuff the nS values into the structure */ + acpi->gtm.drive[unit].pio = pio_cycle[adev->pio_mode - XFER_PIO_0]; + ata_acpi_stm(ap, &acpi->gtm); + /* See what mode we actually got */ + ata_acpi_gtm(ap, &acpi->gtm); +} + +/** + * pacpi_set_dmamode - set initial DMA mode data + * @ap: ATA interface + * @adev: ATA device + */ + +static void pacpi_set_dmamode(struct ata_port *ap, struct ata_device *adev) +{ + int unit = adev->devno; + struct pata_acpi *acpi = ap->private_data; + + if(!(acpi->gtm.flags & 0x10)) + unit = 0; + + /* Now stuff the nS values into the structure */ + if (adev->dma_mode >= XFER_UDMA_0) { + acpi->gtm.drive[unit].dma = udma_cycle[adev->dma_mode - XFER_UDMA_0]; + acpi->gtm.flags |= (1 << (2 * unit)); + } else { + acpi->gtm.drive[unit].dma = mwdma_cycle[adev->dma_mode - XFER_MW_DMA_0]; + acpi->gtm.flags &= ~(1 << (2 * unit)); + } + ata_acpi_stm(ap, &acpi->gtm); + /* See what mode we actually got */ + ata_acpi_gtm(ap, &acpi->gtm); +} + +/** + * pacpi_qc_issue_prot - command issue + * @qc: command pending + * + * Called when the libata layer is about to issue a command. We wrap + * this interface so that we can load the correct ATA timings if + * neccessary. + */ + +static unsigned int pacpi_qc_issue_prot(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct ata_device *adev = qc->dev; + struct pata_acpi *acpi = ap->private_data; + + if (acpi->gtm.flags & 0x10) + return ata_qc_issue_prot(qc); + + if (adev != acpi->last) { + pacpi_set_piomode(ap, adev); + if (adev->dma_mode) + pacpi_set_dmamode(ap, adev); + acpi->last = adev; + } + return ata_qc_issue_prot(qc); +} + +/** + * pacpi_port_start - port setup + * @ap: ATA port being set up + * + * Use the port_start hook to maintain private control structures + */ + +static int pacpi_port_start(struct ata_port *ap) +{ + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + struct pata_acpi *acpi; + + int ret; + + if (ap->acpi_handle == NULL) + return -ENODEV; + + acpi = ap->private_data = devm_kzalloc(&pdev->dev, sizeof(struct pata_acpi), GFP_KERNEL); + if (ap->private_data == NULL) + return -ENOMEM; + acpi->mask[0] = pacpi_discover_modes(ap, &ap->link.device[0]); + acpi->mask[1] = pacpi_discover_modes(ap, &ap->link.device[1]); + ret = ata_sff_port_start(ap); + if (ret < 0) + return ret; + + return ret; +} + +static struct scsi_host_template pacpi_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, + /* Use standard CHS mapping rules */ + .bios_param = ata_std_bios_param, +}; + +static const struct ata_port_operations pacpi_ops = { + .set_piomode = pacpi_set_piomode, + .set_dmamode = pacpi_set_dmamode, + .mode_filter = pacpi_mode_filter, + + /* Task file is PCI ATA format, use helpers */ + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = pacpi_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + .cable_detect = pacpi_cable_detect, + + /* BMDMA handling is PCI ATA format, use helpers */ + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, + .bmdma_stop = ata_bmdma_stop, + .bmdma_status = ata_bmdma_status, + .qc_prep = ata_qc_prep, + .qc_issue = pacpi_qc_issue_prot, + .data_xfer = ata_data_xfer, + + /* Timeout handling */ + .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + + /* Generic PATA PCI ATA helpers */ + .port_start = pacpi_port_start, +}; + + +/** + * pacpi_init_one - Register ACPI ATA PCI device with kernel services + * @pdev: PCI device to register + * @ent: Entry in pacpi_pci_tbl matching with @pdev + * + * Called from kernel PCI layer. + * + * LOCKING: + * Inherited from PCI layer (may sleep). + * + * RETURNS: + * Zero on success, or -ERRNO value. + */ + +static int pacpi_init_one (struct pci_dev *pdev, const struct pci_device_id *id) +{ + static const struct ata_port_info info = { + .sht = &pacpi_sht, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + + .pio_mask = 0x1f, + .mwdma_mask = 0x07, + .udma_mask = 0x7f, + + .port_ops = &pacpi_ops, + }; + const struct ata_port_info *ppi[] = { &info, NULL }; + return ata_pci_init_one(pdev, ppi); +} + +static const struct pci_device_id pacpi_pci_tbl[] = { + { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 1}, + { } /* terminate list */ +}; + +static struct pci_driver pacpi_pci_driver = { + .name = DRV_NAME, + .id_table = pacpi_pci_tbl, + .probe = pacpi_init_one, + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, +}; + +static int __init pacpi_init(void) +{ + return pci_register_driver(&pacpi_pci_driver); +} + +static void __exit pacpi_exit(void) +{ + pci_unregister_driver(&pacpi_pci_driver); +} + +module_init(pacpi_init); +module_exit(pacpi_exit); + +MODULE_AUTHOR("Alan Cox"); +MODULE_DESCRIPTION("SCSI low-level driver for ATA in ACPI mode"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, pacpi_pci_tbl); +MODULE_VERSION(DRV_VERSION); + diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index 32a10c99c06f..364534e7aff4 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -305,7 +305,6 @@ static struct scsi_host_template ali_sht = { */ static struct ata_port_operations ali_early_port_ops = { - .port_disable = ata_port_disable, .set_piomode = ali_set_piomode, .tf_load = ata_tf_load, .tf_read = ata_tf_read, @@ -327,9 +326,8 @@ static struct ata_port_operations ali_early_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /* @@ -337,8 +335,6 @@ static struct ata_port_operations ali_early_port_ops = { * detect */ static struct ata_port_operations ali_20_port_ops = { - .port_disable = ata_port_disable, - .set_piomode = ali_set_piomode, .set_dmamode = ali_set_dmamode, .mode_filter = ali_20_filter, @@ -369,16 +365,14 @@ static struct ata_port_operations ali_20_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /* * Port operations for DMA capable ALi with cable detect */ static struct ata_port_operations ali_c2_port_ops = { - .port_disable = ata_port_disable, .set_piomode = ali_set_piomode, .set_dmamode = ali_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -408,16 +402,14 @@ static struct ata_port_operations ali_c2_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /* * Port operations for DMA capable ALi with cable detect and LBA48 */ static struct ata_port_operations ali_c5_port_ops = { - .port_disable = ata_port_disable, .set_piomode = ali_set_piomode, .set_dmamode = ali_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -446,9 +438,8 @@ static struct ata_port_operations ali_c5_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index 04048fcf6305..c5779ad4abca 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -119,27 +119,28 @@ static void timing_setup(struct ata_port *ap, struct ata_device *adev, int offse } /** - * amd_probe_init - perform reset handling - * @ap: ATA port + * amd_pre_reset - perform reset handling + * @link: ATA link * @deadline: deadline jiffies for the operation * * Reset sequence checking enable bits to see which ports are * active. */ -static int amd_pre_reset(struct ata_port *ap, unsigned long deadline) +static int amd_pre_reset(struct ata_link *link, unsigned long deadline) { static const struct pci_bits amd_enable_bits[] = { { 0x40, 1, 0x02, 0x02 }, { 0x40, 1, 0x01, 0x01 } }; + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (!pci_test_config_bits(pdev, &amd_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } static void amd_error_handler(struct ata_port *ap) @@ -221,25 +222,26 @@ static void amd133_set_dmamode(struct ata_port *ap, struct ata_device *adev) /** * nv_probe_init - cable detection - * @ap: ATA port + * @lin: ATA link * * Perform cable detection. The BIOS stores this in PCI config * space for us. */ -static int nv_pre_reset(struct ata_port *ap, unsigned long deadline) +static int nv_pre_reset(struct ata_link *link, unsigned long deadline) { static const struct pci_bits nv_enable_bits[] = { { 0x50, 1, 0x02, 0x02 }, { 0x50, 1, 0x01, 0x01 } }; + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (!pci_test_config_bits(pdev, &nv_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } static void nv_error_handler(struct ata_port *ap) @@ -268,6 +270,9 @@ static int nv_cable_detect(struct ata_port *ap) pci_read_config_word(pdev, 0x62 - 2 * ap->port_no, &udma); if ((udma & 0xC4) == 0xC4 || (udma & 0xC400) == 0xC400) cbl = ATA_CBL_PATA80; + /* And a triple check across suspend/resume with ACPI around */ + if (ata_acpi_cbl_80wire(ap)) + cbl = ATA_CBL_PATA80; return cbl; } @@ -327,7 +332,6 @@ static struct scsi_host_template amd_sht = { }; static struct ata_port_operations amd33_port_ops = { - .port_disable = ata_port_disable, .set_piomode = amd33_set_piomode, .set_dmamode = amd33_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -356,13 +360,11 @@ static struct ata_port_operations amd33_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations amd66_port_ops = { - .port_disable = ata_port_disable, .set_piomode = amd66_set_piomode, .set_dmamode = amd66_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -391,13 +393,11 @@ static struct ata_port_operations amd66_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations amd100_port_ops = { - .port_disable = ata_port_disable, .set_piomode = amd100_set_piomode, .set_dmamode = amd100_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -426,13 +426,11 @@ static struct ata_port_operations amd100_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations amd133_port_ops = { - .port_disable = ata_port_disable, .set_piomode = amd133_set_piomode, .set_dmamode = amd133_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -461,13 +459,11 @@ static struct ata_port_operations amd133_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations nv100_port_ops = { - .port_disable = ata_port_disable, .set_piomode = nv100_set_piomode, .set_dmamode = nv100_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -496,13 +492,11 @@ static struct ata_port_operations nv100_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations nv133_port_ops = { - .port_disable = ata_port_disable, .set_piomode = nv133_set_piomode, .set_dmamode = nv133_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -531,9 +525,8 @@ static struct ata_port_operations nv133_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c index b5352ebecef9..d4218310327b 100644 --- a/drivers/ata/pata_artop.c +++ b/drivers/ata/pata_artop.c @@ -40,8 +40,9 @@ static int clock = 0; -static int artop6210_pre_reset(struct ata_port *ap, unsigned long deadline) +static int artop6210_pre_reset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); const struct pci_bits artop_enable_bits[] = { { 0x4AU, 1U, 0x02UL, 0x02UL }, /* port 0 */ @@ -51,7 +52,7 @@ static int artop6210_pre_reset(struct ata_port *ap, unsigned long deadline) if (!pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** @@ -71,27 +72,28 @@ static void artop6210_error_handler(struct ata_port *ap) /** * artop6260_pre_reset - check for 40/80 pin - * @ap: Port + * @link: link * @deadline: deadline jiffies for the operation * * The ARTOP hardware reports the cable detect bits in register 0x49. * Nothing complicated needed here. */ -static int artop6260_pre_reset(struct ata_port *ap, unsigned long deadline) +static int artop6260_pre_reset(struct ata_link *link, unsigned long deadline) { static const struct pci_bits artop_enable_bits[] = { { 0x4AU, 1U, 0x02UL, 0x02UL }, /* port 0 */ { 0x4AU, 1U, 0x04UL, 0x04UL }, /* port 1 */ }; + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); /* Odd numbered device ids are the units with enable bits (the -R cards) */ if (pdev->device % 1 && !pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** @@ -330,7 +332,6 @@ static struct scsi_host_template artop_sht = { }; static const struct ata_port_operations artop6210_ops = { - .port_disable = ata_port_disable, .set_piomode = artop6210_set_piomode, .set_dmamode = artop6210_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -359,13 +360,11 @@ static const struct ata_port_operations artop6210_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static const struct ata_port_operations artop6260_ops = { - .port_disable = ata_port_disable, .set_piomode = artop6260_set_piomode, .set_dmamode = artop6260_set_dmamode, @@ -392,9 +391,8 @@ static const struct ata_port_operations artop6260_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_at32.c b/drivers/ata/pata_at32.c new file mode 100644 index 000000000000..bb250a48e27c --- /dev/null +++ b/drivers/ata/pata_at32.c @@ -0,0 +1,441 @@ +/* + * AVR32 SMC/CFC PATA Driver + * + * Copyright (C) 2007 Atmel Norway + * + * 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. + */ + +#define DEBUG + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <scsi/scsi_host.h> +#include <linux/ata.h> +#include <linux/libata.h> +#include <linux/err.h> +#include <linux/io.h> + +#include <asm/arch/board.h> +#include <asm/arch/smc.h> + +#define DRV_NAME "pata_at32" +#define DRV_VERSION "0.0.2" + +/* + * CompactFlash controller memory layout relative to the base address: + * + * Attribute memory: 0000 0000 -> 003f ffff + * Common memory: 0040 0000 -> 007f ffff + * I/O memory: 0080 0000 -> 00bf ffff + * True IDE Mode: 00c0 0000 -> 00df ffff + * Alt IDE Mode: 00e0 0000 -> 00ff ffff + * + * Only True IDE and Alt True IDE mode are needed for this driver. + * + * True IDE mode => CS0 = 0, CS1 = 1 (cmd, error, stat, etc) + * Alt True IDE mode => CS0 = 1, CS1 = 0 (ctl, alt_stat) + */ +#define CF_IDE_OFFSET 0x00c00000 +#define CF_ALT_IDE_OFFSET 0x00e00000 +#define CF_RES_SIZE 2048 + +/* + * Define DEBUG_BUS if you are doing debugging of your own EBI -> PATA + * adaptor with a logic analyzer or similar. + */ +#undef DEBUG_BUS + +/* + * ATA PIO modes + * + * Name | Mb/s | Min cycle time | Mask + * --------+-------+----------------+-------- + * Mode 0 | 3.3 | 600 ns | 0x01 + * Mode 1 | 5.2 | 383 ns | 0x03 + * Mode 2 | 8.3 | 240 ns | 0x07 + * Mode 3 | 11.1 | 180 ns | 0x0f + * Mode 4 | 16.7 | 120 ns | 0x1f + */ +#define PIO_MASK (0x1f) + +/* + * Struct containing private information about device. + */ +struct at32_ide_info { + unsigned int irq; + struct resource res_ide; + struct resource res_alt; + void __iomem *ide_addr; + void __iomem *alt_addr; + unsigned int cs; + struct smc_config smc; +}; + +/* + * Setup SMC for the given ATA timing. + */ +static int pata_at32_setup_timing(struct device *dev, + struct at32_ide_info *info, + const struct ata_timing *timing) +{ + /* These two values are found through testing */ + const int min_recover = 25; + const int ncs_hold = 15; + + struct smc_config *smc = &info->smc; + + int active; + int recover; + + /* Total cycle time */ + smc->read_cycle = timing->cyc8b; + + /* DIOR <= CFIOR timings */ + smc->nrd_setup = timing->setup; + smc->nrd_pulse = timing->act8b; + + /* Compute recover, extend total cycle if needed */ + active = smc->nrd_setup + smc->nrd_pulse; + recover = smc->read_cycle - active; + + if (recover < min_recover) { + smc->read_cycle = active + min_recover; + recover = min_recover; + } + + /* (CS0, CS1, DIR, OE) <= (CFCE1, CFCE2, CFRNW, NCSX) timings */ + smc->ncs_read_setup = 0; + smc->ncs_read_pulse = active + ncs_hold; + + /* Write timings same as read timings */ + smc->write_cycle = smc->read_cycle; + smc->nwe_setup = smc->nrd_setup; + smc->nwe_pulse = smc->nrd_pulse; + smc->ncs_write_setup = smc->ncs_read_setup; + smc->ncs_write_pulse = smc->ncs_read_pulse; + + /* Do some debugging output */ + dev_dbg(dev, "SMC: C=%d S=%d P=%d R=%d NCSS=%d NCSP=%d NCSR=%d\n", + smc->read_cycle, smc->nrd_setup, smc->nrd_pulse, + recover, smc->ncs_read_setup, smc->ncs_read_pulse, + smc->read_cycle - smc->ncs_read_pulse); + + /* Finally, configure the SMC */ + return smc_set_configuration(info->cs, smc); +} + +/* + * Procedures for libATA. + */ +static void pata_at32_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + struct ata_timing timing; + struct at32_ide_info *info = ap->host->private_data; + + int ret; + + /* Compute ATA timing */ + ret = ata_timing_compute(adev, adev->pio_mode, &timing, 1000, 0); + if (ret) { + dev_warn(ap->dev, "Failed to compute ATA timing %d\n", ret); + return; + } + + /* Setup SMC to ATA timing */ + ret = pata_at32_setup_timing(ap->dev, info, &timing); + if (ret) { + dev_warn(ap->dev, "Failed to setup ATA timing %d\n", ret); + return; + } +} + +static void pata_at32_irq_clear(struct ata_port *ap) +{ + /* No DMA controller yet */ +} + +static struct scsi_host_template at32_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, +}; + +static struct ata_port_operations at32_port_ops = { + .port_disable = ata_port_disable, + .set_piomode = pata_at32_set_piomode, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .exec_command = ata_exec_command, + .check_status = ata_check_status, + .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, + .cable_detect = ata_cable_40wire, + + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .data_xfer = ata_data_xfer, + + .irq_clear = pata_at32_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, + + .port_start = ata_sff_port_start, +}; + +static int __init pata_at32_init_one(struct device *dev, + struct at32_ide_info *info) +{ + struct ata_host *host; + struct ata_port *ap; + + host = ata_host_alloc(dev, 1); + if (!host) + return -ENOMEM; + + ap = host->ports[0]; + + /* Setup ATA bindings */ + ap->ops = &at32_port_ops; + ap->pio_mask = PIO_MASK; + ap->flags = ATA_FLAG_MMIO | ATA_FLAG_SLAVE_POSS + | ATA_FLAG_PIO_POLLING; + + /* + * Since all 8-bit taskfile transfers has to go on the lower + * byte of the data bus and there is a bug in the SMC that + * makes it impossible to alter the bus width during runtime, + * we need to hardwire the address signals as follows: + * + * A_IDE(2:0) <= A_EBI(3:1) + * + * This makes all addresses on the EBI even, thus all data + * will be on the lower byte of the data bus. All addresses + * used by libATA need to be altered according to this. + */ + ap->ioaddr.altstatus_addr = info->alt_addr + (0x06 << 1); + ap->ioaddr.ctl_addr = info->alt_addr + (0x06 << 1); + + ap->ioaddr.data_addr = info->ide_addr + (ATA_REG_DATA << 1); + ap->ioaddr.error_addr = info->ide_addr + (ATA_REG_ERR << 1); + ap->ioaddr.feature_addr = info->ide_addr + (ATA_REG_FEATURE << 1); + ap->ioaddr.nsect_addr = info->ide_addr + (ATA_REG_NSECT << 1); + ap->ioaddr.lbal_addr = info->ide_addr + (ATA_REG_LBAL << 1); + ap->ioaddr.lbam_addr = info->ide_addr + (ATA_REG_LBAM << 1); + ap->ioaddr.lbah_addr = info->ide_addr + (ATA_REG_LBAH << 1); + ap->ioaddr.device_addr = info->ide_addr + (ATA_REG_DEVICE << 1); + ap->ioaddr.status_addr = info->ide_addr + (ATA_REG_STATUS << 1); + ap->ioaddr.command_addr = info->ide_addr + (ATA_REG_CMD << 1); + + /* Set info as private data of ATA host */ + host->private_data = info; + + /* Register ATA device and return */ + return ata_host_activate(host, info->irq, ata_interrupt, + IRQF_SHARED | IRQF_TRIGGER_RISING, + &at32_sht); +} + +/* + * This function may come in handy for people analyzing their own + * EBI -> PATA adaptors. + */ +#ifdef DEBUG_BUS + +static void __init pata_at32_debug_bus(struct device *dev, + struct at32_ide_info *info) +{ + const int d1 = 0xff; + const int d2 = 0x00; + + int i; + + /* Write 8-bit values (registers) */ + iowrite8(d1, info->alt_addr + (0x06 << 1)); + iowrite8(d2, info->alt_addr + (0x06 << 1)); + + for (i = 0; i < 8; i++) { + iowrite8(d1, info->ide_addr + (i << 1)); + iowrite8(d2, info->ide_addr + (i << 1)); + } + + /* Write 16 bit values (data) */ + iowrite16(d1, info->ide_addr); + iowrite16(d1 << 8, info->ide_addr); + + iowrite16(d1, info->ide_addr); + iowrite16(d1 << 8, info->ide_addr); +} + +#endif + +static int __init pata_at32_probe(struct platform_device *pdev) +{ + const struct ata_timing initial_timing = + {XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0}; + + struct device *dev = &pdev->dev; + struct at32_ide_info *info; + struct ide_platform_data *board = pdev->dev.platform_data; + struct resource *res; + + int irq; + int ret; + + if (!board) + return -ENXIO; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENXIO; + + /* Retrive IRQ */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + /* Setup struct containing private infomation */ + info = kzalloc(sizeof(struct at32_ide_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + memset(info, 0, sizeof(struct at32_ide_info)); + + info->irq = irq; + info->cs = board->cs; + + /* Request memory resources */ + info->res_ide.start = res->start + CF_IDE_OFFSET; + info->res_ide.end = info->res_ide.start + CF_RES_SIZE - 1; + info->res_ide.name = "ide"; + info->res_ide.flags = IORESOURCE_MEM; + + ret = request_resource(res, &info->res_ide); + if (ret) + goto err_req_res_ide; + + info->res_alt.start = res->start + CF_ALT_IDE_OFFSET; + info->res_alt.end = info->res_alt.start + CF_RES_SIZE - 1; + info->res_alt.name = "alt"; + info->res_alt.flags = IORESOURCE_MEM; + + ret = request_resource(res, &info->res_alt); + if (ret) + goto err_req_res_alt; + + /* Setup non-timing elements of SMC */ + info->smc.bus_width = 2; /* 16 bit data bus */ + info->smc.nrd_controlled = 1; /* Sample data on rising edge of NRD */ + info->smc.nwe_controlled = 0; /* Drive data on falling edge of NCS */ + info->smc.nwait_mode = 3; /* NWAIT is in READY mode */ + info->smc.byte_write = 0; /* Byte select access type */ + info->smc.tdf_mode = 0; /* TDF optimization disabled */ + info->smc.tdf_cycles = 0; /* No TDF wait cycles */ + + /* Setup ATA timing */ + ret = pata_at32_setup_timing(dev, info, &initial_timing); + if (ret) + goto err_setup_timing; + + /* Setup ATA addresses */ + ret = -ENOMEM; + info->ide_addr = devm_ioremap(dev, info->res_ide.start, 16); + info->alt_addr = devm_ioremap(dev, info->res_alt.start, 16); + if (!info->ide_addr || !info->alt_addr) + goto err_ioremap; + +#ifdef DEBUG_BUS + pata_at32_debug_bus(dev, info); +#endif + + /* Register ATA device */ + ret = pata_at32_init_one(dev, info); + if (ret) + goto err_ata_device; + + return 0; + + err_ata_device: + err_ioremap: + err_setup_timing: + release_resource(&info->res_alt); + err_req_res_alt: + release_resource(&info->res_ide); + err_req_res_ide: + kfree(info); + + return ret; +} + +static int __exit pata_at32_remove(struct platform_device *pdev) +{ + struct ata_host *host = platform_get_drvdata(pdev); + struct at32_ide_info *info; + + if (!host) + return 0; + + info = host->private_data; + ata_host_detach(host); + + if (!info) + return 0; + + release_resource(&info->res_ide); + release_resource(&info->res_alt); + + kfree(info); + + return 0; +} + +static struct platform_driver pata_at32_driver = { + .remove = __exit_p(pata_at32_remove), + .driver = { + .name = "at32_ide", + .owner = THIS_MODULE, + }, +}; + +static int __init pata_at32_init(void) +{ + return platform_driver_probe(&pata_at32_driver, pata_at32_probe); +} + +static void __exit pata_at32_exit(void) +{ + platform_driver_unregister(&pata_at32_driver); +} + +module_init(pata_at32_init); +module_exit(pata_at32_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("AVR32 SMC/CFC PATA Driver"); +MODULE_AUTHOR("Kristoffer Nyborg Gregertsen <kngregertsen@norway.atmel.com>"); +MODULE_VERSION(DRV_VERSION); diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 86f85a2cab7e..9623f5295530 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -33,8 +33,9 @@ enum { ATIIXP_IDE_UDMA_MODE = 0x56 }; -static int atiixp_pre_reset(struct ata_port *ap, unsigned long deadline) +static int atiixp_pre_reset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; static const struct pci_bits atiixp_enable_bits[] = { { 0x48, 1, 0x01, 0x00 }, { 0x48, 1, 0x08, 0x00 } @@ -44,7 +45,7 @@ static int atiixp_pre_reset(struct ata_port *ap, unsigned long deadline) if (!pci_test_config_bits(pdev, &atiixp_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } static void atiixp_error_handler(struct ata_port *ap) @@ -172,6 +173,9 @@ static void atiixp_set_dmamode(struct ata_port *ap, struct ata_device *adev) * * When DMA begins we need to ensure that the UDMA control * register for the channel is correctly set. + * + * Note: The host lock held by the libata layer protects + * us from two channels both trying to set DMA bits at once */ static void atiixp_bmdma_start(struct ata_queued_cmd *qc) @@ -198,6 +202,9 @@ static void atiixp_bmdma_start(struct ata_queued_cmd *qc) * * DMA has completed. Clear the UDMA flag as the next operations will * be PIO ones not UDMA data transfer. + * + * Note: The host lock held by the libata layer protects + * us from two channels both trying to set DMA bits at once */ static void atiixp_bmdma_stop(struct ata_queued_cmd *qc) @@ -232,7 +239,6 @@ static struct scsi_host_template atiixp_sht = { }; static struct ata_port_operations atiixp_port_ops = { - .port_disable = ata_port_disable, .set_piomode = atiixp_set_piomode, .set_dmamode = atiixp_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -261,9 +267,8 @@ static struct ata_port_operations atiixp_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c new file mode 100644 index 000000000000..747549e4563a --- /dev/null +++ b/drivers/ata/pata_bf54x.c @@ -0,0 +1,1627 @@ +/* + * File: drivers/ata/pata_bf54x.c + * Author: Sonic Zhang <sonic.zhang@analog.com> + * + * Created: + * Description: PATA Driver for blackfin 54x + * + * Modified: + * Copyright 2007 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, 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> +#include <linux/platform_device.h> +#include <asm/dma.h> +#include <asm/gpio.h> +#include <asm/portmux.h> + +#define DRV_NAME "pata-bf54x" +#define DRV_VERSION "0.9" + +#define ATA_REG_CTRL 0x0E +#define ATA_REG_ALTSTATUS ATA_REG_CTRL + +/* These are the offset of the controller's registers */ +#define ATAPI_OFFSET_CONTROL 0x00 +#define ATAPI_OFFSET_STATUS 0x04 +#define ATAPI_OFFSET_DEV_ADDR 0x08 +#define ATAPI_OFFSET_DEV_TXBUF 0x0c +#define ATAPI_OFFSET_DEV_RXBUF 0x10 +#define ATAPI_OFFSET_INT_MASK 0x14 +#define ATAPI_OFFSET_INT_STATUS 0x18 +#define ATAPI_OFFSET_XFER_LEN 0x1c +#define ATAPI_OFFSET_LINE_STATUS 0x20 +#define ATAPI_OFFSET_SM_STATE 0x24 +#define ATAPI_OFFSET_TERMINATE 0x28 +#define ATAPI_OFFSET_PIO_TFRCNT 0x2c +#define ATAPI_OFFSET_DMA_TFRCNT 0x30 +#define ATAPI_OFFSET_UMAIN_TFRCNT 0x34 +#define ATAPI_OFFSET_UDMAOUT_TFRCNT 0x38 +#define ATAPI_OFFSET_REG_TIM_0 0x40 +#define ATAPI_OFFSET_PIO_TIM_0 0x44 +#define ATAPI_OFFSET_PIO_TIM_1 0x48 +#define ATAPI_OFFSET_MULTI_TIM_0 0x50 +#define ATAPI_OFFSET_MULTI_TIM_1 0x54 +#define ATAPI_OFFSET_MULTI_TIM_2 0x58 +#define ATAPI_OFFSET_ULTRA_TIM_0 0x60 +#define ATAPI_OFFSET_ULTRA_TIM_1 0x64 +#define ATAPI_OFFSET_ULTRA_TIM_2 0x68 +#define ATAPI_OFFSET_ULTRA_TIM_3 0x6c + + +#define ATAPI_GET_CONTROL(base)\ + bfin_read16(base + ATAPI_OFFSET_CONTROL) +#define ATAPI_SET_CONTROL(base, val)\ + bfin_write16(base + ATAPI_OFFSET_CONTROL, val) +#define ATAPI_GET_STATUS(base)\ + bfin_read16(base + ATAPI_OFFSET_STATUS) +#define ATAPI_GET_DEV_ADDR(base)\ + bfin_read16(base + ATAPI_OFFSET_DEV_ADDR) +#define ATAPI_SET_DEV_ADDR(base, val)\ + bfin_write16(base + ATAPI_OFFSET_DEV_ADDR, val) +#define ATAPI_GET_DEV_TXBUF(base)\ + bfin_read16(base + ATAPI_OFFSET_DEV_TXBUF) +#define ATAPI_SET_DEV_TXBUF(base, val)\ + bfin_write16(base + ATAPI_OFFSET_DEV_TXBUF, val) +#define ATAPI_GET_DEV_RXBUF(base)\ + bfin_read16(base + ATAPI_OFFSET_DEV_RXBUF) +#define ATAPI_SET_DEV_RXBUF(base, val)\ + bfin_write16(base + ATAPI_OFFSET_DEV_RXBUF, val) +#define ATAPI_GET_INT_MASK(base)\ + bfin_read16(base + ATAPI_OFFSET_INT_MASK) +#define ATAPI_SET_INT_MASK(base, val)\ + bfin_write16(base + ATAPI_OFFSET_INT_MASK, val) +#define ATAPI_GET_INT_STATUS(base)\ + bfin_read16(base + ATAPI_OFFSET_INT_STATUS) +#define ATAPI_SET_INT_STATUS(base, val)\ + bfin_write16(base + ATAPI_OFFSET_INT_STATUS, val) +#define ATAPI_GET_XFER_LEN(base)\ + bfin_read16(base + ATAPI_OFFSET_XFER_LEN) +#define ATAPI_SET_XFER_LEN(base, val)\ + bfin_write16(base + ATAPI_OFFSET_XFER_LEN, val) +#define ATAPI_GET_LINE_STATUS(base)\ + bfin_read16(base + ATAPI_OFFSET_LINE_STATUS) +#define ATAPI_GET_SM_STATE(base)\ + bfin_read16(base + ATAPI_OFFSET_SM_STATE) +#define ATAPI_GET_TERMINATE(base)\ + bfin_read16(base + ATAPI_OFFSET_TERMINATE) +#define ATAPI_SET_TERMINATE(base, val)\ + bfin_write16(base + ATAPI_OFFSET_TERMINATE, val) +#define ATAPI_GET_PIO_TFRCNT(base)\ + bfin_read16(base + ATAPI_OFFSET_PIO_TFRCNT) +#define ATAPI_GET_DMA_TFRCNT(base)\ + bfin_read16(base + ATAPI_OFFSET_DMA_TFRCNT) +#define ATAPI_GET_UMAIN_TFRCNT(base)\ + bfin_read16(base + ATAPI_OFFSET_UMAIN_TFRCNT) +#define ATAPI_GET_UDMAOUT_TFRCNT(base)\ + bfin_read16(base + ATAPI_OFFSET_UDMAOUT_TFRCNT) +#define ATAPI_GET_REG_TIM_0(base)\ + bfin_read16(base + ATAPI_OFFSET_REG_TIM_0) +#define ATAPI_SET_REG_TIM_0(base, val)\ + bfin_write16(base + ATAPI_OFFSET_REG_TIM_0, val) +#define ATAPI_GET_PIO_TIM_0(base)\ + bfin_read16(base + ATAPI_OFFSET_PIO_TIM_0) +#define ATAPI_SET_PIO_TIM_0(base, val)\ + bfin_write16(base + ATAPI_OFFSET_PIO_TIM_0, val) +#define ATAPI_GET_PIO_TIM_1(base)\ + bfin_read16(base + ATAPI_OFFSET_PIO_TIM_1) +#define ATAPI_SET_PIO_TIM_1(base, val)\ + bfin_write16(base + ATAPI_OFFSET_PIO_TIM_1, val) +#define ATAPI_GET_MULTI_TIM_0(base)\ + bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_0) +#define ATAPI_SET_MULTI_TIM_0(base, val)\ + bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_0, val) +#define ATAPI_GET_MULTI_TIM_1(base)\ + bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_1) +#define ATAPI_SET_MULTI_TIM_1(base, val)\ + bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_1, val) +#define ATAPI_GET_MULTI_TIM_2(base)\ + bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_2) +#define ATAPI_SET_MULTI_TIM_2(base, val)\ + bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_2, val) +#define ATAPI_GET_ULTRA_TIM_0(base)\ + bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_0) +#define ATAPI_SET_ULTRA_TIM_0(base, val)\ + bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_0, val) +#define ATAPI_GET_ULTRA_TIM_1(base)\ + bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_1) +#define ATAPI_SET_ULTRA_TIM_1(base, val)\ + bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_1, val) +#define ATAPI_GET_ULTRA_TIM_2(base)\ + bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_2) +#define ATAPI_SET_ULTRA_TIM_2(base, val)\ + bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_2, val) +#define ATAPI_GET_ULTRA_TIM_3(base)\ + bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_3) +#define ATAPI_SET_ULTRA_TIM_3(base, val)\ + bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_3, val) + +/** + * PIO Mode - Frequency compatibility + */ +/* mode: 0 1 2 3 4 */ +static const u32 pio_fsclk[] = +{ 33333333, 33333333, 33333333, 33333333, 33333333 }; + +/** + * MDMA Mode - Frequency compatibility + */ +/* mode: 0 1 2 */ +static const u32 mdma_fsclk[] = { 33333333, 33333333, 33333333 }; + +/** + * UDMA Mode - Frequency compatibility + * + * UDMA5 - 100 MB/s - SCLK = 133 MHz + * UDMA4 - 66 MB/s - SCLK >= 80 MHz + * UDMA3 - 44.4 MB/s - SCLK >= 50 MHz + * UDMA2 - 33 MB/s - SCLK >= 40 MHz + */ +/* mode: 0 1 2 3 4 5 */ +static const u32 udma_fsclk[] = +{ 33333333, 33333333, 40000000, 50000000, 80000000, 133333333 }; + +/** + * Register transfer timing table + */ +/* mode: 0 1 2 3 4 */ +/* Cycle Time */ +static const u32 reg_t0min[] = { 600, 383, 330, 180, 120 }; +/* DIOR/DIOW to end cycle */ +static const u32 reg_t2min[] = { 290, 290, 290, 70, 25 }; +/* DIOR/DIOW asserted pulse width */ +static const u32 reg_teocmin[] = { 290, 290, 290, 80, 70 }; + +/** + * PIO timing table + */ +/* mode: 0 1 2 3 4 */ +/* Cycle Time */ +static const u32 pio_t0min[] = { 600, 383, 240, 180, 120 }; +/* Address valid to DIOR/DIORW */ +static const u32 pio_t1min[] = { 70, 50, 30, 30, 25 }; +/* DIOR/DIOW to end cycle */ +static const u32 pio_t2min[] = { 165, 125, 100, 80, 70 }; +/* DIOR/DIOW asserted pulse width */ +static const u32 pio_teocmin[] = { 165, 125, 100, 70, 25 }; +/* DIOW data hold */ +static const u32 pio_t4min[] = { 30, 20, 15, 10, 10 }; + +/* ****************************************************************** + * Multiword DMA timing table + * ****************************************************************** + */ +/* mode: 0 1 2 */ +/* Cycle Time */ +static const u32 mdma_t0min[] = { 480, 150, 120 }; +/* DIOR/DIOW asserted pulse width */ +static const u32 mdma_tdmin[] = { 215, 80, 70 }; +/* DMACK to read data released */ +static const u32 mdma_thmin[] = { 20, 15, 10 }; +/* DIOR/DIOW to DMACK hold */ +static const u32 mdma_tjmin[] = { 20, 5, 5 }; +/* DIOR negated pulse width */ +static const u32 mdma_tkrmin[] = { 50, 50, 25 }; +/* DIOR negated pulse width */ +static const u32 mdma_tkwmin[] = { 215, 50, 25 }; +/* CS[1:0] valid to DIOR/DIOW */ +static const u32 mdma_tmmin[] = { 50, 30, 25 }; +/* DMACK to read data released */ +static const u32 mdma_tzmax[] = { 20, 25, 25 }; + +/** + * Ultra DMA timing table + */ +/* mode: 0 1 2 3 4 5 */ +static const u32 udma_tcycmin[] = { 112, 73, 54, 39, 25, 17 }; +static const u32 udma_tdvsmin[] = { 70, 48, 31, 20, 7, 5 }; +static const u32 udma_tenvmax[] = { 70, 70, 70, 55, 55, 50 }; +static const u32 udma_trpmin[] = { 160, 125, 100, 100, 100, 85 }; +static const u32 udma_tmin[] = { 5, 5, 5, 5, 3, 3 }; + + +static const u32 udma_tmlimin = 20; +static const u32 udma_tzahmin = 20; +static const u32 udma_tenvmin = 20; +static const u32 udma_tackmin = 20; +static const u32 udma_tssmin = 50; + +/** + * + * Function: num_clocks_min + * + * Description: + * calculate number of SCLK cycles to meet minimum timing + */ +static unsigned short num_clocks_min(unsigned long tmin, + unsigned long fsclk) +{ + unsigned long tmp ; + unsigned short result; + + tmp = tmin * (fsclk/1000/1000) / 1000; + result = (unsigned short)tmp; + if ((tmp*1000*1000) < (tmin*(fsclk/1000))) { + result++; + } + + return result; +} + +/** + * bfin_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 bfin_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + int mode = adev->pio_mode - XFER_PIO_0; + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + unsigned int fsclk = get_sclk(); + unsigned short teoc_reg, t2_reg, teoc_pio; + unsigned short t4_reg, t2_pio, t1_reg; + unsigned short n0, n6, t6min = 5; + + /* the most restrictive timing value is t6 and tc, the DIOW - data hold + * If one SCLK pulse is longer than this minimum value then register + * transfers cannot be supported at this frequency. + */ + n6 = num_clocks_min(t6min, fsclk); + if (mode >= 0 && mode <= 4 && n6 >= 1) { + pr_debug("set piomode: mode=%d, fsclk=%ud\n", mode, fsclk); + /* calculate the timing values for register transfers. */ + while (mode > 0 && pio_fsclk[mode] > fsclk) + mode--; + + /* DIOR/DIOW to end cycle time */ + t2_reg = num_clocks_min(reg_t2min[mode], fsclk); + /* DIOR/DIOW asserted pulse width */ + teoc_reg = num_clocks_min(reg_teocmin[mode], fsclk); + /* Cycle Time */ + n0 = num_clocks_min(reg_t0min[mode], fsclk); + + /* increase t2 until we meed the minimum cycle length */ + if (t2_reg + teoc_reg < n0) + t2_reg = n0 - teoc_reg; + + /* calculate the timing values for pio transfers. */ + + /* DIOR/DIOW to end cycle time */ + t2_pio = num_clocks_min(pio_t2min[mode], fsclk); + /* DIOR/DIOW asserted pulse width */ + teoc_pio = num_clocks_min(pio_teocmin[mode], fsclk); + /* Cycle Time */ + n0 = num_clocks_min(pio_t0min[mode], fsclk); + + /* increase t2 until we meed the minimum cycle length */ + if (t2_pio + teoc_pio < n0) + t2_pio = n0 - teoc_pio; + + /* Address valid to DIOR/DIORW */ + t1_reg = num_clocks_min(pio_t1min[mode], fsclk); + + /* DIOW data hold */ + t4_reg = num_clocks_min(pio_t4min[mode], fsclk); + + ATAPI_SET_REG_TIM_0(base, (teoc_reg<<8 | t2_reg)); + ATAPI_SET_PIO_TIM_0(base, (t4_reg<<12 | t2_pio<<4 | t1_reg)); + ATAPI_SET_PIO_TIM_1(base, teoc_pio); + if (mode > 2) { + ATAPI_SET_CONTROL(base, + ATAPI_GET_CONTROL(base) | IORDY_EN); + } else { + ATAPI_SET_CONTROL(base, + ATAPI_GET_CONTROL(base) & ~IORDY_EN); + } + + /* Disable host ATAPI PIO interrupts */ + ATAPI_SET_INT_MASK(base, ATAPI_GET_INT_MASK(base) + & ~(PIO_DONE_MASK | HOST_TERM_XFER_MASK)); + SSYNC(); + } +} + +/** + * bfin_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 bfin_set_dmamode(struct ata_port *ap, struct ata_device *adev) +{ + int mode; + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + unsigned long fsclk = get_sclk(); + unsigned short tenv, tack, tcyc_tdvs, tdvs, tmli, tss, trp, tzah; + unsigned short tm, td, tkr, tkw, teoc, th; + unsigned short n0, nf, tfmin = 5; + unsigned short nmin, tcyc; + + mode = adev->dma_mode - XFER_UDMA_0; + if (mode >= 0 && mode <= 5) { + pr_debug("set udmamode: mode=%d\n", mode); + /* the most restrictive timing value is t6 and tc, + * the DIOW - data hold. If one SCLK pulse is longer + * than this minimum value then register + * transfers cannot be supported at this frequency. + */ + while (mode > 0 && udma_fsclk[mode] > fsclk) + mode--; + + nmin = num_clocks_min(udma_tmin[mode], fsclk); + if (nmin >= 1) { + /* calculate the timing values for Ultra DMA. */ + tdvs = num_clocks_min(udma_tdvsmin[mode], fsclk); + tcyc = num_clocks_min(udma_tcycmin[mode], fsclk); + tcyc_tdvs = 2; + + /* increase tcyc - tdvs (tcyc_tdvs) until we meed + * the minimum cycle length + */ + if (tdvs + tcyc_tdvs < tcyc) + tcyc_tdvs = tcyc - tdvs; + + /* Mow assign the values required for the timing + * registers + */ + if (tcyc_tdvs < 2) + tcyc_tdvs = 2; + + if (tdvs < 2) + tdvs = 2; + + tack = num_clocks_min(udma_tackmin, fsclk); + tss = num_clocks_min(udma_tssmin, fsclk); + tmli = num_clocks_min(udma_tmlimin, fsclk); + tzah = num_clocks_min(udma_tzahmin, fsclk); + trp = num_clocks_min(udma_trpmin[mode], fsclk); + tenv = num_clocks_min(udma_tenvmin, fsclk); + if (tenv <= udma_tenvmax[mode]) { + ATAPI_SET_ULTRA_TIM_0(base, (tenv<<8 | tack)); + ATAPI_SET_ULTRA_TIM_1(base, + (tcyc_tdvs<<8 | tdvs)); + ATAPI_SET_ULTRA_TIM_2(base, (tmli<<8 | tss)); + ATAPI_SET_ULTRA_TIM_3(base, (trp<<8 | tzah)); + + /* Enable host ATAPI Untra DMA interrupts */ + ATAPI_SET_INT_MASK(base, + ATAPI_GET_INT_MASK(base) + | UDMAIN_DONE_MASK + | UDMAOUT_DONE_MASK + | UDMAIN_TERM_MASK + | UDMAOUT_TERM_MASK); + } + } + } + + mode = adev->dma_mode - XFER_MW_DMA_0; + if (mode >= 0 && mode <= 2) { + pr_debug("set mdmamode: mode=%d\n", mode); + /* the most restrictive timing value is tf, the DMACK to + * read data released. If one SCLK pulse is longer than + * this maximum value then the MDMA mode + * cannot be supported at this frequency. + */ + while (mode > 0 && mdma_fsclk[mode] > fsclk) + mode--; + + nf = num_clocks_min(tfmin, fsclk); + if (nf >= 1) { + /* calculate the timing values for Multi-word DMA. */ + + /* DIOR/DIOW asserted pulse width */ + td = num_clocks_min(mdma_tdmin[mode], fsclk); + + /* DIOR negated pulse width */ + tkw = num_clocks_min(mdma_tkwmin[mode], fsclk); + + /* Cycle Time */ + n0 = num_clocks_min(mdma_t0min[mode], fsclk); + + /* increase tk until we meed the minimum cycle length */ + if (tkw + td < n0) + tkw = n0 - td; + + /* DIOR negated pulse width - read */ + tkr = num_clocks_min(mdma_tkrmin[mode], fsclk); + /* CS{1:0] valid to DIOR/DIOW */ + tm = num_clocks_min(mdma_tmmin[mode], fsclk); + /* DIOR/DIOW to DMACK hold */ + teoc = num_clocks_min(mdma_tjmin[mode], fsclk); + /* DIOW Data hold */ + th = num_clocks_min(mdma_thmin[mode], fsclk); + + ATAPI_SET_MULTI_TIM_0(base, (tm<<8 | td)); + ATAPI_SET_MULTI_TIM_1(base, (tkr<<8 | tkw)); + ATAPI_SET_MULTI_TIM_2(base, (teoc<<8 | th)); + + /* Enable host ATAPI Multi DMA interrupts */ + ATAPI_SET_INT_MASK(base, ATAPI_GET_INT_MASK(base) + | MULTI_DONE_MASK | MULTI_TERM_MASK); + SSYNC(); + } + } + return; +} + +/** + * + * Function: wait_complete + * + * Description: Waits the interrupt from device + * + */ +static inline void wait_complete(void __iomem *base, unsigned short mask) +{ + unsigned short status; + unsigned int i = 0; + +#define PATA_BF54X_WAIT_TIMEOUT 10000 + + for (i = 0; i < PATA_BF54X_WAIT_TIMEOUT; i++) { + status = ATAPI_GET_INT_STATUS(base) & mask; + if (status) + break; + } + + ATAPI_SET_INT_STATUS(base, mask); +} + +/** + * + * Function: write_atapi_register + * + * Description: Writes to ATA Device Resgister + * + */ + +static void write_atapi_register(void __iomem *base, + unsigned long ata_reg, unsigned short value) +{ + /* Program the ATA_DEV_TXBUF register with write data (to be + * written into the device). + */ + ATAPI_SET_DEV_TXBUF(base, value); + + /* Program the ATA_DEV_ADDR register with address of the + * device register (0x01 to 0x0F). + */ + ATAPI_SET_DEV_ADDR(base, ata_reg); + + /* Program the ATA_CTRL register with dir set to write (1) + */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | XFER_DIR)); + + /* ensure PIO DMA is not set */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA)); + + /* and start the transfer */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START)); + + /* Wait for the interrupt to indicate the end of the transfer. + * (We need to wait on and clear rhe ATA_DEV_INT interrupt status) + */ + wait_complete(base, PIO_DONE_INT); +} + +/** + * + * Function: read_atapi_register + * + *Description: Reads from ATA Device Resgister + * + */ + +static unsigned short read_atapi_register(void __iomem *base, + unsigned long ata_reg) +{ + /* Program the ATA_DEV_ADDR register with address of the + * device register (0x01 to 0x0F). + */ + ATAPI_SET_DEV_ADDR(base, ata_reg); + + /* Program the ATA_CTRL register with dir set to read (0) and + */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~XFER_DIR)); + + /* ensure PIO DMA is not set */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA)); + + /* and start the transfer */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START)); + + /* Wait for the interrupt to indicate the end of the transfer. + * (PIO_DONE interrupt is set and it doesn't seem to matter + * that we don't clear it) + */ + wait_complete(base, PIO_DONE_INT); + + /* Read the ATA_DEV_RXBUF register with write data (to be + * written into the device). + */ + return ATAPI_GET_DEV_RXBUF(base); +} + +/** + * + * Function: write_atapi_register_data + * + * Description: Writes to ATA Device Resgister + * + */ + +static void write_atapi_data(void __iomem *base, + int len, unsigned short *buf) +{ + int i; + + /* Set transfer length to 1 */ + ATAPI_SET_XFER_LEN(base, 1); + + /* Program the ATA_DEV_ADDR register with address of the + * ATA_REG_DATA + */ + ATAPI_SET_DEV_ADDR(base, ATA_REG_DATA); + + /* Program the ATA_CTRL register with dir set to write (1) + */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | XFER_DIR)); + + /* ensure PIO DMA is not set */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA)); + + for (i = 0; i < len; i++) { + /* Program the ATA_DEV_TXBUF register with write data (to be + * written into the device). + */ + ATAPI_SET_DEV_TXBUF(base, buf[i]); + + /* and start the transfer */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START)); + + /* Wait for the interrupt to indicate the end of the transfer. + * (We need to wait on and clear rhe ATA_DEV_INT + * interrupt status) + */ + wait_complete(base, PIO_DONE_INT); + } +} + +/** + * + * Function: read_atapi_register_data + * + * Description: Reads from ATA Device Resgister + * + */ + +static void read_atapi_data(void __iomem *base, + int len, unsigned short *buf) +{ + int i; + + /* Set transfer length to 1 */ + ATAPI_SET_XFER_LEN(base, 1); + + /* Program the ATA_DEV_ADDR register with address of the + * ATA_REG_DATA + */ + ATAPI_SET_DEV_ADDR(base, ATA_REG_DATA); + + /* Program the ATA_CTRL register with dir set to read (0) and + */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~XFER_DIR)); + + /* ensure PIO DMA is not set */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA)); + + for (i = 0; i < len; i++) { + /* and start the transfer */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START)); + + /* Wait for the interrupt to indicate the end of the transfer. + * (PIO_DONE interrupt is set and it doesn't seem to matter + * that we don't clear it) + */ + wait_complete(base, PIO_DONE_INT); + + /* Read the ATA_DEV_RXBUF register with write data (to be + * written into the device). + */ + buf[i] = ATAPI_GET_DEV_RXBUF(base); + } +} + +/** + * bfin_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 bfin_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; + + if (tf->ctl != ap->last_ctl) { + write_atapi_register(base, ATA_REG_CTRL, tf->ctl); + ap->last_ctl = tf->ctl; + ata_wait_idle(ap); + } + + if (is_addr) { + if (tf->flags & ATA_TFLAG_LBA48) { + write_atapi_register(base, ATA_REG_FEATURE, + tf->hob_feature); + write_atapi_register(base, ATA_REG_NSECT, + tf->hob_nsect); + write_atapi_register(base, ATA_REG_LBAL, tf->hob_lbal); + write_atapi_register(base, ATA_REG_LBAM, tf->hob_lbam); + write_atapi_register(base, ATA_REG_LBAH, tf->hob_lbah); + pr_debug("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); + } + + write_atapi_register(base, ATA_REG_FEATURE, tf->feature); + write_atapi_register(base, ATA_REG_NSECT, tf->nsect); + write_atapi_register(base, ATA_REG_LBAL, tf->lbal); + write_atapi_register(base, ATA_REG_LBAM, tf->lbam); + write_atapi_register(base, ATA_REG_LBAH, tf->lbah); + pr_debug("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) { + write_atapi_register(base, ATA_REG_DEVICE, tf->device); + pr_debug("device 0x%X\n", tf->device); + } + + ata_wait_idle(ap); +} + +/** + * bfin_check_status - Read device status reg & clear interrupt + * @ap: port where the device is + * + * Note: Original code is ata_check_status(). + */ + +static u8 bfin_check_status(struct ata_port *ap) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + return read_atapi_register(base, ATA_REG_STATUS); +} + +/** + * bfin_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 bfin_tf_read(struct ata_port *ap, struct ata_taskfile *tf) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + + tf->command = bfin_check_status(ap); + tf->feature = read_atapi_register(base, ATA_REG_ERR); + tf->nsect = read_atapi_register(base, ATA_REG_NSECT); + tf->lbal = read_atapi_register(base, ATA_REG_LBAL); + tf->lbam = read_atapi_register(base, ATA_REG_LBAM); + tf->lbah = read_atapi_register(base, ATA_REG_LBAH); + tf->device = read_atapi_register(base, ATA_REG_DEVICE); + + if (tf->flags & ATA_TFLAG_LBA48) { + write_atapi_register(base, ATA_REG_CTRL, tf->ctl | ATA_HOB); + tf->hob_feature = read_atapi_register(base, ATA_REG_ERR); + tf->hob_nsect = read_atapi_register(base, ATA_REG_NSECT); + tf->hob_lbal = read_atapi_register(base, ATA_REG_LBAL); + tf->hob_lbam = read_atapi_register(base, ATA_REG_LBAM); + tf->hob_lbah = read_atapi_register(base, ATA_REG_LBAH); + } +} + +/** + * bfin_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 bfin_exec_command(struct ata_port *ap, + const struct ata_taskfile *tf) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + pr_debug("ata%u: cmd 0x%X\n", ap->print_id, tf->command); + + write_atapi_register(base, ATA_REG_CMD, tf->command); + ata_pause(ap); +} + +/** + * bfin_check_altstatus - Read device alternate status reg + * @ap: port where the device is + */ + +static u8 bfin_check_altstatus(struct ata_port *ap) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + return read_atapi_register(base, ATA_REG_ALTSTATUS); +} + +/** + * bfin_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 bfin_std_dev_select(struct ata_port *ap, unsigned int device) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + u8 tmp; + + if (device == 0) + tmp = ATA_DEVICE_OBS; + else + tmp = ATA_DEVICE_OBS | ATA_DEV1; + + write_atapi_register(base, ATA_REG_DEVICE, tmp); + ata_pause(ap); +} + +/** + * bfin_bmdma_setup - Set up IDE DMA transaction + * @qc: Info associated with this ATA transaction. + * + * Note: Original code is ata_bmdma_setup(). + */ + +static void bfin_bmdma_setup(struct ata_queued_cmd *qc) +{ + unsigned short config = WDSIZE_16; + struct scatterlist *sg; + + pr_debug("in atapi dma setup\n"); + /* Program the ATA_CTRL register with dir */ + if (qc->tf.flags & ATA_TFLAG_WRITE) { + /* fill the ATAPI DMA controller */ + set_dma_config(CH_ATAPI_TX, config); + set_dma_x_modify(CH_ATAPI_TX, 2); + ata_for_each_sg(sg, qc) { + set_dma_start_addr(CH_ATAPI_TX, sg_dma_address(sg)); + set_dma_x_count(CH_ATAPI_TX, sg_dma_len(sg) >> 1); + } + } else { + config |= WNR; + /* fill the ATAPI DMA controller */ + set_dma_config(CH_ATAPI_RX, config); + set_dma_x_modify(CH_ATAPI_RX, 2); + ata_for_each_sg(sg, qc) { + set_dma_start_addr(CH_ATAPI_RX, sg_dma_address(sg)); + set_dma_x_count(CH_ATAPI_RX, sg_dma_len(sg) >> 1); + } + } +} + +/** + * bfin_bmdma_start - Start an IDE DMA transaction + * @qc: Info associated with this ATA transaction. + * + * Note: Original code is ata_bmdma_start(). + */ + +static void bfin_bmdma_start(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + struct scatterlist *sg; + + pr_debug("in atapi dma start\n"); + if (!(ap->udma_mask || ap->mwdma_mask)) + return; + + /* start ATAPI DMA controller*/ + if (qc->tf.flags & ATA_TFLAG_WRITE) { + /* + * On blackfin arch, uncacheable memory is not + * allocated with flag GFP_DMA. DMA buffer from + * common kenel code should be flushed if WB + * data cache is enabled. Otherwise, this loop + * is an empty loop and optimized out. + */ + ata_for_each_sg(sg, qc) { + flush_dcache_range(sg_dma_address(sg), + sg_dma_address(sg) + sg_dma_len(sg)); + } + enable_dma(CH_ATAPI_TX); + pr_debug("enable udma write\n"); + + /* Send ATA DMA write command */ + bfin_exec_command(ap, &qc->tf); + + /* set ATA DMA write direction */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) + | XFER_DIR)); + } else { + enable_dma(CH_ATAPI_RX); + pr_debug("enable udma read\n"); + + /* Send ATA DMA read command */ + bfin_exec_command(ap, &qc->tf); + + /* set ATA DMA read direction */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) + & ~XFER_DIR)); + } + + /* Reset all transfer count */ + ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | TFRCNT_RST); + + /* Set transfer length to buffer len */ + ata_for_each_sg(sg, qc) { + ATAPI_SET_XFER_LEN(base, (sg_dma_len(sg) >> 1)); + } + + /* Enable ATA DMA operation*/ + if (ap->udma_mask) + ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) + | ULTRA_START); + else + ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) + | MULTI_START); +} + +/** + * bfin_bmdma_stop - Stop IDE DMA transfer + * @qc: Command we are ending DMA for + */ + +static void bfin_bmdma_stop(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct scatterlist *sg; + + pr_debug("in atapi dma stop\n"); + if (!(ap->udma_mask || ap->mwdma_mask)) + return; + + /* stop ATAPI DMA controller*/ + if (qc->tf.flags & ATA_TFLAG_WRITE) + disable_dma(CH_ATAPI_TX); + else { + disable_dma(CH_ATAPI_RX); + if (ap->hsm_task_state & HSM_ST_LAST) { + /* + * On blackfin arch, uncacheable memory is not + * allocated with flag GFP_DMA. DMA buffer from + * common kenel code should be invalidated if + * data cache is enabled. Otherwise, this loop + * is an empty loop and optimized out. + */ + ata_for_each_sg(sg, qc) { + invalidate_dcache_range( + sg_dma_address(sg), + sg_dma_address(sg) + + sg_dma_len(sg)); + } + } + } +} + +/** + * bfin_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 bfin_devchk(struct ata_port *ap, + unsigned int device) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + u8 nsect, lbal; + + bfin_std_dev_select(ap, device); + + write_atapi_register(base, ATA_REG_NSECT, 0x55); + write_atapi_register(base, ATA_REG_LBAL, 0xaa); + + write_atapi_register(base, ATA_REG_NSECT, 0xaa); + write_atapi_register(base, ATA_REG_LBAL, 0x55); + + write_atapi_register(base, ATA_REG_NSECT, 0x55); + write_atapi_register(base, ATA_REG_LBAL, 0xaa); + + nsect = read_atapi_register(base, ATA_REG_NSECT); + lbal = read_atapi_register(base, ATA_REG_LBAL); + + if ((nsect == 0x55) && (lbal == 0xaa)) + return 1; /* we found a device */ + + return 0; /* nothing found */ +} + +/** + * bfin_bus_post_reset - PATA device post reset + * + * Note: Original code is ata_bus_post_reset(). + */ + +static void bfin_bus_post_reset(struct ata_port *ap, unsigned int devmask) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + 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; + + bfin_std_dev_select(ap, 1); + nsect = read_atapi_register(base, ATA_REG_NSECT); + lbal = read_atapi_register(base, ATA_REG_LBAL); + 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? */ + bfin_std_dev_select(ap, 0); + if (dev1) + bfin_std_dev_select(ap, 1); + if (dev0) + bfin_std_dev_select(ap, 0); +} + +/** + * bfin_bus_softreset - PATA device software reset + * + * Note: Original code is ata_bus_softreset(). + */ + +static unsigned int bfin_bus_softreset(struct ata_port *ap, + unsigned int devmask) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + + /* software reset. causes dev0 to be selected */ + write_atapi_register(base, ATA_REG_CTRL, ap->ctl); + udelay(20); + write_atapi_register(base, ATA_REG_CTRL, ap->ctl | ATA_SRST); + udelay(20); + write_atapi_register(base, ATA_REG_CTRL, 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 (bfin_check_status(ap) == 0xFF) + return 0; + + bfin_bus_post_reset(ap, devmask); + + return 0; +} + +/** + * bfin_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 bfin_std_softreset(struct ata_port *ap, unsigned int *classes, + unsigned long deadline) +{ + unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS; + unsigned int devmask = 0, err_mask; + u8 err; + + if (ata_port_offline(ap)) { + classes[0] = ATA_DEV_NONE; + goto out; + } + + /* determine if device 0/1 are present */ + if (bfin_devchk(ap, 0)) + devmask |= (1 << 0); + if (slave_possible && bfin_devchk(ap, 1)) + devmask |= (1 << 1); + + /* select device 0 again */ + bfin_std_dev_select(ap, 0); + + /* issue bus reset */ + err_mask = bfin_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: + return 0; +} + +/** + * bfin_bmdma_status - Read IDE DMA status + * @ap: Port associated with this ATA transaction. + */ + +static unsigned char bfin_bmdma_status(struct ata_port *ap) +{ + unsigned char host_stat = 0; + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + unsigned short int_status = ATAPI_GET_INT_STATUS(base); + + if (ATAPI_GET_STATUS(base) & (MULTI_XFER_ON|ULTRA_XFER_ON)) { + host_stat = ATA_DMA_ACTIVE; + } + if (int_status & (MULTI_DONE_INT|UDMAIN_DONE_INT|UDMAOUT_DONE_INT)) { + host_stat = ATA_DMA_INTR; + } + if (int_status & (MULTI_TERM_INT|UDMAIN_TERM_INT|UDMAOUT_TERM_INT)) { + host_stat = ATA_DMA_ERR; + } + + return host_stat; +} + +/** + * bfin_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 bfin_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 short *buf16 = (u16 *) buf; + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + + /* Transfer multiple of 2 bytes */ + if (write_data) { + write_atapi_data(base, words, buf16); + } else { + read_atapi_data(base, words, buf16); + } + + /* Transfer trailing 1 byte, if any. */ + if (unlikely(buflen & 0x01)) { + unsigned short align_buf[1] = { 0 }; + unsigned char *trailing_buf = buf + buflen - 1; + + if (write_data) { + memcpy(align_buf, trailing_buf, 1); + write_atapi_data(base, 1, align_buf); + } else { + read_atapi_data(base, 1, align_buf); + memcpy(trailing_buf, align_buf, 1); + } + } +} + +/** + * bfin_irq_clear - Clear ATAPI interrupt. + * @ap: Port associated with this ATA transaction. + * + * Note: Original code is ata_bmdma_irq_clear(). + */ + +static void bfin_irq_clear(struct ata_port *ap) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + + pr_debug("in atapi irq clear\n"); + ATAPI_SET_INT_STATUS(base, 0x1FF); +} + +/** + * bfin_irq_on - Enable interrupts on a port. + * @ap: Port on which interrupts are enabled. + * + * Note: Original code is ata_irq_on(). + */ + +static unsigned char bfin_irq_on(struct ata_port *ap) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + u8 tmp; + + pr_debug("in atapi irq on\n"); + ap->ctl &= ~ATA_NIEN; + ap->last_ctl = ap->ctl; + + write_atapi_register(base, ATA_REG_CTRL, ap->ctl); + tmp = ata_wait_idle(ap); + + bfin_irq_clear(ap); + + return tmp; +} + +/** + * bfin_irq_ack - Acknowledge a device interrupt. + * @ap: Port on which interrupts are enabled. + * + * Note: Original code is ata_irq_ack(). + */ + +static unsigned char bfin_irq_ack(struct ata_port *ap, unsigned int chk_drq) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY; + unsigned char status; + + pr_debug("in atapi irq ack\n"); + status = ata_busy_wait(ap, bits, 1000); + if (status & bits) + if (ata_msg_err(ap)) + dev_err(ap->dev, "abnormal status 0x%X\n", status); + + /* get controller status; clear intr, err bits */ + ATAPI_SET_INT_STATUS(base, ATAPI_GET_INT_STATUS(base)|ATAPI_DEV_INT + | MULTI_DONE_INT | UDMAIN_DONE_INT | UDMAOUT_DONE_INT + | MULTI_TERM_INT | UDMAIN_TERM_INT | UDMAOUT_TERM_INT); + + return bfin_bmdma_status(ap); +} + +/** + * bfin_bmdma_freeze - Freeze DMA controller port + * @ap: port to freeze + * + * Note: Original code is ata_bmdma_freeze(). + */ + +static void bfin_bmdma_freeze(struct ata_port *ap) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + + pr_debug("in atapi dma freeze\n"); + ap->ctl |= ATA_NIEN; + ap->last_ctl = ap->ctl; + + write_atapi_register(base, ATA_REG_CTRL, 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); + + bfin_irq_clear(ap); +} + +/** + * bfin_bmdma_thaw - Thaw DMA controller port + * @ap: port to thaw + * + * Note: Original code is ata_bmdma_thaw(). + */ + +void bfin_bmdma_thaw(struct ata_port *ap) +{ + bfin_check_status(ap); + bfin_irq_clear(ap); + bfin_irq_on(ap); +} + +/** + * bfin_std_postreset - standard postreset callback + * @ap: the target ata_port + * @classes: classes of attached devices + * + * Note: Original code is ata_std_postreset(). + */ + +static void bfin_std_postreset(struct ata_port *ap, unsigned int *classes) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + + /* re-enable interrupts */ + bfin_irq_on(ap); + + /* is double-select really necessary? */ + if (classes[0] != ATA_DEV_NONE) + bfin_std_dev_select(ap, 1); + if (classes[1] != ATA_DEV_NONE) + bfin_std_dev_select(ap, 0); + + /* bail out if no device is present */ + if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) { + return; + } + + /* set up device control */ + write_atapi_register(base, ATA_REG_CTRL, ap->ctl); +} + +/** + * bfin_error_handler - Stock error handler for DMA controller + * @ap: port to handle error for + */ + +static void bfin_error_handler(struct ata_port *ap) +{ + ata_bmdma_drive_eh(ap, ata_std_prereset, bfin_std_softreset, NULL, + bfin_std_postreset); +} + +static void bfin_port_stop(struct ata_port *ap) +{ + pr_debug("in atapi port stop\n"); + if (ap->udma_mask != 0 || ap->mwdma_mask != 0) { + free_dma(CH_ATAPI_RX); + free_dma(CH_ATAPI_TX); + } +} + +static int bfin_port_start(struct ata_port *ap) +{ + pr_debug("in atapi port start\n"); + if (!(ap->udma_mask || ap->mwdma_mask)) + return 0; + + if (request_dma(CH_ATAPI_RX, "BFIN ATAPI RX DMA") >= 0) { + if (request_dma(CH_ATAPI_TX, + "BFIN ATAPI TX DMA") >= 0) + return 0; + + free_dma(CH_ATAPI_RX); + } + + ap->udma_mask = 0; + ap->mwdma_mask = 0; + dev_err(ap->dev, "Unable to request ATAPI DMA!" + " Continue in PIO mode.\n"); + + return 0; +} + +static struct scsi_host_template bfin_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 = SG_NONE, + .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 bfin_pata_ops = { + .port_disable = ata_port_disable, + .set_piomode = bfin_set_piomode, + .set_dmamode = bfin_set_dmamode, + + .tf_load = bfin_tf_load, + .tf_read = bfin_tf_read, + .exec_command = bfin_exec_command, + .check_status = bfin_check_status, + .check_altstatus = bfin_check_altstatus, + .dev_select = bfin_std_dev_select, + + .bmdma_setup = bfin_bmdma_setup, + .bmdma_start = bfin_bmdma_start, + .bmdma_stop = bfin_bmdma_stop, + .bmdma_status = bfin_bmdma_status, + .data_xfer = bfin_data_xfer, + + .qc_prep = ata_noop_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .freeze = bfin_bmdma_freeze, + .thaw = bfin_bmdma_thaw, + .error_handler = bfin_error_handler, + .post_internal_cmd = bfin_bmdma_stop, + + .irq_handler = ata_interrupt, + .irq_clear = bfin_irq_clear, + .irq_on = bfin_irq_on, + .irq_ack = bfin_irq_ack, + + .port_start = bfin_port_start, + .port_stop = bfin_port_stop, +}; + +static struct ata_port_info bfin_port_info[] = { + { + .sht = &bfin_sht, + .flags = ATA_FLAG_SLAVE_POSS + | ATA_FLAG_MMIO + | ATA_FLAG_NO_LEGACY, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0, +#ifdef CONFIG_PATA_BF54X_DMA + .udma_mask = ATA_UDMA5, +#else + .udma_mask = 0, +#endif + .port_ops = &bfin_pata_ops, + }, +}; + +/** + * bfin_reset_controller - initialize BF54x ATAPI controller. + */ + +static int bfin_reset_controller(struct ata_host *host) +{ + void __iomem *base = (void __iomem *)host->ports[0]->ioaddr.ctl_addr; + int count; + unsigned short status; + + /* Disable all ATAPI interrupts */ + ATAPI_SET_INT_MASK(base, 0); + SSYNC(); + + /* Assert the RESET signal 25us*/ + ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | DEV_RST); + udelay(30); + + /* Negate the RESET signal for 2ms*/ + ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) & ~DEV_RST); + msleep(2); + + /* Wait on Busy flag to clear */ + count = 10000000; + do { + status = read_atapi_register(base, ATA_REG_STATUS); + } while (count-- && (status & ATA_BUSY)); + + /* Enable only ATAPI Device interrupt */ + ATAPI_SET_INT_MASK(base, 1); + SSYNC(); + + return (!count); +} + +/** + * atapi_io_port - define atapi peripheral port pins. + */ +static unsigned short atapi_io_port[] = { + P_ATAPI_RESET, + P_ATAPI_DIOR, + P_ATAPI_DIOW, + P_ATAPI_CS0, + P_ATAPI_CS1, + P_ATAPI_DMACK, + P_ATAPI_DMARQ, + P_ATAPI_INTRQ, + P_ATAPI_IORDY, + 0 +}; + +/** + * bfin_atapi_probe - attach a bfin atapi interface + * @pdev: platform device + * + * Register a bfin atapi interface. + * + * + * Platform devices are expected to contain 2 resources per port: + * + * - I/O Base (IORESOURCE_IO) + * - IRQ (IORESOURCE_IRQ) + * + */ +static int __devinit bfin_atapi_probe(struct platform_device *pdev) +{ + int board_idx = 0; + struct resource *res; + struct ata_host *host; + const struct ata_port_info *ppi[] = + { &bfin_port_info[board_idx], NULL }; + + /* + * Simple resource validation .. + */ + if (unlikely(pdev->num_resources != 2)) { + dev_err(&pdev->dev, "invalid number of resources\n"); + return -EINVAL; + } + + /* + * Get the register base first + */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) + return -EINVAL; + + /* + * Now that that's out of the way, wire up the port.. + */ + host = ata_host_alloc_pinfo(&pdev->dev, ppi, 1); + if (!host) + return -ENOMEM; + + host->ports[0]->ioaddr.ctl_addr = (void *)res->start; + + if (peripheral_request_list(atapi_io_port, "atapi-io-port")) { + dev_err(&pdev->dev, "Requesting Peripherals faild\n"); + return -EFAULT; + } + + if (bfin_reset_controller(host)) { + peripheral_free_list(atapi_io_port); + dev_err(&pdev->dev, "Fail to reset ATAPI device\n"); + return -EFAULT; + } + + if (ata_host_activate(host, platform_get_irq(pdev, 0), + ata_interrupt, IRQF_SHARED, &bfin_sht) != 0) { + peripheral_free_list(atapi_io_port); + dev_err(&pdev->dev, "Fail to attach ATAPI device\n"); + return -ENODEV; + } + + return 0; +} + +/** + * bfin_atapi_remove - unplug a bfin atapi interface + * @pdev: platform device + * + * A bfin atapi device has been unplugged. Perform the needed + * cleanup. Also called on module unload for any active devices. + */ +static int __devexit bfin_atapi_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ata_host *host = dev_get_drvdata(dev); + + ata_host_detach(host); + + peripheral_free_list(atapi_io_port); + + return 0; +} + +#ifdef CONFIG_PM +int bfin_atapi_suspend(struct platform_device *pdev, pm_message_t state) +{ + return 0; +} + +int bfin_atapi_resume(struct platform_device *pdev) +{ + return 0; +} +#endif + +static struct platform_driver bfin_atapi_driver = { + .probe = bfin_atapi_probe, + .remove = __devexit_p(bfin_atapi_remove), + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, +#ifdef CONFIG_PM + .suspend = bfin_atapi_suspend, + .resume = bfin_atapi_resume, +#endif + }, +}; + +static int __init bfin_atapi_init(void) +{ + pr_info("register bfin atapi driver\n"); + return platform_driver_register(&bfin_atapi_driver); +} + +static void __exit bfin_atapi_exit(void) +{ + platform_driver_unregister(&bfin_atapi_driver); +} + +module_init(bfin_atapi_init); +module_exit(bfin_atapi_exit); + +MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>"); +MODULE_DESCRIPTION("PATA driver for blackfin 54x ATAPI controller"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); diff --git a/drivers/ata/pata_cmd640.c b/drivers/ata/pata_cmd640.c index 0feb5ae8c486..43d198f90968 100644 --- a/drivers/ata/pata_cmd640.c +++ b/drivers/ata/pata_cmd640.c @@ -153,7 +153,7 @@ static int cmd640_port_start(struct ata_port *ap) struct pci_dev *pdev = to_pci_dev(ap->host->dev); struct cmd640_reg *timing; - int ret = ata_port_start(ap); + int ret = ata_sff_port_start(ap); if (ret < 0) return ret; @@ -184,7 +184,6 @@ static struct scsi_host_template cmd640_sht = { }; static struct ata_port_operations cmd640_port_ops = { - .port_disable = ata_port_disable, .set_piomode = cmd640_set_piomode, .mode_filter = ata_pci_default_filter, .tf_load = ata_tf_load, @@ -213,7 +212,6 @@ static struct ata_port_operations cmd640_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = cmd640_port_start, }; diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c index e34b632487d7..9e412c26b2a3 100644 --- a/drivers/ata/pata_cmd64x.c +++ b/drivers/ata/pata_cmd64x.c @@ -31,7 +31,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_cmd64x" -#define DRV_VERSION "0.2.4" +#define DRV_VERSION "0.2.5" /* * CMD64x specific registers definition. @@ -88,14 +88,15 @@ static int cmd648_cable_detect(struct ata_port *ap) } /** - * cmd64x_set_piomode - set initial PIO mode data + * cmd64x_set_piomode - set PIO and MWDMA timing * @ap: ATA interface * @adev: ATA device + * @mode: mode * - * Called to do the PIO mode setup. + * Called to do the PIO and MWDMA mode setup. */ -static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev) +static void cmd64x_set_timing(struct ata_port *ap, struct ata_device *adev, u8 mode) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); struct ata_timing t; @@ -117,8 +118,9 @@ static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev) int arttim = arttim_port[ap->port_no][adev->devno]; int drwtim = drwtim_port[ap->port_no][adev->devno]; - - if (ata_timing_compute(adev, adev->pio_mode, &t, T, 0) < 0) { + /* ata_timing_compute is smart and will produce timings for MWDMA + that don't violate the drives PIO capabilities. */ + if (ata_timing_compute(adev, mode, &t, T, 0) < 0) { printk(KERN_ERR DRV_NAME ": mode computation failed.\n"); return; } @@ -168,6 +170,20 @@ static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev) } /** + * cmd64x_set_piomode - set initial PIO mode data + * @ap: ATA interface + * @adev: ATA device + * + * Used when configuring the devices ot set the PIO timings. All the + * actual work is done by the PIO/MWDMA setting helper + */ + +static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + cmd64x_set_timing(ap, adev, adev->pio_mode); +} + +/** * cmd64x_set_dmamode - set initial DMA mode data * @ap: ATA interface * @adev: ATA device @@ -180,9 +196,6 @@ static void cmd64x_set_dmamode(struct ata_port *ap, struct ata_device *adev) static const u8 udma_data[] = { 0x30, 0x20, 0x10, 0x20, 0x10, 0x00 }; - static const u8 mwdma_data[] = { - 0x30, 0x20, 0x10 - }; struct pci_dev *pdev = to_pci_dev(ap->host->dev); u8 regU, regD; @@ -208,8 +221,10 @@ static void cmd64x_set_dmamode(struct ata_port *ap, struct ata_device *adev) regU |= 1 << adev->devno; /* UDMA on */ if (adev->dma_mode > 2) /* 15nS timing */ regU |= 4 << adev->devno; - } else - regD |= mwdma_data[adev->dma_mode - XFER_MW_DMA_0] << shift; + } else { + regU &= ~ (1 << adev->devno); /* UDMA off */ + cmd64x_set_timing(ap, adev, adev->dma_mode); + } regD |= 0x20 << adev->devno; @@ -269,7 +284,6 @@ static struct scsi_host_template cmd64x_sht = { }; static struct ata_port_operations cmd64x_port_ops = { - .port_disable = ata_port_disable, .set_piomode = cmd64x_set_piomode, .set_dmamode = cmd64x_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -298,13 +312,11 @@ static struct ata_port_operations cmd64x_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; static struct ata_port_operations cmd646r1_port_ops = { - .port_disable = ata_port_disable, .set_piomode = cmd64x_set_piomode, .set_dmamode = cmd64x_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -333,13 +345,11 @@ static struct ata_port_operations cmd646r1_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; static struct ata_port_operations cmd648_port_ops = { - .port_disable = ata_port_disable, .set_piomode = cmd64x_set_piomode, .set_dmamode = cmd64x_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -368,7 +378,6 @@ static struct ata_port_operations cmd648_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c index e2459088cdcd..33f7f0843f4f 100644 --- a/drivers/ata/pata_cs5520.c +++ b/drivers/ata/pata_cs5520.c @@ -158,7 +158,6 @@ static struct scsi_host_template cs5520_sht = { }; static struct ata_port_operations cs5520_port_ops = { - .port_disable = ata_port_disable, .set_piomode = cs5520_set_piomode, .set_dmamode = cs5520_set_dmamode, @@ -184,13 +183,14 @@ static struct ata_port_operations cs5520_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_device_id *id) { + static const unsigned int cmd_port[] = { 0x1F0, 0x170 }; + static const unsigned int ctl_port[] = { 0x3F6, 0x376 }; struct ata_port_info pi = { .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, @@ -244,10 +244,10 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi } /* Map IO ports and initialize host accordingly */ - iomap[0] = devm_ioport_map(&pdev->dev, 0x1F0, 8); - iomap[1] = devm_ioport_map(&pdev->dev, 0x3F6, 1); - iomap[2] = devm_ioport_map(&pdev->dev, 0x170, 8); - iomap[3] = devm_ioport_map(&pdev->dev, 0x376, 1); + iomap[0] = devm_ioport_map(&pdev->dev, cmd_port[0], 8); + iomap[1] = devm_ioport_map(&pdev->dev, ctl_port[0], 1); + iomap[2] = devm_ioport_map(&pdev->dev, cmd_port[1], 8); + iomap[3] = devm_ioport_map(&pdev->dev, ctl_port[1], 1); iomap[4] = pcim_iomap(pdev, 2, 0); if (!iomap[0] || !iomap[1] || !iomap[2] || !iomap[3] || !iomap[4]) @@ -260,6 +260,10 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi ioaddr->bmdma_addr = iomap[4]; ata_std_ports(ioaddr); + ata_port_desc(host->ports[0], + "cmd 0x%x ctl 0x%x", cmd_port[0], ctl_port[0]); + ata_port_pbar_desc(host->ports[0], 4, 0, "bmdma"); + ioaddr = &host->ports[1]->ioaddr; ioaddr->cmd_addr = iomap[2]; ioaddr->ctl_addr = iomap[3]; @@ -267,6 +271,10 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi ioaddr->bmdma_addr = iomap[4] + 8; ata_std_ports(ioaddr); + ata_port_desc(host->ports[1], + "cmd 0x%x ctl 0x%x", cmd_port[1], ctl_port[1]); + ata_port_pbar_desc(host->ports[1], 4, 8, "bmdma"); + /* activate the host */ pci_set_master(pdev); rc = ata_host_start(host); @@ -285,33 +293,12 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi if (rc) return rc; - if (i == 0) - host->irq = irq[0]; - else - host->irq2 = irq[1]; + ata_port_desc(ap, "irq %d", irq[i]); } return ata_host_register(host, &cs5520_sht); } -/** - * cs5520_remove_one - device unload - * @pdev: PCI device being removed - * - * Handle an unplug/unload event for a PCI device. Unload the - * PCI driver but do not use the default handler as we manage - * resources ourself and *MUST NOT* disable the device as it has - * other functions. - */ - -static void __devexit cs5520_remove_one(struct pci_dev *pdev) -{ - struct device *dev = pci_dev_to_dev(pdev); - struct ata_host *host = dev_get_drvdata(dev); - - ata_host_detach(host); -} - #ifdef CONFIG_PM /** * cs5520_reinit_one - device resume @@ -368,7 +355,7 @@ static struct pci_driver cs5520_pci_driver = { .name = DRV_NAME, .id_table = pata_cs5520, .probe = cs5520_init_one, - .remove = cs5520_remove_one, + .remove = ata_pci_remove_one, #ifdef CONFIG_PM .suspend = cs5520_pci_device_suspend, .resume = cs5520_reinit_one, diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c index eaaea848b649..57e827e4109e 100644 --- a/drivers/ata/pata_cs5530.c +++ b/drivers/ata/pata_cs5530.c @@ -179,7 +179,6 @@ static struct scsi_host_template cs5530_sht = { }; static struct ata_port_operations cs5530_port_ops = { - .port_disable = ata_port_disable, .set_piomode = cs5530_set_piomode, .set_dmamode = cs5530_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -209,9 +208,8 @@ static struct ata_port_operations cs5530_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static const struct dmi_system_id palmax_dmi_table[] = { diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c index 360b6f32e17e..3578593a882b 100644 --- a/drivers/ata/pata_cs5535.c +++ b/drivers/ata/pata_cs5535.c @@ -176,7 +176,6 @@ static struct scsi_host_template cs5535_sht = { }; static struct ata_port_operations cs5535_port_ops = { - .port_disable = ata_port_disable, .set_piomode = cs5535_set_piomode, .set_dmamode = cs5535_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -206,9 +205,8 @@ static struct ata_port_operations cs5535_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_cs5536.c b/drivers/ata/pata_cs5536.c new file mode 100644 index 000000000000..53070f6b1fc4 --- /dev/null +++ b/drivers/ata/pata_cs5536.c @@ -0,0 +1,344 @@ +/* + * pata_cs5536.c - CS5536 PATA for new ATA layer + * (C) 2007 Martin K. Petersen <mkp@mkp.net> + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Documentation: + * Available from AMD web site. + * + * The IDE timing registers for the CS5536 live in the Geode Machine + * Specific Register file and not PCI config space. Most BIOSes + * virtualize the PCI registers so the chip looks like a standard IDE + * controller. Unfortunately not all implementations get this right. + * In particular some have problems with unaligned accesses to the + * virtualized PCI registers. This driver always does full dword + * writes to work around the issue. Also, in case of a bad BIOS this + * driver can be loaded with the "msr=1" parameter which forces using + * the Machine Specific Registers to configure the device. + */ + +#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/libata.h> +#include <scsi/scsi_host.h> +#include <asm/msr.h> + +#define DRV_NAME "pata_cs5536" +#define DRV_VERSION "0.0.5" + +enum { + CFG = 0, + DTC = 1, + CAST = 2, + ETC = 3, + + MSR_IDE_BASE = 0x51300000, + MSR_IDE_CFG = (MSR_IDE_BASE + 0x10), + MSR_IDE_DTC = (MSR_IDE_BASE + 0x12), + MSR_IDE_CAST = (MSR_IDE_BASE + 0x13), + MSR_IDE_ETC = (MSR_IDE_BASE + 0x14), + + PCI_IDE_CFG = 0x40, + PCI_IDE_DTC = 0x48, + PCI_IDE_CAST = 0x4c, + PCI_IDE_ETC = 0x50, + + IDE_CFG_CHANEN = 0x2, + IDE_CFG_CABLE = 0x10000, + + IDE_D0_SHIFT = 24, + IDE_D1_SHIFT = 16, + IDE_DRV_MASK = 0xff, + + IDE_CAST_D0_SHIFT = 6, + IDE_CAST_D1_SHIFT = 4, + IDE_CAST_DRV_MASK = 0x3, + IDE_CAST_CMD_MASK = 0xff, + IDE_CAST_CMD_SHIFT = 24, + + IDE_ETC_NODMA = 0x03, +}; + +static int use_msr; + +static const u32 msr_reg[4] = { + MSR_IDE_CFG, MSR_IDE_DTC, MSR_IDE_CAST, MSR_IDE_ETC, +}; + +static const u8 pci_reg[4] = { + PCI_IDE_CFG, PCI_IDE_DTC, PCI_IDE_CAST, PCI_IDE_ETC, +}; + +static inline int cs5536_read(struct pci_dev *pdev, int reg, int *val) +{ + if (unlikely(use_msr)) { + u32 dummy; + + rdmsr(msr_reg[reg], *val, dummy); + return 0; + } + + return pci_read_config_dword(pdev, pci_reg[reg], val); +} + +static inline int cs5536_write(struct pci_dev *pdev, int reg, int val) +{ + if (unlikely(use_msr)) { + wrmsr(msr_reg[reg], val, 0); + return 0; + } + + return pci_write_config_dword(pdev, pci_reg[reg], val); +} + +/** + * cs5536_cable_detect - detect cable type + * @ap: Port to detect on + * @deadline: deadline jiffies for the operation + * + * Perform cable detection for ATA66 capable cable. Return a libata + * cable type. + */ + +static int cs5536_cable_detect(struct ata_port *ap) +{ + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + u32 cfg; + + cs5536_read(pdev, CFG, &cfg); + + if (cfg & (IDE_CFG_CABLE << ap->port_no)) + return ATA_CBL_PATA80; + else + return ATA_CBL_PATA40; +} + +/** + * cs5536_set_piomode - PIO setup + * @ap: ATA interface + * @adev: device on the interface + */ + +static void cs5536_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + static const u8 drv_timings[5] = { + 0x98, 0x55, 0x32, 0x21, 0x20, + }; + + static const u8 addr_timings[5] = { + 0x2, 0x1, 0x0, 0x0, 0x0, + }; + + static const u8 cmd_timings[5] = { + 0x99, 0x92, 0x90, 0x22, 0x20, + }; + + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + struct ata_device *pair = ata_dev_pair(adev); + int mode = adev->pio_mode - XFER_PIO_0; + int cmdmode = mode; + int dshift = ap->port_no ? IDE_D1_SHIFT : IDE_D0_SHIFT; + int cshift = ap->port_no ? IDE_CAST_D1_SHIFT : IDE_CAST_D0_SHIFT; + u32 dtc, cast, etc; + + if (pair) + cmdmode = min(mode, pair->pio_mode - XFER_PIO_0); + + cs5536_read(pdev, DTC, &dtc); + cs5536_read(pdev, CAST, &cast); + cs5536_read(pdev, ETC, &etc); + + dtc &= ~(IDE_DRV_MASK << dshift); + dtc |= drv_timings[mode] << dshift; + + cast &= ~(IDE_CAST_DRV_MASK << cshift); + cast |= addr_timings[mode] << cshift; + + cast &= ~(IDE_CAST_CMD_MASK << IDE_CAST_CMD_SHIFT); + cast |= cmd_timings[cmdmode] << IDE_CAST_CMD_SHIFT; + + etc &= ~(IDE_DRV_MASK << dshift); + etc |= IDE_ETC_NODMA << dshift; + + cs5536_write(pdev, DTC, dtc); + cs5536_write(pdev, CAST, cast); + cs5536_write(pdev, ETC, etc); +} + +/** + * cs5536_set_dmamode - DMA timing setup + * @ap: ATA interface + * @adev: Device being configured + * + */ + +static void cs5536_set_dmamode(struct ata_port *ap, struct ata_device *adev) +{ + static const u8 udma_timings[6] = { + 0xc2, 0xc1, 0xc0, 0xc4, 0xc5, 0xc6, + }; + + static const u8 mwdma_timings[3] = { + 0x67, 0x21, 0x20, + }; + + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + u32 dtc, etc; + int mode = adev->dma_mode; + int dshift = ap->port_no ? IDE_D1_SHIFT : IDE_D0_SHIFT; + + if (mode >= XFER_UDMA_0) { + cs5536_read(pdev, ETC, &etc); + + etc &= ~(IDE_DRV_MASK << dshift); + etc |= udma_timings[mode - XFER_UDMA_0] << dshift; + + cs5536_write(pdev, ETC, etc); + } else { /* MWDMA */ + cs5536_read(pdev, DTC, &dtc); + + dtc &= ~(IDE_DRV_MASK << dshift); + dtc |= mwdma_timings[mode] << dshift; + + cs5536_write(pdev, DTC, dtc); + } +} + +static struct scsi_host_template cs5536_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, +}; + +static struct ata_port_operations cs5536_port_ops = { + .set_piomode = cs5536_set_piomode, + .set_dmamode = cs5536_set_dmamode, + .mode_filter = ata_pci_default_filter, + + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .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, + .cable_detect = cs5536_cable_detect, + + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, + .bmdma_stop = ata_bmdma_stop, + .bmdma_status = ata_bmdma_status, + + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .data_xfer = ata_data_xfer, + + .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + + .port_start = ata_port_start, +}; + +/** + * cs5536_init_one + * @dev: PCI device + * @id: Entry in match table + * + */ + +static int cs5536_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + static const struct ata_port_info info = { + .sht = &cs5536_sht, + .flags = ATA_FLAG_SLAVE_POSS, + .pio_mask = 0x1f, + .mwdma_mask = 0x07, + .udma_mask = ATA_UDMA5, + .port_ops = &cs5536_port_ops, + }; + + const struct ata_port_info *ppi[] = { &info, &ata_dummy_port_info }; + u32 cfg; + + if (use_msr) + printk(KERN_ERR DRV_NAME ": Using MSR regs instead of PCI\n"); + + cs5536_read(dev, CFG, &cfg); + + if ((cfg & IDE_CFG_CHANEN) == 0) { + printk(KERN_ERR DRV_NAME ": disabled by BIOS\n"); + return -ENODEV; + } + + return ata_pci_init_one(dev, ppi); +} + +static const struct pci_device_id cs5536[] = { + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), }, + { }, +}; + +static struct pci_driver cs5536_pci_driver = { + .name = DRV_NAME, + .id_table = cs5536, + .probe = cs5536_init_one, + .remove = ata_pci_remove_one, +#ifdef CONFIG_PM + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, +#endif +}; + +static int __init cs5536_init(void) +{ + return pci_register_driver(&cs5536_pci_driver); +} + +static void __exit cs5536_exit(void) +{ + pci_unregister_driver(&cs5536_pci_driver); +} + +MODULE_AUTHOR("Martin K. Petersen"); +MODULE_DESCRIPTION("low-level driver for the CS5536 IDE controller"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, cs5536); +MODULE_VERSION(DRV_VERSION); +module_param_named(msr, use_msr, int, 0644); +MODULE_PARM_DESC(msr, "Force using MSR to configure IDE function (Default: 0)"); + +module_init(cs5536_init); +module_exit(cs5536_exit); diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c index 6cbc8778bf4f..fc5f9c4e5d87 100644 --- a/drivers/ata/pata_cypress.c +++ b/drivers/ata/pata_cypress.c @@ -128,7 +128,6 @@ static struct scsi_host_template cy82c693_sht = { }; static struct ata_port_operations cy82c693_port_ops = { - .port_disable = ata_port_disable, .set_piomode = cy82c693_set_piomode, .set_dmamode = cy82c693_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -158,9 +157,8 @@ static struct ata_port_operations cy82c693_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c index c8ba59c56114..043dcd35106c 100644 --- a/drivers/ata/pata_efar.c +++ b/drivers/ata/pata_efar.c @@ -26,25 +26,26 @@ /** * efar_pre_reset - Enable bits - * @ap: Port + * @link: ATA link * @deadline: deadline jiffies for the operation * * Perform cable detection for the EFAR ATA interface. This is * different to the PIIX arrangement */ -static int efar_pre_reset(struct ata_port *ap, unsigned long deadline) +static int efar_pre_reset(struct ata_link *link, unsigned long deadline) { static const struct pci_bits efar_enable_bits[] = { { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */ { 0x43U, 1U, 0x80UL, 0x80UL }, /* port 1 */ }; + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (!pci_test_config_bits(pdev, &efar_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** @@ -250,7 +251,6 @@ static struct scsi_host_template efar_sht = { }; static const struct ata_port_operations efar_ops = { - .port_disable = ata_port_disable, .set_piomode = efar_set_piomode, .set_dmamode = efar_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -278,9 +278,8 @@ static const struct ata_port_operations efar_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c index 6f7d34ad19ef..0713872cf65c 100644 --- a/drivers/ata/pata_hpt366.c +++ b/drivers/ata/pata_hpt366.c @@ -312,7 +312,6 @@ static struct scsi_host_template hpt36x_sht = { */ static struct ata_port_operations hpt366_port_ops = { - .port_disable = ata_port_disable, .set_piomode = hpt366_set_piomode, .set_dmamode = hpt366_set_dmamode, .mode_filter = hpt366_filter, @@ -342,9 +341,8 @@ static struct ata_port_operations hpt366_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index c5ddd937dbf2..e61cb1fd57b2 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -304,15 +304,16 @@ static unsigned long hpt370a_filter(struct ata_device *adev, unsigned long mask) /** * hpt37x_pre_reset - reset the hpt37x bus - * @ap: ATA port to reset + * @link: ATA link to reset * @deadline: deadline jiffies for the operation * * Perform the initial reset handling for the 370/372 and 374 func 0 */ -static int hpt37x_pre_reset(struct ata_port *ap, unsigned long deadline) +static int hpt37x_pre_reset(struct ata_link *link, unsigned long deadline) { u8 scr2, ata66; + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); static const struct pci_bits hpt37x_enable_bits[] = { { 0x50, 1, 0x04, 0x04 }, @@ -337,7 +338,7 @@ static int hpt37x_pre_reset(struct ata_port *ap, unsigned long deadline) pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37); udelay(100); - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** @@ -352,7 +353,7 @@ static void hpt37x_error_handler(struct ata_port *ap) ata_bmdma_drive_eh(ap, hpt37x_pre_reset, ata_std_softreset, NULL, ata_std_postreset); } -static int hpt374_pre_reset(struct ata_port *ap, unsigned long deadline) +static int hpt374_pre_reset(struct ata_link *link, unsigned long deadline) { static const struct pci_bits hpt37x_enable_bits[] = { { 0x50, 1, 0x04, 0x04 }, @@ -360,6 +361,7 @@ static int hpt374_pre_reset(struct ata_port *ap, unsigned long deadline) }; u16 mcr3, mcr6; u8 ata66; + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (!pci_test_config_bits(pdev, &hpt37x_enable_bits[ap->port_no])) @@ -387,7 +389,7 @@ static int hpt374_pre_reset(struct ata_port *ap, unsigned long deadline) pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37); udelay(100); - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** @@ -642,7 +644,6 @@ static struct scsi_host_template hpt37x_sht = { */ static struct ata_port_operations hpt370_port_ops = { - .port_disable = ata_port_disable, .set_piomode = hpt370_set_piomode, .set_dmamode = hpt370_set_dmamode, .mode_filter = hpt370_filter, @@ -671,9 +672,8 @@ static struct ata_port_operations hpt370_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /* @@ -681,7 +681,6 @@ static struct ata_port_operations hpt370_port_ops = { */ static struct ata_port_operations hpt370a_port_ops = { - .port_disable = ata_port_disable, .set_piomode = hpt370_set_piomode, .set_dmamode = hpt370_set_dmamode, .mode_filter = hpt370a_filter, @@ -710,9 +709,8 @@ static struct ata_port_operations hpt370a_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /* @@ -721,7 +719,6 @@ static struct ata_port_operations hpt370a_port_ops = { */ static struct ata_port_operations hpt372_port_ops = { - .port_disable = ata_port_disable, .set_piomode = hpt372_set_piomode, .set_dmamode = hpt372_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -750,9 +747,8 @@ static struct ata_port_operations hpt372_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /* @@ -761,7 +757,6 @@ static struct ata_port_operations hpt372_port_ops = { */ static struct ata_port_operations hpt374_port_ops = { - .port_disable = ata_port_disable, .set_piomode = hpt372_set_piomode, .set_dmamode = hpt372_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -790,9 +785,8 @@ static struct ata_port_operations hpt374_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c index f8f234bfc8ce..9f1c084f846f 100644 --- a/drivers/ata/pata_hpt3x2n.c +++ b/drivers/ata/pata_hpt3x2n.c @@ -141,21 +141,22 @@ static int hpt3x2n_cable_detect(struct ata_port *ap) /** * hpt3x2n_pre_reset - reset the hpt3x2n bus - * @ap: ATA port to reset + * @link: ATA link to reset * @deadline: deadline jiffies for the operation * * Perform the initial reset handling for the 3x2n series controllers. * Reset the hardware and state machine, */ -static int hpt3xn_pre_reset(struct ata_port *ap, unsigned long deadline) +static int hpt3xn_pre_reset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); /* Reset the state machine */ pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37); udelay(100); - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** @@ -360,7 +361,6 @@ static struct scsi_host_template hpt3x2n_sht = { */ static struct ata_port_operations hpt3x2n_port_ops = { - .port_disable = ata_port_disable, .set_piomode = hpt3x2n_set_piomode, .set_dmamode = hpt3x2n_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -390,9 +390,8 @@ static struct ata_port_operations hpt3x2n_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c index be0f05efac6d..cb8bdb6887de 100644 --- a/drivers/ata/pata_hpt3x3.c +++ b/drivers/ata/pata_hpt3x3.c @@ -120,7 +120,6 @@ static struct scsi_host_template hpt3x3_sht = { }; static struct ata_port_operations hpt3x3_port_ops = { - .port_disable = ata_port_disable, .set_piomode = hpt3x3_set_piomode, #if defined(CONFIG_PATA_HPT3X3_DMA) .set_dmamode = hpt3x3_set_dmamode, @@ -153,9 +152,8 @@ static struct ata_port_operations hpt3x3_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** @@ -239,7 +237,8 @@ static int hpt3x3_init_one(struct pci_dev *pdev, const struct pci_device_id *id) base = host->iomap[4]; /* Bus mastering base */ for (i = 0; i < host->n_ports; i++) { - struct ata_ioports *ioaddr = &host->ports[i]->ioaddr; + struct ata_port *ap = host->ports[i]; + struct ata_ioports *ioaddr = &ap->ioaddr; ioaddr->cmd_addr = base + offset_cmd[i]; ioaddr->altstatus_addr = @@ -247,6 +246,9 @@ static int hpt3x3_init_one(struct pci_dev *pdev, const struct pci_device_id *id) ioaddr->scr_addr = NULL; ata_std_ports(ioaddr); ioaddr->bmdma_addr = base + 8 * i; + + ata_port_pbar_desc(ap, 4, -1, "ioport"); + ata_port_pbar_desc(ap, 4, offset_cmd[i], "cmd"); } pci_set_master(pdev); return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED, diff --git a/drivers/ata/pata_icside.c b/drivers/ata/pata_icside.c index 64a711776c45..be30923566c5 100644 --- a/drivers/ata/pata_icside.c +++ b/drivers/ata/pata_icside.c @@ -70,6 +70,8 @@ struct pata_icside_info { unsigned int mwdma_mask; unsigned int nr_ports; const struct portinfo *port[2]; + unsigned long raw_base; + unsigned long raw_ioc_base; }; #define ICS_TYPE_A3IN 0 @@ -357,26 +359,7 @@ static void pata_icside_error_handler(struct ata_port *ap) pata_icside_postreset); } -static u8 pata_icside_irq_ack(struct ata_port *ap, unsigned int chk_drq) -{ - unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY; - u8 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); - - if (ata_msg_intr(ap)) - printk(KERN_INFO "%s: irq ack: drv_stat 0x%X\n", - __FUNCTION__, status); - - return status; -} - static struct ata_port_operations pata_icside_port_ops = { - .port_disable = ata_port_disable, - .set_dmamode = pata_icside_set_dmamode, .tf_load = ata_tf_load, @@ -403,7 +386,6 @@ static struct ata_port_operations pata_icside_port_ops = { .irq_clear = ata_dummy_noret, .irq_on = ata_irq_on, - .irq_ack = pata_icside_irq_ack, .port_start = pata_icside_port_start, @@ -412,9 +394,10 @@ static struct ata_port_operations pata_icside_port_ops = { }; static void __devinit -pata_icside_setup_ioaddr(struct ata_ioports *ioaddr, void __iomem *base, +pata_icside_setup_ioaddr(struct ata_port *ap, void __iomem *base, const struct portinfo *info) { + struct ata_ioports *ioaddr = &ap->ioaddr; void __iomem *cmd = base + info->dataoffset; ioaddr->cmd_addr = cmd; @@ -431,6 +414,13 @@ pata_icside_setup_ioaddr(struct ata_ioports *ioaddr, void __iomem *base, ioaddr->ctl_addr = base + info->ctrloffset; ioaddr->altstatus_addr = ioaddr->ctl_addr; + + ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", + info->raw_base + info->dataoffset, + info->raw_base + info->ctrloffset); + + if (info->raw_ioc_base) + ata_port_desc(ap, "iocbase 0x%lx", info->raw_ioc_base); } static int __devinit pata_icside_register_v5(struct pata_icside_info *info) @@ -451,6 +441,8 @@ static int __devinit pata_icside_register_v5(struct pata_icside_info *info) info->nr_ports = 1; info->port[0] = &pata_icside_portinfo_v5; + info->raw_base = ecard_resource_start(ec, ECARD_RES_MEMC); + return 0; } @@ -491,6 +483,9 @@ static int __devinit pata_icside_register_v6(struct pata_icside_info *info) info->port[0] = &pata_icside_portinfo_v6_1; info->port[1] = &pata_icside_portinfo_v6_2; + info->raw_base = ecard_resource_start(ec, ECARD_RES_EASI); + info->raw_ioc_base = ecard_resource_start(ec, ECARD_RES_IOCFAST); + return icside_dma_init(info); } @@ -527,7 +522,7 @@ static int __devinit pata_icside_add_ports(struct pata_icside_info *info) ap->flags |= ATA_FLAG_SLAVE_POSS; ap->ops = &pata_icside_port_ops; - pata_icside_setup_ioaddr(&ap->ioaddr, info->base, info->port[i]); + pata_icside_setup_ioaddr(ap, info->base, info->port[i]); } return ata_host_activate(host, ec->irq, ata_interrupt, 0, diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c index 9e553c54203a..88ab0e1d353f 100644 --- a/drivers/ata/pata_isapnp.c +++ b/drivers/ata/pata_isapnp.c @@ -38,7 +38,6 @@ static struct scsi_host_template isapnp_sht = { }; static struct ata_port_operations isapnp_port_ops = { - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -58,9 +57,8 @@ static struct ata_port_operations isapnp_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** @@ -112,6 +110,10 @@ static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev ata_std_ports(&ap->ioaddr); + ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx", + (unsigned long long)pnp_port_start(idev, 0), + (unsigned long long)pnp_port_start(idev, 1)); + /* activate */ return ata_host_activate(host, pnp_irq(idev, 0), ata_interrupt, 0, &isapnp_sht); diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c index b8af55e89156..1eda821e5e39 100644 --- a/drivers/ata/pata_it8213.c +++ b/drivers/ata/pata_it8213.c @@ -23,23 +23,24 @@ /** * it8213_pre_reset - check for 40/80 pin - * @ap: Port + * @link: link * @deadline: deadline jiffies for the operation * * Filter out ports by the enable bits before doing the normal reset * and probe. */ -static int it8213_pre_reset(struct ata_port *ap, unsigned long deadline) +static int it8213_pre_reset(struct ata_link *link, unsigned long deadline) { static const struct pci_bits it8213_enable_bits[] = { { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */ }; + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (!pci_test_config_bits(pdev, &it8213_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** @@ -260,7 +261,6 @@ static struct scsi_host_template it8213_sht = { }; static const struct ata_port_operations it8213_ops = { - .port_disable = ata_port_disable, .set_piomode = it8213_set_piomode, .set_dmamode = it8213_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -288,9 +288,8 @@ static const struct ata_port_operations it8213_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index 5d8b91e70ecd..988ef736b936 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -391,7 +391,7 @@ static void it821x_passthru_dev_select(struct ata_port *ap, { struct it821x_dev *itdev = ap->private_data; if (itdev && device != itdev->last_device) { - struct ata_device *adev = &ap->device[device]; + struct ata_device *adev = &ap->link.device[device]; it821x_program(ap, adev, itdev->pio[adev->devno]); itdev->last_device = device; } @@ -450,7 +450,7 @@ static unsigned int it821x_passthru_qc_issue_prot(struct ata_queued_cmd *qc) /** * it821x_smart_set_mode - mode setting - * @ap: interface to set up + * @link: interface to set up * @unused: device that failed (error only) * * Use a non standard set_mode function. We don't want to be tuned. @@ -459,12 +459,11 @@ static unsigned int it821x_passthru_qc_issue_prot(struct ata_queued_cmd *qc) * and respect them. */ -static int it821x_smart_set_mode(struct ata_port *ap, struct ata_device **unused) +static int it821x_smart_set_mode(struct ata_link *link, struct ata_device **unused) { - int i; + struct ata_device *dev; - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; + ata_link_for_each_dev(dev, link) { if (ata_dev_enabled(dev)) { /* We don't really care */ dev->pio_mode = XFER_PIO_0; @@ -564,7 +563,7 @@ static int it821x_port_start(struct ata_port *ap) struct it821x_dev *itdev; u8 conf; - int ret = ata_port_start(ap); + int ret = ata_sff_port_start(ap); if (ret < 0) return ret; @@ -621,7 +620,6 @@ static struct scsi_host_template it821x_sht = { static struct ata_port_operations it821x_smart_port_ops = { .set_mode = it821x_smart_set_mode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .mode_filter = ata_pci_default_filter, @@ -651,13 +649,11 @@ static struct ata_port_operations it821x_smart_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = it821x_port_start, }; static struct ata_port_operations it821x_passthru_port_ops = { - .port_disable = ata_port_disable, .set_piomode = it821x_passthru_set_piomode, .set_dmamode = it821x_passthru_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -688,7 +684,6 @@ static struct ata_port_operations it821x_passthru_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_handler = ata_interrupt, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = it821x_port_start, }; diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index 5dea3584c6c2..fcd532afbf2e 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -26,12 +26,11 @@ #define DRV_NAME "pata_ixp4xx_cf" #define DRV_VERSION "0.2" -static int ixp4xx_set_mode(struct ata_port *ap, struct ata_device **error) +static int ixp4xx_set_mode(struct ata_link *link, struct ata_device **error) { - int i; + struct ata_device *dev; - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; + ata_link_for_each_dev(dev, link) { if (ata_dev_enabled(dev)) { ata_dev_printk(dev, KERN_INFO, "configured for PIO0\n"); dev->pio_mode = XFER_PIO_0; @@ -49,7 +48,7 @@ static void ixp4xx_mmio_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int i; unsigned int words = buflen >> 1; u16 *buf16 = (u16 *) buf; - struct ata_port *ap = adev->ap; + struct ata_port *ap = adev->link->ap; void __iomem *mmio = ap->ioaddr.data_addr; struct ixp4xx_pata_data *data = ap->host->dev->platform_data; @@ -108,7 +107,6 @@ static struct ata_port_operations ixp4xx_port_ops = { .set_mode = ixp4xx_set_mode, .mode_filter = ata_pci_default_filter, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .exec_command = ata_exec_command, @@ -128,14 +126,17 @@ static struct ata_port_operations ixp4xx_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_dummy_irq_ack, .port_start = ata_port_start, }; static void ixp4xx_setup_port(struct ata_ioports *ioaddr, - struct ixp4xx_pata_data *data) + struct ixp4xx_pata_data *data, + unsigned long raw_cs0, unsigned long raw_cs1) { + unsigned long raw_cmd = raw_cs0; + unsigned long raw_ctl = raw_cs1 + 0x06; + ioaddr->cmd_addr = data->cs0; ioaddr->altstatus_addr = data->cs1 + 0x06; ioaddr->ctl_addr = data->cs1 + 0x06; @@ -161,7 +162,12 @@ static void ixp4xx_setup_port(struct ata_ioports *ioaddr, *(unsigned long *)&ioaddr->device_addr ^= 0x03; *(unsigned long *)&ioaddr->status_addr ^= 0x03; *(unsigned long *)&ioaddr->command_addr ^= 0x03; + + raw_cmd ^= 0x03; + raw_ctl ^= 0x03; #endif + + ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", raw_cmd, raw_ctl); } static __devinit int ixp4xx_pata_probe(struct platform_device *pdev) @@ -206,7 +212,7 @@ static __devinit int ixp4xx_pata_probe(struct platform_device *pdev) ap->pio_mask = 0x1f; /* PIO4 */ ap->flags |= ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY | ATA_FLAG_NO_ATAPI; - ixp4xx_setup_port(&ap->ioaddr, data); + ixp4xx_setup_port(ap, data, cs0->start, cs1->start); dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c index 4d67f238eee2..225a7223a726 100644 --- a/drivers/ata/pata_jmicron.c +++ b/drivers/ata/pata_jmicron.c @@ -29,7 +29,7 @@ typedef enum { /** * jmicron_pre_reset - check for 40/80 pin - * @ap: Port + * @link: ATA link * @deadline: deadline jiffies for the operation * * Perform the PATA port setup we need. @@ -39,9 +39,9 @@ typedef enum { * and setup here. We assume that has been done by init_one and the * BIOS. */ - -static int jmicron_pre_reset(struct ata_port *ap, unsigned long deadline) +static int jmicron_pre_reset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); u32 control; u32 control5; @@ -103,7 +103,7 @@ static int jmicron_pre_reset(struct ata_port *ap, unsigned long deadline) ap->cbl = ATA_CBL_SATA; break; } - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** @@ -141,8 +141,6 @@ static struct scsi_host_template jmicron_sht = { }; static const struct ata_port_operations jmicron_ops = { - .port_disable = ata_port_disable, - /* Task file is PCI ATA format, use helpers */ .tf_load = ata_tf_load, .tf_read = ata_tf_read, @@ -168,7 +166,6 @@ static const struct ata_port_operations jmicron_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, /* Generic PATA PCI ATA helpers */ .port_start = ata_port_start, @@ -207,17 +204,8 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i } static const struct pci_device_id jmicron_pci_tbl[] = { - { 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 }, - + { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 0 }, { } /* terminate list */ }; diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index edffc25d2d3f..7bed8d806381 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -96,7 +96,7 @@ static int iordy_mask = 0xFFFFFFFF; /* Use iordy if available */ /** * legacy_set_mode - mode setting - * @ap: IDE interface + * @link: IDE link * @unused: Device that failed when error is returned * * Use a non standard set_mode function. We don't want to be tuned. @@ -107,12 +107,11 @@ static int iordy_mask = 0xFFFFFFFF; /* Use iordy if available */ * expand on this as per hdparm in the base kernel. */ -static int legacy_set_mode(struct ata_port *ap, struct ata_device **unused) +static int legacy_set_mode(struct ata_link *link, struct ata_device **unused) { - int i; + struct ata_device *dev; - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; + ata_link_for_each_dev(dev, link) { if (ata_dev_enabled(dev)) { ata_dev_printk(dev, KERN_INFO, "configured for PIO\n"); dev->pio_mode = XFER_PIO_0; @@ -151,7 +150,6 @@ static struct scsi_host_template legacy_sht = { */ static struct ata_port_operations simple_port_ops = { - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -172,7 +170,6 @@ static struct ata_port_operations simple_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -180,7 +177,6 @@ static struct ata_port_operations simple_port_ops = { static struct ata_port_operations legacy_port_ops = { .set_mode = legacy_set_mode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -201,7 +197,6 @@ static struct ata_port_operations legacy_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -256,7 +251,7 @@ static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev) static void pdc_data_xfer_vlb(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data) { - struct ata_port *ap = adev->ap; + struct ata_port *ap = adev->link->ap; int slop = buflen & 3; unsigned long flags; @@ -296,7 +291,6 @@ static void pdc_data_xfer_vlb(struct ata_device *adev, unsigned char *buf, unsig static struct ata_port_operations pdc20230_port_ops = { .set_piomode = pdc20230_set_piomode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -317,7 +311,6 @@ static struct ata_port_operations pdc20230_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -352,7 +345,6 @@ static void ht6560a_set_piomode(struct ata_port *ap, struct ata_device *adev) static struct ata_port_operations ht6560a_port_ops = { .set_piomode = ht6560a_set_piomode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -373,7 +365,6 @@ static struct ata_port_operations ht6560a_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -419,7 +410,6 @@ static void ht6560b_set_piomode(struct ata_port *ap, struct ata_device *adev) static struct ata_port_operations ht6560b_port_ops = { .set_piomode = ht6560b_set_piomode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -440,7 +430,6 @@ static struct ata_port_operations ht6560b_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -541,7 +530,6 @@ static void opti82c611a_set_piomode(struct ata_port *ap, struct ata_device *adev static struct ata_port_operations opti82c611a_port_ops = { .set_piomode = opti82c611a_set_piomode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -562,7 +550,6 @@ static struct ata_port_operations opti82c611a_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -675,7 +662,6 @@ static unsigned int opti82c46x_qc_issue_prot(struct ata_queued_cmd *qc) static struct ata_port_operations opti82c46x_port_ops = { .set_piomode = opti82c46x_set_piomode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -696,7 +682,6 @@ static struct ata_port_operations opti82c46x_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -814,6 +799,8 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl ata_std_ports(&ap->ioaddr); ap->private_data = ld; + ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io, ctrl); + ret = ata_host_activate(host, irq, ata_interrupt, 0, &legacy_sht); if (ret) goto fail; diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c index b45506f1ef73..9afc8a32b226 100644 --- a/drivers/ata/pata_marvell.c +++ b/drivers/ata/pata_marvell.c @@ -24,14 +24,15 @@ /** * marvell_pre_reset - check for 40/80 pin - * @ap: Port + * @link: link * @deadline: deadline jiffies for the operation * * Perform the PATA port setup we need. */ -static int marvell_pre_reset(struct ata_port *ap, unsigned long deadline) +static int marvell_pre_reset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); u32 devices; void __iomem *barp; @@ -54,7 +55,7 @@ static int marvell_pre_reset(struct ata_port *ap, unsigned long deadline) (!(devices & 0x10))) /* PATA enable ? */ return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } static int marvell_cable_detect(struct ata_port *ap) @@ -110,8 +111,6 @@ static struct scsi_host_template marvell_sht = { }; static const struct ata_port_operations marvell_ops = { - .port_disable = ata_port_disable, - /* Task file is PCI ATA format, use helpers */ .tf_load = ata_tf_load, .tf_read = ata_tf_read, @@ -138,10 +137,9 @@ static const struct ata_port_operations marvell_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, /* Generic PATA PCI ATA helpers */ - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c index 099f4cdc4cd9..50c56e2814c1 100644 --- a/drivers/ata/pata_mpc52xx.c +++ b/drivers/ata/pata_mpc52xx.c @@ -283,7 +283,6 @@ static struct scsi_host_template mpc52xx_ata_sht = { }; static struct ata_port_operations mpc52xx_ata_port_ops = { - .port_disable = ata_port_disable, .set_piomode = mpc52xx_ata_set_piomode, .dev_select = mpc52xx_ata_dev_select, .tf_load = ata_tf_load, @@ -299,17 +298,16 @@ static struct ata_port_operations mpc52xx_ata_port_ops = { .data_xfer = ata_data_xfer, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; static int __devinit -mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv) +mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv, + unsigned long raw_ata_regs) { struct ata_host *host; struct ata_port *ap; struct ata_ioports *aio; - int rc; host = ata_host_alloc(dev, 1); if (!host) @@ -338,6 +336,8 @@ mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv) aio->status_addr = &priv->ata_regs->tf_command; aio->command_addr = &priv->ata_regs->tf_command; + ata_port_desc(ap, "ata_regs 0x%lx", raw_ata_regs); + /* activate host */ return ata_host_activate(host, priv->ata_irq, ata_interrupt, 0, &mpc52xx_ata_sht); @@ -434,7 +434,7 @@ mpc52xx_ata_probe(struct of_device *op, const struct of_device_id *match) } /* Register ourselves to libata */ - rv = mpc52xx_ata_init_one(&op->dev, priv); + rv = mpc52xx_ata_init_one(&op->dev, priv, res_mem.start); if (rv) { printk(KERN_ERR DRV_NAME ": " "Error while registering to ATA layer\n"); diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c index 4ea42838297e..d5483087a3fa 100644 --- a/drivers/ata/pata_mpiix.c +++ b/drivers/ata/pata_mpiix.c @@ -46,15 +46,16 @@ enum { SECONDARY = (1 << 14) }; -static int mpiix_pre_reset(struct ata_port *ap, unsigned long deadline) +static int mpiix_pre_reset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); static const struct pci_bits mpiix_enable_bits = { 0x6D, 1, 0x80, 0x80 }; if (!pci_test_config_bits(pdev, &mpiix_enable_bits)) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** @@ -168,7 +169,6 @@ static struct scsi_host_template mpiix_sht = { }; static struct ata_port_operations mpiix_port_ops = { - .port_disable = ata_port_disable, .set_piomode = mpiix_set_piomode, .tf_load = ata_tf_load, @@ -189,9 +189,8 @@ static struct ata_port_operations mpiix_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id) @@ -202,7 +201,7 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id) struct ata_port *ap; void __iomem *cmd_addr, *ctl_addr; u16 idetim; - int irq; + int cmd, ctl, irq; if (!printed_version++) dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n"); @@ -210,6 +209,7 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id) host = ata_host_alloc(&dev->dev, 1); if (!host) return -ENOMEM; + ap = host->ports[0]; /* MPIIX has many functions which can be turned on or off according to other devices present. Make sure IDE is enabled before we try @@ -221,25 +221,28 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id) /* See if it's primary or secondary channel... */ if (!(idetim & SECONDARY)) { + cmd = 0x1F0; + ctl = 0x3F6; irq = 14; - cmd_addr = devm_ioport_map(&dev->dev, 0x1F0, 8); - ctl_addr = devm_ioport_map(&dev->dev, 0x3F6, 1); } else { + cmd = 0x170; + ctl = 0x376; irq = 15; - cmd_addr = devm_ioport_map(&dev->dev, 0x170, 8); - ctl_addr = devm_ioport_map(&dev->dev, 0x376, 1); } + cmd_addr = devm_ioport_map(&dev->dev, cmd, 8); + ctl_addr = devm_ioport_map(&dev->dev, ctl, 1); if (!cmd_addr || !ctl_addr) return -ENOMEM; + ata_port_desc(ap, "cmd 0x%x ctl 0x%x", cmd, ctl); + /* We do our own plumbing to avoid leaking special cases for whacko ancient hardware into the core code. There are two issues to worry about. #1 The chip is a bridge so if in legacy mode and without BARs set fools the setup. #2 If you pci_disable_device the MPIIX your box goes castors up */ - ap = host->ports[0]; ap->ops = &mpiix_port_ops; ap->pio_mask = 0x1F; ap->flags |= ATA_FLAG_SLAVE_POSS; diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c index 40eb574828bf..25c922abd554 100644 --- a/drivers/ata/pata_netcell.c +++ b/drivers/ata/pata_netcell.c @@ -40,8 +40,6 @@ static struct scsi_host_template netcell_sht = { }; static const struct ata_port_operations netcell_ops = { - .port_disable = ata_port_disable, - /* Task file is PCI ATA format, use helpers */ .tf_load = ata_tf_load, .tf_read = ata_tf_read, @@ -68,10 +66,9 @@ static const struct ata_port_operations netcell_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, /* Generic PATA PCI ATA helpers */ - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c index 2f5d714ebfc4..6e8e55745b7b 100644 --- a/drivers/ata/pata_ns87410.c +++ b/drivers/ata/pata_ns87410.c @@ -32,14 +32,15 @@ /** * ns87410_pre_reset - probe begin - * @ap: ATA port + * @link: ATA link * @deadline: deadline jiffies for the operation * * Check enabled ports */ -static int ns87410_pre_reset(struct ata_port *ap, unsigned long deadline) +static int ns87410_pre_reset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); static const struct pci_bits ns87410_enable_bits[] = { { 0x43, 1, 0x08, 0x08 }, @@ -49,7 +50,7 @@ static int ns87410_pre_reset(struct ata_port *ap, unsigned long deadline) if (!pci_test_config_bits(pdev, &ns87410_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** @@ -161,7 +162,6 @@ static struct scsi_host_template ns87410_sht = { }; static struct ata_port_operations ns87410_port_ops = { - .port_disable = ata_port_disable, .set_piomode = ns87410_set_piomode, .tf_load = ata_tf_load, @@ -184,9 +184,8 @@ static struct ata_port_operations ns87410_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int ns87410_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_ns87415.c b/drivers/ata/pata_ns87415.c new file mode 100644 index 000000000000..bb97ef583f9b --- /dev/null +++ b/drivers/ata/pata_ns87415.c @@ -0,0 +1,467 @@ +/* + * pata_ns87415.c - NS87415 (non PARISC) PATA + * + * (C) 2005 Red Hat <alan@redhat.com> + * + * This is a fairly generic MWDMA controller. It has some limitations + * as it requires timing reloads on PIO/DMA transitions but it is otherwise + * fairly well designed. + * + * This driver assumes the firmware has left the chip in a valid ST506 + * compliant state, either legacy IRQ 14/15 or native INTA shared. You + * may need to add platform code if your system fails to do this. + * + * The same cell appears in the 87560 controller used by some PARISC + * systems. This has its own special mountain of errata. + * + * TODO: + * Test PARISC SuperIO + * Get someone to test on SPARC + * Implement lazy pio/dma switching for better performance + * 8bit shared timing. + * See if we need to kill the FIFO for ATAPI + */ + +#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> +#include <linux/ata.h> + +#define DRV_NAME "pata_ns87415" +#define DRV_VERSION "0.0.1" + +/** + * ns87415_set_mode - Initialize host controller mode timings + * @ap: Port whose timings we are configuring + * @adev: Device whose timings we are configuring + * @mode: Mode to set + * + * Program the mode registers for this controller, channel and + * device. Because the chip is quite an old design we have to do this + * for PIO/DMA switches. + * + * LOCKING: + * None (inherited from caller). + */ + +static void ns87415_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mode) +{ + struct pci_dev *dev = to_pci_dev(ap->host->dev); + int unit = 2 * ap->port_no + adev->devno; + int timing = 0x44 + 2 * unit; + unsigned long T = 1000000000 / 33333; /* PCI clocks */ + struct ata_timing t; + u16 clocking; + u8 iordy; + u8 status; + + /* Timing register format is 17 - low nybble read timing with + the high nybble being 16 - x for recovery time in PCI clocks */ + + ata_timing_compute(adev, adev->pio_mode, &t, T, 0); + + clocking = 17 - FIT(t.active, 2, 17); + clocking |= (16 - FIT(t.recover, 1, 16)) << 4; + /* Use the same timing for read and write bytes */ + clocking |= (clocking << 8); + pci_write_config_word(dev, timing, clocking); + + /* Set the IORDY enable versus DMA enable on or off properly */ + pci_read_config_byte(dev, 0x42, &iordy); + iordy &= ~(1 << (4 + unit)); + if (mode >= XFER_MW_DMA_0 || !ata_pio_need_iordy(adev)) + iordy |= (1 << (4 + unit)); + + /* Paranoia: We shouldn't ever get here with busy write buffers + but if so wait */ + + pci_read_config_byte(dev, 0x43, &status); + while (status & 0x03) { + udelay(1); + pci_read_config_byte(dev, 0x43, &status); + } + /* Flip the IORDY/DMA bits now we are sure the write buffers are + clear */ + pci_write_config_byte(dev, 0x42, iordy); + + /* TODO: Set byte 54 command timing to the best 8bit + mode shared by all four devices */ +} + +/** + * ns87415_set_piomode - Initialize host controller PATA PIO timings + * @ap: Port whose timings we are configuring + * @adev: Device to program + * + * Set PIO mode for device, in host controller PCI config space. + * + * LOCKING: + * None (inherited from caller). + */ + +static void ns87415_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + ns87415_set_mode(ap, adev, adev->pio_mode); +} + +/** + * ns87415_bmdma_setup - Set up DMA + * @qc: Command block + * + * Set up for bus masterng DMA. We have to do this ourselves + * rather than use the helper due to a chip erratum + */ + +static void ns87415_bmdma_setup(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); + u8 dmactl; + + /* load PRD table addr. */ + mb(); /* make sure PRD table writes are visible to controller */ + 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); + /* Due to an erratum we need to write these bits to the wrong + place - which does save us an I/O bizarrely */ + dmactl |= ATA_DMA_INTR | ATA_DMA_ERR; + if (!rw) + dmactl |= ATA_DMA_WR; + iowrite8(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + /* issue r/w command */ + ap->ops->exec_command(ap, &qc->tf); +} + +/** + * ns87415_bmdma_start - Begin DMA transfer + * @qc: Command block + * + * Switch the timings for the chip and set up for a DMA transfer + * before the DMA burst begins. + * + * FIXME: We should do lazy switching on bmdma_start versus + * ata_pio_data_xfer for better performance. + */ + +static void ns87415_bmdma_start(struct ata_queued_cmd *qc) +{ + ns87415_set_mode(qc->ap, qc->dev, qc->dev->dma_mode); + ata_bmdma_start(qc); +} + +/** + * ns87415_bmdma_stop - End DMA transfer + * @qc: Command block + * + * End DMA mode and switch the controller back into PIO mode + */ + +static void ns87415_bmdma_stop(struct ata_queued_cmd *qc) +{ + ata_bmdma_stop(qc); + ns87415_set_mode(qc->ap, qc->dev, qc->dev->pio_mode); +} + +/** + * ns87415_bmdma_irq_clear - Clear interrupt + * @ap: Channel to clear + * + * Erratum: Due to a chip bug regisers 02 and 0A bit 1 and 2 (the + * error bits) are reset by writing to register 00 or 08. + */ + +static void ns87415_bmdma_irq_clear(struct ata_port *ap) +{ + void __iomem *mmio = ap->ioaddr.bmdma_addr; + + if (!mmio) + return; + iowrite8((ioread8(mmio + ATA_DMA_CMD) | ATA_DMA_INTR | ATA_DMA_ERR), + mmio + ATA_DMA_CMD); +} + +/** + * ns87415_check_atapi_dma - ATAPI DMA filter + * @qc: Command block + * + * Disable ATAPI DMA (for now). We may be able to do DMA if we + * kill the prefetching. This isn't clear. + */ + +static int ns87415_check_atapi_dma(struct ata_queued_cmd *qc) +{ + return -EOPNOTSUPP; +} + +#if defined(CONFIG_SUPERIO) + +/* SUPERIO 87560 is a PoS chip that NatSem denies exists. + * Unfortunately, it's built-in on all Astro-based PA-RISC workstations + * which use the integrated NS87514 cell for CD-ROM support. + * i.e we have to support for CD-ROM installs. + * See drivers/parisc/superio.c for more gory details. + * + * Workarounds taken from drivers/ide/pci/ns87415.c + */ + +#include <asm/superio.h> + +/** + * ns87560_read_buggy - workaround buggy Super I/O chip + * @port: Port to read + * + * Work around chipset problems in the 87560 SuperIO chip + */ + +static u8 ns87560_read_buggy(void __iomem *port) +{ + u8 tmp; + int retries = SUPERIO_IDE_MAX_RETRIES; + do { + tmp = ioread8(port); + if (tmp != 0) + return tmp; + udelay(50); + } while(retries-- > 0); + return tmp; +} + +/** + * ns87560_check_status + * @ap: channel to check + * + * Return the status of the channel working around the + * 87560 flaws. + */ + +static u8 ns87560_check_status(struct ata_port *ap) +{ + return ns87560_read_buggy(ap->ioaddr.status_addr); +} + +/** + * ns87560_tf_read - input device's ATA taskfile shadow registers + * @ap: Port from which input is read + * @tf: ATA taskfile register set for storing input + * + * Reads ATA taskfile registers for currently-selected device + * into @tf. Work around the 87560 bugs. + * + * LOCKING: + * Inherited from caller. + */ +void ns87560_tf_read(struct ata_port *ap, struct ata_taskfile *tf) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + + tf->command = ns87560_check_status(ap); + tf->feature = ioread8(ioaddr->error_addr); + tf->nsect = ioread8(ioaddr->nsect_addr); + tf->lbal = ioread8(ioaddr->lbal_addr); + tf->lbam = ioread8(ioaddr->lbam_addr); + tf->lbah = ioread8(ioaddr->lbah_addr); + tf->device = ns87560_read_buggy(ioaddr->device_addr); + + if (tf->flags & ATA_TFLAG_LBA48) { + iowrite8(tf->ctl | ATA_HOB, ioaddr->ctl_addr); + tf->hob_feature = ioread8(ioaddr->error_addr); + tf->hob_nsect = ioread8(ioaddr->nsect_addr); + tf->hob_lbal = ioread8(ioaddr->lbal_addr); + tf->hob_lbam = ioread8(ioaddr->lbam_addr); + tf->hob_lbah = ioread8(ioaddr->lbah_addr); + iowrite8(tf->ctl, ioaddr->ctl_addr); + ap->last_ctl = tf->ctl; + } +} + +/** + * ns87560_bmdma_status + * @ap: channel to check + * + * Return the DMA status of the channel working around the + * 87560 flaws. + */ + +static u8 ns87560_bmdma_status(struct ata_port *ap) +{ + return ns87560_read_buggy(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); +} + +static const struct ata_port_operations ns87560_pata_ops = { + .set_piomode = ns87415_set_piomode, + .mode_filter = ata_pci_default_filter, + + .tf_load = ata_tf_load, + .tf_read = ns87560_tf_read, + .check_status = ns87560_check_status, + .check_atapi_dma = ns87415_check_atapi_dma, + .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, + .cable_detect = ata_cable_40wire, + + .bmdma_setup = ns87415_bmdma_setup, + .bmdma_start = ns87415_bmdma_start, + .bmdma_stop = ns87415_bmdma_stop, + .bmdma_status = ns87560_bmdma_status, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + .data_xfer = ata_data_xfer, + + .irq_handler = ata_interrupt, + .irq_clear = ns87415_bmdma_irq_clear, + .irq_on = ata_irq_on, + + .port_start = ata_sff_port_start, +}; + +#endif /* 87560 SuperIO Support */ + + +static const struct ata_port_operations ns87415_pata_ops = { + .set_piomode = ns87415_set_piomode, + .mode_filter = ata_pci_default_filter, + + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .check_atapi_dma = ns87415_check_atapi_dma, + .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, + .cable_detect = ata_cable_40wire, + + .bmdma_setup = ns87415_bmdma_setup, + .bmdma_start = ns87415_bmdma_start, + .bmdma_stop = ns87415_bmdma_stop, + .bmdma_status = ata_bmdma_status, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + .data_xfer = ata_data_xfer, + + .irq_handler = ata_interrupt, + .irq_clear = ns87415_bmdma_irq_clear, + .irq_on = ata_irq_on, + + .port_start = ata_sff_port_start, +}; + +static struct scsi_host_template ns87415_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, +}; + + +/** + * ns87415_init_one - Register 87415 ATA PCI device with kernel services + * @pdev: PCI device to register + * @ent: Entry in ns87415_pci_tbl matching with @pdev + * + * Called from kernel PCI layer. We probe for combined mode (sigh), + * and then hand over control to libata, for it to do the rest. + * + * LOCKING: + * Inherited from PCI layer (may sleep). + * + * RETURNS: + * Zero on success, or -ERRNO value. + */ + +static int ns87415_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) +{ + static int printed_version; + static const struct ata_port_info info = { + .sht = &ns87415_sht, + .flags = ATA_FLAG_SLAVE_POSS, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .port_ops = &ns87415_pata_ops, + }; + const struct ata_port_info *ppi[] = { &info, NULL }; +#if defined(CONFIG_SUPERIO) + static const struct ata_port_info info87560 = { + .sht = &ns87415_sht, + .flags = ATA_FLAG_SLAVE_POSS, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .port_ops = &ns87560_pata_ops, + }; + + if (PCI_SLOT(pdev->devfn) == 0x0E) + ppi[0] = &info87560; +#endif + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, + "version " DRV_VERSION "\n"); + /* Select 512 byte sectors */ + pci_write_config_byte(pdev, 0x55, 0xEE); + /* Select PIO0 8bit clocking */ + pci_write_config_byte(pdev, 0x54, 0xB7); + return ata_pci_init_one(pdev, ppi); +} + +static const struct pci_device_id ns87415_pci_tbl[] = { + { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_87415), }, + + { } /* terminate list */ +}; + +static struct pci_driver ns87415_pci_driver = { + .name = DRV_NAME, + .id_table = ns87415_pci_tbl, + .probe = ns87415_init_one, + .remove = ata_pci_remove_one, +#ifdef CONFIG_PM + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, +#endif +}; + +static int __init ns87415_init(void) +{ + return pci_register_driver(&ns87415_pci_driver); +} + +static void __exit ns87415_exit(void) +{ + pci_unregister_driver(&ns87415_pci_driver); +} + +module_init(ns87415_init); +module_exit(ns87415_exit); + +MODULE_AUTHOR("Alan Cox"); +MODULE_DESCRIPTION("ATA low-level driver for NS87415 controllers"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, ns87415_pci_tbl); +MODULE_VERSION(DRV_VERSION); diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c index 091a70a0ef1c..3cd5eb2b6c91 100644 --- a/drivers/ata/pata_oldpiix.c +++ b/drivers/ata/pata_oldpiix.c @@ -29,14 +29,15 @@ /** * oldpiix_pre_reset - probe begin - * @ap: ATA port + * @link: ATA link * @deadline: deadline jiffies for the operation * * Set up cable type and use generic probe init */ -static int oldpiix_pre_reset(struct ata_port *ap, unsigned long deadline) +static int oldpiix_pre_reset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); static const struct pci_bits oldpiix_enable_bits[] = { { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */ @@ -46,7 +47,7 @@ static int oldpiix_pre_reset(struct ata_port *ap, unsigned long deadline) if (!pci_test_config_bits(pdev, &oldpiix_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** @@ -237,7 +238,6 @@ static struct scsi_host_template oldpiix_sht = { }; static const struct ata_port_operations oldpiix_pata_ops = { - .port_disable = ata_port_disable, .set_piomode = oldpiix_set_piomode, .set_dmamode = oldpiix_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -265,9 +265,8 @@ static const struct ata_port_operations oldpiix_pata_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c index 458bf67f766f..8f79447b6151 100644 --- a/drivers/ata/pata_opti.c +++ b/drivers/ata/pata_opti.c @@ -46,14 +46,15 @@ enum { /** * opti_pre_reset - probe begin - * @ap: ATA port + * @link: ATA link * @deadline: deadline jiffies for the operation * * Set up cable type and use generic probe init */ -static int opti_pre_reset(struct ata_port *ap, unsigned long deadline) +static int opti_pre_reset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); static const struct pci_bits opti_enable_bits[] = { { 0x45, 1, 0x80, 0x00 }, @@ -63,7 +64,7 @@ static int opti_pre_reset(struct ata_port *ap, unsigned long deadline) if (!pci_test_config_bits(pdev, &opti_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** @@ -182,7 +183,6 @@ static struct scsi_host_template opti_sht = { }; static struct ata_port_operations opti_port_ops = { - .port_disable = ata_port_disable, .set_piomode = opti_set_piomode, .tf_load = ata_tf_load, .tf_read = ata_tf_read, @@ -209,9 +209,8 @@ static struct ata_port_operations opti_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int opti_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c index f89bdfde16d0..6b07b5b48532 100644 --- a/drivers/ata/pata_optidma.c +++ b/drivers/ata/pata_optidma.c @@ -47,14 +47,15 @@ static int pci_clock; /* 0 = 33 1 = 25 */ /** * optidma_pre_reset - probe begin - * @ap: ATA port + * @link: ATA link * @deadline: deadline jiffies for the operation * * Set up cable type and use generic probe init */ -static int optidma_pre_reset(struct ata_port *ap, unsigned long deadline) +static int optidma_pre_reset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); static const struct pci_bits optidma_enable_bits = { 0x40, 1, 0x08, 0x00 @@ -63,7 +64,7 @@ static int optidma_pre_reset(struct ata_port *ap, unsigned long deadline) if (ap->port_no && !pci_test_config_bits(pdev, &optidma_enable_bits)) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** @@ -323,25 +324,26 @@ static u8 optidma_make_bits43(struct ata_device *adev) /** * optidma_set_mode - mode setup - * @ap: port to set up + * @link: link to set up * * Use the standard setup to tune the chipset and then finalise the * configuration by writing the nibble of extra bits of data into * the chip. */ -static int optidma_set_mode(struct ata_port *ap, struct ata_device **r_failed) +static int optidma_set_mode(struct ata_link *link, struct ata_device **r_failed) { + struct ata_port *ap = link->ap; u8 r; int nybble = 4 * ap->port_no; struct pci_dev *pdev = to_pci_dev(ap->host->dev); - int rc = ata_do_set_mode(ap, r_failed); + int rc = ata_do_set_mode(link, r_failed); if (rc == 0) { pci_read_config_byte(pdev, 0x43, &r); r &= (0x0F << nybble); - r |= (optidma_make_bits43(&ap->device[0]) + - (optidma_make_bits43(&ap->device[0]) << 2)) << nybble; + r |= (optidma_make_bits43(&link->device[0]) + + (optidma_make_bits43(&link->device[0]) << 2)) << nybble; pci_write_config_byte(pdev, 0x43, r); } return rc; @@ -366,7 +368,6 @@ static struct scsi_host_template optidma_sht = { }; static struct ata_port_operations optidma_port_ops = { - .port_disable = ata_port_disable, .set_piomode = optidma_set_pio_mode, .set_dmamode = optidma_set_dma_mode, @@ -396,13 +397,11 @@ static struct ata_port_operations optidma_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations optiplus_port_ops = { - .port_disable = ata_port_disable, .set_piomode = optiplus_set_pio_mode, .set_dmamode = optiplus_set_dma_mode, @@ -432,9 +431,8 @@ static struct ata_port_operations optiplus_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index 0f2b027624d6..5db2013230b3 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -56,7 +56,7 @@ struct ata_pcmcia_info { /** * pcmcia_set_mode - PCMCIA specific mode setup - * @ap: Port + * @link: link * @r_failed_dev: Return pointer for failed device * * Perform the tuning and setup of the devices and timings, which @@ -65,13 +65,13 @@ struct ata_pcmcia_info { * decode, which alas is embarrassingly common in the PC world */ -static int pcmcia_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) +static int pcmcia_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) { - struct ata_device *master = &ap->device[0]; - struct ata_device *slave = &ap->device[1]; + struct ata_device *master = &link->device[0]; + struct ata_device *slave = &link->device[1]; if (!ata_dev_enabled(master) || !ata_dev_enabled(slave)) - return ata_do_set_mode(ap, r_failed_dev); + return ata_do_set_mode(link, r_failed_dev); if (memcmp(master->id + ATA_ID_FW_REV, slave->id + ATA_ID_FW_REV, ATA_ID_FW_REV_LEN + ATA_ID_PROD_LEN) == 0) @@ -84,7 +84,7 @@ static int pcmcia_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev ata_dev_disable(slave); } } - return ata_do_set_mode(ap, r_failed_dev); + return ata_do_set_mode(link, r_failed_dev); } static struct scsi_host_template pcmcia_sht = { @@ -107,7 +107,6 @@ static struct scsi_host_template pcmcia_sht = { static struct ata_port_operations pcmcia_port_ops = { .set_mode = pcmcia_set_mode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -127,7 +126,6 @@ static struct ata_port_operations pcmcia_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_sff_port_start, }; @@ -304,6 +302,8 @@ next_entry: ap->ioaddr.ctl_addr = ctl_addr; ata_std_ports(&ap->ioaddr); + ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io_base, ctl_base); + /* activate */ ret = ata_host_activate(host, pdev->irq.AssignedIRQ, ata_interrupt, IRQF_SHARED, &pcmcia_sht); @@ -353,6 +353,7 @@ 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(0x0000, 0x0000), /* Corsair */ 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 */ @@ -378,6 +379,7 @@ static struct pcmcia_device_id pcmcia_devices[] = { PCMCIA_DEVICE_PROD_ID12("EXP ", "CD-ROM", 0x0a5c52fd, 0x66536591), PCMCIA_DEVICE_PROD_ID12("EXP ", "PnPIDE", 0x0a5c52fd, 0x0c694728), PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e), + PCMCIA_DEVICE_PROD_ID12("Hyperstone", "Model1", 0x3d5b9ef5, 0xca6ab420), PCMCIA_DEVICE_PROD_ID12("HITACHI", "FLASH", 0xf4f43949, 0x9eb86aae), PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178), PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178), diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index bb64a986e8f5..3d3f1558cdee 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -69,7 +69,7 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev); static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc); static unsigned long pdc2027x_mode_filter(struct ata_device *adev, unsigned long mask); static int pdc2027x_cable_detect(struct ata_port *ap); -static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed); +static int pdc2027x_set_mode(struct ata_link *link, struct ata_device **r_failed); /* * ATA Timing Tables based on 133MHz controller clock. @@ -147,7 +147,6 @@ static struct scsi_host_template pdc2027x_sht = { }; static struct ata_port_operations pdc2027x_pata100_ops = { - .port_disable = ata_port_disable, .mode_filter = ata_pci_default_filter, .tf_load = ata_tf_load, @@ -173,13 +172,11 @@ static struct ata_port_operations pdc2027x_pata100_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations pdc2027x_pata133_ops = { - .port_disable = ata_port_disable, .set_piomode = pdc2027x_set_piomode, .set_dmamode = pdc2027x_set_dmamode, .set_mode = pdc2027x_set_mode, @@ -208,9 +205,8 @@ static struct ata_port_operations pdc2027x_pata133_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_info pdc2027x_port_info[] = { @@ -277,7 +273,7 @@ static int pdc2027x_cable_detect(struct ata_port *ap) u32 cgcr; /* check cable detect results */ - cgcr = readl(port_mmio(ap, PDC_GLOBAL_CTL)); + cgcr = ioread32(port_mmio(ap, PDC_GLOBAL_CTL)); if (cgcr & (1 << 26)) goto cbl40; @@ -295,12 +291,12 @@ cbl40: */ static inline int pdc2027x_port_enabled(struct ata_port *ap) { - return readb(port_mmio(ap, PDC_ATA_CTL)) & 0x02; + return ioread8(port_mmio(ap, PDC_ATA_CTL)) & 0x02; } /** * pdc2027x_prereset - prereset for PATA host controller - * @ap: Target port + * @link: Target link * @deadline: deadline jiffies for the operation * * Probeinit including cable detection. @@ -309,12 +305,12 @@ static inline int pdc2027x_port_enabled(struct ata_port *ap) * None (inherited from caller). */ -static int pdc2027x_prereset(struct ata_port *ap, unsigned long deadline) +static int pdc2027x_prereset(struct ata_link *link, unsigned long deadline) { /* Check whether port enabled */ - if (!pdc2027x_port_enabled(ap)) + if (!pdc2027x_port_enabled(link->ap)) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** @@ -387,16 +383,16 @@ static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev) /* Set the PIO timing registers using value table for 133MHz */ PDPRINTK("Set pio regs... \n"); - ctcr0 = readl(dev_mmio(ap, adev, PDC_CTCR0)); + ctcr0 = ioread32(dev_mmio(ap, adev, PDC_CTCR0)); ctcr0 &= 0xffff0000; ctcr0 |= pdc2027x_pio_timing_tbl[pio].value0 | (pdc2027x_pio_timing_tbl[pio].value1 << 8); - writel(ctcr0, dev_mmio(ap, adev, PDC_CTCR0)); + iowrite32(ctcr0, dev_mmio(ap, adev, PDC_CTCR0)); - ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1)); + ctcr1 = ioread32(dev_mmio(ap, adev, PDC_CTCR1)); ctcr1 &= 0x00ffffff; ctcr1 |= (pdc2027x_pio_timing_tbl[pio].value2 << 24); - writel(ctcr1, dev_mmio(ap, adev, PDC_CTCR1)); + iowrite32(ctcr1, dev_mmio(ap, adev, PDC_CTCR1)); PDPRINTK("Set pio regs done\n"); @@ -430,18 +426,18 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev) * If tHOLD is '1', the hardware will add half clock for data hold time. * This code segment seems to be no effect. tHOLD will be overwritten below. */ - ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1)); - writel(ctcr1 & ~(1 << 7), dev_mmio(ap, adev, PDC_CTCR1)); + ctcr1 = ioread32(dev_mmio(ap, adev, PDC_CTCR1)); + iowrite32(ctcr1 & ~(1 << 7), dev_mmio(ap, adev, PDC_CTCR1)); } PDPRINTK("Set udma regs... \n"); - ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1)); + ctcr1 = ioread32(dev_mmio(ap, adev, PDC_CTCR1)); ctcr1 &= 0xff000000; ctcr1 |= pdc2027x_udma_timing_tbl[udma_mode].value0 | (pdc2027x_udma_timing_tbl[udma_mode].value1 << 8) | (pdc2027x_udma_timing_tbl[udma_mode].value2 << 16); - writel(ctcr1, dev_mmio(ap, adev, PDC_CTCR1)); + iowrite32(ctcr1, dev_mmio(ap, adev, PDC_CTCR1)); PDPRINTK("Set udma regs done\n"); @@ -453,13 +449,13 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev) unsigned int mdma_mode = dma_mode & 0x07; PDPRINTK("Set mdma regs... \n"); - ctcr0 = readl(dev_mmio(ap, adev, PDC_CTCR0)); + ctcr0 = ioread32(dev_mmio(ap, adev, PDC_CTCR0)); ctcr0 &= 0x0000ffff; ctcr0 |= (pdc2027x_mdma_timing_tbl[mdma_mode].value0 << 16) | (pdc2027x_mdma_timing_tbl[mdma_mode].value1 << 24); - writel(ctcr0, dev_mmio(ap, adev, PDC_CTCR0)); + iowrite32(ctcr0, dev_mmio(ap, adev, PDC_CTCR0)); PDPRINTK("Set mdma regs done\n"); PDPRINTK("Set to mdma mode[%u] \n", mdma_mode); @@ -470,24 +466,24 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev) /** * pdc2027x_set_mode - Set the timing registers back to correct values. - * @ap: Port to configure + * @link: link to configure * @r_failed: Returned device for failure * * The pdc2027x hardware will look at "SET FEATURES" and change the timing registers * automatically. The values set by the hardware might be incorrect, under 133Mhz PLL. * This function overwrites the possibly incorrect values set by the hardware to be correct. */ -static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed) +static int pdc2027x_set_mode(struct ata_link *link, struct ata_device **r_failed) { - int i; - - i = ata_do_set_mode(ap, r_failed); - if (i < 0) - return i; + struct ata_port *ap = link->ap; + struct ata_device *dev; + int rc; - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; + rc = ata_do_set_mode(link, r_failed); + if (rc < 0) + return rc; + ata_link_for_each_dev(dev, link) { if (ata_dev_enabled(dev)) { pdc2027x_set_piomode(ap, dev); @@ -496,9 +492,9 @@ static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed) * Enable prefetch if the device support PIO only. */ if (dev->xfer_shift == ATA_SHIFT_PIO) { - u32 ctcr1 = readl(dev_mmio(ap, dev, PDC_CTCR1)); + u32 ctcr1 = ioread32(dev_mmio(ap, dev, PDC_CTCR1)); ctcr1 |= (1 << 25); - writel(ctcr1, dev_mmio(ap, dev, PDC_CTCR1)); + iowrite32(ctcr1, dev_mmio(ap, dev, PDC_CTCR1)); PDPRINTK("Turn on prefetch\n"); } else { @@ -563,14 +559,12 @@ static long pdc_read_counter(struct ata_host *host) u32 bccrl, bccrh, bccrlv, bccrhv; retry: - bccrl = readl(mmio_base + PDC_BYTE_COUNT) & 0x7fff; - bccrh = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff; - rmb(); + bccrl = ioread32(mmio_base + PDC_BYTE_COUNT) & 0x7fff; + bccrh = ioread32(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff; /* Read the counter values again for verification */ - bccrlv = readl(mmio_base + PDC_BYTE_COUNT) & 0x7fff; - bccrhv = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff; - rmb(); + bccrlv = ioread32(mmio_base + PDC_BYTE_COUNT) & 0x7fff; + bccrhv = ioread32(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff; counter = (bccrh << 15) | bccrl; @@ -619,7 +613,7 @@ static void pdc_adjust_pll(struct ata_host *host, long pll_clock, unsigned int b /* Show the current clock value of PLL control register * (maybe already configured by the firmware) */ - pll_ctl = readw(mmio_base + PDC_PLL_CTL); + pll_ctl = ioread16(mmio_base + PDC_PLL_CTL); PDPRINTK("pll_ctl[%X]\n", pll_ctl); #endif @@ -659,8 +653,8 @@ static void pdc_adjust_pll(struct ata_host *host, long pll_clock, unsigned int b PDPRINTK("Writing pll_ctl[%X]\n", pll_ctl); - writew(pll_ctl, mmio_base + PDC_PLL_CTL); - readw(mmio_base + PDC_PLL_CTL); /* flush */ + iowrite16(pll_ctl, mmio_base + PDC_PLL_CTL); + ioread16(mmio_base + PDC_PLL_CTL); /* flush */ /* Wait the PLL circuit to be stable */ mdelay(30); @@ -670,7 +664,7 @@ static void pdc_adjust_pll(struct ata_host *host, long pll_clock, unsigned int b * Show the current clock value of PLL control register * (maybe configured by the firmware) */ - pll_ctl = readw(mmio_base + PDC_PLL_CTL); + pll_ctl = ioread16(mmio_base + PDC_PLL_CTL); PDPRINTK("pll_ctl[%X]\n", pll_ctl); #endif @@ -693,10 +687,10 @@ static long pdc_detect_pll_input_clock(struct ata_host *host) long pll_clock, usec_elapsed; /* Start the test mode */ - scr = readl(mmio_base + PDC_SYS_CTL); + scr = ioread32(mmio_base + PDC_SYS_CTL); PDPRINTK("scr[%X]\n", scr); - writel(scr | (0x01 << 14), mmio_base + PDC_SYS_CTL); - readl(mmio_base + PDC_SYS_CTL); /* flush */ + iowrite32(scr | (0x01 << 14), mmio_base + PDC_SYS_CTL); + ioread32(mmio_base + PDC_SYS_CTL); /* flush */ /* Read current counter value */ start_count = pdc_read_counter(host); @@ -710,10 +704,10 @@ static long pdc_detect_pll_input_clock(struct ata_host *host) do_gettimeofday(&end_time); /* Stop the test mode */ - scr = readl(mmio_base + PDC_SYS_CTL); + scr = ioread32(mmio_base + PDC_SYS_CTL); PDPRINTK("scr[%X]\n", scr); - writel(scr & ~(0x01 << 14), mmio_base + PDC_SYS_CTL); - readl(mmio_base + PDC_SYS_CTL); /* flush */ + iowrite32(scr & ~(0x01 << 14), mmio_base + PDC_SYS_CTL); + ioread32(mmio_base + PDC_SYS_CTL); /* flush */ /* calculate the input clock in Hz */ usec_elapsed = (end_time.tv_sec - start_time.tv_sec) * 1000000 + @@ -745,9 +739,6 @@ static int pdc_hardware_init(struct ata_host *host, unsigned int board_idx) */ pll_clock = pdc_detect_pll_input_clock(host); - if (pll_clock < 0) /* counter overflow? Try again. */ - pll_clock = pdc_detect_pll_input_clock(host); - dev_printk(KERN_INFO, host->dev, "PLL input clock %ld kHz\n", pll_clock/1000); /* Adjust PLL control register */ @@ -791,12 +782,14 @@ static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base) static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; + static const unsigned long cmd_offset[] = { 0x17c0, 0x15c0 }; + static const unsigned long bmdma_offset[] = { 0x1000, 0x1008 }; unsigned int board_idx = (unsigned int) ent->driver_data; const struct ata_port_info *ppi[] = { &pdc2027x_port_info[board_idx], NULL }; struct ata_host *host; void __iomem *mmio_base; - int rc; + int i, rc; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); @@ -826,10 +819,15 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de mmio_base = host->iomap[PDC_MMIO_BAR]; - pdc_ata_setup_port(&host->ports[0]->ioaddr, mmio_base + 0x17c0); - host->ports[0]->ioaddr.bmdma_addr = mmio_base + 0x1000; - pdc_ata_setup_port(&host->ports[1]->ioaddr, mmio_base + 0x15c0); - host->ports[1]->ioaddr.bmdma_addr = mmio_base + 0x1008; + for (i = 0; i < 2; i++) { + struct ata_port *ap = host->ports[i]; + + pdc_ata_setup_port(&ap->ioaddr, mmio_base + cmd_offset[i]); + ap->ioaddr.bmdma_addr = mmio_base + bmdma_offset[i]; + + ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio"); + ata_port_pbar_desc(ap, PDC_MMIO_BAR, cmd_offset[i], "cmd"); + } //pci_enable_intx(pdev); diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c index 92447bed5e77..65d951618c60 100644 --- a/drivers/ata/pata_pdc202xx_old.c +++ b/drivers/ata/pata_pdc202xx_old.c @@ -9,7 +9,7 @@ * First cut with LBA48/ATAPI * * TODO: - * Channel interlock/reset on both required + * Channel interlock/reset on both required ? */ #include <linux/kernel.h> @@ -22,7 +22,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_pdc202xx_old" -#define DRV_VERSION "0.4.2" +#define DRV_VERSION "0.4.3" static int pdc2026x_cable_detect(struct ata_port *ap) { @@ -106,9 +106,9 @@ static void pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev) { 0x20, 0x01 } }; static u8 mdma_timing[3][2] = { - { 0x60, 0x03 }, - { 0x60, 0x04 }, { 0xe0, 0x0f }, + { 0x60, 0x04 }, + { 0x60, 0x03 }, }; u8 r_bp, r_cp; @@ -139,6 +139,9 @@ static void pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev) * * In UDMA3 or higher we have to clock switch for the duration of the * DMA transfer sequence. + * + * Note: The host lock held by the libata layer protects + * us from two channels both trying to set DMA bits at once */ static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc) @@ -187,6 +190,9 @@ static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc) * * After a DMA completes we need to put the clock back to 33MHz for * PIO timings. + * + * Note: The host lock held by the libata layer protects + * us from two channels both trying to set DMA bits at once */ static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc) @@ -206,7 +212,6 @@ static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc) iowrite32(0, atapi_reg); iowrite8(ioread8(clock) & ~sel66, clock); } - /* Check we keep host level locking here */ /* Flip back to 33Mhz for PIO */ if (adev->dma_mode >= XFER_UDMA_2) iowrite8(ioread8(clock) & ~sel66, clock); @@ -247,7 +252,6 @@ static struct scsi_host_template pdc202xx_sht = { }; static struct ata_port_operations pdc2024x_port_ops = { - .port_disable = ata_port_disable, .set_piomode = pdc202xx_set_piomode, .set_dmamode = pdc202xx_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -275,13 +279,11 @@ static struct ata_port_operations pdc2024x_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations pdc2026x_port_ops = { - .port_disable = ata_port_disable, .set_piomode = pdc202xx_set_piomode, .set_dmamode = pdc202xx_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -310,9 +312,8 @@ static struct ata_port_operations pdc2026x_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index 5086d03f2d7c..fc72a965643d 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -30,13 +30,11 @@ static int pio_mask = 1; * Provide our own set_mode() as we don't want to change anything that has * already been configured.. */ -static int pata_platform_set_mode(struct ata_port *ap, struct ata_device **unused) +static int pata_platform_set_mode(struct ata_link *link, struct ata_device **unused) { - int i; - - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; + struct ata_device *dev; + ata_link_for_each_dev(dev, link) { if (ata_dev_enabled(dev)) { /* We don't really care */ dev->pio_mode = dev->xfer_mode = XFER_PIO_0; @@ -71,7 +69,6 @@ static struct scsi_host_template pata_platform_sht = { static struct ata_port_operations pata_platform_port_ops = { .set_mode = pata_platform_set_mode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -91,7 +88,6 @@ static struct ata_port_operations pata_platform_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_dummy_ret0, }; @@ -209,9 +205,13 @@ static int __devinit pata_platform_probe(struct platform_device *pdev) ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr; - pp_info = (struct pata_platform_info *)(pdev->dev.platform_data); + pp_info = pdev->dev.platform_data; pata_platform_setup_port(&ap->ioaddr, pp_info); + ata_port_desc(ap, "%s cmd 0x%llx ctl 0x%llx", mmio ? "mmio" : "ioport", + (unsigned long long)io_res->start, + (unsigned long long)ctl_res->start); + /* activate */ return ata_host_activate(host, platform_get_irq(pdev, 0), ata_interrupt, pp_info ? pp_info->irq_flags diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c index 1998c19e8743..7d4c696c4cb6 100644 --- a/drivers/ata/pata_qdi.c +++ b/drivers/ata/pata_qdi.c @@ -126,7 +126,7 @@ static unsigned int qdi_qc_issue_prot(struct ata_queued_cmd *qc) static void qdi_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data) { - struct ata_port *ap = adev->ap; + struct ata_port *ap = adev->link->ap; int slop = buflen & 3; if (ata_id_has_dword_io(adev->id)) { @@ -170,7 +170,6 @@ static struct scsi_host_template qdi_sht = { }; static struct ata_port_operations qdi6500_port_ops = { - .port_disable = ata_port_disable, .set_piomode = qdi6500_set_piomode, .tf_load = ata_tf_load, @@ -192,13 +191,11 @@ static struct ata_port_operations qdi6500_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations qdi6580_port_ops = { - .port_disable = ata_port_disable, .set_piomode = qdi6580_set_piomode, .tf_load = ata_tf_load, @@ -220,9 +217,8 @@ static struct ata_port_operations qdi6580_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** @@ -238,6 +234,7 @@ static struct ata_port_operations qdi6580_port_ops = { static __init int qdi_init_one(unsigned long port, int type, unsigned long io, int irq, int fast) { + unsigned long ctl = io + 0x206; struct platform_device *pdev; struct ata_host *host; struct ata_port *ap; @@ -254,7 +251,7 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i ret = -ENOMEM; io_addr = devm_ioport_map(&pdev->dev, io, 8); - ctl_addr = devm_ioport_map(&pdev->dev, io + 0x206, 1); + ctl_addr = devm_ioport_map(&pdev->dev, ctl, 1); if (!io_addr || !ctl_addr) goto fail; @@ -279,6 +276,8 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i ap->ioaddr.ctl_addr = ctl_addr; ata_std_ports(&ap->ioaddr); + ata_port_desc(ap, "cmd %lx ctl %lx", io, ctl); + /* * Hook in a private data structure per channel */ diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c index 7d1aabed422d..d5b76497f4a2 100644 --- a/drivers/ata/pata_radisys.c +++ b/drivers/ata/pata_radisys.c @@ -203,7 +203,6 @@ static struct scsi_host_template radisys_sht = { }; static const struct ata_port_operations radisys_pata_ops = { - .port_disable = ata_port_disable, .set_piomode = radisys_set_piomode, .set_dmamode = radisys_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -231,9 +230,8 @@ static const struct ata_port_operations radisys_pata_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index 7632fcb070ca..ba8a31c55edb 100644 --- a/drivers/ata/pata_rz1000.c +++ b/drivers/ata/pata_rz1000.c @@ -26,7 +26,7 @@ /** * rz1000_set_mode - mode setting function - * @ap: ATA interface + * @link: ATA link * @unused: returned device on set_mode failure * * Use a non standard set_mode function. We don't want to be tuned. We @@ -34,12 +34,11 @@ * whacked out. */ -static int rz1000_set_mode(struct ata_port *ap, struct ata_device **unused) +static int rz1000_set_mode(struct ata_link *link, struct ata_device **unused) { - int i; + struct ata_device *dev; - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; + ata_link_for_each_dev(dev, link) { if (ata_dev_enabled(dev)) { /* We don't really care */ dev->pio_mode = XFER_PIO_0; @@ -74,7 +73,6 @@ static struct scsi_host_template rz1000_sht = { static struct ata_port_operations rz1000_port_ops = { .set_mode = rz1000_set_mode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -100,9 +98,8 @@ static struct ata_port_operations rz1000_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int rz1000_fifo_disable(struct pci_dev *pdev) diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c index 5edf67b1f3bf..21ebc485ca4b 100644 --- a/drivers/ata/pata_sc1200.c +++ b/drivers/ata/pata_sc1200.c @@ -197,7 +197,6 @@ static struct scsi_host_template sc1200_sht = { }; static struct ata_port_operations sc1200_port_ops = { - .port_disable = ata_port_disable, .set_piomode = sc1200_set_piomode, .set_dmamode = sc1200_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -227,9 +226,8 @@ static struct ata_port_operations sc1200_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c index 2d048ef25a5a..55576138faea 100644 --- a/drivers/ata/pata_scc.c +++ b/drivers/ata/pata_scc.c @@ -603,16 +603,17 @@ static unsigned int scc_bus_softreset(struct ata_port *ap, unsigned int devmask, * Note: Original code is ata_std_softreset(). */ -static int scc_std_softreset (struct ata_port *ap, unsigned int *classes, - unsigned long deadline) +static int scc_std_softreset(struct ata_link *link, unsigned int *classes, + unsigned long deadline) { + struct ata_port *ap = link->ap; 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)) { + if (ata_link_offline(link)) { classes[0] = ATA_DEV_NONE; goto out; } @@ -636,9 +637,11 @@ static int scc_std_softreset (struct ata_port *ap, unsigned int *classes, } /* determine by signature whether we have ATA or ATAPI devices */ - classes[0] = ata_dev_try_classify(ap, 0, &err); + classes[0] = ata_dev_try_classify(&ap->link.device[0], + devmask & (1 << 0), &err); if (slave_possible && err != 0x81) - classes[1] = ata_dev_try_classify(ap, 1, &err); + classes[1] = ata_dev_try_classify(&ap->link.device[1], + devmask & (1 << 1), &err); out: DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]); @@ -701,7 +704,7 @@ static void scc_bmdma_stop (struct ata_queued_cmd *qc) 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, deadline); + scc_std_softreset(&ap->link, &classes, deadline); continue; } @@ -740,7 +743,7 @@ static u8 scc_bmdma_status (struct ata_port *ap) void __iomem *mmio = ap->ioaddr.bmdma_addr; u8 host_stat = in_be32(mmio + SCC_DMA_STATUS); u32 int_status = in_be32(mmio + SCC_DMA_INTST); - struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); + struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag); static int retry = 0; /* return if IOS_SS is cleared */ @@ -785,7 +788,7 @@ static u8 scc_bmdma_status (struct ata_port *ap) static void scc_data_xfer (struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data) { - struct ata_port *ap = adev->ap; + struct ata_port *ap = adev->link->ap; unsigned int words = buflen >> 1; unsigned int i; u16 *buf16 = (u16 *) buf; @@ -839,38 +842,6 @@ static u8 scc_irq_on (struct ata_port *ap) } /** - * 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 * @@ -901,10 +872,10 @@ static void scc_bmdma_freeze (struct ata_port *ap) * @deadline: deadline jiffies for the operation */ -static int scc_pata_prereset(struct ata_port *ap, unsigned long deadline) +static int scc_pata_prereset(struct ata_link *link, unsigned long deadline) { - ap->cbl = ATA_CBL_PATA80; - return ata_std_prereset(ap, deadline); + link->ap->cbl = ATA_CBL_PATA80; + return ata_std_prereset(link, deadline); } /** @@ -915,8 +886,10 @@ static int scc_pata_prereset(struct ata_port *ap, unsigned long deadline) * Note: Original code is ata_std_postreset(). */ -static void scc_std_postreset (struct ata_port *ap, unsigned int *classes) +static void scc_std_postreset(struct ata_link *link, unsigned int *classes) { + struct ata_port *ap = link->ap; + DPRINTK("ENTER\n"); /* is double-select really necessary? */ @@ -1020,7 +993,6 @@ static struct scsi_host_template scc_sht = { }; 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 = scc_mode_filter, @@ -1047,7 +1019,6 @@ static const struct ata_port_operations scc_pata_ops = { .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, @@ -1193,6 +1164,9 @@ static int scc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) return rc; host->iomap = pcim_iomap_table(pdev); + ata_port_pbar_desc(host->ports[0], SCC_CTRL_BAR, -1, "ctrl"); + ata_port_pbar_desc(host->ports[0], SCC_BMID_BAR, -1, "bmid"); + rc = scc_host_init(host); if (rc) return rc; diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c index 0faf99c8f13e..df68806df4be 100644 --- a/drivers/ata/pata_serverworks.c +++ b/drivers/ata/pata_serverworks.c @@ -318,7 +318,6 @@ static struct scsi_host_template serverworks_sht = { }; static struct ata_port_operations serverworks_osb4_port_ops = { - .port_disable = ata_port_disable, .set_piomode = serverworks_set_piomode, .set_dmamode = serverworks_set_dmamode, .mode_filter = serverworks_osb4_filter, @@ -348,13 +347,11 @@ static struct ata_port_operations serverworks_osb4_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations serverworks_csb_port_ops = { - .port_disable = ata_port_disable, .set_piomode = serverworks_set_piomode, .set_dmamode = serverworks_set_dmamode, .mode_filter = serverworks_csb_filter, @@ -384,9 +381,8 @@ static struct ata_port_operations serverworks_csb_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int serverworks_fixup_osb4(struct pci_dev *pdev) diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index 40395804a66f..4dc2e73298fd 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c @@ -95,15 +95,16 @@ static int sil680_cable_detect(struct ata_port *ap) { /** * sil680_bus_reset - reset the SIL680 bus - * @ap: ATA port to reset + * @link: ATA link to reset * @deadline: deadline jiffies for the operation * * Perform the SIL680 housekeeping when doing an ATA bus reset */ -static int sil680_bus_reset(struct ata_port *ap,unsigned int *classes, +static int sil680_bus_reset(struct ata_link *link, unsigned int *classes, unsigned long deadline) { + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); unsigned long addr = sil680_selreg(ap, 0); u8 reset; @@ -112,7 +113,7 @@ static int sil680_bus_reset(struct ata_port *ap,unsigned int *classes, pci_write_config_byte(pdev, addr, reset | 0x03); udelay(25); pci_write_config_byte(pdev, addr, reset); - return ata_std_softreset(ap, classes, deadline); + return ata_std_softreset(link, classes, deadline); } static void sil680_error_handler(struct ata_port *ap) @@ -237,7 +238,6 @@ static struct scsi_host_template sil680_sht = { }; static struct ata_port_operations sil680_port_ops = { - .port_disable = ata_port_disable, .set_piomode = sil680_set_piomode, .set_dmamode = sil680_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -266,9 +266,8 @@ static struct ata_port_operations sil680_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** @@ -280,7 +279,7 @@ static struct ata_port_operations sil680_port_ops = { * Returns the final clock settings. */ -static u8 sil680_init_chip(struct pci_dev *pdev) +static u8 sil680_init_chip(struct pci_dev *pdev, int *try_mmio) { u32 class_rev = 0; u8 tmpbyte = 0; @@ -298,6 +297,8 @@ static u8 sil680_init_chip(struct pci_dev *pdev) dev_dbg(&pdev->dev, "sil680: BA5_EN = %d clock = %02X\n", tmpbyte & 1, tmpbyte & 0x30); + *try_mmio = (tmpbyte & 1) || pci_resource_start(pdev, 5); + switch(tmpbyte & 0x30) { case 0x00: /* 133 clock attempt to force it on */ @@ -362,25 +363,76 @@ static int __devinit sil680_init_one(struct pci_dev *pdev, }; const struct ata_port_info *ppi[] = { &info, NULL }; static int printed_version; + struct ata_host *host; + void __iomem *mmio_base; + int rc, try_mmio; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - switch(sil680_init_chip(pdev)) - { + switch (sil680_init_chip(pdev, &try_mmio)) { case 0: ppi[0] = &info_slow; break; case 0x30: return -ENODEV; } + + if (!try_mmio) + goto use_ioports; + + /* Try to acquire MMIO resources and fallback to PIO if + * that fails + */ + rc = pcim_enable_device(pdev); + if (rc) + return rc; + rc = pcim_iomap_regions(pdev, 1 << SIL680_MMIO_BAR, DRV_NAME); + if (rc) + goto use_ioports; + + /* Allocate host and set it up */ + host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2); + if (!host) + return -ENOMEM; + host->iomap = pcim_iomap_table(pdev); + + /* Setup DMA masks */ + 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; + pci_set_master(pdev); + + /* Get MMIO base and initialize port addresses */ + mmio_base = host->iomap[SIL680_MMIO_BAR]; + host->ports[0]->ioaddr.bmdma_addr = mmio_base + 0x00; + host->ports[0]->ioaddr.cmd_addr = mmio_base + 0x80; + host->ports[0]->ioaddr.ctl_addr = mmio_base + 0x8a; + host->ports[0]->ioaddr.altstatus_addr = mmio_base + 0x8a; + ata_std_ports(&host->ports[0]->ioaddr); + host->ports[1]->ioaddr.bmdma_addr = mmio_base + 0x08; + host->ports[1]->ioaddr.cmd_addr = mmio_base + 0xc0; + host->ports[1]->ioaddr.ctl_addr = mmio_base + 0xca; + host->ports[1]->ioaddr.altstatus_addr = mmio_base + 0xca; + ata_std_ports(&host->ports[1]->ioaddr); + + /* Register & activate */ + return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED, + &sil680_sht); + +use_ioports: return ata_pci_init_one(pdev, ppi); } #ifdef CONFIG_PM static int sil680_reinit_one(struct pci_dev *pdev) { - sil680_init_chip(pdev); + int try_mmio; + + sil680_init_chip(pdev, &try_mmio); return ata_pci_device_resume(pdev); } #endif diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c index cce2834b2b60..3b5be77e861c 100644 --- a/drivers/ata/pata_sis.c +++ b/drivers/ata/pata_sis.c @@ -84,7 +84,7 @@ static int sis_short_ata40(struct pci_dev *dev) static int sis_old_port_base(struct ata_device *adev) { - return 0x40 + (4 * adev->ap->port_no) + (2 * adev->devno); + return 0x40 + (4 * adev->link->ap->port_no) + (2 * adev->devno); } /** @@ -133,19 +133,20 @@ static int sis_66_cable_detect(struct ata_port *ap) /** * sis_pre_reset - probe begin - * @ap: ATA port + * @link: ATA link * @deadline: deadline jiffies for the operation * * Set up cable type and use generic probe init */ -static int sis_pre_reset(struct ata_port *ap, unsigned long deadline) +static int sis_pre_reset(struct ata_link *link, unsigned long deadline) { static const struct pci_bits sis_enable_bits[] = { { 0x4aU, 1U, 0x02UL, 0x02UL }, /* port 0 */ { 0x4aU, 1U, 0x04UL, 0x04UL }, /* port 1 */ }; + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no])) @@ -154,7 +155,7 @@ static int sis_pre_reset(struct ata_port *ap, unsigned long deadline) /* Clear the FIFO settings. We can't enable the FIFO until we know we are poking at a disk */ pci_write_config_byte(pdev, 0x4B, 0); - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } @@ -530,7 +531,6 @@ static struct scsi_host_template sis_sht = { }; static const struct ata_port_operations sis_133_ops = { - .port_disable = ata_port_disable, .set_piomode = sis_133_set_piomode, .set_dmamode = sis_133_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -558,13 +558,11 @@ static const struct ata_port_operations sis_133_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static const struct ata_port_operations sis_133_for_sata_ops = { - .port_disable = ata_port_disable, .set_piomode = sis_133_set_piomode, .set_dmamode = sis_133_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -592,13 +590,11 @@ static const struct ata_port_operations sis_133_for_sata_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static const struct ata_port_operations sis_133_early_ops = { - .port_disable = ata_port_disable, .set_piomode = sis_100_set_piomode, .set_dmamode = sis_133_early_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -626,13 +622,11 @@ static const struct ata_port_operations sis_133_early_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static const struct ata_port_operations sis_100_ops = { - .port_disable = ata_port_disable, .set_piomode = sis_100_set_piomode, .set_dmamode = sis_100_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -660,13 +654,11 @@ static const struct ata_port_operations sis_100_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static const struct ata_port_operations sis_66_ops = { - .port_disable = ata_port_disable, .set_piomode = sis_old_set_piomode, .set_dmamode = sis_66_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -694,13 +686,11 @@ static const struct ata_port_operations sis_66_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static const struct ata_port_operations sis_old_ops = { - .port_disable = ata_port_disable, .set_piomode = sis_old_set_piomode, .set_dmamode = sis_old_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -728,9 +718,8 @@ static const struct ata_port_operations sis_old_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static const struct ata_port_info sis_info = { diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c index c0f43bb25956..1388cef52c07 100644 --- a/drivers/ata/pata_sl82c105.c +++ b/drivers/ata/pata_sl82c105.c @@ -43,23 +43,24 @@ enum { /** * sl82c105_pre_reset - probe begin - * @ap: ATA port + * @link: ATA link * @deadline: deadline jiffies for the operation * * Set up cable type and use generic probe init */ -static int sl82c105_pre_reset(struct ata_port *ap, unsigned long deadline) +static int sl82c105_pre_reset(struct ata_link *link, unsigned long deadline) { static const struct pci_bits sl82c105_enable_bits[] = { { 0x40, 1, 0x01, 0x01 }, { 0x40, 1, 0x10, 0x10 } }; + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (ap->port_no && !pci_test_config_bits(pdev, &sl82c105_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } @@ -224,7 +225,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, .mode_filter = ata_pci_default_filter, @@ -253,9 +253,8 @@ static struct ata_port_operations sl82c105_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c index af21f443db6e..403eafcffe12 100644 --- a/drivers/ata/pata_triflex.c +++ b/drivers/ata/pata_triflex.c @@ -47,25 +47,26 @@ /** * triflex_prereset - probe begin - * @ap: ATA port + * @link: ATA link * @deadline: deadline jiffies for the operation * * Set up cable type and use generic probe init */ -static int triflex_prereset(struct ata_port *ap, unsigned long deadline) +static int triflex_prereset(struct ata_link *link, unsigned long deadline) { static const struct pci_bits triflex_enable_bits[] = { { 0x80, 1, 0x01, 0x01 }, { 0x80, 1, 0x02, 0x02 } }; + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (!pci_test_config_bits(pdev, &triflex_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } @@ -197,7 +198,6 @@ static struct scsi_host_template triflex_sht = { }; static struct ata_port_operations triflex_port_ops = { - .port_disable = ata_port_disable, .set_piomode = triflex_set_piomode, .mode_filter = ata_pci_default_filter, @@ -226,9 +226,8 @@ static struct ata_port_operations triflex_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index f143db4559e0..5d41b6612d7f 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -184,11 +184,15 @@ static int via_cable_detect(struct ata_port *ap) { two drives */ if (ata66 & (0x10100000 >> (16 * ap->port_no))) return ATA_CBL_PATA80; + /* Check with ACPI so we can spot BIOS reported SATA bridges */ + if (ata_acpi_cbl_80wire(ap)) + return ATA_CBL_PATA80; return ATA_CBL_PATA40; } -static int via_pre_reset(struct ata_port *ap, unsigned long deadline) +static int via_pre_reset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; const struct via_isa_bridge *config = ap->host->private_data; if (!(config->flags & VIA_NO_ENABLES)) { @@ -201,7 +205,7 @@ static int via_pre_reset(struct ata_port *ap, unsigned long deadline) return -ENOENT; } - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } @@ -344,7 +348,6 @@ static struct scsi_host_template via_sht = { }; static struct ata_port_operations via_port_ops = { - .port_disable = ata_port_disable, .set_piomode = via_set_piomode, .set_dmamode = via_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -374,13 +377,11 @@ static struct ata_port_operations via_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations via_port_ops_noirq = { - .port_disable = ata_port_disable, .set_piomode = via_set_piomode, .set_dmamode = via_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -410,9 +411,8 @@ static struct ata_port_operations via_port_ops_noirq = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c index 83abfeca4057..549cbbe9fd07 100644 --- a/drivers/ata/pata_winbond.c +++ b/drivers/ata/pata_winbond.c @@ -94,7 +94,7 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev) static void winbond_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data) { - struct ata_port *ap = adev->ap; + struct ata_port *ap = adev->link->ap; int slop = buflen & 3; if (ata_id_has_dword_io(adev->id)) { @@ -138,7 +138,6 @@ static struct scsi_host_template winbond_sht = { }; static struct ata_port_operations winbond_port_ops = { - .port_disable = ata_port_disable, .set_piomode = winbond_set_piomode, .tf_load = ata_tf_load, @@ -160,9 +159,8 @@ static struct ata_port_operations winbond_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** @@ -199,6 +197,7 @@ static __init int winbond_init_one(unsigned long port) for (i = 0; i < 2 ; i ++) { unsigned long cmd_port = 0x1F0 - (0x80 * i); + unsigned long ctl_port = cmd_port + 0x206; struct ata_host *host; struct ata_port *ap; void __iomem *cmd_addr, *ctl_addr; @@ -214,14 +213,16 @@ static __init int winbond_init_one(unsigned long port) host = ata_host_alloc(&pdev->dev, 1); if (!host) goto err_unregister; + ap = host->ports[0]; rc = -ENOMEM; cmd_addr = devm_ioport_map(&pdev->dev, cmd_port, 8); - ctl_addr = devm_ioport_map(&pdev->dev, cmd_port + 0x0206, 1); + ctl_addr = devm_ioport_map(&pdev->dev, ctl_port, 1); if (!cmd_addr || !ctl_addr) goto err_unregister; - ap = host->ports[0]; + ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", cmd_port, ctl_port); + ap->ops = &winbond_port_ops; ap->pio_mask = 0x1F; ap->flags |= ATA_FLAG_SLAVE_POSS; diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index 5c79271401af..8d1b03d5bcb1 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c @@ -92,6 +92,8 @@ enum { /* CPB bits */ cDONE = (1 << 0), + cATERR = (1 << 3), + cVLD = (1 << 0), cDAT = (1 << 2), cIEN = (1 << 3), @@ -131,14 +133,15 @@ static int adma_ata_init_one (struct pci_dev *pdev, static int adma_port_start(struct ata_port *ap); static void adma_host_stop(struct ata_host *host); static void adma_port_stop(struct ata_port *ap); -static void adma_phy_reset(struct ata_port *ap); static void adma_qc_prep(struct ata_queued_cmd *qc); static unsigned int adma_qc_issue(struct ata_queued_cmd *qc); static int adma_check_atapi_dma(struct ata_queued_cmd *qc); static void adma_bmdma_stop(struct ata_queued_cmd *qc); static u8 adma_bmdma_status(struct ata_port *ap); static void adma_irq_clear(struct ata_port *ap); -static void adma_eng_timeout(struct ata_port *ap); +static void adma_freeze(struct ata_port *ap); +static void adma_thaw(struct ata_port *ap); +static void adma_error_handler(struct ata_port *ap); static struct scsi_host_template adma_ata_sht = { .module = THIS_MODULE, @@ -159,21 +162,20 @@ static struct scsi_host_template adma_ata_sht = { }; static const struct ata_port_operations adma_ata_ops = { - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .exec_command = ata_exec_command, .check_status = ata_check_status, .dev_select = ata_std_dev_select, - .phy_reset = adma_phy_reset, .check_atapi_dma = adma_check_atapi_dma, .data_xfer = ata_data_xfer, .qc_prep = adma_qc_prep, .qc_issue = adma_qc_issue, - .eng_timeout = adma_eng_timeout, + .freeze = adma_freeze, + .thaw = adma_thaw, + .error_handler = adma_error_handler, .irq_clear = adma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = adma_port_start, .port_stop = adma_port_stop, .host_stop = adma_host_stop, @@ -184,7 +186,7 @@ static const struct ata_port_operations adma_ata_ops = { static struct ata_port_info adma_port_info[] = { /* board_1841_idx */ { - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING, .pio_mask = 0x10, /* pio4 */ @@ -273,24 +275,42 @@ static inline void adma_enter_reg_mode(struct ata_port *ap) readb(chan + ADMA_STATUS); /* flush */ } -static void adma_phy_reset(struct ata_port *ap) +static void adma_freeze(struct ata_port *ap) { - struct adma_port_priv *pp = ap->private_data; + void __iomem *chan = ADMA_PORT_REGS(ap); + + /* mask/clear ATA interrupts */ + writeb(ATA_NIEN, ap->ioaddr.ctl_addr); + ata_check_status(ap); - pp->state = adma_state_idle; + /* reset ADMA to idle state */ + writew(aPIOMD4 | aNIEN | aRSTADM, chan + ADMA_CONTROL); + udelay(2); + writew(aPIOMD4 | aNIEN, chan + ADMA_CONTROL); + udelay(2); +} + +static void adma_thaw(struct ata_port *ap) +{ adma_reinit_engine(ap); - ata_port_probe(ap); - ata_bus_reset(ap); } -static void adma_eng_timeout(struct ata_port *ap) +static int adma_prereset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct adma_port_priv *pp = ap->private_data; if (pp->state != adma_state_idle) /* healthy paranoia */ pp->state = adma_state_mmio; adma_reinit_engine(ap); - ata_eng_timeout(ap); + + return ata_std_prereset(link, deadline); +} + +static void adma_error_handler(struct ata_port *ap) +{ + ata_do_eh(ap, adma_prereset, ata_std_softreset, NULL, + ata_std_postreset); } static int adma_fill_sg(struct ata_queued_cmd *qc) @@ -464,14 +484,33 @@ static inline unsigned int adma_intr_pkt(struct ata_host *host) pp = ap->private_data; if (!pp || pp->state != adma_state_pkt) continue; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { - if ((status & (aPERR | aPSD | aUIRQ))) + if (status & aPERR) + qc->err_mask |= AC_ERR_HOST_BUS; + else if ((status & (aPSD | aUIRQ))) qc->err_mask |= AC_ERR_OTHER; + + if (pp->pkt[0] & cATERR) + qc->err_mask |= AC_ERR_DEV; else if (pp->pkt[0] != cDONE) qc->err_mask |= AC_ERR_OTHER; - ata_qc_complete(qc); + if (!qc->err_mask) + ata_qc_complete(qc); + else { + struct ata_eh_info *ehi = &ap->link.eh_info; + ata_ehi_clear_desc(ehi); + ata_ehi_push_desc(ehi, + "ADMA-status 0x%02X", status); + ata_ehi_push_desc(ehi, + "pkt[0] 0x%02X", pp->pkt[0]); + + if (qc->err_mask == AC_ERR_DEV) + ata_port_abort(ap); + else + ata_port_freeze(ap); + } } } return handled; @@ -489,7 +528,7 @@ static inline unsigned int adma_intr_mmio(struct ata_host *host) struct adma_port_priv *pp = ap->private_data; if (!pp || pp->state != adma_state_mmio) continue; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { /* check main status, clearing INTRQ */ @@ -502,7 +541,20 @@ static inline unsigned int adma_intr_mmio(struct ata_host *host) /* complete taskfile transaction */ pp->state = adma_state_idle; qc->err_mask |= ac_err_mask(status); - ata_qc_complete(qc); + if (!qc->err_mask) + ata_qc_complete(qc); + else { + struct ata_eh_info *ehi = + &ap->link.eh_info; + ata_ehi_clear_desc(ehi); + ata_ehi_push_desc(ehi, + "status 0x%02X", status); + + if (qc->err_mask == AC_ERR_DEV) + ata_port_abort(ap); + else + ata_port_freeze(ap); + } handled = 1; } } @@ -652,9 +704,16 @@ static int adma_ata_init_one(struct pci_dev *pdev, if (rc) return rc; - for (port_no = 0; port_no < ADMA_PORTS; ++port_no) - adma_ata_setup_port(&host->ports[port_no]->ioaddr, - ADMA_ATA_REGS(mmio_base, port_no)); + for (port_no = 0; port_no < ADMA_PORTS; ++port_no) { + struct ata_port *ap = host->ports[port_no]; + void __iomem *port_base = ADMA_ATA_REGS(mmio_base, port_no); + unsigned int offset = port_base - mmio_base; + + adma_ata_setup_port(&ap->ioaddr, port_base); + + ata_port_pbar_desc(ap, ADMA_MMIO_BAR, -1, "mmio"); + ata_port_pbar_desc(ap, ADMA_MMIO_BAR, offset, "port"); + } /* initialize adapter */ adma_host_init(host, board_idx); diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index fdbed8ecdfc2..08595f34b3e8 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -285,7 +285,7 @@ static void inic_irq_clear(struct ata_port *ap) static void inic_host_intr(struct ata_port *ap) { void __iomem *port_base = inic_port_base(ap); - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; u8 irq_stat; /* fetch and clear irq */ @@ -293,7 +293,8 @@ static void inic_host_intr(struct ata_port *ap) writeb(irq_stat, port_base + PORT_IRQ_STAT); if (likely(!(irq_stat & PIRQ_ERR))) { - struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); + struct ata_queued_cmd *qc = + ata_qc_from_tag(ap, ap->link.active_tag); if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) { ata_chk_status(ap); /* clear ATA interrupt */ @@ -416,12 +417,13 @@ static void inic_thaw(struct ata_port *ap) * SRST and SControl hardreset don't give valid signature on this * controller. Only controller specific hardreset mechanism works. */ -static int inic_hardreset(struct ata_port *ap, unsigned int *class, +static int inic_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { + struct ata_port *ap = link->ap; void __iomem *port_base = inic_port_base(ap); void __iomem *idma_ctl = port_base + PORT_IDMA_CTL; - const unsigned long *timing = sata_ehc_deb_timing(&ap->eh_context); + const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); u16 val; int rc; @@ -434,15 +436,15 @@ static int inic_hardreset(struct ata_port *ap, unsigned int *class, msleep(1); writew(val & ~IDMA_CTL_RST_ATA, idma_ctl); - rc = sata_phy_resume(ap, timing, deadline); + rc = sata_link_resume(link, timing, deadline); if (rc) { - ata_port_printk(ap, KERN_WARNING, "failed to resume " + ata_link_printk(link, KERN_WARNING, "failed to resume " "link after reset (errno=%d)\n", rc); return rc; } *class = ATA_DEV_NONE; - if (ata_port_online(ap)) { + if (ata_link_online(link)) { struct ata_taskfile tf; /* wait a while before checking status */ @@ -451,7 +453,7 @@ static int inic_hardreset(struct ata_port *ap, unsigned int *class, rc = ata_wait_ready(ap, deadline); /* link occupied, -ENODEV too is an error */ if (rc) { - ata_port_printk(ap, KERN_WARNING, "device not ready " + ata_link_printk(link, KERN_WARNING, "device not ready " "after hardreset (errno=%d)\n", rc); return rc; } @@ -550,7 +552,6 @@ static int inic_port_start(struct ata_port *ap) } static struct ata_port_operations inic_port_ops = { - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -567,7 +568,6 @@ static struct ata_port_operations inic_port_ops = { .irq_clear = inic_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .qc_prep = ata_qc_prep, .qc_issue = inic_qc_issue, @@ -693,16 +693,24 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) host->iomap = iomap = pcim_iomap_table(pdev); for (i = 0; i < NR_PORTS; i++) { - struct ata_ioports *port = &host->ports[i]->ioaddr; - void __iomem *port_base = iomap[MMIO_BAR] + i * PORT_SIZE; + struct ata_port *ap = host->ports[i]; + struct ata_ioports *port = &ap->ioaddr; + unsigned int offset = i * PORT_SIZE; port->cmd_addr = iomap[2 * i]; port->altstatus_addr = port->ctl_addr = (void __iomem *) ((unsigned long)iomap[2 * i + 1] | ATA_PCI_CTL_OFS); - port->scr_addr = port_base + PORT_SCR; + port->scr_addr = iomap[MMIO_BAR] + offset + PORT_SCR; ata_std_ports(port); + + ata_port_pbar_desc(ap, MMIO_BAR, -1, "mmio"); + ata_port_pbar_desc(ap, MMIO_BAR, offset, "port"); + ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx", + (unsigned long long)pci_resource_start(pdev, 2 * i), + (unsigned long long)pci_resource_start(pdev, (2 * i + 1)) | + ATA_PCI_CTL_OFS); } hpriv->cached_hctl = readw(iomap[MMIO_BAR] + HOST_CTL); diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index d9832e234e44..4df8311968e9 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -483,8 +483,6 @@ static struct scsi_host_template mv6_sht = { }; static const struct ata_port_operations mv5_ops = { - .port_disable = ata_port_disable, - .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -499,7 +497,6 @@ static const struct ata_port_operations mv5_ops = { .irq_clear = mv_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .error_handler = mv_error_handler, .post_internal_cmd = mv_post_int_cmd, @@ -514,8 +511,6 @@ static const struct ata_port_operations mv5_ops = { }; static const struct ata_port_operations mv6_ops = { - .port_disable = ata_port_disable, - .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -530,7 +525,6 @@ static const struct ata_port_operations mv6_ops = { .irq_clear = mv_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .error_handler = mv_error_handler, .post_internal_cmd = mv_post_int_cmd, @@ -545,8 +539,6 @@ static const struct ata_port_operations mv6_ops = { }; static const struct ata_port_operations mv_iie_ops = { - .port_disable = ata_port_disable, - .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -561,7 +553,6 @@ static const struct ata_port_operations mv_iie_ops = { .irq_clear = mv_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .error_handler = mv_error_handler, .post_internal_cmd = mv_post_int_cmd, @@ -1415,7 +1406,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc) struct mv_host_priv *hpriv = ap->host->private_data; unsigned int edma_enabled = (pp->pp_flags & MV_PP_FLAG_EDMA_EN); unsigned int action = 0, err_mask = 0; - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; ata_ehi_clear_desc(ehi); @@ -1423,8 +1414,8 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc) /* just a guess: do we need to do this? should we * expand this, and do it in all cases? */ - sata_scr_read(ap, SCR_ERROR, &serr); - sata_scr_write_flush(ap, SCR_ERROR, serr); + sata_scr_read(&ap->link, SCR_ERROR, &serr); + sata_scr_write_flush(&ap->link, SCR_ERROR, serr); } edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); @@ -1468,8 +1459,8 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc) } if (edma_err_cause & EDMA_ERR_SERR) { - sata_scr_read(ap, SCR_ERROR, &serr); - sata_scr_write_flush(ap, SCR_ERROR, serr); + sata_scr_read(&ap->link, SCR_ERROR, &serr); + sata_scr_write_flush(&ap->link, SCR_ERROR, serr); err_mask = AC_ERR_ATA_BUS; action |= ATA_EH_HARDRESET; } @@ -1508,7 +1499,7 @@ static void mv_intr_pio(struct ata_port *ap) return; /* get active ATA command */ - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (unlikely(!qc)) /* no active tag */ return; if (qc->tf.flags & ATA_TFLAG_POLLING) /* polling; we don't own qc */ @@ -1543,7 +1534,7 @@ static void mv_intr_edma(struct ata_port *ap) /* 50xx: get active ATA command */ if (IS_GEN_I(hpriv)) - tag = ap->active_tag; + tag = ap->link.active_tag; /* Gen II/IIE: get active ATA command via tag, to enable * support for queueing. this works transparently for @@ -1646,7 +1637,7 @@ static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc) if (unlikely(have_err_bits)) { struct ata_queued_cmd *qc; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (qc->tf.flags & ATA_TFLAG_POLLING)) continue; @@ -1687,15 +1678,15 @@ static void mv_pci_error(struct ata_host *host, void __iomem *mmio) for (i = 0; i < host->n_ports; i++) { ap = host->ports[i]; - if (!ata_port_offline(ap)) { - ehi = &ap->eh_info; + if (!ata_link_offline(&ap->link)) { + ehi = &ap->link.eh_info; ata_ehi_clear_desc(ehi); if (!printed++) ata_ehi_push_desc(ehi, "PCI err cause 0x%08x", err_cause); err_mask = AC_ERR_HOST_BUS; ehi->action = ATA_EH_HARDRESET; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc) qc->err_mask |= err_mask; else @@ -2198,14 +2189,14 @@ static void mv_phy_reset(struct ata_port *ap, unsigned int *class, /* Issue COMRESET via SControl */ comreset_retry: - sata_scr_write_flush(ap, SCR_CONTROL, 0x301); + sata_scr_write_flush(&ap->link, SCR_CONTROL, 0x301); msleep(1); - sata_scr_write_flush(ap, SCR_CONTROL, 0x300); + sata_scr_write_flush(&ap->link, SCR_CONTROL, 0x300); msleep(20); do { - sata_scr_read(ap, SCR_STATUS, &sstatus); + sata_scr_read(&ap->link, SCR_STATUS, &sstatus); if (((sstatus & 0x3) == 3) || ((sstatus & 0x3) == 0)) break; @@ -2230,7 +2221,7 @@ comreset_retry: } #endif - if (ata_port_offline(ap)) { + if (ata_link_offline(&ap->link)) { *class = ATA_DEV_NONE; return; } @@ -2257,7 +2248,7 @@ comreset_retry: */ /* finally, read device signature from TF registers */ - *class = ata_dev_try_classify(ap, 0, NULL); + *class = ata_dev_try_classify(ap->link.device, 1, NULL); writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); @@ -2266,10 +2257,11 @@ comreset_retry: VPRINTK("EXIT\n"); } -static int mv_prereset(struct ata_port *ap, unsigned long deadline) +static int mv_prereset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct mv_port_priv *pp = ap->private_data; - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_eh_context *ehc = &link->eh_context; int rc; rc = mv_stop_dma(ap); @@ -2285,7 +2277,7 @@ static int mv_prereset(struct ata_port *ap, unsigned long deadline) if (ehc->i.action & ATA_EH_HARDRESET) return 0; - if (ata_port_online(ap)) + if (ata_link_online(link)) rc = ata_wait_ready(ap, deadline); else rc = -ENODEV; @@ -2293,9 +2285,10 @@ static int mv_prereset(struct ata_port *ap, unsigned long deadline) return rc; } -static int mv_hardreset(struct ata_port *ap, unsigned int *class, +static int mv_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { + struct ata_port *ap = link->ap; struct mv_host_priv *hpriv = ap->host->private_data; void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR]; @@ -2308,16 +2301,17 @@ static int mv_hardreset(struct ata_port *ap, unsigned int *class, return 0; } -static void mv_postreset(struct ata_port *ap, unsigned int *classes) +static void mv_postreset(struct ata_link *link, unsigned int *classes) { + struct ata_port *ap = link->ap; u32 serr; /* print link status */ - sata_print_link_status(ap); + sata_print_link_status(link); /* clear SError */ - sata_scr_read(ap, SCR_ERROR, &serr); - sata_scr_write_flush(ap, SCR_ERROR, serr); + sata_scr_read(link, SCR_ERROR, &serr); + sata_scr_write_flush(link, SCR_ERROR, serr); /* bail out if no device is present */ if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) { @@ -2590,8 +2584,14 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx) } for (port = 0; port < host->n_ports; port++) { + struct ata_port *ap = host->ports[port]; void __iomem *port_mmio = mv_port_base(mmio, port); - mv_port_init(&host->ports[port]->ioaddr, port_mmio); + unsigned int offset = port_mmio - mmio; + + mv_port_init(&ap->ioaddr, port_mmio); + + ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio"); + ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port"); } for (hc = 0; hc < n_hc; hc++) { diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 40dc73139858..240a8920d0bd 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -169,6 +169,35 @@ enum { NV_ADMA_PORT_REGISTER_MODE = (1 << 0), NV_ADMA_ATAPI_SETUP_COMPLETE = (1 << 1), + /* MCP55 reg offset */ + NV_CTL_MCP55 = 0x400, + NV_INT_STATUS_MCP55 = 0x440, + NV_INT_ENABLE_MCP55 = 0x444, + NV_NCQ_REG_MCP55 = 0x448, + + /* MCP55 */ + NV_INT_ALL_MCP55 = 0xffff, + NV_INT_PORT_SHIFT_MCP55 = 16, /* each port occupies 16 bits */ + NV_INT_MASK_MCP55 = NV_INT_ALL_MCP55 & 0xfffd, + + /* SWNCQ ENABLE BITS*/ + NV_CTL_PRI_SWNCQ = 0x02, + NV_CTL_SEC_SWNCQ = 0x04, + + /* SW NCQ status bits*/ + NV_SWNCQ_IRQ_DEV = (1 << 0), + NV_SWNCQ_IRQ_PM = (1 << 1), + NV_SWNCQ_IRQ_ADDED = (1 << 2), + NV_SWNCQ_IRQ_REMOVED = (1 << 3), + + NV_SWNCQ_IRQ_BACKOUT = (1 << 4), + NV_SWNCQ_IRQ_SDBFIS = (1 << 5), + NV_SWNCQ_IRQ_DHREGFIS = (1 << 6), + NV_SWNCQ_IRQ_DMASETUP = (1 << 7), + + NV_SWNCQ_IRQ_HOTPLUG = NV_SWNCQ_IRQ_ADDED | + NV_SWNCQ_IRQ_REMOVED, + }; /* ADMA Physical Region Descriptor - one SG segment */ @@ -226,6 +255,42 @@ struct nv_host_priv { unsigned long type; }; +struct defer_queue { + u32 defer_bits; + unsigned int head; + unsigned int tail; + unsigned int tag[ATA_MAX_QUEUE]; +}; + +enum ncq_saw_flag_list { + ncq_saw_d2h = (1U << 0), + ncq_saw_dmas = (1U << 1), + ncq_saw_sdb = (1U << 2), + ncq_saw_backout = (1U << 3), +}; + +struct nv_swncq_port_priv { + struct ata_prd *prd; /* our SG list */ + dma_addr_t prd_dma; /* and its DMA mapping */ + void __iomem *sactive_block; + void __iomem *irq_block; + void __iomem *tag_block; + u32 qc_active; + + unsigned int last_issue_tag; + + /* fifo circular queue to store deferral command */ + struct defer_queue defer_queue; + + /* for NCQ interrupt analysis */ + u32 dhfis_bits; + u32 dmafis_bits; + u32 sdbfis_bits; + + unsigned int ncq_flags; +}; + + #define NV_ADMA_CHECK_INTR(GCTL, PORT) ((GCTL) & ( 1 << (19 + (12 * (PORT))))) static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); @@ -263,13 +328,29 @@ static void nv_adma_host_stop(struct ata_host *host); static void nv_adma_post_internal_cmd(struct ata_queued_cmd *qc); static void nv_adma_tf_read(struct ata_port *ap, struct ata_taskfile *tf); +static void nv_mcp55_thaw(struct ata_port *ap); +static void nv_mcp55_freeze(struct ata_port *ap); +static void nv_swncq_error_handler(struct ata_port *ap); +static int nv_swncq_slave_config(struct scsi_device *sdev); +static int nv_swncq_port_start(struct ata_port *ap); +static void nv_swncq_qc_prep(struct ata_queued_cmd *qc); +static void nv_swncq_fill_sg(struct ata_queued_cmd *qc); +static unsigned int nv_swncq_qc_issue(struct ata_queued_cmd *qc); +static void nv_swncq_irq_clear(struct ata_port *ap, u16 fis); +static irqreturn_t nv_swncq_interrupt(int irq, void *dev_instance); +#ifdef CONFIG_PM +static int nv_swncq_port_suspend(struct ata_port *ap, pm_message_t mesg); +static int nv_swncq_port_resume(struct ata_port *ap); +#endif + enum nv_host_type { GENERIC, NFORCE2, NFORCE3 = NFORCE2, /* NF2 == NF3 as far as sata_nv is concerned */ CK804, - ADMA + ADMA, + SWNCQ, }; static const struct pci_device_id nv_pci_tbl[] = { @@ -280,13 +361,13 @@ static const struct pci_device_id nv_pci_tbl[] = { { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2), CK804 }, { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA), CK804 }, { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2), CK804 }, - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA), GENERIC }, - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2), GENERIC }, - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA), GENERIC }, - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2), GENERIC }, - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA), GENERIC }, - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2), GENERIC }, - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3), GENERIC }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA), SWNCQ }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2), SWNCQ }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA), SWNCQ }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2), SWNCQ }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA), SWNCQ }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2), SWNCQ }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3), SWNCQ }, { } /* terminate list */ }; @@ -339,8 +420,26 @@ static struct scsi_host_template nv_adma_sht = { .bios_param = ata_std_bios_param, }; +static struct scsi_host_template nv_swncq_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .change_queue_depth = ata_scsi_change_queue_depth, + .can_queue = ATA_MAX_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 = nv_swncq_slave_config, + .slave_destroy = ata_scsi_slave_destroy, + .bios_param = ata_std_bios_param, +}; + static const struct ata_port_operations nv_generic_ops = { - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .exec_command = ata_exec_command, @@ -359,14 +458,12 @@ static const struct ata_port_operations nv_generic_ops = { .data_xfer = ata_data_xfer, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = nv_scr_read, .scr_write = nv_scr_write, .port_start = ata_port_start, }; static const struct ata_port_operations nv_nf2_ops = { - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .exec_command = ata_exec_command, @@ -385,14 +482,12 @@ static const struct ata_port_operations nv_nf2_ops = { .data_xfer = ata_data_xfer, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = nv_scr_read, .scr_write = nv_scr_write, .port_start = ata_port_start, }; static const struct ata_port_operations nv_ck804_ops = { - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .exec_command = ata_exec_command, @@ -411,7 +506,6 @@ static const struct ata_port_operations nv_ck804_ops = { .data_xfer = ata_data_xfer, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = nv_scr_read, .scr_write = nv_scr_write, .port_start = ata_port_start, @@ -419,7 +513,6 @@ static const struct ata_port_operations nv_ck804_ops = { }; static const struct ata_port_operations nv_adma_ops = { - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = nv_adma_tf_read, .check_atapi_dma = nv_adma_check_atapi_dma, @@ -430,6 +523,7 @@ static const struct ata_port_operations nv_adma_ops = { .bmdma_start = ata_bmdma_start, .bmdma_stop = ata_bmdma_stop, .bmdma_status = ata_bmdma_status, + .qc_defer = ata_std_qc_defer, .qc_prep = nv_adma_qc_prep, .qc_issue = nv_adma_qc_issue, .freeze = nv_adma_freeze, @@ -439,7 +533,6 @@ static const struct ata_port_operations nv_adma_ops = { .data_xfer = ata_data_xfer, .irq_clear = nv_adma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = nv_scr_read, .scr_write = nv_scr_write, .port_start = nv_adma_port_start, @@ -451,12 +544,41 @@ static const struct ata_port_operations nv_adma_ops = { .host_stop = nv_adma_host_stop, }; +static const struct ata_port_operations nv_swncq_ops = { + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .exec_command = ata_exec_command, + .check_status = ata_check_status, + .dev_select = ata_std_dev_select, + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, + .bmdma_stop = ata_bmdma_stop, + .bmdma_status = ata_bmdma_status, + .qc_defer = ata_std_qc_defer, + .qc_prep = nv_swncq_qc_prep, + .qc_issue = nv_swncq_qc_issue, + .freeze = nv_mcp55_freeze, + .thaw = nv_mcp55_thaw, + .error_handler = nv_swncq_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + .data_xfer = ata_data_xfer, + .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .scr_read = nv_scr_read, + .scr_write = nv_scr_write, +#ifdef CONFIG_PM + .port_suspend = nv_swncq_port_suspend, + .port_resume = nv_swncq_port_resume, +#endif + .port_start = nv_swncq_port_start, +}; + static const struct ata_port_info nv_port_info[] = { /* generic */ { .sht = &nv_sht, - .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_HRST_TO_RESUME, + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, + .link_flags = ATA_LFLAG_HRST_TO_RESUME, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, @@ -466,8 +588,8 @@ static const struct ata_port_info nv_port_info[] = { /* nforce2/3 */ { .sht = &nv_sht, - .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_HRST_TO_RESUME, + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, + .link_flags = ATA_LFLAG_HRST_TO_RESUME, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, @@ -477,8 +599,8 @@ static const struct ata_port_info nv_port_info[] = { /* ck804 */ { .sht = &nv_sht, - .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_HRST_TO_RESUME, + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, + .link_flags = ATA_LFLAG_HRST_TO_RESUME, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, @@ -489,14 +611,26 @@ static const struct ata_port_info nv_port_info[] = { { .sht = &nv_adma_sht, .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_HRST_TO_RESUME | ATA_FLAG_MMIO | ATA_FLAG_NCQ, + .link_flags = ATA_LFLAG_HRST_TO_RESUME, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, .port_ops = &nv_adma_ops, .irq_handler = nv_adma_interrupt, }, + /* SWNCQ */ + { + .sht = &nv_swncq_sht, + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_NCQ, + .link_flags = ATA_LFLAG_HRST_TO_RESUME, + .pio_mask = NV_PIO_MASK, + .mwdma_mask = NV_MWDMA_MASK, + .udma_mask = NV_UDMA_MASK, + .port_ops = &nv_swncq_ops, + .irq_handler = nv_swncq_interrupt, + }, }; MODULE_AUTHOR("NVIDIA"); @@ -506,6 +640,7 @@ MODULE_DEVICE_TABLE(pci, nv_pci_tbl); MODULE_VERSION(DRV_VERSION); static int adma_enabled = 1; +static int swncq_enabled; static void nv_adma_register_mode(struct ata_port *ap) { @@ -594,7 +729,7 @@ static int nv_adma_slave_config(struct scsi_device *sdev) /* Not a proper libata device, ignore */ return rc; - if (ap->device[sdev->id].class == ATA_DEV_ATAPI) { + if (ap->link.device[sdev->id].class == ATA_DEV_ATAPI) { /* * NVIDIA reports that ADMA mode does not support ATAPI commands. * Therefore ATAPI commands are sent through the legacy interface. @@ -711,7 +846,7 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err) flags & (NV_CPB_RESP_ATA_ERR | NV_CPB_RESP_CMD_ERR | NV_CPB_RESP_CPB_ERR)))) { - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; int freeze = 0; ata_ehi_clear_desc(ehi); @@ -747,7 +882,7 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err) DPRINTK("Completing qc from tag %d\n",cpb_num); ata_qc_complete(qc); } else { - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; /* Notifier bits set without a command may indicate the drive is misbehaving. Raise host state machine violation on this condition. */ @@ -764,7 +899,7 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err) static int nv_host_intr(struct ata_port *ap, u8 irq_stat) { - struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); + struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag); /* freeze if hotplugged */ if (unlikely(irq_stat & (NV_INT_ADDED | NV_INT_REMOVED))) { @@ -817,7 +952,7 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) { u8 irq_stat = readb(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804) >> (NV_INT_PORT_SHIFT * i); - if(ata_tag_valid(ap->active_tag)) + if(ata_tag_valid(ap->link.active_tag)) /** NV_INT_DEV indication seems unreliable at times at least in ADMA mode. Force it on always when a command is active, to prevent losing interrupts. */ @@ -852,7 +987,7 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) NV_ADMA_STAT_HOTUNPLUG | NV_ADMA_STAT_TIMEOUT | NV_ADMA_STAT_SERROR))) { - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; ata_ehi_clear_desc(ehi); __ata_ehi_push_desc(ehi, "ADMA status 0x%08x: ", status ); @@ -879,10 +1014,10 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) u32 check_commands; int pos, error = 0; - if(ata_tag_valid(ap->active_tag)) - check_commands = 1 << ap->active_tag; + if(ata_tag_valid(ap->link.active_tag)) + check_commands = 1 << ap->link.active_tag; else - check_commands = ap->sactive; + check_commands = ap->link.sactive; /** Check CPBs for completed commands */ while ((pos = ffs(check_commands)) && !error) { @@ -1333,7 +1468,7 @@ static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance) !(ap->flags & ATA_FLAG_DISABLED)) { struct ata_queued_cmd *qc; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) handled += ata_host_intr(ap, qc); else @@ -1459,7 +1594,35 @@ static void nv_ck804_thaw(struct ata_port *ap) writeb(mask, mmio_base + NV_INT_ENABLE_CK804); } -static int nv_hardreset(struct ata_port *ap, unsigned int *class, +static void nv_mcp55_freeze(struct ata_port *ap) +{ + void __iomem *mmio_base = ap->host->iomap[NV_MMIO_BAR]; + int shift = ap->port_no * NV_INT_PORT_SHIFT_MCP55; + u32 mask; + + writel(NV_INT_ALL_MCP55 << shift, mmio_base + NV_INT_STATUS_MCP55); + + mask = readl(mmio_base + NV_INT_ENABLE_MCP55); + mask &= ~(NV_INT_ALL_MCP55 << shift); + writel(mask, mmio_base + NV_INT_ENABLE_MCP55); + ata_bmdma_freeze(ap); +} + +static void nv_mcp55_thaw(struct ata_port *ap) +{ + void __iomem *mmio_base = ap->host->iomap[NV_MMIO_BAR]; + int shift = ap->port_no * NV_INT_PORT_SHIFT_MCP55; + u32 mask; + + writel(NV_INT_ALL_MCP55 << shift, mmio_base + NV_INT_STATUS_MCP55); + + mask = readl(mmio_base + NV_INT_ENABLE_MCP55); + mask |= (NV_INT_MASK_MCP55 << shift); + writel(mask, mmio_base + NV_INT_ENABLE_MCP55); + ata_bmdma_thaw(ap); +} + +static int nv_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { unsigned int dummy; @@ -1468,7 +1631,7 @@ static int nv_hardreset(struct ata_port *ap, unsigned int *class, * some controllers. Don't classify on hardreset. For more * info, see http://bugme.osdl.org/show_bug.cgi?id=3352 */ - return sata_std_hardreset(ap, &dummy, deadline); + return sata_std_hardreset(link, &dummy, deadline); } static void nv_error_handler(struct ata_port *ap) @@ -1485,7 +1648,7 @@ static void nv_adma_error_handler(struct ata_port *ap) int i; u16 tmp; - if(ata_tag_valid(ap->active_tag) || ap->sactive) { + if(ata_tag_valid(ap->link.active_tag) || ap->link.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); @@ -1501,8 +1664,8 @@ static void nv_adma_error_handler(struct ata_port *ap) 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) ) + if( (ata_tag_valid(ap->link.active_tag) && i == ap->link.active_tag) || + ap->link.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); @@ -1532,6 +1695,663 @@ static void nv_adma_error_handler(struct ata_port *ap) nv_hardreset, ata_std_postreset); } +static void nv_swncq_qc_to_dq(struct ata_port *ap, struct ata_queued_cmd *qc) +{ + struct nv_swncq_port_priv *pp = ap->private_data; + struct defer_queue *dq = &pp->defer_queue; + + /* queue is full */ + WARN_ON(dq->tail - dq->head == ATA_MAX_QUEUE); + dq->defer_bits |= (1 << qc->tag); + dq->tag[dq->tail++ & (ATA_MAX_QUEUE - 1)] = qc->tag; +} + +static struct ata_queued_cmd *nv_swncq_qc_from_dq(struct ata_port *ap) +{ + struct nv_swncq_port_priv *pp = ap->private_data; + struct defer_queue *dq = &pp->defer_queue; + unsigned int tag; + + if (dq->head == dq->tail) /* null queue */ + return NULL; + + tag = dq->tag[dq->head & (ATA_MAX_QUEUE - 1)]; + dq->tag[dq->head++ & (ATA_MAX_QUEUE - 1)] = ATA_TAG_POISON; + WARN_ON(!(dq->defer_bits & (1 << tag))); + dq->defer_bits &= ~(1 << tag); + + return ata_qc_from_tag(ap, tag); +} + +static void nv_swncq_fis_reinit(struct ata_port *ap) +{ + struct nv_swncq_port_priv *pp = ap->private_data; + + pp->dhfis_bits = 0; + pp->dmafis_bits = 0; + pp->sdbfis_bits = 0; + pp->ncq_flags = 0; +} + +static void nv_swncq_pp_reinit(struct ata_port *ap) +{ + struct nv_swncq_port_priv *pp = ap->private_data; + struct defer_queue *dq = &pp->defer_queue; + + dq->head = 0; + dq->tail = 0; + dq->defer_bits = 0; + pp->qc_active = 0; + pp->last_issue_tag = ATA_TAG_POISON; + nv_swncq_fis_reinit(ap); +} + +static void nv_swncq_irq_clear(struct ata_port *ap, u16 fis) +{ + struct nv_swncq_port_priv *pp = ap->private_data; + + writew(fis, pp->irq_block); +} + +static void __ata_bmdma_stop(struct ata_port *ap) +{ + struct ata_queued_cmd qc; + + qc.ap = ap; + ata_bmdma_stop(&qc); +} + +static void nv_swncq_ncq_stop(struct ata_port *ap) +{ + struct nv_swncq_port_priv *pp = ap->private_data; + unsigned int i; + u32 sactive; + u32 done_mask; + + ata_port_printk(ap, KERN_ERR, + "EH in SWNCQ mode,QC:qc_active 0x%X sactive 0x%X\n", + ap->qc_active, ap->link.sactive); + ata_port_printk(ap, KERN_ERR, + "SWNCQ:qc_active 0x%X defer_bits 0x%X last_issue_tag 0x%x\n " + "dhfis 0x%X dmafis 0x%X sdbfis 0x%X\n", + pp->qc_active, pp->defer_queue.defer_bits, pp->last_issue_tag, + pp->dhfis_bits, pp->dmafis_bits, pp->sdbfis_bits); + + ata_port_printk(ap, KERN_ERR, "ATA_REG 0x%X ERR_REG 0x%X\n", + ap->ops->check_status(ap), + ioread8(ap->ioaddr.error_addr)); + + sactive = readl(pp->sactive_block); + done_mask = pp->qc_active ^ sactive; + + ata_port_printk(ap, KERN_ERR, "tag : dhfis dmafis sdbfis sacitve\n"); + for (i = 0; i < ATA_MAX_QUEUE; i++) { + u8 err = 0; + if (pp->qc_active & (1 << i)) + err = 0; + else if (done_mask & (1 << i)) + err = 1; + else + continue; + + ata_port_printk(ap, KERN_ERR, + "tag 0x%x: %01x %01x %01x %01x %s\n", i, + (pp->dhfis_bits >> i) & 0x1, + (pp->dmafis_bits >> i) & 0x1, + (pp->sdbfis_bits >> i) & 0x1, + (sactive >> i) & 0x1, + (err ? "error! tag doesn't exit" : " ")); + } + + nv_swncq_pp_reinit(ap); + ap->ops->irq_clear(ap); + __ata_bmdma_stop(ap); + nv_swncq_irq_clear(ap, 0xffff); +} + +static void nv_swncq_error_handler(struct ata_port *ap) +{ + struct ata_eh_context *ehc = &ap->link.eh_context; + + if (ap->link.sactive) { + nv_swncq_ncq_stop(ap); + ehc->i.action |= ATA_EH_HARDRESET; + } + + ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, + nv_hardreset, ata_std_postreset); +} + +#ifdef CONFIG_PM +static int nv_swncq_port_suspend(struct ata_port *ap, pm_message_t mesg) +{ + void __iomem *mmio = ap->host->iomap[NV_MMIO_BAR]; + u32 tmp; + + /* clear irq */ + writel(~0, mmio + NV_INT_STATUS_MCP55); + + /* disable irq */ + writel(0, mmio + NV_INT_ENABLE_MCP55); + + /* disable swncq */ + tmp = readl(mmio + NV_CTL_MCP55); + tmp &= ~(NV_CTL_PRI_SWNCQ | NV_CTL_SEC_SWNCQ); + writel(tmp, mmio + NV_CTL_MCP55); + + return 0; +} + +static int nv_swncq_port_resume(struct ata_port *ap) +{ + void __iomem *mmio = ap->host->iomap[NV_MMIO_BAR]; + u32 tmp; + + /* clear irq */ + writel(~0, mmio + NV_INT_STATUS_MCP55); + + /* enable irq */ + writel(0x00fd00fd, mmio + NV_INT_ENABLE_MCP55); + + /* enable swncq */ + tmp = readl(mmio + NV_CTL_MCP55); + writel(tmp | NV_CTL_PRI_SWNCQ | NV_CTL_SEC_SWNCQ, mmio + NV_CTL_MCP55); + + return 0; +} +#endif + +static void nv_swncq_host_init(struct ata_host *host) +{ + u32 tmp; + void __iomem *mmio = host->iomap[NV_MMIO_BAR]; + struct pci_dev *pdev = to_pci_dev(host->dev); + u8 regval; + + /* disable ECO 398 */ + pci_read_config_byte(pdev, 0x7f, ®val); + regval &= ~(1 << 7); + pci_write_config_byte(pdev, 0x7f, regval); + + /* enable swncq */ + tmp = readl(mmio + NV_CTL_MCP55); + VPRINTK("HOST_CTL:0x%X\n", tmp); + writel(tmp | NV_CTL_PRI_SWNCQ | NV_CTL_SEC_SWNCQ, mmio + NV_CTL_MCP55); + + /* enable irq intr */ + tmp = readl(mmio + NV_INT_ENABLE_MCP55); + VPRINTK("HOST_ENABLE:0x%X\n", tmp); + writel(tmp | 0x00fd00fd, mmio + NV_INT_ENABLE_MCP55); + + /* clear port irq */ + writel(~0x0, mmio + NV_INT_STATUS_MCP55); +} + +static int nv_swncq_slave_config(struct scsi_device *sdev) +{ + struct ata_port *ap = ata_shost_to_port(sdev->host); + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + struct ata_device *dev; + int rc; + u8 rev; + u8 check_maxtor = 0; + unsigned char model_num[ATA_ID_PROD_LEN + 1]; + + rc = ata_scsi_slave_config(sdev); + if (sdev->id >= ATA_MAX_DEVICES || sdev->channel || sdev->lun) + /* Not a proper libata device, ignore */ + return rc; + + dev = &ap->link.device[sdev->id]; + if (!(ap->flags & ATA_FLAG_NCQ) || dev->class == ATA_DEV_ATAPI) + return rc; + + /* if MCP51 and Maxtor, then disable ncq */ + if (pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA || + pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2) + check_maxtor = 1; + + /* if MCP55 and rev <= a2 and Maxtor, then disable ncq */ + if (pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA || + pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2) { + pci_read_config_byte(pdev, 0x8, &rev); + if (rev <= 0xa2) + check_maxtor = 1; + } + + if (!check_maxtor) + return rc; + + ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num)); + + if (strncmp(model_num, "Maxtor", 6) == 0) { + ata_scsi_change_queue_depth(sdev, 1); + ata_dev_printk(dev, KERN_NOTICE, + "Disabling SWNCQ mode (depth %x)\n", sdev->queue_depth); + } + + return rc; +} + +static int nv_swncq_port_start(struct ata_port *ap) +{ + struct device *dev = ap->host->dev; + void __iomem *mmio = ap->host->iomap[NV_MMIO_BAR]; + struct nv_swncq_port_priv *pp; + int rc; + + rc = ata_port_start(ap); + if (rc) + return rc; + + pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); + if (!pp) + return -ENOMEM; + + pp->prd = dmam_alloc_coherent(dev, ATA_PRD_TBL_SZ * ATA_MAX_QUEUE, + &pp->prd_dma, GFP_KERNEL); + if (!pp->prd) + return -ENOMEM; + memset(pp->prd, 0, ATA_PRD_TBL_SZ * ATA_MAX_QUEUE); + + ap->private_data = pp; + pp->sactive_block = ap->ioaddr.scr_addr + 4 * SCR_ACTIVE; + pp->irq_block = mmio + NV_INT_STATUS_MCP55 + ap->port_no * 2; + pp->tag_block = mmio + NV_NCQ_REG_MCP55 + ap->port_no * 2; + + return 0; +} + +static void nv_swncq_qc_prep(struct ata_queued_cmd *qc) +{ + if (qc->tf.protocol != ATA_PROT_NCQ) { + ata_qc_prep(qc); + return; + } + + if (!(qc->flags & ATA_QCFLAG_DMAMAP)) + return; + + nv_swncq_fill_sg(qc); +} + +static void nv_swncq_fill_sg(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct scatterlist *sg; + unsigned int idx; + struct nv_swncq_port_priv *pp = ap->private_data; + struct ata_prd *prd; + + WARN_ON(qc->__sg == NULL); + WARN_ON(qc->n_elem == 0 && qc->pad_len == 0); + + prd = pp->prd + ATA_MAX_PRD * qc->tag; + + idx = 0; + ata_for_each_sg(sg, qc) { + u32 addr, offset; + u32 sg_len, len; + + addr = (u32)sg_dma_address(sg); + sg_len = sg_dma_len(sg); + + while (sg_len) { + offset = addr & 0xffff; + len = sg_len; + if ((offset + sg_len) > 0x10000) + len = 0x10000 - offset; + + prd[idx].addr = cpu_to_le32(addr); + prd[idx].flags_len = cpu_to_le32(len & 0xffff); + + idx++; + sg_len -= len; + addr += len; + } + } + + if (idx) + prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT); +} + +static unsigned int nv_swncq_issue_atacmd(struct ata_port *ap, + struct ata_queued_cmd *qc) +{ + struct nv_swncq_port_priv *pp = ap->private_data; + + if (qc == NULL) + return 0; + + DPRINTK("Enter\n"); + + writel((1 << qc->tag), pp->sactive_block); + pp->last_issue_tag = qc->tag; + pp->dhfis_bits &= ~(1 << qc->tag); + pp->dmafis_bits &= ~(1 << qc->tag); + pp->qc_active |= (0x1 << qc->tag); + + ap->ops->tf_load(ap, &qc->tf); /* load tf registers */ + ap->ops->exec_command(ap, &qc->tf); + + DPRINTK("Issued tag %u\n", qc->tag); + + return 0; +} + +static unsigned int nv_swncq_qc_issue(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct nv_swncq_port_priv *pp = ap->private_data; + + if (qc->tf.protocol != ATA_PROT_NCQ) + return ata_qc_issue_prot(qc); + + DPRINTK("Enter\n"); + + if (!pp->qc_active) + nv_swncq_issue_atacmd(ap, qc); + else + nv_swncq_qc_to_dq(ap, qc); /* add qc to defer queue */ + + return 0; +} + +static void nv_swncq_hotplug(struct ata_port *ap, u32 fis) +{ + u32 serror; + struct ata_eh_info *ehi = &ap->link.eh_info; + + ata_ehi_clear_desc(ehi); + + /* AHCI needs SError cleared; otherwise, it might lock up */ + sata_scr_read(&ap->link, SCR_ERROR, &serror); + sata_scr_write(&ap->link, SCR_ERROR, serror); + + /* analyze @irq_stat */ + if (fis & NV_SWNCQ_IRQ_ADDED) + ata_ehi_push_desc(ehi, "hot plug"); + else if (fis & NV_SWNCQ_IRQ_REMOVED) + ata_ehi_push_desc(ehi, "hot unplug"); + + ata_ehi_hotplugged(ehi); + + /* okay, let's hand over to EH */ + ehi->serror |= serror; + + ata_port_freeze(ap); +} + +static int nv_swncq_sdbfis(struct ata_port *ap) +{ + struct ata_queued_cmd *qc; + struct nv_swncq_port_priv *pp = ap->private_data; + struct ata_eh_info *ehi = &ap->link.eh_info; + u32 sactive; + int nr_done = 0; + u32 done_mask; + int i; + u8 host_stat; + u8 lack_dhfis = 0; + + host_stat = ap->ops->bmdma_status(ap); + if (unlikely(host_stat & ATA_DMA_ERR)) { + /* error when transfering data to/from memory */ + ata_ehi_clear_desc(ehi); + ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat); + ehi->err_mask |= AC_ERR_HOST_BUS; + ehi->action |= ATA_EH_SOFTRESET; + return -EINVAL; + } + + ap->ops->irq_clear(ap); + __ata_bmdma_stop(ap); + + sactive = readl(pp->sactive_block); + done_mask = pp->qc_active ^ sactive; + + if (unlikely(done_mask & sactive)) { + ata_ehi_clear_desc(ehi); + ata_ehi_push_desc(ehi, "illegal SWNCQ:qc_active transition" + "(%08x->%08x)", pp->qc_active, sactive); + ehi->err_mask |= AC_ERR_HSM; + ehi->action |= ATA_EH_HARDRESET; + return -EINVAL; + } + for (i = 0; i < ATA_MAX_QUEUE; i++) { + if (!(done_mask & (1 << i))) + continue; + + qc = ata_qc_from_tag(ap, i); + if (qc) { + ata_qc_complete(qc); + pp->qc_active &= ~(1 << i); + pp->dhfis_bits &= ~(1 << i); + pp->dmafis_bits &= ~(1 << i); + pp->sdbfis_bits |= (1 << i); + nr_done++; + } + } + + if (!ap->qc_active) { + DPRINTK("over\n"); + nv_swncq_pp_reinit(ap); + return nr_done; + } + + if (pp->qc_active & pp->dhfis_bits) + return nr_done; + + if ((pp->ncq_flags & ncq_saw_backout) || + (pp->qc_active ^ pp->dhfis_bits)) + /* if the controller cann't get a device to host register FIS, + * The driver needs to reissue the new command. + */ + lack_dhfis = 1; + + DPRINTK("id 0x%x QC: qc_active 0x%x," + "SWNCQ:qc_active 0x%X defer_bits %X " + "dhfis 0x%X dmafis 0x%X last_issue_tag %x\n", + ap->print_id, ap->qc_active, pp->qc_active, + pp->defer_queue.defer_bits, pp->dhfis_bits, + pp->dmafis_bits, pp->last_issue_tag); + + nv_swncq_fis_reinit(ap); + + if (lack_dhfis) { + qc = ata_qc_from_tag(ap, pp->last_issue_tag); + nv_swncq_issue_atacmd(ap, qc); + return nr_done; + } + + if (pp->defer_queue.defer_bits) { + /* send deferral queue command */ + qc = nv_swncq_qc_from_dq(ap); + WARN_ON(qc == NULL); + nv_swncq_issue_atacmd(ap, qc); + } + + return nr_done; +} + +static inline u32 nv_swncq_tag(struct ata_port *ap) +{ + struct nv_swncq_port_priv *pp = ap->private_data; + u32 tag; + + tag = readb(pp->tag_block) >> 2; + return (tag & 0x1f); +} + +static int nv_swncq_dmafis(struct ata_port *ap) +{ + struct ata_queued_cmd *qc; + unsigned int rw; + u8 dmactl; + u32 tag; + struct nv_swncq_port_priv *pp = ap->private_data; + + __ata_bmdma_stop(ap); + tag = nv_swncq_tag(ap); + + DPRINTK("dma setup tag 0x%x\n", tag); + qc = ata_qc_from_tag(ap, tag); + + if (unlikely(!qc)) + return 0; + + rw = qc->tf.flags & ATA_TFLAG_WRITE; + + /* load PRD table addr. */ + iowrite32(pp->prd_dma + ATA_PRD_TBL_SZ * qc->tag, + 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; + if (!rw) + dmactl |= ATA_DMA_WR; + + iowrite8(dmactl | ATA_DMA_START, ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + + return 1; +} + +static void nv_swncq_host_interrupt(struct ata_port *ap, u16 fis) +{ + struct nv_swncq_port_priv *pp = ap->private_data; + struct ata_queued_cmd *qc; + struct ata_eh_info *ehi = &ap->link.eh_info; + u32 serror; + u8 ata_stat; + int rc = 0; + + ata_stat = ap->ops->check_status(ap); + nv_swncq_irq_clear(ap, fis); + if (!fis) + return; + + if (ap->pflags & ATA_PFLAG_FROZEN) + return; + + if (fis & NV_SWNCQ_IRQ_HOTPLUG) { + nv_swncq_hotplug(ap, fis); + return; + } + + if (!pp->qc_active) + return; + + if (ap->ops->scr_read(ap, SCR_ERROR, &serror)) + return; + ap->ops->scr_write(ap, SCR_ERROR, serror); + + if (ata_stat & ATA_ERR) { + ata_ehi_clear_desc(ehi); + ata_ehi_push_desc(ehi, "Ata error. fis:0x%X", fis); + ehi->err_mask |= AC_ERR_DEV; + ehi->serror |= serror; + ehi->action |= ATA_EH_SOFTRESET; + ata_port_freeze(ap); + return; + } + + if (fis & NV_SWNCQ_IRQ_BACKOUT) { + /* If the IRQ is backout, driver must issue + * the new command again some time later. + */ + pp->ncq_flags |= ncq_saw_backout; + } + + if (fis & NV_SWNCQ_IRQ_SDBFIS) { + pp->ncq_flags |= ncq_saw_sdb; + DPRINTK("id 0x%x SWNCQ: qc_active 0x%X " + "dhfis 0x%X dmafis 0x%X sactive 0x%X\n", + ap->print_id, pp->qc_active, pp->dhfis_bits, + pp->dmafis_bits, readl(pp->sactive_block)); + rc = nv_swncq_sdbfis(ap); + if (rc < 0) + goto irq_error; + } + + if (fis & NV_SWNCQ_IRQ_DHREGFIS) { + /* The interrupt indicates the new command + * was transmitted correctly to the drive. + */ + pp->dhfis_bits |= (0x1 << pp->last_issue_tag); + pp->ncq_flags |= ncq_saw_d2h; + if (pp->ncq_flags & (ncq_saw_sdb | ncq_saw_backout)) { + ata_ehi_push_desc(ehi, "illegal fis transaction"); + ehi->err_mask |= AC_ERR_HSM; + ehi->action |= ATA_EH_HARDRESET; + goto irq_error; + } + + if (!(fis & NV_SWNCQ_IRQ_DMASETUP) && + !(pp->ncq_flags & ncq_saw_dmas)) { + ata_stat = ap->ops->check_status(ap); + if (ata_stat & ATA_BUSY) + goto irq_exit; + + if (pp->defer_queue.defer_bits) { + DPRINTK("send next command\n"); + qc = nv_swncq_qc_from_dq(ap); + nv_swncq_issue_atacmd(ap, qc); + } + } + } + + if (fis & NV_SWNCQ_IRQ_DMASETUP) { + /* program the dma controller with appropriate PRD buffers + * and start the DMA transfer for requested command. + */ + pp->dmafis_bits |= (0x1 << nv_swncq_tag(ap)); + pp->ncq_flags |= ncq_saw_dmas; + rc = nv_swncq_dmafis(ap); + } + +irq_exit: + return; +irq_error: + ata_ehi_push_desc(ehi, "fis:0x%x", fis); + ata_port_freeze(ap); + return; +} + +static irqreturn_t nv_swncq_interrupt(int irq, void *dev_instance) +{ + struct ata_host *host = dev_instance; + unsigned int i; + unsigned int handled = 0; + unsigned long flags; + u32 irq_stat; + + spin_lock_irqsave(&host->lock, flags); + + irq_stat = readl(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_MCP55); + + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + + if (ap && !(ap->flags & ATA_FLAG_DISABLED)) { + if (ap->link.sactive) { + nv_swncq_host_interrupt(ap, (u16)irq_stat); + handled = 1; + } else { + if (irq_stat) /* reserve Hotplug */ + nv_swncq_irq_clear(ap, 0xfff0); + + handled += nv_host_intr(ap, (u8)irq_stat); + } + } + irq_stat >>= NV_INT_PORT_SHIFT_MCP55; + } + + spin_unlock_irqrestore(&host->lock, flags); + + return IRQ_RETVAL(handled); +} + static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version = 0; @@ -1558,7 +2378,7 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) return rc; /* determine type and allocate host */ - if (type >= CK804 && adma_enabled) { + if (type == CK804 && adma_enabled) { dev_printk(KERN_NOTICE, &pdev->dev, "Using ADMA mode\n"); type = ADMA; } @@ -1604,6 +2424,9 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) rc = nv_adma_host_init(host); if (rc) return rc; + } else if (type == SWNCQ && swncq_enabled) { + dev_printk(KERN_NOTICE, &pdev->dev, "Using SWNCQ mode\n"); + nv_swncq_host_init(host); } pci_set_master(pdev); @@ -1703,3 +2526,6 @@ module_init(nv_init); module_exit(nv_exit); module_param_named(adma, adma_enabled, bool, 0444); MODULE_PARM_DESC(adma, "Enable use of ADMA (Default: true)"); +module_param_named(swncq, swncq_enabled, bool, 0444); +MODULE_PARM_DESC(swncq, "Enable use of SWNCQ (Default: false)"); + diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index 25698cf0dce0..903213153b5d 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -167,7 +167,6 @@ static struct scsi_host_template pdc_ata_sht = { }; static const struct ata_port_operations pdc_sata_ops = { - .port_disable = ata_port_disable, .tf_load = pdc_tf_load_mmio, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -185,7 +184,6 @@ static const struct ata_port_operations pdc_sata_ops = { .data_xfer = ata_data_xfer, .irq_clear = pdc_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = pdc_sata_scr_read, .scr_write = pdc_sata_scr_write, @@ -194,7 +192,6 @@ static const struct ata_port_operations pdc_sata_ops = { /* First-generation chips need a more restrictive ->check_atapi_dma op */ static const struct ata_port_operations pdc_old_sata_ops = { - .port_disable = ata_port_disable, .tf_load = pdc_tf_load_mmio, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -212,7 +209,6 @@ static const struct ata_port_operations pdc_old_sata_ops = { .data_xfer = ata_data_xfer, .irq_clear = pdc_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = pdc_sata_scr_read, .scr_write = pdc_sata_scr_write, @@ -220,7 +216,6 @@ static const struct ata_port_operations pdc_old_sata_ops = { }; static const struct ata_port_operations pdc_pata_ops = { - .port_disable = ata_port_disable, .tf_load = pdc_tf_load_mmio, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -238,7 +233,6 @@ static const struct ata_port_operations pdc_pata_ops = { .data_xfer = ata_data_xfer, .irq_clear = pdc_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = pdc_common_port_start, }; @@ -475,7 +469,7 @@ static void pdc_atapi_pkt(struct ata_queued_cmd *qc) buf32[2] = 0; /* no next-packet */ /* select drive */ - if (sata_scr_valid(ap)) { + if (sata_scr_valid(&ap->link)) { dev_sel = PDC_DEVICE_SATA; } else { dev_sel = ATA_DEVICE_OBS; @@ -626,7 +620,7 @@ static void pdc_post_internal_cmd(struct ata_queued_cmd *qc) static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc, u32 port_status, u32 err_mask) { - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; unsigned int ac_err_mask = 0; ata_ehi_clear_desc(ehi); @@ -643,7 +637,7 @@ static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc, | PDC_PCI_SYS_ERR | PDC1_PCI_PARITY_ERR)) ac_err_mask |= AC_ERR_HOST_BUS; - if (sata_scr_valid(ap)) { + if (sata_scr_valid(&ap->link)) { u32 serror; pdc_sata_scr_read(ap, SCR_ERROR, &serror); @@ -773,7 +767,7 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance) tmp = hotplug_status & (0x11 << ata_no); if (tmp && ap && !(ap->flags & ATA_FLAG_DISABLED)) { - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; ata_ehi_clear_desc(ehi); ata_ehi_hotplugged(ehi); ata_ehi_push_desc(ehi, "hotplug_status %#x", tmp); @@ -788,7 +782,7 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance) !(ap->flags & ATA_FLAG_DISABLED)) { struct ata_queued_cmd *qc; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) handled += pdc_host_intr(ap, qc); } @@ -1009,10 +1003,15 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e is_sataii_tx4 = pdc_is_sataii_tx4(pi->flags); for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; unsigned int ata_no = pdc_port_no_to_ata_no(i, is_sataii_tx4); - pdc_ata_setup_port(host->ports[i], - base + 0x200 + ata_no * 0x80, - base + 0x400 + ata_no * 0x100); + unsigned int port_offset = 0x200 + ata_no * 0x80; + unsigned int scr_offset = 0x400 + ata_no * 0x100; + + pdc_ata_setup_port(ap, base + port_offset, base + scr_offset); + + ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio"); + ata_port_pbar_desc(ap, PDC_MMIO_BAR, port_offset, "port"); } /* initialize adapter */ diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index 5e1dfdda698f..c4c4cd29eebb 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -145,7 +145,6 @@ static struct scsi_host_template qs_ata_sht = { }; static const struct ata_port_operations qs_ata_ops = { - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -159,7 +158,6 @@ static const struct ata_port_operations qs_ata_ops = { .eng_timeout = qs_eng_timeout, .irq_clear = qs_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = qs_scr_read, .scr_write = qs_scr_write, .port_start = qs_port_start, @@ -404,7 +402,7 @@ static inline unsigned int qs_intr_pkt(struct ata_host *host) struct qs_port_priv *pp = ap->private_data; if (!pp || pp->state != qs_state_pkt) continue; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { switch (sHST) { case 0: /* successful CPB */ @@ -437,7 +435,7 @@ static inline unsigned int qs_intr_mmio(struct ata_host *host) struct qs_port_priv *pp = ap->private_data; if (!pp || pp->state != qs_state_mmio) continue; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { /* check main status, clearing INTRQ */ @@ -637,9 +635,14 @@ static int qs_ata_init_one(struct pci_dev *pdev, return rc; for (port_no = 0; port_no < host->n_ports; ++port_no) { - void __iomem *chan = - host->iomap[QS_MMIO_BAR] + (port_no * 0x4000); - qs_ata_setup_port(&host->ports[port_no]->ioaddr, chan); + struct ata_port *ap = host->ports[port_no]; + unsigned int offset = port_no * 0x4000; + void __iomem *chan = host->iomap[QS_MMIO_BAR] + offset; + + qs_ata_setup_port(&ap->ioaddr, chan); + + ata_port_pbar_desc(ap, QS_MMIO_BAR, -1, "mmio"); + ata_port_pbar_desc(ap, QS_MMIO_BAR, offset, "port"); } /* initialize adapter */ diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index 8c72e714b456..ea3a0ab7e027 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -59,7 +59,8 @@ enum { SIL_FLAG_MOD15WRITE = (1 << 30), SIL_DFL_PORT_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_MMIO | ATA_FLAG_HRST_TO_RESUME, + ATA_FLAG_MMIO, + SIL_DFL_LINK_FLAGS = ATA_LFLAG_HRST_TO_RESUME, /* * Controller IDs @@ -117,7 +118,7 @@ static int sil_pci_device_resume(struct pci_dev *pdev); static void sil_dev_config(struct ata_device *dev); static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); -static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed); +static int sil_set_mode(struct ata_link *link, struct ata_device **r_failed); static void sil_freeze(struct ata_port *ap); static void sil_thaw(struct ata_port *ap); @@ -185,7 +186,6 @@ static struct scsi_host_template sil_sht = { }; static const struct ata_port_operations sil_ops = { - .port_disable = ata_port_disable, .dev_config = sil_dev_config, .tf_load = ata_tf_load, .tf_read = ata_tf_read, @@ -206,7 +206,6 @@ static const struct ata_port_operations sil_ops = { .post_internal_cmd = ata_bmdma_post_internal_cmd, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = sil_scr_read, .scr_write = sil_scr_write, .port_start = ata_port_start, @@ -216,6 +215,7 @@ static const struct ata_port_info sil_port_info[] = { /* sil_3112 */ { .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE, + .link_flags = SIL_DFL_LINK_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, @@ -225,6 +225,7 @@ static const struct ata_port_info sil_port_info[] = { { .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE | SIL_FLAG_NO_SATA_IRQ, + .link_flags = SIL_DFL_LINK_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, @@ -233,6 +234,7 @@ static const struct ata_port_info sil_port_info[] = { /* sil_3512 */ { .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT, + .link_flags = SIL_DFL_LINK_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, @@ -241,6 +243,7 @@ static const struct ata_port_info sil_port_info[] = { /* sil_3114 */ { .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT, + .link_flags = SIL_DFL_LINK_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, @@ -290,35 +293,33 @@ static unsigned char sil_get_device_cache_line(struct pci_dev *pdev) /** * sil_set_mode - wrap set_mode functions - * @ap: port to set up + * @link: link to set up * @r_failed: returned device when we fail * * Wrap the libata method for device setup as after the setup we need * to inspect the results and do some configuration work */ -static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed) +static int sil_set_mode(struct ata_link *link, struct ata_device **r_failed) { - struct ata_host *host = ap->host; - struct ata_device *dev; - void __iomem *mmio_base = host->iomap[SIL_MMIO_BAR]; + struct ata_port *ap = link->ap; + void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR]; void __iomem *addr = mmio_base + sil_port[ap->port_no].xfer_mode; - u32 tmp, dev_mode[2]; - unsigned int i; + struct ata_device *dev; + u32 tmp, dev_mode[2] = { }; int rc; - rc = ata_do_set_mode(ap, r_failed); + rc = ata_do_set_mode(link, r_failed); if (rc) return rc; - for (i = 0; i < 2; i++) { - dev = &ap->device[i]; + ata_link_for_each_dev(dev, link) { if (!ata_dev_enabled(dev)) - dev_mode[i] = 0; /* PIO0/1/2 */ + dev_mode[dev->devno] = 0; /* PIO0/1/2 */ else if (dev->flags & ATA_DFLAG_PIO) - dev_mode[i] = 1; /* PIO3/4 */ + dev_mode[dev->devno] = 1; /* PIO3/4 */ else - dev_mode[i] = 3; /* UDMA */ + dev_mode[dev->devno] = 3; /* UDMA */ /* value 2 indicates MDMA */ } @@ -374,8 +375,8 @@ static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) static void sil_host_intr(struct ata_port *ap, u32 bmdma2) { - struct ata_eh_info *ehi = &ap->eh_info; - struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); + struct ata_eh_info *ehi = &ap->link.eh_info; + struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag); u8 status; if (unlikely(bmdma2 & SIL_DMA_SATA_IRQ)) { @@ -394,8 +395,8 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2) * repeat probing needlessly. */ if (!(ap->pflags & ATA_PFLAG_FROZEN)) { - ata_ehi_hotplugged(&ap->eh_info); - ap->eh_info.serror |= serror; + ata_ehi_hotplugged(&ap->link.eh_info); + ap->link.eh_info.serror |= serror; } goto freeze; @@ -562,8 +563,8 @@ static void sil_thaw(struct ata_port *ap) */ static void sil_dev_config(struct ata_device *dev) { - struct ata_port *ap = dev->ap; - int print_info = ap->eh_context.i.flags & ATA_EHI_PRINTINFO; + struct ata_port *ap = dev->link->ap; + int print_info = ap->link.eh_context.i.flags & ATA_EHI_PRINTINFO; unsigned int n, quirks = 0; unsigned char model_num[ATA_ID_PROD_LEN + 1]; @@ -686,7 +687,8 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) mmio_base = host->iomap[SIL_MMIO_BAR]; for (i = 0; i < host->n_ports; i++) { - struct ata_ioports *ioaddr = &host->ports[i]->ioaddr; + struct ata_port *ap = host->ports[i]; + struct ata_ioports *ioaddr = &ap->ioaddr; ioaddr->cmd_addr = mmio_base + sil_port[i].tf; ioaddr->altstatus_addr = @@ -694,6 +696,9 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ioaddr->bmdma_addr = mmio_base + sil_port[i].bmdma; ioaddr->scr_addr = mmio_base + sil_port[i].scr; ata_std_ports(ioaddr); + + ata_port_pbar_desc(ap, SIL_MMIO_BAR, -1, "mmio"); + ata_port_pbar_desc(ap, SIL_MMIO_BAR, sil_port[i].tf, "tf"); } /* initialize and activate */ diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 233e88693395..b0619278454a 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 "1.0" +#define DRV_VERSION "1.1" /* * Port request block (PRB) 32 bytes @@ -168,7 +168,7 @@ enum { DEF_PORT_IRQ = PORT_IRQ_COMPLETE | PORT_IRQ_ERROR | PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG | - PORT_IRQ_UNK_FIS, + PORT_IRQ_UNK_FIS | PORT_IRQ_SDB_NOTIFY, /* bits[27:16] are unmasked (raw) */ PORT_IRQ_RAW_SHIFT = 16, @@ -237,8 +237,9 @@ enum { /* host flags */ SIL24_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | - ATA_FLAG_NCQ | ATA_FLAG_SKIP_D2H_BSY | - ATA_FLAG_ACPI_SATA, + ATA_FLAG_NCQ | ATA_FLAG_ACPI_SATA | + ATA_FLAG_AN | ATA_FLAG_PMP, + SIL24_COMMON_LFLAGS = ATA_LFLAG_SKIP_D2H_BSY, SIL24_FLAG_PCIX_IRQ_WOC = (1 << 24), /* IRQ loss errata on PCI-X */ IRQ_STAT_4PORTS = 0xf, @@ -322,6 +323,7 @@ struct sil24_port_priv { union sil24_cmd_block *cmd_block; /* 32 cmd blocks */ dma_addr_t cmd_block_dma; /* DMA base addr for them */ struct ata_taskfile tf; /* Cached taskfile registers */ + int do_port_rst; }; static void sil24_dev_config(struct ata_device *dev); @@ -329,9 +331,12 @@ static u8 sil24_check_status(struct ata_port *ap); static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val); static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val); static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf); +static int sil24_qc_defer(struct ata_queued_cmd *qc); static void sil24_qc_prep(struct ata_queued_cmd *qc); static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc); static void sil24_irq_clear(struct ata_port *ap); +static void sil24_pmp_attach(struct ata_port *ap); +static void sil24_pmp_detach(struct ata_port *ap); static void sil24_freeze(struct ata_port *ap); static void sil24_thaw(struct ata_port *ap); static void sil24_error_handler(struct ata_port *ap); @@ -340,6 +345,7 @@ static int sil24_port_start(struct ata_port *ap); static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); #ifdef CONFIG_PM static int sil24_pci_device_resume(struct pci_dev *pdev); +static int sil24_port_resume(struct ata_port *ap); #endif static const struct pci_device_id sil24_pci_tbl[] = { @@ -384,8 +390,6 @@ static struct scsi_host_template sil24_sht = { }; static const struct ata_port_operations sil24_ops = { - .port_disable = ata_port_disable, - .dev_config = sil24_dev_config, .check_status = sil24_check_status, @@ -394,22 +398,28 @@ static const struct ata_port_operations sil24_ops = { .tf_read = sil24_tf_read, + .qc_defer = sil24_qc_defer, .qc_prep = sil24_qc_prep, .qc_issue = sil24_qc_issue, .irq_clear = sil24_irq_clear, - .irq_on = ata_dummy_irq_on, - .irq_ack = ata_dummy_irq_ack, .scr_read = sil24_scr_read, .scr_write = sil24_scr_write, + .pmp_attach = sil24_pmp_attach, + .pmp_detach = sil24_pmp_detach, + .freeze = sil24_freeze, .thaw = sil24_thaw, .error_handler = sil24_error_handler, .post_internal_cmd = sil24_post_internal_cmd, .port_start = sil24_port_start, + +#ifdef CONFIG_PM + .port_resume = sil24_port_resume, +#endif }; /* @@ -424,6 +434,7 @@ static const struct ata_port_info sil24_port_info[] = { { .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(4) | SIL24_FLAG_PCIX_IRQ_WOC, + .link_flags = SIL24_COMMON_LFLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, /* udma0-5 */ @@ -432,6 +443,7 @@ static const struct ata_port_info sil24_port_info[] = { /* sil_3132 */ { .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(2), + .link_flags = SIL24_COMMON_LFLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, /* udma0-5 */ @@ -440,6 +452,7 @@ static const struct ata_port_info sil24_port_info[] = { /* sil_3131/sil_3531 */ { .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(1), + .link_flags = SIL24_COMMON_LFLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, /* udma0-5 */ @@ -456,7 +469,7 @@ static int sil24_tag(int tag) static void sil24_dev_config(struct ata_device *dev) { - void __iomem *port = dev->ap->ioaddr.cmd_addr; + void __iomem *port = dev->link->ap->ioaddr.cmd_addr; if (dev->cdb_len == 16) writel(PORT_CS_CDB16, port + PORT_CTRL_STAT); @@ -520,19 +533,78 @@ static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf) *tf = pp->tf; } +static void sil24_config_port(struct ata_port *ap) +{ + void __iomem *port = ap->ioaddr.cmd_addr; + + /* configure IRQ WoC */ + if (ap->flags & SIL24_FLAG_PCIX_IRQ_WOC) + writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT); + else + writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR); + + /* zero error counters. */ + writel(0x8000, port + PORT_DECODE_ERR_THRESH); + writel(0x8000, port + PORT_CRC_ERR_THRESH); + writel(0x8000, port + PORT_HSHK_ERR_THRESH); + writel(0x0000, port + PORT_DECODE_ERR_CNT); + writel(0x0000, port + PORT_CRC_ERR_CNT); + writel(0x0000, port + PORT_HSHK_ERR_CNT); + + /* always use 64bit activation */ + writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR); + + /* clear port multiplier enable and resume bits */ + writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME, port + PORT_CTRL_CLR); +} + +static void sil24_config_pmp(struct ata_port *ap, int attached) +{ + void __iomem *port = ap->ioaddr.cmd_addr; + + if (attached) + writel(PORT_CS_PMP_EN, port + PORT_CTRL_STAT); + else + writel(PORT_CS_PMP_EN, port + PORT_CTRL_CLR); +} + +static void sil24_clear_pmp(struct ata_port *ap) +{ + void __iomem *port = ap->ioaddr.cmd_addr; + int i; + + writel(PORT_CS_PMP_RESUME, port + PORT_CTRL_CLR); + + for (i = 0; i < SATA_PMP_MAX_PORTS; i++) { + void __iomem *pmp_base = port + PORT_PMP + i * PORT_PMP_SIZE; + + writel(0, pmp_base + PORT_PMP_STATUS); + writel(0, pmp_base + PORT_PMP_QACTIVE); + } +} + static int sil24_init_port(struct ata_port *ap) { void __iomem *port = ap->ioaddr.cmd_addr; + struct sil24_port_priv *pp = ap->private_data; u32 tmp; + /* clear PMP error status */ + if (ap->nr_pmp_links) + sil24_clear_pmp(ap); + writel(PORT_CS_INIT, port + PORT_CTRL_STAT); ata_wait_register(port + PORT_CTRL_STAT, PORT_CS_INIT, PORT_CS_INIT, 10, 100); tmp = ata_wait_register(port + PORT_CTRL_STAT, PORT_CS_RDY, 0, 10, 100); - if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY) + if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY) { + pp->do_port_rst = 1; + ap->link.eh_context.i.action |= ATA_EH_HARDRESET; return -EIO; + } + return 0; } @@ -583,9 +655,10 @@ static int sil24_exec_polled_cmd(struct ata_port *ap, int pmp, return rc; } -static int sil24_do_softreset(struct ata_port *ap, unsigned int *class, +static int sil24_do_softreset(struct ata_link *link, unsigned int *class, int pmp, unsigned long deadline) { + struct ata_port *ap = link->ap; unsigned long timeout_msec = 0; struct ata_taskfile tf; const char *reason; @@ -593,7 +666,7 @@ static int sil24_do_softreset(struct ata_port *ap, unsigned int *class, DPRINTK("ENTER\n"); - if (ata_port_offline(ap)) { + if (ata_link_offline(link)) { DPRINTK("PHY reports no device\n"); *class = ATA_DEV_NONE; goto out; @@ -609,7 +682,7 @@ static int sil24_do_softreset(struct ata_port *ap, unsigned int *class, if (time_after(deadline, jiffies)) timeout_msec = jiffies_to_msecs(deadline - jiffies); - ata_tf_init(ap->device, &tf); /* doesn't really matter */ + ata_tf_init(link->device, &tf); /* doesn't really matter */ rc = sil24_exec_polled_cmd(ap, pmp, &tf, 0, PRB_CTRL_SRST, timeout_msec); if (rc == -EBUSY) { @@ -631,29 +704,54 @@ static int sil24_do_softreset(struct ata_port *ap, unsigned int *class, return 0; err: - ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason); + ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason); return -EIO; } -static int sil24_softreset(struct ata_port *ap, unsigned int *class, +static int sil24_softreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { - return sil24_do_softreset(ap, class, 0, deadline); + return sil24_do_softreset(link, class, SATA_PMP_CTRL_PORT, deadline); } -static int sil24_hardreset(struct ata_port *ap, unsigned int *class, +static int sil24_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { + struct ata_port *ap = link->ap; void __iomem *port = ap->ioaddr.cmd_addr; + struct sil24_port_priv *pp = ap->private_data; + int did_port_rst = 0; const char *reason; int tout_msec, rc; u32 tmp; + retry: + /* Sometimes, DEV_RST is not enough to recover the controller. + * This happens often after PM DMA CS errata. + */ + if (pp->do_port_rst) { + ata_port_printk(ap, KERN_WARNING, "controller in dubious " + "state, performing PORT_RST\n"); + + writel(PORT_CS_PORT_RST, port + PORT_CTRL_STAT); + msleep(10); + writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR); + ata_wait_register(port + PORT_CTRL_STAT, PORT_CS_RDY, 0, + 10, 5000); + + /* restore port configuration */ + sil24_config_port(ap); + sil24_config_pmp(ap, ap->nr_pmp_links); + + pp->do_port_rst = 0; + did_port_rst = 1; + } + /* sil24 does the right thing(tm) without any protection */ - sata_set_spd(ap); + sata_set_spd(link); tout_msec = 100; - if (ata_port_online(ap)) + if (ata_link_online(link)) tout_msec = 5000; writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT); @@ -663,14 +761,14 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class, /* SStatus oscillates between zero and valid status after * DEV_RST, debounce it. */ - rc = sata_phy_debounce(ap, sata_deb_timing_long, deadline); + rc = sata_link_debounce(link, sata_deb_timing_long, deadline); if (rc) { reason = "PHY debouncing failed"; goto err; } if (tmp & PORT_CS_DEV_RST) { - if (ata_port_offline(ap)) + if (ata_link_offline(link)) return 0; reason = "link not ready"; goto err; @@ -685,7 +783,12 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class, return -EAGAIN; err: - ata_port_printk(ap, KERN_ERR, "hardreset failed (%s)\n", reason); + if (!did_port_rst) { + pp->do_port_rst = 1; + goto retry; + } + + ata_link_printk(link, KERN_ERR, "hardreset failed (%s)\n", reason); return -EIO; } @@ -705,6 +808,38 @@ static inline void sil24_fill_sg(struct ata_queued_cmd *qc, } } +static int sil24_qc_defer(struct ata_queued_cmd *qc) +{ + struct ata_link *link = qc->dev->link; + struct ata_port *ap = link->ap; + u8 prot = qc->tf.protocol; + int is_atapi = (prot == ATA_PROT_ATAPI || + prot == ATA_PROT_ATAPI_NODATA || + prot == ATA_PROT_ATAPI_DMA); + + /* ATAPI commands completing with CHECK_SENSE cause various + * weird problems if other commands are active. PMP DMA CS + * errata doesn't cover all and HSM violation occurs even with + * only one other device active. Always run an ATAPI command + * by itself. + */ + if (unlikely(ap->excl_link)) { + if (link == ap->excl_link) { + if (ap->nr_active_links) + return ATA_DEFER_PORT; + qc->flags |= ATA_QCFLAG_CLEAR_EXCL; + } else + return ATA_DEFER_PORT; + } else if (unlikely(is_atapi)) { + ap->excl_link = link; + if (ap->nr_active_links) + return ATA_DEFER_PORT; + qc->flags |= ATA_QCFLAG_CLEAR_EXCL; + } + + return ata_std_qc_defer(qc); +} + static void sil24_qc_prep(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; @@ -748,7 +883,7 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc) } prb->ctrl = cpu_to_le16(ctrl); - ata_tf_to_fis(&qc->tf, 0, 1, prb->fis); + ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, prb->fis); if (qc->flags & ATA_QCFLAG_DMAMAP) sil24_fill_sg(qc, sge); @@ -777,6 +912,39 @@ static void sil24_irq_clear(struct ata_port *ap) /* unused */ } +static void sil24_pmp_attach(struct ata_port *ap) +{ + sil24_config_pmp(ap, 1); + sil24_init_port(ap); +} + +static void sil24_pmp_detach(struct ata_port *ap) +{ + sil24_init_port(ap); + sil24_config_pmp(ap, 0); +} + +static int sil24_pmp_softreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + return sil24_do_softreset(link, class, link->pmp, deadline); +} + +static int sil24_pmp_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + int rc; + + rc = sil24_init_port(link->ap); + if (rc) { + ata_link_printk(link, KERN_ERR, + "hardreset failed (port not ready)\n"); + return rc; + } + + return sata_pmp_std_hardreset(link, class, deadline); +} + static void sil24_freeze(struct ata_port *ap) { void __iomem *port = ap->ioaddr.cmd_addr; @@ -804,8 +972,10 @@ static void sil24_error_intr(struct ata_port *ap) { void __iomem *port = ap->ioaddr.cmd_addr; struct sil24_port_priv *pp = ap->private_data; - struct ata_eh_info *ehi = &ap->eh_info; - int freeze = 0; + struct ata_queued_cmd *qc = NULL; + struct ata_link *link; + struct ata_eh_info *ehi; + int abort = 0, freeze = 0; u32 irq_stat; /* on error, we need to clear IRQ explicitly */ @@ -813,10 +983,17 @@ static void sil24_error_intr(struct ata_port *ap) writel(irq_stat, port + PORT_IRQ_STAT); /* first, analyze and record host port events */ + link = &ap->link; + ehi = &link->eh_info; ata_ehi_clear_desc(ehi); ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat); + if (irq_stat & PORT_IRQ_SDB_NOTIFY) { + ata_ehi_push_desc(ehi, "SDB notify"); + sata_async_notification(ap); + } + if (irq_stat & (PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG)) { ata_ehi_hotplugged(ehi); ata_ehi_push_desc(ehi, "%s", @@ -836,8 +1013,44 @@ static void sil24_error_intr(struct ata_port *ap) if (irq_stat & PORT_IRQ_ERROR) { struct sil24_cerr_info *ci = NULL; unsigned int err_mask = 0, action = 0; - struct ata_queued_cmd *qc; - u32 cerr; + u32 context, cerr; + int pmp; + + abort = 1; + + /* DMA Context Switch Failure in Port Multiplier Mode + * errata. If we have active commands to 3 or more + * devices, any error condition on active devices can + * corrupt DMA context switching. + */ + if (ap->nr_active_links >= 3) { + ehi->err_mask |= AC_ERR_OTHER; + ehi->action |= ATA_EH_HARDRESET; + ata_ehi_push_desc(ehi, "PMP DMA CS errata"); + pp->do_port_rst = 1; + freeze = 1; + } + + /* find out the offending link and qc */ + if (ap->nr_pmp_links) { + context = readl(port + PORT_CONTEXT); + pmp = (context >> 5) & 0xf; + + if (pmp < ap->nr_pmp_links) { + link = &ap->pmp_link[pmp]; + ehi = &link->eh_info; + qc = ata_qc_from_tag(ap, link->active_tag); + + ata_ehi_clear_desc(ehi); + ata_ehi_push_desc(ehi, "irq_stat 0x%08x", + irq_stat); + } else { + err_mask |= AC_ERR_HSM; + action |= ATA_EH_HARDRESET; + freeze = 1; + } + } else + qc = ata_qc_from_tag(ap, link->active_tag); /* analyze CMD_ERR */ cerr = readl(port + PORT_CMD_ERR); @@ -856,7 +1069,6 @@ static void sil24_error_intr(struct ata_port *ap) } /* record error info */ - qc = ata_qc_from_tag(ap, ap->active_tag); if (qc) { sil24_read_tf(ap, qc->tag, &pp->tf); qc->err_mask |= err_mask; @@ -864,13 +1076,21 @@ static void sil24_error_intr(struct ata_port *ap) ehi->err_mask |= err_mask; ehi->action |= action; + + /* if PMP, resume */ + if (ap->nr_pmp_links) + writel(PORT_CS_PMP_RESUME, port + PORT_CTRL_STAT); } /* freeze or abort */ if (freeze) ata_port_freeze(ap); - else - ata_port_abort(ap); + else if (abort) { + if (qc) + ata_link_abort(qc->dev->link); + else + ata_port_abort(ap); + } } static void sil24_finish_qc(struct ata_queued_cmd *qc) @@ -910,7 +1130,7 @@ static inline void sil24_host_intr(struct ata_port *ap) if (rc > 0) return; if (rc < 0) { - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; ehi->err_mask |= AC_ERR_HSM; ehi->action |= ATA_EH_SOFTRESET; ata_port_freeze(ap); @@ -921,7 +1141,7 @@ static inline void sil24_host_intr(struct ata_port *ap) if (!(ap->flags & SIL24_FLAG_PCIX_IRQ_WOC) && ata_ratelimit()) ata_port_printk(ap, KERN_INFO, "spurious interrupt " "(slot_stat 0x%x active_tag %d sactive 0x%x)\n", - slot_stat, ap->active_tag, ap->sactive); + slot_stat, ap->link.active_tag, ap->link.sactive); } static irqreturn_t sil24_interrupt(int irq, void *dev_instance) @@ -963,16 +1183,18 @@ static irqreturn_t sil24_interrupt(int irq, void *dev_instance) static void sil24_error_handler(struct ata_port *ap) { - struct ata_eh_context *ehc = &ap->eh_context; + struct sil24_port_priv *pp = ap->private_data; - if (sil24_init_port(ap)) { + if (sil24_init_port(ap)) ata_eh_freeze_port(ap); - ehc->i.action |= ATA_EH_HARDRESET; - } /* perform recovery */ - ata_do_eh(ap, ata_std_prereset, sil24_softreset, sil24_hardreset, - ata_std_postreset); + sata_pmp_do_eh(ap, ata_std_prereset, sil24_softreset, sil24_hardreset, + ata_std_postreset, sata_pmp_std_prereset, + sil24_pmp_softreset, sil24_pmp_hardreset, + sata_pmp_std_postreset); + + pp->do_port_rst = 0; } static void sil24_post_internal_cmd(struct ata_queued_cmd *qc) @@ -980,8 +1202,8 @@ static void sil24_post_internal_cmd(struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; /* make DMA engine forget about the failed command */ - if (qc->flags & ATA_QCFLAG_FAILED) - sil24_init_port(ap); + if ((qc->flags & ATA_QCFLAG_FAILED) && sil24_init_port(ap)) + ata_eh_freeze_port(ap); } static int sil24_port_start(struct ata_port *ap) @@ -1019,7 +1241,6 @@ static int sil24_port_start(struct ata_port *ap) static void sil24_init_controller(struct ata_host *host) { void __iomem *host_base = host->iomap[SIL24_HOST_BAR]; - void __iomem *port_base = host->iomap[SIL24_PORT_BAR]; u32 tmp; int i; @@ -1031,7 +1252,8 @@ static void sil24_init_controller(struct ata_host *host) /* init ports */ for (i = 0; i < host->n_ports; i++) { - void __iomem *port = port_base + i * PORT_REGS_SIZE; + struct ata_port *ap = host->ports[i]; + void __iomem *port = ap->ioaddr.cmd_addr; /* Initial PHY setting */ writel(0x20c, port + PORT_PHY_CFG); @@ -1048,26 +1270,8 @@ static void sil24_init_controller(struct ata_host *host) "failed to clear port RST\n"); } - /* Configure IRQ WoC */ - if (host->ports[0]->flags & SIL24_FLAG_PCIX_IRQ_WOC) - writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT); - else - writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR); - - /* Zero error counters. */ - writel(0x8000, port + PORT_DECODE_ERR_THRESH); - writel(0x8000, port + PORT_CRC_ERR_THRESH); - writel(0x8000, port + PORT_HSHK_ERR_THRESH); - writel(0x0000, port + PORT_DECODE_ERR_CNT); - writel(0x0000, port + PORT_CRC_ERR_CNT); - writel(0x0000, port + PORT_HSHK_ERR_CNT); - - /* Always use 64bit activation */ - writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR); - - /* Clear port multiplier enable and resume bits */ - writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME, - port + PORT_CTRL_CLR); + /* configure port */ + sil24_config_port(ap); } /* Turn on interrupts */ @@ -1118,12 +1322,15 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) host->iomap = iomap; for (i = 0; i < host->n_ports; i++) { - void __iomem *port = iomap[SIL24_PORT_BAR] + i * PORT_REGS_SIZE; + struct ata_port *ap = host->ports[i]; + size_t offset = ap->port_no * PORT_REGS_SIZE; + void __iomem *port = iomap[SIL24_PORT_BAR] + offset; host->ports[i]->ioaddr.cmd_addr = port; host->ports[i]->ioaddr.scr_addr = port + PORT_SCONTROL; - ata_std_ports(&host->ports[i]->ioaddr); + ata_port_pbar_desc(ap, SIL24_HOST_BAR, -1, "host"); + ata_port_pbar_desc(ap, SIL24_PORT_BAR, offset, "port"); } /* configure and activate the device */ @@ -1179,6 +1386,12 @@ static int sil24_pci_device_resume(struct pci_dev *pdev) return 0; } + +static int sil24_port_resume(struct ata_port *ap) +{ + sil24_config_pmp(ap, ap->nr_pmp_links); + return 0; +} #endif static int __init sil24_init(void) diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c index 41c1d6e8f1fe..8d98a9fb0a42 100644 --- a/drivers/ata/sata_sis.c +++ b/drivers/ata/sata_sis.c @@ -104,7 +104,6 @@ static struct scsi_host_template sis_sht = { }; static const struct ata_port_operations sis_ops = { - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -123,7 +122,6 @@ static const struct ata_port_operations sis_ops = { .post_internal_cmd = ata_bmdma_post_internal_cmd, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = sis_scr_read, .scr_write = sis_scr_write, .port_start = ata_port_start, diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c index d9678e7bc3a9..12d613c48c19 100644 --- a/drivers/ata/sata_svw.c +++ b/drivers/ata/sata_svw.c @@ -329,7 +329,6 @@ static struct scsi_host_template k2_sata_sht = { static const struct ata_port_operations k2_sata_ops = { - .port_disable = ata_port_disable, .tf_load = k2_sata_tf_load, .tf_read = k2_sata_tf_read, .check_status = k2_stat_check_status, @@ -349,7 +348,6 @@ static const struct ata_port_operations k2_sata_ops = { .post_internal_cmd = ata_bmdma_post_internal_cmd, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = k2_sata_scr_read, .scr_write = k2_sata_scr_write, .port_start = ata_port_start, @@ -445,9 +443,15 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e /* different controllers have different number of ports - currently 4 or 8 */ /* All ports are on the same function. Multi-function device is no * longer available. This should not be seen in any system. */ - for (i = 0; i < host->n_ports; i++) - k2_sata_setup_port(&host->ports[i]->ioaddr, - mmio_base + i * K2_SATA_PORT_OFFSET); + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + unsigned int offset = i * K2_SATA_PORT_OFFSET; + + k2_sata_setup_port(&ap->ioaddr, mmio_base + offset); + + ata_port_pbar_desc(ap, 5, -1, "mmio"); + ata_port_pbar_desc(ap, 5, offset, "port"); + } rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index 97aefdd87be4..9f9f7b30654a 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -254,7 +254,6 @@ static struct scsi_host_template pdc_sata_sht = { }; static const struct ata_port_operations pdc_20621_ops = { - .port_disable = ata_port_disable, .tf_load = pdc_tf_load_mmio, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -267,7 +266,6 @@ static const struct ata_port_operations pdc_20621_ops = { .eng_timeout = pdc_eng_timeout, .irq_clear = pdc20621_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = pdc_port_start, }; @@ -854,7 +852,7 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance) !(ap->flags & ATA_FLAG_DISABLED)) { struct ata_queued_cmd *qc; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) handled += pdc20621_host_intr(ap, qc, (i > 4), mmio_base); @@ -881,7 +879,7 @@ static void pdc_eng_timeout(struct ata_port *ap) spin_lock_irqsave(&host->lock, flags); - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); switch (qc->tf.protocol) { case ATA_PROT_DMA: @@ -1383,9 +1381,8 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id * const struct ata_port_info *ppi[] = { &pdc_port_info[ent->driver_data], NULL }; struct ata_host *host; - void __iomem *base; struct pdc_host_priv *hpriv; - int rc; + int i, rc; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); @@ -1411,11 +1408,17 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id * return rc; host->iomap = pcim_iomap_table(pdev); - base = host->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS; - pdc_sata_setup_port(&host->ports[0]->ioaddr, base + 0x200); - pdc_sata_setup_port(&host->ports[1]->ioaddr, base + 0x280); - pdc_sata_setup_port(&host->ports[2]->ioaddr, base + 0x300); - pdc_sata_setup_port(&host->ports[3]->ioaddr, base + 0x380); + for (i = 0; i < 4; i++) { + struct ata_port *ap = host->ports[i]; + void __iomem *base = host->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS; + unsigned int offset = 0x200 + i * 0x80; + + pdc_sata_setup_port(&ap->ioaddr, base + offset); + + ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio"); + ata_port_pbar_desc(ap, PDC_DIMM_BAR, -1, "dimm"); + ata_port_pbar_desc(ap, PDC_MMIO_BAR, offset, "port"); + } /* configure and activate */ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c index e6b8b45279af..d394da085ae4 100644 --- a/drivers/ata/sata_uli.c +++ b/drivers/ata/sata_uli.c @@ -94,8 +94,6 @@ static struct scsi_host_template uli_sht = { }; static const struct ata_port_operations uli_ops = { - .port_disable = ata_port_disable, - .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -117,7 +115,6 @@ static const struct ata_port_operations uli_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = uli_scr_read, .scr_write = uli_scr_write, @@ -242,6 +239,12 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) hpriv->scr_cfg_addr[2] = ULI5287_BASE + ULI5287_OFFS*4; ata_std_ports(ioaddr); + ata_port_desc(host->ports[2], + "cmd 0x%llx ctl 0x%llx bmdma 0x%llx", + (unsigned long long)pci_resource_start(pdev, 0) + 8, + ((unsigned long long)pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS) + 4, + (unsigned long long)pci_resource_start(pdev, 4) + 16); + ioaddr = &host->ports[3]->ioaddr; ioaddr->cmd_addr = iomap[2] + 8; ioaddr->altstatus_addr = @@ -250,6 +253,13 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ioaddr->bmdma_addr = iomap[4] + 24; hpriv->scr_cfg_addr[3] = ULI5287_BASE + ULI5287_OFFS*5; ata_std_ports(ioaddr); + + ata_port_desc(host->ports[2], + "cmd 0x%llx ctl 0x%llx bmdma 0x%llx", + (unsigned long long)pci_resource_start(pdev, 2) + 9, + ((unsigned long long)pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS) + 4, + (unsigned long long)pci_resource_start(pdev, 4) + 24); + break; case uli_5289: diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 57fd30de8f0d..cc6ee0890f56 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -57,7 +57,6 @@ enum { SATA_CHAN_ENAB = 0x40, /* SATA channel enable */ SATA_INT_GATE = 0x41, /* SATA interrupt gating */ SATA_NATIVE_MODE = 0x42, /* Native mode enable */ - 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 */ @@ -68,7 +67,6 @@ enum { NATIVE_MODE_ALL = (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4), SATA_EXT_PHY = (1 << 6), /* 0==use PATA, 1==ext phy */ - SATA_2DEV = (1 << 5), /* SATA is master/slave */ }; static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); @@ -122,8 +120,6 @@ static struct scsi_host_template svia_sht = { }; static const struct ata_port_operations vt6420_sata_ops = { - .port_disable = ata_port_disable, - .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -146,14 +142,11 @@ static const struct ata_port_operations vt6420_sata_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; 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, @@ -180,14 +173,11 @@ static const struct ata_port_operations vt6421_pata_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; 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, @@ -211,7 +201,6 @@ static const struct ata_port_operations vt6421_sata_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = svia_scr_read, .scr_write = svia_scr_write, @@ -276,7 +265,7 @@ static void svia_noop_freeze(struct ata_port *ap) /** * vt6420_prereset - prereset for vt6420 - * @ap: target ATA port + * @link: target ATA link * @deadline: deadline jiffies for the operation * * SCR registers on vt6420 are pieces of shit and may hang the @@ -294,9 +283,10 @@ static void svia_noop_freeze(struct ata_port *ap) * RETURNS: * 0 on success, -errno otherwise. */ -static int vt6420_prereset(struct ata_port *ap, unsigned long deadline) +static int vt6420_prereset(struct ata_link *link, unsigned long deadline) { - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_port *ap = link->ap; + struct ata_eh_context *ehc = &ap->link.eh_context; unsigned long timeout = jiffies + (HZ * 5); u32 sstatus, scontrol; int online; @@ -407,6 +397,9 @@ static void vt6421_init_addrs(struct ata_port *ap) ioaddr->scr_addr = vt6421_scr_addr(iomap[5], ap->port_no); ata_std_ports(ioaddr); + + ata_port_pbar_desc(ap, ap->port_no, -1, "port"); + ata_port_pbar_desc(ap, 4, ap->port_no * 8, "bmdma"); } static int vt6420_prepare_host(struct pci_dev *pdev, struct ata_host **r_host) @@ -512,8 +505,7 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) int rc; struct ata_host *host; int board_id = (int) ent->driver_data; - const int *bar_sizes; - u8 tmp8; + const unsigned *bar_sizes; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); @@ -522,19 +514,10 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; - if (board_id == vt6420) { - pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8); - if (tmp8 & SATA_2DEV) { - dev_printk(KERN_ERR, &pdev->dev, - "SATA master/slave not supported (0x%x)\n", - (int) tmp8); - return -EIO; - } - + if (board_id == vt6420) bar_sizes = &svia_bar_sizes[0]; - } else { + else bar_sizes = &vt6421_bar_sizes[0]; - } for (i = 0; i < ARRAY_SIZE(svia_bar_sizes); i++) if ((pci_resource_start(pdev, i) == 0) || diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c index 1920915dfa2c..0d9be1684873 100644 --- a/drivers/ata/sata_vsc.c +++ b/drivers/ata/sata_vsc.c @@ -240,7 +240,7 @@ static void vsc_port_intr(u8 port_status, struct ata_port *ap) return; } - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && likely(!(qc->tf.flags & ATA_TFLAG_POLLING))) handled = ata_host_intr(ap, qc); @@ -317,7 +317,6 @@ static struct scsi_host_template vsc_sata_sht = { static const struct ata_port_operations vsc_sata_ops = { - .port_disable = ata_port_disable, .tf_load = vsc_sata_tf_load, .tf_read = vsc_sata_tf_read, .exec_command = ata_exec_command, @@ -336,7 +335,6 @@ static const struct ata_port_operations vsc_sata_ops = { .post_internal_cmd = ata_bmdma_post_internal_cmd, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = vsc_sata_scr_read, .scr_write = vsc_sata_scr_write, .port_start = ata_port_start, @@ -408,9 +406,15 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d mmio_base = host->iomap[VSC_MMIO_BAR]; - for (i = 0; i < host->n_ports; i++) - vsc_sata_setup_port(&host->ports[i]->ioaddr, - mmio_base + (i + 1) * VSC_SATA_PORT_OFFSET); + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + unsigned int offset = (i + 1) * VSC_SATA_PORT_OFFSET; + + vsc_sata_setup_port(&ap->ioaddr, mmio_base + offset); + + ata_port_pbar_desc(ap, VSC_MMIO_BAR, -1, "mmio"); + ata_port_pbar_desc(ap, VSC_MMIO_BAR, offset, "port"); + } /* * Use 32 bit DMA mask, because 64 bit address support is poor. diff --git a/drivers/atm/ambassador.h b/drivers/atm/ambassador.h index 8296420ceaef..ff2a303cbe00 100644 --- a/drivers/atm/ambassador.h +++ b/drivers/atm/ambassador.h @@ -626,7 +626,7 @@ typedef struct { struct amb_dev { u8 irq; - long flags; + unsigned long flags; u32 iobase; u32 * membase; diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c index 737cea49f872..94ebc9dc40fd 100644 --- a/drivers/atm/firestream.c +++ b/drivers/atm/firestream.c @@ -1295,7 +1295,7 @@ static const struct atmdev_ops ops = { static void __devinit undocumented_pci_fix (struct pci_dev *pdev) { - int tint; + u32 tint; /* The Windows driver says: */ /* Switch off FireStream Retry Limit Threshold diff --git a/drivers/atm/horizon.h b/drivers/atm/horizon.h index 4461229f56a5..b48859d0d434 100644 --- a/drivers/atm/horizon.h +++ b/drivers/atm/horizon.h @@ -423,7 +423,7 @@ struct hrz_dev { wait_queue_head_t tx_queue; u8 irq; - long flags; + unsigned long flags; u8 tx_last; u8 tx_idle; diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 5d6312e33490..d7da109c24fd 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -1,5 +1,13 @@ menu "Generic Driver Options" +config UEVENT_HELPER_PATH + string "path to uevent helper" + depends on HOTPLUG + default "/sbin/hotplug" + help + Path to uevent helper program forked by the kernel for + every uevent. + config STANDALONE bool "Select only drivers that don't need compile-time external firmware" if EXPERIMENTAL default y diff --git a/drivers/base/base.h b/drivers/base/base.h index 47eb02d9f1af..10b2fb6c9ce6 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -18,8 +18,6 @@ extern int attribute_container_init(void); extern int bus_add_device(struct device * dev); extern void bus_attach_device(struct device * dev); extern void bus_remove_device(struct device * dev); -extern struct bus_type *get_bus(struct bus_type * bus); -extern void put_bus(struct bus_type * bus); extern int bus_add_driver(struct device_driver *); extern void bus_remove_driver(struct device_driver *); diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 61c67526a656..9a19b071c573 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -30,6 +30,17 @@ static int __must_check bus_rescan_devices_helper(struct device *dev, void *data); +static struct bus_type *bus_get(struct bus_type *bus) +{ + return bus ? container_of(kset_get(&bus->subsys), + struct bus_type, subsys) : NULL; +} + +static void bus_put(struct bus_type *bus) +{ + kset_put(&bus->subsys); +} + static ssize_t drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) { @@ -78,7 +89,7 @@ static void driver_release(struct kobject * kobj) */ } -static struct kobj_type ktype_driver = { +static struct kobj_type driver_ktype = { .sysfs_ops = &driver_sysfs_ops, .release = driver_release, }; @@ -122,9 +133,9 @@ static struct sysfs_ops bus_sysfs_ops = { int bus_create_file(struct bus_type * bus, struct bus_attribute * attr) { int error; - if (get_bus(bus)) { + if (bus_get(bus)) { error = sysfs_create_file(&bus->subsys.kobj, &attr->attr); - put_bus(bus); + bus_put(bus); } else error = -EINVAL; return error; @@ -132,9 +143,9 @@ int bus_create_file(struct bus_type * bus, struct bus_attribute * attr) void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr) { - if (get_bus(bus)) { + if (bus_get(bus)) { sysfs_remove_file(&bus->subsys.kobj, &attr->attr); - put_bus(bus); + bus_put(bus); } } @@ -172,7 +183,7 @@ static int driver_helper(struct device *dev, void *data) static ssize_t driver_unbind(struct device_driver *drv, const char *buf, size_t count) { - struct bus_type *bus = get_bus(drv->bus); + struct bus_type *bus = bus_get(drv->bus); struct device *dev; int err = -ENODEV; @@ -186,7 +197,7 @@ static ssize_t driver_unbind(struct device_driver *drv, err = count; } put_device(dev); - put_bus(bus); + bus_put(bus); return err; } static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind); @@ -199,7 +210,7 @@ static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind); static ssize_t driver_bind(struct device_driver *drv, const char *buf, size_t count) { - struct bus_type *bus = get_bus(drv->bus); + struct bus_type *bus = bus_get(drv->bus); struct device *dev; int err = -ENODEV; @@ -219,7 +230,7 @@ static ssize_t driver_bind(struct device_driver *drv, err = -ENODEV; } put_device(dev); - put_bus(bus); + bus_put(bus); return err; } static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind); @@ -430,7 +441,7 @@ static inline void remove_deprecated_bus_links(struct device *dev) { } */ int bus_add_device(struct device * dev) { - struct bus_type * bus = get_bus(dev->bus); + struct bus_type * bus = bus_get(dev->bus); int error = 0; if (bus) { @@ -459,7 +470,7 @@ out_subsys: out_id: device_remove_attrs(bus, dev); out_put: - put_bus(dev->bus); + bus_put(dev->bus); return error; } @@ -509,7 +520,7 @@ void bus_remove_device(struct device * dev) } pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id); device_release_driver(dev); - put_bus(dev->bus); + bus_put(dev->bus); } } @@ -568,32 +579,29 @@ static void remove_bind_files(struct device_driver *drv) driver_remove_file(drv, &driver_attr_unbind); } +static BUS_ATTR(drivers_probe, S_IWUSR, NULL, store_drivers_probe); +static BUS_ATTR(drivers_autoprobe, S_IWUSR | S_IRUGO, + show_drivers_autoprobe, store_drivers_autoprobe); + static int add_probe_files(struct bus_type *bus) { int retval; - bus->drivers_probe_attr.attr.name = "drivers_probe"; - bus->drivers_probe_attr.attr.mode = S_IWUSR; - bus->drivers_probe_attr.store = store_drivers_probe; - retval = bus_create_file(bus, &bus->drivers_probe_attr); + retval = bus_create_file(bus, &bus_attr_drivers_probe); if (retval) goto out; - bus->drivers_autoprobe_attr.attr.name = "drivers_autoprobe"; - bus->drivers_autoprobe_attr.attr.mode = S_IWUSR | S_IRUGO; - bus->drivers_autoprobe_attr.show = show_drivers_autoprobe; - bus->drivers_autoprobe_attr.store = store_drivers_autoprobe; - retval = bus_create_file(bus, &bus->drivers_autoprobe_attr); + retval = bus_create_file(bus, &bus_attr_drivers_autoprobe); if (retval) - bus_remove_file(bus, &bus->drivers_probe_attr); + bus_remove_file(bus, &bus_attr_drivers_probe); out: return retval; } static void remove_probe_files(struct bus_type *bus) { - bus_remove_file(bus, &bus->drivers_autoprobe_attr); - bus_remove_file(bus, &bus->drivers_probe_attr); + bus_remove_file(bus, &bus_attr_drivers_autoprobe); + bus_remove_file(bus, &bus_attr_drivers_probe); } #else static inline int add_bind_files(struct device_driver *drv) { return 0; } @@ -602,6 +610,17 @@ static inline int add_probe_files(struct bus_type *bus) { return 0; } static inline void remove_probe_files(struct bus_type *bus) {} #endif +static ssize_t driver_uevent_store(struct device_driver *drv, + const char *buf, size_t count) +{ + enum kobject_action action; + + if (kobject_action_type(buf, count, &action) == 0) + kobject_uevent(&drv->kobj, action); + return count; +} +static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store); + /** * bus_add_driver - Add a driver to the bus. * @drv: driver. @@ -609,7 +628,7 @@ static inline void remove_probe_files(struct bus_type *bus) {} */ int bus_add_driver(struct device_driver *drv) { - struct bus_type * bus = get_bus(drv->bus); + struct bus_type * bus = bus_get(drv->bus); int error = 0; if (!bus) @@ -632,6 +651,11 @@ int bus_add_driver(struct device_driver *drv) klist_add_tail(&drv->knode_bus, &bus->klist_drivers); module_add_driver(drv->owner, drv); + error = driver_create_file(drv, &driver_attr_uevent); + if (error) { + printk(KERN_ERR "%s: uevent attr (%s) failed\n", + __FUNCTION__, drv->name); + } error = driver_add_attrs(bus, drv); if (error) { /* How the hell do we get out of this pickle? Give up */ @@ -649,7 +673,7 @@ int bus_add_driver(struct device_driver *drv) out_unregister: kobject_unregister(&drv->kobj); out_put_bus: - put_bus(bus); + bus_put(bus); return error; } @@ -669,12 +693,13 @@ void bus_remove_driver(struct device_driver * drv) remove_bind_files(drv); driver_remove_attrs(drv->bus, drv); + driver_remove_file(drv, &driver_attr_uevent); klist_remove(&drv->knode_bus); pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name); driver_detach(drv); module_remove_driver(drv); kobject_unregister(&drv->kobj); - put_bus(drv->bus); + bus_put(drv->bus); } @@ -729,18 +754,6 @@ int device_reprobe(struct device *dev) } EXPORT_SYMBOL_GPL(device_reprobe); -struct bus_type *get_bus(struct bus_type *bus) -{ - return bus ? container_of(subsys_get(&bus->subsys), - struct bus_type, subsys) : NULL; -} - -void put_bus(struct bus_type * bus) -{ - subsys_put(&bus->subsys); -} - - /** * find_bus - locate bus by name. * @name: name of bus. @@ -808,6 +821,17 @@ static void klist_devices_put(struct klist_node *n) put_device(dev); } +static ssize_t bus_uevent_store(struct bus_type *bus, + const char *buf, size_t count) +{ + enum kobject_action action; + + if (kobject_action_type(buf, count, &action) == 0) + kobject_uevent(&bus->subsys.kobj, action); + return count; +} +static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store); + /** * bus_register - register a bus with the system. * @bus: bus. @@ -826,11 +850,16 @@ int bus_register(struct bus_type * bus) if (retval) goto out; - subsys_set_kset(bus, bus_subsys); + bus->subsys.kobj.kset = &bus_subsys; + retval = subsystem_register(&bus->subsys); if (retval) goto out; + retval = bus_create_file(bus, &bus_attr_uevent); + if (retval) + goto bus_uevent_fail; + kobject_set_name(&bus->devices.kobj, "devices"); bus->devices.kobj.parent = &bus->subsys.kobj; retval = kset_register(&bus->devices); @@ -839,7 +868,7 @@ int bus_register(struct bus_type * bus) kobject_set_name(&bus->drivers.kobj, "drivers"); bus->drivers.kobj.parent = &bus->subsys.kobj; - bus->drivers.ktype = &ktype_driver; + bus->drivers.ktype = &driver_ktype; retval = kset_register(&bus->drivers); if (retval) goto bus_drivers_fail; @@ -866,6 +895,8 @@ bus_probe_files_fail: bus_drivers_fail: kset_unregister(&bus->devices); bus_devices_fail: + bus_remove_file(bus, &bus_attr_uevent); +bus_uevent_fail: subsystem_unregister(&bus->subsys); out: return retval; @@ -876,7 +907,7 @@ out: * @bus: bus. * * Unregister the child subsystems and the bus itself. - * Finally, we call put_bus() to release the refcount + * Finally, we call bus_put() to release the refcount */ void bus_unregister(struct bus_type * bus) { @@ -885,6 +916,7 @@ void bus_unregister(struct bus_type * bus) remove_probe_files(bus); kset_unregister(&bus->drivers); kset_unregister(&bus->devices); + bus_remove_file(bus, &bus_attr_uevent); subsystem_unregister(&bus->subsys); } diff --git a/drivers/base/class.c b/drivers/base/class.c index 4d2222618b78..a863bb091e11 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -65,13 +65,13 @@ static struct sysfs_ops class_sysfs_ops = { .store = class_attr_store, }; -static struct kobj_type ktype_class = { +static struct kobj_type class_ktype = { .sysfs_ops = &class_sysfs_ops, .release = class_release, }; /* Hotplug events for classes go to the class_obj subsys */ -static decl_subsys(class, &ktype_class, NULL); +static decl_subsys(class, &class_ktype, NULL); int class_create_file(struct class * cls, const struct class_attribute * attr) @@ -93,14 +93,14 @@ void class_remove_file(struct class * cls, const struct class_attribute * attr) static struct class *class_get(struct class *cls) { if (cls) - return container_of(subsys_get(&cls->subsys), struct class, subsys); + return container_of(kset_get(&cls->subsys), struct class, subsys); return NULL; } static void class_put(struct class * cls) { if (cls) - subsys_put(&cls->subsys); + kset_put(&cls->subsys); } @@ -149,7 +149,7 @@ int class_register(struct class * cls) if (error) return error; - subsys_set_kset(cls, class_subsys); + cls->subsys.kobj.kset = &class_subsys; error = subsystem_register(&cls->subsys); if (!error) { @@ -180,8 +180,7 @@ static void class_device_create_release(struct class_device *class_dev) /* needed to allow these devices to have parent class devices */ static int class_device_create_uevent(struct class_device *class_dev, - char **envp, int num_envp, - char *buffer, int buffer_size) + struct kobj_uevent_env *env) { pr_debug("%s called for %s\n", __FUNCTION__, class_dev->class_id); return 0; @@ -324,7 +323,7 @@ static void class_dev_release(struct kobject * kobj) } } -static struct kobj_type ktype_class_device = { +static struct kobj_type class_device_ktype = { .sysfs_ops = &class_dev_sysfs_ops, .release = class_dev_release, }; @@ -333,7 +332,7 @@ static int class_uevent_filter(struct kset *kset, struct kobject *kobj) { struct kobj_type *ktype = get_ktype(kobj); - if (ktype == &ktype_class_device) { + if (ktype == &class_device_ktype) { struct class_device *class_dev = to_class_dev(kobj); if (class_dev->class) return 1; @@ -403,64 +402,43 @@ static void remove_deprecated_class_device_links(struct class_device *cd) { } #endif -static int class_uevent(struct kset *kset, struct kobject *kobj, char **envp, - int num_envp, char *buffer, int buffer_size) +static int class_uevent(struct kset *kset, struct kobject *kobj, + struct kobj_uevent_env *env) { struct class_device *class_dev = to_class_dev(kobj); struct device *dev = class_dev->dev; - int i = 0; - int length = 0; int retval = 0; pr_debug("%s - name = %s\n", __FUNCTION__, class_dev->class_id); if (MAJOR(class_dev->devt)) { - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MAJOR=%u", MAJOR(class_dev->devt)); + add_uevent_var(env, "MAJOR=%u", MAJOR(class_dev->devt)); - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MINOR=%u", MINOR(class_dev->devt)); + add_uevent_var(env, "MINOR=%u", MINOR(class_dev->devt)); } if (dev) { const char *path = kobject_get_path(&dev->kobj, GFP_KERNEL); if (path) { - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVPATH=%s", path); + add_uevent_var(env, "PHYSDEVPATH=%s", path); kfree(path); } if (dev->bus) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVBUS=%s", dev->bus->name); + add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name); if (dev->driver) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVDRIVER=%s", dev->driver->name); + add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name); } - /* terminate, set to next free slot, shrink available space */ - envp[i] = NULL; - envp = &envp[i]; - num_envp -= i; - buffer = &buffer[length]; - buffer_size -= length; - if (class_dev->uevent) { /* have the class device specific function add its stuff */ - retval = class_dev->uevent(class_dev, envp, num_envp, - buffer, buffer_size); + retval = class_dev->uevent(class_dev, env); if (retval) pr_debug("class_dev->uevent() returned %d\n", retval); } else if (class_dev->class->uevent) { /* have the class specific function add its stuff */ - retval = class_dev->class->uevent(class_dev, envp, num_envp, - buffer, buffer_size); + retval = class_dev->class->uevent(class_dev, env); if (retval) pr_debug("class->uevent() returned %d\n", retval); } @@ -474,7 +452,7 @@ static struct kset_uevent_ops class_uevent_ops = { .uevent = class_uevent, }; -static decl_subsys(class_obj, &ktype_class_device, &class_uevent_ops); +static decl_subsys(class_obj, &class_device_ktype, &class_uevent_ops); static int class_device_add_attrs(struct class_device * cd) @@ -883,7 +861,7 @@ int __init classes_init(void) /* ick, this is ugly, the things we go through to keep from showing up * in sysfs... */ - subsystem_init(&class_obj_subsys); + kset_init(&class_obj_subsys); if (!class_obj_subsys.kobj.parent) class_obj_subsys.kobj.parent = &class_obj_subsys.kobj; return 0; diff --git a/drivers/base/core.c b/drivers/base/core.c index ec86d6fc2360..c1343414d285 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -108,7 +108,7 @@ static void device_release(struct kobject * kobj) } } -static struct kobj_type ktype_device = { +static struct kobj_type device_ktype = { .release = device_release, .sysfs_ops = &dev_sysfs_ops, }; @@ -118,7 +118,7 @@ static int dev_uevent_filter(struct kset *kset, struct kobject *kobj) { struct kobj_type *ktype = get_ktype(kobj); - if (ktype == &ktype_device) { + if (ktype == &device_ktype) { struct device *dev = to_dev(kobj); if (dev->uevent_suppress) return 0; @@ -141,33 +141,23 @@ static const char *dev_uevent_name(struct kset *kset, struct kobject *kobj) return NULL; } -static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, - int num_envp, char *buffer, int buffer_size) +static int dev_uevent(struct kset *kset, struct kobject *kobj, + struct kobj_uevent_env *env) { struct device *dev = to_dev(kobj); - int i = 0; - int length = 0; int retval = 0; /* add the major/minor if present */ if (MAJOR(dev->devt)) { - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MAJOR=%u", MAJOR(dev->devt)); - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MINOR=%u", MINOR(dev->devt)); + add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt)); + add_uevent_var(env, "MINOR=%u", MINOR(dev->devt)); } if (dev->type && dev->type->name) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEVTYPE=%s", dev->type->name); + add_uevent_var(env, "DEVTYPE=%s", dev->type->name); if (dev->driver) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DRIVER=%s", dev->driver->name); + add_uevent_var(env, "DRIVER=%s", dev->driver->name); #ifdef CONFIG_SYSFS_DEPRECATED if (dev->class) { @@ -181,59 +171,43 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, path = kobject_get_path(&parent->kobj, GFP_KERNEL); if (path) { - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVPATH=%s", path); + add_uevent_var(env, "PHYSDEVPATH=%s", path); kfree(path); } - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVBUS=%s", parent->bus->name); + add_uevent_var(env, "PHYSDEVBUS=%s", parent->bus->name); if (parent->driver) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVDRIVER=%s", parent->driver->name); + add_uevent_var(env, "PHYSDEVDRIVER=%s", + parent->driver->name); } } else if (dev->bus) { - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVBUS=%s", dev->bus->name); + add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name); if (dev->driver) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVDRIVER=%s", dev->driver->name); + add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name); } #endif - /* terminate, set to next free slot, shrink available space */ - envp[i] = NULL; - envp = &envp[i]; - num_envp -= i; - buffer = &buffer[length]; - buffer_size -= length; - + /* have the bus specific function add its stuff */ if (dev->bus && dev->bus->uevent) { - /* have the bus specific function add its stuff */ - retval = dev->bus->uevent(dev, envp, num_envp, buffer, buffer_size); + retval = dev->bus->uevent(dev, env); if (retval) pr_debug ("%s: bus uevent() returned %d\n", __FUNCTION__, retval); } + /* have the class specific function add its stuff */ if (dev->class && dev->class->dev_uevent) { - /* have the class specific function add its stuff */ - retval = dev->class->dev_uevent(dev, envp, num_envp, buffer, buffer_size); + retval = dev->class->dev_uevent(dev, env); if (retval) pr_debug("%s: class uevent() returned %d\n", __FUNCTION__, retval); } + /* have the device type specific fuction add its stuff */ if (dev->type && dev->type->uevent) { - /* have the device type specific fuction add its stuff */ - retval = dev->type->uevent(dev, envp, num_envp, buffer, buffer_size); + retval = dev->type->uevent(dev, env); if (retval) pr_debug("%s: dev_type uevent() returned %d\n", __FUNCTION__, retval); @@ -253,22 +227,18 @@ static ssize_t show_uevent(struct device *dev, struct device_attribute *attr, { struct kobject *top_kobj; struct kset *kset; - char *envp[32]; - char *data = NULL; - char *pos; + struct kobj_uevent_env *env = NULL; int i; size_t count = 0; int retval; /* search the kset, the device belongs to */ top_kobj = &dev->kobj; - if (!top_kobj->kset && top_kobj->parent) { - do { - top_kobj = top_kobj->parent; - } while (!top_kobj->kset && top_kobj->parent); - } + while (!top_kobj->kset && top_kobj->parent) + top_kobj = top_kobj->parent; if (!top_kobj->kset) goto out; + kset = top_kobj->kset; if (!kset->uevent_ops || !kset->uevent_ops->uevent) goto out; @@ -278,43 +248,29 @@ static ssize_t show_uevent(struct device *dev, struct device_attribute *attr, if (!kset->uevent_ops->filter(kset, &dev->kobj)) goto out; - data = (char *)get_zeroed_page(GFP_KERNEL); - if (!data) + env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL); + if (!env) return -ENOMEM; /* let the kset specific function add its keys */ - pos = data; - memset(envp, 0, sizeof(envp)); - retval = kset->uevent_ops->uevent(kset, &dev->kobj, - envp, ARRAY_SIZE(envp), - pos, PAGE_SIZE); + retval = kset->uevent_ops->uevent(kset, &dev->kobj, env); if (retval) goto out; /* copy keys to file */ - for (i = 0; envp[i]; i++) { - pos = &buf[count]; - count += sprintf(pos, "%s\n", envp[i]); - } + for (i = 0; i < env->envp_idx; i++) + count += sprintf(&buf[count], "%s\n", env->envp[i]); out: - free_page((unsigned long)data); + kfree(env); return count; } static ssize_t store_uevent(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - size_t len = count; enum kobject_action action; - if (len && buf[len-1] == '\n') - len--; - - for (action = 0; action < KOBJ_MAX; action++) { - if (strncmp(kobject_actions[action], buf, len) != 0) - continue; - if (kobject_actions[action][len] != '\0') - continue; + if (kobject_action_type(buf, count, &action) == 0) { kobject_uevent(&dev->kobj, action); goto out; } @@ -449,7 +405,7 @@ static struct device_attribute devt_attr = * devices_subsys - structure to be registered with kobject core. */ -decl_subsys(devices, &ktype_device, &device_uevent_ops); +decl_subsys(devices, &device_ktype, &device_uevent_ops); /** diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index b24efd4e3e3d..0295855a3eef 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -88,19 +88,14 @@ static CLASS_ATTR(timeout, 0644, firmware_timeout_show, firmware_timeout_store); static void fw_dev_release(struct device *dev); -static int firmware_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env) { struct firmware_priv *fw_priv = dev_get_drvdata(dev); - int i = 0, len = 0; - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "FIRMWARE=%s", fw_priv->fw_id)) + if (add_uevent_var(env, "FIRMWARE=%s", fw_priv->fw_id)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "TIMEOUT=%i", loading_timeout)) + if (add_uevent_var(env, "TIMEOUT=%i", loading_timeout)) return -ENOMEM; - envp[i] = NULL; return 0; } @@ -297,8 +292,7 @@ firmware_class_timeout(u_long data) static inline void fw_setup_device_id(struct device *f_dev, struct device *dev) { - /* XXX warning we should watch out for name collisions */ - strlcpy(f_dev->bus_id, dev->bus_id, BUS_ID_SIZE); + snprintf(f_dev->bus_id, BUS_ID_SIZE, "firmware-%s", dev->bus_id); } static int fw_register_device(struct device **dev_p, const char *fw_name, diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 74b96795d2f5..7a1390cd6aad 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -34,8 +34,7 @@ static const char *memory_uevent_name(struct kset *kset, struct kobject *kobj) return MEMORY_CLASS_NAME; } -static int memory_uevent(struct kset *kset, struct kobject *kobj, char **envp, - int num_envp, char *buffer, int buffer_size) +static int memory_uevent(struct kset *kset, struct kobject *obj, struct kobj_uevent_env *env) { int retval = 0; diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 869ff8c00146..fb5609241482 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -160,13 +160,8 @@ static void platform_device_release(struct device *dev) * * Create a platform device object which can have other objects attached * to it, and which will have attached objects freed when it is released. - * - * This device will be marked as not supporting hotpluggable drivers; no - * device add/remove uevents will be generated. In the unusual case that - * the device isn't being dynamically allocated as a legacy "probe the - * hardware" driver, infrastructure code should reverse this marking. */ -struct platform_device *platform_device_alloc(const char *name, unsigned int id) +struct platform_device *platform_device_alloc(const char *name, int id) { struct platform_object *pa; @@ -177,12 +172,6 @@ struct platform_device *platform_device_alloc(const char *name, unsigned int id) pa->pdev.id = id; device_initialize(&pa->pdev.dev); pa->pdev.dev.release = platform_device_release; - - /* prevent hotplug "modprobe $(MODALIAS)" from causing trouble in - * legacy probe-the-hardware drivers, which don't properly split - * out device enumeration logic from drivers. - */ - pa->pdev.dev.uevent_suppress = 1; } return pa ? &pa->pdev : NULL; @@ -256,7 +245,8 @@ int platform_device_add(struct platform_device *pdev) pdev->dev.bus = &platform_bus_type; if (pdev->id != -1) - snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%u", pdev->name, pdev->id); + snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%d", pdev->name, + pdev->id); else strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE); @@ -370,7 +360,7 @@ EXPORT_SYMBOL_GPL(platform_device_unregister); * the Linux driver model. In particular, when such drivers are built * as modules, they can't be "hotplugged". */ -struct platform_device *platform_device_register_simple(char *name, unsigned int id, +struct platform_device *platform_device_register_simple(char *name, int id, struct resource *res, unsigned int num) { struct platform_device *pdev; @@ -530,7 +520,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a, char *buf) { struct platform_device *pdev = to_platform_device(dev); - int len = snprintf(buf, PAGE_SIZE, "%s\n", pdev->name); + int len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name); return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; } @@ -540,13 +530,11 @@ static struct device_attribute platform_dev_attrs[] = { __ATTR_NULL, }; -static int platform_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int platform_uevent(struct device *dev, struct kobj_uevent_env *env) { struct platform_device *pdev = to_platform_device(dev); - envp[0] = buffer; - snprintf(buffer, buffer_size, "MODALIAS=%s", pdev->name); + add_uevent_var(env, "MODALIAS=platform:%s", pdev->name); return 0; } diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile index 9caeaea753a3..a803733c839e 100644 --- a/drivers/base/power/Makefile +++ b/drivers/base/power/Makefile @@ -1,5 +1,5 @@ obj-y := shutdown.o -obj-$(CONFIG_PM_SLEEP) += main.o suspend.o resume.o sysfs.o +obj-$(CONFIG_PM_SLEEP) += main.o sysfs.o obj-$(CONFIG_PM_TRACE) += trace.o ifeq ($(CONFIG_DEBUG_DRIVER),y) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index eb9f38d0aa58..0ab4ab21f564 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -20,19 +20,24 @@ */ #include <linux/device.h> +#include <linux/kallsyms.h> #include <linux/mutex.h> +#include <linux/pm.h> +#include <linux/resume-trace.h> +#include "../base.h" #include "power.h" LIST_HEAD(dpm_active); -LIST_HEAD(dpm_off); -LIST_HEAD(dpm_off_irq); +static LIST_HEAD(dpm_off); +static LIST_HEAD(dpm_off_irq); -DEFINE_MUTEX(dpm_mtx); -DEFINE_MUTEX(dpm_list_mtx); +static DEFINE_MUTEX(dpm_mtx); +static DEFINE_MUTEX(dpm_list_mtx); int (*platform_enable_wakeup)(struct device *dev, int is_on); + int device_pm_add(struct device *dev) { int error; @@ -61,3 +66,334 @@ void device_pm_remove(struct device *dev) } +/*------------------------- Resume routines -------------------------*/ + +/** + * resume_device - Restore state for one device. + * @dev: Device. + * + */ + +static int resume_device(struct device * dev) +{ + int error = 0; + + TRACE_DEVICE(dev); + TRACE_RESUME(0); + + down(&dev->sem); + + if (dev->bus && dev->bus->resume) { + dev_dbg(dev,"resuming\n"); + error = dev->bus->resume(dev); + } + + if (!error && dev->type && dev->type->resume) { + dev_dbg(dev,"resuming\n"); + error = dev->type->resume(dev); + } + + if (!error && dev->class && dev->class->resume) { + dev_dbg(dev,"class resume\n"); + error = dev->class->resume(dev); + } + + up(&dev->sem); + + TRACE_RESUME(error); + return error; +} + + +static int resume_device_early(struct device * dev) +{ + int error = 0; + + TRACE_DEVICE(dev); + TRACE_RESUME(0); + if (dev->bus && dev->bus->resume_early) { + dev_dbg(dev,"EARLY resume\n"); + error = dev->bus->resume_early(dev); + } + TRACE_RESUME(error); + return error; +} + +/* + * Resume the devices that have either not gone through + * the late suspend, or that did go through it but also + * went through the early resume + */ +static void dpm_resume(void) +{ + mutex_lock(&dpm_list_mtx); + while(!list_empty(&dpm_off)) { + struct list_head * entry = dpm_off.next; + struct device * dev = to_device(entry); + + get_device(dev); + list_move_tail(entry, &dpm_active); + + mutex_unlock(&dpm_list_mtx); + resume_device(dev); + mutex_lock(&dpm_list_mtx); + put_device(dev); + } + mutex_unlock(&dpm_list_mtx); +} + + +/** + * device_resume - Restore state of each device in system. + * + * Walk the dpm_off list, remove each entry, resume the device, + * then add it to the dpm_active list. + */ + +void device_resume(void) +{ + might_sleep(); + mutex_lock(&dpm_mtx); + dpm_resume(); + mutex_unlock(&dpm_mtx); +} + +EXPORT_SYMBOL_GPL(device_resume); + + +/** + * dpm_power_up - Power on some devices. + * + * Walk the dpm_off_irq list and power each device up. This + * is used for devices that required they be powered down with + * interrupts disabled. As devices are powered on, they are moved + * to the dpm_active list. + * + * Interrupts must be disabled when calling this. + */ + +static void dpm_power_up(void) +{ + while(!list_empty(&dpm_off_irq)) { + struct list_head * entry = dpm_off_irq.next; + struct device * dev = to_device(entry); + + list_move_tail(entry, &dpm_off); + resume_device_early(dev); + } +} + + +/** + * device_power_up - Turn on all devices that need special attention. + * + * Power on system devices then devices that required we shut them down + * with interrupts disabled. + * Called with interrupts disabled. + */ + +void device_power_up(void) +{ + sysdev_resume(); + dpm_power_up(); +} + +EXPORT_SYMBOL_GPL(device_power_up); + + +/*------------------------- Suspend routines -------------------------*/ + +/* + * The entries in the dpm_active list are in a depth first order, simply + * because children are guaranteed to be discovered after parents, and + * are inserted at the back of the list on discovery. + * + * All list on the suspend path are done in reverse order, so we operate + * on the leaves of the device tree (or forests, depending on how you want + * to look at it ;) first. As nodes are removed from the back of the list, + * they are inserted into the front of their destintation lists. + * + * Things are the reverse on the resume path - iterations are done in + * forward order, and nodes are inserted at the back of their destination + * lists. This way, the ancestors will be accessed before their descendents. + */ + +static inline char *suspend_verb(u32 event) +{ + switch (event) { + case PM_EVENT_SUSPEND: return "suspend"; + case PM_EVENT_FREEZE: return "freeze"; + case PM_EVENT_PRETHAW: return "prethaw"; + default: return "(unknown suspend event)"; + } +} + + +static void +suspend_device_dbg(struct device *dev, pm_message_t state, char *info) +{ + dev_dbg(dev, "%s%s%s\n", info, suspend_verb(state.event), + ((state.event == PM_EVENT_SUSPEND) && device_may_wakeup(dev)) ? + ", may wakeup" : ""); +} + +/** + * suspend_device - Save state of one device. + * @dev: Device. + * @state: Power state device is entering. + */ + +static int suspend_device(struct device * dev, pm_message_t state) +{ + int error = 0; + + down(&dev->sem); + if (dev->power.power_state.event) { + dev_dbg(dev, "PM: suspend %d-->%d\n", + dev->power.power_state.event, state.event); + } + + if (dev->class && dev->class->suspend) { + suspend_device_dbg(dev, state, "class "); + error = dev->class->suspend(dev, state); + suspend_report_result(dev->class->suspend, error); + } + + if (!error && dev->type && dev->type->suspend) { + suspend_device_dbg(dev, state, "type "); + error = dev->type->suspend(dev, state); + suspend_report_result(dev->type->suspend, error); + } + + if (!error && dev->bus && dev->bus->suspend) { + suspend_device_dbg(dev, state, ""); + error = dev->bus->suspend(dev, state); + suspend_report_result(dev->bus->suspend, error); + } + up(&dev->sem); + return error; +} + + +/* + * This is called with interrupts off, only a single CPU + * running. We can't acquire a mutex or semaphore (and we don't + * need the protection) + */ +static int suspend_device_late(struct device *dev, pm_message_t state) +{ + int error = 0; + + if (dev->bus && dev->bus->suspend_late) { + suspend_device_dbg(dev, state, "LATE "); + error = dev->bus->suspend_late(dev, state); + suspend_report_result(dev->bus->suspend_late, error); + } + return error; +} + +/** + * device_suspend - Save state and stop all devices in system. + * @state: Power state to put each device in. + * + * Walk the dpm_active list, call ->suspend() for each device, and move + * it to the dpm_off list. + * + * (For historical reasons, if it returns -EAGAIN, that used to mean + * that the device would be called again with interrupts disabled. + * These days, we use the "suspend_late()" callback for that, so we + * print a warning and consider it an error). + * + * If we get a different error, try and back out. + * + * If we hit a failure with any of the devices, call device_resume() + * above to bring the suspended devices back to life. + * + */ + +int device_suspend(pm_message_t state) +{ + int error = 0; + + might_sleep(); + mutex_lock(&dpm_mtx); + mutex_lock(&dpm_list_mtx); + while (!list_empty(&dpm_active) && error == 0) { + struct list_head * entry = dpm_active.prev; + struct device * dev = to_device(entry); + + get_device(dev); + mutex_unlock(&dpm_list_mtx); + + error = suspend_device(dev, state); + + mutex_lock(&dpm_list_mtx); + + /* Check if the device got removed */ + if (!list_empty(&dev->power.entry)) { + /* Move it to the dpm_off list */ + if (!error) + list_move(&dev->power.entry, &dpm_off); + } + if (error) + printk(KERN_ERR "Could not suspend device %s: " + "error %d%s\n", + kobject_name(&dev->kobj), error, + error == -EAGAIN ? " (please convert to suspend_late)" : ""); + put_device(dev); + } + mutex_unlock(&dpm_list_mtx); + if (error) + dpm_resume(); + + mutex_unlock(&dpm_mtx); + return error; +} + +EXPORT_SYMBOL_GPL(device_suspend); + +/** + * device_power_down - Shut down special devices. + * @state: Power state to enter. + * + * Walk the dpm_off_irq list, calling ->power_down() for each device that + * couldn't power down the device with interrupts enabled. When we're + * done, power down system devices. + */ + +int device_power_down(pm_message_t state) +{ + int error = 0; + struct device * dev; + + while (!list_empty(&dpm_off)) { + struct list_head * entry = dpm_off.prev; + + dev = to_device(entry); + error = suspend_device_late(dev, state); + if (error) + goto Error; + list_move(&dev->power.entry, &dpm_off_irq); + } + + error = sysdev_suspend(state); + Done: + return error; + Error: + printk(KERN_ERR "Could not power down device %s: " + "error %d\n", kobject_name(&dev->kobj), error); + dpm_power_up(); + goto Done; +} + +EXPORT_SYMBOL_GPL(device_power_down); + +void __suspend_report_result(const char *function, void *fn, int ret) +{ + if (ret) { + printk(KERN_ERR "%s(): ", function); + print_fn_descriptor_symbol("%s() returns ", (unsigned long)fn); + printk("%d\n", ret); + } +} +EXPORT_SYMBOL_GPL(__suspend_report_result); diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index 8ba0830cbc03..5c4efd493fa5 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -11,32 +11,11 @@ extern void device_shutdown(void); * main.c */ -/* - * Used to synchronize global power management operations. - */ -extern struct mutex dpm_mtx; - -/* - * Used to serialize changes to the dpm_* lists. - */ -extern struct mutex dpm_list_mtx; - -/* - * The PM lists. - */ -extern struct list_head dpm_active; -extern struct list_head dpm_off; -extern struct list_head dpm_off_irq; - - -static inline struct dev_pm_info * to_pm_info(struct list_head * entry) -{ - return container_of(entry, struct dev_pm_info, entry); -} +extern struct list_head dpm_active; /* The active device list */ static inline struct device * to_device(struct list_head * entry) { - return container_of(to_pm_info(entry), struct device, power); + return container_of(entry, struct device, power.entry); } extern int device_pm_add(struct device *); @@ -49,19 +28,6 @@ extern void device_pm_remove(struct device *); extern int dpm_sysfs_add(struct device *); extern void dpm_sysfs_remove(struct device *); -/* - * resume.c - */ - -extern void dpm_resume(void); -extern void dpm_power_up(void); -extern int resume_device(struct device *); - -/* - * suspend.c - */ -extern int suspend_device(struct device *, pm_message_t); - #else /* CONFIG_PM_SLEEP */ diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c deleted file mode 100644 index 00fd84ae6e66..000000000000 --- a/drivers/base/power/resume.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * resume.c - Functions for waking devices up. - * - * Copyright (c) 2003 Patrick Mochel - * Copyright (c) 2003 Open Source Development Labs - * - * This file is released under the GPLv2 - * - */ - -#include <linux/device.h> -#include <linux/resume-trace.h> -#include "../base.h" -#include "power.h" - - -/** - * resume_device - Restore state for one device. - * @dev: Device. - * - */ - -int resume_device(struct device * dev) -{ - int error = 0; - - TRACE_DEVICE(dev); - TRACE_RESUME(0); - - down(&dev->sem); - - if (dev->bus && dev->bus->resume) { - dev_dbg(dev,"resuming\n"); - error = dev->bus->resume(dev); - } - - if (!error && dev->type && dev->type->resume) { - dev_dbg(dev,"resuming\n"); - error = dev->type->resume(dev); - } - - if (!error && dev->class && dev->class->resume) { - dev_dbg(dev,"class resume\n"); - error = dev->class->resume(dev); - } - - up(&dev->sem); - - TRACE_RESUME(error); - return error; -} - - -static int resume_device_early(struct device * dev) -{ - int error = 0; - - TRACE_DEVICE(dev); - TRACE_RESUME(0); - if (dev->bus && dev->bus->resume_early) { - dev_dbg(dev,"EARLY resume\n"); - error = dev->bus->resume_early(dev); - } - TRACE_RESUME(error); - return error; -} - -/* - * Resume the devices that have either not gone through - * the late suspend, or that did go through it but also - * went through the early resume - */ -void dpm_resume(void) -{ - mutex_lock(&dpm_list_mtx); - while(!list_empty(&dpm_off)) { - struct list_head * entry = dpm_off.next; - struct device * dev = to_device(entry); - - get_device(dev); - list_move_tail(entry, &dpm_active); - - mutex_unlock(&dpm_list_mtx); - resume_device(dev); - mutex_lock(&dpm_list_mtx); - put_device(dev); - } - mutex_unlock(&dpm_list_mtx); -} - - -/** - * device_resume - Restore state of each device in system. - * - * Walk the dpm_off list, remove each entry, resume the device, - * then add it to the dpm_active list. - */ - -void device_resume(void) -{ - might_sleep(); - mutex_lock(&dpm_mtx); - dpm_resume(); - mutex_unlock(&dpm_mtx); -} - -EXPORT_SYMBOL_GPL(device_resume); - - -/** - * dpm_power_up - Power on some devices. - * - * Walk the dpm_off_irq list and power each device up. This - * is used for devices that required they be powered down with - * interrupts disabled. As devices are powered on, they are moved - * to the dpm_active list. - * - * Interrupts must be disabled when calling this. - */ - -void dpm_power_up(void) -{ - while(!list_empty(&dpm_off_irq)) { - struct list_head * entry = dpm_off_irq.next; - struct device * dev = to_device(entry); - - list_move_tail(entry, &dpm_off); - resume_device_early(dev); - } -} - - -/** - * device_power_up - Turn on all devices that need special attention. - * - * Power on system devices then devices that required we shut them down - * with interrupts disabled. - * Called with interrupts disabled. - */ - -void device_power_up(void) -{ - sysdev_resume(); - dpm_power_up(); -} - -EXPORT_SYMBOL_GPL(device_power_up); - - diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c deleted file mode 100644 index 26df9b231737..000000000000 --- a/drivers/base/power/suspend.c +++ /dev/null @@ -1,210 +0,0 @@ -/* - * suspend.c - Functions for putting devices to sleep. - * - * Copyright (c) 2003 Patrick Mochel - * Copyright (c) 2003 Open Source Development Labs - * - * This file is released under the GPLv2 - * - */ - -#include <linux/device.h> -#include <linux/kallsyms.h> -#include <linux/pm.h> -#include "../base.h" -#include "power.h" - -/* - * The entries in the dpm_active list are in a depth first order, simply - * because children are guaranteed to be discovered after parents, and - * are inserted at the back of the list on discovery. - * - * All list on the suspend path are done in reverse order, so we operate - * on the leaves of the device tree (or forests, depending on how you want - * to look at it ;) first. As nodes are removed from the back of the list, - * they are inserted into the front of their destintation lists. - * - * Things are the reverse on the resume path - iterations are done in - * forward order, and nodes are inserted at the back of their destination - * lists. This way, the ancestors will be accessed before their descendents. - */ - -static inline char *suspend_verb(u32 event) -{ - switch (event) { - case PM_EVENT_SUSPEND: return "suspend"; - case PM_EVENT_FREEZE: return "freeze"; - case PM_EVENT_PRETHAW: return "prethaw"; - default: return "(unknown suspend event)"; - } -} - - -static void -suspend_device_dbg(struct device *dev, pm_message_t state, char *info) -{ - dev_dbg(dev, "%s%s%s\n", info, suspend_verb(state.event), - ((state.event == PM_EVENT_SUSPEND) && device_may_wakeup(dev)) ? - ", may wakeup" : ""); -} - -/** - * suspend_device - Save state of one device. - * @dev: Device. - * @state: Power state device is entering. - */ - -int suspend_device(struct device * dev, pm_message_t state) -{ - int error = 0; - - down(&dev->sem); - if (dev->power.power_state.event) { - dev_dbg(dev, "PM: suspend %d-->%d\n", - dev->power.power_state.event, state.event); - } - - if (dev->class && dev->class->suspend) { - suspend_device_dbg(dev, state, "class "); - error = dev->class->suspend(dev, state); - suspend_report_result(dev->class->suspend, error); - } - - if (!error && dev->type && dev->type->suspend) { - suspend_device_dbg(dev, state, "type "); - error = dev->type->suspend(dev, state); - suspend_report_result(dev->type->suspend, error); - } - - if (!error && dev->bus && dev->bus->suspend) { - suspend_device_dbg(dev, state, ""); - error = dev->bus->suspend(dev, state); - suspend_report_result(dev->bus->suspend, error); - } - up(&dev->sem); - return error; -} - - -/* - * This is called with interrupts off, only a single CPU - * running. We can't acquire a mutex or semaphore (and we don't - * need the protection) - */ -static int suspend_device_late(struct device *dev, pm_message_t state) -{ - int error = 0; - - if (dev->bus && dev->bus->suspend_late) { - suspend_device_dbg(dev, state, "LATE "); - error = dev->bus->suspend_late(dev, state); - suspend_report_result(dev->bus->suspend_late, error); - } - return error; -} - -/** - * device_suspend - Save state and stop all devices in system. - * @state: Power state to put each device in. - * - * Walk the dpm_active list, call ->suspend() for each device, and move - * it to the dpm_off list. - * - * (For historical reasons, if it returns -EAGAIN, that used to mean - * that the device would be called again with interrupts disabled. - * These days, we use the "suspend_late()" callback for that, so we - * print a warning and consider it an error). - * - * If we get a different error, try and back out. - * - * If we hit a failure with any of the devices, call device_resume() - * above to bring the suspended devices back to life. - * - */ - -int device_suspend(pm_message_t state) -{ - int error = 0; - - might_sleep(); - mutex_lock(&dpm_mtx); - mutex_lock(&dpm_list_mtx); - while (!list_empty(&dpm_active) && error == 0) { - struct list_head * entry = dpm_active.prev; - struct device * dev = to_device(entry); - - get_device(dev); - mutex_unlock(&dpm_list_mtx); - - error = suspend_device(dev, state); - - mutex_lock(&dpm_list_mtx); - - /* Check if the device got removed */ - if (!list_empty(&dev->power.entry)) { - /* Move it to the dpm_off list */ - if (!error) - list_move(&dev->power.entry, &dpm_off); - } - if (error) - printk(KERN_ERR "Could not suspend device %s: " - "error %d%s\n", - kobject_name(&dev->kobj), error, - error == -EAGAIN ? " (please convert to suspend_late)" : ""); - put_device(dev); - } - mutex_unlock(&dpm_list_mtx); - if (error) - dpm_resume(); - - mutex_unlock(&dpm_mtx); - return error; -} - -EXPORT_SYMBOL_GPL(device_suspend); - -/** - * device_power_down - Shut down special devices. - * @state: Power state to enter. - * - * Walk the dpm_off_irq list, calling ->power_down() for each device that - * couldn't power down the device with interrupts enabled. When we're - * done, power down system devices. - */ - -int device_power_down(pm_message_t state) -{ - int error = 0; - struct device * dev; - - while (!list_empty(&dpm_off)) { - struct list_head * entry = dpm_off.prev; - - dev = to_device(entry); - error = suspend_device_late(dev, state); - if (error) - goto Error; - list_move(&dev->power.entry, &dpm_off_irq); - } - - error = sysdev_suspend(state); - Done: - return error; - Error: - printk(KERN_ERR "Could not power down device %s: " - "error %d\n", kobject_name(&dev->kobj), error); - dpm_power_up(); - goto Done; -} - -EXPORT_SYMBOL_GPL(device_power_down); - -void __suspend_report_result(const char *function, void *fn, int ret) -{ - if (ret) { - printk(KERN_ERR "%s(): ", function); - print_fn_descriptor_symbol("%s() returns ", (unsigned long)fn); - printk("%d\n", ret); - } -} -EXPORT_SYMBOL_GPL(__suspend_report_result); diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 18febe26caa1..ac7ff6d0c6e5 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -139,7 +139,7 @@ int sysdev_class_register(struct sysdev_class * cls) kobject_name(&cls->kset.kobj)); INIT_LIST_HEAD(&cls->drivers); cls->kset.kobj.parent = &system_subsys.kobj; - kset_set_kset_s(cls, system_subsys); + cls->kset.kobj.kset = &system_subsys; return kset_register(&cls->kset); } @@ -153,25 +153,22 @@ void sysdev_class_unregister(struct sysdev_class * cls) EXPORT_SYMBOL_GPL(sysdev_class_register); EXPORT_SYMBOL_GPL(sysdev_class_unregister); - -static LIST_HEAD(sysdev_drivers); static DEFINE_MUTEX(sysdev_drivers_lock); /** * sysdev_driver_register - Register auxillary driver - * @cls: Device class driver belongs to. + * @cls: Device class driver belongs to. * @drv: Driver. * - * If @cls is valid, then @drv is inserted into @cls->drivers to be + * @drv is inserted into @cls->drivers to be * called on each operation on devices of that class. The refcount * of @cls is incremented. - * Otherwise, @drv is inserted into sysdev_drivers, and called for - * each device. */ -int sysdev_driver_register(struct sysdev_class * cls, - struct sysdev_driver * drv) +int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv) { + int err = 0; + mutex_lock(&sysdev_drivers_lock); if (cls && kset_get(&cls->kset)) { list_add_tail(&drv->entry, &cls->drivers); @@ -182,10 +179,13 @@ int sysdev_driver_register(struct sysdev_class * cls, list_for_each_entry(dev, &cls->kset.list, kobj.entry) drv->add(dev); } - } else - list_add_tail(&drv->entry, &sysdev_drivers); + } else { + err = -EINVAL; + printk(KERN_ERR "%s: invalid device class\n", __FUNCTION__); + WARN_ON(1); + } mutex_unlock(&sysdev_drivers_lock); - return 0; + return err; } @@ -251,12 +251,6 @@ int sysdev_register(struct sys_device * sysdev) * code that should have called us. */ - /* Notify global drivers */ - list_for_each_entry(drv, &sysdev_drivers, entry) { - if (drv->add) - drv->add(sysdev); - } - /* Notify class auxillary drivers */ list_for_each_entry(drv, &cls->drivers, entry) { if (drv->add) @@ -272,11 +266,6 @@ void sysdev_unregister(struct sys_device * sysdev) struct sysdev_driver * drv; mutex_lock(&sysdev_drivers_lock); - list_for_each_entry(drv, &sysdev_drivers, entry) { - if (drv->remove) - drv->remove(sysdev); - } - list_for_each_entry(drv, &sysdev->cls->drivers, entry) { if (drv->remove) drv->remove(sysdev); @@ -293,7 +282,7 @@ void sysdev_unregister(struct sys_device * sysdev) * * Loop over each class of system devices, and the devices in each * of those classes. For each device, we call the shutdown method for - * each driver registered for the device - the globals, the auxillaries, + * each driver registered for the device - the auxillaries, * and the class driver. * * Note: The list is iterated in reverse order, so that we shut down @@ -320,13 +309,7 @@ void sysdev_shutdown(void) struct sysdev_driver * drv; pr_debug(" %s\n", kobject_name(&sysdev->kobj)); - /* Call global drivers first. */ - list_for_each_entry(drv, &sysdev_drivers, entry) { - if (drv->shutdown) - drv->shutdown(sysdev); - } - - /* Call auxillary drivers next. */ + /* Call auxillary drivers first */ list_for_each_entry(drv, &cls->drivers, entry) { if (drv->shutdown) drv->shutdown(sysdev); @@ -354,12 +337,6 @@ static void __sysdev_resume(struct sys_device *dev) if (drv->resume) drv->resume(dev); } - - /* Call global drivers. */ - list_for_each_entry(drv, &sysdev_drivers, entry) { - if (drv->resume) - drv->resume(dev); - } } /** @@ -393,16 +370,7 @@ int sysdev_suspend(pm_message_t state) list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { pr_debug(" %s\n", kobject_name(&sysdev->kobj)); - /* Call global drivers first. */ - list_for_each_entry(drv, &sysdev_drivers, entry) { - if (drv->suspend) { - ret = drv->suspend(sysdev, state); - if (ret) - goto gbl_driver; - } - } - - /* Call auxillary drivers next. */ + /* Call auxillary drivers first */ list_for_each_entry(drv, &cls->drivers, entry) { if (drv->suspend) { ret = drv->suspend(sysdev, state); @@ -436,18 +404,7 @@ aux_driver: if (err_drv->resume) err_drv->resume(sysdev); } - drv = NULL; -gbl_driver: - if (drv) - printk(KERN_ERR "sysdev driver suspend failed for %s\n", - kobject_name(&sysdev->kobj)); - list_for_each_entry(err_drv, &sysdev_drivers, entry) { - if (err_drv == drv) - break; - if (err_drv->resume) - err_drv->resume(sysdev); - } /* resume other sysdevs in current class */ list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) { if (err_dev == sysdev) diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 4245b7f80a49..ca4d7f0d09b7 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -361,8 +361,7 @@ config BLK_DEV_RAM_SIZE default "4096" help The default value is 4096 kilobytes. Only change this if you know - what are you doing. If you are using IBM S/390, then set this to - 8192. + what are you doing. config BLK_DEV_RAM_BLOCKSIZE int "Default RAM disk block size (bytes)" diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 28d145756f6c..55c3237fb1bc 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -3101,7 +3101,7 @@ static void cciss_getgeometry(int cntl_num) int i; int listlength = 0; __u32 lunid = 0; - int block_size; + unsigned block_size; sector_t total_size; ld_buff = kzalloc(sizeof(ReportLunData_struct), GFP_KERNEL); diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 8955e7ff759a..b83824c41329 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -58,6 +58,9 @@ struct gatt_mask { * devices this will probably be ignored */ }; +#define AGP_PAGE_DESTROY_UNMAP 1 +#define AGP_PAGE_DESTROY_FREE 2 + struct aper_size_info_8 { int size; int num_entries; @@ -113,7 +116,7 @@ struct agp_bridge_driver { struct agp_memory *(*alloc_by_type) (size_t, int); void (*free_by_type)(struct agp_memory *); void *(*agp_alloc_page)(struct agp_bridge_data *); - void (*agp_destroy_page)(void *); + void (*agp_destroy_page)(void *, int flags); int (*agp_type_to_mask_type) (struct agp_bridge_data *, int); }; @@ -267,7 +270,7 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type); struct agp_memory *agp_generic_alloc_by_type(size_t page_count, int type); void agp_generic_free_by_type(struct agp_memory *curr); void *agp_generic_alloc_page(struct agp_bridge_data *bridge); -void agp_generic_destroy_page(void *addr); +void agp_generic_destroy_page(void *addr, int flags); void agp_free_key(int key); int agp_num_entries(void); u32 agp_collect_device_status(struct agp_bridge_data *bridge, u32 mode, u32 command); diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c index 4941ddb78939..aa5ddb716ffb 100644 --- a/drivers/char/agp/ali-agp.c +++ b/drivers/char/agp/ali-agp.c @@ -156,29 +156,34 @@ static void *m1541_alloc_page(struct agp_bridge_data *bridge) return addr; } -static void ali_destroy_page(void * addr) +static void ali_destroy_page(void * addr, int flags) { if (addr) { - global_cache_flush(); /* is this really needed? --hch */ - agp_generic_destroy_page(addr); - global_flush_tlb(); + if (flags & AGP_PAGE_DESTROY_UNMAP) { + global_cache_flush(); /* is this really needed? --hch */ + agp_generic_destroy_page(addr, flags); + global_flush_tlb(); + } else + agp_generic_destroy_page(addr, flags); } } -static void m1541_destroy_page(void * addr) +static void m1541_destroy_page(void * addr, int flags) { u32 temp; if (addr == NULL) return; - global_cache_flush(); + if (flags & AGP_PAGE_DESTROY_UNMAP) { + global_cache_flush(); - pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp); - pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, - (((temp & ALI_CACHE_FLUSH_ADDR_MASK) | - virt_to_gart(addr)) | ALI_CACHE_FLUSH_EN)); - agp_generic_destroy_page(addr); + pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp); + pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, + (((temp & ALI_CACHE_FLUSH_ADDR_MASK) | + virt_to_gart(addr)) | ALI_CACHE_FLUSH_EN)); + } + agp_generic_destroy_page(addr, flags); } diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c index f60bca70d1fb..1405a42585e1 100644 --- a/drivers/char/agp/amd-k7-agp.c +++ b/drivers/char/agp/amd-k7-agp.c @@ -100,21 +100,16 @@ static int amd_create_gatt_pages(int nr_tables) for (i = 0; i < nr_tables; i++) { entry = kzalloc(sizeof(struct amd_page_map), GFP_KERNEL); + tables[i] = entry; if (entry == NULL) { - while (i > 0) { - kfree(tables[i-1]); - i--; - } - kfree(tables); retval = -ENOMEM; break; } - tables[i] = entry; retval = amd_create_page_map(entry); if (retval != 0) break; } - amd_irongate_private.num_tables = nr_tables; + amd_irongate_private.num_tables = i; amd_irongate_private.gatt_pages = tables; if (retval != 0) diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c index 1b47c89a1b99..832ded20fe70 100644 --- a/drivers/char/agp/backend.c +++ b/drivers/char/agp/backend.c @@ -189,9 +189,11 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge) err_out: if (bridge->driver->needs_scratch_page) { - bridge->driver->agp_destroy_page( - gart_to_virt(bridge->scratch_page_real)); + bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real), + AGP_PAGE_DESTROY_UNMAP); flush_agp_mappings(); + bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real), + AGP_PAGE_DESTROY_FREE); } if (got_gatt) bridge->driver->free_gatt_table(bridge); @@ -215,9 +217,11 @@ static void agp_backend_cleanup(struct agp_bridge_data *bridge) if (bridge->driver->agp_destroy_page && bridge->driver->needs_scratch_page) { - bridge->driver->agp_destroy_page( - gart_to_virt(bridge->scratch_page_real)); + bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real), + AGP_PAGE_DESTROY_UNMAP); flush_agp_mappings(); + bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real), + AGP_PAGE_DESTROY_FREE); } } diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index 3db4f4076ed4..64b2f6d7059d 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -195,9 +195,12 @@ void agp_free_memory(struct agp_memory *curr) } if (curr->page_count != 0) { for (i = 0; i < curr->page_count; i++) { - curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i])); + curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]), AGP_PAGE_DESTROY_UNMAP); } flush_agp_mappings(); + for (i = 0; i < curr->page_count; i++) { + curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]), AGP_PAGE_DESTROY_FREE); + } } agp_free_key(curr->key); agp_free_page_array(curr); @@ -1176,7 +1179,7 @@ void *agp_generic_alloc_page(struct agp_bridge_data *bridge) EXPORT_SYMBOL(agp_generic_alloc_page); -void agp_generic_destroy_page(void *addr) +void agp_generic_destroy_page(void *addr, int flags) { struct page *page; @@ -1184,10 +1187,14 @@ void agp_generic_destroy_page(void *addr) return; page = virt_to_page(addr); - unmap_page_from_agp(page); - put_page(page); - free_page((unsigned long)addr); - atomic_dec(&agp_bridge->current_memory_agp); + if (flags & AGP_PAGE_DESTROY_UNMAP) + unmap_page_from_agp(page); + + if (flags & AGP_PAGE_DESTROY_FREE) { + put_page(page); + free_page((unsigned long)addr); + atomic_dec(&agp_bridge->current_memory_agp); + } } EXPORT_SYMBOL(agp_generic_destroy_page); diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c index 75d2aca6353d..70117df4d067 100644 --- a/drivers/char/agp/i460-agp.c +++ b/drivers/char/agp/i460-agp.c @@ -536,10 +536,10 @@ static void *i460_alloc_page (struct agp_bridge_data *bridge) return page; } -static void i460_destroy_page (void *page) +static void i460_destroy_page (void *page, int flags) { if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT) { - agp_generic_destroy_page(page); + agp_generic_destroy_page(page, flags); global_flush_tlb(); } } diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index 141ca176c397..d87961993ccf 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -400,9 +400,11 @@ static void intel_i810_free_by_type(struct agp_memory *curr) if (curr->page_count == 4) i8xx_destroy_pages(gart_to_virt(curr->memory[0])); else { - agp_bridge->driver->agp_destroy_page( - gart_to_virt(curr->memory[0])); + agp_bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[0]), + AGP_PAGE_DESTROY_UNMAP); global_flush_tlb(); + agp_bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[0]), + AGP_PAGE_DESTROY_FREE); } agp_free_page_array(curr); } diff --git a/drivers/char/drm/drm.h b/drivers/char/drm/drm.h index 2d6f2d0bd02b..82fb3d0d2785 100644 --- a/drivers/char/drm/drm.h +++ b/drivers/char/drm/drm.h @@ -63,27 +63,9 @@ #define DRM_IOC(dir, group, nr, size) _IOC(dir, group, nr, size) #endif -#define XFREE86_VERSION(major,minor,patch,snap) \ - ((major << 16) | (minor << 8) | patch) - -#ifndef CONFIG_XFREE86_VERSION -#define CONFIG_XFREE86_VERSION XFREE86_VERSION(4,1,0,0) -#endif - -#if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0) -#define DRM_PROC_DEVICES "/proc/devices" -#define DRM_PROC_MISC "/proc/misc" -#define DRM_PROC_DRM "/proc/drm" -#define DRM_DEV_DRM "/dev/drm" -#define DRM_DEV_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) -#define DRM_DEV_UID 0 -#define DRM_DEV_GID 0 -#endif - -#if CONFIG_XFREE86_VERSION >= XFREE86_VERSION(4,1,0,0) #define DRM_MAJOR 226 #define DRM_MAX_MINOR 15 -#endif + #define DRM_NAME "drm" /**< Name in kernel, /dev, and /proc */ #define DRM_MIN_ORDER 5 /**< At least 2^5 bytes = 32 bytes */ #define DRM_MAX_ORDER 22 /**< Up to 2^22 bytes = 4MB */ diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index 0df87fc3dcb2..9dd0760dd87a 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -80,6 +80,9 @@ #define __OS_HAS_AGP (defined(CONFIG_AGP) || (defined(CONFIG_AGP_MODULE) && defined(MODULE))) #define __OS_HAS_MTRR (defined(CONFIG_MTRR)) +struct drm_file; +struct drm_device; + #include "drm_os_linux.h" #include "drm_hashtab.h" @@ -231,12 +234,13 @@ * \param dev DRM device. * \param filp file pointer of the caller. */ -#define LOCK_TEST_WITH_RETURN( dev, filp ) \ +#define LOCK_TEST_WITH_RETURN( dev, file_priv ) \ do { \ if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || \ - dev->lock.filp != filp ) { \ - DRM_ERROR( "%s called without lock held\n", \ - __FUNCTION__ ); \ + dev->lock.file_priv != file_priv ) { \ + DRM_ERROR( "%s called without lock held, held %d owner %p %p\n",\ + __FUNCTION__, _DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ),\ + dev->lock.file_priv, file_priv ); \ return -EINVAL; \ } \ } while (0) @@ -257,12 +261,12 @@ do { \ * Ioctl function type. * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private pointer. * \param cmd command. * \param arg argument. */ -typedef int drm_ioctl_t(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); +typedef int drm_ioctl_t(struct drm_device *dev, void *data, + struct drm_file *file_priv); typedef int drm_ioctl_compat_t(struct file *filp, unsigned int cmd, unsigned long arg); @@ -271,10 +275,18 @@ typedef int drm_ioctl_compat_t(struct file *filp, unsigned int cmd, #define DRM_MASTER 0x2 #define DRM_ROOT_ONLY 0x4 -typedef struct drm_ioctl_desc { +struct drm_ioctl_desc { + unsigned int cmd; drm_ioctl_t *func; int flags; -} drm_ioctl_desc_t; +}; + +/** + * Creates a driver or general drm_ioctl_desc array entry for the given + * ioctl, for use by drm_ioctl(). + */ +#define DRM_IOCTL_DEF(ioctl, func, flags) \ + [DRM_IOCTL_NR(ioctl)] = {ioctl, func, flags} struct drm_magic_entry { struct list_head head; @@ -304,7 +316,7 @@ struct drm_buf { __volatile__ int waiting; /**< On kernel DMA queue */ __volatile__ int pending; /**< On hardware DMA queue */ wait_queue_head_t dma_wait; /**< Processes waiting */ - struct file *filp; /**< Pointer to holding file descr */ + struct drm_file *file_priv; /**< Private of holding file descr */ int context; /**< Kernel queue for this buffer */ int while_locked; /**< Dispatch this buffer while locked */ enum { @@ -377,6 +389,7 @@ struct drm_file { int remove_auth_on_close; unsigned long lock_count; void *driver_priv; + struct file *filp; }; /** Wait queue */ @@ -403,7 +416,7 @@ struct drm_queue { */ struct drm_lock_data { struct drm_hw_lock *hw_lock; /**< Hardware lock */ - struct file *filp; /**< File descr of lock holder (0=kernel) */ + struct drm_file *file_priv; /**< File descr of lock holder (0=kernel) */ wait_queue_head_t lock_queue; /**< Queue of blocked processes */ unsigned long lock_time; /**< Time of last lock in jiffies */ spinlock_t spinlock; @@ -552,11 +565,11 @@ struct drm_driver { int (*load) (struct drm_device *, unsigned long flags); int (*firstopen) (struct drm_device *); int (*open) (struct drm_device *, struct drm_file *); - void (*preclose) (struct drm_device *, struct file * filp); + void (*preclose) (struct drm_device *, struct drm_file *file_priv); void (*postclose) (struct drm_device *, struct drm_file *); void (*lastclose) (struct drm_device *); int (*unload) (struct drm_device *); - int (*dma_ioctl) (DRM_IOCTL_ARGS); + int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv); void (*dma_ready) (struct drm_device *); int (*dma_quiescent) (struct drm_device *); int (*context_ctor) (struct drm_device *dev, int context); @@ -587,11 +600,12 @@ struct drm_driver { void (*irq_preinstall) (struct drm_device *dev); void (*irq_postinstall) (struct drm_device *dev); void (*irq_uninstall) (struct drm_device *dev); - void (*reclaim_buffers) (struct drm_device *dev, struct file * filp); + void (*reclaim_buffers) (struct drm_device *dev, + struct drm_file * file_priv); void (*reclaim_buffers_locked) (struct drm_device *dev, - struct file *filp); + struct drm_file *file_priv); void (*reclaim_buffers_idlelocked) (struct drm_device *dev, - struct file * filp); + struct drm_file *file_priv); unsigned long (*get_map_ofs) (struct drm_map * map); unsigned long (*get_reg_ofs) (struct drm_device *dev); void (*set_version) (struct drm_device *dev, @@ -606,7 +620,7 @@ struct drm_driver { u32 driver_features; int dev_priv_size; - drm_ioctl_desc_t *ioctls; + struct drm_ioctl_desc *ioctls; int num_ioctls; struct file_operations fops; struct pci_driver pci_driver; @@ -850,70 +864,70 @@ extern int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start); extern int drm_unbind_agp(DRM_AGP_MEM * handle); /* Misc. IOCTL support (drm_ioctl.h) */ -extern int drm_irq_by_busid(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int drm_getunique(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int drm_setunique(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int drm_getmap(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int drm_getclient(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int drm_getstats(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int drm_setversion(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int drm_noop(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); +extern int drm_irq_by_busid(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_getunique(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_setunique(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_getmap(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_getclient(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_getstats(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_setversion(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_noop(struct drm_device *dev, void *data, + struct drm_file *file_priv); /* Context IOCTL support (drm_context.h) */ -extern int drm_resctx(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int drm_addctx(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int drm_modctx(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int drm_getctx(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int drm_switchctx(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int drm_newctx(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int drm_rmctx(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); +extern int drm_resctx(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_addctx(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_modctx(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_getctx(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_switchctx(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_newctx(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_rmctx(struct drm_device *dev, void *data, + struct drm_file *file_priv); extern int drm_ctxbitmap_init(struct drm_device *dev); extern void drm_ctxbitmap_cleanup(struct drm_device *dev); extern void drm_ctxbitmap_free(struct drm_device *dev, int ctx_handle); -extern int drm_setsareactx(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int drm_getsareactx(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); +extern int drm_setsareactx(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_getsareactx(struct drm_device *dev, void *data, + struct drm_file *file_priv); /* Drawable IOCTL support (drm_drawable.h) */ -extern int drm_adddraw(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int drm_rmdraw(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int drm_update_drawable_info(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); +extern int drm_adddraw(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_rmdraw(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_update_drawable_info(struct drm_device *dev, void *data, + struct drm_file *file_priv); extern struct drm_drawable_info *drm_get_drawable_info(struct drm_device *dev, drm_drawable_t id); extern void drm_drawable_free_all(struct drm_device *dev); /* Authentication IOCTL support (drm_auth.h) */ -extern int drm_getmagic(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int drm_authmagic(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); +extern int drm_getmagic(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_authmagic(struct drm_device *dev, void *data, + struct drm_file *file_priv); /* Locking IOCTL support (drm_lock.h) */ -extern int drm_lock(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int drm_unlock(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); +extern int drm_lock(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_unlock(struct drm_device *dev, void *data, + struct drm_file *file_priv); extern int drm_lock_take(struct drm_lock_data *lock_data, unsigned int context); extern int drm_lock_free(struct drm_lock_data *lock_data, unsigned int context); extern void drm_idlelock_take(struct drm_lock_data *lock_data); @@ -924,8 +938,7 @@ extern void drm_idlelock_release(struct drm_lock_data *lock_data); * DMA quiscent + idle. DMA quiescent usually requires the hardware lock. */ -extern int drm_i_have_hw_lock(struct file *filp); -extern int drm_kernel_take_hw_lock(struct file *filp); +extern int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv); /* Buffer management support (drm_bufs.h) */ extern int drm_addbufs_agp(struct drm_device *dev, struct drm_buf_desc * request); @@ -933,24 +946,23 @@ extern int drm_addbufs_pci(struct drm_device *dev, struct drm_buf_desc * request extern int drm_addmap(struct drm_device *dev, unsigned int offset, unsigned int size, enum drm_map_type type, enum drm_map_flags flags, drm_local_map_t ** map_ptr); -extern int drm_addmap_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int drm_rmmap(struct drm_device *dev, drm_local_map_t * map); -extern int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t * map); -extern int drm_rmmap_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); - +extern int drm_addmap_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_rmmap(struct drm_device *dev, drm_local_map_t *map); +extern int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map); +extern int drm_rmmap_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_addbufs(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_infobufs(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_markbufs(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_freebufs(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_mapbufs(struct drm_device *dev, void *data, + struct drm_file *file_priv); extern int drm_order(unsigned long size); -extern int drm_addbufs(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int drm_infobufs(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int drm_markbufs(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int drm_freebufs(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int drm_mapbufs(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); extern unsigned long drm_get_resource_start(struct drm_device *dev, unsigned int resource); extern unsigned long drm_get_resource_len(struct drm_device *dev, @@ -960,19 +972,20 @@ extern unsigned long drm_get_resource_len(struct drm_device *dev, extern int drm_dma_setup(struct drm_device *dev); extern void drm_dma_takedown(struct drm_device *dev); extern void drm_free_buffer(struct drm_device *dev, struct drm_buf * buf); -extern void drm_core_reclaim_buffers(struct drm_device *dev, struct file *filp); +extern void drm_core_reclaim_buffers(struct drm_device *dev, + struct drm_file *filp); /* IRQ support (drm_irq.h) */ -extern int drm_control(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); +extern int drm_control(struct drm_device *dev, void *data, + struct drm_file *file_priv); extern irqreturn_t drm_irq_handler(DRM_IRQ_ARGS); extern int drm_irq_uninstall(struct drm_device *dev); extern void drm_driver_irq_preinstall(struct drm_device *dev); extern void drm_driver_irq_postinstall(struct drm_device *dev); extern void drm_driver_irq_uninstall(struct drm_device *dev); -extern int drm_wait_vblank(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); +extern int drm_wait_vblank(struct drm_device *dev, void *data, + struct drm_file *file_priv); extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq); extern void drm_vbl_send_signals(struct drm_device *dev); extern void drm_locked_tasklet(struct drm_device *dev, void(*func)(struct drm_device*)); @@ -980,31 +993,30 @@ extern void drm_locked_tasklet(struct drm_device *dev, void(*func)(struct drm_de /* AGP/GART support (drm_agpsupport.h) */ extern struct drm_agp_head *drm_agp_init(struct drm_device *dev); extern int drm_agp_acquire(struct drm_device *dev); -extern int drm_agp_acquire_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); +extern int drm_agp_acquire_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); extern int drm_agp_release(struct drm_device *dev); -extern int drm_agp_release_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); +extern int drm_agp_release_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); extern int drm_agp_enable(struct drm_device *dev, struct drm_agp_mode mode); -extern int drm_agp_enable_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int drm_agp_info(struct drm_device *dev, struct drm_agp_info * info); -extern int drm_agp_info_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); +extern int drm_agp_enable_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_agp_info(struct drm_device *dev, struct drm_agp_info *info); +extern int drm_agp_info_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); extern int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request); -extern int drm_agp_alloc_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); +extern int drm_agp_alloc_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); extern int drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request); -extern int drm_agp_free_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); +extern int drm_agp_free_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); extern int drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request); -extern int drm_agp_unbind_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); +extern int drm_agp_unbind_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); extern int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request); -extern int drm_agp_bind_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern DRM_AGP_MEM *drm_agp_allocate_memory(struct agp_bridge_data *bridge, - size_t pages, u32 type); +extern int drm_agp_bind_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern DRM_AGP_MEM *drm_agp_allocate_memory(struct agp_bridge_data *bridge, size_t pages, u32 type); extern int drm_agp_free_memory(DRM_AGP_MEM * handle); extern int drm_agp_bind_memory(DRM_AGP_MEM * handle, off_t start); extern int drm_agp_unbind_memory(DRM_AGP_MEM * handle); @@ -1033,10 +1045,11 @@ extern int drm_proc_cleanup(int minor, /* Scatter Gather Support (drm_scatter.h) */ extern void drm_sg_cleanup(struct drm_sg_mem * entry); -extern int drm_sg_alloc(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int drm_sg_free(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); +extern int drm_sg_alloc_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request); +extern int drm_sg_free(struct drm_device *dev, void *data, + struct drm_file *file_priv); /* ATI PCIGART support (ati_pcigart.h) */ extern int drm_ati_pcigart_init(struct drm_device *dev, diff --git a/drivers/char/drm/drm_agpsupport.c b/drivers/char/drm/drm_agpsupport.c index 354f0e3674bf..214f4fbcba73 100644 --- a/drivers/char/drm/drm_agpsupport.c +++ b/drivers/char/drm/drm_agpsupport.c @@ -40,7 +40,7 @@ * Get AGP information. * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg pointer to a (output) drm_agp_info structure. * \return zero on success or a negative number on failure. @@ -71,20 +71,16 @@ int drm_agp_info(struct drm_device *dev, struct drm_agp_info *info) EXPORT_SYMBOL(drm_agp_info); -int drm_agp_info_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_agp_info_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - struct drm_agp_info info; + struct drm_agp_info *info = data; int err; - err = drm_agp_info(dev, &info); + err = drm_agp_info(dev, info); if (err) return err; - if (copy_to_user((struct drm_agp_info __user *) arg, &info, sizeof(info))) - return -EFAULT; return 0; } @@ -115,7 +111,7 @@ EXPORT_SYMBOL(drm_agp_acquire); * Acquire the AGP device (ioctl). * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg user argument. * \return zero on success or a negative number on failure. @@ -123,12 +119,10 @@ EXPORT_SYMBOL(drm_agp_acquire); * Verifies the AGP device hasn't been acquired before and calls * \c agp_backend_acquire. */ -int drm_agp_acquire_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_agp_acquire_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - - return drm_agp_acquire((struct drm_device *) priv->head->dev); + return drm_agp_acquire((struct drm_device *) file_priv->head->dev); } /** @@ -149,12 +143,9 @@ int drm_agp_release(struct drm_device * dev) } EXPORT_SYMBOL(drm_agp_release); -int drm_agp_release_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_agp_release_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - return drm_agp_release(dev); } @@ -182,24 +173,19 @@ int drm_agp_enable(struct drm_device * dev, struct drm_agp_mode mode) EXPORT_SYMBOL(drm_agp_enable); -int drm_agp_enable_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_agp_enable_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - struct drm_agp_mode mode; - - if (copy_from_user(&mode, (struct drm_agp_mode __user *) arg, sizeof(mode))) - return -EFAULT; + struct drm_agp_mode *mode = data; - return drm_agp_enable(dev, mode); + return drm_agp_enable(dev, *mode); } /** * Allocate AGP memory. * * \param inode device inode. - * \param filp file pointer. + * \param file_priv file private pointer. * \param cmd command. * \param arg pointer to a drm_agp_buffer structure. * \return zero on success or a negative number on failure. @@ -241,35 +227,13 @@ int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request) } EXPORT_SYMBOL(drm_agp_alloc); -int drm_agp_alloc_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - struct drm_agp_buffer request; - struct drm_agp_buffer __user *argp = (void __user *)arg; - int err; - - if (copy_from_user(&request, argp, sizeof(request))) - return -EFAULT; - err = drm_agp_alloc(dev, &request); - if (err) - return err; - - if (copy_to_user(argp, &request, sizeof(request))) { - struct drm_agp_mem *entry; - list_for_each_entry(entry, &dev->agp->memory, head) { - if (entry->handle == request.handle) - break; - } - list_del(&entry->head); - drm_free_agp(entry->memory, entry->pages); - drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); - return -EFAULT; - } +int drm_agp_alloc_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_agp_buffer *request = data; - return 0; + return drm_agp_alloc(dev, request); } /** @@ -297,7 +261,7 @@ static struct drm_agp_mem *drm_agp_lookup_entry(struct drm_device * dev, * Unbind AGP memory from the GATT (ioctl). * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg pointer to a drm_agp_binding structure. * \return zero on success or a negative number on failure. @@ -323,25 +287,20 @@ int drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request) } EXPORT_SYMBOL(drm_agp_unbind); -int drm_agp_unbind_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - struct drm_agp_binding request; - if (copy_from_user - (&request, (struct drm_agp_binding __user *) arg, sizeof(request))) - return -EFAULT; +int drm_agp_unbind_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_agp_binding *request = data; - return drm_agp_unbind(dev, &request); + return drm_agp_unbind(dev, request); } /** * Bind AGP memory into the GATT (ioctl) * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg pointer to a drm_agp_binding structure. * \return zero on success or a negative number on failure. @@ -372,25 +331,20 @@ int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request) } EXPORT_SYMBOL(drm_agp_bind); -int drm_agp_bind_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - struct drm_agp_binding request; - if (copy_from_user - (&request, (struct drm_agp_binding __user *) arg, sizeof(request))) - return -EFAULT; +int drm_agp_bind_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_agp_binding *request = data; - return drm_agp_bind(dev, &request); + return drm_agp_bind(dev, request); } /** * Free AGP memory (ioctl). * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg pointer to a drm_agp_buffer structure. * \return zero on success or a negative number on failure. @@ -419,18 +373,14 @@ int drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request) } EXPORT_SYMBOL(drm_agp_free); -int drm_agp_free_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - struct drm_agp_buffer request; - if (copy_from_user - (&request, (struct drm_agp_buffer __user *) arg, sizeof(request))) - return -EFAULT; - return drm_agp_free(dev, &request); +int drm_agp_free_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_agp_buffer *request = data; + + return drm_agp_free(dev, request); } /** diff --git a/drivers/char/drm/drm_auth.c b/drivers/char/drm/drm_auth.c index 7f777da872cd..a73462723d2d 100644 --- a/drivers/char/drm/drm_auth.c +++ b/drivers/char/drm/drm_auth.c @@ -128,42 +128,38 @@ static int drm_remove_magic(struct drm_device * dev, drm_magic_t magic) * Get a unique magic number (ioctl). * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg pointer to a resulting drm_auth structure. * \return zero on success, or a negative number on failure. * * If there is a magic number in drm_file::magic then use it, otherwise * searches an unique non-zero magic number and add it associating it with \p - * filp. + * file_priv. */ -int drm_getmagic(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv) { static drm_magic_t sequence = 0; static DEFINE_SPINLOCK(lock); - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - struct drm_auth auth; + struct drm_auth *auth = data; /* Find unique magic */ - if (priv->magic) { - auth.magic = priv->magic; + if (file_priv->magic) { + auth->magic = file_priv->magic; } else { do { spin_lock(&lock); if (!sequence) ++sequence; /* reserve 0 */ - auth.magic = sequence++; + auth->magic = sequence++; spin_unlock(&lock); - } while (drm_find_file(dev, auth.magic)); - priv->magic = auth.magic; - drm_add_magic(dev, priv, auth.magic); + } while (drm_find_file(dev, auth->magic)); + file_priv->magic = auth->magic; + drm_add_magic(dev, file_priv, auth->magic); } - DRM_DEBUG("%u\n", auth.magic); - if (copy_to_user((struct drm_auth __user *) arg, &auth, sizeof(auth))) - return -EFAULT; + DRM_DEBUG("%u\n", auth->magic); + return 0; } @@ -171,27 +167,23 @@ int drm_getmagic(struct inode *inode, struct file *filp, * Authenticate with a magic. * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg pointer to a drm_auth structure. * \return zero if authentication successed, or a negative number otherwise. * - * Checks if \p filp is associated with the magic number passed in \arg. + * Checks if \p file_priv is associated with the magic number passed in \arg. */ -int drm_authmagic(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_authmagic(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - struct drm_auth auth; + struct drm_auth *auth = data; struct drm_file *file; - if (copy_from_user(&auth, (struct drm_auth __user *) arg, sizeof(auth))) - return -EFAULT; - DRM_DEBUG("%u\n", auth.magic); - if ((file = drm_find_file(dev, auth.magic))) { + DRM_DEBUG("%u\n", auth->magic); + if ((file = drm_find_file(dev, auth->magic))) { file->authenticated = 1; - drm_remove_magic(dev, auth.magic); + drm_remove_magic(dev, auth->magic); return 0; } return -EINVAL; diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c index c115b39b8517..856774fbe025 100644 --- a/drivers/char/drm/drm_bufs.c +++ b/drivers/char/drm/drm_bufs.c @@ -92,7 +92,7 @@ static int drm_map_handle(struct drm_device *dev, struct drm_hash_item *hash, * Ioctl to specify a range of memory that is available for mapping by a non-root process. * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg pointer to a drm_map structure. * \return zero on success or a negative value on error. @@ -332,38 +332,24 @@ int drm_addmap(struct drm_device * dev, unsigned int offset, EXPORT_SYMBOL(drm_addmap); -int drm_addmap_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_addmap_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - struct drm_map map; + struct drm_map *map = data; struct drm_map_list *maplist; - struct drm_map __user *argp = (void __user *)arg; int err; - if (!(filp->f_mode & 3)) - return -EACCES; /* Require read/write */ - - if (copy_from_user(&map, argp, sizeof(map))) { - return -EFAULT; - } - - if (!(capable(CAP_SYS_ADMIN) || map.type == _DRM_AGP)) + if (!(capable(CAP_SYS_ADMIN) || map->type == _DRM_AGP)) return -EPERM; - err = drm_addmap_core(dev, map.offset, map.size, map.type, map.flags, - &maplist); + err = drm_addmap_core(dev, map->offset, map->size, map->type, + map->flags, &maplist); if (err) return err; - if (copy_to_user(argp, maplist->map, sizeof(struct drm_map))) - return -EFAULT; - /* avoid a warning on 64-bit, this casting isn't very nice, but the API is set so too late */ - if (put_user((void *)(unsigned long)maplist->user_token, &argp->handle)) - return -EFAULT; + map->handle = (void *)(unsigned long)maplist->user_token; return 0; } @@ -372,7 +358,7 @@ int drm_addmap_ioctl(struct inode *inode, struct file *filp, * isn't in use. * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg pointer to a struct drm_map structure. * \return zero on success or a negative value on error. @@ -453,24 +439,18 @@ int drm_rmmap(struct drm_device *dev, drm_local_map_t *map) * gets used by drivers that the server doesn't need to care about. This seems * unlikely. */ -int drm_rmmap_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_rmmap_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - struct drm_map request; + struct drm_map *request = data; drm_local_map_t *map = NULL; struct drm_map_list *r_list; int ret; - if (copy_from_user(&request, (struct drm_map __user *) arg, sizeof(request))) { - return -EFAULT; - } - mutex_lock(&dev->struct_mutex); list_for_each_entry(r_list, &dev->maplist, head) { if (r_list->map && - r_list->user_token == (unsigned long)request.handle && + r_list->user_token == (unsigned long)request->handle && r_list->map->flags & _DRM_REMOVABLE) { map = r_list->map; break; @@ -661,7 +641,7 @@ int drm_addbufs_agp(struct drm_device * dev, struct drm_buf_desc * request) buf->waiting = 0; buf->pending = 0; init_waitqueue_head(&buf->dma_wait); - buf->filp = NULL; + buf->file_priv = NULL; buf->dev_priv_size = dev->driver->dev_priv_size; buf->dev_private = drm_alloc(buf->dev_priv_size, DRM_MEM_BUFS); @@ -872,7 +852,7 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request) buf->waiting = 0; buf->pending = 0; init_waitqueue_head(&buf->dma_wait); - buf->filp = NULL; + buf->file_priv = NULL; buf->dev_priv_size = dev->driver->dev_priv_size; buf->dev_private = drm_alloc(buf->dev_priv_size, @@ -1050,7 +1030,7 @@ static int drm_addbufs_sg(struct drm_device * dev, struct drm_buf_desc * request buf->waiting = 0; buf->pending = 0; init_waitqueue_head(&buf->dma_wait); - buf->filp = NULL; + buf->file_priv = NULL; buf->dev_priv_size = dev->driver->dev_priv_size; buf->dev_private = drm_alloc(buf->dev_priv_size, DRM_MEM_BUFS); @@ -1211,7 +1191,7 @@ static int drm_addbufs_fb(struct drm_device * dev, struct drm_buf_desc * request buf->waiting = 0; buf->pending = 0; init_waitqueue_head(&buf->dma_wait); - buf->filp = NULL; + buf->file_priv = NULL; buf->dev_priv_size = dev->driver->dev_priv_size; buf->dev_private = drm_alloc(buf->dev_priv_size, DRM_MEM_BUFS); @@ -1275,7 +1255,7 @@ static int drm_addbufs_fb(struct drm_device * dev, struct drm_buf_desc * request * Add buffers for DMA transfers (ioctl). * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg pointer to a struct drm_buf_desc request. * \return zero on success or a negative number on failure. @@ -1285,38 +1265,27 @@ static int drm_addbufs_fb(struct drm_device * dev, struct drm_buf_desc * request * addbufs_sg() or addbufs_pci() for AGP, scatter-gather or consistent * PCI memory respectively. */ -int drm_addbufs(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_addbufs(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_buf_desc request; - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_buf_desc *request = data; int ret; if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) return -EINVAL; - if (copy_from_user(&request, (struct drm_buf_desc __user *) arg, - sizeof(request))) - return -EFAULT; - #if __OS_HAS_AGP - if (request.flags & _DRM_AGP_BUFFER) - ret = drm_addbufs_agp(dev, &request); + if (request->flags & _DRM_AGP_BUFFER) + ret = drm_addbufs_agp(dev, request); else #endif - if (request.flags & _DRM_SG_BUFFER) - ret = drm_addbufs_sg(dev, &request); - else if (request.flags & _DRM_FB_BUFFER) - ret = drm_addbufs_fb(dev, &request); + if (request->flags & _DRM_SG_BUFFER) + ret = drm_addbufs_sg(dev, request); + else if (request->flags & _DRM_FB_BUFFER) + ret = drm_addbufs_fb(dev, request); else - ret = drm_addbufs_pci(dev, &request); + ret = drm_addbufs_pci(dev, request); - if (ret == 0) { - if (copy_to_user((void __user *)arg, &request, sizeof(request))) { - ret = -EFAULT; - } - } return ret; } @@ -1328,7 +1297,7 @@ int drm_addbufs(struct inode *inode, struct file *filp, * large buffers can be used for image transfer). * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg pointer to a drm_buf_info structure. * \return zero on success or a negative number on failure. @@ -1337,14 +1306,11 @@ int drm_addbufs(struct inode *inode, struct file *filp, * lock, preventing of allocating more buffers after this call. Information * about each requested buffer is then copied into user space. */ -int drm_infobufs(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_infobufs(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; struct drm_device_dma *dma = dev->dma; - struct drm_buf_info request; - struct drm_buf_info __user *argp = (void __user *)arg; + struct drm_buf_info *request = data; int i; int count; @@ -1362,9 +1328,6 @@ int drm_infobufs(struct inode *inode, struct file *filp, ++dev->buf_use; /* Can't allocate more after this call */ spin_unlock(&dev->count_lock); - if (copy_from_user(&request, argp, sizeof(request))) - return -EFAULT; - for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) { if (dma->bufs[i].buf_count) ++count; @@ -1372,11 +1335,11 @@ int drm_infobufs(struct inode *inode, struct file *filp, DRM_DEBUG("count = %d\n", count); - if (request.count >= count) { + if (request->count >= count) { for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) { if (dma->bufs[i].buf_count) { struct drm_buf_desc __user *to = - &request.list[count]; + &request->list[count]; struct drm_buf_entry *from = &dma->bufs[i]; struct drm_freelist *list = &dma->bufs[i].freelist; if (copy_to_user(&to->count, @@ -1403,10 +1366,7 @@ int drm_infobufs(struct inode *inode, struct file *filp, } } } - request.count = count; - - if (copy_to_user(argp, &request, sizeof(request))) - return -EFAULT; + request->count = count; return 0; } @@ -1415,7 +1375,7 @@ int drm_infobufs(struct inode *inode, struct file *filp, * Specifies a low and high water mark for buffer allocation * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg a pointer to a drm_buf_desc structure. * \return zero on success or a negative number on failure. @@ -1425,13 +1385,11 @@ int drm_infobufs(struct inode *inode, struct file *filp, * * \note This ioctl is deprecated and mostly never used. */ -int drm_markbufs(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_markbufs(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; struct drm_device_dma *dma = dev->dma; - struct drm_buf_desc request; + struct drm_buf_desc *request = data; int order; struct drm_buf_entry *entry; @@ -1441,24 +1399,20 @@ int drm_markbufs(struct inode *inode, struct file *filp, if (!dma) return -EINVAL; - if (copy_from_user(&request, - (struct drm_buf_desc __user *) arg, sizeof(request))) - return -EFAULT; - DRM_DEBUG("%d, %d, %d\n", - request.size, request.low_mark, request.high_mark); - order = drm_order(request.size); + request->size, request->low_mark, request->high_mark); + order = drm_order(request->size); if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL; entry = &dma->bufs[order]; - if (request.low_mark < 0 || request.low_mark > entry->buf_count) + if (request->low_mark < 0 || request->low_mark > entry->buf_count) return -EINVAL; - if (request.high_mark < 0 || request.high_mark > entry->buf_count) + if (request->high_mark < 0 || request->high_mark > entry->buf_count) return -EINVAL; - entry->freelist.low_mark = request.low_mark; - entry->freelist.high_mark = request.high_mark; + entry->freelist.low_mark = request->low_mark; + entry->freelist.high_mark = request->high_mark; return 0; } @@ -1467,7 +1421,7 @@ int drm_markbufs(struct inode *inode, struct file *filp, * Unreserve the buffers in list, previously reserved using drmDMA. * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg pointer to a drm_buf_free structure. * \return zero on success or a negative number on failure. @@ -1475,13 +1429,11 @@ int drm_markbufs(struct inode *inode, struct file *filp, * Calls free_buffer() for each used buffer. * This function is primarily used for debugging. */ -int drm_freebufs(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_freebufs(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; struct drm_device_dma *dma = dev->dma; - struct drm_buf_free request; + struct drm_buf_free *request = data; int i; int idx; struct drm_buf *buf; @@ -1492,13 +1444,9 @@ int drm_freebufs(struct inode *inode, struct file *filp, if (!dma) return -EINVAL; - if (copy_from_user(&request, - (struct drm_buf_free __user *) arg, sizeof(request))) - return -EFAULT; - - DRM_DEBUG("%d\n", request.count); - for (i = 0; i < request.count; i++) { - if (copy_from_user(&idx, &request.list[i], sizeof(idx))) + DRM_DEBUG("%d\n", request->count); + for (i = 0; i < request->count; i++) { + if (copy_from_user(&idx, &request->list[i], sizeof(idx))) return -EFAULT; if (idx < 0 || idx >= dma->buf_count) { DRM_ERROR("Index %d (of %d max)\n", @@ -1506,7 +1454,7 @@ int drm_freebufs(struct inode *inode, struct file *filp, return -EINVAL; } buf = dma->buflist[idx]; - if (buf->filp != filp) { + if (buf->file_priv != file_priv) { DRM_ERROR("Process %d freeing buffer not owned\n", current->pid); return -EINVAL; @@ -1521,7 +1469,7 @@ int drm_freebufs(struct inode *inode, struct file *filp, * Maps all of the DMA buffers into client-virtual space (ioctl). * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg pointer to a drm_buf_map structure. * \return zero on success or a negative number on failure. @@ -1531,18 +1479,15 @@ int drm_freebufs(struct inode *inode, struct file *filp, * offset equal to 0, which drm_mmap() interpretes as PCI buffers and calls * drm_mmap_dma(). */ -int drm_mapbufs(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_mapbufs(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; struct drm_device_dma *dma = dev->dma; - struct drm_buf_map __user *argp = (void __user *)arg; int retcode = 0; const int zero = 0; unsigned long virtual; unsigned long address; - struct drm_buf_map request; + struct drm_buf_map *request = data; int i; if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) @@ -1559,10 +1504,7 @@ int drm_mapbufs(struct inode *inode, struct file *filp, dev->buf_use++; /* Can't allocate more after this call */ spin_unlock(&dev->count_lock); - if (copy_from_user(&request, argp, sizeof(request))) - return -EFAULT; - - if (request.count >= dma->buf_count) { + if (request->count >= dma->buf_count) { if ((drm_core_has_AGP(dev) && (dma->flags & _DRM_DMA_USE_AGP)) || (drm_core_check_feature(dev, DRIVER_SG) && (dma->flags & _DRM_DMA_USE_SG)) @@ -1575,15 +1517,15 @@ int drm_mapbufs(struct inode *inode, struct file *filp, retcode = -EINVAL; goto done; } - down_write(¤t->mm->mmap_sem); - virtual = do_mmap(filp, 0, map->size, + virtual = do_mmap(file_priv->filp, 0, map->size, PROT_READ | PROT_WRITE, - MAP_SHARED, token); + MAP_SHARED, + token); up_write(¤t->mm->mmap_sem); } else { down_write(¤t->mm->mmap_sem); - virtual = do_mmap(filp, 0, dma->byte_count, + virtual = do_mmap(file_priv->filp, 0, dma->byte_count, PROT_READ | PROT_WRITE, MAP_SHARED, 0); up_write(¤t->mm->mmap_sem); @@ -1593,28 +1535,28 @@ int drm_mapbufs(struct inode *inode, struct file *filp, retcode = (signed long)virtual; goto done; } - request.virtual = (void __user *)virtual; + request->virtual = (void __user *)virtual; for (i = 0; i < dma->buf_count; i++) { - if (copy_to_user(&request.list[i].idx, + if (copy_to_user(&request->list[i].idx, &dma->buflist[i]->idx, - sizeof(request.list[0].idx))) { + sizeof(request->list[0].idx))) { retcode = -EFAULT; goto done; } - if (copy_to_user(&request.list[i].total, + if (copy_to_user(&request->list[i].total, &dma->buflist[i]->total, - sizeof(request.list[0].total))) { + sizeof(request->list[0].total))) { retcode = -EFAULT; goto done; } - if (copy_to_user(&request.list[i].used, + if (copy_to_user(&request->list[i].used, &zero, sizeof(zero))) { retcode = -EFAULT; goto done; } address = virtual + dma->buflist[i]->offset; /* *** */ - if (copy_to_user(&request.list[i].address, + if (copy_to_user(&request->list[i].address, &address, sizeof(address))) { retcode = -EFAULT; goto done; @@ -1622,11 +1564,8 @@ int drm_mapbufs(struct inode *inode, struct file *filp, } } done: - request.count = dma->buf_count; - DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode); - - if (copy_to_user(argp, &request, sizeof(request))) - return -EFAULT; + request->count = dma->buf_count; + DRM_DEBUG("%d buffers, retcode = %d\n", request->count, retcode); return retcode; } diff --git a/drivers/char/drm/drm_context.c b/drivers/char/drm/drm_context.c index 61ad986baa8d..17fe69e7bfc1 100644 --- a/drivers/char/drm/drm_context.c +++ b/drivers/char/drm/drm_context.c @@ -131,7 +131,7 @@ void drm_ctxbitmap_cleanup(struct drm_device * dev) * Get per-context SAREA. * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg user argument pointing to a drm_ctx_priv_map structure. * \return zero on success or a negative number on failure. @@ -139,22 +139,16 @@ void drm_ctxbitmap_cleanup(struct drm_device * dev) * Gets the map from drm_device::ctx_idr with the handle specified and * returns its handle. */ -int drm_getsareactx(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_getsareactx(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - struct drm_ctx_priv_map __user *argp = (void __user *)arg; - struct drm_ctx_priv_map request; + struct drm_ctx_priv_map *request = data; struct drm_map *map; struct drm_map_list *_entry; - if (copy_from_user(&request, argp, sizeof(request))) - return -EFAULT; - mutex_lock(&dev->struct_mutex); - map = idr_find(&dev->ctx_idr, request.ctx_id); + map = idr_find(&dev->ctx_idr, request->ctx_id); if (!map) { mutex_unlock(&dev->struct_mutex); return -EINVAL; @@ -162,19 +156,17 @@ int drm_getsareactx(struct inode *inode, struct file *filp, mutex_unlock(&dev->struct_mutex); - request.handle = NULL; + request->handle = NULL; list_for_each_entry(_entry, &dev->maplist, head) { if (_entry->map == map) { - request.handle = + request->handle = (void *)(unsigned long)_entry->user_token; break; } } - if (request.handle == NULL) + if (request->handle == NULL) return -EINVAL; - if (copy_to_user(argp, &request, sizeof(request))) - return -EFAULT; return 0; } @@ -182,7 +174,7 @@ int drm_getsareactx(struct inode *inode, struct file *filp, * Set per-context SAREA. * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg user argument pointing to a drm_ctx_priv_map structure. * \return zero on success or a negative number on failure. @@ -190,24 +182,17 @@ int drm_getsareactx(struct inode *inode, struct file *filp, * Searches the mapping specified in \p arg and update the entry in * drm_device::ctx_idr with it. */ -int drm_setsareactx(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_setsareactx(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - struct drm_ctx_priv_map request; + struct drm_ctx_priv_map *request = data; struct drm_map *map = NULL; struct drm_map_list *r_list = NULL; - if (copy_from_user(&request, - (struct drm_ctx_priv_map __user *) arg, - sizeof(request))) - return -EFAULT; - mutex_lock(&dev->struct_mutex); list_for_each_entry(r_list, &dev->maplist, head) { if (r_list->map - && r_list->user_token == (unsigned long)request.handle) + && r_list->user_token == (unsigned long) request->handle) goto found; } bad: @@ -219,10 +204,11 @@ int drm_setsareactx(struct inode *inode, struct file *filp, if (!map) goto bad; - if (IS_ERR(idr_replace(&dev->ctx_idr, map, request.ctx_id))) + if (IS_ERR(idr_replace(&dev->ctx_idr, map, request->ctx_id))) goto bad; mutex_unlock(&dev->struct_mutex); + return 0; } @@ -292,34 +278,28 @@ static int drm_context_switch_complete(struct drm_device * dev, int new) * Reserve contexts. * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg user argument pointing to a drm_ctx_res structure. * \return zero on success or a negative number on failure. */ -int drm_resctx(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_resctx(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_ctx_res res; - struct drm_ctx_res __user *argp = (void __user *)arg; + struct drm_ctx_res *res = data; struct drm_ctx ctx; int i; - if (copy_from_user(&res, argp, sizeof(res))) - return -EFAULT; - - if (res.count >= DRM_RESERVED_CONTEXTS) { + if (res->count >= DRM_RESERVED_CONTEXTS) { memset(&ctx, 0, sizeof(ctx)); for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { ctx.handle = i; - if (copy_to_user(&res.contexts[i], &ctx, sizeof(ctx))) + if (copy_to_user(&res->contexts[i], &ctx, sizeof(ctx))) return -EFAULT; } } - res.count = DRM_RESERVED_CONTEXTS; + res->count = DRM_RESERVED_CONTEXTS; - if (copy_to_user(argp, &res, sizeof(res))) - return -EFAULT; return 0; } @@ -327,40 +307,34 @@ int drm_resctx(struct inode *inode, struct file *filp, * Add context. * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg user argument pointing to a drm_ctx structure. * \return zero on success or a negative number on failure. * * Get a new handle for the context and copy to userspace. */ -int drm_addctx(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_addctx(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; struct drm_ctx_list *ctx_entry; - struct drm_ctx __user *argp = (void __user *)arg; - struct drm_ctx ctx; - - if (copy_from_user(&ctx, argp, sizeof(ctx))) - return -EFAULT; + struct drm_ctx *ctx = data; - ctx.handle = drm_ctxbitmap_next(dev); - if (ctx.handle == DRM_KERNEL_CONTEXT) { + ctx->handle = drm_ctxbitmap_next(dev); + if (ctx->handle == DRM_KERNEL_CONTEXT) { /* Skip kernel's context and get a new one. */ - ctx.handle = drm_ctxbitmap_next(dev); + ctx->handle = drm_ctxbitmap_next(dev); } - DRM_DEBUG("%d\n", ctx.handle); - if (ctx.handle == -1) { + DRM_DEBUG("%d\n", ctx->handle); + if (ctx->handle == -1) { DRM_DEBUG("Not enough free contexts.\n"); /* Should this return -EBUSY instead? */ return -ENOMEM; } - if (ctx.handle != DRM_KERNEL_CONTEXT) { + if (ctx->handle != DRM_KERNEL_CONTEXT) { if (dev->driver->context_ctor) - if (!dev->driver->context_ctor(dev, ctx.handle)) { + if (!dev->driver->context_ctor(dev, ctx->handle)) { DRM_DEBUG("Running out of ctxs or memory.\n"); return -ENOMEM; } @@ -373,21 +347,18 @@ int drm_addctx(struct inode *inode, struct file *filp, } INIT_LIST_HEAD(&ctx_entry->head); - ctx_entry->handle = ctx.handle; - ctx_entry->tag = priv; + ctx_entry->handle = ctx->handle; + ctx_entry->tag = file_priv; mutex_lock(&dev->ctxlist_mutex); list_add(&ctx_entry->head, &dev->ctxlist); ++dev->ctx_count; mutex_unlock(&dev->ctxlist_mutex); - if (copy_to_user(argp, &ctx, sizeof(ctx))) - return -EFAULT; return 0; } -int drm_modctx(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_modctx(struct drm_device *dev, void *data, struct drm_file *file_priv) { /* This does nothing */ return 0; @@ -397,25 +368,18 @@ int drm_modctx(struct inode *inode, struct file *filp, * Get context. * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg user argument pointing to a drm_ctx structure. * \return zero on success or a negative number on failure. */ -int drm_getctx(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_getctx(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_ctx __user *argp = (void __user *)arg; - struct drm_ctx ctx; - - if (copy_from_user(&ctx, argp, sizeof(ctx))) - return -EFAULT; + struct drm_ctx *ctx = data; /* This is 0, because we don't handle any context flags */ - ctx.flags = 0; + ctx->flags = 0; - if (copy_to_user(argp, &ctx, sizeof(ctx))) - return -EFAULT; return 0; } @@ -423,50 +387,40 @@ int drm_getctx(struct inode *inode, struct file *filp, * Switch context. * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg user argument pointing to a drm_ctx structure. * \return zero on success or a negative number on failure. * * Calls context_switch(). */ -int drm_switchctx(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_switchctx(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - struct drm_ctx ctx; + struct drm_ctx *ctx = data; - if (copy_from_user(&ctx, (struct drm_ctx __user *) arg, sizeof(ctx))) - return -EFAULT; - - DRM_DEBUG("%d\n", ctx.handle); - return drm_context_switch(dev, dev->last_context, ctx.handle); + DRM_DEBUG("%d\n", ctx->handle); + return drm_context_switch(dev, dev->last_context, ctx->handle); } /** * New context. * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg user argument pointing to a drm_ctx structure. * \return zero on success or a negative number on failure. * * Calls context_switch_complete(). */ -int drm_newctx(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_newctx(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - struct drm_ctx ctx; + struct drm_ctx *ctx = data; - if (copy_from_user(&ctx, (struct drm_ctx __user *) arg, sizeof(ctx))) - return -EFAULT; - - DRM_DEBUG("%d\n", ctx.handle); - drm_context_switch_complete(dev, ctx.handle); + DRM_DEBUG("%d\n", ctx->handle); + drm_context_switch_complete(dev, ctx->handle); return 0; } @@ -475,31 +429,26 @@ int drm_newctx(struct inode *inode, struct file *filp, * Remove context. * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg user argument pointing to a drm_ctx structure. * \return zero on success or a negative number on failure. * * If not the special kernel context, calls ctxbitmap_free() to free the specified context. */ -int drm_rmctx(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_rmctx(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - struct drm_ctx ctx; - - if (copy_from_user(&ctx, (struct drm_ctx __user *) arg, sizeof(ctx))) - return -EFAULT; + struct drm_ctx *ctx = data; - DRM_DEBUG("%d\n", ctx.handle); - if (ctx.handle == DRM_KERNEL_CONTEXT + 1) { - priv->remove_auth_on_close = 1; + DRM_DEBUG("%d\n", ctx->handle); + if (ctx->handle == DRM_KERNEL_CONTEXT + 1) { + file_priv->remove_auth_on_close = 1; } - if (ctx.handle != DRM_KERNEL_CONTEXT) { + if (ctx->handle != DRM_KERNEL_CONTEXT) { if (dev->driver->context_dtor) - dev->driver->context_dtor(dev, ctx.handle); - drm_ctxbitmap_free(dev, ctx.handle); + dev->driver->context_dtor(dev, ctx->handle); + drm_ctxbitmap_free(dev, ctx->handle); } mutex_lock(&dev->ctxlist_mutex); @@ -507,7 +456,7 @@ int drm_rmctx(struct inode *inode, struct file *filp, struct drm_ctx_list *pos, *n; list_for_each_entry_safe(pos, n, &dev->ctxlist, head) { - if (pos->handle == ctx.handle) { + if (pos->handle == ctx->handle) { list_del(&pos->head); drm_free(pos, sizeof(*pos), DRM_MEM_CTXLIST); --dev->ctx_count; diff --git a/drivers/char/drm/drm_dma.c b/drivers/char/drm/drm_dma.c index 802fbdbfe1b3..7a8e2fba4678 100644 --- a/drivers/char/drm/drm_dma.c +++ b/drivers/char/drm/drm_dma.c @@ -136,7 +136,7 @@ void drm_free_buffer(struct drm_device *dev, struct drm_buf * buf) buf->waiting = 0; buf->pending = 0; - buf->filp = NULL; + buf->file_priv = NULL; buf->used = 0; if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE) @@ -148,11 +148,12 @@ void drm_free_buffer(struct drm_device *dev, struct drm_buf * buf) /** * Reclaim the buffers. * - * \param filp file pointer. + * \param file_priv DRM file private. * - * Frees each buffer associated with \p filp not already on the hardware. + * Frees each buffer associated with \p file_priv not already on the hardware. */ -void drm_core_reclaim_buffers(struct drm_device *dev, struct file *filp) +void drm_core_reclaim_buffers(struct drm_device *dev, + struct drm_file *file_priv) { struct drm_device_dma *dma = dev->dma; int i; @@ -160,7 +161,7 @@ void drm_core_reclaim_buffers(struct drm_device *dev, struct file *filp) if (!dma) return; for (i = 0; i < dma->buf_count; i++) { - if (dma->buflist[i]->filp == filp) { + if (dma->buflist[i]->file_priv == file_priv) { switch (dma->buflist[i]->list) { case DRM_LIST_NONE: drm_free_buffer(dev, dma->buflist[i]); diff --git a/drivers/char/drm/drm_drawable.c b/drivers/char/drm/drm_drawable.c index d6cdba5644e2..1839c57663c5 100644 --- a/drivers/char/drm/drm_drawable.c +++ b/drivers/char/drm/drm_drawable.c @@ -40,11 +40,10 @@ /** * Allocate drawable ID and memory to store information about it. */ -int drm_adddraw(DRM_IOCTL_ARGS) +int drm_adddraw(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; unsigned long irqflags; - struct drm_draw draw; + struct drm_draw *draw = data; int new_id = 0; int ret; @@ -63,11 +62,9 @@ again: spin_unlock_irqrestore(&dev->drw_lock, irqflags); - draw.handle = new_id; + draw->handle = new_id; - DRM_DEBUG("%d\n", draw.handle); - - DRM_COPY_TO_USER_IOCTL((struct drm_draw __user *)data, draw, sizeof(draw)); + DRM_DEBUG("%d\n", draw->handle); return 0; } @@ -75,72 +72,64 @@ again: /** * Free drawable ID and memory to store information about it. */ -int drm_rmdraw(DRM_IOCTL_ARGS) +int drm_rmdraw(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; - struct drm_draw draw; + struct drm_draw *draw = data; unsigned long irqflags; - DRM_COPY_FROM_USER_IOCTL(draw, (struct drm_draw __user *) data, - sizeof(draw)); - spin_lock_irqsave(&dev->drw_lock, irqflags); - drm_free(drm_get_drawable_info(dev, draw.handle), + drm_free(drm_get_drawable_info(dev, draw->handle), sizeof(struct drm_drawable_info), DRM_MEM_BUFS); - idr_remove(&dev->drw_idr, draw.handle); + idr_remove(&dev->drw_idr, draw->handle); spin_unlock_irqrestore(&dev->drw_lock, irqflags); - DRM_DEBUG("%d\n", draw.handle); + DRM_DEBUG("%d\n", draw->handle); return 0; } -int drm_update_drawable_info(DRM_IOCTL_ARGS) +int drm_update_drawable_info(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; - struct drm_update_draw update; + struct drm_update_draw *update = data; unsigned long irqflags; struct drm_clip_rect *rects; struct drm_drawable_info *info; int err; - DRM_COPY_FROM_USER_IOCTL(update, (struct drm_update_draw __user *) data, - sizeof(update)); - - info = idr_find(&dev->drw_idr, update.handle); + info = idr_find(&dev->drw_idr, update->handle); if (!info) { info = drm_calloc(1, sizeof(*info), DRM_MEM_BUFS); if (!info) return -ENOMEM; - if (IS_ERR(idr_replace(&dev->drw_idr, info, update.handle))) { - DRM_ERROR("No such drawable %d\n", update.handle); + if (IS_ERR(idr_replace(&dev->drw_idr, info, update->handle))) { + DRM_ERROR("No such drawable %d\n", update->handle); drm_free(info, sizeof(*info), DRM_MEM_BUFS); return -EINVAL; } } - switch (update.type) { + switch (update->type) { case DRM_DRAWABLE_CLIPRECTS: - if (update.num != info->num_rects) { - rects = drm_alloc(update.num * sizeof(struct drm_clip_rect), + if (update->num != info->num_rects) { + rects = drm_alloc(update->num * sizeof(struct drm_clip_rect), DRM_MEM_BUFS); } else rects = info->rects; - if (update.num && !rects) { + if (update->num && !rects) { DRM_ERROR("Failed to allocate cliprect memory\n"); - err = DRM_ERR(ENOMEM); + err = -ENOMEM; goto error; } - if (update.num && DRM_COPY_FROM_USER(rects, + if (update->num && DRM_COPY_FROM_USER(rects, (struct drm_clip_rect __user *) - (unsigned long)update.data, - update.num * + (unsigned long)update->data, + update->num * sizeof(*rects))) { DRM_ERROR("Failed to copy cliprects from userspace\n"); - err = DRM_ERR(EFAULT); + err = -EFAULT; goto error; } @@ -152,23 +141,23 @@ int drm_update_drawable_info(DRM_IOCTL_ARGS) } info->rects = rects; - info->num_rects = update.num; + info->num_rects = update->num; spin_unlock_irqrestore(&dev->drw_lock, irqflags); DRM_DEBUG("Updated %d cliprects for drawable %d\n", - info->num_rects, update.handle); + info->num_rects, update->handle); break; default: - DRM_ERROR("Invalid update type %d\n", update.type); - return DRM_ERR(EINVAL); + DRM_ERROR("Invalid update type %d\n", update->type); + return -EINVAL; } return 0; error: if (rects != info->rects) - drm_free(rects, update.num * sizeof(struct drm_clip_rect), + drm_free(rects, update->num * sizeof(struct drm_clip_rect), DRM_MEM_BUFS); return err; diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c index 19994cd865de..72668b15e5ce 100644 --- a/drivers/char/drm/drm_drv.c +++ b/drivers/char/drm/drm_drv.c @@ -49,73 +49,74 @@ #include "drmP.h" #include "drm_core.h" -static int drm_version(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); +static int drm_version(struct drm_device *dev, void *data, + struct drm_file *file_priv); /** Ioctl table */ -static drm_ioctl_desc_t drm_ioctls[] = { - [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = {drm_version, 0}, - [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = {drm_getunique, 0}, - [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = {drm_getmagic, 0}, - [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = {drm_irq_by_busid, DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_IOCTL_GET_MAP)] = {drm_getmap, 0}, - [DRM_IOCTL_NR(DRM_IOCTL_GET_CLIENT)] = {drm_getclient, 0}, - [DRM_IOCTL_NR(DRM_IOCTL_GET_STATS)] = {drm_getstats, 0}, - [DRM_IOCTL_NR(DRM_IOCTL_SET_VERSION)] = {drm_setversion, DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = {drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)] = {drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = {drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = {drm_authmagic, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - - [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = {drm_addmap_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_IOCTL_RM_MAP)] = {drm_rmmap_ioctl, DRM_AUTH}, - - [DRM_IOCTL_NR(DRM_IOCTL_SET_SAREA_CTX)] = {drm_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_IOCTL_GET_SAREA_CTX)] = {drm_getsareactx, DRM_AUTH}, - - [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = {drm_addctx, DRM_AUTH|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = {drm_rmctx, DRM_AUTH|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = {drm_modctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = {drm_getctx, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = {drm_switchctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = {drm_newctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = {drm_resctx, DRM_AUTH}, - - [DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = {drm_adddraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = {drm_rmdraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - - [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = {drm_lock, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = {drm_unlock, DRM_AUTH}, - - [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = {drm_noop, DRM_AUTH}, - - [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)] = {drm_addbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = {drm_markbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = {drm_infobufs, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = {drm_mapbufs, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = {drm_freebufs, DRM_AUTH}, +static struct drm_ioctl_desc drm_ioctls[] = { + DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, 0), + DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE, drm_getunique, 0), + DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, 0), + DRM_IOCTL_DEF(DRM_IOCTL_IRQ_BUSID, drm_irq_by_busid, DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_GET_MAP, drm_getmap, 0), + DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT, drm_getclient, 0), + DRM_IOCTL_DEF(DRM_IOCTL_GET_STATS, drm_getstats, 0), + DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER|DRM_ROOT_ONLY), + + DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_BLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_UNBLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_AUTH_MAGIC, drm_authmagic, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + + DRM_IOCTL_DEF(DRM_IOCTL_ADD_MAP, drm_addmap_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_RM_MAP, drm_rmmap_ioctl, DRM_AUTH), + + DRM_IOCTL_DEF(DRM_IOCTL_SET_SAREA_CTX, drm_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_GET_SAREA_CTX, drm_getsareactx, DRM_AUTH), + + DRM_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_addctx, DRM_AUTH|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_MOD_CTX, drm_modctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_GET_CTX, drm_getctx, DRM_AUTH), + DRM_IOCTL_DEF(DRM_IOCTL_SWITCH_CTX, drm_switchctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_NEW_CTX, drm_newctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_RES_CTX, drm_resctx, DRM_AUTH), + + DRM_IOCTL_DEF(DRM_IOCTL_ADD_DRAW, drm_adddraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_RM_DRAW, drm_rmdraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + + DRM_IOCTL_DEF(DRM_IOCTL_LOCK, drm_lock, DRM_AUTH), + DRM_IOCTL_DEF(DRM_IOCTL_UNLOCK, drm_unlock, DRM_AUTH), + + DRM_IOCTL_DEF(DRM_IOCTL_FINISH, drm_noop, DRM_AUTH), + + DRM_IOCTL_DEF(DRM_IOCTL_ADD_BUFS, drm_addbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_MARK_BUFS, drm_markbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_INFO_BUFS, drm_infobufs, DRM_AUTH), + DRM_IOCTL_DEF(DRM_IOCTL_MAP_BUFS, drm_mapbufs, DRM_AUTH), + DRM_IOCTL_DEF(DRM_IOCTL_FREE_BUFS, drm_freebufs, DRM_AUTH), /* The DRM_IOCTL_DMA ioctl should be defined by the driver. */ - [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = {NULL, DRM_AUTH}, + DRM_IOCTL_DEF(DRM_IOCTL_DMA, NULL, DRM_AUTH), - [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = {drm_control, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + DRM_IOCTL_DEF(DRM_IOCTL_CONTROL, drm_control, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), #if __OS_HAS_AGP - [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = {drm_agp_acquire_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = {drm_agp_release_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = {drm_agp_enable_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = {drm_agp_info_ioctl, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = {drm_agp_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = {drm_agp_free_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = {drm_agp_bind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = {drm_agp_unbind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + DRM_IOCTL_DEF(DRM_IOCTL_AGP_ACQUIRE, drm_agp_acquire_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_AGP_RELEASE, drm_agp_release_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_AGP_ENABLE, drm_agp_enable_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_AGP_INFO, drm_agp_info_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_IOCTL_AGP_ALLOC, drm_agp_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_AGP_FREE, drm_agp_free_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_AGP_BIND, drm_agp_bind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_AGP_UNBIND, drm_agp_unbind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), #endif - [DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC)] = {drm_sg_alloc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = {drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + DRM_IOCTL_DEF(DRM_IOCTL_SG_ALLOC, drm_sg_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_SG_FREE, drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = {drm_wait_vblank, 0}, + DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, 0), - [DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW)] = {drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), }; #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) @@ -224,7 +225,7 @@ int drm_lastclose(struct drm_device * dev) if (dev->lock.hw_lock) { dev->sigdata.lock = dev->lock.hw_lock = NULL; /* SHM removed */ - dev->lock.filp = NULL; + dev->lock.file_priv = NULL; wake_up_interruptible(&dev->lock.lock_queue); } mutex_unlock(&dev->struct_mutex); @@ -418,27 +419,19 @@ module_exit(drm_core_exit); * * Fills in the version information in \p arg. */ -static int drm_version(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +static int drm_version(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - struct drm_version __user *argp = (void __user *)arg; - struct drm_version version; + struct drm_version *version = data; int len; - if (copy_from_user(&version, argp, sizeof(version))) - return -EFAULT; + version->version_major = dev->driver->major; + version->version_minor = dev->driver->minor; + version->version_patchlevel = dev->driver->patchlevel; + DRM_COPY(version->name, dev->driver->name); + DRM_COPY(version->date, dev->driver->date); + DRM_COPY(version->desc, dev->driver->desc); - version.version_major = dev->driver->major; - version.version_minor = dev->driver->minor; - version.version_patchlevel = dev->driver->patchlevel; - DRM_COPY(version.name, dev->driver->name); - DRM_COPY(version.date, dev->driver->date); - DRM_COPY(version.desc, dev->driver->desc); - - if (copy_to_user(argp, &version, sizeof(version))) - return -EFAULT; return 0; } @@ -446,7 +439,7 @@ static int drm_version(struct inode *inode, struct file *filp, * Called whenever a process performs an ioctl on /dev/drm. * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg user argument. * \return zero on success or negative number on failure. @@ -457,21 +450,22 @@ static int drm_version(struct inode *inode, struct file *filp, int drm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - drm_ioctl_desc_t *ioctl; + struct drm_file *file_priv = filp->private_data; + struct drm_device *dev = file_priv->head->dev; + struct drm_ioctl_desc *ioctl; drm_ioctl_t *func; unsigned int nr = DRM_IOCTL_NR(cmd); int retcode = -EINVAL; + char *kdata = NULL; atomic_inc(&dev->ioctl_count); atomic_inc(&dev->counts[_DRM_STAT_IOCTLS]); - ++priv->ioctl_count; + ++file_priv->ioctl_count; DRM_DEBUG("pid=%d, cmd=0x%02x, nr=0x%02x, dev 0x%lx, auth=%d\n", current->pid, cmd, nr, - (long)old_encode_dev(priv->head->device), - priv->authenticated); + (long)old_encode_dev(file_priv->head->device), + file_priv->authenticated); if ((nr >= DRM_CORE_IOCTL_COUNT) && ((nr < DRM_COMMAND_BASE) || (nr >= DRM_COMMAND_END))) @@ -489,18 +483,40 @@ int drm_ioctl(struct inode *inode, struct file *filp, if ((nr == DRM_IOCTL_NR(DRM_IOCTL_DMA)) && dev->driver->dma_ioctl) func = dev->driver->dma_ioctl; + if (!func) { DRM_DEBUG("no function\n"); retcode = -EINVAL; } else if (((ioctl->flags & DRM_ROOT_ONLY) && !capable(CAP_SYS_ADMIN)) || - ((ioctl->flags & DRM_AUTH) && !priv->authenticated) || - ((ioctl->flags & DRM_MASTER) && !priv->master)) { + ((ioctl->flags & DRM_AUTH) && !file_priv->authenticated) || + ((ioctl->flags & DRM_MASTER) && !file_priv->master)) { retcode = -EACCES; } else { - retcode = func(inode, filp, cmd, arg); + if (cmd & (IOC_IN | IOC_OUT)) { + kdata = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL); + if (!kdata) + return -ENOMEM; + } + + if (cmd & IOC_IN) { + if (copy_from_user(kdata, (void __user *)arg, + _IOC_SIZE(cmd)) != 0) { + retcode = -EACCES; + goto err_i1; + } + } + retcode = func(dev, kdata, file_priv); + + if (cmd & IOC_OUT) { + if (copy_to_user((void __user *)arg, kdata, + _IOC_SIZE(cmd)) != 0) + retcode = -EACCES; + } } err_i1: + if (kdata) + kfree(kdata); atomic_dec(&dev->ioctl_count); if (retcode) DRM_DEBUG("ret = %x\n", retcode); diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c index 7bc51bac450d..f383fc37190c 100644 --- a/drivers/char/drm/drm_fops.c +++ b/drivers/char/drm/drm_fops.c @@ -242,6 +242,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, memset(priv, 0, sizeof(*priv)); filp->private_data = priv; + priv->filp = filp; priv->uid = current->euid; priv->pid = current->pid; priv->minor = minor; @@ -312,7 +313,7 @@ EXPORT_SYMBOL(drm_fasync); * Release file. * * \param inode device inode - * \param filp file pointer. + * \param file_priv DRM file private. * \return zero on success or a negative number on failure. * * If the hardware lock is held then free it, and take it again for the kernel @@ -322,29 +323,28 @@ EXPORT_SYMBOL(drm_fasync); */ int drm_release(struct inode *inode, struct file *filp) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev; + struct drm_file *file_priv = filp->private_data; + struct drm_device *dev = file_priv->head->dev; int retcode = 0; lock_kernel(); - dev = priv->head->dev; DRM_DEBUG("open_count = %d\n", dev->open_count); if (dev->driver->preclose) - dev->driver->preclose(dev, filp); + dev->driver->preclose(dev, file_priv); /* ======================================================== * Begin inline drm_release */ DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n", - current->pid, (long)old_encode_dev(priv->head->device), + current->pid, (long)old_encode_dev(file_priv->head->device), dev->open_count); if (dev->driver->reclaim_buffers_locked && dev->lock.hw_lock) { - if (drm_i_have_hw_lock(filp)) { - dev->driver->reclaim_buffers_locked(dev, filp); + if (drm_i_have_hw_lock(dev, file_priv)) { + dev->driver->reclaim_buffers_locked(dev, file_priv); } else { unsigned long _end=jiffies + 3*DRM_HZ; int locked = 0; @@ -370,7 +370,7 @@ int drm_release(struct inode *inode, struct file *filp) "\tI will go on reclaiming the buffers anyway.\n"); } - dev->driver->reclaim_buffers_locked(dev, filp); + dev->driver->reclaim_buffers_locked(dev, file_priv); drm_idlelock_release(&dev->lock); } } @@ -378,12 +378,12 @@ int drm_release(struct inode *inode, struct file *filp) if (dev->driver->reclaim_buffers_idlelocked && dev->lock.hw_lock) { drm_idlelock_take(&dev->lock); - dev->driver->reclaim_buffers_idlelocked(dev, filp); + dev->driver->reclaim_buffers_idlelocked(dev, file_priv); drm_idlelock_release(&dev->lock); } - if (drm_i_have_hw_lock(filp)) { + if (drm_i_have_hw_lock(dev, file_priv)) { DRM_DEBUG("File %p released, freeing lock for context %d\n", filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); @@ -394,7 +394,7 @@ int drm_release(struct inode *inode, struct file *filp) if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) && !dev->driver->reclaim_buffers_locked) { - dev->driver->reclaim_buffers(dev, filp); + dev->driver->reclaim_buffers(dev, file_priv); } drm_fasync(-1, filp, 0); @@ -404,7 +404,7 @@ int drm_release(struct inode *inode, struct file *filp) struct drm_ctx_list *pos, *n; list_for_each_entry_safe(pos, n, &dev->ctxlist, head) { - if (pos->tag == priv && + if (pos->tag == file_priv && pos->handle != DRM_KERNEL_CONTEXT) { if (dev->driver->context_dtor) dev->driver->context_dtor(dev, @@ -421,18 +421,18 @@ int drm_release(struct inode *inode, struct file *filp) mutex_unlock(&dev->ctxlist_mutex); mutex_lock(&dev->struct_mutex); - if (priv->remove_auth_on_close == 1) { + if (file_priv->remove_auth_on_close == 1) { struct drm_file *temp; list_for_each_entry(temp, &dev->filelist, lhead) temp->authenticated = 0; } - list_del(&priv->lhead); + list_del(&file_priv->lhead); mutex_unlock(&dev->struct_mutex); if (dev->driver->postclose) - dev->driver->postclose(dev, priv); - drm_free(priv, sizeof(*priv), DRM_MEM_FILES); + dev->driver->postclose(dev, file_priv); + drm_free(file_priv, sizeof(*file_priv), DRM_MEM_FILES); /* ======================================================== * End inline drm_release diff --git a/drivers/char/drm/drm_ioc32.c b/drivers/char/drm/drm_ioc32.c index 462f46f2049a..2286f3312c5c 100644 --- a/drivers/char/drm/drm_ioc32.c +++ b/drivers/char/drm/drm_ioc32.c @@ -1040,7 +1040,7 @@ drm_ioctl_compat_t *drm_compat_ioctls[] = { * Called whenever a 32-bit process running under a 64-bit kernel * performs an ioctl on /dev/drm. * - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg user argument. * \return zero on success or negative number on failure. diff --git a/drivers/char/drm/drm_ioctl.c b/drivers/char/drm/drm_ioctl.c index b195e102e737..d9be14624526 100644 --- a/drivers/char/drm/drm_ioctl.c +++ b/drivers/char/drm/drm_ioctl.c @@ -42,30 +42,24 @@ * Get the bus id. * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg user argument, pointing to a drm_unique structure. * \return zero on success or a negative number on failure. * * Copies the bus id from drm_device::unique into user space. */ -int drm_getunique(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_getunique(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - struct drm_unique __user *argp = (void __user *)arg; - struct drm_unique u; + struct drm_unique *u = data; - if (copy_from_user(&u, argp, sizeof(u))) - return -EFAULT; - if (u.unique_len >= dev->unique_len) { - if (copy_to_user(u.unique, dev->unique, dev->unique_len)) + if (u->unique_len >= dev->unique_len) { + if (copy_to_user(u->unique, dev->unique, dev->unique_len)) return -EFAULT; } - u.unique_len = dev->unique_len; - if (copy_to_user(argp, &u, sizeof(u))) - return -EFAULT; + u->unique_len = dev->unique_len; + return 0; } @@ -73,7 +67,7 @@ int drm_getunique(struct inode *inode, struct file *filp, * Set the bus id. * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg user argument, pointing to a drm_unique structure. * \return zero on success or a negative number on failure. @@ -83,28 +77,23 @@ int drm_getunique(struct inode *inode, struct file *filp, * in interface version 1.1 and will return EBUSY when setversion has requested * version 1.1 or greater. */ -int drm_setunique(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_setunique(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - struct drm_unique u; + struct drm_unique *u = data; int domain, bus, slot, func, ret; if (dev->unique_len || dev->unique) return -EBUSY; - if (copy_from_user(&u, (struct drm_unique __user *) arg, sizeof(u))) - return -EFAULT; - - if (!u.unique_len || u.unique_len > 1024) + if (!u->unique_len || u->unique_len > 1024) return -EINVAL; - dev->unique_len = u.unique_len; - dev->unique = drm_alloc(u.unique_len + 1, DRM_MEM_DRIVER); + dev->unique_len = u->unique_len; + dev->unique = drm_alloc(u->unique_len + 1, DRM_MEM_DRIVER); if (!dev->unique) return -ENOMEM; - if (copy_from_user(dev->unique, u.unique, dev->unique_len)) + if (copy_from_user(dev->unique, u->unique, dev->unique_len)) return -EFAULT; dev->unique[dev->unique_len] = '\0'; @@ -123,7 +112,7 @@ int drm_setunique(struct inode *inode, struct file *filp, */ ret = sscanf(dev->unique, "PCI:%d:%d:%d", &bus, &slot, &func); if (ret != 3) - return DRM_ERR(EINVAL); + return -EINVAL; domain = bus >> 8; bus &= 0xff; @@ -172,7 +161,7 @@ static int drm_set_busid(struct drm_device * dev) * Get a mapping information. * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg user argument, pointing to a drm_map structure. * @@ -181,21 +170,16 @@ static int drm_set_busid(struct drm_device * dev) * Searches for the mapping with the specified offset and copies its information * into userspace */ -int drm_getmap(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_getmap(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - struct drm_map __user *argp = (void __user *)arg; - struct drm_map map; + struct drm_map *map = data; struct drm_map_list *r_list = NULL; struct list_head *list; int idx; int i; - if (copy_from_user(&map, argp, sizeof(map))) - return -EFAULT; - idx = map.offset; + idx = map->offset; mutex_lock(&dev->struct_mutex); if (idx < 0) { @@ -216,16 +200,14 @@ int drm_getmap(struct inode *inode, struct file *filp, return -EINVAL; } - map.offset = r_list->map->offset; - map.size = r_list->map->size; - map.type = r_list->map->type; - map.flags = r_list->map->flags; - map.handle = (void *)(unsigned long)r_list->user_token; - map.mtrr = r_list->map->mtrr; + map->offset = r_list->map->offset; + map->size = r_list->map->size; + map->type = r_list->map->type; + map->flags = r_list->map->flags; + map->handle = (void *)(unsigned long) r_list->user_token; + map->mtrr = r_list->map->mtrr; mutex_unlock(&dev->struct_mutex); - if (copy_to_user(argp, &map, sizeof(map))) - return -EFAULT; return 0; } @@ -233,7 +215,7 @@ int drm_getmap(struct inode *inode, struct file *filp, * Get client information. * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg user argument, pointing to a drm_client structure. * @@ -242,20 +224,15 @@ int drm_getmap(struct inode *inode, struct file *filp, * Searches for the client with the specified index and copies its information * into userspace */ -int drm_getclient(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_getclient(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - struct drm_client __user *argp = (struct drm_client __user *)arg; - struct drm_client client; + struct drm_client *client = data; struct drm_file *pt; int idx; int i; - if (copy_from_user(&client, argp, sizeof(client))) - return -EFAULT; - idx = client.idx; + idx = client->idx; mutex_lock(&dev->struct_mutex); if (list_empty(&dev->filelist)) { @@ -269,15 +246,13 @@ int drm_getclient(struct inode *inode, struct file *filp, break; } - client.auth = pt->authenticated; - client.pid = pt->pid; - client.uid = pt->uid; - client.magic = pt->magic; - client.iocs = pt->ioctl_count; + client->auth = pt->authenticated; + client->pid = pt->pid; + client->uid = pt->uid; + client->magic = pt->magic; + client->iocs = pt->ioctl_count; mutex_unlock(&dev->struct_mutex); - if (copy_to_user(argp, &client, sizeof(client))) - return -EFAULT; return 0; } @@ -285,39 +260,35 @@ int drm_getclient(struct inode *inode, struct file *filp, * Get statistics information. * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg user argument, pointing to a drm_stats structure. * * \return zero on success or a negative number on failure. */ -int drm_getstats(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_getstats(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - struct drm_stats stats; + struct drm_stats *stats = data; int i; - memset(&stats, 0, sizeof(stats)); + memset(stats, 0, sizeof(stats)); mutex_lock(&dev->struct_mutex); for (i = 0; i < dev->counters; i++) { if (dev->types[i] == _DRM_STAT_LOCK) - stats.data[i].value - = (dev->lock.hw_lock ? dev->lock.hw_lock->lock : 0); + stats->data[i].value = + (dev->lock.hw_lock ? dev->lock.hw_lock->lock : 0); else - stats.data[i].value = atomic_read(&dev->counts[i]); - stats.data[i].type = dev->types[i]; + stats->data[i].value = atomic_read(&dev->counts[i]); + stats->data[i].type = dev->types[i]; } - stats.count = dev->counters; + stats->count = dev->counters; mutex_unlock(&dev->struct_mutex); - if (copy_to_user((struct drm_stats __user *) arg, &stats, sizeof(stats))) - return -EFAULT; return 0; } @@ -325,64 +296,59 @@ int drm_getstats(struct inode *inode, struct file *filp, * Setversion ioctl. * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg user argument, pointing to a drm_lock structure. * \return zero on success or negative number on failure. * * Sets the requested interface version */ -int drm_setversion(DRM_IOCTL_ARGS) +int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; - struct drm_set_version sv; - struct drm_set_version retv; - int if_version; - struct drm_set_version __user *argp = (void __user *)data; - int ret; - - if (copy_from_user(&sv, argp, sizeof(sv))) - return -EFAULT; - - retv.drm_di_major = DRM_IF_MAJOR; - retv.drm_di_minor = DRM_IF_MINOR; - retv.drm_dd_major = dev->driver->major; - retv.drm_dd_minor = dev->driver->minor; - - if (copy_to_user(argp, &retv, sizeof(retv))) - return -EFAULT; - - if (sv.drm_di_major != -1) { - if (sv.drm_di_major != DRM_IF_MAJOR || - sv.drm_di_minor < 0 || sv.drm_di_minor > DRM_IF_MINOR) - return -EINVAL; - if_version = DRM_IF_VERSION(sv.drm_di_major, sv.drm_di_minor); + struct drm_set_version *sv = data; + int if_version, retcode = 0; + + if (sv->drm_di_major != -1) { + if (sv->drm_di_major != DRM_IF_MAJOR || + sv->drm_di_minor < 0 || sv->drm_di_minor > DRM_IF_MINOR) { + retcode = -EINVAL; + goto done; + } + if_version = DRM_IF_VERSION(sv->drm_di_major, + sv->drm_di_minor); dev->if_version = max(if_version, dev->if_version); - if (sv.drm_di_minor >= 1) { + if (sv->drm_di_minor >= 1) { /* * Version 1.1 includes tying of DRM to specific device */ - ret = drm_set_busid(dev); - if (ret) - return ret; + drm_set_busid(dev); } } - if (sv.drm_dd_major != -1) { - if (sv.drm_dd_major != dev->driver->major || - sv.drm_dd_minor < 0 - || sv.drm_dd_minor > dev->driver->minor) - return -EINVAL; + if (sv->drm_dd_major != -1) { + if (sv->drm_dd_major != dev->driver->major || + sv->drm_dd_minor < 0 || sv->drm_dd_minor > + dev->driver->minor) { + retcode = -EINVAL; + goto done; + } if (dev->driver->set_version) - dev->driver->set_version(dev, &sv); + dev->driver->set_version(dev, sv); } - return 0; + +done: + sv->drm_di_major = DRM_IF_MAJOR; + sv->drm_di_minor = DRM_IF_MINOR; + sv->drm_dd_major = dev->driver->major; + sv->drm_dd_minor = dev->driver->minor; + + return retcode; } /** No-op ioctl. */ -int drm_noop(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) +int drm_noop(struct drm_device *dev, void *data, + struct drm_file *file_priv) { DRM_DEBUG("\n"); return 0; diff --git a/drivers/char/drm/drm_irq.c b/drivers/char/drm/drm_irq.c index 871d2fde09b3..05eae63f85ba 100644 --- a/drivers/char/drm/drm_irq.c +++ b/drivers/char/drm/drm_irq.c @@ -41,7 +41,7 @@ * Get interrupt from bus id. * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg user argument, pointing to a drm_irq_busid structure. * \return zero on success or a negative number on failure. @@ -50,30 +50,24 @@ * This IOCTL is deprecated, and will now return EINVAL for any busid not equal * to that of the device that this DRM instance attached to. */ -int drm_irq_by_busid(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_irq_by_busid(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - struct drm_irq_busid __user *argp = (void __user *)arg; - struct drm_irq_busid p; + struct drm_irq_busid *p = data; if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) return -EINVAL; - if (copy_from_user(&p, argp, sizeof(p))) - return -EFAULT; - - if ((p.busnum >> 8) != drm_get_pci_domain(dev) || - (p.busnum & 0xff) != dev->pdev->bus->number || - p.devnum != PCI_SLOT(dev->pdev->devfn) || p.funcnum != PCI_FUNC(dev->pdev->devfn)) + if ((p->busnum >> 8) != drm_get_pci_domain(dev) || + (p->busnum & 0xff) != dev->pdev->bus->number || + p->devnum != PCI_SLOT(dev->pdev->devfn) || p->funcnum != PCI_FUNC(dev->pdev->devfn)) return -EINVAL; - p.irq = dev->irq; + p->irq = dev->irq; + + DRM_DEBUG("%d:%d:%d => IRQ %d\n", p->busnum, p->devnum, p->funcnum, + p->irq); - DRM_DEBUG("%d:%d:%d => IRQ %d\n", p.busnum, p.devnum, p.funcnum, p.irq); - if (copy_to_user(argp, &p, sizeof(p))) - return -EFAULT; return 0; } @@ -187,31 +181,27 @@ EXPORT_SYMBOL(drm_irq_uninstall); * IRQ control ioctl. * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg user argument, pointing to a drm_control structure. * \return zero on success or a negative number on failure. * * Calls irq_install() or irq_uninstall() according to \p arg. */ -int drm_control(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_control(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - struct drm_control ctl; + struct drm_control *ctl = data; /* if we haven't irq we fallback for compatibility reasons - this used to be a separate function in drm_dma.h */ - if (copy_from_user(&ctl, (struct drm_control __user *) arg, sizeof(ctl))) - return -EFAULT; - switch (ctl.func) { + switch (ctl->func) { case DRM_INST_HANDLER: if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) return 0; if (dev->if_version < DRM_IF_VERSION(1, 2) && - ctl.irq != dev->irq) + ctl->irq != dev->irq) return -EINVAL; return drm_irq_install(dev); case DRM_UNINST_HANDLER: @@ -227,7 +217,7 @@ int drm_control(struct inode *inode, struct file *filp, * Wait for VBLANK. * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param data user argument, pointing to a drm_wait_vblank structure. * \return zero on success or a negative number on failure. @@ -242,31 +232,25 @@ int drm_control(struct inode *inode, struct file *filp, * * If a signal is not requested, then calls vblank_wait(). */ -int drm_wait_vblank(DRM_IOCTL_ARGS) +int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - union drm_wait_vblank __user *argp = (void __user *)data; - union drm_wait_vblank vblwait; + union drm_wait_vblank *vblwait = data; struct timeval now; int ret = 0; unsigned int flags, seq; - if (!dev->irq) + if ((!dev->irq) || (!dev->irq_enabled)) return -EINVAL; - if (copy_from_user(&vblwait, argp, sizeof(vblwait))) - return -EFAULT; - - if (vblwait.request.type & + if (vblwait->request.type & ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) { DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n", - vblwait.request.type, + vblwait->request.type, (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)); return -EINVAL; } - flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK; + flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK; if (!drm_core_check_feature(dev, (flags & _DRM_VBLANK_SECONDARY) ? DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL)) @@ -275,10 +259,10 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) seq = atomic_read((flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2 : &dev->vbl_received); - switch (vblwait.request.type & _DRM_VBLANK_TYPES_MASK) { + switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) { case _DRM_VBLANK_RELATIVE: - vblwait.request.sequence += seq; - vblwait.request.type &= ~_DRM_VBLANK_RELATIVE; + vblwait->request.sequence += seq; + vblwait->request.type &= ~_DRM_VBLANK_RELATIVE; case _DRM_VBLANK_ABSOLUTE: break; default: @@ -286,8 +270,8 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) } if ((flags & _DRM_VBLANK_NEXTONMISS) && - (seq - vblwait.request.sequence) <= (1<<23)) { - vblwait.request.sequence = seq + 1; + (seq - vblwait->request.sequence) <= (1<<23)) { + vblwait->request.sequence = seq + 1; } if (flags & _DRM_VBLANK_SIGNAL) { @@ -303,12 +287,13 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) * that case */ list_for_each_entry(vbl_sig, vbl_sigs, head) { - if (vbl_sig->sequence == vblwait.request.sequence - && vbl_sig->info.si_signo == vblwait.request.signal + if (vbl_sig->sequence == vblwait->request.sequence + && vbl_sig->info.si_signo == + vblwait->request.signal && vbl_sig->task == current) { spin_unlock_irqrestore(&dev->vbl_lock, irqflags); - vblwait.reply.sequence = seq; + vblwait->reply.sequence = seq; goto done; } } @@ -330,8 +315,8 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) memset((void *)vbl_sig, 0, sizeof(*vbl_sig)); - vbl_sig->sequence = vblwait.request.sequence; - vbl_sig->info.si_signo = vblwait.request.signal; + vbl_sig->sequence = vblwait->request.sequence; + vbl_sig->info.si_signo = vblwait->request.signal; vbl_sig->task = current; spin_lock_irqsave(&dev->vbl_lock, irqflags); @@ -340,25 +325,22 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev->vbl_lock, irqflags); - vblwait.reply.sequence = seq; + vblwait->reply.sequence = seq; } else { if (flags & _DRM_VBLANK_SECONDARY) { if (dev->driver->vblank_wait2) - ret = dev->driver->vblank_wait2(dev, &vblwait.request.sequence); + ret = dev->driver->vblank_wait2(dev, &vblwait->request.sequence); } else if (dev->driver->vblank_wait) ret = dev->driver->vblank_wait(dev, - &vblwait.request.sequence); + &vblwait->request.sequence); do_gettimeofday(&now); - vblwait.reply.tval_sec = now.tv_sec; - vblwait.reply.tval_usec = now.tv_usec; + vblwait->reply.tval_sec = now.tv_sec; + vblwait->reply.tval_usec = now.tv_usec; } done: - if (copy_to_user(argp, &vblwait, sizeof(vblwait))) - return -EFAULT; - return ret; } diff --git a/drivers/char/drm/drm_lock.c b/drivers/char/drm/drm_lock.c index c0534b5a8b78..c6b73e744d67 100644 --- a/drivers/char/drm/drm_lock.c +++ b/drivers/char/drm/drm_lock.c @@ -41,39 +41,33 @@ static int drm_notifier(void *priv); * Lock ioctl. * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg user argument, pointing to a drm_lock structure. * \return zero on success or negative number on failure. * * Add the current task to the lock wait queue, and attempt to take to lock. */ -int drm_lock(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; DECLARE_WAITQUEUE(entry, current); - struct drm_lock lock; + struct drm_lock *lock = data; int ret = 0; - ++priv->lock_count; + ++file_priv->lock_count; - if (copy_from_user(&lock, (struct drm_lock __user *) arg, sizeof(lock))) - return -EFAULT; - - if (lock.context == DRM_KERNEL_CONTEXT) { + if (lock->context == DRM_KERNEL_CONTEXT) { DRM_ERROR("Process %d using kernel context %d\n", - current->pid, lock.context); + current->pid, lock->context); return -EINVAL; } DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", - lock.context, current->pid, - dev->lock.hw_lock->lock, lock.flags); + lock->context, current->pid, + dev->lock.hw_lock->lock, lock->flags); if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE)) - if (lock.context < 0) + if (lock->context < 0) return -EINVAL; add_wait_queue(&dev->lock.lock_queue, &entry); @@ -87,8 +81,8 @@ int drm_lock(struct inode *inode, struct file *filp, ret = -EINTR; break; } - if (drm_lock_take(&dev->lock, lock.context)) { - dev->lock.filp = filp; + if (drm_lock_take(&dev->lock, lock->context)) { + dev->lock.file_priv = file_priv; dev->lock.lock_time = jiffies; atomic_inc(&dev->counts[_DRM_STAT_LOCKS]); break; /* Got lock */ @@ -107,7 +101,8 @@ int drm_lock(struct inode *inode, struct file *filp, __set_current_state(TASK_RUNNING); remove_wait_queue(&dev->lock.lock_queue, &entry); - DRM_DEBUG( "%d %s\n", lock.context, ret ? "interrupted" : "has lock" ); + DRM_DEBUG("%d %s\n", lock->context, + ret ? "interrupted" : "has lock"); if (ret) return ret; sigemptyset(&dev->sigmask); @@ -115,24 +110,26 @@ int drm_lock(struct inode *inode, struct file *filp, sigaddset(&dev->sigmask, SIGTSTP); sigaddset(&dev->sigmask, SIGTTIN); sigaddset(&dev->sigmask, SIGTTOU); - dev->sigdata.context = lock.context; + dev->sigdata.context = lock->context; dev->sigdata.lock = dev->lock.hw_lock; block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask); - if (dev->driver->dma_ready && (lock.flags & _DRM_LOCK_READY)) + if (dev->driver->dma_ready && (lock->flags & _DRM_LOCK_READY)) dev->driver->dma_ready(dev); - if (dev->driver->dma_quiescent && (lock.flags & _DRM_LOCK_QUIESCENT)) { + if (dev->driver->dma_quiescent && (lock->flags & _DRM_LOCK_QUIESCENT)) + { if (dev->driver->dma_quiescent(dev)) { - DRM_DEBUG("%d waiting for DMA quiescent\n", lock.context); - return DRM_ERR(EBUSY); + DRM_DEBUG("%d waiting for DMA quiescent\n", + lock->context); + return -EBUSY; } } if (dev->driver->kernel_context_switch && - dev->last_context != lock.context) { + dev->last_context != lock->context) { dev->driver->kernel_context_switch(dev, dev->last_context, - lock.context); + lock->context); } return 0; @@ -142,27 +139,21 @@ int drm_lock(struct inode *inode, struct file *filp, * Unlock ioctl. * * \param inode device inode. - * \param filp file pointer. + * \param file_priv DRM file private. * \param cmd command. * \param arg user argument, pointing to a drm_lock structure. * \return zero on success or negative number on failure. * * Transfer and free the lock. */ -int drm_unlock(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - struct drm_lock lock; + struct drm_lock *lock = data; unsigned long irqflags; - if (copy_from_user(&lock, (struct drm_lock __user *) arg, sizeof(lock))) - return -EFAULT; - - if (lock.context == DRM_KERNEL_CONTEXT) { + if (lock->context == DRM_KERNEL_CONTEXT) { DRM_ERROR("Process %d using kernel context %d\n", - current->pid, lock.context); + current->pid, lock->context); return -EINVAL; } @@ -184,7 +175,7 @@ int drm_unlock(struct inode *inode, struct file *filp, if (dev->driver->kernel_context_switch_unlock) dev->driver->kernel_context_switch_unlock(dev); else { - if (drm_lock_free(&dev->lock,lock.context)) { + if (drm_lock_free(&dev->lock,lock->context)) { /* FIXME: Should really bail out here. */ } } @@ -257,7 +248,7 @@ static int drm_lock_transfer(struct drm_lock_data *lock_data, unsigned int old, new, prev; volatile unsigned int *lock = &lock_data->hw_lock->lock; - lock_data->filp = NULL; + lock_data->file_priv = NULL; do { old = *lock; new = context | _DRM_LOCK_HELD; @@ -390,13 +381,11 @@ void drm_idlelock_release(struct drm_lock_data *lock_data) EXPORT_SYMBOL(drm_idlelock_release); -int drm_i_have_hw_lock(struct file *filp) +int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv) { - DRM_DEVICE; - - return (priv->lock_count && dev->lock.hw_lock && + return (file_priv->lock_count && dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) && - dev->lock.filp == filp); + dev->lock.file_priv == file_priv); } EXPORT_SYMBOL(drm_i_have_hw_lock); diff --git a/drivers/char/drm/drm_os_linux.h b/drivers/char/drm/drm_os_linux.h index 0b8d3433386d..114e54e0f61b 100644 --- a/drivers/char/drm/drm_os_linux.h +++ b/drivers/char/drm/drm_os_linux.h @@ -6,11 +6,6 @@ #include <linux/interrupt.h> /* For task queue support */ #include <linux/delay.h> -/** File pointer type */ -#define DRMFILE struct file * -/** Ioctl arguments */ -#define DRM_IOCTL_ARGS struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data -#define DRM_ERR(d) -(d) /** Current process ID */ #define DRM_CURRENTPID current->pid #define DRM_SUSER(p) capable(CAP_SYS_ADMIN) @@ -33,9 +28,6 @@ #define DRM_WRITEMEMORYBARRIER() wmb() /** Read/write memory barrier */ #define DRM_MEMORYBARRIER() mb() -/** DRM device local declaration */ -#define DRM_DEVICE struct drm_file *priv = filp->private_data; \ - struct drm_device *dev = priv->head->dev /** IRQ handler arguments and return type and values */ #define DRM_IRQ_ARGS int irq, void *arg @@ -94,8 +86,6 @@ static __inline__ int mtrr_del(int reg, unsigned long base, unsigned long size) #define DRM_GET_USER_UNCHECKED(val, uaddr) \ __get_user(val, uaddr) -#define DRM_GET_PRIV_WITH_RETURN(_priv, _filp) _priv = _filp->private_data - #define DRM_HZ HZ #define DRM_WAIT_ON( ret, queue, timeout, condition ) \ diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h index 30b200b01314..f3593974496c 100644 --- a/drivers/char/drm/drm_pciids.h +++ b/drivers/char/drm/drm_pciids.h @@ -236,10 +236,8 @@ {0x1106, 0x3022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x3118, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_PRO_GROUP_A}, \ {0x1106, 0x3122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ - {0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x3108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ - {0x1106, 0x3304, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x3344, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x3343, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x3230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_DX9_0}, \ diff --git a/drivers/char/drm/drm_scatter.c b/drivers/char/drm/drm_scatter.c index 067d25daaf17..eb7fa437355e 100644 --- a/drivers/char/drm/drm_scatter.c +++ b/drivers/char/drm/drm_scatter.c @@ -62,13 +62,8 @@ void drm_sg_cleanup(struct drm_sg_mem * entry) # define ScatterHandle(x) (unsigned int)(x) #endif -int drm_sg_alloc(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - struct drm_scatter_gather __user *argp = (void __user *)arg; - struct drm_scatter_gather request; struct drm_sg_mem *entry; unsigned long pages, i, j; @@ -80,17 +75,13 @@ int drm_sg_alloc(struct inode *inode, struct file *filp, if (dev->sg) return -EINVAL; - if (copy_from_user(&request, argp, sizeof(request))) - return -EFAULT; - entry = drm_alloc(sizeof(*entry), DRM_MEM_SGLISTS); if (!entry) return -ENOMEM; memset(entry, 0, sizeof(*entry)); - - pages = (request.size + PAGE_SIZE - 1) / PAGE_SIZE; - DRM_DEBUG("sg size=%ld pages=%ld\n", request.size, pages); + pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE; + DRM_DEBUG("sg size=%ld pages=%ld\n", request->size, pages); entry->pages = pages; entry->pagelist = drm_alloc(pages * sizeof(*entry->pagelist), @@ -142,12 +133,7 @@ int drm_sg_alloc(struct inode *inode, struct file *filp, SetPageReserved(entry->pagelist[j]); } - request.handle = entry->handle; - - if (copy_to_user(argp, &request, sizeof(request))) { - drm_sg_cleanup(entry); - return -EFAULT; - } + request->handle = entry->handle; dev->sg = entry; @@ -197,27 +183,31 @@ int drm_sg_alloc(struct inode *inode, struct file *filp, drm_sg_cleanup(entry); return -ENOMEM; } +EXPORT_SYMBOL(drm_sg_alloc); + -int drm_sg_free(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_sg_alloc_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - struct drm_scatter_gather request; + struct drm_scatter_gather *request = data; + + return drm_sg_alloc(dev, request); + +} + +int drm_sg_free(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_scatter_gather *request = data; struct drm_sg_mem *entry; if (!drm_core_check_feature(dev, DRIVER_SG)) return -EINVAL; - if (copy_from_user(&request, - (struct drm_scatter_gather __user *) arg, - sizeof(request))) - return -EFAULT; - entry = dev->sg; dev->sg = NULL; - if (!entry || entry->handle != request.handle) + if (!entry || entry->handle != request->handle) return -EINVAL; DRM_DEBUG("sg free virtual = %p\n", entry->virtual); diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c index 68e36e51ba0c..e8d50af58201 100644 --- a/drivers/char/drm/drm_vm.c +++ b/drivers/char/drm/drm_vm.c @@ -463,7 +463,7 @@ static void drm_vm_close(struct vm_area_struct *vma) /** * mmap DMA memory. * - * \param filp file pointer. + * \param file_priv DRM file private. * \param vma virtual memory area. * \return zero on success or a negative number on failure. * @@ -533,7 +533,7 @@ EXPORT_SYMBOL(drm_core_get_reg_ofs); /** * mmap DMA memory. * - * \param filp file pointer. + * \param file_priv DRM file private. * \param vma virtual memory area. * \return zero on success or a negative number on failure. * diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c index cb449999d0ef..8e841bdee6dc 100644 --- a/drivers/char/drm/i810_dma.c +++ b/drivers/char/drm/i810_dma.c @@ -120,10 +120,9 @@ static const struct file_operations i810_buffer_fops = { .fasync = drm_fasync, }; -static int i810_map_buffer(struct drm_buf * buf, struct file *filp) +static int i810_map_buffer(struct drm_buf * buf, struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = file_priv->head->dev; drm_i810_buf_priv_t *buf_priv = buf->dev_private; drm_i810_private_t *dev_priv = dev->dev_private; const struct file_operations *old_fops; @@ -133,14 +132,14 @@ static int i810_map_buffer(struct drm_buf * buf, struct file *filp) return -EINVAL; down_write(¤t->mm->mmap_sem); - old_fops = filp->f_op; - filp->f_op = &i810_buffer_fops; + old_fops = file_priv->filp->f_op; + file_priv->filp->f_op = &i810_buffer_fops; dev_priv->mmap_buffer = buf; - buf_priv->virtual = (void *)do_mmap(filp, 0, buf->total, + buf_priv->virtual = (void *)do_mmap(file_priv->filp, 0, buf->total, PROT_READ | PROT_WRITE, MAP_SHARED, buf->bus_address); dev_priv->mmap_buffer = NULL; - filp->f_op = old_fops; + file_priv->filp->f_op = old_fops; if (IS_ERR(buf_priv->virtual)) { /* Real error */ DRM_ERROR("mmap error\n"); @@ -173,7 +172,7 @@ static int i810_unmap_buffer(struct drm_buf * buf) } static int i810_dma_get_buffer(struct drm_device * dev, drm_i810_dma_t * d, - struct file *filp) + struct drm_file *file_priv) { struct drm_buf *buf; drm_i810_buf_priv_t *buf_priv; @@ -186,13 +185,13 @@ static int i810_dma_get_buffer(struct drm_device * dev, drm_i810_dma_t * d, return retcode; } - retcode = i810_map_buffer(buf, filp); + retcode = i810_map_buffer(buf, file_priv); if (retcode) { i810_freelist_put(dev, buf); DRM_ERROR("mapbuf failed, retcode %d\n", retcode); return retcode; } - buf->filp = filp; + buf->file_priv = file_priv; buf_priv = buf->dev_private; d->granted = 1; d->request_idx = buf->idx; @@ -380,7 +379,7 @@ static int i810_dma_initialize(struct drm_device * dev, i810_dma_cleanup(dev); DRM_ERROR("can not ioremap virtual address for" " ring buffer\n"); - return DRM_ERR(ENOMEM); + return -ENOMEM; } dev_priv->ring.virtual_start = dev_priv->ring.map.handle; @@ -430,99 +429,29 @@ static int i810_dma_initialize(struct drm_device * dev, return 0; } -/* i810 DRM version 1.1 used a smaller init structure with different - * ordering of values than is currently used (drm >= 1.2). There is - * no defined way to detect the XFree version to correct this problem, - * however by checking using this procedure we can detect the correct - * thing to do. - * - * #1 Read the Smaller init structure from user-space - * #2 Verify the overlay_physical is a valid physical address, or NULL - * If it isn't then we have a v1.1 client. Fix up params. - * If it is, then we have a 1.2 client... get the rest of the data. - */ -static int i810_dma_init_compat(drm_i810_init_t * init, unsigned long arg) +static int i810_dma_init(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - - /* Get v1.1 init data */ - if (copy_from_user(init, (drm_i810_pre12_init_t __user *) arg, - sizeof(drm_i810_pre12_init_t))) { - return -EFAULT; - } - - if ((!init->overlay_physical) || (init->overlay_physical > 4096)) { - - /* This is a v1.2 client, just get the v1.2 init data */ - DRM_INFO("Using POST v1.2 init.\n"); - if (copy_from_user(init, (drm_i810_init_t __user *) arg, - sizeof(drm_i810_init_t))) { - return -EFAULT; - } - } else { - - /* This is a v1.1 client, fix the params */ - DRM_INFO("Using PRE v1.2 init.\n"); - init->pitch_bits = init->h; - init->pitch = init->w; - init->h = init->overlay_physical; - init->w = init->overlay_offset; - init->overlay_physical = 0; - init->overlay_offset = 0; - } - - return 0; -} - -static int i810_dma_init(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; drm_i810_private_t *dev_priv; - drm_i810_init_t init; + drm_i810_init_t *init = data; int retcode = 0; - /* Get only the init func */ - if (copy_from_user - (&init, (void __user *)arg, sizeof(drm_i810_init_func_t))) - return -EFAULT; - - switch (init.func) { - case I810_INIT_DMA: - /* This case is for backward compatibility. It - * handles XFree 4.1.0 and 4.2.0, and has to - * do some parameter checking as described below. - * It will someday go away. - */ - retcode = i810_dma_init_compat(&init, arg); - if (retcode) - return retcode; - - dev_priv = drm_alloc(sizeof(drm_i810_private_t), - DRM_MEM_DRIVER); - if (dev_priv == NULL) - return -ENOMEM; - retcode = i810_dma_initialize(dev, dev_priv, &init); - break; - - default: + switch (init->func) { case I810_INIT_DMA_1_4: DRM_INFO("Using v1.4 init.\n"); - if (copy_from_user(&init, (drm_i810_init_t __user *) arg, - sizeof(drm_i810_init_t))) { - return -EFAULT; - } dev_priv = drm_alloc(sizeof(drm_i810_private_t), DRM_MEM_DRIVER); if (dev_priv == NULL) return -ENOMEM; - retcode = i810_dma_initialize(dev, dev_priv, &init); + retcode = i810_dma_initialize(dev, dev_priv, init); break; case I810_CLEANUP_DMA: DRM_INFO("DMA Cleanup\n"); retcode = i810_dma_cleanup(dev); break; + default: + return -EINVAL; } return retcode; @@ -968,7 +897,8 @@ static int i810_flush_queue(struct drm_device * dev) } /* Must be called with the lock held */ -static void i810_reclaim_buffers(struct drm_device * dev, struct file *filp) +static void i810_reclaim_buffers(struct drm_device * dev, + struct drm_file *file_priv) { struct drm_device_dma *dma = dev->dma; int i; @@ -986,7 +916,7 @@ static void i810_reclaim_buffers(struct drm_device * dev, struct file *filp) struct drm_buf *buf = dma->buflist[i]; drm_i810_buf_priv_t *buf_priv = buf->dev_private; - if (buf->filp == filp && buf_priv) { + if (buf->file_priv == file_priv && buf_priv) { int used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, I810_BUF_FREE); @@ -998,47 +928,38 @@ static void i810_reclaim_buffers(struct drm_device * dev, struct file *filp) } } -static int i810_flush_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +static int i810_flush_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); i810_flush_queue(dev); return 0; } -static int i810_dma_vertex(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +static int i810_dma_vertex(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; struct drm_device_dma *dma = dev->dma; drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private; u32 *hw_status = dev_priv->hw_status_page; drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) dev_priv->sarea_priv; - drm_i810_vertex_t vertex; - - if (copy_from_user - (&vertex, (drm_i810_vertex_t __user *) arg, sizeof(vertex))) - return -EFAULT; + drm_i810_vertex_t *vertex = data; - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); DRM_DEBUG("i810 dma vertex, idx %d used %d discard %d\n", - vertex.idx, vertex.used, vertex.discard); + vertex->idx, vertex->used, vertex->discard); - if (vertex.idx < 0 || vertex.idx > dma->buf_count) + if (vertex->idx < 0 || vertex->idx > dma->buf_count) return -EINVAL; i810_dma_dispatch_vertex(dev, - dma->buflist[vertex.idx], - vertex.discard, vertex.used); + dma->buflist[vertex->idx], + vertex->discard, vertex->used); - atomic_add(vertex.used, &dev->counts[_DRM_STAT_SECONDARY]); + atomic_add(vertex->used, &dev->counts[_DRM_STAT_SECONDARY]); atomic_inc(&dev->counts[_DRM_STAT_DMA]); sarea_priv->last_enqueue = dev_priv->counter - 1; sarea_priv->last_dispatch = (int)hw_status[5]; @@ -1046,48 +967,37 @@ static int i810_dma_vertex(struct inode *inode, struct file *filp, return 0; } -static int i810_clear_bufs(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +static int i810_clear_bufs(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - drm_i810_clear_t clear; + drm_i810_clear_t *clear = data; - if (copy_from_user - (&clear, (drm_i810_clear_t __user *) arg, sizeof(clear))) - return -EFAULT; - - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); /* GH: Someone's doing nasty things... */ if (!dev->dev_private) { return -EINVAL; } - i810_dma_dispatch_clear(dev, clear.flags, - clear.clear_color, clear.clear_depth); + i810_dma_dispatch_clear(dev, clear->flags, + clear->clear_color, clear->clear_depth); return 0; } -static int i810_swap_bufs(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +static int i810_swap_bufs(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - DRM_DEBUG("i810_swap_bufs\n"); - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); i810_dma_dispatch_swap(dev); return 0; } -static int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) +static int i810_getage(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private; u32 *hw_status = dev_priv->hw_status_page; drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) @@ -1097,46 +1007,39 @@ static int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd, return 0; } -static int i810_getbuf(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) +static int i810_getbuf(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; int retcode = 0; - drm_i810_dma_t d; + drm_i810_dma_t *d = data; drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private; u32 *hw_status = dev_priv->hw_status_page; drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) dev_priv->sarea_priv; - if (copy_from_user(&d, (drm_i810_dma_t __user *) arg, sizeof(d))) - return -EFAULT; - - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); - d.granted = 0; + d->granted = 0; - retcode = i810_dma_get_buffer(dev, &d, filp); + retcode = i810_dma_get_buffer(dev, d, file_priv); DRM_DEBUG("i810_dma: %d returning %d, granted = %d\n", - current->pid, retcode, d.granted); + current->pid, retcode, d->granted); - if (copy_to_user((void __user *) arg, &d, sizeof(d))) - return -EFAULT; sarea_priv->last_dispatch = (int)hw_status[5]; return retcode; } -static int i810_copybuf(struct inode *inode, - struct file *filp, unsigned int cmd, unsigned long arg) +static int i810_copybuf(struct drm_device *dev, void *data, + struct drm_file *file_priv) { /* Never copy - 2.4.x doesn't need it */ return 0; } -static int i810_docopy(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) +static int i810_docopy(struct drm_device *dev, void *data, + struct drm_file *file_priv) { /* Never copy - 2.4.x doesn't need it */ return 0; @@ -1202,30 +1105,25 @@ static void i810_dma_dispatch_mc(struct drm_device * dev, struct drm_buf * buf, ADVANCE_LP_RING(); } -static int i810_dma_mc(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +static int i810_dma_mc(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; struct drm_device_dma *dma = dev->dma; drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private; u32 *hw_status = dev_priv->hw_status_page; drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) dev_priv->sarea_priv; - drm_i810_mc_t mc; - - if (copy_from_user(&mc, (drm_i810_mc_t __user *) arg, sizeof(mc))) - return -EFAULT; + drm_i810_mc_t *mc = data; - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); - if (mc.idx >= dma->buf_count || mc.idx < 0) + if (mc->idx >= dma->buf_count || mc->idx < 0) return -EINVAL; - i810_dma_dispatch_mc(dev, dma->buflist[mc.idx], mc.used, - mc.last_render); + i810_dma_dispatch_mc(dev, dma->buflist[mc->idx], mc->used, + mc->last_render); - atomic_add(mc.used, &dev->counts[_DRM_STAT_SECONDARY]); + atomic_add(mc->used, &dev->counts[_DRM_STAT_SECONDARY]); atomic_inc(&dev->counts[_DRM_STAT_DMA]); sarea_priv->last_enqueue = dev_priv->counter - 1; sarea_priv->last_dispatch = (int)hw_status[5]; @@ -1233,52 +1131,41 @@ static int i810_dma_mc(struct inode *inode, struct file *filp, return 0; } -static int i810_rstatus(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +static int i810_rstatus(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private; return (int)(((u32 *) (dev_priv->hw_status_page))[4]); } -static int i810_ov0_info(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +static int i810_ov0_info(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private; - drm_i810_overlay_t data; + drm_i810_overlay_t *ov = data; + + ov->offset = dev_priv->overlay_offset; + ov->physical = dev_priv->overlay_physical; - data.offset = dev_priv->overlay_offset; - data.physical = dev_priv->overlay_physical; - if (copy_to_user - ((drm_i810_overlay_t __user *) arg, &data, sizeof(data))) - return -EFAULT; return 0; } -static int i810_fstatus(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +static int i810_fstatus(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private; - LOCK_TEST_WITH_RETURN(dev, filp); - + LOCK_TEST_WITH_RETURN(dev, file_priv); return I810_READ(0x30008); } -static int i810_ov0_flip(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +static int i810_ov0_flip(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private; - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); //Tell the overlay to update I810_WRITE(0x30000, dev_priv->overlay_physical | 0x80000000); @@ -1310,16 +1197,14 @@ static int i810_do_cleanup_pageflip(struct drm_device * dev) return 0; } -static int i810_flip_bufs(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +static int i810_flip_bufs(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; drm_i810_private_t *dev_priv = dev->dev_private; DRM_DEBUG("%s\n", __FUNCTION__); - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); if (!dev_priv->page_flipping) i810_do_init_pageflip(dev); @@ -1345,7 +1230,7 @@ void i810_driver_lastclose(struct drm_device * dev) i810_dma_cleanup(dev); } -void i810_driver_preclose(struct drm_device * dev, DRMFILE filp) +void i810_driver_preclose(struct drm_device * dev, struct drm_file *file_priv) { if (dev->dev_private) { drm_i810_private_t *dev_priv = dev->dev_private; @@ -1355,9 +1240,10 @@ void i810_driver_preclose(struct drm_device * dev, DRMFILE filp) } } -void i810_driver_reclaim_buffers_locked(struct drm_device * dev, struct file *filp) +void i810_driver_reclaim_buffers_locked(struct drm_device * dev, + struct drm_file *file_priv) { - i810_reclaim_buffers(dev, filp); + i810_reclaim_buffers(dev, file_priv); } int i810_driver_dma_quiescent(struct drm_device * dev) @@ -1366,22 +1252,22 @@ int i810_driver_dma_quiescent(struct drm_device * dev) return 0; } -drm_ioctl_desc_t i810_ioctls[] = { - [DRM_IOCTL_NR(DRM_I810_INIT)] = {i810_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_I810_VERTEX)] = {i810_dma_vertex, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I810_CLEAR)] = {i810_clear_bufs, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I810_FLUSH)] = {i810_flush_ioctl, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I810_GETAGE)] = {i810_getage, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I810_GETBUF)] = {i810_getbuf, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I810_SWAP)] = {i810_swap_bufs, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I810_COPY)] = {i810_copybuf, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I810_DOCOPY)] = {i810_docopy, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I810_OV0INFO)] = {i810_ov0_info, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I810_FSTATUS)] = {i810_fstatus, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I810_OV0FLIP)] = {i810_ov0_flip, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I810_MC)] = {i810_dma_mc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_I810_RSTATUS)] = {i810_rstatus, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I810_FLIP)] = {i810_flip_bufs, DRM_AUTH} +struct drm_ioctl_desc i810_ioctls[] = { + DRM_IOCTL_DEF(DRM_I810_INIT, i810_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_I810_VERTEX, i810_dma_vertex, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I810_CLEAR, i810_clear_bufs, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I810_FLUSH, i810_flush_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I810_GETAGE, i810_getage, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I810_GETBUF, i810_getbuf, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I810_SWAP, i810_swap_bufs, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I810_COPY, i810_copybuf, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I810_DOCOPY, i810_docopy, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I810_OV0INFO, i810_ov0_info, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I810_FSTATUS, i810_fstatus, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I810_OV0FLIP, i810_ov0_flip, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I810_MC, i810_dma_mc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_I810_RSTATUS, i810_rstatus, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I810_FLIP, i810_flip_bufs, DRM_AUTH) }; int i810_max_ioctl = DRM_ARRAY_SIZE(i810_ioctls); diff --git a/drivers/char/drm/i810_drm.h b/drivers/char/drm/i810_drm.h index 614977dbce45..7a10bb6f2c0f 100644 --- a/drivers/char/drm/i810_drm.h +++ b/drivers/char/drm/i810_drm.h @@ -102,13 +102,8 @@ typedef enum _drm_i810_init_func { /* This is the init structure after v1.2 */ typedef struct _drm_i810_init { drm_i810_init_func_t func; -#if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0) - int ring_map_idx; - int buffer_map_idx; -#else unsigned int mmio_offset; unsigned int buffers_offset; -#endif int sarea_priv_offset; unsigned int ring_start; unsigned int ring_end; diff --git a/drivers/char/drm/i810_drv.h b/drivers/char/drm/i810_drv.h index 648833844c7f..0af45872f67e 100644 --- a/drivers/char/drm/i810_drv.h +++ b/drivers/char/drm/i810_drv.h @@ -117,15 +117,16 @@ typedef struct drm_i810_private { /* i810_dma.c */ extern int i810_driver_dma_quiescent(struct drm_device * dev); extern void i810_driver_reclaim_buffers_locked(struct drm_device * dev, - struct file *filp); + struct drm_file *file_priv); extern int i810_driver_load(struct drm_device *, unsigned long flags); extern void i810_driver_lastclose(struct drm_device * dev); -extern void i810_driver_preclose(struct drm_device * dev, DRMFILE filp); +extern void i810_driver_preclose(struct drm_device * dev, + struct drm_file *file_priv); extern void i810_driver_reclaim_buffers_locked(struct drm_device * dev, - struct file *filp); + struct drm_file *file_priv); extern int i810_driver_device_is_agp(struct drm_device * dev); -extern drm_ioctl_desc_t i810_ioctls[]; +extern struct drm_ioctl_desc i810_ioctls[]; extern int i810_max_ioctl; #define I810_BASE(reg) ((unsigned long) \ diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c index dc20c1a7834e..43a1f78712d6 100644 --- a/drivers/char/drm/i830_dma.c +++ b/drivers/char/drm/i830_dma.c @@ -122,10 +122,9 @@ static const struct file_operations i830_buffer_fops = { .fasync = drm_fasync, }; -static int i830_map_buffer(struct drm_buf * buf, struct file *filp) +static int i830_map_buffer(struct drm_buf * buf, struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = file_priv->head->dev; drm_i830_buf_priv_t *buf_priv = buf->dev_private; drm_i830_private_t *dev_priv = dev->dev_private; const struct file_operations *old_fops; @@ -136,13 +135,13 @@ static int i830_map_buffer(struct drm_buf * buf, struct file *filp) return -EINVAL; down_write(¤t->mm->mmap_sem); - old_fops = filp->f_op; - filp->f_op = &i830_buffer_fops; + old_fops = file_priv->filp->f_op; + file_priv->filp->f_op = &i830_buffer_fops; dev_priv->mmap_buffer = buf; - virtual = do_mmap(filp, 0, buf->total, PROT_READ | PROT_WRITE, + virtual = do_mmap(file_priv->filp, 0, buf->total, PROT_READ | PROT_WRITE, MAP_SHARED, buf->bus_address); dev_priv->mmap_buffer = NULL; - filp->f_op = old_fops; + file_priv->filp->f_op = old_fops; if (IS_ERR((void *)virtual)) { /* ugh */ /* Real error */ DRM_ERROR("mmap error\n"); @@ -177,7 +176,7 @@ static int i830_unmap_buffer(struct drm_buf * buf) } static int i830_dma_get_buffer(struct drm_device * dev, drm_i830_dma_t * d, - struct file *filp) + struct drm_file *file_priv) { struct drm_buf *buf; drm_i830_buf_priv_t *buf_priv; @@ -190,13 +189,13 @@ static int i830_dma_get_buffer(struct drm_device * dev, drm_i830_dma_t * d, return retcode; } - retcode = i830_map_buffer(buf, filp); + retcode = i830_map_buffer(buf, file_priv); if (retcode) { i830_freelist_put(dev, buf); DRM_ERROR("mapbuf failed, retcode %d\n", retcode); return retcode; } - buf->filp = filp; + buf->file_priv = file_priv; buf_priv = buf->dev_private; d->granted = 1; d->request_idx = buf->idx; @@ -389,7 +388,7 @@ static int i830_dma_initialize(struct drm_device * dev, i830_dma_cleanup(dev); DRM_ERROR("can not ioremap virtual address for" " ring buffer\n"); - return DRM_ERR(ENOMEM); + return -ENOMEM; } dev_priv->ring.virtual_start = dev_priv->ring.map.handle; @@ -451,25 +450,20 @@ static int i830_dma_initialize(struct drm_device * dev, return 0; } -static int i830_dma_init(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +static int i830_dma_init(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; drm_i830_private_t *dev_priv; - drm_i830_init_t init; + drm_i830_init_t *init = data; int retcode = 0; - if (copy_from_user(&init, (void *__user)arg, sizeof(init))) - return -EFAULT; - - switch (init.func) { + switch (init->func) { case I830_INIT_DMA: dev_priv = drm_alloc(sizeof(drm_i830_private_t), DRM_MEM_DRIVER); if (dev_priv == NULL) return -ENOMEM; - retcode = i830_dma_initialize(dev, dev_priv, &init); + retcode = i830_dma_initialize(dev, dev_priv, init); break; case I830_CLEANUP_DMA: retcode = i830_dma_cleanup(dev); @@ -1248,7 +1242,7 @@ static int i830_flush_queue(struct drm_device * dev) } /* Must be called with the lock held */ -static void i830_reclaim_buffers(struct drm_device * dev, struct file *filp) +static void i830_reclaim_buffers(struct drm_device * dev, struct drm_file *file_priv) { struct drm_device_dma *dma = dev->dma; int i; @@ -1266,7 +1260,7 @@ static void i830_reclaim_buffers(struct drm_device * dev, struct file *filp) struct drm_buf *buf = dma->buflist[i]; drm_i830_buf_priv_t *buf_priv = buf->dev_private; - if (buf->filp == filp && buf_priv) { + if (buf->file_priv == file_priv && buf_priv) { int used = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT, I830_BUF_FREE); @@ -1278,45 +1272,36 @@ static void i830_reclaim_buffers(struct drm_device * dev, struct file *filp) } } -static int i830_flush_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +static int i830_flush_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); i830_flush_queue(dev); return 0; } -static int i830_dma_vertex(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +static int i830_dma_vertex(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; struct drm_device_dma *dma = dev->dma; drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private; u32 *hw_status = dev_priv->hw_status_page; drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *) dev_priv->sarea_priv; - drm_i830_vertex_t vertex; - - if (copy_from_user - (&vertex, (drm_i830_vertex_t __user *) arg, sizeof(vertex))) - return -EFAULT; + drm_i830_vertex_t *vertex = data; - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); DRM_DEBUG("i830 dma vertex, idx %d used %d discard %d\n", - vertex.idx, vertex.used, vertex.discard); + vertex->idx, vertex->used, vertex->discard); - if (vertex.idx < 0 || vertex.idx > dma->buf_count) + if (vertex->idx < 0 || vertex->idx > dma->buf_count) return -EINVAL; i830_dma_dispatch_vertex(dev, - dma->buflist[vertex.idx], - vertex.discard, vertex.used); + dma->buflist[vertex->idx], + vertex->discard, vertex->used); sarea_priv->last_enqueue = dev_priv->counter - 1; sarea_priv->last_dispatch = (int)hw_status[5]; @@ -1324,39 +1309,30 @@ static int i830_dma_vertex(struct inode *inode, struct file *filp, return 0; } -static int i830_clear_bufs(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +static int i830_clear_bufs(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - drm_i830_clear_t clear; - - if (copy_from_user - (&clear, (drm_i830_clear_t __user *) arg, sizeof(clear))) - return -EFAULT; + drm_i830_clear_t *clear = data; - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); /* GH: Someone's doing nasty things... */ if (!dev->dev_private) { return -EINVAL; } - i830_dma_dispatch_clear(dev, clear.flags, - clear.clear_color, - clear.clear_depth, clear.clear_depthmask); + i830_dma_dispatch_clear(dev, clear->flags, + clear->clear_color, + clear->clear_depth, clear->clear_depthmask); return 0; } -static int i830_swap_bufs(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +static int i830_swap_bufs(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; - DRM_DEBUG("i830_swap_bufs\n"); - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); i830_dma_dispatch_swap(dev); return 0; @@ -1386,16 +1362,14 @@ static int i830_do_cleanup_pageflip(struct drm_device * dev) return 0; } -static int i830_flip_bufs(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +static int i830_flip_bufs(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; drm_i830_private_t *dev_priv = dev->dev_private; DRM_DEBUG("%s\n", __FUNCTION__); - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); if (!dev_priv->page_flipping) i830_do_init_pageflip(dev); @@ -1404,11 +1378,9 @@ static int i830_flip_bufs(struct inode *inode, struct file *filp, return 0; } -static int i830_getage(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) +static int i830_getage(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private; u32 *hw_status = dev_priv->hw_status_page; drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *) @@ -1418,58 +1390,50 @@ static int i830_getage(struct inode *inode, struct file *filp, unsigned int cmd, return 0; } -static int i830_getbuf(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) +static int i830_getbuf(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; int retcode = 0; - drm_i830_dma_t d; + drm_i830_dma_t *d = data; drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private; u32 *hw_status = dev_priv->hw_status_page; drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *) dev_priv->sarea_priv; DRM_DEBUG("getbuf\n"); - if (copy_from_user(&d, (drm_i830_dma_t __user *) arg, sizeof(d))) - return -EFAULT; - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); - d.granted = 0; + d->granted = 0; - retcode = i830_dma_get_buffer(dev, &d, filp); + retcode = i830_dma_get_buffer(dev, d, file_priv); DRM_DEBUG("i830_dma: %d returning %d, granted = %d\n", - current->pid, retcode, d.granted); + current->pid, retcode, d->granted); - if (copy_to_user((void __user *) arg, &d, sizeof(d))) - return -EFAULT; sarea_priv->last_dispatch = (int)hw_status[5]; return retcode; } -static int i830_copybuf(struct inode *inode, - struct file *filp, unsigned int cmd, unsigned long arg) +static int i830_copybuf(struct drm_device *dev, void *data, + struct drm_file *file_priv) { /* Never copy - 2.4.x doesn't need it */ return 0; } -static int i830_docopy(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) +static int i830_docopy(struct drm_device *dev, void *data, + struct drm_file *file_priv) { return 0; } -static int i830_getparam(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +static int i830_getparam(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; drm_i830_private_t *dev_priv = dev->dev_private; - drm_i830_getparam_t param; + drm_i830_getparam_t *param = data; int value; if (!dev_priv) { @@ -1477,11 +1441,7 @@ static int i830_getparam(struct inode *inode, struct file *filp, return -EINVAL; } - if (copy_from_user - (¶m, (drm_i830_getparam_t __user *) arg, sizeof(param))) - return -EFAULT; - - switch (param.param) { + switch (param->param) { case I830_PARAM_IRQ_ACTIVE: value = dev->irq_enabled; break; @@ -1489,7 +1449,7 @@ static int i830_getparam(struct inode *inode, struct file *filp, return -EINVAL; } - if (copy_to_user(param.value, &value, sizeof(int))) { + if (copy_to_user(param->value, &value, sizeof(int))) { DRM_ERROR("copy_to_user\n"); return -EFAULT; } @@ -1497,26 +1457,20 @@ static int i830_getparam(struct inode *inode, struct file *filp, return 0; } -static int i830_setparam(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +static int i830_setparam(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; drm_i830_private_t *dev_priv = dev->dev_private; - drm_i830_setparam_t param; + drm_i830_setparam_t *param = data; if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __FUNCTION__); return -EINVAL; } - if (copy_from_user - (¶m, (drm_i830_setparam_t __user *) arg, sizeof(param))) - return -EFAULT; - - switch (param.param) { + switch (param->param) { case I830_SETPARAM_USE_MI_BATCHBUFFER_START: - dev_priv->use_mi_batchbuffer_start = param.value; + dev_priv->use_mi_batchbuffer_start = param->value; break; default: return -EINVAL; @@ -1542,7 +1496,7 @@ void i830_driver_lastclose(struct drm_device * dev) i830_dma_cleanup(dev); } -void i830_driver_preclose(struct drm_device * dev, DRMFILE filp) +void i830_driver_preclose(struct drm_device * dev, struct drm_file *file_priv) { if (dev->dev_private) { drm_i830_private_t *dev_priv = dev->dev_private; @@ -1552,9 +1506,9 @@ void i830_driver_preclose(struct drm_device * dev, DRMFILE filp) } } -void i830_driver_reclaim_buffers_locked(struct drm_device * dev, struct file *filp) +void i830_driver_reclaim_buffers_locked(struct drm_device * dev, struct drm_file *file_priv) { - i830_reclaim_buffers(dev, filp); + i830_reclaim_buffers(dev, file_priv); } int i830_driver_dma_quiescent(struct drm_device * dev) @@ -1563,21 +1517,21 @@ int i830_driver_dma_quiescent(struct drm_device * dev) return 0; } -drm_ioctl_desc_t i830_ioctls[] = { - [DRM_IOCTL_NR(DRM_I830_INIT)] = {i830_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_I830_VERTEX)] = {i830_dma_vertex, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I830_CLEAR)] = {i830_clear_bufs, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I830_FLUSH)] = {i830_flush_ioctl, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I830_GETAGE)] = {i830_getage, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I830_GETBUF)] = {i830_getbuf, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I830_SWAP)] = {i830_swap_bufs, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I830_COPY)] = {i830_copybuf, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I830_DOCOPY)] = {i830_docopy, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I830_FLIP)] = {i830_flip_bufs, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I830_IRQ_EMIT)] = {i830_irq_emit, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I830_IRQ_WAIT)] = {i830_irq_wait, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I830_GETPARAM)] = {i830_getparam, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I830_SETPARAM)] = {i830_setparam, DRM_AUTH} +struct drm_ioctl_desc i830_ioctls[] = { + DRM_IOCTL_DEF(DRM_I830_INIT, i830_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_I830_VERTEX, i830_dma_vertex, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I830_CLEAR, i830_clear_bufs, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I830_FLUSH, i830_flush_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I830_GETAGE, i830_getage, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I830_GETBUF, i830_getbuf, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I830_SWAP, i830_swap_bufs, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I830_COPY, i830_copybuf, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I830_DOCOPY, i830_docopy, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I830_FLIP, i830_flip_bufs, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I830_IRQ_EMIT, i830_irq_emit, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I830_IRQ_WAIT, i830_irq_wait, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I830_GETPARAM, i830_getparam, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I830_SETPARAM, i830_setparam, DRM_AUTH) }; int i830_max_ioctl = DRM_ARRAY_SIZE(i830_ioctls); diff --git a/drivers/char/drm/i830_drv.h b/drivers/char/drm/i830_drv.h index ddda67956dea..db3a9fa83960 100644 --- a/drivers/char/drm/i830_drv.h +++ b/drivers/char/drm/i830_drv.h @@ -122,24 +122,25 @@ typedef struct drm_i830_private { } drm_i830_private_t; -extern drm_ioctl_desc_t i830_ioctls[]; +extern struct drm_ioctl_desc i830_ioctls[]; extern int i830_max_ioctl; /* i830_irq.c */ -extern int i830_irq_emit(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int i830_irq_wait(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); +extern int i830_irq_emit(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int i830_irq_wait(struct drm_device *dev, void *data, + struct drm_file *file_priv); extern irqreturn_t i830_driver_irq_handler(DRM_IRQ_ARGS); extern void i830_driver_irq_preinstall(struct drm_device * dev); extern void i830_driver_irq_postinstall(struct drm_device * dev); extern void i830_driver_irq_uninstall(struct drm_device * dev); extern int i830_driver_load(struct drm_device *, unsigned long flags); -extern void i830_driver_preclose(struct drm_device * dev, DRMFILE filp); +extern void i830_driver_preclose(struct drm_device * dev, + struct drm_file *file_priv); extern void i830_driver_lastclose(struct drm_device * dev); extern void i830_driver_reclaim_buffers_locked(struct drm_device * dev, - struct file *filp); + struct drm_file *file_priv); extern int i830_driver_dma_quiescent(struct drm_device * dev); extern int i830_driver_device_is_agp(struct drm_device * dev); diff --git a/drivers/char/drm/i830_irq.c b/drivers/char/drm/i830_irq.c index a1b5c63c3c3e..76403f4b6200 100644 --- a/drivers/char/drm/i830_irq.c +++ b/drivers/char/drm/i830_irq.c @@ -114,29 +114,23 @@ static int i830_wait_irq(struct drm_device * dev, int irq_nr) /* Needs the lock as it touches the ring. */ -int i830_irq_emit(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) +int i830_irq_emit(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; drm_i830_private_t *dev_priv = dev->dev_private; - drm_i830_irq_emit_t emit; + drm_i830_irq_emit_t *emit = data; int result; - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __FUNCTION__); return -EINVAL; } - if (copy_from_user - (&emit, (drm_i830_irq_emit_t __user *) arg, sizeof(emit))) - return -EFAULT; - result = i830_emit_irq(dev); - if (copy_to_user(emit.irq_seq, &result, sizeof(int))) { + if (copy_to_user(emit->irq_seq, &result, sizeof(int))) { DRM_ERROR("copy_to_user\n"); return -EFAULT; } @@ -146,24 +140,18 @@ int i830_irq_emit(struct inode *inode, struct file *filp, unsigned int cmd, /* Doesn't need the hardware lock. */ -int i830_irq_wait(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) +int i830_irq_wait(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; drm_i830_private_t *dev_priv = dev->dev_private; - drm_i830_irq_wait_t irqwait; + drm_i830_irq_wait_t *irqwait = data; if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __FUNCTION__); return -EINVAL; } - if (copy_from_user(&irqwait, (drm_i830_irq_wait_t __user *) arg, - sizeof(irqwait))) - return -EFAULT; - - return i830_wait_irq(dev, irqwait.irq_seq); + return i830_wait_irq(dev, irqwait->irq_seq); } /* drm_dma.h hooks diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c index 8e7d713a5a15..e61a43e5b3ac 100644 --- a/drivers/char/drm/i915_dma.c +++ b/drivers/char/drm/i915_dma.c @@ -70,7 +70,7 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller) last_head = ring->head; } - return DRM_ERR(EBUSY); + return -EBUSY; } void i915_kernel_lost_context(struct drm_device * dev) @@ -137,7 +137,7 @@ static int i915_initialize(struct drm_device * dev, DRM_ERROR("can not find sarea!\n"); dev->dev_private = (void *)dev_priv; i915_dma_cleanup(dev); - return DRM_ERR(EINVAL); + return -EINVAL; } dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset); @@ -145,7 +145,7 @@ static int i915_initialize(struct drm_device * dev, dev->dev_private = (void *)dev_priv; i915_dma_cleanup(dev); DRM_ERROR("can not find mmio map!\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } dev_priv->sarea_priv = (drm_i915_sarea_t *) @@ -169,7 +169,7 @@ static int i915_initialize(struct drm_device * dev, i915_dma_cleanup(dev); DRM_ERROR("can not ioremap virtual address for" " ring buffer\n"); - return DRM_ERR(ENOMEM); + return -ENOMEM; } dev_priv->ring.virtual_start = dev_priv->ring.map.handle; @@ -200,7 +200,7 @@ static int i915_initialize(struct drm_device * dev, dev->dev_private = (void *)dev_priv; i915_dma_cleanup(dev); DRM_ERROR("Can not allocate hardware status page\n"); - return DRM_ERR(ENOMEM); + return -ENOMEM; } dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr; dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr; @@ -221,24 +221,24 @@ static int i915_dma_resume(struct drm_device * dev) if (!dev_priv->sarea) { DRM_ERROR("can not find sarea!\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } if (!dev_priv->mmio_map) { DRM_ERROR("can not find mmio map!\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } if (dev_priv->ring.map.handle == NULL) { DRM_ERROR("can not ioremap virtual address for" " ring buffer\n"); - return DRM_ERR(ENOMEM); + return -ENOMEM; } /* Program Hardware Status Page */ if (!dev_priv->hw_status_page) { DRM_ERROR("Can not find hardware status page\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page); @@ -251,23 +251,20 @@ static int i915_dma_resume(struct drm_device * dev) return 0; } -static int i915_dma_init(DRM_IOCTL_ARGS) +static int i915_dma_init(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - DRM_DEVICE; drm_i915_private_t *dev_priv; - drm_i915_init_t init; + drm_i915_init_t *init = data; int retcode = 0; - DRM_COPY_FROM_USER_IOCTL(init, (drm_i915_init_t __user *) data, - sizeof(init)); - - switch (init.func) { + switch (init->func) { case I915_INIT_DMA: dev_priv = drm_alloc(sizeof(drm_i915_private_t), DRM_MEM_DRIVER); if (dev_priv == NULL) - return DRM_ERR(ENOMEM); - retcode = i915_initialize(dev, dev_priv, &init); + return -ENOMEM; + retcode = i915_initialize(dev, dev_priv, init); break; case I915_CLEANUP_DMA: retcode = i915_dma_cleanup(dev); @@ -276,7 +273,7 @@ static int i915_dma_init(DRM_IOCTL_ARGS) retcode = i915_dma_resume(dev); break; default: - retcode = DRM_ERR(EINVAL); + retcode = -EINVAL; break; } @@ -366,7 +363,7 @@ static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwor RING_LOCALS; if ((dwords+1) * sizeof(int) >= dev_priv->ring.Size - 8) - return DRM_ERR(EINVAL); + return -EINVAL; BEGIN_LP_RING((dwords+1)&~1); @@ -374,17 +371,17 @@ static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwor int cmd, sz; if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i], sizeof(cmd))) - return DRM_ERR(EINVAL); + return -EINVAL; if ((sz = validate_cmd(cmd)) == 0 || i + sz > dwords) - return DRM_ERR(EINVAL); + return -EINVAL; OUT_RING(cmd); while (++i, --sz) { if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i], sizeof(cmd))) { - return DRM_ERR(EINVAL); + return -EINVAL; } OUT_RING(cmd); } @@ -407,13 +404,13 @@ static int i915_emit_box(struct drm_device * dev, RING_LOCALS; if (DRM_COPY_FROM_USER_UNCHECKED(&box, &boxes[i], sizeof(box))) { - return DRM_ERR(EFAULT); + return -EFAULT; } if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) { DRM_ERROR("Bad box %d,%d..%d,%d\n", box.x1, box.y1, box.x2, box.y2); - return DRM_ERR(EINVAL); + return -EINVAL; } if (IS_I965G(dev)) { @@ -467,7 +464,7 @@ static int i915_dispatch_cmdbuffer(struct drm_device * dev, if (cmd->sz & 0x3) { DRM_ERROR("alignment"); - return DRM_ERR(EINVAL); + return -EINVAL; } i915_kernel_lost_context(dev); @@ -502,7 +499,7 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev, if ((batch->start | batch->used) & 0x7) { DRM_ERROR("alignment"); - return DRM_ERR(EINVAL); + return -EINVAL; } i915_kernel_lost_context(dev); @@ -598,76 +595,69 @@ static int i915_quiescent(struct drm_device * dev) return i915_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__); } -static int i915_flush_ioctl(DRM_IOCTL_ARGS) +static int i915_flush_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - DRM_DEVICE; - - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); return i915_quiescent(dev); } -static int i915_batchbuffer(DRM_IOCTL_ARGS) +static int i915_batchbuffer(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - DRM_DEVICE; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; u32 *hw_status = dev_priv->hw_status_page; drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) dev_priv->sarea_priv; - drm_i915_batchbuffer_t batch; + drm_i915_batchbuffer_t *batch = data; int ret; if (!dev_priv->allow_batchbuffer) { DRM_ERROR("Batchbuffer ioctl disabled\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } - DRM_COPY_FROM_USER_IOCTL(batch, (drm_i915_batchbuffer_t __user *) data, - sizeof(batch)); - DRM_DEBUG("i915 batchbuffer, start %x used %d cliprects %d\n", - batch.start, batch.used, batch.num_cliprects); + batch->start, batch->used, batch->num_cliprects); - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); - if (batch.num_cliprects && DRM_VERIFYAREA_READ(batch.cliprects, - batch.num_cliprects * + if (batch->num_cliprects && DRM_VERIFYAREA_READ(batch->cliprects, + batch->num_cliprects * sizeof(struct drm_clip_rect))) - return DRM_ERR(EFAULT); + return -EFAULT; - ret = i915_dispatch_batchbuffer(dev, &batch); + ret = i915_dispatch_batchbuffer(dev, batch); sarea_priv->last_dispatch = (int)hw_status[5]; return ret; } -static int i915_cmdbuffer(DRM_IOCTL_ARGS) +static int i915_cmdbuffer(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - DRM_DEVICE; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; u32 *hw_status = dev_priv->hw_status_page; drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) dev_priv->sarea_priv; - drm_i915_cmdbuffer_t cmdbuf; + drm_i915_cmdbuffer_t *cmdbuf = data; int ret; - DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_i915_cmdbuffer_t __user *) data, - sizeof(cmdbuf)); - DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n", - cmdbuf.buf, cmdbuf.sz, cmdbuf.num_cliprects); + cmdbuf->buf, cmdbuf->sz, cmdbuf->num_cliprects); - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); - if (cmdbuf.num_cliprects && - DRM_VERIFYAREA_READ(cmdbuf.cliprects, - cmdbuf.num_cliprects * + if (cmdbuf->num_cliprects && + DRM_VERIFYAREA_READ(cmdbuf->cliprects, + cmdbuf->num_cliprects * sizeof(struct drm_clip_rect))) { DRM_ERROR("Fault accessing cliprects\n"); - return DRM_ERR(EFAULT); + return -EFAULT; } - ret = i915_dispatch_cmdbuffer(dev, &cmdbuf); + ret = i915_dispatch_cmdbuffer(dev, cmdbuf); if (ret) { DRM_ERROR("i915_dispatch_cmdbuffer failed\n"); return ret; @@ -677,33 +667,29 @@ static int i915_cmdbuffer(DRM_IOCTL_ARGS) return 0; } -static int i915_flip_bufs(DRM_IOCTL_ARGS) +static int i915_flip_bufs(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - DRM_DEVICE; - DRM_DEBUG("%s\n", __FUNCTION__); - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); return i915_dispatch_flip(dev); } -static int i915_getparam(DRM_IOCTL_ARGS) +static int i915_getparam(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - DRM_DEVICE; drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_getparam_t param; + drm_i915_getparam_t *param = data; int value; if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); + return -EINVAL; } - DRM_COPY_FROM_USER_IOCTL(param, (drm_i915_getparam_t __user *) data, - sizeof(param)); - - switch (param.param) { + switch (param->param) { case I915_PARAM_IRQ_ACTIVE: value = dev->irq ? 1 : 0; break; @@ -714,68 +700,64 @@ static int i915_getparam(DRM_IOCTL_ARGS) value = READ_BREADCRUMB(dev_priv); break; default: - DRM_ERROR("Unknown parameter %d\n", param.param); - return DRM_ERR(EINVAL); + DRM_ERROR("Unknown parameter %d\n", param->param); + return -EINVAL; } - if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) { + if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) { DRM_ERROR("DRM_COPY_TO_USER failed\n"); - return DRM_ERR(EFAULT); + return -EFAULT; } return 0; } -static int i915_setparam(DRM_IOCTL_ARGS) +static int i915_setparam(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - DRM_DEVICE; drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_setparam_t param; + drm_i915_setparam_t *param = data; if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); + return -EINVAL; } - DRM_COPY_FROM_USER_IOCTL(param, (drm_i915_setparam_t __user *) data, - sizeof(param)); - - switch (param.param) { + switch (param->param) { case I915_SETPARAM_USE_MI_BATCHBUFFER_START: if (!IS_I965G(dev)) - dev_priv->use_mi_batchbuffer_start = param.value; + dev_priv->use_mi_batchbuffer_start = param->value; break; case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY: - dev_priv->tex_lru_log_granularity = param.value; + dev_priv->tex_lru_log_granularity = param->value; break; case I915_SETPARAM_ALLOW_BATCHBUFFER: - dev_priv->allow_batchbuffer = param.value; + dev_priv->allow_batchbuffer = param->value; break; default: - DRM_ERROR("unknown parameter %d\n", param.param); - return DRM_ERR(EINVAL); + DRM_ERROR("unknown parameter %d\n", param->param); + return -EINVAL; } return 0; } -static int i915_set_status_page(DRM_IOCTL_ARGS) +static int i915_set_status_page(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - DRM_DEVICE; drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_hws_addr_t hws; + drm_i915_hws_addr_t *hws = data; if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); + return -EINVAL; } - DRM_COPY_FROM_USER_IOCTL(hws, (drm_i915_hws_addr_t __user *) data, - sizeof(hws)); - printk(KERN_DEBUG "set status page addr 0x%08x\n", (u32)hws.addr); - dev_priv->status_gfx_addr = hws.addr & (0x1ffff<<12); + printk(KERN_DEBUG "set status page addr 0x%08x\n", (u32)hws->addr); + + dev_priv->status_gfx_addr = hws->addr & (0x1ffff<<12); - dev_priv->hws_map.offset = dev->agp->agp_info.aper_base + hws.addr; + dev_priv->hws_map.offset = dev->agp->agp_info.aper_base + hws->addr; dev_priv->hws_map.size = 4*1024; dev_priv->hws_map.type = 0; dev_priv->hws_map.flags = 0; @@ -788,7 +770,7 @@ static int i915_set_status_page(DRM_IOCTL_ARGS) dev_priv->status_gfx_addr = 0; DRM_ERROR("can not ioremap virtual address for" " G33 hw status page\n"); - return DRM_ERR(ENOMEM); + return -ENOMEM; } dev_priv->hw_status_page = dev_priv->hws_map.handle; @@ -821,32 +803,32 @@ void i915_driver_lastclose(struct drm_device * dev) i915_dma_cleanup(dev); } -void i915_driver_preclose(struct drm_device * dev, DRMFILE filp) +void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv) { if (dev->dev_private) { drm_i915_private_t *dev_priv = dev->dev_private; - i915_mem_release(dev, filp, dev_priv->agp_heap); + i915_mem_release(dev, file_priv, dev_priv->agp_heap); } } -drm_ioctl_desc_t i915_ioctls[] = { - [DRM_IOCTL_NR(DRM_I915_INIT)] = {i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_I915_FLUSH)] = {i915_flush_ioctl, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I915_FLIP)] = {i915_flip_bufs, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I915_BATCHBUFFER)] = {i915_batchbuffer, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I915_IRQ_EMIT)] = {i915_irq_emit, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I915_IRQ_WAIT)] = {i915_irq_wait, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I915_GETPARAM)] = {i915_getparam, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I915_SETPARAM)] = {i915_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_I915_ALLOC)] = {i915_mem_alloc, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I915_FREE)] = {i915_mem_free, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I915_INIT_HEAP)] = {i915_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_I915_CMDBUFFER)] = {i915_cmdbuffer, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I915_DESTROY_HEAP)] = { i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, - [DRM_IOCTL_NR(DRM_I915_SET_VBLANK_PIPE)] = { i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, - [DRM_IOCTL_NR(DRM_I915_GET_VBLANK_PIPE)] = { i915_vblank_pipe_get, DRM_AUTH }, - [DRM_IOCTL_NR(DRM_I915_VBLANK_SWAP)] = {i915_vblank_swap, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_I915_HWS_ADDR)] = {i915_set_status_page, DRM_AUTH}, +struct drm_ioctl_desc i915_ioctls[] = { + DRM_IOCTL_DEF(DRM_I915_INIT, i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_I915_FLUSH, i915_flush_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I915_FLIP, i915_flip_bufs, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I915_BATCHBUFFER, i915_batchbuffer, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I915_IRQ_EMIT, i915_irq_emit, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I915_IRQ_WAIT, i915_irq_wait, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I915_GETPARAM, i915_getparam, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I915_SETPARAM, i915_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_I915_ALLOC, i915_mem_alloc, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I915_FREE, i915_mem_free, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I915_INIT_HEAP, i915_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_I915_CMDBUFFER, i915_cmdbuffer, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I915_DESTROY_HEAP, i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY ), + DRM_IOCTL_DEF(DRM_I915_SET_VBLANK_PIPE, i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY ), + DRM_IOCTL_DEF(DRM_I915_GET_VBLANK_PIPE, i915_vblank_pipe_get, DRM_AUTH ), + DRM_IOCTL_DEF(DRM_I915_VBLANK_SWAP, i915_vblank_swap, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I915_HWS_ADDR, i915_set_status_page, DRM_AUTH), }; int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h index 28b98733beb8..e064292e703a 100644 --- a/drivers/char/drm/i915_drv.h +++ b/drivers/char/drm/i915_drv.h @@ -70,7 +70,7 @@ struct mem_block { struct mem_block *prev; int start; int size; - DRMFILE filp; /* 0: free, -1: heap, other: real files */ + struct drm_file *file_priv; /* NULL: free, -1: heap, other: real files */ }; typedef struct _drm_i915_vbl_swap { @@ -116,21 +116,24 @@ typedef struct drm_i915_private { unsigned int swaps_pending; } drm_i915_private_t; -extern drm_ioctl_desc_t i915_ioctls[]; +extern struct drm_ioctl_desc i915_ioctls[]; extern int i915_max_ioctl; /* i915_dma.c */ extern void i915_kernel_lost_context(struct drm_device * dev); extern int i915_driver_load(struct drm_device *, unsigned long flags); extern void i915_driver_lastclose(struct drm_device * dev); -extern void i915_driver_preclose(struct drm_device * dev, DRMFILE filp); +extern void i915_driver_preclose(struct drm_device *dev, + struct drm_file *file_priv); extern int i915_driver_device_is_agp(struct drm_device * dev); extern long i915_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); /* i915_irq.c */ -extern int i915_irq_emit(DRM_IOCTL_ARGS); -extern int i915_irq_wait(DRM_IOCTL_ARGS); +extern int i915_irq_emit(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int i915_irq_wait(struct drm_device *dev, void *data, + struct drm_file *file_priv); extern int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence); extern int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence); @@ -138,18 +141,25 @@ extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); extern void i915_driver_irq_preinstall(struct drm_device * dev); extern void i915_driver_irq_postinstall(struct drm_device * dev); extern void i915_driver_irq_uninstall(struct drm_device * dev); -extern int i915_vblank_pipe_set(DRM_IOCTL_ARGS); -extern int i915_vblank_pipe_get(DRM_IOCTL_ARGS); -extern int i915_vblank_swap(DRM_IOCTL_ARGS); +extern int i915_vblank_pipe_set(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int i915_vblank_pipe_get(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int i915_vblank_swap(struct drm_device *dev, void *data, + struct drm_file *file_priv); /* i915_mem.c */ -extern int i915_mem_alloc(DRM_IOCTL_ARGS); -extern int i915_mem_free(DRM_IOCTL_ARGS); -extern int i915_mem_init_heap(DRM_IOCTL_ARGS); -extern int i915_mem_destroy_heap(DRM_IOCTL_ARGS); +extern int i915_mem_alloc(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int i915_mem_free(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int i915_mem_init_heap(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int i915_mem_destroy_heap(struct drm_device *dev, void *data, + struct drm_file *file_priv); extern void i915_mem_takedown(struct mem_block **heap); extern void i915_mem_release(struct drm_device * dev, - DRMFILE filp, struct mem_block *heap); + struct drm_file *file_priv, struct mem_block *heap); #define I915_READ(reg) DRM_READ32(dev_priv->mmio_map, (reg)) #define I915_WRITE(reg,val) DRM_WRITE32(dev_priv->mmio_map, (reg), (val)) diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c index bb8e9e9c8201..a443f4a202e3 100644 --- a/drivers/char/drm/i915_irq.c +++ b/drivers/char/drm/i915_irq.c @@ -311,7 +311,7 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ, READ_BREADCRUMB(dev_priv) >= irq_nr); - if (ret == DRM_ERR(EBUSY)) { + if (ret == -EBUSY) { DRM_ERROR("%s: EBUSY -- rec: %d emitted: %d\n", __FUNCTION__, READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); @@ -330,7 +330,7 @@ static int i915_driver_vblank_do_wait(struct drm_device *dev, unsigned int *sequ if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); + return -EINVAL; } DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, @@ -355,28 +355,25 @@ int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence) /* Needs the lock as it touches the ring. */ -int i915_irq_emit(DRM_IOCTL_ARGS) +int i915_irq_emit(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - DRM_DEVICE; drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_irq_emit_t emit; + drm_i915_irq_emit_t *emit = data; int result; - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); + return -EINVAL; } - DRM_COPY_FROM_USER_IOCTL(emit, (drm_i915_irq_emit_t __user *) data, - sizeof(emit)); - result = i915_emit_irq(dev); - if (DRM_COPY_TO_USER(emit.irq_seq, &result, sizeof(int))) { + if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) { DRM_ERROR("copy_to_user\n"); - return DRM_ERR(EFAULT); + return -EFAULT; } return 0; @@ -384,21 +381,18 @@ int i915_irq_emit(DRM_IOCTL_ARGS) /* Doesn't need the hardware lock. */ -int i915_irq_wait(DRM_IOCTL_ARGS) +int i915_irq_wait(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - DRM_DEVICE; drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_irq_wait_t irqwait; + drm_i915_irq_wait_t *irqwait = data; if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); + return -EINVAL; } - DRM_COPY_FROM_USER_IOCTL(irqwait, (drm_i915_irq_wait_t __user *) data, - sizeof(irqwait)); - - return i915_wait_irq(dev, irqwait.irq_seq); + return i915_wait_irq(dev, irqwait->irq_seq); } static void i915_enable_interrupt (struct drm_device *dev) @@ -417,64 +411,60 @@ static void i915_enable_interrupt (struct drm_device *dev) /* Set the vblank monitor pipe */ -int i915_vblank_pipe_set(DRM_IOCTL_ARGS) +int i915_vblank_pipe_set(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - DRM_DEVICE; drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_vblank_pipe_t pipe; + drm_i915_vblank_pipe_t *pipe = data; if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); + return -EINVAL; } - DRM_COPY_FROM_USER_IOCTL(pipe, (drm_i915_vblank_pipe_t __user *) data, - sizeof(pipe)); - - if (pipe.pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) { + if (pipe->pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) { DRM_ERROR("%s called with invalid pipe 0x%x\n", - __FUNCTION__, pipe.pipe); - return DRM_ERR(EINVAL); + __FUNCTION__, pipe->pipe); + return -EINVAL; } - dev_priv->vblank_pipe = pipe.pipe; + dev_priv->vblank_pipe = pipe->pipe; i915_enable_interrupt (dev); return 0; } -int i915_vblank_pipe_get(DRM_IOCTL_ARGS) +int i915_vblank_pipe_get(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - DRM_DEVICE; drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_vblank_pipe_t pipe; + drm_i915_vblank_pipe_t *pipe = data; u16 flag; if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); + return -EINVAL; } flag = I915_READ(I915REG_INT_ENABLE_R); - pipe.pipe = 0; + pipe->pipe = 0; if (flag & VSYNC_PIPEA_FLAG) - pipe.pipe |= DRM_I915_VBLANK_PIPE_A; + pipe->pipe |= DRM_I915_VBLANK_PIPE_A; if (flag & VSYNC_PIPEB_FLAG) - pipe.pipe |= DRM_I915_VBLANK_PIPE_B; - DRM_COPY_TO_USER_IOCTL((drm_i915_vblank_pipe_t __user *) data, pipe, - sizeof(pipe)); + pipe->pipe |= DRM_I915_VBLANK_PIPE_B; + return 0; } /** * Schedule buffer swap at given vertical blank. */ -int i915_vblank_swap(DRM_IOCTL_ARGS) +int i915_vblank_swap(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - DRM_DEVICE; drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_vblank_swap_t swap; + drm_i915_vblank_swap_t *swap = data; drm_i915_vbl_swap_t *vbl_swap; unsigned int pipe, seqtype, curseq; unsigned long irqflags; @@ -482,38 +472,35 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __func__); - return DRM_ERR(EINVAL); + return -EINVAL; } if (dev_priv->sarea_priv->rotation) { DRM_DEBUG("Rotation not supported\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } - DRM_COPY_FROM_USER_IOCTL(swap, (drm_i915_vblank_swap_t __user *) data, - sizeof(swap)); - - if (swap.seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE | + if (swap->seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS)) { - DRM_ERROR("Invalid sequence type 0x%x\n", swap.seqtype); - return DRM_ERR(EINVAL); + DRM_ERROR("Invalid sequence type 0x%x\n", swap->seqtype); + return -EINVAL; } - pipe = (swap.seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0; + pipe = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0; - seqtype = swap.seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE); + seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE); if (!(dev_priv->vblank_pipe & (1 << pipe))) { DRM_ERROR("Invalid pipe %d\n", pipe); - return DRM_ERR(EINVAL); + return -EINVAL; } spin_lock_irqsave(&dev->drw_lock, irqflags); - if (!drm_get_drawable_info(dev, swap.drawable)) { + if (!drm_get_drawable_info(dev, swap->drawable)) { spin_unlock_irqrestore(&dev->drw_lock, irqflags); - DRM_DEBUG("Invalid drawable ID %d\n", swap.drawable); - return DRM_ERR(EINVAL); + DRM_DEBUG("Invalid drawable ID %d\n", swap->drawable); + return -EINVAL; } spin_unlock_irqrestore(&dev->drw_lock, irqflags); @@ -521,14 +508,14 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received); if (seqtype == _DRM_VBLANK_RELATIVE) - swap.sequence += curseq; + swap->sequence += curseq; - if ((curseq - swap.sequence) <= (1<<23)) { - if (swap.seqtype & _DRM_VBLANK_NEXTONMISS) { - swap.sequence = curseq + 1; + if ((curseq - swap->sequence) <= (1<<23)) { + if (swap->seqtype & _DRM_VBLANK_NEXTONMISS) { + swap->sequence = curseq + 1; } else { DRM_DEBUG("Missed target sequence\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } } @@ -537,9 +524,9 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) list_for_each(list, &dev_priv->vbl_swaps.head) { vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); - if (vbl_swap->drw_id == swap.drawable && + if (vbl_swap->drw_id == swap->drawable && vbl_swap->pipe == pipe && - vbl_swap->sequence == swap.sequence) { + vbl_swap->sequence == swap->sequence) { spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); DRM_DEBUG("Already scheduled\n"); return 0; @@ -550,21 +537,21 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) if (dev_priv->swaps_pending >= 100) { DRM_DEBUG("Too many swaps queued\n"); - return DRM_ERR(EBUSY); + return -EBUSY; } - vbl_swap = drm_calloc(1, sizeof(vbl_swap), DRM_MEM_DRIVER); + vbl_swap = drm_calloc(1, sizeof(*vbl_swap), DRM_MEM_DRIVER); if (!vbl_swap) { DRM_ERROR("Failed to allocate memory to queue swap\n"); - return DRM_ERR(ENOMEM); + return -ENOMEM; } DRM_DEBUG("\n"); - vbl_swap->drw_id = swap.drawable; + vbl_swap->drw_id = swap->drawable; vbl_swap->pipe = pipe; - vbl_swap->sequence = swap.sequence; + vbl_swap->sequence = swap->sequence; spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); @@ -573,9 +560,6 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); - DRM_COPY_TO_USER_IOCTL((drm_i915_vblank_swap_t __user *) data, swap, - sizeof(swap)); - return 0; } diff --git a/drivers/char/drm/i915_mem.c b/drivers/char/drm/i915_mem.c index 50b4bacef0e0..56fb9b30a5d7 100644 --- a/drivers/char/drm/i915_mem.c +++ b/drivers/char/drm/i915_mem.c @@ -89,7 +89,7 @@ static void mark_block(struct drm_device * dev, struct mem_block *p, int in_use) */ static struct mem_block *split_block(struct mem_block *p, int start, int size, - DRMFILE filp) + struct drm_file *file_priv) { /* Maybe cut off the start of an existing block */ if (start > p->start) { @@ -99,7 +99,7 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size, goto out; newblock->start = start; newblock->size = p->size - (start - p->start); - newblock->filp = NULL; + newblock->file_priv = NULL; newblock->next = p->next; newblock->prev = p; p->next->prev = newblock; @@ -116,7 +116,7 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size, goto out; newblock->start = start + size; newblock->size = p->size - size; - newblock->filp = NULL; + newblock->file_priv = NULL; newblock->next = p->next; newblock->prev = p; p->next->prev = newblock; @@ -126,20 +126,20 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size, out: /* Our block is in the middle */ - p->filp = filp; + p->file_priv = file_priv; return p; } static struct mem_block *alloc_block(struct mem_block *heap, int size, - int align2, DRMFILE filp) + int align2, struct drm_file *file_priv) { struct mem_block *p; int mask = (1 << align2) - 1; for (p = heap->next; p != heap; p = p->next) { int start = (p->start + mask) & ~mask; - if (p->filp == NULL && start + size <= p->start + p->size) - return split_block(p, start, size, filp); + if (p->file_priv == NULL && start + size <= p->start + p->size) + return split_block(p, start, size, file_priv); } return NULL; @@ -158,12 +158,12 @@ static struct mem_block *find_block(struct mem_block *heap, int start) static void free_block(struct mem_block *p) { - p->filp = NULL; + p->file_priv = NULL; - /* Assumes a single contiguous range. Needs a special filp in + /* Assumes a single contiguous range. Needs a special file_priv in * 'heap' to stop it being subsumed. */ - if (p->next->filp == NULL) { + if (p->next->file_priv == NULL) { struct mem_block *q = p->next; p->size += q->size; p->next = q->next; @@ -171,7 +171,7 @@ static void free_block(struct mem_block *p) drm_free(q, sizeof(*q), DRM_MEM_BUFLISTS); } - if (p->prev->filp == NULL) { + if (p->prev->file_priv == NULL) { struct mem_block *q = p->prev; q->size += p->size; q->next = p->next; @@ -197,18 +197,19 @@ static int init_heap(struct mem_block **heap, int start, int size) blocks->start = start; blocks->size = size; - blocks->filp = NULL; + blocks->file_priv = NULL; blocks->next = blocks->prev = *heap; memset(*heap, 0, sizeof(**heap)); - (*heap)->filp = (DRMFILE) - 1; + (*heap)->file_priv = (struct drm_file *) - 1; (*heap)->next = (*heap)->prev = blocks; return 0; } /* Free all blocks associated with the releasing file. */ -void i915_mem_release(struct drm_device * dev, DRMFILE filp, struct mem_block *heap) +void i915_mem_release(struct drm_device * dev, struct drm_file *file_priv, + struct mem_block *heap) { struct mem_block *p; @@ -216,17 +217,17 @@ void i915_mem_release(struct drm_device * dev, DRMFILE filp, struct mem_block *h return; for (p = heap->next; p != heap; p = p->next) { - if (p->filp == filp) { - p->filp = NULL; + if (p->file_priv == file_priv) { + p->file_priv = NULL; mark_block(dev, p, 0); } } - /* Assumes a single contiguous range. Needs a special filp in + /* Assumes a single contiguous range. Needs a special file_priv in * 'heap' to stop it being subsumed. */ for (p = heap->next; p != heap; p = p->next) { - while (p->filp == NULL && p->next->filp == NULL) { + while (p->file_priv == NULL && p->next->file_priv == NULL) { struct mem_block *q = p->next; p->size += q->size; p->next = q->next; @@ -267,129 +268,117 @@ static struct mem_block **get_heap(drm_i915_private_t * dev_priv, int region) /* IOCTL HANDLERS */ -int i915_mem_alloc(DRM_IOCTL_ARGS) +int i915_mem_alloc(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - DRM_DEVICE; drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_mem_alloc_t alloc; + drm_i915_mem_alloc_t *alloc = data; struct mem_block *block, **heap; if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); + return -EINVAL; } - DRM_COPY_FROM_USER_IOCTL(alloc, (drm_i915_mem_alloc_t __user *) data, - sizeof(alloc)); - - heap = get_heap(dev_priv, alloc.region); + heap = get_heap(dev_priv, alloc->region); if (!heap || !*heap) - return DRM_ERR(EFAULT); + return -EFAULT; /* Make things easier on ourselves: all allocations at least * 4k aligned. */ - if (alloc.alignment < 12) - alloc.alignment = 12; + if (alloc->alignment < 12) + alloc->alignment = 12; - block = alloc_block(*heap, alloc.size, alloc.alignment, filp); + block = alloc_block(*heap, alloc->size, alloc->alignment, file_priv); if (!block) - return DRM_ERR(ENOMEM); + return -ENOMEM; mark_block(dev, block, 1); - if (DRM_COPY_TO_USER(alloc.region_offset, &block->start, sizeof(int))) { + if (DRM_COPY_TO_USER(alloc->region_offset, &block->start, + sizeof(int))) { DRM_ERROR("copy_to_user\n"); - return DRM_ERR(EFAULT); + return -EFAULT; } return 0; } -int i915_mem_free(DRM_IOCTL_ARGS) +int i915_mem_free(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - DRM_DEVICE; drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_mem_free_t memfree; + drm_i915_mem_free_t *memfree = data; struct mem_block *block, **heap; if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); + return -EINVAL; } - DRM_COPY_FROM_USER_IOCTL(memfree, (drm_i915_mem_free_t __user *) data, - sizeof(memfree)); - - heap = get_heap(dev_priv, memfree.region); + heap = get_heap(dev_priv, memfree->region); if (!heap || !*heap) - return DRM_ERR(EFAULT); + return -EFAULT; - block = find_block(*heap, memfree.region_offset); + block = find_block(*heap, memfree->region_offset); if (!block) - return DRM_ERR(EFAULT); + return -EFAULT; - if (block->filp != filp) - return DRM_ERR(EPERM); + if (block->file_priv != file_priv) + return -EPERM; mark_block(dev, block, 0); free_block(block); return 0; } -int i915_mem_init_heap(DRM_IOCTL_ARGS) +int i915_mem_init_heap(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - DRM_DEVICE; drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_mem_init_heap_t initheap; + drm_i915_mem_init_heap_t *initheap = data; struct mem_block **heap; if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); + return -EINVAL; } - DRM_COPY_FROM_USER_IOCTL(initheap, - (drm_i915_mem_init_heap_t __user *) data, - sizeof(initheap)); - - heap = get_heap(dev_priv, initheap.region); + heap = get_heap(dev_priv, initheap->region); if (!heap) - return DRM_ERR(EFAULT); + return -EFAULT; if (*heap) { DRM_ERROR("heap already initialized?"); - return DRM_ERR(EFAULT); + return -EFAULT; } - return init_heap(heap, initheap.start, initheap.size); + return init_heap(heap, initheap->start, initheap->size); } -int i915_mem_destroy_heap( DRM_IOCTL_ARGS ) +int i915_mem_destroy_heap( struct drm_device *dev, void *data, + struct drm_file *file_priv ) { - DRM_DEVICE; drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_mem_destroy_heap_t destroyheap; + drm_i915_mem_destroy_heap_t *destroyheap = data; struct mem_block **heap; if ( !dev_priv ) { DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); - return DRM_ERR(EINVAL); + return -EINVAL; } - DRM_COPY_FROM_USER_IOCTL( destroyheap, (drm_i915_mem_destroy_heap_t *)data, - sizeof(destroyheap) ); - - heap = get_heap( dev_priv, destroyheap.region ); + heap = get_heap( dev_priv, destroyheap->region ); if (!heap) { DRM_ERROR("get_heap failed"); - return DRM_ERR(EFAULT); + return -EFAULT; } if (!*heap) { DRM_ERROR("heap not initialized?"); - return DRM_ERR(EFAULT); + return -EFAULT; } i915_mem_takedown( heap ); diff --git a/drivers/char/drm/mga_dma.c b/drivers/char/drm/mga_dma.c index 9c73a6e3861b..c567c34cda78 100644 --- a/drivers/char/drm/mga_dma.c +++ b/drivers/char/drm/mga_dma.c @@ -71,7 +71,7 @@ int mga_do_wait_for_idle(drm_mga_private_t * dev_priv) DRM_ERROR("failed!\n"); DRM_INFO(" status=0x%08x\n", status); #endif - return DRM_ERR(EBUSY); + return -EBUSY; } static int mga_do_dma_reset(drm_mga_private_t * dev_priv) @@ -256,7 +256,7 @@ static int mga_freelist_init(struct drm_device * dev, drm_mga_private_t * dev_pr dev_priv->head = drm_alloc(sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER); if (dev_priv->head == NULL) - return DRM_ERR(ENOMEM); + return -ENOMEM; memset(dev_priv->head, 0, sizeof(drm_mga_freelist_t)); SET_AGE(&dev_priv->head->age, MGA_BUFFER_USED, 0); @@ -267,7 +267,7 @@ static int mga_freelist_init(struct drm_device * dev, drm_mga_private_t * dev_pr entry = drm_alloc(sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER); if (entry == NULL) - return DRM_ERR(ENOMEM); + return -ENOMEM; memset(entry, 0, sizeof(drm_mga_freelist_t)); @@ -399,7 +399,7 @@ int mga_driver_load(struct drm_device * dev, unsigned long flags) dev_priv = drm_alloc(sizeof(drm_mga_private_t), DRM_MEM_DRIVER); if (!dev_priv) - return DRM_ERR(ENOMEM); + return -ENOMEM; dev->dev_private = (void *)dev_priv; memset(dev_priv, 0, sizeof(drm_mga_private_t)); @@ -578,7 +578,7 @@ static int mga_do_agp_dma_bootstrap(struct drm_device * dev, DRM_ERROR("failed to ioremap agp regions! (%p, %p, %p)\n", dev_priv->warp->handle, dev_priv->primary->handle, dev->agp_buffer_map->handle); - return DRM_ERR(ENOMEM); + return -ENOMEM; } dev_priv->dma_access = MGA_PAGPXFER; @@ -622,7 +622,7 @@ static int mga_do_pci_dma_bootstrap(struct drm_device * dev, if (dev->dma == NULL) { DRM_ERROR("dev->dma is NULL\n"); - return DRM_ERR(EFAULT); + return -EFAULT; } /* Make drm_addbufs happy by not trying to create a mapping for less @@ -656,7 +656,7 @@ static int mga_do_pci_dma_bootstrap(struct drm_device * dev, if (err != 0) { DRM_ERROR("Unable to allocate primary DMA region: %d\n", err); - return DRM_ERR(ENOMEM); + return -ENOMEM; } if (dev_priv->primary->size != dma_bs->primary_size) { @@ -759,36 +759,30 @@ static int mga_do_dma_bootstrap(struct drm_device * dev, return err; } -int mga_dma_bootstrap(DRM_IOCTL_ARGS) +int mga_dma_bootstrap(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - DRM_DEVICE; - drm_mga_dma_bootstrap_t bootstrap; + drm_mga_dma_bootstrap_t *bootstrap = data; int err; static const int modes[] = { 0, 1, 2, 2, 4, 4, 4, 4 }; const drm_mga_private_t *const dev_priv = (drm_mga_private_t *) dev->dev_private; - DRM_COPY_FROM_USER_IOCTL(bootstrap, - (drm_mga_dma_bootstrap_t __user *) data, - sizeof(bootstrap)); - - err = mga_do_dma_bootstrap(dev, &bootstrap); + err = mga_do_dma_bootstrap(dev, bootstrap); if (err) { mga_do_cleanup_dma(dev, FULL_CLEANUP); return err; } if (dev_priv->agp_textures != NULL) { - bootstrap.texture_handle = dev_priv->agp_textures->offset; - bootstrap.texture_size = dev_priv->agp_textures->size; + bootstrap->texture_handle = dev_priv->agp_textures->offset; + bootstrap->texture_size = dev_priv->agp_textures->size; } else { - bootstrap.texture_handle = 0; - bootstrap.texture_size = 0; + bootstrap->texture_handle = 0; + bootstrap->texture_size = 0; } - bootstrap.agp_mode = modes[bootstrap.agp_mode & 0x07]; - DRM_COPY_TO_USER_IOCTL((drm_mga_dma_bootstrap_t __user *)data, - bootstrap, sizeof(bootstrap)); + bootstrap->agp_mode = modes[bootstrap->agp_mode & 0x07]; return err; } @@ -826,7 +820,7 @@ static int mga_do_init_dma(struct drm_device * dev, drm_mga_init_t * init) dev_priv->sarea = drm_getsarea(dev); if (!dev_priv->sarea) { DRM_ERROR("failed to find sarea!\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } if (!dev_priv->used_new_dma_init) { @@ -837,29 +831,29 @@ static int mga_do_init_dma(struct drm_device * dev, drm_mga_init_t * init) dev_priv->status = drm_core_findmap(dev, init->status_offset); if (!dev_priv->status) { DRM_ERROR("failed to find status page!\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset); if (!dev_priv->mmio) { DRM_ERROR("failed to find mmio region!\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } dev_priv->warp = drm_core_findmap(dev, init->warp_offset); if (!dev_priv->warp) { DRM_ERROR("failed to find warp microcode region!\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } dev_priv->primary = drm_core_findmap(dev, init->primary_offset); if (!dev_priv->primary) { DRM_ERROR("failed to find primary dma region!\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } dev->agp_buffer_token = init->buffers_offset; dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); if (!dev->agp_buffer_map) { DRM_ERROR("failed to find dma buffer region!\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } drm_core_ioremap(dev_priv->warp, dev); @@ -877,7 +871,7 @@ static int mga_do_init_dma(struct drm_device * dev, drm_mga_init_t * init) ((dev->agp_buffer_map == NULL) || (dev->agp_buffer_map->handle == NULL)))) { DRM_ERROR("failed to ioremap agp regions!\n"); - return DRM_ERR(ENOMEM); + return -ENOMEM; } ret = mga_warp_install_microcode(dev_priv); @@ -927,7 +921,7 @@ static int mga_do_init_dma(struct drm_device * dev, drm_mga_init_t * init) if (mga_freelist_init(dev, dev_priv) < 0) { DRM_ERROR("could not initialize freelist\n"); - return DRM_ERR(ENOMEM); + return -ENOMEM; } return 0; @@ -1007,20 +1001,17 @@ static int mga_do_cleanup_dma(struct drm_device *dev, int full_cleanup) return 0; } -int mga_dma_init(DRM_IOCTL_ARGS) +int mga_dma_init(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - DRM_DEVICE; - drm_mga_init_t init; + drm_mga_init_t *init = data; int err; - LOCK_TEST_WITH_RETURN(dev, filp); - - DRM_COPY_FROM_USER_IOCTL(init, (drm_mga_init_t __user *) data, - sizeof(init)); + LOCK_TEST_WITH_RETURN(dev, file_priv); - switch (init.func) { + switch (init->func) { case MGA_INIT_DMA: - err = mga_do_init_dma(dev, &init); + err = mga_do_init_dma(dev, init); if (err) { (void)mga_do_cleanup_dma(dev, FULL_CLEANUP); } @@ -1029,36 +1020,33 @@ int mga_dma_init(DRM_IOCTL_ARGS) return mga_do_cleanup_dma(dev, FULL_CLEANUP); } - return DRM_ERR(EINVAL); + return -EINVAL; } /* ================================================================ * Primary DMA stream management */ -int mga_dma_flush(DRM_IOCTL_ARGS) +int mga_dma_flush(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - DRM_DEVICE; drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; - struct drm_lock lock; - - LOCK_TEST_WITH_RETURN(dev, filp); + struct drm_lock *lock = data; - DRM_COPY_FROM_USER_IOCTL(lock, (struct drm_lock __user *) data, - sizeof(lock)); + LOCK_TEST_WITH_RETURN(dev, file_priv); DRM_DEBUG("%s%s%s\n", - (lock.flags & _DRM_LOCK_FLUSH) ? "flush, " : "", - (lock.flags & _DRM_LOCK_FLUSH_ALL) ? "flush all, " : "", - (lock.flags & _DRM_LOCK_QUIESCENT) ? "idle, " : ""); + (lock->flags & _DRM_LOCK_FLUSH) ? "flush, " : "", + (lock->flags & _DRM_LOCK_FLUSH_ALL) ? "flush all, " : "", + (lock->flags & _DRM_LOCK_QUIESCENT) ? "idle, " : ""); WRAP_WAIT_WITH_RETURN(dev_priv); - if (lock.flags & (_DRM_LOCK_FLUSH | _DRM_LOCK_FLUSH_ALL)) { + if (lock->flags & (_DRM_LOCK_FLUSH | _DRM_LOCK_FLUSH_ALL)) { mga_do_dma_flush(dev_priv); } - if (lock.flags & _DRM_LOCK_QUIESCENT) { + if (lock->flags & _DRM_LOCK_QUIESCENT) { #if MGA_DMA_DEBUG int ret = mga_do_wait_for_idle(dev_priv); if (ret < 0) @@ -1072,12 +1060,12 @@ int mga_dma_flush(DRM_IOCTL_ARGS) } } -int mga_dma_reset(DRM_IOCTL_ARGS) +int mga_dma_reset(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - DRM_DEVICE; drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); return mga_do_dma_reset(dev_priv); } @@ -1086,7 +1074,8 @@ int mga_dma_reset(DRM_IOCTL_ARGS) * DMA buffer management */ -static int mga_dma_get_buffers(DRMFILE filp, struct drm_device * dev, struct drm_dma * d) +static int mga_dma_get_buffers(struct drm_device * dev, + struct drm_file *file_priv, struct drm_dma * d) { struct drm_buf *buf; int i; @@ -1094,61 +1083,56 @@ static int mga_dma_get_buffers(DRMFILE filp, struct drm_device * dev, struct drm for (i = d->granted_count; i < d->request_count; i++) { buf = mga_freelist_get(dev); if (!buf) - return DRM_ERR(EAGAIN); + return -EAGAIN; - buf->filp = filp; + buf->file_priv = file_priv; if (DRM_COPY_TO_USER(&d->request_indices[i], &buf->idx, sizeof(buf->idx))) - return DRM_ERR(EFAULT); + return -EFAULT; if (DRM_COPY_TO_USER(&d->request_sizes[i], &buf->total, sizeof(buf->total))) - return DRM_ERR(EFAULT); + return -EFAULT; d->granted_count++; } return 0; } -int mga_dma_buffers(DRM_IOCTL_ARGS) +int mga_dma_buffers(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - DRM_DEVICE; struct drm_device_dma *dma = dev->dma; drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; - struct drm_dma __user *argp = (void __user *)data; - struct drm_dma d; + struct drm_dma *d = data; int ret = 0; - LOCK_TEST_WITH_RETURN(dev, filp); - - DRM_COPY_FROM_USER_IOCTL(d, argp, sizeof(d)); + LOCK_TEST_WITH_RETURN(dev, file_priv); /* Please don't send us buffers. */ - if (d.send_count != 0) { + if (d->send_count != 0) { DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n", - DRM_CURRENTPID, d.send_count); - return DRM_ERR(EINVAL); + DRM_CURRENTPID, d->send_count); + return -EINVAL; } /* We'll send you buffers. */ - if (d.request_count < 0 || d.request_count > dma->buf_count) { + if (d->request_count < 0 || d->request_count > dma->buf_count) { DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n", - DRM_CURRENTPID, d.request_count, dma->buf_count); - return DRM_ERR(EINVAL); + DRM_CURRENTPID, d->request_count, dma->buf_count); + return -EINVAL; } WRAP_TEST_WITH_RETURN(dev_priv); - d.granted_count = 0; + d->granted_count = 0; - if (d.request_count) { - ret = mga_dma_get_buffers(filp, dev, &d); + if (d->request_count) { + ret = mga_dma_get_buffers(dev, file_priv, d); } - DRM_COPY_TO_USER_IOCTL(argp, d, sizeof(d)); - return ret; } diff --git a/drivers/char/drm/mga_drv.h b/drivers/char/drm/mga_drv.h index 49253affa475..cd94c04e31c0 100644 --- a/drivers/char/drm/mga_drv.h +++ b/drivers/char/drm/mga_drv.h @@ -148,15 +148,20 @@ typedef struct drm_mga_private { unsigned int agp_size; } drm_mga_private_t; -extern drm_ioctl_desc_t mga_ioctls[]; +extern struct drm_ioctl_desc mga_ioctls[]; extern int mga_max_ioctl; /* mga_dma.c */ -extern int mga_dma_bootstrap(DRM_IOCTL_ARGS); -extern int mga_dma_init(DRM_IOCTL_ARGS); -extern int mga_dma_flush(DRM_IOCTL_ARGS); -extern int mga_dma_reset(DRM_IOCTL_ARGS); -extern int mga_dma_buffers(DRM_IOCTL_ARGS); +extern int mga_dma_bootstrap(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int mga_dma_init(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int mga_dma_flush(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int mga_dma_reset(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int mga_dma_buffers(struct drm_device *dev, void *data, + struct drm_file *file_priv); extern int mga_driver_load(struct drm_device *dev, unsigned long flags); extern int mga_driver_unload(struct drm_device * dev); extern void mga_driver_lastclose(struct drm_device * dev); @@ -245,7 +250,7 @@ do { \ dev_priv->prim.high_mark ) { \ if ( MGA_DMA_DEBUG ) \ DRM_INFO( "%s: wrap...\n", __FUNCTION__ ); \ - return DRM_ERR(EBUSY); \ + return -EBUSY; \ } \ } \ } while (0) @@ -256,7 +261,7 @@ do { \ if ( mga_do_wait_for_idle( dev_priv ) < 0 ) { \ if ( MGA_DMA_DEBUG ) \ DRM_INFO( "%s: wrap...\n", __FUNCTION__ ); \ - return DRM_ERR(EBUSY); \ + return -EBUSY; \ } \ mga_do_dma_wrap_end( dev_priv ); \ } \ diff --git a/drivers/char/drm/mga_state.c b/drivers/char/drm/mga_state.c index d448b0aef33c..5ec8b61c5d45 100644 --- a/drivers/char/drm/mga_state.c +++ b/drivers/char/drm/mga_state.c @@ -392,7 +392,7 @@ static int mga_verify_context(drm_mga_private_t * dev_priv) ctx->dstorg, dev_priv->front_offset, dev_priv->back_offset); ctx->dstorg = 0; - return DRM_ERR(EINVAL); + return -EINVAL; } return 0; @@ -411,7 +411,7 @@ static int mga_verify_tex(drm_mga_private_t * dev_priv, int unit) if (org == (MGA_TEXORGMAP_SYSMEM | MGA_TEXORGACC_PCI)) { DRM_ERROR("*** bad TEXORG: 0x%x, unit %d\n", tex->texorg, unit); tex->texorg = 0; - return DRM_ERR(EINVAL); + return -EINVAL; } return 0; @@ -453,13 +453,13 @@ static int mga_verify_iload(drm_mga_private_t * dev_priv, dstorg + length > (dev_priv->texture_offset + dev_priv->texture_size)) { DRM_ERROR("*** bad iload DSTORG: 0x%x\n", dstorg); - return DRM_ERR(EINVAL); + return -EINVAL; } if (length & MGA_ILOAD_MASK) { DRM_ERROR("*** bad iload length: 0x%x\n", length & MGA_ILOAD_MASK); - return DRM_ERR(EINVAL); + return -EINVAL; } return 0; @@ -471,7 +471,7 @@ static int mga_verify_blit(drm_mga_private_t * dev_priv, if ((srcorg & 0x3) == (MGA_SRCACC_PCI | MGA_SRCMAP_SYSMEM) || (dstorg & 0x3) == (MGA_SRCACC_PCI | MGA_SRCMAP_SYSMEM)) { DRM_ERROR("*** bad blit: src=0x%x dst=0x%x\n", srcorg, dstorg); - return DRM_ERR(EINVAL); + return -EINVAL; } return 0; } @@ -828,24 +828,20 @@ static void mga_dma_dispatch_blit(struct drm_device * dev, drm_mga_blit_t * blit * */ -static int mga_dma_clear(DRM_IOCTL_ARGS) +static int mga_dma_clear(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_mga_private_t *dev_priv = dev->dev_private; drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - drm_mga_clear_t clear; + drm_mga_clear_t *clear = data; - LOCK_TEST_WITH_RETURN(dev, filp); - - DRM_COPY_FROM_USER_IOCTL(clear, (drm_mga_clear_t __user *) data, - sizeof(clear)); + LOCK_TEST_WITH_RETURN(dev, file_priv); if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS) sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS; WRAP_TEST_WITH_RETURN(dev_priv); - mga_dma_dispatch_clear(dev, &clear); + mga_dma_dispatch_clear(dev, clear); /* Make sure we restore the 3D state next time. */ @@ -854,13 +850,12 @@ static int mga_dma_clear(DRM_IOCTL_ARGS) return 0; } -static int mga_dma_swap(DRM_IOCTL_ARGS) +static int mga_dma_swap(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_mga_private_t *dev_priv = dev->dev_private; drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS) sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS; @@ -876,37 +871,32 @@ static int mga_dma_swap(DRM_IOCTL_ARGS) return 0; } -static int mga_dma_vertex(DRM_IOCTL_ARGS) +static int mga_dma_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_mga_private_t *dev_priv = dev->dev_private; struct drm_device_dma *dma = dev->dma; struct drm_buf *buf; drm_mga_buf_priv_t *buf_priv; - drm_mga_vertex_t vertex; - - LOCK_TEST_WITH_RETURN(dev, filp); + drm_mga_vertex_t *vertex = data; - DRM_COPY_FROM_USER_IOCTL(vertex, - (drm_mga_vertex_t __user *) data, - sizeof(vertex)); + LOCK_TEST_WITH_RETURN(dev, file_priv); - if (vertex.idx < 0 || vertex.idx > dma->buf_count) - return DRM_ERR(EINVAL); - buf = dma->buflist[vertex.idx]; + if (vertex->idx < 0 || vertex->idx > dma->buf_count) + return -EINVAL; + buf = dma->buflist[vertex->idx]; buf_priv = buf->dev_private; - buf->used = vertex.used; - buf_priv->discard = vertex.discard; + buf->used = vertex->used; + buf_priv->discard = vertex->discard; if (!mga_verify_state(dev_priv)) { - if (vertex.discard) { + if (vertex->discard) { if (buf_priv->dispatched == 1) AGE_BUFFER(buf_priv); buf_priv->dispatched = 0; mga_freelist_put(dev, buf); } - return DRM_ERR(EINVAL); + return -EINVAL; } WRAP_TEST_WITH_RETURN(dev_priv); @@ -916,82 +906,73 @@ static int mga_dma_vertex(DRM_IOCTL_ARGS) return 0; } -static int mga_dma_indices(DRM_IOCTL_ARGS) +static int mga_dma_indices(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_mga_private_t *dev_priv = dev->dev_private; struct drm_device_dma *dma = dev->dma; struct drm_buf *buf; drm_mga_buf_priv_t *buf_priv; - drm_mga_indices_t indices; + drm_mga_indices_t *indices = data; - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); - DRM_COPY_FROM_USER_IOCTL(indices, - (drm_mga_indices_t __user *) data, - sizeof(indices)); + if (indices->idx < 0 || indices->idx > dma->buf_count) + return -EINVAL; - if (indices.idx < 0 || indices.idx > dma->buf_count) - return DRM_ERR(EINVAL); - - buf = dma->buflist[indices.idx]; + buf = dma->buflist[indices->idx]; buf_priv = buf->dev_private; - buf_priv->discard = indices.discard; + buf_priv->discard = indices->discard; if (!mga_verify_state(dev_priv)) { - if (indices.discard) { + if (indices->discard) { if (buf_priv->dispatched == 1) AGE_BUFFER(buf_priv); buf_priv->dispatched = 0; mga_freelist_put(dev, buf); } - return DRM_ERR(EINVAL); + return -EINVAL; } WRAP_TEST_WITH_RETURN(dev_priv); - mga_dma_dispatch_indices(dev, buf, indices.start, indices.end); + mga_dma_dispatch_indices(dev, buf, indices->start, indices->end); return 0; } -static int mga_dma_iload(DRM_IOCTL_ARGS) +static int mga_dma_iload(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; struct drm_device_dma *dma = dev->dma; drm_mga_private_t *dev_priv = dev->dev_private; struct drm_buf *buf; drm_mga_buf_priv_t *buf_priv; - drm_mga_iload_t iload; + drm_mga_iload_t *iload = data; DRM_DEBUG("\n"); - LOCK_TEST_WITH_RETURN(dev, filp); - - DRM_COPY_FROM_USER_IOCTL(iload, (drm_mga_iload_t __user *) data, - sizeof(iload)); + LOCK_TEST_WITH_RETURN(dev, file_priv); #if 0 if (mga_do_wait_for_idle(dev_priv) < 0) { if (MGA_DMA_DEBUG) DRM_INFO("%s: -EBUSY\n", __FUNCTION__); - return DRM_ERR(EBUSY); + return -EBUSY; } #endif - if (iload.idx < 0 || iload.idx > dma->buf_count) - return DRM_ERR(EINVAL); + if (iload->idx < 0 || iload->idx > dma->buf_count) + return -EINVAL; - buf = dma->buflist[iload.idx]; + buf = dma->buflist[iload->idx]; buf_priv = buf->dev_private; - if (mga_verify_iload(dev_priv, iload.dstorg, iload.length)) { + if (mga_verify_iload(dev_priv, iload->dstorg, iload->length)) { mga_freelist_put(dev, buf); - return DRM_ERR(EINVAL); + return -EINVAL; } WRAP_TEST_WITH_RETURN(dev_priv); - mga_dma_dispatch_iload(dev, buf, iload.dstorg, iload.length); + mga_dma_dispatch_iload(dev, buf, iload->dstorg, iload->length); /* Make sure we restore the 3D state next time. */ @@ -1000,28 +981,24 @@ static int mga_dma_iload(DRM_IOCTL_ARGS) return 0; } -static int mga_dma_blit(DRM_IOCTL_ARGS) +static int mga_dma_blit(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_mga_private_t *dev_priv = dev->dev_private; drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - drm_mga_blit_t blit; + drm_mga_blit_t *blit = data; DRM_DEBUG("\n"); - LOCK_TEST_WITH_RETURN(dev, filp); - - DRM_COPY_FROM_USER_IOCTL(blit, (drm_mga_blit_t __user *) data, - sizeof(blit)); + LOCK_TEST_WITH_RETURN(dev, file_priv); if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS) sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS; - if (mga_verify_blit(dev_priv, blit.srcorg, blit.dstorg)) - return DRM_ERR(EINVAL); + if (mga_verify_blit(dev_priv, blit->srcorg, blit->dstorg)) + return -EINVAL; WRAP_TEST_WITH_RETURN(dev_priv); - mga_dma_dispatch_blit(dev, &blit); + mga_dma_dispatch_blit(dev, blit); /* Make sure we restore the 3D state next time. */ @@ -1030,24 +1007,20 @@ static int mga_dma_blit(DRM_IOCTL_ARGS) return 0; } -static int mga_getparam(DRM_IOCTL_ARGS) +static int mga_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_mga_private_t *dev_priv = dev->dev_private; - drm_mga_getparam_t param; + drm_mga_getparam_t *param = data; int value; if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); + return -EINVAL; } - DRM_COPY_FROM_USER_IOCTL(param, (drm_mga_getparam_t __user *) data, - sizeof(param)); - DRM_DEBUG("pid=%d\n", DRM_CURRENTPID); - switch (param.param) { + switch (param->param) { case MGA_PARAM_IRQ_NR: value = dev->irq; break; @@ -1055,36 +1028,35 @@ static int mga_getparam(DRM_IOCTL_ARGS) value = dev_priv->chipset; break; default: - return DRM_ERR(EINVAL); + return -EINVAL; } - if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) { + if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) { DRM_ERROR("copy_to_user\n"); - return DRM_ERR(EFAULT); + return -EFAULT; } return 0; } -static int mga_set_fence(DRM_IOCTL_ARGS) +static int mga_set_fence(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_mga_private_t *dev_priv = dev->dev_private; - u32 temp; + u32 *fence = data; DMA_LOCALS; if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); + return -EINVAL; } DRM_DEBUG("pid=%d\n", DRM_CURRENTPID); - /* I would normal do this assignment in the declaration of temp, + /* I would normal do this assignment in the declaration of fence, * but dev_priv may be NULL. */ - temp = dev_priv->next_fence_to_post; + *fence = dev_priv->next_fence_to_post; dev_priv->next_fence_to_post++; BEGIN_DMA(1); @@ -1093,53 +1065,40 @@ static int mga_set_fence(DRM_IOCTL_ARGS) MGA_DMAPAD, 0x00000000, MGA_SOFTRAP, 0x00000000); ADVANCE_DMA(); - if (DRM_COPY_TO_USER((u32 __user *) data, &temp, sizeof(u32))) { - DRM_ERROR("copy_to_user\n"); - return DRM_ERR(EFAULT); - } - return 0; } -static int mga_wait_fence(DRM_IOCTL_ARGS) +static int mga_wait_fence(struct drm_device *dev, void *data, struct drm_file * +file_priv) { - DRM_DEVICE; drm_mga_private_t *dev_priv = dev->dev_private; - u32 fence; + u32 *fence = data; if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); + return -EINVAL; } - DRM_COPY_FROM_USER_IOCTL(fence, (u32 __user *) data, sizeof(u32)); - DRM_DEBUG("pid=%d\n", DRM_CURRENTPID); - mga_driver_fence_wait(dev, &fence); - - if (DRM_COPY_TO_USER((u32 __user *) data, &fence, sizeof(u32))) { - DRM_ERROR("copy_to_user\n"); - return DRM_ERR(EFAULT); - } - + mga_driver_fence_wait(dev, fence); return 0; } -drm_ioctl_desc_t mga_ioctls[] = { - [DRM_IOCTL_NR(DRM_MGA_INIT)] = {mga_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_MGA_FLUSH)] = {mga_dma_flush, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_MGA_RESET)] = {mga_dma_reset, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_MGA_SWAP)] = {mga_dma_swap, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_MGA_CLEAR)] = {mga_dma_clear, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_MGA_VERTEX)] = {mga_dma_vertex, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_MGA_INDICES)] = {mga_dma_indices, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_MGA_ILOAD)] = {mga_dma_iload, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_MGA_BLIT)] = {mga_dma_blit, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_MGA_GETPARAM)] = {mga_getparam, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_MGA_SET_FENCE)] = {mga_set_fence, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_MGA_WAIT_FENCE)] = {mga_wait_fence, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_MGA_DMA_BOOTSTRAP)] = {mga_dma_bootstrap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, +struct drm_ioctl_desc mga_ioctls[] = { + DRM_IOCTL_DEF(DRM_MGA_INIT, mga_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_MGA_FLUSH, mga_dma_flush, DRM_AUTH), + DRM_IOCTL_DEF(DRM_MGA_RESET, mga_dma_reset, DRM_AUTH), + DRM_IOCTL_DEF(DRM_MGA_SWAP, mga_dma_swap, DRM_AUTH), + DRM_IOCTL_DEF(DRM_MGA_CLEAR, mga_dma_clear, DRM_AUTH), + DRM_IOCTL_DEF(DRM_MGA_VERTEX, mga_dma_vertex, DRM_AUTH), + DRM_IOCTL_DEF(DRM_MGA_INDICES, mga_dma_indices, DRM_AUTH), + DRM_IOCTL_DEF(DRM_MGA_ILOAD, mga_dma_iload, DRM_AUTH), + DRM_IOCTL_DEF(DRM_MGA_BLIT, mga_dma_blit, DRM_AUTH), + DRM_IOCTL_DEF(DRM_MGA_GETPARAM, mga_getparam, DRM_AUTH), + DRM_IOCTL_DEF(DRM_MGA_SET_FENCE, mga_set_fence, DRM_AUTH), + DRM_IOCTL_DEF(DRM_MGA_WAIT_FENCE, mga_wait_fence, DRM_AUTH), + DRM_IOCTL_DEF(DRM_MGA_DMA_BOOTSTRAP, mga_dma_bootstrap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), }; int mga_max_ioctl = DRM_ARRAY_SIZE(mga_ioctls); diff --git a/drivers/char/drm/mga_warp.c b/drivers/char/drm/mga_warp.c index d67f4925fbac..651b93c8ab5d 100644 --- a/drivers/char/drm/mga_warp.c +++ b/drivers/char/drm/mga_warp.c @@ -141,7 +141,7 @@ int mga_warp_install_microcode(drm_mga_private_t * dev_priv) if (size > dev_priv->warp->size) { DRM_ERROR("microcode too large! (%u > %lu)\n", size, dev_priv->warp->size); - return DRM_ERR(ENOMEM); + return -ENOMEM; } switch (dev_priv->chipset) { @@ -151,7 +151,7 @@ int mga_warp_install_microcode(drm_mga_private_t * dev_priv) case MGA_CARD_TYPE_G200: return mga_warp_install_g200_microcode(dev_priv); default: - return DRM_ERR(EINVAL); + return -EINVAL; } } @@ -177,7 +177,7 @@ int mga_warp_init(drm_mga_private_t * dev_priv) MGA_WRITE(MGA_WVRTXSZ, 7); break; default: - return DRM_ERR(EINVAL); + return -EINVAL; } MGA_WRITE(MGA_WMISC, (MGA_WUCODECACHE_ENABLE | @@ -186,7 +186,7 @@ int mga_warp_init(drm_mga_private_t * dev_priv) if (wmisc != WMISC_EXPECTED) { DRM_ERROR("WARP engine config failed! 0x%x != 0x%x\n", wmisc, WMISC_EXPECTED); - return DRM_ERR(EINVAL); + return -EINVAL; } return 0; diff --git a/drivers/char/drm/r128_cce.c b/drivers/char/drm/r128_cce.c index b163ed09bd81..7d550aba165e 100644 --- a/drivers/char/drm/r128_cce.c +++ b/drivers/char/drm/r128_cce.c @@ -129,7 +129,7 @@ static int r128_do_pixcache_flush(drm_r128_private_t * dev_priv) #if R128_FIFO_DEBUG DRM_ERROR("failed!\n"); #endif - return DRM_ERR(EBUSY); + return -EBUSY; } static int r128_do_wait_for_fifo(drm_r128_private_t * dev_priv, int entries) @@ -146,7 +146,7 @@ static int r128_do_wait_for_fifo(drm_r128_private_t * dev_priv, int entries) #if R128_FIFO_DEBUG DRM_ERROR("failed!\n"); #endif - return DRM_ERR(EBUSY); + return -EBUSY; } static int r128_do_wait_for_idle(drm_r128_private_t * dev_priv) @@ -168,7 +168,7 @@ static int r128_do_wait_for_idle(drm_r128_private_t * dev_priv) #if R128_FIFO_DEBUG DRM_ERROR("failed!\n"); #endif - return DRM_ERR(EBUSY); + return -EBUSY; } /* ================================================================ @@ -227,7 +227,7 @@ int r128_do_cce_idle(drm_r128_private_t * dev_priv) DRM_ERROR("failed!\n"); r128_status(dev_priv); #endif - return DRM_ERR(EBUSY); + return -EBUSY; } /* Start the Concurrent Command Engine. @@ -355,7 +355,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init) dev_priv = drm_alloc(sizeof(drm_r128_private_t), DRM_MEM_DRIVER); if (dev_priv == NULL) - return DRM_ERR(ENOMEM); + return -ENOMEM; memset(dev_priv, 0, sizeof(drm_r128_private_t)); @@ -365,7 +365,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init) DRM_ERROR("PCI GART memory not allocated!\n"); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce(dev); - return DRM_ERR(EINVAL); + return -EINVAL; } dev_priv->usec_timeout = init->usec_timeout; @@ -374,7 +374,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init) DRM_DEBUG("TIMEOUT problem!\n"); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce(dev); - return DRM_ERR(EINVAL); + return -EINVAL; } dev_priv->cce_mode = init->cce_mode; @@ -394,7 +394,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init) DRM_DEBUG("Bad cce_mode!\n"); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce(dev); - return DRM_ERR(EINVAL); + return -EINVAL; } switch (init->cce_mode) { @@ -461,7 +461,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init) DRM_ERROR("could not find sarea!\n"); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce(dev); - return DRM_ERR(EINVAL); + return -EINVAL; } dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset); @@ -469,21 +469,21 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init) DRM_ERROR("could not find mmio region!\n"); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce(dev); - return DRM_ERR(EINVAL); + return -EINVAL; } dev_priv->cce_ring = drm_core_findmap(dev, init->ring_offset); if (!dev_priv->cce_ring) { DRM_ERROR("could not find cce ring region!\n"); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce(dev); - return DRM_ERR(EINVAL); + return -EINVAL; } dev_priv->ring_rptr = drm_core_findmap(dev, init->ring_rptr_offset); if (!dev_priv->ring_rptr) { DRM_ERROR("could not find ring read pointer!\n"); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce(dev); - return DRM_ERR(EINVAL); + return -EINVAL; } dev->agp_buffer_token = init->buffers_offset; dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); @@ -491,7 +491,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init) DRM_ERROR("could not find dma buffer region!\n"); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce(dev); - return DRM_ERR(EINVAL); + return -EINVAL; } if (!dev_priv->is_pci) { @@ -501,7 +501,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init) DRM_ERROR("could not find agp texture region!\n"); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce(dev); - return DRM_ERR(EINVAL); + return -EINVAL; } } @@ -520,7 +520,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init) DRM_ERROR("Could not ioremap agp regions!\n"); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce(dev); - return DRM_ERR(ENOMEM); + return -ENOMEM; } } else #endif @@ -567,7 +567,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init) DRM_ERROR("failed to init PCI GART!\n"); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce(dev); - return DRM_ERR(ENOMEM); + return -ENOMEM; } R128_WRITE(R128_PCI_GART_PAGE, dev_priv->gart_info.bus_addr); #if __OS_HAS_AGP @@ -625,35 +625,30 @@ int r128_do_cleanup_cce(struct drm_device * dev) return 0; } -int r128_cce_init(DRM_IOCTL_ARGS) +int r128_cce_init(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; - drm_r128_init_t init; + drm_r128_init_t *init = data; DRM_DEBUG("\n"); - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); - DRM_COPY_FROM_USER_IOCTL(init, (drm_r128_init_t __user *) data, - sizeof(init)); - - switch (init.func) { + switch (init->func) { case R128_INIT_CCE: - return r128_do_init_cce(dev, &init); + return r128_do_init_cce(dev, init); case R128_CLEANUP_CCE: return r128_do_cleanup_cce(dev); } - return DRM_ERR(EINVAL); + return -EINVAL; } -int r128_cce_start(DRM_IOCTL_ARGS) +int r128_cce_start(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_r128_private_t *dev_priv = dev->dev_private; DRM_DEBUG("\n"); - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); if (dev_priv->cce_running || dev_priv->cce_mode == R128_PM4_NONPM4) { DRM_DEBUG("%s while CCE running\n", __FUNCTION__); @@ -668,30 +663,26 @@ int r128_cce_start(DRM_IOCTL_ARGS) /* Stop the CCE. The engine must have been idled before calling this * routine. */ -int r128_cce_stop(DRM_IOCTL_ARGS) +int r128_cce_stop(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_r128_private_t *dev_priv = dev->dev_private; - drm_r128_cce_stop_t stop; + drm_r128_cce_stop_t *stop = data; int ret; DRM_DEBUG("\n"); - LOCK_TEST_WITH_RETURN(dev, filp); - - DRM_COPY_FROM_USER_IOCTL(stop, (drm_r128_cce_stop_t __user *) data, - sizeof(stop)); + LOCK_TEST_WITH_RETURN(dev, file_priv); /* Flush any pending CCE commands. This ensures any outstanding * commands are exectuted by the engine before we turn it off. */ - if (stop.flush) { + if (stop->flush) { r128_do_cce_flush(dev_priv); } /* If we fail to make the engine go idle, we return an error * code so that the DRM ioctl wrapper can try again. */ - if (stop.idle) { + if (stop->idle) { ret = r128_do_cce_idle(dev_priv); if (ret) return ret; @@ -711,17 +702,16 @@ int r128_cce_stop(DRM_IOCTL_ARGS) /* Just reset the CCE ring. Called as part of an X Server engine reset. */ -int r128_cce_reset(DRM_IOCTL_ARGS) +int r128_cce_reset(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_r128_private_t *dev_priv = dev->dev_private; DRM_DEBUG("\n"); - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); if (!dev_priv) { DRM_DEBUG("%s called before init done\n", __FUNCTION__); - return DRM_ERR(EINVAL); + return -EINVAL; } r128_do_cce_reset(dev_priv); @@ -732,13 +722,12 @@ int r128_cce_reset(DRM_IOCTL_ARGS) return 0; } -int r128_cce_idle(DRM_IOCTL_ARGS) +int r128_cce_idle(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_r128_private_t *dev_priv = dev->dev_private; DRM_DEBUG("\n"); - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); if (dev_priv->cce_running) { r128_do_cce_flush(dev_priv); @@ -747,19 +736,18 @@ int r128_cce_idle(DRM_IOCTL_ARGS) return r128_do_cce_idle(dev_priv); } -int r128_engine_reset(DRM_IOCTL_ARGS) +int r128_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; DRM_DEBUG("\n"); - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); return r128_do_engine_reset(dev); } -int r128_fullscreen(DRM_IOCTL_ARGS) +int r128_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv) { - return DRM_ERR(EINVAL); + return -EINVAL; } /* ================================================================ @@ -780,7 +768,7 @@ static int r128_freelist_init(struct drm_device * dev) dev_priv->head = drm_alloc(sizeof(drm_r128_freelist_t), DRM_MEM_DRIVER); if (dev_priv->head == NULL) - return DRM_ERR(ENOMEM); + return -ENOMEM; memset(dev_priv->head, 0, sizeof(drm_r128_freelist_t)); dev_priv->head->age = R128_BUFFER_USED; @@ -791,7 +779,7 @@ static int r128_freelist_init(struct drm_device * dev) entry = drm_alloc(sizeof(drm_r128_freelist_t), DRM_MEM_DRIVER); if (!entry) - return DRM_ERR(ENOMEM); + return -ENOMEM; entry->age = R128_BUFFER_FREE; entry->buf = buf; @@ -828,7 +816,7 @@ static struct drm_buf *r128_freelist_get(struct drm_device * dev) for (i = 0; i < dma->buf_count; i++) { buf = dma->buflist[i]; buf_priv = buf->dev_private; - if (buf->filp == 0) + if (buf->file_priv == 0) return buf; } @@ -883,10 +871,12 @@ int r128_wait_ring(drm_r128_private_t * dev_priv, int n) /* FIXME: This is being ignored... */ DRM_ERROR("failed!\n"); - return DRM_ERR(EBUSY); + return -EBUSY; } -static int r128_cce_get_buffers(DRMFILE filp, struct drm_device * dev, struct drm_dma * d) +static int r128_cce_get_buffers(struct drm_device * dev, + struct drm_file *file_priv, + struct drm_dma * d) { int i; struct drm_buf *buf; @@ -894,57 +884,51 @@ static int r128_cce_get_buffers(DRMFILE filp, struct drm_device * dev, struct dr for (i = d->granted_count; i < d->request_count; i++) { buf = r128_freelist_get(dev); if (!buf) - return DRM_ERR(EAGAIN); + return -EAGAIN; - buf->filp = filp; + buf->file_priv = file_priv; if (DRM_COPY_TO_USER(&d->request_indices[i], &buf->idx, sizeof(buf->idx))) - return DRM_ERR(EFAULT); + return -EFAULT; if (DRM_COPY_TO_USER(&d->request_sizes[i], &buf->total, sizeof(buf->total))) - return DRM_ERR(EFAULT); + return -EFAULT; d->granted_count++; } return 0; } -int r128_cce_buffers(DRM_IOCTL_ARGS) +int r128_cce_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; struct drm_device_dma *dma = dev->dma; int ret = 0; - struct drm_dma __user *argp = (void __user *)data; - struct drm_dma d; + struct drm_dma *d = data; - LOCK_TEST_WITH_RETURN(dev, filp); - - DRM_COPY_FROM_USER_IOCTL(d, argp, sizeof(d)); + LOCK_TEST_WITH_RETURN(dev, file_priv); /* Please don't send us buffers. */ - if (d.send_count != 0) { + if (d->send_count != 0) { DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n", - DRM_CURRENTPID, d.send_count); - return DRM_ERR(EINVAL); + DRM_CURRENTPID, d->send_count); + return -EINVAL; } /* We'll send you buffers. */ - if (d.request_count < 0 || d.request_count > dma->buf_count) { + if (d->request_count < 0 || d->request_count > dma->buf_count) { DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n", - DRM_CURRENTPID, d.request_count, dma->buf_count); - return DRM_ERR(EINVAL); + DRM_CURRENTPID, d->request_count, dma->buf_count); + return -EINVAL; } - d.granted_count = 0; + d->granted_count = 0; - if (d.request_count) { - ret = r128_cce_get_buffers(filp, dev, &d); + if (d->request_count) { + ret = r128_cce_get_buffers(dev, file_priv, d); } - DRM_COPY_TO_USER_IOCTL(argp, d, sizeof(d)); - return ret; } diff --git a/drivers/char/drm/r128_drm.h b/drivers/char/drm/r128_drm.h index e94a39c6e327..8d8878b55f55 100644 --- a/drivers/char/drm/r128_drm.h +++ b/drivers/char/drm/r128_drm.h @@ -222,11 +222,7 @@ typedef struct drm_r128_init { R128_INIT_CCE = 0x01, R128_CLEANUP_CCE = 0x02 } func; -#if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0) - int sarea_priv_offset; -#else unsigned long sarea_priv_offset; -#endif int is_pci; int cce_mode; int cce_secure; @@ -240,21 +236,12 @@ typedef struct drm_r128_init { unsigned int depth_offset, depth_pitch; unsigned int span_offset; -#if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0) - unsigned int fb_offset; - unsigned int mmio_offset; - unsigned int ring_offset; - unsigned int ring_rptr_offset; - unsigned int buffers_offset; - unsigned int agp_textures_offset; -#else unsigned long fb_offset; unsigned long mmio_offset; unsigned long ring_offset; unsigned long ring_rptr_offset; unsigned long buffers_offset; unsigned long agp_textures_offset; -#endif } drm_r128_init_t; typedef struct drm_r128_cce_stop { @@ -264,15 +251,10 @@ typedef struct drm_r128_cce_stop { typedef struct drm_r128_clear { unsigned int flags; -#if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0) - int x, y, w, h; -#endif unsigned int clear_color; unsigned int clear_depth; -#if CONFIG_XFREE86_VERSION >= XFREE86_VERSION(4,1,0,0) unsigned int color_mask; unsigned int depth_mask; -#endif } drm_r128_clear_t; typedef struct drm_r128_vertex { diff --git a/drivers/char/drm/r128_drv.h b/drivers/char/drm/r128_drv.h index 72249fb2fd1c..250d2aa46581 100644 --- a/drivers/char/drm/r128_drv.h +++ b/drivers/char/drm/r128_drv.h @@ -129,18 +129,18 @@ typedef struct drm_r128_buf_priv { drm_r128_freelist_t *list_entry; } drm_r128_buf_priv_t; -extern drm_ioctl_desc_t r128_ioctls[]; +extern struct drm_ioctl_desc r128_ioctls[]; extern int r128_max_ioctl; /* r128_cce.c */ -extern int r128_cce_init(DRM_IOCTL_ARGS); -extern int r128_cce_start(DRM_IOCTL_ARGS); -extern int r128_cce_stop(DRM_IOCTL_ARGS); -extern int r128_cce_reset(DRM_IOCTL_ARGS); -extern int r128_cce_idle(DRM_IOCTL_ARGS); -extern int r128_engine_reset(DRM_IOCTL_ARGS); -extern int r128_fullscreen(DRM_IOCTL_ARGS); -extern int r128_cce_buffers(DRM_IOCTL_ARGS); +extern int r128_cce_init(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int r128_cce_start(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int r128_cce_stop(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int r128_cce_reset(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int r128_cce_idle(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int r128_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int r128_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int r128_cce_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv); extern void r128_freelist_reset(struct drm_device * dev); @@ -156,7 +156,8 @@ extern void r128_driver_irq_preinstall(struct drm_device * dev); extern void r128_driver_irq_postinstall(struct drm_device * dev); extern void r128_driver_irq_uninstall(struct drm_device * dev); extern void r128_driver_lastclose(struct drm_device * dev); -extern void r128_driver_preclose(struct drm_device * dev, DRMFILE filp); +extern void r128_driver_preclose(struct drm_device * dev, + struct drm_file *file_priv); extern long r128_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); @@ -428,7 +429,7 @@ do { \ DRM_UDELAY(1); \ } \ DRM_ERROR( "ring space check failed!\n" ); \ - return DRM_ERR(EBUSY); \ + return -EBUSY; \ } \ __ring_space_done: \ ; \ diff --git a/drivers/char/drm/r128_state.c b/drivers/char/drm/r128_state.c index 7b334fb7d649..b7f483cac6d4 100644 --- a/drivers/char/drm/r128_state.c +++ b/drivers/char/drm/r128_state.c @@ -776,8 +776,9 @@ static void r128_cce_dispatch_indices(struct drm_device * dev, sarea_priv->nbox = 0; } -static int r128_cce_dispatch_blit(DRMFILE filp, - struct drm_device * dev, drm_r128_blit_t * blit) +static int r128_cce_dispatch_blit(struct drm_device * dev, + struct drm_file *file_priv, + drm_r128_blit_t * blit) { drm_r128_private_t *dev_priv = dev->dev_private; struct drm_device_dma *dma = dev->dma; @@ -809,7 +810,7 @@ static int r128_cce_dispatch_blit(DRMFILE filp, break; default: DRM_ERROR("invalid blit format %d\n", blit->format); - return DRM_ERR(EINVAL); + return -EINVAL; } /* Flush the pixel cache, and mark the contents as Read Invalid. @@ -829,14 +830,14 @@ static int r128_cce_dispatch_blit(DRMFILE filp, buf = dma->buflist[blit->idx]; buf_priv = buf->dev_private; - if (buf->filp != filp) { + if (buf->file_priv != file_priv) { DRM_ERROR("process %d using buffer owned by %p\n", - DRM_CURRENTPID, buf->filp); - return DRM_ERR(EINVAL); + DRM_CURRENTPID, buf->file_priv); + return -EINVAL; } if (buf->pending) { DRM_ERROR("sending pending buffer %d\n", blit->idx); - return DRM_ERR(EINVAL); + return -EINVAL; } buf_priv->discard = 1; @@ -900,22 +901,22 @@ static int r128_cce_dispatch_write_span(struct drm_device * dev, count = depth->n; if (count > 4096 || count <= 0) - return DRM_ERR(EMSGSIZE); + return -EMSGSIZE; if (DRM_COPY_FROM_USER(&x, depth->x, sizeof(x))) { - return DRM_ERR(EFAULT); + return -EFAULT; } if (DRM_COPY_FROM_USER(&y, depth->y, sizeof(y))) { - return DRM_ERR(EFAULT); + return -EFAULT; } buffer_size = depth->n * sizeof(u32); buffer = drm_alloc(buffer_size, DRM_MEM_BUFS); if (buffer == NULL) - return DRM_ERR(ENOMEM); + return -ENOMEM; if (DRM_COPY_FROM_USER(buffer, depth->buffer, buffer_size)) { drm_free(buffer, buffer_size, DRM_MEM_BUFS); - return DRM_ERR(EFAULT); + return -EFAULT; } mask_size = depth->n * sizeof(u8); @@ -923,12 +924,12 @@ static int r128_cce_dispatch_write_span(struct drm_device * dev, mask = drm_alloc(mask_size, DRM_MEM_BUFS); if (mask == NULL) { drm_free(buffer, buffer_size, DRM_MEM_BUFS); - return DRM_ERR(ENOMEM); + return -ENOMEM; } if (DRM_COPY_FROM_USER(mask, depth->mask, mask_size)) { drm_free(buffer, buffer_size, DRM_MEM_BUFS); drm_free(mask, mask_size, DRM_MEM_BUFS); - return DRM_ERR(EFAULT); + return -EFAULT; } for (i = 0; i < count; i++, x++) { @@ -996,28 +997,28 @@ static int r128_cce_dispatch_write_pixels(struct drm_device * dev, count = depth->n; if (count > 4096 || count <= 0) - return DRM_ERR(EMSGSIZE); + return -EMSGSIZE; xbuf_size = count * sizeof(*x); ybuf_size = count * sizeof(*y); x = drm_alloc(xbuf_size, DRM_MEM_BUFS); if (x == NULL) { - return DRM_ERR(ENOMEM); + return -ENOMEM; } y = drm_alloc(ybuf_size, DRM_MEM_BUFS); if (y == NULL) { drm_free(x, xbuf_size, DRM_MEM_BUFS); - return DRM_ERR(ENOMEM); + return -ENOMEM; } if (DRM_COPY_FROM_USER(x, depth->x, xbuf_size)) { drm_free(x, xbuf_size, DRM_MEM_BUFS); drm_free(y, ybuf_size, DRM_MEM_BUFS); - return DRM_ERR(EFAULT); + return -EFAULT; } if (DRM_COPY_FROM_USER(y, depth->y, xbuf_size)) { drm_free(x, xbuf_size, DRM_MEM_BUFS); drm_free(y, ybuf_size, DRM_MEM_BUFS); - return DRM_ERR(EFAULT); + return -EFAULT; } buffer_size = depth->n * sizeof(u32); @@ -1025,13 +1026,13 @@ static int r128_cce_dispatch_write_pixels(struct drm_device * dev, if (buffer == NULL) { drm_free(x, xbuf_size, DRM_MEM_BUFS); drm_free(y, ybuf_size, DRM_MEM_BUFS); - return DRM_ERR(ENOMEM); + return -ENOMEM; } if (DRM_COPY_FROM_USER(buffer, depth->buffer, buffer_size)) { drm_free(x, xbuf_size, DRM_MEM_BUFS); drm_free(y, ybuf_size, DRM_MEM_BUFS); drm_free(buffer, buffer_size, DRM_MEM_BUFS); - return DRM_ERR(EFAULT); + return -EFAULT; } if (depth->mask) { @@ -1041,14 +1042,14 @@ static int r128_cce_dispatch_write_pixels(struct drm_device * dev, drm_free(x, xbuf_size, DRM_MEM_BUFS); drm_free(y, ybuf_size, DRM_MEM_BUFS); drm_free(buffer, buffer_size, DRM_MEM_BUFS); - return DRM_ERR(ENOMEM); + return -ENOMEM; } if (DRM_COPY_FROM_USER(mask, depth->mask, mask_size)) { drm_free(x, xbuf_size, DRM_MEM_BUFS); drm_free(y, ybuf_size, DRM_MEM_BUFS); drm_free(buffer, buffer_size, DRM_MEM_BUFS); drm_free(mask, mask_size, DRM_MEM_BUFS); - return DRM_ERR(EFAULT); + return -EFAULT; } for (i = 0; i < count; i++) { @@ -1115,13 +1116,13 @@ static int r128_cce_dispatch_read_span(struct drm_device * dev, count = depth->n; if (count > 4096 || count <= 0) - return DRM_ERR(EMSGSIZE); + return -EMSGSIZE; if (DRM_COPY_FROM_USER(&x, depth->x, sizeof(x))) { - return DRM_ERR(EFAULT); + return -EFAULT; } if (DRM_COPY_FROM_USER(&y, depth->y, sizeof(y))) { - return DRM_ERR(EFAULT); + return -EFAULT; } BEGIN_RING(7); @@ -1159,7 +1160,7 @@ static int r128_cce_dispatch_read_pixels(struct drm_device * dev, count = depth->n; if (count > 4096 || count <= 0) - return DRM_ERR(EMSGSIZE); + return -EMSGSIZE; if (count > dev_priv->depth_pitch) { count = dev_priv->depth_pitch; @@ -1169,22 +1170,22 @@ static int r128_cce_dispatch_read_pixels(struct drm_device * dev, ybuf_size = count * sizeof(*y); x = drm_alloc(xbuf_size, DRM_MEM_BUFS); if (x == NULL) { - return DRM_ERR(ENOMEM); + return -ENOMEM; } y = drm_alloc(ybuf_size, DRM_MEM_BUFS); if (y == NULL) { drm_free(x, xbuf_size, DRM_MEM_BUFS); - return DRM_ERR(ENOMEM); + return -ENOMEM; } if (DRM_COPY_FROM_USER(x, depth->x, xbuf_size)) { drm_free(x, xbuf_size, DRM_MEM_BUFS); drm_free(y, ybuf_size, DRM_MEM_BUFS); - return DRM_ERR(EFAULT); + return -EFAULT; } if (DRM_COPY_FROM_USER(y, depth->y, ybuf_size)) { drm_free(x, xbuf_size, DRM_MEM_BUFS); drm_free(y, ybuf_size, DRM_MEM_BUFS); - return DRM_ERR(EFAULT); + return -EFAULT; } for (i = 0; i < count; i++) { @@ -1241,25 +1242,21 @@ static void r128_cce_dispatch_stipple(struct drm_device * dev, u32 * stipple) * IOCTL functions */ -static int r128_cce_clear(DRM_IOCTL_ARGS) +static int r128_cce_clear(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_r128_private_t *dev_priv = dev->dev_private; drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; - drm_r128_clear_t clear; + drm_r128_clear_t *clear = data; DRM_DEBUG("\n"); - LOCK_TEST_WITH_RETURN(dev, filp); - - DRM_COPY_FROM_USER_IOCTL(clear, (drm_r128_clear_t __user *) data, - sizeof(clear)); + LOCK_TEST_WITH_RETURN(dev, file_priv); RING_SPACE_TEST_WITH_RETURN(dev_priv); if (sarea_priv->nbox > R128_NR_SAREA_CLIPRECTS) sarea_priv->nbox = R128_NR_SAREA_CLIPRECTS; - r128_cce_dispatch_clear(dev, &clear); + r128_cce_dispatch_clear(dev, clear); COMMIT_RING(); /* Make sure we restore the 3D state next time. @@ -1309,13 +1306,12 @@ static int r128_do_cleanup_pageflip(struct drm_device * dev) * They can & should be intermixed to support multiple 3d windows. */ -static int r128_cce_flip(DRM_IOCTL_ARGS) +static int r128_cce_flip(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_r128_private_t *dev_priv = dev->dev_private; DRM_DEBUG("%s\n", __FUNCTION__); - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); RING_SPACE_TEST_WITH_RETURN(dev_priv); @@ -1328,14 +1324,13 @@ static int r128_cce_flip(DRM_IOCTL_ARGS) return 0; } -static int r128_cce_swap(DRM_IOCTL_ARGS) +static int r128_cce_swap(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_r128_private_t *dev_priv = dev->dev_private; drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; DRM_DEBUG("%s\n", __FUNCTION__); - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); RING_SPACE_TEST_WITH_RETURN(dev_priv); @@ -1350,58 +1345,54 @@ static int r128_cce_swap(DRM_IOCTL_ARGS) return 0; } -static int r128_cce_vertex(DRM_IOCTL_ARGS) +static int r128_cce_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_r128_private_t *dev_priv = dev->dev_private; struct drm_device_dma *dma = dev->dma; struct drm_buf *buf; drm_r128_buf_priv_t *buf_priv; - drm_r128_vertex_t vertex; + drm_r128_vertex_t *vertex = data; - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); + return -EINVAL; } - DRM_COPY_FROM_USER_IOCTL(vertex, (drm_r128_vertex_t __user *) data, - sizeof(vertex)); - DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n", - DRM_CURRENTPID, vertex.idx, vertex.count, vertex.discard); + DRM_CURRENTPID, vertex->idx, vertex->count, vertex->discard); - if (vertex.idx < 0 || vertex.idx >= dma->buf_count) { + if (vertex->idx < 0 || vertex->idx >= dma->buf_count) { DRM_ERROR("buffer index %d (of %d max)\n", - vertex.idx, dma->buf_count - 1); - return DRM_ERR(EINVAL); + vertex->idx, dma->buf_count - 1); + return -EINVAL; } - if (vertex.prim < 0 || - vertex.prim > R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2) { - DRM_ERROR("buffer prim %d\n", vertex.prim); - return DRM_ERR(EINVAL); + if (vertex->prim < 0 || + vertex->prim > R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2) { + DRM_ERROR("buffer prim %d\n", vertex->prim); + return -EINVAL; } RING_SPACE_TEST_WITH_RETURN(dev_priv); VB_AGE_TEST_WITH_RETURN(dev_priv); - buf = dma->buflist[vertex.idx]; + buf = dma->buflist[vertex->idx]; buf_priv = buf->dev_private; - if (buf->filp != filp) { + if (buf->file_priv != file_priv) { DRM_ERROR("process %d using buffer owned by %p\n", - DRM_CURRENTPID, buf->filp); - return DRM_ERR(EINVAL); + DRM_CURRENTPID, buf->file_priv); + return -EINVAL; } if (buf->pending) { - DRM_ERROR("sending pending buffer %d\n", vertex.idx); - return DRM_ERR(EINVAL); + DRM_ERROR("sending pending buffer %d\n", vertex->idx); + return -EINVAL; } - buf->used = vertex.count; - buf_priv->prim = vertex.prim; - buf_priv->discard = vertex.discard; + buf->used = vertex->count; + buf_priv->prim = vertex->prim; + buf_priv->discard = vertex->discard; r128_cce_dispatch_vertex(dev, buf); @@ -1409,134 +1400,123 @@ static int r128_cce_vertex(DRM_IOCTL_ARGS) return 0; } -static int r128_cce_indices(DRM_IOCTL_ARGS) +static int r128_cce_indices(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_r128_private_t *dev_priv = dev->dev_private; struct drm_device_dma *dma = dev->dma; struct drm_buf *buf; drm_r128_buf_priv_t *buf_priv; - drm_r128_indices_t elts; + drm_r128_indices_t *elts = data; int count; - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); + return -EINVAL; } - DRM_COPY_FROM_USER_IOCTL(elts, (drm_r128_indices_t __user *) data, - sizeof(elts)); - DRM_DEBUG("pid=%d buf=%d s=%d e=%d d=%d\n", DRM_CURRENTPID, - elts.idx, elts.start, elts.end, elts.discard); + elts->idx, elts->start, elts->end, elts->discard); - if (elts.idx < 0 || elts.idx >= dma->buf_count) { + if (elts->idx < 0 || elts->idx >= dma->buf_count) { DRM_ERROR("buffer index %d (of %d max)\n", - elts.idx, dma->buf_count - 1); - return DRM_ERR(EINVAL); + elts->idx, dma->buf_count - 1); + return -EINVAL; } - if (elts.prim < 0 || elts.prim > R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2) { - DRM_ERROR("buffer prim %d\n", elts.prim); - return DRM_ERR(EINVAL); + if (elts->prim < 0 || + elts->prim > R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2) { + DRM_ERROR("buffer prim %d\n", elts->prim); + return -EINVAL; } RING_SPACE_TEST_WITH_RETURN(dev_priv); VB_AGE_TEST_WITH_RETURN(dev_priv); - buf = dma->buflist[elts.idx]; + buf = dma->buflist[elts->idx]; buf_priv = buf->dev_private; - if (buf->filp != filp) { + if (buf->file_priv != file_priv) { DRM_ERROR("process %d using buffer owned by %p\n", - DRM_CURRENTPID, buf->filp); - return DRM_ERR(EINVAL); + DRM_CURRENTPID, buf->file_priv); + return -EINVAL; } if (buf->pending) { - DRM_ERROR("sending pending buffer %d\n", elts.idx); - return DRM_ERR(EINVAL); + DRM_ERROR("sending pending buffer %d\n", elts->idx); + return -EINVAL; } - count = (elts.end - elts.start) / sizeof(u16); - elts.start -= R128_INDEX_PRIM_OFFSET; + count = (elts->end - elts->start) / sizeof(u16); + elts->start -= R128_INDEX_PRIM_OFFSET; - if (elts.start & 0x7) { - DRM_ERROR("misaligned buffer 0x%x\n", elts.start); - return DRM_ERR(EINVAL); + if (elts->start & 0x7) { + DRM_ERROR("misaligned buffer 0x%x\n", elts->start); + return -EINVAL; } - if (elts.start < buf->used) { - DRM_ERROR("no header 0x%x - 0x%x\n", elts.start, buf->used); - return DRM_ERR(EINVAL); + if (elts->start < buf->used) { + DRM_ERROR("no header 0x%x - 0x%x\n", elts->start, buf->used); + return -EINVAL; } - buf->used = elts.end; - buf_priv->prim = elts.prim; - buf_priv->discard = elts.discard; + buf->used = elts->end; + buf_priv->prim = elts->prim; + buf_priv->discard = elts->discard; - r128_cce_dispatch_indices(dev, buf, elts.start, elts.end, count); + r128_cce_dispatch_indices(dev, buf, elts->start, elts->end, count); COMMIT_RING(); return 0; } -static int r128_cce_blit(DRM_IOCTL_ARGS) +static int r128_cce_blit(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; struct drm_device_dma *dma = dev->dma; drm_r128_private_t *dev_priv = dev->dev_private; - drm_r128_blit_t blit; + drm_r128_blit_t *blit = data; int ret; - LOCK_TEST_WITH_RETURN(dev, filp); - - DRM_COPY_FROM_USER_IOCTL(blit, (drm_r128_blit_t __user *) data, - sizeof(blit)); + LOCK_TEST_WITH_RETURN(dev, file_priv); - DRM_DEBUG("pid=%d index=%d\n", DRM_CURRENTPID, blit.idx); + DRM_DEBUG("pid=%d index=%d\n", DRM_CURRENTPID, blit->idx); - if (blit.idx < 0 || blit.idx >= dma->buf_count) { + if (blit->idx < 0 || blit->idx >= dma->buf_count) { DRM_ERROR("buffer index %d (of %d max)\n", - blit.idx, dma->buf_count - 1); - return DRM_ERR(EINVAL); + blit->idx, dma->buf_count - 1); + return -EINVAL; } RING_SPACE_TEST_WITH_RETURN(dev_priv); VB_AGE_TEST_WITH_RETURN(dev_priv); - ret = r128_cce_dispatch_blit(filp, dev, &blit); + ret = r128_cce_dispatch_blit(dev, file_priv, blit); COMMIT_RING(); return ret; } -static int r128_cce_depth(DRM_IOCTL_ARGS) +static int r128_cce_depth(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_r128_private_t *dev_priv = dev->dev_private; - drm_r128_depth_t depth; + drm_r128_depth_t *depth = data; int ret; - LOCK_TEST_WITH_RETURN(dev, filp); - - DRM_COPY_FROM_USER_IOCTL(depth, (drm_r128_depth_t __user *) data, - sizeof(depth)); + LOCK_TEST_WITH_RETURN(dev, file_priv); RING_SPACE_TEST_WITH_RETURN(dev_priv); - ret = DRM_ERR(EINVAL); - switch (depth.func) { + ret = -EINVAL; + switch (depth->func) { case R128_WRITE_SPAN: - ret = r128_cce_dispatch_write_span(dev, &depth); + ret = r128_cce_dispatch_write_span(dev, depth); break; case R128_WRITE_PIXELS: - ret = r128_cce_dispatch_write_pixels(dev, &depth); + ret = r128_cce_dispatch_write_pixels(dev, depth); break; case R128_READ_SPAN: - ret = r128_cce_dispatch_read_span(dev, &depth); + ret = r128_cce_dispatch_read_span(dev, depth); break; case R128_READ_PIXELS: - ret = r128_cce_dispatch_read_pixels(dev, &depth); + ret = r128_cce_dispatch_read_pixels(dev, depth); break; } @@ -1544,20 +1524,16 @@ static int r128_cce_depth(DRM_IOCTL_ARGS) return ret; } -static int r128_cce_stipple(DRM_IOCTL_ARGS) +static int r128_cce_stipple(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_r128_private_t *dev_priv = dev->dev_private; - drm_r128_stipple_t stipple; + drm_r128_stipple_t *stipple = data; u32 mask[32]; - LOCK_TEST_WITH_RETURN(dev, filp); - - DRM_COPY_FROM_USER_IOCTL(stipple, (drm_r128_stipple_t __user *) data, - sizeof(stipple)); + LOCK_TEST_WITH_RETURN(dev, file_priv); - if (DRM_COPY_FROM_USER(&mask, stipple.mask, 32 * sizeof(u32))) - return DRM_ERR(EFAULT); + if (DRM_COPY_FROM_USER(&mask, stipple->mask, 32 * sizeof(u32))) + return -EFAULT; RING_SPACE_TEST_WITH_RETURN(dev_priv); @@ -1567,61 +1543,58 @@ static int r128_cce_stipple(DRM_IOCTL_ARGS) return 0; } -static int r128_cce_indirect(DRM_IOCTL_ARGS) +static int r128_cce_indirect(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_r128_private_t *dev_priv = dev->dev_private; struct drm_device_dma *dma = dev->dma; struct drm_buf *buf; drm_r128_buf_priv_t *buf_priv; - drm_r128_indirect_t indirect; + drm_r128_indirect_t *indirect = data; #if 0 RING_LOCALS; #endif - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); + return -EINVAL; } - DRM_COPY_FROM_USER_IOCTL(indirect, (drm_r128_indirect_t __user *) data, - sizeof(indirect)); - DRM_DEBUG("indirect: idx=%d s=%d e=%d d=%d\n", - indirect.idx, indirect.start, indirect.end, indirect.discard); + indirect->idx, indirect->start, indirect->end, + indirect->discard); - if (indirect.idx < 0 || indirect.idx >= dma->buf_count) { + if (indirect->idx < 0 || indirect->idx >= dma->buf_count) { DRM_ERROR("buffer index %d (of %d max)\n", - indirect.idx, dma->buf_count - 1); - return DRM_ERR(EINVAL); + indirect->idx, dma->buf_count - 1); + return -EINVAL; } - buf = dma->buflist[indirect.idx]; + buf = dma->buflist[indirect->idx]; buf_priv = buf->dev_private; - if (buf->filp != filp) { + if (buf->file_priv != file_priv) { DRM_ERROR("process %d using buffer owned by %p\n", - DRM_CURRENTPID, buf->filp); - return DRM_ERR(EINVAL); + DRM_CURRENTPID, buf->file_priv); + return -EINVAL; } if (buf->pending) { - DRM_ERROR("sending pending buffer %d\n", indirect.idx); - return DRM_ERR(EINVAL); + DRM_ERROR("sending pending buffer %d\n", indirect->idx); + return -EINVAL; } - if (indirect.start < buf->used) { + if (indirect->start < buf->used) { DRM_ERROR("reusing indirect: start=0x%x actual=0x%x\n", - indirect.start, buf->used); - return DRM_ERR(EINVAL); + indirect->start, buf->used); + return -EINVAL; } RING_SPACE_TEST_WITH_RETURN(dev_priv); VB_AGE_TEST_WITH_RETURN(dev_priv); - buf->used = indirect.end; - buf_priv->discard = indirect.discard; + buf->used = indirect->end; + buf_priv->discard = indirect->discard; #if 0 /* Wait for the 3D stream to idle before the indirect buffer @@ -1636,46 +1609,42 @@ static int r128_cce_indirect(DRM_IOCTL_ARGS) * X server. This is insecure and is thus only available to * privileged clients. */ - r128_cce_dispatch_indirect(dev, buf, indirect.start, indirect.end); + r128_cce_dispatch_indirect(dev, buf, indirect->start, indirect->end); COMMIT_RING(); return 0; } -static int r128_getparam(DRM_IOCTL_ARGS) +static int r128_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_r128_private_t *dev_priv = dev->dev_private; - drm_r128_getparam_t param; + drm_r128_getparam_t *param = data; int value; if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); + return -EINVAL; } - DRM_COPY_FROM_USER_IOCTL(param, (drm_r128_getparam_t __user *) data, - sizeof(param)); - DRM_DEBUG("pid=%d\n", DRM_CURRENTPID); - switch (param.param) { + switch (param->param) { case R128_PARAM_IRQ_NR: value = dev->irq; break; default: - return DRM_ERR(EINVAL); + return -EINVAL; } - if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) { + if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) { DRM_ERROR("copy_to_user\n"); - return DRM_ERR(EFAULT); + return -EFAULT; } return 0; } -void r128_driver_preclose(struct drm_device * dev, DRMFILE filp) +void r128_driver_preclose(struct drm_device * dev, struct drm_file *file_priv) { if (dev->dev_private) { drm_r128_private_t *dev_priv = dev->dev_private; @@ -1690,24 +1659,24 @@ void r128_driver_lastclose(struct drm_device * dev) r128_do_cleanup_cce(dev); } -drm_ioctl_desc_t r128_ioctls[] = { - [DRM_IOCTL_NR(DRM_R128_INIT)] = {r128_cce_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_R128_CCE_START)] = {r128_cce_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_R128_CCE_STOP)] = {r128_cce_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_R128_CCE_RESET)] = {r128_cce_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_R128_CCE_IDLE)] = {r128_cce_idle, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_R128_RESET)] = {r128_engine_reset, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_R128_FULLSCREEN)] = {r128_fullscreen, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_R128_SWAP)] = {r128_cce_swap, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_R128_FLIP)] = {r128_cce_flip, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_R128_CLEAR)] = {r128_cce_clear, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_R128_VERTEX)] = {r128_cce_vertex, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_R128_INDICES)] = {r128_cce_indices, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_R128_BLIT)] = {r128_cce_blit, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_R128_DEPTH)] = {r128_cce_depth, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_R128_STIPPLE)] = {r128_cce_stipple, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_R128_INDIRECT)] = {r128_cce_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_R128_GETPARAM)] = {r128_getparam, DRM_AUTH}, +struct drm_ioctl_desc r128_ioctls[] = { + DRM_IOCTL_DEF(DRM_R128_INIT, r128_cce_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_R128_CCE_START, r128_cce_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_R128_CCE_STOP, r128_cce_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_R128_CCE_RESET, r128_cce_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_R128_CCE_IDLE, r128_cce_idle, DRM_AUTH), + DRM_IOCTL_DEF(DRM_R128_RESET, r128_engine_reset, DRM_AUTH), + DRM_IOCTL_DEF(DRM_R128_FULLSCREEN, r128_fullscreen, DRM_AUTH), + DRM_IOCTL_DEF(DRM_R128_SWAP, r128_cce_swap, DRM_AUTH), + DRM_IOCTL_DEF(DRM_R128_FLIP, r128_cce_flip, DRM_AUTH), + DRM_IOCTL_DEF(DRM_R128_CLEAR, r128_cce_clear, DRM_AUTH), + DRM_IOCTL_DEF(DRM_R128_VERTEX, r128_cce_vertex, DRM_AUTH), + DRM_IOCTL_DEF(DRM_R128_INDICES, r128_cce_indices, DRM_AUTH), + DRM_IOCTL_DEF(DRM_R128_BLIT, r128_cce_blit, DRM_AUTH), + DRM_IOCTL_DEF(DRM_R128_DEPTH, r128_cce_depth, DRM_AUTH), + DRM_IOCTL_DEF(DRM_R128_STIPPLE, r128_cce_stipple, DRM_AUTH), + DRM_IOCTL_DEF(DRM_R128_INDIRECT, r128_cce_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_R128_GETPARAM, r128_getparam, DRM_AUTH), }; int r128_max_ioctl = DRM_ARRAY_SIZE(r128_ioctls); diff --git a/drivers/char/drm/r300_cmdbuf.c b/drivers/char/drm/r300_cmdbuf.c index 4e5aca6ba59a..59b2944811c5 100644 --- a/drivers/char/drm/r300_cmdbuf.c +++ b/drivers/char/drm/r300_cmdbuf.c @@ -74,7 +74,7 @@ static int r300_emit_cliprects(drm_radeon_private_t *dev_priv, if (DRM_COPY_FROM_USER_UNCHECKED (&box, &cmdbuf->boxes[n + i], sizeof(box))) { DRM_ERROR("copy cliprect faulted\n"); - return DRM_ERR(EFAULT); + return -EFAULT; } box.x1 = @@ -263,7 +263,7 @@ static __inline__ int r300_emit_carefully_checked_packet0(drm_radeon_private_t * DRM_ERROR ("Cannot emit more than 64 values at a time (reg=%04x sz=%d)\n", reg, sz); - return DRM_ERR(EINVAL); + return -EINVAL; } for (i = 0; i < sz; i++) { values[i] = ((int *)cmdbuf->buf)[i]; @@ -275,13 +275,13 @@ static __inline__ int r300_emit_carefully_checked_packet0(drm_radeon_private_t * DRM_ERROR ("Offset failed range check (reg=%04x sz=%d)\n", reg, sz); - return DRM_ERR(EINVAL); + return -EINVAL; } break; default: DRM_ERROR("Register %04x failed check as flag=%02x\n", reg + i * 4, r300_reg_flags[(reg >> 2) + i]); - return DRM_ERR(EINVAL); + return -EINVAL; } } @@ -317,12 +317,12 @@ static __inline__ int r300_emit_packet0(drm_radeon_private_t *dev_priv, return 0; if (sz * 4 > cmdbuf->bufsz) - return DRM_ERR(EINVAL); + return -EINVAL; if (reg + sz * 4 >= 0x10000) { DRM_ERROR("No such registers in hardware reg=%04x sz=%d\n", reg, sz); - return DRM_ERR(EINVAL); + return -EINVAL; } if (r300_check_range(reg, sz)) { @@ -362,7 +362,7 @@ static __inline__ int r300_emit_vpu(drm_radeon_private_t *dev_priv, if (!sz) return 0; if (sz * 16 > cmdbuf->bufsz) - return DRM_ERR(EINVAL); + return -EINVAL; BEGIN_RING(5 + sz * 4); /* Wait for VAP to come to senses.. */ @@ -391,7 +391,7 @@ static __inline__ int r300_emit_clear(drm_radeon_private_t *dev_priv, RING_LOCALS; if (8 * 4 > cmdbuf->bufsz) - return DRM_ERR(EINVAL); + return -EINVAL; BEGIN_RING(10); OUT_RING(CP_PACKET3(R200_3D_DRAW_IMMD_2, 8)); @@ -421,7 +421,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv, if ((count + 1) > MAX_ARRAY_PACKET) { DRM_ERROR("Too large payload in 3D_LOAD_VBPNTR (count=%d)\n", count); - return DRM_ERR(EINVAL); + return -EINVAL; } memset(payload, 0, MAX_ARRAY_PACKET * 4); memcpy(payload, cmdbuf->buf + 4, (count + 1) * 4); @@ -437,7 +437,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv, DRM_ERROR ("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n", k, i); - return DRM_ERR(EINVAL); + return -EINVAL; } k++; i++; @@ -448,7 +448,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv, DRM_ERROR ("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n", k, i); - return DRM_ERR(EINVAL); + return -EINVAL; } k++; i++; @@ -458,7 +458,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv, DRM_ERROR ("Malformed 3D_LOAD_VBPNTR packet (k=%d i=%d narrays=%d count+1=%d).\n", k, i, narrays, count + 1); - return DRM_ERR(EINVAL); + return -EINVAL; } /* all clear, output packet */ @@ -492,7 +492,7 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv, ret = !radeon_check_offset(dev_priv, offset); if (ret) { DRM_ERROR("Invalid bitblt first offset is %08X\n", offset); - return DRM_ERR(EINVAL); + return -EINVAL; } } @@ -502,7 +502,7 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv, ret = !radeon_check_offset(dev_priv, offset); if (ret) { DRM_ERROR("Invalid bitblt second offset is %08X\n", offset); - return DRM_ERR(EINVAL); + return -EINVAL; } } @@ -530,12 +530,12 @@ static __inline__ int r300_emit_indx_buffer(drm_radeon_private_t *dev_priv, if ((cmd[1] & 0x8000ffff) != 0x80000810) { DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]); - return DRM_ERR(EINVAL); + return -EINVAL; } ret = !radeon_check_offset(dev_priv, cmd[2]); if (ret) { DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]); - return DRM_ERR(EINVAL); + return -EINVAL; } BEGIN_RING(count+2); @@ -557,7 +557,7 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv, RING_LOCALS; if (4 > cmdbuf->bufsz) - return DRM_ERR(EINVAL); + return -EINVAL; /* Fixme !! This simply emits a packet without much checking. We need to be smarter. */ @@ -568,7 +568,7 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv, /* Is it packet 3 ? */ if ((header >> 30) != 0x3) { DRM_ERROR("Not a packet3 header (0x%08x)\n", header); - return DRM_ERR(EINVAL); + return -EINVAL; } count = (header >> 16) & 0x3fff; @@ -578,7 +578,7 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv, DRM_ERROR ("Expected packet3 of length %d but have only %d bytes left\n", (count + 2) * 4, cmdbuf->bufsz); - return DRM_ERR(EINVAL); + return -EINVAL; } /* Is it a packet type we know about ? */ @@ -600,7 +600,7 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv, break; default: DRM_ERROR("Unknown packet3 header (0x%08x)\n", header); - return DRM_ERR(EINVAL); + return -EINVAL; } BEGIN_RING(count + 2); @@ -664,7 +664,7 @@ static __inline__ int r300_emit_packet3(drm_radeon_private_t *dev_priv, DRM_ERROR("bad packet3 type %i at %p\n", header.packet3.packet, cmdbuf->buf - sizeof(header)); - return DRM_ERR(EINVAL); + return -EINVAL; } n += R300_SIMULTANEOUS_CLIPRECTS; @@ -726,11 +726,11 @@ static int r300_scratch(drm_radeon_private_t *dev_priv, if (cmdbuf->bufsz < (sizeof(u64) + header.scratch.n_bufs * sizeof(buf_idx))) { - return DRM_ERR(EINVAL); + return -EINVAL; } if (header.scratch.reg >= 5) { - return DRM_ERR(EINVAL); + return -EINVAL; } dev_priv->scratch_ages[header.scratch.reg]++; @@ -745,21 +745,21 @@ static int r300_scratch(drm_radeon_private_t *dev_priv, buf_idx *= 2; /* 8 bytes per buf */ if (DRM_COPY_TO_USER(ref_age_base + buf_idx, &dev_priv->scratch_ages[header.scratch.reg], sizeof(u32))) { - return DRM_ERR(EINVAL); + return -EINVAL; } if (DRM_COPY_FROM_USER(&h_pending, ref_age_base + buf_idx + 1, sizeof(u32))) { - return DRM_ERR(EINVAL); + return -EINVAL; } if (h_pending == 0) { - return DRM_ERR(EINVAL); + return -EINVAL; } h_pending--; if (DRM_COPY_TO_USER(ref_age_base + buf_idx + 1, &h_pending, sizeof(u32))) { - return DRM_ERR(EINVAL); + return -EINVAL; } cmdbuf->buf += sizeof(buf_idx); @@ -780,8 +780,7 @@ static int r300_scratch(drm_radeon_private_t *dev_priv, * Called by the ioctl handler function radeon_cp_cmdbuf. */ int r300_do_cp_cmdbuf(struct drm_device *dev, - DRMFILE filp, - struct drm_file *filp_priv, + struct drm_file *file_priv, drm_radeon_kcmd_buffer_t *cmdbuf) { drm_radeon_private_t *dev_priv = dev->dev_private; @@ -879,15 +878,16 @@ int r300_do_cp_cmdbuf(struct drm_device *dev, if (idx < 0 || idx >= dma->buf_count) { DRM_ERROR("buffer index %d (of %d max)\n", idx, dma->buf_count - 1); - ret = DRM_ERR(EINVAL); + ret = -EINVAL; goto cleanup; } buf = dma->buflist[idx]; - if (buf->filp != filp || buf->pending) { + if (buf->file_priv != file_priv || buf->pending) { DRM_ERROR("bad buffer %p %p %d\n", - buf->filp, filp, buf->pending); - ret = DRM_ERR(EINVAL); + buf->file_priv, file_priv, + buf->pending); + ret = -EINVAL; goto cleanup; } @@ -924,7 +924,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev, DRM_ERROR("bad cmd_type %i at %p\n", header.header.cmd_type, cmdbuf->buf - sizeof(header)); - ret = DRM_ERR(EINVAL); + ret = -EINVAL; goto cleanup; } } diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c index af5790f8fd53..335423c5c186 100644 --- a/drivers/char/drm/radeon_cp.c +++ b/drivers/char/drm/radeon_cp.c @@ -889,7 +889,7 @@ static int radeon_do_pixcache_flush(drm_radeon_private_t * dev_priv) DRM_ERROR("failed!\n"); radeon_status(dev_priv); #endif - return DRM_ERR(EBUSY); + return -EBUSY; } static int radeon_do_wait_for_fifo(drm_radeon_private_t * dev_priv, int entries) @@ -910,7 +910,7 @@ static int radeon_do_wait_for_fifo(drm_radeon_private_t * dev_priv, int entries) DRM_ERROR("failed!\n"); radeon_status(dev_priv); #endif - return DRM_ERR(EBUSY); + return -EBUSY; } static int radeon_do_wait_for_idle(drm_radeon_private_t * dev_priv) @@ -936,7 +936,7 @@ static int radeon_do_wait_for_idle(drm_radeon_private_t * dev_priv) DRM_ERROR("failed!\n"); radeon_status(dev_priv); #endif - return DRM_ERR(EBUSY); + return -EBUSY; } /* ================================================================ @@ -1394,7 +1394,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) if ((dev_priv->flags & RADEON_NEW_MEMMAP) && !dev_priv->new_memmap) { DRM_ERROR("Cannot initialise DRM on this card\nThis card requires a new X.org DDX for 3D\n"); radeon_do_cleanup_cp(dev); - return DRM_ERR(EINVAL); + return -EINVAL; } if (init->is_pci && (dev_priv->flags & RADEON_IS_AGP)) { @@ -1409,7 +1409,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) if ((!(dev_priv->flags & RADEON_IS_AGP)) && !dev->sg) { DRM_ERROR("PCI GART memory not allocated!\n"); radeon_do_cleanup_cp(dev); - return DRM_ERR(EINVAL); + return -EINVAL; } dev_priv->usec_timeout = init->usec_timeout; @@ -1417,7 +1417,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) dev_priv->usec_timeout > RADEON_MAX_USEC_TIMEOUT) { DRM_DEBUG("TIMEOUT problem!\n"); radeon_do_cleanup_cp(dev); - return DRM_ERR(EINVAL); + return -EINVAL; } /* Enable vblank on CRTC1 for older X servers @@ -1446,7 +1446,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) (init->cp_mode != RADEON_CSQ_PRIBM_INDBM)) { DRM_DEBUG("BAD cp_mode (%x)!\n", init->cp_mode); radeon_do_cleanup_cp(dev); - return DRM_ERR(EINVAL); + return -EINVAL; } switch (init->fb_bpp) { @@ -1515,27 +1515,27 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) if (!dev_priv->sarea) { DRM_ERROR("could not find sarea!\n"); radeon_do_cleanup_cp(dev); - return DRM_ERR(EINVAL); + return -EINVAL; } dev_priv->cp_ring = drm_core_findmap(dev, init->ring_offset); if (!dev_priv->cp_ring) { DRM_ERROR("could not find cp ring region!\n"); radeon_do_cleanup_cp(dev); - return DRM_ERR(EINVAL); + return -EINVAL; } dev_priv->ring_rptr = drm_core_findmap(dev, init->ring_rptr_offset); if (!dev_priv->ring_rptr) { DRM_ERROR("could not find ring read pointer!\n"); radeon_do_cleanup_cp(dev); - return DRM_ERR(EINVAL); + return -EINVAL; } dev->agp_buffer_token = init->buffers_offset; dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); if (!dev->agp_buffer_map) { DRM_ERROR("could not find dma buffer region!\n"); radeon_do_cleanup_cp(dev); - return DRM_ERR(EINVAL); + return -EINVAL; } if (init->gart_textures_offset) { @@ -1544,7 +1544,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) if (!dev_priv->gart_textures) { DRM_ERROR("could not find GART texture region!\n"); radeon_do_cleanup_cp(dev); - return DRM_ERR(EINVAL); + return -EINVAL; } } @@ -1562,7 +1562,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) !dev->agp_buffer_map->handle) { DRM_ERROR("could not find ioremap agp regions!\n"); radeon_do_cleanup_cp(dev); - return DRM_ERR(EINVAL); + return -EINVAL; } } else #endif @@ -1710,14 +1710,14 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) DRM_ERROR ("Cannot use PCI Express without GART in FB memory\n"); radeon_do_cleanup_cp(dev); - return DRM_ERR(EINVAL); + return -EINVAL; } } if (!drm_ati_pcigart_init(dev, &dev_priv->gart_info)) { DRM_ERROR("failed to init PCI GART!\n"); radeon_do_cleanup_cp(dev); - return DRM_ERR(ENOMEM); + return -ENOMEM; } /* Turn on PCI GART */ @@ -1797,7 +1797,7 @@ static int radeon_do_resume_cp(struct drm_device * dev) if (!dev_priv) { DRM_ERROR("Called with no initialization\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } DRM_DEBUG("Starting radeon_do_resume_cp()\n"); @@ -1823,38 +1823,33 @@ static int radeon_do_resume_cp(struct drm_device * dev) return 0; } -int radeon_cp_init(DRM_IOCTL_ARGS) +int radeon_cp_init(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; - drm_radeon_init_t init; + drm_radeon_init_t *init = data; - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); - DRM_COPY_FROM_USER_IOCTL(init, (drm_radeon_init_t __user *) data, - sizeof(init)); - - if (init.func == RADEON_INIT_R300_CP) + if (init->func == RADEON_INIT_R300_CP) r300_init_reg_flags(); - switch (init.func) { + switch (init->func) { case RADEON_INIT_CP: case RADEON_INIT_R200_CP: case RADEON_INIT_R300_CP: - return radeon_do_init_cp(dev, &init); + return radeon_do_init_cp(dev, init); case RADEON_CLEANUP_CP: return radeon_do_cleanup_cp(dev); } - return DRM_ERR(EINVAL); + return -EINVAL; } -int radeon_cp_start(DRM_IOCTL_ARGS) +int radeon_cp_start(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; DRM_DEBUG("\n"); - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); if (dev_priv->cp_running) { DRM_DEBUG("%s while CP running\n", __FUNCTION__); @@ -1874,18 +1869,14 @@ int radeon_cp_start(DRM_IOCTL_ARGS) /* Stop the CP. The engine must have been idled before calling this * routine. */ -int radeon_cp_stop(DRM_IOCTL_ARGS) +int radeon_cp_stop(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; - drm_radeon_cp_stop_t stop; + drm_radeon_cp_stop_t *stop = data; int ret; DRM_DEBUG("\n"); - LOCK_TEST_WITH_RETURN(dev, filp); - - DRM_COPY_FROM_USER_IOCTL(stop, (drm_radeon_cp_stop_t __user *) data, - sizeof(stop)); + LOCK_TEST_WITH_RETURN(dev, file_priv); if (!dev_priv->cp_running) return 0; @@ -1893,14 +1884,14 @@ int radeon_cp_stop(DRM_IOCTL_ARGS) /* Flush any pending CP commands. This ensures any outstanding * commands are exectuted by the engine before we turn it off. */ - if (stop.flush) { + if (stop->flush) { radeon_do_cp_flush(dev_priv); } /* If we fail to make the engine go idle, we return an error * code so that the DRM ioctl wrapper can try again. */ - if (stop.idle) { + if (stop->idle) { ret = radeon_do_cp_idle(dev_priv); if (ret) return ret; @@ -1963,17 +1954,16 @@ void radeon_do_release(struct drm_device * dev) /* Just reset the CP ring. Called as part of an X Server engine reset. */ -int radeon_cp_reset(DRM_IOCTL_ARGS) +int radeon_cp_reset(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; DRM_DEBUG("\n"); - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); if (!dev_priv) { DRM_DEBUG("%s called before init done\n", __FUNCTION__); - return DRM_ERR(EINVAL); + return -EINVAL; } radeon_do_cp_reset(dev_priv); @@ -1984,32 +1974,29 @@ int radeon_cp_reset(DRM_IOCTL_ARGS) return 0; } -int radeon_cp_idle(DRM_IOCTL_ARGS) +int radeon_cp_idle(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; DRM_DEBUG("\n"); - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); return radeon_do_cp_idle(dev_priv); } /* Added by Charl P. Botha to call radeon_do_resume_cp(). */ -int radeon_cp_resume(DRM_IOCTL_ARGS) +int radeon_cp_resume(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; return radeon_do_resume_cp(dev); } -int radeon_engine_reset(DRM_IOCTL_ARGS) +int radeon_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; DRM_DEBUG("\n"); - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); return radeon_do_engine_reset(dev); } @@ -2020,7 +2007,7 @@ int radeon_engine_reset(DRM_IOCTL_ARGS) /* KW: Deprecated to say the least: */ -int radeon_fullscreen(DRM_IOCTL_ARGS) +int radeon_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv) { return 0; } @@ -2066,8 +2053,9 @@ struct drm_buf *radeon_freelist_get(struct drm_device * dev) for (i = start; i < dma->buf_count; i++) { buf = dma->buflist[i]; buf_priv = buf->dev_private; - if (buf->filp == 0 || (buf->pending && - buf_priv->age <= done_age)) { + if (buf->file_priv == NULL || (buf->pending && + buf_priv->age <= + done_age)) { dev_priv->stats.requested_bufs++; buf->pending = 0; return buf; @@ -2106,8 +2094,9 @@ struct drm_buf *radeon_freelist_get(struct drm_device * dev) for (i = start; i < dma->buf_count; i++) { buf = dma->buflist[i]; buf_priv = buf->dev_private; - if (buf->filp == 0 || (buf->pending && - buf_priv->age <= done_age)) { + if (buf->file_priv == 0 || (buf->pending && + buf_priv->age <= + done_age)) { dev_priv->stats.requested_bufs++; buf->pending = 0; return buf; @@ -2167,10 +2156,11 @@ int radeon_wait_ring(drm_radeon_private_t * dev_priv, int n) radeon_status(dev_priv); DRM_ERROR("failed!\n"); #endif - return DRM_ERR(EBUSY); + return -EBUSY; } -static int radeon_cp_get_buffers(DRMFILE filp, struct drm_device * dev, +static int radeon_cp_get_buffers(struct drm_device *dev, + struct drm_file *file_priv, struct drm_dma * d) { int i; @@ -2179,58 +2169,52 @@ static int radeon_cp_get_buffers(DRMFILE filp, struct drm_device * dev, for (i = d->granted_count; i < d->request_count; i++) { buf = radeon_freelist_get(dev); if (!buf) - return DRM_ERR(EBUSY); /* NOTE: broken client */ + return -EBUSY; /* NOTE: broken client */ - buf->filp = filp; + buf->file_priv = file_priv; if (DRM_COPY_TO_USER(&d->request_indices[i], &buf->idx, sizeof(buf->idx))) - return DRM_ERR(EFAULT); + return -EFAULT; if (DRM_COPY_TO_USER(&d->request_sizes[i], &buf->total, sizeof(buf->total))) - return DRM_ERR(EFAULT); + return -EFAULT; d->granted_count++; } return 0; } -int radeon_cp_buffers(DRM_IOCTL_ARGS) +int radeon_cp_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; struct drm_device_dma *dma = dev->dma; int ret = 0; - struct drm_dma __user *argp = (void __user *)data; - struct drm_dma d; + struct drm_dma *d = data; - LOCK_TEST_WITH_RETURN(dev, filp); - - DRM_COPY_FROM_USER_IOCTL(d, argp, sizeof(d)); + LOCK_TEST_WITH_RETURN(dev, file_priv); /* Please don't send us buffers. */ - if (d.send_count != 0) { + if (d->send_count != 0) { DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n", - DRM_CURRENTPID, d.send_count); - return DRM_ERR(EINVAL); + DRM_CURRENTPID, d->send_count); + return -EINVAL; } /* We'll send you buffers. */ - if (d.request_count < 0 || d.request_count > dma->buf_count) { + if (d->request_count < 0 || d->request_count > dma->buf_count) { DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n", - DRM_CURRENTPID, d.request_count, dma->buf_count); - return DRM_ERR(EINVAL); + DRM_CURRENTPID, d->request_count, dma->buf_count); + return -EINVAL; } - d.granted_count = 0; + d->granted_count = 0; - if (d.request_count) { - ret = radeon_cp_get_buffers(filp, dev, &d); + if (d->request_count) { + ret = radeon_cp_get_buffers(dev, file_priv, d); } - DRM_COPY_TO_USER_IOCTL(argp, d, sizeof(d)); - return ret; } @@ -2241,7 +2225,7 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) dev_priv = drm_alloc(sizeof(drm_radeon_private_t), DRM_MEM_DRIVER); if (dev_priv == NULL) - return DRM_ERR(ENOMEM); + return -ENOMEM; memset(dev_priv, 0, sizeof(drm_radeon_private_t)); dev->dev_private = (void *)dev_priv; diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h index 3b3d9357201c..e4077bc212b3 100644 --- a/drivers/char/drm/radeon_drv.h +++ b/drivers/char/drm/radeon_drv.h @@ -188,7 +188,7 @@ struct mem_block { struct mem_block *prev; int start; int size; - DRMFILE filp; /* 0: free, -1: heap, other: real files */ + struct drm_file *file_priv; /* NULL: free, -1: heap, other: real files */ }; struct radeon_surface { @@ -203,7 +203,7 @@ struct radeon_virt_surface { u32 lower; u32 upper; u32 flags; - DRMFILE filp; + struct drm_file *file_priv; }; typedef struct drm_radeon_private { @@ -307,7 +307,7 @@ typedef struct drm_radeon_kcmd_buffer { } drm_radeon_kcmd_buffer_t; extern int radeon_no_wb; -extern drm_ioctl_desc_t radeon_ioctls[]; +extern struct drm_ioctl_desc radeon_ioctls[]; extern int radeon_max_ioctl; /* Check whether the given hardware address is inside the framebuffer or the @@ -326,15 +326,15 @@ static __inline__ int radeon_check_offset(drm_radeon_private_t *dev_priv, } /* radeon_cp.c */ -extern int radeon_cp_init(DRM_IOCTL_ARGS); -extern int radeon_cp_start(DRM_IOCTL_ARGS); -extern int radeon_cp_stop(DRM_IOCTL_ARGS); -extern int radeon_cp_reset(DRM_IOCTL_ARGS); -extern int radeon_cp_idle(DRM_IOCTL_ARGS); -extern int radeon_cp_resume(DRM_IOCTL_ARGS); -extern int radeon_engine_reset(DRM_IOCTL_ARGS); -extern int radeon_fullscreen(DRM_IOCTL_ARGS); -extern int radeon_cp_buffers(DRM_IOCTL_ARGS); +extern int radeon_cp_init(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int radeon_cp_start(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int radeon_cp_stop(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int radeon_cp_reset(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int radeon_cp_idle(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int radeon_cp_resume(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int radeon_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int radeon_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int radeon_cp_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv); extern void radeon_freelist_reset(struct drm_device * dev); extern struct drm_buf *radeon_freelist_get(struct drm_device * dev); @@ -347,15 +347,16 @@ extern int radeon_driver_preinit(struct drm_device *dev, unsigned long flags); extern int radeon_presetup(struct drm_device *dev); extern int radeon_driver_postcleanup(struct drm_device *dev); -extern int radeon_mem_alloc(DRM_IOCTL_ARGS); -extern int radeon_mem_free(DRM_IOCTL_ARGS); -extern int radeon_mem_init_heap(DRM_IOCTL_ARGS); +extern int radeon_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int radeon_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int radeon_mem_init_heap(struct drm_device *dev, void *data, struct drm_file *file_priv); extern void radeon_mem_takedown(struct mem_block **heap); -extern void radeon_mem_release(DRMFILE filp, struct mem_block *heap); +extern void radeon_mem_release(struct drm_file *file_priv, + struct mem_block *heap); /* radeon_irq.c */ -extern int radeon_irq_emit(DRM_IOCTL_ARGS); -extern int radeon_irq_wait(DRM_IOCTL_ARGS); +extern int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv); extern void radeon_do_release(struct drm_device * dev); extern int radeon_driver_vblank_wait(struct drm_device * dev, @@ -372,7 +373,7 @@ extern int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value); extern int radeon_driver_load(struct drm_device *dev, unsigned long flags); extern int radeon_driver_unload(struct drm_device *dev); extern int radeon_driver_firstopen(struct drm_device *dev); -extern void radeon_driver_preclose(struct drm_device * dev, DRMFILE filp); +extern void radeon_driver_preclose(struct drm_device * dev, struct drm_file *file_priv); extern void radeon_driver_postclose(struct drm_device * dev, struct drm_file * filp); extern void radeon_driver_lastclose(struct drm_device * dev); extern int radeon_driver_open(struct drm_device * dev, struct drm_file * filp_priv); @@ -382,8 +383,8 @@ extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd, /* r300_cmdbuf.c */ extern void r300_init_reg_flags(void); -extern int r300_do_cp_cmdbuf(struct drm_device * dev, DRMFILE filp, - struct drm_file * filp_priv, +extern int r300_do_cp_cmdbuf(struct drm_device * dev, + struct drm_file *file_priv, drm_radeon_kcmd_buffer_t * cmdbuf); /* Flags for stats.boxes diff --git a/drivers/char/drm/radeon_irq.c b/drivers/char/drm/radeon_irq.c index ad8a0ac7182e..f89e57665b64 100644 --- a/drivers/char/drm/radeon_irq.c +++ b/drivers/char/drm/radeon_irq.c @@ -155,7 +155,7 @@ int radeon_driver_vblank_do_wait(struct drm_device * dev, unsigned int *sequence atomic_t *counter; if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); + return -EINVAL; } if (crtc == DRM_RADEON_VBLANK_CRTC1) { @@ -165,7 +165,7 @@ int radeon_driver_vblank_do_wait(struct drm_device * dev, unsigned int *sequence counter = &dev->vbl_received2; ack |= RADEON_CRTC2_VBLANK_STAT; } else - return DRM_ERR(EINVAL); + return -EINVAL; radeon_acknowledge_irqs(dev_priv, ack); @@ -196,28 +196,24 @@ int radeon_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence) /* Needs the lock as it touches the ring. */ -int radeon_irq_emit(DRM_IOCTL_ARGS) +int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; - drm_radeon_irq_emit_t emit; + drm_radeon_irq_emit_t *emit = data; int result; - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); + return -EINVAL; } - DRM_COPY_FROM_USER_IOCTL(emit, (drm_radeon_irq_emit_t __user *) data, - sizeof(emit)); - result = radeon_emit_irq(dev); - if (DRM_COPY_TO_USER(emit.irq_seq, &result, sizeof(int))) { + if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) { DRM_ERROR("copy_to_user\n"); - return DRM_ERR(EFAULT); + return -EFAULT; } return 0; @@ -225,21 +221,17 @@ int radeon_irq_emit(DRM_IOCTL_ARGS) /* Doesn't need the hardware lock. */ -int radeon_irq_wait(DRM_IOCTL_ARGS) +int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; - drm_radeon_irq_wait_t irqwait; + drm_radeon_irq_wait_t *irqwait = data; if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); + return -EINVAL; } - DRM_COPY_FROM_USER_IOCTL(irqwait, (drm_radeon_irq_wait_t __user *) data, - sizeof(irqwait)); - - return radeon_wait_irq(dev, irqwait.irq_seq); + return radeon_wait_irq(dev, irqwait->irq_seq); } static void radeon_enable_interrupt(struct drm_device *dev) @@ -320,7 +312,7 @@ int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value) drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; if (value & ~(DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) { DRM_ERROR("called with invalid crtc 0x%x\n", (unsigned int)value); - return DRM_ERR(EINVAL); + return -EINVAL; } dev_priv->vblank_crtc = (unsigned int)value; radeon_enable_interrupt(dev); diff --git a/drivers/char/drm/radeon_mem.c b/drivers/char/drm/radeon_mem.c index 517cad8b6e3a..a29acfe2f973 100644 --- a/drivers/char/drm/radeon_mem.c +++ b/drivers/char/drm/radeon_mem.c @@ -39,7 +39,7 @@ */ static struct mem_block *split_block(struct mem_block *p, int start, int size, - DRMFILE filp) + struct drm_file *file_priv) { /* Maybe cut off the start of an existing block */ if (start > p->start) { @@ -49,7 +49,7 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size, goto out; newblock->start = start; newblock->size = p->size - (start - p->start); - newblock->filp = NULL; + newblock->file_priv = NULL; newblock->next = p->next; newblock->prev = p; p->next->prev = newblock; @@ -66,7 +66,7 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size, goto out; newblock->start = start + size; newblock->size = p->size - size; - newblock->filp = NULL; + newblock->file_priv = NULL; newblock->next = p->next; newblock->prev = p; p->next->prev = newblock; @@ -76,20 +76,20 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size, out: /* Our block is in the middle */ - p->filp = filp; + p->file_priv = file_priv; return p; } static struct mem_block *alloc_block(struct mem_block *heap, int size, - int align2, DRMFILE filp) + int align2, struct drm_file *file_priv) { struct mem_block *p; int mask = (1 << align2) - 1; list_for_each(p, heap) { int start = (p->start + mask) & ~mask; - if (p->filp == 0 && start + size <= p->start + p->size) - return split_block(p, start, size, filp); + if (p->file_priv == 0 && start + size <= p->start + p->size) + return split_block(p, start, size, file_priv); } return NULL; @@ -108,12 +108,12 @@ static struct mem_block *find_block(struct mem_block *heap, int start) static void free_block(struct mem_block *p) { - p->filp = NULL; + p->file_priv = NULL; - /* Assumes a single contiguous range. Needs a special filp in + /* Assumes a single contiguous range. Needs a special file_priv in * 'heap' to stop it being subsumed. */ - if (p->next->filp == 0) { + if (p->next->file_priv == 0) { struct mem_block *q = p->next; p->size += q->size; p->next = q->next; @@ -121,7 +121,7 @@ static void free_block(struct mem_block *p) drm_free(q, sizeof(*q), DRM_MEM_BUFS); } - if (p->prev->filp == 0) { + if (p->prev->file_priv == 0) { struct mem_block *q = p->prev; q->size += p->size; q->next = p->next; @@ -137,28 +137,28 @@ static int init_heap(struct mem_block **heap, int start, int size) struct mem_block *blocks = drm_alloc(sizeof(*blocks), DRM_MEM_BUFS); if (!blocks) - return DRM_ERR(ENOMEM); + return -ENOMEM; *heap = drm_alloc(sizeof(**heap), DRM_MEM_BUFS); if (!*heap) { drm_free(blocks, sizeof(*blocks), DRM_MEM_BUFS); - return DRM_ERR(ENOMEM); + return -ENOMEM; } blocks->start = start; blocks->size = size; - blocks->filp = NULL; + blocks->file_priv = NULL; blocks->next = blocks->prev = *heap; memset(*heap, 0, sizeof(**heap)); - (*heap)->filp = (DRMFILE) - 1; + (*heap)->file_priv = (struct drm_file *) - 1; (*heap)->next = (*heap)->prev = blocks; return 0; } /* Free all blocks associated with the releasing file. */ -void radeon_mem_release(DRMFILE filp, struct mem_block *heap) +void radeon_mem_release(struct drm_file *file_priv, struct mem_block *heap) { struct mem_block *p; @@ -166,15 +166,15 @@ void radeon_mem_release(DRMFILE filp, struct mem_block *heap) return; list_for_each(p, heap) { - if (p->filp == filp) - p->filp = NULL; + if (p->file_priv == file_priv) + p->file_priv = NULL; } - /* Assumes a single contiguous range. Needs a special filp in + /* Assumes a single contiguous range. Needs a special file_priv in * 'heap' to stop it being subsumed. */ list_for_each(p, heap) { - while (p->filp == 0 && p->next->filp == 0) { + while (p->file_priv == 0 && p->next->file_priv == 0) { struct mem_block *q = p->next; p->size += q->size; p->next = q->next; @@ -217,98 +217,86 @@ static struct mem_block **get_heap(drm_radeon_private_t * dev_priv, int region) } } -int radeon_mem_alloc(DRM_IOCTL_ARGS) +int radeon_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; - drm_radeon_mem_alloc_t alloc; + drm_radeon_mem_alloc_t *alloc = data; struct mem_block *block, **heap; if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); + return -EINVAL; } - DRM_COPY_FROM_USER_IOCTL(alloc, (drm_radeon_mem_alloc_t __user *) data, - sizeof(alloc)); - - heap = get_heap(dev_priv, alloc.region); + heap = get_heap(dev_priv, alloc->region); if (!heap || !*heap) - return DRM_ERR(EFAULT); + return -EFAULT; /* Make things easier on ourselves: all allocations at least * 4k aligned. */ - if (alloc.alignment < 12) - alloc.alignment = 12; + if (alloc->alignment < 12) + alloc->alignment = 12; - block = alloc_block(*heap, alloc.size, alloc.alignment, filp); + block = alloc_block(*heap, alloc->size, alloc->alignment, file_priv); if (!block) - return DRM_ERR(ENOMEM); + return -ENOMEM; - if (DRM_COPY_TO_USER(alloc.region_offset, &block->start, sizeof(int))) { + if (DRM_COPY_TO_USER(alloc->region_offset, &block->start, + sizeof(int))) { DRM_ERROR("copy_to_user\n"); - return DRM_ERR(EFAULT); + return -EFAULT; } return 0; } -int radeon_mem_free(DRM_IOCTL_ARGS) +int radeon_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; - drm_radeon_mem_free_t memfree; + drm_radeon_mem_free_t *memfree = data; struct mem_block *block, **heap; if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); + return -EINVAL; } - DRM_COPY_FROM_USER_IOCTL(memfree, (drm_radeon_mem_free_t __user *) data, - sizeof(memfree)); - - heap = get_heap(dev_priv, memfree.region); + heap = get_heap(dev_priv, memfree->region); if (!heap || !*heap) - return DRM_ERR(EFAULT); + return -EFAULT; - block = find_block(*heap, memfree.region_offset); + block = find_block(*heap, memfree->region_offset); if (!block) - return DRM_ERR(EFAULT); + return -EFAULT; - if (block->filp != filp) - return DRM_ERR(EPERM); + if (block->file_priv != file_priv) + return -EPERM; free_block(block); return 0; } -int radeon_mem_init_heap(DRM_IOCTL_ARGS) +int radeon_mem_init_heap(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; - drm_radeon_mem_init_heap_t initheap; + drm_radeon_mem_init_heap_t *initheap = data; struct mem_block **heap; if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); + return -EINVAL; } - DRM_COPY_FROM_USER_IOCTL(initheap, - (drm_radeon_mem_init_heap_t __user *) data, - sizeof(initheap)); - - heap = get_heap(dev_priv, initheap.region); + heap = get_heap(dev_priv, initheap->region); if (!heap) - return DRM_ERR(EFAULT); + return -EFAULT; if (*heap) { DRM_ERROR("heap already initialized?"); - return DRM_ERR(EFAULT); + return -EFAULT; } - return init_heap(heap, initheap.start, initheap.size); + return init_heap(heap, initheap->start, initheap->size); } diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c index 3ddf86f2abf0..69c9f2febf43 100644 --- a/drivers/char/drm/radeon_state.c +++ b/drivers/char/drm/radeon_state.c @@ -39,7 +39,7 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t * dev_priv, - struct drm_file * filp_priv, + struct drm_file * file_priv, u32 *offset) { u64 off = *offset; @@ -71,7 +71,7 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t * * magic offset we get from SETPARAM or calculated from fb_location */ if (off < (dev_priv->fb_size + dev_priv->gart_size)) { - radeon_priv = filp_priv->driver_priv; + radeon_priv = file_priv->driver_priv; off += radeon_priv->radeon_fb_delta; } @@ -85,29 +85,29 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t * *offset = off; return 0; } - return DRM_ERR(EINVAL); + return -EINVAL; } static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t * dev_priv, - struct drm_file * filp_priv, + struct drm_file *file_priv, int id, u32 *data) { switch (id) { case RADEON_EMIT_PP_MISC: - if (radeon_check_and_fixup_offset(dev_priv, filp_priv, + if (radeon_check_and_fixup_offset(dev_priv, file_priv, &data[(RADEON_RB3D_DEPTHOFFSET - RADEON_PP_MISC) / 4])) { DRM_ERROR("Invalid depth buffer offset\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } break; case RADEON_EMIT_PP_CNTL: - if (radeon_check_and_fixup_offset(dev_priv, filp_priv, + if (radeon_check_and_fixup_offset(dev_priv, file_priv, &data[(RADEON_RB3D_COLOROFFSET - RADEON_PP_CNTL) / 4])) { DRM_ERROR("Invalid colour buffer offset\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } break; @@ -117,20 +117,20 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t * case R200_EMIT_PP_TXOFFSET_3: case R200_EMIT_PP_TXOFFSET_4: case R200_EMIT_PP_TXOFFSET_5: - if (radeon_check_and_fixup_offset(dev_priv, filp_priv, + if (radeon_check_and_fixup_offset(dev_priv, file_priv, &data[0])) { DRM_ERROR("Invalid R200 texture offset\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } break; case RADEON_EMIT_PP_TXFILTER_0: case RADEON_EMIT_PP_TXFILTER_1: case RADEON_EMIT_PP_TXFILTER_2: - if (radeon_check_and_fixup_offset(dev_priv, filp_priv, + if (radeon_check_and_fixup_offset(dev_priv, file_priv, &data[(RADEON_PP_TXOFFSET_0 - RADEON_PP_TXFILTER_0) / 4])) { DRM_ERROR("Invalid R100 texture offset\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } break; @@ -143,11 +143,11 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t * int i; for (i = 0; i < 5; i++) { if (radeon_check_and_fixup_offset(dev_priv, - filp_priv, + file_priv, &data[i])) { DRM_ERROR ("Invalid R200 cubic texture offset\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } } break; @@ -159,11 +159,11 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t * int i; for (i = 0; i < 5; i++) { if (radeon_check_and_fixup_offset(dev_priv, - filp_priv, + file_priv, &data[i])) { DRM_ERROR ("Invalid R100 cubic texture offset\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } } } @@ -256,7 +256,7 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t * default: DRM_ERROR("Unknown state packet ID %d\n", id); - return DRM_ERR(EINVAL); + return -EINVAL; } return 0; @@ -264,7 +264,7 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t * static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * dev_priv, - struct drm_file *filp_priv, + struct drm_file *file_priv, drm_radeon_kcmd_buffer_t * cmdbuf, unsigned int *cmdsz) @@ -277,12 +277,12 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * if ((cmd[0] & 0xc0000000) != RADEON_CP_PACKET3) { DRM_ERROR("Not a type 3 packet\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } if (4 * *cmdsz > cmdbuf->bufsz) { DRM_ERROR("Packet size larger than size of data provided\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } switch(cmd[0] & 0xff00) { @@ -307,7 +307,7 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * /* safe but r200 only */ if (dev_priv->microcode_version != UCODE_R200) { DRM_ERROR("Invalid 3d packet for r100-class chip\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } break; @@ -317,7 +317,7 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * if (count > 18) { /* 12 arrays max */ DRM_ERROR("Too large payload in 3D_LOAD_VBPNTR (count=%d)\n", count); - return DRM_ERR(EINVAL); + return -EINVAL; } /* carefully check packet contents */ @@ -326,22 +326,25 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * i = 2; while ((k < narrays) && (i < (count + 2))) { i++; /* skip attribute field */ - if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[i])) { + if (radeon_check_and_fixup_offset(dev_priv, file_priv, + &cmd[i])) { DRM_ERROR ("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n", k, i); - return DRM_ERR(EINVAL); + return -EINVAL; } k++; i++; if (k == narrays) break; /* have one more to process, they come in pairs */ - if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[i])) { + if (radeon_check_and_fixup_offset(dev_priv, + file_priv, &cmd[i])) + { DRM_ERROR ("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n", k, i); - return DRM_ERR(EINVAL); + return -EINVAL; } k++; i++; @@ -351,33 +354,33 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * DRM_ERROR ("Malformed 3D_LOAD_VBPNTR packet (k=%d i=%d narrays=%d count+1=%d).\n", k, i, narrays, count + 1); - return DRM_ERR(EINVAL); + return -EINVAL; } break; case RADEON_3D_RNDR_GEN_INDX_PRIM: if (dev_priv->microcode_version != UCODE_R100) { DRM_ERROR("Invalid 3d packet for r200-class chip\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } - if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[1])) { + if (radeon_check_and_fixup_offset(dev_priv, file_priv, &cmd[1])) { DRM_ERROR("Invalid rndr_gen_indx offset\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } break; case RADEON_CP_INDX_BUFFER: if (dev_priv->microcode_version != UCODE_R200) { DRM_ERROR("Invalid 3d packet for r100-class chip\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } if ((cmd[1] & 0x8000ffff) != 0x80000810) { DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]); - return DRM_ERR(EINVAL); + return -EINVAL; } - if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[2])) { + if (radeon_check_and_fixup_offset(dev_priv, file_priv, &cmd[2])) { DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]); - return DRM_ERR(EINVAL); + return -EINVAL; } break; @@ -389,9 +392,9 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * | RADEON_GMC_DST_PITCH_OFFSET_CNTL)) { offset = cmd[2] << 10; if (radeon_check_and_fixup_offset - (dev_priv, filp_priv, &offset)) { + (dev_priv, file_priv, &offset)) { DRM_ERROR("Invalid first packet offset\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } cmd[2] = (cmd[2] & 0xffc00000) | offset >> 10; } @@ -400,9 +403,9 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * (cmd[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) { offset = cmd[3] << 10; if (radeon_check_and_fixup_offset - (dev_priv, filp_priv, &offset)) { + (dev_priv, file_priv, &offset)) { DRM_ERROR("Invalid second packet offset\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } cmd[3] = (cmd[3] & 0xffc00000) | offset >> 10; } @@ -410,7 +413,7 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * default: DRM_ERROR("Invalid packet type %x\n", cmd[0] & 0xff00); - return DRM_ERR(EINVAL); + return -EINVAL; } return 0; @@ -439,7 +442,7 @@ static __inline__ void radeon_emit_clip_rect(drm_radeon_private_t * dev_priv, /* Emit 1.1 state */ static int radeon_emit_state(drm_radeon_private_t * dev_priv, - struct drm_file * filp_priv, + struct drm_file *file_priv, drm_radeon_context_regs_t * ctx, drm_radeon_texture_regs_t * tex, unsigned int dirty) @@ -448,16 +451,16 @@ static int radeon_emit_state(drm_radeon_private_t * dev_priv, DRM_DEBUG("dirty=0x%08x\n", dirty); if (dirty & RADEON_UPLOAD_CONTEXT) { - if (radeon_check_and_fixup_offset(dev_priv, filp_priv, + if (radeon_check_and_fixup_offset(dev_priv, file_priv, &ctx->rb3d_depthoffset)) { DRM_ERROR("Invalid depth buffer offset\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } - if (radeon_check_and_fixup_offset(dev_priv, filp_priv, + if (radeon_check_and_fixup_offset(dev_priv, file_priv, &ctx->rb3d_coloroffset)) { DRM_ERROR("Invalid depth buffer offset\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } BEGIN_RING(14); @@ -543,10 +546,10 @@ static int radeon_emit_state(drm_radeon_private_t * dev_priv, } if (dirty & RADEON_UPLOAD_TEX0) { - if (radeon_check_and_fixup_offset(dev_priv, filp_priv, + if (radeon_check_and_fixup_offset(dev_priv, file_priv, &tex[0].pp_txoffset)) { DRM_ERROR("Invalid texture offset for unit 0\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } BEGIN_RING(9); @@ -563,10 +566,10 @@ static int radeon_emit_state(drm_radeon_private_t * dev_priv, } if (dirty & RADEON_UPLOAD_TEX1) { - if (radeon_check_and_fixup_offset(dev_priv, filp_priv, + if (radeon_check_and_fixup_offset(dev_priv, file_priv, &tex[1].pp_txoffset)) { DRM_ERROR("Invalid texture offset for unit 1\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } BEGIN_RING(9); @@ -583,10 +586,10 @@ static int radeon_emit_state(drm_radeon_private_t * dev_priv, } if (dirty & RADEON_UPLOAD_TEX2) { - if (radeon_check_and_fixup_offset(dev_priv, filp_priv, + if (radeon_check_and_fixup_offset(dev_priv, file_priv, &tex[2].pp_txoffset)) { DRM_ERROR("Invalid texture offset for unit 2\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } BEGIN_RING(9); @@ -608,7 +611,7 @@ static int radeon_emit_state(drm_radeon_private_t * dev_priv, /* Emit 1.2 state */ static int radeon_emit_state2(drm_radeon_private_t * dev_priv, - struct drm_file * filp_priv, + struct drm_file *file_priv, drm_radeon_state_t * state) { RING_LOCALS; @@ -621,7 +624,7 @@ static int radeon_emit_state2(drm_radeon_private_t * dev_priv, ADVANCE_RING(); } - return radeon_emit_state(dev_priv, filp_priv, &state->context, + return radeon_emit_state(dev_priv, file_priv, &state->context, state->tex, state->dirty); } @@ -1646,13 +1649,12 @@ static void radeon_cp_dispatch_indices(struct drm_device * dev, #define RADEON_MAX_TEXTURE_SIZE RADEON_BUFFER_SIZE -static int radeon_cp_dispatch_texture(DRMFILE filp, - struct drm_device * dev, +static int radeon_cp_dispatch_texture(struct drm_device * dev, + struct drm_file *file_priv, drm_radeon_texture_t * tex, drm_radeon_tex_image_t * image) { drm_radeon_private_t *dev_priv = dev->dev_private; - struct drm_file *filp_priv; struct drm_buf *buf; u32 format; u32 *buffer; @@ -1664,11 +1666,9 @@ static int radeon_cp_dispatch_texture(DRMFILE filp, u32 offset; RING_LOCALS; - DRM_GET_PRIV_WITH_RETURN(filp_priv, filp); - - if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &tex->offset)) { + if (radeon_check_and_fixup_offset(dev_priv, file_priv, &tex->offset)) { DRM_ERROR("Invalid destination offset\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } dev_priv->stats.boxes |= RADEON_BOX_TEXTURE_LOAD; @@ -1711,11 +1711,11 @@ static int radeon_cp_dispatch_texture(DRMFILE filp, break; default: DRM_ERROR("invalid texture format %d\n", tex->format); - return DRM_ERR(EINVAL); + return -EINVAL; } spitch = blit_width >> 6; if (spitch == 0 && image->height > 1) - return DRM_ERR(EINVAL); + return -EINVAL; texpitch = tex->pitch; if ((texpitch << 22) & RADEON_DST_TILE_MICRO) { @@ -1760,8 +1760,8 @@ static int radeon_cp_dispatch_texture(DRMFILE filp, if (!buf) { DRM_DEBUG("radeon_cp_dispatch_texture: EAGAIN\n"); if (DRM_COPY_TO_USER(tex->image, image, sizeof(*image))) - return DRM_ERR(EFAULT); - return DRM_ERR(EAGAIN); + return -EFAULT; + return -EAGAIN; } /* Dispatch the indirect buffer. @@ -1774,7 +1774,7 @@ static int radeon_cp_dispatch_texture(DRMFILE filp, do { \ if (DRM_COPY_FROM_USER(_buf, _data, (_width))) {\ DRM_ERROR("EFAULT on pad, %d bytes\n", (_width)); \ - return DRM_ERR(EFAULT); \ + return -EFAULT; \ } \ } while(0) @@ -1841,7 +1841,7 @@ static int radeon_cp_dispatch_texture(DRMFILE filp, } #undef RADEON_COPY_MT - buf->filp = filp; + buf->file_priv = file_priv; buf->used = size; offset = dev_priv->gart_buffers_offset + buf->offset; BEGIN_RING(9); @@ -1861,6 +1861,7 @@ static int radeon_cp_dispatch_texture(DRMFILE filp, OUT_RING((image->width << 16) | height); RADEON_WAIT_UNTIL_2D_IDLE(); ADVANCE_RING(); + COMMIT_RING(); radeon_cp_discard_buffer(dev, buf); @@ -1878,6 +1879,8 @@ static int radeon_cp_dispatch_texture(DRMFILE filp, RADEON_FLUSH_CACHE(); RADEON_WAIT_UNTIL_2D_IDLE(); ADVANCE_RING(); + COMMIT_RING(); + return 0; } @@ -1929,7 +1932,8 @@ static void radeon_apply_surface_regs(int surf_index, * not always be available. */ static int alloc_surface(drm_radeon_surface_alloc_t *new, - drm_radeon_private_t *dev_priv, DRMFILE filp) + drm_radeon_private_t *dev_priv, + struct drm_file *file_priv) { struct radeon_virt_surface *s; int i; @@ -1959,7 +1963,7 @@ static int alloc_surface(drm_radeon_surface_alloc_t *new, /* find a virtual surface */ for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) - if (dev_priv->virt_surfaces[i].filp == 0) + if (dev_priv->virt_surfaces[i].file_priv == 0) break; if (i == 2 * RADEON_MAX_SURFACES) { return -1; @@ -1977,7 +1981,7 @@ static int alloc_surface(drm_radeon_surface_alloc_t *new, s->lower = new_lower; s->upper = new_upper; s->flags = new->flags; - s->filp = filp; + s->file_priv = file_priv; dev_priv->surfaces[i].refcount++; dev_priv->surfaces[i].lower = s->lower; radeon_apply_surface_regs(s->surface_index, dev_priv); @@ -1993,7 +1997,7 @@ static int alloc_surface(drm_radeon_surface_alloc_t *new, s->lower = new_lower; s->upper = new_upper; s->flags = new->flags; - s->filp = filp; + s->file_priv = file_priv; dev_priv->surfaces[i].refcount++; dev_priv->surfaces[i].upper = s->upper; radeon_apply_surface_regs(s->surface_index, dev_priv); @@ -2009,7 +2013,7 @@ static int alloc_surface(drm_radeon_surface_alloc_t *new, s->lower = new_lower; s->upper = new_upper; s->flags = new->flags; - s->filp = filp; + s->file_priv = file_priv; dev_priv->surfaces[i].refcount = 1; dev_priv->surfaces[i].lower = s->lower; dev_priv->surfaces[i].upper = s->upper; @@ -2023,7 +2027,8 @@ static int alloc_surface(drm_radeon_surface_alloc_t *new, return -1; } -static int free_surface(DRMFILE filp, drm_radeon_private_t * dev_priv, +static int free_surface(struct drm_file *file_priv, + drm_radeon_private_t * dev_priv, int lower) { struct radeon_virt_surface *s; @@ -2031,8 +2036,9 @@ static int free_surface(DRMFILE filp, drm_radeon_private_t * dev_priv, /* find the virtual surface */ for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) { s = &(dev_priv->virt_surfaces[i]); - if (s->filp) { - if ((lower == s->lower) && (filp == s->filp)) { + if (s->file_priv) { + if ((lower == s->lower) && (file_priv == s->file_priv)) + { if (dev_priv->surfaces[s->surface_index]. lower == s->lower) dev_priv->surfaces[s->surface_index]. @@ -2048,7 +2054,7 @@ static int free_surface(DRMFILE filp, drm_radeon_private_t * dev_priv, refcount == 0) dev_priv->surfaces[s->surface_index]. flags = 0; - s->filp = NULL; + s->file_priv = NULL; radeon_apply_surface_regs(s->surface_index, dev_priv); return 0; @@ -2058,13 +2064,13 @@ static int free_surface(DRMFILE filp, drm_radeon_private_t * dev_priv, return 1; } -static void radeon_surfaces_release(DRMFILE filp, +static void radeon_surfaces_release(struct drm_file *file_priv, drm_radeon_private_t * dev_priv) { int i; for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) { - if (dev_priv->virt_surfaces[i].filp == filp) - free_surface(filp, dev_priv, + if (dev_priv->virt_surfaces[i].file_priv == file_priv) + free_surface(file_priv, dev_priv, dev_priv->virt_surfaces[i].lower); } } @@ -2072,61 +2078,48 @@ static void radeon_surfaces_release(DRMFILE filp, /* ================================================================ * IOCTL functions */ -static int radeon_surface_alloc(DRM_IOCTL_ARGS) +static int radeon_surface_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; - drm_radeon_surface_alloc_t alloc; + drm_radeon_surface_alloc_t *alloc = data; - DRM_COPY_FROM_USER_IOCTL(alloc, - (drm_radeon_surface_alloc_t __user *) data, - sizeof(alloc)); - - if (alloc_surface(&alloc, dev_priv, filp) == -1) - return DRM_ERR(EINVAL); + if (alloc_surface(alloc, dev_priv, file_priv) == -1) + return -EINVAL; else return 0; } -static int radeon_surface_free(DRM_IOCTL_ARGS) +static int radeon_surface_free(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; - drm_radeon_surface_free_t memfree; - - DRM_COPY_FROM_USER_IOCTL(memfree, (drm_radeon_surface_free_t __user *) data, - sizeof(memfree)); + drm_radeon_surface_free_t *memfree = data; - if (free_surface(filp, dev_priv, memfree.address)) - return DRM_ERR(EINVAL); + if (free_surface(file_priv, dev_priv, memfree->address)) + return -EINVAL; else return 0; } -static int radeon_cp_clear(DRM_IOCTL_ARGS) +static int radeon_cp_clear(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; - drm_radeon_clear_t clear; + drm_radeon_clear_t *clear = data; drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS]; DRM_DEBUG("\n"); - LOCK_TEST_WITH_RETURN(dev, filp); - - DRM_COPY_FROM_USER_IOCTL(clear, (drm_radeon_clear_t __user *) data, - sizeof(clear)); + LOCK_TEST_WITH_RETURN(dev, file_priv); RING_SPACE_TEST_WITH_RETURN(dev_priv); if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS) sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS; - if (DRM_COPY_FROM_USER(&depth_boxes, clear.depth_boxes, + if (DRM_COPY_FROM_USER(&depth_boxes, clear->depth_boxes, sarea_priv->nbox * sizeof(depth_boxes[0]))) - return DRM_ERR(EFAULT); + return -EFAULT; - radeon_cp_dispatch_clear(dev, &clear, depth_boxes); + radeon_cp_dispatch_clear(dev, clear, depth_boxes); COMMIT_RING(); return 0; @@ -2162,13 +2155,12 @@ static int radeon_do_init_pageflip(struct drm_device * dev) /* Swapping and flipping are different operations, need different ioctls. * They can & should be intermixed to support multiple 3d windows. */ -static int radeon_cp_flip(DRM_IOCTL_ARGS) +static int radeon_cp_flip(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; DRM_DEBUG("\n"); - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); RING_SPACE_TEST_WITH_RETURN(dev_priv); @@ -2181,14 +2173,13 @@ static int radeon_cp_flip(DRM_IOCTL_ARGS) return 0; } -static int radeon_cp_swap(DRM_IOCTL_ARGS) +static int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; DRM_DEBUG("\n"); - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); RING_SPACE_TEST_WITH_RETURN(dev_priv); @@ -2202,64 +2193,57 @@ static int radeon_cp_swap(DRM_IOCTL_ARGS) return 0; } -static int radeon_cp_vertex(DRM_IOCTL_ARGS) +static int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; - struct drm_file *filp_priv; drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; struct drm_device_dma *dma = dev->dma; struct drm_buf *buf; - drm_radeon_vertex_t vertex; + drm_radeon_vertex_t *vertex = data; drm_radeon_tcl_prim_t prim; - LOCK_TEST_WITH_RETURN(dev, filp); - - DRM_GET_PRIV_WITH_RETURN(filp_priv, filp); - - DRM_COPY_FROM_USER_IOCTL(vertex, (drm_radeon_vertex_t __user *) data, - sizeof(vertex)); + LOCK_TEST_WITH_RETURN(dev, file_priv); DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n", - DRM_CURRENTPID, vertex.idx, vertex.count, vertex.discard); + DRM_CURRENTPID, vertex->idx, vertex->count, vertex->discard); - if (vertex.idx < 0 || vertex.idx >= dma->buf_count) { + if (vertex->idx < 0 || vertex->idx >= dma->buf_count) { DRM_ERROR("buffer index %d (of %d max)\n", - vertex.idx, dma->buf_count - 1); - return DRM_ERR(EINVAL); + vertex->idx, dma->buf_count - 1); + return -EINVAL; } - if (vertex.prim < 0 || vertex.prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) { - DRM_ERROR("buffer prim %d\n", vertex.prim); - return DRM_ERR(EINVAL); + if (vertex->prim < 0 || vertex->prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) { + DRM_ERROR("buffer prim %d\n", vertex->prim); + return -EINVAL; } RING_SPACE_TEST_WITH_RETURN(dev_priv); VB_AGE_TEST_WITH_RETURN(dev_priv); - buf = dma->buflist[vertex.idx]; + buf = dma->buflist[vertex->idx]; - if (buf->filp != filp) { + if (buf->file_priv != file_priv) { DRM_ERROR("process %d using buffer owned by %p\n", - DRM_CURRENTPID, buf->filp); - return DRM_ERR(EINVAL); + DRM_CURRENTPID, buf->file_priv); + return -EINVAL; } if (buf->pending) { - DRM_ERROR("sending pending buffer %d\n", vertex.idx); - return DRM_ERR(EINVAL); + DRM_ERROR("sending pending buffer %d\n", vertex->idx); + return -EINVAL; } /* Build up a prim_t record: */ - if (vertex.count) { - buf->used = vertex.count; /* not used? */ + if (vertex->count) { + buf->used = vertex->count; /* not used? */ if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) { - if (radeon_emit_state(dev_priv, filp_priv, + if (radeon_emit_state(dev_priv, file_priv, &sarea_priv->context_state, sarea_priv->tex_state, sarea_priv->dirty)) { DRM_ERROR("radeon_emit_state failed\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES | @@ -2269,15 +2253,15 @@ static int radeon_cp_vertex(DRM_IOCTL_ARGS) } prim.start = 0; - prim.finish = vertex.count; /* unused */ - prim.prim = vertex.prim; - prim.numverts = vertex.count; + prim.finish = vertex->count; /* unused */ + prim.prim = vertex->prim; + prim.numverts = vertex->count; prim.vc_format = dev_priv->sarea_priv->vc_format; radeon_cp_dispatch_vertex(dev, buf, &prim); } - if (vertex.discard) { + if (vertex->discard) { radeon_cp_discard_buffer(dev, buf); } @@ -2285,74 +2269,68 @@ static int radeon_cp_vertex(DRM_IOCTL_ARGS) return 0; } -static int radeon_cp_indices(DRM_IOCTL_ARGS) +static int radeon_cp_indices(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; - struct drm_file *filp_priv; drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; struct drm_device_dma *dma = dev->dma; struct drm_buf *buf; - drm_radeon_indices_t elts; + drm_radeon_indices_t *elts = data; drm_radeon_tcl_prim_t prim; int count; - LOCK_TEST_WITH_RETURN(dev, filp); - - DRM_GET_PRIV_WITH_RETURN(filp_priv, filp); - - DRM_COPY_FROM_USER_IOCTL(elts, (drm_radeon_indices_t __user *) data, - sizeof(elts)); + LOCK_TEST_WITH_RETURN(dev, file_priv); DRM_DEBUG("pid=%d index=%d start=%d end=%d discard=%d\n", - DRM_CURRENTPID, elts.idx, elts.start, elts.end, elts.discard); + DRM_CURRENTPID, elts->idx, elts->start, elts->end, + elts->discard); - if (elts.idx < 0 || elts.idx >= dma->buf_count) { + if (elts->idx < 0 || elts->idx >= dma->buf_count) { DRM_ERROR("buffer index %d (of %d max)\n", - elts.idx, dma->buf_count - 1); - return DRM_ERR(EINVAL); + elts->idx, dma->buf_count - 1); + return -EINVAL; } - if (elts.prim < 0 || elts.prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) { - DRM_ERROR("buffer prim %d\n", elts.prim); - return DRM_ERR(EINVAL); + if (elts->prim < 0 || elts->prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) { + DRM_ERROR("buffer prim %d\n", elts->prim); + return -EINVAL; } RING_SPACE_TEST_WITH_RETURN(dev_priv); VB_AGE_TEST_WITH_RETURN(dev_priv); - buf = dma->buflist[elts.idx]; + buf = dma->buflist[elts->idx]; - if (buf->filp != filp) { + if (buf->file_priv != file_priv) { DRM_ERROR("process %d using buffer owned by %p\n", - DRM_CURRENTPID, buf->filp); - return DRM_ERR(EINVAL); + DRM_CURRENTPID, buf->file_priv); + return -EINVAL; } if (buf->pending) { - DRM_ERROR("sending pending buffer %d\n", elts.idx); - return DRM_ERR(EINVAL); + DRM_ERROR("sending pending buffer %d\n", elts->idx); + return -EINVAL; } - count = (elts.end - elts.start) / sizeof(u16); - elts.start -= RADEON_INDEX_PRIM_OFFSET; + count = (elts->end - elts->start) / sizeof(u16); + elts->start -= RADEON_INDEX_PRIM_OFFSET; - if (elts.start & 0x7) { - DRM_ERROR("misaligned buffer 0x%x\n", elts.start); - return DRM_ERR(EINVAL); + if (elts->start & 0x7) { + DRM_ERROR("misaligned buffer 0x%x\n", elts->start); + return -EINVAL; } - if (elts.start < buf->used) { - DRM_ERROR("no header 0x%x - 0x%x\n", elts.start, buf->used); - return DRM_ERR(EINVAL); + if (elts->start < buf->used) { + DRM_ERROR("no header 0x%x - 0x%x\n", elts->start, buf->used); + return -EINVAL; } - buf->used = elts.end; + buf->used = elts->end; if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) { - if (radeon_emit_state(dev_priv, filp_priv, + if (radeon_emit_state(dev_priv, file_priv, &sarea_priv->context_state, sarea_priv->tex_state, sarea_priv->dirty)) { DRM_ERROR("radeon_emit_state failed\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES | @@ -2363,15 +2341,15 @@ static int radeon_cp_indices(DRM_IOCTL_ARGS) /* Build up a prim_t record: */ - prim.start = elts.start; - prim.finish = elts.end; - prim.prim = elts.prim; + prim.start = elts->start; + prim.finish = elts->end; + prim.prim = elts->prim; prim.offset = 0; /* offset from start of dma buffers */ prim.numverts = RADEON_MAX_VB_VERTS; /* duh */ prim.vc_format = dev_priv->sarea_priv->vc_format; radeon_cp_dispatch_indices(dev, buf, &prim); - if (elts.discard) { + if (elts->discard) { radeon_cp_discard_buffer(dev, buf); } @@ -2379,52 +2357,43 @@ static int radeon_cp_indices(DRM_IOCTL_ARGS) return 0; } -static int radeon_cp_texture(DRM_IOCTL_ARGS) +static int radeon_cp_texture(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; - drm_radeon_texture_t tex; + drm_radeon_texture_t *tex = data; drm_radeon_tex_image_t image; int ret; - LOCK_TEST_WITH_RETURN(dev, filp); - - DRM_COPY_FROM_USER_IOCTL(tex, (drm_radeon_texture_t __user *) data, - sizeof(tex)); + LOCK_TEST_WITH_RETURN(dev, file_priv); - if (tex.image == NULL) { + if (tex->image == NULL) { DRM_ERROR("null texture image!\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } if (DRM_COPY_FROM_USER(&image, - (drm_radeon_tex_image_t __user *) tex.image, + (drm_radeon_tex_image_t __user *) tex->image, sizeof(image))) - return DRM_ERR(EFAULT); + return -EFAULT; RING_SPACE_TEST_WITH_RETURN(dev_priv); VB_AGE_TEST_WITH_RETURN(dev_priv); - ret = radeon_cp_dispatch_texture(filp, dev, &tex, &image); + ret = radeon_cp_dispatch_texture(dev, file_priv, tex, &image); - COMMIT_RING(); return ret; } -static int radeon_cp_stipple(DRM_IOCTL_ARGS) +static int radeon_cp_stipple(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; - drm_radeon_stipple_t stipple; + drm_radeon_stipple_t *stipple = data; u32 mask[32]; - LOCK_TEST_WITH_RETURN(dev, filp); - - DRM_COPY_FROM_USER_IOCTL(stipple, (drm_radeon_stipple_t __user *) data, - sizeof(stipple)); + LOCK_TEST_WITH_RETURN(dev, file_priv); - if (DRM_COPY_FROM_USER(&mask, stipple.mask, 32 * sizeof(u32))) - return DRM_ERR(EFAULT); + if (DRM_COPY_FROM_USER(&mask, stipple->mask, 32 * sizeof(u32))) + return -EFAULT; RING_SPACE_TEST_WITH_RETURN(dev_priv); @@ -2434,52 +2403,48 @@ static int radeon_cp_stipple(DRM_IOCTL_ARGS) return 0; } -static int radeon_cp_indirect(DRM_IOCTL_ARGS) +static int radeon_cp_indirect(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; struct drm_device_dma *dma = dev->dma; struct drm_buf *buf; - drm_radeon_indirect_t indirect; + drm_radeon_indirect_t *indirect = data; RING_LOCALS; - LOCK_TEST_WITH_RETURN(dev, filp); - - DRM_COPY_FROM_USER_IOCTL(indirect, - (drm_radeon_indirect_t __user *) data, - sizeof(indirect)); + LOCK_TEST_WITH_RETURN(dev, file_priv); DRM_DEBUG("indirect: idx=%d s=%d e=%d d=%d\n", - indirect.idx, indirect.start, indirect.end, indirect.discard); + indirect->idx, indirect->start, indirect->end, + indirect->discard); - if (indirect.idx < 0 || indirect.idx >= dma->buf_count) { + if (indirect->idx < 0 || indirect->idx >= dma->buf_count) { DRM_ERROR("buffer index %d (of %d max)\n", - indirect.idx, dma->buf_count - 1); - return DRM_ERR(EINVAL); + indirect->idx, dma->buf_count - 1); + return -EINVAL; } - buf = dma->buflist[indirect.idx]; + buf = dma->buflist[indirect->idx]; - if (buf->filp != filp) { + if (buf->file_priv != file_priv) { DRM_ERROR("process %d using buffer owned by %p\n", - DRM_CURRENTPID, buf->filp); - return DRM_ERR(EINVAL); + DRM_CURRENTPID, buf->file_priv); + return -EINVAL; } if (buf->pending) { - DRM_ERROR("sending pending buffer %d\n", indirect.idx); - return DRM_ERR(EINVAL); + DRM_ERROR("sending pending buffer %d\n", indirect->idx); + return -EINVAL; } - if (indirect.start < buf->used) { + if (indirect->start < buf->used) { DRM_ERROR("reusing indirect: start=0x%x actual=0x%x\n", - indirect.start, buf->used); - return DRM_ERR(EINVAL); + indirect->start, buf->used); + return -EINVAL; } RING_SPACE_TEST_WITH_RETURN(dev_priv); VB_AGE_TEST_WITH_RETURN(dev_priv); - buf->used = indirect.end; + buf->used = indirect->end; /* Wait for the 3D stream to idle before the indirect buffer * containing 2D acceleration commands is processed. @@ -2494,8 +2459,8 @@ static int radeon_cp_indirect(DRM_IOCTL_ARGS) * X server. This is insecure and is thus only available to * privileged clients. */ - radeon_cp_dispatch_indirect(dev, buf, indirect.start, indirect.end); - if (indirect.discard) { + radeon_cp_dispatch_indirect(dev, buf, indirect->start, indirect->end); + if (indirect->discard) { radeon_cp_discard_buffer(dev, buf); } @@ -2503,71 +2468,64 @@ static int radeon_cp_indirect(DRM_IOCTL_ARGS) return 0; } -static int radeon_cp_vertex2(DRM_IOCTL_ARGS) +static int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; - struct drm_file *filp_priv; drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; struct drm_device_dma *dma = dev->dma; struct drm_buf *buf; - drm_radeon_vertex2_t vertex; + drm_radeon_vertex2_t *vertex = data; int i; unsigned char laststate; - LOCK_TEST_WITH_RETURN(dev, filp); - - DRM_GET_PRIV_WITH_RETURN(filp_priv, filp); - - DRM_COPY_FROM_USER_IOCTL(vertex, (drm_radeon_vertex2_t __user *) data, - sizeof(vertex)); + LOCK_TEST_WITH_RETURN(dev, file_priv); DRM_DEBUG("pid=%d index=%d discard=%d\n", - DRM_CURRENTPID, vertex.idx, vertex.discard); + DRM_CURRENTPID, vertex->idx, vertex->discard); - if (vertex.idx < 0 || vertex.idx >= dma->buf_count) { + if (vertex->idx < 0 || vertex->idx >= dma->buf_count) { DRM_ERROR("buffer index %d (of %d max)\n", - vertex.idx, dma->buf_count - 1); - return DRM_ERR(EINVAL); + vertex->idx, dma->buf_count - 1); + return -EINVAL; } RING_SPACE_TEST_WITH_RETURN(dev_priv); VB_AGE_TEST_WITH_RETURN(dev_priv); - buf = dma->buflist[vertex.idx]; + buf = dma->buflist[vertex->idx]; - if (buf->filp != filp) { + if (buf->file_priv != file_priv) { DRM_ERROR("process %d using buffer owned by %p\n", - DRM_CURRENTPID, buf->filp); - return DRM_ERR(EINVAL); + DRM_CURRENTPID, buf->file_priv); + return -EINVAL; } if (buf->pending) { - DRM_ERROR("sending pending buffer %d\n", vertex.idx); - return DRM_ERR(EINVAL); + DRM_ERROR("sending pending buffer %d\n", vertex->idx); + return -EINVAL; } if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS) - return DRM_ERR(EINVAL); + return -EINVAL; - for (laststate = 0xff, i = 0; i < vertex.nr_prims; i++) { + for (laststate = 0xff, i = 0; i < vertex->nr_prims; i++) { drm_radeon_prim_t prim; drm_radeon_tcl_prim_t tclprim; - if (DRM_COPY_FROM_USER(&prim, &vertex.prim[i], sizeof(prim))) - return DRM_ERR(EFAULT); + if (DRM_COPY_FROM_USER(&prim, &vertex->prim[i], sizeof(prim))) + return -EFAULT; if (prim.stateidx != laststate) { drm_radeon_state_t state; if (DRM_COPY_FROM_USER(&state, - &vertex.state[prim.stateidx], + &vertex->state[prim.stateidx], sizeof(state))) - return DRM_ERR(EFAULT); + return -EFAULT; - if (radeon_emit_state2(dev_priv, filp_priv, &state)) { + if (radeon_emit_state2(dev_priv, file_priv, &state)) { DRM_ERROR("radeon_emit_state2 failed\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } laststate = prim.stateidx; @@ -2594,7 +2552,7 @@ static int radeon_cp_vertex2(DRM_IOCTL_ARGS) sarea_priv->nbox = 0; } - if (vertex.discard) { + if (vertex->discard) { radeon_cp_discard_buffer(dev, buf); } @@ -2603,7 +2561,7 @@ static int radeon_cp_vertex2(DRM_IOCTL_ARGS) } static int radeon_emit_packets(drm_radeon_private_t * dev_priv, - struct drm_file * filp_priv, + struct drm_file *file_priv, drm_radeon_cmd_header_t header, drm_radeon_kcmd_buffer_t *cmdbuf) { @@ -2613,19 +2571,19 @@ static int radeon_emit_packets(drm_radeon_private_t * dev_priv, RING_LOCALS; if (id >= RADEON_MAX_STATE_PACKETS) - return DRM_ERR(EINVAL); + return -EINVAL; sz = packet[id].len; reg = packet[id].start; if (sz * sizeof(int) > cmdbuf->bufsz) { DRM_ERROR("Packet size provided larger than data provided\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } - if (radeon_check_and_fixup_packets(dev_priv, filp_priv, id, data)) { + if (radeon_check_and_fixup_packets(dev_priv, file_priv, id, data)) { DRM_ERROR("Packet verification failed\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } BEGIN_RING(sz + 1); @@ -2713,7 +2671,7 @@ static __inline__ int radeon_emit_veclinear(drm_radeon_private_t *dev_priv, if (!sz) return 0; if (sz * 4 > cmdbuf->bufsz) - return DRM_ERR(EINVAL); + return -EINVAL; BEGIN_RING(5 + sz); OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0); @@ -2729,7 +2687,7 @@ static __inline__ int radeon_emit_veclinear(drm_radeon_private_t *dev_priv, } static int radeon_emit_packet3(struct drm_device * dev, - struct drm_file * filp_priv, + struct drm_file *file_priv, drm_radeon_kcmd_buffer_t *cmdbuf) { drm_radeon_private_t *dev_priv = dev->dev_private; @@ -2739,7 +2697,7 @@ static int radeon_emit_packet3(struct drm_device * dev, DRM_DEBUG("\n"); - if ((ret = radeon_check_and_fixup_packet3(dev_priv, filp_priv, + if ((ret = radeon_check_and_fixup_packet3(dev_priv, file_priv, cmdbuf, &cmdsz))) { DRM_ERROR("Packet verification failed\n"); return ret; @@ -2755,7 +2713,7 @@ static int radeon_emit_packet3(struct drm_device * dev, } static int radeon_emit_packet3_cliprect(struct drm_device *dev, - struct drm_file *filp_priv, + struct drm_file *file_priv, drm_radeon_kcmd_buffer_t *cmdbuf, int orig_nbox) { @@ -2769,7 +2727,7 @@ static int radeon_emit_packet3_cliprect(struct drm_device *dev, DRM_DEBUG("\n"); - if ((ret = radeon_check_and_fixup_packet3(dev_priv, filp_priv, + if ((ret = radeon_check_and_fixup_packet3(dev_priv, file_priv, cmdbuf, &cmdsz))) { DRM_ERROR("Packet verification failed\n"); return ret; @@ -2781,7 +2739,7 @@ static int radeon_emit_packet3_cliprect(struct drm_device *dev, do { if (i < cmdbuf->nbox) { if (DRM_COPY_FROM_USER(&box, &boxes[i], sizeof(box))) - return DRM_ERR(EFAULT); + return -EFAULT; /* FIXME The second and subsequent times round * this loop, send a WAIT_UNTIL_3D_IDLE before * calling emit_clip_rect(). This fixes a @@ -2839,62 +2797,54 @@ static int radeon_emit_wait(struct drm_device * dev, int flags) ADVANCE_RING(); break; default: - return DRM_ERR(EINVAL); + return -EINVAL; } return 0; } -static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS) +static int radeon_cp_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; - struct drm_file *filp_priv; struct drm_device_dma *dma = dev->dma; struct drm_buf *buf = NULL; int idx; - drm_radeon_kcmd_buffer_t cmdbuf; + drm_radeon_kcmd_buffer_t *cmdbuf = data; drm_radeon_cmd_header_t header; int orig_nbox, orig_bufsz; char *kbuf = NULL; - LOCK_TEST_WITH_RETURN(dev, filp); - - DRM_GET_PRIV_WITH_RETURN(filp_priv, filp); - - DRM_COPY_FROM_USER_IOCTL(cmdbuf, - (drm_radeon_cmd_buffer_t __user *) data, - sizeof(cmdbuf)); + LOCK_TEST_WITH_RETURN(dev, file_priv); RING_SPACE_TEST_WITH_RETURN(dev_priv); VB_AGE_TEST_WITH_RETURN(dev_priv); - if (cmdbuf.bufsz > 64 * 1024 || cmdbuf.bufsz < 0) { - return DRM_ERR(EINVAL); + if (cmdbuf->bufsz > 64 * 1024 || cmdbuf->bufsz < 0) { + return -EINVAL; } /* Allocate an in-kernel area and copy in the cmdbuf. Do this to avoid * races between checking values and using those values in other code, * and simply to avoid a lot of function calls to copy in data. */ - orig_bufsz = cmdbuf.bufsz; + orig_bufsz = cmdbuf->bufsz; if (orig_bufsz != 0) { - kbuf = drm_alloc(cmdbuf.bufsz, DRM_MEM_DRIVER); + kbuf = drm_alloc(cmdbuf->bufsz, DRM_MEM_DRIVER); if (kbuf == NULL) - return DRM_ERR(ENOMEM); - if (DRM_COPY_FROM_USER(kbuf, (void __user *)cmdbuf.buf, - cmdbuf.bufsz)) { + return -ENOMEM; + if (DRM_COPY_FROM_USER(kbuf, (void __user *)cmdbuf->buf, + cmdbuf->bufsz)) { drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER); - return DRM_ERR(EFAULT); + return -EFAULT; } - cmdbuf.buf = kbuf; + cmdbuf->buf = kbuf; } - orig_nbox = cmdbuf.nbox; + orig_nbox = cmdbuf->nbox; if (dev_priv->microcode_version == UCODE_R300) { int temp; - temp = r300_do_cp_cmdbuf(dev, filp, filp_priv, &cmdbuf); + temp = r300_do_cp_cmdbuf(dev, file_priv, cmdbuf); if (orig_bufsz != 0) drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER); @@ -2903,17 +2853,17 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS) } /* microcode_version != r300 */ - while (cmdbuf.bufsz >= sizeof(header)) { + while (cmdbuf->bufsz >= sizeof(header)) { - header.i = *(int *)cmdbuf.buf; - cmdbuf.buf += sizeof(header); - cmdbuf.bufsz -= sizeof(header); + header.i = *(int *)cmdbuf->buf; + cmdbuf->buf += sizeof(header); + cmdbuf->bufsz -= sizeof(header); switch (header.header.cmd_type) { case RADEON_CMD_PACKET: DRM_DEBUG("RADEON_CMD_PACKET\n"); if (radeon_emit_packets - (dev_priv, filp_priv, header, &cmdbuf)) { + (dev_priv, file_priv, header, cmdbuf)) { DRM_ERROR("radeon_emit_packets failed\n"); goto err; } @@ -2921,7 +2871,7 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS) case RADEON_CMD_SCALARS: DRM_DEBUG("RADEON_CMD_SCALARS\n"); - if (radeon_emit_scalars(dev_priv, header, &cmdbuf)) { + if (radeon_emit_scalars(dev_priv, header, cmdbuf)) { DRM_ERROR("radeon_emit_scalars failed\n"); goto err; } @@ -2929,7 +2879,7 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS) case RADEON_CMD_VECTORS: DRM_DEBUG("RADEON_CMD_VECTORS\n"); - if (radeon_emit_vectors(dev_priv, header, &cmdbuf)) { + if (radeon_emit_vectors(dev_priv, header, cmdbuf)) { DRM_ERROR("radeon_emit_vectors failed\n"); goto err; } @@ -2945,9 +2895,10 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS) } buf = dma->buflist[idx]; - if (buf->filp != filp || buf->pending) { + if (buf->file_priv != file_priv || buf->pending) { DRM_ERROR("bad buffer %p %p %d\n", - buf->filp, filp, buf->pending); + buf->file_priv, file_priv, + buf->pending); goto err; } @@ -2956,7 +2907,7 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS) case RADEON_CMD_PACKET3: DRM_DEBUG("RADEON_CMD_PACKET3\n"); - if (radeon_emit_packet3(dev, filp_priv, &cmdbuf)) { + if (radeon_emit_packet3(dev, file_priv, cmdbuf)) { DRM_ERROR("radeon_emit_packet3 failed\n"); goto err; } @@ -2965,7 +2916,7 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS) case RADEON_CMD_PACKET3_CLIP: DRM_DEBUG("RADEON_CMD_PACKET3_CLIP\n"); if (radeon_emit_packet3_cliprect - (dev, filp_priv, &cmdbuf, orig_nbox)) { + (dev, file_priv, cmdbuf, orig_nbox)) { DRM_ERROR("radeon_emit_packet3_clip failed\n"); goto err; } @@ -2973,7 +2924,7 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS) case RADEON_CMD_SCALARS2: DRM_DEBUG("RADEON_CMD_SCALARS2\n"); - if (radeon_emit_scalars2(dev_priv, header, &cmdbuf)) { + if (radeon_emit_scalars2(dev_priv, header, cmdbuf)) { DRM_ERROR("radeon_emit_scalars2 failed\n"); goto err; } @@ -2988,7 +2939,7 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS) break; case RADEON_CMD_VECLINEAR: DRM_DEBUG("RADEON_CMD_VECLINEAR\n"); - if (radeon_emit_veclinear(dev_priv, header, &cmdbuf)) { + if (radeon_emit_veclinear(dev_priv, header, cmdbuf)) { DRM_ERROR("radeon_emit_veclinear failed\n"); goto err; } @@ -2997,7 +2948,7 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS) default: DRM_ERROR("bad cmd_type %d at %p\n", header.header.cmd_type, - cmdbuf.buf - sizeof(header)); + cmdbuf->buf - sizeof(header)); goto err; } } @@ -3012,22 +2963,18 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS) err: if (orig_bufsz != 0) drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER); - return DRM_ERR(EINVAL); + return -EINVAL; } -static int radeon_cp_getparam(DRM_IOCTL_ARGS) +static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; - drm_radeon_getparam_t param; + drm_radeon_getparam_t *param = data; int value; - DRM_COPY_FROM_USER_IOCTL(param, (drm_radeon_getparam_t __user *) data, - sizeof(param)); - DRM_DEBUG("pid=%d\n", DRM_CURRENTPID); - switch (param.param) { + switch (param->param) { case RADEON_PARAM_GART_BUFFER_OFFSET: value = dev_priv->gart_buffers_offset; break; @@ -3074,7 +3021,7 @@ static int radeon_cp_getparam(DRM_IOCTL_ARGS) break; case RADEON_PARAM_SCRATCH_OFFSET: if (!dev_priv->writeback_works) - return DRM_ERR(EINVAL); + return -EINVAL; value = RADEON_SCRATCH_REG_OFFSET; break; case RADEON_PARAM_CARD_TYPE: @@ -3089,43 +3036,37 @@ static int radeon_cp_getparam(DRM_IOCTL_ARGS) value = radeon_vblank_crtc_get(dev); break; default: - DRM_DEBUG("Invalid parameter %d\n", param.param); - return DRM_ERR(EINVAL); + DRM_DEBUG("Invalid parameter %d\n", param->param); + return -EINVAL; } - if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) { + if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) { DRM_ERROR("copy_to_user\n"); - return DRM_ERR(EFAULT); + return -EFAULT; } return 0; } -static int radeon_cp_setparam(DRM_IOCTL_ARGS) +static int radeon_cp_setparam(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; - struct drm_file *filp_priv; - drm_radeon_setparam_t sp; + drm_radeon_setparam_t *sp = data; struct drm_radeon_driver_file_fields *radeon_priv; - DRM_GET_PRIV_WITH_RETURN(filp_priv, filp); - - DRM_COPY_FROM_USER_IOCTL(sp, (drm_radeon_setparam_t __user *) data, - sizeof(sp)); - - switch (sp.param) { + switch (sp->param) { case RADEON_SETPARAM_FB_LOCATION: - radeon_priv = filp_priv->driver_priv; - radeon_priv->radeon_fb_delta = dev_priv->fb_location - sp.value; + radeon_priv = file_priv->driver_priv; + radeon_priv->radeon_fb_delta = dev_priv->fb_location - + sp->value; break; case RADEON_SETPARAM_SWITCH_TILING: - if (sp.value == 0) { + if (sp->value == 0) { DRM_DEBUG("color tiling disabled\n"); dev_priv->front_pitch_offset &= ~RADEON_DST_TILE_MACRO; dev_priv->back_pitch_offset &= ~RADEON_DST_TILE_MACRO; dev_priv->sarea_priv->tiling_enabled = 0; - } else if (sp.value == 1) { + } else if (sp->value == 1) { DRM_DEBUG("color tiling enabled\n"); dev_priv->front_pitch_offset |= RADEON_DST_TILE_MACRO; dev_priv->back_pitch_offset |= RADEON_DST_TILE_MACRO; @@ -3133,23 +3074,23 @@ static int radeon_cp_setparam(DRM_IOCTL_ARGS) } break; case RADEON_SETPARAM_PCIGART_LOCATION: - dev_priv->pcigart_offset = sp.value; + dev_priv->pcigart_offset = sp->value; dev_priv->pcigart_offset_set = 1; break; case RADEON_SETPARAM_NEW_MEMMAP: - dev_priv->new_memmap = sp.value; + dev_priv->new_memmap = sp->value; break; case RADEON_SETPARAM_PCIGART_TABLE_SIZE: - dev_priv->gart_info.table_size = sp.value; + dev_priv->gart_info.table_size = sp->value; if (dev_priv->gart_info.table_size < RADEON_PCIGART_TABLE_SIZE) dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE; break; case RADEON_SETPARAM_VBLANK_CRTC: - return radeon_vblank_crtc_set(dev, sp.value); + return radeon_vblank_crtc_set(dev, sp->value); break; default: - DRM_DEBUG("Invalid parameter %d\n", sp.param); - return DRM_ERR(EINVAL); + DRM_DEBUG("Invalid parameter %d\n", sp->param); + return -EINVAL; } return 0; @@ -3162,14 +3103,14 @@ static int radeon_cp_setparam(DRM_IOCTL_ARGS) * * DRM infrastructure takes care of reclaiming dma buffers. */ -void radeon_driver_preclose(struct drm_device *dev, DRMFILE filp) +void radeon_driver_preclose(struct drm_device *dev, struct drm_file *file_priv) { if (dev->dev_private) { drm_radeon_private_t *dev_priv = dev->dev_private; dev_priv->page_flipping = 0; - radeon_mem_release(filp, dev_priv->gart_heap); - radeon_mem_release(filp, dev_priv->fb_heap); - radeon_surfaces_release(filp, dev_priv); + radeon_mem_release(file_priv, dev_priv->gart_heap); + radeon_mem_release(file_priv, dev_priv->fb_heap); + radeon_surfaces_release(file_priv, dev_priv); } } @@ -3186,7 +3127,7 @@ void radeon_driver_lastclose(struct drm_device *dev) radeon_do_release(dev); } -int radeon_driver_open(struct drm_device *dev, struct drm_file *filp_priv) +int radeon_driver_open(struct drm_device *dev, struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; struct drm_radeon_driver_file_fields *radeon_priv; @@ -3199,7 +3140,7 @@ int radeon_driver_open(struct drm_device *dev, struct drm_file *filp_priv) if (!radeon_priv) return -ENOMEM; - filp_priv->driver_priv = radeon_priv; + file_priv->driver_priv = radeon_priv; if (dev_priv) radeon_priv->radeon_fb_delta = dev_priv->fb_location; @@ -3208,42 +3149,42 @@ int radeon_driver_open(struct drm_device *dev, struct drm_file *filp_priv) return 0; } -void radeon_driver_postclose(struct drm_device *dev, struct drm_file *filp_priv) +void radeon_driver_postclose(struct drm_device *dev, struct drm_file *file_priv) { struct drm_radeon_driver_file_fields *radeon_priv = - filp_priv->driver_priv; + file_priv->driver_priv; drm_free(radeon_priv, sizeof(*radeon_priv), DRM_MEM_FILES); } -drm_ioctl_desc_t radeon_ioctls[] = { - [DRM_IOCTL_NR(DRM_RADEON_CP_INIT)] = {radeon_cp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_RADEON_CP_START)] = {radeon_cp_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_RADEON_CP_STOP)] = {radeon_cp_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_RADEON_CP_RESET)] = {radeon_cp_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_RADEON_CP_IDLE)] = {radeon_cp_idle, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_RADEON_CP_RESUME)] = {radeon_cp_resume, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_RADEON_RESET)] = {radeon_engine_reset, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_RADEON_FULLSCREEN)] = {radeon_fullscreen, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_RADEON_SWAP)] = {radeon_cp_swap, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_RADEON_CLEAR)] = {radeon_cp_clear, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_RADEON_VERTEX)] = {radeon_cp_vertex, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_RADEON_INDICES)] = {radeon_cp_indices, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_RADEON_TEXTURE)] = {radeon_cp_texture, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_RADEON_STIPPLE)] = {radeon_cp_stipple, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_RADEON_INDIRECT)] = {radeon_cp_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_RADEON_VERTEX2)] = {radeon_cp_vertex2, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_RADEON_CMDBUF)] = {radeon_cp_cmdbuf, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_RADEON_GETPARAM)] = {radeon_cp_getparam, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_RADEON_FLIP)] = {radeon_cp_flip, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_RADEON_ALLOC)] = {radeon_mem_alloc, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_RADEON_FREE)] = {radeon_mem_free, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_RADEON_INIT_HEAP)] = {radeon_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_RADEON_IRQ_EMIT)] = {radeon_irq_emit, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_RADEON_IRQ_WAIT)] = {radeon_irq_wait, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_RADEON_SETPARAM)] = {radeon_cp_setparam, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_RADEON_SURF_ALLOC)] = {radeon_surface_alloc, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_RADEON_SURF_FREE)] = {radeon_surface_free, DRM_AUTH} +struct drm_ioctl_desc radeon_ioctls[] = { + DRM_IOCTL_DEF(DRM_RADEON_CP_INIT, radeon_cp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_RADEON_CP_START, radeon_cp_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_RADEON_CP_STOP, radeon_cp_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_RADEON_CP_RESET, radeon_cp_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_RADEON_CP_IDLE, radeon_cp_idle, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_CP_RESUME, radeon_cp_resume, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_RESET, radeon_engine_reset, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_FULLSCREEN, radeon_fullscreen, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_SWAP, radeon_cp_swap, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_CLEAR, radeon_cp_clear, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_VERTEX, radeon_cp_vertex, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_INDICES, radeon_cp_indices, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_TEXTURE, radeon_cp_texture, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_STIPPLE, radeon_cp_stipple, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_INDIRECT, radeon_cp_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_RADEON_VERTEX2, radeon_cp_vertex2, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_CMDBUF, radeon_cp_cmdbuf, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_GETPARAM, radeon_cp_getparam, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_FLIP, radeon_cp_flip, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_ALLOC, radeon_mem_alloc, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_FREE, radeon_mem_free, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_INIT_HEAP, radeon_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_RADEON_IRQ_EMIT, radeon_irq_emit, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_IRQ_WAIT, radeon_irq_wait, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_SETPARAM, radeon_cp_setparam, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_SURF_ALLOC, radeon_surface_alloc, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_SURF_FREE, radeon_surface_free, DRM_AUTH) }; int radeon_max_ioctl = DRM_ARRAY_SIZE(radeon_ioctls); diff --git a/drivers/char/drm/savage_bci.c b/drivers/char/drm/savage_bci.c index 18c7235f6b73..59484d56b333 100644 --- a/drivers/char/drm/savage_bci.c +++ b/drivers/char/drm/savage_bci.c @@ -60,7 +60,7 @@ savage_bci_wait_fifo_shadow(drm_savage_private_t * dev_priv, unsigned int n) DRM_ERROR("failed!\n"); DRM_INFO(" status=0x%08x, threshold=0x%08x\n", status, threshold); #endif - return DRM_ERR(EBUSY); + return -EBUSY; } static int @@ -81,7 +81,7 @@ savage_bci_wait_fifo_s3d(drm_savage_private_t * dev_priv, unsigned int n) DRM_ERROR("failed!\n"); DRM_INFO(" status=0x%08x\n", status); #endif - return DRM_ERR(EBUSY); + return -EBUSY; } static int @@ -102,7 +102,7 @@ savage_bci_wait_fifo_s4(drm_savage_private_t * dev_priv, unsigned int n) DRM_ERROR("failed!\n"); DRM_INFO(" status=0x%08x\n", status); #endif - return DRM_ERR(EBUSY); + return -EBUSY; } /* @@ -136,7 +136,7 @@ savage_bci_wait_event_shadow(drm_savage_private_t * dev_priv, uint16_t e) DRM_INFO(" status=0x%08x, e=0x%04x\n", status, e); #endif - return DRM_ERR(EBUSY); + return -EBUSY; } static int @@ -158,7 +158,7 @@ savage_bci_wait_event_reg(drm_savage_private_t * dev_priv, uint16_t e) DRM_INFO(" status=0x%08x, e=0x%04x\n", status, e); #endif - return DRM_ERR(EBUSY); + return -EBUSY; } uint16_t savage_bci_emit_event(drm_savage_private_t * dev_priv, @@ -301,7 +301,7 @@ static int savage_dma_init(drm_savage_private_t * dev_priv) dev_priv->dma_pages = drm_alloc(sizeof(drm_savage_dma_page_t) * dev_priv->nr_dma_pages, DRM_MEM_DRIVER); if (dev_priv->dma_pages == NULL) - return DRM_ERR(ENOMEM); + return -ENOMEM; for (i = 0; i < dev_priv->nr_dma_pages; ++i) { SET_AGE(&dev_priv->dma_pages[i].age, 0, 0); @@ -541,7 +541,7 @@ int savage_driver_load(struct drm_device *dev, unsigned long chipset) dev_priv = drm_alloc(sizeof(drm_savage_private_t), DRM_MEM_DRIVER); if (dev_priv == NULL) - return DRM_ERR(ENOMEM); + return -ENOMEM; memset(dev_priv, 0, sizeof(drm_savage_private_t)); dev->dev_private = (void *)dev_priv; @@ -682,16 +682,16 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init) if (init->fb_bpp != 16 && init->fb_bpp != 32) { DRM_ERROR("invalid frame buffer bpp %d!\n", init->fb_bpp); - return DRM_ERR(EINVAL); + return -EINVAL; } if (init->depth_bpp != 16 && init->depth_bpp != 32) { DRM_ERROR("invalid depth buffer bpp %d!\n", init->fb_bpp); - return DRM_ERR(EINVAL); + return -EINVAL; } if (init->dma_type != SAVAGE_DMA_AGP && init->dma_type != SAVAGE_DMA_PCI) { DRM_ERROR("invalid dma memory type %d!\n", init->dma_type); - return DRM_ERR(EINVAL); + return -EINVAL; } dev_priv->cob_size = init->cob_size; @@ -715,14 +715,14 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init) if (!dev_priv->sarea) { DRM_ERROR("could not find sarea!\n"); savage_do_cleanup_bci(dev); - return DRM_ERR(EINVAL); + return -EINVAL; } if (init->status_offset != 0) { dev_priv->status = drm_core_findmap(dev, init->status_offset); if (!dev_priv->status) { DRM_ERROR("could not find shadow status region!\n"); savage_do_cleanup_bci(dev); - return DRM_ERR(EINVAL); + return -EINVAL; } } else { dev_priv->status = NULL; @@ -734,13 +734,13 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init) if (!dev->agp_buffer_map) { DRM_ERROR("could not find DMA buffer region!\n"); savage_do_cleanup_bci(dev); - return DRM_ERR(EINVAL); + return -EINVAL; } drm_core_ioremap(dev->agp_buffer_map, dev); if (!dev->agp_buffer_map) { DRM_ERROR("failed to ioremap DMA buffer region!\n"); savage_do_cleanup_bci(dev); - return DRM_ERR(ENOMEM); + return -ENOMEM; } } if (init->agp_textures_offset) { @@ -749,7 +749,7 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init) if (!dev_priv->agp_textures) { DRM_ERROR("could not find agp texture region!\n"); savage_do_cleanup_bci(dev); - return DRM_ERR(EINVAL); + return -EINVAL; } } else { dev_priv->agp_textures = NULL; @@ -760,39 +760,39 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init) DRM_ERROR("command DMA not supported on " "Savage3D/MX/IX.\n"); savage_do_cleanup_bci(dev); - return DRM_ERR(EINVAL); + return -EINVAL; } if (dev->dma && dev->dma->buflist) { DRM_ERROR("command and vertex DMA not supported " "at the same time.\n"); savage_do_cleanup_bci(dev); - return DRM_ERR(EINVAL); + return -EINVAL; } dev_priv->cmd_dma = drm_core_findmap(dev, init->cmd_dma_offset); if (!dev_priv->cmd_dma) { DRM_ERROR("could not find command DMA region!\n"); savage_do_cleanup_bci(dev); - return DRM_ERR(EINVAL); + return -EINVAL; } if (dev_priv->dma_type == SAVAGE_DMA_AGP) { if (dev_priv->cmd_dma->type != _DRM_AGP) { DRM_ERROR("AGP command DMA region is not a " "_DRM_AGP map!\n"); savage_do_cleanup_bci(dev); - return DRM_ERR(EINVAL); + return -EINVAL; } drm_core_ioremap(dev_priv->cmd_dma, dev); if (!dev_priv->cmd_dma->handle) { DRM_ERROR("failed to ioremap command " "DMA region!\n"); savage_do_cleanup_bci(dev); - return DRM_ERR(ENOMEM); + return -ENOMEM; } } else if (dev_priv->cmd_dma->type != _DRM_CONSISTENT) { DRM_ERROR("PCI command DMA region is not a " "_DRM_CONSISTENT map!\n"); savage_do_cleanup_bci(dev); - return DRM_ERR(EINVAL); + return -EINVAL; } } else { dev_priv->cmd_dma = NULL; @@ -809,7 +809,7 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init) if (!dev_priv->fake_dma.handle) { DRM_ERROR("could not allocate faked DMA buffer!\n"); savage_do_cleanup_bci(dev); - return DRM_ERR(ENOMEM); + return -ENOMEM; } dev_priv->cmd_dma = &dev_priv->fake_dma; dev_priv->dma_flush = savage_fake_dma_flush; @@ -886,13 +886,13 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init) if (savage_freelist_init(dev) < 0) { DRM_ERROR("could not initialize freelist\n"); savage_do_cleanup_bci(dev); - return DRM_ERR(ENOMEM); + return -ENOMEM; } if (savage_dma_init(dev_priv) < 0) { DRM_ERROR("could not initialize command DMA\n"); savage_do_cleanup_bci(dev); - return DRM_ERR(ENOMEM); + return -ENOMEM; } return 0; @@ -928,51 +928,41 @@ static int savage_do_cleanup_bci(struct drm_device * dev) return 0; } -static int savage_bci_init(DRM_IOCTL_ARGS) +static int savage_bci_init(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; - drm_savage_init_t init; + drm_savage_init_t *init = data; - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); - DRM_COPY_FROM_USER_IOCTL(init, (drm_savage_init_t __user *) data, - sizeof(init)); - - switch (init.func) { + switch (init->func) { case SAVAGE_INIT_BCI: - return savage_do_init_bci(dev, &init); + return savage_do_init_bci(dev, init); case SAVAGE_CLEANUP_BCI: return savage_do_cleanup_bci(dev); } - return DRM_ERR(EINVAL); + return -EINVAL; } -static int savage_bci_event_emit(DRM_IOCTL_ARGS) +static int savage_bci_event_emit(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_savage_private_t *dev_priv = dev->dev_private; - drm_savage_event_emit_t event; + drm_savage_event_emit_t *event = data; DRM_DEBUG("\n"); - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); - DRM_COPY_FROM_USER_IOCTL(event, (drm_savage_event_emit_t __user *) data, - sizeof(event)); + event->count = savage_bci_emit_event(dev_priv, event->flags); + event->count |= dev_priv->event_wrap << 16; - event.count = savage_bci_emit_event(dev_priv, event.flags); - event.count |= dev_priv->event_wrap << 16; - DRM_COPY_TO_USER_IOCTL((drm_savage_event_emit_t __user *) data, - event, sizeof(event)); return 0; } -static int savage_bci_event_wait(DRM_IOCTL_ARGS) +static int savage_bci_event_wait(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_savage_private_t *dev_priv = dev->dev_private; - drm_savage_event_wait_t event; + drm_savage_event_wait_t *event = data; unsigned int event_e, hw_e; unsigned int event_w, hw_w; @@ -990,8 +980,8 @@ static int savage_bci_event_wait(DRM_IOCTL_ARGS) if (hw_e > dev_priv->event_counter) hw_w--; /* hardware hasn't passed the last wrap yet */ - event_e = event.count & 0xffff; - event_w = event.count >> 16; + event_e = event->count & 0xffff; + event_w = event->count >> 16; /* Don't need to wait if * - event counter wrapped since the event was emitted or @@ -1007,7 +997,9 @@ static int savage_bci_event_wait(DRM_IOCTL_ARGS) * DMA buffer management */ -static int savage_bci_get_buffers(DRMFILE filp, struct drm_device *dev, struct drm_dma *d) +static int savage_bci_get_buffers(struct drm_device *dev, + struct drm_file *file_priv, + struct drm_dma *d) { struct drm_buf *buf; int i; @@ -1015,61 +1007,56 @@ static int savage_bci_get_buffers(DRMFILE filp, struct drm_device *dev, struct d for (i = d->granted_count; i < d->request_count; i++) { buf = savage_freelist_get(dev); if (!buf) - return DRM_ERR(EAGAIN); + return -EAGAIN; - buf->filp = filp; + buf->file_priv = file_priv; if (DRM_COPY_TO_USER(&d->request_indices[i], &buf->idx, sizeof(buf->idx))) - return DRM_ERR(EFAULT); + return -EFAULT; if (DRM_COPY_TO_USER(&d->request_sizes[i], &buf->total, sizeof(buf->total))) - return DRM_ERR(EFAULT); + return -EFAULT; d->granted_count++; } return 0; } -int savage_bci_buffers(DRM_IOCTL_ARGS) +int savage_bci_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; struct drm_device_dma *dma = dev->dma; - struct drm_dma d; + struct drm_dma *d = data; int ret = 0; - LOCK_TEST_WITH_RETURN(dev, filp); - - DRM_COPY_FROM_USER_IOCTL(d, (struct drm_dma __user *) data, sizeof(d)); + LOCK_TEST_WITH_RETURN(dev, file_priv); /* Please don't send us buffers. */ - if (d.send_count != 0) { + if (d->send_count != 0) { DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n", - DRM_CURRENTPID, d.send_count); - return DRM_ERR(EINVAL); + DRM_CURRENTPID, d->send_count); + return -EINVAL; } /* We'll send you buffers. */ - if (d.request_count < 0 || d.request_count > dma->buf_count) { + if (d->request_count < 0 || d->request_count > dma->buf_count) { DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n", - DRM_CURRENTPID, d.request_count, dma->buf_count); - return DRM_ERR(EINVAL); + DRM_CURRENTPID, d->request_count, dma->buf_count); + return -EINVAL; } - d.granted_count = 0; + d->granted_count = 0; - if (d.request_count) { - ret = savage_bci_get_buffers(filp, dev, &d); + if (d->request_count) { + ret = savage_bci_get_buffers(dev, file_priv, d); } - DRM_COPY_TO_USER_IOCTL((struct drm_dma __user *) data, d, sizeof(d)); - return ret; } -void savage_reclaim_buffers(struct drm_device *dev, DRMFILE filp) +void savage_reclaim_buffers(struct drm_device *dev, struct drm_file *file_priv) { struct drm_device_dma *dma = dev->dma; drm_savage_private_t *dev_priv = dev->dev_private; @@ -1088,7 +1075,7 @@ void savage_reclaim_buffers(struct drm_device *dev, DRMFILE filp) struct drm_buf *buf = dma->buflist[i]; drm_savage_buf_priv_t *buf_priv = buf->dev_private; - if (buf->filp == filp && buf_priv && + if (buf->file_priv == file_priv && buf_priv && buf_priv->next == NULL && buf_priv->prev == NULL) { uint16_t event; DRM_DEBUG("reclaimed from client\n"); @@ -1098,14 +1085,14 @@ void savage_reclaim_buffers(struct drm_device *dev, DRMFILE filp) } } - drm_core_reclaim_buffers(dev, filp); + drm_core_reclaim_buffers(dev, file_priv); } -drm_ioctl_desc_t savage_ioctls[] = { - [DRM_IOCTL_NR(DRM_SAVAGE_BCI_INIT)] = {savage_bci_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_SAVAGE_BCI_CMDBUF)] = {savage_bci_cmdbuf, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_SAVAGE_BCI_EVENT_EMIT)] = {savage_bci_event_emit, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_SAVAGE_BCI_EVENT_WAIT)] = {savage_bci_event_wait, DRM_AUTH}, +struct drm_ioctl_desc savage_ioctls[] = { + DRM_IOCTL_DEF(DRM_SAVAGE_BCI_INIT, savage_bci_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_SAVAGE_BCI_CMDBUF, savage_bci_cmdbuf, DRM_AUTH), + DRM_IOCTL_DEF(DRM_SAVAGE_BCI_EVENT_EMIT, savage_bci_event_emit, DRM_AUTH), + DRM_IOCTL_DEF(DRM_SAVAGE_BCI_EVENT_WAIT, savage_bci_event_wait, DRM_AUTH), }; int savage_max_ioctl = DRM_ARRAY_SIZE(savage_ioctls); diff --git a/drivers/char/drm/savage_drv.h b/drivers/char/drm/savage_drv.h index 5fd54de4280e..df2aac6636f7 100644 --- a/drivers/char/drm/savage_drv.h +++ b/drivers/char/drm/savage_drv.h @@ -104,7 +104,7 @@ enum savage_family { S3_LAST }; -extern drm_ioctl_desc_t savage_ioctls[]; +extern struct drm_ioctl_desc savage_ioctls[]; extern int savage_max_ioctl; #define S3_SAVAGE3D_SERIES(chip) ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE_MX)) @@ -197,8 +197,8 @@ typedef struct drm_savage_private { } drm_savage_private_t; /* ioctls */ -extern int savage_bci_cmdbuf(DRM_IOCTL_ARGS); -extern int savage_bci_buffers(DRM_IOCTL_ARGS); +extern int savage_bci_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int savage_bci_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv); /* BCI functions */ extern uint16_t savage_bci_emit_event(drm_savage_private_t * dev_priv, @@ -212,7 +212,8 @@ extern int savage_driver_load(struct drm_device *dev, unsigned long chipset); extern int savage_driver_firstopen(struct drm_device *dev); extern void savage_driver_lastclose(struct drm_device *dev); extern int savage_driver_unload(struct drm_device *dev); -extern void savage_reclaim_buffers(struct drm_device * dev, DRMFILE filp); +extern void savage_reclaim_buffers(struct drm_device *dev, + struct drm_file *file_priv); /* state functions */ extern void savage_emit_clip_rect_s3d(drm_savage_private_t * dev_priv, diff --git a/drivers/char/drm/savage_state.c b/drivers/char/drm/savage_state.c index 77497841478a..bf8e0e10fe21 100644 --- a/drivers/char/drm/savage_state.c +++ b/drivers/char/drm/savage_state.c @@ -83,7 +83,7 @@ static int savage_verify_texaddr(drm_savage_private_t * dev_priv, int unit, { if ((addr & 6) != 2) { /* reserved bits */ DRM_ERROR("bad texAddr%d %08x (reserved bits)\n", unit, addr); - return DRM_ERR(EINVAL); + return -EINVAL; } if (!(addr & 1)) { /* local */ addr &= ~7; @@ -92,13 +92,13 @@ static int savage_verify_texaddr(drm_savage_private_t * dev_priv, int unit, DRM_ERROR ("bad texAddr%d %08x (local addr out of range)\n", unit, addr); - return DRM_ERR(EINVAL); + return -EINVAL; } } else { /* AGP */ if (!dev_priv->agp_textures) { DRM_ERROR("bad texAddr%d %08x (AGP not available)\n", unit, addr); - return DRM_ERR(EINVAL); + return -EINVAL; } addr &= ~7; if (addr < dev_priv->agp_textures->offset || @@ -107,7 +107,7 @@ static int savage_verify_texaddr(drm_savage_private_t * dev_priv, int unit, DRM_ERROR ("bad texAddr%d %08x (AGP addr out of range)\n", unit, addr); - return DRM_ERR(EINVAL); + return -EINVAL; } } return 0; @@ -133,7 +133,7 @@ static int savage_verify_state_s3d(drm_savage_private_t * dev_priv, start + count - 1 > SAVAGE_DESTTEXRWWATERMARK_S3D) { DRM_ERROR("invalid register range (0x%04x-0x%04x)\n", start, start + count - 1); - return DRM_ERR(EINVAL); + return -EINVAL; } SAVE_STATE_MASK(SAVAGE_SCSTART_S3D, s3d.new_scstart, @@ -165,7 +165,7 @@ static int savage_verify_state_s4(drm_savage_private_t * dev_priv, start + count - 1 > SAVAGE_TEXBLENDCOLOR_S4) { DRM_ERROR("invalid register range (0x%04x-0x%04x)\n", start, start + count - 1); - return DRM_ERR(EINVAL); + return -EINVAL; } SAVE_STATE_MASK(SAVAGE_DRAWCTRL0_S4, s4.new_drawctrl0, @@ -289,7 +289,7 @@ static int savage_dispatch_dma_prim(drm_savage_private_t * dev_priv, if (!dmabuf) { DRM_ERROR("called without dma buffers!\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } if (!n) @@ -303,7 +303,7 @@ static int savage_dispatch_dma_prim(drm_savage_private_t * dev_priv, if (n % 3 != 0) { DRM_ERROR("wrong number of vertices %u in TRILIST\n", n); - return DRM_ERR(EINVAL); + return -EINVAL; } break; case SAVAGE_PRIM_TRISTRIP: @@ -312,18 +312,18 @@ static int savage_dispatch_dma_prim(drm_savage_private_t * dev_priv, DRM_ERROR ("wrong number of vertices %u in TRIFAN/STRIP\n", n); - return DRM_ERR(EINVAL); + return -EINVAL; } break; default: DRM_ERROR("invalid primitive type %u\n", prim); - return DRM_ERR(EINVAL); + return -EINVAL; } if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { if (skip != 0) { DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip); - return DRM_ERR(EINVAL); + return -EINVAL; } } else { unsigned int size = 10 - (skip & 1) - (skip >> 1 & 1) - @@ -331,18 +331,18 @@ static int savage_dispatch_dma_prim(drm_savage_private_t * dev_priv, (skip >> 5 & 1) - (skip >> 6 & 1) - (skip >> 7 & 1); if (skip > SAVAGE_SKIP_ALL_S4 || size != 8) { DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip); - return DRM_ERR(EINVAL); + return -EINVAL; } if (reorder) { DRM_ERROR("TRILIST_201 used on Savage4 hardware\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } } if (start + n > dmabuf->total / 32) { DRM_ERROR("vertex indices (%u-%u) out of range (0-%u)\n", start, start + n - 1, dmabuf->total / 32); - return DRM_ERR(EINVAL); + return -EINVAL; } /* Vertex DMA doesn't work with command DMA at the same time, @@ -440,7 +440,7 @@ static int savage_dispatch_vb_prim(drm_savage_private_t * dev_priv, if (n % 3 != 0) { DRM_ERROR("wrong number of vertices %u in TRILIST\n", n); - return DRM_ERR(EINVAL); + return -EINVAL; } break; case SAVAGE_PRIM_TRISTRIP: @@ -449,24 +449,24 @@ static int savage_dispatch_vb_prim(drm_savage_private_t * dev_priv, DRM_ERROR ("wrong number of vertices %u in TRIFAN/STRIP\n", n); - return DRM_ERR(EINVAL); + return -EINVAL; } break; default: DRM_ERROR("invalid primitive type %u\n", prim); - return DRM_ERR(EINVAL); + return -EINVAL; } if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { if (skip > SAVAGE_SKIP_ALL_S3D) { DRM_ERROR("invalid skip flags 0x%04x\n", skip); - return DRM_ERR(EINVAL); + return -EINVAL; } vtx_size = 8; /* full vertex */ } else { if (skip > SAVAGE_SKIP_ALL_S4) { DRM_ERROR("invalid skip flags 0x%04x\n", skip); - return DRM_ERR(EINVAL); + return -EINVAL; } vtx_size = 10; /* full vertex */ } @@ -478,13 +478,13 @@ static int savage_dispatch_vb_prim(drm_savage_private_t * dev_priv, if (vtx_size > vb_stride) { DRM_ERROR("vertex size greater than vb stride (%u > %u)\n", vtx_size, vb_stride); - return DRM_ERR(EINVAL); + return -EINVAL; } if (start + n > vb_size / (vb_stride * 4)) { DRM_ERROR("vertex indices (%u-%u) out of range (0-%u)\n", start, start + n - 1, vb_size / (vb_stride * 4)); - return DRM_ERR(EINVAL); + return -EINVAL; } prim <<= 25; @@ -547,7 +547,7 @@ static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv, if (!dmabuf) { DRM_ERROR("called without dma buffers!\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } if (!n) @@ -560,7 +560,7 @@ static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv, case SAVAGE_PRIM_TRILIST: if (n % 3 != 0) { DRM_ERROR("wrong number of indices %u in TRILIST\n", n); - return DRM_ERR(EINVAL); + return -EINVAL; } break; case SAVAGE_PRIM_TRISTRIP: @@ -568,18 +568,18 @@ static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv, if (n < 3) { DRM_ERROR ("wrong number of indices %u in TRIFAN/STRIP\n", n); - return DRM_ERR(EINVAL); + return -EINVAL; } break; default: DRM_ERROR("invalid primitive type %u\n", prim); - return DRM_ERR(EINVAL); + return -EINVAL; } if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { if (skip != 0) { DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip); - return DRM_ERR(EINVAL); + return -EINVAL; } } else { unsigned int size = 10 - (skip & 1) - (skip >> 1 & 1) - @@ -587,11 +587,11 @@ static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv, (skip >> 5 & 1) - (skip >> 6 & 1) - (skip >> 7 & 1); if (skip > SAVAGE_SKIP_ALL_S4 || size != 8) { DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip); - return DRM_ERR(EINVAL); + return -EINVAL; } if (reorder) { DRM_ERROR("TRILIST_201 used on Savage4 hardware\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } } @@ -628,7 +628,7 @@ static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv, if (idx[i] > dmabuf->total / 32) { DRM_ERROR("idx[%u]=%u out of range (0-%u)\n", i, idx[i], dmabuf->total / 32); - return DRM_ERR(EINVAL); + return -EINVAL; } } @@ -698,7 +698,7 @@ static int savage_dispatch_vb_idx(drm_savage_private_t * dev_priv, case SAVAGE_PRIM_TRILIST: if (n % 3 != 0) { DRM_ERROR("wrong number of indices %u in TRILIST\n", n); - return DRM_ERR(EINVAL); + return -EINVAL; } break; case SAVAGE_PRIM_TRISTRIP: @@ -706,24 +706,24 @@ static int savage_dispatch_vb_idx(drm_savage_private_t * dev_priv, if (n < 3) { DRM_ERROR ("wrong number of indices %u in TRIFAN/STRIP\n", n); - return DRM_ERR(EINVAL); + return -EINVAL; } break; default: DRM_ERROR("invalid primitive type %u\n", prim); - return DRM_ERR(EINVAL); + return -EINVAL; } if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { if (skip > SAVAGE_SKIP_ALL_S3D) { DRM_ERROR("invalid skip flags 0x%04x\n", skip); - return DRM_ERR(EINVAL); + return -EINVAL; } vtx_size = 8; /* full vertex */ } else { if (skip > SAVAGE_SKIP_ALL_S4) { DRM_ERROR("invalid skip flags 0x%04x\n", skip); - return DRM_ERR(EINVAL); + return -EINVAL; } vtx_size = 10; /* full vertex */ } @@ -735,7 +735,7 @@ static int savage_dispatch_vb_idx(drm_savage_private_t * dev_priv, if (vtx_size > vb_stride) { DRM_ERROR("vertex size greater than vb stride (%u > %u)\n", vtx_size, vb_stride); - return DRM_ERR(EINVAL); + return -EINVAL; } prim <<= 25; @@ -748,7 +748,7 @@ static int savage_dispatch_vb_idx(drm_savage_private_t * dev_priv, if (idx[i] > vb_size / (vb_stride * 4)) { DRM_ERROR("idx[%u]=%u out of range (0-%u)\n", i, idx[i], vb_size / (vb_stride * 4)); - return DRM_ERR(EINVAL); + return -EINVAL; } } @@ -942,7 +942,7 @@ static int savage_dispatch_draw(drm_savage_private_t * dev_priv, DRM_ERROR("IMPLEMENTATION ERROR: " "non-drawing-command %d\n", cmd_header.cmd.cmd); - return DRM_ERR(EINVAL); + return -EINVAL; } if (ret != 0) @@ -953,13 +953,12 @@ static int savage_dispatch_draw(drm_savage_private_t * dev_priv, return 0; } -int savage_bci_cmdbuf(DRM_IOCTL_ARGS) +int savage_bci_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_savage_private_t *dev_priv = dev->dev_private; struct drm_device_dma *dma = dev->dma; struct drm_buf *dmabuf; - drm_savage_cmdbuf_t cmdbuf; + drm_savage_cmdbuf_t *cmdbuf = data; drm_savage_cmd_header_t *kcmd_addr = NULL; drm_savage_cmd_header_t *first_draw_cmd; unsigned int *kvb_addr = NULL; @@ -969,19 +968,16 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS) DRM_DEBUG("\n"); - LOCK_TEST_WITH_RETURN(dev, filp); - - DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_savage_cmdbuf_t __user *) data, - sizeof(cmdbuf)); + LOCK_TEST_WITH_RETURN(dev, file_priv); if (dma && dma->buflist) { - if (cmdbuf.dma_idx > dma->buf_count) { + if (cmdbuf->dma_idx > dma->buf_count) { DRM_ERROR ("vertex buffer index %u out of range (0-%u)\n", - cmdbuf.dma_idx, dma->buf_count - 1); - return DRM_ERR(EINVAL); + cmdbuf->dma_idx, dma->buf_count - 1); + return -EINVAL; } - dmabuf = dma->buflist[cmdbuf.dma_idx]; + dmabuf = dma->buflist[cmdbuf->dma_idx]; } else { dmabuf = NULL; } @@ -991,47 +987,47 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS) * COPY_FROM_USER_UNCHECKED when done in other drivers, and is correct * for locking on FreeBSD. */ - if (cmdbuf.size) { - kcmd_addr = drm_alloc(cmdbuf.size * 8, DRM_MEM_DRIVER); + if (cmdbuf->size) { + kcmd_addr = drm_alloc(cmdbuf->size * 8, DRM_MEM_DRIVER); if (kcmd_addr == NULL) - return DRM_ERR(ENOMEM); + return -ENOMEM; - if (DRM_COPY_FROM_USER(kcmd_addr, cmdbuf.cmd_addr, - cmdbuf.size * 8)) + if (DRM_COPY_FROM_USER(kcmd_addr, cmdbuf->cmd_addr, + cmdbuf->size * 8)) { - drm_free(kcmd_addr, cmdbuf.size * 8, DRM_MEM_DRIVER); - return DRM_ERR(EFAULT); + drm_free(kcmd_addr, cmdbuf->size * 8, DRM_MEM_DRIVER); + return -EFAULT; } - cmdbuf.cmd_addr = kcmd_addr; + cmdbuf->cmd_addr = kcmd_addr; } - if (cmdbuf.vb_size) { - kvb_addr = drm_alloc(cmdbuf.vb_size, DRM_MEM_DRIVER); + if (cmdbuf->vb_size) { + kvb_addr = drm_alloc(cmdbuf->vb_size, DRM_MEM_DRIVER); if (kvb_addr == NULL) { - ret = DRM_ERR(ENOMEM); + ret = -ENOMEM; goto done; } - if (DRM_COPY_FROM_USER(kvb_addr, cmdbuf.vb_addr, - cmdbuf.vb_size)) { - ret = DRM_ERR(EFAULT); + if (DRM_COPY_FROM_USER(kvb_addr, cmdbuf->vb_addr, + cmdbuf->vb_size)) { + ret = -EFAULT; goto done; } - cmdbuf.vb_addr = kvb_addr; + cmdbuf->vb_addr = kvb_addr; } - if (cmdbuf.nbox) { - kbox_addr = drm_alloc(cmdbuf.nbox * sizeof(struct drm_clip_rect), + if (cmdbuf->nbox) { + kbox_addr = drm_alloc(cmdbuf->nbox * sizeof(struct drm_clip_rect), DRM_MEM_DRIVER); if (kbox_addr == NULL) { - ret = DRM_ERR(ENOMEM); + ret = -ENOMEM; goto done; } - if (DRM_COPY_FROM_USER(kbox_addr, cmdbuf.box_addr, - cmdbuf.nbox * sizeof(struct drm_clip_rect))) { - ret = DRM_ERR(EFAULT); + if (DRM_COPY_FROM_USER(kbox_addr, cmdbuf->box_addr, + cmdbuf->nbox * sizeof(struct drm_clip_rect))) { + ret = -EFAULT; goto done; } - cmdbuf.box_addr = kbox_addr; + cmdbuf->box_addr = kbox_addr; } /* Make sure writes to DMA buffers are finished before sending @@ -1044,10 +1040,10 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS) i = 0; first_draw_cmd = NULL; - while (i < cmdbuf.size) { + while (i < cmdbuf->size) { drm_savage_cmd_header_t cmd_header; - cmd_header = *(drm_savage_cmd_header_t *)cmdbuf.cmd_addr; - cmdbuf.cmd_addr++; + cmd_header = *(drm_savage_cmd_header_t *)cmdbuf->cmd_addr; + cmdbuf->cmd_addr++; i++; /* Group drawing commands with same state to minimize @@ -1057,28 +1053,28 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS) case SAVAGE_CMD_DMA_IDX: case SAVAGE_CMD_VB_IDX: j = (cmd_header.idx.count + 3) / 4; - if (i + j > cmdbuf.size) { + if (i + j > cmdbuf->size) { DRM_ERROR("indexed drawing command extends " "beyond end of command buffer\n"); DMA_FLUSH(); - return DRM_ERR(EINVAL); + return -EINVAL; } /* fall through */ case SAVAGE_CMD_DMA_PRIM: case SAVAGE_CMD_VB_PRIM: if (!first_draw_cmd) - first_draw_cmd = cmdbuf.cmd_addr - 1; - cmdbuf.cmd_addr += j; + first_draw_cmd = cmdbuf->cmd_addr - 1; + cmdbuf->cmd_addr += j; i += j; break; default: if (first_draw_cmd) { ret = savage_dispatch_draw( dev_priv, first_draw_cmd, - cmdbuf.cmd_addr - 1, - dmabuf, cmdbuf.vb_addr, cmdbuf.vb_size, - cmdbuf.vb_stride, - cmdbuf.nbox, cmdbuf.box_addr); + cmdbuf->cmd_addr - 1, + dmabuf, cmdbuf->vb_addr, cmdbuf->vb_size, + cmdbuf->vb_stride, + cmdbuf->nbox, cmdbuf->box_addr); if (ret != 0) return ret; first_draw_cmd = NULL; @@ -1090,40 +1086,42 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS) switch (cmd_header.cmd.cmd) { case SAVAGE_CMD_STATE: j = (cmd_header.state.count + 1) / 2; - if (i + j > cmdbuf.size) { + if (i + j > cmdbuf->size) { DRM_ERROR("command SAVAGE_CMD_STATE extends " "beyond end of command buffer\n"); DMA_FLUSH(); - ret = DRM_ERR(EINVAL); + ret = -EINVAL; goto done; } ret = savage_dispatch_state(dev_priv, &cmd_header, - (const uint32_t *)cmdbuf.cmd_addr); - cmdbuf.cmd_addr += j; + (const uint32_t *)cmdbuf->cmd_addr); + cmdbuf->cmd_addr += j; i += j; break; case SAVAGE_CMD_CLEAR: - if (i + 1 > cmdbuf.size) { + if (i + 1 > cmdbuf->size) { DRM_ERROR("command SAVAGE_CMD_CLEAR extends " "beyond end of command buffer\n"); DMA_FLUSH(); - ret = DRM_ERR(EINVAL); + ret = -EINVAL; goto done; } ret = savage_dispatch_clear(dev_priv, &cmd_header, - cmdbuf.cmd_addr, - cmdbuf.nbox, cmdbuf.box_addr); - cmdbuf.cmd_addr++; + cmdbuf->cmd_addr, + cmdbuf->nbox, + cmdbuf->box_addr); + cmdbuf->cmd_addr++; i++; break; case SAVAGE_CMD_SWAP: - ret = savage_dispatch_swap(dev_priv, cmdbuf.nbox, - cmdbuf.box_addr); + ret = savage_dispatch_swap(dev_priv, cmdbuf->nbox, + cmdbuf->box_addr); break; default: - DRM_ERROR("invalid command 0x%x\n", cmd_header.cmd.cmd); + DRM_ERROR("invalid command 0x%x\n", + cmd_header.cmd.cmd); DMA_FLUSH(); - ret = DRM_ERR(EINVAL); + ret = -EINVAL; goto done; } @@ -1135,9 +1133,9 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS) if (first_draw_cmd) { ret = savage_dispatch_draw ( - dev_priv, first_draw_cmd, cmdbuf.cmd_addr, dmabuf, - cmdbuf.vb_addr, cmdbuf.vb_size, cmdbuf.vb_stride, - cmdbuf.nbox, cmdbuf.box_addr); + dev_priv, first_draw_cmd, cmdbuf->cmd_addr, dmabuf, + cmdbuf->vb_addr, cmdbuf->vb_size, cmdbuf->vb_stride, + cmdbuf->nbox, cmdbuf->box_addr); if (ret != 0) { DMA_FLUSH(); goto done; @@ -1146,7 +1144,7 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS) DMA_FLUSH(); - if (dmabuf && cmdbuf.discard) { + if (dmabuf && cmdbuf->discard) { drm_savage_buf_priv_t *buf_priv = dmabuf->dev_private; uint16_t event; event = savage_bci_emit_event(dev_priv, SAVAGE_WAIT_3D); @@ -1156,9 +1154,9 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS) done: /* If we didn't need to allocate them, these'll be NULL */ - drm_free(kcmd_addr, cmdbuf.size * 8, DRM_MEM_DRIVER); - drm_free(kvb_addr, cmdbuf.vb_size, DRM_MEM_DRIVER); - drm_free(kbox_addr, cmdbuf.nbox * sizeof(struct drm_clip_rect), + drm_free(kcmd_addr, cmdbuf->size * 8, DRM_MEM_DRIVER); + drm_free(kvb_addr, cmdbuf->vb_size, DRM_MEM_DRIVER); + drm_free(kbox_addr, cmdbuf->nbox * sizeof(struct drm_clip_rect), DRM_MEM_DRIVER); return ret; diff --git a/drivers/char/drm/sis_drv.c b/drivers/char/drm/sis_drv.c index 1912f5857051..7dacc64e9b56 100644 --- a/drivers/char/drm/sis_drv.c +++ b/drivers/char/drm/sis_drv.c @@ -42,7 +42,7 @@ static int sis_driver_load(struct drm_device *dev, unsigned long chipset) dev_priv = drm_calloc(1, sizeof(drm_sis_private_t), DRM_MEM_DRIVER); if (dev_priv == NULL) - return DRM_ERR(ENOMEM); + return -ENOMEM; dev->dev_private = (void *)dev_priv; dev_priv->chipset = chipset; diff --git a/drivers/char/drm/sis_drv.h b/drivers/char/drm/sis_drv.h index 5630df874353..ef940bad63f7 100644 --- a/drivers/char/drm/sis_drv.h +++ b/drivers/char/drm/sis_drv.h @@ -63,10 +63,11 @@ typedef struct drm_sis_private { } drm_sis_private_t; extern int sis_idle(struct drm_device *dev); -extern void sis_reclaim_buffers_locked(struct drm_device *dev, struct file *filp); +extern void sis_reclaim_buffers_locked(struct drm_device *dev, + struct drm_file *file_priv); extern void sis_lastclose(struct drm_device *dev); -extern drm_ioctl_desc_t sis_ioctls[]; +extern struct drm_ioctl_desc sis_ioctls[]; extern int sis_max_ioctl; #endif diff --git a/drivers/char/drm/sis_mm.c b/drivers/char/drm/sis_mm.c index 441bbdbf1510..8c66838ff515 100644 --- a/drivers/char/drm/sis_mm.c +++ b/drivers/char/drm/sis_mm.c @@ -82,15 +82,12 @@ static unsigned long sis_sman_mm_offset(void *private, void *ref) #endif /* CONFIG_FB_SIS */ -static int sis_fb_init(DRM_IOCTL_ARGS) +static int sis_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_sis_private_t *dev_priv = dev->dev_private; - drm_sis_fb_t fb; + drm_sis_fb_t *fb = data; int ret; - DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_fb_t __user *) data, sizeof(fb)); - mutex_lock(&dev->struct_mutex); #if defined(CONFIG_FB_SIS) { @@ -105,7 +102,7 @@ static int sis_fb_init(DRM_IOCTL_ARGS) } #else ret = drm_sman_set_range(&dev_priv->sman, VIDEO_TYPE, 0, - fb.size >> SIS_MM_ALIGN_SHIFT); + fb->size >> SIS_MM_ALIGN_SHIFT); #endif if (ret) { @@ -115,98 +112,87 @@ static int sis_fb_init(DRM_IOCTL_ARGS) } dev_priv->vram_initialized = 1; - dev_priv->vram_offset = fb.offset; + dev_priv->vram_offset = fb->offset; mutex_unlock(&dev->struct_mutex); - DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size); + DRM_DEBUG("offset = %u, size = %u", fb->offset, fb->size); return 0; } -static int sis_drm_alloc(struct drm_device *dev, struct drm_file * priv, - unsigned long data, int pool) +static int sis_drm_alloc(struct drm_device *dev, struct drm_file *file_priv, + void *data, int pool) { drm_sis_private_t *dev_priv = dev->dev_private; - drm_sis_mem_t __user *argp = (drm_sis_mem_t __user *) data; - drm_sis_mem_t mem; + drm_sis_mem_t *mem = data; int retval = 0; struct drm_memblock_item *item; - DRM_COPY_FROM_USER_IOCTL(mem, argp, sizeof(mem)); - mutex_lock(&dev->struct_mutex); if (0 == ((pool == 0) ? dev_priv->vram_initialized : dev_priv->agp_initialized)) { DRM_ERROR ("Attempt to allocate from uninitialized memory manager.\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } - mem.size = (mem.size + SIS_MM_ALIGN_MASK) >> SIS_MM_ALIGN_SHIFT; - item = drm_sman_alloc(&dev_priv->sman, pool, mem.size, 0, - (unsigned long)priv); + mem->size = (mem->size + SIS_MM_ALIGN_MASK) >> SIS_MM_ALIGN_SHIFT; + item = drm_sman_alloc(&dev_priv->sman, pool, mem->size, 0, + (unsigned long)file_priv); mutex_unlock(&dev->struct_mutex); if (item) { - mem.offset = ((pool == 0) ? + mem->offset = ((pool == 0) ? dev_priv->vram_offset : dev_priv->agp_offset) + (item->mm-> offset(item->mm, item->mm_info) << SIS_MM_ALIGN_SHIFT); - mem.free = item->user_hash.key; - mem.size = mem.size << SIS_MM_ALIGN_SHIFT; + mem->free = item->user_hash.key; + mem->size = mem->size << SIS_MM_ALIGN_SHIFT; } else { - mem.offset = 0; - mem.size = 0; - mem.free = 0; - retval = DRM_ERR(ENOMEM); + mem->offset = 0; + mem->size = 0; + mem->free = 0; + retval = -ENOMEM; } - DRM_COPY_TO_USER_IOCTL(argp, mem, sizeof(mem)); - - DRM_DEBUG("alloc %d, size = %d, offset = %d\n", pool, mem.size, - mem.offset); + DRM_DEBUG("alloc %d, size = %d, offset = %d\n", pool, mem->size, + mem->offset); return retval; } -static int sis_drm_free(DRM_IOCTL_ARGS) +static int sis_drm_free(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_sis_private_t *dev_priv = dev->dev_private; - drm_sis_mem_t mem; + drm_sis_mem_t *mem = data; int ret; - DRM_COPY_FROM_USER_IOCTL(mem, (drm_sis_mem_t __user *) data, - sizeof(mem)); - mutex_lock(&dev->struct_mutex); - ret = drm_sman_free_key(&dev_priv->sman, mem.free); + ret = drm_sman_free_key(&dev_priv->sman, mem->free); mutex_unlock(&dev->struct_mutex); - DRM_DEBUG("free = 0x%lx\n", mem.free); + DRM_DEBUG("free = 0x%lx\n", mem->free); return ret; } -static int sis_fb_alloc(DRM_IOCTL_ARGS) +static int sis_fb_alloc(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - DRM_DEVICE; - return sis_drm_alloc(dev, priv, data, VIDEO_TYPE); + return sis_drm_alloc(dev, file_priv, data, VIDEO_TYPE); } -static int sis_ioctl_agp_init(DRM_IOCTL_ARGS) +static int sis_ioctl_agp_init(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - DRM_DEVICE; drm_sis_private_t *dev_priv = dev->dev_private; - drm_sis_agp_t agp; + drm_sis_agp_t *agp = data; int ret; dev_priv = dev->dev_private; - DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_agp_t __user *) data, - sizeof(agp)); mutex_lock(&dev->struct_mutex); ret = drm_sman_set_range(&dev_priv->sman, AGP_TYPE, 0, - agp.size >> SIS_MM_ALIGN_SHIFT); + agp->size >> SIS_MM_ALIGN_SHIFT); if (ret) { DRM_ERROR("AGP memory manager initialisation error\n"); @@ -215,18 +201,18 @@ static int sis_ioctl_agp_init(DRM_IOCTL_ARGS) } dev_priv->agp_initialized = 1; - dev_priv->agp_offset = agp.offset; + dev_priv->agp_offset = agp->offset; mutex_unlock(&dev->struct_mutex); - DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size); + DRM_DEBUG("offset = %u, size = %u", agp->offset, agp->size); return 0; } -static int sis_ioctl_agp_alloc(DRM_IOCTL_ARGS) +static int sis_ioctl_agp_alloc(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - DRM_DEVICE; - return sis_drm_alloc(dev, priv, data, AGP_TYPE); + return sis_drm_alloc(dev, file_priv, data, AGP_TYPE); } static drm_local_map_t *sis_reg_init(struct drm_device *dev) @@ -314,13 +300,13 @@ void sis_lastclose(struct drm_device *dev) mutex_unlock(&dev->struct_mutex); } -void sis_reclaim_buffers_locked(struct drm_device * dev, struct file *filp) +void sis_reclaim_buffers_locked(struct drm_device * dev, + struct drm_file *file_priv) { drm_sis_private_t *dev_priv = dev->dev_private; - struct drm_file *priv = filp->private_data; mutex_lock(&dev->struct_mutex); - if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)priv)) { + if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)file_priv)) { mutex_unlock(&dev->struct_mutex); return; } @@ -329,20 +315,18 @@ void sis_reclaim_buffers_locked(struct drm_device * dev, struct file *filp) dev->driver->dma_quiescent(dev); } - drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)priv); + drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)file_priv); mutex_unlock(&dev->struct_mutex); return; } -drm_ioctl_desc_t sis_ioctls[] = { - [DRM_IOCTL_NR(DRM_SIS_FB_ALLOC)] = {sis_fb_alloc, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_SIS_FB_FREE)] = {sis_drm_free, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_SIS_AGP_INIT)] = - {sis_ioctl_agp_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_SIS_AGP_ALLOC)] = {sis_ioctl_agp_alloc, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_SIS_AGP_FREE)] = {sis_drm_free, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_SIS_FB_INIT)] = - {sis_fb_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY} +struct drm_ioctl_desc sis_ioctls[] = { + DRM_IOCTL_DEF(DRM_SIS_FB_ALLOC, sis_fb_alloc, DRM_AUTH), + DRM_IOCTL_DEF(DRM_SIS_FB_FREE, sis_drm_free, DRM_AUTH), + DRM_IOCTL_DEF(DRM_SIS_AGP_INIT, sis_ioctl_agp_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_SIS_AGP_ALLOC, sis_ioctl_agp_alloc, DRM_AUTH), + DRM_IOCTL_DEF(DRM_SIS_AGP_FREE, sis_drm_free, DRM_AUTH), + DRM_IOCTL_DEF(DRM_SIS_FB_INIT, sis_fb_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY), }; int sis_max_ioctl = DRM_ARRAY_SIZE(sis_ioctls); diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c index 7ff2b623c2d4..75d6b748c2c0 100644 --- a/drivers/char/drm/via_dma.c +++ b/drivers/char/drm/via_dma.c @@ -175,24 +175,24 @@ static int via_initialize(struct drm_device * dev, { if (!dev_priv || !dev_priv->mmio) { DRM_ERROR("via_dma_init called before via_map_init\n"); - return DRM_ERR(EFAULT); + return -EFAULT; } if (dev_priv->ring.virtual_start != NULL) { DRM_ERROR("%s called again without calling cleanup\n", __FUNCTION__); - return DRM_ERR(EFAULT); + return -EFAULT; } if (!dev->agp || !dev->agp->base) { DRM_ERROR("%s called with no agp memory available\n", __FUNCTION__); - return DRM_ERR(EFAULT); + return -EFAULT; } if (dev_priv->chipset == VIA_DX9_0) { DRM_ERROR("AGP DMA is not supported on this chip\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } dev_priv->ring.map.offset = dev->agp->base + init->offset; @@ -207,7 +207,7 @@ static int via_initialize(struct drm_device * dev, via_dma_cleanup(dev); DRM_ERROR("can not ioremap virtual address for" " ring buffer\n"); - return DRM_ERR(ENOMEM); + return -ENOMEM; } dev_priv->ring.virtual_start = dev_priv->ring.map.handle; @@ -227,35 +227,31 @@ static int via_initialize(struct drm_device * dev, return 0; } -static int via_dma_init(DRM_IOCTL_ARGS) +static int via_dma_init(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; - drm_via_dma_init_t init; + drm_via_dma_init_t *init = data; int retcode = 0; - DRM_COPY_FROM_USER_IOCTL(init, (drm_via_dma_init_t __user *) data, - sizeof(init)); - - switch (init.func) { + switch (init->func) { case VIA_INIT_DMA: if (!DRM_SUSER(DRM_CURPROC)) - retcode = DRM_ERR(EPERM); + retcode = -EPERM; else - retcode = via_initialize(dev, dev_priv, &init); + retcode = via_initialize(dev, dev_priv, init); break; case VIA_CLEANUP_DMA: if (!DRM_SUSER(DRM_CURPROC)) - retcode = DRM_ERR(EPERM); + retcode = -EPERM; else retcode = via_dma_cleanup(dev); break; case VIA_DMA_INITIALIZED: retcode = (dev_priv->ring.virtual_start != NULL) ? - 0 : DRM_ERR(EFAULT); + 0 : -EFAULT; break; default: - retcode = DRM_ERR(EINVAL); + retcode = -EINVAL; break; } @@ -273,15 +269,15 @@ static int via_dispatch_cmdbuffer(struct drm_device * dev, drm_via_cmdbuffer_t * if (dev_priv->ring.virtual_start == NULL) { DRM_ERROR("%s called without initializing AGP ring buffer.\n", __FUNCTION__); - return DRM_ERR(EFAULT); + return -EFAULT; } if (cmd->size > VIA_PCI_BUF_SIZE) { - return DRM_ERR(ENOMEM); + return -ENOMEM; } if (DRM_COPY_FROM_USER(dev_priv->pci_buf, cmd->buf, cmd->size)) - return DRM_ERR(EFAULT); + return -EFAULT; /* * Running this function on AGP memory is dead slow. Therefore @@ -297,7 +293,7 @@ static int via_dispatch_cmdbuffer(struct drm_device * dev, drm_via_cmdbuffer_t * vb = via_check_dma(dev_priv, (cmd->size < 0x100) ? 0x102 : cmd->size); if (vb == NULL) { - return DRM_ERR(EAGAIN); + return -EAGAIN; } memcpy(vb, dev_priv->pci_buf, cmd->size); @@ -321,34 +317,30 @@ int via_driver_dma_quiescent(struct drm_device * dev) drm_via_private_t *dev_priv = dev->dev_private; if (!via_wait_idle(dev_priv)) { - return DRM_ERR(EBUSY); + return -EBUSY; } return 0; } -static int via_flush_ioctl(DRM_IOCTL_ARGS) +static int via_flush_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); return via_driver_dma_quiescent(dev); } -static int via_cmdbuffer(DRM_IOCTL_ARGS) +static int via_cmdbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; - drm_via_cmdbuffer_t cmdbuf; + drm_via_cmdbuffer_t *cmdbuf = data; int ret; - LOCK_TEST_WITH_RETURN(dev, filp); - - DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_via_cmdbuffer_t __user *) data, - sizeof(cmdbuf)); + LOCK_TEST_WITH_RETURN(dev, file_priv); - DRM_DEBUG("via cmdbuffer, buf %p size %lu\n", cmdbuf.buf, cmdbuf.size); + DRM_DEBUG("via cmdbuffer, buf %p size %lu\n", cmdbuf->buf, + cmdbuf->size); - ret = via_dispatch_cmdbuffer(dev, &cmdbuf); + ret = via_dispatch_cmdbuffer(dev, cmdbuf); if (ret) { return ret; } @@ -363,10 +355,10 @@ static int via_dispatch_pci_cmdbuffer(struct drm_device * dev, int ret; if (cmd->size > VIA_PCI_BUF_SIZE) { - return DRM_ERR(ENOMEM); + return -ENOMEM; } if (DRM_COPY_FROM_USER(dev_priv->pci_buf, cmd->buf, cmd->size)) - return DRM_ERR(EFAULT); + return -EFAULT; if ((ret = via_verify_command_stream((uint32_t *) dev_priv->pci_buf, @@ -380,21 +372,17 @@ static int via_dispatch_pci_cmdbuffer(struct drm_device * dev, return ret; } -static int via_pci_cmdbuffer(DRM_IOCTL_ARGS) +static int via_pci_cmdbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; - drm_via_cmdbuffer_t cmdbuf; + drm_via_cmdbuffer_t *cmdbuf = data; int ret; - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); - DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_via_cmdbuffer_t __user *) data, - sizeof(cmdbuf)); + DRM_DEBUG("via_pci_cmdbuffer, buf %p size %lu\n", cmdbuf->buf, + cmdbuf->size); - DRM_DEBUG("via_pci_cmdbuffer, buf %p size %lu\n", cmdbuf.buf, - cmdbuf.size); - - ret = via_dispatch_pci_cmdbuffer(dev, &cmdbuf); + ret = via_dispatch_pci_cmdbuffer(dev, cmdbuf); if (ret) { return ret; } @@ -653,80 +641,74 @@ static void via_cmdbuf_reset(drm_via_private_t * dev_priv) * User interface to the space and lag functions. */ -static int via_cmdbuf_size(DRM_IOCTL_ARGS) +static int via_cmdbuf_size(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; - drm_via_cmdbuf_size_t d_siz; + drm_via_cmdbuf_size_t *d_siz = data; int ret = 0; uint32_t tmp_size, count; drm_via_private_t *dev_priv; DRM_DEBUG("via cmdbuf_size\n"); - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, file_priv); dev_priv = (drm_via_private_t *) dev->dev_private; if (dev_priv->ring.virtual_start == NULL) { DRM_ERROR("%s called without initializing AGP ring buffer.\n", __FUNCTION__); - return DRM_ERR(EFAULT); + return -EFAULT; } - DRM_COPY_FROM_USER_IOCTL(d_siz, (drm_via_cmdbuf_size_t __user *) data, - sizeof(d_siz)); - count = 1000000; - tmp_size = d_siz.size; - switch (d_siz.func) { + tmp_size = d_siz->size; + switch (d_siz->func) { case VIA_CMDBUF_SPACE: - while (((tmp_size = via_cmdbuf_space(dev_priv)) < d_siz.size) + while (((tmp_size = via_cmdbuf_space(dev_priv)) < d_siz->size) && count--) { - if (!d_siz.wait) { + if (!d_siz->wait) { break; } } if (!count) { DRM_ERROR("VIA_CMDBUF_SPACE timed out.\n"); - ret = DRM_ERR(EAGAIN); + ret = -EAGAIN; } break; case VIA_CMDBUF_LAG: - while (((tmp_size = via_cmdbuf_lag(dev_priv)) > d_siz.size) + while (((tmp_size = via_cmdbuf_lag(dev_priv)) > d_siz->size) && count--) { - if (!d_siz.wait) { + if (!d_siz->wait) { break; } } if (!count) { DRM_ERROR("VIA_CMDBUF_LAG timed out.\n"); - ret = DRM_ERR(EAGAIN); + ret = -EAGAIN; } break; default: - ret = DRM_ERR(EFAULT); + ret = -EFAULT; } - d_siz.size = tmp_size; + d_siz->size = tmp_size; - DRM_COPY_TO_USER_IOCTL((drm_via_cmdbuf_size_t __user *) data, d_siz, - sizeof(d_siz)); return ret; } -drm_ioctl_desc_t via_ioctls[] = { - [DRM_IOCTL_NR(DRM_VIA_ALLOCMEM)] = {via_mem_alloc, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_VIA_FREEMEM)] = {via_mem_free, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_VIA_AGP_INIT)] = {via_agp_init, DRM_AUTH|DRM_MASTER}, - [DRM_IOCTL_NR(DRM_VIA_FB_INIT)] = {via_fb_init, DRM_AUTH|DRM_MASTER}, - [DRM_IOCTL_NR(DRM_VIA_MAP_INIT)] = {via_map_init, DRM_AUTH|DRM_MASTER}, - [DRM_IOCTL_NR(DRM_VIA_DEC_FUTEX)] = {via_decoder_futex, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_VIA_DMA_INIT)] = {via_dma_init, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_VIA_CMDBUFFER)] = {via_cmdbuffer, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_VIA_FLUSH)] = {via_flush_ioctl, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_VIA_PCICMD)] = {via_pci_cmdbuffer, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_VIA_CMDBUF_SIZE)] = {via_cmdbuf_size, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_VIA_WAIT_IRQ)] = {via_wait_irq, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_VIA_DMA_BLIT)] = {via_dma_blit, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_VIA_BLIT_SYNC)] = {via_dma_blit_sync, DRM_AUTH} +struct drm_ioctl_desc via_ioctls[] = { + DRM_IOCTL_DEF(DRM_VIA_ALLOCMEM, via_mem_alloc, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_FREEMEM, via_mem_free, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_AGP_INIT, via_agp_init, DRM_AUTH|DRM_MASTER), + DRM_IOCTL_DEF(DRM_VIA_FB_INIT, via_fb_init, DRM_AUTH|DRM_MASTER), + DRM_IOCTL_DEF(DRM_VIA_MAP_INIT, via_map_init, DRM_AUTH|DRM_MASTER), + DRM_IOCTL_DEF(DRM_VIA_DEC_FUTEX, via_decoder_futex, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_DMA_INIT, via_dma_init, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CMDBUFFER, via_cmdbuffer, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_FLUSH, via_flush_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_PCICMD, via_pci_cmdbuffer, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CMDBUF_SIZE, via_cmdbuf_size, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_WAIT_IRQ, via_wait_irq, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_DMA_BLIT, via_dma_blit, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_BLIT_SYNC, via_dma_blit_sync, DRM_AUTH) }; int via_max_ioctl = DRM_ARRAY_SIZE(via_ioctls); diff --git a/drivers/char/drm/via_dmablit.c b/drivers/char/drm/via_dmablit.c index 3dd1ed3d1bf5..c6fd16f3cb43 100644 --- a/drivers/char/drm/via_dmablit.c +++ b/drivers/char/drm/via_dmablit.c @@ -237,7 +237,7 @@ via_lock_all_dma_pages(drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer) first_pfn + 1; if (NULL == (vsg->pages = vmalloc(sizeof(struct page *) * vsg->num_pages))) - return DRM_ERR(ENOMEM); + return -ENOMEM; memset(vsg->pages, 0, sizeof(struct page *) * vsg->num_pages); down_read(¤t->mm->mmap_sem); ret = get_user_pages(current, current->mm, @@ -251,7 +251,7 @@ via_lock_all_dma_pages(drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer) if (ret < 0) return ret; vsg->state = dr_via_pages_locked; - return DRM_ERR(EINVAL); + return -EINVAL; } vsg->state = dr_via_pages_locked; DRM_DEBUG("DMA pages locked\n"); @@ -274,13 +274,13 @@ via_alloc_desc_pages(drm_via_sg_info_t *vsg) vsg->descriptors_per_page; if (NULL == (vsg->desc_pages = kcalloc(vsg->num_desc_pages, sizeof(void *), GFP_KERNEL))) - return DRM_ERR(ENOMEM); + return -ENOMEM; vsg->state = dr_via_desc_pages_alloc; for (i=0; i<vsg->num_desc_pages; ++i) { if (NULL == (vsg->desc_pages[i] = (drm_via_descriptor_t *) __get_free_page(GFP_KERNEL))) - return DRM_ERR(ENOMEM); + return -ENOMEM; } DRM_DEBUG("Allocated %d pages for %d descriptors.\n", vsg->num_desc_pages, vsg->num_desc); @@ -593,7 +593,7 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli if (xfer->num_lines <= 0 || xfer->line_length <= 0) { DRM_ERROR("Zero size bitblt.\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } /* @@ -606,7 +606,7 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli if ((xfer->mem_stride - xfer->line_length) >= PAGE_SIZE) { DRM_ERROR("Too large system memory stride. Stride: %d, " "Length: %d\n", xfer->mem_stride, xfer->line_length); - return DRM_ERR(EINVAL); + return -EINVAL; } if ((xfer->mem_stride == xfer->line_length) && @@ -624,7 +624,7 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli if (xfer->num_lines > 2048 || (xfer->num_lines*xfer->mem_stride > (2048*2048*4))) { DRM_ERROR("Too large PCI DMA bitblt.\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } /* @@ -635,7 +635,7 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli if (xfer->mem_stride < xfer->line_length || abs(xfer->fb_stride) < xfer->line_length) { DRM_ERROR("Invalid frame-buffer / memory stride.\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } /* @@ -648,7 +648,7 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli if ((((unsigned long)xfer->mem_addr & 3) != ((unsigned long)xfer->fb_addr & 3)) || ((xfer->num_lines > 1) && ((xfer->mem_stride & 3) != (xfer->fb_stride & 3)))) { DRM_ERROR("Invalid DRM bitblt alignment.\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } #else if ((((unsigned long)xfer->mem_addr & 15) || @@ -656,7 +656,7 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli ((xfer->num_lines > 1) && ((xfer->mem_stride & 15) || (xfer->fb_stride & 3)))) { DRM_ERROR("Invalid DRM bitblt alignment.\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } #endif @@ -696,7 +696,7 @@ via_dmablit_grab_slot(drm_via_blitq_t *blitq, int engine) DRM_WAIT_ON(ret, blitq->busy_queue, DRM_HZ, blitq->num_free > 0); if (ret) { - return (DRM_ERR(EINTR) == ret) ? DRM_ERR(EAGAIN) : ret; + return (-EINTR == ret) ? -EAGAIN : ret; } spin_lock_irqsave(&blitq->blit_lock, irqsave); @@ -740,7 +740,7 @@ via_dmablit(struct drm_device *dev, drm_via_dmablit_t *xfer) if (dev_priv == NULL) { DRM_ERROR("Called without initialization.\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } engine = (xfer->to_fb) ? 0 : 1; @@ -750,7 +750,7 @@ via_dmablit(struct drm_device *dev, drm_via_dmablit_t *xfer) } if (NULL == (vsg = kmalloc(sizeof(*vsg), GFP_KERNEL))) { via_dmablit_release_slot(blitq); - return DRM_ERR(ENOMEM); + return -ENOMEM; } if (0 != (ret = via_build_sg_info(dev, vsg, xfer))) { via_dmablit_release_slot(blitq); @@ -781,21 +781,18 @@ via_dmablit(struct drm_device *dev, drm_via_dmablit_t *xfer) */ int -via_dma_blit_sync( DRM_IOCTL_ARGS ) +via_dma_blit_sync( struct drm_device *dev, void *data, struct drm_file *file_priv ) { - drm_via_blitsync_t sync; + drm_via_blitsync_t *sync = data; int err; - DRM_DEVICE; - DRM_COPY_FROM_USER_IOCTL(sync, (drm_via_blitsync_t *)data, sizeof(sync)); - - if (sync.engine >= VIA_NUM_BLIT_ENGINES) - return DRM_ERR(EINVAL); + if (sync->engine >= VIA_NUM_BLIT_ENGINES) + return -EINVAL; - err = via_dmablit_sync(dev, sync.sync_handle, sync.engine); + err = via_dmablit_sync(dev, sync->sync_handle, sync->engine); - if (DRM_ERR(EINTR) == err) - err = DRM_ERR(EAGAIN); + if (-EINTR == err) + err = -EAGAIN; return err; } @@ -808,17 +805,12 @@ via_dma_blit_sync( DRM_IOCTL_ARGS ) */ int -via_dma_blit( DRM_IOCTL_ARGS ) +via_dma_blit( struct drm_device *dev, void *data, struct drm_file *file_priv ) { - drm_via_dmablit_t xfer; + drm_via_dmablit_t *xfer = data; int err; - DRM_DEVICE; - - DRM_COPY_FROM_USER_IOCTL(xfer, (drm_via_dmablit_t __user *)data, sizeof(xfer)); - - err = via_dmablit(dev, &xfer); - DRM_COPY_TO_USER_IOCTL((void __user *)data, xfer, sizeof(xfer)); + err = via_dmablit(dev, xfer); return err; } diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h index 576711564a11..2daae81874cd 100644 --- a/drivers/char/drm/via_drv.h +++ b/drivers/char/drm/via_drv.h @@ -110,18 +110,18 @@ enum via_family { #define VIA_READ8(reg) DRM_READ8(VIA_BASE, reg) #define VIA_WRITE8(reg,val) DRM_WRITE8(VIA_BASE, reg, val) -extern drm_ioctl_desc_t via_ioctls[]; +extern struct drm_ioctl_desc via_ioctls[]; extern int via_max_ioctl; -extern int via_fb_init(DRM_IOCTL_ARGS); -extern int via_mem_alloc(DRM_IOCTL_ARGS); -extern int via_mem_free(DRM_IOCTL_ARGS); -extern int via_agp_init(DRM_IOCTL_ARGS); -extern int via_map_init(DRM_IOCTL_ARGS); -extern int via_decoder_futex(DRM_IOCTL_ARGS); -extern int via_wait_irq(DRM_IOCTL_ARGS); -extern int via_dma_blit_sync( DRM_IOCTL_ARGS ); -extern int via_dma_blit( DRM_IOCTL_ARGS ); +extern int via_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int via_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int via_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int via_agp_init(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int via_map_init(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int via_decoder_futex(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int via_dma_blit_sync( struct drm_device *dev, void *data, struct drm_file *file_priv ); +extern int via_dma_blit( struct drm_device *dev, void *data, struct drm_file *file_priv ); extern int via_driver_load(struct drm_device *dev, unsigned long chipset); extern int via_driver_unload(struct drm_device *dev); @@ -144,7 +144,7 @@ extern void via_init_futex(drm_via_private_t * dev_priv); extern void via_cleanup_futex(drm_via_private_t * dev_priv); extern void via_release_futex(drm_via_private_t * dev_priv, int context); -extern void via_reclaim_buffers_locked(struct drm_device *dev, struct file *filp); +extern void via_reclaim_buffers_locked(struct drm_device *dev, struct drm_file *file_priv); extern void via_lastclose(struct drm_device *dev); extern void via_dmablit_handler(struct drm_device *dev, int engine, int from_irq); diff --git a/drivers/char/drm/via_irq.c b/drivers/char/drm/via_irq.c index 8dc99b5fbab6..9c1d52bc92d7 100644 --- a/drivers/char/drm/via_irq.c +++ b/drivers/char/drm/via_irq.c @@ -205,13 +205,13 @@ via_driver_irq_wait(struct drm_device * dev, unsigned int irq, int force_sequenc if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); + return -EINVAL; } if (irq >= drm_via_irq_num) { DRM_ERROR("%s Trying to wait on unknown irq %d\n", __FUNCTION__, irq); - return DRM_ERR(EINVAL); + return -EINVAL; } real_irq = dev_priv->irq_map[irq]; @@ -219,7 +219,7 @@ via_driver_irq_wait(struct drm_device * dev, unsigned int irq, int force_sequenc if (real_irq < 0) { DRM_ERROR("%s Video IRQ %d not available on this hardware.\n", __FUNCTION__, irq); - return DRM_ERR(EINVAL); + return -EINVAL; } masks = dev_priv->irq_masks; @@ -331,11 +331,9 @@ void via_driver_irq_uninstall(struct drm_device * dev) } } -int via_wait_irq(DRM_IOCTL_ARGS) +int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; - drm_via_irqwait_t __user *argp = (void __user *)data; - drm_via_irqwait_t irqwait; + drm_via_irqwait_t *irqwait = data; struct timeval now; int ret = 0; drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; @@ -343,42 +341,39 @@ int via_wait_irq(DRM_IOCTL_ARGS) int force_sequence; if (!dev->irq) - return DRM_ERR(EINVAL); + return -EINVAL; - DRM_COPY_FROM_USER_IOCTL(irqwait, argp, sizeof(irqwait)); - if (irqwait.request.irq >= dev_priv->num_irqs) { + if (irqwait->request.irq >= dev_priv->num_irqs) { DRM_ERROR("%s Trying to wait on unknown irq %d\n", __FUNCTION__, - irqwait.request.irq); - return DRM_ERR(EINVAL); + irqwait->request.irq); + return -EINVAL; } - cur_irq += irqwait.request.irq; + cur_irq += irqwait->request.irq; - switch (irqwait.request.type & ~VIA_IRQ_FLAGS_MASK) { + switch (irqwait->request.type & ~VIA_IRQ_FLAGS_MASK) { case VIA_IRQ_RELATIVE: - irqwait.request.sequence += atomic_read(&cur_irq->irq_received); - irqwait.request.type &= ~_DRM_VBLANK_RELATIVE; + irqwait->request.sequence += atomic_read(&cur_irq->irq_received); + irqwait->request.type &= ~_DRM_VBLANK_RELATIVE; case VIA_IRQ_ABSOLUTE: break; default: - return DRM_ERR(EINVAL); + return -EINVAL; } - if (irqwait.request.type & VIA_IRQ_SIGNAL) { + if (irqwait->request.type & VIA_IRQ_SIGNAL) { DRM_ERROR("%s Signals on Via IRQs not implemented yet.\n", __FUNCTION__); - return DRM_ERR(EINVAL); + return -EINVAL; } - force_sequence = (irqwait.request.type & VIA_IRQ_FORCE_SEQUENCE); + force_sequence = (irqwait->request.type & VIA_IRQ_FORCE_SEQUENCE); - ret = via_driver_irq_wait(dev, irqwait.request.irq, force_sequence, - &irqwait.request.sequence); + ret = via_driver_irq_wait(dev, irqwait->request.irq, force_sequence, + &irqwait->request.sequence); do_gettimeofday(&now); - irqwait.reply.tval_sec = now.tv_sec; - irqwait.reply.tval_usec = now.tv_usec; - - DRM_COPY_TO_USER_IOCTL(argp, irqwait, sizeof(irqwait)); + irqwait->reply.tval_sec = now.tv_sec; + irqwait->reply.tval_usec = now.tv_usec; return ret; } diff --git a/drivers/char/drm/via_map.c b/drivers/char/drm/via_map.c index 7fb9d2a2cce2..10091507a0dc 100644 --- a/drivers/char/drm/via_map.c +++ b/drivers/char/drm/via_map.c @@ -75,19 +75,15 @@ int via_do_cleanup_map(struct drm_device * dev) return 0; } -int via_map_init(DRM_IOCTL_ARGS) +int via_map_init(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; - drm_via_init_t init; + drm_via_init_t *init = data; DRM_DEBUG("%s\n", __FUNCTION__); - DRM_COPY_FROM_USER_IOCTL(init, (drm_via_init_t __user *) data, - sizeof(init)); - - switch (init.func) { + switch (init->func) { case VIA_INIT_MAP: - return via_do_init_map(dev, &init); + return via_do_init_map(dev, init); case VIA_CLEANUP_MAP: return via_do_cleanup_map(dev); } @@ -102,7 +98,7 @@ int via_driver_load(struct drm_device *dev, unsigned long chipset) dev_priv = drm_calloc(1, sizeof(drm_via_private_t), DRM_MEM_DRIVER); if (dev_priv == NULL) - return DRM_ERR(ENOMEM); + return -ENOMEM; dev->dev_private = (void *)dev_priv; diff --git a/drivers/char/drm/via_mm.c b/drivers/char/drm/via_mm.c index 85d56acd9d82..9afc1684348d 100644 --- a/drivers/char/drm/via_mm.c +++ b/drivers/char/drm/via_mm.c @@ -33,18 +33,15 @@ #define VIA_MM_ALIGN_SHIFT 4 #define VIA_MM_ALIGN_MASK ( (1 << VIA_MM_ALIGN_SHIFT) - 1) -int via_agp_init(DRM_IOCTL_ARGS) +int via_agp_init(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; - drm_via_agp_t agp; + drm_via_agp_t *agp = data; drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; int ret; - DRM_COPY_FROM_USER_IOCTL(agp, (drm_via_agp_t __user *) data, - sizeof(agp)); mutex_lock(&dev->struct_mutex); ret = drm_sman_set_range(&dev_priv->sman, VIA_MEM_AGP, 0, - agp.size >> VIA_MM_ALIGN_SHIFT); + agp->size >> VIA_MM_ALIGN_SHIFT); if (ret) { DRM_ERROR("AGP memory manager initialisation error\n"); @@ -53,25 +50,22 @@ int via_agp_init(DRM_IOCTL_ARGS) } dev_priv->agp_initialized = 1; - dev_priv->agp_offset = agp.offset; + dev_priv->agp_offset = agp->offset; mutex_unlock(&dev->struct_mutex); - DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size); + DRM_DEBUG("offset = %u, size = %u", agp->offset, agp->size); return 0; } -int via_fb_init(DRM_IOCTL_ARGS) +int via_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; - drm_via_fb_t fb; + drm_via_fb_t *fb = data; drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; int ret; - DRM_COPY_FROM_USER_IOCTL(fb, (drm_via_fb_t __user *) data, sizeof(fb)); - mutex_lock(&dev->struct_mutex); ret = drm_sman_set_range(&dev_priv->sman, VIA_MEM_VIDEO, 0, - fb.size >> VIA_MM_ALIGN_SHIFT); + fb->size >> VIA_MM_ALIGN_SHIFT); if (ret) { DRM_ERROR("VRAM memory manager initialisation error\n"); @@ -80,10 +74,10 @@ int via_fb_init(DRM_IOCTL_ARGS) } dev_priv->vram_initialized = 1; - dev_priv->vram_offset = fb.offset; + dev_priv->vram_offset = fb->offset; mutex_unlock(&dev->struct_mutex); - DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size); + DRM_DEBUG("offset = %u, size = %u", fb->offset, fb->size); return 0; @@ -121,80 +115,71 @@ void via_lastclose(struct drm_device *dev) mutex_unlock(&dev->struct_mutex); } -int via_mem_alloc(DRM_IOCTL_ARGS) +int via_mem_alloc(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - DRM_DEVICE; - - drm_via_mem_t mem; + drm_via_mem_t *mem = data; int retval = 0; struct drm_memblock_item *item; drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; unsigned long tmpSize; - DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t __user *) data, - sizeof(mem)); - - if (mem.type > VIA_MEM_AGP) { + if (mem->type > VIA_MEM_AGP) { DRM_ERROR("Unknown memory type allocation\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } mutex_lock(&dev->struct_mutex); - if (0 == ((mem.type == VIA_MEM_VIDEO) ? dev_priv->vram_initialized : + if (0 == ((mem->type == VIA_MEM_VIDEO) ? dev_priv->vram_initialized : dev_priv->agp_initialized)) { DRM_ERROR ("Attempt to allocate from uninitialized memory manager.\n"); mutex_unlock(&dev->struct_mutex); - return DRM_ERR(EINVAL); + return -EINVAL; } - tmpSize = (mem.size + VIA_MM_ALIGN_MASK) >> VIA_MM_ALIGN_SHIFT; - item = drm_sman_alloc(&dev_priv->sman, mem.type, tmpSize, 0, - (unsigned long)priv); + tmpSize = (mem->size + VIA_MM_ALIGN_MASK) >> VIA_MM_ALIGN_SHIFT; + item = drm_sman_alloc(&dev_priv->sman, mem->type, tmpSize, 0, + (unsigned long)file_priv); mutex_unlock(&dev->struct_mutex); if (item) { - mem.offset = ((mem.type == VIA_MEM_VIDEO) ? + mem->offset = ((mem->type == VIA_MEM_VIDEO) ? dev_priv->vram_offset : dev_priv->agp_offset) + (item->mm-> offset(item->mm, item->mm_info) << VIA_MM_ALIGN_SHIFT); - mem.index = item->user_hash.key; + mem->index = item->user_hash.key; } else { - mem.offset = 0; - mem.size = 0; - mem.index = 0; + mem->offset = 0; + mem->size = 0; + mem->index = 0; DRM_DEBUG("Video memory allocation failed\n"); - retval = DRM_ERR(ENOMEM); + retval = -ENOMEM; } - DRM_COPY_TO_USER_IOCTL((drm_via_mem_t __user *) data, mem, sizeof(mem)); return retval; } -int via_mem_free(DRM_IOCTL_ARGS) +int via_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; drm_via_private_t *dev_priv = dev->dev_private; - drm_via_mem_t mem; + drm_via_mem_t *mem = data; int ret; - DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t __user *) data, - sizeof(mem)); - mutex_lock(&dev->struct_mutex); - ret = drm_sman_free_key(&dev_priv->sman, mem.index); + ret = drm_sman_free_key(&dev_priv->sman, mem->index); mutex_unlock(&dev->struct_mutex); - DRM_DEBUG("free = 0x%lx\n", mem.index); + DRM_DEBUG("free = 0x%lx\n", mem->index); return ret; } -void via_reclaim_buffers_locked(struct drm_device * dev, struct file *filp) +void via_reclaim_buffers_locked(struct drm_device * dev, + struct drm_file *file_priv) { drm_via_private_t *dev_priv = dev->dev_private; - struct drm_file *priv = filp->private_data; mutex_lock(&dev->struct_mutex); - if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)priv)) { + if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)file_priv)) { mutex_unlock(&dev->struct_mutex); return; } @@ -203,7 +188,7 @@ void via_reclaim_buffers_locked(struct drm_device * dev, struct file *filp) dev->driver->dma_quiescent(dev); } - drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)priv); + drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)file_priv); mutex_unlock(&dev->struct_mutex); return; } diff --git a/drivers/char/drm/via_verifier.c b/drivers/char/drm/via_verifier.c index 832d48356e91..46a579198747 100644 --- a/drivers/char/drm/via_verifier.c +++ b/drivers/char/drm/via_verifier.c @@ -1026,12 +1026,12 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size, case state_error: default: *hc_state = saved_state; - return DRM_ERR(EINVAL); + return -EINVAL; } } if (state == state_error) { *hc_state = saved_state; - return DRM_ERR(EINVAL); + return -EINVAL; } return 0; } @@ -1082,11 +1082,11 @@ via_parse_command_stream(struct drm_device * dev, const uint32_t * buf, break; case state_error: default: - return DRM_ERR(EINVAL); + return -EINVAL; } } if (state == state_error) { - return DRM_ERR(EINVAL); + return -EINVAL; } return 0; } diff --git a/drivers/char/drm/via_video.c b/drivers/char/drm/via_video.c index 300ac61b09ed..c15e75b54cb1 100644 --- a/drivers/char/drm/via_video.c +++ b/drivers/char/drm/via_video.c @@ -65,10 +65,9 @@ void via_release_futex(drm_via_private_t * dev_priv, int context) } } -int via_decoder_futex(DRM_IOCTL_ARGS) +int via_decoder_futex(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; - drm_via_futex_t fx; + drm_via_futex_t *fx = data; volatile int *lock; drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; drm_via_sarea_t *sAPriv = dev_priv->sarea_priv; @@ -76,21 +75,18 @@ int via_decoder_futex(DRM_IOCTL_ARGS) DRM_DEBUG("%s\n", __FUNCTION__); - DRM_COPY_FROM_USER_IOCTL(fx, (drm_via_futex_t __user *) data, - sizeof(fx)); - - if (fx.lock > VIA_NR_XVMC_LOCKS) + if (fx->lock > VIA_NR_XVMC_LOCKS) return -EFAULT; - lock = (volatile int *)XVMCLOCKPTR(sAPriv, fx.lock); + lock = (volatile int *)XVMCLOCKPTR(sAPriv, fx->lock); - switch (fx.func) { + switch (fx->func) { case VIA_FUTEX_WAIT: - DRM_WAIT_ON(ret, dev_priv->decoder_queue[fx.lock], - (fx.ms / 10) * (DRM_HZ / 100), *lock != fx.val); + DRM_WAIT_ON(ret, dev_priv->decoder_queue[fx->lock], + (fx->ms / 10) * (DRM_HZ / 100), *lock != fx->val); return ret; case VIA_FUTEX_WAKE: - DRM_WAKEUP(&(dev_priv->decoder_queue[fx.lock])); + DRM_WAKEUP(&(dev_priv->decoder_queue[fx->lock])); return 0; } return 0; diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c index 9b8278e1f4f8..a69c65283260 100644 --- a/drivers/char/dsp56k.c +++ b/drivers/char/dsp56k.c @@ -136,7 +136,7 @@ static int sizeof_bootstrap = 375; static struct dsp56k_device { - long in_use; + unsigned long in_use; long maxio, timeout; int tx_wsize, rx_wsize; } dsp56k; @@ -513,7 +513,7 @@ static int __init dsp56k_init_driver(void) err = PTR_ERR(dsp56k_class); goto out_chrdev; } - class_device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), NULL, "dsp56k"); + device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), "dsp56k"); printk(banner); goto out; @@ -527,7 +527,7 @@ module_init(dsp56k_init_driver); static void __exit dsp56k_cleanup_driver(void) { - class_device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0)); + device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0)); class_destroy(dsp56k_class); unregister_chrdev(DSP56K_MAJOR, "dsp56k"); } diff --git a/drivers/char/ec3104_keyb.c b/drivers/char/ec3104_keyb.c deleted file mode 100644 index 020011495d91..000000000000 --- a/drivers/char/ec3104_keyb.c +++ /dev/null @@ -1,457 +0,0 @@ -/* - * linux/drivers/char/ec3104_keyb.c - * - * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> - * - * based on linux/drivers/char/pc_keyb.c, which had the following comments: - * - * Separation of the PC low-level part by Geert Uytterhoeven, May 1997 - * See keyboard.c for the whole history. - * - * Major cleanup by Martin Mares, May 1997 - * - * Combined the keyboard and PS/2 mouse handling into one file, - * because they share the same hardware. - * Johan Myreen <jem@iki.fi> 1998-10-08. - * - * Code fixes to handle mouse ACKs properly. - * C. Scott Ananian <cananian@alumni.princeton.edu> 1999-01-29. - */ -/* EC3104 note: - * This code was written without any documentation about the EC3104 chip. While - * I hope I got most of the basic functionality right, the register names I use - * are most likely completely different from those in the chip documentation. - * - * If you have any further information about the EC3104, please tell me - * (prumpf@tux.org). - */ - - -#include <linux/spinlock.h> -#include <linux/sched.h> -#include <linux/interrupt.h> -#include <linux/tty.h> -#include <linux/mm.h> -#include <linux/signal.h> -#include <linux/init.h> -#include <linux/kbd_ll.h> -#include <linux/delay.h> -#include <linux/random.h> -#include <linux/poll.h> -#include <linux/miscdevice.h> -#include <linux/slab.h> -#include <linux/kbd_kern.h> -#include <linux/bitops.h> - -#include <asm/keyboard.h> -#include <asm/uaccess.h> -#include <asm/irq.h> -#include <asm/system.h> -#include <asm/ec3104.h> - -#include <asm/io.h> - -/* Some configuration switches are present in the include file... */ - -#include <linux/pc_keyb.h> - -#define MSR_CTS 0x10 -#define MCR_RTS 0x02 -#define LSR_DR 0x01 -#define LSR_BOTH_EMPTY 0x60 - -static struct e5_struct { - u8 packet[8]; - int pos; - int length; - - u8 cached_mcr; - u8 last_msr; -} ec3104_keyb; - -/* Simple translation table for the SysRq keys */ - - -#ifdef CONFIG_MAGIC_SYSRQ -unsigned char ec3104_kbd_sysrq_xlate[128] = - "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ - "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ - "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ - "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ - "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */ - "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ - "\r\000/"; /* 0x60 - 0x6f */ -#endif - -static void kbd_write_command_w(int data); -static void kbd_write_output_w(int data); -#ifdef CONFIG_PSMOUSE -static void aux_write_ack(int val); -static void __aux_write_ack(int val); -#endif - -static DEFINE_SPINLOCK(kbd_controller_lock); -static unsigned char handle_kbd_event(void); - -/* used only by send_data - set by keyboard_interrupt */ -static volatile unsigned char reply_expected; -static volatile unsigned char acknowledge; -static volatile unsigned char resend; - - -int ec3104_kbd_setkeycode(unsigned int scancode, unsigned int keycode) -{ - return 0; -} - -int ec3104_kbd_getkeycode(unsigned int scancode) -{ - return 0; -} - - -/* yes, it probably would be faster to use an array. I don't care. */ - -static inline unsigned char ec3104_scan2key(unsigned char scancode) -{ - switch (scancode) { - case 1: /* '`' */ - return 41; - - case 2 ... 27: - return scancode; - - case 28: /* '\\' */ - return 43; - - case 29 ... 39: - return scancode + 1; - - case 40: /* '\r' */ - return 28; - - case 41 ... 50: - return scancode + 3; - - case 51: /* ' ' */ - return 57; - - case 52: /* escape */ - return 1; - - case 54: /* insert/delete (labelled delete) */ - /* this should arguably be 110, but I'd like to have ctrl-alt-del - * working with a standard keymap */ - return 111; - - case 55: /* left */ - return 105; - case 56: /* home */ - return 102; - case 57: /* end */ - return 107; - case 58: /* up */ - return 103; - case 59: /* down */ - return 108; - case 60: /* pgup */ - return 104; - case 61: /* pgdown */ - return 109; - case 62: /* right */ - return 106; - - case 79 ... 88: /* f1 - f10 */ - return scancode - 20; - - case 89 ... 90: /* f11 - f12 */ - return scancode - 2; - - case 91: /* left shift */ - return 42; - - case 92: /* right shift */ - return 54; - - case 93: /* left alt */ - return 56; - case 94: /* right alt */ - return 100; - case 95: /* left ctrl */ - return 29; - case 96: /* right ctrl */ - return 97; - - case 97: /* caps lock */ - return 58; - case 102: /* left windows */ - return 125; - case 103: /* right windows */ - return 126; - - case 106: /* Fn */ - /* this is wrong. */ - return 84; - - default: - return 0; - } -} - -int ec3104_kbd_translate(unsigned char scancode, unsigned char *keycode, - char raw_mode) -{ - scancode &= 0x7f; - - *keycode = ec3104_scan2key(scancode); - - return 1; -} - -char ec3104_kbd_unexpected_up(unsigned char keycode) -{ - return 0200; -} - -static inline void handle_keyboard_event(unsigned char scancode) -{ -#ifdef CONFIG_VT - handle_scancode(scancode, !(scancode & 0x80)); -#endif - tasklet_schedule(&keyboard_tasklet); -} - -void ec3104_kbd_leds(unsigned char leds) -{ -} - -static u8 e5_checksum(u8 *packet, int count) -{ - int i; - u8 sum = 0; - - for (i=0; i<count; i++) - sum ^= packet[i]; - - if (sum & 0x80) - sum ^= 0xc0; - - return sum; -} - -static void e5_wait_for_cts(struct e5_struct *k) -{ - u8 msr; - - do { - msr = ctrl_inb(EC3104_SER4_MSR); - } while (!(msr & MSR_CTS)); -} - - -static void e5_send_byte(u8 byte, struct e5_struct *k) -{ - u8 status; - - do { - status = ctrl_inb(EC3104_SER4_LSR); - } while ((status & LSR_BOTH_EMPTY) != LSR_BOTH_EMPTY); - - printk("<%02x>", byte); - - ctrl_outb(byte, EC3104_SER4_DATA); - - do { - status = ctrl_inb(EC3104_SER4_LSR); - } while ((status & LSR_BOTH_EMPTY) != LSR_BOTH_EMPTY); - -} - -static int e5_send_packet(u8 *packet, int count, struct e5_struct *k) -{ - int i; - - disable_irq(EC3104_IRQ_SER4); - - if (k->cached_mcr & MCR_RTS) { - printk("e5_send_packet: too slow\n"); - enable_irq(EC3104_IRQ_SER4); - return -EAGAIN; - } - - k->cached_mcr |= MCR_RTS; - ctrl_outb(k->cached_mcr, EC3104_SER4_MCR); - - e5_wait_for_cts(k); - - printk("p: "); - - for(i=0; i<count; i++) - e5_send_byte(packet[i], k); - - e5_send_byte(e5_checksum(packet, count), k); - - printk("\n"); - - udelay(1500); - - k->cached_mcr &= ~MCR_RTS; - ctrl_outb(k->cached_mcr, EC3104_SER4_MCR); - - set_current_state(TASK_UNINTERRUPTIBLE); - - - - enable_irq(EC3104_IRQ_SER4); - - - - return 0; -} - -/* - * E5 packets we know about: - * E5->host 0x80 0x05 <checksum> - resend packet - * host->E5 0x83 0x43 <contrast> - set LCD contrast - * host->E5 0x85 0x41 0x02 <brightness> 0x02 - set LCD backlight - * E5->host 0x87 <ps2 packet> 0x00 <checksum> - external PS2 - * E5->host 0x88 <scancode> <checksum> - key press - */ - -static void e5_receive(struct e5_struct *k) -{ - k->packet[k->pos++] = ctrl_inb(EC3104_SER4_DATA); - - if (k->pos == 1) { - switch(k->packet[0]) { - case 0x80: - k->length = 3; - break; - - case 0x87: /* PS2 ext */ - k->length = 6; - break; - - case 0x88: /* keyboard */ - k->length = 3; - break; - - default: - k->length = 1; - printk(KERN_WARNING "unknown E5 packet %02x\n", - k->packet[0]); - } - } - - if (k->pos == k->length) { - int i; - - if (e5_checksum(k->packet, k->length) != 0) - printk(KERN_WARNING "E5: wrong checksum\n"); - -#if 0 - printk("E5 packet ["); - for(i=0; i<k->length; i++) { - printk("%02x ", k->packet[i]); - } - - printk("(%02x)]\n", e5_checksum(k->packet, k->length-1)); -#endif - - switch(k->packet[0]) { - case 0x80: - case 0x88: - handle_keyboard_event(k->packet[1]); - break; - } - - k->pos = k->length = 0; - } -} - -static void ec3104_keyb_interrupt(int irq, void *data) -{ - struct e5_struct *k = &ec3104_keyb; - u8 msr, lsr; - - msr = ctrl_inb(EC3104_SER4_MSR); - - if ((msr & MSR_CTS) && !(k->last_msr & MSR_CTS)) { - if (k->cached_mcr & MCR_RTS) - printk("confused: RTS already high\n"); - /* CTS went high. Send RTS. */ - k->cached_mcr |= MCR_RTS; - - ctrl_outb(k->cached_mcr, EC3104_SER4_MCR); - } else if ((!(msr & MSR_CTS)) && (k->last_msr & MSR_CTS)) { - /* CTS went low. */ - if (!(k->cached_mcr & MCR_RTS)) - printk("confused: RTS already low\n"); - - k->cached_mcr &= ~MCR_RTS; - - ctrl_outb(k->cached_mcr, EC3104_SER4_MCR); - } - - k->last_msr = msr; - - lsr = ctrl_inb(EC3104_SER4_LSR); - - if (lsr & LSR_DR) - e5_receive(k); -} - -static void ec3104_keyb_clear_state(void) -{ - struct e5_struct *k = &ec3104_keyb; - u8 msr, lsr; - - /* we want CTS to be low */ - k->last_msr = 0; - - for (;;) { - msleep(100); - - msr = ctrl_inb(EC3104_SER4_MSR); - - lsr = ctrl_inb(EC3104_SER4_LSR); - - if (lsr & LSR_DR) { - e5_receive(k); - continue; - } - - if ((msr & MSR_CTS) && !(k->last_msr & MSR_CTS)) { - if (k->cached_mcr & MCR_RTS) - printk("confused: RTS already high\n"); - /* CTS went high. Send RTS. */ - k->cached_mcr |= MCR_RTS; - - ctrl_outb(k->cached_mcr, EC3104_SER4_MCR); - } else if ((!(msr & MSR_CTS)) && (k->last_msr & MSR_CTS)) { - /* CTS went low. */ - if (!(k->cached_mcr & MCR_RTS)) - printk("confused: RTS already low\n"); - - k->cached_mcr &= ~MCR_RTS; - - ctrl_outb(k->cached_mcr, EC3104_SER4_MCR); - } else - break; - - k->last_msr = msr; - - continue; - } -} - -void __init ec3104_kbd_init_hw(void) -{ - ec3104_keyb.last_msr = ctrl_inb(EC3104_SER4_MSR); - ec3104_keyb.cached_mcr = ctrl_inb(EC3104_SER4_MCR); - - ec3104_keyb_clear_state(); - - /* Ok, finally allocate the IRQ, and off we go.. */ - request_irq(EC3104_IRQ_SER4, ec3104_keyb_interrupt, 0, "keyboard", NULL); -} diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index 8d74b8745e60..bd94d5f9e62b 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -411,8 +411,8 @@ cleanup_module(void) iiResetDelay( i2BoardPtrTable[i] ); /* free io addresses and Tibet */ release_region( ip2config.addr[i], 8 ); - class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i)); - class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1)); + device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i)); + device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1)); } /* Disable and remove interrupt handler. */ if ( (ip2config.irq[i] > 0) && have_requested_irq(ip2config.irq[i]) ) { @@ -718,12 +718,12 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) } if ( NULL != ( pB = i2BoardPtrTable[i] ) ) { - class_device_create(ip2_class, NULL, + device_create(ip2_class, NULL, MKDEV(IP2_IPL_MAJOR, 4 * i), - NULL, "ipl%d", i); - class_device_create(ip2_class, NULL, + "ipl%d", i); + device_create(ip2_class, NULL, MKDEV(IP2_IPL_MAJOR, 4 * i + 1), - NULL, "stat%d", i); + "stat%d", i); for ( box = 0; box < ABS_MAX_BOXES; ++box ) { diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index c2aa44ee6eb6..0246a2b8ce48 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -865,7 +865,7 @@ static void ipmi_new_smi(int if_num, struct device *device) entry->dev = dev; mutex_lock(®_list_mutex); - class_device_create(ipmi_class, NULL, dev, device, "ipmi%d", if_num); + device_create(ipmi_class, device, dev, "ipmi%d", if_num); list_add(&entry->link, ®_list); mutex_unlock(®_list_mutex); } @@ -883,7 +883,7 @@ static void ipmi_smi_gone(int if_num) break; } } - class_device_destroy(ipmi_class, dev); + device_destroy(ipmi_class, dev); mutex_unlock(®_list_mutex); } @@ -938,7 +938,7 @@ static __exit void cleanup_ipmi(void) mutex_lock(®_list_mutex); list_for_each_entry_safe(entry, entry2, ®_list, link) { list_del(&entry->link); - class_device_destroy(ipmi_class, entry->dev); + device_destroy(ipmi_class, entry->dev); kfree(entry); } mutex_unlock(®_list_mutex); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index a2894d425153..c1222e98525d 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1072,19 +1072,19 @@ static char *si_type[SI_MAX_PARMS]; #define MAX_SI_TYPE_STR 30 static char si_type_str[MAX_SI_TYPE_STR]; static unsigned long addrs[SI_MAX_PARMS]; -static int num_addrs; +static unsigned int num_addrs; static unsigned int ports[SI_MAX_PARMS]; -static int num_ports; +static unsigned int num_ports; static int irqs[SI_MAX_PARMS]; -static int num_irqs; +static unsigned int num_irqs; static int regspacings[SI_MAX_PARMS]; -static int num_regspacings; +static unsigned int num_regspacings; static int regsizes[SI_MAX_PARMS]; -static int num_regsizes; +static unsigned int num_regsizes; static int regshifts[SI_MAX_PARMS]; -static int num_regshifts; +static unsigned int num_regshifts; static int slave_addrs[SI_MAX_PARMS]; -static int num_slave_addrs; +static unsigned int num_slave_addrs; #define IPMI_IO_ADDR_SPACE 0 #define IPMI_MEM_ADDR_SPACE 1 @@ -1106,12 +1106,12 @@ MODULE_PARM_DESC(type, "Defines the type of each interface, each" " interface separated by commas. The types are 'kcs'," " 'smic', and 'bt'. For example si_type=kcs,bt will set" " the first interface to kcs and the second to bt"); -module_param_array(addrs, long, &num_addrs, 0); +module_param_array(addrs, ulong, &num_addrs, 0); MODULE_PARM_DESC(addrs, "Sets the memory address of each interface, the" " addresses separated by commas. Only use if an interface" " is in memory. Otherwise, set it to zero or leave" " it blank."); -module_param_array(ports, int, &num_ports, 0); +module_param_array(ports, uint, &num_ports, 0); MODULE_PARM_DESC(ports, "Sets the port address of each interface, the" " addresses separated by commas. Only use if an interface" " is a port. Otherwise, set it to zero or leave" diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 3c66f402f9d7..1f27be1ec3d4 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -4624,9 +4624,8 @@ static int __init istallion_module_init(void) istallion_class = class_create(THIS_MODULE, "staliomem"); for (i = 0; i < 4; i++) - class_device_create(istallion_class, NULL, - MKDEV(STL_SIOMEMMAJOR, i), - NULL, "staliomem%d", i); + device_create(istallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i), + "staliomem%d", i); return 0; err_deinit: @@ -4659,8 +4658,7 @@ static void __exit istallion_module_exit(void) unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"); for (j = 0; j < 4; j++) - class_device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, - j)); + device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, j)); class_destroy(istallion_class); pci_unregister_driver(&stli_pcidriver); diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 62051f8b0910..c59e2a0996cc 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -799,8 +799,7 @@ static int lp_register(int nr, struct parport *port) if (reset) lp_reset(nr); - class_device_create(lp_class, NULL, MKDEV(LP_MAJOR, nr), port->dev, - "lp%d", nr); + device_create(lp_class, port->dev, MKDEV(LP_MAJOR, nr), "lp%d", nr); printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name, (port->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven"); @@ -971,7 +970,7 @@ static void lp_cleanup_module (void) if (lp_table[offset].dev == NULL) continue; parport_unregister_device(lp_table[offset].dev); - class_device_destroy(lp_class, MKDEV(LP_MAJOR, offset)); + device_destroy(lp_class, MKDEV(LP_MAJOR, offset)); } class_destroy(lp_class); } diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c index 4177f6db83e9..cc5d77797def 100644 --- a/drivers/char/pcmcia/cm4000_cs.c +++ b/drivers/char/pcmcia/cm4000_cs.c @@ -1863,8 +1863,7 @@ static int cm4000_probe(struct pcmcia_device *link) return ret; } - class_device_create(cmm_class, NULL, MKDEV(major, i), NULL, - "cmm%d", i); + device_create(cmm_class, NULL, MKDEV(major, i), "cmm%d", i); return 0; } @@ -1888,7 +1887,7 @@ static void cm4000_detach(struct pcmcia_device *link) dev_table[devno] = NULL; kfree(dev); - class_device_destroy(cmm_class, MKDEV(major, devno)); + device_destroy(cmm_class, MKDEV(major, devno)); return; } diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c index b24a3e7bbb9f..a0b9c8728d56 100644 --- a/drivers/char/pcmcia/cm4040_cs.c +++ b/drivers/char/pcmcia/cm4040_cs.c @@ -642,8 +642,7 @@ static int reader_probe(struct pcmcia_device *link) return ret; } - class_device_create(cmx_class, NULL, MKDEV(major, i), NULL, - "cmx%d", i); + device_create(cmx_class, NULL, MKDEV(major, i), "cmx%d", i); return 0; } @@ -666,7 +665,7 @@ static void reader_detach(struct pcmcia_device *link) dev_table[devno] = NULL; kfree(dev); - class_device_destroy(cmx_class, MKDEV(major, devno)); + device_destroy(cmx_class, MKDEV(major, devno)); return; } diff --git a/drivers/char/pty.c b/drivers/char/pty.c index de14aea34e11..73de77105fea 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -248,14 +248,19 @@ static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file, return -ENOIOCTLCMD; } +static int legacy_count = CONFIG_LEGACY_PTY_COUNT; +module_param(legacy_count, int, 0); + static void __init legacy_pty_init(void) { + if (legacy_count <= 0) + return; - pty_driver = alloc_tty_driver(NR_PTYS); + pty_driver = alloc_tty_driver(legacy_count); if (!pty_driver) panic("Couldn't allocate pty driver"); - pty_slave_driver = alloc_tty_driver(NR_PTYS); + pty_slave_driver = alloc_tty_driver(legacy_count); if (!pty_slave_driver) panic("Couldn't allocate pty slave driver"); diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 1f0d7c60c944..bbfa0e241cba 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -255,10 +255,7 @@ static const struct file_operations raw_ctl_fops = { .owner = THIS_MODULE, }; -static struct cdev raw_cdev = { - .kobj = {.name = "raw", }, - .owner = THIS_MODULE, -}; +static struct cdev raw_cdev; static int __init raw_init(void) { diff --git a/drivers/char/rio/host.h b/drivers/char/rio/host.h index 23d0681fe491..78f24540c224 100644 --- a/drivers/char/rio/host.h +++ b/drivers/char/rio/host.h @@ -99,7 +99,7 @@ struct Host { struct UnixRup UnixRups[MAX_RUP + LINKS_PER_UNIT]; int timeout_id; /* For calling 100 ms delays */ int timeout_sem; /* For calling 100 ms delays */ - long locks; /* long req'd for set_bit --RR */ + unsigned long locks; /* long req'd for set_bit --RR */ char ____end_marker____; }; #define Control CardP->DpControl diff --git a/drivers/char/riscom8.h b/drivers/char/riscom8.h index 6317aade201a..9cc1313d5e67 100644 --- a/drivers/char/riscom8.h +++ b/drivers/char/riscom8.h @@ -71,7 +71,7 @@ struct riscom_port { struct tty_struct * tty; int count; int blocked_open; - long event; /* long req'd for set_bit --RR */ + unsigned long event; /* long req'd for set_bit --RR */ int timeout; int close_delay; unsigned char * xmit_buf; diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c index 52753e723eaa..b9c1dba6bd01 100644 --- a/drivers/char/snsc.c +++ b/drivers/char/snsc.c @@ -441,8 +441,7 @@ scdrv_init(void) continue; } - class_device_create(snsc_class, NULL, dev, NULL, - "%s", devname); + device_create(snsc_class, NULL, dev, "%s", devname); ia64_sn_irtr_intr_enable(scd->scd_nasid, 0 /*ignored */ , diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index 4a80b2f864e0..45758d5b56ef 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -4778,9 +4778,8 @@ static int __init stallion_module_init(void) if (IS_ERR(stallion_class)) printk("STALLION: failed to create class\n"); for (i = 0; i < 4; i++) - class_device_create(stallion_class, NULL, - MKDEV(STL_SIOMEMMAJOR, i), NULL, - "staliomem%d", i); + device_create(stallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i), + "staliomem%d", i); return 0; err_unrtty: @@ -4816,7 +4815,7 @@ static void __exit stallion_module_exit(void) } for (i = 0; i < 4; i++) - class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i)); + device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i)); unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"); class_destroy(stallion_class); diff --git a/drivers/char/sx.h b/drivers/char/sx.h index 432aad0a2ddd..70d9783c7323 100644 --- a/drivers/char/sx.h +++ b/drivers/char/sx.h @@ -27,7 +27,7 @@ struct sx_port { int c_dcd; struct sx_board *board; int line; - long locks; + unsigned long locks; }; struct sx_board { @@ -45,7 +45,7 @@ struct sx_board { int poll; int ta_type; struct timer_list timer; - long locks; + unsigned long locks; }; struct vpd_prom { diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index 2f97d2f8f916..64e835f62438 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -206,10 +206,10 @@ static void flush_cond_wait(struct cond_wait **head); */ struct slgt_desc { - unsigned short count; - unsigned short status; - unsigned int pbuf; /* physical address of data buffer */ - unsigned int next; /* physical address of next descriptor */ + __le16 count; + __le16 status; + __le32 pbuf; /* physical address of data buffer */ + __le32 next; /* physical address of next descriptor */ /* driver book keeping */ char *buf; /* virtual address of data buffer */ diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c index 35b40b996534..cef55c40654f 100644 --- a/drivers/char/tipar.c +++ b/drivers/char/tipar.c @@ -441,8 +441,8 @@ tipar_register(int nr, struct parport *port) goto out; } - class_device_create(tipar_class, NULL, MKDEV(TIPAR_MAJOR, - TIPAR_MINOR + nr), port->dev, "par%d", nr); + device_create(tipar_class, port->dev, MKDEV(TIPAR_MAJOR, + TIPAR_MINOR + nr), "par%d", nr); /* Display informations */ pr_info("tipar%d: using %s (%s)\n", nr, port->name, (port->irq == @@ -534,7 +534,7 @@ tipar_cleanup_module(void) if (table[i].dev == NULL) continue; parport_unregister_device(table[i].dev); - class_device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i)); + device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i)); } class_destroy(tipar_class); diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c index f1d60f0cef8f..db7a731e2362 100644 --- a/drivers/char/viotape.c +++ b/drivers/char/viotape.c @@ -871,10 +871,10 @@ static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id) state[i].cur_part = 0; for (j = 0; j < MAX_PARTITIONS; ++j) state[i].part_stat_rwi[j] = VIOT_IDLE; - class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i), NULL, + device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i), "iseries!vt%d", i); - class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80), - NULL, "iseries!nvt%d", i); + device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80), + "iseries!nvt%d", i); printk(VIOTAPE_KERN_INFO "tape iseries/vt%d is iSeries " "resource %10.10s type %4.4s, model %3.3s\n", i, viotape_unitinfo[i].rsrcname, @@ -886,8 +886,8 @@ static int viotape_remove(struct vio_dev *vdev) { int i = vdev->unit_address; - class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80)); - class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i)); + device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80)); + device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i)); return 0; } diff --git a/drivers/char/watchdog/mpc5200_wdt.c b/drivers/char/watchdog/mpc5200_wdt.c index 564143d40610..9cfb97576623 100644 --- a/drivers/char/watchdog/mpc5200_wdt.c +++ b/drivers/char/watchdog/mpc5200_wdt.c @@ -81,7 +81,7 @@ static int mpc5200_wdt_stop(struct mpc5200_wdt *wdt) /* file operations */ -static ssize_t mpc5200_wdt_write(struct file *file, const char *data, +static ssize_t mpc5200_wdt_write(struct file *file, const char __user *data, size_t len, loff_t *ppos) { struct mpc5200_wdt *wdt = file->private_data; diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index 993fa7b89253..721f86f4f008 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -56,10 +56,6 @@ config CPU_FREQ_STAT_DETAILS If in doubt, say N. -# Note that it is not currently possible to set the other governors (such as ondemand) -# as the default, since if they fail to initialise, cpufreq will be -# left in an undefined state. - choice prompt "Default CPUFreq governor" default CPU_FREQ_DEFAULT_GOV_USERSPACE if CPU_FREQ_SA1100 || CPU_FREQ_SA1110 @@ -85,6 +81,29 @@ config CPU_FREQ_DEFAULT_GOV_USERSPACE program shall be able to set the CPU dynamically without having to enable the userspace governor manually. +config CPU_FREQ_DEFAULT_GOV_ONDEMAND + bool "ondemand" + select CPU_FREQ_GOV_ONDEMAND + select CPU_FREQ_GOV_PERFORMANCE + help + Use the CPUFreq governor 'ondemand' as default. This allows + you to get a full dynamic frequency capable system by simply + loading your cpufreq low-level hardware driver. + Be aware that not all cpufreq drivers support the ondemand + governor. If unsure have a look at the help section of the + driver. Fallback governor will be the performance governor. + +config CPU_FREQ_DEFAULT_GOV_CONSERVATIVE + bool "conservative" + select CPU_FREQ_GOV_CONSERVATIVE + select CPU_FREQ_GOV_PERFORMANCE + help + Use the CPUFreq governor 'conservative' as default. This allows + you to get a full dynamic frequency capable system by simply + loading your cpufreq low-level hardware driver. + Be aware that not all cpufreq drivers support the conservative + governor. If unsure have a look at the help section of the + driver. Fallback governor will be the performance governor. endchoice config CPU_FREQ_GOV_PERFORMANCE diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 2f6a73c01b71..5e626b12b97e 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -763,6 +763,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) init_completion(&policy->kobj_unregister); INIT_WORK(&policy->update, handle_update); + /* Set governor before ->init, so that driver could check it */ + policy->governor = CPUFREQ_DEFAULT_GOVERNOR; /* call driver. From then on the cpufreq must be able * to accept all calls to ->verify and ->setpolicy for this CPU */ @@ -828,7 +830,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) /* prepare interface data */ policy->kobj.parent = &sys_dev->kobj; policy->kobj.ktype = &ktype_cpufreq; - strlcpy(policy->kobj.name, "cpufreq", KOBJ_NAME_LEN); + kobject_set_name(&policy->kobj, "cpufreq"); ret = kobject_register(&policy->kobj); if (ret) { @@ -1109,12 +1111,7 @@ unsigned int cpufreq_quick_get(unsigned int cpu) unsigned int ret_freq = 0; if (policy) { - if (unlikely(lock_policy_rwsem_read(cpu))) - return ret_freq; - ret_freq = policy->cur; - - unlock_policy_rwsem_read(cpu); cpufreq_cpu_put(policy); } @@ -1483,6 +1480,31 @@ static int __cpufreq_governor(struct cpufreq_policy *policy, { int ret; + /* Only must be defined when default governor is known to have latency + restrictions, like e.g. conservative or ondemand. + That this is the case is already ensured in Kconfig + */ +#ifdef CONFIG_CPU_FREQ_GOV_PERFORMANCE + struct cpufreq_governor *gov = &cpufreq_gov_performance; +#else + struct cpufreq_governor *gov = NULL; +#endif + + if (policy->governor->max_transition_latency && + policy->cpuinfo.transition_latency > + policy->governor->max_transition_latency) { + if (!gov) + return -EINVAL; + else { + printk(KERN_WARNING "%s governor failed, too long" + " transition latency of HW, fallback" + " to %s governor\n", + policy->governor->name, + gov->name); + policy->governor = gov; + } + } + if (!try_module_get(policy->governor->owner)) return -EINVAL; @@ -1703,7 +1725,7 @@ int cpufreq_update_policy(unsigned int cpu) } EXPORT_SYMBOL(cpufreq_update_policy); -static int cpufreq_cpu_callback(struct notifier_block *nfb, +static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) { unsigned int cpu = (unsigned long)hcpu; diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index 26f440ccc3fb..4bd33ce8a6f3 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -58,7 +58,7 @@ static unsigned int def_sampling_rate; #define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000) #define DEF_SAMPLING_DOWN_FACTOR (1) #define MAX_SAMPLING_DOWN_FACTOR (10) -#define TRANSITION_LATENCY_LIMIT (10 * 1000) +#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000) static void do_dbs_timer(struct work_struct *work); @@ -466,9 +466,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, (!policy->cur)) return -EINVAL; - if (policy->cpuinfo.transition_latency > - (TRANSITION_LATENCY_LIMIT * 1000)) - return -EINVAL; if (this_dbs_info->enable) /* Already enabled */ break; @@ -551,15 +548,17 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, return 0; } -static struct cpufreq_governor cpufreq_gov_dbs = { - .name = "conservative", - .governor = cpufreq_governor_dbs, - .owner = THIS_MODULE, +struct cpufreq_governor cpufreq_gov_conservative = { + .name = "conservative", + .governor = cpufreq_governor_dbs, + .max_transition_latency = TRANSITION_LATENCY_LIMIT, + .owner = THIS_MODULE, }; +EXPORT_SYMBOL(cpufreq_gov_conservative); static int __init cpufreq_gov_dbs_init(void) { - return cpufreq_register_governor(&cpufreq_gov_dbs); + return cpufreq_register_governor(&cpufreq_gov_conservative); } static void __exit cpufreq_gov_dbs_exit(void) @@ -567,7 +566,7 @@ static void __exit cpufreq_gov_dbs_exit(void) /* Make sure that the scheduled work is indeed not running */ flush_scheduled_work(); - cpufreq_unregister_governor(&cpufreq_gov_dbs); + cpufreq_unregister_governor(&cpufreq_gov_conservative); } diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index e794527e4925..369f44595150 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -47,7 +47,7 @@ static unsigned int def_sampling_rate; (def_sampling_rate / MIN_SAMPLING_RATE_RATIO) #define MAX_SAMPLING_RATE (500 * def_sampling_rate) #define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000) -#define TRANSITION_LATENCY_LIMIT (10 * 1000) +#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000) static void do_dbs_timer(struct work_struct *work); @@ -508,12 +508,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, if ((!cpu_online(cpu)) || (!policy->cur)) return -EINVAL; - if (policy->cpuinfo.transition_latency > - (TRANSITION_LATENCY_LIMIT * 1000)) { - printk(KERN_WARNING "ondemand governor failed to load " - "due to too long transition latency\n"); - return -EINVAL; - } if (this_dbs_info->enable) /* Already enabled */ break; @@ -585,11 +579,13 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, return 0; } -static struct cpufreq_governor cpufreq_gov_dbs = { - .name = "ondemand", - .governor = cpufreq_governor_dbs, - .owner = THIS_MODULE, +struct cpufreq_governor cpufreq_gov_ondemand = { + .name = "ondemand", + .governor = cpufreq_governor_dbs, + .max_transition_latency = TRANSITION_LATENCY_LIMIT, + .owner = THIS_MODULE, }; +EXPORT_SYMBOL(cpufreq_gov_ondemand); static int __init cpufreq_gov_dbs_init(void) { @@ -598,12 +594,12 @@ static int __init cpufreq_gov_dbs_init(void) printk(KERN_ERR "Creation of kondemand failed\n"); return -EFAULT; } - return cpufreq_register_governor(&cpufreq_gov_dbs); + return cpufreq_register_governor(&cpufreq_gov_ondemand); } static void __exit cpufreq_gov_dbs_exit(void) { - cpufreq_unregister_governor(&cpufreq_gov_dbs); + cpufreq_unregister_governor(&cpufreq_gov_ondemand); destroy_workqueue(kondemand_wq); } diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 917b9bab9ccb..8a45d0f93e26 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -164,8 +164,7 @@ freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq) return -1; } -static void -cpufreq_stats_free_table (unsigned int cpu) +static void __cpuexit cpufreq_stats_free_table(unsigned int cpu) { struct cpufreq_stats *stat = cpufreq_stats_table[cpu]; struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); @@ -305,8 +304,9 @@ cpufreq_stat_notifier_trans (struct notifier_block *nb, unsigned long val, return 0; } -static int cpufreq_stat_cpu_callback(struct notifier_block *nfb, - unsigned long action, void *hcpu) +static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb, + unsigned long action, + void *hcpu) { unsigned int cpu = (unsigned long)hcpu; @@ -323,7 +323,7 @@ static int cpufreq_stat_cpu_callback(struct notifier_block *nfb, return NOTIFY_OK; } -static struct notifier_block cpufreq_stat_cpu_notifier = +static struct notifier_block cpufreq_stat_cpu_notifier __cpuinitdata = { .notifier_call = cpufreq_stat_cpu_callback, }; @@ -356,8 +356,7 @@ __init cpufreq_stats_init(void) register_hotcpu_notifier(&cpufreq_stat_cpu_notifier); for_each_online_cpu(cpu) { - cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, - CPU_ONLINE, (void *)(long)cpu); + cpufreq_update_policy(cpu); } return 0; } @@ -372,13 +371,12 @@ __exit cpufreq_stats_exit(void) CPUFREQ_TRANSITION_NOTIFIER); unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier); for_each_online_cpu(cpu) { - cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, - CPU_DEAD, (void *)(long)cpu); + cpufreq_stats_free_table(cpu); } } MODULE_AUTHOR ("Zou Nan hai <nanhai.zou@intel.com>"); -MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats" +MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats " "through sysfs filesystem"); MODULE_LICENSE ("GPL"); diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 4a0576bd06fc..3706b2bc0987 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -743,7 +743,7 @@ static struct kobj_type ktype_mc_set_attribs = { * /sys/devices/system/edac/mc */ static struct kset mc_kset = { - .kobj = {.name = "mc", .ktype = &ktype_mc_set_attribs }, + .kobj = {.ktype = &ktype_mc_set_attribs }, .ktype = &ktype_mci, }; @@ -1010,6 +1010,7 @@ int edac_sysfs_setup_mc_kset(void) } /* Init the MC's kobject */ + kobject_set_name(&mc_kset.kobj, "mc"); mc_kset.kobj.parent = &edac_class->kset.kobj; /* register the mc_kset */ diff --git a/drivers/eisa/eisa-bus.c b/drivers/eisa/eisa-bus.c index d944647c82c2..65dcf0432653 100644 --- a/drivers/eisa/eisa-bus.c +++ b/drivers/eisa/eisa-bus.c @@ -35,9 +35,9 @@ static struct eisa_device_info __initdata eisa_table[] = { #define EISA_MAX_FORCED_DEV 16 static int enable_dev[EISA_MAX_FORCED_DEV]; -static int enable_dev_count; +static unsigned int enable_dev_count; static int disable_dev[EISA_MAX_FORCED_DEV]; -static int disable_dev_count; +static unsigned int disable_dev_count; static int is_forced_dev (int *forced_tab, int forced_count, @@ -128,16 +128,11 @@ static int eisa_bus_match (struct device *dev, struct device_driver *drv) return 0; } -static int eisa_bus_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int eisa_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { struct eisa_device *edev = to_eisa_device(dev); - int i = 0; - int length = 0; - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MODALIAS=" EISA_DEVICE_MODALIAS_FMT, edev->id.sig); - envp[i] = NULL; + add_uevent_var(env, "MODALIAS=" EISA_DEVICE_MODALIAS_FMT, edev->id.sig); return 0; } diff --git a/drivers/fc4/fc.c b/drivers/fc4/fc.c index 22b62b3cd14e..82de9e1adb1e 100644 --- a/drivers/fc4/fc.c +++ b/drivers/fc4/fc.c @@ -427,15 +427,10 @@ static inline void fcp_scsi_receive(fc_channel *fc, int token, int status, fc_hd memcpy(SCpnt->sense_buffer, ((char *)(rsp+1)), sense_len); } - if (fcmd->data) { - if (SCpnt->use_sg) - dma_unmap_sg(fc->dev, (struct scatterlist *)SCpnt->request_buffer, - SCpnt->use_sg, - SCpnt->sc_data_direction); - else - dma_unmap_single(fc->dev, fcmd->data, SCpnt->request_bufflen, - SCpnt->sc_data_direction); - } + if (fcmd->data) + dma_unmap_sg(fc->dev, scsi_sglist(SCpnt), + scsi_sg_count(SCpnt), + SCpnt->sc_data_direction); break; default: host_status=DID_ERROR; /* FIXME */ @@ -793,10 +788,14 @@ static int fcp_scsi_queue_it(fc_channel *fc, struct scsi_cmnd *SCpnt, fcp_cntl = FCP_CNTL_QTYPE_SIMPLE; } else fcp_cntl = FCP_CNTL_QTYPE_UNTAGGED; - if (!SCpnt->request_bufflen && !SCpnt->use_sg) { + + if (!scsi_bufflen(SCpnt)) { cmd->fcp_cntl = fcp_cntl; fcmd->data = (dma_addr_t)NULL; } else { + struct scatterlist *sg; + int nents; + switch (SCpnt->cmnd[0]) { case WRITE_6: case WRITE_10: @@ -805,22 +804,12 @@ static int fcp_scsi_queue_it(fc_channel *fc, struct scsi_cmnd *SCpnt, default: cmd->fcp_cntl = (FCP_CNTL_READ | fcp_cntl); break; } - if (!SCpnt->use_sg) { - cmd->fcp_data_len = SCpnt->request_bufflen; - fcmd->data = dma_map_single (fc->dev, (char *)SCpnt->request_buffer, - SCpnt->request_bufflen, - SCpnt->sc_data_direction); - } else { - struct scatterlist *sg = (struct scatterlist *)SCpnt->request_buffer; - int nents; - - FCD(("XXX: Use_sg %d %d\n", SCpnt->use_sg, sg->length)) - nents = dma_map_sg (fc->dev, sg, SCpnt->use_sg, - SCpnt->sc_data_direction); - if (nents > 1) printk ("%s: SG for nents %d (use_sg %d) not handled yet\n", fc->name, nents, SCpnt->use_sg); - fcmd->data = sg_dma_address(sg); - cmd->fcp_data_len = sg_dma_len(sg); - } + + sg = scsi_sglist(SCpnt); + nents = dma_map_sg(fc->dev, sg, scsi_sg_count(SCpnt), + SCpnt->sc_data_direction); + fcmd->data = sg_dma_address(sg); + cmd->fcp_data_len = sg_dma_len(sg); } memcpy (cmd->fcp_cdb, SCpnt->cmnd, SCpnt->cmd_len); memset (cmd->fcp_cdb+SCpnt->cmd_len, 0, sizeof(cmd->fcp_cdb)-SCpnt->cmd_len); diff --git a/drivers/fc4/fcp_impl.h b/drivers/fc4/fcp_impl.h index 1ac61330592e..506338a461ba 100644 --- a/drivers/fc4/fcp_impl.h +++ b/drivers/fc4/fcp_impl.h @@ -91,7 +91,7 @@ typedef struct _fc_channel { fcp_cmd *scsi_cmd_pool; char *scsi_rsp_pool; dma_addr_t dma_scsi_cmd, dma_scsi_rsp; - long *scsi_bitmap; + unsigned long *scsi_bitmap; long scsi_bitmap_end; int scsi_free; int (*encode_addr)(struct scsi_cmnd *, u16 *, struct _fc_channel *, fcp_cmnd *); diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c index 75388641a7d3..06471302200f 100644 --- a/drivers/firewire/fw-cdev.c +++ b/drivers/firewire/fw-cdev.c @@ -722,10 +722,11 @@ static int ioctl_queue_iso(struct client *client, void *buffer) buffer_end = 0; } - if (!access_ok(VERIFY_READ, request->packets, request->size)) + p = (struct fw_cdev_iso_packet __user *)u64_to_uptr(request->packets); + + if (!access_ok(VERIFY_READ, p, request->size)) return -EFAULT; - p = (struct fw_cdev_iso_packet __user *)u64_to_uptr(request->packets); end = (void __user *)p + request->size; count = 0; while (p < end) { diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c index 2b6586341635..56681b3b297b 100644 --- a/drivers/firewire/fw-device.c +++ b/drivers/firewire/fw-device.c @@ -130,23 +130,16 @@ static int get_modalias(struct fw_unit *unit, char *buffer, size_t buffer_size) } static int -fw_unit_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +fw_unit_uevent(struct device *dev, struct kobj_uevent_env *env) { struct fw_unit *unit = fw_unit(dev); char modalias[64]; - int length = 0; - int i = 0; get_modalias(unit, modalias, sizeof(modalias)); - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=%s", modalias)) + if (add_uevent_var(env, "MODALIAS=%s", modalias)) return -ENOMEM; - envp[i] = NULL; - return 0; } diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c index 59c3b5aa89f4..b6e1eb77d148 100644 --- a/drivers/firmware/dmi-id.c +++ b/drivers/firmware/dmi-id.c @@ -13,21 +13,31 @@ #include <linux/device.h> #include <linux/autoconf.h> -#define DEFINE_DMI_ATTR(_name, _mode, _show) \ -static struct device_attribute sys_dmi_##_name##_attr = \ - __ATTR(_name, _mode, _show, NULL); - -#define DEFINE_DMI_ATTR_WITH_SHOW(_name, _mode, _field) \ -static ssize_t sys_dmi_##_name##_show(struct device *dev, \ - struct device_attribute *attr, \ - char *page) \ -{ \ - ssize_t len; \ - len = scnprintf(page, PAGE_SIZE, "%s\n", dmi_get_system_info(_field)); \ - page[len-1] = '\n'; \ - return len; \ -} \ -DEFINE_DMI_ATTR(_name, _mode, sys_dmi_##_name##_show); +struct dmi_device_attribute{ + struct device_attribute dev_attr; + int field; +}; +#define to_dmi_dev_attr(_dev_attr) \ + container_of(_dev_attr, struct dmi_device_attribute, dev_attr) + +static ssize_t sys_dmi_field_show(struct device *dev, + struct device_attribute *attr, + char *page) +{ + int field = to_dmi_dev_attr(attr)->field; + ssize_t len; + len = scnprintf(page, PAGE_SIZE, "%s\n", dmi_get_system_info(field)); + page[len-1] = '\n'; + return len; +} + +#define DMI_ATTR(_name, _mode, _show, _field) \ + { .dev_attr = __ATTR(_name, _mode, _show, NULL), \ + .field = _field } + +#define DEFINE_DMI_ATTR_WITH_SHOW(_name, _mode, _field) \ +static struct dmi_device_attribute sys_dmi_##_name##_attr = \ + DMI_ATTR(_name, _mode, sys_dmi_field_show, _field); DEFINE_DMI_ATTR_WITH_SHOW(bios_vendor, 0444, DMI_BIOS_VENDOR); DEFINE_DMI_ATTR_WITH_SHOW(bios_version, 0444, DMI_BIOS_VERSION); @@ -121,7 +131,8 @@ static ssize_t sys_dmi_modalias_show(struct device *dev, return r+1; } -DEFINE_DMI_ATTR(modalias, 0444, sys_dmi_modalias_show); +static struct device_attribute sys_dmi_modalias_attr = + __ATTR(modalias, 0444, sys_dmi_modalias_show, NULL); static struct attribute *sys_dmi_attributes[DMI_STRING_MAX+2]; @@ -134,14 +145,17 @@ static struct attribute_group* sys_dmi_attribute_groups[] = { NULL }; -static int dmi_dev_uevent(struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size) +static int dmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env) { - strcpy(buffer, "MODALIAS="); - get_modalias(buffer+9, buffer_size-9); - envp[0] = buffer; - envp[1] = NULL; - + ssize_t len; + + if (add_uevent_var(env, "MODALIAS=")) + return -ENOMEM; + len = get_modalias(&env->buf[env->buflen - 1], + sizeof(env->buf) - env->buflen); + if (len >= (sizeof(env->buf) - env->buflen)) + return -ENOMEM; + env->buflen += len; return 0; } @@ -157,7 +171,7 @@ static struct device *dmi_dev; #define ADD_DMI_ATTR(_name, _field) \ if (dmi_get_system_info(_field)) \ - sys_dmi_attributes[i++] = & sys_dmi_##_name##_attr.attr; + sys_dmi_attributes[i++] = &sys_dmi_##_name##_attr.dev_attr.attr; extern int dmi_available; diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c index 0fb730ee1da8..6942e065e609 100644 --- a/drivers/firmware/edd.c +++ b/drivers/firmware/edd.c @@ -625,13 +625,13 @@ static void edd_release(struct kobject * kobj) kfree(dev); } -static struct kobj_type ktype_edd = { +static struct kobj_type edd_ktype = { .release = edd_release, .sysfs_ops = &edd_attr_ops, .default_attrs = def_attrs, }; -static decl_subsys(edd,&ktype_edd,NULL); +static decl_subsys(edd, &edd_ktype, NULL); /** diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index bfd2d67df689..858a7b95933b 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c @@ -402,7 +402,7 @@ static struct attribute *def_attrs[] = { NULL, }; -static struct kobj_type ktype_efivar = { +static struct kobj_type efivar_ktype = { .release = efivar_release, .sysfs_ops = &efivar_attr_ops, .default_attrs = def_attrs, @@ -583,7 +583,7 @@ static struct subsys_attribute *efi_subsys_attrs[] = { NULL, /* maybe more in the future? */ }; -static decl_subsys(vars, &ktype_efivar, NULL); +static decl_subsys(vars, &efivar_ktype, NULL); static decl_subsys(efi, NULL, NULL); /* diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 19667fcc722a..cacf89e65af4 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -46,6 +46,25 @@ config HID_DEBUG If unsure, say N +config HIDRAW + bool "/dev/hidraw raw HID device support" + depends on HID + ---help--- + Say Y here if you want to support HID devices (from the USB + specification standpoint) that aren't strictly user interface + devices, like monitor controls and Uninterruptable Power Supplies. + + This module supports these devices separately using a separate + event interface on /dev/hidraw. + + There is also a /dev/hiddev configuration option in the USB HID + configuration menu. In comparison to hiddev, this device does not process + the hid events at all (no parsing, no lookups). This lets applications + to work on raw hid events when they want to, and avoid using transport-specific + userspace libhid/libusb libraries. + + If unsure, say Y. + source "drivers/hid/usbhid/Kconfig" endif # HID_SUPPORT diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 68d1376a53fb..1ac5103f7c93 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -4,7 +4,9 @@ hid-objs := hid-core.o hid-input.o obj-$(CONFIG_HID) += hid.o + hid-$(CONFIG_HID_DEBUG) += hid-debug.o +hid-$(CONFIG_HIDRAW) += hidraw.o obj-$(CONFIG_USB_HID) += usbhid/ obj-$(CONFIG_USB_MOUSE) += usbhid/ diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 317cf8a7b63c..2884b036495a 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -30,6 +30,7 @@ #include <linux/hid.h> #include <linux/hiddev.h> #include <linux/hid-debug.h> +#include <linux/hidraw.h> /* * Version Information @@ -979,6 +980,8 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event) hid->hiddev_report_event(hid, report); + if (hid->claimed & HID_CLAIMED_HIDRAW) + hidraw_report_event(hid, data, size); for (n = 0; n < report->maxfield; n++) hid_input_field(hid, report->field[n], data, interrupt); @@ -990,5 +993,18 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i } EXPORT_SYMBOL_GPL(hid_input_report); +static int __init hid_init(void) +{ + return hidraw_init(); +} + +static void __exit hid_exit(void) +{ + hidraw_exit(); +} + +module_init(hid_init); +module_exit(hid_exit); + MODULE_LICENSE(DRIVER_LICENSE); diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index a13757b78980..5c24fe46d8eb 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -34,7 +34,7 @@ struct hid_usage_entry { unsigned page; unsigned usage; - char *description; + const char *description; }; static const struct hid_usage_entry hid_usage_table[] = { @@ -365,8 +365,8 @@ void hid_resolv_usage(unsigned usage) { } EXPORT_SYMBOL_GPL(hid_resolv_usage); -__inline__ static void tab(int n) { - while (n--) printk(" "); +static void tab(int n) { + printk(KERN_DEBUG "%*s", n, ""); } void hid_dump_field(struct hid_field *field, int n) { @@ -401,8 +401,8 @@ void hid_dump_field(struct hid_field *field, int n) { tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent); } if (field->unit) { - char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" }; - char *units[5][8] = { + static const char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" }; + static const char *units[5][8] = { { "None", "None", "None", "None", "None", "None", "None", "None" }, { "None", "Centimeter", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" }, { "None", "Radians", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" }, @@ -457,7 +457,7 @@ void hid_dump_field(struct hid_field *field, int n) { printk("%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute "); printk("%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : ""); printk("%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : ""); - printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPrefferedState " : ""); + printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPreferredState " : ""); printk("%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : ""); printk("%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : ""); printk("%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : ""); @@ -470,7 +470,7 @@ void hid_dump_device(struct hid_device *device) { struct hid_report *report; struct list_head *list; unsigned i,k; - static char *table[] = {"INPUT", "OUTPUT", "FEATURE"}; + static const char *table[] = {"INPUT", "OUTPUT", "FEATURE"}; if (!hid_debug) return; @@ -501,13 +501,13 @@ void hid_dump_input(struct hid_usage *usage, __s32 value) { if (!hid_debug) return; - printk("hid-debug: input "); + printk(KERN_DEBUG "hid-debug: input "); hid_resolv_usage(usage->hid); printk(" = %d\n", value); } EXPORT_SYMBOL_GPL(hid_dump_input); -static char *events[EV_MAX + 1] = { +static const char *events[EV_MAX + 1] = { [EV_SYN] = "Sync", [EV_KEY] = "Key", [EV_REL] = "Relative", [EV_ABS] = "Absolute", [EV_MSC] = "Misc", [EV_LED] = "LED", @@ -516,10 +516,10 @@ static char *events[EV_MAX + 1] = { [EV_FF_STATUS] = "ForceFeedbackStatus", }; -static char *syncs[2] = { +static const char *syncs[2] = { [SYN_REPORT] = "Report", [SYN_CONFIG] = "Config", }; -static char *keys[KEY_MAX + 1] = { +static const char *keys[KEY_MAX + 1] = { [KEY_RESERVED] = "Reserved", [KEY_ESC] = "Esc", [KEY_1] = "1", [KEY_2] = "2", [KEY_3] = "3", [KEY_4] = "4", @@ -697,7 +697,8 @@ static char *keys[KEY_MAX + 1] = { [KEY_DEL_LINE] = "DeleteLine", [KEY_SEND] = "Send", [KEY_REPLY] = "Reply", [KEY_FORWARDMAIL] = "ForwardMail", [KEY_SAVE] = "Save", - [KEY_DOCUMENTS] = "Documents", + [KEY_DOCUMENTS] = "Documents", [KEY_SPELLCHECK] = "SpellCheck", + [KEY_LOGOFF] = "Logoff", [KEY_FN] = "Fn", [KEY_FN_ESC] = "Fn+ESC", [KEY_FN_1] = "Fn+1", [KEY_FN_2] = "Fn+2", [KEY_FN_B] = "Fn+B", [KEY_FN_D] = "Fn+D", @@ -715,7 +716,7 @@ static char *keys[KEY_MAX + 1] = { [KEY_SWITCHVIDEOMODE] = "SwitchVideoMode", }; -static char *relatives[REL_MAX + 1] = { +static const char *relatives[REL_MAX + 1] = { [REL_X] = "X", [REL_Y] = "Y", [REL_Z] = "Z", [REL_RX] = "Rx", [REL_RY] = "Ry", [REL_RZ] = "Rz", @@ -723,7 +724,7 @@ static char *relatives[REL_MAX + 1] = { [REL_WHEEL] = "Wheel", [REL_MISC] = "Misc", }; -static char *absolutes[ABS_MAX + 1] = { +static const char *absolutes[ABS_MAX + 1] = { [ABS_X] = "X", [ABS_Y] = "Y", [ABS_Z] = "Z", [ABS_RX] = "Rx", [ABS_RY] = "Ry", [ABS_RZ] = "Rz", @@ -739,12 +740,12 @@ static char *absolutes[ABS_MAX + 1] = { [ABS_VOLUME] = "Volume", [ABS_MISC] = "Misc", }; -static char *misc[MSC_MAX + 1] = { +static const char *misc[MSC_MAX + 1] = { [MSC_SERIAL] = "Serial", [MSC_PULSELED] = "Pulseled", [MSC_GESTURE] = "Gesture", [MSC_RAW] = "RawData" }; -static char *leds[LED_MAX + 1] = { +static const char *leds[LED_MAX + 1] = { [LED_NUML] = "NumLock", [LED_CAPSL] = "CapsLock", [LED_SCROLLL] = "ScrollLock", [LED_COMPOSE] = "Compose", [LED_KANA] = "Kana", [LED_SLEEP] = "Sleep", @@ -752,16 +753,16 @@ static char *leds[LED_MAX + 1] = { [LED_MISC] = "Misc", }; -static char *repeats[REP_MAX + 1] = { +static const char *repeats[REP_MAX + 1] = { [REP_DELAY] = "Delay", [REP_PERIOD] = "Period" }; -static char *sounds[SND_MAX + 1] = { +static const char *sounds[SND_MAX + 1] = { [SND_CLICK] = "Click", [SND_BELL] = "Bell", [SND_TONE] = "Tone" }; -static char **names[EV_MAX + 1] = { +static const char **names[EV_MAX + 1] = { [EV_SYN] = syncs, [EV_KEY] = keys, [EV_REL] = relatives, [EV_ABS] = absolutes, [EV_MSC] = misc, [EV_LED] = leds, @@ -777,4 +778,3 @@ void hid_resolv_event(__u8 type, __u16 code) { names[type] ? (names[type][code] ? names[type][code] : "?") : "?"); } EXPORT_SYMBOL_GPL(hid_resolv_event); - diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 8edbd30cf795..dd332f28e08c 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -53,7 +53,7 @@ static const unsigned char hid_keyboard[256] = { 115,114,unk,unk,unk,121,unk, 89, 93,124, 92, 94, 95,unk,unk,unk, 122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, - unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, + unk,unk,unk,unk,unk,unk,179,180,unk,unk,unk,unk,unk,unk,unk,unk, unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, @@ -86,6 +86,10 @@ static const struct { #define map_abs_clear(c) do { map_abs(c); clear_bit(c, bit); } while (0) #define map_key_clear(c) do { map_key(c); clear_bit(c, bit); } while (0) +/* hardware needing special handling due to colliding MSVENDOR page usages */ +#define IS_CHICONY_TACTICAL_PAD(x) (x->vendor == 0x04f2 && device->product == 0x0418) +#define IS_MS_KB(x) (x->vendor == 0x045e && (x->product == 0x00db || x->product == 0x00f9)) + #ifdef CONFIG_USB_HIDINPUT_POWERBOOK struct hidinput_key_translation { @@ -295,7 +299,7 @@ static int hidinput_getkeycode(struct input_dev *dev, int scancode, { struct hid_device *hid = dev->private; struct hid_usage *usage; - + usage = hidinput_find_key(hid, scancode, 0); if (usage) { *keycode = usage->code; @@ -310,15 +314,15 @@ static int hidinput_setkeycode(struct input_dev *dev, int scancode, struct hid_device *hid = dev->private; struct hid_usage *usage; int old_keycode; - + if (keycode < 0 || keycode > KEY_MAX) return -EINVAL; - + usage = hidinput_find_key(hid, scancode, 0); if (usage) { old_keycode = usage->code; usage->code = keycode; - + clear_bit(old_keycode, dev->keybit); set_bit(usage->code, dev->keybit); dbg_hid(KERN_DEBUG "Assigned keycode %d to HID usage code %x\n", keycode, scancode); @@ -326,10 +330,10 @@ static int hidinput_setkeycode(struct input_dev *dev, int scancode, * by another key */ if (hidinput_find_key (hid, 0, old_keycode)) set_bit(old_keycode, dev->keybit); - + return 0; } - + return -EINVAL; } @@ -351,6 +355,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel if (field->flags & HID_MAIN_ITEM_CONSTANT) goto ignore; + /* only LED usages are supported in output fields */ + if (field->report_type == HID_OUTPUT_REPORT && + (usage->hid & HID_USAGE_PAGE) != HID_UP_LED) { + dbg_hid_line(" [non-LED output field] "); + goto ignore; + } + switch (usage->hid & HID_USAGE_PAGE) { case HID_UP_UNDEFINED: @@ -595,6 +606,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x0f6: map_key_clear(KEY_NEXT); break; case 0x0fa: map_key_clear(KEY_BACK); break; + case 0x182: map_key_clear(KEY_BOOKMARKS); break; case 0x183: map_key_clear(KEY_CONFIG); break; case 0x184: map_key_clear(KEY_WORDPROCESSOR); break; case 0x185: map_key_clear(KEY_EDITOR); break; @@ -611,9 +623,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x192: map_key_clear(KEY_CALC); break; case 0x194: map_key_clear(KEY_FILE); break; case 0x196: map_key_clear(KEY_WWW); break; + case 0x19c: map_key_clear(KEY_LOGOFF); break; case 0x19e: map_key_clear(KEY_COFFEE); break; case 0x1a6: map_key_clear(KEY_HELP); break; case 0x1a7: map_key_clear(KEY_DOCUMENTS); break; + case 0x1ab: map_key_clear(KEY_SPELLCHECK); break; + case 0x1b6: map_key_clear(KEY_MEDIA); break; + case 0x1b7: map_key_clear(KEY_SOUND); break; case 0x1bc: map_key_clear(KEY_MESSENGER); break; case 0x1bd: map_key_clear(KEY_INFO); break; case 0x201: map_key_clear(KEY_NEW); break; @@ -720,8 +736,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case HID_UP_MSVENDOR: - /* special case - Chicony Chicony KU-0418 tactical pad */ - if (device->vendor == 0x04f2 && device->product == 0x0418) { + /* Unfortunately, there are multiple devices which + * emit usages from MSVENDOR page that require different + * handling. If this list grows too much in the future, + * more general handling will have to be introduced here + * (i.e. another blacklist). + */ + + /* Chicony Chicony KU-0418 tactical pad */ + if (IS_CHICONY_TACTICAL_PAD(device)) { set_bit(EV_REP, input->evbit); switch(usage->hid & HID_USAGE) { case 0xff01: map_key_clear(BTN_1); break; @@ -737,6 +760,26 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0xff0b: map_key_clear(BTN_B); break; default: goto ignore; } + + /* Microsoft Natural Ergonomic Keyboard 4000 */ + } else if (IS_MS_KB(device)) { + switch(usage->hid & HID_USAGE) { + case 0xfd06: + map_key_clear(KEY_CHAT); + break; + case 0xfd07: + map_key_clear(KEY_PHONE); + break; + case 0xff05: + set_bit(EV_REP, input->evbit); + map_key_clear(KEY_F13); + set_bit(KEY_F14, input->keybit); + set_bit(KEY_F15, input->keybit); + set_bit(KEY_F16, input->keybit); + set_bit(KEY_F17, input->keybit); + set_bit(KEY_F18, input->keybit); + default: goto ignore; + } } else { goto ignore; } @@ -888,6 +931,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel set_bit(KEY_VOLUMEDOWN, input->keybit); } + if (usage->type == EV_KEY) { + set_bit(EV_MSC, input->evbit); + set_bit(MSC_SCAN, input->mscbit); + } + hid_resolv_event(usage->type, usage->code); dbg_hid_line("\n"); @@ -902,7 +950,7 @@ ignore: void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { struct input_dev *input; - int *quirks = &hid->quirks; + unsigned *quirks = &hid->quirks; if (!field->hidinput) return; @@ -991,6 +1039,29 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct return; } + /* Handling MS keyboards special buttons */ + if (IS_MS_KB(hid) && usage->hid == (HID_UP_MSVENDOR | 0xff05)) { + int key = 0; + static int last_key = 0; + switch (value) { + case 0x01: key = KEY_F14; break; + case 0x02: key = KEY_F15; break; + case 0x04: key = KEY_F16; break; + case 0x08: key = KEY_F17; break; + case 0x10: key = KEY_F18; break; + default: break; + } + if (key) { + input_event(input, usage->type, key, 1); + last_key = key; + } else { + input_event(input, usage->type, last_key, 0); + } + } + /* report the usage code as scancode if the key status has changed */ + if (usage->type == EV_KEY && !!test_bit(usage->code, input->key) != value) + input_event(input, EV_MSC, MSC_SCAN, usage->hid); + input_event(input, usage->type, usage->code, value); if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY)) @@ -1051,6 +1122,9 @@ int hidinput_connect(struct hid_device *hid) int i, j, k; int max_report_type = HID_OUTPUT_REPORT; + if (hid->quirks & HID_QUIRK_IGNORE_HIDINPUT) + return -1; + INIT_LIST_HEAD(&hid->inputs); for (i = 0; i < hid->maxcollection; i++) diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c new file mode 100644 index 000000000000..a702e2f6da7d --- /dev/null +++ b/drivers/hid/hidraw.c @@ -0,0 +1,407 @@ +/* + * HID raw devices, giving access to raw HID events. + * + * In comparison to hiddev, this device does not process the + * hid events at all (no parsing, no lookups). This lets applications + * to work on raw hid events as they want to, and avoids a need to + * use a transport-specific userspace libhid/libusb libraries. + * + * Copyright (c) 2007 Jiri Kosina + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * 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 St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/fs.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/cdev.h> +#include <linux/poll.h> +#include <linux/device.h> +#include <linux/major.h> +#include <linux/hid.h> +#include <linux/mutex.h> + +#include <linux/hidraw.h> + +static int hidraw_major; +static struct cdev hidraw_cdev; +static struct class *hidraw_class; +static struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES]; +static DEFINE_SPINLOCK(minors_lock); + +static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) +{ + struct hidraw_list *list = file->private_data; + int ret = 0, len; + char *report; + DECLARE_WAITQUEUE(wait, current); + + while (ret == 0) { + + mutex_lock(&list->read_mutex); + + if (list->head == list->tail) { + add_wait_queue(&list->hidraw->wait, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + while (list->head == list->tail) { + if (file->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + break; + } + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + if (!list->hidraw->exist) { + ret = -EIO; + break; + } + + /* allow O_NONBLOCK to work well from other threads */ + mutex_unlock(&list->read_mutex); + schedule(); + mutex_lock(&list->read_mutex); + set_current_state(TASK_INTERRUPTIBLE); + } + + set_current_state(TASK_RUNNING); + remove_wait_queue(&list->hidraw->wait, &wait); + } + + if (ret) + goto out; + + report = list->buffer[list->tail].value; + len = list->buffer[list->tail].len > count ? + count : list->buffer[list->tail].len; + + if (copy_to_user(buffer, list->buffer[list->tail].value, len)) { + ret = -EFAULT; + goto out; + } + ret += len; + + kfree(list->buffer[list->tail].value); + list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1); + } +out: + mutex_unlock(&list->read_mutex); + return ret; +} + +/* the first byte is expected to be a report number */ +static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + unsigned int minor = iminor(file->f_path.dentry->d_inode); + struct hid_device *dev = hidraw_table[minor]->hid; + __u8 *buf; + int ret = 0; + + if (!dev->hid_output_raw_report) + return -ENODEV; + + if (count > HID_MIN_BUFFER_SIZE) { + printk(KERN_WARNING "hidraw: pid %d passed too large report\n", + current->pid); + return -EINVAL; + } + + if (count < 2) { + printk(KERN_WARNING "hidraw: pid %d passed too short report\n", + current->pid); + return -EINVAL; + } + + buf = kmalloc(count * sizeof(__u8), GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (copy_from_user(buf, buffer, count)) { + ret = -EFAULT; + goto out; + } + + ret = dev->hid_output_raw_report(dev, buf, count); +out: + kfree(buf); + return ret; +} + +static unsigned int hidraw_poll(struct file *file, poll_table *wait) +{ + struct hidraw_list *list = file->private_data; + + poll_wait(file, &list->hidraw->wait, wait); + if (list->head != list->tail) + return POLLIN | POLLRDNORM; + if (!list->hidraw->exist) + return POLLERR | POLLHUP; + return 0; +} + +static int hidraw_open(struct inode *inode, struct file *file) +{ + unsigned int minor = iminor(inode); + struct hidraw *dev; + struct hidraw_list *list; + int err = 0; + + if (!(list = kzalloc(sizeof(struct hidraw_list), GFP_KERNEL))) { + err = -ENOMEM; + goto out; + } + + spin_lock(&minors_lock); + if (!hidraw_table[minor]) { + printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n", + minor); + kfree(list); + err = -ENODEV; + goto out_unlock; + } + + list->hidraw = hidraw_table[minor]; + mutex_init(&list->read_mutex); + list_add_tail(&list->node, &hidraw_table[minor]->list); + file->private_data = list; + + dev = hidraw_table[minor]; + if (!dev->open++) + dev->hid->hid_open(dev->hid); + +out_unlock: + spin_unlock(&minors_lock); +out: + return err; + +} + +static int hidraw_release(struct inode * inode, struct file * file) +{ + unsigned int minor = iminor(inode); + struct hidraw *dev; + struct hidraw_list *list = file->private_data; + + if (!hidraw_table[minor]) { + printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n", + minor); + return -ENODEV; + } + + list_del(&list->node); + dev = hidraw_table[minor]; + if (!dev->open--) { + if (list->hidraw->exist) + dev->hid->hid_close(dev->hid); + else + kfree(list->hidraw); + } + + return 0; +} + +static int hidraw_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + unsigned int minor = iminor(inode); + struct hidraw *dev = hidraw_table[minor]; + void __user *user_arg = (void __user*) arg; + + switch (cmd) { + case HIDIOCGRDESCSIZE: + if (put_user(dev->hid->rsize, (int __user *)arg)) + return -EFAULT; + return 0; + + case HIDIOCGRDESC: + { + __u32 len; + + if (get_user(len, (int __user *)arg)) + return -EFAULT; + + if (len > HID_MAX_DESCRIPTOR_SIZE - 1) + return -EINVAL; + + if (copy_to_user(user_arg + offsetof( + struct hidraw_report_descriptor, + value[0]), + dev->hid->rdesc, + min(dev->hid->rsize, len))) + return -EFAULT; + return 0; + } + case HIDIOCGRAWINFO: + { + struct hidraw_devinfo dinfo; + + dinfo.bustype = dev->hid->bus; + dinfo.vendor = dev->hid->vendor; + dinfo.product = dev->hid->product; + if (copy_to_user(user_arg, &dinfo, sizeof(dinfo))) + return -EFAULT; + + return 0; + } + default: + printk(KERN_EMERG "hidraw: unsupported ioctl() %x\n", + cmd); + } + return -EINVAL; +} + +static const struct file_operations hidraw_ops = { + .owner = THIS_MODULE, + .read = hidraw_read, + .write = hidraw_write, + .poll = hidraw_poll, + .open = hidraw_open, + .release = hidraw_release, + .ioctl = hidraw_ioctl, +}; + +void hidraw_report_event(struct hid_device *hid, u8 *data, int len) +{ + struct hidraw *dev = hid->hidraw; + struct hidraw_list *list; + + list_for_each_entry(list, &dev->list, node) { + list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC); + list->buffer[list->head].len = len; + list->head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1); + kill_fasync(&list->fasync, SIGIO, POLL_IN); + } + + wake_up_interruptible(&dev->wait); +} +EXPORT_SYMBOL_GPL(hidraw_report_event); + +int hidraw_connect(struct hid_device *hid) +{ + int minor, result; + struct hidraw *dev; + + /* TODO currently we accept any HID device. This should later + * probably be fixed to accept only those devices which provide + * non-input applications + */ + + dev = kzalloc(sizeof(struct hidraw), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + result = -EINVAL; + + spin_lock(&minors_lock); + + for (minor = 0; minor < HIDRAW_MAX_DEVICES; minor++) { + if (hidraw_table[minor]) + continue; + hidraw_table[minor] = dev; + result = 0; + break; + } + + spin_unlock(&minors_lock); + + if (result) { + kfree(dev); + goto out; + } + + dev->dev = device_create(hidraw_class, NULL, MKDEV(hidraw_major, minor), + "%s%d", "hidraw", minor); + + if (IS_ERR(dev->dev)) { + spin_lock(&minors_lock); + hidraw_table[minor] = NULL; + spin_unlock(&minors_lock); + result = PTR_ERR(dev->dev); + kfree(dev); + goto out; + } + + init_waitqueue_head(&dev->wait); + INIT_LIST_HEAD(&dev->list); + + dev->hid = hid; + dev->minor = minor; + + dev->exist = 1; + hid->hidraw = dev; + +out: + return result; + +} +EXPORT_SYMBOL_GPL(hidraw_connect); + +void hidraw_disconnect(struct hid_device *hid) +{ + struct hidraw *hidraw = hid->hidraw; + + hidraw->exist = 0; + + spin_lock(&minors_lock); + hidraw_table[hidraw->minor] = NULL; + spin_unlock(&minors_lock); + + device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor)); + + if (hidraw->open) { + hid->hid_close(hid); + wake_up_interruptible(&hidraw->wait); + } else { + kfree(hidraw); + } +} +EXPORT_SYMBOL_GPL(hidraw_disconnect); + +int __init hidraw_init(void) +{ + int result; + dev_t dev_id; + + result = alloc_chrdev_region(&dev_id, HIDRAW_FIRST_MINOR, + HIDRAW_MAX_DEVICES, "hidraw"); + + hidraw_major = MAJOR(dev_id); + + if (result < 0) { + printk(KERN_WARNING "hidraw: can't get major number\n"); + result = 0; + goto out; + } + + hidraw_class = class_create(THIS_MODULE, "hidraw"); + if (IS_ERR(hidraw_class)) { + result = PTR_ERR(hidraw_class); + unregister_chrdev(hidraw_major, "hidraw"); + goto out; + } + + cdev_init(&hidraw_cdev, &hidraw_ops); + cdev_add(&hidraw_cdev, dev_id, HIDRAW_MAX_DEVICES); +out: + return result; +} + +void __exit hidraw_exit(void) +{ + dev_t dev_id = MKDEV(hidraw_major, 0); + + cdev_del(&hidraw_cdev); + class_destroy(hidraw_class); + unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES); + +} diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig index 1b4b572f899b..c557d7040a69 100644 --- a/drivers/hid/usbhid/Kconfig +++ b/drivers/hid/usbhid/Kconfig @@ -71,19 +71,20 @@ config LOGITECH_FF force feedback. config PANTHERLORD_FF - bool "PantherLord USB/PS2 2in1 Adapter support" + bool "PantherLord/GreenAsia based device support" depends on HID_FF select INPUT_FF_MEMLESS if USB_HID help - Say Y here if you have a PantherLord USB/PS2 2in1 Adapter and want - to enable force feedback support for it. + Say Y here if you have a PantherLord/GreenAsia based game controller + or adapter and want to enable force feedback support for it. config THRUSTMASTER_FF - bool "ThrustMaster FireStorm Dual Power 2 support (EXPERIMENTAL)" + bool "ThrustMaster devices support (EXPERIMENTAL)" depends on HID_FF && EXPERIMENTAL select INPUT_FF_MEMLESS if USB_HID help - Say Y here if you have a THRUSTMASTER FireStore Dual Power 2, + Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or + a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel, and want to enable force feedback support for it. Note: if you say N here, this device will still be supported, but without force feedback. diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 0a1f2b52a12f..b38e559b7a46 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -32,6 +32,7 @@ #include <linux/hid.h> #include <linux/hiddev.h> #include <linux/hid-debug.h> +#include <linux/hidraw.h> #include "usbhid.h" /* @@ -512,7 +513,16 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum, int usbhid_open(struct hid_device *hid) { - ++hid->open; + struct usbhid_device *usbhid = hid->driver_data; + int res; + + if (!hid->open++) { + res = usb_autopm_get_interface(usbhid->intf); + if (res < 0) { + hid->open--; + return -EIO; + } + } if (hid_start_in(hid)) hid_io_error(hid); return 0; @@ -522,8 +532,10 @@ void usbhid_close(struct hid_device *hid) { struct usbhid_device *usbhid = hid->driver_data; - if (!--hid->open) + if (!--hid->open) { usb_kill_urb(usbhid->urbin); + usb_autopm_put_interface(usbhid->intf); + } } /* @@ -628,6 +640,28 @@ static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid) return 0; } +static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t count) +{ + struct usbhid_device *usbhid = hid->driver_data; + struct usb_device *dev = hid_to_usb_dev(hid); + struct usb_interface *intf = usbhid->intf; + struct usb_host_interface *interface = intf->cur_altsetting; + int ret; + + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + HID_REQ_SET_REPORT, + USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, + cpu_to_le16(((HID_OUTPUT_REPORT + 1) << 8) | *buf), + interface->desc.bInterfaceNumber, buf + 1, count - 1, + USB_CTRL_SET_TIMEOUT); + + /* count also the report id */ + if (ret > 0) + ret++; + + return ret; +} + static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid) { struct usbhid_device *usbhid = hid->driver_data; @@ -871,6 +905,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) hid->hiddev_hid_event = hiddev_hid_event; hid->hiddev_report_event = hiddev_report_event; #endif + hid->hid_output_raw_report = usbhid_output_raw_report; return hid; fail: @@ -909,6 +944,8 @@ static void hid_disconnect(struct usb_interface *intf) hidinput_disconnect(hid); if (hid->claimed & HID_CLAIMED_HIDDEV) hiddev_disconnect(hid); + if (hid->claimed & HID_CLAIMED_HIDRAW) + hidraw_disconnect(hid); usb_free_urb(usbhid->urbin); usb_free_urb(usbhid->urbctrl); @@ -941,11 +978,13 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id) hid->claimed |= HID_CLAIMED_INPUT; if (!hiddev_connect(hid)) hid->claimed |= HID_CLAIMED_HIDDEV; + if (!hidraw_connect(hid)) + hid->claimed |= HID_CLAIMED_HIDRAW; usb_set_intfdata(intf, hid); if (!hid->claimed) { - printk ("HID device not claimed by input or hiddev\n"); + printk ("HID device claimed by neither input, hiddev nor hidraw\n"); hid_disconnect(intf); return -ENODEV; } @@ -961,10 +1000,16 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id) if (hid->claimed & HID_CLAIMED_INPUT) printk("input"); - if (hid->claimed == (HID_CLAIMED_INPUT | HID_CLAIMED_HIDDEV)) + if ((hid->claimed & HID_CLAIMED_INPUT) && ((hid->claimed & HID_CLAIMED_HIDDEV) || + hid->claimed & HID_CLAIMED_HIDRAW)) printk(","); if (hid->claimed & HID_CLAIMED_HIDDEV) printk("hiddev%d", hid->minor); + if ((hid->claimed & HID_CLAIMED_INPUT) && (hid->claimed & HID_CLAIMED_HIDDEV) && + (hid->claimed & HID_CLAIMED_HIDRAW)) + printk(","); + if (hid->claimed & HID_CLAIMED_HIDRAW) + printk("hidraw%d", ((struct hidraw*)hid->hidraw)->minor); c = "Device"; for (i = 0; i < hid->maxcollection; i++) { @@ -1048,6 +1093,7 @@ static struct usb_driver hid_driver = { .pre_reset = hid_pre_reset, .post_reset = hid_post_reset, .id_table = hid_usb_ids, + .supports_autosuspend = 1, }; static int __init hid_init(void) diff --git a/drivers/hid/usbhid/hid-ff.c b/drivers/hid/usbhid/hid-ff.c index 23431fbbc3d7..22329feb3b5a 100644 --- a/drivers/hid/usbhid/hid-ff.c +++ b/drivers/hid/usbhid/hid-ff.c @@ -62,11 +62,14 @@ static struct hid_ff_initializer inits[] = { { 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */ #endif #ifdef CONFIG_PANTHERLORD_FF - { 0x810, 0x0001, hid_plff_init }, + { 0x810, 0x0001, hid_plff_init }, /* "Twin USB Joystick" */ + { 0xe8f, 0x0003, hid_plff_init }, /* "GreenAsia Inc. USB Joystick " */ #endif #ifdef CONFIG_THRUSTMASTER_FF { 0x44f, 0xb300, hid_tmff_init }, { 0x44f, 0xb304, hid_tmff_init }, + { 0x44f, 0xb651, hid_tmff_init }, /* FGT Rumble Force Wheel */ + { 0x44f, 0xb654, hid_tmff_init }, /* FGT Force Feedback Wheel */ #endif #ifdef CONFIG_ZEROPLUS_FF { 0xc12, 0x0005, hid_zpff_init }, diff --git a/drivers/hid/usbhid/hid-plff.c b/drivers/hid/usbhid/hid-plff.c index d6a8f2b49bd2..9eb83cf9d22b 100644 --- a/drivers/hid/usbhid/hid-plff.c +++ b/drivers/hid/usbhid/hid-plff.c @@ -1,5 +1,15 @@ /* - * Force feedback support for PantherLord USB/PS2 2in1 Adapter devices + * Force feedback support for PantherLord/GreenAsia based devices + * + * The devices are distributed under various names and the same USB device ID + * can be used in both adapters and actual game controllers. + * + * 0810:0001 "Twin USB Joystick" + * - tested with PantherLord USB/PS2 2in1 Adapter + * - contains two reports, one for each port (HID_QUIRK_MULTI_INPUT) + * + * 0e8f:0003 "GreenAsia Inc. USB Joystick " + * - tested with Köng Gaming gamepad * * Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com> */ @@ -67,11 +77,11 @@ int hid_plff_init(struct hid_device *hid) struct input_dev *dev; int error; - /* The device contains 2 output reports (one for each - HID_QUIRK_MULTI_INPUT device), both containing 1 field, which - contains 4 ff00.0002 usages and 4 16bit absolute values. + /* The device contains one output report per physical device, all + containing 1 field, which contains 4 ff00.0002 usages and 4 16bit + absolute values. - The 2 input reports also contain a field which contains + The input reports also contain a field which contains 8 ff00.0001 usages and 8 boolean values. Their meaning is currently unknown. */ @@ -122,8 +132,8 @@ int hid_plff_init(struct hid_device *hid) usbhid_submit_report(hid, plff->report, USB_DIR_OUT); } - printk(KERN_INFO "hid-plff: Force feedback for PantherLord USB/PS2 " - "2in1 Adapters by Anssi Hannula <anssi.hannula@gmail.com>\n"); + printk(KERN_INFO "hid-plff: Force feedback for PantherLord/GreenAsia " + "devices by Anssi Hannula <anssi.hannula@gmail.com>\n"); return 0; } diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 6b21a214f419..41a59a80e7ed 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -61,6 +61,7 @@ #define USB_DEVICE_ID_APPLE_GEYSER4_JIS 0x021c #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b +#define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242 #define USB_VENDOR_ID_ASUS 0x0b05 #define USB_DEVICE_ID_ASUS_LCM 0x1726 @@ -86,6 +87,9 @@ #define USB_VENDOR_ID_CIDC 0x1677 +#define USB_VENDOR_ID_CMEDIA 0x0d8c +#define USB_DEVICE_ID_CM109 0x000e + #define USB_VENDOR_ID_CODEMERCS 0x07c0 #define USB_DEVICE_ID_CODEMERCS_IOW_FIRST 0x1500 #define USB_DEVICE_ID_CODEMERCS_IOW_LAST 0x15ff @@ -104,12 +108,17 @@ #define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100 #define USB_DEVICE_ID_DELORME_EM_LT20 0x0200 +#define USB_VENDOR_ID_ELO 0x04E7 +#define USB_DEVICE_ID_ELO_TS2700 0x0020 + #define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100 #define USB_VENDOR_ID_GAMERON 0x0810 #define USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR 0x0001 +#define USB_VENDOR_ID_GENERAL_TOUCH 0x0dfc + #define USB_VENDOR_ID_GLAB 0x06c2 #define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038 #define USB_DEVICE_ID_1_PHIDGETSERVO_30 0x0039 @@ -373,6 +382,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES }, { USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV, HID_QUIRK_HIDINPUT }, { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01, HID_QUIRK_IGNORE }, @@ -387,11 +397,16 @@ static const struct hid_blacklist { { USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM, HID_QUIRK_IGNORE}, { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_CIDC, 0x0103, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM109, 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 }, { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GENERAL_TOUCH, 0x0001, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GENERAL_TOUCH, 0x0002, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GENERAL_TOUCH, 0x0003, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GENERAL_TOUCH, 0x0004, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT, HID_QUIRK_IGNORE }, @@ -507,6 +522,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL, HID_QUIRK_NOGET }, { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, @@ -614,6 +630,8 @@ static const struct hid_rdesc_blacklist { { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER, HID_QUIRK_RDESC_LOGITECH }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2, HID_QUIRK_RDESC_LOGITECH }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_RDESC_MACBOOK_JIS }, + { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_RDESC_PETALYNX }, { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_RDESC_SWAPPED_MIN_MAX }, @@ -927,6 +945,18 @@ static void usbhid_fixup_cypress_descriptor(unsigned char *rdesc, int rsize) printk(KERN_INFO "Fixing up Cypress report descriptor\n"); } +/* + * MacBook JIS keyboard has wrong logical maximum + */ +static void usbhid_fixup_macbook_descriptor(unsigned char *rdesc, int rsize) +{ + if (rsize >= 60 && rdesc[53] == 0x65 + && rdesc[59] == 0x65) { + printk(KERN_INFO "Fixing up MacBook JIS keyboard report descriptor\n"); + rdesc[53] = rdesc[59] = 0xe7; + } +} + static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned rsize) { @@ -941,6 +971,9 @@ static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned if (quirks & HID_QUIRK_RDESC_PETALYNX) usbhid_fixup_petalynx_descriptor(rdesc, rsize); + + if (quirks & HID_QUIRK_RDESC_MACBOOK_JIS) + usbhid_fixup_macbook_descriptor(rdesc, rsize); } /** diff --git a/drivers/hid/usbhid/hid-tmff.c b/drivers/hid/usbhid/hid-tmff.c index 555bb48b4295..69882a726e99 100644 --- a/drivers/hid/usbhid/hid-tmff.c +++ b/drivers/hid/usbhid/hid-tmff.c @@ -36,16 +36,39 @@ #include "usbhid.h" /* Usages for thrustmaster devices I know about */ -#define THRUSTMASTER_USAGE_RUMBLE_LR (HID_UP_GENDESK | 0xbb) +#define THRUSTMASTER_USAGE_FF (HID_UP_GENDESK | 0xbb) +struct dev_type { + u16 idVendor; + u16 idProduct; + const signed short *ff; +}; + +static const signed short ff_rumble[] = { + FF_RUMBLE, + -1 +}; + +static const signed short ff_joystick[] = { + FF_CONSTANT, + -1 +}; + +static const struct dev_type devices[] = { + { 0x44f, 0xb300, ff_rumble }, + { 0x44f, 0xb304, ff_rumble }, + { 0x44f, 0xb651, ff_rumble }, /* FGT Rumble Force Wheel */ + { 0x44f, 0xb654, ff_joystick }, /* FGT Force Feedback Wheel */ +}; struct tmff_device { struct hid_report *report; - struct hid_field *rumble; + struct hid_field *ff_field; }; /* Changes values from 0 to 0xffff into values from minimum to maximum */ -static inline int hid_tmff_scale(unsigned int in, int minimum, int maximum) +static inline int hid_tmff_scale_u16(unsigned int in, + int minimum, int maximum) { int ret; @@ -57,22 +80,57 @@ static inline int hid_tmff_scale(unsigned int in, int minimum, int maximum) return ret; } +/* Changes values from -0x80 to 0x7f into values from minimum to maximum */ +static inline int hid_tmff_scale_s8(int in, + int minimum, int maximum) +{ + int ret; + + ret = (((in + 0x80) * (maximum - minimum)) / 0xff) + minimum; + if (ret < minimum) + return minimum; + if (ret > maximum) + return maximum; + return ret; +} + static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *effect) { struct hid_device *hid = input_get_drvdata(dev); struct tmff_device *tmff = data; + struct hid_field *ff_field = tmff->ff_field; + int x, y; int left, right; /* Rumbling */ - left = hid_tmff_scale(effect->u.rumble.weak_magnitude, - tmff->rumble->logical_minimum, tmff->rumble->logical_maximum); - right = hid_tmff_scale(effect->u.rumble.strong_magnitude, - tmff->rumble->logical_minimum, tmff->rumble->logical_maximum); - - tmff->rumble->value[0] = left; - tmff->rumble->value[1] = right; - dbg_hid("(left,right)=(%08x, %08x)\n", left, right); - usbhid_submit_report(hid, tmff->report, USB_DIR_OUT); - + switch (effect->type) { + case FF_CONSTANT: + x = hid_tmff_scale_s8(effect->u.ramp.start_level, + ff_field->logical_minimum, + ff_field->logical_maximum); + y = hid_tmff_scale_s8(effect->u.ramp.end_level, + ff_field->logical_minimum, + ff_field->logical_maximum); + + dbg_hid("(x, y)=(%04x, %04x)\n", x, y); + ff_field->value[0] = x; + ff_field->value[1] = y; + usbhid_submit_report(hid, tmff->report, USB_DIR_OUT); + break; + + case FF_RUMBLE: + left = hid_tmff_scale_u16(effect->u.rumble.weak_magnitude, + ff_field->logical_minimum, + ff_field->logical_maximum); + right = hid_tmff_scale_u16(effect->u.rumble.strong_magnitude, + ff_field->logical_minimum, + ff_field->logical_maximum); + + dbg_hid("(left,right)=(%08x, %08x)\n", left, right); + ff_field->value[0] = left; + ff_field->value[1] = right; + usbhid_submit_report(hid, tmff->report, USB_DIR_OUT); + break; + } return 0; } @@ -82,14 +140,16 @@ int hid_tmff_init(struct hid_device *hid) struct list_head *pos; struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); struct input_dev *input_dev = hidinput->input; + const signed short *ff_bits = ff_joystick; int error; + int i; tmff = kzalloc(sizeof(struct tmff_device), GFP_KERNEL); if (!tmff) return -ENOMEM; /* Find the report to use */ - __list_for_each(pos, &hid->report_enum[HID_OUTPUT_REPORT].report_list) { + list_for_each(pos, &hid->report_enum[HID_OUTPUT_REPORT].report_list) { struct hid_report *report = (struct hid_report *)pos; int fieldnum; @@ -100,48 +160,65 @@ int hid_tmff_init(struct hid_device *hid) continue; switch (field->usage[0].hid) { - case THRUSTMASTER_USAGE_RUMBLE_LR: - if (field->report_count < 2) { - warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR with report_count < 2"); - continue; - } + case THRUSTMASTER_USAGE_FF: + if (field->report_count < 2) { + warn("ignoring FF field with report_count < 2"); + continue; + } - if (field->logical_maximum == field->logical_minimum) { - warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR with logical_maximum == logical_minimum"); - continue; - } + if (field->logical_maximum == field->logical_minimum) { + warn("ignoring FF field with logical_maximum == logical_minimum"); + continue; + } - if (tmff->report && tmff->report != report) { - warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR in other report"); - continue; - } + if (tmff->report && tmff->report != report) { + warn("ignoring FF field in other report"); + continue; + } - if (tmff->rumble && tmff->rumble != field) { - warn("ignoring duplicate THRUSTMASTER_USAGE_RUMBLE_LR"); - continue; + if (tmff->ff_field && tmff->ff_field != field) { + warn("ignoring duplicate FF field"); + continue; + } + + tmff->report = report; + tmff->ff_field = field; + + for (i = 0; i < ARRAY_SIZE(devices); i++) { + if (input_dev->id.vendor == devices[i].idVendor && + input_dev->id.product == devices[i].idProduct) { + ff_bits = devices[i].ff; + break; } + } - tmff->report = report; - tmff->rumble = field; + for (i = 0; ff_bits[i] >= 0; i++) + set_bit(ff_bits[i], input_dev->ffbit); - set_bit(FF_RUMBLE, input_dev->ffbit); - break; + break; - default: - warn("ignoring unknown output usage %08x", field->usage[0].hid); - continue; + default: + warn("ignoring unknown output usage %08x", field->usage[0].hid); + continue; } } } - error = input_ff_create_memless(input_dev, tmff, hid_tmff_play); - if (error) { - kfree(tmff); - return error; + if (!tmff->report) { + err("cant find FF field in output reports\n"); + error = -ENODEV; + goto fail; } - info("Force feedback for ThrustMaster rumble pad devices by Zinx Verituse <zinx@epicsol.org>"); + error = input_ff_create_memless(input_dev, tmff, hid_tmff_play); + if (error) + goto fail; + info("Force feedback for ThrustMaster devices by Zinx Verituse <zinx@epicsol.org>"); return 0; + + fail: + kfree(tmff); + return error; } diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index e793127f971e..9837adcb17e9 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -34,6 +34,7 @@ #include <linux/usb.h> #include <linux/hid.h> #include <linux/hiddev.h> +#include <linux/compat.h> #include "usbhid.h" #ifdef CONFIG_USB_DYNAMIC_MINORS @@ -738,6 +739,14 @@ inval: return -EINVAL; } +#ifdef CONFIG_COMPAT +static long hiddev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct inode *inode = file->f_path.dentry->d_inode; + return hiddev_ioctl(inode, file, cmd, compat_ptr(arg)); +} +#endif + static const struct file_operations hiddev_fops = { .owner = THIS_MODULE, .read = hiddev_read, @@ -747,6 +756,9 @@ static const struct file_operations hiddev_fops = { .release = hiddev_release, .ioctl = hiddev_ioctl, .fasync = hiddev_fasync, +#ifdef CONFIG_COMPAT + .compat_ioctl = hiddev_compat_ioctl, +#endif }; static struct usb_class_driver hiddev_class = { diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 192953b29b28..700a1657554f 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -30,7 +30,7 @@ config HWMON_VID config SENSORS_ABITUGURU tristate "Abit uGuru (rev 1 & 2)" - depends on EXPERIMENTAL + depends on X86 && EXPERIMENTAL help If you say yes here you get support for the sensor part of the first and second revision of the Abit uGuru chip. The voltage and frequency @@ -45,7 +45,7 @@ config SENSORS_ABITUGURU config SENSORS_ABITUGURU3 tristate "Abit uGuru (rev 3)" - depends on HWMON && EXPERIMENTAL + depends on X86 && EXPERIMENTAL help If you say yes here you get support for the sensor part of the third revision of the Abit uGuru chip. Only reading the sensors @@ -133,6 +133,16 @@ config SENSORS_ADM9240 This driver can also be built as a module. If so, the module will be called adm9240. +config SENSORS_ADT7470 + tristate "Analog Devices ADT7470" + depends on I2C && EXPERIMENTAL + help + If you say yes here you get support for the Analog Devices + ADT7470 temperature monitoring chips. + + This driver can also be built as a module. If so, the module + will be called adt7470. + config SENSORS_K8TEMP tristate "AMD Athlon64/FX or Opteron temperature sensor" depends on X86 && PCI && EXPERIMENTAL @@ -148,6 +158,7 @@ config SENSORS_K8TEMP config SENSORS_AMS tristate "Apple Motion Sensor driver" depends on PPC_PMAC && !PPC64 && INPUT && ((ADB_PMU && I2C = y) || (ADB_PMU && !I2C) || I2C) && EXPERIMENTAL + select INPUT_POLLDEV help Support for the motion sensor included in PowerBooks. Includes implementations for PMU and I2C. @@ -172,7 +183,7 @@ config SENSORS_AMS_I2C config SENSORS_ASB100 tristate "Asus ASB100 Bach" - depends on I2C && EXPERIMENTAL + depends on X86 && I2C && EXPERIMENTAL select HWMON_VID help If you say yes here you get support for the ASB100 Bach sensor @@ -206,19 +217,39 @@ config SENSORS_DS1621 will be called ds1621. config SENSORS_F71805F - tristate "Fintek F71805F/FG and F71872F/FG" + tristate "Fintek F71805F/FG, F71806F/FG and F71872F/FG" depends on EXPERIMENTAL help If you say yes here you get support for hardware monitoring - features of the Fintek F71805F/FG and F71872F/FG Super-I/O - chips. + features of the Fintek F71805F/FG, F71806F/FG and F71872F/FG + Super-I/O chips. This driver can also be built as a module. If so, the module will be called f71805f. +config SENSORS_F71882FG + tristate "Fintek F71882FG and F71883FG" + depends on EXPERIMENTAL + help + If you say yes here you get support for hardware monitoring + features of the Fintek F71882FG and F71883FG Super-I/O chips. + + This driver can also be built as a module. If so, the module + will be called f71882fg. + +config SENSORS_F75375S + tristate "Fintek F75375S/SP and F75373"; + depends on I2C && EXPERIMENTAL + help + If you say yes here you get support for hardware monitoring + features of the Fintek F75375S/SP and F75373 + + This driver can also be built as a module. If so, the module + will be called f75375s. + config SENSORS_FSCHER tristate "FSC Hermes" - depends on I2C + depends on X86 && I2C help If you say yes here you get support for Fujitsu Siemens Computers Hermes sensor chips. @@ -228,7 +259,7 @@ config SENSORS_FSCHER config SENSORS_FSCPOS tristate "FSC Poseidon" - depends on I2C + depends on X86 && I2C help If you say yes here you get support for Fujitsu Siemens Computers Poseidon sensor chips. @@ -236,6 +267,20 @@ config SENSORS_FSCPOS This driver can also be built as a module. If so, the module will be called fscpos. +config SENSORS_FSCHMD + tristate "FSC Poseidon, Scylla, Hermes, Heimdall and Heracles" + depends on X86 && I2C && EXPERIMENTAL + help + If you say yes here you get support for various Fujitsu Siemens + Computers sensor chips. + + This is a new merged driver for FSC sensor chips which is intended + as a replacment for the fscpos, fscscy and fscher drivers and adds + support for several other FCS sensor chips. + + This driver can also be built as a module. If so, the module + will be called fschmd. + config SENSORS_GL518SM tristate "Genesys Logic GL518SM" depends on I2C @@ -265,6 +310,19 @@ config SENSORS_CORETEMP sensor inside your CPU. Supported all are all known variants of Intel Core family. +config SENSORS_IBMPEX + tristate "IBM PowerExecutive temperature/power sensors" + select IPMI_SI + depends on IPMI_HANDLER + help + If you say yes here you get support for the temperature and + power sensors in various IBM System X servers that support + PowerExecutive. So far this includes the x3550, x3650, x3655, + x3755, and certain HS20 blades. + + This driver can also be built as a module. If so, the module + will be called ibmpex. + config SENSORS_IT87 tristate "ITE IT87xx and compatibles" select HWMON_VID @@ -401,7 +459,7 @@ config SENSORS_LM92 config SENSORS_LM93 tristate "National Semiconductor LM93 and compatibles" - depends on HWMON && I2C + depends on I2C select HWMON_VID help If you say yes here you get support for National Semiconductor LM93 @@ -466,13 +524,13 @@ config SENSORS_SIS5595 will be called sis5595. config SENSORS_DME1737 - tristate "SMSC DME1737 and compatibles" + tristate "SMSC DME1737, SCH311x and compatibles" depends on I2C && EXPERIMENTAL select HWMON_VID help If you say yes here you get support for the hardware monitoring and fan control features of the SMSC DME1737 (and compatibles - like the Asus A8000) Super-I/O chip. + like the Asus A8000) and SCH311x Super-I/O chips. This driver can also be built as a module. If so, the module will be called dme1737. @@ -644,6 +702,7 @@ config SENSORS_W83627EHF config SENSORS_HDAPS tristate "IBM Hard Drive Active Protection System (hdaps)" depends on INPUT && X86 + select INPUT_POLLDEV default n help This driver provides support for the IBM Hard Drive Active Protection @@ -665,6 +724,7 @@ config SENSORS_APPLESMC depends on INPUT && X86 select NEW_LEDS select LEDS_CLASS + select INPUT_POLLDEV default n help This driver provides support for the Apple System Management diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index d04f90031ebf..6da3eef94306 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o obj-$(CONFIG_SENSORS_ADM1029) += adm1029.o obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o +obj-$(CONFIG_SENSORS_ADT7470) += adt7470.o obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o obj-$(CONFIG_SENSORS_AMS) += ams/ obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o @@ -29,11 +30,15 @@ obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o obj-$(CONFIG_SENSORS_DME1737) += dme1737.o obj-$(CONFIG_SENSORS_DS1621) += ds1621.o obj-$(CONFIG_SENSORS_F71805F) += f71805f.o +obj-$(CONFIG_SENSORS_F71882FG) += f71882fg.o +obj-$(CONFIG_SENSORS_F75375S) += f75375s.o obj-$(CONFIG_SENSORS_FSCHER) += fscher.o +obj-$(CONFIG_SENSORS_FSCHMD) += fschmd.o obj-$(CONFIG_SENSORS_FSCPOS) += fscpos.o obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o +obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o obj-$(CONFIG_SENSORS_IT87) += it87.o obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o obj-$(CONFIG_SENSORS_LM63) += lm63.o diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c index 2317f4bb9c92..4dbdb81ea3b1 100644 --- a/drivers/hwmon/abituguru.c +++ b/drivers/hwmon/abituguru.c @@ -176,7 +176,7 @@ MODULE_PARM_DESC(verbose, "How verbose should the driver be? (0-3):\n" The structure is dynamically allocated, at the same time when a new abituguru device is allocated. */ struct abituguru_data { - struct class_device *class_dev; /* hwmon registered device */ + struct device *hwmon_dev; /* hwmon registered device */ struct mutex update_lock; /* protect access to data and uGuru */ unsigned long last_updated; /* In jiffies */ unsigned short addr; /* uguru base address */ @@ -1287,11 +1287,11 @@ static int __devinit abituguru_probe(struct platform_device *pdev) &abituguru_sysfs_attr[i].dev_attr)) goto abituguru_probe_error; - data->class_dev = hwmon_device_register(&pdev->dev); - if (!IS_ERR(data->class_dev)) + data->hwmon_dev = hwmon_device_register(&pdev->dev); + if (!IS_ERR(data->hwmon_dev)) return 0; /* success */ - res = PTR_ERR(data->class_dev); + res = PTR_ERR(data->hwmon_dev); abituguru_probe_error: for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++) device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr); @@ -1308,7 +1308,7 @@ static int __devexit abituguru_remove(struct platform_device *pdev) int i; struct abituguru_data *data = platform_get_drvdata(pdev); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++) device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr); for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++) diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c index cdd8b6dea16d..cb2331bfd9d5 100644 --- a/drivers/hwmon/abituguru3.c +++ b/drivers/hwmon/abituguru3.c @@ -124,7 +124,7 @@ struct abituguru3_motherboard_info { The structure is dynamically allocated, at the same time when a new abituguru3 device is allocated. */ struct abituguru3_data { - struct class_device *class_dev; /* hwmon registered device */ + struct device *hwmon_dev; /* hwmon registered device */ struct mutex update_lock; /* protect access to data and uGuru */ unsigned short addr; /* uguru base address */ char valid; /* !=0 if following fields are valid */ @@ -933,9 +933,9 @@ static int __devinit abituguru3_probe(struct platform_device *pdev) &abituguru3_sysfs_attr[i].dev_attr)) goto abituguru3_probe_error; - data->class_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(data->class_dev)) { - res = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(data->hwmon_dev)) { + res = PTR_ERR(data->hwmon_dev); goto abituguru3_probe_error; } @@ -957,7 +957,7 @@ static int __devexit abituguru3_remove(struct platform_device *pdev) struct abituguru3_data *data = platform_get_drvdata(pdev); platform_set_drvdata(pdev, NULL); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++) device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr); for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++) diff --git a/drivers/hwmon/ad7418.c b/drivers/hwmon/ad7418.c index cc8b624a1e51..fcd7fe78f3f9 100644 --- a/drivers/hwmon/ad7418.c +++ b/drivers/hwmon/ad7418.c @@ -47,7 +47,7 @@ static const u8 AD7418_REG_TEMP[] = { AD7418_REG_TEMP_IN, struct ad7418_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct attribute_group attrs; enum chips type; struct mutex lock; @@ -172,7 +172,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct i2c_client *client = to_i2c_client(dev); struct ad7418_data *data = i2c_get_clientdata(client); - int temp = simple_strtol(buf, NULL, 10); + long temp = simple_strtol(buf, NULL, 10); mutex_lock(&data->lock); data->temp[attr->index] = LM75_TEMP_TO_REG(temp); @@ -326,9 +326,9 @@ static int ad7418_detect(struct i2c_adapter *adapter, int address, int kind) if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs))) goto exit_detach; - data->class_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove; } @@ -347,7 +347,7 @@ exit: static int ad7418_detach_client(struct i2c_client *client) { struct ad7418_data *data = i2c_get_clientdata(client); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &data->attrs); i2c_detach_client(client); kfree(data); diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c index c466329b2ef4..ebdc6d7db231 100644 --- a/drivers/hwmon/adm1021.c +++ b/drivers/hwmon/adm1021.c @@ -1,6 +1,6 @@ /* adm1021.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring + monitoring Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> and Philip Edelbrock <phil@netroedge.com> @@ -25,6 +25,7 @@ #include <linux/jiffies.h> #include <linux/i2c.h> #include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> #include <linux/err.h> #include <linux/mutex.h> @@ -32,93 +33,77 @@ /* Addresses to scan */ static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, - 0x4c, 0x4d, 0x4e, + 0x4c, 0x4d, 0x4e, I2C_CLIENT_END }; /* Insmod parameters */ -I2C_CLIENT_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm, mc1066); +I2C_CLIENT_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm, + mc1066); /* adm1021 constants specified below */ /* The adm1021 registers */ /* Read-only */ -#define ADM1021_REG_TEMP 0x00 -#define ADM1021_REG_REMOTE_TEMP 0x01 +/* For nr in 0-1 */ +#define ADM1021_REG_TEMP(nr) (nr) #define ADM1021_REG_STATUS 0x02 -#define ADM1021_REG_MAN_ID 0x0FE /* 0x41 = AMD, 0x49 = TI, 0x4D = Maxim, 0x23 = Genesys , 0x54 = Onsemi*/ -#define ADM1021_REG_DEV_ID 0x0FF /* ADM1021 = 0x0X, ADM1023 = 0x3X */ -#define ADM1021_REG_DIE_CODE 0x0FF /* MAX1617A */ +/* 0x41 = AD, 0x49 = TI, 0x4D = Maxim, 0x23 = Genesys , 0x54 = Onsemi */ +#define ADM1021_REG_MAN_ID 0xFE +/* ADM1021 = 0x0X, ADM1023 = 0x3X */ +#define ADM1021_REG_DEV_ID 0xFF /* These use different addresses for reading/writing */ #define ADM1021_REG_CONFIG_R 0x03 #define ADM1021_REG_CONFIG_W 0x09 #define ADM1021_REG_CONV_RATE_R 0x04 #define ADM1021_REG_CONV_RATE_W 0x0A /* These are for the ADM1023's additional precision on the remote temp sensor */ -#define ADM1021_REG_REM_TEMP_PREC 0x010 -#define ADM1021_REG_REM_OFFSET 0x011 -#define ADM1021_REG_REM_OFFSET_PREC 0x012 -#define ADM1021_REG_REM_TOS_PREC 0x013 -#define ADM1021_REG_REM_THYST_PREC 0x014 +#define ADM1023_REG_REM_TEMP_PREC 0x10 +#define ADM1023_REG_REM_OFFSET 0x11 +#define ADM1023_REG_REM_OFFSET_PREC 0x12 +#define ADM1023_REG_REM_TOS_PREC 0x13 +#define ADM1023_REG_REM_THYST_PREC 0x14 /* limits */ -#define ADM1021_REG_TOS_R 0x05 -#define ADM1021_REG_TOS_W 0x0B -#define ADM1021_REG_REMOTE_TOS_R 0x07 -#define ADM1021_REG_REMOTE_TOS_W 0x0D -#define ADM1021_REG_THYST_R 0x06 -#define ADM1021_REG_THYST_W 0x0C -#define ADM1021_REG_REMOTE_THYST_R 0x08 -#define ADM1021_REG_REMOTE_THYST_W 0x0E +/* For nr in 0-1 */ +#define ADM1021_REG_TOS_R(nr) (0x05 + 2 * (nr)) +#define ADM1021_REG_TOS_W(nr) (0x0B + 2 * (nr)) +#define ADM1021_REG_THYST_R(nr) (0x06 + 2 * (nr)) +#define ADM1021_REG_THYST_W(nr) (0x0C + 2 * (nr)) /* write-only */ #define ADM1021_REG_ONESHOT 0x0F - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -/* Conversions note: 1021 uses normal integer signed-byte format*/ -#define TEMP_FROM_REG(val) (val > 127 ? (val-256)*1000 : val*1000) -#define TEMP_TO_REG(val) (SENSORS_LIMIT((val < 0 ? (val/1000)+256 : val/1000),0,255)) - /* Initial values */ -/* Note: Even though I left the low and high limits named os and hyst, -they don't quite work like a thermostat the way the LM75 does. I.e., -a lower temp than THYST actually triggers an alarm instead of +/* Note: Even though I left the low and high limits named os and hyst, +they don't quite work like a thermostat the way the LM75 does. I.e., +a lower temp than THYST actually triggers an alarm instead of clearing it. Weird, ey? --Phil */ /* Each client has this additional data */ struct adm1021_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; enum chips type; struct mutex update_lock; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ - u8 temp_max; /* Register values */ - u8 temp_hyst; - u8 temp_input; - u8 remote_temp_max; - u8 remote_temp_hyst; - u8 remote_temp_input; - u8 alarms; - /* Special values for ADM1023 only */ - u8 remote_temp_prec; - u8 remote_temp_os_prec; - u8 remote_temp_hyst_prec; - u8 remote_temp_offset; - u8 remote_temp_offset_prec; + s8 temp_max[2]; /* Register values */ + s8 temp_min[2]; + s8 temp[2]; + u8 alarms; + /* Special values for ADM1023 only */ + u8 remote_temp_prec; + u8 remote_temp_os_prec; + u8 remote_temp_hyst_prec; + u8 remote_temp_offset; + u8 remote_temp_offset_prec; }; static int adm1021_attach_adapter(struct i2c_adapter *adapter); static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind); static void adm1021_init_client(struct i2c_client *client); static int adm1021_detach_client(struct i2c_client *client); -static int adm1021_read_value(struct i2c_client *client, u8 reg); -static int adm1021_write_value(struct i2c_client *client, u8 reg, - u16 value); static struct adm1021_data *adm1021_update_device(struct device *dev); /* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */ @@ -135,53 +120,104 @@ static struct i2c_driver adm1021_driver = { .detach_client = adm1021_detach_client, }; -#define show(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1021_data *data = adm1021_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \ +static ssize_t show_temp(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct adm1021_data *data = adm1021_update_device(dev); + + return sprintf(buf, "%d\n", 1000 * data->temp[index]); } -show(temp_max); -show(temp_hyst); -show(temp_input); -show(remote_temp_max); -show(remote_temp_hyst); -show(remote_temp_input); - -#define show2(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1021_data *data = adm1021_update_device(dev); \ - return sprintf(buf, "%d\n", data->value); \ + +static ssize_t show_temp_max(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct adm1021_data *data = adm1021_update_device(dev); + + return sprintf(buf, "%d\n", 1000 * data->temp_max[index]); } -show2(alarms); - -#define set(value, reg) \ -static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct adm1021_data *data = i2c_get_clientdata(client); \ - int temp = simple_strtoul(buf, NULL, 10); \ - \ - mutex_lock(&data->update_lock); \ - data->value = TEMP_TO_REG(temp); \ - adm1021_write_value(client, reg, data->value); \ - mutex_unlock(&data->update_lock); \ - return count; \ + +static ssize_t show_temp_min(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct adm1021_data *data = adm1021_update_device(dev); + + return sprintf(buf, "%d\n", 1000 * data->temp_min[index]); +} + +static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int index = to_sensor_dev_attr(attr)->index; + struct adm1021_data *data = adm1021_update_device(dev); + return sprintf(buf, "%u\n", (data->alarms >> index) & 1); +} + +static ssize_t show_alarms(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct adm1021_data *data = adm1021_update_device(dev); + return sprintf(buf, "%u\n", data->alarms); } -set(temp_max, ADM1021_REG_TOS_W); -set(temp_hyst, ADM1021_REG_THYST_W); -set(remote_temp_max, ADM1021_REG_REMOTE_TOS_W); -set(remote_temp_hyst, ADM1021_REG_REMOTE_THYST_W); - -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max); -static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_hyst, set_temp_hyst); -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL); -static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_remote_temp_max, set_remote_temp_max); -static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_remote_temp_hyst, set_remote_temp_hyst); -static DEVICE_ATTR(temp2_input, S_IRUGO, show_remote_temp_input, NULL); -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static ssize_t set_temp_max(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct adm1021_data *data = i2c_get_clientdata(client); + long temp = simple_strtol(buf, NULL, 10) / 1000; + + mutex_lock(&data->update_lock); + data->temp_max[index] = SENSORS_LIMIT(temp, -128, 127); + if (!read_only) + i2c_smbus_write_byte_data(client, ADM1021_REG_TOS_W(index), + data->temp_max[index]); + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t set_temp_min(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct adm1021_data *data = i2c_get_clientdata(client); + long temp = simple_strtol(buf, NULL, 10) / 1000; + + mutex_lock(&data->update_lock); + data->temp_min[index] = SENSORS_LIMIT(temp, -128, 127); + if (!read_only) + i2c_smbus_write_byte_data(client, ADM1021_REG_THYST_W(index), + data->temp_min[index]); + mutex_unlock(&data->update_lock); + + return count; +} + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, + set_temp_max, 0); +static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min, + set_temp_min, 0); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1); +static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_max, + set_temp_max, 1); +static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_min, + set_temp_min, 1); +static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6); +static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 5); +static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4); +static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3); +static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2); + +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); static int adm1021_attach_adapter(struct i2c_adapter *adapter) { @@ -191,12 +227,17 @@ static int adm1021_attach_adapter(struct i2c_adapter *adapter) } static struct attribute *adm1021_attributes[] = { - &dev_attr_temp1_max.attr, - &dev_attr_temp1_min.attr, - &dev_attr_temp1_input.attr, - &dev_attr_temp2_max.attr, - &dev_attr_temp2_min.attr, - &dev_attr_temp2_input.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp2_min.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_min_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_fault.dev_attr.attr, &dev_attr_alarms.attr, NULL }; @@ -208,35 +249,44 @@ static const struct attribute_group adm1021_group = { static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind) { int i; - struct i2c_client *new_client; + struct i2c_client *client; struct adm1021_data *data; int err = 0; const char *type_name = ""; + int conv_rate, status, config; - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + pr_debug("adm1021: detect failed, " + "smbus byte data not supported!\n"); goto error0; + } /* OK. For now, we presume we have a valid client. We now create the client structure, even though we cannot fill it completely yet. - But it allows us to access adm1021_{read,write}_value. */ + But it allows us to access adm1021 register values. */ if (!(data = kzalloc(sizeof(struct adm1021_data), GFP_KERNEL))) { + pr_debug("adm1021: detect failed, kzalloc failed!\n"); err = -ENOMEM; goto error0; } - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &adm1021_driver; - new_client->flags = 0; + client = &data->client; + i2c_set_clientdata(client, data); + client->addr = address; + client->adapter = adapter; + client->driver = &adm1021_driver; + status = i2c_smbus_read_byte_data(client, ADM1021_REG_STATUS); + conv_rate = i2c_smbus_read_byte_data(client, + ADM1021_REG_CONV_RATE_R); + config = i2c_smbus_read_byte_data(client, ADM1021_REG_CONFIG_R); /* Now, we do the remaining detection. */ if (kind < 0) { - if ((adm1021_read_value(new_client, ADM1021_REG_STATUS) & 0x03) != 0x00 - || (adm1021_read_value(new_client, ADM1021_REG_CONFIG_R) & 0x3F) != 0x00 - || (adm1021_read_value(new_client, ADM1021_REG_CONV_RATE_R) & 0xF8) != 0x00) { + if ((status & 0x03) != 0x00 || (config & 0x3F) != 0x00 + || (conv_rate & 0xF8) != 0x00) { + pr_debug("adm1021: detect failed, " + "chip not detected!\n"); err = -ENODEV; goto error1; } @@ -244,9 +294,10 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind) /* Determine the chip type. */ if (kind <= 0) { - i = adm1021_read_value(new_client, ADM1021_REG_MAN_ID); + i = i2c_smbus_read_byte_data(client, ADM1021_REG_MAN_ID); if (i == 0x41) - if ((adm1021_read_value(new_client, ADM1021_REG_DEV_ID) & 0x0F0) == 0x030) + if ((i2c_smbus_read_byte_data(client, + ADM1021_REG_DEV_ID) & 0xF0) == 0x30) kind = adm1023; else kind = adm1021; @@ -255,15 +306,16 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind) else if (i == 0x23) kind = gl523sm; else if ((i == 0x4d) && - (adm1021_read_value(new_client, ADM1021_REG_DEV_ID) == 0x01)) + (i2c_smbus_read_byte_data(client, + ADM1021_REG_DEV_ID) == 0x01)) kind = max1617a; else if (i == 0x54) kind = mc1066; /* LM84 Mfr ID in a different place, and it has more unused bits */ - else if (adm1021_read_value(new_client, ADM1021_REG_CONV_RATE_R) == 0x00 - && (kind == 0 /* skip extra detection */ - || ((adm1021_read_value(new_client, ADM1021_REG_CONFIG_R) & 0x7F) == 0x00 - && (adm1021_read_value(new_client, ADM1021_REG_STATUS) & 0xAB) == 0x00))) + else if (conv_rate == 0x00 + && (kind == 0 /* skip extra detection */ + || ((config & 0x7F) == 0x00 + && (status & 0xAB) == 0x00))) kind = lm84; else kind = max1617; @@ -286,37 +338,38 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind) } else if (kind == mc1066) { type_name = "mc1066"; } + pr_debug("adm1021: Detected chip %s at adapter %d, address 0x%02x.\n", + type_name, i2c_adapter_id(adapter), address); - /* Fill in the remaining client fields and put it into the global list */ - strlcpy(new_client->name, type_name, I2C_NAME_SIZE); + /* Fill in the remaining client fields */ + strlcpy(client->name, type_name, I2C_NAME_SIZE); data->type = kind; - data->valid = 0; mutex_init(&data->update_lock); /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) + if ((err = i2c_attach_client(client))) goto error1; /* Initialize the ADM1021 chip */ - if (kind != lm84) - adm1021_init_client(new_client); + if (kind != lm84 && !read_only) + adm1021_init_client(client); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1021_group))) + if ((err = sysfs_create_group(&client->dev.kobj, &adm1021_group))) goto error2; - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto error3; } return 0; error3: - sysfs_remove_group(&new_client->dev.kobj, &adm1021_group); + sysfs_remove_group(&client->dev.kobj, &adm1021_group); error2: - i2c_detach_client(new_client); + i2c_detach_client(client); error1: kfree(data); error0: @@ -326,10 +379,10 @@ error0: static void adm1021_init_client(struct i2c_client *client) { /* Enable ADC and disable suspend mode */ - adm1021_write_value(client, ADM1021_REG_CONFIG_W, - adm1021_read_value(client, ADM1021_REG_CONFIG_R) & 0xBF); + i2c_smbus_write_byte_data(client, ADM1021_REG_CONFIG_W, + i2c_smbus_read_byte_data(client, ADM1021_REG_CONFIG_R) & 0xBF); /* Set Conversion rate to 1/sec (this can be tinkered with) */ - adm1021_write_value(client, ADM1021_REG_CONV_RATE_W, 0x04); + i2c_smbus_write_byte_data(client, ADM1021_REG_CONV_RATE_W, 0x04); } static int adm1021_detach_client(struct i2c_client *client) @@ -337,7 +390,7 @@ static int adm1021_detach_client(struct i2c_client *client) struct adm1021_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &adm1021_group); if ((err = i2c_detach_client(client))) @@ -347,19 +400,6 @@ static int adm1021_detach_client(struct i2c_client *client) return 0; } -/* All registers are byte-sized */ -static int adm1021_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -static int adm1021_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if (!read_only) - return i2c_smbus_write_byte_data(client, reg, value); - return 0; -} - static struct adm1021_data *adm1021_update_device(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); @@ -369,21 +409,36 @@ static struct adm1021_data *adm1021_update_device(struct device *dev) if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || !data->valid) { + int i; + dev_dbg(&client->dev, "Starting adm1021 update\n"); - data->temp_input = adm1021_read_value(client, ADM1021_REG_TEMP); - data->temp_max = adm1021_read_value(client, ADM1021_REG_TOS_R); - data->temp_hyst = adm1021_read_value(client, ADM1021_REG_THYST_R); - data->remote_temp_input = adm1021_read_value(client, ADM1021_REG_REMOTE_TEMP); - data->remote_temp_max = adm1021_read_value(client, ADM1021_REG_REMOTE_TOS_R); - data->remote_temp_hyst = adm1021_read_value(client, ADM1021_REG_REMOTE_THYST_R); - data->alarms = adm1021_read_value(client, ADM1021_REG_STATUS) & 0x7c; + for (i = 0; i < 2; i++) { + data->temp[i] = i2c_smbus_read_byte_data(client, + ADM1021_REG_TEMP(i)); + data->temp_max[i] = i2c_smbus_read_byte_data(client, + ADM1021_REG_TOS_R(i)); + data->temp_min[i] = i2c_smbus_read_byte_data(client, + ADM1021_REG_THYST_R(i)); + } + data->alarms = i2c_smbus_read_byte_data(client, + ADM1021_REG_STATUS) & 0x7c; if (data->type == adm1023) { - data->remote_temp_prec = adm1021_read_value(client, ADM1021_REG_REM_TEMP_PREC); - data->remote_temp_os_prec = adm1021_read_value(client, ADM1021_REG_REM_TOS_PREC); - data->remote_temp_hyst_prec = adm1021_read_value(client, ADM1021_REG_REM_THYST_PREC); - data->remote_temp_offset = adm1021_read_value(client, ADM1021_REG_REM_OFFSET); - data->remote_temp_offset_prec = adm1021_read_value(client, ADM1021_REG_REM_OFFSET_PREC); + data->remote_temp_prec = + i2c_smbus_read_byte_data(client, + ADM1023_REG_REM_TEMP_PREC); + data->remote_temp_os_prec = + i2c_smbus_read_byte_data(client, + ADM1023_REG_REM_TOS_PREC); + data->remote_temp_hyst_prec = + i2c_smbus_read_byte_data(client, + ADM1023_REG_REM_THYST_PREC); + data->remote_temp_offset = + i2c_smbus_read_byte_data(client, + ADM1023_REG_REM_OFFSET); + data->remote_temp_offset_prec = + i2c_smbus_read_byte_data(client, + ADM1023_REG_REM_OFFSET_PREC); } data->last_updated = jiffies; data->valid = 1; diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c index 8c562885b54b..041ecb0bdf48 100644 --- a/drivers/hwmon/adm1025.c +++ b/drivers/hwmon/adm1025.c @@ -133,7 +133,7 @@ static struct i2c_driver adm1025_driver = { struct adm1025_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -292,7 +292,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) { - struct adm1025_data *data = adm1025_update_device(dev); + struct adm1025_data *data = dev_get_drvdata(dev); return sprintf(buf, "%u\n", data->vrm); } static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -472,9 +472,9 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind) goto exit_remove; } - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove; } @@ -538,7 +538,7 @@ static int adm1025_detach_client(struct i2c_client *client) struct adm1025_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &adm1025_group); sysfs_remove_group(&client->dev.kobj, &adm1025_group_opt); diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c index ba80cd3258c6..aa875ca50d9b 100644 --- a/drivers/hwmon/adm1026.c +++ b/drivers/hwmon/adm1026.c @@ -260,7 +260,7 @@ struct pwm_data { struct adm1026_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; enum chips type; struct mutex update_lock; @@ -1221,7 +1221,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) { - struct adm1026_data *data = adm1026_update_device(dev); + struct adm1026_data *data = dev_get_drvdata(dev); return sprintf(buf,"%d\n", data->vrm); } static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, @@ -1676,9 +1676,9 @@ static int adm1026_detect(struct i2c_adapter *adapter, int address, if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1026_group))) goto exitdetach; - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exitremove; } @@ -1698,7 +1698,7 @@ exit: static int adm1026_detach_client(struct i2c_client *client) { struct adm1026_data *data = i2c_get_clientdata(client); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &adm1026_group); i2c_detach_client(client); kfree(data); diff --git a/drivers/hwmon/adm1029.c b/drivers/hwmon/adm1029.c index 73ce31b31511..0bc897dffa27 100644 --- a/drivers/hwmon/adm1029.c +++ b/drivers/hwmon/adm1029.c @@ -141,7 +141,7 @@ static struct i2c_driver adm1029_driver = { struct adm1029_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -391,9 +391,9 @@ static int adm1029_detect(struct i2c_adapter *adapter, int address, int kind) if ((err = sysfs_create_group(&client->dev.kobj, &adm1029_group))) goto exit_detach; - data->class_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -431,7 +431,7 @@ static int adm1029_detach_client(struct i2c_client *client) struct adm1029_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &adm1029_group); if ((err = i2c_detach_client(client))) diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c index 122683fc91d0..37cfc101da5e 100644 --- a/drivers/hwmon/adm1031.c +++ b/drivers/hwmon/adm1031.c @@ -70,7 +70,7 @@ typedef u8 auto_chan_table_t[8][2]; /* Each client has this additional data */ struct adm1031_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; int chip_type; char valid; /* !=0 if following fields are valid */ @@ -853,9 +853,9 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind) goto exit_remove; } - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove; } @@ -877,7 +877,7 @@ static int adm1031_detach_client(struct i2c_client *client) struct adm1031_data *data = i2c_get_clientdata(client); int ret; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &adm1031_group); sysfs_remove_group(&client->dev.kobj, &adm1031_group_opt); if ((ret = i2c_detach_client(client)) != 0) { diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c index aad594adf0c7..c17d0b6b3283 100644 --- a/drivers/hwmon/adm9240.c +++ b/drivers/hwmon/adm9240.c @@ -150,7 +150,7 @@ static struct i2c_driver adm9240_driver = { struct adm9240_data { enum chips type; struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; unsigned long last_updated_measure; @@ -590,9 +590,9 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind) if ((err = sysfs_create_group(&new_client->dev.kobj, &adm9240_group))) goto exit_detach; - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove; } @@ -620,7 +620,7 @@ static int adm9240_detach_client(struct i2c_client *client) struct adm9240_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &adm9240_group); if ((err = i2c_detach_client(client))) diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c new file mode 100644 index 000000000000..9810aaa0489d --- /dev/null +++ b/drivers/hwmon/adt7470.c @@ -0,0 +1,1050 @@ +/* + * A hwmon driver for the Analog Devices ADT7470 + * Copyright (C) 2007 IBM + * + * Author: Darrick J. Wong <djwong@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/module.h> +#include <linux/jiffies.h> +#include <linux/i2c.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/err.h> +#include <linux/mutex.h> +#include <linux/delay.h> +#include <linux/log2.h> + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END }; + +/* Insmod parameters */ +I2C_CLIENT_INSMOD_1(adt7470); + +/* ADT7470 registers */ +#define ADT7470_REG_BASE_ADDR 0x20 +#define ADT7470_REG_TEMP_BASE_ADDR 0x20 +#define ADT7470_REG_TEMP_MAX_ADDR 0x29 +#define ADT7470_REG_FAN_BASE_ADDR 0x2A +#define ADT7470_REG_FAN_MAX_ADDR 0x31 +#define ADT7470_REG_PWM_BASE_ADDR 0x32 +#define ADT7470_REG_PWM_MAX_ADDR 0x35 +#define ADT7470_REG_PWM_MAX_BASE_ADDR 0x38 +#define ADT7470_REG_PWM_MAX_MAX_ADDR 0x3B +#define ADT7470_REG_CFG 0x40 +#define ADT7470_FSPD_MASK 0x04 +#define ADT7470_REG_ALARM1 0x41 +#define ADT7470_REG_ALARM2 0x42 +#define ADT7470_REG_TEMP_LIMITS_BASE_ADDR 0x44 +#define ADT7470_REG_TEMP_LIMITS_MAX_ADDR 0x57 +#define ADT7470_REG_FAN_MIN_BASE_ADDR 0x58 +#define ADT7470_REG_FAN_MIN_MAX_ADDR 0x5F +#define ADT7470_REG_FAN_MAX_BASE_ADDR 0x60 +#define ADT7470_REG_FAN_MAX_MAX_ADDR 0x67 +#define ADT7470_REG_PWM_CFG_BASE_ADDR 0x68 +#define ADT7470_REG_PWM12_CFG 0x68 +#define ADT7470_PWM2_AUTO_MASK 0x40 +#define ADT7470_PWM1_AUTO_MASK 0x80 +#define ADT7470_REG_PWM34_CFG 0x69 +#define ADT7470_PWM3_AUTO_MASK 0x40 +#define ADT7470_PWM4_AUTO_MASK 0x80 +#define ADT7470_REG_PWM_MIN_BASE_ADDR 0x6A +#define ADT7470_REG_PWM_MIN_MAX_ADDR 0x6D +#define ADT7470_REG_PWM_TEMP_MIN_BASE_ADDR 0x6E +#define ADT7470_REG_PWM_TEMP_MIN_MAX_ADDR 0x71 +#define ADT7470_REG_ACOUSTICS12 0x75 +#define ADT7470_REG_ACOUSTICS34 0x76 +#define ADT7470_REG_DEVICE 0x3D +#define ADT7470_REG_VENDOR 0x3E +#define ADT7470_REG_REVISION 0x3F +#define ADT7470_REG_ALARM1_MASK 0x72 +#define ADT7470_REG_ALARM2_MASK 0x73 +#define ADT7470_REG_PWM_AUTO_TEMP_BASE_ADDR 0x7C +#define ADT7470_REG_PWM_AUTO_TEMP_MAX_ADDR 0x7D +#define ADT7470_REG_MAX_ADDR 0x81 + +#define ADT7470_TEMP_COUNT 10 +#define ADT7470_TEMP_REG(x) (ADT7470_REG_TEMP_BASE_ADDR + (x)) +#define ADT7470_TEMP_MIN_REG(x) (ADT7470_REG_TEMP_LIMITS_BASE_ADDR + ((x) * 2)) +#define ADT7470_TEMP_MAX_REG(x) (ADT7470_REG_TEMP_LIMITS_BASE_ADDR + \ + ((x) * 2) + 1) + +#define ADT7470_FAN_COUNT 4 +#define ADT7470_REG_FAN(x) (ADT7470_REG_FAN_BASE_ADDR + ((x) * 2)) +#define ADT7470_REG_FAN_MIN(x) (ADT7470_REG_FAN_MIN_BASE_ADDR + ((x) * 2)) +#define ADT7470_REG_FAN_MAX(x) (ADT7470_REG_FAN_MAX_BASE_ADDR + ((x) * 2)) + +#define ADT7470_PWM_COUNT 4 +#define ADT7470_REG_PWM(x) (ADT7470_REG_PWM_BASE_ADDR + (x)) +#define ADT7470_REG_PWM_MAX(x) (ADT7470_REG_PWM_MAX_BASE_ADDR + (x)) +#define ADT7470_REG_PWM_MIN(x) (ADT7470_REG_PWM_MIN_BASE_ADDR + (x)) +#define ADT7470_REG_PWM_TMIN(x) (ADT7470_REG_PWM_TEMP_MIN_BASE_ADDR + (x)) +#define ADT7470_REG_PWM_CFG(x) (ADT7470_REG_PWM_CFG_BASE_ADDR + ((x) / 2)) +#define ADT7470_REG_PWM_AUTO_TEMP(x) (ADT7470_REG_PWM_AUTO_TEMP_BASE_ADDR + \ + ((x) / 2)) + +#define ADT7470_VENDOR 0x41 +#define ADT7470_DEVICE 0x70 +/* datasheet only mentions a revision 2 */ +#define ADT7470_REVISION 0x02 + +/* "all temps" according to hwmon sysfs interface spec */ +#define ADT7470_PWM_ALL_TEMPS 0x3FF + +/* How often do we reread sensors values? (In jiffies) */ +#define SENSOR_REFRESH_INTERVAL (5 * HZ) + +/* How often do we reread sensor limit values? (In jiffies) */ +#define LIMIT_REFRESH_INTERVAL (60 * HZ) + +/* sleep 1s while gathering temperature data */ +#define TEMP_COLLECTION_TIME 1000 + +#define power_of_2(x) (((x) & ((x) - 1)) == 0) + +/* datasheet says to divide this number by the fan reading to get fan rpm */ +#define FAN_PERIOD_TO_RPM(x) ((90000 * 60) / (x)) +#define FAN_RPM_TO_PERIOD FAN_PERIOD_TO_RPM +#define FAN_PERIOD_INVALID 65535 +#define FAN_DATA_VALID(x) ((x) && (x) != FAN_PERIOD_INVALID) + +struct adt7470_data { + struct i2c_client client; + struct device *hwmon_dev; + struct attribute_group attrs; + struct mutex lock; + char sensors_valid; + char limits_valid; + unsigned long sensors_last_updated; /* In jiffies */ + unsigned long limits_last_updated; /* In jiffies */ + + s8 temp[ADT7470_TEMP_COUNT]; + s8 temp_min[ADT7470_TEMP_COUNT]; + s8 temp_max[ADT7470_TEMP_COUNT]; + u16 fan[ADT7470_FAN_COUNT]; + u16 fan_min[ADT7470_FAN_COUNT]; + u16 fan_max[ADT7470_FAN_COUNT]; + u16 alarms, alarms_mask; + u8 force_pwm_max; + u8 pwm[ADT7470_PWM_COUNT]; + u8 pwm_max[ADT7470_PWM_COUNT]; + u8 pwm_automatic[ADT7470_PWM_COUNT]; + u8 pwm_min[ADT7470_PWM_COUNT]; + s8 pwm_tmin[ADT7470_PWM_COUNT]; + u8 pwm_auto_temp[ADT7470_PWM_COUNT]; +}; + +static int adt7470_attach_adapter(struct i2c_adapter *adapter); +static int adt7470_detect(struct i2c_adapter *adapter, int address, int kind); +static int adt7470_detach_client(struct i2c_client *client); + +static struct i2c_driver adt7470_driver = { + .driver = { + .name = "adt7470", + }, + .attach_adapter = adt7470_attach_adapter, + .detach_client = adt7470_detach_client, +}; + +/* + * 16-bit registers on the ADT7470 are low-byte first. The data sheet says + * that the low byte must be read before the high byte. + */ +static inline int adt7470_read_word_data(struct i2c_client *client, u8 reg) +{ + u16 foo; + foo = i2c_smbus_read_byte_data(client, reg); + foo |= ((u16)i2c_smbus_read_byte_data(client, reg + 1) << 8); + return foo; +} + +static inline int adt7470_write_word_data(struct i2c_client *client, u8 reg, + u16 value) +{ + return i2c_smbus_write_byte_data(client, reg, value & 0xFF) + && i2c_smbus_write_byte_data(client, reg + 1, value >> 8); +} + +static void adt7470_init_client(struct i2c_client *client) +{ + int reg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG); + + if (reg < 0) { + dev_err(&client->dev, "cannot read configuration register\n"); + } else { + /* start monitoring (and do a self-test) */ + i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, reg | 3); + } +} + +static struct adt7470_data *adt7470_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adt7470_data *data = i2c_get_clientdata(client); + unsigned long local_jiffies = jiffies; + u8 cfg; + int i; + + mutex_lock(&data->lock); + if (time_before(local_jiffies, data->sensors_last_updated + + SENSOR_REFRESH_INTERVAL) + && data->sensors_valid) + goto no_sensor_update; + + /* start reading temperature sensors */ + cfg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG); + cfg |= 0x80; + i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, cfg); + + /* + * Delay is 200ms * number of tmp05 sensors. Too bad + * there's no way to figure out how many are connected. + * For now, assume 1s will work. + */ + msleep(TEMP_COLLECTION_TIME); + + /* done reading temperature sensors */ + cfg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG); + cfg &= ~0x80; + i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, cfg); + + for (i = 0; i < ADT7470_TEMP_COUNT; i++) + data->temp[i] = i2c_smbus_read_byte_data(client, + ADT7470_TEMP_REG(i)); + + for (i = 0; i < ADT7470_FAN_COUNT; i++) + data->fan[i] = adt7470_read_word_data(client, + ADT7470_REG_FAN(i)); + + for (i = 0; i < ADT7470_PWM_COUNT; i++) { + int reg; + int reg_mask; + + data->pwm[i] = i2c_smbus_read_byte_data(client, + ADT7470_REG_PWM(i)); + + if (i % 2) + reg_mask = ADT7470_PWM2_AUTO_MASK; + else + reg_mask = ADT7470_PWM1_AUTO_MASK; + + reg = ADT7470_REG_PWM_CFG(i); + if (i2c_smbus_read_byte_data(client, reg) & reg_mask) + data->pwm_automatic[i] = 1; + else + data->pwm_automatic[i] = 0; + + reg = ADT7470_REG_PWM_AUTO_TEMP(i); + cfg = i2c_smbus_read_byte_data(client, reg); + if (!(i % 2)) + data->pwm_auto_temp[i] = cfg >> 4; + else + data->pwm_auto_temp[i] = cfg & 0xF; + } + + if (i2c_smbus_read_byte_data(client, ADT7470_REG_CFG) & + ADT7470_FSPD_MASK) + data->force_pwm_max = 1; + else + data->force_pwm_max = 0; + + data->alarms = adt7470_read_word_data(client, ADT7470_REG_ALARM1); + data->alarms_mask = adt7470_read_word_data(client, + ADT7470_REG_ALARM1_MASK); + + data->sensors_last_updated = local_jiffies; + data->sensors_valid = 1; + +no_sensor_update: + if (time_before(local_jiffies, data->limits_last_updated + + LIMIT_REFRESH_INTERVAL) + && data->limits_valid) + goto out; + + for (i = 0; i < ADT7470_TEMP_COUNT; i++) { + data->temp_min[i] = i2c_smbus_read_byte_data(client, + ADT7470_TEMP_MIN_REG(i)); + data->temp_max[i] = i2c_smbus_read_byte_data(client, + ADT7470_TEMP_MAX_REG(i)); + } + + for (i = 0; i < ADT7470_FAN_COUNT; i++) { + data->fan_min[i] = adt7470_read_word_data(client, + ADT7470_REG_FAN_MIN(i)); + data->fan_max[i] = adt7470_read_word_data(client, + ADT7470_REG_FAN_MAX(i)); + } + + for (i = 0; i < ADT7470_PWM_COUNT; i++) { + data->pwm_max[i] = i2c_smbus_read_byte_data(client, + ADT7470_REG_PWM_MAX(i)); + data->pwm_min[i] = i2c_smbus_read_byte_data(client, + ADT7470_REG_PWM_MIN(i)); + data->pwm_tmin[i] = i2c_smbus_read_byte_data(client, + ADT7470_REG_PWM_TMIN(i)); + } + + data->limits_last_updated = local_jiffies; + data->limits_valid = 1; + +out: + mutex_unlock(&data->lock); + return data; +} + +static ssize_t show_temp_min(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adt7470_data *data = adt7470_update_device(dev); + return sprintf(buf, "%d\n", 1000 * data->temp_min[attr->index]); +} + +static ssize_t set_temp_min(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct adt7470_data *data = i2c_get_clientdata(client); + int temp = simple_strtol(buf, NULL, 10) / 1000; + + mutex_lock(&data->lock); + data->temp_min[attr->index] = temp; + i2c_smbus_write_byte_data(client, ADT7470_TEMP_MIN_REG(attr->index), + temp); + mutex_unlock(&data->lock); + + return count; +} + +static ssize_t show_temp_max(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adt7470_data *data = adt7470_update_device(dev); + return sprintf(buf, "%d\n", 1000 * data->temp_max[attr->index]); +} + +static ssize_t set_temp_max(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct adt7470_data *data = i2c_get_clientdata(client); + int temp = simple_strtol(buf, NULL, 10) / 1000; + + mutex_lock(&data->lock); + data->temp_max[attr->index] = temp; + i2c_smbus_write_byte_data(client, ADT7470_TEMP_MAX_REG(attr->index), + temp); + mutex_unlock(&data->lock); + + return count; +} + +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adt7470_data *data = adt7470_update_device(dev); + return sprintf(buf, "%d\n", 1000 * data->temp[attr->index]); +} + +static ssize_t show_alarms(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adt7470_data *data = adt7470_update_device(dev); + + if (attr->index) + return sprintf(buf, "%x\n", data->alarms); + else + return sprintf(buf, "%x\n", data->alarms_mask); +} + +static ssize_t show_fan_max(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adt7470_data *data = adt7470_update_device(dev); + + if (FAN_DATA_VALID(data->fan_max[attr->index])) + return sprintf(buf, "%d\n", + FAN_PERIOD_TO_RPM(data->fan_max[attr->index])); + else + return sprintf(buf, "0\n"); +} + +static ssize_t set_fan_max(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct adt7470_data *data = i2c_get_clientdata(client); + int temp = simple_strtol(buf, NULL, 10); + + if (!temp) + return -EINVAL; + temp = FAN_RPM_TO_PERIOD(temp); + + mutex_lock(&data->lock); + data->fan_max[attr->index] = temp; + adt7470_write_word_data(client, ADT7470_REG_FAN_MAX(attr->index), temp); + mutex_unlock(&data->lock); + + return count; +} + +static ssize_t show_fan_min(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adt7470_data *data = adt7470_update_device(dev); + + if (FAN_DATA_VALID(data->fan_min[attr->index])) + return sprintf(buf, "%d\n", + FAN_PERIOD_TO_RPM(data->fan_min[attr->index])); + else + return sprintf(buf, "0\n"); +} + +static ssize_t set_fan_min(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct adt7470_data *data = i2c_get_clientdata(client); + int temp = simple_strtol(buf, NULL, 10); + + if (!temp) + return -EINVAL; + temp = FAN_RPM_TO_PERIOD(temp); + + mutex_lock(&data->lock); + data->fan_min[attr->index] = temp; + adt7470_write_word_data(client, ADT7470_REG_FAN_MIN(attr->index), temp); + mutex_unlock(&data->lock); + + return count; +} + +static ssize_t show_fan(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adt7470_data *data = adt7470_update_device(dev); + + if (FAN_DATA_VALID(data->fan[attr->index])) + return sprintf(buf, "%d\n", + FAN_PERIOD_TO_RPM(data->fan[attr->index])); + else + return sprintf(buf, "0\n"); +} + +static ssize_t show_force_pwm_max(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct adt7470_data *data = adt7470_update_device(dev); + return sprintf(buf, "%d\n", data->force_pwm_max); +} + +static ssize_t set_force_pwm_max(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adt7470_data *data = i2c_get_clientdata(client); + int temp = simple_strtol(buf, NULL, 10); + u8 reg; + + mutex_lock(&data->lock); + data->force_pwm_max = temp; + reg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG); + if (temp) + reg |= ADT7470_FSPD_MASK; + else + reg &= ~ADT7470_FSPD_MASK; + i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, reg); + mutex_unlock(&data->lock); + + return count; +} + +static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adt7470_data *data = adt7470_update_device(dev); + return sprintf(buf, "%d\n", data->pwm[attr->index]); +} + +static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct adt7470_data *data = i2c_get_clientdata(client); + int temp = simple_strtol(buf, NULL, 10); + + mutex_lock(&data->lock); + data->pwm[attr->index] = temp; + i2c_smbus_write_byte_data(client, ADT7470_REG_PWM(attr->index), temp); + mutex_unlock(&data->lock); + + return count; +} + +static ssize_t show_pwm_max(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adt7470_data *data = adt7470_update_device(dev); + return sprintf(buf, "%d\n", data->pwm_max[attr->index]); +} + +static ssize_t set_pwm_max(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct adt7470_data *data = i2c_get_clientdata(client); + int temp = simple_strtol(buf, NULL, 10); + + mutex_lock(&data->lock); + data->pwm_max[attr->index] = temp; + i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_MAX(attr->index), + temp); + mutex_unlock(&data->lock); + + return count; +} + +static ssize_t show_pwm_min(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adt7470_data *data = adt7470_update_device(dev); + return sprintf(buf, "%d\n", data->pwm_min[attr->index]); +} + +static ssize_t set_pwm_min(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct adt7470_data *data = i2c_get_clientdata(client); + int temp = simple_strtol(buf, NULL, 10); + + mutex_lock(&data->lock); + data->pwm_min[attr->index] = temp; + i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_MIN(attr->index), + temp); + mutex_unlock(&data->lock); + + return count; +} + +static ssize_t show_pwm_tmax(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adt7470_data *data = adt7470_update_device(dev); + /* the datasheet says that tmax = tmin + 20C */ + return sprintf(buf, "%d\n", 1000 * (20 + data->pwm_tmin[attr->index])); +} + +static ssize_t show_pwm_tmin(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adt7470_data *data = adt7470_update_device(dev); + return sprintf(buf, "%d\n", 1000 * data->pwm_tmin[attr->index]); +} + +static ssize_t set_pwm_tmin(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct adt7470_data *data = i2c_get_clientdata(client); + int temp = simple_strtol(buf, NULL, 10) / 1000; + + mutex_lock(&data->lock); + data->pwm_tmin[attr->index] = temp; + i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_TMIN(attr->index), + temp); + mutex_unlock(&data->lock); + + return count; +} + +static ssize_t show_pwm_auto(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adt7470_data *data = adt7470_update_device(dev); + return sprintf(buf, "%d\n", 1 + data->pwm_automatic[attr->index]); +} + +static ssize_t set_pwm_auto(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct adt7470_data *data = i2c_get_clientdata(client); + int temp = simple_strtol(buf, NULL, 10); + int pwm_auto_reg = ADT7470_REG_PWM_CFG(attr->index); + int pwm_auto_reg_mask; + u8 reg; + + if (attr->index % 2) + pwm_auto_reg_mask = ADT7470_PWM2_AUTO_MASK; + else + pwm_auto_reg_mask = ADT7470_PWM1_AUTO_MASK; + + if (temp != 2 && temp != 1) + return -EINVAL; + temp--; + + mutex_lock(&data->lock); + data->pwm_automatic[attr->index] = temp; + reg = i2c_smbus_read_byte_data(client, pwm_auto_reg); + if (temp) + reg |= pwm_auto_reg_mask; + else + reg &= ~pwm_auto_reg_mask; + i2c_smbus_write_byte_data(client, pwm_auto_reg, reg); + mutex_unlock(&data->lock); + + return count; +} + +static ssize_t show_pwm_auto_temp(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adt7470_data *data = adt7470_update_device(dev); + u8 ctrl = data->pwm_auto_temp[attr->index]; + + if (ctrl) + return sprintf(buf, "%d\n", 1 << (ctrl - 1)); + else + return sprintf(buf, "%d\n", ADT7470_PWM_ALL_TEMPS); +} + +static int cvt_auto_temp(int input) +{ + if (input == ADT7470_PWM_ALL_TEMPS) + return 0; + if (input < 1 || !power_of_2(input)) + return -EINVAL; + return ilog2(input) + 1; +} + +static ssize_t set_pwm_auto_temp(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct adt7470_data *data = i2c_get_clientdata(client); + int temp = cvt_auto_temp(simple_strtol(buf, NULL, 10)); + int pwm_auto_reg = ADT7470_REG_PWM_AUTO_TEMP(attr->index); + u8 reg; + + if (temp < 0) + return temp; + + mutex_lock(&data->lock); + data->pwm_automatic[attr->index] = temp; + reg = i2c_smbus_read_byte_data(client, pwm_auto_reg); + + if (!(attr->index % 2)) { + reg &= 0xF; + reg |= (temp << 4) & 0xF0; + } else { + reg &= 0xF0; + reg |= temp & 0xF; + } + + i2c_smbus_write_byte_data(client, pwm_auto_reg, reg); + mutex_unlock(&data->lock); + + return count; +} + +static SENSOR_DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL, 0); +static SENSOR_DEVICE_ATTR(alarm_mask, S_IRUGO, show_alarms, NULL, 1); + +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, + set_temp_max, 0); +static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_max, + set_temp_max, 1); +static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_temp_max, + set_temp_max, 2); +static SENSOR_DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_temp_max, + set_temp_max, 3); +static SENSOR_DEVICE_ATTR(temp5_max, S_IWUSR | S_IRUGO, show_temp_max, + set_temp_max, 4); +static SENSOR_DEVICE_ATTR(temp6_max, S_IWUSR | S_IRUGO, show_temp_max, + set_temp_max, 5); +static SENSOR_DEVICE_ATTR(temp7_max, S_IWUSR | S_IRUGO, show_temp_max, + set_temp_max, 6); +static SENSOR_DEVICE_ATTR(temp8_max, S_IWUSR | S_IRUGO, show_temp_max, + set_temp_max, 7); +static SENSOR_DEVICE_ATTR(temp9_max, S_IWUSR | S_IRUGO, show_temp_max, + set_temp_max, 8); +static SENSOR_DEVICE_ATTR(temp10_max, S_IWUSR | S_IRUGO, show_temp_max, + set_temp_max, 9); + +static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min, + set_temp_min, 0); +static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_min, + set_temp_min, 1); +static SENSOR_DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_temp_min, + set_temp_min, 2); +static SENSOR_DEVICE_ATTR(temp4_min, S_IWUSR | S_IRUGO, show_temp_min, + set_temp_min, 3); +static SENSOR_DEVICE_ATTR(temp5_min, S_IWUSR | S_IRUGO, show_temp_min, + set_temp_min, 4); +static SENSOR_DEVICE_ATTR(temp6_min, S_IWUSR | S_IRUGO, show_temp_min, + set_temp_min, 5); +static SENSOR_DEVICE_ATTR(temp7_min, S_IWUSR | S_IRUGO, show_temp_min, + set_temp_min, 6); +static SENSOR_DEVICE_ATTR(temp8_min, S_IWUSR | S_IRUGO, show_temp_min, + set_temp_min, 7); +static SENSOR_DEVICE_ATTR(temp9_min, S_IWUSR | S_IRUGO, show_temp_min, + set_temp_min, 8); +static SENSOR_DEVICE_ATTR(temp10_min, S_IWUSR | S_IRUGO, show_temp_min, + set_temp_min, 9); + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1); +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2); +static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3); +static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4); +static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_temp, NULL, 5); +static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO, show_temp, NULL, 6); +static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, show_temp, NULL, 7); +static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO, show_temp, NULL, 8); +static SENSOR_DEVICE_ATTR(temp10_input, S_IRUGO, show_temp, NULL, 9); + +static SENSOR_DEVICE_ATTR(fan1_max, S_IWUSR | S_IRUGO, show_fan_max, + set_fan_max, 0); +static SENSOR_DEVICE_ATTR(fan2_max, S_IWUSR | S_IRUGO, show_fan_max, + set_fan_max, 1); +static SENSOR_DEVICE_ATTR(fan3_max, S_IWUSR | S_IRUGO, show_fan_max, + set_fan_max, 2); +static SENSOR_DEVICE_ATTR(fan4_max, S_IWUSR | S_IRUGO, show_fan_max, + set_fan_max, 3); + +static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min, + set_fan_min, 0); +static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min, + set_fan_min, 1); +static SENSOR_DEVICE_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min, + set_fan_min, 2); +static SENSOR_DEVICE_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min, + set_fan_min, 3); + +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); +static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1); +static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2); +static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3); + +static SENSOR_DEVICE_ATTR(force_pwm_max, S_IWUSR | S_IRUGO, + show_force_pwm_max, set_force_pwm_max, 0); + +static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 0); +static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 1); +static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2); +static SENSOR_DEVICE_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 3); + +static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IWUSR | S_IRUGO, + show_pwm_min, set_pwm_min, 0); +static SENSOR_DEVICE_ATTR(pwm2_auto_point1_pwm, S_IWUSR | S_IRUGO, + show_pwm_min, set_pwm_min, 1); +static SENSOR_DEVICE_ATTR(pwm3_auto_point1_pwm, S_IWUSR | S_IRUGO, + show_pwm_min, set_pwm_min, 2); +static SENSOR_DEVICE_ATTR(pwm4_auto_point1_pwm, S_IWUSR | S_IRUGO, + show_pwm_min, set_pwm_min, 3); + +static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IWUSR | S_IRUGO, + show_pwm_max, set_pwm_max, 0); +static SENSOR_DEVICE_ATTR(pwm2_auto_point2_pwm, S_IWUSR | S_IRUGO, + show_pwm_max, set_pwm_max, 1); +static SENSOR_DEVICE_ATTR(pwm3_auto_point2_pwm, S_IWUSR | S_IRUGO, + show_pwm_max, set_pwm_max, 2); +static SENSOR_DEVICE_ATTR(pwm4_auto_point2_pwm, S_IWUSR | S_IRUGO, + show_pwm_max, set_pwm_max, 3); + +static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp, S_IWUSR | S_IRUGO, + show_pwm_tmin, set_pwm_tmin, 0); +static SENSOR_DEVICE_ATTR(pwm2_auto_point1_temp, S_IWUSR | S_IRUGO, + show_pwm_tmin, set_pwm_tmin, 1); +static SENSOR_DEVICE_ATTR(pwm3_auto_point1_temp, S_IWUSR | S_IRUGO, + show_pwm_tmin, set_pwm_tmin, 2); +static SENSOR_DEVICE_ATTR(pwm4_auto_point1_temp, S_IWUSR | S_IRUGO, + show_pwm_tmin, set_pwm_tmin, 3); + +static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp, S_IRUGO, show_pwm_tmax, + NULL, 0); +static SENSOR_DEVICE_ATTR(pwm2_auto_point2_temp, S_IRUGO, show_pwm_tmax, + NULL, 1); +static SENSOR_DEVICE_ATTR(pwm3_auto_point2_temp, S_IRUGO, show_pwm_tmax, + NULL, 2); +static SENSOR_DEVICE_ATTR(pwm4_auto_point2_temp, S_IRUGO, show_pwm_tmax, + NULL, 3); + +static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_auto, + set_pwm_auto, 0); +static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_auto, + set_pwm_auto, 1); +static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_auto, + set_pwm_auto, 2); +static SENSOR_DEVICE_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_auto, + set_pwm_auto, 3); + +static SENSOR_DEVICE_ATTR(pwm1_auto_channels_temp, S_IWUSR | S_IRUGO, + show_pwm_auto_temp, set_pwm_auto_temp, 0); +static SENSOR_DEVICE_ATTR(pwm2_auto_channels_temp, S_IWUSR | S_IRUGO, + show_pwm_auto_temp, set_pwm_auto_temp, 1); +static SENSOR_DEVICE_ATTR(pwm3_auto_channels_temp, S_IWUSR | S_IRUGO, + show_pwm_auto_temp, set_pwm_auto_temp, 2); +static SENSOR_DEVICE_ATTR(pwm4_auto_channels_temp, S_IWUSR | S_IRUGO, + show_pwm_auto_temp, set_pwm_auto_temp, 3); + +static struct attribute *adt7470_attr[] = +{ + &sensor_dev_attr_alarms.dev_attr.attr, + &sensor_dev_attr_alarm_mask.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp3_max.dev_attr.attr, + &sensor_dev_attr_temp4_max.dev_attr.attr, + &sensor_dev_attr_temp5_max.dev_attr.attr, + &sensor_dev_attr_temp6_max.dev_attr.attr, + &sensor_dev_attr_temp7_max.dev_attr.attr, + &sensor_dev_attr_temp8_max.dev_attr.attr, + &sensor_dev_attr_temp9_max.dev_attr.attr, + &sensor_dev_attr_temp10_max.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, + &sensor_dev_attr_temp2_min.dev_attr.attr, + &sensor_dev_attr_temp3_min.dev_attr.attr, + &sensor_dev_attr_temp4_min.dev_attr.attr, + &sensor_dev_attr_temp5_min.dev_attr.attr, + &sensor_dev_attr_temp6_min.dev_attr.attr, + &sensor_dev_attr_temp7_min.dev_attr.attr, + &sensor_dev_attr_temp8_min.dev_attr.attr, + &sensor_dev_attr_temp9_min.dev_attr.attr, + &sensor_dev_attr_temp10_min.dev_attr.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp4_input.dev_attr.attr, + &sensor_dev_attr_temp5_input.dev_attr.attr, + &sensor_dev_attr_temp6_input.dev_attr.attr, + &sensor_dev_attr_temp7_input.dev_attr.attr, + &sensor_dev_attr_temp8_input.dev_attr.attr, + &sensor_dev_attr_temp9_input.dev_attr.attr, + &sensor_dev_attr_temp10_input.dev_attr.attr, + &sensor_dev_attr_fan1_max.dev_attr.attr, + &sensor_dev_attr_fan2_max.dev_attr.attr, + &sensor_dev_attr_fan3_max.dev_attr.attr, + &sensor_dev_attr_fan4_max.dev_attr.attr, + &sensor_dev_attr_fan1_min.dev_attr.attr, + &sensor_dev_attr_fan2_min.dev_attr.attr, + &sensor_dev_attr_fan3_min.dev_attr.attr, + &sensor_dev_attr_fan4_min.dev_attr.attr, + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan3_input.dev_attr.attr, + &sensor_dev_attr_fan4_input.dev_attr.attr, + &sensor_dev_attr_force_pwm_max.dev_attr.attr, + &sensor_dev_attr_pwm1.dev_attr.attr, + &sensor_dev_attr_pwm2.dev_attr.attr, + &sensor_dev_attr_pwm3.dev_attr.attr, + &sensor_dev_attr_pwm4.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr, + &sensor_dev_attr_pwm4_auto_point1_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr, + &sensor_dev_attr_pwm4_auto_point2_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_pwm4_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_pwm4_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_enable.dev_attr.attr, + &sensor_dev_attr_pwm2_enable.dev_attr.attr, + &sensor_dev_attr_pwm3_enable.dev_attr.attr, + &sensor_dev_attr_pwm4_enable.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_channels_temp.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_channels_temp.dev_attr.attr, + &sensor_dev_attr_pwm4_auto_channels_temp.dev_attr.attr, + NULL +}; + +static int adt7470_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_probe(adapter, &addr_data, adt7470_detect); +} + +static int adt7470_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *client; + struct adt7470_data *data; + int err = 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + if (!(data = kzalloc(sizeof(struct adt7470_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + + client = &data->client; + client->addr = address; + client->adapter = adapter; + client->driver = &adt7470_driver; + + i2c_set_clientdata(client, data); + + mutex_init(&data->lock); + + if (kind <= 0) { + int vendor, device, revision; + + vendor = i2c_smbus_read_byte_data(client, ADT7470_REG_VENDOR); + if (vendor != ADT7470_VENDOR) { + err = -ENODEV; + goto exit_free; + } + + device = i2c_smbus_read_byte_data(client, ADT7470_REG_DEVICE); + if (device != ADT7470_DEVICE) { + err = -ENODEV; + goto exit_free; + } + + revision = i2c_smbus_read_byte_data(client, + ADT7470_REG_REVISION); + if (revision != ADT7470_REVISION) { + err = -ENODEV; + goto exit_free; + } + } else + dev_dbg(&adapter->dev, "detection forced\n"); + + strlcpy(client->name, "adt7470", I2C_NAME_SIZE); + + if ((err = i2c_attach_client(client))) + goto exit_free; + + dev_info(&client->dev, "%s chip found\n", client->name); + + /* Initialize the ADT7470 chip */ + adt7470_init_client(client); + + /* Register sysfs hooks */ + data->attrs.attrs = adt7470_attr; + if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs))) + goto exit_detach; + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &data->attrs); +exit_detach: + i2c_detach_client(client); +exit_free: + kfree(data); +exit: + return err; +} + +static int adt7470_detach_client(struct i2c_client *client) +{ + struct adt7470_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &data->attrs); + i2c_detach_client(client); + kfree(data); + return 0; +} + +static int __init adt7470_init(void) +{ + return i2c_add_driver(&adt7470_driver); +} + +static void __exit adt7470_exit(void) +{ + i2c_del_driver(&adt7470_driver); +} + +MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>"); +MODULE_DESCRIPTION("ADT7470 driver"); +MODULE_LICENSE("GPL"); + +module_init(adt7470_init); +module_exit(adt7470_exit); diff --git a/drivers/hwmon/ams/ams-input.c b/drivers/hwmon/ams/ams-input.c index ca7095d96ad0..7b81e0c2c2d9 100644 --- a/drivers/hwmon/ams/ams-input.c +++ b/drivers/hwmon/ams/ams-input.c @@ -27,47 +27,32 @@ static unsigned int invert; module_param(invert, bool, 0644); MODULE_PARM_DESC(invert, "Invert input data on X and Y axis"); -static int ams_input_kthread(void *data) +static void ams_idev_poll(struct input_polled_dev *dev) { + struct input_dev *idev = dev->input; s8 x, y, z; - while (!kthread_should_stop()) { - mutex_lock(&ams_info.lock); - - ams_sensors(&x, &y, &z); - - x -= ams_info.xcalib; - y -= ams_info.ycalib; - z -= ams_info.zcalib; - - input_report_abs(ams_info.idev, ABS_X, invert ? -x : x); - input_report_abs(ams_info.idev, ABS_Y, invert ? -y : y); - input_report_abs(ams_info.idev, ABS_Z, z); + mutex_lock(&ams_info.lock); - input_sync(ams_info.idev); + ams_sensors(&x, &y, &z); - mutex_unlock(&ams_info.lock); + x -= ams_info.xcalib; + y -= ams_info.ycalib; + z -= ams_info.zcalib; - msleep(25); - } + input_report_abs(idev, ABS_X, invert ? -x : x); + input_report_abs(idev, ABS_Y, invert ? -y : y); + input_report_abs(idev, ABS_Z, z); - return 0; -} + input_sync(idev); -static int ams_input_open(struct input_dev *dev) -{ - ams_info.kthread = kthread_run(ams_input_kthread, NULL, "kams"); - return IS_ERR(ams_info.kthread) ? PTR_ERR(ams_info.kthread) : 0; -} - -static void ams_input_close(struct input_dev *dev) -{ - kthread_stop(ams_info.kthread); + mutex_unlock(&ams_info.lock); } /* Call with ams_info.lock held! */ static void ams_input_enable(void) { + struct input_dev *input; s8 x, y, z; if (ams_info.idev) @@ -78,27 +63,29 @@ static void ams_input_enable(void) ams_info.ycalib = y; ams_info.zcalib = z; - ams_info.idev = input_allocate_device(); + ams_info.idev = input_allocate_polled_device(); if (!ams_info.idev) return; - ams_info.idev->name = "Apple Motion Sensor"; - ams_info.idev->id.bustype = ams_info.bustype; - ams_info.idev->id.vendor = 0; - ams_info.idev->open = ams_input_open; - ams_info.idev->close = ams_input_close; - ams_info.idev->dev.parent = &ams_info.of_dev->dev; + ams_info.idev->poll = ams_idev_poll; + ams_info.idev->poll_interval = 25; + + input = ams_info.idev->input; + input->name = "Apple Motion Sensor"; + input->id.bustype = ams_info.bustype; + input->id.vendor = 0; + input->dev.parent = &ams_info.of_dev->dev; - input_set_abs_params(ams_info.idev, ABS_X, -50, 50, 3, 0); - input_set_abs_params(ams_info.idev, ABS_Y, -50, 50, 3, 0); - input_set_abs_params(ams_info.idev, ABS_Z, -50, 50, 3, 0); + input_set_abs_params(input, ABS_X, -50, 50, 3, 0); + input_set_abs_params(input, ABS_Y, -50, 50, 3, 0); + input_set_abs_params(input, ABS_Z, -50, 50, 3, 0); - set_bit(EV_ABS, ams_info.idev->evbit); - set_bit(EV_KEY, ams_info.idev->evbit); - set_bit(BTN_TOUCH, ams_info.idev->keybit); + set_bit(EV_ABS, input->evbit); + set_bit(EV_KEY, input->evbit); + set_bit(BTN_TOUCH, input->keybit); - if (input_register_device(ams_info.idev)) { - input_free_device(ams_info.idev); + if (input_register_polled_device(ams_info.idev)) { + input_free_polled_device(ams_info.idev); ams_info.idev = NULL; return; } @@ -108,7 +95,8 @@ static void ams_input_enable(void) static void ams_input_disable(void) { if (ams_info.idev) { - input_unregister_device(ams_info.idev); + input_unregister_polled_device(ams_info.idev); + input_free_polled_device(ams_info.idev); ams_info.idev = NULL; } } diff --git a/drivers/hwmon/ams/ams.h b/drivers/hwmon/ams/ams.h index 240730e6bcde..a6221e5dd984 100644 --- a/drivers/hwmon/ams/ams.h +++ b/drivers/hwmon/ams/ams.h @@ -1,5 +1,5 @@ #include <linux/i2c.h> -#include <linux/input.h> +#include <linux/input-polldev.h> #include <linux/kthread.h> #include <linux/mutex.h> #include <linux/spinlock.h> @@ -52,8 +52,7 @@ struct ams { #endif /* Joystick emulation */ - struct task_struct *kthread; - struct input_dev *idev; + struct input_polled_dev *idev; __u16 bustype; /* calibrated null values */ diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index 56213b7f8188..4879125b4cdc 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c @@ -28,7 +28,7 @@ #include <linux/delay.h> #include <linux/platform_device.h> -#include <linux/input.h> +#include <linux/input-polldev.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/timer.h> @@ -59,9 +59,9 @@ #define LIGHT_SENSOR_LEFT_KEY "ALV0" /* r-o {alv (6 bytes) */ #define LIGHT_SENSOR_RIGHT_KEY "ALV1" /* r-o {alv (6 bytes) */ -#define BACKLIGHT_KEY "LKSB" /* w-o {lkb (2 bytes) */ +#define BACKLIGHT_KEY "LKSB" /* w-o {lkb (2 bytes) */ -#define CLAMSHELL_KEY "MSLD" /* r-o ui8 (unused) */ +#define CLAMSHELL_KEY "MSLD" /* r-o ui8 (unused) */ #define MOTION_SENSOR_X_KEY "MO_X" /* r-o sp78 (2 bytes) */ #define MOTION_SENSOR_Y_KEY "MO_Y" /* r-o sp78 (2 bytes) */ @@ -103,7 +103,7 @@ static const char* fan_speed_keys[] = { #define INIT_TIMEOUT_MSECS 5000 /* wait up to 5s for device init ... */ #define INIT_WAIT_MSECS 50 /* ... in 50ms increments */ -#define APPLESMC_POLL_PERIOD (HZ/20) /* poll for input every 1/20s */ +#define APPLESMC_POLL_INTERVAL 50 /* msecs */ #define APPLESMC_INPUT_FUZZ 4 /* input event threshold */ #define APPLESMC_INPUT_FLAT 4 @@ -125,9 +125,8 @@ static const int debug; static struct platform_device *pdev; static s16 rest_x; static s16 rest_y; -static struct timer_list applesmc_timer; -static struct input_dev *applesmc_idev; -static struct class_device *hwmon_class_dev; +static struct device *hwmon_dev; +static struct input_polled_dev *applesmc_idev; /* Indicates whether this computer has an accelerometer. */ static unsigned int applesmc_accelerometer; @@ -138,7 +137,7 @@ static unsigned int applesmc_light; /* Indicates which temperature sensors set to use. */ static unsigned int applesmc_temperature_set; -static struct mutex applesmc_lock; +static DEFINE_MUTEX(applesmc_lock); /* * Last index written to key_at_index sysfs file, and value to use for all other @@ -455,27 +454,12 @@ static void applesmc_calibrate(void) rest_x = -rest_x; } -static int applesmc_idev_open(struct input_dev *dev) -{ - add_timer(&applesmc_timer); - - return 0; -} - -static void applesmc_idev_close(struct input_dev *dev) -{ - del_timer_sync(&applesmc_timer); -} - -static void applesmc_idev_poll(unsigned long unused) +static void applesmc_idev_poll(struct input_polled_dev *dev) { + struct input_dev *idev = dev->input; s16 x, y; - /* Cannot sleep. Try nonblockingly. If we fail, try again later. */ - if (!mutex_trylock(&applesmc_lock)) { - mod_timer(&applesmc_timer, jiffies + APPLESMC_POLL_PERIOD); - return; - } + mutex_lock(&applesmc_lock); if (applesmc_read_motion_sensor(SENSOR_X, &x)) goto out; @@ -483,13 +467,11 @@ static void applesmc_idev_poll(unsigned long unused) goto out; x = -x; - input_report_abs(applesmc_idev, ABS_X, x - rest_x); - input_report_abs(applesmc_idev, ABS_Y, y - rest_y); - input_sync(applesmc_idev); + input_report_abs(idev, ABS_X, x - rest_x); + input_report_abs(idev, ABS_Y, y - rest_y); + input_sync(idev); out: - mod_timer(&applesmc_timer, jiffies + APPLESMC_POLL_PERIOD); - mutex_unlock(&applesmc_lock); } @@ -821,8 +803,7 @@ static ssize_t applesmc_key_at_index_read_show(struct device *dev, if (!ret) { return info[0]; - } - else { + } else { return ret; } } @@ -1093,6 +1074,7 @@ static int applesmc_dmi_match(const struct dmi_system_id *id) /* Create accelerometer ressources */ static int applesmc_create_accelerometer(void) { + struct input_dev *idev; int ret; ret = sysfs_create_group(&pdev->dev.kobj, @@ -1100,40 +1082,37 @@ static int applesmc_create_accelerometer(void) if (ret) goto out; - applesmc_idev = input_allocate_device(); + applesmc_idev = input_allocate_polled_device(); if (!applesmc_idev) { ret = -ENOMEM; goto out_sysfs; } + applesmc_idev->poll = applesmc_idev_poll; + applesmc_idev->poll_interval = APPLESMC_POLL_INTERVAL; + /* initial calibrate for the input device */ applesmc_calibrate(); - /* initialize the input class */ - applesmc_idev->name = "applesmc"; - applesmc_idev->id.bustype = BUS_HOST; - applesmc_idev->dev.parent = &pdev->dev; - applesmc_idev->evbit[0] = BIT(EV_ABS); - applesmc_idev->open = applesmc_idev_open; - applesmc_idev->close = applesmc_idev_close; - input_set_abs_params(applesmc_idev, ABS_X, + /* initialize the input device */ + idev = applesmc_idev->input; + idev->name = "applesmc"; + idev->id.bustype = BUS_HOST; + idev->dev.parent = &pdev->dev; + idev->evbit[0] = BIT(EV_ABS); + input_set_abs_params(idev, ABS_X, -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT); - input_set_abs_params(applesmc_idev, ABS_Y, + input_set_abs_params(idev, ABS_Y, -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT); - ret = input_register_device(applesmc_idev); + ret = input_register_polled_device(applesmc_idev); if (ret) goto out_idev; - /* start up our timer for the input device */ - init_timer(&applesmc_timer); - applesmc_timer.function = applesmc_idev_poll; - applesmc_timer.expires = jiffies + APPLESMC_POLL_PERIOD; - return 0; out_idev: - input_free_device(applesmc_idev); + input_free_polled_device(applesmc_idev); out_sysfs: sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group); @@ -1146,8 +1125,8 @@ out: /* Release all ressources used by the accelerometer */ static void applesmc_release_accelerometer(void) { - del_timer_sync(&applesmc_timer); - input_unregister_device(applesmc_idev); + input_unregister_polled_device(applesmc_idev); + input_free_polled_device(applesmc_idev); sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group); } @@ -1184,8 +1163,6 @@ static int __init applesmc_init(void) int count; int i; - mutex_init(&applesmc_lock); - if (!dmi_check_system(applesmc_whitelist)) { printk(KERN_WARNING "applesmc: supported laptop not found!\n"); ret = -ENODEV; @@ -1287,9 +1264,9 @@ static int __init applesmc_init(void) goto out_light_wq; } - hwmon_class_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(hwmon_class_dev)) { - ret = PTR_ERR(hwmon_class_dev); + hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(hwmon_dev)) { + ret = PTR_ERR(hwmon_dev); goto out_light_ledclass; } @@ -1331,7 +1308,7 @@ out: static void __exit applesmc_exit(void) { - hwmon_device_unregister(hwmon_class_dev); + hwmon_device_unregister(hwmon_dev); if (applesmc_light) { led_classdev_unregister(&applesmc_backlight); destroy_workqueue(applesmc_led_wq); diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c index 57b1c7b7ac3f..9460dba4cf74 100644 --- a/drivers/hwmon/asb100.c +++ b/drivers/hwmon/asb100.c @@ -143,7 +143,7 @@ static int FAN_FROM_REG(u8 val, int div) /* TEMP: 0.001C/bit (-128C to +127C) REG: 1C/bit, two's complement */ -static u8 TEMP_TO_REG(int temp) +static u8 TEMP_TO_REG(long temp) { int ntemp = SENSORS_LIMIT(temp, ASB100_TEMP_MIN, ASB100_TEMP_MAX); ntemp += (ntemp<0 ? -500 : 500); @@ -182,7 +182,7 @@ static u8 DIV_TO_REG(long val) dynamically allocated, at the same time the client itself is allocated. */ struct asb100_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex lock; enum chips type; @@ -448,7 +448,7 @@ static ssize_t set_##reg(struct device *dev, const char *buf, \ { \ struct i2c_client *client = to_i2c_client(dev); \ struct asb100_data *data = i2c_get_clientdata(client); \ - unsigned long val = simple_strtoul(buf, NULL, 10); \ + long val = simple_strtol(buf, NULL, 10); \ \ mutex_lock(&data->update_lock); \ switch (nr) { \ @@ -514,7 +514,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); /* VRM */ static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) { - struct asb100_data *data = asb100_update_device(dev); + struct asb100_data *data = dev_get_drvdata(dev); return sprintf(buf, "%d\n", data->vrm); } @@ -844,9 +844,9 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind) if ((err = sysfs_create_group(&new_client->dev.kobj, &asb100_group))) goto ERROR3; - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto ERROR4; } @@ -874,7 +874,7 @@ static int asb100_detach_client(struct i2c_client *client) /* main client */ if (data) { - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &asb100_group); } diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c index 0ccdd0750c44..cce3350e539e 100644 --- a/drivers/hwmon/atxp1.c +++ b/drivers/hwmon/atxp1.c @@ -61,7 +61,7 @@ static struct i2c_driver atxp1_driver = { struct atxp1_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; unsigned long last_updated; u8 valid; @@ -335,9 +335,9 @@ static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind) if ((err = sysfs_create_group(&new_client->dev.kobj, &atxp1_group))) goto exit_detach; - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -361,7 +361,7 @@ static int atxp1_detach_client(struct i2c_client * client) struct atxp1_data * data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &atxp1_group); err = i2c_detach_client(client); diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 7c1795225b06..6f66551d9e51 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -47,7 +47,7 @@ typedef enum { SHOW_TEMP, SHOW_TJMAX, SHOW_LABEL, SHOW_NAME } SHOW; static struct coretemp_data *coretemp_update_device(struct device *dev); struct coretemp_data { - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; const char *name; u32 id; @@ -58,8 +58,6 @@ struct coretemp_data { u8 alarm; }; -static struct coretemp_data *coretemp_update_device(struct device *dev); - /* * Sysfs stuff */ @@ -228,9 +226,9 @@ static int __devinit coretemp_probe(struct platform_device *pdev) if ((err = sysfs_create_group(&pdev->dev.kobj, &coretemp_group))) goto exit_free; - data->class_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); dev_err(&pdev->dev, "Class registration failed (%d)\n", err); goto exit_class; @@ -250,7 +248,7 @@ static int __devexit coretemp_remove(struct platform_device *pdev) { struct coretemp_data *data = platform_get_drvdata(pdev); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&pdev->dev.kobj, &coretemp_group); platform_set_drvdata(pdev, NULL); kfree(data); @@ -350,7 +348,7 @@ static int coretemp_cpu_callback(struct notifier_block *nfb, return NOTIFY_OK; } -static struct notifier_block __cpuinitdata coretemp_cpu_notifier = { +static struct notifier_block coretemp_cpu_notifier = { .notifier_call = coretemp_cpu_callback, }; #endif /* !CONFIG_HOTPLUG_CPU */ @@ -371,9 +369,10 @@ static int __init coretemp_init(void) for_each_online_cpu(i) { struct cpuinfo_x86 *c = &(cpu_data)[i]; - /* check if family 6, models e, f */ + /* check if family 6, models e, f, 16 */ if ((c->cpuid_level < 0) || (c->x86 != 0x6) || - !((c->x86_model == 0xe) || (c->x86_model == 0xf))) { + !((c->x86_model == 0xe) || (c->x86_model == 0xf) || + (c->x86_model == 0x16))) { /* supported CPU not found, but report the unknown family 6 CPU */ diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c index e9cbc727664d..a878c98e252e 100644 --- a/drivers/hwmon/dme1737.c +++ b/drivers/hwmon/dme1737.c @@ -1,12 +1,12 @@ /* - * dme1737.c - driver for the SMSC DME1737 and Asus A8000 Super-I/O chips - * integrated hardware monitoring features. + * dme1737.c - Driver for the SMSC DME1737, Asus A8000, and SMSC SCH311x + * Super-I/O chips integrated hardware monitoring features. * Copyright (c) 2007 Juerg Haefliger <juergh@gmail.com> * - * This driver is based on the LM85 driver. The hardware monitoring - * capabilities of the DME1737 are very similar to the LM85 with some - * additional features. Even though the DME1737 is a Super-I/O chip, the - * hardware monitoring registers are only accessible via SMBus. + * This driver is an I2C/ISA hybrid, meaning that it uses the I2C bus to access + * the chip registers if a DME1737 (or A8000) is found and the ISA bus if a + * SCH311x chip is found. Both types of chips have very similar hardware + * monitoring capabilities but differ in the way they can be accessed. * * 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 @@ -28,6 +28,7 @@ #include <linux/slab.h> #include <linux/jiffies.h> #include <linux/i2c.h> +#include <linux/platform_device.h> #include <linux/hwmon.h> #include <linux/hwmon-sysfs.h> #include <linux/hwmon-vid.h> @@ -35,6 +36,9 @@ #include <linux/mutex.h> #include <asm/io.h> +/* ISA device, if found */ +static struct platform_device *pdev; + /* Module load parameters */ static int force_start; module_param(force_start, bool, 0); @@ -133,6 +137,7 @@ static const u8 DME1737_BIT_ALARM_TEMP[] = {4, 5, 6}; static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23}; /* Miscellaneous registers */ +#define DME1737_REG_DEVICE 0x3d #define DME1737_REG_COMPANY 0x3e #define DME1737_REG_VERSTEP 0x3f #define DME1737_REG_CONFIG 0x40 @@ -148,14 +153,20 @@ static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23}; #define DME1737_COMPANY_SMSC 0x5c #define DME1737_VERSTEP 0x88 #define DME1737_VERSTEP_MASK 0xf8 +#define SCH311X_DEVICE 0x8c + +/* Length of ISA address segment */ +#define DME1737_EXTENT 2 /* --------------------------------------------------------------------- * Data structures and manipulation thereof * --------------------------------------------------------------------- */ +/* For ISA chips, we abuse the i2c_client addr and name fields. We also use + the driver field to differentiate between I2C and ISA chips. */ struct dme1737_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; int valid; /* !=0 if following fields are valid */ @@ -465,27 +476,48 @@ static inline int PWM_OFF_TO_REG(int val, int ix, int reg) /* --------------------------------------------------------------------- * Device I/O access + * + * ISA access is performed through an index/data register pair and needs to + * be protected by a mutex during runtime (not required for initialization). + * We use data->update_lock for this and need to ensure that we acquire it + * before calling dme1737_read or dme1737_write. * --------------------------------------------------------------------- */ static u8 dme1737_read(struct i2c_client *client, u8 reg) { - s32 val = i2c_smbus_read_byte_data(client, reg); + s32 val; + + if (client->driver) { /* I2C device */ + val = i2c_smbus_read_byte_data(client, reg); - if (val < 0) { - dev_warn(&client->dev, "Read from register 0x%02x failed! " - "Please report to the driver maintainer.\n", reg); + if (val < 0) { + dev_warn(&client->dev, "Read from register " + "0x%02x failed! Please report to the driver " + "maintainer.\n", reg); + } + } else { /* ISA device */ + outb(reg, client->addr); + val = inb(client->addr + 1); } return val; } -static s32 dme1737_write(struct i2c_client *client, u8 reg, u8 value) +static s32 dme1737_write(struct i2c_client *client, u8 reg, u8 val) { - s32 res = i2c_smbus_write_byte_data(client, reg, value); + s32 res = 0; + + if (client->driver) { /* I2C device */ + res = i2c_smbus_write_byte_data(client, reg, val); - if (res < 0) { - dev_warn(&client->dev, "Write to register 0x%02x failed! " - "Please report to the driver maintainer.\n", reg); + if (res < 0) { + dev_warn(&client->dev, "Write to register " + "0x%02x failed! Please report to the driver " + "maintainer.\n", reg); + } + } else { /* ISA device */ + outb(reg, client->addr); + outb(val, client->addr + 1); } return res; @@ -493,8 +525,8 @@ static s32 dme1737_write(struct i2c_client *client, u8 reg, u8 value) static struct dme1737_data *dme1737_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct dme1737_data *data = i2c_get_clientdata(client); + struct dme1737_data *data = dev_get_drvdata(dev); + struct i2c_client *client = &data->client; int ix; u8 lsb[5]; @@ -630,6 +662,24 @@ static struct dme1737_data *dme1737_update_device(struct device *dev) DME1737_REG_ALARM3) << 16; } + /* The ISA chips require explicit clearing of alarm bits. + * Don't worry, an alarm will come back if the condition + * that causes it still exists */ + if (!client->driver) { + if (data->alarms & 0xff0000) { + dme1737_write(client, DME1737_REG_ALARM3, + 0xff); + } + if (data->alarms & 0xff00) { + dme1737_write(client, DME1737_REG_ALARM2, + 0xff); + } + if (data->alarms & 0xff) { + dme1737_write(client, DME1737_REG_ALARM1, + 0xff); + } + } + data->last_update = jiffies; data->valid = 1; } @@ -674,7 +724,7 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr, break; default: res = 0; - dev_dbg(dev, "Unknown attr fetch (%d)\n", fn); + dev_dbg(dev, "Unknown function %d.\n", fn); } return sprintf(buf, "%d\n", res); @@ -683,8 +733,8 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr, static ssize_t set_in(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct dme1737_data *data = i2c_get_clientdata(client); + struct dme1737_data *data = dev_get_drvdata(dev); + struct i2c_client *client = &data->client; struct sensor_device_attribute_2 *sensor_attr_2 = to_sensor_dev_attr_2(attr); int ix = sensor_attr_2->index; @@ -704,7 +754,7 @@ static ssize_t set_in(struct device *dev, struct device_attribute *attr, data->in_max[ix]); break; default: - dev_dbg(dev, "Unknown attr fetch (%d)\n", fn); + dev_dbg(dev, "Unknown function %d.\n", fn); } mutex_unlock(&data->update_lock); @@ -754,7 +804,7 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *attr, break; default: res = 0; - dev_dbg(dev, "Unknown attr fetch (%d)\n", fn); + dev_dbg(dev, "Unknown function %d.\n", fn); } return sprintf(buf, "%d\n", res); @@ -763,8 +813,8 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *attr, static ssize_t set_temp(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct dme1737_data *data = i2c_get_clientdata(client); + struct dme1737_data *data = dev_get_drvdata(dev); + struct i2c_client *client = &data->client; struct sensor_device_attribute_2 *sensor_attr_2 = to_sensor_dev_attr_2(attr); int ix = sensor_attr_2->index; @@ -789,7 +839,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr, data->temp_offset[ix]); break; default: - dev_dbg(dev, "Unknown attr fetch (%d)\n", fn); + dev_dbg(dev, "Unknown function %d.\n", fn); } mutex_unlock(&data->update_lock); @@ -843,7 +893,7 @@ static ssize_t show_zone(struct device *dev, struct device_attribute *attr, break; default: res = 0; - dev_dbg(dev, "Unknown attr fetch (%d)\n", fn); + dev_dbg(dev, "Unknown function %d.\n", fn); } return sprintf(buf, "%d\n", res); @@ -852,8 +902,8 @@ static ssize_t show_zone(struct device *dev, struct device_attribute *attr, static ssize_t set_zone(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct dme1737_data *data = i2c_get_clientdata(client); + struct dme1737_data *data = dev_get_drvdata(dev); + struct i2c_client *client = &data->client; struct sensor_device_attribute_2 *sensor_attr_2 = to_sensor_dev_attr_2(attr); int ix = sensor_attr_2->index; @@ -898,7 +948,7 @@ static ssize_t set_zone(struct device *dev, struct device_attribute *attr, data->zone_abs[ix]); break; default: - dev_dbg(dev, "Unknown attr fetch (%d)\n", fn); + dev_dbg(dev, "Unknown function %d.\n", fn); } mutex_unlock(&data->update_lock); @@ -950,7 +1000,7 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *attr, break; default: res = 0; - dev_dbg(dev, "Unknown attr fetch (%d)\n", fn); + dev_dbg(dev, "Unknown function %d.\n", fn); } return sprintf(buf, "%d\n", res); @@ -959,8 +1009,8 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *attr, static ssize_t set_fan(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct dme1737_data *data = i2c_get_clientdata(client); + struct dme1737_data *data = dev_get_drvdata(dev); + struct i2c_client *client = &data->client; struct sensor_device_attribute_2 *sensor_attr_2 = to_sensor_dev_attr_2(attr); int ix = sensor_attr_2->index; @@ -995,7 +1045,7 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr, /* Only valid for fan[1-4] */ if (!(val == 1 || val == 2 || val == 4)) { count = -EINVAL; - dev_warn(&client->dev, "Fan type value %ld not " + dev_warn(dev, "Fan type value %ld not " "supported. Choose one of 1, 2, or 4.\n", val); goto exit; @@ -1006,7 +1056,7 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr, data->fan_opt[ix]); break; default: - dev_dbg(dev, "Unknown attr fetch (%d)\n", fn); + dev_dbg(dev, "Unknown function %d.\n", fn); } exit: mutex_unlock(&data->update_lock); @@ -1086,20 +1136,20 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, break; default: res = 0; - dev_dbg(dev, "Unknown attr fetch (%d)\n", fn); + dev_dbg(dev, "Unknown function %d.\n", fn); } return sprintf(buf, "%d\n", res); } static struct attribute *dme1737_attr_pwm[]; -static void dme1737_chmod_file(struct i2c_client*, struct attribute*, mode_t); +static void dme1737_chmod_file(struct device*, struct attribute*, mode_t); static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct dme1737_data *data = i2c_get_clientdata(client); + struct dme1737_data *data = dev_get_drvdata(dev); + struct i2c_client *client = &data->client; struct sensor_device_attribute_2 *sensor_attr_2 = to_sensor_dev_attr_2(attr); int ix = sensor_attr_2->index; @@ -1122,7 +1172,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, /* Only valid for pwm[1-3] */ if (val < 0 || val > 2) { count = -EINVAL; - dev_warn(&client->dev, "PWM enable %ld not " + dev_warn(dev, "PWM enable %ld not " "supported. Choose one of 0, 1, or 2.\n", val); goto exit; @@ -1156,7 +1206,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, switch (val) { case 0: /* Change permissions of pwm[ix] to read-only */ - dme1737_chmod_file(client, dme1737_attr_pwm[ix], + dme1737_chmod_file(dev, dme1737_attr_pwm[ix], S_IRUGO); /* Turn fan fully on */ data->pwm_config[ix] = PWM_EN_TO_REG(0, @@ -1171,12 +1221,12 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, dme1737_write(client, DME1737_REG_PWM_CONFIG(ix), data->pwm_config[ix]); /* Change permissions of pwm[ix] to read-writeable */ - dme1737_chmod_file(client, dme1737_attr_pwm[ix], + dme1737_chmod_file(dev, dme1737_attr_pwm[ix], S_IRUGO | S_IWUSR); break; case 2: /* Change permissions of pwm[ix] to read-only */ - dme1737_chmod_file(client, dme1737_attr_pwm[ix], + dme1737_chmod_file(dev, dme1737_attr_pwm[ix], S_IRUGO); /* Turn on auto mode using the saved zone channel * assignment */ @@ -1223,7 +1273,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, if (!(val == 1 || val == 2 || val == 4 || val == 6 || val == 7)) { count = -EINVAL; - dev_warn(&client->dev, "PWM auto channels zone %ld " + dev_warn(dev, "PWM auto channels zone %ld " "not supported. Choose one of 1, 2, 4, 6, " "or 7.\n", val); goto exit; @@ -1257,12 +1307,10 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, data->pwm_rr[0] = PWM_OFF_TO_REG(1, ix, dme1737_read(client, DME1737_REG_PWM_RR(0))); - } else { data->pwm_rr[0] = PWM_OFF_TO_REG(0, ix, dme1737_read(client, DME1737_REG_PWM_RR(0))); - } dme1737_write(client, DME1737_REG_PWM_RR(0), data->pwm_rr[0]); @@ -1274,7 +1322,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, data->pwm_min[ix]); break; default: - dev_dbg(dev, "Unknown attr fetch (%d)\n", fn); + dev_dbg(dev, "Unknown function %d.\n", fn); } exit: mutex_unlock(&data->update_lock); @@ -1298,8 +1346,7 @@ static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct dme1737_data *data = i2c_get_clientdata(client); + struct dme1737_data *data = dev_get_drvdata(dev); long val = simple_strtol(buf, NULL, 10); data->vrm = val; @@ -1314,6 +1361,14 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); } +static ssize_t show_name(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct dme1737_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", data->client.name); +} + /* --------------------------------------------------------------------- * Sysfs device attribute defines and structs * --------------------------------------------------------------------- */ @@ -1322,13 +1377,13 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr, #define SENSOR_DEVICE_ATTR_IN(ix) \ static SENSOR_DEVICE_ATTR_2(in##ix##_input, S_IRUGO, \ - show_in, NULL, SYS_IN_INPUT, ix); \ + show_in, NULL, SYS_IN_INPUT, ix); \ static SENSOR_DEVICE_ATTR_2(in##ix##_min, S_IRUGO | S_IWUSR, \ - show_in, set_in, SYS_IN_MIN, ix); \ + show_in, set_in, SYS_IN_MIN, ix); \ static SENSOR_DEVICE_ATTR_2(in##ix##_max, S_IRUGO | S_IWUSR, \ - show_in, set_in, SYS_IN_MAX, ix); \ + show_in, set_in, SYS_IN_MAX, ix); \ static SENSOR_DEVICE_ATTR_2(in##ix##_alarm, S_IRUGO, \ - show_in, NULL, SYS_IN_ALARM, ix) + show_in, NULL, SYS_IN_ALARM, ix) SENSOR_DEVICE_ATTR_IN(0); SENSOR_DEVICE_ATTR_IN(1); @@ -1342,17 +1397,17 @@ SENSOR_DEVICE_ATTR_IN(6); #define SENSOR_DEVICE_ATTR_TEMP(ix) \ static SENSOR_DEVICE_ATTR_2(temp##ix##_input, S_IRUGO, \ - show_temp, NULL, SYS_TEMP_INPUT, ix-1); \ + show_temp, NULL, SYS_TEMP_INPUT, ix-1); \ static SENSOR_DEVICE_ATTR_2(temp##ix##_min, S_IRUGO | S_IWUSR, \ - show_temp, set_temp, SYS_TEMP_MIN, ix-1); \ + show_temp, set_temp, SYS_TEMP_MIN, ix-1); \ static SENSOR_DEVICE_ATTR_2(temp##ix##_max, S_IRUGO | S_IWUSR, \ - show_temp, set_temp, SYS_TEMP_MAX, ix-1); \ + show_temp, set_temp, SYS_TEMP_MAX, ix-1); \ static SENSOR_DEVICE_ATTR_2(temp##ix##_offset, S_IRUGO, \ - show_temp, set_temp, SYS_TEMP_OFFSET, ix-1); \ + show_temp, set_temp, SYS_TEMP_OFFSET, ix-1); \ static SENSOR_DEVICE_ATTR_2(temp##ix##_alarm, S_IRUGO, \ - show_temp, NULL, SYS_TEMP_ALARM, ix-1); \ + show_temp, NULL, SYS_TEMP_ALARM, ix-1); \ static SENSOR_DEVICE_ATTR_2(temp##ix##_fault, S_IRUGO, \ - show_temp, NULL, SYS_TEMP_FAULT, ix-1) + show_temp, NULL, SYS_TEMP_FAULT, ix-1) SENSOR_DEVICE_ATTR_TEMP(1); SENSOR_DEVICE_ATTR_TEMP(2); @@ -1362,15 +1417,15 @@ SENSOR_DEVICE_ATTR_TEMP(3); #define SENSOR_DEVICE_ATTR_ZONE(ix) \ static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_channels_temp, S_IRUGO, \ - show_zone, NULL, SYS_ZONE_AUTO_CHANNELS_TEMP, ix-1); \ + show_zone, NULL, SYS_ZONE_AUTO_CHANNELS_TEMP, ix-1); \ static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point1_temp_hyst, S_IRUGO, \ - show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP_HYST, ix-1); \ + show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP_HYST, ix-1); \ static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point1_temp, S_IRUGO, \ - show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP, ix-1); \ + show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP, ix-1); \ static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point2_temp, S_IRUGO, \ - show_zone, set_zone, SYS_ZONE_AUTO_POINT2_TEMP, ix-1); \ + show_zone, set_zone, SYS_ZONE_AUTO_POINT2_TEMP, ix-1); \ static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point3_temp, S_IRUGO, \ - show_zone, set_zone, SYS_ZONE_AUTO_POINT3_TEMP, ix-1) + show_zone, set_zone, SYS_ZONE_AUTO_POINT3_TEMP, ix-1) SENSOR_DEVICE_ATTR_ZONE(1); SENSOR_DEVICE_ATTR_ZONE(2); @@ -1380,13 +1435,13 @@ SENSOR_DEVICE_ATTR_ZONE(3); #define SENSOR_DEVICE_ATTR_FAN_1TO4(ix) \ static SENSOR_DEVICE_ATTR_2(fan##ix##_input, S_IRUGO, \ - show_fan, NULL, SYS_FAN_INPUT, ix-1); \ + show_fan, NULL, SYS_FAN_INPUT, ix-1); \ static SENSOR_DEVICE_ATTR_2(fan##ix##_min, S_IRUGO | S_IWUSR, \ - show_fan, set_fan, SYS_FAN_MIN, ix-1); \ + show_fan, set_fan, SYS_FAN_MIN, ix-1); \ static SENSOR_DEVICE_ATTR_2(fan##ix##_alarm, S_IRUGO, \ - show_fan, NULL, SYS_FAN_ALARM, ix-1); \ + show_fan, NULL, SYS_FAN_ALARM, ix-1); \ static SENSOR_DEVICE_ATTR_2(fan##ix##_type, S_IRUGO | S_IWUSR, \ - show_fan, set_fan, SYS_FAN_TYPE, ix-1) + show_fan, set_fan, SYS_FAN_TYPE, ix-1) SENSOR_DEVICE_ATTR_FAN_1TO4(1); SENSOR_DEVICE_ATTR_FAN_1TO4(2); @@ -1397,13 +1452,13 @@ SENSOR_DEVICE_ATTR_FAN_1TO4(4); #define SENSOR_DEVICE_ATTR_FAN_5TO6(ix) \ static SENSOR_DEVICE_ATTR_2(fan##ix##_input, S_IRUGO, \ - show_fan, NULL, SYS_FAN_INPUT, ix-1); \ + show_fan, NULL, SYS_FAN_INPUT, ix-1); \ static SENSOR_DEVICE_ATTR_2(fan##ix##_min, S_IRUGO | S_IWUSR, \ - show_fan, set_fan, SYS_FAN_MIN, ix-1); \ + show_fan, set_fan, SYS_FAN_MIN, ix-1); \ static SENSOR_DEVICE_ATTR_2(fan##ix##_alarm, S_IRUGO, \ - show_fan, NULL, SYS_FAN_ALARM, ix-1); \ + show_fan, NULL, SYS_FAN_ALARM, ix-1); \ static SENSOR_DEVICE_ATTR_2(fan##ix##_max, S_IRUGO | S_IWUSR, \ - show_fan, set_fan, SYS_FAN_MAX, ix-1) + show_fan, set_fan, SYS_FAN_MAX, ix-1) SENSOR_DEVICE_ATTR_FAN_5TO6(5); SENSOR_DEVICE_ATTR_FAN_5TO6(6); @@ -1412,21 +1467,21 @@ SENSOR_DEVICE_ATTR_FAN_5TO6(6); #define SENSOR_DEVICE_ATTR_PWM_1TO3(ix) \ static SENSOR_DEVICE_ATTR_2(pwm##ix, S_IRUGO, \ - show_pwm, set_pwm, SYS_PWM, ix-1); \ + show_pwm, set_pwm, SYS_PWM, ix-1); \ static SENSOR_DEVICE_ATTR_2(pwm##ix##_freq, S_IRUGO, \ - show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \ + show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \ static SENSOR_DEVICE_ATTR_2(pwm##ix##_enable, S_IRUGO, \ - show_pwm, set_pwm, SYS_PWM_ENABLE, ix-1); \ + show_pwm, set_pwm, SYS_PWM_ENABLE, ix-1); \ static SENSOR_DEVICE_ATTR_2(pwm##ix##_ramp_rate, S_IRUGO, \ - show_pwm, set_pwm, SYS_PWM_RAMP_RATE, ix-1); \ + show_pwm, set_pwm, SYS_PWM_RAMP_RATE, ix-1); \ static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_channels_zone, S_IRUGO, \ - show_pwm, set_pwm, SYS_PWM_AUTO_CHANNELS_ZONE, ix-1); \ + show_pwm, set_pwm, SYS_PWM_AUTO_CHANNELS_ZONE, ix-1); \ static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_pwm_min, S_IRUGO, \ - show_pwm, set_pwm, SYS_PWM_AUTO_PWM_MIN, ix-1); \ + show_pwm, set_pwm, SYS_PWM_AUTO_PWM_MIN, ix-1); \ static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_point1_pwm, S_IRUGO, \ - show_pwm, set_pwm, SYS_PWM_AUTO_POINT1_PWM, ix-1); \ + show_pwm, set_pwm, SYS_PWM_AUTO_POINT1_PWM, ix-1); \ static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_point2_pwm, S_IRUGO, \ - show_pwm, NULL, SYS_PWM_AUTO_POINT2_PWM, ix-1) + show_pwm, NULL, SYS_PWM_AUTO_POINT2_PWM, ix-1) SENSOR_DEVICE_ATTR_PWM_1TO3(1); SENSOR_DEVICE_ATTR_PWM_1TO3(2); @@ -1436,11 +1491,11 @@ SENSOR_DEVICE_ATTR_PWM_1TO3(3); #define SENSOR_DEVICE_ATTR_PWM_5TO6(ix) \ static SENSOR_DEVICE_ATTR_2(pwm##ix, S_IRUGO | S_IWUSR, \ - show_pwm, set_pwm, SYS_PWM, ix-1); \ + show_pwm, set_pwm, SYS_PWM, ix-1); \ static SENSOR_DEVICE_ATTR_2(pwm##ix##_freq, S_IRUGO | S_IWUSR, \ - show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \ + show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \ static SENSOR_DEVICE_ATTR_2(pwm##ix##_enable, S_IRUGO, \ - show_pwm, NULL, SYS_PWM_ENABLE, ix-1) + show_pwm, NULL, SYS_PWM_ENABLE, ix-1) SENSOR_DEVICE_ATTR_PWM_5TO6(5); SENSOR_DEVICE_ATTR_PWM_5TO6(6); @@ -1449,6 +1504,7 @@ SENSOR_DEVICE_ATTR_PWM_5TO6(6); static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); +static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); /* for ISA devices */ #define SENSOR_DEV_ATTR_IN(ix) \ &sensor_dev_attr_in##ix##_input.dev_attr.attr, \ @@ -1519,53 +1575,53 @@ SENSOR_DEV_ATTR_PWM_5TO6_LOCK(ix), \ * permissions are created read-only and write permissions are added or removed * on the fly when required */ static struct attribute *dme1737_attr[] ={ - /* Voltages */ - SENSOR_DEV_ATTR_IN(0), - SENSOR_DEV_ATTR_IN(1), - SENSOR_DEV_ATTR_IN(2), - SENSOR_DEV_ATTR_IN(3), - SENSOR_DEV_ATTR_IN(4), - SENSOR_DEV_ATTR_IN(5), - SENSOR_DEV_ATTR_IN(6), - /* Temperatures */ - SENSOR_DEV_ATTR_TEMP(1), - SENSOR_DEV_ATTR_TEMP(2), - SENSOR_DEV_ATTR_TEMP(3), - /* Zones */ - SENSOR_DEV_ATTR_ZONE(1), - SENSOR_DEV_ATTR_ZONE(2), - SENSOR_DEV_ATTR_ZONE(3), - /* Misc */ - &dev_attr_vrm.attr, - &dev_attr_cpu0_vid.attr, + /* Voltages */ + SENSOR_DEV_ATTR_IN(0), + SENSOR_DEV_ATTR_IN(1), + SENSOR_DEV_ATTR_IN(2), + SENSOR_DEV_ATTR_IN(3), + SENSOR_DEV_ATTR_IN(4), + SENSOR_DEV_ATTR_IN(5), + SENSOR_DEV_ATTR_IN(6), + /* Temperatures */ + SENSOR_DEV_ATTR_TEMP(1), + SENSOR_DEV_ATTR_TEMP(2), + SENSOR_DEV_ATTR_TEMP(3), + /* Zones */ + SENSOR_DEV_ATTR_ZONE(1), + SENSOR_DEV_ATTR_ZONE(2), + SENSOR_DEV_ATTR_ZONE(3), + /* Misc */ + &dev_attr_vrm.attr, + &dev_attr_cpu0_vid.attr, NULL }; static const struct attribute_group dme1737_group = { - .attrs = dme1737_attr, + .attrs = dme1737_attr, }; /* The following structs hold the PWM attributes, some of which are optional. * Their creation depends on the chip configuration which is determined during * module load. */ static struct attribute *dme1737_attr_pwm1[] = { - SENSOR_DEV_ATTR_PWM_1TO3(1), + SENSOR_DEV_ATTR_PWM_1TO3(1), NULL }; static struct attribute *dme1737_attr_pwm2[] = { - SENSOR_DEV_ATTR_PWM_1TO3(2), + SENSOR_DEV_ATTR_PWM_1TO3(2), NULL }; static struct attribute *dme1737_attr_pwm3[] = { - SENSOR_DEV_ATTR_PWM_1TO3(3), + SENSOR_DEV_ATTR_PWM_1TO3(3), NULL }; static struct attribute *dme1737_attr_pwm5[] = { - SENSOR_DEV_ATTR_PWM_5TO6(5), + SENSOR_DEV_ATTR_PWM_5TO6(5), NULL }; static struct attribute *dme1737_attr_pwm6[] = { - SENSOR_DEV_ATTR_PWM_5TO6(6), + SENSOR_DEV_ATTR_PWM_5TO6(6), NULL }; @@ -1582,27 +1638,27 @@ static const struct attribute_group dme1737_pwm_group[] = { * Their creation depends on the chip configuration which is determined during * module load. */ static struct attribute *dme1737_attr_fan1[] = { - SENSOR_DEV_ATTR_FAN_1TO4(1), + SENSOR_DEV_ATTR_FAN_1TO4(1), NULL }; static struct attribute *dme1737_attr_fan2[] = { - SENSOR_DEV_ATTR_FAN_1TO4(2), + SENSOR_DEV_ATTR_FAN_1TO4(2), NULL }; static struct attribute *dme1737_attr_fan3[] = { - SENSOR_DEV_ATTR_FAN_1TO4(3), + SENSOR_DEV_ATTR_FAN_1TO4(3), NULL }; static struct attribute *dme1737_attr_fan4[] = { - SENSOR_DEV_ATTR_FAN_1TO4(4), + SENSOR_DEV_ATTR_FAN_1TO4(4), NULL }; static struct attribute *dme1737_attr_fan5[] = { - SENSOR_DEV_ATTR_FAN_5TO6(5), + SENSOR_DEV_ATTR_FAN_5TO6(5), NULL }; static struct attribute *dme1737_attr_fan6[] = { - SENSOR_DEV_ATTR_FAN_5TO6(6), + SENSOR_DEV_ATTR_FAN_5TO6(6), NULL }; @@ -1637,23 +1693,23 @@ static const struct attribute_group dme1737_lock_group = { * writeable if the chip is *not* locked and the respective PWM is available. * Otherwise they stay read-only. */ static struct attribute *dme1737_attr_pwm1_lock[] = { - SENSOR_DEV_ATTR_PWM_1TO3_LOCK(1), + SENSOR_DEV_ATTR_PWM_1TO3_LOCK(1), NULL }; static struct attribute *dme1737_attr_pwm2_lock[] = { - SENSOR_DEV_ATTR_PWM_1TO3_LOCK(2), + SENSOR_DEV_ATTR_PWM_1TO3_LOCK(2), NULL }; static struct attribute *dme1737_attr_pwm3_lock[] = { - SENSOR_DEV_ATTR_PWM_1TO3_LOCK(3), + SENSOR_DEV_ATTR_PWM_1TO3_LOCK(3), NULL }; static struct attribute *dme1737_attr_pwm5_lock[] = { - SENSOR_DEV_ATTR_PWM_5TO6_LOCK(5), + SENSOR_DEV_ATTR_PWM_5TO6_LOCK(5), NULL }; static struct attribute *dme1737_attr_pwm6_lock[] = { - SENSOR_DEV_ATTR_PWM_5TO6_LOCK(6), + SENSOR_DEV_ATTR_PWM_5TO6_LOCK(6), NULL }; @@ -1678,6 +1734,16 @@ static struct attribute *dme1737_attr_pwm[] = { * Super-IO functions * --------------------------------------------------------------------- */ +static inline void dme1737_sio_enter(int sio_cip) +{ + outb(0x55, sio_cip); +} + +static inline void dme1737_sio_exit(int sio_cip) +{ + outb(0xaa, sio_cip); +} + static inline int dme1737_sio_inb(int sio_cip, int reg) { outb(reg, sio_cip); @@ -1690,136 +1756,196 @@ static inline void dme1737_sio_outb(int sio_cip, int reg, int val) outb(val, sio_cip + 1); } -static int dme1737_sio_get_features(int sio_cip, struct i2c_client *client) +/* --------------------------------------------------------------------- + * Device initialization + * --------------------------------------------------------------------- */ + +static int dme1737_i2c_get_features(int, struct dme1737_data*); + +static void dme1737_chmod_file(struct device *dev, + struct attribute *attr, mode_t mode) { - struct dme1737_data *data = i2c_get_clientdata(client); - int err = 0, reg; - u16 addr; + if (sysfs_chmod_file(&dev->kobj, attr, mode)) { + dev_warn(dev, "Failed to change permissions of %s.\n", + attr->name); + } +} - /* Enter configuration mode */ - outb(0x55, sio_cip); +static void dme1737_chmod_group(struct device *dev, + const struct attribute_group *group, + mode_t mode) +{ + struct attribute **attr; - /* Check device ID - * The DME1737 can return either 0x78 or 0x77 as its device ID. */ - reg = dme1737_sio_inb(sio_cip, 0x20); - if (!(reg == 0x77 || reg == 0x78)) { - err = -ENODEV; - goto exit; + for (attr = group->attrs; *attr; attr++) { + dme1737_chmod_file(dev, *attr, mode); } +} - /* Select logical device A (runtime registers) */ - dme1737_sio_outb(sio_cip, 0x07, 0x0a); +static void dme1737_remove_files(struct device *dev) +{ + struct dme1737_data *data = dev_get_drvdata(dev); + int ix; - /* Get the base address of the runtime registers */ - if (!(addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) | - dme1737_sio_inb(sio_cip, 0x61))) { - err = -ENODEV; - goto exit; + for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) { + if (data->has_fan & (1 << ix)) { + sysfs_remove_group(&dev->kobj, + &dme1737_fan_group[ix]); + } } - /* Read the runtime registers to determine which optional features - * are enabled and available. Bits [3:2] of registers 0x43-0x46 are set - * to '10' if the respective feature is enabled. */ - if ((inb(addr + 0x43) & 0x0c) == 0x08) { /* fan6 */ - data->has_fan |= (1 << 5); + for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) { + if (data->has_pwm & (1 << ix)) { + sysfs_remove_group(&dev->kobj, + &dme1737_pwm_group[ix]); + } } - if ((inb(addr + 0x44) & 0x0c) == 0x08) { /* pwm6 */ - data->has_pwm |= (1 << 5); + + sysfs_remove_group(&dev->kobj, &dme1737_group); + + if (!data->client.driver) { + sysfs_remove_file(&dev->kobj, &dev_attr_name.attr); } - if ((inb(addr + 0x45) & 0x0c) == 0x08) { /* fan5 */ - data->has_fan |= (1 << 4); +} + +static int dme1737_create_files(struct device *dev) +{ + struct dme1737_data *data = dev_get_drvdata(dev); + int err, ix; + + /* Create a name attribute for ISA devices */ + if (!data->client.driver && + (err = sysfs_create_file(&dev->kobj, &dev_attr_name.attr))) { + goto exit; } - if ((inb(addr + 0x46) & 0x0c) == 0x08) { /* pwm5 */ - data->has_pwm |= (1 << 4); + + /* Create standard sysfs attributes */ + if ((err = sysfs_create_group(&dev->kobj, &dme1737_group))) { + goto exit_remove; } -exit: - /* Exit configuration mode */ - outb(0xaa, sio_cip); + /* Create fan sysfs attributes */ + for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) { + if (data->has_fan & (1 << ix)) { + if ((err = sysfs_create_group(&dev->kobj, + &dme1737_fan_group[ix]))) { + goto exit_remove; + } + } + } - return err; -} + /* Create PWM sysfs attributes */ + for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) { + if (data->has_pwm & (1 << ix)) { + if ((err = sysfs_create_group(&dev->kobj, + &dme1737_pwm_group[ix]))) { + goto exit_remove; + } + } + } -/* --------------------------------------------------------------------- - * Device detection, registration and initialization - * --------------------------------------------------------------------- */ + /* Inform if the device is locked. Otherwise change the permissions of + * selected attributes from read-only to read-writeable. */ + if (data->config & 0x02) { + dev_info(dev, "Device is locked. Some attributes " + "will be read-only.\n"); + } else { + /* Change permissions of standard attributes */ + dme1737_chmod_group(dev, &dme1737_lock_group, + S_IRUGO | S_IWUSR); -static struct i2c_driver dme1737_driver; + /* Change permissions of PWM attributes */ + for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_lock_group); ix++) { + if (data->has_pwm & (1 << ix)) { + dme1737_chmod_group(dev, + &dme1737_pwm_lock_group[ix], + S_IRUGO | S_IWUSR); + } + } -static void dme1737_chmod_file(struct i2c_client *client, - struct attribute *attr, mode_t mode) -{ - if (sysfs_chmod_file(&client->dev.kobj, attr, mode)) { - dev_warn(&client->dev, "Failed to change permissions of %s.\n", - attr->name); + /* Change permissions of pwm[1-3] if in manual mode */ + for (ix = 0; ix < 3; ix++) { + if ((data->has_pwm & (1 << ix)) && + (PWM_EN_FROM_REG(data->pwm_config[ix]) == 1)) { + dme1737_chmod_file(dev, + dme1737_attr_pwm[ix], + S_IRUGO | S_IWUSR); + } + } } -} -static void dme1737_chmod_group(struct i2c_client *client, - const struct attribute_group *group, - mode_t mode) -{ - struct attribute **attr; + return 0; - for (attr = group->attrs; *attr; attr++) { - dme1737_chmod_file(client, *attr, mode); - } +exit_remove: + dme1737_remove_files(dev); +exit: + return err; } -static int dme1737_init_client(struct i2c_client *client) +static int dme1737_init_device(struct device *dev) { - struct dme1737_data *data = i2c_get_clientdata(client); + struct dme1737_data *data = dev_get_drvdata(dev); + struct i2c_client *client = &data->client; int ix; u8 reg; - data->config = dme1737_read(client, DME1737_REG_CONFIG); - /* Inform if part is not monitoring/started */ - if (!(data->config & 0x01)) { - if (!force_start) { - dev_err(&client->dev, "Device is not monitoring. " - "Use the force_start load parameter to " - "override.\n"); - return -EFAULT; - } - - /* Force monitoring */ - data->config |= 0x01; - dme1737_write(client, DME1737_REG_CONFIG, data->config); - } + data->config = dme1737_read(client, DME1737_REG_CONFIG); + /* Inform if part is not monitoring/started */ + if (!(data->config & 0x01)) { + if (!force_start) { + dev_err(dev, "Device is not monitoring. " + "Use the force_start load parameter to " + "override.\n"); + return -EFAULT; + } + + /* Force monitoring */ + data->config |= 0x01; + dme1737_write(client, DME1737_REG_CONFIG, data->config); + } /* Inform if part is not ready */ if (!(data->config & 0x04)) { - dev_err(&client->dev, "Device is not ready.\n"); + dev_err(dev, "Device is not ready.\n"); return -EFAULT; } - data->config2 = dme1737_read(client, DME1737_REG_CONFIG2); - /* Check if optional fan3 input is enabled */ - if (data->config2 & 0x04) { - data->has_fan |= (1 << 2); - } + /* Determine which optional fan and pwm features are enabled/present */ + if (client->driver) { /* I2C chip */ + data->config2 = dme1737_read(client, DME1737_REG_CONFIG2); + /* Check if optional fan3 input is enabled */ + if (data->config2 & 0x04) { + data->has_fan |= (1 << 2); + } - /* Fan4 and pwm3 are only available if the client's I2C address - * is the default 0x2e. Otherwise the I/Os associated with these - * functions are used for addr enable/select. */ - if (client->addr == 0x2e) { - data->has_fan |= (1 << 3); - data->has_pwm |= (1 << 2); - } + /* Fan4 and pwm3 are only available if the client's I2C address + * is the default 0x2e. Otherwise the I/Os associated with + * these functions are used for addr enable/select. */ + if (data->client.addr == 0x2e) { + data->has_fan |= (1 << 3); + data->has_pwm |= (1 << 2); + } - /* Determine if the optional fan[5-6] and/or pwm[5-6] are enabled. - * For this, we need to query the runtime registers through the - * Super-IO LPC interface. Try both config ports 0x2e and 0x4e. */ - if (dme1737_sio_get_features(0x2e, client) && - dme1737_sio_get_features(0x4e, client)) { - dev_warn(&client->dev, "Failed to query Super-IO for optional " - "features.\n"); + /* Determine which of the optional fan[5-6] and pwm[5-6] + * features are enabled. For this, we need to query the runtime + * registers through the Super-IO LPC interface. Try both + * config ports 0x2e and 0x4e. */ + if (dme1737_i2c_get_features(0x2e, data) && + dme1737_i2c_get_features(0x4e, data)) { + dev_warn(dev, "Failed to query Super-IO for optional " + "features.\n"); + } + } else { /* ISA chip */ + /* Fan3 and pwm3 are always available. Fan[4-5] and pwm[5-6] + * don't exist in the ISA chip. */ + data->has_fan |= (1 << 2); + data->has_pwm |= (1 << 2); } /* Fan1, fan2, pwm1, and pwm2 are always present */ data->has_fan |= 0x03; data->has_pwm |= 0x03; - dev_info(&client->dev, "Optional features: pwm3=%s, pwm5=%s, pwm6=%s, " + dev_info(dev, "Optional features: pwm3=%s, pwm5=%s, pwm6=%s, " "fan3=%s, fan4=%s, fan5=%s, fan6=%s.\n", (data->has_pwm & (1 << 2)) ? "yes" : "no", (data->has_pwm & (1 << 4)) ? "yes" : "no", @@ -1831,13 +1957,19 @@ static int dme1737_init_client(struct i2c_client *client) reg = dme1737_read(client, DME1737_REG_TACH_PWM); /* Inform if fan-to-pwm mapping differs from the default */ - if (reg != 0xa4) { - dev_warn(&client->dev, "Non-standard fan to pwm mapping: " + if (client->driver && reg != 0xa4) { /* I2C chip */ + dev_warn(dev, "Non-standard fan to pwm mapping: " "fan1->pwm%d, fan2->pwm%d, fan3->pwm%d, " "fan4->pwm%d. Please report to the driver " "maintainer.\n", (reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1, ((reg >> 4) & 0x03) + 1, ((reg >> 6) & 0x03) + 1); + } else if (!client->driver && reg != 0x24) { /* ISA chip */ + dev_warn(dev, "Non-standard fan to pwm mapping: " + "fan1->pwm%d, fan2->pwm%d, fan3->pwm%d. " + "Please report to the driver maintainer.\n", + (reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1, + ((reg >> 4) & 0x03) + 1); } /* Switch pwm[1-3] to manual mode if they are currently disabled and @@ -1849,7 +1981,7 @@ static int dme1737_init_client(struct i2c_client *client) DME1737_REG_PWM_CONFIG(ix)); if ((data->has_pwm & (1 << ix)) && (PWM_EN_FROM_REG(data->pwm_config[ix]) == -1)) { - dev_info(&client->dev, "Switching pwm%d to " + dev_info(dev, "Switching pwm%d to " "manual mode.\n", ix + 1); data->pwm_config[ix] = PWM_EN_TO_REG(1, data->pwm_config[ix]); @@ -1872,13 +2004,67 @@ static int dme1737_init_client(struct i2c_client *client) return 0; } -static int dme1737_detect(struct i2c_adapter *adapter, int address, - int kind) +/* --------------------------------------------------------------------- + * I2C device detection and registration + * --------------------------------------------------------------------- */ + +static struct i2c_driver dme1737_i2c_driver; + +static int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data) +{ + int err = 0, reg; + u16 addr; + + dme1737_sio_enter(sio_cip); + + /* Check device ID + * The DME1737 can return either 0x78 or 0x77 as its device ID. */ + reg = dme1737_sio_inb(sio_cip, 0x20); + if (!(reg == 0x77 || reg == 0x78)) { + err = -ENODEV; + goto exit; + } + + /* Select logical device A (runtime registers) */ + dme1737_sio_outb(sio_cip, 0x07, 0x0a); + + /* Get the base address of the runtime registers */ + if (!(addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) | + dme1737_sio_inb(sio_cip, 0x61))) { + err = -ENODEV; + goto exit; + } + + /* Read the runtime registers to determine which optional features + * are enabled and available. Bits [3:2] of registers 0x43-0x46 are set + * to '10' if the respective feature is enabled. */ + if ((inb(addr + 0x43) & 0x0c) == 0x08) { /* fan6 */ + data->has_fan |= (1 << 5); + } + if ((inb(addr + 0x44) & 0x0c) == 0x08) { /* pwm6 */ + data->has_pwm |= (1 << 5); + } + if ((inb(addr + 0x45) & 0x0c) == 0x08) { /* fan5 */ + data->has_fan |= (1 << 4); + } + if ((inb(addr + 0x46) & 0x0c) == 0x08) { /* pwm5 */ + data->has_pwm |= (1 << 4); + } + +exit: + dme1737_sio_exit(sio_cip); + + return err; +} + +static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address, + int kind) { u8 company, verstep = 0; struct i2c_client *client; struct dme1737_data *data; - int ix, err = 0; + struct device *dev; + int err = 0; const char *name; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { @@ -1894,7 +2080,8 @@ static int dme1737_detect(struct i2c_adapter *adapter, int address, i2c_set_clientdata(client, data); client->addr = address; client->adapter = adapter; - client->driver = &dme1737_driver; + client->driver = &dme1737_i2c_driver; + dev = &client->dev; /* A negative kind means that the driver was loaded with no force * parameter (default), so we must identify the chip. */ @@ -1922,92 +2109,33 @@ static int dme1737_detect(struct i2c_adapter *adapter, int address, goto exit_kfree; } + dev_info(dev, "Found a DME1737 chip at 0x%02x (rev 0x%02x).\n", + client->addr, verstep); + /* Initialize the DME1737 chip */ - if ((err = dme1737_init_client(client))) { + if ((err = dme1737_init_device(dev))) { + dev_err(dev, "Failed to initialize device.\n"); goto exit_detach; } - /* Create standard sysfs attributes */ - if ((err = sysfs_create_group(&client->dev.kobj, &dme1737_group))) { - goto exit_detach; - } - - /* Create fan sysfs attributes */ - for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) { - if (data->has_fan & (1 << ix)) { - if ((err = sysfs_create_group(&client->dev.kobj, - &dme1737_fan_group[ix]))) { - goto exit_remove; - } - } - } - - /* Create PWM sysfs attributes */ - for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) { - if (data->has_pwm & (1 << ix)) { - if ((err = sysfs_create_group(&client->dev.kobj, - &dme1737_pwm_group[ix]))) { - goto exit_remove; - } - } - } - - /* Inform if the device is locked. Otherwise change the permissions of - * selected attributes from read-only to read-writeable. */ - if (data->config & 0x02) { - dev_info(&client->dev, "Device is locked. Some attributes " - "will be read-only.\n"); - } else { - /* Change permissions of standard attributes */ - dme1737_chmod_group(client, &dme1737_lock_group, - S_IRUGO | S_IWUSR); - - /* Change permissions of PWM attributes */ - for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_lock_group); ix++) { - if (data->has_pwm & (1 << ix)) { - dme1737_chmod_group(client, - &dme1737_pwm_lock_group[ix], - S_IRUGO | S_IWUSR); - } - } - - /* Change permissions of pwm[1-3] if in manual mode */ - for (ix = 0; ix < 3; ix++) { - if ((data->has_pwm & (1 << ix)) && - (PWM_EN_FROM_REG(data->pwm_config[ix]) == 1)) { - dme1737_chmod_file(client, - dme1737_attr_pwm[ix], - S_IRUGO | S_IWUSR); - } - } + /* Create sysfs files */ + if ((err = dme1737_create_files(dev))) { + dev_err(dev, "Failed to create sysfs files.\n"); + goto exit_detach; } /* Register device */ - data->class_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(data->hwmon_dev)) { + dev_err(dev, "Failed to register device.\n"); + err = PTR_ERR(data->hwmon_dev); goto exit_remove; } - dev_info(&adapter->dev, "Found a DME1737 chip at 0x%02x " - "(rev 0x%02x)\n", client->addr, verstep); - return 0; exit_remove: - for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) { - if (data->has_fan & (1 << ix)) { - sysfs_remove_group(&client->dev.kobj, - &dme1737_fan_group[ix]); - } - } - for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) { - if (data->has_pwm & (1 << ix)) { - sysfs_remove_group(&client->dev.kobj, - &dme1737_pwm_group[ix]); - } - } - sysfs_remove_group(&client->dev.kobj, &dme1737_group); + dme1737_remove_files(dev); exit_detach: i2c_detach_client(client); exit_kfree: @@ -2016,60 +2144,260 @@ exit: return err; } -static int dme1737_attach_adapter(struct i2c_adapter *adapter) +static int dme1737_i2c_attach_adapter(struct i2c_adapter *adapter) { if (!(adapter->class & I2C_CLASS_HWMON)) { return 0; } - return i2c_probe(adapter, &addr_data, dme1737_detect); + return i2c_probe(adapter, &addr_data, dme1737_i2c_detect); } -static int dme1737_detach_client(struct i2c_client *client) +static int dme1737_i2c_detach_client(struct i2c_client *client) { struct dme1737_data *data = i2c_get_clientdata(client); - int ix, err; + int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); + dme1737_remove_files(&client->dev); - for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) { - if (data->has_fan & (1 << ix)) { - sysfs_remove_group(&client->dev.kobj, - &dme1737_fan_group[ix]); - } + if ((err = i2c_detach_client(client))) { + return err; } - for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) { - if (data->has_pwm & (1 << ix)) { - sysfs_remove_group(&client->dev.kobj, - &dme1737_pwm_group[ix]); - } + + kfree(data); + return 0; +} + +static struct i2c_driver dme1737_i2c_driver = { + .driver = { + .name = "dme1737", + }, + .attach_adapter = dme1737_i2c_attach_adapter, + .detach_client = dme1737_i2c_detach_client, +}; + +/* --------------------------------------------------------------------- + * ISA device detection and registration + * --------------------------------------------------------------------- */ + +static int __init dme1737_isa_detect(int sio_cip, unsigned short *addr) +{ + int err = 0, reg; + unsigned short base_addr; + + dme1737_sio_enter(sio_cip); + + /* Check device ID + * We currently know about SCH3112 (0x7c), SCH3114 (0x7d), and + * SCH3116 (0x7f). */ + reg = dme1737_sio_inb(sio_cip, 0x20); + if (!(reg == 0x7c || reg == 0x7d || reg == 0x7f)) { + err = -ENODEV; + goto exit; } - sysfs_remove_group(&client->dev.kobj, &dme1737_group); - if ((err = i2c_detach_client(client))) { - return err; + /* Select logical device A (runtime registers) */ + dme1737_sio_outb(sio_cip, 0x07, 0x0a); + + /* Get the base address of the runtime registers */ + if (!(base_addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) | + dme1737_sio_inb(sio_cip, 0x61))) { + printk(KERN_ERR "dme1737: Base address not set.\n"); + err = -ENODEV; + goto exit; + } + + /* Access to the hwmon registers is through an index/data register + * pair located at offset 0x70/0x71. */ + *addr = base_addr + 0x70; + +exit: + dme1737_sio_exit(sio_cip); + return err; +} + +static int __init dme1737_isa_device_add(unsigned short addr) +{ + struct resource res = { + .start = addr, + .end = addr + DME1737_EXTENT - 1, + .name = "dme1737", + .flags = IORESOURCE_IO, + }; + int err; + + if (!(pdev = platform_device_alloc("dme1737", addr))) { + printk(KERN_ERR "dme1737: Failed to allocate device.\n"); + err = -ENOMEM; + goto exit; + } + + if ((err = platform_device_add_resources(pdev, &res, 1))) { + printk(KERN_ERR "dme1737: Failed to add device resource " + "(err = %d).\n", err); + goto exit_device_put; + } + + if ((err = platform_device_add(pdev))) { + printk(KERN_ERR "dme1737: Failed to add device (err = %d).\n", + err); + goto exit_device_put; + } + + return 0; + +exit_device_put: + platform_device_put(pdev); + pdev = NULL; +exit: + return err; +} + +static int __devinit dme1737_isa_probe(struct platform_device *pdev) +{ + u8 company, device; + struct resource *res; + struct i2c_client *client; + struct dme1737_data *data; + struct device *dev = &pdev->dev; + int err; + + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!request_region(res->start, DME1737_EXTENT, "dme1737")) { + dev_err(dev, "Failed to request region 0x%04x-0x%04x.\n", + (unsigned short)res->start, + (unsigned short)res->start + DME1737_EXTENT - 1); + err = -EBUSY; + goto exit; + } + + if (!(data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit_release_region; + } + + client = &data->client; + i2c_set_clientdata(client, data); + client->addr = res->start; + platform_set_drvdata(pdev, data); + + company = dme1737_read(client, DME1737_REG_COMPANY); + device = dme1737_read(client, DME1737_REG_DEVICE); + + if (!((company == DME1737_COMPANY_SMSC) && + (device == SCH311X_DEVICE))) { + err = -ENODEV; + goto exit_kfree; + } + + /* Fill in the remaining client fields and initialize the mutex */ + strlcpy(client->name, "sch311x", I2C_NAME_SIZE); + mutex_init(&data->update_lock); + + dev_info(dev, "Found a SCH311x chip at 0x%04x\n", client->addr); + + /* Initialize the chip */ + if ((err = dme1737_init_device(dev))) { + dev_err(dev, "Failed to initialize device.\n"); + goto exit_kfree; } + /* Create sysfs files */ + if ((err = dme1737_create_files(dev))) { + dev_err(dev, "Failed to create sysfs files.\n"); + goto exit_kfree; + } + + /* Register device */ + data->hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(data->hwmon_dev)) { + dev_err(dev, "Failed to register device.\n"); + err = PTR_ERR(data->hwmon_dev); + goto exit_remove_files; + } + + return 0; + +exit_remove_files: + dme1737_remove_files(dev); +exit_kfree: + platform_set_drvdata(pdev, NULL); + kfree(data); +exit_release_region: + release_region(res->start, DME1737_EXTENT); +exit: + return err; +} + +static int __devexit dme1737_isa_remove(struct platform_device *pdev) +{ + struct dme1737_data *data = platform_get_drvdata(pdev); + + hwmon_device_unregister(data->hwmon_dev); + dme1737_remove_files(&pdev->dev); + release_region(data->client.addr, DME1737_EXTENT); + platform_set_drvdata(pdev, NULL); kfree(data); + return 0; } -static struct i2c_driver dme1737_driver = { +static struct platform_driver dme1737_isa_driver = { .driver = { + .owner = THIS_MODULE, .name = "dme1737", }, - .attach_adapter = dme1737_attach_adapter, - .detach_client = dme1737_detach_client, + .probe = dme1737_isa_probe, + .remove = __devexit_p(dme1737_isa_remove), }; +/* --------------------------------------------------------------------- + * Module initialization and cleanup + * --------------------------------------------------------------------- */ + static int __init dme1737_init(void) { - return i2c_add_driver(&dme1737_driver); + int err; + unsigned short addr; + + if ((err = i2c_add_driver(&dme1737_i2c_driver))) { + goto exit; + } + + if (dme1737_isa_detect(0x2e, &addr) && + dme1737_isa_detect(0x4e, &addr)) { + /* Return 0 if we didn't find an ISA device */ + return 0; + } + + if ((err = platform_driver_register(&dme1737_isa_driver))) { + goto exit_del_i2c_driver; + } + + /* Sets global pdev as a side effect */ + if ((err = dme1737_isa_device_add(addr))) { + goto exit_del_isa_driver; + } + + return 0; + +exit_del_isa_driver: + platform_driver_unregister(&dme1737_isa_driver); +exit_del_i2c_driver: + i2c_del_driver(&dme1737_i2c_driver); +exit: + return err; } static void __exit dme1737_exit(void) { - i2c_del_driver(&dme1737_driver); + if (pdev) { + platform_device_unregister(pdev); + platform_driver_unregister(&dme1737_isa_driver); + } + + i2c_del_driver(&dme1737_i2c_driver); } MODULE_AUTHOR("Juerg Haefliger <juergh@gmail.com>"); diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c index 1212d6b7f316..b7bd000b130f 100644 --- a/drivers/hwmon/ds1621.c +++ b/drivers/hwmon/ds1621.c @@ -73,7 +73,7 @@ static const u8 DS1621_REG_TEMP[3] = { /* Each client has this additional data */ struct ds1621_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ @@ -151,7 +151,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da, struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct i2c_client *client = to_i2c_client(dev); struct ds1621_data *data = ds1621_update_client(dev); - u16 val = LM75_TEMP_TO_REG(simple_strtoul(buf, NULL, 10)); + u16 val = LM75_TEMP_TO_REG(simple_strtol(buf, NULL, 10)); mutex_lock(&data->update_lock); data->temp[attr->index] = val; @@ -266,9 +266,9 @@ static int ds1621_detect(struct i2c_adapter *adapter, int address, if ((err = sysfs_create_group(&client->dev.kobj, &ds1621_group))) goto exit_detach; - data->class_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -289,7 +289,7 @@ static int ds1621_detach_client(struct i2c_client *client) struct ds1621_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &ds1621_group); if ((err = i2c_detach_client(client))) diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c index 6f60715f34f8..5d9d5cc816a2 100644 --- a/drivers/hwmon/f71805f.c +++ b/drivers/hwmon/f71805f.c @@ -10,6 +10,9 @@ * The F71872F/FG is almost the same, with two more voltages monitored, * and 6 VID inputs. * + * The F71806F/FG is essentially the same as the F71872F/FG. It even has + * the same chip ID, so the driver can't differentiate between. + * * 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 @@ -159,7 +162,7 @@ struct f71805f_auto_point { struct f71805f_data { unsigned short addr; const char *name; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* !=0 if following fields are valid */ @@ -1378,9 +1381,9 @@ static int __devinit f71805f_probe(struct platform_device *pdev) } } - data->class_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); dev_err(&pdev->dev, "Class registration failed (%d)\n", err); goto exit_remove_files; } @@ -1407,7 +1410,7 @@ static int __devexit f71805f_remove(struct platform_device *pdev) struct resource *res; int i; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&pdev->dev.kobj, &f71805f_group); for (i = 0; i < 4; i++) sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_optin[i]); @@ -1485,7 +1488,7 @@ static int __init f71805f_find(int sioaddr, unsigned short *address, static const char *names[] = { "F71805F/FG", - "F71872F/FG", + "F71872F/FG or F71806F/FG", }; superio_enter(sioaddr); diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c new file mode 100644 index 000000000000..6db74434a02e --- /dev/null +++ b/drivers/hwmon/f71882fg.c @@ -0,0 +1,950 @@ +/*************************************************************************** + * Copyright (C) 2006 by Hans Edgington <hans@edgington.nl> * + * Copyright (C) 2007 by Hans de Goede <j.w.r.degoede@hhs.nl> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/jiffies.h> +#include <linux/platform_device.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/err.h> +#include <linux/mutex.h> +#include <asm/io.h> + +#define DRVNAME "f71882fg" + +#define SIO_F71882FG_LD_HWM 0x04 /* Hardware monitor logical device*/ +#define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */ +#define SIO_LOCK_KEY 0xAA /* Key to diasble Super-I/O */ + +#define SIO_REG_LDSEL 0x07 /* Logical device select */ +#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ +#define SIO_REG_DEVREV 0x22 /* Device revision */ +#define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */ +#define SIO_REG_ENABLE 0x30 /* Logical device enable */ +#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ + +#define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */ +#define SIO_F71882_ID 0x0541 /* Chipset ID */ + +#define REGION_LENGTH 8 +#define ADDR_REG_OFFSET 5 +#define DATA_REG_OFFSET 6 + +#define F71882FG_REG_PECI 0x0A + +#define F71882FG_REG_IN_STATUS 0x12 +#define F71882FG_REG_IN_BEEP 0x13 +#define F71882FG_REG_IN(nr) (0x20 + (nr)) +#define F71882FG_REG_IN1_HIGH 0x32 + +#define F71882FG_REG_FAN(nr) (0xA0 + (16 * (nr))) +#define F71882FG_REG_FAN_STATUS 0x92 +#define F71882FG_REG_FAN_BEEP 0x93 + +#define F71882FG_REG_TEMP(nr) (0x72 + 2 * (nr)) +#define F71882FG_REG_TEMP_OVT(nr) (0x82 + 2 * (nr)) +#define F71882FG_REG_TEMP_HIGH(nr) (0x83 + 2 * (nr)) +#define F71882FG_REG_TEMP_STATUS 0x62 +#define F71882FG_REG_TEMP_BEEP 0x63 +#define F71882FG_REG_TEMP_HYST1 0x6C +#define F71882FG_REG_TEMP_HYST23 0x6D +#define F71882FG_REG_TEMP_TYPE 0x6B +#define F71882FG_REG_TEMP_DIODE_OPEN 0x6F + +#define F71882FG_REG_START 0x01 + +#define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */ + +static struct platform_device *f71882fg_pdev = NULL; + +/* Super-I/O Function prototypes */ +static inline int superio_inb(int base, int reg); +static inline int superio_inw(int base, int reg); +static inline void superio_enter(int base); +static inline void superio_select(int base, int ld); +static inline void superio_exit(int base); + +static inline u16 fan_from_reg ( u16 reg ); + +struct f71882fg_data { + unsigned short addr; + struct device *hwmon_dev; + + struct mutex update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + unsigned long last_limits; /* In jiffies */ + + /* Register Values */ + u8 in[9]; + u8 in1_max; + u8 in_status; + u8 in_beep; + u16 fan[4]; + u8 fan_status; + u8 fan_beep; + u8 temp[3]; + u8 temp_ovt[3]; + u8 temp_high[3]; + u8 temp_hyst[3]; + u8 temp_type[3]; + u8 temp_status; + u8 temp_beep; + u8 temp_diode_open; +}; + +static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg); +static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg); +static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val); + +/* Sysfs in*/ +static ssize_t show_in(struct device *dev, struct device_attribute *devattr, + char *buf); +static ssize_t show_in_max(struct device *dev, struct device_attribute + *devattr, char *buf); +static ssize_t store_in_max(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count); +static ssize_t show_in_beep(struct device *dev, struct device_attribute + *devattr, char *buf); +static ssize_t store_in_beep(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count); +static ssize_t show_in_alarm(struct device *dev, struct device_attribute + *devattr, char *buf); +/* Sysfs Fan */ +static ssize_t show_fan(struct device *dev, struct device_attribute *devattr, + char *buf); +static ssize_t show_fan_beep(struct device *dev, struct device_attribute + *devattr, char *buf); +static ssize_t store_fan_beep(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count); +static ssize_t show_fan_alarm(struct device *dev, struct device_attribute + *devattr, char *buf); +/* Sysfs Temp */ +static ssize_t show_temp(struct device *dev, struct device_attribute + *devattr, char *buf); +static ssize_t show_temp_max(struct device *dev, struct device_attribute + *devattr, char *buf); +static ssize_t store_temp_max(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count); +static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute + *devattr, char *buf); +static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count); +static ssize_t show_temp_crit(struct device *dev, struct device_attribute + *devattr, char *buf); +static ssize_t store_temp_crit(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count); +static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute + *devattr, char *buf); +static ssize_t show_temp_type(struct device *dev, struct device_attribute + *devattr, char *buf); +static ssize_t show_temp_beep(struct device *dev, struct device_attribute + *devattr, char *buf); +static ssize_t store_temp_beep(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count); +static ssize_t show_temp_alarm(struct device *dev, struct device_attribute + *devattr, char *buf); +static ssize_t show_temp_fault(struct device *dev, struct device_attribute + *devattr, char *buf); +/* Sysfs misc */ +static ssize_t show_name(struct device *dev, struct device_attribute *devattr, + char *buf); + +static int __devinit f71882fg_probe(struct platform_device * pdev); +static int __devexit f71882fg_remove(struct platform_device *pdev); +static int __init f71882fg_init(void); +static int __init f71882fg_find(int sioaddr, unsigned short *address); +static int __init f71882fg_device_add(unsigned short address); +static void __exit f71882fg_exit(void); + +static struct platform_driver f71882fg_driver = { + .driver = { + .owner = THIS_MODULE, + .name = DRVNAME, + }, + .probe = f71882fg_probe, + .remove = __devexit_p(f71882fg_remove), +}; + +static struct device_attribute f71882fg_dev_attr[] = +{ + __ATTR( name, S_IRUGO, show_name, NULL ), +}; + +static struct sensor_device_attribute f71882fg_in_temp_attr[] = +{ + SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0), + SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1), + SENSOR_ATTR(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max, 1), + SENSOR_ATTR(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep, 1), + SENSOR_ATTR(in1_alarm, S_IRUGO, show_in_alarm, NULL, 1), + SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2), + SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3), + SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4), + SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5), + SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6), + SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7), + SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8), + SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0), + SENSOR_ATTR(temp1_max, S_IRUGO|S_IWUSR, show_temp_max, + store_temp_max, 0), + SENSOR_ATTR(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst, + store_temp_max_hyst, 0), + SENSOR_ATTR(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit, + store_temp_crit, 0), + SENSOR_ATTR(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 0), + SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0), + SENSOR_ATTR(temp1_beep, S_IRUGO|S_IWUSR, show_temp_beep, + store_temp_beep, 0), + SENSOR_ATTR(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0), + SENSOR_ATTR(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0), + SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1), + SENSOR_ATTR(temp2_max, S_IRUGO|S_IWUSR, show_temp_max, + store_temp_max, 1), + SENSOR_ATTR(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst, + store_temp_max_hyst, 1), + SENSOR_ATTR(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit, + store_temp_crit, 1), + SENSOR_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 1), + SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1), + SENSOR_ATTR(temp2_beep, S_IRUGO|S_IWUSR, show_temp_beep, + store_temp_beep, 1), + SENSOR_ATTR(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 1), + SENSOR_ATTR(temp2_fault, S_IRUGO, show_temp_fault, NULL, 1), + SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2), + SENSOR_ATTR(temp3_max, S_IRUGO|S_IWUSR, show_temp_max, + store_temp_max, 2), + SENSOR_ATTR(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst, + store_temp_max_hyst, 2), + SENSOR_ATTR(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit, + store_temp_crit, 2), + SENSOR_ATTR(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 2), + SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2), + SENSOR_ATTR(temp3_beep, S_IRUGO|S_IWUSR, show_temp_beep, + store_temp_beep, 2), + SENSOR_ATTR(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 2), + SENSOR_ATTR(temp3_fault, S_IRUGO, show_temp_fault, NULL, 2) +}; + +static struct sensor_device_attribute f71882fg_fan_attr[] = +{ + SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0), + SENSOR_ATTR(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep, + store_fan_beep, 0), + SENSOR_ATTR(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0), + SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1), + SENSOR_ATTR(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep, + store_fan_beep, 1), + SENSOR_ATTR(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 1), + SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2), + SENSOR_ATTR(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep, + store_fan_beep, 2), + SENSOR_ATTR(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 2), + SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3), + SENSOR_ATTR(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep, + store_fan_beep, 3), + SENSOR_ATTR(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 3) +}; + + +/* Super I/O functions */ +static inline int superio_inb(int base, int reg) +{ + outb(reg, base); + return inb(base + 1); +} + +static int superio_inw(int base, int reg) +{ + int val; + outb(reg++, base); + val = inb(base + 1) << 8; + outb(reg, base); + val |= inb(base + 1); + return val; +} + +static inline void superio_enter(int base) +{ + /* according to the datasheet the key must be send twice! */ + outb( SIO_UNLOCK_KEY, base); + outb( SIO_UNLOCK_KEY, base); +} + +static inline void superio_select( int base, int ld) +{ + outb(SIO_REG_LDSEL, base); + outb(ld, base + 1); +} + +static inline void superio_exit(int base) +{ + outb(SIO_LOCK_KEY, base); +} + +static inline u16 fan_from_reg(u16 reg) +{ + return reg ? (1500000 / reg) : 0; +} + +static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg) +{ + u8 val; + + outb(reg, data->addr + ADDR_REG_OFFSET); + val = inb(data->addr + DATA_REG_OFFSET); + + return val; +} + +static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg) +{ + u16 val; + + outb(reg++, data->addr + ADDR_REG_OFFSET); + val = inb(data->addr + DATA_REG_OFFSET) << 8; + outb(reg, data->addr + ADDR_REG_OFFSET); + val |= inb(data->addr + DATA_REG_OFFSET); + + return val; +} + +static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val) +{ + outb(reg, data->addr + ADDR_REG_OFFSET); + outb(val, data->addr + DATA_REG_OFFSET); +} + +static struct f71882fg_data *f71882fg_update_device(struct device * dev) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int nr, reg, reg2; + + mutex_lock(&data->update_lock); + + /* Update once every 60 seconds */ + if ( time_after(jiffies, data->last_limits + 60 * HZ ) || + !data->valid) { + data->in1_max = f71882fg_read8(data, F71882FG_REG_IN1_HIGH); + data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP); + + /* Get High & boundary temps*/ + for (nr = 0; nr < 3; nr++) { + data->temp_ovt[nr] = f71882fg_read8(data, + F71882FG_REG_TEMP_OVT(nr)); + data->temp_high[nr] = f71882fg_read8(data, + F71882FG_REG_TEMP_HIGH(nr)); + } + + /* Have to hardcode hyst*/ + data->temp_hyst[0] = f71882fg_read8(data, + F71882FG_REG_TEMP_HYST1) >> 4; + /* Hyst temps 2 & 3 stored in same register */ + reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST23); + data->temp_hyst[1] = reg & 0x0F; + data->temp_hyst[2] = reg >> 4; + + /* Have to hardcode type, because temp1 is special */ + reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE); + reg2 = f71882fg_read8(data, F71882FG_REG_PECI); + if ((reg2 & 0x03) == 0x01) + data->temp_type[0] = 6 /* PECI */; + else if ((reg2 & 0x03) == 0x02) + data->temp_type[0] = 5 /* AMDSI */; + else + data->temp_type[0] = (reg & 0x02) ? 2 : 4; + + data->temp_type[1] = (reg & 0x04) ? 2 : 4; + data->temp_type[2] = (reg & 0x08) ? 2 : 4; + + data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP); + + data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP); + + data->last_limits = jiffies; + } + + /* Update every second */ + if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { + data->temp_status = f71882fg_read8(data, + F71882FG_REG_TEMP_STATUS); + data->temp_diode_open = f71882fg_read8(data, + F71882FG_REG_TEMP_DIODE_OPEN); + for (nr = 0; nr < 3; nr++) + data->temp[nr] = f71882fg_read8(data, + F71882FG_REG_TEMP(nr)); + + data->fan_status = f71882fg_read8(data, + F71882FG_REG_FAN_STATUS); + for (nr = 0; nr < 4; nr++) + data->fan[nr] = f71882fg_read16(data, + F71882FG_REG_FAN(nr)); + + data->in_status = f71882fg_read8(data, + F71882FG_REG_IN_STATUS); + for (nr = 0; nr < 9; nr++) + data->in[nr] = f71882fg_read8(data, + F71882FG_REG_IN(nr)); + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + +/* Sysfs Interface */ +static ssize_t show_fan(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr(devattr)->index; + int speed = fan_from_reg(data->fan[nr]); + + if (speed == FAN_MIN_DETECT) + speed = 0; + + return sprintf(buf, "%d\n", speed); +} + +static ssize_t show_fan_beep(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr(devattr)->index; + + if (data->fan_beep & (1 << nr)) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + +static ssize_t store_fan_beep(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int nr = to_sensor_dev_attr(devattr)->index; + int val = simple_strtoul(buf, NULL, 10); + + mutex_lock(&data->update_lock); + if (val) + data->fan_beep |= 1 << nr; + else + data->fan_beep &= ~(1 << nr); + + f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep); + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_fan_alarm(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr(devattr)->index; + + if (data->fan_status & (1 << nr)) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + +static ssize_t show_in(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr(devattr)->index; + + return sprintf(buf, "%d\n", data->in[nr] * 8); +} + +static ssize_t show_in_max(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + + return sprintf(buf, "%d\n", data->in1_max * 8); +} + +static ssize_t store_in_max(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int val = simple_strtoul(buf, NULL, 10) / 8; + + if (val > 255) + val = 255; + + mutex_lock(&data->update_lock); + f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val); + data->in1_max = val; + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_in_beep(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr(devattr)->index; + + if (data->in_beep & (1 << nr)) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + +static ssize_t store_in_beep(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int nr = to_sensor_dev_attr(devattr)->index; + int val = simple_strtoul(buf, NULL, 10); + + mutex_lock(&data->update_lock); + if (val) + data->in_beep |= 1 << nr; + else + data->in_beep &= ~(1 << nr); + + f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep); + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_in_alarm(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr(devattr)->index; + + if (data->in_status & (1 << nr)) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr(devattr)->index; + + return sprintf(buf, "%d\n", data->temp[nr] * 1000); +} + +static ssize_t show_temp_max(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr(devattr)->index; + + return sprintf(buf, "%d\n", data->temp_high[nr] * 1000); +} + +static ssize_t store_temp_max(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int nr = to_sensor_dev_attr(devattr)->index; + int val = simple_strtoul(buf, NULL, 10) / 1000; + + if (val > 255) + val = 255; + + mutex_lock(&data->update_lock); + f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val); + data->temp_high[nr] = val; + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr(devattr)->index; + + return sprintf(buf, "%d\n", + (data->temp_high[nr] - data->temp_hyst[nr]) * 1000); +} + +static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int nr = to_sensor_dev_attr(devattr)->index; + int val = simple_strtoul(buf, NULL, 10) / 1000; + ssize_t ret = count; + + mutex_lock(&data->update_lock); + + /* convert abs to relative and check */ + val = data->temp_high[nr] - val; + if (val < 0 || val > 15) { + ret = -EINVAL; + goto store_temp_max_hyst_exit; + } + + data->temp_hyst[nr] = val; + + /* convert value to register contents */ + switch (nr) { + case 0: + val = val << 4; + break; + case 1: + val = val | (data->temp_hyst[2] << 4); + break; + case 2: + val = data->temp_hyst[1] | (val << 4); + break; + } + + f71882fg_write8(data, nr ? F71882FG_REG_TEMP_HYST23 : + F71882FG_REG_TEMP_HYST1, val); + +store_temp_max_hyst_exit: + mutex_unlock(&data->update_lock); + return ret; +} + +static ssize_t show_temp_crit(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr(devattr)->index; + + return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000); +} + +static ssize_t store_temp_crit(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int nr = to_sensor_dev_attr(devattr)->index; + int val = simple_strtoul(buf, NULL, 10) / 1000; + + if (val > 255) + val = 255; + + mutex_lock(&data->update_lock); + f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val); + data->temp_ovt[nr] = val; + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr(devattr)->index; + + return sprintf(buf, "%d\n", + (data->temp_ovt[nr] - data->temp_hyst[nr]) * 1000); +} + +static ssize_t show_temp_type(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr(devattr)->index; + + return sprintf(buf, "%d\n", data->temp_type[nr]); +} + +static ssize_t show_temp_beep(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr(devattr)->index; + + if (data->temp_beep & (1 << (nr + 1))) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + +static ssize_t store_temp_beep(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int nr = to_sensor_dev_attr(devattr)->index; + int val = simple_strtoul(buf, NULL, 10); + + mutex_lock(&data->update_lock); + if (val) + data->temp_beep |= 1 << (nr + 1); + else + data->temp_beep &= ~(1 << (nr + 1)); + + f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep); + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_temp_alarm(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr(devattr)->index; + + if (data->temp_status & (1 << (nr + 1))) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + +static ssize_t show_temp_fault(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr(devattr)->index; + + if (data->temp_diode_open & (1 << (nr + 1))) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + +static ssize_t show_name(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + return sprintf(buf, DRVNAME "\n"); +} + + +static int __devinit f71882fg_probe(struct platform_device * pdev) +{ + struct f71882fg_data *data; + int err, i; + u8 start_reg; + + if (!(data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL))) + return -ENOMEM; + + data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start; + mutex_init(&data->update_lock); + platform_set_drvdata(pdev, data); + + /* Register sysfs interface files */ + for (i = 0; i < ARRAY_SIZE(f71882fg_dev_attr); i++) { + err = device_create_file(&pdev->dev, &f71882fg_dev_attr[i]); + if (err) + goto exit_unregister_sysfs; + } + + start_reg = f71882fg_read8(data, F71882FG_REG_START); + if (start_reg & 0x01) { + for (i = 0; i < ARRAY_SIZE(f71882fg_in_temp_attr); i++) { + err = device_create_file(&pdev->dev, + &f71882fg_in_temp_attr[i].dev_attr); + if (err) + goto exit_unregister_sysfs; + } + } + + if (start_reg & 0x02) { + for (i = 0; i < ARRAY_SIZE(f71882fg_fan_attr); i++) { + err = device_create_file(&pdev->dev, + &f71882fg_fan_attr[i].dev_attr); + if (err) + goto exit_unregister_sysfs; + } + } + + data->hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); + goto exit_unregister_sysfs; + } + + return 0; + +exit_unregister_sysfs: + for (i = 0; i < ARRAY_SIZE(f71882fg_dev_attr); i++) + device_remove_file(&pdev->dev, &f71882fg_dev_attr[i]); + + for (i = 0; i < ARRAY_SIZE(f71882fg_in_temp_attr); i++) + device_remove_file(&pdev->dev, + &f71882fg_in_temp_attr[i].dev_attr); + + for (i = 0; i < ARRAY_SIZE(f71882fg_fan_attr); i++) + device_remove_file(&pdev->dev, &f71882fg_fan_attr[i].dev_attr); + + kfree(data); + + return err; +} + +static int __devexit f71882fg_remove(struct platform_device *pdev) +{ + int i; + struct f71882fg_data *data = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + hwmon_device_unregister(data->hwmon_dev); + + for (i = 0; i < ARRAY_SIZE(f71882fg_dev_attr); i++) + device_remove_file(&pdev->dev, &f71882fg_dev_attr[i]); + + for (i = 0; i < ARRAY_SIZE(f71882fg_in_temp_attr); i++) + device_remove_file(&pdev->dev, + &f71882fg_in_temp_attr[i].dev_attr); + + for (i = 0; i < ARRAY_SIZE(f71882fg_fan_attr); i++) + device_remove_file(&pdev->dev, &f71882fg_fan_attr[i].dev_attr); + + kfree(data); + + return 0; +} + +static int __init f71882fg_find(int sioaddr, unsigned short *address) +{ + int err = -ENODEV; + u16 devid; + u8 start_reg; + struct f71882fg_data data; + + superio_enter(sioaddr); + + devid = superio_inw(sioaddr, SIO_REG_MANID); + if (devid != SIO_FINTEK_ID) { + printk(KERN_INFO DRVNAME ": Not a Fintek device\n"); + goto exit; + } + + devid = superio_inw(sioaddr, SIO_REG_DEVID); + if (devid != SIO_F71882_ID) { + printk(KERN_INFO DRVNAME ": Unsupported Fintek device\n"); + goto exit; + } + + superio_select(sioaddr, SIO_F71882FG_LD_HWM); + if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) { + printk(KERN_WARNING DRVNAME ": Device not activated\n"); + goto exit; + } + + *address = superio_inw(sioaddr, SIO_REG_ADDR); + if (*address == 0) + { + printk(KERN_WARNING DRVNAME ": Base address not set\n"); + goto exit; + } + *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */ + + data.addr = *address; + start_reg = f71882fg_read8(&data, F71882FG_REG_START); + if (!(start_reg & 0x03)) { + printk(KERN_WARNING DRVNAME + ": Hardware monitoring not activated\n"); + goto exit; + } + + err = 0; + printk(KERN_INFO DRVNAME ": Found F71882FG chip at %#x, revision %d\n", + (unsigned int)*address, + (int)superio_inb(sioaddr, SIO_REG_DEVREV)); +exit: + superio_exit(sioaddr); + return err; +} + +static int __init f71882fg_device_add(unsigned short address) +{ + struct resource res = { + .start = address, + .end = address + REGION_LENGTH - 1, + .flags = IORESOURCE_IO, + }; + int err; + + f71882fg_pdev = platform_device_alloc(DRVNAME, address); + if (!f71882fg_pdev) + return -ENOMEM; + + res.name = f71882fg_pdev->name; + err = platform_device_add_resources(f71882fg_pdev, &res, 1); + if (err) { + printk(KERN_ERR DRVNAME ": Device resource addition failed\n"); + goto exit_device_put; + } + + err = platform_device_add(f71882fg_pdev); + if (err) { + printk(KERN_ERR DRVNAME ": Device addition failed\n"); + goto exit_device_put; + } + + return 0; + +exit_device_put: + platform_device_put(f71882fg_pdev); + + return err; +} + +static int __init f71882fg_init(void) +{ + int err = -ENODEV; + unsigned short address; + + if (f71882fg_find(0x2e, &address) && f71882fg_find(0x4e, &address)) + goto exit; + + if ((err = platform_driver_register(&f71882fg_driver))) + goto exit; + + if ((err = f71882fg_device_add(address))) + goto exit_driver; + + return 0; + +exit_driver: + platform_driver_unregister(&f71882fg_driver); +exit: + return err; +} + +static void __exit f71882fg_exit(void) +{ + platform_device_unregister(f71882fg_pdev); + platform_driver_unregister(&f71882fg_driver); +} + +MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver"); +MODULE_AUTHOR("Hans Edgington (hans@edgington.nl)"); +MODULE_LICENSE("GPL"); + +module_init(f71882fg_init); +module_exit(f71882fg_exit); diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c new file mode 100644 index 000000000000..13a041326a04 --- /dev/null +++ b/drivers/hwmon/f75375s.c @@ -0,0 +1,691 @@ +/* + * f75375s.c - driver for the Fintek F75375/SP and F75373 + * hardware monitoring features + * Copyright (C) 2006-2007 Riku Voipio <riku.voipio@movial.fi> + * + * Datasheets available at: + * + * f75375: + * http://www.fintek.com.tw/files/productfiles/2005111152950.pdf + * + * f75373: + * http://www.fintek.com.tw/files/productfiles/2005111153128.pdf + * + * 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. + * + */ + +#include <linux/module.h> +#include <linux/jiffies.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/i2c.h> +#include <linux/err.h> +#include <linux/mutex.h> + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x2d, 0x2e, I2C_CLIENT_END }; + +/* Insmod parameters */ +I2C_CLIENT_INSMOD_2(f75373, f75375); + +/* Fintek F75375 registers */ +#define F75375_REG_CONFIG0 0x0 +#define F75375_REG_CONFIG1 0x1 +#define F75375_REG_CONFIG2 0x2 +#define F75375_REG_CONFIG3 0x3 +#define F75375_REG_ADDR 0x4 +#define F75375_REG_INTR 0x31 +#define F75375_CHIP_ID 0x5A +#define F75375_REG_VERSION 0x5C +#define F75375_REG_VENDOR 0x5D +#define F75375_REG_FAN_TIMER 0x60 + +#define F75375_REG_VOLT(nr) (0x10 + (nr)) +#define F75375_REG_VOLT_HIGH(nr) (0x20 + (nr) * 2) +#define F75375_REG_VOLT_LOW(nr) (0x21 + (nr) * 2) + +#define F75375_REG_TEMP(nr) (0x14 + (nr)) +#define F75375_REG_TEMP_HIGH(nr) (0x28 + (nr) * 2) +#define F75375_REG_TEMP_HYST(nr) (0x29 + (nr) * 2) + +#define F75375_REG_FAN(nr) (0x16 + (nr) * 2) +#define F75375_REG_FAN_MIN(nr) (0x2C + (nr) * 2) +#define F75375_REG_FAN_FULL(nr) (0x70 + (nr) * 0x10) +#define F75375_REG_FAN_PWM_DUTY(nr) (0x76 + (nr) * 0x10) +#define F75375_REG_FAN_PWM_CLOCK(nr) (0x7D + (nr) * 0x10) + +#define F75375_REG_FAN_EXP(nr) (0x74 + (nr) * 0x10) +#define F75375_REG_FAN_B_TEMP(nr, step) ((0xA0 + (nr) * 0x10) + (step)) +#define F75375_REG_FAN_B_SPEED(nr, step) \ + ((0xA5 + (nr) * 0x10) + (step) * 2) + +#define F75375_REG_PWM1_RAISE_DUTY 0x69 +#define F75375_REG_PWM2_RAISE_DUTY 0x6A +#define F75375_REG_PWM1_DROP_DUTY 0x6B +#define F75375_REG_PWM2_DROP_DUTY 0x6C + +#define FAN_CTRL_LINEAR(nr) (4 + nr) +#define FAN_CTRL_MODE(nr) (5 + ((nr) * 2)) + +/* + * Data structures and manipulation thereof + */ + +struct f75375_data { + unsigned short addr; + struct i2c_client client; + struct device *hwmon_dev; + + const char *name; + int kind; + struct mutex update_lock; /* protect register access */ + char valid; + unsigned long last_updated; /* In jiffies */ + unsigned long last_limits; /* In jiffies */ + + /* Register values */ + u8 in[4]; + u8 in_max[4]; + u8 in_min[4]; + u16 fan[2]; + u16 fan_min[2]; + u16 fan_full[2]; + u16 fan_exp[2]; + u8 fan_timer; + u8 pwm[2]; + u8 pwm_mode[2]; + u8 pwm_enable[2]; + s8 temp[2]; + s8 temp_high[2]; + s8 temp_max_hyst[2]; +}; + +static int f75375_attach_adapter(struct i2c_adapter *adapter); +static int f75375_detect(struct i2c_adapter *adapter, int address, int kind); +static int f75375_detach_client(struct i2c_client *client); + +static struct i2c_driver f75375_driver = { + .driver = { + .name = "f75375", + }, + .attach_adapter = f75375_attach_adapter, + .detach_client = f75375_detach_client, +}; + +static inline int f75375_read8(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +/* in most cases, should be called while holding update_lock */ +static inline u16 f75375_read16(struct i2c_client *client, u8 reg) +{ + return ((i2c_smbus_read_byte_data(client, reg) << 8) + | i2c_smbus_read_byte_data(client, reg + 1)); +} + +static inline void f75375_write8(struct i2c_client *client, u8 reg, + u8 value) +{ + i2c_smbus_write_byte_data(client, reg, value); +} + +static inline void f75375_write16(struct i2c_client *client, u8 reg, + u16 value) +{ + int err = i2c_smbus_write_byte_data(client, reg, (value << 8)); + if (err) + return; + i2c_smbus_write_byte_data(client, reg + 1, (value & 0xFF)); +} + +static struct f75375_data *f75375_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct f75375_data *data = i2c_get_clientdata(client); + int nr; + + mutex_lock(&data->update_lock); + + /* Limit registers cache is refreshed after 60 seconds */ + if (time_after(jiffies, data->last_limits + 60 * HZ) + || !data->valid) { + for (nr = 0; nr < 2; nr++) { + data->temp_high[nr] = + f75375_read8(client, F75375_REG_TEMP_HIGH(nr)); + data->temp_max_hyst[nr] = + f75375_read8(client, F75375_REG_TEMP_HYST(nr)); + data->fan_full[nr] = + f75375_read16(client, F75375_REG_FAN_FULL(nr)); + data->fan_min[nr] = + f75375_read16(client, F75375_REG_FAN_MIN(nr)); + data->fan_exp[nr] = + f75375_read16(client, F75375_REG_FAN_EXP(nr)); + data->pwm[nr] = f75375_read8(client, + F75375_REG_FAN_PWM_DUTY(nr)); + + } + for (nr = 0; nr < 4; nr++) { + data->in_max[nr] = + f75375_read8(client, F75375_REG_VOLT_HIGH(nr)); + data->in_min[nr] = + f75375_read8(client, F75375_REG_VOLT_LOW(nr)); + } + data->fan_timer = f75375_read8(client, F75375_REG_FAN_TIMER); + data->last_limits = jiffies; + } + + /* Measurement registers cache is refreshed after 2 second */ + if (time_after(jiffies, data->last_updated + 2 * HZ) + || !data->valid) { + for (nr = 0; nr < 2; nr++) { + data->temp[nr] = + f75375_read8(client, F75375_REG_TEMP(nr)); + data->fan[nr] = + f75375_read16(client, F75375_REG_FAN(nr)); + } + for (nr = 0; nr < 4; nr++) + data->in[nr] = + f75375_read8(client, F75375_REG_VOLT(nr)); + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + return data; +} + +static inline u16 rpm_from_reg(u16 reg) +{ + if (reg == 0 || reg == 0xffff) + return 0; + return (1500000 / reg); +} + +static inline u16 rpm_to_reg(int rpm) +{ + if (rpm < 367 || rpm > 0xffff) + return 0xffff; + return (1500000 / rpm); +} + +static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct f75375_data *data = i2c_get_clientdata(client); + int val = simple_strtoul(buf, NULL, 10); + + mutex_lock(&data->update_lock); + data->fan_min[nr] = rpm_to_reg(val); + f75375_write16(client, F75375_REG_FAN_MIN(nr), data->fan_min[nr]); + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t set_fan_exp(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct f75375_data *data = i2c_get_clientdata(client); + int val = simple_strtoul(buf, NULL, 10); + + mutex_lock(&data->update_lock); + data->fan_exp[nr] = rpm_to_reg(val); + f75375_write16(client, F75375_REG_FAN_EXP(nr), data->fan_exp[nr]); + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct f75375_data *data = i2c_get_clientdata(client); + int val = simple_strtoul(buf, NULL, 10); + + mutex_lock(&data->update_lock); + data->pwm[nr] = SENSORS_LIMIT(val, 0, 255); + f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr), data->pwm[nr]); + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t show_pwm_enable(struct device *dev, struct device_attribute + *attr, char *buf) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct f75375_data *data = f75375_update_device(dev); + return sprintf(buf, "%d\n", data->pwm_enable[nr]); +} + +static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct f75375_data *data = i2c_get_clientdata(client); + int val = simple_strtoul(buf, NULL, 10); + u8 fanmode; + + if (val < 0 || val > 4) + return -EINVAL; + + mutex_lock(&data->update_lock); + fanmode = f75375_read8(client, F75375_REG_FAN_TIMER); + fanmode = ~(3 << FAN_CTRL_MODE(nr)); + + switch (val) { + case 0: /* Full speed */ + fanmode |= (3 << FAN_CTRL_MODE(nr)); + data->pwm[nr] = 255; + f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr), + data->pwm[nr]); + break; + case 1: /* PWM */ + fanmode |= (3 << FAN_CTRL_MODE(nr)); + break; + case 2: /* AUTOMATIC*/ + fanmode |= (2 << FAN_CTRL_MODE(nr)); + break; + case 3: /* fan speed */ + break; + } + f75375_write8(client, F75375_REG_FAN_TIMER, fanmode); + data->pwm_enable[nr] = val; + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t set_pwm_mode(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct f75375_data *data = i2c_get_clientdata(client); + int val = simple_strtoul(buf, NULL, 10); + u8 conf = 0; + + if (val != 0 || val != 1 || data->kind == f75373) + return -EINVAL; + + mutex_lock(&data->update_lock); + conf = f75375_read8(client, F75375_REG_CONFIG1); + conf = ~(1 << FAN_CTRL_LINEAR(nr)); + + if (val == 0) + conf |= (1 << FAN_CTRL_LINEAR(nr)) ; + + f75375_write8(client, F75375_REG_CONFIG1, conf); + data->pwm_mode[nr] = val; + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t show_pwm(struct device *dev, struct device_attribute + *attr, char *buf) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct f75375_data *data = f75375_update_device(dev); + return sprintf(buf, "%d\n", data->pwm[nr]); +} + +static ssize_t show_pwm_mode(struct device *dev, struct device_attribute + *attr, char *buf) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct f75375_data *data = f75375_update_device(dev); + return sprintf(buf, "%d\n", data->pwm_mode[nr]); +} + +#define VOLT_FROM_REG(val) ((val) * 8) +#define VOLT_TO_REG(val) ((val) / 8) + +static ssize_t show_in(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct f75375_data *data = f75375_update_device(dev); + return sprintf(buf, "%d\n", VOLT_FROM_REG(data->in[nr])); +} + +static ssize_t show_in_max(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct f75375_data *data = f75375_update_device(dev); + return sprintf(buf, "%d\n", VOLT_FROM_REG(data->in_max[nr])); +} + +static ssize_t show_in_min(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct f75375_data *data = f75375_update_device(dev); + return sprintf(buf, "%d\n", VOLT_FROM_REG(data->in_min[nr])); +} + +static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct f75375_data *data = i2c_get_clientdata(client); + int val = simple_strtoul(buf, NULL, 10); + val = SENSORS_LIMIT(VOLT_TO_REG(val), 0, 0xff); + mutex_lock(&data->update_lock); + data->in_max[nr] = val; + f75375_write8(client, F75375_REG_VOLT_HIGH(nr), data->in_max[nr]); + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct f75375_data *data = i2c_get_clientdata(client); + int val = simple_strtoul(buf, NULL, 10); + val = SENSORS_LIMIT(VOLT_TO_REG(val), 0, 0xff); + mutex_lock(&data->update_lock); + data->in_min[nr] = val; + f75375_write8(client, F75375_REG_VOLT_LOW(nr), data->in_min[nr]); + mutex_unlock(&data->update_lock); + return count; +} +#define TEMP_FROM_REG(val) ((val) * 1000) +#define TEMP_TO_REG(val) ((val) / 1000) + +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct f75375_data *data = f75375_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr])); +} + +static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct f75375_data *data = f75375_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr])); +} + +static ssize_t show_temp_max_hyst(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct f75375_data *data = f75375_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max_hyst[nr])); +} + +static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct f75375_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + val = SENSORS_LIMIT(TEMP_TO_REG(val), 0, 127); + mutex_lock(&data->update_lock); + data->temp_high[nr] = val; + f75375_write8(client, F75375_REG_TEMP_HIGH(nr), data->temp_high[nr]); + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t set_temp_max_hyst(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct f75375_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + val = SENSORS_LIMIT(TEMP_TO_REG(val), 0, 127); + mutex_lock(&data->update_lock); + data->temp_max_hyst[nr] = val; + f75375_write8(client, F75375_REG_TEMP_HYST(nr), + data->temp_max_hyst[nr]); + mutex_unlock(&data->update_lock); + return count; +} + +#define show_fan(thing) \ +static ssize_t show_##thing(struct device *dev, struct device_attribute *attr, \ + char *buf)\ +{\ + int nr = to_sensor_dev_attr(attr)->index;\ + struct f75375_data *data = f75375_update_device(dev); \ + return sprintf(buf, "%d\n", rpm_from_reg(data->thing[nr])); \ +} + +show_fan(fan); +show_fan(fan_min); +show_fan(fan_full); +show_fan(fan_exp); + +static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in, NULL, 0); +static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO|S_IWUSR, + show_in_max, set_in_max, 0); +static SENSOR_DEVICE_ATTR(in0_min, S_IRUGO|S_IWUSR, + show_in_min, set_in_min, 0); +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1); +static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO|S_IWUSR, + show_in_max, set_in_max, 1); +static SENSOR_DEVICE_ATTR(in1_min, S_IRUGO|S_IWUSR, + show_in_min, set_in_min, 1); +static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in, NULL, 2); +static SENSOR_DEVICE_ATTR(in2_max, S_IRUGO|S_IWUSR, + show_in_max, set_in_max, 2); +static SENSOR_DEVICE_ATTR(in2_min, S_IRUGO|S_IWUSR, + show_in_min, set_in_min, 2); +static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in, NULL, 3); +static SENSOR_DEVICE_ATTR(in3_max, S_IRUGO|S_IWUSR, + show_in_max, set_in_max, 3); +static SENSOR_DEVICE_ATTR(in3_min, S_IRUGO|S_IWUSR, + show_in_min, set_in_min, 3); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO|S_IWUSR, + show_temp_max_hyst, set_temp_max_hyst, 0); +static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO|S_IWUSR, + show_temp_max, set_temp_max, 0); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1); +static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO|S_IWUSR, + show_temp_max_hyst, set_temp_max_hyst, 1); +static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO|S_IWUSR, + show_temp_max, set_temp_max, 1); +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); +static SENSOR_DEVICE_ATTR(fan1_full, S_IRUGO, show_fan_full, NULL, 0); +static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO|S_IWUSR, + show_fan_min, set_fan_min, 0); +static SENSOR_DEVICE_ATTR(fan1_exp, S_IRUGO|S_IWUSR, + show_fan_exp, set_fan_exp, 0); +static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1); +static SENSOR_DEVICE_ATTR(fan2_full, S_IRUGO, show_fan_full, NULL, 1); +static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO|S_IWUSR, + show_fan_min, set_fan_min, 1); +static SENSOR_DEVICE_ATTR(fan2_exp, S_IRUGO|S_IWUSR, + show_fan_exp, set_fan_exp, 1); +static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO|S_IWUSR, + show_pwm, set_pwm, 0); +static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO|S_IWUSR, + show_pwm_enable, set_pwm_enable, 0); +static SENSOR_DEVICE_ATTR(pwm1_mode, S_IRUGO|S_IWUSR, + show_pwm_mode, set_pwm_mode, 0); +static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, + show_pwm, set_pwm, 1); +static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO|S_IWUSR, + show_pwm_enable, set_pwm_enable, 1); +static SENSOR_DEVICE_ATTR(pwm2_mode, S_IRUGO|S_IWUSR, + show_pwm_mode, set_pwm_mode, 1); + +static struct attribute *f75375_attributes[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp2_max_hyst.dev_attr.attr, + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan1_full.dev_attr.attr, + &sensor_dev_attr_fan1_min.dev_attr.attr, + &sensor_dev_attr_fan1_exp.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan2_full.dev_attr.attr, + &sensor_dev_attr_fan2_min.dev_attr.attr, + &sensor_dev_attr_fan2_exp.dev_attr.attr, + &sensor_dev_attr_pwm1.dev_attr.attr, + &sensor_dev_attr_pwm1_enable.dev_attr.attr, + &sensor_dev_attr_pwm1_mode.dev_attr.attr, + &sensor_dev_attr_pwm2.dev_attr.attr, + &sensor_dev_attr_pwm2_enable.dev_attr.attr, + &sensor_dev_attr_pwm2_mode.dev_attr.attr, + &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in0_max.dev_attr.attr, + &sensor_dev_attr_in0_min.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in1_max.dev_attr.attr, + &sensor_dev_attr_in1_min.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in2_max.dev_attr.attr, + &sensor_dev_attr_in2_min.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in3_max.dev_attr.attr, + &sensor_dev_attr_in3_min.dev_attr.attr, + NULL +}; + +static const struct attribute_group f75375_group = { + .attrs = f75375_attributes, +}; + +static int f75375_detach_client(struct i2c_client *client) +{ + struct f75375_data *data = i2c_get_clientdata(client); + int err; + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &f75375_group); + + err = i2c_detach_client(client); + if (err) { + dev_err(&client->dev, + "Client deregistration failed, " + "client not detached.\n"); + return err; + } + kfree(data); + return 0; +} + +static int f75375_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_probe(adapter, &addr_data, f75375_detect); +} + +/* This function is called by i2c_probe */ +static int f75375_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *client; + struct f75375_data *data; + u8 version = 0; + int err = 0; + const char *name = ""; + + if (!(data = kzalloc(sizeof(struct f75375_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + client = &data->client; + i2c_set_clientdata(client, data); + client->addr = address; + client->adapter = adapter; + client->driver = &f75375_driver; + + if (kind < 0) { + u16 vendid = f75375_read16(client, F75375_REG_VENDOR); + u16 chipid = f75375_read16(client, F75375_CHIP_ID); + version = f75375_read8(client, F75375_REG_VERSION); + if (chipid == 0x0306 && vendid == 0x1934) { + kind = f75375; + } else if (chipid == 0x0204 && vendid == 0x1934) { + kind = f75373; + } else { + dev_err(&adapter->dev, + "failed,%02X,%02X,%02X\n", + chipid, version, vendid); + goto exit_free; + } + } + + if (kind == f75375) { + name = "f75375"; + } else if (kind == f75373) { + name = "f75373"; + } + + dev_info(&adapter->dev, "found %s version: %02X\n", name, version); + strlcpy(client->name, name, I2C_NAME_SIZE); + data->kind = kind; + mutex_init(&data->update_lock); + if ((err = i2c_attach_client(client))) + goto exit_free; + + if ((err = sysfs_create_group(&client->dev.kobj, &f75375_group))) + goto exit_detach; + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &f75375_group); +exit_detach: + i2c_detach_client(client); +exit_free: + kfree(data); +exit: + return err; +} + +static int __init sensors_f75375_init(void) +{ + return i2c_add_driver(&f75375_driver); +} + +static void __exit sensors_f75375_exit(void) +{ + i2c_del_driver(&f75375_driver); +} + +MODULE_AUTHOR("Riku Voipio <riku.voipio@movial.fi>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("F75373/F75375 hardware monitoring driver"); + +module_init(sensors_f75375_init); +module_exit(sensors_f75375_exit); diff --git a/drivers/hwmon/fscher.c b/drivers/hwmon/fscher.c index b34b546c68b8..e67c36953b2d 100644 --- a/drivers/hwmon/fscher.c +++ b/drivers/hwmon/fscher.c @@ -134,7 +134,7 @@ static struct i2c_driver fscher_driver = { struct fscher_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -344,9 +344,9 @@ static int fscher_detect(struct i2c_adapter *adapter, int address, int kind) if ((err = sysfs_create_group(&new_client->dev.kobj, &fscher_group))) goto exit_detach; - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -367,7 +367,7 @@ static int fscher_detach_client(struct i2c_client *client) struct fscher_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &fscher_group); if ((err = i2c_detach_client(client))) diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c new file mode 100644 index 000000000000..63a4df0580db --- /dev/null +++ b/drivers/hwmon/fschmd.c @@ -0,0 +1,778 @@ +/* fschmd.c + * + * Copyright (C) 2007 Hans de Goede <j.w.r.degoede@hhs.nl> + * + * 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. + */ + +/* + * Merged Fujitsu Siemens hwmon driver, supporting the Poseidon, Hermes, + * Scylla, Heracles and Heimdall chips + * + * Based on the original 2.4 fscscy, 2.6 fscpos, 2.6 fscher and 2.6 + * (candidate) fschmd drivers: + * Copyright (C) 2006 Thilo Cestonaro + * <thilo.cestonaro.external@fujitsu-siemens.com> + * Copyright (C) 2004, 2005 Stefan Ott <stefan@desire.ch> + * Copyright (C) 2003, 2004 Reinhard Nissl <rnissl@gmx.de> + * Copyright (c) 2001 Martin Knoblauch <mkn@teraport.de, knobi@knobisoft.de> + * Copyright (C) 2000 Hermann Jung <hej@odn.de> + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/jiffies.h> +#include <linux/i2c.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/err.h> +#include <linux/mutex.h> +#include <linux/sysfs.h> + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END }; + +/* Insmod parameters */ +I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd); + +/* + * The FSCHMD registers and other defines + */ + +/* chip identification */ +#define FSCHMD_REG_IDENT_0 0x00 +#define FSCHMD_REG_IDENT_1 0x01 +#define FSCHMD_REG_IDENT_2 0x02 +#define FSCHMD_REG_REVISION 0x03 + +/* global control and status */ +#define FSCHMD_REG_EVENT_STATE 0x04 +#define FSCHMD_REG_CONTROL 0x05 + +#define FSCHMD_CONTROL_ALERT_LED_MASK 0x01 + +/* watchdog (support to be implemented) */ +#define FSCHMD_REG_WDOG_PRESET 0x28 +#define FSCHMD_REG_WDOG_STATE 0x23 +#define FSCHMD_REG_WDOG_CONTROL 0x21 + +/* voltages, weird order is to keep the same order as the old drivers */ +static const u8 FSCHMD_REG_VOLT[3] = { 0x45, 0x42, 0x48 }; + +/* minimum pwm at which the fan is driven (pwm can by increased depending on + the temp. Notice that for the scy some fans share there minimum speed. + Also notice that with the scy the sensor order is different then with the + other chips, this order was in the 2.4 driver and kept for consistency. */ +static const u8 FSCHMD_REG_FAN_MIN[5][6] = { + { 0x55, 0x65 }, /* pos */ + { 0x55, 0x65, 0xb5 }, /* her */ + { 0x65, 0x65, 0x55, 0xa5, 0x55, 0xa5 }, /* scy */ + { 0x55, 0x65, 0xa5, 0xb5 }, /* hrc */ + { 0x55, 0x65, 0xa5, 0xb5, 0xc5 }, /* hmd */ +}; + +/* actual fan speed */ +static const u8 FSCHMD_REG_FAN_ACT[5][6] = { + { 0x0e, 0x6b, 0xab }, /* pos */ + { 0x0e, 0x6b, 0xbb }, /* her */ + { 0x6b, 0x6c, 0x0e, 0xab, 0x5c, 0xbb }, /* scy */ + { 0x0e, 0x6b, 0xab, 0xbb }, /* hrc */ + { 0x5b, 0x6b, 0xab, 0xbb, 0xcb }, /* hmd */ +}; + +/* fan status registers */ +static const u8 FSCHMD_REG_FAN_STATE[5][6] = { + { 0x0d, 0x62, 0xa2 }, /* pos */ + { 0x0d, 0x62, 0xb2 }, /* her */ + { 0x62, 0x61, 0x0d, 0xa2, 0x52, 0xb2 }, /* scy */ + { 0x0d, 0x62, 0xa2, 0xb2 }, /* hrc */ + { 0x52, 0x62, 0xa2, 0xb2, 0xc2 }, /* hmd */ +}; + +/* fan ripple / divider registers */ +static const u8 FSCHMD_REG_FAN_RIPPLE[5][6] = { + { 0x0f, 0x6f, 0xaf }, /* pos */ + { 0x0f, 0x6f, 0xbf }, /* her */ + { 0x6f, 0x6f, 0x0f, 0xaf, 0x0f, 0xbf }, /* scy */ + { 0x0f, 0x6f, 0xaf, 0xbf }, /* hrc */ + { 0x5f, 0x6f, 0xaf, 0xbf, 0xcf }, /* hmd */ +}; + +static const int FSCHMD_NO_FAN_SENSORS[5] = { 3, 3, 6, 4, 5 }; + +/* Fan status register bitmasks */ +#define FSCHMD_FAN_ALARM_MASK 0x04 /* called fault by FSC! */ +#define FSCHMD_FAN_NOT_PRESENT_MASK 0x08 /* not documented */ + + +/* actual temperature registers */ +static const u8 FSCHMD_REG_TEMP_ACT[5][5] = { + { 0x64, 0x32, 0x35 }, /* pos */ + { 0x64, 0x32, 0x35 }, /* her */ + { 0x64, 0xD0, 0x32, 0x35 }, /* scy */ + { 0x64, 0x32, 0x35 }, /* hrc */ + { 0x70, 0x80, 0x90, 0xd0, 0xe0 }, /* hmd */ +}; + +/* temperature state registers */ +static const u8 FSCHMD_REG_TEMP_STATE[5][5] = { + { 0x71, 0x81, 0x91 }, /* pos */ + { 0x71, 0x81, 0x91 }, /* her */ + { 0x71, 0xd1, 0x81, 0x91 }, /* scy */ + { 0x71, 0x81, 0x91 }, /* hrc */ + { 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hmd */ +}; + +/* temperature high limit registers, FSC does not document these. Proven to be + there with field testing on the fscher and fschrc, already supported / used + in the fscscy 2.4 driver. FSC has confirmed that the fschmd has registers + at these addresses, but doesn't want to confirm they are the same as with + the fscher?? */ +static const u8 FSCHMD_REG_TEMP_LIMIT[5][5] = { + { 0, 0, 0 }, /* pos */ + { 0x76, 0x86, 0x96 }, /* her */ + { 0x76, 0xd6, 0x86, 0x96 }, /* scy */ + { 0x76, 0x86, 0x96 }, /* hrc */ + { 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hmd */ +}; + +/* These were found through experimenting with an fscher, currently they are + not used, but we keep them around for future reference. +static const u8 FSCHER_REG_TEMP_AUTOP1[] = { 0x73, 0x83, 0x93 }; +static const u8 FSCHER_REG_TEMP_AUTOP2[] = { 0x75, 0x85, 0x95 }; */ + +static const int FSCHMD_NO_TEMP_SENSORS[5] = { 3, 3, 4, 3, 5 }; + +/* temp status register bitmasks */ +#define FSCHMD_TEMP_WORKING_MASK 0x01 +#define FSCHMD_TEMP_ALERT_MASK 0x02 +/* there only really is an alarm if the sensor is working and alert == 1 */ +#define FSCHMD_TEMP_ALARM_MASK \ + (FSCHMD_TEMP_WORKING_MASK | FSCHMD_TEMP_ALERT_MASK) + +/* our driver name */ +#define FSCHMD_NAME "fschmd" + +/* + * Functions declarations + */ + +static int fschmd_attach_adapter(struct i2c_adapter *adapter); +static int fschmd_detach_client(struct i2c_client *client); +static struct fschmd_data *fschmd_update_device(struct device *dev); + +/* + * Driver data (common to all clients) + */ + +static struct i2c_driver fschmd_driver = { + .driver = { + .name = FSCHMD_NAME, + }, + .attach_adapter = fschmd_attach_adapter, + .detach_client = fschmd_detach_client, +}; + +/* + * Client data (each client gets its own) + */ + +struct fschmd_data { + struct i2c_client client; + struct device *hwmon_dev; + struct mutex update_lock; + int kind; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + + /* register values */ + u8 global_control; /* global control register */ + u8 volt[3]; /* 12, 5, battery voltage */ + u8 temp_act[5]; /* temperature */ + u8 temp_status[5]; /* status of sensor */ + u8 temp_max[5]; /* high temp limit, notice: undocumented! */ + u8 fan_act[6]; /* fans revolutions per second */ + u8 fan_status[6]; /* fan status */ + u8 fan_min[6]; /* fan min value for rps */ + u8 fan_ripple[6]; /* divider for rps */ +}; + +/* + * Sysfs attr show / store functions + */ + +static ssize_t show_in_value(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + const int max_reading[3] = { 14200, 6600, 3300 }; + int index = to_sensor_dev_attr(devattr)->index; + struct fschmd_data *data = fschmd_update_device(dev); + + return sprintf(buf, "%d\n", (data->volt[index] * + max_reading[index] + 128) / 255); +} + + +#define TEMP_FROM_REG(val) (((val) - 128) * 1000) + +static ssize_t show_temp_value(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct fschmd_data *data = fschmd_update_device(dev); + + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_act[index])); +} + +static ssize_t show_temp_max(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct fschmd_data *data = fschmd_update_device(dev); + + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[index])); +} + +static ssize_t store_temp_max(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct fschmd_data *data = dev_get_drvdata(dev); + long v = simple_strtol(buf, NULL, 10) / 1000; + + v = SENSORS_LIMIT(v, -128, 127) + 128; + + mutex_lock(&data->update_lock); + i2c_smbus_write_byte_data(&data->client, + FSCHMD_REG_TEMP_LIMIT[data->kind][index], v); + data->temp_max[index] = v; + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_temp_fault(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct fschmd_data *data = fschmd_update_device(dev); + + /* bit 0 set means sensor working ok, so no fault! */ + if (data->temp_status[index] & FSCHMD_TEMP_WORKING_MASK) + return sprintf(buf, "0\n"); + else + return sprintf(buf, "1\n"); +} + +static ssize_t show_temp_alarm(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct fschmd_data *data = fschmd_update_device(dev); + + if ((data->temp_status[index] & FSCHMD_TEMP_ALARM_MASK) == + FSCHMD_TEMP_ALARM_MASK) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + + +#define RPM_FROM_REG(val) ((val) * 60) + +static ssize_t show_fan_value(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct fschmd_data *data = fschmd_update_device(dev); + + return sprintf(buf, "%u\n", RPM_FROM_REG(data->fan_act[index])); +} + +static ssize_t show_fan_div(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct fschmd_data *data = fschmd_update_device(dev); + + /* bits 2..7 reserved => mask with 3 */ + return sprintf(buf, "%d\n", 1 << (data->fan_ripple[index] & 3)); +} + +static ssize_t store_fan_div(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + u8 reg; + int index = to_sensor_dev_attr(devattr)->index; + struct fschmd_data *data = dev_get_drvdata(dev); + /* supported values: 2, 4, 8 */ + unsigned long v = simple_strtoul(buf, NULL, 10); + + switch (v) { + case 2: v = 1; break; + case 4: v = 2; break; + case 8: v = 3; break; + default: + dev_err(dev, "fan_div value %lu not supported. " + "Choose one of 2, 4 or 8!\n", v); + return -EINVAL; + } + + mutex_lock(&data->update_lock); + + reg = i2c_smbus_read_byte_data(&data->client, + FSCHMD_REG_FAN_RIPPLE[data->kind][index]); + + /* bits 2..7 reserved => mask with 0x03 */ + reg &= ~0x03; + reg |= v; + + i2c_smbus_write_byte_data(&data->client, + FSCHMD_REG_FAN_RIPPLE[data->kind][index], reg); + + data->fan_ripple[index] = reg; + + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_fan_alarm(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct fschmd_data *data = fschmd_update_device(dev); + + if (data->fan_status[index] & FSCHMD_FAN_ALARM_MASK) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + +static ssize_t show_fan_fault(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct fschmd_data *data = fschmd_update_device(dev); + + if (data->fan_status[index] & FSCHMD_FAN_NOT_PRESENT_MASK) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + + +static ssize_t show_pwm_auto_point1_pwm(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + int val = fschmd_update_device(dev)->fan_min[index]; + + /* 0 = allow turning off, 1-255 = 50-100% */ + if (val) + val = val / 2 + 128; + + return sprintf(buf, "%d\n", val); +} + +static ssize_t store_pwm_auto_point1_pwm(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct fschmd_data *data = dev_get_drvdata(dev); + unsigned long v = simple_strtoul(buf, NULL, 10); + + /* register: 0 = allow turning off, 1-255 = 50-100% */ + if (v) { + v = SENSORS_LIMIT(v, 128, 255); + v = (v - 128) * 2 + 1; + } + + mutex_lock(&data->update_lock); + + i2c_smbus_write_byte_data(&data->client, + FSCHMD_REG_FAN_MIN[data->kind][index], v); + data->fan_min[index] = v; + + mutex_unlock(&data->update_lock); + + return count; +} + + +/* The FSC hwmon family has the ability to force an attached alert led to flash + from software, we export this as an alert_led sysfs attr */ +static ssize_t show_alert_led(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct fschmd_data *data = fschmd_update_device(dev); + + if (data->global_control & FSCHMD_CONTROL_ALERT_LED_MASK) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + +static ssize_t store_alert_led(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) +{ + u8 reg; + struct fschmd_data *data = dev_get_drvdata(dev); + unsigned long v = simple_strtoul(buf, NULL, 10); + + mutex_lock(&data->update_lock); + + reg = i2c_smbus_read_byte_data(&data->client, FSCHMD_REG_CONTROL); + + if (v) + reg |= FSCHMD_CONTROL_ALERT_LED_MASK; + else + reg &= ~FSCHMD_CONTROL_ALERT_LED_MASK; + + i2c_smbus_write_byte_data(&data->client, FSCHMD_REG_CONTROL, reg); + + data->global_control = reg; + + mutex_unlock(&data->update_lock); + + return count; +} + +static struct sensor_device_attribute fschmd_attr[] = { + SENSOR_ATTR(in0_input, 0444, show_in_value, NULL, 0), + SENSOR_ATTR(in1_input, 0444, show_in_value, NULL, 1), + SENSOR_ATTR(in2_input, 0444, show_in_value, NULL, 2), + SENSOR_ATTR(alert_led, 0644, show_alert_led, store_alert_led, 0), +}; + +static struct sensor_device_attribute fschmd_temp_attr[] = { + SENSOR_ATTR(temp1_input, 0444, show_temp_value, NULL, 0), + SENSOR_ATTR(temp1_max, 0644, show_temp_max, store_temp_max, 0), + SENSOR_ATTR(temp1_fault, 0444, show_temp_fault, NULL, 0), + SENSOR_ATTR(temp1_alarm, 0444, show_temp_alarm, NULL, 0), + SENSOR_ATTR(temp2_input, 0444, show_temp_value, NULL, 1), + SENSOR_ATTR(temp2_max, 0644, show_temp_max, store_temp_max, 1), + SENSOR_ATTR(temp2_fault, 0444, show_temp_fault, NULL, 1), + SENSOR_ATTR(temp2_alarm, 0444, show_temp_alarm, NULL, 1), + SENSOR_ATTR(temp3_input, 0444, show_temp_value, NULL, 2), + SENSOR_ATTR(temp3_max, 0644, show_temp_max, store_temp_max, 2), + SENSOR_ATTR(temp3_fault, 0444, show_temp_fault, NULL, 2), + SENSOR_ATTR(temp3_alarm, 0444, show_temp_alarm, NULL, 2), + SENSOR_ATTR(temp4_input, 0444, show_temp_value, NULL, 3), + SENSOR_ATTR(temp4_max, 0644, show_temp_max, store_temp_max, 3), + SENSOR_ATTR(temp4_fault, 0444, show_temp_fault, NULL, 3), + SENSOR_ATTR(temp4_alarm, 0444, show_temp_alarm, NULL, 3), + SENSOR_ATTR(temp5_input, 0444, show_temp_value, NULL, 4), + SENSOR_ATTR(temp5_max, 0644, show_temp_max, store_temp_max, 4), + SENSOR_ATTR(temp5_fault, 0444, show_temp_fault, NULL, 4), + SENSOR_ATTR(temp5_alarm, 0444, show_temp_alarm, NULL, 4), +}; + +static struct sensor_device_attribute fschmd_fan_attr[] = { + SENSOR_ATTR(fan1_input, 0444, show_fan_value, NULL, 0), + SENSOR_ATTR(fan1_div, 0644, show_fan_div, store_fan_div, 0), + SENSOR_ATTR(fan1_alarm, 0444, show_fan_alarm, NULL, 0), + SENSOR_ATTR(fan1_fault, 0444, show_fan_fault, NULL, 0), + SENSOR_ATTR(pwm1_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, + store_pwm_auto_point1_pwm, 0), + SENSOR_ATTR(fan2_input, 0444, show_fan_value, NULL, 1), + SENSOR_ATTR(fan2_div, 0644, show_fan_div, store_fan_div, 1), + SENSOR_ATTR(fan2_alarm, 0444, show_fan_alarm, NULL, 1), + SENSOR_ATTR(fan2_fault, 0444, show_fan_fault, NULL, 1), + SENSOR_ATTR(pwm2_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, + store_pwm_auto_point1_pwm, 1), + SENSOR_ATTR(fan3_input, 0444, show_fan_value, NULL, 2), + SENSOR_ATTR(fan3_div, 0644, show_fan_div, store_fan_div, 2), + SENSOR_ATTR(fan3_alarm, 0444, show_fan_alarm, NULL, 2), + SENSOR_ATTR(fan3_fault, 0444, show_fan_fault, NULL, 2), + SENSOR_ATTR(pwm3_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, + store_pwm_auto_point1_pwm, 2), + SENSOR_ATTR(fan4_input, 0444, show_fan_value, NULL, 3), + SENSOR_ATTR(fan4_div, 0644, show_fan_div, store_fan_div, 3), + SENSOR_ATTR(fan4_alarm, 0444, show_fan_alarm, NULL, 3), + SENSOR_ATTR(fan4_fault, 0444, show_fan_fault, NULL, 3), + SENSOR_ATTR(pwm4_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, + store_pwm_auto_point1_pwm, 3), + SENSOR_ATTR(fan5_input, 0444, show_fan_value, NULL, 4), + SENSOR_ATTR(fan5_div, 0644, show_fan_div, store_fan_div, 4), + SENSOR_ATTR(fan5_alarm, 0444, show_fan_alarm, NULL, 4), + SENSOR_ATTR(fan5_fault, 0444, show_fan_fault, NULL, 4), + SENSOR_ATTR(pwm5_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, + store_pwm_auto_point1_pwm, 4), + SENSOR_ATTR(fan6_input, 0444, show_fan_value, NULL, 5), + SENSOR_ATTR(fan6_div, 0644, show_fan_div, store_fan_div, 5), + SENSOR_ATTR(fan6_alarm, 0444, show_fan_alarm, NULL, 5), + SENSOR_ATTR(fan6_fault, 0444, show_fan_fault, NULL, 5), + SENSOR_ATTR(pwm6_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, + store_pwm_auto_point1_pwm, 5), +}; + + +/* + * Real code + */ + +static int fschmd_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *client; + struct fschmd_data *data; + u8 revision; + const char * const names[5] = { "Poseidon", "Hermes", "Scylla", + "Heracles", "Heimdall" }; + const char * const client_names[5] = { "fscpos", "fscher", "fscscy", + "fschrc", "fschmd" }; + int i, err = 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return 0; + + /* OK. For now, we presume we have a valid client. We now create the + * client structure, even though we cannot fill it completely yet. + * But it allows us to access i2c_smbus_read_byte_data. */ + if (!(data = kzalloc(sizeof(struct fschmd_data), GFP_KERNEL))) + return -ENOMEM; + + client = &data->client; + i2c_set_clientdata(client, data); + client->addr = address; + client->adapter = adapter; + client->driver = &fschmd_driver; + mutex_init(&data->update_lock); + + /* Detect & Identify the chip */ + if (kind <= 0) { + char id[4]; + + id[0] = i2c_smbus_read_byte_data(client, + FSCHMD_REG_IDENT_0); + id[1] = i2c_smbus_read_byte_data(client, + FSCHMD_REG_IDENT_1); + id[2] = i2c_smbus_read_byte_data(client, + FSCHMD_REG_IDENT_2); + id[3] = '\0'; + + if (!strcmp(id, "PEG")) + kind = fscpos; + else if (!strcmp(id, "HER")) + kind = fscher; + else if (!strcmp(id, "SCY")) + kind = fscscy; + else if (!strcmp(id, "HRC")) + kind = fschrc; + else if (!strcmp(id, "HMD")) + kind = fschmd; + else + goto exit_free; + } + + if (kind == fscpos) { + /* The Poseidon has hardwired temp limits, fill these + in for the alarm resetting code */ + data->temp_max[0] = 70 + 128; + data->temp_max[1] = 50 + 128; + data->temp_max[2] = 50 + 128; + } + + /* i2c kind goes from 1-5, we want from 0-4 to address arrays */ + data->kind = kind - 1; + strlcpy(client->name, client_names[data->kind], I2C_NAME_SIZE); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(client))) + goto exit_free; + + for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++) { + err = device_create_file(&client->dev, + &fschmd_attr[i].dev_attr); + if (err) + goto exit_detach; + } + + for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++) { + /* Poseidon doesn't have TEMP_LIMIT registers */ + if (kind == fscpos && fschmd_temp_attr[i].dev_attr.show == + show_temp_max) + continue; + + err = device_create_file(&client->dev, + &fschmd_temp_attr[i].dev_attr); + if (err) + goto exit_detach; + } + + for (i = 0; i < (FSCHMD_NO_FAN_SENSORS[data->kind] * 5); i++) { + /* Poseidon doesn't have a FAN_MIN register for its 3rd fan */ + if (kind == fscpos && + !strcmp(fschmd_fan_attr[i].dev_attr.attr.name, + "pwm3_auto_point1_pwm")) + continue; + + err = device_create_file(&client->dev, + &fschmd_fan_attr[i].dev_attr); + if (err) + goto exit_detach; + } + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); + data->hwmon_dev = NULL; + goto exit_detach; + } + + revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION); + printk(KERN_INFO FSCHMD_NAME ": Detected FSC %s chip, revision: %d\n", + names[data->kind], (int) revision); + + return 0; + +exit_detach: + fschmd_detach_client(client); /* will also free data for us */ + return err; + +exit_free: + kfree(data); + return err; +} + +static int fschmd_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_probe(adapter, &addr_data, fschmd_detect); +} + +static int fschmd_detach_client(struct i2c_client *client) +{ + struct fschmd_data *data = i2c_get_clientdata(client); + int i, err; + + /* Check if registered in case we're called from fschmd_detect + to cleanup after an error */ + if (data->hwmon_dev) + hwmon_device_unregister(data->hwmon_dev); + + for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++) + device_remove_file(&client->dev, &fschmd_attr[i].dev_attr); + for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++) + device_remove_file(&client->dev, + &fschmd_temp_attr[i].dev_attr); + for (i = 0; i < (FSCHMD_NO_FAN_SENSORS[data->kind] * 5); i++) + device_remove_file(&client->dev, + &fschmd_fan_attr[i].dev_attr); + + if ((err = i2c_detach_client(client))) + return err; + + kfree(data); + return 0; +} + +static struct fschmd_data *fschmd_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct fschmd_data *data = i2c_get_clientdata(client); + int i; + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) { + + for (i = 0; i < FSCHMD_NO_TEMP_SENSORS[data->kind]; i++) { + data->temp_act[i] = i2c_smbus_read_byte_data(client, + FSCHMD_REG_TEMP_ACT[data->kind][i]); + data->temp_status[i] = i2c_smbus_read_byte_data(client, + FSCHMD_REG_TEMP_STATE[data->kind][i]); + + /* The fscpos doesn't have TEMP_LIMIT registers */ + if (FSCHMD_REG_TEMP_LIMIT[data->kind][i]) + data->temp_max[i] = i2c_smbus_read_byte_data( + client, + FSCHMD_REG_TEMP_LIMIT[data->kind][i]); + + /* reset alarm if the alarm condition is gone, + the chip doesn't do this itself */ + if ((data->temp_status[i] & FSCHMD_TEMP_ALARM_MASK) == + FSCHMD_TEMP_ALARM_MASK && + data->temp_act[i] < data->temp_max[i]) + i2c_smbus_write_byte_data(client, + FSCHMD_REG_TEMP_STATE[data->kind][i], + FSCHMD_TEMP_ALERT_MASK); + } + + for (i = 0; i < FSCHMD_NO_FAN_SENSORS[data->kind]; i++) { + data->fan_act[i] = i2c_smbus_read_byte_data(client, + FSCHMD_REG_FAN_ACT[data->kind][i]); + data->fan_status[i] = i2c_smbus_read_byte_data(client, + FSCHMD_REG_FAN_STATE[data->kind][i]); + data->fan_ripple[i] = i2c_smbus_read_byte_data(client, + FSCHMD_REG_FAN_RIPPLE[data->kind][i]); + + /* The fscpos third fan doesn't have a fan_min */ + if (FSCHMD_REG_FAN_MIN[data->kind][i]) + data->fan_min[i] = i2c_smbus_read_byte_data( + client, + FSCHMD_REG_FAN_MIN[data->kind][i]); + + /* reset fan status if speed is back to > 0 */ + if ((data->fan_status[i] & FSCHMD_FAN_ALARM_MASK) && + data->fan_act[i]) + i2c_smbus_write_byte_data(client, + FSCHMD_REG_FAN_STATE[data->kind][i], + FSCHMD_FAN_ALARM_MASK); + } + + for (i = 0; i < 3; i++) + data->volt[i] = i2c_smbus_read_byte_data(client, + FSCHMD_REG_VOLT[i]); + + data->global_control = i2c_smbus_read_byte_data(client, + FSCHMD_REG_CONTROL); + + /* To be implemented in the future + data->watchdog[0] = i2c_smbus_read_byte_data(client, + FSCHMD_REG_WDOG_PRESET); + data->watchdog[1] = i2c_smbus_read_byte_data(client, + FSCHMD_REG_WDOG_STATE); + data->watchdog[2] = i2c_smbus_read_byte_data(client, + FSCHMD_REG_WDOG_CONTROL); */ + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + +static int __init fschmd_init(void) +{ + return i2c_add_driver(&fschmd_driver); +} + +static void __exit fschmd_exit(void) +{ + i2c_del_driver(&fschmd_driver); +} + +MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>"); +MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles and " + "Heimdall driver"); +MODULE_LICENSE("GPL"); + +module_init(fschmd_init); +module_exit(fschmd_exit); diff --git a/drivers/hwmon/fscpos.c b/drivers/hwmon/fscpos.c index ea506a77f9c9..92c9703d0ac0 100644 --- a/drivers/hwmon/fscpos.c +++ b/drivers/hwmon/fscpos.c @@ -115,7 +115,7 @@ static struct i2c_driver fscpos_driver = { */ struct fscpos_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* 0 until following fields are valid */ unsigned long last_updated; /* In jiffies */ @@ -539,9 +539,9 @@ static int fscpos_detect(struct i2c_adapter *adapter, int address, int kind) if ((err = sysfs_create_group(&new_client->dev.kobj, &fscpos_group))) goto exit_detach; - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -562,7 +562,7 @@ static int fscpos_detach_client(struct i2c_client *client) struct fscpos_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &fscpos_group); if ((err = i2c_detach_client(client))) diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c index c103640455a3..bb58d9866a37 100644 --- a/drivers/hwmon/gl518sm.c +++ b/drivers/hwmon/gl518sm.c @@ -119,7 +119,7 @@ static inline u8 FAN_TO_REG(long rpm, int div) /* Each client has this additional data */ struct gl518_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; enum chips type; struct mutex update_lock; @@ -460,9 +460,9 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind) if ((err = sysfs_create_group(&new_client->dev.kobj, &gl518_group))) goto exit_detach; - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -502,7 +502,7 @@ static int gl518_detach_client(struct i2c_client *client) struct gl518_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &gl518_group); if ((err = i2c_detach_client(client))) diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c index ebe7b9aaa916..a3b56c816e11 100644 --- a/drivers/hwmon/gl520sm.c +++ b/drivers/hwmon/gl520sm.c @@ -122,7 +122,7 @@ static struct i2c_driver gl520_driver = { /* Client data */ struct gl520_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* zero until the following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -622,9 +622,9 @@ static int gl520_detect(struct i2c_adapter *adapter, int address, int kind) } - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -685,7 +685,7 @@ static int gl520_detach_client(struct i2c_client *client) struct gl520_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &gl520_group); sysfs_remove_group(&client->dev.kobj, &gl520_group_opt); diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c index a7c6d407572b..8a7ae03aeee4 100644 --- a/drivers/hwmon/hdaps.c +++ b/drivers/hwmon/hdaps.c @@ -28,7 +28,7 @@ #include <linux/delay.h> #include <linux/platform_device.h> -#include <linux/input.h> +#include <linux/input-polldev.h> #include <linux/kernel.h> #include <linux/mutex.h> #include <linux/module.h> @@ -61,13 +61,12 @@ #define INIT_TIMEOUT_MSECS 4000 /* wait up to 4s for device init ... */ #define INIT_WAIT_MSECS 200 /* ... in 200ms increments */ -#define HDAPS_POLL_PERIOD (HZ/20) /* poll for input every 1/20s */ +#define HDAPS_POLL_INTERVAL 50 /* poll for input every 1/20s (50 ms)*/ #define HDAPS_INPUT_FUZZ 4 /* input event threshold */ #define HDAPS_INPUT_FLAT 4 -static struct timer_list hdaps_timer; static struct platform_device *pdev; -static struct input_dev *hdaps_idev; +static struct input_polled_dev *hdaps_idev; static unsigned int hdaps_invert; static u8 km_activity; static int rest_x; @@ -323,24 +322,19 @@ static void hdaps_calibrate(void) __hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &rest_x, &rest_y); } -static void hdaps_mousedev_poll(unsigned long unused) +static void hdaps_mousedev_poll(struct input_polled_dev *dev) { + struct input_dev *input_dev = dev->input; int x, y; - /* Cannot sleep. Try nonblockingly. If we fail, try again later. */ - if (mutex_trylock(&hdaps_mtx)) { - mod_timer(&hdaps_timer,jiffies + HDAPS_POLL_PERIOD); - return; - } + mutex_lock(&hdaps_mtx); if (__hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y)) goto out; - input_report_abs(hdaps_idev, ABS_X, x - rest_x); - input_report_abs(hdaps_idev, ABS_Y, y - rest_y); - input_sync(hdaps_idev); - - mod_timer(&hdaps_timer, jiffies + HDAPS_POLL_PERIOD); + input_report_abs(input_dev, ABS_X, x - rest_x); + input_report_abs(input_dev, ABS_Y, y - rest_y); + input_sync(input_dev); out: mutex_unlock(&hdaps_mtx); @@ -536,6 +530,7 @@ static struct dmi_system_id __initdata hdaps_whitelist[] = { static int __init hdaps_init(void) { + struct input_dev *idev; int ret; if (!dmi_check_system(hdaps_whitelist)) { @@ -563,39 +558,37 @@ static int __init hdaps_init(void) if (ret) goto out_device; - hdaps_idev = input_allocate_device(); + hdaps_idev = input_allocate_polled_device(); if (!hdaps_idev) { ret = -ENOMEM; goto out_group; } + hdaps_idev->poll = hdaps_mousedev_poll; + hdaps_idev->poll_interval = HDAPS_POLL_INTERVAL; + /* initial calibrate for the input device */ hdaps_calibrate(); /* initialize the input class */ - hdaps_idev->name = "hdaps"; - hdaps_idev->dev.parent = &pdev->dev; - hdaps_idev->evbit[0] = BIT(EV_ABS); - input_set_abs_params(hdaps_idev, ABS_X, + idev = hdaps_idev->input; + idev->name = "hdaps"; + idev->dev.parent = &pdev->dev; + idev->evbit[0] = BIT(EV_ABS); + input_set_abs_params(idev, ABS_X, -256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT); - input_set_abs_params(hdaps_idev, ABS_Y, + input_set_abs_params(idev, ABS_Y, -256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT); - ret = input_register_device(hdaps_idev); + ret = input_register_polled_device(hdaps_idev); if (ret) goto out_idev; - /* start up our timer for the input device */ - init_timer(&hdaps_timer); - hdaps_timer.function = hdaps_mousedev_poll; - hdaps_timer.expires = jiffies + HDAPS_POLL_PERIOD; - add_timer(&hdaps_timer); - printk(KERN_INFO "hdaps: driver successfully loaded.\n"); return 0; out_idev: - input_free_device(hdaps_idev); + input_free_polled_device(hdaps_idev); out_group: sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group); out_device: @@ -611,8 +604,8 @@ out: static void __exit hdaps_exit(void) { - del_timer_sync(&hdaps_timer); - input_unregister_device(hdaps_idev); + input_unregister_polled_device(hdaps_idev); + input_free_polled_device(hdaps_idev); sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group); platform_device_unregister(pdev); platform_driver_unregister(&hdaps_driver); diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index affcc00764d3..3db28450a3b3 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -28,17 +28,17 @@ static DEFINE_IDR(hwmon_idr); static DEFINE_SPINLOCK(idr_lock); /** - * hwmon_device_register - register w/ hwmon sysfs class + * hwmon_device_register - register w/ hwmon * @dev: the device to register * - * hwmon_device_unregister() must be called when the class device is no + * hwmon_device_unregister() must be called when the device is no * longer needed. * - * Returns the pointer to the new struct class device. + * Returns the pointer to the new device. */ -struct class_device *hwmon_device_register(struct device *dev) +struct device *hwmon_device_register(struct device *dev) { - struct class_device *cdev; + struct device *hwdev; int id, err; again: @@ -55,34 +55,33 @@ again: return ERR_PTR(err); id = id & MAX_ID_MASK; - cdev = class_device_create(hwmon_class, NULL, MKDEV(0,0), dev, - HWMON_ID_FORMAT, id); + hwdev = device_create(hwmon_class, dev, MKDEV(0,0), HWMON_ID_FORMAT, id); - if (IS_ERR(cdev)) { + if (IS_ERR(hwdev)) { spin_lock(&idr_lock); idr_remove(&hwmon_idr, id); spin_unlock(&idr_lock); } - return cdev; + return hwdev; } /** * hwmon_device_unregister - removes the previously registered class device * - * @cdev: the class device to destroy + * @dev: the class device to destroy */ -void hwmon_device_unregister(struct class_device *cdev) +void hwmon_device_unregister(struct device *dev) { int id; - if (likely(sscanf(cdev->class_id, HWMON_ID_FORMAT, &id) == 1)) { - class_device_unregister(cdev); + if (likely(sscanf(dev->bus_id, HWMON_ID_FORMAT, &id) == 1)) { + device_unregister(dev); spin_lock(&idr_lock); idr_remove(&hwmon_idr, id); spin_unlock(&idr_lock); } else - dev_dbg(cdev->dev, + dev_dbg(dev->parent, "hwmon_device_unregister() failed: bad class ID!\n"); } diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c new file mode 100644 index 000000000000..c462824ffccf --- /dev/null +++ b/drivers/hwmon/ibmpex.c @@ -0,0 +1,607 @@ +/* + * A hwmon driver for the IBM PowerExecutive temperature/power sensors + * Copyright (C) 2007 IBM + * + * Author: Darrick J. Wong <djwong@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/ipmi.h> +#include <linux/module.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/jiffies.h> +#include <linux/mutex.h> + +#define REFRESH_INTERVAL (2 * HZ) +#define DRVNAME "ibmpex" + +#define PEX_GET_VERSION 1 +#define PEX_GET_SENSOR_COUNT 2 +#define PEX_GET_SENSOR_NAME 3 +#define PEX_RESET_HIGH_LOW 4 +#define PEX_GET_SENSOR_DATA 6 + +#define PEX_NET_FUNCTION 0x3A +#define PEX_COMMAND 0x3C + +static inline u16 extract_value(const char *data, int offset) +{ + return be16_to_cpup((u16 *)&data[offset]); +} + +#define TEMP_SENSOR 1 +#define POWER_SENSOR 2 + +#define PEX_SENSOR_TYPE_LEN 3 +static u8 const power_sensor_sig[] = {0x70, 0x77, 0x72}; +static u8 const temp_sensor_sig[] = {0x74, 0x65, 0x6D}; + +#define PEX_MULT_LEN 2 +static u8 const watt_sensor_sig[] = {0x41, 0x43}; + +#define PEX_NUM_SENSOR_FUNCS 3 +static char const * const power_sensor_name_templates[] = { + "%s%d_average", + "%s%d_average_lowest", + "%s%d_average_highest" +}; +static char const * const temp_sensor_name_templates[] = { + "%s%d_input", + "%s%d_input_lowest", + "%s%d_input_highest" +}; + +static void ibmpex_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); +static void ibmpex_register_bmc(int iface, struct device *dev); +static void ibmpex_bmc_gone(int iface); + +struct ibmpex_sensor_data { + int in_use; + s16 values[PEX_NUM_SENSOR_FUNCS]; + int multiplier; + + struct sensor_device_attribute_2 attr[PEX_NUM_SENSOR_FUNCS]; +}; + +struct ibmpex_bmc_data { + struct list_head list; + struct device *hwmon_dev; + struct device *bmc_device; + struct mutex lock; + char valid; + unsigned long last_updated; /* In jiffies */ + + struct ipmi_addr address; + struct completion read_complete; + ipmi_user_t user; + int interface; + + struct kernel_ipmi_msg tx_message; + unsigned char tx_msg_data[IPMI_MAX_MSG_LENGTH]; + long tx_msgid; + + unsigned char rx_msg_data[IPMI_MAX_MSG_LENGTH]; + unsigned long rx_msg_len; + unsigned char rx_result; + int rx_recv_type; + + unsigned char sensor_major; + unsigned char sensor_minor; + + unsigned char num_sensors; + struct ibmpex_sensor_data *sensors; +}; + +struct ibmpex_driver_data { + struct list_head bmc_data; + struct ipmi_smi_watcher bmc_events; + struct ipmi_user_hndl ipmi_hndlrs; +}; + +static struct ibmpex_driver_data driver_data = { + .bmc_data = LIST_HEAD_INIT(driver_data.bmc_data), + .bmc_events = { + .owner = THIS_MODULE, + .new_smi = ibmpex_register_bmc, + .smi_gone = ibmpex_bmc_gone, + }, + .ipmi_hndlrs = { + .ipmi_recv_hndl = ibmpex_msg_handler, + }, +}; + +static int ibmpex_send_message(struct ibmpex_bmc_data *data) +{ + int err; + + err = ipmi_validate_addr(&data->address, sizeof(data->address)); + if (err) + goto out; + + data->tx_msgid++; + err = ipmi_request_settime(data->user, &data->address, data->tx_msgid, + &data->tx_message, data, 0, 0, 0); + if (err) + goto out1; + + return 0; +out1: + printk(KERN_ERR "%s: request_settime=%x\n", __FUNCTION__, err); + return err; +out: + printk(KERN_ERR "%s: validate_addr=%x\n", __FUNCTION__, err); + return err; +} + +static int ibmpex_ver_check(struct ibmpex_bmc_data *data) +{ + data->tx_msg_data[0] = PEX_GET_VERSION; + data->tx_message.data_len = 1; + ibmpex_send_message(data); + + wait_for_completion(&data->read_complete); + + if (data->rx_result || data->rx_msg_len != 6) + return -ENOENT; + + data->sensor_major = data->rx_msg_data[0]; + data->sensor_minor = data->rx_msg_data[1]; + + printk(KERN_INFO DRVNAME ": Found BMC with sensor interface " + "v%d.%d %d-%02d-%02d on interface %d\n", + data->sensor_major, + data->sensor_minor, + extract_value(data->rx_msg_data, 2), + data->rx_msg_data[4], + data->rx_msg_data[5], + data->interface); + + return 0; +} + +static int ibmpex_query_sensor_count(struct ibmpex_bmc_data *data) +{ + data->tx_msg_data[0] = PEX_GET_SENSOR_COUNT; + data->tx_message.data_len = 1; + ibmpex_send_message(data); + + wait_for_completion(&data->read_complete); + + if (data->rx_result || data->rx_msg_len != 1) + return -ENOENT; + + return data->rx_msg_data[0]; +} + +static int ibmpex_query_sensor_name(struct ibmpex_bmc_data *data, int sensor) +{ + data->tx_msg_data[0] = PEX_GET_SENSOR_NAME; + data->tx_msg_data[1] = sensor; + data->tx_message.data_len = 2; + ibmpex_send_message(data); + + wait_for_completion(&data->read_complete); + + if (data->rx_result || data->rx_msg_len < 1) + return -ENOENT; + + return 0; +} + +static int ibmpex_query_sensor_data(struct ibmpex_bmc_data *data, int sensor) +{ + data->tx_msg_data[0] = PEX_GET_SENSOR_DATA; + data->tx_msg_data[1] = sensor; + data->tx_message.data_len = 2; + ibmpex_send_message(data); + + wait_for_completion(&data->read_complete); + + if (data->rx_result || data->rx_msg_len < 26) { + printk(KERN_ERR "Error reading sensor %d, please check.\n", + sensor); + return -ENOENT; + } + + return 0; +} + +static int ibmpex_reset_high_low_data(struct ibmpex_bmc_data *data) +{ + data->tx_msg_data[0] = PEX_RESET_HIGH_LOW; + data->tx_message.data_len = 1; + ibmpex_send_message(data); + + wait_for_completion(&data->read_complete); + + return 0; +} + +static void ibmpex_update_device(struct ibmpex_bmc_data *data) +{ + int i, err; + + mutex_lock(&data->lock); + if (time_before(jiffies, data->last_updated + REFRESH_INTERVAL) && + data->valid) + goto out; + + for (i = 0; i < data->num_sensors; i++) { + if (!data->sensors[i].in_use) + continue; + err = ibmpex_query_sensor_data(data, i); + if (err) + continue; + data->sensors[i].values[0] = + extract_value(data->rx_msg_data, 16); + data->sensors[i].values[1] = + extract_value(data->rx_msg_data, 18); + data->sensors[i].values[2] = + extract_value(data->rx_msg_data, 20); + } + + data->last_updated = jiffies; + data->valid = 1; + +out: + mutex_unlock(&data->lock); +} + +static struct ibmpex_bmc_data *get_bmc_data(int iface) +{ + struct ibmpex_bmc_data *p, *next; + + list_for_each_entry_safe(p, next, &driver_data.bmc_data, list) + if (p->interface == iface) + return p; + + return NULL; +} + +static ssize_t show_name(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + return sprintf(buf, "%s\n", DRVNAME); +} +static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0); + +static ssize_t ibmpex_show_sensor(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); + struct ibmpex_bmc_data *data = dev_get_drvdata(dev); + int mult = data->sensors[attr->index].multiplier; + ibmpex_update_device(data); + + return sprintf(buf, "%d\n", + data->sensors[attr->index].values[attr->nr] * mult); +} + +static ssize_t ibmpex_reset_high_low(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct ibmpex_bmc_data *data = dev_get_drvdata(dev); + + ibmpex_reset_high_low_data(data); + + return count; +} + +static SENSOR_DEVICE_ATTR(reset_high_low, S_IWUSR, NULL, + ibmpex_reset_high_low, 0); + +static int is_power_sensor(const char *sensor_id, int len) +{ + if (len < PEX_SENSOR_TYPE_LEN) + return 0; + + if (!memcmp(sensor_id, power_sensor_sig, PEX_SENSOR_TYPE_LEN)) + return 1; + return 0; +} + +static int is_temp_sensor(const char *sensor_id, int len) +{ + if (len < PEX_SENSOR_TYPE_LEN) + return 0; + + if (!memcmp(sensor_id, temp_sensor_sig, PEX_SENSOR_TYPE_LEN)) + return 1; + return 0; +} + +static int power_sensor_multiplier(const char *sensor_id, int len) +{ + int i; + + for (i = PEX_SENSOR_TYPE_LEN; i < len - 1; i++) + if (!memcmp(&sensor_id[i], watt_sensor_sig, PEX_MULT_LEN)) + return 1000000; + + return 100000; +} + +static int create_sensor(struct ibmpex_bmc_data *data, int type, + int counter, int sensor, int func) +{ + int err; + char *n; + + n = kmalloc(32, GFP_KERNEL); + if (!n) + return -ENOMEM; + + if (type == TEMP_SENSOR) + sprintf(n, temp_sensor_name_templates[func], "temp", counter); + else if (type == POWER_SENSOR) + sprintf(n, power_sensor_name_templates[func], "power", counter); + + data->sensors[sensor].attr[func].dev_attr.attr.name = n; + data->sensors[sensor].attr[func].dev_attr.attr.mode = S_IRUGO; + data->sensors[sensor].attr[func].dev_attr.show = ibmpex_show_sensor; + data->sensors[sensor].attr[func].index = sensor; + data->sensors[sensor].attr[func].nr = func; + + err = device_create_file(data->bmc_device, + &data->sensors[sensor].attr[func].dev_attr); + if (err) { + data->sensors[sensor].attr[func].dev_attr.attr.name = NULL; + kfree(n); + return err; + } + + return 0; +} + +static int ibmpex_find_sensors(struct ibmpex_bmc_data *data) +{ + int i, j, err; + int sensor_type; + int sensor_counter; + int num_power = 0; + int num_temp = 0; + + err = ibmpex_query_sensor_count(data); + if (err <= 0) + return -ENOENT; + data->num_sensors = err; + + data->sensors = kzalloc(data->num_sensors * sizeof(*data->sensors), + GFP_KERNEL); + if (!data->sensors) + return -ENOMEM; + + for (i = 0; i < data->num_sensors; i++) { + err = ibmpex_query_sensor_name(data, i); + if (err) + continue; + + if (is_power_sensor(data->rx_msg_data, data->rx_msg_len)) { + sensor_type = POWER_SENSOR; + num_power++; + sensor_counter = num_power; + data->sensors[i].multiplier = + power_sensor_multiplier(data->rx_msg_data, + data->rx_msg_len); + } else if (is_temp_sensor(data->rx_msg_data, + data->rx_msg_len)) { + sensor_type = TEMP_SENSOR; + num_temp++; + sensor_counter = num_temp; + data->sensors[i].multiplier = 1; + } else + continue; + + data->sensors[i].in_use = 1; + + /* Create attributes */ + for (j = 0; j < PEX_NUM_SENSOR_FUNCS; j++) { + err = create_sensor(data, sensor_type, sensor_counter, + i, j); + if (err) + goto exit_remove; + } + } + + err = device_create_file(data->bmc_device, + &sensor_dev_attr_reset_high_low.dev_attr); + if (err) + goto exit_remove; + + err = device_create_file(data->bmc_device, + &sensor_dev_attr_name.dev_attr); + if (err) + goto exit_remove; + + return 0; + +exit_remove: + device_remove_file(data->bmc_device, + &sensor_dev_attr_reset_high_low.dev_attr); + device_remove_file(data->bmc_device, &sensor_dev_attr_name.dev_attr); + for (i = 0; i < data->num_sensors; i++) + for (j = 0; j < PEX_NUM_SENSOR_FUNCS; j++) { + if (!data->sensors[i].attr[j].dev_attr.attr.name) + continue; + device_remove_file(data->bmc_device, + &data->sensors[i].attr[j].dev_attr); + kfree(data->sensors[i].attr[j].dev_attr.attr.name); + } + + kfree(data->sensors); + return err; +} + +static void ibmpex_register_bmc(int iface, struct device *dev) +{ + struct ibmpex_bmc_data *data; + int err; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) { + printk(KERN_ERR DRVNAME ": Insufficient memory for BMC " + "interface %d.\n", data->interface); + return; + } + + data->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + data->address.channel = IPMI_BMC_CHANNEL; + data->address.data[0] = 0; + data->interface = iface; + data->bmc_device = dev; + + /* Create IPMI messaging interface user */ + err = ipmi_create_user(data->interface, &driver_data.ipmi_hndlrs, + data, &data->user); + if (err < 0) { + printk(KERN_ERR DRVNAME ": Error, unable to register user with " + "ipmi interface %d\n", + data->interface); + goto out; + } + + mutex_init(&data->lock); + + /* Initialize message */ + data->tx_msgid = 0; + init_completion(&data->read_complete); + data->tx_message.netfn = PEX_NET_FUNCTION; + data->tx_message.cmd = PEX_COMMAND; + data->tx_message.data = data->tx_msg_data; + + /* Does this BMC support PowerExecutive? */ + err = ibmpex_ver_check(data); + if (err) + goto out_user; + + /* Register the BMC as a HWMON class device */ + data->hwmon_dev = hwmon_device_register(data->bmc_device); + + if (IS_ERR(data->hwmon_dev)) { + printk(KERN_ERR DRVNAME ": Error, unable to register hwmon " + "class device for interface %d\n", + data->interface); + goto out_user; + } + + /* finally add the new bmc data to the bmc data list */ + dev_set_drvdata(dev, data); + list_add_tail(&data->list, &driver_data.bmc_data); + + /* Now go find all the sensors */ + err = ibmpex_find_sensors(data); + if (err) { + printk(KERN_ERR "Error %d allocating memory\n", err); + goto out_register; + } + + return; + +out_register: + hwmon_device_unregister(data->hwmon_dev); +out_user: + ipmi_destroy_user(data->user); +out: + kfree(data); +} + +static void ibmpex_bmc_delete(struct ibmpex_bmc_data *data) +{ + int i, j; + + device_remove_file(data->bmc_device, + &sensor_dev_attr_reset_high_low.dev_attr); + device_remove_file(data->bmc_device, &sensor_dev_attr_name.dev_attr); + for (i = 0; i < data->num_sensors; i++) + for (j = 0; j < PEX_NUM_SENSOR_FUNCS; j++) { + if (!data->sensors[i].attr[j].dev_attr.attr.name) + continue; + device_remove_file(data->bmc_device, + &data->sensors[i].attr[j].dev_attr); + kfree(data->sensors[i].attr[j].dev_attr.attr.name); + } + + list_del(&data->list); + dev_set_drvdata(data->bmc_device, NULL); + hwmon_device_unregister(data->hwmon_dev); + ipmi_destroy_user(data->user); + kfree(data->sensors); + kfree(data); +} + +static void ibmpex_bmc_gone(int iface) +{ + struct ibmpex_bmc_data *data = get_bmc_data(iface); + + if (!data) + return; + + ibmpex_bmc_delete(data); +} + +static void ibmpex_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) +{ + struct ibmpex_bmc_data *data = (struct ibmpex_bmc_data *)user_msg_data; + + if (msg->msgid != data->tx_msgid) { + printk(KERN_ERR "Received msgid (%02x) and transmitted " + "msgid (%02x) mismatch!\n", + (int)msg->msgid, + (int)data->tx_msgid); + ipmi_free_recv_msg(msg); + return; + } + + data->rx_recv_type = msg->recv_type; + if (msg->msg.data_len > 0) + data->rx_result = msg->msg.data[0]; + else + data->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE; + + if (msg->msg.data_len > 1) { + data->rx_msg_len = msg->msg.data_len - 1; + memcpy(data->rx_msg_data, msg->msg.data + 1, data->rx_msg_len); + } else + data->rx_msg_len = 0; + + ipmi_free_recv_msg(msg); + complete(&data->read_complete); +} + +static int __init ibmpex_init(void) +{ + return ipmi_smi_watcher_register(&driver_data.bmc_events); +} + +static void __exit ibmpex_exit(void) +{ + struct ibmpex_bmc_data *p, *next; + + ipmi_smi_watcher_unregister(&driver_data.bmc_events); + list_for_each_entry_safe(p, next, &driver_data.bmc_data, list) + ibmpex_bmc_delete(p); +} + +MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>"); +MODULE_DESCRIPTION("IBM PowerExecutive power/temperature sensor driver"); +MODULE_LICENSE("GPL"); + +module_init(ibmpex_init); +module_exit(ibmpex_exit); diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index d75dba9b810b..6a182e14cf58 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -141,10 +141,10 @@ static int fix_pwm_polarity; /* Monitors: 9 voltage (0 to 7, battery), 3 temp (1 to 3), 3 fan (1 to 3) */ -#define IT87_REG_FAN(nr) (0x0d + (nr)) -#define IT87_REG_FAN_MIN(nr) (0x10 + (nr)) -#define IT87_REG_FANX(nr) (0x18 + (nr)) -#define IT87_REG_FANX_MIN(nr) (0x1b + (nr)) +static const u8 IT87_REG_FAN[] = { 0x0d, 0x0e, 0x0f, 0x80, 0x82 }; +static const u8 IT87_REG_FAN_MIN[] = { 0x10, 0x11, 0x12, 0x84, 0x86 }; +static const u8 IT87_REG_FANX[] = { 0x18, 0x19, 0x1a, 0x81, 0x83 }; +static const u8 IT87_REG_FANX_MIN[] = { 0x1b, 0x1c, 0x1d, 0x85, 0x87 }; #define IT87_REG_FAN_MAIN_CTRL 0x13 #define IT87_REG_FAN_CTL 0x14 #define IT87_REG_PWM(nr) (0x15 + (nr)) @@ -222,7 +222,7 @@ struct it87_sio_data { /* For each registered chip, we need to keep some data in memory. The structure is dynamically allocated. */ struct it87_data { - struct class_device *class_dev; + struct device *hwmon_dev; enum chips type; unsigned short addr; @@ -235,8 +235,8 @@ struct it87_data { u8 in_max[8]; /* Register value */ u8 in_min[8]; /* Register value */ u8 has_fan; /* Bitfield, fans enabled */ - u16 fan[3]; /* Register values, possibly combined */ - u16 fan_min[3]; /* Register values, possibly combined */ + u16 fan[5]; /* Register values, possibly combined */ + u16 fan_min[5]; /* Register values, possibly combined */ u8 temp[3]; /* Register value */ u8 temp_high[3]; /* Register value */ u8 temp_low[3]; /* Register value */ @@ -555,7 +555,7 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, } data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); - it87_write_value(data, IT87_REG_FAN_MIN(nr), data->fan_min[nr]); + it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan_min[nr]); mutex_unlock(&data->update_lock); return count; } @@ -596,7 +596,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, /* Restore fan min limit */ data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); - it87_write_value(data, IT87_REG_FAN_MIN(nr), data->fan_min[nr]); + it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan_min[nr]); mutex_unlock(&data->update_lock); return count; @@ -729,9 +729,9 @@ static ssize_t set_fan16_min(struct device *dev, struct device_attribute *attr, mutex_lock(&data->update_lock); data->fan_min[nr] = FAN16_TO_REG(val); - it87_write_value(data, IT87_REG_FAN_MIN(nr), + it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan_min[nr] & 0xff); - it87_write_value(data, IT87_REG_FANX_MIN(nr), + it87_write_value(data, IT87_REG_FANX_MIN[nr], data->fan_min[nr] >> 8); mutex_unlock(&data->update_lock); return count; @@ -751,6 +751,8 @@ static struct sensor_device_attribute sensor_dev_attr_fan##offset##_min16 \ show_fan16_offset(1); show_fan16_offset(2); show_fan16_offset(3); +show_fan16_offset(4); +show_fan16_offset(5); /* Alarms */ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) @@ -763,7 +765,7 @@ static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) { - struct it87_data *data = it87_update_device(dev); + struct it87_data *data = dev_get_drvdata(dev); return sprintf(buf, "%u\n", data->vrm); } static ssize_t @@ -851,6 +853,10 @@ static struct attribute *it87_attributes_opt[] = { &sensor_dev_attr_fan2_min16.dev_attr.attr, &sensor_dev_attr_fan3_input16.dev_attr.attr, &sensor_dev_attr_fan3_min16.dev_attr.attr, + &sensor_dev_attr_fan4_input16.dev_attr.attr, + &sensor_dev_attr_fan4_min16.dev_attr.attr, + &sensor_dev_attr_fan5_input16.dev_attr.attr, + &sensor_dev_attr_fan5_min16.dev_attr.attr, &sensor_dev_attr_fan1_input.dev_attr.attr, &sensor_dev_attr_fan1_min.dev_attr.attr, @@ -1024,6 +1030,20 @@ static int __devinit it87_probe(struct platform_device *pdev) &sensor_dev_attr_fan3_min16.dev_attr))) goto ERROR4; } + if (data->has_fan & (1 << 3)) { + if ((err = device_create_file(dev, + &sensor_dev_attr_fan4_input16.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_fan4_min16.dev_attr))) + goto ERROR4; + } + if (data->has_fan & (1 << 4)) { + if ((err = device_create_file(dev, + &sensor_dev_attr_fan5_input16.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_fan5_min16.dev_attr))) + goto ERROR4; + } } else { /* 8-bit tachometers with clock divider */ if (data->has_fan & (1 << 0)) { @@ -1089,9 +1109,9 @@ static int __devinit it87_probe(struct platform_device *pdev) goto ERROR4; } - data->class_dev = hwmon_device_register(dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto ERROR4; } @@ -1113,7 +1133,7 @@ static int __devexit it87_remove(struct platform_device *pdev) { struct it87_data *data = platform_get_drvdata(pdev); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&pdev->dev.kobj, &it87_group); sysfs_remove_group(&pdev->dev.kobj, &it87_group_opt); @@ -1260,6 +1280,10 @@ static void __devinit it87_init_device(struct platform_device *pdev) it87_write_value(data, IT87_REG_FAN_16BIT, tmp | 0x07); } + if (tmp & (1 << 4)) + data->has_fan |= (1 << 3); /* fan4 enabled */ + if (tmp & (1 << 5)) + data->has_fan |= (1 << 4); /* fan5 enabled */ } /* Set current fan mode registers and the default settings for the @@ -1314,21 +1338,21 @@ static struct it87_data *it87_update_device(struct device *dev) data->in[8] = it87_read_value(data, IT87_REG_VIN(8)); - for (i = 0; i < 3; i++) { + for (i = 0; i < 5; i++) { /* Skip disabled fans */ if (!(data->has_fan & (1 << i))) continue; data->fan_min[i] = - it87_read_value(data, IT87_REG_FAN_MIN(i)); + it87_read_value(data, IT87_REG_FAN_MIN[i]); data->fan[i] = it87_read_value(data, - IT87_REG_FAN(i)); + IT87_REG_FAN[i]); /* Add high byte if in 16-bit mode */ if (data->type == it8716 || data->type == it8718) { data->fan[i] |= it87_read_value(data, - IT87_REG_FANX(i)) << 8; + IT87_REG_FANX[i]) << 8; data->fan_min[i] |= it87_read_value(data, - IT87_REG_FANX_MIN(i)) << 8; + IT87_REG_FANX_MIN[i]) << 8; } } for (i = 0; i < 3; i++) { diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c index 5d8d0ca08fa9..bd2bde0ef95e 100644 --- a/drivers/hwmon/k8temp.c +++ b/drivers/hwmon/k8temp.c @@ -38,7 +38,7 @@ #define SEL_CORE 0x04 struct k8temp_data { - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; const char *name; char valid; /* zero until following fields are valid */ @@ -225,10 +225,10 @@ static int __devinit k8temp_probe(struct pci_dev *pdev, if (err) goto exit_remove; - data->class_dev = hwmon_device_register(&pdev->dev); + data->hwmon_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove; } @@ -255,7 +255,7 @@ static void __devexit k8temp_remove(struct pci_dev *pdev) { struct k8temp_data *data = dev_get_drvdata(&pdev->dev); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); device_remove_file(&pdev->dev, &sensor_dev_attr_temp1_input.dev_attr); device_remove_file(&pdev->dev, diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c index 2162d69a8c06..f207434730de 100644 --- a/drivers/hwmon/lm63.c +++ b/drivers/hwmon/lm63.c @@ -154,7 +154,7 @@ static struct i2c_driver lm63_driver = { struct lm63_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -502,9 +502,9 @@ static int lm63_detect(struct i2c_adapter *adapter, int address, int kind) goto exit_remove_files; } - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -561,7 +561,7 @@ static int lm63_detach_client(struct i2c_client *client) struct lm63_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm63_group); sysfs_remove_group(&client->dev.kobj, &lm63_group_fan1); diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c index 275d392eca61..dd366889ce9b 100644 --- a/drivers/hwmon/lm70.c +++ b/drivers/hwmon/lm70.c @@ -37,7 +37,7 @@ #define DRVNAME "lm70" struct lm70 { - struct class_device *cdev; + struct device *hwmon_dev; struct semaphore sem; }; @@ -81,7 +81,7 @@ static ssize_t lm70_sense_temp(struct device *dev, * So it's equivalent to multiplying by 0.25 * 1000 = 250. */ val = ((int)raw/32) * 250; - status = sprintf(buf, "%+d\n", val); /* millidegrees Celsius */ + status = sprintf(buf, "%d\n", val); /* millidegrees Celsius */ out: up(&p_lm70->sem); return status; @@ -89,6 +89,14 @@ out: static DEVICE_ATTR(temp1_input, S_IRUGO, lm70_sense_temp, NULL); +static ssize_t lm70_show_name(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + return sprintf(buf, "lm70\n"); +} + +static DEVICE_ATTR(name, S_IRUGO, lm70_show_name, NULL); + /*----------------------------------------------------------------------*/ static int __devinit lm70_probe(struct spi_device *spi) @@ -107,15 +115,16 @@ static int __devinit lm70_probe(struct spi_device *spi) init_MUTEX(&p_lm70->sem); /* sysfs hook */ - p_lm70->cdev = hwmon_device_register(&spi->dev); - if (IS_ERR(p_lm70->cdev)) { + p_lm70->hwmon_dev = hwmon_device_register(&spi->dev); + if (IS_ERR(p_lm70->hwmon_dev)) { dev_dbg(&spi->dev, "hwmon_device_register failed.\n"); - status = PTR_ERR(p_lm70->cdev); + status = PTR_ERR(p_lm70->hwmon_dev); goto out_dev_reg_failed; } dev_set_drvdata(&spi->dev, p_lm70); - if ((status = device_create_file(&spi->dev, &dev_attr_temp1_input))) { + if ((status = device_create_file(&spi->dev, &dev_attr_temp1_input)) + || (status = device_create_file(&spi->dev, &dev_attr_name))) { dev_dbg(&spi->dev, "device_create_file failure.\n"); goto out_dev_create_file_failed; } @@ -123,7 +132,8 @@ static int __devinit lm70_probe(struct spi_device *spi) return 0; out_dev_create_file_failed: - hwmon_device_unregister(p_lm70->cdev); + device_remove_file(&spi->dev, &dev_attr_temp1_input); + hwmon_device_unregister(p_lm70->hwmon_dev); out_dev_reg_failed: dev_set_drvdata(&spi->dev, NULL); kfree(p_lm70); @@ -135,7 +145,8 @@ static int __devexit lm70_remove(struct spi_device *spi) struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev); device_remove_file(&spi->dev, &dev_attr_temp1_input); - hwmon_device_unregister(p_lm70->cdev); + device_remove_file(&spi->dev, &dev_attr_name); + hwmon_device_unregister(p_lm70->hwmon_dev); dev_set_drvdata(&spi->dev, NULL); kfree(p_lm70); diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index a40166ffad12..37a8cc032ffa 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -50,7 +50,7 @@ static const u8 LM75_REG_TEMP[3] = { /* Each client has this additional data */ struct lm75_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ @@ -95,7 +95,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da, struct i2c_client *client = to_i2c_client(dev); struct lm75_data *data = i2c_get_clientdata(client); int nr = attr->index; - unsigned long temp = simple_strtoul(buf, NULL, 10); + long temp = simple_strtol(buf, NULL, 10); mutex_lock(&data->update_lock); data->temp[nr] = LM75_TEMP_TO_REG(temp); @@ -219,9 +219,9 @@ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind) if ((err = sysfs_create_group(&new_client->dev.kobj, &lm75_group))) goto exit_detach; - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove; } @@ -240,7 +240,7 @@ exit: static int lm75_detach_client(struct i2c_client *client) { struct lm75_data *data = i2c_get_clientdata(client); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm75_group); i2c_detach_client(client); kfree(data); diff --git a/drivers/hwmon/lm75.h b/drivers/hwmon/lm75.h index af7dc650ee15..7c93454bb4e3 100644 --- a/drivers/hwmon/lm75.h +++ b/drivers/hwmon/lm75.h @@ -33,7 +33,7 @@ /* TEMP: 0.001C/bit (-55C to +125C) REG: (0.5C/bit, two's complement) << 7 */ -static inline u16 LM75_TEMP_TO_REG(int temp) +static inline u16 LM75_TEMP_TO_REG(long temp) { int ntemp = SENSORS_LIMIT(temp, LM75_TEMP_MIN, LM75_TEMP_MAX); ntemp += (ntemp<0 ? -250 : 250); diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c index dd969f1e8415..cee5c2e8cfad 100644 --- a/drivers/hwmon/lm77.c +++ b/drivers/hwmon/lm77.c @@ -51,7 +51,7 @@ I2C_CLIENT_INSMOD_1(lm77); /* Each client has this additional data */ struct lm77_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; unsigned long last_updated; /* In jiffies */ @@ -138,7 +138,7 @@ static ssize_t set_##value(struct device *dev, struct device_attribute *attr, co { \ struct i2c_client *client = to_i2c_client(dev); \ struct lm77_data *data = i2c_get_clientdata(client); \ - long val = simple_strtoul(buf, NULL, 10); \ + long val = simple_strtol(buf, NULL, 10); \ \ mutex_lock(&data->update_lock); \ data->value = val; \ @@ -337,9 +337,9 @@ static int lm77_detect(struct i2c_adapter *adapter, int address, int kind) if ((err = sysfs_create_group(&new_client->dev.kobj, &lm77_group))) goto exit_detach; - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove; } @@ -358,7 +358,7 @@ exit: static int lm77_detach_client(struct i2c_client *client) { struct lm77_data *data = i2c_get_clientdata(client); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm77_group); i2c_detach_client(client); kfree(data); diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index 6eea3476b90c..3f7055ee679f 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c @@ -131,7 +131,7 @@ static inline int TEMP_FROM_REG(s8 val) the driver field to differentiate between I2C and ISA chips. */ struct lm78_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex lock; enum chips type; @@ -438,6 +438,25 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *da, } static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static ssize_t show_alarm(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct lm78_data *data = lm78_update_device(dev); + int nr = to_sensor_dev_attr(da)->index; + return sprintf(buf, "%u\n", (data->alarms >> nr) & 1); +} +static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); +static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2); +static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3); +static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8); +static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9); +static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10); +static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6); +static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7); +static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11); +static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4); + /* This function is called when: * lm78_driver is inserted (when this module is loaded), for each available adapter @@ -453,36 +472,47 @@ static struct attribute *lm78_attributes[] = { &sensor_dev_attr_in0_input.dev_attr.attr, &sensor_dev_attr_in0_min.dev_attr.attr, &sensor_dev_attr_in0_max.dev_attr.attr, + &sensor_dev_attr_in0_alarm.dev_attr.attr, &sensor_dev_attr_in1_input.dev_attr.attr, &sensor_dev_attr_in1_min.dev_attr.attr, &sensor_dev_attr_in1_max.dev_attr.attr, + &sensor_dev_attr_in1_alarm.dev_attr.attr, &sensor_dev_attr_in2_input.dev_attr.attr, &sensor_dev_attr_in2_min.dev_attr.attr, &sensor_dev_attr_in2_max.dev_attr.attr, + &sensor_dev_attr_in2_alarm.dev_attr.attr, &sensor_dev_attr_in3_input.dev_attr.attr, &sensor_dev_attr_in3_min.dev_attr.attr, &sensor_dev_attr_in3_max.dev_attr.attr, + &sensor_dev_attr_in3_alarm.dev_attr.attr, &sensor_dev_attr_in4_input.dev_attr.attr, &sensor_dev_attr_in4_min.dev_attr.attr, &sensor_dev_attr_in4_max.dev_attr.attr, + &sensor_dev_attr_in4_alarm.dev_attr.attr, &sensor_dev_attr_in5_input.dev_attr.attr, &sensor_dev_attr_in5_min.dev_attr.attr, &sensor_dev_attr_in5_max.dev_attr.attr, + &sensor_dev_attr_in5_alarm.dev_attr.attr, &sensor_dev_attr_in6_input.dev_attr.attr, &sensor_dev_attr_in6_min.dev_attr.attr, &sensor_dev_attr_in6_max.dev_attr.attr, + &sensor_dev_attr_in6_alarm.dev_attr.attr, &dev_attr_temp1_input.attr, &dev_attr_temp1_max.attr, &dev_attr_temp1_max_hyst.attr, + &sensor_dev_attr_temp1_alarm.dev_attr.attr, &sensor_dev_attr_fan1_input.dev_attr.attr, &sensor_dev_attr_fan1_min.dev_attr.attr, &sensor_dev_attr_fan1_div.dev_attr.attr, + &sensor_dev_attr_fan1_alarm.dev_attr.attr, &sensor_dev_attr_fan2_input.dev_attr.attr, &sensor_dev_attr_fan2_min.dev_attr.attr, &sensor_dev_attr_fan2_div.dev_attr.attr, + &sensor_dev_attr_fan2_alarm.dev_attr.attr, &sensor_dev_attr_fan3_input.dev_attr.attr, &sensor_dev_attr_fan3_min.dev_attr.attr, &sensor_dev_attr_fan3_div.dev_attr.attr, + &sensor_dev_attr_fan3_alarm.dev_attr.attr, &dev_attr_alarms.attr, &dev_attr_cpu0_vid.attr, @@ -585,9 +615,9 @@ static int lm78_detect(struct i2c_adapter *adapter, int address, int kind) if ((err = sysfs_create_group(&new_client->dev.kobj, &lm78_group))) goto ERROR3; - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto ERROR4; } @@ -608,7 +638,7 @@ static int lm78_detach_client(struct i2c_client *client) struct lm78_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm78_group); if ((err = i2c_detach_client(client))) @@ -659,9 +689,9 @@ static int __devinit lm78_isa_probe(struct platform_device *pdev) || (err = device_create_file(&pdev->dev, &dev_attr_name))) goto exit_remove_files; - data->class_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -681,7 +711,7 @@ static int __devexit lm78_isa_remove(struct platform_device *pdev) { struct lm78_data *data = platform_get_drvdata(pdev); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&pdev->dev.kobj, &lm78_group); device_remove_file(&pdev->dev, &dev_attr_name); release_region(data->client.addr, LM78_EXTENT); diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c index 064516d824ad..063cdba00a88 100644 --- a/drivers/hwmon/lm80.c +++ b/drivers/hwmon/lm80.c @@ -108,7 +108,7 @@ static inline long TEMP_FROM_REG(u16 temp) struct lm80_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ @@ -497,9 +497,9 @@ static int lm80_detect(struct i2c_adapter *adapter, int address, int kind) if ((err = sysfs_create_group(&new_client->dev.kobj, &lm80_group))) goto error_detach; - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto error_remove; } @@ -520,7 +520,7 @@ static int lm80_detach_client(struct i2c_client *client) struct lm80_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm80_group); if ((err = i2c_detach_client(client))) return err; diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c index 654c0f73464d..0336b4572a61 100644 --- a/drivers/hwmon/lm83.c +++ b/drivers/hwmon/lm83.c @@ -144,7 +144,7 @@ static struct i2c_driver lm83_driver = { struct lm83_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -400,9 +400,9 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind) goto exit_remove_files; } - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -424,7 +424,7 @@ static int lm83_detach_client(struct i2c_client *client) struct lm83_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm83_group); sysfs_remove_group(&client->dev.kobj, &lm83_group_opt); diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index 20a8c648280d..a02480be65f2 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -30,6 +30,7 @@ #include <linux/i2c.h> #include <linux/hwmon.h> #include <linux/hwmon-vid.h> +#include <linux/hwmon-sysfs.h> #include <linux/err.h> #include <linux/mutex.h> @@ -122,23 +123,6 @@ I2C_CLIENT_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102); #define EMC6D102_REG_EXTEND_ADC3 0x87 #define EMC6D102_REG_EXTEND_ADC4 0x88 -#define LM85_ALARM_IN0 0x0001 -#define LM85_ALARM_IN1 0x0002 -#define LM85_ALARM_IN2 0x0004 -#define LM85_ALARM_IN3 0x0008 -#define LM85_ALARM_TEMP1 0x0010 -#define LM85_ALARM_TEMP2 0x0020 -#define LM85_ALARM_TEMP3 0x0040 -#define LM85_ALARM_ALARM2 0x0080 -#define LM85_ALARM_IN4 0x0100 -#define LM85_ALARM_RESERVED 0x0200 -#define LM85_ALARM_FAN1 0x0400 -#define LM85_ALARM_FAN2 0x0800 -#define LM85_ALARM_FAN3 0x1000 -#define LM85_ALARM_FAN4 0x2000 -#define LM85_ALARM_TEMP1_FAULT 0x4000 -#define LM85_ALARM_TEMP3_FAULT 0x8000 - /* Conversions. Rounding and limit checking is only done on the TO_REG variants. Note that you should be a bit careful with which arguments @@ -155,22 +139,26 @@ static int lm85_scaling[] = { /* .001 Volts */ #define INS_TO_REG(n,val) \ SENSORS_LIMIT(SCALE(val,lm85_scaling[n],192),0,255) -#define INSEXT_FROM_REG(n,val,ext,scale) \ - SCALE((val)*(scale) + (ext),192*(scale),lm85_scaling[n]) +#define INSEXT_FROM_REG(n,val,ext) \ + SCALE(((val) << 4) + (ext), 192 << 4, lm85_scaling[n]) -#define INS_FROM_REG(n,val) INSEXT_FROM_REG(n,val,0,1) +#define INS_FROM_REG(n,val) SCALE((val), 192, lm85_scaling[n]) /* FAN speed is measured using 90kHz clock */ -#define FAN_TO_REG(val) (SENSORS_LIMIT( (val)<=0?0: 5400000/(val),0,65534)) +static inline u16 FAN_TO_REG(unsigned long val) +{ + if (!val) + return 0xffff; + return SENSORS_LIMIT(5400000 / val, 1, 0xfffe); +} #define FAN_FROM_REG(val) ((val)==0?-1:(val)==0xffff?0:5400000/(val)) /* Temperature is reported in .001 degC increments */ #define TEMP_TO_REG(val) \ SENSORS_LIMIT(SCALE(val,1000,1),-127,127) -#define TEMPEXT_FROM_REG(val,ext,scale) \ - SCALE((val)*scale + (ext),scale,1000) -#define TEMP_FROM_REG(val) \ - TEMPEXT_FROM_REG(val,0,1) +#define TEMPEXT_FROM_REG(val,ext) \ + SCALE(((val) << 4) + (ext), 16, 1000) +#define TEMP_FROM_REG(val) ((val) * 1000) #define PWM_TO_REG(val) (SENSORS_LIMIT(val,0,255)) #define PWM_FROM_REG(val) (val) @@ -328,7 +316,7 @@ struct lm85_autofan { The structure is dynamically allocated. */ struct lm85_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; enum chips type; struct mutex update_lock; @@ -350,7 +338,6 @@ struct lm85_data { u8 tach_mode; /* Register encoding, combined */ u8 temp_ext[3]; /* Decoded values */ u8 in_ext[8]; /* Decoded values */ - u8 adc_scale; /* ADC Extended bits scaling factor */ u8 fan_ppr; /* Register value */ u8 smooth[3]; /* Register encoding */ u8 vid; /* Register value */ @@ -387,22 +374,29 @@ static struct i2c_driver lm85_driver = { /* 4 Fans */ -static ssize_t show_fan(struct device *dev, char *buf, int nr) +static ssize_t show_fan(struct device *dev, struct device_attribute *attr, + char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr]) ); } -static ssize_t show_fan_min(struct device *dev, char *buf, int nr) + +static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr, + char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr]) ); } -static ssize_t set_fan_min(struct device *dev, const char *buf, - size_t count, int nr) + +static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + unsigned long val = simple_strtoul(buf, NULL, 10); mutex_lock(&data->update_lock); data->fan_min[nr] = FAN_TO_REG(val); @@ -412,23 +406,10 @@ static ssize_t set_fan_min(struct device *dev, const char *buf, } #define show_fan_offset(offset) \ -static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_min(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_min(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, \ - NULL); \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_min, set_fan_##offset##_min); +static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ + show_fan, NULL, offset - 1); \ +static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan_min, set_fan_min, offset - 1) show_fan_offset(1); show_fan_offset(2); @@ -457,7 +438,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) { - struct lm85_data *data = lm85_update_device(dev); + struct lm85_data *data = dev_get_drvdata(dev); return sprintf(buf, "%ld\n", (long) data->vrm); } @@ -482,16 +463,46 @@ static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); +static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf, "%u\n", (data->alarms >> nr) & 1); +} + +static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); +static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2); +static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3); +static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8); +static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 18); +static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 16); +static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 17); +static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4); +static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_alarm, NULL, 14); +static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5); +static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 6); +static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 15); +static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 10); +static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 11); +static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 12); +static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 13); + /* pwm */ -static ssize_t show_pwm(struct device *dev, char *buf, int nr) +static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, + char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", PWM_FROM_REG(data->pwm[nr]) ); } -static ssize_t set_pwm(struct device *dev, const char *buf, - size_t count, int nr) + +static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); long val = simple_strtol(buf, NULL, 10); @@ -502,8 +513,11 @@ static ssize_t set_pwm(struct device *dev, const char *buf, mutex_unlock(&data->update_lock); return count; } -static ssize_t show_pwm_enable(struct device *dev, char *buf, int nr) + +static ssize_t show_pwm_enable(struct device *dev, struct device_attribute + *attr, char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); int pwm_zone; @@ -512,23 +526,10 @@ static ssize_t show_pwm_enable(struct device *dev, char *buf, int nr) } #define show_pwm_reg(offset) \ -static ssize_t show_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_pwm(dev, buf, offset - 1); \ -} \ -static ssize_t set_pwm_##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm(dev, buf, count, offset - 1); \ -} \ -static ssize_t show_pwm_enable##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_pwm_enable(dev, buf, offset - 1); \ -} \ -static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ - show_pwm_##offset, set_pwm_##offset); \ -static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO, \ - show_pwm_enable##offset, NULL); +static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ + show_pwm, set_pwm, offset - 1); \ +static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO, \ + show_pwm_enable, NULL, offset - 1) show_pwm_reg(1); show_pwm_reg(2); @@ -536,22 +537,28 @@ show_pwm_reg(3); /* Voltages */ -static ssize_t show_in(struct device *dev, char *buf, int nr) +static ssize_t show_in(struct device *dev, struct device_attribute *attr, + char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf( buf, "%d\n", INSEXT_FROM_REG(nr, data->in[nr], - data->in_ext[nr], - data->adc_scale) ); + data->in_ext[nr])); } -static ssize_t show_in_min(struct device *dev, char *buf, int nr) + +static ssize_t show_in_min(struct device *dev, struct device_attribute *attr, + char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_min[nr]) ); } -static ssize_t set_in_min(struct device *dev, const char *buf, - size_t count, int nr) + +static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); long val = simple_strtol(buf, NULL, 10); @@ -562,14 +569,19 @@ static ssize_t set_in_min(struct device *dev, const char *buf, mutex_unlock(&data->update_lock); return count; } -static ssize_t show_in_max(struct device *dev, char *buf, int nr) + +static ssize_t show_in_max(struct device *dev, struct device_attribute *attr, + char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_max[nr]) ); } -static ssize_t set_in_max(struct device *dev, const char *buf, - size_t count, int nr) + +static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); long val = simple_strtol(buf, NULL, 10); @@ -580,59 +592,47 @@ static ssize_t set_in_max(struct device *dev, const char *buf, mutex_unlock(&data->update_lock); return count; } + #define show_in_reg(offset) \ -static ssize_t show_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in(dev, buf, offset); \ -} \ -static ssize_t show_in_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_min(dev, buf, offset); \ -} \ -static ssize_t show_in_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_max(dev, buf, offset); \ -} \ -static ssize_t set_in_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_min(dev, buf, count, offset); \ -} \ -static ssize_t set_in_##offset##_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_max(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in_##offset, \ - NULL); \ -static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in_##offset##_min, set_in_##offset##_min); \ -static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in_##offset##_max, set_in_##offset##_max); +static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \ + show_in, NULL, offset); \ +static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ + show_in_min, set_in_min, offset); \ +static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ + show_in_max, set_in_max, offset) show_in_reg(0); show_in_reg(1); show_in_reg(2); show_in_reg(3); show_in_reg(4); +show_in_reg(5); +show_in_reg(6); +show_in_reg(7); /* Temps */ -static ssize_t show_temp(struct device *dev, char *buf, int nr) +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, + char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", TEMPEXT_FROM_REG(data->temp[nr], - data->temp_ext[nr], - data->adc_scale) ); + data->temp_ext[nr])); } -static ssize_t show_temp_min(struct device *dev, char *buf, int nr) + +static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr, + char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_min[nr]) ); } -static ssize_t set_temp_min(struct device *dev, const char *buf, - size_t count, int nr) + +static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); long val = simple_strtol(buf, NULL, 10); @@ -643,14 +643,19 @@ static ssize_t set_temp_min(struct device *dev, const char *buf, mutex_unlock(&data->update_lock); return count; } -static ssize_t show_temp_max(struct device *dev, char *buf, int nr) + +static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr, + char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_max[nr]) ); } -static ssize_t set_temp_max(struct device *dev, const char *buf, - size_t count, int nr) + +static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); long val = simple_strtol(buf, NULL, 10); @@ -661,35 +666,14 @@ static ssize_t set_temp_max(struct device *dev, const char *buf, mutex_unlock(&data->update_lock); return count; } + #define show_temp_reg(offset) \ -static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp(dev, buf, offset - 1); \ -} \ -static ssize_t show_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_min(dev, buf, offset - 1); \ -} \ -static ssize_t show_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_max(dev, buf, offset - 1); \ -} \ -static ssize_t set_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t set_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_max(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, \ - NULL); \ -static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_min, set_temp_##offset##_min); \ -static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_max, set_temp_##offset##_max); +static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ + show_temp, NULL, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ + show_temp_min, set_temp_min, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ + show_temp_max, set_temp_max, offset - 1); show_temp_reg(1); show_temp_reg(2); @@ -698,14 +682,18 @@ show_temp_reg(3); /* Automatic PWM control */ -static ssize_t show_pwm_auto_channels(struct device *dev, char *buf, int nr) +static ssize_t show_pwm_auto_channels(struct device *dev, + struct device_attribute *attr, char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", ZONE_FROM_REG(data->autofan[nr].config)); } -static ssize_t set_pwm_auto_channels(struct device *dev, const char *buf, - size_t count, int nr) + +static ssize_t set_pwm_auto_channels(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { + int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); long val = simple_strtol(buf, NULL, 10); @@ -718,14 +706,19 @@ static ssize_t set_pwm_auto_channels(struct device *dev, const char *buf, mutex_unlock(&data->update_lock); return count; } -static ssize_t show_pwm_auto_pwm_min(struct device *dev, char *buf, int nr) + +static ssize_t show_pwm_auto_pwm_min(struct device *dev, + struct device_attribute *attr, char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", PWM_FROM_REG(data->autofan[nr].min_pwm)); } -static ssize_t set_pwm_auto_pwm_min(struct device *dev, const char *buf, - size_t count, int nr) + +static ssize_t set_pwm_auto_pwm_min(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { + int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); long val = simple_strtol(buf, NULL, 10); @@ -737,14 +730,19 @@ static ssize_t set_pwm_auto_pwm_min(struct device *dev, const char *buf, mutex_unlock(&data->update_lock); return count; } -static ssize_t show_pwm_auto_pwm_minctl(struct device *dev, char *buf, int nr) + +static ssize_t show_pwm_auto_pwm_minctl(struct device *dev, + struct device_attribute *attr, char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", data->autofan[nr].min_off); } -static ssize_t set_pwm_auto_pwm_minctl(struct device *dev, const char *buf, - size_t count, int nr) + +static ssize_t set_pwm_auto_pwm_minctl(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { + int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); long val = simple_strtol(buf, NULL, 10); @@ -760,14 +758,19 @@ static ssize_t set_pwm_auto_pwm_minctl(struct device *dev, const char *buf, mutex_unlock(&data->update_lock); return count; } -static ssize_t show_pwm_auto_pwm_freq(struct device *dev, char *buf, int nr) + +static ssize_t show_pwm_auto_pwm_freq(struct device *dev, + struct device_attribute *attr, char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", FREQ_FROM_REG(data->autofan[nr].freq)); } -static ssize_t set_pwm_auto_pwm_freq(struct device *dev, const char *buf, - size_t count, int nr) + +static ssize_t set_pwm_auto_pwm_freq(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { + int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); long val = simple_strtol(buf, NULL, 10); @@ -781,74 +784,40 @@ static ssize_t set_pwm_auto_pwm_freq(struct device *dev, const char *buf, mutex_unlock(&data->update_lock); return count; } + #define pwm_auto(offset) \ -static ssize_t show_pwm##offset##_auto_channels (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_pwm_auto_channels(dev, buf, offset - 1); \ -} \ -static ssize_t set_pwm##offset##_auto_channels (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm_auto_channels(dev, buf, count, offset - 1); \ -} \ -static ssize_t show_pwm##offset##_auto_pwm_min (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_pwm_auto_pwm_min(dev, buf, offset - 1); \ -} \ -static ssize_t set_pwm##offset##_auto_pwm_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm_auto_pwm_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t show_pwm##offset##_auto_pwm_minctl (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_pwm_auto_pwm_minctl(dev, buf, offset - 1); \ -} \ -static ssize_t set_pwm##offset##_auto_pwm_minctl (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm_auto_pwm_minctl(dev, buf, count, offset - 1); \ -} \ -static ssize_t show_pwm##offset##_auto_pwm_freq (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_pwm_auto_pwm_freq(dev, buf, offset - 1); \ -} \ -static ssize_t set_pwm##offset##_auto_pwm_freq(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm_auto_pwm_freq(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(pwm##offset##_auto_channels, S_IRUGO | S_IWUSR, \ - show_pwm##offset##_auto_channels, \ - set_pwm##offset##_auto_channels); \ -static DEVICE_ATTR(pwm##offset##_auto_pwm_min, S_IRUGO | S_IWUSR, \ - show_pwm##offset##_auto_pwm_min, \ - set_pwm##offset##_auto_pwm_min); \ -static DEVICE_ATTR(pwm##offset##_auto_pwm_minctl, S_IRUGO | S_IWUSR, \ - show_pwm##offset##_auto_pwm_minctl, \ - set_pwm##offset##_auto_pwm_minctl); \ -static DEVICE_ATTR(pwm##offset##_auto_pwm_freq, S_IRUGO | S_IWUSR, \ - show_pwm##offset##_auto_pwm_freq, \ - set_pwm##offset##_auto_pwm_freq); +static SENSOR_DEVICE_ATTR(pwm##offset##_auto_channels, \ + S_IRUGO | S_IWUSR, show_pwm_auto_channels, \ + set_pwm_auto_channels, offset - 1); \ +static SENSOR_DEVICE_ATTR(pwm##offset##_auto_pwm_min, \ + S_IRUGO | S_IWUSR, show_pwm_auto_pwm_min, \ + set_pwm_auto_pwm_min, offset - 1); \ +static SENSOR_DEVICE_ATTR(pwm##offset##_auto_pwm_minctl, \ + S_IRUGO | S_IWUSR, show_pwm_auto_pwm_minctl, \ + set_pwm_auto_pwm_minctl, offset - 1); \ +static SENSOR_DEVICE_ATTR(pwm##offset##_auto_pwm_freq, \ + S_IRUGO | S_IWUSR, show_pwm_auto_pwm_freq, \ + set_pwm_auto_pwm_freq, offset - 1); + pwm_auto(1); pwm_auto(2); pwm_auto(3); /* Temperature settings for automatic PWM control */ -static ssize_t show_temp_auto_temp_off(struct device *dev, char *buf, int nr) +static ssize_t show_temp_auto_temp_off(struct device *dev, + struct device_attribute *attr, char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].limit) - HYST_FROM_REG(data->zone[nr].hyst)); } -static ssize_t set_temp_auto_temp_off(struct device *dev, const char *buf, - size_t count, int nr) + +static ssize_t set_temp_auto_temp_off(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { + int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); int min; @@ -871,14 +840,19 @@ static ssize_t set_temp_auto_temp_off(struct device *dev, const char *buf, mutex_unlock(&data->update_lock); return count; } -static ssize_t show_temp_auto_temp_min(struct device *dev, char *buf, int nr) + +static ssize_t show_temp_auto_temp_min(struct device *dev, + struct device_attribute *attr, char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].limit) ); } -static ssize_t set_temp_auto_temp_min(struct device *dev, const char *buf, - size_t count, int nr) + +static ssize_t set_temp_auto_temp_min(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { + int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); long val = simple_strtol(buf, NULL, 10); @@ -913,15 +887,20 @@ static ssize_t set_temp_auto_temp_min(struct device *dev, const char *buf, mutex_unlock(&data->update_lock); return count; } -static ssize_t show_temp_auto_temp_max(struct device *dev, char *buf, int nr) + +static ssize_t show_temp_auto_temp_max(struct device *dev, + struct device_attribute *attr, char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].limit) + RANGE_FROM_REG(data->zone[nr].range)); } -static ssize_t set_temp_auto_temp_max(struct device *dev, const char *buf, - size_t count, int nr) + +static ssize_t set_temp_auto_temp_max(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { + int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); int min; @@ -938,14 +917,19 @@ static ssize_t set_temp_auto_temp_max(struct device *dev, const char *buf, mutex_unlock(&data->update_lock); return count; } -static ssize_t show_temp_auto_temp_crit(struct device *dev, char *buf, int nr) + +static ssize_t show_temp_auto_temp_crit(struct device *dev, + struct device_attribute *attr, char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].critical)); } -static ssize_t set_temp_auto_temp_crit(struct device *dev, const char *buf, - size_t count, int nr) + +static ssize_t set_temp_auto_temp_crit(struct device *dev, + struct device_attribute *attr,const char *buf, size_t count) { + int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); long val = simple_strtol(buf, NULL, 10); @@ -957,59 +941,21 @@ static ssize_t set_temp_auto_temp_crit(struct device *dev, const char *buf, mutex_unlock(&data->update_lock); return count; } + #define temp_auto(offset) \ -static ssize_t show_temp##offset##_auto_temp_off (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_temp_auto_temp_off(dev, buf, offset - 1); \ -} \ -static ssize_t set_temp##offset##_auto_temp_off (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_auto_temp_off(dev, buf, count, offset - 1); \ -} \ -static ssize_t show_temp##offset##_auto_temp_min (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_temp_auto_temp_min(dev, buf, offset - 1); \ -} \ -static ssize_t set_temp##offset##_auto_temp_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_auto_temp_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t show_temp##offset##_auto_temp_max (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_temp_auto_temp_max(dev, buf, offset - 1); \ -} \ -static ssize_t set_temp##offset##_auto_temp_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_auto_temp_max(dev, buf, count, offset - 1); \ -} \ -static ssize_t show_temp##offset##_auto_temp_crit (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_temp_auto_temp_crit(dev, buf, offset - 1); \ -} \ -static ssize_t set_temp##offset##_auto_temp_crit (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_auto_temp_crit(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(temp##offset##_auto_temp_off, S_IRUGO | S_IWUSR, \ - show_temp##offset##_auto_temp_off, \ - set_temp##offset##_auto_temp_off); \ -static DEVICE_ATTR(temp##offset##_auto_temp_min, S_IRUGO | S_IWUSR, \ - show_temp##offset##_auto_temp_min, \ - set_temp##offset##_auto_temp_min); \ -static DEVICE_ATTR(temp##offset##_auto_temp_max, S_IRUGO | S_IWUSR, \ - show_temp##offset##_auto_temp_max, \ - set_temp##offset##_auto_temp_max); \ -static DEVICE_ATTR(temp##offset##_auto_temp_crit, S_IRUGO | S_IWUSR, \ - show_temp##offset##_auto_temp_crit, \ - set_temp##offset##_auto_temp_crit); +static SENSOR_DEVICE_ATTR(temp##offset##_auto_temp_off, \ + S_IRUGO | S_IWUSR, show_temp_auto_temp_off, \ + set_temp_auto_temp_off, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_auto_temp_min, \ + S_IRUGO | S_IWUSR, show_temp_auto_temp_min, \ + set_temp_auto_temp_min, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_auto_temp_max, \ + S_IRUGO | S_IWUSR, show_temp_auto_temp_max, \ + set_temp_auto_temp_max, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_auto_temp_crit, \ + S_IRUGO | S_IWUSR, show_temp_auto_temp_crit, \ + set_temp_auto_temp_crit, offset - 1); + temp_auto(1); temp_auto(2); temp_auto(3); @@ -1022,69 +968,87 @@ static int lm85_attach_adapter(struct i2c_adapter *adapter) } static struct attribute *lm85_attributes[] = { - &dev_attr_fan1_input.attr, - &dev_attr_fan2_input.attr, - &dev_attr_fan3_input.attr, - &dev_attr_fan4_input.attr, - &dev_attr_fan1_min.attr, - &dev_attr_fan2_min.attr, - &dev_attr_fan3_min.attr, - &dev_attr_fan4_min.attr, - &dev_attr_pwm1.attr, - &dev_attr_pwm2.attr, - &dev_attr_pwm3.attr, - &dev_attr_pwm1_enable.attr, - &dev_attr_pwm2_enable.attr, - &dev_attr_pwm3_enable.attr, - &dev_attr_in0_input.attr, - &dev_attr_in1_input.attr, - &dev_attr_in2_input.attr, - &dev_attr_in3_input.attr, - &dev_attr_in0_min.attr, - &dev_attr_in1_min.attr, - &dev_attr_in2_min.attr, - &dev_attr_in3_min.attr, - &dev_attr_in0_max.attr, - &dev_attr_in1_max.attr, - &dev_attr_in2_max.attr, - &dev_attr_in3_max.attr, - &dev_attr_temp1_input.attr, - &dev_attr_temp2_input.attr, - &dev_attr_temp3_input.attr, - &dev_attr_temp1_min.attr, - &dev_attr_temp2_min.attr, - &dev_attr_temp3_min.attr, - &dev_attr_temp1_max.attr, - &dev_attr_temp2_max.attr, - &dev_attr_temp3_max.attr, + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan3_input.dev_attr.attr, + &sensor_dev_attr_fan4_input.dev_attr.attr, + &sensor_dev_attr_fan1_min.dev_attr.attr, + &sensor_dev_attr_fan2_min.dev_attr.attr, + &sensor_dev_attr_fan3_min.dev_attr.attr, + &sensor_dev_attr_fan4_min.dev_attr.attr, + &sensor_dev_attr_fan1_alarm.dev_attr.attr, + &sensor_dev_attr_fan2_alarm.dev_attr.attr, + &sensor_dev_attr_fan3_alarm.dev_attr.attr, + &sensor_dev_attr_fan4_alarm.dev_attr.attr, + + &sensor_dev_attr_pwm1.dev_attr.attr, + &sensor_dev_attr_pwm2.dev_attr.attr, + &sensor_dev_attr_pwm3.dev_attr.attr, + &sensor_dev_attr_pwm1_enable.dev_attr.attr, + &sensor_dev_attr_pwm2_enable.dev_attr.attr, + &sensor_dev_attr_pwm3_enable.dev_attr.attr, + + &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in0_min.dev_attr.attr, + &sensor_dev_attr_in1_min.dev_attr.attr, + &sensor_dev_attr_in2_min.dev_attr.attr, + &sensor_dev_attr_in3_min.dev_attr.attr, + &sensor_dev_attr_in0_max.dev_attr.attr, + &sensor_dev_attr_in1_max.dev_attr.attr, + &sensor_dev_attr_in2_max.dev_attr.attr, + &sensor_dev_attr_in3_max.dev_attr.attr, + &sensor_dev_attr_in0_alarm.dev_attr.attr, + &sensor_dev_attr_in1_alarm.dev_attr.attr, + &sensor_dev_attr_in2_alarm.dev_attr.attr, + &sensor_dev_attr_in3_alarm.dev_attr.attr, + + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, + &sensor_dev_attr_temp2_min.dev_attr.attr, + &sensor_dev_attr_temp3_min.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp3_max.dev_attr.attr, + &sensor_dev_attr_temp1_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_fault.dev_attr.attr, + &sensor_dev_attr_temp3_fault.dev_attr.attr, + + &sensor_dev_attr_pwm1_auto_channels.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_channels.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_channels.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_pwm_min.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_pwm_minctl.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_pwm_minctl.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_pwm_minctl.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_pwm_freq.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_pwm_freq.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_pwm_freq.dev_attr.attr, + + &sensor_dev_attr_temp1_auto_temp_off.dev_attr.attr, + &sensor_dev_attr_temp2_auto_temp_off.dev_attr.attr, + &sensor_dev_attr_temp3_auto_temp_off.dev_attr.attr, + &sensor_dev_attr_temp1_auto_temp_min.dev_attr.attr, + &sensor_dev_attr_temp2_auto_temp_min.dev_attr.attr, + &sensor_dev_attr_temp3_auto_temp_min.dev_attr.attr, + &sensor_dev_attr_temp1_auto_temp_max.dev_attr.attr, + &sensor_dev_attr_temp2_auto_temp_max.dev_attr.attr, + &sensor_dev_attr_temp3_auto_temp_max.dev_attr.attr, + &sensor_dev_attr_temp1_auto_temp_crit.dev_attr.attr, + &sensor_dev_attr_temp2_auto_temp_crit.dev_attr.attr, + &sensor_dev_attr_temp3_auto_temp_crit.dev_attr.attr, + &dev_attr_vrm.attr, &dev_attr_cpu0_vid.attr, &dev_attr_alarms.attr, - &dev_attr_pwm1_auto_channels.attr, - &dev_attr_pwm2_auto_channels.attr, - &dev_attr_pwm3_auto_channels.attr, - &dev_attr_pwm1_auto_pwm_min.attr, - &dev_attr_pwm2_auto_pwm_min.attr, - &dev_attr_pwm3_auto_pwm_min.attr, - &dev_attr_pwm1_auto_pwm_minctl.attr, - &dev_attr_pwm2_auto_pwm_minctl.attr, - &dev_attr_pwm3_auto_pwm_minctl.attr, - &dev_attr_pwm1_auto_pwm_freq.attr, - &dev_attr_pwm2_auto_pwm_freq.attr, - &dev_attr_pwm3_auto_pwm_freq.attr, - &dev_attr_temp1_auto_temp_off.attr, - &dev_attr_temp2_auto_temp_off.attr, - &dev_attr_temp3_auto_temp_off.attr, - &dev_attr_temp1_auto_temp_min.attr, - &dev_attr_temp2_auto_temp_min.attr, - &dev_attr_temp3_auto_temp_min.attr, - &dev_attr_temp1_auto_temp_max.attr, - &dev_attr_temp2_auto_temp_max.attr, - &dev_attr_temp3_auto_temp_max.attr, - &dev_attr_temp1_auto_temp_crit.attr, - &dev_attr_temp2_auto_temp_crit.attr, - &dev_attr_temp3_auto_temp_crit.attr, - NULL }; @@ -1092,16 +1056,36 @@ static const struct attribute_group lm85_group = { .attrs = lm85_attributes, }; -static struct attribute *lm85_attributes_opt[] = { - &dev_attr_in4_input.attr, - &dev_attr_in4_min.attr, - &dev_attr_in4_max.attr, +static struct attribute *lm85_attributes_in4[] = { + &sensor_dev_attr_in4_input.dev_attr.attr, + &sensor_dev_attr_in4_min.dev_attr.attr, + &sensor_dev_attr_in4_max.dev_attr.attr, + &sensor_dev_attr_in4_alarm.dev_attr.attr, + NULL +}; + +static const struct attribute_group lm85_group_in4 = { + .attrs = lm85_attributes_in4, +}; +static struct attribute *lm85_attributes_in567[] = { + &sensor_dev_attr_in5_input.dev_attr.attr, + &sensor_dev_attr_in6_input.dev_attr.attr, + &sensor_dev_attr_in7_input.dev_attr.attr, + &sensor_dev_attr_in5_min.dev_attr.attr, + &sensor_dev_attr_in6_min.dev_attr.attr, + &sensor_dev_attr_in7_min.dev_attr.attr, + &sensor_dev_attr_in5_max.dev_attr.attr, + &sensor_dev_attr_in6_max.dev_attr.attr, + &sensor_dev_attr_in7_max.dev_attr.attr, + &sensor_dev_attr_in5_alarm.dev_attr.attr, + &sensor_dev_attr_in6_alarm.dev_attr.attr, + &sensor_dev_attr_in7_alarm.dev_attr.attr, NULL }; -static const struct attribute_group lm85_group_opt = { - .attrs = lm85_attributes_opt, +static const struct attribute_group lm85_group_in567 = { + .attrs = lm85_attributes_in567, }; static int lm85_detect(struct i2c_adapter *adapter, int address, @@ -1249,17 +1233,19 @@ static int lm85_detect(struct i2c_adapter *adapter, int address, as a sixth digital VID input rather than an analog input. */ data->vid = lm85_read_value(new_client, LM85_REG_VID); if (!(kind == adt7463 && (data->vid & 0x80))) - if ((err = device_create_file(&new_client->dev, - &dev_attr_in4_input)) - || (err = device_create_file(&new_client->dev, - &dev_attr_in4_min)) - || (err = device_create_file(&new_client->dev, - &dev_attr_in4_max))) + if ((err = sysfs_create_group(&new_client->dev.kobj, + &lm85_group_in4))) goto ERROR3; - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + /* The EMC6D100 has 3 additional voltage inputs */ + if (kind == emc6d100) + if ((err = sysfs_create_group(&new_client->dev.kobj, + &lm85_group_in567))) + goto ERROR3; + + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto ERROR3; } @@ -1268,7 +1254,9 @@ static int lm85_detect(struct i2c_adapter *adapter, int address, /* Error out and cleanup code */ ERROR3: sysfs_remove_group(&new_client->dev.kobj, &lm85_group); - sysfs_remove_group(&new_client->dev.kobj, &lm85_group_opt); + sysfs_remove_group(&new_client->dev.kobj, &lm85_group_in4); + if (kind == emc6d100) + sysfs_remove_group(&new_client->dev.kobj, &lm85_group_in567); ERROR2: i2c_detach_client(new_client); ERROR1: @@ -1280,9 +1268,11 @@ static int lm85_detect(struct i2c_adapter *adapter, int address, static int lm85_detach_client(struct i2c_client *client) { struct lm85_data *data = i2c_get_clientdata(client); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm85_group); - sysfs_remove_group(&client->dev.kobj, &lm85_group_opt); + sysfs_remove_group(&client->dev.kobj, &lm85_group_in4); + if (data->type == emc6d100) + sysfs_remove_group(&client->dev.kobj, &lm85_group_in567); i2c_detach_client(client); kfree(data); return 0; @@ -1405,6 +1395,8 @@ static struct lm85_data *lm85_update_device(struct device *dev) /* Have to read extended bits first to "freeze" the * more significant bits that are read later. + * There are 2 additional resolution bits per channel and we + * have room for 4, so we shift them to the left. */ if ( (data->type == adm1027) || (data->type == adt7463) ) { int ext1 = lm85_read_value(client, @@ -1414,18 +1406,12 @@ static struct lm85_data *lm85_update_device(struct device *dev) int val = (ext1 << 8) + ext2; for(i = 0; i <= 4; i++) - data->in_ext[i] = (val>>(i * 2))&0x03; + data->in_ext[i] = ((val>>(i * 2))&0x03) << 2; for(i = 0; i <= 2; i++) - data->temp_ext[i] = (val>>((i + 5) * 2))&0x03; + data->temp_ext[i] = (val>>((i + 4) * 2))&0x0c; } - /* adc_scale is 2^(number of LSBs). There are 4 extra bits in - the emc6d102 and 2 in the adt7463 and adm1027. In all - other chips ext is always 0 and the value of scale is - irrelevant. So it is left in 4*/ - data->adc_scale = (data->type == emc6d102 ) ? 16 : 4; - data->vid = lm85_read_value(client, LM85_REG_VID); for (i = 0; i <= 3; ++i) { diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c index 988ae1c4aada..28cdff0c556b 100644 --- a/drivers/hwmon/lm87.c +++ b/drivers/hwmon/lm87.c @@ -58,6 +58,7 @@ #include <linux/jiffies.h> #include <linux/i2c.h> #include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> #include <linux/hwmon-vid.h> #include <linux/err.h> #include <linux/mutex.h> @@ -129,7 +130,7 @@ static u8 LM87_REG_TEMP_LOW[3] = { 0x3A, 0x38, 0x2C }; (((val) < 0 ? (val)-500 : (val)+500) / 1000)) #define FAN_FROM_REG(reg,div) ((reg) == 255 || (reg) == 0 ? 0 : \ - 1350000 + (reg)*(div) / 2) / ((reg)*(div)) + (1350000 + (reg)*(div) / 2) / ((reg)*(div))) #define FAN_TO_REG(val,div) ((val)*(div) * 255 <= 1350000 ? 255 : \ (1350000 + (val)*(div) / 2) / ((val)*(div))) @@ -145,7 +146,7 @@ static u8 LM87_REG_TEMP_LOW[3] = { 0x3A, 0x38, 0x2C }; #define CHAN_NO_FAN(nr) (1 << (nr)) #define CHAN_TEMP3 (1 << 2) #define CHAN_VCC_5V (1 << 3) -#define CHAN_NO_VID (1 << 8) +#define CHAN_NO_VID (1 << 7) /* * Functions declaration @@ -176,7 +177,7 @@ static struct i2c_driver lm87_driver = { struct lm87_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* In jiffies */ @@ -500,7 +501,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) { - struct lm87_data *data = lm87_update_device(dev); + struct lm87_data *data = dev_get_drvdata(dev); return sprintf(buf, "%d\n", data->vrm); } static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -531,6 +532,29 @@ static ssize_t set_aout(struct device *dev, struct device_attribute *attr, const } static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout); +static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct lm87_data *data = lm87_update_device(dev); + int bitnr = to_sensor_dev_attr(attr)->index; + return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); +} +static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); +static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2); +static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3); +static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8); +static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9); +static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6); +static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 7); +static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4); +static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5); +static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 5); +static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6); +static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7); +static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 14); +static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 15); + /* * Real code */ @@ -546,24 +570,31 @@ static struct attribute *lm87_attributes[] = { &dev_attr_in1_input.attr, &dev_attr_in1_min.attr, &dev_attr_in1_max.attr, + &sensor_dev_attr_in1_alarm.dev_attr.attr, &dev_attr_in2_input.attr, &dev_attr_in2_min.attr, &dev_attr_in2_max.attr, + &sensor_dev_attr_in2_alarm.dev_attr.attr, &dev_attr_in3_input.attr, &dev_attr_in3_min.attr, &dev_attr_in3_max.attr, + &sensor_dev_attr_in3_alarm.dev_attr.attr, &dev_attr_in4_input.attr, &dev_attr_in4_min.attr, &dev_attr_in4_max.attr, + &sensor_dev_attr_in4_alarm.dev_attr.attr, &dev_attr_temp1_input.attr, &dev_attr_temp1_max.attr, &dev_attr_temp1_min.attr, &dev_attr_temp1_crit.attr, + &sensor_dev_attr_temp1_alarm.dev_attr.attr, &dev_attr_temp2_input.attr, &dev_attr_temp2_max.attr, &dev_attr_temp2_min.attr, &dev_attr_temp2_crit.attr, + &sensor_dev_attr_temp2_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_fault.dev_attr.attr, &dev_attr_alarms.attr, &dev_attr_aout_output.attr, @@ -579,30 +610,38 @@ static struct attribute *lm87_attributes_opt[] = { &dev_attr_in6_input.attr, &dev_attr_in6_min.attr, &dev_attr_in6_max.attr, + &sensor_dev_attr_in6_alarm.dev_attr.attr, &dev_attr_fan1_input.attr, &dev_attr_fan1_min.attr, &dev_attr_fan1_div.attr, + &sensor_dev_attr_fan1_alarm.dev_attr.attr, &dev_attr_in7_input.attr, &dev_attr_in7_min.attr, &dev_attr_in7_max.attr, + &sensor_dev_attr_in7_alarm.dev_attr.attr, &dev_attr_fan2_input.attr, &dev_attr_fan2_min.attr, &dev_attr_fan2_div.attr, + &sensor_dev_attr_fan2_alarm.dev_attr.attr, &dev_attr_temp3_input.attr, &dev_attr_temp3_max.attr, &dev_attr_temp3_min.attr, &dev_attr_temp3_crit.attr, + &sensor_dev_attr_temp3_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_fault.dev_attr.attr, &dev_attr_in0_input.attr, &dev_attr_in0_min.attr, &dev_attr_in0_max.attr, + &sensor_dev_attr_in0_alarm.dev_attr.attr, &dev_attr_in5_input.attr, &dev_attr_in5_min.attr, &dev_attr_in5_max.attr, + &sensor_dev_attr_in5_alarm.dev_attr.attr, &dev_attr_cpu0_vid.attr, &dev_attr_vrm.attr, @@ -690,7 +729,9 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind) || (err = device_create_file(&new_client->dev, &dev_attr_in6_min)) || (err = device_create_file(&new_client->dev, - &dev_attr_in6_max))) + &dev_attr_in6_max)) + || (err = device_create_file(&new_client->dev, + &sensor_dev_attr_in6_alarm.dev_attr))) goto exit_remove; } else { if ((err = device_create_file(&new_client->dev, @@ -698,7 +739,9 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind) || (err = device_create_file(&new_client->dev, &dev_attr_fan1_min)) || (err = device_create_file(&new_client->dev, - &dev_attr_fan1_div))) + &dev_attr_fan1_div)) + || (err = device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_alarm.dev_attr))) goto exit_remove; } @@ -708,7 +751,9 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind) || (err = device_create_file(&new_client->dev, &dev_attr_in7_min)) || (err = device_create_file(&new_client->dev, - &dev_attr_in7_max))) + &dev_attr_in7_max)) + || (err = device_create_file(&new_client->dev, + &sensor_dev_attr_in7_alarm.dev_attr))) goto exit_remove; } else { if ((err = device_create_file(&new_client->dev, @@ -716,7 +761,9 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind) || (err = device_create_file(&new_client->dev, &dev_attr_fan2_min)) || (err = device_create_file(&new_client->dev, - &dev_attr_fan2_div))) + &dev_attr_fan2_div)) + || (err = device_create_file(&new_client->dev, + &sensor_dev_attr_fan2_alarm.dev_attr))) goto exit_remove; } @@ -728,7 +775,11 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind) || (err = device_create_file(&new_client->dev, &dev_attr_temp3_min)) || (err = device_create_file(&new_client->dev, - &dev_attr_temp3_crit))) + &dev_attr_temp3_crit)) + || (err = device_create_file(&new_client->dev, + &sensor_dev_attr_temp3_alarm.dev_attr)) + || (err = device_create_file(&new_client->dev, + &sensor_dev_attr_temp3_fault.dev_attr))) goto exit_remove; } else { if ((err = device_create_file(&new_client->dev, @@ -738,11 +789,15 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind) || (err = device_create_file(&new_client->dev, &dev_attr_in0_max)) || (err = device_create_file(&new_client->dev, + &sensor_dev_attr_in0_alarm.dev_attr)) + || (err = device_create_file(&new_client->dev, &dev_attr_in5_input)) || (err = device_create_file(&new_client->dev, &dev_attr_in5_min)) || (err = device_create_file(&new_client->dev, - &dev_attr_in5_max))) + &dev_attr_in5_max)) + || (err = device_create_file(&new_client->dev, + &sensor_dev_attr_in5_alarm.dev_attr))) goto exit_remove; } @@ -755,9 +810,9 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind) goto exit_remove; } - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove; } @@ -816,7 +871,7 @@ static int lm87_detach_client(struct i2c_client *client) struct lm87_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm87_group); sysfs_remove_group(&client->dev.kobj, &lm87_group_opt); diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index af541d67245d..960df9fa75af 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -41,7 +41,8 @@ * http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578 * Note that there is no easy way to differentiate between the three * variants. The extra address and features of the MAX6659 are not - * supported by this driver. + * supported by this driver. These chips lack the remote temperature + * offset feature. * * This driver also supports the MAX6680 and MAX6681, two other sensor * chips made by Maxim. These are quite similar to the other Maxim @@ -214,7 +215,7 @@ static struct i2c_driver lm90_driver = { struct lm90_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -226,9 +227,10 @@ struct lm90_data { 2: local high limit 3: local critical limit 4: remote critical limit */ - s16 temp11[3]; /* 0: remote input + s16 temp11[4]; /* 0: remote input 1: remote low limit - 2: remote high limit */ + 2: remote high limit + 3: remote offset (except max6657) */ u8 temp_hyst; u8 alarms; /* bitvector */ }; @@ -282,11 +284,13 @@ static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr, static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) { - static const u8 reg[4] = { + static const u8 reg[6] = { LM90_REG_W_REMOTE_LOWH, LM90_REG_W_REMOTE_LOWL, LM90_REG_W_REMOTE_HIGHH, LM90_REG_W_REMOTE_HIGHL, + LM90_REG_W_REMOTE_OFFSH, + LM90_REG_W_REMOTE_OFFSL, }; struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); @@ -367,6 +371,8 @@ static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp8, static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temphyst, set_temphyst, 3); static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 4); +static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO, show_temp11, + set_temp11, 3); /* Individual alarm files */ static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0); @@ -652,10 +658,15 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind) &dev_attr_pec))) goto exit_remove_files; } + if (data->kind != max6657) { + if ((err = device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_offset.dev_attr))) + goto exit_remove_files; + } - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -707,9 +718,12 @@ static int lm90_detach_client(struct i2c_client *client) struct lm90_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm90_group); device_remove_file(&client->dev, &dev_attr_pec); + if (data->kind != max6657) + device_remove_file(&client->dev, + &sensor_dev_attr_temp2_offset.dev_attr); if ((err = i2c_detach_client(client))) return err; @@ -763,6 +777,13 @@ static struct lm90_data *lm90_update_device(struct device *dev) if (lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH, &newh) == 0 && lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHL, &l) == 0) data->temp11[2] = (newh << 8) | l; + if (data->kind != max6657) { + if (lm90_read_reg(client, LM90_REG_R_REMOTE_OFFSH, + &newh) == 0 + && lm90_read_reg(client, LM90_REG_R_REMOTE_OFFSL, + &l) == 0) + data->temp11[3] = (newh << 8) | l; + } lm90_read_reg(client, LM90_REG_R_STATUS, &data->alarms); data->last_updated = jiffies; diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c index 30b536333f14..61d1bd1d5b6e 100644 --- a/drivers/hwmon/lm92.c +++ b/drivers/hwmon/lm92.c @@ -96,7 +96,7 @@ static struct i2c_driver lm92_driver; /* Client data (each client gets its own) */ struct lm92_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -379,9 +379,9 @@ static int lm92_detect(struct i2c_adapter *adapter, int address, int kind) if ((err = sysfs_create_group(&new_client->dev.kobj, &lm92_group))) goto exit_detach; - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove; } @@ -409,7 +409,7 @@ static int lm92_detach_client(struct i2c_client *client) struct lm92_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm92_group); if ((err = i2c_detach_client(client))) diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c index d84f8bf6f284..ea61946a4bf7 100644 --- a/drivers/hwmon/lm93.c +++ b/drivers/hwmon/lm93.c @@ -201,7 +201,7 @@ struct block1_t { */ struct lm93_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; unsigned long last_updated; /* In jiffies */ @@ -413,7 +413,7 @@ static int LM93_TEMP_FROM_REG(u8 reg) /* TEMP: 1/1000 degrees C (-128C to +127C) REG: 1C/bit, two's complement */ -static u8 LM93_TEMP_TO_REG(int temp) +static u8 LM93_TEMP_TO_REG(long temp) { int ntemp = SENSORS_LIMIT(temp, LM93_TEMP_MIN, LM93_TEMP_MAX); ntemp += (ntemp<0 ? -500 : 500); @@ -1268,7 +1268,7 @@ static ssize_t store_temp_min(struct device *dev, struct device_attribute *attr, int nr = (to_sensor_dev_attr(attr))->index; struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); + long val = simple_strtol(buf, NULL, 10); mutex_lock(&data->update_lock); data->temp_lim[nr].min = LM93_TEMP_TO_REG(val); @@ -1298,7 +1298,7 @@ static ssize_t store_temp_max(struct device *dev, struct device_attribute *attr, int nr = (to_sensor_dev_attr(attr))->index; struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); + long val = simple_strtol(buf, NULL, 10); mutex_lock(&data->update_lock); data->temp_lim[nr].max = LM93_TEMP_TO_REG(val); @@ -1329,7 +1329,7 @@ static ssize_t store_temp_auto_base(struct device *dev, int nr = (to_sensor_dev_attr(attr))->index; struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); + long val = simple_strtol(buf, NULL, 10); mutex_lock(&data->update_lock); data->block10.base[nr] = LM93_TEMP_TO_REG(val); @@ -1360,7 +1360,7 @@ static ssize_t store_temp_auto_boost(struct device *dev, int nr = (to_sensor_dev_attr(attr))->index; struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); + long val = simple_strtol(buf, NULL, 10); mutex_lock(&data->update_lock); data->boost[nr] = LM93_TEMP_TO_REG(val); @@ -2078,8 +2078,8 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr, return sprintf(buf,"%d\n",LM93_VID_FROM_REG(data->vid[nr])); } -static SENSOR_DEVICE_ATTR(vid1, S_IRUGO, show_vid, NULL, 0); -static SENSOR_DEVICE_ATTR(vid2, S_IRUGO, show_vid, NULL, 1); +static SENSOR_DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL, 0); +static SENSOR_DEVICE_ATTR(cpu1_vid, S_IRUGO, show_vid, NULL, 1); static ssize_t show_prochot(struct device *dev, struct device_attribute *attr, char *buf) @@ -2431,8 +2431,8 @@ static struct attribute *lm93_attrs[] = { &sensor_dev_attr_pwm2_auto_spinup_time.dev_attr.attr, &dev_attr_pwm_auto_prochot_ramp.attr, &dev_attr_pwm_auto_vrdhot_ramp.attr, - &sensor_dev_attr_vid1.dev_attr.attr, - &sensor_dev_attr_vid2.dev_attr.attr, + &sensor_dev_attr_cpu0_vid.dev_attr.attr, + &sensor_dev_attr_cpu1_vid.dev_attr.attr, &sensor_dev_attr_prochot1.dev_attr.attr, &sensor_dev_attr_prochot2.dev_attr.attr, &sensor_dev_attr_prochot1_avg.dev_attr.attr, @@ -2590,11 +2590,11 @@ static int lm93_detect(struct i2c_adapter *adapter, int address, int kind) goto err_detach; /* Register hwmon driver class */ - data->class_dev = hwmon_device_register(&client->dev); - if ( !IS_ERR(data->class_dev)) + data->hwmon_dev = hwmon_device_register(&client->dev); + if ( !IS_ERR(data->hwmon_dev)) return 0; - err = PTR_ERR(data->class_dev); + err = PTR_ERR(data->hwmon_dev); dev_err(&client->dev, "error registering hwmon device.\n"); sysfs_remove_group(&client->dev.kobj, &lm93_attr_grp); err_detach: @@ -2619,7 +2619,7 @@ static int lm93_detach_client(struct i2c_client *client) struct lm93_data *data = i2c_get_clientdata(client); int err = 0; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm93_attr_grp); err = i2c_detach_client(client); diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c index 2f58f651f03a..38a44c3d6cee 100644 --- a/drivers/hwmon/max1619.c +++ b/drivers/hwmon/max1619.c @@ -105,7 +105,7 @@ static struct i2c_driver max1619_driver = { struct max1619_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -293,9 +293,9 @@ static int max1619_detect(struct i2c_adapter *adapter, int address, int kind) if ((err = sysfs_create_group(&new_client->dev.kobj, &max1619_group))) goto exit_detach; - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -331,7 +331,7 @@ static int max1619_detach_client(struct i2c_client *client) struct max1619_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &max1619_group); if ((err = i2c_detach_client(client))) diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c index 8415664f33c2..755570c1f4eb 100644 --- a/drivers/hwmon/max6650.c +++ b/drivers/hwmon/max6650.c @@ -128,7 +128,7 @@ static struct i2c_driver max6650_driver = { struct max6650_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -523,11 +523,11 @@ static int max6650_detect(struct i2c_adapter *adapter, int address, int kind) if (err) goto err_detach; - data->class_dev = hwmon_device_register(&client->dev); - if (!IS_ERR(data->class_dev)) + data->hwmon_dev = hwmon_device_register(&client->dev); + if (!IS_ERR(data->hwmon_dev)) return 0; - err = PTR_ERR(data->class_dev); + err = PTR_ERR(data->hwmon_dev); dev_err(&client->dev, "error registering hwmon device.\n"); sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp); err_detach: @@ -543,7 +543,7 @@ static int max6650_detach_client(struct i2c_client *client) int err; sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); err = i2c_detach_client(client); if (!err) kfree(data); diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c index f57c75d59a5b..9d660133d517 100644 --- a/drivers/hwmon/pc87360.c +++ b/drivers/hwmon/pc87360.c @@ -180,7 +180,7 @@ static inline u8 PWM_TO_REG(int val, int inv) struct pc87360_data { const char *name; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex lock; struct mutex update_lock; char valid; /* !=0 if following fields are valid */ @@ -500,7 +500,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) { - struct pc87360_data *data = pc87360_update_device(dev); + struct pc87360_data *data = dev_get_drvdata(dev); return sprintf(buf, "%u\n", data->vrm); } static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1054,9 +1054,9 @@ static int __devinit pc87360_probe(struct platform_device *pdev) if ((err = device_create_file(dev, &dev_attr_name))) goto ERROR3; - data->class_dev = hwmon_device_register(dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto ERROR3; } return 0; @@ -1083,7 +1083,7 @@ static int __devexit pc87360_remove(struct platform_device *pdev) struct pc87360_data *data = platform_get_drvdata(pdev); int i; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); device_remove_file(&pdev->dev, &dev_attr_name); sysfs_remove_group(&pdev->dev.kobj, &pc8736x_temp_group); diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c index 2915bc4ad0d5..d40509ad6ae6 100644 --- a/drivers/hwmon/pc87427.c +++ b/drivers/hwmon/pc87427.c @@ -42,7 +42,7 @@ static struct platform_device *pdev; device is using banked registers) and the register cache (needed to keep the data in the registers and the cache in sync at any time). */ struct pc87427_data { - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex lock; int address[2]; const char *name; @@ -454,9 +454,9 @@ static int __devinit pc87427_probe(struct platform_device *pdev) goto exit_remove_files; } - data->class_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); dev_err(&pdev->dev, "Class registration failed (%d)\n", err); goto exit_remove_files; } @@ -484,7 +484,7 @@ static int __devexit pc87427_remove(struct platform_device *pdev) struct resource *res; int i; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); device_remove_file(&pdev->dev, &dev_attr_name); for (i = 0; i < 8; i++) { if (!(data->fan_enabled & (1 << i))) diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c index 92956eb3f3c1..860b71ccbb86 100644 --- a/drivers/hwmon/sis5595.c +++ b/drivers/hwmon/sis5595.c @@ -163,7 +163,7 @@ static inline u8 DIV_TO_REG(int val) struct sis5595_data { unsigned short addr; const char *name; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex lock; struct mutex update_lock; @@ -517,7 +517,7 @@ static int __devinit sis5595_probe(struct platform_device *pdev) platform_set_drvdata(pdev, data); /* Check revision and pin registers to determine whether 4 or 5 voltages */ - pci_read_config_byte(s_bridge, PCI_REVISION_ID, &data->revision); + data->revision = s_bridge->revision; /* 4 voltages, 1 temp */ data->maxins = 3; if (data->revision >= REV2MIN) { @@ -557,9 +557,9 @@ static int __devinit sis5595_probe(struct platform_device *pdev) goto exit_remove_files; } - data->class_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -580,7 +580,7 @@ static int __devexit sis5595_remove(struct platform_device *pdev) { struct sis5595_data *data = platform_get_drvdata(pdev); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&pdev->dev.kobj, &sis5595_group); sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_opt); @@ -739,11 +739,10 @@ static int __devinit sis5595_pci_probe(struct pci_dev *dev, int *i; for (i = blacklist; *i != 0; i++) { - struct pci_dev *dev; - dev = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL); - if (dev) { - dev_err(&dev->dev, "Looked for SIS5595 but found unsupported device %.4x\n", *i); - pci_dev_put(dev); + struct pci_dev *d; + if ((d = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL))) { + dev_err(&d->dev, "Looked for SIS5595 but found unsupported device %.4x\n", *i); + pci_dev_put(d); return -ENODEV; } } diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c index 45266b30ce1d..0b57d2ea2cf7 100644 --- a/drivers/hwmon/smsc47b397.c +++ b/drivers/hwmon/smsc47b397.c @@ -94,7 +94,7 @@ static u8 smsc47b397_reg_temp[] = {0x25, 0x26, 0x27, 0x80}; struct smsc47b397_data { unsigned short addr; const char *name; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex lock; struct mutex update_lock; @@ -222,7 +222,7 @@ static int __devexit smsc47b397_remove(struct platform_device *pdev) struct smsc47b397_data *data = platform_get_drvdata(pdev); struct resource *res; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&pdev->dev.kobj, &smsc47b397_group); res = platform_get_resource(pdev, IORESOURCE_IO, 0); release_region(res->start, SMSC_EXTENT); @@ -272,9 +272,9 @@ static int __devinit smsc47b397_probe(struct platform_device *pdev) if ((err = sysfs_create_group(&dev->kobj, &smsc47b397_group))) goto error_free; - data->class_dev = hwmon_device_register(dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto error_remove; } diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c index d3181967f167..a10a380868e2 100644 --- a/drivers/hwmon/smsc47m1.c +++ b/drivers/hwmon/smsc47m1.c @@ -116,7 +116,7 @@ struct smsc47m1_data { unsigned short addr; const char *name; enum chips type; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; unsigned long last_updated; /* In jiffies */ @@ -553,7 +553,7 @@ static int __devinit smsc47m1_probe(struct platform_device *pdev) || (err = device_create_file(dev, &sensor_dev_attr_fan3_div.dev_attr))) goto error_remove_files; - } else + } else if (data->type == smsc47m2) dev_dbg(dev, "Fan 3 not enabled by hardware, skipping\n"); if (pwm1) { @@ -580,7 +580,7 @@ static int __devinit smsc47m1_probe(struct platform_device *pdev) || (err = device_create_file(dev, &sensor_dev_attr_pwm3_enable.dev_attr))) goto error_remove_files; - } else + } else if (data->type == smsc47m2) dev_dbg(dev, "PWM 3 not enabled by hardware, skipping\n"); if ((err = device_create_file(dev, &dev_attr_alarms))) @@ -588,9 +588,9 @@ static int __devinit smsc47m1_probe(struct platform_device *pdev) if ((err = device_create_file(dev, &dev_attr_name))) goto error_remove_files; - data->class_dev = hwmon_device_register(dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto error_remove_files; } @@ -611,7 +611,7 @@ static int __devexit smsc47m1_remove(struct platform_device *pdev) struct smsc47m1_data *data = platform_get_drvdata(pdev); struct resource *res; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&pdev->dev.kobj, &smsc47m1_group); res = platform_get_resource(pdev, IORESOURCE_IO, 0); diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c index d3a3ba04cb0f..b87552652588 100644 --- a/drivers/hwmon/smsc47m192.c +++ b/drivers/hwmon/smsc47m192.c @@ -97,7 +97,7 @@ static inline int TEMP_FROM_REG(s8 val) struct smsc47m192_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ @@ -334,7 +334,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) { - struct smsc47m192_data *data = smsc47m192_update_device(dev); + struct smsc47m192_data *data = dev_get_drvdata(dev); return sprintf(buf, "%d\n", data->vrm); } @@ -553,9 +553,9 @@ static int smsc47m192_detect(struct i2c_adapter *adapter, int address, goto exit_remove_files; } - data->class_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -577,7 +577,7 @@ static int smsc47m192_detach_client(struct i2c_client *client) struct smsc47m192_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &smsc47m192_group); sysfs_remove_group(&client->dev.kobj, &smsc47m192_group_in4); diff --git a/drivers/hwmon/thmc50.c b/drivers/hwmon/thmc50.c index 9395b52d9b99..04dd7699b3ac 100644 --- a/drivers/hwmon/thmc50.c +++ b/drivers/hwmon/thmc50.c @@ -46,6 +46,11 @@ I2C_CLIENT_MODULE_PARM(adm1022_temp3, "List of adapter,address pairs " #define THMC50_REG_COMPANY_ID 0x3E #define THMC50_REG_DIE_CODE 0x3F #define THMC50_REG_ANALOG_OUT 0x19 +/* + * The mirror status register cannot be used as + * reading it does not clear alarms. + */ +#define THMC50_REG_INTR 0x41 const static u8 THMC50_REG_TEMP[] = { 0x27, 0x26, 0x20 }; const static u8 THMC50_REG_TEMP_MIN[] = { 0x3A, 0x38, 0x2C }; @@ -56,7 +61,7 @@ const static u8 THMC50_REG_TEMP_MAX[] = { 0x39, 0x37, 0x2B }; /* Each client has this additional data */ struct thmc50_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; enum chips type; @@ -69,6 +74,7 @@ struct thmc50_data { s8 temp_max[3]; s8 temp_min[3]; u8 analog_out; + u8 alarms; }; static int thmc50_attach_adapter(struct i2c_adapter *adapter); @@ -180,6 +186,15 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, return count; } +static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int index = to_sensor_dev_attr(attr)->index; + struct thmc50_data *data = thmc50_update_device(dev); + + return sprintf(buf, "%u\n", (data->alarms >> index) & 1); +} + #define temp_reg(offset) \ static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp, \ NULL, offset - 1); \ @@ -192,6 +207,12 @@ temp_reg(1); temp_reg(2); temp_reg(3); +static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5); +static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 1); +static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 7); +static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 2); + static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_analog_out, set_analog_out, 0); static SENSOR_DEVICE_ATTR(pwm1_mode, S_IRUGO, show_pwm_mode, NULL, 0); @@ -200,9 +221,12 @@ static struct attribute *thmc50_attributes[] = { &sensor_dev_attr_temp1_max.dev_attr.attr, &sensor_dev_attr_temp1_min.dev_attr.attr, &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_alarm.dev_attr.attr, &sensor_dev_attr_temp2_max.dev_attr.attr, &sensor_dev_attr_temp2_min.dev_attr.attr, &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_fault.dev_attr.attr, &sensor_dev_attr_pwm1.dev_attr.attr, &sensor_dev_attr_pwm1_mode.dev_attr.attr, NULL @@ -213,15 +237,17 @@ static const struct attribute_group thmc50_group = { }; /* for ADM1022 3rd temperature mode */ -static struct attribute *adm1022_attributes[] = { +static struct attribute *temp3_attributes[] = { &sensor_dev_attr_temp3_max.dev_attr.attr, &sensor_dev_attr_temp3_min.dev_attr.attr, &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp3_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_fault.dev_attr.attr, NULL }; -static const struct attribute_group adm1022_group = { - .attrs = adm1022_attributes, +static const struct attribute_group temp3_group = { + .attrs = temp3_attributes, }; static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind) @@ -233,7 +259,7 @@ static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind) struct thmc50_data *data; struct device *dev; int err = 0; - const char *type_name = ""; + const char *type_name; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { pr_debug("thmc50: detect failed, " @@ -283,13 +309,9 @@ static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind) pr_debug("thmc50: Detection of THMC50/ADM1022 failed\n"); goto exit_free; } - pr_debug("thmc50: Detected %s (version %x, revision %x)\n", - type_name, (revision >> 4) - 0xc, revision & 0xf); data->type = kind; - if (kind == thmc50) - type_name = "thmc50"; - else if (kind == adm1022) { + if (kind == adm1022) { int id = i2c_adapter_id(client->adapter); int i; @@ -302,7 +324,11 @@ static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind) data->has_temp3 = 1; break; } + } else { + type_name = "thmc50"; } + pr_debug("thmc50: Detected %s (version %x, revision %x)\n", + type_name, (revision >> 4) - 0xc, revision & 0xf); /* Fill in the remaining client fields & put it into the global list */ strlcpy(client->name, type_name, I2C_NAME_SIZE); @@ -319,23 +345,23 @@ static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind) goto exit_detach; /* Register ADM1022 sysfs hooks */ - if (data->type == adm1022) + if (data->has_temp3) if ((err = sysfs_create_group(&client->dev.kobj, - &adm1022_group))) + &temp3_group))) goto exit_remove_sysfs_thmc50; /* Register a new directory entry with module sensors */ - data->class_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_sysfs; } return 0; exit_remove_sysfs: - if (data->type == adm1022) - sysfs_remove_group(&client->dev.kobj, &adm1022_group); + if (data->has_temp3) + sysfs_remove_group(&client->dev.kobj, &temp3_group); exit_remove_sysfs_thmc50: sysfs_remove_group(&client->dev.kobj, &thmc50_group); exit_detach: @@ -358,10 +384,10 @@ static int thmc50_detach_client(struct i2c_client *client) struct thmc50_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &thmc50_group); - if (data->type == adm1022) - sysfs_remove_group(&client->dev.kobj, &adm1022_group); + if (data->has_temp3) + sysfs_remove_group(&client->dev.kobj, &temp3_group); if ((err = i2c_detach_client(client))) return err; @@ -414,6 +440,8 @@ static struct thmc50_data *thmc50_update_device(struct device *dev) } data->analog_out = i2c_smbus_read_byte_data(client, THMC50_REG_ANALOG_OUT); + data->alarms = + i2c_smbus_read_byte_data(client, THMC50_REG_INTR); data->last_updated = jiffies; data->valid = 1; } diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c index 696c8a2e5374..8f63dada6019 100644 --- a/drivers/hwmon/via686a.c +++ b/drivers/hwmon/via686a.c @@ -294,7 +294,7 @@ static inline long TEMP_FROM_REG10(u16 val) struct via686a_data { unsigned short addr; const char *name; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ @@ -627,9 +627,9 @@ static int __devinit via686a_probe(struct platform_device *pdev) if ((err = sysfs_create_group(&pdev->dev.kobj, &via686a_group))) goto exit_free; - data->class_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -648,7 +648,7 @@ static int __devexit via686a_remove(struct platform_device *pdev) { struct via686a_data *data = platform_get_drvdata(pdev); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&pdev->dev.kobj, &via686a_group); release_region(data->addr, VIA686A_EXTENT); diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c index 9f3e332c5b7f..e69416465e6d 100644 --- a/drivers/hwmon/vt1211.c +++ b/drivers/hwmon/vt1211.c @@ -108,7 +108,7 @@ static const u8 bitalarmfan[] = {6, 7}; struct vt1211_data { unsigned short addr; const char *name; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* !=0 if following fields are valid */ @@ -1191,9 +1191,9 @@ static int __devinit vt1211_probe(struct platform_device *pdev) } /* Register device */ - data->class_dev = hwmon_device_register(dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); dev_err(dev, "Class registration failed (%d)\n", err); goto EXIT_DEV_REMOVE_SILENT; } @@ -1217,7 +1217,7 @@ static int __devexit vt1211_remove(struct platform_device *pdev) struct vt1211_data *data = platform_get_drvdata(pdev); struct resource *res; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); vt1211_remove_sysfs(pdev); platform_set_drvdata(pdev, NULL); kfree(data); diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c index 3e63eaf19041..2196a84603f5 100644 --- a/drivers/hwmon/vt8231.c +++ b/drivers/hwmon/vt8231.c @@ -148,7 +148,7 @@ struct vt8231_data { const char *name; struct mutex update_lock; - struct class_device *class_dev; + struct device *hwmon_dev; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ @@ -676,7 +676,7 @@ static struct pci_driver vt8231_pci_driver = { .probe = vt8231_pci_probe, }; -int vt8231_probe(struct platform_device *pdev) +static int vt8231_probe(struct platform_device *pdev) { struct resource *res; struct vt8231_data *data; @@ -726,9 +726,9 @@ int vt8231_probe(struct platform_device *pdev) } } - data->class_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } return 0; @@ -756,7 +756,7 @@ static int __devexit vt8231_remove(struct platform_device *pdev) struct vt8231_data *data = platform_get_drvdata(pdev); int i; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++) sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_volts[i]); diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index d9a9ec7dd84a..b15c6a998b72 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -223,7 +223,7 @@ temp1_from_reg(s8 reg) } static inline s8 -temp1_to_reg(int temp, int min, int max) +temp1_to_reg(long temp, int min, int max) { if (temp <= min) return min / 1000; @@ -256,7 +256,7 @@ struct w83627ehf_data { int addr; /* IO base of hw monitor block */ const char *name; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex lock; struct mutex update_lock; @@ -805,7 +805,7 @@ store_temp1_##reg(struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ struct w83627ehf_data *data = dev_get_drvdata(dev); \ - u32 val = simple_strtoul(buf, NULL, 10); \ + long val = simple_strtol(buf, NULL, 10); \ \ mutex_lock(&data->update_lock); \ data->temp1_##reg = temp1_to_reg(val, -128000, 127000); \ @@ -840,7 +840,7 @@ store_##reg(struct device *dev, struct device_attribute *attr, \ struct w83627ehf_data *data = dev_get_drvdata(dev); \ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \ int nr = sensor_attr->index; \ - u32 val = simple_strtoul(buf, NULL, 10); \ + long val = simple_strtol(buf, NULL, 10); \ \ mutex_lock(&data->update_lock); \ data->reg[nr] = LM75_TEMP_TO_REG(val); \ @@ -1384,9 +1384,9 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) goto exit_remove; } - data->class_dev = hwmon_device_register(dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove; } @@ -1406,7 +1406,7 @@ static int __devexit w83627ehf_remove(struct platform_device *pdev) { struct w83627ehf_data *data = platform_get_drvdata(pdev); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); w83627ehf_device_remove_files(&pdev->dev); release_region(data->addr, IOREGION_LENGTH); platform_set_drvdata(pdev, NULL); diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index 7a4a15f4bf8b..20ae425a1980 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c @@ -45,6 +45,7 @@ #include <linux/jiffies.h> #include <linux/platform_device.h> #include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> #include <linux/hwmon-vid.h> #include <linux/err.h> #include <linux/mutex.h> @@ -218,7 +219,7 @@ static const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 }; static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2, W83627THF_REG_PWM3 }; #define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \ - regpwm_627hf[(nr) - 1] : regpwm[(nr) - 1]) + regpwm_627hf[nr] : regpwm[nr]) #define W83627HF_REG_PWM_FREQ 0x5C /* Only for the 627HF */ @@ -263,7 +264,7 @@ static inline u8 FAN_TO_REG(long rpm, int div) /* TEMP: 0.001C/bit (-128C to +127C) REG: 1C/bit, two's complement */ -static u8 TEMP_TO_REG(int temp) +static u8 TEMP_TO_REG(long temp) { int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX); ntemp += (ntemp<0 ? -500 : 500); @@ -346,7 +347,7 @@ static inline u8 DIV_TO_REG(long val) struct w83627hf_data { unsigned short addr; const char *name; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex lock; enum chips type; @@ -372,11 +373,8 @@ struct w83627hf_data { u8 beep_enable; /* Boolean */ u8 pwm[3]; /* Register value */ u8 pwm_freq[3]; /* Register value */ - u16 sens[3]; /* 782D/783S only. - 1 = pentium diode; 2 = 3904 diode; - 3000-5000 = thermistor beta. - Default = 3435. - Other Betas unimplemented */ + u16 sens[3]; /* 1 = pentium diode; 2 = 3904 diode; + 4 = thermistor */ u8 vrm; u8 vrm_ovt; /* Register value, 627THF/637HF/687THF only */ }; @@ -391,6 +389,7 @@ static int __devexit w83627hf_remove(struct platform_device *pdev); static int w83627hf_read_value(struct w83627hf_data *data, u16 reg); static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value); +static void w83627hf_update_fan_div(struct w83627hf_data *data); static struct w83627hf_data *w83627hf_update_device(struct device *dev); static void w83627hf_init_device(struct platform_device *pdev); @@ -403,72 +402,71 @@ static struct platform_driver w83627hf_driver = { .remove = __devexit_p(w83627hf_remove), }; -/* following are the sysfs callback functions */ -#define show_in_reg(reg) \ -static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ -{ \ - struct w83627hf_data *data = w83627hf_update_device(dev); \ - return sprintf(buf,"%ld\n", (long)IN_FROM_REG(data->reg[nr])); \ +static ssize_t +show_in_input(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in[nr])); } -show_in_reg(in) -show_in_reg(in_min) -show_in_reg(in_max) - -#define store_in_reg(REG, reg) \ -static ssize_t \ -store_in_##reg (struct device *dev, const char *buf, size_t count, int nr) \ -{ \ - struct w83627hf_data *data = dev_get_drvdata(dev); \ - u32 val; \ - \ - val = simple_strtoul(buf, NULL, 10); \ - \ - mutex_lock(&data->update_lock); \ - data->in_##reg[nr] = IN_TO_REG(val); \ - w83627hf_write_value(data, W83781D_REG_IN_##REG(nr), \ - data->in_##reg[nr]); \ - \ - mutex_unlock(&data->update_lock); \ - return count; \ +static ssize_t +show_in_min(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in_min[nr])); } -store_in_reg(MIN, min) -store_in_reg(MAX, max) +static ssize_t +show_in_max(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in_max[nr])); +} +static ssize_t +store_in_min(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = dev_get_drvdata(dev); + long val = simple_strtol(buf, NULL, 10); -#define sysfs_in_offset(offset) \ -static ssize_t \ -show_regs_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in(dev, buf, offset); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL); + mutex_lock(&data->update_lock); + data->in_min[nr] = IN_TO_REG(val); + w83627hf_write_value(data, W83781D_REG_IN_MIN(nr), data->in_min[nr]); + mutex_unlock(&data->update_lock); + return count; +} +static ssize_t +store_in_max(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = dev_get_drvdata(dev); + long val = simple_strtol(buf, NULL, 10); -#define sysfs_in_reg_offset(reg, offset) \ -static ssize_t show_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_##reg (dev, buf, offset); \ -} \ -static ssize_t \ -store_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return store_in_##reg (dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, \ - show_regs_in_##reg##offset, store_regs_in_##reg##offset); - -#define sysfs_in_offsets(offset) \ -sysfs_in_offset(offset) \ -sysfs_in_reg_offset(min, offset) \ -sysfs_in_reg_offset(max, offset) - -sysfs_in_offsets(1); -sysfs_in_offsets(2); -sysfs_in_offsets(3); -sysfs_in_offsets(4); -sysfs_in_offsets(5); -sysfs_in_offsets(6); -sysfs_in_offsets(7); -sysfs_in_offsets(8); + mutex_lock(&data->update_lock); + data->in_max[nr] = IN_TO_REG(val); + w83627hf_write_value(data, W83781D_REG_IN_MAX(nr), data->in_max[nr]); + mutex_unlock(&data->update_lock); + return count; +} +#define sysfs_vin_decl(offset) \ +static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \ + show_in_input, NULL, offset); \ +static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO|S_IWUSR, \ + show_in_min, store_in_min, offset); \ +static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO|S_IWUSR, \ + show_in_max, store_in_max, offset); + +sysfs_vin_decl(1); +sysfs_vin_decl(2); +sysfs_vin_decl(3); +sysfs_vin_decl(4); +sysfs_vin_decl(5); +sysfs_vin_decl(6); +sysfs_vin_decl(7); +sysfs_vin_decl(8); /* use a different set of functions for in0 */ static ssize_t show_in_0(struct w83627hf_data *data, char *buf, u8 reg) @@ -566,134 +564,148 @@ static DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR, static DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR, show_regs_in_max0, store_regs_in_max0); -#define show_fan_reg(reg) \ -static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ -{ \ - struct w83627hf_data *data = w83627hf_update_device(dev); \ - return sprintf(buf,"%ld\n", \ - FAN_FROM_REG(data->reg[nr-1], \ - (long)DIV_FROM_REG(data->fan_div[nr-1]))); \ +static ssize_t +show_fan_input(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", FAN_FROM_REG(data->fan[nr], + (long)DIV_FROM_REG(data->fan_div[nr]))); } -show_fan_reg(fan); -show_fan_reg(fan_min); - static ssize_t -store_fan_min(struct device *dev, const char *buf, size_t count, int nr) +show_fan_min(struct device *dev, struct device_attribute *devattr, char *buf) { + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", FAN_FROM_REG(data->fan_min[nr], + (long)DIV_FROM_REG(data->fan_div[nr]))); +} +static ssize_t +store_fan_min(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = dev_get_drvdata(dev); - u32 val; - - val = simple_strtoul(buf, NULL, 10); + u32 val = simple_strtoul(buf, NULL, 10); mutex_lock(&data->update_lock); - data->fan_min[nr - 1] = - FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1])); - w83627hf_write_value(data, W83781D_REG_FAN_MIN(nr), - data->fan_min[nr - 1]); + data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); + w83627hf_write_value(data, W83781D_REG_FAN_MIN(nr+1), + data->fan_min[nr]); mutex_unlock(&data->update_lock); return count; } +#define sysfs_fan_decl(offset) \ +static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ + show_fan_input, NULL, offset - 1); \ +static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan_min, store_fan_min, offset - 1); -#define sysfs_fan_offset(offset) \ -static ssize_t show_regs_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan(dev, buf, offset); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL); +sysfs_fan_decl(1); +sysfs_fan_decl(2); +sysfs_fan_decl(3); -#define sysfs_fan_min_offset(offset) \ -static ssize_t show_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_min(dev, buf, offset); \ -} \ -static ssize_t \ -store_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_fan_min(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_regs_fan_min##offset, store_regs_fan_min##offset); - -sysfs_fan_offset(1); -sysfs_fan_min_offset(1); -sysfs_fan_offset(2); -sysfs_fan_min_offset(2); -sysfs_fan_offset(3); -sysfs_fan_min_offset(3); - -#define show_temp_reg(reg) \ -static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ -{ \ - struct w83627hf_data *data = w83627hf_update_device(dev); \ - if (nr >= 2) { /* TEMP2 and TEMP3 */ \ - return sprintf(buf,"%ld\n", \ - (long)LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \ - } else { /* TEMP1 */ \ - return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \ - } \ +static ssize_t +show_temp(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = w83627hf_update_device(dev); + if (nr >= 2) { /* TEMP2 and TEMP3 */ + return sprintf(buf, "%ld\n", + (long)LM75_TEMP_FROM_REG(data->temp_add[nr-2])); + } else { /* TEMP1 */ + return sprintf(buf, "%ld\n", (long)TEMP_FROM_REG(data->temp)); + } } -show_temp_reg(temp); -show_temp_reg(temp_max); -show_temp_reg(temp_max_hyst); -#define store_temp_reg(REG, reg) \ -static ssize_t \ -store_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \ -{ \ - struct w83627hf_data *data = dev_get_drvdata(dev); \ - u32 val; \ - \ - val = simple_strtoul(buf, NULL, 10); \ - \ - mutex_lock(&data->update_lock); \ - \ - if (nr >= 2) { /* TEMP2 and TEMP3 */ \ - data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \ - w83627hf_write_value(data, W83781D_REG_TEMP_##REG(nr), \ - data->temp_##reg##_add[nr-2]); \ - } else { /* TEMP1 */ \ - data->temp_##reg = TEMP_TO_REG(val); \ - w83627hf_write_value(data, W83781D_REG_TEMP_##REG(nr), \ - data->temp_##reg); \ - } \ - \ - mutex_unlock(&data->update_lock); \ - return count; \ +static ssize_t +show_temp_max(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = w83627hf_update_device(dev); + if (nr >= 2) { /* TEMP2 and TEMP3 */ + return sprintf(buf, "%ld\n", + (long)LM75_TEMP_FROM_REG(data->temp_max_add[nr-2])); + } else { /* TEMP1 */ + return sprintf(buf, "%ld\n", + (long)TEMP_FROM_REG(data->temp_max)); + } } -store_temp_reg(OVER, max); -store_temp_reg(HYST, max_hyst); -#define sysfs_temp_offset(offset) \ -static ssize_t \ -show_regs_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp(dev, buf, offset); \ -} \ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL); +static ssize_t +show_temp_max_hyst(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = w83627hf_update_device(dev); + if (nr >= 2) { /* TEMP2 and TEMP3 */ + return sprintf(buf, "%ld\n", + (long)LM75_TEMP_FROM_REG(data->temp_max_hyst_add[nr-2])); + } else { /* TEMP1 */ + return sprintf(buf, "%ld\n", + (long)TEMP_FROM_REG(data->temp_max_hyst)); + } +} -#define sysfs_temp_reg_offset(reg, offset) \ -static ssize_t show_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_##reg (dev, buf, offset); \ -} \ -static ssize_t \ -store_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return store_temp_##reg (dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, \ - show_regs_temp_##reg##offset, store_regs_temp_##reg##offset); +static ssize_t +store_temp_max(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = dev_get_drvdata(dev); + long val = simple_strtol(buf, NULL, 10); -#define sysfs_temp_offsets(offset) \ -sysfs_temp_offset(offset) \ -sysfs_temp_reg_offset(max, offset) \ -sysfs_temp_reg_offset(max_hyst, offset) + mutex_lock(&data->update_lock); -sysfs_temp_offsets(1); -sysfs_temp_offsets(2); -sysfs_temp_offsets(3); + if (nr >= 2) { /* TEMP2 and TEMP3 */ + data->temp_max_add[nr-2] = LM75_TEMP_TO_REG(val); + w83627hf_write_value(data, W83781D_REG_TEMP_OVER(nr), + data->temp_max_add[nr-2]); + } else { /* TEMP1 */ + data->temp_max = TEMP_TO_REG(val); + w83627hf_write_value(data, W83781D_REG_TEMP_OVER(nr), + data->temp_max); + } + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t +store_temp_max_hyst(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = dev_get_drvdata(dev); + long val = simple_strtol(buf, NULL, 10); + + mutex_lock(&data->update_lock); + + if (nr >= 2) { /* TEMP2 and TEMP3 */ + data->temp_max_hyst_add[nr-2] = LM75_TEMP_TO_REG(val); + w83627hf_write_value(data, W83781D_REG_TEMP_HYST(nr), + data->temp_max_hyst_add[nr-2]); + } else { /* TEMP1 */ + data->temp_max_hyst = TEMP_TO_REG(val); + w83627hf_write_value(data, W83781D_REG_TEMP_HYST(nr), + data->temp_max_hyst); + } + mutex_unlock(&data->update_lock); + return count; +} + +#define sysfs_temp_decl(offset) \ +static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ + show_temp, NULL, offset); \ +static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO|S_IWUSR, \ + show_temp_max, store_temp_max, offset); \ +static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO|S_IWUSR, \ + show_temp_max_hyst, store_temp_max_hyst, offset); + +sysfs_temp_decl(1); +sysfs_temp_decl(2); +sysfs_temp_decl(3); static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) @@ -706,7 +718,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) { - struct w83627hf_data *data = w83627hf_update_device(dev); + struct w83627hf_data *data = dev_get_drvdata(dev); return sprintf(buf, "%ld\n", (long) data->vrm); } static ssize_t @@ -791,20 +803,22 @@ sysfs_beep(ENABLE, enable); sysfs_beep(MASK, mask); static ssize_t -show_fan_div_reg(struct device *dev, char *buf, int nr) +show_fan_div(struct device *dev, struct device_attribute *devattr, char *buf) { + int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = w83627hf_update_device(dev); return sprintf(buf, "%ld\n", - (long) DIV_FROM_REG(data->fan_div[nr - 1])); + (long) DIV_FROM_REG(data->fan_div[nr])); } - /* Note: we save and restore the fan minimum here, because its value is determined in part by the fan divisor. This follows the principle of least surprise; the user doesn't expect the fan minimum to change just because the divisor changed. */ static ssize_t -store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr) +store_fan_div(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) { + int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = dev_get_drvdata(dev); unsigned long min; u8 reg; @@ -836,92 +850,72 @@ store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr) return count; } -#define sysfs_fan_div(offset) \ -static ssize_t show_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_div_reg(dev, buf, offset); \ -} \ -static ssize_t \ -store_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return store_fan_div_reg(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ - show_regs_fan_div_##offset, store_regs_fan_div_##offset); - -sysfs_fan_div(1); -sysfs_fan_div(2); -sysfs_fan_div(3); +static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO|S_IWUSR, + show_fan_div, store_fan_div, 0); +static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO|S_IWUSR, + show_fan_div, store_fan_div, 1); +static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO|S_IWUSR, + show_fan_div, store_fan_div, 2); static ssize_t -show_pwm_reg(struct device *dev, char *buf, int nr) +show_pwm(struct device *dev, struct device_attribute *devattr, char *buf) { + int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = w83627hf_update_device(dev); - return sprintf(buf, "%ld\n", (long) data->pwm[nr - 1]); + return sprintf(buf, "%ld\n", (long) data->pwm[nr]); } static ssize_t -store_pwm_reg(struct device *dev, const char *buf, size_t count, int nr) +store_pwm(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) { + int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = dev_get_drvdata(dev); - u32 val; - - val = simple_strtoul(buf, NULL, 10); + u32 val = simple_strtoul(buf, NULL, 10); mutex_lock(&data->update_lock); if (data->type == w83627thf) { /* bits 0-3 are reserved in 627THF */ - data->pwm[nr - 1] = PWM_TO_REG(val) & 0xf0; + data->pwm[nr] = PWM_TO_REG(val) & 0xf0; w83627hf_write_value(data, W836X7HF_REG_PWM(data->type, nr), - data->pwm[nr - 1] | + data->pwm[nr] | (w83627hf_read_value(data, W836X7HF_REG_PWM(data->type, nr)) & 0x0f)); } else { - data->pwm[nr - 1] = PWM_TO_REG(val); + data->pwm[nr] = PWM_TO_REG(val); w83627hf_write_value(data, W836X7HF_REG_PWM(data->type, nr), - data->pwm[nr - 1]); + data->pwm[nr]); } mutex_unlock(&data->update_lock); return count; } -#define sysfs_pwm(offset) \ -static ssize_t show_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_pwm_reg(dev, buf, offset); \ -} \ -static ssize_t \ -store_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_pwm_reg(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ - show_regs_pwm_##offset, store_regs_pwm_##offset); - -sysfs_pwm(1); -sysfs_pwm(2); -sysfs_pwm(3); +static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0); +static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 1); +static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 2); static ssize_t -show_pwm_freq_reg(struct device *dev, char *buf, int nr) +show_pwm_freq(struct device *dev, struct device_attribute *devattr, char *buf) { + int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = w83627hf_update_device(dev); if (data->type == w83627hf) return sprintf(buf, "%ld\n", - pwm_freq_from_reg_627hf(data->pwm_freq[nr - 1])); + pwm_freq_from_reg_627hf(data->pwm_freq[nr])); else return sprintf(buf, "%ld\n", - pwm_freq_from_reg(data->pwm_freq[nr - 1])); + pwm_freq_from_reg(data->pwm_freq[nr])); } static ssize_t -store_pwm_freq_reg(struct device *dev, const char *buf, size_t count, int nr) +store_pwm_freq(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) { + int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = dev_get_drvdata(dev); static const u8 mask[]={0xF8, 0x8F}; u32 val; @@ -931,50 +925,42 @@ store_pwm_freq_reg(struct device *dev, const char *buf, size_t count, int nr) mutex_lock(&data->update_lock); if (data->type == w83627hf) { - data->pwm_freq[nr - 1] = pwm_freq_to_reg_627hf(val); + data->pwm_freq[nr] = pwm_freq_to_reg_627hf(val); w83627hf_write_value(data, W83627HF_REG_PWM_FREQ, - (data->pwm_freq[nr - 1] << ((nr - 1)*4)) | + (data->pwm_freq[nr] << (nr*4)) | (w83627hf_read_value(data, - W83627HF_REG_PWM_FREQ) & mask[nr - 1])); + W83627HF_REG_PWM_FREQ) & mask[nr])); } else { - data->pwm_freq[nr - 1] = pwm_freq_to_reg(val); - w83627hf_write_value(data, W83637HF_REG_PWM_FREQ[nr - 1], - data->pwm_freq[nr - 1]); + data->pwm_freq[nr] = pwm_freq_to_reg(val); + w83627hf_write_value(data, W83637HF_REG_PWM_FREQ[nr], + data->pwm_freq[nr]); } mutex_unlock(&data->update_lock); return count; } -#define sysfs_pwm_freq(offset) \ -static ssize_t show_regs_pwm_freq_##offset(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - return show_pwm_freq_reg(dev, buf, offset); \ -} \ -static ssize_t \ -store_regs_pwm_freq_##offset(struct device *dev, \ - struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_pwm_freq_reg(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(pwm##offset##_freq, S_IRUGO | S_IWUSR, \ - show_regs_pwm_freq_##offset, store_regs_pwm_freq_##offset); - -sysfs_pwm_freq(1); -sysfs_pwm_freq(2); -sysfs_pwm_freq(3); +static SENSOR_DEVICE_ATTR(pwm1_freq, S_IRUGO|S_IWUSR, + show_pwm_freq, store_pwm_freq, 0); +static SENSOR_DEVICE_ATTR(pwm2_freq, S_IRUGO|S_IWUSR, + show_pwm_freq, store_pwm_freq, 1); +static SENSOR_DEVICE_ATTR(pwm3_freq, S_IRUGO|S_IWUSR, + show_pwm_freq, store_pwm_freq, 2); static ssize_t -show_sensor_reg(struct device *dev, char *buf, int nr) +show_temp_type(struct device *dev, struct device_attribute *devattr, + char *buf) { + int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = w83627hf_update_device(dev); - return sprintf(buf, "%ld\n", (long) data->sens[nr - 1]); + return sprintf(buf, "%ld\n", (long) data->sens[nr]); } static ssize_t -store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr) +store_temp_type(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) { + int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = dev_get_drvdata(dev); u32 val, tmp; @@ -986,31 +972,35 @@ store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr) case 1: /* PII/Celeron diode */ tmp = w83627hf_read_value(data, W83781D_REG_SCFG1); w83627hf_write_value(data, W83781D_REG_SCFG1, - tmp | BIT_SCFG1[nr - 1]); + tmp | BIT_SCFG1[nr]); tmp = w83627hf_read_value(data, W83781D_REG_SCFG2); w83627hf_write_value(data, W83781D_REG_SCFG2, - tmp | BIT_SCFG2[nr - 1]); - data->sens[nr - 1] = val; + tmp | BIT_SCFG2[nr]); + data->sens[nr] = val; break; case 2: /* 3904 */ tmp = w83627hf_read_value(data, W83781D_REG_SCFG1); w83627hf_write_value(data, W83781D_REG_SCFG1, - tmp | BIT_SCFG1[nr - 1]); + tmp | BIT_SCFG1[nr]); tmp = w83627hf_read_value(data, W83781D_REG_SCFG2); w83627hf_write_value(data, W83781D_REG_SCFG2, - tmp & ~BIT_SCFG2[nr - 1]); - data->sens[nr - 1] = val; + tmp & ~BIT_SCFG2[nr]); + data->sens[nr] = val; break; - case W83781D_DEFAULT_BETA: /* thermistor */ + case W83781D_DEFAULT_BETA: + dev_warn(dev, "Sensor type %d is deprecated, please use 4 " + "instead\n", W83781D_DEFAULT_BETA); + /* fall through */ + case 4: /* thermistor */ tmp = w83627hf_read_value(data, W83781D_REG_SCFG1); w83627hf_write_value(data, W83781D_REG_SCFG1, - tmp & ~BIT_SCFG1[nr - 1]); - data->sens[nr - 1] = val; + tmp & ~BIT_SCFG1[nr]); + data->sens[nr] = val; break; default: dev_err(dev, - "Invalid sensor type %ld; must be 1, 2, or %d\n", - (long) val, W83781D_DEFAULT_BETA); + "Invalid sensor type %ld; must be 1, 2, or 4\n", + (long) val); break; } @@ -1018,25 +1008,16 @@ store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr) return count; } -#define sysfs_sensor(offset) \ -static ssize_t show_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_sensor_reg(dev, buf, offset); \ -} \ -static ssize_t \ -store_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_sensor_reg(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \ - show_regs_sensor_##offset, store_regs_sensor_##offset); +#define sysfs_temp_type(offset) \ +static SENSOR_DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \ + show_temp_type, store_temp_type, offset - 1); -sysfs_sensor(1); -sysfs_sensor(2); -sysfs_sensor(3); +sysfs_temp_type(1); +sysfs_temp_type(2); +sysfs_temp_type(3); -static ssize_t show_name(struct device *dev, struct device_attribute - *devattr, char *buf) +static ssize_t +show_name(struct device *dev, struct device_attribute *devattr, char *buf) { struct w83627hf_data *data = dev_get_drvdata(dev); @@ -1118,49 +1099,44 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr, return err; } +#define VIN_UNIT_ATTRS(_X_) \ + &sensor_dev_attr_in##_X_##_input.dev_attr.attr, \ + &sensor_dev_attr_in##_X_##_min.dev_attr.attr, \ + &sensor_dev_attr_in##_X_##_max.dev_attr.attr + +#define FAN_UNIT_ATTRS(_X_) \ + &sensor_dev_attr_fan##_X_##_input.dev_attr.attr, \ + &sensor_dev_attr_fan##_X_##_min.dev_attr.attr, \ + &sensor_dev_attr_fan##_X_##_div.dev_attr.attr + +#define TEMP_UNIT_ATTRS(_X_) \ + &sensor_dev_attr_temp##_X_##_input.dev_attr.attr, \ + &sensor_dev_attr_temp##_X_##_max.dev_attr.attr, \ + &sensor_dev_attr_temp##_X_##_max_hyst.dev_attr.attr, \ + &sensor_dev_attr_temp##_X_##_type.dev_attr.attr + static struct attribute *w83627hf_attributes[] = { &dev_attr_in0_input.attr, &dev_attr_in0_min.attr, &dev_attr_in0_max.attr, - &dev_attr_in2_input.attr, - &dev_attr_in2_min.attr, - &dev_attr_in2_max.attr, - &dev_attr_in3_input.attr, - &dev_attr_in3_min.attr, - &dev_attr_in3_max.attr, - &dev_attr_in4_input.attr, - &dev_attr_in4_min.attr, - &dev_attr_in4_max.attr, - &dev_attr_in7_input.attr, - &dev_attr_in7_min.attr, - &dev_attr_in7_max.attr, - &dev_attr_in8_input.attr, - &dev_attr_in8_min.attr, - &dev_attr_in8_max.attr, - - &dev_attr_fan1_input.attr, - &dev_attr_fan1_min.attr, - &dev_attr_fan1_div.attr, - &dev_attr_fan2_input.attr, - &dev_attr_fan2_min.attr, - &dev_attr_fan2_div.attr, - - &dev_attr_temp1_input.attr, - &dev_attr_temp1_max.attr, - &dev_attr_temp1_max_hyst.attr, - &dev_attr_temp1_type.attr, - &dev_attr_temp2_input.attr, - &dev_attr_temp2_max.attr, - &dev_attr_temp2_max_hyst.attr, - &dev_attr_temp2_type.attr, + VIN_UNIT_ATTRS(2), + VIN_UNIT_ATTRS(3), + VIN_UNIT_ATTRS(4), + VIN_UNIT_ATTRS(7), + VIN_UNIT_ATTRS(8), + + FAN_UNIT_ATTRS(1), + FAN_UNIT_ATTRS(2), + + TEMP_UNIT_ATTRS(1), + TEMP_UNIT_ATTRS(2), &dev_attr_alarms.attr, &dev_attr_beep_enable.attr, &dev_attr_beep_mask.attr, - &dev_attr_pwm1.attr, - &dev_attr_pwm2.attr, - + &sensor_dev_attr_pwm1.dev_attr.attr, + &sensor_dev_attr_pwm2.dev_attr.attr, &dev_attr_name.attr, NULL }; @@ -1170,30 +1146,17 @@ static const struct attribute_group w83627hf_group = { }; static struct attribute *w83627hf_attributes_opt[] = { - &dev_attr_in1_input.attr, - &dev_attr_in1_min.attr, - &dev_attr_in1_max.attr, - &dev_attr_in5_input.attr, - &dev_attr_in5_min.attr, - &dev_attr_in5_max.attr, - &dev_attr_in6_input.attr, - &dev_attr_in6_min.attr, - &dev_attr_in6_max.attr, - - &dev_attr_fan3_input.attr, - &dev_attr_fan3_min.attr, - &dev_attr_fan3_div.attr, - - &dev_attr_temp3_input.attr, - &dev_attr_temp3_max.attr, - &dev_attr_temp3_max_hyst.attr, - &dev_attr_temp3_type.attr, - - &dev_attr_pwm3.attr, - - &dev_attr_pwm1_freq.attr, - &dev_attr_pwm2_freq.attr, - &dev_attr_pwm3_freq.attr, + VIN_UNIT_ATTRS(1), + VIN_UNIT_ATTRS(5), + VIN_UNIT_ATTRS(6), + + FAN_UNIT_ATTRS(3), + TEMP_UNIT_ATTRS(3), + &sensor_dev_attr_pwm3.dev_attr.attr, + + &sensor_dev_attr_pwm1_freq.dev_attr.attr, + &sensor_dev_attr_pwm2_freq.dev_attr.attr, + &sensor_dev_attr_pwm3_freq.dev_attr.attr, NULL }; @@ -1244,6 +1207,7 @@ static int __devinit w83627hf_probe(struct platform_device *pdev) data->fan_min[0] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(1)); data->fan_min[1] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(2)); data->fan_min[2] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(3)); + w83627hf_update_fan_div(data); /* Register common device attributes */ if ((err = sysfs_create_group(&dev->kobj, &w83627hf_group))) @@ -1251,27 +1215,45 @@ static int __devinit w83627hf_probe(struct platform_device *pdev) /* Register chip-specific device attributes */ if (data->type == w83627hf || data->type == w83697hf) - if ((err = device_create_file(dev, &dev_attr_in5_input)) - || (err = device_create_file(dev, &dev_attr_in5_min)) - || (err = device_create_file(dev, &dev_attr_in5_max)) - || (err = device_create_file(dev, &dev_attr_in6_input)) - || (err = device_create_file(dev, &dev_attr_in6_min)) - || (err = device_create_file(dev, &dev_attr_in6_max)) - || (err = device_create_file(dev, &dev_attr_pwm1_freq)) - || (err = device_create_file(dev, &dev_attr_pwm2_freq))) + if ((err = device_create_file(dev, + &sensor_dev_attr_in5_input.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in5_min.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in5_max.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in6_input.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in6_min.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in6_max.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_pwm1_freq.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_pwm2_freq.dev_attr))) goto ERROR4; if (data->type != w83697hf) - if ((err = device_create_file(dev, &dev_attr_in1_input)) - || (err = device_create_file(dev, &dev_attr_in1_min)) - || (err = device_create_file(dev, &dev_attr_in1_max)) - || (err = device_create_file(dev, &dev_attr_fan3_input)) - || (err = device_create_file(dev, &dev_attr_fan3_min)) - || (err = device_create_file(dev, &dev_attr_fan3_div)) - || (err = device_create_file(dev, &dev_attr_temp3_input)) - || (err = device_create_file(dev, &dev_attr_temp3_max)) - || (err = device_create_file(dev, &dev_attr_temp3_max_hyst)) - || (err = device_create_file(dev, &dev_attr_temp3_type))) + if ((err = device_create_file(dev, + &sensor_dev_attr_in1_input.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in1_min.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in1_max.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_fan3_input.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_fan3_min.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_fan3_div.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_temp3_input.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_temp3_max.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_temp3_max_hyst.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_temp3_type.dev_attr))) goto ERROR4; if (data->type != w83697hf && data->vid != 0xff) { @@ -1285,18 +1267,22 @@ static int __devinit w83627hf_probe(struct platform_device *pdev) if (data->type == w83627thf || data->type == w83637hf || data->type == w83687thf) - if ((err = device_create_file(dev, &dev_attr_pwm3))) + if ((err = device_create_file(dev, + &sensor_dev_attr_pwm3.dev_attr))) goto ERROR4; if (data->type == w83637hf || data->type == w83687thf) - if ((err = device_create_file(dev, &dev_attr_pwm1_freq)) - || (err = device_create_file(dev, &dev_attr_pwm2_freq)) - || (err = device_create_file(dev, &dev_attr_pwm3_freq))) + if ((err = device_create_file(dev, + &sensor_dev_attr_pwm1_freq.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_pwm2_freq.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_pwm3_freq.dev_attr))) goto ERROR4; - data->class_dev = hwmon_device_register(dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto ERROR4; } @@ -1319,7 +1305,7 @@ static int __devexit w83627hf_remove(struct platform_device *pdev) struct w83627hf_data *data = platform_get_drvdata(pdev); struct resource *res; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group); sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group_opt); @@ -1333,6 +1319,24 @@ static int __devexit w83627hf_remove(struct platform_device *pdev) } +/* Registers 0x50-0x5f are banked */ +static inline void w83627hf_set_bank(struct w83627hf_data *data, u16 reg) +{ + if ((reg & 0x00f0) == 0x50) { + outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET); + outb_p(reg >> 8, data->addr + W83781D_DATA_REG_OFFSET); + } +} + +/* Not strictly necessary, but play it safe for now */ +static inline void w83627hf_reset_bank(struct w83627hf_data *data, u16 reg) +{ + if (reg & 0xff00) { + outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET); + outb_p(0, data->addr + W83781D_DATA_REG_OFFSET); + } +} + static int w83627hf_read_value(struct w83627hf_data *data, u16 reg) { int res, word_sized; @@ -1343,12 +1347,7 @@ static int w83627hf_read_value(struct w83627hf_data *data, u16 reg) && (((reg & 0x00ff) == 0x50) || ((reg & 0x00ff) == 0x53) || ((reg & 0x00ff) == 0x55)); - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - data->addr + W83781D_ADDR_REG_OFFSET); - outb_p(reg >> 8, - data->addr + W83781D_DATA_REG_OFFSET); - } + w83627hf_set_bank(data, reg); outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET); res = inb_p(data->addr + W83781D_DATA_REG_OFFSET); if (word_sized) { @@ -1358,11 +1357,7 @@ static int w83627hf_read_value(struct w83627hf_data *data, u16 reg) (res << 8) + inb_p(data->addr + W83781D_DATA_REG_OFFSET); } - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - data->addr + W83781D_ADDR_REG_OFFSET); - outb_p(0, data->addr + W83781D_DATA_REG_OFFSET); - } + w83627hf_reset_bank(data, reg); mutex_unlock(&data->lock); return res; } @@ -1433,12 +1428,7 @@ static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value) || ((reg & 0xff00) == 0x200)) && (((reg & 0x00ff) == 0x53) || ((reg & 0x00ff) == 0x55)); - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - data->addr + W83781D_ADDR_REG_OFFSET); - outb_p(reg >> 8, - data->addr + W83781D_DATA_REG_OFFSET); - } + w83627hf_set_bank(data, reg); outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET); if (word_sized) { outb_p(value >> 8, @@ -1448,11 +1438,7 @@ static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value) } outb_p(value & 0xff, data->addr + W83781D_DATA_REG_OFFSET); - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - data->addr + W83781D_ADDR_REG_OFFSET); - outb_p(0, data->addr + W83781D_DATA_REG_OFFSET); - } + w83627hf_reset_bank(data, reg); mutex_unlock(&data->lock); return 0; } @@ -1513,7 +1499,7 @@ static void __devinit w83627hf_init_device(struct platform_device *pdev) tmp = w83627hf_read_value(data, W83781D_REG_SCFG1); for (i = 1; i <= 3; i++) { if (!(tmp & BIT_SCFG1[i - 1])) { - data->sens[i - 1] = W83781D_DEFAULT_BETA; + data->sens[i - 1] = 4; } else { if (w83627hf_read_value (data, @@ -1556,6 +1542,24 @@ static void __devinit w83627hf_init_device(struct platform_device *pdev) | 0x01); } +static void w83627hf_update_fan_div(struct w83627hf_data *data) +{ + int reg; + + reg = w83627hf_read_value(data, W83781D_REG_VID_FANDIV); + data->fan_div[0] = (reg >> 4) & 0x03; + data->fan_div[1] = (reg >> 6) & 0x03; + if (data->type != w83697hf) { + data->fan_div[2] = (w83627hf_read_value(data, + W83781D_REG_PIN) >> 6) & 0x03; + } + reg = w83627hf_read_value(data, W83781D_REG_VBAT); + data->fan_div[0] |= (reg >> 3) & 0x04; + data->fan_div[1] |= (reg >> 4) & 0x04; + if (data->type != w83697hf) + data->fan_div[2] |= (reg >> 5) & 0x04; +} + static struct w83627hf_data *w83627hf_update_device(struct device *dev) { struct w83627hf_data *data = dev_get_drvdata(dev); @@ -1587,15 +1591,15 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev) w83627hf_read_value(data, W83781D_REG_FAN_MIN(i)); } - for (i = 1; i <= 3; i++) { + for (i = 0; i <= 2; i++) { u8 tmp = w83627hf_read_value(data, W836X7HF_REG_PWM(data->type, i)); /* bits 0-3 are reserved in 627THF */ if (data->type == w83627thf) tmp &= 0xf0; - data->pwm[i - 1] = tmp; - if(i == 2 && - (data->type == w83627hf || data->type == w83697hf)) + data->pwm[i] = tmp; + if (i == 1 && + (data->type == w83627hf || data->type == w83697hf)) break; } if (data->type == w83627hf) { @@ -1633,18 +1637,8 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev) w83627hf_read_value(data, W83781D_REG_TEMP_HYST(3)); } - i = w83627hf_read_value(data, W83781D_REG_VID_FANDIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = (i >> 6) & 0x03; - if (data->type != w83697hf) { - data->fan_div[2] = (w83627hf_read_value(data, - W83781D_REG_PIN) >> 6) & 0x03; - } - i = w83627hf_read_value(data, W83781D_REG_VBAT); - data->fan_div[0] |= (i >> 3) & 0x04; - data->fan_div[1] |= (i >> 4) & 0x04; - if (data->type != w83697hf) - data->fan_div[2] |= (i >> 5) & 0x04; + w83627hf_update_fan_div(data); + data->alarms = w83627hf_read_value(data, W83781D_REG_ALARM1) | (w83627hf_read_value(data, W83781D_REG_ALARM2) << 8) | diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index dcc941a5aaff..a6a1edfe7614 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -220,7 +220,7 @@ DIV_TO_REG(long val, enum chips type) the driver field to differentiate between I2C and ISA chips. */ struct w83781d_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex lock; enum chips type; @@ -251,9 +251,7 @@ struct w83781d_data { u8 pwm2_enable; /* Boolean */ u16 sens[3]; /* 782D/783S only. 1 = pentium diode; 2 = 3904 diode; - 3000-5000 = thermistor beta. - Default = 3435. - Other Betas unimplemented */ + 4 = thermistor */ u8 vrm; }; @@ -410,7 +408,7 @@ static ssize_t store_temp_##reg (struct device *dev, \ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \ struct w83781d_data *data = dev_get_drvdata(dev); \ int nr = attr->index; \ - s32 val; \ + long val; \ \ val = simple_strtol(buf, NULL, 10); \ \ @@ -456,7 +454,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) { - struct w83781d_data *data = w83781d_update_device(dev); + struct w83781d_data *data = dev_get_drvdata(dev); return sprintf(buf, "%ld\n", (long) data->vrm); } @@ -483,6 +481,39 @@ show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); +static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct w83781d_data *data = w83781d_update_device(dev); + int bitnr = to_sensor_dev_attr(attr)->index; + return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); +} + +/* The W83781D has a single alarm bit for temp2 and temp3 */ +static ssize_t show_temp3_alarm(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct w83781d_data *data = w83781d_update_device(dev); + int bitnr = (data->type == w83781d) ? 5 : 13; + return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); +} + +static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); +static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2); +static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3); +static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8); +static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9); +static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10); +static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16); +static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17); +static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6); +static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7); +static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11); +static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4); +static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5); +static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_temp3_alarm, NULL, 0); + static ssize_t show_beep_mask (struct device *dev, struct device_attribute *attr, char *buf) { struct w83781d_data *data = w83781d_update_device(dev); @@ -546,6 +577,100 @@ static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR, static DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR, show_beep_enable, store_beep_enable); +static ssize_t show_beep(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct w83781d_data *data = w83781d_update_device(dev); + int bitnr = to_sensor_dev_attr(attr)->index; + return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1); +} + +static ssize_t +store_beep(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct w83781d_data *data = dev_get_drvdata(dev); + int bitnr = to_sensor_dev_attr(attr)->index; + unsigned long bit; + u8 reg; + + bit = simple_strtoul(buf, NULL, 10); + if (bit & ~1) + return -EINVAL; + + mutex_lock(&data->update_lock); + if (bit) + data->beep_mask |= (1 << bitnr); + else + data->beep_mask &= ~(1 << bitnr); + + if (bitnr < 8) { + reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS1); + if (bit) + reg |= (1 << bitnr); + else + reg &= ~(1 << bitnr); + w83781d_write_value(data, W83781D_REG_BEEP_INTS1, reg); + } else if (bitnr < 16) { + reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS2); + if (bit) + reg |= (1 << (bitnr - 8)); + else + reg &= ~(1 << (bitnr - 8)); + w83781d_write_value(data, W83781D_REG_BEEP_INTS2, reg); + } else { + reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS3); + if (bit) + reg |= (1 << (bitnr - 16)); + else + reg &= ~(1 << (bitnr - 16)); + w83781d_write_value(data, W83781D_REG_BEEP_INTS3, reg); + } + mutex_unlock(&data->update_lock); + + return count; +} + +/* The W83781D has a single beep bit for temp2 and temp3 */ +static ssize_t show_temp3_beep(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct w83781d_data *data = w83781d_update_device(dev); + int bitnr = (data->type == w83781d) ? 5 : 13; + return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1); +} + +static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 0); +static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 1); +static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 2); +static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 3); +static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 8); +static SENSOR_DEVICE_ATTR(in5_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 9); +static SENSOR_DEVICE_ATTR(in6_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 10); +static SENSOR_DEVICE_ATTR(in7_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 16); +static SENSOR_DEVICE_ATTR(in8_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 17); +static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 6); +static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 7); +static SENSOR_DEVICE_ATTR(fan3_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 11); +static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 4); +static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 5); +static SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO, + show_temp3_beep, store_beep, 13); + static ssize_t show_fan_div(struct device *dev, struct device_attribute *da, char *buf) { @@ -721,15 +846,19 @@ store_sensor(struct device *dev, struct device_attribute *da, tmp & ~BIT_SCFG2[nr]); data->sens[nr] = val; break; - case W83781D_DEFAULT_BETA: /* thermistor */ + case W83781D_DEFAULT_BETA: + dev_warn(dev, "Sensor type %d is deprecated, please use 4 " + "instead\n", W83781D_DEFAULT_BETA); + /* fall through */ + case 4: /* thermistor */ tmp = w83781d_read_value(data, W83781D_REG_SCFG1); w83781d_write_value(data, W83781D_REG_SCFG1, tmp & ~BIT_SCFG1[nr]); data->sens[nr] = val; break; default: - dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or %d\n", - (long) val, W83781D_DEFAULT_BETA); + dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or 4\n", + (long) val); break; } @@ -875,17 +1004,23 @@ ERROR_SC_0: #define IN_UNIT_ATTRS(X) \ &sensor_dev_attr_in##X##_input.dev_attr.attr, \ &sensor_dev_attr_in##X##_min.dev_attr.attr, \ - &sensor_dev_attr_in##X##_max.dev_attr.attr + &sensor_dev_attr_in##X##_max.dev_attr.attr, \ + &sensor_dev_attr_in##X##_alarm.dev_attr.attr, \ + &sensor_dev_attr_in##X##_beep.dev_attr.attr #define FAN_UNIT_ATTRS(X) \ &sensor_dev_attr_fan##X##_input.dev_attr.attr, \ &sensor_dev_attr_fan##X##_min.dev_attr.attr, \ - &sensor_dev_attr_fan##X##_div.dev_attr.attr + &sensor_dev_attr_fan##X##_div.dev_attr.attr, \ + &sensor_dev_attr_fan##X##_alarm.dev_attr.attr, \ + &sensor_dev_attr_fan##X##_beep.dev_attr.attr #define TEMP_UNIT_ATTRS(X) \ &sensor_dev_attr_temp##X##_input.dev_attr.attr, \ &sensor_dev_attr_temp##X##_max.dev_attr.attr, \ - &sensor_dev_attr_temp##X##_max_hyst.dev_attr.attr + &sensor_dev_attr_temp##X##_max_hyst.dev_attr.attr, \ + &sensor_dev_attr_temp##X##_alarm.dev_attr.attr, \ + &sensor_dev_attr_temp##X##_beep.dev_attr.attr static struct attribute* w83781d_attributes[] = { IN_UNIT_ATTRS(0), @@ -944,7 +1079,11 @@ w83781d_create_files(struct device *dev, int kind, int is_isa) || (err = device_create_file(dev, &sensor_dev_attr_in1_min.dev_attr)) || (err = device_create_file(dev, - &sensor_dev_attr_in1_max.dev_attr))) + &sensor_dev_attr_in1_max.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in1_alarm.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in1_beep.dev_attr))) return err; } if (kind != as99127f && kind != w83781d && kind != w83783s) { @@ -955,11 +1094,19 @@ w83781d_create_files(struct device *dev, int kind, int is_isa) || (err = device_create_file(dev, &sensor_dev_attr_in7_max.dev_attr)) || (err = device_create_file(dev, + &sensor_dev_attr_in7_alarm.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in7_beep.dev_attr)) + || (err = device_create_file(dev, &sensor_dev_attr_in8_input.dev_attr)) || (err = device_create_file(dev, &sensor_dev_attr_in8_min.dev_attr)) || (err = device_create_file(dev, - &sensor_dev_attr_in8_max.dev_attr))) + &sensor_dev_attr_in8_max.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in8_alarm.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in8_beep.dev_attr))) return err; } if (kind != w83783s) { @@ -968,8 +1115,19 @@ w83781d_create_files(struct device *dev, int kind, int is_isa) || (err = device_create_file(dev, &sensor_dev_attr_temp3_max.dev_attr)) || (err = device_create_file(dev, - &sensor_dev_attr_temp3_max_hyst.dev_attr))) + &sensor_dev_attr_temp3_max_hyst.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_temp3_alarm.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_temp3_beep.dev_attr))) return err; + + if (kind != w83781d) + err = sysfs_chmod_file(&dev->kobj, + &sensor_dev_attr_temp3_alarm.dev_attr.attr, + S_IRUGO | S_IWUSR); + if (err) + return err; } if (kind != w83781d && kind != as99127f) { @@ -1156,9 +1314,9 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) if (err) goto ERROR4; - data->class_dev = hwmon_device_register(dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto ERROR4; } @@ -1192,7 +1350,7 @@ w83781d_detach_client(struct i2c_client *client) /* main client */ if (data) { - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &w83781d_group); sysfs_remove_group(&client->dev.kobj, &w83781d_group_opt); } @@ -1259,9 +1417,9 @@ w83781d_isa_probe(struct platform_device *pdev) if (err) goto exit_remove_files; - data->class_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -1283,7 +1441,7 @@ w83781d_isa_remove(struct platform_device *pdev) { struct w83781d_data *data = platform_get_drvdata(pdev); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&pdev->dev.kobj, &w83781d_group); sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt); device_remove_file(&pdev->dev, &dev_attr_name); @@ -1485,7 +1643,7 @@ w83781d_init_device(struct device *dev) tmp = w83781d_read_value(data, W83781D_REG_SCFG1); for (i = 1; i <= 3; i++) { if (!(tmp & BIT_SCFG1[i - 1])) { - data->sens[i - 1] = W83781D_DEFAULT_BETA; + data->sens[i - 1] = 4; } else { if (w83781d_read_value (data, diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c index 9e5f885368b4..b6f2ebf9f9cf 100644 --- a/drivers/hwmon/w83791d.c +++ b/drivers/hwmon/w83791d.c @@ -2,7 +2,7 @@ w83791d.c - Part of lm_sensors, Linux kernel modules for hardware monitoring - Copyright (C) 2006 Charles Spirakis <bezaur@gmail.com> + Copyright (C) 2006-2007 Charles Spirakis <bezaur@gmail.com> 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 @@ -247,7 +247,7 @@ static u8 div_to_reg(int nr, long val) struct w83791d_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* !=0 if following fields are valid */ @@ -384,6 +384,85 @@ static struct sensor_device_attribute sda_in_max[] = { SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9), }; + +static ssize_t show_beep(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = + to_sensor_dev_attr(attr); + struct w83791d_data *data = w83791d_update_device(dev); + int bitnr = sensor_attr->index; + + return sprintf(buf, "%d\n", (data->beep_mask >> bitnr) & 1); +} + +static ssize_t store_beep(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = + to_sensor_dev_attr(attr); + struct i2c_client *client = to_i2c_client(dev); + struct w83791d_data *data = i2c_get_clientdata(client); + int bitnr = sensor_attr->index; + int bytenr = bitnr / 8; + long val = simple_strtol(buf, NULL, 10) ? 1 : 0; + + mutex_lock(&data->update_lock); + + data->beep_mask &= ~(0xff << (bytenr * 8)); + data->beep_mask |= w83791d_read(client, W83791D_REG_BEEP_CTRL[bytenr]) + << (bytenr * 8); + + data->beep_mask &= ~(1 << bitnr); + data->beep_mask |= val << bitnr; + + w83791d_write(client, W83791D_REG_BEEP_CTRL[bytenr], + (data->beep_mask >> (bytenr * 8)) & 0xff); + + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = + to_sensor_dev_attr(attr); + struct w83791d_data *data = w83791d_update_device(dev); + int bitnr = sensor_attr->index; + + return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1); +} + +/* Note: The bitmask for the beep enable/disable is different than + the bitmask for the alarm. */ +static struct sensor_device_attribute sda_in_beep[] = { + SENSOR_ATTR(in0_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 0), + SENSOR_ATTR(in1_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 13), + SENSOR_ATTR(in2_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 2), + SENSOR_ATTR(in3_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 3), + SENSOR_ATTR(in4_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 8), + SENSOR_ATTR(in5_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 9), + SENSOR_ATTR(in6_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 10), + SENSOR_ATTR(in7_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 16), + SENSOR_ATTR(in8_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 17), + SENSOR_ATTR(in9_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 14), +}; + +static struct sensor_device_attribute sda_in_alarm[] = { + SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0), + SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1), + SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2), + SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3), + SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8), + SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9), + SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10), + SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 19), + SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 20), + SENSOR_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 14), +}; + #define show_fan_reg(reg) \ static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ char *buf) \ @@ -536,6 +615,22 @@ static struct sensor_device_attribute sda_fan_div[] = { show_fan_div, store_fan_div, 4), }; +static struct sensor_device_attribute sda_fan_beep[] = { + SENSOR_ATTR(fan1_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 6), + SENSOR_ATTR(fan2_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 7), + SENSOR_ATTR(fan3_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 11), + SENSOR_ATTR(fan4_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 21), + SENSOR_ATTR(fan5_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 22), +}; + +static struct sensor_device_attribute sda_fan_alarm[] = { + SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6), + SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7), + SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11), + SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 21), + SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 22), +}; + /* read/write the temperature1, includes measured value and limits */ static ssize_t show_temp1(struct device *dev, struct device_attribute *devattr, char *buf) @@ -618,6 +713,19 @@ static struct sensor_device_attribute_2 sda_temp_max_hyst[] = { show_temp23, store_temp23, 1, 2), }; +/* Note: The bitmask for the beep enable/disable is different than + the bitmask for the alarm. */ +static struct sensor_device_attribute sda_temp_beep[] = { + SENSOR_ATTR(temp1_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 4), + SENSOR_ATTR(temp2_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 5), + SENSOR_ATTR(temp3_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 1), +}; + +static struct sensor_device_attribute sda_temp_alarm[] = { + SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4), + SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5), + SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13), +}; /* get reatime status of all sensors items: voltage, temp, fan */ static ssize_t show_alarms_reg(struct device *dev, @@ -724,7 +832,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) { - struct w83791d_data *data = w83791d_update_device(dev); + struct w83791d_data *data = dev_get_drvdata(dev); return sprintf(buf, "%d\n", data->vrm); } @@ -749,17 +857,23 @@ static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); #define IN_UNIT_ATTRS(X) \ &sda_in_input[X].dev_attr.attr, \ &sda_in_min[X].dev_attr.attr, \ - &sda_in_max[X].dev_attr.attr + &sda_in_max[X].dev_attr.attr, \ + &sda_in_beep[X].dev_attr.attr, \ + &sda_in_alarm[X].dev_attr.attr #define FAN_UNIT_ATTRS(X) \ &sda_fan_input[X].dev_attr.attr, \ &sda_fan_min[X].dev_attr.attr, \ - &sda_fan_div[X].dev_attr.attr + &sda_fan_div[X].dev_attr.attr, \ + &sda_fan_beep[X].dev_attr.attr, \ + &sda_fan_alarm[X].dev_attr.attr #define TEMP_UNIT_ATTRS(X) \ &sda_temp_input[X].dev_attr.attr, \ &sda_temp_max[X].dev_attr.attr, \ - &sda_temp_max_hyst[X].dev_attr.attr + &sda_temp_max_hyst[X].dev_attr.attr, \ + &sda_temp_beep[X].dev_attr.attr, \ + &sda_temp_alarm[X].dev_attr.attr static struct attribute *w83791d_attributes[] = { IN_UNIT_ATTRS(0), @@ -1017,9 +1131,9 @@ static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind) goto error3; /* Everything is ready, now register the working device */ - data->class_dev = hwmon_device_register(dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto error4; } @@ -1051,7 +1165,7 @@ static int w83791d_detach_client(struct i2c_client *client) /* main client */ if (data) { - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &w83791d_group); } diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c index b0fa296740d1..f836198b705c 100644 --- a/drivers/hwmon/w83792d.c +++ b/drivers/hwmon/w83792d.c @@ -267,7 +267,7 @@ DIV_TO_REG(long val) struct w83792d_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; enum chips type; struct mutex update_lock; @@ -540,6 +540,15 @@ show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%d\n", data->alarms); } +static ssize_t show_alarm(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct w83792d_data *data = w83792d_update_device(dev); + return sprintf(buf, "%d\n", (data->alarms >> nr) & 1); +} + static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, char *buf) @@ -1015,6 +1024,25 @@ static SENSOR_DEVICE_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR, static SENSOR_DEVICE_ATTR_2(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 1, 4); static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); +static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); +static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 2); +static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 3); +static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 4); +static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 5); +static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 6); +static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 7); +static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 8); +static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 9); +static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 10); +static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 11); +static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 12); +static SENSOR_DEVICE_ATTR(fan7_alarm, S_IRUGO, show_alarm, NULL, 15); +static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 19); +static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 20); +static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 21); +static SENSOR_DEVICE_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 22); +static SENSOR_DEVICE_ATTR(fan6_alarm, S_IRUGO, show_alarm, NULL, 23); static DEVICE_ATTR(chassis, S_IRUGO, show_regs_chassis, NULL); static DEVICE_ATTR(chassis_clear, S_IRUGO | S_IWUSR, show_chassis_clear, store_chassis_clear); @@ -1123,26 +1151,30 @@ static SENSOR_DEVICE_ATTR(fan6_div, S_IWUSR | S_IRUGO, static SENSOR_DEVICE_ATTR(fan7_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 7); -static struct attribute *w83792d_attributes_fan[4][4] = { +static struct attribute *w83792d_attributes_fan[4][5] = { { &sensor_dev_attr_fan4_input.dev_attr.attr, &sensor_dev_attr_fan4_min.dev_attr.attr, &sensor_dev_attr_fan4_div.dev_attr.attr, + &sensor_dev_attr_fan4_alarm.dev_attr.attr, NULL }, { &sensor_dev_attr_fan5_input.dev_attr.attr, &sensor_dev_attr_fan5_min.dev_attr.attr, &sensor_dev_attr_fan5_div.dev_attr.attr, + &sensor_dev_attr_fan5_alarm.dev_attr.attr, NULL }, { &sensor_dev_attr_fan6_input.dev_attr.attr, &sensor_dev_attr_fan6_min.dev_attr.attr, &sensor_dev_attr_fan6_div.dev_attr.attr, + &sensor_dev_attr_fan6_alarm.dev_attr.attr, NULL }, { &sensor_dev_attr_fan7_input.dev_attr.attr, &sensor_dev_attr_fan7_min.dev_attr.attr, &sensor_dev_attr_fan7_div.dev_attr.attr, + &sensor_dev_attr_fan7_alarm.dev_attr.attr, NULL } }; @@ -1182,6 +1214,15 @@ static struct attribute *w83792d_attributes[] = { &sensor_dev_attr_in8_input.dev_attr.attr, &sensor_dev_attr_in8_max.dev_attr.attr, &sensor_dev_attr_in8_min.dev_attr.attr, + &sensor_dev_attr_in0_alarm.dev_attr.attr, + &sensor_dev_attr_in1_alarm.dev_attr.attr, + &sensor_dev_attr_in2_alarm.dev_attr.attr, + &sensor_dev_attr_in3_alarm.dev_attr.attr, + &sensor_dev_attr_in4_alarm.dev_attr.attr, + &sensor_dev_attr_in5_alarm.dev_attr.attr, + &sensor_dev_attr_in6_alarm.dev_attr.attr, + &sensor_dev_attr_in7_alarm.dev_attr.attr, + &sensor_dev_attr_in8_alarm.dev_attr.attr, &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, @@ -1191,6 +1232,9 @@ static struct attribute *w83792d_attributes[] = { &sensor_dev_attr_temp3_input.dev_attr.attr, &sensor_dev_attr_temp3_max.dev_attr.attr, &sensor_dev_attr_temp3_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_alarm.dev_attr.attr, &sensor_dev_attr_pwm1.dev_attr.attr, &sensor_dev_attr_pwm1_mode.dev_attr.attr, &sensor_dev_attr_pwm1_enable.dev_attr.attr, @@ -1233,12 +1277,15 @@ static struct attribute *w83792d_attributes[] = { &sensor_dev_attr_fan1_input.dev_attr.attr, &sensor_dev_attr_fan1_min.dev_attr.attr, &sensor_dev_attr_fan1_div.dev_attr.attr, + &sensor_dev_attr_fan1_alarm.dev_attr.attr, &sensor_dev_attr_fan2_input.dev_attr.attr, &sensor_dev_attr_fan2_min.dev_attr.attr, &sensor_dev_attr_fan2_div.dev_attr.attr, + &sensor_dev_attr_fan2_alarm.dev_attr.attr, &sensor_dev_attr_fan3_input.dev_attr.attr, &sensor_dev_attr_fan3_min.dev_attr.attr, &sensor_dev_attr_fan3_div.dev_attr.attr, + &sensor_dev_attr_fan3_alarm.dev_attr.attr, NULL }; @@ -1396,9 +1443,9 @@ w83792d_detect(struct i2c_adapter *adapter, int address, int kind) &w83792d_group_fan[3]))) goto exit_remove_files; - data->class_dev = hwmon_device_register(dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -1433,7 +1480,7 @@ w83792d_detach_client(struct i2c_client *client) /* main client */ if (data) { - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &w83792d_group); for (i = 0; i < ARRAY_SIZE(w83792d_group_fan); i++) sysfs_remove_group(&client->dev.kobj, diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c index 253ffaf1568a..48599e1cc554 100644 --- a/drivers/hwmon/w83793.c +++ b/drivers/hwmon/w83793.c @@ -179,7 +179,7 @@ static inline s8 TEMP_TO_REG(long val, s8 min, s8 max) struct w83793_data { struct i2c_client client; struct i2c_client *lm75[2]; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ @@ -1075,7 +1075,7 @@ static int w83793_detach_client(struct i2c_client *client) /* main client */ if (data) { - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); for (i = 0; i < ARRAY_SIZE(w83793_sensor_attr_2); i++) device_remove_file(dev, @@ -1434,9 +1434,9 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind) } } - data->class_dev = hwmon_device_register(dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove; } diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c index a3fcace412f0..b5db354e2f19 100644 --- a/drivers/hwmon/w83l785ts.c +++ b/drivers/hwmon/w83l785ts.c @@ -107,7 +107,7 @@ static struct i2c_driver w83l785ts_driver = { struct w83l785ts_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -247,9 +247,9 @@ static int w83l785ts_detect(struct i2c_adapter *adapter, int address, int kind) goto exit_remove; /* Register sysfs hooks */ - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove; } @@ -272,7 +272,7 @@ static int w83l785ts_detach_client(struct i2c_client *client) struct w83l785ts_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); device_remove_file(&client->dev, &sensor_dev_attr_temp1_input.dev_attr); device_remove_file(&client->dev, diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 9f3a4cd0b07f..de95c75efb41 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -75,11 +75,19 @@ config I2C_AMD8111 config I2C_AT91 tristate "Atmel AT91 I2C Two-Wire interface (TWI)" - depends on ARCH_AT91 && EXPERIMENTAL + depends on ARCH_AT91 && EXPERIMENTAL && BROKEN help This supports the use of the I2C interface on Atmel AT91 processors. + This driver is BROKEN because the controller which it uses + will easily trigger RX overrun and TX underrun errors. Using + low I2C clock rates may partially work around those issues + on some systems. Another serious problem is that there is no + documented way to issue repeated START conditions, as needed + to support combined I2C messages. Use the i2c-gpio driver + unless your system can cope with those limitations. + config I2C_AU1550 tristate "Au1550/Au1200 SMBus interface" depends on SOC_AU1550 || SOC_AU1200 @@ -106,6 +114,19 @@ config I2C_BLACKFIN_TWI_CLK_KHZ help The unit of the TWI clock is kHz. +config I2C_DAVINCI + tristate "DaVinci I2C driver" + depends on ARCH_DAVINCI + help + Support for TI DaVinci I2C controller driver. + + This driver can also be built as a module. If so, the module + will be called i2c-davinci. + + Please note that this driver might be needed to bring up other + devices such as DaVinci NIC. + For details please see http://www.ti.com/davinci + config I2C_ELEKTOR tristate "Elektor ISA card" depends on ISA && BROKEN_ON_SMP diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 5b752e4e1918..81d43c27cf93 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o obj-$(CONFIG_I2C_AT91) += i2c-at91.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o +obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index c9fca7b49267..5d1a27ef2504 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -326,7 +326,7 @@ static u32 amd8111_func(struct i2c_adapter *adapter) I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_PROC_CALL | - I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HWPEC_CALC; + I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_PEC; } static const struct i2c_algorithm smbus_algorithm = { diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c index d7e7c359fc36..2f684166c43d 100644 --- a/drivers/i2c/busses/i2c-au1550.c +++ b/drivers/i2c/busses/i2c-au1550.c @@ -48,17 +48,14 @@ wait_xfer_done(struct i2c_au1550_data *adap) sp = (volatile psc_smb_t *)(adap->psc_base); - /* Wait for Tx FIFO Underflow. + /* Wait for Tx Buffer Empty */ for (i = 0; i < adap->xfer_timeout; i++) { - stat = sp->psc_smbevnt; + stat = sp->psc_smbstat; au_sync(); - if ((stat & PSC_SMBEVNT_TU) != 0) { - /* Clear it. */ - sp->psc_smbevnt = PSC_SMBEVNT_TU; - au_sync(); + if ((stat & PSC_SMBSTAT_TE) != 0) return 0; - } + udelay(1); } diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 6311039dfe60..67224a424aba 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -44,7 +44,6 @@ #define TWI_I2C_MODE_COMBINED 0x04 struct bfin_twi_iface { - struct mutex twi_lock; int irq; spinlock_t lock; char read_write; @@ -228,12 +227,8 @@ static int bfin_twi_master_xfer(struct i2c_adapter *adap, if (!(bfin_read_TWI_CONTROL() & TWI_ENA)) return -ENXIO; - mutex_lock(&iface->twi_lock); - while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) { - mutex_unlock(&iface->twi_lock); yield(); - mutex_lock(&iface->twi_lock); } ret = 0; @@ -310,9 +305,6 @@ static int bfin_twi_master_xfer(struct i2c_adapter *adap, break; } - /* Release mutex */ - mutex_unlock(&iface->twi_lock); - return ret; } @@ -330,12 +322,8 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr, if (!(bfin_read_TWI_CONTROL() & TWI_ENA)) return -ENXIO; - mutex_lock(&iface->twi_lock); - while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) { - mutex_unlock(&iface->twi_lock); yield(); - mutex_lock(&iface->twi_lock); } iface->writeNum = 0; @@ -502,9 +490,6 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr, rc = (iface->result >= 0) ? 0 : -1; - /* Release mutex */ - mutex_unlock(&iface->twi_lock); - return rc; } @@ -555,7 +540,6 @@ static int i2c_bfin_twi_probe(struct platform_device *dev) struct i2c_adapter *p_adap; int rc; - mutex_init(&(iface->twi_lock)); spin_lock_init(&(iface->lock)); init_completion(&(iface->complete)); iface->irq = IRQ_TWI; diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c new file mode 100644 index 000000000000..bd7aaff35240 --- /dev/null +++ b/drivers/i2c/busses/i2c-davinci.c @@ -0,0 +1,586 @@ +/* + * TI DAVINCI I2C adapter driver. + * + * Copyright (C) 2006 Texas Instruments. + * Copyright (C) 2007 MontaVista Software Inc. + * + * Updated by Vinod & Sudhakar Feb 2005 + * + * ---------------------------------------------------------------------------- + * + * 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. + * ---------------------------------------------------------------------------- + * + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/clk.h> +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/io.h> + +#include <asm/hardware.h> +#include <asm/mach-types.h> + +#include <asm/arch/i2c.h> + +/* ----- global defines ----------------------------------------------- */ + +#define DAVINCI_I2C_TIMEOUT (1*HZ) +#define I2C_DAVINCI_INTR_ALL (DAVINCI_I2C_IMR_AAS | \ + DAVINCI_I2C_IMR_SCD | \ + DAVINCI_I2C_IMR_ARDY | \ + DAVINCI_I2C_IMR_NACK | \ + DAVINCI_I2C_IMR_AL) + +#define DAVINCI_I2C_OAR_REG 0x00 +#define DAVINCI_I2C_IMR_REG 0x04 +#define DAVINCI_I2C_STR_REG 0x08 +#define DAVINCI_I2C_CLKL_REG 0x0c +#define DAVINCI_I2C_CLKH_REG 0x10 +#define DAVINCI_I2C_CNT_REG 0x14 +#define DAVINCI_I2C_DRR_REG 0x18 +#define DAVINCI_I2C_SAR_REG 0x1c +#define DAVINCI_I2C_DXR_REG 0x20 +#define DAVINCI_I2C_MDR_REG 0x24 +#define DAVINCI_I2C_IVR_REG 0x28 +#define DAVINCI_I2C_EMDR_REG 0x2c +#define DAVINCI_I2C_PSC_REG 0x30 + +#define DAVINCI_I2C_IVR_AAS 0x07 +#define DAVINCI_I2C_IVR_SCD 0x06 +#define DAVINCI_I2C_IVR_XRDY 0x05 +#define DAVINCI_I2C_IVR_RDR 0x04 +#define DAVINCI_I2C_IVR_ARDY 0x03 +#define DAVINCI_I2C_IVR_NACK 0x02 +#define DAVINCI_I2C_IVR_AL 0x01 + +#define DAVINCI_I2C_STR_BB (1 << 12) +#define DAVINCI_I2C_STR_RSFULL (1 << 11) +#define DAVINCI_I2C_STR_SCD (1 << 5) +#define DAVINCI_I2C_STR_ARDY (1 << 2) +#define DAVINCI_I2C_STR_NACK (1 << 1) +#define DAVINCI_I2C_STR_AL (1 << 0) + +#define DAVINCI_I2C_MDR_NACK (1 << 15) +#define DAVINCI_I2C_MDR_STT (1 << 13) +#define DAVINCI_I2C_MDR_STP (1 << 11) +#define DAVINCI_I2C_MDR_MST (1 << 10) +#define DAVINCI_I2C_MDR_TRX (1 << 9) +#define DAVINCI_I2C_MDR_XA (1 << 8) +#define DAVINCI_I2C_MDR_IRS (1 << 5) + +#define DAVINCI_I2C_IMR_AAS (1 << 6) +#define DAVINCI_I2C_IMR_SCD (1 << 5) +#define DAVINCI_I2C_IMR_XRDY (1 << 4) +#define DAVINCI_I2C_IMR_RRDY (1 << 3) +#define DAVINCI_I2C_IMR_ARDY (1 << 2) +#define DAVINCI_I2C_IMR_NACK (1 << 1) +#define DAVINCI_I2C_IMR_AL (1 << 0) + +#define MOD_REG_BIT(val, mask, set) do { \ + if (set) { \ + val |= mask; \ + } else { \ + val &= ~mask; \ + } \ +} while (0) + +struct davinci_i2c_dev { + struct device *dev; + void __iomem *base; + struct completion cmd_complete; + struct clk *clk; + int cmd_err; + u8 *buf; + size_t buf_len; + int irq; + struct i2c_adapter adapter; +}; + +/* default platform data to use if not supplied in the platform_device */ +static struct davinci_i2c_platform_data davinci_i2c_platform_data_default = { + .bus_freq = 100, + .bus_delay = 0, +}; + +static inline void davinci_i2c_write_reg(struct davinci_i2c_dev *i2c_dev, + int reg, u16 val) +{ + __raw_writew(val, i2c_dev->base + reg); +} + +static inline u16 davinci_i2c_read_reg(struct davinci_i2c_dev *i2c_dev, int reg) +{ + return __raw_readw(i2c_dev->base + reg); +} + +/* + * This functions configures I2C and brings I2C out of reset. + * This function is called during I2C init function. This function + * also gets called if I2C encounters any errors. + */ +static int i2c_davinci_init(struct davinci_i2c_dev *dev) +{ + struct davinci_i2c_platform_data *pdata = dev->dev->platform_data; + u16 psc; + u32 clk; + u32 clkh; + u32 clkl; + u32 input_clock = clk_get_rate(dev->clk); + u16 w; + + if (!pdata) + pdata = &davinci_i2c_platform_data_default; + + /* put I2C into reset */ + w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG); + MOD_REG_BIT(w, DAVINCI_I2C_MDR_IRS, 0); + davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w); + + /* NOTE: I2C Clock divider programming info + * As per I2C specs the following formulas provide prescaler + * and low/high divider values + * input clk --> PSC Div -----------> ICCL/H Div --> output clock + * module clk + * + * output clk = module clk / (PSC + 1) [ (ICCL + d) + (ICCH + d) ] + * + * Thus, + * (ICCL + ICCH) = clk = (input clk / ((psc +1) * output clk)) - 2d; + * + * where if PSC == 0, d = 7, + * if PSC == 1, d = 6 + * if PSC > 1 , d = 5 + */ + + psc = 26; /* To get 1MHz clock */ + + clk = ((input_clock / (psc + 1)) / (pdata->bus_freq * 1000)) - 10; + clkh = (50 * clk) / 100; + clkl = clk - clkh; + + davinci_i2c_write_reg(dev, DAVINCI_I2C_PSC_REG, psc); + davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKH_REG, clkh); + davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKL_REG, clkl); + + dev_dbg(dev->dev, "CLK = %d\n", clk); + dev_dbg(dev->dev, "PSC = %d\n", + davinci_i2c_read_reg(dev, DAVINCI_I2C_PSC_REG)); + dev_dbg(dev->dev, "CLKL = %d\n", + davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKL_REG)); + dev_dbg(dev->dev, "CLKH = %d\n", + davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKH_REG)); + + /* Take the I2C module out of reset: */ + w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG); + MOD_REG_BIT(w, DAVINCI_I2C_MDR_IRS, 1); + davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w); + + /* Enable interrupts */ + davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, I2C_DAVINCI_INTR_ALL); + + return 0; +} + +/* + * Waiting for bus not busy + */ +static int i2c_davinci_wait_bus_not_busy(struct davinci_i2c_dev *dev, + char allow_sleep) +{ + unsigned long timeout; + + timeout = jiffies + DAVINCI_I2C_TIMEOUT; + while (davinci_i2c_read_reg(dev, DAVINCI_I2C_STR_REG) + & DAVINCI_I2C_STR_BB) { + if (time_after(jiffies, timeout)) { + dev_warn(dev->dev, + "timeout waiting for bus ready\n"); + return -ETIMEDOUT; + } + if (allow_sleep) + schedule_timeout(1); + } + + return 0; +} + +/* + * Low level master read/write transaction. This function is called + * from i2c_davinci_xfer. + */ +static int +i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) +{ + struct davinci_i2c_dev *dev = i2c_get_adapdata(adap); + struct davinci_i2c_platform_data *pdata = dev->dev->platform_data; + u32 flag; + u32 stat; + u16 w; + int r; + + if (msg->len == 0) + return -EINVAL; + + if (!pdata) + pdata = &davinci_i2c_platform_data_default; + /* Introduce a delay, required for some boards (e.g Davinci EVM) */ + if (pdata->bus_delay) + udelay(pdata->bus_delay); + + /* set the slave address */ + davinci_i2c_write_reg(dev, DAVINCI_I2C_SAR_REG, msg->addr); + + dev->buf = msg->buf; + dev->buf_len = msg->len; + + davinci_i2c_write_reg(dev, DAVINCI_I2C_CNT_REG, dev->buf_len); + + init_completion(&dev->cmd_complete); + dev->cmd_err = 0; + + /* Clear any pending interrupts by reading the IVR */ + stat = davinci_i2c_read_reg(dev, DAVINCI_I2C_IVR_REG); + + /* Take I2C out of reset, configure it as master and set the + * start bit */ + flag = DAVINCI_I2C_MDR_IRS | DAVINCI_I2C_MDR_MST | DAVINCI_I2C_MDR_STT; + + /* if the slave address is ten bit address, enable XA bit */ + if (msg->flags & I2C_M_TEN) + flag |= DAVINCI_I2C_MDR_XA; + if (!(msg->flags & I2C_M_RD)) + flag |= DAVINCI_I2C_MDR_TRX; + if (stop) + flag |= DAVINCI_I2C_MDR_STP; + + /* Enable receive or transmit interrupts */ + w = davinci_i2c_read_reg(dev, DAVINCI_I2C_IMR_REG); + if (msg->flags & I2C_M_RD) + MOD_REG_BIT(w, DAVINCI_I2C_IMR_RRDY, 1); + else + MOD_REG_BIT(w, DAVINCI_I2C_IMR_XRDY, 1); + davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, w); + + /* write the data into mode register */ + davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag); + + r = wait_for_completion_interruptible_timeout(&dev->cmd_complete, + DAVINCI_I2C_TIMEOUT); + dev->buf_len = 0; + if (r < 0) + return r; + + if (r == 0) { + dev_err(dev->dev, "controller timed out\n"); + i2c_davinci_init(dev); + return -ETIMEDOUT; + } + + /* no error */ + if (likely(!dev->cmd_err)) + return msg->len; + + /* We have an error */ + if (dev->cmd_err & DAVINCI_I2C_STR_AL) { + i2c_davinci_init(dev); + return -EIO; + } + + if (dev->cmd_err & DAVINCI_I2C_STR_NACK) { + if (msg->flags & I2C_M_IGNORE_NAK) + return msg->len; + if (stop) { + w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG); + MOD_REG_BIT(w, DAVINCI_I2C_MDR_STP, 1); + davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w); + } + return -EREMOTEIO; + } + return -EIO; +} + +/* + * Prepare controller for a transaction and call i2c_davinci_xfer_msg + */ +static int +i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +{ + struct davinci_i2c_dev *dev = i2c_get_adapdata(adap); + int i; + int ret; + + dev_dbg(dev->dev, "%s: msgs: %d\n", __FUNCTION__, num); + + ret = i2c_davinci_wait_bus_not_busy(dev, 1); + if (ret < 0) { + dev_warn(dev->dev, "timeout waiting for bus ready\n"); + return ret; + } + + for (i = 0; i < num; i++) { + ret = i2c_davinci_xfer_msg(adap, &msgs[i], (i == (num - 1))); + if (ret < 0) + return ret; + } + + dev_dbg(dev->dev, "%s:%d ret: %d\n", __FUNCTION__, __LINE__, ret); + + return num; +} + +static u32 i2c_davinci_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); +} + +/* + * Interrupt service routine. This gets called whenever an I2C interrupt + * occurs. + */ +static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id) +{ + struct davinci_i2c_dev *dev = dev_id; + u32 stat; + int count = 0; + u16 w; + + while ((stat = davinci_i2c_read_reg(dev, DAVINCI_I2C_IVR_REG))) { + dev_dbg(dev->dev, "%s: stat=0x%x\n", __FUNCTION__, stat); + if (count++ == 100) { + dev_warn(dev->dev, "Too much work in one IRQ\n"); + break; + } + + switch (stat) { + case DAVINCI_I2C_IVR_AL: + dev->cmd_err |= DAVINCI_I2C_STR_AL; + complete(&dev->cmd_complete); + break; + + case DAVINCI_I2C_IVR_NACK: + dev->cmd_err |= DAVINCI_I2C_STR_NACK; + complete(&dev->cmd_complete); + break; + + case DAVINCI_I2C_IVR_ARDY: + w = davinci_i2c_read_reg(dev, DAVINCI_I2C_STR_REG); + MOD_REG_BIT(w, DAVINCI_I2C_STR_ARDY, 1); + davinci_i2c_write_reg(dev, DAVINCI_I2C_STR_REG, w); + complete(&dev->cmd_complete); + break; + + case DAVINCI_I2C_IVR_RDR: + if (dev->buf_len) { + *dev->buf++ = + davinci_i2c_read_reg(dev, + DAVINCI_I2C_DRR_REG); + dev->buf_len--; + if (dev->buf_len) + continue; + + w = davinci_i2c_read_reg(dev, + DAVINCI_I2C_STR_REG); + MOD_REG_BIT(w, DAVINCI_I2C_IMR_RRDY, 0); + davinci_i2c_write_reg(dev, + DAVINCI_I2C_STR_REG, + w); + } else + dev_err(dev->dev, "RDR IRQ while no" + "data requested\n"); + break; + + case DAVINCI_I2C_IVR_XRDY: + if (dev->buf_len) { + davinci_i2c_write_reg(dev, DAVINCI_I2C_DXR_REG, + *dev->buf++); + dev->buf_len--; + if (dev->buf_len) + continue; + + w = davinci_i2c_read_reg(dev, + DAVINCI_I2C_IMR_REG); + MOD_REG_BIT(w, DAVINCI_I2C_IMR_XRDY, 0); + davinci_i2c_write_reg(dev, + DAVINCI_I2C_IMR_REG, + w); + } else + dev_err(dev->dev, "TDR IRQ while no data to" + "send\n"); + break; + + case DAVINCI_I2C_IVR_SCD: + w = davinci_i2c_read_reg(dev, DAVINCI_I2C_STR_REG); + MOD_REG_BIT(w, DAVINCI_I2C_STR_SCD, 1); + davinci_i2c_write_reg(dev, DAVINCI_I2C_STR_REG, w); + complete(&dev->cmd_complete); + break; + + case DAVINCI_I2C_IVR_AAS: + dev_warn(dev->dev, "Address as slave interrupt\n"); + }/* switch */ + }/* while */ + + return count ? IRQ_HANDLED : IRQ_NONE; +} + +static struct i2c_algorithm i2c_davinci_algo = { + .master_xfer = i2c_davinci_xfer, + .functionality = i2c_davinci_func, +}; + +static int davinci_i2c_probe(struct platform_device *pdev) +{ + struct davinci_i2c_dev *dev; + struct i2c_adapter *adap; + struct resource *mem, *irq, *ioarea; + int r; + + /* NOTE: driver uses the static register mapping */ + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(&pdev->dev, "no mem resource?\n"); + return -ENODEV; + } + + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!irq) { + dev_err(&pdev->dev, "no irq resource?\n"); + return -ENODEV; + } + + ioarea = request_mem_region(mem->start, (mem->end - mem->start) + 1, + pdev->name); + if (!ioarea) { + dev_err(&pdev->dev, "I2C region already claimed\n"); + return -EBUSY; + } + + dev = kzalloc(sizeof(struct davinci_i2c_dev), GFP_KERNEL); + if (!dev) { + r = -ENOMEM; + goto err_release_region; + } + + dev->dev = get_device(&pdev->dev); + dev->irq = irq->start; + platform_set_drvdata(pdev, dev); + + dev->clk = clk_get(&pdev->dev, "I2CCLK"); + if (IS_ERR(dev->clk)) { + r = -ENODEV; + goto err_free_mem; + } + clk_enable(dev->clk); + + dev->base = (void __iomem *)IO_ADDRESS(mem->start); + i2c_davinci_init(dev); + + r = request_irq(dev->irq, i2c_davinci_isr, 0, pdev->name, dev); + if (r) { + dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq); + goto err_unuse_clocks; + } + + adap = &dev->adapter; + i2c_set_adapdata(adap, dev); + adap->owner = THIS_MODULE; + adap->class = I2C_CLASS_HWMON; + strlcpy(adap->name, "DaVinci I2C adapter", sizeof(adap->name)); + adap->algo = &i2c_davinci_algo; + adap->dev.parent = &pdev->dev; + + /* FIXME */ + adap->timeout = 1; + adap->retries = 1; + + adap->nr = pdev->id; + r = i2c_add_numbered_adapter(adap); + if (r) { + dev_err(&pdev->dev, "failure adding adapter\n"); + goto err_free_irq; + } + + return 0; + +err_free_irq: + free_irq(dev->irq, dev); +err_unuse_clocks: + clk_disable(dev->clk); + clk_put(dev->clk); + dev->clk = NULL; +err_free_mem: + platform_set_drvdata(pdev, NULL); + put_device(&pdev->dev); + kfree(dev); +err_release_region: + release_mem_region(mem->start, (mem->end - mem->start) + 1); + + return r; +} + +static int davinci_i2c_remove(struct platform_device *pdev) +{ + struct davinci_i2c_dev *dev = platform_get_drvdata(pdev); + struct resource *mem; + + platform_set_drvdata(pdev, NULL); + i2c_del_adapter(&dev->adapter); + put_device(&pdev->dev); + + clk_disable(dev->clk); + clk_put(dev->clk); + dev->clk = NULL; + + davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, 0); + free_irq(IRQ_I2C, dev); + kfree(dev); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(mem->start, (mem->end - mem->start) + 1); + return 0; +} + +static struct platform_driver davinci_i2c_driver = { + .probe = davinci_i2c_probe, + .remove = davinci_i2c_remove, + .driver = { + .name = "i2c_davinci", + .owner = THIS_MODULE, + }, +}; + +/* I2C may be needed to bring up other drivers */ +static int __init davinci_i2c_init_driver(void) +{ + return platform_driver_register(&davinci_i2c_driver); +} +subsys_initcall(davinci_i2c_init_driver); + +static void __exit davinci_i2c_exit_driver(void) +{ + platform_driver_unregister(&davinci_i2c_driver); +} +module_exit(davinci_i2c_exit_driver); + +MODULE_AUTHOR("Texas Instruments India"); +MODULE_DESCRIPTION("TI DaVinci I2C bus adapter"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 289816db52ae..ac27e5f84ebe 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -34,6 +34,7 @@ ESB2 269B ICH8 283E ICH9 2930 + Tolapai 5032 This driver supports several versions of Intel's I/O Controller Hubs (ICH). For SMBus support, they are similar to the PIIX4 and are part of Intel's '810' and other chipsets. @@ -515,7 +516,7 @@ static u32 i801_func(struct i2c_adapter *adapter) return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK - | (isich4 ? I2C_FUNC_SMBUS_HWPEC_CALC : 0); + | (isich4 ? I2C_FUNC_SMBUS_PEC : 0); } static const struct i2c_algorithm smbus_algorithm = { @@ -543,6 +544,7 @@ static struct pci_device_id i801_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_17) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_5) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_6) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TOLAPAI_1) }, { 0, } }; @@ -563,6 +565,7 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id case PCI_DEVICE_ID_INTEL_ESB2_17: case PCI_DEVICE_ID_INTEL_ICH8_5: case PCI_DEVICE_ID_INTEL_ICH9_6: + case PCI_DEVICE_ID_INTEL_TOLAPAI_1: isich4 = 1; break; default: diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index 8b14d14e60ca..e08bacadd6bc 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -738,7 +738,14 @@ static int __devinit iic_probe(struct ocp_device *ocp){ adap->timeout = 1; adap->retries = 1; - if ((ret = i2c_add_adapter(adap)) != 0){ + /* + * If "dev->idx" is negative we consider it as zero. + * The reason to do so is to avoid sysfs names that only make + * sense when there are multiple adapters. + */ + adap->nr = dev->idx >= 0 ? dev->idx : 0; + + if ((ret = i2c_add_numbered_adapter(adap)) < 0) { printk(KERN_CRIT "ibm-iic%d: failed to register i2c adapter\n", dev->idx); goto fail; diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index ace644e21b14..c70146e4c2c0 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -389,13 +389,6 @@ iop3xx_i2c_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, return im; } -static int -iop3xx_i2c_algo_control(struct i2c_adapter *adapter, unsigned int cmd, - unsigned long arg) -{ - return 0; -} - static u32 iop3xx_i2c_func(struct i2c_adapter *adap) { @@ -404,7 +397,6 @@ iop3xx_i2c_func(struct i2c_adapter *adap) static const struct i2c_algorithm iop3xx_i2c_algo = { .master_xfer = iop3xx_i2c_master_xfer, - .algo_control = iop3xx_i2c_algo_control, .functionality = iop3xx_i2c_func, }; diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index c48140f782d0..1bf590c74166 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -62,6 +62,7 @@ struct nforce2_smbus { int base; int size; int blockops; + int can_abort; }; @@ -83,7 +84,14 @@ struct nforce2_smbus { #define NVIDIA_SMB_DATA (smbus->base + 0x04) /* 32 data registers */ #define NVIDIA_SMB_BCNT (smbus->base + 0x24) /* number of data bytes */ - +#define NVIDIA_SMB_STATUS_ABRT (smbus->base + 0x3c) /* register used to + check the status of + the abort command */ +#define NVIDIA_SMB_CTRL (smbus->base + 0x3e) /* control register */ + +#define NVIDIA_SMB_STATUS_ABRT_STS 0x01 /* Bit to notify that + abort succeeded */ +#define NVIDIA_SMB_CTRL_ABORT 0x20 #define NVIDIA_SMB_STS_DONE 0x80 #define NVIDIA_SMB_STS_ALRM 0x40 #define NVIDIA_SMB_STS_RES 0x20 @@ -98,15 +106,61 @@ struct nforce2_smbus { #define NVIDIA_SMB_PRTCL_BLOCK_DATA 0x0a #define NVIDIA_SMB_PRTCL_PEC 0x80 +/* Misc definitions */ +#define MAX_TIMEOUT 100 + static struct pci_driver nforce2_driver; +static void nforce2_abort(struct i2c_adapter *adap) +{ + struct nforce2_smbus *smbus = adap->algo_data; + int timeout = 0; + unsigned char temp; + + dev_dbg(&adap->dev, "Aborting current transaction\n"); + + outb_p(NVIDIA_SMB_CTRL_ABORT, NVIDIA_SMB_CTRL); + do { + msleep(1); + temp = inb_p(NVIDIA_SMB_STATUS_ABRT); + } while (!(temp & NVIDIA_SMB_STATUS_ABRT_STS) && + (timeout++ < MAX_TIMEOUT)); + if (!(temp & NVIDIA_SMB_STATUS_ABRT_STS)) + dev_err(&adap->dev, "Can't reset the smbus\n"); + outb_p(NVIDIA_SMB_STATUS_ABRT_STS, NVIDIA_SMB_STATUS_ABRT); +} + +static int nforce2_check_status(struct i2c_adapter *adap) +{ + struct nforce2_smbus *smbus = adap->algo_data; + int timeout = 0; + unsigned char temp; + + do { + msleep(1); + temp = inb_p(NVIDIA_SMB_STS); + } while ((!temp) && (timeout++ < MAX_TIMEOUT)); + + if (timeout >= MAX_TIMEOUT) { + dev_dbg(&adap->dev, "SMBus Timeout!\n"); + if (smbus->can_abort) + nforce2_abort(adap); + return -1; + } + if (!(temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) { + dev_dbg(&adap->dev, "Transaction failed (0x%02x)!\n", temp); + return -1; + } + return 0; +} + /* Return -1 on error */ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data * data) { struct nforce2_smbus *smbus = adap->algo_data; - unsigned char protocol, pec, temp; + unsigned char protocol, pec; u8 len; int i; @@ -170,21 +224,8 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, outb_p((addr & 0x7f) << 1, NVIDIA_SMB_ADDR); outb_p(protocol, NVIDIA_SMB_PRTCL); - temp = inb_p(NVIDIA_SMB_STS); - - if (~temp & NVIDIA_SMB_STS_DONE) { - udelay(500); - temp = inb_p(NVIDIA_SMB_STS); - } - if (~temp & NVIDIA_SMB_STS_DONE) { - msleep(10); - temp = inb_p(NVIDIA_SMB_STS); - } - - if ((~temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) { - dev_dbg(&adap->dev, "SMBus Timeout! (0x%02x)\n", temp); + if (nforce2_check_status(adap)) return -1; - } if (read_write == I2C_SMBUS_WRITE) return 0; @@ -202,7 +243,12 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, case I2C_SMBUS_BLOCK_DATA: len = inb_p(NVIDIA_SMB_BCNT); - len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX); + if ((len <= 0) || (len > I2C_SMBUS_BLOCK_MAX)) { + dev_err(&adap->dev, "Transaction failed " + "(received block size: 0x%02x)\n", + len); + return -1; + } for (i = 0; i < len; i++) data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i); data->block[0] = len; @@ -218,6 +264,7 @@ static u32 nforce2_func(struct i2c_adapter *adapter) /* other functionality might be possible, but is not tested */ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_PEC | (((struct nforce2_smbus*)adapter->algo_data)->blockops ? I2C_FUNC_SMBUS_BLOCK_DATA : 0); } @@ -308,6 +355,8 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_ case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS: smbuses[0].blockops = 1; smbuses[1].blockops = 1; + smbuses[0].can_abort = 1; + smbuses[1].can_abort = 1; } /* SMBus adapter 1 */ diff --git a/drivers/i2c/busses/i2c-stub.c b/drivers/i2c/busses/i2c-stub.c index a54adc50d162..84df29da1ddc 100644 --- a/drivers/i2c/busses/i2c-stub.c +++ b/drivers/i2c/busses/i2c-stub.c @@ -24,24 +24,41 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> +#include <linux/slab.h> #include <linux/errno.h> #include <linux/i2c.h> -static unsigned short chip_addr; -module_param(chip_addr, ushort, S_IRUGO); -MODULE_PARM_DESC(chip_addr, "Chip address (between 0x03 and 0x77)\n"); +#define MAX_CHIPS 10 -static u8 stub_pointer; -static u8 stub_bytes[256]; -static u16 stub_words[256]; +static unsigned short chip_addr[MAX_CHIPS]; +module_param_array(chip_addr, ushort, NULL, S_IRUGO); +MODULE_PARM_DESC(chip_addr, + "Chip addresses (up to 10, between 0x03 and 0x77)\n"); + +struct stub_chip { + u8 pointer; + u8 bytes[256]; + u16 words[256]; +}; + +static struct stub_chip *stub_chips; /* Return -1 on error. */ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data * data) { s32 ret; - - if (addr != chip_addr) + int i; + struct stub_chip *chip = NULL; + + /* Search for the right chip */ + for (i = 0; i < MAX_CHIPS && chip_addr[i]; i++) { + if (addr == chip_addr[i]) { + chip = stub_chips + i; + break; + } + } + if (!chip) return -ENODEV; switch (size) { @@ -53,12 +70,12 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags, case I2C_SMBUS_BYTE: if (read_write == I2C_SMBUS_WRITE) { - stub_pointer = command; + chip->pointer = command; dev_dbg(&adap->dev, "smbus byte - addr 0x%02x, " "wrote 0x%02x.\n", addr, command); } else { - data->byte = stub_bytes[stub_pointer++]; + data->byte = chip->bytes[chip->pointer++]; dev_dbg(&adap->dev, "smbus byte - addr 0x%02x, " "read 0x%02x.\n", addr, data->byte); @@ -69,29 +86,29 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags, case I2C_SMBUS_BYTE_DATA: if (read_write == I2C_SMBUS_WRITE) { - stub_bytes[command] = data->byte; + chip->bytes[command] = data->byte; dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, " "wrote 0x%02x at 0x%02x.\n", addr, data->byte, command); } else { - data->byte = stub_bytes[command]; + data->byte = chip->bytes[command]; dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, " "read 0x%02x at 0x%02x.\n", addr, data->byte, command); } - stub_pointer = command + 1; + chip->pointer = command + 1; ret = 0; break; case I2C_SMBUS_WORD_DATA: if (read_write == I2C_SMBUS_WRITE) { - stub_words[command] = data->word; + chip->words[command] = data->word; dev_dbg(&adap->dev, "smbus word data - addr 0x%02x, " "wrote 0x%04x at 0x%02x.\n", addr, data->word, command); } else { - data->word = stub_words[command]; + data->word = chip->words[command]; dev_dbg(&adap->dev, "smbus word data - addr 0x%02x, " "read 0x%04x at 0x%02x.\n", addr, data->word, command); @@ -129,23 +146,41 @@ static struct i2c_adapter stub_adapter = { static int __init i2c_stub_init(void) { - if (!chip_addr) { + int i, ret; + + if (!chip_addr[0]) { printk(KERN_ERR "i2c-stub: Please specify a chip address\n"); return -ENODEV; } - if (chip_addr < 0x03 || chip_addr > 0x77) { - printk(KERN_ERR "i2c-stub: Invalid chip address 0x%02x\n", - chip_addr); - return -EINVAL; + + for (i = 0; i < MAX_CHIPS && chip_addr[i]; i++) { + if (chip_addr[i] < 0x03 || chip_addr[i] > 0x77) { + printk(KERN_ERR "i2c-stub: Invalid chip address " + "0x%02x\n", chip_addr[i]); + return -EINVAL; + } + + printk(KERN_INFO "i2c-stub: Virtual chip at 0x%02x\n", + chip_addr[i]); } - printk(KERN_INFO "i2c-stub: Virtual chip at 0x%02x\n", chip_addr); - return i2c_add_adapter(&stub_adapter); + /* Allocate memory for all chips at once */ + stub_chips = kzalloc(i * sizeof(struct stub_chip), GFP_KERNEL); + if (!stub_chips) { + printk(KERN_ERR "i2c-stub: Out of memory\n"); + return -ENOMEM; + } + + ret = i2c_add_adapter(&stub_adapter); + if (ret) + kfree(stub_chips); + return ret; } static void __exit i2c_stub_exit(void) { i2c_del_adapter(&stub_adapter); + kfree(stub_chips); } MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>"); diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c index 32b25427eaba..21c6dd69193c 100644 --- a/drivers/i2c/chips/pcf8574.c +++ b/drivers/i2c/chips/pcf8574.c @@ -48,14 +48,11 @@ static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, /* Insmod parameters */ I2C_CLIENT_INSMOD_2(pcf8574, pcf8574a); -/* Initial values */ -#define PCF8574_INIT 255 /* All outputs on (input mode) */ - /* Each client has this additional data */ struct pcf8574_data { struct i2c_client client; - u8 write; /* Remember last written value */ + int write; /* Remember last written value */ }; static int pcf8574_attach_adapter(struct i2c_adapter *adapter); @@ -85,7 +82,11 @@ static DEVICE_ATTR(read, S_IRUGO, show_read, NULL); static ssize_t show_write(struct device *dev, struct device_attribute *attr, char *buf) { struct pcf8574_data *data = i2c_get_clientdata(to_i2c_client(dev)); - return sprintf(buf, "%u\n", data->write); + + if (data->write < 0) + return data->write; + + return sprintf(buf, "%d\n", data->write); } static ssize_t set_write(struct device *dev, struct device_attribute *attr, const char *buf, @@ -206,8 +207,7 @@ static int pcf8574_detach_client(struct i2c_client *client) static void pcf8574_init_client(struct i2c_client *client) { struct pcf8574_data *data = i2c_get_clientdata(client); - data->write = PCF8574_INIT; - i2c_smbus_write_byte(client, data->write); + data->write = -EAGAIN; } static int __init pcf8574_init(void) diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c index 503ffec2ce07..e320994b981c 100644 --- a/drivers/i2c/chips/tps65010.c +++ b/drivers/i2c/chips/tps65010.c @@ -24,20 +24,13 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/interrupt.h> -#include <linux/device.h> #include <linux/i2c.h> #include <linux/delay.h> #include <linux/workqueue.h> -#include <linux/suspend.h> #include <linux/debugfs.h> #include <linux/seq_file.h> #include <linux/mutex.h> -#include <asm/irq.h> -#include <asm/mach-types.h> - -#include <asm/arch/gpio.h> -#include <asm/arch/mux.h> #include <asm/arch/tps65010.h> /*-------------------------------------------------------------------------*/ @@ -48,10 +41,6 @@ MODULE_DESCRIPTION("TPS6501x Power Management Driver"); MODULE_LICENSE("GPL"); -static unsigned short normal_i2c[] = { 0x48, /* 0x49, */ I2C_CLIENT_END }; - -I2C_CLIENT_INSMOD; - static struct i2c_driver tps65010_driver; /*-------------------------------------------------------------------------*/ @@ -79,9 +68,8 @@ enum tps_model { }; struct tps65010 { - struct i2c_client client; + struct i2c_client *client; struct mutex lock; - int irq; struct delayed_work work; struct dentry *file; unsigned charging:1; @@ -229,22 +217,22 @@ static int dbg_show(struct seq_file *s, void *_) /* registers for monitoring battery charging and status; note * that reading chgstat and regstat may ack IRQs... */ - value = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG); + value = i2c_smbus_read_byte_data(tps->client, TPS_CHGCONFIG); dbg_chgconf(tps->por, buf, sizeof buf, value); seq_printf(s, "chgconfig %s", buf); - value = i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS); + value = i2c_smbus_read_byte_data(tps->client, TPS_CHGSTATUS); dbg_chgstat(buf, sizeof buf, value); seq_printf(s, "chgstat %s", buf); - value = i2c_smbus_read_byte_data(&tps->client, TPS_MASK1); + value = i2c_smbus_read_byte_data(tps->client, TPS_MASK1); dbg_chgstat(buf, sizeof buf, value); seq_printf(s, "mask1 %s", buf); /* ignore ackint1 */ - value = i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS); + value = i2c_smbus_read_byte_data(tps->client, TPS_REGSTATUS); dbg_regstat(buf, sizeof buf, value); seq_printf(s, "regstat %s", buf); - value = i2c_smbus_read_byte_data(&tps->client, TPS_MASK2); + value = i2c_smbus_read_byte_data(tps->client, TPS_MASK2); dbg_regstat(buf, sizeof buf, value); seq_printf(s, "mask2 %s\n", buf); /* ignore ackint2 */ @@ -253,21 +241,21 @@ static int dbg_show(struct seq_file *s, void *_) /* VMAIN voltage, enable lowpower, etc */ - value = i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC1); + value = i2c_smbus_read_byte_data(tps->client, TPS_VDCDC1); seq_printf(s, "vdcdc1 %02x\n", value); /* VCORE voltage, vibrator on/off */ - value = i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC2); + value = i2c_smbus_read_byte_data(tps->client, TPS_VDCDC2); seq_printf(s, "vdcdc2 %02x\n", value); /* both LD0s, and their lowpower behavior */ - value = i2c_smbus_read_byte_data(&tps->client, TPS_VREGS1); + value = i2c_smbus_read_byte_data(tps->client, TPS_VREGS1); seq_printf(s, "vregs1 %02x\n\n", value); /* LEDs and GPIOs */ - value = i2c_smbus_read_byte_data(&tps->client, TPS_LED1_ON); - v2 = i2c_smbus_read_byte_data(&tps->client, TPS_LED1_PER); + value = i2c_smbus_read_byte_data(tps->client, TPS_LED1_ON); + v2 = i2c_smbus_read_byte_data(tps->client, TPS_LED1_PER); seq_printf(s, "led1 %s, on=%02x, per=%02x, %d/%d msec\n", (value & 0x80) ? ((v2 & 0x80) ? "on" : "off") @@ -275,8 +263,8 @@ static int dbg_show(struct seq_file *s, void *_) value, v2, (value & 0x7f) * 10, (v2 & 0x7f) * 100); - value = i2c_smbus_read_byte_data(&tps->client, TPS_LED2_ON); - v2 = i2c_smbus_read_byte_data(&tps->client, TPS_LED2_PER); + value = i2c_smbus_read_byte_data(tps->client, TPS_LED2_ON); + v2 = i2c_smbus_read_byte_data(tps->client, TPS_LED2_PER); seq_printf(s, "led2 %s, on=%02x, per=%02x, %d/%d msec\n", (value & 0x80) ? ((v2 & 0x80) ? "on" : "off") @@ -284,8 +272,8 @@ static int dbg_show(struct seq_file *s, void *_) value, v2, (value & 0x7f) * 10, (v2 & 0x7f) * 100); - value = i2c_smbus_read_byte_data(&tps->client, TPS_DEFGPIO); - v2 = i2c_smbus_read_byte_data(&tps->client, TPS_MASK3); + value = i2c_smbus_read_byte_data(tps->client, TPS_DEFGPIO); + v2 = i2c_smbus_read_byte_data(tps->client, TPS_MASK3); seq_printf(s, "defgpio %02x mask3 %02x\n", value, v2); for (i = 0; i < 4; i++) { @@ -335,7 +323,7 @@ static void tps65010_interrupt(struct tps65010 *tps) /* regstatus irqs */ if (tps->nmask2) { - tmp = i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS); + tmp = i2c_smbus_read_byte_data(tps->client, TPS_REGSTATUS); mask = tmp ^ tps->regstatus; tps->regstatus = tmp; mask &= tps->nmask2; @@ -362,7 +350,7 @@ static void tps65010_interrupt(struct tps65010 *tps) /* chgstatus irqs */ if (tps->nmask1) { - tmp = i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS); + tmp = i2c_smbus_read_byte_data(tps->client, TPS_CHGSTATUS); mask = tmp ^ tps->chgstatus; tps->chgstatus = tmp; mask &= tps->nmask1; @@ -426,7 +414,7 @@ static void tps65010_work(struct work_struct *work) int status; u8 chgconfig, tmp; - chgconfig = i2c_smbus_read_byte_data(&tps->client, + chgconfig = i2c_smbus_read_byte_data(tps->client, TPS_CHGCONFIG); chgconfig &= ~(TPS_VBUS_500MA | TPS_VBUS_CHARGING); if (tps->vbus == 500) @@ -434,17 +422,17 @@ static void tps65010_work(struct work_struct *work) else if (tps->vbus >= 100) chgconfig |= TPS_VBUS_CHARGING; - status = i2c_smbus_write_byte_data(&tps->client, + status = i2c_smbus_write_byte_data(tps->client, TPS_CHGCONFIG, chgconfig); /* vbus update fails unless VBUS is connected! */ - tmp = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG); + tmp = i2c_smbus_read_byte_data(tps->client, TPS_CHGCONFIG); tps->chgconf = tmp; show_chgconfig(tps->por, "update vbus", tmp); } if (test_and_clear_bit(FLAG_IRQ_ENABLE, &tps->flags)) - enable_irq(tps->irq); + enable_irq(tps->client->irq); mutex_unlock(&tps->lock); } @@ -463,114 +451,75 @@ static irqreturn_t tps65010_irq(int irq, void *_tps) static struct tps65010 *the_tps; -static int __exit tps65010_detach_client(struct i2c_client *client) +static int __exit tps65010_remove(struct i2c_client *client) { - struct tps65010 *tps; + struct tps65010 *tps = i2c_get_clientdata(client); - tps = container_of(client, struct tps65010, client); - free_irq(tps->irq, tps); -#ifdef CONFIG_ARM - if (machine_is_omap_h2()) - omap_free_gpio(58); - if (machine_is_omap_osk()) - omap_free_gpio(OMAP_MPUIO(1)); -#endif + if (client->irq > 0) + free_irq(client->irq, tps); cancel_delayed_work(&tps->work); flush_scheduled_work(); debugfs_remove(tps->file); - if (i2c_detach_client(client) == 0) - kfree(tps); + kfree(tps); the_tps = NULL; return 0; } -static int tps65010_noscan(struct i2c_adapter *bus) -{ - /* pure paranoia, in case someone adds another i2c bus - * after our init section's gone... - */ - return -ENODEV; -} - -/* no error returns, they'd just make bus scanning stop */ -static int __init -tps65010_probe(struct i2c_adapter *bus, int address, int kind) +static int tps65010_probe(struct i2c_client *client) { struct tps65010 *tps; int status; - unsigned long irqflags; if (the_tps) { - dev_dbg(&bus->dev, "only one %s for now\n", DRIVER_NAME); - return 0; + dev_dbg(&client->dev, "only one tps6501x chip allowed\n"); + return -ENODEV; } + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EINVAL; + tps = kzalloc(sizeof *tps, GFP_KERNEL); if (!tps) - return 0; + return -ENOMEM; mutex_init(&tps->lock); INIT_DELAYED_WORK(&tps->work, tps65010_work); - tps->irq = -1; - tps->client.addr = address; - tps->client.adapter = bus; - tps->client.driver = &tps65010_driver; - strlcpy(tps->client.name, DRIVER_NAME, I2C_NAME_SIZE); - - status = i2c_attach_client(&tps->client); - if (status < 0) { - dev_dbg(&bus->dev, "can't attach %s to device %d, err %d\n", - DRIVER_NAME, address, status); - goto fail1; - } + tps->client = client; - /* the IRQ is active low, but many gpio lines can't support that - * so this driver can use falling-edge triggers instead. - */ - irqflags = IRQF_SAMPLE_RANDOM; -#ifdef CONFIG_ARM - if (machine_is_omap_h2()) { - tps->model = TPS65010; - omap_cfg_reg(W4_GPIO58); - tps->irq = OMAP_GPIO_IRQ(58); - omap_request_gpio(58); - omap_set_gpio_direction(58, 1); - irqflags |= IRQF_TRIGGER_FALLING; - } - if (machine_is_omap_osk()) { + if (strcmp(client->name, "tps65010") == 0) tps->model = TPS65010; - // omap_cfg_reg(U19_1610_MPUIO1); - tps->irq = OMAP_GPIO_IRQ(OMAP_MPUIO(1)); - omap_request_gpio(OMAP_MPUIO(1)); - omap_set_gpio_direction(OMAP_MPUIO(1), 1); - irqflags |= IRQF_TRIGGER_FALLING; - } - if (machine_is_omap_h3()) { + else if (strcmp(client->name, "tps65011") == 0) + tps->model = TPS65011; + else if (strcmp(client->name, "tps65012") == 0) + tps->model = TPS65012; + else if (strcmp(client->name, "tps65013") == 0) tps->model = TPS65013; - - // FIXME set up this board's IRQ ... + else { + dev_warn(&client->dev, "unknown chip '%s'\n", client->name); + status = -ENODEV; + goto fail1; } -#endif - if (tps->irq > 0) { - status = request_irq(tps->irq, tps65010_irq, - irqflags, DRIVER_NAME, tps); + /* the IRQ is active low, but many gpio lines can't support that + * so this driver uses falling-edge triggers instead. + */ + if (client->irq > 0) { + status = request_irq(client->irq, tps65010_irq, + IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_FALLING, + DRIVER_NAME, tps); if (status < 0) { - dev_dbg(&tps->client.dev, "can't get IRQ %d, err %d\n", - tps->irq, status); - i2c_detach_client(&tps->client); + dev_dbg(&client->dev, "can't get IRQ %d, err %d\n", + client->irq, status); goto fail1; } -#ifdef CONFIG_ARM /* annoying race here, ideally we'd have an option * to claim the irq now and enable it later. + * FIXME genirq IRQF_NOAUTOEN now solves that ... */ - disable_irq(tps->irq); + disable_irq(client->irq); set_bit(FLAG_IRQ_ENABLE, &tps->flags); -#endif } else - printk(KERN_WARNING "%s: IRQ not configured!\n", - DRIVER_NAME); + dev_warn(&client->dev, "IRQ not configured!\n"); switch (tps->model) { @@ -583,23 +532,22 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind) break; /* else CHGCONFIG.POR is replaced by AUA, enabling a WAIT mode */ } - tps->chgconf = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG); + tps->chgconf = i2c_smbus_read_byte_data(client, TPS_CHGCONFIG); show_chgconfig(tps->por, "conf/init", tps->chgconf); show_chgstatus("chg/init", - i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS)); + i2c_smbus_read_byte_data(client, TPS_CHGSTATUS)); show_regstatus("reg/init", - i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS)); + i2c_smbus_read_byte_data(client, TPS_REGSTATUS)); pr_debug("%s: vdcdc1 0x%02x, vdcdc2 %02x, vregs1 %02x\n", DRIVER_NAME, - i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC1), - i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC2), - i2c_smbus_read_byte_data(&tps->client, TPS_VREGS1)); + i2c_smbus_read_byte_data(client, TPS_VDCDC1), + i2c_smbus_read_byte_data(client, TPS_VDCDC2), + i2c_smbus_read_byte_data(client, TPS_VREGS1)); pr_debug("%s: defgpio 0x%02x, mask3 0x%02x\n", DRIVER_NAME, - i2c_smbus_read_byte_data(&tps->client, TPS_DEFGPIO), - i2c_smbus_read_byte_data(&tps->client, TPS_MASK3)); + i2c_smbus_read_byte_data(client, TPS_DEFGPIO), + i2c_smbus_read_byte_data(client, TPS_MASK3)); - tps65010_driver.attach_adapter = tps65010_noscan; the_tps = tps; #if defined(CONFIG_USB_GADGET) && !defined(CONFIG_USB_OTG) @@ -615,15 +563,15 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind) * registers, and maybe disable VBUS draw. */ tps->nmask1 = ~0; - (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK1, ~tps->nmask1); + (void) i2c_smbus_write_byte_data(client, TPS_MASK1, ~tps->nmask1); tps->nmask2 = TPS_REG_ONOFF; if (tps->model == TPS65013) tps->nmask2 |= TPS_REG_NO_CHG; - (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK2, ~tps->nmask2); + (void) i2c_smbus_write_byte_data(client, TPS_MASK2, ~tps->nmask2); - (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK3, 0x0f - | i2c_smbus_read_byte_data(&tps->client, TPS_MASK3)); + (void) i2c_smbus_write_byte_data(client, TPS_MASK3, 0x0f + | i2c_smbus_read_byte_data(client, TPS_MASK3)); tps65010_work(&tps->work.work); @@ -632,22 +580,15 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind) return 0; fail1: kfree(tps); - return 0; -} - -static int __init tps65010_scan_bus(struct i2c_adapter *bus) -{ - if (!i2c_check_functionality(bus, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EINVAL; - return i2c_probe(bus, &addr_data, tps65010_probe); + return status; } static struct i2c_driver tps65010_driver = { .driver = { .name = "tps65010", }, - .attach_adapter = tps65010_scan_bus, - .detach_client = __exit_p(tps65010_detach_client), + .probe = tps65010_probe, + .remove = __exit_p(tps65010_remove), }; /*-------------------------------------------------------------------------*/ @@ -702,7 +643,7 @@ int tps65010_set_gpio_out_value(unsigned gpio, unsigned value) mutex_lock(&the_tps->lock); - defgpio = i2c_smbus_read_byte_data(&the_tps->client, TPS_DEFGPIO); + defgpio = i2c_smbus_read_byte_data(the_tps->client, TPS_DEFGPIO); /* Configure GPIO for output */ defgpio |= 1 << (gpio + 3); @@ -718,12 +659,12 @@ int tps65010_set_gpio_out_value(unsigned gpio, unsigned value) break; } - status = i2c_smbus_write_byte_data(&the_tps->client, + status = i2c_smbus_write_byte_data(the_tps->client, TPS_DEFGPIO, defgpio); pr_debug("%s: gpio%dout = %s, defgpio 0x%02x\n", DRIVER_NAME, gpio, value ? "high" : "low", - i2c_smbus_read_byte_data(&the_tps->client, TPS_DEFGPIO)); + i2c_smbus_read_byte_data(the_tps->client, TPS_DEFGPIO)); mutex_unlock(&the_tps->lock); return status; @@ -753,11 +694,11 @@ int tps65010_set_led(unsigned led, unsigned mode) mutex_lock(&the_tps->lock); pr_debug("%s: led%i_on 0x%02x\n", DRIVER_NAME, led, - i2c_smbus_read_byte_data(&the_tps->client, + i2c_smbus_read_byte_data(the_tps->client, TPS_LED1_ON + offs)); pr_debug("%s: led%i_per 0x%02x\n", DRIVER_NAME, led, - i2c_smbus_read_byte_data(&the_tps->client, + i2c_smbus_read_byte_data(the_tps->client, TPS_LED1_PER + offs)); switch (mode) { @@ -780,7 +721,7 @@ int tps65010_set_led(unsigned led, unsigned mode) return -EINVAL; } - status = i2c_smbus_write_byte_data(&the_tps->client, + status = i2c_smbus_write_byte_data(the_tps->client, TPS_LED1_ON + offs, led_on); if (status != 0) { @@ -791,9 +732,9 @@ int tps65010_set_led(unsigned led, unsigned mode) } pr_debug("%s: led%i_on 0x%02x\n", DRIVER_NAME, led, - i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_ON + offs)); + i2c_smbus_read_byte_data(the_tps->client, TPS_LED1_ON + offs)); - status = i2c_smbus_write_byte_data(&the_tps->client, + status = i2c_smbus_write_byte_data(the_tps->client, TPS_LED1_PER + offs, led_per); if (status != 0) { @@ -804,7 +745,7 @@ int tps65010_set_led(unsigned led, unsigned mode) } pr_debug("%s: led%i_per 0x%02x\n", DRIVER_NAME, led, - i2c_smbus_read_byte_data(&the_tps->client, + i2c_smbus_read_byte_data(the_tps->client, TPS_LED1_PER + offs)); mutex_unlock(&the_tps->lock); @@ -827,11 +768,11 @@ int tps65010_set_vib(unsigned value) mutex_lock(&the_tps->lock); - vdcdc2 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC2); + vdcdc2 = i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC2); vdcdc2 &= ~(1 << 1); if (value) vdcdc2 |= (1 << 1); - status = i2c_smbus_write_byte_data(&the_tps->client, + status = i2c_smbus_write_byte_data(the_tps->client, TPS_VDCDC2, vdcdc2); pr_debug("%s: vibrator %s\n", DRIVER_NAME, value ? "on" : "off"); @@ -857,9 +798,9 @@ int tps65010_set_low_pwr(unsigned mode) pr_debug("%s: %s low_pwr, vdcdc1 0x%02x\n", DRIVER_NAME, mode ? "enable" : "disable", - i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); + i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1)); - vdcdc1 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1); + vdcdc1 = i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1); switch (mode) { case OFF: @@ -871,7 +812,7 @@ int tps65010_set_low_pwr(unsigned mode) break; } - status = i2c_smbus_write_byte_data(&the_tps->client, + status = i2c_smbus_write_byte_data(the_tps->client, TPS_VDCDC1, vdcdc1); if (status != 0) @@ -879,7 +820,7 @@ int tps65010_set_low_pwr(unsigned mode) DRIVER_NAME); else pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME, - i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); + i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1)); mutex_unlock(&the_tps->lock); @@ -902,9 +843,9 @@ int tps65010_config_vregs1(unsigned value) mutex_lock(&the_tps->lock); pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME, - i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1)); + i2c_smbus_read_byte_data(the_tps->client, TPS_VREGS1)); - status = i2c_smbus_write_byte_data(&the_tps->client, + status = i2c_smbus_write_byte_data(the_tps->client, TPS_VREGS1, value); if (status != 0) @@ -912,7 +853,7 @@ int tps65010_config_vregs1(unsigned value) DRIVER_NAME); else pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME, - i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1)); + i2c_smbus_read_byte_data(the_tps->client, TPS_VREGS1)); mutex_unlock(&the_tps->lock); @@ -941,11 +882,11 @@ int tps65013_set_low_pwr(unsigned mode) pr_debug("%s: %s low_pwr, chgconfig 0x%02x vdcdc1 0x%02x\n", DRIVER_NAME, mode ? "enable" : "disable", - i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG), - i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); + i2c_smbus_read_byte_data(the_tps->client, TPS_CHGCONFIG), + i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1)); - chgconfig = i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG); - vdcdc1 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1); + chgconfig = i2c_smbus_read_byte_data(the_tps->client, TPS_CHGCONFIG); + vdcdc1 = i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1); switch (mode) { case OFF: @@ -959,7 +900,7 @@ int tps65013_set_low_pwr(unsigned mode) break; } - status = i2c_smbus_write_byte_data(&the_tps->client, + status = i2c_smbus_write_byte_data(the_tps->client, TPS_CHGCONFIG, chgconfig); if (status != 0) { printk(KERN_ERR "%s: Failed to write chconfig register\n", @@ -968,11 +909,11 @@ int tps65013_set_low_pwr(unsigned mode) return status; } - chgconfig = i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG); + chgconfig = i2c_smbus_read_byte_data(the_tps->client, TPS_CHGCONFIG); the_tps->chgconf = chgconfig; show_chgconfig(0, "chgconf", chgconfig); - status = i2c_smbus_write_byte_data(&the_tps->client, + status = i2c_smbus_write_byte_data(the_tps->client, TPS_VDCDC1, vdcdc1); if (status != 0) @@ -980,7 +921,7 @@ int tps65013_set_low_pwr(unsigned mode) DRIVER_NAME); else pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME, - i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); + i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1)); mutex_unlock(&the_tps->lock); @@ -1011,52 +952,6 @@ static int __init tps_init(void) msleep(10); } -#ifdef CONFIG_ARM - if (machine_is_omap_osk()) { - - // FIXME: More should be placed in the initialization code - // of the submodules (DSP, ethernet, power management, - // board-osk.c). Careful: I2C is initialized "late". - - /* Let LED1 (D9) blink */ - tps65010_set_led(LED1, BLINK); - - /* Disable LED 2 (D2) */ - tps65010_set_led(LED2, OFF); - - /* Set GPIO 1 HIGH to disable VBUS power supply; - * OHCI driver powers it up/down as needed. - */ - tps65010_set_gpio_out_value(GPIO1, HIGH); - - /* Set GPIO 2 low to turn on LED D3 */ - tps65010_set_gpio_out_value(GPIO2, HIGH); - - /* Set GPIO 3 low to take ethernet out of reset */ - tps65010_set_gpio_out_value(GPIO3, LOW); - - /* gpio4 for VDD_DSP */ - - /* Enable LOW_PWR */ - tps65010_set_low_pwr(ON); - - /* Switch VLDO2 to 3.0V for AIC23 */ - tps65010_config_vregs1(TPS_LDO2_ENABLE | TPS_VLDO2_3_0V | TPS_LDO1_ENABLE); - - } else if (machine_is_omap_h2()) { - /* gpio3 for SD, gpio4 for VDD_DSP */ - - /* Enable LOW_PWR */ - tps65010_set_low_pwr(ON); - } else if (machine_is_omap_h3()) { - /* gpio4 for SD, gpio3 for VDD_DSP */ -#ifdef CONFIG_PM - /* Enable LOW_PWR */ - tps65013_set_low_pwr(ON); -#endif - } -#endif - return status; } /* NOTE: this MUST be initialized before the other parts of the system diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index d663e6960d93..e73d58c43f38 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -67,20 +67,16 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv) #ifdef CONFIG_HOTPLUG /* uevent helps with hotplug: modprobe -q $(MODALIAS) */ -static int i2c_device_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env) { struct i2c_client *client = to_i2c_client(dev); - int i = 0, length = 0; /* by definition, legacy drivers can't hotplug */ if (dev->driver || !client->driver_name) return 0; - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MODALIAS=%s", client->driver_name)) + if (add_uevent_var(env, "MODALIAS=%s", client->driver_name)) return -ENOMEM; - envp[i] = NULL; dev_dbg(dev, "uevent\n"); return 0; } @@ -190,7 +186,7 @@ static struct device_attribute i2c_dev_attrs[] = { { }, }; -struct bus_type i2c_bus_type = { +static struct bus_type i2c_bus_type = { .name = "i2c", .dev_attrs = i2c_dev_attrs, .match = i2c_device_match, @@ -201,7 +197,6 @@ struct bus_type i2c_bus_type = { .suspend = i2c_device_suspend, .resume = i2c_device_resume, }; -EXPORT_SYMBOL_GPL(i2c_bus_type); /** * i2c_new_device - instantiate an i2c device for use with a new style driver @@ -230,7 +225,9 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) client->adapter = adap; client->dev.platform_data = info->platform_data; - client->flags = info->flags; + device_init_wakeup(&client->dev, info->flags & I2C_CLIENT_WAKE); + + client->flags = info->flags & ~I2C_CLIENT_WAKE; client->addr = info->addr; client->irq = info->irq; @@ -283,7 +280,7 @@ EXPORT_SYMBOL_GPL(i2c_unregister_device); /* I2C bus adapters -- one roots each I2C or SMBUS segment */ -void i2c_adapter_dev_release(struct device *dev) +static void i2c_adapter_dev_release(struct device *dev) { struct i2c_adapter *adap = to_i2c_adapter(dev); complete(&adap->dev_released); @@ -301,7 +298,7 @@ static struct device_attribute i2c_adapter_attrs[] = { { }, }; -struct class i2c_adapter_class = { +static struct class i2c_adapter_class = { .owner = THIS_MODULE, .name = "i2c-adapter", .dev_attrs = i2c_adapter_attrs, @@ -934,28 +931,6 @@ int i2c_master_recv(struct i2c_client *client, char *buf ,int count) } EXPORT_SYMBOL(i2c_master_recv); -int i2c_control(struct i2c_client *client, - unsigned int cmd, unsigned long arg) -{ - int ret = 0; - struct i2c_adapter *adap = client->adapter; - - dev_dbg(&client->adapter->dev, "i2c ioctl, cmd: 0x%x, arg: %#lx\n", cmd, arg); - switch (cmd) { - case I2C_RETRIES: - adap->retries = arg; - break; - case I2C_TIMEOUT: - adap->timeout = arg; - break; - default: - if (adap->algo->algo_control!=NULL) - ret = adap->algo->algo_control(adap,cmd,arg); - } - return ret; -} -EXPORT_SYMBOL(i2c_control); - /* ---------------------------------------------------- * the i2c address scanning function * Will not work for 10-bit addresses! @@ -1310,7 +1285,22 @@ s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value) } EXPORT_SYMBOL(i2c_smbus_write_word_data); -/* Returns the number of read bytes */ +/** + * i2c_smbus_read_block_data - SMBus block read request + * @client: Handle to slave device + * @command: Command byte issued to let the slave know what data should + * be returned + * @values: Byte array into which data will be read; big enough to hold + * the data returned by the slave. SMBus allows at most 32 bytes. + * + * Returns the number of bytes read in the slave's response, else a + * negative number to indicate some kind of error. + * + * Note that using this function requires that the client's adapter support + * the I2C_FUNC_SMBUS_READ_BLOCK_DATA functionality. Not all adapter drivers + * support this; its emulation through I2C messaging relies on a specific + * mechanism (I2C_M_RECV_LEN) which may not be implemented. + */ s32 i2c_smbus_read_block_data(struct i2c_client *client, u8 command, u8 *values) { diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 64eee9551b22..5a15e50748de 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -226,8 +226,10 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file, res = 0; for( i=0; i<rdwr_arg.nmsgs; i++ ) { - /* Limit the size of the message to a sane amount */ - if (rdwr_pa[i].len > 8192) { + /* Limit the size of the message to a sane amount; + * and don't let length change either. */ + if ((rdwr_pa[i].len > 8192) || + (rdwr_pa[i].flags & I2C_M_RECV_LEN)) { res = -EINVAL; break; } @@ -352,9 +354,19 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file, return -EFAULT; } return res; - + case I2C_RETRIES: + client->adapter->retries = arg; + break; + case I2C_TIMEOUT: + client->adapter->timeout = arg; + break; default: - return i2c_control(client,cmd,arg); + /* NOTE: returning a fault code here could cause trouble + * in buggy userspace code. Some old kernel bugs returned + * zero in this case, and userspace code might accidentally + * have depended on that bug. + */ + return -ENOTTY; } return 0; } diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index aa0e0c9f74c5..8982c0932438 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -1074,22 +1074,6 @@ endif config BLK_DEV_IDEDMA def_bool BLK_DEV_IDEDMA_PCI || BLK_DEV_IDEDMA_PMAC || BLK_DEV_IDEDMA_ICS || BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA -config IDEDMA_IVB - bool "IGNORE word93 Validation BITS" - depends on BLK_DEV_IDEDMA_PCI || BLK_DEV_IDEDMA_PMAC || BLK_DEV_IDEDMA_ICS - ---help--- - There are unclear terms in ATA-4 and ATA-5 standards how certain - hardware (an 80c ribbon) should be detected. Different interpretations - of the standards have been released in hardware. This causes problems: - for example, a host with Ultra Mode 4 (or higher) will not run - in that mode with an 80c ribbon. - - If you are experiencing compatibility or performance problems, you - MAY try to answer Y here. However, it does not necessarily solve - any of your problems, it could even cause more of them. - - It is normally safe to answer Y; however, the default is N. - endif config BLK_DEV_HD_ONLY diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c index 7912a471f10d..bd1f5b670378 100644 --- a/drivers/ide/arm/icside.c +++ b/drivers/ide/arm/icside.c @@ -248,7 +248,7 @@ static void icside_build_sglist(ide_drive_t *drive, struct request *rq) * MW1 80 50 50 150 C * MW2 70 25 25 120 C */ -static int icside_set_speed(ide_drive_t *drive, const u8 xfer_mode) +static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode) { int cycle_time, use_dma_info = 0; @@ -273,7 +273,7 @@ static int icside_set_speed(ide_drive_t *drive, const u8 xfer_mode) cycle_time = 480; break; default: - return 1; + return; } /* @@ -287,8 +287,6 @@ static int icside_set_speed(ide_drive_t *drive, const u8 xfer_mode) printk("%s: %s selected (peak %dMB/s)\n", drive->name, ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data); - - return ide_config_drive_speed(drive, xfer_mode); } static void icside_dma_host_off(ide_drive_t *drive) @@ -313,41 +311,10 @@ static int icside_dma_on(ide_drive_t *drive) static int icside_dma_check(ide_drive_t *drive) { - struct hd_driveid *id = drive->id; - ide_hwif_t *hwif = HWIF(drive); - int xfer_mode = 0; - - if (!(id->capability & 1) || !hwif->autodma) - goto out; - - /* - * Consult the list of known "bad" drives - */ - if (__ide_dma_bad_drive(drive)) - goto out; - - /* - * Enable DMA on any drive that has multiword DMA - */ - if (id->field_valid & 2) { - xfer_mode = ide_max_dma_mode(drive); - goto out; - } - - /* - * Consult the list of known "good" drives - */ - if (__ide_dma_good_drive(drive)) { - if (id->eide_dma_time > 150) - goto out; - xfer_mode = XFER_MW_DMA_1; - } - -out: - if (xfer_mode == 0) - return -1; + if (ide_tune_dma(drive)) + return 0; - return icside_set_speed(drive, xfer_mode) ? -1 : 0; + return -1; } static int icside_dma_end(ide_drive_t *drive) @@ -464,7 +431,7 @@ static void icside_dma_init(ide_hwif_t *hwif) hwif->dmatable_cpu = NULL; hwif->dmatable_dma = 0; - hwif->speedproc = icside_set_speed; + hwif->set_dma_mode = icside_set_dma_mode; hwif->autodma = 1; hwif->ide_dma_check = icside_dma_check; diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c index 4bb42b30bfc0..2b4d2a0ae5c2 100644 --- a/drivers/ide/cris/ide-cris.c +++ b/drivers/ide/cris/ide-cris.c @@ -716,11 +716,9 @@ static void cris_set_pio_mode(ide_drive_t *drive, const u8 pio) } cris_ide_set_speed(TYPE_PIO, setup, strobe, hold); - - (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio); } -static int speed_cris_ide(ide_drive_t *drive, const u8 speed) +static void cris_set_dma_mode(ide_drive_t *drive, const u8 speed) { int cyc = 0, dvs = 0, strobe = 0, hold = 0; @@ -759,8 +757,6 @@ static int speed_cris_ide(ide_drive_t *drive, const u8 speed) cris_ide_set_speed(TYPE_UDMA, cyc, dvs, 0); else cris_ide_set_speed(TYPE_DMA, 0, strobe, hold); - - return ide_config_drive_speed(drive, speed); } void __init @@ -791,7 +787,7 @@ init_e100_ide (void) hwif->mmio = 1; hwif->chipset = ide_etrax100; hwif->set_pio_mode = &cris_set_pio_mode; - hwif->speedproc = &speed_cris_ide; + hwif->set_dma_mode = &cris_set_dma_mode; hwif->ata_input_data = &cris_ide_input_data; hwif->ata_output_data = &cris_ide_output_data; hwif->atapi_input_bytes = &cris_atapi_input_bytes; diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c index 6bff81a58bf3..1d5f6823101c 100644 --- a/drivers/ide/ide-acpi.c +++ b/drivers/ide/ide-acpi.c @@ -649,7 +649,6 @@ void ide_acpi_set_state(ide_hwif_t *hwif, int on) if (!on) acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D3); } -EXPORT_SYMBOL_GPL(ide_acpi_set_state); /** * ide_acpi_init - initialize the ACPI link for an IDE interface diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index 6000c08f51ba..b453211ee0fc 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -169,6 +169,11 @@ ide_startstop_t ide_dma_intr (ide_drive_t *drive) EXPORT_SYMBOL_GPL(ide_dma_intr); +static int ide_dma_good_drive(ide_drive_t *drive) +{ + return ide_in_drive_list(drive->id, drive_whitelist); +} + #ifdef CONFIG_BLK_DEV_IDEDMA_PCI /** * ide_build_sglist - map IDE scatter gather for DMA I/O @@ -357,7 +362,7 @@ static int config_drive_for_dma (ide_drive_t *drive) return 0; /* Consult the list of known "good" drives */ - if (__ide_dma_good_drive(drive)) + if (ide_dma_good_drive(drive)) return 0; } @@ -639,14 +644,6 @@ int __ide_dma_bad_drive (ide_drive_t *drive) EXPORT_SYMBOL(__ide_dma_bad_drive); -int __ide_dma_good_drive (ide_drive_t *drive) -{ - struct hd_driveid *id = drive->id; - return ide_in_drive_list(id, drive_whitelist); -} - -EXPORT_SYMBOL(__ide_dma_good_drive); - static const u8 xfer_mode_bases[] = { XFER_UDMA_0, XFER_MW_DMA_0, @@ -746,6 +743,14 @@ u8 ide_find_dma_mode(ide_drive_t *drive, u8 req_mode) } } + if (hwif->chipset == ide_acorn && mode == 0) { + /* + * is this correct? + */ + if (ide_dma_good_drive(drive) && drive->id->eide_dma_time < 150) + mode = XFER_MW_DMA_1; + } + printk(KERN_DEBUG "%s: selected mode 0x%x\n", drive->name, mode); return min(mode, req_mode); @@ -769,7 +774,10 @@ int ide_tune_dma(ide_drive_t *drive) if (!speed) return 0; - if (drive->hwif->speedproc(drive, speed)) + if (drive->hwif->host_flags & IDE_HFLAG_NO_SET_MODE) + return 0; + + if (ide_set_dma_mode(drive, speed)) return 0; return 1; diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 9560a8f4a86c..4cece930114c 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -836,9 +836,17 @@ static ide_startstop_t do_special (ide_drive_t *drive) if (set_pio_mode_abuse(drive->hwif, req_pio)) { if (hwif->set_pio_mode) hwif->set_pio_mode(drive, req_pio); - } else + } else { + int keep_dma = drive->using_dma; + ide_set_pio(drive, req_pio); + if (hwif->host_flags & IDE_HFLAG_SET_PIO_MODE_KEEP_DMA) { + if (keep_dma) + hwif->ide_dma_on(drive); + } + } + return ide_stopped; } else { if (drive->media == ide_disk) diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c index cf0678b61161..aa738833bed5 100644 --- a/drivers/ide/ide-iops.c +++ b/drivers/ide/ide-iops.c @@ -473,57 +473,22 @@ int drive_is_ready (ide_drive_t *drive) EXPORT_SYMBOL(drive_is_ready); /* - * Global for All, and taken from ide-pmac.c. Can be called - * with spinlock held & IRQs disabled, so don't schedule ! - */ -int wait_for_ready (ide_drive_t *drive, int timeout) -{ - ide_hwif_t *hwif = HWIF(drive); - u8 stat = 0; - - while(--timeout) { - stat = hwif->INB(IDE_STATUS_REG); - if (!(stat & BUSY_STAT)) { - if (drive->ready_stat == 0) - break; - else if ((stat & drive->ready_stat)||(stat & ERR_STAT)) - break; - } - mdelay(1); - } - if ((stat & ERR_STAT) || timeout <= 0) { - if (stat & ERR_STAT) { - printk(KERN_ERR "%s: wait_for_ready, " - "error status: %x\n", drive->name, stat); - } - return 1; - } - return 0; -} - -/* * This routine busy-waits for the drive status to be not "busy". * It then checks the status for all of the "good" bits and none * of the "bad" bits, and if all is okay it returns 0. All other - * cases return 1 after invoking ide_error() -- caller should just return. + * cases return error -- caller may then invoke ide_error(). * * This routine should get fixed to not hog the cpu during extra long waits.. * That could be done by busy-waiting for the first jiffy or two, and then * setting a timer to wake up at half second intervals thereafter, * until timeout is achieved, before timing out. */ -int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 bad, unsigned long timeout) +static int __ide_wait_stat(ide_drive_t *drive, u8 good, u8 bad, unsigned long timeout, u8 *rstat) { - ide_hwif_t *hwif = HWIF(drive); - u8 stat; - int i; + ide_hwif_t *hwif = drive->hwif; unsigned long flags; - - /* bail early if we've exceeded max_failures */ - if (drive->max_failures && (drive->failures > drive->max_failures)) { - *startstop = ide_stopped; - return 1; - } + int i; + u8 stat; udelay(1); /* spec allows drive 400ns to assert "BUSY" */ if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) { @@ -541,8 +506,8 @@ int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 b break; local_irq_restore(flags); - *startstop = ide_error(drive, "status timeout", stat); - return 1; + *rstat = stat; + return -EBUSY; } } local_irq_restore(flags); @@ -556,11 +521,39 @@ int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 b */ for (i = 0; i < 10; i++) { udelay(1); - if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), good, bad)) + if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), good, bad)) { + *rstat = stat; return 0; + } } - *startstop = ide_error(drive, "status error", stat); - return 1; + *rstat = stat; + return -EFAULT; +} + +/* + * In case of error returns error value after doing "*startstop = ide_error()". + * The caller should return the updated value of "startstop" in this case, + * "startstop" is unchanged when the function returns 0. + */ +int ide_wait_stat(ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 bad, unsigned long timeout) +{ + int err; + u8 stat; + + /* bail early if we've exceeded max_failures */ + if (drive->max_failures && (drive->failures > drive->max_failures)) { + *startstop = ide_stopped; + return 1; + } + + err = __ide_wait_stat(drive, good, bad, timeout, &stat); + + if (err) { + char *s = (err == -EBUSY) ? "status timeout" : "status error"; + *startstop = ide_error(drive, s, stat); + } + + return err; } EXPORT_SYMBOL(ide_wait_stat); @@ -620,15 +613,10 @@ u8 eighty_ninty_three (ide_drive_t *drive) /* * FIXME: - * - change master/slave IDENTIFY order * - force bit13 (80c cable present) check also for !ivb devices * (unless the slave device is pre-ATA3) */ -#ifndef CONFIG_IDEDMA_IVB if ((id->hw_config & 0x4000) || (ivb && (id->hw_config & 0x2000))) -#else - if (id->hw_config & 0x6000) -#endif return 1; no_80w: @@ -778,15 +766,10 @@ int ide_driveid_update (ide_drive_t *drive) #endif } -/* - * Similar to ide_wait_stat(), except it never calls ide_error internally. - * - * const char *msg == consider adding for verbose errors. - */ -int ide_config_drive_speed (ide_drive_t *drive, u8 speed) +int ide_config_drive_speed(ide_drive_t *drive, u8 speed) { - ide_hwif_t *hwif = HWIF(drive); - int i, error = 1; + ide_hwif_t *hwif = drive->hwif; + int error; u8 stat; // while (HWGROUP(drive)->busy) @@ -826,35 +809,10 @@ int ide_config_drive_speed (ide_drive_t *drive, u8 speed) hwif->OUTBSYNC(drive, WIN_SETFEATURES, IDE_COMMAND_REG); if ((IDE_CONTROL_REG) && (drive->quirk_list == 2)) hwif->OUTB(drive->ctl, IDE_CONTROL_REG); - udelay(1); - /* - * Wait for drive to become non-BUSY - */ - if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) { - unsigned long flags, timeout; - local_irq_set(flags); - timeout = jiffies + WAIT_CMD; - while ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) { - if (time_after(jiffies, timeout)) - break; - } - local_irq_restore(flags); - } - /* - * Allow status to settle, then read it again. - * A few rare drives vastly violate the 400ns spec here, - * so we'll wait up to 10usec for a "good" status - * rather than expensively fail things immediately. - * This fix courtesy of Matthew Faupel & Niccolo Rigacci. - */ - for (i = 0; i < 10; i++) { - udelay(1); - if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), drive->ready_stat, BUSY_STAT|DRQ_STAT|ERR_STAT)) { - error = 0; - break; - } - } + error = __ide_wait_stat(drive, drive->ready_stat, + BUSY_STAT|DRQ_STAT|ERR_STAT, + WAIT_CMD, &stat); SELECT_MASK(drive, 0); @@ -899,9 +857,6 @@ int ide_config_drive_speed (ide_drive_t *drive, u8 speed) return error; } -EXPORT_SYMBOL(ide_config_drive_speed); - - /* * This should get invoked any time we exit the driver to * wait for an interrupt response from a drive. handler() points diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index d97390c0543b..0e2562f0f74e 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c @@ -349,7 +349,7 @@ void ide_set_pio(ide_drive_t *drive, u8 req_pio) drive->name, host_pio, req_pio, req_pio == 255 ? "(auto-tune)" : "", pio); - hwif->set_pio_mode(drive, pio); + (void)ide_set_pio_mode(drive, XFER_PIO_0 + pio); } EXPORT_SYMBOL_GPL(ide_set_pio); @@ -378,39 +378,83 @@ void ide_toggle_bounce(ide_drive_t *drive, int on) blk_queue_bounce_limit(drive->queue, addr); } +int ide_set_pio_mode(ide_drive_t *drive, const u8 mode) +{ + ide_hwif_t *hwif = drive->hwif; + + if (hwif->set_pio_mode == NULL) + return -1; + + /* + * TODO: temporary hack for some legacy host drivers that didn't + * set transfer mode on the device in ->set_pio_mode method... + */ + if (hwif->set_dma_mode == NULL) { + hwif->set_pio_mode(drive, mode - XFER_PIO_0); + return 0; + } + + if (hwif->host_flags & IDE_HFLAG_POST_SET_MODE) { + if (ide_config_drive_speed(drive, mode)) + return -1; + hwif->set_pio_mode(drive, mode - XFER_PIO_0); + return 0; + } else { + hwif->set_pio_mode(drive, mode - XFER_PIO_0); + return ide_config_drive_speed(drive, mode); + } +} + +int ide_set_dma_mode(ide_drive_t *drive, const u8 mode) +{ + ide_hwif_t *hwif = drive->hwif; + + if (hwif->set_dma_mode == NULL) + return -1; + + if (hwif->host_flags & IDE_HFLAG_POST_SET_MODE) { + if (ide_config_drive_speed(drive, mode)) + return -1; + hwif->set_dma_mode(drive, mode); + return 0; + } else { + hwif->set_dma_mode(drive, mode); + return ide_config_drive_speed(drive, mode); + } +} + +EXPORT_SYMBOL_GPL(ide_set_dma_mode); + /** * ide_set_xfer_rate - set transfer rate * @drive: drive to set - * @speed: speed to attempt to set + * @rate: speed to attempt to set * * General helper for setting the speed of an IDE device. This * function knows about user enforced limits from the configuration - * which speedproc() does not. High level drivers should never - * invoke speedproc() directly. + * which ->set_pio_mode/->set_dma_mode does not. */ - + int ide_set_xfer_rate(ide_drive_t *drive, u8 rate) { ide_hwif_t *hwif = drive->hwif; - if (hwif->speedproc == NULL) + if (hwif->set_dma_mode == NULL) return -1; rate = ide_rate_filter(drive, rate); - if (rate >= XFER_PIO_0 && rate <= XFER_PIO_5) { - if (hwif->set_pio_mode) - hwif->set_pio_mode(drive, rate - XFER_PIO_0); + if (rate >= XFER_PIO_0 && rate <= XFER_PIO_5) + return ide_set_pio_mode(drive, rate); - /* - * FIXME: this is incorrect to return zero here but - * since all users of ide_set_xfer_rate() ignore - * the return value it is not a problem currently - */ - return 0; - } + /* + * TODO: transfer modes 0x00-0x07 passed from the user-space are + * currently handled here which needs fixing (please note that such + * case could happen iff the transfer mode has already been set on + * the device by ide-proc.c::set_xfer_rate()). + */ - return hwif->speedproc(drive, rate); + return ide_set_dma_mode(drive, rate); } static void ide_dump_opcode(ide_drive_t *drive) diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index b4c9f63a3854..d1011712601c 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -719,9 +719,9 @@ EXPORT_SYMBOL_GPL(ide_undecoded_slave); */ static void probe_hwif(ide_hwif_t *hwif, void (*fixup)(ide_hwif_t *hwif)) { - unsigned int unit; unsigned long flags; unsigned int irqd; + int unit; if (hwif->noprobe) return; @@ -777,10 +777,9 @@ static void probe_hwif(ide_hwif_t *hwif, void (*fixup)(ide_hwif_t *hwif)) printk(KERN_DEBUG "%s: Wait for ready failed before probe !\n", hwif->name); /* - * Second drive should only exist if first drive was found, - * but a lot of cdrom drives are configured as single slaves. + * Need to probe slave device first to make it release PDIAG-. */ - for (unit = 0; unit < MAX_DRIVES; ++unit) { + for (unit = MAX_DRIVES - 1; unit >= 0; unit--) { ide_drive_t *drive = &hwif->drives[unit]; drive->dn = (hwif->channel ? 2 : 0) + unit; (void) probe_for_drive(drive); diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index e96212ce5729..5c0e4078b5cb 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -397,7 +397,7 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif) #endif hwif->set_pio_mode = tmp_hwif->set_pio_mode; - hwif->speedproc = tmp_hwif->speedproc; + hwif->set_dma_mode = tmp_hwif->set_dma_mode; hwif->mdma_filter = tmp_hwif->mdma_filter; hwif->udma_filter = tmp_hwif->udma_filter; hwif->selectproc = tmp_hwif->selectproc; @@ -1663,20 +1663,13 @@ static struct device_attribute ide_dev_attrs[] = { __ATTR_NULL }; -static int ide_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int ide_uevent(struct device *dev, struct kobj_uevent_env *env) { ide_drive_t *drive = to_ide_device(dev); - int i = 0; - int length = 0; - - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MEDIA=%s", media_string(drive)); - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "DRIVENAME=%s", drive->name); - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MODALIAS=ide:m-%s", media_string(drive)); - envp[i] = NULL; + + add_uevent_var(env, "MEDIA=%s", media_string(drive)); + add_uevent_var(env, "DRIVENAME=%s", drive->name); + add_uevent_var(env, "MODALIAS=ide:m-%s", media_string(drive)); return 0; } diff --git a/drivers/ide/legacy/ide_platform.c b/drivers/ide/legacy/ide_platform.c index ccfb9893a467..b992b2b91fe2 100644 --- a/drivers/ide/legacy/ide_platform.c +++ b/drivers/ide/legacy/ide_platform.c @@ -65,7 +65,7 @@ found: hwif->hw.irq = hwif->irq = irq; hwif->hw.dma = NO_DMA; - hwif->hw.chipset = ide_generic; + hwif->chipset = hwif->hw.chipset = ide_generic; if (mmio) { hwif->mmio = 1; diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c index 85819ae20602..aebde49365d1 100644 --- a/drivers/ide/mips/au1xxx-ide.c +++ b/drivers/ide/mips/au1xxx-ide.c @@ -101,12 +101,7 @@ void auide_outsw(unsigned long port, void *addr, u32 count) static void au1xxx_set_pio_mode(ide_drive_t *drive, const u8 pio) { - int mem_sttime; - int mem_stcfg; - u8 speed; - - mem_sttime = 0; - mem_stcfg = au_readl(MEM_STCFG2); + int mem_sttime = 0, mem_stcfg = au_readl(MEM_STCFG2); /* set pio mode! */ switch(pio) { @@ -164,18 +159,11 @@ static void au1xxx_set_pio_mode(ide_drive_t *drive, const u8 pio) au_writel(mem_sttime,MEM_STTIME2); au_writel(mem_stcfg,MEM_STCFG2); - - speed = pio + XFER_PIO_0; - ide_config_drive_speed(drive, speed); } -static int auide_tune_chipset(ide_drive_t *drive, const u8 speed) +static void auide_set_dma_mode(ide_drive_t *drive, const u8 speed) { - int mem_sttime; - int mem_stcfg; - - mem_sttime = 0; - mem_stcfg = au_readl(MEM_STCFG2); + int mem_sttime = 0, mem_stcfg = au_readl(MEM_STCFG2); switch(speed) { #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA @@ -211,16 +199,11 @@ static int auide_tune_chipset(ide_drive_t *drive, const u8 speed) break; #endif default: - return 1; + return; } - if (ide_config_drive_speed(drive, speed)) - return 1; - au_writel(mem_sttime,MEM_STTIME2); au_writel(mem_stcfg,MEM_STCFG2); - - return 0; } /* @@ -682,6 +665,7 @@ static int au_ide_probe(struct device *dev) #endif hwif->pio_mask = ATA_PIO4; + hwif->host_flags = IDE_HFLAG_POST_SET_MODE; hwif->noprobe = 0; hwif->drives[0].unmask = 1; @@ -702,7 +686,7 @@ static int au_ide_probe(struct device *dev) #endif hwif->set_pio_mode = &au1xxx_set_pio_mode; - hwif->speedproc = &auide_tune_chipset; + hwif->set_dma_mode = &auide_set_dma_mode; #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA hwif->dma_off_quietly = &auide_dma_off_quietly; diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c index 0d5f62c5dfae..d6cb2d5143c8 100644 --- a/drivers/ide/pci/aec62xx.c +++ b/drivers/ide/pci/aec62xx.c @@ -87,7 +87,7 @@ static u8 pci_bus_clock_list_ultra (u8 speed, struct chipset_bus_clock_list_entr return chipset_table->ultra_settings; } -static int aec6210_tune_chipset(ide_drive_t *drive, const u8 speed) +static void aec6210_set_mode(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; @@ -111,10 +111,9 @@ static int aec6210_tune_chipset(ide_drive_t *drive, const u8 speed) tmp2 = ((ultra_conf << (2*drive->dn)) | (tmp1 & ~(3 << (2*drive->dn)))); pci_write_config_byte(dev, 0x54, tmp2); local_irq_restore(flags); - return(ide_config_drive_speed(drive, speed)); } -static int aec6260_tune_chipset(ide_drive_t *drive, const u8 speed) +static void aec6260_set_mode(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; @@ -135,12 +134,11 @@ static int aec6260_tune_chipset(ide_drive_t *drive, const u8 speed) tmp2 = ((ultra_conf << (4*unit)) | (tmp1 & ~(7 << (4*unit)))); pci_write_config_byte(dev, (0x44|hwif->channel), tmp2); local_irq_restore(flags); - return(ide_config_drive_speed(drive, speed)); } static void aec_set_pio_mode(ide_drive_t *drive, const u8 pio) { - (void) HWIF(drive)->speedproc(drive, pio + XFER_PIO_0); + drive->hwif->set_dma_mode(drive, pio + XFER_PIO_0); } static int aec62xx_config_drive_xfer_rate (ide_drive_t *drive) @@ -205,9 +203,9 @@ static void __devinit init_hwif_aec62xx(ide_hwif_t *hwif) if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) { if(hwif->mate) hwif->mate->serialized = hwif->serialized = 1; - hwif->speedproc = &aec6210_tune_chipset; + hwif->set_dma_mode = &aec6210_set_mode; } else - hwif->speedproc = &aec6260_tune_chipset; + hwif->set_dma_mode = &aec6260_set_mode; if (!hwif->dma_base) { hwif->drives[0].autotune = hwif->drives[1].autotune = 1; diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c index d04b966b4347..0b83443bf250 100644 --- a/drivers/ide/pci/alim15x3.c +++ b/drivers/ide/pci/alim15x3.c @@ -283,14 +283,14 @@ static int ali_get_info (char *buffer, char **addr, off_t offset, int count) #endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_IDE_PROC_FS) */ /** - * ali_tune_pio - set host controller for PIO mode + * ali_set_pio_mode - set host controller for PIO mode * @drive: drive * @pio: PIO mode number * * Program the controller for the given PIO mode. */ -static void ali_tune_pio(ide_drive_t *drive, const u8 pio) +static void ali_set_pio_mode(ide_drive_t *drive, const u8 pio) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; @@ -358,21 +358,6 @@ static void ali_tune_pio(ide_drive_t *drive, const u8 pio) } /** - * ali_set_pio_mode - set up drive for PIO mode - * @drive: drive to tune - * @pio: desired mode - * - * Program the controller with the desired PIO timing for the given drive. - * Then set up the drive itself. - */ - -static void ali_set_pio_mode(ide_drive_t *drive, const u8 pio) -{ - ali_tune_pio(drive, pio); - (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio); -} - -/** * ali_udma_filter - compute UDMA mask * @drive: IDE device * @@ -401,15 +386,14 @@ static u8 ali_udma_filter(ide_drive_t *drive) } /** - * ali15x3_tune_chipset - set up chipset/drive for new speed - * @drive: drive to configure for - * @speed: desired speed + * ali_set_dma_mode - set host controller for DMA mode + * @drive: drive + * @speed: DMA mode * * Configure the hardware for the desired IDE transfer mode. - * We also do the needed drive configuration through helpers */ -static int ali15x3_tune_chipset(ide_drive_t *drive, const u8 speed) +static void ali_set_dma_mode(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; @@ -419,7 +403,7 @@ static int ali15x3_tune_chipset(ide_drive_t *drive, const u8 speed) int m5229_udma = (hwif->channel) ? 0x57 : 0x56; if (speed < XFER_PIO_0) - return 1; + return; if (speed == XFER_UDMA_6) speed1 = 0x47; @@ -450,7 +434,6 @@ static int ali15x3_tune_chipset(ide_drive_t *drive, const u8 speed) pci_write_config_byte(dev, 0x4b, tmpbyte); } } - return (ide_config_drive_speed(drive, speed)); } /** @@ -699,7 +682,7 @@ static void __devinit init_hwif_common_ali15x3 (ide_hwif_t *hwif) { hwif->autodma = 0; hwif->set_pio_mode = &ali_set_pio_mode; - hwif->speedproc = &ali15x3_tune_chipset; + hwif->set_dma_mode = &ali_set_dma_mode; hwif->udma_filter = &ali_udma_filter; /* don't use LBA48 DMA on ALi devices before rev 0xC5 */ @@ -711,6 +694,10 @@ static void __devinit init_hwif_common_ali15x3 (ide_hwif_t *hwif) return; } + /* + * check in ->init_dma guarantees m5229_revision >= 0x20 here + */ + if (m5229_revision > 0x20) hwif->atapi_dma = 1; @@ -728,18 +715,15 @@ static void __devinit init_hwif_common_ali15x3 (ide_hwif_t *hwif) hwif->mwdma_mask = 0x07; hwif->swdma_mask = 0x07; - if (m5229_revision >= 0x20) { - /* - * M1543C or newer for DMAing - */ - hwif->ide_dma_check = &ali15x3_config_drive_for_dma; - hwif->dma_setup = &ali15x3_dma_setup; - if (!noautodma) - hwif->autodma = 1; - - if (hwif->cbl != ATA_CBL_PATA40_SHORT) - hwif->cbl = ata66_ali15x3(hwif); - } + hwif->ide_dma_check = &ali15x3_config_drive_for_dma; + hwif->dma_setup = &ali15x3_dma_setup; + + if (hwif->cbl != ATA_CBL_PATA40_SHORT) + hwif->cbl = ata66_ali15x3(hwif); + + if (!noautodma) + hwif->autodma = 1; + hwif->drives[0].autodma = hwif->autodma; hwif->drives[1].autodma = hwif->autodma; } diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c index 513205e52ad2..6ff4089a2379 100644 --- a/drivers/ide/pci/amd74xx.c +++ b/drivers/ide/pci/amd74xx.c @@ -1,5 +1,5 @@ /* - * Version 2.22 + * Version 2.23 * * AMD 755/756/766/8111 and nVidia nForce/2/2s/3/3s/CK804/MCP04 * IDE driver for Linux. @@ -229,20 +229,16 @@ static void amd_set_speed(struct pci_dev *dev, unsigned char dn, struct ide_timi } /* - * amd_set_drive() computes timing values configures the drive and - * the chipset to a desired transfer mode. It also can be called - * by upper layers. + * amd_set_drive() computes timing values and configures the chipset + * to a desired transfer mode. It also can be called by upper layers. */ -static int amd_set_drive(ide_drive_t *drive, const u8 speed) +static void amd_set_drive(ide_drive_t *drive, const u8 speed) { ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1); struct ide_timing t, p; int T, UT; - if (speed != XFER_PIO_SLOW) - ide_config_drive_speed(drive, speed); - T = 1000000000 / amd_clock; UT = (amd_config->udma_mask == ATA_UDMA2) ? T : (T / 2); @@ -257,12 +253,6 @@ static int amd_set_drive(ide_drive_t *drive, const u8 speed) if (speed == XFER_UDMA_6 && amd_clock <= 33333) t.udma = 15; amd_set_speed(HWIF(drive)->pci_dev, drive->dn, &t); - - if (!drive->init_speed) - drive->init_speed = speed; - drive->current_speed = speed; - - return 0; } /* @@ -399,7 +389,7 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif) hwif->autodma = 0; hwif->set_pio_mode = &amd_set_pio_mode; - hwif->speedproc = &amd_set_drive; + hwif->set_dma_mode = &amd_set_drive; for (i = 0; i < 2; i++) { hwif->drives[i].io_32bit = 1; @@ -441,7 +431,8 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif) .enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, \ .bootable = ON_BOARD, \ .host_flags = IDE_HFLAG_PIO_NO_BLACKLIST \ - | IDE_HFLAG_PIO_NO_DOWNGRADE, \ + | IDE_HFLAG_PIO_NO_DOWNGRADE \ + | IDE_HFLAG_POST_SET_MODE, \ .pio_mask = ATA_PIO5, \ } @@ -454,7 +445,8 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif) .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, \ .bootable = ON_BOARD, \ .host_flags = IDE_HFLAG_PIO_NO_BLACKLIST \ - | IDE_HFLAG_PIO_NO_DOWNGRADE, \ + | IDE_HFLAG_PIO_NO_DOWNGRADE \ + | IDE_HFLAG_POST_SET_MODE, \ .pio_mask = ATA_PIO5, \ } diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c index 178876a3afca..0eb97f021d39 100644 --- a/drivers/ide/pci/atiixp.c +++ b/drivers/ide/pci/atiixp.c @@ -122,14 +122,14 @@ static void atiixp_dma_host_off(ide_drive_t *drive) } /** - * atiixp_tune_pio - tune a drive attached to a ATIIXP - * @drive: drive to tune - * @pio: desired PIO mode + * atiixp_set_pio_mode - set host controller for PIO mode + * @drive: drive + * @pio: PIO mode number * * Set the interface PIO mode. */ -static void atiixp_tune_pio(ide_drive_t *drive, u8 pio) +static void atiixp_set_pio_mode(ide_drive_t *drive, const u8 pio) { struct pci_dev *dev = drive->hwif->pci_dev; unsigned long flags; @@ -153,23 +153,16 @@ static void atiixp_tune_pio(ide_drive_t *drive, u8 pio) spin_unlock_irqrestore(&atiixp_lock, flags); } -static void atiixp_set_pio_mode(ide_drive_t *drive, const u8 pio) -{ - atiixp_tune_pio(drive, pio); - (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio); -} - /** - * atiixp_tune_chipset - tune a ATIIXP interface - * @drive: IDE drive to tune - * @speed: speed to configure + * atiixp_set_dma_mode - set host controller for DMA mode + * @drive: drive + * @speed: DMA mode * - * Set a ATIIXP interface channel to the desired speeds. This involves - * requires the right timing data into the ATIIXP configuration space - * then setting the drive parameters appropriately + * Set a ATIIXP host controller to the desired DMA mode. This involves + * programming the right timing data into the PCI configuration space. */ -static int atiixp_speedproc(ide_drive_t *drive, const u8 speed) +static void atiixp_set_dma_mode(ide_drive_t *drive, const u8 speed) { struct pci_dev *dev = drive->hwif->pci_dev; unsigned long flags; @@ -204,9 +197,7 @@ static int atiixp_speedproc(ide_drive_t *drive, const u8 speed) else pio = speed - XFER_PIO_0; - atiixp_tune_pio(drive, pio); - - return ide_config_drive_speed(drive, speed); + atiixp_set_pio_mode(drive, pio); } /** @@ -249,7 +240,7 @@ static void __devinit init_hwif_atiixp(ide_hwif_t *hwif) hwif->autodma = 0; hwif->set_pio_mode = &atiixp_set_pio_mode; - hwif->speedproc = &atiixp_speedproc; + hwif->set_dma_mode = &atiixp_set_dma_mode; hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c index 0b568c60f926..d50f15e34b80 100644 --- a/drivers/ide/pci/cmd64x.c +++ b/drivers/ide/pci/cmd64x.c @@ -280,10 +280,9 @@ static void cmd64x_set_pio_mode(ide_drive_t *drive, const u8 pio) return; cmd64x_tune_pio(drive, pio); - (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio); } -static int cmd64x_tune_chipset(ide_drive_t *drive, const u8 speed) +static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; @@ -324,13 +323,11 @@ static int cmd64x_tune_chipset(ide_drive_t *drive, const u8 speed) program_cycle_times(drive, 480, 215); break; default: - return 1; + return; } if (speed >= XFER_SW_DMA_0) (void) pci_write_config_byte(dev, pciU, regU); - - return ide_config_drive_speed(drive, speed); } static int cmd64x_config_drive_for_dma (ide_drive_t *drive) @@ -524,7 +521,7 @@ static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif) pci_read_config_byte(dev, PCI_REVISION_ID, &rev); hwif->set_pio_mode = &cmd64x_set_pio_mode; - hwif->speedproc = &cmd64x_tune_chipset; + hwif->set_dma_mode = &cmd64x_set_dma_mode; hwif->drives[0].autotune = hwif->drives[1].autotune = 1; diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c index 1217d2a747fb..fbce90048aec 100644 --- a/drivers/ide/pci/cs5520.c +++ b/drivers/ide/pci/cs5520.c @@ -96,22 +96,13 @@ static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio) reg = inb(hwif->dma_base + 0x02 + 8*controller); reg |= 1<<((drive->dn&1)+5); outb(reg, hwif->dma_base + 0x02 + 8*controller); - - (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio); } -static int cs5520_tune_chipset(ide_drive_t *drive, const u8 speed) +static void cs5520_set_dma_mode(ide_drive_t *drive, const u8 speed) { printk(KERN_ERR "cs55x0: bad ide timing.\n"); cs5520_set_pio_mode(drive, 0); - - /* - * FIXME: this is incorrect to return zero here but - * since all users of ide_set_xfer_rate() ignore - * the return value it is not a problem currently - */ - return 0; } static int cs5520_config_drive_xfer_rate(ide_drive_t *drive) @@ -150,26 +141,25 @@ static int cs5520_dma_on(ide_drive_t *drive) static void __devinit init_hwif_cs5520(ide_hwif_t *hwif) { hwif->set_pio_mode = &cs5520_set_pio_mode; - hwif->speedproc = &cs5520_tune_chipset; - hwif->ide_dma_check = &cs5520_config_drive_xfer_rate; - hwif->ide_dma_on = &cs5520_dma_on; + hwif->set_dma_mode = &cs5520_set_dma_mode; - if(!noautodma) - hwif->autodma = 1; - - if(!hwif->dma_base) - { - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; + if (hwif->dma_base == 0) { + hwif->drives[1].autotune = hwif->drives[0].autotune = 1; return; } + hwif->ide_dma_check = &cs5520_config_drive_xfer_rate; + hwif->ide_dma_on = &cs5520_dma_on; + /* ATAPI is harder so leave it for now */ hwif->atapi_dma = 0; hwif->ultra_mask = 0; hwif->swdma_mask = 0; hwif->mwdma_mask = 0; - + + if (!noautodma) + hwif->autodma = 1; + hwif->drives[0].autodma = hwif->autodma; hwif->drives[1].autodma = hwif->autodma; } diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c index 741507b4cd93..e4121577cef0 100644 --- a/drivers/ide/pci/cs5530.c +++ b/drivers/ide/pci/cs5530.c @@ -30,22 +30,6 @@ #include <asm/io.h> #include <asm/irq.h> -/** - * cs5530_xfer_set_mode - set a new transfer mode at the drive - * @drive: drive to tune - * @mode: new mode - * - * Logging wrapper to the IDE driver speed configuration. This can - * probably go away now. - */ - -static int cs5530_set_xfer_mode (ide_drive_t *drive, u8 mode) -{ - printk(KERN_DEBUG "%s: cs5530_set_xfer_mode(%s)\n", - drive->name, ide_xfer_verbose(mode)); - return (ide_config_drive_speed(drive, mode)); -} - /* * Here are the standard PIO mode 0-4 timings for each "format". * Format-0 uses fast data reg timings, with slower command reg timings. @@ -62,20 +46,12 @@ static unsigned int cs5530_pio_timings[2][5] = { #define CS5530_BAD_PIO(timings) (((timings)&~0x80000000)==0x0000e132) #define CS5530_BASEREG(hwif) (((hwif)->dma_base & ~0xf) + ((hwif)->channel ? 0x30 : 0x20)) -static void cs5530_tunepio(ide_drive_t *drive, u8 pio) -{ - unsigned long basereg = CS5530_BASEREG(drive->hwif); - unsigned int format = (inl(basereg + 4) >> 31) & 1; - - outl(cs5530_pio_timings[format][pio], basereg + ((drive->dn & 1)<<3)); -} - /** - * cs5530_set_pio_mode - set PIO mode + * cs5530_set_pio_mode - set host controller for PIO mode * @drive: drive * @pio: PIO mode number * - * Handles setting of PIO mode for both the chipset and drive. + * Handles setting of PIO mode for the chipset. * * The init_hwif_cs5530() routine guarantees that all drives * will have valid default PIO timings set up before we get here. @@ -83,8 +59,10 @@ static void cs5530_tunepio(ide_drive_t *drive, u8 pio) static void cs5530_set_pio_mode(ide_drive_t *drive, const u8 pio) { - if (cs5530_set_xfer_mode(drive, XFER_PIO_0 + pio) == 0) - cs5530_tunepio(drive, pio); + unsigned long basereg = CS5530_BASEREG(drive->hwif); + unsigned int format = (inl(basereg + 4) >> 31) & 1; + + outl(cs5530_pio_timings[format][pio], basereg + ((drive->dn & 1)<<3)); } /** @@ -142,20 +120,11 @@ static int cs5530_config_dma(ide_drive_t *drive) return 1; } -static int cs5530_tune_chipset(ide_drive_t *drive, const u8 mode) +static void cs5530_set_dma_mode(ide_drive_t *drive, const u8 mode) { unsigned long basereg; unsigned int reg, timings = 0; - /* - * Tell the drive to switch to the new mode; abort on failure. - */ - if (cs5530_set_xfer_mode(drive, mode)) - return 1; /* failure */ - - /* - * Now tune the chipset to match the drive: - */ switch (mode) { case XFER_UDMA_0: timings = 0x00921250; break; case XFER_UDMA_1: timings = 0x00911140; break; @@ -180,8 +149,6 @@ static int cs5530_tune_chipset(ide_drive_t *drive, const u8 mode) outl(reg, basereg + 4); /* write drive0 config register */ outl(timings, basereg + 12); /* write drive1 config register */ } - - return 0; /* success */ } /** @@ -299,7 +266,7 @@ static void __devinit init_hwif_cs5530 (ide_hwif_t *hwif) hwif->serialized = hwif->mate->serialized = 1; hwif->set_pio_mode = &cs5530_set_pio_mode; - hwif->speedproc = &cs5530_tune_chipset; + hwif->set_dma_mode = &cs5530_set_dma_mode; basereg = CS5530_BASEREG(hwif); d0_timings = inl(basereg + 0); @@ -340,6 +307,7 @@ static ide_pci_device_t cs5530_chipset __devinitdata = { .autodma = AUTODMA, .bootable = ON_BOARD, .pio_mask = ATA_PIO4, + .host_flags = IDE_HFLAG_POST_SET_MODE, }; static int __devinit cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ide/pci/cs5535.c b/drivers/ide/pci/cs5535.c index 383b7eccbcbb..257865778f92 100644 --- a/drivers/ide/pci/cs5535.c +++ b/drivers/ide/pci/cs5535.c @@ -131,24 +131,21 @@ static void cs5535_set_speed(ide_drive_t *drive, const u8 speed) } } -/**** - * cs5535_set_drive - Configure the drive to the new speed - * @drive: Drive to set up - * @speed: desired speed +/** + * cs5535_set_dma_mode - set host controller for DMA mode + * @drive: drive + * @speed: DMA mode * - * cs5535_set_drive() configures the drive and the chipset to a - * new speed. It also can be called by upper layers. + * Programs the chipset for DMA mode. */ -static int cs5535_set_drive(ide_drive_t *drive, u8 speed) + +static void cs5535_set_dma_mode(ide_drive_t *drive, const u8 speed) { - ide_config_drive_speed(drive, speed); cs5535_set_speed(drive, speed); - - return 0; } /** - * cs5535_set_pio_mode - PIO setup + * cs5535_set_pio_mode - set host controller for PIO mode * @drive: drive * @pio: PIO mode number * @@ -157,7 +154,6 @@ static int cs5535_set_drive(ide_drive_t *drive, u8 speed) static void cs5535_set_pio_mode(ide_drive_t *drive, const u8 pio) { - ide_config_drive_speed(drive, XFER_PIO_0 + pio); cs5535_set_speed(drive, XFER_PIO_0 + pio); } @@ -194,12 +190,16 @@ static u8 __devinit cs5535_cable_detect(struct pci_dev *dev) */ static void __devinit init_hwif_cs5535(ide_hwif_t *hwif) { - int i; - hwif->autodma = 0; hwif->set_pio_mode = &cs5535_set_pio_mode; - hwif->speedproc = &cs5535_set_drive; + hwif->set_dma_mode = &cs5535_set_dma_mode; + + hwif->drives[1].autotune = hwif->drives[0].autotune = 1; + + if (hwif->dma_base == 0) + return; + hwif->ide_dma_check = &cs5535_dma_check; hwif->atapi_dma = 1; @@ -211,11 +211,7 @@ static void __devinit init_hwif_cs5535(ide_hwif_t *hwif) if (!noautodma) hwif->autodma = 1; - /* just setting autotune and not worrying about bios timings */ - for (i = 0; i < 2; i++) { - hwif->drives[i].autotune = 1; - hwif->drives[i].autodma = hwif->autodma; - } + hwif->drives[1].autodma = hwif->drives[0].autodma = hwif->autodma; } static ide_pci_device_t cs5535_chipset __devinitdata = { @@ -223,7 +219,7 @@ static ide_pci_device_t cs5535_chipset __devinitdata = { .init_hwif = init_hwif_cs5535, .autodma = AUTODMA, .bootable = ON_BOARD, - .host_flags = IDE_HFLAG_SINGLE, + .host_flags = IDE_HFLAG_SINGLE | IDE_HFLAG_POST_SET_MODE, .pio_mask = ATA_PIO4, }; diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c index a1bb10188fe5..218852aaf22a 100644 --- a/drivers/ide/pci/hpt34x.c +++ b/drivers/ide/pci/hpt34x.c @@ -43,7 +43,7 @@ #define HPT343_DEBUG_DRIVE_INFO 0 -static int hpt34x_tune_chipset(ide_drive_t *drive, const u8 speed) +static void hpt34x_set_mode(ide_drive_t *drive, const u8 speed) { struct pci_dev *dev = HWIF(drive)->pci_dev; u32 reg1= 0, tmp1 = 0, reg2 = 0, tmp2 = 0; @@ -73,13 +73,11 @@ static int hpt34x_tune_chipset(ide_drive_t *drive, const u8 speed) drive->dn, reg1, tmp1, reg2, tmp2, hi_speed, lo_speed); #endif /* HPT343_DEBUG_DRIVE_INFO */ - - return(ide_config_drive_speed(drive, speed)); } static void hpt34x_set_pio_mode(ide_drive_t *drive, const u8 pio) { - (void) hpt34x_tune_chipset(drive, (XFER_PIO_0 + pio)); + hpt34x_set_mode(drive, XFER_PIO_0 + pio); } static int hpt34x_config_drive_xfer_rate (ide_drive_t *drive) @@ -145,7 +143,8 @@ static void __devinit init_hwif_hpt34x(ide_hwif_t *hwif) hwif->autodma = 0; hwif->set_pio_mode = &hpt34x_set_pio_mode; - hwif->speedproc = &hpt34x_tune_chipset; + hwif->set_dma_mode = &hpt34x_set_mode; + hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c index 0e7d3b60d43c..8812a9bb032f 100644 --- a/drivers/ide/pci/hpt366.c +++ b/drivers/ide/pci/hpt366.c @@ -600,7 +600,7 @@ static u32 get_speed_setting(u8 speed, struct hpt_info *info) return (*info->settings)[i]; } -static int hpt36x_tune_chipset(ide_drive_t *drive, const u8 speed) +static void hpt36x_set_mode(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; @@ -623,11 +623,9 @@ static int hpt36x_tune_chipset(ide_drive_t *drive, const u8 speed) new_itr &= ~0xc0000000; pci_write_config_dword(dev, itr_addr, new_itr); - - return ide_config_drive_speed(drive, speed); } -static int hpt37x_tune_chipset(ide_drive_t *drive, const u8 speed) +static void hpt37x_set_mode(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; @@ -647,24 +645,22 @@ static int hpt37x_tune_chipset(ide_drive_t *drive, const u8 speed) if (speed < XFER_MW_DMA_0) new_itr &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */ pci_write_config_dword(dev, itr_addr, new_itr); - - return ide_config_drive_speed(drive, speed); } -static int hpt3xx_tune_chipset(ide_drive_t *drive, u8 speed) +static void hpt3xx_set_mode(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct hpt_info *info = pci_get_drvdata(hwif->pci_dev); if (info->chip_type >= HPT370) - return hpt37x_tune_chipset(drive, speed); + hpt37x_set_mode(drive, speed); else /* hpt368: hpt_minimum_revision(dev, 2) */ - return hpt36x_tune_chipset(drive, speed); + hpt36x_set_mode(drive, speed); } static void hpt3xx_set_pio_mode(ide_drive_t *drive, const u8 pio) { - (void) hpt3xx_tune_chipset (drive, XFER_PIO_0 + pio); + hpt3xx_set_mode(drive, XFER_PIO_0 + pio); } static int hpt3xx_quirkproc(ide_drive_t *drive) @@ -1257,7 +1253,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif) hwif->select_data = hwif->channel ? 0x54 : 0x50; hwif->set_pio_mode = &hpt3xx_set_pio_mode; - hwif->speedproc = &hpt3xx_tune_chipset; + hwif->set_dma_mode = &hpt3xx_set_mode; hwif->quirkproc = &hpt3xx_quirkproc; hwif->intrproc = &hpt3xx_intrproc; hwif->maskproc = &hpt3xx_maskproc; diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c index 76e91ff9420b..ecf4ce078dce 100644 --- a/drivers/ide/pci/it8213.c +++ b/drivers/ide/pci/it8213.c @@ -48,15 +48,15 @@ static u8 it8213_dma_2_pio (u8 xfer_rate) { } } -/* - * it8213_tune_pio - tune a drive - * @drive: drive to tune - * @pio: desired PIO mode +/** + * it8213_set_pio_mode - set host controller for PIO mode + * @drive: drive + * @pio: PIO mode number * * Set the interface PIO mode. */ -static void it8213_tune_pio(ide_drive_t *drive, const u8 pio) +static void it8213_set_pio_mode(ide_drive_t *drive, const u8 pio) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; @@ -105,21 +105,15 @@ static void it8213_tune_pio(ide_drive_t *drive, const u8 pio) spin_unlock_irqrestore(&tune_lock, flags); } -static void it8213_set_pio_mode(ide_drive_t *drive, const u8 pio) -{ - it8213_tune_pio(drive, pio); - ide_config_drive_speed(drive, XFER_PIO_0 + pio); -} - /** - * it8213_tune_chipset - set controller timings - * @drive: Drive to set up - * @speed: speed we want to achieve + * it8213_set_dma_mode - set host controller for DMA mode + * @drive: drive + * @speed: DMA mode * - * Tune the ITE chipset for the desired mode. + * Tune the ITE chipset for the DMA mode. */ -static int it8213_tune_chipset(ide_drive_t *drive, const u8 speed) +static void it8213_set_dma_mode(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; @@ -152,7 +146,7 @@ static int it8213_tune_chipset(ide_drive_t *drive, const u8 speed) case XFER_SW_DMA_2: break; default: - return -1; + return; } if (speed >= XFER_UDMA_0) { @@ -182,9 +176,7 @@ static int it8213_tune_chipset(ide_drive_t *drive, const u8 speed) pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); } - it8213_tune_pio(drive, it8213_dma_2_pio(speed)); - - return ide_config_drive_speed(drive, speed); + it8213_set_pio_mode(drive, it8213_dma_2_pio(speed)); } /** @@ -220,7 +212,7 @@ static void __devinit init_hwif_it8213(ide_hwif_t *hwif) { u8 reg42h = 0; - hwif->speedproc = &it8213_tune_chipset; + hwif->set_dma_mode = &it8213_set_dma_mode; hwif->set_pio_mode = &it8213_set_pio_mode; hwif->autodma = 0; diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c index 758a98230cc5..1b69d82478c6 100644 --- a/drivers/ide/pci/it821x.c +++ b/drivers/ide/pci/it821x.c @@ -229,24 +229,24 @@ static void it821x_clock_strategy(ide_drive_t *drive) } /** - * it821x_tunepio - tune a drive - * @drive: drive to tune - * @pio: the desired PIO mode + * it821x_set_pio_mode - set host controller for PIO mode + * @drive: drive + * @pio: PIO mode number * - * Try to tune the drive/host to the desired PIO mode taking into - * the consideration the maximum PIO mode supported by the other - * device on the cable. + * Tune the host to the desired PIO mode taking into the consideration + * the maximum PIO mode supported by the other device on the cable. */ -static int it821x_tunepio(ide_drive_t *drive, u8 set_pio) +static void it821x_set_pio_mode(ide_drive_t *drive, const u8 pio) { ide_hwif_t *hwif = drive->hwif; struct it821x_dev *itdev = ide_get_hwifdata(hwif); int unit = drive->select.b.unit; ide_drive_t *pair = &hwif->drives[1 - unit]; + u8 set_pio = pio; /* Spec says 89 ref driver uses 88 */ - static u16 pio[] = { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 }; + static u16 pio_timings[]= { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 }; static u8 pio_want[] = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY }; /* @@ -261,22 +261,12 @@ static int it821x_tunepio(ide_drive_t *drive, u8 set_pio) set_pio = pair_pio; } - if (itdev->smart) - return 0; - /* We prefer 66Mhz clock for PIO 0-3, don't care for PIO4 */ itdev->want[unit][1] = pio_want[set_pio]; itdev->want[unit][0] = 1; /* PIO is lowest priority */ - itdev->pio[unit] = pio[set_pio]; + itdev->pio[unit] = pio_timings[set_pio]; it821x_clock_strategy(drive); it821x_program(drive, itdev->pio[unit]); - - return ide_config_drive_speed(drive, XFER_PIO_0 + set_pio); -} - -static void it821x_set_pio_mode(ide_drive_t *drive, const u8 pio) -{ - (void)it821x_tunepio(drive, pio); } /** @@ -405,47 +395,24 @@ static int it821x_dma_end(ide_drive_t *drive) } /** - * it821x_tune_chipset - set controller timings - * @drive: Drive to set up - * @speed: speed we want to achieve + * it821x_set_dma_mode - set host controller for DMA mode + * @drive: drive + * @speed: DMA mode * - * Tune the ITE chipset for the desired mode. + * Tune the ITE chipset for the desired DMA mode. */ -static int it821x_tune_chipset(ide_drive_t *drive, const u8 speed) +static void it821x_set_dma_mode(ide_drive_t *drive, const u8 speed) { - - ide_hwif_t *hwif = drive->hwif; - struct it821x_dev *itdev = ide_get_hwifdata(hwif); - - if (itdev->smart == 0) { - switch (speed) { - /* MWDMA tuning is really hard because our MWDMA and PIO - timings are kept in the same place. We can switch in the - host dma on/off callbacks */ - case XFER_MW_DMA_2: - case XFER_MW_DMA_1: - case XFER_MW_DMA_0: - it821x_tune_mwdma(drive, (speed - XFER_MW_DMA_0)); - break; - case XFER_UDMA_6: - case XFER_UDMA_5: - case XFER_UDMA_4: - case XFER_UDMA_3: - case XFER_UDMA_2: - case XFER_UDMA_1: - case XFER_UDMA_0: - it821x_tune_udma(drive, (speed - XFER_UDMA_0)); - break; - default: - return 1; - } - - return ide_config_drive_speed(drive, speed); - } - - /* don't touch anything in the smart mode */ - return 0; + /* + * MWDMA tuning is really hard because our MWDMA and PIO + * timings are kept in the same place. We can switch in the + * host dma on/off callbacks. + */ + if (speed >= XFER_UDMA_0 && speed <= XFER_UDMA_6) + it821x_tune_udma(drive, speed - XFER_UDMA_0); + else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2) + it821x_tune_mwdma(drive, speed - XFER_MW_DMA_0); } /** @@ -629,14 +596,15 @@ static void __devinit init_hwif_it821x(ide_hwif_t *hwif) printk(KERN_WARNING "it821x: Revision 0x10, workarounds activated.\n"); } - hwif->speedproc = &it821x_tune_chipset; - hwif->set_pio_mode = &it821x_set_pio_mode; + if (idev->smart == 0) { + hwif->set_pio_mode = &it821x_set_pio_mode; + hwif->set_dma_mode = &it821x_set_dma_mode; - /* MWDMA/PIO clock switching for pass through mode */ - if(!idev->smart) { + /* MWDMA/PIO clock switching for pass through mode */ hwif->dma_start = &it821x_dma_start; hwif->ide_dma_end = &it821x_dma_end; - } + } else + hwif->host_flags |= IDE_HFLAG_NO_SET_MODE; hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; diff --git a/drivers/ide/pci/jmicron.c b/drivers/ide/pci/jmicron.c index d379fbaf6743..582b4cae2b53 100644 --- a/drivers/ide/pci/jmicron.c +++ b/drivers/ide/pci/jmicron.c @@ -85,21 +85,18 @@ static u8 __devinit ata66_jmicron(ide_hwif_t *hwif) static void jmicron_set_pio_mode(ide_drive_t *drive, const u8 pio) { - ide_config_drive_speed(drive, XFER_PIO_0 + pio); } /** - * jmicron_tune_chipset - set controller timings - * @drive: Drive to set up - * @speed: speed we want to achieve + * jmicron_set_dma_mode - set host controller for DMA mode + * @drive: drive + * @mode: DMA mode * - * As the JMicron snoops for timings all we actually need to do is - * set the transfer mode on the device. + * As the JMicron snoops for timings we don't need to do anything here. */ -static int jmicron_tune_chipset(ide_drive_t *drive, const u8 speed) +static void jmicron_set_dma_mode(ide_drive_t *drive, const u8 mode) { - return ide_config_drive_speed(drive, speed); } /** @@ -129,8 +126,8 @@ static int jmicron_config_drive_for_dma (ide_drive_t *drive) static void __devinit init_hwif_jmicron(ide_hwif_t *hwif) { - hwif->speedproc = &jmicron_tune_chipset; hwif->set_pio_mode = &jmicron_set_pio_mode; + hwif->set_dma_mode = &jmicron_set_dma_mode; hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c index 5fb1eedc8194..ad0bdcb0c02b 100644 --- a/drivers/ide/pci/pdc202xx_new.c +++ b/drivers/ide/pci/pdc202xx_new.c @@ -146,19 +146,16 @@ static struct udma_timing { { 0x1a, 0x01, 0xcb }, /* UDMA mode 6 */ }; -static int pdcnew_tune_chipset(ide_drive_t *drive, const u8 speed) +static void pdcnew_set_mode(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); u8 adj = (drive->dn & 1) ? 0x08 : 0x00; - int err; /* - * Issue SETFEATURES_XFER to the drive first. PDC202xx hardware will + * IDE core issues SETFEATURES_XFER to the drive first (thanks to + * IDE_HFLAG_POST_SET_MODE in ->host_flags). PDC202xx hardware will * automatically set the timing registers based on 100 MHz PLL output. - */ - err = ide_config_drive_speed(drive, speed); - - /* + * * As we set up the PLL to output 133 MHz for UltraDMA/133 capable * chips, we must override the default register settings... */ @@ -211,13 +208,11 @@ static int pdcnew_tune_chipset(ide_drive_t *drive, const u8 speed) set_indexed_reg(hwif, 0x10 + adj, tmp & 0x7f); } - - return err; } static void pdcnew_set_pio_mode(ide_drive_t *drive, const u8 pio) { - (void)pdcnew_tune_chipset(drive, XFER_PIO_0 + pio); + pdcnew_set_mode(drive, XFER_PIO_0 + pio); } static u8 pdcnew_cable_detect(ide_hwif_t *hwif) @@ -490,9 +485,9 @@ static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif) hwif->autodma = 0; hwif->set_pio_mode = &pdcnew_set_pio_mode; + hwif->set_dma_mode = &pdcnew_set_mode; hwif->quirkproc = &pdcnew_quirkproc; - hwif->speedproc = &pdcnew_tune_chipset; hwif->resetproc = &pdcnew_reset; hwif->err_stops_fifo = 1; @@ -583,6 +578,7 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = { .bootable = OFF_BOARD, .pio_mask = ATA_PIO4, .udma_mask = 0x3f, /* udma0-5 */ + .host_flags = IDE_HFLAG_POST_SET_MODE, },{ /* 1 */ .name = "PDC20269", .init_setup = init_setup_pdcnew, @@ -592,6 +588,7 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = { .bootable = OFF_BOARD, .pio_mask = ATA_PIO4, .udma_mask = 0x7f, /* udma0-6*/ + .host_flags = IDE_HFLAG_POST_SET_MODE, },{ /* 2 */ .name = "PDC20270", .init_setup = init_setup_pdc20270, @@ -601,6 +598,7 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = { .bootable = OFF_BOARD, .pio_mask = ATA_PIO4, .udma_mask = 0x3f, /* udma0-5 */ + .host_flags = IDE_HFLAG_POST_SET_MODE, },{ /* 3 */ .name = "PDC20271", .init_setup = init_setup_pdcnew, @@ -610,6 +608,7 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = { .bootable = OFF_BOARD, .pio_mask = ATA_PIO4, .udma_mask = 0x7f, /* udma0-6*/ + .host_flags = IDE_HFLAG_POST_SET_MODE, },{ /* 4 */ .name = "PDC20275", .init_setup = init_setup_pdcnew, @@ -619,6 +618,7 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = { .bootable = OFF_BOARD, .pio_mask = ATA_PIO4, .udma_mask = 0x7f, /* udma0-6*/ + .host_flags = IDE_HFLAG_POST_SET_MODE, },{ /* 5 */ .name = "PDC20276", .init_setup = init_setup_pdc20276, @@ -628,6 +628,7 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = { .bootable = OFF_BOARD, .pio_mask = ATA_PIO4, .udma_mask = 0x7f, /* udma0-6*/ + .host_flags = IDE_HFLAG_POST_SET_MODE, },{ /* 6 */ .name = "PDC20277", .init_setup = init_setup_pdcnew, @@ -637,6 +638,7 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = { .bootable = OFF_BOARD, .pio_mask = ATA_PIO4, .udma_mask = 0x7f, /* udma0-6*/ + .host_flags = IDE_HFLAG_POST_SET_MODE, } }; diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c index b578307fad51..8c3e8cf36ec9 100644 --- a/drivers/ide/pci/pdc202xx_old.c +++ b/drivers/ide/pci/pdc202xx_old.c @@ -63,7 +63,7 @@ static const char *pdc_quirk_drives[] = { static void pdc_old_disable_66MHz_clock(ide_hwif_t *); -static int pdc202xx_tune_chipset(ide_drive_t *drive, const u8 speed) +static void pdc202xx_set_mode(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; @@ -138,13 +138,11 @@ static int pdc202xx_tune_chipset(ide_drive_t *drive, const u8 speed) pci_read_config_dword(dev, drive_pci, &drive_conf); printk("0x%08x\n", drive_conf); #endif - - return ide_config_drive_speed(drive, speed); } static void pdc202xx_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pdc202xx_tune_chipset(drive, XFER_PIO_0 + pio); + pdc202xx_set_mode(drive, XFER_PIO_0 + pio); } static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif) @@ -330,14 +328,13 @@ static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif) hwif->autodma = 0; hwif->set_pio_mode = &pdc202xx_set_pio_mode; + hwif->set_dma_mode = &pdc202xx_set_mode; hwif->quirkproc = &pdc202xx_quirkproc; if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) hwif->resetproc = &pdc202xx_reset; - hwif->speedproc = &pdc202xx_tune_chipset; - hwif->err_stops_fifo = 1; hwif->drives[0].autotune = hwif->drives[1].autotune = 1; diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c index fd8214a7ab98..38c91ba6497b 100644 --- a/drivers/ide/pci/piix.c +++ b/drivers/ide/pci/piix.c @@ -137,13 +137,14 @@ static u8 piix_dma_2_pio (u8 xfer_rate) { } /** - * piix_tune_pio - tune PIIX for PIO mode - * @drive: drive to tune - * @pio: desired PIO mode + * piix_set_pio_mode - set host controller for PIO mode + * @drive: drive + * @pio: PIO mode number * * Set the interface PIO mode based upon the settings done by AMI BIOS. */ -static void piix_tune_pio (ide_drive_t *drive, u8 pio) + +static void piix_set_pio_mode(ide_drive_t *drive, const u8 pio) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; @@ -204,31 +205,15 @@ static void piix_tune_pio (ide_drive_t *drive, u8 pio) } /** - * piix_set_pio_mode - set PIO mode - * @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_set_pio_mode(ide_drive_t *drive, const u8 pio) -{ - 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 - * @speed: speed to configure + * piix_set_dma_mode - set host controller for DMA mode + * @drive: drive + * @speed: DMA mode * - * Set a PIIX interface channel to the desired speeds. This involves - * requires the right timing data into the PIIX configuration space - * then setting the drive parameters appropriately + * Set a PIIX host controller to the desired DMA mode. This involves + * programming the right timing data into the PCI configuration space. */ -static int piix_tune_chipset(ide_drive_t *drive, const u8 speed) +static void piix_set_dma_mode(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; @@ -259,7 +244,7 @@ static int piix_tune_chipset(ide_drive_t *drive, const u8 speed) case XFER_MW_DMA_2: case XFER_MW_DMA_1: case XFER_SW_DMA_2: break; - default: return -1; + default: return; } if (speed >= XFER_UDMA_0) { @@ -288,9 +273,7 @@ static int piix_tune_chipset(ide_drive_t *drive, const u8 speed) pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); } - piix_tune_pio(drive, piix_dma_2_pio(speed)); - - return ide_config_drive_speed(drive, speed); + piix_set_pio_mode(drive, piix_dma_2_pio(speed)); } /** @@ -448,7 +431,8 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif) hwif->autodma = 0; hwif->set_pio_mode = &piix_set_pio_mode; - hwif->speedproc = &piix_tune_chipset; + hwif->set_dma_mode = &piix_set_dma_mode; + hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c index 79ecab689489..ee0e3f554d9a 100644 --- a/drivers/ide/pci/sc1200.c +++ b/drivers/ide/pci/sc1200.c @@ -68,17 +68,6 @@ static unsigned short sc1200_get_pci_clock (void) return pci_clock; } -extern char *ide_xfer_verbose (byte xfer_rate); - -/* - * Set a new transfer mode at the drive - */ -static int sc1200_set_xfer_mode (ide_drive_t *drive, byte mode) -{ - printk("%s: sc1200_set_xfer_mode(%s)\n", drive->name, ide_xfer_verbose(mode)); - return ide_config_drive_speed(drive, mode); -} - /* * Here are the standard PIO mode 0-4 timings for each "format". * Format-0 uses fast data reg timings, with slower command reg timings. @@ -138,7 +127,7 @@ out: return mask; } -static int sc1200_tune_chipset(ide_drive_t *drive, const u8 mode) +static void sc1200_set_dma_mode(ide_drive_t *drive, const u8 mode) { ide_hwif_t *hwif = HWIF(drive); int unit = drive->select.b.unit; @@ -146,17 +135,9 @@ static int sc1200_tune_chipset(ide_drive_t *drive, const u8 mode) unsigned short pci_clock; unsigned int basereg = hwif->channel ? 0x50 : 0x40; - /* - * Tell the drive to switch to the new mode; abort on failure. - */ - if (sc1200_set_xfer_mode(drive, mode)) - return 1; /* failure */ - pci_clock = sc1200_get_pci_clock(); /* - * Now tune the chipset to match the drive: - * * Note that each DMA mode has several timings associated with it. * The correct timing depends on the fast PCI clock freq. */ @@ -216,8 +197,6 @@ static int sc1200_tune_chipset(ide_drive_t *drive, const u8 mode) } else { pci_write_config_dword(hwif->pci_dev, basereg+12, timings); } - - return 0; /* success */ } /* @@ -286,13 +265,12 @@ static void sc1200_set_pio_mode(ide_drive_t *drive, const u8 pio) if (mode != -1) { printk("SC1200: %s: changing (U)DMA mode\n", drive->name); hwif->dma_off_quietly(drive); - if (sc1200_tune_chipset(drive, mode) == 0) + if (ide_set_dma_mode(drive, mode) == 0) hwif->dma_host_on(drive); return; } - if (sc1200_set_xfer_mode(drive, XFER_PIO_0 + pio) == 0) - sc1200_tunepio(drive, pio); + sc1200_tunepio(drive, pio); } #ifdef CONFIG_PM @@ -400,16 +378,20 @@ static void __devinit init_hwif_sc1200 (ide_hwif_t *hwif) if (hwif->mate) hwif->serialized = hwif->mate->serialized = 1; hwif->autodma = 0; - if (hwif->dma_base) { - hwif->udma_filter = sc1200_udma_filter; - hwif->ide_dma_check = &sc1200_config_dma; - hwif->ide_dma_end = &sc1200_ide_dma_end; - if (!noautodma) - hwif->autodma = 1; - - hwif->set_pio_mode = &sc1200_set_pio_mode; - hwif->speedproc = &sc1200_tune_chipset; - } + + hwif->set_pio_mode = &sc1200_set_pio_mode; + hwif->set_dma_mode = &sc1200_set_dma_mode; + + if (hwif->dma_base == 0) + return; + + hwif->udma_filter = sc1200_udma_filter; + hwif->ide_dma_check = &sc1200_config_dma; + hwif->ide_dma_end = &sc1200_ide_dma_end; + + if (!noautodma) + hwif->autodma = 1; + hwif->atapi_dma = 1; hwif->ultra_mask = 0x07; hwif->mwdma_mask = 0x07; @@ -423,7 +405,7 @@ static ide_pci_device_t sc1200_chipset __devinitdata = { .init_hwif = init_hwif_sc1200, .autodma = AUTODMA, .bootable = ON_BOARD, - .host_flags = IDE_HFLAG_ABUSE_DMA_MODES, + .host_flags = IDE_HFLAG_ABUSE_DMA_MODES | IDE_HFLAG_POST_SET_MODE, .pio_mask = ATA_PIO4, }; diff --git a/drivers/ide/pci/scc_pata.c b/drivers/ide/pci/scc_pata.c index 66a526e0ece4..67f06dd11b34 100644 --- a/drivers/ide/pci/scc_pata.c +++ b/drivers/ide/pci/scc_pata.c @@ -190,15 +190,15 @@ scc_ide_outsl(unsigned long port, void *addr, u32 count) } /** - * scc_tune_pio - tune a drive PIO mode - * @drive: drive to tune - * @mode_wanted: the target operating mode + * scc_set_pio_mode - set host controller for PIO mode + * @drive: drive + * @pio: PIO mode number * * Load the timing settings for this device mode into the * controller. */ -static void scc_tune_pio(ide_drive_t *drive, const u8 pio) +static void scc_set_pio_mode(ide_drive_t *drive, const u8 pio) { ide_hwif_t *hwif = HWIF(drive); struct scc_ports *ports = ide_get_hwifdata(hwif); @@ -221,22 +221,16 @@ static void scc_tune_pio(ide_drive_t *drive, const u8 pio) out_be32((void __iomem *)pioct_port, reg); } -static void scc_set_pio_mode(ide_drive_t *drive, const u8 pio) -{ - scc_tune_pio(drive, pio); - ide_config_drive_speed(drive, XFER_PIO_0 + pio); -} - /** - * scc_tune_chipset - tune a drive DMA mode - * @drive: Drive to set up - * @speed: speed we want to achieve + * scc_set_dma_mode - set host controller for DMA mode + * @drive: drive + * @speed: DMA mode * * Load the timing settings for this device mode into the * controller. */ -static int scc_tune_chipset(ide_drive_t *drive, const u8 speed) +static void scc_set_dma_mode(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct scc_ports *ports = ide_get_hwifdata(hwif); @@ -271,7 +265,7 @@ static int scc_tune_chipset(ide_drive_t *drive, const u8 speed) idx = speed - XFER_UDMA_0; break; default: - return 1; + return; } jcactsel = JCACTSELtbl[offset][idx]; @@ -287,8 +281,6 @@ static int scc_tune_chipset(ide_drive_t *drive, const u8 speed) } reg = JCTSStbl[offset][idx] << 16 | JCENVTtbl[offset][idx]; out_be32((void __iomem *)udenvt_port, reg); - - return ide_config_drive_speed(drive, speed); } /** @@ -708,8 +700,8 @@ static void __devinit init_hwif_scc(ide_hwif_t *hwif) hwif->dma_setup = scc_dma_setup; hwif->ide_dma_end = scc_ide_dma_end; - hwif->speedproc = scc_tune_chipset; hwif->set_pio_mode = scc_set_pio_mode; + hwif->set_dma_mode = scc_set_dma_mode; hwif->ide_dma_check = scc_config_drive_for_dma; hwif->ide_dma_test_irq = scc_dma_test_irq; hwif->udma_filter = scc_udma_filter; diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c index 0351cf210427..49ec0ac64a4b 100644 --- a/drivers/ide/pci/serverworks.c +++ b/drivers/ide/pci/serverworks.c @@ -124,7 +124,7 @@ static u8 svwks_csb_check (struct pci_dev *dev) return 0; } -static void svwks_tune_pio(ide_drive_t *drive, const u8 pio) +static void svwks_set_pio_mode(ide_drive_t *drive, const u8 pio) { static const u8 pio_modes[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 }; static const u8 drive_pci[] = { 0x41, 0x40, 0x43, 0x42 }; @@ -145,7 +145,7 @@ static void svwks_tune_pio(ide_drive_t *drive, const u8 pio) } } -static int svwks_tune_chipset(ide_drive_t *drive, const u8 speed) +static void svwks_set_dma_mode(ide_drive_t *drive, const u8 speed) { static const u8 udma_modes[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 }; static const u8 dma_modes[] = { 0x77, 0x21, 0x20 }; @@ -193,14 +193,6 @@ static int svwks_tune_chipset(ide_drive_t *drive, const u8 speed) pci_write_config_byte(dev, drive_pci2[drive->dn], dma_timing); pci_write_config_byte(dev, (0x56|hwif->channel), ultra_timing); pci_write_config_byte(dev, 0x54, ultra_enable); - - return (ide_config_drive_speed(drive, speed)); -} - -static void svwks_set_pio_mode(ide_drive_t *drive, const u8 pio) -{ - svwks_tune_pio(drive, pio); - (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio); } static int svwks_config_drive_xfer_rate (ide_drive_t *drive) @@ -384,7 +376,7 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif) hwif->irq = hwif->channel ? 15 : 14; hwif->set_pio_mode = &svwks_set_pio_mode; - hwif->speedproc = &svwks_tune_chipset; + hwif->set_dma_mode = &svwks_set_dma_mode; hwif->udma_filter = &svwks_udma_filter; hwif->atapi_dma = 1; diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c index c292e1de1d56..85ffaaa39b1b 100644 --- a/drivers/ide/pci/sgiioc4.c +++ b/drivers/ide/pci/sgiioc4.c @@ -291,12 +291,8 @@ static void sgiioc4_dma_off_quietly(ide_drive_t *drive) drive->hwif->dma_host_off(drive); } -static int sgiioc4_speedproc(ide_drive_t *drive, const u8 speed) +static void sgiioc4_set_dma_mode(ide_drive_t *drive, const u8 speed) { - if (speed != XFER_MW_DMA_2) - return 1; - - return ide_config_drive_speed(drive, speed); } static int sgiioc4_ide_dma_check(ide_drive_t *drive) @@ -591,11 +587,9 @@ static void __devinit ide_init_sgiioc4(ide_hwif_t * hwif) { hwif->mmio = 1; - hwif->atapi_dma = 1; - hwif->mwdma_mask = 0x04; hwif->pio_mask = 0x00; hwif->set_pio_mode = NULL; /* Sets timing for PIO mode */ - hwif->speedproc = &sgiioc4_speedproc; + hwif->set_dma_mode = &sgiioc4_set_dma_mode; hwif->selectproc = NULL;/* Use the default routine to select drive */ hwif->reset_poll = NULL;/* No HBA specific reset_poll needed */ hwif->pre_reset = NULL; /* No HBA specific pre_set needed */ @@ -606,6 +600,14 @@ ide_init_sgiioc4(ide_hwif_t * hwif) hwif->quirkproc = NULL; hwif->busproc = NULL; + hwif->INB = &sgiioc4_INB; + + if (hwif->dma_base == 0) + return; + + hwif->atapi_dma = 1; + hwif->mwdma_mask = 0x04; + hwif->dma_setup = &sgiioc4_ide_dma_setup; hwif->dma_start = &sgiioc4_ide_dma_start; hwif->ide_dma_end = &sgiioc4_ide_dma_end; @@ -617,8 +619,6 @@ ide_init_sgiioc4(ide_hwif_t * hwif) hwif->dma_host_off = &sgiioc4_dma_host_off; hwif->dma_lost_irq = &sgiioc4_dma_lost_irq; hwif->dma_timeout = &ide_dma_timeout; - - hwif->INB = &sgiioc4_INB; } static int __devinit @@ -688,8 +688,6 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev) /* Initializing chipset IRQ Registers */ writel(0x03, (void __iomem *)(irqport + IOC4_INTR_SET * 4)); - ide_init_sgiioc4(hwif); - hwif->autodma = 0; if (dma_base && ide_dma_sgiioc4(hwif, dma_base) == 0) { @@ -699,6 +697,8 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev) printk(KERN_INFO "%s: %s Bus-Master DMA disabled\n", hwif->name, DRV_NAME); + ide_init_sgiioc4(hwif); + if (probe_hwif_init(hwif)) return -EIO; diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c index 5d1e5e52a044..ce7784996d12 100644 --- a/drivers/ide/pci/siimage.c +++ b/drivers/ide/pci/siimage.c @@ -165,16 +165,16 @@ out: } /** - * sil_tune_pio - tune a drive - * @drive: drive to tune - * @pio: the desired PIO mode + * sil_set_pio_mode - set host controller for PIO mode + * @drive: drive + * @pio: PIO mode number * * Load the timing settings for this device mode into the * controller. If we are in PIO mode 3 or 4 turn on IORDY * monitoring (bit 9). The TF timing is bits 31:16 */ -static void sil_tune_pio(ide_drive_t *drive, u8 pio) +static void sil_set_pio_mode(ide_drive_t *drive, u8 pio) { const u16 tf_speed[] = { 0x328a, 0x2283, 0x1281, 0x10c3, 0x10c1 }; const u16 data_speed[] = { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 }; @@ -234,21 +234,15 @@ static void sil_tune_pio(ide_drive_t *drive, u8 pio) } } -static void sil_set_pio_mode(ide_drive_t *drive, const u8 pio) -{ - sil_tune_pio(drive, pio); - (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio); -} - /** - * siimage_tune_chipset - set controller timings - * @drive: Drive to set up - * @speed: speed we want to achieve + * sil_set_dma_mode - set host controller for DMA mode + * @drive: drive + * @speed: DMA mode * - * Tune the SII chipset for the desired mode. + * Tune the SiI chipset for the desired DMA mode. */ -static int siimage_tune_chipset(ide_drive_t *drive, const u8 speed) +static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed) { u8 ultra6[] = { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 }; u8 ultra5[] = { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01 }; @@ -303,7 +297,7 @@ static int siimage_tune_chipset(ide_drive_t *drive, const u8 speed) mode |= ((unit) ? 0x30 : 0x03); break; default: - return 1; + return; } if (hwif->mmio) { @@ -315,7 +309,6 @@ static int siimage_tune_chipset(ide_drive_t *drive, const u8 speed) pci_write_config_word(hwif->pci_dev, ma, multi); pci_write_config_word(hwif->pci_dev, ua, ultra); } - return (ide_config_drive_speed(drive, speed)); } /** @@ -904,8 +897,8 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif) hwif->autodma = 0; hwif->resetproc = &siimage_reset; - hwif->speedproc = &siimage_tune_chipset; hwif->set_pio_mode = &sil_set_pio_mode; + hwif->set_dma_mode = &sil_set_dma_mode; hwif->reset_poll = &siimage_reset_poll; hwif->pre_reset = &siimage_pre_reset; hwif->udma_filter = &sil_udma_filter; diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c index 3e18899de631..b375ee53d66d 100644 --- a/drivers/ide/pci/sis5513.c +++ b/drivers/ide/pci/sis5513.c @@ -451,7 +451,7 @@ static void config_drive_art_rwp (ide_drive_t *drive) } /* Set per-drive active and recovery time */ -static void config_art_rwp_pio (ide_drive_t *drive, u8 pio) +static void sis_set_pio_mode(ide_drive_t *drive, const u8 pio) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; @@ -519,20 +519,14 @@ static void config_art_rwp_pio (ide_drive_t *drive, u8 pio) } } -static void sis_set_pio_mode(ide_drive_t *drive, const u8 pio) -{ - config_art_rwp_pio(drive, pio); - (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio); -} - -static int sis5513_tune_chipset(ide_drive_t *drive, const u8 speed) +static void sis_set_dma_mode(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; u32 regdw; u8 drive_pci, reg; - /* See config_art_rwp_pio for drive pci config registers */ + /* See sis_set_pio_mode() for drive PCI config registers */ drive_pci = 0x40; if (chipset_family >= ATA_133) { u32 reg54h; @@ -600,8 +594,6 @@ static int sis5513_tune_chipset(ide_drive_t *drive, const u8 speed) BUG(); break; } - - return ide_config_drive_speed(drive, speed); } static int sis5513_config_xfer_rate(ide_drive_t *drive) @@ -841,7 +833,7 @@ static void __devinit init_hwif_sis5513 (ide_hwif_t *hwif) hwif->irq = hwif->channel ? 15 : 14; hwif->set_pio_mode = &sis_set_pio_mode; - hwif->speedproc = &sis5513_tune_chipset; + hwif->set_dma_mode = &sis_set_dma_mode; if (chipset_family >= ATA_133) hwif->udma_filter = sis5513_ata133_udma_filter; diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c index f492318ba797..2ef26e3f7be4 100644 --- a/drivers/ide/pci/sl82c105.c +++ b/drivers/ide/pci/sl82c105.c @@ -75,7 +75,7 @@ static unsigned int get_pio_timings(ide_drive_t *drive, u8 pio) /* * Configure the chipset for PIO mode. */ -static void sl82c105_tune_pio(ide_drive_t *drive, const u8 pio) +static void sl82c105_set_pio_mode(ide_drive_t *drive, const u8 pio) { struct pci_dev *dev = HWIF(drive)->pci_dev; int reg = 0x44 + drive->dn * 4; @@ -105,9 +105,9 @@ static void sl82c105_tune_pio(ide_drive_t *drive, const u8 pio) } /* - * Configure the drive and chipset for a new transfer speed. + * Configure the chipset for DMA mode. */ -static int sl82c105_tune_chipset(ide_drive_t *drive, const u8 speed) +static void sl82c105_set_dma_mode(ide_drive_t *drive, const u8 speed) { static u16 mwdma_timings[] = {0x0707, 0x0201, 0x0200}; u16 drv_ctrl; @@ -140,10 +140,8 @@ static int sl82c105_tune_chipset(ide_drive_t *drive, const u8 speed) } break; default: - return -1; + return; } - - return ide_config_drive_speed(drive, speed); } /* @@ -306,17 +304,6 @@ static void sl82c105_resetproc(ide_drive_t *drive) pci_read_config_dword(dev, 0x40, &val); pci_set_drvdata(dev, (void *)val); } - -/* - * We only deal with PIO mode here - DMA mode 'using_dma' is not - * initialised at the point that this function is called. - */ -static void sl82c105_set_pio_mode(ide_drive_t *drive, const u8 pio) -{ - sl82c105_tune_pio(drive, pio); - - (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio); -} /* * Return the revision of the Winbond bridge @@ -383,7 +370,7 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif) DBG(("init_hwif_sl82c105(hwif: ide%d)\n", hwif->index)); hwif->set_pio_mode = &sl82c105_set_pio_mode; - hwif->speedproc = &sl82c105_tune_chipset; + hwif->set_dma_mode = &sl82c105_set_dma_mode; hwif->selectproc = &sl82c105_selectproc; hwif->resetproc = &sl82c105_resetproc; diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c index ae8e91324577..ebac87f7200a 100644 --- a/drivers/ide/pci/slc90e66.c +++ b/drivers/ide/pci/slc90e66.c @@ -42,7 +42,7 @@ static u8 slc90e66_dma_2_pio (u8 xfer_rate) { } } -static void slc90e66_tune_pio (ide_drive_t *drive, u8 pio) +static void slc90e66_set_pio_mode(ide_drive_t *drive, const u8 pio) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; @@ -95,13 +95,7 @@ static void slc90e66_tune_pio (ide_drive_t *drive, u8 pio) spin_unlock_irqrestore(&ide_lock, flags); } -static void slc90e66_set_pio_mode(ide_drive_t *drive, const u8 pio) -{ - slc90e66_tune_pio(drive, pio); - (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio); -} - -static int slc90e66_tune_chipset(ide_drive_t *drive, const u8 speed) +static void slc90e66_set_dma_mode(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; @@ -125,7 +119,7 @@ static int slc90e66_tune_chipset(ide_drive_t *drive, const u8 speed) case XFER_MW_DMA_2: case XFER_MW_DMA_1: case XFER_SW_DMA_2: break; - default: return -1; + default: return; } if (speed >= XFER_UDMA_0) { @@ -144,9 +138,7 @@ static int slc90e66_tune_chipset(ide_drive_t *drive, const u8 speed) pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); } - slc90e66_tune_pio(drive, slc90e66_dma_2_pio(speed)); - - return ide_config_drive_speed(drive, speed); + slc90e66_set_pio_mode(drive, slc90e66_dma_2_pio(speed)); } static int slc90e66_config_drive_xfer_rate (ide_drive_t *drive) @@ -172,8 +164,8 @@ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif) if (!hwif->irq) hwif->irq = hwif->channel ? 15 : 14; - hwif->speedproc = &slc90e66_tune_chipset; hwif->set_pio_mode = &slc90e66_set_pio_mode; + hwif->set_dma_mode = &slc90e66_set_dma_mode; pci_read_config_byte(hwif->pci_dev, 0x47, ®47); diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c index e23b9cfb6eb4..840415d68d38 100644 --- a/drivers/ide/pci/tc86c001.c +++ b/drivers/ide/pci/tc86c001.c @@ -13,7 +13,7 @@ #include <linux/pci.h> #include <linux/ide.h> -static int tc86c001_tune_chipset(ide_drive_t *drive, const u8 speed) +static void tc86c001_set_mode(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); unsigned long scr_port = hwif->config_data + (drive->dn ? 0x02 : 0x00); @@ -39,13 +39,11 @@ static int tc86c001_tune_chipset(ide_drive_t *drive, const u8 speed) scr &= (speed < XFER_MW_DMA_0) ? 0xf8ff : 0xff0f; scr |= mode; outw(scr, scr_port); - - return ide_config_drive_speed(drive, speed); } static void tc86c001_set_pio_mode(ide_drive_t *drive, const u8 pio) { - (void) tc86c001_tune_chipset(drive, XFER_PIO_0 + pio); + tc86c001_set_mode(drive, XFER_PIO_0 + pio); } /* @@ -193,7 +191,8 @@ static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif) hwif->config_data = sc_base; hwif->set_pio_mode = &tc86c001_set_pio_mode; - hwif->speedproc = &tc86c001_tune_chipset; + hwif->set_dma_mode = &tc86c001_set_mode; + hwif->busproc = &tc86c001_busproc; hwif->drives[0].autotune = hwif->drives[1].autotune = 1; diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c index c3ff066eea5a..54e411d4e56c 100644 --- a/drivers/ide/pci/triflex.c +++ b/drivers/ide/pci/triflex.c @@ -40,7 +40,7 @@ #include <linux/ide.h> #include <linux/init.h> -static int triflex_tune_chipset(ide_drive_t *drive, const u8 speed) +static void triflex_set_mode(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; @@ -82,20 +82,18 @@ static int triflex_tune_chipset(ide_drive_t *drive, const u8 speed) timing = 0x0808; break; default: - return -1; + return; } triflex_timings &= ~(0xFFFF << (16 * unit)); triflex_timings |= (timing << (16 * unit)); pci_write_config_dword(dev, channel_offset, triflex_timings); - - return (ide_config_drive_speed(drive, speed)); } static void triflex_set_pio_mode(ide_drive_t *drive, const u8 pio) { - (void)triflex_tune_chipset(drive, XFER_PIO_0 + pio); + triflex_set_mode(drive, XFER_PIO_0 + pio); } static int triflex_config_drive_xfer_rate(ide_drive_t *drive) @@ -111,7 +109,7 @@ static int triflex_config_drive_xfer_rate(ide_drive_t *drive) static void __devinit init_hwif_triflex(ide_hwif_t *hwif) { hwif->set_pio_mode = &triflex_set_pio_mode; - hwif->speedproc = &triflex_tune_chipset; + hwif->set_dma_mode = &triflex_set_mode; if (hwif->dma_base == 0) return; diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c index 378feb491ec4..479e49661032 100644 --- a/drivers/ide/pci/via82cxxx.c +++ b/drivers/ide/pci/via82cxxx.c @@ -1,6 +1,6 @@ /* * - * Version 3.48 + * Version 3.49 * * VIA IDE driver for Linux. Supported southbridges: * @@ -153,21 +153,17 @@ static void via_set_speed(ide_hwif_t *hwif, u8 dn, struct ide_timing *timing) * @drive: Drive to set up * @speed: desired speed * - * via_set_drive() computes timing values configures the drive and - * the chipset to a desired transfer mode. It also can be called - * by upper layers. + * via_set_drive() computes timing values configures the chipset to + * a desired transfer mode. It also can be called by upper layers. */ -static int via_set_drive(ide_drive_t *drive, const u8 speed) +static void via_set_drive(ide_drive_t *drive, const u8 speed) { ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1); struct via82cxxx_dev *vdev = pci_get_drvdata(drive->hwif->pci_dev); struct ide_timing t, p; unsigned int T, UT; - if (speed != XFER_PIO_SLOW) - ide_config_drive_speed(drive, speed); - T = 1000000000 / via_clock; switch (vdev->via_config->udma_mask) { @@ -186,16 +182,10 @@ static int via_set_drive(ide_drive_t *drive, const u8 speed) } via_set_speed(HWIF(drive), drive->dn, &t); - - if (!drive->init_speed) - drive->init_speed = speed; - drive->current_speed = speed; - - return 0; } /** - * via_set_pio_mode - PIO setup + * via_set_pio_mode - set host controller for PIO mode * @drive: drive * @pio: PIO mode number * @@ -456,8 +446,7 @@ static void __devinit init_hwif_via82cxxx(ide_hwif_t *hwif) hwif->autodma = 0; hwif->set_pio_mode = &via_set_pio_mode; - hwif->speedproc = &via_set_drive; - + hwif->set_dma_mode = &via_set_drive; #ifdef CONFIG_PPC_CHRP if(machine_is(chrp) && _chrp_type == _CHRP_Pegasos) { @@ -500,7 +489,8 @@ static ide_pci_device_t via82cxxx_chipsets[] __devinitdata = { .enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, .bootable = ON_BOARD, .host_flags = IDE_HFLAG_PIO_NO_BLACKLIST - | IDE_HFLAG_PIO_NO_DOWNGRADE, + | IDE_HFLAG_PIO_NO_DOWNGRADE + | IDE_HFLAG_POST_SET_MODE, .pio_mask = ATA_PIO5, },{ /* 1 */ .name = "VP_IDE", @@ -510,7 +500,8 @@ static ide_pci_device_t via82cxxx_chipsets[] __devinitdata = { .enablebits = {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, .bootable = ON_BOARD, .host_flags = IDE_HFLAG_PIO_NO_BLACKLIST - | IDE_HFLAG_PIO_NO_DOWNGRADE, + | IDE_HFLAG_PIO_NO_DOWNGRADE + | IDE_HFLAG_POST_SET_MODE, .pio_mask = ATA_PIO5, } }; diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index f759a5397865..7d8873839e21 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -392,6 +392,7 @@ kauai_lookup_timing(struct kauai_timing* table, int cycle_time) for (i=0; table[i].cycle_time; i++) if (cycle_time > table[i+1].cycle_time) return table[i].timing_reg; + BUG(); return 0; } @@ -529,97 +530,12 @@ pmac_outbsync(ide_drive_t *drive, u8 value, unsigned long port) } /* - * Send the SET_FEATURE IDE command to the drive and update drive->id with - * the new state. We currently don't use the generic routine as it used to - * cause various trouble, especially with older mediabays. - * This code is sometimes triggering a spurrious interrupt though, I need - * to sort that out sooner or later and see if I can finally get the - * common version to work properly in all cases - */ -static int -pmac_ide_do_setfeature(ide_drive_t *drive, u8 command) -{ - ide_hwif_t *hwif = HWIF(drive); - int result = 1; - - disable_irq_nosync(hwif->irq); - udelay(1); - SELECT_DRIVE(drive); - SELECT_MASK(drive, 0); - udelay(1); - /* Get rid of pending error state */ - (void) hwif->INB(IDE_STATUS_REG); - /* Timeout bumped for some powerbooks */ - if (wait_for_ready(drive, 2000)) { - /* Timeout bumped for some powerbooks */ - printk(KERN_ERR "%s: pmac_ide_do_setfeature disk not ready " - "before SET_FEATURE!\n", drive->name); - goto out; - } - udelay(10); - hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG); - hwif->OUTB(command, IDE_NSECTOR_REG); - hwif->OUTB(SETFEATURES_XFER, IDE_FEATURE_REG); - hwif->OUTBSYNC(drive, WIN_SETFEATURES, IDE_COMMAND_REG); - udelay(1); - /* Timeout bumped for some powerbooks */ - result = wait_for_ready(drive, 2000); - hwif->OUTB(drive->ctl, IDE_CONTROL_REG); - if (result) - printk(KERN_ERR "%s: pmac_ide_do_setfeature disk not ready " - "after SET_FEATURE !\n", drive->name); -out: - SELECT_MASK(drive, 0); - if (result == 0) { - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - switch(command) { - case XFER_UDMA_7: - drive->id->dma_ultra |= 0x8080; break; - case XFER_UDMA_6: - drive->id->dma_ultra |= 0x4040; break; - case XFER_UDMA_5: - drive->id->dma_ultra |= 0x2020; break; - case XFER_UDMA_4: - drive->id->dma_ultra |= 0x1010; break; - case XFER_UDMA_3: - drive->id->dma_ultra |= 0x0808; break; - case XFER_UDMA_2: - drive->id->dma_ultra |= 0x0404; break; - case XFER_UDMA_1: - drive->id->dma_ultra |= 0x0202; break; - case XFER_UDMA_0: - drive->id->dma_ultra |= 0x0101; break; - case XFER_MW_DMA_2: - drive->id->dma_mword |= 0x0404; break; - case XFER_MW_DMA_1: - drive->id->dma_mword |= 0x0202; break; - case XFER_MW_DMA_0: - drive->id->dma_mword |= 0x0101; break; - case XFER_SW_DMA_2: - drive->id->dma_1word |= 0x0404; break; - case XFER_SW_DMA_1: - drive->id->dma_1word |= 0x0202; break; - case XFER_SW_DMA_0: - drive->id->dma_1word |= 0x0101; break; - default: break; - } - if (!drive->init_speed) - drive->init_speed = command; - drive->current_speed = command; - } - enable_irq(hwif->irq); - return result; -} - -/* * Old tuning functions (called on hdparm -p), sets up drive PIO timings */ static void pmac_ide_set_pio_mode(ide_drive_t *drive, const u8 pio) { - u32 *timings; + u32 *timings, t; unsigned accessTicks, recTicks; unsigned accessTime, recTime; pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; @@ -630,6 +546,7 @@ pmac_ide_set_pio_mode(ide_drive_t *drive, const u8 pio) /* which drive is it ? */ timings = &pmif->timings[drive->select.b.unit & 0x01]; + t = *timings; cycle_time = ide_pio_cycle_time(drive, pio); @@ -637,18 +554,14 @@ pmac_ide_set_pio_mode(ide_drive_t *drive, const u8 pio) case controller_sh_ata6: { /* 133Mhz cell */ u32 tr = kauai_lookup_timing(shasta_pio_timings, cycle_time); - if (tr == 0) - return; - *timings = ((*timings) & ~TR_133_PIOREG_PIO_MASK) | tr; + t = (t & ~TR_133_PIOREG_PIO_MASK) | tr; break; } case controller_un_ata6: case controller_k2_ata6: { /* 100Mhz cell */ u32 tr = kauai_lookup_timing(kauai_pio_timings, cycle_time); - if (tr == 0) - return; - *timings = ((*timings) & ~TR_100_PIOREG_PIO_MASK) | tr; + t = (t & ~TR_100_PIOREG_PIO_MASK) | tr; break; } case controller_kl_ata4: @@ -662,9 +575,9 @@ pmac_ide_set_pio_mode(ide_drive_t *drive, const u8 pio) accessTicks = min(accessTicks, 0x1fU); recTicks = SYSCLK_TICKS_66(recTime); recTicks = min(recTicks, 0x1fU); - *timings = ((*timings) & ~TR_66_PIO_MASK) | - (accessTicks << TR_66_PIO_ACCESS_SHIFT) | - (recTicks << TR_66_PIO_RECOVERY_SHIFT); + t = (t & ~TR_66_PIO_MASK) | + (accessTicks << TR_66_PIO_ACCESS_SHIFT) | + (recTicks << TR_66_PIO_RECOVERY_SHIFT); break; default: { /* 33Mhz cell */ @@ -684,11 +597,11 @@ pmac_ide_set_pio_mode(ide_drive_t *drive, const u8 pio) recTicks--; /* guess, but it's only for PIO0, so... */ ebit = 1; } - *timings = ((*timings) & ~TR_33_PIO_MASK) | + t = (t & ~TR_33_PIO_MASK) | (accessTicks << TR_33_PIO_ACCESS_SHIFT) | (recTicks << TR_33_PIO_RECOVERY_SHIFT); if (ebit) - *timings |= TR_33_PIO_E; + t |= TR_33_PIO_E; break; } } @@ -698,9 +611,7 @@ pmac_ide_set_pio_mode(ide_drive_t *drive, const u8 pio) drive->name, pio, *timings); #endif - if (pmac_ide_do_setfeature(drive, XFER_PIO_0 + pio)) - return; - + *timings = t; pmac_ide_do_update_timings(drive); } @@ -746,8 +657,6 @@ set_timings_udma_ata6(u32 *pio_timings, u32 *ultra_timings, u8 speed) if (speed > XFER_UDMA_5 || t == NULL) return 1; tr = kauai_lookup_timing(kauai_udma_timings, (int)t->udma); - if (tr == 0) - return 1; *ultra_timings = ((*ultra_timings) & ~TR_100_UDMAREG_UDMA_MASK) | tr; *ultra_timings = (*ultra_timings) | TR_100_UDMAREG_UDMA_EN; @@ -766,8 +675,6 @@ set_timings_udma_shasta(u32 *pio_timings, u32 *ultra_timings, u8 speed) if (speed > XFER_UDMA_6 || t == NULL) return 1; tr = kauai_lookup_timing(shasta_udma133_timings, (int)t->udma); - if (tr == 0) - return 1; *ultra_timings = ((*ultra_timings) & ~TR_133_UDMAREG_UDMA_MASK) | tr; *ultra_timings = (*ultra_timings) | TR_133_UDMAREG_UDMA_EN; @@ -777,12 +684,13 @@ set_timings_udma_shasta(u32 *pio_timings, u32 *ultra_timings, u8 speed) /* * Calculate MDMA timings for all cells */ -static int +static void set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2, - u8 speed, int drive_cycle_time) + u8 speed) { int cycleTime, accessTime = 0, recTime = 0; unsigned accessTicks, recTicks; + struct hd_driveid *id = drive->id; struct mdma_timings_t* tm = NULL; int i; @@ -792,11 +700,14 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2, case 1: cycleTime = 150; break; case 2: cycleTime = 120; break; default: - return 1; + BUG(); + break; } - /* Adjust for drive */ - if (drive_cycle_time && drive_cycle_time > cycleTime) - cycleTime = drive_cycle_time; + + /* Check if drive provides explicit DMA cycle time */ + if ((id->field_valid & 2) && id->eide_dma_time) + cycleTime = max_t(int, id->eide_dma_time, cycleTime); + /* OHare limits according to some old Apple sources */ if ((intf_type == controller_ohare) && (cycleTime < 150)) cycleTime = 150; @@ -824,8 +735,6 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2, break; i++; } - if (i < 0) - return 1; cycleTime = tm[i].cycleTime; accessTime = tm[i].accessTime; recTime = tm[i].recoveryTime; @@ -839,8 +748,6 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2, case controller_sh_ata6: { /* 133Mhz cell */ u32 tr = kauai_lookup_timing(shasta_mdma_timings, cycleTime); - if (tr == 0) - return 1; *timings = ((*timings) & ~TR_133_PIOREG_MDMA_MASK) | tr; *timings2 = (*timings2) & ~TR_133_UDMAREG_UDMA_EN; } @@ -848,8 +755,6 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2, case controller_k2_ata6: { /* 100Mhz cell */ u32 tr = kauai_lookup_timing(kauai_mdma_timings, cycleTime); - if (tr == 0) - return 1; *timings = ((*timings) & ~TR_100_PIOREG_MDMA_MASK) | tr; *timings2 = (*timings2) & ~TR_100_UDMAREG_UDMA_EN; } @@ -911,30 +816,23 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2, printk(KERN_ERR "%s: Set MDMA timing for mode %d, reg: 0x%08x\n", drive->name, speed & 0xf, *timings); #endif - return 0; } #endif /* #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC */ -/* - * Speedproc. This function is called by the core to set any of the standard - * DMA timing (MDMA or UDMA) to both the drive and the controller. - * You may notice we don't use this function on normal "dma check" operation, - * our dedicated function is more precise as it uses the drive provided - * cycle time value. We should probably fix this one to deal with that too... - */ -static int pmac_ide_tune_chipset(ide_drive_t *drive, const u8 speed) +static void pmac_ide_set_dma_mode(ide_drive_t *drive, const u8 speed) { int unit = (drive->select.b.unit & 0x01); int ret = 0; pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; - u32 *timings, *timings2; + u32 *timings, *timings2, tl[2]; - if (pmif == NULL) - return 1; - timings = &pmif->timings[unit]; timings2 = &pmif->timings[unit+2]; - + + /* Copy timings to local image */ + tl[0] = *timings; + tl[1] = *timings2; + switch(speed) { #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC case XFER_UDMA_6: @@ -945,38 +843,36 @@ static int pmac_ide_tune_chipset(ide_drive_t *drive, const u8 speed) case XFER_UDMA_1: case XFER_UDMA_0: if (pmif->kind == controller_kl_ata4) - ret = set_timings_udma_ata4(timings, speed); + ret = set_timings_udma_ata4(&tl[0], speed); else if (pmif->kind == controller_un_ata6 || pmif->kind == controller_k2_ata6) - ret = set_timings_udma_ata6(timings, timings2, speed); + ret = set_timings_udma_ata6(&tl[0], &tl[1], speed); else if (pmif->kind == controller_sh_ata6) - ret = set_timings_udma_shasta(timings, timings2, speed); + ret = set_timings_udma_shasta(&tl[0], &tl[1], speed); else - ret = 1; + ret = 1; break; case XFER_MW_DMA_2: case XFER_MW_DMA_1: case XFER_MW_DMA_0: - ret = set_timings_mdma(drive, pmif->kind, timings, timings2, speed, 0); + set_timings_mdma(drive, pmif->kind, &tl[0], &tl[1], speed); break; case XFER_SW_DMA_2: case XFER_SW_DMA_1: case XFER_SW_DMA_0: - return 1; + return; #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ default: ret = 1; } if (ret) - return ret; + return; - ret = pmac_ide_do_setfeature(drive, speed); - if (ret) - return ret; - - pmac_ide_do_update_timings(drive); + /* Apply timings to controller */ + *timings = tl[0]; + *timings2 = tl[1]; - return 0; + pmac_ide_do_update_timings(drive); } /* @@ -1236,6 +1132,10 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif) hwif->cbl = pmif->cable_80 ? ATA_CBL_PATA80 : ATA_CBL_PATA40; hwif->drives[0].unmask = 1; hwif->drives[1].unmask = 1; + hwif->drives[0].autotune = IDE_TUNE_AUTO; + hwif->drives[1].autotune = IDE_TUNE_AUTO; + hwif->host_flags = IDE_HFLAG_SET_PIO_MODE_KEEP_DMA | + IDE_HFLAG_POST_SET_MODE; hwif->pio_mask = ATA_PIO4; hwif->set_pio_mode = pmac_ide_set_pio_mode; if (pmif->kind == controller_un_ata6 @@ -1244,7 +1144,7 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif) hwif->selectproc = pmac_ide_kauai_selectproc; else hwif->selectproc = pmac_ide_selectproc; - hwif->speedproc = pmac_ide_tune_chipset; + hwif->set_dma_mode = pmac_ide_set_dma_mode; printk(KERN_INFO "ide%d: Found Apple %s controller, bus ID %d%s, irq %d\n", hwif->index, model_name[pmif->kind], pmif->aapl_bus_id, @@ -1679,138 +1579,16 @@ pmac_ide_destroy_dmatable (ide_drive_t *drive) } /* - * Pick up best MDMA timing for the drive and apply it - */ -static int -pmac_ide_mdma_enable(ide_drive_t *drive, u16 mode) -{ - ide_hwif_t *hwif = HWIF(drive); - pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data; - int drive_cycle_time; - struct hd_driveid *id = drive->id; - u32 *timings, *timings2; - u32 timing_local[2]; - int ret; - - /* which drive is it ? */ - timings = &pmif->timings[drive->select.b.unit & 0x01]; - timings2 = &pmif->timings[(drive->select.b.unit & 0x01) + 2]; - - /* Check if drive provide explicit cycle time */ - if ((id->field_valid & 2) && (id->eide_dma_time)) - drive_cycle_time = id->eide_dma_time; - else - drive_cycle_time = 0; - - /* Copy timings to local image */ - timing_local[0] = *timings; - timing_local[1] = *timings2; - - /* Calculate controller timings */ - ret = set_timings_mdma( drive, pmif->kind, - &timing_local[0], - &timing_local[1], - mode, - drive_cycle_time); - if (ret) - return 0; - - /* Set feature on drive */ - printk(KERN_INFO "%s: Enabling MultiWord DMA %d\n", drive->name, mode & 0xf); - ret = pmac_ide_do_setfeature(drive, mode); - if (ret) { - printk(KERN_WARNING "%s: Failed !\n", drive->name); - return 0; - } - - /* Apply timings to controller */ - *timings = timing_local[0]; - *timings2 = timing_local[1]; - - return 1; -} - -/* - * Pick up best UDMA timing for the drive and apply it - */ -static int -pmac_ide_udma_enable(ide_drive_t *drive, u16 mode) -{ - ide_hwif_t *hwif = HWIF(drive); - pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data; - u32 *timings, *timings2; - u32 timing_local[2]; - int ret; - - /* which drive is it ? */ - timings = &pmif->timings[drive->select.b.unit & 0x01]; - timings2 = &pmif->timings[(drive->select.b.unit & 0x01) + 2]; - - /* Copy timings to local image */ - timing_local[0] = *timings; - timing_local[1] = *timings2; - - /* Calculate timings for interface */ - if (pmif->kind == controller_un_ata6 - || pmif->kind == controller_k2_ata6) - ret = set_timings_udma_ata6( &timing_local[0], - &timing_local[1], - mode); - else if (pmif->kind == controller_sh_ata6) - ret = set_timings_udma_shasta( &timing_local[0], - &timing_local[1], - mode); - else - ret = set_timings_udma_ata4(&timing_local[0], mode); - if (ret) - return 0; - - /* Set feature on drive */ - printk(KERN_INFO "%s: Enabling Ultra DMA %d\n", drive->name, mode & 0x0f); - ret = pmac_ide_do_setfeature(drive, mode); - if (ret) { - printk(KERN_WARNING "%s: Failed !\n", drive->name); - return 0; - } - - /* Apply timings to controller */ - *timings = timing_local[0]; - *timings2 = timing_local[1]; - - return 1; -} - -/* * Check what is the best DMA timing setting for the drive and * call appropriate functions to apply it. */ static int pmac_ide_dma_check(ide_drive_t *drive) { - struct hd_driveid *id = drive->id; - ide_hwif_t *hwif = HWIF(drive); - int enable = 1; - drive->using_dma = 0; - - if (drive->media == ide_floppy) - enable = 0; - if (((id->capability & 1) == 0) && !__ide_dma_good_drive(drive)) - enable = 0; - if (__ide_dma_bad_drive(drive)) - enable = 0; - - if (enable) { - u8 mode = ide_max_dma_mode(drive); - - if (mode >= XFER_UDMA_0) - drive->using_dma = pmac_ide_udma_enable(drive, mode); - else if (mode >= XFER_MW_DMA_0) - drive->using_dma = pmac_ide_mdma_enable(drive, mode); - hwif->OUTB(0, IDE_CONTROL_REG); - /* Apply settings to controller */ - pmac_ide_do_update_timings(drive); - } - return 0; + if (ide_tune_dma(drive)) + return 0; + + return -1; } /* @@ -2044,7 +1822,10 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif) hwif->mwdma_mask = 0x07; hwif->swdma_mask = 0x00; break; - } + } + + hwif->autodma = 1; + hwif->drives[1].autodma = hwif->drives[0].autodma = hwif->autodma; } #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index 2ffd53461db6..1939fee616ec 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -153,8 +153,7 @@ struct host_info { }; static int nodemgr_bus_match(struct device * dev, struct device_driver * drv); -static int nodemgr_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size); +static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env); static void nodemgr_resume_ne(struct node_entry *ne); static void nodemgr_remove_ne(struct node_entry *ne); static struct node_entry *find_entry_by_guid(u64 guid); @@ -1160,12 +1159,9 @@ static void nodemgr_process_root_directory(struct host_info *hi, struct node_ent #ifdef CONFIG_HOTPLUG -static int nodemgr_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env) { struct unit_directory *ud; - int i = 0; - int length = 0; int retval = 0; /* ieee1394:venNmoNspNverN */ char buf[8 + 1 + 3 + 8 + 2 + 8 + 2 + 8 + 3 + 8 + 1]; @@ -1180,9 +1176,7 @@ static int nodemgr_uevent(struct device *dev, char **envp, int num_envp, #define PUT_ENVP(fmt,val) \ do { \ - retval = add_uevent_var(envp, num_envp, &i, \ - buffer, buffer_size, &length, \ - fmt, val); \ + retval = add_uevent_var(env, fmt, val); \ if (retval) \ return retval; \ } while (0) @@ -1201,15 +1195,12 @@ do { \ #undef PUT_ENVP - envp[i] = NULL; - return 0; } #else -static int nodemgr_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index 70b77ae67422..3d4050681325 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -434,21 +434,18 @@ static void ib_device_release(struct class_device *cdev) kfree(dev); } -static int ib_device_uevent(struct class_device *cdev, char **envp, - int num_envp, char *buf, int size) +static int ib_device_uevent(struct class_device *cdev, + struct kobj_uevent_env *env) { struct ib_device *dev = container_of(cdev, struct ib_device, class_dev); - int i = 0, len = 0; - if (add_uevent_var(envp, num_envp, &i, buf, size, &len, - "NAME=%s", dev->name)) + if (add_uevent_var(env, "NAME=%s", dev->name)) return -ENOMEM; /* * It would be nice to pass the node GUID with the event... */ - envp[i] = NULL; return 0; } diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 6545fa798b12..1b3327ad6bc4 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -349,6 +349,7 @@ struct ipoib_neigh { struct sk_buff_head queue; struct neighbour *neighbour; + struct net_device *dev; struct list_head list; }; @@ -365,7 +366,8 @@ static inline struct ipoib_neigh **to_ipoib_neigh(struct neighbour *neigh) INFINIBAND_ALEN, sizeof(void *)); } -struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neigh); +struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neigh, + struct net_device *dev); void ipoib_neigh_free(struct net_device *dev, struct ipoib_neigh *neigh); extern struct workqueue_struct *ipoib_workqueue; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index e072f3c32ce6..362610d870e4 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -517,7 +517,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) struct ipoib_path *path; struct ipoib_neigh *neigh; - neigh = ipoib_neigh_alloc(skb->dst->neighbour); + neigh = ipoib_neigh_alloc(skb->dst->neighbour, skb->dev); if (!neigh) { ++dev->stats.tx_dropped; dev_kfree_skb_any(skb); @@ -692,9 +692,10 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) goto out; } } else if (neigh->ah) { - if (unlikely(memcmp(&neigh->dgid.raw, + if (unlikely((memcmp(&neigh->dgid.raw, skb->dst->neighbour->ha + 4, - sizeof(union ib_gid)))) { + sizeof(union ib_gid))) || + (neigh->dev != dev))) { spin_lock(&priv->lock); /* * It's safe to call ipoib_put_ah() inside @@ -817,6 +818,13 @@ static void ipoib_neigh_cleanup(struct neighbour *n) unsigned long flags; struct ipoib_ah *ah = NULL; + neigh = *to_ipoib_neigh(n); + if (neigh) { + priv = netdev_priv(neigh->dev); + ipoib_dbg(priv, "neigh_destructor for bonding device: %s\n", + n->dev->name); + } else + return; ipoib_dbg(priv, "neigh_cleanup for %06x " IPOIB_GID_FMT "\n", IPOIB_QPN(n->ha), @@ -824,13 +832,10 @@ static void ipoib_neigh_cleanup(struct neighbour *n) spin_lock_irqsave(&priv->lock, flags); - neigh = *to_ipoib_neigh(n); - if (neigh) { - if (neigh->ah) - ah = neigh->ah; - list_del(&neigh->list); - ipoib_neigh_free(n->dev, neigh); - } + if (neigh->ah) + ah = neigh->ah; + list_del(&neigh->list); + ipoib_neigh_free(n->dev, neigh); spin_unlock_irqrestore(&priv->lock, flags); @@ -838,7 +843,8 @@ static void ipoib_neigh_cleanup(struct neighbour *n) ipoib_put_ah(ah); } -struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour) +struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour, + struct net_device *dev) { struct ipoib_neigh *neigh; @@ -847,6 +853,7 @@ struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour) return NULL; neigh->neighbour = neighbour; + neigh->dev = dev; *to_ipoib_neigh(neighbour) = neigh; skb_queue_head_init(&neigh->queue); ipoib_cm_set(neigh, NULL); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 827820ec66d1..9bcfc7ad6aa6 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -705,7 +705,8 @@ out: if (skb->dst && skb->dst->neighbour && !*to_ipoib_neigh(skb->dst->neighbour)) { - struct ipoib_neigh *neigh = ipoib_neigh_alloc(skb->dst->neighbour); + struct ipoib_neigh *neigh = ipoib_neigh_alloc(skb->dst->neighbour, + skb->dev); if (neigh) { kref_get(&mcast->ah->ref); diff --git a/drivers/infiniband/ulp/srp/Kconfig b/drivers/infiniband/ulp/srp/Kconfig index 3432dce29520..c74ee9633041 100644 --- a/drivers/infiniband/ulp/srp/Kconfig +++ b/drivers/infiniband/ulp/srp/Kconfig @@ -1,6 +1,7 @@ config INFINIBAND_SRP tristate "InfiniBand SCSI RDMA Protocol" depends on SCSI + select SCSI_SRP_ATTRS ---help--- Support for the SCSI RDMA Protocol over InfiniBand. This allows you to access storage devices that speak SRP over diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 9ccc63886d92..950228fb009f 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -47,6 +47,7 @@ #include <scsi/scsi_device.h> #include <scsi/scsi_dbg.h> #include <scsi/srp.h> +#include <scsi/scsi_transport_srp.h> #include <rdma/ib_cache.h> @@ -86,6 +87,8 @@ static void srp_remove_one(struct ib_device *device); static void srp_completion(struct ib_cq *cq, void *target_ptr); static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event); +static struct scsi_transport_template *ib_srp_transport_template; + static struct ib_client srp_client = { .name = "srp", .add = srp_add_one, @@ -420,6 +423,7 @@ static void srp_remove_work(struct work_struct *work) list_del(&target->list); spin_unlock(&target->srp_host->target_lock); + srp_remove_host(target->scsi_host); scsi_remove_host(target->scsi_host); ib_destroy_cm_id(target->cm_id); srp_free_target_ib(target); @@ -1544,12 +1548,24 @@ static struct scsi_host_template srp_template = { static int srp_add_target(struct srp_host *host, struct srp_target_port *target) { + struct srp_rport_identifiers ids; + struct srp_rport *rport; + sprintf(target->target_name, "SRP.T10:%016llX", (unsigned long long) be64_to_cpu(target->id_ext)); if (scsi_add_host(target->scsi_host, host->dev->dev->dma_device)) return -ENODEV; + memcpy(ids.port_id, &target->id_ext, 8); + memcpy(ids.port_id + 8, &target->ioc_guid, 8); + ids.roles = SRP_RPORT_ROLE_TARGET; + rport = srp_rport_add(target->scsi_host, &ids); + if (IS_ERR(rport)) { + scsi_remove_host(target->scsi_host); + return PTR_ERR(rport); + } + spin_lock(&host->target_lock); list_add_tail(&target->list, &host->target_list); spin_unlock(&host->target_lock); @@ -1775,6 +1791,7 @@ static ssize_t srp_create_target(struct class_device *class_dev, if (!target_host) return -ENOMEM; + target_host->transportt = ib_srp_transport_template; target_host->max_lun = SRP_MAX_LUN; target_host->max_cmd_len = sizeof ((struct srp_cmd *) (void *) 0L)->cdb; @@ -2054,10 +2071,18 @@ static void srp_remove_one(struct ib_device *device) kfree(srp_dev); } +static struct srp_function_template ib_srp_transport_functions = { +}; + static int __init srp_init_module(void) { int ret; + ib_srp_transport_template = + srp_attach_transport(&ib_srp_transport_functions); + if (!ib_srp_transport_template) + return -ENOMEM; + srp_template.sg_tablesize = srp_sg_tablesize; srp_max_iu_len = (sizeof (struct srp_cmd) + sizeof (struct srp_indirect_buf) + @@ -2066,6 +2091,7 @@ static int __init srp_init_module(void) ret = class_register(&srp_class); if (ret) { printk(KERN_ERR PFX "couldn't register class infiniband_srp\n"); + srp_release_transport(ib_srp_transport_template); return ret; } @@ -2074,6 +2100,7 @@ static int __init srp_init_module(void) ret = ib_register_client(&srp_client); if (ret) { printk(KERN_ERR PFX "couldn't register IB client\n"); + srp_release_transport(ib_srp_transport_template); ib_sa_unregister_client(&srp_sa_client); class_unregister(&srp_class); return ret; @@ -2087,6 +2114,7 @@ static void __exit srp_cleanup_module(void) ib_unregister_client(&srp_client); ib_sa_unregister_client(&srp_sa_client); class_unregister(&srp_class); + srp_release_transport(ib_srp_transport_template); } module_init(srp_init_module); diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 2d87357e2b2b..63512d906f02 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -114,28 +114,6 @@ config INPUT_JOYDEV To compile this driver as a module, choose M here: the module will be called joydev. -config INPUT_TSDEV - tristate "Touchscreen interface" - ---help--- - Say Y here if you have an application that only can understand the - Compaq touchscreen protocol for absolute pointer data. This is - useful namely for embedded configurations. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called tsdev. - -config INPUT_TSDEV_SCREEN_X - int "Horizontal screen resolution" - depends on INPUT_TSDEV - default "240" - -config INPUT_TSDEV_SCREEN_Y - int "Vertical screen resolution" - depends on INPUT_TSDEV - default "320" - config INPUT_EVDEV tristate "Event interface" help diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 15eb752697b3..99af903bd3ce 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -13,7 +13,6 @@ obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o obj-$(CONFIG_INPUT_JOYDEV) += joydev.o obj-$(CONFIG_INPUT_EVDEV) += evdev.o -obj-$(CONFIG_INPUT_TSDEV) += tsdev.o obj-$(CONFIG_INPUT_EVBUG) += evbug.o obj-$(CONFIG_INPUT_KEYBOARD) += keyboard/ diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index f1c3d6cebd58..1d62c8b88e12 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -30,6 +30,8 @@ struct evdev { wait_queue_head_t wait; struct evdev_client *grab; struct list_head client_list; + spinlock_t client_lock; /* protects client_list */ + struct mutex mutex; struct device dev; }; @@ -37,39 +39,54 @@ struct evdev_client { struct input_event buffer[EVDEV_BUFFER_SIZE]; int head; int tail; + spinlock_t buffer_lock; /* protects access to buffer, head and tail */ struct fasync_struct *fasync; struct evdev *evdev; struct list_head node; }; static struct evdev *evdev_table[EVDEV_MINORS]; +static DEFINE_MUTEX(evdev_table_mutex); -static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) +static void evdev_pass_event(struct evdev_client *client, + struct input_event *event) +{ + /* + * Interrupts are disabled, just acquire the lock + */ + spin_lock(&client->buffer_lock); + client->buffer[client->head++] = *event; + client->head &= EVDEV_BUFFER_SIZE - 1; + spin_unlock(&client->buffer_lock); + + kill_fasync(&client->fasync, SIGIO, POLL_IN); +} + +/* + * Pass incoming event to all connected clients. + */ +static void evdev_event(struct input_handle *handle, + unsigned int type, unsigned int code, int value) { struct evdev *evdev = handle->private; struct evdev_client *client; + struct input_event event; - if (evdev->grab) { - client = evdev->grab; + do_gettimeofday(&event.time); + event.type = type; + event.code = code; + event.value = value; - do_gettimeofday(&client->buffer[client->head].time); - client->buffer[client->head].type = type; - client->buffer[client->head].code = code; - client->buffer[client->head].value = value; - client->head = (client->head + 1) & (EVDEV_BUFFER_SIZE - 1); + rcu_read_lock(); - kill_fasync(&client->fasync, SIGIO, POLL_IN); - } else - list_for_each_entry(client, &evdev->client_list, node) { + client = rcu_dereference(evdev->grab); + if (client) + evdev_pass_event(client, &event); + else + list_for_each_entry_rcu(client, &evdev->client_list, node) + evdev_pass_event(client, &event); - do_gettimeofday(&client->buffer[client->head].time); - client->buffer[client->head].type = type; - client->buffer[client->head].code = code; - client->buffer[client->head].value = value; - client->head = (client->head + 1) & (EVDEV_BUFFER_SIZE - 1); - - kill_fasync(&client->fasync, SIGIO, POLL_IN); - } + rcu_read_unlock(); wake_up_interruptible(&evdev->wait); } @@ -88,38 +105,140 @@ static int evdev_flush(struct file *file, fl_owner_t id) { struct evdev_client *client = file->private_data; struct evdev *evdev = client->evdev; + int retval; + + retval = mutex_lock_interruptible(&evdev->mutex); + if (retval) + return retval; if (!evdev->exist) - return -ENODEV; + retval = -ENODEV; + else + retval = input_flush_device(&evdev->handle, file); - return input_flush_device(&evdev->handle, file); + mutex_unlock(&evdev->mutex); + return retval; } static void evdev_free(struct device *dev) { struct evdev *evdev = container_of(dev, struct evdev, dev); - evdev_table[evdev->minor] = NULL; kfree(evdev); } +/* + * Grabs an event device (along with underlying input device). + * This function is called with evdev->mutex taken. + */ +static int evdev_grab(struct evdev *evdev, struct evdev_client *client) +{ + int error; + + if (evdev->grab) + return -EBUSY; + + error = input_grab_device(&evdev->handle); + if (error) + return error; + + rcu_assign_pointer(evdev->grab, client); + synchronize_rcu(); + + return 0; +} + +static int evdev_ungrab(struct evdev *evdev, struct evdev_client *client) +{ + if (evdev->grab != client) + return -EINVAL; + + rcu_assign_pointer(evdev->grab, NULL); + synchronize_rcu(); + input_release_device(&evdev->handle); + + return 0; +} + +static void evdev_attach_client(struct evdev *evdev, + struct evdev_client *client) +{ + spin_lock(&evdev->client_lock); + list_add_tail_rcu(&client->node, &evdev->client_list); + spin_unlock(&evdev->client_lock); + synchronize_rcu(); +} + +static void evdev_detach_client(struct evdev *evdev, + struct evdev_client *client) +{ + spin_lock(&evdev->client_lock); + list_del_rcu(&client->node); + spin_unlock(&evdev->client_lock); + synchronize_rcu(); +} + +static int evdev_open_device(struct evdev *evdev) +{ + int retval; + + retval = mutex_lock_interruptible(&evdev->mutex); + if (retval) + return retval; + + if (!evdev->exist) + retval = -ENODEV; + else if (!evdev->open++) { + retval = input_open_device(&evdev->handle); + if (retval) + evdev->open--; + } + + mutex_unlock(&evdev->mutex); + return retval; +} + +static void evdev_close_device(struct evdev *evdev) +{ + mutex_lock(&evdev->mutex); + + if (evdev->exist && !--evdev->open) + input_close_device(&evdev->handle); + + mutex_unlock(&evdev->mutex); +} + +/* + * Wake up users waiting for IO so they can disconnect from + * dead device. + */ +static void evdev_hangup(struct evdev *evdev) +{ + struct evdev_client *client; + + spin_lock(&evdev->client_lock); + list_for_each_entry(client, &evdev->client_list, node) + kill_fasync(&client->fasync, SIGIO, POLL_HUP); + spin_unlock(&evdev->client_lock); + + wake_up_interruptible(&evdev->wait); +} + static int evdev_release(struct inode *inode, struct file *file) { struct evdev_client *client = file->private_data; struct evdev *evdev = client->evdev; - if (evdev->grab == client) { - input_release_device(&evdev->handle); - evdev->grab = NULL; - } + mutex_lock(&evdev->mutex); + if (evdev->grab == client) + evdev_ungrab(evdev, client); + mutex_unlock(&evdev->mutex); evdev_fasync(-1, file, 0); - list_del(&client->node); + evdev_detach_client(evdev, client); kfree(client); - if (!--evdev->open && evdev->exist) - input_close_device(&evdev->handle); - + evdev_close_device(evdev); put_device(&evdev->dev); return 0; @@ -127,41 +246,44 @@ static int evdev_release(struct inode *inode, struct file *file) static int evdev_open(struct inode *inode, struct file *file) { - struct evdev_client *client; struct evdev *evdev; + struct evdev_client *client; int i = iminor(inode) - EVDEV_MINOR_BASE; int error; if (i >= EVDEV_MINORS) return -ENODEV; + error = mutex_lock_interruptible(&evdev_table_mutex); + if (error) + return error; evdev = evdev_table[i]; + if (evdev) + get_device(&evdev->dev); + mutex_unlock(&evdev_table_mutex); - if (!evdev || !evdev->exist) + if (!evdev) return -ENODEV; - get_device(&evdev->dev); - client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL); if (!client) { error = -ENOMEM; goto err_put_evdev; } + spin_lock_init(&client->buffer_lock); client->evdev = evdev; - list_add_tail(&client->node, &evdev->client_list); + evdev_attach_client(evdev, client); - if (!evdev->open++ && evdev->exist) { - error = input_open_device(&evdev->handle); - if (error) - goto err_free_client; - } + error = evdev_open_device(evdev); + if (error) + goto err_free_client; file->private_data = client; return 0; err_free_client: - list_del(&client->node); + evdev_detach_client(evdev, client); kfree(client); err_put_evdev: put_device(&evdev->dev); @@ -197,12 +319,14 @@ static inline size_t evdev_event_size(void) sizeof(struct input_event_compat) : sizeof(struct input_event); } -static int evdev_event_from_user(const char __user *buffer, struct input_event *event) +static int evdev_event_from_user(const char __user *buffer, + struct input_event *event) { if (COMPAT_TEST) { struct input_event_compat compat_event; - if (copy_from_user(&compat_event, buffer, sizeof(struct input_event_compat))) + if (copy_from_user(&compat_event, buffer, + sizeof(struct input_event_compat))) return -EFAULT; event->time.tv_sec = compat_event.time.tv_sec; @@ -219,7 +343,8 @@ static int evdev_event_from_user(const char __user *buffer, struct input_event * return 0; } -static int evdev_event_to_user(char __user *buffer, const struct input_event *event) +static int evdev_event_to_user(char __user *buffer, + const struct input_event *event) { if (COMPAT_TEST) { struct input_event_compat compat_event; @@ -230,7 +355,8 @@ static int evdev_event_to_user(char __user *buffer, const struct input_event *ev compat_event.code = event->code; compat_event.value = event->value; - if (copy_to_user(buffer, &compat_event, sizeof(struct input_event_compat))) + if (copy_to_user(buffer, &compat_event, + sizeof(struct input_event_compat))) return -EFAULT; } else { @@ -248,7 +374,8 @@ static inline size_t evdev_event_size(void) return sizeof(struct input_event); } -static int evdev_event_from_user(const char __user *buffer, struct input_event *event) +static int evdev_event_from_user(const char __user *buffer, + struct input_event *event) { if (copy_from_user(event, buffer, sizeof(struct input_event))) return -EFAULT; @@ -256,7 +383,8 @@ static int evdev_event_from_user(const char __user *buffer, struct input_event * return 0; } -static int evdev_event_to_user(char __user *buffer, const struct input_event *event) +static int evdev_event_to_user(char __user *buffer, + const struct input_event *event) { if (copy_to_user(buffer, event, sizeof(struct input_event))) return -EFAULT; @@ -266,37 +394,71 @@ static int evdev_event_to_user(char __user *buffer, const struct input_event *ev #endif /* CONFIG_COMPAT */ -static ssize_t evdev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +static ssize_t evdev_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) { struct evdev_client *client = file->private_data; struct evdev *evdev = client->evdev; struct input_event event; - int retval = 0; + int retval; - if (!evdev->exist) - return -ENODEV; + retval = mutex_lock_interruptible(&evdev->mutex); + if (retval) + return retval; + + if (!evdev->exist) { + retval = -ENODEV; + goto out; + } while (retval < count) { - if (evdev_event_from_user(buffer + retval, &event)) - return -EFAULT; - input_inject_event(&evdev->handle, event.type, event.code, event.value); + if (evdev_event_from_user(buffer + retval, &event)) { + retval = -EFAULT; + goto out; + } + + input_inject_event(&evdev->handle, + event.type, event.code, event.value); retval += evdev_event_size(); } + out: + mutex_unlock(&evdev->mutex); return retval; } -static ssize_t evdev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) +static int evdev_fetch_next_event(struct evdev_client *client, + struct input_event *event) +{ + int have_event; + + spin_lock_irq(&client->buffer_lock); + + have_event = client->head != client->tail; + if (have_event) { + *event = client->buffer[client->tail++]; + client->tail &= EVDEV_BUFFER_SIZE - 1; + } + + spin_unlock_irq(&client->buffer_lock); + + return have_event; +} + +static ssize_t evdev_read(struct file *file, char __user *buffer, + size_t count, loff_t *ppos) { struct evdev_client *client = file->private_data; struct evdev *evdev = client->evdev; + struct input_event event; int retval; if (count < evdev_event_size()) return -EINVAL; - if (client->head == client->tail && evdev->exist && (file->f_flags & O_NONBLOCK)) + if (client->head == client->tail && evdev->exist && + (file->f_flags & O_NONBLOCK)) return -EAGAIN; retval = wait_event_interruptible(evdev->wait, @@ -307,14 +469,12 @@ static ssize_t evdev_read(struct file *file, char __user *buffer, size_t count, if (!evdev->exist) return -ENODEV; - while (client->head != client->tail && retval + evdev_event_size() <= count) { - - struct input_event *event = (struct input_event *) client->buffer + client->tail; + while (retval + evdev_event_size() <= count && + evdev_fetch_next_event(client, &event)) { - if (evdev_event_to_user(buffer + retval, event)) + if (evdev_event_to_user(buffer + retval, &event)) return -EFAULT; - client->tail = (client->tail + 1) & (EVDEV_BUFFER_SIZE - 1); retval += evdev_event_size(); } @@ -409,8 +569,8 @@ static int str_to_user(const char *str, unsigned int maxlen, void __user *p) return copy_to_user(p, str, len) ? -EFAULT : len; } -static long evdev_ioctl_handler(struct file *file, unsigned int cmd, - void __user *p, int compat_mode) +static long evdev_do_ioctl(struct file *file, unsigned int cmd, + void __user *p, int compat_mode) { struct evdev_client *client = file->private_data; struct evdev *evdev = client->evdev; @@ -421,215 +581,289 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd, int i, t, u, v; int error; - if (!evdev->exist) - return -ENODEV; - switch (cmd) { - case EVIOCGVERSION: - return put_user(EV_VERSION, ip); + case EVIOCGVERSION: + return put_user(EV_VERSION, ip); - case EVIOCGID: - if (copy_to_user(p, &dev->id, sizeof(struct input_id))) - return -EFAULT; - return 0; + case EVIOCGID: + if (copy_to_user(p, &dev->id, sizeof(struct input_id))) + return -EFAULT; + return 0; - case EVIOCGREP: - if (!test_bit(EV_REP, dev->evbit)) - return -ENOSYS; - if (put_user(dev->rep[REP_DELAY], ip)) - return -EFAULT; - if (put_user(dev->rep[REP_PERIOD], ip + 1)) - return -EFAULT; - return 0; + case EVIOCGREP: + if (!test_bit(EV_REP, dev->evbit)) + return -ENOSYS; + if (put_user(dev->rep[REP_DELAY], ip)) + return -EFAULT; + if (put_user(dev->rep[REP_PERIOD], ip + 1)) + return -EFAULT; + return 0; - case EVIOCSREP: - if (!test_bit(EV_REP, dev->evbit)) - return -ENOSYS; - if (get_user(u, ip)) - return -EFAULT; - if (get_user(v, ip + 1)) - return -EFAULT; + case EVIOCSREP: + if (!test_bit(EV_REP, dev->evbit)) + return -ENOSYS; + if (get_user(u, ip)) + return -EFAULT; + if (get_user(v, ip + 1)) + return -EFAULT; - input_inject_event(&evdev->handle, EV_REP, REP_DELAY, u); - input_inject_event(&evdev->handle, EV_REP, REP_PERIOD, v); + input_inject_event(&evdev->handle, EV_REP, REP_DELAY, u); + input_inject_event(&evdev->handle, EV_REP, REP_PERIOD, v); - return 0; + return 0; - case EVIOCGKEYCODE: - if (get_user(t, ip)) - return -EFAULT; + case EVIOCGKEYCODE: + if (get_user(t, ip)) + return -EFAULT; - error = dev->getkeycode(dev, t, &v); - if (error) - return error; + error = dev->getkeycode(dev, t, &v); + if (error) + return error; - if (put_user(v, ip + 1)) - return -EFAULT; + if (put_user(v, ip + 1)) + return -EFAULT; - return 0; + return 0; - case EVIOCSKEYCODE: - if (get_user(t, ip) || get_user(v, ip + 1)) - return -EFAULT; + case EVIOCSKEYCODE: + if (get_user(t, ip) || get_user(v, ip + 1)) + return -EFAULT; - return dev->setkeycode(dev, t, v); + return dev->setkeycode(dev, t, v); - case EVIOCSFF: - if (copy_from_user(&effect, p, sizeof(effect))) - return -EFAULT; + case EVIOCSFF: + if (copy_from_user(&effect, p, sizeof(effect))) + return -EFAULT; - error = input_ff_upload(dev, &effect, file); + error = input_ff_upload(dev, &effect, file); - if (put_user(effect.id, &(((struct ff_effect __user *)p)->id))) - return -EFAULT; + if (put_user(effect.id, &(((struct ff_effect __user *)p)->id))) + return -EFAULT; - return error; + return error; - case EVIOCRMFF: - return input_ff_erase(dev, (int)(unsigned long) p, file); + case EVIOCRMFF: + return input_ff_erase(dev, (int)(unsigned long) p, file); - case EVIOCGEFFECTS: - i = test_bit(EV_FF, dev->evbit) ? dev->ff->max_effects : 0; - if (put_user(i, ip)) - return -EFAULT; - return 0; - - case EVIOCGRAB: - if (p) { - if (evdev->grab) - return -EBUSY; - if (input_grab_device(&evdev->handle)) - return -EBUSY; - evdev->grab = client; - return 0; - } else { - if (evdev->grab != client) - return -EINVAL; - input_release_device(&evdev->handle); - evdev->grab = NULL; - return 0; - } + case EVIOCGEFFECTS: + i = test_bit(EV_FF, dev->evbit) ? + dev->ff->max_effects : 0; + if (put_user(i, ip)) + return -EFAULT; + return 0; + + case EVIOCGRAB: + if (p) + return evdev_grab(evdev, client); + else + return evdev_ungrab(evdev, client); - default: + default: - if (_IOC_TYPE(cmd) != 'E') - return -EINVAL; + if (_IOC_TYPE(cmd) != 'E') + return -EINVAL; - if (_IOC_DIR(cmd) == _IOC_READ) { + if (_IOC_DIR(cmd) == _IOC_READ) { - if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) { + if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0))) { - unsigned long *bits; - int len; + unsigned long *bits; + int len; - switch (_IOC_NR(cmd) & EV_MAX) { - case 0: bits = dev->evbit; len = EV_MAX; break; - case EV_KEY: bits = dev->keybit; len = KEY_MAX; break; - case EV_REL: bits = dev->relbit; len = REL_MAX; break; - case EV_ABS: bits = dev->absbit; len = ABS_MAX; break; - case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break; - case EV_LED: bits = dev->ledbit; len = LED_MAX; break; - case EV_SND: bits = dev->sndbit; len = SND_MAX; break; - case EV_FF: bits = dev->ffbit; len = FF_MAX; break; - case EV_SW: bits = dev->swbit; len = SW_MAX; break; - default: return -EINVAL; - } - return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode); - } + switch (_IOC_NR(cmd) & EV_MAX) { - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) - return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd), - p, compat_mode); + case 0: bits = dev->evbit; len = EV_MAX; break; + case EV_KEY: bits = dev->keybit; len = KEY_MAX; break; + case EV_REL: bits = dev->relbit; len = REL_MAX; break; + case EV_ABS: bits = dev->absbit; len = ABS_MAX; break; + case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break; + case EV_LED: bits = dev->ledbit; len = LED_MAX; break; + case EV_SND: bits = dev->sndbit; len = SND_MAX; break; + case EV_FF: bits = dev->ffbit; len = FF_MAX; break; + case EV_SW: bits = dev->swbit; len = SW_MAX; break; + default: return -EINVAL; + } + return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode); + } - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) - return bits_to_user(dev->led, LED_MAX, _IOC_SIZE(cmd), - p, compat_mode); + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) + return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd), + p, compat_mode); - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) - return bits_to_user(dev->snd, SND_MAX, _IOC_SIZE(cmd), - p, compat_mode); + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) + return bits_to_user(dev->led, LED_MAX, _IOC_SIZE(cmd), + p, compat_mode); - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0))) - return bits_to_user(dev->sw, SW_MAX, _IOC_SIZE(cmd), - p, compat_mode); + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) + return bits_to_user(dev->snd, SND_MAX, _IOC_SIZE(cmd), + p, compat_mode); - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) - return str_to_user(dev->name, _IOC_SIZE(cmd), p); + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0))) + return bits_to_user(dev->sw, SW_MAX, _IOC_SIZE(cmd), + p, compat_mode); - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) - return str_to_user(dev->phys, _IOC_SIZE(cmd), p); + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) + return str_to_user(dev->name, _IOC_SIZE(cmd), p); - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) - return str_to_user(dev->uniq, _IOC_SIZE(cmd), p); + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) + return str_to_user(dev->phys, _IOC_SIZE(cmd), p); - if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) + return str_to_user(dev->uniq, _IOC_SIZE(cmd), p); - t = _IOC_NR(cmd) & ABS_MAX; + if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { - abs.value = dev->abs[t]; - abs.minimum = dev->absmin[t]; - abs.maximum = dev->absmax[t]; - abs.fuzz = dev->absfuzz[t]; - abs.flat = dev->absflat[t]; + t = _IOC_NR(cmd) & ABS_MAX; - if (copy_to_user(p, &abs, sizeof(struct input_absinfo))) - return -EFAULT; + abs.value = dev->abs[t]; + abs.minimum = dev->absmin[t]; + abs.maximum = dev->absmax[t]; + abs.fuzz = dev->absfuzz[t]; + abs.flat = dev->absflat[t]; - return 0; - } + if (copy_to_user(p, &abs, sizeof(struct input_absinfo))) + return -EFAULT; + return 0; } - if (_IOC_DIR(cmd) == _IOC_WRITE) { + } + + if (_IOC_DIR(cmd) == _IOC_WRITE) { - if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) { + if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) { - t = _IOC_NR(cmd) & ABS_MAX; + t = _IOC_NR(cmd) & ABS_MAX; - if (copy_from_user(&abs, p, sizeof(struct input_absinfo))) - return -EFAULT; + if (copy_from_user(&abs, p, + sizeof(struct input_absinfo))) + return -EFAULT; - dev->abs[t] = abs.value; - dev->absmin[t] = abs.minimum; - dev->absmax[t] = abs.maximum; - dev->absfuzz[t] = abs.fuzz; - dev->absflat[t] = abs.flat; + /* + * Take event lock to ensure that we are not + * changing device parameters in the middle + * of event. + */ + spin_lock_irq(&dev->event_lock); - return 0; - } + dev->abs[t] = abs.value; + dev->absmin[t] = abs.minimum; + dev->absmax[t] = abs.maximum; + dev->absfuzz[t] = abs.fuzz; + dev->absflat[t] = abs.flat; + + spin_unlock_irq(&dev->event_lock); + + return 0; } + } } return -EINVAL; } +static long evdev_ioctl_handler(struct file *file, unsigned int cmd, + void __user *p, int compat_mode) +{ + struct evdev_client *client = file->private_data; + struct evdev *evdev = client->evdev; + int retval; + + retval = mutex_lock_interruptible(&evdev->mutex); + if (retval) + return retval; + + if (!evdev->exist) { + retval = -ENODEV; + goto out; + } + + retval = evdev_do_ioctl(file, cmd, p, compat_mode); + + out: + mutex_unlock(&evdev->mutex); + return retval; +} + static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { return evdev_ioctl_handler(file, cmd, (void __user *)arg, 0); } #ifdef CONFIG_COMPAT -static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) +static long evdev_ioctl_compat(struct file *file, + unsigned int cmd, unsigned long arg) { return evdev_ioctl_handler(file, cmd, compat_ptr(arg), 1); } #endif static const struct file_operations evdev_fops = { - .owner = THIS_MODULE, - .read = evdev_read, - .write = evdev_write, - .poll = evdev_poll, - .open = evdev_open, - .release = evdev_release, - .unlocked_ioctl = evdev_ioctl, + .owner = THIS_MODULE, + .read = evdev_read, + .write = evdev_write, + .poll = evdev_poll, + .open = evdev_open, + .release = evdev_release, + .unlocked_ioctl = evdev_ioctl, #ifdef CONFIG_COMPAT - .compat_ioctl = evdev_ioctl_compat, + .compat_ioctl = evdev_ioctl_compat, #endif - .fasync = evdev_fasync, - .flush = evdev_flush + .fasync = evdev_fasync, + .flush = evdev_flush }; +static int evdev_install_chrdev(struct evdev *evdev) +{ + /* + * No need to do any locking here as calls to connect and + * disconnect are serialized by the input core + */ + evdev_table[evdev->minor] = evdev; + return 0; +} + +static void evdev_remove_chrdev(struct evdev *evdev) +{ + /* + * Lock evdev table to prevent race with evdev_open() + */ + mutex_lock(&evdev_table_mutex); + evdev_table[evdev->minor] = NULL; + mutex_unlock(&evdev_table_mutex); +} + +/* + * Mark device non-existent. This disables writes, ioctls and + * prevents new users from opening the device. Already posted + * blocking reads will stay, however new ones will fail. + */ +static void evdev_mark_dead(struct evdev *evdev) +{ + mutex_lock(&evdev->mutex); + evdev->exist = 0; + mutex_unlock(&evdev->mutex); +} + +static void evdev_cleanup(struct evdev *evdev) +{ + struct input_handle *handle = &evdev->handle; + + evdev_mark_dead(evdev); + evdev_hangup(evdev); + evdev_remove_chrdev(evdev); + + /* evdev is marked dead so no one else accesses evdev->open */ + if (evdev->open) { + input_flush_device(handle, NULL); + input_close_device(handle); + } +} + +/* + * Create new evdev device. Note that input core serializes calls + * to connect and disconnect so we don't need to lock evdev_table here. + */ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id) { @@ -637,7 +871,10 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, int minor; int error; - for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++); + for (minor = 0; minor < EVDEV_MINORS; minor++) + if (!evdev_table[minor]) + break; + if (minor == EVDEV_MINORS) { printk(KERN_ERR "evdev: no more free evdev devices\n"); return -ENFILE; @@ -648,38 +885,44 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, return -ENOMEM; INIT_LIST_HEAD(&evdev->client_list); + spin_lock_init(&evdev->client_lock); + mutex_init(&evdev->mutex); init_waitqueue_head(&evdev->wait); + snprintf(evdev->name, sizeof(evdev->name), "event%d", minor); evdev->exist = 1; evdev->minor = minor; + evdev->handle.dev = dev; evdev->handle.name = evdev->name; evdev->handle.handler = handler; evdev->handle.private = evdev; - snprintf(evdev->name, sizeof(evdev->name), "event%d", minor); - snprintf(evdev->dev.bus_id, sizeof(evdev->dev.bus_id), - "event%d", minor); + strlcpy(evdev->dev.bus_id, evdev->name, sizeof(evdev->dev.bus_id)); + evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor); evdev->dev.class = &input_class; evdev->dev.parent = &dev->dev; - evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor); evdev->dev.release = evdev_free; device_initialize(&evdev->dev); - evdev_table[minor] = evdev; - - error = device_add(&evdev->dev); + error = input_register_handle(&evdev->handle); if (error) goto err_free_evdev; - error = input_register_handle(&evdev->handle); + error = evdev_install_chrdev(evdev); + if (error) + goto err_unregister_handle; + + error = device_add(&evdev->dev); if (error) - goto err_delete_evdev; + goto err_cleanup_evdev; return 0; - err_delete_evdev: - device_del(&evdev->dev); + err_cleanup_evdev: + evdev_cleanup(evdev); + err_unregister_handle: + input_unregister_handle(&evdev->handle); err_free_evdev: put_device(&evdev->dev); return error; @@ -688,21 +931,10 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, static void evdev_disconnect(struct input_handle *handle) { struct evdev *evdev = handle->private; - struct evdev_client *client; - input_unregister_handle(handle); device_del(&evdev->dev); - - evdev->exist = 0; - - if (evdev->open) { - input_flush_device(handle, NULL); - input_close_device(handle); - list_for_each_entry(client, &evdev->client_list, node) - kill_fasync(&client->fasync, SIGIO, POLL_HUP); - wake_up_interruptible(&evdev->wait); - } - + evdev_cleanup(evdev); + input_unregister_handle(handle); put_device(&evdev->dev); } @@ -714,13 +946,13 @@ static const struct input_device_id evdev_ids[] = { MODULE_DEVICE_TABLE(input, evdev_ids); static struct input_handler evdev_handler = { - .event = evdev_event, - .connect = evdev_connect, - .disconnect = evdev_disconnect, - .fops = &evdev_fops, - .minor = EVDEV_MINOR_BASE, - .name = "evdev", - .id_table = evdev_ids, + .event = evdev_event, + .connect = evdev_connect, + .disconnect = evdev_disconnect, + .fops = &evdev_fops, + .minor = EVDEV_MINOR_BASE, + .name = "evdev", + .id_table = evdev_ids, }; static int __init evdev_init(void) diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c index b773d4c756a6..92b359894e81 100644 --- a/drivers/input/input-polldev.c +++ b/drivers/input/input-polldev.c @@ -70,6 +70,7 @@ static int input_open_polled_device(struct input_dev *input) { struct input_polled_dev *dev = input->private; int error; + unsigned long ticks; error = input_polldev_start_workqueue(); if (error) @@ -78,8 +79,10 @@ static int input_open_polled_device(struct input_dev *input) if (dev->flush) dev->flush(dev); - queue_delayed_work(polldev_wq, &dev->work, - msecs_to_jiffies(dev->poll_interval)); + ticks = msecs_to_jiffies(dev->poll_interval); + if (ticks >= HZ) + ticks = round_jiffies(ticks); + queue_delayed_work(polldev_wq, &dev->work, ticks); return 0; } diff --git a/drivers/input/input.c b/drivers/input/input.c index 5fe755586623..2f2b020cd629 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -17,10 +17,10 @@ #include <linux/major.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> -#include <linux/interrupt.h> #include <linux/poll.h> #include <linux/device.h> #include <linux/mutex.h> +#include <linux/rcupdate.h> MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); MODULE_DESCRIPTION("Input core"); @@ -31,167 +31,245 @@ MODULE_LICENSE("GPL"); static LIST_HEAD(input_dev_list); static LIST_HEAD(input_handler_list); +/* + * input_mutex protects access to both input_dev_list and input_handler_list. + * This also causes input_[un]register_device and input_[un]register_handler + * be mutually exclusive which simplifies locking in drivers implementing + * input handlers. + */ +static DEFINE_MUTEX(input_mutex); + static struct input_handler *input_table[8]; -/** - * input_event() - report new input event - * @dev: device that generated the event - * @type: type of the event - * @code: event code - * @value: value of the event - * - * This function should be used by drivers implementing various input devices - * See also input_inject_event() - */ -void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +static inline int is_event_supported(unsigned int code, + unsigned long *bm, unsigned int max) { - struct input_handle *handle; - - if (type > EV_MAX || !test_bit(type, dev->evbit)) - return; + return code <= max && test_bit(code, bm); +} - add_input_randomness(type, code, value); +static int input_defuzz_abs_event(int value, int old_val, int fuzz) +{ + if (fuzz) { + if (value > old_val - fuzz / 2 && value < old_val + fuzz / 2) + return old_val; - switch (type) { + if (value > old_val - fuzz && value < old_val + fuzz) + return (old_val * 3 + value) / 4; - case EV_SYN: - switch (code) { - case SYN_CONFIG: - if (dev->event) - dev->event(dev, type, code, value); - break; - - case SYN_REPORT: - if (dev->sync) - return; - dev->sync = 1; - break; - } - break; + if (value > old_val - fuzz * 2 && value < old_val + fuzz * 2) + return (old_val + value) / 2; + } - case EV_KEY: + return value; +} - if (code > KEY_MAX || !test_bit(code, dev->keybit) || !!test_bit(code, dev->key) == value) - return; +/* + * Pass event through all open handles. This function is called with + * dev->event_lock held and interrupts disabled. + */ +static void input_pass_event(struct input_dev *dev, + unsigned int type, unsigned int code, int value) +{ + struct input_handle *handle; - if (value == 2) - break; + rcu_read_lock(); - change_bit(code, dev->key); + handle = rcu_dereference(dev->grab); + if (handle) + handle->handler->event(handle, type, code, value); + else + list_for_each_entry_rcu(handle, &dev->h_list, d_node) + if (handle->open) + handle->handler->event(handle, + type, code, value); + rcu_read_unlock(); +} - if (test_bit(EV_REP, dev->evbit) && dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] && dev->timer.data && value) { - dev->repeat_key = code; - mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->rep[REP_DELAY])); - } +/* + * Generate software autorepeat event. Note that we take + * dev->event_lock here to avoid racing with input_event + * which may cause keys get "stuck". + */ +static void input_repeat_key(unsigned long data) +{ + struct input_dev *dev = (void *) data; + unsigned long flags; - break; + spin_lock_irqsave(&dev->event_lock, flags); - case EV_SW: + if (test_bit(dev->repeat_key, dev->key) && + is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) { - if (code > SW_MAX || !test_bit(code, dev->swbit) || !!test_bit(code, dev->sw) == value) - return; + input_pass_event(dev, EV_KEY, dev->repeat_key, 2); - change_bit(code, dev->sw); + if (dev->sync) { + /* + * Only send SYN_REPORT if we are not in a middle + * of driver parsing a new hardware packet. + * Otherwise assume that the driver will send + * SYN_REPORT once it's done. + */ + input_pass_event(dev, EV_SYN, SYN_REPORT, 1); + } - break; + if (dev->rep[REP_PERIOD]) + mod_timer(&dev->timer, jiffies + + msecs_to_jiffies(dev->rep[REP_PERIOD])); + } - case EV_ABS: + spin_unlock_irqrestore(&dev->event_lock, flags); +} - if (code > ABS_MAX || !test_bit(code, dev->absbit)) - return; +static void input_start_autorepeat(struct input_dev *dev, int code) +{ + if (test_bit(EV_REP, dev->evbit) && + dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] && + dev->timer.data) { + dev->repeat_key = code; + mod_timer(&dev->timer, + jiffies + msecs_to_jiffies(dev->rep[REP_DELAY])); + } +} - if (dev->absfuzz[code]) { - if ((value > dev->abs[code] - (dev->absfuzz[code] >> 1)) && - (value < dev->abs[code] + (dev->absfuzz[code] >> 1))) - return; +#define INPUT_IGNORE_EVENT 0 +#define INPUT_PASS_TO_HANDLERS 1 +#define INPUT_PASS_TO_DEVICE 2 +#define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE) - if ((value > dev->abs[code] - dev->absfuzz[code]) && - (value < dev->abs[code] + dev->absfuzz[code])) - value = (dev->abs[code] * 3 + value) >> 2; +static void input_handle_event(struct input_dev *dev, + unsigned int type, unsigned int code, int value) +{ + int disposition = INPUT_IGNORE_EVENT; - if ((value > dev->abs[code] - (dev->absfuzz[code] << 1)) && - (value < dev->abs[code] + (dev->absfuzz[code] << 1))) - value = (dev->abs[code] + value) >> 1; - } + switch (type) { - if (dev->abs[code] == value) - return; + case EV_SYN: + switch (code) { + case SYN_CONFIG: + disposition = INPUT_PASS_TO_ALL; + break; - dev->abs[code] = value; + case SYN_REPORT: + if (!dev->sync) { + dev->sync = 1; + disposition = INPUT_PASS_TO_HANDLERS; + } break; + } + break; - case EV_REL: + case EV_KEY: + if (is_event_supported(code, dev->keybit, KEY_MAX) && + !!test_bit(code, dev->key) != value) { - if (code > REL_MAX || !test_bit(code, dev->relbit) || (value == 0)) - return; + if (value != 2) { + __change_bit(code, dev->key); + if (value) + input_start_autorepeat(dev, code); + } - break; + disposition = INPUT_PASS_TO_HANDLERS; + } + break; - case EV_MSC: + case EV_SW: + if (is_event_supported(code, dev->swbit, SW_MAX) && + !!test_bit(code, dev->sw) != value) { - if (code > MSC_MAX || !test_bit(code, dev->mscbit)) - return; + __change_bit(code, dev->sw); + disposition = INPUT_PASS_TO_HANDLERS; + } + break; + + case EV_ABS: + if (is_event_supported(code, dev->absbit, ABS_MAX)) { - if (dev->event) - dev->event(dev, type, code, value); + value = input_defuzz_abs_event(value, + dev->abs[code], dev->absfuzz[code]); - break; + if (dev->abs[code] != value) { + dev->abs[code] = value; + disposition = INPUT_PASS_TO_HANDLERS; + } + } + break; - case EV_LED: + case EV_REL: + if (is_event_supported(code, dev->relbit, REL_MAX) && value) + disposition = INPUT_PASS_TO_HANDLERS; - if (code > LED_MAX || !test_bit(code, dev->ledbit) || !!test_bit(code, dev->led) == value) - return; + break; - change_bit(code, dev->led); + case EV_MSC: + if (is_event_supported(code, dev->mscbit, MSC_MAX)) + disposition = INPUT_PASS_TO_ALL; - if (dev->event) - dev->event(dev, type, code, value); + break; - break; + case EV_LED: + if (is_event_supported(code, dev->ledbit, LED_MAX) && + !!test_bit(code, dev->led) != value) { - case EV_SND: + __change_bit(code, dev->led); + disposition = INPUT_PASS_TO_ALL; + } + break; - if (code > SND_MAX || !test_bit(code, dev->sndbit)) - return; + case EV_SND: + if (is_event_supported(code, dev->sndbit, SND_MAX)) { if (!!test_bit(code, dev->snd) != !!value) - change_bit(code, dev->snd); + __change_bit(code, dev->snd); + disposition = INPUT_PASS_TO_ALL; + } + break; - if (dev->event) - dev->event(dev, type, code, value); + case EV_REP: + if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) { + dev->rep[code] = value; + disposition = INPUT_PASS_TO_ALL; + } + break; - break; + case EV_FF: + if (value >= 0) + disposition = INPUT_PASS_TO_ALL; + break; + } - case EV_REP: + if (type != EV_SYN) + dev->sync = 0; - if (code > REP_MAX || value < 0 || dev->rep[code] == value) - return; + if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event) + dev->event(dev, type, code, value); - dev->rep[code] = value; - if (dev->event) - dev->event(dev, type, code, value); + if (disposition & INPUT_PASS_TO_HANDLERS) + input_pass_event(dev, type, code, value); +} - break; +/** + * input_event() - report new input event + * @dev: device that generated the event + * @type: type of the event + * @code: event code + * @value: value of the event + * + * This function should be used by drivers implementing various input + * devices. See also input_inject_event(). + */ - case EV_FF: +void input_event(struct input_dev *dev, + unsigned int type, unsigned int code, int value) +{ + unsigned long flags; - if (value < 0) - return; + if (is_event_supported(type, dev->evbit, EV_MAX)) { - if (dev->event) - dev->event(dev, type, code, value); - break; + spin_lock_irqsave(&dev->event_lock, flags); + add_input_randomness(type, code, value); + input_handle_event(dev, type, code, value); + spin_unlock_irqrestore(&dev->event_lock, flags); } - - if (type != EV_SYN) - dev->sync = 0; - - if (dev->grab) - dev->grab->handler->event(dev->grab, type, code, value); - else - list_for_each_entry(handle, &dev->h_list, d_node) - if (handle->open) - handle->handler->event(handle, type, code, value); } EXPORT_SYMBOL(input_event); @@ -202,102 +280,228 @@ EXPORT_SYMBOL(input_event); * @code: event code * @value: value of the event * - * Similar to input_event() but will ignore event if device is "grabbed" and handle - * injecting event is not the one that owns the device. + * Similar to input_event() but will ignore event if device is + * "grabbed" and handle injecting event is not the one that owns + * the device. */ -void input_inject_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) +void input_inject_event(struct input_handle *handle, + unsigned int type, unsigned int code, int value) { - if (!handle->dev->grab || handle->dev->grab == handle) - input_event(handle->dev, type, code, value); -} -EXPORT_SYMBOL(input_inject_event); - -static void input_repeat_key(unsigned long data) -{ - struct input_dev *dev = (void *) data; + struct input_dev *dev = handle->dev; + struct input_handle *grab; + unsigned long flags; - if (!test_bit(dev->repeat_key, dev->key)) - return; + if (is_event_supported(type, dev->evbit, EV_MAX)) { + spin_lock_irqsave(&dev->event_lock, flags); - input_event(dev, EV_KEY, dev->repeat_key, 2); - input_sync(dev); + rcu_read_lock(); + grab = rcu_dereference(dev->grab); + if (!grab || grab == handle) + input_handle_event(dev, type, code, value); + rcu_read_unlock(); - if (dev->rep[REP_PERIOD]) - mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->rep[REP_PERIOD])); + spin_unlock_irqrestore(&dev->event_lock, flags); + } } +EXPORT_SYMBOL(input_inject_event); +/** + * input_grab_device - grabs device for exclusive use + * @handle: input handle that wants to own the device + * + * When a device is grabbed by an input handle all events generated by + * the device are delivered only to this handle. Also events injected + * by other input handles are ignored while device is grabbed. + */ int input_grab_device(struct input_handle *handle) { - if (handle->dev->grab) - return -EBUSY; + struct input_dev *dev = handle->dev; + int retval; - handle->dev->grab = handle; - return 0; + retval = mutex_lock_interruptible(&dev->mutex); + if (retval) + return retval; + + if (dev->grab) { + retval = -EBUSY; + goto out; + } + + rcu_assign_pointer(dev->grab, handle); + synchronize_rcu(); + + out: + mutex_unlock(&dev->mutex); + return retval; } EXPORT_SYMBOL(input_grab_device); -void input_release_device(struct input_handle *handle) +static void __input_release_device(struct input_handle *handle) { struct input_dev *dev = handle->dev; if (dev->grab == handle) { - dev->grab = NULL; + rcu_assign_pointer(dev->grab, NULL); + /* Make sure input_pass_event() notices that grab is gone */ + synchronize_rcu(); list_for_each_entry(handle, &dev->h_list, d_node) - if (handle->handler->start) + if (handle->open && handle->handler->start) handle->handler->start(handle); } } + +/** + * input_release_device - release previously grabbed device + * @handle: input handle that owns the device + * + * Releases previously grabbed device so that other input handles can + * start receiving input events. Upon release all handlers attached + * to the device have their start() method called so they have a change + * to synchronize device state with the rest of the system. + */ +void input_release_device(struct input_handle *handle) +{ + struct input_dev *dev = handle->dev; + + mutex_lock(&dev->mutex); + __input_release_device(handle); + mutex_unlock(&dev->mutex); +} EXPORT_SYMBOL(input_release_device); +/** + * input_open_device - open input device + * @handle: handle through which device is being accessed + * + * This function should be called by input handlers when they + * want to start receive events from given input device. + */ int input_open_device(struct input_handle *handle) { struct input_dev *dev = handle->dev; - int err; + int retval; - err = mutex_lock_interruptible(&dev->mutex); - if (err) - return err; + retval = mutex_lock_interruptible(&dev->mutex); + if (retval) + return retval; + + if (dev->going_away) { + retval = -ENODEV; + goto out; + } handle->open++; if (!dev->users++ && dev->open) - err = dev->open(dev); - - if (err) - handle->open--; + retval = dev->open(dev); + + if (retval) { + dev->users--; + if (!--handle->open) { + /* + * Make sure we are not delivering any more events + * through this handle + */ + synchronize_rcu(); + } + } + out: mutex_unlock(&dev->mutex); - - return err; + return retval; } EXPORT_SYMBOL(input_open_device); -int input_flush_device(struct input_handle* handle, struct file* file) +int input_flush_device(struct input_handle *handle, struct file *file) { - if (handle->dev->flush) - return handle->dev->flush(handle->dev, file); + struct input_dev *dev = handle->dev; + int retval; - return 0; + retval = mutex_lock_interruptible(&dev->mutex); + if (retval) + return retval; + + if (dev->flush) + retval = dev->flush(dev, file); + + mutex_unlock(&dev->mutex); + return retval; } EXPORT_SYMBOL(input_flush_device); +/** + * input_close_device - close input device + * @handle: handle through which device is being accessed + * + * This function should be called by input handlers when they + * want to stop receive events from given input device. + */ void input_close_device(struct input_handle *handle) { struct input_dev *dev = handle->dev; - input_release_device(handle); - mutex_lock(&dev->mutex); + __input_release_device(handle); + if (!--dev->users && dev->close) dev->close(dev); - handle->open--; + + if (!--handle->open) { + /* + * synchronize_rcu() makes sure that input_pass_event() + * completed and that no more input events are delivered + * through this handle + */ + synchronize_rcu(); + } mutex_unlock(&dev->mutex); } EXPORT_SYMBOL(input_close_device); +/* + * Prepare device for unregistering + */ +static void input_disconnect_device(struct input_dev *dev) +{ + struct input_handle *handle; + int code; + + /* + * Mark device as going away. Note that we take dev->mutex here + * not to protect access to dev->going_away but rather to ensure + * that there are no threads in the middle of input_open_device() + */ + mutex_lock(&dev->mutex); + dev->going_away = 1; + mutex_unlock(&dev->mutex); + + spin_lock_irq(&dev->event_lock); + + /* + * Simulate keyup events for all pressed keys so that handlers + * are not left with "stuck" keys. The driver may continue + * generate events even after we done here but they will not + * reach any handlers. + */ + if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) { + for (code = 0; code <= KEY_MAX; code++) { + if (is_event_supported(code, dev->keybit, KEY_MAX) && + test_bit(code, dev->key)) { + input_pass_event(dev, EV_KEY, code, 0); + } + } + input_pass_event(dev, EV_SYN, SYN_REPORT, 1); + } + + list_for_each_entry(handle, &dev->h_list, d_node) + handle->open = 0; + + spin_unlock_irq(&dev->event_lock); +} + static int input_fetch_keycode(struct input_dev *dev, int scancode) { switch (dev->keycodesize) { @@ -473,7 +677,8 @@ static unsigned int input_proc_devices_poll(struct file *file, poll_table *wait) static void *input_devices_seq_start(struct seq_file *seq, loff_t *pos) { - /* acquire lock here ... Yes, we do need locking, I knowi, I know... */ + if (mutex_lock_interruptible(&input_mutex)) + return NULL; return seq_list_start(&input_dev_list, *pos); } @@ -485,7 +690,7 @@ static void *input_devices_seq_next(struct seq_file *seq, void *v, loff_t *pos) static void input_devices_seq_stop(struct seq_file *seq, void *v) { - /* release lock here */ + mutex_unlock(&input_mutex); } static void input_seq_print_bitmap(struct seq_file *seq, const char *name, @@ -569,7 +774,9 @@ static const struct file_operations input_devices_fileops = { static void *input_handlers_seq_start(struct seq_file *seq, loff_t *pos) { - /* acquire lock here ... Yes, we do need locking, I knowi, I know... */ + if (mutex_lock_interruptible(&input_mutex)) + return NULL; + seq->private = (void *)(unsigned long)*pos; return seq_list_start(&input_handler_list, *pos); } @@ -582,7 +789,7 @@ static void *input_handlers_seq_next(struct seq_file *seq, void *v, loff_t *pos) static void input_handlers_seq_stop(struct seq_file *seq, void *v) { - /* release lock here */ + mutex_unlock(&input_mutex); } static int input_handlers_seq_show(struct seq_file *seq, void *v) @@ -859,87 +1066,66 @@ static void input_dev_release(struct device *device) * Input uevent interface - loading event handlers based on * device bitfields. */ -static int input_add_uevent_bm_var(char **envp, int num_envp, int *cur_index, - char *buffer, int buffer_size, int *cur_len, +static int input_add_uevent_bm_var(struct kobj_uevent_env *env, const char *name, unsigned long *bitmap, int max) { - if (*cur_index >= num_envp - 1) - return -ENOMEM; - - envp[*cur_index] = buffer + *cur_len; + int len; - *cur_len += snprintf(buffer + *cur_len, max(buffer_size - *cur_len, 0), name); - if (*cur_len >= buffer_size) + if (add_uevent_var(env, "%s=", name)) return -ENOMEM; - *cur_len += input_print_bitmap(buffer + *cur_len, - max(buffer_size - *cur_len, 0), - bitmap, max, 0) + 1; - if (*cur_len > buffer_size) + len = input_print_bitmap(&env->buf[env->buflen - 1], + sizeof(env->buf) - env->buflen, + bitmap, max, 0); + if (len >= (sizeof(env->buf) - env->buflen)) return -ENOMEM; - (*cur_index)++; + env->buflen += len; return 0; } -static int input_add_uevent_modalias_var(char **envp, int num_envp, int *cur_index, - char *buffer, int buffer_size, int *cur_len, +static int input_add_uevent_modalias_var(struct kobj_uevent_env *env, struct input_dev *dev) { - if (*cur_index >= num_envp - 1) - return -ENOMEM; - - envp[*cur_index] = buffer + *cur_len; + int len; - *cur_len += snprintf(buffer + *cur_len, max(buffer_size - *cur_len, 0), - "MODALIAS="); - if (*cur_len >= buffer_size) + if (add_uevent_var(env, "MODALIAS=")) return -ENOMEM; - *cur_len += input_print_modalias(buffer + *cur_len, - max(buffer_size - *cur_len, 0), - dev, 0) + 1; - if (*cur_len > buffer_size) + len = input_print_modalias(&env->buf[env->buflen - 1], + sizeof(env->buf) - env->buflen, + dev, 0); + if (len >= (sizeof(env->buf) - env->buflen)) return -ENOMEM; - (*cur_index)++; + env->buflen += len; return 0; } #define INPUT_ADD_HOTPLUG_VAR(fmt, val...) \ do { \ - int err = add_uevent_var(envp, num_envp, &i, \ - buffer, buffer_size, &len, \ - fmt, val); \ + int err = add_uevent_var(env, fmt, val); \ if (err) \ return err; \ } while (0) #define INPUT_ADD_HOTPLUG_BM_VAR(name, bm, max) \ do { \ - int err = input_add_uevent_bm_var(envp, num_envp, &i, \ - buffer, buffer_size, &len, \ - name, bm, max); \ + int err = input_add_uevent_bm_var(env, name, bm, max); \ if (err) \ return err; \ } while (0) #define INPUT_ADD_HOTPLUG_MODALIAS_VAR(dev) \ do { \ - int err = input_add_uevent_modalias_var(envp, \ - num_envp, &i, \ - buffer, buffer_size, &len, \ - dev); \ + int err = input_add_uevent_modalias_var(env, dev); \ if (err) \ return err; \ } while (0) -static int input_dev_uevent(struct device *device, char **envp, - int num_envp, char *buffer, int buffer_size) +static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env) { struct input_dev *dev = to_input_dev(device); - int i = 0; - int len = 0; INPUT_ADD_HOTPLUG_VAR("PRODUCT=%x/%x/%x/%x", dev->id.bustype, dev->id.vendor, @@ -971,7 +1157,6 @@ static int input_dev_uevent(struct device *device, char **envp, INPUT_ADD_HOTPLUG_MODALIAS_VAR(dev); - envp[i] = NULL; return 0; } @@ -1005,6 +1190,7 @@ struct input_dev *input_allocate_device(void) dev->dev.class = &input_class; device_initialize(&dev->dev); mutex_init(&dev->mutex); + spin_lock_init(&dev->event_lock); INIT_LIST_HEAD(&dev->h_list); INIT_LIST_HEAD(&dev->node); @@ -1022,7 +1208,7 @@ EXPORT_SYMBOL(input_allocate_device); * This function should only be used if input_register_device() * was not called yet or if it failed. Once device was registered * use input_unregister_device() and memory will be freed once last - * refrence to the device is dropped. + * reference to the device is dropped. * * Device should be allocated by input_allocate_device(). * @@ -1092,6 +1278,18 @@ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int } EXPORT_SYMBOL(input_set_capability); +/** + * input_register_device - register device with input core + * @dev: device to be registered + * + * This function registers device with input core. The device must be + * allocated with input_allocate_device() and all it's capabilities + * set up before registering. + * If function fails the device must be freed with input_free_device(). + * Once device has been successfully registered it can be unregistered + * with input_unregister_device(); input_free_device() should not be + * called in this case. + */ int input_register_device(struct input_dev *dev) { static atomic_t input_no = ATOMIC_INIT(0); @@ -1099,7 +1297,7 @@ int input_register_device(struct input_dev *dev) const char *path; int error; - set_bit(EV_SYN, dev->evbit); + __set_bit(EV_SYN, dev->evbit); /* * If delay and period are pre-set by the driver, then autorepeating @@ -1120,8 +1318,6 @@ int input_register_device(struct input_dev *dev) if (!dev->setkeycode) dev->setkeycode = input_default_setkeycode; - list_add_tail(&dev->node, &input_dev_list); - snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id), "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1); @@ -1137,49 +1333,79 @@ int input_register_device(struct input_dev *dev) dev->name ? dev->name : "Unspecified device", path ? path : "N/A"); kfree(path); + error = mutex_lock_interruptible(&input_mutex); + if (error) { + device_del(&dev->dev); + return error; + } + + list_add_tail(&dev->node, &input_dev_list); + list_for_each_entry(handler, &input_handler_list, node) input_attach_handler(dev, handler); input_wakeup_procfs_readers(); + mutex_unlock(&input_mutex); + return 0; } EXPORT_SYMBOL(input_register_device); +/** + * input_unregister_device - unregister previously registered device + * @dev: device to be unregistered + * + * This function unregisters an input device. Once device is unregistered + * the caller should not try to access it as it may get freed at any moment. + */ void input_unregister_device(struct input_dev *dev) { struct input_handle *handle, *next; - int code; - for (code = 0; code <= KEY_MAX; code++) - if (test_bit(code, dev->key)) - input_report_key(dev, code, 0); - input_sync(dev); + input_disconnect_device(dev); - del_timer_sync(&dev->timer); + mutex_lock(&input_mutex); list_for_each_entry_safe(handle, next, &dev->h_list, d_node) handle->handler->disconnect(handle); WARN_ON(!list_empty(&dev->h_list)); + del_timer_sync(&dev->timer); list_del_init(&dev->node); - device_unregister(&dev->dev); - input_wakeup_procfs_readers(); + + mutex_unlock(&input_mutex); + + device_unregister(&dev->dev); } EXPORT_SYMBOL(input_unregister_device); +/** + * input_register_handler - register a new input handler + * @handler: handler to be registered + * + * This function registers a new input handler (interface) for input + * devices in the system and attaches it to all input devices that + * are compatible with the handler. + */ int input_register_handler(struct input_handler *handler) { struct input_dev *dev; + int retval; + + retval = mutex_lock_interruptible(&input_mutex); + if (retval) + return retval; INIT_LIST_HEAD(&handler->h_list); if (handler->fops != NULL) { - if (input_table[handler->minor >> 5]) - return -EBUSY; - + if (input_table[handler->minor >> 5]) { + retval = -EBUSY; + goto out; + } input_table[handler->minor >> 5] = handler; } @@ -1189,14 +1415,26 @@ int input_register_handler(struct input_handler *handler) input_attach_handler(dev, handler); input_wakeup_procfs_readers(); - return 0; + + out: + mutex_unlock(&input_mutex); + return retval; } EXPORT_SYMBOL(input_register_handler); +/** + * input_unregister_handler - unregisters an input handler + * @handler: handler to be unregistered + * + * This function disconnects a handler from its input devices and + * removes it from lists of known handlers. + */ void input_unregister_handler(struct input_handler *handler) { struct input_handle *handle, *next; + mutex_lock(&input_mutex); + list_for_each_entry_safe(handle, next, &handler->h_list, h_node) handler->disconnect(handle); WARN_ON(!list_empty(&handler->h_list)); @@ -1207,14 +1445,45 @@ void input_unregister_handler(struct input_handler *handler) input_table[handler->minor >> 5] = NULL; input_wakeup_procfs_readers(); + + mutex_unlock(&input_mutex); } EXPORT_SYMBOL(input_unregister_handler); +/** + * input_register_handle - register a new input handle + * @handle: handle to register + * + * This function puts a new input handle onto device's + * and handler's lists so that events can flow through + * it once it is opened using input_open_device(). + * + * This function is supposed to be called from handler's + * connect() method. + */ int input_register_handle(struct input_handle *handle) { struct input_handler *handler = handle->handler; + struct input_dev *dev = handle->dev; + int error; - list_add_tail(&handle->d_node, &handle->dev->h_list); + /* + * We take dev->mutex here to prevent race with + * input_release_device(). + */ + error = mutex_lock_interruptible(&dev->mutex); + if (error) + return error; + list_add_tail_rcu(&handle->d_node, &dev->h_list); + mutex_unlock(&dev->mutex); + synchronize_rcu(); + + /* + * Since we are supposed to be called from ->connect() + * which is mutually exclusive with ->disconnect() + * we can't be racing with input_unregister_handle() + * and so separate lock is not needed here. + */ list_add_tail(&handle->h_node, &handler->h_list); if (handler->start) @@ -1224,10 +1493,29 @@ int input_register_handle(struct input_handle *handle) } EXPORT_SYMBOL(input_register_handle); +/** + * input_unregister_handle - unregister an input handle + * @handle: handle to unregister + * + * This function removes input handle from device's + * and handler's lists. + * + * This function is supposed to be called from handler's + * disconnect() method. + */ void input_unregister_handle(struct input_handle *handle) { + struct input_dev *dev = handle->dev; + list_del_init(&handle->h_node); - list_del_init(&handle->d_node); + + /* + * Take dev->mutex to prevent race with input_release_device(). + */ + mutex_lock(&dev->mutex); + list_del_rcu(&handle->d_node); + mutex_unlock(&dev->mutex); + synchronize_rcu(); } EXPORT_SYMBOL(input_unregister_handle); diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index a9a0180bfd46..2b201f9aa024 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -43,6 +43,8 @@ struct joydev { struct input_handle handle; wait_queue_head_t wait; struct list_head client_list; + spinlock_t client_lock; /* protects client_list */ + struct mutex mutex; struct device dev; struct js_corr corr[ABS_MAX + 1]; @@ -61,31 +63,61 @@ struct joydev_client { int head; int tail; int startup; + spinlock_t buffer_lock; /* protects access to buffer, head and tail */ struct fasync_struct *fasync; struct joydev *joydev; struct list_head node; }; static struct joydev *joydev_table[JOYDEV_MINORS]; +static DEFINE_MUTEX(joydev_table_mutex); static int joydev_correct(int value, struct js_corr *corr) { switch (corr->type) { - case JS_CORR_NONE: - break; - case JS_CORR_BROKEN: - value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 : - ((corr->coef[3] * (value - corr->coef[1])) >> 14)) : - ((corr->coef[2] * (value - corr->coef[0])) >> 14); - break; - default: - return 0; + + case JS_CORR_NONE: + break; + + case JS_CORR_BROKEN: + value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 : + ((corr->coef[3] * (value - corr->coef[1])) >> 14)) : + ((corr->coef[2] * (value - corr->coef[0])) >> 14); + break; + + default: + return 0; } return value < -32767 ? -32767 : (value > 32767 ? 32767 : value); } -static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) +static void joydev_pass_event(struct joydev_client *client, + struct js_event *event) +{ + struct joydev *joydev = client->joydev; + + /* + * IRQs already disabled, just acquire the lock + */ + spin_lock(&client->buffer_lock); + + client->buffer[client->head] = *event; + + if (client->startup == joydev->nabs + joydev->nkey) { + client->head++; + client->head &= JOYDEV_BUFFER_SIZE - 1; + if (client->tail == client->head) + client->startup = 0; + } + + spin_unlock(&client->buffer_lock); + + kill_fasync(&client->fasync, SIGIO, POLL_IN); +} + +static void joydev_event(struct input_handle *handle, + unsigned int type, unsigned int code, int value) { struct joydev *joydev = handle->private; struct joydev_client *client; @@ -93,39 +125,34 @@ static void joydev_event(struct input_handle *handle, unsigned int type, unsigne switch (type) { - case EV_KEY: - if (code < BTN_MISC || value == 2) - return; - event.type = JS_EVENT_BUTTON; - event.number = joydev->keymap[code - BTN_MISC]; - event.value = value; - break; - - case EV_ABS: - event.type = JS_EVENT_AXIS; - event.number = joydev->absmap[code]; - event.value = joydev_correct(value, joydev->corr + event.number); - if (event.value == joydev->abs[event.number]) - return; - joydev->abs[event.number] = event.value; - break; + case EV_KEY: + if (code < BTN_MISC || value == 2) + return; + event.type = JS_EVENT_BUTTON; + event.number = joydev->keymap[code - BTN_MISC]; + event.value = value; + break; - default: + case EV_ABS: + event.type = JS_EVENT_AXIS; + event.number = joydev->absmap[code]; + event.value = joydev_correct(value, + &joydev->corr[event.number]); + if (event.value == joydev->abs[event.number]) return; + joydev->abs[event.number] = event.value; + break; + + default: + return; } event.time = jiffies_to_msecs(jiffies); - list_for_each_entry(client, &joydev->client_list, node) { - - memcpy(client->buffer + client->head, &event, sizeof(struct js_event)); - - if (client->startup == joydev->nabs + joydev->nkey) - if (client->tail == (client->head = (client->head + 1) & (JOYDEV_BUFFER_SIZE - 1))) - client->startup = 0; - - kill_fasync(&client->fasync, SIGIO, POLL_IN); - } + rcu_read_lock(); + list_for_each_entry_rcu(client, &joydev->client_list, node) + joydev_pass_event(client, &event); + rcu_read_unlock(); wake_up_interruptible(&joydev->wait); } @@ -144,23 +171,83 @@ static void joydev_free(struct device *dev) { struct joydev *joydev = container_of(dev, struct joydev, dev); - joydev_table[joydev->minor] = NULL; kfree(joydev); } +static void joydev_attach_client(struct joydev *joydev, + struct joydev_client *client) +{ + spin_lock(&joydev->client_lock); + list_add_tail_rcu(&client->node, &joydev->client_list); + spin_unlock(&joydev->client_lock); + synchronize_rcu(); +} + +static void joydev_detach_client(struct joydev *joydev, + struct joydev_client *client) +{ + spin_lock(&joydev->client_lock); + list_del_rcu(&client->node); + spin_unlock(&joydev->client_lock); + synchronize_rcu(); +} + +static int joydev_open_device(struct joydev *joydev) +{ + int retval; + + retval = mutex_lock_interruptible(&joydev->mutex); + if (retval) + return retval; + + if (!joydev->exist) + retval = -ENODEV; + else if (!joydev->open++) { + retval = input_open_device(&joydev->handle); + if (retval) + joydev->open--; + } + + mutex_unlock(&joydev->mutex); + return retval; +} + +static void joydev_close_device(struct joydev *joydev) +{ + mutex_lock(&joydev->mutex); + + if (joydev->exist && !--joydev->open) + input_close_device(&joydev->handle); + + mutex_unlock(&joydev->mutex); +} + +/* + * Wake up users waiting for IO so they can disconnect from + * dead device. + */ +static void joydev_hangup(struct joydev *joydev) +{ + struct joydev_client *client; + + spin_lock(&joydev->client_lock); + list_for_each_entry(client, &joydev->client_list, node) + kill_fasync(&client->fasync, SIGIO, POLL_HUP); + spin_unlock(&joydev->client_lock); + + wake_up_interruptible(&joydev->wait); +} + static int joydev_release(struct inode *inode, struct file *file) { struct joydev_client *client = file->private_data; struct joydev *joydev = client->joydev; joydev_fasync(-1, file, 0); - - list_del(&client->node); + joydev_detach_client(joydev, client); kfree(client); - if (!--joydev->open && joydev->exist) - input_close_device(&joydev->handle); - + joydev_close_device(joydev); put_device(&joydev->dev); return 0; @@ -176,11 +263,16 @@ static int joydev_open(struct inode *inode, struct file *file) if (i >= JOYDEV_MINORS) return -ENODEV; + error = mutex_lock_interruptible(&joydev_table_mutex); + if (error) + return error; joydev = joydev_table[i]; - if (!joydev || !joydev->exist) - return -ENODEV; + if (joydev) + get_device(&joydev->dev); + mutex_unlock(&joydev_table_mutex); - get_device(&joydev->dev); + if (!joydev) + return -ENODEV; client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL); if (!client) { @@ -188,37 +280,129 @@ static int joydev_open(struct inode *inode, struct file *file) goto err_put_joydev; } + spin_lock_init(&client->buffer_lock); client->joydev = joydev; - list_add_tail(&client->node, &joydev->client_list); + joydev_attach_client(joydev, client); - if (!joydev->open++ && joydev->exist) { - error = input_open_device(&joydev->handle); - if (error) - goto err_free_client; - } + error = joydev_open_device(joydev); + if (error) + goto err_free_client; file->private_data = client; return 0; err_free_client: - list_del(&client->node); + joydev_detach_client(joydev, client); kfree(client); err_put_joydev: put_device(&joydev->dev); return error; } -static ssize_t joydev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +static int joydev_generate_startup_event(struct joydev_client *client, + struct input_dev *input, + struct js_event *event) { - return -EINVAL; + struct joydev *joydev = client->joydev; + int have_event; + + spin_lock_irq(&client->buffer_lock); + + have_event = client->startup < joydev->nabs + joydev->nkey; + + if (have_event) { + + event->time = jiffies_to_msecs(jiffies); + if (client->startup < joydev->nkey) { + event->type = JS_EVENT_BUTTON | JS_EVENT_INIT; + event->number = client->startup; + event->value = !!test_bit(joydev->keypam[event->number], + input->key); + } else { + event->type = JS_EVENT_AXIS | JS_EVENT_INIT; + event->number = client->startup - joydev->nkey; + event->value = joydev->abs[event->number]; + } + client->startup++; + } + + spin_unlock_irq(&client->buffer_lock); + + return have_event; +} + +static int joydev_fetch_next_event(struct joydev_client *client, + struct js_event *event) +{ + int have_event; + + spin_lock_irq(&client->buffer_lock); + + have_event = client->head != client->tail; + if (have_event) { + *event = client->buffer[client->tail++]; + client->tail &= JOYDEV_BUFFER_SIZE - 1; + } + + spin_unlock_irq(&client->buffer_lock); + + return have_event; +} + +/* + * Old joystick interface + */ +static ssize_t joydev_0x_read(struct joydev_client *client, + struct input_dev *input, + char __user *buf) +{ + struct joydev *joydev = client->joydev; + struct JS_DATA_TYPE data; + int i; + + spin_lock_irq(&input->event_lock); + + /* + * Get device state + */ + for (data.buttons = i = 0; i < 32 && i < joydev->nkey; i++) + data.buttons |= + test_bit(joydev->keypam[i], input->key) ? (1 << i) : 0; + data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x; + data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y; + + /* + * Reset reader's event queue + */ + spin_lock(&client->buffer_lock); + client->startup = 0; + client->tail = client->head; + spin_unlock(&client->buffer_lock); + + spin_unlock_irq(&input->event_lock); + + if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE))) + return -EFAULT; + + return sizeof(struct JS_DATA_TYPE); +} + +static inline int joydev_data_pending(struct joydev_client *client) +{ + struct joydev *joydev = client->joydev; + + return client->startup < joydev->nabs + joydev->nkey || + client->head != client->tail; } -static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +static ssize_t joydev_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) { struct joydev_client *client = file->private_data; struct joydev *joydev = client->joydev; struct input_dev *input = joydev->handle.dev; - int retval = 0; + struct js_event event; + int retval; if (!joydev->exist) return -ENODEV; @@ -226,68 +410,35 @@ static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, lo if (count < sizeof(struct js_event)) return -EINVAL; - if (count == sizeof(struct JS_DATA_TYPE)) { - - struct JS_DATA_TYPE data; - int i; - - for (data.buttons = i = 0; i < 32 && i < joydev->nkey; i++) - data.buttons |= test_bit(joydev->keypam[i], input->key) ? (1 << i) : 0; - data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x; - data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y; - - if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE))) - return -EFAULT; - - client->startup = 0; - client->tail = client->head; + if (count == sizeof(struct JS_DATA_TYPE)) + return joydev_0x_read(client, input, buf); - return sizeof(struct JS_DATA_TYPE); - } - - if (client->startup == joydev->nabs + joydev->nkey && - client->head == client->tail && (file->f_flags & O_NONBLOCK)) + if (!joydev_data_pending(client) && (file->f_flags & O_NONBLOCK)) return -EAGAIN; retval = wait_event_interruptible(joydev->wait, - !joydev->exist || - client->startup < joydev->nabs + joydev->nkey || - client->head != client->tail); + !joydev->exist || joydev_data_pending(client)); if (retval) return retval; if (!joydev->exist) return -ENODEV; - while (client->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) { - - struct js_event event; - - event.time = jiffies_to_msecs(jiffies); - - if (client->startup < joydev->nkey) { - event.type = JS_EVENT_BUTTON | JS_EVENT_INIT; - event.number = client->startup; - event.value = !!test_bit(joydev->keypam[event.number], input->key); - } else { - event.type = JS_EVENT_AXIS | JS_EVENT_INIT; - event.number = client->startup - joydev->nkey; - event.value = joydev->abs[event.number]; - } + while (retval + sizeof(struct js_event) <= count && + joydev_generate_startup_event(client, input, &event)) { if (copy_to_user(buf + retval, &event, sizeof(struct js_event))) return -EFAULT; - client->startup++; retval += sizeof(struct js_event); } - while (client->head != client->tail && retval + sizeof(struct js_event) <= count) { + while (retval + sizeof(struct js_event) <= count && + joydev_fetch_next_event(client, &event)) { - if (copy_to_user(buf + retval, client->buffer + client->tail, sizeof(struct js_event))) + if (copy_to_user(buf + retval, &event, sizeof(struct js_event))) return -EFAULT; - client->tail = (client->tail + 1) & (JOYDEV_BUFFER_SIZE - 1); retval += sizeof(struct js_event); } @@ -301,126 +452,144 @@ static unsigned int joydev_poll(struct file *file, poll_table *wait) struct joydev *joydev = client->joydev; poll_wait(file, &joydev->wait, wait); - return ((client->head != client->tail || client->startup < joydev->nabs + joydev->nkey) ? - (POLLIN | POLLRDNORM) : 0) | (joydev->exist ? 0 : (POLLHUP | POLLERR)); + return (joydev_data_pending(client) ? (POLLIN | POLLRDNORM) : 0) | + (joydev->exist ? 0 : (POLLHUP | POLLERR)); } -static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __user *argp) +static int joydev_ioctl_common(struct joydev *joydev, + unsigned int cmd, void __user *argp) { struct input_dev *dev = joydev->handle.dev; int i, j; switch (cmd) { - case JS_SET_CAL: - return copy_from_user(&joydev->glue.JS_CORR, argp, + case JS_SET_CAL: + return copy_from_user(&joydev->glue.JS_CORR, argp, sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0; - case JS_GET_CAL: - return copy_to_user(argp, &joydev->glue.JS_CORR, + case JS_GET_CAL: + return copy_to_user(argp, &joydev->glue.JS_CORR, sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0; - case JS_SET_TIMEOUT: - return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp); + case JS_SET_TIMEOUT: + return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp); - case JS_GET_TIMEOUT: - return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp); + case JS_GET_TIMEOUT: + return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp); - case JSIOCGVERSION: - return put_user(JS_VERSION, (__u32 __user *) argp); + case JSIOCGVERSION: + return put_user(JS_VERSION, (__u32 __user *) argp); - case JSIOCGAXES: - return put_user(joydev->nabs, (__u8 __user *) argp); + case JSIOCGAXES: + return put_user(joydev->nabs, (__u8 __user *) argp); - case JSIOCGBUTTONS: - return put_user(joydev->nkey, (__u8 __user *) argp); + case JSIOCGBUTTONS: + return put_user(joydev->nkey, (__u8 __user *) argp); - case JSIOCSCORR: - if (copy_from_user(joydev->corr, argp, - sizeof(joydev->corr[0]) * joydev->nabs)) - return -EFAULT; - for (i = 0; i < joydev->nabs; i++) { - j = joydev->abspam[i]; - joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i); - } - return 0; + case JSIOCSCORR: + if (copy_from_user(joydev->corr, argp, + sizeof(joydev->corr[0]) * joydev->nabs)) + return -EFAULT; - case JSIOCGCORR: - return copy_to_user(argp, joydev->corr, - sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0; + for (i = 0; i < joydev->nabs; i++) { + j = joydev->abspam[i]; + joydev->abs[i] = joydev_correct(dev->abs[j], + &joydev->corr[i]); + } + return 0; - case JSIOCSAXMAP: - if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * (ABS_MAX + 1))) - return -EFAULT; - for (i = 0; i < joydev->nabs; i++) { - if (joydev->abspam[i] > ABS_MAX) - return -EINVAL; - joydev->absmap[joydev->abspam[i]] = i; - } - return 0; - - case JSIOCGAXMAP: - return copy_to_user(argp, joydev->abspam, - sizeof(__u8) * (ABS_MAX + 1)) ? -EFAULT : 0; - - case JSIOCSBTNMAP: - if (copy_from_user(joydev->keypam, argp, sizeof(__u16) * (KEY_MAX - BTN_MISC + 1))) + case JSIOCGCORR: + return copy_to_user(argp, joydev->corr, + sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0; + + case JSIOCSAXMAP: + if (copy_from_user(joydev->abspam, argp, + sizeof(__u8) * (ABS_MAX + 1))) + return -EFAULT; + + for (i = 0; i < joydev->nabs; i++) { + if (joydev->abspam[i] > ABS_MAX) + return -EINVAL; + joydev->absmap[joydev->abspam[i]] = i; + } + return 0; + + case JSIOCGAXMAP: + return copy_to_user(argp, joydev->abspam, + sizeof(__u8) * (ABS_MAX + 1)) ? -EFAULT : 0; + + case JSIOCSBTNMAP: + if (copy_from_user(joydev->keypam, argp, + sizeof(__u16) * (KEY_MAX - BTN_MISC + 1))) + return -EFAULT; + + for (i = 0; i < joydev->nkey; i++) { + if (joydev->keypam[i] > KEY_MAX || + joydev->keypam[i] < BTN_MISC) + return -EINVAL; + joydev->keymap[joydev->keypam[i] - BTN_MISC] = i; + } + + return 0; + + case JSIOCGBTNMAP: + return copy_to_user(argp, joydev->keypam, + sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)) ? -EFAULT : 0; + + default: + if ((cmd & ~IOCSIZE_MASK) == JSIOCGNAME(0)) { + int len; + if (!dev->name) + return 0; + len = strlen(dev->name) + 1; + if (len > _IOC_SIZE(cmd)) + len = _IOC_SIZE(cmd); + if (copy_to_user(argp, dev->name, len)) return -EFAULT; - for (i = 0; i < joydev->nkey; i++) { - if (joydev->keypam[i] > KEY_MAX || joydev->keypam[i] < BTN_MISC) - return -EINVAL; - joydev->keymap[joydev->keypam[i] - BTN_MISC] = i; - } - return 0; - - case JSIOCGBTNMAP: - return copy_to_user(argp, joydev->keypam, - sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)) ? -EFAULT : 0; - - default: - if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) { - int len; - if (!dev->name) - return 0; - len = strlen(dev->name) + 1; - if (len > _IOC_SIZE(cmd)) - len = _IOC_SIZE(cmd); - if (copy_to_user(argp, dev->name, len)) - return -EFAULT; - return len; - } + return len; + } } return -EINVAL; } #ifdef CONFIG_COMPAT -static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +static long joydev_compat_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) { struct joydev_client *client = file->private_data; struct joydev *joydev = client->joydev; void __user *argp = (void __user *)arg; s32 tmp32; struct JS_DATA_SAVE_TYPE_32 ds32; - int err; + int retval; - if (!joydev->exist) - return -ENODEV; + retval = mutex_lock_interruptible(&joydev->mutex); + if (retval) + return retval; + + if (!joydev->exist) { + retval = -ENODEV; + goto out; + } + + switch (cmd) { - switch(cmd) { case JS_SET_TIMELIMIT: - err = get_user(tmp32, (s32 __user *) arg); - if (err == 0) + retval = get_user(tmp32, (s32 __user *) arg); + if (retval == 0) joydev->glue.JS_TIMELIMIT = tmp32; break; + case JS_GET_TIMELIMIT: tmp32 = joydev->glue.JS_TIMELIMIT; - err = put_user(tmp32, (s32 __user *) arg); + retval = put_user(tmp32, (s32 __user *) arg); break; case JS_SET_ALL: - err = copy_from_user(&ds32, argp, - sizeof(ds32)) ? -EFAULT : 0; - if (err == 0) { + retval = copy_from_user(&ds32, argp, + sizeof(ds32)) ? -EFAULT : 0; + if (retval == 0) { joydev->glue.JS_TIMEOUT = ds32.JS_TIMEOUT; joydev->glue.BUSY = ds32.BUSY; joydev->glue.JS_EXPIRETIME = ds32.JS_EXPIRETIME; @@ -438,55 +607,119 @@ static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned lo ds32.JS_SAVE = joydev->glue.JS_SAVE; ds32.JS_CORR = joydev->glue.JS_CORR; - err = copy_to_user(argp, &ds32, sizeof(ds32)) ? -EFAULT : 0; + retval = copy_to_user(argp, &ds32, sizeof(ds32)) ? -EFAULT : 0; break; default: - err = joydev_ioctl_common(joydev, cmd, argp); + retval = joydev_ioctl_common(joydev, cmd, argp); + break; } - return err; + + out: + mutex_unlock(&joydev->mutex); + return retval; } #endif /* CONFIG_COMPAT */ -static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +static long joydev_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) { struct joydev_client *client = file->private_data; struct joydev *joydev = client->joydev; void __user *argp = (void __user *)arg; + int retval; - if (!joydev->exist) - return -ENODEV; + retval = mutex_lock_interruptible(&joydev->mutex); + if (retval) + return retval; + + if (!joydev->exist) { + retval = -ENODEV; + goto out; + } + + switch (cmd) { + + case JS_SET_TIMELIMIT: + retval = get_user(joydev->glue.JS_TIMELIMIT, + (long __user *) arg); + break; + + case JS_GET_TIMELIMIT: + retval = put_user(joydev->glue.JS_TIMELIMIT, + (long __user *) arg); + break; + + case JS_SET_ALL: + retval = copy_from_user(&joydev->glue, argp, + sizeof(joydev->glue)) ? -EFAULT: 0; + break; + + case JS_GET_ALL: + retval = copy_to_user(argp, &joydev->glue, + sizeof(joydev->glue)) ? -EFAULT : 0; + break; - switch(cmd) { - case JS_SET_TIMELIMIT: - return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg); - case JS_GET_TIMELIMIT: - return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg); - case JS_SET_ALL: - return copy_from_user(&joydev->glue, argp, - sizeof(joydev->glue)) ? -EFAULT : 0; - case JS_GET_ALL: - return copy_to_user(argp, &joydev->glue, - sizeof(joydev->glue)) ? -EFAULT : 0; - default: - return joydev_ioctl_common(joydev, cmd, argp); + default: + retval = joydev_ioctl_common(joydev, cmd, argp); + break; } + out: + mutex_unlock(&joydev->mutex); + return retval; } static const struct file_operations joydev_fops = { - .owner = THIS_MODULE, - .read = joydev_read, - .write = joydev_write, - .poll = joydev_poll, - .open = joydev_open, - .release = joydev_release, - .ioctl = joydev_ioctl, + .owner = THIS_MODULE, + .read = joydev_read, + .poll = joydev_poll, + .open = joydev_open, + .release = joydev_release, + .unlocked_ioctl = joydev_ioctl, #ifdef CONFIG_COMPAT - .compat_ioctl = joydev_compat_ioctl, + .compat_ioctl = joydev_compat_ioctl, #endif - .fasync = joydev_fasync, + .fasync = joydev_fasync, }; +static int joydev_install_chrdev(struct joydev *joydev) +{ + joydev_table[joydev->minor] = joydev; + return 0; +} + +static void joydev_remove_chrdev(struct joydev *joydev) +{ + mutex_lock(&joydev_table_mutex); + joydev_table[joydev->minor] = NULL; + mutex_unlock(&joydev_table_mutex); +} + +/* + * Mark device non-existant. This disables writes, ioctls and + * prevents new users from opening the device. Already posted + * blocking reads will stay, however new ones will fail. + */ +static void joydev_mark_dead(struct joydev *joydev) +{ + mutex_lock(&joydev->mutex); + joydev->exist = 0; + mutex_unlock(&joydev->mutex); +} + +static void joydev_cleanup(struct joydev *joydev) +{ + struct input_handle *handle = &joydev->handle; + + joydev_mark_dead(joydev); + joydev_hangup(joydev); + joydev_remove_chrdev(joydev); + + /* joydev is marked dead so noone else accesses joydev->open */ + if (joydev->open) + input_close_device(handle); +} + static int joydev_connect(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id) { @@ -494,7 +727,10 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, int i, j, t, minor; int error; - for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++); + for (minor = 0; minor < JOYDEV_MINORS; minor++) + if (!joydev_table[minor]) + break; + if (minor == JOYDEV_MINORS) { printk(KERN_ERR "joydev: no more free joydev devices\n"); return -ENFILE; @@ -505,15 +741,19 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, return -ENOMEM; INIT_LIST_HEAD(&joydev->client_list); + spin_lock_init(&joydev->client_lock); + mutex_init(&joydev->mutex); init_waitqueue_head(&joydev->wait); + snprintf(joydev->name, sizeof(joydev->name), "js%d", minor); + joydev->exist = 1; joydev->minor = minor; + joydev->exist = 1; joydev->handle.dev = dev; joydev->handle.name = joydev->name; joydev->handle.handler = handler; joydev->handle.private = joydev; - snprintf(joydev->name, sizeof(joydev->name), "js%d", minor); for (i = 0; i < ABS_MAX + 1; i++) if (test_bit(i, dev->absbit)) { @@ -545,67 +785,65 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, } joydev->corr[i].type = JS_CORR_BROKEN; joydev->corr[i].prec = dev->absfuzz[j]; - joydev->corr[i].coef[0] = (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j]; - joydev->corr[i].coef[1] = (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j]; - if (!(t = ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]))) - continue; - joydev->corr[i].coef[2] = (1 << 29) / t; - joydev->corr[i].coef[3] = (1 << 29) / t; - - joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i); + joydev->corr[i].coef[0] = + (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j]; + joydev->corr[i].coef[1] = + (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j]; + + t = (dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]; + if (t) { + joydev->corr[i].coef[2] = (1 << 29) / t; + joydev->corr[i].coef[3] = (1 << 29) / t; + + joydev->abs[i] = joydev_correct(dev->abs[j], + joydev->corr + i); + } } - snprintf(joydev->dev.bus_id, sizeof(joydev->dev.bus_id), - "js%d", minor); + strlcpy(joydev->dev.bus_id, joydev->name, sizeof(joydev->dev.bus_id)); + joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor); joydev->dev.class = &input_class; joydev->dev.parent = &dev->dev; - joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor); joydev->dev.release = joydev_free; device_initialize(&joydev->dev); - joydev_table[minor] = joydev; - - error = device_add(&joydev->dev); + error = input_register_handle(&joydev->handle); if (error) goto err_free_joydev; - error = input_register_handle(&joydev->handle); + error = joydev_install_chrdev(joydev); if (error) - goto err_delete_joydev; + goto err_unregister_handle; + + error = device_add(&joydev->dev); + if (error) + goto err_cleanup_joydev; return 0; - err_delete_joydev: - device_del(&joydev->dev); + err_cleanup_joydev: + joydev_cleanup(joydev); + err_unregister_handle: + input_unregister_handle(&joydev->handle); err_free_joydev: put_device(&joydev->dev); return error; } - static void joydev_disconnect(struct input_handle *handle) { struct joydev *joydev = handle->private; - struct joydev_client *client; - input_unregister_handle(handle); device_del(&joydev->dev); - - joydev->exist = 0; - - if (joydev->open) { - input_close_device(handle); - list_for_each_entry(client, &joydev->client_list, node) - kill_fasync(&client->fasync, SIGIO, POLL_HUP); - wake_up_interruptible(&joydev->wait); - } - + joydev_cleanup(joydev); + input_unregister_handle(handle); put_device(&joydev->dev); } static const struct input_device_id joydev_blacklist[] = { { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | + INPUT_DEVICE_ID_MATCH_KEYBIT, .evbit = { BIT(EV_KEY) }, .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, }, /* Avoid itouchpads, touchscreens and tablets */ @@ -614,17 +852,20 @@ static const struct input_device_id joydev_blacklist[] = { static const struct input_device_id joydev_ids[] = { { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | + INPUT_DEVICE_ID_MATCH_ABSBIT, .evbit = { BIT(EV_ABS) }, .absbit = { BIT(ABS_X) }, }, { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | + INPUT_DEVICE_ID_MATCH_ABSBIT, .evbit = { BIT(EV_ABS) }, .absbit = { BIT(ABS_WHEEL) }, }, { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | + INPUT_DEVICE_ID_MATCH_ABSBIT, .evbit = { BIT(EV_ABS) }, .absbit = { BIT(ABS_THROTTLE) }, }, @@ -634,14 +875,14 @@ static const struct input_device_id joydev_ids[] = { MODULE_DEVICE_TABLE(input, joydev_ids); static struct input_handler joydev_handler = { - .event = joydev_event, - .connect = joydev_connect, - .disconnect = joydev_disconnect, - .fops = &joydev_fops, - .minor = JOYDEV_MINOR_BASE, - .name = "joydev", - .id_table = joydev_ids, - .blacklist = joydev_blacklist, + .event = joydev_event, + .connect = joydev_connect, + .disconnect = joydev_disconnect, + .fops = &joydev_fops, + .minor = JOYDEV_MINOR_BASE, + .name = "joydev", + .id_table = joydev_ids, + .blacklist = joydev_blacklist, }; static int __init joydev_init(void) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 28080395899c..623629a69b03 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -223,12 +223,16 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d struct input_dev *dev = xpad->dev; /* left stick */ - input_report_abs(dev, ABS_X, (__s16) (((__s16)data[13] << 8) | data[12])); - input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[15] << 8) | data[14])); + input_report_abs(dev, ABS_X, + (__s16) le16_to_cpup((__le16 *)(data + 12))); + input_report_abs(dev, ABS_Y, + (__s16) le16_to_cpup((__le16 *)(data + 14))); /* right stick */ - input_report_abs(dev, ABS_RX, (__s16) (((__s16)data[17] << 8) | data[16])); - input_report_abs(dev, ABS_RY, (__s16) (((__s16)data[19] << 8) | data[18])); + input_report_abs(dev, ABS_RX, + (__s16) le16_to_cpup((__le16 *)(data + 16))); + input_report_abs(dev, ABS_RY, + (__s16) le16_to_cpup((__le16 *)(data + 18))); /* triggers left/right */ input_report_abs(dev, ABS_Z, data[10]); @@ -236,8 +240,10 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d /* digital pad */ if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) { - input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04)); - input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01)); + input_report_abs(dev, ABS_HAT0X, + !!(data[2] & 0x08) - !!(data[2] & 0x04)); + input_report_abs(dev, ABS_HAT0Y, + !!(data[2] & 0x02) - !!(data[2] & 0x01)); } else /* xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS */ { input_report_key(dev, BTN_LEFT, data[2] & 0x04); input_report_key(dev, BTN_RIGHT, data[2] & 0x08); @@ -274,14 +280,17 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d * http://www.free60.org/wiki/Gamepad */ -static void xpad360_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data) +static void xpad360_process_packet(struct usb_xpad *xpad, + u16 cmd, unsigned char *data) { struct input_dev *dev = xpad->dev; /* digital pad */ if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) { - input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04)); - input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01)); + input_report_abs(dev, ABS_HAT0X, + !!(data[2] & 0x08) - !!(data[2] & 0x04)); + input_report_abs(dev, ABS_HAT0Y, + !!(data[2] & 0x02) - !!(data[2] & 0x01)); } else if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS) { /* dpad as buttons (right, left, down, up) */ input_report_key(dev, BTN_LEFT, data[2] & 0x04); @@ -308,12 +317,16 @@ static void xpad360_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char input_report_key(dev, BTN_MODE, data[3] & 0x04); /* left stick */ - input_report_abs(dev, ABS_X, (__s16) (((__s16)data[7] << 8) | (__s16)data[6])); - input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[9] << 8) | (__s16)data[8])); + input_report_abs(dev, ABS_X, + (__s16) le16_to_cpup((__le16 *)(data + 6))); + input_report_abs(dev, ABS_Y, + (__s16) le16_to_cpup((__le16 *)(data + 8))); /* right stick */ - input_report_abs(dev, ABS_RX, (__s16) (((__s16)data[11] << 8) | (__s16)data[10])); - input_report_abs(dev, ABS_RY, (__s16) (((__s16)data[13] << 8) | (__s16)data[12])); + input_report_abs(dev, ABS_RX, + (__s16) le16_to_cpup((__le16 *)(data + 10))); + input_report_abs(dev, ABS_RY, + (__s16) le16_to_cpup((__le16 *)(data + 12))); /* triggers left/right */ input_report_abs(dev, ABS_Z, data[4]); @@ -335,10 +348,12 @@ static void xpad_irq_in(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); + dbg("%s - urb shutting down with status: %d", + __FUNCTION__, urb->status); return; default: - dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); + dbg("%s - nonzero urb status received: %d", + __FUNCTION__, urb->status); goto exit; } @@ -367,10 +382,12 @@ static void xpad_irq_out(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); + dbg("%s - urb shutting down with status: %d", + __FUNCTION__, urb->status); return; default: - dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); + dbg("%s - nonzero urb status received: %d", + __FUNCTION__, urb->status); goto exit; } @@ -378,7 +395,7 @@ exit: retval = usb_submit_urb(urb, GFP_ATOMIC); if (retval) err("%s - usb_submit_urb failed with result %d", - __FUNCTION__, retval); + __FUNCTION__, retval); } static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) @@ -595,7 +612,7 @@ static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs) static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id) { - struct usb_device *udev = interface_to_usbdev (intf); + struct usb_device *udev = interface_to_usbdev(intf); struct usb_xpad *xpad; struct input_dev *input_dev; struct usb_endpoint_descriptor *ep_irq_in; diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index c97d5eb0075d..2316a018fae6 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -208,6 +208,27 @@ config KEYBOARD_HIL This driver implements support for HIL-keyboards attached to your machine, so normally you should say Y here. +config KEYBOARD_HP6XX + tristate "HP Jornada 6XX Keyboard support" + depends on SH_HP6XX + select INPUT_POLLDEV + help + This adds support for the onboard keyboard found on + HP Jornada 620/660/680/690. + + To compile this driver as a module, choose M here: the + module will be called jornada680_kbd. + +config KEYBOARD_HP7XX + tristate "HP Jornada 7XX Keyboard Driver" + depends on SA1100_JORNADA720_SSP && SA1100_SSP + help + Say Y here to add support for the HP Jornada 7xx (710/720/728) + onboard keyboard. + + To compile this driver as a module, choose M here: the + module will be called jornada720_kbd. + config KEYBOARD_OMAP tristate "TI OMAP keypad support" depends on (ARCH_OMAP1 || ARCH_OMAP2) @@ -253,4 +274,23 @@ config KEYBOARD_GPIO To compile this driver as a module, choose M here: the module will be called gpio-keys. +config KEYBOARD_MAPLE + tristate "Maple bus keyboard" + depends on SH_DREAMCAST && MAPLE + help + Say Y here if you have a Dreamcast console running Linux and have + a keyboard attached to its Maple bus. + + To compile this driver as a module, choose M here: the + module will be called maple_keyb. + +config KEYBOARD_BFIN + tristate "Blackfin BF54x keypad support" + depends on BF54x + help + Say Y here if you want to use the BF54x keypad. + + To compile this driver as a module, choose M here: the + module will be called bf54x-keys. + endif diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 28d211b87b14..e97455fdcc83 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -21,4 +21,7 @@ obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keyboard.o obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o - +obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o +obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o +obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o +obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o diff --git a/drivers/input/keyboard/atakbd.c b/drivers/input/keyboard/atakbd.c index ded1d6ac6ff3..a1800151b6ce 100644 --- a/drivers/input/keyboard/atakbd.c +++ b/drivers/input/keyboard/atakbd.c @@ -55,7 +55,140 @@ MODULE_AUTHOR("Michael Schmitz <schmitz@biophys.uni-duesseldorf.de>"); MODULE_DESCRIPTION("Atari keyboard driver"); MODULE_LICENSE("GPL"); -static unsigned char atakbd_keycode[0x72]; +/* + 0x47: KP_7 71 + 0x48: KP_8 72 + 0x49: KP_9 73 + 0x62: KP_/ 98 + 0x4b: KP_4 75 + 0x4c: KP_5 76 + 0x4d: KP_6 77 + 0x37: KP_* 55 + 0x4f: KP_1 79 + 0x50: KP_2 80 + 0x51: KP_3 81 + 0x4a: KP_- 74 + 0x52: KP_0 82 + 0x53: KP_. 83 + 0x4e: KP_+ 78 + + 0x67: Up 103 + 0x6c: Down 108 + 0x69: Left 105 + 0x6a: Right 106 + */ + + +static unsigned char atakbd_keycode[0x72] = { /* American layout */ + [0] = KEY_GRAVE, + [1] = KEY_ESC, + [2] = KEY_1, + [3] = KEY_2, + [4] = KEY_3, + [5] = KEY_4, + [6] = KEY_5, + [7] = KEY_6, + [8] = KEY_7, + [9] = KEY_8, + [10] = KEY_9, + [11] = KEY_0, + [12] = KEY_MINUS, + [13] = KEY_EQUAL, + [14] = KEY_BACKSPACE, + [15] = KEY_TAB, + [16] = KEY_Q, + [17] = KEY_W, + [18] = KEY_E, + [19] = KEY_R, + [20] = KEY_T, + [21] = KEY_Y, + [22] = KEY_U, + [23] = KEY_I, + [24] = KEY_O, + [25] = KEY_P, + [26] = KEY_LEFTBRACE, + [27] = KEY_RIGHTBRACE, + [28] = KEY_ENTER, + [29] = KEY_LEFTCTRL, + [30] = KEY_A, + [31] = KEY_S, + [32] = KEY_D, + [33] = KEY_F, + [34] = KEY_G, + [35] = KEY_H, + [36] = KEY_J, + [37] = KEY_K, + [38] = KEY_L, + [39] = KEY_SEMICOLON, + [40] = KEY_APOSTROPHE, + [41] = KEY_BACKSLASH, /* FIXME, '#' */ + [42] = KEY_LEFTSHIFT, + [43] = KEY_GRAVE, /* FIXME: '~' */ + [44] = KEY_Z, + [45] = KEY_X, + [46] = KEY_C, + [47] = KEY_V, + [48] = KEY_B, + [49] = KEY_N, + [50] = KEY_M, + [51] = KEY_COMMA, + [52] = KEY_DOT, + [53] = KEY_SLASH, + [54] = KEY_RIGHTSHIFT, + [55] = KEY_KPASTERISK, + [56] = KEY_LEFTALT, + [57] = KEY_SPACE, + [58] = KEY_CAPSLOCK, + [59] = KEY_F1, + [60] = KEY_F2, + [61] = KEY_F3, + [62] = KEY_F4, + [63] = KEY_F5, + [64] = KEY_F6, + [65] = KEY_F7, + [66] = KEY_F8, + [67] = KEY_F9, + [68] = KEY_F10, + [69] = KEY_ESC, + [70] = KEY_DELETE, + [71] = KEY_KP7, + [72] = KEY_KP8, + [73] = KEY_KP9, + [74] = KEY_KPMINUS, + [75] = KEY_KP4, + [76] = KEY_KP5, + [77] = KEY_KP6, + [78] = KEY_KPPLUS, + [79] = KEY_KP1, + [80] = KEY_KP2, + [81] = KEY_KP3, + [82] = KEY_KP0, + [83] = KEY_KPDOT, + [90] = KEY_KPLEFTPAREN, + [91] = KEY_KPRIGHTPAREN, + [92] = KEY_KPASTERISK, /* FIXME */ + [93] = KEY_KPASTERISK, + [94] = KEY_KPPLUS, + [95] = KEY_HELP, + [96] = KEY_BACKSLASH, /* FIXME: '<' */ + [97] = KEY_KPASTERISK, /* FIXME */ + [98] = KEY_KPSLASH, + [99] = KEY_KPLEFTPAREN, + [100] = KEY_KPRIGHTPAREN, + [101] = KEY_KPSLASH, + [102] = KEY_KPASTERISK, + [103] = KEY_UP, + [104] = KEY_KPASTERISK, /* FIXME */ + [105] = KEY_LEFT, + [106] = KEY_RIGHT, + [107] = KEY_KPASTERISK, /* FIXME */ + [108] = KEY_DOWN, + [109] = KEY_KPASTERISK, /* FIXME */ + [110] = KEY_KPASTERISK, /* FIXME */ + [111] = KEY_KPASTERISK, /* FIXME */ + [112] = KEY_KPASTERISK, /* FIXME */ + [113] = KEY_KPASTERISK /* FIXME */ +}; static struct input_dev *atakbd_dev; @@ -84,23 +217,22 @@ static void atakbd_interrupt(unsigned char scancode, char down) static int __init atakbd_init(void) { - int i; + int i, error; - if (!ATARIHW_PRESENT(ST_MFP)) + if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ST_MFP)) return -EIO; - // TODO: request_mem_region if not done in arch code - - if (!(atakbd_dev = input_allocate_device())) - return -ENOMEM; - // need to init core driver if not already done so if (atari_keyb_init()) return -ENODEV; + atakbd_dev = input_allocate_device(); + if (!atakbd_dev) + return -ENOMEM; + atakbd_dev->name = "Atari Keyboard"; atakbd_dev->phys = "atakbd/input0"; - atakbd_dev->id.bustype = BUS_ATARI; + atakbd_dev->id.bustype = BUS_HOST; atakbd_dev->id.vendor = 0x0001; atakbd_dev->id.product = 0x0001; atakbd_dev->id.version = 0x0100; @@ -111,16 +243,18 @@ static int __init atakbd_init(void) atakbd_dev->keycodemax = ARRAY_SIZE(atakbd_keycode); for (i = 1; i < 0x72; i++) { - atakbd_keycode[i] = i; set_bit(atakbd_keycode[i], atakbd_dev->keybit); } - input_register_device(atakbd_dev); + /* error check */ + error = input_register_device(atakbd_dev); + if (error) { + input_free_device(atakbd_dev); + return error; + } atari_input_keyboard_interrupt_hook = atakbd_interrupt; - printk(KERN_INFO "input: %s at IKBD ACIA\n", atakbd_dev->name); - return 0; } diff --git a/drivers/input/keyboard/bf54x-keys.c b/drivers/input/keyboard/bf54x-keys.c new file mode 100644 index 000000000000..a67b29b089ef --- /dev/null +++ b/drivers/input/keyboard/bf54x-keys.c @@ -0,0 +1,382 @@ +/* + * File: drivers/input/keyboard/bf54x-keys.c + * Based on: + * Author: Michael Hennerich <hennerich@blackfin.uclinux.org> + * + * Created: + * Description: keypad driver for Analog Devices Blackfin BF54x Processors + * + * + * Modified: + * Copyright 2007 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <linux/module.h> +#include <linux/version.h> + +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/sched.h> +#include <linux/pm.h> +#include <linux/sysctl.h> +#include <linux/proc_fs.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/input.h> +#include <linux/irq.h> + +#include <asm/portmux.h> +#include <asm/mach/bf54x_keys.h> + +#define DRV_NAME "bf54x-keys" +#define TIME_SCALE 100 /* 100 ns */ +#define MAX_MULT (0xFF * TIME_SCALE) +#define MAX_RC 8 /* Max Row/Col */ + +static const u16 per_rows[] = { + P_KEY_ROW7, + P_KEY_ROW6, + P_KEY_ROW5, + P_KEY_ROW4, + P_KEY_ROW3, + P_KEY_ROW2, + P_KEY_ROW1, + P_KEY_ROW0, + 0 +}; + +static const u16 per_cols[] = { + P_KEY_COL7, + P_KEY_COL6, + P_KEY_COL5, + P_KEY_COL4, + P_KEY_COL3, + P_KEY_COL2, + P_KEY_COL1, + P_KEY_COL0, + 0 +}; + +struct bf54x_kpad { + struct input_dev *input; + int irq; + unsigned short lastkey; + unsigned short *keycode; + struct timer_list timer; + unsigned int keyup_test_jiffies; +}; + +static inline int bfin_kpad_find_key(struct bf54x_kpad *bf54x_kpad, + struct input_dev *input, u16 keyident) +{ + u16 i; + + for (i = 0; i < input->keycodemax; i++) + if (bf54x_kpad->keycode[i + input->keycodemax] == keyident) + return bf54x_kpad->keycode[i]; + return -1; +} + +static inline void bfin_keycodecpy(unsigned short *keycode, + const unsigned int *pdata_kc, + unsigned short keymapsize) +{ + unsigned int i; + + for (i = 0; i < keymapsize; i++) { + keycode[i] = pdata_kc[i] & 0xffff; + keycode[i + keymapsize] = pdata_kc[i] >> 16; + } +} + +static inline u16 bfin_kpad_get_prescale(u32 timescale) +{ + u32 sclk = get_sclk(); + + return ((((sclk / 1000) * timescale) / 1024) - 1); +} + +static inline u16 bfin_kpad_get_keypressed(struct bf54x_kpad *bf54x_kpad) +{ + return (bfin_read_KPAD_STAT() & KPAD_PRESSED); +} + +static inline void bfin_kpad_clear_irq(void) +{ + bfin_write_KPAD_STAT(0xFFFF); + bfin_write_KPAD_ROWCOL(0xFFFF); +} + +static void bfin_kpad_timer(unsigned long data) +{ + struct platform_device *pdev = (struct platform_device *) data; + struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev); + + if (bfin_kpad_get_keypressed(bf54x_kpad)) { + /* Try again later */ + mod_timer(&bf54x_kpad->timer, + jiffies + bf54x_kpad->keyup_test_jiffies); + return; + } + + input_report_key(bf54x_kpad->input, bf54x_kpad->lastkey, 0); + input_sync(bf54x_kpad->input); + + /* Clear IRQ Status */ + + bfin_kpad_clear_irq(); + enable_irq(bf54x_kpad->irq); +} + +static irqreturn_t bfin_kpad_isr(int irq, void *dev_id) +{ + struct platform_device *pdev = dev_id; + struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev); + struct input_dev *input = bf54x_kpad->input; + int key; + u16 rowcol = bfin_read_KPAD_ROWCOL(); + + key = bfin_kpad_find_key(bf54x_kpad, input, rowcol); + + input_report_key(input, key, 1); + input_sync(input); + + if (bfin_kpad_get_keypressed(bf54x_kpad)) { + disable_irq(bf54x_kpad->irq); + bf54x_kpad->lastkey = key; + mod_timer(&bf54x_kpad->timer, + jiffies + bf54x_kpad->keyup_test_jiffies); + } else { + input_report_key(input, key, 0); + input_sync(input); + + bfin_kpad_clear_irq(); + } + + return IRQ_HANDLED; +} + +static int __devinit bfin_kpad_probe(struct platform_device *pdev) +{ + struct bf54x_kpad *bf54x_kpad; + struct bfin_kpad_platform_data *pdata = pdev->dev.platform_data; + struct input_dev *input; + int i, error; + + if (!pdata->rows || !pdata->cols || !pdata->keymap) { + printk(KERN_ERR DRV_NAME + ": No rows, cols or keymap from pdata\n"); + return -EINVAL; + } + + if (!pdata->keymapsize || + pdata->keymapsize > (pdata->rows * pdata->cols)) { + printk(KERN_ERR DRV_NAME ": Invalid keymapsize\n"); + return -EINVAL; + } + + bf54x_kpad = kzalloc(sizeof(struct bf54x_kpad), GFP_KERNEL); + if (!bf54x_kpad) + return -ENOMEM; + + platform_set_drvdata(pdev, bf54x_kpad); + + /* Allocate memory for keymap followed by private LUT */ + bf54x_kpad->keycode = kmalloc(pdata->keymapsize * + sizeof(unsigned short) * 2, GFP_KERNEL); + if (!bf54x_kpad->keycode) { + error = -ENOMEM; + goto out; + } + + if (!pdata->debounce_time || !pdata->debounce_time > MAX_MULT || + !pdata->coldrive_time || !pdata->coldrive_time > MAX_MULT) { + printk(KERN_ERR DRV_NAME + ": Invalid Debounce/Columdrive Time from pdata\n"); + bfin_write_KPAD_MSEL(0xFF0); /* Default MSEL */ + } else { + bfin_write_KPAD_MSEL( + ((pdata->debounce_time / TIME_SCALE) + & DBON_SCALE) | + (((pdata->coldrive_time / TIME_SCALE) << 8) + & COLDRV_SCALE)); + + } + + if (!pdata->keyup_test_interval) + bf54x_kpad->keyup_test_jiffies = msecs_to_jiffies(50); + else + bf54x_kpad->keyup_test_jiffies = + msecs_to_jiffies(pdata->keyup_test_interval); + + if (peripheral_request_list((u16 *)&per_rows[MAX_RC - pdata->rows], + DRV_NAME)) { + printk(KERN_ERR DRV_NAME + ": Requesting Peripherals failed\n"); + error = -EFAULT; + goto out0; + } + + if (peripheral_request_list((u16 *)&per_cols[MAX_RC - pdata->cols], + DRV_NAME)) { + printk(KERN_ERR DRV_NAME + ": Requesting Peripherals failed\n"); + error = -EFAULT; + goto out1; + } + + bf54x_kpad->irq = platform_get_irq(pdev, 0); + if (bf54x_kpad->irq < 0) { + error = -ENODEV; + goto out2; + } + + error = request_irq(bf54x_kpad->irq, bfin_kpad_isr, + IRQF_SAMPLE_RANDOM, DRV_NAME, pdev); + if (error) { + printk(KERN_ERR DRV_NAME + ": unable to claim irq %d; error %d\n", + bf54x_kpad->irq, error); + error = -EBUSY; + goto out2; + } + + input = input_allocate_device(); + if (!input) { + error = -ENOMEM; + goto out3; + } + + bf54x_kpad->input = input; + + input->name = pdev->name; + input->phys = "bf54x-keys/input0"; + input->dev.parent = &pdev->dev; + + input_set_drvdata(input, bf54x_kpad); + + input->id.bustype = BUS_HOST; + input->id.vendor = 0x0001; + input->id.product = 0x0001; + input->id.version = 0x0100; + + input->keycodesize = sizeof(unsigned short); + input->keycodemax = pdata->keymapsize; + input->keycode = bf54x_kpad->keycode; + + bfin_keycodecpy(bf54x_kpad->keycode, pdata->keymap, pdata->keymapsize); + + /* setup input device */ + __set_bit(EV_KEY, input->evbit); + + if (pdata->repeat) + __set_bit(EV_REP, input->evbit); + + for (i = 0; i < input->keycodemax; i++) + __set_bit(bf54x_kpad->keycode[i] & KEY_MAX, input->keybit); + __clear_bit(KEY_RESERVED, input->keybit); + + error = input_register_device(input); + if (error) { + printk(KERN_ERR DRV_NAME + ": Unable to register input device (%d)\n", error); + goto out4; + } + + /* Init Keypad Key Up/Release test timer */ + + setup_timer(&bf54x_kpad->timer, bfin_kpad_timer, (unsigned long) pdev); + + bfin_write_KPAD_PRESCALE(bfin_kpad_get_prescale(TIME_SCALE)); + + bfin_write_KPAD_CTL((((pdata->cols - 1) << 13) & KPAD_COLEN) | + (((pdata->rows - 1) << 10) & KPAD_ROWEN) | + (2 & KPAD_IRQMODE)); + + bfin_write_KPAD_CTL(bfin_read_KPAD_CTL() | KPAD_EN); + + printk(KERN_ERR DRV_NAME + ": Blackfin BF54x Keypad registered IRQ %d\n", bf54x_kpad->irq); + + return 0; + +out4: + input_free_device(input); +out3: + free_irq(bf54x_kpad->irq, pdev); +out2: + peripheral_free_list((u16 *)&per_cols[MAX_RC - pdata->cols]); +out1: + peripheral_free_list((u16 *)&per_rows[MAX_RC - pdata->rows]); +out0: + kfree(bf54x_kpad->keycode); +out: + kfree(bf54x_kpad); + platform_set_drvdata(pdev, NULL); + + return error; +} + +static int __devexit bfin_kpad_remove(struct platform_device *pdev) +{ + struct bfin_kpad_platform_data *pdata = pdev->dev.platform_data; + struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev); + + del_timer_sync(&bf54x_kpad->timer); + free_irq(bf54x_kpad->irq, pdev); + + input_unregister_device(bf54x_kpad->input); + + peripheral_free_list((u16 *)&per_rows[MAX_RC - pdata->rows]); + peripheral_free_list((u16 *)&per_cols[MAX_RC - pdata->cols]); + + kfree(bf54x_kpad->keycode); + kfree(bf54x_kpad); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +struct platform_driver bfin_kpad_device_driver = { + .probe = bfin_kpad_probe, + .remove = __devexit_p(bfin_kpad_remove), + .driver = { + .name = DRV_NAME, + } +}; + +static int __init bfin_kpad_init(void) +{ + return platform_driver_register(&bfin_kpad_device_driver); +} + +static void __exit bfin_kpad_exit(void) +{ + platform_driver_unregister(&bfin_kpad_device_driver); +} + +module_init(bfin_kpad_init); +module_exit(bfin_kpad_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); +MODULE_DESCRIPTION("Keypad driver for BF54x Processors"); diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index f0b22b8b2769..e2a3293bc67e 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -54,6 +54,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; struct input_dev *input; int i, error; + int wakeup = 0; input = input_allocate_device(); if (!input) @@ -77,31 +78,51 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) int irq = gpio_to_irq(button->gpio); unsigned int type = button->type ?: EV_KEY; - set_irq_type(irq, IRQ_TYPE_EDGE_BOTH); - error = request_irq(irq, gpio_keys_isr, IRQF_SAMPLE_RANDOM, - button->desc ? button->desc : "gpio_keys", - pdev); + if (irq < 0) { + error = irq; + printk(KERN_ERR + "gpio-keys: " + "Unable to get irq number for GPIO %d," + "error %d\n", + button->gpio, error); + goto fail; + } + + error = request_irq(irq, gpio_keys_isr, + IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING, + button->desc ? button->desc : "gpio_keys", + pdev); if (error) { - printk(KERN_ERR "gpio-keys: unable to claim irq %d; error %d\n", + printk(KERN_ERR + "gpio-keys: Unable to claim irq %d; error %d\n", irq, error); goto fail; } + if (button->wakeup) + wakeup = 1; + input_set_capability(input, type, button->code); } error = input_register_device(input); if (error) { - printk(KERN_ERR "Unable to register gpio-keys input device\n"); + printk(KERN_ERR + "gpio-keys: Unable to register input device, " + "error: %d\n", error); goto fail; } + device_init_wakeup(&pdev->dev, wakeup); + return 0; fail: - for (i = i - 1; i >= 0; i--) + while (--i >= 0) free_irq(gpio_to_irq(pdata->buttons[i].gpio), pdev); + platform_set_drvdata(pdev, NULL); input_free_device(input); return error; @@ -113,6 +134,8 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev) struct input_dev *input = platform_get_drvdata(pdev); int i; + device_init_wakeup(&pdev->dev, 0); + for (i = 0; i < pdata->nbuttons; i++) { int irq = gpio_to_irq(pdata->buttons[i].gpio); free_irq(irq, pdev); @@ -123,9 +146,53 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev) return 0; } + +#ifdef CONFIG_PM +static int gpio_keys_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; + int i; + + if (device_may_wakeup(&pdev->dev)) { + for (i = 0; i < pdata->nbuttons; i++) { + struct gpio_keys_button *button = &pdata->buttons[i]; + if (button->wakeup) { + int irq = gpio_to_irq(button->gpio); + enable_irq_wake(irq); + } + } + } + + return 0; +} + +static int gpio_keys_resume(struct platform_device *pdev) +{ + struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; + int i; + + if (device_may_wakeup(&pdev->dev)) { + for (i = 0; i < pdata->nbuttons; i++) { + struct gpio_keys_button *button = &pdata->buttons[i]; + if (button->wakeup) { + int irq = gpio_to_irq(button->gpio); + disable_irq_wake(irq); + } + } + } + + return 0; +} +#else +#define gpio_keys_suspend NULL +#define gpio_keys_resume NULL +#endif + struct platform_driver gpio_keys_device_driver = { .probe = gpio_keys_probe, .remove = __devexit_p(gpio_keys_remove), + .suspend = gpio_keys_suspend, + .resume = gpio_keys_resume, .driver = { .name = "gpio-keys", } diff --git a/drivers/input/keyboard/jornada680_kbd.c b/drivers/input/keyboard/jornada680_kbd.c new file mode 100644 index 000000000000..bec1cf483723 --- /dev/null +++ b/drivers/input/keyboard/jornada680_kbd.c @@ -0,0 +1,277 @@ +/* + * drivers/input/keyboard/jornada680_kbd.c + * + * HP Jornada 620/660/680/690 scan keyboard platform driver + * Copyright (C) 2007 Kristoffer Ericson <Kristoffer.Ericson@gmail.com> + * + * Based on hp680_keyb.c + * Copyright (C) 2006 Paul Mundt + * Copyright (C) 2005 Andriy Skulysh + * Split from drivers/input/keyboard/hp600_keyb.c + * Copyright (C) 2000 Yaegashi Takeshi (hp6xx kbd scan routine and translation table) + * Copyright (C) 2000 Niibe Yutaka (HP620 Keyb translation table) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/input.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/input-polldev.h> +#include <linux/jiffies.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> + +#include <asm/delay.h> +#include <asm/io.h> + +#define PCCR 0xa4000104 +#define PDCR 0xa4000106 +#define PECR 0xa4000108 +#define PFCR 0xa400010a +#define PCDR 0xa4000124 +#define PDDR 0xa4000126 +#define PEDR 0xa4000128 +#define PFDR 0xa400012a +#define PGDR 0xa400012c +#define PHDR 0xa400012e +#define PJDR 0xa4000130 +#define PKDR 0xa4000132 +#define PLDR 0xa4000134 + +static const unsigned short jornada_scancodes[] = { +/* PTD1 */ KEY_CAPSLOCK, KEY_MACRO, KEY_LEFTCTRL, 0, KEY_ESC, 0, 0, 0, /* 1 -> 8 */ + KEY_F1, KEY_F2, KEY_F3, KEY_F8, KEY_F7, KEY_F2, KEY_F4, KEY_F5, /* 9 -> 16 */ +/* PTD5 */ KEY_SLASH, KEY_APOSTROPHE, KEY_ENTER, 0, KEY_Z, 0, 0, 0, /* 17 -> 24 */ + KEY_X, KEY_C, KEY_V, KEY_DOT, KEY_COMMA, KEY_M, KEY_B, KEY_N, /* 25 -> 32 */ +/* PTD7 */ KEY_KP2, KEY_KP6, 0, 0, 0, 0, 0, 0, /* 33 -> 40 */ + 0, 0, 0, KEY_KP4, 0, 0, KEY_LEFTALT, KEY_HANJA, /* 41 -> 48 */ +/* PTE0 */ 0, 0, 0, 0, KEY_FINANCE, 0, 0, 0, /* 49 -> 56 */ + KEY_LEFTCTRL, 0, KEY_SPACE, KEY_KPDOT, KEY_VOLUMEUP, 249, 0, 0, /* 57 -> 64 */ +/* PTE1 */ KEY_SEMICOLON, KEY_RIGHTBRACE, KEY_BACKSLASH, 0, KEY_A, 0, 0, 0,/* 65 -> 72 */ + KEY_S, KEY_D, KEY_F, KEY_L, KEY_K, KEY_J, KEY_G, KEY_H, /* 73 -> 80 */ +/* PTE3 */ KEY_KP8, KEY_LEFTMETA, KEY_RIGHTSHIFT, 0, KEY_TAB, 0, 0,0, /* 81 -> 88 */ + 0, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 0, /* 89 -> 96 */ +/* PTE6 */ KEY_P, KEY_LEFTBRACE, KEY_BACKSPACE, 0, KEY_Q, 0, 0, 0, /* 97 -> 104 */ + KEY_W, KEY_E, KEY_R, KEY_O, KEY_I, KEY_U, KEY_T, KEY_R, /* 105 -> 112 */ +/* PTE7 */ KEY_0, KEY_MINUS, KEY_EQUAL, 0, KEY_1, 0, 0, 0, /* 113 -> 120 */ + KEY_2, KEY_3, KEY_4, KEY_9, KEY_8, KEY_7, KEY_5, KEY_6, /* 121 -> 128 */ +/* **** */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0 +}; + +#define JORNADA_SCAN_SIZE 18 + +struct jornadakbd { + struct input_polled_dev *poll_dev; + unsigned short keymap[ARRAY_SIZE(jornada_scancodes)]; + unsigned char length; + unsigned char old_scan[JORNADA_SCAN_SIZE]; + unsigned char new_scan[JORNADA_SCAN_SIZE]; +}; + +static void jornada_parse_kbd(struct jornadakbd *jornadakbd) +{ + struct input_dev *input_dev = jornadakbd->poll_dev->input; + unsigned short *keymap = jornadakbd->keymap; + unsigned int sync_me = 0; + unsigned int i, j; + + for (i = 0; i < JORNADA_SCAN_SIZE; i++) { + unsigned char new = jornadakbd->new_scan[i]; + unsigned char old = jornadakbd->old_scan[i]; + unsigned int xor = new ^ old; + + if (xor == 0) + continue; + + for (j = 0; j < 8; j++) { + unsigned int bit = 1 << j; + if (xor & bit) { + unsigned int scancode = (i << 3) + j; + input_event(input_dev, + EV_MSC, MSC_SCAN, scancode); + input_report_key(input_dev, + keymap[scancode], + !(new & bit)); + sync_me = 1; + } + } + } + + if (sync_me) + input_sync(input_dev); +} + +static void jornada_scan_keyb(unsigned char *s) +{ + int i; + unsigned short ec_static, dc_static; /* = UINT16_t */ + unsigned char matrix_switch[] = { + 0xfd, 0xff, /* PTD1 PD(1) */ + 0xdf, 0xff, /* PTD5 PD(5) */ + 0x7f, 0xff, /* PTD7 PD(7) */ + 0xff, 0xfe, /* PTE0 PE(0) */ + 0xff, 0xfd, /* PTE1 PE(1) */ + 0xff, 0xf7, /* PTE3 PE(3) */ + 0xff, 0xbf, /* PTE6 PE(6) */ + 0xff, 0x7f, /* PTE7 PE(7) */ + }, *t = matrix_switch; + /* PD(x) : + 1. 0xcc0c & (1~(1 << (2*(x)+1))))) + 2. (0xf0cf & 0xfffff) */ + /* PE(x) : + 1. 0xcc0c & 0xffff + 2. 0xf0cf & (1~(1 << (2*(x)+1))))) */ + unsigned short matrix_PDE[] = { + 0xcc04, 0xf0cf, /* PD(1) */ + 0xc40c, 0xf0cf, /* PD(5) */ + 0x4c0c, 0xf0cf, /* PD(7) */ + 0xcc0c, 0xf0cd, /* PE(0) */ + 0xcc0c, 0xf0c7, /* PE(1) */ + 0xcc0c, 0xf04f, /* PE(3) */ + 0xcc0c, 0xd0cf, /* PE(6) */ + 0xcc0c, 0x70cf, /* PE(7) */ + }, *y = matrix_PDE; + + /* Save these control reg bits */ + dc_static = (ctrl_inw(PDCR) & (~0xcc0c)); + ec_static = (ctrl_inw(PECR) & (~0xf0cf)); + + for (i = 0; i < 8; i++) { + /* disable output for all but the one we want to scan */ + ctrl_outw((dc_static | *y++), PDCR); + ctrl_outw((ec_static | *y++), PECR); + udelay(5); + + /* Get scanline row */ + ctrl_outb(*t++, PDDR); + ctrl_outb(*t++, PEDR); + udelay(50); + + /* Read data */ + *s++ = ctrl_inb(PCDR); + *s++ = ctrl_inb(PFDR); + } + /* Scan no lines */ + ctrl_outb(0xff, PDDR); + ctrl_outb(0xff, PEDR); + + /* Enable all scanlines */ + ctrl_outw((dc_static | (0x5555 & 0xcc0c)),PDCR); + ctrl_outw((ec_static | (0x5555 & 0xf0cf)),PECR); + + /* Ignore extra keys and events */ + *s++ = ctrl_inb(PGDR); + *s++ = ctrl_inb(PHDR); +} + +static void jornadakbd680_poll(struct input_polled_dev *dev) +{ + struct jornadakbd *jornadakbd = dev->private; + + jornada_scan_keyb(jornadakbd->new_scan); + jornada_parse_kbd(jornadakbd); + memcpy(jornadakbd->old_scan, jornadakbd->new_scan, JORNADA_SCAN_SIZE); +} + +static int __devinit jornada680kbd_probe(struct platform_device *pdev) +{ + struct jornadakbd *jornadakbd; + struct input_polled_dev *poll_dev; + struct input_dev *input_dev; + int i, error; + + jornadakbd = kzalloc(sizeof(struct jornadakbd), GFP_KERNEL); + if (!jornadakbd) + return -ENOMEM; + + poll_dev = input_allocate_polled_device(); + if (!poll_dev) { + error = -ENOMEM; + goto failed; + } + + platform_set_drvdata(pdev, jornadakbd); + + jornadakbd->poll_dev = poll_dev; + + memcpy(jornadakbd->keymap, jornada_scancodes, + sizeof(jornadakbd->keymap)); + + poll_dev->private = jornadakbd; + poll_dev->poll = jornadakbd680_poll; + poll_dev->poll_interval = 50; /* msec */ + + input_dev = poll_dev->input; + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + input_dev->name = "HP Jornada 680 keyboard"; + input_dev->phys = "jornadakbd/input0"; + input_dev->keycode = jornadakbd->keymap; + input_dev->keycodesize = sizeof(unsigned short); + input_dev->keycodemax = ARRAY_SIZE(jornada_scancodes); + input_dev->dev.parent = &pdev->dev; + input_dev->id.bustype = BUS_HOST; + + for (i = 0; i < 128; i++) + if (jornadakbd->keymap[i]) + __set_bit(jornadakbd->keymap[i], input_dev->keybit); + __clear_bit(KEY_RESERVED, input_dev->keybit); + + input_set_capability(input_dev, EV_MSC, MSC_SCAN); + + error = input_register_polled_device(jornadakbd->poll_dev); + if (error) + goto failed; + + return 0; + + failed: + printk(KERN_ERR "Jornadakbd: failed to register driver, error: %d\n", + error); + platform_set_drvdata(pdev, NULL); + input_free_polled_device(poll_dev); + kfree(jornadakbd); + return error; + +} + +static int __devexit jornada680kbd_remove(struct platform_device *pdev) +{ + struct jornadakbd *jornadakbd = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + input_unregister_polled_device(jornadakbd->poll_dev); + input_free_polled_device(jornadakbd->poll_dev); + kfree(jornadakbd); + + return 0; +} + +static struct platform_driver jornada680kbd_driver = { + .driver = { + .name = "jornada680_kbd", + }, + .probe = jornada680kbd_probe, + .remove = __devexit_p(jornada680kbd_remove), +}; + +static int __init jornada680kbd_init(void) +{ + return platform_driver_register(&jornada680kbd_driver); +} + +static void __exit jornada680kbd_exit(void) +{ + platform_driver_unregister(&jornada680kbd_driver); +} + +module_init(jornada680kbd_init); +module_exit(jornada680kbd_exit); + +MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>"); +MODULE_DESCRIPTION("HP Jornada 620/660/680/690 Keyboard Driver"); +MODULE_LICENSE("GPLv2"); diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c new file mode 100644 index 000000000000..e6696b3c9416 --- /dev/null +++ b/drivers/input/keyboard/jornada720_kbd.c @@ -0,0 +1,185 @@ +/* + * drivers/input/keyboard/jornada720_kbd.c + * + * HP Jornada 720 keyboard platform driver + * + * Copyright (C) 2006/2007 Kristoffer Ericson <Kristoffer.Ericson@Gmail.com> + * + * Copyright (C) 2006 jornada 720 kbd driver by + Filip Zyzniewsk <Filip.Zyzniewski@tefnet.plX + * based on (C) 2004 jornada 720 kbd driver by + Alex Lange <chicken@handhelds.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#include <asm/arch/jornada720.h> +#include <asm/hardware.h> + +MODULE_AUTHOR("Kristoffer Ericson <Kristoffer.Ericson@gmail.com>"); +MODULE_DESCRIPTION("HP Jornada 710/720/728 keyboard driver"); +MODULE_LICENSE("GPLv2"); + +static unsigned short jornada_std_keymap[128] = { /* ROW */ + 0, KEY_ESC, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, /* #1 */ + KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_MUTE, /* -> */ + 0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, /* #2 */ + KEY_0, KEY_MINUS, KEY_EQUAL,0, 0, 0, /* -> */ + 0, KEY_Q, KEY_W, KEY_E, KEY_R, KEY_T, KEY_Y, KEY_U, KEY_I, KEY_O, /* #3 */ + KEY_P, KEY_BACKSLASH, KEY_BACKSPACE, 0, 0, 0, /* -> */ + 0, KEY_A, KEY_S, KEY_D, KEY_F, KEY_G, KEY_H, KEY_J, KEY_K, KEY_L, /* #4 */ + KEY_SEMICOLON, KEY_LEFTBRACE, KEY_RIGHTBRACE, 0, 0, 0, /* -> */ + 0, KEY_Z, KEY_X, KEY_C, KEY_V, KEY_B, KEY_N, KEY_M, KEY_COMMA, /* #5 */ + KEY_DOT, KEY_KPMINUS, KEY_APOSTROPHE, KEY_ENTER, 0, 0,0, /* -> */ + 0, KEY_TAB, 0, KEY_LEFTSHIFT, 0, KEY_APOSTROPHE, 0, 0, 0, 0, /* #6 */ + KEY_UP, 0, KEY_RIGHTSHIFT, 0, 0, 0,0, 0, 0, 0, 0, KEY_LEFTALT, KEY_GRAVE, /* -> */ + 0, 0, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0,0, KEY_KPASTERISK, /* -> */ + KEY_LEFTCTRL, 0, KEY_SPACE, 0, 0, 0, KEY_SLASH, KEY_DELETE, 0, 0, /* -> */ + 0, 0, 0, KEY_POWER, /* -> */ +}; + +struct jornadakbd { + unsigned short keymap[ARRAY_SIZE(jornada_std_keymap)]; + struct input_dev *input; +}; + +static irqreturn_t jornada720_kbd_interrupt(int irq, void *dev_id) +{ + struct platform_device *pdev = dev_id; + struct jornadakbd *jornadakbd = platform_get_drvdata(pdev); + struct input_dev *input = jornadakbd->input; + u8 count, kbd_data, scan_code; + + /* startup ssp with spinlock */ + jornada_ssp_start(); + + if (jornada_ssp_inout(GETSCANKEYCODE) != TXDUMMY) { + printk(KERN_DEBUG + "jornada720_kbd: " + "GetKeycode command failed with ETIMEDOUT, " + "flushed bus\n"); + } else { + /* How many keycodes are waiting for us? */ + count = jornada_ssp_byte(TXDUMMY); + + /* Lets drag them out one at a time */ + while (count--) { + /* Exchange TxDummy for location (keymap[kbddata]) */ + kbd_data = jornada_ssp_byte(TXDUMMY); + scan_code = kbd_data & 0x7f; + + input_event(input, EV_MSC, MSC_SCAN, scan_code); + input_report_key(input, jornadakbd->keymap[scan_code], + !(kbd_data & 0x80)); + input_sync(input); + } + } + + /* release spinlock and turn off ssp */ + jornada_ssp_end(); + + return IRQ_HANDLED; +}; + +static int __devinit jornada720_kbd_probe(struct platform_device *pdev) +{ + struct jornadakbd *jornadakbd; + struct input_dev *input_dev; + int i, err; + + jornadakbd = kzalloc(sizeof(struct jornadakbd), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!jornadakbd || !input_dev) { + err = -ENOMEM; + goto fail1; + } + + platform_set_drvdata(pdev, jornadakbd); + + memcpy(jornadakbd->keymap, jornada_std_keymap, + sizeof(jornada_std_keymap)); + jornadakbd->input = input_dev; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + input_dev->name = "HP Jornada 720 keyboard"; + input_dev->phys = "jornadakbd/input0"; + input_dev->keycode = jornadakbd->keymap; + input_dev->keycodesize = sizeof(unsigned short); + input_dev->keycodemax = ARRAY_SIZE(jornada_std_keymap); + input_dev->id.bustype = BUS_HOST; + input_dev->dev.parent = &pdev->dev; + + for (i = 0; i < ARRAY_SIZE(jornadakbd->keymap); i++) + __set_bit(jornadakbd->keymap[i], input_dev->keybit); + __clear_bit(KEY_RESERVED, input_dev->keybit); + + input_set_capability(input_dev, EV_MSC, MSC_SCAN); + + err = request_irq(IRQ_GPIO0, + jornada720_kbd_interrupt, + IRQF_DISABLED | IRQF_TRIGGER_FALLING, + "jornadakbd", pdev); + if (err) { + printk(KERN_INFO "jornadakbd720_kbd: Unable to grab IRQ\n"); + goto fail1; + } + + err = input_register_device(jornadakbd->input); + if (err) + goto fail2; + + return 0; + + fail2: /* IRQ, DEVICE, MEMORY */ + free_irq(IRQ_GPIO0, pdev); + fail1: /* DEVICE, MEMORY */ + platform_set_drvdata(pdev, NULL); + input_free_device(input_dev); + kfree(jornadakbd); + return err; +}; + +static int __devexit jornada720_kbd_remove(struct platform_device *pdev) +{ + struct jornadakbd *jornadakbd = platform_get_drvdata(pdev); + + free_irq(IRQ_GPIO0, pdev); + platform_set_drvdata(pdev, NULL); + input_unregister_device(jornadakbd->input); + kfree(jornadakbd); + + return 0; +} + +static struct platform_driver jornada720_kbd_driver = { + .driver = { + .name = "jornada720_kbd", + }, + .probe = jornada720_kbd_probe, + .remove = __devexit_p(jornada720_kbd_remove), +}; + +static int __init jornada720_kbd_init(void) +{ + return platform_driver_register(&jornada720_kbd_driver); +} + +static void __exit jornada720_kbd_exit(void) +{ + platform_driver_unregister(&jornada720_kbd_driver); +} + +module_init(jornada720_kbd_init); +module_exit(jornada720_kbd_exit); diff --git a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c new file mode 100644 index 000000000000..2b404284c28a --- /dev/null +++ b/drivers/input/keyboard/maple_keyb.c @@ -0,0 +1,252 @@ +/* + * SEGA Dreamcast keyboard driver + * Based on drivers/usb/usbkbd.c + * Copyright YAEGASHI Takeshi, 2001 + * Porting to 2.6 Copyright Adrian McMenamin, 2007 + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/input.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/timer.h> +#include <linux/maple.h> +#include <asm/mach/maple.h> + +/* Very simple mutex to ensure proper cleanup */ +static DEFINE_MUTEX(maple_keyb_mutex); + +#define NR_SCANCODES 256 + +MODULE_AUTHOR("YAEGASHI Takeshi, Adrian McMenamin"); +MODULE_DESCRIPTION("SEGA Dreamcast keyboard driver"); +MODULE_LICENSE("GPL"); + +struct dc_kbd { + struct input_dev *dev; + unsigned short keycode[NR_SCANCODES]; + unsigned char new[8]; + unsigned char old[8]; +}; + +static const unsigned short dc_kbd_keycode[NR_SCANCODES] = { + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_A, KEY_B, KEY_C, KEY_D, + KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, + KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, + KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z, KEY_1, KEY_2, + KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0, + KEY_ENTER, KEY_ESC, KEY_BACKSPACE, KEY_TAB, KEY_SPACE, KEY_MINUS, KEY_EQUAL, KEY_LEFTBRACE, + KEY_RIGHTBRACE, KEY_BACKSLASH, KEY_BACKSLASH, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_GRAVE, KEY_COMMA, + KEY_DOT, KEY_SLASH, KEY_CAPSLOCK, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, + KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, KEY_SYSRQ, + KEY_SCROLLLOCK, KEY_PAUSE, KEY_INSERT, KEY_HOME, KEY_PAGEUP, KEY_DELETE, + KEY_END, KEY_PAGEDOWN, KEY_RIGHT, KEY_LEFT, KEY_DOWN, KEY_UP, + KEY_NUMLOCK, KEY_KPSLASH, KEY_KPASTERISK, KEY_KPMINUS, KEY_KPPLUS, KEY_KPENTER, KEY_KP1, KEY_KP2, + KEY_KP3, KEY_KP4, KEY_KP5, KEY_KP6, KEY_KP7, KEY_KP8, KEY_KP9, KEY_KP0, KEY_KPDOT, + KEY_102ND, KEY_COMPOSE, KEY_POWER, KEY_KPEQUAL, KEY_F13, KEY_F14, KEY_F15, + KEY_F16, KEY_F17, KEY_F18, KEY_F19, KEY_F20, + KEY_F21, KEY_F22, KEY_F23, KEY_F24, KEY_OPEN, KEY_HELP, KEY_PROPS, KEY_FRONT, + KEY_STOP, KEY_AGAIN, KEY_UNDO, KEY_CUT, KEY_COPY, KEY_PASTE, KEY_FIND, KEY_MUTE, + KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_KPCOMMA, KEY_RESERVED, KEY_RO, KEY_KATAKANAHIRAGANA , KEY_YEN, + KEY_HENKAN, KEY_MUHENKAN, KEY_KPJPCOMMA, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_HANGEUL, KEY_HANJA, KEY_KATAKANA, KEY_HIRAGANA, KEY_ZENKAKUHANKAKU, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_LEFTCTRL, KEY_LEFTSHIFT, KEY_LEFTALT, KEY_LEFTMETA, KEY_RIGHTCTRL, KEY_RIGHTSHIFT, KEY_RIGHTALT, KEY_RIGHTMETA, + KEY_PLAYPAUSE, KEY_STOPCD, KEY_PREVIOUSSONG, KEY_NEXTSONG, KEY_EJECTCD, KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_MUTE, + KEY_WWW, KEY_BACK, KEY_FORWARD, KEY_STOP, KEY_FIND, KEY_SCROLLUP, KEY_SCROLLDOWN, KEY_EDIT, KEY_SLEEP, + KEY_SCREENLOCK, KEY_REFRESH, KEY_CALC, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED +}; + +static void dc_scan_kbd(struct dc_kbd *kbd) +{ + struct input_dev *dev = kbd->dev; + void *ptr; + int code, keycode; + int i; + + for (i = 0; i < 8; i++) { + code = i + 224; + keycode = kbd->keycode[code]; + input_event(dev, EV_MSC, MSC_SCAN, code); + input_report_key(dev, keycode, (kbd->new[0] >> i) & 1); + } + + for (i = 2; i < 8; i++) { + ptr = memchr(kbd->new + 2, kbd->old[i], 6); + code = kbd->old[i]; + if (code > 3 && ptr == NULL) { + keycode = kbd->keycode[code]; + if (keycode) { + input_event(dev, EV_MSC, MSC_SCAN, code); + input_report_key(dev, keycode, 0); + } else + printk(KERN_DEBUG "maple_keyb: " + "Unknown key (scancode %#x) released.", + code); + } + ptr = memchr(kbd->old + 2, kbd->new[i], 6); + code = kbd->new[i]; + if (code > 3 && ptr) { + keycode = kbd->keycode[code]; + if (keycode) { + input_event(dev, EV_MSC, MSC_SCAN, code); + input_report_key(dev, keycode, 1); + } else + printk(KERN_DEBUG "maple_keyb: " + "Unknown key (scancode %#x) pressed.", + code); + } + } + input_sync(dev); + memcpy(kbd->old, kbd->new, 8); +} + +static void dc_kbd_callback(struct mapleq *mq) +{ + struct maple_device *mapledev = mq->dev; + struct dc_kbd *kbd = mapledev->private_data; + unsigned long *buf = mq->recvbuf; + + /* + * We should always be getting the lock because the only + * time it may be locked if driver is in cleanup phase. + */ + if (likely(mutex_trylock(&maple_keyb_mutex))) { + + if (buf[1] == mapledev->function) { + memcpy(kbd->new, buf + 2, 8); + dc_scan_kbd(kbd); + } + + mutex_unlock(&maple_keyb_mutex); + } +} + +static int dc_kbd_connect(struct maple_device *mdev) +{ + int i, error; + struct dc_kbd *kbd; + struct input_dev *dev; + + if (!(mdev->function & MAPLE_FUNC_KEYBOARD)) + return -EINVAL; + + kbd = kzalloc(sizeof(struct dc_kbd), GFP_KERNEL); + dev = input_allocate_device(); + if (!kbd || !dev) { + error = -ENOMEM; + goto fail; + } + + mdev->private_data = kbd; + + kbd->dev = dev; + memcpy(kbd->keycode, dc_kbd_keycode, sizeof(kbd->keycode)); + + dev->name = mdev->product_name; + dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + dev->keycode = kbd->keycode; + dev->keycodesize = sizeof (unsigned short); + dev->keycodemax = ARRAY_SIZE(kbd->keycode); + dev->id.bustype = BUS_HOST; + dev->dev.parent = &mdev->dev; + + for (i = 0; i < NR_SCANCODES; i++) + __set_bit(dc_kbd_keycode[i], dev->keybit); + __clear_bit(KEY_RESERVED, dev->keybit); + + input_set_capability(dev, EV_MSC, MSC_SCAN); + input_set_drvdata(dev, kbd); + + error = input_register_device(dev); + if (error) + goto fail; + + /* Maple polling is locked to VBLANK - which may be just 50/s */ + maple_getcond_callback(mdev, dc_kbd_callback, HZ/50, MAPLE_FUNC_KEYBOARD); + return 0; + + fail: + input_free_device(dev); + kfree(kbd); + mdev->private_data = NULL; + return error; +} + +static void dc_kbd_disconnect(struct maple_device *mdev) +{ + struct dc_kbd *kbd; + + mutex_lock(&maple_keyb_mutex); + + kbd = mdev->private_data; + mdev->private_data = NULL; + input_unregister_device(kbd->dev); + kfree(kbd); + + mutex_unlock(&maple_keyb_mutex); +} + +/* allow the keyboard to be used */ +static int probe_maple_kbd(struct device *dev) +{ + struct maple_device *mdev = to_maple_dev(dev); + struct maple_driver *mdrv = to_maple_driver(dev->driver); + int error; + + error = dc_kbd_connect(mdev); + if (error) + return error; + + mdev->driver = mdrv; + mdev->registered = 1; + + return 0; +} + +static struct maple_driver dc_kbd_driver = { + .function = MAPLE_FUNC_KEYBOARD, + .connect = dc_kbd_connect, + .disconnect = dc_kbd_disconnect, + .drv = { + .name = "Dreamcast_keyboard", + .probe = probe_maple_kbd, + }, +}; + +static int __init dc_kbd_init(void) +{ + return maple_driver_register(&dc_kbd_driver.drv); +} + +static void __exit dc_kbd_exit(void) +{ + driver_unregister(&dc_kbd_driver.drv); +} + +module_init(dc_kbd_init); +module_exit(dc_kbd_exit); diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c index 3a228634f101..76f1969552c5 100644 --- a/drivers/input/keyboard/omap-keypad.c +++ b/drivers/input/keyboard/omap-keypad.c @@ -233,7 +233,7 @@ static void omap_kp_tasklet(unsigned long data) omap_writew(0, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); kp_cur_group = -1; } - } + } } static ssize_t omap_kp_enable_show(struct device *dev, @@ -318,7 +318,7 @@ static int __init omap_kp_probe(struct platform_device *pdev) keymap = pdata->keymap; if (pdata->rep) - set_bit(EV_REP, input_dev->evbit); + __set_bit(EV_REP, input_dev->evbit); if (pdata->delay) omap_kp->delay = pdata->delay; @@ -365,9 +365,9 @@ static int __init omap_kp_probe(struct platform_device *pdev) goto err2; /* setup input device */ - set_bit(EV_KEY, input_dev->evbit); + __set_bit(EV_KEY, input_dev->evbit); for (i = 0; keymap[i] != 0; i++) - set_bit(keymap[i] & KEY_MAX, input_dev->keybit); + __set_bit(keymap[i] & KEY_MAX, input_dev->keybit); input_dev->name = "omap-keypad"; input_dev->phys = "omap-keypad/input0"; input_dev->dev.parent = &pdev->dev; @@ -377,10 +377,6 @@ static int __init omap_kp_probe(struct platform_device *pdev) input_dev->id.product = 0x0001; input_dev->id.version = 0x0100; - input_dev->keycode = keymap; - input_dev->keycodesize = sizeof(unsigned int); - input_dev->keycodemax = pdata->keymapsize; - ret = input_register_device(omap_kp->input); if (ret < 0) { printk(KERN_ERR "Unable to register omap-keypad input device\n"); @@ -403,15 +399,15 @@ static int __init omap_kp_probe(struct platform_device *pdev) } else { for (irq_idx = 0; irq_idx < omap_kp->rows; irq_idx++) { if (request_irq(OMAP_GPIO_IRQ(row_gpios[irq_idx]), - omap_kp_interrupt, + omap_kp_interrupt, IRQF_TRIGGER_FALLING, - "omap-keypad", omap_kp) < 0) + "omap-keypad", omap_kp) < 0) goto err5; } } return 0; err5: - for (i = irq_idx-1; i >=0; i--) + for (i = irq_idx - 1; i >=0; i--) free_irq(row_gpios[i], 0); err4: input_unregister_device(omap_kp->input); @@ -440,9 +436,9 @@ static int omap_kp_remove(struct platform_device *pdev) if (cpu_is_omap24xx()) { int i; for (i = 0; i < omap_kp->cols; i++) - omap_free_gpio(col_gpios[i]); + omap_free_gpio(col_gpios[i]); for (i = 0; i < omap_kp->rows; i++) { - omap_free_gpio(row_gpios[i]); + omap_free_gpio(row_gpios[i]); free_irq(OMAP_GPIO_IRQ(row_gpios[i]), 0); } } else { diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c index 906bf5e8de89..c19f77fbaf2a 100644 --- a/drivers/input/misc/pcspkr.c +++ b/drivers/input/misc/pcspkr.c @@ -17,17 +17,18 @@ #include <linux/init.h> #include <linux/input.h> #include <linux/platform_device.h> -#include <asm/8253pit.h> #include <asm/io.h> MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); MODULE_DESCRIPTION("PC Speaker beeper driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pcspkr"); #ifdef CONFIG_X86 /* Use the global PIT lock ! */ #include <asm/i8253.h> #else +#include <asm/8253pit.h> static DEFINE_SPINLOCK(i8253_lock); #endif diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 2c5f11a4f6b4..64d70a9b714c 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -48,11 +48,13 @@ static const struct alps_model_info alps_model_data[] = { { { 0x63, 0x02, 0x50 }, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */ { { 0x63, 0x02, 0x64 }, 0xf8, 0xf8, 0 }, { { 0x63, 0x03, 0xc8 }, 0xf8, 0xf8, ALPS_PASS }, /* Dell Latitude D800 */ + { { 0x73, 0x00, 0x0a }, 0xf8, 0xf8, ALPS_DUALPOINT }, /* ThinkPad R61 8918-5QG */ { { 0x73, 0x02, 0x0a }, 0xf8, 0xf8, 0 }, { { 0x73, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */ { { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */ { { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, { { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */ + { { 0x73, 0x02, 0x50 }, 0xcf, 0xff, ALPS_FW_BK_1 } /* Dell Vostro 1400 */ }; /* diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c index a1804bfdbb8c..0117817bf538 100644 --- a/drivers/input/mouse/appletouch.c +++ b/drivers/input/mouse/appletouch.c @@ -502,18 +502,23 @@ static void atp_complete(struct urb* urb) /* reset the accumulator on release */ memset(dev->xy_acc, 0, sizeof(dev->xy_acc)); + } + + /* Geyser 3 will continue to send packets continually after + the first touch unless reinitialised. Do so if it's been + idle for a while in order to avoid waking the kernel up + several hundred times a second */ - /* Geyser 3 will continue to send packets continually after - the first touch unless reinitialised. Do so if it's been - idle for a while in order to avoid waking the kernel up - several hundred times a second */ - if (!key && atp_is_geyser_3(dev)) { + if (atp_is_geyser_3(dev)) { + if (!x && !y && !key) { dev->idlecount++; if (dev->idlecount == 10) { dev->valid = 0; schedule_work(&dev->work); } } + else + dev->idlecount = 0; } input_report_key(dev->input, BTN_LEFT, key); diff --git a/drivers/input/mouse/atarimouse.c b/drivers/input/mouse/atarimouse.c index 43ab6566fb65..c8c7244b48a1 100644 --- a/drivers/input/mouse/atarimouse.c +++ b/drivers/input/mouse/atarimouse.c @@ -73,14 +73,11 @@ static void atamouse_interrupt(char *buf) { int buttons, dx, dy; -/* ikbd_mouse_disable(); */ - buttons = (buf[0] & 1) | ((buf[0] & 2) << 1); #ifdef FIXED_ATARI_JOYSTICK buttons |= atari_mouse_buttons & 2; atari_mouse_buttons = buttons; #endif -/* ikbd_mouse_rel_pos(); */ /* only relative events get here */ dx = buf[1]; @@ -126,15 +123,16 @@ static int __init atamouse_init(void) if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ST_MFP)) return -ENODEV; - if (!(atamouse_dev = input_allocate_device())) - return -ENOMEM; - if (!(atari_keyb_init())) return -ENODEV; + atamouse_dev = input_allocate_device(); + if (!atamouse_dev) + return -ENOMEM; + atamouse_dev->name = "Atari mouse"; atamouse_dev->phys = "atamouse/input0"; - atamouse_dev->id.bustype = BUS_ATARI; + atamouse_dev->id.bustype = BUS_HOST; atamouse_dev->id.vendor = 0x0001; atamouse_dev->id.product = 0x0002; atamouse_dev->id.version = 0x0100; @@ -145,9 +143,11 @@ static int __init atamouse_init(void) atamouse_dev->open = atamouse_open; atamouse_dev->close = atamouse_close; - input_register_device(atamouse_dev); + if (input_register_device(atamouse_dev)) { + input_free_device(atamouse_dev); + return -ENOMEM; + } - printk(KERN_INFO "input: %s at keyboard ACIA\n", atamouse_dev->name); return 0; } diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c index 608674d0be8b..d7de4c53b3d8 100644 --- a/drivers/input/mouse/lifebook.c +++ b/drivers/input/mouse/lifebook.c @@ -97,6 +97,14 @@ static const struct dmi_system_id lifebook_dmi_table[] = { .callback = lifebook_set_6byte_proto, }, { + .ident = "CF-72", + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "CF-72"), + }, + .callback = lifebook_set_serio_phys, + .driver_data = "isa0060/serio3", + }, + { .ident = "Lifebook B142", .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B142"), @@ -282,7 +290,7 @@ static int lifebook_create_relative_device(struct psmouse *psmouse) int lifebook_init(struct psmouse *psmouse) { struct input_dev *dev1 = psmouse->dev; - int max_coord = lifebook_use_6byte_proto ? 1024 : 4096; + int max_coord = lifebook_use_6byte_proto ? 4096 : 1024; if (lifebook_absolute_mode(psmouse)) return -1; diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index b9f0fb2530e2..073525756532 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -648,9 +648,10 @@ static int psmouse_extensions(struct psmouse *psmouse, /* * Reset to defaults in case the device got confused by extended - * protocol probes. Note that we do full reset becuase some mice - * put themselves to sleep when see PSMOUSE_RESET_DIS. + * protocol probes. Note that we follow up with full reset because + * some mice put themselves to sleep when they see PSMOUSE_RESET_DIS. */ + ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); psmouse_reset(psmouse); if (max_proto >= PSMOUSE_IMEX && im_explorer_detect(psmouse, set_properties) == 0) diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 9173916b8be5..79146d6ed2ab 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -61,9 +61,11 @@ struct mousedev { int open; int minor; char name[16]; + struct input_handle handle; wait_queue_head_t wait; struct list_head client_list; - struct input_handle handle; + spinlock_t client_lock; /* protects client_list */ + struct mutex mutex; struct device dev; struct list_head mixdev_node; @@ -113,108 +115,137 @@ static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 }; static struct input_handler mousedev_handler; static struct mousedev *mousedev_table[MOUSEDEV_MINORS]; +static DEFINE_MUTEX(mousedev_table_mutex); static struct mousedev *mousedev_mix; static LIST_HEAD(mousedev_mix_list); +static void mixdev_open_devices(void); +static void mixdev_close_devices(void); + #define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03]) #define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03]) -static void mousedev_touchpad_event(struct input_dev *dev, struct mousedev *mousedev, unsigned int code, int value) +static void mousedev_touchpad_event(struct input_dev *dev, + struct mousedev *mousedev, + unsigned int code, int value) { int size, tmp; enum { FRACTION_DENOM = 128 }; switch (code) { - case ABS_X: - fx(0) = value; - if (mousedev->touch && mousedev->pkt_count >= 2) { - size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; - if (size == 0) - size = 256 * 2; - tmp = ((value - fx(2)) * (256 * FRACTION_DENOM)) / size; - tmp += mousedev->frac_dx; - mousedev->packet.dx = tmp / FRACTION_DENOM; - mousedev->frac_dx = tmp - mousedev->packet.dx * FRACTION_DENOM; - } - break; - case ABS_Y: - fy(0) = value; - if (mousedev->touch && mousedev->pkt_count >= 2) { - /* use X size to keep the same scale */ - size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; - if (size == 0) - size = 256 * 2; - tmp = -((value - fy(2)) * (256 * FRACTION_DENOM)) / size; - tmp += mousedev->frac_dy; - mousedev->packet.dy = tmp / FRACTION_DENOM; - mousedev->frac_dy = tmp - mousedev->packet.dy * FRACTION_DENOM; - } - break; + case ABS_X: + fx(0) = value; + if (mousedev->touch && mousedev->pkt_count >= 2) { + size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; + if (size == 0) + size = 256 * 2; + tmp = ((value - fx(2)) * 256 * FRACTION_DENOM) / size; + tmp += mousedev->frac_dx; + mousedev->packet.dx = tmp / FRACTION_DENOM; + mousedev->frac_dx = + tmp - mousedev->packet.dx * FRACTION_DENOM; + } + break; + + case ABS_Y: + fy(0) = value; + if (mousedev->touch && mousedev->pkt_count >= 2) { + /* use X size to keep the same scale */ + size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; + if (size == 0) + size = 256 * 2; + tmp = -((value - fy(2)) * 256 * FRACTION_DENOM) / size; + tmp += mousedev->frac_dy; + mousedev->packet.dy = tmp / FRACTION_DENOM; + mousedev->frac_dy = tmp - + mousedev->packet.dy * FRACTION_DENOM; + } + break; } } -static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, unsigned int code, int value) +static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, + unsigned int code, int value) { int size; switch (code) { - case ABS_X: - size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; - if (size == 0) - size = xres ? : 1; - if (value > dev->absmax[ABS_X]) - value = dev->absmax[ABS_X]; - if (value < dev->absmin[ABS_X]) - value = dev->absmin[ABS_X]; - mousedev->packet.x = ((value - dev->absmin[ABS_X]) * xres) / size; - mousedev->packet.abs_event = 1; - break; - case ABS_Y: - size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y]; - if (size == 0) - size = yres ? : 1; - if (value > dev->absmax[ABS_Y]) - value = dev->absmax[ABS_Y]; - if (value < dev->absmin[ABS_Y]) - value = dev->absmin[ABS_Y]; - mousedev->packet.y = yres - ((value - dev->absmin[ABS_Y]) * yres) / size; - mousedev->packet.abs_event = 1; - break; + case ABS_X: + size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; + if (size == 0) + size = xres ? : 1; + if (value > dev->absmax[ABS_X]) + value = dev->absmax[ABS_X]; + if (value < dev->absmin[ABS_X]) + value = dev->absmin[ABS_X]; + mousedev->packet.x = + ((value - dev->absmin[ABS_X]) * xres) / size; + mousedev->packet.abs_event = 1; + break; + + case ABS_Y: + size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y]; + if (size == 0) + size = yres ? : 1; + if (value > dev->absmax[ABS_Y]) + value = dev->absmax[ABS_Y]; + if (value < dev->absmin[ABS_Y]) + value = dev->absmin[ABS_Y]; + mousedev->packet.y = yres - + ((value - dev->absmin[ABS_Y]) * yres) / size; + mousedev->packet.abs_event = 1; + break; } } -static void mousedev_rel_event(struct mousedev *mousedev, unsigned int code, int value) +static void mousedev_rel_event(struct mousedev *mousedev, + unsigned int code, int value) { switch (code) { - case REL_X: mousedev->packet.dx += value; break; - case REL_Y: mousedev->packet.dy -= value; break; - case REL_WHEEL: mousedev->packet.dz -= value; break; + case REL_X: + mousedev->packet.dx += value; + break; + + case REL_Y: + mousedev->packet.dy -= value; + break; + + case REL_WHEEL: + mousedev->packet.dz -= value; + break; } } -static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int value) +static void mousedev_key_event(struct mousedev *mousedev, + unsigned int code, int value) { int index; switch (code) { - case BTN_TOUCH: - case BTN_0: - case BTN_LEFT: index = 0; break; - case BTN_STYLUS: - case BTN_1: - case BTN_RIGHT: index = 1; break; - case BTN_2: - case BTN_FORWARD: - case BTN_STYLUS2: - case BTN_MIDDLE: index = 2; break; - case BTN_3: - case BTN_BACK: - case BTN_SIDE: index = 3; break; - case BTN_4: - case BTN_EXTRA: index = 4; break; - default: return; + + case BTN_TOUCH: + case BTN_0: + case BTN_LEFT: index = 0; break; + + case BTN_STYLUS: + case BTN_1: + case BTN_RIGHT: index = 1; break; + + case BTN_2: + case BTN_FORWARD: + case BTN_STYLUS2: + case BTN_MIDDLE: index = 2; break; + + case BTN_3: + case BTN_BACK: + case BTN_SIDE: index = 3; break; + + case BTN_4: + case BTN_EXTRA: index = 4; break; + + default: return; } if (value) { @@ -226,19 +257,23 @@ static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int } } -static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_hw_data *packet) +static void mousedev_notify_readers(struct mousedev *mousedev, + struct mousedev_hw_data *packet) { struct mousedev_client *client; struct mousedev_motion *p; - unsigned long flags; + unsigned int new_head; int wake_readers = 0; - list_for_each_entry(client, &mousedev->client_list, node) { - spin_lock_irqsave(&client->packet_lock, flags); + rcu_read_lock(); + list_for_each_entry_rcu(client, &mousedev->client_list, node) { + + /* Just acquire the lock, interrupts already disabled */ + spin_lock(&client->packet_lock); p = &client->packets[client->head]; if (client->ready && p->buttons != mousedev->packet.buttons) { - unsigned int new_head = (client->head + 1) % PACKET_QUEUE_LEN; + new_head = (client->head + 1) % PACKET_QUEUE_LEN; if (new_head != client->tail) { p = &client->packets[client->head = new_head]; memset(p, 0, sizeof(struct mousedev_motion)); @@ -253,25 +288,29 @@ static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_h } client->pos_x += packet->dx; - client->pos_x = client->pos_x < 0 ? 0 : (client->pos_x >= xres ? xres : client->pos_x); + client->pos_x = client->pos_x < 0 ? + 0 : (client->pos_x >= xres ? xres : client->pos_x); client->pos_y += packet->dy; - client->pos_y = client->pos_y < 0 ? 0 : (client->pos_y >= yres ? yres : client->pos_y); + client->pos_y = client->pos_y < 0 ? + 0 : (client->pos_y >= yres ? yres : client->pos_y); p->dx += packet->dx; p->dy += packet->dy; p->dz += packet->dz; p->buttons = mousedev->packet.buttons; - if (p->dx || p->dy || p->dz || p->buttons != client->last_buttons) + if (p->dx || p->dy || p->dz || + p->buttons != client->last_buttons) client->ready = 1; - spin_unlock_irqrestore(&client->packet_lock, flags); + spin_unlock(&client->packet_lock); if (client->ready) { kill_fasync(&client->fasync, SIGIO, POLL_IN); wake_readers = 1; } } + rcu_read_unlock(); if (wake_readers) wake_up_interruptible(&mousedev->wait); @@ -281,7 +320,8 @@ static void mousedev_touchpad_touch(struct mousedev *mousedev, int value) { if (!value) { if (mousedev->touch && - time_before(jiffies, mousedev->touch + msecs_to_jiffies(tap_time))) { + time_before(jiffies, + mousedev->touch + msecs_to_jiffies(tap_time))) { /* * Toggle left button to emulate tap. * We rely on the fact that mousedev_mix always has 0 @@ -290,7 +330,8 @@ static void mousedev_touchpad_touch(struct mousedev *mousedev, int value) set_bit(0, &mousedev->packet.buttons); set_bit(0, &mousedev_mix->packet.buttons); mousedev_notify_readers(mousedev, &mousedev_mix->packet); - mousedev_notify_readers(mousedev_mix, &mousedev_mix->packet); + mousedev_notify_readers(mousedev_mix, + &mousedev_mix->packet); clear_bit(0, &mousedev->packet.buttons); clear_bit(0, &mousedev_mix->packet.buttons); } @@ -302,54 +343,61 @@ static void mousedev_touchpad_touch(struct mousedev *mousedev, int value) mousedev->touch = jiffies; } -static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) +static void mousedev_event(struct input_handle *handle, + unsigned int type, unsigned int code, int value) { struct mousedev *mousedev = handle->private; switch (type) { - case EV_ABS: - /* Ignore joysticks */ - if (test_bit(BTN_TRIGGER, handle->dev->keybit)) - return; - if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) - mousedev_touchpad_event(handle->dev, mousedev, code, value); - else - mousedev_abs_event(handle->dev, mousedev, code, value); + case EV_ABS: + /* Ignore joysticks */ + if (test_bit(BTN_TRIGGER, handle->dev->keybit)) + return; - break; + if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) + mousedev_touchpad_event(handle->dev, + mousedev, code, value); + else + mousedev_abs_event(handle->dev, mousedev, code, value); - case EV_REL: - mousedev_rel_event(mousedev, code, value); - break; + break; - case EV_KEY: - if (value != 2) { - if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) - mousedev_touchpad_touch(mousedev, value); - else - mousedev_key_event(mousedev, code, value); - } - break; + case EV_REL: + mousedev_rel_event(mousedev, code, value); + break; - case EV_SYN: - if (code == SYN_REPORT) { - if (mousedev->touch) { - mousedev->pkt_count++; - /* Input system eats duplicate events, but we need all of them - * to do correct averaging so apply present one forward - */ - fx(0) = fx(1); - fy(0) = fy(1); - } - - mousedev_notify_readers(mousedev, &mousedev->packet); - mousedev_notify_readers(mousedev_mix, &mousedev->packet); - - mousedev->packet.dx = mousedev->packet.dy = mousedev->packet.dz = 0; - mousedev->packet.abs_event = 0; + case EV_KEY: + if (value != 2) { + if (code == BTN_TOUCH && + test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) + mousedev_touchpad_touch(mousedev, value); + else + mousedev_key_event(mousedev, code, value); + } + break; + + case EV_SYN: + if (code == SYN_REPORT) { + if (mousedev->touch) { + mousedev->pkt_count++; + /* + * Input system eats duplicate events, + * but we need all of them to do correct + * averaging so apply present one forward + */ + fx(0) = fx(1); + fy(0) = fy(1); } - break; + + mousedev_notify_readers(mousedev, &mousedev->packet); + mousedev_notify_readers(mousedev_mix, &mousedev->packet); + + mousedev->packet.dx = mousedev->packet.dy = + mousedev->packet.dz = 0; + mousedev->packet.abs_event = 0; + } + break; } } @@ -367,41 +415,48 @@ static void mousedev_free(struct device *dev) { struct mousedev *mousedev = container_of(dev, struct mousedev, dev); - mousedev_table[mousedev->minor] = NULL; kfree(mousedev); } -static int mixdev_add_device(struct mousedev *mousedev) +static int mousedev_open_device(struct mousedev *mousedev) { - int error; + int retval; - if (mousedev_mix->open) { - error = input_open_device(&mousedev->handle); - if (error) - return error; + retval = mutex_lock_interruptible(&mousedev->mutex); + if (retval) + return retval; - mousedev->open++; - mousedev->mixdev_open = 1; + if (mousedev->minor == MOUSEDEV_MIX) + mixdev_open_devices(); + else if (!mousedev->exist) + retval = -ENODEV; + else if (!mousedev->open++) { + retval = input_open_device(&mousedev->handle); + if (retval) + mousedev->open--; } - get_device(&mousedev->dev); - list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list); - - return 0; + mutex_unlock(&mousedev->mutex); + return retval; } -static void mixdev_remove_device(struct mousedev *mousedev) +static void mousedev_close_device(struct mousedev *mousedev) { - if (mousedev->mixdev_open) { - mousedev->mixdev_open = 0; - if (!--mousedev->open && mousedev->exist) - input_close_device(&mousedev->handle); - } + mutex_lock(&mousedev->mutex); - list_del_init(&mousedev->mixdev_node); - put_device(&mousedev->dev); + if (mousedev->minor == MOUSEDEV_MIX) + mixdev_close_devices(); + else if (mousedev->exist && !--mousedev->open) + input_close_device(&mousedev->handle); + + mutex_unlock(&mousedev->mutex); } +/* + * Open all available devices so they can all be multiplexed in one. + * stream. Note that this function is called with mousedev_mix->mutex + * held. + */ static void mixdev_open_devices(void) { struct mousedev *mousedev; @@ -411,16 +466,19 @@ static void mixdev_open_devices(void) list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { if (!mousedev->mixdev_open) { - if (!mousedev->open && mousedev->exist) - if (input_open_device(&mousedev->handle)) - continue; + if (mousedev_open_device(mousedev)) + continue; - mousedev->open++; mousedev->mixdev_open = 1; } } } +/* + * Close all devices that were opened as part of multiplexed + * device. Note that this function is called with mousedev_mix->mutex + * held. + */ static void mixdev_close_devices(void) { struct mousedev *mousedev; @@ -431,33 +489,45 @@ static void mixdev_close_devices(void) list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { if (mousedev->mixdev_open) { mousedev->mixdev_open = 0; - if (!--mousedev->open && mousedev->exist) - input_close_device(&mousedev->handle); + mousedev_close_device(mousedev); } } } + +static void mousedev_attach_client(struct mousedev *mousedev, + struct mousedev_client *client) +{ + spin_lock(&mousedev->client_lock); + list_add_tail_rcu(&client->node, &mousedev->client_list); + spin_unlock(&mousedev->client_lock); + synchronize_rcu(); +} + +static void mousedev_detach_client(struct mousedev *mousedev, + struct mousedev_client *client) +{ + spin_lock(&mousedev->client_lock); + list_del_rcu(&client->node); + spin_unlock(&mousedev->client_lock); + synchronize_rcu(); +} + static int mousedev_release(struct inode *inode, struct file *file) { struct mousedev_client *client = file->private_data; struct mousedev *mousedev = client->mousedev; mousedev_fasync(-1, file, 0); - - list_del(&client->node); + mousedev_detach_client(mousedev, client); kfree(client); - if (mousedev->minor == MOUSEDEV_MIX) - mixdev_close_devices(); - else if (!--mousedev->open && mousedev->exist) - input_close_device(&mousedev->handle); - + mousedev_close_device(mousedev); put_device(&mousedev->dev); return 0; } - static int mousedev_open(struct inode *inode, struct file *file) { struct mousedev_client *client; @@ -475,12 +545,17 @@ static int mousedev_open(struct inode *inode, struct file *file) if (i >= MOUSEDEV_MINORS) return -ENODEV; + error = mutex_lock_interruptible(&mousedev_table_mutex); + if (error) + return error; mousedev = mousedev_table[i]; + if (mousedev) + get_device(&mousedev->dev); + mutex_unlock(&mousedev_table_mutex); + if (!mousedev) return -ENODEV; - get_device(&mousedev->dev); - client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL); if (!client) { error = -ENOMEM; @@ -491,21 +566,17 @@ static int mousedev_open(struct inode *inode, struct file *file) client->pos_x = xres / 2; client->pos_y = yres / 2; client->mousedev = mousedev; - list_add_tail(&client->node, &mousedev->client_list); + mousedev_attach_client(mousedev, client); - if (mousedev->minor == MOUSEDEV_MIX) - mixdev_open_devices(); - else if (!mousedev->open++ && mousedev->exist) { - error = input_open_device(&mousedev->handle); - if (error) - goto err_free_client; - } + error = mousedev_open_device(mousedev); + if (error) + goto err_free_client; file->private_data = client; return 0; err_free_client: - list_del(&client->node); + mousedev_detach_client(mousedev, client); kfree(client); err_put_mousedev: put_device(&mousedev->dev); @@ -517,41 +588,41 @@ static inline int mousedev_limit_delta(int delta, int limit) return delta > limit ? limit : (delta < -limit ? -limit : delta); } -static void mousedev_packet(struct mousedev_client *client, signed char *ps2_data) +static void mousedev_packet(struct mousedev_client *client, + signed char *ps2_data) { - struct mousedev_motion *p; - unsigned long flags; - - spin_lock_irqsave(&client->packet_lock, flags); - p = &client->packets[client->tail]; + struct mousedev_motion *p = &client->packets[client->tail]; - ps2_data[0] = 0x08 | ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07); + ps2_data[0] = 0x08 | + ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07); ps2_data[1] = mousedev_limit_delta(p->dx, 127); ps2_data[2] = mousedev_limit_delta(p->dy, 127); p->dx -= ps2_data[1]; p->dy -= ps2_data[2]; switch (client->mode) { - case MOUSEDEV_EMUL_EXPS: - ps2_data[3] = mousedev_limit_delta(p->dz, 7); - p->dz -= ps2_data[3]; - ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1); - client->bufsiz = 4; - break; - - case MOUSEDEV_EMUL_IMPS: - ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); - ps2_data[3] = mousedev_limit_delta(p->dz, 127); - p->dz -= ps2_data[3]; - client->bufsiz = 4; - break; - - case MOUSEDEV_EMUL_PS2: - default: - ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); - p->dz = 0; - client->bufsiz = 3; - break; + case MOUSEDEV_EMUL_EXPS: + ps2_data[3] = mousedev_limit_delta(p->dz, 7); + p->dz -= ps2_data[3]; + ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1); + client->bufsiz = 4; + break; + + case MOUSEDEV_EMUL_IMPS: + ps2_data[0] |= + ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); + ps2_data[3] = mousedev_limit_delta(p->dz, 127); + p->dz -= ps2_data[3]; + client->bufsiz = 4; + break; + + case MOUSEDEV_EMUL_PS2: + default: + ps2_data[0] |= + ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); + p->dz = 0; + client->bufsiz = 3; + break; } if (!p->dx && !p->dy && !p->dz) { @@ -561,12 +632,56 @@ static void mousedev_packet(struct mousedev_client *client, signed char *ps2_dat } else client->tail = (client->tail + 1) % PACKET_QUEUE_LEN; } - - spin_unlock_irqrestore(&client->packet_lock, flags); } +static void mousedev_generate_response(struct mousedev_client *client, + int command) +{ + client->ps2[0] = 0xfa; /* ACK */ + + switch (command) { -static ssize_t mousedev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) + case 0xeb: /* Poll */ + mousedev_packet(client, &client->ps2[1]); + client->bufsiz++; /* account for leading ACK */ + break; + + case 0xf2: /* Get ID */ + switch (client->mode) { + case MOUSEDEV_EMUL_PS2: + client->ps2[1] = 0; + break; + case MOUSEDEV_EMUL_IMPS: + client->ps2[1] = 3; + break; + case MOUSEDEV_EMUL_EXPS: + client->ps2[1] = 4; + break; + } + client->bufsiz = 2; + break; + + case 0xe9: /* Get info */ + client->ps2[1] = 0x60; client->ps2[2] = 3; client->ps2[3] = 200; + client->bufsiz = 4; + break; + + case 0xff: /* Reset */ + client->impsseq = client->imexseq = 0; + client->mode = MOUSEDEV_EMUL_PS2; + client->ps2[1] = 0xaa; client->ps2[2] = 0x00; + client->bufsiz = 3; + break; + + default: + client->bufsiz = 1; + break; + } + client->buffer = client->bufsiz; +} + +static ssize_t mousedev_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) { struct mousedev_client *client = file->private_data; unsigned char c; @@ -577,6 +692,8 @@ static ssize_t mousedev_write(struct file *file, const char __user *buffer, size if (get_user(c, buffer + i)) return -EFAULT; + spin_lock_irq(&client->packet_lock); + if (c == mousedev_imex_seq[client->imexseq]) { if (++client->imexseq == MOUSEDEV_SEQ_LEN) { client->imexseq = 0; @@ -593,68 +710,39 @@ static ssize_t mousedev_write(struct file *file, const char __user *buffer, size } else client->impsseq = 0; - client->ps2[0] = 0xfa; - - switch (c) { - - case 0xeb: /* Poll */ - mousedev_packet(client, &client->ps2[1]); - client->bufsiz++; /* account for leading ACK */ - break; - - case 0xf2: /* Get ID */ - switch (client->mode) { - case MOUSEDEV_EMUL_PS2: client->ps2[1] = 0; break; - case MOUSEDEV_EMUL_IMPS: client->ps2[1] = 3; break; - case MOUSEDEV_EMUL_EXPS: client->ps2[1] = 4; break; - } - client->bufsiz = 2; - break; - - case 0xe9: /* Get info */ - client->ps2[1] = 0x60; client->ps2[2] = 3; client->ps2[3] = 200; - client->bufsiz = 4; - break; - - case 0xff: /* Reset */ - client->impsseq = client->imexseq = 0; - client->mode = MOUSEDEV_EMUL_PS2; - client->ps2[1] = 0xaa; client->ps2[2] = 0x00; - client->bufsiz = 3; - break; - - default: - client->bufsiz = 1; - break; - } + mousedev_generate_response(client, c); - client->buffer = client->bufsiz; + spin_unlock_irq(&client->packet_lock); } kill_fasync(&client->fasync, SIGIO, POLL_IN); - wake_up_interruptible(&client->mousedev->wait); return count; } -static ssize_t mousedev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) +static ssize_t mousedev_read(struct file *file, char __user *buffer, + size_t count, loff_t *ppos) { struct mousedev_client *client = file->private_data; + struct mousedev *mousedev = client->mousedev; + signed char data[sizeof(client->ps2)]; int retval = 0; - if (!client->ready && !client->buffer && (file->f_flags & O_NONBLOCK)) + if (!client->ready && !client->buffer && mousedev->exist && + (file->f_flags & O_NONBLOCK)) return -EAGAIN; - retval = wait_event_interruptible(client->mousedev->wait, - !client->mousedev->exist || client->ready || client->buffer); - + retval = wait_event_interruptible(mousedev->wait, + !mousedev->exist || client->ready || client->buffer); if (retval) return retval; - if (!client->mousedev->exist) + if (!mousedev->exist) return -ENODEV; + spin_lock_irq(&client->packet_lock); + if (!client->buffer && client->ready) { mousedev_packet(client, client->ps2); client->buffer = client->bufsiz; @@ -663,9 +751,12 @@ static ssize_t mousedev_read(struct file *file, char __user *buffer, size_t coun if (count > client->buffer) count = client->buffer; + memcpy(data, client->ps2 + client->bufsiz - client->buffer, count); client->buffer -= count; - if (copy_to_user(buffer, client->ps2 + client->bufsiz - client->buffer - count, count)) + spin_unlock_irq(&client->packet_lock); + + if (copy_to_user(buffer, data, count)) return -EFAULT; return count; @@ -692,6 +783,60 @@ static const struct file_operations mousedev_fops = { .fasync = mousedev_fasync, }; +static int mousedev_install_chrdev(struct mousedev *mousedev) +{ + mousedev_table[mousedev->minor] = mousedev; + return 0; +} + +static void mousedev_remove_chrdev(struct mousedev *mousedev) +{ + mutex_lock(&mousedev_table_mutex); + mousedev_table[mousedev->minor] = NULL; + mutex_unlock(&mousedev_table_mutex); +} + +/* + * Mark device non-existent. This disables writes, ioctls and + * prevents new users from opening the device. Already posted + * blocking reads will stay, however new ones will fail. + */ +static void mousedev_mark_dead(struct mousedev *mousedev) +{ + mutex_lock(&mousedev->mutex); + mousedev->exist = 0; + mutex_unlock(&mousedev->mutex); +} + +/* + * Wake up users waiting for IO so they can disconnect from + * dead device. + */ +static void mousedev_hangup(struct mousedev *mousedev) +{ + struct mousedev_client *client; + + spin_lock(&mousedev->client_lock); + list_for_each_entry(client, &mousedev->client_list, node) + kill_fasync(&client->fasync, SIGIO, POLL_HUP); + spin_unlock(&mousedev->client_lock); + + wake_up_interruptible(&mousedev->wait); +} + +static void mousedev_cleanup(struct mousedev *mousedev) +{ + struct input_handle *handle = &mousedev->handle; + + mousedev_mark_dead(mousedev); + mousedev_hangup(mousedev); + mousedev_remove_chrdev(mousedev); + + /* mousedev is marked dead so no one else accesses mousedev->open */ + if (mousedev->open) + input_close_device(handle); +} + static struct mousedev *mousedev_create(struct input_dev *dev, struct input_handler *handler, int minor) @@ -707,6 +852,10 @@ static struct mousedev *mousedev_create(struct input_dev *dev, INIT_LIST_HEAD(&mousedev->client_list); INIT_LIST_HEAD(&mousedev->mixdev_node); + spin_lock_init(&mousedev->client_lock); + mutex_init(&mousedev->mutex); + lockdep_set_subclass(&mousedev->mutex, + minor == MOUSEDEV_MIX ? MOUSEDEV_MIX : 0); init_waitqueue_head(&mousedev->wait); if (minor == MOUSEDEV_MIX) @@ -731,14 +880,27 @@ static struct mousedev *mousedev_create(struct input_dev *dev, mousedev->dev.release = mousedev_free; device_initialize(&mousedev->dev); - mousedev_table[minor] = mousedev; + if (minor != MOUSEDEV_MIX) { + error = input_register_handle(&mousedev->handle); + if (error) + goto err_free_mousedev; + } + + error = mousedev_install_chrdev(mousedev); + if (error) + goto err_unregister_handle; error = device_add(&mousedev->dev); if (error) - goto err_free_mousedev; + goto err_cleanup_mousedev; return mousedev; + err_cleanup_mousedev: + mousedev_cleanup(mousedev); + err_unregister_handle: + if (minor != MOUSEDEV_MIX) + input_unregister_handle(&mousedev->handle); err_free_mousedev: put_device(&mousedev->dev); err_out: @@ -747,29 +909,64 @@ static struct mousedev *mousedev_create(struct input_dev *dev, static void mousedev_destroy(struct mousedev *mousedev) { - struct mousedev_client *client; - device_del(&mousedev->dev); - mousedev->exist = 0; + mousedev_cleanup(mousedev); + if (mousedev->minor != MOUSEDEV_MIX) + input_unregister_handle(&mousedev->handle); + put_device(&mousedev->dev); +} - if (mousedev->open) { - input_close_device(&mousedev->handle); - list_for_each_entry(client, &mousedev->client_list, node) - kill_fasync(&client->fasync, SIGIO, POLL_HUP); - wake_up_interruptible(&mousedev->wait); +static int mixdev_add_device(struct mousedev *mousedev) +{ + int retval; + + retval = mutex_lock_interruptible(&mousedev_mix->mutex); + if (retval) + return retval; + + if (mousedev_mix->open) { + retval = mousedev_open_device(mousedev); + if (retval) + goto out; + + mousedev->mixdev_open = 1; } + get_device(&mousedev->dev); + list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list); + + out: + mutex_unlock(&mousedev_mix->mutex); + return retval; +} + +static void mixdev_remove_device(struct mousedev *mousedev) +{ + mutex_lock(&mousedev_mix->mutex); + + if (mousedev->mixdev_open) { + mousedev->mixdev_open = 0; + mousedev_close_device(mousedev); + } + + list_del_init(&mousedev->mixdev_node); + mutex_unlock(&mousedev_mix->mutex); + put_device(&mousedev->dev); } -static int mousedev_connect(struct input_handler *handler, struct input_dev *dev, +static int mousedev_connect(struct input_handler *handler, + struct input_dev *dev, const struct input_device_id *id) { struct mousedev *mousedev; int minor; int error; - for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++); + for (minor = 0; minor < MOUSEDEV_MINORS; minor++) + if (!mousedev_table[minor]) + break; + if (minor == MOUSEDEV_MINORS) { printk(KERN_ERR "mousedev: no more free mousedev devices\n"); return -ENFILE; @@ -779,21 +976,13 @@ static int mousedev_connect(struct input_handler *handler, struct input_dev *dev if (IS_ERR(mousedev)) return PTR_ERR(mousedev); - error = input_register_handle(&mousedev->handle); - if (error) - goto err_delete_mousedev; - error = mixdev_add_device(mousedev); - if (error) - goto err_unregister_handle; + if (error) { + mousedev_destroy(mousedev); + return error; + } return 0; - - err_unregister_handle: - input_unregister_handle(&mousedev->handle); - err_delete_mousedev: - device_unregister(&mousedev->dev); - return error; } static void mousedev_disconnect(struct input_handle *handle) @@ -801,33 +990,42 @@ static void mousedev_disconnect(struct input_handle *handle) struct mousedev *mousedev = handle->private; mixdev_remove_device(mousedev); - input_unregister_handle(handle); mousedev_destroy(mousedev); } static const struct input_device_id mousedev_ids[] = { { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT, + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | + INPUT_DEVICE_ID_MATCH_KEYBIT | + INPUT_DEVICE_ID_MATCH_RELBIT, .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) }, .relbit = { BIT(REL_X) | BIT(REL_Y) }, - }, /* A mouse like device, at least one button, two relative axes */ + }, /* A mouse like device, at least one button, + two relative axes */ { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_RELBIT, + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | + INPUT_DEVICE_ID_MATCH_RELBIT, .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, .relbit = { BIT(REL_WHEEL) }, }, /* A separate scrollwheel */ { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | + INPUT_DEVICE_ID_MATCH_KEYBIT | + INPUT_DEVICE_ID_MATCH_ABSBIT, .evbit = { BIT(EV_KEY) | BIT(EV_ABS) }, .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, .absbit = { BIT(ABS_X) | BIT(ABS_Y) }, - }, /* A tablet like device, at least touch detection, two absolute axes */ + }, /* A tablet like device, at least touch detection, + two absolute axes */ { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | + INPUT_DEVICE_ID_MATCH_KEYBIT | + INPUT_DEVICE_ID_MATCH_ABSBIT, .evbit = { BIT(EV_KEY) | BIT(EV_ABS) }, .keybit = { [LONG(BTN_TOOL_FINGER)] = BIT(BTN_TOOL_FINGER) }, - .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_TOOL_WIDTH) }, + .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | + BIT(ABS_TOOL_WIDTH) }, }, /* A touchpad */ { }, /* Terminating entry */ diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index c2eea2767e10..11dafc0ee994 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -385,6 +385,8 @@ static int i8042_enable_kbd_port(void) i8042_ctr |= I8042_CTR_KBDINT; if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { + i8042_ctr &= ~I8042_CTR_KBDINT; + i8042_ctr |= I8042_CTR_KBDDIS; printk(KERN_ERR "i8042.c: Failed to enable KBD port.\n"); return -EIO; } @@ -402,6 +404,8 @@ static int i8042_enable_aux_port(void) i8042_ctr |= I8042_CTR_AUXINT; if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { + i8042_ctr &= ~I8042_CTR_AUXINT; + i8042_ctr |= I8042_CTR_AUXDIS; printk(KERN_ERR "i8042.c: Failed to enable AUX port.\n"); return -EIO; } diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 372ca4931194..b3bc15acd3f5 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -876,18 +876,14 @@ static int serio_bus_match(struct device *dev, struct device_driver *drv) #define SERIO_ADD_UEVENT_VAR(fmt, val...) \ do { \ - int err = add_uevent_var(envp, num_envp, &i, \ - buffer, buffer_size, &len, \ - fmt, val); \ + int err = add_uevent_var(env, fmt, val); \ if (err) \ return err; \ } while (0) -static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) +static int serio_uevent(struct device *dev, struct kobj_uevent_env *env) { struct serio *serio; - int i = 0; - int len = 0; if (!dev) return -ENODEV; @@ -900,7 +896,6 @@ static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buf SERIO_ADD_UEVENT_VAR("SERIO_EXTRA=%02x", serio->id.extra); SERIO_ADD_UEVENT_VAR("MODALIAS=serio:ty%02Xpr%02Xid%02Xex%02X", serio->id.type, serio->id.proto, serio->id.id, serio->id.extra); - envp[i] = NULL; return 0; } @@ -908,7 +903,7 @@ static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buf #else -static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) +static int serio_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index f929fcdbae2e..e3e0baa1a158 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -126,6 +126,16 @@ config TOUCHSCREEN_HP600 To compile this driver as a module, choose M here: the module will be called hp680_ts_input. +config TOUCHSCREEN_HP7XX + tristate "HP Jornada 710/720/728 touchscreen" + depends on SA1100_JORNADA720_SSP + help + Say Y here if you have a HP Jornada 710/720/728 and want + to support the built-in touchscreen. + + To compile this driver as a module, choose M here: the + module will be called jornada720_ts. + config TOUCHSCREEN_PENMOUNT tristate "Penmount serial touchscreen" select SERIO @@ -191,6 +201,7 @@ config TOUCHSCREEN_USB_COMPOSITE - Gunze AHL61 - DMC TSC-10/25 - IRTOUCHSYSTEMS/UNITOP + - IdealTEK URTC1000 Have a look at <http://linux.chapter7.ch/touchkit/> for a usage description and the required user-space stuff. @@ -238,4 +249,14 @@ config TOUCHSCREEN_USB_IRTOUCH bool "IRTOUCHSYSTEMS/UNITOP device support" if EMBEDDED depends on TOUCHSCREEN_USB_COMPOSITE +config TOUCHSCREEN_USB_IDEALTEK + default y + bool "IdealTEK URTC1000 device support" if EMBEDDED + depends on TOUCHSCREEN_USB_COMPOSITE + +config TOUCHSCREEN_USB_GENERAL_TOUCH + default y + bool "GeneralTouch Touchscreen device support" if EMBEDDED + depends on TOUCHSCREEN_USB_COMPOSITE + endif diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 5de8933c4993..35d4097df35a 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o +obj-$(CONFIG_TOUCHSCREEN_HP7XX) += jornada720_ts.o obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 96581d08774f..51ae4fb7d123 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -83,7 +83,7 @@ struct ads7846 { #if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE) struct attribute_group *attr_group; - struct class_device *hwmon; + struct device *hwmon; #endif u16 model; @@ -369,7 +369,7 @@ static struct attribute_group ads7845_attr_group = { static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts) { - struct class_device *hwmon; + struct device *hwmon; int err; /* hwmon sensors need a reference voltage */ diff --git a/drivers/input/touchscreen/jornada720_ts.c b/drivers/input/touchscreen/jornada720_ts.c new file mode 100644 index 000000000000..42a1c9a1940e --- /dev/null +++ b/drivers/input/touchscreen/jornada720_ts.c @@ -0,0 +1,182 @@ +/* + * drivers/input/touchscreen/jornada720_ts.c + * + * Copyright (C) 2007 Kristoffer Ericson <Kristoffer.Ericson@gmail.com> + * + * Copyright (C) 2006 Filip Zyzniewski <filip.zyzniewski@tefnet.pl> + * based on HP Jornada 56x touchscreen driver by Alex Lange <chicken@handhelds.org> + * + * 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. + * + * HP Jornada 710/720/729 Touchscreen Driver + */ + +#include <linux/platform_device.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/module.h> + +#include <asm/hardware.h> +#include <asm/arch/jornada720.h> + +MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>"); +MODULE_DESCRIPTION("HP Jornada 710/720/728 touchscreen driver"); +MODULE_LICENSE("GPLv2"); + +struct jornada_ts { + struct input_dev *dev; + int x_data[4]; /* X sample values */ + int y_data[4]; /* Y sample values */ +}; + +static void jornada720_ts_collect_data(struct jornada_ts *jornada_ts) +{ + + /* 3 low word X samples */ + jornada_ts->x_data[0] = jornada_ssp_byte(TXDUMMY); + jornada_ts->x_data[1] = jornada_ssp_byte(TXDUMMY); + jornada_ts->x_data[2] = jornada_ssp_byte(TXDUMMY); + + /* 3 low word Y samples */ + jornada_ts->y_data[0] = jornada_ssp_byte(TXDUMMY); + jornada_ts->y_data[1] = jornada_ssp_byte(TXDUMMY); + jornada_ts->y_data[2] = jornada_ssp_byte(TXDUMMY); + + /* combined x samples bits */ + jornada_ts->x_data[3] = jornada_ssp_byte(TXDUMMY); + + /* combined y samples bits */ + jornada_ts->y_data[3] = jornada_ssp_byte(TXDUMMY); +} + +static int jornada720_ts_average(int coords[4]) +{ + int coord, high_bits = coords[3]; + + coord = coords[0] | ((high_bits & 0x03) << 8); + coord += coords[1] | ((high_bits & 0x0c) << 6); + coord += coords[2] | ((high_bits & 0x30) << 4); + + return coord / 3; +} + +static irqreturn_t jornada720_ts_interrupt(int irq, void *dev_id) +{ + struct platform_device *pdev = dev_id; + struct jornada_ts *jornada_ts = platform_get_drvdata(pdev); + struct input_dev *input = jornada_ts->dev; + int x, y; + + /* If GPIO_GPIO9 is set to high then report pen up */ + if (GPLR & GPIO_GPIO(9)) { + input_report_key(input, BTN_TOUCH, 0); + input_sync(input); + } else { + jornada_ssp_start(); + + /* proper reply to request is always TXDUMMY */ + if (jornada_ssp_inout(GETTOUCHSAMPLES) == TXDUMMY) { + jornada720_ts_collect_data(jornada_ts); + + x = jornada720_ts_average(jornada_ts->x_data); + y = jornada720_ts_average(jornada_ts->y_data); + + input_report_key(input, BTN_TOUCH, 1); + input_report_abs(input, ABS_X, x); + input_report_abs(input, ABS_Y, y); + input_sync(input); + } + + jornada_ssp_end(); + } + + return IRQ_HANDLED; +} + +static int __devinit jornada720_ts_probe(struct platform_device *pdev) +{ + struct jornada_ts *jornada_ts; + struct input_dev *input_dev; + int error; + + jornada_ts = kzalloc(sizeof(struct jornada_ts), GFP_KERNEL); + input_dev = input_allocate_device(); + + if (!jornada_ts || !input_dev) { + error = -ENOMEM; + goto fail1; + } + + platform_set_drvdata(pdev, jornada_ts); + + jornada_ts->dev = input_dev; + + input_dev->name = "HP Jornada 7xx Touchscreen"; + input_dev->phys = "jornadats/input0"; + input_dev->id.bustype = BUS_HOST; + input_dev->dev.parent = &pdev->dev; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + input_set_abs_params(input_dev, ABS_X, 270, 3900, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 180, 3700, 0, 0); + + error = request_irq(IRQ_GPIO9, + jornada720_ts_interrupt, + IRQF_DISABLED | IRQF_TRIGGER_RISING, + "HP7XX Touchscreen driver", pdev); + if (error) { + printk(KERN_INFO "HP7XX TS : Unable to acquire irq!\n"); + goto fail1; + } + + error = input_register_device(jornada_ts->dev); + if (error) + goto fail2; + + return 0; + + fail2: + free_irq(IRQ_GPIO9, pdev); + fail1: + platform_set_drvdata(pdev, NULL); + input_free_device(input_dev); + kfree(jornada_ts); + return error; +} + +static int __devexit jornada720_ts_remove(struct platform_device *pdev) +{ + struct jornada_ts *jornada_ts = platform_get_drvdata(pdev); + + free_irq(IRQ_GPIO9, pdev); + platform_set_drvdata(pdev, NULL); + input_unregister_device(jornada_ts->dev); + kfree(jornada_ts); + + return 0; +} + +static struct platform_driver jornada720_ts_driver = { + .probe = jornada720_ts_probe, + .remove = __devexit_p(jornada720_ts_remove), + .driver = { + .name = "jornada_ts", + }, +}; + +static int __init jornada720_ts_init(void) +{ + return platform_driver_register(&jornada720_ts_driver); +} + +static void __exit jornada720_ts_exit(void) +{ + platform_driver_unregister(&jornada720_ts_driver); +} + +module_init(jornada720_ts_init); +module_exit(jornada720_ts_exit); diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c index 36f944019158..86aed64ec0fb 100644 --- a/drivers/input/touchscreen/ucb1400_ts.c +++ b/drivers/input/touchscreen/ucb1400_ts.c @@ -130,8 +130,7 @@ static unsigned int ucb1400_adc_read(struct ucb1400 *ucb, u16 adc_channel) if (val & UCB_ADC_DAT_VALID) break; /* yield to other processes */ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } return UCB_ADC_DAT_VALUE(val); diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index 741f6c6f1e50..9fb3d5c30999 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -10,6 +10,7 @@ * - Gunze AHL61 * - DMC TSC-10/25 * - IRTOUCHSYSTEMS/UNITOP + * - IdealTEK URTC1000 * * Copyright (C) 2004-2006 by Daniel Ritz <daniel.ritz@gmx.ch> * Copyright (C) by Todd E. Johnson (mtouchusb.c) @@ -92,7 +93,7 @@ struct usbtouch_usb { }; -#if defined(CONFIG_TOUCHSCREEN_USB_EGALAX) || defined(CONFIG_TOUCHSCREEN_USB_ETURBO) +#if defined(CONFIG_TOUCHSCREEN_USB_EGALAX) || defined(CONFIG_TOUCHSCREEN_USB_ETURBO) || defined(CONFIG_TOUCHSCREEN_USB_IDEALTEK) #define MULTI_PACKET #endif @@ -112,6 +113,8 @@ enum { DEVTYPE_GUNZE, DEVTYPE_DMC_TSC10, DEVTYPE_IRTOUCH, + DEVTYPE_IDEALTEK, + DEVTYPE_GENERAL_TOUCH, }; static struct usb_device_id usbtouch_devices[] = { @@ -157,6 +160,14 @@ static struct usb_device_id usbtouch_devices[] = { {USB_DEVICE(0x6615, 0x0001), .driver_info = DEVTYPE_IRTOUCH}, #endif +#ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK + {USB_DEVICE(0x1391, 0x1000), .driver_info = DEVTYPE_IDEALTEK}, +#endif + +#ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH + {USB_DEVICE(0x0dfc, 0x0001), .driver_info = DEVTYPE_GENERAL_TOUCH}, +#endif + {} }; @@ -396,7 +407,8 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch) TSC10_RATE_150, 0, buf, 2, USB_CTRL_SET_TIMEOUT); if (ret < 0) return ret; - if (buf[0] != 0x06 || buf[1] != 0x00) + if ((buf[0] != 0x06 || buf[1] != 0x00) && + (buf[0] != 0x15 || buf[1] != 0x01)) return -ENODEV; /* start sending data */ @@ -438,6 +450,57 @@ static int irtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt) /***************************************************************************** + * IdealTEK URTC1000 Part + */ +#ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK +static int idealtek_get_pkt_len(unsigned char *buf, int len) +{ + if (buf[0] & 0x80) + return 5; + if (buf[0] == 0x01) + return len; + return 0; +} + +static int idealtek_read_data(struct usbtouch_usb *dev, unsigned char *pkt) +{ + switch (pkt[0] & 0x98) { + case 0x88: + /* touch data in IdealTEK mode */ + dev->x = (pkt[1] << 5) | (pkt[2] >> 2); + dev->y = (pkt[3] << 5) | (pkt[4] >> 2); + dev->touch = (pkt[0] & 0x40) ? 1 : 0; + return 1; + + case 0x98: + /* touch data in MT emulation mode */ + dev->x = (pkt[2] << 5) | (pkt[1] >> 2); + dev->y = (pkt[4] << 5) | (pkt[3] >> 2); + dev->touch = (pkt[0] & 0x40) ? 1 : 0; + return 1; + + default: + return 0; + } +} +#endif + +/***************************************************************************** + * General Touch Part + */ +#ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH +static int general_touch_read_data(struct usbtouch_usb *dev, unsigned char *pkt) +{ + dev->x = ((pkt[2] & 0x0F) << 8) | pkt[1] ; + dev->y = ((pkt[4] & 0x0F) << 8) | pkt[3] ; + dev->press = pkt[5] & 0xff; + dev->touch = pkt[0] & 0x01; + + return 1; +} +#endif + +/***************************************************************************** * the different device descriptors */ static struct usbtouch_device_info usbtouch_dev_info[] = { @@ -537,6 +600,32 @@ static struct usbtouch_device_info usbtouch_dev_info[] = { .read_data = irtouch_read_data, }, #endif + +#ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK + [DEVTYPE_IDEALTEK] = { + .min_xc = 0x0, + .max_xc = 0x0fff, + .min_yc = 0x0, + .max_yc = 0x0fff, + .rept_size = 8, + .flags = USBTOUCH_FLG_BUFFER, + .process_pkt = usbtouch_process_multi, + .get_pkt_len = idealtek_get_pkt_len, + .read_data = idealtek_read_data, + }, +#endif + +#ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH + [DEVTYPE_GENERAL_TOUCH] = { + .min_xc = 0x0, + .max_xc = 0x0500, + .min_yc = 0x0, + .max_yc = 0x0500, + .rept_size = 7, + .read_data = general_touch_read_data, + } +#endif + }; diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c deleted file mode 100644 index d2f882e98e5e..000000000000 --- a/drivers/input/tsdev.c +++ /dev/null @@ -1,533 +0,0 @@ -/* - * $Id: tsdev.c,v 1.15 2002/04/10 16:50:19 jsimmons Exp $ - * - * Copyright (c) 2001 "Crazy" james Simmons - * - * Compaq touchscreen protocol driver. The protocol emulated by this driver - * is obsolete; for new programs use the tslib library which can read directly - * from evdev and perform dejittering, variance filtering and calibration - - * all in user space, not at kernel level. The meaning of this driver is - * to allow usage of newer input drivers with old applications that use the - * old /dev/h3600_ts and /dev/h3600_tsraw devices. - * - * 09-Apr-2004: Andrew Zabolotny <zap@homelink.ru> - * Fixed to actually work, not just output random numbers. - * Added support for both h3600_ts and h3600_tsraw protocol - * emulation. - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to <jsimmons@infradead.org>. - */ - -#define TSDEV_MINOR_BASE 128 -#define TSDEV_MINORS 32 -/* First 16 devices are h3600_ts compatible; second 16 are h3600_tsraw */ -#define TSDEV_MINOR_MASK 15 -#define TSDEV_BUFFER_SIZE 64 - -#include <linux/slab.h> -#include <linux/poll.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/init.h> -#include <linux/input.h> -#include <linux/major.h> -#include <linux/random.h> -#include <linux/time.h> -#include <linux/device.h> - -#ifndef CONFIG_INPUT_TSDEV_SCREEN_X -#define CONFIG_INPUT_TSDEV_SCREEN_X 240 -#endif -#ifndef CONFIG_INPUT_TSDEV_SCREEN_Y -#define CONFIG_INPUT_TSDEV_SCREEN_Y 320 -#endif - -/* This driver emulates both protocols of the old h3600_ts and h3600_tsraw - * devices. The first one must output X/Y data in 'cooked' format, e.g. - * filtered, dejittered and calibrated. Second device just outputs raw - * data received from the hardware. - * - * This driver doesn't support filtering and dejittering; it supports only - * calibration. Filtering and dejittering must be done in the low-level - * driver, if needed, because it may gain additional benefits from knowing - * the low-level details, the nature of noise and so on. - * - * The driver precomputes a calibration matrix given the initial xres and - * yres values (quite innacurate for most touchscreens) that will result - * in a more or less expected range of output values. The driver supports - * the TS_SET_CAL ioctl, which will replace the calibration matrix with a - * new one, supposedly generated from the values taken from the raw device. - */ - -MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>"); -MODULE_DESCRIPTION("Input driver to touchscreen converter"); -MODULE_LICENSE("GPL"); - -static int xres = CONFIG_INPUT_TSDEV_SCREEN_X; -module_param(xres, uint, 0); -MODULE_PARM_DESC(xres, "Horizontal screen resolution (can be negative for X-mirror)"); - -static int yres = CONFIG_INPUT_TSDEV_SCREEN_Y; -module_param(yres, uint, 0); -MODULE_PARM_DESC(yres, "Vertical screen resolution (can be negative for Y-mirror)"); - -/* From Compaq's Touch Screen Specification version 0.2 (draft) */ -struct ts_event { - short pressure; - short x; - short y; - short millisecs; -}; - -struct ts_calibration { - int xscale; - int xtrans; - int yscale; - int ytrans; - int xyswap; -}; - -struct tsdev { - int exist; - int open; - int minor; - char name[8]; - struct input_handle handle; - wait_queue_head_t wait; - struct list_head client_list; - struct device dev; - - int x, y, pressure; - struct ts_calibration cal; -}; - -struct tsdev_client { - struct fasync_struct *fasync; - struct list_head node; - struct tsdev *tsdev; - int head, tail; - struct ts_event event[TSDEV_BUFFER_SIZE]; - int raw; -}; - -/* The following ioctl codes are defined ONLY for backward compatibility. - * Don't use tsdev for new developement; use the tslib library instead. - * Touchscreen calibration is a fully userspace task. - */ -/* Use 'f' as magic number */ -#define IOC_H3600_TS_MAGIC 'f' -#define TS_GET_CAL _IOR(IOC_H3600_TS_MAGIC, 10, struct ts_calibration) -#define TS_SET_CAL _IOW(IOC_H3600_TS_MAGIC, 11, struct ts_calibration) - -static struct tsdev *tsdev_table[TSDEV_MINORS/2]; - -static int tsdev_fasync(int fd, struct file *file, int on) -{ - struct tsdev_client *client = file->private_data; - int retval; - - retval = fasync_helper(fd, file, on, &client->fasync); - return retval < 0 ? retval : 0; -} - -static int tsdev_open(struct inode *inode, struct file *file) -{ - int i = iminor(inode) - TSDEV_MINOR_BASE; - struct tsdev_client *client; - struct tsdev *tsdev; - int error; - - printk(KERN_WARNING "tsdev (compaq touchscreen emulation) is scheduled " - "for removal.\nSee Documentation/feature-removal-schedule.txt " - "for details.\n"); - - if (i >= TSDEV_MINORS) - return -ENODEV; - - tsdev = tsdev_table[i & TSDEV_MINOR_MASK]; - if (!tsdev || !tsdev->exist) - return -ENODEV; - - get_device(&tsdev->dev); - - client = kzalloc(sizeof(struct tsdev_client), GFP_KERNEL); - if (!client) { - error = -ENOMEM; - goto err_put_tsdev; - } - - client->tsdev = tsdev; - client->raw = (i >= TSDEV_MINORS / 2) ? 1 : 0; - list_add_tail(&client->node, &tsdev->client_list); - - if (!tsdev->open++ && tsdev->exist) { - error = input_open_device(&tsdev->handle); - if (error) - goto err_free_client; - } - - file->private_data = client; - return 0; - - err_free_client: - list_del(&client->node); - kfree(client); - err_put_tsdev: - put_device(&tsdev->dev); - return error; -} - -static void tsdev_free(struct device *dev) -{ - struct tsdev *tsdev = container_of(dev, struct tsdev, dev); - - tsdev_table[tsdev->minor] = NULL; - kfree(tsdev); -} - -static int tsdev_release(struct inode *inode, struct file *file) -{ - struct tsdev_client *client = file->private_data; - struct tsdev *tsdev = client->tsdev; - - tsdev_fasync(-1, file, 0); - - list_del(&client->node); - kfree(client); - - if (!--tsdev->open && tsdev->exist) - input_close_device(&tsdev->handle); - - put_device(&tsdev->dev); - - return 0; -} - -static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count, - loff_t *ppos) -{ - struct tsdev_client *client = file->private_data; - struct tsdev *tsdev = client->tsdev; - int retval = 0; - - if (client->head == client->tail && tsdev->exist && (file->f_flags & O_NONBLOCK)) - return -EAGAIN; - - retval = wait_event_interruptible(tsdev->wait, - client->head != client->tail || !tsdev->exist); - if (retval) - return retval; - - if (!tsdev->exist) - return -ENODEV; - - while (client->head != client->tail && - retval + sizeof (struct ts_event) <= count) { - if (copy_to_user (buffer + retval, client->event + client->tail, - sizeof (struct ts_event))) - return -EFAULT; - client->tail = (client->tail + 1) & (TSDEV_BUFFER_SIZE - 1); - retval += sizeof (struct ts_event); - } - - return retval; -} - -/* No kernel lock - fine */ -static unsigned int tsdev_poll(struct file *file, poll_table *wait) -{ - struct tsdev_client *client = file->private_data; - struct tsdev *tsdev = client->tsdev; - - poll_wait(file, &tsdev->wait, wait); - return ((client->head == client->tail) ? 0 : (POLLIN | POLLRDNORM)) | - (tsdev->exist ? 0 : (POLLHUP | POLLERR)); -} - -static int tsdev_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct tsdev_client *client = file->private_data; - struct tsdev *tsdev = client->tsdev; - int retval = 0; - - switch (cmd) { - case TS_GET_CAL: - if (copy_to_user((void __user *)arg, &tsdev->cal, - sizeof (struct ts_calibration))) - retval = -EFAULT; - break; - - case TS_SET_CAL: - if (copy_from_user(&tsdev->cal, (void __user *)arg, - sizeof (struct ts_calibration))) - retval = -EFAULT; - break; - - default: - retval = -EINVAL; - break; - } - - return retval; -} - -static const struct file_operations tsdev_fops = { - .owner = THIS_MODULE, - .open = tsdev_open, - .release = tsdev_release, - .read = tsdev_read, - .poll = tsdev_poll, - .fasync = tsdev_fasync, - .ioctl = tsdev_ioctl, -}; - -static void tsdev_event(struct input_handle *handle, unsigned int type, - unsigned int code, int value) -{ - struct tsdev *tsdev = handle->private; - struct tsdev_client *client; - struct timeval time; - - switch (type) { - case EV_ABS: - switch (code) { - case ABS_X: - tsdev->x = value; - break; - - case ABS_Y: - tsdev->y = value; - break; - - case ABS_PRESSURE: - if (value > handle->dev->absmax[ABS_PRESSURE]) - value = handle->dev->absmax[ABS_PRESSURE]; - value -= handle->dev->absmin[ABS_PRESSURE]; - if (value < 0) - value = 0; - tsdev->pressure = value; - break; - } - break; - - case EV_REL: - switch (code) { - case REL_X: - tsdev->x += value; - if (tsdev->x < 0) - tsdev->x = 0; - else if (tsdev->x > xres) - tsdev->x = xres; - break; - - case REL_Y: - tsdev->y += value; - if (tsdev->y < 0) - tsdev->y = 0; - else if (tsdev->y > yres) - tsdev->y = yres; - break; - } - break; - - case EV_KEY: - if (code == BTN_TOUCH || code == BTN_MOUSE) { - switch (value) { - case 0: - tsdev->pressure = 0; - break; - - case 1: - if (!tsdev->pressure) - tsdev->pressure = 1; - break; - } - } - break; - } - - if (type != EV_SYN || code != SYN_REPORT) - return; - - list_for_each_entry(client, &tsdev->client_list, node) { - int x, y, tmp; - - do_gettimeofday(&time); - client->event[client->head].millisecs = time.tv_usec / 1000; - client->event[client->head].pressure = tsdev->pressure; - - x = tsdev->x; - y = tsdev->y; - - /* Calibration */ - if (!client->raw) { - x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans; - y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans; - if (tsdev->cal.xyswap) { - tmp = x; x = y; y = tmp; - } - } - - client->event[client->head].x = x; - client->event[client->head].y = y; - client->head = (client->head + 1) & (TSDEV_BUFFER_SIZE - 1); - kill_fasync(&client->fasync, SIGIO, POLL_IN); - } - wake_up_interruptible(&tsdev->wait); -} - -static int tsdev_connect(struct input_handler *handler, struct input_dev *dev, - const struct input_device_id *id) -{ - struct tsdev *tsdev; - int minor, delta; - int error; - - for (minor = 0; minor < TSDEV_MINORS / 2 && tsdev_table[minor]; minor++); - if (minor >= TSDEV_MINORS / 2) { - printk(KERN_ERR - "tsdev: You have way too many touchscreens\n"); - return -ENFILE; - } - - tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL); - if (!tsdev) - return -ENOMEM; - - INIT_LIST_HEAD(&tsdev->client_list); - init_waitqueue_head(&tsdev->wait); - - tsdev->exist = 1; - tsdev->minor = minor; - tsdev->handle.dev = dev; - tsdev->handle.name = tsdev->name; - tsdev->handle.handler = handler; - tsdev->handle.private = tsdev; - snprintf(tsdev->name, sizeof(tsdev->name), "ts%d", minor); - - /* Precompute the rough calibration matrix */ - delta = dev->absmax [ABS_X] - dev->absmin [ABS_X] + 1; - if (delta == 0) - delta = 1; - tsdev->cal.xscale = (xres << 8) / delta; - tsdev->cal.xtrans = - ((dev->absmin [ABS_X] * tsdev->cal.xscale) >> 8); - - delta = dev->absmax [ABS_Y] - dev->absmin [ABS_Y] + 1; - if (delta == 0) - delta = 1; - tsdev->cal.yscale = (yres << 8) / delta; - tsdev->cal.ytrans = - ((dev->absmin [ABS_Y] * tsdev->cal.yscale) >> 8); - - snprintf(tsdev->dev.bus_id, sizeof(tsdev->dev.bus_id), - "ts%d", minor); - tsdev->dev.class = &input_class; - tsdev->dev.parent = &dev->dev; - tsdev->dev.devt = MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor); - tsdev->dev.release = tsdev_free; - device_initialize(&tsdev->dev); - - tsdev_table[minor] = tsdev; - - error = device_add(&tsdev->dev); - if (error) - goto err_free_tsdev; - - error = input_register_handle(&tsdev->handle); - if (error) - goto err_delete_tsdev; - - return 0; - - err_delete_tsdev: - device_del(&tsdev->dev); - err_free_tsdev: - put_device(&tsdev->dev); - return error; -} - -static void tsdev_disconnect(struct input_handle *handle) -{ - struct tsdev *tsdev = handle->private; - struct tsdev_client *client; - - input_unregister_handle(handle); - device_del(&tsdev->dev); - - tsdev->exist = 0; - - if (tsdev->open) { - input_close_device(handle); - list_for_each_entry(client, &tsdev->client_list, node) - kill_fasync(&client->fasync, SIGIO, POLL_HUP); - wake_up_interruptible(&tsdev->wait); - } - - put_device(&tsdev->dev); -} - -static const struct input_device_id tsdev_ids[] = { - { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT, - .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, - .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) }, - .relbit = { BIT(REL_X) | BIT(REL_Y) }, - }, /* A mouse like device, at least one button, two relative axes */ - - { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, - .evbit = { BIT(EV_KEY) | BIT(EV_ABS) }, - .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, - .absbit = { BIT(ABS_X) | BIT(ABS_Y) }, - }, /* A tablet like device, at least touch detection, two absolute axes */ - - { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, - .evbit = { BIT(EV_ABS) }, - .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) }, - }, /* A tablet like device with several gradations of pressure */ - - {} /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(input, tsdev_ids); - -static struct input_handler tsdev_handler = { - .event = tsdev_event, - .connect = tsdev_connect, - .disconnect = tsdev_disconnect, - .fops = &tsdev_fops, - .minor = TSDEV_MINOR_BASE, - .name = "tsdev", - .id_table = tsdev_ids, -}; - -static int __init tsdev_init(void) -{ - return input_register_handler(&tsdev_handler); -} - -static void __exit tsdev_exit(void) -{ - input_unregister_handler(&tsdev_handler); -} - -module_init(tsdev_init); -module_exit(tsdev_exit); diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c index b04a178e5021..f8b79783c8b3 100644 --- a/drivers/isdn/hisax/avm_pci.c +++ b/drivers/isdn/hisax/avm_pci.c @@ -20,7 +20,6 @@ #include <linux/isapnp.h> #include <linux/interrupt.h> -extern const char *CardType[]; static const char *avm_pci_rev = "$Revision: 1.29.2.4 $"; #define AVM_FRITZ_PCI 1 @@ -726,100 +725,15 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -#ifdef CONFIG_PCI -static struct pci_dev *dev_avm __devinitdata = NULL; -#endif -#ifdef __ISAPNP__ -static struct pnp_card *pnp_avm_c __devinitdata = NULL; -#endif - -int __devinit -setup_avm_pcipnp(struct IsdnCard *card) +static int __devinit avm_setup_rest(struct IsdnCardState *cs) { u_int val, ver; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - strcpy(tmp, avm_pci_rev); - printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_FRITZPCI) - return (0); - if (card->para[1]) { - /* old manual method */ - cs->hw.avm.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - cs->subtyp = AVM_FRITZ_PNP; - goto ready; - } -#ifdef __ISAPNP__ - if (isapnp_present()) { - struct pnp_dev *pnp_avm_d = NULL; - if ((pnp_avm_c = pnp_find_card( - ISAPNP_VENDOR('A', 'V', 'M'), - ISAPNP_FUNCTION(0x0900), pnp_avm_c))) { - if ((pnp_avm_d = pnp_find_dev(pnp_avm_c, - ISAPNP_VENDOR('A', 'V', 'M'), - ISAPNP_FUNCTION(0x0900), pnp_avm_d))) { - int err; - - pnp_disable_dev(pnp_avm_d); - err = pnp_activate_dev(pnp_avm_d); - if (err<0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); - return(0); - } - cs->hw.avm.cfg_reg = - pnp_port_start(pnp_avm_d, 0); - cs->irq = pnp_irq(pnp_avm_d, 0); - if (!cs->irq) { - printk(KERN_ERR "FritzPnP:No IRQ\n"); - return(0); - } - if (!cs->hw.avm.cfg_reg) { - printk(KERN_ERR "FritzPnP:No IO address\n"); - return(0); - } - cs->subtyp = AVM_FRITZ_PNP; - goto ready; - } - } - } else { - printk(KERN_INFO "FritzPnP: no ISA PnP present\n"); - } -#endif -#ifdef CONFIG_PCI - if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM, - PCI_DEVICE_ID_AVM_A1, dev_avm))) { - if (pci_enable_device(dev_avm)) - return(0); - cs->irq = dev_avm->irq; - if (!cs->irq) { - printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n"); - return(0); - } - cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1); - if (!cs->hw.avm.cfg_reg) { - printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n"); - return(0); - } - cs->subtyp = AVM_FRITZ_PCI; - } else { - printk(KERN_WARNING "FritzPCI: No PCI card found\n"); - return(0); - } - cs->irq_flags |= IRQF_SHARED; -#else - printk(KERN_WARNING "FritzPCI: NO_PCI_BIOS\n"); - return (0); -#endif /* CONFIG_PCI */ -ready: cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10; if (!request_region(cs->hw.avm.cfg_reg, 32, (cs->subtyp == AVM_FRITZ_PCI) ? "avm PCI" : "avm PnP")) { printk(KERN_WARNING - "HiSax: %s config port %x-%x already in use\n", - CardType[card->typ], + "HiSax: Fritz!PCI/PNP config port %x-%x already in use\n", cs->hw.avm.cfg_reg, cs->hw.avm.cfg_reg + 31); return (0); @@ -860,3 +774,137 @@ ready: ISACVersion(cs, (cs->subtyp == AVM_FRITZ_PCI) ? "AVM PCI:" : "AVM PnP:"); return (1); } + +#ifndef __ISAPNP__ + +static int __devinit avm_pnp_setup(struct IsdnCardState *cs) +{ + return(1); /* no-op: success */ +} + +#else + +static struct pnp_card *pnp_avm_c __devinitdata = NULL; + +static int __devinit avm_pnp_setup(struct IsdnCardState *cs) +{ + struct pnp_dev *pnp_avm_d = NULL; + + if (!isapnp_present()) + return(1); /* no-op: success */ + + if ((pnp_avm_c = pnp_find_card( + ISAPNP_VENDOR('A', 'V', 'M'), + ISAPNP_FUNCTION(0x0900), pnp_avm_c))) { + if ((pnp_avm_d = pnp_find_dev(pnp_avm_c, + ISAPNP_VENDOR('A', 'V', 'M'), + ISAPNP_FUNCTION(0x0900), pnp_avm_d))) { + int err; + + pnp_disable_dev(pnp_avm_d); + err = pnp_activate_dev(pnp_avm_d); + if (err<0) { + printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", + __FUNCTION__, err); + return(0); + } + cs->hw.avm.cfg_reg = + pnp_port_start(pnp_avm_d, 0); + cs->irq = pnp_irq(pnp_avm_d, 0); + if (!cs->irq) { + printk(KERN_ERR "FritzPnP:No IRQ\n"); + return(0); + } + if (!cs->hw.avm.cfg_reg) { + printk(KERN_ERR "FritzPnP:No IO address\n"); + return(0); + } + cs->subtyp = AVM_FRITZ_PNP; + + return (2); /* goto 'ready' label */ + } + } + + return (1); +} + +#endif /* __ISAPNP__ */ + +#ifndef CONFIG_PCI + +static int __devinit avm_pci_setup(struct IsdnCardState *cs) +{ + return(1); /* no-op: success */ +} + +#else + +static struct pci_dev *dev_avm __devinitdata = NULL; + +static int __devinit avm_pci_setup(struct IsdnCardState *cs) +{ + if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM, + PCI_DEVICE_ID_AVM_A1, dev_avm))) { + + if (pci_enable_device(dev_avm)) + return(0); + + cs->irq = dev_avm->irq; + if (!cs->irq) { + printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n"); + return(0); + } + + cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1); + if (!cs->hw.avm.cfg_reg) { + printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n"); + return(0); + } + + cs->subtyp = AVM_FRITZ_PCI; + } else { + printk(KERN_WARNING "FritzPCI: No PCI card found\n"); + return(0); + } + + cs->irq_flags |= IRQF_SHARED; + + return (1); +} + +#endif /* CONFIG_PCI */ + +int __devinit +setup_avm_pcipnp(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + char tmp[64]; + int rc; + + strcpy(tmp, avm_pci_rev); + printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp)); + + if (cs->typ != ISDN_CTYPE_FRITZPCI) + return (0); + + if (card->para[1]) { + /* old manual method */ + cs->hw.avm.cfg_reg = card->para[1]; + cs->irq = card->para[0]; + cs->subtyp = AVM_FRITZ_PNP; + goto ready; + } + + rc = avm_pnp_setup(cs); + if (rc < 1) + return (0); + if (rc == 2) + goto ready; + + rc = avm_pci_setup(cs); + if (rc < 1) + return (0); + +ready: + return avm_setup_rest(cs); +} diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c index 6339bb443f62..99ef3b43fcd7 100644 --- a/drivers/isdn/hisax/bkm_a8.c +++ b/drivers/isdn/hisax/bkm_a8.c @@ -20,8 +20,6 @@ #include <linux/pci.h> #include "bkm_ax.h" -#ifdef CONFIG_PCI - #define ATTEMPT_PCI_REMAPPING /* Required for PLX rev 1 */ extern const char *CardType[]; @@ -279,12 +277,9 @@ static u_char pci_bus __devinitdata = 0; static u_char pci_device_fn __devinitdata = 0; static u_char pci_irq __devinitdata = 0; -#endif /* CONFIG_PCI */ - int __devinit setup_sct_quadro(struct IsdnCard *card) { -#ifdef CONFIG_PCI struct IsdnCardState *cs = card->cs; char tmp[64]; u_int found = 0; @@ -442,7 +437,4 @@ setup_sct_quadro(struct IsdnCard *card) sct_quadro_subtypes[cs->subtyp], readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID)); return (1); -#else - printk(KERN_ERR "HiSax: bkm_a8 only supported on PCI Systems\n"); -#endif /* CONFIG_PCI */ } diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c index 6eebeb441bfd..826745078746 100644 --- a/drivers/isdn/hisax/diva.c +++ b/drivers/isdn/hisax/diva.c @@ -25,8 +25,6 @@ #include <linux/pci.h> #include <linux/isapnp.h> -extern const char *CardType[]; - static const char *Diva_revision = "$Revision: 1.33.2.6 $"; #define byteout(addr,val) outb(val,addr) @@ -906,225 +904,15 @@ Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -static struct pci_dev *dev_diva __devinitdata = NULL; -static struct pci_dev *dev_diva_u __devinitdata = NULL; -static struct pci_dev *dev_diva201 __devinitdata = NULL; -static struct pci_dev *dev_diva202 __devinitdata = NULL; - -#ifdef __ISAPNP__ -static struct isapnp_device_id diva_ids[] __devinitdata = { - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), - ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), - (unsigned long) "Diva picola" }, - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), - ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51), - (unsigned long) "Diva picola" }, - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), - ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), - (unsigned long) "Diva 2.0" }, - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), - ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71), - (unsigned long) "Diva 2.0" }, - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), - ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), - (unsigned long) "Diva 2.01" }, - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), - ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1), - (unsigned long) "Diva 2.01" }, - { 0, } -}; - -static struct isapnp_device_id *ipid __devinitdata = &diva_ids[0]; -static struct pnp_card *pnp_c __devinitdata = NULL; -#endif - - -int __devinit -setup_diva(struct IsdnCard *card) +static int __devinit setup_diva_common(struct IsdnCardState *cs) { - int bytecnt = 8; + int bytecnt; u_char val; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, Diva_revision); - printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_DIEHLDIVA) - return(0); - cs->hw.diva.status = 0; - if (card->para[1]) { - cs->hw.diva.ctrl_reg = 0; - cs->hw.diva.cfg_reg = card->para[1]; - val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR, - cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID); - printk(KERN_INFO "Diva: IPAC version %x\n", val); - if ((val == 1) || (val==2)) { - cs->subtyp = DIVA_IPAC_ISA; - cs->hw.diva.ctrl = 0; - cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA; - cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA; - cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR; - cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - } else { - cs->subtyp = DIVA_ISA; - cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL; - cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA; - cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA; - cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR; - cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR; - } - cs->irq = card->para[0]; - } else { -#ifdef __ISAPNP__ - if (isapnp_present()) { - struct pnp_dev *pnp_d; - while(ipid->card_vendor) { - if ((pnp_c = pnp_find_card(ipid->card_vendor, - ipid->card_device, pnp_c))) { - pnp_d = NULL; - if ((pnp_d = pnp_find_dev(pnp_c, - ipid->vendor, ipid->function, pnp_d))) { - int err; - - printk(KERN_INFO "HiSax: %s detected\n", - (char *)ipid->driver_data); - pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err<0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); - return(0); - } - card->para[1] = pnp_port_start(pnp_d, 0); - card->para[0] = pnp_irq(pnp_d, 0); - if (!card->para[0] || !card->para[1]) { - printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n", - card->para[0], card->para[1]); - pnp_disable_dev(pnp_d); - return(0); - } - cs->hw.diva.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - if (ipid->function == ISAPNP_FUNCTION(0xA1)) { - cs->subtyp = DIVA_IPAC_ISA; - cs->hw.diva.ctrl = 0; - cs->hw.diva.isac = - card->para[1] + DIVA_IPAC_DATA; - cs->hw.diva.hscx = - card->para[1] + DIVA_IPAC_DATA; - cs->hw.diva.isac_adr = - card->para[1] + DIVA_IPAC_ADR; - cs->hw.diva.hscx_adr = - card->para[1] + DIVA_IPAC_ADR; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - } else { - cs->subtyp = DIVA_ISA; - cs->hw.diva.ctrl = - card->para[1] + DIVA_ISA_CTRL; - cs->hw.diva.isac = - card->para[1] + DIVA_ISA_ISAC_DATA; - cs->hw.diva.hscx = - card->para[1] + DIVA_HSCX_DATA; - cs->hw.diva.isac_adr = - card->para[1] + DIVA_ISA_ISAC_ADR; - cs->hw.diva.hscx_adr = - card->para[1] + DIVA_HSCX_ADR; - } - goto ready; - } else { - printk(KERN_ERR "Diva PnP: PnP error card found, no device\n"); - return(0); - } - } - ipid++; - pnp_c=NULL; - } - if (!ipid->card_vendor) { - printk(KERN_INFO "Diva PnP: no ISAPnP card found\n"); - } - } -#endif -#ifdef CONFIG_PCI - cs->subtyp = 0; - if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON, - PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) { - if (pci_enable_device(dev_diva)) - return(0); - cs->subtyp = DIVA_PCI; - cs->irq = dev_diva->irq; - cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2); - } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON, - PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) { - if (pci_enable_device(dev_diva_u)) - return(0); - cs->subtyp = DIVA_PCI; - cs->irq = dev_diva_u->irq; - cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2); - } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON, - PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) { - if (pci_enable_device(dev_diva201)) - return(0); - cs->subtyp = DIVA_IPAC_PCI; - cs->irq = dev_diva201->irq; - cs->hw.diva.pci_cfg = - (ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096); - cs->hw.diva.cfg_reg = - (ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096); - } else if ((dev_diva202 = pci_find_device(PCI_VENDOR_ID_EICON, - PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) { - if (pci_enable_device(dev_diva202)) - return(0); - cs->subtyp = DIVA_IPACX_PCI; - cs->irq = dev_diva202->irq; - cs->hw.diva.pci_cfg = - (ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096); - cs->hw.diva.cfg_reg = - (ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096); - } else { - printk(KERN_WARNING "Diva: No PCI card found\n"); - return(0); - } - - if (!cs->irq) { - printk(KERN_WARNING "Diva: No IRQ for PCI card found\n"); - iounmap_diva(cs); - return(0); - } - - if (!cs->hw.diva.cfg_reg) { - printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n"); - iounmap_diva(cs); - return(0); - } - cs->irq_flags |= IRQF_SHARED; -#else - printk(KERN_WARNING "Diva: cfgreg 0 and NO_PCI_BIOS\n"); - printk(KERN_WARNING "Diva: unable to config DIVA PCI\n"); - return (0); -#endif /* CONFIG_PCI */ - if ((cs->subtyp == DIVA_IPAC_PCI) || - (cs->subtyp == DIVA_IPACX_PCI) ) { - cs->hw.diva.ctrl = 0; - cs->hw.diva.isac = 0; - cs->hw.diva.hscx = 0; - cs->hw.diva.isac_adr = 0; - cs->hw.diva.hscx_adr = 0; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - bytecnt = 0; - } else { - cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL; - cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA; - cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA; - cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR; - cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR; - bytecnt = 32; - } - } -#ifdef __ISAPNP__ -ready: -#endif + if ((cs->subtyp == DIVA_ISA) || (cs->subtyp == DIVA_IPAC_ISA)) + bytecnt = 8; + else + bytecnt = 32; printk(KERN_INFO "Diva: %s card configured at %#lx IRQ %d\n", @@ -1145,7 +933,7 @@ ready: if (!request_region(cs->hw.diva.cfg_reg, bytecnt, "diva isdn")) { printk(KERN_WARNING "HiSax: %s config port %lx-%lx already in use\n", - CardType[card->typ], + "diva", cs->hw.diva.cfg_reg, cs->hw.diva.cfg_reg + bytecnt); iounmap_diva(cs); @@ -1206,3 +994,290 @@ ready: } return (1); } + +#ifdef CONFIG_ISA + +static int __devinit setup_diva_isa(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + u_char val; + + if (!card->para[1]) + return (-1); /* card not found; continue search */ + + cs->hw.diva.ctrl_reg = 0; + cs->hw.diva.cfg_reg = card->para[1]; + val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR, + cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID); + printk(KERN_INFO "Diva: IPAC version %x\n", val); + if ((val == 1) || (val==2)) { + cs->subtyp = DIVA_IPAC_ISA; + cs->hw.diva.ctrl = 0; + cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA; + cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA; + cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR; + cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + } else { + cs->subtyp = DIVA_ISA; + cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL; + cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA; + cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA; + cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR; + cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR; + } + cs->irq = card->para[0]; + + return (1); /* card found */ +} + +#else /* if !CONFIG_ISA */ + +static int __devinit setup_diva_isa(struct IsdnCard *card) +{ + return (-1); /* card not found; continue search */ +} + +#endif /* CONFIG_ISA */ + +#ifdef __ISAPNP__ +static struct isapnp_device_id diva_ids[] __devinitdata = { + { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), + ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), + (unsigned long) "Diva picola" }, + { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), + ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51), + (unsigned long) "Diva picola" }, + { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), + ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), + (unsigned long) "Diva 2.0" }, + { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), + ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71), + (unsigned long) "Diva 2.0" }, + { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), + ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), + (unsigned long) "Diva 2.01" }, + { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), + ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1), + (unsigned long) "Diva 2.01" }, + { 0, } +}; + +static struct isapnp_device_id *ipid __devinitdata = &diva_ids[0]; +static struct pnp_card *pnp_c __devinitdata = NULL; + +static int __devinit setup_diva_isapnp(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + struct pnp_dev *pnp_d; + + if (!isapnp_present()) + return (-1); /* card not found; continue search */ + + while(ipid->card_vendor) { + if ((pnp_c = pnp_find_card(ipid->card_vendor, + ipid->card_device, pnp_c))) { + pnp_d = NULL; + if ((pnp_d = pnp_find_dev(pnp_c, + ipid->vendor, ipid->function, pnp_d))) { + int err; + + printk(KERN_INFO "HiSax: %s detected\n", + (char *)ipid->driver_data); + pnp_disable_dev(pnp_d); + err = pnp_activate_dev(pnp_d); + if (err<0) { + printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", + __FUNCTION__, err); + return(0); + } + card->para[1] = pnp_port_start(pnp_d, 0); + card->para[0] = pnp_irq(pnp_d, 0); + if (!card->para[0] || !card->para[1]) { + printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n", + card->para[0], card->para[1]); + pnp_disable_dev(pnp_d); + return(0); + } + cs->hw.diva.cfg_reg = card->para[1]; + cs->irq = card->para[0]; + if (ipid->function == ISAPNP_FUNCTION(0xA1)) { + cs->subtyp = DIVA_IPAC_ISA; + cs->hw.diva.ctrl = 0; + cs->hw.diva.isac = + card->para[1] + DIVA_IPAC_DATA; + cs->hw.diva.hscx = + card->para[1] + DIVA_IPAC_DATA; + cs->hw.diva.isac_adr = + card->para[1] + DIVA_IPAC_ADR; + cs->hw.diva.hscx_adr = + card->para[1] + DIVA_IPAC_ADR; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + } else { + cs->subtyp = DIVA_ISA; + cs->hw.diva.ctrl = + card->para[1] + DIVA_ISA_CTRL; + cs->hw.diva.isac = + card->para[1] + DIVA_ISA_ISAC_DATA; + cs->hw.diva.hscx = + card->para[1] + DIVA_HSCX_DATA; + cs->hw.diva.isac_adr = + card->para[1] + DIVA_ISA_ISAC_ADR; + cs->hw.diva.hscx_adr = + card->para[1] + DIVA_HSCX_ADR; + } + return (1); /* card found */ + } else { + printk(KERN_ERR "Diva PnP: PnP error card found, no device\n"); + return(0); + } + } + ipid++; + pnp_c=NULL; + } + + return (-1); /* card not found; continue search */ +} + +#else /* if !ISAPNP */ + +static int __devinit setup_diva_isapnp(struct IsdnCard *card) +{ + return (-1); /* card not found; continue search */ +} + +#endif /* ISAPNP */ + +#ifdef CONFIG_PCI +static struct pci_dev *dev_diva __devinitdata = NULL; +static struct pci_dev *dev_diva_u __devinitdata = NULL; +static struct pci_dev *dev_diva201 __devinitdata = NULL; +static struct pci_dev *dev_diva202 __devinitdata = NULL; + +static int __devinit setup_diva_pci(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + + cs->subtyp = 0; + if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) { + if (pci_enable_device(dev_diva)) + return(0); + cs->subtyp = DIVA_PCI; + cs->irq = dev_diva->irq; + cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2); + } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) { + if (pci_enable_device(dev_diva_u)) + return(0); + cs->subtyp = DIVA_PCI; + cs->irq = dev_diva_u->irq; + cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2); + } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) { + if (pci_enable_device(dev_diva201)) + return(0); + cs->subtyp = DIVA_IPAC_PCI; + cs->irq = dev_diva201->irq; + cs->hw.diva.pci_cfg = + (ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096); + cs->hw.diva.cfg_reg = + (ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096); + } else if ((dev_diva202 = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) { + if (pci_enable_device(dev_diva202)) + return(0); + cs->subtyp = DIVA_IPACX_PCI; + cs->irq = dev_diva202->irq; + cs->hw.diva.pci_cfg = + (ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096); + cs->hw.diva.cfg_reg = + (ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096); + } else { + return (-1); /* card not found; continue search */ + } + + if (!cs->irq) { + printk(KERN_WARNING "Diva: No IRQ for PCI card found\n"); + iounmap_diva(cs); + return(0); + } + + if (!cs->hw.diva.cfg_reg) { + printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n"); + iounmap_diva(cs); + return(0); + } + cs->irq_flags |= IRQF_SHARED; + + if ((cs->subtyp == DIVA_IPAC_PCI) || + (cs->subtyp == DIVA_IPACX_PCI) ) { + cs->hw.diva.ctrl = 0; + cs->hw.diva.isac = 0; + cs->hw.diva.hscx = 0; + cs->hw.diva.isac_adr = 0; + cs->hw.diva.hscx_adr = 0; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + } else { + cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL; + cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA; + cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA; + cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR; + cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR; + } + + return (1); /* card found */ +} + +#else /* if !CONFIG_PCI */ + +static int __devinit setup_diva_pci(struct IsdnCard *card) +{ + return (-1); /* card not found; continue search */ +} + +#endif /* CONFIG_PCI */ + +int __devinit +setup_diva(struct IsdnCard *card) +{ + int rc, have_card = 0; + struct IsdnCardState *cs = card->cs; + char tmp[64]; + + strcpy(tmp, Diva_revision); + printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_DIEHLDIVA) + return(0); + cs->hw.diva.status = 0; + + rc = setup_diva_isa(card); + if (!rc) + return rc; + if (rc > 0) { + have_card = 1; + goto ready; + } + + rc = setup_diva_isapnp(card); + if (!rc) + return rc; + if (rc > 0) { + have_card = 1; + goto ready; + } + + rc = setup_diva_pci(card); + if (!rc) + return rc; + if (rc > 0) + have_card = 1; + +ready: + if (!have_card) { + printk(KERN_WARNING "Diva: No ISA, ISAPNP or PCI card found\n"); + return(0); + } + + return setup_diva_common(card->cs); +} diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c index fab3e4ea0595..948a9b290fd1 100644 --- a/drivers/isdn/hisax/elsa.c +++ b/drivers/isdn/hisax/elsa.c @@ -30,8 +30,6 @@ #include <linux/serial.h> #include <linux/serial_reg.h> -extern const char *CardType[]; - static const char *Elsa_revision = "$Revision: 2.32.2.4 $"; static const char *Elsa_Types[] = {"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro", @@ -832,8 +830,75 @@ probe_elsa(struct IsdnCardState *cs) return (CARD_portlist[i]); } -static struct pci_dev *dev_qs1000 __devinitdata = NULL; -static struct pci_dev *dev_qs3000 __devinitdata = NULL; +static int __devinit +setup_elsa_isa(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + u_char val; + + cs->hw.elsa.base = card->para[0]; + printk(KERN_INFO "Elsa: Microlink IO probing\n"); + if (cs->hw.elsa.base) { + if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base, + cs->typ))) { + printk(KERN_WARNING + "Elsa: no Elsa Microlink at %#lx\n", + cs->hw.elsa.base); + return (0); + } + } else + cs->hw.elsa.base = probe_elsa(cs); + + if (!cs->hw.elsa.base) { + printk(KERN_WARNING + "No Elsa Microlink found\n"); + return (0); + } + + cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG; + cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL; + cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE; + cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC; + cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC; + cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; + cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ; + cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER; + val = bytein(cs->hw.elsa.cfg); + if (cs->subtyp == ELSA_PC) { + const u_char CARD_IrqTab[8] = + {7, 3, 5, 9, 0, 0, 0, 0}; + cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2]; + } else if (cs->subtyp == ELSA_PCC8) { + const u_char CARD_IrqTab[8] = + {7, 3, 5, 9, 0, 0, 0, 0}; + cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4]; + } else { + const u_char CARD_IrqTab[8] = + {15, 10, 15, 3, 11, 5, 11, 9}; + cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3]; + } + val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE; + if (val < 3) + val |= 8; + val += 'A' - 3; + if (val == 'B' || val == 'C') + val ^= 1; + if ((cs->subtyp == ELSA_PCFPRO) && (val = 'G')) + val = 'C'; + printk(KERN_INFO + "Elsa: %s found at %#lx Rev.:%c IRQ %d\n", + Elsa_Types[cs->subtyp], + cs->hw.elsa.base, + val, cs->irq); + val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD; + if (val) { + printk(KERN_WARNING + "Elsa: Microlink S0 bus power bad\n"); + cs->hw.elsa.status |= ELSA_BAD_PWR; + } + + return (1); +} #ifdef __ISAPNP__ static struct isapnp_device_id elsa_ids[] __devinitdata = { @@ -848,233 +913,194 @@ static struct isapnp_device_id elsa_ids[] __devinitdata = { static struct isapnp_device_id *ipid __devinitdata = &elsa_ids[0]; static struct pnp_card *pnp_c __devinitdata = NULL; -#endif +#endif /* __ISAPNP__ */ -int __devinit -setup_elsa(struct IsdnCard *card) +static int __devinit +setup_elsa_isapnp(struct IsdnCard *card) { - int bytecnt; - u_char val; struct IsdnCardState *cs = card->cs; - char tmp[64]; - strcpy(tmp, Elsa_revision); - printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp)); - cs->hw.elsa.ctrl_reg = 0; - cs->hw.elsa.status = 0; - cs->hw.elsa.MFlag = 0; - cs->subtyp = 0; - if (cs->typ == ISDN_CTYPE_ELSA) { - cs->hw.elsa.base = card->para[0]; - printk(KERN_INFO "Elsa: Microlink IO probing\n"); - if (cs->hw.elsa.base) { - if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base, - cs->typ))) { - printk(KERN_WARNING - "Elsa: no Elsa Microlink at %#lx\n", - cs->hw.elsa.base); - return (0); - } - } else - cs->hw.elsa.base = probe_elsa(cs); - if (cs->hw.elsa.base) { - cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG; - cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL; - cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE; - cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC; - cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC; - cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; - cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ; - cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER; - val = bytein(cs->hw.elsa.cfg); - if (cs->subtyp == ELSA_PC) { - const u_char CARD_IrqTab[8] = - {7, 3, 5, 9, 0, 0, 0, 0}; - cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2]; - } else if (cs->subtyp == ELSA_PCC8) { - const u_char CARD_IrqTab[8] = - {7, 3, 5, 9, 0, 0, 0, 0}; - cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4]; - } else { - const u_char CARD_IrqTab[8] = - {15, 10, 15, 3, 11, 5, 11, 9}; - cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3]; - } - val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE; - if (val < 3) - val |= 8; - val += 'A' - 3; - if (val == 'B' || val == 'C') - val ^= 1; - if ((cs->subtyp == ELSA_PCFPRO) && (val = 'G')) - val = 'C'; - printk(KERN_INFO - "Elsa: %s found at %#lx Rev.:%c IRQ %d\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base, - val, cs->irq); - val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD; - if (val) { - printk(KERN_WARNING - "Elsa: Microlink S0 bus power bad\n"); - cs->hw.elsa.status |= ELSA_BAD_PWR; - } - } else { - printk(KERN_WARNING - "No Elsa Microlink found\n"); - return (0); - } - } else if (cs->typ == ISDN_CTYPE_ELSA_PNP) { #ifdef __ISAPNP__ - if (!card->para[1] && isapnp_present()) { - struct pnp_dev *pnp_d; - while(ipid->card_vendor) { - if ((pnp_c = pnp_find_card(ipid->card_vendor, - ipid->card_device, pnp_c))) { - pnp_d = NULL; - if ((pnp_d = pnp_find_dev(pnp_c, - ipid->vendor, ipid->function, pnp_d))) { - int err; - - printk(KERN_INFO "HiSax: %s detected\n", - (char *)ipid->driver_data); + if (!card->para[1] && isapnp_present()) { + struct pnp_dev *pnp_d; + while(ipid->card_vendor) { + if ((pnp_c = pnp_find_card(ipid->card_vendor, + ipid->card_device, pnp_c))) { + pnp_d = NULL; + if ((pnp_d = pnp_find_dev(pnp_c, + ipid->vendor, ipid->function, pnp_d))) { + int err; + + printk(KERN_INFO "HiSax: %s detected\n", + (char *)ipid->driver_data); + pnp_disable_dev(pnp_d); + err = pnp_activate_dev(pnp_d); + if (err<0) { + printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", + __FUNCTION__, err); + return(0); + } + card->para[1] = pnp_port_start(pnp_d, 0); + card->para[0] = pnp_irq(pnp_d, 0); + + if (!card->para[0] || !card->para[1]) { + printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n", + card->para[0], card->para[1]); pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err<0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); - return(0); - } - card->para[1] = pnp_port_start(pnp_d, 0); - card->para[0] = pnp_irq(pnp_d, 0); - - if (!card->para[0] || !card->para[1]) { - printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n", - card->para[0], card->para[1]); - pnp_disable_dev(pnp_d); - return(0); - } - if (ipid->function == ISAPNP_FUNCTION(0x133)) - cs->subtyp = ELSA_QS1000; - else - cs->subtyp = ELSA_QS3000; - break; - } else { - printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n"); return(0); } + if (ipid->function == ISAPNP_FUNCTION(0x133)) + cs->subtyp = ELSA_QS1000; + else + cs->subtyp = ELSA_QS3000; + break; + } else { + printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n"); + return(0); } - ipid++; - pnp_c=NULL; - } - if (!ipid->card_vendor) { - printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n"); - return(0); } + ipid++; + pnp_c=NULL; + } + if (!ipid->card_vendor) { + printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n"); + return(0); } -#endif - if (card->para[1] && card->para[0]) { - cs->hw.elsa.base = card->para[1]; - cs->irq = card->para[0]; - if (!cs->subtyp) - cs->subtyp = ELSA_QS1000; - } else { - printk(KERN_ERR "Elsa PnP: no parameter\n"); - } - cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG; - cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE; - cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC; - cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; - cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ; - cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER; - cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL; - printk(KERN_INFO - "Elsa: %s defined at %#lx IRQ %d\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base, - cs->irq); - } else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA) { + } +#endif /* __ISAPNP__ */ + + if (card->para[1] && card->para[0]) { cs->hw.elsa.base = card->para[1]; cs->irq = card->para[0]; - val = readreg(cs->hw.elsa.base + 0, cs->hw.elsa.base + 2, IPAC_ID); - if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */ - cs->subtyp = ELSA_PCMCIA_IPAC; - cs->hw.elsa.ale = cs->hw.elsa.base + 0; - cs->hw.elsa.isac = cs->hw.elsa.base + 2; - cs->hw.elsa.hscx = cs->hw.elsa.base + 2; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - } else { - cs->subtyp = ELSA_PCMCIA; - cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM; - cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM; - cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; - } - cs->hw.elsa.timer = 0; - cs->hw.elsa.trig = 0; - cs->hw.elsa.ctrl = 0; - cs->irq_flags |= IRQF_SHARED; - printk(KERN_INFO - "Elsa: %s defined at %#lx IRQ %d\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base, - cs->irq); - } else if (cs->typ == ISDN_CTYPE_ELSA_PCI) { + if (!cs->subtyp) + cs->subtyp = ELSA_QS1000; + } else { + printk(KERN_ERR "Elsa PnP: no parameter\n"); + } + cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG; + cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE; + cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC; + cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; + cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ; + cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER; + cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL; + printk(KERN_INFO + "Elsa: %s defined at %#lx IRQ %d\n", + Elsa_Types[cs->subtyp], + cs->hw.elsa.base, + cs->irq); + + return (1); +} + +static void __devinit +setup_elsa_pcmcia(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + u_char val; + + cs->hw.elsa.base = card->para[1]; + cs->irq = card->para[0]; + val = readreg(cs->hw.elsa.base + 0, cs->hw.elsa.base + 2, IPAC_ID); + if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */ + cs->subtyp = ELSA_PCMCIA_IPAC; + cs->hw.elsa.ale = cs->hw.elsa.base + 0; + cs->hw.elsa.isac = cs->hw.elsa.base + 2; + cs->hw.elsa.hscx = cs->hw.elsa.base + 2; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + } else { + cs->subtyp = ELSA_PCMCIA; + cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM; + cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM; + cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; + } + cs->hw.elsa.timer = 0; + cs->hw.elsa.trig = 0; + cs->hw.elsa.ctrl = 0; + cs->irq_flags |= IRQF_SHARED; + printk(KERN_INFO + "Elsa: %s defined at %#lx IRQ %d\n", + Elsa_Types[cs->subtyp], + cs->hw.elsa.base, + cs->irq); +} + #ifdef CONFIG_PCI - cs->subtyp = 0; - if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA, - PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) { - if (pci_enable_device(dev_qs1000)) - return(0); - cs->subtyp = ELSA_QS1000PCI; - cs->irq = dev_qs1000->irq; - cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1); - cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3); - } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA, - PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) { - if (pci_enable_device(dev_qs3000)) - return(0); - cs->subtyp = ELSA_QS3000PCI; - cs->irq = dev_qs3000->irq; - cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1); - cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3); - } else { - printk(KERN_WARNING "Elsa: No PCI card found\n"); +static struct pci_dev *dev_qs1000 __devinitdata = NULL; +static struct pci_dev *dev_qs3000 __devinitdata = NULL; + +static int __devinit +setup_elsa_pci(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + + cs->subtyp = 0; + if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA, + PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) { + if (pci_enable_device(dev_qs1000)) return(0); - } - if (!cs->irq) { - printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n"); + cs->subtyp = ELSA_QS1000PCI; + cs->irq = dev_qs1000->irq; + cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1); + cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3); + } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA, + PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) { + if (pci_enable_device(dev_qs3000)) return(0); - } + cs->subtyp = ELSA_QS3000PCI; + cs->irq = dev_qs3000->irq; + cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1); + cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3); + } else { + printk(KERN_WARNING "Elsa: No PCI card found\n"); + return(0); + } + if (!cs->irq) { + printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n"); + return(0); + } + + if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) { + printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n"); + return(0); + } + if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) { + printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n"); + printk(KERN_WARNING "Elsa: If your system hangs now, read\n"); + printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n"); + } + cs->hw.elsa.ale = cs->hw.elsa.base; + cs->hw.elsa.isac = cs->hw.elsa.base +1; + cs->hw.elsa.hscx = cs->hw.elsa.base +1; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + cs->hw.elsa.timer = 0; + cs->hw.elsa.trig = 0; + cs->irq_flags |= IRQF_SHARED; + printk(KERN_INFO + "Elsa: %s defined at %#lx/0x%x IRQ %d\n", + Elsa_Types[cs->subtyp], + cs->hw.elsa.base, + cs->hw.elsa.cfg, + cs->irq); + + return (1); +} - if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) { - printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n"); - return(0); - } - if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) { - printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n"); - printk(KERN_WARNING "Elsa: If your system hangs now, read\n"); - printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n"); - } - cs->hw.elsa.ale = cs->hw.elsa.base; - cs->hw.elsa.isac = cs->hw.elsa.base +1; - cs->hw.elsa.hscx = cs->hw.elsa.base +1; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - cs->hw.elsa.timer = 0; - cs->hw.elsa.trig = 0; - cs->irq_flags |= IRQF_SHARED; - printk(KERN_INFO - "Elsa: %s defined at %#lx/0x%x IRQ %d\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base, - cs->hw.elsa.cfg, - cs->irq); #else - printk(KERN_WARNING "Elsa: Elsa PCI and NO_PCI_BIOS\n"); - printk(KERN_WARNING "Elsa: unable to config Elsa PCI\n"); - return (0); + +static int __devinit +setup_elsa_pci(struct IsdnCard *card) +{ + return (1); +} #endif /* CONFIG_PCI */ - } else - return (0); + +static int __devinit +setup_elsa_common(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + u_char val; + int bytecnt; switch (cs->subtyp) { case ELSA_PC: @@ -1104,8 +1130,7 @@ setup_elsa(struct IsdnCard *card) here, it would fail. */ if (cs->typ != ISDN_CTYPE_ELSA_PCMCIA && !request_region(cs->hw.elsa.base, bytecnt, "elsa isdn")) { printk(KERN_WARNING - "HiSax: %s config port %#lx-%#lx already in use\n", - CardType[card->typ], + "HiSax: ELSA config port %#lx-%#lx already in use\n", cs->hw.elsa.base, cs->hw.elsa.base + bytecnt); return (0); @@ -1113,8 +1138,7 @@ setup_elsa(struct IsdnCard *card) if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) { if (!request_region(cs->hw.elsa.cfg, 0x80, "elsa isdn pci")) { printk(KERN_WARNING - "HiSax: %s pci port %x-%x already in use\n", - CardType[card->typ], + "HiSax: ELSA pci port %x-%x already in use\n", cs->hw.elsa.cfg, cs->hw.elsa.cfg + 0x80); release_region(cs->hw.elsa.base, bytecnt); @@ -1186,3 +1210,41 @@ setup_elsa(struct IsdnCard *card) } return (1); } + +int __devinit +setup_elsa(struct IsdnCard *card) +{ + int rc; + struct IsdnCardState *cs = card->cs; + char tmp[64]; + + strcpy(tmp, Elsa_revision); + printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp)); + cs->hw.elsa.ctrl_reg = 0; + cs->hw.elsa.status = 0; + cs->hw.elsa.MFlag = 0; + cs->subtyp = 0; + + if (cs->typ == ISDN_CTYPE_ELSA) { + rc = setup_elsa_isa(card); + if (!rc) + return (0); + + } else if (cs->typ == ISDN_CTYPE_ELSA_PNP) { + rc = setup_elsa_isapnp(card); + if (!rc) + return (0); + + } else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA) + setup_elsa_pcmcia(card); + + else if (cs->typ == ISDN_CTYPE_ELSA_PCI) { + rc = setup_elsa_pci(card); + if (!rc) + return (0); + + } else + return (0); + + return setup_elsa_common(card); +} diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c index 8d9864453a23..5c46a7130e06 100644 --- a/drivers/isdn/hisax/hfc_2bds0.c +++ b/drivers/isdn/hisax/hfc_2bds0.c @@ -1019,7 +1019,8 @@ hfc_dbusy_timer(struct IsdnCardState *cs) static unsigned int *init_send_hfcd(int cnt) { - int i, *send; + int i; + unsigned *send; if (!(send = kmalloc(cnt * sizeof(unsigned int), GFP_ATOMIC))) { printk(KERN_WARNING diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c index 60843b3f3b6f..98b0149bca68 100644 --- a/drivers/isdn/hisax/hfc_usb.c +++ b/drivers/isdn/hisax/hfc_usb.c @@ -1,7 +1,7 @@ /* * hfc_usb.c * - * $Id: hfc_usb.c,v 2.3.2.20 2007/08/20 14:07:54 mbachem Exp $ + * $Id: hfc_usb.c,v 2.3.2.24 2007/10/14 08:40:29 mbachem Exp $ * * modular HiSax ISDN driver for Colognechip HFC-S USB chip * @@ -45,7 +45,7 @@ #include "hfc_usb.h" static const char *hfcusb_revision = - "$Revision: 2.3.2.20 $ $Date: 2007/08/20 14:07:54 $ "; + "$Revision: 2.3.2.24 $ $Date: 2007/10/14 08:40:29 $ "; /* Hisax debug support * debug flags defined in hfc_usb.h as HFCUSB_DBG_[*] @@ -126,6 +126,12 @@ static struct usb_device_id hfcusb_idtab[] = { {LED_SCHEME1, {0x80, -64, -32, -16}, "Twister ISDN TA"}), }, + { + USB_DEVICE(0x071d, 0x1005), + .driver_info = (unsigned long) &((hfcsusb_vdata) + {LED_SCHEME1, {0x02, 0, 0x01, 0x04}, + "Eicon DIVA USB 4.0"}), + }, { } }; @@ -187,7 +193,7 @@ typedef struct hfcusb_data { struct usb_ctrlrequest ctrl_write; /* buffer for control write request */ struct usb_ctrlrequest ctrl_read; /* same for read request */ - __u8 old_led_state, led_state, led_new_data, led_b_active; + __u8 old_led_state, led_state; volatile __u8 threshold_mask; /* threshold actually reported */ volatile __u8 bch_enables; /* or mask for sctrl_r and sctrl register values */ @@ -263,7 +269,7 @@ ctrl_complete(struct urb *urb) ctrl_start_transfer(hfc); /* start next transfer */ } -} /* ctrl_complete */ +} /* write led data to auxport & invert if necessary */ static void @@ -276,18 +282,18 @@ write_led(hfcusb_data * hfc, __u8 led_state) } static void -set_led_bit(hfcusb_data * hfc, signed short led_bits, int unset) +set_led_bit(hfcusb_data * hfc, signed short led_bits, int on) { - if (unset) { + if (on) { if (led_bits < 0) - hfc->led_state |= abs(led_bits); + hfc->led_state &= ~abs(led_bits); else - hfc->led_state &= ~led_bits; + hfc->led_state |= led_bits; } else { if (led_bits < 0) - hfc->led_state &= ~abs(led_bits); + hfc->led_state |= abs(led_bits); else - hfc->led_state |= led_bits; + hfc->led_state &= ~led_bits; } } @@ -304,34 +310,34 @@ handle_led(hfcusb_data * hfc, int event) switch (event) { case LED_POWER_ON: - set_led_bit(hfc, driver_info->led_bits[0], 0); - set_led_bit(hfc, driver_info->led_bits[1], 1); - set_led_bit(hfc, driver_info->led_bits[2], 1); - set_led_bit(hfc, driver_info->led_bits[3], 1); + set_led_bit(hfc, driver_info->led_bits[0], 1); + set_led_bit(hfc, driver_info->led_bits[1], 0); + set_led_bit(hfc, driver_info->led_bits[2], 0); + set_led_bit(hfc, driver_info->led_bits[3], 0); break; case LED_POWER_OFF: - set_led_bit(hfc, driver_info->led_bits[0], 1); - set_led_bit(hfc, driver_info->led_bits[1], 1); - set_led_bit(hfc, driver_info->led_bits[2], 1); - set_led_bit(hfc, driver_info->led_bits[3], 1); + set_led_bit(hfc, driver_info->led_bits[0], 0); + set_led_bit(hfc, driver_info->led_bits[1], 0); + set_led_bit(hfc, driver_info->led_bits[2], 0); + set_led_bit(hfc, driver_info->led_bits[3], 0); break; case LED_S0_ON: - set_led_bit(hfc, driver_info->led_bits[1], 0); + set_led_bit(hfc, driver_info->led_bits[1], 1); break; case LED_S0_OFF: - set_led_bit(hfc, driver_info->led_bits[1], 1); + set_led_bit(hfc, driver_info->led_bits[1], 0); break; case LED_B1_ON: - set_led_bit(hfc, driver_info->led_bits[2], 0); + set_led_bit(hfc, driver_info->led_bits[2], 1); break; case LED_B1_OFF: - set_led_bit(hfc, driver_info->led_bits[2], 1); + set_led_bit(hfc, driver_info->led_bits[2], 0); break; case LED_B2_ON: - set_led_bit(hfc, driver_info->led_bits[3], 0); + set_led_bit(hfc, driver_info->led_bits[3], 1); break; case LED_B2_OFF: - set_led_bit(hfc, driver_info->led_bits[3], 1); + set_led_bit(hfc, driver_info->led_bits[3], 0); break; } write_led(hfc, hfc->led_state); @@ -1159,7 +1165,6 @@ hfc_usb_init(hfcusb_data * hfc) hfc->l1_activated = 0; hfc->disc_flag = 0; hfc->led_state = 0; - hfc->led_new_data = 0; hfc->old_led_state = 0; /* init the t3 timer */ @@ -1514,20 +1519,18 @@ hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) /* callback for unplugged USB device */ static void -hfc_usb_disconnect(struct usb_interface - *intf) +hfc_usb_disconnect(struct usb_interface *intf) { hfcusb_data *context = usb_get_intfdata(intf); int i; handle_led(context, LED_POWER_OFF); - schedule_timeout((10 * HZ) / 1000); + schedule_timeout(HZ / 100); printk(KERN_INFO "HFC-S USB: device disconnect\n"); context->disc_flag = 1; usb_set_intfdata(intf, NULL); - if (!context) - return; + if (timer_pending(&context->t3_timer)) del_timer(&context->t3_timer); if (timer_pending(&context->t4_timer)) diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h index 3cd8d5ba239b..34733c903df7 100644 --- a/drivers/isdn/hisax/hisax.h +++ b/drivers/isdn/hisax/hisax.h @@ -202,7 +202,7 @@ struct Layer1 { void *hardware; struct BCState *bcs; struct PStack **stlistp; - long Flags; + unsigned long Flags; struct FsmInst l1m; struct FsmTimer timer; void (*l1l2) (struct PStack *, int, void *); diff --git a/drivers/isdn/hisax/hisax_if.h b/drivers/isdn/hisax/hisax_if.h index 4898fce2d509..aa7c94037b2b 100644 --- a/drivers/isdn/hisax/hisax_if.h +++ b/drivers/isdn/hisax/hisax_if.h @@ -56,7 +56,7 @@ struct hisax_d_if { struct IsdnCardState *cs; struct hisax_b_if *b_if[2]; struct sk_buff_head erq; - long ph_state; + unsigned long ph_state; }; int hisax_register(struct hisax_d_if *hisax_if, struct hisax_b_if *b_if[], diff --git a/drivers/isdn/hisax/nj_s.c b/drivers/isdn/hisax/nj_s.c index fa2db87667c8..a895dfed40e5 100644 --- a/drivers/isdn/hisax/nj_s.c +++ b/drivers/isdn/hisax/nj_s.c @@ -151,7 +151,7 @@ NETjet_S_card_msg(struct IsdnCardState *cs, int mt, void *arg) static int __devinit njs_pci_probe(struct pci_dev *dev_netjet, struct IsdnCardState *cs) { - int cfg; + u32 cfg; if (pci_enable_device(dev_netjet)) return(0); diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c index ad06f3cc60fb..03dfc32166a0 100644 --- a/drivers/isdn/hisax/sedlbauer.c +++ b/drivers/isdn/hisax/sedlbauer.c @@ -518,8 +518,6 @@ Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -static struct pci_dev *dev_sedl __devinitdata = NULL; - #ifdef __ISAPNP__ static struct isapnp_device_id sedl_ids[] __devinitdata = { { ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01), @@ -533,15 +531,158 @@ static struct isapnp_device_id sedl_ids[] __devinitdata = { static struct isapnp_device_id *ipid __devinitdata = &sedl_ids[0]; static struct pnp_card *pnp_c __devinitdata = NULL; -#endif + +static int __devinit +setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt) +{ + struct IsdnCardState *cs = card->cs; + struct pnp_dev *pnp_d; + + if (!isapnp_present()) + return -1; + + while(ipid->card_vendor) { + if ((pnp_c = pnp_find_card(ipid->card_vendor, + ipid->card_device, pnp_c))) { + pnp_d = NULL; + if ((pnp_d = pnp_find_dev(pnp_c, + ipid->vendor, ipid->function, pnp_d))) { + int err; + + printk(KERN_INFO "HiSax: %s detected\n", + (char *)ipid->driver_data); + pnp_disable_dev(pnp_d); + err = pnp_activate_dev(pnp_d); + if (err<0) { + printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", + __FUNCTION__, err); + return(0); + } + card->para[1] = pnp_port_start(pnp_d, 0); + card->para[0] = pnp_irq(pnp_d, 0); + + if (!card->para[0] || !card->para[1]) { + printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n", + card->para[0], card->para[1]); + pnp_disable_dev(pnp_d); + return(0); + } + cs->hw.sedl.cfg_reg = card->para[1]; + cs->irq = card->para[0]; + if (ipid->function == ISAPNP_FUNCTION(0x2)) { + cs->subtyp = SEDL_SPEED_FAX; + cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; + *bytecnt = 16; + } else { + cs->subtyp = SEDL_SPEED_CARD_WIN; + cs->hw.sedl.chip = SEDL_CHIP_TEST; + } + + return (1); + } else { + printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n"); + return(0); + } + } + ipid++; + pnp_c = NULL; + } + + printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n"); + return -1; +} +#else + +static int __devinit +setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt) +{ + return -1; +} +#endif /* __ISAPNP__ */ + +#ifdef CONFIG_PCI +static struct pci_dev *dev_sedl __devinitdata = NULL; + +static int __devinit +setup_sedlbauer_pci(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + u16 sub_vendor_id, sub_id; + + if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET, + PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) { + if (pci_enable_device(dev_sedl)) + return(0); + cs->irq = dev_sedl->irq; + if (!cs->irq) { + printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n"); + return(0); + } + cs->hw.sedl.cfg_reg = pci_resource_start(dev_sedl, 0); + } else { + printk(KERN_WARNING "Sedlbauer: No PCI card found\n"); + return(0); + } + cs->irq_flags |= IRQF_SHARED; + cs->hw.sedl.bus = SEDL_BUS_PCI; + sub_vendor_id = dev_sedl->subsystem_vendor; + sub_id = dev_sedl->subsystem_device; + printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n", + sub_vendor_id, sub_id); + printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n", + cs->hw.sedl.cfg_reg); + if (sub_id != PCI_SUB_ID_SEDLBAUER) { + printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id); + return(0); + } + if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) { + cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; + cs->subtyp = SEDL_SPEEDFAX_PYRAMID; + } else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) { + cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; + cs->subtyp = SEDL_SPEEDFAX_PCI; + } else if (sub_vendor_id == PCI_SUBVENDOR_HST_SAPHIR3) { + cs->hw.sedl.chip = SEDL_CHIP_IPAC; + cs->subtyp = HST_SAPHIR3; + } else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) { + cs->hw.sedl.chip = SEDL_CHIP_IPAC; + cs->subtyp = SEDL_SPEED_PCI; + } else { + printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n", + sub_vendor_id); + return(0); + } + + cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON; + cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF; + byteout(cs->hw.sedl.cfg_reg, 0xff); + byteout(cs->hw.sedl.cfg_reg, 0x00); + byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd); + byteout(cs->hw.sedl.cfg_reg+ 5, 0); /* disable all IRQ */ + byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on); + mdelay(2); + byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off); + mdelay(10); + + return (1); +} + +#else + +static int __devinit +setup_sedlbauer_pci(struct IsdnCard *card) +{ + return (1); +} + +#endif /* CONFIG_PCI */ int __devinit setup_sedlbauer(struct IsdnCard *card) { - int bytecnt, ver, val; + int bytecnt = 8, ver, val, rc; struct IsdnCardState *cs = card->cs; char tmp[64]; - u16 sub_vendor_id, sub_id; strcpy(tmp, Sedlbauer_revision); printk(KERN_INFO "HiSax: Sedlbauer driver Rev. %s\n", HiSax_getrev(tmp)); @@ -569,124 +710,21 @@ setup_sedlbauer(struct IsdnCard *card) bytecnt = 16; } } else { -#ifdef __ISAPNP__ - if (isapnp_present()) { - struct pnp_dev *pnp_d; - while(ipid->card_vendor) { - if ((pnp_c = pnp_find_card(ipid->card_vendor, - ipid->card_device, pnp_c))) { - pnp_d = NULL; - if ((pnp_d = pnp_find_dev(pnp_c, - ipid->vendor, ipid->function, pnp_d))) { - int err; - - printk(KERN_INFO "HiSax: %s detected\n", - (char *)ipid->driver_data); - pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err<0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); - return(0); - } - card->para[1] = pnp_port_start(pnp_d, 0); - card->para[0] = pnp_irq(pnp_d, 0); - - if (!card->para[0] || !card->para[1]) { - printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n", - card->para[0], card->para[1]); - pnp_disable_dev(pnp_d); - return(0); - } - cs->hw.sedl.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - if (ipid->function == ISAPNP_FUNCTION(0x2)) { - cs->subtyp = SEDL_SPEED_FAX; - cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; - bytecnt = 16; - } else { - cs->subtyp = SEDL_SPEED_CARD_WIN; - cs->hw.sedl.chip = SEDL_CHIP_TEST; - } - goto ready; - } else { - printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n"); - return(0); - } - } - ipid++; - pnp_c = NULL; - } - if (!ipid->card_vendor) { - printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n"); - } - } -#endif -/* Probe for Sedlbauer speed pci */ -#ifdef CONFIG_PCI - if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET, - PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) { - if (pci_enable_device(dev_sedl)) - return(0); - cs->irq = dev_sedl->irq; - if (!cs->irq) { - printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n"); - return(0); - } - cs->hw.sedl.cfg_reg = pci_resource_start(dev_sedl, 0); - } else { - printk(KERN_WARNING "Sedlbauer: No PCI card found\n"); - return(0); - } - cs->irq_flags |= IRQF_SHARED; - cs->hw.sedl.bus = SEDL_BUS_PCI; - sub_vendor_id = dev_sedl->subsystem_vendor; - sub_id = dev_sedl->subsystem_device; - printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n", - sub_vendor_id, sub_id); - printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n", - cs->hw.sedl.cfg_reg); - if (sub_id != PCI_SUB_ID_SEDLBAUER) { - printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id); - return(0); - } - if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) { - cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; - cs->subtyp = SEDL_SPEEDFAX_PYRAMID; - } else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) { - cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; - cs->subtyp = SEDL_SPEEDFAX_PCI; - } else if (sub_vendor_id == PCI_SUBVENDOR_HST_SAPHIR3) { - cs->hw.sedl.chip = SEDL_CHIP_IPAC; - cs->subtyp = HST_SAPHIR3; - } else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) { - cs->hw.sedl.chip = SEDL_CHIP_IPAC; - cs->subtyp = SEDL_SPEED_PCI; - } else { - printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n", - sub_vendor_id); - return(0); - } + rc = setup_sedlbauer_isapnp(card, &bytecnt); + if (!rc) + return (0); + if (rc > 0) + goto ready; + + /* Probe for Sedlbauer speed pci */ + rc = setup_sedlbauer_pci(card); + if (!rc) + return (0); + bytecnt = 256; - cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON; - cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF; - byteout(cs->hw.sedl.cfg_reg, 0xff); - byteout(cs->hw.sedl.cfg_reg, 0x00); - byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd); - byteout(cs->hw.sedl.cfg_reg+ 5, 0); /* disable all IRQ */ - byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on); - mdelay(2); - byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off); - mdelay(10); -#else - printk(KERN_WARNING "Sedlbauer: NO_PCI_BIOS\n"); - return (0); -#endif /* CONFIG_PCI */ } -#ifdef __ISAPNP__ ready: -#endif /* In case of the sedlbauer pcmcia card, this region is in use, * reserved for us by the card manager. So we do not check it diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c index d09f6d033f15..4393003ae162 100644 --- a/drivers/isdn/hisax/telespci.c +++ b/drivers/isdn/hisax/telespci.c @@ -295,11 +295,12 @@ setup_telespci(struct IsdnCard *card) #ifdef __BIG_ENDIAN #error "not running on big endian machines now" #endif + strcpy(tmp, telespci_revision); printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", HiSax_getrev(tmp)); if (cs->typ != ISDN_CTYPE_TELESPCI) return (0); -#ifdef CONFIG_PCI + if ((dev_tel = pci_find_device (PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) { if (pci_enable_device(dev_tel)) return(0); @@ -317,11 +318,6 @@ setup_telespci(struct IsdnCard *card) printk(KERN_WARNING "TelesPCI: No PCI card found\n"); return(0); } -#else - printk(KERN_WARNING "HiSax: Teles/PCI and NO_PCI_BIOS\n"); - printk(KERN_WARNING "HiSax: Teles/PCI unable to config\n"); - return (0); -#endif /* CONFIG_PCI */ /* Initialize Zoran PCI controller */ writel(0x00000000, cs->hw.teles0.membase + 0x28); diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c index 3aeceaf9769e..39129b94f8be 100644 --- a/drivers/isdn/hisax/w6692.c +++ b/drivers/isdn/hisax/w6692.c @@ -1009,7 +1009,7 @@ setup_w6692(struct IsdnCard *card) printk(KERN_INFO "HiSax: W6692 driver Rev. %s\n", HiSax_getrev(tmp)); if (cs->typ != ISDN_CTYPE_W6692) return (0); -#ifdef CONFIG_PCI + while (id_list[id_idx].vendor_id) { dev_w6692 = pci_find_device(id_list[id_idx].vendor_id, id_list[id_idx].device_id, @@ -1061,11 +1061,6 @@ setup_w6692(struct IsdnCard *card) cs->hw.w6692.iobase + 255); return (0); } -#else - printk(KERN_WARNING "HiSax: W6692 and NO_PCI_BIOS\n"); - printk(KERN_WARNING "HiSax: W6692 unable to config\n"); - return (0); -#endif /* CONFIG_PCI */ printk(KERN_INFO "HiSax: %s config irq:%d I/O:%x\n", diff --git a/drivers/isdn/hysdn/hysdn_init.c b/drivers/isdn/hysdn/hysdn_init.c index 9e01748a176e..b7cc5c2f08c6 100644 --- a/drivers/isdn/hysdn/hysdn_init.c +++ b/drivers/isdn/hysdn/hysdn_init.c @@ -20,10 +20,15 @@ #include "hysdn_defs.h" static struct pci_device_id hysdn_pci_tbl[] = { - {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_METRO}, - {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2}, - {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_ERGO}, - {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO}, + { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, + PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_METRO, 0, 0, BD_METRO }, + { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, + PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2, 0, 0, BD_CHAMP2 }, + { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, + PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_ERGO, 0, 0, BD_ERGO }, + { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, + PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO, 0, 0, BD_ERGO }, + { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(pci, hysdn_pci_tbl); @@ -34,128 +39,7 @@ MODULE_LICENSE("GPL"); static char *hysdn_init_revision = "$Revision: 1.6.6.6 $"; static int cardmax; /* number of found cards */ hysdn_card *card_root = NULL; /* pointer to first card */ - -/**********************************************/ -/* table assigning PCI-sub ids to board types */ -/* the last entry contains all 0 */ -/**********************************************/ -static struct { - unsigned short subid; /* PCI sub id */ - unsigned char cardtyp; /* card type assigned */ -} pci_subid_map[] = { - - { - PCI_SUBDEVICE_ID_HYPERCOPE_METRO, BD_METRO - }, - { - PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2, BD_CHAMP2 - }, - { - PCI_SUBDEVICE_ID_HYPERCOPE_ERGO, BD_ERGO - }, - { - PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO, BD_ERGO - }, - { - 0, 0 - } /* terminating entry */ -}; - - -/*********************************************************************/ -/* search_cards searches for available cards in the pci config data. */ -/* If a card is found, the card structure is allocated and the cards */ -/* ressources are reserved. cardmax is incremented. */ -/*********************************************************************/ -static void -search_cards(void) -{ - struct pci_dev *akt_pcidev = NULL; - hysdn_card *card, *card_last; - int i; - - card_root = NULL; - card_last = NULL; - while ((akt_pcidev = pci_find_device(PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, - akt_pcidev)) != NULL) { - if (pci_enable_device(akt_pcidev)) - continue; - - if (!(card = kzalloc(sizeof(hysdn_card), GFP_KERNEL))) { - printk(KERN_ERR "HYSDN: unable to alloc device mem \n"); - return; - } - card->myid = cardmax; /* set own id */ - card->bus = akt_pcidev->bus->number; - card->devfn = akt_pcidev->devfn; /* slot + function */ - card->subsysid = akt_pcidev->subsystem_device; - card->irq = akt_pcidev->irq; - card->iobase = pci_resource_start(akt_pcidev, PCI_REG_PLX_IO_BASE); - card->plxbase = pci_resource_start(akt_pcidev, PCI_REG_PLX_MEM_BASE); - card->membase = pci_resource_start(akt_pcidev, PCI_REG_MEMORY_BASE); - card->brdtype = BD_NONE; /* unknown */ - card->debug_flags = DEF_DEB_FLAGS; /* set default debug */ - card->faxchans = 0; /* default no fax channels */ - card->bchans = 2; /* and 2 b-channels */ - for (i = 0; pci_subid_map[i].subid; i++) - if (pci_subid_map[i].subid == card->subsysid) { - card->brdtype = pci_subid_map[i].cardtyp; - break; - } - if (card->brdtype != BD_NONE) { - if (ergo_inithardware(card)) { - printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase); - kfree(card); - continue; - } - } else { - printk(KERN_WARNING "HYSDN: unknown card id 0x%04x\n", card->subsysid); - kfree(card); /* release mem */ - continue; - } - cardmax++; - card->next = NULL; /*end of chain */ - if (card_last) - card_last->next = card; /* pointer to next card */ - else - card_root = card; - card_last = card; /* new chain end */ - } /* device found */ -} /* search_cards */ - -/************************************************************************************/ -/* free_resources frees the acquired PCI resources and returns the allocated memory */ -/************************************************************************************/ -static void -free_resources(void) -{ - hysdn_card *card; - - while (card_root) { - card = card_root; - if (card->releasehardware) - card->releasehardware(card); /* free all hardware resources */ - card_root = card_root->next; /* remove card from chain */ - kfree(card); /* return mem */ - - } /* while card_root */ -} /* free_resources */ - -/**************************************************************************/ -/* stop_cards disables (hardware resets) all cards and disables interrupt */ -/**************************************************************************/ -static void -stop_cards(void) -{ - hysdn_card *card; - - card = card_root; /* first in chain */ - while (card) { - if (card->stopcard) - card->stopcard(card); - card = card->next; /* remove card from chain */ - } /* while card */ -} /* stop_cards */ +static hysdn_card *card_last = NULL; /* pointer to first card */ /****************************************************************************/ @@ -191,31 +75,138 @@ hysdn_getrev(const char *revision) /* and the module is added to the list in /proc/modules, otherwise an error */ /* is assumed and the module will not be kept in memory. */ /****************************************************************************/ + +static int __devinit hysdn_pci_init_one(struct pci_dev *akt_pcidev, + const struct pci_device_id *ent) +{ + hysdn_card *card; + int rc; + + rc = pci_enable_device(akt_pcidev); + if (rc) + return rc; + + if (!(card = kzalloc(sizeof(hysdn_card), GFP_KERNEL))) { + printk(KERN_ERR "HYSDN: unable to alloc device mem \n"); + rc = -ENOMEM; + goto err_out; + } + card->myid = cardmax; /* set own id */ + card->bus = akt_pcidev->bus->number; + card->devfn = akt_pcidev->devfn; /* slot + function */ + card->subsysid = akt_pcidev->subsystem_device; + card->irq = akt_pcidev->irq; + card->iobase = pci_resource_start(akt_pcidev, PCI_REG_PLX_IO_BASE); + card->plxbase = pci_resource_start(akt_pcidev, PCI_REG_PLX_MEM_BASE); + card->membase = pci_resource_start(akt_pcidev, PCI_REG_MEMORY_BASE); + card->brdtype = BD_NONE; /* unknown */ + card->debug_flags = DEF_DEB_FLAGS; /* set default debug */ + card->faxchans = 0; /* default no fax channels */ + card->bchans = 2; /* and 2 b-channels */ + card->brdtype = ent->driver_data; + + if (ergo_inithardware(card)) { + printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase); + rc = -EBUSY; + goto err_out_card; + } + + cardmax++; + card->next = NULL; /*end of chain */ + if (card_last) + card_last->next = card; /* pointer to next card */ + else + card_root = card; + card_last = card; /* new chain end */ + + pci_set_drvdata(akt_pcidev, card); + return 0; + +err_out_card: + kfree(card); +err_out: + pci_disable_device(akt_pcidev); + return rc; +} + +static void __devexit hysdn_pci_remove_one(struct pci_dev *akt_pcidev) +{ + hysdn_card *card = pci_get_drvdata(akt_pcidev); + + pci_set_drvdata(akt_pcidev, NULL); + + if (card->stopcard) + card->stopcard(card); + +#ifdef CONFIG_HYSDN_CAPI + hycapi_capi_release(card); +#endif + + if (card->releasehardware) + card->releasehardware(card); /* free all hardware resources */ + + if (card == card_root) { + card_root = card_root->next; + if (!card_root) + card_last = NULL; + } else { + hysdn_card *tmp = card_root; + while (tmp) { + if (tmp->next == card) + tmp->next = card->next; + card_last = tmp; + tmp = tmp->next; + } + } + + kfree(card); + pci_disable_device(akt_pcidev); +} + +static struct pci_driver hysdn_pci_driver = { + .name = "hysdn", + .id_table = hysdn_pci_tbl, + .probe = hysdn_pci_init_one, + .remove = __devexit_p(hysdn_pci_remove_one), +}; + +static int hysdn_have_procfs; + static int __init hysdn_init(void) { char tmp[50]; + int rc; strcpy(tmp, hysdn_init_revision); printk(KERN_NOTICE "HYSDN: module Rev: %s loaded\n", hysdn_getrev(tmp)); strcpy(tmp, hysdn_net_revision); printk(KERN_NOTICE "HYSDN: network interface Rev: %s \n", hysdn_getrev(tmp)); - search_cards(); + + rc = pci_register_driver(&hysdn_pci_driver); + if (rc) + return rc; + printk(KERN_INFO "HYSDN: %d card(s) found.\n", cardmax); - if (hysdn_procconf_init()) { - free_resources(); /* proc file_sys not created */ - return (-1); - } + if (!hysdn_procconf_init()) + hysdn_have_procfs = 1; + #ifdef CONFIG_HYSDN_CAPI if(cardmax > 0) { if(hycapi_init()) { printk(KERN_ERR "HYCAPI: init failed\n"); - return(-1); + + if (hysdn_have_procfs) + hysdn_procconf_release(); + + pci_unregister_driver(&hysdn_pci_driver); + return -ESPIPE; } } #endif /* CONFIG_HYSDN_CAPI */ - return (0); /* no error */ + + return 0; /* no error */ } /* init_module */ @@ -230,20 +221,15 @@ hysdn_init(void) static void __exit hysdn_exit(void) { + if (hysdn_have_procfs) + hysdn_procconf_release(); + + pci_unregister_driver(&hysdn_pci_driver); + #ifdef CONFIG_HYSDN_CAPI - hysdn_card *card; -#endif /* CONFIG_HYSDN_CAPI */ - stop_cards(); -#ifdef CONFIG_HYSDN_CAPI - card = card_root; /* first in chain */ - while (card) { - hycapi_capi_release(card); - card = card->next; /* remove card from chain */ - } /* while card */ hycapi_cleanup(); #endif /* CONFIG_HYSDN_CAPI */ - hysdn_procconf_release(); - free_resources(); + printk(KERN_NOTICE "HYSDN: module unloaded\n"); } /* cleanup_module */ diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index 7c9cb7e19f2e..b39d1f5b378e 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -328,7 +328,7 @@ isdn_net_autohup(void) l->cps = (l->transcount * HZ) / (jiffies - last_jiffies); l->transcount = 0; if (dev->net_verbose > 3) - printk(KERN_DEBUG "%s: %d bogocps\n", l->name, l->cps); + printk(KERN_DEBUG "%s: %d bogocps\n", p->dev->name, l->cps); if ((l->flags & ISDN_NET_CONNECTED) && (!l->dialstate)) { anymore = 1; l->huptimer++; @@ -350,12 +350,12 @@ isdn_net_autohup(void) if (l->hupflags & ISDN_CHARGEHUP) { if (l->hupflags & ISDN_WAITCHARGE) { printk(KERN_DEBUG "isdn_net: Hupflags of %s are %X\n", - l->name, l->hupflags); + p->dev->name, l->hupflags); isdn_net_hangup(p->dev); } else if (time_after(jiffies, l->chargetime + l->chargeint)) { printk(KERN_DEBUG "isdn_net: %s: chtime = %lu, chint = %d\n", - l->name, l->chargetime, l->chargeint); + p->dev->name, l->chargetime, l->chargeint); isdn_net_hangup(p->dev); } } else @@ -442,8 +442,8 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c) #endif isdn_net_lp_disconnected(lp); isdn_all_eaz(lp->isdn_device, lp->isdn_channel); - printk(KERN_INFO "%s: remote hangup\n", lp->name); - printk(KERN_INFO "%s: Chargesum is %d\n", lp->name, + printk(KERN_INFO "%s: remote hangup\n", p->dev->name); + printk(KERN_INFO "%s: Chargesum is %d\n", p->dev->name, lp->charge); isdn_net_unbind_channel(lp); return 1; @@ -487,7 +487,7 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c) isdn_net_add_to_bundle(nd, lp); } } - printk(KERN_INFO "isdn_net: %s connected\n", lp->name); + printk(KERN_INFO "isdn_net: %s connected\n", p->dev->name); /* If first Chargeinfo comes before B-Channel connect, * we correct the timestamp here. */ @@ -534,7 +534,7 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c) lp->hupflags |= ISDN_HAVECHARGE; lp->chargetime = jiffies; printk(KERN_DEBUG "isdn_net: Got CINF chargetime of %s now %lu\n", - lp->name, lp->chargetime); + p->dev->name, lp->chargetime); return 1; } } @@ -565,7 +565,7 @@ isdn_net_dial(void) #ifdef ISDN_DEBUG_NET_DIAL if (lp->dialstate) - printk(KERN_DEBUG "%s: dialstate=%d\n", lp->name, lp->dialstate); + printk(KERN_DEBUG "%s: dialstate=%d\n", p->dev->name, lp->dialstate); #endif switch (lp->dialstate) { case 0: @@ -578,7 +578,7 @@ isdn_net_dial(void) lp->dial = lp->phone[1]; if (!lp->dial) { printk(KERN_WARNING "%s: phone number deleted?\n", - lp->name); + p->dev->name); isdn_net_hangup(p->dev); break; } @@ -632,13 +632,13 @@ isdn_net_dial(void) cmd.arg = lp->isdn_channel; if (!lp->dial) { printk(KERN_WARNING "%s: phone number deleted?\n", - lp->name); + p->dev->name); isdn_net_hangup(p->dev); break; } if (!strncmp(lp->dial->num, "LEASED", strlen("LEASED"))) { lp->dialstate = 4; - printk(KERN_INFO "%s: Open leased line ...\n", lp->name); + printk(KERN_INFO "%s: Open leased line ...\n", p->dev->name); } else { if(lp->dialtimeout > 0) if (time_after(jiffies, lp->dialstarted + lp->dialtimeout)) { @@ -688,7 +688,7 @@ isdn_net_dial(void) dev->usage[i] |= ISDN_USAGE_OUTGOING; isdn_info_update(); } - printk(KERN_INFO "%s: dialing %d %s... %s\n", lp->name, + printk(KERN_INFO "%s: dialing %d %s... %s\n", p->dev->name, lp->dialretry, cmd.parm.setup.phone, (cmd.parm.setup.si1 == 1) ? "DOV" : ""); lp->dtimer = 0; @@ -797,7 +797,7 @@ isdn_net_dial(void) */ if (lp->dtimer++ > lp->cbdelay) { - printk(KERN_INFO "%s: hangup waiting for callback ...\n", lp->name); + printk(KERN_INFO "%s: hangup waiting for callback ...\n", p->dev->name); lp->dtimer = 0; lp->dialstate = 4; cmd.driver = lp->isdn_device; @@ -810,7 +810,7 @@ isdn_net_dial(void) break; default: printk(KERN_WARNING "isdn_net: Illegal dialstate %d for device %s\n", - lp->dialstate, lp->name); + lp->dialstate, p->dev->name); } p = (isdn_net_dev *) p->next; } @@ -836,11 +836,11 @@ isdn_net_hangup(struct net_device *d) if (slp->flags & ISDN_NET_CONNECTED) { printk(KERN_INFO "isdn_net: hang up slave %s before %s\n", - slp->name, lp->name); + lp->slave->name, d->name); isdn_net_hangup(lp->slave); } } - printk(KERN_INFO "isdn_net: local hangup %s\n", lp->name); + printk(KERN_INFO "isdn_net: local hangup %s\n", d->name); #ifdef CONFIG_ISDN_PPP if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) isdn_ppp_free(lp); @@ -858,7 +858,7 @@ isdn_net_hangup(struct net_device *d) cmd.command = ISDN_CMD_HANGUP; cmd.arg = lp->isdn_channel; isdn_command(&cmd); - printk(KERN_INFO "%s: Chargesum is %d\n", lp->name, lp->charge); + printk(KERN_INFO "%s: Chargesum is %d\n", d->name, lp->charge); isdn_all_eaz(lp->isdn_device, lp->isdn_channel); } isdn_net_unbind_channel(lp); @@ -885,7 +885,7 @@ isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp) /* fall back to old isdn_net_log_packet method() */ char * buf = skb->data; - printk(KERN_DEBUG "isdn_net: protocol %04x is buggy, dev %s\n", skb->protocol, lp->name); + printk(KERN_DEBUG "isdn_net: protocol %04x is buggy, dev %s\n", skb->protocol, lp->netdev->dev->name); p = buf; proto = ETH_P_IP; switch (lp->p_encap) { @@ -1023,7 +1023,7 @@ void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb) ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb); if (ret != len) { /* we should never get here */ - printk(KERN_WARNING "%s: HL driver queue full\n", lp->name); + printk(KERN_WARNING "%s: HL driver queue full\n", lp->netdev->dev->name); goto error; } @@ -1461,7 +1461,7 @@ isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) mod_timer(&lp->cisco_timer, expires); printk(KERN_INFO "%s: Keepalive period set " "to %d seconds.\n", - lp->name, lp->cisco_keepalive_period); + dev->name, lp->cisco_keepalive_period); } break; @@ -1512,7 +1512,7 @@ isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data) lp->cisco_line_state = 0; printk (KERN_WARNING "UPDOWN: Line protocol on Interface %s," - " changed state to down\n", lp->name); + " changed state to down\n", lp->netdev->dev->name); /* should stop routing higher-level data accross */ } else if ((!lp->cisco_line_state) && (myseq_diff >= 0) && (myseq_diff <= 2)) { @@ -1520,14 +1520,14 @@ isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data) lp->cisco_line_state = 1; printk (KERN_WARNING "UPDOWN: Line protocol on Interface %s," - " changed state to up\n", lp->name); + " changed state to up\n", lp->netdev->dev->name); /* restart routing higher-level data accross */ } if (lp->cisco_debserint) printk (KERN_DEBUG "%s: HDLC " "myseq %lu, mineseen %lu%c, yourseen %lu, %s\n", - lp->name, last_cisco_myseq, lp->cisco_mineseen, + lp->netdev->dev->name, last_cisco_myseq, lp->cisco_mineseen, ((last_cisco_myseq == lp->cisco_mineseen) ? '*' : 040), lp->cisco_yourseq, ((lp->cisco_line_state) ? "line up" : "line down")); @@ -1682,7 +1682,7 @@ isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb) "remote ip: %d.%d.%d.%d, " "local ip: %d.%d.%d.%d " "mask: %d.%d.%d.%d\n", - lp->name, + lp->netdev->dev->name, HIPQUAD(addr), HIPQUAD(local), HIPQUAD(mask)); @@ -1690,7 +1690,7 @@ isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb) slarp_reply_out: printk(KERN_INFO "%s: got invalid slarp " "reply (%d.%d.%d.%d/%d.%d.%d.%d) " - "- ignored\n", lp->name, + "- ignored\n", lp->netdev->dev->name, HIPQUAD(addr), HIPQUAD(mask)); break; case CISCO_SLARP_KEEPALIVE: @@ -1701,7 +1701,8 @@ isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb) lp->cisco_last_slarp_in) { printk(KERN_DEBUG "%s: Keepalive period mismatch - " "is %d but should be %d.\n", - lp->name, period, lp->cisco_keepalive_period); + lp->netdev->dev->name, period, + lp->cisco_keepalive_period); } lp->cisco_last_slarp_in = jiffies; p += get_u32(p, &my_seq); @@ -1732,12 +1733,12 @@ isdn_net_ciscohdlck_receive(isdn_net_local *lp, struct sk_buff *skb) if (addr != CISCO_ADDR_UNICAST && addr != CISCO_ADDR_BROADCAST) { printk(KERN_WARNING "%s: Unknown Cisco addr 0x%02x\n", - lp->name, addr); + lp->netdev->dev->name, addr); goto out_free; } if (ctrl != CISCO_CTRL) { printk(KERN_WARNING "%s: Unknown Cisco ctrl 0x%02x\n", - lp->name, ctrl); + lp->netdev->dev->name, ctrl); goto out_free; } @@ -1748,7 +1749,8 @@ isdn_net_ciscohdlck_receive(isdn_net_local *lp, struct sk_buff *skb) case CISCO_TYPE_CDP: if (lp->cisco_debserint) printk(KERN_DEBUG "%s: Received CDP packet. use " - "\"no cdp enable\" on cisco.\n", lp->name); + "\"no cdp enable\" on cisco.\n", + lp->netdev->dev->name); goto out_free; default: /* no special cisco protocol */ @@ -1843,7 +1845,7 @@ isdn_net_receive(struct net_device *ndev, struct sk_buff *skb) }; #endif /* CONFIG_ISDN_X25 */ printk(KERN_WARNING "%s: unknown encapsulation, dropping\n", - lp->name); + lp->netdev->dev->name); kfree_skb(skb); return; } @@ -2174,7 +2176,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup) wret = matchret; #ifdef ISDN_DEBUG_NET_ICALL printk(KERN_DEBUG "n_fi: if='%s', l.msn=%s, l.flags=%d, l.dstate=%d\n", - lp->name, lp->msn, lp->flags, lp->dialstate); + p->dev->name, lp->msn, lp->flags, lp->dialstate); #endif if ((!matchret) && /* EAZ is matching */ (((!(lp->flags & ISDN_NET_CONNECTED)) && /* but not connected */ @@ -2277,7 +2279,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup) * */ if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) { printk(KERN_INFO "incoming call, interface %s `stopped' -> rejected\n", - lp->name); + p->dev->name); return 3; } /* @@ -2286,7 +2288,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup) */ if (!isdn_net_device_started(p)) { printk(KERN_INFO "%s: incoming call, interface down -> rejected\n", - lp->name); + p->dev->name); return 3; } /* Interface is up, now see if it's a slave. If so, see if @@ -2294,8 +2296,8 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup) */ if (lp->master) { isdn_net_local *mlp = (isdn_net_local *) lp->master->priv; - printk(KERN_DEBUG "ICALLslv: %s\n", lp->name); - printk(KERN_DEBUG "master=%s\n", mlp->name); + printk(KERN_DEBUG "ICALLslv: %s\n", p->dev->name); + printk(KERN_DEBUG "master=%s\n", lp->master->name); if (mlp->flags & ISDN_NET_CONNECTED) { printk(KERN_DEBUG "master online\n"); /* Master is online, find parent-slave (master if first slave) */ @@ -2322,11 +2324,11 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup) * */ if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) { printk(KERN_INFO "incoming call for callback, interface %s `off' -> rejected\n", - lp->name); + p->dev->name); return 3; } printk(KERN_DEBUG "%s: call from %s -> %s, start callback\n", - lp->name, nr, eaz); + p->dev->name, nr, eaz); if (lp->phone[1]) { /* Grab a free ISDN-Channel */ spin_lock_irqsave(&dev->lock, flags); @@ -2340,7 +2342,8 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup) lp->msn) ) < 0) { - printk(KERN_WARNING "isdn_net_find_icall: No channel for %s\n", lp->name); + printk(KERN_WARNING "isdn_net_find_icall: No channel for %s\n", + p->dev->name); spin_unlock_irqrestore(&dev->lock, flags); return 0; } @@ -2361,11 +2364,12 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup) /* Initiate dialing by returning 2 or 4 */ return (lp->flags & ISDN_NET_CBHUP) ? 2 : 4; } else - printk(KERN_WARNING "isdn_net: %s: No phone number\n", lp->name); + printk(KERN_WARNING "isdn_net: %s: No phone number\n", + p->dev->name); return 0; } else { - printk(KERN_DEBUG "%s: call from %s -> %s accepted\n", lp->name, nr, - eaz); + printk(KERN_DEBUG "%s: call from %s -> %s accepted\n", + p->dev->name, nr, eaz); /* if this interface is dialing, it does it probably on a different device, so free this device */ if ((lp->dialstate == 4) || (lp->dialstate == 12)) { @@ -2424,7 +2428,7 @@ isdn_net_findif(char *name) isdn_net_dev *p = dev->netdev; while (p) { - if (!strcmp(p->local->name, name)) + if (!strcmp(p->dev->name, name)) return p; p = (isdn_net_dev *) p->next; } @@ -2453,7 +2457,8 @@ isdn_net_force_dial_lp(isdn_net_local * lp) lp->pre_device, lp->pre_channel, lp->msn)) < 0) { - printk(KERN_WARNING "isdn_net_force_dial: No channel for %s\n", lp->name); + printk(KERN_WARNING "isdn_net_force_dial: No channel for %s\n", + lp->netdev->dev->name); spin_unlock_irqrestore(&dev->lock, flags); return -EAGAIN; } @@ -2556,7 +2561,7 @@ isdn_net_new(char *name, struct net_device *master) return NULL; } if (name == NULL) - name = " "; + return NULL; if (!(netdev = kzalloc(sizeof(isdn_net_dev), GFP_KERNEL))) { printk(KERN_WARNING "isdn_net: Could not allocate net-device\n"); return NULL; @@ -2568,7 +2573,6 @@ isdn_net_new(char *name, struct net_device *master) return NULL; } netdev->local = netdev->dev->priv; - strcpy(netdev->local->name, netdev->dev->name); netdev->dev->init = isdn_net_init; if (master) { /* Device shall be a slave */ @@ -2673,7 +2677,7 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg) #endif if (isdn_net_device_started(p)) { printk(KERN_WARNING "%s: cannot change encap when if is up\n", - lp->name); + p->dev->name); return -EBUSY; } #ifdef CONFIG_ISDN_X25 @@ -2698,7 +2702,7 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg) case ISDN_NET_ENCAP_SYNCPPP: #ifndef CONFIG_ISDN_PPP printk(KERN_WARNING "%s: SyncPPP support not configured\n", - lp->name); + p->dev->name); return -EINVAL; #else p->dev->type = ARPHRD_PPP; /* change ARP type */ @@ -2709,7 +2713,7 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg) case ISDN_NET_ENCAP_X25IFACE: #ifndef CONFIG_ISDN_X25 printk(KERN_WARNING "%s: isdn-x25 support not configured\n", - p->local->name); + p->dev->name); return -EINVAL; #else p->dev->type = ARPHRD_X25; /* change ARP type */ @@ -2725,7 +2729,7 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg) break; printk(KERN_WARNING "%s: encapsulation protocol %d not supported\n", - p->local->name, cfg->p_encap); + p->dev->name, cfg->p_encap); return -EINVAL; } if (strlen(cfg->drvid)) { @@ -2902,13 +2906,18 @@ isdn_net_getcfg(isdn_net_ioctl_cfg * cfg) cfg->pppbind = lp->pppbind; cfg->dialtimeout = lp->dialtimeout >= 0 ? lp->dialtimeout / HZ : -1; cfg->dialwait = lp->dialwait / HZ; - if (lp->slave) - strcpy(cfg->slave, ((isdn_net_local *) lp->slave->priv)->name); - else + if (lp->slave) { + if (strlen(lp->slave->name) > 8) + strcpy(cfg->slave, "too-long"); + else + strcpy(cfg->slave, lp->slave->name); + } else cfg->slave[0] = '\0'; - if (lp->master) - strcpy(cfg->master, ((isdn_net_local *) lp->master->priv)->name); - else + if (lp->master) { + if (strlen(lp->master->name) > 8) + strcpy(cfg->master, "too-long"); + strcpy(cfg->master, lp->master->name); + } else cfg->master[0] = '\0'; return 0; } @@ -2978,7 +2987,8 @@ isdn_net_getpeer(isdn_net_ioctl_phone *phone, isdn_net_ioctl_phone __user *peer) isdn_net_dev *p = isdn_net_findif(phone->name); int ch, dv, idx; - if (!p) return -ENODEV; + if (!p) + return -ENODEV; /* * Theoretical race: while this executes, the remote number might * become invalid (hang up) or change (new connection), resulting @@ -2987,14 +2997,18 @@ isdn_net_getpeer(isdn_net_ioctl_phone *phone, isdn_net_ioctl_phone __user *peer) */ ch = p->local->isdn_channel; dv = p->local->isdn_device; - if(ch<0 && dv<0) return -ENOTCONN; + if(ch < 0 && dv < 0) + return -ENOTCONN; idx = isdn_dc2minor(dv, ch); - if (idx<0) return -ENODEV; + if (idx <0 ) + return -ENODEV; /* for pre-bound channels, we need this extra check */ - if ( strncmp(dev->num[idx],"???",3) == 0 ) return -ENOTCONN; - strncpy(phone->phone,dev->num[idx],ISDN_MSNLEN); - phone->outgoing=USG_OUTGOING(dev->usage[idx]); - if ( copy_to_user(peer,phone,sizeof(*peer)) ) return -EFAULT; + if (strncmp(dev->num[idx], "???", 3) == 0) + return -ENOTCONN; + strncpy(phone->phone, dev->num[idx], ISDN_MSNLEN); + phone->outgoing = USG_OUTGOING(dev->usage[idx]); + if (copy_to_user(peer, phone, sizeof(*peer))) + return -EFAULT; return 0; } /* @@ -3113,18 +3127,18 @@ isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q) dev->netdev = p->next; if (p->local->slave) { /* If this interface has a slave, remove it also */ - char *slavename = ((isdn_net_local *) (p->local->slave->priv))->name; + char *slavename = p->local->slave->name; isdn_net_dev *n = dev->netdev; q = NULL; while (n) { - if (!strcmp(n->local->name, slavename)) { + if (!strcmp(n->dev->name, slavename)) { spin_unlock_irqrestore(&dev->lock, flags); isdn_net_realrm(n, q); spin_lock_irqsave(&dev->lock, flags); break; } q = n; - n = (isdn_net_dev *) n->next; + n = (isdn_net_dev *)n->next; } } spin_unlock_irqrestore(&dev->lock, flags); @@ -3152,7 +3166,7 @@ isdn_net_rm(char *name) p = dev->netdev; q = NULL; while (p) { - if (!strcmp(p->local->name, name)) { + if (!strcmp(p->dev->name, name)) { spin_unlock_irqrestore(&dev->lock, flags); return (isdn_net_realrm(p, q)); } diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index 0e5e59f84344..9f5fe372f83d 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -190,9 +190,11 @@ isdn_ppp_bind(isdn_net_local * lp) retval = -1; goto out; } - unit = isdn_ppp_if_get_unit(lp->name); /* get unit number from interface name .. ugly! */ + /* get unit number from interface name .. ugly! */ + unit = isdn_ppp_if_get_unit(lp->netdev->dev->name); if (unit < 0) { - printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n", lp->name); + printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n", + lp->netdev->dev->name); retval = -1; goto out; } @@ -507,7 +509,8 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) case PPPIOCGIFNAME: if(!lp) return -EINVAL; - if ((r = set_arg(argp, lp->name, strlen(lp->name)))) + if ((r = set_arg(argp, lp->netdev->dev->name, + strlen(lp->netdev->dev->name)))) return r; break; case PPPIOCGMPFLAGS: /* get configuration flags */ diff --git a/drivers/kvm/Kconfig b/drivers/kvm/Kconfig index 0a419a0de603..8749fa4ffcee 100644 --- a/drivers/kvm/Kconfig +++ b/drivers/kvm/Kconfig @@ -17,6 +17,7 @@ if VIRTUALIZATION config KVM tristate "Kernel-based Virtual Machine (KVM) support" depends on X86 && EXPERIMENTAL + select PREEMPT_NOTIFIERS select ANON_INODES ---help--- Support hosting fully virtualized guest machines using hardware diff --git a/drivers/kvm/Makefile b/drivers/kvm/Makefile index c0a789fa9d65..e5a8f4d3e973 100644 --- a/drivers/kvm/Makefile +++ b/drivers/kvm/Makefile @@ -2,7 +2,7 @@ # Makefile for Kernel-based Virtual Machine module # -kvm-objs := kvm_main.o mmu.o x86_emulate.o +kvm-objs := kvm_main.o mmu.o x86_emulate.o i8259.o irq.o lapic.o ioapic.o obj-$(CONFIG_KVM) += kvm.o kvm-intel-objs = vmx.o obj-$(CONFIG_KVM_INTEL) += kvm-intel.o diff --git a/drivers/kvm/i8259.c b/drivers/kvm/i8259.c new file mode 100644 index 000000000000..a679157bc599 --- /dev/null +++ b/drivers/kvm/i8259.c @@ -0,0 +1,450 @@ +/* + * 8259 interrupt controller emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * Copyright (c) 2007 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * Authors: + * Yaozu (Eddie) Dong <Eddie.dong@intel.com> + * Port from Qemu. + */ +#include <linux/mm.h> +#include "irq.h" + +/* + * set irq level. If an edge is detected, then the IRR is set to 1 + */ +static inline void pic_set_irq1(struct kvm_kpic_state *s, int irq, int level) +{ + int mask; + mask = 1 << irq; + if (s->elcr & mask) /* level triggered */ + if (level) { + s->irr |= mask; + s->last_irr |= mask; + } else { + s->irr &= ~mask; + s->last_irr &= ~mask; + } + else /* edge triggered */ + if (level) { + if ((s->last_irr & mask) == 0) + s->irr |= mask; + s->last_irr |= mask; + } else + s->last_irr &= ~mask; +} + +/* + * return the highest priority found in mask (highest = smallest + * number). Return 8 if no irq + */ +static inline int get_priority(struct kvm_kpic_state *s, int mask) +{ + int priority; + if (mask == 0) + return 8; + priority = 0; + while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0) + priority++; + return priority; +} + +/* + * return the pic wanted interrupt. return -1 if none + */ +static int pic_get_irq(struct kvm_kpic_state *s) +{ + int mask, cur_priority, priority; + + mask = s->irr & ~s->imr; + priority = get_priority(s, mask); + if (priority == 8) + return -1; + /* + * compute current priority. If special fully nested mode on the + * master, the IRQ coming from the slave is not taken into account + * for the priority computation. + */ + mask = s->isr; + if (s->special_fully_nested_mode && s == &s->pics_state->pics[0]) + mask &= ~(1 << 2); + cur_priority = get_priority(s, mask); + if (priority < cur_priority) + /* + * higher priority found: an irq should be generated + */ + return (priority + s->priority_add) & 7; + else + return -1; +} + +/* + * raise irq to CPU if necessary. must be called every time the active + * irq may change + */ +static void pic_update_irq(struct kvm_pic *s) +{ + int irq2, irq; + + irq2 = pic_get_irq(&s->pics[1]); + if (irq2 >= 0) { + /* + * if irq request by slave pic, signal master PIC + */ + pic_set_irq1(&s->pics[0], 2, 1); + pic_set_irq1(&s->pics[0], 2, 0); + } + irq = pic_get_irq(&s->pics[0]); + if (irq >= 0) + s->irq_request(s->irq_request_opaque, 1); + else + s->irq_request(s->irq_request_opaque, 0); +} + +void kvm_pic_update_irq(struct kvm_pic *s) +{ + pic_update_irq(s); +} + +void kvm_pic_set_irq(void *opaque, int irq, int level) +{ + struct kvm_pic *s = opaque; + + pic_set_irq1(&s->pics[irq >> 3], irq & 7, level); + pic_update_irq(s); +} + +/* + * acknowledge interrupt 'irq' + */ +static inline void pic_intack(struct kvm_kpic_state *s, int irq) +{ + if (s->auto_eoi) { + if (s->rotate_on_auto_eoi) + s->priority_add = (irq + 1) & 7; + } else + s->isr |= (1 << irq); + /* + * We don't clear a level sensitive interrupt here + */ + if (!(s->elcr & (1 << irq))) + s->irr &= ~(1 << irq); +} + +int kvm_pic_read_irq(struct kvm_pic *s) +{ + int irq, irq2, intno; + + irq = pic_get_irq(&s->pics[0]); + if (irq >= 0) { + pic_intack(&s->pics[0], irq); + if (irq == 2) { + irq2 = pic_get_irq(&s->pics[1]); + if (irq2 >= 0) + pic_intack(&s->pics[1], irq2); + else + /* + * spurious IRQ on slave controller + */ + irq2 = 7; + intno = s->pics[1].irq_base + irq2; + irq = irq2 + 8; + } else + intno = s->pics[0].irq_base + irq; + } else { + /* + * spurious IRQ on host controller + */ + irq = 7; + intno = s->pics[0].irq_base + irq; + } + pic_update_irq(s); + + return intno; +} + +static void pic_reset(void *opaque) +{ + struct kvm_kpic_state *s = opaque; + + s->last_irr = 0; + s->irr = 0; + s->imr = 0; + s->isr = 0; + s->priority_add = 0; + s->irq_base = 0; + s->read_reg_select = 0; + s->poll = 0; + s->special_mask = 0; + s->init_state = 0; + s->auto_eoi = 0; + s->rotate_on_auto_eoi = 0; + s->special_fully_nested_mode = 0; + s->init4 = 0; +} + +static void pic_ioport_write(void *opaque, u32 addr, u32 val) +{ + struct kvm_kpic_state *s = opaque; + int priority, cmd, irq; + + addr &= 1; + if (addr == 0) { + if (val & 0x10) { + pic_reset(s); /* init */ + /* + * deassert a pending interrupt + */ + s->pics_state->irq_request(s->pics_state-> + irq_request_opaque, 0); + s->init_state = 1; + s->init4 = val & 1; + if (val & 0x02) + printk(KERN_ERR "single mode not supported"); + if (val & 0x08) + printk(KERN_ERR + "level sensitive irq not supported"); + } else if (val & 0x08) { + if (val & 0x04) + s->poll = 1; + if (val & 0x02) + s->read_reg_select = val & 1; + if (val & 0x40) + s->special_mask = (val >> 5) & 1; + } else { + cmd = val >> 5; + switch (cmd) { + case 0: + case 4: + s->rotate_on_auto_eoi = cmd >> 2; + break; + case 1: /* end of interrupt */ + case 5: + priority = get_priority(s, s->isr); + if (priority != 8) { + irq = (priority + s->priority_add) & 7; + s->isr &= ~(1 << irq); + if (cmd == 5) + s->priority_add = (irq + 1) & 7; + pic_update_irq(s->pics_state); + } + break; + case 3: + irq = val & 7; + s->isr &= ~(1 << irq); + pic_update_irq(s->pics_state); + break; + case 6: + s->priority_add = (val + 1) & 7; + pic_update_irq(s->pics_state); + break; + case 7: + irq = val & 7; + s->isr &= ~(1 << irq); + s->priority_add = (irq + 1) & 7; + pic_update_irq(s->pics_state); + break; + default: + break; /* no operation */ + } + } + } else + switch (s->init_state) { + case 0: /* normal mode */ + s->imr = val; + pic_update_irq(s->pics_state); + break; + case 1: + s->irq_base = val & 0xf8; + s->init_state = 2; + break; + case 2: + if (s->init4) + s->init_state = 3; + else + s->init_state = 0; + break; + case 3: + s->special_fully_nested_mode = (val >> 4) & 1; + s->auto_eoi = (val >> 1) & 1; + s->init_state = 0; + break; + } +} + +static u32 pic_poll_read(struct kvm_kpic_state *s, u32 addr1) +{ + int ret; + + ret = pic_get_irq(s); + if (ret >= 0) { + if (addr1 >> 7) { + s->pics_state->pics[0].isr &= ~(1 << 2); + s->pics_state->pics[0].irr &= ~(1 << 2); + } + s->irr &= ~(1 << ret); + s->isr &= ~(1 << ret); + if (addr1 >> 7 || ret != 2) + pic_update_irq(s->pics_state); + } else { + ret = 0x07; + pic_update_irq(s->pics_state); + } + + return ret; +} + +static u32 pic_ioport_read(void *opaque, u32 addr1) +{ + struct kvm_kpic_state *s = opaque; + unsigned int addr; + int ret; + + addr = addr1; + addr &= 1; + if (s->poll) { + ret = pic_poll_read(s, addr1); + s->poll = 0; + } else + if (addr == 0) + if (s->read_reg_select) + ret = s->isr; + else + ret = s->irr; + else + ret = s->imr; + return ret; +} + +static void elcr_ioport_write(void *opaque, u32 addr, u32 val) +{ + struct kvm_kpic_state *s = opaque; + s->elcr = val & s->elcr_mask; +} + +static u32 elcr_ioport_read(void *opaque, u32 addr1) +{ + struct kvm_kpic_state *s = opaque; + return s->elcr; +} + +static int picdev_in_range(struct kvm_io_device *this, gpa_t addr) +{ + switch (addr) { + case 0x20: + case 0x21: + case 0xa0: + case 0xa1: + case 0x4d0: + case 0x4d1: + return 1; + default: + return 0; + } +} + +static void picdev_write(struct kvm_io_device *this, + gpa_t addr, int len, const void *val) +{ + struct kvm_pic *s = this->private; + unsigned char data = *(unsigned char *)val; + + if (len != 1) { + if (printk_ratelimit()) + printk(KERN_ERR "PIC: non byte write\n"); + return; + } + switch (addr) { + case 0x20: + case 0x21: + case 0xa0: + case 0xa1: + pic_ioport_write(&s->pics[addr >> 7], addr, data); + break; + case 0x4d0: + case 0x4d1: + elcr_ioport_write(&s->pics[addr & 1], addr, data); + break; + } +} + +static void picdev_read(struct kvm_io_device *this, + gpa_t addr, int len, void *val) +{ + struct kvm_pic *s = this->private; + unsigned char data = 0; + + if (len != 1) { + if (printk_ratelimit()) + printk(KERN_ERR "PIC: non byte read\n"); + return; + } + switch (addr) { + case 0x20: + case 0x21: + case 0xa0: + case 0xa1: + data = pic_ioport_read(&s->pics[addr >> 7], addr); + break; + case 0x4d0: + case 0x4d1: + data = elcr_ioport_read(&s->pics[addr & 1], addr); + break; + } + *(unsigned char *)val = data; +} + +/* + * callback when PIC0 irq status changed + */ +static void pic_irq_request(void *opaque, int level) +{ + struct kvm *kvm = opaque; + struct kvm_vcpu *vcpu = kvm->vcpus[0]; + + pic_irqchip(kvm)->output = level; + if (vcpu) + kvm_vcpu_kick(vcpu); +} + +struct kvm_pic *kvm_create_pic(struct kvm *kvm) +{ + struct kvm_pic *s; + s = kzalloc(sizeof(struct kvm_pic), GFP_KERNEL); + if (!s) + return NULL; + s->pics[0].elcr_mask = 0xf8; + s->pics[1].elcr_mask = 0xde; + s->irq_request = pic_irq_request; + s->irq_request_opaque = kvm; + s->pics[0].pics_state = s; + s->pics[1].pics_state = s; + + /* + * Initialize PIO device + */ + s->dev.read = picdev_read; + s->dev.write = picdev_write; + s->dev.in_range = picdev_in_range; + s->dev.private = s; + kvm_io_bus_register_dev(&kvm->pio_bus, &s->dev); + return s; +} diff --git a/drivers/kvm/ioapic.c b/drivers/kvm/ioapic.c new file mode 100644 index 000000000000..c7992e667fdb --- /dev/null +++ b/drivers/kvm/ioapic.c @@ -0,0 +1,388 @@ +/* + * Copyright (C) 2001 MandrakeSoft S.A. + * + * MandrakeSoft S.A. + * 43, rue d'Aboukir + * 75002 Paris - France + * http://www.linux-mandrake.com/ + * http://www.mandrakesoft.com/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Yunhong Jiang <yunhong.jiang@intel.com> + * Yaozu (Eddie) Dong <eddie.dong@intel.com> + * Based on Xen 3.1 code. + */ + +#include "kvm.h" +#include <linux/kvm.h> +#include <linux/mm.h> +#include <linux/highmem.h> +#include <linux/smp.h> +#include <linux/hrtimer.h> +#include <linux/io.h> +#include <asm/processor.h> +#include <asm/msr.h> +#include <asm/page.h> +#include <asm/current.h> +#include <asm/apicdef.h> +#include <asm/io_apic.h> +#include "irq.h" +/* #define ioapic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg) */ +#define ioapic_debug(fmt, arg...) +static void ioapic_deliver(struct kvm_ioapic *vioapic, int irq); + +static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic, + unsigned long addr, + unsigned long length) +{ + unsigned long result = 0; + + switch (ioapic->ioregsel) { + case IOAPIC_REG_VERSION: + result = ((((IOAPIC_NUM_PINS - 1) & 0xff) << 16) + | (IOAPIC_VERSION_ID & 0xff)); + break; + + case IOAPIC_REG_APIC_ID: + case IOAPIC_REG_ARB_ID: + result = ((ioapic->id & 0xf) << 24); + break; + + default: + { + u32 redir_index = (ioapic->ioregsel - 0x10) >> 1; + u64 redir_content; + + ASSERT(redir_index < IOAPIC_NUM_PINS); + + redir_content = ioapic->redirtbl[redir_index].bits; + result = (ioapic->ioregsel & 0x1) ? + (redir_content >> 32) & 0xffffffff : + redir_content & 0xffffffff; + break; + } + } + + return result; +} + +static void ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx) +{ + union ioapic_redir_entry *pent; + + pent = &ioapic->redirtbl[idx]; + + if (!pent->fields.mask) { + ioapic_deliver(ioapic, idx); + if (pent->fields.trig_mode == IOAPIC_LEVEL_TRIG) + pent->fields.remote_irr = 1; + } + if (!pent->fields.trig_mode) + ioapic->irr &= ~(1 << idx); +} + +static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val) +{ + unsigned index; + + switch (ioapic->ioregsel) { + case IOAPIC_REG_VERSION: + /* Writes are ignored. */ + break; + + case IOAPIC_REG_APIC_ID: + ioapic->id = (val >> 24) & 0xf; + break; + + case IOAPIC_REG_ARB_ID: + break; + + default: + index = (ioapic->ioregsel - 0x10) >> 1; + + ioapic_debug("change redir index %x val %x", index, val); + if (index >= IOAPIC_NUM_PINS) + return; + if (ioapic->ioregsel & 1) { + ioapic->redirtbl[index].bits &= 0xffffffff; + ioapic->redirtbl[index].bits |= (u64) val << 32; + } else { + ioapic->redirtbl[index].bits &= ~0xffffffffULL; + ioapic->redirtbl[index].bits |= (u32) val; + ioapic->redirtbl[index].fields.remote_irr = 0; + } + if (ioapic->irr & (1 << index)) + ioapic_service(ioapic, index); + break; + } +} + +static void ioapic_inj_irq(struct kvm_ioapic *ioapic, + struct kvm_lapic *target, + u8 vector, u8 trig_mode, u8 delivery_mode) +{ + ioapic_debug("irq %d trig %d deliv %d", vector, trig_mode, + delivery_mode); + + ASSERT((delivery_mode == dest_Fixed) || + (delivery_mode == dest_LowestPrio)); + + kvm_apic_set_irq(target, vector, trig_mode); +} + +static u32 ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest, + u8 dest_mode) +{ + u32 mask = 0; + int i; + struct kvm *kvm = ioapic->kvm; + struct kvm_vcpu *vcpu; + + ioapic_debug("dest %d dest_mode %d", dest, dest_mode); + + if (dest_mode == 0) { /* Physical mode. */ + if (dest == 0xFF) { /* Broadcast. */ + for (i = 0; i < KVM_MAX_VCPUS; ++i) + if (kvm->vcpus[i] && kvm->vcpus[i]->apic) + mask |= 1 << i; + return mask; + } + for (i = 0; i < KVM_MAX_VCPUS; ++i) { + vcpu = kvm->vcpus[i]; + if (!vcpu) + continue; + if (kvm_apic_match_physical_addr(vcpu->apic, dest)) { + if (vcpu->apic) + mask = 1 << i; + break; + } + } + } else if (dest != 0) /* Logical mode, MDA non-zero. */ + for (i = 0; i < KVM_MAX_VCPUS; ++i) { + vcpu = kvm->vcpus[i]; + if (!vcpu) + continue; + if (vcpu->apic && + kvm_apic_match_logical_addr(vcpu->apic, dest)) + mask |= 1 << vcpu->vcpu_id; + } + ioapic_debug("mask %x", mask); + return mask; +} + +static void ioapic_deliver(struct kvm_ioapic *ioapic, int irq) +{ + u8 dest = ioapic->redirtbl[irq].fields.dest_id; + u8 dest_mode = ioapic->redirtbl[irq].fields.dest_mode; + u8 delivery_mode = ioapic->redirtbl[irq].fields.delivery_mode; + u8 vector = ioapic->redirtbl[irq].fields.vector; + u8 trig_mode = ioapic->redirtbl[irq].fields.trig_mode; + u32 deliver_bitmask; + struct kvm_lapic *target; + struct kvm_vcpu *vcpu; + int vcpu_id; + + ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x " + "vector=%x trig_mode=%x", + dest, dest_mode, delivery_mode, vector, trig_mode); + + deliver_bitmask = ioapic_get_delivery_bitmask(ioapic, dest, dest_mode); + if (!deliver_bitmask) { + ioapic_debug("no target on destination"); + return; + } + + switch (delivery_mode) { + case dest_LowestPrio: + target = + kvm_apic_round_robin(ioapic->kvm, vector, deliver_bitmask); + if (target != NULL) + ioapic_inj_irq(ioapic, target, vector, + trig_mode, delivery_mode); + else + ioapic_debug("null round robin: " + "mask=%x vector=%x delivery_mode=%x", + deliver_bitmask, vector, dest_LowestPrio); + break; + case dest_Fixed: + for (vcpu_id = 0; deliver_bitmask != 0; vcpu_id++) { + if (!(deliver_bitmask & (1 << vcpu_id))) + continue; + deliver_bitmask &= ~(1 << vcpu_id); + vcpu = ioapic->kvm->vcpus[vcpu_id]; + if (vcpu) { + target = vcpu->apic; + ioapic_inj_irq(ioapic, target, vector, + trig_mode, delivery_mode); + } + } + break; + + /* TODO: NMI */ + default: + printk(KERN_WARNING "Unsupported delivery mode %d\n", + delivery_mode); + break; + } +} + +void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level) +{ + u32 old_irr = ioapic->irr; + u32 mask = 1 << irq; + union ioapic_redir_entry entry; + + if (irq >= 0 && irq < IOAPIC_NUM_PINS) { + entry = ioapic->redirtbl[irq]; + level ^= entry.fields.polarity; + if (!level) + ioapic->irr &= ~mask; + else { + ioapic->irr |= mask; + if ((!entry.fields.trig_mode && old_irr != ioapic->irr) + || !entry.fields.remote_irr) + ioapic_service(ioapic, irq); + } + } +} + +static int get_eoi_gsi(struct kvm_ioapic *ioapic, int vector) +{ + int i; + + for (i = 0; i < IOAPIC_NUM_PINS; i++) + if (ioapic->redirtbl[i].fields.vector == vector) + return i; + return -1; +} + +void kvm_ioapic_update_eoi(struct kvm *kvm, int vector) +{ + struct kvm_ioapic *ioapic = kvm->vioapic; + union ioapic_redir_entry *ent; + int gsi; + + gsi = get_eoi_gsi(ioapic, vector); + if (gsi == -1) { + printk(KERN_WARNING "Can't find redir item for %d EOI\n", + vector); + return; + } + + ent = &ioapic->redirtbl[gsi]; + ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG); + + ent->fields.remote_irr = 0; + if (!ent->fields.mask && (ioapic->irr & (1 << gsi))) + ioapic_deliver(ioapic, gsi); +} + +static int ioapic_in_range(struct kvm_io_device *this, gpa_t addr) +{ + struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private; + + return ((addr >= ioapic->base_address && + (addr < ioapic->base_address + IOAPIC_MEM_LENGTH))); +} + +static void ioapic_mmio_read(struct kvm_io_device *this, gpa_t addr, int len, + void *val) +{ + struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private; + u32 result; + + ioapic_debug("addr %lx", (unsigned long)addr); + ASSERT(!(addr & 0xf)); /* check alignment */ + + addr &= 0xff; + switch (addr) { + case IOAPIC_REG_SELECT: + result = ioapic->ioregsel; + break; + + case IOAPIC_REG_WINDOW: + result = ioapic_read_indirect(ioapic, addr, len); + break; + + default: + result = 0; + break; + } + switch (len) { + case 8: + *(u64 *) val = result; + break; + case 1: + case 2: + case 4: + memcpy(val, (char *)&result, len); + break; + default: + printk(KERN_WARNING "ioapic: wrong length %d\n", len); + } +} + +static void ioapic_mmio_write(struct kvm_io_device *this, gpa_t addr, int len, + const void *val) +{ + struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private; + u32 data; + + ioapic_debug("ioapic_mmio_write addr=%lx len=%d val=%p\n", + addr, len, val); + ASSERT(!(addr & 0xf)); /* check alignment */ + if (len == 4 || len == 8) + data = *(u32 *) val; + else { + printk(KERN_WARNING "ioapic: Unsupported size %d\n", len); + return; + } + + addr &= 0xff; + switch (addr) { + case IOAPIC_REG_SELECT: + ioapic->ioregsel = data; + break; + + case IOAPIC_REG_WINDOW: + ioapic_write_indirect(ioapic, data); + break; + + default: + break; + } +} + +int kvm_ioapic_init(struct kvm *kvm) +{ + struct kvm_ioapic *ioapic; + int i; + + ioapic = kzalloc(sizeof(struct kvm_ioapic), GFP_KERNEL); + if (!ioapic) + return -ENOMEM; + kvm->vioapic = ioapic; + for (i = 0; i < IOAPIC_NUM_PINS; i++) + ioapic->redirtbl[i].fields.mask = 1; + ioapic->base_address = IOAPIC_DEFAULT_BASE_ADDRESS; + ioapic->dev.read = ioapic_mmio_read; + ioapic->dev.write = ioapic_mmio_write; + ioapic->dev.in_range = ioapic_in_range; + ioapic->dev.private = ioapic; + ioapic->kvm = kvm; + kvm_io_bus_register_dev(&kvm->mmio_bus, &ioapic->dev); + return 0; +} diff --git a/drivers/kvm/irq.c b/drivers/kvm/irq.c new file mode 100644 index 000000000000..7628c7ff628f --- /dev/null +++ b/drivers/kvm/irq.c @@ -0,0 +1,98 @@ +/* + * irq.c: API for in kernel interrupt controller + * Copyright (c) 2007, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * Authors: + * Yaozu (Eddie) Dong <Eddie.dong@intel.com> + * + */ + +#include <linux/module.h> + +#include "kvm.h" +#include "irq.h" + +/* + * check if there is pending interrupt without + * intack. + */ +int kvm_cpu_has_interrupt(struct kvm_vcpu *v) +{ + struct kvm_pic *s; + + if (kvm_apic_has_interrupt(v) == -1) { /* LAPIC */ + if (kvm_apic_accept_pic_intr(v)) { + s = pic_irqchip(v->kvm); /* PIC */ + return s->output; + } else + return 0; + } + return 1; +} +EXPORT_SYMBOL_GPL(kvm_cpu_has_interrupt); + +/* + * Read pending interrupt vector and intack. + */ +int kvm_cpu_get_interrupt(struct kvm_vcpu *v) +{ + struct kvm_pic *s; + int vector; + + vector = kvm_get_apic_interrupt(v); /* APIC */ + if (vector == -1) { + if (kvm_apic_accept_pic_intr(v)) { + s = pic_irqchip(v->kvm); + s->output = 0; /* PIC */ + vector = kvm_pic_read_irq(s); + } + } + return vector; +} +EXPORT_SYMBOL_GPL(kvm_cpu_get_interrupt); + +static void vcpu_kick_intr(void *info) +{ +#ifdef DEBUG + struct kvm_vcpu *vcpu = (struct kvm_vcpu *)info; + printk(KERN_DEBUG "vcpu_kick_intr %p \n", vcpu); +#endif +} + +void kvm_vcpu_kick(struct kvm_vcpu *vcpu) +{ + int ipi_pcpu = vcpu->cpu; + + if (waitqueue_active(&vcpu->wq)) { + wake_up_interruptible(&vcpu->wq); + ++vcpu->stat.halt_wakeup; + } + if (vcpu->guest_mode) + smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0, 0); +} + +void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu) +{ + kvm_inject_apic_timer_irqs(vcpu); + /* TODO: PIT, RTC etc. */ +} +EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs); + +void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec) +{ + kvm_apic_timer_intr_post(vcpu, vec); + /* TODO: PIT, RTC etc. */ +} +EXPORT_SYMBOL_GPL(kvm_timer_intr_post); diff --git a/drivers/kvm/irq.h b/drivers/kvm/irq.h new file mode 100644 index 000000000000..11fc014e2b30 --- /dev/null +++ b/drivers/kvm/irq.h @@ -0,0 +1,165 @@ +/* + * irq.h: in kernel interrupt controller related definitions + * Copyright (c) 2007, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * Authors: + * Yaozu (Eddie) Dong <Eddie.dong@intel.com> + * + */ + +#ifndef __IRQ_H +#define __IRQ_H + +#include "kvm.h" + +typedef void irq_request_func(void *opaque, int level); + +struct kvm_kpic_state { + u8 last_irr; /* edge detection */ + u8 irr; /* interrupt request register */ + u8 imr; /* interrupt mask register */ + u8 isr; /* interrupt service register */ + u8 priority_add; /* highest irq priority */ + u8 irq_base; + u8 read_reg_select; + u8 poll; + u8 special_mask; + u8 init_state; + u8 auto_eoi; + u8 rotate_on_auto_eoi; + u8 special_fully_nested_mode; + u8 init4; /* true if 4 byte init */ + u8 elcr; /* PIIX edge/trigger selection */ + u8 elcr_mask; + struct kvm_pic *pics_state; +}; + +struct kvm_pic { + struct kvm_kpic_state pics[2]; /* 0 is master pic, 1 is slave pic */ + irq_request_func *irq_request; + void *irq_request_opaque; + int output; /* intr from master PIC */ + struct kvm_io_device dev; +}; + +struct kvm_pic *kvm_create_pic(struct kvm *kvm); +void kvm_pic_set_irq(void *opaque, int irq, int level); +int kvm_pic_read_irq(struct kvm_pic *s); +int kvm_cpu_get_interrupt(struct kvm_vcpu *v); +int kvm_cpu_has_interrupt(struct kvm_vcpu *v); +void kvm_pic_update_irq(struct kvm_pic *s); + +#define IOAPIC_NUM_PINS KVM_IOAPIC_NUM_PINS +#define IOAPIC_VERSION_ID 0x11 /* IOAPIC version */ +#define IOAPIC_EDGE_TRIG 0 +#define IOAPIC_LEVEL_TRIG 1 + +#define IOAPIC_DEFAULT_BASE_ADDRESS 0xfec00000 +#define IOAPIC_MEM_LENGTH 0x100 + +/* Direct registers. */ +#define IOAPIC_REG_SELECT 0x00 +#define IOAPIC_REG_WINDOW 0x10 +#define IOAPIC_REG_EOI 0x40 /* IA64 IOSAPIC only */ + +/* Indirect registers. */ +#define IOAPIC_REG_APIC_ID 0x00 /* x86 IOAPIC only */ +#define IOAPIC_REG_VERSION 0x01 +#define IOAPIC_REG_ARB_ID 0x02 /* x86 IOAPIC only */ + +struct kvm_ioapic { + u64 base_address; + u32 ioregsel; + u32 id; + u32 irr; + u32 pad; + union ioapic_redir_entry { + u64 bits; + struct { + u8 vector; + u8 delivery_mode:3; + u8 dest_mode:1; + u8 delivery_status:1; + u8 polarity:1; + u8 remote_irr:1; + u8 trig_mode:1; + u8 mask:1; + u8 reserve:7; + u8 reserved[4]; + u8 dest_id; + } fields; + } redirtbl[IOAPIC_NUM_PINS]; + struct kvm_io_device dev; + struct kvm *kvm; +}; + +struct kvm_lapic { + unsigned long base_address; + struct kvm_io_device dev; + struct { + atomic_t pending; + s64 period; /* unit: ns */ + u32 divide_count; + ktime_t last_update; + struct hrtimer dev; + } timer; + struct kvm_vcpu *vcpu; + struct page *regs_page; + void *regs; +}; + +#ifdef DEBUG +#define ASSERT(x) \ +do { \ + if (!(x)) { \ + printk(KERN_EMERG "assertion failed %s: %d: %s\n", \ + __FILE__, __LINE__, #x); \ + BUG(); \ + } \ +} while (0) +#else +#define ASSERT(x) do { } while (0) +#endif + +void kvm_vcpu_kick(struct kvm_vcpu *vcpu); +int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu); +int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu); +int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu); +int kvm_create_lapic(struct kvm_vcpu *vcpu); +void kvm_lapic_reset(struct kvm_vcpu *vcpu); +void kvm_free_apic(struct kvm_lapic *apic); +u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu); +void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8); +void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value); +struct kvm_lapic *kvm_apic_round_robin(struct kvm *kvm, u8 vector, + unsigned long bitmap); +u64 kvm_get_apic_base(struct kvm_vcpu *vcpu); +void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data); +int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest); +void kvm_ioapic_update_eoi(struct kvm *kvm, int vector); +int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda); +int kvm_apic_set_irq(struct kvm_lapic *apic, u8 vec, u8 trig); +void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu); +int kvm_ioapic_init(struct kvm *kvm); +void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level); +int kvm_lapic_enabled(struct kvm_vcpu *vcpu); +int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu); +void kvm_apic_timer_intr_post(struct kvm_vcpu *vcpu, int vec); +void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec); +void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu); +void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu); +void kvm_migrate_apic_timer(struct kvm_vcpu *vcpu); + +#endif diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h index 336be86c6f5a..3b0bc4bda5f2 100644 --- a/drivers/kvm/kvm.h +++ b/drivers/kvm/kvm.h @@ -13,60 +13,38 @@ #include <linux/signal.h> #include <linux/sched.h> #include <linux/mm.h> +#include <linux/preempt.h> #include <asm/signal.h> -#include "vmx.h" #include <linux/kvm.h> #include <linux/kvm_para.h> -#define CR0_PE_MASK (1ULL << 0) -#define CR0_MP_MASK (1ULL << 1) -#define CR0_TS_MASK (1ULL << 3) -#define CR0_NE_MASK (1ULL << 5) -#define CR0_WP_MASK (1ULL << 16) -#define CR0_NW_MASK (1ULL << 29) -#define CR0_CD_MASK (1ULL << 30) -#define CR0_PG_MASK (1ULL << 31) - -#define CR3_WPT_MASK (1ULL << 3) -#define CR3_PCD_MASK (1ULL << 4) - -#define CR3_RESEVED_BITS 0x07ULL -#define CR3_L_MODE_RESEVED_BITS (~((1ULL << 40) - 1) | 0x0fe7ULL) -#define CR3_FLAGS_MASK ((1ULL << 5) - 1) - -#define CR4_VME_MASK (1ULL << 0) -#define CR4_PSE_MASK (1ULL << 4) -#define CR4_PAE_MASK (1ULL << 5) -#define CR4_PGE_MASK (1ULL << 7) -#define CR4_VMXE_MASK (1ULL << 13) +#define CR3_PAE_RESERVED_BITS ((X86_CR3_PWT | X86_CR3_PCD) - 1) +#define CR3_NONPAE_RESERVED_BITS ((PAGE_SIZE-1) & ~(X86_CR3_PWT | X86_CR3_PCD)) +#define CR3_L_MODE_RESERVED_BITS (CR3_NONPAE_RESERVED_BITS|0xFFFFFF0000000000ULL) #define KVM_GUEST_CR0_MASK \ - (CR0_PG_MASK | CR0_PE_MASK | CR0_WP_MASK | CR0_NE_MASK \ - | CR0_NW_MASK | CR0_CD_MASK) + (X86_CR0_PG | X86_CR0_PE | X86_CR0_WP | X86_CR0_NE \ + | X86_CR0_NW | X86_CR0_CD) #define KVM_VM_CR0_ALWAYS_ON \ - (CR0_PG_MASK | CR0_PE_MASK | CR0_WP_MASK | CR0_NE_MASK | CR0_TS_MASK \ - | CR0_MP_MASK) + (X86_CR0_PG | X86_CR0_PE | X86_CR0_WP | X86_CR0_NE | X86_CR0_TS \ + | X86_CR0_MP) #define KVM_GUEST_CR4_MASK \ - (CR4_PSE_MASK | CR4_PAE_MASK | CR4_PGE_MASK | CR4_VMXE_MASK | CR4_VME_MASK) -#define KVM_PMODE_VM_CR4_ALWAYS_ON (CR4_VMXE_MASK | CR4_PAE_MASK) -#define KVM_RMODE_VM_CR4_ALWAYS_ON (CR4_VMXE_MASK | CR4_PAE_MASK | CR4_VME_MASK) + (X86_CR4_VME | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_PGE | X86_CR4_VMXE) +#define KVM_PMODE_VM_CR4_ALWAYS_ON (X86_CR4_PAE | X86_CR4_VMXE) +#define KVM_RMODE_VM_CR4_ALWAYS_ON (X86_CR4_VME | X86_CR4_PAE | X86_CR4_VMXE) #define INVALID_PAGE (~(hpa_t)0) #define UNMAPPED_GVA (~(gpa_t)0) #define KVM_MAX_VCPUS 4 #define KVM_ALIAS_SLOTS 4 -#define KVM_MEMORY_SLOTS 4 +#define KVM_MEMORY_SLOTS 8 #define KVM_NUM_MMU_PAGES 1024 #define KVM_MIN_FREE_MMU_PAGES 5 #define KVM_REFILL_PAGES 25 #define KVM_MAX_CPUID_ENTRIES 40 -#define FX_IMAGE_SIZE 512 -#define FX_IMAGE_ALIGN 16 -#define FX_BUF_SIZE (2 * FX_IMAGE_SIZE + FX_IMAGE_ALIGN) - #define DE_VECTOR 0 #define NM_VECTOR 7 #define DF_VECTOR 8 @@ -158,15 +136,8 @@ struct kvm_mmu_page { }; }; -struct vmcs { - u32 revision_id; - u32 abort; - char data[0]; -}; - -#define vmx_msr_entry kvm_msr_entry - struct kvm_vcpu; +extern struct kmem_cache *kvm_vcpu_cache; /* * x86 supports 3 paging modes (4-level 64-bit, 3-level 64-bit, and 2-level @@ -260,6 +231,7 @@ struct kvm_stat { u32 signal_exits; u32 irq_window_exits; u32 halt_exits; + u32 halt_wakeup; u32 request_irq_exits; u32 irq_exits; u32 light_exits; @@ -328,21 +300,17 @@ void kvm_io_bus_register_dev(struct kvm_io_bus *bus, struct kvm_vcpu { struct kvm *kvm; - union { - struct vmcs *vmcs; - struct vcpu_svm *svm; - }; + struct preempt_notifier preempt_notifier; + int vcpu_id; struct mutex mutex; int cpu; - int launched; u64 host_tsc; struct kvm_run *run; int interrupt_window_open; int guest_mode; unsigned long requests; unsigned long irq_summary; /* bit vector: 1 per word in irq_pending */ -#define NR_IRQ_WORDS KVM_IRQ_BITMAP_SIZE(unsigned long) - unsigned long irq_pending[NR_IRQ_WORDS]; + DECLARE_BITMAP(irq_pending, KVM_NR_INTERRUPTS); unsigned long regs[NR_VCPU_REGS]; /* for rsp: vcpu_load_rsp_rip() */ unsigned long rip; /* needs vcpu_load_rsp_rip() */ @@ -357,15 +325,15 @@ struct kvm_vcpu { u64 pdptrs[4]; /* pae */ u64 shadow_efer; u64 apic_base; + struct kvm_lapic *apic; /* kernel irqchip context */ +#define VCPU_MP_STATE_RUNNABLE 0 +#define VCPU_MP_STATE_UNINITIALIZED 1 +#define VCPU_MP_STATE_INIT_RECEIVED 2 +#define VCPU_MP_STATE_SIPI_RECEIVED 3 +#define VCPU_MP_STATE_HALTED 4 + int mp_state; + int sipi_vector; u64 ia32_misc_enable_msr; - int nmsrs; - int save_nmsrs; - int msr_offset_efer; -#ifdef CONFIG_X86_64 - int msr_offset_kernel_gs_base; -#endif - struct vmx_msr_entry *guest_msrs; - struct vmx_msr_entry *host_msrs; struct kvm_mmu mmu; @@ -379,16 +347,10 @@ struct kvm_vcpu { struct kvm_guest_debug guest_debug; - char fx_buf[FX_BUF_SIZE]; - char *host_fx_image; - char *guest_fx_image; + struct i387_fxsave_struct host_fx_image; + struct i387_fxsave_struct guest_fx_image; int fpu_active; int guest_fpu_loaded; - struct vmx_host_state { - int loaded; - u16 fs_sel, gs_sel, ldt_sel; - int fs_gs_ldt_reload_needed; - } vmx_host_state; int mmio_needed; int mmio_read_completed; @@ -399,6 +361,7 @@ struct kvm_vcpu { gva_t mmio_fault_cr2; struct kvm_pio_request pio; void *pio_data; + wait_queue_head_t wq; int sigset_active; sigset_t sigset; @@ -436,7 +399,7 @@ struct kvm_memory_slot { }; struct kvm { - spinlock_t lock; /* protects everything except vcpus */ + struct mutex lock; /* protects everything except vcpus */ int naliases; struct kvm_mem_alias aliases[KVM_ALIAS_SLOTS]; int nmemslots; @@ -447,39 +410,59 @@ struct kvm { struct list_head active_mmu_pages; int n_free_mmu_pages; struct hlist_head mmu_page_hash[KVM_NUM_MMU_PAGES]; - int nvcpus; - struct kvm_vcpu vcpus[KVM_MAX_VCPUS]; - int memory_config_version; - int busy; + struct kvm_vcpu *vcpus[KVM_MAX_VCPUS]; unsigned long rmap_overflow; struct list_head vm_list; struct file *filp; struct kvm_io_bus mmio_bus; struct kvm_io_bus pio_bus; + struct kvm_pic *vpic; + struct kvm_ioapic *vioapic; + int round_robin_prev_vcpu; }; +static inline struct kvm_pic *pic_irqchip(struct kvm *kvm) +{ + return kvm->vpic; +} + +static inline struct kvm_ioapic *ioapic_irqchip(struct kvm *kvm) +{ + return kvm->vioapic; +} + +static inline int irqchip_in_kernel(struct kvm *kvm) +{ + return pic_irqchip(kvm) != 0; +} + struct descriptor_table { u16 limit; unsigned long base; } __attribute__((packed)); -struct kvm_arch_ops { +struct kvm_x86_ops { int (*cpu_has_kvm_support)(void); /* __init */ int (*disabled_by_bios)(void); /* __init */ void (*hardware_enable)(void *dummy); /* __init */ void (*hardware_disable)(void *dummy); + void (*check_processor_compatibility)(void *rtn); int (*hardware_setup)(void); /* __init */ void (*hardware_unsetup)(void); /* __exit */ - int (*vcpu_create)(struct kvm_vcpu *vcpu); + /* Create, but do not attach this VCPU */ + struct kvm_vcpu *(*vcpu_create)(struct kvm *kvm, unsigned id); void (*vcpu_free)(struct kvm_vcpu *vcpu); + void (*vcpu_reset)(struct kvm_vcpu *vcpu); - void (*vcpu_load)(struct kvm_vcpu *vcpu); + void (*prepare_guest_switch)(struct kvm_vcpu *vcpu); + void (*vcpu_load)(struct kvm_vcpu *vcpu, int cpu); void (*vcpu_put)(struct kvm_vcpu *vcpu); void (*vcpu_decache)(struct kvm_vcpu *vcpu); int (*set_guest_debug)(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg); + void (*guest_debug_pre)(struct kvm_vcpu *vcpu); int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata); int (*set_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 data); u64 (*get_segment_base)(struct kvm_vcpu *vcpu, int seg); @@ -505,27 +488,43 @@ struct kvm_arch_ops { unsigned long (*get_rflags)(struct kvm_vcpu *vcpu); void (*set_rflags)(struct kvm_vcpu *vcpu, unsigned long rflags); - void (*invlpg)(struct kvm_vcpu *vcpu, gva_t addr); void (*tlb_flush)(struct kvm_vcpu *vcpu); void (*inject_page_fault)(struct kvm_vcpu *vcpu, unsigned long addr, u32 err_code); void (*inject_gp)(struct kvm_vcpu *vcpu, unsigned err_code); - int (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run); - int (*vcpu_setup)(struct kvm_vcpu *vcpu); + void (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run); + int (*handle_exit)(struct kvm_run *run, struct kvm_vcpu *vcpu); void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu); void (*patch_hypercall)(struct kvm_vcpu *vcpu, unsigned char *hypercall_addr); + int (*get_irq)(struct kvm_vcpu *vcpu); + void (*set_irq)(struct kvm_vcpu *vcpu, int vec); + void (*inject_pending_irq)(struct kvm_vcpu *vcpu); + void (*inject_pending_vectors)(struct kvm_vcpu *vcpu, + struct kvm_run *run); }; -extern struct kvm_arch_ops *kvm_arch_ops; +extern struct kvm_x86_ops *kvm_x86_ops; + +/* The guest did something we don't support. */ +#define pr_unimpl(vcpu, fmt, ...) \ + do { \ + if (printk_ratelimit()) \ + printk(KERN_ERR "kvm: %i: cpu%i " fmt, \ + current->tgid, (vcpu)->vcpu_id , ## __VA_ARGS__); \ + } while(0) #define kvm_printf(kvm, fmt ...) printk(KERN_DEBUG fmt) #define vcpu_printf(vcpu, fmt...) kvm_printf(vcpu->kvm, fmt) -int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module); -void kvm_exit_arch(void); +int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id); +void kvm_vcpu_uninit(struct kvm_vcpu *vcpu); + +int kvm_init_x86(struct kvm_x86_ops *ops, unsigned int vcpu_size, + struct module *module); +void kvm_exit_x86(void); int kvm_mmu_module_init(void); void kvm_mmu_module_exit(void); @@ -545,8 +544,6 @@ static inline int is_error_hpa(hpa_t hpa) { return hpa >> HPA_MSB; } hpa_t gva_to_hpa(struct kvm_vcpu *vcpu, gva_t gva); struct page *gva_to_page(struct kvm_vcpu *vcpu, gva_t gva); -void kvm_emulator_want_group7_invlpg(void); - extern hpa_t bad_page_address; struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn); @@ -561,6 +558,7 @@ enum emulation_result { int emulate_instruction(struct kvm_vcpu *vcpu, struct kvm_run *run, unsigned long cr2, u16 error_code); +void kvm_report_emulation_failure(struct kvm_vcpu *cvpu, const char *context); void realmode_lgdt(struct kvm_vcpu *vcpu, u16 size, unsigned long address); void realmode_lidt(struct kvm_vcpu *vcpu, u16 size, unsigned long address); void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw, @@ -574,9 +572,11 @@ int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data); struct x86_emulate_ctxt; -int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, - int size, unsigned long count, int string, int down, - gva_t address, int rep, unsigned port); +int kvm_emulate_pio (struct kvm_vcpu *vcpu, struct kvm_run *run, int in, + int size, unsigned port); +int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, + int size, unsigned long count, int down, + gva_t address, int rep, unsigned port); void kvm_emulate_cpuid(struct kvm_vcpu *vcpu); int kvm_emulate_halt(struct kvm_vcpu *vcpu); int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address); @@ -590,34 +590,33 @@ void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0); void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr0); void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr0); void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr0); +unsigned long get_cr8(struct kvm_vcpu *vcpu); void lmsw(struct kvm_vcpu *vcpu, unsigned long msw); +void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l); int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata); int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data); void fx_init(struct kvm_vcpu *vcpu); -void load_msrs(struct vmx_msr_entry *e, int n); -void save_msrs(struct vmx_msr_entry *e, int n); void kvm_resched(struct kvm_vcpu *vcpu); void kvm_load_guest_fpu(struct kvm_vcpu *vcpu); void kvm_put_guest_fpu(struct kvm_vcpu *vcpu); void kvm_flush_remote_tlbs(struct kvm *kvm); -int kvm_read_guest(struct kvm_vcpu *vcpu, - gva_t addr, - unsigned long size, - void *dest); - -int kvm_write_guest(struct kvm_vcpu *vcpu, - gva_t addr, - unsigned long size, - void *data); +int emulator_read_std(unsigned long addr, + void *val, + unsigned int bytes, + struct kvm_vcpu *vcpu); +int emulator_write_emulated(unsigned long addr, + const void *val, + unsigned int bytes, + struct kvm_vcpu *vcpu); unsigned long segment_base(u16 selector); void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, - const u8 *old, const u8 *new, int bytes); + const u8 *new, 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_mmu_load(struct kvm_vcpu *vcpu); @@ -625,6 +624,16 @@ void kvm_mmu_unload(struct kvm_vcpu *vcpu); int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run); +static inline void kvm_guest_enter(void) +{ + current->flags |= PF_VCPU; +} + +static inline void kvm_guest_exit(void) +{ + current->flags &= ~PF_VCPU; +} + static inline int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva, u32 error_code) { @@ -656,17 +665,17 @@ static inline int is_long_mode(struct kvm_vcpu *vcpu) static inline int is_pae(struct kvm_vcpu *vcpu) { - return vcpu->cr4 & CR4_PAE_MASK; + return vcpu->cr4 & X86_CR4_PAE; } static inline int is_pse(struct kvm_vcpu *vcpu) { - return vcpu->cr4 & CR4_PSE_MASK; + return vcpu->cr4 & X86_CR4_PSE; } static inline int is_paging(struct kvm_vcpu *vcpu) { - return vcpu->cr0 & CR0_PG_MASK; + return vcpu->cr0 & X86_CR0_PG; } static inline int memslot_id(struct kvm *kvm, struct kvm_memory_slot *slot) @@ -746,12 +755,12 @@ static inline unsigned long read_msr(unsigned long msr) } #endif -static inline void fx_save(void *image) +static inline void fx_save(struct i387_fxsave_struct *image) { asm ("fxsave (%0)":: "r" (image)); } -static inline void fx_restore(void *image) +static inline void fx_restore(struct i387_fxsave_struct *image) { asm ("fxrstor (%0)":: "r" (image)); } diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index cd0557954e50..af2d288c881d 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c @@ -18,6 +18,7 @@ #include "kvm.h" #include "x86_emulate.h" #include "segment_descriptor.h" +#include "irq.h" #include <linux/kvm.h> #include <linux/module.h> @@ -37,6 +38,7 @@ #include <linux/cpumask.h> #include <linux/smp.h> #include <linux/anon_inodes.h> +#include <linux/profile.h> #include <asm/processor.h> #include <asm/msr.h> @@ -52,9 +54,11 @@ static LIST_HEAD(vm_list); static cpumask_t cpus_hardware_enabled; -struct kvm_arch_ops *kvm_arch_ops; +struct kvm_x86_ops *kvm_x86_ops; +struct kmem_cache *kvm_vcpu_cache; +EXPORT_SYMBOL_GPL(kvm_vcpu_cache); -static void hardware_disable(void *ignored); +static __read_mostly struct preempt_ops kvm_preempt_ops; #define STAT_OFFSET(x) offsetof(struct kvm_vcpu, stat.x) @@ -73,6 +77,7 @@ static struct kvm_stats_debugfs_item { { "signal_exits", STAT_OFFSET(signal_exits) }, { "irq_window", STAT_OFFSET(irq_window_exits) }, { "halt_exits", STAT_OFFSET(halt_exits) }, + { "halt_wakeup", STAT_OFFSET(halt_wakeup) }, { "request_irq", STAT_OFFSET(request_irq_exits) }, { "irq_exits", STAT_OFFSET(irq_exits) }, { "light_exits", STAT_OFFSET(light_exits) }, @@ -84,10 +89,17 @@ static struct dentry *debugfs_dir; #define MAX_IO_MSRS 256 -#define CR0_RESEVED_BITS 0xffffffff1ffaffc0ULL -#define LMSW_GUEST_MASK 0x0eULL -#define CR4_RESEVED_BITS (~((1ULL << 11) - 1)) -#define CR8_RESEVED_BITS (~0x0fULL) +#define CR0_RESERVED_BITS \ + (~(unsigned long)(X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS \ + | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM \ + | X86_CR0_NW | X86_CR0_CD | X86_CR0_PG)) +#define CR4_RESERVED_BITS \ + (~(unsigned long)(X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD | X86_CR4_DE\ + | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_MCE \ + | X86_CR4_PGE | X86_CR4_PCE | X86_CR4_OSFXSR \ + | X86_CR4_OSXMMEXCPT | X86_CR4_VMXE)) + +#define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR) #define EFER_RESERVED_BITS 0xfffffffffffff2fe #ifdef CONFIG_X86_64 @@ -139,82 +151,14 @@ 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) -{ - unsigned char *host_buf = dest; - unsigned long req_size = size; - - while (size) { - hpa_t paddr; - unsigned now; - unsigned offset; - hva_t guest_buf; - - paddr = gva_to_hpa(vcpu, addr); - - if (is_error_hpa(paddr)) - break; - - guest_buf = (hva_t)kmap_atomic( - pfn_to_page(paddr >> PAGE_SHIFT), - KM_USER0); - offset = addr & ~PAGE_MASK; - guest_buf |= offset; - now = min(size, PAGE_SIZE - offset); - memcpy(host_buf, (void*)guest_buf, now); - host_buf += now; - addr += now; - size -= now; - kunmap_atomic((void *)(guest_buf & PAGE_MASK), KM_USER0); - } - return req_size - size; -} -EXPORT_SYMBOL_GPL(kvm_read_guest); - -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; - - while (size) { - hpa_t paddr; - 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; - guest_buf |= offset; - now = min(size, PAGE_SIZE - offset); - memcpy((void*)guest_buf, host_buf, now); - host_buf += now; - addr += now; - size -= now; - kunmap_atomic((void *)(guest_buf & PAGE_MASK), KM_USER0); - } - return req_size - size; -} -EXPORT_SYMBOL_GPL(kvm_write_guest); - void kvm_load_guest_fpu(struct kvm_vcpu *vcpu) { if (!vcpu->fpu_active || vcpu->guest_fpu_loaded) return; vcpu->guest_fpu_loaded = 1; - fx_save(vcpu->host_fx_image); - fx_restore(vcpu->guest_fx_image); + fx_save(&vcpu->host_fx_image); + fx_restore(&vcpu->guest_fx_image); } EXPORT_SYMBOL_GPL(kvm_load_guest_fpu); @@ -224,8 +168,8 @@ void kvm_put_guest_fpu(struct kvm_vcpu *vcpu) return; vcpu->guest_fpu_loaded = 0; - fx_save(vcpu->guest_fx_image); - fx_restore(vcpu->host_fx_image); + fx_save(&vcpu->guest_fx_image); + fx_restore(&vcpu->host_fx_image); } EXPORT_SYMBOL_GPL(kvm_put_guest_fpu); @@ -234,13 +178,21 @@ EXPORT_SYMBOL_GPL(kvm_put_guest_fpu); */ static void vcpu_load(struct kvm_vcpu *vcpu) { + int cpu; + mutex_lock(&vcpu->mutex); - kvm_arch_ops->vcpu_load(vcpu); + cpu = get_cpu(); + preempt_notifier_register(&vcpu->preempt_notifier); + kvm_x86_ops->vcpu_load(vcpu, cpu); + put_cpu(); } static void vcpu_put(struct kvm_vcpu *vcpu) { - kvm_arch_ops->vcpu_put(vcpu); + preempt_disable(); + kvm_x86_ops->vcpu_put(vcpu); + preempt_notifier_unregister(&vcpu->preempt_notifier); + preempt_enable(); mutex_unlock(&vcpu->mutex); } @@ -261,8 +213,10 @@ void kvm_flush_remote_tlbs(struct kvm *kvm) atomic_set(&completed, 0); cpus_clear(cpus); needed = 0; - for (i = 0; i < kvm->nvcpus; ++i) { - vcpu = &kvm->vcpus[i]; + for (i = 0; i < KVM_MAX_VCPUS; ++i) { + vcpu = kvm->vcpus[i]; + if (!vcpu) + continue; if (test_and_set_bit(KVM_TLB_FLUSH, &vcpu->requests)) continue; cpu = vcpu->cpu; @@ -286,37 +240,79 @@ void kvm_flush_remote_tlbs(struct kvm *kvm) } } +int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id) +{ + struct page *page; + int r; + + mutex_init(&vcpu->mutex); + vcpu->cpu = -1; + vcpu->mmu.root_hpa = INVALID_PAGE; + vcpu->kvm = kvm; + vcpu->vcpu_id = id; + if (!irqchip_in_kernel(kvm) || id == 0) + vcpu->mp_state = VCPU_MP_STATE_RUNNABLE; + else + vcpu->mp_state = VCPU_MP_STATE_UNINITIALIZED; + init_waitqueue_head(&vcpu->wq); + + page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (!page) { + r = -ENOMEM; + goto fail; + } + vcpu->run = page_address(page); + + page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (!page) { + r = -ENOMEM; + goto fail_free_run; + } + vcpu->pio_data = page_address(page); + + r = kvm_mmu_create(vcpu); + if (r < 0) + goto fail_free_pio_data; + + return 0; + +fail_free_pio_data: + free_page((unsigned long)vcpu->pio_data); +fail_free_run: + free_page((unsigned long)vcpu->run); +fail: + return -ENOMEM; +} +EXPORT_SYMBOL_GPL(kvm_vcpu_init); + +void kvm_vcpu_uninit(struct kvm_vcpu *vcpu) +{ + kvm_mmu_destroy(vcpu); + if (vcpu->apic) + hrtimer_cancel(&vcpu->apic->timer.dev); + kvm_free_apic(vcpu->apic); + free_page((unsigned long)vcpu->pio_data); + free_page((unsigned long)vcpu->run); +} +EXPORT_SYMBOL_GPL(kvm_vcpu_uninit); + static struct kvm *kvm_create_vm(void) { struct kvm *kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL); - int i; if (!kvm) return ERR_PTR(-ENOMEM); kvm_io_bus_init(&kvm->pio_bus); - spin_lock_init(&kvm->lock); + mutex_init(&kvm->lock); INIT_LIST_HEAD(&kvm->active_mmu_pages); kvm_io_bus_init(&kvm->mmio_bus); - for (i = 0; i < KVM_MAX_VCPUS; ++i) { - struct kvm_vcpu *vcpu = &kvm->vcpus[i]; - - mutex_init(&vcpu->mutex); - vcpu->cpu = -1; - vcpu->kvm = kvm; - vcpu->mmu.root_hpa = INVALID_PAGE; - } spin_lock(&kvm_lock); list_add(&kvm->vm_list, &vm_list); spin_unlock(&kvm_lock); return kvm; } -static int kvm_dev_open(struct inode *inode, struct file *filp) -{ - return 0; -} - /* * Free any memory in @free but not in @dont. */ @@ -353,7 +349,7 @@ static void free_pio_guest_pages(struct kvm_vcpu *vcpu) { int i; - for (i = 0; i < 2; ++i) + for (i = 0; i < ARRAY_SIZE(vcpu->pio.guest_pages); ++i) if (vcpu->pio.guest_pages[i]) { __free_page(vcpu->pio.guest_pages[i]); vcpu->pio.guest_pages[i] = NULL; @@ -362,30 +358,11 @@ static void free_pio_guest_pages(struct kvm_vcpu *vcpu) static void kvm_unload_vcpu_mmu(struct kvm_vcpu *vcpu) { - if (!vcpu->vmcs) - return; - vcpu_load(vcpu); kvm_mmu_unload(vcpu); vcpu_put(vcpu); } -static void kvm_free_vcpu(struct kvm_vcpu *vcpu) -{ - if (!vcpu->vmcs) - return; - - vcpu_load(vcpu); - kvm_mmu_destroy(vcpu); - vcpu_put(vcpu); - kvm_arch_ops->vcpu_free(vcpu); - free_page((unsigned long)vcpu->run); - vcpu->run = NULL; - free_page((unsigned long)vcpu->pio_data); - vcpu->pio_data = NULL; - free_pio_guest_pages(vcpu); -} - static void kvm_free_vcpus(struct kvm *kvm) { unsigned int i; @@ -394,14 +371,15 @@ static void kvm_free_vcpus(struct kvm *kvm) * Unpin any mmu pages first. */ for (i = 0; i < KVM_MAX_VCPUS; ++i) - kvm_unload_vcpu_mmu(&kvm->vcpus[i]); - for (i = 0; i < KVM_MAX_VCPUS; ++i) - kvm_free_vcpu(&kvm->vcpus[i]); -} + if (kvm->vcpus[i]) + kvm_unload_vcpu_mmu(kvm->vcpus[i]); + for (i = 0; i < KVM_MAX_VCPUS; ++i) { + if (kvm->vcpus[i]) { + kvm_x86_ops->vcpu_free(kvm->vcpus[i]); + kvm->vcpus[i] = NULL; + } + } -static int kvm_dev_release(struct inode *inode, struct file *filp) -{ - return 0; } static void kvm_destroy_vm(struct kvm *kvm) @@ -411,6 +389,8 @@ static void kvm_destroy_vm(struct kvm *kvm) spin_unlock(&kvm_lock); kvm_io_bus_destroy(&kvm->pio_bus); kvm_io_bus_destroy(&kvm->mmio_bus); + kfree(kvm->vpic); + kfree(kvm->vioapic); kvm_free_vcpus(kvm); kvm_free_physmem(kvm); kfree(kvm); @@ -426,7 +406,7 @@ static int kvm_vm_release(struct inode *inode, struct file *filp) static void inject_gp(struct kvm_vcpu *vcpu) { - kvm_arch_ops->inject_gp(vcpu, 0); + kvm_x86_ops->inject_gp(vcpu, 0); } /* @@ -437,58 +417,60 @@ static int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3) gfn_t pdpt_gfn = cr3 >> PAGE_SHIFT; unsigned offset = ((cr3 & (PAGE_SIZE-1)) >> 5) << 2; int i; - u64 pdpte; u64 *pdpt; int ret; struct page *page; + u64 pdpte[ARRAY_SIZE(vcpu->pdptrs)]; - spin_lock(&vcpu->kvm->lock); + mutex_lock(&vcpu->kvm->lock); page = gfn_to_page(vcpu->kvm, pdpt_gfn); - /* FIXME: !page - emulate? 0xff? */ + if (!page) { + ret = 0; + goto out; + } + pdpt = kmap_atomic(page, KM_USER0); + memcpy(pdpte, pdpt+offset, sizeof(pdpte)); + kunmap_atomic(pdpt, KM_USER0); - ret = 1; - for (i = 0; i < 4; ++i) { - pdpte = pdpt[offset + i]; - if ((pdpte & 1) && (pdpte & 0xfffffff0000001e6ull)) { + for (i = 0; i < ARRAY_SIZE(pdpte); ++i) { + if ((pdpte[i] & 1) && (pdpte[i] & 0xfffffff0000001e6ull)) { ret = 0; goto out; } } + ret = 1; - for (i = 0; i < 4; ++i) - vcpu->pdptrs[i] = pdpt[offset + i]; - + memcpy(vcpu->pdptrs, pdpte, sizeof(vcpu->pdptrs)); out: - kunmap_atomic(pdpt, KM_USER0); - spin_unlock(&vcpu->kvm->lock); + mutex_unlock(&vcpu->kvm->lock); return ret; } void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) { - if (cr0 & CR0_RESEVED_BITS) { + if (cr0 & CR0_RESERVED_BITS) { printk(KERN_DEBUG "set_cr0: 0x%lx #GP, reserved bits 0x%lx\n", cr0, vcpu->cr0); inject_gp(vcpu); return; } - if ((cr0 & CR0_NW_MASK) && !(cr0 & CR0_CD_MASK)) { + if ((cr0 & X86_CR0_NW) && !(cr0 & X86_CR0_CD)) { printk(KERN_DEBUG "set_cr0: #GP, CD == 0 && NW == 1\n"); inject_gp(vcpu); return; } - if ((cr0 & CR0_PG_MASK) && !(cr0 & CR0_PE_MASK)) { + if ((cr0 & X86_CR0_PG) && !(cr0 & X86_CR0_PE)) { printk(KERN_DEBUG "set_cr0: #GP, set PG flag " "and a clear PE flag\n"); inject_gp(vcpu); return; } - if (!is_paging(vcpu) && (cr0 & CR0_PG_MASK)) { + if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) { #ifdef CONFIG_X86_64 if ((vcpu->shadow_efer & EFER_LME)) { int cs_db, cs_l; @@ -499,7 +481,7 @@ void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) inject_gp(vcpu); return; } - kvm_arch_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l); + kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l); if (cs_l) { printk(KERN_DEBUG "set_cr0: #GP, start paging " "in long mode while CS.L == 1\n"); @@ -518,12 +500,12 @@ void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) } - kvm_arch_ops->set_cr0(vcpu, cr0); + kvm_x86_ops->set_cr0(vcpu, cr0); vcpu->cr0 = cr0; - spin_lock(&vcpu->kvm->lock); + mutex_lock(&vcpu->kvm->lock); kvm_mmu_reset_context(vcpu); - spin_unlock(&vcpu->kvm->lock); + mutex_unlock(&vcpu->kvm->lock); return; } EXPORT_SYMBOL_GPL(set_cr0); @@ -536,62 +518,72 @@ EXPORT_SYMBOL_GPL(lmsw); void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) { - if (cr4 & CR4_RESEVED_BITS) { + if (cr4 & CR4_RESERVED_BITS) { printk(KERN_DEBUG "set_cr4: #GP, reserved bits\n"); inject_gp(vcpu); return; } if (is_long_mode(vcpu)) { - if (!(cr4 & CR4_PAE_MASK)) { + if (!(cr4 & X86_CR4_PAE)) { printk(KERN_DEBUG "set_cr4: #GP, clearing PAE while " "in long mode\n"); inject_gp(vcpu); return; } - } else if (is_paging(vcpu) && !is_pae(vcpu) && (cr4 & CR4_PAE_MASK) + } else if (is_paging(vcpu) && !is_pae(vcpu) && (cr4 & X86_CR4_PAE) && !load_pdptrs(vcpu, vcpu->cr3)) { printk(KERN_DEBUG "set_cr4: #GP, pdptrs reserved bits\n"); inject_gp(vcpu); + return; } - if (cr4 & CR4_VMXE_MASK) { + if (cr4 & X86_CR4_VMXE) { printk(KERN_DEBUG "set_cr4: #GP, setting VMXE\n"); inject_gp(vcpu); return; } - kvm_arch_ops->set_cr4(vcpu, cr4); - spin_lock(&vcpu->kvm->lock); + kvm_x86_ops->set_cr4(vcpu, cr4); + vcpu->cr4 = cr4; + mutex_lock(&vcpu->kvm->lock); kvm_mmu_reset_context(vcpu); - spin_unlock(&vcpu->kvm->lock); + mutex_unlock(&vcpu->kvm->lock); } 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_RESERVED_BITS) { printk(KERN_DEBUG "set_cr3: #GP, reserved bits\n"); inject_gp(vcpu); return; } } else { - if (cr3 & CR3_RESEVED_BITS) { - printk(KERN_DEBUG "set_cr3: #GP, reserved bits\n"); - inject_gp(vcpu); - return; - } - if (is_paging(vcpu) && is_pae(vcpu) && - !load_pdptrs(vcpu, cr3)) { - printk(KERN_DEBUG "set_cr3: #GP, pdptrs " - "reserved bits\n"); - inject_gp(vcpu); - return; + if (is_pae(vcpu)) { + if (cr3 & CR3_PAE_RESERVED_BITS) { + printk(KERN_DEBUG + "set_cr3: #GP, reserved bits\n"); + inject_gp(vcpu); + return; + } + if (is_paging(vcpu) && !load_pdptrs(vcpu, cr3)) { + printk(KERN_DEBUG "set_cr3: #GP, pdptrs " + "reserved bits\n"); + inject_gp(vcpu); + return; + } + } else { + if (cr3 & CR3_NONPAE_RESERVED_BITS) { + printk(KERN_DEBUG + "set_cr3: #GP, reserved bits\n"); + inject_gp(vcpu); + return; + } } } - vcpu->cr3 = cr3; - spin_lock(&vcpu->kvm->lock); + mutex_lock(&vcpu->kvm->lock); /* * Does the new cr3 value map to physical memory? (Note, we * catch an invalid cr3 even in real-mode, because it would @@ -603,46 +595,73 @@ void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) */ if (unlikely(!gfn_to_memslot(vcpu->kvm, cr3 >> PAGE_SHIFT))) inject_gp(vcpu); - else + else { + vcpu->cr3 = cr3; vcpu->mmu.new_cr3(vcpu); - spin_unlock(&vcpu->kvm->lock); + } + mutex_unlock(&vcpu->kvm->lock); } EXPORT_SYMBOL_GPL(set_cr3); void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8) { - if ( cr8 & CR8_RESEVED_BITS) { + if (cr8 & CR8_RESERVED_BITS) { printk(KERN_DEBUG "set_cr8: #GP, reserved bits 0x%lx\n", cr8); inject_gp(vcpu); return; } - vcpu->cr8 = cr8; + if (irqchip_in_kernel(vcpu->kvm)) + kvm_lapic_set_tpr(vcpu, cr8); + else + vcpu->cr8 = cr8; } EXPORT_SYMBOL_GPL(set_cr8); -void fx_init(struct kvm_vcpu *vcpu) +unsigned long get_cr8(struct kvm_vcpu *vcpu) +{ + if (irqchip_in_kernel(vcpu->kvm)) + return kvm_lapic_get_cr8(vcpu); + else + return vcpu->cr8; +} +EXPORT_SYMBOL_GPL(get_cr8); + +u64 kvm_get_apic_base(struct kvm_vcpu *vcpu) { - struct __attribute__ ((__packed__)) fx_image_s { - u16 control; //fcw - u16 status; //fsw - u16 tag; // ftw - u16 opcode; //fop - u64 ip; // fpu ip - u64 operand;// fpu dp - u32 mxcsr; - u32 mxcsr_mask; + if (irqchip_in_kernel(vcpu->kvm)) + return vcpu->apic_base; + else + return vcpu->apic_base; +} +EXPORT_SYMBOL_GPL(kvm_get_apic_base); - } *fx_image; +void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data) +{ + /* TODO: reserve bits check */ + if (irqchip_in_kernel(vcpu->kvm)) + kvm_lapic_set_base(vcpu, data); + else + vcpu->apic_base = data; +} +EXPORT_SYMBOL_GPL(kvm_set_apic_base); + +void fx_init(struct kvm_vcpu *vcpu) +{ + unsigned after_mxcsr_mask; - fx_save(vcpu->host_fx_image); + /* Initialize guest FPU by resetting ours and saving into guest's */ + preempt_disable(); + fx_save(&vcpu->host_fx_image); fpu_init(); - fx_save(vcpu->guest_fx_image); - fx_restore(vcpu->host_fx_image); + fx_save(&vcpu->guest_fx_image); + fx_restore(&vcpu->host_fx_image); + preempt_enable(); - fx_image = (struct fx_image_s *)vcpu->guest_fx_image; - fx_image->mxcsr = 0x1f80; - memset(vcpu->guest_fx_image + sizeof(struct fx_image_s), - 0, FX_IMAGE_SIZE - sizeof(struct fx_image_s)); + vcpu->cr0 |= X86_CR0_ET; + after_mxcsr_mask = offsetof(struct i387_fxsave_struct, st_space); + vcpu->guest_fx_image.mxcsr = 0x1f80; + memset((void *)&vcpu->guest_fx_image + after_mxcsr_mask, + 0, sizeof(struct i387_fxsave_struct) - after_mxcsr_mask); } EXPORT_SYMBOL_GPL(fx_init); @@ -661,7 +680,6 @@ static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm, unsigned long i; struct kvm_memory_slot *memslot; struct kvm_memory_slot old, new; - int memory_config_version; r = -EINVAL; /* General sanity checks */ @@ -681,10 +699,8 @@ static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm, if (!npages) mem->flags &= ~KVM_MEM_LOG_DIRTY_PAGES; -raced: - spin_lock(&kvm->lock); + mutex_lock(&kvm->lock); - memory_config_version = kvm->memory_config_version; new = old = *memslot; new.base_gfn = base_gfn; @@ -707,11 +723,6 @@ raced: (base_gfn >= s->base_gfn + s->npages))) goto out_unlock; } - /* - * Do memory allocations outside lock. memory_config_version will - * detect any races. - */ - spin_unlock(&kvm->lock); /* Deallocate if slot is being removed */ if (!npages) @@ -728,14 +739,14 @@ raced: new.phys_mem = vmalloc(npages * sizeof(struct page *)); if (!new.phys_mem) - goto out_free; + goto out_unlock; memset(new.phys_mem, 0, npages * sizeof(struct page *)); for (i = 0; i < npages; ++i) { new.phys_mem[i] = alloc_page(GFP_HIGHUSER | __GFP_ZERO); if (!new.phys_mem[i]) - goto out_free; + goto out_unlock; set_page_private(new.phys_mem[i],0); } } @@ -746,39 +757,25 @@ raced: new.dirty_bitmap = vmalloc(dirty_bytes); if (!new.dirty_bitmap) - goto out_free; + goto out_unlock; memset(new.dirty_bitmap, 0, dirty_bytes); } - spin_lock(&kvm->lock); - - if (memory_config_version != kvm->memory_config_version) { - spin_unlock(&kvm->lock); - kvm_free_physmem_slot(&new, &old); - goto raced; - } - - r = -EAGAIN; - if (kvm->busy) - goto out_unlock; - if (mem->slot >= kvm->nmemslots) kvm->nmemslots = mem->slot + 1; *memslot = new; - ++kvm->memory_config_version; kvm_mmu_slot_remove_write_access(kvm, mem->slot); kvm_flush_remote_tlbs(kvm); - spin_unlock(&kvm->lock); + mutex_unlock(&kvm->lock); kvm_free_physmem_slot(&old, &new); return 0; out_unlock: - spin_unlock(&kvm->lock); -out_free: + mutex_unlock(&kvm->lock); kvm_free_physmem_slot(&new, &old); out: return r; @@ -795,14 +792,8 @@ static int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, int n; unsigned long any = 0; - spin_lock(&kvm->lock); + mutex_lock(&kvm->lock); - /* - * Prevent changes to guest memory configuration even while the lock - * is not taken. - */ - ++kvm->busy; - spin_unlock(&kvm->lock); r = -EINVAL; if (log->slot >= KVM_MEMORY_SLOTS) goto out; @@ -821,18 +812,17 @@ static int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, if (copy_to_user(log->dirty_bitmap, memslot->dirty_bitmap, n)) goto out; - spin_lock(&kvm->lock); - kvm_mmu_slot_remove_write_access(kvm, log->slot); - kvm_flush_remote_tlbs(kvm); - memset(memslot->dirty_bitmap, 0, n); - spin_unlock(&kvm->lock); + /* If nothing is dirty, don't bother messing with page tables. */ + if (any) { + kvm_mmu_slot_remove_write_access(kvm, log->slot); + kvm_flush_remote_tlbs(kvm); + memset(memslot->dirty_bitmap, 0, n); + } r = 0; out: - spin_lock(&kvm->lock); - --kvm->busy; - spin_unlock(&kvm->lock); + mutex_unlock(&kvm->lock); return r; } @@ -862,7 +852,7 @@ static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm, < alias->target_phys_addr) goto out; - spin_lock(&kvm->lock); + mutex_lock(&kvm->lock); p = &kvm->aliases[alias->slot]; p->base_gfn = alias->guest_phys_addr >> PAGE_SHIFT; @@ -876,7 +866,7 @@ static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm, kvm_mmu_zap_all(kvm); - spin_unlock(&kvm->lock); + mutex_unlock(&kvm->lock); return 0; @@ -884,6 +874,63 @@ out: return r; } +static int kvm_vm_ioctl_get_irqchip(struct kvm *kvm, struct kvm_irqchip *chip) +{ + int r; + + r = 0; + switch (chip->chip_id) { + case KVM_IRQCHIP_PIC_MASTER: + memcpy (&chip->chip.pic, + &pic_irqchip(kvm)->pics[0], + sizeof(struct kvm_pic_state)); + break; + case KVM_IRQCHIP_PIC_SLAVE: + memcpy (&chip->chip.pic, + &pic_irqchip(kvm)->pics[1], + sizeof(struct kvm_pic_state)); + break; + case KVM_IRQCHIP_IOAPIC: + memcpy (&chip->chip.ioapic, + ioapic_irqchip(kvm), + sizeof(struct kvm_ioapic_state)); + break; + default: + r = -EINVAL; + break; + } + return r; +} + +static int kvm_vm_ioctl_set_irqchip(struct kvm *kvm, struct kvm_irqchip *chip) +{ + int r; + + r = 0; + switch (chip->chip_id) { + case KVM_IRQCHIP_PIC_MASTER: + memcpy (&pic_irqchip(kvm)->pics[0], + &chip->chip.pic, + sizeof(struct kvm_pic_state)); + break; + case KVM_IRQCHIP_PIC_SLAVE: + memcpy (&pic_irqchip(kvm)->pics[1], + &chip->chip.pic, + sizeof(struct kvm_pic_state)); + break; + case KVM_IRQCHIP_IOAPIC: + memcpy (ioapic_irqchip(kvm), + &chip->chip.ioapic, + sizeof(struct kvm_ioapic_state)); + break; + default: + r = -EINVAL; + break; + } + kvm_pic_update_irq(pic_irqchip(kvm)); + return r; +} + static gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn) { int i; @@ -930,37 +977,26 @@ struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn) } EXPORT_SYMBOL_GPL(gfn_to_page); +/* WARNING: Does not work on aliased pages. */ void mark_page_dirty(struct kvm *kvm, gfn_t gfn) { - int i; struct kvm_memory_slot *memslot; - unsigned long rel_gfn; - for (i = 0; i < kvm->nmemslots; ++i) { - memslot = &kvm->memslots[i]; - - if (gfn >= memslot->base_gfn - && gfn < memslot->base_gfn + memslot->npages) { + memslot = __gfn_to_memslot(kvm, gfn); + if (memslot && memslot->dirty_bitmap) { + unsigned long rel_gfn = gfn - memslot->base_gfn; - if (!memslot->dirty_bitmap) - return; - - rel_gfn = gfn - memslot->base_gfn; - - /* avoid RMW */ - if (!test_bit(rel_gfn, memslot->dirty_bitmap)) - set_bit(rel_gfn, memslot->dirty_bitmap); - return; - } + /* avoid RMW */ + if (!test_bit(rel_gfn, memslot->dirty_bitmap)) + set_bit(rel_gfn, memslot->dirty_bitmap); } } -static int emulator_read_std(unsigned long addr, +int emulator_read_std(unsigned long addr, void *val, unsigned int bytes, - struct x86_emulate_ctxt *ctxt) + struct kvm_vcpu *vcpu) { - struct kvm_vcpu *vcpu = ctxt->vcpu; void *data = val; while (bytes) { @@ -990,26 +1026,42 @@ static int emulator_read_std(unsigned long addr, return X86EMUL_CONTINUE; } +EXPORT_SYMBOL_GPL(emulator_read_std); static int emulator_write_std(unsigned long addr, const void *val, unsigned int bytes, - struct x86_emulate_ctxt *ctxt) + struct kvm_vcpu *vcpu) { - printk(KERN_ERR "emulator_write_std: addr %lx n %d\n", - addr, bytes); + pr_unimpl(vcpu, "emulator_write_std: addr %lx n %d\n", addr, bytes); return X86EMUL_UNHANDLEABLE; } +/* + * Only apic need an MMIO device hook, so shortcut now.. + */ +static struct kvm_io_device *vcpu_find_pervcpu_dev(struct kvm_vcpu *vcpu, + gpa_t addr) +{ + struct kvm_io_device *dev; + + if (vcpu->apic) { + dev = &vcpu->apic->dev; + if (dev->in_range(dev, addr)) + return dev; + } + return NULL; +} + static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu, gpa_t addr) { - /* - * Note that its important to have this wrapper function because - * in the very near future we will be checking for MMIOs against - * the LAPIC as well as the general MMIO bus - */ - return kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr); + struct kvm_io_device *dev; + + dev = vcpu_find_pervcpu_dev(vcpu, addr); + if (dev == NULL) + dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr); + return dev; } static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu, @@ -1021,9 +1073,8 @@ static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu, static int emulator_read_emulated(unsigned long addr, void *val, unsigned int bytes, - struct x86_emulate_ctxt *ctxt) + struct kvm_vcpu *vcpu) { - struct kvm_vcpu *vcpu = ctxt->vcpu; struct kvm_io_device *mmio_dev; gpa_t gpa; @@ -1031,7 +1082,7 @@ static int emulator_read_emulated(unsigned long addr, memcpy(val, vcpu->mmio_data, bytes); vcpu->mmio_read_completed = 0; return X86EMUL_CONTINUE; - } else if (emulator_read_std(addr, val, bytes, ctxt) + } else if (emulator_read_std(addr, val, bytes, vcpu) == X86EMUL_CONTINUE) return X86EMUL_CONTINUE; @@ -1061,7 +1112,6 @@ static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa, { struct page *page; void *virt; - unsigned offset = offset_in_page(gpa); if (((gpa + bytes - 1) >> PAGE_SHIFT) != (gpa >> PAGE_SHIFT)) return 0; @@ -1070,7 +1120,7 @@ static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa, return 0; mark_page_dirty(vcpu->kvm, gpa >> PAGE_SHIFT); virt = kmap_atomic(page, KM_USER0); - kvm_mmu_pte_write(vcpu, gpa, virt + offset, val, bytes); + kvm_mmu_pte_write(vcpu, gpa, val, bytes); memcpy(virt + offset_in_page(gpa), val, bytes); kunmap_atomic(virt, KM_USER0); return 1; @@ -1079,14 +1129,13 @@ static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa, static int emulator_write_emulated_onepage(unsigned long addr, const void *val, unsigned int bytes, - struct x86_emulate_ctxt *ctxt) + struct kvm_vcpu *vcpu) { - struct kvm_vcpu *vcpu = ctxt->vcpu; struct kvm_io_device *mmio_dev; gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, addr); if (gpa == UNMAPPED_GVA) { - kvm_arch_ops->inject_page_fault(vcpu, addr, 2); + kvm_x86_ops->inject_page_fault(vcpu, addr, 2); return X86EMUL_PROPAGATE_FAULT; } @@ -1111,31 +1160,32 @@ static int emulator_write_emulated_onepage(unsigned long addr, return X86EMUL_CONTINUE; } -static int emulator_write_emulated(unsigned long addr, +int emulator_write_emulated(unsigned long addr, const void *val, unsigned int bytes, - struct x86_emulate_ctxt *ctxt) + struct kvm_vcpu *vcpu) { /* Crossing a page boundary? */ if (((addr + bytes - 1) ^ addr) & PAGE_MASK) { int rc, now; now = -addr & ~PAGE_MASK; - rc = emulator_write_emulated_onepage(addr, val, now, ctxt); + rc = emulator_write_emulated_onepage(addr, val, now, vcpu); if (rc != X86EMUL_CONTINUE) return rc; addr += now; val += now; bytes -= now; } - return emulator_write_emulated_onepage(addr, val, bytes, ctxt); + return emulator_write_emulated_onepage(addr, val, bytes, vcpu); } +EXPORT_SYMBOL_GPL(emulator_write_emulated); static int emulator_cmpxchg_emulated(unsigned long addr, const void *old, const void *new, unsigned int bytes, - struct x86_emulate_ctxt *ctxt) + struct kvm_vcpu *vcpu) { static int reported; @@ -1143,12 +1193,12 @@ static int emulator_cmpxchg_emulated(unsigned long addr, reported = 1; printk(KERN_WARNING "kvm: emulating exchange as write\n"); } - return emulator_write_emulated(addr, new, bytes, ctxt); + return emulator_write_emulated(addr, new, bytes, vcpu); } static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg) { - return kvm_arch_ops->get_segment_base(vcpu, seg); + return kvm_x86_ops->get_segment_base(vcpu, seg); } int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address) @@ -1158,10 +1208,8 @@ int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address) int emulate_clts(struct kvm_vcpu *vcpu) { - unsigned long cr0; - - cr0 = vcpu->cr0 & ~CR0_TS_MASK; - kvm_arch_ops->set_cr0(vcpu, cr0); + vcpu->cr0 &= ~X86_CR0_TS; + kvm_x86_ops->set_cr0(vcpu, vcpu->cr0); return X86EMUL_CONTINUE; } @@ -1171,11 +1219,10 @@ int emulator_get_dr(struct x86_emulate_ctxt* ctxt, int dr, unsigned long *dest) switch (dr) { case 0 ... 3: - *dest = kvm_arch_ops->get_dr(vcpu, dr); + *dest = kvm_x86_ops->get_dr(vcpu, dr); return X86EMUL_CONTINUE; default: - printk(KERN_DEBUG "%s: unexpected dr %u\n", - __FUNCTION__, dr); + pr_unimpl(vcpu, "%s: unexpected dr %u\n", __FUNCTION__, dr); return X86EMUL_UNHANDLEABLE; } } @@ -1185,7 +1232,7 @@ int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long value) unsigned long mask = (ctxt->mode == X86EMUL_MODE_PROT64) ? ~0ULL : ~0U; int exception; - kvm_arch_ops->set_dr(ctxt->vcpu, dr, value & mask, &exception); + kvm_x86_ops->set_dr(ctxt->vcpu, dr, value & mask, &exception); if (exception) { /* FIXME: better handling */ return X86EMUL_UNHANDLEABLE; @@ -1193,25 +1240,25 @@ int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long value) return X86EMUL_CONTINUE; } -static void report_emulation_failure(struct x86_emulate_ctxt *ctxt) +void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context) { static int reported; u8 opcodes[4]; - unsigned long rip = ctxt->vcpu->rip; + unsigned long rip = vcpu->rip; unsigned long rip_linear; - rip_linear = rip + get_segment_base(ctxt->vcpu, VCPU_SREG_CS); + rip_linear = rip + get_segment_base(vcpu, VCPU_SREG_CS); if (reported) return; - emulator_read_std(rip_linear, (void *)opcodes, 4, ctxt); + emulator_read_std(rip_linear, (void *)opcodes, 4, vcpu); - printk(KERN_ERR "emulation failed but !mmio_needed?" - " rip %lx %02x %02x %02x %02x\n", - rip, opcodes[0], opcodes[1], opcodes[2], opcodes[3]); + printk(KERN_ERR "emulation failed (%s) rip %lx %02x %02x %02x %02x\n", + context, rip, opcodes[0], opcodes[1], opcodes[2], opcodes[3]); reported = 1; } +EXPORT_SYMBOL_GPL(kvm_report_emulation_failure); struct x86_emulate_ops emulate_ops = { .read_std = emulator_read_std, @@ -1231,12 +1278,12 @@ int emulate_instruction(struct kvm_vcpu *vcpu, int cs_db, cs_l; vcpu->mmio_fault_cr2 = cr2; - kvm_arch_ops->cache_regs(vcpu); + kvm_x86_ops->cache_regs(vcpu); - kvm_arch_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l); + kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l); emulate_ctxt.vcpu = vcpu; - emulate_ctxt.eflags = kvm_arch_ops->get_rflags(vcpu); + emulate_ctxt.eflags = kvm_x86_ops->get_rflags(vcpu); emulate_ctxt.cr2 = cr2; emulate_ctxt.mode = (emulate_ctxt.eflags & X86_EFLAGS_VM) ? X86EMUL_MODE_REAL : cs_l @@ -1259,9 +1306,13 @@ int emulate_instruction(struct kvm_vcpu *vcpu, emulate_ctxt.fs_base = get_segment_base(vcpu, VCPU_SREG_FS); vcpu->mmio_is_write = 0; + vcpu->pio.string = 0; r = x86_emulate_memop(&emulate_ctxt, &emulate_ops); + if (vcpu->pio.string) + return EMULATE_DO_MMIO; if ((r || vcpu->mmio_is_write) && run) { + run->exit_reason = KVM_EXIT_MMIO; run->mmio.phys_addr = vcpu->mmio_phys_addr; memcpy(run->mmio.data, vcpu->mmio_data, 8); run->mmio.len = vcpu->mmio_size; @@ -1272,14 +1323,14 @@ int emulate_instruction(struct kvm_vcpu *vcpu, if (kvm_mmu_unprotect_page_virt(vcpu, cr2)) return EMULATE_DONE; if (!vcpu->mmio_needed) { - report_emulation_failure(&emulate_ctxt); + kvm_report_emulation_failure(vcpu, "mmio"); return EMULATE_FAIL; } return EMULATE_DO_MMIO; } - kvm_arch_ops->decache_regs(vcpu); - kvm_arch_ops->set_rflags(vcpu, emulate_ctxt.eflags); + kvm_x86_ops->decache_regs(vcpu); + kvm_x86_ops->set_rflags(vcpu, emulate_ctxt.eflags); if (vcpu->mmio_is_write) { vcpu->mmio_needed = 0; @@ -1290,14 +1341,45 @@ int emulate_instruction(struct kvm_vcpu *vcpu, } EXPORT_SYMBOL_GPL(emulate_instruction); -int kvm_emulate_halt(struct kvm_vcpu *vcpu) +/* + * The vCPU has executed a HLT instruction with in-kernel mode enabled. + */ +static void kvm_vcpu_block(struct kvm_vcpu *vcpu) { - if (vcpu->irq_summary) - return 1; + DECLARE_WAITQUEUE(wait, current); - vcpu->run->exit_reason = KVM_EXIT_HLT; + add_wait_queue(&vcpu->wq, &wait); + + /* + * We will block until either an interrupt or a signal wakes us up + */ + while (!kvm_cpu_has_interrupt(vcpu) + && !signal_pending(current) + && vcpu->mp_state != VCPU_MP_STATE_RUNNABLE + && vcpu->mp_state != VCPU_MP_STATE_SIPI_RECEIVED) { + set_current_state(TASK_INTERRUPTIBLE); + vcpu_put(vcpu); + schedule(); + vcpu_load(vcpu); + } + + __set_current_state(TASK_RUNNING); + remove_wait_queue(&vcpu->wq, &wait); +} + +int kvm_emulate_halt(struct kvm_vcpu *vcpu) +{ ++vcpu->stat.halt_exits; - return 0; + if (irqchip_in_kernel(vcpu->kvm)) { + vcpu->mp_state = VCPU_MP_STATE_HALTED; + kvm_vcpu_block(vcpu); + if (vcpu->mp_state != VCPU_MP_STATE_RUNNABLE) + return -EINTR; + return 1; + } else { + vcpu->run->exit_reason = KVM_EXIT_HLT; + return 0; + } } EXPORT_SYMBOL_GPL(kvm_emulate_halt); @@ -1305,7 +1387,7 @@ int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run) { unsigned long nr, a0, a1, a2, a3, a4, a5, ret; - kvm_arch_ops->cache_regs(vcpu); + kvm_x86_ops->cache_regs(vcpu); ret = -KVM_EINVAL; #ifdef CONFIG_X86_64 if (is_long_mode(vcpu)) { @@ -1329,6 +1411,7 @@ int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run) } switch (nr) { default: + run->hypercall.nr = nr; run->hypercall.args[0] = a0; run->hypercall.args[1] = a1; run->hypercall.args[2] = a2; @@ -1337,11 +1420,11 @@ int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run) run->hypercall.args[5] = a5; run->hypercall.ret = ret; run->hypercall.longmode = is_long_mode(vcpu); - kvm_arch_ops->decache_regs(vcpu); + kvm_x86_ops->decache_regs(vcpu); return 0; } vcpu->regs[VCPU_REGS_RAX] = ret; - kvm_arch_ops->decache_regs(vcpu); + kvm_x86_ops->decache_regs(vcpu); return 1; } EXPORT_SYMBOL_GPL(kvm_hypercall); @@ -1355,26 +1438,26 @@ void realmode_lgdt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base) { struct descriptor_table dt = { limit, base }; - kvm_arch_ops->set_gdt(vcpu, &dt); + kvm_x86_ops->set_gdt(vcpu, &dt); } void realmode_lidt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base) { struct descriptor_table dt = { limit, base }; - kvm_arch_ops->set_idt(vcpu, &dt); + kvm_x86_ops->set_idt(vcpu, &dt); } void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw, unsigned long *rflags) { lmsw(vcpu, msw); - *rflags = kvm_arch_ops->get_rflags(vcpu); + *rflags = kvm_x86_ops->get_rflags(vcpu); } unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr) { - kvm_arch_ops->decache_cr4_guest_bits(vcpu); + kvm_x86_ops->decache_cr4_guest_bits(vcpu); switch (cr) { case 0: return vcpu->cr0; @@ -1396,7 +1479,7 @@ void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val, switch (cr) { case 0: set_cr0(vcpu, mk_cr_64(vcpu->cr0, val)); - *rflags = kvm_arch_ops->get_rflags(vcpu); + *rflags = kvm_x86_ops->get_rflags(vcpu); break; case 2: vcpu->cr2 = val; @@ -1439,7 +1522,7 @@ static int vcpu_register_para(struct kvm_vcpu *vcpu, gpa_t para_state_gpa) 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); + para_state = kmap(para_state_page); printk(KERN_DEBUG ".... guest version: %d\n", para_state->guest_version); printk(KERN_DEBUG ".... size: %d\n", para_state->size); @@ -1470,12 +1553,12 @@ static int vcpu_register_para(struct kvm_vcpu *vcpu, gpa_t para_state_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); + kvm_x86_ops->patch_hypercall(vcpu, hypercall); kunmap_atomic(hypercall, KM_USER1); para_state->ret = 0; err_kunmap_skip: - kunmap_atomic(para_state, KM_USER0); + kunmap(para_state_page); return 0; err_gp: return 1; @@ -1511,7 +1594,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) data = 3; break; case MSR_IA32_APICBASE: - data = vcpu->apic_base; + data = kvm_get_apic_base(vcpu); break; case MSR_IA32_MISC_ENABLE: data = vcpu->ia32_misc_enable_msr; @@ -1522,7 +1605,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) break; #endif default: - printk(KERN_ERR "kvm: unhandled rdmsr: 0x%x\n", msr); + pr_unimpl(vcpu, "unhandled rdmsr: 0x%x\n", msr); return 1; } *pdata = data; @@ -1537,7 +1620,7 @@ EXPORT_SYMBOL_GPL(kvm_get_msr_common); */ int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) { - return kvm_arch_ops->get_msr(vcpu, msr_index, pdata); + return kvm_x86_ops->get_msr(vcpu, msr_index, pdata); } #ifdef CONFIG_X86_64 @@ -1558,7 +1641,7 @@ static void set_efer(struct kvm_vcpu *vcpu, u64 efer) return; } - kvm_arch_ops->set_efer(vcpu, efer); + kvm_x86_ops->set_efer(vcpu, efer); efer &= ~EFER_LMA; efer |= vcpu->shadow_efer & EFER_LMA; @@ -1577,11 +1660,11 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) break; #endif case MSR_IA32_MC0_STATUS: - printk(KERN_WARNING "%s: MSR_IA32_MC0_STATUS 0x%llx, nop\n", + pr_unimpl(vcpu, "%s: MSR_IA32_MC0_STATUS 0x%llx, nop\n", __FUNCTION__, data); break; case MSR_IA32_MCG_STATUS: - printk(KERN_WARNING "%s: MSR_IA32_MCG_STATUS 0x%llx, nop\n", + pr_unimpl(vcpu, "%s: MSR_IA32_MCG_STATUS 0x%llx, nop\n", __FUNCTION__, data); break; case MSR_IA32_UCODE_REV: @@ -1589,7 +1672,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) case 0x200 ... 0x2ff: /* MTRRs */ break; case MSR_IA32_APICBASE: - vcpu->apic_base = data; + kvm_set_apic_base(vcpu, data); break; case MSR_IA32_MISC_ENABLE: vcpu->ia32_misc_enable_msr = data; @@ -1601,7 +1684,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) return vcpu_register_para(vcpu, data); default: - printk(KERN_ERR "kvm: unhandled wrmsr: 0x%x\n", msr); + pr_unimpl(vcpu, "unhandled wrmsr: 0x%x\n", msr); return 1; } return 0; @@ -1615,44 +1698,24 @@ EXPORT_SYMBOL_GPL(kvm_set_msr_common); */ int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data) { - return kvm_arch_ops->set_msr(vcpu, msr_index, data); + return kvm_x86_ops->set_msr(vcpu, msr_index, data); } void kvm_resched(struct kvm_vcpu *vcpu) { if (!need_resched()) return; - vcpu_put(vcpu); cond_resched(); - vcpu_load(vcpu); } EXPORT_SYMBOL_GPL(kvm_resched); -void load_msrs(struct vmx_msr_entry *e, int n) -{ - int i; - - for (i = 0; i < n; ++i) - wrmsrl(e[i].index, e[i].data); -} -EXPORT_SYMBOL_GPL(load_msrs); - -void save_msrs(struct vmx_msr_entry *e, int n) -{ - int i; - - for (i = 0; i < n; ++i) - rdmsrl(e[i].index, e[i].data); -} -EXPORT_SYMBOL_GPL(save_msrs); - void kvm_emulate_cpuid(struct kvm_vcpu *vcpu) { int i; u32 function; struct kvm_cpuid_entry *e, *best; - kvm_arch_ops->cache_regs(vcpu); + kvm_x86_ops->cache_regs(vcpu); function = vcpu->regs[VCPU_REGS_RAX]; vcpu->regs[VCPU_REGS_RAX] = 0; vcpu->regs[VCPU_REGS_RBX] = 0; @@ -1678,8 +1741,8 @@ void kvm_emulate_cpuid(struct kvm_vcpu *vcpu) vcpu->regs[VCPU_REGS_RCX] = best->ecx; vcpu->regs[VCPU_REGS_RDX] = best->edx; } - kvm_arch_ops->decache_regs(vcpu); - kvm_arch_ops->skip_emulated_instruction(vcpu); + kvm_x86_ops->decache_regs(vcpu); + kvm_x86_ops->skip_emulated_instruction(vcpu); } EXPORT_SYMBOL_GPL(kvm_emulate_cpuid); @@ -1690,11 +1753,9 @@ static int pio_copy_data(struct kvm_vcpu *vcpu) unsigned bytes; int nr_pages = vcpu->pio.guest_pages[1] ? 2 : 1; - kvm_arch_ops->vcpu_put(vcpu); q = vmap(vcpu->pio.guest_pages, nr_pages, VM_READ|VM_WRITE, PAGE_KERNEL); if (!q) { - kvm_arch_ops->vcpu_load(vcpu); free_pio_guest_pages(vcpu); return -ENOMEM; } @@ -1706,7 +1767,6 @@ static int pio_copy_data(struct kvm_vcpu *vcpu) memcpy(p, q, bytes); q -= vcpu->pio.guest_page_offset; vunmap(q); - kvm_arch_ops->vcpu_load(vcpu); free_pio_guest_pages(vcpu); return 0; } @@ -1717,7 +1777,7 @@ static int complete_pio(struct kvm_vcpu *vcpu) long delta; int r; - kvm_arch_ops->cache_regs(vcpu); + kvm_x86_ops->cache_regs(vcpu); if (!io->string) { if (io->in) @@ -1727,7 +1787,7 @@ static int complete_pio(struct kvm_vcpu *vcpu) if (io->in) { r = pio_copy_data(vcpu); if (r) { - kvm_arch_ops->cache_regs(vcpu); + kvm_x86_ops->cache_regs(vcpu); return r; } } @@ -1750,79 +1810,109 @@ static int complete_pio(struct kvm_vcpu *vcpu) vcpu->regs[VCPU_REGS_RSI] += delta; } - kvm_arch_ops->decache_regs(vcpu); + kvm_x86_ops->decache_regs(vcpu); io->count -= io->cur_count; io->cur_count = 0; - if (!io->count) - kvm_arch_ops->skip_emulated_instruction(vcpu); return 0; } -void kernel_pio(struct kvm_io_device *pio_dev, struct kvm_vcpu *vcpu) +static void kernel_pio(struct kvm_io_device *pio_dev, + struct kvm_vcpu *vcpu, + void *pd) { /* TODO: String I/O for in kernel device */ + mutex_lock(&vcpu->kvm->lock); if (vcpu->pio.in) kvm_iodevice_read(pio_dev, vcpu->pio.port, vcpu->pio.size, - vcpu->pio_data); + pd); else kvm_iodevice_write(pio_dev, vcpu->pio.port, vcpu->pio.size, - vcpu->pio_data); + pd); + mutex_unlock(&vcpu->kvm->lock); +} + +static void pio_string_write(struct kvm_io_device *pio_dev, + struct kvm_vcpu *vcpu) +{ + struct kvm_pio_request *io = &vcpu->pio; + void *pd = vcpu->pio_data; + int i; + + mutex_lock(&vcpu->kvm->lock); + for (i = 0; i < io->cur_count; i++) { + kvm_iodevice_write(pio_dev, io->port, + io->size, + pd); + pd += io->size; + } + mutex_unlock(&vcpu->kvm->lock); } -int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, - int size, unsigned long count, int string, int down, +int kvm_emulate_pio (struct kvm_vcpu *vcpu, struct kvm_run *run, int in, + int size, unsigned port) +{ + struct kvm_io_device *pio_dev; + + vcpu->run->exit_reason = KVM_EXIT_IO; + vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT; + vcpu->run->io.size = vcpu->pio.size = size; + vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE; + vcpu->run->io.count = vcpu->pio.count = vcpu->pio.cur_count = 1; + vcpu->run->io.port = vcpu->pio.port = port; + vcpu->pio.in = in; + vcpu->pio.string = 0; + vcpu->pio.down = 0; + vcpu->pio.guest_page_offset = 0; + vcpu->pio.rep = 0; + + kvm_x86_ops->cache_regs(vcpu); + memcpy(vcpu->pio_data, &vcpu->regs[VCPU_REGS_RAX], 4); + kvm_x86_ops->decache_regs(vcpu); + + kvm_x86_ops->skip_emulated_instruction(vcpu); + + pio_dev = vcpu_find_pio_dev(vcpu, port); + if (pio_dev) { + kernel_pio(pio_dev, vcpu, vcpu->pio_data); + complete_pio(vcpu); + return 1; + } + return 0; +} +EXPORT_SYMBOL_GPL(kvm_emulate_pio); + +int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, + int size, unsigned long count, int down, gva_t address, int rep, unsigned port) { unsigned now, in_page; - int i; + int i, ret = 0; int nr_pages = 1; struct page *page; struct kvm_io_device *pio_dev; vcpu->run->exit_reason = KVM_EXIT_IO; vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT; - vcpu->run->io.size = size; + vcpu->run->io.size = vcpu->pio.size = size; vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE; - vcpu->run->io.count = count; - vcpu->run->io.port = port; - vcpu->pio.count = count; - vcpu->pio.cur_count = count; - vcpu->pio.size = size; + vcpu->run->io.count = vcpu->pio.count = vcpu->pio.cur_count = count; + vcpu->run->io.port = vcpu->pio.port = port; vcpu->pio.in = in; - vcpu->pio.port = port; - vcpu->pio.string = string; + vcpu->pio.string = 1; vcpu->pio.down = down; vcpu->pio.guest_page_offset = offset_in_page(address); vcpu->pio.rep = rep; - pio_dev = vcpu_find_pio_dev(vcpu, port); - if (!string) { - kvm_arch_ops->cache_regs(vcpu); - memcpy(vcpu->pio_data, &vcpu->regs[VCPU_REGS_RAX], 4); - kvm_arch_ops->decache_regs(vcpu); - if (pio_dev) { - kernel_pio(pio_dev, vcpu); - complete_pio(vcpu); - return 1; - } - return 0; - } - /* TODO: String I/O for in kernel device */ - if (pio_dev) - printk(KERN_ERR "kvm_setup_pio: no string io support\n"); - if (!count) { - kvm_arch_ops->skip_emulated_instruction(vcpu); + kvm_x86_ops->skip_emulated_instruction(vcpu); return 1; } - now = min(count, PAGE_SIZE / size); - if (!down) in_page = PAGE_SIZE - offset_in_page(address); else @@ -1841,20 +1931,23 @@ int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, /* * String I/O in reverse. Yuck. Kill the guest, fix later. */ - printk(KERN_ERR "kvm: guest string pio down\n"); + pr_unimpl(vcpu, "guest string pio down\n"); inject_gp(vcpu); return 1; } vcpu->run->io.count = now; vcpu->pio.cur_count = now; + if (vcpu->pio.cur_count == vcpu->pio.count) + kvm_x86_ops->skip_emulated_instruction(vcpu); + for (i = 0; i < nr_pages; ++i) { - spin_lock(&vcpu->kvm->lock); + mutex_lock(&vcpu->kvm->lock); page = gva_to_page(vcpu, address + i * PAGE_SIZE); if (page) get_page(page); vcpu->pio.guest_pages[i] = page; - spin_unlock(&vcpu->kvm->lock); + mutex_unlock(&vcpu->kvm->lock); if (!page) { inject_gp(vcpu); free_pio_guest_pages(vcpu); @@ -1862,11 +1955,147 @@ int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, } } - if (!vcpu->pio.in) - return pio_copy_data(vcpu); - return 0; + pio_dev = vcpu_find_pio_dev(vcpu, port); + if (!vcpu->pio.in) { + /* string PIO write */ + ret = pio_copy_data(vcpu); + if (ret >= 0 && pio_dev) { + pio_string_write(pio_dev, vcpu); + complete_pio(vcpu); + if (vcpu->pio.count == 0) + ret = 1; + } + } else if (pio_dev) + pr_unimpl(vcpu, "no string pio read support yet, " + "port %x size %d count %ld\n", + port, size, count); + + return ret; +} +EXPORT_SYMBOL_GPL(kvm_emulate_pio_string); + +/* + * Check if userspace requested an interrupt window, and that the + * interrupt window is open. + * + * No need to exit to userspace if we already have an interrupt queued. + */ +static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu, + struct kvm_run *kvm_run) +{ + return (!vcpu->irq_summary && + kvm_run->request_interrupt_window && + vcpu->interrupt_window_open && + (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF)); +} + +static void post_kvm_run_save(struct kvm_vcpu *vcpu, + struct kvm_run *kvm_run) +{ + kvm_run->if_flag = (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF) != 0; + kvm_run->cr8 = get_cr8(vcpu); + kvm_run->apic_base = kvm_get_apic_base(vcpu); + if (irqchip_in_kernel(vcpu->kvm)) + kvm_run->ready_for_interrupt_injection = 1; + else + kvm_run->ready_for_interrupt_injection = + (vcpu->interrupt_window_open && + vcpu->irq_summary == 0); +} + +static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + int r; + + if (unlikely(vcpu->mp_state == VCPU_MP_STATE_SIPI_RECEIVED)) { + printk("vcpu %d received sipi with vector # %x\n", + vcpu->vcpu_id, vcpu->sipi_vector); + kvm_lapic_reset(vcpu); + kvm_x86_ops->vcpu_reset(vcpu); + vcpu->mp_state = VCPU_MP_STATE_RUNNABLE; + } + +preempted: + if (vcpu->guest_debug.enabled) + kvm_x86_ops->guest_debug_pre(vcpu); + +again: + r = kvm_mmu_reload(vcpu); + if (unlikely(r)) + goto out; + + preempt_disable(); + + kvm_x86_ops->prepare_guest_switch(vcpu); + kvm_load_guest_fpu(vcpu); + + local_irq_disable(); + + if (signal_pending(current)) { + local_irq_enable(); + preempt_enable(); + r = -EINTR; + kvm_run->exit_reason = KVM_EXIT_INTR; + ++vcpu->stat.signal_exits; + goto out; + } + + if (irqchip_in_kernel(vcpu->kvm)) + kvm_x86_ops->inject_pending_irq(vcpu); + else if (!vcpu->mmio_read_completed) + kvm_x86_ops->inject_pending_vectors(vcpu, kvm_run); + + vcpu->guest_mode = 1; + kvm_guest_enter(); + + if (vcpu->requests) + if (test_and_clear_bit(KVM_TLB_FLUSH, &vcpu->requests)) + kvm_x86_ops->tlb_flush(vcpu); + + kvm_x86_ops->run(vcpu, kvm_run); + + kvm_guest_exit(); + vcpu->guest_mode = 0; + local_irq_enable(); + + ++vcpu->stat.exits; + + preempt_enable(); + + /* + * Profile KVM exit RIPs: + */ + if (unlikely(prof_on == KVM_PROFILING)) { + kvm_x86_ops->cache_regs(vcpu); + profile_hit(KVM_PROFILING, (void *)vcpu->rip); + } + + r = kvm_x86_ops->handle_exit(kvm_run, vcpu); + + if (r > 0) { + if (dm_request_for_irq_injection(vcpu, kvm_run)) { + r = -EINTR; + kvm_run->exit_reason = KVM_EXIT_INTR; + ++vcpu->stat.request_irq_exits; + goto out; + } + if (!need_resched()) { + ++vcpu->stat.light_exits; + goto again; + } + } + +out: + if (r > 0) { + kvm_resched(vcpu); + goto preempted; + } + + post_kvm_run_save(vcpu, kvm_run); + + return r; } -EXPORT_SYMBOL_GPL(kvm_setup_pio); + static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { @@ -1875,11 +2104,18 @@ static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) vcpu_load(vcpu); + if (unlikely(vcpu->mp_state == VCPU_MP_STATE_UNINITIALIZED)) { + kvm_vcpu_block(vcpu); + vcpu_put(vcpu); + return -EAGAIN; + } + if (vcpu->sigset_active) sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved); /* re-sync apic's tpr */ - vcpu->cr8 = kvm_run->cr8; + if (!irqchip_in_kernel(vcpu->kvm)) + set_cr8(vcpu, kvm_run->cr8); if (vcpu->pio.cur_count) { r = complete_pio(vcpu); @@ -1897,19 +2133,18 @@ static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) /* * Read-modify-write. Back to userspace. */ - kvm_run->exit_reason = KVM_EXIT_MMIO; r = 0; goto out; } } if (kvm_run->exit_reason == KVM_EXIT_HYPERCALL) { - kvm_arch_ops->cache_regs(vcpu); + kvm_x86_ops->cache_regs(vcpu); vcpu->regs[VCPU_REGS_RAX] = kvm_run->hypercall.ret; - kvm_arch_ops->decache_regs(vcpu); + kvm_x86_ops->decache_regs(vcpu); } - r = kvm_arch_ops->run(vcpu, kvm_run); + r = __vcpu_run(vcpu, kvm_run); out: if (vcpu->sigset_active) @@ -1924,7 +2159,7 @@ static int kvm_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, { vcpu_load(vcpu); - kvm_arch_ops->cache_regs(vcpu); + kvm_x86_ops->cache_regs(vcpu); regs->rax = vcpu->regs[VCPU_REGS_RAX]; regs->rbx = vcpu->regs[VCPU_REGS_RBX]; @@ -1946,7 +2181,7 @@ static int kvm_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, #endif regs->rip = vcpu->rip; - regs->rflags = kvm_arch_ops->get_rflags(vcpu); + regs->rflags = kvm_x86_ops->get_rflags(vcpu); /* * Don't leak debug flags in case they were set for guest debugging @@ -1984,9 +2219,9 @@ static int kvm_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, #endif vcpu->rip = regs->rip; - kvm_arch_ops->set_rflags(vcpu, regs->rflags); + kvm_x86_ops->set_rflags(vcpu, regs->rflags); - kvm_arch_ops->decache_regs(vcpu); + kvm_x86_ops->decache_regs(vcpu); vcpu_put(vcpu); @@ -1996,13 +2231,14 @@ static int kvm_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, static void get_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg) { - return kvm_arch_ops->get_segment(vcpu, var, seg); + return kvm_x86_ops->get_segment(vcpu, var, seg); } static int kvm_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) { struct descriptor_table dt; + int pending_vec; vcpu_load(vcpu); @@ -2016,24 +2252,31 @@ static int kvm_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, get_segment(vcpu, &sregs->tr, VCPU_SREG_TR); get_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR); - kvm_arch_ops->get_idt(vcpu, &dt); + kvm_x86_ops->get_idt(vcpu, &dt); sregs->idt.limit = dt.limit; sregs->idt.base = dt.base; - kvm_arch_ops->get_gdt(vcpu, &dt); + kvm_x86_ops->get_gdt(vcpu, &dt); sregs->gdt.limit = dt.limit; sregs->gdt.base = dt.base; - kvm_arch_ops->decache_cr4_guest_bits(vcpu); + kvm_x86_ops->decache_cr4_guest_bits(vcpu); sregs->cr0 = vcpu->cr0; sregs->cr2 = vcpu->cr2; sregs->cr3 = vcpu->cr3; sregs->cr4 = vcpu->cr4; - sregs->cr8 = vcpu->cr8; + sregs->cr8 = get_cr8(vcpu); sregs->efer = vcpu->shadow_efer; - sregs->apic_base = vcpu->apic_base; - - memcpy(sregs->interrupt_bitmap, vcpu->irq_pending, - sizeof sregs->interrupt_bitmap); + sregs->apic_base = kvm_get_apic_base(vcpu); + + if (irqchip_in_kernel(vcpu->kvm)) { + memset(sregs->interrupt_bitmap, 0, + sizeof sregs->interrupt_bitmap); + pending_vec = kvm_x86_ops->get_irq(vcpu); + if (pending_vec >= 0) + set_bit(pending_vec, (unsigned long *)sregs->interrupt_bitmap); + } else + memcpy(sregs->interrupt_bitmap, vcpu->irq_pending, + sizeof sregs->interrupt_bitmap); vcpu_put(vcpu); @@ -2043,56 +2286,69 @@ static int kvm_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, static void set_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg) { - return kvm_arch_ops->set_segment(vcpu, var, seg); + return kvm_x86_ops->set_segment(vcpu, var, seg); } static int kvm_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) { int mmu_reset_needed = 0; - int i; + int i, pending_vec, max_bits; struct descriptor_table dt; vcpu_load(vcpu); dt.limit = sregs->idt.limit; dt.base = sregs->idt.base; - kvm_arch_ops->set_idt(vcpu, &dt); + kvm_x86_ops->set_idt(vcpu, &dt); dt.limit = sregs->gdt.limit; dt.base = sregs->gdt.base; - kvm_arch_ops->set_gdt(vcpu, &dt); + kvm_x86_ops->set_gdt(vcpu, &dt); vcpu->cr2 = sregs->cr2; mmu_reset_needed |= vcpu->cr3 != sregs->cr3; vcpu->cr3 = sregs->cr3; - vcpu->cr8 = sregs->cr8; + set_cr8(vcpu, sregs->cr8); mmu_reset_needed |= vcpu->shadow_efer != sregs->efer; #ifdef CONFIG_X86_64 - kvm_arch_ops->set_efer(vcpu, sregs->efer); + kvm_x86_ops->set_efer(vcpu, sregs->efer); #endif - vcpu->apic_base = sregs->apic_base; + kvm_set_apic_base(vcpu, sregs->apic_base); - kvm_arch_ops->decache_cr4_guest_bits(vcpu); + kvm_x86_ops->decache_cr4_guest_bits(vcpu); mmu_reset_needed |= vcpu->cr0 != sregs->cr0; - kvm_arch_ops->set_cr0(vcpu, sregs->cr0); + vcpu->cr0 = sregs->cr0; + kvm_x86_ops->set_cr0(vcpu, sregs->cr0); mmu_reset_needed |= vcpu->cr4 != sregs->cr4; - kvm_arch_ops->set_cr4(vcpu, sregs->cr4); + kvm_x86_ops->set_cr4(vcpu, sregs->cr4); if (!is_long_mode(vcpu) && is_pae(vcpu)) load_pdptrs(vcpu, vcpu->cr3); if (mmu_reset_needed) kvm_mmu_reset_context(vcpu); - memcpy(vcpu->irq_pending, sregs->interrupt_bitmap, - sizeof vcpu->irq_pending); - vcpu->irq_summary = 0; - for (i = 0; i < NR_IRQ_WORDS; ++i) - if (vcpu->irq_pending[i]) - __set_bit(i, &vcpu->irq_summary); + if (!irqchip_in_kernel(vcpu->kvm)) { + memcpy(vcpu->irq_pending, sregs->interrupt_bitmap, + sizeof vcpu->irq_pending); + vcpu->irq_summary = 0; + for (i = 0; i < ARRAY_SIZE(vcpu->irq_pending); ++i) + if (vcpu->irq_pending[i]) + __set_bit(i, &vcpu->irq_summary); + } else { + max_bits = (sizeof sregs->interrupt_bitmap) << 3; + pending_vec = find_first_bit( + (const unsigned long *)sregs->interrupt_bitmap, + max_bits); + /* Only pending external irq is handled here */ + if (pending_vec < max_bits) { + kvm_x86_ops->set_irq(vcpu, pending_vec); + printk("Set back pending irq %d\n", pending_vec); + } + } set_segment(vcpu, &sregs->cs, VCPU_SREG_CS); set_segment(vcpu, &sregs->ds, VCPU_SREG_DS); @@ -2109,6 +2365,16 @@ static int kvm_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, return 0; } +void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l) +{ + struct kvm_segment cs; + + get_segment(vcpu, &cs, VCPU_SREG_CS); + *db = cs.db; + *l = cs.l; +} +EXPORT_SYMBOL_GPL(kvm_get_cs_db_l_bits); + /* * List of msr numbers which we expose to userspace through KVM_GET_MSRS * and KVM_SET_MSRS, and KVM_GET_MSR_INDEX_LIST. @@ -2236,13 +2502,13 @@ static int kvm_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, gpa_t gpa; vcpu_load(vcpu); - spin_lock(&vcpu->kvm->lock); + mutex_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(&vcpu->kvm->lock); + mutex_unlock(&vcpu->kvm->lock); vcpu_put(vcpu); return 0; @@ -2253,6 +2519,8 @@ static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, { if (irq->irq < 0 || irq->irq >= 256) return -EINVAL; + if (irqchip_in_kernel(vcpu->kvm)) + return -ENXIO; vcpu_load(vcpu); set_bit(irq->irq, vcpu->irq_pending); @@ -2270,7 +2538,7 @@ static int kvm_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu, vcpu_load(vcpu); - r = kvm_arch_ops->set_guest_debug(vcpu, dbg); + r = kvm_x86_ops->set_guest_debug(vcpu, dbg); vcpu_put(vcpu); @@ -2285,7 +2553,6 @@ static struct page *kvm_vcpu_nopage(struct vm_area_struct *vma, unsigned long pgoff; struct page *page; - *type = VM_FAULT_MINOR; pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; if (pgoff == 0) page = virt_to_page(vcpu->run); @@ -2294,6 +2561,9 @@ static struct page *kvm_vcpu_nopage(struct vm_area_struct *vma, else return NOPAGE_SIGBUS; get_page(page); + if (type != NULL) + *type = VM_FAULT_MINOR; + return page; } @@ -2346,74 +2616,52 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n) { int r; struct kvm_vcpu *vcpu; - struct page *page; - 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; - } - - page = alloc_page(GFP_KERNEL | __GFP_ZERO); - r = -ENOMEM; - if (!page) - goto out_unlock; - vcpu->run = page_address(page); - - page = alloc_page(GFP_KERNEL | __GFP_ZERO); - r = -ENOMEM; - if (!page) - goto out_free_run; - vcpu->pio_data = page_address(page); + return -EINVAL; - 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; - vcpu->cr0 = 0x10; + vcpu = kvm_x86_ops->vcpu_create(kvm, n); + if (IS_ERR(vcpu)) + return PTR_ERR(vcpu); - r = kvm_arch_ops->vcpu_create(vcpu); - if (r < 0) - goto out_free_vcpus; + preempt_notifier_init(&vcpu->preempt_notifier, &kvm_preempt_ops); - r = kvm_mmu_create(vcpu); - if (r < 0) - goto out_free_vcpus; + /* We do fxsave: this must be aligned. */ + BUG_ON((unsigned long)&vcpu->host_fx_image & 0xF); - kvm_arch_ops->vcpu_load(vcpu); + 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; + goto free_vcpu; + mutex_lock(&kvm->lock); + if (kvm->vcpus[n]) { + r = -EEXIST; + mutex_unlock(&kvm->lock); + goto mmu_unload; + } + kvm->vcpus[n] = vcpu; + mutex_unlock(&kvm->lock); + + /* Now it's all set up, let userspace reach it */ r = create_vcpu_fd(vcpu); if (r < 0) - goto out_free_vcpus; + goto unlink; + return r; - spin_lock(&kvm_lock); - if (n >= kvm->nvcpus) - kvm->nvcpus = n + 1; - spin_unlock(&kvm_lock); +unlink: + mutex_lock(&kvm->lock); + kvm->vcpus[n] = NULL; + mutex_unlock(&kvm->lock); - return r; +mmu_unload: + vcpu_load(vcpu); + kvm_mmu_unload(vcpu); + vcpu_put(vcpu); -out_free_vcpus: - kvm_free_vcpu(vcpu); -out_free_run: - free_page((unsigned long)vcpu->run); - vcpu->run = NULL; -out_unlock: - mutex_unlock(&vcpu->mutex); -out: +free_vcpu: + kvm_x86_ops->vcpu_free(vcpu); return r; } @@ -2493,7 +2741,7 @@ struct fxsave { static int kvm_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) { - struct fxsave *fxsave = (struct fxsave *)vcpu->guest_fx_image; + struct fxsave *fxsave = (struct fxsave *)&vcpu->guest_fx_image; vcpu_load(vcpu); @@ -2513,7 +2761,7 @@ static int kvm_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) static int kvm_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) { - struct fxsave *fxsave = (struct fxsave *)vcpu->guest_fx_image; + struct fxsave *fxsave = (struct fxsave *)&vcpu->guest_fx_image; vcpu_load(vcpu); @@ -2531,6 +2779,27 @@ static int kvm_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) return 0; } +static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu, + struct kvm_lapic_state *s) +{ + vcpu_load(vcpu); + memcpy(s->regs, vcpu->apic->regs, sizeof *s); + vcpu_put(vcpu); + + return 0; +} + +static int kvm_vcpu_ioctl_set_lapic(struct kvm_vcpu *vcpu, + struct kvm_lapic_state *s) +{ + vcpu_load(vcpu); + memcpy(vcpu->apic->regs, s->regs, sizeof *s); + kvm_apic_post_state_restore(vcpu); + vcpu_put(vcpu); + + return 0; +} + static long kvm_vcpu_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { @@ -2700,6 +2969,31 @@ static long kvm_vcpu_ioctl(struct file *filp, r = 0; break; } + case KVM_GET_LAPIC: { + struct kvm_lapic_state lapic; + + memset(&lapic, 0, sizeof lapic); + r = kvm_vcpu_ioctl_get_lapic(vcpu, &lapic); + if (r) + goto out; + r = -EFAULT; + if (copy_to_user(argp, &lapic, sizeof lapic)) + goto out; + r = 0; + break; + } + case KVM_SET_LAPIC: { + struct kvm_lapic_state lapic; + + r = -EFAULT; + if (copy_from_user(&lapic, argp, sizeof lapic)) + goto out; + r = kvm_vcpu_ioctl_set_lapic(vcpu, &lapic);; + if (r) + goto out; + r = 0; + break; + } default: ; } @@ -2753,6 +3047,75 @@ static long kvm_vm_ioctl(struct file *filp, goto out; break; } + case KVM_CREATE_IRQCHIP: + r = -ENOMEM; + kvm->vpic = kvm_create_pic(kvm); + if (kvm->vpic) { + r = kvm_ioapic_init(kvm); + if (r) { + kfree(kvm->vpic); + kvm->vpic = NULL; + goto out; + } + } + else + goto out; + break; + case KVM_IRQ_LINE: { + struct kvm_irq_level irq_event; + + r = -EFAULT; + if (copy_from_user(&irq_event, argp, sizeof irq_event)) + goto out; + if (irqchip_in_kernel(kvm)) { + mutex_lock(&kvm->lock); + if (irq_event.irq < 16) + kvm_pic_set_irq(pic_irqchip(kvm), + irq_event.irq, + irq_event.level); + kvm_ioapic_set_irq(kvm->vioapic, + irq_event.irq, + irq_event.level); + mutex_unlock(&kvm->lock); + r = 0; + } + break; + } + case KVM_GET_IRQCHIP: { + /* 0: PIC master, 1: PIC slave, 2: IOAPIC */ + struct kvm_irqchip chip; + + r = -EFAULT; + if (copy_from_user(&chip, argp, sizeof chip)) + goto out; + r = -ENXIO; + if (!irqchip_in_kernel(kvm)) + goto out; + r = kvm_vm_ioctl_get_irqchip(kvm, &chip); + if (r) + goto out; + r = -EFAULT; + if (copy_to_user(argp, &chip, sizeof chip)) + goto out; + r = 0; + break; + } + case KVM_SET_IRQCHIP: { + /* 0: PIC master, 1: PIC slave, 2: IOAPIC */ + struct kvm_irqchip chip; + + r = -EFAULT; + if (copy_from_user(&chip, argp, sizeof chip)) + goto out; + r = -ENXIO; + if (!irqchip_in_kernel(kvm)) + goto out; + r = kvm_vm_ioctl_set_irqchip(kvm, &chip); + if (r) + goto out; + r = 0; + break; + } default: ; } @@ -2768,12 +3131,14 @@ static struct page *kvm_vm_nopage(struct vm_area_struct *vma, unsigned long pgoff; struct page *page; - *type = VM_FAULT_MINOR; pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; page = gfn_to_page(kvm, pgoff); if (!page) return NOPAGE_SIGBUS; get_page(page); + if (type != NULL) + *type = VM_FAULT_MINOR; + return page; } @@ -2861,12 +3226,20 @@ static long kvm_dev_ioctl(struct file *filp, r = 0; break; } - case KVM_CHECK_EXTENSION: - /* - * No extensions defined at present. - */ - r = 0; + case KVM_CHECK_EXTENSION: { + int ext = (long)argp; + + switch (ext) { + case KVM_CAP_IRQCHIP: + case KVM_CAP_HLT: + r = 1; + break; + default: + r = 0; + break; + } break; + } case KVM_GET_VCPU_MMAP_SIZE: r = -EINVAL; if (arg) @@ -2881,8 +3254,6 @@ out: } 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, }; @@ -2893,25 +3264,6 @@ static struct miscdevice kvm_dev = { &kvm_chardev_ops, }; -static int kvm_reboot(struct notifier_block *notifier, unsigned long val, - void *v) -{ - if (val == SYS_RESTART) { - /* - * Some (well, at least mine) BIOSes hang on reboot if - * in vmx root mode. - */ - printk(KERN_INFO "kvm: exiting hardware virtualization\n"); - on_each_cpu(hardware_disable, NULL, 0, 1); - } - return NOTIFY_OK; -} - -static struct notifier_block kvm_reboot_notifier = { - .notifier_call = kvm_reboot, - .priority = 0, -}; - /* * Make sure that a cpu that is being hot-unplugged does not have any vcpus * cached on it. @@ -2925,7 +3277,9 @@ static void decache_vcpus_on_cpu(int cpu) spin_lock(&kvm_lock); list_for_each_entry(vm, &vm_list, vm_list) for (i = 0; i < KVM_MAX_VCPUS; ++i) { - vcpu = &vm->vcpus[i]; + vcpu = vm->vcpus[i]; + if (!vcpu) + continue; /* * If the vcpu is locked, then it is running on some * other cpu and therefore it is not cached on the @@ -2936,7 +3290,7 @@ static void decache_vcpus_on_cpu(int cpu) */ if (mutex_trylock(&vcpu->mutex)) { if (vcpu->cpu == cpu) { - kvm_arch_ops->vcpu_decache(vcpu); + kvm_x86_ops->vcpu_decache(vcpu); vcpu->cpu = -1; } mutex_unlock(&vcpu->mutex); @@ -2952,7 +3306,7 @@ static void hardware_enable(void *junk) if (cpu_isset(cpu, cpus_hardware_enabled)) return; cpu_set(cpu, cpus_hardware_enabled); - kvm_arch_ops->hardware_enable(NULL); + kvm_x86_ops->hardware_enable(NULL); } static void hardware_disable(void *junk) @@ -2963,7 +3317,7 @@ static void hardware_disable(void *junk) return; cpu_clear(cpu, cpus_hardware_enabled); decache_vcpus_on_cpu(cpu); - kvm_arch_ops->hardware_disable(NULL); + kvm_x86_ops->hardware_disable(NULL); } static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val, @@ -2994,6 +3348,25 @@ static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val, return NOTIFY_OK; } +static int kvm_reboot(struct notifier_block *notifier, unsigned long val, + void *v) +{ + if (val == SYS_RESTART) { + /* + * Some (well, at least mine) BIOSes hang on reboot if + * in vmx root mode. + */ + printk(KERN_INFO "kvm: exiting hardware virtualization\n"); + on_each_cpu(hardware_disable, NULL, 0, 1); + } + return NOTIFY_OK; +} + +static struct notifier_block kvm_reboot_notifier = { + .notifier_call = kvm_reboot, + .priority = 0, +}; + void kvm_io_bus_init(struct kvm_io_bus *bus) { memset(bus, 0, sizeof(*bus)); @@ -3047,18 +3420,15 @@ static u64 stat_get(void *_offset) spin_lock(&kvm_lock); list_for_each_entry(kvm, &vm_list, vm_list) for (i = 0; i < KVM_MAX_VCPUS; ++i) { - vcpu = &kvm->vcpus[i]; - total += *(u32 *)((void *)vcpu + offset); + vcpu = kvm->vcpus[i]; + if (vcpu) + total += *(u32 *)((void *)vcpu + offset); } spin_unlock(&kvm_lock); return total; } -static void stat_set(void *offset, u64 val) -{ -} - -DEFINE_SIMPLE_ATTRIBUTE(stat_fops, stat_get, stat_set, "%llu\n"); +DEFINE_SIMPLE_ATTRIBUTE(stat_fops, stat_get, NULL, "%llu\n"); static __init void kvm_init_debug(void) { @@ -3105,11 +3475,34 @@ static struct sys_device kvm_sysdev = { hpa_t bad_page_address; -int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module) +static inline +struct kvm_vcpu *preempt_notifier_to_vcpu(struct preempt_notifier *pn) +{ + return container_of(pn, struct kvm_vcpu, preempt_notifier); +} + +static void kvm_sched_in(struct preempt_notifier *pn, int cpu) +{ + struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn); + + kvm_x86_ops->vcpu_load(vcpu, cpu); +} + +static void kvm_sched_out(struct preempt_notifier *pn, + struct task_struct *next) +{ + struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn); + + kvm_x86_ops->vcpu_put(vcpu); +} + +int kvm_init_x86(struct kvm_x86_ops *ops, unsigned int vcpu_size, + struct module *module) { int r; + int cpu; - if (kvm_arch_ops) { + if (kvm_x86_ops) { printk(KERN_ERR "kvm: already loaded the other module\n"); return -EEXIST; } @@ -3123,12 +3516,20 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module) return -EOPNOTSUPP; } - kvm_arch_ops = ops; + kvm_x86_ops = ops; - r = kvm_arch_ops->hardware_setup(); + r = kvm_x86_ops->hardware_setup(); if (r < 0) goto out; + for_each_online_cpu(cpu) { + smp_call_function_single(cpu, + kvm_x86_ops->check_processor_compatibility, + &r, 0, 1); + if (r < 0) + goto out_free_0; + } + on_each_cpu(hardware_enable, NULL, 0, 1); r = register_cpu_notifier(&kvm_cpu_notifier); if (r) @@ -3143,6 +3544,14 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module) if (r) goto out_free_3; + /* A kmem cache lets us meet the alignment requirements of fx_save. */ + kvm_vcpu_cache = kmem_cache_create("kvm_vcpu", vcpu_size, + __alignof__(struct kvm_vcpu), 0, 0); + if (!kvm_vcpu_cache) { + r = -ENOMEM; + goto out_free_4; + } + kvm_chardev_ops.owner = module; r = misc_register(&kvm_dev); @@ -3151,9 +3560,14 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module) goto out_free; } + kvm_preempt_ops.sched_in = kvm_sched_in; + kvm_preempt_ops.sched_out = kvm_sched_out; + return r; out_free: + kmem_cache_destroy(kvm_vcpu_cache); +out_free_4: sysdev_unregister(&kvm_sysdev); out_free_3: sysdev_class_unregister(&kvm_sysdev_class); @@ -3162,22 +3576,24 @@ out_free_2: unregister_cpu_notifier(&kvm_cpu_notifier); out_free_1: on_each_cpu(hardware_disable, NULL, 0, 1); - kvm_arch_ops->hardware_unsetup(); +out_free_0: + kvm_x86_ops->hardware_unsetup(); out: - kvm_arch_ops = NULL; + kvm_x86_ops = NULL; return r; } -void kvm_exit_arch(void) +void kvm_exit_x86(void) { misc_deregister(&kvm_dev); + kmem_cache_destroy(kvm_vcpu_cache); sysdev_unregister(&kvm_sysdev); sysdev_class_unregister(&kvm_sysdev_class); unregister_reboot_notifier(&kvm_reboot_notifier); unregister_cpu_notifier(&kvm_cpu_notifier); on_each_cpu(hardware_disable, NULL, 0, 1); - kvm_arch_ops->hardware_unsetup(); - kvm_arch_ops = NULL; + kvm_x86_ops->hardware_unsetup(); + kvm_x86_ops = NULL; } static __init int kvm_init(void) @@ -3220,5 +3636,5 @@ static __exit void kvm_exit(void) module_init(kvm_init) module_exit(kvm_exit) -EXPORT_SYMBOL_GPL(kvm_init_arch); -EXPORT_SYMBOL_GPL(kvm_exit_arch); +EXPORT_SYMBOL_GPL(kvm_init_x86); +EXPORT_SYMBOL_GPL(kvm_exit_x86); diff --git a/drivers/kvm/kvm_svm.h b/drivers/kvm/kvm_svm.h index a869983d683d..a0e415daef5b 100644 --- a/drivers/kvm/kvm_svm.h +++ b/drivers/kvm/kvm_svm.h @@ -20,7 +20,10 @@ static const u32 host_save_user_msrs[] = { #define NR_HOST_SAVE_USER_MSRS ARRAY_SIZE(host_save_user_msrs) #define NUM_DB_REGS 4 +struct kvm_vcpu; + struct vcpu_svm { + struct kvm_vcpu vcpu; struct vmcb *vmcb; unsigned long vmcb_pa; struct svm_cpu_data *svm_data; diff --git a/drivers/kvm/lapic.c b/drivers/kvm/lapic.c new file mode 100644 index 000000000000..a190587cf6a5 --- /dev/null +++ b/drivers/kvm/lapic.c @@ -0,0 +1,1064 @@ + +/* + * Local APIC virtualization + * + * Copyright (C) 2006 Qumranet, Inc. + * Copyright (C) 2007 Novell + * Copyright (C) 2007 Intel + * + * Authors: + * Dor Laor <dor.laor@qumranet.com> + * Gregory Haskins <ghaskins@novell.com> + * Yaozu (Eddie) Dong <eddie.dong@intel.com> + * + * Based on Xen 3.1 code, Copyright (c) 2004, Intel Corporation. + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include "kvm.h" +#include <linux/kvm.h> +#include <linux/mm.h> +#include <linux/highmem.h> +#include <linux/smp.h> +#include <linux/hrtimer.h> +#include <linux/io.h> +#include <linux/module.h> +#include <asm/processor.h> +#include <asm/msr.h> +#include <asm/page.h> +#include <asm/current.h> +#include <asm/apicdef.h> +#include <asm/atomic.h> +#include <asm/div64.h> +#include "irq.h" + +#define PRId64 "d" +#define PRIx64 "llx" +#define PRIu64 "u" +#define PRIo64 "o" + +#define APIC_BUS_CYCLE_NS 1 + +/* #define apic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg) */ +#define apic_debug(fmt, arg...) + +#define APIC_LVT_NUM 6 +/* 14 is the version for Xeon and Pentium 8.4.8*/ +#define APIC_VERSION (0x14UL | ((APIC_LVT_NUM - 1) << 16)) +#define LAPIC_MMIO_LENGTH (1 << 12) +/* followed define is not in apicdef.h */ +#define APIC_SHORT_MASK 0xc0000 +#define APIC_DEST_NOSHORT 0x0 +#define APIC_DEST_MASK 0x800 +#define MAX_APIC_VECTOR 256 + +#define VEC_POS(v) ((v) & (32 - 1)) +#define REG_POS(v) (((v) >> 5) << 4) +static inline u32 apic_get_reg(struct kvm_lapic *apic, int reg_off) +{ + return *((u32 *) (apic->regs + reg_off)); +} + +static inline void apic_set_reg(struct kvm_lapic *apic, int reg_off, u32 val) +{ + *((u32 *) (apic->regs + reg_off)) = val; +} + +static inline int apic_test_and_set_vector(int vec, void *bitmap) +{ + return test_and_set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); +} + +static inline int apic_test_and_clear_vector(int vec, void *bitmap) +{ + return test_and_clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); +} + +static inline void apic_set_vector(int vec, void *bitmap) +{ + set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); +} + +static inline void apic_clear_vector(int vec, void *bitmap) +{ + clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); +} + +static inline int apic_hw_enabled(struct kvm_lapic *apic) +{ + return (apic)->vcpu->apic_base & MSR_IA32_APICBASE_ENABLE; +} + +static inline int apic_sw_enabled(struct kvm_lapic *apic) +{ + return apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_APIC_ENABLED; +} + +static inline int apic_enabled(struct kvm_lapic *apic) +{ + return apic_sw_enabled(apic) && apic_hw_enabled(apic); +} + +#define LVT_MASK \ + (APIC_LVT_MASKED | APIC_SEND_PENDING | APIC_VECTOR_MASK) + +#define LINT_MASK \ + (LVT_MASK | APIC_MODE_MASK | APIC_INPUT_POLARITY | \ + APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER) + +static inline int kvm_apic_id(struct kvm_lapic *apic) +{ + return (apic_get_reg(apic, APIC_ID) >> 24) & 0xff; +} + +static inline int apic_lvt_enabled(struct kvm_lapic *apic, int lvt_type) +{ + return !(apic_get_reg(apic, lvt_type) & APIC_LVT_MASKED); +} + +static inline int apic_lvt_vector(struct kvm_lapic *apic, int lvt_type) +{ + return apic_get_reg(apic, lvt_type) & APIC_VECTOR_MASK; +} + +static inline int apic_lvtt_period(struct kvm_lapic *apic) +{ + return apic_get_reg(apic, APIC_LVTT) & APIC_LVT_TIMER_PERIODIC; +} + +static unsigned int apic_lvt_mask[APIC_LVT_NUM] = { + LVT_MASK | APIC_LVT_TIMER_PERIODIC, /* LVTT */ + LVT_MASK | APIC_MODE_MASK, /* LVTTHMR */ + LVT_MASK | APIC_MODE_MASK, /* LVTPC */ + LINT_MASK, LINT_MASK, /* LVT0-1 */ + LVT_MASK /* LVTERR */ +}; + +static int find_highest_vector(void *bitmap) +{ + u32 *word = bitmap; + int word_offset = MAX_APIC_VECTOR >> 5; + + while ((word_offset != 0) && (word[(--word_offset) << 2] == 0)) + continue; + + if (likely(!word_offset && !word[0])) + return -1; + else + return fls(word[word_offset << 2]) - 1 + (word_offset << 5); +} + +static inline int apic_test_and_set_irr(int vec, struct kvm_lapic *apic) +{ + return apic_test_and_set_vector(vec, apic->regs + APIC_IRR); +} + +static inline void apic_clear_irr(int vec, struct kvm_lapic *apic) +{ + apic_clear_vector(vec, apic->regs + APIC_IRR); +} + +static inline int apic_find_highest_irr(struct kvm_lapic *apic) +{ + int result; + + result = find_highest_vector(apic->regs + APIC_IRR); + ASSERT(result == -1 || result >= 16); + + return result; +} + +int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic; + int highest_irr; + + if (!apic) + return 0; + highest_irr = apic_find_highest_irr(apic); + + return highest_irr; +} +EXPORT_SYMBOL_GPL(kvm_lapic_find_highest_irr); + +int kvm_apic_set_irq(struct kvm_lapic *apic, u8 vec, u8 trig) +{ + if (!apic_test_and_set_irr(vec, apic)) { + /* a new pending irq is set in IRR */ + if (trig) + apic_set_vector(vec, apic->regs + APIC_TMR); + else + apic_clear_vector(vec, apic->regs + APIC_TMR); + kvm_vcpu_kick(apic->vcpu); + return 1; + } + return 0; +} + +static inline int apic_find_highest_isr(struct kvm_lapic *apic) +{ + int result; + + result = find_highest_vector(apic->regs + APIC_ISR); + ASSERT(result == -1 || result >= 16); + + return result; +} + +static void apic_update_ppr(struct kvm_lapic *apic) +{ + u32 tpr, isrv, ppr; + int isr; + + tpr = apic_get_reg(apic, APIC_TASKPRI); + isr = apic_find_highest_isr(apic); + isrv = (isr != -1) ? isr : 0; + + if ((tpr & 0xf0) >= (isrv & 0xf0)) + ppr = tpr & 0xff; + else + ppr = isrv & 0xf0; + + apic_debug("vlapic %p, ppr 0x%x, isr 0x%x, isrv 0x%x", + apic, ppr, isr, isrv); + + apic_set_reg(apic, APIC_PROCPRI, ppr); +} + +static void apic_set_tpr(struct kvm_lapic *apic, u32 tpr) +{ + apic_set_reg(apic, APIC_TASKPRI, tpr); + apic_update_ppr(apic); +} + +int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest) +{ + return kvm_apic_id(apic) == dest; +} + +int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda) +{ + int result = 0; + u8 logical_id; + + logical_id = GET_APIC_LOGICAL_ID(apic_get_reg(apic, APIC_LDR)); + + switch (apic_get_reg(apic, APIC_DFR)) { + case APIC_DFR_FLAT: + if (logical_id & mda) + result = 1; + break; + case APIC_DFR_CLUSTER: + if (((logical_id >> 4) == (mda >> 0x4)) + && (logical_id & mda & 0xf)) + result = 1; + break; + default: + printk(KERN_WARNING "Bad DFR vcpu %d: %08x\n", + apic->vcpu->vcpu_id, apic_get_reg(apic, APIC_DFR)); + break; + } + + return result; +} + +static int apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, + int short_hand, int dest, int dest_mode) +{ + int result = 0; + struct kvm_lapic *target = vcpu->apic; + + apic_debug("target %p, source %p, dest 0x%x, " + "dest_mode 0x%x, short_hand 0x%x", + target, source, dest, dest_mode, short_hand); + + ASSERT(!target); + switch (short_hand) { + case APIC_DEST_NOSHORT: + if (dest_mode == 0) { + /* Physical mode. */ + if ((dest == 0xFF) || (dest == kvm_apic_id(target))) + result = 1; + } else + /* Logical mode. */ + result = kvm_apic_match_logical_addr(target, dest); + break; + case APIC_DEST_SELF: + if (target == source) + result = 1; + break; + case APIC_DEST_ALLINC: + result = 1; + break; + case APIC_DEST_ALLBUT: + if (target != source) + result = 1; + break; + default: + printk(KERN_WARNING "Bad dest shorthand value %x\n", + short_hand); + break; + } + + return result; +} + +/* + * Add a pending IRQ into lapic. + * Return 1 if successfully added and 0 if discarded. + */ +static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, + int vector, int level, int trig_mode) +{ + int orig_irr, result = 0; + struct kvm_vcpu *vcpu = apic->vcpu; + + switch (delivery_mode) { + case APIC_DM_FIXED: + case APIC_DM_LOWEST: + /* FIXME add logic for vcpu on reset */ + if (unlikely(!apic_enabled(apic))) + break; + + orig_irr = apic_test_and_set_irr(vector, apic); + if (orig_irr && trig_mode) { + apic_debug("level trig mode repeatedly for vector %d", + vector); + break; + } + + if (trig_mode) { + apic_debug("level trig mode for vector %d", vector); + apic_set_vector(vector, apic->regs + APIC_TMR); + } else + apic_clear_vector(vector, apic->regs + APIC_TMR); + + if (vcpu->mp_state == VCPU_MP_STATE_RUNNABLE) + kvm_vcpu_kick(vcpu); + else if (vcpu->mp_state == VCPU_MP_STATE_HALTED) { + vcpu->mp_state = VCPU_MP_STATE_RUNNABLE; + if (waitqueue_active(&vcpu->wq)) + wake_up_interruptible(&vcpu->wq); + } + + result = (orig_irr == 0); + break; + + case APIC_DM_REMRD: + printk(KERN_DEBUG "Ignoring delivery mode 3\n"); + break; + + case APIC_DM_SMI: + printk(KERN_DEBUG "Ignoring guest SMI\n"); + break; + case APIC_DM_NMI: + printk(KERN_DEBUG "Ignoring guest NMI\n"); + break; + + case APIC_DM_INIT: + if (level) { + if (vcpu->mp_state == VCPU_MP_STATE_RUNNABLE) + printk(KERN_DEBUG + "INIT on a runnable vcpu %d\n", + vcpu->vcpu_id); + vcpu->mp_state = VCPU_MP_STATE_INIT_RECEIVED; + kvm_vcpu_kick(vcpu); + } else { + printk(KERN_DEBUG + "Ignoring de-assert INIT to vcpu %d\n", + vcpu->vcpu_id); + } + + break; + + case APIC_DM_STARTUP: + printk(KERN_DEBUG "SIPI to vcpu %d vector 0x%02x\n", + vcpu->vcpu_id, vector); + if (vcpu->mp_state == VCPU_MP_STATE_INIT_RECEIVED) { + vcpu->sipi_vector = vector; + vcpu->mp_state = VCPU_MP_STATE_SIPI_RECEIVED; + if (waitqueue_active(&vcpu->wq)) + wake_up_interruptible(&vcpu->wq); + } + break; + + default: + printk(KERN_ERR "TODO: unsupported delivery mode %x\n", + delivery_mode); + break; + } + return result; +} + +struct kvm_lapic *kvm_apic_round_robin(struct kvm *kvm, u8 vector, + unsigned long bitmap) +{ + int vcpu_id; + int last; + int next; + struct kvm_lapic *apic; + + last = kvm->round_robin_prev_vcpu; + next = last; + + do { + if (++next == KVM_MAX_VCPUS) + next = 0; + if (kvm->vcpus[next] == NULL || !test_bit(next, &bitmap)) + continue; + apic = kvm->vcpus[next]->apic; + if (apic && apic_enabled(apic)) + break; + apic = NULL; + } while (next != last); + kvm->round_robin_prev_vcpu = next; + + if (!apic) { + vcpu_id = ffs(bitmap) - 1; + if (vcpu_id < 0) { + vcpu_id = 0; + printk(KERN_DEBUG "vcpu not ready for apic_round_robin\n"); + } + apic = kvm->vcpus[vcpu_id]->apic; + } + + return apic; +} + +static void apic_set_eoi(struct kvm_lapic *apic) +{ + int vector = apic_find_highest_isr(apic); + + /* + * Not every write EOI will has corresponding ISR, + * one example is when Kernel check timer on setup_IO_APIC + */ + if (vector == -1) + return; + + apic_clear_vector(vector, apic->regs + APIC_ISR); + apic_update_ppr(apic); + + if (apic_test_and_clear_vector(vector, apic->regs + APIC_TMR)) + kvm_ioapic_update_eoi(apic->vcpu->kvm, vector); +} + +static void apic_send_ipi(struct kvm_lapic *apic) +{ + u32 icr_low = apic_get_reg(apic, APIC_ICR); + u32 icr_high = apic_get_reg(apic, APIC_ICR2); + + unsigned int dest = GET_APIC_DEST_FIELD(icr_high); + unsigned int short_hand = icr_low & APIC_SHORT_MASK; + unsigned int trig_mode = icr_low & APIC_INT_LEVELTRIG; + unsigned int level = icr_low & APIC_INT_ASSERT; + unsigned int dest_mode = icr_low & APIC_DEST_MASK; + unsigned int delivery_mode = icr_low & APIC_MODE_MASK; + unsigned int vector = icr_low & APIC_VECTOR_MASK; + + struct kvm_lapic *target; + struct kvm_vcpu *vcpu; + unsigned long lpr_map = 0; + int i; + + apic_debug("icr_high 0x%x, icr_low 0x%x, " + "short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, " + "dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x\n", + icr_high, icr_low, short_hand, dest, + trig_mode, level, dest_mode, delivery_mode, vector); + + for (i = 0; i < KVM_MAX_VCPUS; i++) { + vcpu = apic->vcpu->kvm->vcpus[i]; + if (!vcpu) + continue; + + if (vcpu->apic && + apic_match_dest(vcpu, apic, short_hand, dest, dest_mode)) { + if (delivery_mode == APIC_DM_LOWEST) + set_bit(vcpu->vcpu_id, &lpr_map); + else + __apic_accept_irq(vcpu->apic, delivery_mode, + vector, level, trig_mode); + } + } + + if (delivery_mode == APIC_DM_LOWEST) { + target = kvm_apic_round_robin(vcpu->kvm, vector, lpr_map); + if (target != NULL) + __apic_accept_irq(target, delivery_mode, + vector, level, trig_mode); + } +} + +static u32 apic_get_tmcct(struct kvm_lapic *apic) +{ + u32 counter_passed; + ktime_t passed, now = apic->timer.dev.base->get_time(); + u32 tmcct = apic_get_reg(apic, APIC_TMICT); + + ASSERT(apic != NULL); + + if (unlikely(ktime_to_ns(now) <= + ktime_to_ns(apic->timer.last_update))) { + /* Wrap around */ + passed = ktime_add(( { + (ktime_t) { + .tv64 = KTIME_MAX - + (apic->timer.last_update).tv64}; } + ), now); + apic_debug("time elapsed\n"); + } else + passed = ktime_sub(now, apic->timer.last_update); + + counter_passed = div64_64(ktime_to_ns(passed), + (APIC_BUS_CYCLE_NS * apic->timer.divide_count)); + tmcct -= counter_passed; + + if (tmcct <= 0) { + if (unlikely(!apic_lvtt_period(apic))) + tmcct = 0; + else + do { + tmcct += apic_get_reg(apic, APIC_TMICT); + } while (tmcct <= 0); + } + + return tmcct; +} + +static u32 __apic_read(struct kvm_lapic *apic, unsigned int offset) +{ + u32 val = 0; + + if (offset >= LAPIC_MMIO_LENGTH) + return 0; + + switch (offset) { + case APIC_ARBPRI: + printk(KERN_WARNING "Access APIC ARBPRI register " + "which is for P6\n"); + break; + + case APIC_TMCCT: /* Timer CCR */ + val = apic_get_tmcct(apic); + break; + + default: + apic_update_ppr(apic); + val = apic_get_reg(apic, offset); + break; + } + + return val; +} + +static void apic_mmio_read(struct kvm_io_device *this, + gpa_t address, int len, void *data) +{ + struct kvm_lapic *apic = (struct kvm_lapic *)this->private; + unsigned int offset = address - apic->base_address; + unsigned char alignment = offset & 0xf; + u32 result; + + if ((alignment + len) > 4) { + printk(KERN_ERR "KVM_APIC_READ: alignment error %lx %d", + (unsigned long)address, len); + return; + } + result = __apic_read(apic, offset & ~0xf); + + switch (len) { + case 1: + case 2: + case 4: + memcpy(data, (char *)&result + alignment, len); + break; + default: + printk(KERN_ERR "Local APIC read with len = %x, " + "should be 1,2, or 4 instead\n", len); + break; + } +} + +static void update_divide_count(struct kvm_lapic *apic) +{ + u32 tmp1, tmp2, tdcr; + + tdcr = apic_get_reg(apic, APIC_TDCR); + tmp1 = tdcr & 0xf; + tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1; + apic->timer.divide_count = 0x1 << (tmp2 & 0x7); + + apic_debug("timer divide count is 0x%x\n", + apic->timer.divide_count); +} + +static void start_apic_timer(struct kvm_lapic *apic) +{ + ktime_t now = apic->timer.dev.base->get_time(); + + apic->timer.last_update = now; + + apic->timer.period = apic_get_reg(apic, APIC_TMICT) * + APIC_BUS_CYCLE_NS * apic->timer.divide_count; + atomic_set(&apic->timer.pending, 0); + hrtimer_start(&apic->timer.dev, + ktime_add_ns(now, apic->timer.period), + HRTIMER_MODE_ABS); + + apic_debug("%s: bus cycle is %" PRId64 "ns, now 0x%016" + PRIx64 ", " + "timer initial count 0x%x, period %lldns, " + "expire @ 0x%016" PRIx64 ".\n", __FUNCTION__, + APIC_BUS_CYCLE_NS, ktime_to_ns(now), + apic_get_reg(apic, APIC_TMICT), + apic->timer.period, + ktime_to_ns(ktime_add_ns(now, + apic->timer.period))); +} + +static void apic_mmio_write(struct kvm_io_device *this, + gpa_t address, int len, const void *data) +{ + struct kvm_lapic *apic = (struct kvm_lapic *)this->private; + unsigned int offset = address - apic->base_address; + unsigned char alignment = offset & 0xf; + u32 val; + + /* + * APIC register must be aligned on 128-bits boundary. + * 32/64/128 bits registers must be accessed thru 32 bits. + * Refer SDM 8.4.1 + */ + if (len != 4 || alignment) { + if (printk_ratelimit()) + printk(KERN_ERR "apic write: bad size=%d %lx\n", + len, (long)address); + return; + } + + val = *(u32 *) data; + + /* too common printing */ + if (offset != APIC_EOI) + apic_debug("%s: offset 0x%x with length 0x%x, and value is " + "0x%x\n", __FUNCTION__, offset, len, val); + + offset &= 0xff0; + + switch (offset) { + case APIC_ID: /* Local APIC ID */ + apic_set_reg(apic, APIC_ID, val); + break; + + case APIC_TASKPRI: + apic_set_tpr(apic, val & 0xff); + break; + + case APIC_EOI: + apic_set_eoi(apic); + break; + + case APIC_LDR: + apic_set_reg(apic, APIC_LDR, val & APIC_LDR_MASK); + break; + + case APIC_DFR: + apic_set_reg(apic, APIC_DFR, val | 0x0FFFFFFF); + break; + + case APIC_SPIV: + apic_set_reg(apic, APIC_SPIV, val & 0x3ff); + if (!(val & APIC_SPIV_APIC_ENABLED)) { + int i; + u32 lvt_val; + + for (i = 0; i < APIC_LVT_NUM; i++) { + lvt_val = apic_get_reg(apic, + APIC_LVTT + 0x10 * i); + apic_set_reg(apic, APIC_LVTT + 0x10 * i, + lvt_val | APIC_LVT_MASKED); + } + atomic_set(&apic->timer.pending, 0); + + } + break; + + case APIC_ICR: + /* No delay here, so we always clear the pending bit */ + apic_set_reg(apic, APIC_ICR, val & ~(1 << 12)); + apic_send_ipi(apic); + break; + + case APIC_ICR2: + apic_set_reg(apic, APIC_ICR2, val & 0xff000000); + break; + + case APIC_LVTT: + case APIC_LVTTHMR: + case APIC_LVTPC: + case APIC_LVT0: + case APIC_LVT1: + case APIC_LVTERR: + /* TODO: Check vector */ + if (!apic_sw_enabled(apic)) + val |= APIC_LVT_MASKED; + + val &= apic_lvt_mask[(offset - APIC_LVTT) >> 4]; + apic_set_reg(apic, offset, val); + + break; + + case APIC_TMICT: + hrtimer_cancel(&apic->timer.dev); + apic_set_reg(apic, APIC_TMICT, val); + start_apic_timer(apic); + return; + + case APIC_TDCR: + if (val & 4) + printk(KERN_ERR "KVM_WRITE:TDCR %x\n", val); + apic_set_reg(apic, APIC_TDCR, val); + update_divide_count(apic); + break; + + default: + apic_debug("Local APIC Write to read-only register %x\n", + offset); + break; + } + +} + +static int apic_mmio_range(struct kvm_io_device *this, gpa_t addr) +{ + struct kvm_lapic *apic = (struct kvm_lapic *)this->private; + int ret = 0; + + + if (apic_hw_enabled(apic) && + (addr >= apic->base_address) && + (addr < (apic->base_address + LAPIC_MMIO_LENGTH))) + ret = 1; + + return ret; +} + +void kvm_free_apic(struct kvm_lapic *apic) +{ + if (!apic) + return; + + hrtimer_cancel(&apic->timer.dev); + + if (apic->regs_page) { + __free_page(apic->regs_page); + apic->regs_page = 0; + } + + kfree(apic); +} + +/* + *---------------------------------------------------------------------- + * LAPIC interface + *---------------------------------------------------------------------- + */ + +void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8) +{ + struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic; + + if (!apic) + return; + apic_set_tpr(apic, ((cr8 & 0x0f) << 4)); +} + +u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic; + u64 tpr; + + if (!apic) + return 0; + tpr = (u64) apic_get_reg(apic, APIC_TASKPRI); + + return (tpr & 0xf0) >> 4; +} +EXPORT_SYMBOL_GPL(kvm_lapic_get_cr8); + +void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value) +{ + struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic; + + if (!apic) { + value |= MSR_IA32_APICBASE_BSP; + vcpu->apic_base = value; + return; + } + if (apic->vcpu->vcpu_id) + value &= ~MSR_IA32_APICBASE_BSP; + + vcpu->apic_base = value; + apic->base_address = apic->vcpu->apic_base & + MSR_IA32_APICBASE_BASE; + + /* with FSB delivery interrupt, we can restart APIC functionality */ + apic_debug("apic base msr is 0x%016" PRIx64 ", and base address is " + "0x%lx.\n", apic->apic_base, apic->base_address); + +} + +u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu) +{ + return vcpu->apic_base; +} +EXPORT_SYMBOL_GPL(kvm_lapic_get_base); + +void kvm_lapic_reset(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic; + int i; + + apic_debug("%s\n", __FUNCTION__); + + ASSERT(vcpu); + apic = vcpu->apic; + ASSERT(apic != NULL); + + /* Stop the timer in case it's a reset to an active apic */ + hrtimer_cancel(&apic->timer.dev); + + apic_set_reg(apic, APIC_ID, vcpu->vcpu_id << 24); + apic_set_reg(apic, APIC_LVR, APIC_VERSION); + + for (i = 0; i < APIC_LVT_NUM; i++) + apic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED); + apic_set_reg(apic, APIC_LVT0, + SET_APIC_DELIVERY_MODE(0, APIC_MODE_EXTINT)); + + apic_set_reg(apic, APIC_DFR, 0xffffffffU); + apic_set_reg(apic, APIC_SPIV, 0xff); + apic_set_reg(apic, APIC_TASKPRI, 0); + apic_set_reg(apic, APIC_LDR, 0); + apic_set_reg(apic, APIC_ESR, 0); + apic_set_reg(apic, APIC_ICR, 0); + apic_set_reg(apic, APIC_ICR2, 0); + apic_set_reg(apic, APIC_TDCR, 0); + apic_set_reg(apic, APIC_TMICT, 0); + for (i = 0; i < 8; i++) { + apic_set_reg(apic, APIC_IRR + 0x10 * i, 0); + apic_set_reg(apic, APIC_ISR + 0x10 * i, 0); + apic_set_reg(apic, APIC_TMR + 0x10 * i, 0); + } + apic->timer.divide_count = 0; + atomic_set(&apic->timer.pending, 0); + if (vcpu->vcpu_id == 0) + vcpu->apic_base |= MSR_IA32_APICBASE_BSP; + apic_update_ppr(apic); + + apic_debug(KERN_INFO "%s: vcpu=%p, id=%d, base_msr=" + "0x%016" PRIx64 ", base_address=0x%0lx.\n", __FUNCTION__, + vcpu, kvm_apic_id(apic), + vcpu->apic_base, apic->base_address); +} +EXPORT_SYMBOL_GPL(kvm_lapic_reset); + +int kvm_lapic_enabled(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic; + int ret = 0; + + if (!apic) + return 0; + ret = apic_enabled(apic); + + return ret; +} +EXPORT_SYMBOL_GPL(kvm_lapic_enabled); + +/* + *---------------------------------------------------------------------- + * timer interface + *---------------------------------------------------------------------- + */ + +/* TODO: make sure __apic_timer_fn runs in current pCPU */ +static int __apic_timer_fn(struct kvm_lapic *apic) +{ + int result = 0; + wait_queue_head_t *q = &apic->vcpu->wq; + + atomic_inc(&apic->timer.pending); + if (waitqueue_active(q)) + { + apic->vcpu->mp_state = VCPU_MP_STATE_RUNNABLE; + wake_up_interruptible(q); + } + if (apic_lvtt_period(apic)) { + result = 1; + apic->timer.dev.expires = ktime_add_ns( + apic->timer.dev.expires, + apic->timer.period); + } + return result; +} + +static int __inject_apic_timer_irq(struct kvm_lapic *apic) +{ + int vector; + + vector = apic_lvt_vector(apic, APIC_LVTT); + return __apic_accept_irq(apic, APIC_DM_FIXED, vector, 1, 0); +} + +static enum hrtimer_restart apic_timer_fn(struct hrtimer *data) +{ + struct kvm_lapic *apic; + int restart_timer = 0; + + apic = container_of(data, struct kvm_lapic, timer.dev); + + restart_timer = __apic_timer_fn(apic); + + if (restart_timer) + return HRTIMER_RESTART; + else + return HRTIMER_NORESTART; +} + +int kvm_create_lapic(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic; + + ASSERT(vcpu != NULL); + apic_debug("apic_init %d\n", vcpu->vcpu_id); + + apic = kzalloc(sizeof(*apic), GFP_KERNEL); + if (!apic) + goto nomem; + + vcpu->apic = apic; + + apic->regs_page = alloc_page(GFP_KERNEL); + if (apic->regs_page == NULL) { + printk(KERN_ERR "malloc apic regs error for vcpu %x\n", + vcpu->vcpu_id); + goto nomem; + } + apic->regs = page_address(apic->regs_page); + memset(apic->regs, 0, PAGE_SIZE); + apic->vcpu = vcpu; + + hrtimer_init(&apic->timer.dev, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); + apic->timer.dev.function = apic_timer_fn; + apic->base_address = APIC_DEFAULT_PHYS_BASE; + vcpu->apic_base = APIC_DEFAULT_PHYS_BASE; + + kvm_lapic_reset(vcpu); + apic->dev.read = apic_mmio_read; + apic->dev.write = apic_mmio_write; + apic->dev.in_range = apic_mmio_range; + apic->dev.private = apic; + + return 0; +nomem: + kvm_free_apic(apic); + return -ENOMEM; +} +EXPORT_SYMBOL_GPL(kvm_create_lapic); + +int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic = vcpu->apic; + int highest_irr; + + if (!apic || !apic_enabled(apic)) + return -1; + + apic_update_ppr(apic); + highest_irr = apic_find_highest_irr(apic); + if ((highest_irr == -1) || + ((highest_irr & 0xF0) <= apic_get_reg(apic, APIC_PROCPRI))) + return -1; + return highest_irr; +} + +int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu) +{ + u32 lvt0 = apic_get_reg(vcpu->apic, APIC_LVT0); + int r = 0; + + if (vcpu->vcpu_id == 0) { + if (!apic_hw_enabled(vcpu->apic)) + r = 1; + if ((lvt0 & APIC_LVT_MASKED) == 0 && + GET_APIC_DELIVERY_MODE(lvt0) == APIC_MODE_EXTINT) + r = 1; + } + return r; +} + +void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic = vcpu->apic; + + if (apic && apic_lvt_enabled(apic, APIC_LVTT) && + atomic_read(&apic->timer.pending) > 0) { + if (__inject_apic_timer_irq(apic)) + atomic_dec(&apic->timer.pending); + } +} + +void kvm_apic_timer_intr_post(struct kvm_vcpu *vcpu, int vec) +{ + struct kvm_lapic *apic = vcpu->apic; + + if (apic && apic_lvt_vector(apic, APIC_LVTT) == vec) + apic->timer.last_update = ktime_add_ns( + apic->timer.last_update, + apic->timer.period); +} + +int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu) +{ + int vector = kvm_apic_has_interrupt(vcpu); + struct kvm_lapic *apic = vcpu->apic; + + if (vector == -1) + return -1; + + apic_set_vector(vector, apic->regs + APIC_ISR); + apic_update_ppr(apic); + apic_clear_irr(vector, apic); + return vector; +} + +void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic = vcpu->apic; + + apic->base_address = vcpu->apic_base & + MSR_IA32_APICBASE_BASE; + apic_set_reg(apic, APIC_LVR, APIC_VERSION); + apic_update_ppr(apic); + hrtimer_cancel(&apic->timer.dev); + update_divide_count(apic); + start_apic_timer(apic); +} + +void kvm_migrate_apic_timer(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic = vcpu->apic; + struct hrtimer *timer; + + if (!apic) + return; + + timer = &apic->timer.dev; + if (hrtimer_cancel(timer)) + hrtimer_start(timer, timer->expires, HRTIMER_MODE_ABS); +} +EXPORT_SYMBOL_GPL(kvm_migrate_apic_timer); diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c index 23965aa5ee78..6d84d30f5ed0 100644 --- a/drivers/kvm/mmu.c +++ b/drivers/kvm/mmu.c @@ -158,7 +158,7 @@ static struct kmem_cache *mmu_page_header_cache; static int is_write_protection(struct kvm_vcpu *vcpu) { - return vcpu->cr0 & CR0_WP_MASK; + return vcpu->cr0 & X86_CR0_WP; } static int is_cpuid_PSE36(void) @@ -202,15 +202,14 @@ static void set_shadow_pte(u64 *sptep, u64 spte) } static int mmu_topup_memory_cache(struct kvm_mmu_memory_cache *cache, - struct kmem_cache *base_cache, int min, - gfp_t gfp_flags) + struct kmem_cache *base_cache, int min) { void *obj; if (cache->nobjs >= min) return 0; while (cache->nobjs < ARRAY_SIZE(cache->objects)) { - obj = kmem_cache_zalloc(base_cache, gfp_flags); + obj = kmem_cache_zalloc(base_cache, GFP_KERNEL); if (!obj) return -ENOMEM; cache->objects[cache->nobjs++] = obj; @@ -225,14 +224,14 @@ static void mmu_free_memory_cache(struct kvm_mmu_memory_cache *mc) } static int mmu_topup_memory_cache_page(struct kvm_mmu_memory_cache *cache, - int min, gfp_t gfp_flags) + int min) { struct page *page; if (cache->nobjs >= min) return 0; while (cache->nobjs < ARRAY_SIZE(cache->objects)) { - page = alloc_page(gfp_flags); + page = alloc_page(GFP_KERNEL); if (!page) return -ENOMEM; set_page_private(page, 0); @@ -247,44 +246,28 @@ static void mmu_free_memory_cache_page(struct kvm_mmu_memory_cache *mc) free_page((unsigned long)mc->objects[--mc->nobjs]); } -static int __mmu_topup_memory_caches(struct kvm_vcpu *vcpu, gfp_t gfp_flags) +static int mmu_topup_memory_caches(struct kvm_vcpu *vcpu) { int r; + kvm_mmu_free_some_pages(vcpu); r = mmu_topup_memory_cache(&vcpu->mmu_pte_chain_cache, - pte_chain_cache, 4, gfp_flags); + pte_chain_cache, 4); if (r) goto out; r = mmu_topup_memory_cache(&vcpu->mmu_rmap_desc_cache, - rmap_desc_cache, 1, gfp_flags); + rmap_desc_cache, 1); if (r) goto out; - r = mmu_topup_memory_cache_page(&vcpu->mmu_page_cache, 4, gfp_flags); + r = mmu_topup_memory_cache_page(&vcpu->mmu_page_cache, 4); if (r) goto out; r = mmu_topup_memory_cache(&vcpu->mmu_page_header_cache, - mmu_page_header_cache, 4, gfp_flags); + mmu_page_header_cache, 4); out: return r; } -static int mmu_topup_memory_caches(struct kvm_vcpu *vcpu) -{ - int r; - - r = __mmu_topup_memory_caches(vcpu, GFP_NOWAIT); - kvm_mmu_free_some_pages(vcpu); - if (r < 0) { - spin_unlock(&vcpu->kvm->lock); - kvm_arch_ops->vcpu_put(vcpu); - r = __mmu_topup_memory_caches(vcpu, GFP_KERNEL); - kvm_arch_ops->vcpu_load(vcpu); - spin_lock(&vcpu->kvm->lock); - kvm_mmu_free_some_pages(vcpu); - } - return r; -} - static void mmu_free_memory_caches(struct kvm_vcpu *vcpu) { mmu_free_memory_cache(&vcpu->mmu_pte_chain_cache); @@ -969,7 +952,7 @@ static int nonpaging_init_context(struct kvm_vcpu *vcpu) static void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu) { ++vcpu->stat.tlb_flush; - kvm_arch_ops->tlb_flush(vcpu); + kvm_x86_ops->tlb_flush(vcpu); } static void paging_new_cr3(struct kvm_vcpu *vcpu) @@ -982,7 +965,7 @@ static void inject_page_fault(struct kvm_vcpu *vcpu, u64 addr, u32 err_code) { - kvm_arch_ops->inject_page_fault(vcpu, addr, err_code); + kvm_x86_ops->inject_page_fault(vcpu, addr, err_code); } static void paging_free(struct kvm_vcpu *vcpu) @@ -1071,15 +1054,15 @@ int kvm_mmu_load(struct kvm_vcpu *vcpu) { int r; - spin_lock(&vcpu->kvm->lock); + mutex_lock(&vcpu->kvm->lock); r = mmu_topup_memory_caches(vcpu); if (r) goto out; mmu_alloc_roots(vcpu); - kvm_arch_ops->set_cr3(vcpu, vcpu->mmu.root_hpa); + kvm_x86_ops->set_cr3(vcpu, vcpu->mmu.root_hpa); kvm_mmu_flush_tlb(vcpu); out: - spin_unlock(&vcpu->kvm->lock); + mutex_unlock(&vcpu->kvm->lock); return r; } EXPORT_SYMBOL_GPL(kvm_mmu_load); @@ -1124,7 +1107,7 @@ static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu, } void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, - const u8 *old, const u8 *new, int bytes) + const u8 *new, int bytes) { gfn_t gfn = gpa >> PAGE_SHIFT; struct kvm_mmu_page *page; diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h index 4b5391c717f8..6b094b44f8fb 100644 --- a/drivers/kvm/paging_tmpl.h +++ b/drivers/kvm/paging_tmpl.h @@ -58,7 +58,10 @@ struct guest_walker { int level; gfn_t table_gfn[PT_MAX_FULL_LEVELS]; pt_element_t *table; + pt_element_t pte; pt_element_t *ptep; + struct page *page; + int index; pt_element_t inherited_ar; gfn_t gfn; u32 error_code; @@ -80,11 +83,14 @@ static int FNAME(walk_addr)(struct guest_walker *walker, pgprintk("%s: addr %lx\n", __FUNCTION__, addr); walker->level = vcpu->mmu.root_level; walker->table = NULL; + walker->page = NULL; + walker->ptep = NULL; root = vcpu->cr3; #if PTTYPE == 64 if (!is_long_mode(vcpu)) { walker->ptep = &vcpu->pdptrs[(addr >> 30) & 3]; root = *walker->ptep; + walker->pte = root; if (!(root & PT_PRESENT_MASK)) goto not_present; --walker->level; @@ -96,10 +102,11 @@ static int FNAME(walk_addr)(struct guest_walker *walker, walker->level - 1, table_gfn); slot = gfn_to_memslot(vcpu->kvm, table_gfn); hpa = safe_gpa_to_hpa(vcpu, root & PT64_BASE_ADDR_MASK); - walker->table = kmap_atomic(pfn_to_page(hpa >> PAGE_SHIFT), KM_USER0); + walker->page = pfn_to_page(hpa >> PAGE_SHIFT); + walker->table = kmap_atomic(walker->page, KM_USER0); ASSERT((!is_long_mode(vcpu) && is_pae(vcpu)) || - (vcpu->cr3 & ~(PAGE_MASK | CR3_FLAGS_MASK)) == 0); + (vcpu->cr3 & CR3_NONPAE_RESERVED_BITS) == 0); walker->inherited_ar = PT_USER_MASK | PT_WRITABLE_MASK; @@ -108,6 +115,7 @@ static int FNAME(walk_addr)(struct guest_walker *walker, hpa_t paddr; ptep = &walker->table[index]; + walker->index = index; ASSERT(((unsigned long)walker->table & PAGE_MASK) == ((unsigned long)ptep & PAGE_MASK)); @@ -148,16 +156,20 @@ static int FNAME(walk_addr)(struct guest_walker *walker, walker->inherited_ar &= walker->table[index]; table_gfn = (*ptep & PT_BASE_ADDR_MASK) >> PAGE_SHIFT; - paddr = safe_gpa_to_hpa(vcpu, *ptep & PT_BASE_ADDR_MASK); kunmap_atomic(walker->table, KM_USER0); - walker->table = kmap_atomic(pfn_to_page(paddr >> PAGE_SHIFT), - KM_USER0); + paddr = safe_gpa_to_hpa(vcpu, table_gfn << PAGE_SHIFT); + walker->page = pfn_to_page(paddr >> PAGE_SHIFT); + walker->table = kmap_atomic(walker->page, KM_USER0); --walker->level; walker->table_gfn[walker->level - 1 ] = table_gfn; pgprintk("%s: table_gfn[%d] %lx\n", __FUNCTION__, walker->level - 1, table_gfn); } - walker->ptep = ptep; + walker->pte = *ptep; + if (walker->page) + walker->ptep = NULL; + if (walker->table) + kunmap_atomic(walker->table, KM_USER0); pgprintk("%s: pte %llx\n", __FUNCTION__, (u64)*ptep); return 1; @@ -175,13 +187,9 @@ err: walker->error_code |= PFERR_USER_MASK; if (fetch_fault) walker->error_code |= PFERR_FETCH_MASK; - return 0; -} - -static void FNAME(release_walker)(struct guest_walker *walker) -{ if (walker->table) kunmap_atomic(walker->table, KM_USER0); + return 0; } static void FNAME(mark_pagetable_dirty)(struct kvm *kvm, @@ -193,7 +201,7 @@ static void FNAME(mark_pagetable_dirty)(struct kvm *kvm, static void FNAME(set_pte_common)(struct kvm_vcpu *vcpu, u64 *shadow_pte, gpa_t gaddr, - pt_element_t *gpte, + pt_element_t gpte, u64 access_bits, int user_fault, int write_fault, @@ -202,23 +210,34 @@ static void FNAME(set_pte_common)(struct kvm_vcpu *vcpu, gfn_t gfn) { hpa_t paddr; - int dirty = *gpte & PT_DIRTY_MASK; + int dirty = gpte & PT_DIRTY_MASK; u64 spte = *shadow_pte; int was_rmapped = is_rmap_pte(spte); pgprintk("%s: spte %llx gpte %llx access %llx write_fault %d" " user_fault %d gfn %lx\n", - __FUNCTION__, spte, (u64)*gpte, access_bits, + __FUNCTION__, spte, (u64)gpte, access_bits, write_fault, user_fault, gfn); if (write_fault && !dirty) { - *gpte |= PT_DIRTY_MASK; + pt_element_t *guest_ent, *tmp = NULL; + + if (walker->ptep) + guest_ent = walker->ptep; + else { + tmp = kmap_atomic(walker->page, KM_USER0); + guest_ent = &tmp[walker->index]; + } + + *guest_ent |= PT_DIRTY_MASK; + if (!walker->ptep) + kunmap_atomic(tmp, KM_USER0); dirty = 1; FNAME(mark_pagetable_dirty)(vcpu->kvm, walker); } spte |= PT_PRESENT_MASK | PT_ACCESSED_MASK | PT_DIRTY_MASK; - spte |= *gpte & PT64_NX_MASK; + spte |= gpte & PT64_NX_MASK; if (!dirty) access_bits &= ~PT_WRITABLE_MASK; @@ -255,7 +274,7 @@ static void FNAME(set_pte_common)(struct kvm_vcpu *vcpu, access_bits &= ~PT_WRITABLE_MASK; if (is_writeble_pte(spte)) { spte &= ~PT_WRITABLE_MASK; - kvm_arch_ops->tlb_flush(vcpu); + kvm_x86_ops->tlb_flush(vcpu); } if (write_fault) *ptwrite = 1; @@ -273,13 +292,13 @@ unshadowed: rmap_add(vcpu, shadow_pte); } -static void FNAME(set_pte)(struct kvm_vcpu *vcpu, pt_element_t *gpte, +static void FNAME(set_pte)(struct kvm_vcpu *vcpu, pt_element_t gpte, u64 *shadow_pte, u64 access_bits, int user_fault, int write_fault, int *ptwrite, struct guest_walker *walker, gfn_t gfn) { - access_bits &= *gpte; - FNAME(set_pte_common)(vcpu, shadow_pte, *gpte & PT_BASE_ADDR_MASK, + access_bits &= gpte; + FNAME(set_pte_common)(vcpu, shadow_pte, gpte & PT_BASE_ADDR_MASK, gpte, access_bits, user_fault, write_fault, ptwrite, walker, gfn); } @@ -295,22 +314,22 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page, if (~gpte & (PT_PRESENT_MASK | PT_ACCESSED_MASK)) return; pgprintk("%s: gpte %llx spte %p\n", __FUNCTION__, (u64)gpte, spte); - FNAME(set_pte)(vcpu, &gpte, spte, PT_USER_MASK | PT_WRITABLE_MASK, 0, + FNAME(set_pte)(vcpu, gpte, spte, PT_USER_MASK | PT_WRITABLE_MASK, 0, 0, NULL, NULL, (gpte & PT_BASE_ADDR_MASK) >> PAGE_SHIFT); } -static void FNAME(set_pde)(struct kvm_vcpu *vcpu, pt_element_t *gpde, +static void FNAME(set_pde)(struct kvm_vcpu *vcpu, pt_element_t gpde, u64 *shadow_pte, u64 access_bits, int user_fault, int write_fault, int *ptwrite, struct guest_walker *walker, gfn_t gfn) { gpa_t gaddr; - access_bits &= *gpde; + access_bits &= gpde; gaddr = (gpa_t)gfn << PAGE_SHIFT; if (PTTYPE == 32 && is_cpuid_PSE36()) - gaddr |= (*gpde & PT32_DIR_PSE36_MASK) << + gaddr |= (gpde & PT32_DIR_PSE36_MASK) << (32 - PT32_DIR_PSE36_SHIFT); FNAME(set_pte_common)(vcpu, shadow_pte, gaddr, gpde, access_bits, user_fault, write_fault, @@ -328,9 +347,8 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, int level; u64 *shadow_ent; u64 *prev_shadow_ent = NULL; - pt_element_t *guest_ent = walker->ptep; - if (!is_present_pte(*guest_ent)) + if (!is_present_pte(walker->pte)) return NULL; shadow_addr = vcpu->mmu.root_hpa; @@ -364,12 +382,12 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, if (level - 1 == PT_PAGE_TABLE_LEVEL && walker->level == PT_DIRECTORY_LEVEL) { metaphysical = 1; - hugepage_access = *guest_ent; + hugepage_access = walker->pte; hugepage_access &= PT_USER_MASK | PT_WRITABLE_MASK; - if (*guest_ent & PT64_NX_MASK) + if (walker->pte & PT64_NX_MASK) hugepage_access |= (1 << 2); hugepage_access >>= PT_WRITABLE_SHIFT; - table_gfn = (*guest_ent & PT_BASE_ADDR_MASK) + table_gfn = (walker->pte & PT_BASE_ADDR_MASK) >> PAGE_SHIFT; } else { metaphysical = 0; @@ -386,12 +404,12 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, } if (walker->level == PT_DIRECTORY_LEVEL) { - FNAME(set_pde)(vcpu, guest_ent, shadow_ent, + FNAME(set_pde)(vcpu, walker->pte, shadow_ent, walker->inherited_ar, user_fault, write_fault, ptwrite, walker, walker->gfn); } else { ASSERT(walker->level == PT_PAGE_TABLE_LEVEL); - FNAME(set_pte)(vcpu, guest_ent, shadow_ent, + FNAME(set_pte)(vcpu, walker->pte, shadow_ent, walker->inherited_ar, user_fault, write_fault, ptwrite, walker, walker->gfn); } @@ -442,7 +460,6 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, if (!r) { pgprintk("%s: guest page fault\n", __FUNCTION__); inject_page_fault(vcpu, addr, walker.error_code); - FNAME(release_walker)(&walker); vcpu->last_pt_write_count = 0; /* reset fork detector */ return 0; } @@ -452,8 +469,6 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, pgprintk("%s: shadow pte %p %llx ptwrite %d\n", __FUNCTION__, shadow_pte, *shadow_pte, write_pt); - FNAME(release_walker)(&walker); - if (!write_pt) vcpu->last_pt_write_count = 0; /* reset fork detector */ @@ -482,7 +497,6 @@ static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr) gpa |= vaddr & ~PAGE_MASK; } - FNAME(release_walker)(&walker); return gpa; } diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c index bc818cc126e3..729f1cd93606 100644 --- a/drivers/kvm/svm.c +++ b/drivers/kvm/svm.c @@ -16,12 +16,12 @@ #include "kvm_svm.h" #include "x86_emulate.h" +#include "irq.h" #include <linux/module.h> #include <linux/kernel.h> #include <linux/vmalloc.h> #include <linux/highmem.h> -#include <linux/profile.h> #include <linux/sched.h> #include <asm/desc.h> @@ -38,7 +38,6 @@ MODULE_LICENSE("GPL"); #define DR7_GD_MASK (1 << 13) #define DR6_BD_MASK (1 << 13) -#define CR4_DE_MASK (1UL << 3) #define SEG_TYPE_LDT 2 #define SEG_TYPE_BUSY_TSS16 3 @@ -50,6 +49,13 @@ MODULE_LICENSE("GPL"); #define SVM_FEATURE_LBRV (1 << 1) #define SVM_DEATURE_SVML (1 << 2) +static void kvm_reput_irq(struct vcpu_svm *svm); + +static inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu) +{ + return container_of(vcpu, struct vcpu_svm, vcpu); +} + unsigned long iopm_base; unsigned long msrpm_base; @@ -94,20 +100,6 @@ static inline u32 svm_has(u32 feat) return svm_features & feat; } -static unsigned get_addr_size(struct kvm_vcpu *vcpu) -{ - struct vmcb_save_area *sa = &vcpu->svm->vmcb->save; - u16 cs_attrib; - - if (!(sa->cr0 & CR0_PE_MASK) || (sa->rflags & X86_EFLAGS_VM)) - return 2; - - cs_attrib = sa->cs.attrib; - - return (cs_attrib & SVM_SELECTOR_L_MASK) ? 8 : - (cs_attrib & SVM_SELECTOR_DB_MASK) ? 4 : 2; -} - static inline u8 pop_irq(struct kvm_vcpu *vcpu) { int word_index = __ffs(vcpu->irq_summary); @@ -182,7 +174,7 @@ static inline void write_dr7(unsigned long val) static inline void force_new_asid(struct kvm_vcpu *vcpu) { - vcpu->svm->asid_generation--; + to_svm(vcpu)->asid_generation--; } static inline void flush_guest_tlb(struct kvm_vcpu *vcpu) @@ -195,22 +187,24 @@ static void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer) if (!(efer & KVM_EFER_LMA)) efer &= ~KVM_EFER_LME; - vcpu->svm->vmcb->save.efer = efer | MSR_EFER_SVME_MASK; + to_svm(vcpu)->vmcb->save.efer = efer | MSR_EFER_SVME_MASK; vcpu->shadow_efer = efer; } static void svm_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code) { - vcpu->svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | + struct vcpu_svm *svm = to_svm(vcpu); + + svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | SVM_EVTINJ_VALID_ERR | SVM_EVTINJ_TYPE_EXEPT | GP_VECTOR; - vcpu->svm->vmcb->control.event_inj_err = error_code; + svm->vmcb->control.event_inj_err = error_code; } static void inject_ud(struct kvm_vcpu *vcpu) { - vcpu->svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | + to_svm(vcpu)->vmcb->control.event_inj = SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_EXEPT | UD_VECTOR; } @@ -229,19 +223,21 @@ static int is_external_interrupt(u32 info) static void skip_emulated_instruction(struct kvm_vcpu *vcpu) { - if (!vcpu->svm->next_rip) { + struct vcpu_svm *svm = to_svm(vcpu); + + if (!svm->next_rip) { printk(KERN_DEBUG "%s: NOP\n", __FUNCTION__); return; } - if (vcpu->svm->next_rip - vcpu->svm->vmcb->save.rip > 15) { + if (svm->next_rip - svm->vmcb->save.rip > MAX_INST_SIZE) { printk(KERN_ERR "%s: ip 0x%llx next 0x%llx\n", __FUNCTION__, - vcpu->svm->vmcb->save.rip, - vcpu->svm->next_rip); + svm->vmcb->save.rip, + svm->next_rip); } - vcpu->rip = vcpu->svm->vmcb->save.rip = vcpu->svm->next_rip; - vcpu->svm->vmcb->control.int_state &= ~SVM_INTERRUPT_SHADOW_MASK; + vcpu->rip = svm->vmcb->save.rip = svm->next_rip; + svm->vmcb->control.int_state &= ~SVM_INTERRUPT_SHADOW_MASK; vcpu->interrupt_window_open = 1; } @@ -351,8 +347,8 @@ err_1: } -static int set_msr_interception(u32 *msrpm, unsigned msr, - int read, int write) +static void set_msr_interception(u32 *msrpm, unsigned msr, + int read, int write) { int i; @@ -367,11 +363,10 @@ static int set_msr_interception(u32 *msrpm, unsigned msr, u32 mask = ((write) ? 0 : 2) | ((read) ? 0 : 1); *base = (*base & ~(0x3 << msr_shift)) | (mask << msr_shift); - return 1; + return; } } - printk(KERN_DEBUG "%s: not found 0x%x\n", __FUNCTION__, msr); - return 0; + BUG(); } static __init int svm_hardware_setup(void) @@ -382,8 +377,6 @@ static __init int svm_hardware_setup(void) void *iopm_va, *msrpm_va; int r; - kvm_emulator_want_group7_invlpg(); - iopm_pages = alloc_pages(GFP_KERNEL, IOPM_ALLOC_ORDER); if (!iopm_pages) @@ -458,11 +451,6 @@ static void init_sys_seg(struct vmcb_seg *seg, uint32_t type) seg->base = 0; } -static int svm_vcpu_setup(struct kvm_vcpu *vcpu) -{ - return 0; -} - static void init_vmcb(struct vmcb *vmcb) { struct vmcb_control_area *control = &vmcb->control; @@ -563,59 +551,83 @@ 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 | CR0_WP_MASK; - save->cr4 = CR4_PAE_MASK; + save->cr0 = 0x00000010 | X86_CR0_PG | X86_CR0_WP; + save->cr4 = X86_CR4_PAE; /* rdx = ?? */ } -static int svm_create_vcpu(struct kvm_vcpu *vcpu) +static void svm_vcpu_reset(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + init_vmcb(svm->vmcb); +} + +static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id) { + struct vcpu_svm *svm; struct page *page; - int r; + int err; + + svm = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL); + if (!svm) { + err = -ENOMEM; + goto out; + } + + err = kvm_vcpu_init(&svm->vcpu, kvm, id); + if (err) + goto free_svm; + + if (irqchip_in_kernel(kvm)) { + err = kvm_create_lapic(&svm->vcpu); + if (err < 0) + goto free_svm; + } - r = -ENOMEM; - vcpu->svm = kzalloc(sizeof *vcpu->svm, GFP_KERNEL); - if (!vcpu->svm) - goto out1; page = alloc_page(GFP_KERNEL); - if (!page) - goto out2; - - vcpu->svm->vmcb = page_address(page); - clear_page(vcpu->svm->vmcb); - vcpu->svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT; - vcpu->svm->asid_generation = 0; - memset(vcpu->svm->db_regs, 0, sizeof(vcpu->svm->db_regs)); - init_vmcb(vcpu->svm->vmcb); - - fx_init(vcpu); - vcpu->fpu_active = 1; - vcpu->apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE; - if (vcpu == &vcpu->kvm->vcpus[0]) - vcpu->apic_base |= MSR_IA32_APICBASE_BSP; + if (!page) { + err = -ENOMEM; + goto uninit; + } - return 0; + svm->vmcb = page_address(page); + clear_page(svm->vmcb); + svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT; + svm->asid_generation = 0; + memset(svm->db_regs, 0, sizeof(svm->db_regs)); + init_vmcb(svm->vmcb); -out2: - kfree(vcpu->svm); -out1: - return r; + fx_init(&svm->vcpu); + svm->vcpu.fpu_active = 1; + svm->vcpu.apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE; + if (svm->vcpu.vcpu_id == 0) + svm->vcpu.apic_base |= MSR_IA32_APICBASE_BSP; + + return &svm->vcpu; + +uninit: + kvm_vcpu_uninit(&svm->vcpu); +free_svm: + kmem_cache_free(kvm_vcpu_cache, svm); +out: + return ERR_PTR(err); } static void svm_free_vcpu(struct kvm_vcpu *vcpu) { - if (!vcpu->svm) - return; - if (vcpu->svm->vmcb) - __free_page(pfn_to_page(vcpu->svm->vmcb_pa >> PAGE_SHIFT)); - kfree(vcpu->svm); + struct vcpu_svm *svm = to_svm(vcpu); + + __free_page(pfn_to_page(svm->vmcb_pa >> PAGE_SHIFT)); + kvm_vcpu_uninit(vcpu); + kmem_cache_free(kvm_vcpu_cache, svm); } -static void svm_vcpu_load(struct kvm_vcpu *vcpu) +static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu) { - int cpu, i; + struct vcpu_svm *svm = to_svm(vcpu); + int i; - cpu = get_cpu(); if (unlikely(cpu != vcpu->cpu)) { u64 tsc_this, delta; @@ -625,23 +637,24 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu) */ rdtscll(tsc_this); delta = vcpu->host_tsc - tsc_this; - vcpu->svm->vmcb->control.tsc_offset += delta; + svm->vmcb->control.tsc_offset += delta; vcpu->cpu = cpu; + kvm_migrate_apic_timer(vcpu); } for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++) - rdmsrl(host_save_user_msrs[i], vcpu->svm->host_user_msrs[i]); + rdmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]); } static void svm_vcpu_put(struct kvm_vcpu *vcpu) { + struct vcpu_svm *svm = to_svm(vcpu); int i; for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++) - wrmsrl(host_save_user_msrs[i], vcpu->svm->host_user_msrs[i]); + wrmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]); rdtscll(vcpu->host_tsc); - put_cpu(); } static void svm_vcpu_decache(struct kvm_vcpu *vcpu) @@ -650,31 +663,34 @@ static void svm_vcpu_decache(struct kvm_vcpu *vcpu) static void svm_cache_regs(struct kvm_vcpu *vcpu) { - vcpu->regs[VCPU_REGS_RAX] = vcpu->svm->vmcb->save.rax; - vcpu->regs[VCPU_REGS_RSP] = vcpu->svm->vmcb->save.rsp; - vcpu->rip = vcpu->svm->vmcb->save.rip; + struct vcpu_svm *svm = to_svm(vcpu); + + vcpu->regs[VCPU_REGS_RAX] = svm->vmcb->save.rax; + vcpu->regs[VCPU_REGS_RSP] = svm->vmcb->save.rsp; + vcpu->rip = svm->vmcb->save.rip; } static void svm_decache_regs(struct kvm_vcpu *vcpu) { - vcpu->svm->vmcb->save.rax = vcpu->regs[VCPU_REGS_RAX]; - vcpu->svm->vmcb->save.rsp = vcpu->regs[VCPU_REGS_RSP]; - vcpu->svm->vmcb->save.rip = vcpu->rip; + struct vcpu_svm *svm = to_svm(vcpu); + svm->vmcb->save.rax = vcpu->regs[VCPU_REGS_RAX]; + svm->vmcb->save.rsp = vcpu->regs[VCPU_REGS_RSP]; + svm->vmcb->save.rip = vcpu->rip; } static unsigned long svm_get_rflags(struct kvm_vcpu *vcpu) { - return vcpu->svm->vmcb->save.rflags; + return to_svm(vcpu)->vmcb->save.rflags; } static void svm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags) { - vcpu->svm->vmcb->save.rflags = rflags; + to_svm(vcpu)->vmcb->save.rflags = rflags; } static struct vmcb_seg *svm_seg(struct kvm_vcpu *vcpu, int seg) { - struct vmcb_save_area *save = &vcpu->svm->vmcb->save; + struct vmcb_save_area *save = &to_svm(vcpu)->vmcb->save; switch (seg) { case VCPU_SREG_CS: return &save->cs; @@ -716,36 +732,36 @@ static void svm_get_segment(struct kvm_vcpu *vcpu, var->unusable = !var->present; } -static void svm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l) -{ - struct vmcb_seg *s = svm_seg(vcpu, VCPU_SREG_CS); - - *db = (s->attrib >> SVM_SELECTOR_DB_SHIFT) & 1; - *l = (s->attrib >> SVM_SELECTOR_L_SHIFT) & 1; -} - static void svm_get_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) { - dt->limit = vcpu->svm->vmcb->save.idtr.limit; - dt->base = vcpu->svm->vmcb->save.idtr.base; + struct vcpu_svm *svm = to_svm(vcpu); + + dt->limit = svm->vmcb->save.idtr.limit; + dt->base = svm->vmcb->save.idtr.base; } static void svm_set_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) { - vcpu->svm->vmcb->save.idtr.limit = dt->limit; - vcpu->svm->vmcb->save.idtr.base = dt->base ; + struct vcpu_svm *svm = to_svm(vcpu); + + svm->vmcb->save.idtr.limit = dt->limit; + svm->vmcb->save.idtr.base = dt->base ; } static void svm_get_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) { - dt->limit = vcpu->svm->vmcb->save.gdtr.limit; - dt->base = vcpu->svm->vmcb->save.gdtr.base; + struct vcpu_svm *svm = to_svm(vcpu); + + dt->limit = svm->vmcb->save.gdtr.limit; + dt->base = svm->vmcb->save.gdtr.base; } static void svm_set_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) { - vcpu->svm->vmcb->save.gdtr.limit = dt->limit; - vcpu->svm->vmcb->save.gdtr.base = dt->base ; + struct vcpu_svm *svm = to_svm(vcpu); + + svm->vmcb->save.gdtr.limit = dt->limit; + svm->vmcb->save.gdtr.base = dt->base ; } static void svm_decache_cr4_guest_bits(struct kvm_vcpu *vcpu) @@ -754,39 +770,42 @@ static void svm_decache_cr4_guest_bits(struct kvm_vcpu *vcpu) static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) { + struct vcpu_svm *svm = to_svm(vcpu); + #ifdef CONFIG_X86_64 if (vcpu->shadow_efer & KVM_EFER_LME) { - if (!is_paging(vcpu) && (cr0 & CR0_PG_MASK)) { + if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) { vcpu->shadow_efer |= KVM_EFER_LMA; - vcpu->svm->vmcb->save.efer |= KVM_EFER_LMA | KVM_EFER_LME; + svm->vmcb->save.efer |= KVM_EFER_LMA | KVM_EFER_LME; } - if (is_paging(vcpu) && !(cr0 & CR0_PG_MASK) ) { + if (is_paging(vcpu) && !(cr0 & X86_CR0_PG) ) { vcpu->shadow_efer &= ~KVM_EFER_LMA; - vcpu->svm->vmcb->save.efer &= ~(KVM_EFER_LMA | KVM_EFER_LME); + svm->vmcb->save.efer &= ~(KVM_EFER_LMA | KVM_EFER_LME); } } #endif - if ((vcpu->cr0 & CR0_TS_MASK) && !(cr0 & CR0_TS_MASK)) { - vcpu->svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR); + if ((vcpu->cr0 & X86_CR0_TS) && !(cr0 & X86_CR0_TS)) { + svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR); vcpu->fpu_active = 1; } vcpu->cr0 = cr0; - cr0 |= CR0_PG_MASK | CR0_WP_MASK; - cr0 &= ~(CR0_CD_MASK | CR0_NW_MASK); - vcpu->svm->vmcb->save.cr0 = cr0; + cr0 |= X86_CR0_PG | X86_CR0_WP; + cr0 &= ~(X86_CR0_CD | X86_CR0_NW); + svm->vmcb->save.cr0 = cr0; } static void svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) { vcpu->cr4 = cr4; - vcpu->svm->vmcb->save.cr4 = cr4 | CR4_PAE_MASK; + to_svm(vcpu)->vmcb->save.cr4 = cr4 | X86_CR4_PAE; } static void svm_set_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg) { + struct vcpu_svm *svm = to_svm(vcpu); struct vmcb_seg *s = svm_seg(vcpu, seg); s->base = var->base; @@ -805,16 +824,16 @@ static void svm_set_segment(struct kvm_vcpu *vcpu, s->attrib |= (var->g & 1) << SVM_SELECTOR_G_SHIFT; } if (seg == VCPU_SREG_CS) - vcpu->svm->vmcb->save.cpl - = (vcpu->svm->vmcb->save.cs.attrib + svm->vmcb->save.cpl + = (svm->vmcb->save.cs.attrib >> SVM_SELECTOR_DPL_SHIFT) & 3; } /* FIXME: - vcpu->svm->vmcb->control.int_ctl &= ~V_TPR_MASK; - vcpu->svm->vmcb->control.int_ctl |= (sregs->cr8 & V_TPR_MASK); + svm(vcpu)->vmcb->control.int_ctl &= ~V_TPR_MASK; + svm(vcpu)->vmcb->control.int_ctl |= (sregs->cr8 & V_TPR_MASK); */ @@ -823,61 +842,68 @@ static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg) return -EOPNOTSUPP; } +static int svm_get_irq(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + u32 exit_int_info = svm->vmcb->control.exit_int_info; + + if (is_external_interrupt(exit_int_info)) + return exit_int_info & SVM_EVTINJ_VEC_MASK; + return -1; +} + static void load_host_msrs(struct kvm_vcpu *vcpu) { #ifdef CONFIG_X86_64 - wrmsrl(MSR_GS_BASE, vcpu->svm->host_gs_base); + wrmsrl(MSR_GS_BASE, to_svm(vcpu)->host_gs_base); #endif } static void save_host_msrs(struct kvm_vcpu *vcpu) { #ifdef CONFIG_X86_64 - rdmsrl(MSR_GS_BASE, vcpu->svm->host_gs_base); + rdmsrl(MSR_GS_BASE, to_svm(vcpu)->host_gs_base); #endif } -static void new_asid(struct kvm_vcpu *vcpu, struct svm_cpu_data *svm_data) +static void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *svm_data) { if (svm_data->next_asid > svm_data->max_asid) { ++svm_data->asid_generation; svm_data->next_asid = 1; - vcpu->svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ALL_ASID; + svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ALL_ASID; } - vcpu->cpu = svm_data->cpu; - vcpu->svm->asid_generation = svm_data->asid_generation; - vcpu->svm->vmcb->control.asid = svm_data->next_asid++; -} - -static void svm_invlpg(struct kvm_vcpu *vcpu, gva_t address) -{ - invlpga(address, vcpu->svm->vmcb->control.asid); // is needed? + svm->vcpu.cpu = svm_data->cpu; + svm->asid_generation = svm_data->asid_generation; + svm->vmcb->control.asid = svm_data->next_asid++; } static unsigned long svm_get_dr(struct kvm_vcpu *vcpu, int dr) { - return vcpu->svm->db_regs[dr]; + return to_svm(vcpu)->db_regs[dr]; } static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value, int *exception) { + struct vcpu_svm *svm = to_svm(vcpu); + *exception = 0; - if (vcpu->svm->vmcb->save.dr7 & DR7_GD_MASK) { - vcpu->svm->vmcb->save.dr7 &= ~DR7_GD_MASK; - vcpu->svm->vmcb->save.dr6 |= DR6_BD_MASK; + if (svm->vmcb->save.dr7 & DR7_GD_MASK) { + svm->vmcb->save.dr7 &= ~DR7_GD_MASK; + svm->vmcb->save.dr6 |= DR6_BD_MASK; *exception = DB_VECTOR; return; } switch (dr) { case 0 ... 3: - vcpu->svm->db_regs[dr] = value; + svm->db_regs[dr] = value; return; case 4 ... 5: - if (vcpu->cr4 & CR4_DE_MASK) { + if (vcpu->cr4 & X86_CR4_DE) { *exception = UD_VECTOR; return; } @@ -886,7 +912,7 @@ static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value, *exception = GP_VECTOR; return; } - vcpu->svm->vmcb->save.dr7 = value; + svm->vmcb->save.dr7 = value; return; } default: @@ -897,42 +923,44 @@ static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value, } } -static int pf_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) { - u32 exit_int_info = vcpu->svm->vmcb->control.exit_int_info; + u32 exit_int_info = svm->vmcb->control.exit_int_info; + struct kvm *kvm = svm->vcpu.kvm; u64 fault_address; u32 error_code; enum emulation_result er; int r; - if (is_external_interrupt(exit_int_info)) - push_irq(vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK); + if (!irqchip_in_kernel(kvm) && + is_external_interrupt(exit_int_info)) + push_irq(&svm->vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK); - spin_lock(&vcpu->kvm->lock); + mutex_lock(&kvm->lock); - fault_address = vcpu->svm->vmcb->control.exit_info_2; - error_code = vcpu->svm->vmcb->control.exit_info_1; - r = kvm_mmu_page_fault(vcpu, fault_address, error_code); + fault_address = svm->vmcb->control.exit_info_2; + error_code = svm->vmcb->control.exit_info_1; + r = kvm_mmu_page_fault(&svm->vcpu, fault_address, error_code); if (r < 0) { - spin_unlock(&vcpu->kvm->lock); + mutex_unlock(&kvm->lock); return r; } if (!r) { - spin_unlock(&vcpu->kvm->lock); + mutex_unlock(&kvm->lock); return 1; } - er = emulate_instruction(vcpu, kvm_run, fault_address, error_code); - spin_unlock(&vcpu->kvm->lock); + er = emulate_instruction(&svm->vcpu, kvm_run, fault_address, + error_code); + mutex_unlock(&kvm->lock); switch (er) { case EMULATE_DONE: return 1; case EMULATE_DO_MMIO: - ++vcpu->stat.mmio_exits; - kvm_run->exit_reason = KVM_EXIT_MMIO; + ++svm->vcpu.stat.mmio_exits; return 0; case EMULATE_FAIL: - vcpu_printf(vcpu, "%s: emulate fail\n", __FUNCTION__); + kvm_report_emulation_failure(&svm->vcpu, "pagetable"); break; default: BUG(); @@ -942,252 +970,142 @@ static int pf_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) return 0; } -static int nm_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static int nm_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) { - vcpu->svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR); - if (!(vcpu->cr0 & CR0_TS_MASK)) - vcpu->svm->vmcb->save.cr0 &= ~CR0_TS_MASK; - vcpu->fpu_active = 1; + svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR); + if (!(svm->vcpu.cr0 & X86_CR0_TS)) + svm->vmcb->save.cr0 &= ~X86_CR0_TS; + svm->vcpu.fpu_active = 1; - return 1; + return 1; } -static int shutdown_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static int shutdown_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) { /* * VMCB is undefined after a SHUTDOWN intercept * so reinitialize it. */ - clear_page(vcpu->svm->vmcb); - init_vmcb(vcpu->svm->vmcb); + clear_page(svm->vmcb); + init_vmcb(svm->vmcb); kvm_run->exit_reason = KVM_EXIT_SHUTDOWN; return 0; } -static int io_get_override(struct kvm_vcpu *vcpu, - struct vmcb_seg **seg, - int *addr_override) -{ - u8 inst[MAX_INST_SIZE]; - unsigned ins_length; - gva_t rip; - int i; - - rip = vcpu->svm->vmcb->save.rip; - ins_length = vcpu->svm->next_rip - rip; - rip += vcpu->svm->vmcb->save.cs.base; - - if (ins_length > MAX_INST_SIZE) - printk(KERN_DEBUG - "%s: inst length err, cs base 0x%llx rip 0x%llx " - "next rip 0x%llx ins_length %u\n", - __FUNCTION__, - vcpu->svm->vmcb->save.cs.base, - vcpu->svm->vmcb->save.rip, - vcpu->svm->vmcb->control.exit_info_2, - ins_length); - - if (kvm_read_guest(vcpu, rip, ins_length, inst) != ins_length) - /* #PF */ - return 0; - - *addr_override = 0; - *seg = NULL; - for (i = 0; i < ins_length; i++) - switch (inst[i]) { - case 0xf0: - case 0xf2: - case 0xf3: - case 0x66: - continue; - case 0x67: - *addr_override = 1; - continue; - case 0x2e: - *seg = &vcpu->svm->vmcb->save.cs; - continue; - case 0x36: - *seg = &vcpu->svm->vmcb->save.ss; - continue; - case 0x3e: - *seg = &vcpu->svm->vmcb->save.ds; - continue; - case 0x26: - *seg = &vcpu->svm->vmcb->save.es; - continue; - case 0x64: - *seg = &vcpu->svm->vmcb->save.fs; - continue; - case 0x65: - *seg = &vcpu->svm->vmcb->save.gs; - continue; - default: - return 1; - } - printk(KERN_DEBUG "%s: unexpected\n", __FUNCTION__); - return 0; -} - -static unsigned long io_adress(struct kvm_vcpu *vcpu, int ins, gva_t *address) +static int io_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) { - unsigned long addr_mask; - unsigned long *reg; - struct vmcb_seg *seg; - int addr_override; - struct vmcb_save_area *save_area = &vcpu->svm->vmcb->save; - u16 cs_attrib = save_area->cs.attrib; - unsigned addr_size = get_addr_size(vcpu); - - if (!io_get_override(vcpu, &seg, &addr_override)) - return 0; - - if (addr_override) - addr_size = (addr_size == 2) ? 4: (addr_size >> 1); + u32 io_info = svm->vmcb->control.exit_info_1; //address size bug? + int size, down, in, string, rep; + unsigned port; - if (ins) { - reg = &vcpu->regs[VCPU_REGS_RDI]; - seg = &vcpu->svm->vmcb->save.es; - } else { - reg = &vcpu->regs[VCPU_REGS_RSI]; - seg = (seg) ? seg : &vcpu->svm->vmcb->save.ds; - } + ++svm->vcpu.stat.io_exits; - addr_mask = ~0ULL >> (64 - (addr_size * 8)); + svm->next_rip = svm->vmcb->control.exit_info_2; - if ((cs_attrib & SVM_SELECTOR_L_MASK) && - !(vcpu->svm->vmcb->save.rflags & X86_EFLAGS_VM)) { - *address = (*reg & addr_mask); - return addr_mask; - } + string = (io_info & SVM_IOIO_STR_MASK) != 0; - if (!(seg->attrib & SVM_SELECTOR_P_SHIFT)) { - svm_inject_gp(vcpu, 0); - return 0; + if (string) { + if (emulate_instruction(&svm->vcpu, kvm_run, 0, 0) == EMULATE_DO_MMIO) + return 0; + return 1; } - *address = (*reg & addr_mask) + seg->base; - return addr_mask; -} - -static int io_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) -{ - u32 io_info = vcpu->svm->vmcb->control.exit_info_1; //address size bug? - int size, down, in, string, rep; - unsigned port; - unsigned long count; - gva_t address = 0; - - ++vcpu->stat.io_exits; - - vcpu->svm->next_rip = vcpu->svm->vmcb->control.exit_info_2; - in = (io_info & SVM_IOIO_TYPE_MASK) != 0; port = io_info >> 16; size = (io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT; - string = (io_info & SVM_IOIO_STR_MASK) != 0; rep = (io_info & SVM_IOIO_REP_MASK) != 0; - count = 1; - down = (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_DF) != 0; + down = (svm->vmcb->save.rflags & X86_EFLAGS_DF) != 0; - if (string) { - unsigned addr_mask; - - addr_mask = io_adress(vcpu, in, &address); - if (!addr_mask) { - printk(KERN_DEBUG "%s: get io address failed\n", - __FUNCTION__); - return 1; - } - - if (rep) - count = vcpu->regs[VCPU_REGS_RCX] & addr_mask; - } - return kvm_setup_pio(vcpu, kvm_run, in, size, count, string, down, - address, rep, port); + return kvm_emulate_pio(&svm->vcpu, kvm_run, in, size, port); } -static int nop_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static int nop_on_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) { return 1; } -static int halt_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static int halt_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) { - vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 1; - skip_emulated_instruction(vcpu); - return kvm_emulate_halt(vcpu); + svm->next_rip = svm->vmcb->save.rip + 1; + skip_emulated_instruction(&svm->vcpu); + return kvm_emulate_halt(&svm->vcpu); } -static int vmmcall_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static int vmmcall_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) { - vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 3; - skip_emulated_instruction(vcpu); - return kvm_hypercall(vcpu, kvm_run); + svm->next_rip = svm->vmcb->save.rip + 3; + skip_emulated_instruction(&svm->vcpu); + return kvm_hypercall(&svm->vcpu, kvm_run); } -static int invalid_op_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static int invalid_op_interception(struct vcpu_svm *svm, + struct kvm_run *kvm_run) { - inject_ud(vcpu); + inject_ud(&svm->vcpu); return 1; } -static int task_switch_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static int task_switch_interception(struct vcpu_svm *svm, + struct kvm_run *kvm_run) { - printk(KERN_DEBUG "%s: task swiche is unsupported\n", __FUNCTION__); + pr_unimpl(&svm->vcpu, "%s: task switch is unsupported\n", __FUNCTION__); kvm_run->exit_reason = KVM_EXIT_UNKNOWN; return 0; } -static int cpuid_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static int cpuid_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) { - vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2; - kvm_emulate_cpuid(vcpu); + svm->next_rip = svm->vmcb->save.rip + 2; + kvm_emulate_cpuid(&svm->vcpu); return 1; } -static int emulate_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static int emulate_on_interception(struct vcpu_svm *svm, + struct kvm_run *kvm_run) { - if (emulate_instruction(vcpu, NULL, 0, 0) != EMULATE_DONE) - printk(KERN_ERR "%s: failed\n", __FUNCTION__); + if (emulate_instruction(&svm->vcpu, NULL, 0, 0) != EMULATE_DONE) + pr_unimpl(&svm->vcpu, "%s: failed\n", __FUNCTION__); return 1; } static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data) { + struct vcpu_svm *svm = to_svm(vcpu); + switch (ecx) { case MSR_IA32_TIME_STAMP_COUNTER: { u64 tsc; rdtscll(tsc); - *data = vcpu->svm->vmcb->control.tsc_offset + tsc; + *data = svm->vmcb->control.tsc_offset + tsc; break; } case MSR_K6_STAR: - *data = vcpu->svm->vmcb->save.star; + *data = svm->vmcb->save.star; break; #ifdef CONFIG_X86_64 case MSR_LSTAR: - *data = vcpu->svm->vmcb->save.lstar; + *data = svm->vmcb->save.lstar; break; case MSR_CSTAR: - *data = vcpu->svm->vmcb->save.cstar; + *data = svm->vmcb->save.cstar; break; case MSR_KERNEL_GS_BASE: - *data = vcpu->svm->vmcb->save.kernel_gs_base; + *data = svm->vmcb->save.kernel_gs_base; break; case MSR_SYSCALL_MASK: - *data = vcpu->svm->vmcb->save.sfmask; + *data = svm->vmcb->save.sfmask; break; #endif case MSR_IA32_SYSENTER_CS: - *data = vcpu->svm->vmcb->save.sysenter_cs; + *data = svm->vmcb->save.sysenter_cs; break; case MSR_IA32_SYSENTER_EIP: - *data = vcpu->svm->vmcb->save.sysenter_eip; + *data = svm->vmcb->save.sysenter_eip; break; case MSR_IA32_SYSENTER_ESP: - *data = vcpu->svm->vmcb->save.sysenter_esp; + *data = svm->vmcb->save.sysenter_esp; break; default: return kvm_get_msr_common(vcpu, ecx, data); @@ -1195,57 +1113,59 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data) return 0; } -static int rdmsr_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static int rdmsr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) { - u32 ecx = vcpu->regs[VCPU_REGS_RCX]; + u32 ecx = svm->vcpu.regs[VCPU_REGS_RCX]; u64 data; - if (svm_get_msr(vcpu, ecx, &data)) - svm_inject_gp(vcpu, 0); + if (svm_get_msr(&svm->vcpu, ecx, &data)) + svm_inject_gp(&svm->vcpu, 0); else { - vcpu->svm->vmcb->save.rax = data & 0xffffffff; - vcpu->regs[VCPU_REGS_RDX] = data >> 32; - vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2; - skip_emulated_instruction(vcpu); + svm->vmcb->save.rax = data & 0xffffffff; + svm->vcpu.regs[VCPU_REGS_RDX] = data >> 32; + svm->next_rip = svm->vmcb->save.rip + 2; + skip_emulated_instruction(&svm->vcpu); } return 1; } static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data) { + struct vcpu_svm *svm = to_svm(vcpu); + switch (ecx) { case MSR_IA32_TIME_STAMP_COUNTER: { u64 tsc; rdtscll(tsc); - vcpu->svm->vmcb->control.tsc_offset = data - tsc; + svm->vmcb->control.tsc_offset = data - tsc; break; } case MSR_K6_STAR: - vcpu->svm->vmcb->save.star = data; + svm->vmcb->save.star = data; break; #ifdef CONFIG_X86_64 case MSR_LSTAR: - vcpu->svm->vmcb->save.lstar = data; + svm->vmcb->save.lstar = data; break; case MSR_CSTAR: - vcpu->svm->vmcb->save.cstar = data; + svm->vmcb->save.cstar = data; break; case MSR_KERNEL_GS_BASE: - vcpu->svm->vmcb->save.kernel_gs_base = data; + svm->vmcb->save.kernel_gs_base = data; break; case MSR_SYSCALL_MASK: - vcpu->svm->vmcb->save.sfmask = data; + svm->vmcb->save.sfmask = data; break; #endif case MSR_IA32_SYSENTER_CS: - vcpu->svm->vmcb->save.sysenter_cs = data; + svm->vmcb->save.sysenter_cs = data; break; case MSR_IA32_SYSENTER_EIP: - vcpu->svm->vmcb->save.sysenter_eip = data; + svm->vmcb->save.sysenter_eip = data; break; case MSR_IA32_SYSENTER_ESP: - vcpu->svm->vmcb->save.sysenter_esp = data; + svm->vmcb->save.sysenter_esp = data; break; default: return kvm_set_msr_common(vcpu, ecx, data); @@ -1253,37 +1173,39 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data) return 0; } -static int wrmsr_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static int wrmsr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) { - u32 ecx = vcpu->regs[VCPU_REGS_RCX]; - u64 data = (vcpu->svm->vmcb->save.rax & -1u) - | ((u64)(vcpu->regs[VCPU_REGS_RDX] & -1u) << 32); - vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2; - if (svm_set_msr(vcpu, ecx, data)) - svm_inject_gp(vcpu, 0); + u32 ecx = svm->vcpu.regs[VCPU_REGS_RCX]; + u64 data = (svm->vmcb->save.rax & -1u) + | ((u64)(svm->vcpu.regs[VCPU_REGS_RDX] & -1u) << 32); + svm->next_rip = svm->vmcb->save.rip + 2; + if (svm_set_msr(&svm->vcpu, ecx, data)) + svm_inject_gp(&svm->vcpu, 0); else - skip_emulated_instruction(vcpu); + skip_emulated_instruction(&svm->vcpu); return 1; } -static int msr_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static int msr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) { - if (vcpu->svm->vmcb->control.exit_info_1) - return wrmsr_interception(vcpu, kvm_run); + if (svm->vmcb->control.exit_info_1) + return wrmsr_interception(svm, kvm_run); else - return rdmsr_interception(vcpu, kvm_run); + return rdmsr_interception(svm, kvm_run); } -static int interrupt_window_interception(struct kvm_vcpu *vcpu, +static int interrupt_window_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) { + svm->vmcb->control.intercept &= ~(1ULL << INTERCEPT_VINTR); + svm->vmcb->control.int_ctl &= ~V_IRQ_MASK; /* * If the user space waits to inject interrupts, exit as soon as * possible */ if (kvm_run->request_interrupt_window && - !vcpu->irq_summary) { - ++vcpu->stat.irq_window_exits; + !svm->vcpu.irq_summary) { + ++svm->vcpu.stat.irq_window_exits; kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN; return 0; } @@ -1291,7 +1213,7 @@ static int interrupt_window_interception(struct kvm_vcpu *vcpu, return 1; } -static int (*svm_exit_handlers[])(struct kvm_vcpu *vcpu, +static int (*svm_exit_handlers[])(struct vcpu_svm *svm, struct kvm_run *kvm_run) = { [SVM_EXIT_READ_CR0] = emulate_on_interception, [SVM_EXIT_READ_CR3] = emulate_on_interception, @@ -1338,15 +1260,25 @@ static int (*svm_exit_handlers[])(struct kvm_vcpu *vcpu, }; -static int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static int handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) { - u32 exit_code = vcpu->svm->vmcb->control.exit_code; + struct vcpu_svm *svm = to_svm(vcpu); + u32 exit_code = svm->vmcb->control.exit_code; + + kvm_reput_irq(svm); - if (is_external_interrupt(vcpu->svm->vmcb->control.exit_int_info) && + if (svm->vmcb->control.exit_code == SVM_EXIT_ERR) { + kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY; + kvm_run->fail_entry.hardware_entry_failure_reason + = svm->vmcb->control.exit_code; + return 0; + } + + if (is_external_interrupt(svm->vmcb->control.exit_int_info) && exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR) printk(KERN_ERR "%s: unexpected exit_ini_info 0x%x " "exit_code 0x%x\n", - __FUNCTION__, vcpu->svm->vmcb->control.exit_int_info, + __FUNCTION__, svm->vmcb->control.exit_int_info, exit_code); if (exit_code >= ARRAY_SIZE(svm_exit_handlers) @@ -1356,7 +1288,7 @@ static int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) return 0; } - return svm_exit_handlers[exit_code](vcpu, kvm_run); + return svm_exit_handlers[exit_code](svm, kvm_run); } static void reload_tss(struct kvm_vcpu *vcpu) @@ -1368,93 +1300,126 @@ static void reload_tss(struct kvm_vcpu *vcpu) load_TR_desc(); } -static void pre_svm_run(struct kvm_vcpu *vcpu) +static void pre_svm_run(struct vcpu_svm *svm) { int cpu = raw_smp_processor_id(); struct svm_cpu_data *svm_data = per_cpu(svm_data, cpu); - vcpu->svm->vmcb->control.tlb_ctl = TLB_CONTROL_DO_NOTHING; - if (vcpu->cpu != cpu || - vcpu->svm->asid_generation != svm_data->asid_generation) - new_asid(vcpu, svm_data); + svm->vmcb->control.tlb_ctl = TLB_CONTROL_DO_NOTHING; + if (svm->vcpu.cpu != cpu || + svm->asid_generation != svm_data->asid_generation) + new_asid(svm, svm_data); } -static inline void kvm_do_inject_irq(struct kvm_vcpu *vcpu) +static inline void svm_inject_irq(struct vcpu_svm *svm, int irq) { struct vmcb_control_area *control; - control = &vcpu->svm->vmcb->control; - control->int_vector = pop_irq(vcpu); + control = &svm->vmcb->control; + control->int_vector = irq; control->int_ctl &= ~V_INTR_PRIO_MASK; control->int_ctl |= V_IRQ_MASK | ((/*control->int_vector >> 4*/ 0xf) << V_INTR_PRIO_SHIFT); } -static void kvm_reput_irq(struct kvm_vcpu *vcpu) +static void svm_set_irq(struct kvm_vcpu *vcpu, int irq) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + svm_inject_irq(svm, irq); +} + +static void svm_intr_assist(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + struct vmcb *vmcb = svm->vmcb; + int intr_vector = -1; + + kvm_inject_pending_timer_irqs(vcpu); + if ((vmcb->control.exit_int_info & SVM_EVTINJ_VALID) && + ((vmcb->control.exit_int_info & SVM_EVTINJ_TYPE_MASK) == 0)) { + intr_vector = vmcb->control.exit_int_info & + SVM_EVTINJ_VEC_MASK; + vmcb->control.exit_int_info = 0; + svm_inject_irq(svm, intr_vector); + return; + } + + if (vmcb->control.int_ctl & V_IRQ_MASK) + return; + + if (!kvm_cpu_has_interrupt(vcpu)) + return; + + if (!(vmcb->save.rflags & X86_EFLAGS_IF) || + (vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) || + (vmcb->control.event_inj & SVM_EVTINJ_VALID)) { + /* unable to deliver irq, set pending irq */ + vmcb->control.intercept |= (1ULL << INTERCEPT_VINTR); + svm_inject_irq(svm, 0x0); + return; + } + /* Okay, we can deliver the interrupt: grab it and update PIC state. */ + intr_vector = kvm_cpu_get_interrupt(vcpu); + svm_inject_irq(svm, intr_vector); + kvm_timer_intr_post(vcpu, intr_vector); +} + +static void kvm_reput_irq(struct vcpu_svm *svm) { - struct vmcb_control_area *control = &vcpu->svm->vmcb->control; + struct vmcb_control_area *control = &svm->vmcb->control; - if (control->int_ctl & V_IRQ_MASK) { + if ((control->int_ctl & V_IRQ_MASK) + && !irqchip_in_kernel(svm->vcpu.kvm)) { control->int_ctl &= ~V_IRQ_MASK; - push_irq(vcpu, control->int_vector); + push_irq(&svm->vcpu, control->int_vector); } - vcpu->interrupt_window_open = + svm->vcpu.interrupt_window_open = !(control->int_state & SVM_INTERRUPT_SHADOW_MASK); } +static void svm_do_inject_vector(struct vcpu_svm *svm) +{ + struct kvm_vcpu *vcpu = &svm->vcpu; + int word_index = __ffs(vcpu->irq_summary); + int bit_index = __ffs(vcpu->irq_pending[word_index]); + int irq = word_index * BITS_PER_LONG + bit_index; + + clear_bit(bit_index, &vcpu->irq_pending[word_index]); + if (!vcpu->irq_pending[word_index]) + clear_bit(word_index, &vcpu->irq_summary); + svm_inject_irq(svm, irq); +} + static void do_interrupt_requests(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { - struct vmcb_control_area *control = &vcpu->svm->vmcb->control; + struct vcpu_svm *svm = to_svm(vcpu); + struct vmcb_control_area *control = &svm->vmcb->control; - vcpu->interrupt_window_open = + svm->vcpu.interrupt_window_open = (!(control->int_state & SVM_INTERRUPT_SHADOW_MASK) && - (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_IF)); + (svm->vmcb->save.rflags & X86_EFLAGS_IF)); - if (vcpu->interrupt_window_open && vcpu->irq_summary) + if (svm->vcpu.interrupt_window_open && svm->vcpu.irq_summary) /* * If interrupts enabled, and not blocked by sti or mov ss. Good. */ - kvm_do_inject_irq(vcpu); + svm_do_inject_vector(svm); /* * Interrupts blocked. Wait for unblock. */ - if (!vcpu->interrupt_window_open && - (vcpu->irq_summary || kvm_run->request_interrupt_window)) { + if (!svm->vcpu.interrupt_window_open && + (svm->vcpu.irq_summary || kvm_run->request_interrupt_window)) { control->intercept |= 1ULL << INTERCEPT_VINTR; } else control->intercept &= ~(1ULL << INTERCEPT_VINTR); } -static void post_kvm_run_save(struct kvm_vcpu *vcpu, - struct kvm_run *kvm_run) -{ - kvm_run->ready_for_interrupt_injection = (vcpu->interrupt_window_open && - vcpu->irq_summary == 0); - kvm_run->if_flag = (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_IF) != 0; - kvm_run->cr8 = vcpu->cr8; - kvm_run->apic_base = vcpu->apic_base; -} - -/* - * Check if userspace requested an interrupt window, and that the - * interrupt window is open. - * - * No need to exit to userspace if we already have an interrupt queued. - */ -static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu, - struct kvm_run *kvm_run) -{ - return (!vcpu->irq_summary && - kvm_run->request_interrupt_window && - vcpu->interrupt_window_open && - (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_IF)); -} - static void save_db_regs(unsigned long *db_regs) { asm volatile ("mov %%dr0, %0" : "=r"(db_regs[0])); @@ -1476,49 +1441,37 @@ static void svm_flush_tlb(struct kvm_vcpu *vcpu) force_new_asid(vcpu); } -static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static void svm_prepare_guest_switch(struct kvm_vcpu *vcpu) +{ +} + +static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { + struct vcpu_svm *svm = to_svm(vcpu); u16 fs_selector; u16 gs_selector; u16 ldt_selector; - int r; - -again: - r = kvm_mmu_reload(vcpu); - if (unlikely(r)) - return r; - - if (!vcpu->mmio_read_completed) - do_interrupt_requests(vcpu, kvm_run); - clgi(); - - vcpu->guest_mode = 1; - if (vcpu->requests) - if (test_and_clear_bit(KVM_TLB_FLUSH, &vcpu->requests)) - svm_flush_tlb(vcpu); - - pre_svm_run(vcpu); + pre_svm_run(svm); save_host_msrs(vcpu); fs_selector = read_fs(); gs_selector = read_gs(); ldt_selector = read_ldt(); - vcpu->svm->host_cr2 = kvm_read_cr2(); - vcpu->svm->host_dr6 = read_dr6(); - vcpu->svm->host_dr7 = read_dr7(); - vcpu->svm->vmcb->save.cr2 = vcpu->cr2; + svm->host_cr2 = kvm_read_cr2(); + svm->host_dr6 = read_dr6(); + svm->host_dr7 = read_dr7(); + svm->vmcb->save.cr2 = vcpu->cr2; - if (vcpu->svm->vmcb->save.dr7 & 0xff) { + if (svm->vmcb->save.dr7 & 0xff) { write_dr7(0); - save_db_regs(vcpu->svm->host_db_regs); - load_db_regs(vcpu->svm->db_regs); + save_db_regs(svm->host_db_regs); + load_db_regs(svm->db_regs); } - if (vcpu->fpu_active) { - fx_save(vcpu->host_fx_image); - fx_restore(vcpu->guest_fx_image); - } + clgi(); + + local_irq_enable(); asm volatile ( #ifdef CONFIG_X86_64 @@ -1532,34 +1485,33 @@ again: #endif #ifdef CONFIG_X86_64 - "mov %c[rbx](%[vcpu]), %%rbx \n\t" - "mov %c[rcx](%[vcpu]), %%rcx \n\t" - "mov %c[rdx](%[vcpu]), %%rdx \n\t" - "mov %c[rsi](%[vcpu]), %%rsi \n\t" - "mov %c[rdi](%[vcpu]), %%rdi \n\t" - "mov %c[rbp](%[vcpu]), %%rbp \n\t" - "mov %c[r8](%[vcpu]), %%r8 \n\t" - "mov %c[r9](%[vcpu]), %%r9 \n\t" - "mov %c[r10](%[vcpu]), %%r10 \n\t" - "mov %c[r11](%[vcpu]), %%r11 \n\t" - "mov %c[r12](%[vcpu]), %%r12 \n\t" - "mov %c[r13](%[vcpu]), %%r13 \n\t" - "mov %c[r14](%[vcpu]), %%r14 \n\t" - "mov %c[r15](%[vcpu]), %%r15 \n\t" + "mov %c[rbx](%[svm]), %%rbx \n\t" + "mov %c[rcx](%[svm]), %%rcx \n\t" + "mov %c[rdx](%[svm]), %%rdx \n\t" + "mov %c[rsi](%[svm]), %%rsi \n\t" + "mov %c[rdi](%[svm]), %%rdi \n\t" + "mov %c[rbp](%[svm]), %%rbp \n\t" + "mov %c[r8](%[svm]), %%r8 \n\t" + "mov %c[r9](%[svm]), %%r9 \n\t" + "mov %c[r10](%[svm]), %%r10 \n\t" + "mov %c[r11](%[svm]), %%r11 \n\t" + "mov %c[r12](%[svm]), %%r12 \n\t" + "mov %c[r13](%[svm]), %%r13 \n\t" + "mov %c[r14](%[svm]), %%r14 \n\t" + "mov %c[r15](%[svm]), %%r15 \n\t" #else - "mov %c[rbx](%[vcpu]), %%ebx \n\t" - "mov %c[rcx](%[vcpu]), %%ecx \n\t" - "mov %c[rdx](%[vcpu]), %%edx \n\t" - "mov %c[rsi](%[vcpu]), %%esi \n\t" - "mov %c[rdi](%[vcpu]), %%edi \n\t" - "mov %c[rbp](%[vcpu]), %%ebp \n\t" + "mov %c[rbx](%[svm]), %%ebx \n\t" + "mov %c[rcx](%[svm]), %%ecx \n\t" + "mov %c[rdx](%[svm]), %%edx \n\t" + "mov %c[rsi](%[svm]), %%esi \n\t" + "mov %c[rdi](%[svm]), %%edi \n\t" + "mov %c[rbp](%[svm]), %%ebp \n\t" #endif #ifdef CONFIG_X86_64 /* Enter guest mode */ "push %%rax \n\t" - "mov %c[svm](%[vcpu]), %%rax \n\t" - "mov %c[vmcb](%%rax), %%rax \n\t" + "mov %c[vmcb](%[svm]), %%rax \n\t" SVM_VMLOAD "\n\t" SVM_VMRUN "\n\t" SVM_VMSAVE "\n\t" @@ -1567,8 +1519,7 @@ again: #else /* Enter guest mode */ "push %%eax \n\t" - "mov %c[svm](%[vcpu]), %%eax \n\t" - "mov %c[vmcb](%%eax), %%eax \n\t" + "mov %c[vmcb](%[svm]), %%eax \n\t" SVM_VMLOAD "\n\t" SVM_VMRUN "\n\t" SVM_VMSAVE "\n\t" @@ -1577,73 +1528,69 @@ again: /* Save guest registers, load host registers */ #ifdef CONFIG_X86_64 - "mov %%rbx, %c[rbx](%[vcpu]) \n\t" - "mov %%rcx, %c[rcx](%[vcpu]) \n\t" - "mov %%rdx, %c[rdx](%[vcpu]) \n\t" - "mov %%rsi, %c[rsi](%[vcpu]) \n\t" - "mov %%rdi, %c[rdi](%[vcpu]) \n\t" - "mov %%rbp, %c[rbp](%[vcpu]) \n\t" - "mov %%r8, %c[r8](%[vcpu]) \n\t" - "mov %%r9, %c[r9](%[vcpu]) \n\t" - "mov %%r10, %c[r10](%[vcpu]) \n\t" - "mov %%r11, %c[r11](%[vcpu]) \n\t" - "mov %%r12, %c[r12](%[vcpu]) \n\t" - "mov %%r13, %c[r13](%[vcpu]) \n\t" - "mov %%r14, %c[r14](%[vcpu]) \n\t" - "mov %%r15, %c[r15](%[vcpu]) \n\t" + "mov %%rbx, %c[rbx](%[svm]) \n\t" + "mov %%rcx, %c[rcx](%[svm]) \n\t" + "mov %%rdx, %c[rdx](%[svm]) \n\t" + "mov %%rsi, %c[rsi](%[svm]) \n\t" + "mov %%rdi, %c[rdi](%[svm]) \n\t" + "mov %%rbp, %c[rbp](%[svm]) \n\t" + "mov %%r8, %c[r8](%[svm]) \n\t" + "mov %%r9, %c[r9](%[svm]) \n\t" + "mov %%r10, %c[r10](%[svm]) \n\t" + "mov %%r11, %c[r11](%[svm]) \n\t" + "mov %%r12, %c[r12](%[svm]) \n\t" + "mov %%r13, %c[r13](%[svm]) \n\t" + "mov %%r14, %c[r14](%[svm]) \n\t" + "mov %%r15, %c[r15](%[svm]) \n\t" "pop %%r15; pop %%r14; pop %%r13; pop %%r12;" "pop %%r11; pop %%r10; pop %%r9; pop %%r8;" "pop %%rbp; pop %%rdi; pop %%rsi;" "pop %%rdx; pop %%rcx; pop %%rbx; \n\t" #else - "mov %%ebx, %c[rbx](%[vcpu]) \n\t" - "mov %%ecx, %c[rcx](%[vcpu]) \n\t" - "mov %%edx, %c[rdx](%[vcpu]) \n\t" - "mov %%esi, %c[rsi](%[vcpu]) \n\t" - "mov %%edi, %c[rdi](%[vcpu]) \n\t" - "mov %%ebp, %c[rbp](%[vcpu]) \n\t" + "mov %%ebx, %c[rbx](%[svm]) \n\t" + "mov %%ecx, %c[rcx](%[svm]) \n\t" + "mov %%edx, %c[rdx](%[svm]) \n\t" + "mov %%esi, %c[rsi](%[svm]) \n\t" + "mov %%edi, %c[rdi](%[svm]) \n\t" + "mov %%ebp, %c[rbp](%[svm]) \n\t" "pop %%ebp; pop %%edi; pop %%esi;" "pop %%edx; pop %%ecx; pop %%ebx; \n\t" #endif : - : [vcpu]"a"(vcpu), - [svm]"i"(offsetof(struct kvm_vcpu, svm)), + : [svm]"a"(svm), [vmcb]"i"(offsetof(struct vcpu_svm, vmcb_pa)), - [rbx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBX])), - [rcx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RCX])), - [rdx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RDX])), - [rsi]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RSI])), - [rdi]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RDI])), - [rbp]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBP])) + [rbx]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RBX])), + [rcx]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RCX])), + [rdx]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RDX])), + [rsi]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RSI])), + [rdi]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RDI])), + [rbp]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RBP])) #ifdef CONFIG_X86_64 - ,[r8 ]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R8 ])), - [r9 ]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R9 ])), - [r10]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R10])), - [r11]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R11])), - [r12]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R12])), - [r13]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R13])), - [r14]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R14])), - [r15]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R15])) + ,[r8 ]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R8])), + [r9 ]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R9 ])), + [r10]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R10])), + [r11]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R11])), + [r12]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R12])), + [r13]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R13])), + [r14]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R14])), + [r15]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R15])) #endif : "cc", "memory" ); - vcpu->guest_mode = 0; + local_irq_disable(); - if (vcpu->fpu_active) { - fx_save(vcpu->guest_fx_image); - fx_restore(vcpu->host_fx_image); - } + stgi(); - if ((vcpu->svm->vmcb->save.dr7 & 0xff)) - load_db_regs(vcpu->svm->host_db_regs); + if ((svm->vmcb->save.dr7 & 0xff)) + load_db_regs(svm->host_db_regs); - vcpu->cr2 = vcpu->svm->vmcb->save.cr2; + vcpu->cr2 = svm->vmcb->save.cr2; - write_dr6(vcpu->svm->host_dr6); - write_dr7(vcpu->svm->host_dr7); - kvm_write_cr2(vcpu->svm->host_cr2); + write_dr6(svm->host_dr6); + write_dr7(svm->host_dr7); + kvm_write_cr2(svm->host_cr2); load_fs(fs_selector); load_gs(gs_selector); @@ -1652,57 +1599,19 @@ again: reload_tss(vcpu); - /* - * Profile KVM exit RIPs: - */ - if (unlikely(prof_on == KVM_PROFILING)) - profile_hit(KVM_PROFILING, - (void *)(unsigned long)vcpu->svm->vmcb->save.rip); - - stgi(); - - kvm_reput_irq(vcpu); - - vcpu->svm->next_rip = 0; - - if (vcpu->svm->vmcb->control.exit_code == SVM_EXIT_ERR) { - kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY; - kvm_run->fail_entry.hardware_entry_failure_reason - = vcpu->svm->vmcb->control.exit_code; - post_kvm_run_save(vcpu, kvm_run); - return 0; - } - - r = handle_exit(vcpu, kvm_run); - if (r > 0) { - if (signal_pending(current)) { - ++vcpu->stat.signal_exits; - post_kvm_run_save(vcpu, kvm_run); - kvm_run->exit_reason = KVM_EXIT_INTR; - return -EINTR; - } - - if (dm_request_for_irq_injection(vcpu, kvm_run)) { - ++vcpu->stat.request_irq_exits; - post_kvm_run_save(vcpu, kvm_run); - kvm_run->exit_reason = KVM_EXIT_INTR; - return -EINTR; - } - kvm_resched(vcpu); - goto again; - } - post_kvm_run_save(vcpu, kvm_run); - return r; + svm->next_rip = 0; } static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root) { - vcpu->svm->vmcb->save.cr3 = root; + struct vcpu_svm *svm = to_svm(vcpu); + + svm->vmcb->save.cr3 = root; force_new_asid(vcpu); if (vcpu->fpu_active) { - vcpu->svm->vmcb->control.intercept_exceptions |= (1 << NM_VECTOR); - vcpu->svm->vmcb->save.cr0 |= CR0_TS_MASK; + svm->vmcb->control.intercept_exceptions |= (1 << NM_VECTOR); + svm->vmcb->save.cr0 |= X86_CR0_TS; vcpu->fpu_active = 0; } } @@ -1711,26 +1620,27 @@ static void svm_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long addr, uint32_t err_code) { - uint32_t exit_int_info = vcpu->svm->vmcb->control.exit_int_info; + struct vcpu_svm *svm = to_svm(vcpu); + uint32_t exit_int_info = svm->vmcb->control.exit_int_info; ++vcpu->stat.pf_guest; if (is_page_fault(exit_int_info)) { - vcpu->svm->vmcb->control.event_inj_err = 0; - vcpu->svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | - SVM_EVTINJ_VALID_ERR | - SVM_EVTINJ_TYPE_EXEPT | - DF_VECTOR; + svm->vmcb->control.event_inj_err = 0; + svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | + SVM_EVTINJ_VALID_ERR | + SVM_EVTINJ_TYPE_EXEPT | + DF_VECTOR; return; } vcpu->cr2 = addr; - vcpu->svm->vmcb->save.cr2 = addr; - vcpu->svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | - SVM_EVTINJ_VALID_ERR | - SVM_EVTINJ_TYPE_EXEPT | - PF_VECTOR; - vcpu->svm->vmcb->control.event_inj_err = err_code; + svm->vmcb->save.cr2 = addr; + svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | + SVM_EVTINJ_VALID_ERR | + SVM_EVTINJ_TYPE_EXEPT | + PF_VECTOR; + svm->vmcb->control.event_inj_err = err_code; } @@ -1757,17 +1667,25 @@ svm_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall) hypercall[3] = 0xc3; } -static struct kvm_arch_ops svm_arch_ops = { +static void svm_check_processor_compat(void *rtn) +{ + *(int *)rtn = 0; +} + +static struct kvm_x86_ops svm_x86_ops = { .cpu_has_kvm_support = has_svm, .disabled_by_bios = is_disabled, .hardware_setup = svm_hardware_setup, .hardware_unsetup = svm_hardware_unsetup, + .check_processor_compatibility = svm_check_processor_compat, .hardware_enable = svm_hardware_enable, .hardware_disable = svm_hardware_disable, .vcpu_create = svm_create_vcpu, .vcpu_free = svm_free_vcpu, + .vcpu_reset = svm_vcpu_reset, + .prepare_guest_switch = svm_prepare_guest_switch, .vcpu_load = svm_vcpu_load, .vcpu_put = svm_vcpu_put, .vcpu_decache = svm_vcpu_decache, @@ -1778,7 +1696,7 @@ static struct kvm_arch_ops svm_arch_ops = { .get_segment_base = svm_get_segment_base, .get_segment = svm_get_segment, .set_segment = svm_set_segment, - .get_cs_db_l_bits = svm_get_cs_db_l_bits, + .get_cs_db_l_bits = kvm_get_cs_db_l_bits, .decache_cr4_guest_bits = svm_decache_cr4_guest_bits, .set_cr0 = svm_set_cr0, .set_cr3 = svm_set_cr3, @@ -1795,26 +1713,30 @@ static struct kvm_arch_ops svm_arch_ops = { .get_rflags = svm_get_rflags, .set_rflags = svm_set_rflags, - .invlpg = svm_invlpg, .tlb_flush = svm_flush_tlb, .inject_page_fault = svm_inject_page_fault, .inject_gp = svm_inject_gp, .run = svm_vcpu_run, + .handle_exit = handle_exit, .skip_emulated_instruction = skip_emulated_instruction, - .vcpu_setup = svm_vcpu_setup, .patch_hypercall = svm_patch_hypercall, + .get_irq = svm_get_irq, + .set_irq = svm_set_irq, + .inject_pending_irq = svm_intr_assist, + .inject_pending_vectors = do_interrupt_requests, }; static int __init svm_init(void) { - return kvm_init_arch(&svm_arch_ops, THIS_MODULE); + return kvm_init_x86(&svm_x86_ops, sizeof(struct vcpu_svm), + THIS_MODULE); } static void __exit svm_exit(void) { - kvm_exit_arch(); + kvm_exit_x86(); } module_init(svm_init) diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c index 80628f69916d..4f115a8e45ef 100644 --- a/drivers/kvm/vmx.c +++ b/drivers/kvm/vmx.c @@ -16,6 +16,8 @@ */ #include "kvm.h" +#include "x86_emulate.h" +#include "irq.h" #include "vmx.h" #include "segment_descriptor.h" @@ -23,7 +25,6 @@ #include <linux/kernel.h> #include <linux/mm.h> #include <linux/highmem.h> -#include <linux/profile.h> #include <linux/sched.h> #include <asm/io.h> @@ -32,6 +33,39 @@ MODULE_AUTHOR("Qumranet"); MODULE_LICENSE("GPL"); +struct vmcs { + u32 revision_id; + u32 abort; + char data[0]; +}; + +struct vcpu_vmx { + struct kvm_vcpu vcpu; + int launched; + u8 fail; + struct kvm_msr_entry *guest_msrs; + struct kvm_msr_entry *host_msrs; + int nmsrs; + int save_nmsrs; + int msr_offset_efer; +#ifdef CONFIG_X86_64 + int msr_offset_kernel_gs_base; +#endif + struct vmcs *vmcs; + struct { + int loaded; + u16 fs_sel, gs_sel, ldt_sel; + int gs_ldt_reload_needed; + int fs_reload_needed; + }host_state; + +}; + +static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu) +{ + return container_of(vcpu, struct vcpu_vmx, vcpu); +} + static int init_rmode_tss(struct kvm *kvm); static DEFINE_PER_CPU(struct vmcs *, vmxarea); @@ -40,18 +74,17 @@ static DEFINE_PER_CPU(struct vmcs *, current_vmcs); static struct page *vmx_io_bitmap_a; static struct page *vmx_io_bitmap_b; -#ifdef CONFIG_X86_64 -#define HOST_IS_64 1 -#else -#define HOST_IS_64 0 -#endif #define EFER_SAVE_RESTORE_BITS ((u64)EFER_SCE) -static struct vmcs_descriptor { +static struct vmcs_config { int size; int order; u32 revision_id; -} vmcs_descriptor; + u32 pin_based_exec_ctrl; + u32 cpu_based_exec_ctrl; + u32 vmexit_ctrl; + u32 vmentry_ctrl; +} vmcs_config; #define VMX_SEGMENT_FIELD(seg) \ [VCPU_SREG_##seg] = { \ @@ -89,16 +122,32 @@ static const u32 vmx_msr_index[] = { }; #define NR_VMX_MSR ARRAY_SIZE(vmx_msr_index) -static inline u64 msr_efer_save_restore_bits(struct vmx_msr_entry msr) +static void load_msrs(struct kvm_msr_entry *e, int n) +{ + int i; + + for (i = 0; i < n; ++i) + wrmsrl(e[i].index, e[i].data); +} + +static void save_msrs(struct kvm_msr_entry *e, int n) +{ + int i; + + for (i = 0; i < n; ++i) + rdmsrl(e[i].index, e[i].data); +} + +static inline u64 msr_efer_save_restore_bits(struct kvm_msr_entry msr) { return (u64)msr.data & EFER_SAVE_RESTORE_BITS; } -static inline int msr_efer_need_save_restore(struct kvm_vcpu *vcpu) +static inline int msr_efer_need_save_restore(struct vcpu_vmx *vmx) { - int efer_offset = vcpu->msr_offset_efer; - return msr_efer_save_restore_bits(vcpu->host_msrs[efer_offset]) != - msr_efer_save_restore_bits(vcpu->guest_msrs[efer_offset]); + int efer_offset = vmx->msr_offset_efer; + return msr_efer_save_restore_bits(vmx->host_msrs[efer_offset]) != + msr_efer_save_restore_bits(vmx->guest_msrs[efer_offset]); } static inline int is_page_fault(u32 intr_info) @@ -121,23 +170,33 @@ static inline int is_external_interrupt(u32 intr_info) == (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK); } -static int __find_msr_index(struct kvm_vcpu *vcpu, u32 msr) +static inline int cpu_has_vmx_tpr_shadow(void) +{ + return (vmcs_config.cpu_based_exec_ctrl & CPU_BASED_TPR_SHADOW); +} + +static inline int vm_need_tpr_shadow(struct kvm *kvm) +{ + return ((cpu_has_vmx_tpr_shadow()) && (irqchip_in_kernel(kvm))); +} + +static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr) { int i; - for (i = 0; i < vcpu->nmsrs; ++i) - if (vcpu->guest_msrs[i].index == msr) + for (i = 0; i < vmx->nmsrs; ++i) + if (vmx->guest_msrs[i].index == msr) return i; return -1; } -static struct vmx_msr_entry *find_msr_entry(struct kvm_vcpu *vcpu, u32 msr) +static struct kvm_msr_entry *find_msr_entry(struct vcpu_vmx *vmx, u32 msr) { int i; - i = __find_msr_index(vcpu, msr); + i = __find_msr_index(vmx, msr); if (i >= 0) - return &vcpu->guest_msrs[i]; + return &vmx->guest_msrs[i]; return NULL; } @@ -156,23 +215,24 @@ static void vmcs_clear(struct vmcs *vmcs) static void __vcpu_clear(void *arg) { - struct kvm_vcpu *vcpu = arg; + struct vcpu_vmx *vmx = arg; int cpu = raw_smp_processor_id(); - if (vcpu->cpu == cpu) - vmcs_clear(vcpu->vmcs); - if (per_cpu(current_vmcs, cpu) == vcpu->vmcs) + if (vmx->vcpu.cpu == cpu) + vmcs_clear(vmx->vmcs); + if (per_cpu(current_vmcs, cpu) == vmx->vmcs) per_cpu(current_vmcs, cpu) = NULL; - rdtscll(vcpu->host_tsc); + rdtscll(vmx->vcpu.host_tsc); } -static void vcpu_clear(struct kvm_vcpu *vcpu) +static void vcpu_clear(struct vcpu_vmx *vmx) { - if (vcpu->cpu != raw_smp_processor_id() && vcpu->cpu != -1) - smp_call_function_single(vcpu->cpu, __vcpu_clear, vcpu, 0, 1); + if (vmx->vcpu.cpu != raw_smp_processor_id() && vmx->vcpu.cpu != -1) + smp_call_function_single(vmx->vcpu.cpu, __vcpu_clear, + vmx, 0, 1); else - __vcpu_clear(vcpu); - vcpu->launched = 0; + __vcpu_clear(vmx); + vmx->launched = 0; } static unsigned long vmcs_readl(unsigned long field) @@ -282,121 +342,122 @@ static void reload_tss(void) #endif } -static void load_transition_efer(struct kvm_vcpu *vcpu) +static void load_transition_efer(struct vcpu_vmx *vmx) { u64 trans_efer; - int efer_offset = vcpu->msr_offset_efer; + int efer_offset = vmx->msr_offset_efer; - trans_efer = vcpu->host_msrs[efer_offset].data; + trans_efer = vmx->host_msrs[efer_offset].data; trans_efer &= ~EFER_SAVE_RESTORE_BITS; - trans_efer |= msr_efer_save_restore_bits( - vcpu->guest_msrs[efer_offset]); + trans_efer |= msr_efer_save_restore_bits(vmx->guest_msrs[efer_offset]); wrmsrl(MSR_EFER, trans_efer); - vcpu->stat.efer_reload++; + vmx->vcpu.stat.efer_reload++; } static void vmx_save_host_state(struct kvm_vcpu *vcpu) { - struct vmx_host_state *hs = &vcpu->vmx_host_state; + struct vcpu_vmx *vmx = to_vmx(vcpu); - if (hs->loaded) + if (vmx->host_state.loaded) return; - hs->loaded = 1; + vmx->host_state.loaded = 1; /* * Set host fs and gs selectors. Unfortunately, 22.2.3 does not * allow segment selectors with cpl > 0 or ti == 1. */ - hs->ldt_sel = read_ldt(); - hs->fs_gs_ldt_reload_needed = hs->ldt_sel; - hs->fs_sel = read_fs(); - if (!(hs->fs_sel & 7)) - vmcs_write16(HOST_FS_SELECTOR, hs->fs_sel); - else { + vmx->host_state.ldt_sel = read_ldt(); + vmx->host_state.gs_ldt_reload_needed = vmx->host_state.ldt_sel; + vmx->host_state.fs_sel = read_fs(); + if (!(vmx->host_state.fs_sel & 7)) { + vmcs_write16(HOST_FS_SELECTOR, vmx->host_state.fs_sel); + vmx->host_state.fs_reload_needed = 0; + } else { vmcs_write16(HOST_FS_SELECTOR, 0); - hs->fs_gs_ldt_reload_needed = 1; + vmx->host_state.fs_reload_needed = 1; } - hs->gs_sel = read_gs(); - if (!(hs->gs_sel & 7)) - vmcs_write16(HOST_GS_SELECTOR, hs->gs_sel); + vmx->host_state.gs_sel = read_gs(); + if (!(vmx->host_state.gs_sel & 7)) + vmcs_write16(HOST_GS_SELECTOR, vmx->host_state.gs_sel); else { vmcs_write16(HOST_GS_SELECTOR, 0); - hs->fs_gs_ldt_reload_needed = 1; + vmx->host_state.gs_ldt_reload_needed = 1; } #ifdef CONFIG_X86_64 vmcs_writel(HOST_FS_BASE, read_msr(MSR_FS_BASE)); vmcs_writel(HOST_GS_BASE, read_msr(MSR_GS_BASE)); #else - vmcs_writel(HOST_FS_BASE, segment_base(hs->fs_sel)); - vmcs_writel(HOST_GS_BASE, segment_base(hs->gs_sel)); + vmcs_writel(HOST_FS_BASE, segment_base(vmx->host_state.fs_sel)); + vmcs_writel(HOST_GS_BASE, segment_base(vmx->host_state.gs_sel)); #endif #ifdef CONFIG_X86_64 - if (is_long_mode(vcpu)) { - save_msrs(vcpu->host_msrs + vcpu->msr_offset_kernel_gs_base, 1); + if (is_long_mode(&vmx->vcpu)) { + save_msrs(vmx->host_msrs + + vmx->msr_offset_kernel_gs_base, 1); } #endif - load_msrs(vcpu->guest_msrs, vcpu->save_nmsrs); - if (msr_efer_need_save_restore(vcpu)) - load_transition_efer(vcpu); + load_msrs(vmx->guest_msrs, vmx->save_nmsrs); + if (msr_efer_need_save_restore(vmx)) + load_transition_efer(vmx); } -static void vmx_load_host_state(struct kvm_vcpu *vcpu) +static void vmx_load_host_state(struct vcpu_vmx *vmx) { - struct vmx_host_state *hs = &vcpu->vmx_host_state; + unsigned long flags; - if (!hs->loaded) + if (!vmx->host_state.loaded) return; - hs->loaded = 0; - if (hs->fs_gs_ldt_reload_needed) { - load_ldt(hs->ldt_sel); - load_fs(hs->fs_sel); + vmx->host_state.loaded = 0; + if (vmx->host_state.fs_reload_needed) + load_fs(vmx->host_state.fs_sel); + if (vmx->host_state.gs_ldt_reload_needed) { + load_ldt(vmx->host_state.ldt_sel); /* * If we have to reload gs, we must take care to * preserve our gs base. */ - local_irq_disable(); - load_gs(hs->gs_sel); + local_irq_save(flags); + load_gs(vmx->host_state.gs_sel); #ifdef CONFIG_X86_64 wrmsrl(MSR_GS_BASE, vmcs_readl(HOST_GS_BASE)); #endif - local_irq_enable(); - - reload_tss(); + local_irq_restore(flags); } - save_msrs(vcpu->guest_msrs, vcpu->save_nmsrs); - load_msrs(vcpu->host_msrs, vcpu->save_nmsrs); - if (msr_efer_need_save_restore(vcpu)) - load_msrs(vcpu->host_msrs + vcpu->msr_offset_efer, 1); + reload_tss(); + save_msrs(vmx->guest_msrs, vmx->save_nmsrs); + load_msrs(vmx->host_msrs, vmx->save_nmsrs); + if (msr_efer_need_save_restore(vmx)) + load_msrs(vmx->host_msrs + vmx->msr_offset_efer, 1); } /* * Switches to specified vcpu, until a matching vcpu_put(), but assumes * vcpu mutex is already taken. */ -static void vmx_vcpu_load(struct kvm_vcpu *vcpu) +static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu) { - u64 phys_addr = __pa(vcpu->vmcs); - int cpu; + struct vcpu_vmx *vmx = to_vmx(vcpu); + u64 phys_addr = __pa(vmx->vmcs); u64 tsc_this, delta; - cpu = get_cpu(); - - if (vcpu->cpu != cpu) - vcpu_clear(vcpu); + if (vcpu->cpu != cpu) { + vcpu_clear(vmx); + kvm_migrate_apic_timer(vcpu); + } - if (per_cpu(current_vmcs, cpu) != vcpu->vmcs) { + if (per_cpu(current_vmcs, cpu) != vmx->vmcs) { u8 error; - per_cpu(current_vmcs, cpu) = vcpu->vmcs; + per_cpu(current_vmcs, cpu) = vmx->vmcs; asm volatile (ASM_VMX_VMPTRLD_RAX "; setna %0" : "=g"(error) : "a"(&phys_addr), "m"(phys_addr) : "cc"); if (error) printk(KERN_ERR "kvm: vmptrld %p/%llx fail\n", - vcpu->vmcs, phys_addr); + vmx->vmcs, phys_addr); } if (vcpu->cpu != cpu) { @@ -426,9 +487,8 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu) static void vmx_vcpu_put(struct kvm_vcpu *vcpu) { - vmx_load_host_state(vcpu); + vmx_load_host_state(to_vmx(vcpu)); kvm_put_guest_fpu(vcpu); - put_cpu(); } static void vmx_fpu_activate(struct kvm_vcpu *vcpu) @@ -436,9 +496,9 @@ static void vmx_fpu_activate(struct kvm_vcpu *vcpu) if (vcpu->fpu_active) return; vcpu->fpu_active = 1; - vmcs_clear_bits(GUEST_CR0, CR0_TS_MASK); - if (vcpu->cr0 & CR0_TS_MASK) - vmcs_set_bits(GUEST_CR0, CR0_TS_MASK); + vmcs_clear_bits(GUEST_CR0, X86_CR0_TS); + if (vcpu->cr0 & X86_CR0_TS) + vmcs_set_bits(GUEST_CR0, X86_CR0_TS); update_exception_bitmap(vcpu); } @@ -447,13 +507,13 @@ static void vmx_fpu_deactivate(struct kvm_vcpu *vcpu) if (!vcpu->fpu_active) return; vcpu->fpu_active = 0; - vmcs_set_bits(GUEST_CR0, CR0_TS_MASK); + vmcs_set_bits(GUEST_CR0, X86_CR0_TS); update_exception_bitmap(vcpu); } static void vmx_vcpu_decache(struct kvm_vcpu *vcpu) { - vcpu_clear(vcpu); + vcpu_clear(to_vmx(vcpu)); } static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu) @@ -501,59 +561,62 @@ static void vmx_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code) /* * Swap MSR entry in host/guest MSR entry array. */ -void move_msr_up(struct kvm_vcpu *vcpu, int from, int to) +#ifdef CONFIG_X86_64 +static void move_msr_up(struct vcpu_vmx *vmx, int from, int to) { - struct vmx_msr_entry tmp; - tmp = vcpu->guest_msrs[to]; - vcpu->guest_msrs[to] = vcpu->guest_msrs[from]; - vcpu->guest_msrs[from] = tmp; - tmp = vcpu->host_msrs[to]; - vcpu->host_msrs[to] = vcpu->host_msrs[from]; - vcpu->host_msrs[from] = tmp; + struct kvm_msr_entry tmp; + + tmp = vmx->guest_msrs[to]; + vmx->guest_msrs[to] = vmx->guest_msrs[from]; + vmx->guest_msrs[from] = tmp; + tmp = vmx->host_msrs[to]; + vmx->host_msrs[to] = vmx->host_msrs[from]; + vmx->host_msrs[from] = tmp; } +#endif /* * Set up the vmcs to automatically save and restore system * msrs. Don't touch the 64-bit msrs if the guest is in legacy * mode, as fiddling with msrs is very expensive. */ -static void setup_msrs(struct kvm_vcpu *vcpu) +static void setup_msrs(struct vcpu_vmx *vmx) { int save_nmsrs; save_nmsrs = 0; #ifdef CONFIG_X86_64 - if (is_long_mode(vcpu)) { + if (is_long_mode(&vmx->vcpu)) { int index; - index = __find_msr_index(vcpu, MSR_SYSCALL_MASK); + index = __find_msr_index(vmx, MSR_SYSCALL_MASK); if (index >= 0) - move_msr_up(vcpu, index, save_nmsrs++); - index = __find_msr_index(vcpu, MSR_LSTAR); + move_msr_up(vmx, index, save_nmsrs++); + index = __find_msr_index(vmx, MSR_LSTAR); if (index >= 0) - move_msr_up(vcpu, index, save_nmsrs++); - index = __find_msr_index(vcpu, MSR_CSTAR); + move_msr_up(vmx, index, save_nmsrs++); + index = __find_msr_index(vmx, MSR_CSTAR); if (index >= 0) - move_msr_up(vcpu, index, save_nmsrs++); - index = __find_msr_index(vcpu, MSR_KERNEL_GS_BASE); + move_msr_up(vmx, index, save_nmsrs++); + index = __find_msr_index(vmx, MSR_KERNEL_GS_BASE); if (index >= 0) - move_msr_up(vcpu, index, save_nmsrs++); + move_msr_up(vmx, index, save_nmsrs++); /* * MSR_K6_STAR is only needed on long mode guests, and only * if efer.sce is enabled. */ - index = __find_msr_index(vcpu, MSR_K6_STAR); - if ((index >= 0) && (vcpu->shadow_efer & EFER_SCE)) - move_msr_up(vcpu, index, save_nmsrs++); + index = __find_msr_index(vmx, MSR_K6_STAR); + if ((index >= 0) && (vmx->vcpu.shadow_efer & EFER_SCE)) + move_msr_up(vmx, index, save_nmsrs++); } #endif - vcpu->save_nmsrs = save_nmsrs; + vmx->save_nmsrs = save_nmsrs; #ifdef CONFIG_X86_64 - vcpu->msr_offset_kernel_gs_base = - __find_msr_index(vcpu, MSR_KERNEL_GS_BASE); + vmx->msr_offset_kernel_gs_base = + __find_msr_index(vmx, MSR_KERNEL_GS_BASE); #endif - vcpu->msr_offset_efer = __find_msr_index(vcpu, MSR_EFER); + vmx->msr_offset_efer = __find_msr_index(vmx, MSR_EFER); } /* @@ -589,7 +652,7 @@ static void guest_write_tsc(u64 guest_tsc) static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) { u64 data; - struct vmx_msr_entry *msr; + struct kvm_msr_entry *msr; if (!pdata) { printk(KERN_ERR "BUG: get_msr called with NULL pdata\n"); @@ -620,7 +683,7 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) data = vmcs_readl(GUEST_SYSENTER_ESP); break; default: - msr = find_msr_entry(vcpu, msr_index); + msr = find_msr_entry(to_vmx(vcpu), msr_index); if (msr) { data = msr->data; break; @@ -639,15 +702,16 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) */ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data) { - struct vmx_msr_entry *msr; + struct vcpu_vmx *vmx = to_vmx(vcpu); + struct kvm_msr_entry *msr; int ret = 0; switch (msr_index) { #ifdef CONFIG_X86_64 case MSR_EFER: ret = kvm_set_msr_common(vcpu, msr_index, data); - if (vcpu->vmx_host_state.loaded) - load_transition_efer(vcpu); + if (vmx->host_state.loaded) + load_transition_efer(vmx); break; case MSR_FS_BASE: vmcs_writel(GUEST_FS_BASE, data); @@ -669,11 +733,11 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data) guest_write_tsc(data); break; default: - msr = find_msr_entry(vcpu, msr_index); + msr = find_msr_entry(vmx, msr_index); if (msr) { msr->data = data; - if (vcpu->vmx_host_state.loaded) - load_msrs(vcpu->guest_msrs, vcpu->save_nmsrs); + if (vmx->host_state.loaded) + load_msrs(vmx->guest_msrs, vmx->save_nmsrs); break; } ret = kvm_set_msr_common(vcpu, msr_index, data); @@ -740,6 +804,20 @@ static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg) return 0; } +static int vmx_get_irq(struct kvm_vcpu *vcpu) +{ + u32 idtv_info_field; + + idtv_info_field = vmcs_read32(IDT_VECTORING_INFO_FIELD); + if (idtv_info_field & INTR_INFO_VALID_MASK) { + if (is_external_interrupt(idtv_info_field)) + return idtv_info_field & VECTORING_INFO_VECTOR_MASK; + else + printk("pending exception: not handled yet\n"); + } + return -1; +} + static __init int cpu_has_kvm_support(void) { unsigned long ecx = cpuid_ecx(1); @@ -751,7 +829,10 @@ static __init int vmx_disabled_by_bios(void) u64 msr; rdmsrl(MSR_IA32_FEATURE_CONTROL, msr); - return (msr & 5) == 1; /* locked but not enabled */ + return (msr & (MSR_IA32_FEATURE_CONTROL_LOCKED | + MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED)) + == MSR_IA32_FEATURE_CONTROL_LOCKED; + /* locked but not enabled */ } static void hardware_enable(void *garbage) @@ -761,10 +842,15 @@ static void hardware_enable(void *garbage) u64 old; rdmsrl(MSR_IA32_FEATURE_CONTROL, old); - if ((old & 5) != 5) + if ((old & (MSR_IA32_FEATURE_CONTROL_LOCKED | + MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED)) + != (MSR_IA32_FEATURE_CONTROL_LOCKED | + MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED)) /* enable and lock */ - wrmsrl(MSR_IA32_FEATURE_CONTROL, old | 5); - write_cr4(read_cr4() | CR4_VMXE); /* FIXME: not cpu hotplug safe */ + wrmsrl(MSR_IA32_FEATURE_CONTROL, old | + MSR_IA32_FEATURE_CONTROL_LOCKED | + MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED); + write_cr4(read_cr4() | X86_CR4_VMXE); /* FIXME: not cpu hotplug safe */ asm volatile (ASM_VMX_VMXON_RAX : : "a"(&phys_addr), "m"(phys_addr) : "memory", "cc"); } @@ -774,14 +860,102 @@ static void hardware_disable(void *garbage) asm volatile (ASM_VMX_VMXOFF : : : "cc"); } -static __init void setup_vmcs_descriptor(void) +static __init int adjust_vmx_controls(u32 ctl_min, u32 ctl_opt, + u32 msr, u32* result) +{ + u32 vmx_msr_low, vmx_msr_high; + u32 ctl = ctl_min | ctl_opt; + + rdmsr(msr, vmx_msr_low, vmx_msr_high); + + ctl &= vmx_msr_high; /* bit == 0 in high word ==> must be zero */ + ctl |= vmx_msr_low; /* bit == 1 in low word ==> must be one */ + + /* Ensure minimum (required) set of control bits are supported. */ + if (ctl_min & ~ctl) + return -EIO; + + *result = ctl; + return 0; +} + +static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf) { u32 vmx_msr_low, vmx_msr_high; + u32 min, opt; + u32 _pin_based_exec_control = 0; + u32 _cpu_based_exec_control = 0; + u32 _vmexit_control = 0; + u32 _vmentry_control = 0; + + min = PIN_BASED_EXT_INTR_MASK | PIN_BASED_NMI_EXITING; + opt = 0; + if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PINBASED_CTLS, + &_pin_based_exec_control) < 0) + return -EIO; + + min = CPU_BASED_HLT_EXITING | +#ifdef CONFIG_X86_64 + CPU_BASED_CR8_LOAD_EXITING | + CPU_BASED_CR8_STORE_EXITING | +#endif + CPU_BASED_USE_IO_BITMAPS | + CPU_BASED_MOV_DR_EXITING | + CPU_BASED_USE_TSC_OFFSETING; +#ifdef CONFIG_X86_64 + opt = CPU_BASED_TPR_SHADOW; +#else + opt = 0; +#endif + if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS, + &_cpu_based_exec_control) < 0) + return -EIO; +#ifdef CONFIG_X86_64 + if ((_cpu_based_exec_control & CPU_BASED_TPR_SHADOW)) + _cpu_based_exec_control &= ~CPU_BASED_CR8_LOAD_EXITING & + ~CPU_BASED_CR8_STORE_EXITING; +#endif + + min = 0; +#ifdef CONFIG_X86_64 + min |= VM_EXIT_HOST_ADDR_SPACE_SIZE; +#endif + opt = 0; + if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_EXIT_CTLS, + &_vmexit_control) < 0) + return -EIO; + + min = opt = 0; + if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_ENTRY_CTLS, + &_vmentry_control) < 0) + return -EIO; rdmsr(MSR_IA32_VMX_BASIC, vmx_msr_low, vmx_msr_high); - vmcs_descriptor.size = vmx_msr_high & 0x1fff; - vmcs_descriptor.order = get_order(vmcs_descriptor.size); - vmcs_descriptor.revision_id = vmx_msr_low; + + /* IA-32 SDM Vol 3B: VMCS size is never greater than 4kB. */ + if ((vmx_msr_high & 0x1fff) > PAGE_SIZE) + return -EIO; + +#ifdef CONFIG_X86_64 + /* IA-32 SDM Vol 3B: 64-bit CPUs always have VMX_BASIC_MSR[48]==0. */ + if (vmx_msr_high & (1u<<16)) + return -EIO; +#endif + + /* Require Write-Back (WB) memory type for VMCS accesses. */ + if (((vmx_msr_high >> 18) & 15) != 6) + return -EIO; + + vmcs_conf->size = vmx_msr_high & 0x1fff; + vmcs_conf->order = get_order(vmcs_config.size); + vmcs_conf->revision_id = vmx_msr_low; + + vmcs_conf->pin_based_exec_ctrl = _pin_based_exec_control; + vmcs_conf->cpu_based_exec_ctrl = _cpu_based_exec_control; + vmcs_conf->vmexit_ctrl = _vmexit_control; + vmcs_conf->vmentry_ctrl = _vmentry_control; + + return 0; } static struct vmcs *alloc_vmcs_cpu(int cpu) @@ -790,12 +964,12 @@ static struct vmcs *alloc_vmcs_cpu(int cpu) struct page *pages; struct vmcs *vmcs; - pages = alloc_pages_node(node, GFP_KERNEL, vmcs_descriptor.order); + pages = alloc_pages_node(node, GFP_KERNEL, vmcs_config.order); if (!pages) return NULL; vmcs = page_address(pages); - memset(vmcs, 0, vmcs_descriptor.size); - vmcs->revision_id = vmcs_descriptor.revision_id; /* vmcs revision id */ + memset(vmcs, 0, vmcs_config.size); + vmcs->revision_id = vmcs_config.revision_id; /* vmcs revision id */ return vmcs; } @@ -806,7 +980,7 @@ static struct vmcs *alloc_vmcs(void) static void free_vmcs(struct vmcs *vmcs) { - free_pages((unsigned long)vmcs, vmcs_descriptor.order); + free_pages((unsigned long)vmcs, vmcs_config.order); } static void free_kvm_area(void) @@ -817,8 +991,6 @@ static void free_kvm_area(void) free_vmcs(per_cpu(vmxarea, cpu)); } -extern struct vmcs *alloc_vmcs_cpu(int cpu); - static __init int alloc_kvm_area(void) { int cpu; @@ -839,7 +1011,8 @@ static __init int alloc_kvm_area(void) static __init int hardware_setup(void) { - setup_vmcs_descriptor(); + if (setup_vmcs_config(&vmcs_config) < 0) + return -EIO; return alloc_kvm_area(); } @@ -879,8 +1052,8 @@ static void enter_pmode(struct kvm_vcpu *vcpu) flags |= (vcpu->rmode.save_iopl << IOPL_SHIFT); vmcs_writel(GUEST_RFLAGS, flags); - vmcs_writel(GUEST_CR4, (vmcs_readl(GUEST_CR4) & ~CR4_VME_MASK) | - (vmcs_readl(CR4_READ_SHADOW) & CR4_VME_MASK)); + vmcs_writel(GUEST_CR4, (vmcs_readl(GUEST_CR4) & ~X86_CR4_VME) | + (vmcs_readl(CR4_READ_SHADOW) & X86_CR4_VME)); update_exception_bitmap(vcpu); @@ -897,7 +1070,7 @@ static void enter_pmode(struct kvm_vcpu *vcpu) vmcs_write32(GUEST_CS_AR_BYTES, 0x9b); } -static int rmode_tss_base(struct kvm* kvm) +static gva_t rmode_tss_base(struct kvm* kvm) { gfn_t base_gfn = kvm->memslots[0].base_gfn + kvm->memslots[0].npages - 3; return base_gfn << PAGE_SHIFT; @@ -937,7 +1110,7 @@ static void enter_rmode(struct kvm_vcpu *vcpu) flags |= IOPL_MASK | X86_EFLAGS_VM; vmcs_writel(GUEST_RFLAGS, flags); - vmcs_writel(GUEST_CR4, vmcs_readl(GUEST_CR4) | CR4_VME_MASK); + vmcs_writel(GUEST_CR4, vmcs_readl(GUEST_CR4) | X86_CR4_VME); update_exception_bitmap(vcpu); vmcs_write16(GUEST_SS_SELECTOR, vmcs_readl(GUEST_SS_BASE) >> 4); @@ -975,10 +1148,10 @@ static void enter_lmode(struct kvm_vcpu *vcpu) vcpu->shadow_efer |= EFER_LMA; - find_msr_entry(vcpu, MSR_EFER)->data |= EFER_LMA | EFER_LME; + find_msr_entry(to_vmx(vcpu), MSR_EFER)->data |= EFER_LMA | EFER_LME; vmcs_write32(VM_ENTRY_CONTROLS, vmcs_read32(VM_ENTRY_CONTROLS) - | VM_ENTRY_CONTROLS_IA32E_MASK); + | VM_ENTRY_IA32E_MODE); } static void exit_lmode(struct kvm_vcpu *vcpu) @@ -987,7 +1160,7 @@ static void exit_lmode(struct kvm_vcpu *vcpu) vmcs_write32(VM_ENTRY_CONTROLS, vmcs_read32(VM_ENTRY_CONTROLS) - & ~VM_ENTRY_CONTROLS_IA32E_MASK); + & ~VM_ENTRY_IA32E_MODE); } #endif @@ -1002,17 +1175,17 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) { vmx_fpu_deactivate(vcpu); - if (vcpu->rmode.active && (cr0 & CR0_PE_MASK)) + if (vcpu->rmode.active && (cr0 & X86_CR0_PE)) enter_pmode(vcpu); - if (!vcpu->rmode.active && !(cr0 & CR0_PE_MASK)) + if (!vcpu->rmode.active && !(cr0 & X86_CR0_PE)) enter_rmode(vcpu); #ifdef CONFIG_X86_64 if (vcpu->shadow_efer & EFER_LME) { - if (!is_paging(vcpu) && (cr0 & CR0_PG_MASK)) + if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) enter_lmode(vcpu); - if (is_paging(vcpu) && !(cr0 & CR0_PG_MASK)) + if (is_paging(vcpu) && !(cr0 & X86_CR0_PG)) exit_lmode(vcpu); } #endif @@ -1022,14 +1195,14 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) (cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON); vcpu->cr0 = cr0; - if (!(cr0 & CR0_TS_MASK) || !(cr0 & CR0_PE_MASK)) + if (!(cr0 & X86_CR0_TS) || !(cr0 & X86_CR0_PE)) vmx_fpu_activate(vcpu); } static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) { vmcs_writel(GUEST_CR3, cr3); - if (vcpu->cr0 & CR0_PE_MASK) + if (vcpu->cr0 & X86_CR0_PE) vmx_fpu_deactivate(vcpu); } @@ -1045,23 +1218,24 @@ static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) static void vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer) { - struct vmx_msr_entry *msr = find_msr_entry(vcpu, MSR_EFER); + struct vcpu_vmx *vmx = to_vmx(vcpu); + struct kvm_msr_entry *msr = find_msr_entry(vmx, MSR_EFER); vcpu->shadow_efer = efer; if (efer & EFER_LMA) { vmcs_write32(VM_ENTRY_CONTROLS, vmcs_read32(VM_ENTRY_CONTROLS) | - VM_ENTRY_CONTROLS_IA32E_MASK); + VM_ENTRY_IA32E_MODE); msr->data = efer; } else { vmcs_write32(VM_ENTRY_CONTROLS, vmcs_read32(VM_ENTRY_CONTROLS) & - ~VM_ENTRY_CONTROLS_IA32E_MASK); + ~VM_ENTRY_IA32E_MODE); msr->data = efer & ~EFER_LME; } - setup_msrs(vcpu); + setup_msrs(vmx); } #endif @@ -1210,17 +1384,6 @@ static int init_rmode_tss(struct kvm* kvm) return 1; } -static void vmcs_write32_fixedbits(u32 msr, u32 vmcs_field, u32 val) -{ - u32 msr_high, msr_low; - - rdmsr(msr, msr_low, msr_high); - - val &= msr_high; - val |= msr_low; - vmcs_write32(vmcs_field, val); -} - static void seg_setup(int seg) { struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; @@ -1234,7 +1397,7 @@ static void seg_setup(int seg) /* * Sets up the vmcs for emulated real mode. */ -static int vmx_vcpu_setup(struct kvm_vcpu *vcpu) +static int vmx_vcpu_setup(struct vcpu_vmx *vmx) { u32 host_sysenter_cs; u32 junk; @@ -1243,27 +1406,36 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu) int i; int ret = 0; unsigned long kvm_vmx_return; + u64 msr; + u32 exec_control; - if (!init_rmode_tss(vcpu->kvm)) { + if (!init_rmode_tss(vmx->vcpu.kvm)) { ret = -ENOMEM; goto out; } - memset(vcpu->regs, 0, sizeof(vcpu->regs)); - vcpu->regs[VCPU_REGS_RDX] = get_rdx_init_val(); - vcpu->cr8 = 0; - vcpu->apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE; - if (vcpu == &vcpu->kvm->vcpus[0]) - vcpu->apic_base |= MSR_IA32_APICBASE_BSP; + vmx->vcpu.rmode.active = 0; - fx_init(vcpu); + vmx->vcpu.regs[VCPU_REGS_RDX] = get_rdx_init_val(); + set_cr8(&vmx->vcpu, 0); + msr = 0xfee00000 | MSR_IA32_APICBASE_ENABLE; + if (vmx->vcpu.vcpu_id == 0) + msr |= MSR_IA32_APICBASE_BSP; + kvm_set_apic_base(&vmx->vcpu, msr); + + fx_init(&vmx->vcpu); /* * GUEST_CS_BASE should really be 0xffff0000, but VT vm86 mode * insists on having GUEST_CS_BASE == GUEST_CS_SELECTOR << 4. Sigh. */ - vmcs_write16(GUEST_CS_SELECTOR, 0xf000); - vmcs_writel(GUEST_CS_BASE, 0x000f0000); + if (vmx->vcpu.vcpu_id == 0) { + vmcs_write16(GUEST_CS_SELECTOR, 0xf000); + vmcs_writel(GUEST_CS_BASE, 0x000f0000); + } else { + vmcs_write16(GUEST_CS_SELECTOR, vmx->vcpu.sipi_vector << 8); + vmcs_writel(GUEST_CS_BASE, vmx->vcpu.sipi_vector << 12); + } vmcs_write32(GUEST_CS_LIMIT, 0xffff); vmcs_write32(GUEST_CS_AR_BYTES, 0x9b); @@ -1288,7 +1460,10 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu) vmcs_writel(GUEST_SYSENTER_EIP, 0); vmcs_writel(GUEST_RFLAGS, 0x02); - vmcs_writel(GUEST_RIP, 0xfff0); + if (vmx->vcpu.vcpu_id == 0) + vmcs_writel(GUEST_RIP, 0xfff0); + else + vmcs_writel(GUEST_RIP, 0); vmcs_writel(GUEST_RSP, 0); //todo: dr0 = dr1 = dr2 = dr3 = 0; dr6 = 0xffff0ff0 @@ -1316,20 +1491,18 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu) vmcs_write64(GUEST_IA32_DEBUGCTL, 0); /* Control */ - vmcs_write32_fixedbits(MSR_IA32_VMX_PINBASED_CTLS, - PIN_BASED_VM_EXEC_CONTROL, - PIN_BASED_EXT_INTR_MASK /* 20.6.1 */ - | PIN_BASED_NMI_EXITING /* 20.6.1 */ - ); - vmcs_write32_fixedbits(MSR_IA32_VMX_PROCBASED_CTLS, - CPU_BASED_VM_EXEC_CONTROL, - CPU_BASED_HLT_EXITING /* 20.6.2 */ - | CPU_BASED_CR8_LOAD_EXITING /* 20.6.2 */ - | CPU_BASED_CR8_STORE_EXITING /* 20.6.2 */ - | CPU_BASED_ACTIVATE_IO_BITMAP /* 20.6.2 */ - | CPU_BASED_MOV_DR_EXITING - | CPU_BASED_USE_TSC_OFFSETING /* 21.3 */ - ); + vmcs_write32(PIN_BASED_VM_EXEC_CONTROL, + vmcs_config.pin_based_exec_ctrl); + + exec_control = vmcs_config.cpu_based_exec_ctrl; + if (!vm_need_tpr_shadow(vmx->vcpu.kvm)) { + exec_control &= ~CPU_BASED_TPR_SHADOW; +#ifdef CONFIG_X86_64 + exec_control |= CPU_BASED_CR8_STORE_EXITING | + CPU_BASED_CR8_LOAD_EXITING; +#endif + } + vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, exec_control); vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, 0); vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, 0); @@ -1377,46 +1550,48 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu) u32 index = vmx_msr_index[i]; u32 data_low, data_high; u64 data; - int j = vcpu->nmsrs; + int j = vmx->nmsrs; if (rdmsr_safe(index, &data_low, &data_high) < 0) continue; if (wrmsr_safe(index, data_low, data_high) < 0) continue; data = data_low | ((u64)data_high << 32); - vcpu->host_msrs[j].index = index; - vcpu->host_msrs[j].reserved = 0; - vcpu->host_msrs[j].data = data; - vcpu->guest_msrs[j] = vcpu->host_msrs[j]; - ++vcpu->nmsrs; + vmx->host_msrs[j].index = index; + vmx->host_msrs[j].reserved = 0; + vmx->host_msrs[j].data = data; + vmx->guest_msrs[j] = vmx->host_msrs[j]; + ++vmx->nmsrs; } - setup_msrs(vcpu); + setup_msrs(vmx); - vmcs_write32_fixedbits(MSR_IA32_VMX_EXIT_CTLS, VM_EXIT_CONTROLS, - (HOST_IS_64 << 9)); /* 22.2,1, 20.7.1 */ + vmcs_write32(VM_EXIT_CONTROLS, vmcs_config.vmexit_ctrl); /* 22.2.1, 20.8.1 */ - vmcs_write32_fixedbits(MSR_IA32_VMX_ENTRY_CTLS, - VM_ENTRY_CONTROLS, 0); + vmcs_write32(VM_ENTRY_CONTROLS, vmcs_config.vmentry_ctrl); + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0); /* 22.2.1 */ #ifdef CONFIG_X86_64 - vmcs_writel(VIRTUAL_APIC_PAGE_ADDR, 0); - vmcs_writel(TPR_THRESHOLD, 0); + vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, 0); + if (vm_need_tpr_shadow(vmx->vcpu.kvm)) + vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, + page_to_phys(vmx->vcpu.apic->regs_page)); + vmcs_write32(TPR_THRESHOLD, 0); #endif vmcs_writel(CR0_GUEST_HOST_MASK, ~0UL); vmcs_writel(CR4_GUEST_HOST_MASK, KVM_GUEST_CR4_MASK); - vcpu->cr0 = 0x60000010; - vmx_set_cr0(vcpu, vcpu->cr0); // enter rmode - vmx_set_cr4(vcpu, 0); + vmx->vcpu.cr0 = 0x60000010; + vmx_set_cr0(&vmx->vcpu, vmx->vcpu.cr0); // enter rmode + vmx_set_cr4(&vmx->vcpu, 0); #ifdef CONFIG_X86_64 - vmx_set_efer(vcpu, 0); + vmx_set_efer(&vmx->vcpu, 0); #endif - vmx_fpu_activate(vcpu); - update_exception_bitmap(vcpu); + vmx_fpu_activate(&vmx->vcpu); + update_exception_bitmap(&vmx->vcpu); return 0; @@ -1424,6 +1599,13 @@ out: return ret; } +static void vmx_vcpu_reset(struct kvm_vcpu *vcpu) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + + vmx_vcpu_setup(vmx); +} + static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq) { u16 ent[2]; @@ -1443,8 +1625,8 @@ static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq) return; } - if (kvm_read_guest(vcpu, irq * sizeof(ent), sizeof(ent), &ent) != - sizeof(ent)) { + if (emulator_read_std(irq * sizeof(ent), &ent, sizeof(ent), vcpu) != + X86EMUL_CONTINUE) { vcpu_printf(vcpu, "%s: read guest err\n", __FUNCTION__); return; } @@ -1454,9 +1636,9 @@ static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq) ip = vmcs_readl(GUEST_RIP); - if (kvm_write_guest(vcpu, ss_base + sp - 2, 2, &flags) != 2 || - kvm_write_guest(vcpu, ss_base + sp - 4, 2, &cs) != 2 || - kvm_write_guest(vcpu, ss_base + sp - 6, 2, &ip) != 2) { + if (emulator_write_emulated(ss_base + sp - 2, &flags, 2, vcpu) != X86EMUL_CONTINUE || + emulator_write_emulated(ss_base + sp - 4, &cs, 2, vcpu) != X86EMUL_CONTINUE || + emulator_write_emulated(ss_base + sp - 6, &ip, 2, vcpu) != X86EMUL_CONTINUE) { vcpu_printf(vcpu, "%s: write guest err\n", __FUNCTION__); return; } @@ -1469,6 +1651,16 @@ static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq) vmcs_writel(GUEST_RSP, (vmcs_readl(GUEST_RSP) & ~0xffff) | (sp - 6)); } +static void vmx_inject_irq(struct kvm_vcpu *vcpu, int irq) +{ + if (vcpu->rmode.active) { + inject_rmode_irq(vcpu, irq); + return; + } + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, + irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK); +} + static void kvm_do_inject_irq(struct kvm_vcpu *vcpu) { int word_index = __ffs(vcpu->irq_summary); @@ -1478,13 +1670,7 @@ static void kvm_do_inject_irq(struct kvm_vcpu *vcpu) clear_bit(bit_index, &vcpu->irq_pending[word_index]); if (!vcpu->irq_pending[word_index]) clear_bit(word_index, &vcpu->irq_summary); - - if (vcpu->rmode.active) { - inject_rmode_irq(vcpu, irq); - return; - } - vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, - irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK); + vmx_inject_irq(vcpu, irq); } @@ -1568,7 +1754,7 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) "intr info 0x%x\n", __FUNCTION__, vect_info, intr_info); } - if (is_external_interrupt(vect_info)) { + if (!irqchip_in_kernel(vcpu->kvm) && is_external_interrupt(vect_info)) { int irq = vect_info & VECTORING_INFO_VECTOR_MASK; set_bit(irq, vcpu->irq_pending); set_bit(irq / BITS_PER_LONG, &vcpu->irq_summary); @@ -1591,29 +1777,28 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) if (is_page_fault(intr_info)) { cr2 = vmcs_readl(EXIT_QUALIFICATION); - spin_lock(&vcpu->kvm->lock); + mutex_lock(&vcpu->kvm->lock); r = kvm_mmu_page_fault(vcpu, cr2, error_code); if (r < 0) { - spin_unlock(&vcpu->kvm->lock); + mutex_unlock(&vcpu->kvm->lock); return r; } if (!r) { - spin_unlock(&vcpu->kvm->lock); + mutex_unlock(&vcpu->kvm->lock); return 1; } er = emulate_instruction(vcpu, kvm_run, cr2, error_code); - spin_unlock(&vcpu->kvm->lock); + mutex_unlock(&vcpu->kvm->lock); switch (er) { case EMULATE_DONE: return 1; case EMULATE_DO_MMIO: ++vcpu->stat.mmio_exits; - kvm_run->exit_reason = KVM_EXIT_MMIO; return 0; case EMULATE_FAIL: - vcpu_printf(vcpu, "%s: emulate fail\n", __FUNCTION__); + kvm_report_emulation_failure(vcpu, "pagetable"); break; default: BUG(); @@ -1653,80 +1838,29 @@ static int handle_triple_fault(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) return 0; } -static int get_io_count(struct kvm_vcpu *vcpu, unsigned long *count) -{ - u64 inst; - gva_t rip; - int countr_size; - int i, n; - - if ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_VM)) { - countr_size = 2; - } else { - u32 cs_ar = vmcs_read32(GUEST_CS_AR_BYTES); - - countr_size = (cs_ar & AR_L_MASK) ? 8: - (cs_ar & AR_DB_MASK) ? 4: 2; - } - - rip = vmcs_readl(GUEST_RIP); - if (countr_size != 8) - rip += vmcs_readl(GUEST_CS_BASE); - - n = kvm_read_guest(vcpu, rip, sizeof(inst), &inst); - - for (i = 0; i < n; i++) { - switch (((u8*)&inst)[i]) { - case 0xf0: - case 0xf2: - case 0xf3: - case 0x2e: - case 0x36: - case 0x3e: - case 0x26: - case 0x64: - case 0x65: - case 0x66: - break; - case 0x67: - countr_size = (countr_size == 2) ? 4: (countr_size >> 1); - default: - goto done; - } - } - return 0; -done: - countr_size *= 8; - *count = vcpu->regs[VCPU_REGS_RCX] & (~0ULL >> (64 - countr_size)); - //printk("cx: %lx\n", vcpu->regs[VCPU_REGS_RCX]); - return 1; -} - static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { - u64 exit_qualification; + unsigned long exit_qualification; int size, down, in, string, rep; unsigned port; - unsigned long count; - gva_t address; ++vcpu->stat.io_exits; - exit_qualification = vmcs_read64(EXIT_QUALIFICATION); - in = (exit_qualification & 8) != 0; - size = (exit_qualification & 7) + 1; + exit_qualification = vmcs_readl(EXIT_QUALIFICATION); string = (exit_qualification & 16) != 0; + + if (string) { + if (emulate_instruction(vcpu, kvm_run, 0, 0) == EMULATE_DO_MMIO) + return 0; + return 1; + } + + size = (exit_qualification & 7) + 1; + in = (exit_qualification & 8) != 0; down = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_DF) != 0; - count = 1; rep = (exit_qualification & 32) != 0; port = exit_qualification >> 16; - address = 0; - if (string) { - if (rep && !get_io_count(vcpu, &count)) - return 1; - address = vmcs_readl(GUEST_LINEAR_ADDRESS); - } - return kvm_setup_pio(vcpu, kvm_run, in, size, count, string, down, - address, rep, port); + + return kvm_emulate_pio(vcpu, kvm_run, in, size, port); } static void @@ -1743,11 +1877,11 @@ vmx_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall) static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { - u64 exit_qualification; + unsigned long exit_qualification; int cr; int reg; - exit_qualification = vmcs_read64(EXIT_QUALIFICATION); + exit_qualification = vmcs_readl(EXIT_QUALIFICATION); cr = exit_qualification & 15; reg = (exit_qualification >> 8) & 15; switch ((exit_qualification >> 4) & 3) { @@ -1772,13 +1906,14 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) vcpu_load_rsp_rip(vcpu); set_cr8(vcpu, vcpu->regs[reg]); skip_emulated_instruction(vcpu); - return 1; + kvm_run->exit_reason = KVM_EXIT_SET_TPR; + return 0; }; break; case 2: /* clts */ vcpu_load_rsp_rip(vcpu); vmx_fpu_deactivate(vcpu); - vcpu->cr0 &= ~CR0_TS_MASK; + vcpu->cr0 &= ~X86_CR0_TS; vmcs_writel(CR0_READ_SHADOW, vcpu->cr0); vmx_fpu_activate(vcpu); skip_emulated_instruction(vcpu); @@ -1793,7 +1928,7 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) return 1; case 8: vcpu_load_rsp_rip(vcpu); - vcpu->regs[reg] = vcpu->cr8; + vcpu->regs[reg] = get_cr8(vcpu); vcpu_put_rsp_rip(vcpu); skip_emulated_instruction(vcpu); return 1; @@ -1808,14 +1943,14 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) break; } kvm_run->exit_reason = 0; - printk(KERN_ERR "kvm: unhandled control register: op %d cr %d\n", + pr_unimpl(vcpu, "unhandled control register: op %d cr %d\n", (int)(exit_qualification >> 4) & 3, cr); return 0; } static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { - u64 exit_qualification; + unsigned long exit_qualification; unsigned long val; int dr, reg; @@ -1823,7 +1958,7 @@ static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) * FIXME: this code assumes the host is debugging the guest. * need to deal with guest debugging itself too. */ - exit_qualification = vmcs_read64(EXIT_QUALIFICATION); + exit_qualification = vmcs_readl(EXIT_QUALIFICATION); dr = exit_qualification & 7; reg = (exit_qualification >> 8) & 15; vcpu_load_rsp_rip(vcpu); @@ -1886,19 +2021,21 @@ static int handle_wrmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) return 1; } -static void post_kvm_run_save(struct kvm_vcpu *vcpu, - struct kvm_run *kvm_run) +static int handle_tpr_below_threshold(struct kvm_vcpu *vcpu, + struct kvm_run *kvm_run) { - kvm_run->if_flag = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) != 0; - kvm_run->cr8 = vcpu->cr8; - kvm_run->apic_base = vcpu->apic_base; - kvm_run->ready_for_interrupt_injection = (vcpu->interrupt_window_open && - vcpu->irq_summary == 0); + return 1; } static int handle_interrupt_window(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { + u32 cpu_based_vm_exec_control; + + /* clear pending irq */ + cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL); + cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING; + vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); /* * If the user space waits to inject interrupts, exit as soon as * possible @@ -1943,6 +2080,7 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu, [EXIT_REASON_PENDING_INTERRUPT] = handle_interrupt_window, [EXIT_REASON_HLT] = handle_halt, [EXIT_REASON_VMCALL] = handle_vmcall, + [EXIT_REASON_TPR_BELOW_THRESHOLD] = handle_tpr_below_threshold }; static const int kvm_vmx_max_exit_handlers = @@ -1956,6 +2094,14 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) { u32 vectoring_info = vmcs_read32(IDT_VECTORING_INFO_FIELD); u32 exit_reason = vmcs_read32(VM_EXIT_REASON); + struct vcpu_vmx *vmx = to_vmx(vcpu); + + if (unlikely(vmx->fail)) { + kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY; + kvm_run->fail_entry.hardware_entry_failure_reason + = vmcs_read32(VM_INSTRUCTION_ERROR); + return 0; + } if ( (vectoring_info & VECTORING_INFO_VALID_MASK) && exit_reason != EXIT_REASON_EXCEPTION_NMI ) @@ -1971,57 +2117,91 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) return 0; } -/* - * Check if userspace requested an interrupt window, and that the - * interrupt window is open. - * - * No need to exit to userspace if we already have an interrupt queued. - */ -static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu, - struct kvm_run *kvm_run) +static void vmx_flush_tlb(struct kvm_vcpu *vcpu) { - return (!vcpu->irq_summary && - kvm_run->request_interrupt_window && - vcpu->interrupt_window_open && - (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF)); } -static void vmx_flush_tlb(struct kvm_vcpu *vcpu) +static void update_tpr_threshold(struct kvm_vcpu *vcpu) { + int max_irr, tpr; + + if (!vm_need_tpr_shadow(vcpu->kvm)) + return; + + if (!kvm_lapic_enabled(vcpu) || + ((max_irr = kvm_lapic_find_highest_irr(vcpu)) == -1)) { + vmcs_write32(TPR_THRESHOLD, 0); + return; + } + + tpr = (kvm_lapic_get_cr8(vcpu) & 0x0f) << 4; + vmcs_write32(TPR_THRESHOLD, (max_irr > tpr) ? tpr >> 4 : max_irr >> 4); } -static int vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static void enable_irq_window(struct kvm_vcpu *vcpu) { - u8 fail; - int r; + u32 cpu_based_vm_exec_control; -preempted: - if (vcpu->guest_debug.enabled) - kvm_guest_debug_pre(vcpu); + cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL); + cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING; + vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); +} -again: - if (!vcpu->mmio_read_completed) - do_interrupt_requests(vcpu, kvm_run); +static void vmx_intr_assist(struct kvm_vcpu *vcpu) +{ + u32 idtv_info_field, intr_info_field; + int has_ext_irq, interrupt_window_open; + int vector; - vmx_save_host_state(vcpu); - kvm_load_guest_fpu(vcpu); + kvm_inject_pending_timer_irqs(vcpu); + update_tpr_threshold(vcpu); - r = kvm_mmu_reload(vcpu); - if (unlikely(r)) - goto out; + has_ext_irq = kvm_cpu_has_interrupt(vcpu); + intr_info_field = vmcs_read32(VM_ENTRY_INTR_INFO_FIELD); + idtv_info_field = vmcs_read32(IDT_VECTORING_INFO_FIELD); + if (intr_info_field & INTR_INFO_VALID_MASK) { + if (idtv_info_field & INTR_INFO_VALID_MASK) { + /* TODO: fault when IDT_Vectoring */ + printk(KERN_ERR "Fault when IDT_Vectoring\n"); + } + if (has_ext_irq) + enable_irq_window(vcpu); + return; + } + if (unlikely(idtv_info_field & INTR_INFO_VALID_MASK)) { + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field); + vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, + vmcs_read32(VM_EXIT_INSTRUCTION_LEN)); + + if (unlikely(idtv_info_field & INTR_INFO_DELIEVER_CODE_MASK)) + vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, + vmcs_read32(IDT_VECTORING_ERROR_CODE)); + if (unlikely(has_ext_irq)) + enable_irq_window(vcpu); + return; + } + if (!has_ext_irq) + return; + interrupt_window_open = + ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) && + (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0); + if (interrupt_window_open) { + vector = kvm_cpu_get_interrupt(vcpu); + vmx_inject_irq(vcpu, vector); + kvm_timer_intr_post(vcpu, vector); + } else + enable_irq_window(vcpu); +} + +static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); /* * Loading guest fpu may have cleared host cr0.ts */ vmcs_writel(HOST_CR0, read_cr0()); - local_irq_disable(); - - vcpu->guest_mode = 1; - if (vcpu->requests) - if (test_and_clear_bit(KVM_TLB_FLUSH, &vcpu->requests)) - vmx_flush_tlb(vcpu); - asm ( /* Store host registers */ #ifdef CONFIG_X86_64 @@ -2115,8 +2295,8 @@ again: "pop %%ecx; popa \n\t" #endif "setbe %0 \n\t" - : "=q" (fail) - : "r"(vcpu->launched), "d"((unsigned long)HOST_RSP), + : "=q" (vmx->fail) + : "r"(vmx->launched), "d"((unsigned long)HOST_RSP), "c"(vcpu), [rax]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RAX])), [rbx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBX])), @@ -2138,59 +2318,10 @@ again: [cr2]"i"(offsetof(struct kvm_vcpu, cr2)) : "cc", "memory" ); - vcpu->guest_mode = 0; - local_irq_enable(); - - ++vcpu->stat.exits; - vcpu->interrupt_window_open = (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0; asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS)); - - if (unlikely(fail)) { - kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY; - kvm_run->fail_entry.hardware_entry_failure_reason - = vmcs_read32(VM_INSTRUCTION_ERROR); - r = 0; - goto out; - } - /* - * Profile KVM exit RIPs: - */ - if (unlikely(prof_on == KVM_PROFILING)) - profile_hit(KVM_PROFILING, (void *)vmcs_readl(GUEST_RIP)); - - vcpu->launched = 1; - r = kvm_handle_exit(kvm_run, vcpu); - if (r > 0) { - /* Give scheduler a change to reschedule. */ - if (signal_pending(current)) { - r = -EINTR; - kvm_run->exit_reason = KVM_EXIT_INTR; - ++vcpu->stat.signal_exits; - goto out; - } - - if (dm_request_for_irq_injection(vcpu, kvm_run)) { - r = -EINTR; - kvm_run->exit_reason = KVM_EXIT_INTR; - ++vcpu->stat.request_irq_exits; - goto out; - } - if (!need_resched()) { - ++vcpu->stat.light_exits; - goto again; - } - } - -out: - if (r > 0) { - kvm_resched(vcpu); - goto preempted; - } - - post_kvm_run_save(vcpu, kvm_run); - return r; + vmx->launched = 1; } static void vmx_inject_page_fault(struct kvm_vcpu *vcpu, @@ -2225,67 +2356,118 @@ static void vmx_inject_page_fault(struct kvm_vcpu *vcpu, static void vmx_free_vmcs(struct kvm_vcpu *vcpu) { - if (vcpu->vmcs) { - on_each_cpu(__vcpu_clear, vcpu, 0, 1); - free_vmcs(vcpu->vmcs); - vcpu->vmcs = NULL; + struct vcpu_vmx *vmx = to_vmx(vcpu); + + if (vmx->vmcs) { + on_each_cpu(__vcpu_clear, vmx, 0, 1); + free_vmcs(vmx->vmcs); + vmx->vmcs = NULL; } } static void vmx_free_vcpu(struct kvm_vcpu *vcpu) { + struct vcpu_vmx *vmx = to_vmx(vcpu); + vmx_free_vmcs(vcpu); + kfree(vmx->host_msrs); + kfree(vmx->guest_msrs); + kvm_vcpu_uninit(vcpu); + kmem_cache_free(kvm_vcpu_cache, vmx); } -static int vmx_create_vcpu(struct kvm_vcpu *vcpu) +static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id) { - struct vmcs *vmcs; + int err; + struct vcpu_vmx *vmx = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL); + int cpu; - vcpu->guest_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!vcpu->guest_msrs) - return -ENOMEM; + if (!vmx) + return ERR_PTR(-ENOMEM); - vcpu->host_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!vcpu->host_msrs) - goto out_free_guest_msrs; + err = kvm_vcpu_init(&vmx->vcpu, kvm, id); + if (err) + goto free_vcpu; - vmcs = alloc_vmcs(); - if (!vmcs) - goto out_free_msrs; + if (irqchip_in_kernel(kvm)) { + err = kvm_create_lapic(&vmx->vcpu); + if (err < 0) + goto free_vcpu; + } - vmcs_clear(vmcs); - vcpu->vmcs = vmcs; - vcpu->launched = 0; + vmx->guest_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!vmx->guest_msrs) { + err = -ENOMEM; + goto uninit_vcpu; + } - return 0; + vmx->host_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!vmx->host_msrs) + goto free_guest_msrs; -out_free_msrs: - kfree(vcpu->host_msrs); - vcpu->host_msrs = NULL; + vmx->vmcs = alloc_vmcs(); + if (!vmx->vmcs) + goto free_msrs; -out_free_guest_msrs: - kfree(vcpu->guest_msrs); - vcpu->guest_msrs = NULL; + vmcs_clear(vmx->vmcs); - return -ENOMEM; + cpu = get_cpu(); + vmx_vcpu_load(&vmx->vcpu, cpu); + err = vmx_vcpu_setup(vmx); + vmx_vcpu_put(&vmx->vcpu); + put_cpu(); + if (err) + goto free_vmcs; + + return &vmx->vcpu; + +free_vmcs: + free_vmcs(vmx->vmcs); +free_msrs: + kfree(vmx->host_msrs); +free_guest_msrs: + kfree(vmx->guest_msrs); +uninit_vcpu: + kvm_vcpu_uninit(&vmx->vcpu); +free_vcpu: + kmem_cache_free(kvm_vcpu_cache, vmx); + return ERR_PTR(err); +} + +static void __init vmx_check_processor_compat(void *rtn) +{ + struct vmcs_config vmcs_conf; + + *(int *)rtn = 0; + if (setup_vmcs_config(&vmcs_conf) < 0) + *(int *)rtn = -EIO; + if (memcmp(&vmcs_config, &vmcs_conf, sizeof(struct vmcs_config)) != 0) { + printk(KERN_ERR "kvm: CPU %d feature inconsistency!\n", + smp_processor_id()); + *(int *)rtn = -EIO; + } } -static struct kvm_arch_ops vmx_arch_ops = { +static struct kvm_x86_ops vmx_x86_ops = { .cpu_has_kvm_support = cpu_has_kvm_support, .disabled_by_bios = vmx_disabled_by_bios, .hardware_setup = hardware_setup, .hardware_unsetup = hardware_unsetup, + .check_processor_compatibility = vmx_check_processor_compat, .hardware_enable = hardware_enable, .hardware_disable = hardware_disable, .vcpu_create = vmx_create_vcpu, .vcpu_free = vmx_free_vcpu, + .vcpu_reset = vmx_vcpu_reset, + .prepare_guest_switch = vmx_save_host_state, .vcpu_load = vmx_vcpu_load, .vcpu_put = vmx_vcpu_put, .vcpu_decache = vmx_vcpu_decache, .set_guest_debug = set_guest_debug, + .guest_debug_pre = kvm_guest_debug_pre, .get_msr = vmx_get_msr, .set_msr = vmx_set_msr, .get_segment_base = vmx_get_segment_base, @@ -2314,9 +2496,13 @@ static struct kvm_arch_ops vmx_arch_ops = { .inject_gp = vmx_inject_gp, .run = vmx_vcpu_run, + .handle_exit = kvm_handle_exit, .skip_emulated_instruction = skip_emulated_instruction, - .vcpu_setup = vmx_vcpu_setup, .patch_hypercall = vmx_patch_hypercall, + .get_irq = vmx_get_irq, + .set_irq = vmx_inject_irq, + .inject_pending_irq = vmx_intr_assist, + .inject_pending_vectors = do_interrupt_requests, }; static int __init vmx_init(void) @@ -2347,7 +2533,7 @@ static int __init vmx_init(void) memset(iova, 0xff, PAGE_SIZE); kunmap(vmx_io_bitmap_b); - r = kvm_init_arch(&vmx_arch_ops, THIS_MODULE); + r = kvm_init_x86(&vmx_x86_ops, sizeof(struct vcpu_vmx), THIS_MODULE); if (r) goto out1; @@ -2365,7 +2551,7 @@ static void __exit vmx_exit(void) __free_page(vmx_io_bitmap_b); __free_page(vmx_io_bitmap_a); - kvm_exit_arch(); + kvm_exit_x86(); } module_init(vmx_init) diff --git a/drivers/kvm/vmx.h b/drivers/kvm/vmx.h index d0dc93df411b..fd4e14666088 100644 --- a/drivers/kvm/vmx.h +++ b/drivers/kvm/vmx.h @@ -25,29 +25,36 @@ * */ -#define CPU_BASED_VIRTUAL_INTR_PENDING 0x00000004 -#define CPU_BASED_USE_TSC_OFFSETING 0x00000008 -#define CPU_BASED_HLT_EXITING 0x00000080 -#define CPU_BASED_INVDPG_EXITING 0x00000200 -#define CPU_BASED_MWAIT_EXITING 0x00000400 -#define CPU_BASED_RDPMC_EXITING 0x00000800 -#define CPU_BASED_RDTSC_EXITING 0x00001000 -#define CPU_BASED_CR8_LOAD_EXITING 0x00080000 -#define CPU_BASED_CR8_STORE_EXITING 0x00100000 -#define CPU_BASED_TPR_SHADOW 0x00200000 -#define CPU_BASED_MOV_DR_EXITING 0x00800000 -#define CPU_BASED_UNCOND_IO_EXITING 0x01000000 -#define CPU_BASED_ACTIVATE_IO_BITMAP 0x02000000 -#define CPU_BASED_MSR_BITMAPS 0x10000000 -#define CPU_BASED_MONITOR_EXITING 0x20000000 -#define CPU_BASED_PAUSE_EXITING 0x40000000 +#define CPU_BASED_VIRTUAL_INTR_PENDING 0x00000004 +#define CPU_BASED_USE_TSC_OFFSETING 0x00000008 +#define CPU_BASED_HLT_EXITING 0x00000080 +#define CPU_BASED_INVLPG_EXITING 0x00000200 +#define CPU_BASED_MWAIT_EXITING 0x00000400 +#define CPU_BASED_RDPMC_EXITING 0x00000800 +#define CPU_BASED_RDTSC_EXITING 0x00001000 +#define CPU_BASED_CR8_LOAD_EXITING 0x00080000 +#define CPU_BASED_CR8_STORE_EXITING 0x00100000 +#define CPU_BASED_TPR_SHADOW 0x00200000 +#define CPU_BASED_MOV_DR_EXITING 0x00800000 +#define CPU_BASED_UNCOND_IO_EXITING 0x01000000 +#define CPU_BASED_USE_IO_BITMAPS 0x02000000 +#define CPU_BASED_USE_MSR_BITMAPS 0x10000000 +#define CPU_BASED_MONITOR_EXITING 0x20000000 +#define CPU_BASED_PAUSE_EXITING 0x40000000 +#define CPU_BASED_ACTIVATE_SECONDARY_CONTROLS 0x80000000 -#define PIN_BASED_EXT_INTR_MASK 0x1 -#define PIN_BASED_NMI_EXITING 0x8 +#define PIN_BASED_EXT_INTR_MASK 0x00000001 +#define PIN_BASED_NMI_EXITING 0x00000008 +#define PIN_BASED_VIRTUAL_NMIS 0x00000020 -#define VM_EXIT_ACK_INTR_ON_EXIT 0x00008000 -#define VM_EXIT_HOST_ADD_SPACE_SIZE 0x00000200 +#define VM_EXIT_HOST_ADDR_SPACE_SIZE 0x00000200 +#define VM_EXIT_ACK_INTR_ON_EXIT 0x00008000 +#define VM_ENTRY_IA32E_MODE 0x00000200 +#define VM_ENTRY_SMM 0x00000400 +#define VM_ENTRY_DEACT_DUAL_MONITOR 0x00000800 + +#define SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES 0x00000001 /* VMCS Encodings */ enum vmcs_field { @@ -206,6 +213,7 @@ enum vmcs_field { #define EXIT_REASON_MSR_READ 31 #define EXIT_REASON_MSR_WRITE 32 #define EXIT_REASON_MWAIT_INSTRUCTION 36 +#define EXIT_REASON_TPR_BELOW_THRESHOLD 43 /* * Interruption-information format @@ -261,9 +269,6 @@ enum vmcs_field { /* segment AR */ #define SEGMENT_AR_L_MASK (1 << 13) -/* entry controls */ -#define VM_ENTRY_CONTROLS_IA32E_MASK (1 << 9) - #define AR_TYPE_ACCESSES_MASK 1 #define AR_TYPE_READABLE_MASK (1 << 1) #define AR_TYPE_WRITEABLE_MASK (1 << 2) @@ -285,13 +290,21 @@ enum vmcs_field { #define AR_RESERVD_MASK 0xfffe0f00 -#define CR4_VMXE 0x2000 +#define MSR_IA32_VMX_BASIC 0x480 +#define MSR_IA32_VMX_PINBASED_CTLS 0x481 +#define MSR_IA32_VMX_PROCBASED_CTLS 0x482 +#define MSR_IA32_VMX_EXIT_CTLS 0x483 +#define MSR_IA32_VMX_ENTRY_CTLS 0x484 +#define MSR_IA32_VMX_MISC 0x485 +#define MSR_IA32_VMX_CR0_FIXED0 0x486 +#define MSR_IA32_VMX_CR0_FIXED1 0x487 +#define MSR_IA32_VMX_CR4_FIXED0 0x488 +#define MSR_IA32_VMX_CR4_FIXED1 0x489 +#define MSR_IA32_VMX_VMCS_ENUM 0x48a +#define MSR_IA32_VMX_PROCBASED_CTLS2 0x48b -#define MSR_IA32_VMX_BASIC 0x480 -#define MSR_IA32_FEATURE_CONTROL 0x03a -#define MSR_IA32_VMX_PINBASED_CTLS 0x481 -#define MSR_IA32_VMX_PROCBASED_CTLS 0x482 -#define MSR_IA32_VMX_EXIT_CTLS 0x483 -#define MSR_IA32_VMX_ENTRY_CTLS 0x484 +#define MSR_IA32_FEATURE_CONTROL 0x3a +#define MSR_IA32_FEATURE_CONTROL_LOCKED 0x1 +#define MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED 0x4 #endif diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c index 4b8a0cc9665e..9737c3b2f48c 100644 --- a/drivers/kvm/x86_emulate.c +++ b/drivers/kvm/x86_emulate.c @@ -6,7 +6,7 @@ * Copyright (c) 2005 Keir Fraser * * Linux coding style, mod r/m decoder, segment base fixes, real-mode - * privieged instructions: + * privileged instructions: * * Copyright (C) 2006 Qumranet * @@ -83,7 +83,7 @@ static u8 opcode_table[256] = { /* 0x20 - 0x27 */ ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, - 0, 0, 0, 0, + SrcImmByte, SrcImm, 0, 0, /* 0x28 - 0x2F */ ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, @@ -99,15 +99,24 @@ static u8 opcode_table[256] = { /* 0x40 - 0x4F */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x57 */ - 0, 0, 0, 0, 0, 0, 0, 0, + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, /* 0x58 - 0x5F */ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, - /* 0x60 - 0x6F */ + /* 0x60 - 0x67 */ 0, 0, 0, DstReg | SrcMem32 | ModRM | Mov /* movsxd (x86/64) */ , - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x70 - 0x7F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + /* 0x68 - 0x6F */ + 0, 0, ImplicitOps|Mov, 0, + SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, /* insb, insw/insd */ + SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, /* outsb, outsw/outsd */ + /* 0x70 - 0x77 */ + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, + /* 0x78 - 0x7F */ + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, /* 0x80 - 0x87 */ ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImmByte | ModRM, @@ -116,9 +125,9 @@ static u8 opcode_table[256] = { /* 0x88 - 0x8F */ ByteOp | DstMem | SrcReg | ModRM | Mov, DstMem | SrcReg | ModRM | Mov, ByteOp | DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, - 0, 0, 0, DstMem | SrcNone | ModRM | Mov, + 0, ModRM | DstReg, 0, DstMem | SrcNone | ModRM | Mov, /* 0x90 - 0x9F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps, ImplicitOps, 0, 0, /* 0xA0 - 0xA7 */ ByteOp | DstReg | SrcMem | Mov, DstReg | SrcMem | Mov, ByteOp | DstMem | SrcReg | Mov, DstMem | SrcReg | Mov, @@ -142,8 +151,10 @@ static u8 opcode_table[256] = { 0, 0, 0, 0, /* 0xD8 - 0xDF */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 0xE0 - 0xEF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xE0 - 0xE7 */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xE8 - 0xEF */ + ImplicitOps, SrcImm|ImplicitOps, 0, SrcImmByte|ImplicitOps, 0, 0, 0, 0, /* 0xF0 - 0xF7 */ 0, 0, 0, 0, ImplicitOps, 0, @@ -181,7 +192,10 @@ static u16 twobyte_table[256] = { /* 0x70 - 0x7F */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, /* 0x90 - 0x9F */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA0 - 0xA7 */ @@ -207,19 +221,6 @@ static u16 twobyte_table[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -/* - * Tell the emulator that of the Group 7 instructions (sgdt, lidt, etc.) we - * are interested only in invlpg and not in any of the rest. - * - * invlpg is a special instruction in that the data it references may not - * be mapped. - */ -void kvm_emulator_want_group7_invlpg(void) -{ - twobyte_table[1] &= ~SrcMem; -} -EXPORT_SYMBOL_GPL(kvm_emulator_want_group7_invlpg); - /* Type, address-of, and value of an instruction's operand. */ struct operand { enum { OP_REG, OP_MEM, OP_IMM } type; @@ -420,7 +421,7 @@ struct operand { #define insn_fetch(_type, _size, _eip) \ ({ unsigned long _x; \ rc = ops->read_std((unsigned long)(_eip) + ctxt->cs_base, &_x, \ - (_size), ctxt); \ + (_size), ctxt->vcpu); \ if ( rc != 0 ) \ goto done; \ (_eip) += (_size); \ @@ -428,10 +429,11 @@ struct operand { }) /* Access/update address held in a register, based on addressing mode. */ +#define address_mask(reg) \ + ((ad_bytes == sizeof(unsigned long)) ? \ + (reg) : ((reg) & ((1UL << (ad_bytes << 3)) - 1))) #define register_address(base, reg) \ - ((base) + ((ad_bytes == sizeof(unsigned long)) ? (reg) : \ - ((reg) & ((1UL << (ad_bytes << 3)) - 1)))) - + ((base) + address_mask(reg)) #define register_address_increment(reg, inc) \ do { \ /* signed type ensures sign extension to long */ \ @@ -443,8 +445,19 @@ struct operand { (((reg) + _inc) & ((1UL << (ad_bytes << 3)) - 1)); \ } while (0) -void *decode_register(u8 modrm_reg, unsigned long *regs, - int highbyte_regs) +#define JMP_REL(rel) \ + do { \ + _eip += (int)(rel); \ + _eip = ((op_bytes == 2) ? (uint16_t)_eip : (uint32_t)_eip); \ + } while (0) + +/* + * Given the 'reg' portion of a ModRM byte, and a register block, return a + * pointer into the block that addresses the relevant register. + * @highbyte_regs specifies whether to decode AH,CH,DH,BH. + */ +static void *decode_register(u8 modrm_reg, unsigned long *regs, + int highbyte_regs) { void *p; @@ -464,13 +477,50 @@ static int read_descriptor(struct x86_emulate_ctxt *ctxt, if (op_bytes == 2) op_bytes = 3; *address = 0; - rc = ops->read_std((unsigned long)ptr, (unsigned long *)size, 2, ctxt); + rc = ops->read_std((unsigned long)ptr, (unsigned long *)size, 2, + ctxt->vcpu); if (rc) return rc; - rc = ops->read_std((unsigned long)ptr + 2, address, op_bytes, ctxt); + rc = ops->read_std((unsigned long)ptr + 2, address, op_bytes, + ctxt->vcpu); return rc; } +static int test_cc(unsigned int condition, unsigned int flags) +{ + int rc = 0; + + switch ((condition & 15) >> 1) { + case 0: /* o */ + rc |= (flags & EFLG_OF); + break; + case 1: /* b/c/nae */ + rc |= (flags & EFLG_CF); + break; + case 2: /* z/e */ + rc |= (flags & EFLG_ZF); + break; + case 3: /* be/na */ + rc |= (flags & (EFLG_CF|EFLG_ZF)); + break; + case 4: /* s */ + rc |= (flags & EFLG_SF); + break; + case 5: /* p/pe */ + rc |= (flags & EFLG_PF); + break; + case 7: /* le/ng */ + rc |= (flags & EFLG_ZF); + /* fall through */ + case 6: /* l/nge */ + rc |= (!(flags & EFLG_SF) != !(flags & EFLG_OF)); + break; + } + + /* Odd condition identifiers (lsb == 1) have inverted sense. */ + return (!!rc ^ (condition & 1)); +} + int x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) { @@ -771,11 +821,15 @@ done_prefixes: goto srcmem_common; case SrcMem: src.bytes = (d & ByteOp) ? 1 : op_bytes; + /* Don't fetch the address for invlpg: it could be unmapped. */ + if (twobyte && b == 0x01 && modrm_reg == 7) + break; srcmem_common: src.type = OP_MEM; src.ptr = (unsigned long *)cr2; + src.val = 0; if ((rc = ops->read_emulated((unsigned long)src.ptr, - &src.val, src.bytes, ctxt)) != 0) + &src.val, src.bytes, ctxt->vcpu)) != 0) goto done; src.orig_val = src.val; break; @@ -814,7 +868,7 @@ done_prefixes: case DstReg: dst.type = OP_REG; if ((d & ByteOp) - && !(twobyte_table && (b == 0xb6 || b == 0xb7))) { + && !(twobyte && (b == 0xb6 || b == 0xb7))) { dst.ptr = decode_register(modrm_reg, _regs, (rex_prefix == 0)); dst.val = *(u8 *) dst.ptr; @@ -838,6 +892,7 @@ done_prefixes: dst.type = OP_MEM; dst.ptr = (unsigned long *)cr2; dst.bytes = (d & ByteOp) ? 1 : op_bytes; + dst.val = 0; if (d & BitOp) { unsigned long mask = ~(dst.bytes * 8 - 1); @@ -845,7 +900,7 @@ done_prefixes: } if (!(d & Mov) && /* optimisation - avoid slow emulated read */ ((rc = ops->read_emulated((unsigned long)dst.ptr, - &dst.val, dst.bytes, ctxt)) != 0)) + &dst.val, dst.bytes, ctxt->vcpu)) != 0)) goto done; break; } @@ -871,10 +926,27 @@ done_prefixes: sbb: /* sbb */ emulate_2op_SrcV("sbb", src, dst, _eflags); break; - case 0x20 ... 0x25: + case 0x20 ... 0x23: and: /* and */ emulate_2op_SrcV("and", src, dst, _eflags); break; + case 0x24: /* and al imm8 */ + dst.type = OP_REG; + dst.ptr = &_regs[VCPU_REGS_RAX]; + dst.val = *(u8 *)dst.ptr; + dst.bytes = 1; + dst.orig_val = dst.val; + goto and; + case 0x25: /* and ax imm16, or eax imm32 */ + dst.type = OP_REG; + dst.bytes = op_bytes; + dst.ptr = &_regs[VCPU_REGS_RAX]; + if (op_bytes == 2) + dst.val = *(u16 *)dst.ptr; + else + dst.val = *(u32 *)dst.ptr; + dst.orig_val = dst.val; + goto and; case 0x28 ... 0x2d: sub: /* sub */ emulate_2op_SrcV("sub", src, dst, _eflags); @@ -892,6 +964,17 @@ done_prefixes: goto cannot_emulate; dst.val = (s32) src.val; break; + case 0x6a: /* push imm8 */ + src.val = 0L; + src.val = insn_fetch(s8, 1, _eip); +push: + dst.type = OP_MEM; + dst.bytes = op_bytes; + dst.val = src.val; + register_address_increment(_regs[VCPU_REGS_RSP], -op_bytes); + dst.ptr = (void *) register_address(ctxt->ss_base, + _regs[VCPU_REGS_RSP]); + break; case 0x80 ... 0x83: /* Grp1 */ switch (modrm_reg) { case 0: @@ -939,18 +1022,10 @@ done_prefixes: dst.val = src.val; lock_prefix = 1; break; - case 0xa0 ... 0xa1: /* mov */ - dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX]; - dst.val = src.val; - _eip += ad_bytes; /* skip src displacement */ - break; - case 0xa2 ... 0xa3: /* mov */ - dst.val = (unsigned long)_regs[VCPU_REGS_RAX]; - _eip += ad_bytes; /* skip dst displacement */ - break; case 0x88 ... 0x8b: /* mov */ - case 0xc6 ... 0xc7: /* mov (sole member of Grp11) */ - dst.val = src.val; + goto mov; + case 0x8d: /* lea r16/r32, m */ + dst.val = modrm_val; break; case 0x8f: /* pop (sole member of Grp1a) */ /* 64-bit mode: POP always pops a 64-bit operand. */ @@ -958,10 +1033,19 @@ done_prefixes: dst.bytes = 8; if ((rc = ops->read_std(register_address(ctxt->ss_base, _regs[VCPU_REGS_RSP]), - &dst.val, dst.bytes, ctxt)) != 0) + &dst.val, dst.bytes, ctxt->vcpu)) != 0) goto done; register_address_increment(_regs[VCPU_REGS_RSP], dst.bytes); break; + case 0xa0 ... 0xa1: /* mov */ + dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX]; + dst.val = src.val; + _eip += ad_bytes; /* skip src displacement */ + break; + case 0xa2 ... 0xa3: /* mov */ + dst.val = (unsigned long)_regs[VCPU_REGS_RAX]; + _eip += ad_bytes; /* skip dst displacement */ + break; case 0xc0 ... 0xc1: grp2: /* Grp2 */ switch (modrm_reg) { @@ -989,12 +1073,41 @@ done_prefixes: break; } break; + case 0xc6 ... 0xc7: /* mov (sole member of Grp11) */ + mov: + dst.val = src.val; + break; case 0xd0 ... 0xd1: /* Grp2 */ src.val = 1; goto grp2; case 0xd2 ... 0xd3: /* Grp2 */ src.val = _regs[VCPU_REGS_RCX]; goto grp2; + case 0xe8: /* call (near) */ { + long int rel; + switch (op_bytes) { + case 2: + rel = insn_fetch(s16, 2, _eip); + break; + case 4: + rel = insn_fetch(s32, 4, _eip); + break; + case 8: + rel = insn_fetch(s64, 8, _eip); + break; + default: + DPRINTF("Call: Invalid op_bytes\n"); + goto cannot_emulate; + } + src.val = (unsigned long) _eip; + JMP_REL(rel); + goto push; + } + case 0xe9: /* jmp rel */ + case 0xeb: /* jmp rel short */ + JMP_REL(src.val); + no_wb = 1; /* Disable writeback. */ + break; case 0xf6 ... 0xf7: /* Grp3 */ switch (modrm_reg) { case 0 ... 1: /* test */ @@ -1037,13 +1150,19 @@ done_prefixes: case 1: /* dec */ emulate_1op("dec", dst, _eflags); break; + case 4: /* jmp abs */ + if (b == 0xff) + _eip = dst.val; + else + goto cannot_emulate; + break; case 6: /* push */ /* 64-bit mode: PUSH always pushes a 64-bit operand. */ if (mode == X86EMUL_MODE_PROT64) { dst.bytes = 8; if ((rc = ops->read_std((unsigned long)dst.ptr, &dst.val, 8, - ctxt)) != 0) + ctxt->vcpu)) != 0) goto done; } register_address_increment(_regs[VCPU_REGS_RSP], @@ -1051,7 +1170,7 @@ done_prefixes: if ((rc = ops->write_std( register_address(ctxt->ss_base, _regs[VCPU_REGS_RSP]), - &dst.val, dst.bytes, ctxt)) != 0) + &dst.val, dst.bytes, ctxt->vcpu)) != 0) goto done; no_wb = 1; break; @@ -1086,11 +1205,11 @@ writeback: rc = ops->cmpxchg_emulated((unsigned long)dst. ptr, &dst.orig_val, &dst.val, dst.bytes, - ctxt); + ctxt->vcpu); else rc = ops->write_emulated((unsigned long)dst.ptr, &dst.val, dst.bytes, - ctxt); + ctxt->vcpu); if (rc != 0) goto done; default: @@ -1109,6 +1228,81 @@ done: special_insn: if (twobyte) goto twobyte_special_insn; + switch(b) { + case 0x50 ... 0x57: /* push reg */ + if (op_bytes == 2) + src.val = (u16) _regs[b & 0x7]; + else + src.val = (u32) _regs[b & 0x7]; + dst.type = OP_MEM; + dst.bytes = op_bytes; + dst.val = src.val; + register_address_increment(_regs[VCPU_REGS_RSP], -op_bytes); + dst.ptr = (void *) register_address( + ctxt->ss_base, _regs[VCPU_REGS_RSP]); + break; + case 0x58 ... 0x5f: /* pop reg */ + dst.ptr = (unsigned long *)&_regs[b & 0x7]; + pop_instruction: + if ((rc = ops->read_std(register_address(ctxt->ss_base, + _regs[VCPU_REGS_RSP]), dst.ptr, op_bytes, ctxt->vcpu)) + != 0) + goto done; + + register_address_increment(_regs[VCPU_REGS_RSP], op_bytes); + no_wb = 1; /* Disable writeback. */ + break; + case 0x6c: /* insb */ + case 0x6d: /* insw/insd */ + if (kvm_emulate_pio_string(ctxt->vcpu, NULL, + 1, /* in */ + (d & ByteOp) ? 1 : op_bytes, /* size */ + rep_prefix ? + address_mask(_regs[VCPU_REGS_RCX]) : 1, /* count */ + (_eflags & EFLG_DF), /* down */ + register_address(ctxt->es_base, + _regs[VCPU_REGS_RDI]), /* address */ + rep_prefix, + _regs[VCPU_REGS_RDX] /* port */ + ) == 0) + return -1; + return 0; + case 0x6e: /* outsb */ + case 0x6f: /* outsw/outsd */ + if (kvm_emulate_pio_string(ctxt->vcpu, NULL, + 0, /* in */ + (d & ByteOp) ? 1 : op_bytes, /* size */ + rep_prefix ? + address_mask(_regs[VCPU_REGS_RCX]) : 1, /* count */ + (_eflags & EFLG_DF), /* down */ + register_address(override_base ? + *override_base : ctxt->ds_base, + _regs[VCPU_REGS_RSI]), /* address */ + rep_prefix, + _regs[VCPU_REGS_RDX] /* port */ + ) == 0) + return -1; + return 0; + case 0x70 ... 0x7f: /* jcc (short) */ { + int rel = insn_fetch(s8, 1, _eip); + + if (test_cc(b, _eflags)) + JMP_REL(rel); + break; + } + case 0x9c: /* pushf */ + src.val = (unsigned long) _eflags; + goto push; + case 0x9d: /* popf */ + dst.ptr = (unsigned long *) &_eflags; + goto pop_instruction; + case 0xc3: /* ret */ + dst.ptr = &_eip; + goto pop_instruction; + case 0xf4: /* hlt */ + ctxt->vcpu->halt_request = 1; + goto done; + } if (rep_prefix) { if (_regs[VCPU_REGS_RCX] == 0) { ctxt->vcpu->rip = _eip; @@ -1125,7 +1319,7 @@ special_insn: _regs[VCPU_REGS_RDI]); if ((rc = ops->read_emulated(register_address( override_base ? *override_base : ctxt->ds_base, - _regs[VCPU_REGS_RSI]), &dst.val, dst.bytes, ctxt)) != 0) + _regs[VCPU_REGS_RSI]), &dst.val, dst.bytes, ctxt->vcpu)) != 0) goto done; register_address_increment(_regs[VCPU_REGS_RSI], (_eflags & EFLG_DF) ? -dst.bytes : dst.bytes); @@ -1147,7 +1341,8 @@ special_insn: dst.type = OP_REG; dst.bytes = (d & ByteOp) ? 1 : op_bytes; dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX]; - if ((rc = ops->read_emulated(cr2, &dst.val, dst.bytes, ctxt)) != 0) + if ((rc = ops->read_emulated(cr2, &dst.val, dst.bytes, + ctxt->vcpu)) != 0) goto done; register_address_increment(_regs[VCPU_REGS_RSI], (_eflags & EFLG_DF) ? -dst.bytes : dst.bytes); @@ -1155,23 +1350,7 @@ special_insn: case 0xae ... 0xaf: /* scas */ DPRINTF("Urk! I don't handle SCAS.\n"); goto cannot_emulate; - case 0xf4: /* hlt */ - ctxt->vcpu->halt_request = 1; - goto done; - case 0xc3: /* ret */ - dst.ptr = &_eip; - goto pop_instruction; - case 0x58 ... 0x5f: /* pop reg */ - dst.ptr = (unsigned long *)&_regs[b & 0x7]; -pop_instruction: - if ((rc = ops->read_std(register_address(ctxt->ss_base, - _regs[VCPU_REGS_RSP]), dst.ptr, op_bytes, ctxt)) != 0) - goto done; - - register_address_increment(_regs[VCPU_REGS_RSP], op_bytes); - no_wb = 1; /* Disable writeback. */ - break; } goto writeback; @@ -1230,40 +1409,50 @@ twobyte_insn: break; case 0x40 ... 0x4f: /* cmov */ dst.val = dst.orig_val = src.val; - d &= ~Mov; /* default to no move */ + no_wb = 1; /* * First, assume we're decoding an even cmov opcode * (lsb == 0). */ switch ((b & 15) >> 1) { case 0: /* cmovo */ - d |= (_eflags & EFLG_OF) ? Mov : 0; + no_wb = (_eflags & EFLG_OF) ? 0 : 1; break; case 1: /* cmovb/cmovc/cmovnae */ - d |= (_eflags & EFLG_CF) ? Mov : 0; + no_wb = (_eflags & EFLG_CF) ? 0 : 1; break; case 2: /* cmovz/cmove */ - d |= (_eflags & EFLG_ZF) ? Mov : 0; + no_wb = (_eflags & EFLG_ZF) ? 0 : 1; break; case 3: /* cmovbe/cmovna */ - d |= (_eflags & (EFLG_CF | EFLG_ZF)) ? Mov : 0; + no_wb = (_eflags & (EFLG_CF | EFLG_ZF)) ? 0 : 1; break; case 4: /* cmovs */ - d |= (_eflags & EFLG_SF) ? Mov : 0; + no_wb = (_eflags & EFLG_SF) ? 0 : 1; break; case 5: /* cmovp/cmovpe */ - d |= (_eflags & EFLG_PF) ? Mov : 0; + no_wb = (_eflags & EFLG_PF) ? 0 : 1; break; case 7: /* cmovle/cmovng */ - d |= (_eflags & EFLG_ZF) ? Mov : 0; + no_wb = (_eflags & EFLG_ZF) ? 0 : 1; /* fall through */ case 6: /* cmovl/cmovnge */ - d |= (!(_eflags & EFLG_SF) != - !(_eflags & EFLG_OF)) ? Mov : 0; + no_wb &= (!(_eflags & EFLG_SF) != + !(_eflags & EFLG_OF)) ? 0 : 1; break; } /* Odd cmov opcodes (lsb == 1) have inverted sense. */ - d ^= (b & 1) ? Mov : 0; + no_wb ^= b & 1; + break; + case 0xa3: + bt: /* bt */ + src.val &= (dst.bytes << 3) - 1; /* only subword offset */ + emulate_2op_SrcV_nobyte("bt", src, dst, _eflags); + break; + case 0xab: + bts: /* bts */ + src.val &= (dst.bytes << 3) - 1; /* only subword offset */ + emulate_2op_SrcV_nobyte("bts", src, dst, _eflags); break; case 0xb0 ... 0xb1: /* cmpxchg */ /* @@ -1273,8 +1462,6 @@ twobyte_insn: src.orig_val = src.val; src.val = _regs[VCPU_REGS_RAX]; emulate_2op_SrcV("cmp", src, dst, _eflags); - /* Always write back. The question is: where to? */ - d |= Mov; if (_eflags & EFLG_ZF) { /* Success: write back to memory. */ dst.val = src.orig_val; @@ -1284,30 +1471,15 @@ twobyte_insn: dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX]; } break; - case 0xa3: - bt: /* bt */ - src.val &= (dst.bytes << 3) - 1; /* only subword offset */ - emulate_2op_SrcV_nobyte("bt", src, dst, _eflags); - break; case 0xb3: btr: /* btr */ src.val &= (dst.bytes << 3) - 1; /* only subword offset */ emulate_2op_SrcV_nobyte("btr", src, dst, _eflags); break; - case 0xab: - bts: /* bts */ - src.val &= (dst.bytes << 3) - 1; /* only subword offset */ - emulate_2op_SrcV_nobyte("bts", src, dst, _eflags); - break; case 0xb6 ... 0xb7: /* movzx */ dst.bytes = op_bytes; dst.val = (d & ByteOp) ? (u8) src.val : (u16) src.val; break; - case 0xbb: - btc: /* btc */ - src.val &= (dst.bytes << 3) - 1; /* only subword offset */ - emulate_2op_SrcV_nobyte("btc", src, dst, _eflags); - break; case 0xba: /* Grp8 */ switch (modrm_reg & 3) { case 0: @@ -1320,6 +1492,11 @@ twobyte_insn: goto btc; } break; + case 0xbb: + btc: /* btc */ + src.val &= (dst.bytes << 3) - 1; /* only subword offset */ + emulate_2op_SrcV_nobyte("btc", src, dst, _eflags); + break; case 0xbe ... 0xbf: /* movsx */ dst.bytes = op_bytes; dst.val = (d & ByteOp) ? (s8) src.val : (s16) src.val; @@ -1331,14 +1508,14 @@ twobyte_special_insn: /* Disable writeback. */ no_wb = 1; switch (b) { + case 0x06: + emulate_clts(ctxt->vcpu); + break; case 0x09: /* wbinvd */ break; case 0x0d: /* GrpP (prefetch) */ case 0x18: /* Grp16 (prefetch/nop) */ break; - case 0x06: - emulate_clts(ctxt->vcpu); - break; case 0x20: /* mov cr, reg */ if (modrm_mod != 3) goto cannot_emulate; @@ -1355,7 +1532,7 @@ twobyte_special_insn: | ((u64)_regs[VCPU_REGS_RDX] << 32); rc = kvm_set_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], msr_data); if (rc) { - kvm_arch_ops->inject_gp(ctxt->vcpu, 0); + kvm_x86_ops->inject_gp(ctxt->vcpu, 0); _eip = ctxt->vcpu->rip; } rc = X86EMUL_CONTINUE; @@ -1364,7 +1541,7 @@ twobyte_special_insn: /* rdmsr */ rc = kvm_get_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], &msr_data); if (rc) { - kvm_arch_ops->inject_gp(ctxt->vcpu, 0); + kvm_x86_ops->inject_gp(ctxt->vcpu, 0); _eip = ctxt->vcpu->rip; } else { _regs[VCPU_REGS_RAX] = (u32)msr_data; @@ -1372,10 +1549,32 @@ twobyte_special_insn: } rc = X86EMUL_CONTINUE; break; + case 0x80 ... 0x8f: /* jnz rel, etc*/ { + long int rel; + + switch (op_bytes) { + case 2: + rel = insn_fetch(s16, 2, _eip); + break; + case 4: + rel = insn_fetch(s32, 4, _eip); + break; + case 8: + rel = insn_fetch(s64, 8, _eip); + break; + default: + DPRINTF("jnz: Invalid op_bytes\n"); + goto cannot_emulate; + } + if (test_cc(b, _eflags)) + JMP_REL(rel); + break; + } case 0xc7: /* Grp9 (cmpxchg8b) */ { u64 old, new; - if ((rc = ops->read_emulated(cr2, &old, 8, ctxt)) != 0) + if ((rc = ops->read_emulated(cr2, &old, 8, ctxt->vcpu)) + != 0) goto done; if (((u32) (old >> 0) != (u32) _regs[VCPU_REGS_RAX]) || ((u32) (old >> 32) != (u32) _regs[VCPU_REGS_RDX])) { @@ -1386,7 +1585,7 @@ twobyte_special_insn: new = ((u64)_regs[VCPU_REGS_RCX] << 32) | (u32) _regs[VCPU_REGS_RBX]; if ((rc = ops->cmpxchg_emulated(cr2, &old, - &new, 8, ctxt)) != 0) + &new, 8, ctxt->vcpu)) != 0) goto done; _eflags |= EFLG_ZF; } diff --git a/drivers/kvm/x86_emulate.h b/drivers/kvm/x86_emulate.h index ea3407d7feee..92c73aa7f9ac 100644 --- a/drivers/kvm/x86_emulate.h +++ b/drivers/kvm/x86_emulate.h @@ -60,7 +60,7 @@ struct x86_emulate_ops { * @bytes: [IN ] Number of bytes to read from memory. */ int (*read_std)(unsigned long addr, void *val, - unsigned int bytes, struct x86_emulate_ctxt * ctxt); + unsigned int bytes, struct kvm_vcpu *vcpu); /* * write_std: Write bytes of standard (non-emulated/special) memory. @@ -71,7 +71,7 @@ struct x86_emulate_ops { * @bytes: [IN ] Number of bytes to write to memory. */ int (*write_std)(unsigned long addr, const void *val, - unsigned int bytes, struct x86_emulate_ctxt * ctxt); + unsigned int bytes, struct kvm_vcpu *vcpu); /* * read_emulated: Read bytes from emulated/special memory area. @@ -82,7 +82,7 @@ struct x86_emulate_ops { int (*read_emulated) (unsigned long addr, void *val, unsigned int bytes, - struct x86_emulate_ctxt * ctxt); + struct kvm_vcpu *vcpu); /* * write_emulated: Read bytes from emulated/special memory area. @@ -94,7 +94,7 @@ struct x86_emulate_ops { int (*write_emulated) (unsigned long addr, const void *val, unsigned int bytes, - struct x86_emulate_ctxt * ctxt); + struct kvm_vcpu *vcpu); /* * cmpxchg_emulated: Emulate an atomic (LOCKed) CMPXCHG operation on an @@ -108,12 +108,10 @@ struct x86_emulate_ops { const void *old, const void *new, unsigned int bytes, - struct x86_emulate_ctxt * ctxt); + struct kvm_vcpu *vcpu); }; -struct cpu_user_regs; - struct x86_emulate_ctxt { /* Register state before/after emulation. */ struct kvm_vcpu *vcpu; @@ -154,12 +152,4 @@ struct x86_emulate_ctxt { int x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops); -/* - * Given the 'reg' portion of a ModRM byte, and a register block, return a - * pointer into the block that addresses the relevant register. - * @highbyte_regs specifies whether to decode AH,CH,DH,BH. - */ -void *decode_register(u8 modrm_reg, unsigned long *regs, - int highbyte_regs); - #endif /* __X86_EMULATE_H__ */ diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig index 56cd8998fe4b..77f50b63a970 100644 --- a/drivers/macintosh/Kconfig +++ b/drivers/macintosh/Kconfig @@ -172,6 +172,7 @@ config INPUT_ADBHID config MAC_EMUMOUSEBTN bool "Support for mouse button 2+3 emulation" + select INPUT help This provides generic support for emulating the 2nd and 3rd mouse button with keypresses. If you say Y here, the emulation is still diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c index 48d17bf6c927..8cce016b3d09 100644 --- a/drivers/macintosh/adbhid.c +++ b/drivers/macintosh/adbhid.c @@ -52,6 +52,11 @@ MODULE_AUTHOR("Franz Sirl <Franz.Sirl-kernel@lauterbach.com>"); +static int restore_capslock_events; +module_param(restore_capslock_events, int, 0644); +MODULE_PARM_DESC(restore_capslock_events, + "Produce keypress events for capslock on both keyup and keydown."); + #define KEYB_KEYREG 0 /* register # for key up/down data */ #define KEYB_LEDREG 2 /* register # for leds on ADB keyboard */ #define MOUSE_DATAREG 0 /* reg# for movement/button codes from mouse */ @@ -217,6 +222,8 @@ struct adbhid { #define FLAG_FN_KEY_PRESSED 0x00000001 #define FLAG_POWER_FROM_FN 0x00000002 #define FLAG_EMU_FWDEL_DOWN 0x00000004 +#define FLAG_CAPSLOCK_TRANSLATE 0x00000008 +#define FLAG_CAPSLOCK_DOWN 0x00000010 static struct adbhid *adbhid[16]; @@ -272,19 +279,50 @@ adbhid_keyboard_input(unsigned char *data, int nb, int apoll) } static void -adbhid_input_keycode(int id, int keycode, int repeat) +adbhid_input_keycode(int id, int scancode, int repeat) { struct adbhid *ahid = adbhid[id]; - int up_flag, key; - - up_flag = (keycode & 0x80); - keycode &= 0x7f; + int keycode, up_flag; + + keycode = scancode & 0x7f; + up_flag = scancode & 0x80; + + if (restore_capslock_events) { + if (keycode == ADB_KEY_CAPSLOCK && !up_flag) { + /* Key pressed, turning on the CapsLock LED. + * The next 0xff will be interpreted as a release. */ + ahid->flags |= FLAG_CAPSLOCK_TRANSLATE + | FLAG_CAPSLOCK_DOWN; + } else if (scancode == 0xff) { + /* Scancode 0xff usually signifies that the capslock + * key was either pressed or released. */ + if (ahid->flags & FLAG_CAPSLOCK_TRANSLATE) { + keycode = ADB_KEY_CAPSLOCK; + if (ahid->flags & FLAG_CAPSLOCK_DOWN) { + /* Key released */ + up_flag = 1; + ahid->flags &= ~FLAG_CAPSLOCK_DOWN; + } else { + /* Key pressed */ + up_flag = 0; + ahid->flags &= ~FLAG_CAPSLOCK_TRANSLATE; + } + } else { + printk(KERN_INFO "Spurious caps lock event " + "(scancode 0xff)."); + } + } + } switch (keycode) { - case ADB_KEY_CAPSLOCK: /* Generate down/up events for CapsLock everytime. */ - input_report_key(ahid->input, KEY_CAPSLOCK, 1); - input_report_key(ahid->input, KEY_CAPSLOCK, 0); - input_sync(ahid->input); + case ADB_KEY_CAPSLOCK: + if (!restore_capslock_events) { + /* Generate down/up events for CapsLock everytime. */ + input_report_key(ahid->input, KEY_CAPSLOCK, 1); + input_sync(ahid->input); + input_report_key(ahid->input, KEY_CAPSLOCK, 0); + input_sync(ahid->input); + } return; #ifdef CONFIG_PPC_PMAC case ADB_KEY_POWER_OLD: /* Power key on PBook 3400 needs remapping */ @@ -296,7 +334,7 @@ adbhid_input_keycode(int id, int keycode, int repeat) keycode = ADB_KEY_POWER; } break; - case ADB_KEY_POWER: + case ADB_KEY_POWER: /* Fn + Command will produce a bogus "power" keycode */ if (ahid->flags & FLAG_FN_KEY_PRESSED) { keycode = ADB_KEY_CMD; diff --git a/drivers/md/dm-emc.c b/drivers/md/dm-emc.c index a2191a4fcf77..342517261ece 100644 --- a/drivers/md/dm-emc.c +++ b/drivers/md/dm-emc.c @@ -54,8 +54,6 @@ static void emc_endio(struct bio *bio, int error) /* request is freed in block layer */ free_bio(bio); - - return 0; } static struct bio *get_failover_bio(struct dm_path *path, unsigned data_size) diff --git a/drivers/md/md.c b/drivers/md/md.c index e8f102ea9b03..acf1b81b47cb 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3076,8 +3076,7 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data) mddev->gendisk = disk; mutex_unlock(&disks_mutex); mddev->kobj.parent = &disk->kobj; - mddev->kobj.k_name = NULL; - snprintf(mddev->kobj.name, KOBJ_NAME_LEN, "%s", "md"); + kobject_set_name(&mddev->kobj, "%s", "md"); mddev->kobj.ktype = &md_ktype; if (kobject_register(&mddev->kobj)) printk(KERN_WARNING "md: cannot register %s/md - name in use\n", diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index 56231d8edc07..18738faecbbc 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -103,10 +103,7 @@ static struct file_operations dvb_device_fops = .open = dvb_device_open, }; -static struct cdev dvb_device_cdev = { - .kobj = {.name = "dvb", }, - .owner = THIS_MODULE, -}; +static struct cdev dvb_device_cdev; int dvb_generic_open(struct inode *inode, struct file *file) { diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c index 844f1762c45a..4d5b8035e466 100644 --- a/drivers/media/video/bt8xx/bttv-i2c.c +++ b/drivers/media/video/bt8xx/bttv-i2c.c @@ -124,12 +124,6 @@ static struct i2c_adapter bttv_i2c_adap_sw_template = { /* ----------------------------------------------------------------------- */ /* I2C functions - hardware i2c */ -static int algo_control(struct i2c_adapter *adapter, - unsigned int cmd, unsigned long arg) -{ - return 0; -} - static u32 functionality(struct i2c_adapter *adap) { return I2C_FUNC_SMBUS_EMUL; @@ -278,7 +272,6 @@ static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int static struct i2c_algorithm bttv_algo = { .master_xfer = bttv_i2c_xfer, - .algo_control = algo_control, .functionality = functionality, }; diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index b517c8b5a566..71da528932df 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -272,12 +272,6 @@ void cx23885_call_i2c_clients(struct cx23885_i2c *bus, i2c_clients_command(&bus->i2c_adap, cmd, arg); } -static int cx23885_algo_control(struct i2c_adapter *adap, - unsigned int cmd, unsigned long arg) -{ - return 0; -} - static u32 cx23885_functionality(struct i2c_adapter *adap) { return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; @@ -285,7 +279,6 @@ static u32 cx23885_functionality(struct i2c_adapter *adap) static struct i2c_algorithm cx23885_i2c_algo_template = { .master_xfer = i2c_xfer, - .algo_control = cx23885_algo_control, .functionality = cx23885_functionality, }; diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c index 54ccc6e1f92e..997d067e32e0 100644 --- a/drivers/media/video/em28xx/em28xx-i2c.c +++ b/drivers/media/video/em28xx/em28xx-i2c.c @@ -383,15 +383,6 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) /* ----------------------------------------------------------- */ /* - * algo_control() - */ -static int algo_control(struct i2c_adapter *adapter, - unsigned int cmd, unsigned long arg) -{ - return 0; -} - -/* * functionality() */ static u32 functionality(struct i2c_adapter *adap) @@ -475,7 +466,6 @@ static int attach_inform(struct i2c_client *client) static struct i2c_algorithm em28xx_algo = { .master_xfer = em28xx_i2c_xfer, - .algo_control = algo_control, .functionality = functionality, }; diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 511a66252413..fd7a932e1d33 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -98,9 +98,9 @@ static int radio[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; -static int cardtype_c = 1; -static int tuner_c = 1; -static int radio_c = 1; +static unsigned int cardtype_c = 1; +static unsigned int tuner_c = 1; +static unsigned int radio_c = 1; static char pal[] = "--"; static char secam[] = "--"; static char ntsc[] = "-"; diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c index 9eb2562347a8..b8d4ac0d938e 100644 --- a/drivers/media/video/ov511.c +++ b/drivers/media/video/ov511.c @@ -181,7 +181,7 @@ module_param(force_palette, int, 0); MODULE_PARM_DESC(force_palette, "Force the palette to a specific value"); module_param(backlight, int, 0); MODULE_PARM_DESC(backlight, "For objects that are lit from behind"); -static int num_uv; +static unsigned int num_uv; module_param_array(unit_video, int, &num_uv, 0); MODULE_PARM_DESC(unit_video, "Force use of specific minor number(s). 0 is not allowed."); diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c index 898c9d2e4cdf..c817c864e6a0 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c @@ -520,12 +520,6 @@ static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap, return ret; } -static int pvr2_i2c_control(struct i2c_adapter *adapter, - unsigned int cmd, unsigned long arg) -{ - return 0; -} - static u32 pvr2_i2c_functionality(struct i2c_adapter *adap) { return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; @@ -942,7 +936,6 @@ static int pvr2_i2c_detach_inform(struct i2c_client *client) static struct i2c_algorithm pvr2_i2c_algo_template = { .master_xfer = pvr2_i2c_xfer, - .algo_control = pvr2_i2c_control, .functionality = pvr2_i2c_functionality, }; diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index 7a78d6b34738..2ee3c3049e8f 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c @@ -905,8 +905,8 @@ struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *mp, } -static int pvr2_sysfs_hotplug(struct device *cd,char **envp, - int numenvp,char *buf,int size) +static int pvr2_sysfs_hotplug(struct device *d, + struct kobj_uevent_env *env) { /* Even though we don't do anything here, we still need this function because sysfs will still try to call it. */ diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 0b67d4ec0318..950da2542148 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -1903,9 +1903,9 @@ static int fbufs; static int mbufs; static int compression = -1; static int leds[2] = { -1, -1 }; -static int leds_nargs; +static unsigned int leds_nargs; static char *dev_hint[MAX_DEV_HINTS]; -static int dev_hint_nargs; +static unsigned int dev_hint_nargs; module_param(size, charp, 0444); module_param(fps, int, 0444); diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c index cc87f5855a21..6deaad1a5480 100644 --- a/drivers/media/video/saa7134/saa7134-i2c.c +++ b/drivers/media/video/saa7134/saa7134-i2c.c @@ -314,12 +314,6 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap, /* ----------------------------------------------------------- */ -static int algo_control(struct i2c_adapter *adapter, - unsigned int cmd, unsigned long arg) -{ - return 0; -} - static u32 functionality(struct i2c_adapter *adap) { return I2C_FUNC_SMBUS_EMUL; @@ -387,7 +381,6 @@ static int attach_inform(struct i2c_client *client) static struct i2c_algorithm saa7134_algo = { .master_xfer = saa7134_i2c_xfer, - .algo_control = algo_control, .functionality = functionality, }; diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c index c66aef63916f..aabc42cae9c7 100644 --- a/drivers/media/video/usbvision/usbvision-i2c.c +++ b/drivers/media/video/usbvision/usbvision-i2c.c @@ -183,11 +183,6 @@ usbvision_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) return num; } -static int algo_control(struct i2c_adapter *adapter, unsigned int cmd, unsigned long arg) -{ - return 0; -} - static u32 functionality(struct i2c_adapter *adap) { return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR; @@ -199,7 +194,6 @@ static u32 functionality(struct i2c_adapter *adap) static struct i2c_algorithm usbvision_algo = { .master_xfer = usbvision_i2c_xfer, .smbus_xfer = NULL, - .algo_control = algo_control, .functionality = functionality, }; diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index c606332512b6..5599a36490fc 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -674,7 +674,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q, } /* Copy to userspace */ - retval=CALL(q,copy_to_user,q,data,count,nonblocking); + retval=CALL(q,video_copy_to_user,q,data,count,nonblocking); if (retval<0) goto done; diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c index 8bb7fdd306d6..3eb6123227b2 100644 --- a/drivers/media/video/videobuf-dma-sg.c +++ b/drivers/media/video/videobuf-dma-sg.c @@ -670,7 +670,7 @@ static struct videobuf_qtype_ops pci_ops = { .sync = __videobuf_sync, .mmap_free = __videobuf_mmap_free, .mmap_mapper = __videobuf_mmap_mapper, - .copy_to_user = __videobuf_copy_to_user, + .video_copy_to_user = __videobuf_copy_to_user, .copy_stream = __videobuf_copy_stream, }; diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c index 2e3689a12a28..cd74341c984f 100644 --- a/drivers/media/video/videobuf-vmalloc.c +++ b/drivers/media/video/videobuf-vmalloc.c @@ -320,7 +320,7 @@ static struct videobuf_qtype_ops qops = { .sync = __videobuf_sync, .mmap_free = __videobuf_mmap_free, .mmap_mapper = __videobuf_mmap_mapper, - .copy_to_user = __videobuf_copy_to_user, + .video_copy_to_user = __videobuf_copy_to_user, .copy_stream = __videobuf_copy_stream, }; diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c index 5a1b5f5a7d46..9e7f3e685d73 100644 --- a/drivers/media/video/w9968cf.c +++ b/drivers/media/video/w9968cf.c @@ -444,8 +444,6 @@ static int w9968cf_i2c_smbus_xfer(struct i2c_adapter*, u16 addr, static u32 w9968cf_i2c_func(struct i2c_adapter*); static int w9968cf_i2c_attach_inform(struct i2c_client*); static int w9968cf_i2c_detach_inform(struct i2c_client*); -static int w9968cf_i2c_control(struct i2c_adapter*, unsigned int cmd, - unsigned long arg); /* Memory management */ static void* rvmalloc(unsigned long size); @@ -1543,21 +1541,12 @@ static int w9968cf_i2c_detach_inform(struct i2c_client* client) } -static int -w9968cf_i2c_control(struct i2c_adapter* adapter, unsigned int cmd, - unsigned long arg) -{ - return 0; -} - - static int w9968cf_i2c_init(struct w9968cf_device* cam) { int err = 0; static struct i2c_algorithm algo = { .smbus_xfer = w9968cf_i2c_smbus_xfer, - .algo_control = w9968cf_i2c_control, .functionality = w9968cf_i2c_func, }; diff --git a/drivers/message/fusion/Kconfig b/drivers/message/fusion/Kconfig index f55cc03a75c9..a34a11d2fef2 100644 --- a/drivers/message/fusion/Kconfig +++ b/drivers/message/fusion/Kconfig @@ -1,15 +1,19 @@ -menu "Fusion MPT device support" +menuconfig FUSION + bool "Fusion MPT device support" depends on PCI + ---help--- + Say Y here to get to see options for Fusion Message + Passing Technology (MPT) drivers. + This option alone does not add any kernel code. + + If you say N, all options in this submenu will be skipped and disabled. -config FUSION - bool - default n +if FUSION config FUSION_SPI tristate "Fusion MPT ScsiHost drivers for SPI" depends on PCI && SCSI - select FUSION select SCSI_SPI_ATTRS ---help--- SCSI HOST support for a parallel SCSI host adapters. @@ -20,11 +24,11 @@ config FUSION_SPI LSI53C1020A LSI53C1030 LSI53C1035 + ATTO UL4D config FUSION_FC tristate "Fusion MPT ScsiHost drivers for FC" depends on PCI && SCSI - select FUSION select SCSI_FC_ATTRS ---help--- SCSI HOST support for a Fiber Channel host adapters. @@ -37,12 +41,13 @@ config FUSION_FC LSIFC929 LSIFC929X LSIFC929XL + LSIFC949X + LSIFC949E Brocade FC 410/420 config FUSION_SAS tristate "Fusion MPT ScsiHost drivers for SAS" depends on PCI && SCSI - select FUSION select SCSI_SAS_ATTRS ---help--- SCSI HOST support for a SAS host adapters. @@ -53,10 +58,10 @@ config FUSION_SAS LSISAS1068 LSISAS1064E LSISAS1068E + LSISAS1078 config FUSION_MAX_SGE int "Maximum number of scatter gather entries (16 - 128)" - depends on FUSION default "128" range 16 128 help @@ -104,7 +109,6 @@ config FUSION_LAN config FUSION_LOGGING bool "Fusion MPT logging facility" - depends on FUSION ---help--- This turns on a logging facility that can be used to debug a number of Fusion MPT related problems. @@ -113,7 +117,7 @@ config FUSION_LOGGING echo [level] > /sys/class/scsi_host/host#/debug_level - There are various debug levels that an be found in the source: + There are various debug levels that can be found in the source: file:drivers/message/fusion/mptdebug.h -endmenu +endif # FUSION diff --git a/drivers/message/fusion/lsi/mpi.h b/drivers/message/fusion/lsi/mpi.h index 6a92e3d118fe..1acbdd61b670 100644 --- a/drivers/message/fusion/lsi/mpi.h +++ b/drivers/message/fusion/lsi/mpi.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2007 LSI Logic Corporation. + * Copyright (c) 2000-2007 LSI Corporation. * * * Name: mpi.h diff --git a/drivers/message/fusion/lsi/mpi_cnfg.h b/drivers/message/fusion/lsi/mpi_cnfg.h index eda769730e39..2bd8adae0f00 100644 --- a/drivers/message/fusion/lsi/mpi_cnfg.h +++ b/drivers/message/fusion/lsi/mpi_cnfg.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2007 LSI Logic Corporation. + * Copyright (c) 2000-2007 LSI Corporation. * * * Name: mpi_cnfg.h diff --git a/drivers/message/fusion/lsi/mpi_fc.h b/drivers/message/fusion/lsi/mpi_fc.h index 51a6aeb990ba..627acfbb8623 100644 --- a/drivers/message/fusion/lsi/mpi_fc.h +++ b/drivers/message/fusion/lsi/mpi_fc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2004 LSI Logic Corporation. + * Copyright (c) 2000-2004 LSI Corporation. * * * Name: mpi_fc.h diff --git a/drivers/message/fusion/lsi/mpi_history.txt b/drivers/message/fusion/lsi/mpi_history.txt index a1f479057ea3..241592ab13ad 100644 --- a/drivers/message/fusion/lsi/mpi_history.txt +++ b/drivers/message/fusion/lsi/mpi_history.txt @@ -3,7 +3,7 @@ MPI Header File Change History ============================== - Copyright (c) 2000-2007 LSI Logic Corporation. + Copyright (c) 2000-2007 LSI Corporation. --------------------------------------- Header Set Release Version: 01.05.16 diff --git a/drivers/message/fusion/lsi/mpi_init.h b/drivers/message/fusion/lsi/mpi_init.h index 3a02615f12d6..a9e3693601a7 100644 --- a/drivers/message/fusion/lsi/mpi_init.h +++ b/drivers/message/fusion/lsi/mpi_init.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2007 LSI Logic Corporation. + * Copyright (c) 2000-2007 LSI Corporation. * * * Name: mpi_init.h diff --git a/drivers/message/fusion/lsi/mpi_ioc.h b/drivers/message/fusion/lsi/mpi_ioc.h index b1893d185bc4..5cbb6bd048e1 100644 --- a/drivers/message/fusion/lsi/mpi_ioc.h +++ b/drivers/message/fusion/lsi/mpi_ioc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2007 LSI Logic Corporation. + * Copyright (c) 2000-2007 LSI Corporation. * * * Name: mpi_ioc.h diff --git a/drivers/message/fusion/lsi/mpi_lan.h b/drivers/message/fusion/lsi/mpi_lan.h index dc0b52ae83dd..03253b53b785 100644 --- a/drivers/message/fusion/lsi/mpi_lan.h +++ b/drivers/message/fusion/lsi/mpi_lan.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2004 LSI Logic Corporation. + * Copyright (c) 2000-2004 LSI Corporation. * * * Name: mpi_lan.h diff --git a/drivers/message/fusion/lsi/mpi_log_fc.h b/drivers/message/fusion/lsi/mpi_log_fc.h index dc98d46f9071..e4dafcefeecd 100644 --- a/drivers/message/fusion/lsi/mpi_log_fc.h +++ b/drivers/message/fusion/lsi/mpi_log_fc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2001 LSI Logic Corporation. All rights reserved. + * Copyright (c) 2000-2001 LSI Corporation. All rights reserved. * * NAME: fc_log.h * SUMMARY: MPI IocLogInfo definitions for the SYMFC9xx chips diff --git a/drivers/message/fusion/lsi/mpi_log_sas.h b/drivers/message/fusion/lsi/mpi_log_sas.h index 635bbe04513e..6be1f6b65777 100644 --- a/drivers/message/fusion/lsi/mpi_log_sas.h +++ b/drivers/message/fusion/lsi/mpi_log_sas.h @@ -1,6 +1,6 @@ /*************************************************************************** * * - * Copyright 2003 LSI Logic Corporation. All rights reserved. * + * Copyright 2003 LSI Corporation. All rights reserved. * * * * Description * * ------------ * diff --git a/drivers/message/fusion/lsi/mpi_raid.h b/drivers/message/fusion/lsi/mpi_raid.h index 32819b1ec8ec..2856108421d7 100644 --- a/drivers/message/fusion/lsi/mpi_raid.h +++ b/drivers/message/fusion/lsi/mpi_raid.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2007 LSI Logic Corporation. + * Copyright (c) 2001-2007 LSI Corporation. * * * Name: mpi_raid.h diff --git a/drivers/message/fusion/lsi/mpi_sas.h b/drivers/message/fusion/lsi/mpi_sas.h index 8e990a0fa7a2..33fca83cefc2 100644 --- a/drivers/message/fusion/lsi/mpi_sas.h +++ b/drivers/message/fusion/lsi/mpi_sas.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2006 LSI Logic Corporation. + * Copyright (c) 2004-2006 LSI Corporation. * * * Name: mpi_sas.h diff --git a/drivers/message/fusion/lsi/mpi_targ.h b/drivers/message/fusion/lsi/mpi_targ.h index 20b667315773..ff8c37d3fdcb 100644 --- a/drivers/message/fusion/lsi/mpi_targ.h +++ b/drivers/message/fusion/lsi/mpi_targ.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2004 LSI Logic Corporation. + * Copyright (c) 2000-2004 LSI Corporation. * * * Name: mpi_targ.h diff --git a/drivers/message/fusion/lsi/mpi_tool.h b/drivers/message/fusion/lsi/mpi_tool.h index aa9053da1f58..8834ae6ce0f2 100644 --- a/drivers/message/fusion/lsi/mpi_tool.h +++ b/drivers/message/fusion/lsi/mpi_tool.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2005 LSI Logic Corporation. + * Copyright (c) 2001-2005 LSI Corporation. * * * Name: mpi_tool.h diff --git a/drivers/message/fusion/lsi/mpi_type.h b/drivers/message/fusion/lsi/mpi_type.h index 32cc9b1151b8..08dad9c1e446 100644 --- a/drivers/message/fusion/lsi/mpi_type.h +++ b/drivers/message/fusion/lsi/mpi_type.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2004 LSI Logic Corporation. + * Copyright (c) 2000-2004 LSI Corporation. * * * Name: mpi_type.h diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 414c109f4cf5..52fb216dfe74 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -2,10 +2,10 @@ * linux/drivers/message/fusion/mptbase.c * This is the Fusion MPT base driver which supports multiple * (SCSI + LAN) specialized protocol drivers. - * For use with LSI Logic PCI chip/adapter(s) - * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * For use with LSI PCI chip/adapter(s) + * running LSI Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2007 LSI Logic Corporation + * Copyright (c) 1999-2007 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) * */ @@ -102,8 +102,6 @@ static int mfcounter = 0; /* * Public data... */ -int mpt_lan_index = -1; -int mpt_stm_index = -1; struct proc_dir_entry *mpt_proc_root_dir; @@ -125,11 +123,14 @@ static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS]; static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS]; static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS]; -static int mpt_base_index = -1; -static int last_drv_idx = -1; - static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq); +/* + * Driver Callback Index's + */ +static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS; +static u8 last_drv_idx; + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * Forward protos... @@ -235,6 +236,23 @@ static int mpt_set_debug_level(const char *val, struct kernel_param *kp) return 0; } +/** + * mpt_get_cb_idx - obtain cb_idx for registered driver + * @dclass: class driver enum + * + * Returns cb_idx, or zero means it wasn't found + **/ +static u8 +mpt_get_cb_idx(MPT_DRIVER_CLASS dclass) +{ + u8 cb_idx; + + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) + if (MptDriverClass[cb_idx] == dclass) + return cb_idx; + return 0; +} + /* * Process turbo (context) reply... */ @@ -243,8 +261,8 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa) { MPT_FRAME_HDR *mf = NULL; MPT_FRAME_HDR *mr = NULL; - int req_idx = 0; - int cb_idx; + u16 req_idx = 0; + u8 cb_idx; dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n", ioc->name, pa)); @@ -256,7 +274,7 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa) mf = MPT_INDEX_2_MFPTR(ioc, req_idx); break; case MPI_CONTEXT_REPLY_TYPE_LAN: - cb_idx = mpt_lan_index; + cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER); /* * Blind set of mf to NULL here was fatal * after lan_reply says "freeme" @@ -277,7 +295,7 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa) mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa); break; case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET: - cb_idx = mpt_stm_index; + cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER); mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa); break; default: @@ -286,8 +304,8 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa) } /* Check for (valid) IO callback! */ - if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS || - MptCallbacks[cb_idx] == NULL) { + if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS || + MptCallbacks[cb_idx] == NULL) { printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n", __FUNCTION__, ioc->name, cb_idx); goto out; @@ -304,8 +322,8 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa) { MPT_FRAME_HDR *mf; MPT_FRAME_HDR *mr; - int req_idx; - int cb_idx; + u16 req_idx; + u8 cb_idx; int freeme; u32 reply_dma_low; @@ -331,7 +349,7 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa) dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n", ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function)); - DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr) + DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr); /* Check/log IOC log info */ @@ -350,8 +368,8 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa) mpt_iocstatus_info(ioc, (u32)ioc_stat, mf); /* Check for (valid) IO callback! */ - if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS || - MptCallbacks[cb_idx] == NULL) { + if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS || + MptCallbacks[cb_idx] == NULL) { printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n", __FUNCTION__, ioc->name, cb_idx); freeme = 0; @@ -433,8 +451,9 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) #ifdef CONFIG_FUSION_LOGGING if ((ioc->debug_level & MPT_DEBUG_MSG_FRAME) && !(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) { - dmfprintk(ioc, printk(KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf)); - DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)mf) + dmfprintk(ioc, printk(MYIOC_s_INFO_FMT ": Original request frame (@%p) header\n", + ioc->name, mf)); + DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)mf); } #endif @@ -499,8 +518,8 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) u16 status; status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK; - dcprintk(ioc, printk(KERN_NOTICE " IOCStatus=%04xh, IOCLogInfo=%08xh\n", - status, le32_to_cpu(pReply->IOCLogInfo))); + dcprintk(ioc, printk(MYIOC_s_NOTE_FMT " IOCStatus=%04xh, IOCLogInfo=%08xh\n", + ioc->name, status, le32_to_cpu(pReply->IOCLogInfo))); pCfg->status = status; if (status == MPI_IOCSTATUS_SUCCESS) { @@ -563,28 +582,27 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) * in order to register separate callbacks; one for "normal" SCSI IO; * one for MptScsiTaskMgmt requests; one for Scan/DV requests. * - * Returns a positive integer valued "handle" in the - * range (and S.O.D. order) {N,...,7,6,5,...,1} if successful. - * Any non-positive return value (including zero!) should be considered - * an error by the caller. + * Returns u8 valued "handle" in the range (and S.O.D. order) + * {N,...,7,6,5,...,1} if successful. + * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be + * considered an error by the caller. */ -int +u8 mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass) { - int i; - - last_drv_idx = -1; + u8 cb_idx; + last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS; /* * Search for empty callback slot in this order: {N,...,7,6,5,...,1} * (slot/handle 0 is reserved!) */ - for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) { - if (MptCallbacks[i] == NULL) { - MptCallbacks[i] = cbfunc; - MptDriverClass[i] = dclass; - MptEvHandlers[i] = NULL; - last_drv_idx = i; + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { + if (MptCallbacks[cb_idx] == NULL) { + MptCallbacks[cb_idx] = cbfunc; + MptDriverClass[cb_idx] = dclass; + MptEvHandlers[cb_idx] = NULL; + last_drv_idx = cb_idx; break; } } @@ -601,9 +619,9 @@ mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass) * module is unloaded. */ void -mpt_deregister(int cb_idx) +mpt_deregister(u8 cb_idx) { - if ((cb_idx >= 0) && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) { + if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) { MptCallbacks[cb_idx] = NULL; MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER; MptEvHandlers[cb_idx] = NULL; @@ -625,9 +643,9 @@ mpt_deregister(int cb_idx) * Returns 0 for success. */ int -mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc) +mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc) { - if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) + if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) return -1; MptEvHandlers[cb_idx] = ev_cbfunc; @@ -645,9 +663,9 @@ mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc) * or when its module is unloaded. */ void -mpt_event_deregister(int cb_idx) +mpt_event_deregister(u8 cb_idx) { - if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) + if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) return; MptEvHandlers[cb_idx] = NULL; @@ -665,9 +683,9 @@ mpt_event_deregister(int cb_idx) * Returns 0 for success. */ int -mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func) +mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func) { - if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) + if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) return -1; MptResetHandlers[cb_idx] = reset_func; @@ -684,9 +702,9 @@ mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func) * or when its module is unloaded. */ void -mpt_reset_deregister(int cb_idx) +mpt_reset_deregister(u8 cb_idx) { - if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) + if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) return; MptResetHandlers[cb_idx] = NULL; @@ -699,12 +717,12 @@ mpt_reset_deregister(int cb_idx) * @cb_idx: MPT protocol driver index */ int -mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx) +mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx) { MPT_ADAPTER *ioc; const struct pci_device_id *id; - if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) + if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) return -EINVAL; MptDeviceDriverHandlers[cb_idx] = dd_cbfunc; @@ -726,12 +744,12 @@ mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx) * @cb_idx: MPT protocol driver index */ void -mpt_device_driver_deregister(int cb_idx) +mpt_device_driver_deregister(u8 cb_idx) { struct mpt_pci_driver *dd_cbfunc; MPT_ADAPTER *ioc; - if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) + if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) return; dd_cbfunc = MptDeviceDriverHandlers[cb_idx]; @@ -749,14 +767,14 @@ mpt_device_driver_deregister(int cb_idx) /** * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024) * allocated per MPT adapter. - * @handle: Handle of registered MPT protocol driver + * @cb_idx: Handle of registered MPT protocol driver * @ioc: Pointer to MPT adapter structure * * Returns pointer to a MPT request frame or %NULL if none are available * or IOC is not active. */ MPT_FRAME_HDR* -mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc) +mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc) { MPT_FRAME_HDR *mf; unsigned long flags; @@ -766,7 +784,8 @@ mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc) #ifdef MFCNT if (!ioc->active) - printk(KERN_WARNING "IOC Not Active! mpt_get_msg_frame returning NULL!\n"); + printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame " + "returning NULL!\n", ioc->name); #endif /* If interrupts are not attached, do not return a request frame */ @@ -781,13 +800,14 @@ mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc) u.frame.linkage.list); list_del(&mf->u.frame.linkage.list); mf->u.frame.linkage.arg1 = 0; - mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */ + mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */ req_offset = (u8 *)mf - (u8 *)ioc->req_frames; /* u16! */ req_idx = req_offset / ioc->req_sz; mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx); mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0; - ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame; /* Default, will be changed if necessary in SG generation */ + /* Default, will be changed if necessary in SG generation */ + ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame; #ifdef MFCNT ioc->mfcnt++; #endif @@ -798,14 +818,17 @@ mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc) #ifdef MFCNT if (mf == NULL) - printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", ioc->mfcnt, ioc->req_depth); + printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! " + "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt, + ioc->req_depth); mfcounter++; if (mfcounter == PRINT_MF_COUNT) - printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", ioc->mfcnt, ioc->req_depth); + printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name, + ioc->mfcnt, ioc->req_depth); #endif - dmfprintk(ioc, printk(KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n", - ioc->name, handle, ioc->id, mf)); + dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n", + ioc->name, cb_idx, ioc->id, mf)); return mf; } @@ -813,7 +836,7 @@ mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc) /** * mpt_put_msg_frame - Send a protocol specific MPT request frame * to a IOC. - * @handle: Handle of registered MPT protocol driver + * @cb_idx: Handle of registered MPT protocol driver * @ioc: Pointer to MPT adapter structure * @mf: Pointer to MPT request frame * @@ -821,14 +844,14 @@ mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc) * specific MPT adapter. */ void -mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) +mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) { u32 mf_dma_addr; int req_offset; u16 req_idx; /* Request index */ /* ensure values are reset properly! */ - mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */ + mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */ req_offset = (u8 *)mf - (u8 *)ioc->req_frames; /* u16! */ req_idx = req_offset / ioc->req_sz; @@ -838,10 +861,44 @@ mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf); mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx]; - dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx, ioc->RequestNB[req_idx])); + dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d " + "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx, + ioc->RequestNB[req_idx])); CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr); } +/** + * mpt_put_msg_frame_hi_pri - Send a protocol specific MPT request frame + * to a IOC using hi priority request queue. + * @cb_idx: Handle of registered MPT protocol driver + * @ioc: Pointer to MPT adapter structure + * @mf: Pointer to MPT request frame + * + * This routine posts a MPT request frame to the request post FIFO of a + * specific MPT adapter. + **/ +void +mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) +{ + u32 mf_dma_addr; + int req_offset; + u16 req_idx; /* Request index */ + + /* ensure values are reset properly! */ + mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; + req_offset = (u8 *)mf - (u8 *)ioc->req_frames; + req_idx = req_offset / ioc->req_sz; + mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx); + mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0; + + DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf); + + mf_dma_addr = (ioc->req_frames_low_dma + req_offset); + dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n", + ioc->name, mf_dma_addr, req_idx)); + CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr); +} + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_free_msg_frame - Place MPT request frame back on FreeQ. @@ -899,7 +956,7 @@ mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_send_handshake_request - Send MPT request via doorbell handshake method. - * @handle: Handle of registered MPT protocol driver + * @cb_idx: Handle of registered MPT protocol driver * @ioc: Pointer to MPT adapter structure * @reqBytes: Size of the request in bytes * @req: Pointer to MPT request frame @@ -914,7 +971,7 @@ mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr) * Returns 0 for success, non-zero for failure. */ int -mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag) +mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag) { int r = 0; u8 *req_as_bytes; @@ -934,7 +991,7 @@ mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) { MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req; mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii); - mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; + mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; } /* Make sure there are no doorbells */ @@ -953,7 +1010,7 @@ mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE)) return -5; - dhsprintk(ioc, printk(KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n", + dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n", ioc->name, ii)); CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); @@ -1395,11 +1452,13 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) { MPT_ADAPTER *ioc; u8 __iomem *mem; + u8 __iomem *pmem; unsigned long mem_phys; unsigned long port; u32 msize; u32 psize; int ii; + u8 cb_idx; int r = -ENODEV; u8 revision; u8 pcixcmd; @@ -1408,35 +1467,39 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) struct proc_dir_entry *dent, *ent; #endif + if (mpt_debug_level) + printk(KERN_INFO MYNAM ": mpt_debug_level=%xh\n", mpt_debug_level); + + if (pci_enable_device(pdev)) + return r; + ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC); if (ioc == NULL) { printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n"); return -ENOMEM; } - ioc->debug_level = mpt_debug_level; - if (mpt_debug_level) - printk(KERN_INFO MYNAM ": mpt_debug_level=%xh\n", mpt_debug_level); - - if (pci_enable_device(pdev)) - return r; + ioc->id = mpt_ids++; + sprintf(ioc->name, "ioc%d", ioc->id); - dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n")); + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name)); if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { - dprintk(ioc, printk(KERN_INFO MYNAM - ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n")); + dprintk(ioc, printk(MYIOC_s_INFO_FMT + ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", ioc->name)); } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { - printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n"); + printk(MYIOC_s_WARN_FMT ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n", + ioc->name); + kfree(ioc); return r; } if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) { - dprintk(ioc, printk(KERN_INFO MYNAM - ": Using 64 bit consistent mask\n")); + dprintk(ioc, printk(MYIOC_s_INFO_FMT + ": Using 64 bit consistent mask\n", ioc->name)); } else { - dprintk(ioc, printk(KERN_INFO MYNAM - ": Not using 64 bit consistent mask\n")); + dprintk(ioc, printk(MYIOC_s_INFO_FMT + ": Not using 64 bit consistent mask\n", ioc->name)); } ioc->alloc_total = sizeof(MPT_ADAPTER); @@ -1475,7 +1538,6 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) /* Find lookup slot. */ INIT_LIST_HEAD(&ioc->list); - ioc->id = mpt_ids++; mem_phys = msize = 0; port = psize = 0; @@ -1501,25 +1563,23 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) /*mem = ioremap(mem_phys, msize);*/ mem = ioremap(mem_phys, msize); if (mem == NULL) { - printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n"); + printk(MYIOC_s_ERR_FMT "Unable to map adapter memory!\n", ioc->name); kfree(ioc); return -EINVAL; } ioc->memmap = mem; - dinitprintk(ioc, printk(KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys)); + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n", ioc->name, mem, mem_phys)); - dinitprintk(ioc, printk(KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n", - &ioc->facts, &ioc->pfacts[0])); + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n", + ioc->name, &ioc->facts, &ioc->pfacts[0])); ioc->mem_phys = mem_phys; ioc->chip = (SYSIF_REGS __iomem *)mem; /* Save Port IO values in case we need to do downloadboot */ - { - u8 *pmem = (u8*)port; - ioc->pio_mem_phys = port; - ioc->pio_chip = (SYSIF_REGS __iomem *)pmem; - } + ioc->pio_mem_phys = port; + pmem = (u8 __iomem *)port; + ioc->pio_chip = (SYSIF_REGS __iomem *)pmem; pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name); @@ -1591,8 +1651,6 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) if (ioc->errata_flag_1064) pci_disable_io_access(pdev); - sprintf(ioc->name, "ioc%d", ioc->id); - spin_lock_init(&ioc->FreeQlock); /* Disable all! */ @@ -1609,9 +1667,8 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, CAN_SLEEP)) != 0){ - printk(KERN_WARNING MYNAM - ": WARNING - %s did not initialize properly! (%d)\n", - ioc->name, r); + printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n", + ioc->name, r); list_del(&ioc->list); if (ioc->alt_ioc) @@ -1623,10 +1680,10 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) } /* call per device driver probe entry point */ - for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) { - if(MptDeviceDriverHandlers[ii] && - MptDeviceDriverHandlers[ii]->probe) { - MptDeviceDriverHandlers[ii]->probe(pdev,id); + for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) { + if(MptDeviceDriverHandlers[cb_idx] && + MptDeviceDriverHandlers[cb_idx]->probe) { + MptDeviceDriverHandlers[cb_idx]->probe(pdev,id); } } @@ -1663,7 +1720,7 @@ mpt_detach(struct pci_dev *pdev) { MPT_ADAPTER *ioc = pci_get_drvdata(pdev); char pname[32]; - int ii; + u8 cb_idx; sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name); remove_proc_entry(pname, NULL); @@ -1673,10 +1730,10 @@ mpt_detach(struct pci_dev *pdev) remove_proc_entry(pname, NULL); /* call per device driver remove entry point */ - for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) { - if(MptDeviceDriverHandlers[ii] && - MptDeviceDriverHandlers[ii]->remove) { - MptDeviceDriverHandlers[ii]->remove(pdev); + for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) { + if(MptDeviceDriverHandlers[cb_idx] && + MptDeviceDriverHandlers[cb_idx]->remove) { + MptDeviceDriverHandlers[cb_idx]->remove(pdev); } } @@ -1788,7 +1845,7 @@ mpt_resume(struct pci_dev *pdev) #endif static int -mpt_signal_reset(int index, MPT_ADAPTER *ioc, int reset_phase) +mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase) { if ((MptDriverClass[index] == MPTSPI_DRIVER && ioc->bus_type != SPI) || @@ -1830,14 +1887,15 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) int hard; int rc=0; int ii; + u8 cb_idx; int handlers; int ret = 0; int reset_alt_ioc_active = 0; int irq_allocated = 0; u8 *a; - printk(KERN_INFO MYNAM ": Initiating %s %s\n", - ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery"); + printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name, + reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery"); /* Disable reply interrupts (also blocks FreeQ) */ CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); @@ -1858,21 +1916,19 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) { if (hard_reset_done == -4) { - printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n", - ioc->name); + printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n", + ioc->name); if (reset_alt_ioc_active && ioc->alt_ioc) { /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */ - dprintk(ioc, printk(KERN_INFO MYNAM - ": alt-%s reply irq re-enabled\n", - ioc->alt_ioc->name)); + dprintk(ioc, printk(MYIOC_s_INFO_FMT + "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name)); CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM); ioc->alt_ioc->active = 1; } } else { - printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n", - ioc->name); + printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name); } return -1; } @@ -1884,9 +1940,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0) alt_ioc_ready = 1; else - printk(KERN_WARNING MYNAM - ": alt-%s: Not ready WARNING!\n", - ioc->alt_ioc->name); + printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name); } for (ii=0; ii<5; ii++) { @@ -1897,7 +1951,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) if (ii == 5) { - dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc)); + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Retry IocFacts failed rc=%x\n", ioc->name, rc)); ret = -2; } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { MptDisplayIocCapabilities(ioc); @@ -1906,14 +1961,14 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) if (alt_ioc_ready) { if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) { dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc)); + "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc)); /* Retry - alt IOC was initialized once */ rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason); } if (rc) { dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc)); + "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc)); alt_ioc_ready = 0; reset_alt_ioc_active = 0; } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { @@ -1931,13 +1986,12 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) if (ioc->pcidev->irq) { if (mpt_msi_enable && !pci_enable_msi(ioc->pcidev)) printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n", - ioc->name); + ioc->name); rc = request_irq(ioc->pcidev->irq, mpt_interrupt, - IRQF_SHARED, ioc->name, ioc); + IRQF_SHARED, ioc->name, ioc); if (rc < 0) { printk(MYIOC_s_ERR_FMT "Unable to allocate " - "interrupt %d!\n", ioc->name, - ioc->pcidev->irq); + "interrupt %d!\n", ioc->name, ioc->pcidev->irq); if (mpt_msi_enable) pci_disable_msi(ioc->pcidev); return -EBUSY; @@ -1946,8 +2000,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) ioc->pci_irq = ioc->pcidev->irq; pci_set_master(ioc->pcidev); /* ?? */ pci_set_drvdata(ioc->pcidev, ioc); - dprintk(ioc, printk(KERN_INFO MYNAM ": %s installed at interrupt " - "%d\n", ioc->name, ioc->pcidev->irq)); + dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt " + "%d\n", ioc->name, ioc->pcidev->irq)); } } @@ -1966,8 +2020,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) ret = -4; // NEW! if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) { - printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n", - ioc->alt_ioc->name, rc); + printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n", + ioc->alt_ioc->name, rc); alt_ioc_ready = 0; reset_alt_ioc_active = 0; } @@ -1976,16 +2030,15 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) { alt_ioc_ready = 0; reset_alt_ioc_active = 0; - printk(KERN_WARNING MYNAM - ": alt-%s: (%d) init failure WARNING!\n", - ioc->alt_ioc->name, rc); + printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n", + ioc->alt_ioc->name, rc); } } if (reason == MPT_HOSTEVENT_IOC_BRINGUP){ if (ioc->upload_fw) { ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "firmware upload required!\n", ioc->name)); + "firmware upload required!\n", ioc->name)); /* Controller is not operational, cannot do upload */ @@ -2001,12 +2054,13 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) * mpt_diag_reset) */ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT - ": mpt_upload: alt_%s has cached_fw=%p \n", - ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw)); + "mpt_upload: alt_%s has cached_fw=%p \n", + ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw)); ioc->alt_ioc->cached_fw = NULL; } } else { - printk(KERN_WARNING MYNAM ": firmware upload failure!\n"); + printk(MYIOC_s_WARN_FMT + "firmware upload failure!\n", ioc->name); ret = -5; } } @@ -2021,8 +2075,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) if (reset_alt_ioc_active && ioc->alt_ioc) { /* (re)Enable alt-IOC! (reply interrupt) */ - dinitprintk(ioc, printk(KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n", - ioc->alt_ioc->name)); + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "alt_ioc reply irq re-enabled\n", + ioc->alt_ioc->name)); CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM); ioc->alt_ioc->active = 1; } @@ -2075,10 +2129,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) (void) GetLanConfigPages(ioc); a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; dprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "LanAddr = %02X:%02X:%02X:" - "%02X:%02X:%02X\n", - ioc->name, a[5], a[4], - a[3], a[2], a[1], a[0] )); + "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n", + ioc->name, a[5], a[4], a[3], a[2], a[1], a[0])); } } else { @@ -2114,20 +2166,20 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) */ if (hard_reset_done) { rc = handlers = 0; - for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) { - if ((ret == 0) && MptResetHandlers[ii]) { + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { + if ((ret == 0) && MptResetHandlers[cb_idx]) { dprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "Calling IOC post_reset handler #%d\n", - ioc->name, ii)); - rc += mpt_signal_reset(ii, ioc, MPT_IOC_POST_RESET); + "Calling IOC post_reset handler #%d\n", + ioc->name, cb_idx)); + rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET); handlers++; } - if (alt_ioc_ready && MptResetHandlers[ii]) { + if (alt_ioc_ready && MptResetHandlers[cb_idx]) { drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "Calling alt-%s post_reset handler #%d\n", - ioc->name, ioc->alt_ioc->name, ii)); - rc += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_POST_RESET); + "Calling IOC post_reset handler #%d\n", + ioc->alt_ioc->name, cb_idx)); + rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET); handlers++; } } @@ -2166,8 +2218,8 @@ mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev) dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x," " searching for devfn match on %x or %x\n", - ioc->name, pci_name(pdev), pdev->bus->number, - pdev->devfn, func-1, func+1)); + ioc->name, pci_name(pdev), pdev->bus->number, + pdev->devfn, func-1, func+1)); peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1)); if (!peer) { @@ -2181,15 +2233,15 @@ mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev) if (_pcidev == peer) { /* Paranoia checks */ if (ioc->alt_ioc != NULL) { - printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n", + printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n", ioc->name, ioc->alt_ioc->name); break; } else if (ioc_srch->alt_ioc != NULL) { - printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n", + printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n", ioc_srch->name, ioc_srch->alt_ioc->name); break; } - dprintk(ioc, printk(KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n", + dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n", ioc->name, ioc_srch->name)); ioc_srch->alt_ioc = ioc; ioc->alt_ioc = ioc_srch; @@ -2210,10 +2262,11 @@ mpt_adapter_disable(MPT_ADAPTER *ioc) int ret; if (ioc->cached_fw != NULL) { - ddlprintk(ioc, printk(KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n")); + ddlprintk(ioc, printk(MYIOC_s_INFO_FMT + "mpt_adapter_disable: Pushing FW onto adapter\n", ioc->name)); if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) { - printk(KERN_WARNING MYNAM - ": firmware downloadboot failure (%d)!\n", ret); + printk(MYIOC_s_WARN_FMT "firmware downloadboot failure (%d)!\n", + ioc->name, ret); } } @@ -2225,8 +2278,8 @@ mpt_adapter_disable(MPT_ADAPTER *ioc) if (ioc->alloc != NULL) { sz = ioc->alloc_sz; - dexitprintk(ioc, printk(KERN_INFO MYNAM ": %s.free @ %p, sz=%d bytes\n", - ioc->name, ioc->alloc, ioc->alloc_sz)); + dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n", + ioc->name, ioc->alloc, ioc->alloc_sz)); pci_free_consistent(ioc->pcidev, sz, ioc->alloc, ioc->alloc_dma); ioc->reply_frames = NULL; @@ -2286,15 +2339,14 @@ mpt_adapter_disable(MPT_ADAPTER *ioc) if (ioc->HostPageBuffer != NULL) { if((ret = mpt_host_page_access_control(ioc, MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) { - printk(KERN_ERR MYNAM - ": %s: host page buffers free failed (%d)!\n", - __FUNCTION__, ret); + printk(MYIOC_s_ERR_FMT + "host page buffers free failed (%d)!\n", + ioc->name, ret); } - dexitprintk(ioc, printk(KERN_INFO MYNAM ": %s HostPageBuffer free @ %p, sz=%d bytes\n", + dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free @ %p, sz=%d bytes\n", ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz)); pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz, - ioc->HostPageBuffer, - ioc->HostPageBuffer_dma); + ioc->HostPageBuffer, ioc->HostPageBuffer_dma); ioc->HostPageBuffer = NULL; ioc->HostPageBuffer_sz = 0; ioc->alloc_total -= ioc->HostPageBuffer_sz; @@ -2336,7 +2388,7 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc) #if defined(CONFIG_MTRR) && 0 if (ioc->mtrr_reg > 0) { mtrr_del(ioc->mtrr_reg, 0, 0); - dprintk(ioc, printk(KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name)); + dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name)); } #endif @@ -2344,8 +2396,8 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc) list_del(&ioc->list); sz_last = ioc->alloc_total; - dprintk(ioc, printk(KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n", - ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first)); + dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n", + ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first)); if (ioc->alt_ioc) ioc->alt_ioc->alt_ioc = NULL; @@ -2424,7 +2476,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag) /* Get current [raw] IOC state */ ioc_state = mpt_GetIocState(ioc, 0); - dhsprintk(ioc, printk(KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state)); + dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state)); /* * Check to see if IOC got left/stuck in doorbell handshake @@ -2446,9 +2498,9 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag) if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) { statefault = 2; printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n", - ioc->name); - printk(KERN_WARNING " FAULT code = %04xh\n", - ioc_state & MPI_DOORBELL_DATA_MASK); + ioc->name); + printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n", + ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK); } /* @@ -2464,9 +2516,9 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag) * Else, fall through to KickStart case */ whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT; - dinitprintk(ioc, printk(KERN_INFO MYNAM - ": whoinit 0x%x statefault %d force %d\n", - whoinit, statefault, force)); + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT + "whoinit 0x%x statefault %d force %d\n", + ioc->name, whoinit, statefault, force)); if (whoinit == MPI_WHOINIT_PCI_PEER) return -4; else { @@ -2549,7 +2601,6 @@ mpt_GetIocState(MPT_ADAPTER *ioc, int cooked) /* Get! */ s = CHIPREG_READ32(&ioc->chip->Doorbell); -// dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s)); sc = s & MPI_IOC_STATE_MASK; /* Save! */ @@ -2581,9 +2632,8 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) /* IOC *must* NOT be in RESET state! */ if (ioc->last_state == MPI_IOC_STATE_RESET) { - printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n", - ioc->name, - ioc->last_state ); + printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n", + ioc->name, ioc->last_state ); return -44; } @@ -2703,8 +2753,8 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) } ioc->NBShiftFactor = shiftFactor; dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n", - ioc->name, vv, shiftFactor, r)); + "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n", + ioc->name, vv, shiftFactor, r)); if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { /* @@ -2757,9 +2807,8 @@ GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag) /* IOC *must* NOT be in RESET state! */ if (ioc->last_state == MPI_IOC_STATE_RESET) { - printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n", - ioc->name, - ioc->last_state ); + printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n", + ioc->name, ioc->last_state ); return -4; } @@ -2934,7 +2983,7 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag) state = mpt_GetIocState(ioc, 1); count++; } - dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n", + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n", ioc->name, count)); ioc->aen_event_read_flag=0; @@ -3027,10 +3076,9 @@ mpt_free_fw_memory(MPT_ADAPTER *ioc) int sz; sz = ioc->facts.FWImageSize; - dinitprintk(ioc, printk(KERN_INFO MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n", - ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz)); - pci_free_consistent(ioc->pcidev, sz, - ioc->cached_fw, ioc->cached_fw_dma); + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n", + ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz)); + pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma); ioc->cached_fw = NULL; return; @@ -3054,7 +3102,6 @@ mpt_free_fw_memory(MPT_ADAPTER *ioc) static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag) { - u8 request[ioc->req_sz]; u8 reply[sizeof(FWUploadReply_t)]; FWUpload_t *prequest; FWUploadReply_t *preply; @@ -3071,8 +3118,8 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag) mpt_alloc_fw_memory(ioc, sz); - dinitprintk(ioc, printk(KERN_INFO MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n", - ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz)); + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n", + ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz)); if (ioc->cached_fw == NULL) { /* Major Failure. @@ -3080,11 +3127,16 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag) return -ENOMEM; } - prequest = (FWUpload_t *)&request; - preply = (FWUploadReply_t *)&reply; + prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) : + kzalloc(ioc->req_sz, GFP_KERNEL); + if (!prequest) { + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed " + "while allocating memory \n", ioc->name)); + mpt_free_fw_memory(ioc); + return -ENOMEM; + } - /* Destination... */ - memset(prequest, 0, ioc->req_sz); + preply = (FWUploadReply_t *)&reply; reply_sz = sizeof(reply); memset(preply, 0, reply_sz); @@ -3096,21 +3148,22 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag) ptcsge->DetailsLength = 12; ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT; ptcsge->ImageSize = cpu_to_le32(sz); + ptcsge++; sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t); flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz; - mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma); + mpt_add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma); sgeoffset += sizeof(u32) + sizeof(dma_addr_t); - dinitprintk(ioc, printk(KERN_INFO MYNAM ": Sending FW Upload (req @ %p) sgeoffset=%d \n", - prequest, sgeoffset)); - DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest) + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": Sending FW Upload (req @ %p) sgeoffset=%d \n", + ioc->name, prequest, sgeoffset)); + DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest); ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest, reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag); - dinitprintk(ioc, printk(KERN_INFO MYNAM ": FW Upload completed rc=%x \n", ii)); + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii)); cmdStatus = -EFAULT; if (ii == 0) { @@ -3135,6 +3188,7 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag) ioc->name)); mpt_free_fw_memory(ioc); } + kfree(prequest); return cmdStatus; } @@ -3381,7 +3435,7 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag) u32 ioc_state=0; int cnt,cntdn; - dinitprintk(ioc, printk(KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name)); + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name)); if (ioc->bus_type == SPI) { /* Always issue a Msg Unit Reset first. This will clear some * SCSI bus hang conditions. @@ -3400,7 +3454,7 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag) return hard_reset_done; dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n", - ioc->name)); + ioc->name)); cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */ for (cnt=0; cnt<cntdn; cnt++) { @@ -3417,8 +3471,8 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag) } } - printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n", - ioc->name, ioc_state); + dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n", + ioc->name, mpt_GetIocState(ioc, 0))); return -1; } @@ -3560,20 +3614,20 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) * MptResetHandlers[] registered yet. */ { - int ii; + u8 cb_idx; int r = 0; - for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) { - if (MptResetHandlers[ii]) { + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { + if (MptResetHandlers[cb_idx]) { dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC pre_reset handler #%d\n", - ioc->name, ii)); - r += mpt_signal_reset(ii, ioc, MPT_IOC_PRE_RESET); + ioc->name, cb_idx)); + r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET); if (ioc->alt_ioc) { dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s pre_reset handler #%d\n", - ioc->name, ioc->alt_ioc->name, ii)); - r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_PRE_RESET); + ioc->name, ioc->alt_ioc->name, cb_idx)); + r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET); } } } @@ -3606,8 +3660,8 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) } if ((count = mpt_downloadboot(ioc, (MpiFwHeader_t *)iocp->cached_fw, sleepFlag)) < 0) { - printk(KERN_WARNING MYNAM - ": firmware downloadboot failure (%d)!\n", count); + printk(MYIOC_s_WARN_FMT + "firmware downloadboot failure (%d)!\n", ioc->name, count); } } else { @@ -3750,8 +3804,8 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag) if (sleepFlag != CAN_SLEEP) count *= 10; - printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n", - ioc->name, (int)((count+5)/HZ)); + printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n", + ioc->name, (int)((count+5)/HZ)); return -ETIME; } @@ -4144,7 +4198,7 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req, } dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req)); - DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req) + DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req); dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n", ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : "")); @@ -4349,7 +4403,7 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag) #endif dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name)); - DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply) + DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply); dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n", ioc->name, t, u16cnt/2)); @@ -4824,8 +4878,8 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum) if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) { ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS; - ddvprintk(ioc, printk(KERN_INFO MYNAM - " :%s noQas due to Capabilities=%x\n", + ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "noQas due to Capabilities=%x\n", ioc->name, pPP0->Capabilities)); } ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0; @@ -4888,6 +4942,38 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum) /* Nvram data is left with INVALID mark */ rc = 1; + } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) { + + /* This is an ATTO adapter, read Page2 accordingly + */ + ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf; + ATTODeviceInfo_t *pdevice = NULL; + u16 ATTOFlags; + + /* Save the Port Page 2 data + * (reformat into a 32bit quantity) + */ + for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { + pdevice = &pPP2->DeviceSettings[ii]; + ATTOFlags = le16_to_cpu(pdevice->ATTOFlags); + data = 0; + + /* Translate ATTO device flags to LSI format + */ + if (ATTOFlags & ATTOFLAG_DISC) + data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE); + if (ATTOFlags & ATTOFLAG_ID_ENB) + data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE); + if (ATTOFlags & ATTOFLAG_LUN_ENB) + data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE); + if (ATTOFlags & ATTOFLAG_TAGGED) + data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE); + if (!(ATTOFlags & ATTOFLAG_WIDE_ENB)) + data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE); + + data = (data << 16) | (pdevice->Period << 8) | 10; + ioc->spi_data.nvram[ii] = data; + } } else { SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf; MpiDeviceInfo_t *pdevice = NULL; @@ -5701,10 +5787,10 @@ mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) CONFIGPARMS *pCfg; unsigned long flags; - dprintk(ioc, printk(KERN_DEBUG MYNAM - ": IOC %s_reset routed to MPT base driver!\n", - reset_phase==MPT_IOC_SETUP_RESET ? "setup" : ( - reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT + ": IOC %s_reset routed to MPT base driver!\n", + ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : ( + reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); if (reset_phase == MPT_IOC_SETUP_RESET) { ; @@ -5843,7 +5929,7 @@ procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eo static int procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - int ii; + u8 cb_idx; int scsi, fc, sas, lan, ctl, targ, dmp; char *drvname; int len; @@ -5852,10 +5938,10 @@ procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eo len += sprintf(buf+len, " Fusion MPT base driver\n"); scsi = fc = sas = lan = ctl = targ = dmp = 0; - for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) { + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { drvname = NULL; - if (MptCallbacks[ii]) { - switch (MptDriverClass[ii]) { + if (MptCallbacks[cb_idx]) { + switch (MptDriverClass[cb_idx]) { case MPTSPI_DRIVER: if (!scsi++) drvname = "SPI host"; break; @@ -6099,26 +6185,25 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) * For all other protocol drivers, this is a no-op. */ { - int ii; + u8 cb_idx; int r = 0; - for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) { - if (MptResetHandlers[ii]) { + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { + if (MptResetHandlers[cb_idx]) { dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n", - ioc->name, ii)); - r += mpt_signal_reset(ii, ioc, MPT_IOC_SETUP_RESET); + ioc->name, cb_idx)); + r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET); if (ioc->alt_ioc) { dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n", - ioc->name, ioc->alt_ioc->name, ii)); - r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_SETUP_RESET); + ioc->name, ioc->alt_ioc->name, cb_idx)); + r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET); } } } } if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) { - printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n", - rc, ioc->name); + printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc); } ioc->reload_fw = 0; if (ioc->alt_ioc) @@ -6515,6 +6600,7 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply u32 evData0 = 0; // u32 evCtx; int ii; + u8 cb_idx; int r = 0; int handlers = 0; char evStr[EVENT_DESCR_STR_SZ]; @@ -6537,12 +6623,12 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply evStr)); #ifdef CONFIG_FUSION_LOGGING - devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM - ": Event data:\n")); + devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT + ": Event data:\n", ioc->name)); for (ii = 0; ii < evDataLen; ii++) devtverboseprintk(ioc, printk(" %08x", le32_to_cpu(pEventReply->Data[ii]))); - devtverboseprintk(ioc, printk(KERN_DEBUG "\n")); + devtverboseprintk(ioc, printk("\n")); #endif /* @@ -6595,11 +6681,11 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply /* * Call each currently registered protocol event handler. */ - for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) { - if (MptEvHandlers[ii]) { + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { + if (MptEvHandlers[cb_idx]) { devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n", - ioc->name, ii)); - r += (*(MptEvHandlers[ii]))(ioc, pEventReply); + ioc->name, cb_idx)); + r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply); handlers++; } } @@ -7034,8 +7120,8 @@ mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf) if (!desc) return; - printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s: %s\n", - ioc->name, ioc_status, desc, extend_desc); + dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n", + ioc->name, ioc_status, desc, extend_desc)); } /** @@ -7261,7 +7347,8 @@ mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf) if (!desc) return; - printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s\n", ioc->name, status, desc); + dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n", + ioc->name, status, desc)); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -7283,14 +7370,13 @@ EXPORT_SYMBOL(mpt_device_driver_register); EXPORT_SYMBOL(mpt_device_driver_deregister); EXPORT_SYMBOL(mpt_get_msg_frame); EXPORT_SYMBOL(mpt_put_msg_frame); +EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri); EXPORT_SYMBOL(mpt_free_msg_frame); EXPORT_SYMBOL(mpt_add_sge); EXPORT_SYMBOL(mpt_send_handshake_request); EXPORT_SYMBOL(mpt_verify_adapter); EXPORT_SYMBOL(mpt_GetIocState); EXPORT_SYMBOL(mpt_print_ioc_summary); -EXPORT_SYMBOL(mpt_lan_index); -EXPORT_SYMBOL(mpt_stm_index); EXPORT_SYMBOL(mpt_HardResetHandler); EXPORT_SYMBOL(mpt_config); EXPORT_SYMBOL(mpt_findImVolumes); @@ -7308,16 +7394,16 @@ EXPORT_SYMBOL(mpt_raid_phys_disk_pg0); static int __init fusion_init(void) { - int i; + u8 cb_idx; show_mptmod_ver(my_NAME, my_VERSION); printk(KERN_INFO COPYRIGHT "\n"); - for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) { - MptCallbacks[i] = NULL; - MptDriverClass[i] = MPTUNKNOWN_DRIVER; - MptEvHandlers[i] = NULL; - MptResetHandlers[i] = NULL; + for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) { + MptCallbacks[cb_idx] = NULL; + MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER; + MptEvHandlers[cb_idx] = NULL; + MptResetHandlers[cb_idx] = NULL; } /* Register ourselves (mptbase) in order to facilitate diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index 15ff22645844..d7682e083f59 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -3,9 +3,9 @@ * High performance SCSI + LAN / Fibre Channel device drivers. * For use with PCI chip/adapter(s): * LSIFC9xx/LSI409xx Fibre Channel - * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * running LSI Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2007 LSI Logic Corporation + * Copyright (c) 1999-2007 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) * */ @@ -68,15 +68,15 @@ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ #ifndef MODULEAUTHOR -#define MODULEAUTHOR "LSI Logic Corporation" +#define MODULEAUTHOR "LSI Corporation" #endif #ifndef COPYRIGHT #define COPYRIGHT "Copyright (c) 1999-2007 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "3.04.05" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.05" +#define MPT_LINUX_VERSION_COMMON "3.04.06" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.06" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ @@ -186,6 +186,7 @@ * MPT drivers. NOTE: Users of these macro defs must * themselves define their own MYNAM. */ +#define MYIOC_s_FMT MYNAM ": %s: " #define MYIOC_s_DEBUG_FMT KERN_DEBUG MYNAM ": %s: " #define MYIOC_s_INFO_FMT KERN_INFO MYNAM ": %s: " #define MYIOC_s_NOTE_FMT KERN_NOTICE MYNAM ": %s: " @@ -194,6 +195,35 @@ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* + * ATTO UL4D associated structures and defines + */ +#define ATTOFLAG_DISC 0x0001 +#define ATTOFLAG_TAGGED 0x0002 +#define ATTOFLAG_WIDE_ENB 0x0008 +#define ATTOFLAG_ID_ENB 0x0010 +#define ATTOFLAG_LUN_ENB 0x0060 + +typedef struct _ATTO_DEVICE_INFO +{ + u8 Offset; /* 00h */ + u8 Period; /* 01h */ + u16 ATTOFlags; /* 02h */ +} ATTO_DEVICE_INFO, MPI_POINTER PTR_ATTO_DEVICE_INFO, + ATTODeviceInfo_t, MPI_POINTER pATTODeviceInfo_t; + +typedef struct _ATTO_CONFIG_PAGE_SCSI_PORT_2 +{ + CONFIG_PAGE_HEADER Header; /* 00h */ + u16 PortFlags; /* 04h */ + u16 Unused1; /* 06h */ + u32 Unused2; /* 08h */ + ATTO_DEVICE_INFO DeviceSettings[16]; /* 0Ch */ +} fATTO_CONFIG_PAGE_SCSI_PORT_2, MPI_POINTER PTR_ATTO_CONFIG_PAGE_SCSI_PORT_2, + ATTO_SCSIPortPage2_t, MPI_POINTER pATTO_SCSIPortPage2_t; + + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* * MPT protocol driver defs... */ typedef enum { @@ -307,7 +337,8 @@ typedef struct _SYSIF_REGS u32 Reserved2[2]; /* 38-3F reserved for future use */ u32 RequestFifo; /* 40 Request Post/Free FIFO */ u32 ReplyFifo; /* 44 Reply Post/Free FIFO */ - u32 Reserved3[2]; /* 48-4F reserved for future use */ + u32 RequestHiPriFifo; /* 48 Hi Priority Request FIFO */ + u32 Reserved3; /* 4C-4F reserved for future use */ u32 HostIndex; /* 50 Host Index register */ u32 Reserved4[15]; /* 54-8F */ u32 Fubar; /* 90 For Fubar usage */ @@ -649,9 +680,9 @@ typedef struct _MPT_ADAPTER u8 reload_fw; /* Force a FW Reload on next reset */ u8 NBShiftFactor; /* NB Shift Factor based on Block Size (Facts) */ u8 pad1[4]; - int DoneCtx; - int TaskCtx; - int InternalCtx; + u8 DoneCtx; + u8 TaskCtx; + u8 InternalCtx; spinlock_t initializing_hba_lock; int initializing_hba_lock_flag; struct list_head list; @@ -668,10 +699,14 @@ typedef struct _MPT_ADAPTER struct work_struct fc_setup_reset_work; struct list_head fc_rports; + struct work_struct fc_lsc_work; + u8 fc_link_speed[2]; spinlock_t fc_rescan_work_lock; struct work_struct fc_rescan_work; char fc_rescan_work_q_name[KOBJ_NAME_LEN]; struct workqueue_struct *fc_rescan_work_q; + struct scsi_cmnd **ScsiLookup; + spinlock_t scsi_lookup_lock; } MPT_ADAPTER; /* @@ -785,7 +820,6 @@ typedef struct _MPT_SCSI_HOST { MPT_ADAPTER *ioc; int port; u32 pad0; - struct scsi_cmnd **ScsiLookup; MPT_LOCAL_REPLY *pLocal; /* used for internal commands */ struct timer_list timer; /* Pool of memory for holding SCpnts before doing @@ -853,20 +887,21 @@ extern void mpt_detach(struct pci_dev *pdev); extern int mpt_suspend(struct pci_dev *pdev, pm_message_t state); extern int mpt_resume(struct pci_dev *pdev); #endif -extern int mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass); -extern void mpt_deregister(int cb_idx); -extern int mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc); -extern void mpt_event_deregister(int cb_idx); -extern int mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func); -extern void mpt_reset_deregister(int cb_idx); -extern int mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx); -extern void mpt_device_driver_deregister(int cb_idx); -extern MPT_FRAME_HDR *mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc); +extern u8 mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass); +extern void mpt_deregister(u8 cb_idx); +extern int mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc); +extern void mpt_event_deregister(u8 cb_idx); +extern int mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func); +extern void mpt_reset_deregister(u8 cb_idx); +extern int mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx); +extern void mpt_device_driver_deregister(u8 cb_idx); +extern MPT_FRAME_HDR *mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc); extern void mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf); -extern void mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf); +extern void mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf); +extern void mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf); extern void mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr); -extern int mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag); +extern int mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag); extern int mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp); extern u32 mpt_GetIocState(MPT_ADAPTER *ioc, int cooked); extern void mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buf, int *size, int len, int showlan); @@ -884,9 +919,6 @@ extern int mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhys extern struct list_head ioc_list; extern struct proc_dir_entry *mpt_proc_root_dir; -extern int mpt_lan_index; /* needed by mptlan.c */ -extern int mpt_stm_index; /* needed by mptstm.c */ - /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ #endif /* } __KERNEL__ */ diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index 89695e705bdc..6029509702d3 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c @@ -1,10 +1,10 @@ /* * linux/drivers/message/fusion/mptctl.c * mpt Ioctl driver. - * For use with LSI Logic PCI chip/adapters - * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * For use with LSI PCI chip/adapters + * running LSI Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2007 LSI Logic Corporation + * Copyright (c) 1999-2007 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) * */ @@ -66,8 +66,8 @@ #include <scsi/scsi_host.h> #include <scsi/scsi_tcq.h> -#define COPYRIGHT "Copyright (c) 1999-2007 LSI Logic Corporation" -#define MODULEAUTHOR "LSI Logic Corporation" +#define COPYRIGHT "Copyright (c) 1999-2007 LSI Corporation" +#define MODULEAUTHOR "LSI Corporation" #include "mptbase.h" #include "mptctl.h" @@ -83,7 +83,7 @@ MODULE_VERSION(my_VERSION); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -static int mptctl_id = -1; +static u8 mptctl_id = MPT_MAX_PROTOCOL_DRIVERS; static DECLARE_WAIT_QUEUE_HEAD ( mptctl_wait ); @@ -181,7 +181,6 @@ static inline int mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock) { int rc = 0; -// dctlprintk(ioc, printk(KERN_DEBUG MYNAM "::mptctl_syscall_down(%p,%d) called\n", ioc, nonblock)); if (nonblock) { if (!mutex_trylock(&ioc->ioctl->ioctl_mutex)) @@ -190,7 +189,6 @@ mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock) if (mutex_lock_interruptible(&ioc->ioctl->ioctl_mutex)) rc = -ERESTARTSYS; } -// dctlprintk(ioc, printk(KERN_DEBUG MYNAM "::mptctl_syscall_down return %d\n", rc)); return rc; } @@ -342,7 +340,7 @@ static int mptctl_bus_reset(MPT_IOCTL *ioctl) SCSITaskMgmt_t *pScsiTm; MPT_SCSI_HOST *hd; int ii; - int retval; + int retval=0; ioctl->reset &= ~MPTCTL_RESET_OK; @@ -350,7 +348,7 @@ static int mptctl_bus_reset(MPT_IOCTL *ioctl) if (ioctl->ioc->sh == NULL) return -EPERM; - hd = (MPT_SCSI_HOST *) ioctl->ioc->sh->hostdata; + hd = shost_priv(ioctl->ioc->sh); if (hd == NULL) return -EPERM; @@ -395,12 +393,19 @@ static int mptctl_bus_reset(MPT_IOCTL *ioctl) DBG_DUMP_TM_REQUEST_FRAME(ioctl->ioc, (u32 *)mf); ioctl->wait_done=0; - if ((retval = mpt_send_handshake_request(mptctl_id, ioctl->ioc, - sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP)) != 0) { - dfailprintk(ioctl->ioc, printk(MYIOC_s_ERR_FMT "_send_handshake FAILED!" - " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd, - hd->ioc, mf)); - goto mptctl_bus_reset_done; + + if ((ioctl->ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) && + (ioctl->ioc->facts.MsgVersion >= MPI_VERSION_01_05)) + mpt_put_msg_frame_hi_pri(mptctl_id, ioctl->ioc, mf); + else { + retval = mpt_send_handshake_request(mptctl_id, ioctl->ioc, + sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP); + if (retval != 0) { + dfailprintk(ioctl->ioc, printk(MYIOC_s_ERR_FMT "_send_handshake FAILED!" + " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd, + hd->ioc, mf)); + goto mptctl_bus_reset_done; + } } /* Now wait for the command to complete */ @@ -444,7 +449,7 @@ mptctl_free_tm_flags(MPT_ADAPTER *ioc) MPT_SCSI_HOST * hd; unsigned long flags; - hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; + hd = shost_priv(ioc->sh); if (hd == NULL) return; @@ -468,7 +473,7 @@ static int mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) { MPT_IOCTL *ioctl = ioc->ioctl; - dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": IOC %s_reset routed to IOCTL driver!\n",ioc->name, + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC %s_reset routed to IOCTL driver!\n", ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : ( reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); @@ -574,7 +579,7 @@ __mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) MPT_ADAPTER *iocp = NULL; if (copy_from_user(&khdr, uhdr, sizeof(khdr))) { - printk(KERN_ERR "%s::mptctl_ioctl() @%d - " + printk(KERN_ERR MYNAM "%s::mptctl_ioctl() @%d - " "Unable to copy mpt_ioctl_header data @ %p\n", __FILE__, __LINE__, uhdr); return -EFAULT; @@ -587,13 +592,13 @@ __mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) iocnumX = khdr.iocnum & 0xFF; if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || (iocp == NULL)) { - printk(KERN_DEBUG "%s::mptctl_ioctl() @%d - ioc%d not found!\n", + printk(KERN_DEBUG MYNAM "%s::mptctl_ioctl() @%d - ioc%d not found!\n", __FILE__, __LINE__, iocnumX); return -ENODEV; } if (!iocp->active) { - printk(KERN_DEBUG "%s::mptctl_ioctl() @%d - Controller disabled.\n", + printk(KERN_DEBUG MYNAM "%s::mptctl_ioctl() @%d - Controller disabled.\n", __FILE__, __LINE__); return -EFAULT; } @@ -660,14 +665,14 @@ static int mptctl_do_reset(unsigned long arg) MPT_ADAPTER *iocp; if (copy_from_user(&krinfo, urinfo, sizeof(struct mpt_ioctl_diag_reset))) { - printk(KERN_ERR "%s@%d::mptctl_do_reset - " + printk(KERN_ERR MYNAM "%s@%d::mptctl_do_reset - " "Unable to copy mpt_ioctl_diag_reset struct @ %p\n", __FILE__, __LINE__, urinfo); return -EFAULT; } if (mpt_verify_adapter(krinfo.hdr.iocnum, &iocp) < 0) { - printk(KERN_DEBUG "%s@%d::mptctl_do_reset - ioc%d not found!\n", + printk(KERN_DEBUG MYNAM "%s@%d::mptctl_do_reset - ioc%d not found!\n", __FILE__, __LINE__, krinfo.hdr.iocnum); return -ENODEV; /* (-6) No such device or address */ } @@ -676,8 +681,8 @@ static int mptctl_do_reset(unsigned long arg) iocp->name)); if (mpt_HardResetHandler(iocp, CAN_SLEEP) != 0) { - printk (KERN_ERR "%s@%d::mptctl_do_reset - reset failed.\n", - __FILE__, __LINE__); + printk (MYIOC_s_ERR_FMT "%s@%d::mptctl_do_reset - reset failed.\n", + iocp->name, __FILE__, __LINE__); return -1; } @@ -708,7 +713,7 @@ mptctl_fw_download(unsigned long arg) struct mpt_fw_xfer kfwdl; if (copy_from_user(&kfwdl, ufwdl, sizeof(struct mpt_fw_xfer))) { - printk(KERN_ERR "%s@%d::_ioctl_fwdl - " + printk(KERN_ERR MYNAM "%s@%d::_ioctl_fwdl - " "Unable to copy mpt_fw_xfer struct @ %p\n", __FILE__, __LINE__, ufwdl); return -EFAULT; @@ -756,7 +761,8 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen) pFWDownloadReply_t ReplyMsg = NULL; if (mpt_verify_adapter(ioc, &iocp) < 0) { - printk(KERN_DEBUG "ioctl_fwdl - ioc%d not found!\n", ioc); + printk(KERN_DEBUG MYNAM "ioctl_fwdl - ioc%d not found!\n", + ioc); return -ENODEV; /* (-6) No such device or address */ } else { @@ -868,9 +874,9 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen) mpt_add_sge(sgOut, sgIn->FlagsLength, sgIn->Address); n++; if (copy_from_user(bl->kptr, ufwbuf+fw_bytes_copied, bl->len)) { - printk(KERN_ERR "%s@%d::_ioctl_fwdl - " - "Unable to copy f/w buffer hunk#%d @ %p\n", - __FILE__, __LINE__, n, ufwbuf); + printk(MYIOC_s_ERR_FMT "%s@%d::_ioctl_fwdl - " + "Unable to copy f/w buffer hunk#%d @ %p\n", + iocp->name, __FILE__, __LINE__, n, ufwbuf); goto fwdl_out; } fw_bytes_copied += bl->len; @@ -906,21 +912,22 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen) ReplyMsg = (pFWDownloadReply_t)iocp->ioctl->ReplyFrame; iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK; if (iocstat == MPI_IOCSTATUS_SUCCESS) { - printk(KERN_INFO MYNAM ": F/W update successfully sent to %s!\n", iocp->name); + printk(MYIOC_s_INFO_FMT "F/W update successfull!\n", iocp->name); return 0; } else if (iocstat == MPI_IOCSTATUS_INVALID_FUNCTION) { - printk(KERN_WARNING MYNAM ": ?Hmmm... %s says it doesn't support F/W download!?!\n", - iocp->name); - printk(KERN_WARNING MYNAM ": (time to go bang on somebodies door)\n"); + printk(MYIOC_s_WARN_FMT "Hmmm... F/W download not supported!?!\n", + iocp->name); + printk(MYIOC_s_WARN_FMT "(time to go bang on somebodies door)\n", + iocp->name); return -EBADRQC; } else if (iocstat == MPI_IOCSTATUS_BUSY) { - printk(KERN_WARNING MYNAM ": Warning! %s says: IOC_BUSY!\n", iocp->name); - printk(KERN_WARNING MYNAM ": (try again later?)\n"); + printk(MYIOC_s_WARN_FMT "IOC_BUSY!\n", iocp->name); + printk(MYIOC_s_WARN_FMT "(try again later?)\n", iocp->name); return -EBUSY; } else { - printk(KERN_WARNING MYNAM "::ioctl_fwdl() ERROR! %s returned [bad] status = %04xh\n", - iocp->name, iocstat); - printk(KERN_WARNING MYNAM ": (bad VooDoo)\n"); + printk(MYIOC_s_WARN_FMT "ioctl_fwdl() returned [bad] status = %04xh\n", + iocp->name, iocstat); + printk(MYIOC_s_WARN_FMT "(bad VooDoo)\n", iocp->name); return -ENOMSG; } return 0; @@ -970,10 +977,9 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags, * structures for the SG elements. */ i = MAX_SGL_BYTES / 8; - buflist = kmalloc(i, GFP_USER); - if (buflist == NULL) + buflist = kzalloc(i, GFP_USER); + if (!buflist) return NULL; - memset(buflist, 0, i); buflist_ent = 0; /* Allocate a single block of memory to store the sg elements and @@ -1008,10 +1014,10 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags, if (buflist[buflist_ent].kptr == NULL) { alloc_sz = alloc_sz / 2; if (alloc_sz == 0) { - printk(KERN_WARNING MYNAM "-SG: No can do - " - "not enough memory! :-(\n"); - printk(KERN_WARNING MYNAM "-SG: (freeing %d frags)\n", - numfrags); + printk(MYIOC_s_WARN_FMT "-SG: No can do - " + "not enough memory! :-(\n", ioc->name); + printk(MYIOC_s_WARN_FMT "-SG: (freeing %d frags)\n", + ioc->name, numfrags); goto free_and_fail; } continue; @@ -1034,18 +1040,19 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags, /* Need to chain? */ if (fragcnt == sg_spill) { - printk(KERN_WARNING MYNAM "-SG: No can do - " "Chain required! :-(\n"); - printk(KERN_WARNING MYNAM "(freeing %d frags)\n", numfrags); + printk(MYIOC_s_WARN_FMT + "-SG: No can do - " "Chain required! :-(\n", ioc->name); + printk(MYIOC_s_WARN_FMT "(freeing %d frags)\n", ioc->name, numfrags); goto free_and_fail; } /* overflow check... */ if (numfrags*8 > MAX_SGL_BYTES){ /* GRRRRR... */ - printk(KERN_WARNING MYNAM "-SG: No can do - " - "too many SG frags! :-(\n"); - printk(KERN_WARNING MYNAM "-SG: (freeing %d frags)\n", - numfrags); + printk(MYIOC_s_WARN_FMT "-SG: No can do - " + "too many SG frags! :-(\n", ioc->name); + printk(MYIOC_s_WARN_FMT "-SG: (freeing %d frags)\n", + ioc->name, numfrags); goto free_and_fail; } } @@ -1066,8 +1073,6 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags, free_and_fail: if (sglbuf != NULL) { - int i; - for (i = 0; i < numfrags; i++) { dma_addr_t dma_addr; u8 *kptr; @@ -1170,7 +1175,7 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size) int cim_rev; u8 revision; struct scsi_device *sdev; - VirtDevice *vdev; + VirtDevice *vdevice; /* Add of PCI INFO results in unaligned access for * IA64 and Sparc. Reset long to int. Return no PCI @@ -1189,13 +1194,13 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size) karg = kmalloc(data_size, GFP_KERNEL); if (karg == NULL) { - printk(KERN_ERR "%s::mpt_ioctl_iocinfo() @%d - no memory available!\n", + printk(KERN_ERR MYNAM "%s::mpt_ioctl_iocinfo() @%d - no memory available!\n", __FILE__, __LINE__); return -ENOMEM; } if (copy_from_user(karg, uarg, data_size)) { - printk(KERN_ERR "%s@%d::mptctl_getiocinfo - " + printk(KERN_ERR MYNAM "%s@%d::mptctl_getiocinfo - " "Unable to read in mpt_ioctl_iocinfo struct @ %p\n", __FILE__, __LINE__, uarg); kfree(karg); @@ -1204,7 +1209,7 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size) if (((iocnum = mpt_verify_adapter(karg->hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - printk(KERN_DEBUG "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n", + printk(KERN_DEBUG MYNAM "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n", __FILE__, __LINE__, iocnum); kfree(karg); return -ENODEV; @@ -1212,9 +1217,9 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size) /* Verify the data transfer size is correct. */ if (karg->hdr.maxDataSize != data_size) { - printk(KERN_ERR "%s@%d::mptctl_getiocinfo - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_getiocinfo - " "Structure size mismatch. Command not completed.\n", - __FILE__, __LINE__); + ioc->name, __FILE__, __LINE__); kfree(karg); return -EFAULT; } @@ -1265,8 +1270,8 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size) karg->numDevices = 0; if (ioc->sh) { shost_for_each_device(sdev, ioc->sh) { - vdev = sdev->hostdata; - if (vdev->vtarget->tflags & + vdevice = sdev->hostdata; + if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) continue; karg->numDevices++; @@ -1290,9 +1295,9 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size) /* Copy the data from kernel memory to user memory */ if (copy_to_user((char __user *)arg, karg, data_size)) { - printk(KERN_ERR "%s@%d::mptctl_getiocinfo - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_getiocinfo - " "Unable to write out mpt_ioctl_iocinfo struct @ %p\n", - __FILE__, __LINE__, uarg); + ioc->name, __FILE__, __LINE__, uarg); kfree(karg); return -EFAULT; } @@ -1317,7 +1322,7 @@ mptctl_gettargetinfo (unsigned long arg) struct mpt_ioctl_targetinfo __user *uarg = (void __user *) arg; struct mpt_ioctl_targetinfo karg; MPT_ADAPTER *ioc; - VirtDevice *vdev; + VirtDevice *vdevice; char *pmem; int *pdata; int iocnum; @@ -1329,7 +1334,7 @@ mptctl_gettargetinfo (unsigned long arg) struct scsi_device *sdev; if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_targetinfo))) { - printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - " + printk(KERN_ERR MYNAM "%s@%d::mptctl_gettargetinfo - " "Unable to read in mpt_ioctl_targetinfo struct @ %p\n", __FILE__, __LINE__, uarg); return -EFAULT; @@ -1337,7 +1342,7 @@ mptctl_gettargetinfo (unsigned long arg) if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - printk(KERN_DEBUG "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n", + printk(KERN_DEBUG MYNAM "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n", __FILE__, __LINE__, iocnum); return -ENODEV; } @@ -1353,8 +1358,8 @@ mptctl_gettargetinfo (unsigned long arg) port = karg.hdr.port; if (maxWordsLeft <= 0) { - printk(KERN_ERR "%s::mptctl_gettargetinfo() @%d - no memory available!\n", - __FILE__, __LINE__); + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo() - no memory available!\n", + ioc->name, __FILE__, __LINE__); return -ENOMEM; } @@ -1372,13 +1377,12 @@ mptctl_gettargetinfo (unsigned long arg) * 15- 8: Bus Number * 7- 0: Target ID */ - pmem = kmalloc(numBytes, GFP_KERNEL); - if (pmem == NULL) { - printk(KERN_ERR "%s::mptctl_gettargetinfo() @%d - no memory available!\n", - __FILE__, __LINE__); + pmem = kzalloc(numBytes, GFP_KERNEL); + if (!pmem) { + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo() - no memory available!\n", + ioc->name, __FILE__, __LINE__); return -ENOMEM; } - memset(pmem, 0, numBytes); pdata = (int *) pmem; /* Get number of devices @@ -1387,13 +1391,13 @@ mptctl_gettargetinfo (unsigned long arg) shost_for_each_device(sdev, ioc->sh) { if (!maxWordsLeft) continue; - vdev = sdev->hostdata; - if (vdev->vtarget->tflags & + vdevice = sdev->hostdata; + if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) continue; - lun = (vdev->vtarget->raidVolume) ? 0x80 : vdev->lun; - *pdata = (((u8)lun << 16) + (vdev->vtarget->channel << 8) + - (vdev->vtarget->id )); + lun = (vdevice->vtarget->raidVolume) ? 0x80 : vdevice->lun; + *pdata = (((u8)lun << 16) + (vdevice->vtarget->channel << 8) + + (vdevice->vtarget->id )); pdata++; numDevices++; --maxWordsLeft; @@ -1405,9 +1409,9 @@ mptctl_gettargetinfo (unsigned long arg) */ if (copy_to_user((char __user *)arg, &karg, sizeof(struct mpt_ioctl_targetinfo))) { - printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo - " "Unable to write out mpt_ioctl_targetinfo struct @ %p\n", - __FILE__, __LINE__, uarg); + ioc->name, __FILE__, __LINE__, uarg); kfree(pmem); return -EFAULT; } @@ -1415,9 +1419,9 @@ mptctl_gettargetinfo (unsigned long arg) /* Copy the remaining data from kernel memory to user memory */ if (copy_to_user(uarg->targetInfo, pmem, numBytes)) { - printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo - " "Unable to write out mpt_ioctl_targetinfo struct @ %p\n", - __FILE__, __LINE__, pdata); + ioc->name, __FILE__, __LINE__, pdata); kfree(pmem); return -EFAULT; } @@ -1444,7 +1448,7 @@ mptctl_readtest (unsigned long arg) int iocnum; if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_test))) { - printk(KERN_ERR "%s@%d::mptctl_readtest - " + printk(KERN_ERR MYNAM "%s@%d::mptctl_readtest - " "Unable to read in mpt_ioctl_test struct @ %p\n", __FILE__, __LINE__, uarg); return -EFAULT; @@ -1452,7 +1456,7 @@ mptctl_readtest (unsigned long arg) if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - printk(KERN_DEBUG "%s::mptctl_readtest() @%d - ioc%d not found!\n", + printk(KERN_DEBUG MYNAM "%s::mptctl_readtest() @%d - ioc%d not found!\n", __FILE__, __LINE__, iocnum); return -ENODEV; } @@ -1476,9 +1480,9 @@ mptctl_readtest (unsigned long arg) /* Copy the data from kernel memory to user memory */ if (copy_to_user((char __user *)arg, &karg, sizeof(struct mpt_ioctl_test))) { - printk(KERN_ERR "%s@%d::mptctl_readtest - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_readtest - " "Unable to write out mpt_ioctl_test struct @ %p\n", - __FILE__, __LINE__, uarg); + ioc->name, __FILE__, __LINE__, uarg); return -EFAULT; } @@ -1505,7 +1509,7 @@ mptctl_eventquery (unsigned long arg) int iocnum; if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventquery))) { - printk(KERN_ERR "%s@%d::mptctl_eventquery - " + printk(KERN_ERR MYNAM "%s@%d::mptctl_eventquery - " "Unable to read in mpt_ioctl_eventquery struct @ %p\n", __FILE__, __LINE__, uarg); return -EFAULT; @@ -1513,7 +1517,7 @@ mptctl_eventquery (unsigned long arg) if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - printk(KERN_DEBUG "%s::mptctl_eventquery() @%d - ioc%d not found!\n", + printk(KERN_DEBUG MYNAM "%s::mptctl_eventquery() @%d - ioc%d not found!\n", __FILE__, __LINE__, iocnum); return -ENODEV; } @@ -1526,9 +1530,9 @@ mptctl_eventquery (unsigned long arg) /* Copy the data from kernel memory to user memory */ if (copy_to_user((char __user *)arg, &karg, sizeof(struct mpt_ioctl_eventquery))) { - printk(KERN_ERR "%s@%d::mptctl_eventquery - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_eventquery - " "Unable to write out mpt_ioctl_eventquery struct @ %p\n", - __FILE__, __LINE__, uarg); + ioc->name, __FILE__, __LINE__, uarg); return -EFAULT; } return 0; @@ -1544,7 +1548,7 @@ mptctl_eventenable (unsigned long arg) int iocnum; if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventenable))) { - printk(KERN_ERR "%s@%d::mptctl_eventenable - " + printk(KERN_ERR MYNAM "%s@%d::mptctl_eventenable - " "Unable to read in mpt_ioctl_eventenable struct @ %p\n", __FILE__, __LINE__, uarg); return -EFAULT; @@ -1552,7 +1556,7 @@ mptctl_eventenable (unsigned long arg) if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - printk(KERN_DEBUG "%s::mptctl_eventenable() @%d - ioc%d not found!\n", + printk(KERN_DEBUG MYNAM "%s::mptctl_eventenable() @%d - ioc%d not found!\n", __FILE__, __LINE__, iocnum); return -ENODEV; } @@ -1563,12 +1567,13 @@ mptctl_eventenable (unsigned long arg) /* Have not yet allocated memory - do so now. */ int sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS); - ioc->events = kmalloc(sz, GFP_KERNEL); - if (ioc->events == NULL) { - printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n"); + ioc->events = kzalloc(sz, GFP_KERNEL); + if (!ioc->events) { + printk(MYIOC_s_ERR_FMT + ": ERROR - Insufficient memory to add adapter!\n", + ioc->name); return -ENOMEM; } - memset(ioc->events, 0, sz); ioc->alloc_total += sz; ioc->eventContext = 0; @@ -1592,7 +1597,7 @@ mptctl_eventreport (unsigned long arg) int numBytes, maxEvents, max; if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventreport))) { - printk(KERN_ERR "%s@%d::mptctl_eventreport - " + printk(KERN_ERR MYNAM "%s@%d::mptctl_eventreport - " "Unable to read in mpt_ioctl_eventreport struct @ %p\n", __FILE__, __LINE__, uarg); return -EFAULT; @@ -1600,7 +1605,7 @@ mptctl_eventreport (unsigned long arg) if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - printk(KERN_DEBUG "%s::mptctl_eventreport() @%d - ioc%d not found!\n", + printk(KERN_DEBUG MYNAM "%s::mptctl_eventreport() @%d - ioc%d not found!\n", __FILE__, __LINE__, iocnum); return -ENODEV; } @@ -1626,9 +1631,9 @@ mptctl_eventreport (unsigned long arg) */ numBytes = max * sizeof(MPT_IOCTL_EVENTS); if (copy_to_user(uarg->eventData, ioc->events, numBytes)) { - printk(KERN_ERR "%s@%d::mptctl_eventreport - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_eventreport - " "Unable to write out mpt_ioctl_eventreport struct @ %p\n", - __FILE__, __LINE__, ioc->events); + ioc->name, __FILE__, __LINE__, ioc->events); return -EFAULT; } @@ -1646,7 +1651,7 @@ mptctl_replace_fw (unsigned long arg) int newFwSize; if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_replace_fw))) { - printk(KERN_ERR "%s@%d::mptctl_replace_fw - " + printk(KERN_ERR MYNAM "%s@%d::mptctl_replace_fw - " "Unable to read in mpt_ioctl_replace_fw struct @ %p\n", __FILE__, __LINE__, uarg); return -EFAULT; @@ -1654,7 +1659,7 @@ mptctl_replace_fw (unsigned long arg) if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - printk(KERN_DEBUG "%s::mptctl_replace_fw() @%d - ioc%d not found!\n", + printk(KERN_DEBUG MYNAM "%s::mptctl_replace_fw() @%d - ioc%d not found!\n", __FILE__, __LINE__, iocnum); return -ENODEV; } @@ -1684,9 +1689,9 @@ mptctl_replace_fw (unsigned long arg) /* Copy the data from user memory to kernel space */ if (copy_from_user(ioc->cached_fw, uarg->newImage, newFwSize)) { - printk(KERN_ERR "%s@%d::mptctl_replace_fw - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_replace_fw - " "Unable to read in mpt_ioctl_replace_fw image " - "@ %p\n", __FILE__, __LINE__, uarg); + "@ %p\n", ioc->name, __FILE__, __LINE__, uarg); mpt_free_fw_memory(ioc); return -EFAULT; } @@ -1720,7 +1725,7 @@ mptctl_mpt_command (unsigned long arg) if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_command))) { - printk(KERN_ERR "%s@%d::mptctl_mpt_command - " + printk(KERN_ERR MYNAM "%s@%d::mptctl_mpt_command - " "Unable to read in mpt_ioctl_command struct @ %p\n", __FILE__, __LINE__, uarg); return -EFAULT; @@ -1728,7 +1733,7 @@ mptctl_mpt_command (unsigned long arg) if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - printk(KERN_DEBUG "%s::mptctl_mpt_command() @%d - ioc%d not found!\n", + printk(KERN_DEBUG MYNAM "%s::mptctl_mpt_command() @%d - ioc%d not found!\n", __FILE__, __LINE__, iocnum); return -ENODEV; } @@ -1769,21 +1774,24 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) ulong timeout; struct scsi_device *sdev; + /* bufIn and bufOut are used for user to kernel space transfers + */ bufIn.kptr = bufOut.kptr = NULL; + bufIn.len = bufOut.len = 0; if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - printk(KERN_DEBUG "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n", + printk(KERN_DEBUG MYNAM "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n", __FILE__, __LINE__, iocnum); return -ENODEV; } if (!ioc->ioctl) { - printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + printk(KERN_ERR MYNAM "%s@%d::mptctl_do_mpt_command - " "No memory available during driver init.\n", __FILE__, __LINE__); return -ENOMEM; } else if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_IOCRESET) { - printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + printk(KERN_ERR MYNAM "%s@%d::mptctl_do_mpt_command - " "Busy with IOC Reset \n", __FILE__, __LINE__); return -EBUSY; } @@ -1797,9 +1805,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) sz += sizeof(dma_addr_t) + sizeof(u32); if (sz > ioc->req_sz) { - printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "Request frame too large (%d) maximum (%d)\n", - __FILE__, __LINE__, sz, ioc->req_sz); + ioc->name, __FILE__, __LINE__, sz, ioc->req_sz); return -EFAULT; } @@ -1817,9 +1825,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) * Request frame in user space */ if (copy_from_user(mf, mfPtr, karg.dataSgeOffset * 4)) { - printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "Unable to read MF from mpt_ioctl_command struct @ %p\n", - __FILE__, __LINE__, mfPtr); + ioc->name, __FILE__, __LINE__, mfPtr); rc = -EFAULT; goto done_free_mem; } @@ -1870,17 +1878,17 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) id = (ioc->devices_per_bus == 0) ? 256 : ioc->devices_per_bus; if (pScsiReq->TargetID > id) { - printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "Target ID out of bounds. \n", - __FILE__, __LINE__); + ioc->name, __FILE__, __LINE__); rc = -ENODEV; goto done_free_mem; } if (pScsiReq->Bus >= ioc->number_of_buses) { - printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "Target Bus out of bounds. \n", - __FILE__, __LINE__); + ioc->name, __FILE__, __LINE__); rc = -ENODEV; goto done_free_mem; } @@ -1932,9 +1940,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) ioc->ioctl->id = pScsiReq->TargetID; } else { - printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "SCSI driver is not loaded. \n", - __FILE__, __LINE__); + ioc->name, __FILE__, __LINE__); rc = -EFAULT; goto done_free_mem; } @@ -1951,9 +1959,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) case MPI_FUNCTION_SATA_PASSTHROUGH: if (!ioc->sh) { - printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "SCSI driver is not loaded. \n", - __FILE__, __LINE__); + ioc->name, __FILE__, __LINE__); rc = -EFAULT; goto done_free_mem; } @@ -2010,9 +2018,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) ioc->ioctl->reset = MPTCTL_RESET_OK; ioc->ioctl->id = pScsiReq->TargetID; } else { - printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "SCSI driver is not loaded. \n", - __FILE__, __LINE__); + ioc->name, __FILE__, __LINE__); rc = -EFAULT; goto done_free_mem; } @@ -2021,10 +2029,10 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) case MPI_FUNCTION_SCSI_TASK_MGMT: { MPT_SCSI_HOST *hd = NULL; - if ((ioc->sh == NULL) || ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL)) { - printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + if ((ioc->sh == NULL) || ((hd = shost_priv(ioc->sh)) == NULL)) { + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "SCSI driver not loaded or SCSI host not found. \n", - __FILE__, __LINE__); + ioc->name, __FILE__, __LINE__); rc = -EFAULT; goto done_free_mem; } else if (mptctl_set_tm_flags(hd) != 0) { @@ -2055,9 +2063,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) (pInit->ReplyFrameSize != cpu_to_le16(ioc->reply_sz)) || (pInit->HostMfaHighAddr != high_addr) || (pInit->SenseBufferHighAddr != sense_high)) { - printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "IOC_INIT issued with 1 or more incorrect parameters. Rejected.\n", - __FILE__, __LINE__); + ioc->name, __FILE__, __LINE__); rc = -EFAULT; goto done_free_mem; } @@ -2088,9 +2096,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) MPI_FUNCTION_LAN_RESET */ - printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "Illegal request (function 0x%x) \n", - __FILE__, __LINE__, hdr->Function); + ioc->name, __FILE__, __LINE__, hdr->Function); rc = -EFAULT; goto done_free_mem; } @@ -2103,11 +2111,6 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) psge = (char *) (((int *) mf) + karg.dataSgeOffset); flagsLength = 0; - /* bufIn and bufOut are used for user to kernel space transfers - */ - bufIn.kptr = bufOut.kptr = NULL; - bufIn.len = bufOut.len = 0; - if (karg.dataOutSize > 0) sgSize ++; @@ -2147,11 +2150,11 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) if (copy_from_user(bufOut.kptr, karg.dataOutBufPtr, bufOut.len)) { - printk(KERN_ERR + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - Unable " "to read user data " "struct @ %p\n", - __FILE__, __LINE__,karg.dataOutBufPtr); + ioc->name, __FILE__, __LINE__,karg.dataOutBufPtr); rc = -EFAULT; goto done_free_mem; } @@ -2187,15 +2190,20 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf); - if (mpt_send_handshake_request(mptctl_id, ioc, - sizeof(SCSITaskMgmt_t), (u32*)mf, - CAN_SLEEP) != 0) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "_send_handshake FAILED!" - " (ioc %p, mf %p) \n", ioc->name, - ioc, mf)); - mptctl_free_tm_flags(ioc); - rc = -ENODATA; - goto done_free_mem; + if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) && + (ioc->facts.MsgVersion >= MPI_VERSION_01_05)) + mpt_put_msg_frame_hi_pri(mptctl_id, ioc, mf); + else { + rc =mpt_send_handshake_request(mptctl_id, ioc, + sizeof(SCSITaskMgmt_t), (u32*)mf, CAN_SLEEP); + if (rc != 0) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "_send_handshake FAILED! (ioc %p, mf %p)\n", + ioc->name, ioc, mf)); + mptctl_free_tm_flags(ioc); + rc = -ENODATA; + goto done_free_mem; + } } } else @@ -2233,10 +2241,10 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) if (sz > 0) { if (copy_to_user(karg.replyFrameBufPtr, &ioc->ioctl->ReplyFrame, sz)){ - printk(KERN_ERR + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "Unable to write out reply frame %p\n", - __FILE__, __LINE__, karg.replyFrameBufPtr); + ioc->name, __FILE__, __LINE__, karg.replyFrameBufPtr); rc = -ENODATA; goto done_free_mem; } @@ -2249,9 +2257,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) sz = min(karg.maxSenseBytes, MPT_SENSE_BUFFER_SIZE); if (sz > 0) { if (copy_to_user(karg.senseDataPtr, ioc->ioctl->sense, sz)) { - printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "Unable to write sense data to user %p\n", - __FILE__, __LINE__, + ioc->name, __FILE__, __LINE__, karg.senseDataPtr); rc = -ENODATA; goto done_free_mem; @@ -2267,9 +2275,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) if (copy_to_user(karg.dataInBufPtr, bufIn.kptr, karg.dataInSize)) { - printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "Unable to write data to user %p\n", - __FILE__, __LINE__, + ioc->name, __FILE__, __LINE__, karg.dataInBufPtr); rc = -ENODATA; } @@ -2340,7 +2348,7 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size) return -EFAULT; if (copy_from_user(&karg, uarg, sizeof(hp_host_info_t))) { - printk(KERN_ERR "%s@%d::mptctl_hp_host_info - " + printk(KERN_ERR MYNAM "%s@%d::mptctl_hp_host_info - " "Unable to read in hp_host_info struct @ %p\n", __FILE__, __LINE__, uarg); return -EFAULT; @@ -2348,7 +2356,7 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size) if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - printk(KERN_DEBUG "%s::mptctl_hp_hostinfo() @%d - ioc%d not found!\n", + printk(KERN_DEBUG MYNAM "%s::mptctl_hp_hostinfo() @%d - ioc%d not found!\n", __FILE__, __LINE__, iocnum); return -ENODEV; } @@ -2456,7 +2464,7 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size) karg.soft_resets = 0; karg.timeouts = 0; if (ioc->sh != NULL) { - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata; + MPT_SCSI_HOST *hd = shost_priv(ioc->sh); if (hd && (cim_rev == 1)) { karg.hard_resets = hd->hard_resets; @@ -2529,9 +2537,9 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size) /* Copy the data from kernel memory to user memory */ if (copy_to_user((char __user *)arg, &karg, sizeof(hp_host_info_t))) { - printk(KERN_ERR "%s@%d::mptctl_hpgethostinfo - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_hpgethostinfo - " "Unable to write out hp_host_info @ %p\n", - __FILE__, __LINE__, uarg); + ioc->name, __FILE__, __LINE__, uarg); return -EFAULT; } @@ -2567,7 +2575,7 @@ mptctl_hp_targetinfo(unsigned long arg) int tmp, np, rc = 0; if (copy_from_user(&karg, uarg, sizeof(hp_target_info_t))) { - printk(KERN_ERR "%s@%d::mptctl_hp_targetinfo - " + printk(KERN_ERR MYNAM "%s@%d::mptctl_hp_targetinfo - " "Unable to read in hp_host_targetinfo struct @ %p\n", __FILE__, __LINE__, uarg); return -EFAULT; @@ -2575,11 +2583,11 @@ mptctl_hp_targetinfo(unsigned long arg) if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - printk(KERN_DEBUG "%s::mptctl_hp_targetinfo() @%d - ioc%d not found!\n", + printk(KERN_DEBUG MYNAM "%s::mptctl_hp_targetinfo() @%d - ioc%d not found!\n", __FILE__, __LINE__, iocnum); return -ENODEV; } - dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": mptctl_hp_targetinfo called.\n", + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_hp_targetinfo called.\n", ioc->name)); /* There is nothing to do for FCP parts. @@ -2673,16 +2681,16 @@ mptctl_hp_targetinfo(unsigned long arg) pci_free_consistent(ioc->pcidev, data_sz, (u8 *) pg3_alloc, page_dma); } } - hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; + hd = shost_priv(ioc->sh); if (hd != NULL) karg.select_timeouts = hd->sel_timeout[karg.hdr.id]; /* Copy the data from kernel memory to user memory */ if (copy_to_user((char __user *)arg, &karg, sizeof(hp_target_info_t))) { - printk(KERN_ERR "%s@%d::mptctl_hp_target_info - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_hp_target_info - " "Unable to write out mpt_ioctl_targetinfo struct @ %p\n", - __FILE__, __LINE__, uarg); + ioc->name, __FILE__, __LINE__, uarg); return -EFAULT; } @@ -2732,7 +2740,7 @@ compat_mptfwxfer_ioctl(struct file *filp, unsigned int cmd, if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || (iocp == NULL)) { printk(KERN_DEBUG MYNAM "::compat_mptfwxfer_ioctl @%d - ioc%d not found!\n", - __LINE__, iocnumX); + __LINE__, iocnumX); return -ENODEV; } @@ -2772,7 +2780,7 @@ compat_mpt_command(struct file *filp, unsigned int cmd, if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || (iocp == NULL)) { printk(KERN_DEBUG MYNAM "::compat_mpt_command @%d - ioc%d not found!\n", - __LINE__, iocnumX); + __LINE__, iocnumX); return -ENODEV; } @@ -2853,31 +2861,22 @@ static long compat_mpctl_ioctl(struct file *f, unsigned int cmd, unsigned long a static int mptctl_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - int err; - int sz; - u8 *mem; + MPT_IOCTL *mem; MPT_ADAPTER *ioc = pci_get_drvdata(pdev); /* * Allocate and inite a MPT_IOCTL structure */ - sz = sizeof (MPT_IOCTL); - mem = kmalloc(sz, GFP_KERNEL); - if (mem == NULL) { - err = -ENOMEM; - goto out_fail; + mem = kzalloc(sizeof(MPT_IOCTL), GFP_KERNEL); + if (!mem) { + mptctl_remove(pdev); + return -ENOMEM; } - memset(mem, 0, sz); - ioc->ioctl = (MPT_IOCTL *) mem; + ioc->ioctl = mem; ioc->ioctl->ioc = ioc; mutex_init(&ioc->ioctl->ioctl_mutex); return 0; - -out_fail: - - mptctl_remove(pdev); - return err; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -2924,7 +2923,8 @@ static int __init mptctl_init(void) * Install our handler */ ++where; - if ((mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER)) < 0) { + mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER); + if (!mptctl_id || mptctl_id >= MPT_MAX_PROTOCOL_DRIVERS) { printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n"); misc_deregister(&mptctl_miscdev); err = -EBUSY; diff --git a/drivers/message/fusion/mptctl.h b/drivers/message/fusion/mptctl.h index 180b3c156247..2c1890127e15 100644 --- a/drivers/message/fusion/mptctl.h +++ b/drivers/message/fusion/mptctl.h @@ -3,9 +3,9 @@ * Fusion MPT misc device (ioctl) driver. * For use with PCI chip/adapter(s): * LSIFC9xx/LSI409xx Fibre Channel - * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * running LSI Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2007 LSI Logic Corporation + * Copyright (c) 1999-2007 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) * */ diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index 8422c25e4a3e..3cdd4e962115 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -1,9 +1,9 @@ /* * linux/drivers/message/fusion/mptfc.c - * For use with LSI Logic PCI chip/adapter(s) - * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * For use with LSI PCI chip/adapter(s) + * running LSI Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2007 LSI Logic Corporation + * Copyright (c) 1999-2007 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) * */ @@ -90,9 +90,9 @@ static int max_lun = MPTFC_MAX_LUN; module_param(max_lun, int, 0); MODULE_PARM_DESC(max_lun, " max lun, default=16895 "); -static int mptfcDoneCtx = -1; -static int mptfcTaskCtx = -1; -static int mptfcInternalCtx = -1; /* Used only for internal commands */ +static u8 mptfcDoneCtx = MPT_MAX_PROTOCOL_DRIVERS; +static u8 mptfcTaskCtx = MPT_MAX_PROTOCOL_DRIVERS; +static u8 mptfcInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; static int mptfc_target_alloc(struct scsi_target *starget); static int mptfc_slave_alloc(struct scsi_device *sdev); @@ -194,37 +194,36 @@ mptfc_block_error_handler(struct scsi_cmnd *SCpnt, struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); unsigned long flags; int ready; + MPT_ADAPTER *ioc; - hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata; + hd = shost_priv(SCpnt->device->host); + ioc = hd->ioc; spin_lock_irqsave(shost->host_lock, flags); while ((ready = fc_remote_port_chkready(rport) >> 16) == DID_IMM_RETRY) { spin_unlock_irqrestore(shost->host_lock, flags); - dfcprintk (hd->ioc, printk(MYIOC_s_DEBUG_FMT + dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT "mptfc_block_error_handler.%d: %d:%d, port status is " "DID_IMM_RETRY, deferring %s recovery.\n", - ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name, - ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no, - SCpnt->device->id,SCpnt->device->lun,caller)); + ioc->name, ioc->sh->host_no, + SCpnt->device->id, SCpnt->device->lun, caller)); msleep(1000); spin_lock_irqsave(shost->host_lock, flags); } spin_unlock_irqrestore(shost->host_lock, flags); if (ready == DID_NO_CONNECT || !SCpnt->device->hostdata) { - dfcprintk (hd->ioc, printk(MYIOC_s_DEBUG_FMT + dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT "%s.%d: %d:%d, failing recovery, " - "port state %d, vdev %p.\n", caller, - ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name, - ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no, - SCpnt->device->id,SCpnt->device->lun,ready, + "port state %d, vdevice %p.\n", caller, + ioc->name, ioc->sh->host_no, + SCpnt->device->id, SCpnt->device->lun, ready, SCpnt->device->hostdata)); return FAILED; } - dfcprintk (hd->ioc, printk(MYIOC_s_DEBUG_FMT + dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT "%s.%d: %d:%d, executing recovery.\n", caller, - ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name, - ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no, - SCpnt->device->id,SCpnt->device->lun)); + ioc->name, ioc->sh->host_no, + SCpnt->device->id, SCpnt->device->lun)); return (*func)(SCpnt); } @@ -470,7 +469,7 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) /* * if already mapped, remap here. If not mapped, * target_alloc will allocate vtarget and map, - * slave_alloc will fill in vdev from vtarget. + * slave_alloc will fill in vdevice from vtarget. */ if (ri->starget) { vtarget = ri->starget->hostdata; @@ -602,10 +601,10 @@ mptfc_slave_alloc(struct scsi_device *sdev) { MPT_SCSI_HOST *hd; VirtTarget *vtarget; - VirtDevice *vdev; + VirtDevice *vdevice; struct scsi_target *starget; struct fc_rport *rport; - + MPT_ADAPTER *ioc; starget = scsi_target(sdev); rport = starget_to_rport(starget); @@ -613,31 +612,32 @@ mptfc_slave_alloc(struct scsi_device *sdev) if (!rport || fc_remote_port_chkready(rport)) return -ENXIO; - hd = (MPT_SCSI_HOST *)sdev->host->hostdata; + hd = shost_priv(sdev->host); + ioc = hd->ioc; - vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL); - if (!vdev) { + vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL); + if (!vdevice) { printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n", - hd->ioc->name, sizeof(VirtDevice)); + ioc->name, sizeof(VirtDevice)); return -ENOMEM; } - sdev->hostdata = vdev; + sdev->hostdata = vdevice; vtarget = starget->hostdata; if (vtarget->num_luns == 0) { - vtarget->ioc_id = hd->ioc->id; + vtarget->ioc_id = ioc->id; vtarget->tflags = MPT_TARGET_FLAGS_Q_YES; } - vdev->vtarget = vtarget; - vdev->lun = sdev->lun; + vdevice->vtarget = vtarget; + vdevice->lun = sdev->lun; vtarget->num_luns++; - mptfc_dump_lun_info(hd->ioc, rport, sdev, vtarget); + mptfc_dump_lun_info(ioc, rport, sdev, vtarget); return 0; } @@ -648,9 +648,9 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) struct mptfc_rport_info *ri; struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device)); int err; - VirtDevice *vdev = SCpnt->device->hostdata; + VirtDevice *vdevice = SCpnt->device->hostdata; - if (!vdev || !vdev->vtarget) { + if (!vdevice || !vdevice->vtarget) { SCpnt->result = DID_NO_CONNECT << 16; done(SCpnt); return 0; @@ -675,6 +675,50 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) } /* + * mptfc_display_port_link_speed - displaying link speed + * @ioc: Pointer to MPT_ADAPTER structure + * @portnum: IOC Port number + * @pp0dest: port page0 data payload + * + */ +static void +mptfc_display_port_link_speed(MPT_ADAPTER *ioc, int portnum, FCPortPage0_t *pp0dest) +{ + u8 old_speed, new_speed, state; + char *old, *new; + + if (portnum >= 2) + return; + + old_speed = ioc->fc_link_speed[portnum]; + new_speed = pp0dest->CurrentSpeed; + state = pp0dest->PortState; + + if (state != MPI_FCPORTPAGE0_PORTSTATE_OFFLINE && + new_speed != MPI_FCPORTPAGE0_CURRENT_SPEED_UKNOWN) { + + old = old_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT ? "1 Gbps" : + old_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT ? "2 Gbps" : + old_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT ? "4 Gbps" : + "Unknown"; + new = new_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT ? "1 Gbps" : + new_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT ? "2 Gbps" : + new_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT ? "4 Gbps" : + "Unknown"; + if (old_speed == 0) + printk(MYIOC_s_NOTE_FMT + "FC Link Established, Speed = %s\n", + ioc->name, new); + else if (old_speed != new_speed) + printk(MYIOC_s_WARN_FMT + "FC Link Speed Change, Old Speed = %s, New Speed = %s\n", + ioc->name, old, new); + + ioc->fc_link_speed[portnum] = new_speed; + } +} + +/* * mptfc_GetFcPortPage0 - Fetch FCPort config Page0. * @ioc: Pointer to MPT_ADAPTER structure * @portnum: IOC Port number @@ -773,6 +817,7 @@ mptfc_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum) " complete.\n", ioc->name); } + mptfc_display_port_link_speed(ioc, portnum, pp0dest); } pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma); @@ -1023,6 +1068,18 @@ mptfc_init_host_attr(MPT_ADAPTER *ioc,int portnum) } static void +mptfc_link_status_change(struct work_struct *work) +{ + MPT_ADAPTER *ioc = + container_of(work, MPT_ADAPTER, fc_rescan_work); + int ii; + + for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) + (void) mptfc_GetFcPortPage0(ioc, ii); + +} + +static void mptfc_setup_reset(struct work_struct *work) { MPT_ADAPTER *ioc = @@ -1163,6 +1220,7 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id) spin_lock_init(&ioc->fc_rescan_work_lock); INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices); INIT_WORK(&ioc->fc_setup_reset_work, mptfc_setup_reset); + INIT_WORK(&ioc->fc_lsc_work, mptfc_link_status_change); spin_lock_irqsave(&ioc->FreeQlock, flags); @@ -1218,20 +1276,21 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id) spin_unlock_irqrestore(&ioc->FreeQlock, flags); - hd = (MPT_SCSI_HOST *) sh->hostdata; + hd = shost_priv(sh); hd->ioc = ioc; /* SCSI needs scsi_cmnd lookup table! * (with size equal to req_depth*PtrSz!) */ - hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC); - if (!hd->ScsiLookup) { + ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC); + if (!ioc->ScsiLookup) { error = -ENOMEM; goto out_mptfc_probe; } + spin_lock_init(&ioc->scsi_lookup_lock); dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n", - ioc->name, hd->ScsiLookup)); + ioc->name, ioc->ScsiLookup)); /* Clear the TM flags */ @@ -1262,8 +1321,8 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id) sh->transportt = mptfc_transport_template; error = scsi_add_host (sh, &ioc->pcidev->dev); if(error) { - dprintk(ioc, printk(KERN_ERR MYNAM - "scsi_add_host failed\n")); + dprintk(ioc, printk(MYIOC_s_ERR_FMT + "scsi_add_host failed\n", ioc->name)); goto out_mptfc_probe; } @@ -1325,7 +1384,7 @@ mptfc_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) ioc->name, event)); if (ioc->sh == NULL || - ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL)) + ((hd = shost_priv(ioc->sh)) == NULL)) return 1; switch (event) { @@ -1337,6 +1396,14 @@ mptfc_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) } spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags); break; + case MPI_EVENT_LINK_STATUS_CHANGE: + spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags); + if (ioc->fc_rescan_work_q) { + queue_work(ioc->fc_rescan_work_q, + &ioc->fc_lsc_work); + } + spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags); + break; default: rc = mptscsih_event_process(ioc,pEvReply); break; diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c index 3da4c37846ec..7950fc678ed1 100644 --- a/drivers/message/fusion/mptlan.c +++ b/drivers/message/fusion/mptlan.c @@ -1,10 +1,10 @@ /* * linux/drivers/message/fusion/mptlan.c * IP Over Fibre Channel device driver. - * For use with LSI Logic Fibre Channel PCI chip/adapters - * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * For use with LSI Fibre Channel PCI chip/adapters + * running LSI Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 2000-2007 LSI Logic Corporation + * Copyright (c) 2000-2007 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) * */ @@ -154,7 +154,7 @@ static unsigned short mpt_lan_type_trans(struct sk_buff *skb, /* * Fusion MPT LAN private data */ -static int LanCtx = -1; +static u8 LanCtx = MPT_MAX_PROTOCOL_DRIVERS; static u32 max_buckets_out = 127; static u32 tx_max_out_p = 127 - 16; @@ -165,12 +165,6 @@ DEFINE_RWLOCK(bad_naa_lock); #endif /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * Fusion MPT LAN external data - */ -extern int mpt_lan_index; - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * lan_reply - Handle all data sent from the hardware. * @ioc: Pointer to MPT_ADAPTER structure @@ -1230,6 +1224,8 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv) } pRecvReq = (LANReceivePostRequest_t *) mf; + i = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); + mpt_dev->RequestNB[i] = 0; count = buckets; if (count > max) count = max; @@ -1351,10 +1347,11 @@ mpt_lan_post_receive_buckets_work(struct work_struct *work) static struct net_device * mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum) { - struct net_device *dev = alloc_fcdev(sizeof(struct mpt_lan_priv)); - struct mpt_lan_priv *priv = NULL; + struct net_device *dev; + struct mpt_lan_priv *priv; u8 HWaddr[FC_ALEN], *a; + dev = alloc_fcdev(sizeof(struct mpt_lan_priv)); if (!dev) return NULL; @@ -1366,7 +1363,6 @@ mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum) priv->mpt_dev = mpt_dev; priv->pnum = pnum; - memset(&priv->post_buckets_task, 0, sizeof(priv->post_buckets_task)); INIT_DELAYED_WORK(&priv->post_buckets_task, mpt_lan_post_receive_buckets_work); priv->post_buckets_active = 0; @@ -1391,8 +1387,6 @@ mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum) spin_lock_init(&priv->txfidx_lock); spin_lock_init(&priv->rxfidx_lock); - memset(&priv->stats, 0, sizeof(priv->stats)); - /* Grab pre-fetched LANPage1 stuff. :-) */ a = (u8 *) &mpt_dev->lan_cnfg_page1.HardwareAddressLow; @@ -1508,9 +1502,6 @@ static int __init mpt_lan_init (void) return -EBUSY; } - /* Set the callback index to be used by driver core for turbo replies */ - mpt_lan_index = LanCtx; - dlprintk((KERN_INFO MYNAM ": assigned context of %d\n", LanCtx)); if (mpt_reset_register(LanCtx, mpt_lan_ioc_reset)) { @@ -1531,10 +1522,9 @@ static void __exit mpt_lan_exit(void) mpt_device_driver_deregister(MPTLAN_DRIVER); mpt_reset_deregister(LanCtx); - if (LanCtx >= 0) { + if (LanCtx) { mpt_deregister(LanCtx); - LanCtx = -1; - mpt_lan_index = 0; + LanCtx = MPT_MAX_PROTOCOL_DRIVERS; } } diff --git a/drivers/message/fusion/mptlan.h b/drivers/message/fusion/mptlan.h index 8d08c2bed24a..bafb67fc8181 100644 --- a/drivers/message/fusion/mptlan.h +++ b/drivers/message/fusion/mptlan.h @@ -1,10 +1,10 @@ /* * linux/drivers/message/fusion/mptlan.h * IP Over Fibre Channel device driver. - * For use with LSI Logic Fibre Channel PCI chip/adapters - * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * For use with LSI Fibre Channel PCI chip/adapters + * running LSI Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 2000-2007 LSI Logic Corporation + * Copyright (c) 2000-2007 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) * */ @@ -75,7 +75,7 @@ #include <asm/io.h> /* Override mptbase.h by pre-defining these! */ -#define MODULEAUTHOR "LSI Logic Corporation" +#define MODULEAUTHOR "LSI Corporation" #include "mptbase.h" diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index b9c69bff218c..e4c94f93de16 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -1,11 +1,10 @@ /* * linux/drivers/message/fusion/mptsas.c - * For use with LSI Logic PCI chip/adapter(s) - * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * For use with LSI PCI chip/adapter(s) + * running LSI Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2007 LSI Logic Corporation + * Copyright (c) 1999-2007 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) - * Copyright (c) 2005-2007 Dell */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -61,6 +60,7 @@ #include "mptbase.h" #include "mptscsih.h" +#include "mptsas.h" #define my_NAME "Fusion MPT SAS Host driver" @@ -89,134 +89,35 @@ static int max_lun = MPTSAS_MAX_LUN; module_param(max_lun, int, 0); MODULE_PARM_DESC(max_lun, " max lun, default=16895 "); -static int mptsasDoneCtx = -1; -static int mptsasTaskCtx = -1; -static int mptsasInternalCtx = -1; /* Used only for internal commands */ -static int mptsasMgmtCtx = -1; +static u8 mptsasDoneCtx = MPT_MAX_PROTOCOL_DRIVERS; +static u8 mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS; +static u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */ +static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS; static void mptsas_hotplug_work(struct work_struct *work); -struct mptsas_target_reset_event { - struct list_head list; - EVENT_DATA_SAS_DEVICE_STATUS_CHANGE sas_event_data; - u8 target_reset_issued; -}; - -enum mptsas_hotplug_action { - MPTSAS_ADD_DEVICE, - MPTSAS_DEL_DEVICE, - MPTSAS_ADD_RAID, - MPTSAS_DEL_RAID, - MPTSAS_ADD_INACTIVE_VOLUME, - MPTSAS_IGNORE_EVENT, -}; - -struct mptsas_hotplug_event { - struct work_struct work; - MPT_ADAPTER *ioc; - enum mptsas_hotplug_action event_type; - u64 sas_address; - u8 channel; - u8 id; - u32 device_info; - u16 handle; - u16 parent_handle; - u8 phy_id; - u8 phys_disk_num_valid; /* hrc (hidden raid component) */ - u8 phys_disk_num; /* hrc - unique index*/ - u8 hidden_raid_component; /* hrc - don't expose*/ -}; - -struct mptsas_discovery_event { - struct work_struct work; - MPT_ADAPTER *ioc; -}; - -/* - * SAS topology structures - * - * The MPT Fusion firmware interface spreads information about the - * SAS topology over many manufacture pages, thus we need some data - * structure to collect it and process it for the SAS transport class. - */ - -struct mptsas_devinfo { - u16 handle; /* unique id to address this device */ - u16 handle_parent; /* unique id to address parent device */ - u16 handle_enclosure; /* enclosure identifier of the enclosure */ - u16 slot; /* physical slot in enclosure */ - u8 phy_id; /* phy number of parent device */ - u8 port_id; /* sas physical port this device - is assoc'd with */ - u8 id; /* logical target id of this device */ - u32 phys_disk_num; /* phys disk id, for csmi-ioctls */ - u8 channel; /* logical bus number of this device */ - u64 sas_address; /* WWN of this device, - SATA is assigned by HBA,expander */ - u32 device_info; /* bitfield detailed info about this device */ -}; - -/* - * Specific details on ports, wide/narrow - */ -struct mptsas_portinfo_details{ - u16 num_phys; /* number of phys belong to this port */ - u64 phy_bitmask; /* TODO, extend support for 255 phys */ - struct sas_rphy *rphy; /* transport layer rphy object */ - struct sas_port *port; /* transport layer port object */ - struct scsi_target *starget; - struct mptsas_portinfo *port_info; -}; - -struct mptsas_phyinfo { - u16 handle; /* unique id to address this */ - u8 phy_id; /* phy index */ - u8 port_id; /* firmware port identifier */ - u8 negotiated_link_rate; /* nego'd link rate for this phy */ - u8 hw_link_rate; /* hardware max/min phys link rate */ - u8 programmed_link_rate; /* programmed max/min phy link rate */ - u8 sas_port_add_phy; /* flag to request sas_port_add_phy*/ - struct mptsas_devinfo identify; /* point to phy device info */ - struct mptsas_devinfo attached; /* point to attached device info */ - struct sas_phy *phy; /* transport layer phy object */ - struct mptsas_portinfo *portinfo; - struct mptsas_portinfo_details * port_details; -}; - -struct mptsas_portinfo { - struct list_head list; - u16 num_phys; /* number of phys */ - struct mptsas_phyinfo *phy_info; -}; - -struct mptsas_enclosure { - u64 enclosure_logical_id; /* The WWN for the enclosure */ - u16 enclosure_handle; /* unique id to address this */ - u16 flags; /* details enclosure management */ - u16 num_slot; /* num slots */ - u16 start_slot; /* first slot */ - u8 start_id; /* starting logical target id */ - u8 start_channel; /* starting logical channel id */ - u8 sep_id; /* SEP device logical target id */ - u8 sep_channel; /* SEP channel logical channel id */ -}; - static void mptsas_print_phy_data(MPT_ADAPTER *ioc, MPI_SAS_IO_UNIT0_PHY_DATA *phy_data) { - dsasprintk(ioc, printk(KERN_DEBUG "---- IO UNIT PAGE 0 ------------\n")); - dsasprintk(ioc, printk(KERN_DEBUG "Handle=0x%X\n", - le16_to_cpu(phy_data->AttachedDeviceHandle))); - dsasprintk(ioc, printk(KERN_DEBUG "Controller Handle=0x%X\n", - le16_to_cpu(phy_data->ControllerDevHandle))); - dsasprintk(ioc, printk(KERN_DEBUG "Port=0x%X\n", phy_data->Port)); - dsasprintk(ioc, printk(KERN_DEBUG "Port Flags=0x%X\n", phy_data->PortFlags)); - dsasprintk(ioc, printk(KERN_DEBUG "PHY Flags=0x%X\n", phy_data->PhyFlags)); - dsasprintk(ioc, printk(KERN_DEBUG "Negotiated Link Rate=0x%X\n", phy_data->NegotiatedLinkRate)); - dsasprintk(ioc, printk(KERN_DEBUG "Controller PHY Device Info=0x%X\n", - le32_to_cpu(phy_data->ControllerPhyDeviceInfo))); - dsasprintk(ioc, printk(KERN_DEBUG "DiscoveryStatus=0x%X\n\n", - le32_to_cpu(phy_data->DiscoveryStatus))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "---- IO UNIT PAGE 0 ------------\n", ioc->name)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n", + ioc->name, le16_to_cpu(phy_data->AttachedDeviceHandle))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Controller Handle=0x%X\n", + ioc->name, le16_to_cpu(phy_data->ControllerDevHandle))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port=0x%X\n", + ioc->name, phy_data->Port)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port Flags=0x%X\n", + ioc->name, phy_data->PortFlags)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Flags=0x%X\n", + ioc->name, phy_data->PhyFlags)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n", + ioc->name, phy_data->NegotiatedLinkRate)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Controller PHY Device Info=0x%X\n", ioc->name, + le32_to_cpu(phy_data->ControllerPhyDeviceInfo))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DiscoveryStatus=0x%X\n\n", + ioc->name, le32_to_cpu(phy_data->DiscoveryStatus))); } static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0) @@ -225,27 +126,41 @@ static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0) memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64)); - dsasprintk(ioc, printk(KERN_DEBUG "---- SAS PHY PAGE 0 ------------\n")); - dsasprintk(ioc, printk(KERN_DEBUG "Attached Device Handle=0x%X\n", - le16_to_cpu(pg0->AttachedDevHandle))); - dsasprintk(ioc, printk(KERN_DEBUG "SAS Address=0x%llX\n", - (unsigned long long)le64_to_cpu(sas_address))); - dsasprintk(ioc, printk(KERN_DEBUG "Attached PHY Identifier=0x%X\n", pg0->AttachedPhyIdentifier)); - dsasprintk(ioc, printk(KERN_DEBUG "Attached Device Info=0x%X\n", - le32_to_cpu(pg0->AttachedDeviceInfo))); - dsasprintk(ioc, printk(KERN_DEBUG "Programmed Link Rate=0x%X\n", pg0->ProgrammedLinkRate)); - dsasprintk(ioc, printk(KERN_DEBUG "Change Count=0x%X\n", pg0->ChangeCount)); - dsasprintk(ioc, printk(KERN_DEBUG "PHY Info=0x%X\n\n", le32_to_cpu(pg0->PhyInfo))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "---- SAS PHY PAGE 0 ------------\n", ioc->name)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Attached Device Handle=0x%X\n", ioc->name, + le16_to_cpu(pg0->AttachedDevHandle))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n", + ioc->name, (unsigned long long)le64_to_cpu(sas_address))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Attached PHY Identifier=0x%X\n", ioc->name, + pg0->AttachedPhyIdentifier)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Attached Device Info=0x%X\n", + ioc->name, le32_to_cpu(pg0->AttachedDeviceInfo))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n", + ioc->name, pg0->ProgrammedLinkRate)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Change Count=0x%X\n", + ioc->name, pg0->ChangeCount)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Info=0x%X\n\n", + ioc->name, le32_to_cpu(pg0->PhyInfo))); } static void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1) { - dsasprintk(ioc, printk(KERN_DEBUG "---- SAS PHY PAGE 1 ------------\n")); - dsasprintk(ioc, printk(KERN_DEBUG "Invalid Dword Count=0x%x\n", pg1->InvalidDwordCount)); - dsasprintk(ioc, printk(KERN_DEBUG "Running Disparity Error Count=0x%x\n", - pg1->RunningDisparityErrorCount)); - dsasprintk(ioc, printk(KERN_DEBUG "Loss Dword Synch Count=0x%x\n", pg1->LossDwordSynchCount)); - dsasprintk(ioc, printk(KERN_DEBUG "PHY Reset Problem Count=0x%x\n\n", pg1->PhyResetProblemCount)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "---- SAS PHY PAGE 1 ------------\n", ioc->name)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Invalid Dword Count=0x%x\n", + ioc->name, pg1->InvalidDwordCount)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Running Disparity Error Count=0x%x\n", ioc->name, + pg1->RunningDisparityErrorCount)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Loss Dword Synch Count=0x%x\n", ioc->name, + pg1->LossDwordSynchCount)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "PHY Reset Problem Count=0x%x\n\n", ioc->name, + pg1->PhyResetProblemCount)); } static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0) @@ -254,37 +169,53 @@ static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0) memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64)); - dsasprintk(ioc, printk(KERN_DEBUG "---- SAS DEVICE PAGE 0 ---------\n")); - dsasprintk(ioc, printk(KERN_DEBUG "Handle=0x%X\n" ,le16_to_cpu(pg0->DevHandle))); - dsasprintk(ioc, printk(KERN_DEBUG "Parent Handle=0x%X\n" ,le16_to_cpu(pg0->ParentDevHandle))); - dsasprintk(ioc, printk(KERN_DEBUG "Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle))); - dsasprintk(ioc, printk(KERN_DEBUG "Slot=0x%X\n", le16_to_cpu(pg0->Slot))); - dsasprintk(ioc, printk(KERN_DEBUG "SAS Address=0x%llX\n", (unsigned long long) - le64_to_cpu(sas_address))); - dsasprintk(ioc, printk(KERN_DEBUG "Target ID=0x%X\n", pg0->TargetID)); - dsasprintk(ioc, printk(KERN_DEBUG "Bus=0x%X\n", pg0->Bus)); - /* The PhyNum field specifies the PHY number of the parent - * device this device is linked to - */ - dsasprintk(ioc, printk(KERN_DEBUG "Parent Phy Num=0x%X\n", pg0->PhyNum)); - dsasprintk(ioc, printk(KERN_DEBUG "Access Status=0x%X\n", le16_to_cpu(pg0->AccessStatus))); - dsasprintk(ioc, printk(KERN_DEBUG "Device Info=0x%X\n", le32_to_cpu(pg0->DeviceInfo))); - dsasprintk(ioc, printk(KERN_DEBUG "Flags=0x%X\n", le16_to_cpu(pg0->Flags))); - dsasprintk(ioc, printk(KERN_DEBUG "Physical Port=0x%X\n\n", pg0->PhysicalPort)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "---- SAS DEVICE PAGE 0 ---------\n", ioc->name)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n", + ioc->name, le16_to_cpu(pg0->DevHandle))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Handle=0x%X\n", + ioc->name, le16_to_cpu(pg0->ParentDevHandle))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Enclosure Handle=0x%X\n", + ioc->name, le16_to_cpu(pg0->EnclosureHandle))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Slot=0x%X\n", + ioc->name, le16_to_cpu(pg0->Slot))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n", + ioc->name, (unsigned long long)le64_to_cpu(sas_address))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Target ID=0x%X\n", + ioc->name, pg0->TargetID)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Bus=0x%X\n", + ioc->name, pg0->Bus)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Phy Num=0x%X\n", + ioc->name, pg0->PhyNum)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Access Status=0x%X\n", + ioc->name, le16_to_cpu(pg0->AccessStatus))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Device Info=0x%X\n", + ioc->name, le32_to_cpu(pg0->DeviceInfo))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Flags=0x%X\n", + ioc->name, le16_to_cpu(pg0->Flags))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n\n", + ioc->name, pg0->PhysicalPort)); } static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1) { - dsasprintk(ioc, printk(KERN_DEBUG "---- SAS EXPANDER PAGE 1 ------------\n")); - dsasprintk(ioc, printk(KERN_DEBUG "Physical Port=0x%X\n", pg1->PhysicalPort)); - dsasprintk(ioc, printk(KERN_DEBUG "PHY Identifier=0x%X\n", pg1->PhyIdentifier)); - dsasprintk(ioc, printk(KERN_DEBUG "Negotiated Link Rate=0x%X\n", pg1->NegotiatedLinkRate)); - dsasprintk(ioc, printk(KERN_DEBUG "Programmed Link Rate=0x%X\n", pg1->ProgrammedLinkRate)); - dsasprintk(ioc, printk(KERN_DEBUG "Hardware Link Rate=0x%X\n", pg1->HwLinkRate)); - dsasprintk(ioc, printk(KERN_DEBUG "Owner Device Handle=0x%X\n", - le16_to_cpu(pg1->OwnerDevHandle))); - dsasprintk(ioc, printk(KERN_DEBUG "Attached Device Handle=0x%X\n\n", - le16_to_cpu(pg1->AttachedDevHandle))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "---- SAS EXPANDER PAGE 1 ------------\n", ioc->name)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n", + ioc->name, pg1->PhysicalPort)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Identifier=0x%X\n", + ioc->name, pg1->PhyIdentifier)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n", + ioc->name, pg1->NegotiatedLinkRate)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n", + ioc->name, pg1->ProgrammedLinkRate)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hardware Link Rate=0x%X\n", + ioc->name, pg1->HwLinkRate)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Owner Device Handle=0x%X\n", + ioc->name, le16_to_cpu(pg1->OwnerDevHandle))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Attached Device Handle=0x%X\n\n", ioc->name, + le16_to_cpu(pg1->AttachedDevHandle))); } static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy) @@ -354,8 +285,8 @@ mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_detai port_info = port_details->port_info; phy_info = port_info->phy_info; - dsaswideprintk(ioc, printk(KERN_DEBUG "%s: [%p]: num_phys=%02d " - "bitmask=0x%016llX\n", __FUNCTION__, port_details, + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d " + "bitmask=0x%016llX\n", ioc->name, __FUNCTION__, port_details, port_details->num_phys, (unsigned long long) port_details->phy_bitmask)); @@ -382,14 +313,15 @@ mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rp { if (phy_info->port_details) { phy_info->port_details->rphy = rphy; - dsaswideprintk(ioc, printk(KERN_DEBUG "sas_rphy_add: rphy=%p\n", rphy)); + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n", + ioc->name, rphy)); } if (rphy) { dsaswideprintk(ioc, dev_printk(KERN_DEBUG, - &rphy->dev, "add:")); - dsaswideprintk(ioc, printk(KERN_DEBUG "rphy=%p release=%p\n", - rphy, rphy->dev.release)); + &rphy->dev, MYIOC_s_FMT "add:", ioc->name)); + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n", + ioc->name, rphy, rphy->dev.release)); } } @@ -410,9 +342,9 @@ mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_po if (port) { dsaswideprintk(ioc, dev_printk(KERN_DEBUG, - &port->dev, "add:")); - dsaswideprintk(ioc, printk(KERN_DEBUG "port=%p release=%p\n", - port, port->dev.release)); + &port->dev, MYIOC_s_FMT "add:", ioc->name)); + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "port=%p release=%p\n", + ioc->name, port, port->dev.release)); } } @@ -463,9 +395,9 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) * Removing a phy from a port, letting the last * phy be removed by firmware events. */ - dsaswideprintk(ioc, printk(KERN_DEBUG - "%s: [%p]: deleting phy = %d\n", - __FUNCTION__, port_details, i)); + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: [%p]: deleting phy = %d\n", + ioc->name, __FUNCTION__, port_details, i)); port_details->num_phys--; port_details->phy_bitmask &= ~ (1 << phy_info->phy_id); memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); @@ -479,8 +411,8 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) phy_info = port_info->phy_info; for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) { sas_address = phy_info->attached.sas_address; - dsaswideprintk(ioc, printk(KERN_DEBUG "phy_id=%d sas_address=0x%018llX\n", - i, (unsigned long long)sas_address)); + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n", + ioc->name, i, (unsigned long long)sas_address)); if (!sas_address) continue; port_details = phy_info->port_details; @@ -498,9 +430,9 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) port_details->phy_bitmask |= (1 << phy_info->phy_id); phy_info->sas_port_add_phy=1; - dsaswideprintk(ioc, printk(KERN_DEBUG "\t\tForming port\n\t\t" + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t" "phy_id=%d sas_address=0x%018llX\n", - i, (unsigned long long)sas_address)); + ioc->name, i, (unsigned long long)sas_address)); phy_info->port_details = port_details; } @@ -515,9 +447,9 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) continue; if (phy_info_cmp->port_details == port_details ) continue; - dsaswideprintk(ioc, printk(KERN_DEBUG + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tphy_id=%d sas_address=0x%018llX\n", - j, (unsigned long long) + ioc->name, j, (unsigned long long) phy_info_cmp->attached.sas_address)); if (phy_info_cmp->port_details) { port_details->rphy = @@ -549,15 +481,15 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) port_details = port_info->phy_info[i].port_details; if (!port_details) continue; - dsaswideprintk(ioc, printk(KERN_DEBUG + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: phy_id=%02d num_phys=%02d " - "bitmask=0x%016llX\n", __FUNCTION__, + "bitmask=0x%016llX\n", ioc->name, __FUNCTION__, port_details, i, port_details->num_phys, (unsigned long long)port_details->phy_bitmask)); - dsaswideprintk(ioc, printk(KERN_DEBUG"\t\tport = %p rphy=%p\n", - port_details->port, port_details->rphy)); + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n", + ioc->name, port_details->port, port_details->rphy)); } - dsaswideprintk(ioc, printk(KERN_DEBUG"\n")); + dsaswideprintk(ioc, printk("\n")); mutex_unlock(&ioc->sas_topology_mutex); } @@ -573,15 +505,15 @@ static VirtTarget * mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id) { struct scsi_device *sdev; - VirtDevice *vdev; + VirtDevice *vdevice; VirtTarget *vtarget = NULL; shost_for_each_device(sdev, ioc->sh) { - if ((vdev = sdev->hostdata) == NULL) + if ((vdevice = sdev->hostdata) == NULL) continue; - if (vdev->vtarget->id == id && - vdev->vtarget->channel == channel) - vtarget = vdev->vtarget; + if (vdevice->vtarget->id == id && + vdevice->vtarget->channel == channel) + vtarget = vdevice->vtarget; } return vtarget; } @@ -623,13 +555,7 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id) DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf); - if (mpt_send_handshake_request(ioc->TaskCtx, ioc, - sizeof(SCSITaskMgmt_t), (u32 *)mf, NO_SLEEP)) { - mpt_free_msg_frame(ioc, mf); - dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, tm handshake failed @%d!!\n", - ioc->name,__FUNCTION__, __LINE__)); - return 0; - } + mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf); return 1; } @@ -649,7 +575,7 @@ static void mptsas_target_reset_queue(MPT_ADAPTER *ioc, EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data) { - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata; + MPT_SCSI_HOST *hd = shost_priv(ioc->sh); VirtTarget *vtarget = NULL; struct mptsas_target_reset_event *target_reset_list; u8 id, channel; @@ -696,7 +622,7 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc, static void mptsas_dev_reset_complete(MPT_ADAPTER *ioc) { - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata; + MPT_SCSI_HOST *hd = shost_priv(ioc->sh); struct list_head *head = &hd->target_reset_list; struct mptsas_target_reset_event *target_reset_list; struct mptsas_hotplug_event *ev; @@ -813,7 +739,7 @@ mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) if (!ioc->sh || !ioc->sh->hostdata) goto out; - hd = (MPT_SCSI_HOST *)ioc->sh->hostdata; + hd = shost_priv(ioc->sh); if (!hd->ioc) goto out; @@ -913,19 +839,20 @@ static int mptsas_target_alloc(struct scsi_target *starget) { struct Scsi_Host *host = dev_to_shost(&starget->dev); - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; + MPT_SCSI_HOST *hd = shost_priv(host); VirtTarget *vtarget; u8 id, channel; struct sas_rphy *rphy; struct mptsas_portinfo *p; int i; + MPT_ADAPTER *ioc = hd->ioc; vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL); if (!vtarget) return -ENOMEM; vtarget->starget = starget; - vtarget->ioc_id = hd->ioc->id; + vtarget->ioc_id = ioc->id; vtarget->tflags = MPT_TARGET_FLAGS_Q_YES; id = starget->id; channel = 0; @@ -934,15 +861,15 @@ mptsas_target_alloc(struct scsi_target *starget) * RAID volumes placed beyond the last expected port. */ if (starget->channel == MPTSAS_RAID_CHANNEL) { - for (i=0; i < hd->ioc->raid_data.pIocPg2->NumActiveVolumes; i++) - if (id == hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID) - channel = hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus; + for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) + if (id == ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID) + channel = ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus; goto out; } rphy = dev_to_rphy(starget->dev.parent); - mutex_lock(&hd->ioc->sas_topology_mutex); - list_for_each_entry(p, &hd->ioc->sas_topology, list) { + mutex_lock(&ioc->sas_topology_mutex); + list_for_each_entry(p, &ioc->sas_topology, list) { for (i = 0; i < p->num_phys; i++) { if (p->phy_info[i].attached.sas_address != rphy->identify.sas_address) @@ -954,18 +881,18 @@ mptsas_target_alloc(struct scsi_target *starget) /* * Exposing hidden raid components */ - if (mptscsih_is_phys_disk(hd->ioc, channel, id)) { - id = mptscsih_raid_id_to_num(hd->ioc, + if (mptscsih_is_phys_disk(ioc, channel, id)) { + id = mptscsih_raid_id_to_num(ioc, channel, id); vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT; p->phy_info[i].attached.phys_disk_num = id; } - mutex_unlock(&hd->ioc->sas_topology_mutex); + mutex_unlock(&ioc->sas_topology_mutex); goto out; } } - mutex_unlock(&hd->ioc->sas_topology_mutex); + mutex_unlock(&ioc->sas_topology_mutex); kfree(vtarget); return -ENXIO; @@ -981,10 +908,11 @@ static void mptsas_target_destroy(struct scsi_target *starget) { struct Scsi_Host *host = dev_to_shost(&starget->dev); - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; + MPT_SCSI_HOST *hd = shost_priv(host); struct sas_rphy *rphy; struct mptsas_portinfo *p; int i; + MPT_ADAPTER *ioc = hd->ioc; if (!starget->hostdata) return; @@ -993,7 +921,7 @@ mptsas_target_destroy(struct scsi_target *starget) goto out; rphy = dev_to_rphy(starget->dev.parent); - list_for_each_entry(p, &hd->ioc->sas_topology, list) { + list_for_each_entry(p, &ioc->sas_topology, list) { for (i = 0; i < p->num_phys; i++) { if (p->phy_info[i].attached.sas_address != rphy->identify.sas_address) @@ -1013,61 +941,62 @@ static int mptsas_slave_alloc(struct scsi_device *sdev) { struct Scsi_Host *host = sdev->host; - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; + MPT_SCSI_HOST *hd = shost_priv(host); struct sas_rphy *rphy; struct mptsas_portinfo *p; - VirtDevice *vdev; + VirtDevice *vdevice; struct scsi_target *starget; int i; + MPT_ADAPTER *ioc = hd->ioc; - vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL); - if (!vdev) { + vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL); + if (!vdevice) { printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n", - hd->ioc->name, sizeof(VirtDevice)); + ioc->name, sizeof(VirtDevice)); return -ENOMEM; } starget = scsi_target(sdev); - vdev->vtarget = starget->hostdata; + vdevice->vtarget = starget->hostdata; if (sdev->channel == MPTSAS_RAID_CHANNEL) goto out; rphy = dev_to_rphy(sdev->sdev_target->dev.parent); - mutex_lock(&hd->ioc->sas_topology_mutex); - list_for_each_entry(p, &hd->ioc->sas_topology, list) { + mutex_lock(&ioc->sas_topology_mutex); + list_for_each_entry(p, &ioc->sas_topology, list) { for (i = 0; i < p->num_phys; i++) { if (p->phy_info[i].attached.sas_address != rphy->identify.sas_address) continue; - vdev->lun = sdev->lun; + vdevice->lun = sdev->lun; /* * Exposing hidden raid components */ - if (mptscsih_is_phys_disk(hd->ioc, + if (mptscsih_is_phys_disk(ioc, p->phy_info[i].attached.channel, p->phy_info[i].attached.id)) sdev->no_uld_attach = 1; - mutex_unlock(&hd->ioc->sas_topology_mutex); + mutex_unlock(&ioc->sas_topology_mutex); goto out; } } - mutex_unlock(&hd->ioc->sas_topology_mutex); + mutex_unlock(&ioc->sas_topology_mutex); - kfree(vdev); + kfree(vdevice); return -ENXIO; out: - vdev->vtarget->num_luns++; - sdev->hostdata = vdev; + vdevice->vtarget->num_luns++; + sdev->hostdata = vdevice; return 0; } static int mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) { - VirtDevice *vdev = SCpnt->device->hostdata; + VirtDevice *vdevice = SCpnt->device->hostdata; - if (!vdev || !vdev->vtarget || vdev->vtarget->deleted) { + if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) { SCpnt->result = DID_NO_CONNECT << 16; done(SCpnt); return 0; @@ -1239,10 +1168,8 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset) /* process the completed Reply Message Frame */ reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply; if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) { - printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", - __FUNCTION__, - reply->IOCStatus, - reply->IOCLogInfo); + printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", + ioc->name, __FUNCTION__, reply->IOCStatus, reply->IOCLogInfo); error = -ENXIO; goto out_unlock; } @@ -1328,16 +1255,16 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, u64 sas_address = 0; if (!rsp) { - printk(KERN_ERR "%s: the smp response space is missing\n", - __FUNCTION__); + printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n", + ioc->name, __FUNCTION__); return -EINVAL; } /* do we need to support multiple segments? */ if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) { - printk(KERN_ERR "%s: multiple segments req %u %u, rsp %u %u\n", - __FUNCTION__, req->bio->bi_vcnt, req->data_len, - rsp->bio->bi_vcnt, rsp->data_len); + printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n", + ioc->name, __FUNCTION__, req->bio->bi_vcnt, req->data_len, + rsp->bio->bi_vcnt, rsp->data_len); return -EINVAL; } @@ -1402,7 +1329,7 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ); if (!timeleft) { - printk(KERN_ERR "%s: smp timeout!\n", __FUNCTION__); + printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __FUNCTION__); /* On timeout reset the board */ mpt_HardResetHandler(ioc, CAN_SLEEP); ret = -ETIMEDOUT; @@ -1417,8 +1344,8 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, memcpy(req->sense, smprep, sizeof(*smprep)); req->sense_len = sizeof(*smprep); } else { - printk(KERN_ERR "%s: smp passthru reply failed to be returned\n", - __FUNCTION__); + printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n", + ioc->name, __FUNCTION__); ret = -ENXIO; } unmap: @@ -2062,12 +1989,12 @@ static int mptsas_probe_one_phy(struct device *dev, goto out; } mptsas_set_port(ioc, phy_info, port); - dsaswideprintk(ioc, printk(KERN_DEBUG + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_port_alloc: port=%p dev=%p port_id=%d\n", - port, dev, port->port_identifier)); + ioc->name, port, dev, port->port_identifier)); } - dsaswideprintk(ioc, printk(KERN_DEBUG "sas_port_add_phy: phy_id=%d\n", - phy_info->phy_id)); + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_port_add_phy: phy_id=%d\n", + ioc->name, phy_info->phy_id)); sas_port_add_phy(port, phy_info->phy); phy_info->sas_port_add_phy = 0; } @@ -2369,8 +2296,9 @@ mptsas_delete_expander_phys(MPT_ADAPTER *ioc) expander_sas_address) continue; dsaswideprintk(ioc, - dev_printk(KERN_DEBUG, &port->dev, - "delete port (%d)\n", port->port_identifier)); + dev_printk(KERN_DEBUG, &port->dev, + MYIOC_s_FMT "delete port (%d)\n", ioc->name, + port->port_identifier)); sas_port_delete(port); mptsas_port_delete(ioc, phy_info->port_details); } @@ -2613,7 +2541,7 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id) ev = kzalloc(sizeof(*ev), GFP_ATOMIC); if (!ev) { - printk(KERN_WARNING "mptsas: lost hotplug event\n"); + printk(MYIOC_s_WARN_FMT "mptsas: lost hotplug event\n", ioc->name); goto out; } @@ -2754,8 +2682,8 @@ mptsas_hotplug_work(struct work_struct *work) printk(MYIOC_s_INFO_FMT "removing %s device, channel %d, id %d, phy %d\n", ioc->name, ds, ev->channel, ev->id, phy_info->phy_id); - dev_printk(KERN_DEBUG, &port->dev, - "delete port (%d)\n", port->port_identifier); + dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT + "delete port (%d)\n", ioc->name, port->port_identifier); sas_port_delete(port); mptsas_port_delete(ioc, phy_info->port_details); break; @@ -2796,8 +2724,8 @@ mptsas_hotplug_work(struct work_struct *work) if (!vtarget) { dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __FUNCTION__, __LINE__)); + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); break; } /* @@ -2930,7 +2858,7 @@ mptsas_send_sas_event(MPT_ADAPTER *ioc, case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: ev = kzalloc(sizeof(*ev), GFP_ATOMIC); if (!ev) { - printk(KERN_WARNING "mptsas: lost hotplug event\n"); + printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name); break; } @@ -2989,7 +2917,7 @@ mptsas_send_raid_event(MPT_ADAPTER *ioc, ev = kzalloc(sizeof(*ev), GFP_ATOMIC); if (!ev) { - printk(KERN_WARNING "mptsas: lost hotplug event\n"); + printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name); return; } @@ -3288,20 +3216,22 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) sh->sg_tablesize = numSGE; } - hd = (MPT_SCSI_HOST *) sh->hostdata; + hd = shost_priv(sh); hd->ioc = ioc; /* SCSI needs scsi_cmnd lookup table! * (with size equal to req_depth*PtrSz!) */ - hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC); - if (!hd->ScsiLookup) { + ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC); + if (!ioc->ScsiLookup) { error = -ENOMEM; + spin_unlock_irqrestore(&ioc->FreeQlock, flags); goto out_mptsas_probe; } + spin_lock_init(&ioc->scsi_lookup_lock); dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n", - ioc->name, hd->ScsiLookup)); + ioc->name, ioc->ScsiLookup)); /* Clear the TM flags */ @@ -3340,8 +3270,8 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) error = scsi_add_host(sh, &ioc->pcidev->dev); if (error) { - dprintk(ioc, printk(KERN_ERR MYNAM - "scsi_add_host failed\n")); + dprintk(ioc, printk(MYIOC_s_ERR_FMT + "scsi_add_host failed\n", ioc->name)); goto out_mptsas_probe; } diff --git a/drivers/message/fusion/mptsas.h b/drivers/message/fusion/mptsas.h new file mode 100644 index 000000000000..7c150f50629a --- /dev/null +++ b/drivers/message/fusion/mptsas.h @@ -0,0 +1,158 @@ +/* + * linux/drivers/message/fusion/mptsas.h + * High performance SCSI + LAN / Fibre Channel device drivers. + * For use with PCI chip/adapter(s): + * LSIFC9xx/LSI409xx Fibre Channel + * running LSI MPT (Message Passing Technology) firmware. + * + * Copyright (c) 1999-2007 LSI Corporation + * (mailto:DL-MPTFusionLinux@lsi.com) + * + */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + 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 of the License. + + 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. + + NO WARRANTY + THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + solely responsible for determining the appropriateness of using and + distributing the Program and assumes all risks associated with its + exercise of rights under this Agreement, including but not limited to + the risks and costs of program errors, damage to or loss of data, + programs or equipment, and unavailability or interruption of operations. + + DISCLAIMER OF LIABILITY + NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef MPTSAS_H_INCLUDED +#define MPTSAS_H_INCLUDED +/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +struct mptsas_target_reset_event { + struct list_head list; + EVENT_DATA_SAS_DEVICE_STATUS_CHANGE sas_event_data; + u8 target_reset_issued; +}; + +enum mptsas_hotplug_action { + MPTSAS_ADD_DEVICE, + MPTSAS_DEL_DEVICE, + MPTSAS_ADD_RAID, + MPTSAS_DEL_RAID, + MPTSAS_ADD_INACTIVE_VOLUME, + MPTSAS_IGNORE_EVENT, +}; + +struct mptsas_hotplug_event { + struct work_struct work; + MPT_ADAPTER *ioc; + enum mptsas_hotplug_action event_type; + u64 sas_address; + u8 channel; + u8 id; + u32 device_info; + u16 handle; + u16 parent_handle; + u8 phy_id; + u8 phys_disk_num_valid; /* hrc (hidden raid component) */ + u8 phys_disk_num; /* hrc - unique index*/ + u8 hidden_raid_component; /* hrc - don't expose*/ +}; + +struct mptsas_discovery_event { + struct work_struct work; + MPT_ADAPTER *ioc; +}; + +/* + * SAS topology structures + * + * The MPT Fusion firmware interface spreads information about the + * SAS topology over many manufacture pages, thus we need some data + * structure to collect it and process it for the SAS transport class. + */ + +struct mptsas_devinfo { + u16 handle; /* unique id to address this device */ + u16 handle_parent; /* unique id to address parent device */ + u16 handle_enclosure; /* enclosure identifier of the enclosure */ + u16 slot; /* physical slot in enclosure */ + u8 phy_id; /* phy number of parent device */ + u8 port_id; /* sas physical port this device + is assoc'd with */ + u8 id; /* logical target id of this device */ + u32 phys_disk_num; /* phys disk id, for csmi-ioctls */ + u8 channel; /* logical bus number of this device */ + u64 sas_address; /* WWN of this device, + SATA is assigned by HBA,expander */ + u32 device_info; /* bitfield detailed info about this device */ +}; + +/* + * Specific details on ports, wide/narrow + */ +struct mptsas_portinfo_details{ + u16 num_phys; /* number of phys belong to this port */ + u64 phy_bitmask; /* TODO, extend support for 255 phys */ + struct sas_rphy *rphy; /* transport layer rphy object */ + struct sas_port *port; /* transport layer port object */ + struct scsi_target *starget; + struct mptsas_portinfo *port_info; +}; + +struct mptsas_phyinfo { + u16 handle; /* unique id to address this */ + u8 phy_id; /* phy index */ + u8 port_id; /* firmware port identifier */ + u8 negotiated_link_rate; /* nego'd link rate for this phy */ + u8 hw_link_rate; /* hardware max/min phys link rate */ + u8 programmed_link_rate; /* programmed max/min phy link rate */ + u8 sas_port_add_phy; /* flag to request sas_port_add_phy*/ + struct mptsas_devinfo identify; /* point to phy device info */ + struct mptsas_devinfo attached; /* point to attached device info */ + struct sas_phy *phy; /* transport layer phy object */ + struct mptsas_portinfo *portinfo; + struct mptsas_portinfo_details * port_details; +}; + +struct mptsas_portinfo { + struct list_head list; + u16 num_phys; /* number of phys */ + struct mptsas_phyinfo *phy_info; +}; + +struct mptsas_enclosure { + u64 enclosure_logical_id; /* The WWN for the enclosure */ + u16 enclosure_handle; /* unique id to address this */ + u16 flags; /* details enclosure management */ + u16 num_slot; /* num slots */ + u16 start_slot; /* first slot */ + u8 start_id; /* starting logical target id */ + u8 start_channel; /* starting logical channel id */ + u8 sep_id; /* SEP device logical target id */ + u8 sep_channel; /* SEP channel logical channel id */ +}; + +/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#endif diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 5431529741ad..bdff950a54a1 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -1,9 +1,9 @@ /* * linux/drivers/message/fusion/mptscsih.c - * For use with LSI Logic PCI chip/adapter(s) - * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * For use with LSI PCI chip/adapter(s) + * running LSI Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2007 LSI Logic Corporation + * Copyright (c) 1999-2007 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) * */ @@ -80,6 +80,10 @@ MODULE_VERSION(my_VERSION); /* * Other private/forward protos... */ +static struct scsi_cmnd * mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i); +static struct scsi_cmnd * mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i); +static void mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd); +static int SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *scmd); int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r); static void mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq); int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r); @@ -90,7 +94,6 @@ static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx); static void mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply); static int mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd); static int mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout ); -static int SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc); static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout); @@ -192,7 +195,7 @@ mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex) int chain_idx; dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer called\n", - ioc->name)); + ioc->name)); spin_lock_irqsave(&ioc->FreeQlock, flags); if (!list_empty(&ioc->FreeChainQ)) { int offset; @@ -203,13 +206,14 @@ mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex) offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer; chain_idx = offset / ioc->req_sz; rc = SUCCESS; - dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n", - ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx)); + dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n", + ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx)); } else { rc = FAILED; chain_idx = MPT_HOST_NO_CHAIN; - dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer failed\n", - ioc->name)); + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "getFreeChainBuffer failed\n", + ioc->name)); } spin_unlock_irqrestore(&ioc->FreeQlock, flags); @@ -419,8 +423,8 @@ nextSGEset: * out the Address and Flags fields. */ chainSge = (char *) psge; - dsgprintk(ioc, printk(KERN_DEBUG " Current buff @ %p (index 0x%x)", - psge, req_idx)); + dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Current buff @ %p (index 0x%x)", + ioc->name, psge, req_idx)); /* Start the SGE for the next buffer */ @@ -428,8 +432,8 @@ nextSGEset: sgeOffset = 0; sg_done = 0; - dsgprintk(ioc, printk(KERN_DEBUG " Chain buff @ %p (index 0x%x)\n", - psge, chain_idx)); + dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Chain buff @ %p (index 0x%x)\n", + ioc->name, psge, chain_idx)); /* Start the SGE for the next buffer */ @@ -588,18 +592,17 @@ mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pSc } scsi_print_command(sc); - printk(KERN_DEBUG "\tfw_channel = %d, fw_id = %d\n", - pScsiReply->Bus, pScsiReply->TargetID); - printk(KERN_DEBUG "\trequest_len = %d, underflow = %d, resid = %d\n", - scsi_bufflen(sc), sc->underflow, scsi_get_resid(sc)); - printk(KERN_DEBUG "\ttag = %d, transfer_count = %d, sc->result = %08X\n", - le16_to_cpu(pScsiReply->TaskTag), + printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d\n", + ioc->name, pScsiReply->Bus, pScsiReply->TargetID); + printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, " + "resid = %d\n", ioc->name, scsi_bufflen(sc), sc->underflow, + scsi_get_resid(sc)); + printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, " + "sc->result = %08X\n", ioc->name, le16_to_cpu(pScsiReply->TaskTag), le32_to_cpu(pScsiReply->TransferCount), sc->result); - - printk(KERN_DEBUG "\tiocstatus = %s (0x%04x), " + printk(MYIOC_s_DEBUG_FMT "\tiocstatus = %s (0x%04x), " "scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n", - desc, ioc_status, - desc1, pScsiReply->SCSIStatus, + ioc->name, desc, ioc_status, desc1, pScsiReply->SCSIStatus, pScsiReply->SCSIState); if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) { @@ -607,9 +610,8 @@ mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pSc asc = sc->sense_buffer[12]; ascq = sc->sense_buffer[13]; - printk(KERN_DEBUG "\t[sense_key,asc,ascq]: " - "[0x%02x,0x%02x,0x%02x]\n", - skey, asc, ascq); + printk(MYIOC_s_DEBUG_FMT "\t[sense_key,asc,ascq]: " + "[0x%02x,0x%02x,0x%02x]\n", ioc->name, skey, asc, ascq); } /* @@ -617,8 +619,8 @@ mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pSc */ if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID && pScsiReply->ResponseInfo) - printk(KERN_DEBUG "response_info = %08xh\n", - le32_to_cpu(pScsiReply->ResponseInfo)); + printk(MYIOC_s_DEBUG_FMT "response_info = %08xh\n", + ioc->name, le32_to_cpu(pScsiReply->ResponseInfo)); } #endif @@ -645,11 +647,10 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) SCSIIORequest_t *pScsiReq; SCSIIOReply_t *pScsiReply; u16 req_idx, req_idx_MR; - VirtDevice *vdev; + VirtDevice *vdevice; VirtTarget *vtarget; - hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; - + hd = shost_priv(ioc->sh); req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); req_idx_MR = (mr != NULL) ? le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx; @@ -660,12 +661,11 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) printk (MYIOC_s_ERR_FMT "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n", ioc->name, req_idx, req_idx_MR, mf, mr, - hd->ScsiLookup[req_idx_MR]); + mptscsih_get_scsi_lookup(ioc, req_idx_MR)); return 0; } - sc = hd->ScsiLookup[req_idx]; - hd->ScsiLookup[req_idx] = NULL; + sc = mptscsih_getclear_scsi_lookup(ioc, req_idx); if (sc == NULL) { MPIHeader_t *hdr = (MPIHeader_t *)mf; @@ -738,8 +738,8 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) */ if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID && pScsiReply->ResponseInfo) { - printk(KERN_NOTICE "[%d:%d:%d:%d] " - "FCP_ResponseInfo=%08xh\n", + printk(MYIOC_s_NOTE_FMT "[%d:%d:%d:%d] " + "FCP_ResponseInfo=%08xh\n", ioc->name, sc->device->host->host_no, sc->device->channel, sc->device->id, sc->device->lun, le32_to_cpu(pScsiReply->ResponseInfo)); @@ -771,10 +771,10 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF) hd->sel_timeout[pScsiReq->TargetID]++; - vdev = sc->device->hostdata; - if (!vdev) + vdevice = sc->device->hostdata; + if (!vdevice) break; - vtarget = vdev->vtarget; + vtarget = vdevice->vtarget; if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) { mptscsih_issue_sep_command(ioc, vtarget, MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED); @@ -824,9 +824,9 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) sc->result=DID_SOFT_ERROR << 16; else /* Sufficient data transfer occurred */ sc->result = (DID_OK << 16) | scsi_status; - dreplyprintk(ioc, printk(KERN_DEBUG + dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n", - sc->result, sc->device->channel, sc->device->id)); + ioc->name, sc->result, sc->device->channel, sc->device->id)); break; case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ @@ -858,9 +858,11 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) } - dreplyprintk(ioc, printk(KERN_DEBUG " sc->underflow={report ERR if < %02xh bytes xfer'd}\n", - sc->underflow)); - dreplyprintk(ioc, printk(KERN_DEBUG " ActBytesXferd=%02xh\n", xfer_cnt)); + dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT + " sc->underflow={report ERR if < %02xh bytes xfer'd}\n", + ioc->name, sc->underflow)); + dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT + " ActBytesXferd=%02xh\n", ioc->name, xfer_cnt)); /* Report Queue Full */ @@ -969,48 +971,32 @@ static void mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd) { MPT_ADAPTER *ioc = hd->ioc; - struct scsi_cmnd *SCpnt; - MPT_FRAME_HDR *mf; + struct scsi_cmnd *sc; + SCSIIORequest_t *mf = NULL; int ii; - int max = ioc->req_depth; - - dprintk(ioc, printk(KERN_DEBUG MYNAM ": flush_ScsiLookup called\n")); - for (ii= 0; ii < max; ii++) { - if ((SCpnt = hd->ScsiLookup[ii]) != NULL) { - - /* Command found. - */ - - /* Null ScsiLookup index - */ - hd->ScsiLookup[ii] = NULL; - - mf = MPT_INDEX_2_MFPTR(ioc, ii); - dmfprintk(ioc, printk(KERN_DEBUG MYNAM ": flush: ScsiDone (mf=%p,sc=%p)\n", - mf, SCpnt)); - - /* Free Chain buffers */ - mptscsih_freeChainBuffers(ioc, ii); - - /* Free Message frames */ - mpt_free_msg_frame(ioc, mf); - - if ((unsigned char *)mf != SCpnt->host_scribble) - continue; - - /* Set status, free OS resources (SG DMA buffers) - * Do OS callback - */ - scsi_dma_unmap(SCpnt); - - SCpnt->result = DID_RESET << 16; - SCpnt->host_scribble = NULL; + int channel, id; - SCpnt->scsi_done(SCpnt); /* Issue the command callback */ - } + for (ii= 0; ii < ioc->req_depth; ii++) { + sc = mptscsih_getclear_scsi_lookup(ioc, ii); + if (!sc) + continue; + mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii); + if (!mf) + continue; + channel = mf->Bus; + id = mf->TargetID; + mptscsih_freeChainBuffers(ioc, ii); + mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf); + if ((unsigned char *)mf != sc->host_scribble) + continue; + scsi_dma_unmap(sc); + sc->result = DID_RESET << 16; + sc->host_scribble = NULL; + sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT + "completing cmds: fw_channel %d, fw_id %d, sc=%p," + " mf = %p, idx=%x\n", ioc->name, channel, id, sc, mf, ii); + sc->scsi_done(sc); } - - return; } /* @@ -1032,17 +1018,16 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice) { SCSIIORequest_t *mf = NULL; int ii; - int max = hd->ioc->req_depth; struct scsi_cmnd *sc; struct scsi_lun lun; + MPT_ADAPTER *ioc = hd->ioc; + unsigned long flags; - dsprintk(hd->ioc, printk(KERN_DEBUG MYNAM ": search_running channel %d id %d lun %d max %d\n", - vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun, max)); - - for (ii=0; ii < max; ii++) { - if ((sc = hd->ScsiLookup[ii]) != NULL) { + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); + for (ii = 0; ii < ioc->req_depth; ii++) { + if ((sc = ioc->ScsiLookup[ii]) != NULL) { - mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii); + mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii); if (mf == NULL) continue; /* If the device is a hidden raid component, then its @@ -1059,22 +1044,23 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice) memcmp(lun.scsi_lun, mf->LUN, 8)) continue; - /* Cleanup - */ - hd->ScsiLookup[ii] = NULL; - mptscsih_freeChainBuffers(hd->ioc, ii); - mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf); if ((unsigned char *)mf != sc->host_scribble) continue; + ioc->ScsiLookup[ii] = NULL; + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + mptscsih_freeChainBuffers(ioc, ii); + mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf); scsi_dma_unmap(sc); sc->host_scribble = NULL; sc->result = DID_NO_CONNECT << 16; - sdev_printk(KERN_INFO, sc->device, "completing cmds: fw_channel %d," - "fw_id %d, sc=%p, mf = %p, idx=%x\n", vdevice->vtarget->channel, + sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT "completing cmds: fw_channel %d," + "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name, vdevice->vtarget->channel, vdevice->vtarget->id, sc, mf, ii); sc->scsi_done(sc); + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); } } + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); return; } @@ -1097,17 +1083,18 @@ mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSI { long time = jiffies; MPT_SCSI_HOST *hd; + MPT_ADAPTER *ioc; if (sc->device == NULL) return; if (sc->device->host == NULL) return; - if ((hd = (MPT_SCSI_HOST *)sc->device->host->hostdata) == NULL) + if ((hd = shost_priv(sc->device->host)) == NULL) return; - + ioc = hd->ioc; if (time - hd->last_queue_full > 10 * HZ) { - dprintk(hd->ioc, printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n", - hd->ioc->name, 0, sc->device->id, sc->device->lun)); + dprintk(ioc, printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n", + ioc->name, 0, sc->device->id, sc->device->lun)); hd->last_queue_full = time; } } @@ -1134,28 +1121,28 @@ mptscsih_remove(struct pci_dev *pdev) scsi_remove_host(host); - if((hd = (MPT_SCSI_HOST *)host->hostdata) == NULL) + if((hd = shost_priv(host)) == NULL) return; mptscsih_shutdown(pdev); sz1=0; - if (hd->ScsiLookup != NULL) { - sz1 = hd->ioc->req_depth * sizeof(void *); - kfree(hd->ScsiLookup); - hd->ScsiLookup = NULL; + if (ioc->ScsiLookup != NULL) { + sz1 = ioc->req_depth * sizeof(void *); + kfree(ioc->ScsiLookup); + ioc->ScsiLookup = NULL; } - dprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Free'd ScsiLookup (%d) memory\n", - hd->ioc->name, sz1)); + ioc->name, sz1)); kfree(hd->info_kbuf); /* NULL the Scsi_Host pointer */ - hd->ioc->sh = NULL; + ioc->sh = NULL; scsi_host_put(host); @@ -1171,15 +1158,6 @@ mptscsih_remove(struct pci_dev *pdev) void mptscsih_shutdown(struct pci_dev *pdev) { - MPT_ADAPTER *ioc = pci_get_drvdata(pdev); - struct Scsi_Host *host = ioc->sh; - MPT_SCSI_HOST *hd; - - if(!host) - return; - - hd = (MPT_SCSI_HOST *)host->hostdata; - } #ifdef CONFIG_PM @@ -1225,7 +1203,7 @@ mptscsih_info(struct Scsi_Host *SChost) MPT_SCSI_HOST *h; int size = 0; - h = (MPT_SCSI_HOST *)SChost->hostdata; + h = shost_priv(SChost); if (h) { if (h->info_kbuf == NULL) @@ -1319,7 +1297,7 @@ int mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int func) { - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; + MPT_SCSI_HOST *hd = shost_priv(host); MPT_ADAPTER *ioc = hd->ioc; int size = 0; @@ -1358,7 +1336,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) MPT_SCSI_HOST *hd; MPT_FRAME_HDR *mf; SCSIIORequest_t *pScsiReq; - VirtDevice *vdev = SCpnt->device->hostdata; + VirtDevice *vdevice = SCpnt->device->hostdata; int lun; u32 datalen; u32 scsictl; @@ -1368,7 +1346,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) int ii; MPT_ADAPTER *ioc; - hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata; + hd = shost_priv(SCpnt->device->host); ioc = hd->ioc; lun = SCpnt->device->lun; SCpnt->scsi_done = done; @@ -1385,7 +1363,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) /* * Put together a MPT SCSI request... */ - if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) { + if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) { dprintk(ioc, printk(MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n", ioc->name)); return SCSI_MLQUEUE_HOST_BUSY; @@ -1415,8 +1393,8 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) /* Default to untagged. Once a target structure has been allocated, * use the Inquiry data to determine if device supports tagged. */ - if (vdev - && (vdev->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES) + if (vdevice + && (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES) && (SCpnt->device->tagged_supported)) { scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ; } else { @@ -1425,10 +1403,10 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) /* Use the above information to set up the message frame */ - pScsiReq->TargetID = (u8) vdev->vtarget->id; - pScsiReq->Bus = vdev->vtarget->channel; + pScsiReq->TargetID = (u8) vdevice->vtarget->id; + pScsiReq->Bus = vdevice->vtarget->channel; pScsiReq->ChainOffset = 0; - if (vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) + if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH; else pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST; @@ -1453,7 +1431,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) pScsiReq->DataLength = cpu_to_le32(datalen); /* SenseBuffer low address */ - pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma + pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma + (my_idx * MPT_SENSE_BUFFER_ALLOC)); /* Now add the SG list @@ -1465,23 +1443,22 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) (dma_addr_t) -1); } else { /* Add a 32 or 64 bit SGE */ - if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS) + if (mptscsih_AddSGE(ioc, SCpnt, pScsiReq, my_idx) != SUCCESS) goto fail; } SCpnt->host_scribble = (unsigned char *)mf; - hd->ScsiLookup[my_idx] = SCpnt; + mptscsih_set_scsi_lookup(ioc, my_idx, SCpnt); - mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf); + mpt_put_msg_frame(ioc->DoneCtx, ioc, mf); dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n", ioc->name, SCpnt, mf, my_idx)); - DBG_DUMP_REQUEST_FRAME(ioc, (u32 *)mf) + DBG_DUMP_REQUEST_FRAME(ioc, (u32 *)mf); return 0; fail: - hd->ScsiLookup[my_idx] = NULL; - mptscsih_freeChainBuffers(hd->ioc, my_idx); - mpt_free_msg_frame(hd->ioc, mf); + mptscsih_freeChainBuffers(ioc, my_idx); + mpt_free_msg_frame(ioc, mf); return SCSI_MLQUEUE_HOST_BUSY; } @@ -1590,38 +1567,38 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int c */ if (mptscsih_tm_pending_wait(hd) == FAILED) { if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) { - dtmprintk(ioc, printk(KERN_DEBUG MYNAM ": %s: TMHandler abort: " + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler abort: " "Timed out waiting for last TM (%d) to complete! \n", ioc->name, hd->tmPending)); return FAILED; } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) { - dtmprintk(ioc, printk(KERN_DEBUG MYNAM ": %s: TMHandler target " + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler target " "reset: Timed out waiting for last TM (%d) " "to complete! \n", ioc->name, hd->tmPending)); return FAILED; } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) { - dtmprintk(ioc, printk(KERN_DEBUG MYNAM ": %s: TMHandler bus reset: " + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler bus reset: " "Timed out waiting for last TM (%d) to complete! \n", ioc->name, hd->tmPending)); return FAILED; } } else { - spin_lock_irqsave(&hd->ioc->FreeQlock, flags); + spin_lock_irqsave(&ioc->FreeQlock, flags); hd->tmPending |= (1 << type); - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + spin_unlock_irqrestore(&ioc->FreeQlock, flags); } - ioc_raw_state = mpt_GetIocState(hd->ioc, 0); + ioc_raw_state = mpt_GetIocState(ioc, 0); if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) { printk(MYIOC_s_WARN_FMT "TM Handler for type=%x: IOC Not operational (0x%x)!\n", ioc->name, type, ioc_raw_state); - printk(KERN_WARNING " Issuing HardReset!!\n"); + printk(MYIOC_s_WARN_FMT " Issuing HardReset!!\n", ioc->name); if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0) - printk((KERN_WARNING "TMHandler: HardReset " - "FAILED!!\n")); + printk(MYIOC_s_WARN_FMT "TMHandler: HardReset " + "FAILED!!\n", ioc->name); return FAILED; } @@ -1680,16 +1657,17 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, i SCSITaskMgmt_t *pScsiTm; int ii; int retval; + MPT_ADAPTER *ioc = hd->ioc; /* Return Fail to calling function if no message frames available. */ - if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) { - dfailprintk(hd->ioc, printk(MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n", - hd->ioc->name)); + if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n", + ioc->name)); return FAILED; } - dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n", - hd->ioc->name, mf)); + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n", + ioc->name, mf)); /* Format the Request */ @@ -1712,28 +1690,34 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, i pScsiTm->TaskMsgContext = ctx2abort; - dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt: ctx2abort (0x%08x) " - "type=%d\n", hd->ioc->name, ctx2abort, type)); + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt: ctx2abort (0x%08x) " + "type=%d\n", ioc->name, ctx2abort, type)); DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm); - if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc, - sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP)) != 0) { - dfailprintk(hd->ioc, printk(MYIOC_s_ERR_FMT "send_handshake FAILED!" - " (hd %p, ioc %p, mf %p, rc=%d) \n", hd->ioc->name, hd, - hd->ioc, mf, retval)); - goto fail_out; + if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) && + (ioc->facts.MsgVersion >= MPI_VERSION_01_05)) + mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf); + else { + retval = mpt_send_handshake_request(ioc->TaskCtx, ioc, + sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP); + if (retval) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "send_handshake FAILED!" + " (hd %p, ioc %p, mf %p, rc=%d) \n", ioc->name, hd, + ioc, mf, retval)); + goto fail_out; + } } if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) { - dfailprintk(hd->ioc, printk(MYIOC_s_ERR_FMT "task management request TIMED OUT!" - " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd, - hd->ioc, mf)); - dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n", - hd->ioc->name)); - retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP); - dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "rc=%d \n", - hd->ioc->name, retval)); + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "task management request TIMED OUT!" + " (hd %p, ioc %p, mf %p) \n", ioc->name, hd, + ioc, mf)); + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n", + ioc->name)); + retval = mpt_HardResetHandler(ioc, CAN_SLEEP); + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rc=%d \n", + ioc->name, retval)); goto fail_out; } @@ -1754,7 +1738,7 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, i /* * Free task managment mf, and corresponding tm flags */ - mpt_free_msg_frame(hd->ioc, mf); + mpt_free_msg_frame(ioc, mf); hd->tmPending = 0; hd->tmState = TM_STATE_NONE; return FAILED; @@ -1797,11 +1781,11 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) /* If we can't locate our host adapter structure, return FAILED status. */ - if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) { + if ((hd = shost_priv(SCpnt->device->host)) == NULL) { SCpnt->result = DID_RESET << 16; SCpnt->scsi_done(SCpnt); - printk(KERN_DEBUG MYNAM ": mptscsih_abort: Can't locate " - "host! (sc=%p)\n", SCpnt); + printk(KERN_ERR MYNAM ": task abort: " + "can't locate host! (sc=%p)\n", SCpnt); return FAILED; } @@ -1812,8 +1796,9 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) vdevice = SCpnt->device->hostdata; if (!vdevice || !vdevice->vtarget) { - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: device has been " - "deleted (sc=%p)\n", ioc->name, SCpnt)); + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "task abort: device has been deleted (sc=%p)\n", + ioc->name, SCpnt)); SCpnt->result = DID_NO_CONNECT << 16; SCpnt->scsi_done(SCpnt); retval = 0; @@ -1823,8 +1808,9 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) /* Task aborts are not supported for hidden raid components. */ if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) { - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: hidden raid " - "component (sc=%p)\n", ioc->name, SCpnt)); + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "task abort: hidden raid component (sc=%p)\n", + ioc->name, SCpnt)); SCpnt->result = DID_RESET << 16; retval = FAILED; goto out; @@ -1832,12 +1818,12 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) /* Find this command */ - if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) { + if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) { /* Cmd not found in ScsiLookup. * Do OS callback. */ SCpnt->result = DID_RESET << 16; - dtmprintk(ioc, printk(KERN_DEBUG MYNAM ": %s: mptscsih_abort: " + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: " "Command not in the active list! (sc=%p)\n", ioc->name, SCpnt)); retval = 0; @@ -1859,7 +1845,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) * swap it here either. It is an opaque cookie to * the controller, so it does not matter. -DaveM */ - mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx); + mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx); ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext; hd->abortSCpnt = SCpnt; @@ -1868,7 +1854,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun, ctx2abort, mptscsih_get_tm_timeout(ioc)); - if (SCPNT_TO_LOOKUP_IDX(SCpnt) == scpnt_idx && + if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx && SCpnt->serial_number == sn) retval = FAILED; @@ -1901,9 +1887,9 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt) /* If we can't locate our host adapter structure, return FAILED status. */ - if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){ - printk(KERN_DEBUG MYNAM ": mptscsih_dev_reset: Can't " - "locate host! (sc=%p)\n", SCpnt); + if ((hd = shost_priv(SCpnt->device->host)) == NULL){ + printk(KERN_ERR MYNAM ": target reset: " + "Can't locate host! (sc=%p)\n", SCpnt); return FAILED; } @@ -1959,14 +1945,14 @@ mptscsih_bus_reset(struct scsi_cmnd * SCpnt) { MPT_SCSI_HOST *hd; int retval; - VirtDevice *vdev; + VirtDevice *vdevice; MPT_ADAPTER *ioc; /* If we can't locate our host adapter structure, return FAILED status. */ - if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){ - printk(KERN_DEBUG MYNAM ": mptscsih_bus_reset: Can't " - "locate host! (sc=%p)\n", SCpnt ); + if ((hd = shost_priv(SCpnt->device->host)) == NULL){ + printk(KERN_ERR MYNAM ": bus reset: " + "Can't locate host! (sc=%p)\n", SCpnt); return FAILED; } @@ -1978,9 +1964,9 @@ mptscsih_bus_reset(struct scsi_cmnd * SCpnt) if (hd->timeouts < -1) hd->timeouts++; - vdev = SCpnt->device->hostdata; + vdevice = SCpnt->device->hostdata; retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, - vdev->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(ioc)); + vdevice->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(ioc)); printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n", ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt); @@ -2008,9 +1994,9 @@ mptscsih_host_reset(struct scsi_cmnd *SCpnt) MPT_ADAPTER *ioc; /* If we can't locate the host to reset, then we failed. */ - if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){ - printk( KERN_DEBUG MYNAM ": mptscsih_host_reset: Can't " - "locate host! (sc=%p)\n", SCpnt); + if ((hd = shost_priv(SCpnt->device->host)) == NULL){ + printk(KERN_ERR MYNAM ": host reset: " + "Can't locate host! (sc=%p)\n", SCpnt); return FAILED; } @@ -2021,7 +2007,7 @@ mptscsih_host_reset(struct scsi_cmnd *SCpnt) /* If our attempts to reset the host failed, then return a failed * status. The host will be taken off line by the SCSI mid-layer. */ - if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0) { + if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0) { retval = FAILED; } else { /* Make sure TM pending is cleared and TM state is set to @@ -2051,17 +2037,18 @@ mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd) unsigned long flags; int loop_count = 4 * 10; /* Wait 10 seconds */ int status = FAILED; + MPT_ADAPTER *ioc = hd->ioc; do { - spin_lock_irqsave(&hd->ioc->FreeQlock, flags); + spin_lock_irqsave(&ioc->FreeQlock, flags); if (hd->tmState == TM_STATE_NONE) { hd->tmState = TM_STATE_IN_PROGRESS; hd->tmPending = 1; - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + spin_unlock_irqrestore(&ioc->FreeQlock, flags); status = SUCCESS; break; } - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + spin_unlock_irqrestore(&ioc->FreeQlock, flags); msleep(250); } while (--loop_count); @@ -2082,15 +2069,16 @@ mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout ) unsigned long flags; int loop_count = 4 * timeout; int status = FAILED; + MPT_ADAPTER *ioc = hd->ioc; do { - spin_lock_irqsave(&hd->ioc->FreeQlock, flags); + spin_lock_irqsave(&ioc->FreeQlock, flags); if(hd->tmPending == 0) { status = SUCCESS; - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + spin_unlock_irqrestore(&ioc->FreeQlock, flags); break; } - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + spin_unlock_irqrestore(&ioc->FreeQlock, flags); msleep(250); } while (--loop_count); @@ -2172,7 +2160,7 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *m return 1; } - hd = (MPT_SCSI_HOST *)ioc->sh->hostdata; + hd = shost_priv(ioc->sh); pScsiTmReply = (SCSITaskMgmtReply_t*)mr; pScsiTmReq = (SCSITaskMgmt_t*)mf; tmType = pScsiTmReq->TaskType; @@ -2223,7 +2211,7 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *m if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED || hd->cmdPtr) if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) - printk((KERN_WARNING " Firmware Reload FAILED!!\n")); + printk(MYIOC_s_WARN_FMT " Firmware Reload FAILED!!\n", ioc->name); break; case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET: @@ -2366,7 +2354,7 @@ void mptscsih_slave_destroy(struct scsi_device *sdev) { struct Scsi_Host *host = sdev->host; - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; + MPT_SCSI_HOST *hd = shost_priv(host); VirtTarget *vtarget; VirtDevice *vdevice; struct scsi_target *starget; @@ -2393,16 +2381,17 @@ mptscsih_slave_destroy(struct scsi_device *sdev) int mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth) { - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata; + MPT_SCSI_HOST *hd = shost_priv(sdev->host); VirtTarget *vtarget; struct scsi_target *starget; int max_depth; int tagged; + MPT_ADAPTER *ioc = hd->ioc; starget = scsi_target(sdev); vtarget = starget->hostdata; - if (hd->ioc->bus_type == SPI) { + if (ioc->bus_type == SPI) { if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)) max_depth = 1; else if (sdev->type == TYPE_DISK && @@ -2437,19 +2426,20 @@ mptscsih_slave_configure(struct scsi_device *sdev) VirtTarget *vtarget; VirtDevice *vdevice; struct scsi_target *starget; - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata; + MPT_SCSI_HOST *hd = shost_priv(sh); + MPT_ADAPTER *ioc = hd->ioc; starget = scsi_target(sdev); vtarget = starget->hostdata; vdevice = sdev->hostdata; - dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT + dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "device @ %p, channel=%d, id=%d, lun=%d\n", - hd->ioc->name, sdev, sdev->channel, sdev->id, sdev->lun)); - if (hd->ioc->bus_type == SPI) - dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT + ioc->name, sdev, sdev->channel, sdev->id, sdev->lun)); + if (ioc->bus_type == SPI) + dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sdtr %d wdtr %d ppr %d inq length=%d\n", - hd->ioc->name, sdev->sdtr, sdev->wdtr, + ioc->name, sdev->sdtr, sdev->wdtr, sdev->ppr, sdev->inquiry_len)); if (sdev->id > sh->max_id) { @@ -2461,21 +2451,21 @@ mptscsih_slave_configure(struct scsi_device *sdev) vdevice->configured_lun = 1; mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH); - dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT + dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Queue depth=%d, tflags=%x\n", - hd->ioc->name, sdev->queue_depth, vtarget->tflags)); + ioc->name, sdev->queue_depth, vtarget->tflags)); - if (hd->ioc->bus_type == SPI) - dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT + if (ioc->bus_type == SPI) + dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n", - hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset, + ioc->name, vtarget->negoFlags, vtarget->maxOffset, vtarget->minSyncFactor)); slave_configure_exit: - dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT + dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "tagged %d, simple %d, ordered %d\n", - hd->ioc->name,sdev->tagged_supported, sdev->simple_tags, + ioc->name,sdev->tagged_supported, sdev->simple_tags, sdev->ordered_tags)); return 0; @@ -2494,14 +2484,15 @@ slave_configure_exit: static void mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply) { - VirtDevice *vdev; + VirtDevice *vdevice; SCSIIORequest_t *pReq; u32 sense_count = le32_to_cpu(pScsiReply->SenseCount); + MPT_ADAPTER *ioc = hd->ioc; /* Get target structure */ pReq = (SCSIIORequest_t *) mf; - vdev = sc->device->hostdata; + vdevice = sc->device->hostdata; if (sense_count) { u8 *sense_data; @@ -2509,15 +2500,14 @@ mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR /* Copy the sense received into the scsi command block. */ req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); - sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC)); + sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC)); memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc)); /* Log SMART data (asc = 0x5D, non-IM case only) if required. */ - if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) { - if ((sense_data[12] == 0x5D) && (vdev->vtarget->raidVolume == 0)) { + if ((ioc->events) && (ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) { + if ((sense_data[12] == 0x5D) && (vdevice->vtarget->raidVolume == 0)) { int idx; - MPT_ADAPTER *ioc = hd->ioc; idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE; ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE; @@ -2530,36 +2520,116 @@ mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12]; ioc->eventContext++; - if (hd->ioc->pcidev->vendor == + if (ioc->pcidev->vendor == PCI_VENDOR_ID_IBM) { - mptscsih_issue_sep_command(hd->ioc, - vdev->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT); - vdev->vtarget->tflags |= + mptscsih_issue_sep_command(ioc, + vdevice->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT); + vdevice->vtarget->tflags |= MPT_TARGET_FLAGS_LED_ON; } } } } else { - dprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n", - hd->ioc->name)); + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n", + ioc->name)); } } -static int -SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc) +/** + * mptscsih_get_scsi_lookup + * + * retrieves scmd entry from ScsiLookup[] array list + * + * @ioc: Pointer to MPT_ADAPTER structure + * @i: index into the array + * + * Returns the scsi_cmd pointer + * + **/ +static struct scsi_cmnd * +mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i) { - MPT_SCSI_HOST *hd; - int i; + unsigned long flags; + struct scsi_cmnd *scmd; - hd = (MPT_SCSI_HOST *) sc->device->host->hostdata; + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); + scmd = ioc->ScsiLookup[i]; + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + + return scmd; +} + +/** + * mptscsih_getclear_scsi_lookup + * + * retrieves and clears scmd entry from ScsiLookup[] array list + * + * @ioc: Pointer to MPT_ADAPTER structure + * @i: index into the array + * + * Returns the scsi_cmd pointer + * + **/ +static struct scsi_cmnd * +mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i) +{ + unsigned long flags; + struct scsi_cmnd *scmd; + + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); + scmd = ioc->ScsiLookup[i]; + ioc->ScsiLookup[i] = NULL; + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + + return scmd; +} - for (i = 0; i < hd->ioc->req_depth; i++) { - if (hd->ScsiLookup[i] == sc) { - return i; +/** + * mptscsih_set_scsi_lookup + * + * writes a scmd entry into the ScsiLookup[] array list + * + * @ioc: Pointer to MPT_ADAPTER structure + * @i: index into the array + * @scmd: scsi_cmnd pointer + * + **/ +static void +mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd) +{ + unsigned long flags; + + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); + ioc->ScsiLookup[i] = scmd; + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); +} + +/** + * SCPNT_TO_LOOKUP_IDX + * + * search's for a given scmd in the ScsiLookup[] array list + * + * @ioc: Pointer to MPT_ADAPTER structure + * @scmd: scsi_cmnd pointer + * + **/ +static int +SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc) +{ + unsigned long flags; + int i, index=-1; + + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); + for (i = 0; i < ioc->req_depth; i++) { + if (ioc->ScsiLookup[i] == sc) { + index = i; + goto out; } } - return -1; + out: + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + return index; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -2568,21 +2638,20 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) { MPT_SCSI_HOST *hd; unsigned long flags; - int ii; - dtmprintk(ioc, printk(KERN_DEBUG MYNAM - ": IOC %s_reset routed to SCSI host driver!\n", - reset_phase==MPT_IOC_SETUP_RESET ? "setup" : ( - reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + ": IOC %s_reset routed to SCSI host driver!\n", + ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : ( + reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); /* If a FW reload request arrives after base installed but * before all scsi hosts have been attached, then an alt_ioc * may have a NULL sh pointer. */ - if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL)) + if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL) return 0; else - hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; + hd = shost_priv(ioc->sh); if (reset_phase == MPT_IOC_SETUP_RESET) { dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Setup-Diag Reset\n", ioc->name)); @@ -2624,11 +2693,6 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) * Init all control structures. */ - /* ScsiLookup initialization - */ - for (ii=0; ii < hd->ioc->req_depth; ii++) - hd->ScsiLookup[ii] = NULL; - /* 2. Chain Buffer initialization */ @@ -2675,7 +2739,7 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) ioc->name, event)); if (ioc->sh == NULL || - ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL)) + ((hd = shost_priv(ioc->sh)) == NULL)) return 1; switch (event) { @@ -2713,7 +2777,8 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) case MPI_EVENT_STATE_CHANGE: /* 02 */ case MPI_EVENT_EVENT_CHANGE: /* 0A */ default: - dprintk(ioc, printk(KERN_DEBUG MYNAM ": Ignoring event (=%02Xh)\n", event)); + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": Ignoring event (=%02Xh)\n", + ioc->name, event)); break; } @@ -2753,7 +2818,7 @@ mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) int completionCode; u16 req_idx; - hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; + hd = shost_priv(ioc->sh); if ((mf == NULL) || (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) { @@ -2765,17 +2830,17 @@ mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) del_timer(&hd->timer); req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); - hd->ScsiLookup[req_idx] = NULL; + mptscsih_set_scsi_lookup(ioc, req_idx, NULL); pReq = (SCSIIORequest_t *) mf; if (mf != hd->cmdPtr) { printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n", - hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx); + ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx); } hd->cmdPtr = NULL; ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n", - hd->ioc->name, mf, mr, req_idx)); + ioc->name, mf, mr, req_idx)); hd->pLocal = &hd->localReply; hd->pLocal->scsiStatus = 0; @@ -2839,15 +2904,15 @@ mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) */ completionCode = MPT_SCANDV_SENSE; hd->pLocal->scsiStatus = scsi_status; - sense_data = ((u8 *)hd->ioc->sense_buf_pool + + sense_data = ((u8 *)ioc->sense_buf_pool + (req_idx * MPT_SENSE_BUFFER_ALLOC)); sz = min_t(int, pReq->SenseBufferLength, SCSI_STD_SENSE_BYTES); memcpy(hd->pLocal->sense, sense_data, sz); - ddvprintk(ioc, printk(KERN_DEBUG " Check Condition, sense ptr %p\n", - sense_data)); + ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Check Condition, sense ptr %p\n", + ioc->name, sense_data)); } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) { if (pReq->CDB[0] == INQUIRY) completionCode = MPT_SCANDV_ISSUE_SENSE; @@ -2906,8 +2971,9 @@ void mptscsih_timer_expired(unsigned long data) { MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data; + MPT_ADAPTER *ioc = hd->ioc; - ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr)); + ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired! Cmd %p\n", ioc->name, hd->cmdPtr)); if (hd->cmdPtr) { MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr; @@ -2921,13 +2987,13 @@ mptscsih_timer_expired(unsigned long data) */ } else { /* Perform a FW reload */ - if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) { - printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name); + if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) { + printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name); } } } else { /* This should NEVER happen */ - printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name); + printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", ioc->name); } /* No more processing. @@ -2935,7 +3001,7 @@ mptscsih_timer_expired(unsigned long data) * The FW will reply to all outstanding commands, callback will finish cleanup. * Hard reset clean-up will free all resources. */ - ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired Complete!\n", hd->ioc->name)); + ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired Complete!\n", ioc->name)); return; } @@ -2973,11 +3039,12 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) char cmdLen; char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; char cmd = io->cmd; + MPT_ADAPTER *ioc = hd->ioc; in_isr = in_interrupt(); if (in_isr) { - dprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Internal SCSI IO request not allowed in ISR context!\n", - hd->ioc->name)); + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Internal SCSI IO request not allowed in ISR context!\n", + ioc->name)); return -EPERM; } @@ -3078,9 +3145,9 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) /* Get and Populate a free Frame */ - if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) { - ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "No msg frames!\n", - hd->ioc->name)); + if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) { + dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "No msg frames!\n", + ioc->name)); return -EBUSY; } @@ -3119,19 +3186,19 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) if (cmd == REQUEST_SENSE) { pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED); - ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Untagged! 0x%2x\n", - hd->ioc->name, cmd)); + ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Untagged! 0x%2x\n", + ioc->name, cmd)); } for (ii=0; ii < 16; ii++) pScsiReq->CDB[ii] = CDB[ii]; pScsiReq->DataLength = cpu_to_le32(io->size); - pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma + pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma + (my_idx * MPT_SENSE_BUFFER_ALLOC)); - ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Sending Command 0x%x for (%d:%d:%d)\n", - hd->ioc->name, cmd, io->channel, io->id, io->lun)); + ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Command 0x%x for (%d:%d:%d)\n", + ioc->name, cmd, io->channel, io->id, io->lun)); if (dir == MPI_SCSIIO_CONTROL_READ) { mpt_add_sge((char *) &pScsiReq->SGL, @@ -3166,7 +3233,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) hd->cmdPtr = mf; add_timer(&hd->timer); - mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf); + mpt_put_msg_frame(ioc->InternalCtx, ioc, mf); wait_event(hd->scandv_waitq, hd->scandv_wait_done); if (hd->pLocal) { @@ -3182,8 +3249,8 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) } else { rc = -EFAULT; /* This should never happen. */ - ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "_do_cmd: Null pLocal!!!\n", - hd->ioc->name)); + ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "_do_cmd: Null pLocal!!!\n", + ioc->name)); } return rc; @@ -3235,7 +3302,7 @@ static ssize_t mptscsih_version_fw_show(struct class_device *cdev, char *buf) { struct Scsi_Host *host = class_to_shost(cdev); - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; + MPT_SCSI_HOST *hd = shost_priv(host); MPT_ADAPTER *ioc = hd->ioc; return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n", @@ -3250,7 +3317,7 @@ static ssize_t mptscsih_version_bios_show(struct class_device *cdev, char *buf) { struct Scsi_Host *host = class_to_shost(cdev); - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; + MPT_SCSI_HOST *hd = shost_priv(host); MPT_ADAPTER *ioc = hd->ioc; return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n", @@ -3265,7 +3332,7 @@ static ssize_t mptscsih_version_mpi_show(struct class_device *cdev, char *buf) { struct Scsi_Host *host = class_to_shost(cdev); - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; + MPT_SCSI_HOST *hd = shost_priv(host); MPT_ADAPTER *ioc = hd->ioc; return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion); @@ -3276,7 +3343,7 @@ static ssize_t mptscsih_version_product_show(struct class_device *cdev, char *buf) { struct Scsi_Host *host = class_to_shost(cdev); - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; + MPT_SCSI_HOST *hd = shost_priv(host); MPT_ADAPTER *ioc = hd->ioc; return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name); @@ -3288,7 +3355,7 @@ static ssize_t mptscsih_version_nvdata_persistent_show(struct class_device *cdev, char *buf) { struct Scsi_Host *host = class_to_shost(cdev); - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; + MPT_SCSI_HOST *hd = shost_priv(host); MPT_ADAPTER *ioc = hd->ioc; return snprintf(buf, PAGE_SIZE, "%02xh\n", @@ -3301,7 +3368,7 @@ static ssize_t mptscsih_version_nvdata_default_show(struct class_device *cdev, char *buf) { struct Scsi_Host *host = class_to_shost(cdev); - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; + MPT_SCSI_HOST *hd = shost_priv(host); MPT_ADAPTER *ioc = hd->ioc; return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default); @@ -3313,7 +3380,7 @@ static ssize_t mptscsih_board_name_show(struct class_device *cdev, char *buf) { struct Scsi_Host *host = class_to_shost(cdev); - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; + MPT_SCSI_HOST *hd = shost_priv(host); MPT_ADAPTER *ioc = hd->ioc; return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name); @@ -3324,7 +3391,7 @@ static ssize_t mptscsih_board_assembly_show(struct class_device *cdev, char *buf) { struct Scsi_Host *host = class_to_shost(cdev); - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; + MPT_SCSI_HOST *hd = shost_priv(host); MPT_ADAPTER *ioc = hd->ioc; return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly); @@ -3336,7 +3403,7 @@ static ssize_t mptscsih_board_tracer_show(struct class_device *cdev, char *buf) { struct Scsi_Host *host = class_to_shost(cdev); - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; + MPT_SCSI_HOST *hd = shost_priv(host); MPT_ADAPTER *ioc = hd->ioc; return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer); @@ -3348,7 +3415,7 @@ static ssize_t mptscsih_io_delay_show(struct class_device *cdev, char *buf) { struct Scsi_Host *host = class_to_shost(cdev); - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; + MPT_SCSI_HOST *hd = shost_priv(host); MPT_ADAPTER *ioc = hd->ioc; return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay); @@ -3360,7 +3427,7 @@ static ssize_t mptscsih_device_delay_show(struct class_device *cdev, char *buf) { struct Scsi_Host *host = class_to_shost(cdev); - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; + MPT_SCSI_HOST *hd = shost_priv(host); MPT_ADAPTER *ioc = hd->ioc; return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay); @@ -3372,7 +3439,7 @@ static ssize_t mptscsih_debug_level_show(struct class_device *cdev, char *buf) { struct Scsi_Host *host = class_to_shost(cdev); - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; + MPT_SCSI_HOST *hd = shost_priv(host); MPT_ADAPTER *ioc = hd->ioc; return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level); @@ -3382,7 +3449,7 @@ mptscsih_debug_level_store(struct class_device *cdev, const char *buf, size_t count) { struct Scsi_Host *host = class_to_shost(cdev); - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; + MPT_SCSI_HOST *hd = shost_priv(host); MPT_ADAPTER *ioc = hd->ioc; int val = 0; diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h index 67b088db2f10..d289e97cfe8b 100644 --- a/drivers/message/fusion/mptscsih.h +++ b/drivers/message/fusion/mptscsih.h @@ -3,9 +3,9 @@ * High performance SCSI / Fibre Channel SCSI Host device driver. * For use with PCI chip/adapter(s): * LSIFC9xx/LSI409xx Fibre Channel - * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * running LSI Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2007 LSI Logic Corporation + * Copyright (c) 1999-2007 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) * */ diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index 8c98420640a5..25bcfcf36f2e 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c @@ -1,9 +1,9 @@ /* * linux/drivers/message/fusion/mptspi.c - * For use with LSI Logic PCI chip/adapter(s) - * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * For use with LSI PCI chip/adapter(s) + * running LSI Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2007 LSI Logic Corporation + * Copyright (c) 1999-2007 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) * */ @@ -90,9 +90,9 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *, static struct scsi_transport_template *mptspi_transport_template = NULL; -static int mptspiDoneCtx = -1; -static int mptspiTaskCtx = -1; -static int mptspiInternalCtx = -1; /* Used only for internal commands */ +static u8 mptspiDoneCtx = MPT_MAX_PROTOCOL_DRIVERS; +static u8 mptspiTaskCtx = MPT_MAX_PROTOCOL_DRIVERS; +static u8 mptspiInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */ /** * mptspi_setTargetNegoParms - Update the target negotiation parameters @@ -107,7 +107,8 @@ static void mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target, struct scsi_device *sdev) { - SpiCfgData *pspi_data = &hd->ioc->spi_data; + MPT_ADAPTER *ioc = hd->ioc; + SpiCfgData *pspi_data = &ioc->spi_data; int id = (int) target->id; int nvram; u8 width = MPT_NARROW; @@ -138,9 +139,10 @@ mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target, else { factor = MPT_ULTRA320; if (scsi_device_qas(sdev)) { - ddvprintk(hd->ioc, - printk(KERN_DEBUG "Enabling QAS due to " - "byte56=%02x on id=%d!\n", scsi_device_qas(sdev), id)); + ddvprintk(ioc, + printk(MYIOC_s_DEBUG_FMT "Enabling QAS due to " + "byte56=%02x on id=%d!\n", ioc->name, + scsi_device_qas(sdev), id)); noQas = 0; } if (sdev->type == TYPE_TAPE && @@ -227,8 +229,8 @@ mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target, /* Disable QAS in a mixed configuration case */ - ddvprintk(hd->ioc, printk(KERN_DEBUG - "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id)); + ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Disabling QAS due to noQas=%02x on id=%d!\n", ioc->name, noQas, id)); } } @@ -302,7 +304,7 @@ mptspi_writeIOCPage4(MPT_SCSI_HOST *hd, u8 channel , u8 id) ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n", - ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, id, channel)); + ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, id, channel)); mpt_put_msg_frame(ioc->DoneCtx, ioc, mf); @@ -374,14 +376,15 @@ static int mptspi_is_raid(struct _MPT_SCSI_HOST *hd, u32 id) { int i, rc = 0; + MPT_ADAPTER *ioc = hd->ioc; - if (!hd->ioc->raid_data.pIocPg2) + if (!ioc->raid_data.pIocPg2) goto out; - if (!hd->ioc->raid_data.pIocPg2->NumActiveVolumes) + if (!ioc->raid_data.pIocPg2->NumActiveVolumes) goto out; - for (i=0; i < hd->ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { - if (hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id) { + for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { + if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id) { rc = 1; goto out; } @@ -394,17 +397,19 @@ mptspi_is_raid(struct _MPT_SCSI_HOST *hd, u32 id) static int mptspi_target_alloc(struct scsi_target *starget) { struct Scsi_Host *shost = dev_to_shost(&starget->dev); - struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata; + struct _MPT_SCSI_HOST *hd = shost_priv(shost); VirtTarget *vtarget; + MPT_ADAPTER *ioc; if (hd == NULL) return -ENODEV; + ioc = hd->ioc; vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL); if (!vtarget) return -ENOMEM; - vtarget->ioc_id = hd->ioc->id; + vtarget->ioc_id = ioc->id; vtarget->tflags = MPT_TARGET_FLAGS_Q_YES; vtarget->id = (u8)starget->id; vtarget->channel = (u8)starget->channel; @@ -412,34 +417,34 @@ static int mptspi_target_alloc(struct scsi_target *starget) starget->hostdata = vtarget; if (starget->channel == 1) { - if (mptscsih_is_phys_disk(hd->ioc, 0, starget->id) == 0) + if (mptscsih_is_phys_disk(ioc, 0, starget->id) == 0) return 0; vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT; /* The real channel for this device is zero */ vtarget->channel = 0; /* The actual physdisknum (for RAID passthrough) */ - vtarget->id = mptscsih_raid_id_to_num(hd->ioc, 0, + vtarget->id = mptscsih_raid_id_to_num(ioc, 0, starget->id); } if (starget->channel == 0 && mptspi_is_raid(hd, starget->id)) { vtarget->raidVolume = 1; - ddvprintk(hd->ioc, printk(KERN_DEBUG - "RAID Volume @ channel=%d id=%d\n", starget->channel, + ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "RAID Volume @ channel=%d id=%d\n", ioc->name, starget->channel, starget->id)); } - if (hd->ioc->spi_data.nvram && - hd->ioc->spi_data.nvram[starget->id] != MPT_HOST_NVRAM_INVALID) { - u32 nvram = hd->ioc->spi_data.nvram[starget->id]; + if (ioc->spi_data.nvram && + ioc->spi_data.nvram[starget->id] != MPT_HOST_NVRAM_INVALID) { + u32 nvram = ioc->spi_data.nvram[starget->id]; spi_min_period(starget) = (nvram & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT; spi_max_width(starget) = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1; } else { - spi_min_period(starget) = hd->ioc->spi_data.minSyncFactor; - spi_max_width(starget) = hd->ioc->spi_data.maxBusWidth; + spi_min_period(starget) = ioc->spi_data.minSyncFactor; + spi_max_width(starget) = ioc->spi_data.maxBusWidth; } - spi_max_offset(starget) = hd->ioc->spi_data.maxSyncOffset; + spi_max_offset(starget) = ioc->spi_data.maxSyncOffset; spi_offset(starget) = 0; mptspi_write_width(starget, 0); @@ -509,10 +514,10 @@ static int mptspi_read_spi_device_pg0(struct scsi_target *starget, struct _CONFIG_PAGE_SCSI_DEVICE_0 *pass_pg0) { struct Scsi_Host *shost = dev_to_shost(&starget->dev); - struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata; + struct _MPT_SCSI_HOST *hd = shost_priv(shost); struct _MPT_ADAPTER *ioc = hd->ioc; - struct _CONFIG_PAGE_SCSI_DEVICE_0 *pg0; - dma_addr_t pg0_dma; + struct _CONFIG_PAGE_SCSI_DEVICE_0 *spi_dev_pg0; + dma_addr_t spi_dev_pg0_dma; int size; struct _x_config_parms cfg; struct _CONFIG_PAGE_HEADER hdr; @@ -530,9 +535,10 @@ static int mptspi_read_spi_device_pg0(struct scsi_target *starget, size += 2048; */ - pg0 = dma_alloc_coherent(&ioc->pcidev->dev, size, &pg0_dma, GFP_KERNEL); - if (pg0 == NULL) { - starget_printk(KERN_ERR, starget, "dma_alloc_coherent for parameters failed\n"); + spi_dev_pg0 = dma_alloc_coherent(&ioc->pcidev->dev, size, &spi_dev_pg0_dma, GFP_KERNEL); + if (spi_dev_pg0 == NULL) { + starget_printk(KERN_ERR, starget, MYIOC_s_FMT + "dma_alloc_coherent for parameters failed\n", ioc->name); return -EINVAL; } @@ -546,22 +552,22 @@ static int mptspi_read_spi_device_pg0(struct scsi_target *starget, memset(&cfg, 0, sizeof(cfg)); cfg.cfghdr.hdr = &hdr; - cfg.physAddr = pg0_dma; + cfg.physAddr = spi_dev_pg0_dma; cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; cfg.dir = 0; cfg.pageAddr = starget->id; if (mpt_config(ioc, &cfg)) { - starget_printk(KERN_ERR, starget, "mpt_config failed\n"); + starget_printk(KERN_ERR, starget, MYIOC_s_FMT "mpt_config failed\n", ioc->name); goto out_free; } err = 0; - memcpy(pass_pg0, pg0, size); + memcpy(pass_pg0, spi_dev_pg0, size); - mptspi_print_read_nego(hd, starget, le32_to_cpu(pg0->NegotiatedParameters)); + mptspi_print_read_nego(hd, starget, le32_to_cpu(spi_dev_pg0->NegotiatedParameters)); out_free: - dma_free_coherent(&ioc->pcidev->dev, size, pg0, pg0_dma); + dma_free_coherent(&ioc->pcidev->dev, size, spi_dev_pg0, spi_dev_pg0_dma); return err; } @@ -588,11 +594,11 @@ static u32 mptspi_getRP(struct scsi_target *starget) static void mptspi_read_parameters(struct scsi_target *starget) { int nego; - struct _CONFIG_PAGE_SCSI_DEVICE_0 pg0; + struct _CONFIG_PAGE_SCSI_DEVICE_0 spi_dev_pg0; - mptspi_read_spi_device_pg0(starget, &pg0); + mptspi_read_spi_device_pg0(starget, &spi_dev_pg0); - nego = le32_to_cpu(pg0.NegotiatedParameters); + nego = le32_to_cpu(spi_dev_pg0.NegotiatedParameters); spi_iu(starget) = (nego & MPI_SCSIDEVPAGE0_NP_IU) ? 1 : 0; spi_dt(starget) = (nego & MPI_SCSIDEVPAGE0_NP_DT) ? 1 : 0; @@ -612,12 +618,13 @@ mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id) { MpiRaidActionRequest_t *pReq; MPT_FRAME_HDR *mf; + MPT_ADAPTER *ioc = hd->ioc; /* Get and Populate a free Frame */ - if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) { - ddvprintk(hd->ioc, printk(MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n", - hd->ioc->name)); + if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) { + ddvprintk(ioc, printk(MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n", + ioc->name)); return -EAGAIN; } pReq = (MpiRaidActionRequest_t *)mf; @@ -638,8 +645,8 @@ mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id) mpt_add_sge((char *)&pReq->ActionDataSGE, MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1); - ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "RAID Volume action=%x channel=%d id=%d\n", - hd->ioc->name, pReq->Action, channel, id)); + ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RAID Volume action=%x channel=%d id=%d\n", + ioc->name, pReq->Action, channel, id)); hd->pLocal = NULL; hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */ @@ -651,7 +658,7 @@ mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id) hd->cmdPtr = mf; add_timer(&hd->timer); - mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf); + mpt_put_msg_frame(ioc->InternalCtx, ioc, mf); wait_event(hd->scandv_waitq, hd->scandv_wait_done); if ((hd->pLocal == NULL) || (hd->pLocal->completion != 0)) @@ -664,6 +671,7 @@ static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd, struct scsi_device *sdev) { VirtTarget *vtarget = scsi_target(sdev)->hostdata; + MPT_ADAPTER *ioc = hd->ioc; /* no DV on RAID devices */ if (sdev->channel == 0 && @@ -673,8 +681,8 @@ static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd, /* If this is a piece of a RAID, then quiesce first */ if (sdev->channel == 1 && mptscsih_quiesce_raid(hd, 1, vtarget->channel, vtarget->id) < 0) { - starget_printk(KERN_ERR, scsi_target(sdev), - "Integrated RAID quiesce failed\n"); + starget_printk(KERN_ERR, scsi_target(sdev), MYIOC_s_FMT + "Integrated RAID quiesce failed\n", ioc->name); return; } @@ -684,8 +692,8 @@ static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd, if (sdev->channel == 1 && mptscsih_quiesce_raid(hd, 0, vtarget->channel, vtarget->id) < 0) - starget_printk(KERN_ERR, scsi_target(sdev), - "Integrated RAID resume failed\n"); + starget_printk(KERN_ERR, scsi_target(sdev), MYIOC_s_FMT + "Integrated RAID resume failed\n", ioc->name); mptspi_read_parameters(sdev->sdev_target); spi_display_xfer_agreement(sdev->sdev_target); @@ -694,28 +702,29 @@ static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd, static int mptspi_slave_alloc(struct scsi_device *sdev) { - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata; + MPT_SCSI_HOST *hd = shost_priv(sdev->host); VirtTarget *vtarget; - VirtDevice *vdev; + VirtDevice *vdevice; struct scsi_target *starget; + MPT_ADAPTER *ioc = hd->ioc; if (sdev->channel == 1 && - mptscsih_is_phys_disk(hd->ioc, 0, sdev->id) == 0) + mptscsih_is_phys_disk(ioc, 0, sdev->id) == 0) return -ENXIO; - vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL); - if (!vdev) { + vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL); + if (!vdevice) { printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n", - hd->ioc->name, sizeof(VirtDevice)); + ioc->name, sizeof(VirtDevice)); return -ENOMEM; } - vdev->lun = sdev->lun; - sdev->hostdata = vdev; + vdevice->lun = sdev->lun; + sdev->hostdata = vdevice; starget = scsi_target(sdev); vtarget = starget->hostdata; - vdev->vtarget = vtarget; + vdevice->vtarget = vtarget; vtarget->num_luns++; if (sdev->channel == 1) @@ -726,8 +735,7 @@ static int mptspi_slave_alloc(struct scsi_device *sdev) static int mptspi_slave_configure(struct scsi_device *sdev) { - struct _MPT_SCSI_HOST *hd = - (struct _MPT_SCSI_HOST *)sdev->host->hostdata; + struct _MPT_SCSI_HOST *hd = shost_priv(sdev->host); VirtTarget *vtarget = scsi_target(sdev)->hostdata; int ret; @@ -755,24 +763,25 @@ static int mptspi_slave_configure(struct scsi_device *sdev) static int mptspi_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) { - struct _MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata; - VirtDevice *vdev = SCpnt->device->hostdata; + struct _MPT_SCSI_HOST *hd = shost_priv(SCpnt->device->host); + VirtDevice *vdevice = SCpnt->device->hostdata; + MPT_ADAPTER *ioc = hd->ioc; - if (!vdev || !vdev->vtarget) { + if (!vdevice || !vdevice->vtarget) { SCpnt->result = DID_NO_CONNECT << 16; done(SCpnt); return 0; } if (SCpnt->device->channel == 1 && - mptscsih_is_phys_disk(hd->ioc, 0, SCpnt->device->id) == 0) { + mptscsih_is_phys_disk(ioc, 0, SCpnt->device->id) == 0) { SCpnt->result = DID_NO_CONNECT << 16; done(SCpnt); return 0; } if (spi_dv_pending(scsi_target(SCpnt->device))) - ddvprintk(hd->ioc, scsi_print_command(SCpnt)); + ddvprintk(ioc, scsi_print_command(SCpnt)); return mptscsih_qcmd(SCpnt,done); } @@ -829,7 +838,7 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *starget, struct _CONFIG_PAGE_SCSI_DEVICE_1 *pass_pg1) { struct Scsi_Host *shost = dev_to_shost(&starget->dev); - struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata; + struct _MPT_SCSI_HOST *hd = shost_priv(shost); struct _MPT_ADAPTER *ioc = hd->ioc; struct _CONFIG_PAGE_SCSI_DEVICE_1 *pg1; dma_addr_t pg1_dma; @@ -847,7 +856,8 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *starget, pg1 = dma_alloc_coherent(&ioc->pcidev->dev, size, &pg1_dma, GFP_KERNEL); if (pg1 == NULL) { - starget_printk(KERN_ERR, starget, "dma_alloc_coherent for parameters failed\n"); + starget_printk(KERN_ERR, starget, MYIOC_s_FMT + "dma_alloc_coherent for parameters failed\n", ioc->name); return -EINVAL; } @@ -876,7 +886,8 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *starget, mptspi_print_write_nego(hd, starget, le32_to_cpu(pg1->RequestedParameters)); if (mpt_config(ioc, &cfg)) { - starget_printk(KERN_ERR, starget, "mpt_config failed\n"); + starget_printk(KERN_ERR, starget, MYIOC_s_FMT + "mpt_config failed\n", ioc->name); goto out_free; } err = 0; @@ -1015,7 +1026,7 @@ static void mptspi_write_qas(struct scsi_target *starget, int qas) { struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; struct Scsi_Host *shost = dev_to_shost(&starget->dev); - struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata; + struct _MPT_SCSI_HOST *hd = shost_priv(shost); VirtTarget *vtarget = starget->hostdata; u32 nego; @@ -1067,15 +1078,16 @@ static void mpt_work_wrapper(struct work_struct *work) struct work_queue_wrapper *wqw = container_of(work, struct work_queue_wrapper, work); struct _MPT_SCSI_HOST *hd = wqw->hd; - struct Scsi_Host *shost = hd->ioc->sh; + MPT_ADAPTER *ioc = hd->ioc; + struct Scsi_Host *shost = ioc->sh; struct scsi_device *sdev; int disk = wqw->disk; struct _CONFIG_PAGE_IOC_3 *pg3; kfree(wqw); - mpt_findImVolumes(hd->ioc); - pg3 = hd->ioc->raid_data.pIocPg3; + mpt_findImVolumes(ioc); + pg3 = ioc->raid_data.pIocPg3; if (!pg3) return; @@ -1092,24 +1104,25 @@ static void mpt_work_wrapper(struct work_struct *work) if(vtarget->id != disk) continue; - starget_printk(KERN_INFO, vtarget->starget, - "Integrated RAID requests DV of new device\n"); + starget_printk(KERN_INFO, vtarget->starget, MYIOC_s_FMT + "Integrated RAID requests DV of new device\n", ioc->name); mptspi_dv_device(hd, sdev); } - shost_printk(KERN_INFO, shost, - "Integrated RAID detects new device %d\n", disk); - scsi_scan_target(&hd->ioc->sh->shost_gendev, 1, disk, 0, 1); + shost_printk(KERN_INFO, shost, MYIOC_s_FMT + "Integrated RAID detects new device %d\n", ioc->name, disk); + scsi_scan_target(&ioc->sh->shost_gendev, 1, disk, 0, 1); } static void mpt_dv_raid(struct _MPT_SCSI_HOST *hd, int disk) { struct work_queue_wrapper *wqw = kmalloc(sizeof(*wqw), GFP_ATOMIC); + MPT_ADAPTER *ioc = hd->ioc; if (!wqw) { - shost_printk(KERN_ERR, hd->ioc->sh, - "Failed to act on RAID event for physical disk %d\n", - disk); + shost_printk(KERN_ERR, ioc->sh, MYIOC_s_FMT + "Failed to act on RAID event for physical disk %d\n", + ioc->name, disk); return; } INIT_WORK(&wqw->work, mpt_work_wrapper); @@ -1123,7 +1136,7 @@ static int mptspi_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) { u8 event = le32_to_cpu(pEvReply->Event) & 0xFF; - struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)ioc->sh->hostdata; + struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh); if (hd && event == MPI_EVENT_INTEGRATED_RAID) { int reason @@ -1190,6 +1203,8 @@ static struct spi_function_template mptspi_transport_functions = { static struct pci_device_id mptspi_pci_table[] = { { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_53C1030, PCI_ANY_ID, PCI_ANY_ID }, + { PCI_VENDOR_ID_ATTO, MPI_MANUFACTPAGE_DEVID_53C1030, + PCI_ANY_ID, PCI_ANY_ID }, { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_53C1035, PCI_ANY_ID, PCI_ANY_ID }, {0} /* Terminating entry */ @@ -1210,11 +1225,12 @@ mptspi_dv_renegotiate_work(struct work_struct *work) struct scsi_target *starget; struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; u32 nego; + MPT_ADAPTER *ioc = hd->ioc; kfree(wqw); if (hd->spi_pending) { - shost_for_each_device(sdev, hd->ioc->sh) { + shost_for_each_device(sdev, ioc->sh) { if (hd->spi_pending & (1 << sdev->id)) continue; starget = scsi_target(sdev); @@ -1225,7 +1241,7 @@ mptspi_dv_renegotiate_work(struct work_struct *work) mptspi_write_spi_device_pg1(starget, &pg1); } } else { - shost_for_each_device(sdev, hd->ioc->sh) + shost_for_each_device(sdev, ioc->sh) mptspi_dv_device(hd, sdev); } } @@ -1250,7 +1266,7 @@ mptspi_dv_renegotiate(struct _MPT_SCSI_HOST *hd) static int mptspi_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) { - struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)ioc->sh->hostdata; + struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh); int rc; rc = mptscsih_ioc_reset(ioc, reset_phase); @@ -1269,7 +1285,7 @@ static int mptspi_resume(struct pci_dev *pdev) { MPT_ADAPTER *ioc = pci_get_drvdata(pdev); - struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)ioc->sh->hostdata; + struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh); int rc; rc = mptscsih_resume(pdev); @@ -1416,7 +1432,7 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (numSGE < sh->sg_tablesize) { /* Reset this value */ - dprintk(ioc, printk(MYIOC_s_INFO_FMT + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Resetting sg_tablesize to %d from %d\n", ioc->name, numSGE, sh->sg_tablesize)); sh->sg_tablesize = numSGE; @@ -1424,20 +1440,21 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id) spin_unlock_irqrestore(&ioc->FreeQlock, flags); - hd = (MPT_SCSI_HOST *) sh->hostdata; + hd = shost_priv(sh); hd->ioc = ioc; /* SCSI needs scsi_cmnd lookup table! * (with size equal to req_depth*PtrSz!) */ - hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC); - if (!hd->ScsiLookup) { + ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC); + if (!ioc->ScsiLookup) { error = -ENOMEM; goto out_mptspi_probe; } + spin_lock_init(&ioc->scsi_lookup_lock); dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n", - ioc->name, hd->ScsiLookup)); + ioc->name, ioc->ScsiLookup)); /* Clear the TM flags */ @@ -1477,13 +1494,13 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* Some versions of the firmware don't support page 0; without * that we can't get the parameters */ - if (hd->ioc->spi_data.sdp0length != 0) + if (ioc->spi_data.sdp0length != 0) sh->transportt = mptspi_transport_template; error = scsi_add_host (sh, &ioc->pcidev->dev); if(error) { - dprintk(ioc, printk(KERN_ERR MYNAM - "scsi_add_host failed\n")); + dprintk(ioc, printk(MYIOC_s_ERR_FMT + "scsi_add_host failed\n", ioc->name)); goto out_mptspi_probe; } diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 6c0b2f0a51ab..81e068fa7ac5 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -517,7 +517,7 @@ static char *next_cmd(char **cmds) ****************************************************************************/ static struct platform_device *tpacpi_pdev; -static struct class_device *tpacpi_hwmon; +static struct device *tpacpi_hwmon; static struct input_dev *tpacpi_inputdev; @@ -945,15 +945,15 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */ KEY_UNKNOWN, /* 0x0D: FN+INSERT */ KEY_UNKNOWN, /* 0x0E: FN+DELETE */ - KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ + KEY_BRIGHTNESSUP, /* 0x0F: FN+HOME (brightness up) */ /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */ - KEY_RESERVED, /* 0x10: FN+END (brightness down) */ + KEY_BRIGHTNESSDOWN, /* 0x10: FN+END (brightness down) */ KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ - KEY_RESERVED, /* 0x14: VOLUME UP */ - KEY_RESERVED, /* 0x15: VOLUME DOWN */ - KEY_RESERVED, /* 0x16: MUTE */ + KEY_VOLUMEUP, /* 0x14: VOLUME UP */ + KEY_VOLUMEDOWN, /* 0x15: VOLUME DOWN */ + KEY_MUTE, /* 0x16: MUTE */ KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ /* (assignments unknown, please report if found) */ KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, @@ -974,9 +974,9 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ - KEY_RESERVED, /* 0x14: VOLUME UP */ - KEY_RESERVED, /* 0x15: VOLUME DOWN */ - KEY_RESERVED, /* 0x16: MUTE */ + KEY_VOLUMEUP, /* 0x14: VOLUME UP */ + KEY_VOLUMEDOWN, /* 0x15: VOLUME DOWN */ + KEY_MUTE, /* 0x16: MUTE */ KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ /* (assignments unknown, please report if found) */ KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index 082a1cbc16c0..acd5835ec889 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -171,7 +171,7 @@ static int parse_strtoul(const char *buf, unsigned long max, /* Device model */ static struct platform_device *tpacpi_pdev; -static struct class_device *tpacpi_hwmon; +static struct device *tpacpi_hwmon; static struct platform_driver tpacpi_pdriver; static struct input_dev *tpacpi_inputdev; static int tpacpi_create_driver_attributes(struct device_driver *drv); diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c index d195fb088f4a..8f77949f93dd 100644 --- a/drivers/misc/tifm_core.c +++ b/drivers/misc/tifm_core.c @@ -57,16 +57,11 @@ static int tifm_bus_match(struct device *dev, struct device_driver *drv) return 0; } -static int tifm_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int tifm_uevent(struct device *dev, struct kobj_uevent_env *env) { struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev); - int i = 0; - int length = 0; - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "TIFM_CARD_TYPE=%s", - tifm_media_type_name(sock->type, 1))) + if (add_uevent_var(env, "TIFM_CARD_TYPE=%s", tifm_media_type_name(sock->type, 1))) return -ENOMEM; return 0; diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 8d6f6014870f..b0c22cad9423 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -58,12 +58,11 @@ static int mmc_bus_match(struct device *dev, struct device_driver *drv) } static int -mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf, - int buf_size) +mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { struct mmc_card *card = dev_to_mmc_card(dev); const char *type; - int i = 0, length = 0; + int retval = 0; switch (card->type) { case MMC_TYPE_MMC: @@ -80,20 +79,14 @@ mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf, } if (type) { - if (add_uevent_var(envp, num_envp, &i, - buf, buf_size, &length, - "MMC_TYPE=%s", type)) - return -ENOMEM; + retval = add_uevent_var(env, "MMC_TYPE=%s", type); + if (retval) + return retval; } - if (add_uevent_var(envp, num_envp, &i, - buf, buf_size, &length, - "MMC_NAME=%s", mmc_card_name(card))) - return -ENOMEM; + retval = add_uevent_var(env, "MMC_NAME=%s", mmc_card_name(card)); - envp[i] = NULL; - - return 0; + return retval; } static int mmc_bus_probe(struct device *dev) diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 64fbc9759a30..c65d203a846d 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -143,7 +143,7 @@ void mmc_remove_host(struct mmc_host *host) device_del(&host->class_dev); - led_trigger_unregister(host->led); + led_trigger_unregister_simple(host->led); spin_lock(&mmc_host_lock); idr_remove(&mmc_host_idr, host->index); diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 0713a8c71e54..233d0f9b3c4b 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -96,30 +96,23 @@ static int sdio_bus_match(struct device *dev, struct device_driver *drv) } static int -sdio_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf, - int buf_size) +sdio_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { struct sdio_func *func = dev_to_sdio_func(dev); - int i = 0, length = 0; - if (add_uevent_var(envp, num_envp, &i, - buf, buf_size, &length, + if (add_uevent_var(env, "SDIO_CLASS=%02X", func->class)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buf, buf_size, &length, + if (add_uevent_var(env, "SDIO_ID=%04X:%04X", func->vendor, func->device)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buf, buf_size, &length, + if (add_uevent_var(env, "MODALIAS=sdio:c%02Xv%04Xd%04X", func->class, func->vendor, func->device)) return -ENOMEM; - envp[i] = NULL; - return 0; } diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index f30327bba6f6..254b194e7625 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -26,7 +26,7 @@ */ #include <linux/hrtimer.h> #include <linux/delay.h> -#include <linux/blkdev.h> +#include <linux/bio.h> #include <linux/dma-mapping.h> #include <linux/crc7.h> #include <linux/crc-itu-t.h> diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index fbec8cd55e38..8848e8ac705d 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -278,6 +278,14 @@ config SSFDC This enables read only access to SmartMedia formatted NAND flash. You can mount it with FAT file system. +config MTD_OOPS + tristate "Log panic/oops to an MTD buffer" + depends on MTD + help + This enables panic and oops messages to be logged to a circular + buffer in a flash partition where it can be read back at some + later point. + source "drivers/mtd/chips/Kconfig" source "drivers/mtd/maps/Kconfig" diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 6d958a4566ff..7f0b04b4caa7 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_NFTL) += nftl.o obj-$(CONFIG_INFTL) += inftl.o obj-$(CONFIG_RFD_FTL) += rfd_ftl.o obj-$(CONFIG_SSFDC) += ssfdc.o +obj-$(CONFIG_MTD_OOPS) += mtdoops.o nftl-objs := nftlcore.o nftlmount.o inftl-objs := inftlcore.o inftlmount.o diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 2f19fa78d24a..3aa3dca56ae6 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -526,7 +526,7 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd, struct cfi_pri_intelext *extp = cfi->cmdset_priv; /* - * Probing of multi-partition flash ships. + * Probing of multi-partition flash chips. * * To support multiple partitions when available, we simply arrange * for each of them to have their own flchip structure even if they @@ -653,7 +653,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr resettime: timeo = jiffies + HZ; retry: - if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING || mode == FL_OTP_WRITE)) { + if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING || mode == FL_OTP_WRITE || mode == FL_SHUTDOWN)) { /* * OK. We have possibility for contension on the write/erase * operations which are global to the real chip and not per @@ -798,6 +798,9 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr if (mode == FL_READY && chip->oldstate == FL_READY) return 0; + case FL_SHUTDOWN: + /* The machine is rebooting now,so no one can get chip anymore */ + return -EIO; default: sleep: set_current_state(TASK_UNINTERRUPTIBLE); @@ -1166,28 +1169,34 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; - unsigned long ofs; + unsigned long ofs, last_end = 0; int chipnum; int ret = 0; if (!map->virt || (from + len > mtd->size)) return -EINVAL; - *mtdbuf = (void *)map->virt + from; - *retlen = 0; - /* Now lock the chip(s) to POINT state */ /* ofs: offset within the first chip that the first read should start */ chipnum = (from >> cfi->chipshift); ofs = from - (chipnum << cfi->chipshift); + *mtdbuf = (void *)map->virt + cfi->chips[chipnum].start + ofs; + *retlen = 0; + while (len) { unsigned long thislen; if (chipnum >= cfi->numchips) break; + /* We cannot point across chips that are virtually disjoint */ + if (!last_end) + last_end = cfi->chips[chipnum].start; + else if (cfi->chips[chipnum].start != last_end) + break; + if ((len + ofs -1) >> cfi->chipshift) thislen = (1<<cfi->chipshift) - ofs; else @@ -1201,6 +1210,7 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si len -= thislen; ofs = 0; + last_end += 1 << cfi->chipshift; chipnum++; } return 0; @@ -1780,7 +1790,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, return ret; } -int cfi_intelext_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) +static int cfi_intelext_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) { unsigned long ofs, len; int ret; @@ -1930,7 +1940,7 @@ static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len) printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n", __FUNCTION__, ofs, len); cfi_varsize_frob(mtd, do_printlockstatus_oneblock, - ofs, len, 0); + ofs, len, NULL); #endif ret = cfi_varsize_frob(mtd, do_xxlock_oneblock, @@ -1940,7 +1950,7 @@ static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len) printk(KERN_DEBUG "%s: lock status after, ret=%d\n", __FUNCTION__, ret); cfi_varsize_frob(mtd, do_printlockstatus_oneblock, - ofs, len, 0); + ofs, len, NULL); #endif return ret; @@ -1954,7 +1964,7 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n", __FUNCTION__, ofs, len); cfi_varsize_frob(mtd, do_printlockstatus_oneblock, - ofs, len, 0); + ofs, len, NULL); #endif ret = cfi_varsize_frob(mtd, do_xxlock_oneblock, @@ -1964,7 +1974,7 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) printk(KERN_DEBUG "%s: lock status after, ret=%d\n", __FUNCTION__, ret); cfi_varsize_frob(mtd, do_printlockstatus_oneblock, - ofs, len, 0); + ofs, len, NULL); #endif return ret; @@ -2255,7 +2265,7 @@ static void cfi_intelext_save_locks(struct mtd_info *mtd) adr = region->offset + block * len; status = cfi_varsize_frob(mtd, - do_getlockstatus_oneblock, adr, len, 0); + do_getlockstatus_oneblock, adr, len, NULL); if (status) set_bit(block, region->lockmap); else @@ -2402,10 +2412,10 @@ static int cfi_intelext_reset(struct mtd_info *mtd) and switch to array mode so any bootloader in flash is accessible for soft reboot. */ spin_lock(chip->mutex); - ret = get_chip(map, chip, chip->start, FL_SYNCING); + ret = get_chip(map, chip, chip->start, FL_SHUTDOWN); if (!ret) { map_write(map, CMD(0xff), chip->start); - chip->state = FL_READY; + chip->state = FL_SHUTDOWN; } spin_unlock(chip->mutex); } diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 1f6445840461..389acc600f5e 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -1609,7 +1609,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, } -int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) +static int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) { unsigned long ofs, len; int ret; diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index 58e561e87699..a67b23b87fc0 100644 --- a/drivers/mtd/chips/jedec_probe.c +++ b/drivers/mtd/chips/jedec_probe.c @@ -17,7 +17,6 @@ #include <linux/errno.h> #include <linux/slab.h> #include <linux/interrupt.h> -#include <linux/init.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> @@ -70,6 +69,7 @@ /* Fujitsu */ #define MBM29F040C 0x00A4 +#define MBM29F800BA 0x2258 #define MBM29LV650UE 0x22D7 #define MBM29LV320TE 0x22F6 #define MBM29LV320BE 0x22F9 @@ -129,6 +129,7 @@ #define LH28F640BF 0x00b0 /* ST - www.st.com */ +#define M29F800AB 0x0058 #define M29W800DT 0x00D7 #define M29W800DB 0x005B #define M29W160DT 0x22C4 @@ -646,6 +647,23 @@ static const struct amd_flash_info jedec_table[] = { } }, { .mfr_id = MANUFACTURER_FUJITSU, + .dev_id = MBM29F800BA, + .name = "Fujitsu MBM29F800BA", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x04000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x08000,1), + ERASEINFO(0x10000,15), + } + }, { + .mfr_id = MANUFACTURER_FUJITSU, .dev_id = MBM29LV650UE, .name = "Fujitsu MBM29LV650UE", .uaddr = { @@ -1510,6 +1528,23 @@ static const struct amd_flash_info jedec_table[] = { ERASEINFO(0x1000,256) } + }, { + .mfr_id = MANUFACTURER_ST, + .dev_id = M29F800AB, + .name = "ST M29F800AB", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x04000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x08000,1), + ERASEINFO(0x10000,15), + } }, { .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */ .dev_id = M29W800DT, diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index ff642f8fbee7..811d56fd890f 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig @@ -60,21 +60,22 @@ config MTD_DATAFLASH Sometimes DataFlash chips are packaged inside MMC-format cards; at this writing, the MMC stack won't handle those. -config MTD_DATAFLASH26 - tristate "AT91RM9200 DataFlash AT26xxx" - depends on MTD && ARCH_AT91RM9200 && AT91_SPI - help - This enables access to the DataFlash chip (AT26xxx) on an - AT91RM9200-based board. - If you have such a board and such a DataFlash, say 'Y'. - config MTD_M25P80 - tristate "Support for M25 SPI Flash" + tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)" depends on SPI_MASTER && EXPERIMENTAL help - This enables access to ST M25P80 and similar SPI flash chips, - used for program and data storage. Set up your spi devices - with the right board-specific platform data. + This enables access to most modern SPI flash chips, used for + program and data storage. Series supported include Atmel AT26DF, + Spansion S25SL, SST 25VF, ST M25P, and Winbond W25X. Other chips + are supported as well. See the driver source for the current list, + or to add other chips. + + Note that the original DataFlash chips (AT45 series, not AT26DF), + need an entirely different driver. + + Set up your spi devices with the right board-specific platform data, + if you want to specify device partitioning or to use a device which + doesn't support the JEDEC ID instruction. config MTD_SLRAM tristate "Uncached system RAM" diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile index 8ab568b3f533..0f788d5c4bf8 100644 --- a/drivers/mtd/devices/Makefile +++ b/drivers/mtd/devices/Makefile @@ -16,5 +16,4 @@ obj-$(CONFIG_MTD_MTDRAM) += mtdram.o obj-$(CONFIG_MTD_LART) += lart.o obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o -obj-$(CONFIG_MTD_DATAFLASH26) += at91_dataflash26.o obj-$(CONFIG_MTD_M25P80) += m25p80.o diff --git a/drivers/mtd/devices/at91_dataflash26.c b/drivers/mtd/devices/at91_dataflash26.c deleted file mode 100644 index 64ce37f986fc..000000000000 --- a/drivers/mtd/devices/at91_dataflash26.c +++ /dev/null @@ -1,485 +0,0 @@ -/* - * Atmel DataFlash driver for Atmel AT91RM9200 (Thunder) - * This is a largely modified version of at91_dataflash.c that - * supports AT26xxx dataflash chips. The original driver supports - * AT45xxx chips. - * - * Note: This driver was only tested with an AT26F004. It should be - * easy to make it work with other AT26xxx dataflash devices, though. - * - * Copyright (C) 2007 Hans J. Koch <hjk@linutronix.de> - * original Copyright (C) SAN People (Pty) Ltd - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. -*/ - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/mtd/mtd.h> - -#include <asm/arch/at91_spi.h> - -#define DATAFLASH_MAX_DEVICES 4 /* max number of dataflash devices */ - -#define MANUFACTURER_ID_ATMEL 0x1F - -/* command codes */ - -#define AT26_OP_READ_STATUS 0x05 -#define AT26_OP_READ_DEV_ID 0x9F -#define AT26_OP_ERASE_PAGE_4K 0x20 -#define AT26_OP_READ_ARRAY_FAST 0x0B -#define AT26_OP_SEQUENTIAL_WRITE 0xAF -#define AT26_OP_WRITE_ENABLE 0x06 -#define AT26_OP_WRITE_DISABLE 0x04 -#define AT26_OP_SECTOR_PROTECT 0x36 -#define AT26_OP_SECTOR_UNPROTECT 0x39 - -/* status register bits */ - -#define AT26_STATUS_BUSY 0x01 -#define AT26_STATUS_WRITE_ENABLE 0x02 - -struct dataflash_local -{ - int spi; /* SPI chip-select number */ - unsigned int page_size; /* number of bytes per page */ -}; - - -/* Detected DataFlash devices */ -static struct mtd_info* mtd_devices[DATAFLASH_MAX_DEVICES]; -static int nr_devices = 0; - -/* Allocate a single SPI transfer descriptor. We're assuming that if multiple - SPI transfers occur at the same time, spi_access_bus() will serialize them. - If this is not valid, then either (i) each dataflash 'priv' structure - needs it's own transfer descriptor, (ii) we lock this one, or (iii) use - another mechanism. */ -static struct spi_transfer_list* spi_transfer_desc; - -/* - * Perform a SPI transfer to access the DataFlash device. - */ -static int do_spi_transfer(int nr, char* tx, int tx_len, char* rx, int rx_len, - char* txnext, int txnext_len, char* rxnext, int rxnext_len) -{ - struct spi_transfer_list* list = spi_transfer_desc; - - list->tx[0] = tx; list->txlen[0] = tx_len; - list->rx[0] = rx; list->rxlen[0] = rx_len; - - list->tx[1] = txnext; list->txlen[1] = txnext_len; - list->rx[1] = rxnext; list->rxlen[1] = rxnext_len; - - list->nr_transfers = nr; - /* Note: spi_transfer() always returns 0, there are no error checks */ - return spi_transfer(list); -} - -/* - * Return the status of the DataFlash device. - */ -static unsigned char at91_dataflash26_status(void) -{ - unsigned char command[2]; - - command[0] = AT26_OP_READ_STATUS; - command[1] = 0; - - do_spi_transfer(1, command, 2, command, 2, NULL, 0, NULL, 0); - - return command[1]; -} - -/* - * Poll the DataFlash device until it is READY. - */ -static unsigned char at91_dataflash26_waitready(void) -{ - unsigned char status; - - while (1) { - status = at91_dataflash26_status(); - if (!(status & AT26_STATUS_BUSY)) - return status; - } -} - -/* - * Enable/disable write access - */ - static void at91_dataflash26_write_enable(int enable) -{ - unsigned char cmd[2]; - - DEBUG(MTD_DEBUG_LEVEL3, "write_enable: enable=%i\n", enable); - - if (enable) - cmd[0] = AT26_OP_WRITE_ENABLE; - else - cmd[0] = AT26_OP_WRITE_DISABLE; - cmd[1] = 0; - - do_spi_transfer(1, cmd, 2, cmd, 2, NULL, 0, NULL, 0); -} - -/* - * Protect/unprotect sector - */ - static void at91_dataflash26_sector_protect(loff_t addr, int protect) -{ - unsigned char cmd[4]; - - DEBUG(MTD_DEBUG_LEVEL3, "sector_protect: addr=0x%06x prot=%d\n", - addr, protect); - - if (protect) - cmd[0] = AT26_OP_SECTOR_PROTECT; - else - cmd[0] = AT26_OP_SECTOR_UNPROTECT; - cmd[1] = (addr & 0x00FF0000) >> 16; - cmd[2] = (addr & 0x0000FF00) >> 8; - cmd[3] = (addr & 0x000000FF); - - do_spi_transfer(1, cmd, 4, cmd, 4, NULL, 0, NULL, 0); -} - -/* - * Erase blocks of flash. - */ -static int at91_dataflash26_erase(struct mtd_info *mtd, - struct erase_info *instr) -{ - struct dataflash_local *priv = (struct dataflash_local *) mtd->priv; - unsigned char cmd[4]; - - DEBUG(MTD_DEBUG_LEVEL1, "dataflash_erase: addr=0x%06x len=%i\n", - instr->addr, instr->len); - - /* Sanity checks */ - if (priv->page_size != 4096) - return -EINVAL; /* Can't handle other sizes at the moment */ - - if ( ((instr->len % mtd->erasesize) != 0) - || ((instr->len % priv->page_size) != 0) - || ((instr->addr % priv->page_size) != 0) - || ((instr->addr + instr->len) > mtd->size)) - return -EINVAL; - - spi_access_bus(priv->spi); - - while (instr->len > 0) { - at91_dataflash26_write_enable(1); - at91_dataflash26_sector_protect(instr->addr, 0); - at91_dataflash26_write_enable(1); - cmd[0] = AT26_OP_ERASE_PAGE_4K; - cmd[1] = (instr->addr & 0x00FF0000) >> 16; - cmd[2] = (instr->addr & 0x0000FF00) >> 8; - cmd[3] = (instr->addr & 0x000000FF); - - DEBUG(MTD_DEBUG_LEVEL3, "ERASE: (0x%02x) 0x%02x 0x%02x" - "0x%02x\n", - cmd[0], cmd[1], cmd[2], cmd[3]); - - do_spi_transfer(1, cmd, 4, cmd, 4, NULL, 0, NULL, 0); - at91_dataflash26_waitready(); - - instr->addr += priv->page_size; /* next page */ - instr->len -= priv->page_size; - } - - at91_dataflash26_write_enable(0); - spi_release_bus(priv->spi); - - /* Inform MTD subsystem that erase is complete */ - instr->state = MTD_ERASE_DONE; - if (instr->callback) - instr->callback(instr); - - return 0; -} - -/* - * Read from the DataFlash device. - * from : Start offset in flash device - * len : Number of bytes to read - * retlen : Number of bytes actually read - * buf : Buffer that will receive data - */ -static int at91_dataflash26_read(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf) -{ - struct dataflash_local *priv = (struct dataflash_local *) mtd->priv; - unsigned char cmd[5]; - - DEBUG(MTD_DEBUG_LEVEL1, "dataflash_read: %lli .. %lli\n", - from, from+len); - - *retlen = 0; - - /* Sanity checks */ - if (!len) - return 0; - if (from + len > mtd->size) - return -EINVAL; - - cmd[0] = AT26_OP_READ_ARRAY_FAST; - cmd[1] = (from & 0x00FF0000) >> 16; - cmd[2] = (from & 0x0000FF00) >> 8; - cmd[3] = (from & 0x000000FF); - /* cmd[4] is a "Don't care" byte */ - - DEBUG(MTD_DEBUG_LEVEL3, "READ: (0x%02x) 0x%02x 0x%02x 0x%02x\n", - cmd[0], cmd[1], cmd[2], cmd[3]); - - spi_access_bus(priv->spi); - do_spi_transfer(2, cmd, 5, cmd, 5, buf, len, buf, len); - spi_release_bus(priv->spi); - - *retlen = len; - return 0; -} - -/* - * Write to the DataFlash device. - * to : Start offset in flash device - * len : Number of bytes to write - * retlen : Number of bytes actually written - * buf : Buffer containing the data - */ -static int at91_dataflash26_write(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) -{ - struct dataflash_local *priv = (struct dataflash_local *) mtd->priv; - unsigned int addr, buf_index = 0; - int ret = -EIO, sector, last_sector; - unsigned char status, cmd[5]; - - DEBUG(MTD_DEBUG_LEVEL1, "dataflash_write: %lli .. %lli\n", to, to+len); - - *retlen = 0; - - /* Sanity checks */ - if (!len) - return 0; - if (to + len > mtd->size) - return -EINVAL; - - spi_access_bus(priv->spi); - - addr = to; - last_sector = -1; - - while (buf_index < len) { - sector = addr / priv->page_size; - /* Write first byte if a new sector begins */ - if (sector != last_sector) { - at91_dataflash26_write_enable(1); - at91_dataflash26_sector_protect(addr, 0); - at91_dataflash26_write_enable(1); - - /* Program first byte of a new sector */ - cmd[0] = AT26_OP_SEQUENTIAL_WRITE; - cmd[1] = (addr & 0x00FF0000) >> 16; - cmd[2] = (addr & 0x0000FF00) >> 8; - cmd[3] = (addr & 0x000000FF); - cmd[4] = buf[buf_index++]; - do_spi_transfer(1, cmd, 5, cmd, 5, NULL, 0, NULL, 0); - status = at91_dataflash26_waitready(); - addr++; - /* On write errors, the chip resets the write enable - flag. This also happens after the last byte of a - sector is successfully programmed. */ - if ( ( !(status & AT26_STATUS_WRITE_ENABLE)) - && ((addr % priv->page_size) != 0) ) { - DEBUG(MTD_DEBUG_LEVEL1, - "write error1: addr=0x%06x, " - "status=0x%02x\n", addr, status); - goto write_err; - } - (*retlen)++; - last_sector = sector; - } - - /* Write subsequent bytes in the same sector */ - cmd[0] = AT26_OP_SEQUENTIAL_WRITE; - cmd[1] = buf[buf_index++]; - do_spi_transfer(1, cmd, 2, cmd, 2, NULL, 0, NULL, 0); - status = at91_dataflash26_waitready(); - addr++; - - if ( ( !(status & AT26_STATUS_WRITE_ENABLE)) - && ((addr % priv->page_size) != 0) ) { - DEBUG(MTD_DEBUG_LEVEL1, "write error2: addr=0x%06x, " - "status=0x%02x\n", addr, status); - goto write_err; - } - - (*retlen)++; - } - - ret = 0; - at91_dataflash26_write_enable(0); -write_err: - spi_release_bus(priv->spi); - return ret; -} - -/* - * Initialize and register DataFlash device with MTD subsystem. - */ -static int __init add_dataflash(int channel, char *name, int nr_pages, - int pagesize) -{ - struct mtd_info *device; - struct dataflash_local *priv; - - if (nr_devices >= DATAFLASH_MAX_DEVICES) { - printk(KERN_ERR "at91_dataflash26: Too many devices " - "detected\n"); - return 0; - } - - device = kzalloc(sizeof(struct mtd_info) + strlen(name) + 8, - GFP_KERNEL); - if (!device) - return -ENOMEM; - - device->name = (char *)&device[1]; - sprintf(device->name, "%s.spi%d", name, channel); - device->size = nr_pages * pagesize; - device->erasesize = pagesize; - device->owner = THIS_MODULE; - device->type = MTD_DATAFLASH; - device->flags = MTD_CAP_NORFLASH; - device->erase = at91_dataflash26_erase; - device->read = at91_dataflash26_read; - device->write = at91_dataflash26_write; - - priv = (struct dataflash_local *)kzalloc(sizeof(struct dataflash_local), - GFP_KERNEL); - if (!priv) { - kfree(device); - return -ENOMEM; - } - - priv->spi = channel; - priv->page_size = pagesize; - device->priv = priv; - - mtd_devices[nr_devices] = device; - nr_devices++; - printk(KERN_INFO "at91_dataflash26: %s detected [spi%i] (%i bytes)\n", - name, channel, device->size); - - return add_mtd_device(device); -} - -/* - * Detect and initialize DataFlash device connected to specified SPI channel. - * - */ - -struct dataflash26_types { - unsigned char id0; - unsigned char id1; - char *name; - int pagesize; - int nr_pages; -}; - -struct dataflash26_types df26_types[] = { - { - .id0 = 0x04, - .id1 = 0x00, - .name = "AT26F004", - .pagesize = 4096, - .nr_pages = 128, - }, - { - .id0 = 0x45, - .id1 = 0x01, - .name = "AT26DF081A", /* Not tested ! */ - .pagesize = 4096, - .nr_pages = 256, - }, -}; - -static int __init at91_dataflash26_detect(int channel) -{ - unsigned char status, cmd[5]; - int i; - - spi_access_bus(channel); - status = at91_dataflash26_status(); - - if (status == 0 || status == 0xff) { - printk(KERN_ERR "at91_dataflash26_detect: status error %d\n", - status); - spi_release_bus(channel); - return -ENODEV; - } - - cmd[0] = AT26_OP_READ_DEV_ID; - do_spi_transfer(1, cmd, 5, cmd, 5, NULL, 0, NULL, 0); - spi_release_bus(channel); - - if (cmd[1] != MANUFACTURER_ID_ATMEL) - return -ENODEV; - - for (i = 0; i < ARRAY_SIZE(df26_types); i++) { - if ( cmd[2] == df26_types[i].id0 - && cmd[3] == df26_types[i].id1) - return add_dataflash(channel, - df26_types[i].name, - df26_types[i].nr_pages, - df26_types[i].pagesize); - } - - printk(KERN_ERR "at91_dataflash26_detect: Unsupported device " - "(0x%02x/0x%02x)\n", cmd[2], cmd[3]); - return -ENODEV; -} - -static int __init at91_dataflash26_init(void) -{ - spi_transfer_desc = kmalloc(sizeof(struct spi_transfer_list), - GFP_KERNEL); - if (!spi_transfer_desc) - return -ENOMEM; - - /* DataFlash (SPI chip select 0) */ - at91_dataflash26_detect(0); - -#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD - /* DataFlash card (SPI chip select 3) */ - at91_dataflash26_detect(3); -#endif - return 0; -} - -static void __exit at91_dataflash26_exit(void) -{ - int i; - - for (i = 0; i < DATAFLASH_MAX_DEVICES; i++) { - if (mtd_devices[i]) { - del_mtd_device(mtd_devices[i]); - kfree(mtd_devices[i]->priv); - kfree(mtd_devices[i]); - } - } - nr_devices = 0; - kfree(spi_transfer_desc); -} - -module_init(at91_dataflash26_init); -module_exit(at91_dataflash26_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Hans J. Koch"); -MODULE_DESCRIPTION("DataFlash AT26xxx driver for Atmel AT91RM9200"); diff --git a/drivers/mtd/devices/docprobe.c b/drivers/mtd/devices/docprobe.c index 54aa75907640..d8cc94ec4e50 100644 --- a/drivers/mtd/devices/docprobe.c +++ b/drivers/mtd/devices/docprobe.c @@ -81,9 +81,7 @@ static unsigned long __initdata doc_locations[] = { #endif /* CONFIG_MTD_DOCPROBE_HIGH */ #elif defined(__PPC__) 0xe4000000, -#elif defined(CONFIG_MOMENCO_OCELOT_G) - 0xff000000, -##else +#else #warning Unknown architecture for DiskOnChip. No default probe locations defined #endif 0xffffffff }; diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 78c2511ae9e0..98df5bcc02f3 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -1,5 +1,5 @@ /* - * MTD SPI driver for ST M25Pxx flash chips + * MTD SPI driver for ST M25Pxx (and similar) serial flash chips * * Author: Mike Lavender, mike@steroidmicros.com * @@ -19,33 +19,32 @@ #include <linux/module.h> #include <linux/device.h> #include <linux/interrupt.h> -#include <linux/interrupt.h> +#include <linux/mutex.h> + #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> + #include <linux/spi/spi.h> #include <linux/spi/flash.h> -#include <asm/semaphore.h> - - -/* NOTE: AT 25F and SST 25LF series are very similar, - * but commands for sector erase and chip id differ... - */ #define FLASH_PAGESIZE 256 /* Flash opcodes. */ -#define OPCODE_WREN 6 /* Write enable */ -#define OPCODE_RDSR 5 /* Read status register */ -#define OPCODE_READ 3 /* Read data bytes */ -#define OPCODE_PP 2 /* Page program */ -#define OPCODE_SE 0xd8 /* Sector erase */ -#define OPCODE_RES 0xab /* Read Electronic Signature */ +#define OPCODE_WREN 0x06 /* Write enable */ +#define OPCODE_RDSR 0x05 /* Read status register */ +#define OPCODE_READ 0x03 /* Read data bytes (low frequency) */ +#define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */ +#define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */ +#define OPCODE_BE_4K 0x20 /* Erase 4KiB block */ +#define OPCODE_BE_32K 0x52 /* Erase 32KiB block */ +#define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */ #define OPCODE_RDID 0x9f /* Read JEDEC ID */ /* Status Register bits. */ #define SR_WIP 1 /* Write in progress */ #define SR_WEL 2 /* Write enable latch */ +/* meaning of other SR_* bits may differ between vendors */ #define SR_BP0 4 /* Block protect 0 */ #define SR_BP1 8 /* Block protect 1 */ #define SR_BP2 0x10 /* Block protect 2 */ @@ -65,9 +64,10 @@ struct m25p { struct spi_device *spi; - struct semaphore lock; + struct mutex lock; struct mtd_info mtd; - unsigned partitioned; + unsigned partitioned:1; + u8 erase_opcode; u8 command[4]; }; @@ -150,8 +150,9 @@ static int wait_till_ready(struct m25p *flash) */ static int erase_sector(struct m25p *flash, u32 offset) { - DEBUG(MTD_DEBUG_LEVEL3, "%s: %s at 0x%08x\n", flash->spi->dev.bus_id, - __FUNCTION__, offset); + DEBUG(MTD_DEBUG_LEVEL3, "%s: %s %dKiB at 0x%08x\n", + flash->spi->dev.bus_id, __FUNCTION__, + flash->mtd.erasesize / 1024, offset); /* Wait until finished previous write command. */ if (wait_till_ready(flash)) @@ -161,7 +162,7 @@ static int erase_sector(struct m25p *flash, u32 offset) write_enable(flash); /* Set up command buffer. */ - flash->command[0] = OPCODE_SE; + flash->command[0] = flash->erase_opcode; flash->command[1] = offset >> 16; flash->command[2] = offset >> 8; flash->command[3] = offset; @@ -201,13 +202,17 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr) addr = instr->addr; len = instr->len; - down(&flash->lock); + mutex_lock(&flash->lock); + + /* REVISIT in some cases we could speed up erasing large regions + * by using OPCODE_SE instead of OPCODE_BE_4K + */ /* now erase those sectors */ while (len) { if (erase_sector(flash, addr)) { instr->state = MTD_ERASE_FAILED; - up(&flash->lock); + mutex_unlock(&flash->lock); return -EIO; } @@ -215,7 +220,7 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr) len -= mtd->erasesize; } - up(&flash->lock); + mutex_unlock(&flash->lock); instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); @@ -260,16 +265,19 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, if (retlen) *retlen = 0; - down(&flash->lock); + mutex_lock(&flash->lock); /* Wait till previous write/erase is done. */ if (wait_till_ready(flash)) { /* REVISIT status return?? */ - up(&flash->lock); + mutex_unlock(&flash->lock); return 1; } - /* NOTE: OPCODE_FAST_READ (if available) is faster... */ + /* FIXME switch to OPCODE_FAST_READ. It's required for higher + * clocks; and at this writing, every chip this driver handles + * supports that opcode. + */ /* Set up the write data buffer. */ flash->command[0] = OPCODE_READ; @@ -281,7 +289,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, *retlen = m.actual_length - sizeof(flash->command); - up(&flash->lock); + mutex_unlock(&flash->lock); return 0; } @@ -323,7 +331,7 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len, t[1].tx_buf = buf; spi_message_add_tail(&t[1], &m); - down(&flash->lock); + mutex_lock(&flash->lock); /* Wait until finished previous write command. */ if (wait_till_ready(flash)) @@ -381,10 +389,10 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len, if (retlen) *retlen += m.actual_length - sizeof(flash->command); - } - } + } + } - up(&flash->lock); + mutex_unlock(&flash->lock); return 0; } @@ -398,24 +406,118 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len, struct flash_info { char *name; - u8 id; - u16 jedec_id; + + /* JEDEC id zero means "no ID" (most older chips); otherwise it has + * a high byte of zero plus three data bytes: the manufacturer id, + * then a two byte device id. + */ + u32 jedec_id; + + /* The size listed here is what works with OPCODE_SE, which isn't + * necessarily called a "sector" by the vendor. + */ unsigned sector_size; - unsigned n_sectors; + u16 n_sectors; + + u16 flags; +#define SECT_4K 0x01 /* OPCODE_BE_4K works uniformly */ }; + +/* NOTE: double check command sets and memory organization when you add + * more flash chips. This current list focusses on newer chips, which + * have been converging on command sets which including JEDEC ID. + */ static struct flash_info __devinitdata m25p_data [] = { - /* REVISIT: fill in JEDEC ids, for parts that have them */ - { "m25p05", 0x05, 0x2010, 32 * 1024, 2 }, - { "m25p10", 0x10, 0x2011, 32 * 1024, 4 }, - { "m25p20", 0x11, 0x2012, 64 * 1024, 4 }, - { "m25p40", 0x12, 0x2013, 64 * 1024, 8 }, - { "m25p80", 0x13, 0x0000, 64 * 1024, 16 }, - { "m25p16", 0x14, 0x2015, 64 * 1024, 32 }, - { "m25p32", 0x15, 0x2016, 64 * 1024, 64 }, - { "m25p64", 0x16, 0x2017, 64 * 1024, 128 }, + + /* Atmel -- some are (confusingly) marketed as "DataFlash" */ + { "at25fs010", 0x1f6601, 32 * 1024, 4, SECT_4K, }, + { "at25fs040", 0x1f6604, 64 * 1024, 8, SECT_4K, }, + + { "at25df041a", 0x1f4401, 64 * 1024, 8, SECT_4K, }, + + { "at26f004", 0x1f0400, 64 * 1024, 8, SECT_4K, }, + { "at26df081a", 0x1f4501, 64 * 1024, 16, SECT_4K, }, + { "at26df161a", 0x1f4601, 64 * 1024, 32, SECT_4K, }, + { "at26df321", 0x1f4701, 64 * 1024, 64, SECT_4K, }, + + /* Spansion -- single (large) sector size only, at least + * for the chips listed here (without boot sectors). + */ + { "s25sl004a", 0x010212, 64 * 1024, 8, }, + { "s25sl008a", 0x010213, 64 * 1024, 16, }, + { "s25sl016a", 0x010214, 64 * 1024, 32, }, + { "s25sl032a", 0x010215, 64 * 1024, 64, }, + { "s25sl064a", 0x010216, 64 * 1024, 128, }, + + /* SST -- large erase sizes are "overlays", "sectors" are 4K */ + { "sst25vf040b", 0xbf258d, 64 * 1024, 8, SECT_4K, }, + { "sst25vf080b", 0xbf258e, 64 * 1024, 16, SECT_4K, }, + { "sst25vf016b", 0xbf2541, 64 * 1024, 32, SECT_4K, }, + { "sst25vf032b", 0xbf254a, 64 * 1024, 64, SECT_4K, }, + + /* ST Microelectronics -- newer production may have feature updates */ + { "m25p05", 0x202010, 32 * 1024, 2, }, + { "m25p10", 0x202011, 32 * 1024, 4, }, + { "m25p20", 0x202012, 64 * 1024, 4, }, + { "m25p40", 0x202013, 64 * 1024, 8, }, + { "m25p80", 0, 64 * 1024, 16, }, + { "m25p16", 0x202015, 64 * 1024, 32, }, + { "m25p32", 0x202016, 64 * 1024, 64, }, + { "m25p64", 0x202017, 64 * 1024, 128, }, + { "m25p128", 0x202018, 256 * 1024, 64, }, + + { "m45pe80", 0x204014, 64 * 1024, 16, }, + { "m45pe16", 0x204015, 64 * 1024, 32, }, + + { "m25pe80", 0x208014, 64 * 1024, 16, }, + { "m25pe16", 0x208015, 64 * 1024, 32, SECT_4K, }, + + /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ + { "w25x10", 0xef3011, 64 * 1024, 2, SECT_4K, }, + { "w25x20", 0xef3012, 64 * 1024, 4, SECT_4K, }, + { "w25x40", 0xef3013, 64 * 1024, 8, SECT_4K, }, + { "w25x80", 0xef3014, 64 * 1024, 16, SECT_4K, }, + { "w25x16", 0xef3015, 64 * 1024, 32, SECT_4K, }, + { "w25x32", 0xef3016, 64 * 1024, 64, SECT_4K, }, + { "w25x64", 0xef3017, 64 * 1024, 128, SECT_4K, }, }; +static struct flash_info *__devinit jedec_probe(struct spi_device *spi) +{ + int tmp; + u8 code = OPCODE_RDID; + u8 id[3]; + u32 jedec; + struct flash_info *info; + + /* JEDEC also defines an optional "extended device information" + * string for after vendor-specific data, after the three bytes + * we use here. Supporting some chips might require using it. + */ + tmp = spi_write_then_read(spi, &code, 1, id, 3); + if (tmp < 0) { + DEBUG(MTD_DEBUG_LEVEL0, "%s: error %d reading JEDEC ID\n", + spi->dev.bus_id, tmp); + return NULL; + } + jedec = id[0]; + jedec = jedec << 8; + jedec |= id[1]; + jedec = jedec << 8; + jedec |= id[2]; + + for (tmp = 0, info = m25p_data; + tmp < ARRAY_SIZE(m25p_data); + tmp++, info++) { + if (info->jedec_id == jedec) + return info; + } + dev_err(&spi->dev, "unrecognized JEDEC id %06x\n", jedec); + return NULL; +} + + /* * board specific setup should have ensured the SPI clock used here * matches what the READ command supports, at least until this driver @@ -429,37 +531,51 @@ static int __devinit m25p_probe(struct spi_device *spi) unsigned i; /* Platform data helps sort out which chip type we have, as - * well as how this board partitions it. + * well as how this board partitions it. If we don't have + * a chip ID, try the JEDEC id commands; they'll work for most + * newer chips, even if we don't recognize the particular chip. */ data = spi->dev.platform_data; - if (!data || !data->type) { - /* FIXME some chips can identify themselves with RES - * or JEDEC get-id commands. Try them ... - */ - DEBUG(MTD_DEBUG_LEVEL1, "%s: no chip id\n", - spi->dev.bus_id); - return -ENODEV; - } + if (data && data->type) { + for (i = 0, info = m25p_data; + i < ARRAY_SIZE(m25p_data); + i++, info++) { + if (strcmp(data->type, info->name) == 0) + break; + } - for (i = 0, info = m25p_data; i < ARRAY_SIZE(m25p_data); i++, info++) { - if (strcmp(data->type, info->name) == 0) - break; - } - if (i == ARRAY_SIZE(m25p_data)) { - DEBUG(MTD_DEBUG_LEVEL1, "%s: unrecognized id %s\n", - spi->dev.bus_id, data->type); + /* unrecognized chip? */ + if (i == ARRAY_SIZE(m25p_data)) { + DEBUG(MTD_DEBUG_LEVEL0, "%s: unrecognized id %s\n", + spi->dev.bus_id, data->type); + info = NULL; + + /* recognized; is that chip really what's there? */ + } else if (info->jedec_id) { + struct flash_info *chip = jedec_probe(spi); + + if (!chip || chip != info) { + dev_warn(&spi->dev, "found %s, expected %s\n", + chip ? chip->name : "UNKNOWN", + info->name); + info = NULL; + } + } + } else + info = jedec_probe(spi); + + if (!info) return -ENODEV; - } flash = kzalloc(sizeof *flash, GFP_KERNEL); if (!flash) return -ENOMEM; flash->spi = spi; - init_MUTEX(&flash->lock); + mutex_init(&flash->lock); dev_set_drvdata(&spi->dev, flash); - if (data->name) + if (data && data->name) flash->mtd.name = data->name; else flash->mtd.name = spi->dev.bus_id; @@ -468,17 +584,25 @@ static int __devinit m25p_probe(struct spi_device *spi) flash->mtd.writesize = 1; flash->mtd.flags = MTD_CAP_NORFLASH; flash->mtd.size = info->sector_size * info->n_sectors; - flash->mtd.erasesize = info->sector_size; flash->mtd.erase = m25p80_erase; flash->mtd.read = m25p80_read; flash->mtd.write = m25p80_write; + /* prefer "small sector" erase if possible */ + if (info->flags & SECT_4K) { + flash->erase_opcode = OPCODE_BE_4K; + flash->mtd.erasesize = 4096; + } else { + flash->erase_opcode = OPCODE_SE; + flash->mtd.erasesize = info->sector_size; + } + dev_info(&spi->dev, "%s (%d Kbytes)\n", info->name, flash->mtd.size / 1024); DEBUG(MTD_DEBUG_LEVEL2, - "mtd .name = %s, .size = 0x%.8x (%uM) " - ".erasesize = 0x%.8x (%uK) .numeraseregions = %d\n", + "mtd .name = %s, .size = 0x%.8x (%uMiB) " + ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n", flash->mtd.name, flash->mtd.size, flash->mtd.size / (1024*1024), flash->mtd.erasesize, flash->mtd.erasesize / 1024, @@ -488,7 +612,7 @@ static int __devinit m25p_probe(struct spi_device *spi) for (i = 0; i < flash->mtd.numeraseregions; i++) DEBUG(MTD_DEBUG_LEVEL2, "mtd.eraseregions[%d] = { .offset = 0x%.8x, " - ".erasesize = 0x%.8x (%uK), " + ".erasesize = 0x%.8x (%uKiB), " ".numblocks = %d }\n", i, flash->mtd.eraseregions[i].offset, flash->mtd.eraseregions[i].erasesize, @@ -516,14 +640,14 @@ static int __devinit m25p_probe(struct spi_device *spi) } if (nr_parts > 0) { - for (i = 0; i < data->nr_parts; i++) { + for (i = 0; i < nr_parts; i++) { DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = " "{.name = %s, .offset = 0x%.8x, " - ".size = 0x%.8x (%uK) }\n", - i, data->parts[i].name, - data->parts[i].offset, - data->parts[i].size, - data->parts[i].size / 1024); + ".size = 0x%.8x (%uKiB) }\n", + i, parts[i].name, + parts[i].offset, + parts[i].size, + parts[i].size / 1024); } flash->partitioned = 1; return add_mtd_partitions(&flash->mtd, parts, nr_parts); @@ -560,6 +684,11 @@ static struct spi_driver m25p80_driver = { }, .probe = m25p_probe, .remove = __devexit_p(m25p_remove), + + /* REVISIT: many of these chips have deep power-down modes, which + * should clearly be entered on suspend() to minimize power use. + * And also when they're otherwise idle... + */ }; diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index a987e917f4e0..a5ed6d232c35 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -14,6 +14,7 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/device.h> +#include <linux/mutex.h> #include <linux/spi/spi.h> #include <linux/spi/flash.h> @@ -89,7 +90,7 @@ struct dataflash { unsigned short page_offset; /* offset in flash address */ unsigned int page_size; /* of bytes per page */ - struct semaphore lock; + struct mutex lock; struct spi_device *spi; struct mtd_info mtd; @@ -167,7 +168,7 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr) x.len = 4; spi_message_add_tail(&x, &msg); - down(&priv->lock); + mutex_lock(&priv->lock); while (instr->len > 0) { unsigned int pageaddr; int status; @@ -210,7 +211,7 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr) instr->len -= priv->page_size; } } - up(&priv->lock); + mutex_unlock(&priv->lock); /* Inform MTD subsystem that erase is complete */ instr->state = MTD_ERASE_DONE; @@ -266,7 +267,7 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len, x[1].len = len; spi_message_add_tail(&x[1], &msg); - down(&priv->lock); + mutex_lock(&priv->lock); /* Continuous read, max clock = f(car) which may be less than * the peak rate available. Some chips support commands with @@ -279,7 +280,7 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len, /* plus 4 "don't care" bytes */ status = spi_sync(priv->spi, &msg); - up(&priv->lock); + mutex_unlock(&priv->lock); if (status >= 0) { *retlen = msg.actual_length - 8; @@ -336,7 +337,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, else writelen = len; - down(&priv->lock); + mutex_lock(&priv->lock); while (remaining > 0) { DEBUG(MTD_DEBUG_LEVEL3, "write @ %i:%i len=%i\n", pageaddr, offset, writelen); @@ -441,7 +442,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, else writelen = remaining; } - up(&priv->lock); + mutex_unlock(&priv->lock); return status; } @@ -463,7 +464,7 @@ add_dataflash(struct spi_device *spi, char *name, if (!priv) return -ENOMEM; - init_MUTEX(&priv->lock); + mutex_init(&priv->lock); priv->spi = spi; priv->page_size = pagesize; priv->page_offset = pageoffset; diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c index e8f686f7a357..7060a0895ce2 100644 --- a/drivers/mtd/devices/pmc551.c +++ b/drivers/mtd/devices/pmc551.c @@ -30,8 +30,8 @@ * * Notes: * Due to what I assume is more buggy SROM, the 64M PMC551 I - * have available claims that all 4 of it's DRAM banks have 64M - * of ram configured (making a grand total of 256M onboard). + * have available claims that all 4 of its DRAM banks have 64MiB + * of ram configured (making a grand total of 256MiB onboard). * This is slightly annoying since the BAR0 size reflects the * aperture size, not the dram size, and the V370PDC supplies no * other method for memory size discovery. This problem is @@ -70,7 +70,7 @@ * made the memory unusable, added a fix to code to touch up * the DRAM some. * - * Bugs/FIXME's: + * Bugs/FIXMEs: * * MUST fix the init function to not spin on a register * waiting for it to set .. this does not safely handle busted * devices that never reset the register correctly which will @@ -562,10 +562,10 @@ static u32 fixup_pmc551(struct pci_dev *dev) /* * Some screen fun */ - printk(KERN_DEBUG "pmc551: %d%c (0x%x) of %sprefetchable memory at " + printk(KERN_DEBUG "pmc551: %d%sB (0x%x) of %sprefetchable memory at " "0x%llx\n", (size < 1024) ? size : (size < 1048576) ? size >> 10 : size >> 20, - (size < 1024) ? 'B' : (size < 1048576) ? 'K' : 'M', size, + (size < 1024) ? "" : (size < 1048576) ? "Ki" : "Mi", size, ((dcmd & (0x1 << 3)) == 0) ? "non-" : "", (unsigned long long)pci_resource_start(dev, 0)); @@ -649,14 +649,10 @@ MODULE_DESCRIPTION(PMC551_VERSION); * Stuff these outside the ifdef so as to not bust compiled in driver support */ static int msize = 0; -#if defined(CONFIG_MTD_PMC551_APERTURE_SIZE) -static int asize = CONFIG_MTD_PMC551_APERTURE_SIZE; -#else static int asize = 0; -#endif module_param(msize, int, 0); -MODULE_PARM_DESC(msize, "memory size in Megabytes [1 - 1024]"); +MODULE_PARM_DESC(msize, "memory size in MiB [1 - 1024]"); module_param(asize, int, 0); MODULE_PARM_DESC(asize, "aperture size, must be <= memsize [1-1024]"); @@ -799,8 +795,7 @@ static int __init init_pmc551(void) mtd->owner = THIS_MODULE; if (add_mtd_device(mtd)) { - printk(KERN_NOTICE "pmc551: Failed to register new " - "device\n"); + printk(KERN_NOTICE "pmc551: Failed to register new device\n"); pci_iounmap(PCI_Device, priv->start); kfree(mtd->priv); kfree(mtd); @@ -811,13 +806,13 @@ static int __init init_pmc551(void) pci_dev_get(PCI_Device); printk(KERN_NOTICE "Registered pmc551 memory device.\n"); - printk(KERN_NOTICE "Mapped %dM of memory from 0x%p to 0x%p\n", + printk(KERN_NOTICE "Mapped %dMiB of memory from 0x%p to 0x%p\n", priv->asize >> 20, priv->start, priv->start + priv->asize); - printk(KERN_NOTICE "Total memory is %d%c\n", + printk(KERN_NOTICE "Total memory is %d%sB\n", (length < 1024) ? length : (length < 1048576) ? length >> 10 : length >> 20, - (length < 1024) ? 'B' : (length < 1048576) ? 'K' : 'M'); + (length < 1024) ? "" : (length < 1048576) ? "Ki" : "Mi"); priv->nextpmc551 = pmc551list; pmc551list = mtd; found++; @@ -850,7 +845,7 @@ static void __exit cleanup_pmc551(void) pmc551list = priv->nextpmc551; if (priv->start) { - printk(KERN_DEBUG "pmc551: unmapping %dM starting at " + printk(KERN_DEBUG "pmc551: unmapping %dMiB starting at " "0x%p\n", priv->asize >> 20, priv->start); pci_iounmap(priv->dev, priv->start); } diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c index ecac0e438f49..b8917beeb650 100644 --- a/drivers/mtd/inftlmount.c +++ b/drivers/mtd/inftlmount.c @@ -580,14 +580,13 @@ int INFTL_mount(struct INFTLrecord *s) logical_block = block = BLOCK_NIL; /* Temporary buffer to store ANAC numbers. */ - ANACtable = kmalloc(s->nb_blocks * sizeof(u8), GFP_KERNEL); + ANACtable = kcalloc(s->nb_blocks, sizeof(u8), GFP_KERNEL); if (!ANACtable) { printk(KERN_WARNING "INFTL: allocation of ANACtable " "failed (%zd bytes)\n", s->nb_blocks * sizeof(u8)); return -ENOMEM; } - memset(ANACtable, 0, s->nb_blocks); /* * First pass is to explore each physical unit, and construct the diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 6cd132c75187..2a2a125b0c76 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -163,20 +163,12 @@ config MTD_SBC_GXX More info at <http://www.arcomcontrols.com/products/icp/pc104/processors/SBC_GX1.htm>. -config MTD_LUBBOCK - tristate "CFI Flash device mapped on Intel Lubbock XScale eval board" - depends on ARCH_LUBBOCK && MTD_CFI_INTELEXT && MTD_PARTITIONS - help - This provides a driver for the on-board flash of the Intel - 'Lubbock' XScale evaluation board. - -config MTD_MAINSTONE - tristate "CFI Flash device mapped on Intel Mainstone XScale eval board" - depends on MACH_MAINSTONE && MTD_CFI_INTELEXT +config MTD_PXA2XX + tristate "CFI Flash device mapped on Intel XScale PXA2xx based boards" + depends on (PXA25x || PXA27x) && MTD_CFI_INTELEXT select MTD_PARTITIONS help - This provides a driver for the on-board flash of the Intel - 'Mainstone PXA27x evaluation board. + This provides a driver for the NOR flash attached to a PXA2xx chip. config MTD_OCTAGON tristate "JEDEC Flash device mapped on Octagon 5066 SBC" @@ -354,7 +346,7 @@ config MTD_CFI_FLAGADM config MTD_WALNUT tristate "Flash device mapped on IBM 405GP Walnut" - depends on MTD_JEDECPROBE && WALNUT + depends on MTD_JEDECPROBE && WALNUT && !PPC_MERGE help This enables access routines for the flash chips on the IBM 405GP Walnut board. If you have one of these boards and would like to @@ -370,7 +362,7 @@ config MTD_EBONY config MTD_OCOTEA tristate "Flash devices mapped on IBM 440GX Ocotea" - depends on MTD_CFI && OCOTEA + depends on MTD_CFI && OCOTEA && !PPC_MERGE help This enables access routines for the flash chips on the IBM 440GX Ocotea board. If you have one of these boards and would like to @@ -384,22 +376,6 @@ config MTD_REDWOOD Redwood board. If you have one of these boards and would like to use the flash chips on it, say 'Y'. -config MTD_TQM834x - tristate "Flash device mapped on TQ Components TQM834x Boards" - depends on MTD_CFI && TQM834x - help - This enables access routines for the flash chips on the - TQ Components TQM834x boards. If you have one of these boards - and would like to use the flash chips on it, say 'Y'. - -config MTD_OCELOT - tristate "Momenco Ocelot boot flash device" - depends on MOMENCO_OCELOT - help - This enables access routines for the boot flash device and for the - NVRAM on the Momenco Ocelot board. If you have one of these boards - and would like access to either of these, say 'Y'. - config MTD_SOLUTIONENGINE tristate "CFI Flash device mapped on Hitachi SolutionEngine" depends on SUPERH && MTD_CFI && MTD_REDBOOT_PARTS @@ -605,6 +581,13 @@ config MTD_SHARP_SL help This enables access to the flash chip on the Sharp SL Series of PDAs. +config MTD_INTEL_VR_NOR + tristate "NOR flash on Intel Vermilion Range Expansion Bus CS0" + depends on PCI + help + Map driver for a NOR flash bank located on the Expansion Bus of the + Intel Vermilion Range chipset. + config MTD_PLATRAM tristate "Map driver for platform device RAM (mtd-ram)" select MTD_RAM diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index 970b189271a2..316382a1401b 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -20,8 +20,7 @@ obj-$(CONFIG_MTD_ESB2ROM) += esb2rom.o obj-$(CONFIG_MTD_ICHXROM) += ichxrom.o obj-$(CONFIG_MTD_CK804XROM) += ck804xrom.o obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o -obj-$(CONFIG_MTD_LUBBOCK) += lubbock-flash.o -obj-$(CONFIG_MTD_MAINSTONE) += mainstone-flash.o +obj-$(CONFIG_MTD_PXA2XX) += pxa2xx-flash.o obj-$(CONFIG_MTD_MBX860) += mbx860.o obj-$(CONFIG_MTD_CEIVA) += ceiva.o obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o @@ -43,7 +42,6 @@ obj-$(CONFIG_MTD_SUN_UFLASH) += sun_uflash.o obj-$(CONFIG_MTD_VMAX) += vmax301.o obj-$(CONFIG_MTD_SCx200_DOCFLASH)+= scx200_docflash.o obj-$(CONFIG_MTD_DBOX2) += dbox2-flash.o -obj-$(CONFIG_MTD_OCELOT) += ocelot.o obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o obj-$(CONFIG_MTD_PCI) += pci.o obj-$(CONFIG_MTD_ALCHEMY) += alchemy-flash.o @@ -70,4 +68,4 @@ obj-$(CONFIG_MTD_SHARP_SL) += sharpsl-flash.o obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o obj-$(CONFIG_MTD_OMAP_NOR) += omap_nor.o obj-$(CONFIG_MTD_MTX1) += mtx-1_flash.o -obj-$(CONFIG_MTD_TQM834x) += tqm834x.o +obj-$(CONFIG_MTD_INTEL_VR_NOR) += intel_vr_nor.o diff --git a/drivers/mtd/maps/alchemy-flash.c b/drivers/mtd/maps/alchemy-flash.c index 84fbe0e8c47e..82811bcb0436 100644 --- a/drivers/mtd/maps/alchemy-flash.c +++ b/drivers/mtd/maps/alchemy-flash.c @@ -75,13 +75,6 @@ #define BOARD_FLASH_WIDTH 2 /* 16-bits */ #endif -#ifdef CONFIG_MIPS_HYDROGEN3 -#define BOARD_MAP_NAME "Hydrogen3 Flash" -#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */ -#define BOARD_FLASH_WIDTH 4 /* 32-bits */ -#define USE_LOCAL_ACCESSORS /* why? */ -#endif - #ifdef CONFIG_MIPS_BOSPORUS #define BOARD_MAP_NAME "Bosporus Flash" #define BOARD_FLASH_SIZE 0x01000000 /* 16MB */ @@ -130,13 +123,6 @@ int __init alchemy_mtd_init(void) window_addr = 0x20000000 - BOARD_FLASH_SIZE; window_size = BOARD_FLASH_SIZE; -#ifdef CONFIG_MIPS_MIRAGE_WHY - /* Boot ROM flash bank only; no user bank */ - window_addr = 0x1C000000; - window_size = 0x04000000; - /* USERFS from 0x1C00 0000 to 0x1FC00000 */ - alchemy_partitions[0].size = 0x03C00000; -#endif /* * Static partition definition selection diff --git a/drivers/mtd/maps/intel_vr_nor.c b/drivers/mtd/maps/intel_vr_nor.c new file mode 100644 index 000000000000..1e7814ae212a --- /dev/null +++ b/drivers/mtd/maps/intel_vr_nor.c @@ -0,0 +1,298 @@ +/* + * drivers/mtd/maps/intel_vr_nor.c + * + * An MTD map driver for a NOR flash bank on the Expansion Bus of the Intel + * Vermilion Range chipset. + * + * The Vermilion Range Expansion Bus supports four chip selects, each of which + * has 64MiB of address space. The 2nd BAR of the Expansion Bus PCI Device + * is a 256MiB memory region containing the address spaces for all four of the + * chip selects, with start addresses hardcoded on 64MiB boundaries. + * + * This map driver only supports NOR flash on chip select 0. The buswidth + * (either 8 bits or 16 bits) is determined by reading the Expansion Bus Timing + * and Control Register for Chip Select 0 (EXP_TIMING_CS0). This driver does + * not modify the value in the EXP_TIMING_CS0 register except to enable writing + * and disable boot acceleration. The timing parameters in the register are + * assumed to have been properly initialized by the BIOS. The reset default + * timing parameters are maximally conservative (slow), so access to the flash + * will be slower than it should be if the BIOS has not initialized the timing + * parameters. + * + * Author: Andy Lowe <alowe@mvista.com> + * + * 2006 (c) MontaVista Software, Inc. 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. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/cfi.h> +#include <linux/mtd/flashchip.h> + +#define DRV_NAME "vr_nor" + +struct vr_nor_mtd { + void __iomem *csr_base; + struct map_info map; + struct mtd_info *info; + int nr_parts; + struct pci_dev *dev; +}; + +/* Expansion Bus Configuration and Status Registers are in BAR 0 */ +#define EXP_CSR_MBAR 0 +/* Expansion Bus Memory Window is BAR 1 */ +#define EXP_WIN_MBAR 1 +/* Maximum address space for Chip Select 0 is 64MiB */ +#define CS0_SIZE 0x04000000 +/* Chip Select 0 is at offset 0 in the Memory Window */ +#define CS0_START 0x0 +/* Chip Select 0 Timing Register is at offset 0 in CSR */ +#define EXP_TIMING_CS0 0x00 +#define TIMING_CS_EN (1 << 31) /* Chip Select Enable */ +#define TIMING_BOOT_ACCEL_DIS (1 << 8) /* Boot Acceleration Disable */ +#define TIMING_WR_EN (1 << 1) /* Write Enable */ +#define TIMING_BYTE_EN (1 << 0) /* 8-bit vs 16-bit bus */ +#define TIMING_MASK 0x3FFF0000 + +static void __devexit vr_nor_destroy_partitions(struct vr_nor_mtd *p) +{ + if (p->nr_parts > 0) { +#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE) + del_mtd_partitions(p->info); +#endif + } else + del_mtd_device(p->info); +} + +static int __devinit vr_nor_init_partitions(struct vr_nor_mtd *p) +{ + int err = 0; +#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE) + struct mtd_partition *parts; + static const char *part_probes[] = { "cmdlinepart", NULL }; +#endif + + /* register the flash bank */ +#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE) + /* partition the flash bank */ + p->nr_parts = parse_mtd_partitions(p->info, part_probes, &parts, 0); + if (p->nr_parts > 0) + err = add_mtd_partitions(p->info, parts, p->nr_parts); +#endif + if (p->nr_parts <= 0) + err = add_mtd_device(p->info); + + return err; +} + +static void __devexit vr_nor_destroy_mtd_setup(struct vr_nor_mtd *p) +{ + map_destroy(p->info); +} + +static int __devinit vr_nor_mtd_setup(struct vr_nor_mtd *p) +{ + static const char *probe_types[] = + { "cfi_probe", "jedec_probe", NULL }; + const char **type; + + for (type = probe_types; !p->info && *type; type++) + p->info = do_map_probe(*type, &p->map); + if (!p->info) + return -ENODEV; + + p->info->owner = THIS_MODULE; + + return 0; +} + +static void __devexit vr_nor_destroy_maps(struct vr_nor_mtd *p) +{ + unsigned int exp_timing_cs0; + + /* write-protect the flash bank */ + exp_timing_cs0 = readl(p->csr_base + EXP_TIMING_CS0); + exp_timing_cs0 &= ~TIMING_WR_EN; + writel(exp_timing_cs0, p->csr_base + EXP_TIMING_CS0); + + /* unmap the flash window */ + iounmap(p->map.virt); + + /* unmap the csr window */ + iounmap(p->csr_base); +} + +/* + * Initialize the map_info structure and map the flash. + * Returns 0 on success, nonzero otherwise. + */ +static int __devinit vr_nor_init_maps(struct vr_nor_mtd *p) +{ + unsigned long csr_phys, csr_len; + unsigned long win_phys, win_len; + unsigned int exp_timing_cs0; + int err; + + csr_phys = pci_resource_start(p->dev, EXP_CSR_MBAR); + csr_len = pci_resource_len(p->dev, EXP_CSR_MBAR); + win_phys = pci_resource_start(p->dev, EXP_WIN_MBAR); + win_len = pci_resource_len(p->dev, EXP_WIN_MBAR); + + if (!csr_phys || !csr_len || !win_phys || !win_len) + return -ENODEV; + + if (win_len < (CS0_START + CS0_SIZE)) + return -ENXIO; + + p->csr_base = ioremap_nocache(csr_phys, csr_len); + if (!p->csr_base) + return -ENOMEM; + + exp_timing_cs0 = readl(p->csr_base + EXP_TIMING_CS0); + if (!(exp_timing_cs0 & TIMING_CS_EN)) { + dev_warn(&p->dev->dev, "Expansion Bus Chip Select 0 " + "is disabled.\n"); + err = -ENODEV; + goto release; + } + if ((exp_timing_cs0 & TIMING_MASK) == TIMING_MASK) { + dev_warn(&p->dev->dev, "Expansion Bus Chip Select 0 " + "is configured for maximally slow access times.\n"); + } + p->map.name = DRV_NAME; + p->map.bankwidth = (exp_timing_cs0 & TIMING_BYTE_EN) ? 1 : 2; + p->map.phys = win_phys + CS0_START; + p->map.size = CS0_SIZE; + p->map.virt = ioremap_nocache(p->map.phys, p->map.size); + if (!p->map.virt) { + err = -ENOMEM; + goto release; + } + simple_map_init(&p->map); + + /* Enable writes to flash bank */ + exp_timing_cs0 |= TIMING_BOOT_ACCEL_DIS | TIMING_WR_EN; + writel(exp_timing_cs0, p->csr_base + EXP_TIMING_CS0); + + return 0; + + release: + iounmap(p->csr_base); + return err; +} + +static struct pci_device_id vr_nor_pci_ids[] = { + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x500D)}, + {0,} +}; + +static void __devexit vr_nor_pci_remove(struct pci_dev *dev) +{ + struct vr_nor_mtd *p = pci_get_drvdata(dev); + + pci_set_drvdata(dev, NULL); + vr_nor_destroy_partitions(p); + vr_nor_destroy_mtd_setup(p); + vr_nor_destroy_maps(p); + kfree(p); + pci_release_regions(dev); + pci_disable_device(dev); +} + +static int __devinit +vr_nor_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + struct vr_nor_mtd *p = NULL; + unsigned int exp_timing_cs0; + int err; + + err = pci_enable_device(dev); + if (err) + goto out; + + err = pci_request_regions(dev, DRV_NAME); + if (err) + goto disable_dev; + + p = kzalloc(sizeof(*p), GFP_KERNEL); + err = -ENOMEM; + if (!p) + goto release; + + p->dev = dev; + + err = vr_nor_init_maps(p); + if (err) + goto release; + + err = vr_nor_mtd_setup(p); + if (err) + goto destroy_maps; + + err = vr_nor_init_partitions(p); + if (err) + goto destroy_mtd_setup; + + pci_set_drvdata(dev, p); + + return 0; + + destroy_mtd_setup: + map_destroy(p->info); + + destroy_maps: + /* write-protect the flash bank */ + exp_timing_cs0 = readl(p->csr_base + EXP_TIMING_CS0); + exp_timing_cs0 &= ~TIMING_WR_EN; + writel(exp_timing_cs0, p->csr_base + EXP_TIMING_CS0); + + /* unmap the flash window */ + iounmap(p->map.virt); + + /* unmap the csr window */ + iounmap(p->csr_base); + + release: + kfree(p); + pci_release_regions(dev); + + disable_dev: + pci_disable_device(dev); + + out: + return err; +} + +static struct pci_driver vr_nor_pci_driver = { + .name = DRV_NAME, + .probe = vr_nor_pci_probe, + .remove = __devexit_p(vr_nor_pci_remove), + .id_table = vr_nor_pci_ids, +}; + +static int __init vr_nor_mtd_init(void) +{ + return pci_register_driver(&vr_nor_pci_driver); +} + +static void __exit vr_nor_mtd_exit(void) +{ + pci_unregister_driver(&vr_nor_pci_driver); +} + +module_init(vr_nor_mtd_init); +module_exit(vr_nor_mtd_exit); + +MODULE_AUTHOR("Andy Lowe"); +MODULE_DESCRIPTION("MTD map driver for NOR flash on Intel Vermilion Range"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, vr_nor_pci_ids); diff --git a/drivers/mtd/maps/lubbock-flash.c b/drivers/mtd/maps/lubbock-flash.c deleted file mode 100644 index e8560683b973..000000000000 --- a/drivers/mtd/maps/lubbock-flash.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - * $Id: lubbock-flash.c,v 1.21 2005/11/07 11:14:27 gleixner Exp $ - * - * Map driver for the Lubbock developer platform. - * - * Author: Nicolas Pitre - * Copyright: (C) 2001 MontaVista Software Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/init.h> - -#include <linux/mtd/mtd.h> -#include <linux/mtd/map.h> -#include <linux/mtd/partitions.h> - -#include <asm/io.h> -#include <asm/hardware.h> -#include <asm/arch/pxa-regs.h> -#include <asm/arch/lubbock.h> -#include <asm/cacheflush.h> - -#define ROM_ADDR 0x00000000 -#define FLASH_ADDR 0x04000000 - -#define WINDOW_SIZE 64*1024*1024 - -static void lubbock_map_inval_cache(struct map_info *map, unsigned long from, ssize_t len) -{ - flush_ioremap_region(map->phys, map->cached, from, len); -} - -static struct map_info lubbock_maps[2] = { { - .size = WINDOW_SIZE, - .phys = 0x00000000, - .inval_cache = lubbock_map_inval_cache, -}, { - .size = WINDOW_SIZE, - .phys = 0x04000000, - .inval_cache = lubbock_map_inval_cache, -} }; - -static struct mtd_partition lubbock_partitions[] = { - { - .name = "Bootloader", - .size = 0x00040000, - .offset = 0, - .mask_flags = MTD_WRITEABLE /* force read-only */ - },{ - .name = "Kernel", - .size = 0x00100000, - .offset = 0x00040000, - },{ - .name = "Filesystem", - .size = MTDPART_SIZ_FULL, - .offset = 0x00140000 - } -}; - -static struct mtd_info *mymtds[2]; -static struct mtd_partition *parsed_parts[2]; -static int nr_parsed_parts[2]; - -static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; - -static int __init init_lubbock(void) -{ - int flashboot = (LUB_CONF_SWITCHES & 1); - int ret = 0, i; - - lubbock_maps[0].bankwidth = lubbock_maps[1].bankwidth = - (BOOT_DEF & 1) ? 2 : 4; - - /* Compensate for the nROMBT switch which swaps the flash banks */ - printk(KERN_NOTICE "Lubbock configured to boot from %s (bank %d)\n", - flashboot?"Flash":"ROM", flashboot); - - lubbock_maps[flashboot^1].name = "Lubbock Application Flash"; - lubbock_maps[flashboot].name = "Lubbock Boot ROM"; - - for (i = 0; i < 2; i++) { - lubbock_maps[i].virt = ioremap(lubbock_maps[i].phys, WINDOW_SIZE); - if (!lubbock_maps[i].virt) { - printk(KERN_WARNING "Failed to ioremap %s\n", lubbock_maps[i].name); - if (!ret) - ret = -ENOMEM; - continue; - } - lubbock_maps[i].cached = ioremap_cached(lubbock_maps[i].phys, WINDOW_SIZE); - if (!lubbock_maps[i].cached) - printk(KERN_WARNING "Failed to ioremap cached %s\n", lubbock_maps[i].name); - simple_map_init(&lubbock_maps[i]); - - printk(KERN_NOTICE "Probing %s at physical address 0x%08lx (%d-bit bankwidth)\n", - lubbock_maps[i].name, lubbock_maps[i].phys, - lubbock_maps[i].bankwidth * 8); - - mymtds[i] = do_map_probe("cfi_probe", &lubbock_maps[i]); - - if (!mymtds[i]) { - iounmap((void *)lubbock_maps[i].virt); - if (lubbock_maps[i].cached) - iounmap(lubbock_maps[i].cached); - if (!ret) - ret = -EIO; - continue; - } - mymtds[i]->owner = THIS_MODULE; - - ret = parse_mtd_partitions(mymtds[i], probes, - &parsed_parts[i], 0); - - if (ret > 0) - nr_parsed_parts[i] = ret; - } - - if (!mymtds[0] && !mymtds[1]) - return ret; - - for (i = 0; i < 2; i++) { - if (!mymtds[i]) { - printk(KERN_WARNING "%s is absent. Skipping\n", lubbock_maps[i].name); - } else if (nr_parsed_parts[i]) { - add_mtd_partitions(mymtds[i], parsed_parts[i], nr_parsed_parts[i]); - } else if (!i) { - printk("Using static partitions on %s\n", lubbock_maps[i].name); - add_mtd_partitions(mymtds[i], lubbock_partitions, ARRAY_SIZE(lubbock_partitions)); - } else { - printk("Registering %s as whole device\n", lubbock_maps[i].name); - add_mtd_device(mymtds[i]); - } - } - return 0; -} - -static void __exit cleanup_lubbock(void) -{ - int i; - for (i = 0; i < 2; i++) { - if (!mymtds[i]) - continue; - - if (nr_parsed_parts[i] || !i) - del_mtd_partitions(mymtds[i]); - else - del_mtd_device(mymtds[i]); - - map_destroy(mymtds[i]); - iounmap((void *)lubbock_maps[i].virt); - if (lubbock_maps[i].cached) - iounmap(lubbock_maps[i].cached); - - kfree(parsed_parts[i]); - } -} - -module_init(init_lubbock); -module_exit(cleanup_lubbock); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>"); -MODULE_DESCRIPTION("MTD map driver for Intel Lubbock"); diff --git a/drivers/mtd/maps/mainstone-flash.c b/drivers/mtd/maps/mainstone-flash.c deleted file mode 100644 index d76487d82dcd..000000000000 --- a/drivers/mtd/maps/mainstone-flash.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * $Id: $ - * - * Map driver for the Mainstone developer platform. - * - * Author: Nicolas Pitre - * Copyright: (C) 2001 MontaVista Software Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/init.h> - -#include <linux/mtd/mtd.h> -#include <linux/mtd/map.h> -#include <linux/mtd/partitions.h> - -#include <asm/io.h> -#include <asm/hardware.h> -#include <asm/arch/pxa-regs.h> -#include <asm/arch/mainstone.h> -#include <asm/cacheflush.h> - - -#define ROM_ADDR 0x00000000 -#define FLASH_ADDR 0x04000000 - -#define WINDOW_SIZE 0x04000000 - -static void mainstone_map_inval_cache(struct map_info *map, unsigned long from, - ssize_t len) -{ - flush_ioremap_region(map->phys, map->cached, from, len); -} - -static struct map_info mainstone_maps[2] = { { - .size = WINDOW_SIZE, - .phys = PXA_CS0_PHYS, - .inval_cache = mainstone_map_inval_cache, -}, { - .size = WINDOW_SIZE, - .phys = PXA_CS1_PHYS, - .inval_cache = mainstone_map_inval_cache, -} }; - -static struct mtd_partition mainstone_partitions[] = { - { - .name = "Bootloader", - .size = 0x00040000, - .offset = 0, - .mask_flags = MTD_WRITEABLE /* force read-only */ - },{ - .name = "Kernel", - .size = 0x00400000, - .offset = 0x00040000, - },{ - .name = "Filesystem", - .size = MTDPART_SIZ_FULL, - .offset = 0x00440000 - } -}; - -static struct mtd_info *mymtds[2]; -static struct mtd_partition *parsed_parts[2]; -static int nr_parsed_parts[2]; - -static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; - -static int __init init_mainstone(void) -{ - int SW7 = 0; /* FIXME: get from SCR (Mst doc section 3.2.1.1) */ - int ret = 0, i; - - mainstone_maps[0].bankwidth = (BOOT_DEF & 1) ? 2 : 4; - mainstone_maps[1].bankwidth = 4; - - /* Compensate for SW7 which swaps the flash banks */ - mainstone_maps[SW7].name = "processor flash"; - mainstone_maps[SW7 ^ 1].name = "main board flash"; - - printk(KERN_NOTICE "Mainstone configured to boot from %s\n", - mainstone_maps[0].name); - - for (i = 0; i < 2; i++) { - mainstone_maps[i].virt = ioremap(mainstone_maps[i].phys, - WINDOW_SIZE); - if (!mainstone_maps[i].virt) { - printk(KERN_WARNING "Failed to ioremap %s\n", - mainstone_maps[i].name); - if (!ret) - ret = -ENOMEM; - continue; - } - mainstone_maps[i].cached = - ioremap_cached(mainstone_maps[i].phys, WINDOW_SIZE); - if (!mainstone_maps[i].cached) - printk(KERN_WARNING "Failed to ioremap cached %s\n", - mainstone_maps[i].name); - simple_map_init(&mainstone_maps[i]); - - printk(KERN_NOTICE - "Probing %s at physical address 0x%08lx" - " (%d-bit bankwidth)\n", - mainstone_maps[i].name, mainstone_maps[i].phys, - mainstone_maps[i].bankwidth * 8); - - mymtds[i] = do_map_probe("cfi_probe", &mainstone_maps[i]); - - if (!mymtds[i]) { - iounmap((void *)mainstone_maps[i].virt); - if (mainstone_maps[i].cached) - iounmap(mainstone_maps[i].cached); - if (!ret) - ret = -EIO; - continue; - } - mymtds[i]->owner = THIS_MODULE; - - ret = parse_mtd_partitions(mymtds[i], probes, - &parsed_parts[i], 0); - - if (ret > 0) - nr_parsed_parts[i] = ret; - } - - if (!mymtds[0] && !mymtds[1]) - return ret; - - for (i = 0; i < 2; i++) { - if (!mymtds[i]) { - printk(KERN_WARNING "%s is absent. Skipping\n", - mainstone_maps[i].name); - } else if (nr_parsed_parts[i]) { - add_mtd_partitions(mymtds[i], parsed_parts[i], - nr_parsed_parts[i]); - } else if (!i) { - printk("Using static partitions on %s\n", - mainstone_maps[i].name); - add_mtd_partitions(mymtds[i], mainstone_partitions, - ARRAY_SIZE(mainstone_partitions)); - } else { - printk("Registering %s as whole device\n", - mainstone_maps[i].name); - add_mtd_device(mymtds[i]); - } - } - return 0; -} - -static void __exit cleanup_mainstone(void) -{ - int i; - for (i = 0; i < 2; i++) { - if (!mymtds[i]) - continue; - - if (nr_parsed_parts[i] || !i) - del_mtd_partitions(mymtds[i]); - else - del_mtd_device(mymtds[i]); - - map_destroy(mymtds[i]); - iounmap((void *)mainstone_maps[i].virt); - if (mainstone_maps[i].cached) - iounmap(mainstone_maps[i].cached); - kfree(parsed_parts[i]); - } -} - -module_init(init_mainstone); -module_exit(cleanup_mainstone); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>"); -MODULE_DESCRIPTION("MTD map driver for Intel Mainstone"); diff --git a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c index 7b96cd02f82b..0c9b305a72e0 100644 --- a/drivers/mtd/maps/nettel.c +++ b/drivers/mtd/maps/nettel.c @@ -158,68 +158,11 @@ static struct notifier_block nettel_notifier_block = { nettel_reboot_notifier, NULL, 0 }; -/* - * Erase the configuration file system. - * Used to support the software reset button. - */ -static void nettel_erasecallback(struct erase_info *done) -{ - wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv; - wake_up(wait_q); -} - -static struct erase_info nettel_erase; - -int nettel_eraseconfig(void) -{ - struct mtd_info *mtd; - DECLARE_WAITQUEUE(wait, current); - wait_queue_head_t wait_q; - int ret; - - init_waitqueue_head(&wait_q); - mtd = get_mtd_device(NULL, 2); - if (!IS_ERR(mtd)) { - nettel_erase.mtd = mtd; - nettel_erase.callback = nettel_erasecallback; - nettel_erase.callback = NULL; - nettel_erase.addr = 0; - nettel_erase.len = mtd->size; - nettel_erase.priv = (u_long) &wait_q; - nettel_erase.priv = 0; - - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&wait_q, &wait); - - ret = mtd->erase(mtd, &nettel_erase); - if (ret) { - set_current_state(TASK_RUNNING); - remove_wait_queue(&wait_q, &wait); - put_mtd_device(mtd); - return(ret); - } - - schedule(); /* Wait for erase to finish. */ - remove_wait_queue(&wait_q, &wait); - - put_mtd_device(mtd); - } - - return(0); -} - -#else - -int nettel_eraseconfig(void) -{ - return(0); -} - #endif /****************************************************************************/ -int __init nettel_init(void) +static int __init nettel_init(void) { volatile unsigned long *amdpar; unsigned long amdaddr, maxsize; @@ -421,10 +364,6 @@ int __init nettel_init(void) intel_mtd->owner = THIS_MODULE; -#ifndef CONFIG_BLK_DEV_INITRD - ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, 1); -#endif - num_intel_partitions = sizeof(nettel_intel_partitions) / sizeof(nettel_intel_partitions[0]); @@ -477,7 +416,7 @@ out_unmap2: /****************************************************************************/ -void __exit nettel_cleanup(void) +static void __exit nettel_cleanup(void) { #ifdef CONFIG_MTD_CFI_INTELEXT unregister_reboot_notifier(&nettel_notifier_block); diff --git a/drivers/mtd/maps/ocelot.c b/drivers/mtd/maps/ocelot.c deleted file mode 100644 index 6977963d7897..000000000000 --- a/drivers/mtd/maps/ocelot.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * $Id: ocelot.c,v 1.17 2005/11/07 11:14:27 gleixner Exp $ - * - * Flash on Momenco Ocelot - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <asm/io.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/map.h> -#include <linux/mtd/partitions.h> - -#define OCELOT_PLD 0x2c000000 -#define FLASH_WINDOW_ADDR 0x2fc00000 -#define FLASH_WINDOW_SIZE 0x00080000 -#define FLASH_BUSWIDTH 1 -#define NVRAM_WINDOW_ADDR 0x2c800000 -#define NVRAM_WINDOW_SIZE 0x00007FF0 -#define NVRAM_BUSWIDTH 1 - -static unsigned int cacheflush = 0; - -static struct mtd_info *flash_mtd; -static struct mtd_info *nvram_mtd; - -static void ocelot_ram_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) -{ - struct map_info *map = mtd->priv; - size_t done = 0; - - /* If we use memcpy, it does word-wide writes. Even though we told the - GT64120A that it's an 8-bit wide region, word-wide writes don't work. - We end up just writing the first byte of the four to all four bytes. - So we have this loop instead */ - *retlen = len; - while(len) { - __raw_writeb(*(unsigned char *) from, map->virt + to); - from++; - to++; - len--; - } -} - -static struct mtd_partition *parsed_parts; - -struct map_info ocelot_flash_map = { - .name = "Ocelot boot flash", - .size = FLASH_WINDOW_SIZE, - .bankwidth = FLASH_BUSWIDTH, - .phys = FLASH_WINDOW_ADDR, -}; - -struct map_info ocelot_nvram_map = { - .name = "Ocelot NVRAM", - .size = NVRAM_WINDOW_SIZE, - .bankwidth = NVRAM_BUSWIDTH, - .phys = NVRAM_WINDOW_ADDR, -}; - -static const char *probes[] = { "RedBoot", NULL }; - -static int __init init_ocelot_maps(void) -{ - void *pld; - int nr_parts; - unsigned char brd_status; - - printk(KERN_INFO "Momenco Ocelot MTD mappings: Flash 0x%x at 0x%x, NVRAM 0x%x at 0x%x\n", - FLASH_WINDOW_SIZE, FLASH_WINDOW_ADDR, NVRAM_WINDOW_SIZE, NVRAM_WINDOW_ADDR); - - /* First check whether the flash jumper is present */ - pld = ioremap(OCELOT_PLD, 0x10); - if (!pld) { - printk(KERN_NOTICE "Failed to ioremap Ocelot PLD\n"); - return -EIO; - } - brd_status = readb(pld+4); - iounmap(pld); - - /* Now ioremap the NVRAM space */ - ocelot_nvram_map.virt = ioremap_nocache(NVRAM_WINDOW_ADDR, NVRAM_WINDOW_SIZE); - if (!ocelot_nvram_map.virt) { - printk(KERN_NOTICE "Failed to ioremap Ocelot NVRAM space\n"); - return -EIO; - } - - simple_map_init(&ocelot_nvram_map); - - /* And do the RAM probe on it to get an MTD device */ - nvram_mtd = do_map_probe("map_ram", &ocelot_nvram_map); - if (!nvram_mtd) { - printk("NVRAM probe failed\n"); - goto fail_1; - } - nvram_mtd->owner = THIS_MODULE; - nvram_mtd->erasesize = 16; - /* Override the write() method */ - nvram_mtd->write = ocelot_ram_write; - - /* Now map the flash space */ - ocelot_flash_map.virt = ioremap_nocache(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE); - if (!ocelot_flash_map.virt) { - printk(KERN_NOTICE "Failed to ioremap Ocelot flash space\n"); - goto fail_2; - } - /* Now the cached version */ - ocelot_flash_map.cached = (unsigned long)__ioremap(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE, 0); - - simple_map_init(&ocelot_flash_map); - - /* Only probe for flash if the write jumper is present */ - if (brd_status & 0x40) { - flash_mtd = do_map_probe("jedec", &ocelot_flash_map); - } else { - printk(KERN_NOTICE "Ocelot flash write jumper not present. Treating as ROM\n"); - } - /* If that failed or the jumper's absent, pretend it's ROM */ - if (!flash_mtd) { - flash_mtd = do_map_probe("map_rom", &ocelot_flash_map); - /* If we're treating it as ROM, set the erase size */ - if (flash_mtd) - flash_mtd->erasesize = 0x10000; - } - if (!flash_mtd) - goto fail3; - - add_mtd_device(nvram_mtd); - - flash_mtd->owner = THIS_MODULE; - nr_parts = parse_mtd_partitions(flash_mtd, probes, &parsed_parts, 0); - - if (nr_parts > 0) - add_mtd_partitions(flash_mtd, parsed_parts, nr_parts); - else - add_mtd_device(flash_mtd); - - return 0; - - fail3: - iounmap((void *)ocelot_flash_map.virt); - if (ocelot_flash_map.cached) - iounmap((void *)ocelot_flash_map.cached); - fail_2: - map_destroy(nvram_mtd); - fail_1: - iounmap((void *)ocelot_nvram_map.virt); - - return -ENXIO; -} - -static void __exit cleanup_ocelot_maps(void) -{ - del_mtd_device(nvram_mtd); - map_destroy(nvram_mtd); - iounmap((void *)ocelot_nvram_map.virt); - - if (parsed_parts) - del_mtd_partitions(flash_mtd); - else - del_mtd_device(flash_mtd); - map_destroy(flash_mtd); - iounmap((void *)ocelot_flash_map.virt); - if (ocelot_flash_map.cached) - iounmap((void *)ocelot_flash_map.cached); -} - -module_init(init_ocelot_maps); -module_exit(cleanup_ocelot_maps); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Red Hat, Inc. - David Woodhouse <dwmw2@cambridge.redhat.com>"); -MODULE_DESCRIPTION("MTD map driver for Momenco Ocelot board"); diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index cf75a566442e..aeed9ea79714 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -232,7 +232,6 @@ static int __devinit of_flash_probe(struct of_device *dev, info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) goto err_out; - memset(info, 0, sizeof(*info)); dev_set_drvdata(&dev->dev, info); diff --git a/drivers/mtd/maps/pmcmsp-flash.c b/drivers/mtd/maps/pmcmsp-flash.c index 7e0377ec1c40..02bde8c982ec 100644 --- a/drivers/mtd/maps/pmcmsp-flash.c +++ b/drivers/mtd/maps/pmcmsp-flash.c @@ -73,13 +73,16 @@ int __init init_msp_flash(void) return -ENXIO; printk(KERN_NOTICE "Found %d PMC flash devices\n", fcnt); - msp_flash = (struct mtd_info **)kmalloc( - fcnt * sizeof(struct map_info *), GFP_KERNEL); - msp_parts = (struct mtd_partition **)kmalloc( - fcnt * sizeof(struct mtd_partition *), GFP_KERNEL); - msp_maps = (struct map_info *)kmalloc( - fcnt * sizeof(struct mtd_info), GFP_KERNEL); - memset(msp_maps, 0, fcnt * sizeof(struct mtd_info)); + + msp_flash = kmalloc(fcnt * sizeof(struct map_info *), GFP_KERNEL); + msp_parts = kmalloc(fcnt * sizeof(struct mtd_partition *), GFP_KERNEL); + msp_maps = kcalloc(fcnt, sizeof(struct mtd_info), GFP_KERNEL); + if (!msp_flash || !msp_parts || !msp_maps) { + kfree(msp_maps); + kfree(msp_parts); + kfree(msp_flash); + return -ENOMEM; + } /* loop over the flash devices, initializing each */ for (i = 0; i < fcnt; i++) { @@ -95,9 +98,8 @@ int __init init_msp_flash(void) continue; } - msp_parts[i] = (struct mtd_partition *)kmalloc( - pcnt * sizeof(struct mtd_partition), GFP_KERNEL); - memset(msp_parts[i], 0, pcnt * sizeof(struct mtd_partition)); + msp_parts[i] = kcalloc(pcnt, sizeof(struct mtd_partition), + GFP_KERNEL); /* now initialize the devices proper */ flash_name[5] = '0' + i; diff --git a/drivers/mtd/maps/pmcmsp-ramroot.c b/drivers/mtd/maps/pmcmsp-ramroot.c index 18049bceba8d..30de5c0c09a9 100644 --- a/drivers/mtd/maps/pmcmsp-ramroot.c +++ b/drivers/mtd/maps/pmcmsp-ramroot.c @@ -79,7 +79,6 @@ static int __init init_rrmap(void) rr_mtd->owner = THIS_MODULE; add_mtd_device(rr_mtd); - ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, rr_mtd->index); return 0; } diff --git a/drivers/mtd/maps/pq2fads.c b/drivers/mtd/maps/pq2fads.c deleted file mode 100644 index fb78d87cc130..000000000000 --- a/drivers/mtd/maps/pq2fads.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * drivers/mtd/maps/pq2fads.c - * - * Mapping for the flash SIMM on 8272ADS and PQ2FADS board - * - * Author: Vitaly Bordug <vbordug@ru.mvista.com> - * - * 2005 (c) MontaVista Software, Inc. 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. - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <asm/io.h> -#include <asm/ppcboot.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/map.h> -#include <linux/mtd/partitions.h> -#include <linux/mtd/physmap.h> - -/* - NOTE: bank width and interleave relative to the installed flash - should have been chosen within MTD_CFI_GEOMETRY options. - */ -#define PQ2FADS_BANK_WIDTH 4 - -static struct mtd_partition pq2fads_partitions[] = { - { -#ifdef CONFIG_ADS8272 - .name = "HRCW", - .size = 0x40000, - .offset = 0, - .mask_flags = MTD_WRITEABLE, /* force read-only */ - }, { - .name = "User FS", - .size = 0x5c0000, - .offset = 0x40000, -#else - .name = "User FS", - .size = 0x600000, - .offset = 0, -#endif - }, { - .name = "uImage", - .size = 0x100000, - .offset = 0x600000, - .mask_flags = MTD_WRITEABLE, /* force read-only */ - }, { - .name = "bootloader", - .size = 0x40000, - .offset = 0x700000, - .mask_flags = MTD_WRITEABLE, /* force read-only */ - }, { - .name = "bootloader env", - .size = 0x40000, - .offset = 0x740000, - .mask_flags = MTD_WRITEABLE, /* force read-only */ - } -}; - - -/* pointer to MPC885ADS board info data */ -extern unsigned char __res[]; - -static int __init init_pq2fads_mtd(void) -{ - bd_t *bd = (bd_t *)__res; - physmap_configure(bd->bi_flashstart, bd->bi_flashsize, PQ2FADS_BANK_WIDTH, NULL); - - physmap_set_partitions(pq2fads_partitions, - sizeof (pq2fads_partitions) / - sizeof (pq2fads_partitions[0])); - return 0; -} - -static void __exit cleanup_pq2fads_mtd(void) -{ -} - -module_init(init_pq2fads_mtd); -module_exit(cleanup_pq2fads_mtd); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("MTD map and partitions for MPC8272ADS boards"); diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c new file mode 100644 index 000000000000..82113295c266 --- /dev/null +++ b/drivers/mtd/maps/pxa2xx-flash.c @@ -0,0 +1,200 @@ +/* + * Map driver for Intel XScale PXA2xx platforms. + * + * Author: Nicolas Pitre + * Copyright: (C) 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> + +#include <asm/io.h> +#include <asm/hardware.h> +#include <asm/cacheflush.h> + +#include <asm/mach/flash.h> + +static void pxa2xx_map_inval_cache(struct map_info *map, unsigned long from, + ssize_t len) +{ + flush_ioremap_region(map->phys, map->cached, from, len); +} + +struct pxa2xx_flash_info { + struct mtd_partition *parts; + int nr_parts; + struct mtd_info *mtd; + struct map_info map; +}; + + +static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; + + +static int __init pxa2xx_flash_probe(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct flash_platform_data *flash = pdev->dev.platform_data; + struct pxa2xx_flash_info *info; + struct mtd_partition *parts; + struct resource *res; + int ret = 0; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + info = kmalloc(sizeof(struct pxa2xx_flash_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + memset(info, 0, sizeof(struct pxa2xx_flash_info)); + info->map.name = (char *) flash->name; + info->map.bankwidth = flash->width; + info->map.phys = res->start; + info->map.size = res->end - res->start + 1; + info->parts = flash->parts; + info->nr_parts = flash->nr_parts; + + info->map.virt = ioremap(info->map.phys, info->map.size); + if (!info->map.virt) { + printk(KERN_WARNING "Failed to ioremap %s\n", + info->map.name); + return -ENOMEM; + } + info->map.cached = + ioremap_cached(info->map.phys, info->map.size); + if (!info->map.cached) + printk(KERN_WARNING "Failed to ioremap cached %s\n", + info->map.name); + info->map.inval_cache = pxa2xx_map_inval_cache; + simple_map_init(&info->map); + + printk(KERN_NOTICE + "Probing %s at physical address 0x%08lx" + " (%d-bit bankwidth)\n", + info->map.name, (unsigned long)info->map.phys, + info->map.bankwidth * 8); + + info->mtd = do_map_probe(flash->map_name, &info->map); + + if (!info->mtd) { + iounmap((void *)info->map.virt); + if (info->map.cached) + iounmap(info->map.cached); + return -EIO; + } + info->mtd->owner = THIS_MODULE; + +#ifdef CONFIG_MTD_PARTITIONS + ret = parse_mtd_partitions(info->mtd, probes, &parts, 0); + + if (ret > 0) { + info->nr_parts = ret; + info->parts = parts; + } +#endif + + if (info->nr_parts) { + add_mtd_partitions(info->mtd, info->parts, + info->nr_parts); + } else { + printk("Registering %s as whole device\n", + info->map.name); + add_mtd_device(info->mtd); + } + + dev_set_drvdata(dev, info); + return 0; +} + +static int __exit pxa2xx_flash_remove(struct device *dev) +{ + struct pxa2xx_flash_info *info = dev_get_drvdata(dev); + + dev_set_drvdata(dev, NULL); + +#ifdef CONFIG_MTD_PARTITIONS + if (info->nr_parts) + del_mtd_partitions(info->mtd); + else +#endif + del_mtd_device(info->mtd); + + map_destroy(info->mtd); + iounmap(info->map.virt); + if (info->map.cached) + iounmap(info->map.cached); + kfree(info->parts); + kfree(info); + return 0; +} + +#ifdef CONFIG_PM +static int pxa2xx_flash_suspend(struct device *dev, pm_message_t state) +{ + struct pxa2xx_flash_info *info = dev_get_drvdata(dev); + int ret = 0; + + if (info->mtd && info->mtd->suspend) + ret = info->mtd->suspend(info->mtd); + return ret; +} + +static int pxa2xx_flash_resume(struct device *dev) +{ + struct pxa2xx_flash_info *info = dev_get_drvdata(dev); + + if (info->mtd && info->mtd->resume) + info->mtd->resume(info->mtd); + return 0; +} +static void pxa2xx_flash_shutdown(struct device *dev) +{ + struct pxa2xx_flash_info *info = dev_get_drvdata(dev); + + if (info && info->mtd->suspend(info->mtd) == 0) + info->mtd->resume(info->mtd); +} +#else +#define pxa2xx_flash_suspend NULL +#define pxa2xx_flash_resume NULL +#define pxa2xx_flash_shutdown NULL +#endif + +static struct device_driver pxa2xx_flash_driver = { + .name = "pxa2xx-flash", + .bus = &platform_bus_type, + .probe = pxa2xx_flash_probe, + .remove = __exit_p(pxa2xx_flash_remove), + .suspend = pxa2xx_flash_suspend, + .resume = pxa2xx_flash_resume, + .shutdown = pxa2xx_flash_shutdown, +}; + +static int __init init_pxa2xx_flash(void) +{ + return driver_register(&pxa2xx_flash_driver); +} + +static void __exit cleanup_pxa2xx_flash(void) +{ + driver_unregister(&pxa2xx_flash_driver); +} + +module_init(init_pxa2xx_flash); +module_exit(cleanup_pxa2xx_flash); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>"); +MODULE_DESCRIPTION("MTD map driver for Intel XScale PXA2xx"); diff --git a/drivers/mtd/maps/tqm834x.c b/drivers/mtd/maps/tqm834x.c deleted file mode 100644 index 9adc970e55e6..000000000000 --- a/drivers/mtd/maps/tqm834x.c +++ /dev/null @@ -1,286 +0,0 @@ -/* - * drivers/mtd/maps/tqm834x.c - * - * MTD mapping driver for TQM834x boards - * - * Copyright 2005 Wolfgang Denk, DENX Software Engineering, <wd@denx.de>. - * - * 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. - * - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <asm/io.h> -#include <asm/ppcboot.h> - -#include <linux/mtd/mtd.h> -#include <linux/mtd/map.h> -#include <linux/mtd/partitions.h> - -#define FLASH_BANK_MAX 2 - -extern unsigned char __res[]; - -/* trivial struct to describe partition information */ -struct mtd_part_def -{ - int nums; - unsigned char *type; - struct mtd_partition* mtd_part; -}; - -static struct mtd_info* mtd_banks[FLASH_BANK_MAX]; -static struct map_info* map_banks[FLASH_BANK_MAX]; -static struct mtd_part_def part_banks[FLASH_BANK_MAX]; - -static unsigned long num_banks; -static unsigned long start_scan_addr; - -#ifdef CONFIG_MTD_PARTITIONS -/* - * The following defines the partition layout of TQM834x boards. - * - * See include/linux/mtd/partitions.h for definition of the - * mtd_partition structure. - * - * Assume minimal initial size of 4 MiB per bank, will be updated - * later in init_tqm834x_mtd() routine. - */ - -/* Partition definition for the first flash bank which is always present. */ -static struct mtd_partition tqm834x_partitions_bank1[] = { - { - .name = "u-boot", /* u-boot firmware */ - .offset = 0x00000000, - .size = 0x00040000, /* 256 KiB */ - /*mask_flags: MTD_WRITEABLE, * force read-only */ - }, - { - .name = "env", /* u-boot environment */ - .offset = 0x00040000, - .size = 0x00020000, /* 128 KiB */ - /*mask_flags: MTD_WRITEABLE, * force read-only */ - }, - { - .name = "kernel", /* linux kernel image */ - .offset = 0x00060000, - .size = 0x00100000, /* 1 MiB */ - /*mask_flags: MTD_WRITEABLE, * force read-only */ - }, - { - .name = "initrd", /* ramdisk image */ - .offset = 0x00160000, - .size = 0x00200000, /* 2 MiB */ - }, - { - .name = "user", /* user data */ - .offset = 0x00360000, - .size = 0x000a0000, /* remaining space */ - /* NOTE: this parttion size is re-calcated in */ - /* init_tqm834x_mtd() to cover actual remaining space. */ - }, -}; - -/* Partition definition for the second flash bank which may be present on some - * TQM834x boards. - */ -static struct mtd_partition tqm834x_partitions_bank2[] = { - { - .name = "jffs2", /* jffs2 filesystem */ - .offset = 0x00000000, - .size = 0x00400000, /* whole device */ - /* NOTE: this parttion size is re-calcated in */ - /* init_tqm834x_mtd() to cover actual device size. */ - }, -}; - -#endif /* CONFIG_MTD_PARTITIONS */ - -static int __init init_tqm834x_mtd(void) -{ - int idx = 0, ret = 0; - unsigned long flash_addr, flash_size, mtd_size = 0; - - /* pointer to TQM834x board info data */ - bd_t *bd = (bd_t *)__res; -#ifdef CONFIG_MTD_CMDLINE_PARTS - int n; - char mtdid[4]; - const char *part_probes[] = { "cmdlinepart", NULL }; -#endif - - flash_addr = bd->bi_flashstart; - flash_size = bd->bi_flashsize; - - /* request maximum flash size address space */ - start_scan_addr = (unsigned long)ioremap(flash_addr, flash_size); - if (!start_scan_addr) { - printk("%s: Failed to ioremap address: 0x%lx\n", - __FUNCTION__, flash_addr); - return -EIO; - } - - for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++) { - if (mtd_size >= flash_size) - break; - - pr_debug("%s: chip probing count %d\n", __FUNCTION__, idx); - - map_banks[idx] = kzalloc(sizeof(struct map_info), GFP_KERNEL); - if (map_banks[idx] == NULL) { - ret = -ENOMEM; - goto error_mem; - } - map_banks[idx]->name = kzalloc(16, GFP_KERNEL); - if (map_banks[idx]->name == NULL) { - ret = -ENOMEM; - goto error_mem; - } - - sprintf(map_banks[idx]->name, "TQM834x-%d", idx); - map_banks[idx]->size = flash_size; - map_banks[idx]->bankwidth = 4; - - simple_map_init(map_banks[idx]); - - map_banks[idx]->virt = (void __iomem *) - (start_scan_addr + ((idx > 0) ? - (mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0)); - map_banks[idx]->phys = - flash_addr + ((idx > 0) ? - (mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0); - - /* start to probe flash chips */ - mtd_banks[idx] = do_map_probe("cfi_probe", map_banks[idx]); - if (mtd_banks[idx]) { - mtd_banks[idx]->owner = THIS_MODULE; - mtd_size += mtd_banks[idx]->size; - num_banks++; - pr_debug("%s: bank %ld, name: %s, size: %d bytes \n", - __FUNCTION__, num_banks, - mtd_banks[idx]->name, mtd_banks[idx]->size); - } - } - - /* no supported flash chips found */ - if (!num_banks) { - printk("TQM834x: No supported flash chips found!\n"); - ret = -ENXIO; - goto error_mem; - } - -#ifdef CONFIG_MTD_PARTITIONS - /* - * Select static partition definitions - */ - n = ARRAY_SIZE(tqm834x_partitions_bank1); - part_banks[0].mtd_part = tqm834x_partitions_bank1; - part_banks[0].type = "static image bank1"; - part_banks[0].nums = n; - - /* update last partition size to cover actual remaining space */ - tqm834x_partitions_bank1[n - 1].size = - mtd_banks[0]->size - - tqm834x_partitions_bank1[n - 1].offset; - - /* check if we have second bank? */ - if (num_banks == 2) { - n = ARRAY_SIZE(tqm834x_partitions_bank2); - part_banks[1].mtd_part = tqm834x_partitions_bank2; - part_banks[1].type = "static image bank2"; - part_banks[1].nums = n; - - /* update last partition size to cover actual remaining space */ - tqm834x_partitions_bank2[n - 1].size = - mtd_banks[1]->size - - tqm834x_partitions_bank2[n - 1].offset; - } - - for(idx = 0; idx < num_banks ; idx++) { -#ifdef CONFIG_MTD_CMDLINE_PARTS - sprintf(mtdid, "%d", idx); - n = parse_mtd_partitions(mtd_banks[idx], - part_probes, - &part_banks[idx].mtd_part, - 0); - pr_debug("%s: %d command line partitions on bank %s\n", - __FUNCTION__, n, mtdid); - if (n > 0) { - part_banks[idx].type = "command line"; - part_banks[idx].nums = n; - } -#endif /* CONFIG_MTD_CMDLINE_PARTS */ - if (part_banks[idx].nums == 0) { - printk(KERN_NOTICE - "TQM834x flash bank %d: no partition info " - "available, registering whole device\n", idx); - add_mtd_device(mtd_banks[idx]); - } else { - printk(KERN_NOTICE - "TQM834x flash bank %d: Using %s partition " - "definition\n", idx, part_banks[idx].type); - add_mtd_partitions(mtd_banks[idx], - part_banks[idx].mtd_part, - part_banks[idx].nums); - } - } -#else /* ! CONFIG_MTD_PARTITIONS */ - printk(KERN_NOTICE "TQM834x flash: registering %d flash banks " - "at once\n", num_banks); - - for(idx = 0 ; idx < num_banks ; idx++) - add_mtd_device(mtd_banks[idx]); - -#endif /* CONFIG_MTD_PARTITIONS */ - - return 0; -error_mem: - for (idx = 0 ; idx < FLASH_BANK_MAX ; idx++) { - if (map_banks[idx] != NULL) { - if (map_banks[idx]->name != NULL) { - kfree(map_banks[idx]->name); - map_banks[idx]->name = NULL; - } - kfree(map_banks[idx]); - map_banks[idx] = NULL; - } - } - - iounmap((void *)start_scan_addr); - - return ret; -} - -static void __exit cleanup_tqm834x_mtd(void) -{ - unsigned int idx = 0; - for(idx = 0 ; idx < num_banks ; idx++) { - /* destroy mtd_info previously allocated */ - if (mtd_banks[idx]) { - del_mtd_partitions(mtd_banks[idx]); - map_destroy(mtd_banks[idx]); - } - - /* release map_info not used anymore */ - kfree(map_banks[idx]->name); - kfree(map_banks[idx]); - } - - if (start_scan_addr) { - iounmap((void *)start_scan_addr); - start_scan_addr = 0; - } -} - -module_init(init_tqm834x_mtd); -module_exit(cleanup_tqm834x_mtd); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Wolfgang Denk <wd@denx.de>"); -MODULE_DESCRIPTION("MTD map driver for TQM834x boards"); diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index ef89780eb9d6..74d9d30edabd 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -24,10 +24,9 @@ #include <linux/kthread.h> #include <asm/uaccess.h> -static LIST_HEAD(blktrans_majors); +#include "mtdcore.h" -extern struct mutex mtd_table_mutex; -extern struct mtd_info *mtd_table[]; +static LIST_HEAD(blktrans_majors); struct mtd_blkcore_priv { struct task_struct *thread; @@ -202,7 +201,7 @@ static int blktrans_ioctl(struct inode *inode, struct file *file, } } -struct block_device_operations mtd_blktrans_ops = { +static struct block_device_operations mtd_blktrans_ops = { .owner = THIS_MODULE, .open = blktrans_open, .release = blktrans_release, diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index d091b2430b48..22ed96c4b7bd 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -136,7 +136,8 @@ static int mtd_close(struct inode *inode, struct file *file) DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n"); - if (mtd->sync) + /* Only sync if opened RW */ + if ((file->f_mode & 2) && mtd->sync) mtd->sync(mtd); put_mtd_device(mtd); diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index 41844ea02462..d563dcd4b264 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -178,7 +178,7 @@ concat_writev(struct mtd_info *mtd, const struct kvec *vecs, /* Check alignment */ if (mtd->writesize > 1) { - loff_t __to = to; + uint64_t __to = to; if (do_div(__to, mtd->writesize) || (total_len % mtd->writesize)) return -EINVAL; } @@ -726,6 +726,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c concat->mtd.size = subdev[0]->size; concat->mtd.erasesize = subdev[0]->erasesize; concat->mtd.writesize = subdev[0]->writesize; + concat->mtd.subpage_sft = subdev[0]->subpage_sft; concat->mtd.oobsize = subdev[0]->oobsize; concat->mtd.oobavail = subdev[0]->oobavail; if (subdev[0]->writev) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index c153b64a8300..6c2645e28371 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -22,6 +22,8 @@ #include <linux/mtd/mtd.h> +#include "mtdcore.h" + /* These are exported solely for the purpose of mtd_blkdevs.c. You should not use them for _anything_ else */ DEFINE_MUTEX(mtd_table_mutex); diff --git a/drivers/mtd/mtdcore.h b/drivers/mtd/mtdcore.h new file mode 100644 index 000000000000..a33251f4b872 --- /dev/null +++ b/drivers/mtd/mtdcore.h @@ -0,0 +1,11 @@ +/* linux/drivers/mtd/mtdcore.h + * + * Header file for driver private mtdcore exports + * + */ + +/* These are exported solely for the purpose of mtd_blkdevs.c. You + should not use them for _anything_ else */ + +extern struct mutex mtd_table_mutex; +extern struct mtd_info *mtd_table[MAX_MTD_DEVICES]; diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c new file mode 100644 index 000000000000..f8af627f0b98 --- /dev/null +++ b/drivers/mtd/mtdoops.c @@ -0,0 +1,376 @@ +/* + * MTD Oops/Panic logger + * + * Copyright (C) 2007 Nokia Corporation. All rights reserved. + * + * Author: Richard Purdie <rpurdie@openedhand.com> + * + * 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. + * + * 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 St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/console.h> +#include <linux/vmalloc.h> +#include <linux/workqueue.h> +#include <linux/sched.h> +#include <linux/wait.h> +#include <linux/mtd/mtd.h> + +#define OOPS_PAGE_SIZE 4096 + +static struct mtdoops_context { + int mtd_index; + struct work_struct work; + struct mtd_info *mtd; + int oops_pages; + int nextpage; + int nextcount; + + void *oops_buf; + int ready; + int writecount; +} oops_cxt; + +static void mtdoops_erase_callback(struct erase_info *done) +{ + wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv; + wake_up(wait_q); +} + +static int mtdoops_erase_block(struct mtd_info *mtd, int offset) +{ + struct erase_info erase; + DECLARE_WAITQUEUE(wait, current); + wait_queue_head_t wait_q; + int ret; + + init_waitqueue_head(&wait_q); + erase.mtd = mtd; + erase.callback = mtdoops_erase_callback; + erase.addr = offset; + if (mtd->erasesize < OOPS_PAGE_SIZE) + erase.len = OOPS_PAGE_SIZE; + else + erase.len = mtd->erasesize; + erase.priv = (u_long)&wait_q; + + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&wait_q, &wait); + + ret = mtd->erase(mtd, &erase); + if (ret) { + set_current_state(TASK_RUNNING); + remove_wait_queue(&wait_q, &wait); + printk (KERN_WARNING "mtdoops: erase of region [0x%x, 0x%x] " + "on \"%s\" failed\n", + erase.addr, erase.len, mtd->name); + return ret; + } + + schedule(); /* Wait for erase to finish. */ + remove_wait_queue(&wait_q, &wait); + + return 0; +} + +static int mtdoops_inc_counter(struct mtdoops_context *cxt) +{ + struct mtd_info *mtd = cxt->mtd; + size_t retlen; + u32 count; + int ret; + + cxt->nextpage++; + if (cxt->nextpage > cxt->oops_pages) + cxt->nextpage = 0; + cxt->nextcount++; + if (cxt->nextcount == 0xffffffff) + cxt->nextcount = 0; + + ret = mtd->read(mtd, cxt->nextpage * OOPS_PAGE_SIZE, 4, + &retlen, (u_char *) &count); + if ((retlen != 4) || (ret < 0)) { + printk(KERN_ERR "mtdoops: Read failure at %d (%td of 4 read)" + ", err %d.\n", cxt->nextpage * OOPS_PAGE_SIZE, + retlen, ret); + return 1; + } + + /* See if we need to erase the next block */ + if (count != 0xffffffff) + return 1; + + printk(KERN_DEBUG "mtdoops: Ready %d, %d (no erase)\n", + cxt->nextpage, cxt->nextcount); + cxt->ready = 1; + return 0; +} + +static void mtdoops_prepare(struct mtdoops_context *cxt) +{ + struct mtd_info *mtd = cxt->mtd; + int i = 0, j, ret, mod; + + /* We were unregistered */ + if (!mtd) + return; + + mod = (cxt->nextpage * OOPS_PAGE_SIZE) % mtd->erasesize; + if (mod != 0) { + cxt->nextpage = cxt->nextpage + ((mtd->erasesize - mod) / OOPS_PAGE_SIZE); + if (cxt->nextpage > cxt->oops_pages) + cxt->nextpage = 0; + } + + while (mtd->block_isbad && + mtd->block_isbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE)) { +badblock: + printk(KERN_WARNING "mtdoops: Bad block at %08x\n", + cxt->nextpage * OOPS_PAGE_SIZE); + i++; + cxt->nextpage = cxt->nextpage + (mtd->erasesize / OOPS_PAGE_SIZE); + if (cxt->nextpage > cxt->oops_pages) + cxt->nextpage = 0; + if (i == (cxt->oops_pages / (mtd->erasesize / OOPS_PAGE_SIZE))) { + printk(KERN_ERR "mtdoops: All blocks bad!\n"); + return; + } + } + + for (j = 0, ret = -1; (j < 3) && (ret < 0); j++) + ret = mtdoops_erase_block(mtd, cxt->nextpage * OOPS_PAGE_SIZE); + + if (ret < 0) { + if (mtd->block_markbad) + mtd->block_markbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE); + goto badblock; + } + + printk(KERN_DEBUG "mtdoops: Ready %d, %d \n", cxt->nextpage, cxt->nextcount); + + cxt->ready = 1; +} + +static void mtdoops_workfunc(struct work_struct *work) +{ + struct mtdoops_context *cxt = + container_of(work, struct mtdoops_context, work); + + mtdoops_prepare(cxt); +} + +static int find_next_position(struct mtdoops_context *cxt) +{ + struct mtd_info *mtd = cxt->mtd; + int page, maxpos = 0; + u32 count, maxcount = 0xffffffff; + size_t retlen; + + for (page = 0; page < cxt->oops_pages; page++) { + mtd->read(mtd, page * OOPS_PAGE_SIZE, 4, &retlen, (u_char *) &count); + if (count == 0xffffffff) + continue; + if (maxcount == 0xffffffff) { + maxcount = count; + maxpos = page; + } else if ((count < 0x40000000) && (maxcount > 0xc0000000)) { + maxcount = count; + maxpos = page; + } else if ((count > maxcount) && (count < 0xc0000000)) { + maxcount = count; + maxpos = page; + } else if ((count > maxcount) && (count > 0xc0000000) + && (maxcount > 0x80000000)) { + maxcount = count; + maxpos = page; + } + } + if (maxcount == 0xffffffff) { + cxt->nextpage = 0; + cxt->nextcount = 1; + cxt->ready = 1; + printk(KERN_DEBUG "mtdoops: Ready %d, %d (first init)\n", + cxt->nextpage, cxt->nextcount); + return 0; + } + + cxt->nextpage = maxpos; + cxt->nextcount = maxcount; + + return mtdoops_inc_counter(cxt); +} + + +static void mtdoops_notify_add(struct mtd_info *mtd) +{ + struct mtdoops_context *cxt = &oops_cxt; + int ret; + + if ((mtd->index != cxt->mtd_index) || cxt->mtd_index < 0) + return; + + if (mtd->size < (mtd->erasesize * 2)) { + printk(KERN_ERR "MTD partition %d not big enough for mtdoops\n", + mtd->index); + return; + } + + cxt->mtd = mtd; + cxt->oops_pages = mtd->size / OOPS_PAGE_SIZE; + + ret = find_next_position(cxt); + if (ret == 1) + mtdoops_prepare(cxt); + + printk(KERN_DEBUG "mtdoops: Attached to MTD device %d\n", mtd->index); +} + +static void mtdoops_notify_remove(struct mtd_info *mtd) +{ + struct mtdoops_context *cxt = &oops_cxt; + + if ((mtd->index != cxt->mtd_index) || cxt->mtd_index < 0) + return; + + cxt->mtd = NULL; + flush_scheduled_work(); +} + +static void mtdoops_console_sync(void) +{ + struct mtdoops_context *cxt = &oops_cxt; + struct mtd_info *mtd = cxt->mtd; + size_t retlen; + int ret; + + if (!cxt->ready || !mtd) + return; + + if (cxt->writecount == 0) + return; + + if (cxt->writecount < OOPS_PAGE_SIZE) + memset(cxt->oops_buf + cxt->writecount, 0xff, + OOPS_PAGE_SIZE - cxt->writecount); + + ret = mtd->write(mtd, cxt->nextpage * OOPS_PAGE_SIZE, + OOPS_PAGE_SIZE, &retlen, cxt->oops_buf); + cxt->ready = 0; + cxt->writecount = 0; + + if ((retlen != OOPS_PAGE_SIZE) || (ret < 0)) + printk(KERN_ERR "mtdoops: Write failure at %d (%td of %d written), err %d.\n", + cxt->nextpage * OOPS_PAGE_SIZE, retlen, OOPS_PAGE_SIZE, ret); + + ret = mtdoops_inc_counter(cxt); + if (ret == 1) + schedule_work(&cxt->work); +} + +static void +mtdoops_console_write(struct console *co, const char *s, unsigned int count) +{ + struct mtdoops_context *cxt = co->data; + struct mtd_info *mtd = cxt->mtd; + int i; + + if (!oops_in_progress) { + mtdoops_console_sync(); + return; + } + + if (!cxt->ready || !mtd) + return; + + if (cxt->writecount == 0) { + u32 *stamp = cxt->oops_buf; + *stamp = cxt->nextcount; + cxt->writecount = 4; + } + + if ((count + cxt->writecount) > OOPS_PAGE_SIZE) + count = OOPS_PAGE_SIZE - cxt->writecount; + + for (i = 0; i < count; i++, s++) + *((char *)(cxt->oops_buf) + cxt->writecount + i) = *s; + + cxt->writecount = cxt->writecount + count; +} + +static int __init mtdoops_console_setup(struct console *co, char *options) +{ + struct mtdoops_context *cxt = co->data; + + if (cxt->mtd_index != -1) + return -EBUSY; + if (co->index == -1) + return -EINVAL; + + cxt->mtd_index = co->index; + return 0; +} + +static struct mtd_notifier mtdoops_notifier = { + .add = mtdoops_notify_add, + .remove = mtdoops_notify_remove, +}; + +static struct console mtdoops_console = { + .name = "ttyMTD", + .write = mtdoops_console_write, + .setup = mtdoops_console_setup, + .unblank = mtdoops_console_sync, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &oops_cxt, +}; + +static int __init mtdoops_console_init(void) +{ + struct mtdoops_context *cxt = &oops_cxt; + + cxt->mtd_index = -1; + cxt->oops_buf = vmalloc(OOPS_PAGE_SIZE); + + if (!cxt->oops_buf) { + printk(KERN_ERR "Failed to allocate oops buffer workspace\n"); + return -ENOMEM; + } + + INIT_WORK(&cxt->work, mtdoops_workfunc); + + register_console(&mtdoops_console); + register_mtd_user(&mtdoops_notifier); + return 0; +} + +static void __exit mtdoops_console_exit(void) +{ + struct mtdoops_context *cxt = &oops_cxt; + + unregister_mtd_user(&mtdoops_notifier); + unregister_console(&mtdoops_console); + vfree(cxt->oops_buf); +} + + +subsys_initcall(mtdoops_console_init); +module_exit(mtdoops_console_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>"); +MODULE_DESCRIPTION("MTD Oops/Panic console logger/driver"); diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index f1d60b6f048e..8f9c3baeb38e 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -91,6 +91,25 @@ config MTD_NAND_AU1550 This enables the driver for the NAND flash controller on the AMD/Alchemy 1550 SOC. +config MTD_NAND_BF5XX + tristate "Blackfin on-chip NAND Flash Controller driver" + depends on BF54x && MTD_NAND + help + This enables the Blackfin on-chip NAND flash controller + + No board specific support is done by this driver, each board + must advertise a platform_device for the driver to attach. + + This driver can also be built as a module. If so, the module + will be called bf5xx-nand. + +config MTD_NAND_BF5XX_HWECC + bool "BF5XX NAND Hardware ECC" + depends on MTD_NAND_BF5XX + help + Enable the use of the BF5XX's internal ECC generator when + using NAND. + config MTD_NAND_RTC_FROM4 tristate "Renesas Flash ROM 4-slot interface board (FROM_BOARD4)" depends on SH_SOLUTION_ENGINE @@ -134,10 +153,10 @@ config MTD_NAND_S3C2410_HWECC config MTD_NAND_NDFC tristate "NDFC NanD Flash Controller" - depends on 44x + depends on 4xx && !PPC_MERGE select MTD_NAND_ECC_SMC help - NDFC Nand Flash Controllers are integrated in EP44x SoCs + NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs config MTD_NAND_S3C2410_CLKSTOP bool "S3C2410 NAND IDLE clock stop" @@ -237,7 +256,7 @@ config MTD_NAND_CAFE select REED_SOLOMON select REED_SOLOMON_DEC16 help - Use NAND flash attached to the CAFÉ chip designed for the $100 + Use NAND flash attached to the CAFÉ chip designed for the OLPC laptop. config MTD_NAND_CS553X @@ -280,5 +299,11 @@ config MTD_NAND_PLATFORM devices. You will need to provide platform-specific functions via platform_data. +config MTD_ALAUDA + tristate "MTD driver for Olympus MAUSB-10 and Fijufilm DPC-R1" + depends on MTD_NAND && USB + help + These two (and possibly other) Alauda-based cardreaders for + SmartMedia and xD allow raw flash access. endif # MTD_NAND diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index edba1db14bfa..3ad6c0165da3 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_MTD_NAND_TOTO) += toto.o obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o +obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o @@ -27,5 +28,6 @@ obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o +obj-$(CONFIG_MTD_ALAUDA) += alauda.o nand-objs := nand_base.o nand_bbt.o diff --git a/drivers/mtd/nand/alauda.c b/drivers/mtd/nand/alauda.c new file mode 100644 index 000000000000..257937cd99bf --- /dev/null +++ b/drivers/mtd/nand/alauda.c @@ -0,0 +1,742 @@ +/* + * MTD driver for Alauda chips + * + * Copyright (C) 2007 Joern Engel <joern@logfs.org> + * + * Based on drivers/usb/usb-skeleton.c which is: + * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) + * and on drivers/usb/storage/alauda.c, which is: + * (c) 2005 Daniel Drake <dsd@gentoo.org> + * + * Idea and initial work by Arnd Bergmann <arnd@arndb.de> + */ +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/kref.h> +#include <linux/usb.h> +#include <linux/mutex.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand_ecc.h> + +/* Control commands */ +#define ALAUDA_GET_XD_MEDIA_STATUS 0x08 +#define ALAUDA_ACK_XD_MEDIA_CHANGE 0x0a +#define ALAUDA_GET_XD_MEDIA_SIG 0x86 + +/* Common prefix */ +#define ALAUDA_BULK_CMD 0x40 + +/* The two ports */ +#define ALAUDA_PORT_XD 0x00 +#define ALAUDA_PORT_SM 0x01 + +/* Bulk commands */ +#define ALAUDA_BULK_READ_PAGE 0x84 +#define ALAUDA_BULK_READ_OOB 0x85 /* don't use, there's a chip bug */ +#define ALAUDA_BULK_READ_BLOCK 0x94 +#define ALAUDA_BULK_ERASE_BLOCK 0xa3 +#define ALAUDA_BULK_WRITE_PAGE 0xa4 +#define ALAUDA_BULK_WRITE_BLOCK 0xb4 +#define ALAUDA_BULK_RESET_MEDIA 0xe0 + +/* Address shifting */ +#define PBA_LO(pba) ((pba & 0xF) << 5) +#define PBA_HI(pba) (pba >> 3) +#define PBA_ZONE(pba) (pba >> 11) + +#define TIMEOUT HZ + +static struct usb_device_id alauda_table [] = { + { USB_DEVICE(0x0584, 0x0008) }, /* Fujifilm DPC-R1 */ + { USB_DEVICE(0x07b4, 0x010a) }, /* Olympus MAUSB-10 */ + { } +}; +MODULE_DEVICE_TABLE(usb, alauda_table); + +struct alauda_card { + u8 id; /* id byte */ + u8 chipshift; /* 1<<chipshift total size */ + u8 pageshift; /* 1<<pageshift page size */ + u8 blockshift; /* 1<<blockshift block size */ +}; + +struct alauda { + struct usb_device *dev; + struct usb_interface *interface; + struct mtd_info *mtd; + struct alauda_card *card; + struct mutex card_mutex; + u32 pagemask; + u32 bytemask; + u32 blockmask; + unsigned int write_out; + unsigned int bulk_in; + unsigned int bulk_out; + u8 port; + struct kref kref; +}; + +static struct alauda_card alauda_card_ids[] = { + /* NAND flash */ + { 0x6e, 20, 8, 12}, /* 1 MB */ + { 0xe8, 20, 8, 12}, /* 1 MB */ + { 0xec, 20, 8, 12}, /* 1 MB */ + { 0x64, 21, 8, 12}, /* 2 MB */ + { 0xea, 21, 8, 12}, /* 2 MB */ + { 0x6b, 22, 9, 13}, /* 4 MB */ + { 0xe3, 22, 9, 13}, /* 4 MB */ + { 0xe5, 22, 9, 13}, /* 4 MB */ + { 0xe6, 23, 9, 13}, /* 8 MB */ + { 0x73, 24, 9, 14}, /* 16 MB */ + { 0x75, 25, 9, 14}, /* 32 MB */ + { 0x76, 26, 9, 14}, /* 64 MB */ + { 0x79, 27, 9, 14}, /* 128 MB */ + { 0x71, 28, 9, 14}, /* 256 MB */ + + /* MASK ROM */ + { 0x5d, 21, 9, 13}, /* 2 MB */ + { 0xd5, 22, 9, 13}, /* 4 MB */ + { 0xd6, 23, 9, 13}, /* 8 MB */ + { 0x57, 24, 9, 13}, /* 16 MB */ + { 0x58, 25, 9, 13}, /* 32 MB */ + { } +}; + +static struct alauda_card *get_card(u8 id) +{ + struct alauda_card *card; + + for (card = alauda_card_ids; card->id; card++) + if (card->id == id) + return card; + return NULL; +} + +static void alauda_delete(struct kref *kref) +{ + struct alauda *al = container_of(kref, struct alauda, kref); + + if (al->mtd) { + del_mtd_device(al->mtd); + kfree(al->mtd); + } + usb_put_dev(al->dev); + kfree(al); +} + +static int alauda_get_media_status(struct alauda *al, void *buf) +{ + int ret; + + mutex_lock(&al->card_mutex); + ret = usb_control_msg(al->dev, usb_rcvctrlpipe(al->dev, 0), + ALAUDA_GET_XD_MEDIA_STATUS, 0xc0, 0, 1, buf, 2, HZ); + mutex_unlock(&al->card_mutex); + return ret; +} + +static int alauda_ack_media(struct alauda *al) +{ + int ret; + + mutex_lock(&al->card_mutex); + ret = usb_control_msg(al->dev, usb_sndctrlpipe(al->dev, 0), + ALAUDA_ACK_XD_MEDIA_CHANGE, 0x40, 0, 1, NULL, 0, HZ); + mutex_unlock(&al->card_mutex); + return ret; +} + +static int alauda_get_media_signatures(struct alauda *al, void *buf) +{ + int ret; + + mutex_lock(&al->card_mutex); + ret = usb_control_msg(al->dev, usb_rcvctrlpipe(al->dev, 0), + ALAUDA_GET_XD_MEDIA_SIG, 0xc0, 0, 0, buf, 4, HZ); + mutex_unlock(&al->card_mutex); + return ret; +} + +static void alauda_reset(struct alauda *al) +{ + u8 command[] = { + ALAUDA_BULK_CMD, ALAUDA_BULK_RESET_MEDIA, 0, 0, + 0, 0, 0, 0, al->port + }; + mutex_lock(&al->card_mutex); + usb_bulk_msg(al->dev, al->bulk_out, command, 9, NULL, HZ); + mutex_unlock(&al->card_mutex); +} + +static void correct_data(void *buf, void *read_ecc, + int *corrected, int *uncorrected) +{ + u8 calc_ecc[3]; + int err; + + nand_calculate_ecc(NULL, buf, calc_ecc); + err = nand_correct_data(NULL, buf, read_ecc, calc_ecc); + if (err) { + if (err > 0) + (*corrected)++; + else + (*uncorrected)++; + } +} + +struct alauda_sg_request { + struct urb *urb[3]; + struct completion comp; +}; + +static void alauda_complete(struct urb *urb) +{ + struct completion *comp = urb->context; + + if (comp) + complete(comp); +} + +static int __alauda_read_page(struct mtd_info *mtd, loff_t from, void *buf, + void *oob) +{ + struct alauda_sg_request sg; + struct alauda *al = mtd->priv; + u32 pba = from >> al->card->blockshift; + u32 page = (from >> al->card->pageshift) & al->pagemask; + u8 command[] = { + ALAUDA_BULK_CMD, ALAUDA_BULK_READ_PAGE, PBA_HI(pba), + PBA_ZONE(pba), 0, PBA_LO(pba) + page, 1, 0, al->port + }; + int i, err; + + for (i=0; i<3; i++) + sg.urb[i] = NULL; + + err = -ENOMEM; + for (i=0; i<3; i++) { + sg.urb[i] = usb_alloc_urb(0, GFP_NOIO); + if (!sg.urb[i]) + goto out; + } + init_completion(&sg.comp); + usb_fill_bulk_urb(sg.urb[0], al->dev, al->bulk_out, command, 9, + alauda_complete, NULL); + usb_fill_bulk_urb(sg.urb[1], al->dev, al->bulk_in, buf, mtd->writesize, + alauda_complete, NULL); + usb_fill_bulk_urb(sg.urb[2], al->dev, al->bulk_in, oob, 16, + alauda_complete, &sg.comp); + + mutex_lock(&al->card_mutex); + for (i=0; i<3; i++) { + err = usb_submit_urb(sg.urb[i], GFP_NOIO); + if (err) + goto cancel; + } + if (!wait_for_completion_timeout(&sg.comp, TIMEOUT)) { + err = -ETIMEDOUT; +cancel: + for (i=0; i<3; i++) { + usb_kill_urb(sg.urb[i]); + } + } + mutex_unlock(&al->card_mutex); + +out: + usb_free_urb(sg.urb[0]); + usb_free_urb(sg.urb[1]); + usb_free_urb(sg.urb[2]); + return err; +} + +static int alauda_read_page(struct mtd_info *mtd, loff_t from, + void *buf, u8 *oob, int *corrected, int *uncorrected) +{ + int err; + + err = __alauda_read_page(mtd, from, buf, oob); + if (err) + return err; + correct_data(buf, oob+13, corrected, uncorrected); + correct_data(buf+256, oob+8, corrected, uncorrected); + return 0; +} + +static int alauda_write_page(struct mtd_info *mtd, loff_t to, void *buf, + void *oob) +{ + struct alauda_sg_request sg; + struct alauda *al = mtd->priv; + u32 pba = to >> al->card->blockshift; + u32 page = (to >> al->card->pageshift) & al->pagemask; + u8 command[] = { + ALAUDA_BULK_CMD, ALAUDA_BULK_WRITE_PAGE, PBA_HI(pba), + PBA_ZONE(pba), 0, PBA_LO(pba) + page, 32, 0, al->port + }; + int i, err; + + for (i=0; i<3; i++) + sg.urb[i] = NULL; + + err = -ENOMEM; + for (i=0; i<3; i++) { + sg.urb[i] = usb_alloc_urb(0, GFP_NOIO); + if (!sg.urb[i]) + goto out; + } + init_completion(&sg.comp); + usb_fill_bulk_urb(sg.urb[0], al->dev, al->bulk_out, command, 9, + alauda_complete, NULL); + usb_fill_bulk_urb(sg.urb[1], al->dev, al->write_out, buf,mtd->writesize, + alauda_complete, NULL); + usb_fill_bulk_urb(sg.urb[2], al->dev, al->write_out, oob, 16, + alauda_complete, &sg.comp); + + mutex_lock(&al->card_mutex); + for (i=0; i<3; i++) { + err = usb_submit_urb(sg.urb[i], GFP_NOIO); + if (err) + goto cancel; + } + if (!wait_for_completion_timeout(&sg.comp, TIMEOUT)) { + err = -ETIMEDOUT; +cancel: + for (i=0; i<3; i++) { + usb_kill_urb(sg.urb[i]); + } + } + mutex_unlock(&al->card_mutex); + +out: + usb_free_urb(sg.urb[0]); + usb_free_urb(sg.urb[1]); + usb_free_urb(sg.urb[2]); + return err; +} + +static int alauda_erase_block(struct mtd_info *mtd, loff_t ofs) +{ + struct alauda_sg_request sg; + struct alauda *al = mtd->priv; + u32 pba = ofs >> al->card->blockshift; + u8 command[] = { + ALAUDA_BULK_CMD, ALAUDA_BULK_ERASE_BLOCK, PBA_HI(pba), + PBA_ZONE(pba), 0, PBA_LO(pba), 0x02, 0, al->port + }; + u8 buf[2]; + int i, err; + + for (i=0; i<2; i++) + sg.urb[i] = NULL; + + err = -ENOMEM; + for (i=0; i<2; i++) { + sg.urb[i] = usb_alloc_urb(0, GFP_NOIO); + if (!sg.urb[i]) + goto out; + } + init_completion(&sg.comp); + usb_fill_bulk_urb(sg.urb[0], al->dev, al->bulk_out, command, 9, + alauda_complete, NULL); + usb_fill_bulk_urb(sg.urb[1], al->dev, al->bulk_in, buf, 2, + alauda_complete, &sg.comp); + + mutex_lock(&al->card_mutex); + for (i=0; i<2; i++) { + err = usb_submit_urb(sg.urb[i], GFP_NOIO); + if (err) + goto cancel; + } + if (!wait_for_completion_timeout(&sg.comp, TIMEOUT)) { + err = -ETIMEDOUT; +cancel: + for (i=0; i<2; i++) { + usb_kill_urb(sg.urb[i]); + } + } + mutex_unlock(&al->card_mutex); + +out: + usb_free_urb(sg.urb[0]); + usb_free_urb(sg.urb[1]); + return err; +} + +static int alauda_read_oob(struct mtd_info *mtd, loff_t from, void *oob) +{ + static u8 ignore_buf[512]; /* write only */ + + return __alauda_read_page(mtd, from, ignore_buf, oob); +} + +static int popcount8(u8 c) +{ + int ret = 0; + + for ( ; c; c>>=1) + ret += c & 1; + return ret; +} + +static int alauda_isbad(struct mtd_info *mtd, loff_t ofs) +{ + u8 oob[16]; + int err; + + err = alauda_read_oob(mtd, ofs, oob); + if (err) + return err; + + /* A block is marked bad if two or more bits are zero */ + return popcount8(oob[5]) >= 7 ? 0 : 1; +} + +static int alauda_bounce_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct alauda *al = mtd->priv; + void *bounce_buf; + int err, corrected=0, uncorrected=0; + + bounce_buf = kmalloc(mtd->writesize, GFP_KERNEL); + if (!bounce_buf) + return -ENOMEM; + + *retlen = len; + while (len) { + u8 oob[16]; + size_t byte = from & al->bytemask; + size_t cplen = min(len, mtd->writesize - byte); + + err = alauda_read_page(mtd, from, bounce_buf, oob, + &corrected, &uncorrected); + if (err) + goto out; + + memcpy(buf, bounce_buf + byte, cplen); + buf += cplen; + from += cplen; + len -= cplen; + } + err = 0; + if (corrected) + err = -EUCLEAN; + if (uncorrected) + err = -EBADMSG; +out: + kfree(bounce_buf); + return err; +} + +static int alauda_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct alauda *al = mtd->priv; + int err, corrected=0, uncorrected=0; + + if ((from & al->bytemask) || (len & al->bytemask)) + return alauda_bounce_read(mtd, from, len, retlen, buf); + + *retlen = len; + while (len) { + u8 oob[16]; + + err = alauda_read_page(mtd, from, buf, oob, + &corrected, &uncorrected); + if (err) + return err; + + buf += mtd->writesize; + from += mtd->writesize; + len -= mtd->writesize; + } + err = 0; + if (corrected) + err = -EUCLEAN; + if (uncorrected) + err = -EBADMSG; + return err; +} + +static int alauda_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct alauda *al = mtd->priv; + int err; + + if ((to & al->bytemask) || (len & al->bytemask)) + return -EINVAL; + + *retlen = len; + while (len) { + u32 page = (to >> al->card->pageshift) & al->pagemask; + u8 oob[16] = { 'h', 'e', 'l', 'l', 'o', 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + /* don't write to bad blocks */ + if (page == 0) { + err = alauda_isbad(mtd, to); + if (err) { + return -EIO; + } + } + nand_calculate_ecc(mtd, buf, &oob[13]); + nand_calculate_ecc(mtd, buf+256, &oob[8]); + + err = alauda_write_page(mtd, to, (void*)buf, oob); + if (err) + return err; + + buf += mtd->writesize; + to += mtd->writesize; + len -= mtd->writesize; + } + return 0; +} + +static int __alauda_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + struct alauda *al = mtd->priv; + u32 ofs = instr->addr; + u32 len = instr->len; + int err; + + if ((ofs & al->blockmask) || (len & al->blockmask)) + return -EINVAL; + + while (len) { + /* don't erase bad blocks */ + err = alauda_isbad(mtd, ofs); + if (err > 0) + err = -EIO; + if (err < 0) + return err; + + err = alauda_erase_block(mtd, ofs); + if (err < 0) + return err; + + ofs += mtd->erasesize; + len -= mtd->erasesize; + } + return 0; +} + +static int alauda_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + int err; + + err = __alauda_erase(mtd, instr); + instr->state = err ? MTD_ERASE_FAILED : MTD_ERASE_DONE; + mtd_erase_callback(instr); + return err; +} + +static int alauda_init_media(struct alauda *al) +{ + u8 buf[4], *b0=buf, *b1=buf+1; + struct alauda_card *card; + struct mtd_info *mtd; + int err; + + mtd = kzalloc(sizeof(*mtd), GFP_KERNEL); + if (!mtd) + return -ENOMEM; + + for (;;) { + err = alauda_get_media_status(al, buf); + if (err < 0) + goto error; + if (*b0 & 0x10) + break; + msleep(20); + } + + err = alauda_ack_media(al); + if (err) + goto error; + + msleep(10); + + err = alauda_get_media_status(al, buf); + if (err < 0) + goto error; + + if (*b0 != 0x14) { + /* media not ready */ + err = -EIO; + goto error; + } + err = alauda_get_media_signatures(al, buf); + if (err < 0) + goto error; + + card = get_card(*b1); + if (!card) { + printk(KERN_ERR"Alauda: unknown card id %02x\n", *b1); + err = -EIO; + goto error; + } + printk(KERN_INFO"pagesize=%x\nerasesize=%x\nsize=%xMiB\n", + 1<<card->pageshift, 1<<card->blockshift, + 1<<(card->chipshift-20)); + al->card = card; + al->pagemask = (1 << (card->blockshift - card->pageshift)) - 1; + al->bytemask = (1 << card->pageshift) - 1; + al->blockmask = (1 << card->blockshift) - 1; + + mtd->name = "alauda"; + mtd->size = 1<<card->chipshift; + mtd->erasesize = 1<<card->blockshift; + mtd->writesize = 1<<card->pageshift; + mtd->type = MTD_NANDFLASH; + mtd->flags = MTD_CAP_NANDFLASH; + mtd->read = alauda_read; + mtd->write = alauda_write; + mtd->erase = alauda_erase; + mtd->block_isbad = alauda_isbad; + mtd->priv = al; + mtd->owner = THIS_MODULE; + + err = add_mtd_device(mtd); + if (err) { + err = -ENFILE; + goto error; + } + + al->mtd = mtd; + alauda_reset(al); /* no clue whether this is necessary */ + return 0; +error: + kfree(mtd); + return err; +} + +static int alauda_check_media(struct alauda *al) +{ + u8 buf[2], *b0 = buf, *b1 = buf+1; + int err; + + err = alauda_get_media_status(al, buf); + if (err < 0) + return err; + + if ((*b1 & 0x01) == 0) { + /* door open */ + return -EIO; + } + if ((*b0 & 0x80) || ((*b0 & 0x1F) == 0x10)) { + /* no media ? */ + return -EIO; + } + if (*b0 & 0x08) { + /* media change ? */ + return alauda_init_media(al); + } + return 0; +} + +static int alauda_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct alauda *al; + struct usb_host_interface *iface; + struct usb_endpoint_descriptor *ep, + *ep_in=NULL, *ep_out=NULL, *ep_wr=NULL; + int i, err = -ENOMEM; + + al = kzalloc(2*sizeof(*al), GFP_KERNEL); + if (!al) + goto error; + + kref_init(&al->kref); + usb_set_intfdata(interface, al); + + al->dev = usb_get_dev(interface_to_usbdev(interface)); + al->interface = interface; + + iface = interface->cur_altsetting; + for (i = 0; i < iface->desc.bNumEndpoints; ++i) { + ep = &iface->endpoint[i].desc; + + if (usb_endpoint_is_bulk_in(ep)) { + ep_in = ep; + } else if (usb_endpoint_is_bulk_out(ep)) { + if (i==0) + ep_wr = ep; + else + ep_out = ep; + } + } + err = -EIO; + if (!ep_wr || !ep_in || !ep_out) + goto error; + + al->write_out = usb_sndbulkpipe(al->dev, + ep_wr->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + al->bulk_in = usb_rcvbulkpipe(al->dev, + ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + al->bulk_out = usb_sndbulkpipe(al->dev, + ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + + /* second device is identical up to now */ + memcpy(al+1, al, sizeof(*al)); + + mutex_init(&al[0].card_mutex); + mutex_init(&al[1].card_mutex); + + al[0].port = ALAUDA_PORT_XD; + al[1].port = ALAUDA_PORT_SM; + + info("alauda probed"); + alauda_check_media(al); + alauda_check_media(al+1); + + return 0; + +error: + if (al) + kref_put(&al->kref, alauda_delete); + return err; +} + +static void alauda_disconnect(struct usb_interface *interface) +{ + struct alauda *al; + + al = usb_get_intfdata(interface); + usb_set_intfdata(interface, NULL); + + /* FIXME: prevent more I/O from starting */ + + /* decrement our usage count */ + if (al) + kref_put(&al->kref, alauda_delete); + + info("alauda gone"); +} + +static struct usb_driver alauda_driver = { + .name = "alauda", + .probe = alauda_probe, + .disconnect = alauda_disconnect, + .id_table = alauda_table, +}; + +static int __init alauda_init(void) +{ + return usb_register(&alauda_driver); +} + +static void __exit alauda_exit(void) +{ + usb_deregister(&alauda_driver); +} + +module_init(alauda_init); +module_exit(alauda_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c new file mode 100644 index 000000000000..1657ecd74881 --- /dev/null +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -0,0 +1,788 @@ +/* linux/drivers/mtd/nand/bf5xx_nand.c + * + * Copyright 2006-2007 Analog Devices Inc. + * http://blackfin.uclinux.org/ + * Bryan Wu <bryan.wu@analog.com> + * + * Blackfin BF5xx on-chip NAND flash controler driver + * + * Derived from drivers/mtd/nand/s3c2410.c + * Copyright (c) 2007 Ben Dooks <ben@simtec.co.uk> + * + * Derived from drivers/mtd/nand/cafe.c + * Copyright © 2006 Red Hat, Inc. + * Copyright © 2006 David Woodhouse <dwmw2@infradead.org> + * + * Changelog: + * 12-Jun-2007 Bryan Wu: Initial version + * 18-Jul-2007 Bryan Wu: + * - ECC_HW and ECC_SW supported + * - DMA supported in ECC_HW + * - YAFFS tested as rootfs in both ECC_HW and ECC_SW + * + * TODO: + * Enable JFFS2 over NAND as rootfs + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/ioport.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/bitops.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/nand_ecc.h> +#include <linux/mtd/partitions.h> + +#include <asm/blackfin.h> +#include <asm/dma.h> +#include <asm/cacheflush.h> +#include <asm/nand.h> +#include <asm/portmux.h> + +#define DRV_NAME "bf5xx-nand" +#define DRV_VERSION "1.2" +#define DRV_AUTHOR "Bryan Wu <bryan.wu@analog.com>" +#define DRV_DESC "BF5xx on-chip NAND FLash Controller Driver" + +#ifdef CONFIG_MTD_NAND_BF5XX_HWECC +static int hardware_ecc = 1; +#else +static int hardware_ecc; +#endif + +static unsigned short bfin_nfc_pin_req[] = {P_NAND_CE, P_NAND_RB, 0}; + +/* + * Data structures for bf5xx nand flash controller driver + */ + +/* bf5xx nand info */ +struct bf5xx_nand_info { + /* mtd info */ + struct nand_hw_control controller; + struct mtd_info mtd; + struct nand_chip chip; + + /* platform info */ + struct bf5xx_nand_platform *platform; + + /* device info */ + struct device *device; + + /* DMA stuff */ + struct completion dma_completion; +}; + +/* + * Conversion functions + */ +static struct bf5xx_nand_info *mtd_to_nand_info(struct mtd_info *mtd) +{ + return container_of(mtd, struct bf5xx_nand_info, mtd); +} + +static struct bf5xx_nand_info *to_nand_info(struct platform_device *pdev) +{ + return platform_get_drvdata(pdev); +} + +static struct bf5xx_nand_platform *to_nand_plat(struct platform_device *pdev) +{ + return pdev->dev.platform_data; +} + +/* + * struct nand_chip interface function pointers + */ + +/* + * bf5xx_nand_hwcontrol + * + * Issue command and address cycles to the chip + */ +static void bf5xx_nand_hwcontrol(struct mtd_info *mtd, int cmd, + unsigned int ctrl) +{ + if (cmd == NAND_CMD_NONE) + return; + + while (bfin_read_NFC_STAT() & WB_FULL) + cpu_relax(); + + if (ctrl & NAND_CLE) + bfin_write_NFC_CMD(cmd); + else + bfin_write_NFC_ADDR(cmd); + SSYNC(); +} + +/* + * bf5xx_nand_devready() + * + * returns 0 if the nand is busy, 1 if it is ready + */ +static int bf5xx_nand_devready(struct mtd_info *mtd) +{ + unsigned short val = bfin_read_NFC_IRQSTAT(); + + if ((val & NBUSYIRQ) == NBUSYIRQ) + return 1; + else + return 0; +} + +/* + * ECC functions + * These allow the bf5xx to use the controller's ECC + * generator block to ECC the data as it passes through + */ + +/* + * ECC error correction function + */ +static int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat, + u_char *read_ecc, u_char *calc_ecc) +{ + struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); + u32 syndrome[5]; + u32 calced, stored; + int i; + unsigned short failing_bit, failing_byte; + u_char data; + + calced = calc_ecc[0] | (calc_ecc[1] << 8) | (calc_ecc[2] << 16); + stored = read_ecc[0] | (read_ecc[1] << 8) | (read_ecc[2] << 16); + + syndrome[0] = (calced ^ stored); + + /* + * syndrome 0: all zero + * No error in data + * No action + */ + if (!syndrome[0] || !calced || !stored) + return 0; + + /* + * sysdrome 0: only one bit is one + * ECC data was incorrect + * No action + */ + if (hweight32(syndrome[0]) == 1) { + dev_err(info->device, "ECC data was incorrect!\n"); + return 1; + } + + syndrome[1] = (calced & 0x7FF) ^ (stored & 0x7FF); + syndrome[2] = (calced & 0x7FF) ^ ((calced >> 11) & 0x7FF); + syndrome[3] = (stored & 0x7FF) ^ ((stored >> 11) & 0x7FF); + syndrome[4] = syndrome[2] ^ syndrome[3]; + + for (i = 0; i < 5; i++) + dev_info(info->device, "syndrome[%d] 0x%08x\n", i, syndrome[i]); + + dev_info(info->device, + "calced[0x%08x], stored[0x%08x]\n", + calced, stored); + + /* + * sysdrome 0: exactly 11 bits are one, each parity + * and parity' pair is 1 & 0 or 0 & 1. + * 1-bit correctable error + * Correct the error + */ + if (hweight32(syndrome[0]) == 11 && syndrome[4] == 0x7FF) { + dev_info(info->device, + "1-bit correctable error, correct it.\n"); + dev_info(info->device, + "syndrome[1] 0x%08x\n", syndrome[1]); + + failing_bit = syndrome[1] & 0x7; + failing_byte = syndrome[1] >> 0x3; + data = *(dat + failing_byte); + data = data ^ (0x1 << failing_bit); + *(dat + failing_byte) = data; + + return 0; + } + + /* + * sysdrome 0: random data + * More than 1-bit error, non-correctable error + * Discard data, mark bad block + */ + dev_err(info->device, + "More than 1-bit error, non-correctable error.\n"); + dev_err(info->device, + "Please discard data, mark bad block\n"); + + return 1; +} + +static int bf5xx_nand_correct_data(struct mtd_info *mtd, u_char *dat, + u_char *read_ecc, u_char *calc_ecc) +{ + struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); + struct bf5xx_nand_platform *plat = info->platform; + unsigned short page_size = (plat->page_size ? 512 : 256); + int ret; + + ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc); + + /* If page size is 512, correct second 256 bytes */ + if (page_size == 512) { + dat += 256; + read_ecc += 8; + calc_ecc += 8; + ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc); + } + + return ret; +} + +static void bf5xx_nand_enable_hwecc(struct mtd_info *mtd, int mode) +{ + return; +} + +static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd, + const u_char *dat, u_char *ecc_code) +{ + struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); + struct bf5xx_nand_platform *plat = info->platform; + u16 page_size = (plat->page_size ? 512 : 256); + u16 ecc0, ecc1; + u32 code[2]; + u8 *p; + int bytes = 3, i; + + /* first 4 bytes ECC code for 256 page size */ + ecc0 = bfin_read_NFC_ECC0(); + ecc1 = bfin_read_NFC_ECC1(); + + code[0] = (ecc0 & 0x3FF) | ((ecc1 & 0x3FF) << 11); + + dev_dbg(info->device, "returning ecc 0x%08x\n", code[0]); + + /* second 4 bytes ECC code for 512 page size */ + if (page_size == 512) { + ecc0 = bfin_read_NFC_ECC2(); + ecc1 = bfin_read_NFC_ECC3(); + code[1] = (ecc0 & 0x3FF) | ((ecc1 & 0x3FF) << 11); + bytes = 6; + dev_dbg(info->device, "returning ecc 0x%08x\n", code[1]); + } + + p = (u8 *)code; + for (i = 0; i < bytes; i++) + ecc_code[i] = p[i]; + + return 0; +} + +/* + * PIO mode for buffer writing and reading + */ +static void bf5xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{ + int i; + unsigned short val; + + /* + * Data reads are requested by first writing to NFC_DATA_RD + * and then reading back from NFC_READ. + */ + for (i = 0; i < len; i++) { + while (bfin_read_NFC_STAT() & WB_FULL) + cpu_relax(); + + /* Contents do not matter */ + bfin_write_NFC_DATA_RD(0x0000); + SSYNC(); + + while ((bfin_read_NFC_IRQSTAT() & RD_RDY) != RD_RDY) + cpu_relax(); + + buf[i] = bfin_read_NFC_READ(); + + val = bfin_read_NFC_IRQSTAT(); + val |= RD_RDY; + bfin_write_NFC_IRQSTAT(val); + SSYNC(); + } +} + +static uint8_t bf5xx_nand_read_byte(struct mtd_info *mtd) +{ + uint8_t val; + + bf5xx_nand_read_buf(mtd, &val, 1); + + return val; +} + +static void bf5xx_nand_write_buf(struct mtd_info *mtd, + const uint8_t *buf, int len) +{ + int i; + + for (i = 0; i < len; i++) { + while (bfin_read_NFC_STAT() & WB_FULL) + cpu_relax(); + + bfin_write_NFC_DATA_WR(buf[i]); + SSYNC(); + } +} + +static void bf5xx_nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) +{ + int i; + u16 *p = (u16 *) buf; + len >>= 1; + + /* + * Data reads are requested by first writing to NFC_DATA_RD + * and then reading back from NFC_READ. + */ + bfin_write_NFC_DATA_RD(0x5555); + + SSYNC(); + + for (i = 0; i < len; i++) + p[i] = bfin_read_NFC_READ(); +} + +static void bf5xx_nand_write_buf16(struct mtd_info *mtd, + const uint8_t *buf, int len) +{ + int i; + u16 *p = (u16 *) buf; + len >>= 1; + + for (i = 0; i < len; i++) + bfin_write_NFC_DATA_WR(p[i]); + + SSYNC(); +} + +/* + * DMA functions for buffer writing and reading + */ +static irqreturn_t bf5xx_nand_dma_irq(int irq, void *dev_id) +{ + struct bf5xx_nand_info *info = dev_id; + + clear_dma_irqstat(CH_NFC); + disable_dma(CH_NFC); + complete(&info->dma_completion); + + return IRQ_HANDLED; +} + +static int bf5xx_nand_dma_rw(struct mtd_info *mtd, + uint8_t *buf, int is_read) +{ + struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); + struct bf5xx_nand_platform *plat = info->platform; + unsigned short page_size = (plat->page_size ? 512 : 256); + unsigned short val; + + dev_dbg(info->device, " mtd->%p, buf->%p, is_read %d\n", + mtd, buf, is_read); + + /* + * Before starting a dma transfer, be sure to invalidate/flush + * the cache over the address range of your DMA buffer to + * prevent cache coherency problems. Otherwise very subtle bugs + * can be introduced to your driver. + */ + if (is_read) + invalidate_dcache_range((unsigned int)buf, + (unsigned int)(buf + page_size)); + else + flush_dcache_range((unsigned int)buf, + (unsigned int)(buf + page_size)); + + /* + * This register must be written before each page is + * transferred to generate the correct ECC register + * values. + */ + bfin_write_NFC_RST(0x1); + SSYNC(); + + disable_dma(CH_NFC); + clear_dma_irqstat(CH_NFC); + + /* setup DMA register with Blackfin DMA API */ + set_dma_config(CH_NFC, 0x0); + set_dma_start_addr(CH_NFC, (unsigned long) buf); + set_dma_x_count(CH_NFC, (page_size >> 2)); + set_dma_x_modify(CH_NFC, 4); + + /* setup write or read operation */ + val = DI_EN | WDSIZE_32; + if (is_read) + val |= WNR; + set_dma_config(CH_NFC, val); + enable_dma(CH_NFC); + + /* Start PAGE read/write operation */ + if (is_read) + bfin_write_NFC_PGCTL(0x1); + else + bfin_write_NFC_PGCTL(0x2); + wait_for_completion(&info->dma_completion); + + return 0; +} + +static void bf5xx_nand_dma_read_buf(struct mtd_info *mtd, + uint8_t *buf, int len) +{ + struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); + struct bf5xx_nand_platform *plat = info->platform; + unsigned short page_size = (plat->page_size ? 512 : 256); + + dev_dbg(info->device, "mtd->%p, buf->%p, int %d\n", mtd, buf, len); + + if (len == page_size) + bf5xx_nand_dma_rw(mtd, buf, 1); + else + bf5xx_nand_read_buf(mtd, buf, len); +} + +static void bf5xx_nand_dma_write_buf(struct mtd_info *mtd, + const uint8_t *buf, int len) +{ + struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); + struct bf5xx_nand_platform *plat = info->platform; + unsigned short page_size = (plat->page_size ? 512 : 256); + + dev_dbg(info->device, "mtd->%p, buf->%p, len %d\n", mtd, buf, len); + + if (len == page_size) + bf5xx_nand_dma_rw(mtd, (uint8_t *)buf, 0); + else + bf5xx_nand_write_buf(mtd, buf, len); +} + +/* + * System initialization functions + */ + +static int bf5xx_nand_dma_init(struct bf5xx_nand_info *info) +{ + int ret; + unsigned short val; + + /* Do not use dma */ + if (!hardware_ecc) + return 0; + + init_completion(&info->dma_completion); + + /* Setup DMAC1 channel mux for NFC which shared with SDH */ + val = bfin_read_DMAC1_PERIMUX(); + val &= 0xFFFE; + bfin_write_DMAC1_PERIMUX(val); + SSYNC(); + + /* Request NFC DMA channel */ + ret = request_dma(CH_NFC, "BF5XX NFC driver"); + if (ret < 0) { + dev_err(info->device, " unable to get DMA channel\n"); + return ret; + } + + set_dma_callback(CH_NFC, (void *) bf5xx_nand_dma_irq, (void *) info); + + /* Turn off the DMA channel first */ + disable_dma(CH_NFC); + return 0; +} + +/* + * BF5XX NFC hardware initialization + * - pin mux setup + * - clear interrupt status + */ +static int bf5xx_nand_hw_init(struct bf5xx_nand_info *info) +{ + int err = 0; + unsigned short val; + struct bf5xx_nand_platform *plat = info->platform; + + /* setup NFC_CTL register */ + dev_info(info->device, + "page_size=%d, data_width=%d, wr_dly=%d, rd_dly=%d\n", + (plat->page_size ? 512 : 256), + (plat->data_width ? 16 : 8), + plat->wr_dly, plat->rd_dly); + + val = (plat->page_size << NFC_PG_SIZE_OFFSET) | + (plat->data_width << NFC_NWIDTH_OFFSET) | + (plat->rd_dly << NFC_RDDLY_OFFSET) | + (plat->rd_dly << NFC_WRDLY_OFFSET); + dev_dbg(info->device, "NFC_CTL is 0x%04x\n", val); + + bfin_write_NFC_CTL(val); + SSYNC(); + + /* clear interrupt status */ + bfin_write_NFC_IRQMASK(0x0); + SSYNC(); + val = bfin_read_NFC_IRQSTAT(); + bfin_write_NFC_IRQSTAT(val); + SSYNC(); + + if (peripheral_request_list(bfin_nfc_pin_req, DRV_NAME)) { + printk(KERN_ERR DRV_NAME + ": Requesting Peripherals failed\n"); + return -EFAULT; + } + + /* DMA initialization */ + if (bf5xx_nand_dma_init(info)) + err = -ENXIO; + + return err; +} + +/* + * Device management interface + */ +static int bf5xx_nand_add_partition(struct bf5xx_nand_info *info) +{ + struct mtd_info *mtd = &info->mtd; + +#ifdef CONFIG_MTD_PARTITIONS + struct mtd_partition *parts = info->platform->partitions; + int nr = info->platform->nr_partitions; + + return add_mtd_partitions(mtd, parts, nr); +#else + return add_mtd_device(mtd); +#endif +} + +static int bf5xx_nand_remove(struct platform_device *pdev) +{ + struct bf5xx_nand_info *info = to_nand_info(pdev); + struct mtd_info *mtd = NULL; + + platform_set_drvdata(pdev, NULL); + + /* first thing we need to do is release all our mtds + * and their partitions, then go through freeing the + * resources used + */ + mtd = &info->mtd; + if (mtd) { + nand_release(mtd); + kfree(mtd); + } + + peripheral_free_list(bfin_nfc_pin_req); + + /* free the common resources */ + kfree(info); + + return 0; +} + +/* + * bf5xx_nand_probe + * + * called by device layer when it finds a device matching + * one our driver can handled. This code checks to see if + * it can allocate all necessary resources then calls the + * nand layer to look for devices + */ +static int bf5xx_nand_probe(struct platform_device *pdev) +{ + struct bf5xx_nand_platform *plat = to_nand_plat(pdev); + struct bf5xx_nand_info *info = NULL; + struct nand_chip *chip = NULL; + struct mtd_info *mtd = NULL; + int err = 0; + + dev_dbg(&pdev->dev, "(%p)\n", pdev); + + if (!plat) { + dev_err(&pdev->dev, "no platform specific information\n"); + goto exit_error; + } + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (info == NULL) { + dev_err(&pdev->dev, "no memory for flash info\n"); + err = -ENOMEM; + goto exit_error; + } + + platform_set_drvdata(pdev, info); + + spin_lock_init(&info->controller.lock); + init_waitqueue_head(&info->controller.wq); + + info->device = &pdev->dev; + info->platform = plat; + + /* initialise chip data struct */ + chip = &info->chip; + + if (plat->data_width) + chip->options |= NAND_BUSWIDTH_16; + + chip->options |= NAND_CACHEPRG | NAND_SKIP_BBTSCAN; + + chip->read_buf = (plat->data_width) ? + bf5xx_nand_read_buf16 : bf5xx_nand_read_buf; + chip->write_buf = (plat->data_width) ? + bf5xx_nand_write_buf16 : bf5xx_nand_write_buf; + + chip->read_byte = bf5xx_nand_read_byte; + + chip->cmd_ctrl = bf5xx_nand_hwcontrol; + chip->dev_ready = bf5xx_nand_devready; + + chip->priv = &info->mtd; + chip->controller = &info->controller; + + chip->IO_ADDR_R = (void __iomem *) NFC_READ; + chip->IO_ADDR_W = (void __iomem *) NFC_DATA_WR; + + chip->chip_delay = 0; + + /* initialise mtd info data struct */ + mtd = &info->mtd; + mtd->priv = chip; + mtd->owner = THIS_MODULE; + + /* initialise the hardware */ + err = bf5xx_nand_hw_init(info); + if (err != 0) + goto exit_error; + + /* setup hardware ECC data struct */ + if (hardware_ecc) { + if (plat->page_size == NFC_PG_SIZE_256) { + chip->ecc.bytes = 3; + chip->ecc.size = 256; + } else if (plat->page_size == NFC_PG_SIZE_512) { + chip->ecc.bytes = 6; + chip->ecc.size = 512; + } + + chip->read_buf = bf5xx_nand_dma_read_buf; + chip->write_buf = bf5xx_nand_dma_write_buf; + chip->ecc.calculate = bf5xx_nand_calculate_ecc; + chip->ecc.correct = bf5xx_nand_correct_data; + chip->ecc.mode = NAND_ECC_HW; + chip->ecc.hwctl = bf5xx_nand_enable_hwecc; + } else { + chip->ecc.mode = NAND_ECC_SOFT; + } + + /* scan hardware nand chip and setup mtd info data struct */ + if (nand_scan(mtd, 1)) { + err = -ENXIO; + goto exit_error; + } + + /* add NAND partition */ + bf5xx_nand_add_partition(info); + + dev_dbg(&pdev->dev, "initialised ok\n"); + return 0; + +exit_error: + bf5xx_nand_remove(pdev); + + if (err == 0) + err = -EINVAL; + return err; +} + +/* PM Support */ +#ifdef CONFIG_PM + +static int bf5xx_nand_suspend(struct platform_device *dev, pm_message_t pm) +{ + struct bf5xx_nand_info *info = platform_get_drvdata(dev); + + return 0; +} + +static int bf5xx_nand_resume(struct platform_device *dev) +{ + struct bf5xx_nand_info *info = platform_get_drvdata(dev); + + if (info) + bf5xx_nand_hw_init(info); + + return 0; +} + +#else +#define bf5xx_nand_suspend NULL +#define bf5xx_nand_resume NULL +#endif + +/* driver device registration */ +static struct platform_driver bf5xx_nand_driver = { + .probe = bf5xx_nand_probe, + .remove = bf5xx_nand_remove, + .suspend = bf5xx_nand_suspend, + .resume = bf5xx_nand_resume, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init bf5xx_nand_init(void) +{ + printk(KERN_INFO "%s, Version %s (c) 2007 Analog Devices, Inc.\n", + DRV_DESC, DRV_VERSION); + + return platform_driver_register(&bf5xx_nand_driver); +} + +static void __exit bf5xx_nand_exit(void) +{ + platform_driver_unregister(&bf5xx_nand_driver); +} + +module_init(bf5xx_nand_init); +module_exit(bf5xx_nand_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR(DRV_AUTHOR); +MODULE_DESCRIPTION(DRV_DESC); diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index 6f32a35eb106..1e811715211a 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c @@ -80,7 +80,7 @@ module_param(regdebug, int, 0644); static int checkecc = 1; module_param(checkecc, int, 0644); -static int numtimings; +static unsigned int numtimings; static int timing[3]; module_param_array(timing, int, &numtimings, 0644); @@ -623,6 +623,11 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, uint32_t ctrl; int err = 0; + /* Very old versions shared the same PCI ident for all three + functions on the chip. Verify the class too... */ + if ((pdev->class >> 8) != PCI_CLASS_MEMORY_FLASH) + return -ENODEV; + err = pci_enable_device(pdev); if (err) return err; @@ -816,21 +821,57 @@ static void __devexit cafe_nand_remove(struct pci_dev *pdev) } static struct pci_device_id cafe_nand_tbl[] = { - { 0x11ab, 0x4100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MEMORY_FLASH << 8, 0xFFFF0 }, - { 0, } + { 0x11ab, 0x4100, PCI_ANY_ID, PCI_ANY_ID }, + { } }; MODULE_DEVICE_TABLE(pci, cafe_nand_tbl); +static int cafe_nand_resume(struct pci_dev *pdev) +{ + uint32_t ctrl; + struct mtd_info *mtd = pci_get_drvdata(pdev); + struct cafe_priv *cafe = mtd->priv; + + /* Start off by resetting the NAND controller completely */ + cafe_writel(cafe, 1, NAND_RESET); + cafe_writel(cafe, 0, NAND_RESET); + cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK); + + /* Restore timing configuration */ + cafe_writel(cafe, timing[0], NAND_TIMING1); + cafe_writel(cafe, timing[1], NAND_TIMING2); + cafe_writel(cafe, timing[2], NAND_TIMING3); + + /* Disable master reset, enable NAND clock */ + ctrl = cafe_readl(cafe, GLOBAL_CTRL); + ctrl &= 0xffffeff0; + ctrl |= 0x00007000; + cafe_writel(cafe, ctrl | 0x05, GLOBAL_CTRL); + cafe_writel(cafe, ctrl | 0x0a, GLOBAL_CTRL); + cafe_writel(cafe, 0, NAND_DMA_CTRL); + cafe_writel(cafe, 0x7006, GLOBAL_CTRL); + cafe_writel(cafe, 0x700a, GLOBAL_CTRL); + + /* Set up DMA address */ + cafe_writel(cafe, cafe->dmaaddr & 0xffffffff, NAND_DMA_ADDR0); + if (sizeof(cafe->dmaaddr) > 4) + /* Shift in two parts to shut the compiler up */ + cafe_writel(cafe, (cafe->dmaaddr >> 16) >> 16, NAND_DMA_ADDR1); + else + cafe_writel(cafe, 0, NAND_DMA_ADDR1); + + /* Enable NAND IRQ in global IRQ mask register */ + cafe_writel(cafe, 0x80000007, GLOBAL_IRQ_MASK); + return 0; +} + static struct pci_driver cafe_nand_pci_driver = { .name = "CAFÉ NAND", .id_table = cafe_nand_tbl, .probe = cafe_nand_probe, .remove = __devexit_p(cafe_nand_remove), -#ifdef CONFIG_PMx - .suspend = cafe_nand_suspend, .resume = cafe_nand_resume, -#endif }; static int cafe_nand_init(void) diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index e96259f22cca..ab9f5c5db38d 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -56,8 +56,6 @@ static unsigned long __initdata doc_locations[] = { #endif /* CONFIG_MTD_DOCPROBE_HIGH */ #elif defined(__PPC__) 0xe4000000, -#elif defined(CONFIG_MOMENCO_OCELOT_G) - 0xff000000, #else #warning Unknown architecture for DiskOnChip. No default probe locations defined #endif diff --git a/drivers/mtd/nand/excite_nandflash.c b/drivers/mtd/nand/excite_nandflash.c index 7e9afc4c7757..bed87290decc 100644 --- a/drivers/mtd/nand/excite_nandflash.c +++ b/drivers/mtd/nand/excite_nandflash.c @@ -27,7 +27,6 @@ #include <linux/platform_device.h> #include <linux/delay.h> #include <linux/err.h> -#include <linux/kernel.h> #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 24ac6778b1a8..b4e0e7723894 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -7,7 +7,7 @@ * Basic support for AG-AND chips is provided. * * Additional technical information is available on - * http://www.linux-mtd.infradead.org/tech/nand.html + * http://www.linux-mtd.infradead.org/doc/nand.html * * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) * 2002-2006 Thomas Gleixner (tglx@linutronix.de) @@ -2069,13 +2069,14 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, erase_exit: ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO; - /* Do call back function */ - if (!ret) - mtd_erase_callback(instr); /* Deselect and wake up anyone waiting on the device */ nand_release_device(mtd); + /* Do call back function */ + if (!ret) + mtd_erase_callback(instr); + /* * If BBT requires refresh and erase was successful, rewrite any * selected bad block tables diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 2fc674a190cf..a3e3ab0185d5 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -141,6 +141,7 @@ struct nand_manufacturers nand_manuf_ids[] = { {NAND_MFR_STMICRO, "ST Micro"}, {NAND_MFR_HYNIX, "Hynix"}, {NAND_MFR_MICRON, "Micron"}, + {NAND_MFR_AMD, "AMD"}, {0x0, "Unknown"} }; diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 205df0f771fe..a7574807dc46 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -1272,7 +1272,13 @@ static int prog_page(struct nandsim *ns, int num) mypage = NS_GET_PAGE(ns); if (mypage->byte == NULL) { NS_DBG("prog_page: allocating page %d\n", ns->regs.row); - mypage->byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL); + /* + * We allocate memory with GFP_NOFS because a flash FS may + * utilize this. If it is holding an FS lock, then gets here, + * then kmalloc runs writeback which goes to the FS again + * and deadlocks. This was seen in practice. + */ + mypage->byte = kmalloc(ns->geom.pgszoob, GFP_NOFS); if (mypage->byte == NULL) { NS_ERR("prog_page: error allocating memory for page %d\n", ns->regs.row); return -1; diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index fd7a8d5ba29a..1c0e89f00e8d 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -24,7 +24,11 @@ #include <linux/platform_device.h> #include <asm/io.h> +#ifdef CONFIG_40x +#include <asm/ibm405.h> +#else #include <asm/ibm44x.h> +#endif struct ndfc_nand_mtd { struct mtd_info mtd; @@ -230,7 +234,11 @@ static int ndfc_nand_probe(struct platform_device *pdev) struct ndfc_controller *ndfc = &ndfc_ctrl; unsigned long long phys = settings->ndfc_erpn | res->start; +#ifndef CONFIG_PHYS_64BIT + ndfc->ndfcbase = ioremap((phys_addr_t)phys, res->end - res->start + 1); +#else ndfc->ndfcbase = ioremap64(phys, res->end - res->start + 1); +#endif if (!ndfc->ndfcbase) { printk(KERN_ERR "NDFC: ioremap failed\n"); return -EIO; diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 5fac4c421a20..b79a9cf2d162 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -60,8 +60,8 @@ #include <asm/io.h> -#include <asm/arch/regs-nand.h> -#include <asm/arch/nand.h> +#include <asm/plat-s3c/regs-nand.h> +#include <asm/plat-s3c/nand.h> #ifdef CONFIG_MTD_NAND_S3C2410_HWECC static int hardware_ecc = 1; diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig index c257d397d08a..cb41cbca64f7 100644 --- a/drivers/mtd/onenand/Kconfig +++ b/drivers/mtd/onenand/Kconfig @@ -40,4 +40,27 @@ config MTD_ONENAND_OTP OTP block is fully-guaranteed to be a valid block. +config MTD_ONENAND_2X_PROGRAM + bool "OneNAND 2X program support" + help + The 2X Program is an extension of Program Operation. + Since the device is equipped with two DataRAMs, and two-plane NAND + Flash memory array, these two component enables simultaneous program + of 4KiB. Plane1 has only even blocks such as block0, block2, block4 + while Plane2 has only odd blocks such as block1, block3, block5. + So MTD regards it as 4KiB page size and 256KiB block size + + Now the following chips support it. (KFXXX16Q2M) + Demux: KFG2G16Q2M, KFH4G16Q2M, KFW8G16Q2M, + Mux: KFM2G16Q2M, KFN4G16Q2M, + + And more recent chips + +config MTD_ONENAND_SIM + tristate "OneNAND simulator support" + depends on MTD_PARTITIONS + help + The simulator may simulate various OneNAND flash chips for the + OneNAND MTD layer. + endif # MTD_ONENAND diff --git a/drivers/mtd/onenand/Makefile b/drivers/mtd/onenand/Makefile index 269cfe467345..4d2eacfd7e11 100644 --- a/drivers/mtd/onenand/Makefile +++ b/drivers/mtd/onenand/Makefile @@ -8,4 +8,7 @@ obj-$(CONFIG_MTD_ONENAND) += onenand.o # Board specific. obj-$(CONFIG_MTD_ONENAND_GENERIC) += generic.o +# Simulator +obj-$(CONFIG_MTD_ONENAND_SIM) += onenand_sim.o + onenand-objs = onenand_base.o onenand_bbt.o diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 0537fac8de74..dd2835569092 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -206,6 +206,15 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le default: block = (int) (addr >> this->erase_shift); page = (int) (addr >> this->page_shift); + + if (ONENAND_IS_2PLANE(this)) { + /* Make the even block number */ + block &= ~1; + /* Is it the odd plane? */ + if (addr & this->writesize) + block++; + page >>= 1; + } page &= this->page_mask; break; } @@ -216,8 +225,12 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le value = onenand_bufferram_address(this, block); this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); - /* Switch to the next data buffer */ - ONENAND_SET_NEXT_BUFFERRAM(this); + if (ONENAND_IS_2PLANE(this)) + /* It is always BufferRAM0 */ + ONENAND_SET_BUFFERRAM0(this); + else + /* Switch to the next data buffer */ + ONENAND_SET_NEXT_BUFFERRAM(this); return 0; } @@ -247,6 +260,8 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le break; default: + if (ONENAND_IS_2PLANE(this) && cmd == ONENAND_CMD_PROG) + cmd = ONENAND_CMD_2X_PROG; dataram = ONENAND_CURRENT_BUFFERRAM(this); break; } @@ -312,18 +327,20 @@ static int onenand_wait(struct mtd_info *mtd, int state) printk(KERN_ERR "onenand_wait: controller error = 0x%04x\n", ctrl); if (ctrl & ONENAND_CTRL_LOCK) printk(KERN_ERR "onenand_wait: it's locked error.\n"); - return ctrl; + return -EIO; } if (interrupt & ONENAND_INT_READ) { int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS); if (ecc) { - printk(KERN_ERR "onenand_wait: ECC error = 0x%04x\n", ecc); if (ecc & ONENAND_ECC_2BIT_ALL) { + printk(KERN_ERR "onenand_wait: ECC error = 0x%04x\n", ecc); mtd->ecc_stats.failed++; - return ecc; - } else if (ecc & ONENAND_ECC_1BIT_ALL) + return -EBADMSG; + } else if (ecc & ONENAND_ECC_1BIT_ALL) { + printk(KERN_INFO "onenand_wait: correctable ECC error = 0x%04x\n", ecc); mtd->ecc_stats.corrected++; + } } } else if (state == FL_READING) { printk(KERN_ERR "onenand_wait: read timeout! ctrl=0x%04x intr=0x%04x\n", ctrl, interrupt); @@ -445,8 +462,9 @@ static inline int onenand_bufferram_offset(struct mtd_info *mtd, int area) struct onenand_chip *this = mtd->priv; if (ONENAND_CURRENT_BUFFERRAM(this)) { + /* Note: the 'this->writesize' is a real page size */ if (area == ONENAND_DATARAM) - return mtd->writesize; + return this->writesize; if (area == ONENAND_SPARERAM) return mtd->oobsize; } @@ -572,6 +590,30 @@ static int onenand_write_bufferram(struct mtd_info *mtd, int area, } /** + * onenand_get_2x_blockpage - [GENERIC] Get blockpage at 2x program mode + * @param mtd MTD data structure + * @param addr address to check + * @return blockpage address + * + * Get blockpage address at 2x program mode + */ +static int onenand_get_2x_blockpage(struct mtd_info *mtd, loff_t addr) +{ + struct onenand_chip *this = mtd->priv; + int blockpage, block, page; + + /* Calculate the even block number */ + block = (int) (addr >> this->erase_shift) & ~1; + /* Is it the odd plane? */ + if (addr & this->writesize) + block++; + page = (int) (addr >> (this->page_shift + 1)) & this->page_mask; + blockpage = (block << 7) | page; + + return blockpage; +} + +/** * onenand_check_bufferram - [GENERIC] Check BufferRAM information * @param mtd MTD data structure * @param addr address to check @@ -585,7 +627,10 @@ static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr) int blockpage, found = 0; unsigned int i; - blockpage = (int) (addr >> this->page_shift); + if (ONENAND_IS_2PLANE(this)) + blockpage = onenand_get_2x_blockpage(mtd, addr); + else + blockpage = (int) (addr >> this->page_shift); /* Is there valid data? */ i = ONENAND_CURRENT_BUFFERRAM(this); @@ -625,7 +670,10 @@ static void onenand_update_bufferram(struct mtd_info *mtd, loff_t addr, int blockpage; unsigned int i; - blockpage = (int) (addr >> this->page_shift); + if (ONENAND_IS_2PLANE(this)) + blockpage = onenand_get_2x_blockpage(mtd, addr); + else + blockpage = (int) (addr >> this->page_shift); /* Invalidate another BufferRAM */ i = ONENAND_NEXT_BUFFERRAM(this); @@ -717,36 +765,86 @@ static void onenand_release_device(struct mtd_info *mtd) } /** - * onenand_read - [MTD Interface] Read data from flash + * onenand_transfer_auto_oob - [Internal] oob auto-placement transfer + * @param mtd MTD device structure + * @param buf destination address + * @param column oob offset to read from + * @param thislen oob length to read + */ +static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int column, + int thislen) +{ + struct onenand_chip *this = mtd->priv; + struct nand_oobfree *free; + int readcol = column; + int readend = column + thislen; + int lastgap = 0; + unsigned int i; + uint8_t *oob_buf = this->oob_buf; + + free = this->ecclayout->oobfree; + for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { + if (readcol >= lastgap) + readcol += free->offset - lastgap; + if (readend >= lastgap) + readend += free->offset - lastgap; + lastgap = free->offset + free->length; + } + this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize); + free = this->ecclayout->oobfree; + for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { + int free_end = free->offset + free->length; + if (free->offset < readend && free_end > readcol) { + int st = max_t(int,free->offset,readcol); + int ed = min_t(int,free_end,readend); + int n = ed - st; + memcpy(buf, oob_buf + st, n); + buf += n; + } else if (column == 0) + break; + } + return 0; +} + +/** + * onenand_read_ops_nolock - [OneNAND Interface] OneNAND read main and/or out-of-band * @param mtd MTD device structure * @param from offset to read from - * @param len number of bytes to read - * @param retlen pointer to variable to store the number of read bytes - * @param buf the databuffer to put data + * @param ops: oob operation description structure * - * Read with ecc -*/ -static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf) + * OneNAND read main and/or out-of-band data + */ +static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops) { struct onenand_chip *this = mtd->priv; struct mtd_ecc_stats stats; - int read = 0, column; - int thislen; + size_t len = ops->len; + size_t ooblen = ops->ooblen; + u_char *buf = ops->datbuf; + u_char *oobbuf = ops->oobbuf; + int read = 0, column, thislen; + int oobread = 0, oobcolumn, thisooblen, oobsize; int ret = 0, boundary = 0; + int writesize = this->writesize; + + DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ops_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); - DEBUG(MTD_DEBUG_LEVEL3, "onenand_read: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); + if (ops->mode == MTD_OOB_AUTO) + oobsize = this->ecclayout->oobavail; + else + oobsize = mtd->oobsize; + + oobcolumn = from & (mtd->oobsize - 1); /* Do not allow reads past end of device */ if ((from + len) > mtd->size) { - printk(KERN_ERR "onenand_read: Attempt read beyond end of device\n"); - *retlen = 0; + printk(KERN_ERR "onenand_read_ops_nolock: Attempt read beyond end of device\n"); + ops->retlen = 0; + ops->oobretlen = 0; return -EINVAL; } - /* Grab the lock and see if the device is available */ - onenand_get_device(mtd, FL_READING); - stats = mtd->ecc_stats; /* Read-while-load method */ @@ -754,22 +852,22 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, /* Do first load to bufferRAM */ if (read < len) { if (!onenand_check_bufferram(mtd, from)) { - this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize); + this->command(mtd, ONENAND_CMD_READ, from, writesize); ret = this->wait(mtd, FL_READING); onenand_update_bufferram(mtd, from, !ret); } } - thislen = min_t(int, mtd->writesize, len - read); - column = from & (mtd->writesize - 1); - if (column + thislen > mtd->writesize) - thislen = mtd->writesize - column; + thislen = min_t(int, writesize, len - read); + column = from & (writesize - 1); + if (column + thislen > writesize) + thislen = writesize - column; while (!ret) { /* If there is more to load then start next load */ from += thislen; if (read + thislen < len) { - this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize); + this->command(mtd, ONENAND_CMD_READ, from, writesize); /* * Chip boundary handling in DDP * Now we issued chip 1 read and pointed chip 1 @@ -785,6 +883,21 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, } /* While load is going, read from last bufferRAM */ this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen); + + /* Read oob area if needed */ + if (oobbuf) { + thisooblen = oobsize - oobcolumn; + thisooblen = min_t(int, thisooblen, ooblen - oobread); + + if (ops->mode == MTD_OOB_AUTO) + onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen); + else + this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen); + oobread += thisooblen; + oobbuf += thisooblen; + oobcolumn = 0; + } + /* See if we are done */ read += thislen; if (read == len) @@ -794,7 +907,7 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, this->write_word(ONENAND_DDP_CHIP1, this->base + ONENAND_REG_START_ADDRESS2); ONENAND_SET_NEXT_BUFFERRAM(this); buf += thislen; - thislen = min_t(int, mtd->writesize, len - read); + thislen = min_t(int, writesize, len - read); column = 0; cond_resched(); /* Now wait for load */ @@ -802,15 +915,13 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, onenand_update_bufferram(mtd, from, !ret); } - /* Deselect and wake up anyone waiting on the device */ - onenand_release_device(mtd); - /* * Return success, if no ECC failures, else -EBADMSG * fs driver will take care of that, because * retlen == desired len and result == -EBADMSG */ - *retlen = read; + ops->retlen = read; + ops->oobretlen = oobread; if (mtd->ecc_stats.failed - stats.failed) return -EBADMSG; @@ -822,69 +933,29 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, } /** - * onenand_transfer_auto_oob - [Internal] oob auto-placement transfer - * @param mtd MTD device structure - * @param buf destination address - * @param column oob offset to read from - * @param thislen oob length to read - */ -static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int column, - int thislen) -{ - struct onenand_chip *this = mtd->priv; - struct nand_oobfree *free; - int readcol = column; - int readend = column + thislen; - int lastgap = 0; - unsigned int i; - uint8_t *oob_buf = this->oob_buf; - - free = this->ecclayout->oobfree; - for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { - if (readcol >= lastgap) - readcol += free->offset - lastgap; - if (readend >= lastgap) - readend += free->offset - lastgap; - lastgap = free->offset + free->length; - } - this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize); - free = this->ecclayout->oobfree; - for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { - int free_end = free->offset + free->length; - if (free->offset < readend && free_end > readcol) { - int st = max_t(int,free->offset,readcol); - int ed = min_t(int,free_end,readend); - int n = ed - st; - memcpy(buf, oob_buf + st, n); - buf += n; - } else if (column == 0) - break; - } - return 0; -} - -/** - * onenand_do_read_oob - [MTD Interface] OneNAND read out-of-band + * onenand_read_oob_nolock - [MTD Interface] OneNAND read out-of-band * @param mtd MTD device structure * @param from offset to read from - * @param len number of bytes to read - * @param retlen pointer to variable to store the number of read bytes - * @param buf the databuffer to put data - * @param mode operation mode + * @param ops: oob operation description structure * * OneNAND read out-of-band data from the spare area */ -static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf, mtd_oob_mode_t mode) +static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops) { struct onenand_chip *this = mtd->priv; int read = 0, thislen, column, oobsize; + size_t len = ops->ooblen; + mtd_oob_mode_t mode = ops->mode; + u_char *buf = ops->oobbuf; int ret = 0; - DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); + from += ops->ooboffs; + + DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); /* Initialize return length value */ - *retlen = 0; + ops->oobretlen = 0; if (mode == MTD_OOB_AUTO) oobsize = this->ecclayout->oobavail; @@ -894,7 +965,7 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len, column = from & (mtd->oobsize - 1); if (unlikely(column >= oobsize)) { - printk(KERN_ERR "onenand_read_oob: Attempted to start read outside oob\n"); + printk(KERN_ERR "onenand_read_oob_nolock: Attempted to start read outside oob\n"); return -EINVAL; } @@ -902,13 +973,10 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len, if (unlikely(from >= mtd->size || column + len > ((mtd->size >> this->page_shift) - (from >> this->page_shift)) * oobsize)) { - printk(KERN_ERR "onenand_read_oob: Attempted to read beyond end of device\n"); + printk(KERN_ERR "onenand_read_oob_nolock: Attempted to read beyond end of device\n"); return -EINVAL; } - /* Grab the lock and see if the device is available */ - onenand_get_device(mtd, FL_READING); - while (read < len) { cond_resched(); @@ -928,7 +996,7 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len, this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); if (ret) { - printk(KERN_ERR "onenand_read_oob: read failed = 0x%x\n", ret); + printk(KERN_ERR "onenand_read_oob_nolock: read failed = 0x%x\n", ret); break; } @@ -947,22 +1015,52 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len, } } - /* Deselect and wake up anyone waiting on the device */ + ops->oobretlen = read; + return ret; +} + +/** + * onenand_read - [MTD Interface] Read data from flash + * @param mtd MTD device structure + * @param from offset to read from + * @param len number of bytes to read + * @param retlen pointer to variable to store the number of read bytes + * @param buf the databuffer to put data + * + * Read with ecc +*/ +static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct mtd_oob_ops ops = { + .len = len, + .ooblen = 0, + .datbuf = buf, + .oobbuf = NULL, + }; + int ret; + + onenand_get_device(mtd, FL_READING); + ret = onenand_read_ops_nolock(mtd, from, &ops); onenand_release_device(mtd); - *retlen = read; + *retlen = ops.retlen; return ret; } /** - * onenand_read_oob - [MTD Interface] NAND write data and/or out-of-band + * onenand_read_oob - [MTD Interface] Read main and/or out-of-band * @param mtd: MTD device structure * @param from: offset to read from * @param ops: oob operation description structure + + * Read main and/or out-of-band */ static int onenand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { + int ret; + switch (ops->mode) { case MTD_OOB_PLACE: case MTD_OOB_AUTO: @@ -972,8 +1070,15 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from, default: return -EINVAL; } - return onenand_do_read_oob(mtd, from + ops->ooboffs, ops->ooblen, - &ops->oobretlen, ops->oobbuf, ops->mode); + + onenand_get_device(mtd, FL_READING); + if (ops->datbuf) + ret = onenand_read_ops_nolock(mtd, from, ops); + else + ret = onenand_read_oob_nolock(mtd, from, ops); + onenand_release_device(mtd); + + return ret; } /** @@ -1079,7 +1184,7 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, /* Read more? */ if (read < len) { /* Update Page size */ - from += mtd->writesize; + from += this->writesize; column = 0; } } @@ -1097,7 +1202,6 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, * @param mtd MTD device structure * @param buf the databuffer to verify * @param to offset to read from - * */ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to) { @@ -1125,7 +1229,6 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to * @param buf the databuffer to verify * @param addr offset to read from * @param len number of bytes to read and compare - * */ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, size_t len) { @@ -1135,12 +1238,12 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, int thislen, column; while (len != 0) { - thislen = min_t(int, mtd->writesize, len); - column = addr & (mtd->writesize - 1); - if (column + thislen > mtd->writesize) - thislen = mtd->writesize - column; + thislen = min_t(int, this->writesize, len); + column = addr & (this->writesize - 1); + if (column + thislen > this->writesize) + thislen = this->writesize - column; - this->command(mtd, ONENAND_CMD_READ, addr, mtd->writesize); + this->command(mtd, ONENAND_CMD_READ, addr, this->writesize); onenand_update_bufferram(mtd, addr, 0); @@ -1171,50 +1274,101 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, #define NOTALIGNED(x) ((x & (this->subpagesize - 1)) != 0) /** - * onenand_write - [MTD Interface] write buffer to FLASH + * onenand_fill_auto_oob - [Internal] oob auto-placement transfer + * @param mtd MTD device structure + * @param oob_buf oob buffer + * @param buf source address + * @param column oob offset to write to + * @param thislen oob length to write + */ +static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf, + const u_char *buf, int column, int thislen) +{ + struct onenand_chip *this = mtd->priv; + struct nand_oobfree *free; + int writecol = column; + int writeend = column + thislen; + int lastgap = 0; + unsigned int i; + + free = this->ecclayout->oobfree; + for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { + if (writecol >= lastgap) + writecol += free->offset - lastgap; + if (writeend >= lastgap) + writeend += free->offset - lastgap; + lastgap = free->offset + free->length; + } + free = this->ecclayout->oobfree; + for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { + int free_end = free->offset + free->length; + if (free->offset < writeend && free_end > writecol) { + int st = max_t(int,free->offset,writecol); + int ed = min_t(int,free_end,writeend); + int n = ed - st; + memcpy(oob_buf + st, buf, n); + buf += n; + } else if (column == 0) + break; + } + return 0; +} + +/** + * onenand_write_ops_nolock - [OneNAND Interface] write main and/or out-of-band * @param mtd MTD device structure * @param to offset to write to - * @param len number of bytes to write - * @param retlen pointer to variable to store the number of written bytes - * @param buf the data to write + * @param ops oob operation description structure * - * Write with ECC + * Write main and/or oob with ECC */ -static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) +static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, + struct mtd_oob_ops *ops) { struct onenand_chip *this = mtd->priv; - int written = 0; + int written = 0, column, thislen, subpage; + int oobwritten = 0, oobcolumn, thisooblen, oobsize; + size_t len = ops->len; + size_t ooblen = ops->ooblen; + const u_char *buf = ops->datbuf; + const u_char *oob = ops->oobbuf; + u_char *oobbuf; int ret = 0; - int column, subpage; - DEBUG(MTD_DEBUG_LEVEL3, "onenand_write: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); + DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ops_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); /* Initialize retlen, in case of early exit */ - *retlen = 0; + ops->retlen = 0; + ops->oobretlen = 0; /* Do not allow writes past end of device */ if (unlikely((to + len) > mtd->size)) { - printk(KERN_ERR "onenand_write: Attempt write to past end of device\n"); + printk(KERN_ERR "onenand_write_ops_nolock: Attempt write to past end of device\n"); return -EINVAL; } /* Reject writes, which are not page aligned */ if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) { - printk(KERN_ERR "onenand_write: Attempt to write not page aligned data\n"); + printk(KERN_ERR "onenand_write_ops_nolock: Attempt to write not page aligned data\n"); return -EINVAL; } - column = to & (mtd->writesize - 1); + if (ops->mode == MTD_OOB_AUTO) + oobsize = this->ecclayout->oobavail; + else + oobsize = mtd->oobsize; - /* Grab the lock and see if the device is available */ - onenand_get_device(mtd, FL_WRITING); + oobcolumn = to & (mtd->oobsize - 1); + + column = to & (mtd->writesize - 1); /* Loop until all data write */ while (written < len) { - int thislen = min_t(int, mtd->writesize - column, len - written); u_char *wbuf = (u_char *) buf; + thislen = min_t(int, mtd->writesize - column, len - written); + thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten); + cond_resched(); this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen); @@ -1228,7 +1382,25 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, } this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize); - this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); + + if (oob) { + oobbuf = this->oob_buf; + + /* We send data to spare ram with oobsize + * to prevent byte access */ + memset(oobbuf, 0xff, mtd->oobsize); + if (ops->mode == MTD_OOB_AUTO) + onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen); + else + memcpy(oobbuf + oobcolumn, oob, thisooblen); + + oobwritten += thisooblen; + oob += thisooblen; + oobcolumn = 0; + } else + oobbuf = (u_char *) ffchars; + + this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize); this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); @@ -1236,16 +1408,20 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, /* In partial page write we don't update bufferram */ onenand_update_bufferram(mtd, to, !ret && !subpage); + if (ONENAND_IS_2PLANE(this)) { + ONENAND_SET_BUFFERRAM1(this); + onenand_update_bufferram(mtd, to + this->writesize, !ret && !subpage); + } if (ret) { - printk(KERN_ERR "onenand_write: write filaed %d\n", ret); + printk(KERN_ERR "onenand_write_ops_nolock: write filaed %d\n", ret); break; } /* Only check verify write turn on */ ret = onenand_verify(mtd, (u_char *) wbuf, to, thislen); if (ret) { - printk(KERN_ERR "onenand_write: verify failed %d\n", ret); + printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret); break; } @@ -1262,54 +1438,14 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, /* Deselect and wake up anyone waiting on the device */ onenand_release_device(mtd); - *retlen = written; + ops->retlen = written; return ret; } -/** - * onenand_fill_auto_oob - [Internal] oob auto-placement transfer - * @param mtd MTD device structure - * @param oob_buf oob buffer - * @param buf source address - * @param column oob offset to write to - * @param thislen oob length to write - */ -static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf, - const u_char *buf, int column, int thislen) -{ - struct onenand_chip *this = mtd->priv; - struct nand_oobfree *free; - int writecol = column; - int writeend = column + thislen; - int lastgap = 0; - unsigned int i; - - free = this->ecclayout->oobfree; - for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { - if (writecol >= lastgap) - writecol += free->offset - lastgap; - if (writeend >= lastgap) - writeend += free->offset - lastgap; - lastgap = free->offset + free->length; - } - free = this->ecclayout->oobfree; - for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { - int free_end = free->offset + free->length; - if (free->offset < writeend && free_end > writecol) { - int st = max_t(int,free->offset,writecol); - int ed = min_t(int,free_end,writeend); - int n = ed - st; - memcpy(oob_buf + st, buf, n); - buf += n; - } else if (column == 0) - break; - } - return 0; -} /** - * onenand_do_write_oob - [Internal] OneNAND write out-of-band + * onenand_write_oob_nolock - [Internal] OneNAND write out-of-band * @param mtd MTD device structure * @param to offset to write to * @param len number of bytes to write @@ -1319,18 +1455,23 @@ static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf, * * OneNAND write out-of-band */ -static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf, mtd_oob_mode_t mode) +static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, + struct mtd_oob_ops *ops) { struct onenand_chip *this = mtd->priv; int column, ret = 0, oobsize; int written = 0; u_char *oobbuf; + size_t len = ops->ooblen; + const u_char *buf = ops->oobbuf; + mtd_oob_mode_t mode = ops->mode; - DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); + to += ops->ooboffs; + + DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); /* Initialize retlen, in case of early exit */ - *retlen = 0; + ops->oobretlen = 0; if (mode == MTD_OOB_AUTO) oobsize = this->ecclayout->oobavail; @@ -1340,13 +1481,13 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, column = to & (mtd->oobsize - 1); if (unlikely(column >= oobsize)) { - printk(KERN_ERR "onenand_write_oob: Attempted to start write outside oob\n"); + printk(KERN_ERR "onenand_write_oob_nolock: Attempted to start write outside oob\n"); return -EINVAL; } /* For compatibility with NAND: Do not allow write past end of page */ if (unlikely(column + len > oobsize)) { - printk(KERN_ERR "onenand_write_oob: " + printk(KERN_ERR "onenand_write_oob_nolock: " "Attempt to write past end of page\n"); return -EINVAL; } @@ -1355,13 +1496,10 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, if (unlikely(to >= mtd->size || column + len > ((mtd->size >> this->page_shift) - (to >> this->page_shift)) * oobsize)) { - printk(KERN_ERR "onenand_write_oob: Attempted to write past end of device\n"); + printk(KERN_ERR "onenand_write_oob_nolock: Attempted to write past end of device\n"); return -EINVAL; } - /* 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 */ @@ -1384,16 +1522,20 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize); onenand_update_bufferram(mtd, to, 0); + if (ONENAND_IS_2PLANE(this)) { + ONENAND_SET_BUFFERRAM1(this); + onenand_update_bufferram(mtd, to + this->writesize, 0); + } ret = this->wait(mtd, FL_WRITING); if (ret) { - printk(KERN_ERR "onenand_write_oob: write failed %d\n", ret); + printk(KERN_ERR "onenand_write_oob_nolock: write failed %d\n", ret); break; } ret = onenand_verify_oob(mtd, oobbuf, to); if (ret) { - printk(KERN_ERR "onenand_write_oob: verify failed %d\n", ret); + printk(KERN_ERR "onenand_write_oob_nolock: verify failed %d\n", ret); break; } @@ -1406,11 +1548,37 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, column = 0; } - /* Deselect and wake up anyone waiting on the device */ - onenand_release_device(mtd); + ops->oobretlen = written; - *retlen = written; + return ret; +} +/** + * onenand_write - [MTD Interface] write buffer to FLASH + * @param mtd MTD device structure + * @param to offset to write to + * @param len number of bytes to write + * @param retlen pointer to variable to store the number of written bytes + * @param buf the data to write + * + * Write with ECC + */ +static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct mtd_oob_ops ops = { + .len = len, + .ooblen = 0, + .datbuf = (u_char *) buf, + .oobbuf = NULL, + }; + int ret; + + onenand_get_device(mtd, FL_WRITING); + ret = onenand_write_ops_nolock(mtd, to, &ops); + onenand_release_device(mtd); + + *retlen = ops.retlen; return ret; } @@ -1423,6 +1591,8 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, static int onenand_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) { + int ret; + switch (ops->mode) { case MTD_OOB_PLACE: case MTD_OOB_AUTO: @@ -1432,21 +1602,27 @@ static int onenand_write_oob(struct mtd_info *mtd, loff_t to, default: return -EINVAL; } - return onenand_do_write_oob(mtd, to + ops->ooboffs, ops->ooblen, - &ops->oobretlen, ops->oobbuf, ops->mode); + + onenand_get_device(mtd, FL_WRITING); + if (ops->datbuf) + ret = onenand_write_ops_nolock(mtd, to, ops); + else + ret = onenand_write_oob_nolock(mtd, to, ops); + onenand_release_device(mtd); + + return ret; } /** - * onenand_block_checkbad - [GENERIC] Check if a block is marked bad + * onenand_block_isbad_nolock - [GENERIC] Check if a block is marked bad * @param mtd MTD device structure * @param ofs offset from device start - * @param getchip 0, if the chip is already selected * @param allowbbt 1, if its allowed to access the bbt area * * Check, if the block is bad. Either by reading the bad block table or * calling of the scan function. */ -static int onenand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt) +static int onenand_block_isbad_nolock(struct mtd_info *mtd, loff_t ofs, int allowbbt) { struct onenand_chip *this = mtd->priv; struct bbm_info *bbm = this->bbm; @@ -1507,7 +1683,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) cond_resched(); /* Check if we have a bad block, we do not erase bad blocks */ - if (onenand_block_checkbad(mtd, addr, 0, 0)) { + if (onenand_block_isbad_nolock(mtd, addr, 0)) { printk (KERN_WARNING "onenand_erase: attempt to erase a bad block at addr 0x%08x\n", (unsigned int) addr); instr->state = MTD_ERASE_FAILED; goto erase_exit; @@ -1535,13 +1711,14 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) erase_exit: ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO; - /* Do call back function */ - if (!ret) - mtd_erase_callback(instr); /* Deselect and wake up anyone waiting on the device */ onenand_release_device(mtd); + /* Do call back function */ + if (!ret) + mtd_erase_callback(instr); + return ret; } @@ -1571,11 +1748,16 @@ static void onenand_sync(struct mtd_info *mtd) */ static int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs) { + int ret; + /* Check for invalid offset */ if (ofs > mtd->size) return -EINVAL; - return onenand_block_checkbad(mtd, ofs, 1, 0); + onenand_get_device(mtd, FL_READING); + ret = onenand_block_isbad_nolock(mtd, ofs, 0); + onenand_release_device(mtd); + return ret; } /** @@ -1591,7 +1773,12 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) struct onenand_chip *this = mtd->priv; struct bbm_info *bbm = this->bbm; u_char buf[2] = {0, 0}; - size_t retlen; + struct mtd_oob_ops ops = { + .mode = MTD_OOB_PLACE, + .ooblen = 2, + .oobbuf = buf, + .ooboffs = 0, + }; int block; /* Get block number */ @@ -1601,7 +1788,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) /* We write two bytes, so we dont have to mess with 16 bit access */ ofs += mtd->oobsize + (bbm->badblockpos & ~0x01); - return onenand_do_write_oob(mtd, ofs , 2, &retlen, buf, MTD_OOB_PLACE); + return onenand_write_oob_nolock(mtd, ofs, &ops); } /** @@ -1624,7 +1811,10 @@ static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs) return ret; } - return this->block_markbad(mtd, ofs); + onenand_get_device(mtd, FL_WRITING); + ret = this->block_markbad(mtd, ofs); + onenand_release_device(mtd); + return ret; } /** @@ -1715,7 +1905,12 @@ static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int */ static int onenand_lock(struct mtd_info *mtd, loff_t ofs, size_t len) { - return onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_LOCK); + int ret; + + onenand_get_device(mtd, FL_LOCKING); + ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_LOCK); + onenand_release_device(mtd); + return ret; } /** @@ -1728,7 +1923,12 @@ static int onenand_lock(struct mtd_info *mtd, loff_t ofs, size_t len) */ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) { - return onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK); + int ret; + + onenand_get_device(mtd, FL_LOCKING); + ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK); + onenand_release_device(mtd); + return ret; } /** @@ -1790,7 +1990,7 @@ static int onenand_unlock_all(struct mtd_info *mtd) loff_t ofs = this->chipsize >> 1; size_t len = mtd->erasesize; - onenand_unlock(mtd, ofs, len); + onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK); } onenand_check_lock_status(this); @@ -1798,7 +1998,7 @@ static int onenand_unlock_all(struct mtd_info *mtd) return 0; } - onenand_unlock(mtd, 0x0, this->chipsize); + onenand_do_lock_cmd(mtd, 0x0, this->chipsize, ONENAND_CMD_UNLOCK); return 0; } @@ -1823,13 +2023,19 @@ static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct onenand_chip *this = mtd->priv; + struct mtd_oob_ops ops = { + .len = len, + .ooblen = 0, + .datbuf = buf, + .oobbuf = NULL, + }; int ret; /* Enter OTP access mode */ this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); this->wait(mtd, FL_OTPING); - ret = mtd->read(mtd, from, len, retlen, buf); + ret = onenand_read_ops_nolock(mtd, from, &ops); /* Exit OTP access mode */ this->command(mtd, ONENAND_CMD_RESET, 0, 0); @@ -1841,19 +2047,20 @@ static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len, /** * do_otp_write - [DEFAULT] Write OTP block area * @param mtd MTD device structure - * @param from The offset to write + * @param to The offset to write * @param len number of bytes to write * @param retlen pointer to variable to store the number of write bytes * @param buf the databuffer to put/get data * * Write OTP block area. */ -static int do_otp_write(struct mtd_info *mtd, loff_t from, size_t len, +static int do_otp_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, u_char *buf) { struct onenand_chip *this = mtd->priv; unsigned char *pbuf = buf; int ret; + struct mtd_oob_ops ops; /* Force buffer page aligned */ if (len < mtd->writesize) { @@ -1867,7 +2074,12 @@ static int do_otp_write(struct mtd_info *mtd, loff_t from, size_t len, this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); this->wait(mtd, FL_OTPING); - ret = mtd->write(mtd, from, len, retlen, pbuf); + ops.len = len; + ops.ooblen = 0; + ops.datbuf = pbuf; + ops.oobbuf = NULL; + ret = onenand_write_ops_nolock(mtd, to, &ops); + *retlen = ops.retlen; /* Exit OTP access mode */ this->command(mtd, ONENAND_CMD_RESET, 0, 0); @@ -1890,13 +2102,21 @@ static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct onenand_chip *this = mtd->priv; + struct mtd_oob_ops ops = { + .mode = MTD_OOB_PLACE, + .ooblen = len, + .oobbuf = buf, + .ooboffs = 0, + }; int ret; /* Enter OTP access mode */ this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); this->wait(mtd, FL_OTPING); - ret = onenand_do_write_oob(mtd, from, len, retlen, buf, MTD_OOB_PLACE); + ret = onenand_write_oob_nolock(mtd, from, &ops); + + *retlen = ops.oobretlen; /* Exit OTP access mode */ this->command(mtd, ONENAND_CMD_RESET, 0, 0); @@ -1943,13 +2163,16 @@ static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len, if (((mtd->writesize * otp_pages) - (from + len)) < 0) return 0; + onenand_get_device(mtd, FL_OTPING); while (len > 0 && otp_pages > 0) { if (!action) { /* OTP Info functions */ struct otp_info *otpinfo; len -= sizeof(struct otp_info); - if (len <= 0) - return -ENOSPC; + if (len <= 0) { + ret = -ENOSPC; + break; + } otpinfo = (struct otp_info *) buf; otpinfo->start = from; @@ -1969,13 +2192,14 @@ static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len, len -= size; *retlen += size; - if (ret < 0) - return ret; + if (ret) + break; } otp_pages--; } + onenand_release_device(mtd); - return 0; + return ret; } /** @@ -2107,6 +2331,7 @@ static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, * * Check and set OneNAND features * - lock scheme + * - two plane */ static void onenand_check_features(struct mtd_info *mtd) { @@ -2118,19 +2343,35 @@ static void onenand_check_features(struct mtd_info *mtd) process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT; /* Lock scheme */ - if (density >= ONENAND_DEVICE_DENSITY_1Gb) { + switch (density) { + case ONENAND_DEVICE_DENSITY_4Gb: + this->options |= ONENAND_HAS_2PLANE; + + case ONENAND_DEVICE_DENSITY_2Gb: + /* 2Gb DDP don't have 2 plane */ + if (!ONENAND_IS_DDP(this)) + this->options |= ONENAND_HAS_2PLANE; + this->options |= ONENAND_HAS_UNLOCK_ALL; + + case ONENAND_DEVICE_DENSITY_1Gb: /* A-Die has all block unlock */ - if (process) { - printk(KERN_DEBUG "Chip support all block unlock\n"); + if (process) this->options |= ONENAND_HAS_UNLOCK_ALL; - } - } else { - /* Some OneNAND has continues lock scheme */ - if (!process) { - printk(KERN_DEBUG "Lock scheme is Continues Lock\n"); + break; + + default: + /* Some OneNAND has continuous lock scheme */ + if (!process) this->options |= ONENAND_HAS_CONT_LOCK; - } + break; } + + if (this->options & ONENAND_HAS_CONT_LOCK) + printk(KERN_DEBUG "Lock scheme is Continuous Lock\n"); + if (this->options & ONENAND_HAS_UNLOCK_ALL) + printk(KERN_DEBUG "Chip support all block unlock\n"); + if (this->options & ONENAND_HAS_2PLANE) + printk(KERN_DEBUG "Chip has 2 plane\n"); } /** @@ -2154,7 +2395,7 @@ static void onenand_print_device_info(int device, int version) (16 << density), vcc ? "2.65/3.3" : "1.8", device); - printk(KERN_DEBUG "OneNAND version = 0x%04x\n", version); + printk(KERN_INFO "OneNAND version = 0x%04x\n", version); } static const struct onenand_manufacturers onenand_manuf_ids[] = { @@ -2257,6 +2498,8 @@ static int onenand_probe(struct mtd_info *mtd) this->erase_shift = ffs(mtd->erasesize) - 1; this->page_shift = ffs(mtd->writesize) - 1; this->page_mask = (1 << (this->erase_shift - this->page_shift)) - 1; + /* It's real page size */ + this->writesize = mtd->writesize; /* REVIST: Multichip handling */ @@ -2265,6 +2508,17 @@ static int onenand_probe(struct mtd_info *mtd) /* Check OneNAND features */ onenand_check_features(mtd); + /* + * We emulate the 4KiB page and 256KiB erase block size + * But oobsize is still 64 bytes. + * It is only valid if you turn on 2X program support, + * Otherwise it will be ignored by compiler. + */ + if (ONENAND_IS_2PLANE(this)) { + mtd->writesize <<= 1; + mtd->erasesize <<= 1; + } + return 0; } diff --git a/drivers/mtd/onenand/onenand_sim.c b/drivers/mtd/onenand/onenand_sim.c new file mode 100644 index 000000000000..0d89ad5776fa --- /dev/null +++ b/drivers/mtd/onenand/onenand_sim.c @@ -0,0 +1,495 @@ +/* + * linux/drivers/mtd/onenand/onenand_sim.c + * + * The OneNAND simulator + * + * Copyright © 2005-2007 Samsung Electronics + * Kyungmin Park <kyungmin.park@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/vmalloc.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/onenand.h> + +#include <linux/io.h> + +#ifndef CONFIG_ONENAND_SIM_MANUFACTURER +#define CONFIG_ONENAND_SIM_MANUFACTURER 0xec +#endif +#ifndef CONFIG_ONENAND_SIM_DEVICE_ID +#define CONFIG_ONENAND_SIM_DEVICE_ID 0x04 +#endif +#ifndef CONFIG_ONENAND_SIM_VERSION_ID +#define CONFIG_ONENAND_SIM_VERSION_ID 0x1e +#endif + +static int manuf_id = CONFIG_ONENAND_SIM_MANUFACTURER; +static int device_id = CONFIG_ONENAND_SIM_DEVICE_ID; +static int version_id = CONFIG_ONENAND_SIM_VERSION_ID; + +struct onenand_flash { + void __iomem *base; + void __iomem *data; +}; + +#define ONENAND_CORE(flash) (flash->data) +#define ONENAND_CORE_SPARE(flash, this, offset) \ + ((flash->data) + (this->chipsize) + (offset >> 5)) + +#define ONENAND_MAIN_AREA(this, offset) \ + (this->base + ONENAND_DATARAM + offset) + +#define ONENAND_SPARE_AREA(this, offset) \ + (this->base + ONENAND_SPARERAM + offset) + +#define ONENAND_GET_WP_STATUS(this) \ + (readw(this->base + ONENAND_REG_WP_STATUS)) + +#define ONENAND_SET_WP_STATUS(v, this) \ + (writew(v, this->base + ONENAND_REG_WP_STATUS)) + +/* It has all 0xff chars */ +#define MAX_ONENAND_PAGESIZE (2048 + 64) +static unsigned char *ffchars; + +static struct mtd_partition os_partitions[] = { + { + .name = "OneNAND simulator partition", + .offset = 0, + .size = MTDPART_SIZ_FULL, + }, +}; + +/* + * OneNAND simulator mtd + */ +struct onenand_info { + struct mtd_info mtd; + struct mtd_partition *parts; + struct onenand_chip onenand; + struct onenand_flash flash; +}; + +static struct onenand_info *info; + +#define DPRINTK(format, args...) \ +do { \ + printk(KERN_DEBUG "%s[%d]: " format "\n", __func__, \ + __LINE__, ##args); \ +} while (0) + +/** + * onenand_lock_handle - Handle Lock scheme + * @param this OneNAND device structure + * @param cmd The command to be sent + * + * Send lock command to OneNAND device. + * The lock scheme is depends on chip type. + */ +static void onenand_lock_handle(struct onenand_chip *this, int cmd) +{ + int block_lock_scheme; + int status; + + status = ONENAND_GET_WP_STATUS(this); + block_lock_scheme = !(this->options & ONENAND_HAS_CONT_LOCK); + + switch (cmd) { + case ONENAND_CMD_UNLOCK: + if (block_lock_scheme) + ONENAND_SET_WP_STATUS(ONENAND_WP_US, this); + else + ONENAND_SET_WP_STATUS(status | ONENAND_WP_US, this); + break; + + case ONENAND_CMD_LOCK: + if (block_lock_scheme) + ONENAND_SET_WP_STATUS(ONENAND_WP_LS, this); + else + ONENAND_SET_WP_STATUS(status | ONENAND_WP_LS, this); + break; + + case ONENAND_CMD_LOCK_TIGHT: + if (block_lock_scheme) + ONENAND_SET_WP_STATUS(ONENAND_WP_LTS, this); + else + ONENAND_SET_WP_STATUS(status | ONENAND_WP_LTS, this); + break; + + default: + break; + } +} + +/** + * onenand_bootram_handle - Handle BootRAM area + * @param this OneNAND device structure + * @param cmd The command to be sent + * + * Emulate BootRAM area. It is possible to do basic operation using BootRAM. + */ +static void onenand_bootram_handle(struct onenand_chip *this, int cmd) +{ + switch (cmd) { + case ONENAND_CMD_READID: + writew(manuf_id, this->base); + writew(device_id, this->base + 2); + writew(version_id, this->base + 4); + break; + + default: + /* REVIST: Handle other commands */ + break; + } +} + +/** + * onenand_update_interrupt - Set interrupt register + * @param this OneNAND device structure + * @param cmd The command to be sent + * + * Update interrupt register. The status is depends on command. + */ +static void onenand_update_interrupt(struct onenand_chip *this, int cmd) +{ + int interrupt = ONENAND_INT_MASTER; + + switch (cmd) { + case ONENAND_CMD_READ: + case ONENAND_CMD_READOOB: + interrupt |= ONENAND_INT_READ; + break; + + case ONENAND_CMD_PROG: + case ONENAND_CMD_PROGOOB: + interrupt |= ONENAND_INT_WRITE; + break; + + case ONENAND_CMD_ERASE: + interrupt |= ONENAND_INT_ERASE; + break; + + case ONENAND_CMD_RESET: + interrupt |= ONENAND_INT_RESET; + break; + + default: + break; + } + + writew(interrupt, this->base + ONENAND_REG_INTERRUPT); +} + +/** + * onenand_check_overwrite - Check over-write if happend + * @param dest The destination pointer + * @param src The source pointer + * @param count The length to be check + * @return 0 on same, otherwise 1 + * + * Compare the source with destination + */ +static int onenand_check_overwrite(void *dest, void *src, size_t count) +{ + unsigned int *s = (unsigned int *) src; + unsigned int *d = (unsigned int *) dest; + int i; + + count >>= 2; + for (i = 0; i < count; i++) + if ((*s++ ^ *d++) != 0) + return 1; + + return 0; +} + +/** + * onenand_data_handle - Handle OneNAND Core and DataRAM + * @param this OneNAND device structure + * @param cmd The command to be sent + * @param dataram Which dataram used + * @param offset The offset to OneNAND Core + * + * Copy data from OneNAND Core to DataRAM (read) + * Copy data from DataRAM to OneNAND Core (write) + * Erase the OneNAND Core (erase) + */ +static void onenand_data_handle(struct onenand_chip *this, int cmd, + int dataram, unsigned int offset) +{ + struct mtd_info *mtd = &info->mtd; + struct onenand_flash *flash = this->priv; + int main_offset, spare_offset; + void __iomem *src; + void __iomem *dest; + unsigned int i; + + if (dataram) { + main_offset = mtd->writesize; + spare_offset = mtd->oobsize; + } else { + main_offset = 0; + spare_offset = 0; + } + + switch (cmd) { + case ONENAND_CMD_READ: + src = ONENAND_CORE(flash) + offset; + dest = ONENAND_MAIN_AREA(this, main_offset); + memcpy(dest, src, mtd->writesize); + /* Fall through */ + + case ONENAND_CMD_READOOB: + src = ONENAND_CORE_SPARE(flash, this, offset); + dest = ONENAND_SPARE_AREA(this, spare_offset); + memcpy(dest, src, mtd->oobsize); + break; + + case ONENAND_CMD_PROG: + src = ONENAND_MAIN_AREA(this, main_offset); + dest = ONENAND_CORE(flash) + offset; + /* To handle partial write */ + for (i = 0; i < (1 << mtd->subpage_sft); i++) { + int off = i * this->subpagesize; + if (!memcmp(src + off, ffchars, this->subpagesize)) + continue; + if (memcmp(dest + off, ffchars, this->subpagesize) && + onenand_check_overwrite(dest + off, src + off, this->subpagesize)) + printk(KERN_ERR "over-write happend at 0x%08x\n", offset); + memcpy(dest + off, src + off, this->subpagesize); + } + /* Fall through */ + + case ONENAND_CMD_PROGOOB: + src = ONENAND_SPARE_AREA(this, spare_offset); + /* Check all data is 0xff chars */ + if (!memcmp(src, ffchars, mtd->oobsize)) + break; + + dest = ONENAND_CORE_SPARE(flash, this, offset); + if (memcmp(dest, ffchars, mtd->oobsize) && + onenand_check_overwrite(dest, src, mtd->oobsize)) + printk(KERN_ERR "OOB: over-write happend at 0x%08x\n", + offset); + memcpy(dest, src, mtd->oobsize); + break; + + case ONENAND_CMD_ERASE: + memset(ONENAND_CORE(flash) + offset, 0xff, mtd->erasesize); + memset(ONENAND_CORE_SPARE(flash, this, offset), 0xff, + (mtd->erasesize >> 5)); + break; + + default: + break; + } +} + +/** + * onenand_command_handle - Handle command + * @param this OneNAND device structure + * @param cmd The command to be sent + * + * Emulate OneNAND command. + */ +static void onenand_command_handle(struct onenand_chip *this, int cmd) +{ + unsigned long offset = 0; + int block = -1, page = -1, bufferram = -1; + int dataram = 0; + + switch (cmd) { + case ONENAND_CMD_UNLOCK: + case ONENAND_CMD_LOCK: + case ONENAND_CMD_LOCK_TIGHT: + case ONENAND_CMD_UNLOCK_ALL: + onenand_lock_handle(this, cmd); + break; + + case ONENAND_CMD_BUFFERRAM: + /* Do nothing */ + return; + + default: + block = (int) readw(this->base + ONENAND_REG_START_ADDRESS1); + if (block & (1 << ONENAND_DDP_SHIFT)) { + block &= ~(1 << ONENAND_DDP_SHIFT); + /* The half of chip block */ + block += this->chipsize >> (this->erase_shift + 1); + } + if (cmd == ONENAND_CMD_ERASE) + break; + + page = (int) readw(this->base + ONENAND_REG_START_ADDRESS8); + page = (page >> ONENAND_FPA_SHIFT); + bufferram = (int) readw(this->base + ONENAND_REG_START_BUFFER); + bufferram >>= ONENAND_BSA_SHIFT; + bufferram &= ONENAND_BSA_DATARAM1; + dataram = (bufferram == ONENAND_BSA_DATARAM1) ? 1 : 0; + break; + } + + if (block != -1) + offset += block << this->erase_shift; + + if (page != -1) + offset += page << this->page_shift; + + onenand_data_handle(this, cmd, dataram, offset); + + onenand_update_interrupt(this, cmd); +} + +/** + * onenand_writew - [OneNAND Interface] Emulate write operation + * @param value value to write + * @param addr address to write + * + * Write OneNAND register with value + */ +static void onenand_writew(unsigned short value, void __iomem * addr) +{ + struct onenand_chip *this = info->mtd.priv; + + /* BootRAM handling */ + if (addr < this->base + ONENAND_DATARAM) { + onenand_bootram_handle(this, value); + return; + } + /* Command handling */ + if (addr == this->base + ONENAND_REG_COMMAND) + onenand_command_handle(this, value); + + writew(value, addr); +} + +/** + * flash_init - Initialize OneNAND simulator + * @param flash OneNAND simulaotr data strucutres + * + * Initialize OneNAND simulator. + */ +static int __init flash_init(struct onenand_flash *flash) +{ + int density, size; + int buffer_size; + + flash->base = kzalloc(131072, GFP_KERNEL); + if (!flash->base) { + printk(KERN_ERR "Unable to allocate base address.\n"); + return -ENOMEM; + } + + density = device_id >> ONENAND_DEVICE_DENSITY_SHIFT; + size = ((16 << 20) << density); + + ONENAND_CORE(flash) = vmalloc(size + (size >> 5)); + if (!ONENAND_CORE(flash)) { + printk(KERN_ERR "Unable to allocate nand core address.\n"); + kfree(flash->base); + return -ENOMEM; + } + + memset(ONENAND_CORE(flash), 0xff, size + (size >> 5)); + + /* Setup registers */ + writew(manuf_id, flash->base + ONENAND_REG_MANUFACTURER_ID); + writew(device_id, flash->base + ONENAND_REG_DEVICE_ID); + writew(version_id, flash->base + ONENAND_REG_VERSION_ID); + + if (density < 2) + buffer_size = 0x0400; /* 1KiB page */ + else + buffer_size = 0x0800; /* 2KiB page */ + writew(buffer_size, flash->base + ONENAND_REG_DATA_BUFFER_SIZE); + + return 0; +} + +/** + * flash_exit - Clean up OneNAND simulator + * @param flash OneNAND simulaotr data strucutres + * + * Clean up OneNAND simulator. + */ +static void flash_exit(struct onenand_flash *flash) +{ + vfree(ONENAND_CORE(flash)); + kfree(flash->base); + kfree(flash); +} + +static int __init onenand_sim_init(void) +{ + /* Allocate all 0xff chars pointer */ + ffchars = kmalloc(MAX_ONENAND_PAGESIZE, GFP_KERNEL); + if (!ffchars) { + printk(KERN_ERR "Unable to allocate ff chars.\n"); + return -ENOMEM; + } + memset(ffchars, 0xff, MAX_ONENAND_PAGESIZE); + + /* Allocate OneNAND simulator mtd pointer */ + info = kzalloc(sizeof(struct onenand_info), GFP_KERNEL); + if (!info) { + printk(KERN_ERR "Unable to allocate core structures.\n"); + kfree(ffchars); + return -ENOMEM; + } + + /* Override write_word function */ + info->onenand.write_word = onenand_writew; + + if (flash_init(&info->flash)) { + printk(KERN_ERR "Unable to allocat flash.\n"); + kfree(ffchars); + kfree(info); + return -ENOMEM; + } + + info->parts = os_partitions; + + info->onenand.base = info->flash.base; + info->onenand.priv = &info->flash; + + info->mtd.name = "OneNAND simulator"; + info->mtd.priv = &info->onenand; + info->mtd.owner = THIS_MODULE; + + if (onenand_scan(&info->mtd, 1)) { + flash_exit(&info->flash); + kfree(ffchars); + kfree(info); + return -ENXIO; + } + + add_mtd_partitions(&info->mtd, info->parts, ARRAY_SIZE(os_partitions)); + + return 0; +} + +static void __exit onenand_sim_exit(void) +{ + struct onenand_chip *this = info->mtd.priv; + struct onenand_flash *flash = this->priv; + + onenand_release(&info->mtd); + flash_exit(flash); + kfree(ffchars); + kfree(info); +} + +module_init(onenand_sim_init); +module_exit(onenand_sim_exit); + +MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>"); +MODULE_DESCRIPTION("The OneNAND flash simulator"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c index 006c03aacb55..823fba4e6d2f 100644 --- a/drivers/mtd/rfd_ftl.c +++ b/drivers/mtd/rfd_ftl.c @@ -779,10 +779,8 @@ static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) else { if (!mtd->erasesize) { printk(KERN_WARNING PREFIX "please provide block_size"); - kfree(part); - return; - } - else + goto out; + } else part->block_size = mtd->erasesize; } @@ -804,7 +802,7 @@ static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) if (!add_mtd_blktrans_dev((void*)part)) return; } - +out: kfree(part); } diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 1cb22bfae750..023653977a1a 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -565,7 +565,7 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset, } ubi = ubi_devices[ubi_devices_cnt] = kzalloc(sizeof(struct ubi_device), - GFP_KERNEL); + GFP_KERNEL); if (!ubi) { err = -ENOMEM; goto out_mtd; @@ -583,6 +583,22 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset, if (err) goto out_free; + mutex_init(&ubi->buf_mutex); + ubi->peb_buf1 = vmalloc(ubi->peb_size); + if (!ubi->peb_buf1) + goto out_free; + + ubi->peb_buf2 = vmalloc(ubi->peb_size); + if (!ubi->peb_buf2) + goto out_free; + +#ifdef CONFIG_MTD_UBI_DEBUG + mutex_init(&ubi->dbg_buf_mutex); + ubi->dbg_peb_buf = vmalloc(ubi->peb_size); + if (!ubi->dbg_peb_buf) + goto out_free; +#endif + err = attach_by_scanning(ubi); if (err) { dbg_err("failed to attach by scanning, error %d", err); @@ -630,6 +646,11 @@ out_detach: ubi_wl_close(ubi); vfree(ubi->vtbl); out_free: + vfree(ubi->peb_buf1); + vfree(ubi->peb_buf2); +#ifdef CONFIG_MTD_UBI_DEBUG + vfree(ubi->dbg_peb_buf); +#endif kfree(ubi); out_mtd: put_mtd_device(mtd); @@ -651,6 +672,11 @@ static void detach_mtd_dev(struct ubi_device *ubi) ubi_wl_close(ubi); vfree(ubi->vtbl); put_mtd_device(ubi->mtd); + vfree(ubi->peb_buf1); + vfree(ubi->peb_buf2); +#ifdef CONFIG_MTD_UBI_DEBUG + vfree(ubi->dbg_peb_buf); +#endif kfree(ubi_devices[ubi_num]); ubi_devices[ubi_num] = NULL; ubi_devices_cnt -= 1; diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c index 310341e5cd43..56956ec2845f 100644 --- a/drivers/mtd/ubi/debug.c +++ b/drivers/mtd/ubi/debug.c @@ -42,7 +42,8 @@ void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr) dbg_msg("data_offset %d", be32_to_cpu(ec_hdr->data_offset)); dbg_msg("hdr_crc %#08x", be32_to_cpu(ec_hdr->hdr_crc)); dbg_msg("erase counter header hexdump:"); - ubi_dbg_hexdump(ec_hdr, UBI_EC_HDR_SIZE); + print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, + ec_hdr, UBI_EC_HDR_SIZE, 1); } /** @@ -187,38 +188,4 @@ void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req) dbg_msg("the 1st 16 characters of the name: %s", nm); } -#define BYTES_PER_LINE 32 - -/** - * ubi_dbg_hexdump - dump a buffer. - * @ptr: the buffer to dump - * @size: buffer size which must be multiple of 4 bytes - */ -void ubi_dbg_hexdump(const void *ptr, int size) -{ - int i, k = 0, rows, columns; - const uint8_t *p = ptr; - - size = ALIGN(size, 4); - rows = size/BYTES_PER_LINE + size % BYTES_PER_LINE; - for (i = 0; i < rows; i++) { - int j; - - cond_resched(); - columns = min(size - k, BYTES_PER_LINE) / 4; - if (columns == 0) - break; - printk(KERN_DEBUG "%5d: ", i * BYTES_PER_LINE); - for (j = 0; j < columns; j++) { - int n, N; - - N = size - k > 4 ? 4 : size - k; - for (n = 0; n < N; n++) - printk("%02x", p[k++]); - printk(" "); - } - printk("\n"); - } -} - #endif /* CONFIG_MTD_UBI_DEBUG_MSG */ diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h index ff8f39548cd8..467722eb618b 100644 --- a/drivers/mtd/ubi/debug.h +++ b/drivers/mtd/ubi/debug.h @@ -59,7 +59,6 @@ void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx); void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv); void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type); void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req); -void ubi_dbg_hexdump(const void *buf, int size); #else @@ -72,7 +71,6 @@ void ubi_dbg_hexdump(const void *buf, int size); #define ubi_dbg_dump_sv(sv) ({}) #define ubi_dbg_dump_seb(seb, type) ({}) #define ubi_dbg_dump_mkvol_req(req) ({}) -#define ubi_dbg_hexdump(buf, size) ({}) #endif /* CONFIG_MTD_UBI_DEBUG_MSG */ diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 7c5e29eaf118..1297732f4db9 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -46,6 +46,9 @@ #include <linux/err.h> #include "ubi.h" +/* Number of physical eraseblocks reserved for atomic LEB change operation */ +#define EBA_RESERVED_PEBS 1 + /** * struct ltree_entry - an entry in the lock tree. * @rb: links RB-tree nodes @@ -157,7 +160,7 @@ static struct ltree_entry *ltree_add_entry(struct ubi_device *ubi, int vol_id, { struct ltree_entry *le, *le1, *le_free; - le = kmem_cache_alloc(ltree_slab, GFP_KERNEL); + le = kmem_cache_alloc(ltree_slab, GFP_NOFS); if (!le) return ERR_PTR(-ENOMEM); @@ -397,7 +400,7 @@ int ubi_eba_read_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf, retry: if (check) { - vid_hdr = ubi_zalloc_vid_hdr(ubi); + vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); if (!vid_hdr) { err = -ENOMEM; goto out_unlock; @@ -495,16 +498,18 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum, int err, idx = vol_id2idx(ubi, vol_id), new_pnum, data_size, tries = 0; struct ubi_volume *vol = ubi->volumes[idx]; struct ubi_vid_hdr *vid_hdr; - unsigned char *new_buf; - vid_hdr = ubi_zalloc_vid_hdr(ubi); + vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); if (!vid_hdr) { return -ENOMEM; } + mutex_lock(&ubi->buf_mutex); + retry: new_pnum = ubi_wl_get_peb(ubi, UBI_UNKNOWN); if (new_pnum < 0) { + mutex_unlock(&ubi->buf_mutex); ubi_free_vid_hdr(ubi, vid_hdr); return new_pnum; } @@ -524,31 +529,22 @@ retry: goto write_error; data_size = offset + len; - new_buf = vmalloc(data_size); - if (!new_buf) { - err = -ENOMEM; - goto out_put; - } - memset(new_buf + offset, 0xFF, len); + memset(ubi->peb_buf1 + offset, 0xFF, len); /* Read everything before the area where the write failure happened */ if (offset > 0) { - err = ubi_io_read_data(ubi, new_buf, pnum, 0, offset); - if (err && err != UBI_IO_BITFLIPS) { - vfree(new_buf); + err = ubi_io_read_data(ubi, ubi->peb_buf1, pnum, 0, offset); + if (err && err != UBI_IO_BITFLIPS) goto out_put; - } } - memcpy(new_buf + offset, buf, len); + memcpy(ubi->peb_buf1 + offset, buf, len); - err = ubi_io_write_data(ubi, new_buf, new_pnum, 0, data_size); - if (err) { - vfree(new_buf); + err = ubi_io_write_data(ubi, ubi->peb_buf1, new_pnum, 0, data_size); + if (err) goto write_error; - } - vfree(new_buf); + mutex_unlock(&ubi->buf_mutex); ubi_free_vid_hdr(ubi, vid_hdr); vol->eba_tbl[lnum] = new_pnum; @@ -558,6 +554,7 @@ retry: return 0; out_put: + mutex_unlock(&ubi->buf_mutex); ubi_wl_put_peb(ubi, new_pnum, 1); ubi_free_vid_hdr(ubi, vid_hdr); return err; @@ -570,6 +567,7 @@ write_error: ubi_warn("failed to write to PEB %d", new_pnum); ubi_wl_put_peb(ubi, new_pnum, 1); if (++tries > UBI_IO_RETRIES) { + mutex_unlock(&ubi->buf_mutex); ubi_free_vid_hdr(ubi, vid_hdr); return err; } @@ -627,7 +625,7 @@ int ubi_eba_write_leb(struct ubi_device *ubi, int vol_id, int lnum, * The logical eraseblock is not mapped. We have to get a free physical * eraseblock and write the volume identifier header there first. */ - vid_hdr = ubi_zalloc_vid_hdr(ubi); + vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); if (!vid_hdr) { leb_write_unlock(ubi, vol_id, lnum); return -ENOMEM; @@ -738,7 +736,7 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, int vol_id, int lnum, else ubi_assert(len % ubi->min_io_size == 0); - vid_hdr = ubi_zalloc_vid_hdr(ubi); + vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); if (!vid_hdr) return -ENOMEM; @@ -832,6 +830,9 @@ write_error: * data, which has to be aligned. This function guarantees that in case of an * unclean reboot the old contents is preserved. Returns zero in case of * success and a negative error code in case of failure. + * + * UBI reserves one LEB for the "atomic LEB change" operation, so only one + * LEB change may be done at a time. This is ensured by @ubi->alc_mutex. */ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum, const void *buf, int len, int dtype) @@ -844,15 +845,14 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum, if (ubi->ro_mode) return -EROFS; - vid_hdr = ubi_zalloc_vid_hdr(ubi); + vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); if (!vid_hdr) return -ENOMEM; + mutex_lock(&ubi->alc_mutex); err = leb_write_lock(ubi, vol_id, lnum); - if (err) { - ubi_free_vid_hdr(ubi, vid_hdr); - return err; - } + if (err) + goto out_mutex; vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); vid_hdr->vol_id = cpu_to_be32(vol_id); @@ -869,9 +869,8 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum, retry: pnum = ubi_wl_get_peb(ubi, dtype); if (pnum < 0) { - ubi_free_vid_hdr(ubi, vid_hdr); - leb_write_unlock(ubi, vol_id, lnum); - return pnum; + err = pnum; + goto out_leb_unlock; } dbg_eba("change LEB %d:%d, PEB %d, write VID hdr to PEB %d", @@ -893,17 +892,18 @@ retry: if (vol->eba_tbl[lnum] >= 0) { err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 1); - if (err) { - ubi_free_vid_hdr(ubi, vid_hdr); - leb_write_unlock(ubi, vol_id, lnum); - return err; - } + if (err) + goto out_leb_unlock; } vol->eba_tbl[lnum] = pnum; + +out_leb_unlock: leb_write_unlock(ubi, vol_id, lnum); +out_mutex: + mutex_unlock(&ubi->alc_mutex); ubi_free_vid_hdr(ubi, vid_hdr); - return 0; + return err; write_error: if (err != -EIO || !ubi->bad_allowed) { @@ -913,17 +913,13 @@ write_error: * mode just in case. */ ubi_ro_mode(ubi); - leb_write_unlock(ubi, vol_id, lnum); - ubi_free_vid_hdr(ubi, vid_hdr); - return err; + goto out_leb_unlock; } err = ubi_wl_put_peb(ubi, pnum, 1); if (err || ++tries > UBI_IO_RETRIES) { ubi_ro_mode(ubi); - leb_write_unlock(ubi, vol_id, lnum); - ubi_free_vid_hdr(ubi, vid_hdr); - return err; + goto out_leb_unlock; } vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); @@ -965,7 +961,6 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, int err, vol_id, lnum, data_size, aldata_size, pnum, idx; struct ubi_volume *vol; uint32_t crc; - void *buf, *buf1 = NULL; vol_id = be32_to_cpu(vid_hdr->vol_id); lnum = be32_to_cpu(vid_hdr->lnum); @@ -979,19 +974,15 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, data_size = aldata_size = ubi->leb_size - be32_to_cpu(vid_hdr->data_pad); - buf = vmalloc(aldata_size); - if (!buf) - return -ENOMEM; - /* * We do not want anybody to write to this logical eraseblock while we * are moving it, so we lock it. */ err = leb_write_lock(ubi, vol_id, lnum); - if (err) { - vfree(buf); + if (err) return err; - } + + mutex_lock(&ubi->buf_mutex); /* * But the logical eraseblock might have been put by this time. @@ -1023,7 +1014,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, /* OK, now the LEB is locked and we can safely start moving it */ dbg_eba("read %d bytes of data", aldata_size); - err = ubi_io_read_data(ubi, buf, from, 0, aldata_size); + err = ubi_io_read_data(ubi, ubi->peb_buf1, from, 0, aldata_size); if (err && err != UBI_IO_BITFLIPS) { ubi_warn("error %d while reading data from PEB %d", err, from); @@ -1042,10 +1033,10 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, */ if (vid_hdr->vol_type == UBI_VID_DYNAMIC) aldata_size = data_size = - ubi_calc_data_len(ubi, buf, data_size); + ubi_calc_data_len(ubi, ubi->peb_buf1, data_size); cond_resched(); - crc = crc32(UBI_CRC32_INIT, buf, data_size); + crc = crc32(UBI_CRC32_INIT, ubi->peb_buf1, data_size); cond_resched(); /* @@ -1076,23 +1067,18 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, } if (data_size > 0) { - err = ubi_io_write_data(ubi, buf, to, 0, aldata_size); + err = ubi_io_write_data(ubi, ubi->peb_buf1, to, 0, aldata_size); if (err) goto out_unlock; + cond_resched(); + /* * We've written the data and are going to read it back to make * sure it was written correctly. */ - buf1 = vmalloc(aldata_size); - if (!buf1) { - err = -ENOMEM; - goto out_unlock; - } - - cond_resched(); - err = ubi_io_read_data(ubi, buf1, to, 0, aldata_size); + err = ubi_io_read_data(ubi, ubi->peb_buf2, to, 0, aldata_size); if (err) { if (err != UBI_IO_BITFLIPS) ubi_warn("cannot read data back from PEB %d", @@ -1102,7 +1088,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, cond_resched(); - if (memcmp(buf, buf1, aldata_size)) { + if (memcmp(ubi->peb_buf1, ubi->peb_buf2, aldata_size)) { ubi_warn("read data back from PEB %d - it is different", to); goto out_unlock; @@ -1112,16 +1098,9 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, ubi_assert(vol->eba_tbl[lnum] == from); vol->eba_tbl[lnum] = to; - leb_write_unlock(ubi, vol_id, lnum); - vfree(buf); - vfree(buf1); - - return 0; - out_unlock: + mutex_unlock(&ubi->buf_mutex); leb_write_unlock(ubi, vol_id, lnum); - vfree(buf); - vfree(buf1); return err; } @@ -1144,6 +1123,7 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si) dbg_eba("initialize EBA unit"); spin_lock_init(&ubi->ltree_lock); + mutex_init(&ubi->alc_mutex); ubi->ltree = RB_ROOT; if (ubi_devices_cnt == 0) { @@ -1205,6 +1185,15 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si) ubi->rsvd_pebs += ubi->beb_rsvd_pebs; } + if (ubi->avail_pebs < EBA_RESERVED_PEBS) { + ubi_err("no enough physical eraseblocks (%d, need %d)", + ubi->avail_pebs, EBA_RESERVED_PEBS); + err = -ENOSPC; + goto out_free; + } + ubi->avail_pebs -= EBA_RESERVED_PEBS; + ubi->rsvd_pebs += EBA_RESERVED_PEBS; + dbg_eba("EBA unit is initialized"); return 0; diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index b0d8f4cede97..7c304eec78b5 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -98,8 +98,8 @@ static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum, static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum); static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum, const struct ubi_vid_hdr *vid_hdr); -static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum, - int offset, int len); +static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset, + int len); #else #define paranoid_check_not_bad(ubi, pnum) 0 #define paranoid_check_peb_ec_hdr(ubi, pnum) 0 @@ -202,8 +202,8 @@ retry: * Note, in case of an error, it is possible that something was still written * to the flash media, but may be some garbage. */ -int ubi_io_write(const struct ubi_device *ubi, const void *buf, int pnum, - int offset, int len) +int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset, + int len) { int err; size_t written; @@ -285,7 +285,7 @@ static void erase_callback(struct erase_info *ei) * zero in case of success and a negative error code in case of failure. If * %-EIO is returned, the physical eraseblock most probably went bad. */ -static int do_sync_erase(const struct ubi_device *ubi, int pnum) +static int do_sync_erase(struct ubi_device *ubi, int pnum) { int err, retries = 0; struct erase_info ei; @@ -377,29 +377,25 @@ static uint8_t patterns[] = {0xa5, 0x5a, 0x0}; * test, a positive number of erase operations done if the test was * successfully passed, and other negative error codes in case of other errors. */ -static int torture_peb(const struct ubi_device *ubi, int pnum) +static int torture_peb(struct ubi_device *ubi, int pnum) { - void *buf; int err, i, patt_count; - buf = vmalloc(ubi->peb_size); - if (!buf) - return -ENOMEM; - patt_count = ARRAY_SIZE(patterns); ubi_assert(patt_count > 0); + mutex_lock(&ubi->buf_mutex); for (i = 0; i < patt_count; i++) { err = do_sync_erase(ubi, pnum); if (err) goto out; /* Make sure the PEB contains only 0xFF bytes */ - err = ubi_io_read(ubi, buf, pnum, 0, ubi->peb_size); + err = ubi_io_read(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size); if (err) goto out; - err = check_pattern(buf, 0xFF, ubi->peb_size); + err = check_pattern(ubi->peb_buf1, 0xFF, ubi->peb_size); if (err == 0) { ubi_err("erased PEB %d, but a non-0xFF byte found", pnum); @@ -408,17 +404,17 @@ static int torture_peb(const struct ubi_device *ubi, int pnum) } /* Write a pattern and check it */ - memset(buf, patterns[i], ubi->peb_size); - err = ubi_io_write(ubi, buf, pnum, 0, ubi->peb_size); + memset(ubi->peb_buf1, patterns[i], ubi->peb_size); + err = ubi_io_write(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size); if (err) goto out; - memset(buf, ~patterns[i], ubi->peb_size); - err = ubi_io_read(ubi, buf, pnum, 0, ubi->peb_size); + memset(ubi->peb_buf1, ~patterns[i], ubi->peb_size); + err = ubi_io_read(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size); if (err) goto out; - err = check_pattern(buf, patterns[i], ubi->peb_size); + err = check_pattern(ubi->peb_buf1, patterns[i], ubi->peb_size); if (err == 0) { ubi_err("pattern %x checking failed for PEB %d", patterns[i], pnum); @@ -430,14 +426,17 @@ static int torture_peb(const struct ubi_device *ubi, int pnum) err = patt_count; out: - if (err == UBI_IO_BITFLIPS || err == -EBADMSG) + mutex_unlock(&ubi->buf_mutex); + if (err == UBI_IO_BITFLIPS || err == -EBADMSG) { /* * If a bit-flip or data integrity error was detected, the test * has not passed because it happened on a freshly erased * physical eraseblock which means something is wrong with it. */ + ubi_err("read problems on freshly erased PEB %d, must be bad", + pnum); err = -EIO; - vfree(buf); + } return err; } @@ -457,7 +456,7 @@ out: * codes in case of other errors. Note, %-EIO means that the physical * eraseblock is bad. */ -int ubi_io_sync_erase(const struct ubi_device *ubi, int pnum, int torture) +int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture) { int err, ret = 0; @@ -614,7 +613,7 @@ bad: * o %UBI_IO_PEB_EMPTY if the physical eraseblock is empty; * o a negative error code in case of failure. */ -int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum, +int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, struct ubi_ec_hdr *ec_hdr, int verbose) { int err, read_err = 0; @@ -720,7 +719,7 @@ int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum, * case of failure. If %-EIO is returned, the physical eraseblock most probably * went bad. */ -int ubi_io_write_ec_hdr(const struct ubi_device *ubi, int pnum, +int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum, struct ubi_ec_hdr *ec_hdr) { int err; @@ -886,7 +885,7 @@ bad: * header there); * o a negative error code in case of failure. */ -int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum, +int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, struct ubi_vid_hdr *vid_hdr, int verbose) { int err, read_err = 0; @@ -993,7 +992,7 @@ int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum, * case of failure. If %-EIO is returned, the physical eraseblock probably went * bad. */ -int ubi_io_write_vid_hdr(const struct ubi_device *ubi, int pnum, +int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum, struct ubi_vid_hdr *vid_hdr) { int err; @@ -1096,7 +1095,7 @@ static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum) uint32_t crc, hdr_crc; struct ubi_ec_hdr *ec_hdr; - ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL); + ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS); if (!ec_hdr) return -ENOMEM; @@ -1176,7 +1175,7 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum) struct ubi_vid_hdr *vid_hdr; void *p; - vid_hdr = ubi_zalloc_vid_hdr(ubi); + vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); if (!vid_hdr) return -ENOMEM; @@ -1216,44 +1215,40 @@ exit: * @offset of the physical eraseblock @pnum, %1 if not, and a negative error * code if an error occurred. */ -static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum, - int offset, int len) +static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset, + int len) { size_t read; int err; - void *buf; loff_t addr = (loff_t)pnum * ubi->peb_size + offset; - buf = vmalloc(len); - if (!buf) - return -ENOMEM; - memset(buf, 0, len); - - err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf); + mutex_lock(&ubi->dbg_buf_mutex); + err = ubi->mtd->read(ubi->mtd, addr, len, &read, ubi->dbg_peb_buf); if (err && err != -EUCLEAN) { ubi_err("error %d while reading %d bytes from PEB %d:%d, " "read %zd bytes", err, len, pnum, offset, read); goto error; } - err = check_pattern(buf, 0xFF, len); + err = check_pattern(ubi->dbg_peb_buf, 0xFF, len); if (err == 0) { ubi_err("flash region at PEB %d:%d, length %d does not " "contain all 0xFF bytes", pnum, offset, len); goto fail; } + mutex_unlock(&ubi->dbg_buf_mutex); - vfree(buf); return 0; fail: ubi_err("paranoid check failed for PEB %d", pnum); dbg_msg("hex dump of the %d-%d region", offset, offset + len); - ubi_dbg_hexdump(buf, len); + print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, + ubi->dbg_peb_buf, len, 1); err = 1; error: ubi_dbg_dump_stack(); - vfree(buf); + mutex_unlock(&ubi->dbg_buf_mutex); return err; } diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c index 4a458e83e4e9..03c774f41549 100644 --- a/drivers/mtd/ubi/kapi.c +++ b/drivers/mtd/ubi/kapi.c @@ -99,16 +99,21 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode) { int err; struct ubi_volume_desc *desc; - struct ubi_device *ubi = ubi_devices[ubi_num]; + struct ubi_device *ubi; struct ubi_volume *vol; dbg_msg("open device %d volume %d, mode %d", ubi_num, vol_id, mode); err = -ENODEV; + if (ubi_num < 0) + return ERR_PTR(err); + + ubi = ubi_devices[ubi_num]; + if (!try_module_get(THIS_MODULE)) return ERR_PTR(err); - if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES || !ubi) + if (ubi_num >= UBI_MAX_DEVICES || !ubi) goto out_put; err = -EINVAL; diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c index 94ee54934411..c7b0afc9d280 100644 --- a/drivers/mtd/ubi/scan.c +++ b/drivers/mtd/ubi/scan.c @@ -45,8 +45,7 @@ #include "ubi.h" #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID -static int paranoid_check_si(const struct ubi_device *ubi, - struct ubi_scan_info *si); +static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si); #else #define paranoid_check_si(ubi, si) 0 #endif @@ -259,14 +258,13 @@ static struct ubi_scan_volume *add_volume(struct ubi_scan_info *si, int vol_id, * o bit 2 is cleared: the older LEB is not corrupted; * o bit 2 is set: the older LEB is corrupted. */ -static int compare_lebs(const struct ubi_device *ubi, - const struct ubi_scan_leb *seb, int pnum, - const struct ubi_vid_hdr *vid_hdr) +static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb, + int pnum, const struct ubi_vid_hdr *vid_hdr) { void *buf; int len, err, second_is_newer, bitflips = 0, corrupted = 0; uint32_t data_crc, crc; - struct ubi_vid_hdr *vidh = NULL; + struct ubi_vid_hdr *vh = NULL; unsigned long long sqnum2 = be64_to_cpu(vid_hdr->sqnum); if (seb->sqnum == 0 && sqnum2 == 0) { @@ -323,11 +321,11 @@ static int compare_lebs(const struct ubi_device *ubi, } else { pnum = seb->pnum; - vidh = ubi_zalloc_vid_hdr(ubi); - if (!vidh) + vh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL); + if (!vh) return -ENOMEM; - err = ubi_io_read_vid_hdr(ubi, pnum, vidh, 0); + err = ubi_io_read_vid_hdr(ubi, pnum, vh, 0); if (err) { if (err == UBI_IO_BITFLIPS) bitflips = 1; @@ -341,7 +339,7 @@ static int compare_lebs(const struct ubi_device *ubi, } } - if (!vidh->copy_flag) { + if (!vh->copy_flag) { /* It is not a copy, so it is newer */ dbg_bld("first PEB %d is newer, copy_flag is unset", pnum); @@ -349,7 +347,7 @@ static int compare_lebs(const struct ubi_device *ubi, goto out_free_vidh; } - vid_hdr = vidh; + vid_hdr = vh; } /* Read the data of the copy and check the CRC */ @@ -379,7 +377,7 @@ static int compare_lebs(const struct ubi_device *ubi, } vfree(buf); - ubi_free_vid_hdr(ubi, vidh); + ubi_free_vid_hdr(ubi, vh); if (second_is_newer) dbg_bld("second PEB %d is newer, copy_flag is set", pnum); @@ -391,7 +389,7 @@ static int compare_lebs(const struct ubi_device *ubi, out_free_buf: vfree(buf); out_free_vidh: - ubi_free_vid_hdr(ubi, vidh); + ubi_free_vid_hdr(ubi, vh); ubi_assert(err < 0); return err; } @@ -413,7 +411,7 @@ out_free_vidh: * to be picked, while the older one has to be dropped. This function returns * zero in case of success and a negative error code in case of failure. */ -int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si, +int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum, int ec, const struct ubi_vid_hdr *vid_hdr, int bitflips) { @@ -667,16 +665,12 @@ void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv) * function returns zero in case of success and a negative error code in case * of failure. */ -int ubi_scan_erase_peb(const struct ubi_device *ubi, - const struct ubi_scan_info *si, int pnum, int ec) +int ubi_scan_erase_peb(struct ubi_device *ubi, const struct ubi_scan_info *si, + int pnum, int ec) { int err; struct ubi_ec_hdr *ec_hdr; - ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL); - if (!ec_hdr) - return -ENOMEM; - if ((long long)ec >= UBI_MAX_ERASECOUNTER) { /* * Erase counter overflow. Upgrade UBI and use 64-bit @@ -686,6 +680,10 @@ int ubi_scan_erase_peb(const struct ubi_device *ubi, return -EINVAL; } + ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL); + if (!ec_hdr) + return -ENOMEM; + ec_hdr->ec = cpu_to_be64(ec); err = ubi_io_sync_erase(ubi, pnum, 0); @@ -712,7 +710,7 @@ out_free: * This function returns scanning physical eraseblock information in case of * success and an error code in case of failure. */ -struct ubi_scan_leb *ubi_scan_get_free_peb(const struct ubi_device *ubi, +struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi, struct ubi_scan_info *si) { int err = 0, i; @@ -948,7 +946,7 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi) if (!ech) goto out_si; - vidh = ubi_zalloc_vid_hdr(ubi); + vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL); if (!vidh) goto out_ech; @@ -1110,8 +1108,7 @@ void ubi_scan_destroy_si(struct ubi_scan_info *si) * This function returns zero if the scanning information is all right, %1 if * not and a negative error code if an error occurred. */ -static int paranoid_check_si(const struct ubi_device *ubi, - struct ubi_scan_info *si) +static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si) { int pnum, err, vols_found = 0; struct rb_node *rb1, *rb2; @@ -1314,11 +1311,10 @@ static int paranoid_check_si(const struct ubi_device *ubi, * Make sure that all the physical eraseblocks are in one of the lists * or trees. */ - buf = kmalloc(ubi->peb_count, GFP_KERNEL); + buf = kzalloc(ubi->peb_count, GFP_KERNEL); if (!buf) return -ENOMEM; - memset(buf, 1, ubi->peb_count); for (pnum = 0; pnum < ubi->peb_count; pnum++) { err = ubi_io_is_bad(ubi, pnum); if (err < 0) { @@ -1326,28 +1322,28 @@ static int paranoid_check_si(const struct ubi_device *ubi, return err; } else if (err) - buf[pnum] = 0; + buf[pnum] = 1; } ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) - buf[seb->pnum] = 0; + buf[seb->pnum] = 1; list_for_each_entry(seb, &si->free, u.list) - buf[seb->pnum] = 0; + buf[seb->pnum] = 1; list_for_each_entry(seb, &si->corr, u.list) - buf[seb->pnum] = 0; + buf[seb->pnum] = 1; list_for_each_entry(seb, &si->erase, u.list) - buf[seb->pnum] = 0; + buf[seb->pnum] = 1; list_for_each_entry(seb, &si->alien, u.list) - buf[seb->pnum] = 0; + buf[seb->pnum] = 1; err = 0; for (pnum = 0; pnum < ubi->peb_count; pnum++) - if (buf[pnum]) { + if (!buf[pnum]) { ubi_err("PEB %d is not referred", pnum); err = 1; } diff --git a/drivers/mtd/ubi/scan.h b/drivers/mtd/ubi/scan.h index 140e82e26534..46d444af471a 100644 --- a/drivers/mtd/ubi/scan.h +++ b/drivers/mtd/ubi/scan.h @@ -147,7 +147,7 @@ static inline void ubi_scan_move_to_list(struct ubi_scan_volume *sv, list_add_tail(&seb->u.list, list); } -int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si, +int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum, int ec, const struct ubi_vid_hdr *vid_hdr, int bitflips); struct ubi_scan_volume *ubi_scan_find_sv(const struct ubi_scan_info *si, @@ -155,10 +155,10 @@ struct ubi_scan_volume *ubi_scan_find_sv(const struct ubi_scan_info *si, struct ubi_scan_leb *ubi_scan_find_seb(const struct ubi_scan_volume *sv, int lnum); void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv); -struct ubi_scan_leb *ubi_scan_get_free_peb(const struct ubi_device *ubi, +struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi, struct ubi_scan_info *si); -int ubi_scan_erase_peb(const struct ubi_device *ubi, - const struct ubi_scan_info *si, int pnum, int ec); +int ubi_scan_erase_peb(struct ubi_device *ubi, const struct ubi_scan_info *si, + int pnum, int ec); struct ubi_scan_info *ubi_scan(struct ubi_device *ubi); void ubi_scan_destroy_si(struct ubi_scan_info *si); diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index 5959f91be240..5e941a633030 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -221,14 +221,15 @@ struct ubi_wl_entry; * @vtbl_slots: how many slots are available in the volume table * @vtbl_size: size of the volume table in bytes * @vtbl: in-RAM volume table copy + * @vtbl_mutex: protects on-flash volume table * * @max_ec: current highest erase counter value * @mean_ec: current mean erase counter value * - * global_sqnum: global sequence number + * @global_sqnum: global sequence number * @ltree_lock: protects the lock tree and @global_sqnum * @ltree: the lock tree - * @vtbl_mutex: protects on-flash volume table + * @alc_mutex: serializes "atomic LEB change" operations * * @used: RB-tree of used physical eraseblocks * @free: RB-tree of free physical eraseblocks @@ -274,6 +275,12 @@ struct ubi_wl_entry; * @bad_allowed: whether the MTD device admits of bad physical eraseblocks or * not * @mtd: MTD device descriptor + * + * @peb_buf1: a buffer of PEB size used for different purposes + * @peb_buf2: another buffer of PEB size used for different purposes + * @buf_mutex: proptects @peb_buf1 and @peb_buf2 + * @dbg_peb_buf: buffer of PEB size used for debugging + * @dbg_buf_mutex: proptects @dbg_peb_buf */ struct ubi_device { struct cdev cdev; @@ -302,6 +309,7 @@ struct ubi_device { unsigned long long global_sqnum; spinlock_t ltree_lock; struct rb_root ltree; + struct mutex alc_mutex; /* Wear-leveling unit's stuff */ struct rb_root used; @@ -343,6 +351,14 @@ struct ubi_device { int vid_hdr_shift; int bad_allowed; struct mtd_info *mtd; + + void *peb_buf1; + void *peb_buf2; + struct mutex buf_mutex; +#ifdef CONFIG_MTD_UBI_DEBUG + void *dbg_peb_buf; + struct mutex dbg_buf_mutex; +#endif }; extern struct file_operations ubi_cdev_operations; @@ -409,18 +425,18 @@ void ubi_wl_close(struct ubi_device *ubi); /* io.c */ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset, int len); -int ubi_io_write(const struct ubi_device *ubi, const void *buf, int pnum, - int offset, int len); -int ubi_io_sync_erase(const struct ubi_device *ubi, int pnum, int torture); +int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset, + int len); +int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture); int ubi_io_is_bad(const struct ubi_device *ubi, int pnum); int ubi_io_mark_bad(const struct ubi_device *ubi, int pnum); -int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum, +int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, struct ubi_ec_hdr *ec_hdr, int verbose); -int ubi_io_write_ec_hdr(const struct ubi_device *ubi, int pnum, +int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum, struct ubi_ec_hdr *ec_hdr); -int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum, +int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, struct ubi_vid_hdr *vid_hdr, int verbose); -int ubi_io_write_vid_hdr(const struct ubi_device *ubi, int pnum, +int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum, struct ubi_vid_hdr *vid_hdr); /* @@ -439,16 +455,18 @@ int ubi_io_write_vid_hdr(const struct ubi_device *ubi, int pnum, /** * ubi_zalloc_vid_hdr - allocate a volume identifier header object. * @ubi: UBI device description object + * @gfp_flags: GFP flags to allocate with * * This function returns a pointer to the newly allocated and zero-filled * volume identifier header object in case of success and %NULL in case of * failure. */ -static inline struct ubi_vid_hdr *ubi_zalloc_vid_hdr(const struct ubi_device *ubi) +static inline struct ubi_vid_hdr * +ubi_zalloc_vid_hdr(const struct ubi_device *ubi, gfp_t gfp_flags) { void *vid_hdr; - vid_hdr = kzalloc(ubi->vid_hdr_alsize, GFP_KERNEL); + vid_hdr = kzalloc(ubi->vid_hdr_alsize, gfp_flags); if (!vid_hdr) return NULL; @@ -492,7 +510,7 @@ static inline int ubi_io_read_data(const struct ubi_device *ubi, void *buf, * the beginning of the logical eraseblock, not to the beginning of the * physical eraseblock. */ -static inline int ubi_io_write_data(const struct ubi_device *ubi, const void *buf, +static inline int ubi_io_write_data(struct ubi_device *ubi, const void *buf, int pnum, int offset, int len) { ubi_assert(offset >= 0); diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index ea0d5c825ab4..88629a320c2b 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -37,21 +37,21 @@ static ssize_t vol_attribute_show(struct device *dev, struct device_attribute *attr, char *buf); /* Device attributes corresponding to files in '/<sysfs>/class/ubi/ubiX_Y' */ -static struct device_attribute vol_reserved_ebs = +static struct device_attribute attr_vol_reserved_ebs = __ATTR(reserved_ebs, S_IRUGO, vol_attribute_show, NULL); -static struct device_attribute vol_type = +static struct device_attribute attr_vol_type = __ATTR(type, S_IRUGO, vol_attribute_show, NULL); -static struct device_attribute vol_name = +static struct device_attribute attr_vol_name = __ATTR(name, S_IRUGO, vol_attribute_show, NULL); -static struct device_attribute vol_corrupted = +static struct device_attribute attr_vol_corrupted = __ATTR(corrupted, S_IRUGO, vol_attribute_show, NULL); -static struct device_attribute vol_alignment = +static struct device_attribute attr_vol_alignment = __ATTR(alignment, S_IRUGO, vol_attribute_show, NULL); -static struct device_attribute vol_usable_eb_size = +static struct device_attribute attr_vol_usable_eb_size = __ATTR(usable_eb_size, S_IRUGO, vol_attribute_show, NULL); -static struct device_attribute vol_data_bytes = +static struct device_attribute attr_vol_data_bytes = __ATTR(data_bytes, S_IRUGO, vol_attribute_show, NULL); -static struct device_attribute vol_upd_marker = +static struct device_attribute attr_vol_upd_marker = __ATTR(upd_marker, S_IRUGO, vol_attribute_show, NULL); /* @@ -78,23 +78,27 @@ static ssize_t vol_attribute_show(struct device *dev, spin_unlock(&vol->ubi->volumes_lock); return -ENODEV; } - if (attr == &vol_reserved_ebs) + if (attr == &attr_vol_reserved_ebs) ret = sprintf(buf, "%d\n", vol->reserved_pebs); - else if (attr == &vol_type) { + else if (attr == &attr_vol_type) { const char *tp; - tp = vol->vol_type == UBI_DYNAMIC_VOLUME ? "dynamic" : "static"; + + if (vol->vol_type == UBI_DYNAMIC_VOLUME) + tp = "dynamic"; + else + tp = "static"; ret = sprintf(buf, "%s\n", tp); - } else if (attr == &vol_name) + } else if (attr == &attr_vol_name) ret = sprintf(buf, "%s\n", vol->name); - else if (attr == &vol_corrupted) + else if (attr == &attr_vol_corrupted) ret = sprintf(buf, "%d\n", vol->corrupted); - else if (attr == &vol_alignment) + else if (attr == &attr_vol_alignment) ret = sprintf(buf, "%d\n", vol->alignment); - else if (attr == &vol_usable_eb_size) { + else if (attr == &attr_vol_usable_eb_size) { ret = sprintf(buf, "%d\n", vol->usable_leb_size); - } else if (attr == &vol_data_bytes) + } else if (attr == &attr_vol_data_bytes) ret = sprintf(buf, "%lld\n", vol->used_bytes); - else if (attr == &vol_upd_marker) + else if (attr == &attr_vol_upd_marker) ret = sprintf(buf, "%d\n", vol->upd_marker); else BUG(); @@ -126,28 +130,28 @@ static int volume_sysfs_init(struct ubi_device *ubi, struct ubi_volume *vol) { int err; - err = device_create_file(&vol->dev, &vol_reserved_ebs); + err = device_create_file(&vol->dev, &attr_vol_reserved_ebs); if (err) return err; - err = device_create_file(&vol->dev, &vol_type); + err = device_create_file(&vol->dev, &attr_vol_type); if (err) return err; - err = device_create_file(&vol->dev, &vol_name); + err = device_create_file(&vol->dev, &attr_vol_name); if (err) return err; - err = device_create_file(&vol->dev, &vol_corrupted); + err = device_create_file(&vol->dev, &attr_vol_corrupted); if (err) return err; - err = device_create_file(&vol->dev, &vol_alignment); + err = device_create_file(&vol->dev, &attr_vol_alignment); if (err) return err; - err = device_create_file(&vol->dev, &vol_usable_eb_size); + err = device_create_file(&vol->dev, &attr_vol_usable_eb_size); if (err) return err; - err = device_create_file(&vol->dev, &vol_data_bytes); + err = device_create_file(&vol->dev, &attr_vol_data_bytes); if (err) return err; - err = device_create_file(&vol->dev, &vol_upd_marker); + err = device_create_file(&vol->dev, &attr_vol_upd_marker); if (err) return err; return 0; @@ -159,14 +163,14 @@ static int volume_sysfs_init(struct ubi_device *ubi, struct ubi_volume *vol) */ static void volume_sysfs_close(struct ubi_volume *vol) { - device_remove_file(&vol->dev, &vol_upd_marker); - device_remove_file(&vol->dev, &vol_data_bytes); - device_remove_file(&vol->dev, &vol_usable_eb_size); - device_remove_file(&vol->dev, &vol_alignment); - device_remove_file(&vol->dev, &vol_corrupted); - device_remove_file(&vol->dev, &vol_name); - device_remove_file(&vol->dev, &vol_type); - device_remove_file(&vol->dev, &vol_reserved_ebs); + device_remove_file(&vol->dev, &attr_vol_upd_marker); + device_remove_file(&vol->dev, &attr_vol_data_bytes); + device_remove_file(&vol->dev, &attr_vol_usable_eb_size); + device_remove_file(&vol->dev, &attr_vol_alignment); + device_remove_file(&vol->dev, &attr_vol_corrupted); + device_remove_file(&vol->dev, &attr_vol_name); + device_remove_file(&vol->dev, &attr_vol_type); + device_remove_file(&vol->dev, &attr_vol_reserved_ebs); device_unregister(&vol->dev); } diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index bc5df50813d6..25b3bd61c7ec 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c @@ -254,7 +254,7 @@ bad: * This function returns zero in case of success and a negative error code in * case of failure. */ -static int create_vtbl(const struct ubi_device *ubi, struct ubi_scan_info *si, +static int create_vtbl(struct ubi_device *ubi, struct ubi_scan_info *si, int copy, void *vtbl) { int err, tries = 0; @@ -264,7 +264,7 @@ static int create_vtbl(const struct ubi_device *ubi, struct ubi_scan_info *si, ubi_msg("create volume table (copy #%d)", copy + 1); - vid_hdr = ubi_zalloc_vid_hdr(ubi); + vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL); if (!vid_hdr) return -ENOMEM; @@ -339,7 +339,7 @@ out_free: * not corrupted, and recovering from corruptions if needed. Returns volume * table in case of success and a negative error code in case of failure. */ -static struct ubi_vtbl_record *process_lvol(const struct ubi_device *ubi, +static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi, struct ubi_scan_info *si, struct ubi_scan_volume *sv) { @@ -453,7 +453,7 @@ out_free: * This function returns volume table contents in case of success and a * negative error code in case of failure. */ -static struct ubi_vtbl_record *create_empty_lvol(const struct ubi_device *ubi, +static struct ubi_vtbl_record *create_empty_lvol(struct ubi_device *ubi, struct ubi_scan_info *si) { int i; diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index a5a9b8d87302..a4f1bf33164a 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -208,7 +208,7 @@ struct ubi_work { }; #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID -static int paranoid_check_ec(const struct ubi_device *ubi, int pnum, int ec); +static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec); static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e, struct rb_root *root); #else @@ -220,17 +220,6 @@ static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e, static struct kmem_cache *wl_entries_slab; /** - * tree_empty - a helper function to check if an RB-tree is empty. - * @root: the root of the tree - * - * This function returns non-zero if the RB-tree is empty and zero if not. - */ -static inline int tree_empty(struct rb_root *root) -{ - return root->rb_node == NULL; -} - -/** * wl_tree_add - add a wear-leveling entry to a WL RB-tree. * @e: the wear-leveling entry to add * @root: the root of the tree @@ -266,45 +255,6 @@ static void wl_tree_add(struct ubi_wl_entry *e, struct rb_root *root) rb_insert_color(&e->rb, root); } - -/* - * Helper functions to add and delete wear-leveling entries from different - * trees. - */ - -static void free_tree_add(struct ubi_device *ubi, struct ubi_wl_entry *e) -{ - wl_tree_add(e, &ubi->free); -} -static inline void used_tree_add(struct ubi_device *ubi, - struct ubi_wl_entry *e) -{ - wl_tree_add(e, &ubi->used); -} -static inline void scrub_tree_add(struct ubi_device *ubi, - struct ubi_wl_entry *e) -{ - wl_tree_add(e, &ubi->scrub); -} -static inline void free_tree_del(struct ubi_device *ubi, - struct ubi_wl_entry *e) -{ - paranoid_check_in_wl_tree(e, &ubi->free); - rb_erase(&e->rb, &ubi->free); -} -static inline void used_tree_del(struct ubi_device *ubi, - struct ubi_wl_entry *e) -{ - paranoid_check_in_wl_tree(e, &ubi->used); - rb_erase(&e->rb, &ubi->used); -} -static inline void scrub_tree_del(struct ubi_device *ubi, - struct ubi_wl_entry *e) -{ - paranoid_check_in_wl_tree(e, &ubi->scrub); - rb_erase(&e->rb, &ubi->scrub); -} - /** * do_work - do one pending work. * @ubi: UBI device description object @@ -358,7 +308,7 @@ static int produce_free_peb(struct ubi_device *ubi) int err; spin_lock(&ubi->wl_lock); - while (tree_empty(&ubi->free)) { + while (!ubi->free.rb_node) { spin_unlock(&ubi->wl_lock); dbg_wl("do one work synchronously"); @@ -508,13 +458,13 @@ int ubi_wl_get_peb(struct ubi_device *ubi, int dtype) ubi_assert(dtype == UBI_LONGTERM || dtype == UBI_SHORTTERM || dtype == UBI_UNKNOWN); - pe = kmalloc(sizeof(struct ubi_wl_prot_entry), GFP_KERNEL); + pe = kmalloc(sizeof(struct ubi_wl_prot_entry), GFP_NOFS); if (!pe) return -ENOMEM; retry: spin_lock(&ubi->wl_lock); - if (tree_empty(&ubi->free)) { + if (!ubi->free.rb_node) { if (ubi->works_count == 0) { ubi_assert(list_empty(&ubi->works)); ubi_err("no free eraseblocks"); @@ -585,7 +535,8 @@ retry: * Move the physical eraseblock to the protection trees where it will * be protected from being moved for some time. */ - free_tree_del(ubi, e); + paranoid_check_in_wl_tree(e, &ubi->free); + rb_erase(&e->rb, &ubi->free); prot_tree_add(ubi, e, pe, protect); dbg_wl("PEB %d EC %d, protection %d", e->pnum, e->ec, protect); @@ -645,7 +596,7 @@ static int sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, int tortur if (err > 0) return -EINVAL; - ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL); + ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS); if (!ec_hdr) return -ENOMEM; @@ -704,7 +655,7 @@ static void check_protection_over(struct ubi_device *ubi) */ while (1) { spin_lock(&ubi->wl_lock); - if (tree_empty(&ubi->prot.aec)) { + if (!ubi->prot.aec.rb_node) { spin_unlock(&ubi->wl_lock); break; } @@ -721,7 +672,7 @@ static void check_protection_over(struct ubi_device *ubi) pe->e->pnum, ubi->abs_ec, pe->abs_ec); rb_erase(&pe->rb_aec, &ubi->prot.aec); rb_erase(&pe->rb_pnum, &ubi->prot.pnum); - used_tree_add(ubi, pe->e); + wl_tree_add(pe->e, &ubi->used); spin_unlock(&ubi->wl_lock); kfree(pe); @@ -768,7 +719,7 @@ static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, dbg_wl("schedule erasure of PEB %d, EC %d, torture %d", e->pnum, e->ec, torture); - wl_wrk = kmalloc(sizeof(struct ubi_work), GFP_KERNEL); + wl_wrk = kmalloc(sizeof(struct ubi_work), GFP_NOFS); if (!wl_wrk) return -ENOMEM; @@ -802,7 +753,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, if (cancel) return 0; - vid_hdr = ubi_zalloc_vid_hdr(ubi); + vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); if (!vid_hdr) return -ENOMEM; @@ -812,8 +763,8 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, * Only one WL worker at a time is supported at this implementation, so * make sure a PEB is not being moved already. */ - if (ubi->move_to || tree_empty(&ubi->free) || - (tree_empty(&ubi->used) && tree_empty(&ubi->scrub))) { + if (ubi->move_to || !ubi->free.rb_node || + (!ubi->used.rb_node && !ubi->scrub.rb_node)) { /* * Only one WL worker at a time is supported at this * implementation, so if a LEB is already being moved, cancel. @@ -828,14 +779,14 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, * triggered again. */ dbg_wl("cancel WL, a list is empty: free %d, used %d", - tree_empty(&ubi->free), tree_empty(&ubi->used)); + !ubi->free.rb_node, !ubi->used.rb_node); ubi->wl_scheduled = 0; spin_unlock(&ubi->wl_lock); ubi_free_vid_hdr(ubi, vid_hdr); return 0; } - if (tree_empty(&ubi->scrub)) { + if (!ubi->scrub.rb_node) { /* * Now pick the least worn-out used physical eraseblock and a * highly worn-out free physical eraseblock. If the erase @@ -852,17 +803,20 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, ubi_free_vid_hdr(ubi, vid_hdr); return 0; } - used_tree_del(ubi, e1); + paranoid_check_in_wl_tree(e1, &ubi->used); + rb_erase(&e1->rb, &ubi->used); dbg_wl("move PEB %d EC %d to PEB %d EC %d", e1->pnum, e1->ec, e2->pnum, e2->ec); } else { e1 = rb_entry(rb_first(&ubi->scrub), struct ubi_wl_entry, rb); e2 = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF); - scrub_tree_del(ubi, e1); + paranoid_check_in_wl_tree(e1, &ubi->scrub); + rb_erase(&e1->rb, &ubi->scrub); dbg_wl("scrub PEB %d to PEB %d", e1->pnum, e2->pnum); } - free_tree_del(ubi, e2); + paranoid_check_in_wl_tree(e2, &ubi->free); + rb_erase(&e2->rb, &ubi->free); ubi_assert(!ubi->move_from && !ubi->move_to); ubi_assert(!ubi->move_to_put && !ubi->move_from_put); ubi->move_from = e1; @@ -908,7 +862,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, ubi_free_vid_hdr(ubi, vid_hdr); spin_lock(&ubi->wl_lock); if (!ubi->move_to_put) - used_tree_add(ubi, e2); + wl_tree_add(e2, &ubi->used); else put = 1; ubi->move_from = ubi->move_to = NULL; @@ -953,7 +907,7 @@ error: if (ubi->move_from_put) put = 1; else - used_tree_add(ubi, e1); + wl_tree_add(e1, &ubi->used); ubi->move_from = ubi->move_to = NULL; ubi->move_from_put = ubi->move_to_put = 0; spin_unlock(&ubi->wl_lock); @@ -1005,8 +959,8 @@ static int ensure_wear_leveling(struct ubi_device *ubi) * If the ubi->scrub tree is not empty, scrubbing is needed, and the * the WL worker has to be scheduled anyway. */ - if (tree_empty(&ubi->scrub)) { - if (tree_empty(&ubi->used) || tree_empty(&ubi->free)) + if (!ubi->scrub.rb_node) { + if (!ubi->used.rb_node || !ubi->free.rb_node) /* No physical eraseblocks - no deal */ goto out_unlock; @@ -1028,7 +982,7 @@ static int ensure_wear_leveling(struct ubi_device *ubi) ubi->wl_scheduled = 1; spin_unlock(&ubi->wl_lock); - wrk = kmalloc(sizeof(struct ubi_work), GFP_KERNEL); + wrk = kmalloc(sizeof(struct ubi_work), GFP_NOFS); if (!wrk) { err = -ENOMEM; goto out_cancel; @@ -1079,7 +1033,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, spin_lock(&ubi->wl_lock); ubi->abs_ec += 1; - free_tree_add(ubi, e); + wl_tree_add(e, &ubi->free); spin_unlock(&ubi->wl_lock); /* @@ -1093,6 +1047,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, return err; } + ubi_err("failed to erase PEB %d, error %d", pnum, err); kfree(wl_wrk); kmem_cache_free(wl_entries_slab, e); @@ -1211,11 +1166,13 @@ int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture) spin_unlock(&ubi->wl_lock); return 0; } else { - if (in_wl_tree(e, &ubi->used)) - used_tree_del(ubi, e); - else if (in_wl_tree(e, &ubi->scrub)) - scrub_tree_del(ubi, e); - else + if (in_wl_tree(e, &ubi->used)) { + paranoid_check_in_wl_tree(e, &ubi->used); + rb_erase(&e->rb, &ubi->used); + } else if (in_wl_tree(e, &ubi->scrub)) { + paranoid_check_in_wl_tree(e, &ubi->scrub); + rb_erase(&e->rb, &ubi->scrub); + } else prot_tree_del(ubi, e->pnum); } spin_unlock(&ubi->wl_lock); @@ -1223,7 +1180,7 @@ int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture) err = schedule_erase(ubi, e, torture); if (err) { spin_lock(&ubi->wl_lock); - used_tree_add(ubi, e); + wl_tree_add(e, &ubi->used); spin_unlock(&ubi->wl_lock); } @@ -1267,12 +1224,13 @@ retry: goto retry; } - if (in_wl_tree(e, &ubi->used)) - used_tree_del(ubi, e); - else + if (in_wl_tree(e, &ubi->used)) { + paranoid_check_in_wl_tree(e, &ubi->used); + rb_erase(&e->rb, &ubi->used); + } else prot_tree_del(ubi, pnum); - scrub_tree_add(ubi, e); + wl_tree_add(e, &ubi->scrub); spin_unlock(&ubi->wl_lock); /* @@ -1488,7 +1446,7 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si) e->pnum = seb->pnum; e->ec = seb->ec; ubi_assert(e->ec >= 0); - free_tree_add(ubi, e); + wl_tree_add(e, &ubi->free); ubi->lookuptbl[e->pnum] = e; } @@ -1522,16 +1480,16 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si) if (!seb->scrub) { dbg_wl("add PEB %d EC %d to the used tree", e->pnum, e->ec); - used_tree_add(ubi, e); + wl_tree_add(e, &ubi->used); } else { dbg_wl("add PEB %d EC %d to the scrub tree", e->pnum, e->ec); - scrub_tree_add(ubi, e); + wl_tree_add(e, &ubi->scrub); } } } - if (WL_RESERVED_PEBS > ubi->avail_pebs) { + if (ubi->avail_pebs < WL_RESERVED_PEBS) { ubi_err("no enough physical eraseblocks (%d, need %d)", ubi->avail_pebs, WL_RESERVED_PEBS); goto out_free; @@ -1624,13 +1582,13 @@ void ubi_wl_close(struct ubi_device *ubi) * is equivalent to @ec, %1 if not, and a negative error code if an error * occurred. */ -static int paranoid_check_ec(const struct ubi_device *ubi, int pnum, int ec) +static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec) { int err; long long read_ec; struct ubi_ec_hdr *ec_hdr; - ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL); + ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS); if (!ec_hdr) return -ENOMEM; diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 9c635a237a9d..8f99a0626616 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1780,6 +1780,15 @@ config SC92031 To compile this driver as a module, choose M here: the module will be called sc92031. This is recommended. +config CPMAC + tristate "TI AR7 CPMAC Ethernet support (EXPERIMENTAL)" + depends on NET_ETHERNET && EXPERIMENTAL && AR7 + select PHYLIB + select FIXED_PHY + select FIXED_MII_100_FDX + help + TI AR7 CPMAC Ethernet support + config NET_POCKET bool "Pocket and portable adapters" depends on PARPORT diff --git a/drivers/net/Makefile b/drivers/net/Makefile index d2e0f35da42e..22f78cbd126b 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -159,6 +159,7 @@ obj-$(CONFIG_8139CP) += 8139cp.o obj-$(CONFIG_8139TOO) += 8139too.o obj-$(CONFIG_ZNET) += znet.o obj-$(CONFIG_LAN_SAA9730) += saa9730.o +obj-$(CONFIG_CPMAC) += cpmac.o obj-$(CONFIG_DEPCA) += depca.o obj-$(CONFIG_EWRK3) += ewrk3.o obj-$(CONFIG_ATP) += atp.o diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index ebf1a3a88e15..b74dbeef8050 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -1023,7 +1023,7 @@ static int lance_rx( struct net_device *dev ) DECLARE_MAC_BUF(mac); DECLARE_MAC_BUF(mac2); - printk(KERN_DEBUG "%s: RX pkt type 0x%04x from %s to %s ", + printk(KERN_DEBUG "%s: RX pkt type 0x%04x from %s to %s " "data %02x %02x %02x %02x %02x %02x %02x %02x " "len %d\n", dev->name, ((u_short *)data)[6], diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index b46c5d8a77bd..185f98e3964c 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -54,13 +54,16 @@ #include <linux/delay.h> #include <linux/crc32.h> #include <linux/phy.h> + +#include <asm/cpu.h> #include <asm/mipsregs.h> #include <asm/irq.h> #include <asm/io.h> #include <asm/processor.h> -#include <asm/mach-au1x00/au1000.h> -#include <asm/cpu.h> +#include <au1000.h> +#include <prom.h> + #include "au1000_eth.h" #ifdef AU1000_ETH_DEBUG @@ -96,11 +99,6 @@ static void mdio_write(struct net_device *, int, int, u16); static void au1000_adjust_link(struct net_device *); static void enable_mac(struct net_device *, int); -// externs -extern int get_ethernet_addr(char *ethernet_addr); -extern void str2eaddr(unsigned char *ea, unsigned char *str); -extern char * prom_getcmdline(void); - /* * Theory of operation * @@ -619,7 +617,6 @@ static struct net_device * au1000_probe(int port_num) struct au1000_private *aup = NULL; struct net_device *dev = NULL; db_dest_t *pDB, *pDBfree; - char *pmac, *argptr; char ethaddr[6]; int irq, i, err; u32 base, macen; @@ -677,21 +674,12 @@ static struct net_device * au1000_probe(int port_num) au_macs[port_num] = aup; if (port_num == 0) { - /* Check the environment variables first */ - if (get_ethernet_addr(ethaddr) == 0) + if (prom_get_ethernet_addr(ethaddr) == 0) memcpy(au1000_mac_addr, ethaddr, sizeof(au1000_mac_addr)); else { - /* Check command line */ - argptr = prom_getcmdline(); - if ((pmac = strstr(argptr, "ethaddr=")) == NULL) - printk(KERN_INFO "%s: No MAC address found\n", - dev->name); + printk(KERN_INFO "%s: No MAC address found\n", + dev->name); /* Use the hard coded MAC addresses */ - else { - str2eaddr(ethaddr, pmac + strlen("ethaddr=")); - memcpy(au1000_mac_addr, ethaddr, - sizeof(au1000_mac_addr)); - } } setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR); diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index d68accea380b..78ed633ceb82 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -2652,10 +2652,10 @@ static int bnx2_poll_work(struct bnx2 *bp, int work_done, int budget) REG_RD(bp, BNX2_HC_COMMAND); } - if (bp->status_blk->status_tx_quick_consumer_index0 != bp->hw_tx_cons) + if (sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons) bnx2_tx_int(bp); - if (bp->status_blk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) + if (sblk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) work_done += bnx2_rx_int(bp, budget - work_done); return work_done; @@ -2665,6 +2665,7 @@ static int bnx2_poll(struct napi_struct *napi, int budget) { struct bnx2 *bp = container_of(napi, struct bnx2, napi); int work_done = 0; + struct status_block *sblk = bp->status_blk; while (1) { work_done = bnx2_poll_work(bp, work_done, budget); @@ -2672,16 +2673,19 @@ static int bnx2_poll(struct napi_struct *napi, int budget) if (unlikely(work_done >= budget)) break; + /* bp->last_status_idx is used below to tell the hw how + * much work has been processed, so we must read it before + * checking for more work. + */ + bp->last_status_idx = sblk->status_idx; + rmb(); if (likely(!bnx2_has_work(bp))) { - bp->last_status_idx = bp->status_blk->status_idx; - rmb(); - netif_rx_complete(bp->dev, napi); if (likely(bp->flags & USING_MSI_FLAG)) { REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | bp->last_status_idx); - return 0; + break; } REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 64bfec32e2a6..db80f243dd37 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -98,6 +98,7 @@ static char *xmit_hash_policy = NULL; static int arp_interval = BOND_LINK_ARP_INTERV; static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, }; static char *arp_validate = NULL; +static int fail_over_mac = 0; struct bond_params bonding_defaults; module_param(max_bonds, int, 0); @@ -131,6 +132,8 @@ module_param_array(arp_ip_target, charp, NULL, 0); MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form"); module_param(arp_validate, charp, 0); MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes: none (default), active, backup or all"); +module_param(fail_over_mac, int, 0); +MODULE_PARM_DESC(fail_over_mac, "For active-backup, do not set all slaves to the same MAC. 0 of off (default), 1 for on."); /*----------------------------- Global variables ----------------------------*/ @@ -1096,7 +1099,21 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) if (new_active) { bond_set_slave_active_flags(new_active); } - bond_send_gratuitous_arp(bond); + + /* when bonding does not set the slave MAC address, the bond MAC + * address is the one of the active slave. + */ + if (new_active && bond->params.fail_over_mac) + memcpy(bond->dev->dev_addr, new_active->dev->dev_addr, + new_active->dev->addr_len); + if (bond->curr_active_slave && + test_bit(__LINK_STATE_LINKWATCH_PENDING, + &bond->curr_active_slave->dev->state)) { + dprintk("delaying gratuitous arp on %s\n", + bond->curr_active_slave->dev->name); + bond->send_grat_arp = 1; + } else + bond_send_gratuitous_arp(bond); } } @@ -1217,7 +1234,8 @@ static int bond_compute_features(struct bonding *bond) struct slave *slave; struct net_device *bond_dev = bond->dev; unsigned long features = bond_dev->features; - unsigned short max_hard_header_len = ETH_HLEN; + unsigned short max_hard_header_len = max((u16)ETH_HLEN, + bond_dev->hard_header_len); int i; features &= ~(NETIF_F_ALL_CSUM | BOND_VLAN_FEATURES); @@ -1238,6 +1256,23 @@ static int bond_compute_features(struct bonding *bond) return 0; } + +static void bond_setup_by_slave(struct net_device *bond_dev, + struct net_device *slave_dev) +{ + struct bonding *bond = bond_dev->priv; + + bond_dev->neigh_setup = slave_dev->neigh_setup; + + bond_dev->type = slave_dev->type; + bond_dev->hard_header_len = slave_dev->hard_header_len; + bond_dev->addr_len = slave_dev->addr_len; + + memcpy(bond_dev->broadcast, slave_dev->broadcast, + slave_dev->addr_len); + bond->setup_by_slave = 1; +} + /* enslave device <slave> to bond device <master> */ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) { @@ -1258,8 +1293,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) /* bond must be initialized by bond_open() before enslaving */ if (!(bond_dev->flags & IFF_UP)) { - dprintk("Error, master_dev is not up\n"); - return -EPERM; + printk(KERN_WARNING DRV_NAME + " %s: master_dev is not up in bond_enslave\n", + bond_dev->name); } /* already enslaved */ @@ -1312,14 +1348,42 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) goto err_undo_flags; } + /* set bonding device ether type by slave - bonding netdevices are + * created with ether_setup, so when the slave type is not ARPHRD_ETHER + * there is a need to override some of the type dependent attribs/funcs. + * + * bond ether type mutual exclusion - don't allow slaves of dissimilar + * ether type (eg ARPHRD_ETHER and ARPHRD_INFINIBAND) share the same bond + */ + if (bond->slave_cnt == 0) { + if (slave_dev->type != ARPHRD_ETHER) + bond_setup_by_slave(bond_dev, slave_dev); + } else if (bond_dev->type != slave_dev->type) { + printk(KERN_ERR DRV_NAME ": %s ether type (%d) is different " + "from other slaves (%d), can not enslave it.\n", + slave_dev->name, + slave_dev->type, bond_dev->type); + res = -EINVAL; + goto err_undo_flags; + } + if (slave_dev->set_mac_address == NULL) { - printk(KERN_ERR DRV_NAME - ": %s: Error: The slave device you specified does " - "not support setting the MAC address. " - "Your kernel likely does not support slave " - "devices.\n", bond_dev->name); - res = -EOPNOTSUPP; - goto err_undo_flags; + if (bond->slave_cnt == 0) { + printk(KERN_WARNING DRV_NAME + ": %s: Warning: The first slave device " + "specified does not support setting the MAC " + "address. Enabling the fail_over_mac option.", + bond_dev->name); + bond->params.fail_over_mac = 1; + } else if (!bond->params.fail_over_mac) { + printk(KERN_ERR DRV_NAME + ": %s: Error: The slave device specified " + "does not support setting the MAC address, " + "but fail_over_mac is not enabled.\n" + , bond_dev->name); + res = -EOPNOTSUPP; + goto err_undo_flags; + } } new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL); @@ -1340,16 +1404,18 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) */ memcpy(new_slave->perm_hwaddr, slave_dev->dev_addr, ETH_ALEN); - /* - * Set slave to master's mac address. The application already - * set the master's mac address to that of the first slave - */ - memcpy(addr.sa_data, bond_dev->dev_addr, bond_dev->addr_len); - addr.sa_family = slave_dev->type; - res = dev_set_mac_address(slave_dev, &addr); - if (res) { - dprintk("Error %d calling set_mac_address\n", res); - goto err_free; + if (!bond->params.fail_over_mac) { + /* + * Set slave to master's mac address. The application already + * set the master's mac address to that of the first slave + */ + memcpy(addr.sa_data, bond_dev->dev_addr, bond_dev->addr_len); + addr.sa_family = slave_dev->type; + res = dev_set_mac_address(slave_dev, &addr); + if (res) { + dprintk("Error %d calling set_mac_address\n", res); + goto err_free; + } } res = netdev_set_master(slave_dev, bond_dev); @@ -1574,9 +1640,11 @@ err_close: dev_close(slave_dev); err_restore_mac: - memcpy(addr.sa_data, new_slave->perm_hwaddr, ETH_ALEN); - addr.sa_family = slave_dev->type; - dev_set_mac_address(slave_dev, &addr); + if (!bond->params.fail_over_mac) { + memcpy(addr.sa_data, new_slave->perm_hwaddr, ETH_ALEN); + addr.sa_family = slave_dev->type; + dev_set_mac_address(slave_dev, &addr); + } err_free: kfree(new_slave); @@ -1749,10 +1817,12 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) /* close slave before restoring its mac address */ dev_close(slave_dev); - /* restore original ("permanent") mac address */ - memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN); - addr.sa_family = slave_dev->type; - dev_set_mac_address(slave_dev, &addr); + if (!bond->params.fail_over_mac) { + /* restore original ("permanent") mac address */ + memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN); + addr.sa_family = slave_dev->type; + dev_set_mac_address(slave_dev, &addr); + } slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB | IFF_SLAVE_INACTIVE | IFF_BONDING | @@ -1764,6 +1834,35 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) } /* +* Destroy a bonding device. +* Must be under rtnl_lock when this function is called. +*/ +void bond_destroy(struct bonding *bond) +{ + bond_deinit(bond->dev); + bond_destroy_sysfs_entry(bond); + unregister_netdevice(bond->dev); +} + +/* +* First release a slave and than destroy the bond if no more slaves iare left. +* Must be under rtnl_lock when this function is called. +*/ +int bond_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev) +{ + struct bonding *bond = bond_dev->priv; + int ret; + + ret = bond_release(bond_dev, slave_dev); + if ((ret == 0) && (bond->slave_cnt == 0)) { + printk(KERN_INFO DRV_NAME ": %s: destroying bond %s.\n", + bond_dev->name, bond_dev->name); + bond_destroy(bond); + } + return ret; +} + +/* * This function releases all slaves. */ static int bond_release_all(struct net_device *bond_dev) @@ -1839,10 +1938,12 @@ static int bond_release_all(struct net_device *bond_dev) /* close slave before restoring its mac address */ dev_close(slave_dev); - /* restore original ("permanent") mac address*/ - memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN); - addr.sa_family = slave_dev->type; - dev_set_mac_address(slave_dev, &addr); + if (!bond->params.fail_over_mac) { + /* restore original ("permanent") mac address*/ + memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN); + addr.sa_family = slave_dev->type; + dev_set_mac_address(slave_dev, &addr); + } slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB | IFF_SLAVE_INACTIVE); @@ -2013,6 +2114,17 @@ void bond_mii_monitor(struct net_device *bond_dev) * program could monitor the link itself if needed. */ + if (bond->send_grat_arp) { + if (bond->curr_active_slave && test_bit(__LINK_STATE_LINKWATCH_PENDING, + &bond->curr_active_slave->dev->state)) + dprintk("Needs to send gratuitous arp but not yet\n"); + else { + dprintk("sending delayed gratuitous arp on on %s\n", + bond->curr_active_slave->dev->name); + bond_send_gratuitous_arp(bond); + bond->send_grat_arp = 0; + } + } read_lock(&bond->curr_slave_lock); oldcurrent = bond->curr_active_slave; read_unlock(&bond->curr_slave_lock); @@ -2414,7 +2526,7 @@ static void bond_send_gratuitous_arp(struct bonding *bond) if (bond->master_ip) { bond_arp_send(slave->dev, ARPOP_REPLY, bond->master_ip, - bond->master_ip, 0); + bond->master_ip, 0); } list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { @@ -2951,9 +3063,15 @@ static void bond_info_show_master(struct seq_file *seq) curr = bond->curr_active_slave; read_unlock(&bond->curr_slave_lock); - seq_printf(seq, "Bonding Mode: %s\n", + seq_printf(seq, "Bonding Mode: %s", bond_mode_name(bond->params.mode)); + if (bond->params.mode == BOND_MODE_ACTIVEBACKUP && + bond->params.fail_over_mac) + seq_printf(seq, " (fail_over_mac)"); + + seq_printf(seq, "\n"); + if (bond->params.mode == BOND_MODE_XOR || bond->params.mode == BOND_MODE_8023AD) { seq_printf(seq, "Transmit Hash Policy: %s (%d)\n", @@ -3248,6 +3366,11 @@ static int bond_slave_netdev_event(unsigned long event, struct net_device *slave * ... Or is it this? */ break; + case NETDEV_GOING_DOWN: + dprintk("slave %s is going down\n", slave_dev->name); + if (bond->setup_by_slave) + bond_release_and_destroy(bond_dev, slave_dev); + break; case NETDEV_CHANGEMTU: /* * TODO: Should slaves be allowed to @@ -3880,6 +4003,13 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr) dprintk("bond=%p, name=%s\n", bond, (bond_dev ? bond_dev->name : "None")); + /* + * If fail_over_mac is enabled, do nothing and return success. + * Returning an error causes ifenslave to fail. + */ + if (bond->params.fail_over_mac) + return 0; + if (!is_valid_ether_addr(sa->sa_data)) { return -EADDRNOTAVAIL; } @@ -4217,6 +4347,8 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params) bond->current_arp_slave = NULL; bond->primary_slave = NULL; bond->dev = bond_dev; + bond->send_grat_arp = 0; + bond->setup_by_slave = 0; INIT_LIST_HEAD(&bond->vlan_list); /* Initialize the device entry points */ @@ -4265,7 +4397,6 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params) #ifdef CONFIG_PROC_FS bond_create_proc_entry(bond); #endif - list_add_tail(&bond->bond_list, &bond_dev_list); return 0; @@ -4599,6 +4730,11 @@ static int bond_check_params(struct bond_params *params) primary = NULL; } + if (fail_over_mac && (bond_mode != BOND_MODE_ACTIVEBACKUP)) + printk(KERN_WARNING DRV_NAME + ": Warning: fail_over_mac only affects " + "active-backup mode.\n"); + /* fill params struct with the proper values */ params->mode = bond_mode; params->xmit_policy = xmit_hashtype; @@ -4610,6 +4746,7 @@ static int bond_check_params(struct bond_params *params) params->use_carrier = use_carrier; params->lacp_fast = lacp_fast; params->primary[0] = 0; + params->fail_over_mac = fail_over_mac; if (primary) { strncpy(params->primary, primary, IFNAMSIZ); diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 6f49ca7e9b66..80c0c8c415ed 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -164,9 +164,7 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t printk(KERN_INFO DRV_NAME ": %s is being deleted...\n", bond->dev->name); - bond_deinit(bond->dev); - bond_destroy_sysfs_entry(bond); - unregister_netdevice(bond->dev); + bond_destroy(bond); rtnl_unlock(); goto out; } @@ -260,17 +258,16 @@ static ssize_t bonding_store_slaves(struct device *d, char command[IFNAMSIZ + 1] = { 0, }; char *ifname; int i, res, found, ret = count; + u32 original_mtu; struct slave *slave; struct net_device *dev = NULL; struct bonding *bond = to_bond(d); /* Quick sanity check -- is the bond interface up? */ if (!(bond->dev->flags & IFF_UP)) { - printk(KERN_ERR DRV_NAME - ": %s: Unable to update slaves because interface is down.\n", + printk(KERN_WARNING DRV_NAME + ": %s: doing slave updates when interface is down.\n", bond->dev->name); - ret = -EPERM; - goto out; } /* Note: We can't hold bond->lock here, as bond_create grabs it. */ @@ -327,6 +324,7 @@ static ssize_t bonding_store_slaves(struct device *d, } /* Set the slave's MTU to match the bond */ + original_mtu = dev->mtu; if (dev->mtu != bond->dev->mtu) { if (dev->change_mtu) { res = dev->change_mtu(dev, @@ -341,6 +339,9 @@ static ssize_t bonding_store_slaves(struct device *d, } rtnl_lock(); res = bond_enslave(bond->dev, dev); + bond_for_each_slave(bond, slave, i) + if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0) + slave->original_mtu = original_mtu; rtnl_unlock(); if (res) { ret = res; @@ -353,13 +354,17 @@ static ssize_t bonding_store_slaves(struct device *d, bond_for_each_slave(bond, slave, i) if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0) { dev = slave->dev; + original_mtu = slave->original_mtu; break; } if (dev) { printk(KERN_INFO DRV_NAME ": %s: Removing slave %s\n", bond->dev->name, dev->name); rtnl_lock(); - res = bond_release(bond->dev, dev); + if (bond->setup_by_slave) + res = bond_release_and_destroy(bond->dev, dev); + else + res = bond_release(bond->dev, dev); rtnl_unlock(); if (res) { ret = res; @@ -367,9 +372,9 @@ static ssize_t bonding_store_slaves(struct device *d, } /* set the slave MTU to the default */ if (dev->change_mtu) { - dev->change_mtu(dev, 1500); + dev->change_mtu(dev, original_mtu); } else { - dev->mtu = 1500; + dev->mtu = original_mtu; } } else { @@ -563,6 +568,54 @@ static ssize_t bonding_store_arp_validate(struct device *d, static DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate); /* + * Show and store fail_over_mac. User only allowed to change the + * value when there are no slaves. + */ +static ssize_t bonding_show_fail_over_mac(struct device *d, struct device_attribute *attr, char *buf) +{ + struct bonding *bond = to_bond(d); + + return sprintf(buf, "%d\n", bond->params.fail_over_mac) + 1; +} + +static ssize_t bonding_store_fail_over_mac(struct device *d, struct device_attribute *attr, const char *buf, size_t count) +{ + int new_value; + int ret = count; + struct bonding *bond = to_bond(d); + + if (bond->slave_cnt != 0) { + printk(KERN_ERR DRV_NAME + ": %s: Can't alter fail_over_mac with slaves in bond.\n", + bond->dev->name); + ret = -EPERM; + goto out; + } + + if (sscanf(buf, "%d", &new_value) != 1) { + printk(KERN_ERR DRV_NAME + ": %s: no fail_over_mac value specified.\n", + bond->dev->name); + ret = -EINVAL; + goto out; + } + + if ((new_value == 0) || (new_value == 1)) { + bond->params.fail_over_mac = new_value; + printk(KERN_INFO DRV_NAME ": %s: Setting fail_over_mac to %d.\n", + bond->dev->name, new_value); + } else { + printk(KERN_INFO DRV_NAME + ": %s: Ignoring invalid fail_over_mac value %d.\n", + bond->dev->name, new_value); + } +out: + return ret; +} + +static DEVICE_ATTR(fail_over_mac, S_IRUGO | S_IWUSR, bonding_show_fail_over_mac, bonding_store_fail_over_mac); + +/* * Show and set the arp timer interval. There are two tricky bits * here. First, if ARP monitoring is activated, then we must disable * MII monitoring. Second, if the ARP timer isn't running, we must @@ -1383,6 +1436,7 @@ static DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, NULL); static struct attribute *per_bond_attrs[] = { &dev_attr_slaves.attr, &dev_attr_mode.attr, + &dev_attr_fail_over_mac.attr, &dev_attr_arp_validate.attr, &dev_attr_arp_interval.attr, &dev_attr_arp_ip_target.attr, diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 2a6af7d23728..a8bbd563265c 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -22,8 +22,8 @@ #include "bond_3ad.h" #include "bond_alb.h" -#define DRV_VERSION "3.1.3" -#define DRV_RELDATE "June 13, 2007" +#define DRV_VERSION "3.2.0" +#define DRV_RELDATE "September 13, 2007" #define DRV_NAME "bonding" #define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" @@ -128,6 +128,7 @@ struct bond_params { int arp_interval; int arp_validate; int use_carrier; + int fail_over_mac; int updelay; int downdelay; int lacp_fast; @@ -156,6 +157,7 @@ struct slave { s8 link; /* one of BOND_LINK_XXXX */ s8 state; /* one of BOND_STATE_XXXX */ u32 original_flags; + u32 original_mtu; u32 link_failure_count; u16 speed; u8 duplex; @@ -185,6 +187,8 @@ struct bonding { struct timer_list mii_timer; struct timer_list arp_timer; s8 kill_timers; + s8 send_grat_arp; + s8 setup_by_slave; struct net_device_stats stats; #ifdef CONFIG_PROC_FS struct proc_dir_entry *proc_entry; @@ -292,6 +296,8 @@ static inline void bond_unset_master_alb_flags(struct bonding *bond) struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr); int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev); int bond_create(char *name, struct bond_params *params, struct bonding **newbond); +void bond_destroy(struct bonding *bond); +int bond_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev); void bond_deinit(struct net_device *bond_dev); int bond_create_sysfs(void); void bond_destroy_sysfs(void); diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index 563bf5f6fa2a..7df31b5561cc 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -4443,7 +4443,7 @@ static struct { {REG_MAC_COLL_EXCESS}, {REG_MAC_COLL_LATE} }; -#define CAS_REG_LEN (sizeof(ethtool_register_table)/sizeof(int)) +#define CAS_REG_LEN ARRAY_SIZE(ethtool_register_table) #define CAS_MAX_REGS (sizeof (u32)*CAS_REG_LEN) static void cas_read_regs(struct cas *cp, u8 *ptr, int len) diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c new file mode 100644 index 000000000000..ed53aaab4c02 --- /dev/null +++ b/drivers/net/cpmac.c @@ -0,0 +1,1174 @@ +/* + * Copyright (C) 2006, 2007 Eugene Konev + * + * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/moduleparam.h> + +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/types.h> +#include <linux/delay.h> +#include <linux/version.h> + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/skbuff.h> +#include <linux/mii.h> +#include <linux/phy.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <asm/gpio.h> + +MODULE_AUTHOR("Eugene Konev <ejka@imfi.kspu.ru>"); +MODULE_DESCRIPTION("TI AR7 ethernet driver (CPMAC)"); +MODULE_LICENSE("GPL"); + +static int debug_level = 8; +static int dumb_switch; + +/* Next 2 are only used in cpmac_probe, so it's pointless to change them */ +module_param(debug_level, int, 0444); +module_param(dumb_switch, int, 0444); + +MODULE_PARM_DESC(debug_level, "Number of NETIF_MSG bits to enable"); +MODULE_PARM_DESC(dumb_switch, "Assume switch is not connected to MDIO bus"); + +#define CPMAC_VERSION "0.5.0" +/* stolen from net/ieee80211.h */ +#ifndef MAC_FMT +#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" +#define MAC_ARG(x) ((u8*)(x))[0], ((u8*)(x))[1], ((u8*)(x))[2], \ + ((u8*)(x))[3], ((u8*)(x))[4], ((u8*)(x))[5] +#endif +/* frame size + 802.1q tag */ +#define CPMAC_SKB_SIZE (ETH_FRAME_LEN + 4) +#define CPMAC_QUEUES 8 + +/* Ethernet registers */ +#define CPMAC_TX_CONTROL 0x0004 +#define CPMAC_TX_TEARDOWN 0x0008 +#define CPMAC_RX_CONTROL 0x0014 +#define CPMAC_RX_TEARDOWN 0x0018 +#define CPMAC_MBP 0x0100 +# define MBP_RXPASSCRC 0x40000000 +# define MBP_RXQOS 0x20000000 +# define MBP_RXNOCHAIN 0x10000000 +# define MBP_RXCMF 0x01000000 +# define MBP_RXSHORT 0x00800000 +# define MBP_RXCEF 0x00400000 +# define MBP_RXPROMISC 0x00200000 +# define MBP_PROMISCCHAN(channel) (((channel) & 0x7) << 16) +# define MBP_RXBCAST 0x00002000 +# define MBP_BCASTCHAN(channel) (((channel) & 0x7) << 8) +# define MBP_RXMCAST 0x00000020 +# define MBP_MCASTCHAN(channel) ((channel) & 0x7) +#define CPMAC_UNICAST_ENABLE 0x0104 +#define CPMAC_UNICAST_CLEAR 0x0108 +#define CPMAC_MAX_LENGTH 0x010c +#define CPMAC_BUFFER_OFFSET 0x0110 +#define CPMAC_MAC_CONTROL 0x0160 +# define MAC_TXPTYPE 0x00000200 +# define MAC_TXPACE 0x00000040 +# define MAC_MII 0x00000020 +# define MAC_TXFLOW 0x00000010 +# define MAC_RXFLOW 0x00000008 +# define MAC_MTEST 0x00000004 +# define MAC_LOOPBACK 0x00000002 +# define MAC_FDX 0x00000001 +#define CPMAC_MAC_STATUS 0x0164 +# define MAC_STATUS_QOS 0x00000004 +# define MAC_STATUS_RXFLOW 0x00000002 +# define MAC_STATUS_TXFLOW 0x00000001 +#define CPMAC_TX_INT_ENABLE 0x0178 +#define CPMAC_TX_INT_CLEAR 0x017c +#define CPMAC_MAC_INT_VECTOR 0x0180 +# define MAC_INT_STATUS 0x00080000 +# define MAC_INT_HOST 0x00040000 +# define MAC_INT_RX 0x00020000 +# define MAC_INT_TX 0x00010000 +#define CPMAC_MAC_EOI_VECTOR 0x0184 +#define CPMAC_RX_INT_ENABLE 0x0198 +#define CPMAC_RX_INT_CLEAR 0x019c +#define CPMAC_MAC_INT_ENABLE 0x01a8 +#define CPMAC_MAC_INT_CLEAR 0x01ac +#define CPMAC_MAC_ADDR_LO(channel) (0x01b0 + (channel) * 4) +#define CPMAC_MAC_ADDR_MID 0x01d0 +#define CPMAC_MAC_ADDR_HI 0x01d4 +#define CPMAC_MAC_HASH_LO 0x01d8 +#define CPMAC_MAC_HASH_HI 0x01dc +#define CPMAC_TX_PTR(channel) (0x0600 + (channel) * 4) +#define CPMAC_RX_PTR(channel) (0x0620 + (channel) * 4) +#define CPMAC_TX_ACK(channel) (0x0640 + (channel) * 4) +#define CPMAC_RX_ACK(channel) (0x0660 + (channel) * 4) +#define CPMAC_REG_END 0x0680 +/* + * Rx/Tx statistics + * TODO: use some of them to fill stats in cpmac_stats() + */ +#define CPMAC_STATS_RX_GOOD 0x0200 +#define CPMAC_STATS_RX_BCAST 0x0204 +#define CPMAC_STATS_RX_MCAST 0x0208 +#define CPMAC_STATS_RX_PAUSE 0x020c +#define CPMAC_STATS_RX_CRC 0x0210 +#define CPMAC_STATS_RX_ALIGN 0x0214 +#define CPMAC_STATS_RX_OVER 0x0218 +#define CPMAC_STATS_RX_JABBER 0x021c +#define CPMAC_STATS_RX_UNDER 0x0220 +#define CPMAC_STATS_RX_FRAG 0x0224 +#define CPMAC_STATS_RX_FILTER 0x0228 +#define CPMAC_STATS_RX_QOSFILTER 0x022c +#define CPMAC_STATS_RX_OCTETS 0x0230 + +#define CPMAC_STATS_TX_GOOD 0x0234 +#define CPMAC_STATS_TX_BCAST 0x0238 +#define CPMAC_STATS_TX_MCAST 0x023c +#define CPMAC_STATS_TX_PAUSE 0x0240 +#define CPMAC_STATS_TX_DEFER 0x0244 +#define CPMAC_STATS_TX_COLLISION 0x0248 +#define CPMAC_STATS_TX_SINGLECOLL 0x024c +#define CPMAC_STATS_TX_MULTICOLL 0x0250 +#define CPMAC_STATS_TX_EXCESSCOLL 0x0254 +#define CPMAC_STATS_TX_LATECOLL 0x0258 +#define CPMAC_STATS_TX_UNDERRUN 0x025c +#define CPMAC_STATS_TX_CARRIERSENSE 0x0260 +#define CPMAC_STATS_TX_OCTETS 0x0264 + +#define cpmac_read(base, reg) (readl((void __iomem *)(base) + (reg))) +#define cpmac_write(base, reg, val) (writel(val, (void __iomem *)(base) + \ + (reg))) + +/* MDIO bus */ +#define CPMAC_MDIO_VERSION 0x0000 +#define CPMAC_MDIO_CONTROL 0x0004 +# define MDIOC_IDLE 0x80000000 +# define MDIOC_ENABLE 0x40000000 +# define MDIOC_PREAMBLE 0x00100000 +# define MDIOC_FAULT 0x00080000 +# define MDIOC_FAULTDETECT 0x00040000 +# define MDIOC_INTTEST 0x00020000 +# define MDIOC_CLKDIV(div) ((div) & 0xff) +#define CPMAC_MDIO_ALIVE 0x0008 +#define CPMAC_MDIO_LINK 0x000c +#define CPMAC_MDIO_ACCESS(channel) (0x0080 + (channel) * 8) +# define MDIO_BUSY 0x80000000 +# define MDIO_WRITE 0x40000000 +# define MDIO_REG(reg) (((reg) & 0x1f) << 21) +# define MDIO_PHY(phy) (((phy) & 0x1f) << 16) +# define MDIO_DATA(data) ((data) & 0xffff) +#define CPMAC_MDIO_PHYSEL(channel) (0x0084 + (channel) * 8) +# define PHYSEL_LINKSEL 0x00000040 +# define PHYSEL_LINKINT 0x00000020 + +struct cpmac_desc { + u32 hw_next; + u32 hw_data; + u16 buflen; + u16 bufflags; + u16 datalen; + u16 dataflags; +#define CPMAC_SOP 0x8000 +#define CPMAC_EOP 0x4000 +#define CPMAC_OWN 0x2000 +#define CPMAC_EOQ 0x1000 + struct sk_buff *skb; + struct cpmac_desc *next; + dma_addr_t mapping; + dma_addr_t data_mapping; +}; + +struct cpmac_priv { + spinlock_t lock; + spinlock_t rx_lock; + struct cpmac_desc *rx_head; + int ring_size; + struct cpmac_desc *desc_ring; + dma_addr_t dma_ring; + void __iomem *regs; + struct mii_bus *mii_bus; + struct phy_device *phy; + char phy_name[BUS_ID_SIZE]; + int oldlink, oldspeed, oldduplex; + u32 msg_enable; + struct net_device *dev; + struct work_struct reset_work; + struct platform_device *pdev; +}; + +static irqreturn_t cpmac_irq(int, void *); +static void cpmac_hw_start(struct net_device *dev); +static void cpmac_hw_stop(struct net_device *dev); +static int cpmac_stop(struct net_device *dev); +static int cpmac_open(struct net_device *dev); + +static void cpmac_dump_regs(struct net_device *dev) +{ + int i; + struct cpmac_priv *priv = netdev_priv(dev); + for (i = 0; i < CPMAC_REG_END; i += 4) { + if (i % 16 == 0) { + if (i) + printk("\n"); + printk(KERN_DEBUG "%s: reg[%p]:", dev->name, + priv->regs + i); + } + printk(" %08x", cpmac_read(priv->regs, i)); + } + printk("\n"); +} + +static void cpmac_dump_desc(struct net_device *dev, struct cpmac_desc *desc) +{ + int i; + printk(KERN_DEBUG "%s: desc[%p]:", dev->name, desc); + for (i = 0; i < sizeof(*desc) / 4; i++) + printk(" %08x", ((u32 *)desc)[i]); + printk("\n"); +} + +static void cpmac_dump_skb(struct net_device *dev, struct sk_buff *skb) +{ + int i; + printk(KERN_DEBUG "%s: skb 0x%p, len=%d\n", dev->name, skb, skb->len); + for (i = 0; i < skb->len; i++) { + if (i % 16 == 0) { + if (i) + printk("\n"); + printk(KERN_DEBUG "%s: data[%p]:", dev->name, + skb->data + i); + } + printk(" %02x", ((u8 *)skb->data)[i]); + } + printk("\n"); +} + +static int cpmac_mdio_read(struct mii_bus *bus, int phy_id, int reg) +{ + u32 val; + + while (cpmac_read(bus->priv, CPMAC_MDIO_ACCESS(0)) & MDIO_BUSY) + cpu_relax(); + cpmac_write(bus->priv, CPMAC_MDIO_ACCESS(0), MDIO_BUSY | MDIO_REG(reg) | + MDIO_PHY(phy_id)); + while ((val = cpmac_read(bus->priv, CPMAC_MDIO_ACCESS(0))) & MDIO_BUSY) + cpu_relax(); + return MDIO_DATA(val); +} + +static int cpmac_mdio_write(struct mii_bus *bus, int phy_id, + int reg, u16 val) +{ + while (cpmac_read(bus->priv, CPMAC_MDIO_ACCESS(0)) & MDIO_BUSY) + cpu_relax(); + cpmac_write(bus->priv, CPMAC_MDIO_ACCESS(0), MDIO_BUSY | MDIO_WRITE | + MDIO_REG(reg) | MDIO_PHY(phy_id) | MDIO_DATA(val)); + return 0; +} + +static int cpmac_mdio_reset(struct mii_bus *bus) +{ + ar7_device_reset(AR7_RESET_BIT_MDIO); + cpmac_write(bus->priv, CPMAC_MDIO_CONTROL, MDIOC_ENABLE | + MDIOC_CLKDIV(ar7_cpmac_freq() / 2200000 - 1)); + return 0; +} + +static int mii_irqs[PHY_MAX_ADDR] = { PHY_POLL, }; + +static struct mii_bus cpmac_mii = { + .name = "cpmac-mii", + .read = cpmac_mdio_read, + .write = cpmac_mdio_write, + .reset = cpmac_mdio_reset, + .irq = mii_irqs, +}; + +static int cpmac_config(struct net_device *dev, struct ifmap *map) +{ + if (dev->flags & IFF_UP) + return -EBUSY; + + /* Don't allow changing the I/O address */ + if (map->base_addr != dev->base_addr) + return -EOPNOTSUPP; + + /* ignore other fields */ + return 0; +} + +static void cpmac_set_multicast_list(struct net_device *dev) +{ + struct dev_mc_list *iter; + int i; + u8 tmp; + u32 mbp, bit, hash[2] = { 0, }; + struct cpmac_priv *priv = netdev_priv(dev); + + mbp = cpmac_read(priv->regs, CPMAC_MBP); + if (dev->flags & IFF_PROMISC) { + cpmac_write(priv->regs, CPMAC_MBP, (mbp & ~MBP_PROMISCCHAN(0)) | + MBP_RXPROMISC); + } else { + cpmac_write(priv->regs, CPMAC_MBP, mbp & ~MBP_RXPROMISC); + if (dev->flags & IFF_ALLMULTI) { + /* enable all multicast mode */ + cpmac_write(priv->regs, CPMAC_MAC_HASH_LO, 0xffffffff); + cpmac_write(priv->regs, CPMAC_MAC_HASH_HI, 0xffffffff); + } else { + /* + * cpmac uses some strange mac address hashing + * (not crc32) + */ + for (i = 0, iter = dev->mc_list; i < dev->mc_count; + i++, iter = iter->next) { + bit = 0; + tmp = iter->dmi_addr[0]; + bit ^= (tmp >> 2) ^ (tmp << 4); + tmp = iter->dmi_addr[1]; + bit ^= (tmp >> 4) ^ (tmp << 2); + tmp = iter->dmi_addr[2]; + bit ^= (tmp >> 6) ^ tmp; + tmp = iter->dmi_addr[3]; + bit ^= (tmp >> 2) ^ (tmp << 4); + tmp = iter->dmi_addr[4]; + bit ^= (tmp >> 4) ^ (tmp << 2); + tmp = iter->dmi_addr[5]; + bit ^= (tmp >> 6) ^ tmp; + bit &= 0x3f; + hash[bit / 32] |= 1 << (bit % 32); + } + + cpmac_write(priv->regs, CPMAC_MAC_HASH_LO, hash[0]); + cpmac_write(priv->regs, CPMAC_MAC_HASH_HI, hash[1]); + } + } +} + +static struct sk_buff *cpmac_rx_one(struct net_device *dev, + struct cpmac_priv *priv, + struct cpmac_desc *desc) +{ + struct sk_buff *skb, *result = NULL; + + if (unlikely(netif_msg_hw(priv))) + cpmac_dump_desc(dev, desc); + cpmac_write(priv->regs, CPMAC_RX_ACK(0), (u32)desc->mapping); + if (unlikely(!desc->datalen)) { + if (netif_msg_rx_err(priv) && net_ratelimit()) + printk(KERN_WARNING "%s: rx: spurious interrupt\n", + dev->name); + return NULL; + } + + skb = netdev_alloc_skb(dev, CPMAC_SKB_SIZE); + if (likely(skb)) { + skb_reserve(skb, 2); + skb_put(desc->skb, desc->datalen); + desc->skb->protocol = eth_type_trans(desc->skb, dev); + desc->skb->ip_summed = CHECKSUM_NONE; + dev->stats.rx_packets++; + dev->stats.rx_bytes += desc->datalen; + result = desc->skb; + dma_unmap_single(&dev->dev, desc->data_mapping, CPMAC_SKB_SIZE, + DMA_FROM_DEVICE); + desc->skb = skb; + desc->data_mapping = dma_map_single(&dev->dev, skb->data, + CPMAC_SKB_SIZE, + DMA_FROM_DEVICE); + desc->hw_data = (u32)desc->data_mapping; + if (unlikely(netif_msg_pktdata(priv))) { + printk(KERN_DEBUG "%s: received packet:\n", dev->name); + cpmac_dump_skb(dev, result); + } + } else { + if (netif_msg_rx_err(priv) && net_ratelimit()) + printk(KERN_WARNING + "%s: low on skbs, dropping packet\n", dev->name); + dev->stats.rx_dropped++; + } + + desc->buflen = CPMAC_SKB_SIZE; + desc->dataflags = CPMAC_OWN; + + return result; +} + +static int cpmac_poll(struct net_device *dev, int *budget) +{ + struct sk_buff *skb; + struct cpmac_desc *desc; + int received = 0, quota = min(dev->quota, *budget); + struct cpmac_priv *priv = netdev_priv(dev); + + spin_lock(&priv->rx_lock); + if (unlikely(!priv->rx_head)) { + if (netif_msg_rx_err(priv) && net_ratelimit()) + printk(KERN_WARNING "%s: rx: polling, but no queue\n", + dev->name); + netif_rx_complete(dev); + return 0; + } + + desc = priv->rx_head; + while ((received < quota) && ((desc->dataflags & CPMAC_OWN) == 0)) { + skb = cpmac_rx_one(dev, priv, desc); + if (likely(skb)) { + netif_receive_skb(skb); + received++; + } + desc = desc->next; + } + + priv->rx_head = desc; + spin_unlock(&priv->rx_lock); + *budget -= received; + dev->quota -= received; + if (unlikely(netif_msg_rx_status(priv))) + printk(KERN_DEBUG "%s: poll processed %d packets\n", dev->name, + received); + if (desc->dataflags & CPMAC_OWN) { + netif_rx_complete(dev); + cpmac_write(priv->regs, CPMAC_RX_PTR(0), (u32)desc->mapping); + cpmac_write(priv->regs, CPMAC_RX_INT_ENABLE, 1); + return 0; + } + + return 1; +} + +static int cpmac_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + int queue, len; + struct cpmac_desc *desc; + struct cpmac_priv *priv = netdev_priv(dev); + + if (unlikely(skb_padto(skb, ETH_ZLEN))) { + if (netif_msg_tx_err(priv) && net_ratelimit()) + printk(KERN_WARNING + "%s: tx: padding failed, dropping\n", dev->name); + spin_lock(&priv->lock); + dev->stats.tx_dropped++; + spin_unlock(&priv->lock); + return -ENOMEM; + } + + len = max(skb->len, ETH_ZLEN); + queue = skb->queue_mapping; +#ifdef CONFIG_NETDEVICES_MULTIQUEUE + netif_stop_subqueue(dev, queue); +#else + netif_stop_queue(dev); +#endif + + desc = &priv->desc_ring[queue]; + if (unlikely(desc->dataflags & CPMAC_OWN)) { + if (netif_msg_tx_err(priv) && net_ratelimit()) + printk(KERN_WARNING "%s: tx dma ring full, dropping\n", + dev->name); + spin_lock(&priv->lock); + dev->stats.tx_dropped++; + spin_unlock(&priv->lock); + dev_kfree_skb_any(skb); + return -ENOMEM; + } + + spin_lock(&priv->lock); + dev->trans_start = jiffies; + spin_unlock(&priv->lock); + desc->dataflags = CPMAC_SOP | CPMAC_EOP | CPMAC_OWN; + desc->skb = skb; + desc->data_mapping = dma_map_single(&dev->dev, skb->data, len, + DMA_TO_DEVICE); + desc->hw_data = (u32)desc->data_mapping; + desc->datalen = len; + desc->buflen = len; + if (unlikely(netif_msg_tx_queued(priv))) + printk(KERN_DEBUG "%s: sending 0x%p, len=%d\n", dev->name, skb, + skb->len); + if (unlikely(netif_msg_hw(priv))) + cpmac_dump_desc(dev, desc); + if (unlikely(netif_msg_pktdata(priv))) + cpmac_dump_skb(dev, skb); + cpmac_write(priv->regs, CPMAC_TX_PTR(queue), (u32)desc->mapping); + + return 0; +} + +static void cpmac_end_xmit(struct net_device *dev, int queue) +{ + struct cpmac_desc *desc; + struct cpmac_priv *priv = netdev_priv(dev); + + desc = &priv->desc_ring[queue]; + cpmac_write(priv->regs, CPMAC_TX_ACK(queue), (u32)desc->mapping); + if (likely(desc->skb)) { + spin_lock(&priv->lock); + dev->stats.tx_packets++; + dev->stats.tx_bytes += desc->skb->len; + spin_unlock(&priv->lock); + dma_unmap_single(&dev->dev, desc->data_mapping, desc->skb->len, + DMA_TO_DEVICE); + + if (unlikely(netif_msg_tx_done(priv))) + printk(KERN_DEBUG "%s: sent 0x%p, len=%d\n", dev->name, + desc->skb, desc->skb->len); + + dev_kfree_skb_irq(desc->skb); + desc->skb = NULL; +#ifdef CONFIG_NETDEVICES_MULTIQUEUE + if (netif_subqueue_stopped(dev, queue)) + netif_wake_subqueue(dev, queue); +#else + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); +#endif + } else { + if (netif_msg_tx_err(priv) && net_ratelimit()) + printk(KERN_WARNING + "%s: end_xmit: spurious interrupt\n", dev->name); +#ifdef CONFIG_NETDEVICES_MULTIQUEUE + if (netif_subqueue_stopped(dev, queue)) + netif_wake_subqueue(dev, queue); +#else + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); +#endif + } +} + +static void cpmac_hw_stop(struct net_device *dev) +{ + int i; + struct cpmac_priv *priv = netdev_priv(dev); + struct plat_cpmac_data *pdata = priv->pdev->dev.platform_data; + + ar7_device_reset(pdata->reset_bit); + cpmac_write(priv->regs, CPMAC_RX_CONTROL, + cpmac_read(priv->regs, CPMAC_RX_CONTROL) & ~1); + cpmac_write(priv->regs, CPMAC_TX_CONTROL, + cpmac_read(priv->regs, CPMAC_TX_CONTROL) & ~1); + for (i = 0; i < 8; i++) { + cpmac_write(priv->regs, CPMAC_TX_PTR(i), 0); + cpmac_write(priv->regs, CPMAC_RX_PTR(i), 0); + } + cpmac_write(priv->regs, CPMAC_UNICAST_CLEAR, 0xff); + cpmac_write(priv->regs, CPMAC_RX_INT_CLEAR, 0xff); + cpmac_write(priv->regs, CPMAC_TX_INT_CLEAR, 0xff); + cpmac_write(priv->regs, CPMAC_MAC_INT_CLEAR, 0xff); + cpmac_write(priv->regs, CPMAC_MAC_CONTROL, + cpmac_read(priv->regs, CPMAC_MAC_CONTROL) & ~MAC_MII); +} + +static void cpmac_hw_start(struct net_device *dev) +{ + int i; + struct cpmac_priv *priv = netdev_priv(dev); + struct plat_cpmac_data *pdata = priv->pdev->dev.platform_data; + + ar7_device_reset(pdata->reset_bit); + for (i = 0; i < 8; i++) { + cpmac_write(priv->regs, CPMAC_TX_PTR(i), 0); + cpmac_write(priv->regs, CPMAC_RX_PTR(i), 0); + } + cpmac_write(priv->regs, CPMAC_RX_PTR(0), priv->rx_head->mapping); + + cpmac_write(priv->regs, CPMAC_MBP, MBP_RXSHORT | MBP_RXBCAST | + MBP_RXMCAST); + cpmac_write(priv->regs, CPMAC_BUFFER_OFFSET, 0); + for (i = 0; i < 8; i++) + cpmac_write(priv->regs, CPMAC_MAC_ADDR_LO(i), dev->dev_addr[5]); + cpmac_write(priv->regs, CPMAC_MAC_ADDR_MID, dev->dev_addr[4]); + cpmac_write(priv->regs, CPMAC_MAC_ADDR_HI, dev->dev_addr[0] | + (dev->dev_addr[1] << 8) | (dev->dev_addr[2] << 16) | + (dev->dev_addr[3] << 24)); + cpmac_write(priv->regs, CPMAC_MAX_LENGTH, CPMAC_SKB_SIZE); + cpmac_write(priv->regs, CPMAC_UNICAST_CLEAR, 0xff); + cpmac_write(priv->regs, CPMAC_RX_INT_CLEAR, 0xff); + cpmac_write(priv->regs, CPMAC_TX_INT_CLEAR, 0xff); + cpmac_write(priv->regs, CPMAC_MAC_INT_CLEAR, 0xff); + cpmac_write(priv->regs, CPMAC_UNICAST_ENABLE, 1); + cpmac_write(priv->regs, CPMAC_RX_INT_ENABLE, 1); + cpmac_write(priv->regs, CPMAC_TX_INT_ENABLE, 0xff); + cpmac_write(priv->regs, CPMAC_MAC_INT_ENABLE, 3); + + cpmac_write(priv->regs, CPMAC_RX_CONTROL, + cpmac_read(priv->regs, CPMAC_RX_CONTROL) | 1); + cpmac_write(priv->regs, CPMAC_TX_CONTROL, + cpmac_read(priv->regs, CPMAC_TX_CONTROL) | 1); + cpmac_write(priv->regs, CPMAC_MAC_CONTROL, + cpmac_read(priv->regs, CPMAC_MAC_CONTROL) | MAC_MII | + MAC_FDX); +} + +static void cpmac_clear_rx(struct net_device *dev) +{ + struct cpmac_priv *priv = netdev_priv(dev); + struct cpmac_desc *desc; + int i; + if (unlikely(!priv->rx_head)) + return; + desc = priv->rx_head; + for (i = 0; i < priv->ring_size; i++) { + if ((desc->dataflags & CPMAC_OWN) == 0) { + if (netif_msg_rx_err(priv) && net_ratelimit()) + printk(KERN_WARNING "%s: packet dropped\n", + dev->name); + if (unlikely(netif_msg_hw(priv))) + cpmac_dump_desc(dev, desc); + desc->dataflags = CPMAC_OWN; + dev->stats.rx_dropped++; + } + desc = desc->next; + } +} + +static void cpmac_clear_tx(struct net_device *dev) +{ + struct cpmac_priv *priv = netdev_priv(dev); + int i; + if (unlikely(!priv->desc_ring)) + return; + for (i = 0; i < CPMAC_QUEUES; i++) + if (priv->desc_ring[i].skb) { + dev_kfree_skb_any(priv->desc_ring[i].skb); + if (netif_subqueue_stopped(dev, i)) + netif_wake_subqueue(dev, i); + } +} + +static void cpmac_hw_error(struct work_struct *work) +{ + struct cpmac_priv *priv = + container_of(work, struct cpmac_priv, reset_work); + + spin_lock(&priv->rx_lock); + cpmac_clear_rx(priv->dev); + spin_unlock(&priv->rx_lock); + cpmac_clear_tx(priv->dev); + cpmac_hw_start(priv->dev); + netif_start_queue(priv->dev); +} + +static irqreturn_t cpmac_irq(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct cpmac_priv *priv; + int queue; + u32 status; + + if (!dev) + return IRQ_NONE; + + priv = netdev_priv(dev); + + status = cpmac_read(priv->regs, CPMAC_MAC_INT_VECTOR); + + if (unlikely(netif_msg_intr(priv))) + printk(KERN_DEBUG "%s: interrupt status: 0x%08x\n", dev->name, + status); + + if (status & MAC_INT_TX) + cpmac_end_xmit(dev, (status & 7)); + + if (status & MAC_INT_RX) { + queue = (status >> 8) & 7; + netif_rx_schedule(dev); + cpmac_write(priv->regs, CPMAC_RX_INT_CLEAR, 1 << queue); + } + + cpmac_write(priv->regs, CPMAC_MAC_EOI_VECTOR, 0); + + if (unlikely(status & (MAC_INT_HOST | MAC_INT_STATUS))) { + if (netif_msg_drv(priv) && net_ratelimit()) + printk(KERN_ERR "%s: hw error, resetting...\n", + dev->name); + netif_stop_queue(dev); + cpmac_hw_stop(dev); + schedule_work(&priv->reset_work); + if (unlikely(netif_msg_hw(priv))) + cpmac_dump_regs(dev); + } + + return IRQ_HANDLED; +} + +static void cpmac_tx_timeout(struct net_device *dev) +{ + struct cpmac_priv *priv = netdev_priv(dev); + int i; + + spin_lock(&priv->lock); + dev->stats.tx_errors++; + spin_unlock(&priv->lock); + if (netif_msg_tx_err(priv) && net_ratelimit()) + printk(KERN_WARNING "%s: transmit timeout\n", dev->name); + /* + * FIXME: waking up random queue is not the best thing to + * do... on the other hand why we got here at all? + */ +#ifdef CONFIG_NETDEVICES_MULTIQUEUE + for (i = 0; i < CPMAC_QUEUES; i++) + if (priv->desc_ring[i].skb) { + dev_kfree_skb_any(priv->desc_ring[i].skb); + netif_wake_subqueue(dev, i); + break; + } +#else + if (priv->desc_ring[0].skb) + dev_kfree_skb_any(priv->desc_ring[0].skb); + netif_wake_queue(dev); +#endif +} + +static int cpmac_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct cpmac_priv *priv = netdev_priv(dev); + if (!(netif_running(dev))) + return -EINVAL; + if (!priv->phy) + return -EINVAL; + if ((cmd == SIOCGMIIPHY) || (cmd == SIOCGMIIREG) || + (cmd == SIOCSMIIREG)) + return phy_mii_ioctl(priv->phy, if_mii(ifr), cmd); + + return -EOPNOTSUPP; +} + +static int cpmac_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct cpmac_priv *priv = netdev_priv(dev); + + if (priv->phy) + return phy_ethtool_gset(priv->phy, cmd); + + return -EINVAL; +} + +static int cpmac_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct cpmac_priv *priv = netdev_priv(dev); + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + if (priv->phy) + return phy_ethtool_sset(priv->phy, cmd); + + return -EINVAL; +} + +static void cpmac_get_ringparam(struct net_device *dev, struct ethtool_ringparam* ring) +{ + struct cpmac_priv *priv = netdev_priv(dev); + + ring->rx_max_pending = 1024; + ring->rx_mini_max_pending = 1; + ring->rx_jumbo_max_pending = 1; + ring->tx_max_pending = 1; + + ring->rx_pending = priv->ring_size; + ring->rx_mini_pending = 1; + ring->rx_jumbo_pending = 1; + ring->tx_pending = 1; +} + +static int cpmac_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ring) +{ + struct cpmac_priv *priv = netdev_priv(dev); + + if (dev->flags && IFF_UP) + return -EBUSY; + priv->ring_size = ring->rx_pending; + return 0; +} + +static void cpmac_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + strcpy(info->driver, "cpmac"); + strcpy(info->version, CPMAC_VERSION); + info->fw_version[0] = '\0'; + sprintf(info->bus_info, "%s", "cpmac"); + info->regdump_len = 0; +} + +static const struct ethtool_ops cpmac_ethtool_ops = { + .get_settings = cpmac_get_settings, + .set_settings = cpmac_set_settings, + .get_drvinfo = cpmac_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_ringparam = cpmac_get_ringparam, + .set_ringparam = cpmac_set_ringparam, +}; + +static void cpmac_adjust_link(struct net_device *dev) +{ + struct cpmac_priv *priv = netdev_priv(dev); + int new_state = 0; + + spin_lock(&priv->lock); + if (priv->phy->link) { + netif_start_queue(dev); + if (priv->phy->duplex != priv->oldduplex) { + new_state = 1; + priv->oldduplex = priv->phy->duplex; + } + + if (priv->phy->speed != priv->oldspeed) { + new_state = 1; + priv->oldspeed = priv->phy->speed; + } + + if (!priv->oldlink) { + new_state = 1; + priv->oldlink = 1; + netif_schedule(dev); + } + } else if (priv->oldlink) { + netif_stop_queue(dev); + new_state = 1; + priv->oldlink = 0; + priv->oldspeed = 0; + priv->oldduplex = -1; + } + + if (new_state && netif_msg_link(priv) && net_ratelimit()) + phy_print_status(priv->phy); + + spin_unlock(&priv->lock); +} + +static int cpmac_open(struct net_device *dev) +{ + int i, size, res; + struct cpmac_priv *priv = netdev_priv(dev); + struct resource *mem; + struct cpmac_desc *desc; + struct sk_buff *skb; + + priv->phy = phy_connect(dev, priv->phy_name, &cpmac_adjust_link, + 0, PHY_INTERFACE_MODE_MII); + if (IS_ERR(priv->phy)) { + if (netif_msg_drv(priv)) + printk(KERN_ERR "%s: Could not attach to PHY\n", + dev->name); + return PTR_ERR(priv->phy); + } + + mem = platform_get_resource_byname(priv->pdev, IORESOURCE_MEM, "regs"); + if (!request_mem_region(mem->start, mem->end - mem->start, dev->name)) { + if (netif_msg_drv(priv)) + printk(KERN_ERR "%s: failed to request registers\n", + dev->name); + res = -ENXIO; + goto fail_reserve; + } + + priv->regs = ioremap(mem->start, mem->end - mem->start); + if (!priv->regs) { + if (netif_msg_drv(priv)) + printk(KERN_ERR "%s: failed to remap registers\n", + dev->name); + res = -ENXIO; + goto fail_remap; + } + + size = priv->ring_size + CPMAC_QUEUES; + priv->desc_ring = dma_alloc_coherent(&dev->dev, + sizeof(struct cpmac_desc) * size, + &priv->dma_ring, + GFP_KERNEL); + if (!priv->desc_ring) { + res = -ENOMEM; + goto fail_alloc; + } + + for (i = 0; i < size; i++) + priv->desc_ring[i].mapping = priv->dma_ring + sizeof(*desc) * i; + + priv->rx_head = &priv->desc_ring[CPMAC_QUEUES]; + for (i = 0, desc = priv->rx_head; i < priv->ring_size; i++, desc++) { + skb = netdev_alloc_skb(dev, CPMAC_SKB_SIZE); + if (unlikely(!skb)) { + res = -ENOMEM; + goto fail_desc; + } + skb_reserve(skb, 2); + desc->skb = skb; + desc->data_mapping = dma_map_single(&dev->dev, skb->data, + CPMAC_SKB_SIZE, + DMA_FROM_DEVICE); + desc->hw_data = (u32)desc->data_mapping; + desc->buflen = CPMAC_SKB_SIZE; + desc->dataflags = CPMAC_OWN; + desc->next = &priv->rx_head[(i + 1) % priv->ring_size]; + desc->hw_next = (u32)desc->next->mapping; + } + + if ((res = request_irq(dev->irq, cpmac_irq, IRQF_SHARED, + dev->name, dev))) { + if (netif_msg_drv(priv)) + printk(KERN_ERR "%s: failed to obtain irq\n", + dev->name); + goto fail_irq; + } + + INIT_WORK(&priv->reset_work, cpmac_hw_error); + cpmac_hw_start(dev); + + priv->phy->state = PHY_CHANGELINK; + phy_start(priv->phy); + + return 0; + +fail_irq: +fail_desc: + for (i = 0; i < priv->ring_size; i++) { + if (priv->rx_head[i].skb) { + dma_unmap_single(&dev->dev, + priv->rx_head[i].data_mapping, + CPMAC_SKB_SIZE, + DMA_FROM_DEVICE); + kfree_skb(priv->rx_head[i].skb); + } + } +fail_alloc: + kfree(priv->desc_ring); + iounmap(priv->regs); + +fail_remap: + release_mem_region(mem->start, mem->end - mem->start); + +fail_reserve: + phy_disconnect(priv->phy); + + return res; +} + +static int cpmac_stop(struct net_device *dev) +{ + int i; + struct cpmac_priv *priv = netdev_priv(dev); + struct resource *mem; + + netif_stop_queue(dev); + + cancel_work_sync(&priv->reset_work); + phy_stop(priv->phy); + phy_disconnect(priv->phy); + priv->phy = NULL; + + cpmac_hw_stop(dev); + + for (i = 0; i < 8; i++) + cpmac_write(priv->regs, CPMAC_TX_PTR(i), 0); + cpmac_write(priv->regs, CPMAC_RX_PTR(0), 0); + cpmac_write(priv->regs, CPMAC_MBP, 0); + + free_irq(dev->irq, dev); + iounmap(priv->regs); + mem = platform_get_resource_byname(priv->pdev, IORESOURCE_MEM, "regs"); + release_mem_region(mem->start, mem->end - mem->start); + priv->rx_head = &priv->desc_ring[CPMAC_QUEUES]; + for (i = 0; i < priv->ring_size; i++) { + if (priv->rx_head[i].skb) { + dma_unmap_single(&dev->dev, + priv->rx_head[i].data_mapping, + CPMAC_SKB_SIZE, + DMA_FROM_DEVICE); + kfree_skb(priv->rx_head[i].skb); + } + } + + dma_free_coherent(&dev->dev, sizeof(struct cpmac_desc) * + (CPMAC_QUEUES + priv->ring_size), + priv->desc_ring, priv->dma_ring); + return 0; +} + +static int external_switch; + +static int __devinit cpmac_probe(struct platform_device *pdev) +{ + int rc, phy_id; + struct resource *mem; + struct cpmac_priv *priv; + struct net_device *dev; + struct plat_cpmac_data *pdata; + + pdata = pdev->dev.platform_data; + + for (phy_id = 0; phy_id < PHY_MAX_ADDR; phy_id++) { + if (!(pdata->phy_mask & (1 << phy_id))) + continue; + if (!cpmac_mii.phy_map[phy_id]) + continue; + break; + } + + if (phy_id == PHY_MAX_ADDR) { + if (external_switch || dumb_switch) + phy_id = 0; + else { + printk(KERN_ERR "cpmac: no PHY present\n"); + return -ENODEV; + } + } + + dev = alloc_etherdev_mq(sizeof(*priv), CPMAC_QUEUES); + + if (!dev) { + printk(KERN_ERR "cpmac: Unable to allocate net_device\n"); + return -ENOMEM; + } + + platform_set_drvdata(pdev, dev); + priv = netdev_priv(dev); + + priv->pdev = pdev; + mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); + if (!mem) { + rc = -ENODEV; + goto fail; + } + + dev->irq = platform_get_irq_byname(pdev, "irq"); + + dev->open = cpmac_open; + dev->stop = cpmac_stop; + dev->set_config = cpmac_config; + dev->hard_start_xmit = cpmac_start_xmit; + dev->do_ioctl = cpmac_ioctl; + dev->set_multicast_list = cpmac_set_multicast_list; + dev->tx_timeout = cpmac_tx_timeout; + dev->ethtool_ops = &cpmac_ethtool_ops; + dev->poll = cpmac_poll; + dev->weight = 64; + dev->features |= NETIF_F_MULTI_QUEUE; + + spin_lock_init(&priv->lock); + spin_lock_init(&priv->rx_lock); + priv->dev = dev; + priv->ring_size = 64; + priv->msg_enable = netif_msg_init(debug_level, 0xff); + memcpy(dev->dev_addr, pdata->dev_addr, sizeof(dev->dev_addr)); + if (phy_id == 31) { + snprintf(priv->phy_name, BUS_ID_SIZE, PHY_ID_FMT, + cpmac_mii.id, phy_id); + } else + snprintf(priv->phy_name, BUS_ID_SIZE, "fixed@%d:%d", 100, 1); + + if ((rc = register_netdev(dev))) { + printk(KERN_ERR "cpmac: error %i registering device %s\n", rc, + dev->name); + goto fail; + } + + if (netif_msg_probe(priv)) { + printk(KERN_INFO + "cpmac: device %s (regs: %p, irq: %d, phy: %s, mac: " + MAC_FMT ")\n", dev->name, (void *)mem->start, dev->irq, + priv->phy_name, MAC_ARG(dev->dev_addr)); + } + return 0; + +fail: + free_netdev(dev); + return rc; +} + +static int __devexit cpmac_remove(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + unregister_netdev(dev); + free_netdev(dev); + return 0; +} + +static struct platform_driver cpmac_driver = { + .driver.name = "cpmac", + .probe = cpmac_probe, + .remove = __devexit_p(cpmac_remove), +}; + +int __devinit cpmac_init(void) +{ + u32 mask; + int i, res; + + cpmac_mii.priv = ioremap(AR7_REGS_MDIO, 256); + + if (!cpmac_mii.priv) { + printk(KERN_ERR "Can't ioremap mdio registers\n"); + return -ENXIO; + } + +#warning FIXME: unhardcode gpio&reset bits + ar7_gpio_disable(26); + ar7_gpio_disable(27); + ar7_device_reset(AR7_RESET_BIT_CPMAC_LO); + ar7_device_reset(AR7_RESET_BIT_CPMAC_HI); + ar7_device_reset(AR7_RESET_BIT_EPHY); + + cpmac_mii.reset(&cpmac_mii); + + for (i = 0; i < 300000; i++) + if ((mask = cpmac_read(cpmac_mii.priv, CPMAC_MDIO_ALIVE))) + break; + else + cpu_relax(); + + mask &= 0x7fffffff; + if (mask & (mask - 1)) { + external_switch = 1; + mask = 0; + } + + cpmac_mii.phy_mask = ~(mask | 0x80000000); + + res = mdiobus_register(&cpmac_mii); + if (res) + goto fail_mii; + + res = platform_driver_register(&cpmac_driver); + if (res) + goto fail_cpmac; + + return 0; + +fail_cpmac: + mdiobus_unregister(&cpmac_mii); + +fail_mii: + iounmap(cpmac_mii.priv); + + return res; +} + +void __devexit cpmac_exit(void) +{ + platform_driver_unregister(&cpmac_driver); + mdiobus_unregister(&cpmac_mii); + iounmap(cpmac_mii.priv); +} + +module_init(cpmac_init); +module_exit(cpmac_exit); diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 0db5e6fabe73..558440c15b6c 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -168,7 +168,6 @@ static int gfar_probe(struct platform_device *pdev) struct gfar_private *priv = NULL; struct gianfar_platform_data *einfo; struct resource *r; - int idx; int err = 0; DECLARE_MAC_BUF(mac); @@ -261,7 +260,9 @@ static int gfar_probe(struct platform_device *pdev) dev->hard_start_xmit = gfar_start_xmit; dev->tx_timeout = gfar_timeout; dev->watchdog_timeo = TX_TIMEOUT; +#ifdef CONFIG_GFAR_NAPI netif_napi_add(dev, &priv->napi, gfar_poll, GFAR_DEV_WEIGHT); +#endif #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = gfar_netpoll; #endif @@ -931,9 +932,14 @@ tx_skb_fail: /* Returns 0 for success. */ static int gfar_enet_open(struct net_device *dev) { +#ifdef CONFIG_GFAR_NAPI + struct gfar_private *priv = netdev_priv(dev); +#endif int err; +#ifdef CONFIG_GFAR_NAPI napi_enable(&priv->napi); +#endif /* Initialize a bunch of registers */ init_registers(dev); @@ -943,13 +949,17 @@ static int gfar_enet_open(struct net_device *dev) err = init_phy(dev); if(err) { +#ifdef CONFIG_GFAR_NAPI napi_disable(&priv->napi); +#endif return err; } err = startup_gfar(dev); if (err) +#ifdef CONFIG_GFAR_NAPI napi_disable(&priv->napi); +#endif netif_start_queue(dev); @@ -1103,7 +1113,9 @@ static int gfar_close(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); +#ifdef CONFIG_GFAR_NAPI napi_disable(&priv->napi); +#endif stop_gfar(dev); diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index ecd156def039..ad9e327c3b03 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -292,7 +292,7 @@ static int sp_header(struct sk_buff *skb, struct net_device *dev, const void *saddr, unsigned len) { #ifdef CONFIG_INET - if (type != htons(ETH_P_AX25)) + if (type != ETH_P_AX25) return ax25_hard_header(skb, dev, type, daddr, saddr, len); #endif return 0; diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index 9e43c47691ca..803a3bdea0af 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -583,7 +583,7 @@ static int ax_header(struct sk_buff *skb, struct net_device *dev, const void *saddr, unsigned len) { #ifdef CONFIG_INET - if (type != htons(ETH_P_AX25)) + if (type != ETH_P_AX25) return ax25_hard_header(skb, dev, type, daddr, saddr, len); #endif return 0; diff --git a/drivers/net/ibm_emac/ibm_emac_mal.c b/drivers/net/ibm_emac/ibm_emac_mal.c index 4e49e8c4f871..dcd8826fc749 100644 --- a/drivers/net/ibm_emac/ibm_emac_mal.c +++ b/drivers/net/ibm_emac/ibm_emac_mal.c @@ -413,7 +413,10 @@ static int __init mal_probe(struct ocp_device *ocpdev) ocpdev->def->index); return -ENOMEM; } - mal->dcrbase = maldata->dcr_base; + + /* XXX This only works for native dcr for now */ + mal->dcrhost = dcr_map(NULL, maldata->dcr_base, 0); + mal->def = ocpdev->def; INIT_LIST_HEAD(&mal->poll_list); diff --git a/drivers/net/ibm_emac/ibm_emac_mal.h b/drivers/net/ibm_emac/ibm_emac_mal.h index 8f54d621994d..b8adbe6d4b01 100644 --- a/drivers/net/ibm_emac/ibm_emac_mal.h +++ b/drivers/net/ibm_emac/ibm_emac_mal.h @@ -191,7 +191,6 @@ struct mal_commac { }; struct ibm_ocp_mal { - int dcrbase; dcr_host_t dcrhost; struct list_head poll_list; @@ -209,12 +208,12 @@ struct ibm_ocp_mal { static inline u32 get_mal_dcrn(struct ibm_ocp_mal *mal, int reg) { - return dcr_read(mal->dcrhost, mal->dcrbase + reg); + return dcr_read(mal->dcrhost, reg); } static inline void set_mal_dcrn(struct ibm_ocp_mal *mal, int reg, u32 val) { - dcr_write(mal->dcrhost, mal->dcrbase + reg, val); + dcr_write(mal->dcrhost, reg, val); } /* Register MAL devices */ diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index 8ea500961871..0de3aa2a2e44 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -1534,7 +1534,7 @@ static inline int emac_rx_sg_append(struct emac_instance *dev, int slot) dev_kfree_skb(dev->rx_sg_skb); dev->rx_sg_skb = NULL; } else { - cacheable_memcpy(dev->rx_sg_skb->tail, + cacheable_memcpy(skb_tail_pointer(dev->rx_sg_skb), dev->rx_skb[slot]->data, len); skb_put(dev->rx_sg_skb, len); emac_recycle_rx_skb(dev, slot, len); @@ -1950,7 +1950,7 @@ static u32 emac_ethtool_get_rx_csum(struct net_device *ndev) { struct emac_instance *dev = netdev_priv(ndev); - return dev->tah_dev != 0; + return dev->tah_dev != NULL; } static int emac_get_regs_len(struct emac_instance *dev) diff --git a/drivers/net/ibm_newemac/mal.c b/drivers/net/ibm_newemac/mal.c index 58854117b1a9..39f4cb6b0cf3 100644 --- a/drivers/net/ibm_newemac/mal.c +++ b/drivers/net/ibm_newemac/mal.c @@ -461,6 +461,7 @@ static int __devinit mal_probe(struct of_device *ofdev, struct mal_instance *mal; int err = 0, i, bd_size; int index = mal_count++; + unsigned int dcr_base; const u32 *prop; u32 cfg; @@ -497,14 +498,14 @@ static int __devinit mal_probe(struct of_device *ofdev, } mal->num_rx_chans = prop[0]; - mal->dcr_base = dcr_resource_start(ofdev->node, 0); - if (mal->dcr_base == 0) { + dcr_base = dcr_resource_start(ofdev->node, 0); + if (dcr_base == 0) { printk(KERN_ERR "mal%d: can't find DCR resource!\n", index); err = -ENODEV; goto fail; } - mal->dcr_host = dcr_map(ofdev->node, mal->dcr_base, 0x100); + mal->dcr_host = dcr_map(ofdev->node, dcr_base, 0x100); if (!DCR_MAP_OK(mal->dcr_host)) { printk(KERN_ERR "mal%d: failed to map DCRs !\n", index); @@ -626,7 +627,7 @@ static int __devinit mal_probe(struct of_device *ofdev, fail2: dma_free_coherent(&ofdev->dev, bd_size, mal->bd_virt, mal->bd_dma); fail_unmap: - dcr_unmap(mal->dcr_host, mal->dcr_base, 0x100); + dcr_unmap(mal->dcr_host, 0x100); fail: kfree(mal); diff --git a/drivers/net/ibm_newemac/mal.h b/drivers/net/ibm_newemac/mal.h index cb1a16d589fe..784edb8ea822 100644 --- a/drivers/net/ibm_newemac/mal.h +++ b/drivers/net/ibm_newemac/mal.h @@ -185,7 +185,6 @@ struct mal_commac { struct mal_instance { int version; - int dcr_base; dcr_host_t dcr_host; int num_tx_chans; /* Number of TX channels */ @@ -213,12 +212,12 @@ struct mal_instance { static inline u32 get_mal_dcrn(struct mal_instance *mal, int reg) { - return dcr_read(mal->dcr_host, mal->dcr_base + reg); + return dcr_read(mal->dcr_host, reg); } static inline void set_mal_dcrn(struct mal_instance *mal, int reg, u32 val) { - dcr_write(mal->dcr_host, mal->dcr_base + reg, val); + dcr_write(mal->dcr_host, reg, val); } /* Register MAL devices */ diff --git a/drivers/net/ibm_newemac/rgmii.c b/drivers/net/ibm_newemac/rgmii.c index bcd7fc639c40..de416951a435 100644 --- a/drivers/net/ibm_newemac/rgmii.c +++ b/drivers/net/ibm_newemac/rgmii.c @@ -84,7 +84,7 @@ static inline u32 rgmii_mode_mask(int mode, int input) int __devinit rgmii_attach(struct of_device *ofdev, int input, int mode) { struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev); - struct rgmii_regs *p = dev->base; + struct rgmii_regs __iomem *p = dev->base; RGMII_DBG(dev, "attach(%d)" NL, input); @@ -113,7 +113,7 @@ int __devinit rgmii_attach(struct of_device *ofdev, int input, int mode) void rgmii_set_speed(struct of_device *ofdev, int input, int speed) { struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev); - struct rgmii_regs *p = dev->base; + struct rgmii_regs __iomem *p = dev->base; u32 ssr; mutex_lock(&dev->lock); @@ -135,7 +135,7 @@ void rgmii_set_speed(struct of_device *ofdev, int input, int speed) void rgmii_get_mdio(struct of_device *ofdev, int input) { struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev); - struct rgmii_regs *p = dev->base; + struct rgmii_regs __iomem *p = dev->base; u32 fer; RGMII_DBG2(dev, "get_mdio(%d)" NL, input); @@ -156,7 +156,7 @@ void rgmii_get_mdio(struct of_device *ofdev, int input) void rgmii_put_mdio(struct of_device *ofdev, int input) { struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev); - struct rgmii_regs *p = dev->base; + struct rgmii_regs __iomem *p = dev->base; u32 fer; RGMII_DBG2(dev, "put_mdio(%d)" NL, input); @@ -177,7 +177,7 @@ void rgmii_put_mdio(struct of_device *ofdev, int input) void __devexit rgmii_detach(struct of_device *ofdev, int input) { struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev); - struct rgmii_regs *p = dev->base; + struct rgmii_regs __iomem *p = dev->base; mutex_lock(&dev->lock); @@ -242,7 +242,7 @@ static int __devinit rgmii_probe(struct of_device *ofdev, } rc = -ENOMEM; - dev->base = (struct rgmii_regs *)ioremap(regs.start, + dev->base = (struct rgmii_regs __iomem *)ioremap(regs.start, sizeof(struct rgmii_regs)); if (dev->base == NULL) { printk(KERN_ERR "%s: Can't map device registers!\n", @@ -251,7 +251,7 @@ static int __devinit rgmii_probe(struct of_device *ofdev, } /* Check for RGMII type */ - if (device_is_compatible(ofdev->node, "ibm,rgmii-axon")) + if (of_device_is_compatible(ofdev->node, "ibm,rgmii-axon")) dev->type = RGMII_AXON; else dev->type = RGMII_STANDARD; diff --git a/drivers/net/ibm_newemac/tah.c b/drivers/net/ibm_newemac/tah.c index e05c7e81efb6..f161fb100e8e 100644 --- a/drivers/net/ibm_newemac/tah.c +++ b/drivers/net/ibm_newemac/tah.c @@ -42,7 +42,7 @@ void __devexit tah_detach(struct of_device *ofdev, int channel) void tah_reset(struct of_device *ofdev) { struct tah_instance *dev = dev_get_drvdata(&ofdev->dev); - struct tah_regs *p = dev->base; + struct tah_regs __iomem *p = dev->base; int n; /* Reset TAH */ @@ -108,7 +108,7 @@ static int __devinit tah_probe(struct of_device *ofdev, } rc = -ENOMEM; - dev->base = (struct tah_regs *)ioremap(regs.start, + dev->base = (struct tah_regs __iomem *)ioremap(regs.start, sizeof(struct tah_regs)); if (dev->base == NULL) { printk(KERN_ERR "%s: Can't map device registers!\n", diff --git a/drivers/net/ibm_newemac/zmii.c b/drivers/net/ibm_newemac/zmii.c index d06312901848..2219ec2740e0 100644 --- a/drivers/net/ibm_newemac/zmii.c +++ b/drivers/net/ibm_newemac/zmii.c @@ -79,7 +79,7 @@ static inline u32 zmii_mode_mask(int mode, int input) int __devinit zmii_attach(struct of_device *ofdev, int input, int *mode) { struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev); - struct zmii_regs *p = dev->base; + struct zmii_regs __iomem *p = dev->base; ZMII_DBG(dev, "init(%d, %d)" NL, input, *mode); @@ -250,7 +250,7 @@ static int __devinit zmii_probe(struct of_device *ofdev, } rc = -ENOMEM; - dev->base = (struct zmii_regs *)ioremap(regs.start, + dev->base = (struct zmii_regs __iomem *)ioremap(regs.start, sizeof(struct zmii_regs)); if (dev->base == NULL) { printk(KERN_ERR "%s: Can't map device registers!\n", diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 4ac161e1ca12..7d7758f3ad8c 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -1183,7 +1183,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ pool_count[i], pool_size[i], pool_active[i]); kobj->parent = &dev->dev.kobj; - sprintf(kobj->name, "pool%d", i); + kobject_set_name(kobj, "pool%d", i); kobj->ktype = &ktype_veth_pool; kobject_register(kobj); } diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c index 59898ce54dcf..68887235d7e9 100644 --- a/drivers/net/ipg.c +++ b/drivers/net/ipg.c @@ -754,7 +754,7 @@ static int init_rfdlist(struct net_device *dev) if (sp->RxBuff[i]) { pci_unmap_single(sp->pdev, - le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN), + le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN, sp->rx_buf_sz, PCI_DMA_FROMDEVICE); IPG_DEV_KFREE_SKB(sp->RxBuff[i]); sp->RxBuff[i] = NULL; @@ -871,7 +871,7 @@ static void ipg_nic_txfree(struct net_device *dev) /* Free the transmit buffer. */ if (skb) { pci_unmap_single(sp->pdev, - le64_to_cpu(txfd->frag_info & ~IPG_TFI_FRAGLEN), + le64_to_cpu(txfd->frag_info) & ~IPG_TFI_FRAGLEN, skb->len, PCI_DMA_TODEVICE); IPG_DEV_KFREE_SKB(skb); @@ -1413,10 +1413,10 @@ static int ipg_nic_rx(struct net_device *dev) framelen = IPG_RXFRAG_SIZE; } - if ((IPG_DROP_ON_RX_ETH_ERRORS && (le64_to_cpu(rxfd->rfs & + if ((IPG_DROP_ON_RX_ETH_ERRORS && (le64_to_cpu(rxfd->rfs) & (IPG_RFS_RXFIFOOVERRUN | IPG_RFS_RXRUNTFRAME | IPG_RFS_RXALIGNMENTERROR | IPG_RFS_RXFCSERROR | - IPG_RFS_RXOVERSIZEDFRAME | IPG_RFS_RXLENGTHERROR))))) { + IPG_RFS_RXOVERSIZEDFRAME | IPG_RFS_RXLENGTHERROR)))) { IPG_DEBUG_MSG("Rx error, RFS = %16.16lx\n", (unsigned long int) rxfd->rfs); @@ -1425,27 +1425,27 @@ static int ipg_nic_rx(struct net_device *dev) sp->stats.rx_errors++; /* Increment detailed receive error statistics. */ - if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXFIFOOVERRUN)) { + if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFIFOOVERRUN) { IPG_DEBUG_MSG("RX FIFO overrun occured.\n"); sp->stats.rx_fifo_errors++; } - if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXRUNTFRAME)) { + if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXRUNTFRAME) { IPG_DEBUG_MSG("RX runt occured.\n"); sp->stats.rx_length_errors++; } - if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXOVERSIZEDFRAME)) ; + if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXOVERSIZEDFRAME) ; /* Do nothing, error count handled by a IPG * statistic register. */ - if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXALIGNMENTERROR)) { + if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXALIGNMENTERROR) { IPG_DEBUG_MSG("RX alignment error occured.\n"); sp->stats.rx_frame_errors++; } - if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXFCSERROR)) ; + if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFCSERROR) ; /* Do nothing, error count handled by a IPG * statistic register. */ @@ -1455,10 +1455,10 @@ static int ipg_nic_rx(struct net_device *dev) * not pass it to higher layer processes. */ if (skb) { - u64 info = rxfd->frag_info; + __le64 info = rxfd->frag_info; pci_unmap_single(sp->pdev, - le64_to_cpu(info & ~IPG_RFI_FRAGLEN), + le64_to_cpu(info) & ~IPG_RFI_FRAGLEN, sp->rx_buf_sz, PCI_DMA_FROMDEVICE); IPG_DEV_KFREE_SKB(skb); @@ -1532,9 +1532,9 @@ static int ipg_nic_rx(struct net_device *dev) if (!i) sp->EmptyRFDListCount++; #endif - while ((le64_to_cpu(rxfd->rfs & IPG_RFS_RFDDONE)) && - !((le64_to_cpu(rxfd->rfs & IPG_RFS_FRAMESTART)) && - (le64_to_cpu(rxfd->rfs & IPG_RFS_FRAMEEND)))) { + while ((le64_to_cpu(rxfd->rfs) & IPG_RFS_RFDDONE) && + !((le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMESTART) && + (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMEEND))) { unsigned int entry = curr++ % IPG_RFDLIST_LENGTH; rxfd = sp->rxd + entry; @@ -1552,7 +1552,7 @@ static int ipg_nic_rx(struct net_device *dev) */ if (sp->RxBuff[entry]) { pci_unmap_single(sp->pdev, - le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN), + le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN, sp->rx_buf_sz, PCI_DMA_FROMDEVICE); IPG_DEV_KFREE_SKB(sp->RxBuff[entry]); } @@ -1730,7 +1730,7 @@ static void ipg_rx_clear(struct ipg_nic_private *sp) IPG_DEV_KFREE_SKB(sp->RxBuff[i]); sp->RxBuff[i] = NULL; pci_unmap_single(sp->pdev, - le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN), + le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN, sp->rx_buf_sz, PCI_DMA_FROMDEVICE); } } @@ -1745,7 +1745,7 @@ static void ipg_tx_clear(struct ipg_nic_private *sp) struct ipg_tx *txfd = sp->txd + i; pci_unmap_single(sp->pdev, - le64_to_cpu(txfd->frag_info & ~IPG_TFI_FRAGLEN), + le64_to_cpu(txfd->frag_info) & ~IPG_TFI_FRAGLEN, sp->TxBuff[i]->len, PCI_DMA_TODEVICE); IPG_DEV_KFREE_SKB(sp->TxBuff[i]); diff --git a/drivers/net/ipg.h b/drivers/net/ipg.h index 1952d0dfd314..e418b9035cac 100644 --- a/drivers/net/ipg.h +++ b/drivers/net/ipg.h @@ -776,17 +776,17 @@ enum ipg_regs { * TFD field is 64 bits wide. */ struct ipg_tx { - u64 next_desc; - u64 tfc; - u64 frag_info; + __le64 next_desc; + __le64 tfc; + __le64 frag_info; }; /* Receive Frame Descriptor. Note, each RFD field is 64 bits wide. */ struct ipg_rx { - u64 next_desc; - u64 rfs; - u64 frag_info; + __le64 next_desc; + __le64 rfs; + __le64 frag_info; }; struct SJumbo { diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c index 3e5eca1aa987..a82d8f98383d 100644 --- a/drivers/net/irda/donauboe.c +++ b/drivers/net/irda/donauboe.c @@ -840,7 +840,7 @@ toshoboe_probe (struct toshoboe_cb *self) /* test 1: SIR filter and back to back */ - for (j = 0; j < (sizeof (bauds) / sizeof (int)); ++j) + for (j = 0; j < ARRAY_SIZE(bauds); ++j) { int fir = (j > 1); toshoboe_stopchip (self); diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c index d3825c8ee994..5c154fe13859 100644 --- a/drivers/net/jazzsonic.c +++ b/drivers/net/jazzsonic.c @@ -208,7 +208,6 @@ static int __init jazz_sonic_probe(struct platform_device *pdev) struct sonic_local *lp; struct resource *res; int err = 0; - int i; DECLARE_MAC_BUF(mac); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index be25aa33971c..662b8d16803c 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -265,17 +265,16 @@ static __net_init int loopback_net_init(struct net *net) if (err) goto out_free_netdev; - err = 0; net->loopback_dev = dev; + return 0; -out: - if (err) - panic("loopback: Failed to register netdevice: %d\n", err); - return err; out_free_netdev: free_netdev(dev); - goto out; +out: + if (net == &init_net) + panic("loopback: Failed to register netdevice: %d\n", err); + return err; } static __net_exit void loopback_net_exit(struct net *net) diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c index 6589239b79ee..18770527df99 100644 --- a/drivers/net/macmace.c +++ b/drivers/net/macmace.c @@ -538,8 +538,9 @@ static void mace_set_multicast(struct net_device *dev) local_irq_restore(flags); } -static void mace_handle_misc_intrs(struct mace_data *mp, int intr) +static void mace_handle_misc_intrs(struct net_device *dev, int intr) { + struct mace_data *mp = netdev_priv(dev); volatile struct mace *mb = mp->mace; static int mace_babbles, mace_jabbers; @@ -571,7 +572,7 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id) local_irq_save(flags); intr = mb->ir; /* read interrupt register */ - mace_handle_misc_intrs(mp, intr); + mace_handle_misc_intrs(dev, intr); if (intr & XMTINT) { fs = mb->xmtfs; @@ -645,7 +646,6 @@ static void mace_tx_timeout(struct net_device *dev) static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf) { - struct mace_data *mp = netdev_priv(dev); struct sk_buff *skb; unsigned int frame_status = mf->rcvsts; diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index b7c81c874f7a..2e4bcd5654c4 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -178,7 +178,6 @@ static const struct header_ops macvlan_hard_header_ops = { .create = macvlan_hard_header, .rebuild = eth_rebuild_header, .parse = eth_header_parse, - .rebuild = eth_rebuild_header, .cache = eth_header_cache, .cache_update = eth_header_cache_update, }; diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c index d593175ab6f0..37707a0c0498 100644 --- a/drivers/net/mipsnet.c +++ b/drivers/net/mipsnet.c @@ -7,12 +7,12 @@ #define DEBUG #include <linux/init.h> +#include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/platform_device.h> -#include <asm/io.h> #include <asm/mips-boards/simint.h> #include "mipsnet.h" /* actual device IO mapping */ @@ -33,9 +33,8 @@ static int ioiocpy_frommipsnet(struct net_device *dev, unsigned char *kdata, if (available_len < len) return -EFAULT; - for (; len > 0; len--, kdata++) { + for (; len > 0; len--, kdata++) *kdata = inb(mipsnet_reg_address(dev, rxDataBuffer)); - } return inl(mipsnet_reg_address(dev, rxDataCount)); } @@ -47,16 +46,15 @@ static inline ssize_t mipsnet_put_todevice(struct net_device *dev, char *buf_ptr = skb->data; pr_debug("%s: %s(): telling MIPSNET txDataCount(%d)\n", - dev->name, __FUNCTION__, skb->len); + dev->name, __FUNCTION__, skb->len); outl(skb->len, mipsnet_reg_address(dev, txDataCount)); pr_debug("%s: %s(): sending data to MIPSNET txDataBuffer(%d)\n", - dev->name, __FUNCTION__, skb->len); + dev->name, __FUNCTION__, skb->len); - for (; count_to_go; buf_ptr++, count_to_go--) { + for (; count_to_go; buf_ptr++, count_to_go--) outb(*buf_ptr, mipsnet_reg_address(dev, txDataBuffer)); - } dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; @@ -67,7 +65,7 @@ static inline ssize_t mipsnet_put_todevice(struct net_device *dev, static int mipsnet_xmit(struct sk_buff *skb, struct net_device *dev) { pr_debug("%s:%s(): transmitting %d bytes\n", - dev->name, __FUNCTION__, skb->len); + dev->name, __FUNCTION__, skb->len); /* Only one packet at a time. Once TXDONE interrupt is serviced, the * queue will be restarted. @@ -83,7 +81,8 @@ static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t count) struct sk_buff *skb; size_t len = count; - if (!(skb = alloc_skb(len + 2, GFP_KERNEL))) { + skb = alloc_skb(len + 2, GFP_KERNEL); + if (!skb) { dev->stats.rx_dropped++; return -ENOMEM; } @@ -96,7 +95,7 @@ static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t count) skb->ip_summed = CHECKSUM_UNNECESSARY; pr_debug("%s:%s(): pushing RXed data to kernel\n", - dev->name, __FUNCTION__); + dev->name, __FUNCTION__); netif_rx(skb); dev->stats.rx_packets++; @@ -114,42 +113,44 @@ static irqreturn_t mipsnet_interrupt(int irq, void *dev_id) if (irq == dev->irq) { pr_debug("%s:%s(): irq %d for device\n", - dev->name, __FUNCTION__, irq); + dev->name, __FUNCTION__, irq); retval = IRQ_HANDLED; interruptFlags = inl(mipsnet_reg_address(dev, interruptControl)); pr_debug("%s:%s(): intCtl=0x%016llx\n", dev->name, - __FUNCTION__, interruptFlags); + __FUNCTION__, interruptFlags); if (interruptFlags & MIPSNET_INTCTL_TXDONE) { pr_debug("%s:%s(): got TXDone\n", - dev->name, __FUNCTION__); + dev->name, __FUNCTION__); outl(MIPSNET_INTCTL_TXDONE, mipsnet_reg_address(dev, interruptControl)); - // only one packet at a time, we are done. + /* only one packet at a time, we are done. */ netif_wake_queue(dev); } else if (interruptFlags & MIPSNET_INTCTL_RXDONE) { pr_debug("%s:%s(): got RX data\n", - dev->name, __FUNCTION__); + dev->name, __FUNCTION__); mipsnet_get_fromdev(dev, - inl(mipsnet_reg_address(dev, rxDataCount))); + inl(mipsnet_reg_address(dev, rxDataCount))); pr_debug("%s:%s(): clearing RX int\n", - dev->name, __FUNCTION__); + dev->name, __FUNCTION__); outl(MIPSNET_INTCTL_RXDONE, mipsnet_reg_address(dev, interruptControl)); } else if (interruptFlags & MIPSNET_INTCTL_TESTBIT) { pr_debug("%s:%s(): got test interrupt\n", - dev->name, __FUNCTION__); - // TESTBIT is cleared on read. - // And takes effect after a write with 0 + dev->name, __FUNCTION__); + /* + * TESTBIT is cleared on read. + * And takes effect after a write with 0 + */ outl(0, mipsnet_reg_address(dev, interruptControl)); } else { pr_debug("%s:%s(): no valid fags 0x%016llx\n", - dev->name, __FUNCTION__, interruptFlags); - // Maybe shared IRQ, just ignore, no clearing. + dev->name, __FUNCTION__, interruptFlags); + /* Maybe shared IRQ, just ignore, no clearing. */ retval = IRQ_NONE; } @@ -159,7 +160,7 @@ static irqreturn_t mipsnet_interrupt(int irq, void *dev_id) retval = IRQ_NONE; } return retval; -} //mipsnet_interrupt() +} static int mipsnet_open(struct net_device *dev) { @@ -171,18 +172,18 @@ static int mipsnet_open(struct net_device *dev) if (err) { pr_debug("%s: %s(): can't get irq %d\n", - dev->name, __FUNCTION__, dev->irq); + dev->name, __FUNCTION__, dev->irq); release_region(dev->base_addr, MIPSNET_IO_EXTENT); return err; } pr_debug("%s: %s(): got IO region at 0x%04lx and irq %d for dev.\n", - dev->name, __FUNCTION__, dev->base_addr, dev->irq); + dev->name, __FUNCTION__, dev->base_addr, dev->irq); netif_start_queue(dev); - // test interrupt handler + /* test interrupt handler */ outl(MIPSNET_INTCTL_TESTBIT, mipsnet_reg_address(dev, interruptControl)); @@ -199,8 +200,6 @@ static int mipsnet_close(struct net_device *dev) static void mipsnet_set_mclist(struct net_device *dev) { - // we don't do anything - return; } static int __init mipsnet_probe(struct device *dev) @@ -226,13 +225,13 @@ static int __init mipsnet_probe(struct device *dev) */ netdev->base_addr = 0x4200; netdev->irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_MB0 + - inl(mipsnet_reg_address(netdev, interruptInfo)); + inl(mipsnet_reg_address(netdev, interruptInfo)); - // Get the io region now, get irq on open() + /* Get the io region now, get irq on open() */ if (!request_region(netdev->base_addr, MIPSNET_IO_EXTENT, "mipsnet")) { pr_debug("%s: %s(): IO region {start: 0x%04lux, len: %d} " - "for dev is not availble.\n", netdev->name, - __FUNCTION__, netdev->base_addr, MIPSNET_IO_EXTENT); + "for dev is not availble.\n", netdev->name, + __FUNCTION__, netdev->base_addr, MIPSNET_IO_EXTENT); err = -EBUSY; goto out_free_netdev; } diff --git a/drivers/net/mipsnet.h b/drivers/net/mipsnet.h index 026c732024c9..0132c6714a40 100644 --- a/drivers/net/mipsnet.h +++ b/drivers/net/mipsnet.h @@ -9,32 +9,34 @@ /* * Id of this Net device, as seen by the core. */ -#define MIPS_NET_DEV_ID ((uint64_t) \ - ((uint64_t)'M'<< 0)| \ - ((uint64_t)'I'<< 8)| \ - ((uint64_t)'P'<<16)| \ - ((uint64_t)'S'<<24)| \ - ((uint64_t)'N'<<32)| \ - ((uint64_t)'E'<<40)| \ - ((uint64_t)'T'<<48)| \ - ((uint64_t)'0'<<56)) +#define MIPS_NET_DEV_ID ((uint64_t) \ + ((uint64_t) 'M' << 0)| \ + ((uint64_t) 'I' << 8)| \ + ((uint64_t) 'P' << 16)| \ + ((uint64_t) 'S' << 24)| \ + ((uint64_t) 'N' << 32)| \ + ((uint64_t) 'E' << 40)| \ + ((uint64_t) 'T' << 48)| \ + ((uint64_t) '0' << 56)) /* * Net status/control block as seen by sw in the core. * (Why not use bit fields? can't be bothered with cross-platform struct * packing.) */ -typedef struct _net_control_block { - /// dev info for probing - /// reads as MIPSNET%d where %d is some form of version - uint64_t devId; /*0x00 */ +struct net_control_block { + /* + * dev info for probing + * reads as MIPSNET%d where %d is some form of version + */ + uint64_t devId; /* 0x00 */ /* * read only busy flag. * Set and cleared by the Net Device to indicate that an rx or a tx * is in progress. */ - uint32_t busy; /*0x08 */ + uint32_t busy; /* 0x08 */ /* * Set by the Net Device. @@ -43,16 +45,16 @@ typedef struct _net_control_block { * rxDataBuffer. The value will decrease till 0 until all the data * from rxDataBuffer has been read. */ - uint32_t rxDataCount; /*0x0c */ + uint32_t rxDataCount; /* 0x0c */ #define MIPSNET_MAX_RXTX_DATACOUNT (1<<16) /* - * Settable from the MIPS core, cleared by the Net Device. - * The core should set the number of bytes it wants to send, - * then it should write those bytes of data to txDataBuffer. - * The device will clear txDataCount has been processed (not necessarily sent). + * Settable from the MIPS core, cleared by the Net Device. The core + * should set the number of bytes it wants to send, then it should + * write those bytes of data to txDataBuffer. The device will clear + * txDataCount has been processed (not necessarily sent). */ - uint32_t txDataCount; /*0x10 */ + uint32_t txDataCount; /* 0x10 */ /* * Interrupt control @@ -69,39 +71,42 @@ typedef struct _net_control_block { * To clear the test interrupt, write 0 to this register. */ uint32_t interruptControl; /*0x14 */ -#define MIPSNET_INTCTL_TXDONE ((uint32_t)(1<< 0)) -#define MIPSNET_INTCTL_RXDONE ((uint32_t)(1<< 1)) -#define MIPSNET_INTCTL_TESTBIT ((uint32_t)(1<<31)) -#define MIPSNET_INTCTL_ALLSOURCES (MIPSNET_INTCTL_TXDONE|MIPSNET_INTCTL_RXDONE|MIPSNET_INTCTL_TESTBIT) +#define MIPSNET_INTCTL_TXDONE ((uint32_t)(1 << 0)) +#define MIPSNET_INTCTL_RXDONE ((uint32_t)(1 << 1)) +#define MIPSNET_INTCTL_TESTBIT ((uint32_t)(1 << 31)) +#define MIPSNET_INTCTL_ALLSOURCES (MIPSNET_INTCTL_TXDONE | \ + MIPSNET_INTCTL_RXDONE | \ + MIPSNET_INTCTL_TESTBIT) /* - * Readonly core-specific interrupt info for the device to signal the core. - * The meaning of the contents of this field might change. - */ - /*###\todo: the whole memIntf interrupt scheme is messy: the device should have - * no control what so ever of what VPE/register set is being used. - * The MemIntf should only expose interrupt lines, and something in the - * config should be responsible for the line<->core/vpe bindings. + * Readonly core-specific interrupt info for the device to signal the + * core. The meaning of the contents of this field might change. + * + * TODO: the whole memIntf interrupt scheme is messy: the device should + * have no control what so ever of what VPE/register set is being + * used. The MemIntf should only expose interrupt lines, and + * something in the config should be responsible for the + * line<->core/vpe bindings. */ - uint32_t interruptInfo; /*0x18 */ + uint32_t interruptInfo; /* 0x18 */ /* * This is where the received data is read out. * There is more data to read until rxDataReady is 0. * Only 1 byte at this regs offset is used. */ - uint32_t rxDataBuffer; /*0x1c */ + uint32_t rxDataBuffer; /* 0x1c */ /* - * This is where the data to transmit is written. - * Data should be written for the amount specified in the txDataCount register. - * Only 1 byte at this regs offset is used. + * This is where the data to transmit is written. Data should be + * written for the amount specified in the txDataCount register. Only + * 1 byte at this regs offset is used. */ - uint32_t txDataBuffer; /*0x20 */ -} MIPS_T_NetControl; + uint32_t txDataBuffer; /* 0x20 */ +}; #define MIPSNET_IO_EXTENT 0x40 /* being generous */ -#define field_offset(field) ((int)&((MIPS_T_NetControl*)(0))->field) +#define field_offset(field) (offsetof(struct net_control_block, field)) #endif /* __MIPSNET_H */ diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index e029b8afbd37..89b3f0b7cdc0 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -884,7 +884,7 @@ static int __devinit mlx4_init_one(struct pci_dev *pdev, ++mlx4_version_printed; } - return mlx4_init_one(pdev, id); + return __mlx4_init_one(pdev, id); } static void mlx4_remove_one(struct pci_dev *pdev) diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index b33d21f4efff..84f2d6382f1e 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -784,7 +784,6 @@ static int mv643xx_eth_open(struct net_device *dev) unsigned int port_num = mp->port_num; unsigned int size; int err; - DECLARE_MAC_BUF(mac); /* Clear any pending ethernet port interrupts */ mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0); @@ -1296,6 +1295,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev) struct ethtool_cmd cmd; int duplex = DUPLEX_HALF; int speed = 0; /* default to auto-negotiation */ + DECLARE_MAC_BUF(mac); pd = pdev->dev.platform_data; if (pd == NULL) { diff --git a/drivers/net/mvme147.c b/drivers/net/mvme147.c index 86c9c06433cb..06ca4252155f 100644 --- a/drivers/net/mvme147.c +++ b/drivers/net/mvme147.c @@ -85,7 +85,6 @@ struct net_device * __init mvme147lance_probe(int unit) dev->open = &m147lance_open; dev->stop = &m147lance_close; dev->hard_start_xmit = &lance_start_xmit; - dev->get_stats = &lance_get_stats; dev->set_multicast_list = &lance_set_multicast; dev->tx_timeout = &lance_tx_timeout; dev->dma = 0; diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index e8afa101433e..64c8151f2004 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -75,7 +75,7 @@ #include "myri10ge_mcp.h" #include "myri10ge_mcp_gen_header.h" -#define MYRI10GE_VERSION_STR "1.3.2-1.269" +#define MYRI10GE_VERSION_STR "1.3.2-1.287" MODULE_DESCRIPTION("Myricom 10G driver (10GbE)"); MODULE_AUTHOR("Maintainer: help@myri.com"); @@ -214,6 +214,8 @@ struct myri10ge_priv { unsigned long serial_number; int vendor_specific_offset; int fw_multicast_support; + unsigned long features; + u32 max_tso6; u32 read_dma; u32 write_dma; u32 read_write_dma; @@ -311,6 +313,7 @@ MODULE_PARM_DESC(myri10ge_wcfifo, "Enable WC Fifo when WC is enabled\n"); #define myri10ge_pio_copy(to,from,size) __iowrite64_copy(to,from,size/8) static void myri10ge_set_multicast_list(struct net_device *dev); +static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev); static inline void put_be32(__be32 val, __be32 __iomem * p) { @@ -612,6 +615,7 @@ static int myri10ge_load_firmware(struct myri10ge_priv *mgp) __be32 buf[16]; u32 dma_low, dma_high, size; int status, i; + struct myri10ge_cmd cmd; size = 0; status = myri10ge_load_hotplug_firmware(mgp, &size); @@ -688,6 +692,14 @@ static int myri10ge_load_firmware(struct myri10ge_priv *mgp) dev_info(&mgp->pdev->dev, "handoff confirmed\n"); myri10ge_dummy_rdma(mgp, 1); + /* probe for IPv6 TSO support */ + mgp->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO; + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_MAX_TSO6_HDR_SIZE, + &cmd, 0); + if (status == 0) { + mgp->max_tso6 = cmd.data0; + mgp->features |= NETIF_F_TSO6; + } return 0; } @@ -1047,7 +1059,8 @@ myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx, hlen = MYRI10GE_HLEN > len ? len : MYRI10GE_HLEN; - /* allocate an skb to attach the page(s) to. */ + /* allocate an skb to attach the page(s) to. This is done + * after trying LRO, so as to avoid skb allocation overheads */ skb = netdev_alloc_skb(dev, MYRI10GE_HLEN + 16); if (unlikely(skb == NULL)) { @@ -1217,7 +1230,8 @@ static inline void myri10ge_check_statblock(struct myri10ge_priv *mgp) static int myri10ge_poll(struct napi_struct *napi, int budget) { - struct myri10ge_priv *mgp = container_of(napi, struct myri10ge_priv, napi); + struct myri10ge_priv *mgp = + container_of(napi, struct myri10ge_priv, napi); struct net_device *netdev = mgp->dev; struct myri10ge_rx_done *rx_done = &mgp->rx_done; int work_done; @@ -1382,6 +1396,18 @@ static int myri10ge_set_rx_csum(struct net_device *netdev, u32 csum_enabled) return 0; } +static int myri10ge_set_tso(struct net_device *netdev, u32 tso_enabled) +{ + struct myri10ge_priv *mgp = netdev_priv(netdev); + unsigned long flags = mgp->features & (NETIF_F_TSO6 | NETIF_F_TSO); + + if (tso_enabled) + netdev->features |= flags; + else + netdev->features &= ~flags; + return 0; +} + static const char myri10ge_gstrings_stats[][ETH_GSTRING_LEN] = { "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors", "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions", @@ -1506,7 +1532,7 @@ static const struct ethtool_ops myri10ge_ethtool_ops = { .set_rx_csum = myri10ge_set_rx_csum, .set_tx_csum = ethtool_op_set_tx_hw_csum, .set_sg = ethtool_op_set_sg, - .set_tso = ethtool_op_set_tso, + .set_tso = myri10ge_set_tso, .get_link = ethtool_op_get_link, .get_strings = myri10ge_get_strings, .get_sset_count = myri10ge_get_sset_count, @@ -2164,7 +2190,8 @@ again: pseudo_hdr_offset = cksum_offset + skb->csum_offset; /* If the headers are excessively large, then we must * fall back to a software checksum */ - if (unlikely(cksum_offset > 255 || pseudo_hdr_offset > 127)) { + if (unlikely(!mss && (cksum_offset > 255 || + pseudo_hdr_offset > 127))) { if (skb_checksum_help(skb)) goto drop; cksum_offset = 0; @@ -2184,9 +2211,18 @@ again: /* negative cum_len signifies to the * send loop that we are still in the * header portion of the TSO packet. - * TSO header must be at most 134 bytes long */ + * TSO header can be at most 1KB long */ cum_len = -(skb_transport_offset(skb) + tcp_hdrlen(skb)); + /* for IPv6 TSO, the checksum offset stores the + * TCP header length, to save the firmware from + * the need to parse the headers */ + if (skb_is_gso_v6(skb)) { + cksum_offset = tcp_hdrlen(skb); + /* Can only handle headers <= max_tso6 long */ + if (unlikely(-cum_len > mgp->max_tso6)) + return myri10ge_sw_tso(skb, dev); + } /* for TSO, pseudo_hdr_offset holds mss. * The firmware figures out where to put * the checksum by parsing the header. */ @@ -2301,10 +2337,12 @@ again: req++; count++; rdma_count++; - if (unlikely(cksum_offset > seglen)) - cksum_offset -= seglen; - else - cksum_offset = 0; + if (cksum_offset != 0 && !(mss && skb_is_gso_v6(skb))) { + if (unlikely(cksum_offset > seglen)) + cksum_offset -= seglen; + else + cksum_offset = 0; + } } if (frag_idx == frag_cnt) break; @@ -2387,6 +2425,41 @@ drop: } +static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev) +{ + struct sk_buff *segs, *curr; + struct myri10ge_priv *mgp = dev->priv; + int status; + + segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO6); + if (unlikely(IS_ERR(segs))) + goto drop; + + while (segs) { + curr = segs; + segs = segs->next; + curr->next = NULL; + status = myri10ge_xmit(curr, dev); + if (status != 0) { + dev_kfree_skb_any(curr); + if (segs != NULL) { + curr = segs; + segs = segs->next; + curr->next = NULL; + dev_kfree_skb_any(segs); + } + goto drop; + } + } + dev_kfree_skb_any(skb); + return 0; + +drop: + dev_kfree_skb_any(skb); + mgp->stats.tx_dropped += 1; + return 0; +} + static struct net_device_stats *myri10ge_get_stats(struct net_device *dev) { struct myri10ge_priv *mgp = netdev_priv(dev); @@ -2706,7 +2779,6 @@ static void myri10ge_select_firmware(struct myri10ge_priv *mgp) } #ifdef CONFIG_PM - static int myri10ge_suspend(struct pci_dev *pdev, pm_message_t state) { struct myri10ge_priv *mgp; @@ -2787,7 +2859,6 @@ abort_with_enabled: return -EIO; } - #endif /* CONFIG_PM */ static u32 myri10ge_read_reboot(struct myri10ge_priv *mgp) @@ -2954,8 +3025,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) mgp = netdev_priv(netdev); mgp->dev = netdev; - netif_napi_add(netdev, &mgp->napi, - myri10ge_poll, myri10ge_napi_weight); + netif_napi_add(netdev, &mgp->napi, myri10ge_poll, myri10ge_napi_weight); mgp->pdev = pdev; mgp->csum_flag = MXGEFW_FLAGS_CKSUM; mgp->pause = myri10ge_flow_control; @@ -3077,7 +3147,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->change_mtu = myri10ge_change_mtu; netdev->set_multicast_list = myri10ge_set_multicast_list; netdev->set_mac_address = myri10ge_set_mac_address; - netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO; + netdev->features = mgp->features; if (dac_enabled) netdev->features |= NETIF_F_HIGHDMA; diff --git a/drivers/net/myri10ge/myri10ge_mcp.h b/drivers/net/myri10ge/myri10ge_mcp.h index a1d2a22296a9..58e57178c563 100644 --- a/drivers/net/myri10ge/myri10ge_mcp.h +++ b/drivers/net/myri10ge/myri10ge_mcp.h @@ -10,7 +10,7 @@ struct mcp_dma_addr { __be32 low; }; -/* 4 Bytes */ +/* 4 Bytes. 8 Bytes for NDIS drivers. */ struct mcp_slot { __sum16 checksum; __be16 length; @@ -205,8 +205,87 @@ enum myri10ge_mcp_cmd_type { /* same than DMA_TEST (same args) but abort with UNALIGNED on unaligned * chipset */ - MXGEFW_CMD_UNALIGNED_STATUS - /* return data = boolean, true if the chipset is known to be unaligned */ + MXGEFW_CMD_UNALIGNED_STATUS, + /* return data = boolean, true if the chipset is known to be unaligned */ + + MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS, + /* data0 = number of big buffers to use. It must be 0 or a power of 2. + * 0 indicates that the NIC consumes as many buffers as they are required + * for packet. This is the default behavior. + * A power of 2 number indicates that the NIC always uses the specified + * number of buffers for each big receive packet. + * It is up to the driver to ensure that this value is big enough for + * the NIC to be able to receive maximum-sized packets. + */ + + MXGEFW_CMD_GET_MAX_RSS_QUEUES, + MXGEFW_CMD_ENABLE_RSS_QUEUES, + /* data0 = number of slices n (0, 1, ..., n-1) to enable + * data1 = interrupt mode. 0=share one INTx/MSI, 1=use one MSI-X per queue. + * If all queues share one interrupt, the driver must have set + * RSS_SHARED_INTERRUPT_DMA before enabling queues. + */ + MXGEFW_CMD_GET_RSS_SHARED_INTERRUPT_MASK_OFFSET, + MXGEFW_CMD_SET_RSS_SHARED_INTERRUPT_DMA, + /* data0, data1 = bus address lsw, msw */ + MXGEFW_CMD_GET_RSS_TABLE_OFFSET, + /* get the offset of the indirection table */ + MXGEFW_CMD_SET_RSS_TABLE_SIZE, + /* set the size of the indirection table */ + MXGEFW_CMD_GET_RSS_KEY_OFFSET, + /* get the offset of the secret key */ + MXGEFW_CMD_RSS_KEY_UPDATED, + /* tell nic that the secret key's been updated */ + MXGEFW_CMD_SET_RSS_ENABLE, + /* data0 = enable/disable rss + * 0: disable rss. nic does not distribute receive packets. + * 1: enable rss. nic distributes receive packets among queues. + * data1 = hash type + * 1: IPV4 + * 2: TCP_IPV4 + * 3: IPV4 | TCP_IPV4 + */ + + MXGEFW_CMD_GET_MAX_TSO6_HDR_SIZE, + /* Return data = the max. size of the entire headers of a IPv6 TSO packet. + * If the header size of a IPv6 TSO packet is larger than the specified + * value, then the driver must not use TSO. + * This size restriction only applies to IPv6 TSO. + * For IPv4 TSO, the maximum size of the headers is fixed, and the NIC + * always has enough header buffer to store maximum-sized headers. + */ + + MXGEFW_CMD_SET_TSO_MODE, + /* data0 = TSO mode. + * 0: Linux/FreeBSD style (NIC default) + * 1: NDIS/NetBSD style + */ + + MXGEFW_CMD_MDIO_READ, + /* data0 = dev_addr (PMA/PMD or PCS ...), data1 = register/addr */ + MXGEFW_CMD_MDIO_WRITE, + /* data0 = dev_addr, data1 = register/addr, data2 = value */ + + MXGEFW_CMD_XFP_I2C_READ, + /* Starts to get a fresh copy of one byte or of the whole xfp i2c table, the + * obtained data is cached inside the xaui-xfi chip : + * data0 : "all" flag : 0 => get one byte, 1=> get 256 bytes, + * data1 : if (data0 == 0): index of byte to refresh [ not used otherwise ] + * The operation might take ~1ms for a single byte or ~65ms when refreshing all 256 bytes + * During the i2c operation, MXGEFW_CMD_XFP_I2C_READ or MXGEFW_CMD_XFP_BYTE attempts + * will return MXGEFW_CMD_ERROR_BUSY + */ + MXGEFW_CMD_XFP_BYTE, + /* Return the last obtained copy of a given byte in the xfp i2c table + * (copy cached during the last relevant MXGEFW_CMD_XFP_I2C_READ) + * data0 : index of the desired table entry + * Return data = the byte stored at the requested index in the table + */ + + MXGEFW_CMD_GET_VPUMP_OFFSET, + /* Return data = NIC memory offset of mcp_vpump_public_global */ + MXGEFW_CMD_RESET_VPUMP, + /* Resets the VPUMP state */ }; enum myri10ge_mcp_cmd_status { @@ -220,7 +299,10 @@ enum myri10ge_mcp_cmd_status { MXGEFW_CMD_ERROR_BAD_PORT, MXGEFW_CMD_ERROR_RESOURCES, MXGEFW_CMD_ERROR_MULTICAST, - MXGEFW_CMD_ERROR_UNALIGNED + MXGEFW_CMD_ERROR_UNALIGNED, + MXGEFW_CMD_ERROR_NO_MDIO, + MXGEFW_CMD_ERROR_XFP_FAILURE, + MXGEFW_CMD_ERROR_XFP_ABSENT }; #define MXGEFW_OLD_IRQ_DATA_LEN 40 diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 527f9dcc7f69..50e1ec67ef9c 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -1576,7 +1576,7 @@ static int netdev_open(struct net_device *dev) /* Set the timer to check for link beat. */ init_timer(&np->timer); - np->timer.expires = jiffies + NATSEMI_TIMER_FREQ; + np->timer.expires = round_jiffies(jiffies + NATSEMI_TIMER_FREQ); np->timer.data = (unsigned long)dev; np->timer.function = &netdev_timer; /* timer handler */ add_timer(&np->timer); @@ -1856,7 +1856,11 @@ static void netdev_timer(unsigned long data) next_tick = 1; } } - mod_timer(&np->timer, jiffies + next_tick); + + if (next_tick > 1) + mod_timer(&np->timer, round_jiffies(jiffies + next_tick)); + else + mod_timer(&np->timer, jiffies + next_tick); } static void dump_ring(struct net_device *dev) @@ -3310,13 +3314,19 @@ static int natsemi_resume (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata (pdev); struct netdev_private *np = netdev_priv(dev); + int ret = 0; rtnl_lock(); if (netif_device_present(dev)) goto out; if (netif_running(dev)) { BUG_ON(!np->hands_off); - pci_enable_device(pdev); + ret = pci_enable_device(pdev); + if (ret < 0) { + dev_err(&pdev->dev, + "pci_enable_device() failed: %d\n", ret); + goto out; + } /* pci_power_on(pdev); */ napi_enable(&np->napi); @@ -3331,12 +3341,12 @@ static int natsemi_resume (struct pci_dev *pdev) spin_unlock_irq(&np->lock); enable_irq(dev->irq); - mod_timer(&np->timer, jiffies + 1*HZ); + mod_timer(&np->timer, round_jiffies(jiffies + 1*HZ)); } netif_device_attach(dev); out: rtnl_unlock(); - return 0; + return ret; } #endif /* CONFIG_PM */ diff --git a/drivers/net/ne-h8300.c b/drivers/net/ne-h8300.c index 368f2560856d..fbc7531d3c7d 100644 --- a/drivers/net/ne-h8300.c +++ b/drivers/net/ne-h8300.c @@ -93,7 +93,7 @@ static int __init init_reg_offset(struct net_device *dev,unsigned long base_addr bus_width = *(volatile unsigned char *)ABWCR; bus_width &= 1 << ((base_addr >> 21) & 7); - for (i = 0; i < sizeof(reg_offset) / sizeof(u32); i++) + for (i = 0; i < ARRAY_SIZE(reg_offset); i++) if (bus_width == 0) reg_offset[i] = i * 2 + 1; else @@ -115,7 +115,7 @@ static int h8300_ne_irq[] = {EXT_IRQ5}; static inline int init_dev(struct net_device *dev) { - if (h8300_ne_count < (sizeof(h8300_ne_base) / sizeof(unsigned long))) { + if (h8300_ne_count < ARRAY_SIZE(h8300_ne_base)) { dev->base_addr = h8300_ne_base[h8300_ne_count]; dev->irq = h8300_ne_irq[h8300_ne_count]; h8300_ne_count++; diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c index 097685245112..3edc971d0eca 100644 --- a/drivers/net/ni65.c +++ b/drivers/net/ni65.c @@ -183,7 +183,7 @@ static struct card { short addr_offset; unsigned char *vendor_id; char *cardname; - long config; + unsigned long config; } cards[] = { { .id0 = NI65_ID0, diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 43bfe7e6b6f5..ed1f9bbb2a32 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -6123,19 +6123,19 @@ static int __devinit niu_pci_probe_sprom(struct niu *np) val = nr64(ESPC_PHY_TYPE); switch (np->port) { case 0: - val = (val & ESPC_PHY_TYPE_PORT0) >> + val8 = (val & ESPC_PHY_TYPE_PORT0) >> ESPC_PHY_TYPE_PORT0_SHIFT; break; case 1: - val = (val & ESPC_PHY_TYPE_PORT1) >> + val8 = (val & ESPC_PHY_TYPE_PORT1) >> ESPC_PHY_TYPE_PORT1_SHIFT; break; case 2: - val = (val & ESPC_PHY_TYPE_PORT2) >> + val8 = (val & ESPC_PHY_TYPE_PORT2) >> ESPC_PHY_TYPE_PORT2_SHIFT; break; case 3: - val = (val & ESPC_PHY_TYPE_PORT3) >> + val8 = (val & ESPC_PHY_TYPE_PORT3) >> ESPC_PHY_TYPE_PORT3_SHIFT; break; default: @@ -6143,9 +6143,9 @@ static int __devinit niu_pci_probe_sprom(struct niu *np) np->port); return -EINVAL; } - niudbg(PROBE, "SPROM: PHY type %llx\n", (unsigned long long) val); + niudbg(PROBE, "SPROM: PHY type %x\n", val8); - switch (val) { + switch (val8) { case ESPC_PHY_TYPE_1G_COPPER: /* 1G copper, MII */ np->flags &= ~(NIU_FLAGS_FIBER | @@ -6175,8 +6175,7 @@ static int __devinit niu_pci_probe_sprom(struct niu *np) break; default: - dev_err(np->device, PFX "Bogus SPROM phy type %llu\n", - (unsigned long long) val); + dev_err(np->device, PFX "Bogus SPROM phy type %u\n", val8); return -EINVAL; } @@ -6213,7 +6212,7 @@ static int __devinit niu_pci_probe_sprom(struct niu *np) val = nr64(ESPC_MOD_STR_LEN); niudbg(PROBE, "SPROM: MOD_STR_LEN[%llu]\n", (unsigned long long) val); - if (val > 8 * 4) + if (val >= 8 * 4) return -EINVAL; for (i = 0; i < val; i += 4) { @@ -6229,7 +6228,7 @@ static int __devinit niu_pci_probe_sprom(struct niu *np) val = nr64(ESPC_BD_MOD_STR_LEN); niudbg(PROBE, "SPROM: BD_MOD_STR_LEN[%llu]\n", (unsigned long long) val); - if (val > 4 * 4) + if (val >= 4 * 4) return -EINVAL; for (i = 0; i < val; i += 4) { diff --git a/drivers/net/saa9730.c b/drivers/net/saa9730.c index 14361e885415..c65199df8a7f 100644 --- a/drivers/net/saa9730.c +++ b/drivers/net/saa9730.c @@ -97,13 +97,16 @@ static void evm_saa9730_unblock_lan_int(struct lan_saa9730_private *lp) &lp->evm_saa9730_regs->InterruptBlock1); } -static void __attribute_used__ show_saa9730_regs(struct lan_saa9730_private *lp) +static void __used show_saa9730_regs(struct net_device *dev) { + struct lan_saa9730_private *lp = netdev_priv(dev); int i, j; + printk("TxmBufferA = %p\n", lp->TxmBuffer[0][0]); printk("TxmBufferB = %p\n", lp->TxmBuffer[1][0]); printk("RcvBufferA = %p\n", lp->RcvBuffer[0][0]); printk("RcvBufferB = %p\n", lp->RcvBuffer[1][0]); + for (i = 0; i < LAN_SAA9730_BUFFERS; i++) { for (j = 0; j < LAN_SAA9730_TXM_Q_SIZE; j++) { printk("TxmBuffer[%d][%d] = %x\n", i, j, @@ -146,11 +149,13 @@ static void __attribute_used__ show_saa9730_regs(struct lan_saa9730_private *lp) readl(&lp->lan_saa9730_regs->RxCtl)); printk("lp->lan_saa9730_regs->RxStatus = %x\n", readl(&lp->lan_saa9730_regs->RxStatus)); + for (i = 0; i < LAN_SAA9730_CAM_DWORDS; i++) { writel(i, &lp->lan_saa9730_regs->CamAddress); printk("lp->lan_saa9730_regs->CamData = %x\n", readl(&lp->lan_saa9730_regs->CamData)); } + printk("dev->stats.tx_packets = %lx\n", dev->stats.tx_packets); printk("dev->stats.tx_errors = %lx\n", dev->stats.tx_errors); printk("dev->stats.tx_aborted_errors = %lx\n", @@ -855,7 +860,7 @@ static void lan_saa9730_tx_timeout(struct net_device *dev) /* Transmitter timeout, serious problems */ dev->stats.tx_errors++; printk("%s: transmit timed out, reset\n", dev->name); - /*show_saa9730_regs(lp); */ + /*show_saa9730_regs(dev); */ lan_saa9730_restart(lp); dev->trans_start = jiffies; diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 0a3203465415..7967240534d5 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -52,7 +52,7 @@ #include "sky2.h" #define DRV_NAME "sky2" -#define DRV_VERSION "1.18" +#define DRV_VERSION "1.19" #define PFX DRV_NAME " " /* @@ -296,10 +296,10 @@ static const u16 copper_fc_adv[] = { /* flow control to advertise bits when using 1000BaseX */ static const u16 fiber_fc_adv[] = { - [FC_BOTH] = PHY_M_P_BOTH_MD_X, + [FC_NONE] = PHY_M_P_NO_PAUSE_X, [FC_TX] = PHY_M_P_ASYM_MD_X, [FC_RX] = PHY_M_P_SYM_MD_X, - [FC_NONE] = PHY_M_P_NO_PAUSE_X, + [FC_BOTH] = PHY_M_P_BOTH_MD_X, }; /* flow control to GMA disable bits */ @@ -606,20 +606,19 @@ static void sky2_phy_power(struct sky2_hw *hw, unsigned port, int onoff) { struct pci_dev *pdev = hw->pdev; u32 reg1; - static const u32 phy_power[] - = { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD }; - - /* looks like this XL is back asswards .. */ - if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) - onoff = !onoff; + static const u32 phy_power[] = { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD }; + static const u32 coma_mode[] = { PCI_Y2_PHY1_COMA, PCI_Y2_PHY2_COMA }; pci_read_config_dword(pdev, PCI_DEV_REG1, ®1); + /* Turn on/off phy power saving */ if (onoff) - /* Turn off phy power saving */ reg1 &= ~phy_power[port]; else reg1 |= phy_power[port]; + if (onoff && hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) + reg1 |= coma_mode[port]; + pci_write_config_dword(pdev, PCI_DEV_REG1, reg1); pci_read_config_dword(pdev, PCI_DEV_REG1, ®1); @@ -1636,8 +1635,8 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done) printk(KERN_DEBUG "%s: tx done %u\n", dev->name, idx); - sky2->net_stats.tx_packets++; - sky2->net_stats.tx_bytes += re->skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += re->skb->len; dev_kfree_skb_any(re->skb); sky2->tx_next = RING_NEXT(idx, TX_RING_SIZE); @@ -2205,16 +2204,16 @@ resubmit: len_error: /* Truncation of overlength packets causes PHY length to not match MAC length */ - ++sky2->net_stats.rx_length_errors; + ++dev->stats.rx_length_errors; if (netif_msg_rx_err(sky2) && net_ratelimit()) pr_info(PFX "%s: rx length error: status %#x length %d\n", dev->name, status, length); goto resubmit; error: - ++sky2->net_stats.rx_errors; + ++dev->stats.rx_errors; if (status & GMR_FS_RX_FF_OV) { - sky2->net_stats.rx_over_errors++; + dev->stats.rx_over_errors++; goto resubmit; } @@ -2223,11 +2222,11 @@ error: dev->name, status, length); if (status & (GMR_FS_LONG_ERR | GMR_FS_UN_SIZE)) - sky2->net_stats.rx_length_errors++; + dev->stats.rx_length_errors++; if (status & GMR_FS_FRAGMENT) - sky2->net_stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (status & GMR_FS_CRC_ERR) - sky2->net_stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; goto resubmit; } @@ -2272,7 +2271,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) ++rx[port]; skb = sky2_receive(dev, length, status); if (unlikely(!skb)) { - sky2->net_stats.rx_dropped++; + dev->stats.rx_dropped++; break; } @@ -2287,8 +2286,8 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) } skb->protocol = eth_type_trans(skb, dev); - sky2->net_stats.rx_packets++; - sky2->net_stats.rx_bytes += skb->len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; dev->last_rx = jiffies; #ifdef SKY2_VLAN_TAG_USED @@ -2479,12 +2478,12 @@ static void sky2_mac_intr(struct sky2_hw *hw, unsigned port) gma_read16(hw, port, GM_TX_IRQ_SRC); if (status & GM_IS_RX_FF_OR) { - ++sky2->net_stats.rx_fifo_errors; + ++dev->stats.rx_fifo_errors; sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_CLI_RX_FO); } if (status & GM_IS_TX_FF_UR) { - ++sky2->net_stats.tx_fifo_errors; + ++dev->stats.tx_fifo_errors; sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_CLI_TX_FU); } } @@ -3223,12 +3222,6 @@ static void sky2_get_strings(struct net_device *dev, u32 stringset, u8 * data) } } -static struct net_device_stats *sky2_get_stats(struct net_device *dev) -{ - struct sky2_port *sky2 = netdev_priv(dev); - return &sky2->net_stats; -} - static int sky2_set_mac_address(struct net_device *dev, void *p) { struct sky2_port *sky2 = netdev_priv(dev); @@ -3569,20 +3562,64 @@ static void sky2_get_regs(struct net_device *dev, struct ethtool_regs *regs, { const struct sky2_port *sky2 = netdev_priv(dev); const void __iomem *io = sky2->hw->regs; + unsigned int b; regs->version = 1; - memset(p, 0, regs->len); - - memcpy_fromio(p, io, B3_RAM_ADDR); - /* skip diagnostic ram region */ - memcpy_fromio(p + B3_RI_WTO_R1, io + B3_RI_WTO_R1, 0x2000 - B3_RI_WTO_R1); + for (b = 0; b < 128; b++) { + /* This complicated switch statement is to make sure and + * only access regions that are unreserved. + * Some blocks are only valid on dual port cards. + * and block 3 has some special diagnostic registers that + * are poison. + */ + switch (b) { + case 3: + /* skip diagnostic ram region */ + memcpy_fromio(p + 0x10, io + 0x10, 128 - 0x10); + break; - /* copy GMAC registers */ - memcpy_fromio(p + BASE_GMAC_1, io + BASE_GMAC_1, 0x1000); - if (sky2->hw->ports > 1) - memcpy_fromio(p + BASE_GMAC_2, io + BASE_GMAC_2, 0x1000); + /* dual port cards only */ + case 5: /* Tx Arbiter 2 */ + case 9: /* RX2 */ + case 14 ... 15: /* TX2 */ + case 17: case 19: /* Ram Buffer 2 */ + case 22 ... 23: /* Tx Ram Buffer 2 */ + case 25: /* Rx MAC Fifo 1 */ + case 27: /* Tx MAC Fifo 2 */ + case 31: /* GPHY 2 */ + case 40 ... 47: /* Pattern Ram 2 */ + case 52: case 54: /* TCP Segmentation 2 */ + case 112 ... 116: /* GMAC 2 */ + if (sky2->hw->ports == 1) + goto reserved; + /* fall through */ + case 0: /* Control */ + case 2: /* Mac address */ + case 4: /* Tx Arbiter 1 */ + case 7: /* PCI express reg */ + case 8: /* RX1 */ + case 12 ... 13: /* TX1 */ + case 16: case 18:/* Rx Ram Buffer 1 */ + case 20 ... 21: /* Tx Ram Buffer 1 */ + case 24: /* Rx MAC Fifo 1 */ + case 26: /* Tx MAC Fifo 1 */ + case 28 ... 29: /* Descriptor and status unit */ + case 30: /* GPHY 1*/ + case 32 ... 39: /* Pattern Ram 1 */ + case 48: case 50: /* TCP Segmentation 1 */ + case 56 ... 60: /* PCI space */ + case 80 ... 84: /* GMAC 1 */ + memcpy_fromio(p, io, 128); + break; + default: +reserved: + memset(p, 0, 128); + } + p += 128; + io += 128; + } } /* In order to do Jumbo packets on these chips, need to turn off the @@ -3934,7 +3971,6 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, dev->stop = sky2_down; dev->do_ioctl = sky2_ioctl; dev->hard_start_xmit = sky2_xmit_frame; - dev->get_stats = sky2_get_stats; dev->set_multicast_list = sky2_set_multicast; dev->set_mac_address = sky2_set_mac_address; dev->change_mtu = sky2_change_mtu; @@ -4360,7 +4396,7 @@ static void sky2_shutdown(struct pci_dev *pdev) if (!hw) return; - napi_disable(&hw->napi); + del_timer_sync(&hw->watchdog_timer); for (i = 0; i < hw->ports; i++) { struct net_device *dev = hw->dev[i]; diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index f4a3c2f403e5..49ee264064ab 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -2031,8 +2031,6 @@ struct sky2_port { #ifdef CONFIG_SKY2_DEBUG struct dentry *debugfs; #endif - struct net_device_stats net_stats; - }; struct sky2_hw { diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index a679f4310ce1..8038f2882c9b 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -1461,7 +1461,6 @@ static irqreturn_t tc35815_interrupt(int irq, void *dev_id) } return IRQ_NONE; #else - struct tc35815_local *lp = dev->priv; int handled; u32 status; diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index 8d04654f0c59..4e1b84e6d66a 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -1906,7 +1906,7 @@ bdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /************** pci *****************/ if ((err = pci_enable_device(pdev))) /* it trigers interrupt, dunno why. */ - RET(err); /* it's not a problem though */ + goto err_pci; /* it's not a problem though */ if (!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK)) && !(err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))) { @@ -2076,6 +2076,7 @@ err_out_res: pci_release_regions(pdev); err_dma: pci_disable_device(pdev); +err_pci: vfree(nic); RET(err); diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index a402b5c01896..014dc2cfe4d6 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.83" -#define DRV_MODULE_RELDATE "October 10, 2007" +#define DRV_MODULE_VERSION "3.84" +#define DRV_MODULE_RELDATE "October 12, 2007" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -3576,7 +3576,7 @@ static int tg3_poll_work(struct tg3 *tp, int work_done, int budget) if (sblk->idx[0].tx_consumer != tp->tx_cons) { tg3_tx(tp); if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) - return 0; + return work_done; } /* run RX thread, within the bounds set by NAPI. @@ -3593,6 +3593,7 @@ static int tg3_poll(struct napi_struct *napi, int budget) { struct tg3 *tp = container_of(napi, struct tg3, napi); int work_done = 0; + struct tg3_hw_status *sblk = tp->hw_status; while (1) { work_done = tg3_poll_work(tp, work_done, budget); @@ -3603,15 +3604,17 @@ static int tg3_poll(struct napi_struct *napi, int budget) if (unlikely(work_done >= budget)) break; - if (likely(!tg3_has_work(tp))) { - struct tg3_hw_status *sblk = tp->hw_status; - - if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) { - tp->last_tag = sblk->status_tag; - rmb(); - } else - sblk->status &= ~SD_STATUS_UPDATED; + if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) { + /* tp->last_tag is used in tg3_restart_ints() below + * to tell the hw how much work has been processed, + * so we must read it before checking for more work. + */ + tp->last_tag = sblk->status_tag; + rmb(); + } else + sblk->status &= ~SD_STATUS_UPDATED; + if (likely(!tg3_has_work(tp))) { netif_rx_complete(tp->dev, napi); tg3_restart_ints(tp); break; @@ -3621,9 +3624,10 @@ static int tg3_poll(struct napi_struct *napi, int budget) return work_done; tx_recovery: + /* work_done is guaranteed to be less than budget. */ netif_rx_complete(tp->dev, napi); schedule_work(&tp->reset_task); - return 0; + return work_done; } static void tg3_irq_quiesce(struct tg3 *tp) @@ -5052,6 +5056,12 @@ static void tg3_restore_pci_state(struct tg3 *tp) pci_write_config_dword(tp->pdev, TG3PCI_COMMAND, tp->pci_cmd); + if (!(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)) { + pci_write_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE, + tp->pci_cacheline_sz); + pci_write_config_byte(tp->pdev, PCI_LATENCY_TIMER, + tp->pci_lat_timer); + } /* Make sure PCI-X relaxed ordering bit is clear. */ if (tp->pcix_cap) { u16 pcix_cmd; @@ -6985,9 +6995,10 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) break; }; - /* Write our heartbeat update interval to APE. */ - tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_INT_MS, - APE_HOST_HEARTBEAT_INT_DISABLE); + if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) + /* Write our heartbeat update interval to APE. */ + tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_INT_MS, + APE_HOST_HEARTBEAT_INT_DISABLE); tg3_write_sig_post_reset(tp, RESET_KIND_INIT); @@ -9029,7 +9040,7 @@ static int tg3_do_mem_test(struct tg3 *tp, u32 offset, u32 len) int i; u32 j; - for (i = 0; i < sizeof(test_pattern)/sizeof(u32); i++) { + for (i = 0; i < ARRAY_SIZE(test_pattern); i++) { for (j = 0; j < len; j += 4) { u32 val; diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index 9b9cd83fb8b6..41f34bb91cad 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -1041,7 +1041,7 @@ static struct InfoLeaf infoleaf_array[] = { {DC21142, dc21142_infoleaf}, {DC21143, dc21143_infoleaf} }; -#define INFOLEAF_SIZE (sizeof(infoleaf_array)/(sizeof(int)+sizeof(int *))) +#define INFOLEAF_SIZE ARRAY_SIZE(infoleaf_array) /* ** List the SROM info block functions @@ -1056,7 +1056,7 @@ static int (*dc_infoblock[])(struct net_device *dev, u_char, u_char *) = { compact_infoblock }; -#define COMPACT (sizeof(dc_infoblock)/sizeof(int *) - 1) +#define COMPACT (ARRAY_SIZE(dc_infoblock) - 1) /* ** Miscellaneous defines... diff --git a/drivers/net/tulip/de4x5.h b/drivers/net/tulip/de4x5.h index 12af0cc037fb..9fb8d7f07994 100644 --- a/drivers/net/tulip/de4x5.h +++ b/drivers/net/tulip/de4x5.h @@ -1017,4 +1017,4 @@ struct de4x5_ioctl { #define DE4X5_SET_OMR 0x0d /* Set the OMR Register contents */ #define DE4X5_GET_REG 0x0e /* Get the DE4X5 Registers */ -#define MOTO_SROM_BUG ((lp->active == 8) && (((le32_to_cpu(get_unaligned(((s32 *)dev->dev_addr))))&0x00ffffff)==0x3e0008)) +#define MOTO_SROM_BUG ((lp->active == 8) && (((le32_to_cpu(get_unaligned(((__le32 *)dev->dev_addr))))&0x00ffffff)==0x3e0008)) diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index ee08292bcf85..e5e2c9c4ebfe 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -292,6 +292,7 @@ static void tulip_up(struct net_device *dev) struct tulip_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->base_addr; int next_tick = 3*HZ; + u32 reg; int i; #ifdef CONFIG_TULIP_NAPI @@ -307,14 +308,14 @@ static void tulip_up(struct net_device *dev) /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */ iowrite32(0x00000001, ioaddr + CSR0); - pci_read_config_dword(tp->pdev, PCI_COMMAND, &i); /* flush write */ + pci_read_config_dword(tp->pdev, PCI_COMMAND, ®); /* flush write */ udelay(100); /* Deassert reset. Wait the specified 50 PCI cycles after a reset by initializing Tx and Rx queues and the address filter list. */ iowrite32(tp->csr0, ioaddr + CSR0); - pci_read_config_dword(tp->pdev, PCI_COMMAND, &i); /* flush write */ + pci_read_config_dword(tp->pdev, PCI_COMMAND, ®); /* flush write */ udelay(100); if (tulip_debug > 1) diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index d00e7d41f6a5..bec413ba9bca 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -63,7 +63,7 @@ #define UGETH_MSG_DEFAULT (NETIF_MSG_IFUP << 1 ) - 1 void uec_set_ethtool_ops(struct net_device *netdev); - + static DEFINE_SPINLOCK(ugeth_lock); static struct { @@ -3454,9 +3454,12 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit u16 length, howmany = 0; u32 bd_status; u8 *bdBuffer; + struct net_device * dev; ugeth_vdbg("%s: IN", __FUNCTION__); + dev = ugeth->dev; + /* collect received buffers */ bd = ugeth->rxBd[rxQ]; diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index 26058b4f8f36..ff37bf437a99 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -154,8 +154,8 @@ struct cosa_data { int nchannels; /* # of channels on this card */ int driver_status; /* For communicating with firmware */ int firmware_status; /* Downloaded, reseted, etc. */ - long int rxbitmap, txbitmap; /* Bitmap of channels who are willing to send/receive data */ - long int rxtx; /* RX or TX in progress? */ + unsigned long rxbitmap, txbitmap;/* Bitmap of channels who are willing to send/receive data */ + unsigned long rxtx; /* RX or TX in progress? */ int enabled; int usage; /* usage count */ int txchan, txsize, rxsize; diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c index b39a541b2509..05df0a345b60 100644 --- a/drivers/net/wan/sdla.c +++ b/drivers/net/wan/sdla.c @@ -1342,11 +1342,11 @@ static int sdla_set_config(struct net_device *dev, struct ifmap *map) if (flp->initialized) return(-EINVAL); - for(i=0;i < sizeof(valid_port) / sizeof (int) ; i++) + for(i=0; i < ARRAY_SIZE(valid_port); i++) if (valid_port[i] == map->base_addr) break; - if (i == sizeof(valid_port) / sizeof(int)) + if (i == ARRAY_SIZE(valid_port)) return(-EINVAL); if (!request_region(map->base_addr, SDLA_IO_EXTENTS, dev->name)){ @@ -1487,12 +1487,12 @@ got_type: } } - for(i=0;i < sizeof(valid_mem) / sizeof (int) ; i++) + for(i=0; i < ARRAY_SIZE(valid_mem); i++) if (valid_mem[i] == map->mem_start) break; err = -EINVAL; - if (i == sizeof(valid_mem) / sizeof(int)) + if (i == ARRAY_SIZE(valid_mem)) goto fail2; if (flp->type == SDLA_S502A && (map->mem_start & 0xF000) >> 12 == 0x0E) diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy.c index 5f7ffa0a76c0..3d4ed647c311 100644 --- a/drivers/net/wireless/b43/phy.c +++ b/drivers/net/wireless/b43/phy.c @@ -26,6 +26,7 @@ */ #include <linux/delay.h> +#include <linux/io.h> #include <linux/types.h> #include "b43.h" diff --git a/drivers/net/wireless/b43/pio.h b/drivers/net/wireless/b43/pio.h index 34a44c1b6314..3488f2447bbf 100644 --- a/drivers/net/wireless/b43/pio.h +++ b/drivers/net/wireless/b43/pio.h @@ -4,6 +4,7 @@ #include "b43.h" #include <linux/interrupt.h> +#include <linux/io.h> #include <linux/list.h> #include <linux/skbuff.h> diff --git a/drivers/net/wireless/b43/sysfs.c b/drivers/net/wireless/b43/sysfs.c index fcb777383e70..f4faff6a7d6c 100644 --- a/drivers/net/wireless/b43/sysfs.c +++ b/drivers/net/wireless/b43/sysfs.c @@ -23,13 +23,14 @@ */ +#include <linux/capability.h> +#include <linux/io.h> + #include "b43.h" #include "sysfs.h" #include "main.h" #include "phy.h" -#include <linux/capability.h> - #define GENERIC_FILESIZE 64 static int get_integer(const char *buf, size_t count) diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h index c27b2c1c06af..e6516a186d0e 100644 --- a/drivers/net/wireless/hostap/hostap_wlan.h +++ b/drivers/net/wireless/hostap/hostap_wlan.h @@ -661,7 +661,7 @@ struct local_info { #define HOSTAP_BITS_TRANSMIT 0 #define HOSTAP_BITS_BAP_TASKLET 1 #define HOSTAP_BITS_BAP_TASKLET2 2 - long bits; + unsigned long bits; struct ap_data *ap; diff --git a/drivers/net/wireless/ray_cs.h b/drivers/net/wireless/ray_cs.h index bd73ebf03340..1e23b7f4cca7 100644 --- a/drivers/net/wireless/ray_cs.h +++ b/drivers/net/wireless/ray_cs.h @@ -33,8 +33,8 @@ typedef struct ray_dev_t { void __iomem *rmem; /* pointer to receive buffer window */ struct pcmcia_device *finder; /* pointer back to struct pcmcia_device for card */ struct timer_list timer; - long tx_ccs_lock; - long ccs_lock; + unsigned long tx_ccs_lock; + unsigned long ccs_lock; int dl_param_ccs; union { struct b4_startup_params b4; diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index f464b82c7d5f..7fd505cc4f7a 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -74,22 +74,12 @@ struct netfront_info { struct napi_struct napi; - struct xen_netif_tx_front_ring tx; - struct xen_netif_rx_front_ring rx; - - spinlock_t tx_lock; - spinlock_t rx_lock; - unsigned int evtchn; + struct xenbus_device *xbdev; - /* Receive-ring batched refills. */ -#define RX_MIN_TARGET 8 -#define RX_DFL_MIN_TARGET 64 -#define RX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256) - unsigned rx_min_target, rx_max_target, rx_target; - struct sk_buff_head rx_batch; - - struct timer_list rx_refill_timer; + spinlock_t tx_lock; + struct xen_netif_tx_front_ring tx; + int tx_ring_ref; /* * {tx,rx}_skbs store outstanding skbuffs. Free tx_skb entries @@ -108,14 +98,23 @@ struct netfront_info { grant_ref_t grant_tx_ref[NET_TX_RING_SIZE]; unsigned tx_skb_freelist; + spinlock_t rx_lock ____cacheline_aligned_in_smp; + struct xen_netif_rx_front_ring rx; + int rx_ring_ref; + + /* Receive-ring batched refills. */ +#define RX_MIN_TARGET 8 +#define RX_DFL_MIN_TARGET 64 +#define RX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256) + unsigned rx_min_target, rx_max_target, rx_target; + struct sk_buff_head rx_batch; + + struct timer_list rx_refill_timer; + struct sk_buff *rx_skbs[NET_RX_RING_SIZE]; grant_ref_t gref_rx_head; grant_ref_t grant_rx_ref[NET_RX_RING_SIZE]; - struct xenbus_device *xbdev; - int tx_ring_ref; - int rx_ring_ref; - unsigned long rx_pfn_array[NET_RX_RING_SIZE]; struct multicall_entry rx_mcl[NET_RX_RING_SIZE+1]; struct mmu_update rx_mmu[NET_RX_RING_SIZE]; diff --git a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c index 1c97e7dd130b..2b5352a7dffc 100644 --- a/drivers/pci/hotplug.c +++ b/drivers/pci/hotplug.c @@ -3,12 +3,9 @@ #include <linux/module.h> #include "pci.h" -int pci_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +int pci_uevent(struct device *dev, struct kobj_uevent_env *env) { struct pci_dev *pdev; - int i = 0; - int length = 0; if (!dev) return -ENODEV; @@ -17,37 +14,24 @@ int pci_uevent(struct device *dev, char **envp, int num_envp, if (!pdev) return -ENODEV; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PCI_CLASS=%04X", pdev->class)) + if (add_uevent_var(env, "PCI_CLASS=%04X", pdev->class)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PCI_ID=%04X:%04X", pdev->vendor, pdev->device)) + if (add_uevent_var(env, "PCI_ID=%04X:%04X", pdev->vendor, pdev->device)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor, + if (add_uevent_var(env, "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor, pdev->subsystem_device)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PCI_SLOT_NAME=%s", pci_name(pdev))) + if (add_uevent_var(env, "PCI_SLOT_NAME=%s", pci_name(pdev))) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x", + if (add_uevent_var(env, "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x", pdev->vendor, pdev->device, pdev->subsystem_vendor, pdev->subsystem_device, (u8)(pdev->class >> 16), (u8)(pdev->class >> 8), (u8)(pdev->class))) return -ENOMEM; - - envp[i] = NULL; - return 0; } diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index 2305cc450a45..a96b739b2d35 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -549,7 +549,7 @@ get_slot_mapping(struct pci_bus *bus, u8 bus_num, u8 dev_num, u8 *slot) * slot. */ bus->number = tbus; pci_bus_read_config_dword(bus, PCI_DEVFN(tdevice, 0), - PCI_REVISION_ID, &work); + PCI_CLASS_REVISION, &work); if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) { pci_bus_read_config_dword(bus, diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c index 37d72f123a80..3ef0a4875a62 100644 --- a/drivers/pci/hotplug/cpqphp_ctrl.c +++ b/drivers/pci/hotplug/cpqphp_ctrl.c @@ -37,6 +37,7 @@ #include <linux/smp_lock.h> #include <linux/pci.h> #include <linux/pci_hotplug.h> +#include <linux/kthread.h> #include "cpqphp.h" static u32 configure_new_device(struct controller* ctrl, struct pci_func *func, @@ -45,34 +46,20 @@ static int configure_new_function(struct controller* ctrl, struct pci_func *func u8 behind_bridge, struct resource_lists *resources); static void interrupt_event_handler(struct controller *ctrl); -static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ -static struct semaphore event_exit; /* guard ensure thread has exited before calling it quits */ -static int event_finished; -static unsigned long pushbutton_pending; /* = 0 */ -/* things needed for the long_delay function */ -static struct semaphore delay_sem; -static wait_queue_head_t delay_wait; +static struct task_struct *cpqhp_event_thread; +static unsigned long pushbutton_pending; /* = 0 */ /* delay is in jiffies to wait for */ static void long_delay(int delay) { - DECLARE_WAITQUEUE(wait, current); - - /* only allow 1 customer into the delay queue at once - * yes this makes some people wait even longer, but who really cares? - * this is for _huge_ delays to make the hardware happy as the - * signals bounce around + /* + * XXX(hch): if someone is bored please convert all callers + * to call msleep_interruptible directly. They really want + * to specify timeouts in natural units and spend a lot of + * effort converting them to jiffies.. */ - down (&delay_sem); - - init_waitqueue_head(&delay_wait); - - add_wait_queue(&delay_wait, &wait); msleep_interruptible(jiffies_to_msecs(delay)); - remove_wait_queue(&delay_wait, &wait); - - up(&delay_sem); } @@ -955,8 +942,8 @@ irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data) } if (schedule_flag) { - up(&event_semaphore); - dbg("Signal event_semaphore\n"); + wake_up_process(cpqhp_event_thread); + dbg("Waking even thread"); } return IRQ_HANDLED; } @@ -973,16 +960,13 @@ struct pci_func *cpqhp_slot_create(u8 busnumber) struct pci_func *new_slot; struct pci_func *next; - new_slot = kmalloc(sizeof(*new_slot), GFP_KERNEL); - + new_slot = kzalloc(sizeof(*new_slot), GFP_KERNEL); if (new_slot == NULL) { /* I'm not dead yet! * You will be. */ return new_slot; } - memset(new_slot, 0, sizeof(struct pci_func)); - new_slot->next = NULL; new_slot->configured = 1; @@ -1738,7 +1722,7 @@ static u32 remove_board(struct pci_func * func, u32 replace_flag, struct control static void pushbutton_helper_thread(unsigned long data) { pushbutton_pending = data; - up(&event_semaphore); + wake_up_process(cpqhp_event_thread); } @@ -1747,13 +1731,13 @@ static int event_thread(void* data) { struct controller *ctrl; - daemonize("phpd_event"); - while (1) { dbg("!!!!event_thread sleeping\n"); - down_interruptible (&event_semaphore); - dbg("event_thread woken finished = %d\n", event_finished); - if (event_finished) break; + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + + if (kthread_should_stop()) + break; /* Do stuff here */ if (pushbutton_pending) cpqhp_pushbutton_thread(pushbutton_pending); @@ -1762,38 +1746,24 @@ static int event_thread(void* data) interrupt_event_handler(ctrl); } dbg("event_thread signals exit\n"); - up(&event_exit); return 0; } - int cpqhp_event_start_thread(void) { - int pid; - - /* initialize our semaphores */ - init_MUTEX(&delay_sem); - init_MUTEX_LOCKED(&event_semaphore); - init_MUTEX_LOCKED(&event_exit); - event_finished=0; - - pid = kernel_thread(event_thread, NULL, 0); - if (pid < 0) { + cpqhp_event_thread = kthread_run(event_thread, NULL, "phpd_event"); + if (IS_ERR(cpqhp_event_thread)) { err ("Can't start up our event thread\n"); - return -1; + return PTR_ERR(cpqhp_event_thread); } - dbg("Our event thread pid = %d\n", pid); + return 0; } void cpqhp_event_stop_thread(void) { - event_finished = 1; - dbg("event_thread finish command given\n"); - up(&event_semaphore); - dbg("wait for event_thread to exit\n"); - down(&event_exit); + kthread_stop(cpqhp_event_thread); } diff --git a/drivers/pci/hotplug/ibmphp_hpc.c b/drivers/pci/hotplug/ibmphp_hpc.c index d06ccb69e411..c31e7bf34502 100644 --- a/drivers/pci/hotplug/ibmphp_hpc.c +++ b/drivers/pci/hotplug/ibmphp_hpc.c @@ -35,7 +35,7 @@ #include <linux/init.h> #include <linux/mutex.h> #include <linux/sched.h> - +#include <linux/kthread.h> #include "ibmphp.h" static int to_debug = 0; @@ -101,12 +101,11 @@ static int to_debug = 0; //---------------------------------------------------------------------------- // global variables //---------------------------------------------------------------------------- -static int ibmphp_shutdown; -static int tid_poll; static struct mutex sem_hpcaccess; // lock access to HPC static struct semaphore semOperations; // lock all operations and // access to data structures static struct semaphore sem_exit; // make sure polling thread goes away +static struct task_struct *ibmphp_poll_thread; //---------------------------------------------------------------------------- // local function prototypes //---------------------------------------------------------------------------- @@ -116,10 +115,9 @@ static u8 hpc_writecmdtoindex (u8, u8); static u8 hpc_readcmdtoindex (u8, u8); static void get_hpc_access (void); static void free_hpc_access (void); -static void poll_hpc (void); +static int poll_hpc(void *data); static int process_changeinstatus (struct slot *, struct slot *); static int process_changeinlatch (u8, u8, struct controller *); -static int hpc_poll_thread (void *); static int hpc_wait_ctlr_notworking (int, struct controller *, void __iomem *, u8 *); //---------------------------------------------------------------------------- @@ -137,8 +135,6 @@ void __init ibmphp_hpc_initvars (void) init_MUTEX (&semOperations); init_MUTEX_LOCKED (&sem_exit); to_debug = 0; - ibmphp_shutdown = 0; - tid_poll = 0; debug ("%s - Exit\n", __FUNCTION__); } @@ -819,7 +815,7 @@ void ibmphp_unlock_operations (void) #define POLL_LATCH_REGISTER 0 #define POLL_SLOTS 1 #define POLL_SLEEP 2 -static void poll_hpc (void) +static int poll_hpc(void *data) { struct slot myslot; struct slot *pslot = NULL; @@ -833,10 +829,7 @@ static void poll_hpc (void) debug ("%s - Entry\n", __FUNCTION__); - while (!ibmphp_shutdown) { - if (ibmphp_shutdown) - break; - + while (!kthread_should_stop()) { /* try to get the lock to do some kind of hardware access */ down (&semOperations); @@ -896,7 +889,7 @@ static void poll_hpc (void) up (&semOperations); msleep(POLL_INTERVAL_SEC * 1000); - if (ibmphp_shutdown) + if (kthread_should_stop()) break; down (&semOperations); @@ -915,6 +908,7 @@ static void poll_hpc (void) } up (&sem_exit); debug ("%s - Exit\n", __FUNCTION__); + return 0; } @@ -1050,47 +1044,20 @@ static int process_changeinlatch (u8 old, u8 new, struct controller *ctrl) } /*---------------------------------------------------------------------- -* Name: hpc_poll_thread -* -* Action: polling -* -* Return 0 -* Value: -*---------------------------------------------------------------------*/ -static int hpc_poll_thread (void *data) -{ - debug ("%s - Entry\n", __FUNCTION__); - - daemonize("hpc_poll"); - allow_signal(SIGKILL); - - poll_hpc (); - - tid_poll = 0; - debug ("%s - Exit\n", __FUNCTION__); - return 0; -} - - -/*---------------------------------------------------------------------- * Name: ibmphp_hpc_start_poll_thread * * Action: start polling thread *---------------------------------------------------------------------*/ int __init ibmphp_hpc_start_poll_thread (void) { - int rc = 0; - debug ("%s - Entry\n", __FUNCTION__); - tid_poll = kernel_thread (hpc_poll_thread, NULL, 0); - if (tid_poll < 0) { + ibmphp_poll_thread = kthread_run(poll_hpc, NULL, "hpc_poll"); + if (IS_ERR(ibmphp_poll_thread)) { err ("%s - Error, thread not started\n", __FUNCTION__); - rc = -1; + return PTR_ERR(ibmphp_poll_thread); } - - debug ("%s - Exit tid_poll[%d] rc[%d]\n", __FUNCTION__, tid_poll, rc); - return rc; + return 0; } /*---------------------------------------------------------------------- @@ -1102,7 +1069,7 @@ void __exit ibmphp_hpc_stop_poll_thread (void) { debug ("%s - Entry\n", __FUNCTION__); - ibmphp_shutdown = 1; + kthread_stop(ibmphp_poll_thread); debug ("before locking operations \n"); ibmphp_lock_operations (); debug ("after locking operations \n"); diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index bd433ef6bfc6..01c351c176ac 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -689,71 +689,9 @@ int pci_hp_deregister (struct hotplug_slot *slot) int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot, struct hotplug_slot_info *info) { - int retval; - if ((slot == NULL) || (info == NULL)) return -ENODEV; - /* - * check all fields in the info structure, and update timestamps - * for the files referring to the fields that have now changed. - */ - if ((has_power_file(slot) == 0) && - (slot->info->power_status != info->power_status)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_power.attr); - if (retval) - return retval; - } - - if ((has_attention_file(slot) == 0) && - (slot->info->attention_status != info->attention_status)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_attention.attr); - if (retval) - return retval; - } - - if ((has_latch_file(slot) == 0) && - (slot->info->latch_status != info->latch_status)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_latch.attr); - if (retval) - return retval; - } - - if ((has_adapter_file(slot) == 0) && - (slot->info->adapter_status != info->adapter_status)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_presence.attr); - if (retval) - return retval; - } - - if ((has_address_file(slot) == 0) && - (slot->info->address != info->address)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_address.attr); - if (retval) - return retval; - } - - if ((has_max_bus_speed_file(slot) == 0) && - (slot->info->max_bus_speed != info->max_bus_speed)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_max_bus_speed.attr); - if (retval) - return retval; - } - - if ((has_cur_bus_speed_file(slot) == 0) && - (slot->info->cur_bus_speed != info->cur_bus_speed)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_cur_bus_speed.attr); - if (retval) - return retval; - } - memcpy (slot->info, info, sizeof (struct hotplug_slot_info)); return 0; diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index e5d3f0b4f45a..6462ac3b405f 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -304,8 +304,8 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); hotplug_slot->info->attention_status = status; - - if (ATTN_LED(slot->ctrl->ctrlcap)) + + if (ATTN_LED(slot->ctrl->ctrlcap)) slot->hpc_ops->set_attention_status(slot, status); return 0; @@ -405,7 +405,7 @@ static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe int retval; dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - + retval = slot->hpc_ops->get_max_bus_speed(slot, value); if (retval < 0) *value = PCI_SPEED_UNKNOWN; @@ -419,7 +419,7 @@ static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe int retval; dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - + retval = slot->hpc_ops->get_cur_bus_speed(slot, value); if (retval < 0) *value = PCI_SPEED_UNKNOWN; @@ -434,7 +434,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ struct slot *t_slot; u8 value; struct pci_dev *pdev; - + ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); if (!ctrl) { err("%s : out of memory\n", __FUNCTION__); @@ -502,23 +502,23 @@ static void pciehp_remove (struct pcie_device *dev) #ifdef CONFIG_PM static int pciehp_suspend (struct pcie_device *dev, pm_message_t state) { - printk("%s ENTRY\n", __FUNCTION__); + printk("%s ENTRY\n", __FUNCTION__); return 0; } static int pciehp_resume (struct pcie_device *dev) { - printk("%s ENTRY\n", __FUNCTION__); + printk("%s ENTRY\n", __FUNCTION__); return 0; } #endif -static struct pcie_port_service_id port_pci_ids[] = { { - .vendor = PCI_ANY_ID, +static struct pcie_port_service_id port_pci_ids[] = { { + .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, .port_type = PCIE_ANY_PORT, .service_type = PCIE_PORT_SERVICE_HP, - .driver_data = 0, + .driver_data = 0, }, { /* end: all zeroes */ } }; static const char device_name[] = "hpdriver"; @@ -540,10 +540,6 @@ static int __init pcied_init(void) { int retval = 0; -#ifdef CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE - pciehp_poll_mode = 1; -#endif - retval = pcie_port_service_register(&hpdriver_portdrv); dbg("pcie_port_service_register = %d\n", retval); info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 98e541ffef3d..c8cb49c5a752 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -173,7 +173,7 @@ u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl) return 1; } -/* The following routines constitute the bulk of the +/* The following routines constitute the bulk of the hotplug controller logic */ @@ -181,7 +181,7 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot) { /* turn off slot, turn on Amber LED, turn off Green LED if supported*/ if (POWER_CTRL(ctrl->ctrlcap)) { - if (pslot->hpc_ops->power_off_slot(pslot)) { + if (pslot->hpc_ops->power_off_slot(pslot)) { err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__); return; @@ -189,7 +189,7 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot) } if (PWR_LED(ctrl->ctrlcap)) - pslot->hpc_ops->green_led_off(pslot); + pslot->hpc_ops->green_led_off(pslot); if (ATTN_LED(ctrl->ctrlcap)) { if (pslot->hpc_ops->set_attention_status(pslot, 1)) { @@ -231,7 +231,7 @@ static int board_added(struct slot *p_slot) if (retval) return retval; } - + if (PWR_LED(ctrl->ctrlcap)) p_slot->hpc_ops->green_led_blink(p_slot); @@ -548,7 +548,7 @@ int pciehp_enable_slot(struct slot *p_slot) mutex_unlock(&p_slot->ctrl->crit_sect); return -ENODEV; } - if (MRL_SENS(p_slot->ctrl->ctrlcap)) { + if (MRL_SENS(p_slot->ctrl->ctrlcap)) { rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (rc || getstatus) { info("%s: latch open on slot(%s)\n", __FUNCTION__, @@ -557,8 +557,8 @@ int pciehp_enable_slot(struct slot *p_slot) return -ENODEV; } } - - if (POWER_CTRL(p_slot->ctrl->ctrlcap)) { + + if (POWER_CTRL(p_slot->ctrl->ctrlcap)) { rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (rc || getstatus) { info("%s: already enabled on slot(%s)\n", __FUNCTION__, @@ -593,7 +593,7 @@ int pciehp_disable_slot(struct slot *p_slot) /* Check to see if (latch closed, card present, power on) */ mutex_lock(&p_slot->ctrl->crit_sect); - if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) { + if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) { ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); if (ret || !getstatus) { info("%s: no adapter on slot(%s)\n", __FUNCTION__, @@ -603,7 +603,7 @@ int pciehp_disable_slot(struct slot *p_slot) } } - if (MRL_SENS(p_slot->ctrl->ctrlcap)) { + if (MRL_SENS(p_slot->ctrl->ctrlcap)) { ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (ret || getstatus) { info("%s: latch open on slot(%s)\n", __FUNCTION__, @@ -613,7 +613,7 @@ int pciehp_disable_slot(struct slot *p_slot) } } - if (POWER_CTRL(p_slot->ctrl->ctrlcap)) { + if (POWER_CTRL(p_slot->ctrl->ctrlcap)) { ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (ret || !getstatus) { info("%s: already disabled slot(%s)\n", __FUNCTION__, diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 016eea94a8a5..06d025b8b13f 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -39,37 +39,6 @@ #include "../pci.h" #include "pciehp.h" -#ifdef DEBUG -#define DBG_K_TRACE_ENTRY ((unsigned int)0x00000001) /* On function entry */ -#define DBG_K_TRACE_EXIT ((unsigned int)0x00000002) /* On function exit */ -#define DBG_K_INFO ((unsigned int)0x00000004) /* Info messages */ -#define DBG_K_ERROR ((unsigned int)0x00000008) /* Error messages */ -#define DBG_K_TRACE (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT) -#define DBG_K_STANDARD (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE) -/* Redefine this flagword to set debug level */ -#define DEBUG_LEVEL DBG_K_STANDARD - -#define DEFINE_DBG_BUFFER char __dbg_str_buf[256]; - -#define DBG_PRINT( dbg_flags, args... ) \ - do { \ - if ( DEBUG_LEVEL & ( dbg_flags ) ) \ - { \ - int len; \ - len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \ - __FILE__, __LINE__, __FUNCTION__ ); \ - sprintf( __dbg_str_buf + len, args ); \ - printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \ - } \ - } while (0) - -#define DBG_ENTER_ROUTINE DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]"); -#define DBG_LEAVE_ROUTINE DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]"); -#else -#define DEFINE_DBG_BUFFER -#define DBG_ENTER_ROUTINE -#define DBG_LEAVE_ROUTINE -#endif /* DEBUG */ static atomic_t pciehp_num_controllers = ATOMIC_INIT(0); @@ -160,10 +129,10 @@ static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value) /* Link Width Encoding */ #define LNK_X1 0x01 #define LNK_X2 0x02 -#define LNK_X4 0x04 +#define LNK_X4 0x04 #define LNK_X8 0x08 #define LNK_X12 0x0C -#define LNK_X16 0x10 +#define LNK_X16 0x10 #define LNK_X32 0x20 /*Field definitions of Link Status Register */ @@ -221,8 +190,6 @@ static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value) #define EMI_STATE 0x0080 #define EMI_STATUS_BIT 7 -DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */ - static irqreturn_t pcie_isr(int irq, void *dev_id); static void start_int_poll_timer(struct controller *ctrl, int sec); @@ -231,14 +198,12 @@ static void int_poll_timeout(unsigned long data) { struct controller *ctrl = (struct controller *)data; - DBG_ENTER_ROUTINE - /* Poll for interrupt events. regs == NULL => polling */ pcie_isr(0, ctrl); init_timer(&ctrl->poll_timer); if (!pciehp_poll_time) - pciehp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/ + pciehp_poll_time = 2; /* default polling interval is 2 sec */ start_int_poll_timer(ctrl, pciehp_poll_time); } @@ -289,8 +254,6 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask) u16 slot_ctrl; unsigned long flags; - DBG_ENTER_ROUTINE - mutex_lock(&ctrl->ctrl_lock); retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); @@ -299,7 +262,7 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask) goto out; } - if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) { + if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) { /* After 1 sec and CMD_COMPLETED still not set, just proceed forward to issue the next command according to spec. Just print out the error message */ @@ -332,7 +295,6 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask) retval = pcie_wait_cmd(ctrl); out: mutex_unlock(&ctrl->ctrl_lock); - DBG_LEAVE_ROUTINE return retval; } @@ -341,8 +303,6 @@ static int hpc_check_lnk_status(struct controller *ctrl) u16 lnk_status; int retval = 0; - DBG_ENTER_ROUTINE - retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status); if (retval) { err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__); @@ -350,26 +310,22 @@ static int hpc_check_lnk_status(struct controller *ctrl) } dbg("%s: lnk_status = %x\n", __FUNCTION__, lnk_status); - if ( (lnk_status & LNK_TRN) || (lnk_status & LNK_TRN_ERR) || + if ( (lnk_status & LNK_TRN) || (lnk_status & LNK_TRN_ERR) || !(lnk_status & NEG_LINK_WD)) { err("%s : Link Training Error occurs \n", __FUNCTION__); retval = -1; return retval; } - DBG_LEAVE_ROUTINE return retval; } - static int hpc_get_attention_status(struct slot *slot, u8 *status) { struct controller *ctrl = slot->ctrl; u16 slot_ctrl; u8 atten_led_state; int retval = 0; - - DBG_ENTER_ROUTINE retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); if (retval) { @@ -400,7 +356,6 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status) break; } - DBG_LEAVE_ROUTINE return 0; } @@ -410,8 +365,6 @@ static int hpc_get_power_status(struct slot *slot, u8 *status) u16 slot_ctrl; u8 pwr_state; int retval = 0; - - DBG_ENTER_ROUTINE retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); if (retval) { @@ -428,35 +381,30 @@ static int hpc_get_power_status(struct slot *slot, u8 *status) *status = 1; break; case 1: - *status = 0; + *status = 0; break; default: *status = 0xFF; break; } - DBG_LEAVE_ROUTINE return retval; } - static int hpc_get_latch_status(struct slot *slot, u8 *status) { struct controller *ctrl = slot->ctrl; u16 slot_status; int retval = 0; - DBG_ENTER_ROUTINE - retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (retval) { err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); return retval; } - *status = (((slot_status & MRL_STATE) >> 5) == 0) ? 0 : 1; + *status = (((slot_status & MRL_STATE) >> 5) == 0) ? 0 : 1; - DBG_LEAVE_ROUTINE return 0; } @@ -467,8 +415,6 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status) u8 card_state; int retval = 0; - DBG_ENTER_ROUTINE - retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (retval) { err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); @@ -477,7 +423,6 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status) card_state = (u8)((slot_status & PRSN_STATE) >> 6); *status = (card_state == 1) ? 1 : 0; - DBG_LEAVE_ROUTINE return 0; } @@ -488,16 +433,13 @@ static int hpc_query_power_fault(struct slot *slot) u8 pwr_fault; int retval = 0; - DBG_ENTER_ROUTINE - retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (retval) { err("%s: Cannot check for power fault\n", __FUNCTION__); return retval; } pwr_fault = (u8)((slot_status & PWR_FAULT_DETECTED) >> 1); - - DBG_LEAVE_ROUTINE + return pwr_fault; } @@ -507,8 +449,6 @@ static int hpc_get_emi_status(struct slot *slot, u8 *status) u16 slot_status; int retval = 0; - DBG_ENTER_ROUTINE - retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (retval) { err("%s : Cannot check EMI status\n", __FUNCTION__); @@ -516,7 +456,6 @@ static int hpc_get_emi_status(struct slot *slot, u8 *status) } *status = (slot_status & EMI_STATE) >> EMI_STATUS_BIT; - DBG_LEAVE_ROUTINE return retval; } @@ -526,8 +465,6 @@ static int hpc_toggle_emi(struct slot *slot) u16 cmd_mask; int rc; - DBG_ENTER_ROUTINE - slot_cmd = EMI_CTRL; cmd_mask = EMI_CTRL; if (!pciehp_poll_mode) { @@ -537,7 +474,7 @@ static int hpc_toggle_emi(struct slot *slot) rc = pcie_write_cmd(slot, slot_cmd, cmd_mask); slot->last_emi_toggle = get_seconds(); - DBG_LEAVE_ROUTINE + return rc; } @@ -548,8 +485,6 @@ static int hpc_set_attention_status(struct slot *slot, u8 value) u16 cmd_mask; int rc; - DBG_ENTER_ROUTINE - cmd_mask = ATTN_LED_CTRL; switch (value) { case 0 : /* turn off */ @@ -572,19 +507,15 @@ static int hpc_set_attention_status(struct slot *slot, u8 value) rc = pcie_write_cmd(slot, slot_cmd, cmd_mask); dbg("%s: SLOTCTRL %x write cmd %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); - - DBG_LEAVE_ROUTINE + return rc; } - static void hpc_set_green_led_on(struct slot *slot) { struct controller *ctrl = slot->ctrl; u16 slot_cmd; u16 cmd_mask; - - DBG_ENTER_ROUTINE slot_cmd = 0x0100; cmd_mask = PWR_LED_CTRL; @@ -597,8 +528,6 @@ static void hpc_set_green_led_on(struct slot *slot) dbg("%s: SLOTCTRL %x write cmd %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); - DBG_LEAVE_ROUTINE - return; } static void hpc_set_green_led_off(struct slot *slot) @@ -607,8 +536,6 @@ static void hpc_set_green_led_off(struct slot *slot) u16 slot_cmd; u16 cmd_mask; - DBG_ENTER_ROUTINE - slot_cmd = 0x0300; cmd_mask = PWR_LED_CTRL; if (!pciehp_poll_mode) { @@ -619,9 +546,6 @@ static void hpc_set_green_led_off(struct slot *slot) pcie_write_cmd(slot, slot_cmd, cmd_mask); dbg("%s: SLOTCTRL %x write cmd %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); - - DBG_LEAVE_ROUTINE - return; } static void hpc_set_green_led_blink(struct slot *slot) @@ -629,8 +553,6 @@ static void hpc_set_green_led_blink(struct slot *slot) struct controller *ctrl = slot->ctrl; u16 slot_cmd; u16 cmd_mask; - - DBG_ENTER_ROUTINE slot_cmd = 0x0200; cmd_mask = PWR_LED_CTRL; @@ -643,14 +565,10 @@ static void hpc_set_green_led_blink(struct slot *slot) dbg("%s: SLOTCTRL %x write cmd %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); - DBG_LEAVE_ROUTINE - return; } static void hpc_release_ctlr(struct controller *ctrl) { - DBG_ENTER_ROUTINE - if (pciehp_poll_mode) del_timer(&ctrl->poll_timer); else @@ -662,8 +580,6 @@ static void hpc_release_ctlr(struct controller *ctrl) */ if (atomic_dec_and_test(&pciehp_num_controllers)) destroy_workqueue(pciehp_wq); - - DBG_LEAVE_ROUTINE } static int hpc_power_on_slot(struct slot * slot) @@ -674,8 +590,6 @@ static int hpc_power_on_slot(struct slot * slot) u16 slot_status; int retval = 0; - DBG_ENTER_ROUTINE - dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot); /* Clear sticky power-fault bit from previous power failures */ @@ -719,8 +633,6 @@ static int hpc_power_on_slot(struct slot * slot) dbg("%s: SLOTCTRL %x write cmd %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); - DBG_LEAVE_ROUTINE - return retval; } @@ -731,8 +643,6 @@ static int hpc_power_off_slot(struct slot * slot) u16 cmd_mask; int retval = 0; - DBG_ENTER_ROUTINE - dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot); slot_cmd = POWER_OFF; @@ -764,8 +674,6 @@ static int hpc_power_off_slot(struct slot * slot) dbg("%s: SLOTCTRL %x write cmd %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); - DBG_LEAVE_ROUTINE - return retval; } @@ -784,8 +692,8 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) return IRQ_NONE; } - intr_detect = ( ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED | MRL_SENS_CHANGED | - PRSN_DETECT_CHANGED | CMD_COMPLETED ); + intr_detect = (ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED | + MRL_SENS_CHANGED | PRSN_DETECT_CHANGED | CMD_COMPLETED); intr_loc = slot_status & intr_detect; @@ -807,7 +715,8 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) dbg("%s: pciehp_readw(SLOTCTRL) with value %x\n", __FUNCTION__, temp_word); - temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00; + temp_word = (temp_word & ~HP_INTR_ENABLE & + ~CMD_CMPL_INTR_ENABLE) | 0x00; rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); if (rc) { err("%s: Cannot write to SLOTCTRL register\n", @@ -825,7 +734,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) } dbg("%s: pciehp_readw(SLOTSTATUS) with value %x\n", __FUNCTION__, slot_status); - + /* Clear command complete interrupt caused by this write */ temp_word = 0x1f; rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); @@ -835,10 +744,10 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) return IRQ_NONE; } } - + if (intr_loc & CMD_COMPLETED) { - /* - * Command Complete Interrupt Pending + /* + * Command Complete Interrupt Pending */ ctrl->cmd_busy = 0; wake_up_interruptible(&ctrl->queue); @@ -892,7 +801,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) __FUNCTION__); return IRQ_NONE; } - + /* Clear command complete interrupt caused by this write */ temp_word = 0x1F; rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); @@ -904,19 +813,17 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) dbg("%s: pciehp_writew(SLOTSTATUS) with value %x\n", __FUNCTION__, temp_word); } - + return IRQ_HANDLED; } -static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value) +static int hpc_get_max_lnk_speed(struct slot *slot, enum pci_bus_speed *value) { struct controller *ctrl = slot->ctrl; enum pcie_link_speed lnk_speed; u32 lnk_cap; int retval = 0; - DBG_ENTER_ROUTINE - retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap); if (retval) { err("%s: Cannot read LNKCAP register\n", __FUNCTION__); @@ -934,19 +841,18 @@ static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value) *value = lnk_speed; dbg("Max link speed = %d\n", lnk_speed); - DBG_LEAVE_ROUTINE + return retval; } -static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value) +static int hpc_get_max_lnk_width(struct slot *slot, + enum pcie_link_width *value) { struct controller *ctrl = slot->ctrl; enum pcie_link_width lnk_wdth; u32 lnk_cap; int retval = 0; - DBG_ENTER_ROUTINE - retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap); if (retval) { err("%s: Cannot read LNKCAP register\n", __FUNCTION__); @@ -985,19 +891,17 @@ static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value *value = lnk_wdth; dbg("Max link width = %d\n", lnk_wdth); - DBG_LEAVE_ROUTINE + return retval; } -static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value) +static int hpc_get_cur_lnk_speed(struct slot *slot, enum pci_bus_speed *value) { struct controller *ctrl = slot->ctrl; enum pcie_link_speed lnk_speed = PCI_SPEED_UNKNOWN; int retval = 0; u16 lnk_status; - DBG_ENTER_ROUTINE - retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status); if (retval) { err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__); @@ -1015,25 +919,24 @@ static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value) *value = lnk_speed; dbg("Current link speed = %d\n", lnk_speed); - DBG_LEAVE_ROUTINE + return retval; } -static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value) +static int hpc_get_cur_lnk_width(struct slot *slot, + enum pcie_link_width *value) { struct controller *ctrl = slot->ctrl; enum pcie_link_width lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN; int retval = 0; u16 lnk_status; - DBG_ENTER_ROUTINE - retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status); if (retval) { err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__); return retval; } - + switch ((lnk_status & 0x03F0) >> 4){ case 0: lnk_wdth = PCIE_LNK_WIDTH_RESRV; @@ -1066,7 +969,7 @@ static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value *value = lnk_wdth; dbg("Current link width = %d\n", lnk_wdth); - DBG_LEAVE_ROUTINE + return retval; } @@ -1085,12 +988,12 @@ static struct hpc_ops pciehp_hpc_ops = { .get_cur_bus_speed = hpc_get_cur_lnk_speed, .get_max_lnk_width = hpc_get_max_lnk_width, .get_cur_lnk_width = hpc_get_cur_lnk_width, - + .query_power_fault = hpc_query_power_fault, .green_led_on = hpc_set_green_led_on, .green_led_off = hpc_set_green_led_off, .green_led_blink = hpc_set_green_led_blink, - + .release_ctlr = hpc_release_ctlr, .check_lnk_status = hpc_check_lnk_status, }; @@ -1138,6 +1041,7 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) dbg("Trying to get hotplug control for %s \n", (char *)string.pointer); status = pci_osc_control_set(handle, + OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL | OSC_PCI_EXPRESS_NATIVE_HP_CONTROL); if (status == AE_NOT_FOUND) status = acpi_run_oshp(handle); @@ -1163,8 +1067,6 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) } #endif - - int pcie_init(struct controller * ctrl, struct pcie_device *dev) { int rc; @@ -1176,8 +1078,6 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) u16 slot_status, slot_ctrl; struct pci_dev *pdev; - DBG_ENTER_ROUTINE - pdev = dev->port; ctrl->pci_dev = pdev; /* save pci_dev in context */ @@ -1201,9 +1101,11 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) dbg("%s: CAPREG offset %x cap_reg %x\n", __FUNCTION__, ctrl->cap_base + CAPREG, cap_reg); - if (((cap_reg & SLOT_IMPL) == 0) || (((cap_reg & DEV_PORT_TYPE) != 0x0040) + if (((cap_reg & SLOT_IMPL) == 0) || + (((cap_reg & DEV_PORT_TYPE) != 0x0040) && ((cap_reg & DEV_PORT_TYPE) != 0x0060))) { - dbg("%s : This is not a root port or the port is not connected to a slot\n", __FUNCTION__); + dbg("%s : This is not a root port or the port is not " + "connected to a slot\n", __FUNCTION__); goto abort_free_ctlr; } @@ -1236,14 +1138,15 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl); - for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++) + for (rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++) if (pci_resource_len(pdev, rc) > 0) dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc, (unsigned long long)pci_resource_start(pdev, rc), (unsigned long long)pci_resource_len(pdev, rc)); - info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, - pdev->subsystem_vendor, pdev->subsystem_device); + info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", + pdev->vendor, pdev->device, + pdev->subsystem_vendor, pdev->subsystem_device); mutex_init(&ctrl->crit_sect); mutex_init(&ctrl->ctrl_lock); @@ -1267,7 +1170,8 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) dbg("%s: SLOTCTRL %x value read %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, temp_word); - temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00; + temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | + 0x00; rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); if (rc) { @@ -1330,14 +1234,14 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) if (ATTN_BUTTN(slot_cap)) intr_enable = intr_enable | ATTN_BUTTN_ENABLE; - + if (POWER_CTRL(slot_cap)) intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE; - + if (MRL_SENS(slot_cap)) intr_enable = intr_enable | MRL_DETECT_ENABLE; - temp_word = (temp_word & ~intr_enable) | intr_enable; + temp_word = (temp_word & ~intr_enable) | intr_enable; if (pciehp_poll_mode) { temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0; @@ -1345,7 +1249,10 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE; } - /* Unmask Hot-plug Interrupt Enable for the interrupt notification mechanism case */ + /* + * Unmask Hot-plug Interrupt Enable for the interrupt + * notification mechanism case. + */ rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); if (rc) { err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); @@ -1356,14 +1263,14 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); goto abort_disable_intr; } - + temp_word = 0x1F; /* Clear all events */ rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); if (rc) { err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__); goto abort_disable_intr; } - + if (pciehp_force) { dbg("Bypassing BIOS check for pciehp use on %s\n", pci_name(ctrl->pci_dev)); @@ -1375,10 +1282,9 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) ctrl->hpc_ops = &pciehp_hpc_ops; - DBG_LEAVE_ROUTINE return 0; - /* We end up here for the many possible ways to fail this API. */ + /* We end up here for the many possible ways to fail this API. */ abort_disable_intr: rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); if (!rc) { @@ -1395,6 +1301,5 @@ abort_free_irq: free_irq(ctrl->pci_dev->irq, ctrl); abort_free_ctlr: - DBG_LEAVE_ROUTINE return -1; } diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c index 854aaea09e4d..c424aded13fb 100644 --- a/drivers/pci/hotplug/pciehp_pci.c +++ b/drivers/pci/hotplug/pciehp_pci.c @@ -243,9 +243,10 @@ int pciehp_configure_device(struct slot *p_slot) int pciehp_unconfigure_device(struct slot *p_slot) { - int rc = 0; + int ret, rc = 0; int j; u8 bctl = 0; + u8 presence = 0; struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus, @@ -263,23 +264,28 @@ int pciehp_unconfigure_device(struct slot *p_slot) continue; } if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl); - if (bctl & PCI_BRIDGE_CTL_VGA) { - err("Cannot remove display device %s\n", + ret = p_slot->hpc_ops->get_adapter_status(p_slot, + &presence); + if (!ret && presence) { + pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, + &bctl); + if (bctl & PCI_BRIDGE_CTL_VGA) { + err("Cannot remove display device %s\n", pci_name(temp)); - pci_dev_put(temp); - continue; + pci_dev_put(temp); + continue; + } } } pci_remove_bus_device(temp); pci_dev_put(temp); } - /* + /* * Some PCI Express root ports require fixup after hot-plug operation. */ - if (pcie_mch_quirk) + if (pcie_mch_quirk) pci_fixup_device(pci_fixup_final, p_slot->ctrl->pci_dev); - + return rc; } diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c index df076064a3e0..a080fedf0332 100644 --- a/drivers/pci/hotplug/rpadlpar_sysfs.c +++ b/drivers/pci/hotplug/rpadlpar_sysfs.c @@ -129,17 +129,17 @@ struct kobj_type ktype_dlpar_io = { }; struct kset dlpar_io_kset = { - .kobj = {.name = DLPAR_KOBJ_NAME, - .ktype = &ktype_dlpar_io, + .kobj = {.ktype = &ktype_dlpar_io, .parent = &pci_hotplug_slots_subsys.kobj}, .ktype = &ktype_dlpar_io, }; int dlpar_sysfs_init(void) { + kobject_set_name(&dlpar_io_kset.kobj, DLPAR_KOBJ_NAME); if (kset_register(&dlpar_io_kset)) { printk(KERN_ERR "rpadlpar_io: cannot register kset for %s\n", - dlpar_io_kset.kobj.name); + kobject_name(&dlpar_io_kset.kobj)); return -EINVAL; } diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index be1df85e5e2d..87e01615053d 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -132,7 +132,7 @@ void read_msi_msg(unsigned int irq, struct msi_msg *msg) pci_read_config_word(dev, msi_data_reg(pos, 1), &data); } else { msg->address_hi = 0; - pci_read_config_word(dev, msi_data_reg(pos, 1), &data); + pci_read_config_word(dev, msi_data_reg(pos, 0), &data); } msg->data = data; break; diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 004bc2487270..6e2760b6c20a 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -54,7 +54,6 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count) if (!dynid) return -ENOMEM; - INIT_LIST_HEAD(&dynid->node); dynid->id.vendor = vendor; dynid->id.device = device; dynid->id.subvendor = subvendor; @@ -65,7 +64,7 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count) driver_data : 0UL; spin_lock(&pdrv->dynids.lock); - list_add_tail(&pdrv->dynids.list, &dynid->node); + list_add_tail(&dynid->node, &pdrv->dynids.list); spin_unlock(&pdrv->dynids.lock); if (get_driver(&pdrv->driver)) { @@ -532,8 +531,7 @@ void pci_dev_put(struct pci_dev *dev) } #ifndef CONFIG_HOTPLUG -int pci_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +int pci_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 37c00f6fd801..71d561fda0a2 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -17,11 +17,16 @@ #include <linux/module.h> #include <linux/spinlock.h> #include <linux/string.h> +#include <linux/log2.h> #include <asm/dma.h> /* isa_dma_bridge_buggy */ #include "pci.h" unsigned int pci_pm_d3_delay = 10; +#ifdef CONFIG_PCI_DOMAINS +int pci_domains_supported = 1; +#endif + #define DEFAULT_CARDBUS_IO_SIZE (256) #define DEFAULT_CARDBUS_MEM_SIZE (64*1024*1024) /* pci=cbmemsize=nnM,cbiosize=nn can override this */ @@ -653,7 +658,7 @@ int pci_restore_state(struct pci_dev *dev) { int i; - int val; + u32 val; /* PCI Express register must be restored first */ pci_restore_pcie_state(dev); @@ -1454,7 +1459,7 @@ int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc) int cap, err = -EINVAL; u32 stat, cmd, v, o; - if (mmrbc < 512 || mmrbc > 4096 || (mmrbc & (mmrbc-1))) + if (mmrbc < 512 || mmrbc > 4096 || !is_power_of_2(mmrbc)) goto out; v = ffs(mmrbc) - 10; @@ -1526,7 +1531,7 @@ int pcie_set_readrq(struct pci_dev *dev, int rq) int cap, err = -EINVAL; u16 ctl, v; - if (rq < 128 || rq > 4096 || (rq & (rq-1))) + if (rq < 128 || rq > 4096 || !is_power_of_2(rq)) goto out; v = (ffs(rq) - 8) << 12; @@ -1566,6 +1571,13 @@ int pci_select_bars(struct pci_dev *dev, unsigned long flags) return bars; } +static void __devinit pci_no_domains(void) +{ +#ifdef CONFIG_PCI_DOMAINS + pci_domains_supported = 0; +#endif +} + static int __devinit pci_init(void) { struct pci_dev *dev = NULL; @@ -1585,6 +1597,10 @@ static int __devinit pci_setup(char *str) if (*str && (str = pcibios_setup(str)) && *str) { if (!strcmp(str, "nomsi")) { pci_no_msi(); + } else if (!strcmp(str, "noaer")) { + pci_no_aer(); + } else if (!strcmp(str, "nodomains")) { + pci_no_domains(); } else if (!strncmp(str, "cbiosize=", 9)) { pci_cardbus_io_size = memparse(str + 9, &str); } else if (!strncmp(str, "cbmemsize=", 10)) { diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 4c36e80f6d26..6fda33de84e8 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -1,7 +1,6 @@ /* Functions internal to the PCI core code */ -extern int pci_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size); +extern int pci_uevent(struct device *dev, struct kobj_uevent_env *env); extern int pci_create_sysfs_dev_files(struct pci_dev *pdev); extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev); extern void pci_cleanup_rom(struct pci_dev *dev); @@ -52,6 +51,12 @@ void pci_restore_msi_state(struct pci_dev *dev); static inline void pci_restore_msi_state(struct pci_dev *dev) {} #endif +#ifdef CONFIG_PCIEAER +void pci_no_aer(void); +#else +static inline void pci_no_aer(void) { } +#endif + static inline int pci_no_d1d2(struct pci_dev *dev) { unsigned int parent_dstates = 0; diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig index 0ad92a8ad8b1..287a9311716c 100644 --- a/drivers/pci/pcie/Kconfig +++ b/drivers/pci/pcie/Kconfig @@ -25,13 +25,4 @@ config HOTPLUG_PCI_PCIE When in doubt, say N. -config HOTPLUG_PCI_PCIE_POLL_EVENT_MODE - bool "Use polling mechanism for hot-plug events (for testing purpose)" - depends on HOTPLUG_PCI_PCIE - help - Say Y here if you want to use the polling mechanism for hot-plug - events for early platform testing. - - When in doubt, say N. - source "drivers/pci/pcie/aer/Kconfig" diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c index ad90a01b0dfc..7a62f7dd9009 100644 --- a/drivers/pci/pcie/aer/aerdrv.c +++ b/drivers/pci/pcie/aer/aerdrv.c @@ -81,6 +81,13 @@ static struct pcie_port_service_driver aerdriver = { .reset_link = aer_root_reset, }; +static int pcie_aer_disable; + +void pci_no_aer(void) +{ + pcie_aer_disable = 1; /* has priority over 'forceload' */ +} + /** * aer_irq - Root Port's ISR * @irq: IRQ assigned to Root Port @@ -327,6 +334,8 @@ static void aer_error_resume(struct pci_dev *dev) **/ static int __init aer_service_init(void) { + if (pcie_aer_disable) + return -ENXIO; return pcie_port_service_register(&aerdriver); } diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 171ca712e523..5db6b6690b59 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -276,8 +276,7 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) sz = pci_size(l, sz, (u32)PCI_ROM_ADDRESS_MASK); if (sz) { res->flags = (l & IORESOURCE_ROM_ENABLE) | - IORESOURCE_MEM | IORESOURCE_PREFETCH | - IORESOURCE_READONLY | IORESOURCE_CACHEABLE; + IORESOURCE_MEM | IORESOURCE_READONLY; res->start = l & PCI_ROM_ADDRESS_MASK; res->end = res->start + (unsigned long) sz; } @@ -597,7 +596,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses); if (!is_cardbus) { - child->bridge_ctl = bctl | PCI_BRIDGE_CTL_NO_ISA; + child->bridge_ctl = bctl; /* * Adjust subordinate busnr in parent buses. * We do this before scanning for children because @@ -744,22 +743,46 @@ static int pci_setup_device(struct pci_dev * dev) */ if (class == PCI_CLASS_STORAGE_IDE) { u8 progif; + struct pci_bus_region region; + 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; + struct resource resource = { + .start = 0x1F0, + .end = 0x1F7, + .flags = LEGACY_IO_RESOURCE, + }; + + pcibios_resource_to_bus(dev, ®ion, &resource); + dev->resource[0].start = region.start; + dev->resource[0].end = region.end; + dev->resource[0].flags = resource.flags; + resource.start = 0x3F6; + resource.end = 0x3F6; + resource.flags = LEGACY_IO_RESOURCE; + pcibios_resource_to_bus(dev, ®ion, &resource); + dev->resource[1].start = region.start; + dev->resource[1].end = region.end; + dev->resource[1].flags = resource.flags; } 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; + struct resource resource = { + .start = 0x170, + .end = 0x177, + .flags = LEGACY_IO_RESOURCE, + }; + + pcibios_resource_to_bus(dev, ®ion, &resource); + dev->resource[2].start = region.start; + dev->resource[2].end = region.end; + dev->resource[2].flags = resource.flags; + resource.start = 0x376; + resource.end = 0x376; + resource.flags = LEGACY_IO_RESOURCE; + pcibios_resource_to_bus(dev, ®ion, &resource); + dev->resource[3].start = region.start; + dev->resource[3].end = region.end; + dev->resource[3].flags = resource.flags; } } break; diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index 90adc62d07ff..716439e25dd2 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -60,7 +60,7 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp */ if (capable(CAP_SYS_ADMIN)) - size = dev->cfg_size; + size = dp->size; else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) size = 128; else @@ -129,11 +129,11 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp static ssize_t proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, loff_t *ppos) { - const struct inode *ino = file->f_path.dentry->d_inode; + struct inode *ino = file->f_path.dentry->d_inode; const struct proc_dir_entry *dp = PDE(ino); struct pci_dev *dev = dp->data; int pos = *ppos; - int size = dev->cfg_size; + int size = dp->size; int cnt; if (pos >= size) @@ -193,6 +193,7 @@ proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, lof } *ppos = pos; + i_size_write(ino, dp->size); return nbytes; } diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 50f2dd9e1bb2..59d4da2734c1 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -472,11 +472,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, quirk_ */ static void __devinit quirk_vt82c586_acpi(struct pci_dev *dev) { - u8 rev; u32 region; - pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev); - if (rev & 0x10) { + if (dev->revision & 0x10) { pci_read_config_dword(dev, 0x48, ®ion); region &= PCI_BASE_ADDRESS_IO_MASK; quirk_io_region(dev, region, 256, PCI_BRIDGE_RESOURCES, "vt82c586 ACPI"); @@ -629,12 +627,9 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk */ static void __init quirk_amd_8131_mmrbc(struct pci_dev *dev) { - unsigned char revid; - - pci_read_config_byte(dev, PCI_REVISION_ID, &revid); - if (dev->subordinate && revid <= 0x12) { + if (dev->subordinate && dev->revision <= 0x12) { printk(KERN_INFO "AMD8131 rev %x detected, disabling PCI-X " - "MMRBC\n", revid); + "MMRBC\n", dev->revision); dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MMRBC; } } @@ -930,38 +925,6 @@ static void __init quirk_eisa_bridge(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_eisa_bridge ); -/* - * On the MSI-K8T-Neo2Fir Board, the internal Soundcard is disabled - * when a PCI-Soundcard is added. The BIOS only gives Options - * "Disabled" and "AUTO". This Quirk Sets the corresponding - * Register-Value to enable the Soundcard. - * - * FIXME: Presently this quirk will run on anything that has an 8237 - * which isn't correct, we need to check DMI tables or something in - * order to make sure it only runs on the MSI-K8T-Neo2Fir. Because it - * runs everywhere at present we suppress the printk output in most - * irrelevant cases. - */ -static void k8t_sound_hostbridge(struct pci_dev *dev) -{ - unsigned char val; - - pci_read_config_byte(dev, 0x50, &val); - if (val == 0xc8) { - /* Assume it's probably a MSI-K8T-Neo2Fir */ - printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, attempting to turn soundcard ON\n"); - pci_write_config_byte(dev, 0x50, val & (~0x40)); - - /* Verify the Change for Status output */ - pci_read_config_byte(dev, 0x50, &val); - if (val & 0x40) - printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, soundcard still off\n"); - else - printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, soundcard on\n"); - } -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge); /* * On ASUS P4B boards, the SMBus PCI Device within the ICH2/4 southbridge diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 5e5191ec8de6..401e03c920bd 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -472,7 +472,12 @@ void pci_bus_size_bridges(struct pci_bus *bus) break; case PCI_CLASS_BRIDGE_PCI: + /* don't size subtractive decoding (transparent) + * PCI-to-PCI bridges */ + if (bus->self->transparent) + break; pci_bridge_check_ranges(bus); + /* fall through */ default: pbus_size_io(bus); /* If the bridge supports prefetchable range, size it diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c index 568f1877315c..05ca2ed9eb51 100644 --- a/drivers/pci/setup-irq.c +++ b/drivers/pci/setup-irq.c @@ -48,7 +48,7 @@ pdev_fixup_irq(struct pci_dev *dev, dev->irq = irq; pr_debug("PCI: fixup irq: (%s) got %d\n", - dev->dev.kobj.name, dev->irq); + kobject_name(&dev->dev.kobj), dev->irq); /* Always tell the device, so the driver knows what is the real IRQ to use; the device does not use it. */ diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index f8b13f0270d7..a0aca46ce877 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -907,18 +907,14 @@ int pcmcia_insert_card(struct pcmcia_socket *skt) EXPORT_SYMBOL(pcmcia_insert_card); -static int pcmcia_socket_uevent(struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size) +static int pcmcia_socket_uevent(struct device *dev, + struct kobj_uevent_env *env) { struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev); - int i = 0, length = 0; - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "SOCKET_NO=%u", s->sock)) + if (add_uevent_var(env, "SOCKET_NO=%u", s->sock)) return -ENOMEM; - envp[i] = NULL; - return 0; } diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index a99607142fc8..55baa1f0fcbb 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -1064,11 +1064,10 @@ static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) { #ifdef CONFIG_HOTPLUG -static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { struct pcmcia_device *p_dev; - int i, length = 0; + int i; u32 hash[4] = { 0, 0, 0, 0}; if (!dev) @@ -1083,23 +1082,13 @@ static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp, hash[i] = crc32(0, p_dev->prod_id[i], strlen(p_dev->prod_id[i])); } - i = 0; - - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "SOCKET_NO=%u", - p_dev->socket->sock)) + if (add_uevent_var(env, "SOCKET_NO=%u", p_dev->socket->sock)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEVICE_NO=%02X", - p_dev->device_no)) + if (add_uevent_var(env, "DEVICE_NO=%02X", p_dev->device_no)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X" + if (add_uevent_var(env, "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X" "pa%08Xpb%08Xpc%08Xpd%08X", p_dev->has_manf_id ? p_dev->manf_id : 0, p_dev->has_card_id ? p_dev->card_id : 0, @@ -1112,15 +1101,12 @@ static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp, hash[3])) return -ENOMEM; - envp[i] = NULL; - return 0; } #else -static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index 71b33707117f..839bb1c0db58 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c @@ -101,7 +101,7 @@ static int ignore = -1; /* Bit map or list of interrupts to choose from */ static u_int irq_mask = 0xffff; static int irq_list[16]; -static int irq_list_count; +static unsigned int irq_list_count; /* The card status change interrupt -- 0 means autoselect */ static int cs_irq = 0; diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c index dd0ddf19ee57..abc10fe49bd8 100644 --- a/drivers/pcmcia/pd6729.c +++ b/drivers/pcmcia/pd6729.c @@ -58,7 +58,7 @@ MODULE_AUTHOR("Jun Komuro <komurojun-mbn@nifty.com>"); static int irq_mode = 1; /* 0 = ISA interrupt, 1 = PCI interrupt */ static int irq_list[16]; -static int irq_list_count = 0; +static unsigned int irq_list_count = 0; module_param(irq_mode, int, 0444); module_param_array(irq_list, int, &irq_list_count, 0444); diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c index 36c671c5fb65..6fa5eaaab8af 100644 --- a/drivers/pcmcia/pxa2xx_mainstone.c +++ b/drivers/pcmcia/pxa2xx_mainstone.c @@ -157,7 +157,6 @@ static int __init mst_pcmcia_init(void) if (!mst_pcmcia_device) return -ENOMEM; - mst_pcmcia_device->dev.uevent_suppress = 0; mst_pcmcia_device->dev.platform_data = &mst_pcmcia_ops; ret = platform_device_add(mst_pcmcia_device); @@ -177,3 +176,4 @@ fs_initcall(mst_pcmcia_init); module_exit(mst_pcmcia_exit); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pxa2xx-pcmcia"); diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c index a2daa3f531b2..d5c33bd78d68 100644 --- a/drivers/pcmcia/pxa2xx_sharpsl.c +++ b/drivers/pcmcia/pxa2xx_sharpsl.c @@ -261,7 +261,6 @@ static int __init sharpsl_pcmcia_init(void) if (!sharpsl_pcmcia_device) return -ENOMEM; - sharpsl_pcmcia_device->dev.uevent_suppress = 0; sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops; sharpsl_pcmcia_device->dev.parent = platform_scoop_config->devs[0].dev; @@ -284,3 +283,4 @@ module_exit(sharpsl_pcmcia_exit); MODULE_DESCRIPTION("Sharp SL Series PCMCIA Support"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pxa2xx-pcmcia"); diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c index c158cf38b9dd..749ac3710914 100644 --- a/drivers/pcmcia/tcic.c +++ b/drivers/pcmcia/tcic.c @@ -90,7 +90,7 @@ static int do_scan = 1; /* Bit map of interrupts to choose from */ static u_int irq_mask = 0xffff; static int irq_list[16]; -static int irq_list_count; +static unsigned int irq_list_count; /* The card status change interrupt -- 0 means autoselect */ static int cs_irq; diff --git a/drivers/power/power_supply.h b/drivers/power/power_supply.h index a9880d468ee4..f38ba482be75 100644 --- a/drivers/power/power_supply.h +++ b/drivers/power/power_supply.h @@ -14,8 +14,7 @@ extern int power_supply_create_attrs(struct power_supply *psy); extern void power_supply_remove_attrs(struct power_supply *psy); -extern int power_supply_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size); +extern int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env); #else diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index de3155b21285..249f61bae639 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -195,11 +195,10 @@ static char *kstruprdup(const char *str, gfp_t gfp) return ret; } -int power_supply_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env) { struct power_supply *psy = dev_get_drvdata(dev); - int i = 0, length = 0, ret = 0, j; + int ret = 0, j; char *prop_buf; char *attrname; @@ -212,8 +211,7 @@ int power_supply_uevent(struct device *dev, char **envp, int num_envp, dev_dbg(dev, "POWER_SUPPLY_NAME=%s\n", psy->name); - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "POWER_SUPPLY_NAME=%s", psy->name); + ret = add_uevent_var(env, "POWER_SUPPLY_NAME=%s", psy->name); if (ret) return ret; @@ -243,9 +241,7 @@ int power_supply_uevent(struct device *dev, char **envp, int num_envp, dev_dbg(dev, "Static prop %s=%s\n", attrname, prop_buf); - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "POWER_SUPPLY_%s=%s", - attrname, prop_buf); + ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf); kfree(attrname); if (ret) goto out; @@ -282,14 +278,11 @@ int power_supply_uevent(struct device *dev, char **envp, int num_envp, dev_dbg(dev, "prop %s=%s\n", attrname, prop_buf); - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "POWER_SUPPLY_%s=%s", - attrname, prop_buf); + ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf); kfree(attrname); if (ret) goto out; } - envp[i] = NULL; out: free_page((unsigned long)prop_buf); diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 93ee05eeaeba..78277a118b67 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -1,7 +1,7 @@ /* * SuperH On-Chip RTC Support * - * Copyright (C) 2006 Paul Mundt + * Copyright (C) 2006, 2007 Paul Mundt * Copyright (C) 2006 Jamie Lenehan * * Based on the old arch/sh/kernel/cpu/rtc.c by: @@ -23,16 +23,19 @@ #include <linux/interrupt.h> #include <linux/spinlock.h> #include <linux/io.h> +#include <asm/rtc.h> #define DRV_NAME "sh-rtc" -#define DRV_VERSION "0.1.2" +#define DRV_VERSION "0.1.3" #ifdef CONFIG_CPU_SH3 #define rtc_reg_size sizeof(u16) #define RTC_BIT_INVERTED 0 /* No bug on SH7708, SH7709A */ +#define RTC_DEF_CAPABILITIES 0UL #elif defined(CONFIG_CPU_SH4) #define rtc_reg_size sizeof(u32) #define RTC_BIT_INVERTED 0x40 /* bug on SH7750, SH7750S */ +#define RTC_DEF_CAPABILITIES RTC_CAP_4_DIGIT_YEAR #endif #define RTC_REG(r) ((r) * rtc_reg_size) @@ -80,6 +83,7 @@ struct sh_rtc { struct rtc_device *rtc_dev; spinlock_t lock; int rearm_aie; + unsigned long capabilities; /* See asm-sh/rtc.h for cap bits */ }; static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id) @@ -319,14 +323,14 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm) tm->tm_mday = BCD2BIN(readb(rtc->regbase + RDAYCNT)); tm->tm_mon = BCD2BIN(readb(rtc->regbase + RMONCNT)) - 1; -#if defined(CONFIG_CPU_SH4) - yr = readw(rtc->regbase + RYRCNT); - yr100 = BCD2BIN(yr >> 8); - yr &= 0xff; -#else - yr = readb(rtc->regbase + RYRCNT); - yr100 = BCD2BIN((yr == 0x99) ? 0x19 : 0x20); -#endif + if (rtc->capabilities & RTC_CAP_4_DIGIT_YEAR) { + yr = readw(rtc->regbase + RYRCNT); + yr100 = BCD2BIN(yr >> 8); + yr &= 0xff; + } else { + yr = readb(rtc->regbase + RYRCNT); + yr100 = BCD2BIN((yr == 0x99) ? 0x19 : 0x20); + } tm->tm_year = (yr100 * 100 + BCD2BIN(yr)) - 1900; @@ -375,14 +379,14 @@ static int sh_rtc_set_time(struct device *dev, struct rtc_time *tm) writeb(BIN2BCD(tm->tm_mday), rtc->regbase + RDAYCNT); writeb(BIN2BCD(tm->tm_mon + 1), rtc->regbase + RMONCNT); -#ifdef CONFIG_CPU_SH3 - year = tm->tm_year % 100; - writeb(BIN2BCD(year), rtc->regbase + RYRCNT); -#else - year = (BIN2BCD((tm->tm_year + 1900) / 100) << 8) | - BIN2BCD(tm->tm_year % 100); - writew(year, rtc->regbase + RYRCNT); -#endif + if (rtc->capabilities & RTC_CAP_4_DIGIT_YEAR) { + year = (BIN2BCD((tm->tm_year + 1900) / 100) << 8) | + BIN2BCD(tm->tm_year % 100); + writew(year, rtc->regbase + RYRCNT); + } else { + year = tm->tm_year % 100; + writeb(BIN2BCD(year), rtc->regbase + RYRCNT); + } /* Start RTC */ tmp = readb(rtc->regbase + RCR2); @@ -589,6 +593,17 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) goto err_badmap; } + rtc->capabilities = RTC_DEF_CAPABILITIES; + if (pdev->dev.platform_data) { + struct sh_rtc_platform_info *pinfo = pdev->dev.platform_data; + + /* + * Some CPUs have special capabilities in addition to the + * default set. Add those in here. + */ + rtc->capabilities |= pinfo->capabilities; + } + platform_set_drvdata(pdev, rtc); return 0; diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index aeda52682446..d427daeef511 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -53,6 +53,7 @@ #include <linux/genhd.h> #include <linux/hdreg.h> #include <linux/interrupt.h> +#include <linux/log2.h> #include <asm/ccwdev.h> #include <linux/workqueue.h> #include <asm/debug.h> @@ -456,7 +457,7 @@ dasd_free_chunk(struct list_head *chunk_list, void *mem) static inline int dasd_check_blocksize(int bsize) { - if (bsize < 512 || bsize > 4096 || (bsize & (bsize - 1)) != 0) + if (bsize < 512 || bsize > 4096 || !is_power_of_2(bsize)) return -EMEDIUMTYPE; return 0; } diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 0fbacc8b1063..f231bc21b1ca 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -230,7 +230,7 @@ static int xpram_make_request(struct request_queue *q, struct bio *bio) } } set_bit(BIO_UPTODATE, &bio->bi_flags); - bio_end_io(bio, 0); + bio_endio(bio, 0); return 0; fail: bio_io_error(bio); diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 6000bdee4082..0e1f35c9ed9d 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -667,6 +667,9 @@ raw3215_probe (struct ccw_device *cdev) struct raw3215_info *raw; int line; + /* Console is special. */ + if (raw3215[0] && (cdev->dev.driver_data == raw3215[0])) + return 0; raw = kmalloc(sizeof(struct raw3215_info) + RAW3215_INBUF_SIZE, GFP_KERNEL|GFP_DMA); if (raw == NULL) diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c index fd3479119eb4..0b040557db02 100644 --- a/drivers/s390/char/con3270.c +++ b/drivers/s390/char/con3270.c @@ -22,6 +22,7 @@ #include <asm/ebcdic.h> #include "raw3270.h" +#include "tty3270.h" #include "ctrlchar.h" #define CON3270_OUTPUT_BUFFER_SIZE 1024 @@ -507,8 +508,6 @@ con3270_write(struct console *co, const char *str, unsigned int count) spin_unlock_irqrestore(&cp->view.lock,flags); } -extern struct tty_driver *tty3270_driver; - static struct tty_driver * con3270_device(struct console *c, int *index) { diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index fa62e6944057..25629b92dec3 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -93,6 +93,7 @@ static volatile enum sclp_mask_state_t { #define SCLP_RETRY_INTERVAL 30 static void sclp_process_queue(void); +static void __sclp_make_read_req(void); static int sclp_init_mask(int calculate); static int sclp_init(void); @@ -115,7 +116,6 @@ sclp_service_call(sclp_cmdw_t command, void *sccb) return 0; } -static inline void __sclp_make_read_req(void); static void __sclp_queue_read_req(void) @@ -318,8 +318,7 @@ sclp_read_cb(struct sclp_req *req, void *data) } /* Prepare read event data request. Called while sclp_lock is locked. */ -static inline void -__sclp_make_read_req(void) +static void __sclp_make_read_req(void) { struct sccb_header *sccb; diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index 9f244c591eeb..da25f8e24152 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -708,16 +708,22 @@ static void tape_3590_med_state_set(struct tape_device *device, c_info = &TAPE_3590_CRYPT_INFO(device); - if (sense->masst == MSENSE_UNASSOCIATED) { + DBF_EVENT(6, "medium state: %x:%x\n", sense->macst, sense->masst); + switch (sense->macst) { + case 0x04: + case 0x05: + case 0x06: tape_med_state_set(device, MS_UNLOADED); TAPE_3590_CRYPT_INFO(device).medium_status = 0; return; - } - if (sense->masst != MSENSE_ASSOCIATED_MOUNT) { - PRINT_ERR("Unknown medium state: %x\n", sense->masst); + case 0x08: + case 0x09: + tape_med_state_set(device, MS_LOADED); + break; + default: + tape_med_state_set(device, MS_UNKNOWN); return; } - tape_med_state_set(device, MS_LOADED); c_info->medium_status |= TAPE390_MEDIUM_LOADED_MASK; if (sense->flags & MSENSE_CRYPT_MASK) { PRINT_INFO("Medium is encrypted (%04x)\n", sense->flags); @@ -835,15 +841,17 @@ tape_3590_unsolicited_irq(struct tape_device *device, struct irb *irb) /* Probably result of halt ssch */ return TAPE_IO_PENDING; else if (irb->scsw.dstat == 0x85) - /* Device Ready -> check medium state */ - tape_3590_schedule_work(device, TO_MSEN); - else if (irb->scsw.dstat & DEV_STAT_ATTENTION) + /* Device Ready */ + DBF_EVENT(3, "unsol.irq! tape ready: %08x\n", device->cdev_id); + else if (irb->scsw.dstat & DEV_STAT_ATTENTION) { tape_3590_schedule_work(device, TO_READ_ATTMSG); - else { + } else { DBF_EVENT(3, "unsol.irq! dev end: %08x\n", device->cdev_id); PRINT_WARN("Unsolicited IRQ (Device End) caught.\n"); tape_dump_sense(device, NULL, irb); } + /* check medium state */ + tape_3590_schedule_work(device, TO_MSEN); return TAPE_IO_SUCCESS; } diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index bc33068b9ce2..70b1980a08b6 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -25,8 +25,8 @@ #include <asm/ebcdic.h> #include <asm/uaccess.h> - #include "raw3270.h" +#include "tty3270.h" #include "keyboard.h" #define TTY3270_CHAR_BUF_SIZE 256 @@ -1338,8 +1338,11 @@ tty3270_getpar(struct tty3270 *tp, int ix) static void tty3270_goto_xy(struct tty3270 *tp, int cx, int cy) { - tp->cx = min_t(int, tp->view.cols - 1, max_t(int, 0, cx)); - cy = min_t(int, tp->view.rows - 3, max_t(int, 0, cy)); + int max_cx = max(0, cx); + int max_cy = max(0, cy); + + tp->cx = min_t(int, tp->view.cols - 1, max_cx); + cy = min_t(int, tp->view.rows - 3, max_cy); if (cy != tp->cy) { tty3270_convert_line(tp, tp->cy); tp->cy = cy; diff --git a/drivers/s390/char/tty3270.h b/drivers/s390/char/tty3270.h new file mode 100644 index 000000000000..799da57f0390 --- /dev/null +++ b/drivers/s390/char/tty3270.h @@ -0,0 +1,16 @@ +/* + * drivers/s390/char/tty3270.h + * + * Copyright IBM Corp. 2007 + * + */ + +#ifndef __DRIVERS_S390_CHAR_TTY3270_H +#define __DRIVERS_S390_CHAR_TTY3270_H + +#include <linux/tty.h> +#include <linux/tty_driver.h> + +extern struct tty_driver *tty3270_driver; + +#endif /* __DRIVERS_S390_CHAR_TTY3270_H */ diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c index 680b9b58b80e..6f40facb1c4d 100644 --- a/drivers/s390/char/vmwatchdog.c +++ b/drivers/s390/char/vmwatchdog.c @@ -66,8 +66,8 @@ static int __diag288(enum vmwdt_func func, unsigned int timeout, "0: la %0,0\n" "1:\n" EX_TABLE(0b,1b) - : "=d" (err) : "d"(__func), "d"(__timeout), - "d"(__cmdp), "d"(__cmdl), "0" (-EINVAL) : "1", "cc"); + : "+d" (err) : "d"(__func), "d"(__timeout), + "d"(__cmdp), "d"(__cmdl) : "1", "cc"); return err; } diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index 3712ede16723..7073daf77981 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -141,15 +141,16 @@ static int memcpy_real(void *dest, unsigned long src, size_t count) if (count == 0) return 0; - flags = __raw_local_irq_stnsm(0xf8); /* switch to real mode */ + flags = __raw_local_irq_stnsm(0xf8UL); /* switch to real mode */ asm volatile ( "0: mvcle %1,%2,0x0\n" "1: jo 0b\n" " lhi %0,0x0\n" "2:\n" EX_TABLE(1b,2b) - : "+d" (rc) - : "d" (_dest), "d" (_src), "d" (_len1), "d" (_len2) + : "+d" (rc), "+d" (_dest), "+d" (_src), "+d" (_len1), + "+d" (_len2), "=m" (*((long*)dest)) + : "m" (*((long*)src)) : "cc", "memory"); __raw_local_irq_ssm(flags); diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index b0a18f5176aa..5baa517c3b66 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -44,8 +44,7 @@ ccwgroup_bus_match (struct device * dev, struct device_driver * drv) return 0; } static int -ccwgroup_uevent (struct device *dev, char **envp, int num_envp, char *buffer, - int buffer_size) +ccwgroup_uevent (struct device *dev, struct kobj_uevent_env *env) { /* TODO */ return 0; @@ -152,16 +151,24 @@ __ccwgroup_create_symlinks(struct ccwgroup_device *gdev) return 0; } -/* - * try to add a new ccwgroup device for one driver - * argc and argv[] are a list of bus_id's of devices - * belonging to the driver. +/** + * ccwgroup_create() - create and register a ccw group device + * @root: parent device for the new device + * @creator_id: identifier of creating driver + * @cdrv: ccw driver of slave devices + * @argc: number of slave devices + * @argv: bus ids of slave devices + * + * Create and register a new ccw group device as a child of @root. Slave + * devices are obtained from the list of bus ids given in @argv[] and must all + * belong to @cdrv. + * Returns: + * %0 on success and an error code on failure. + * Context: + * non-atomic */ -int -ccwgroup_create(struct device *root, - unsigned int creator_id, - struct ccw_driver *cdrv, - int argc, char *argv[]) +int ccwgroup_create(struct device *root, unsigned int creator_id, + struct ccw_driver *cdrv, int argc, char *argv[]) { struct ccwgroup_device *gdev; int i; @@ -390,8 +397,13 @@ static struct bus_type ccwgroup_bus_type = { .remove = ccwgroup_remove, }; -int -ccwgroup_driver_register (struct ccwgroup_driver *cdriver) +/** + * ccwgroup_driver_register() - register a ccw group driver + * @cdriver: driver to be registered + * + * This function is mainly a wrapper around driver_register(). + */ +int ccwgroup_driver_register(struct ccwgroup_driver *cdriver) { /* register our new driver with the core */ cdriver->driver.bus = &ccwgroup_bus_type; @@ -406,8 +418,13 @@ __ccwgroup_match_all(struct device *dev, void *data) return 1; } -void -ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver) +/** + * ccwgroup_driver_unregister() - deregister a ccw group driver + * @cdriver: driver to be deregistered + * + * This function is mainly a wrapper around driver_unregister(). + */ +void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver) { struct device *dev; @@ -427,8 +444,16 @@ ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver) driver_unregister(&cdriver->driver); } -int -ccwgroup_probe_ccwdev(struct ccw_device *cdev) +/** + * ccwgroup_probe_ccwdev() - probe function for slave devices + * @cdev: ccw device to be probed + * + * This is a dummy probe function for ccw devices that are slave devices in + * a ccw group device. + * Returns: + * always %0 + */ +int ccwgroup_probe_ccwdev(struct ccw_device *cdev) { return 0; } @@ -452,8 +477,15 @@ __ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev) return NULL; } -void -ccwgroup_remove_ccwdev(struct ccw_device *cdev) +/** + * ccwgroup_remove_ccwdev() - remove function for slave devices + * @cdev: ccw device to be removed + * + * This is a remove function for ccw devices that are slave devices in a ccw + * group device. It sets the ccw device offline and also deregisters the + * embedding ccw group device. + */ +void ccwgroup_remove_ccwdev(struct ccw_device *cdev) { struct ccwgroup_device *gdev; diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index 920dd71e6434..42c1f4659adb 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c @@ -14,7 +14,7 @@ #include <linux/jiffies.h> #include <linux/wait.h> #include <linux/mutex.h> -#include <asm/errno.h> +#include <linux/errno.h> #include <asm/chpid.h> #include <asm/sclp.h> @@ -55,7 +55,7 @@ static wait_queue_head_t cfg_wait_queue; /* Return channel_path struct for given chpid. */ static inline struct channel_path *chpid_to_chp(struct chp_id chpid) { - return css[chpid.cssid]->chps[chpid.id]; + return channel_subsystems[chpid.cssid]->chps[chpid.id]; } /* Set vary state for given chpid. */ @@ -86,7 +86,7 @@ u8 chp_get_sch_opm(struct subchannel *sch) opm = 0; chp_id_init(&chpid); - for (i=0; i < 8; i++) { + for (i = 0; i < 8; i++) { opm <<= 1; chpid.id = sch->schib.pmcw.chpid[i]; if (chp_get_status(chpid) != 0) @@ -118,7 +118,7 @@ static int s390_vary_chpid(struct chp_id chpid, int on) sprintf(dbf_text, on?"varyon%x.%02x":"varyoff%x.%02x", chpid.cssid, chpid.id); - CIO_TRACE_EVENT( 2, dbf_text); + CIO_TRACE_EVENT(2, dbf_text); status = chp_get_status(chpid); if (!on && !status) { @@ -140,9 +140,11 @@ static ssize_t chp_measurement_chars_read(struct kobject *kobj, char *buf, loff_t off, size_t count) { struct channel_path *chp; + struct device *device; unsigned int size; - chp = to_channelpath(container_of(kobj, struct device, kobj)); + device = container_of(kobj, struct device, kobj); + chp = to_channelpath(device); if (!chp->cmg_chars) return 0; @@ -193,9 +195,11 @@ static ssize_t chp_measurement_read(struct kobject *kobj, { struct channel_path *chp; struct channel_subsystem *css; + struct device *device; unsigned int size; - chp = to_channelpath(container_of(kobj, struct device, kobj)); + device = container_of(kobj, struct device, kobj); + chp = to_channelpath(device); css = to_css(chp->dev.parent); size = sizeof(struct cmg_entry); @@ -353,7 +357,7 @@ static ssize_t chp_shared_show(struct device *dev, static DEVICE_ATTR(shared, 0444, chp_shared_show, NULL); -static struct attribute * chp_attrs[] = { +static struct attribute *chp_attrs[] = { &dev_attr_status.attr, &dev_attr_configure.attr, &dev_attr_type.attr, @@ -395,7 +399,7 @@ int chp_new(struct chp_id chpid) /* fill in status, etc. */ chp->chpid = chpid; chp->state = 1; - chp->dev.parent = &css[chpid.cssid]->device; + chp->dev.parent = &channel_subsystems[chpid.cssid]->device; chp->dev.release = chp_release; snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp%x.%02x", chpid.cssid, chpid.id); @@ -430,18 +434,18 @@ int chp_new(struct chp_id chpid) device_unregister(&chp->dev); goto out_free; } - mutex_lock(&css[chpid.cssid]->mutex); - if (css[chpid.cssid]->cm_enabled) { + mutex_lock(&channel_subsystems[chpid.cssid]->mutex); + if (channel_subsystems[chpid.cssid]->cm_enabled) { ret = chp_add_cmg_attr(chp); if (ret) { sysfs_remove_group(&chp->dev.kobj, &chp_attr_group); device_unregister(&chp->dev); - mutex_unlock(&css[chpid.cssid]->mutex); + mutex_unlock(&channel_subsystems[chpid.cssid]->mutex); goto out_free; } } - css[chpid.cssid]->chps[chpid.id] = chp; - mutex_unlock(&css[chpid.cssid]->mutex); + channel_subsystems[chpid.cssid]->chps[chpid.id] = chp; + mutex_unlock(&channel_subsystems[chpid.cssid]->mutex); return ret; out_free: kfree(chp); diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index f2708d65be5a..46905345159e 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -619,6 +619,11 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) sch->schib.pmcw.ena = 0; if ((sch->lpm & (sch->lpm - 1)) != 0) sch->schib.pmcw.mp = 1; /* multipath mode */ + /* clean up possible residual cmf stuff */ + sch->schib.pmcw.mme = 0; + sch->schib.pmcw.mbfc = 0; + sch->schib.pmcw.mbi = 0; + sch->schib.mba = 0; return 0; out: if (!cio_is_console(schid)) diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index 34a796913b06..b960f66843e4 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -45,7 +45,8 @@ #include "ioasm.h" #include "chsc.h" -/* parameter to enable cmf during boot, possible uses are: +/* + * parameter to enable cmf during boot, possible uses are: * "s390cmf" -- enable cmf and allocate 2 MB of ram so measuring can be * used on any subchannel * "s390cmf=<num>" -- enable cmf and allocate enough memory to measure @@ -73,18 +74,20 @@ enum cmb_index { * enum cmb_format - types of supported measurement block formats * * @CMF_BASIC: traditional channel measurement blocks supported - * by all machines that we run on + * by all machines that we run on * @CMF_EXTENDED: improved format that was introduced with the z990 - * machine - * @CMF_AUTODETECT: default: use extended format when running on a z990 - * or later machine, otherwise fall back to basic format - **/ + * machine + * @CMF_AUTODETECT: default: use extended format when running on a machine + * supporting extended format, otherwise fall back to + * basic format + */ enum cmb_format { CMF_BASIC, CMF_EXTENDED, CMF_AUTODETECT = -1, }; -/** + +/* * format - actual format for all measurement blocks * * The format module parameter can be set to a value of 0 (zero) @@ -105,20 +108,21 @@ module_param(format, bool, 0444); * either with the help of a special pool or with kmalloc * @free: free memory allocated with @alloc * @set: enable or disable measurement + * @read: read a measurement entry at an index * @readall: read a measurement block in a common format * @reset: clear the data in the associated measurement block and * reset its time stamp * @align: align an allocated block so that the hardware can use it */ struct cmb_operations { - int (*alloc) (struct ccw_device*); - void(*free) (struct ccw_device*); - int (*set) (struct ccw_device*, u32); - u64 (*read) (struct ccw_device*, int); - int (*readall)(struct ccw_device*, struct cmbdata *); - void (*reset) (struct ccw_device*); - void * (*align) (void *); - + int (*alloc) (struct ccw_device *); + void (*free) (struct ccw_device *); + int (*set) (struct ccw_device *, u32); + u64 (*read) (struct ccw_device *, int); + int (*readall)(struct ccw_device *, struct cmbdata *); + void (*reset) (struct ccw_device *); + void *(*align) (void *); +/* private: */ struct attribute_group *attr_group; }; static struct cmb_operations *cmbops; @@ -130,9 +134,11 @@ struct cmb_data { unsigned long long last_update; /* when last_block was updated */ }; -/* our user interface is designed in terms of nanoseconds, +/* + * Our user interface is designed in terms of nanoseconds, * while the hardware measures total times in its own - * unit.*/ + * unit. + */ static inline u64 time_to_nsec(u32 value) { return ((u64)value) * 128000ull; @@ -159,12 +165,13 @@ static inline u64 time_to_avg_nsec(u32 value, u32 count) return ret; } -/* activate or deactivate the channel monitor. When area is NULL, +/* + * Activate or deactivate the channel monitor. When area is NULL, * the monitor is deactivated. The channel monitor needs to * be active in order to measure subchannels, which also need - * to be enabled. */ -static inline void -cmf_activate(void *area, unsigned int onoff) + * to be enabled. + */ +static inline void cmf_activate(void *area, unsigned int onoff) { register void * __gpr2 asm("2"); register long __gpr1 asm("1"); @@ -175,8 +182,8 @@ cmf_activate(void *area, unsigned int onoff) asm("schm" : : "d" (__gpr2), "d" (__gpr1) ); } -static int -set_schib(struct ccw_device *cdev, u32 mme, int mbfc, unsigned long address) +static int set_schib(struct ccw_device *cdev, u32 mme, int mbfc, + unsigned long address) { int ret; int retry; @@ -466,6 +473,7 @@ static void cmf_generic_reset(struct ccw_device *cdev) * * @mem: pointer to CMBs (only in basic measurement mode) * @list: contains a linked list of all subchannels + * @num_channels: number of channels to be measured * @lock: protect concurrent access to @mem and @list */ struct cmb_area { @@ -481,28 +489,36 @@ static struct cmb_area cmb_area = { .num_channels = 1024, }; - /* ****** old style CMB handling ********/ -/** int maxchannels - * +/* * Basic channel measurement blocks are allocated in one contiguous * block of memory, which can not be moved as long as any channel * is active. Therefore, a maximum number of subchannels needs to * be defined somewhere. This is a module parameter, defaulting to * a resonable value of 1024, or 32 kb of memory. * Current kernels don't allow kmalloc with more than 128kb, so the - * maximum is 4096 + * maximum is 4096. */ module_param_named(maxchannels, cmb_area.num_channels, uint, 0444); /** * struct cmb - basic channel measurement block + * @ssch_rsch_count: number of ssch and rsch + * @sample_count: number of samples + * @device_connect_time: time of device connect + * @function_pending_time: time of function pending + * @device_disconnect_time: time of device disconnect + * @control_unit_queuing_time: time of control unit queuing + * @device_active_only_time: time of device active only + * @reserved: unused in basic measurement mode + * + * The measurement block as used by the hardware. The fields are described + * further in z/Architecture Principles of Operation, chapter 17. * - * cmb as used by the hardware the fields are described in z/Architecture - * Principles of Operation, chapter 17. - * The area to be a contiguous array and may not be reallocated or freed. + * The cmb area made up from these blocks must be a contiguous array and may + * not be reallocated or freed. * Only one cmb area can be present in the system. */ struct cmb { @@ -516,8 +532,9 @@ struct cmb { u32 reserved[2]; }; -/* insert a single device into the cmb_area list - * called with cmb_area.lock held from alloc_cmb +/* + * Insert a single device into the cmb_area list. + * Called with cmb_area.lock held from alloc_cmb. */ static int alloc_cmb_single(struct ccw_device *cdev, struct cmb_data *cmb_data) @@ -532,9 +549,11 @@ static int alloc_cmb_single(struct ccw_device *cdev, goto out; } - /* find first unused cmb in cmb_area.mem. - * this is a little tricky: cmb_area.list - * remains sorted by ->cmb->hw_data pointers */ + /* + * Find first unused cmb in cmb_area.mem. + * This is a little tricky: cmb_area.list + * remains sorted by ->cmb->hw_data pointers. + */ cmb = cmb_area.mem; list_for_each_entry(node, &cmb_area.list, cmb_list) { struct cmb_data *data; @@ -558,8 +577,7 @@ out: return ret; } -static int -alloc_cmb (struct ccw_device *cdev) +static int alloc_cmb(struct ccw_device *cdev) { int ret; struct cmb *mem; @@ -670,7 +688,7 @@ static int set_cmb(struct ccw_device *cdev, u32 mme) return set_schib_wait(cdev, mme, 0, offset); } -static u64 read_cmb (struct ccw_device *cdev, int index) +static u64 read_cmb(struct ccw_device *cdev, int index) { struct cmb *cmb; u32 val; @@ -720,7 +738,7 @@ out: return ret; } -static int readall_cmb (struct ccw_device *cdev, struct cmbdata *data) +static int readall_cmb(struct ccw_device *cdev, struct cmbdata *data) { struct cmb *cmb; struct cmb_data *cmb_data; @@ -793,14 +811,25 @@ static struct cmb_operations cmbops_basic = { .align = align_cmb, .attr_group = &cmf_attr_group, }; - + /* ******** extended cmb handling ********/ /** * struct cmbe - extended channel measurement block + * @ssch_rsch_count: number of ssch and rsch + * @sample_count: number of samples + * @device_connect_time: time of device connect + * @function_pending_time: time of function pending + * @device_disconnect_time: time of device disconnect + * @control_unit_queuing_time: time of control unit queuing + * @device_active_only_time: time of device active only + * @device_busy_time: time of device busy + * @initial_command_response_time: initial command response time + * @reserved: unused * - * cmb as used by the hardware, may be in any 64 bit physical location, - * the fields are described in z/Architecture Principles of Operation, + * The measurement block as used by the hardware. May be in any 64 bit physical + * location. + * The fields are described further in z/Architecture Principles of Operation, * third edition, chapter 17. */ struct cmbe { @@ -816,10 +845,12 @@ struct cmbe { u32 reserved[7]; }; -/* kmalloc only guarantees 8 byte alignment, but we need cmbe +/* + * kmalloc only guarantees 8 byte alignment, but we need cmbe * pointers to be naturally aligned. Make sure to allocate - * enough space for two cmbes */ -static inline struct cmbe* cmbe_align(struct cmbe *c) + * enough space for two cmbes. + */ +static inline struct cmbe *cmbe_align(struct cmbe *c) { unsigned long addr; addr = ((unsigned long)c + sizeof (struct cmbe) - sizeof(long)) & @@ -827,7 +858,7 @@ static inline struct cmbe* cmbe_align(struct cmbe *c) return (struct cmbe*)addr; } -static int alloc_cmbe (struct ccw_device *cdev) +static int alloc_cmbe(struct ccw_device *cdev) { struct cmbe *cmbe; struct cmb_data *cmb_data; @@ -873,7 +904,7 @@ out_free: return ret; } -static void free_cmbe (struct ccw_device *cdev) +static void free_cmbe(struct ccw_device *cdev) { struct cmb_data *cmb_data; @@ -912,7 +943,7 @@ static int set_cmbe(struct ccw_device *cdev, u32 mme) } -static u64 read_cmbe (struct ccw_device *cdev, int index) +static u64 read_cmbe(struct ccw_device *cdev, int index) { struct cmbe *cmb; struct cmb_data *cmb_data; @@ -970,7 +1001,7 @@ out: return ret; } -static int readall_cmbe (struct ccw_device *cdev, struct cmbdata *data) +static int readall_cmbe(struct ccw_device *cdev, struct cmbdata *data) { struct cmbe *cmb; struct cmb_data *cmb_data; @@ -1047,17 +1078,16 @@ static struct cmb_operations cmbops_extended = { .align = align_cmbe, .attr_group = &cmf_attr_group_ext, }; - -static ssize_t -cmb_show_attr(struct device *dev, char *buf, enum cmb_index idx) +static ssize_t cmb_show_attr(struct device *dev, char *buf, enum cmb_index idx) { return sprintf(buf, "%lld\n", (unsigned long long) cmf_read(to_ccwdev(dev), idx)); } -static ssize_t -cmb_show_avg_sample_interval(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t cmb_show_avg_sample_interval(struct device *dev, + struct device_attribute *attr, + char *buf) { struct ccw_device *cdev; long interval; @@ -1079,8 +1109,9 @@ cmb_show_avg_sample_interval(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%ld\n", interval); } -static ssize_t -cmb_show_avg_utilization(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t cmb_show_avg_utilization(struct device *dev, + struct device_attribute *attr, + char *buf) { struct cmbdata data; u64 utilization; @@ -1112,14 +1143,16 @@ cmb_show_avg_utilization(struct device *dev, struct device_attribute *attr, char } #define cmf_attr(name) \ -static ssize_t show_ ## name (struct device * dev, struct device_attribute *attr, char * buf) \ -{ return cmb_show_attr((dev), buf, cmb_ ## name); } \ -static DEVICE_ATTR(name, 0444, show_ ## name, NULL); +static ssize_t show_##name(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ return cmb_show_attr((dev), buf, cmb_##name); } \ +static DEVICE_ATTR(name, 0444, show_##name, NULL); #define cmf_attr_avg(name) \ -static ssize_t show_avg_ ## name (struct device * dev, struct device_attribute *attr, char * buf) \ -{ return cmb_show_attr((dev), buf, cmb_ ## name); } \ -static DEVICE_ATTR(avg_ ## name, 0444, show_avg_ ## name, NULL); +static ssize_t show_avg_##name(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ return cmb_show_attr((dev), buf, cmb_##name); } \ +static DEVICE_ATTR(avg_##name, 0444, show_avg_##name, NULL); cmf_attr(ssch_rsch_count); cmf_attr(sample_count); @@ -1131,7 +1164,8 @@ cmf_attr_avg(device_active_only_time); cmf_attr_avg(device_busy_time); cmf_attr_avg(initial_command_response_time); -static DEVICE_ATTR(avg_sample_interval, 0444, cmb_show_avg_sample_interval, NULL); +static DEVICE_ATTR(avg_sample_interval, 0444, cmb_show_avg_sample_interval, + NULL); static DEVICE_ATTR(avg_utilization, 0444, cmb_show_avg_utilization, NULL); static struct attribute *cmf_attributes[] = { @@ -1172,12 +1206,16 @@ static struct attribute_group cmf_attr_group_ext = { .attrs = cmf_attributes_ext, }; -static ssize_t cmb_enable_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t cmb_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) { return sprintf(buf, "%d\n", to_ccwdev(dev)->private->cmb ? 1 : 0); } -static ssize_t cmb_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t c) +static ssize_t cmb_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t c) { struct ccw_device *cdev; int ret; @@ -1202,9 +1240,16 @@ static ssize_t cmb_enable_store(struct device *dev, struct device_attribute *att DEVICE_ATTR(cmb_enable, 0644, cmb_enable_show, cmb_enable_store); -/* enable_cmf/disable_cmf: module interface for cmf (de)activation */ -int -enable_cmf(struct ccw_device *cdev) +/** + * enable_cmf() - switch on the channel measurement for a specific device + * @cdev: The ccw device to be enabled + * + * Returns %0 for success or a negative error value. + * + * Context: + * non-atomic + */ +int enable_cmf(struct ccw_device *cdev) { int ret; @@ -1225,8 +1270,16 @@ enable_cmf(struct ccw_device *cdev) return ret; } -int -disable_cmf(struct ccw_device *cdev) +/** + * disable_cmf() - switch off the channel measurement for a specific device + * @cdev: The ccw device to be disabled + * + * Returns %0 for success or a negative error value. + * + * Context: + * non-atomic + */ +int disable_cmf(struct ccw_device *cdev) { int ret; @@ -1238,14 +1291,32 @@ disable_cmf(struct ccw_device *cdev) return ret; } -u64 -cmf_read(struct ccw_device *cdev, int index) +/** + * cmf_read() - read one value from the current channel measurement block + * @cdev: the channel to be read + * @index: the index of the value to be read + * + * Returns the value read or %0 if the value cannot be read. + * + * Context: + * any + */ +u64 cmf_read(struct ccw_device *cdev, int index) { return cmbops->read(cdev, index); } -int -cmf_readall(struct ccw_device *cdev, struct cmbdata *data) +/** + * cmf_readall() - read the current channel measurement block + * @cdev: the channel to be read + * @data: a pointer to a data block that will be filled + * + * Returns %0 on success, a negative error value otherwise. + * + * Context: + * any + */ +int cmf_readall(struct ccw_device *cdev, struct cmbdata *data) { return cmbops->readall(cdev, data); } @@ -1257,15 +1328,16 @@ int cmf_reenable(struct ccw_device *cdev) return cmbops->set(cdev, 2); } -static int __init -init_cmf(void) +static int __init init_cmf(void) { char *format_string; char *detect_string = "parameter"; - /* We cannot really autoprobe this. If the user did not give a parameter, - see if we are running on z990 or up, otherwise fall back to basic mode. */ - + /* + * If the user did not give a parameter, see if we are running on a + * machine supporting extended measurement blocks, otherwise fall back + * to basic mode. + */ if (format == CMF_AUTODETECT) { if (!css_characteristics_avail || !css_general_characteristics.ext_mb) { @@ -1284,7 +1356,7 @@ init_cmf(void) cmbops = &cmbops_basic; break; case CMF_EXTENDED: - format_string = "extended"; + format_string = "extended"; cmbops = &cmbops_extended; break; default: diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 5635e656c1a3..5d83dd471461 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -13,6 +13,7 @@ #include <linux/slab.h> #include <linux/errno.h> #include <linux/list.h> +#include <linux/reboot.h> #include "css.h" #include "cio.h" @@ -27,7 +28,7 @@ int css_init_done = 0; static int need_reprobe = 0; static int max_ssid = 0; -struct channel_subsystem *css[__MAX_CSSID + 1]; +struct channel_subsystem *channel_subsystems[__MAX_CSSID + 1]; int css_characteristics_avail = 0; @@ -177,7 +178,7 @@ static int css_register_subchannel(struct subchannel *sch) int ret; /* Initialize the subchannel structure */ - sch->dev.parent = &css[0]->device; + sch->dev.parent = &channel_subsystems[0]->device; sch->dev.bus = &css_bus_type; sch->dev.release = &css_subchannel_release; sch->dev.groups = subch_attr_groups; @@ -606,30 +607,55 @@ static int __init setup_css(int nr) { u32 tod_high; int ret; + struct channel_subsystem *css; - memset(css[nr], 0, sizeof(struct channel_subsystem)); - css[nr]->pseudo_subchannel = - kzalloc(sizeof(*css[nr]->pseudo_subchannel), GFP_KERNEL); - if (!css[nr]->pseudo_subchannel) + css = channel_subsystems[nr]; + memset(css, 0, sizeof(struct channel_subsystem)); + css->pseudo_subchannel = + kzalloc(sizeof(*css->pseudo_subchannel), GFP_KERNEL); + if (!css->pseudo_subchannel) return -ENOMEM; - css[nr]->pseudo_subchannel->dev.parent = &css[nr]->device; - css[nr]->pseudo_subchannel->dev.release = css_subchannel_release; - sprintf(css[nr]->pseudo_subchannel->dev.bus_id, "defunct"); - ret = cio_create_sch_lock(css[nr]->pseudo_subchannel); + css->pseudo_subchannel->dev.parent = &css->device; + css->pseudo_subchannel->dev.release = css_subchannel_release; + sprintf(css->pseudo_subchannel->dev.bus_id, "defunct"); + ret = cio_create_sch_lock(css->pseudo_subchannel); if (ret) { - kfree(css[nr]->pseudo_subchannel); + kfree(css->pseudo_subchannel); return ret; } - mutex_init(&css[nr]->mutex); - css[nr]->valid = 1; - css[nr]->cssid = nr; - sprintf(css[nr]->device.bus_id, "css%x", nr); - css[nr]->device.release = channel_subsystem_release; + mutex_init(&css->mutex); + css->valid = 1; + css->cssid = nr; + sprintf(css->device.bus_id, "css%x", nr); + css->device.release = channel_subsystem_release; tod_high = (u32) (get_clock() >> 32); - css_generate_pgid(css[nr], tod_high); + css_generate_pgid(css, tod_high); return 0; } +static int css_reboot_event(struct notifier_block *this, + unsigned long event, + void *ptr) +{ + int ret, i; + + ret = NOTIFY_DONE; + for (i = 0; i <= __MAX_CSSID; i++) { + struct channel_subsystem *css; + + css = channel_subsystems[i]; + if (css->cm_enabled) + if (chsc_secm(css, 0)) + ret = NOTIFY_BAD; + } + + return ret; +} + +static struct notifier_block css_reboot_notifier = { + .notifier_call = css_reboot_event, +}; + /* * Now that the driver core is running, we can setup our channel subsystem. * The struct subchannel's are created during probing (except for the @@ -670,51 +696,63 @@ init_channel_subsystem (void) } /* Setup css structure. */ for (i = 0; i <= __MAX_CSSID; i++) { - css[i] = kmalloc(sizeof(struct channel_subsystem), GFP_KERNEL); - if (!css[i]) { + struct channel_subsystem *css; + + css = kmalloc(sizeof(struct channel_subsystem), GFP_KERNEL); + if (!css) { ret = -ENOMEM; goto out_unregister; } + channel_subsystems[i] = css; ret = setup_css(i); if (ret) goto out_free; - ret = device_register(&css[i]->device); + ret = device_register(&css->device); if (ret) goto out_free_all; if (css_characteristics_avail && css_chsc_characteristics.secm) { - ret = device_create_file(&css[i]->device, + ret = device_create_file(&css->device, &dev_attr_cm_enable); if (ret) goto out_device; } - ret = device_register(&css[i]->pseudo_subchannel->dev); + ret = device_register(&css->pseudo_subchannel->dev); if (ret) goto out_file; } + ret = register_reboot_notifier(&css_reboot_notifier); + if (ret) + goto out_pseudo; css_init_done = 1; ctl_set_bit(6, 28); for_each_subchannel(__init_channel_subsystem, NULL); return 0; +out_pseudo: + device_unregister(&channel_subsystems[i]->pseudo_subchannel->dev); out_file: - device_remove_file(&css[i]->device, &dev_attr_cm_enable); + device_remove_file(&channel_subsystems[i]->device, + &dev_attr_cm_enable); out_device: - device_unregister(&css[i]->device); + device_unregister(&channel_subsystems[i]->device); out_free_all: - kfree(css[i]->pseudo_subchannel->lock); - kfree(css[i]->pseudo_subchannel); + kfree(channel_subsystems[i]->pseudo_subchannel->lock); + kfree(channel_subsystems[i]->pseudo_subchannel); out_free: - kfree(css[i]); + kfree(channel_subsystems[i]); out_unregister: while (i > 0) { + struct channel_subsystem *css; + i--; - device_unregister(&css[i]->pseudo_subchannel->dev); + css = channel_subsystems[i]; + device_unregister(&css->pseudo_subchannel->dev); if (css_characteristics_avail && css_chsc_characteristics.secm) - device_remove_file(&css[i]->device, + device_remove_file(&css->device, &dev_attr_cm_enable); - device_unregister(&css[i]->device); + device_unregister(&css->device); } out_bus: bus_unregister(&css_bus_type); diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index 5d65e83ca66e..81215ef32435 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h @@ -167,7 +167,7 @@ struct channel_subsystem { #define to_css(dev) container_of(dev, struct channel_subsystem, device) extern struct bus_type css_bus_type; -extern struct channel_subsystem *css[]; +extern struct channel_subsystem *channel_subsystems[]; /* Some helper functions for disconnected state. */ int device_is_disconnected(struct subchannel *); @@ -191,6 +191,5 @@ int sch_is_pseudo_sch(struct subchannel *); extern struct workqueue_struct *slow_path_wq; -int subchannel_add_files (struct device *); extern struct attribute_group *subch_attr_groups[]; #endif diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index e44d92eac8e9..7ee57f084a89 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -21,6 +21,7 @@ #include <asm/ccwdev.h> #include <asm/cio.h> #include <asm/param.h> /* HZ */ +#include <asm/cmb.h> #include "cio.h" #include "cio_debug.h" @@ -78,49 +79,38 @@ static int snprint_alias(char *buf, size_t size, /* Set up environment variables for ccw device uevent. Return 0 on success, * non-zero otherwise. */ -static int ccw_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int ccw_uevent(struct device *dev, struct kobj_uevent_env *env) { struct ccw_device *cdev = to_ccwdev(dev); struct ccw_device_id *id = &(cdev->id); - int i = 0; - int len = 0; int ret; char modalias_buf[30]; /* CU_TYPE= */ - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "CU_TYPE=%04X", id->cu_type); + ret = add_uevent_var(env, "CU_TYPE=%04X", id->cu_type); if (ret) return ret; /* CU_MODEL= */ - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "CU_MODEL=%02X", id->cu_model); + ret = add_uevent_var(env, "CU_MODEL=%02X", id->cu_model); if (ret) return ret; /* The next two can be zero, that's ok for us */ /* DEV_TYPE= */ - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "DEV_TYPE=%04X", id->dev_type); + ret = add_uevent_var(env, "DEV_TYPE=%04X", id->dev_type); if (ret) return ret; /* DEV_MODEL= */ - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "DEV_MODEL=%02X", id->dev_model); + ret = add_uevent_var(env, "DEV_MODEL=%02X", id->dev_model); if (ret) return ret; /* MODALIAS= */ snprint_alias(modalias_buf, sizeof(modalias_buf), id, ""); - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "MODALIAS=%s", modalias_buf); - if (ret) - return ret; - envp[i] = NULL; - return 0; + ret = add_uevent_var(env, "MODALIAS=%s", modalias_buf); + return ret; } struct bus_type ccw_bus_type; @@ -357,8 +347,18 @@ ccw_device_remove_disconnected(struct ccw_device *cdev) cdev->private->dev_id.devno); } -int -ccw_device_set_offline(struct ccw_device *cdev) +/** + * ccw_device_set_offline() - disable a ccw device for I/O + * @cdev: target ccw device + * + * This function calls the driver's set_offline() function for @cdev, if + * given, and then disables @cdev. + * Returns: + * %0 on success and a negative error value on failure. + * Context: + * enabled, ccw device lock not held + */ +int ccw_device_set_offline(struct ccw_device *cdev) { int ret; @@ -396,8 +396,19 @@ ccw_device_set_offline(struct ccw_device *cdev) return ret; } -int -ccw_device_set_online(struct ccw_device *cdev) +/** + * ccw_device_set_online() - enable a ccw device for I/O + * @cdev: target ccw device + * + * This function first enables @cdev and then calls the driver's set_online() + * function for @cdev, if given. If set_online() returns an error, @cdev is + * disabled again. + * Returns: + * %0 on success and a negative error value on failure. + * Context: + * enabled, ccw device lock not held + */ +int ccw_device_set_online(struct ccw_device *cdev) { int ret; @@ -947,8 +958,7 @@ out: wake_up(&ccw_device_init_wq); } -void -ccw_device_call_sch_unregister(struct work_struct *work) +static void ccw_device_call_sch_unregister(struct work_struct *work) { struct ccw_device_private *priv; struct ccw_device *cdev; @@ -1101,6 +1111,7 @@ io_subchannel_probe (struct subchannel *sch) * device, e.g. the console. */ cdev = sch->dev.driver_data; + cdev->dev.groups = ccwdev_attr_groups; device_initialize(&cdev->dev); ccw_device_register(cdev); /* @@ -1326,8 +1337,19 @@ __ccwdev_check_busid(struct device *dev, void *id) } -struct ccw_device * -get_ccwdev_by_busid(struct ccw_driver *cdrv, const char *bus_id) +/** + * get_ccwdev_by_busid() - obtain device from a bus id + * @cdrv: driver the device is owned by + * @bus_id: bus id of the device to be searched + * + * This function searches all devices owned by @cdrv for a device with a bus + * id matching @bus_id. + * Returns: + * If a match is found, its reference count of the found device is increased + * and it is returned; else %NULL is returned. + */ +struct ccw_device *get_ccwdev_by_busid(struct ccw_driver *cdrv, + const char *bus_id) { struct device *dev; struct device_driver *drv; @@ -1401,16 +1423,34 @@ ccw_device_remove (struct device *dev) return 0; } +static void ccw_device_shutdown(struct device *dev) +{ + struct ccw_device *cdev; + + cdev = to_ccwdev(dev); + if (cdev->drv && cdev->drv->shutdown) + cdev->drv->shutdown(cdev); + disable_cmf(cdev); +} + struct bus_type ccw_bus_type = { .name = "ccw", .match = ccw_bus_match, .uevent = ccw_uevent, .probe = ccw_device_probe, .remove = ccw_device_remove, + .shutdown = ccw_device_shutdown, }; -int -ccw_driver_register (struct ccw_driver *cdriver) +/** + * ccw_driver_register() - register a ccw driver + * @cdriver: driver to be registered + * + * This function is mainly a wrapper around driver_register(). + * Returns: + * %0 on success and a negative error value on failure. + */ +int ccw_driver_register(struct ccw_driver *cdriver) { struct device_driver *drv = &cdriver->driver; @@ -1420,8 +1460,13 @@ ccw_driver_register (struct ccw_driver *cdriver) return driver_register(drv); } -void -ccw_driver_unregister (struct ccw_driver *cdriver) +/** + * ccw_driver_unregister() - deregister a ccw driver + * @cdriver: driver to be deregistered + * + * This function is mainly a wrapper around driver_unregister(). + */ +void ccw_driver_unregister(struct ccw_driver *cdriver) { driver_unregister(&cdriver->driver); } diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index b66338b76579..0d4089600439 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h @@ -80,7 +80,6 @@ void io_subchannel_recog_done(struct ccw_device *cdev); int ccw_device_cancel_halt_clear(struct ccw_device *); void ccw_device_do_unreg_rereg(struct work_struct *); -void ccw_device_call_sch_unregister(struct work_struct *); void ccw_device_move_to_orphanage(struct work_struct *); int ccw_device_is_orphan(struct ccw_device *); diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 8633dc537695..8867443b8060 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -446,7 +446,8 @@ static void __ccw_device_get_common_pgid(struct ccw_device *cdev) if (cdev->private->pgid[last].inf.ps.state1 == SNID_STATE1_RESET) /* No previous pgid found */ - memcpy(&cdev->private->pgid[0], &css[0]->global_pgid, + memcpy(&cdev->private->pgid[0], + &channel_subsystems[0]->global_pgid, sizeof(struct pgid)); else /* Use existing pgid */ @@ -543,51 +544,6 @@ ccw_device_recog_timeout(struct ccw_device *cdev, enum dev_event dev_event) } -static void -ccw_device_nopath_notify(struct work_struct *work) -{ - struct ccw_device_private *priv; - 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) - 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. */ - cio_disable_subchannel(sch); - if (get_device(&cdev->dev)) { - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_call_sch_unregister); - queue_work(ccw_device_work, - &cdev->private->kick_work); - } else - put_device(&sch->dev); - } - } else { - cio_disable_subchannel(sch); - ccw_device_set_timeout(cdev, 0); - cdev->private->flags.fake_irb = 0; - cdev->private->state = DEV_STATE_DISCONNECTED; - wake_up(&cdev->private->wait_q); - } -out_unlock: - spin_unlock_irqrestore(cdev->ccwlock, flags); -} - void ccw_device_verify_done(struct ccw_device *cdev, int err) { @@ -631,12 +587,9 @@ ccw_device_verify_done(struct ccw_device *cdev, int err) default: /* Reset oper notify indication after verify error. */ cdev->private->flags.donotify = 0; - if (cdev->online) { - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_nopath_notify); - queue_work(ccw_device_notify_work, - &cdev->private->kick_work); - } else + if (cdev->online) + dev_fsm_event(cdev, DEV_EVENT_NOTOPER); + else ccw_device_done(cdev, DEV_STATE_NOT_OPER); break; } @@ -690,11 +643,7 @@ ccw_device_disband_done(struct ccw_device *cdev, int err) break; default: cdev->private->flags.donotify = 0; - if (get_device(&cdev->dev)) { - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_call_sch_unregister); - queue_work(ccw_device_work, &cdev->private->kick_work); - } + dev_fsm_event(cdev, DEV_EVENT_NOTOPER); ccw_device_done(cdev, DEV_STATE_NOT_OPER); break; } @@ -765,59 +714,16 @@ ccw_device_recog_notoper(struct ccw_device *cdev, enum dev_event dev_event) } /* - * Handle not operational event while offline. + * Handle not operational event in non-special state. */ -static void -ccw_device_offline_notoper(struct ccw_device *cdev, enum dev_event dev_event) +static void ccw_device_generic_notoper(struct ccw_device *cdev, + enum dev_event dev_event) { struct subchannel *sch; cdev->private->state = DEV_STATE_NOT_OPER; sch = to_subchannel(cdev->dev.parent); - if (get_device(&cdev->dev)) { - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_call_sch_unregister); - queue_work(ccw_device_work, &cdev->private->kick_work); - } - wake_up(&cdev->private->wait_q); -} - -/* - * Handle not operational event while online. - */ -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) { - 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); - if (sch->schib.scsw.actl != 0) { - // FIXME: not-oper indication to device driver ? - ccw_device_call_handler(cdev); - } - if (get_device(&cdev->dev)) { - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_call_sch_unregister); - queue_work(ccw_device_work, &cdev->private->kick_work); - } - wake_up(&cdev->private->wait_q); + css_schedule_eval(sch->schid); } /* @@ -915,18 +821,9 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event) cdev->private->state = DEV_STATE_TIMEOUT_KILL; 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); - } else if (cdev->handler) + if (ret == -ENODEV) + dev_fsm_event(cdev, DEV_EVENT_NOTOPER); + else if (cdev->handler) cdev->handler(cdev, cdev->private->intparm, ERR_PTR(-ETIMEDOUT)); } @@ -1233,7 +1130,7 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = { [DEV_EVENT_VERIFY] = ccw_device_nop, }, [DEV_STATE_SENSE_PGID] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_sense_pgid_irq, [DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout, [DEV_EVENT_VERIFY] = ccw_device_nop, @@ -1245,50 +1142,50 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = { [DEV_EVENT_VERIFY] = ccw_device_nop, }, [DEV_STATE_OFFLINE] = { - [DEV_EVENT_NOTOPER] = ccw_device_offline_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_offline_irq, [DEV_EVENT_TIMEOUT] = ccw_device_nop, [DEV_EVENT_VERIFY] = ccw_device_nop, }, [DEV_STATE_VERIFY] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_verify_irq, [DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout, [DEV_EVENT_VERIFY] = ccw_device_delay_verify, }, [DEV_STATE_ONLINE] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_irq, [DEV_EVENT_TIMEOUT] = ccw_device_online_timeout, [DEV_EVENT_VERIFY] = ccw_device_online_verify, }, [DEV_STATE_W4SENSE] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_w4sense, [DEV_EVENT_TIMEOUT] = ccw_device_nop, [DEV_EVENT_VERIFY] = ccw_device_online_verify, }, [DEV_STATE_DISBAND_PGID] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_disband_irq, [DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout, [DEV_EVENT_VERIFY] = ccw_device_nop, }, [DEV_STATE_BOXED] = { - [DEV_EVENT_NOTOPER] = ccw_device_offline_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_stlck_done, [DEV_EVENT_TIMEOUT] = ccw_device_stlck_done, [DEV_EVENT_VERIFY] = ccw_device_nop, }, /* states to wait for i/o completion before doing something */ [DEV_STATE_CLEAR_VERIFY] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_clear_verify, [DEV_EVENT_TIMEOUT] = ccw_device_nop, [DEV_EVENT_VERIFY] = ccw_device_nop, }, [DEV_STATE_TIMEOUT_KILL] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_killing_irq, [DEV_EVENT_TIMEOUT] = ccw_device_killing_timeout, [DEV_EVENT_VERIFY] = ccw_device_nop, //FIXME diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index 14eba854b155..7fd2dadc3297 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -25,6 +25,16 @@ #include "device.h" #include "chp.h" +/** + * ccw_device_set_options_mask() - set some options and unset the rest + * @cdev: device for which the options are to be set + * @flags: options to be set + * + * All flags specified in @flags are set, all flags not specified in @flags + * are cleared. + * Returns: + * %0 on success, -%EINVAL on an invalid flag combination. + */ int ccw_device_set_options_mask(struct ccw_device *cdev, unsigned long flags) { /* @@ -40,6 +50,15 @@ int ccw_device_set_options_mask(struct ccw_device *cdev, unsigned long flags) return 0; } +/** + * ccw_device_set_options() - set some options + * @cdev: device for which the options are to be set + * @flags: options to be set + * + * All flags specified in @flags are set, the remainder is left untouched. + * Returns: + * %0 on success, -%EINVAL if an invalid flag combination would ensue. + */ int ccw_device_set_options(struct ccw_device *cdev, unsigned long flags) { /* @@ -59,6 +78,13 @@ int ccw_device_set_options(struct ccw_device *cdev, unsigned long flags) return 0; } +/** + * ccw_device_clear_options() - clear some options + * @cdev: device for which the options are to be cleared + * @flags: options to be cleared + * + * All flags specified in @flags are cleared, the remainder is left untouched. + */ void ccw_device_clear_options(struct ccw_device *cdev, unsigned long flags) { cdev->private->options.fast &= (flags & CCWDEV_EARLY_NOTIFICATION) == 0; @@ -67,8 +93,22 @@ void ccw_device_clear_options(struct ccw_device *cdev, unsigned long flags) cdev->private->options.force &= (flags & CCWDEV_ALLOW_FORCE) == 0; } -int -ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) +/** + * ccw_device_clear() - terminate I/O request processing + * @cdev: target ccw device + * @intparm: interruption parameter; value is only used if no I/O is + * outstanding, otherwise the intparm associated with the I/O request + * is returned + * + * ccw_device_clear() calls csch on @cdev's subchannel. + * Returns: + * %0 on success, + * -%ENODEV on device not operational, + * -%EINVAL on invalid device state. + * Context: + * Interrupts disabled, ccw device lock held + */ +int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) { struct subchannel *sch; int ret; @@ -89,10 +129,33 @@ ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) return ret; } -int -ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, - unsigned long intparm, __u8 lpm, __u8 key, - unsigned long flags) +/** + * ccw_device_start_key() - start a s390 channel program with key + * @cdev: target ccw device + * @cpa: logical start address of channel program + * @intparm: user specific interruption parameter; will be presented back to + * @cdev's interrupt handler. Allows a device driver to associate + * the interrupt with a particular I/O request. + * @lpm: defines the channel path to be used for a specific I/O request. A + * value of 0 will make cio use the opm. + * @key: storage key to be used for the I/O + * @flags: additional flags; defines the action to be performed for I/O + * processing. + * + * Start a S/390 channel program. When the interrupt arrives, the + * IRQ handler is called, either immediately, delayed (dev-end missing, + * or sense required) or never (no IRQ handler registered). + * Returns: + * %0, if the operation was successful; + * -%EBUSY, if the device is busy, or status pending; + * -%EACCES, if no path specified in @lpm is operational; + * -%ENODEV, if the device is not operational. + * Context: + * Interrupts disabled, ccw device lock held + */ +int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, + unsigned long intparm, __u8 lpm, __u8 key, + unsigned long flags) { struct subchannel *sch; int ret; @@ -135,11 +198,38 @@ ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, return ret; } - -int -ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa, - unsigned long intparm, __u8 lpm, __u8 key, - unsigned long flags, int expires) +/** + * ccw_device_start_timeout_key() - start a s390 channel program with timeout and key + * @cdev: target ccw device + * @cpa: logical start address of channel program + * @intparm: user specific interruption parameter; will be presented back to + * @cdev's interrupt handler. Allows a device driver to associate + * the interrupt with a particular I/O request. + * @lpm: defines the channel path to be used for a specific I/O request. A + * value of 0 will make cio use the opm. + * @key: storage key to be used for the I/O + * @flags: additional flags; defines the action to be performed for I/O + * processing. + * @expires: timeout value in jiffies + * + * Start a S/390 channel program. When the interrupt arrives, the + * IRQ handler is called, either immediately, delayed (dev-end missing, + * or sense required) or never (no IRQ handler registered). + * This function notifies the device driver if the channel program has not + * completed during the time specified by @expires. If a timeout occurs, the + * channel program is terminated via xsch, hsch or csch, and the device's + * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT). + * Returns: + * %0, if the operation was successful; + * -%EBUSY, if the device is busy, or status pending; + * -%EACCES, if no path specified in @lpm is operational; + * -%ENODEV, if the device is not operational. + * Context: + * Interrupts disabled, ccw device lock held + */ +int ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa, + unsigned long intparm, __u8 lpm, __u8 key, + unsigned long flags, int expires) { int ret; @@ -152,18 +242,67 @@ ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa, return ret; } -int -ccw_device_start(struct ccw_device *cdev, struct ccw1 *cpa, - unsigned long intparm, __u8 lpm, unsigned long flags) +/** + * ccw_device_start() - start a s390 channel program + * @cdev: target ccw device + * @cpa: logical start address of channel program + * @intparm: user specific interruption parameter; will be presented back to + * @cdev's interrupt handler. Allows a device driver to associate + * the interrupt with a particular I/O request. + * @lpm: defines the channel path to be used for a specific I/O request. A + * value of 0 will make cio use the opm. + * @flags: additional flags; defines the action to be performed for I/O + * processing. + * + * Start a S/390 channel program. When the interrupt arrives, the + * IRQ handler is called, either immediately, delayed (dev-end missing, + * or sense required) or never (no IRQ handler registered). + * Returns: + * %0, if the operation was successful; + * -%EBUSY, if the device is busy, or status pending; + * -%EACCES, if no path specified in @lpm is operational; + * -%ENODEV, if the device is not operational. + * Context: + * Interrupts disabled, ccw device lock held + */ +int ccw_device_start(struct ccw_device *cdev, struct ccw1 *cpa, + unsigned long intparm, __u8 lpm, unsigned long flags) { return ccw_device_start_key(cdev, cpa, intparm, lpm, PAGE_DEFAULT_KEY, flags); } -int -ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa, - unsigned long intparm, __u8 lpm, unsigned long flags, - int expires) +/** + * ccw_device_start_timeout() - start a s390 channel program with timeout + * @cdev: target ccw device + * @cpa: logical start address of channel program + * @intparm: user specific interruption parameter; will be presented back to + * @cdev's interrupt handler. Allows a device driver to associate + * the interrupt with a particular I/O request. + * @lpm: defines the channel path to be used for a specific I/O request. A + * value of 0 will make cio use the opm. + * @flags: additional flags; defines the action to be performed for I/O + * processing. + * @expires: timeout value in jiffies + * + * Start a S/390 channel program. When the interrupt arrives, the + * IRQ handler is called, either immediately, delayed (dev-end missing, + * or sense required) or never (no IRQ handler registered). + * This function notifies the device driver if the channel program has not + * completed during the time specified by @expires. If a timeout occurs, the + * channel program is terminated via xsch, hsch or csch, and the device's + * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT). + * Returns: + * %0, if the operation was successful; + * -%EBUSY, if the device is busy, or status pending; + * -%EACCES, if no path specified in @lpm is operational; + * -%ENODEV, if the device is not operational. + * Context: + * Interrupts disabled, ccw device lock held + */ +int ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa, + unsigned long intparm, __u8 lpm, + unsigned long flags, int expires) { return ccw_device_start_timeout_key(cdev, cpa, intparm, lpm, PAGE_DEFAULT_KEY, flags, @@ -171,8 +310,23 @@ ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa, } -int -ccw_device_halt(struct ccw_device *cdev, unsigned long intparm) +/** + * ccw_device_halt() - halt I/O request processing + * @cdev: target ccw device + * @intparm: interruption parameter; value is only used if no I/O is + * outstanding, otherwise the intparm associated with the I/O request + * is returned + * + * ccw_device_halt() calls hsch on @cdev's subchannel. + * Returns: + * %0 on success, + * -%ENODEV on device not operational, + * -%EINVAL on invalid device state, + * -%EBUSY on device busy or interrupt pending. + * Context: + * Interrupts disabled, ccw device lock held + */ +int ccw_device_halt(struct ccw_device *cdev, unsigned long intparm) { struct subchannel *sch; int ret; @@ -193,8 +347,20 @@ ccw_device_halt(struct ccw_device *cdev, unsigned long intparm) return ret; } -int -ccw_device_resume(struct ccw_device *cdev) +/** + * ccw_device_resume() - resume channel program execution + * @cdev: target ccw device + * + * ccw_device_resume() calls rsch on @cdev's subchannel. + * Returns: + * %0 on success, + * -%ENODEV on device not operational, + * -%EINVAL on invalid device state, + * -%EBUSY on device busy or interrupt pending. + * Context: + * Interrupts disabled, ccw device lock held + */ +int ccw_device_resume(struct ccw_device *cdev) { struct subchannel *sch; @@ -260,11 +426,21 @@ ccw_device_call_handler(struct ccw_device *cdev) return 1; } -/* - * Search for CIW command in extended sense data. +/** + * ccw_device_get_ciw() - Search for CIW command in extended sense data. + * @cdev: ccw device to inspect + * @ct: command type to look for + * + * During SenseID, command information words (CIWs) describing special + * commands available to the device may have been stored in the extended + * sense data. This function searches for CIWs of a specified command + * type in the extended sense data. + * Returns: + * %NULL if no extended sense data has been stored or if no CIW of the + * specified command type could be found, + * else a pointer to the CIW of the specified command type. */ -struct ciw * -ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct) +struct ciw *ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct) { int ciw_cnt; @@ -276,8 +452,14 @@ ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct) return NULL; } -__u8 -ccw_device_get_path_mask(struct ccw_device *cdev) +/** + * ccw_device_get_path_mask() - get currently available paths + * @cdev: ccw device to be queried + * Returns: + * %0 if no subchannel for the device is available, + * else the mask of currently available paths for the ccw device's subchannel. + */ +__u8 ccw_device_get_path_mask(struct ccw_device *cdev) { struct subchannel *sch; @@ -357,8 +539,7 @@ out_unlock: return ret; } -void * -ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no) +void *ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no) { struct subchannel *sch; struct chp_id chpid; diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index d8d479876ec7..40a3208c7cf3 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -1024,9 +1024,9 @@ __qdio_outbound_processing(struct qdio_q *q) } static void -qdio_outbound_processing(struct qdio_q *q) +qdio_outbound_processing(unsigned long q) { - __qdio_outbound_processing(q); + __qdio_outbound_processing((struct qdio_q *) q); } /************************* INBOUND ROUTINES *******************************/ @@ -1449,9 +1449,10 @@ out: } static void -tiqdio_inbound_processing(struct qdio_q *q) +tiqdio_inbound_processing(unsigned long q) { - __tiqdio_inbound_processing(q, atomic_read(&spare_indicator_usecount)); + __tiqdio_inbound_processing((struct qdio_q *) q, + atomic_read(&spare_indicator_usecount)); } static void @@ -1494,9 +1495,9 @@ again: } static void -qdio_inbound_processing(struct qdio_q *q) +qdio_inbound_processing(unsigned long q) { - __qdio_inbound_processing(q); + __qdio_inbound_processing((struct qdio_q *) q); } /************************* MAIN ROUTINES *******************************/ @@ -1760,12 +1761,15 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev, q->handler=input_handler; q->dev_st_chg_ind=irq_ptr->dev_st_chg_ind; - q->tasklet.data=(unsigned long)q; /* q->is_thinint_q isn't valid at this time, but - * irq_ptr->is_thinint_irq is */ - q->tasklet.func=(void(*)(unsigned long)) - ((irq_ptr->is_thinint_irq)?&tiqdio_inbound_processing: - &qdio_inbound_processing); + * irq_ptr->is_thinint_irq is + */ + if (irq_ptr->is_thinint_irq) + tasklet_init(&q->tasklet, tiqdio_inbound_processing, + (unsigned long) q); + else + tasklet_init(&q->tasklet, qdio_inbound_processing, + (unsigned long) q); /* actually this is not used for inbound queues. yet. */ atomic_set(&q->busy_siga_counter,0); @@ -1836,13 +1840,10 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev, q->last_move_ftc=0; q->handler=output_handler; - q->tasklet.data=(unsigned long)q; - q->tasklet.func=(void(*)(unsigned long)) - &qdio_outbound_processing; - q->timer.function=(void(*)(unsigned long)) - &qdio_outbound_processing; - q->timer.data = (long)q; - init_timer(&q->timer); + tasklet_init(&q->tasklet, qdio_outbound_processing, + (unsigned long) q); + setup_timer(&q->timer, qdio_outbound_processing, + (unsigned long) q); atomic_set(&q->busy_siga_counter,0); q->timing.busy_start=0; @@ -3726,7 +3727,7 @@ qdio_performance_stats_store(struct bus_type *bus, const char *buf, size_t count #endif /* CONFIG_64BIT */ } } else { - QDIO_PRINT_WARN("QDIO performance_stats: write 0 or 1 to this file!\n"); + QDIO_PRINT_ERR("QDIO performance_stats: write 0 or 1 to this file!\n"); return -EINVAL; } return count; diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 90bd22014513..67aaff3e668d 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -458,28 +458,22 @@ static int ap_bus_match(struct device *dev, struct device_driver *drv) * uevent function for AP devices. It sets up a single environment * variable DEV_TYPE which contains the hardware device type. */ -static int ap_uevent (struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int ap_uevent (struct device *dev, struct kobj_uevent_env *env) { struct ap_device *ap_dev = to_ap_dev(dev); - int retval = 0, length = 0, i = 0; + int retval = 0; if (!ap_dev) return -ENODEV; /* Set up DEV_TYPE environment variable. */ - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEV_TYPE=%04X", ap_dev->device_type); + retval = add_uevent_var(env, "DEV_TYPE=%04X", ap_dev->device_type); if (retval) return retval; /* Add MODALIAS= */ - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=ap:t%02X", ap_dev->device_type); + retval = add_uevent_var(env, "MODALIAS=ap:t%02X", ap_dev->device_type); - envp[i] = NULL; return retval; } @@ -1231,8 +1225,9 @@ static void ap_reset_domain(void) { int i; - for (i = 0; i < AP_DEVICES; i++) - ap_reset_queue(AP_MKQID(i, ap_domain_index)); + if (ap_domain_index != -1) + for (i = 0; i < AP_DEVICES; i++) + ap_reset_queue(AP_MKQID(i, ap_domain_index)); } static void ap_reset_all(void) diff --git a/drivers/s390/crypto/zcrypt_mono.c b/drivers/s390/crypto/zcrypt_mono.c index 2a9349ad68b7..44253fdd4136 100644 --- a/drivers/s390/crypto/zcrypt_mono.c +++ b/drivers/s390/crypto/zcrypt_mono.c @@ -45,7 +45,7 @@ /** * The module initialization code. */ -int __init zcrypt_init(void) +static int __init zcrypt_init(void) { int rc; @@ -86,7 +86,7 @@ out: /** * The module termination code. */ -void __exit zcrypt_exit(void) +static void __exit zcrypt_exit(void) { zcrypt_cex2a_exit(); zcrypt_pcixcc_exit(); diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index 64948788d301..70b9ddc8cf9d 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c @@ -277,7 +277,7 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, }; struct { struct type6_hdr hdr; - struct ica_CPRBX cprbx; + struct CPRBX cprbx; } __attribute__((packed)) *msg = ap_msg->message; int rcblen = CEIL4(xcRB->request_control_blk_length); @@ -432,14 +432,17 @@ static int convert_type86_ica(struct zcrypt_device *zdev, } if (service_rc == 8 && service_rs == 770) { PDEBUG("Invalid key length on PCIXCC/CEX2C\n"); - zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD; - return -EAGAIN; + return -EINVAL; } if (service_rc == 8 && service_rs == 783) { PDEBUG("Extended bitlengths not enabled on PCIXCC/CEX2C\n"); zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD; return -EAGAIN; } + if (service_rc == 12 && service_rs == 769) { + PDEBUG("Invalid key on PCIXCC/CEX2C\n"); + return -EINVAL; + } PRINTK("Unknown service rc/rs (PCIXCC/CEX2C): %d/%d\n", service_rc, service_rs); zdev->online = 0; diff --git a/drivers/s390/crypto/zcrypt_pcixcc.h b/drivers/s390/crypto/zcrypt_pcixcc.h index a78ff307fd19..8cb7d7a6973b 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.h +++ b/drivers/s390/crypto/zcrypt_pcixcc.h @@ -28,51 +28,6 @@ #ifndef _ZCRYPT_PCIXCC_H_ #define _ZCRYPT_PCIXCC_H_ -/** - * CPRBX - * Note that all shorts and ints are big-endian. - * All pointer fields are 16 bytes long, and mean nothing. - * - * A request CPRB is followed by a request_parameter_block. - * - * The request (or reply) parameter block is organized thus: - * function code - * VUD block - * key block - */ -struct CPRBX { - unsigned short cprb_len; /* CPRB length 220 */ - unsigned char cprb_ver_id; /* CPRB version id. 0x02 */ - unsigned char pad_000[3]; /* Alignment pad bytes */ - unsigned char func_id[2]; /* function id 0x5432 */ - unsigned char cprb_flags[4]; /* Flags */ - unsigned int req_parml; /* request parameter buffer len */ - unsigned int req_datal; /* request data buffer */ - unsigned int rpl_msgbl; /* reply message block length */ - unsigned int rpld_parml; /* replied parameter block len */ - unsigned int rpl_datal; /* reply data block len */ - unsigned int rpld_datal; /* replied data block len */ - unsigned int req_extbl; /* request extension block len */ - unsigned char pad_001[4]; /* reserved */ - unsigned int rpld_extbl; /* replied extension block len */ - unsigned char req_parmb[16]; /* request parm block 'address' */ - unsigned char req_datab[16]; /* request data block 'address' */ - unsigned char rpl_parmb[16]; /* reply parm block 'address' */ - unsigned char rpl_datab[16]; /* reply data block 'address' */ - unsigned char req_extb[16]; /* request extension block 'addr'*/ - unsigned char rpl_extb[16]; /* reply extension block 'addres'*/ - unsigned short ccp_rtcode; /* server return code */ - unsigned short ccp_rscode; /* server reason code */ - unsigned int mac_data_len; /* Mac Data Length */ - unsigned char logon_id[8]; /* Logon Identifier */ - unsigned char mac_value[8]; /* Mac Value */ - unsigned char mac_content_flgs;/* Mac content flag byte */ - unsigned char pad_002; /* Alignment */ - unsigned short domain; /* Domain */ - unsigned char pad_003[12]; /* Domain masks */ - unsigned char pad_004[36]; /* reserved */ -} __attribute__((packed)); - int zcrypt_pcixcc_init(void); void zcrypt_pcixcc_exit(void); diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 90aa53fc4f3e..7507067351bd 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -891,7 +891,7 @@ zfcp_unit_dequeue(struct zfcp_unit *unit) /* * Allocates a combined QTCB/fsf_req buffer for erp actions and fcp/SCSI * commands. - * It also genrates fcp-nameserver request/response buffer and unsolicited + * It also genrates fcp-nameserver request/response buffer and unsolicited * status read fsf_req buffers. * * locks: must only be called with zfcp_data.config_sema taken @@ -982,7 +982,7 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) struct zfcp_adapter *adapter; /* - * Note: It is safe to release the list_lock, as any list changes + * Note: It is safe to release the list_lock, as any list changes * are protected by the config_sema, which must be held to get here */ @@ -1038,6 +1038,10 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) spin_lock_init(&adapter->san_dbf_lock); spin_lock_init(&adapter->scsi_dbf_lock); + retval = zfcp_adapter_debug_register(adapter); + if (retval) + goto debug_register_failed; + /* initialize error recovery stuff */ rwlock_init(&adapter->erp_lock); @@ -1058,7 +1062,6 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) /* mark adapter unusable as long as sysfs registration is not complete */ atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); - adapter->ccw_device = ccw_device; dev_set_drvdata(&ccw_device->dev, adapter); if (zfcp_sysfs_adapter_create_files(&ccw_device->dev)) @@ -1085,6 +1088,8 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) generic_services_failed: zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev); sysfs_failed: + zfcp_adapter_debug_unregister(adapter); + debug_register_failed: dev_set_drvdata(&ccw_device->dev, NULL); zfcp_reqlist_free(adapter); failed_low_mem_buffers: @@ -1130,6 +1135,8 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter) goto out; } + zfcp_adapter_debug_unregister(adapter); + /* remove specified adapter data structure from list */ write_lock_irq(&zfcp_data.config_lock); list_del(&adapter->list); diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index 1c8f71a59855..e01cbf152a81 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -28,7 +28,7 @@ static void zfcp_ccw_remove(struct ccw_device *); static int zfcp_ccw_set_online(struct ccw_device *); static int zfcp_ccw_set_offline(struct ccw_device *); static int zfcp_ccw_notify(struct ccw_device *, int); -static void zfcp_ccw_shutdown(struct device *); +static void zfcp_ccw_shutdown(struct ccw_device *); static struct ccw_device_id zfcp_ccw_device_id[] = { {CCW_DEVICE_DEVTYPE(ZFCP_CONTROL_UNIT_TYPE, @@ -51,9 +51,7 @@ static struct ccw_driver zfcp_ccw_driver = { .set_online = zfcp_ccw_set_online, .set_offline = zfcp_ccw_set_offline, .notify = zfcp_ccw_notify, - .driver = { - .shutdown = zfcp_ccw_shutdown, - }, + .shutdown = zfcp_ccw_shutdown, }; MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id); @@ -150,15 +148,12 @@ zfcp_ccw_set_online(struct ccw_device *ccw_device) down(&zfcp_data.config_sema); adapter = dev_get_drvdata(&ccw_device->dev); - retval = zfcp_adapter_debug_register(adapter); - if (retval) - goto out; retval = zfcp_erp_thread_setup(adapter); if (retval) { ZFCP_LOG_INFO("error: start of error recovery thread for " "adapter %s failed\n", zfcp_get_busid_by_adapter(adapter)); - goto out_erp_thread; + goto out; } retval = zfcp_adapter_scsi_register(adapter); @@ -177,8 +172,6 @@ zfcp_ccw_set_online(struct ccw_device *ccw_device) out_scsi_register: zfcp_erp_thread_kill(adapter); - out_erp_thread: - zfcp_adapter_debug_unregister(adapter); out: up(&zfcp_data.config_sema); return retval; @@ -201,7 +194,6 @@ zfcp_ccw_set_offline(struct ccw_device *ccw_device) zfcp_erp_adapter_shutdown(adapter, 0); zfcp_erp_wait(adapter); zfcp_erp_thread_kill(adapter); - zfcp_adapter_debug_unregister(adapter); up(&zfcp_data.config_sema); return 0; } @@ -277,12 +269,12 @@ zfcp_ccw_register(void) * Makes sure that QDIO queues are down when the system gets stopped. */ static void -zfcp_ccw_shutdown(struct device *dev) +zfcp_ccw_shutdown(struct ccw_device *cdev) { struct zfcp_adapter *adapter; down(&zfcp_data.config_sema); - adapter = dev_get_drvdata(dev); + adapter = dev_get_drvdata(&cdev->dev); zfcp_erp_adapter_shutdown(adapter, 0); zfcp_erp_wait(adapter); up(&zfcp_data.config_sema); diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 5f3212440f68..ffa3bf756943 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -19,8 +19,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <asm/debug.h> #include <linux/ctype.h> +#include <asm/debug.h> #include "zfcp_ext.h" static u32 dbfsize = 4; @@ -35,17 +35,17 @@ static int zfcp_dbf_stck(char *out_buf, const char *label, unsigned long long stck) { unsigned long long sec; - struct timespec xtime; + struct timespec dbftime; int len = 0; stck -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096); sec = stck >> 12; do_div(sec, 1000000); - xtime.tv_sec = sec; + dbftime.tv_sec = sec; stck -= (sec * 1000000) << 12; - xtime.tv_nsec = ((stck * 1000) >> 12); + dbftime.tv_nsec = ((stck * 1000) >> 12); len += sprintf(out_buf + len, "%-24s%011lu:%06lu\n", - label, xtime.tv_sec, xtime.tv_nsec); + label, dbftime.tv_sec, dbftime.tv_nsec); return len; } diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index b36dfc40d9fa..16e5563e0c65 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -1,23 +1,23 @@ -/* +/* * This file is part of the zfcp device driver for * FCP adapters for IBM System z9 and zSeries. * * (C) Copyright IBM Corp. 2002, 2006 - * - * 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, 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. - */ + * + * 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, 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. + */ #ifndef ZFCP_DEF_H #define ZFCP_DEF_H @@ -90,7 +90,7 @@ zfcp_address_to_sg(void *address, struct scatterlist *list) #define ZFCP_DEVICE_TYPE 0x1732 #define ZFCP_DEVICE_MODEL 0x03 #define ZFCP_DEVICE_MODEL_PRIV 0x04 - + /* allow as many chained SBALs as are supported by hardware */ #define ZFCP_MAX_SBALS_PER_REQ FSF_MAX_SBALS_PER_REQ #define ZFCP_MAX_SBALS_PER_CT_REQ FSF_MAX_SBALS_PER_REQ @@ -508,7 +508,7 @@ struct zfcp_rc_entry { /* * this allows removal of logging code by the preprocessor - * (the most detailed log level still to be compiled in is specified, + * (the most detailed log level still to be compiled in is specified, * higher log levels are removed) */ #define ZFCP_LOG_LEVEL_LIMIT ZFCP_LOG_LEVEL_TRACE @@ -546,7 +546,7 @@ do { \ if (ZFCP_LOG_CHECK(level)) \ _ZFCP_LOG(fmt, ##args); \ } while (0) - + #if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_NORMAL # define ZFCP_LOG_NORMAL(fmt, args...) do { } while (0) #else @@ -583,8 +583,8 @@ do { \ /*************** ADAPTER/PORT/UNIT AND FSF_REQ STATUS FLAGS ******************/ -/* - * Note, the leftmost status byte is common among adapter, port +/* + * Note, the leftmost status byte is common among adapter, port * and unit */ #define ZFCP_COMMON_FLAGS 0xfff00000 @@ -1007,8 +1007,8 @@ struct zfcp_fsf_req { u32 fsf_command; /* FSF Command copy */ struct fsf_qtcb *qtcb; /* address of associated QTCB */ u32 seq_no; /* Sequence number of request */ - unsigned long data; /* private data of request */ - struct timer_list timer; /* used for erp or scsi er */ + unsigned long data; /* private data of request */ + struct timer_list timer; /* used for erp or scsi er */ struct zfcp_erp_action *erp_action; /* used if this request is issued on behalf of erp */ mempool_t *pool; /* used if request was alloacted diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index d8cd75ce2d9a..a6475a2bb8a7 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -1,22 +1,22 @@ -/* +/* * This file is part of the zfcp device driver for * FCP adapters for IBM System z9 and zSeries. * * (C) Copyright IBM Corp. 2002, 2006 - * - * 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, 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. + * + * 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, 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. */ #define ZFCP_LOG_AREA ZFCP_LOG_AREA_ERP @@ -54,7 +54,7 @@ static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *, int); static int zfcp_erp_strategy_statechange(int, u32, struct zfcp_adapter *, struct zfcp_port *, struct zfcp_unit *, int); -static inline int zfcp_erp_strategy_statechange_detected(atomic_t *, u32); +static int zfcp_erp_strategy_statechange_detected(atomic_t *, u32); static int zfcp_erp_strategy_followup_actions(int, struct zfcp_adapter *, struct zfcp_port *, struct zfcp_unit *, int); @@ -106,8 +106,8 @@ static void zfcp_erp_action_cleanup(int, struct zfcp_adapter *, static void zfcp_erp_action_ready(struct zfcp_erp_action *); static int zfcp_erp_action_exists(struct zfcp_erp_action *); -static inline void zfcp_erp_action_to_ready(struct zfcp_erp_action *); -static inline void zfcp_erp_action_to_running(struct zfcp_erp_action *); +static void zfcp_erp_action_to_ready(struct zfcp_erp_action *); +static void zfcp_erp_action_to_running(struct zfcp_erp_action *); static void zfcp_erp_memwait_handler(unsigned long); @@ -191,7 +191,7 @@ void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req, unsigned long timeout) } /* - * function: + * function: * * purpose: called if an adapter failed, * initiates adapter recovery which is done @@ -228,7 +228,7 @@ zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *adapter, int clear_mask) } /* - * function: + * function: * * purpose: Wrappper for zfcp_erp_adapter_reopen_internal * used to ensure the correct locking @@ -476,7 +476,7 @@ zfcp_test_link(struct zfcp_port *port) /* - * function: + * function: * * purpose: called if a port failed to be opened normally * initiates Forced Reopen recovery which is done @@ -517,7 +517,7 @@ zfcp_erp_port_forced_reopen_internal(struct zfcp_port *port, int clear_mask) } /* - * function: + * function: * * purpose: Wrappper for zfcp_erp_port_forced_reopen_internal * used to ensure the correct locking @@ -543,7 +543,7 @@ zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear_mask) } /* - * function: + * function: * * purpose: called if a port is to be opened * initiates Reopen recovery which is done @@ -612,7 +612,7 @@ zfcp_erp_port_reopen(struct zfcp_port *port, int clear_mask) } /* - * function: + * function: * * purpose: called if a unit is to be opened * initiates Reopen recovery which is done @@ -704,7 +704,7 @@ static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter) } /* - * function: + * function: * * purpose: disable I/O, * return any open requests and clean them up, @@ -725,7 +725,7 @@ zfcp_erp_port_block(struct zfcp_port *port, int clear_mask) } /* - * function: + * function: * * purpose: enable I/O * @@ -742,7 +742,7 @@ zfcp_erp_port_unblock(struct zfcp_port *port) } /* - * function: + * function: * * purpose: disable I/O, * return any open requests and clean them up, @@ -763,7 +763,7 @@ zfcp_erp_unit_block(struct zfcp_unit *unit, int clear_mask) } /* - * function: + * function: * * purpose: enable I/O * @@ -792,7 +792,7 @@ zfcp_erp_action_ready(struct zfcp_erp_action *erp_action) } /* - * function: + * function: * * purpose: * @@ -952,7 +952,7 @@ zfcp_erp_memwait_handler(unsigned long data) * action gets an appropriate flag and will be processed * accordingly */ -void zfcp_erp_timeout_handler(unsigned long data) +static void zfcp_erp_timeout_handler(unsigned long data) { struct zfcp_erp_action *erp_action = (struct zfcp_erp_action *) data; struct zfcp_adapter *adapter = erp_action->adapter; @@ -967,7 +967,7 @@ void zfcp_erp_timeout_handler(unsigned long data) * zfcp_erp_action_dismiss - dismiss an erp_action * * adapter->erp_lock must be held - * + * * Dismissal of an erp_action is usually required if an erp_action of * higher priority is generated. */ @@ -1005,9 +1005,9 @@ zfcp_erp_thread_setup(struct zfcp_adapter *adapter) } /* - * function: + * function: * - * purpose: + * purpose: * * returns: * @@ -1094,7 +1094,7 @@ zfcp_erp_thread(void *data) } /* - * function: + * function: * * purpose: drives single error recovery action and schedules higher and * subordinate actions, if necessary @@ -1206,7 +1206,7 @@ zfcp_erp_strategy(struct zfcp_erp_action *erp_action) /* * put this target through the erp mill again if someone has - * requested to change the status of a target being online + * requested to change the status of a target being online * to offline or the other way around * (old retval is preserved if nothing has to be done here) */ @@ -1228,7 +1228,7 @@ zfcp_erp_strategy(struct zfcp_erp_action *erp_action) unlock: write_unlock(&adapter->erp_lock); read_unlock_irqrestore(&zfcp_data.config_lock, flags); - + if (retval != ZFCP_ERP_CONTINUES) zfcp_erp_action_cleanup(action, adapter, port, unit, retval); @@ -1250,9 +1250,9 @@ zfcp_erp_strategy(struct zfcp_erp_action *erp_action) } /* - * function: + * function: * - * purpose: + * purpose: * * returns: ZFCP_ERP_DISMISSED - if action has been dismissed * retval - otherwise @@ -1322,7 +1322,7 @@ zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action) } /* - * function: + * function: * * purpose: triggers retry of this action after a certain amount of time * by means of timer provided by erp_action @@ -1346,7 +1346,7 @@ zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action) return retval; } -/* +/* * function: zfcp_erp_adapter_failed * * purpose: sets the adapter and all underlying devices to ERP_FAILED @@ -1362,7 +1362,7 @@ zfcp_erp_adapter_failed(struct zfcp_adapter *adapter) debug_text_event(adapter->erp_dbf, 2, "a_afail"); } -/* +/* * function: zfcp_erp_port_failed * * purpose: sets the port and all underlying devices to ERP_FAILED @@ -1386,7 +1386,7 @@ zfcp_erp_port_failed(struct zfcp_port *port) debug_event(port->adapter->erp_dbf, 2, &port->wwpn, sizeof (wwn_t)); } -/* +/* * function: zfcp_erp_unit_failed * * purpose: sets the unit to ERP_FAILED @@ -1417,7 +1417,7 @@ zfcp_erp_unit_failed(struct zfcp_unit *unit) * successfully is reset. * * returns: ZFCP_ERP_CONTINUES - action continues (not considered) - * ZFCP_ERP_SUCCEEDED - action finished successfully + * ZFCP_ERP_SUCCEEDED - action finished successfully * ZFCP_ERP_EXIT - action failed and will not continue */ static int @@ -1491,7 +1491,7 @@ zfcp_erp_strategy_statechange(int action, return retval; } -static inline int +static int zfcp_erp_strategy_statechange_detected(atomic_t * target_status, u32 erp_status) { return @@ -1646,7 +1646,7 @@ zfcp_erp_schedule_work(struct zfcp_unit *unit) } /* - * function: + * function: * * purpose: remaining things in good cases, * escalation in bad cases @@ -1687,8 +1687,8 @@ zfcp_erp_strategy_followup_actions(int action, break; case ZFCP_ERP_ACTION_REOPEN_UNIT: - if (status == ZFCP_ERP_SUCCEEDED) ; /* no further action */ - else + /* Nothing to do if status == ZFCP_ERP_SUCCEEDED */ + if (status != ZFCP_ERP_SUCCEEDED) zfcp_erp_port_reopen_internal(unit->port, 0); break; } @@ -1815,7 +1815,7 @@ zfcp_erp_modify_unit_status(struct zfcp_unit *unit, u32 mask, int set_or_clear) } /* - * function: + * function: * * purpose: Wrappper for zfcp_erp_port_reopen_all_internal * used to ensure the correct locking @@ -1852,9 +1852,9 @@ zfcp_erp_port_reopen_all_internal(struct zfcp_adapter *adapter, int clear_mask) } /* - * function: + * function: * - * purpose: + * purpose: * * returns: FIXME */ @@ -1871,7 +1871,7 @@ zfcp_erp_unit_reopen_all_internal(struct zfcp_port *port, int clear_mask) } /* - * function: + * function: * * purpose: this routine executes the 'Reopen Adapter' action * (the entire action is processed synchronously, since @@ -1908,9 +1908,9 @@ zfcp_erp_adapter_strategy(struct zfcp_erp_action *erp_action) } /* - * function: + * function: * - * purpose: + * purpose: * * returns: ZFCP_ERP_SUCCEEDED - action finished successfully * ZFCP_ERP_FAILED - action finished unsuccessfully @@ -1930,9 +1930,9 @@ zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *erp_action) } /* - * function: + * function: * - * purpose: + * purpose: * * returns: ZFCP_ERP_SUCCEEDED - action finished successfully * ZFCP_ERP_FAILED - action finished unsuccessfully @@ -1957,7 +1957,7 @@ zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *erp_action) * purpose: allocate the irq associated with this devno and register * the FSF adapter with the SCSI stack * - * returns: + * returns: */ static int zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *erp_action, int close) @@ -2001,7 +2001,7 @@ zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *erp_action, int close) * returns: 0 - successful setup * !0 - failed setup */ -int +static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action) { int retval; @@ -2197,7 +2197,7 @@ zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *erp_action) zfcp_erp_action_to_running(erp_action); write_unlock_irq(&adapter->erp_lock); - ret = zfcp_fsf_exchange_port_data(erp_action, adapter, NULL); + ret = zfcp_fsf_exchange_port_data(erp_action); if (ret == -EOPNOTSUPP) { debug_text_event(adapter->erp_dbf, 3, "a_xport_notsupp"); return ZFCP_ERP_SUCCEEDED; @@ -2249,7 +2249,7 @@ zfcp_erp_adapter_strategy_open_fsf_statusread(struct zfcp_erp_action } /* - * function: + * function: * * purpose: this routine executes the 'Reopen Physical Port' action * @@ -2308,7 +2308,7 @@ zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action) } /* - * function: + * function: * * purpose: this routine executes the 'Reopen Port' action * @@ -2530,7 +2530,7 @@ zfcp_erp_port_strategy_open_nameserver(struct zfcp_erp_action *erp_action) } /* - * function: + * function: * * purpose: makes the erp thread continue with reopen (physical) port * actions which have been paused until the name server port @@ -2570,9 +2570,9 @@ zfcp_erp_port_strategy_open_nameserver_wakeup(struct zfcp_erp_action } /* - * function: + * function: * - * purpose: + * purpose: * * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) * ZFCP_ERP_FAILED - action finished unsuccessfully @@ -2626,9 +2626,9 @@ zfcp_erp_port_strategy_clearstati(struct zfcp_port *port) } /* - * function: + * function: * - * purpose: + * purpose: * * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) * ZFCP_ERP_FAILED - action finished unsuccessfully @@ -2663,9 +2663,9 @@ zfcp_erp_port_strategy_close(struct zfcp_erp_action *erp_action) } /* - * function: + * function: * - * purpose: + * purpose: * * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) * ZFCP_ERP_FAILED - action finished unsuccessfully @@ -2700,9 +2700,9 @@ zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *erp_action) } /* - * function: + * function: * - * purpose: + * purpose: * * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) * ZFCP_ERP_FAILED - action finished unsuccessfully @@ -2737,7 +2737,7 @@ zfcp_erp_port_strategy_open_common_lookup(struct zfcp_erp_action *erp_action) } /* - * function: + * function: * * purpose: this routine executes the 'Reopen Unit' action * currently no retries @@ -2825,9 +2825,9 @@ zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *unit) } /* - * function: + * function: * - * purpose: + * purpose: * * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) * ZFCP_ERP_FAILED - action finished unsuccessfully @@ -2865,9 +2865,9 @@ zfcp_erp_unit_strategy_close(struct zfcp_erp_action *erp_action) } /* - * function: + * function: * - * purpose: + * purpose: * * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) * ZFCP_ERP_FAILED - action finished unsuccessfully @@ -2913,7 +2913,7 @@ void zfcp_erp_start_timer(struct zfcp_fsf_req *fsf_req) } /* - * function: + * function: * * purpose: enqueue the specified error recovery action, if needed * @@ -2992,7 +2992,7 @@ zfcp_erp_action_enqueue(int action, port->erp_action.action); debug_text_event(adapter->erp_dbf, 4, "pf_actenq_drp"); - } else + } else debug_text_event(adapter->erp_dbf, 4, "pf_actenq_drpcp"); debug_event(adapter->erp_dbf, 4, &port->wwpn, @@ -3248,8 +3248,7 @@ static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit) zfcp_erp_action_dismiss(&unit->erp_action); } -static inline void -zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) +static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) { struct zfcp_adapter *adapter = erp_action->adapter; @@ -3258,8 +3257,7 @@ zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) list_move(&erp_action->list, &erp_action->adapter->erp_running_head); } -static inline void -zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action) +static void zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action) { struct zfcp_adapter *adapter = erp_action->adapter; diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 991d45667a44..8534cf09546c 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -1,22 +1,22 @@ -/* +/* * This file is part of the zfcp device driver for * FCP adapters for IBM System z9 and zSeries. * * (C) Copyright IBM Corp. 2002, 2006 - * - * 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, 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. + * + * 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, 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. */ #ifndef ZFCP_EXT_H @@ -82,9 +82,11 @@ extern int zfcp_fsf_open_unit(struct zfcp_erp_action *); extern int zfcp_fsf_close_unit(struct zfcp_erp_action *); extern int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *); -extern int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *, - struct zfcp_adapter *, - struct fsf_qtcb_bottom_port *); +extern int zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *, + struct fsf_qtcb_bottom_config *); +extern int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *); +extern int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *, + struct fsf_qtcb_bottom_port *); extern int zfcp_fsf_control_file(struct zfcp_adapter *, struct zfcp_fsf_req **, u32, u32, struct zfcp_sg_list *); extern void zfcp_fsf_start_timer(struct zfcp_fsf_req *, unsigned long); diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 99299976e891..ff866ebd44ac 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -80,10 +80,10 @@ static const char zfcp_act_subtable_type[5][8] = { /* * function: zfcp_fsf_req_alloc * - * purpose: Obtains an fsf_req and potentially a qtcb (for all but + * purpose: Obtains an fsf_req and potentially a qtcb (for all but * unsolicited requests) via helper functions * Does some initial fsf request set-up. - * + * * returns: pointer to allocated fsf_req if successfull * NULL otherwise * @@ -192,7 +192,7 @@ void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter) * returns: 0 - success * !0 - failure * - * context: + * context: */ int zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req) @@ -214,8 +214,8 @@ zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req) } /* - * fsf_req may be deleted due to waking up functions, so - * cleanup is saved here and used later + * fsf_req may be deleted due to waking up functions, so + * cleanup is saved here and used later */ if (likely(fsf_req->status & ZFCP_STATUS_FSFREQ_CLEANUP)) cleanup = 1; @@ -259,9 +259,9 @@ zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req) * and initiates appropriate actions * (usually calling FSF command specific handlers) * - * returns: + * returns: * - * context: + * context: * * locks: */ @@ -638,7 +638,7 @@ zfcp_fsf_link_down_info_eval(struct zfcp_adapter *adapter, * * purpose: calls the appropriate command specific handler * - * returns: + * returns: */ static int zfcp_fsf_req_dispatch(struct zfcp_fsf_req *fsf_req) @@ -854,7 +854,7 @@ zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *fsf_req) * * purpose: is called for finished Open Port command * - * returns: + * returns: */ static int zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req) @@ -1088,7 +1088,7 @@ zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req) * returns: address of initiated FSF request * NULL - request could not be initiated * - * FIXME(design): should be watched by a timeout !!! + * FIXME(design): should be watched by a timeout !!! * FIXME(design) shouldn't this be modified to return an int * also...don't know how though */ @@ -1157,7 +1157,7 @@ zfcp_fsf_abort_fcp_command(unsigned long old_req_id, * * purpose: is called for finished Abort FCP Command request * - * returns: + * returns: */ static int zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req) @@ -1941,25 +1941,28 @@ zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) { volatile struct qdio_buffer_element *sbale; struct zfcp_fsf_req *fsf_req; + struct zfcp_adapter *adapter = erp_action->adapter; unsigned long lock_flags; - int retval = 0; + int retval; /* setup new FSF request */ - retval = zfcp_fsf_req_create(erp_action->adapter, + retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA, ZFCP_REQ_AUTO_CLEANUP, - erp_action->adapter->pool.fsf_req_erp, + adapter->pool.fsf_req_erp, &lock_flags, &fsf_req); - if (retval < 0) { + if (retval) { ZFCP_LOG_INFO("error: Could not create exchange configuration " "data request for adapter %s.\n", - zfcp_get_busid_by_adapter(erp_action->adapter)); - goto out; + zfcp_get_busid_by_adapter(adapter)); + write_unlock_irqrestore(&adapter->request_queue.queue_lock, + lock_flags); + return retval; } sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); - sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; - sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; + sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; + sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; fsf_req->qtcb->bottom.config.feature_selection = FSF_FEATURE_CFDC | @@ -1971,23 +1974,71 @@ zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) zfcp_erp_start_timer(fsf_req); retval = zfcp_fsf_req_send(fsf_req); + write_unlock_irqrestore(&adapter->request_queue.queue_lock, + lock_flags); if (retval) { - ZFCP_LOG_INFO - ("error: Could not send exchange configuration data " - "command on the adapter %s\n", - zfcp_get_busid_by_adapter(erp_action->adapter)); + ZFCP_LOG_INFO("error: Could not send exchange configuration " + "data command on the adapter %s\n", + zfcp_get_busid_by_adapter(adapter)); zfcp_fsf_req_free(fsf_req); erp_action->fsf_req = NULL; - goto out; } + else + ZFCP_LOG_DEBUG("exchange configuration data request initiated " + "(adapter %s)\n", + zfcp_get_busid_by_adapter(adapter)); - ZFCP_LOG_DEBUG("exchange configuration data request initiated " - "(adapter %s)\n", - zfcp_get_busid_by_adapter(erp_action->adapter)); + return retval; +} - out: - write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock, +int +zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter, + struct fsf_qtcb_bottom_config *data) +{ + volatile struct qdio_buffer_element *sbale; + struct zfcp_fsf_req *fsf_req; + unsigned long lock_flags; + int retval; + + /* setup new FSF request */ + retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA, + 0, NULL, &lock_flags, &fsf_req); + if (retval) { + ZFCP_LOG_INFO("error: Could not create exchange configuration " + "data request for adapter %s.\n", + zfcp_get_busid_by_adapter(adapter)); + write_unlock_irqrestore(&adapter->request_queue.queue_lock, + lock_flags); + return retval; + } + + sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); + sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; + sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; + + fsf_req->qtcb->bottom.config.feature_selection = + FSF_FEATURE_CFDC | + FSF_FEATURE_LUN_SHARING | + FSF_FEATURE_NOTIFICATION_LOST | + FSF_FEATURE_UPDATE_ALERT; + + if (data) + fsf_req->data = (unsigned long) data; + + zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); + retval = zfcp_fsf_req_send(fsf_req); + write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); + if (retval) + ZFCP_LOG_INFO("error: Could not send exchange configuration " + "data command on the adapter %s\n", + zfcp_get_busid_by_adapter(adapter)); + else + wait_event(fsf_req->completion_wq, + fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); + + zfcp_fsf_req_free(fsf_req); + return retval; } @@ -2016,11 +2067,17 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok) adapter->peer_d_id = 0; if (xchg_ok) { + + if (fsf_req->data) + memcpy((struct fsf_qtcb_bottom_config *) fsf_req->data, + bottom, sizeof (struct fsf_qtcb_bottom_config)); + fc_host_node_name(shost) = bottom->nport_serv_param.wwnn; fc_host_port_name(shost) = bottom->nport_serv_param.wwpn; fc_host_port_id(shost) = bottom->s_id & ZFCP_DID_MASK; fc_host_speed(shost) = bottom->fc_link_speed; - fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3; + fc_host_supported_classes(shost) = + FC_COS_CLASS2 | FC_COS_CLASS3; adapter->hydra_version = bottom->adapter_type; if (fc_host_permanent_port_name(shost) == -1) fc_host_permanent_port_name(shost) = @@ -2053,7 +2110,8 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok) min(FC_SERIAL_NUMBER_SIZE, 17)); } - ZFCP_LOG_NORMAL("The adapter %s reported the following characteristics:\n" + ZFCP_LOG_NORMAL("The adapter %s reported the following " + "characteristics:\n" "WWNN 0x%016Lx, " "WWPN 0x%016Lx, " "S_ID 0x%06x,\n" @@ -2090,7 +2148,7 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok) return 0; } -/* +/** * function: zfcp_fsf_exchange_config_data_handler * * purpose: is called for finished Exchange Configuration Data command @@ -2125,7 +2183,7 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req) adapter->peer_wwpn, adapter->peer_d_id); debug_text_event(fsf_req->adapter->erp_dbf, 0, - "top-p-to-p"); + "top-p-to-p"); break; case FC_PORTTYPE_NLPORT: ZFCP_LOG_NORMAL("error: Arbitrated loop fibrechannel " @@ -2138,8 +2196,8 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req) return -EIO; case FC_PORTTYPE_NPORT: ZFCP_LOG_NORMAL("Switched fabric fibrechannel " - "network detected at adapter %s.\n", - zfcp_get_busid_by_adapter(adapter)); + "network detected at adapter %s.\n", + zfcp_get_busid_by_adapter(adapter)); break; default: ZFCP_LOG_NORMAL("bug: The fibrechannel topology " @@ -2179,7 +2237,8 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req) if (zfcp_fsf_exchange_config_evaluate(fsf_req, 0)) return -EIO; - atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status); + atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, + &adapter->status); zfcp_fsf_link_down_info_eval(adapter, &qtcb->header.fsf_status_qual.link_down_info); @@ -2187,7 +2246,7 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req) default: debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf-stat-ng"); debug_event(fsf_req->adapter->erp_dbf, 0, - &fsf_req->qtcb->header.fsf_status, sizeof (u32)); + &fsf_req->qtcb->header.fsf_status, sizeof(u32)); zfcp_erp_adapter_shutdown(adapter, 0); return -EIO; } @@ -2197,74 +2256,118 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req) /** * zfcp_fsf_exchange_port_data - request information about local port * @erp_action: ERP action for the adapter for which port data is requested - * @adapter: for which port data is requested - * @data: response to exchange port data request */ int -zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action, - struct zfcp_adapter *adapter, - struct fsf_qtcb_bottom_port *data) +zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) { volatile struct qdio_buffer_element *sbale; - struct zfcp_fsf_req *fsf_req; + struct zfcp_fsf_req *fsf_req; + struct zfcp_adapter *adapter = erp_action->adapter; unsigned long lock_flags; - int retval = 0; + int retval; if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) { ZFCP_LOG_INFO("error: exchange port data " - "command not supported by adapter %s\n", + "command not supported by adapter %s\n", zfcp_get_busid_by_adapter(adapter)); - return -EOPNOTSUPP; - } + return -EOPNOTSUPP; + } /* setup new FSF request */ retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, - erp_action ? ZFCP_REQ_AUTO_CLEANUP : 0, - NULL, &lock_flags, &fsf_req); - if (retval < 0) { + ZFCP_REQ_AUTO_CLEANUP, + adapter->pool.fsf_req_erp, + &lock_flags, &fsf_req); + if (retval) { ZFCP_LOG_INFO("error: Out of resources. Could not create an " - "exchange port data request for" - "the adapter %s.\n", + "exchange port data request for" + "the adapter %s.\n", zfcp_get_busid_by_adapter(adapter)); write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); return retval; } - if (data) - fsf_req->data = (unsigned long) data; - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); - sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; - sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; + sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; + sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; - if (erp_action) { - erp_action->fsf_req = fsf_req; - fsf_req->erp_action = erp_action; - zfcp_erp_start_timer(fsf_req); - } else - zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); + erp_action->fsf_req = fsf_req; + fsf_req->erp_action = erp_action; + zfcp_erp_start_timer(fsf_req); retval = zfcp_fsf_req_send(fsf_req); + write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); + if (retval) { ZFCP_LOG_INFO("error: Could not send an exchange port data " - "command on the adapter %s\n", + "command on the adapter %s\n", zfcp_get_busid_by_adapter(adapter)); zfcp_fsf_req_free(fsf_req); - if (erp_action) - erp_action->fsf_req = NULL; + erp_action->fsf_req = NULL; + } + else + ZFCP_LOG_DEBUG("exchange port data request initiated " + "(adapter %s)\n", + zfcp_get_busid_by_adapter(adapter)); + return retval; +} + + +/** + * zfcp_fsf_exchange_port_data_sync - request information about local port + * and wait until information is ready + */ +int +zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter, + struct fsf_qtcb_bottom_port *data) +{ + volatile struct qdio_buffer_element *sbale; + struct zfcp_fsf_req *fsf_req; + unsigned long lock_flags; + int retval; + + if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) { + ZFCP_LOG_INFO("error: exchange port data " + "command not supported by adapter %s\n", + zfcp_get_busid_by_adapter(adapter)); + return -EOPNOTSUPP; + } + + /* setup new FSF request */ + retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, + 0, NULL, &lock_flags, &fsf_req); + if (retval) { + ZFCP_LOG_INFO("error: Out of resources. Could not create an " + "exchange port data request for" + "the adapter %s.\n", + zfcp_get_busid_by_adapter(adapter)); write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); return retval; } + if (data) + fsf_req->data = (unsigned long) data; + + sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); + sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; + sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; + + zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); + retval = zfcp_fsf_req_send(fsf_req); write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); - if (!erp_action) { + if (retval) + ZFCP_LOG_INFO("error: Could not send an exchange port data " + "command on the adapter %s\n", + zfcp_get_busid_by_adapter(adapter)); + else wait_event(fsf_req->completion_wq, fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); - zfcp_fsf_req_free(fsf_req); - } + + zfcp_fsf_req_free(fsf_req); + return retval; } @@ -2277,18 +2380,16 @@ static void zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok) { struct zfcp_adapter *adapter; - struct fsf_qtcb *qtcb; - struct fsf_qtcb_bottom_port *bottom, *data; + struct fsf_qtcb_bottom_port *bottom; struct Scsi_Host *shost; adapter = fsf_req->adapter; - qtcb = fsf_req->qtcb; - bottom = &qtcb->bottom.port; + bottom = &fsf_req->qtcb->bottom.port; shost = adapter->scsi_host; - data = (struct fsf_qtcb_bottom_port*) fsf_req->data; - if (data) - memcpy(data, bottom, sizeof(struct fsf_qtcb_bottom_port)); + if (fsf_req->data) + memcpy((struct fsf_qtcb_bottom_port*) fsf_req->data, bottom, + sizeof(struct fsf_qtcb_bottom_port)); if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) fc_host_permanent_port_name(shost) = bottom->wwpn; @@ -2336,10 +2437,10 @@ zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *fsf_req) /* * function: zfcp_fsf_open_port * - * purpose: + * purpose: * * returns: address of initiated FSF request - * NULL - request could not be initiated + * NULL - request could not be initiated */ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) @@ -2400,7 +2501,7 @@ zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) * * purpose: is called for finished Open Port command * - * returns: + * returns: */ static int zfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req) @@ -3002,7 +3103,7 @@ zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) * * purpose: is called for finished Open LUN command * - * returns: + * returns: */ static int zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) @@ -3265,7 +3366,7 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) * purpose: * * returns: address of fsf_req - request successfully initiated - * NULL - + * NULL - * * assumptions: This routine does not check whether the associated * remote port/lun has already been opened. This should be @@ -3586,17 +3687,17 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, ZFCP_LOG_DEBUG( "Data did not fit into available buffer(s), " "waiting for more...\n"); - retval = -EIO; - } else { - ZFCP_LOG_NORMAL("error: No truncation implemented but " - "required. Shutting down unit " - "(adapter %s, port 0x%016Lx, " - "unit 0x%016Lx)\n", - zfcp_get_busid_by_unit(unit), - unit->port->wwpn, - unit->fcp_lun); - zfcp_erp_unit_shutdown(unit, 0); - retval = -EINVAL; + retval = -EIO; + } else { + ZFCP_LOG_NORMAL("error: No truncation implemented but " + "required. Shutting down unit " + "(adapter %s, port 0x%016Lx, " + "unit 0x%016Lx)\n", + zfcp_get_busid_by_unit(unit), + unit->port->wwpn, + unit->fcp_lun); + zfcp_erp_unit_shutdown(unit, 0); + retval = -EINVAL; } goto no_fit; } @@ -3727,7 +3828,7 @@ zfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter, * * purpose: is called for finished Send FCP Command * - * returns: + * returns: */ static int zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req) @@ -3964,7 +4065,7 @@ zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req) * * purpose: evaluates FCP_RSP IU * - * returns: + * returns: */ static int zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) @@ -4192,7 +4293,7 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) * * purpose: evaluates FCP_RSP IU * - * returns: + * returns: */ static int zfcp_fsf_send_fcp_command_task_management_handler(struct zfcp_fsf_req *fsf_req) @@ -4635,7 +4736,7 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags, INIT_LIST_HEAD(&fsf_req->list); init_timer(&fsf_req->timer); - /* initialize waitqueue which may be used to wait on + /* initialize waitqueue which may be used to wait on this request completion */ init_waitqueue_head(&fsf_req->completion_wq); diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h index 71186618947c..8cce5cc11d50 100644 --- a/drivers/s390/scsi/zfcp_fsf.h +++ b/drivers/s390/scsi/zfcp_fsf.h @@ -1,22 +1,22 @@ -/* +/* * This file is part of the zfcp device driver for * FCP adapters for IBM System z9 and zSeries. * * (C) Copyright IBM Corp. 2002, 2006 - * - * 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, 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. + * + * 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, 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. */ #ifndef FSF_H diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index c6899efdc8f6..3f105fdcf239 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -174,10 +174,9 @@ zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter, unsigned int status, * That is why we need to clear the link-down flag * which is set again in case we have missed by a mile. */ - zfcp_erp_adapter_reopen( - adapter, - ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | - ZFCP_STATUS_COMMON_ERP_FAILED); + zfcp_erp_adapter_reopen(adapter, + ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | + ZFCP_STATUS_COMMON_ERP_FAILED); } return retval; } diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index ad7eb4a9261c..abae2027f7e5 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -1,22 +1,22 @@ -/* +/* * This file is part of the zfcp device driver for * FCP adapters for IBM System z9 and zSeries. * * (C) Copyright IBM Corp. 2002, 2006 - * - * 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, 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. + * + * 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, 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. */ #define ZFCP_LOG_AREA ZFCP_LOG_AREA_SCSI @@ -101,7 +101,7 @@ zfcp_get_fcp_dl_ptr(struct fcp_cmnd_iu * fcp_cmd) ((unsigned char *) fcp_cmd + sizeof (struct fcp_cmnd_iu) + additional_length); /* - * fcp_dl_addr = start address of fcp_cmnd structure + + * fcp_dl_addr = start address of fcp_cmnd structure + * size of fixed part + size of dynamically sized add_dcp_cdb field * SEE FCP-2 documentation */ @@ -189,13 +189,12 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) unit->device = NULL; zfcp_erp_unit_failed(unit); zfcp_unit_put(unit); - } else { + } else ZFCP_LOG_NORMAL("bug: no unit associated with SCSI device at " "address %p\n", sdpnt); - } } -/* +/* * called from scsi midlayer to allow finetuning of a device. */ static int @@ -361,12 +360,11 @@ zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, unsigned int id, list_for_each_entry(port, &adapter->port_list_head, list) { if (!port->rport || (id != port->rport->scsi_target_id)) continue; - list_for_each_entry(unit, &port->unit_list_head, list) { + list_for_each_entry(unit, &port->unit_list_head, list) if (lun == unit->scsi_lun) { retval = unit; goto out; } - } } out: return retval; @@ -374,7 +372,7 @@ zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, unsigned int id, /** * zfcp_scsi_eh_abort_handler - abort the specified SCSI command - * @scpnt: pointer to scsi_cmnd to be aborted + * @scpnt: pointer to scsi_cmnd to be aborted * Return: SUCCESS - command has been aborted and cleaned up in internal * bookkeeping, SCSI stack won't be called for aborted command * FAILED - otherwise @@ -733,7 +731,7 @@ zfcp_get_fc_host_stats(struct Scsi_Host *shost) if (!data) return NULL; - ret = zfcp_fsf_exchange_port_data(NULL, adapter, data); + ret = zfcp_fsf_exchange_port_data_sync(adapter, data); if (ret) { kfree(data); return NULL; /* XXX return zeroed fc_stats? */ @@ -763,7 +761,7 @@ zfcp_reset_fc_host_stats(struct Scsi_Host *shost) if (!data) return; - ret = zfcp_fsf_exchange_port_data(NULL, adapter, data); + ret = zfcp_fsf_exchange_port_data_sync(adapter, data); if (ret) { kfree(data); } else { @@ -802,6 +800,7 @@ struct fc_function_template zfcp_transport_functions = { .show_host_port_type = 1, .show_host_speed = 1, .show_host_port_id = 1, + .disable_target_scan = 1, }; /** diff --git a/drivers/s390/scsi/zfcp_sysfs_unit.c b/drivers/s390/scsi/zfcp_sysfs_unit.c index 81a484175863..63f75ee95c33 100644 --- a/drivers/s390/scsi/zfcp_sysfs_unit.c +++ b/drivers/s390/scsi/zfcp_sysfs_unit.c @@ -139,7 +139,7 @@ static struct attribute_group zfcp_unit_attr_group = { .attrs = zfcp_unit_attrs, }; -/** +/** * zfcp_sysfs_create_unit_files - create sysfs unit files * @dev: pointer to belonging device * @@ -151,7 +151,7 @@ zfcp_sysfs_unit_create_files(struct device *dev) return sysfs_create_group(&dev->kobj, &zfcp_unit_attr_group); } -/** +/** * zfcp_sysfs_remove_unit_files - remove sysfs unit files * @dev: pointer to belonging device * diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 6f2c71ef47ee..30905cebefbb 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -272,6 +272,13 @@ config SCSI_FC_ATTRS each attached FiberChannel device to sysfs, say Y. Otherwise, say N. +config SCSI_FC_TGT_ATTRS + bool "SCSI target support for FiberChannel Transport Attributes" + depends on SCSI_FC_ATTRS + depends on SCSI_TGT = y || SCSI_TGT = SCSI_FC_ATTRS + help + If you want to use SCSI target mode drivers enable this option. + config SCSI_ISCSI_ATTRS tristate "iSCSI Transport Attributes" depends on SCSI && NET @@ -289,6 +296,20 @@ config SCSI_SAS_ATTRS source "drivers/scsi/libsas/Kconfig" +config SCSI_SRP_ATTRS + tristate "SRP Transport Attributes" + depends on SCSI + help + If you wish to export transport-specific information about + each attached SRP device to sysfs, say Y. + +config SCSI_SRP_TGT_ATTRS + bool "SCSI target support for SRP Transport Attributes" + depends on SCSI_SRP_ATTRS + depends on SCSI_TGT = y || SCSI_TGT = SCSI_SRP_ATTRS + help + If you want to use SCSI target mode drivers enable this option. + endmenu menuconfig SCSI_LOWLEVEL @@ -502,7 +523,6 @@ config SCSI_ADVANSYS tristate "AdvanSys SCSI support" depends on SCSI depends on ISA || EISA || PCI - depends on BROKEN || X86_32 help This is a driver for all SCSI host adapters manufactured by AdvanSys. It is documented in the kernel source in @@ -524,19 +544,32 @@ config SCSI_IN2000 module will be called in2000. config SCSI_ARCMSR - tristate "ARECA ARC11X0[PCI-X]/ARC12X0[PCI-EXPRESS] SATA-RAID support" + tristate "ARECA (ARC11xx/12xx/13xx/16xx) SATA/SAS RAID Host Adapter" depends on PCI && SCSI help - This driver supports all of ARECA's SATA RAID controller cards. + This driver supports all of ARECA's SATA/SAS RAID controller cards. This is an ARECA-maintained driver by Erich Chen. - If you have any problems, please mail to: < erich@areca.com.tw > + If you have any problems, please mail to: <erich@areca.com.tw>. Areca supports Linux RAID config tools. - - < http://www.areca.com.tw > + Please link <http://www.areca.com.tw> To compile this driver as a module, choose M here: the module will be called arcmsr (modprobe arcmsr). +config SCSI_ARCMSR_AER + bool "Enable PCI Error Recovery Capability in Areca Driver(ARCMSR)" + depends on SCSI_ARCMSR && PCIEAER + default n + help + The advanced error reporting(AER) capability is "NOT" provided by + ARC1200/1201/1202 SATA RAID controllers cards. + If your card is one of ARC1200/1201/1202, please use the default setting, n. + If your card is other models, you could pick it + on condition that the kernel version is greater than 2.6.19. + This function is maintained driver by Nick Cheng. If you have any + problems or suggestion, you are welcome to contact with <nick.cheng@areca.com.tw>. + To enable this function, choose Y here. + source "drivers/scsi/megaraid/Kconfig.megaraid" config SCSI_HPTIOP @@ -836,6 +869,7 @@ config SCSI_IPS config SCSI_IBMVSCSI tristate "IBM Virtual SCSI support" depends on PPC_PSERIES || PPC_ISERIES + select SCSI_SRP_ATTRS help This is the IBM POWER Virtual SCSI Client @@ -844,7 +878,7 @@ config SCSI_IBMVSCSI config SCSI_IBMVSCSIS tristate "IBM Virtual SCSI Server support" - depends on PPC_PSERIES && SCSI_TGT && SCSI_SRP + depends on PPC_PSERIES && SCSI_SRP && SCSI_SRP_TGT_ATTRS help This is the SRP target driver for IBM pSeries virtual environments. diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 86a7ba7bad63..6141389dcdb2 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_SCSI_FC_ATTRS) += scsi_transport_fc.o obj-$(CONFIG_SCSI_ISCSI_ATTRS) += scsi_transport_iscsi.o obj-$(CONFIG_SCSI_SAS_ATTRS) += scsi_transport_sas.o obj-$(CONFIG_SCSI_SAS_LIBSAS) += libsas/ +obj-$(CONFIG_SCSI_SRP_ATTRS) += scsi_transport_srp.o obj-$(CONFIG_ISCSI_TCP) += libiscsi.o iscsi_tcp.o obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index f8e449a98d29..988f0bc5eda5 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -1542,9 +1542,7 @@ part2: hostdata->connected = cmd; hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); - if (cmd->SCp.ptr != (char *)cmd->sense_buffer) { - initialize_SCp(cmd); - } + initialize_SCp(cmd); return 0; @@ -2133,7 +2131,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) { sink = 1; do_abort(instance); cmd->result = DID_ERROR << 16; - cmd->done(cmd); + cmd->scsi_done(cmd); return; #endif /* @@ -2196,7 +2194,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) { sink = 1; do_abort(instance); cmd->result = DID_ERROR << 16; - cmd->done(cmd); + cmd->scsi_done(cmd); /* XXX - need to source or sink data here, as appropriate */ } else cmd->SCp.this_residual -= transfersize - len; @@ -2280,19 +2278,16 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) { cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); #ifdef AUTOSENSE + if ((cmd->cmnd[0] == REQUEST_SENSE) && + hostdata->ses.cmd_len) { + scsi_eh_restore_cmnd(cmd, &hostdata->ses); + hostdata->ses.cmd_len = 0 ; + } + if ((cmd->cmnd[0] != REQUEST_SENSE) && (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) { + scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0); + dprintk(NDEBUG_AUTOSENSE, ("scsi%d : performing request sense\n", instance->host_no)); - cmd->cmnd[0] = REQUEST_SENSE; - cmd->cmnd[1] &= 0xe0; - cmd->cmnd[2] = 0; - cmd->cmnd[3] = 0; - cmd->cmnd[4] = sizeof(cmd->sense_buffer); - cmd->cmnd[5] = 0; - - cmd->SCp.buffer = NULL; - cmd->SCp.buffers_residual = 0; - cmd->SCp.ptr = (char *) cmd->sense_buffer; - cmd->SCp.this_residual = sizeof(cmd->sense_buffer); LIST(cmd, hostdata->issue_queue); cmd->host_scribble = (unsigned char *) @@ -2740,7 +2735,7 @@ static int NCR5380_abort(Scsi_Cmnd * cmd) { tmp->host_scribble = NULL; tmp->result = DID_ABORT << 16; dprintk(NDEBUG_ABORT, ("scsi%d : abort removed command from issue queue.\n", instance->host_no)); - tmp->done(tmp); + tmp->scsi_done(tmp); return SUCCESS; } #if (NDEBUG & NDEBUG_ABORT) @@ -2805,7 +2800,7 @@ static int NCR5380_abort(Scsi_Cmnd * cmd) { *prev = (Scsi_Cmnd *) tmp->host_scribble; tmp->host_scribble = NULL; tmp->result = DID_ABORT << 16; - tmp->done(tmp); + tmp->scsi_done(tmp); return SUCCESS; } } diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h index bccf13f71532..bdc468c9e1d9 100644 --- a/drivers/scsi/NCR5380.h +++ b/drivers/scsi/NCR5380.h @@ -30,6 +30,10 @@ #include <linux/interrupt.h> +#ifdef AUTOSENSE +#include <scsi/scsi_eh.h> +#endif + #define NCR5380_PUBLIC_RELEASE 7 #define NCR53C400_PUBLIC_RELEASE 2 @@ -281,6 +285,9 @@ struct NCR5380_hostdata { unsigned pendingr; unsigned pendingw; #endif +#ifdef AUTOSENSE + struct scsi_eh_save ses; +#endif }; #ifdef __KERNEL__ diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c index 79b4df158140..96e8e29aa05d 100644 --- a/drivers/scsi/NCR53C9x.c +++ b/drivers/scsi/NCR53C9x.c @@ -1385,7 +1385,7 @@ int esp_abort(Scsi_Cmnd *SCptr) this->host_scribble = NULL; esp_release_dmabufs(esp, this); this->result = DID_ABORT << 16; - this->done(this); + this->scsi_done(this); if(don) esp->dma_ints_on(esp); return SUCCESS; diff --git a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c index 3a8089705feb..9e64b21ef637 100644 --- a/drivers/scsi/NCR_D700.c +++ b/drivers/scsi/NCR_D700.c @@ -97,7 +97,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/mca.h> -#include <linux/interrupt.h> #include <asm/io.h> #include <scsi/scsi_host.h> #include <scsi/scsi_device.h> @@ -314,10 +313,10 @@ NCR_D700_probe(struct device *dev) break; } - p = kmalloc(sizeof(*p), GFP_KERNEL); + p = kzalloc(sizeof(*p), GFP_KERNEL); if (!p) return -ENOMEM; - memset(p, '\0', sizeof(*p)); + p->dev = dev; snprintf(p->name, sizeof(p->name), "D700(%s)", dev->bus_id); if (request_irq(irq, NCR_D700_intr, IRQF_SHARED, p->name, p)) { diff --git a/drivers/scsi/a4000t.c b/drivers/scsi/a4000t.c index 0c758d1452ba..d4bda2017746 100644 --- a/drivers/scsi/a4000t.c +++ b/drivers/scsi/a4000t.c @@ -37,7 +37,7 @@ static struct platform_device *a4000t_scsi_device; static int __devinit a4000t_probe(struct device *dev) { - struct Scsi_Host * host = NULL; + struct Scsi_Host *host; struct NCR_700_Host_Parameters *hostdata; if (!(MACH_IS_AMIGA && AMIGAHW_PRESENT(A4000_SCSI))) @@ -47,12 +47,11 @@ static int __devinit a4000t_probe(struct device *dev) "A4000T builtin SCSI")) goto out; - hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL); - if (hostdata == NULL) { + hostdata = kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL); + if (!hostdata) { printk(KERN_ERR "a4000t-scsi: Failed to allocate host data\n"); goto out_release; } - memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters)); /* Fill in the required pieces of hostdata */ hostdata->base = (void __iomem *)ZTWO_VADDR(A4000T_SCSI_ADDR); diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 6800e578e4b1..80e448d0f3db 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -177,9 +177,9 @@ int check_interval = 24 * 60 * 60; module_param(check_interval, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(check_interval, "Interval in seconds between adapter health checks."); -int check_reset = 1; -module_param(check_reset, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(check_reset, "If adapter fails health check, reset the adapter."); +int aac_check_reset = 1; +module_param_named(check_reset, aac_check_reset, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(aac_check_reset, "If adapter fails health check, reset the adapter."); int expose_physicals = -1; module_param(expose_physicals, int, S_IRUGO|S_IWUSR); @@ -1305,7 +1305,7 @@ int aac_get_adapter_info(struct aac_dev* dev) (int)sizeof(dev->supplement_adapter_info.VpdInfo.Tsid), dev->supplement_adapter_info.VpdInfo.Tsid); } - if (!check_reset || + if (!aac_check_reset || (dev->supplement_adapter_info.SupportedOptions2 & le32_to_cpu(AAC_OPTION_IGNORE_RESET))) { printk(KERN_INFO "%s%d: Reset Adapter Ignored\n", diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 94727b9375ec..03b51025a8f4 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -1871,4 +1871,4 @@ extern int aac_reset_devices; extern int aac_commit; extern int update_interval; extern int check_interval; -extern int check_reset; +extern int aac_check_reset; diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index bb870906b4cf..240a0bb8986f 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -1372,8 +1372,9 @@ int aac_check_health(struct aac_dev * aac) printk(KERN_ERR "%s: Host adapter BLINK LED 0x%x\n", aac->name, BlinkLED); - if (!check_reset || (aac->supplement_adapter_info.SupportedOptions2 & - le32_to_cpu(AAC_OPTION_IGNORE_RESET))) + if (!aac_check_reset || + (aac->supplement_adapter_info.SupportedOptions2 & + le32_to_cpu(AAC_OPTION_IGNORE_RESET))) goto out; host = aac->scsi_host_ptr; if (aac->thread->pid != current->pid) diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 79c0b6e37a3b..9dd3952516c5 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -1,765 +1,27 @@ -#define ASC_VERSION "3.3K" /* AdvanSys Driver Version */ +#define DRV_NAME "advansys" +#define ASC_VERSION "3.4" /* AdvanSys Driver Version */ /* * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters * * Copyright (c) 1995-2000 Advanced System Products, Inc. * Copyright (c) 2000-2001 ConnectCom Solutions, Inc. + * Copyright (c) 2007 Matthew Wilcox <matthew@wil.cx> * All Rights Reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that redistributions of source - * code retain the above copyright notice and this comment without - * modification. - * - * As of March 8, 2000 Advanced System Products, Inc. (AdvanSys) - * changed its name to ConnectCom Solutions, Inc. - * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. */ /* - - Documentation for the AdvanSys Driver - - A. Linux Kernels Supported by this Driver - B. Adapters Supported by this Driver - C. Linux source files modified by AdvanSys Driver - D. Source Comments - E. Driver Compile Time Options and Debugging - F. Driver LILO Option - G. Tests to run before releasing new driver - H. Release History - I. Known Problems/Fix List - J. Credits (Chronological Order) - - A. Linux Kernels Supported by this Driver - - This driver has been tested in the following Linux kernels: v2.2.18 - v2.4.0. The driver is supported on v2.2 and v2.4 kernels and on x86, - alpha, and PowerPC platforms. - - B. Adapters Supported by this Driver - - AdvanSys (Advanced System Products, Inc.) manufactures the following - RISC-based, Bus-Mastering, Fast (10 Mhz) and Ultra (20 Mhz) Narrow - (8-bit transfer) SCSI Host Adapters for the ISA, EISA, VL, and PCI - buses and RISC-based, Bus-Mastering, Ultra (20 Mhz) Wide (16-bit - transfer) SCSI Host Adapters for the PCI bus. - - The CDB counts below indicate the number of SCSI CDB (Command - Descriptor Block) requests that can be stored in the RISC chip - cache and board LRAM. A CDB is a single SCSI command. The driver - detect routine will display the number of CDBs available for each - adapter detected. The number of CDBs used by the driver can be - lowered in the BIOS by changing the 'Host Queue Size' adapter setting. - - Laptop Products: - ABP-480 - Bus-Master CardBus (16 CDB) (2.4 kernel and greater) - - Connectivity Products: - ABP510/5150 - Bus-Master ISA (240 CDB) - ABP5140 - Bus-Master ISA PnP (16 CDB) - ABP5142 - Bus-Master ISA PnP with floppy (16 CDB) - ABP902/3902 - Bus-Master PCI (16 CDB) - ABP3905 - Bus-Master PCI (16 CDB) - ABP915 - Bus-Master PCI (16 CDB) - ABP920 - Bus-Master PCI (16 CDB) - ABP3922 - Bus-Master PCI (16 CDB) - ABP3925 - Bus-Master PCI (16 CDB) - ABP930 - Bus-Master PCI (16 CDB) - ABP930U - Bus-Master PCI Ultra (16 CDB) - ABP930UA - Bus-Master PCI Ultra (16 CDB) - ABP960 - Bus-Master PCI MAC/PC (16 CDB) - ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB) - - Single Channel Products: - ABP542 - Bus-Master ISA with floppy (240 CDB) - ABP742 - Bus-Master EISA (240 CDB) - ABP842 - Bus-Master VL (240 CDB) - ABP940 - Bus-Master PCI (240 CDB) - ABP940U - Bus-Master PCI Ultra (240 CDB) - ABP940UA/3940UA - Bus-Master PCI Ultra (240 CDB) - ABP970 - Bus-Master PCI MAC/PC (240 CDB) - ABP970U - Bus-Master PCI MAC/PC Ultra (240 CDB) - ABP3960UA - Bus-Master PCI MAC/PC Ultra (240 CDB) - ABP940UW/3940UW - Bus-Master PCI Ultra-Wide (253 CDB) - ABP970UW - Bus-Master PCI MAC/PC Ultra-Wide (253 CDB) - ABP3940U2W - Bus-Master PCI LVD/Ultra2-Wide (253 CDB) - - Multi-Channel Products: - ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel) - ABP852 - Dual Channel Bus-Master VL (240 CDB Per Channel) - ABP950 - Dual Channel Bus-Master PCI (240 CDB Per Channel) - ABP950UW - Dual Channel Bus-Master PCI Ultra-Wide (253 CDB Per Channel) - ABP980 - Four Channel Bus-Master PCI (240 CDB Per Channel) - ABP980U - Four Channel Bus-Master PCI Ultra (240 CDB Per Channel) - ABP980UA/3980UA - Four Channel Bus-Master PCI Ultra (16 CDB Per Chan.) - ABP3950U2W - Bus-Master PCI LVD/Ultra2-Wide and Ultra-Wide (253 CDB) - ABP3950U3W - Bus-Master PCI Dual LVD2/Ultra3-Wide (253 CDB) - - C. Linux source files modified by AdvanSys Driver - - This section for historical purposes documents the changes - originally made to the Linux kernel source to add the advansys - driver. As Linux has changed some of these files have also - been modified. - - 1. linux/arch/i386/config.in: - - bool 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS y - - 2. linux/drivers/scsi/hosts.c: - - #ifdef CONFIG_SCSI_ADVANSYS - #include "advansys.h" - #endif - - and after "static struct scsi_host_template builtin_scsi_hosts[] =": - - #ifdef CONFIG_SCSI_ADVANSYS - ADVANSYS, - #endif - - 3. linux/drivers/scsi/Makefile: - - ifdef CONFIG_SCSI_ADVANSYS - SCSI_SRCS := $(SCSI_SRCS) advansys.c - SCSI_OBJS := $(SCSI_OBJS) advansys.o - else - SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) advansys.o - endif - - 4. linux/init/main.c: - - extern void advansys_setup(char *str, int *ints); - - and add the following lines to the bootsetups[] array. - - #ifdef CONFIG_SCSI_ADVANSYS - { "advansys=", advansys_setup }, - #endif - - D. Source Comments - - 1. Use tab stops set to 4 for the source files. For vi use 'se tabstops=4'. - - 2. This driver should be maintained in multiple files. But to make - it easier to include with Linux and to follow Linux conventions, - the whole driver is maintained in the source files advansys.h and - advansys.c. In this file logical sections of the driver begin with - a comment that contains '---'. The following are the logical sections - of the driver below. - - --- Linux Version - --- Linux Include File - --- Driver Options - --- Debugging Header - --- Asc Library Constants and Macros - --- Adv Library Constants and Macros - --- Driver Constants and Macros - --- Driver Structures - --- Driver Data - --- Driver Function Prototypes - --- Linux 'struct scsi_host_template' and advansys_setup() Functions - --- Loadable Driver Support - --- Miscellaneous Driver Functions - --- Functions Required by the Asc Library - --- Functions Required by the Adv Library - --- Tracing and Debugging Functions - --- Asc Library Functions - --- Adv Library Functions - - 3. The string 'XXX' is used to flag code that needs to be re-written - or that contains a problem that needs to be addressed. - - 4. I have stripped comments from and reformatted the source for the - Asc Library and Adv Library to reduce the size of this file. This - source can be found under the following headings. The Asc Library - is used to support Narrow Boards. The Adv Library is used to - support Wide Boards. - - --- Asc Library Constants and Macros - --- Adv Library Constants and Macros - --- Asc Library Functions - --- Adv Library Functions - - E. Driver Compile Time Options and Debugging - - In this source file the following constants can be defined. They are - defined in the source below. Both of these options are enabled by - default. - - 1. ADVANSYS_ASSERT - Enable driver assertions (Def: Enabled) - - Enabling this option adds assertion logic statements to the - driver. If an assertion fails a message will be displayed to - the console, but the system will continue to operate. Any - assertions encountered should be reported to the person - responsible for the driver. Assertion statements may proactively - detect problems with the driver and facilitate fixing these - problems. Enabling assertions will add a small overhead to the - execution of the driver. - - 2. ADVANSYS_DEBUG - Enable driver debugging (Def: Disabled) - - Enabling this option adds tracing functions to the driver and - the ability to set a driver tracing level at boot time. This - option will also export symbols not required outside the driver to - the kernel name space. This option is very useful for debugging - the driver, but it will add to the size of the driver execution - image and add overhead to the execution of the driver. - - The amount of debugging output can be controlled with the global - variable 'asc_dbglvl'. The higher the number the more output. By - default the debug level is 0. - - If the driver is loaded at boot time and the LILO Driver Option - is included in the system, the debug level can be changed by - specifying a 5th (ASC_NUM_IOPORT_PROBE + 1) I/O Port. The - first three hex digits of the pseudo I/O Port must be set to - 'deb' and the fourth hex digit specifies the debug level: 0 - F. - The following command line will look for an adapter at 0x330 - and set the debug level to 2. - - linux advansys=0x330,0,0,0,0xdeb2 - - If the driver is built as a loadable module this variable can be - defined when the driver is loaded. The following insmod command - will set the debug level to one. - - insmod advansys.o asc_dbglvl=1 - - Debugging Message Levels: - 0: Errors Only - 1: High-Level Tracing - 2-N: Verbose Tracing - - To enable debug output to console, please make sure that: - - a. System and kernel logging is enabled (syslogd, klogd running). - b. Kernel messages are routed to console output. Check - /etc/syslog.conf for an entry similar to this: - - kern.* /dev/console - - c. klogd is started with the appropriate -c parameter - (e.g. klogd -c 8) - - This will cause printk() messages to be be displayed on the - current console. Refer to the klogd(8) and syslogd(8) man pages - for details. - - Alternatively you can enable printk() to console with this - program. However, this is not the 'official' way to do this. - Debug output is logged in /var/log/messages. - - main() - { - syscall(103, 7, 0, 0); - } - - Increasing LOG_BUF_LEN in kernel/printk.c to something like - 40960 allows more debug messages to be buffered in the kernel - and written to the console or log file. - - 3. ADVANSYS_STATS - Enable statistics (Def: Enabled >= v1.3.0) - - Enabling this option adds statistics collection and display - through /proc to the driver. The information is useful for - monitoring driver and device performance. It will add to the - size of the driver execution image and add minor overhead to - the execution of the driver. - - Statistics are maintained on a per adapter basis. Driver entry - point call counts and transfer size counts are maintained. - Statistics are only available for kernels greater than or equal - to v1.3.0 with the CONFIG_PROC_FS (/proc) file system configured. - - AdvanSys SCSI adapter files have the following path name format: - - /proc/scsi/advansys/[0-(ASC_NUM_BOARD_SUPPORTED-1)] - - This information can be displayed with cat. For example: - - cat /proc/scsi/advansys/0 - - When ADVANSYS_STATS is not defined the AdvanSys /proc files only - contain adapter and device configuration information. - - F. Driver LILO Option - - If init/main.c is modified as described in the 'Directions for Adding - the AdvanSys Driver to Linux' section (B.4.) above, the driver will - recognize the 'advansys' LILO command line and /etc/lilo.conf option. - This option can be used to either disable I/O port scanning or to limit - scanning to 1 - 4 I/O ports. Regardless of the option setting EISA and - PCI boards will still be searched for and detected. This option only - affects searching for ISA and VL boards. - - Examples: - 1. Eliminate I/O port scanning: - boot: linux advansys= - or - boot: linux advansys=0x0 - 2. Limit I/O port scanning to one I/O port: - boot: linux advansys=0x110 - 3. Limit I/O port scanning to four I/O ports: - boot: linux advansys=0x110,0x210,0x230,0x330 - - For a loadable module the same effect can be achieved by setting - the 'asc_iopflag' variable and 'asc_ioport' array when loading - the driver, e.g. - - insmod advansys.o asc_iopflag=1 asc_ioport=0x110,0x330 - - If ADVANSYS_DEBUG is defined a 5th (ASC_NUM_IOPORT_PROBE + 1) - I/O Port may be added to specify the driver debug level. Refer to - the 'Driver Compile Time Options and Debugging' section above for - more information. - - G. Tests to run before releasing new driver - - 1. In the supported kernels verify there are no warning or compile - errors when the kernel is built as both a driver and as a module - and with the following options: - - ADVANSYS_DEBUG - enabled and disabled - CONFIG_SMP - enabled and disabled - CONFIG_PROC_FS - enabled and disabled - - 2. Run tests on an x86, alpha, and PowerPC with at least one narrow - card and one wide card attached to a hard disk and CD-ROM drive: - fdisk, mkfs, fsck, bonnie, copy/compare test from the - CD-ROM to the hard drive. - - H. Release History - - BETA-1.0 (12/23/95): - First Release - - BETA-1.1 (12/28/95): - 1. Prevent advansys_detect() from being called twice. - 2. Add LILO 0xdeb[0-f] option to set 'asc_dbglvl'. - - 1.2 (1/12/96): - 1. Prevent re-entrancy in the interrupt handler which - resulted in the driver hanging Linux. - 2. Fix problem that prevented ABP-940 cards from being - recognized on some PCI motherboards. - 3. Add support for the ABP-5140 PnP ISA card. - 4. Fix check condition return status. - 5. Add conditionally compiled code for Linux v1.3.X. - - 1.3 (2/23/96): - 1. Fix problem in advansys_biosparam() that resulted in the - wrong drive geometry being returned for drives > 1GB with - extended translation enabled. - 2. Add additional tracing during device initialization. - 3. Change code that only applies to ISA PnP adapter. - 4. Eliminate 'make dep' warning. - 5. Try to fix problem with handling resets by increasing their - timeout value. - - 1.4 (5/8/96): - 1. Change definitions to eliminate conflicts with other subsystems. - 2. Add versioning code for the shared interrupt changes. - 3. Eliminate problem in asc_rmqueue() with iterating after removing - a request. - 4. Remove reset request loop problem from the "Known Problems or - Issues" section. This problem was isolated and fixed in the - mid-level SCSI driver. - - 1.5 (8/8/96): - 1. Add support for ABP-940U (PCI Ultra) adapter. - 2. Add support for IRQ sharing by setting the IRQF_SHARED flag for - request_irq and supplying a dev_id pointer to both request_irq() - and free_irq(). - 3. In AscSearchIOPortAddr11() restore a call to check_region() which - should be used before I/O port probing. - 4. Fix bug in asc_prt_hex() which resulted in the displaying - the wrong data. - 5. Incorporate miscellaneous Asc Library bug fixes and new microcode. - 6. Change driver versioning to be specific to each Linux sub-level. - 7. Change statistics gathering to be per adapter instead of global - to the driver. - 8. Add more information and statistics to the adapter /proc file: - /proc/scsi/advansys[0...]. - 9. Remove 'cmd_per_lun' from the "Known Problems or Issues" list. - This problem has been addressed with the SCSI mid-level changes - made in v1.3.89. The advansys_select_queue_depths() function - was added for the v1.3.89 changes. - - 1.6 (9/10/96): - 1. Incorporate miscellaneous Asc Library bug fixes and new microcode. - - 1.7 (9/25/96): - 1. Enable clustering and optimize the setting of the maximum number - of scatter gather elements for any particular board. Clustering - increases CPU utilization, but results in a relatively larger - increase in I/O throughput. - 2. Improve the performance of the request queuing functions by - adding a last pointer to the queue structure. - 3. Correct problems with reset and abort request handling that - could have hung or crashed Linux. - 4. Add more information to the adapter /proc file: - /proc/scsi/advansys[0...]. - 5. Remove the request timeout issue form the driver issues list. - 6. Miscellaneous documentation additions and changes. - - 1.8 (10/4/96): - 1. Make changes to handle the new v2.1.0 kernel memory mapping - in which a kernel virtual address may not be equivalent to its - bus or DMA memory address. - 2. Change abort and reset request handling to make it yet even - more robust. - 3. Try to mitigate request starvation by sending ordered requests - to heavily loaded, tag queuing enabled devices. - 4. Maintain statistics on request response time. - 5. Add request response time statistics and other information to - the adapter /proc file: /proc/scsi/advansys[0...]. - - 1.9 (10/21/96): - 1. Add conditionally compiled code (ASC_QUEUE_FLOW_CONTROL) to - make use of mid-level SCSI driver device queue depth flow - control mechanism. This will eliminate aborts caused by a - device being unable to keep up with requests and eliminate - repeat busy or QUEUE FULL status returned by a device. - 2. Incorporate miscellaneous Asc Library bug fixes. - 3. To allow the driver to work in kernels with broken module - support set 'cmd_per_lun' if the driver is compiled as a - module. This change affects kernels v1.3.89 to present. - 4. Remove PCI BIOS address from the driver banner. The PCI BIOS - is relocated by the motherboard BIOS and its new address can - not be determined by the driver. - 5. Add mid-level SCSI queue depth information to the adapter - /proc file: /proc/scsi/advansys[0...]. - - 2.0 (11/14/96): - 1. Change allocation of global structures used for device - initialization to guarantee they are in DMA-able memory. - Previously when the driver was loaded as a module these - structures might not have been in DMA-able memory, causing - device initialization to fail. - - 2.1 (12/30/96): - 1. In advansys_reset(), if the request is a synchronous reset - request, even if the request serial number has changed, then - complete the request. - 2. Add Asc Library bug fixes including new microcode. - 3. Clear inquiry buffer before using it. - 4. Correct ifdef typo. - - 2.2 (1/15/97): - 1. Add Asc Library bug fixes including new microcode. - 2. Add synchronous data transfer rate information to the - adapter /proc file: /proc/scsi/advansys[0...]. - 3. Change ADVANSYS_DEBUG to be disabled by default. This - will reduce the size of the driver image, eliminate execution - overhead, and remove unneeded symbols from the kernel symbol - space that were previously added by the driver. - 4. Add new compile-time option ADVANSYS_ASSERT for assertion - code that used to be defined within ADVANSYS_DEBUG. This - option is enabled by default. - - 2.8 (5/26/97): - 1. Change version number to 2.8 to synchronize the Linux driver - version numbering with other AdvanSys drivers. - 2. Reformat source files without tabs to present the same view - of the file to everyone regardless of the editor tab setting - being used. - 3. Add Asc Library bug fixes. - - 3.1A (1/8/98): - 1. Change version number to 3.1 to indicate that support for - Ultra-Wide adapters (ABP-940UW) is included in this release. - 2. Add Asc Library (Narrow Board) bug fixes. - 3. Report an underrun condition with the host status byte set - to DID_UNDERRUN. Currently DID_UNDERRUN is defined to 0 which - causes the underrun condition to be ignored. When Linux defines - its own DID_UNDERRUN the constant defined in this file can be - removed. - 4. Add patch to AscWaitTixISRDone(). - 5. Add support for up to 16 different AdvanSys host adapter SCSI - channels in one system. This allows four cards with four channels - to be used in one system. - - 3.1B (1/9/98): - 1. Handle that PCI register base addresses are not always page - aligned even though ioremap() requires that the address argument - be page aligned. - - 3.1C (1/10/98): - 1. Update latest BIOS version checked for from the /proc file. - 2. Don't set microcode SDTR variable at initialization. Instead - wait until device capabilities have been detected from an Inquiry - command. - - 3.1D (1/21/98): - 1. Improve performance when the driver is compiled as module by - allowing up to 64 scatter-gather elements instead of 8. - - 3.1E (5/1/98): - 1. Set time delay in AscWaitTixISRDone() to 1000 ms. - 2. Include SMP locking changes. - 3. For v2.1.93 and newer kernels use CONFIG_PCI and new PCI BIOS - access functions. - 4. Update board serial number printing. - 5. Try allocating an IRQ both with and without the IRQF_DISABLED - flag set to allow IRQ sharing with drivers that do not set - the IRQF_DISABLED flag. Also display a more descriptive error - message if request_irq() fails. - 6. Update to latest Asc and Adv Libraries. - - 3.2A (7/22/99): - 1. Update Adv Library to 4.16 which includes support for - the ASC38C0800 (Ultra2/LVD) IC. - - 3.2B (8/23/99): - 1. Correct PCI compile time option for v2.1.93 and greater - kernels, advansys_info() string, and debug compile time - option. - 2. Correct DvcSleepMilliSecond() for v2.1.0 and greater - kernels. This caused an LVD detection/BIST problem problem - among other things. - 3. Sort PCI cards by PCI Bus, Slot, Function ascending order - to be consistent with the BIOS. - 4. Update to Asc Library S121 and Adv Library 5.2. - - 3.2C (8/24/99): - 1. Correct PCI card detection bug introduced in 3.2B that - prevented PCI cards from being detected in kernels older - than v2.1.93. - - 3.2D (8/26/99): - 1. Correct /proc device synchronous speed information display. - Also when re-negotiation is pending for a target device - note this condition with an * and footnote. - 2. Correct initialization problem with Ultra-Wide cards that - have a pre-3.2 BIOS. A microcode variable changed locations - in 3.2 and greater BIOSes which caused WDTR to be attempted - erroneously with drives that don't support WDTR. - - 3.2E (8/30/99): - 1. Fix compile error caused by v2.3.13 PCI structure change. - 2. Remove field from ASCEEP_CONFIG that resulted in an EEPROM - checksum error for ISA cards. - 3. Remove ASC_QUEUE_FLOW_CONTROL conditional code. The mid-level - SCSI changes that it depended on were never included in Linux. - - 3.2F (9/3/99): - 1. Handle new initial function code added in v2.3.16 for all - driver versions. - - 3.2G (9/8/99): - 1. Fix PCI board detection in v2.3.13 and greater kernels. - 2. Fix comiple errors in v2.3.X with debugging enabled. - - 3.2H (9/13/99): - 1. Add 64-bit address, long support for Alpha and UltraSPARC. - The driver has been verified to work on an Alpha system. - 2. Add partial byte order handling support for Power PC and - other big-endian platforms. This support has not yet been - completed or verified. - 3. For wide boards replace block zeroing of request and - scatter-gather structures with individual field initialization - to improve performance. - 4. Correct and clarify ROM BIOS version detection. - - 3.2I (10/8/99): - 1. Update to Adv Library 5.4. - 2. Add v2.3.19 underrun reporting to asc_isr_callback() and - adv_isr_callback(). Remove DID_UNDERRUN constant and other - no longer needed code that previously documented the lack - of underrun handling. - - 3.2J (10/14/99): - 1. Eliminate compile errors for v2.0 and earlier kernels. - - 3.2K (11/15/99): - 1. Correct debug compile error in asc_prt_adv_scsi_req_q(). - 2. Update Adv Library to 5.5. - 3. Add ifdef handling for /proc changes added in v2.3.28. - 4. Increase Wide board scatter-gather list maximum length to - 255 when the driver is compiled into the kernel. - - 3.2L (11/18/99): - 1. Fix bug in adv_get_sglist() that caused an assertion failure - at line 7475. The reqp->sgblkp pointer must be initialized - to NULL in adv_get_sglist(). - - 3.2M (11/29/99): - 1. Really fix bug in adv_get_sglist(). - 2. Incorporate v2.3.29 changes into driver. - - 3.2N (4/1/00): - 1. Add CONFIG_ISA ifdef code. - 2. Include advansys_interrupts_enabled name change patch. - 3. For >= v2.3.28 use new SCSI error handling with new function - advansys_eh_bus_reset(). Don't include an abort function - because of base library limitations. - 4. For >= v2.3.28 use per board lock instead of io_request_lock. - 5. For >= v2.3.28 eliminate advansys_command() and - advansys_command_done(). - 6. Add some changes for PowerPC (Big Endian) support, but it isn't - working yet. - 7. Fix "nonexistent resource free" problem that occurred on a module - unload for boards with an I/O space >= 255. The 'n_io_port' field - is only one byte and can not be used to hold an ioport length more - than 255. - - 3.3A (4/4/00): - 1. Update to Adv Library 5.8. - 2. For wide cards add support for CDBs up to 16 bytes. - 3. Eliminate warnings when CONFIG_PROC_FS is not defined. - - 3.3B (5/1/00): - 1. Support for PowerPC (Big Endian) wide cards. Narrow cards - still need work. - 2. Change bitfields to shift and mask access for endian - portability. - - 3.3C (10/13/00): - 1. Update for latest 2.4 kernel. - 2. Test ABP-480 CardBus support in 2.4 kernel - works! - 3. Update to Asc Library S123. - 4. Update to Adv Library 5.12. - - 3.3D (11/22/00): - 1. Update for latest 2.4 kernel. - 2. Create patches for 2.2 and 2.4 kernels. - - 3.3E (1/9/01): - 1. Now that 2.4 is released remove ifdef code for kernel versions - less than 2.2. The driver is now only supported in kernels 2.2, - 2.4, and greater. - 2. Add code to release and acquire the io_request_lock in - the driver entrypoint functions: advansys_detect and - advansys_queuecommand. In kernel 2.4 the SCSI mid-level driver - still holds the io_request_lock on entry to SCSI low-level drivers. - This was supposed to be removed before 2.4 was released but never - happened. When the mid-level SCSI driver is changed all references - to the io_request_lock should be removed from the driver. - 3. Simplify error handling by removing advansys_abort(), - AscAbortSRB(), AscResetDevice(). SCSI bus reset requests are - now handled by resetting the SCSI bus and fully re-initializing - the chip. This simple method of error recovery has proven to work - most reliably after attempts at different methods. Also now only - support the "new" error handling method and remove the obsolete - error handling interface. - 4. Fix debug build errors. - - 3.3F (1/24/01): - 1. Merge with ConnectCom version from Andy Kellner which - updates Adv Library to 5.14. - 2. Make PowerPC (Big Endian) work for narrow cards and - fix problems writing EEPROM for wide cards. - 3. Remove interrupts_enabled assertion function. - - 3.3G (2/16/01): - 1. Return an error from narrow boards if passed a 16 byte - CDB. The wide board can already handle 16 byte CDBs. - - 3.3GJ (4/15/02): - 1. hacks for lk 2.5 series (D. Gilbert) - - 3.3GJD (10/14/02): - 1. change select_queue_depths to slave_configure - 2. make cmd_per_lun be sane again - - 3.3K [2004/06/24]: - 1. continuing cleanup for lk 2.6 series - 2. Fix problem in lk 2.6.7-bk2 that broke PCI wide cards - 3. Fix problem that oopsed ISA cards - - I. Known Problems/Fix List (XXX) - - 1. Need to add memory mapping workaround. Test the memory mapping. - If it doesn't work revert to I/O port access. Can a test be done - safely? - 2. Handle an interrupt not working. Keep an interrupt counter in - the interrupt handler. In the timeout function if the interrupt - has not occurred then print a message and run in polled mode. - 3. Allow bus type scanning order to be changed. - 4. Need to add support for target mode commands, cf. CAM XPT. - - J. Credits (Chronological Order) - - Bob Frey <bfrey@turbolinux.com.cn> wrote the AdvanSys SCSI driver - and maintained it up to 3.3F. He continues to answer questions - and help maintain the driver. - - Nathan Hartwell <mage@cdc3.cdc.net> provided the directions and - basis for the Linux v1.3.X changes which were included in the - 1.2 release. - - Thomas E Zerucha <zerucha@shell.portal.com> pointed out a bug - in advansys_biosparam() which was fixed in the 1.3 release. - - Erik Ratcliffe <erik@caldera.com> has done testing of the - AdvanSys driver in the Caldera releases. - - Rik van Riel <H.H.vanRiel@fys.ruu.nl> provided a patch to - AscWaitTixISRDone() which he found necessary to make the - driver work with a SCSI-1 disk. - - Mark Moran <mmoran@mmoran.com> has helped test Ultra-Wide - support in the 3.1A driver. - - Doug Gilbert <dgilbert@interlog.com> has made changes and - suggestions to improve the driver and done a lot of testing. - - Ken Mort <ken@mort.net> reported a DEBUG compile bug fixed - in 3.2K. - - Tom Rini <trini@kernel.crashing.org> provided the CONFIG_ISA - patch and helped with PowerPC wide and narrow board support. - - Philip Blundell <philb@gnu.org> provided an - advansys_interrupts_enabled patch. - - Dave Jones <dave@denial.force9.co.uk> reported the compiler - warnings generated when CONFIG_PROC_FS was not defined in - the 3.2M driver. - - Jerry Quinn <jlquinn@us.ibm.com> fixed PowerPC support (endian - problems) for wide cards. - - Bryan Henderson <bryanh@giraffe-data.com> helped debug narrow - card error handling. - - Manuel Veloso <veloso@pobox.com> worked hard on PowerPC narrow - board support and fixed a bug in AscGetEEPConfig(). - - Arnaldo Carvalho de Melo <acme@conectiva.com.br> made - save_flags/restore_flags changes. - - Andy Kellner <AKellner@connectcom.net> continues the Advansys SCSI - driver development for ConnectCom (Version > 3.3F). - - K. ConnectCom (AdvanSys) Contact Information - - Mail: ConnectCom Solutions, Inc. - 1150 Ringwood Court - San Jose, CA 95131 - Operator/Sales: 1-408-383-9400 - FAX: 1-408-383-9612 - Tech Support: 1-408-467-2930 - Tech Support E-Mail: linux@connectcom.net - FTP Site: ftp.connectcom.net (login: anonymous) - Web Site: http://www.connectcom.net - -*/ - -/* - * --- Linux Include Files + * As of March 8, 2000 Advanced System Products, Inc. (AdvanSys) + * changed its name to ConnectCom Solutions, Inc. + * On June 18, 2001 Initio Corp. acquired ConnectCom's SCSI assets */ #include <linux/module.h> - -#if defined(CONFIG_X86) && !defined(CONFIG_ISA) -#define CONFIG_ISA -#endif /* CONFIG_X86 && !CONFIG_ISA */ - #include <linux/string.h> #include <linux/kernel.h> #include <linux/types.h> @@ -771,7 +33,9 @@ #include <linux/proc_fs.h> #include <linux/init.h> #include <linux/blkdev.h> -#include <linux/stat.h> +#include <linux/isa.h> +#include <linux/eisa.h> +#include <linux/pci.h> #include <linux/spinlock.h> #include <linux/dma-mapping.h> @@ -779,49 +43,38 @@ #include <asm/system.h> #include <asm/dma.h> -/* FIXME: (by jejb@steeleye.com) This warning is present for two - * reasons: - * - * 1) This driver badly needs converting to the correct driver model - * probing API - * - * 2) Although all of the necessary command mapping places have the - * appropriate dma_map.. APIs, the driver still processes its internal - * queue using bus_to_virt() and virt_to_bus() which are illegal under - * the API. The entire queue processing structure will need to be - * altered to fix this. - */ -#warning this driver is still not properly converted to the DMA API - #include <scsi/scsi_cmnd.h> #include <scsi/scsi_device.h> #include <scsi/scsi_tcq.h> #include <scsi/scsi.h> #include <scsi/scsi_host.h> -#ifdef CONFIG_PCI -#include <linux/pci.h> -#endif /* CONFIG_PCI */ -/* - * --- Driver Options +/* FIXME: + * + * 1. Although all of the necessary command mapping places have the + * appropriate dma_map.. APIs, the driver still processes its internal + * queue using bus_to_virt() and virt_to_bus() which are illegal under + * the API. The entire queue processing structure will need to be + * altered to fix this. + * 2. Need to add memory mapping workaround. Test the memory mapping. + * If it doesn't work revert to I/O port access. Can a test be done + * safely? + * 3. Handle an interrupt not working. Keep an interrupt counter in + * the interrupt handler. In the timeout function if the interrupt + * has not occurred then print a message and run in polled mode. + * 4. Need to add support for target mode commands, cf. CAM XPT. + * 5. check DMA mapping functions for failure + * 6. Use scsi_transport_spi + * 7. advansys_info is not safe against multiple simultaneous callers + * 8. Add module_param to override ISA/VLB ioport array */ - -/* Enable driver assertions. */ -#define ADVANSYS_ASSERT +#warning this driver is still not properly converted to the DMA API /* Enable driver /proc statistics. */ #define ADVANSYS_STATS /* Enable driver tracing. */ -/* #define ADVANSYS_DEBUG */ - -/* - * --- Asc Library Constants and Macros - */ - -#define ASC_LIB_VERSION_MAJOR 1 -#define ASC_LIB_VERSION_MINOR 24 -#define ASC_LIB_SERIAL_NUMBER 123 +#undef ADVANSYS_DEBUG /* * Portable Data Types @@ -837,17 +90,6 @@ #define ASC_DCNT __u32 /* Unsigned Data count type. */ #define ASC_SDCNT __s32 /* Signed Data count type. */ -/* - * These macros are used to convert a virtual address to a - * 32-bit value. This currently can be used on Linux Alpha - * which uses 64-bit virtual address but a 32-bit bus address. - * This is likely to break in the future, but doing this now - * will give us time to change the HW and FW to handle 64-bit - * addresses. - */ -#define ASC_VADDR_TO_U32 virt_to_bus -#define ASC_U32_TO_VADDR bus_to_virt - typedef unsigned char uchar; #ifndef TRUE @@ -857,29 +99,9 @@ typedef unsigned char uchar; #define FALSE (0) #endif -#define EOF (-1) #define ERR (-1) #define UW_ERR (uint)(0xFFFF) #define isodd_word(val) ((((uint)val) & (uint)0x0001) != 0) -#define AscPCIConfigVendorIDRegister 0x0000 -#define AscPCIConfigDeviceIDRegister 0x0002 -#define AscPCIConfigCommandRegister 0x0004 -#define AscPCIConfigStatusRegister 0x0006 -#define AscPCIConfigRevisionIDRegister 0x0008 -#define AscPCIConfigCacheSize 0x000C -#define AscPCIConfigLatencyTimer 0x000D -#define AscPCIIOBaseRegister 0x0010 -#define AscPCICmdRegBits_IOMemBusMaster 0x0007 -#define ASC_PCI_ID2BUS(id) ((id) & 0xFF) -#define ASC_PCI_ID2DEV(id) (((id) >> 11) & 0x1F) -#define ASC_PCI_ID2FUNC(id) (((id) >> 8) & 0x7) -#define ASC_PCI_MKID(bus, dev, func) ((((dev) & 0x1F) << 11) | (((func) & 0x7) << 8) | ((bus) & 0xFF)) -#define ASC_PCI_REVISION_3150 0x02 -#define ASC_PCI_REVISION_3050 0x03 - -#define ASC_DVCLIB_CALL_DONE (1) -#define ASC_DVCLIB_CALL_FAILED (0) -#define ASC_DVCLIB_CALL_ERROR (-1) #define PCI_VENDOR_ID_ASP 0x10cd #define PCI_DEVICE_ID_ASP_1200A 0x1100 @@ -898,7 +120,7 @@ typedef unsigned char uchar; #define CC_VERY_LONG_SG_LIST 0 #define ASC_SRB2SCSIQ(srb_ptr) (srb_ptr) -#define PortAddr unsigned short /* port address size */ +#define PortAddr unsigned int /* port address size */ #define inp(port) inb(port) #define outp(port, byte) outb((byte), (port)) @@ -918,11 +140,10 @@ typedef unsigned char uchar; #define ASC_IS_PCMCIA (0x0008) #define ASC_IS_MCA (0x0020) #define ASC_IS_VL (0x0040) -#define ASC_ISA_PNP_PORT_ADDR (0x279) -#define ASC_ISA_PNP_PORT_WRITE (ASC_ISA_PNP_PORT_ADDR+0x800) #define ASC_IS_WIDESCSI_16 (0x0100) #define ASC_IS_WIDESCSI_32 (0x0200) #define ASC_IS_BIG_ENDIAN (0x8000) + #define ASC_CHIP_MIN_VER_VL (0x01) #define ASC_CHIP_MAX_VER_VL (0x07) #define ASC_CHIP_MIN_VER_PCI (0x09) @@ -941,16 +162,9 @@ typedef unsigned char uchar; #define ASC_CHIP_MAX_VER_EISA (0x47) #define ASC_CHIP_VER_EISA_BIT (0x40) #define ASC_CHIP_LATEST_VER_EISA ((ASC_CHIP_MIN_VER_EISA - 1) + 3) -#define ASC_MAX_LIB_SUPPORTED_ISA_CHIP_VER 0x21 -#define ASC_MAX_LIB_SUPPORTED_PCI_CHIP_VER 0x0A -#define ASC_MAX_VL_DMA_ADDR (0x07FFFFFFL) #define ASC_MAX_VL_DMA_COUNT (0x07FFFFFFL) -#define ASC_MAX_PCI_DMA_ADDR (0xFFFFFFFFL) #define ASC_MAX_PCI_DMA_COUNT (0xFFFFFFFFL) -#define ASC_MAX_ISA_DMA_ADDR (0x00FFFFFFL) #define ASC_MAX_ISA_DMA_COUNT (0x00FFFFFFL) -#define ASC_MAX_EISA_DMA_ADDR (0x07FFFFFFL) -#define ASC_MAX_EISA_DMA_COUNT (0x07FFFFFFL) #define ASC_SCSI_ID_BITS 3 #define ASC_SCSI_TIX_TYPE uchar @@ -961,82 +175,17 @@ typedef unsigned char uchar; #define ASC_SCSI_WIDTH_BIT_SET 0xFF #define ASC_MAX_SENSE_LEN 32 #define ASC_MIN_SENSE_LEN 14 -#define ASC_MAX_CDB_LEN 12 #define ASC_SCSI_RESET_HOLD_TIME_US 60 -#define ADV_INQ_CLOCKING_ST_ONLY 0x0 -#define ADV_INQ_CLOCKING_DT_ONLY 0x1 -#define ADV_INQ_CLOCKING_ST_AND_DT 0x3 - /* - * Inquiry SPC-2 SPI Byte 1 EVPD (Enable Vital Product Data) - * and CmdDt (Command Support Data) field bit definitions. + * Narrow boards only support 12-byte commands, while wide boards + * extend to 16-byte commands. */ -#define ADV_INQ_RTN_VPD_AND_CMDDT 0x3 -#define ADV_INQ_RTN_CMDDT_FOR_OP_CODE 0x2 -#define ADV_INQ_RTN_VPD_FOR_PG_CODE 0x1 -#define ADV_INQ_RTN_STD_INQUIRY_DATA 0x0 - -#define ASC_SCSIDIR_NOCHK 0x00 -#define ASC_SCSIDIR_T2H 0x08 -#define ASC_SCSIDIR_H2T 0x10 -#define ASC_SCSIDIR_NODATA 0x18 -#define SCSI_ASC_NOMEDIA 0x3A -#define ASC_SRB_HOST(x) ((uchar)((uchar)(x) >> 4)) -#define ASC_SRB_TID(x) ((uchar)((uchar)(x) & (uchar)0x0F)) -#define ASC_SRB_LUN(x) ((uchar)((uint)(x) >> 13)) -#define PUT_CDB1(x) ((uchar)((uint)(x) >> 8)) -#define MS_CMD_DONE 0x00 -#define MS_EXTEND 0x01 +#define ASC_MAX_CDB_LEN 12 +#define ADV_MAX_CDB_LEN 16 + #define MS_SDTR_LEN 0x03 -#define MS_SDTR_CODE 0x01 #define MS_WDTR_LEN 0x02 -#define MS_WDTR_CODE 0x03 -#define MS_MDP_LEN 0x05 -#define MS_MDP_CODE 0x00 - -/* - * Inquiry data structure and bitfield macros - * - * Only quantities of more than 1 bit are shifted, since the others are - * just tested for true or false. C bitfields aren't portable between big - * and little-endian platforms so they are not used. - */ - -#define ASC_INQ_DVC_TYPE(inq) ((inq)->periph & 0x1f) -#define ASC_INQ_QUALIFIER(inq) (((inq)->periph & 0xe0) >> 5) -#define ASC_INQ_DVC_TYPE_MOD(inq) ((inq)->devtype & 0x7f) -#define ASC_INQ_REMOVABLE(inq) ((inq)->devtype & 0x80) -#define ASC_INQ_ANSI_VER(inq) ((inq)->ver & 0x07) -#define ASC_INQ_ECMA_VER(inq) (((inq)->ver & 0x38) >> 3) -#define ASC_INQ_ISO_VER(inq) (((inq)->ver & 0xc0) >> 6) -#define ASC_INQ_RESPONSE_FMT(inq) ((inq)->byte3 & 0x0f) -#define ASC_INQ_TERM_IO(inq) ((inq)->byte3 & 0x40) -#define ASC_INQ_ASYNC_NOTIF(inq) ((inq)->byte3 & 0x80) -#define ASC_INQ_SOFT_RESET(inq) ((inq)->flags & 0x01) -#define ASC_INQ_CMD_QUEUE(inq) ((inq)->flags & 0x02) -#define ASC_INQ_LINK_CMD(inq) ((inq)->flags & 0x08) -#define ASC_INQ_SYNC(inq) ((inq)->flags & 0x10) -#define ASC_INQ_WIDE16(inq) ((inq)->flags & 0x20) -#define ASC_INQ_WIDE32(inq) ((inq)->flags & 0x40) -#define ASC_INQ_REL_ADDR(inq) ((inq)->flags & 0x80) -#define ASC_INQ_INFO_UNIT(inq) ((inq)->info & 0x01) -#define ASC_INQ_QUICK_ARB(inq) ((inq)->info & 0x02) -#define ASC_INQ_CLOCKING(inq) (((inq)->info & 0x0c) >> 2) - -typedef struct { - uchar periph; - uchar devtype; - uchar ver; - uchar byte3; - uchar add_len; - uchar res1; - uchar res2; - uchar flags; - uchar vendor_id[8]; - uchar product_id[16]; - uchar product_rev_level[4]; -} ASC_SCSI_INQUIRY; #define ASC_SG_LIST_PER_Q 7 #define QS_FREE 0x00 @@ -1215,22 +364,9 @@ typedef struct asc_sg_head { ushort queue_cnt; ushort entry_to_copy; ushort res; - ASC_SG_LIST sg_list[ASC_MAX_SG_LIST]; + ASC_SG_LIST sg_list[0]; } ASC_SG_HEAD; -#define ASC_MIN_SG_LIST 2 - -typedef struct asc_min_sg_head { - ushort entry_cnt; - ushort queue_cnt; - ushort entry_to_copy; - ushort res; - ASC_SG_LIST sg_list[ASC_MIN_SG_LIST]; -} ASC_MIN_SG_HEAD; - -#define QCX_SORT (0x0001) -#define QCX_COALEASE (0x0002) - typedef struct asc_scsi_q { ASC_SCSIQ_1 q1; ASC_SCSIQ_2 q2; @@ -1287,45 +423,12 @@ typedef struct asc_risc_sg_list_q { ASC_SG_LIST sg_list[7]; } ASC_RISC_SG_LIST_Q; -#define ASC_EXE_SCSI_IO_MAX_IDLE_LOOP 0x1000000UL -#define ASC_EXE_SCSI_IO_MAX_WAIT_LOOP 1024 -#define ASCQ_ERR_NO_ERROR 0 -#define ASCQ_ERR_IO_NOT_FOUND 1 -#define ASCQ_ERR_LOCAL_MEM 2 -#define ASCQ_ERR_CHKSUM 3 -#define ASCQ_ERR_START_CHIP 4 -#define ASCQ_ERR_INT_TARGET_ID 5 -#define ASCQ_ERR_INT_LOCAL_MEM 6 -#define ASCQ_ERR_HALT_RISC 7 -#define ASCQ_ERR_GET_ASPI_ENTRY 8 -#define ASCQ_ERR_CLOSE_ASPI 9 -#define ASCQ_ERR_HOST_INQUIRY 0x0A -#define ASCQ_ERR_SAVED_SRB_BAD 0x0B -#define ASCQ_ERR_QCNTL_SG_LIST 0x0C #define ASCQ_ERR_Q_STATUS 0x0D -#define ASCQ_ERR_WR_SCSIQ 0x0E -#define ASCQ_ERR_PC_ADDR 0x0F -#define ASCQ_ERR_SYN_OFFSET 0x10 -#define ASCQ_ERR_SYN_XFER_TIME 0x11 -#define ASCQ_ERR_LOCK_DMA 0x12 -#define ASCQ_ERR_UNLOCK_DMA 0x13 -#define ASCQ_ERR_VDS_CHK_INSTALL 0x14 -#define ASCQ_ERR_MICRO_CODE_HALT 0x15 -#define ASCQ_ERR_SET_LRAM_ADDR 0x16 #define ASCQ_ERR_CUR_QNG 0x17 #define ASCQ_ERR_SG_Q_LINKS 0x18 -#define ASCQ_ERR_SCSIQ_PTR 0x19 #define ASCQ_ERR_ISR_RE_ENTRY 0x1A #define ASCQ_ERR_CRITICAL_RE_ENTRY 0x1B #define ASCQ_ERR_ISR_ON_CRITICAL 0x1C -#define ASCQ_ERR_SG_LIST_ODD_ADDRESS 0x1D -#define ASCQ_ERR_XFER_ADDRESS_TOO_BIG 0x1E -#define ASCQ_ERR_SCSIQ_NULL_PTR 0x1F -#define ASCQ_ERR_SCSIQ_BAD_NEXT_PTR 0x20 -#define ASCQ_ERR_GET_NUM_OF_FREE_Q 0x21 -#define ASCQ_ERR_SEND_SCSI_Q 0x22 -#define ASCQ_ERR_HOST_REQ_RISC_HALT 0x23 -#define ASCQ_ERR_RESET_SDTR 0x24 /* * Warning code values are set in ASC_DVC_VAR 'warn_code'. @@ -1338,84 +441,51 @@ typedef struct asc_risc_sg_list_q { #define ASC_WARN_CMD_QNG_CONFLICT 0x0010 #define ASC_WARN_EEPROM_RECOVER 0x0020 #define ASC_WARN_CFG_MSW_RECOVER 0x0040 -#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080 /* - * Error code values are set in ASC_DVC_VAR 'err_code'. + * Error code values are set in {ASC/ADV}_DVC_VAR 'err_code'. */ -#define ASC_IERR_WRITE_EEPROM 0x0001 -#define ASC_IERR_MCODE_CHKSUM 0x0002 -#define ASC_IERR_SET_PC_ADDR 0x0004 -#define ASC_IERR_START_STOP_CHIP 0x0008 -#define ASC_IERR_IRQ_NO 0x0010 -#define ASC_IERR_SET_IRQ_NO 0x0020 -#define ASC_IERR_CHIP_VERSION 0x0040 -#define ASC_IERR_SET_SCSI_ID 0x0080 -#define ASC_IERR_GET_PHY_ADDR 0x0100 -#define ASC_IERR_BAD_SIGNATURE 0x0200 -#define ASC_IERR_NO_BUS_TYPE 0x0400 -#define ASC_IERR_SCAM 0x0800 -#define ASC_IERR_SET_SDTR 0x1000 -#define ASC_IERR_RW_LRAM 0x8000 - -#define ASC_DEF_IRQ_NO 10 -#define ASC_MAX_IRQ_NO 15 -#define ASC_MIN_IRQ_NO 10 -#define ASC_MIN_REMAIN_Q (0x02) +#define ASC_IERR_NO_CARRIER 0x0001 /* No more carrier memory */ +#define ASC_IERR_MCODE_CHKSUM 0x0002 /* micro code check sum error */ +#define ASC_IERR_SET_PC_ADDR 0x0004 +#define ASC_IERR_START_STOP_CHIP 0x0008 /* start/stop chip failed */ +#define ASC_IERR_ILLEGAL_CONNECTION 0x0010 /* Illegal cable connection */ +#define ASC_IERR_SINGLE_END_DEVICE 0x0020 /* SE device on DIFF bus */ +#define ASC_IERR_REVERSED_CABLE 0x0040 /* Narrow flat cable reversed */ +#define ASC_IERR_SET_SCSI_ID 0x0080 /* set SCSI ID failed */ +#define ASC_IERR_HVD_DEVICE 0x0100 /* HVD device on LVD port */ +#define ASC_IERR_BAD_SIGNATURE 0x0200 /* signature not found */ +#define ASC_IERR_NO_BUS_TYPE 0x0400 +#define ASC_IERR_BIST_PRE_TEST 0x0800 /* BIST pre-test error */ +#define ASC_IERR_BIST_RAM_TEST 0x1000 /* BIST RAM test error */ +#define ASC_IERR_BAD_CHIPTYPE 0x2000 /* Invalid chip_type setting */ + #define ASC_DEF_MAX_TOTAL_QNG (0xF0) #define ASC_MIN_TAG_Q_PER_DVC (0x04) -#define ASC_DEF_TAG_Q_PER_DVC (0x04) -#define ASC_MIN_FREE_Q ASC_MIN_REMAIN_Q +#define ASC_MIN_FREE_Q (0x02) #define ASC_MIN_TOTAL_QNG ((ASC_MAX_SG_QUEUE)+(ASC_MIN_FREE_Q)) #define ASC_MAX_TOTAL_QNG 240 #define ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG 16 #define ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG 8 #define ASC_MAX_PCI_INRAM_TOTAL_QNG 20 #define ASC_MAX_INRAM_TAG_QNG 16 -#define ASC_IOADR_TABLE_MAX_IX 11 #define ASC_IOADR_GAP 0x10 -#define ASC_SEARCH_IOP_GAP 0x10 -#define ASC_MIN_IOP_ADDR (PortAddr)0x0100 -#define ASC_MAX_IOP_ADDR (PortAddr)0x3F0 -#define ASC_IOADR_1 (PortAddr)0x0110 -#define ASC_IOADR_2 (PortAddr)0x0130 -#define ASC_IOADR_3 (PortAddr)0x0150 -#define ASC_IOADR_4 (PortAddr)0x0190 -#define ASC_IOADR_5 (PortAddr)0x0210 -#define ASC_IOADR_6 (PortAddr)0x0230 -#define ASC_IOADR_7 (PortAddr)0x0250 -#define ASC_IOADR_8 (PortAddr)0x0330 -#define ASC_IOADR_DEF ASC_IOADR_8 -#define ASC_LIB_SCSIQ_WK_SP 256 -#define ASC_MAX_SYN_XFER_NO 16 #define ASC_SYN_MAX_OFFSET 0x0F #define ASC_DEF_SDTR_OFFSET 0x0F -#define ASC_DEF_SDTR_INDEX 0x00 #define ASC_SDTR_ULTRA_PCI_10MB_INDEX 0x02 -#define SYN_XFER_NS_0 25 -#define SYN_XFER_NS_1 30 -#define SYN_XFER_NS_2 35 -#define SYN_XFER_NS_3 40 -#define SYN_XFER_NS_4 50 -#define SYN_XFER_NS_5 60 -#define SYN_XFER_NS_6 70 -#define SYN_XFER_NS_7 85 -#define SYN_ULTRA_XFER_NS_0 12 -#define SYN_ULTRA_XFER_NS_1 19 -#define SYN_ULTRA_XFER_NS_2 25 -#define SYN_ULTRA_XFER_NS_3 32 -#define SYN_ULTRA_XFER_NS_4 38 -#define SYN_ULTRA_XFER_NS_5 44 -#define SYN_ULTRA_XFER_NS_6 50 -#define SYN_ULTRA_XFER_NS_7 57 -#define SYN_ULTRA_XFER_NS_8 63 -#define SYN_ULTRA_XFER_NS_9 69 -#define SYN_ULTRA_XFER_NS_10 75 -#define SYN_ULTRA_XFER_NS_11 82 -#define SYN_ULTRA_XFER_NS_12 88 -#define SYN_ULTRA_XFER_NS_13 94 -#define SYN_ULTRA_XFER_NS_14 100 -#define SYN_ULTRA_XFER_NS_15 107 +#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41 + +/* The narrow chip only supports a limited selection of transfer rates. + * These are encoded in the range 0..7 or 0..15 depending whether the chip + * is Ultra-capable or not. These tables let us convert from one to the other. + */ +static const unsigned char asc_syn_xfer_period[8] = { + 25, 30, 35, 40, 50, 60, 70, 85 +}; + +static const unsigned char asc_syn_ultra_xfer_period[16] = { + 12, 19, 25, 32, 38, 44, 50, 57, 63, 69, 75, 82, 88, 94, 100, 107 +}; typedef struct ext_msg { uchar msg_type; @@ -1456,22 +526,16 @@ typedef struct asc_dvc_cfg { uchar isa_dma_speed; uchar isa_dma_channel; uchar chip_version; - ushort lib_serial_no; - ushort lib_version; ushort mcode_date; ushort mcode_version; uchar max_tag_qng[ASC_MAX_TID + 1]; - uchar *overrun_buf; uchar sdtr_period_offset[ASC_MAX_TID + 1]; - ushort pci_slot_info; uchar adapter_info[6]; - struct device *dev; } ASC_DVC_CFG; #define ASC_DEF_DVC_CNTL 0xFFFF #define ASC_DEF_CHIP_SCSI_ID 7 #define ASC_DEF_ISA_DMA_SPEED 4 -#define ASC_INIT_STATE_NULL 0x0000 #define ASC_INIT_STATE_BEG_GET_CFG 0x0001 #define ASC_INIT_STATE_END_GET_CFG 0x0002 #define ASC_INIT_STATE_BEG_SET_CFG 0x0004 @@ -1484,43 +548,39 @@ typedef struct asc_dvc_cfg { #define ASC_INIT_STATE_WITHOUT_EEP 0x8000 #define ASC_BUG_FIX_IF_NOT_DWB 0x0001 #define ASC_BUG_FIX_ASYN_USE_SYN 0x0002 -#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41 #define ASC_MIN_TAGGED_CMD 7 #define ASC_MAX_SCSI_RESET_WAIT 30 +#define ASC_OVERRUN_BSIZE 64 struct asc_dvc_var; /* Forward Declaration. */ -typedef void (*ASC_ISR_CALLBACK) (struct asc_dvc_var *, ASC_QDONE_INFO *); -typedef int (*ASC_EXE_CALLBACK) (struct asc_dvc_var *, ASC_SCSI_Q *); - typedef struct asc_dvc_var { PortAddr iop_base; ushort err_code; ushort dvc_cntl; ushort bug_fix_cntl; ushort bus_type; - ASC_ISR_CALLBACK isr_callback; - ASC_EXE_CALLBACK exe_callback; ASC_SCSI_BIT_ID_TYPE init_sdtr; ASC_SCSI_BIT_ID_TYPE sdtr_done; ASC_SCSI_BIT_ID_TYPE use_tagged_qng; ASC_SCSI_BIT_ID_TYPE unit_not_ready; ASC_SCSI_BIT_ID_TYPE queue_full_or_busy; ASC_SCSI_BIT_ID_TYPE start_motor; + uchar overrun_buf[ASC_OVERRUN_BSIZE] __aligned(8); + dma_addr_t overrun_dma; uchar scsi_reset_wait; uchar chip_no; char is_in_int; uchar max_total_qng; uchar cur_total_qng; uchar in_critical_cnt; - uchar irq_no; uchar last_q_shortage; ushort init_state; uchar cur_dvc_qng[ASC_MAX_TID + 1]; uchar max_dvc_qng[ASC_MAX_TID + 1]; ASC_SCSI_Q *scsiq_busy_head[ASC_MAX_TID + 1]; ASC_SCSI_Q *scsiq_busy_tail[ASC_MAX_TID + 1]; - uchar sdtr_period_tbl[ASC_MAX_SYN_XFER_NO]; + const uchar *sdtr_period_tbl; ASC_DVC_CFG *cfg; ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer_always; char redo_scam; @@ -1529,9 +589,11 @@ typedef struct asc_dvc_var { ASC_DCNT max_dma_count; ASC_SCSI_BIT_ID_TYPE no_scam; ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer; + uchar min_sdtr_index; uchar max_sdtr_index; - uchar host_init_sdtr_index; struct asc_board *drv_ptr; + int ptr_map_count; + void **ptr_map; ASC_DCNT uc_break; } ASC_DVC_VAR; @@ -1568,12 +630,7 @@ typedef struct asc_cap_info_array { #define ASC_EEP_MAX_DVC_ADDR_VL 15 #define ASC_EEP_DVC_CFG_BEG 32 #define ASC_EEP_MAX_DVC_ADDR 45 -#define ASC_EEP_DEFINED_WORDS 10 -#define ASC_EEP_MAX_ADDR 63 -#define ASC_EEP_RES_WORDS 0 #define ASC_EEP_MAX_RETRY 20 -#define ASC_MAX_INIT_BUSY_RETRY 8 -#define ASC_EEP_ISA_PNP_WSIZE 16 /* * These macros keep the chip SCSI id and ISA DMA speed @@ -1609,17 +666,10 @@ typedef struct asceep_config { ushort chksum; } ASCEEP_CONFIG; -#define ASC_PCI_CFG_LSW_SCSI_PARITY 0x0800 -#define ASC_PCI_CFG_LSW_BURST_MODE 0x0080 -#define ASC_PCI_CFG_LSW_INTR_ABLE 0x0020 - #define ASC_EEP_CMD_READ 0x80 #define ASC_EEP_CMD_WRITE 0x40 #define ASC_EEP_CMD_WRITE_ABLE 0x30 #define ASC_EEP_CMD_WRITE_DISABLE 0x00 -#define ASC_OVERRUN_BSIZE 0x00000048UL -#define ASC_CTRL_BREAK_ONCE 0x0001 -#define ASC_CTRL_BREAK_STAY_IDLE 0x0002 #define ASCV_MSGOUT_BEG 0x0000 #define ASCV_MSGOUT_SDTR_PERIOD (ASCV_MSGOUT_BEG+3) #define ASCV_MSGOUT_SDTR_OFFSET (ASCV_MSGOUT_BEG+4) @@ -1796,16 +846,9 @@ typedef struct asceep_config { #define ASC_1000_ID0W 0x04C1 #define ASC_1000_ID0W_FIX 0x00C1 #define ASC_1000_ID1B 0x25 -#define ASC_EISA_BIG_IOP_GAP (0x1C30-0x0C50) -#define ASC_EISA_SMALL_IOP_GAP (0x0020) -#define ASC_EISA_MIN_IOP_ADDR (0x0C30) -#define ASC_EISA_MAX_IOP_ADDR (0xFC50) #define ASC_EISA_REV_IOP_MASK (0x0C83) -#define ASC_EISA_PID_IOP_MASK (0x0C80) #define ASC_EISA_CFG_IOP_MASK (0x0C86) #define ASC_GET_EISA_SLOT(iop) (PortAddr)((iop) & 0xF000) -#define ASC_EISA_ID_740 0x01745004UL -#define ASC_EISA_ID_750 0x01755004UL #define INS_HALTINT (ushort)0x6281 #define INS_HALT (ushort)0x6280 #define INS_SINT (ushort)0x6200 @@ -1828,11 +871,10 @@ typedef struct asc_mc_saved { #define AscGetRiscVarDoneQTail(port) AscReadLramByte((port), ASCV_DONENEXT_B) #define AscPutRiscVarFreeQHead(port, val) AscWriteLramByte((port), ASCV_NEXTRDY_B, val) #define AscPutRiscVarDoneQTail(port, val) AscWriteLramByte((port), ASCV_DONENEXT_B, val) -#define AscPutMCodeSDTRDoneAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id), (data)); -#define AscGetMCodeSDTRDoneAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id)); -#define AscPutMCodeInitSDTRAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id), data); -#define AscGetMCodeInitSDTRAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id)); -#define AscSynIndexToPeriod(index) (uchar)(asc_dvc->sdtr_period_tbl[ (index) ]) +#define AscPutMCodeSDTRDoneAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id), (data)) +#define AscGetMCodeSDTRDoneAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id)) +#define AscPutMCodeInitSDTRAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id), data) +#define AscGetMCodeInitSDTRAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id)) #define AscGetChipSignatureByte(port) (uchar)inp((port)+IOP_SIG_BYTE) #define AscGetChipSignatureWord(port) (ushort)inpw((port)+IOP_SIG_WORD) #define AscGetChipVerNo(port) (uchar)inp((port)+IOP_VERSION) @@ -1887,125 +929,6 @@ typedef struct asc_mc_saved { #define AscReadChipDvcID(port) (uchar)inp((port)+IOP_REG_ID) #define AscWriteChipDvcID(port, data) outp((port)+IOP_REG_ID, data) -static int AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg); -static int AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg); -static void AscWaitEEPRead(void); -static void AscWaitEEPWrite(void); -static ushort AscReadEEPWord(PortAddr, uchar); -static ushort AscWriteEEPWord(PortAddr, uchar, ushort); -static ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort); -static int AscSetEEPConfigOnce(PortAddr, ASCEEP_CONFIG *, ushort); -static int AscSetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort); -static int AscStartChip(PortAddr); -static int AscStopChip(PortAddr); -static void AscSetChipIH(PortAddr, ushort); -static int AscIsChipHalted(PortAddr); -static void AscAckInterrupt(PortAddr); -static void AscDisableInterrupt(PortAddr); -static void AscEnableInterrupt(PortAddr); -static void AscSetBank(PortAddr, uchar); -static int AscResetChipAndScsiBus(ASC_DVC_VAR *); -#ifdef CONFIG_ISA -static ushort AscGetIsaDmaChannel(PortAddr); -static ushort AscSetIsaDmaChannel(PortAddr, ushort); -static uchar AscSetIsaDmaSpeed(PortAddr, uchar); -static uchar AscGetIsaDmaSpeed(PortAddr); -#endif /* CONFIG_ISA */ -static uchar AscReadLramByte(PortAddr, ushort); -static ushort AscReadLramWord(PortAddr, ushort); -#if CC_VERY_LONG_SG_LIST -static ASC_DCNT AscReadLramDWord(PortAddr, ushort); -#endif /* CC_VERY_LONG_SG_LIST */ -static void AscWriteLramWord(PortAddr, ushort, ushort); -static void AscWriteLramByte(PortAddr, ushort, uchar); -static ASC_DCNT AscMemSumLramWord(PortAddr, ushort, int); -static void AscMemWordSetLram(PortAddr, ushort, ushort, int); -static void AscMemWordCopyPtrToLram(PortAddr, ushort, uchar *, int); -static void AscMemDWordCopyPtrToLram(PortAddr, ushort, uchar *, int); -static void AscMemWordCopyPtrFromLram(PortAddr, ushort, uchar *, int); -static ushort AscInitAscDvcVar(ASC_DVC_VAR *); -static ushort AscInitFromEEP(ASC_DVC_VAR *); -static ushort AscInitFromAscDvcVar(ASC_DVC_VAR *); -static ushort AscInitMicroCodeVar(ASC_DVC_VAR *); -static int AscTestExternalLram(ASC_DVC_VAR *); -static uchar AscMsgOutSDTR(ASC_DVC_VAR *, uchar, uchar); -static uchar AscCalSDTRData(ASC_DVC_VAR *, uchar, uchar); -static void AscSetChipSDTR(PortAddr, uchar, uchar); -static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *, uchar); -static uchar AscAllocFreeQueue(PortAddr, uchar); -static uchar AscAllocMultipleFreeQueue(PortAddr, uchar, uchar); -static int AscHostReqRiscHalt(PortAddr); -static int AscStopQueueExe(PortAddr); -static int AscSendScsiQueue(ASC_DVC_VAR *, - ASC_SCSI_Q *scsiq, uchar n_q_required); -static int AscPutReadyQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar); -static int AscPutReadySgListQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar); -static int AscSetChipSynRegAtID(PortAddr, uchar, uchar); -static int AscSetRunChipSynRegAtID(PortAddr, uchar, uchar); -static ushort AscInitLram(ASC_DVC_VAR *); -static ushort AscInitQLinkVar(ASC_DVC_VAR *); -static int AscSetLibErrorCode(ASC_DVC_VAR *, ushort); -static int AscIsrChipHalted(ASC_DVC_VAR *); -static uchar _AscCopyLramScsiDoneQ(PortAddr, ushort, - ASC_QDONE_INFO *, ASC_DCNT); -static int AscIsrQDone(ASC_DVC_VAR *); -static int AscCompareString(uchar *, uchar *, int); -#ifdef CONFIG_ISA -static ushort AscGetEisaChipCfg(PortAddr); -static ASC_DCNT AscGetEisaProductID(PortAddr); -static PortAddr AscSearchIOPortAddrEISA(PortAddr); -static PortAddr AscSearchIOPortAddr11(PortAddr); -static PortAddr AscSearchIOPortAddr(PortAddr, ushort); -static void AscSetISAPNPWaitForKey(void); -#endif /* CONFIG_ISA */ -static uchar AscGetChipScsiCtrl(PortAddr); -static uchar AscSetChipScsiID(PortAddr, uchar); -static uchar AscGetChipVersion(PortAddr, ushort); -static ushort AscGetChipBusType(PortAddr); -static ASC_DCNT AscLoadMicroCode(PortAddr, ushort, uchar *, ushort); -static int AscFindSignature(PortAddr); -static void AscToggleIRQAct(PortAddr); -static uchar AscGetChipIRQ(PortAddr, ushort); -static uchar AscSetChipIRQ(PortAddr, uchar, ushort); -static ushort AscGetChipBiosAddress(PortAddr, ushort); -static inline ulong DvcEnterCritical(void); -static inline void DvcLeaveCritical(ulong); -#ifdef CONFIG_PCI -static uchar DvcReadPCIConfigByte(ASC_DVC_VAR *, ushort); -static void DvcWritePCIConfigByte(ASC_DVC_VAR *, ushort, uchar); -#endif /* CONFIG_PCI */ -static ushort AscGetChipBiosAddress(PortAddr, ushort); -static void DvcSleepMilliSecond(ASC_DCNT); -static void DvcDelayNanoSecond(ASC_DVC_VAR *, ASC_DCNT); -static void DvcPutScsiQ(PortAddr, ushort, uchar *, int); -static void DvcGetQinfo(PortAddr, ushort, uchar *, int); -static ushort AscInitGetConfig(ASC_DVC_VAR *); -static ushort AscInitSetConfig(ASC_DVC_VAR *); -static ushort AscInitAsc1000Driver(ASC_DVC_VAR *); -static void AscAsyncFix(ASC_DVC_VAR *, uchar, ASC_SCSI_INQUIRY *); -static int AscTagQueuingSafe(ASC_SCSI_INQUIRY *); -static void AscInquiryHandling(ASC_DVC_VAR *, uchar, ASC_SCSI_INQUIRY *); -static int AscExeScsiQueue(ASC_DVC_VAR *, ASC_SCSI_Q *); -static int AscISR(ASC_DVC_VAR *); -static uint AscGetNumOfFreeQueue(ASC_DVC_VAR *, uchar, uchar); -static int AscSgListToQueue(int); -#ifdef CONFIG_ISA -static void AscEnableIsaDma(uchar); -#endif /* CONFIG_ISA */ -static ASC_DCNT AscGetMaxDmaCount(ushort); -static const char *advansys_info(struct Scsi_Host *shost); - -/* - * --- Adv Library Constants and Macros - */ - -#define ADV_LIB_VERSION_MAJOR 5 -#define ADV_LIB_VERSION_MINOR 14 - -/* - * Define Adv Library required special types. - */ - /* * Portable Data Types * @@ -2045,12 +968,6 @@ static const char *advansys_info(struct Scsi_Host *shost); #define ADV_CARRIER_COUNT (ASC_DEF_MAX_HOST_QNG + 15) /* - * For wide boards a CDB length maximum of 16 bytes - * is supported. - */ -#define ADV_MAX_CDB_LEN 16 - -/* * Define total number of simultaneous maximum element scatter-gather * request blocks per wide adapter. ASC_DEF_MAX_HOST_QNG (253) is the * maximum number of outstanding commands per wide host adapter. Each @@ -2058,28 +975,14 @@ static const char *advansys_info(struct Scsi_Host *shost); * elements. Allow each command to have at least one ADV_SG_BLOCK structure. * This allows about 15 commands to have the maximum 17 ADV_SG_BLOCK * structures or 255 scatter-gather elements. - * */ #define ADV_TOT_SG_BLOCK ASC_DEF_MAX_HOST_QNG /* - * Define Adv Library required maximum number of scatter-gather - * elements per request. + * Define maximum number of scatter-gather elements per request. */ #define ADV_MAX_SG_LIST 255 - -/* Number of SG blocks needed. */ -#define ADV_NUM_SG_BLOCK \ - ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK) - -/* Total contiguous memory needed for SG blocks. */ -#define ADV_SG_TOTAL_MEM_SIZE \ - (sizeof(ADV_SG_BLOCK) * ADV_NUM_SG_BLOCK) - -#define ADV_PAGE_SIZE PAGE_SIZE - -#define ADV_NUM_PAGE_CROSSING \ - ((ADV_SG_TOTAL_MEM_SIZE + (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE) +#define NO_OF_SG_PER_BLOCK 15 #define ADV_EEP_DVC_CFG_BEGIN (0x00) #define ADV_EEP_DVC_CFG_END (0x15) @@ -2385,10 +1288,6 @@ typedef struct adveep_38C1600_config { * EEPROM Commands */ #define ASC_EEP_CMD_DONE 0x0200 -#define ASC_EEP_CMD_DONE_ERR 0x0001 - -/* cfg_word */ -#define EEP_CFG_WORD_BIG_ENDIAN 0x8000 /* bios_ctrl */ #define BIOS_CTRL_BIOS 0x0001 @@ -2405,10 +1304,8 @@ typedef struct adveep_38C1600_config { #define BIOS_CTRL_AIPP_DIS 0x2000 #define ADV_3550_MEMSIZE 0x2000 /* 8 KB Internal Memory */ -#define ADV_3550_IOLEN 0x40 /* I/O Port Range in bytes */ #define ADV_38C0800_MEMSIZE 0x4000 /* 16 KB Internal Memory */ -#define ADV_38C0800_IOLEN 0x100 /* I/O Port Range in bytes */ /* * XXX - Since ASC38C1600 Rev.3 has a local RAM failure issue, there is @@ -2418,8 +1315,6 @@ typedef struct adveep_38C1600_config { * #define ADV_38C1600_MEMSIZE 0x8000L * 32 KB Internal Memory * */ #define ADV_38C1600_MEMSIZE 0x4000 /* 16 KB Internal Memory */ -#define ADV_38C1600_IOLEN 0x100 /* I/O Port Range 256 bytes */ -#define ADV_38C1600_MEMLEN 0x1000 /* Memory Range 4KB bytes */ /* * Byte I/O register address from base of 'iop_base'. @@ -2549,8 +1444,6 @@ typedef struct adveep_38C1600_config { #define ADV_CHIP_ID_BYTE 0x25 #define ADV_CHIP_ID_WORD 0x04C1 -#define ADV_SC_SCSI_BUS_RESET 0x2000 - #define ADV_INTR_ENABLE_HOST_INTR 0x01 #define ADV_INTR_ENABLE_SEL_INTR 0x02 #define ADV_INTR_ENABLE_DPR_INTR 0x04 @@ -2590,8 +1483,6 @@ typedef struct adveep_38C1600_config { #define ADV_TICKLE_B 0x02 #define ADV_TICKLE_C 0x03 -#define ADV_SCSI_CTRL_RSTOUT 0x2000 - #define AdvIsIntPending(port) \ (AdvReadWordRegister(port, IOPW_CTRL_REG) & ADV_CTRL_REG_HOST_INTR) @@ -2744,14 +1635,11 @@ typedef struct adveep_38C1600_config { */ #define INTAB 0x01 -/* a_advlib.h */ - /* * Adv Library Status Definitions */ #define ADV_TRUE 1 #define ADV_FALSE 0 -#define ADV_NOERROR 1 #define ADV_SUCCESS 1 #define ADV_BUSY 0 #define ADV_ERROR (-1) @@ -2762,31 +1650,12 @@ typedef struct adveep_38C1600_config { #define ASC_WARN_BUSRESET_ERROR 0x0001 /* SCSI Bus Reset error */ #define ASC_WARN_EEPROM_CHKSUM 0x0002 /* EEP check sum error */ #define ASC_WARN_EEPROM_TERMINATION 0x0004 /* EEP termination bad field */ -#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080 /* PCI config space set error */ #define ASC_WARN_ERROR 0xFFFF /* ADV_ERROR return */ #define ADV_MAX_TID 15 /* max. target identifier */ #define ADV_MAX_LUN 7 /* max. logical unit number */ /* - * Error code values are set in ADV_DVC_VAR 'err_code'. - */ -#define ASC_IERR_WRITE_EEPROM 0x0001 /* write EEPROM error */ -#define ASC_IERR_MCODE_CHKSUM 0x0002 /* micro code check sum error */ -#define ASC_IERR_NO_CARRIER 0x0004 /* No more carrier memory. */ -#define ASC_IERR_START_STOP_CHIP 0x0008 /* start/stop chip failed */ -#define ASC_IERR_CHIP_VERSION 0x0040 /* wrong chip version */ -#define ASC_IERR_SET_SCSI_ID 0x0080 /* set SCSI ID failed */ -#define ASC_IERR_HVD_DEVICE 0x0100 /* HVD attached to LVD connector. */ -#define ASC_IERR_BAD_SIGNATURE 0x0200 /* signature not found */ -#define ASC_IERR_ILLEGAL_CONNECTION 0x0400 /* Illegal cable connection */ -#define ASC_IERR_SINGLE_END_DEVICE 0x0800 /* Single-end used w/differential */ -#define ASC_IERR_REVERSED_CABLE 0x1000 /* Narrow flat cable reversed */ -#define ASC_IERR_BIST_PRE_TEST 0x2000 /* BIST pre-test error */ -#define ASC_IERR_BIST_RAM_TEST 0x4000 /* BIST RAM test error */ -#define ASC_IERR_BAD_CHIPTYPE 0x8000 /* Invalid 'chip_type' setting. */ - -/* * Fixed locations of microcode operating variables. */ #define ASC_MC_CODE_BEGIN_ADDR 0x0028 /* microcode start address */ @@ -2902,8 +1771,7 @@ typedef struct adv_carr_t { #define ASC_GET_CARRP(carrp) ((carrp) & ASC_NEXT_VPA_MASK) #define ADV_CARRIER_NUM_PAGE_CROSSING \ - (((ADV_CARRIER_COUNT * sizeof(ADV_CARR_T)) + \ - (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE) + (((ADV_CARRIER_COUNT * sizeof(ADV_CARR_T)) + (PAGE_SIZE - 1))/PAGE_SIZE) #define ADV_CARRIER_BUFSIZE \ ((ADV_CARRIER_COUNT + ADV_CARRIER_NUM_PAGE_CROSSING) * sizeof(ADV_CARR_T)) @@ -2937,80 +1805,17 @@ typedef struct adv_dvc_cfg { ushort disc_enable; /* enable disconnection */ uchar chip_version; /* chip version */ uchar termination; /* Term. Ctrl. bits 6-5 of SCSI_CFG1 register */ - ushort lib_version; /* Adv Library version number */ ushort control_flag; /* Microcode Control Flag */ ushort mcode_date; /* Microcode date */ ushort mcode_version; /* Microcode version */ - ushort pci_slot_info; /* high byte device/function number */ - /* bits 7-3 device num., bits 2-0 function num. */ - /* low byte bus num. */ ushort serial1; /* EEPROM serial number word 1 */ ushort serial2; /* EEPROM serial number word 2 */ ushort serial3; /* EEPROM serial number word 3 */ - struct device *dev; /* pointer to the pci dev structure for this board */ } ADV_DVC_CFG; struct adv_dvc_var; struct adv_scsi_req_q; -typedef void (*ADV_ISR_CALLBACK) - (struct adv_dvc_var *, struct adv_scsi_req_q *); - -typedef void (*ADV_ASYNC_CALLBACK) - (struct adv_dvc_var *, uchar); - -/* - * Adapter operation variable structure. - * - * One structure is required per host adapter. - * - * Field naming convention: - * - * *_able indicates both whether a feature should be enabled or disabled - * and whether a device isi capable of the feature. At initialization - * this field may be set, but later if a device is found to be incapable - * of the feature, the field is cleared. - */ -typedef struct adv_dvc_var { - AdvPortAddr iop_base; /* I/O port address */ - ushort err_code; /* fatal error code */ - ushort bios_ctrl; /* BIOS control word, EEPROM word 12 */ - ADV_ISR_CALLBACK isr_callback; - ADV_ASYNC_CALLBACK async_callback; - ushort wdtr_able; /* try WDTR for a device */ - ushort sdtr_able; /* try SDTR for a device */ - ushort ultra_able; /* try SDTR Ultra speed for a device */ - ushort sdtr_speed1; /* EEPROM SDTR Speed for TID 0-3 */ - ushort sdtr_speed2; /* EEPROM SDTR Speed for TID 4-7 */ - ushort sdtr_speed3; /* EEPROM SDTR Speed for TID 8-11 */ - ushort sdtr_speed4; /* EEPROM SDTR Speed for TID 12-15 */ - ushort tagqng_able; /* try tagged queuing with a device */ - ushort ppr_able; /* PPR message capable per TID bitmask. */ - uchar max_dvc_qng; /* maximum number of tagged commands per device */ - ushort start_motor; /* start motor command allowed */ - uchar scsi_reset_wait; /* delay in seconds after scsi bus reset */ - uchar chip_no; /* should be assigned by caller */ - uchar max_host_qng; /* maximum number of Q'ed command allowed */ - uchar irq_no; /* IRQ number */ - ushort no_scam; /* scam_tolerant of EEPROM */ - struct asc_board *drv_ptr; /* driver pointer to private structure */ - uchar chip_scsi_id; /* chip SCSI target ID */ - uchar chip_type; - uchar bist_err_code; - ADV_CARR_T *carrier_buf; - ADV_CARR_T *carr_freelist; /* Carrier free list. */ - ADV_CARR_T *icq_sp; /* Initiator command queue stopper pointer. */ - ADV_CARR_T *irq_sp; /* Initiator response queue stopper pointer. */ - ushort carr_pending_cnt; /* Count of pending carriers. */ - /* - * Note: The following fields will not be used after initialization. The - * driver may discard the buffer after initialization is done. - */ - ADV_DVC_CFG *cfg; /* temporary configuration structure */ -} ADV_DVC_VAR; - -#define NO_OF_SG_PER_BLOCK 15 - typedef struct asc_sg_block { uchar reserved1; uchar reserved2; @@ -3069,6 +1874,83 @@ typedef struct adv_scsi_req_q { } ADV_SCSI_REQ_Q; /* + * The following two structures are used to process Wide Board requests. + * + * The ADV_SCSI_REQ_Q structure in adv_req_t is passed to the Adv Library + * and microcode with the ADV_SCSI_REQ_Q field 'srb_ptr' pointing to the + * adv_req_t. The adv_req_t structure 'cmndp' field in turn points to the + * Mid-Level SCSI request structure. + * + * Zero or more ADV_SG_BLOCK are used with each ADV_SCSI_REQ_Q. Each + * ADV_SG_BLOCK structure holds 15 scatter-gather elements. Under Linux + * up to 255 scatter-gather elements may be used per request or + * ADV_SCSI_REQ_Q. + * + * Both structures must be 32 byte aligned. + */ +typedef struct adv_sgblk { + ADV_SG_BLOCK sg_block; /* Sgblock structure. */ + uchar align[32]; /* Sgblock structure padding. */ + struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */ +} adv_sgblk_t; + +typedef struct adv_req { + ADV_SCSI_REQ_Q scsi_req_q; /* Adv Library request structure. */ + uchar align[32]; /* Request structure padding. */ + struct scsi_cmnd *cmndp; /* Mid-Level SCSI command pointer. */ + adv_sgblk_t *sgblkp; /* Adv Library scatter-gather pointer. */ + struct adv_req *next_reqp; /* Next Request Structure. */ +} adv_req_t; + +/* + * Adapter operation variable structure. + * + * One structure is required per host adapter. + * + * Field naming convention: + * + * *_able indicates both whether a feature should be enabled or disabled + * and whether a device isi capable of the feature. At initialization + * this field may be set, but later if a device is found to be incapable + * of the feature, the field is cleared. + */ +typedef struct adv_dvc_var { + AdvPortAddr iop_base; /* I/O port address */ + ushort err_code; /* fatal error code */ + ushort bios_ctrl; /* BIOS control word, EEPROM word 12 */ + ushort wdtr_able; /* try WDTR for a device */ + ushort sdtr_able; /* try SDTR for a device */ + ushort ultra_able; /* try SDTR Ultra speed for a device */ + ushort sdtr_speed1; /* EEPROM SDTR Speed for TID 0-3 */ + ushort sdtr_speed2; /* EEPROM SDTR Speed for TID 4-7 */ + ushort sdtr_speed3; /* EEPROM SDTR Speed for TID 8-11 */ + ushort sdtr_speed4; /* EEPROM SDTR Speed for TID 12-15 */ + ushort tagqng_able; /* try tagged queuing with a device */ + ushort ppr_able; /* PPR message capable per TID bitmask. */ + uchar max_dvc_qng; /* maximum number of tagged commands per device */ + ushort start_motor; /* start motor command allowed */ + uchar scsi_reset_wait; /* delay in seconds after scsi bus reset */ + uchar chip_no; /* should be assigned by caller */ + uchar max_host_qng; /* maximum number of Q'ed command allowed */ + ushort no_scam; /* scam_tolerant of EEPROM */ + struct asc_board *drv_ptr; /* driver pointer to private structure */ + uchar chip_scsi_id; /* chip SCSI target ID */ + uchar chip_type; + uchar bist_err_code; + ADV_CARR_T *carrier_buf; + ADV_CARR_T *carr_freelist; /* Carrier free list. */ + ADV_CARR_T *icq_sp; /* Initiator command queue stopper pointer. */ + ADV_CARR_T *irq_sp; /* Initiator response queue stopper pointer. */ + ushort carr_pending_cnt; /* Count of pending carriers. */ + struct adv_req *orig_reqp; /* adv_req_t memory block. */ + /* + * Note: The following fields will not be used after initialization. The + * driver may discard the buffer after initialization is done. + */ + ADV_DVC_CFG *cfg; /* temporary configuration structure */ +} ADV_DVC_VAR; + +/* * Microcode idle loop commands */ #define IDLE_CMD_COMPLETED 0 @@ -3092,10 +1974,8 @@ typedef struct adv_scsi_req_q { /* * Wait loop time out values. */ -#define SCSI_WAIT_10_SEC 10UL /* 10 seconds */ #define SCSI_WAIT_100_MSEC 100UL /* 100 milliseconds */ #define SCSI_US_PER_MSEC 1000 /* microseconds per millisecond */ -#define SCSI_MS_PER_SEC 1000UL /* milliseconds per second */ #define SCSI_MAX_RETRY 10 /* retry count */ #define ADV_ASYNC_RDMA_FAILURE 0x01 /* Fatal RDMA failure. */ @@ -3105,53 +1985,6 @@ typedef struct adv_scsi_req_q { #define ADV_HOST_SCSI_BUS_RESET 0x80 /* Host Initiated SCSI Bus Reset. */ -/* - * Device drivers must define the following functions. - */ -static inline ulong DvcEnterCritical(void); -static inline void DvcLeaveCritical(ulong); -static void DvcSleepMilliSecond(ADV_DCNT); -static uchar DvcAdvReadPCIConfigByte(ADV_DVC_VAR *, ushort); -static void DvcAdvWritePCIConfigByte(ADV_DVC_VAR *, ushort, uchar); -static ADV_PADDR DvcGetPhyAddr(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *, - uchar *, ASC_SDCNT *, int); -static void DvcDelayMicroSecond(ADV_DVC_VAR *, ushort); - -/* - * Adv Library functions available to drivers. - */ -static int AdvExeScsiQueue(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *); -static int AdvISR(ADV_DVC_VAR *); -static int AdvInitGetConfig(ADV_DVC_VAR *); -static int AdvInitAsc3550Driver(ADV_DVC_VAR *); -static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *); -static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *); -static int AdvResetChipAndSB(ADV_DVC_VAR *); -static int AdvResetSB(ADV_DVC_VAR *asc_dvc); - -/* - * Internal Adv Library functions. - */ -static int AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ADV_DCNT); -static void AdvInquiryHandling(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *); -static int AdvInitFrom3550EEP(ADV_DVC_VAR *); -static int AdvInitFrom38C0800EEP(ADV_DVC_VAR *); -static int AdvInitFrom38C1600EEP(ADV_DVC_VAR *); -static ushort AdvGet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *); -static void AdvSet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *); -static ushort AdvGet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *); -static void AdvSet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *); -static ushort AdvGet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *); -static void AdvSet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *); -static void AdvWaitEEPCmd(AdvPortAddr); -static ushort AdvReadEEPWord(AdvPortAddr, int); - -/* - * PCI Bus Definitions - */ -#define AscPCICmdRegBits_BusMastering 0x0007 -#define AscPCICmdRegBits_ParErrRespCtrl 0x0040 - /* Read byte from a register. */ #define AdvReadByteRegister(iop_base, reg_off) \ (ADV_MEM_READB((iop_base) + (reg_off))) @@ -3319,23 +2152,6 @@ do { \ #define QHSTA_M_FROZEN_TIDQ 0x46 /* TID Queue frozen. */ #define QHSTA_M_SGBACKUP_ERROR 0x47 /* Scatter-Gather backup error */ -/* - * Default EEPROM Configuration structure defined in a_init.c. - */ -static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config; -static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config; -static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config; - -/* - * DvcGetPhyAddr() flag arguments - */ -#define ADV_IS_SCSIQ_FLAG 0x01 /* 'addr' is ASC_SCSI_REQ_Q pointer */ -#define ADV_ASCGETSGLIST_VADDR 0x02 /* 'addr' is AscGetSGList() virtual addr */ -#define ADV_IS_SENSE_FLAG 0x04 /* 'addr' is sense virtual pointer */ -#define ADV_IS_DATA_FLAG 0x08 /* 'addr' is data virtual pointer */ -#define ADV_IS_SGLIST_FLAG 0x10 /* 'addr' is sglist virtual pointer */ -#define ADV_IS_CARRIER_FLAG 0x20 /* 'addr' is ADV_CARR_T pointer */ - /* Return the address that is aligned at the next doubleword >= to 'addr'. */ #define ADV_8BALIGN(addr) (((ulong) (addr) + 0x7) & ~0x7) #define ADV_16BALIGN(addr) (((ulong) (addr) + 0xF) & ~0xF) @@ -3353,92 +2169,10 @@ static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config; (sizeof(ADV_SG_BLOCK) * \ ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)) -/* - * Inquiry data structure and bitfield macros - * - * Using bitfields to access the subchar data isn't portable across - * endianness, so instead mask and shift. Only quantities of more - * than 1 bit are shifted, since the others are just tested for true - * or false. - */ - -#define ADV_INQ_DVC_TYPE(inq) ((inq)->periph & 0x1f) -#define ADV_INQ_QUALIFIER(inq) (((inq)->periph & 0xe0) >> 5) -#define ADV_INQ_DVC_TYPE_MOD(inq) ((inq)->devtype & 0x7f) -#define ADV_INQ_REMOVABLE(inq) ((inq)->devtype & 0x80) -#define ADV_INQ_ANSI_VER(inq) ((inq)->ver & 0x07) -#define ADV_INQ_ECMA_VER(inq) (((inq)->ver & 0x38) >> 3) -#define ADV_INQ_ISO_VER(inq) (((inq)->ver & 0xc0) >> 6) -#define ADV_INQ_RESPONSE_FMT(inq) ((inq)->byte3 & 0x0f) -#define ADV_INQ_TERM_IO(inq) ((inq)->byte3 & 0x40) -#define ADV_INQ_ASYNC_NOTIF(inq) ((inq)->byte3 & 0x80) -#define ADV_INQ_SOFT_RESET(inq) ((inq)->flags & 0x01) -#define ADV_INQ_CMD_QUEUE(inq) ((inq)->flags & 0x02) -#define ADV_INQ_LINK_CMD(inq) ((inq)->flags & 0x08) -#define ADV_INQ_SYNC(inq) ((inq)->flags & 0x10) -#define ADV_INQ_WIDE16(inq) ((inq)->flags & 0x20) -#define ADV_INQ_WIDE32(inq) ((inq)->flags & 0x40) -#define ADV_INQ_REL_ADDR(inq) ((inq)->flags & 0x80) -#define ADV_INQ_INFO_UNIT(inq) ((inq)->info & 0x01) -#define ADV_INQ_QUICK_ARB(inq) ((inq)->info & 0x02) -#define ADV_INQ_CLOCKING(inq) (((inq)->info & 0x0c) >> 2) - -typedef struct { - uchar periph; /* peripheral device type [0:4] */ - /* peripheral qualifier [5:7] */ - uchar devtype; /* device type modifier (for SCSI I) [0:6] */ - /* RMB - removable medium bit [7] */ - uchar ver; /* ANSI approved version [0:2] */ - /* ECMA version [3:5] */ - /* ISO version [6:7] */ - uchar byte3; /* response data format [0:3] */ - /* 0 SCSI 1 */ - /* 1 CCS */ - /* 2 SCSI-2 */ - /* 3-F reserved */ - /* reserved [4:5] */ - /* terminate I/O process bit (see 5.6.22) [6] */ - /* asynch. event notification (processor) [7] */ - uchar add_len; /* additional length */ - uchar res1; /* reserved */ - uchar res2; /* reserved */ - uchar flags; /* soft reset implemented [0] */ - /* command queuing [1] */ - /* reserved [2] */ - /* linked command for this logical unit [3] */ - /* synchronous data transfer [4] */ - /* wide bus 16 bit data transfer [5] */ - /* wide bus 32 bit data transfer [6] */ - /* relative addressing mode [7] */ - uchar vendor_id[8]; /* vendor identification */ - uchar product_id[16]; /* product identification */ - uchar product_rev_level[4]; /* product revision level */ - uchar vendor_specific[20]; /* vendor specific */ - uchar info; /* information unit supported [0] */ - /* quick arbitrate supported [1] */ - /* clocking field [2:3] */ - /* reserved [4:7] */ - uchar res3; /* reserved */ -} ADV_SCSI_INQUIRY; /* 58 bytes */ - -/* - * --- Driver Constants and Macros - */ - -#define ASC_NUM_BOARD_SUPPORTED 16 -#define ASC_NUM_IOPORT_PROBE 4 -#define ASC_NUM_BUS 4 - -/* Reference Scsi_Host hostdata */ -#define ASC_BOARDP(host) ((asc_board_t *) &((host)->hostdata)) - -/* asc_board_t flags */ -#define ASC_HOST_IN_RESET 0x01 +/* struct asc_board flags */ #define ASC_IS_WIDE_BOARD 0x04 /* AdvanSys Wide Board */ -#define ASC_SELECT_QUEUE_DEPTHS 0x08 #define ASC_NARROW_BOARD(boardp) (((boardp)->flags & ASC_IS_WIDE_BOARD) == 0) -#define ASC_WIDE_BOARD(boardp) ((boardp)->flags & ASC_IS_WIDE_BOARD) #define NO_ISA_DMA 0xff /* No ISA DMA Channel Used */ @@ -3473,82 +2207,14 @@ typedef struct { #define HOST_BYTE(byte) ((byte) << 16) #define DRIVER_BYTE(byte) ((byte) << 24) -/* - * The following definitions and macros are OS independent interfaces to - * the queue functions: - * REQ - SCSI request structure - * REQP - pointer to SCSI request structure - * REQPTID(reqp) - reqp's target id - * REQPNEXT(reqp) - reqp's next pointer - * REQPNEXTP(reqp) - pointer to reqp's next pointer - * REQPTIME(reqp) - reqp's time stamp value - * REQTIMESTAMP() - system time stamp value - */ -typedef struct scsi_cmnd REQ, *REQP; -#define REQPNEXT(reqp) ((REQP) ((reqp)->host_scribble)) -#define REQPNEXTP(reqp) ((REQP *) &((reqp)->host_scribble)) -#define REQPTID(reqp) ((reqp)->device->id) -#define REQPTIME(reqp) ((reqp)->SCp.this_residual) -#define REQTIMESTAMP() (jiffies) - -#define REQTIMESTAT(function, ascq, reqp, tid) \ -{ \ - /* - * If the request time stamp is less than the system time stamp, then \ - * maybe the system time stamp wrapped. Set the request time to zero.\ - */ \ - if (REQPTIME(reqp) <= REQTIMESTAMP()) { \ - REQPTIME(reqp) = REQTIMESTAMP() - REQPTIME(reqp); \ - } else { \ - /* Indicate an error occurred with the assertion. */ \ - ASC_ASSERT(REQPTIME(reqp) <= REQTIMESTAMP()); \ - REQPTIME(reqp) = 0; \ - } \ - /* Handle first minimum time case without external initialization. */ \ - if (((ascq)->q_tot_cnt[tid] == 1) || \ - (REQPTIME(reqp) < (ascq)->q_min_tim[tid])) { \ - (ascq)->q_min_tim[tid] = REQPTIME(reqp); \ - ASC_DBG3(1, "%s: new q_min_tim[%d] %u\n", \ - (function), (tid), (ascq)->q_min_tim[tid]); \ - } \ - if (REQPTIME(reqp) > (ascq)->q_max_tim[tid]) { \ - (ascq)->q_max_tim[tid] = REQPTIME(reqp); \ - ASC_DBG3(1, "%s: new q_max_tim[%d] %u\n", \ - (function), tid, (ascq)->q_max_tim[tid]); \ - } \ - (ascq)->q_tot_tim[tid] += REQPTIME(reqp); \ - /* Reset the time stamp field. */ \ - REQPTIME(reqp) = 0; \ -} - -/* asc_enqueue() flags */ -#define ASC_FRONT 1 -#define ASC_BACK 2 - -/* asc_dequeue_list() argument */ -#define ASC_TID_ALL (-1) - -/* Return non-zero, if the queue is empty. */ -#define ASC_QUEUE_EMPTY(ascq) ((ascq)->q_tidmask == 0) - -#define PCI_MAX_SLOT 0x1F -#define PCI_MAX_BUS 0xFF -#define PCI_IOADDRESS_MASK 0xFFFE -#define ASC_PCI_DEVICE_ID_CNT 6 /* PCI Device ID count. */ - +#define ASC_STATS(shost, counter) ASC_STATS_ADD(shost, counter, 1) #ifndef ADVANSYS_STATS -#define ASC_STATS(shost, counter) #define ASC_STATS_ADD(shost, counter, count) #else /* ADVANSYS_STATS */ -#define ASC_STATS(shost, counter) \ - (ASC_BOARDP(shost)->asc_stats.counter++) - #define ASC_STATS_ADD(shost, counter, count) \ - (ASC_BOARDP(shost)->asc_stats.counter += (count)) + (((struct asc_board *) shost_priv(shost))->asc_stats.counter += (count)) #endif /* ADVANSYS_STATS */ -#define ASC_CEILING(val, unit) (((val) + ((unit) - 1))/(unit)) - /* If the result wraps when calculating tenths, return 0. */ #define ASC_TENTHS(num, den) \ (((10 * ((num)/(den))) > (((num) * 10)/(den))) ? \ @@ -3589,13 +2255,8 @@ typedef struct scsi_cmnd REQ, *REQP; #ifndef ADVANSYS_DEBUG -#define ASC_DBG(lvl, s) -#define ASC_DBG1(lvl, s, a1) -#define ASC_DBG2(lvl, s, a1, a2) -#define ASC_DBG3(lvl, s, a1, a2, a3) -#define ASC_DBG4(lvl, s, a1, a2, a3, a4) +#define ASC_DBG(lvl, s...) #define ASC_DBG_PRT_SCSI_HOST(lvl, s) -#define ASC_DBG_PRT_SCSI_CMND(lvl, s) #define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp) #define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp) #define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone) @@ -3614,40 +2275,11 @@ typedef struct scsi_cmnd REQ, *REQP; * 2-N: Verbose Tracing */ -#define ASC_DBG(lvl, s) \ - { \ - if (asc_dbglvl >= (lvl)) { \ - printk(s); \ - } \ - } - -#define ASC_DBG1(lvl, s, a1) \ - { \ - if (asc_dbglvl >= (lvl)) { \ - printk((s), (a1)); \ - } \ - } - -#define ASC_DBG2(lvl, s, a1, a2) \ - { \ - if (asc_dbglvl >= (lvl)) { \ - printk((s), (a1), (a2)); \ - } \ - } - -#define ASC_DBG3(lvl, s, a1, a2, a3) \ - { \ - if (asc_dbglvl >= (lvl)) { \ - printk((s), (a1), (a2), (a3)); \ - } \ - } - -#define ASC_DBG4(lvl, s, a1, a2, a3, a4) \ - { \ - if (asc_dbglvl >= (lvl)) { \ - printk((s), (a1), (a2), (a3), (a4)); \ - } \ - } +#define ASC_DBG(lvl, format, arg...) { \ + if (asc_dbglvl >= (lvl)) \ + printk(KERN_DEBUG "%s: %s: " format, DRV_NAME, \ + __FUNCTION__ , ## arg); \ +} #define ASC_DBG_PRT_SCSI_HOST(lvl, s) \ { \ @@ -3656,13 +2288,6 @@ typedef struct scsi_cmnd REQ, *REQP; } \ } -#define ASC_DBG_PRT_SCSI_CMND(lvl, s) \ - { \ - if (asc_dbglvl >= (lvl)) { \ - asc_prt_scsi_cmnd(s); \ - } \ - } - #define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp) \ { \ if (asc_dbglvl >= (lvl)) { \ @@ -3701,24 +2326,6 @@ typedef struct scsi_cmnd REQ, *REQP; ASC_DBG_PRT_HEX((lvl), "INQUIRY", (uchar *) (inq), (len)); #endif /* ADVANSYS_DEBUG */ -#ifndef ADVANSYS_ASSERT -#define ASC_ASSERT(a) -#else /* ADVANSYS_ASSERT */ - -#define ASC_ASSERT(a) \ - { \ - if (!(a)) { \ - printk("ASC_ASSERT() Failure: file %s, line %d\n", \ - __FILE__, __LINE__); \ - } \ - } - -#endif /* ADVANSYS_ASSERT */ - -/* - * --- Driver Structures - */ - #ifdef ADVANSYS_STATS /* Per board statistics structure */ @@ -3739,72 +2346,23 @@ struct asc_stats { ADV_DCNT exe_error; /* # ASC_ERROR returns. */ ADV_DCNT exe_unknown; /* # unknown returns. */ /* Data Transfer Statistics */ - ADV_DCNT cont_cnt; /* # non-scatter-gather I/O requests received */ - ADV_DCNT cont_xfer; /* # contiguous transfer 512-bytes */ - ADV_DCNT sg_cnt; /* # scatter-gather I/O requests received */ - ADV_DCNT sg_elem; /* # scatter-gather elements */ - ADV_DCNT sg_xfer; /* # scatter-gather transfer 512-bytes */ + ADV_DCNT xfer_cnt; /* # I/O requests received */ + ADV_DCNT xfer_elem; /* # scatter-gather elements */ + ADV_DCNT xfer_sect; /* # 512-byte blocks */ }; #endif /* ADVANSYS_STATS */ /* - * Request queuing structure - */ -typedef struct asc_queue { - ADV_SCSI_BIT_ID_TYPE q_tidmask; /* queue mask */ - REQP q_first[ADV_MAX_TID + 1]; /* first queued request */ - REQP q_last[ADV_MAX_TID + 1]; /* last queued request */ -#ifdef ADVANSYS_STATS - short q_cur_cnt[ADV_MAX_TID + 1]; /* current queue count */ - short q_max_cnt[ADV_MAX_TID + 1]; /* maximum queue count */ - ADV_DCNT q_tot_cnt[ADV_MAX_TID + 1]; /* total enqueue count */ - ADV_DCNT q_tot_tim[ADV_MAX_TID + 1]; /* total time queued */ - ushort q_max_tim[ADV_MAX_TID + 1]; /* maximum time queued */ - ushort q_min_tim[ADV_MAX_TID + 1]; /* minimum time queued */ -#endif /* ADVANSYS_STATS */ -} asc_queue_t; - -/* - * Adv Library Request Structures - * - * The following two structures are used to process Wide Board requests. - * - * The ADV_SCSI_REQ_Q structure in adv_req_t is passed to the Adv Library - * and microcode with the ADV_SCSI_REQ_Q field 'srb_ptr' pointing to the - * adv_req_t. The adv_req_t structure 'cmndp' field in turn points to the - * Mid-Level SCSI request structure. - * - * Zero or more ADV_SG_BLOCK are used with each ADV_SCSI_REQ_Q. Each - * ADV_SG_BLOCK structure holds 15 scatter-gather elements. Under Linux - * up to 255 scatter-gather elements may be used per request or - * ADV_SCSI_REQ_Q. - * - * Both structures must be 32 byte aligned. - */ -typedef struct adv_sgblk { - ADV_SG_BLOCK sg_block; /* Sgblock structure. */ - uchar align[32]; /* Sgblock structure padding. */ - struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */ -} adv_sgblk_t; - -typedef struct adv_req { - ADV_SCSI_REQ_Q scsi_req_q; /* Adv Library request structure. */ - uchar align[32]; /* Request structure padding. */ - struct scsi_cmnd *cmndp; /* Mid-Level SCSI command pointer. */ - adv_sgblk_t *sgblkp; /* Adv Library scatter-gather pointer. */ - struct adv_req *next_reqp; /* Next Request Structure. */ -} adv_req_t; - -/* * Structure allocated for each board. * - * This structure is allocated by scsi_register() at the end + * This structure is allocated by scsi_host_alloc() at the end * of the 'Scsi_Host' structure starting at the 'hostdata' * field. It is guaranteed to be allocated from DMA-able memory. */ -typedef struct asc_board { - int id; /* Board Id */ +struct asc_board { + struct device *dev; uint flags; /* Board flags */ + unsigned int irq; union { ASC_DVC_VAR asc_dvc_var; /* Narrow board */ ADV_DVC_VAR adv_dvc_var; /* Wide board */ @@ -3814,11 +2372,7 @@ typedef struct asc_board { ADV_DVC_CFG adv_dvc_cfg; /* Wide board */ } dvc_cfg; ushort asc_n_io_port; /* Number I/O ports. */ - asc_queue_t active; /* Active command queue */ - asc_queue_t waiting; /* Waiting command queue */ - asc_queue_t done; /* Done command queue */ ADV_SCSI_BIT_ID_TYPE init_tidmask; /* Target init./valid mask */ - struct scsi_device *device[ADV_MAX_TID + 1]; /* Mid-Level Scsi Device */ ushort reqcnt[ADV_MAX_TID + 1]; /* Starvation request count */ ADV_SCSI_BIT_ID_TYPE queue_full; /* Queue full mask */ ushort queue_full_cnt[ADV_MAX_TID + 1]; /* Queue full count */ @@ -3829,2409 +2383,529 @@ typedef struct asc_board { ADVEEP_38C1600_CONFIG adv_38C1600_eep; /* 38C1600 EEPROM config. */ } eep_config; ulong last_reset; /* Saved last reset time */ - spinlock_t lock; /* Board spinlock */ -#ifdef CONFIG_PROC_FS /* /proc/scsi/advansys/[0...] */ char *prtbuf; /* /proc print buffer */ -#endif /* CONFIG_PROC_FS */ #ifdef ADVANSYS_STATS struct asc_stats asc_stats; /* Board statistics */ #endif /* ADVANSYS_STATS */ /* * The following fields are used only for Narrow Boards. */ - /* The following three structures must be in DMA-able memory. */ - ASC_SCSI_REQ_Q scsireqq; - ASC_CAP_INFO cap_info; - ASC_SCSI_INQUIRY inquiry; uchar sdtr_data[ASC_MAX_TID + 1]; /* SDTR information */ /* * The following fields are used only for Wide Boards. */ void __iomem *ioremap_addr; /* I/O Memory remap address. */ ushort ioport; /* I/O Port address. */ - ADV_CARR_T *orig_carrp; /* ADV_CARR_T memory block. */ - adv_req_t *orig_reqp; /* adv_req_t memory block. */ adv_req_t *adv_reqp; /* Request structures. */ adv_sgblk_t *adv_sgblkp; /* Scatter-gather structures. */ ushort bios_signature; /* BIOS Signature. */ ushort bios_version; /* BIOS Version. */ ushort bios_codeseg; /* BIOS Code Segment. */ ushort bios_codelen; /* BIOS Code Segment Length. */ -} asc_board_t; - -/* - * PCI configuration structures - */ -typedef struct _PCI_DATA_ { - uchar type; - uchar bus; - uchar slot; - uchar func; - uchar offset; -} PCI_DATA; - -typedef struct _PCI_DEVICE_ { - ushort vendorID; - ushort deviceID; - ushort slotNumber; - ushort slotFound; - uchar busNumber; - uchar maxBusNumber; - uchar devFunc; - ushort startSlot; - ushort endSlot; - uchar bridge; - uchar type; -} PCI_DEVICE; - -typedef struct _PCI_CONFIG_SPACE_ { - ushort vendorID; - ushort deviceID; - ushort command; - ushort status; - uchar revision; - uchar classCode[3]; - uchar cacheSize; - uchar latencyTimer; - uchar headerType; - uchar bist; - ADV_PADDR baseAddress[6]; - ushort reserved[4]; - ADV_PADDR optionRomAddr; - ushort reserved2[4]; - uchar irqLine; - uchar irqPin; - uchar minGnt; - uchar maxLatency; -} PCI_CONFIG_SPACE; - -/* - * --- Driver Data - */ - -/* Note: All driver global data should be initialized. */ - -/* Number of boards detected in system. */ -static int asc_board_count = 0; -static struct Scsi_Host *asc_host[ASC_NUM_BOARD_SUPPORTED] = { NULL }; - -/* Overrun buffer used by all narrow boards. */ -static uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 }; - -/* - * Global structures required to issue a command. - */ -static ASC_SCSI_Q asc_scsi_q = { {0} }; -static ASC_SG_HEAD asc_sg_head = { 0 }; - -/* List of supported bus types. */ -static ushort asc_bus[ASC_NUM_BUS] __initdata = { - ASC_IS_ISA, - ASC_IS_VL, - ASC_IS_EISA, - ASC_IS_PCI, }; -static int asc_iopflag = ASC_FALSE; -static int asc_ioport[ASC_NUM_IOPORT_PROBE] = { 0, 0, 0, 0 }; +#define asc_dvc_to_board(asc_dvc) container_of(asc_dvc, struct asc_board, \ + dvc_var.asc_dvc_var) +#define adv_dvc_to_board(adv_dvc) container_of(adv_dvc, struct asc_board, \ + dvc_var.adv_dvc_var) +#define adv_dvc_to_pdev(adv_dvc) to_pci_dev(adv_dvc_to_board(adv_dvc)->dev) #ifdef ADVANSYS_DEBUG -static char *asc_bus_name[ASC_NUM_BUS] = { - "ASC_IS_ISA", - "ASC_IS_VL", - "ASC_IS_EISA", - "ASC_IS_PCI", -}; - static int asc_dbglvl = 3; -#endif /* ADVANSYS_DEBUG */ - -/* Declaration for Asc Library internal data referenced by driver. */ -static PortAddr _asc_def_iop_base[]; - -/* - * --- Driver Function Prototypes - * - * advansys.h contains function prototypes for functions global to Linux. - */ - -static irqreturn_t advansys_interrupt(int, void *); -static int advansys_slave_configure(struct scsi_device *); -static void asc_scsi_done_list(struct scsi_cmnd *); -static int asc_execute_scsi_cmnd(struct scsi_cmnd *); -static int asc_build_req(asc_board_t *, struct scsi_cmnd *); -static int adv_build_req(asc_board_t *, struct scsi_cmnd *, ADV_SCSI_REQ_Q **); -static int adv_get_sglist(asc_board_t *, adv_req_t *, struct scsi_cmnd *, int); -static void asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *); -static void adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *); -static void adv_async_callback(ADV_DVC_VAR *, uchar); -static void asc_enqueue(asc_queue_t *, REQP, int); -static REQP asc_dequeue(asc_queue_t *, int); -static REQP asc_dequeue_list(asc_queue_t *, REQP *, int); -static int asc_rmqueue(asc_queue_t *, REQP); -static void asc_execute_queue(asc_queue_t *); -#ifdef CONFIG_PROC_FS -static int asc_proc_copy(off_t, off_t, char *, int, char *, int); -static int asc_prt_board_devices(struct Scsi_Host *, char *, int); -static int asc_prt_adv_bios(struct Scsi_Host *, char *, int); -static int asc_get_eeprom_string(ushort *serialnum, uchar *cp); -static int asc_prt_asc_board_eeprom(struct Scsi_Host *, char *, int); -static int asc_prt_adv_board_eeprom(struct Scsi_Host *, char *, int); -static int asc_prt_driver_conf(struct Scsi_Host *, char *, int); -static int asc_prt_asc_board_info(struct Scsi_Host *, char *, int); -static int asc_prt_adv_board_info(struct Scsi_Host *, char *, int); -static int asc_prt_line(char *, int, char *fmt, ...); -#endif /* CONFIG_PROC_FS */ - -/* Declaration for Asc Library internal functions referenced by driver. */ -static int AscFindSignature(PortAddr); -static ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort); - -/* Statistics function prototypes. */ -#ifdef ADVANSYS_STATS -#ifdef CONFIG_PROC_FS -static int asc_prt_board_stats(struct Scsi_Host *, char *, int); -static int asc_prt_target_stats(struct Scsi_Host *, int, char *, int); -#endif /* CONFIG_PROC_FS */ -#endif /* ADVANSYS_STATS */ - -/* Debug function prototypes. */ -#ifdef ADVANSYS_DEBUG -static void asc_prt_scsi_host(struct Scsi_Host *); -static void asc_prt_scsi_cmnd(struct scsi_cmnd *); -static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *); -static void asc_prt_asc_dvc_var(ASC_DVC_VAR *); -static void asc_prt_asc_scsi_q(ASC_SCSI_Q *); -static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *); -static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *); -static void asc_prt_adv_dvc_var(ADV_DVC_VAR *); -static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *); -static void asc_prt_adv_sgblock(int, ADV_SG_BLOCK *); -static void asc_prt_hex(char *f, uchar *, int); -#endif /* ADVANSYS_DEBUG */ -#ifdef CONFIG_PROC_FS /* - * advansys_proc_info() - /proc/scsi/advansys/[0-(ASC_NUM_BOARD_SUPPORTED-1)] - * - * *buffer: I/O buffer - * **start: if inout == FALSE pointer into buffer where user read should start - * offset: current offset into a /proc/scsi/advansys/[0...] file - * length: length of buffer - * hostno: Scsi_Host host_no - * inout: TRUE - user is writing; FALSE - user is reading - * - * Return the number of bytes read from or written to a - * /proc/scsi/advansys/[0...] file. - * - * Note: This function uses the per board buffer 'prtbuf' which is - * allocated when the board is initialized in advansys_detect(). The - * buffer is ASC_PRTBUF_SIZE bytes. The function asc_proc_copy() is - * used to write to the buffer. The way asc_proc_copy() is written - * if 'prtbuf' is too small it will not be overwritten. Instead the - * user just won't get all the available statistics. + * asc_prt_asc_dvc_var() */ -static int -advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start, - off_t offset, int length, int inout) +static void asc_prt_asc_dvc_var(ASC_DVC_VAR *h) { - struct Scsi_Host *shp; - asc_board_t *boardp; - int i; - char *cp; - int cplen; - int cnt; - int totcnt; - int leftlen; - char *curbuf; - off_t advoffset; -#ifdef ADVANSYS_STATS - int tgt_id; -#endif /* ADVANSYS_STATS */ - - ASC_DBG(1, "advansys_proc_info: begin\n"); - - /* - * User write not supported. - */ - if (inout == TRUE) { - return (-ENOSYS); - } - - /* - * User read of /proc/scsi/advansys/[0...] file. - */ - - /* Find the specified board. */ - for (i = 0; i < asc_board_count; i++) { - if (asc_host[i]->host_no == shost->host_no) { - break; - } - } - if (i == asc_board_count) { - return (-ENOENT); - } - - shp = asc_host[i]; - boardp = ASC_BOARDP(shp); - - /* Copy read data starting at the beginning of the buffer. */ - *start = buffer; - curbuf = buffer; - advoffset = 0; - totcnt = 0; - leftlen = length; - - /* - * Get board configuration information. - * - * advansys_info() returns the board string from its own static buffer. - */ - cp = (char *)advansys_info(shp); - strcat(cp, "\n"); - cplen = strlen(cp); - /* Copy board information. */ - cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); - totcnt += cnt; - leftlen -= cnt; - if (leftlen == 0) { - ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt); - return totcnt; - } - advoffset += cplen; - curbuf += cnt; - - /* - * Display Wide Board BIOS Information. - */ - if (ASC_WIDE_BOARD(boardp)) { - cp = boardp->prtbuf; - cplen = asc_prt_adv_bios(shp, cp, ASC_PRTBUF_SIZE); - ASC_ASSERT(cplen < ASC_PRTBUF_SIZE); - cnt = - asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, - cplen); - totcnt += cnt; - leftlen -= cnt; - if (leftlen == 0) { - ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt); - return totcnt; - } - advoffset += cplen; - curbuf += cnt; - } - - /* - * Display driver information for each device attached to the board. - */ - cp = boardp->prtbuf; - cplen = asc_prt_board_devices(shp, cp, ASC_PRTBUF_SIZE); - ASC_ASSERT(cplen < ASC_PRTBUF_SIZE); - cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); - totcnt += cnt; - leftlen -= cnt; - if (leftlen == 0) { - ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt); - return totcnt; - } - advoffset += cplen; - curbuf += cnt; - - /* - * Display EEPROM configuration for the board. - */ - cp = boardp->prtbuf; - if (ASC_NARROW_BOARD(boardp)) { - cplen = asc_prt_asc_board_eeprom(shp, cp, ASC_PRTBUF_SIZE); - } else { - cplen = asc_prt_adv_board_eeprom(shp, cp, ASC_PRTBUF_SIZE); - } - ASC_ASSERT(cplen < ASC_PRTBUF_SIZE); - cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); - totcnt += cnt; - leftlen -= cnt; - if (leftlen == 0) { - ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt); - return totcnt; - } - advoffset += cplen; - curbuf += cnt; - - /* - * Display driver configuration and information for the board. - */ - cp = boardp->prtbuf; - cplen = asc_prt_driver_conf(shp, cp, ASC_PRTBUF_SIZE); - ASC_ASSERT(cplen < ASC_PRTBUF_SIZE); - cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); - totcnt += cnt; - leftlen -= cnt; - if (leftlen == 0) { - ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt); - return totcnt; - } - advoffset += cplen; - curbuf += cnt; + printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong)h); -#ifdef ADVANSYS_STATS - /* - * Display driver statistics for the board. - */ - cp = boardp->prtbuf; - cplen = asc_prt_board_stats(shp, cp, ASC_PRTBUF_SIZE); - ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE); - cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); - totcnt += cnt; - leftlen -= cnt; - if (leftlen == 0) { - ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt); - return totcnt; - } - advoffset += cplen; - curbuf += cnt; + printk(" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl " + "%d,\n", h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl); - /* - * Display driver statistics for each target. - */ - for (tgt_id = 0; tgt_id <= ADV_MAX_TID; tgt_id++) { - cp = boardp->prtbuf; - cplen = asc_prt_target_stats(shp, tgt_id, cp, ASC_PRTBUF_SIZE); - ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE); - cnt = - asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, - cplen); - totcnt += cnt; - leftlen -= cnt; - if (leftlen == 0) { - ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt); - return totcnt; - } - advoffset += cplen; - curbuf += cnt; - } -#endif /* ADVANSYS_STATS */ + printk(" bus_type %d, init_sdtr 0x%x,\n", h->bus_type, + (unsigned)h->init_sdtr); - /* - * Display Asc Library dynamic configuration information - * for the board. - */ - cp = boardp->prtbuf; - if (ASC_NARROW_BOARD(boardp)) { - cplen = asc_prt_asc_board_info(shp, cp, ASC_PRTBUF_SIZE); - } else { - cplen = asc_prt_adv_board_info(shp, cp, ASC_PRTBUF_SIZE); - } - ASC_ASSERT(cplen < ASC_PRTBUF_SIZE); - cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); - totcnt += cnt; - leftlen -= cnt; - if (leftlen == 0) { - ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt); - return totcnt; - } - advoffset += cplen; - curbuf += cnt; + printk(" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, " + "chip_no 0x%x,\n", (unsigned)h->sdtr_done, + (unsigned)h->use_tagged_qng, (unsigned)h->unit_not_ready, + (unsigned)h->chip_no); - ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt); + printk(" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait " + "%u,\n", (unsigned)h->queue_full_or_busy, + (unsigned)h->start_motor, (unsigned)h->scsi_reset_wait); - return totcnt; -} -#endif /* CONFIG_PROC_FS */ + printk(" is_in_int %u, max_total_qng %u, cur_total_qng %u, " + "in_critical_cnt %u,\n", (unsigned)h->is_in_int, + (unsigned)h->max_total_qng, (unsigned)h->cur_total_qng, + (unsigned)h->in_critical_cnt); -/* - * advansys_info() - * - * Return suitable for printing on the console with the argument - * adapter's configuration information. - * - * Note: The information line should not exceed ASC_INFO_SIZE bytes, - * otherwise the static 'info' array will be overrun. - */ -static const char *advansys_info(struct Scsi_Host *shost) -{ - static char info[ASC_INFO_SIZE]; - asc_board_t *boardp; - ASC_DVC_VAR *asc_dvc_varp; - ADV_DVC_VAR *adv_dvc_varp; - char *busname; - int iolen; - char *widename = NULL; + printk(" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, " + "pci_fix_asyn_xfer 0x%x,\n", (unsigned)h->last_q_shortage, + (unsigned)h->init_state, (unsigned)h->no_scam, + (unsigned)h->pci_fix_asyn_xfer); - boardp = ASC_BOARDP(shost); - if (ASC_NARROW_BOARD(boardp)) { - asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; - ASC_DBG(1, "advansys_info: begin\n"); - if (asc_dvc_varp->bus_type & ASC_IS_ISA) { - if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) == - ASC_IS_ISAPNP) { - busname = "ISA PnP"; - } else { - busname = "ISA"; - } - /* Don't reference 'shost->n_io_port'; It may be truncated. */ - sprintf(info, - "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X", - ASC_VERSION, busname, - (ulong)shost->io_port, - (ulong)shost->io_port + boardp->asc_n_io_port - - 1, shost->irq, shost->dma_channel); - } else { - if (asc_dvc_varp->bus_type & ASC_IS_VL) { - busname = "VL"; - } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) { - busname = "EISA"; - } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) { - if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA) - == ASC_IS_PCI_ULTRA) { - busname = "PCI Ultra"; - } else { - busname = "PCI"; - } - } else { - busname = "?"; - ASC_PRINT2 - ("advansys_info: board %d: unknown bus type %d\n", - boardp->id, asc_dvc_varp->bus_type); - } - /* Don't reference 'shost->n_io_port'; It may be truncated. */ - sprintf(info, - "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X", - ASC_VERSION, busname, - (ulong)shost->io_port, - (ulong)shost->io_port + boardp->asc_n_io_port - - 1, shost->irq); - } - } else { - /* - * Wide Adapter Information - * - * Memory-mapped I/O is used instead of I/O space to access - * the adapter, but display the I/O Port range. The Memory - * I/O address is displayed through the driver /proc file. - */ - adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; - if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { - iolen = ADV_3550_IOLEN; - widename = "Ultra-Wide"; - } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { - iolen = ADV_38C0800_IOLEN; - widename = "Ultra2-Wide"; - } else { - iolen = ADV_38C1600_IOLEN; - widename = "Ultra3-Wide"; - } - sprintf(info, - "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X", - ASC_VERSION, widename, (ulong)adv_dvc_varp->iop_base, - (ulong)adv_dvc_varp->iop_base + iolen - 1, shost->irq); - } - ASC_ASSERT(strlen(info) < ASC_INFO_SIZE); - ASC_DBG(1, "advansys_info: end\n"); - return info; + printk(" cfg 0x%lx\n", (ulong)h->cfg); } /* - * advansys_queuecommand() - interrupt-driven I/O entrypoint. - * - * This function always returns 0. Command return status is saved - * in the 'scp' result field. + * asc_prt_asc_dvc_cfg() */ -static int -advansys_queuecommand(struct scsi_cmnd *scp, void (*done) (struct scsi_cmnd *)) +static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h) { - struct Scsi_Host *shost; - asc_board_t *boardp; - ulong flags; - struct scsi_cmnd *done_scp; - - shost = scp->device->host; - boardp = ASC_BOARDP(shost); - ASC_STATS(shost, queuecommand); - - /* host_lock taken by mid-level prior to call but need to protect */ - /* against own ISR */ - spin_lock_irqsave(&boardp->lock, flags); - - /* - * Block new commands while handling a reset or abort request. - */ - if (boardp->flags & ASC_HOST_IN_RESET) { - ASC_DBG1(1, - "advansys_queuecommand: scp 0x%lx blocked for reset request\n", - (ulong)scp); - scp->result = HOST_BYTE(DID_RESET); - - /* - * Add blocked requests to the board's 'done' queue. The queued - * requests will be completed at the end of the abort or reset - * handling. - */ - asc_enqueue(&boardp->done, scp, ASC_BACK); - spin_unlock_irqrestore(&boardp->lock, flags); - return 0; - } + printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong)h); - /* - * Attempt to execute any waiting commands for the board. - */ - if (!ASC_QUEUE_EMPTY(&boardp->waiting)) { - ASC_DBG(1, - "advansys_queuecommand: before asc_execute_queue() waiting\n"); - asc_execute_queue(&boardp->waiting); - } + printk(" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n", + h->can_tagged_qng, h->cmd_qng_enabled); + printk(" disc_enable 0x%x, sdtr_enable 0x%x,\n", + h->disc_enable, h->sdtr_enable); - /* - * Save the function pointer to Linux mid-level 'done' function - * and attempt to execute the command. - * - * If ASC_NOERROR is returned the request has been added to the - * board's 'active' queue and will be completed by the interrupt - * handler. - * - * If ASC_BUSY is returned add the request to the board's per - * target waiting list. This is the first time the request has - * been tried. Add it to the back of the waiting list. It will be - * retried later. - * - * If an error occurred, the request will have been placed on the - * board's 'done' queue and must be completed before returning. - */ - scp->scsi_done = done; - switch (asc_execute_scsi_cmnd(scp)) { - case ASC_NOERROR: - break; - case ASC_BUSY: - asc_enqueue(&boardp->waiting, scp, ASC_BACK); - break; - case ASC_ERROR: - default: - done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL); - /* Interrupts could be enabled here. */ - asc_scsi_done_list(done_scp); - break; - } - spin_unlock_irqrestore(&boardp->lock, flags); + printk(" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, " + "chip_version %d,\n", h->chip_scsi_id, h->isa_dma_speed, + h->isa_dma_channel, h->chip_version); - return 0; + printk(" mcode_date 0x%x, mcode_version %d\n", + h->mcode_date, h->mcode_version); } /* - * advansys_reset() - * - * Reset the bus associated with the command 'scp'. + * asc_prt_adv_dvc_var() * - * This function runs its own thread. Interrupts must be blocked but - * sleeping is allowed and no locking other than for host structures is - * required. Returns SUCCESS or FAILED. + * Display an ADV_DVC_VAR structure. */ -static int advansys_reset(struct scsi_cmnd *scp) +static void asc_prt_adv_dvc_var(ADV_DVC_VAR *h) { - struct Scsi_Host *shost; - asc_board_t *boardp; - ASC_DVC_VAR *asc_dvc_varp; - ADV_DVC_VAR *adv_dvc_varp; - ulong flags; - struct scsi_cmnd *done_scp = NULL, *last_scp = NULL; - struct scsi_cmnd *tscp, *new_last_scp; - int status; - int ret = SUCCESS; - - ASC_DBG1(1, "advansys_reset: 0x%lx\n", (ulong)scp); - -#ifdef ADVANSYS_STATS - if (scp->device->host != NULL) { - ASC_STATS(scp->device->host, reset); - } -#endif /* ADVANSYS_STATS */ - - if ((shost = scp->device->host) == NULL) { - scp->result = HOST_BYTE(DID_ERROR); - return FAILED; - } - - boardp = ASC_BOARDP(shost); - - ASC_PRINT1("advansys_reset: board %d: SCSI bus reset started...\n", - boardp->id); - /* - * Check for re-entrancy. - */ - spin_lock_irqsave(&boardp->lock, flags); - if (boardp->flags & ASC_HOST_IN_RESET) { - spin_unlock_irqrestore(&boardp->lock, flags); - return FAILED; - } - boardp->flags |= ASC_HOST_IN_RESET; - spin_unlock_irqrestore(&boardp->lock, flags); - - if (ASC_NARROW_BOARD(boardp)) { - /* - * Narrow Board - */ - asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; - - /* - * Reset the chip and SCSI bus. - */ - ASC_DBG(1, "advansys_reset: before AscInitAsc1000Driver()\n"); - status = AscInitAsc1000Driver(asc_dvc_varp); - - /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */ - if (asc_dvc_varp->err_code) { - ASC_PRINT2 - ("advansys_reset: board %d: SCSI bus reset error: 0x%x\n", - boardp->id, asc_dvc_varp->err_code); - ret = FAILED; - } else if (status) { - ASC_PRINT2 - ("advansys_reset: board %d: SCSI bus reset warning: 0x%x\n", - boardp->id, status); - } else { - ASC_PRINT1 - ("advansys_reset: board %d: SCSI bus reset successful.\n", - boardp->id); - } - - ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n"); - spin_lock_irqsave(&boardp->lock, flags); - - } else { - /* - * Wide Board - * - * If the suggest reset bus flags are set, then reset the bus. - * Otherwise only reset the device. - */ - adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; - - /* - * Reset the target's SCSI bus. - */ - ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n"); - switch (AdvResetChipAndSB(adv_dvc_varp)) { - case ASC_TRUE: - ASC_PRINT1 - ("advansys_reset: board %d: SCSI bus reset successful.\n", - boardp->id); - break; - case ASC_FALSE: - default: - ASC_PRINT1 - ("advansys_reset: board %d: SCSI bus reset error.\n", - boardp->id); - ret = FAILED; - break; - } - spin_lock_irqsave(&boardp->lock, flags); - (void)AdvISR(adv_dvc_varp); - } - /* Board lock is held. */ - - /* - * Dequeue all board 'done' requests. A pointer to the last request - * is returned in 'last_scp'. - */ - done_scp = asc_dequeue_list(&boardp->done, &last_scp, ASC_TID_ALL); - - /* - * Dequeue all board 'active' requests for all devices and set - * the request status to DID_RESET. A pointer to the last request - * is returned in 'last_scp'. - */ - if (done_scp == NULL) { - done_scp = - asc_dequeue_list(&boardp->active, &last_scp, ASC_TID_ALL); - for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) { - tscp->result = HOST_BYTE(DID_RESET); - } - } else { - /* Append to 'done_scp' at the end with 'last_scp'. */ - ASC_ASSERT(last_scp != NULL); - last_scp->host_scribble = - (unsigned char *)asc_dequeue_list(&boardp->active, - &new_last_scp, - ASC_TID_ALL); - if (new_last_scp != NULL) { - ASC_ASSERT(REQPNEXT(last_scp) != NULL); - for (tscp = REQPNEXT(last_scp); tscp; - tscp = REQPNEXT(tscp)) { - tscp->result = HOST_BYTE(DID_RESET); - } - last_scp = new_last_scp; - } - } - - /* - * Dequeue all 'waiting' requests and set the request status - * to DID_RESET. - */ - if (done_scp == NULL) { - done_scp = - asc_dequeue_list(&boardp->waiting, &last_scp, ASC_TID_ALL); - for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) { - tscp->result = HOST_BYTE(DID_RESET); - } - } else { - /* Append to 'done_scp' at the end with 'last_scp'. */ - ASC_ASSERT(last_scp != NULL); - last_scp->host_scribble = - (unsigned char *)asc_dequeue_list(&boardp->waiting, - &new_last_scp, - ASC_TID_ALL); - if (new_last_scp != NULL) { - ASC_ASSERT(REQPNEXT(last_scp) != NULL); - for (tscp = REQPNEXT(last_scp); tscp; - tscp = REQPNEXT(tscp)) { - tscp->result = HOST_BYTE(DID_RESET); - } - last_scp = new_last_scp; - } - } + printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong)h); - /* Save the time of the most recently completed reset. */ - boardp->last_reset = jiffies; + printk(" iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n", + (ulong)h->iop_base, h->err_code, (unsigned)h->ultra_able); - /* Clear reset flag. */ - boardp->flags &= ~ASC_HOST_IN_RESET; - spin_unlock_irqrestore(&boardp->lock, flags); + printk(" sdtr_able 0x%x, wdtr_able 0x%x\n", + (unsigned)h->sdtr_able, (unsigned)h->wdtr_able); - /* - * Complete all the 'done_scp' requests. - */ - if (done_scp != NULL) { - asc_scsi_done_list(done_scp); - } + printk(" start_motor 0x%x, scsi_reset_wait 0x%x\n", + (unsigned)h->start_motor, (unsigned)h->scsi_reset_wait); - ASC_DBG1(1, "advansys_reset: ret %d\n", ret); + printk(" max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n", + (unsigned)h->max_host_qng, (unsigned)h->max_dvc_qng, + (ulong)h->carr_freelist); - return ret; -} + printk(" icq_sp 0x%lx, irq_sp 0x%lx\n", + (ulong)h->icq_sp, (ulong)h->irq_sp); -/* - * advansys_biosparam() - * - * Translate disk drive geometry if the "BIOS greater than 1 GB" - * support is enabled for a drive. - * - * ip (information pointer) is an int array with the following definition: - * ip[0]: heads - * ip[1]: sectors - * ip[2]: cylinders - */ -static int -advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev, - sector_t capacity, int ip[]) -{ - asc_board_t *boardp; + printk(" no_scam 0x%x, tagqng_able 0x%x\n", + (unsigned)h->no_scam, (unsigned)h->tagqng_able); - ASC_DBG(1, "advansys_biosparam: begin\n"); - ASC_STATS(sdev->host, biosparam); - boardp = ASC_BOARDP(sdev->host); - if (ASC_NARROW_BOARD(boardp)) { - if ((boardp->dvc_var.asc_dvc_var.dvc_cntl & - ASC_CNTL_BIOS_GT_1GB) && capacity > 0x200000) { - ip[0] = 255; - ip[1] = 63; - } else { - ip[0] = 64; - ip[1] = 32; - } - } else { - if ((boardp->dvc_var.adv_dvc_var.bios_ctrl & - BIOS_CTRL_EXTENDED_XLAT) && capacity > 0x200000) { - ip[0] = 255; - ip[1] = 63; - } else { - ip[0] = 64; - ip[1] = 32; - } - } - ip[2] = (unsigned long)capacity / (ip[0] * ip[1]); - ASC_DBG(1, "advansys_biosparam: end\n"); - return 0; + printk(" chip_scsi_id 0x%x, cfg 0x%lx\n", + (unsigned)h->chip_scsi_id, (ulong)h->cfg); } -static int __init advansys_detect(struct scsi_host_template *tpnt); -static int advansys_release(struct Scsi_Host *shp); - -static struct scsi_host_template driver_template = { - .proc_name = "advansys", -#ifdef CONFIG_PROC_FS - .proc_info = advansys_proc_info, -#endif - .name = "advansys", - .detect = advansys_detect, - .release = advansys_release, - .info = advansys_info, - .queuecommand = advansys_queuecommand, - .eh_bus_reset_handler = advansys_reset, - .bios_param = advansys_biosparam, - .slave_configure = advansys_slave_configure, - /* - * Because the driver may control an ISA adapter 'unchecked_isa_dma' - * must be set. The flag will be cleared in advansys_detect for non-ISA - * adapters. Refer to the comment in scsi_module.c for more information. - */ - .unchecked_isa_dma = 1, - /* - * All adapters controlled by this driver are capable of large - * scatter-gather lists. According to the mid-level SCSI documentation - * this obviates any performance gain provided by setting - * 'use_clustering'. But empirically while CPU utilization is increased - * by enabling clustering, I/O throughput increases as well. - */ - .use_clustering = ENABLE_CLUSTERING, -}; - -#include "scsi_module.c" - -/* - * --- Miscellaneous Driver Functions - */ - /* - * First-level interrupt handler. + * asc_prt_adv_dvc_cfg() * - * 'dev_id' is a pointer to the interrupting adapter's asc_board_t. Because - * all boards are currently checked for interrupts on each interrupt, 'dev_id' - * is not referenced. 'dev_id' could be used to identify an interrupt passed - * to the AdvanSys driver which is for a device sharing an interrupt with - * an AdvanSys adapter. + * Display an ADV_DVC_CFG structure. */ -static irqreturn_t advansys_interrupt(int irq, void *dev_id) +static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h) { - ulong flags; - int i; - asc_board_t *boardp; - struct scsi_cmnd *done_scp = NULL, *last_scp = NULL; - struct scsi_cmnd *new_last_scp; - struct Scsi_Host *shost; - - ASC_DBG(1, "advansys_interrupt: begin\n"); - - /* - * Check for interrupts on all boards. - * AscISR() will call asc_isr_callback(). - */ - for (i = 0; i < asc_board_count; i++) { - shost = asc_host[i]; - boardp = ASC_BOARDP(shost); - ASC_DBG2(2, "advansys_interrupt: i %d, boardp 0x%lx\n", - i, (ulong)boardp); - spin_lock_irqsave(&boardp->lock, flags); - if (ASC_NARROW_BOARD(boardp)) { - /* - * Narrow Board - */ - if (AscIsIntPending(shost->io_port)) { - ASC_STATS(shost, interrupt); - ASC_DBG(1, - "advansys_interrupt: before AscISR()\n"); - AscISR(&boardp->dvc_var.asc_dvc_var); - } - } else { - /* - * Wide Board - */ - ASC_DBG(1, "advansys_interrupt: before AdvISR()\n"); - if (AdvISR(&boardp->dvc_var.adv_dvc_var)) { - ASC_STATS(shost, interrupt); - } - } - - /* - * Start waiting requests and create a list of completed requests. - * - * If a reset request is being performed for the board, the reset - * handler will complete pending requests after it has completed. - */ - if ((boardp->flags & ASC_HOST_IN_RESET) == 0) { - ASC_DBG2(1, - "advansys_interrupt: done_scp 0x%lx, last_scp 0x%lx\n", - (ulong)done_scp, (ulong)last_scp); - - /* Start any waiting commands for the board. */ - if (!ASC_QUEUE_EMPTY(&boardp->waiting)) { - ASC_DBG(1, - "advansys_interrupt: before asc_execute_queue()\n"); - asc_execute_queue(&boardp->waiting); - } - - /* - * Add to the list of requests that must be completed. - * - * 'done_scp' will always be NULL on the first iteration - * of this loop. 'last_scp' is set at the same time as - * 'done_scp'. - */ - if (done_scp == NULL) { - done_scp = - asc_dequeue_list(&boardp->done, &last_scp, - ASC_TID_ALL); - } else { - ASC_ASSERT(last_scp != NULL); - last_scp->host_scribble = - (unsigned char *)asc_dequeue_list(&boardp-> - done, - &new_last_scp, - ASC_TID_ALL); - if (new_last_scp != NULL) { - ASC_ASSERT(REQPNEXT(last_scp) != NULL); - last_scp = new_last_scp; - } - } - } - spin_unlock_irqrestore(&boardp->lock, flags); - } - - /* - * If interrupts were enabled on entry, then they - * are now enabled here. - * - * Complete all requests on the done list. - */ - - asc_scsi_done_list(done_scp); + printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong)h); - ASC_DBG(1, "advansys_interrupt: end\n"); - return IRQ_HANDLED; -} + printk(" disc_enable 0x%x, termination 0x%x\n", + h->disc_enable, h->termination); -/* - * Set the number of commands to queue per device for the - * specified host adapter. - */ -static int advansys_slave_configure(struct scsi_device *device) -{ - asc_board_t *boardp; + printk(" chip_version 0x%x, mcode_date 0x%x\n", + h->chip_version, h->mcode_date); - boardp = ASC_BOARDP(device->host); - boardp->flags |= ASC_SELECT_QUEUE_DEPTHS; - /* - * Save a pointer to the device and set its initial/maximum - * queue depth. Only save the pointer for a lun0 dev though. - */ - if (device->lun == 0) - boardp->device[device->id] = device; - if (device->tagged_supported) { - if (ASC_NARROW_BOARD(boardp)) { - scsi_adjust_queue_depth(device, MSG_ORDERED_TAG, - boardp->dvc_var.asc_dvc_var. - max_dvc_qng[device->id]); - } else { - scsi_adjust_queue_depth(device, MSG_ORDERED_TAG, - boardp->dvc_var.adv_dvc_var. - max_dvc_qng); - } - } else { - scsi_adjust_queue_depth(device, 0, device->host->cmd_per_lun); - } - ASC_DBG4(1, - "advansys_slave_configure: device 0x%lx, boardp 0x%lx, id %d, depth %d\n", - (ulong)device, (ulong)boardp, device->id, device->queue_depth); - return 0; + printk(" mcode_version 0x%x, control_flag 0x%x\n", + h->mcode_version, h->control_flag); } /* - * Complete all requests on the singly linked list pointed - * to by 'scp'. - * - * Interrupts can be enabled on entry. + * asc_prt_scsi_host() */ -static void asc_scsi_done_list(struct scsi_cmnd *scp) +static void asc_prt_scsi_host(struct Scsi_Host *s) { - struct scsi_cmnd *tscp; - - ASC_DBG(2, "asc_scsi_done_list: begin\n"); - while (scp != NULL) { - asc_board_t *boardp; - struct device *dev; + struct asc_board *boardp = shost_priv(s); - ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lx\n", (ulong)scp); - tscp = REQPNEXT(scp); - scp->host_scribble = NULL; - - boardp = ASC_BOARDP(scp->device->host); - - if (ASC_NARROW_BOARD(boardp)) - dev = boardp->dvc_cfg.asc_dvc_cfg.dev; - else - dev = boardp->dvc_cfg.adv_dvc_cfg.dev; + printk("Scsi_Host at addr 0x%p, device %s\n", s, boardp->dev->bus_id); + printk(" host_busy %u, host_no %d, last_reset %d,\n", + s->host_busy, s->host_no, (unsigned)s->last_reset); - if (scp->use_sg) - dma_unmap_sg(dev, - (struct scatterlist *)scp->request_buffer, - scp->use_sg, scp->sc_data_direction); - else if (scp->request_bufflen) - dma_unmap_single(dev, scp->SCp.dma_handle, - scp->request_bufflen, - scp->sc_data_direction); + printk(" base 0x%lx, io_port 0x%lx, irq %d,\n", + (ulong)s->base, (ulong)s->io_port, boardp->irq); - ASC_STATS(scp->device->host, done); - ASC_ASSERT(scp->scsi_done != NULL); + printk(" dma_channel %d, this_id %d, can_queue %d,\n", + s->dma_channel, s->this_id, s->can_queue); - scp->scsi_done(scp); + printk(" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n", + s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma); - scp = tscp; + if (ASC_NARROW_BOARD(boardp)) { + asc_prt_asc_dvc_var(&boardp->dvc_var.asc_dvc_var); + asc_prt_asc_dvc_cfg(&boardp->dvc_cfg.asc_dvc_cfg); + } else { + asc_prt_adv_dvc_var(&boardp->dvc_var.adv_dvc_var); + asc_prt_adv_dvc_cfg(&boardp->dvc_cfg.adv_dvc_cfg); } - ASC_DBG(2, "asc_scsi_done_list: done\n"); - return; } /* - * Execute a single 'Scsi_Cmnd'. - * - * The function 'done' is called when the request has been completed. - * - * Scsi_Cmnd: - * - * host - board controlling device - * device - device to send command - * target - target of device - * lun - lun of device - * cmd_len - length of SCSI CDB - * cmnd - buffer for SCSI 8, 10, or 12 byte CDB - * use_sg - if non-zero indicates scatter-gather request with use_sg elements - * - * if (use_sg == 0) { - * request_buffer - buffer address for request - * request_bufflen - length of request buffer - * } else { - * request_buffer - pointer to scatterlist structure - * } - * - * sense_buffer - sense command buffer - * - * result (4 bytes of an int): - * Byte Meaning - * 0 SCSI Status Byte Code - * 1 SCSI One Byte Message Code - * 2 Host Error Code - * 3 Mid-Level Error Code - * - * host driver fields: - * SCp - Scsi_Pointer used for command processing status - * scsi_done - used to save caller's done function - * host_scribble - used for pointer to another struct scsi_cmnd - * - * If this function returns ASC_NOERROR the request has been enqueued - * on the board's 'active' queue and will be completed from the - * interrupt handler. - * - * If this function returns ASC_NOERROR the request has been enqueued - * on the board's 'done' queue and must be completed by the caller. + * asc_prt_hex() * - * If ASC_BUSY is returned the request will be enqueued by the - * caller on the target's waiting queue and re-tried later. + * Print hexadecimal output in 4 byte groupings 32 bytes + * or 8 double-words per line. */ -static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp) +static void asc_prt_hex(char *f, uchar *s, int l) { - asc_board_t *boardp; - ASC_DVC_VAR *asc_dvc_varp; - ADV_DVC_VAR *adv_dvc_varp; - ADV_SCSI_REQ_Q *adv_scsiqp; - struct scsi_device *device; - int ret; - - ASC_DBG2(1, "asc_execute_scsi_cmnd: scp 0x%lx, done 0x%lx\n", - (ulong)scp, (ulong)scp->scsi_done); - - boardp = ASC_BOARDP(scp->device->host); - device = boardp->device[scp->device->id]; + int i; + int j; + int k; + int m; - if (ASC_NARROW_BOARD(boardp)) { - /* - * Build and execute Narrow Board request. - */ + printk("%s: (%d bytes)\n", f, l); - asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; + for (i = 0; i < l; i += 32) { - /* - * Build Asc Library request structure using the - * global structures 'asc_scsi_req' and 'asc_sg_head'. - * - * If an error is returned, then the request has been - * queued on the board done queue. It will be completed - * by the caller. - * - * asc_build_req() can not return ASC_BUSY. - */ - if (asc_build_req(boardp, scp) == ASC_ERROR) { - ASC_STATS(scp->device->host, build_error); - return ASC_ERROR; + /* Display a maximum of 8 double-words per line. */ + if ((k = (l - i) / 4) >= 8) { + k = 8; + m = 0; + } else { + m = (l - i) % 4; } - /* - * Execute the command. If there is no error, add the command - * to the active queue. - */ - switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) { - case ASC_NOERROR: - ASC_STATS(scp->device->host, exe_noerror); - /* - * Increment monotonically increasing per device successful - * request counter. Wrapping doesn't matter. - */ - boardp->reqcnt[scp->device->id]++; - asc_enqueue(&boardp->active, scp, ASC_BACK); - ASC_DBG(1, - "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n"); - break; - case ASC_BUSY: - /* - * Caller will enqueue request on the target's waiting queue - * and retry later. - */ - ASC_STATS(scp->device->host, exe_busy); - break; - case ASC_ERROR: - ASC_PRINT2 - ("asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code 0x%x\n", - boardp->id, asc_dvc_varp->err_code); - ASC_STATS(scp->device->host, exe_error); - scp->result = HOST_BYTE(DID_ERROR); - asc_enqueue(&boardp->done, scp, ASC_BACK); - break; - default: - ASC_PRINT2 - ("asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code 0x%x\n", - boardp->id, asc_dvc_varp->err_code); - ASC_STATS(scp->device->host, exe_unknown); - scp->result = HOST_BYTE(DID_ERROR); - asc_enqueue(&boardp->done, scp, ASC_BACK); - break; + for (j = 0; j < k; j++) { + printk(" %2.2X%2.2X%2.2X%2.2X", + (unsigned)s[i + (j * 4)], + (unsigned)s[i + (j * 4) + 1], + (unsigned)s[i + (j * 4) + 2], + (unsigned)s[i + (j * 4) + 3]); } - } else { - /* - * Build and execute Wide Board request. - */ - adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; - /* - * Build and get a pointer to an Adv Library request structure. - * - * If the request is successfully built then send it below, - * otherwise return with an error. - */ - switch (adv_build_req(boardp, scp, &adv_scsiqp)) { - case ASC_NOERROR: - ASC_DBG(3, - "asc_execute_scsi_cmnd: adv_build_req ASC_NOERROR\n"); - break; - case ASC_BUSY: - ASC_DBG(1, - "asc_execute_scsi_cmnd: adv_build_req ASC_BUSY\n"); - /* - * If busy is returned the request has not been enqueued. - * It will be enqueued by the caller on the target's waiting - * queue and retried later. - * - * The asc_stats fields 'adv_build_noreq' and 'adv_build_nosg' - * count wide board busy conditions. They are updated in - * adv_build_req and adv_get_sglist, respectively. - */ - return ASC_BUSY; - case ASC_ERROR: - /* - * If an error is returned, then the request has been - * queued on the board done queue. It will be completed - * by the caller. - */ + switch (m) { + case 0: default: - ASC_DBG(1, - "asc_execute_scsi_cmnd: adv_build_req ASC_ERROR\n"); - ASC_STATS(scp->device->host, build_error); - return ASC_ERROR; - } - - /* - * Execute the command. If there is no error, add the command - * to the active queue. - */ - switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) { - case ASC_NOERROR: - ASC_STATS(scp->device->host, exe_noerror); - /* - * Increment monotonically increasing per device successful - * request counter. Wrapping doesn't matter. - */ - boardp->reqcnt[scp->device->id]++; - asc_enqueue(&boardp->active, scp, ASC_BACK); - ASC_DBG(1, - "asc_execute_scsi_cmnd: AdvExeScsiQueue(), ASC_NOERROR\n"); break; - case ASC_BUSY: - /* - * Caller will enqueue request on the target's waiting queue - * and retry later. - */ - ASC_STATS(scp->device->host, exe_busy); + case 1: + printk(" %2.2X", (unsigned)s[i + (j * 4)]); break; - case ASC_ERROR: - ASC_PRINT2 - ("asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() ASC_ERROR, err_code 0x%x\n", - boardp->id, adv_dvc_varp->err_code); - ASC_STATS(scp->device->host, exe_error); - scp->result = HOST_BYTE(DID_ERROR); - asc_enqueue(&boardp->done, scp, ASC_BACK); + case 2: + printk(" %2.2X%2.2X", + (unsigned)s[i + (j * 4)], + (unsigned)s[i + (j * 4) + 1]); break; - default: - ASC_PRINT2 - ("asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() unknown, err_code 0x%x\n", - boardp->id, adv_dvc_varp->err_code); - ASC_STATS(scp->device->host, exe_unknown); - scp->result = HOST_BYTE(DID_ERROR); - asc_enqueue(&boardp->done, scp, ASC_BACK); + case 3: + printk(" %2.2X%2.2X%2.2X", + (unsigned)s[i + (j * 4) + 1], + (unsigned)s[i + (j * 4) + 2], + (unsigned)s[i + (j * 4) + 3]); break; } - } - - ASC_DBG(1, "asc_execute_scsi_cmnd: end\n"); - return ret; -} -/* - * Build a request structure for the Asc Library (Narrow Board). - * - * The global structures 'asc_scsi_q' and 'asc_sg_head' are - * used to build the request. - * - * If an error occurs, then queue the request on the board done - * queue and return ASC_ERROR. - */ -static int asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp) -{ - struct device *dev = boardp->dvc_cfg.asc_dvc_cfg.dev; - - /* - * Mutually exclusive access is required to 'asc_scsi_q' and - * 'asc_sg_head' until after the request is started. - */ - memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q)); - - /* - * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'. - */ - asc_scsi_q.q2.srb_ptr = ASC_VADDR_TO_U32(scp); - - /* - * Build the ASC_SCSI_Q request. - * - * For narrow boards a CDB length maximum of 12 bytes - * is supported. - */ - if (scp->cmd_len > ASC_MAX_CDB_LEN) { - ASC_PRINT3 - ("asc_build_req: board %d: cmd_len %d > ASC_MAX_CDB_LEN %d\n", - boardp->id, scp->cmd_len, ASC_MAX_CDB_LEN); - scp->result = HOST_BYTE(DID_ERROR); - asc_enqueue(&boardp->done, scp, ASC_BACK); - return ASC_ERROR; - } - asc_scsi_q.cdbptr = &scp->cmnd[0]; - asc_scsi_q.q2.cdb_len = scp->cmd_len; - asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id); - asc_scsi_q.q1.target_lun = scp->device->lun; - asc_scsi_q.q2.target_ix = - ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun); - asc_scsi_q.q1.sense_addr = - cpu_to_le32(virt_to_bus(&scp->sense_buffer[0])); - asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer); - - /* - * If there are any outstanding requests for the current target, - * then every 255th request send an ORDERED request. This heuristic - * tries to retain the benefit of request sorting while preventing - * request starvation. 255 is the max number of tags or pending commands - * a device may have outstanding. - * - * The request count is incremented below for every successfully - * started request. - * - */ - if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->device->id] > 0) && - (boardp->reqcnt[scp->device->id] % 255) == 0) { - asc_scsi_q.q2.tag_code = MSG_ORDERED_TAG; - } else { - asc_scsi_q.q2.tag_code = MSG_SIMPLE_TAG; - } - - /* - * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather - * buffer command. - */ - if (scp->use_sg == 0) { - /* - * CDB request of single contiguous buffer. - */ - ASC_STATS(scp->device->host, cont_cnt); - scp->SCp.dma_handle = scp->request_bufflen ? - dma_map_single(dev, scp->request_buffer, - scp->request_bufflen, - scp->sc_data_direction) : 0; - asc_scsi_q.q1.data_addr = cpu_to_le32(scp->SCp.dma_handle); - asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen); - ASC_STATS_ADD(scp->device->host, cont_xfer, - ASC_CEILING(scp->request_bufflen, 512)); - asc_scsi_q.q1.sg_queue_cnt = 0; - asc_scsi_q.sg_head = NULL; - } else { - /* - * CDB scatter-gather request list. - */ - int sgcnt; - int use_sg; - struct scatterlist *slp; - - slp = (struct scatterlist *)scp->request_buffer; - use_sg = - dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction); - - if (use_sg > scp->device->host->sg_tablesize) { - ASC_PRINT3 - ("asc_build_req: board %d: use_sg %d > sg_tablesize %d\n", - boardp->id, use_sg, - scp->device->host->sg_tablesize); - dma_unmap_sg(dev, slp, scp->use_sg, - scp->sc_data_direction); - scp->result = HOST_BYTE(DID_ERROR); - asc_enqueue(&boardp->done, scp, ASC_BACK); - return ASC_ERROR; - } - - ASC_STATS(scp->device->host, sg_cnt); - - /* - * Use global ASC_SG_HEAD structure and set the ASC_SCSI_Q - * structure to point to it. - */ - memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD)); - - asc_scsi_q.q1.cntl |= QC_SG_HEAD; - asc_scsi_q.sg_head = &asc_sg_head; - asc_scsi_q.q1.data_cnt = 0; - asc_scsi_q.q1.data_addr = 0; - /* This is a byte value, otherwise it would need to be swapped. */ - asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = use_sg; - ASC_STATS_ADD(scp->device->host, sg_elem, - asc_sg_head.entry_cnt); - - /* - * Convert scatter-gather list into ASC_SG_HEAD list. - */ - for (sgcnt = 0; sgcnt < use_sg; sgcnt++, slp++) { - asc_sg_head.sg_list[sgcnt].addr = - cpu_to_le32(sg_dma_address(slp)); - asc_sg_head.sg_list[sgcnt].bytes = - cpu_to_le32(sg_dma_len(slp)); - ASC_STATS_ADD(scp->device->host, sg_xfer, - ASC_CEILING(sg_dma_len(slp), 512)); - } + printk("\n"); } - - ASC_DBG_PRT_ASC_SCSI_Q(2, &asc_scsi_q); - ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len); - - return ASC_NOERROR; } /* - * Build a request structure for the Adv Library (Wide Board). - * - * If an adv_req_t can not be allocated to issue the request, - * then return ASC_BUSY. If an error occurs, then return ASC_ERROR. - * - * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the - * microcode for DMA addresses or math operations are byte swapped - * to little-endian order. + * asc_prt_asc_scsi_q() */ -static int -adv_build_req(asc_board_t *boardp, struct scsi_cmnd *scp, - ADV_SCSI_REQ_Q **adv_scsiqpp) +static void asc_prt_asc_scsi_q(ASC_SCSI_Q *q) { - adv_req_t *reqp; - ADV_SCSI_REQ_Q *scsiqp; + ASC_SG_HEAD *sgp; int i; - int ret; - struct device *dev = boardp->dvc_cfg.adv_dvc_cfg.dev; - /* - * Allocate an adv_req_t structure from the board to execute - * the command. - */ - if (boardp->adv_reqp == NULL) { - ASC_DBG(1, "adv_build_req: no free adv_req_t\n"); - ASC_STATS(scp->device->host, adv_build_noreq); - return ASC_BUSY; - } else { - reqp = boardp->adv_reqp; - boardp->adv_reqp = reqp->next_reqp; - reqp->next_reqp = NULL; - } - - /* - * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers. - */ - scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q); - - /* - * Initialize the structure. - */ - scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0; - - /* - * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure. - */ - scsiqp->srb_ptr = ASC_VADDR_TO_U32(reqp); - - /* - * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure. - */ - reqp->cmndp = scp; - - /* - * Build the ADV_SCSI_REQ_Q request. - */ - - /* - * Set CDB length and copy it to the request structure. - * For wide boards a CDB length maximum of 16 bytes - * is supported. - */ - if (scp->cmd_len > ADV_MAX_CDB_LEN) { - ASC_PRINT3 - ("adv_build_req: board %d: cmd_len %d > ADV_MAX_CDB_LEN %d\n", - boardp->id, scp->cmd_len, ADV_MAX_CDB_LEN); - scp->result = HOST_BYTE(DID_ERROR); - asc_enqueue(&boardp->done, scp, ASC_BACK); - return ASC_ERROR; - } - scsiqp->cdb_len = scp->cmd_len; - /* Copy first 12 CDB bytes to cdb[]. */ - for (i = 0; i < scp->cmd_len && i < 12; i++) { - scsiqp->cdb[i] = scp->cmnd[i]; - } - /* Copy last 4 CDB bytes, if present, to cdb16[]. */ - for (; i < scp->cmd_len; i++) { - scsiqp->cdb16[i - 12] = scp->cmnd[i]; - } - - scsiqp->target_id = scp->device->id; - scsiqp->target_lun = scp->device->lun; - - scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0])); - scsiqp->sense_len = sizeof(scp->sense_buffer); - - /* - * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather - * buffer command. - */ - - scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen); - scsiqp->vdata_addr = scp->request_buffer; - scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer)); - - if (scp->use_sg == 0) { - /* - * CDB request of single contiguous buffer. - */ - reqp->sgblkp = NULL; - scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen); - if (scp->request_bufflen) { - scsiqp->vdata_addr = scp->request_buffer; - scp->SCp.dma_handle = - dma_map_single(dev, scp->request_buffer, - scp->request_bufflen, - scp->sc_data_direction); - } else { - scsiqp->vdata_addr = NULL; - scp->SCp.dma_handle = 0; - } - scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle); - scsiqp->sg_list_ptr = NULL; - scsiqp->sg_real_addr = 0; - ASC_STATS(scp->device->host, cont_cnt); - ASC_STATS_ADD(scp->device->host, cont_xfer, - ASC_CEILING(scp->request_bufflen, 512)); - } else { - /* - * CDB scatter-gather request list. - */ - struct scatterlist *slp; - int use_sg; - - slp = (struct scatterlist *)scp->request_buffer; - use_sg = - dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction); - - if (use_sg > ADV_MAX_SG_LIST) { - ASC_PRINT3 - ("adv_build_req: board %d: use_sg %d > ADV_MAX_SG_LIST %d\n", - boardp->id, use_sg, - scp->device->host->sg_tablesize); - dma_unmap_sg(dev, slp, scp->use_sg, - scp->sc_data_direction); - scp->result = HOST_BYTE(DID_ERROR); - asc_enqueue(&boardp->done, scp, ASC_BACK); + printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong)q); - /* - * Free the 'adv_req_t' structure by adding it back to the - * board free list. - */ - reqp->next_reqp = boardp->adv_reqp; - boardp->adv_reqp = reqp; + printk + (" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n", + q->q2.target_ix, q->q1.target_lun, (ulong)q->q2.srb_ptr, + q->q2.tag_code); - return ASC_ERROR; - } + printk + (" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n", + (ulong)le32_to_cpu(q->q1.data_addr), + (ulong)le32_to_cpu(q->q1.data_cnt), + (ulong)le32_to_cpu(q->q1.sense_addr), q->q1.sense_len); - if ((ret = - adv_get_sglist(boardp, reqp, scp, - use_sg)) != ADV_SUCCESS) { - /* - * Free the adv_req_t structure by adding it back to the - * board free list. - */ - reqp->next_reqp = boardp->adv_reqp; - boardp->adv_reqp = reqp; + printk(" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n", + (ulong)q->cdbptr, q->q2.cdb_len, + (ulong)q->sg_head, q->q1.sg_queue_cnt); - return ret; + if (q->sg_head) { + sgp = q->sg_head; + printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong)sgp); + printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt, + sgp->queue_cnt); + for (i = 0; i < sgp->entry_cnt; i++) { + printk(" [%u]: addr 0x%lx, bytes %lu\n", + i, (ulong)le32_to_cpu(sgp->sg_list[i].addr), + (ulong)le32_to_cpu(sgp->sg_list[i].bytes)); } - ASC_STATS(scp->device->host, sg_cnt); - ASC_STATS_ADD(scp->device->host, sg_elem, use_sg); } - - ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp); - ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len); - - *adv_scsiqpp = scsiqp; - - return ASC_NOERROR; } /* - * Build scatter-gather list for Adv Library (Wide Board). - * - * Additional ADV_SG_BLOCK structures will need to be allocated - * if the total number of scatter-gather elements exceeds - * NO_OF_SG_PER_BLOCK (15). The ADV_SG_BLOCK structures are - * assumed to be physically contiguous. - * - * Return: - * ADV_SUCCESS(1) - SG List successfully created - * ADV_ERROR(-1) - SG List creation failed + * asc_prt_asc_qdone_info() */ -static int -adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, struct scsi_cmnd *scp, - int use_sg) +static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *q) { - adv_sgblk_t *sgblkp; - ADV_SCSI_REQ_Q *scsiqp; - struct scatterlist *slp; - int sg_elem_cnt; - ADV_SG_BLOCK *sg_block, *prev_sg_block; - ADV_PADDR sg_block_paddr; - int i; - - scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q); - slp = (struct scatterlist *)scp->request_buffer; - sg_elem_cnt = use_sg; - prev_sg_block = NULL; - reqp->sgblkp = NULL; - - do { - /* - * Allocate a 'adv_sgblk_t' structure from the board free - * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK - * (15) scatter-gather elements. - */ - if ((sgblkp = boardp->adv_sgblkp) == NULL) { - ASC_DBG(1, "adv_get_sglist: no free adv_sgblk_t\n"); - ASC_STATS(scp->device->host, adv_build_nosg); - - /* - * Allocation failed. Free 'adv_sgblk_t' structures already - * allocated for the request. - */ - while ((sgblkp = reqp->sgblkp) != NULL) { - /* Remove 'sgblkp' from the request list. */ - reqp->sgblkp = sgblkp->next_sgblkp; - - /* Add 'sgblkp' to the board free list. */ - sgblkp->next_sgblkp = boardp->adv_sgblkp; - boardp->adv_sgblkp = sgblkp; - } - return ASC_BUSY; - } else { - /* Complete 'adv_sgblk_t' board allocation. */ - boardp->adv_sgblkp = sgblkp->next_sgblkp; - sgblkp->next_sgblkp = NULL; - - /* - * Get 8 byte aligned virtual and physical addresses for - * the allocated ADV_SG_BLOCK structure. - */ - sg_block = - (ADV_SG_BLOCK *)ADV_8BALIGN(&sgblkp->sg_block); - sg_block_paddr = virt_to_bus(sg_block); - - /* - * Check if this is the first 'adv_sgblk_t' for the request. - */ - if (reqp->sgblkp == NULL) { - /* Request's first scatter-gather block. */ - reqp->sgblkp = sgblkp; - - /* - * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical - * address pointers. - */ - scsiqp->sg_list_ptr = sg_block; - scsiqp->sg_real_addr = - cpu_to_le32(sg_block_paddr); - } else { - /* Request's second or later scatter-gather block. */ - sgblkp->next_sgblkp = reqp->sgblkp; - reqp->sgblkp = sgblkp; - - /* - * Point the previous ADV_SG_BLOCK structure to - * the newly allocated ADV_SG_BLOCK structure. - */ - ASC_ASSERT(prev_sg_block != NULL); - prev_sg_block->sg_ptr = - cpu_to_le32(sg_block_paddr); - } - } - - for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) { - sg_block->sg_list[i].sg_addr = - cpu_to_le32(sg_dma_address(slp)); - sg_block->sg_list[i].sg_count = - cpu_to_le32(sg_dma_len(slp)); - ASC_STATS_ADD(scp->device->host, sg_xfer, - ASC_CEILING(sg_dma_len(slp), 512)); - - if (--sg_elem_cnt == 0) { /* Last ADV_SG_BLOCK and scatter-gather entry. */ - sg_block->sg_cnt = i + 1; - sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */ - return ADV_SUCCESS; - } - slp++; - } - sg_block->sg_cnt = NO_OF_SG_PER_BLOCK; - prev_sg_block = sg_block; - } - while (1); - /* NOTREACHED */ + printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong)q); + printk(" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n", + (ulong)q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len, + q->d2.tag_code); + printk + (" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n", + q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg); } /* - * asc_isr_callback() - Second Level Interrupt Handler called by AscISR(). + * asc_prt_adv_sgblock() * - * Interrupt callback function for the Narrow SCSI Asc Library. + * Display an ADV_SG_BLOCK structure. */ -static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep) +static void asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b) { - asc_board_t *boardp; - struct scsi_cmnd *scp; - struct Scsi_Host *shost; int i; - ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp 0x%lx, qdonep 0x%lx\n", - (ulong)asc_dvc_varp, (ulong)qdonep); - ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep); - - /* - * Get the struct scsi_cmnd structure and Scsi_Host structure for the - * command that has been completed. - */ - scp = (struct scsi_cmnd *)ASC_U32_TO_VADDR(qdonep->d2.srb_ptr); - ASC_DBG1(1, "asc_isr_callback: scp 0x%lx\n", (ulong)scp); - - if (scp == NULL) { - ASC_PRINT("asc_isr_callback: scp is NULL\n"); - return; - } - ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len); - - /* - * If the request's host pointer is not valid, display a - * message and return. - */ - shost = scp->device->host; - for (i = 0; i < asc_board_count; i++) { - if (asc_host[i] == shost) { - break; - } - } - if (i == asc_board_count) { - ASC_PRINT2 - ("asc_isr_callback: scp 0x%lx has bad host pointer, host 0x%lx\n", - (ulong)scp, (ulong)shost); - return; - } - - ASC_STATS(shost, callback); - ASC_DBG1(1, "asc_isr_callback: shost 0x%lx\n", (ulong)shost); - - /* - * If the request isn't found on the active queue, it may - * have been removed to handle a reset request. - * Display a message and return. - */ - boardp = ASC_BOARDP(shost); - ASC_ASSERT(asc_dvc_varp == &boardp->dvc_var.asc_dvc_var); - if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) { - ASC_PRINT2 - ("asc_isr_callback: board %d: scp 0x%lx not on active queue\n", - boardp->id, (ulong)scp); - return; - } - - /* - * 'qdonep' contains the command's ending status. - */ - switch (qdonep->d3.done_stat) { - case QD_NO_ERROR: - ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n"); - scp->result = 0; - - /* - * If an INQUIRY command completed successfully, then call - * the AscInquiryHandling() function to set-up the device. - */ - if (scp->cmnd[0] == INQUIRY && scp->device->lun == 0 && - (scp->request_bufflen - qdonep->remain_bytes) >= 8) { - AscInquiryHandling(asc_dvc_varp, scp->device->id & 0x7, - (ASC_SCSI_INQUIRY *)scp-> - request_buffer); - } - - /* - * Check for an underrun condition. - * - * If there was no error and an underrun condition, then - * then return the number of underrun bytes. - */ - if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 && - qdonep->remain_bytes <= scp->request_bufflen) { - ASC_DBG1(1, - "asc_isr_callback: underrun condition %u bytes\n", - (unsigned)qdonep->remain_bytes); - scp->resid = qdonep->remain_bytes; - } - break; - - case QD_WITH_ERROR: - ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n"); - switch (qdonep->d3.host_stat) { - case QHSTA_NO_ERROR: - if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) { - ASC_DBG(2, - "asc_isr_callback: SAM_STAT_CHECK_CONDITION\n"); - ASC_DBG_PRT_SENSE(2, scp->sense_buffer, - sizeof(scp->sense_buffer)); - /* - * Note: The 'status_byte()' macro used by target drivers - * defined in scsi.h shifts the status byte returned by - * host drivers right by 1 bit. This is why target drivers - * also use right shifted status byte definitions. For - * instance target drivers use CHECK_CONDITION, defined to - * 0x1, instead of the SCSI defined check condition value - * of 0x2. Host drivers are supposed to return the status - * byte as it is defined by SCSI. - */ - scp->result = DRIVER_BYTE(DRIVER_SENSE) | - STATUS_BYTE(qdonep->d3.scsi_stat); - } else { - scp->result = STATUS_BYTE(qdonep->d3.scsi_stat); - } - break; - - default: - /* QHSTA error occurred */ - ASC_DBG1(1, "asc_isr_callback: host_stat 0x%x\n", - qdonep->d3.host_stat); - scp->result = HOST_BYTE(DID_BAD_TARGET); - break; - } - break; - - case QD_ABORTED_BY_HOST: - ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOST\n"); - scp->result = - HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3. - scsi_msg) | - STATUS_BYTE(qdonep->d3.scsi_stat); - break; - - default: - ASC_DBG1(1, "asc_isr_callback: done_stat 0x%x\n", - qdonep->d3.done_stat); - scp->result = - HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3. - scsi_msg) | - STATUS_BYTE(qdonep->d3.scsi_stat); - break; - } - - /* - * If the 'init_tidmask' bit isn't already set for the target and the - * current request finished normally, then set the bit for the target - * to indicate that a device is present. - */ - if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 && - qdonep->d3.done_stat == QD_NO_ERROR && - qdonep->d3.host_stat == QHSTA_NO_ERROR) { - boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id); + printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n", + (ulong)b, sgblockno); + printk(" sg_cnt %u, sg_ptr 0x%lx\n", + b->sg_cnt, (ulong)le32_to_cpu(b->sg_ptr)); + BUG_ON(b->sg_cnt > NO_OF_SG_PER_BLOCK); + if (b->sg_ptr != 0) + BUG_ON(b->sg_cnt != NO_OF_SG_PER_BLOCK); + for (i = 0; i < b->sg_cnt; i++) { + printk(" [%u]: sg_addr 0x%lx, sg_count 0x%lx\n", + i, (ulong)b->sg_list[i].sg_addr, + (ulong)b->sg_list[i].sg_count); } - - /* - * Because interrupts may be enabled by the 'struct scsi_cmnd' done - * function, add the command to the end of the board's done queue. - * The done function for the command will be called from - * advansys_interrupt(). - */ - asc_enqueue(&boardp->done, scp, ASC_BACK); - - return; } /* - * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR(). + * asc_prt_adv_scsi_req_q() * - * Callback function for the Wide SCSI Adv Library. + * Display an ADV_SCSI_REQ_Q structure. */ -static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp) +static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q) { - asc_board_t *boardp; - adv_req_t *reqp; - adv_sgblk_t *sgblkp; - struct scsi_cmnd *scp; - struct Scsi_Host *shost; - int i; - ADV_DCNT resid_cnt; - - ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp 0x%lx, scsiqp 0x%lx\n", - (ulong)adv_dvc_varp, (ulong)scsiqp); - ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp); + int sg_blk_cnt; + struct asc_sg_block *sg_ptr; - /* - * Get the adv_req_t structure for the command that has been - * completed. The adv_req_t structure actually contains the - * completed ADV_SCSI_REQ_Q structure. - */ - reqp = (adv_req_t *)ADV_U32_TO_VADDR(scsiqp->srb_ptr); - ASC_DBG1(1, "adv_isr_callback: reqp 0x%lx\n", (ulong)reqp); - if (reqp == NULL) { - ASC_PRINT("adv_isr_callback: reqp is NULL\n"); - return; - } + printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong)q); - /* - * Get the struct scsi_cmnd structure and Scsi_Host structure for the - * command that has been completed. - * - * Note: The adv_req_t request structure and adv_sgblk_t structure, - * if any, are dropped, because a board structure pointer can not be - * determined. - */ - scp = reqp->cmndp; - ASC_DBG1(1, "adv_isr_callback: scp 0x%lx\n", (ulong)scp); - if (scp == NULL) { - ASC_PRINT - ("adv_isr_callback: scp is NULL; adv_req_t dropped.\n"); - return; - } - ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len); + printk(" target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n", + q->target_id, q->target_lun, (ulong)q->srb_ptr, q->a_flag); - /* - * If the request's host pointer is not valid, display a message - * and return. - */ - shost = scp->device->host; - for (i = 0; i < asc_board_count; i++) { - if (asc_host[i] == shost) { - break; - } - } - /* - * Note: If the host structure is not found, the adv_req_t request - * structure and adv_sgblk_t structure, if any, is dropped. - */ - if (i == asc_board_count) { - ASC_PRINT2 - ("adv_isr_callback: scp 0x%lx has bad host pointer, host 0x%lx\n", - (ulong)scp, (ulong)shost); - return; - } + printk(" cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n", + q->cntl, (ulong)le32_to_cpu(q->data_addr), (ulong)q->vdata_addr); - ASC_STATS(shost, callback); - ASC_DBG1(1, "adv_isr_callback: shost 0x%lx\n", (ulong)shost); + printk(" data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n", + (ulong)le32_to_cpu(q->data_cnt), + (ulong)le32_to_cpu(q->sense_addr), q->sense_len); - /* - * If the request isn't found on the active queue, it may have been - * removed to handle a reset request. Display a message and return. - * - * Note: Because the structure may still be in use don't attempt - * to free the adv_req_t and adv_sgblk_t, if any, structures. - */ - boardp = ASC_BOARDP(shost); - ASC_ASSERT(adv_dvc_varp == &boardp->dvc_var.adv_dvc_var); - if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) { - ASC_PRINT2 - ("adv_isr_callback: board %d: scp 0x%lx not on active queue\n", - boardp->id, (ulong)scp); - return; - } + printk + (" cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n", + q->cdb_len, q->done_status, q->host_status, q->scsi_status); - /* - * 'done_status' contains the command's ending status. - */ - switch (scsiqp->done_status) { - case QD_NO_ERROR: - ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n"); - scp->result = 0; + printk(" sg_working_ix 0x%x, target_cmd %u\n", + q->sg_working_ix, q->target_cmd); - /* - * Check for an underrun condition. - * - * If there was no error and an underrun condition, then - * then return the number of underrun bytes. - */ - resid_cnt = le32_to_cpu(scsiqp->data_cnt); - if (scp->request_bufflen != 0 && resid_cnt != 0 && - resid_cnt <= scp->request_bufflen) { - ASC_DBG1(1, - "adv_isr_callback: underrun condition %lu bytes\n", - (ulong)resid_cnt); - scp->resid = resid_cnt; - } - break; + printk(" scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n", + (ulong)le32_to_cpu(q->scsiq_rptr), + (ulong)le32_to_cpu(q->sg_real_addr), (ulong)q->sg_list_ptr); - case QD_WITH_ERROR: - ASC_DBG(2, "adv_isr_callback: QD_WITH_ERROR\n"); - switch (scsiqp->host_status) { - case QHSTA_NO_ERROR: - if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) { - ASC_DBG(2, - "adv_isr_callback: SAM_STAT_CHECK_CONDITION\n"); - ASC_DBG_PRT_SENSE(2, scp->sense_buffer, - sizeof(scp->sense_buffer)); - /* - * Note: The 'status_byte()' macro used by target drivers - * defined in scsi.h shifts the status byte returned by - * host drivers right by 1 bit. This is why target drivers - * also use right shifted status byte definitions. For - * instance target drivers use CHECK_CONDITION, defined to - * 0x1, instead of the SCSI defined check condition value - * of 0x2. Host drivers are supposed to return the status - * byte as it is defined by SCSI. - */ - scp->result = DRIVER_BYTE(DRIVER_SENSE) | - STATUS_BYTE(scsiqp->scsi_status); - } else { - scp->result = STATUS_BYTE(scsiqp->scsi_status); + /* Display the request's ADV_SG_BLOCK structures. */ + if (q->sg_list_ptr != NULL) { + sg_blk_cnt = 0; + while (1) { + /* + * 'sg_ptr' is a physical address. Convert it to a virtual + * address by indexing 'sg_blk_cnt' into the virtual address + * array 'sg_list_ptr'. + * + * XXX - Assumes all SG physical blocks are virtually contiguous. + */ + sg_ptr = + &(((ADV_SG_BLOCK *)(q->sg_list_ptr))[sg_blk_cnt]); + asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr); + if (sg_ptr->sg_ptr == 0) { + break; } - break; - - default: - /* Some other QHSTA error occurred. */ - ASC_DBG1(1, "adv_isr_callback: host_status 0x%x\n", - scsiqp->host_status); - scp->result = HOST_BYTE(DID_BAD_TARGET); - break; + sg_blk_cnt++; } - break; - - case QD_ABORTED_BY_HOST: - ASC_DBG(1, "adv_isr_callback: QD_ABORTED_BY_HOST\n"); - scp->result = - HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status); - break; - - default: - ASC_DBG1(1, "adv_isr_callback: done_status 0x%x\n", - scsiqp->done_status); - scp->result = - HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status); - break; - } - - /* - * If the 'init_tidmask' bit isn't already set for the target and the - * current request finished normally, then set the bit for the target - * to indicate that a device is present. - */ - if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 && - scsiqp->done_status == QD_NO_ERROR && - scsiqp->host_status == QHSTA_NO_ERROR) { - boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id); - } - - /* - * Because interrupts may be enabled by the 'struct scsi_cmnd' done - * function, add the command to the end of the board's done queue. - * The done function for the command will be called from - * advansys_interrupt(). - */ - asc_enqueue(&boardp->done, scp, ASC_BACK); - - /* - * Free all 'adv_sgblk_t' structures allocated for the request. - */ - while ((sgblkp = reqp->sgblkp) != NULL) { - /* Remove 'sgblkp' from the request list. */ - reqp->sgblkp = sgblkp->next_sgblkp; - - /* Add 'sgblkp' to the board free list. */ - sgblkp->next_sgblkp = boardp->adv_sgblkp; - boardp->adv_sgblkp = sgblkp; } - - /* - * Free the adv_req_t structure used with the command by adding - * it back to the board free list. - */ - reqp->next_reqp = boardp->adv_reqp; - boardp->adv_reqp = reqp; - - ASC_DBG(1, "adv_isr_callback: done\n"); - - return; } +#endif /* ADVANSYS_DEBUG */ /* - * adv_async_callback() - Adv Library asynchronous event callback function. + * The advansys chip/microcode contains a 32-bit identifier for each command + * known as the 'srb'. I don't know what it stands for. The driver used + * to encode the scsi_cmnd pointer by calling virt_to_bus and retrieve it + * with bus_to_virt. Now the driver keeps a per-host map of integers to + * pointers. It auto-expands when full, unless it can't allocate memory. + * Note that an srb of 0 is treated specially by the chip/firmware, hence + * the return of i+1 in this routine, and the corresponding subtraction in + * the inverse routine. */ -static void adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code) +#define BAD_SRB 0 +static u32 advansys_ptr_to_srb(struct asc_dvc_var *asc_dvc, void *ptr) { - switch (code) { - case ADV_ASYNC_SCSI_BUS_RESET_DET: - /* - * The firmware detected a SCSI Bus reset. - */ - ASC_DBG(0, - "adv_async_callback: ADV_ASYNC_SCSI_BUS_RESET_DET\n"); - break; + int i; + void **new_ptr; - case ADV_ASYNC_RDMA_FAILURE: - /* - * Handle RDMA failure by resetting the SCSI Bus and - * possibly the chip if it is unresponsive. Log the error - * with a unique code. - */ - ASC_DBG(0, "adv_async_callback: ADV_ASYNC_RDMA_FAILURE\n"); - AdvResetChipAndSB(adv_dvc_varp); - break; + for (i = 0; i < asc_dvc->ptr_map_count; i++) { + if (!asc_dvc->ptr_map[i]) + goto out; + } - case ADV_HOST_SCSI_BUS_RESET: - /* - * Host generated SCSI bus reset occurred. - */ - ASC_DBG(0, "adv_async_callback: ADV_HOST_SCSI_BUS_RESET\n"); - break; + if (asc_dvc->ptr_map_count == 0) + asc_dvc->ptr_map_count = 1; + else + asc_dvc->ptr_map_count *= 2; - default: - ASC_DBG1(0, "DvcAsyncCallBack: unknown code 0x%x\n", code); - break; - } + new_ptr = krealloc(asc_dvc->ptr_map, + asc_dvc->ptr_map_count * sizeof(void *), GFP_ATOMIC); + if (!new_ptr) + return BAD_SRB; + asc_dvc->ptr_map = new_ptr; + out: + ASC_DBG(3, "Putting ptr %p into array offset %d\n", ptr, i); + asc_dvc->ptr_map[i] = ptr; + return i + 1; } -/* - * Add a 'REQP' to the end of specified queue. Set 'tidmask' - * to indicate a command is queued for the device. - * - * 'flag' may be either ASC_FRONT or ASC_BACK. - * - * 'REQPNEXT(reqp)' returns reqp's next pointer. - */ -static void asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag) +static void * advansys_srb_to_ptr(struct asc_dvc_var *asc_dvc, u32 srb) { - int tid; - - ASC_DBG3(3, "asc_enqueue: ascq 0x%lx, reqp 0x%lx, flag %d\n", - (ulong)ascq, (ulong)reqp, flag); - ASC_ASSERT(reqp != NULL); - ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK); - tid = REQPTID(reqp); - ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID); - if (flag == ASC_FRONT) { - reqp->host_scribble = (unsigned char *)ascq->q_first[tid]; - ascq->q_first[tid] = reqp; - /* If the queue was empty, set the last pointer. */ - if (ascq->q_last[tid] == NULL) { - ascq->q_last[tid] = reqp; - } - } else { /* ASC_BACK */ - if (ascq->q_last[tid] != NULL) { - ascq->q_last[tid]->host_scribble = - (unsigned char *)reqp; - } - ascq->q_last[tid] = reqp; - reqp->host_scribble = NULL; - /* If the queue was empty, set the first pointer. */ - if (ascq->q_first[tid] == NULL) { - ascq->q_first[tid] = reqp; - } - } - /* The queue has at least one entry, set its bit. */ - ascq->q_tidmask |= ADV_TID_TO_TIDMASK(tid); -#ifdef ADVANSYS_STATS - /* Maintain request queue statistics. */ - ascq->q_tot_cnt[tid]++; - ascq->q_cur_cnt[tid]++; - if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) { - ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid]; - ASC_DBG2(2, "asc_enqueue: new q_max_cnt[%d] %d\n", - tid, ascq->q_max_cnt[tid]); - } - REQPTIME(reqp) = REQTIMESTAMP(); -#endif /* ADVANSYS_STATS */ - ASC_DBG1(3, "asc_enqueue: reqp 0x%lx\n", (ulong)reqp); - return; -} + void *ptr; -/* - * Return first queued 'REQP' on the specified queue for - * the specified target device. Clear the 'tidmask' bit for - * the device if no more commands are left queued for it. - * - * 'REQPNEXT(reqp)' returns reqp's next pointer. - */ -static REQP asc_dequeue(asc_queue_t *ascq, int tid) -{ - REQP reqp; - - ASC_DBG2(3, "asc_dequeue: ascq 0x%lx, tid %d\n", (ulong)ascq, tid); - ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID); - if ((reqp = ascq->q_first[tid]) != NULL) { - ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)); - ascq->q_first[tid] = REQPNEXT(reqp); - /* If the queue is empty, clear its bit and the last pointer. */ - if (ascq->q_first[tid] == NULL) { - ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid); - ASC_ASSERT(ascq->q_last[tid] == reqp); - ascq->q_last[tid] = NULL; - } -#ifdef ADVANSYS_STATS - /* Maintain request queue statistics. */ - ascq->q_cur_cnt[tid]--; - ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0); - REQTIMESTAT("asc_dequeue", ascq, reqp, tid); -#endif /* ADVANSYS_STATS */ + srb--; + if (srb >= asc_dvc->ptr_map_count) { + printk("advansys: bad SRB %u, max %u\n", srb, + asc_dvc->ptr_map_count); + return NULL; } - ASC_DBG1(3, "asc_dequeue: reqp 0x%lx\n", (ulong)reqp); - return reqp; + ptr = asc_dvc->ptr_map[srb]; + asc_dvc->ptr_map[srb] = NULL; + ASC_DBG(3, "Returning ptr %p from array offset %d\n", ptr, srb); + return ptr; } /* - * Return a pointer to a singly linked list of all the requests queued - * for 'tid' on the 'asc_queue_t' pointed to by 'ascq'. - * - * If 'lastpp' is not NULL, '*lastpp' will be set to point to the - * the last request returned in the singly linked list. - * - * 'tid' should either be a valid target id or if it is ASC_TID_ALL, - * then all queued requests are concatenated into one list and - * returned. + * advansys_info() * - * Note: If 'lastpp' is used to append a new list to the end of - * an old list, only change the old list last pointer if '*lastpp' - * (or the function return value) is not NULL, i.e. use a temporary - * variable for 'lastpp' and check its value after the function return - * before assigning it to the list last pointer. + * Return suitable for printing on the console with the argument + * adapter's configuration information. * - * Unfortunately collecting queuing time statistics adds overhead to - * the function that isn't inherent to the function's algorithm. + * Note: The information line should not exceed ASC_INFO_SIZE bytes, + * otherwise the static 'info' array will be overrun. */ -static REQP asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid) +static const char *advansys_info(struct Scsi_Host *shost) { - REQP firstp, lastp; - int i; - - ASC_DBG2(3, "asc_dequeue_list: ascq 0x%lx, tid %d\n", (ulong)ascq, tid); - ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID)); + static char info[ASC_INFO_SIZE]; + struct asc_board *boardp = shost_priv(shost); + ASC_DVC_VAR *asc_dvc_varp; + ADV_DVC_VAR *adv_dvc_varp; + char *busname; + char *widename = NULL; - /* - * If 'tid' is not ASC_TID_ALL, return requests only for - * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all - * requests for all tids. - */ - if (tid != ASC_TID_ALL) { - /* Return all requests for the specified 'tid'. */ - if ((ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)) == 0) { - /* List is empty; Set first and last return pointers to NULL. */ - firstp = lastp = NULL; - } else { - firstp = ascq->q_first[tid]; - lastp = ascq->q_last[tid]; - ascq->q_first[tid] = ascq->q_last[tid] = NULL; - ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid); -#ifdef ADVANSYS_STATS - { - REQP reqp; - ascq->q_cur_cnt[tid] = 0; - for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) { - REQTIMESTAT("asc_dequeue_list", ascq, - reqp, tid); - } + if (ASC_NARROW_BOARD(boardp)) { + asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; + ASC_DBG(1, "begin\n"); + if (asc_dvc_varp->bus_type & ASC_IS_ISA) { + if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) == + ASC_IS_ISAPNP) { + busname = "ISA PnP"; + } else { + busname = "ISA"; } -#endif /* ADVANSYS_STATS */ - } - } else { - /* Return all requests for all tids. */ - firstp = lastp = NULL; - for (i = 0; i <= ADV_MAX_TID; i++) { - if (ascq->q_tidmask & ADV_TID_TO_TIDMASK(i)) { - if (firstp == NULL) { - firstp = ascq->q_first[i]; - lastp = ascq->q_last[i]; + sprintf(info, + "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X", + ASC_VERSION, busname, + (ulong)shost->io_port, + (ulong)shost->io_port + ASC_IOADR_GAP - 1, + boardp->irq, shost->dma_channel); + } else { + if (asc_dvc_varp->bus_type & ASC_IS_VL) { + busname = "VL"; + } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) { + busname = "EISA"; + } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) { + if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA) + == ASC_IS_PCI_ULTRA) { + busname = "PCI Ultra"; } else { - ASC_ASSERT(lastp != NULL); - lastp->host_scribble = - (unsigned char *)ascq->q_first[i]; - lastp = ascq->q_last[i]; + busname = "PCI"; } - ascq->q_first[i] = ascq->q_last[i] = NULL; - ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(i); -#ifdef ADVANSYS_STATS - ascq->q_cur_cnt[i] = 0; -#endif /* ADVANSYS_STATS */ - } - } -#ifdef ADVANSYS_STATS - { - REQP reqp; - for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) { - REQTIMESTAT("asc_dequeue_list", ascq, reqp, - reqp->device->id); + } else { + busname = "?"; + shost_printk(KERN_ERR, shost, "unknown bus " + "type %d\n", asc_dvc_varp->bus_type); } + sprintf(info, + "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X", + ASC_VERSION, busname, (ulong)shost->io_port, + (ulong)shost->io_port + ASC_IOADR_GAP - 1, + boardp->irq); } -#endif /* ADVANSYS_STATS */ - } - if (lastpp) { - *lastpp = lastp; - } - ASC_DBG1(3, "asc_dequeue_list: firstp 0x%lx\n", (ulong)firstp); - return firstp; -} - -/* - * Remove the specified 'REQP' from the specified queue for - * the specified target device. Clear the 'tidmask' bit for the - * device if no more commands are left queued for it. - * - * 'REQPNEXT(reqp)' returns reqp's the next pointer. - * - * Return ASC_TRUE if the command was found and removed, - * otherwise return ASC_FALSE. - */ -static int asc_rmqueue(asc_queue_t *ascq, REQP reqp) -{ - REQP currp, prevp; - int tid; - int ret = ASC_FALSE; - - ASC_DBG2(3, "asc_rmqueue: ascq 0x%lx, reqp 0x%lx\n", - (ulong)ascq, (ulong)reqp); - ASC_ASSERT(reqp != NULL); - - tid = REQPTID(reqp); - ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID); - - /* - * Handle the common case of 'reqp' being the first - * entry on the queue. - */ - if (reqp == ascq->q_first[tid]) { - ret = ASC_TRUE; - ascq->q_first[tid] = REQPNEXT(reqp); - /* If the queue is now empty, clear its bit and the last pointer. */ - if (ascq->q_first[tid] == NULL) { - ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid); - ASC_ASSERT(ascq->q_last[tid] == reqp); - ascq->q_last[tid] = NULL; - } - } else if (ascq->q_first[tid] != NULL) { - ASC_ASSERT(ascq->q_last[tid] != NULL); + } else { /* - * Because the case of 'reqp' being the first entry has been - * handled above and it is known the queue is not empty, if - * 'reqp' is found on the queue it is guaranteed the queue will - * not become empty and that 'q_first[tid]' will not be changed. + * Wide Adapter Information * - * Set 'prevp' to the first entry, 'currp' to the second entry, - * and search for 'reqp'. + * Memory-mapped I/O is used instead of I/O space to access + * the adapter, but display the I/O Port range. The Memory + * I/O address is displayed through the driver /proc file. */ - for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp); - currp; prevp = currp, currp = REQPNEXT(currp)) { - if (currp == reqp) { - ret = ASC_TRUE; - prevp->host_scribble = - (unsigned char *)REQPNEXT(currp); - reqp->host_scribble = NULL; - if (ascq->q_last[tid] == reqp) { - ascq->q_last[tid] = prevp; - } - break; - } + adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; + if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { + widename = "Ultra-Wide"; + } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { + widename = "Ultra2-Wide"; + } else { + widename = "Ultra3-Wide"; } + sprintf(info, + "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X", + ASC_VERSION, widename, (ulong)adv_dvc_varp->iop_base, + (ulong)adv_dvc_varp->iop_base + boardp->asc_n_io_port - 1, boardp->irq); } -#ifdef ADVANSYS_STATS - /* Maintain request queue statistics. */ - if (ret == ASC_TRUE) { - ascq->q_cur_cnt[tid]--; - REQTIMESTAT("asc_rmqueue", ascq, reqp, tid); - } - ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0); -#endif /* ADVANSYS_STATS */ - ASC_DBG2(3, "asc_rmqueue: reqp 0x%lx, ret %d\n", (ulong)reqp, ret); - return ret; + BUG_ON(strlen(info) >= ASC_INFO_SIZE); + ASC_DBG(1, "end\n"); + return info; } +#ifdef CONFIG_PROC_FS /* - * Execute as many queued requests as possible for the specified queue. + * asc_prt_line() + * + * If 'cp' is NULL print to the console, otherwise print to a buffer. * - * Calls asc_execute_scsi_cmnd() to execute a REQP/struct scsi_cmnd. + * Return 0 if printing to the console, otherwise return the number of + * bytes written to the buffer. + * + * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack + * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes. */ -static void asc_execute_queue(asc_queue_t *ascq) +static int asc_prt_line(char *buf, int buflen, char *fmt, ...) { - ADV_SCSI_BIT_ID_TYPE scan_tidmask; - REQP reqp; - int i; + va_list args; + int ret; + char s[ASC_PRTLINE_SIZE]; - ASC_DBG1(1, "asc_execute_queue: ascq 0x%lx\n", (ulong)ascq); - /* - * Execute queued commands for devices attached to - * the current board in round-robin fashion. - */ - scan_tidmask = ascq->q_tidmask; - do { - for (i = 0; i <= ADV_MAX_TID; i++) { - if (scan_tidmask & ADV_TID_TO_TIDMASK(i)) { - if ((reqp = asc_dequeue(ascq, i)) == NULL) { - scan_tidmask &= ~ADV_TID_TO_TIDMASK(i); - } else - if (asc_execute_scsi_cmnd - ((struct scsi_cmnd *)reqp) - == ASC_BUSY) { - scan_tidmask &= ~ADV_TID_TO_TIDMASK(i); - /* - * The request returned ASC_BUSY. Enqueue at the front of - * target's waiting list to maintain correct ordering. - */ - asc_enqueue(ascq, reqp, ASC_FRONT); - } - } - } - } while (scan_tidmask); - return; + va_start(args, fmt); + ret = vsprintf(s, fmt, args); + BUG_ON(ret >= ASC_PRTLINE_SIZE); + if (buf == NULL) { + (void)printk(s); + ret = 0; + } else { + ret = min(buflen, ret); + memcpy(buf, s, ret); + } + va_end(args); + return ret; } -#ifdef CONFIG_PROC_FS /* * asc_prt_board_devices() * @@ -6245,14 +2919,13 @@ static void asc_execute_queue(asc_queue_t *ascq) */ static int asc_prt_board_devices(struct Scsi_Host *shost, char *cp, int cplen) { - asc_board_t *boardp; + struct asc_board *boardp = shost_priv(shost); int leftlen; int totlen; int len; int chip_scsi_id; int i; - boardp = ASC_BOARDP(shost); leftlen = cplen; totlen = len = 0; @@ -6286,13 +2959,12 @@ static int asc_prt_board_devices(struct Scsi_Host *shost, char *cp, int cplen) */ static int asc_prt_adv_bios(struct Scsi_Host *shost, char *cp, int cplen) { - asc_board_t *boardp; + struct asc_board *boardp = shost_priv(shost); int leftlen; int totlen; int len; ushort major, minor, letter; - boardp = ASC_BOARDP(shost); leftlen = cplen; totlen = len = 0; @@ -6452,7 +3124,7 @@ static int asc_get_eeprom_string(ushort *serialnum, uchar *cp) */ static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen) { - asc_board_t *boardp; + struct asc_board *boardp = shost_priv(shost); ASC_DVC_VAR *asc_dvc_varp; int leftlen; int totlen; @@ -6464,7 +3136,6 @@ static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen #endif /* CONFIG_ISA */ uchar serialstr[13]; - boardp = ASC_BOARDP(shost); asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; ep = &boardp->eep_config.asc_eep; @@ -6586,7 +3257,7 @@ static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen */ static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen) { - asc_board_t *boardp; + struct asc_board *boardp = shost_priv(shost); ADV_DVC_VAR *adv_dvc_varp; int leftlen; int totlen; @@ -6601,7 +3272,6 @@ static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen ushort *wordp; ushort sdtr_speed = 0; - boardp = ASC_BOARDP(shost); adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { ep_3550 = &boardp->eep_config.adv_3550_eep; @@ -6873,14 +3543,12 @@ static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen */ static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen) { - asc_board_t *boardp; + struct asc_board *boardp = shost_priv(shost); int leftlen; int totlen; int len; int chip_scsi_id; - boardp = ASC_BOARDP(shost); - leftlen = cplen; totlen = len = 0; @@ -6912,10 +3580,7 @@ static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen) boardp->asc_n_io_port); ASC_PRT_NEXT(); - /* 'shost->n_io_port' may be truncated because it is only one byte. */ - len = asc_prt_line(cp, leftlen, - " io_port 0x%x, n_io_port 0x%x\n", - shost->io_port, shost->n_io_port); + len = asc_prt_line(cp, leftlen, " io_port 0x%x\n", shost->io_port); ASC_PRT_NEXT(); if (ASC_NARROW_BOARD(boardp)) { @@ -6940,7 +3605,7 @@ static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen) */ static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen) { - asc_board_t *boardp; + struct asc_board *boardp = shost_priv(shost); int chip_scsi_id; int leftlen; int totlen; @@ -6950,7 +3615,6 @@ static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen) int i; int renegotiate = 0; - boardp = ASC_BOARDP(shost); v = &boardp->dvc_var.asc_dvc_var; c = &boardp->dvc_cfg.asc_dvc_cfg; chip_scsi_id = c->chip_scsi_id; @@ -6963,15 +3627,10 @@ static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen) shost->host_no); ASC_PRT_NEXT(); - len = asc_prt_line(cp, leftlen, - " chip_version %u, lib_version 0x%x, lib_serial_no %u, mcode_date 0x%x\n", - c->chip_version, c->lib_version, c->lib_serial_no, - c->mcode_date); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, - " mcode_version 0x%x, err_code %u\n", - c->mcode_version, v->err_code); + len = asc_prt_line(cp, leftlen, " chip_version %u, mcode_date 0x%x, " + "mcode_version 0x%x, err_code %u\n", + c->chip_version, c->mcode_date, c->mcode_version, + v->err_code); ASC_PRT_NEXT(); /* Current number of commands waiting for the host. */ @@ -7128,7 +3787,7 @@ static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen) */ static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen) { - asc_board_t *boardp; + struct asc_board *boardp = shost_priv(shost); int leftlen; int totlen; int len; @@ -7145,7 +3804,6 @@ static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen) ushort period = 0; int renegotiate = 0; - boardp = ASC_BOARDP(shost); v = &boardp->dvc_var.adv_dvc_var; c = &boardp->dvc_cfg.adv_dvc_cfg; iop_base = v->iop_base; @@ -7167,10 +3825,9 @@ static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen) v->err_code); ASC_PRT_NEXT(); - len = asc_prt_line(cp, leftlen, - " chip_version %u, lib_version 0x%x, mcode_date 0x%x, mcode_version 0x%x\n", - c->chip_version, c->lib_version, c->mcode_date, - c->mcode_version); + len = asc_prt_line(cp, leftlen, " chip_version %u, mcode_date 0x%x, " + "mcode_version 0x%x\n", c->chip_version, + c->mcode_date, c->mcode_version); ASC_PRT_NEXT(); AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); @@ -7376,12 +4033,12 @@ asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen, { int cnt = 0; - ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n", + ASC_DBG(2, "offset %d, advoffset %d, cplen %d\n", (unsigned)offset, (unsigned)advoffset, cplen); if (offset <= advoffset) { /* Read offset below current offset, copy everything. */ cnt = min(cplen, leftlen); - ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n", + ASC_DBG(2, "curbuf 0x%lx, cp 0x%lx, cnt %d\n", (ulong)curbuf, (ulong)cp, cnt); memcpy(curbuf, cp, cnt); } else if (offset < advoffset + cplen) { @@ -7389,1125 +4046,4537 @@ asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen, cnt = (advoffset + cplen) - offset; cp = (cp + cplen) - cnt; cnt = min(cnt, leftlen); - ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n", + ASC_DBG(2, "curbuf 0x%lx, cp 0x%lx, cnt %d\n", (ulong)curbuf, (ulong)cp, cnt); memcpy(curbuf, cp, cnt); } return cnt; } +#ifdef ADVANSYS_STATS /* - * asc_prt_line() + * asc_prt_board_stats() * - * If 'cp' is NULL print to the console, otherwise print to a buffer. + * Note: no single line should be greater than ASC_PRTLINE_SIZE, + * cf. asc_prt_line(). * - * Return 0 if printing to the console, otherwise return the number of - * bytes written to the buffer. + * Return the number of characters copied into 'cp'. No more than + * 'cplen' characters will be copied to 'cp'. + */ +static int asc_prt_board_stats(struct Scsi_Host *shost, char *cp, int cplen) +{ + struct asc_board *boardp = shost_priv(shost); + struct asc_stats *s = &boardp->asc_stats; + + int leftlen = cplen; + int len, totlen = 0; + + len = asc_prt_line(cp, leftlen, + "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n", + shost->host_no); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, + " queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n", + s->queuecommand, s->reset, s->biosparam, + s->interrupt); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, + " callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n", + s->callback, s->done, s->build_error, + s->adv_build_noreq, s->adv_build_nosg); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, + " exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n", + s->exe_noerror, s->exe_busy, s->exe_error, + s->exe_unknown); + ASC_PRT_NEXT(); + + /* + * Display data transfer statistics. + */ + if (s->xfer_cnt > 0) { + len = asc_prt_line(cp, leftlen, " xfer_cnt %lu, xfer_elem %lu, ", + s->xfer_cnt, s->xfer_elem); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, "xfer_bytes %lu.%01lu kb\n", + s->xfer_sect / 2, ASC_TENTHS(s->xfer_sect, 2)); + ASC_PRT_NEXT(); + + /* Scatter gather transfer statistics */ + len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ", + s->xfer_elem / s->xfer_cnt, + ASC_TENTHS(s->xfer_elem, s->xfer_cnt)); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ", + (s->xfer_sect / 2) / s->xfer_elem, + ASC_TENTHS((s->xfer_sect / 2), s->xfer_elem)); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n", + (s->xfer_sect / 2) / s->xfer_cnt, + ASC_TENTHS((s->xfer_sect / 2), s->xfer_cnt)); + ASC_PRT_NEXT(); + } + + return totlen; +} +#endif /* ADVANSYS_STATS */ + +/* + * advansys_proc_info() - /proc/scsi/advansys/{0,1,2,3,...} * - * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack - * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes. + * *buffer: I/O buffer + * **start: if inout == FALSE pointer into buffer where user read should start + * offset: current offset into a /proc/scsi/advansys/[0...] file + * length: length of buffer + * hostno: Scsi_Host host_no + * inout: TRUE - user is writing; FALSE - user is reading + * + * Return the number of bytes read from or written to a + * /proc/scsi/advansys/[0...] file. + * + * Note: This function uses the per board buffer 'prtbuf' which is + * allocated when the board is initialized in advansys_detect(). The + * buffer is ASC_PRTBUF_SIZE bytes. The function asc_proc_copy() is + * used to write to the buffer. The way asc_proc_copy() is written + * if 'prtbuf' is too small it will not be overwritten. Instead the + * user just won't get all the available statistics. */ -static int asc_prt_line(char *buf, int buflen, char *fmt, ...) +static int +advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start, + off_t offset, int length, int inout) { - va_list args; - int ret; - char s[ASC_PRTLINE_SIZE]; + struct asc_board *boardp = shost_priv(shost); + char *cp; + int cplen; + int cnt; + int totcnt; + int leftlen; + char *curbuf; + off_t advoffset; - va_start(args, fmt); - ret = vsprintf(s, fmt, args); - ASC_ASSERT(ret < ASC_PRTLINE_SIZE); - if (buf == NULL) { - (void)printk(s); - ret = 0; + ASC_DBG(1, "begin\n"); + + /* + * User write not supported. + */ + if (inout == TRUE) + return -ENOSYS; + + /* + * User read of /proc/scsi/advansys/[0...] file. + */ + + /* Copy read data starting at the beginning of the buffer. */ + *start = buffer; + curbuf = buffer; + advoffset = 0; + totcnt = 0; + leftlen = length; + + /* + * Get board configuration information. + * + * advansys_info() returns the board string from its own static buffer. + */ + cp = (char *)advansys_info(shost); + strcat(cp, "\n"); + cplen = strlen(cp); + /* Copy board information. */ + cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); + totcnt += cnt; + leftlen -= cnt; + if (leftlen == 0) { + ASC_DBG(1, "totcnt %d\n", totcnt); + return totcnt; + } + advoffset += cplen; + curbuf += cnt; + + /* + * Display Wide Board BIOS Information. + */ + if (!ASC_NARROW_BOARD(boardp)) { + cp = boardp->prtbuf; + cplen = asc_prt_adv_bios(shost, cp, ASC_PRTBUF_SIZE); + BUG_ON(cplen >= ASC_PRTBUF_SIZE); + cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, + cplen); + totcnt += cnt; + leftlen -= cnt; + if (leftlen == 0) { + ASC_DBG(1, "totcnt %d\n", totcnt); + return totcnt; + } + advoffset += cplen; + curbuf += cnt; + } + + /* + * Display driver information for each device attached to the board. + */ + cp = boardp->prtbuf; + cplen = asc_prt_board_devices(shost, cp, ASC_PRTBUF_SIZE); + BUG_ON(cplen >= ASC_PRTBUF_SIZE); + cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); + totcnt += cnt; + leftlen -= cnt; + if (leftlen == 0) { + ASC_DBG(1, "totcnt %d\n", totcnt); + return totcnt; + } + advoffset += cplen; + curbuf += cnt; + + /* + * Display EEPROM configuration for the board. + */ + cp = boardp->prtbuf; + if (ASC_NARROW_BOARD(boardp)) { + cplen = asc_prt_asc_board_eeprom(shost, cp, ASC_PRTBUF_SIZE); } else { - ret = min(buflen, ret); - memcpy(buf, s, ret); + cplen = asc_prt_adv_board_eeprom(shost, cp, ASC_PRTBUF_SIZE); } - va_end(args); - return ret; + BUG_ON(cplen >= ASC_PRTBUF_SIZE); + cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); + totcnt += cnt; + leftlen -= cnt; + if (leftlen == 0) { + ASC_DBG(1, "totcnt %d\n", totcnt); + return totcnt; + } + advoffset += cplen; + curbuf += cnt; + + /* + * Display driver configuration and information for the board. + */ + cp = boardp->prtbuf; + cplen = asc_prt_driver_conf(shost, cp, ASC_PRTBUF_SIZE); + BUG_ON(cplen >= ASC_PRTBUF_SIZE); + cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); + totcnt += cnt; + leftlen -= cnt; + if (leftlen == 0) { + ASC_DBG(1, "totcnt %d\n", totcnt); + return totcnt; + } + advoffset += cplen; + curbuf += cnt; + +#ifdef ADVANSYS_STATS + /* + * Display driver statistics for the board. + */ + cp = boardp->prtbuf; + cplen = asc_prt_board_stats(shost, cp, ASC_PRTBUF_SIZE); + BUG_ON(cplen >= ASC_PRTBUF_SIZE); + cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); + totcnt += cnt; + leftlen -= cnt; + if (leftlen == 0) { + ASC_DBG(1, "totcnt %d\n", totcnt); + return totcnt; + } + advoffset += cplen; + curbuf += cnt; +#endif /* ADVANSYS_STATS */ + + /* + * Display Asc Library dynamic configuration information + * for the board. + */ + cp = boardp->prtbuf; + if (ASC_NARROW_BOARD(boardp)) { + cplen = asc_prt_asc_board_info(shost, cp, ASC_PRTBUF_SIZE); + } else { + cplen = asc_prt_adv_board_info(shost, cp, ASC_PRTBUF_SIZE); + } + BUG_ON(cplen >= ASC_PRTBUF_SIZE); + cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); + totcnt += cnt; + leftlen -= cnt; + if (leftlen == 0) { + ASC_DBG(1, "totcnt %d\n", totcnt); + return totcnt; + } + advoffset += cplen; + curbuf += cnt; + + ASC_DBG(1, "totcnt %d\n", totcnt); + + return totcnt; } #endif /* CONFIG_PROC_FS */ -/* - * --- Functions Required by the Asc Library - */ +static void asc_scsi_done(struct scsi_cmnd *scp) +{ + scsi_dma_unmap(scp); + ASC_STATS(scp->device->host, done); + scp->scsi_done(scp); +} -/* - * Delay for 'n' milliseconds. Don't use the 'jiffies' - * global variable which is incremented once every 5 ms - * from a timer interrupt, because this function may be - * called when interrupts are disabled. - */ -static void DvcSleepMilliSecond(ADV_DCNT n) +static void AscSetBank(PortAddr iop_base, uchar bank) { - ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", (ulong)n); - mdelay(n); + uchar val; + + val = AscGetChipControl(iop_base) & + (~ + (CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET | + CC_CHIP_RESET)); + if (bank == 1) { + val |= CC_BANK_ONE; + } else if (bank == 2) { + val |= CC_DIAG | CC_BANK_ONE; + } else { + val &= ~CC_BANK_ONE; + } + AscSetChipControl(iop_base, val); } -/* - * Currently and inline noop but leave as a placeholder. - * Leave DvcEnterCritical() as a noop placeholder. - */ -static inline ulong DvcEnterCritical(void) +static void AscSetChipIH(PortAddr iop_base, ushort ins_code) { - return 0; + AscSetBank(iop_base, 1); + AscWriteChipIH(iop_base, ins_code); + AscSetBank(iop_base, 0); } -/* - * Critical sections are all protected by the board spinlock. - * Leave DvcLeaveCritical() as a noop placeholder. - */ -static inline void DvcLeaveCritical(ulong flags) +static int AscStartChip(PortAddr iop_base) +{ + AscSetChipControl(iop_base, 0); + if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) { + return (0); + } + return (1); +} + +static int AscStopChip(PortAddr iop_base) +{ + uchar cc_val; + + cc_val = + AscGetChipControl(iop_base) & + (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG)); + AscSetChipControl(iop_base, (uchar)(cc_val | CC_HALT)); + AscSetChipIH(iop_base, INS_HALT); + AscSetChipIH(iop_base, INS_RFLAG_WTM); + if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) { + return (0); + } + return (1); +} + +static int AscIsChipHalted(PortAddr iop_base) +{ + if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) { + if ((AscGetChipControl(iop_base) & CC_HALT) != 0) { + return (1); + } + } + return (0); +} + +static int AscResetChipAndScsiBus(ASC_DVC_VAR *asc_dvc) +{ + PortAddr iop_base; + int i = 10; + + iop_base = asc_dvc->iop_base; + while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) + && (i-- > 0)) { + mdelay(100); + } + AscStopChip(iop_base); + AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT); + udelay(60); + AscSetChipIH(iop_base, INS_RFLAG_WTM); + AscSetChipIH(iop_base, INS_HALT); + AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT); + AscSetChipControl(iop_base, CC_HALT); + mdelay(200); + AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT); + AscSetChipStatus(iop_base, 0); + return (AscIsChipHalted(iop_base)); +} + +static int AscFindSignature(PortAddr iop_base) +{ + ushort sig_word; + + ASC_DBG(1, "AscGetChipSignatureByte(0x%x) 0x%x\n", + iop_base, AscGetChipSignatureByte(iop_base)); + if (AscGetChipSignatureByte(iop_base) == (uchar)ASC_1000_ID1B) { + ASC_DBG(1, "AscGetChipSignatureWord(0x%x) 0x%x\n", + iop_base, AscGetChipSignatureWord(iop_base)); + sig_word = AscGetChipSignatureWord(iop_base); + if ((sig_word == (ushort)ASC_1000_ID0W) || + (sig_word == (ushort)ASC_1000_ID0W_FIX)) { + return (1); + } + } + return (0); +} + +static void AscEnableInterrupt(PortAddr iop_base) +{ + ushort cfg; + + cfg = AscGetChipCfgLsw(iop_base); + AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON); +} + +static void AscDisableInterrupt(PortAddr iop_base) +{ + ushort cfg; + + cfg = AscGetChipCfgLsw(iop_base); + AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON)); +} + +static uchar AscReadLramByte(PortAddr iop_base, ushort addr) +{ + unsigned char byte_data; + unsigned short word_data; + + if (isodd_word(addr)) { + AscSetChipLramAddr(iop_base, addr - 1); + word_data = AscGetChipLramData(iop_base); + byte_data = (word_data >> 8) & 0xFF; + } else { + AscSetChipLramAddr(iop_base, addr); + word_data = AscGetChipLramData(iop_base); + byte_data = word_data & 0xFF; + } + return byte_data; +} + +static ushort AscReadLramWord(PortAddr iop_base, ushort addr) +{ + ushort word_data; + + AscSetChipLramAddr(iop_base, addr); + word_data = AscGetChipLramData(iop_base); + return (word_data); +} + +#if CC_VERY_LONG_SG_LIST +static ASC_DCNT AscReadLramDWord(PortAddr iop_base, ushort addr) +{ + ushort val_low, val_high; + ASC_DCNT dword_data; + + AscSetChipLramAddr(iop_base, addr); + val_low = AscGetChipLramData(iop_base); + val_high = AscGetChipLramData(iop_base); + dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low; + return (dword_data); +} +#endif /* CC_VERY_LONG_SG_LIST */ + +static void +AscMemWordSetLram(PortAddr iop_base, ushort s_addr, ushort set_wval, int words) +{ + int i; + + AscSetChipLramAddr(iop_base, s_addr); + for (i = 0; i < words; i++) { + AscSetChipLramData(iop_base, set_wval); + } +} + +static void AscWriteLramWord(PortAddr iop_base, ushort addr, ushort word_val) +{ + AscSetChipLramAddr(iop_base, addr); + AscSetChipLramData(iop_base, word_val); +} + +static void AscWriteLramByte(PortAddr iop_base, ushort addr, uchar byte_val) { - return; + ushort word_data; + + if (isodd_word(addr)) { + addr--; + word_data = AscReadLramWord(iop_base, addr); + word_data &= 0x00FF; + word_data |= (((ushort)byte_val << 8) & 0xFF00); + } else { + word_data = AscReadLramWord(iop_base, addr); + word_data &= 0xFF00; + word_data |= ((ushort)byte_val & 0x00FF); + } + AscWriteLramWord(iop_base, addr, word_data); } /* - * void - * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words) - * - * Calling/Exit State: - * none + * Copy 2 bytes to LRAM. * - * Description: - * Output an ASC_SCSI_Q structure to the chip + * The source data is assumed to be in little-endian order in memory + * and is maintained in little-endian order when written to LRAM. */ static void -DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words) +AscMemWordCopyPtrToLram(PortAddr iop_base, + ushort s_addr, uchar *s_buffer, int words) { int i; - ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words); AscSetChipLramAddr(iop_base, s_addr); for (i = 0; i < 2 * words; i += 2) { - if (i == 4 || i == 20) { - continue; - } + /* + * On a little-endian system the second argument below + * produces a little-endian ushort which is written to + * LRAM in little-endian order. On a big-endian system + * the second argument produces a big-endian ushort which + * is "transparently" byte-swapped by outpw() and written + * in little-endian order to LRAM. + */ outpw(iop_base + IOP_RAM_DATA, - ((ushort)outbuf[i + 1] << 8) | outbuf[i]); + ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]); } } /* - * void - * DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words) + * Copy 4 bytes to LRAM. * - * Calling/Exit State: - * none + * The source data is assumed to be in little-endian order in memory + * and is maintained in little-endian order when writen to LRAM. + */ +static void +AscMemDWordCopyPtrToLram(PortAddr iop_base, + ushort s_addr, uchar *s_buffer, int dwords) +{ + int i; + + AscSetChipLramAddr(iop_base, s_addr); + for (i = 0; i < 4 * dwords; i += 4) { + outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]); /* LSW */ + outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 3] << 8) | s_buffer[i + 2]); /* MSW */ + } +} + +/* + * Copy 2 bytes from LRAM. * - * Description: - * Input an ASC_QDONE_INFO structure from the chip + * The source data is assumed to be in little-endian order in LRAM + * and is maintained in little-endian order when written to memory. */ static void -DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words) +AscMemWordCopyPtrFromLram(PortAddr iop_base, + ushort s_addr, uchar *d_buffer, int words) { int i; ushort word; AscSetChipLramAddr(iop_base, s_addr); for (i = 0; i < 2 * words; i += 2) { - if (i == 10) { - continue; - } word = inpw(iop_base + IOP_RAM_DATA); - inbuf[i] = word & 0xff; - inbuf[i + 1] = (word >> 8) & 0xff; + d_buffer[i] = word & 0xff; + d_buffer[i + 1] = (word >> 8) & 0xff; } - ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words); } -/* - * Read a PCI configuration byte. - */ -static uchar __init DvcReadPCIConfigByte(ASC_DVC_VAR *asc_dvc, ushort offset) +static ASC_DCNT AscMemSumLramWord(PortAddr iop_base, ushort s_addr, int words) { -#ifdef CONFIG_PCI - uchar byte_data; - pci_read_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, &byte_data); - return byte_data; -#else /* !defined(CONFIG_PCI) */ - return 0; -#endif /* !defined(CONFIG_PCI) */ + ASC_DCNT sum; + int i; + + sum = 0L; + for (i = 0; i < words; i++, s_addr += 2) { + sum += AscReadLramWord(iop_base, s_addr); + } + return (sum); } -/* - * Write a PCI configuration byte. - */ -static void __init -DvcWritePCIConfigByte(ASC_DVC_VAR *asc_dvc, ushort offset, uchar byte_data) +static ushort AscInitLram(ASC_DVC_VAR *asc_dvc) { -#ifdef CONFIG_PCI - pci_write_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, byte_data); -#endif /* CONFIG_PCI */ + uchar i; + ushort s_addr; + PortAddr iop_base; + ushort warn_code; + + iop_base = asc_dvc->iop_base; + warn_code = 0; + AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0, + (ushort)(((int)(asc_dvc->max_total_qng + 2 + 1) * + 64) >> 1)); + i = ASC_MIN_ACTIVE_QNO; + s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE; + AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD), + (uchar)(i + 1)); + AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD), + (uchar)(asc_dvc->max_total_qng)); + AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO), + (uchar)i); + i++; + s_addr += ASC_QBLK_SIZE; + for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) { + AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD), + (uchar)(i + 1)); + AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD), + (uchar)(i - 1)); + AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO), + (uchar)i); + } + AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD), + (uchar)ASC_QLINK_END); + AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD), + (uchar)(asc_dvc->max_total_qng - 1)); + AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO), + (uchar)asc_dvc->max_total_qng); + i++; + s_addr += ASC_QBLK_SIZE; + for (; i <= (uchar)(asc_dvc->max_total_qng + 3); + i++, s_addr += ASC_QBLK_SIZE) { + AscWriteLramByte(iop_base, + (ushort)(s_addr + (ushort)ASC_SCSIQ_B_FWD), i); + AscWriteLramByte(iop_base, + (ushort)(s_addr + (ushort)ASC_SCSIQ_B_BWD), i); + AscWriteLramByte(iop_base, + (ushort)(s_addr + (ushort)ASC_SCSIQ_B_QNO), i); + } + return warn_code; } -/* - * Return the BIOS address of the adapter at the specified - * I/O port and with the specified bus type. - */ -static ushort __init AscGetChipBiosAddress(PortAddr iop_base, ushort bus_type) +static ASC_DCNT +AscLoadMicroCode(PortAddr iop_base, + ushort s_addr, uchar *mcode_buf, ushort mcode_size) { - ushort cfg_lsw; - ushort bios_addr; + ASC_DCNT chksum; + ushort mcode_word_size; + ushort mcode_chksum; - /* - * The PCI BIOS is re-located by the motherboard BIOS. Because - * of this the driver can not determine where a PCI BIOS is - * loaded and executes. - */ - if (bus_type & ASC_IS_PCI) { - return (0); + /* Write the microcode buffer starting at LRAM address 0. */ + mcode_word_size = (ushort)(mcode_size >> 1); + AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size); + AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size); + + chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size); + ASC_DBG(1, "chksum 0x%lx\n", (ulong)chksum); + mcode_chksum = (ushort)AscMemSumLramWord(iop_base, + (ushort)ASC_CODE_SEC_BEG, + (ushort)((mcode_size - + s_addr - (ushort) + ASC_CODE_SEC_BEG) / + 2)); + ASC_DBG(1, "mcode_chksum 0x%lx\n", (ulong)mcode_chksum); + AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum); + AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size); + return chksum; +} + +/* Microcode buffer is kept after initialization for error recovery. */ +static uchar _asc_mcode_buf[] = { + 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x12, 0x0D, 0x05, + 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xE4, 0x88, 0x00, 0x00, 0x00, 0x00, 0x80, 0x73, 0x48, 0x04, + 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73, 0x03, 0x23, 0x36, 0x40, + 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2, + 0xC2, 0x00, 0x92, 0x80, 0x1E, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x48, 0x98, + 0xDF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, 0x4F, 0x00, 0xF5, 0x00, + 0x48, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, 0x80, 0x62, + 0x92, 0x80, 0x00, 0x46, 0x15, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8, + 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xD6, 0x00, 0xA6, 0x97, 0x7F, 0x23, + 0x04, 0x61, 0x84, 0x01, 0xE6, 0x84, 0xD2, 0xC1, 0x80, 0x73, 0xCD, 0x04, + 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x01, 0xA6, 0x97, 0xC6, 0x81, 0xC2, 0x88, + 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0xFE, 0x00, 0x4F, 0x00, + 0x84, 0x97, 0x07, 0xA6, 0x08, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88, + 0x03, 0x03, 0x01, 0xDE, 0xC2, 0x88, 0xCE, 0x00, 0x69, 0x60, 0xCE, 0x00, + 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x78, 0x01, 0x80, 0x63, 0x07, 0xA6, + 0x24, 0x01, 0x78, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6, + 0x34, 0x01, 0x00, 0x33, 0x04, 0x00, 0xC2, 0x88, 0x03, 0x07, 0x02, 0x01, + 0x04, 0xCA, 0x0D, 0x23, 0x68, 0x98, 0x4D, 0x04, 0x04, 0x85, 0x05, 0xD8, + 0x0D, 0x23, 0x68, 0x98, 0xCD, 0x04, 0x15, 0x23, 0xF8, 0x88, 0xFB, 0x23, + 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x62, 0x01, + 0x00, 0x33, 0x0A, 0x00, 0xC2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x6E, 0x01, + 0x00, 0x33, 0x0B, 0x00, 0xC2, 0x88, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, + 0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x88, 0x81, 0x06, 0xAB, 0x82, 0x01, + 0x88, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x92, 0x01, 0x50, 0x00, 0x00, 0xA3, + 0x3C, 0x01, 0x00, 0x05, 0x7C, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6, + 0x04, 0x23, 0xA0, 0x01, 0x15, 0x23, 0xA1, 0x01, 0xBE, 0x81, 0xFD, 0x23, + 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, + 0xB4, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00, + 0xC2, 0x88, 0x06, 0x23, 0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01, + 0x00, 0xA2, 0xD4, 0x01, 0x57, 0x60, 0x00, 0xA0, 0xDA, 0x01, 0xE6, 0x84, + 0x80, 0x23, 0xA0, 0x01, 0xE6, 0x84, 0x80, 0x73, 0x4B, 0x00, 0x06, 0x61, + 0x00, 0xA2, 0x00, 0x02, 0x04, 0x01, 0x0C, 0xDE, 0x02, 0x01, 0x03, 0xCC, + 0x4F, 0x00, 0x84, 0x97, 0xFC, 0x81, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, + 0x4F, 0x00, 0x62, 0x97, 0x48, 0x04, 0x84, 0x80, 0xF0, 0x97, 0x00, 0x46, + 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00, 0x81, 0x73, 0x06, 0x29, + 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x6B, 0xEB, 0x11, 0x23, 0xF8, 0x88, + 0x04, 0x98, 0xF0, 0x80, 0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x2A, 0x02, + 0x7C, 0x95, 0x06, 0xA6, 0x34, 0x02, 0x03, 0xA6, 0x4C, 0x04, 0x46, 0x82, + 0x04, 0x01, 0x03, 0xD8, 0xB4, 0x98, 0x6A, 0x96, 0x46, 0x82, 0xFE, 0x95, + 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x6C, 0x02, + 0x07, 0xA6, 0x5A, 0x02, 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x62, 0x02, + 0xC2, 0x88, 0x7C, 0x95, 0x48, 0x82, 0x60, 0x96, 0x48, 0x82, 0x04, 0x23, + 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84, 0x04, 0x01, 0x0C, 0xDC, + 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01, + 0x6F, 0x00, 0xA5, 0x01, 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01, + 0x24, 0x2B, 0x1C, 0x01, 0x02, 0xA6, 0xAA, 0x02, 0x07, 0xA6, 0x5A, 0x02, + 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x20, 0x04, 0x01, 0xA6, 0xB4, 0x02, + 0x00, 0xA6, 0xB4, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E, + 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0x8C, 0x02, 0x4D, 0x04, 0x04, 0x01, + 0x0B, 0xDC, 0xE7, 0x23, 0x04, 0x61, 0x84, 0x01, 0x10, 0x31, 0x12, 0x35, + 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0xEA, 0x82, + 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0xA2, 0xC8, + 0x00, 0x33, 0x1F, 0x00, 0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, + 0x0E, 0x3D, 0x7E, 0x98, 0xB6, 0x2D, 0x01, 0xA6, 0x14, 0x03, 0x00, 0xA6, + 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6, 0x10, 0x03, 0x03, 0xA6, + 0x20, 0x04, 0x02, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88, + 0x7C, 0x95, 0xEE, 0x82, 0x60, 0x96, 0xEE, 0x82, 0x82, 0x98, 0x80, 0x42, + 0x7E, 0x98, 0x64, 0xE4, 0x04, 0x01, 0x2D, 0xC8, 0x31, 0x05, 0x07, 0x01, + 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01, 0x05, 0x05, 0x86, 0x98, + 0x7E, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6, + 0x3C, 0x04, 0x06, 0xA6, 0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33, + 0x25, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x32, 0x83, 0x60, 0x96, 0x32, 0x83, + 0x04, 0x01, 0x10, 0xCE, 0x07, 0xC8, 0x05, 0x05, 0xEB, 0x04, 0x00, 0x33, + 0x00, 0x20, 0xC0, 0x20, 0x81, 0x62, 0x72, 0x83, 0x00, 0x01, 0x05, 0x05, + 0xFF, 0xA2, 0x7A, 0x03, 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83, + 0x05, 0x05, 0x15, 0x01, 0x00, 0xA2, 0x9A, 0x03, 0xEC, 0x00, 0x6E, 0x00, + 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0x01, 0xA6, 0x96, 0x03, + 0x00, 0xA6, 0x96, 0x03, 0x10, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6, + 0xA4, 0x03, 0x00, 0xA6, 0xBC, 0x03, 0x10, 0x84, 0xA8, 0x98, 0x80, 0x42, + 0x01, 0xA6, 0xA4, 0x03, 0x07, 0xA6, 0xB2, 0x03, 0xD4, 0x83, 0x7C, 0x95, + 0xA8, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC2, 0x88, 0xA8, 0x98, 0x80, 0x42, + 0x00, 0xA6, 0xBC, 0x03, 0x07, 0xA6, 0xCA, 0x03, 0xD4, 0x83, 0x7C, 0x95, + 0xC0, 0x83, 0x00, 0x33, 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32, + 0x80, 0x36, 0x04, 0x23, 0xA0, 0x01, 0x12, 0x23, 0xA1, 0x01, 0x10, 0x84, + 0x07, 0xF0, 0x06, 0xA4, 0xF4, 0x03, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23, + 0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x0E, 0x04, 0x07, 0xA6, 0x06, 0x04, + 0x06, 0xA6, 0x0A, 0x04, 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x7C, 0x95, + 0xF4, 0x83, 0x60, 0x96, 0xF4, 0x83, 0x20, 0x84, 0x07, 0xF0, 0x06, 0xA4, + 0x20, 0x04, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23, 0x83, 0x03, 0x80, 0x63, + 0xB6, 0x2D, 0x03, 0xA6, 0x3C, 0x04, 0x07, 0xA6, 0x34, 0x04, 0x06, 0xA6, + 0x38, 0x04, 0x00, 0x33, 0x30, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x20, 0x84, + 0x60, 0x96, 0x20, 0x84, 0x1D, 0x01, 0x06, 0xCC, 0x00, 0x33, 0x00, 0x84, + 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62, 0xA2, 0x0D, 0x80, 0x63, + 0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03, + 0x80, 0x63, 0xA3, 0x01, 0x07, 0xA4, 0x64, 0x04, 0x23, 0x01, 0x00, 0xA2, + 0x86, 0x04, 0x0A, 0xA0, 0x76, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1D, 0x00, + 0xC2, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1E, 0x00, + 0xC2, 0x88, 0x42, 0x23, 0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04, + 0x08, 0x23, 0x22, 0xA3, 0xA2, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xAE, 0x04, + 0x02, 0x23, 0x22, 0xA3, 0xC4, 0x04, 0x42, 0x23, 0xF8, 0x88, 0x4A, 0x00, + 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23, 0xF8, 0x88, 0x04, 0x98, + 0x00, 0xA2, 0xC0, 0x04, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20, + 0x81, 0x62, 0xE8, 0x81, 0x47, 0x23, 0xF8, 0x88, 0x04, 0x01, 0x0B, 0xDE, + 0x04, 0x98, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x81, 0xC0, 0x20, 0x81, 0x62, + 0x14, 0x01, 0x00, 0xA0, 0x00, 0x02, 0x43, 0x23, 0xF8, 0x88, 0x04, 0x23, + 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3, + 0xF4, 0x04, 0x00, 0x33, 0x27, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x04, 0xDC, + 0x02, 0x23, 0xA2, 0x01, 0x04, 0x23, 0xA0, 0x01, 0x04, 0x98, 0x26, 0x95, + 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00, 0x00, 0xA3, 0x22, 0x05, + 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x1C, 0x05, 0x0A, 0x85, + 0x46, 0x97, 0xCD, 0x04, 0x24, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01, + 0x03, 0xDA, 0x80, 0x23, 0x82, 0x01, 0x34, 0x85, 0x02, 0x23, 0xA0, 0x01, + 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x40, 0x05, 0x1D, 0x01, 0x04, 0xD6, + 0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01, + 0x49, 0x00, 0x81, 0x01, 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01, + 0xF7, 0x04, 0x03, 0x01, 0x49, 0x04, 0x80, 0x01, 0xC9, 0x00, 0x00, 0x05, + 0x00, 0x01, 0xFF, 0xA0, 0x60, 0x05, 0x77, 0x04, 0x01, 0x23, 0xEA, 0x00, + 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63, + 0x07, 0xA4, 0xF8, 0x05, 0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85, + 0x00, 0x33, 0x2D, 0x00, 0xC2, 0x88, 0x04, 0xA0, 0xB8, 0x05, 0x80, 0x63, + 0x00, 0x23, 0xDF, 0x00, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0xA4, 0x05, + 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00, + 0x62, 0x97, 0x04, 0x85, 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0x04, 0x85, + 0x08, 0xA0, 0xBE, 0x05, 0xF4, 0x85, 0x03, 0xA0, 0xC4, 0x05, 0xF4, 0x85, + 0x01, 0xA0, 0xCE, 0x05, 0x88, 0x00, 0x80, 0x63, 0xCC, 0x86, 0x07, 0xA0, + 0xEE, 0x05, 0x5F, 0x00, 0x00, 0x2B, 0xDF, 0x08, 0x00, 0xA2, 0xE6, 0x05, + 0x80, 0x67, 0x80, 0x63, 0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23, + 0x68, 0x98, 0x48, 0x23, 0xF8, 0x88, 0x07, 0x23, 0x80, 0x00, 0x06, 0x87, + 0x80, 0x63, 0x7C, 0x85, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63, 0x4A, 0x00, + 0x06, 0x61, 0x00, 0xA2, 0x36, 0x06, 0x1D, 0x01, 0x16, 0xD4, 0xC0, 0x23, + 0x07, 0x41, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33, + 0x37, 0x00, 0xC2, 0x88, 0x1D, 0x01, 0x01, 0xD6, 0x20, 0x23, 0x63, 0x60, + 0x83, 0x03, 0x80, 0x63, 0x02, 0x23, 0xDF, 0x00, 0x07, 0xA6, 0x7C, 0x05, + 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00, + 0x52, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x4E, 0x06, 0x1D, 0x01, 0x03, 0xCA, + 0xC0, 0x23, 0x07, 0x41, 0x00, 0x63, 0x1D, 0x01, 0x04, 0xCC, 0x00, 0x33, + 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23, 0x07, 0x41, 0x00, 0x63, + 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x01, 0x23, + 0xDF, 0x00, 0x06, 0xA6, 0x84, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, + 0x80, 0x63, 0x00, 0x33, 0x00, 0x40, 0xC0, 0x20, 0x81, 0x62, 0x00, 0x63, + 0x00, 0x00, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x94, 0x06, + 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x00, 0x01, 0xA0, 0x14, 0x07, 0x00, 0x2B, + 0x40, 0x0E, 0x80, 0x63, 0x01, 0x00, 0x06, 0xA6, 0xAA, 0x06, 0x07, 0xA6, + 0x7C, 0x05, 0x40, 0x0E, 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0xA2, 0x06, + 0x06, 0xA6, 0xBC, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x40, 0x0E, + 0x80, 0x63, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63, + 0x07, 0xA6, 0xD6, 0x06, 0x00, 0x33, 0x2A, 0x00, 0xC2, 0x88, 0x03, 0x03, + 0x80, 0x63, 0x89, 0x00, 0x0A, 0x2B, 0x07, 0xA6, 0xE8, 0x06, 0x00, 0x33, + 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, 0x00, 0xA2, 0xF4, 0x06, 0xC0, 0x0E, + 0x80, 0x63, 0xDE, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20, + 0x81, 0x62, 0x04, 0x01, 0x02, 0xDA, 0x80, 0x63, 0x7C, 0x85, 0x80, 0x7B, + 0x80, 0x63, 0x06, 0xA6, 0x8C, 0x06, 0x00, 0x33, 0x2C, 0x00, 0xC2, 0x88, + 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, + 0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88, + 0x00, 0x00, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x44, 0x07, + 0x07, 0xA6, 0x7C, 0x05, 0xBF, 0x23, 0x04, 0x61, 0x84, 0x01, 0xE6, 0x84, + 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x00, 0x01, 0xF2, 0x00, + 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04, + 0x80, 0x05, 0x81, 0x05, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, + 0x01, 0x01, 0xF1, 0x00, 0x70, 0x00, 0x81, 0x01, 0x70, 0x04, 0x71, 0x00, + 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04, 0x70, 0x00, 0x80, 0x01, + 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01, + 0xF1, 0x00, 0x70, 0x00, 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01, + 0x72, 0x00, 0x81, 0x01, 0x71, 0x04, 0x70, 0x00, 0x81, 0x01, 0x70, 0x04, + 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05, 0xA3, 0x01, 0xA2, 0x01, + 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1, + 0xC4, 0x07, 0x00, 0x33, 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05, + 0x04, 0x01, 0x11, 0xC8, 0x48, 0x00, 0xB0, 0x01, 0xB1, 0x01, 0x08, 0x23, + 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43, 0x00, 0xA2, 0xE4, 0x07, + 0x00, 0x05, 0xDA, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01, + 0x05, 0x05, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, + 0x00, 0x02, 0x80, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04, 0x00, 0x63, + 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x00, 0xA0, + 0x14, 0x08, 0x16, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04, + 0x00, 0x63, 0xF3, 0x04, 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43, + 0xF4, 0x00, 0xCF, 0x40, 0x00, 0xA2, 0x44, 0x08, 0x74, 0x04, 0x02, 0x01, + 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1, 0x24, 0x08, 0x04, 0x98, + 0x26, 0x95, 0x24, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04, + 0x5A, 0x88, 0x02, 0x01, 0x04, 0xD8, 0x46, 0x97, 0x04, 0x98, 0x26, 0x95, + 0x4A, 0x88, 0x75, 0x00, 0x00, 0xA3, 0x64, 0x08, 0x00, 0x05, 0x4E, 0x88, + 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x76, 0x08, + 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, + 0x00, 0x63, 0x38, 0x2B, 0x9C, 0x88, 0x38, 0x2B, 0x92, 0x88, 0x32, 0x09, + 0x31, 0x05, 0x92, 0x98, 0x05, 0x05, 0xB2, 0x09, 0x00, 0x63, 0x00, 0x32, + 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63, 0x80, 0x32, 0x80, 0x36, + 0x80, 0x3A, 0x80, 0x3E, 0xB4, 0x3D, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32, + 0x40, 0x36, 0x40, 0x3A, 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, + 0x00, 0xA0, 0xB4, 0x08, 0x5D, 0x00, 0xFE, 0xC3, 0x00, 0x63, 0x80, 0x73, + 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73, 0xFF, 0xFD, 0x80, 0x73, + 0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01, + 0xA1, 0x23, 0xA1, 0x01, 0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77, + 0x68, 0x00, 0x00, 0xA2, 0x80, 0x00, 0x03, 0xC2, 0xF1, 0xC7, 0x41, 0x23, + 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xE6, 0x84, +}; + +static unsigned short _asc_mcode_size = sizeof(_asc_mcode_buf); +static ADV_DCNT _asc_mcode_chksum = 0x012C453FUL; + +/* Microcode buffer is kept after initialization for error recovery. */ +static unsigned char _adv_asc3550_buf[] = { + 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x18, 0xe4, 0x00, 0xfc, + 0x01, 0x00, 0x48, 0xe4, 0xbe, 0x18, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, + 0x00, 0xfa, 0xff, 0xff, 0x28, 0x0e, 0x9e, 0xe7, 0xff, 0x00, 0x82, 0xe7, + 0x00, 0xea, 0x00, 0xf6, 0x01, 0xe6, 0x09, 0xe7, 0x55, 0xf0, 0x01, 0xf6, + 0x01, 0xfa, 0x08, 0x00, 0x03, 0x00, 0x04, 0x00, 0x18, 0xf4, 0x10, 0x00, + 0x00, 0xec, 0x85, 0xf0, 0xbc, 0x00, 0xd5, 0xf0, 0x8e, 0x0c, 0x38, 0x54, + 0x00, 0xe6, 0x1e, 0xf0, 0x86, 0xf0, 0xb4, 0x00, 0x98, 0x57, 0xd0, 0x01, + 0x0c, 0x1c, 0x3e, 0x1c, 0x0c, 0x00, 0xbb, 0x00, 0xaa, 0x18, 0x02, 0x80, + 0x32, 0xf0, 0x01, 0xfc, 0x88, 0x0c, 0xc6, 0x12, 0x02, 0x13, 0x18, 0x40, + 0x00, 0x57, 0x01, 0xea, 0x3c, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12, + 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00, 0xc0, 0x00, 0x01, 0x01, + 0x3e, 0x01, 0xda, 0x0f, 0x22, 0x10, 0x08, 0x12, 0x02, 0x4a, 0xb9, 0x54, + 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x20, 0x00, 0x32, 0x00, + 0x3e, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, + 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01, 0x78, 0x01, 0x62, 0x0a, + 0x92, 0x0c, 0x2c, 0x10, 0x2e, 0x10, 0x06, 0x13, 0x4c, 0x1c, 0xbb, 0x55, + 0x3c, 0x56, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0xb1, 0xf0, + 0x03, 0xf7, 0x06, 0xf7, 0x03, 0xfc, 0x0f, 0x00, 0x40, 0x00, 0xbe, 0x00, + 0x00, 0x01, 0xb0, 0x08, 0x30, 0x13, 0x64, 0x15, 0x32, 0x1c, 0x38, 0x1c, + 0x4e, 0x1c, 0x10, 0x44, 0x02, 0x48, 0x00, 0x4c, 0x04, 0xea, 0x5d, 0xf0, + 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00, + 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x4e, 0x0b, 0x1e, 0x0e, 0x0c, 0x10, + 0x0a, 0x12, 0x04, 0x13, 0x40, 0x13, 0x30, 0x1c, 0x00, 0x4e, 0xbd, 0x56, + 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0, 0x59, 0xf0, 0xa7, 0xf0, + 0xb8, 0xf0, 0x0e, 0xf7, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00, + 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, + 0xde, 0x03, 0x56, 0x0a, 0x14, 0x0e, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, + 0x36, 0x10, 0x0a, 0x13, 0x12, 0x13, 0x52, 0x13, 0x10, 0x15, 0x14, 0x15, + 0xac, 0x16, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44, + 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x83, 0x55, + 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0, 0x0c, 0xf0, + 0x5c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, + 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x1c, 0x00, + 0x9e, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, + 0x26, 0x01, 0x79, 0x01, 0x7a, 0x01, 0xc0, 0x01, 0xc2, 0x01, 0x7c, 0x02, + 0x5a, 0x03, 0xea, 0x04, 0xe8, 0x07, 0x68, 0x08, 0x69, 0x08, 0xba, 0x08, + 0xe9, 0x09, 0x06, 0x0b, 0x3a, 0x0e, 0x00, 0x10, 0x1a, 0x10, 0xed, 0x10, + 0xf1, 0x10, 0x06, 0x12, 0x0c, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x82, 0x13, + 0x42, 0x14, 0xd6, 0x14, 0x8a, 0x15, 0xc6, 0x17, 0xd2, 0x17, 0x6b, 0x18, + 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0x48, 0x47, + 0x41, 0x48, 0x89, 0x48, 0x80, 0x4c, 0x00, 0x54, 0x44, 0x55, 0xe5, 0x55, + 0x14, 0x56, 0x77, 0x57, 0xbf, 0x57, 0x40, 0x5c, 0x06, 0x80, 0x08, 0x90, + 0x03, 0xa1, 0xfe, 0x9c, 0xf0, 0x29, 0x02, 0xfe, 0xb8, 0x0c, 0xff, 0x10, + 0x00, 0x00, 0xd0, 0xfe, 0xcc, 0x18, 0x00, 0xcf, 0xfe, 0x80, 0x01, 0xff, + 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00, + 0x00, 0xfe, 0x57, 0x24, 0x00, 0xfe, 0x48, 0x00, 0x4f, 0xff, 0x04, 0x00, + 0x00, 0x10, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x08, + 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x0f, + 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00, + 0xfe, 0x04, 0xf7, 0xcf, 0x2a, 0x67, 0x0b, 0x01, 0xfe, 0xce, 0x0e, 0xfe, + 0x04, 0xf7, 0xcf, 0x67, 0x0b, 0x3c, 0x2a, 0xfe, 0x3d, 0xf0, 0xfe, 0x02, + 0x02, 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x91, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, + 0x90, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, 0x8f, 0xf0, 0x9c, 0x05, 0x51, 0x3b, + 0x02, 0xfe, 0xd4, 0x0c, 0x01, 0xfe, 0x44, 0x0d, 0xfe, 0xdd, 0x12, 0xfe, + 0xfc, 0x10, 0xfe, 0x28, 0x1c, 0x05, 0xfe, 0xa6, 0x00, 0xfe, 0xd3, 0x12, + 0x47, 0x18, 0xfe, 0xa6, 0x00, 0xb5, 0xfe, 0x48, 0xf0, 0xfe, 0x86, 0x02, + 0xfe, 0x49, 0xf0, 0xfe, 0xa0, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xbe, 0x02, + 0xfe, 0x46, 0xf0, 0xfe, 0x50, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x56, 0x02, + 0xfe, 0x43, 0xf0, 0xfe, 0x44, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x48, 0x02, + 0xfe, 0x45, 0xf0, 0xfe, 0x4c, 0x02, 0x17, 0x0b, 0xa0, 0x17, 0x06, 0x18, + 0x96, 0x02, 0x29, 0xfe, 0x00, 0x1c, 0xde, 0xfe, 0x02, 0x1c, 0xdd, 0xfe, + 0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0xfe, 0x20, 0x17, 0xfe, 0xe7, 0x10, + 0xfe, 0x06, 0xfc, 0xc7, 0x0a, 0x6b, 0x01, 0x9e, 0x02, 0x29, 0x14, 0x4d, + 0x37, 0x97, 0x01, 0xfe, 0x64, 0x0f, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xbd, + 0x10, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe, + 0x58, 0x1c, 0x17, 0x06, 0x18, 0x96, 0x2a, 0x25, 0x29, 0xfe, 0x3d, 0xf0, + 0xfe, 0x02, 0x02, 0x21, 0xfe, 0x94, 0x02, 0xfe, 0x5a, 0x1c, 0xea, 0xfe, + 0x14, 0x1c, 0x14, 0xfe, 0x30, 0x00, 0x37, 0x97, 0x01, 0xfe, 0x54, 0x0f, + 0x17, 0x06, 0x18, 0x96, 0x02, 0xd0, 0x1e, 0x20, 0x07, 0x10, 0x34, 0xfe, + 0x69, 0x10, 0x17, 0x06, 0x18, 0x96, 0xfe, 0x04, 0xec, 0x20, 0x46, 0x3d, + 0x12, 0x20, 0xfe, 0x05, 0xf6, 0xc7, 0x01, 0xfe, 0x52, 0x16, 0x09, 0x4a, + 0x4c, 0x35, 0x11, 0x2d, 0x3c, 0x8a, 0x01, 0xe6, 0x02, 0x29, 0x0a, 0x40, + 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x01, 0x6f, 0xfe, 0x18, 0x10, 0xfe, 0x41, + 0x58, 0x0a, 0x99, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x64, 0xfe, 0x0c, 0x03, + 0x01, 0xe6, 0x02, 0x29, 0x2a, 0x46, 0xfe, 0x02, 0xe8, 0x27, 0xf8, 0xfe, + 0x9e, 0x43, 0xf7, 0xfe, 0x27, 0xf0, 0xfe, 0xdc, 0x01, 0xfe, 0x07, 0x4b, + 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x40, 0x1c, 0x25, 0xd2, 0xfe, 0x26, 0xf0, + 0xfe, 0x56, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x44, 0x03, 0xfe, 0x11, 0xf0, + 0x9c, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x64, 0x03, 0xeb, 0x0f, + 0xfe, 0x11, 0x00, 0x02, 0x5a, 0x2a, 0xfe, 0x48, 0x1c, 0xeb, 0x09, 0x04, + 0x1d, 0xfe, 0x18, 0x13, 0x23, 0x1e, 0x98, 0xac, 0x12, 0x98, 0x0a, 0x40, + 0x01, 0x0e, 0xac, 0x75, 0x01, 0xfe, 0xbc, 0x15, 0x11, 0xca, 0x25, 0xd2, + 0xfe, 0x01, 0xf0, 0xd2, 0xfe, 0x82, 0xf0, 0xfe, 0x92, 0x03, 0xec, 0x11, + 0xfe, 0xe4, 0x00, 0x65, 0xfe, 0xa4, 0x03, 0x25, 0x32, 0x1f, 0xfe, 0xb4, + 0x03, 0x01, 0x43, 0xfe, 0x06, 0xf0, 0xfe, 0xc4, 0x03, 0x8d, 0x81, 0xfe, + 0x0a, 0xf0, 0xfe, 0x7a, 0x06, 0x02, 0x22, 0x05, 0x6b, 0x28, 0x16, 0xfe, + 0xf6, 0x04, 0x14, 0x2c, 0x01, 0x33, 0x8f, 0xfe, 0x66, 0x02, 0x02, 0xd1, + 0xeb, 0x2a, 0x67, 0x1a, 0xfe, 0x67, 0x1b, 0xf8, 0xf7, 0xfe, 0x48, 0x1c, + 0x70, 0x01, 0x6e, 0x87, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x16, 0xd3, + 0x0a, 0xca, 0x01, 0x0e, 0x74, 0x60, 0x59, 0x76, 0x27, 0x05, 0x6b, 0x28, + 0xfe, 0x10, 0x12, 0x14, 0x2c, 0x01, 0x33, 0x8f, 0xfe, 0x66, 0x02, 0x02, + 0xd1, 0xbc, 0x7d, 0xbd, 0x7f, 0x25, 0x22, 0x65, 0xfe, 0x3c, 0x04, 0x1f, + 0xfe, 0x38, 0x04, 0x68, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e, + 0x12, 0x2b, 0xff, 0x02, 0x00, 0x10, 0x01, 0x08, 0x1f, 0xfe, 0xe0, 0x04, + 0x2b, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd5, 0xfe, 0x4c, 0x44, 0xfe, + 0x4c, 0x12, 0x60, 0xfe, 0x44, 0x48, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64, + 0xd3, 0x46, 0x76, 0x27, 0xfa, 0xef, 0xfe, 0x62, 0x13, 0x09, 0x04, 0x1d, + 0xfe, 0x2a, 0x13, 0x2f, 0x07, 0x7e, 0xa5, 0xfe, 0x20, 0x10, 0x13, 0x2c, + 0xfe, 0x4c, 0x54, 0x64, 0xd3, 0xfa, 0xef, 0x86, 0x09, 0x04, 0x1d, 0xfe, + 0x08, 0x13, 0x2f, 0x07, 0x7e, 0x6e, 0x09, 0x04, 0x1d, 0xfe, 0x1c, 0x12, + 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, + 0x70, 0x0c, 0x02, 0x22, 0x2b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90, + 0xf9, 0x03, 0x14, 0x92, 0x01, 0x33, 0x02, 0x29, 0xfe, 0x42, 0x5b, 0x67, + 0x1a, 0xfe, 0x46, 0x59, 0xf8, 0xf7, 0xfe, 0x87, 0x80, 0xfe, 0x31, 0xe4, + 0x4f, 0x09, 0x04, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x1a, + 0xfe, 0x70, 0x12, 0x49, 0x04, 0x06, 0xfe, 0x60, 0x13, 0x05, 0xfe, 0xa2, + 0x00, 0x28, 0x16, 0xfe, 0x80, 0x05, 0xfe, 0x31, 0xe4, 0x6a, 0x49, 0x04, + 0x0b, 0xfe, 0x4a, 0x13, 0x05, 0xfe, 0xa0, 0x00, 0x28, 0xfe, 0x42, 0x12, + 0x5e, 0x01, 0x08, 0x25, 0x32, 0xf1, 0x01, 0x08, 0x26, 0xfe, 0x98, 0x05, + 0x11, 0xfe, 0xe3, 0x00, 0x23, 0x49, 0xfe, 0x4a, 0xf0, 0xfe, 0x6a, 0x05, + 0xfe, 0x49, 0xf0, 0xfe, 0x64, 0x05, 0x83, 0x24, 0xfe, 0x21, 0x00, 0xa1, + 0x24, 0xfe, 0x22, 0x00, 0xa0, 0x24, 0x4c, 0xfe, 0x09, 0x48, 0x01, 0x08, + 0x26, 0xfe, 0x98, 0x05, 0xfe, 0xe2, 0x08, 0x49, 0x04, 0xc5, 0x3b, 0x01, + 0x86, 0x24, 0x06, 0x12, 0xcc, 0x37, 0xfe, 0x27, 0x01, 0x09, 0x04, 0x1d, + 0xfe, 0x22, 0x12, 0x47, 0x01, 0xa7, 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, + 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c, 0x02, 0x22, 0x05, 0xfe, + 0x9c, 0x00, 0x28, 0xfe, 0x3e, 0x12, 0x05, 0x50, 0x28, 0xfe, 0x36, 0x13, + 0x47, 0x01, 0xa7, 0x26, 0xfe, 0x08, 0x06, 0x0a, 0x06, 0x49, 0x04, 0x19, + 0xfe, 0x02, 0x12, 0x5f, 0x01, 0xfe, 0xaa, 0x14, 0x1f, 0xfe, 0xfe, 0x05, + 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x50, 0xb4, 0x0c, + 0x50, 0x05, 0xc6, 0x28, 0xfe, 0x62, 0x12, 0x05, 0x3f, 0x28, 0xfe, 0x5a, + 0x13, 0x01, 0xfe, 0x14, 0x18, 0x01, 0xfe, 0x66, 0x18, 0xfe, 0x43, 0x48, + 0xb7, 0x19, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0x1c, 0x3d, + 0x85, 0xb7, 0x69, 0x47, 0x01, 0xa7, 0x26, 0xfe, 0x72, 0x06, 0x49, 0x04, + 0x1b, 0xdf, 0x89, 0x0a, 0x4d, 0x01, 0xfe, 0xd8, 0x14, 0x1f, 0xfe, 0x68, + 0x06, 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x3f, 0xb4, + 0x0c, 0x3f, 0x17, 0x06, 0x01, 0xa7, 0xec, 0x72, 0x70, 0x01, 0x6e, 0x87, + 0x11, 0xfe, 0xe2, 0x00, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0, 0xfe, + 0xa6, 0x06, 0x8c, 0xfe, 0x5c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, 0x64, 0x07, + 0x8d, 0x81, 0x02, 0x22, 0x09, 0x04, 0x0b, 0xfe, 0x2e, 0x12, 0x15, 0x1a, + 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, + 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x15, 0x00, 0x02, 0xfe, 0x32, + 0x08, 0x61, 0x04, 0x1b, 0xfe, 0x38, 0x12, 0x09, 0x04, 0x1b, 0x6e, 0x15, + 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, + 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x06, 0x01, 0x08, 0x15, 0x00, 0x02, + 0xd9, 0x66, 0x4c, 0xfe, 0x3a, 0x55, 0x5f, 0xfe, 0x9a, 0x81, 0x4b, 0x1d, + 0xba, 0xfe, 0x32, 0x07, 0x0a, 0x1d, 0xfe, 0x09, 0x6f, 0xaf, 0xfe, 0xca, + 0x45, 0xfe, 0x32, 0x12, 0x62, 0x2c, 0x85, 0x66, 0x7b, 0x01, 0x08, 0x25, + 0x32, 0xfe, 0x0a, 0xf0, 0xfe, 0x32, 0x07, 0x8d, 0x81, 0x8c, 0xfe, 0x5c, + 0x07, 0x02, 0x22, 0x01, 0x43, 0x02, 0xfe, 0x8a, 0x06, 0x15, 0x19, 0x02, + 0xfe, 0x8a, 0x06, 0xfe, 0x9c, 0xf7, 0xd4, 0xfe, 0x2c, 0x90, 0xfe, 0xae, + 0x90, 0x77, 0xfe, 0xca, 0x07, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x4a, 0x6a, + 0x35, 0x1e, 0x20, 0x07, 0x10, 0xfe, 0x0e, 0x12, 0x74, 0xfe, 0x80, 0x80, + 0x37, 0x20, 0x63, 0x27, 0xfe, 0x06, 0x10, 0xfe, 0x83, 0xe7, 0xc4, 0xa1, + 0xfe, 0x03, 0x40, 0x09, 0x4a, 0x4f, 0x35, 0x01, 0xa8, 0xad, 0xfe, 0x1f, + 0x40, 0x12, 0x58, 0x01, 0xa5, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, + 0x44, 0x51, 0xfe, 0xc6, 0x51, 0x83, 0xfb, 0xfe, 0x8a, 0x90, 0x0c, 0x52, + 0x18, 0x53, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, + 0xc2, 0x50, 0x0c, 0x39, 0x18, 0x3a, 0xfe, 0x4a, 0x10, 0x09, 0x04, 0x6a, + 0xfe, 0x2a, 0x12, 0xfe, 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x54, 0x18, + 0x55, 0x09, 0x04, 0x4f, 0x85, 0x01, 0xa8, 0xfe, 0x1f, 0x80, 0x12, 0x58, + 0xfe, 0x44, 0x90, 0xfe, 0xc6, 0x90, 0x0c, 0x56, 0x18, 0x57, 0xfb, 0xfe, + 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, + 0x0c, 0x39, 0x18, 0x3a, 0x0c, 0x38, 0x18, 0x4e, 0x09, 0x4a, 0x19, 0x35, + 0x2a, 0x13, 0xfe, 0x4e, 0x11, 0x65, 0xfe, 0x48, 0x08, 0xfe, 0x9e, 0xf0, + 0xfe, 0x5c, 0x08, 0xb1, 0x16, 0x32, 0x2a, 0x73, 0xdd, 0xb8, 0xfe, 0x80, + 0x08, 0xb9, 0xfe, 0x9e, 0x08, 0x8c, 0xfe, 0x74, 0x08, 0xfe, 0x06, 0xf0, + 0xfe, 0x7a, 0x08, 0x8d, 0x81, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xc9, 0x10, + 0x15, 0x19, 0xfe, 0xc9, 0x10, 0x61, 0x04, 0x06, 0xfe, 0x10, 0x12, 0x61, + 0x04, 0x0b, 0x45, 0x09, 0x04, 0x0b, 0xfe, 0x68, 0x12, 0xfe, 0x2e, 0x1c, + 0x02, 0xfe, 0x24, 0x0a, 0x61, 0x04, 0x06, 0x45, 0x61, 0x04, 0x0b, 0xfe, + 0x52, 0x12, 0xfe, 0x2c, 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x1e, 0x09, 0xfe, + 0xac, 0xf0, 0xfe, 0xbe, 0x08, 0xfe, 0x8a, 0x10, 0xaa, 0xfe, 0xf3, 0x10, + 0xfe, 0xad, 0xf0, 0xfe, 0xca, 0x08, 0x02, 0xfe, 0x24, 0x0a, 0xab, 0xfe, + 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0x9d, 0xe9, 0x1c, 0xfe, 0x00, 0xfe, 0xfe, + 0x1c, 0x12, 0xb5, 0xfe, 0xd2, 0xf0, 0x9d, 0xfe, 0x76, 0x18, 0x1c, 0x1a, + 0x16, 0x9d, 0x05, 0xcb, 0x1c, 0x06, 0x16, 0x9d, 0xb8, 0x6d, 0xb9, 0x6d, + 0xaa, 0xab, 0xfe, 0xb1, 0x10, 0x70, 0x5e, 0x2b, 0x14, 0x92, 0x01, 0x33, + 0x0f, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x5a, 0x0f, 0x7c, 0x02, 0x5a, + 0xfe, 0x74, 0x18, 0x1c, 0xfe, 0x00, 0xf8, 0x16, 0x6d, 0x67, 0x1b, 0x01, + 0xfe, 0x44, 0x0d, 0x3b, 0x01, 0xe6, 0x1e, 0x27, 0x74, 0x67, 0x1a, 0x02, + 0x6d, 0x09, 0x04, 0x0b, 0x21, 0xfe, 0x06, 0x0a, 0x09, 0x04, 0x6a, 0xfe, + 0x82, 0x12, 0x09, 0x04, 0x19, 0xfe, 0x66, 0x13, 0x1e, 0x58, 0xac, 0xfc, + 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, + 0xfe, 0x86, 0x91, 0x63, 0x27, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x77, + 0xd7, 0x05, 0x54, 0x31, 0x55, 0x0c, 0x7b, 0x18, 0x7c, 0xbe, 0x54, 0xbf, + 0x55, 0x01, 0xa8, 0xad, 0x63, 0x27, 0x12, 0x58, 0xc0, 0x38, 0xc1, 0x4e, + 0x79, 0x56, 0x68, 0x57, 0xf4, 0xf5, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05, + 0xfa, 0x4e, 0x01, 0xa5, 0xa2, 0x23, 0x0c, 0x7b, 0x0c, 0x7c, 0x79, 0x56, + 0x68, 0x57, 0xfe, 0x12, 0x10, 0x09, 0x04, 0x19, 0x16, 0xd7, 0x79, 0x39, + 0x68, 0x3a, 0x09, 0x04, 0xfe, 0xf7, 0x00, 0x35, 0x05, 0x52, 0x31, 0x53, + 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, + 0x02, 0x6d, 0x09, 0x04, 0x19, 0x16, 0xd7, 0x09, 0x04, 0xfe, 0xf7, 0x00, + 0x35, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x5f, 0xfe, 0x10, 0x90, 0xfe, + 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x2f, 0x07, 0x9b, 0x16, 0xfe, 0xc6, 0x08, + 0x11, 0x9b, 0x09, 0x04, 0x0b, 0xfe, 0x14, 0x13, 0x05, 0x39, 0x31, 0x3a, + 0x77, 0xfe, 0xc6, 0x08, 0xfe, 0x0c, 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x6d, + 0x23, 0x47, 0xfe, 0x19, 0x80, 0xde, 0x09, 0x04, 0x0b, 0xfe, 0x1a, 0x12, + 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xe9, 0xb5, 0xfe, 0xd1, 0xf0, 0xd9, + 0x14, 0x7a, 0x01, 0x33, 0x0f, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, + 0x6c, 0x19, 0xbe, 0x39, 0xfe, 0xed, 0x19, 0xbf, 0x3a, 0xfe, 0x0c, 0x51, + 0xfe, 0x8e, 0x51, 0xe9, 0x1c, 0xfe, 0x00, 0xff, 0x34, 0xfe, 0x74, 0x10, + 0xb5, 0xfe, 0xd2, 0xf0, 0xfe, 0xb2, 0x0a, 0xfe, 0x76, 0x18, 0x1c, 0x1a, + 0x84, 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0x08, 0x13, 0x0f, 0xfe, 0x16, 0x00, + 0x02, 0x5a, 0xfe, 0xd1, 0xf0, 0xfe, 0xc4, 0x0a, 0x14, 0x7a, 0x01, 0x33, + 0x0f, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe, 0xce, 0xf0, 0xfe, 0xca, + 0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x0f, 0xfe, + 0x22, 0x00, 0x02, 0x5a, 0xfe, 0xcb, 0xf0, 0xfe, 0xe2, 0x0a, 0x0f, 0xfe, + 0x24, 0x00, 0x02, 0x5a, 0xfe, 0xd0, 0xf0, 0xfe, 0xec, 0x0a, 0x0f, 0x93, + 0xdc, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x0f, 0x4c, 0xfe, 0x10, 0x10, + 0xfe, 0xcc, 0xf0, 0xd9, 0x61, 0x04, 0x19, 0x3b, 0x0f, 0xfe, 0x12, 0x00, + 0x2a, 0x13, 0xfe, 0x4e, 0x11, 0x65, 0xfe, 0x0c, 0x0b, 0xfe, 0x9e, 0xf0, + 0xfe, 0x20, 0x0b, 0xb1, 0x16, 0x32, 0x2a, 0x73, 0xdd, 0xb8, 0x22, 0xb9, + 0x22, 0x2a, 0xec, 0x65, 0xfe, 0x2c, 0x0b, 0x25, 0x32, 0x8c, 0xfe, 0x48, + 0x0b, 0x8d, 0x81, 0xb8, 0xd4, 0xb9, 0xd4, 0x02, 0x22, 0x01, 0x43, 0xfe, + 0xdb, 0x10, 0x11, 0xfe, 0xe8, 0x00, 0xaa, 0xab, 0x70, 0xbc, 0x7d, 0xbd, + 0x7f, 0xfe, 0x89, 0xf0, 0x22, 0x30, 0x2e, 0xd8, 0xbc, 0x7d, 0xbd, 0x7f, + 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd6, 0xb1, 0x45, 0x0f, 0xfe, 0x42, + 0x00, 0x02, 0x5a, 0x78, 0x06, 0xfe, 0x81, 0x49, 0x16, 0xfe, 0x38, 0x0c, + 0x09, 0x04, 0x0b, 0xfe, 0x44, 0x13, 0x0f, 0x00, 0x4b, 0x0b, 0xfe, 0x54, + 0x12, 0x4b, 0xfe, 0x28, 0x00, 0x21, 0xfe, 0xa6, 0x0c, 0x0a, 0x40, 0x01, + 0x0e, 0x07, 0x00, 0x5d, 0x3e, 0xfe, 0x28, 0x00, 0xfe, 0xe2, 0x10, 0x01, + 0xe7, 0x01, 0xe8, 0x0a, 0x99, 0x01, 0xfe, 0x32, 0x0e, 0x59, 0x11, 0x2d, + 0x01, 0x6f, 0x02, 0x29, 0x0f, 0xfe, 0x44, 0x00, 0x4b, 0x0b, 0xdf, 0x3e, + 0x0b, 0xfe, 0xb4, 0x10, 0x01, 0x86, 0x3e, 0x0b, 0xfe, 0xaa, 0x10, 0x01, + 0x86, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xa3, 0x3e, 0x0b, 0x0f, 0xfe, + 0x43, 0x00, 0xfe, 0x96, 0x10, 0x09, 0x4a, 0x0b, 0x35, 0x01, 0xe7, 0x01, + 0xe8, 0x59, 0x11, 0x2d, 0x01, 0x6f, 0x67, 0x0b, 0x59, 0x3c, 0x8a, 0x02, + 0xfe, 0x2a, 0x03, 0x09, 0x04, 0x0b, 0x84, 0x3e, 0x0b, 0x0f, 0x00, 0xfe, + 0x5c, 0x10, 0x61, 0x04, 0x1b, 0xfe, 0x58, 0x12, 0x09, 0x04, 0x1b, 0xfe, + 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x5c, 0x0c, 0xfe, + 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x62, 0x0c, 0x09, 0x4a, 0x1b, 0x35, + 0xfe, 0xa9, 0x10, 0x0f, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0b, 0x5f, + 0x5c, 0x0f, 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x0f, 0xfe, 0x47, 0x00, + 0xa1, 0x0f, 0xfe, 0x41, 0x00, 0xa0, 0x0f, 0xfe, 0x24, 0x00, 0x87, 0xaa, + 0xab, 0x70, 0x05, 0x6b, 0x28, 0x21, 0xd1, 0x5f, 0xfe, 0x04, 0xe6, 0x1b, + 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x59, 0x01, 0xda, 0x02, 0x29, 0xea, + 0x14, 0x0b, 0x37, 0x95, 0xa9, 0x14, 0xfe, 0x31, 0x00, 0x37, 0x97, 0x01, + 0xfe, 0x54, 0x0f, 0x02, 0xd0, 0x3c, 0xfe, 0x06, 0xec, 0xc9, 0xee, 0x3e, + 0x1d, 0xfe, 0xce, 0x45, 0x34, 0x3c, 0xfe, 0x06, 0xea, 0xc9, 0xfe, 0x47, + 0x4b, 0x89, 0xfe, 0x75, 0x57, 0x05, 0x51, 0xfe, 0x98, 0x56, 0xfe, 0x38, + 0x12, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x44, 0x48, 0x46, 0x09, 0x04, 0x1d, + 0xfe, 0x1a, 0x13, 0x0a, 0x40, 0x01, 0x0e, 0x47, 0xfe, 0x41, 0x58, 0x0a, + 0x99, 0x01, 0x0e, 0xfe, 0x49, 0x54, 0x8e, 0xfe, 0x2a, 0x0d, 0x02, 0xfe, + 0x2a, 0x03, 0x0a, 0x51, 0xfe, 0xee, 0x14, 0xee, 0x3e, 0x1d, 0xfe, 0xce, + 0x45, 0x34, 0x3c, 0xfe, 0xce, 0x47, 0xfe, 0xad, 0x13, 0x02, 0x29, 0x1e, + 0x20, 0x07, 0x10, 0xfe, 0x9e, 0x12, 0x23, 0x12, 0x4d, 0x12, 0x94, 0x12, + 0xce, 0x1e, 0x2d, 0x47, 0x37, 0x2d, 0xb1, 0xe0, 0xfe, 0xbc, 0xf0, 0xfe, + 0xec, 0x0d, 0x13, 0x06, 0x12, 0x4d, 0x01, 0xfe, 0xe2, 0x15, 0x05, 0xfe, + 0x38, 0x01, 0x31, 0xfe, 0x3a, 0x01, 0x77, 0xfe, 0xf0, 0x0d, 0xfe, 0x02, + 0xec, 0xce, 0x62, 0x00, 0x5d, 0xfe, 0x04, 0xec, 0x20, 0x46, 0xfe, 0x05, + 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x52, 0x16, 0xfb, 0xfe, 0x48, 0xf4, + 0x0d, 0xfe, 0x18, 0x13, 0xaf, 0xfe, 0x02, 0xea, 0xce, 0x62, 0x7a, 0xfe, + 0xc5, 0x13, 0x14, 0x1b, 0x37, 0x95, 0xa9, 0x5c, 0x05, 0xfe, 0x38, 0x01, + 0x1c, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x05, 0xfe, 0x3a, 0x01, + 0x0c, 0xfe, 0x62, 0x01, 0x3d, 0x12, 0x20, 0x24, 0x06, 0x12, 0x2d, 0x11, + 0x2d, 0x8a, 0x13, 0x06, 0x03, 0x23, 0x03, 0x1e, 0x4d, 0xfe, 0xf7, 0x12, + 0x1e, 0x94, 0xac, 0x12, 0x94, 0x07, 0x7a, 0xfe, 0x71, 0x13, 0xfe, 0x24, + 0x1c, 0x14, 0x1a, 0x37, 0x95, 0xa9, 0xfe, 0xd9, 0x10, 0xb6, 0xfe, 0x03, + 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x03, 0xb6, 0xfe, 0x03, 0xdc, + 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x03, 0xfe, 0x03, 0x57, 0xb6, 0x23, + 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0xb6, 0x75, 0x03, 0x09, 0x04, + 0x4c, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13, + 0xfe, 0x1e, 0x80, 0xe1, 0xfe, 0x1d, 0x80, 0xa4, 0xfe, 0x0c, 0x90, 0xfe, + 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xa3, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, + 0x0b, 0xfe, 0x3c, 0x50, 0xa0, 0x01, 0xfe, 0x82, 0x16, 0x2f, 0x07, 0x2d, + 0xe0, 0x01, 0xfe, 0xbc, 0x15, 0x09, 0x04, 0x1d, 0x45, 0x01, 0xe7, 0x01, + 0xe8, 0x11, 0xfe, 0xe9, 0x00, 0x09, 0x04, 0x4c, 0xfe, 0x2c, 0x13, 0x01, + 0xfe, 0x14, 0x16, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90, + 0x0c, 0xfe, 0x64, 0x01, 0x18, 0xfe, 0x66, 0x01, 0x09, 0x04, 0x4f, 0xfe, + 0x12, 0x12, 0xfe, 0x03, 0x80, 0x74, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80, + 0x40, 0x12, 0x20, 0x63, 0x27, 0x11, 0xc8, 0x59, 0x1e, 0x20, 0xed, 0x76, + 0x20, 0x03, 0xfe, 0x08, 0x1c, 0x05, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58, + 0x05, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x05, 0xfe, 0xb0, 0x00, 0xfe, + 0x08, 0x58, 0x05, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, + 0x24, 0x69, 0x12, 0xc9, 0x23, 0x0c, 0x50, 0x0c, 0x3f, 0x13, 0x40, 0x48, + 0x5f, 0x17, 0x1d, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x21, 0xfe, 0x08, + 0x0f, 0x3e, 0x10, 0x13, 0x42, 0x48, 0x17, 0x4c, 0xfe, 0x90, 0x4d, 0xfe, + 0x91, 0x54, 0x21, 0xfe, 0x1e, 0x0f, 0x24, 0x10, 0x12, 0x20, 0x78, 0x2c, + 0x46, 0x1e, 0x20, 0xed, 0x76, 0x20, 0x11, 0xc8, 0xf6, 0xfe, 0xd6, 0xf0, + 0xfe, 0x32, 0x0f, 0xea, 0x70, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, + 0x18, 0x1c, 0x03, 0x3c, 0xfe, 0x0c, 0x14, 0xee, 0xfe, 0x07, 0xe6, 0x1d, + 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x86, 0x78, 0x2c, 0x46, + 0xfa, 0xef, 0xfe, 0x42, 0x13, 0x2f, 0x07, 0x2d, 0xfe, 0x34, 0x13, 0x0a, + 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x36, 0x12, 0xf0, 0xfe, 0x45, 0x48, 0x01, + 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10, + 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x6f, 0xfe, 0x0e, + 0x10, 0x07, 0x7e, 0x45, 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x6c, 0x0f, 0x03, + 0xfe, 0x44, 0x58, 0x74, 0xfe, 0x01, 0xec, 0x97, 0xfe, 0x9e, 0x40, 0xfe, + 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1b, 0x76, 0x27, 0x01, 0xda, 0xfe, + 0xdd, 0x10, 0x2a, 0xbc, 0x7d, 0xbd, 0x7f, 0x30, 0x2e, 0xd5, 0x07, 0x1b, + 0xfe, 0x48, 0x12, 0x07, 0x0b, 0xfe, 0x56, 0x12, 0x07, 0x1a, 0xfe, 0x30, + 0x12, 0x07, 0xc2, 0x16, 0xfe, 0x3e, 0x11, 0x07, 0xfe, 0x23, 0x00, 0x16, + 0xfe, 0x4a, 0x11, 0x07, 0x06, 0x16, 0xfe, 0xa8, 0x11, 0x07, 0x19, 0xfe, + 0x12, 0x12, 0x07, 0x00, 0x16, 0x22, 0x14, 0xc2, 0x01, 0x33, 0x9f, 0x2b, + 0x01, 0x08, 0x8c, 0x43, 0x03, 0x2b, 0xfe, 0x62, 0x08, 0x0a, 0xca, 0x01, + 0xfe, 0x32, 0x0e, 0x11, 0x7e, 0x02, 0x29, 0x2b, 0x2f, 0x07, 0x9b, 0xfe, + 0xd9, 0x13, 0x79, 0x39, 0x68, 0x3a, 0x77, 0xfe, 0xfc, 0x10, 0x09, 0x04, + 0x6a, 0xfe, 0x72, 0x12, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x8e, 0xfe, + 0xc6, 0x10, 0x1e, 0x58, 0xfe, 0x26, 0x13, 0x05, 0x7b, 0x31, 0x7c, 0x77, + 0xfe, 0x82, 0x0c, 0x0c, 0x54, 0x18, 0x55, 0x23, 0x0c, 0x7b, 0x0c, 0x7c, + 0x01, 0xa8, 0x24, 0x69, 0x73, 0x12, 0x58, 0x01, 0xa5, 0xc0, 0x38, 0xc1, + 0x4e, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x38, 0xfe, + 0x05, 0xfa, 0x4e, 0xfe, 0x91, 0x10, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x40, + 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x56, 0x18, 0x57, 0x83, 0xc0, 0x38, 0xc1, + 0x4e, 0xf4, 0xf5, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x00, 0x56, 0xfe, 0xa1, + 0x56, 0x0c, 0x52, 0x18, 0x53, 0x09, 0x04, 0x6a, 0xfe, 0x1e, 0x12, 0x1e, + 0x58, 0xfe, 0x1f, 0x40, 0x05, 0x54, 0x31, 0x55, 0xfe, 0x2c, 0x50, 0xfe, + 0xae, 0x50, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x44, 0x50, 0xfe, 0xc6, 0x50, + 0x05, 0x52, 0x31, 0x53, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x05, 0x39, + 0x31, 0x3a, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x5c, 0x24, 0x06, + 0x12, 0xcd, 0x02, 0x5b, 0x2b, 0x01, 0x08, 0x1f, 0x44, 0x30, 0x2e, 0xd5, + 0x07, 0x06, 0x21, 0x44, 0x2f, 0x07, 0x9b, 0x21, 0x5b, 0x01, 0x6e, 0x1c, + 0x3d, 0x16, 0x44, 0x09, 0x04, 0x0b, 0xe2, 0x79, 0x39, 0x68, 0x3a, 0xfe, + 0x0a, 0x55, 0x34, 0xfe, 0x8b, 0x55, 0xbe, 0x39, 0xbf, 0x3a, 0xfe, 0x0c, + 0x51, 0xfe, 0x8e, 0x51, 0x02, 0x5b, 0xfe, 0x19, 0x81, 0xaf, 0xfe, 0x19, + 0x41, 0x02, 0x5b, 0x2b, 0x01, 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, + 0xd8, 0x4b, 0x1a, 0xfe, 0xa6, 0x12, 0x4b, 0x0b, 0x3b, 0x02, 0x44, 0x01, + 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, 0xd6, 0x07, 0x1a, 0x21, 0x44, + 0x01, 0x08, 0x1f, 0xa2, 0x30, 0x2e, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, + 0x60, 0x05, 0xfe, 0x9c, 0x00, 0x28, 0x84, 0x49, 0x04, 0x19, 0x34, 0x9f, + 0xfe, 0xbb, 0x45, 0x4b, 0x00, 0x45, 0x3e, 0x06, 0x78, 0x3d, 0xfe, 0xda, + 0x14, 0x01, 0x6e, 0x87, 0xfe, 0x4b, 0x45, 0xe2, 0x2f, 0x07, 0x9a, 0xe1, + 0x05, 0xc6, 0x28, 0x84, 0x05, 0x3f, 0x28, 0x34, 0x5e, 0x02, 0x5b, 0xfe, + 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17, 0x05, 0x50, 0xb4, 0x0c, + 0x50, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe, 0xaa, 0x14, 0x02, + 0x5c, 0x01, 0x08, 0x25, 0x32, 0x1f, 0x44, 0x30, 0x2e, 0xd6, 0x07, 0x06, + 0x21, 0x44, 0x01, 0xfe, 0x8e, 0x13, 0xfe, 0x42, 0x58, 0xfe, 0x82, 0x14, + 0xfe, 0xa4, 0x14, 0x87, 0xfe, 0x4a, 0xf4, 0x0b, 0x16, 0x44, 0xfe, 0x4a, + 0xf4, 0x06, 0xfe, 0x0c, 0x12, 0x2f, 0x07, 0x9a, 0x85, 0x02, 0x5b, 0x05, + 0x3f, 0xb4, 0x0c, 0x3f, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe, + 0xd8, 0x14, 0x02, 0x5c, 0x13, 0x06, 0x65, 0xfe, 0xca, 0x12, 0x26, 0xfe, + 0xe0, 0x12, 0x72, 0xf1, 0x01, 0x08, 0x23, 0x72, 0x03, 0x8f, 0xfe, 0xdc, + 0x12, 0x25, 0xfe, 0xdc, 0x12, 0x1f, 0xfe, 0xca, 0x12, 0x5e, 0x2b, 0x01, + 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, + 0x1c, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, + 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0x1c, 0x3d, 0xfe, 0x30, 0x56, + 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, + 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0xfe, 0x0b, 0x58, + 0x03, 0x0a, 0x50, 0x01, 0x82, 0x0a, 0x3f, 0x01, 0x82, 0x03, 0xfc, 0x1c, + 0x10, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x19, 0x48, 0xfe, 0x00, + 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x63, 0x27, + 0x0c, 0x52, 0x18, 0x53, 0xbe, 0x56, 0xbf, 0x57, 0x03, 0xfe, 0x62, 0x08, + 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x74, 0x03, 0x01, + 0xfe, 0x14, 0x18, 0xfe, 0x42, 0x48, 0x5f, 0x60, 0x89, 0x01, 0x08, 0x1f, + 0xfe, 0xa2, 0x14, 0x30, 0x2e, 0xd8, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14, + 0x30, 0x2e, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x05, 0xc6, 0x28, 0xfe, + 0xcc, 0x12, 0x49, 0x04, 0x1b, 0xfe, 0xc4, 0x13, 0x23, 0x62, 0x1b, 0xe2, + 0x4b, 0xc3, 0x64, 0xfe, 0xe8, 0x13, 0x3b, 0x13, 0x06, 0x17, 0xc3, 0x78, + 0xdb, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xa1, 0xff, 0x02, 0x83, + 0x55, 0x62, 0x1a, 0xa4, 0xbb, 0xfe, 0x30, 0x00, 0x8e, 0xe4, 0x17, 0x2c, + 0x13, 0x06, 0xfe, 0x56, 0x10, 0x62, 0x0b, 0xe1, 0xbb, 0xfe, 0x64, 0x00, + 0x8e, 0xe4, 0x0a, 0xfe, 0x64, 0x00, 0x17, 0x93, 0x13, 0x06, 0xfe, 0x28, + 0x10, 0x62, 0x06, 0xfe, 0x60, 0x13, 0xbb, 0xfe, 0xc8, 0x00, 0x8e, 0xe4, + 0x0a, 0xfe, 0xc8, 0x00, 0x17, 0x4d, 0x13, 0x06, 0x83, 0xbb, 0xfe, 0x90, + 0x01, 0xba, 0xfe, 0x4e, 0x14, 0x89, 0xfe, 0x12, 0x10, 0xfe, 0x43, 0xf4, + 0x94, 0xfe, 0x56, 0xf0, 0xfe, 0x60, 0x14, 0xfe, 0x04, 0xf4, 0x6c, 0xfe, + 0x43, 0xf4, 0x93, 0xfe, 0xf3, 0x10, 0xf9, 0x01, 0xfe, 0x22, 0x13, 0x1c, + 0x3d, 0xfe, 0x10, 0x13, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x69, 0xba, + 0xfe, 0x9c, 0x14, 0xb7, 0x69, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, + 0x4d, 0xe4, 0x19, 0xba, 0xfe, 0x9c, 0x14, 0xb7, 0x19, 0x83, 0x60, 0x23, + 0xfe, 0x4d, 0xf4, 0x00, 0xdf, 0x89, 0x13, 0x06, 0xfe, 0xb4, 0x56, 0xfe, + 0xc3, 0x58, 0x03, 0x60, 0x13, 0x0b, 0x03, 0x15, 0x06, 0x01, 0x08, 0x26, + 0xe5, 0x15, 0x0b, 0x01, 0x08, 0x26, 0xe5, 0x15, 0x1a, 0x01, 0x08, 0x26, + 0xe5, 0x72, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x03, 0x15, 0x06, 0x01, 0x08, + 0x26, 0xa6, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x06, 0x01, 0x08, + 0x26, 0xa6, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x26, 0xa6, 0x72, 0xfe, 0x89, + 0x4a, 0x01, 0x08, 0x03, 0x60, 0x03, 0x1e, 0xcc, 0x07, 0x06, 0xfe, 0x44, + 0x13, 0xad, 0x12, 0xcc, 0xfe, 0x49, 0xf4, 0x00, 0x3b, 0x72, 0x9f, 0x5e, + 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01, 0x08, 0x2f, 0x07, 0xfe, + 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0x5a, 0x15, 0x23, 0x12, 0xcd, + 0x01, 0x43, 0x1e, 0xcd, 0x07, 0x06, 0x45, 0x09, 0x4a, 0x06, 0x35, 0x03, + 0x0a, 0x42, 0x01, 0x0e, 0xed, 0x88, 0x07, 0x10, 0xa4, 0x0a, 0x80, 0x01, + 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x80, 0x01, 0x0e, 0x88, + 0xfe, 0x80, 0xe7, 0x10, 0x07, 0x10, 0x84, 0xfe, 0x45, 0x58, 0x01, 0xe3, + 0x88, 0x03, 0x0a, 0x42, 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, + 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x80, 0x80, 0xf2, 0xfe, 0x49, 0xe4, 0x10, + 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x0a, 0x51, 0x01, 0x82, 0x03, 0x17, + 0x10, 0x71, 0x66, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, + 0xfe, 0x24, 0x1c, 0xfe, 0x1d, 0xf7, 0x1d, 0x90, 0xfe, 0xf6, 0x15, 0x01, + 0xfe, 0xfc, 0x16, 0xe0, 0x91, 0x1d, 0x66, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, + 0x19, 0x03, 0xae, 0x21, 0xfe, 0xe6, 0x15, 0xfe, 0xda, 0x10, 0x17, 0x10, + 0x71, 0x05, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58, + 0x05, 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0x91, 0x19, 0xfe, 0x3c, 0x90, + 0xfe, 0x30, 0xf4, 0x06, 0xfe, 0x3c, 0x50, 0x66, 0xfe, 0x38, 0x00, 0xfe, + 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x90, 0xfe, 0x40, 0x16, 0xfe, 0xb6, + 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x18, 0x16, 0xfe, 0x9c, 0x10, 0x17, + 0x10, 0x71, 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, + 0x1d, 0xf7, 0x38, 0x90, 0xfe, 0x62, 0x16, 0xfe, 0x94, 0x14, 0xfe, 0x10, + 0x13, 0x91, 0x38, 0x66, 0x1b, 0xfe, 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00, + 0x03, 0xae, 0x21, 0xfe, 0x56, 0x16, 0xfe, 0x6c, 0x10, 0x17, 0x10, 0x71, + 0xfe, 0x30, 0xbc, 0xfe, 0xb2, 0xbc, 0x91, 0xc5, 0x66, 0x1b, 0xfe, 0x0f, + 0x79, 0xfe, 0x1c, 0xf7, 0xc5, 0x90, 0xfe, 0x9a, 0x16, 0xfe, 0x5c, 0x14, + 0x34, 0x03, 0xae, 0x21, 0xfe, 0x86, 0x16, 0xfe, 0x42, 0x10, 0xfe, 0x02, + 0xf6, 0x10, 0x71, 0xfe, 0x18, 0xfe, 0x54, 0xfe, 0x19, 0xfe, 0x55, 0xfc, + 0xfe, 0x1d, 0xf7, 0x4f, 0x90, 0xfe, 0xc0, 0x16, 0xfe, 0x36, 0x14, 0xfe, + 0x1c, 0x13, 0x91, 0x4f, 0x47, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, + 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11, 0xfe, 0xdd, 0x00, 0x63, + 0x27, 0x03, 0x63, 0x27, 0xfe, 0x12, 0x45, 0x21, 0xfe, 0xb0, 0x16, 0x14, + 0x06, 0x37, 0x95, 0xa9, 0x02, 0x29, 0xfe, 0x39, 0xf0, 0xfe, 0x04, 0x17, + 0x23, 0x03, 0xfe, 0x7e, 0x18, 0x1c, 0x1a, 0x5d, 0x13, 0x0d, 0x03, 0x71, + 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x78, 0x2c, + 0x46, 0x2f, 0x07, 0x2d, 0xfe, 0x3c, 0x13, 0xfe, 0x82, 0x14, 0xfe, 0x42, + 0x13, 0x3c, 0x8a, 0x0a, 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x3e, 0x12, 0xf0, + 0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13, + 0x3d, 0x75, 0x07, 0x10, 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x01, 0x6f, + 0xfe, 0x16, 0x10, 0x07, 0x7e, 0x85, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12, + 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x24, 0x17, 0x17, 0x0b, 0x03, 0xfe, 0x9c, + 0xe7, 0x0b, 0x0f, 0xfe, 0x15, 0x00, 0x59, 0x76, 0x27, 0x01, 0xda, 0x17, + 0x06, 0x03, 0x3c, 0x8a, 0x09, 0x4a, 0x1d, 0x35, 0x11, 0x2d, 0x01, 0x6f, + 0x17, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x79, 0xc7, 0x68, + 0xc8, 0xfe, 0x48, 0x55, 0x34, 0xfe, 0xc9, 0x55, 0x03, 0x1e, 0x98, 0x73, + 0x12, 0x98, 0x03, 0x0a, 0x99, 0x01, 0x0e, 0xf0, 0x0a, 0x40, 0x01, 0x0e, + 0xfe, 0x49, 0x44, 0x16, 0xfe, 0xf0, 0x17, 0x73, 0x75, 0x03, 0x0a, 0x42, + 0x01, 0x0e, 0x07, 0x10, 0x45, 0x0a, 0x51, 0x01, 0x9e, 0x0a, 0x40, 0x01, + 0x0e, 0x73, 0x75, 0x03, 0xfe, 0x4e, 0xe4, 0x1a, 0x64, 0xfe, 0x24, 0x18, + 0x05, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0x5b, 0xfe, 0x4e, 0xe4, 0xc2, + 0x64, 0xfe, 0x36, 0x18, 0x05, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1b, + 0xdc, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x64, 0xfe, 0x48, 0x18, 0x05, + 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x19, 0xfe, 0x08, 0x10, 0x05, 0xfe, + 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x2c, 0xfe, 0x4e, 0x45, 0xfe, 0x0c, 0x12, + 0xaf, 0xff, 0x04, 0x68, 0x54, 0xde, 0x1c, 0x69, 0x03, 0x07, 0x7a, 0xfe, + 0x5a, 0xf0, 0xfe, 0x74, 0x18, 0x24, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10, + 0x07, 0x1b, 0xfe, 0x5a, 0xf0, 0xfe, 0x82, 0x18, 0x24, 0xc3, 0xfe, 0x26, + 0x10, 0x07, 0x1a, 0x5d, 0x24, 0x2c, 0xdc, 0x07, 0x0b, 0x5d, 0x24, 0x93, + 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x5d, 0x24, 0x4d, 0x9f, 0xad, 0x03, 0x14, + 0xfe, 0x09, 0x00, 0x01, 0x33, 0xfe, 0x04, 0xfe, 0x7d, 0x05, 0x7f, 0xf9, + 0x03, 0x25, 0xfe, 0xca, 0x18, 0xfe, 0x14, 0xf0, 0x08, 0x65, 0xfe, 0xc6, + 0x18, 0x03, 0xff, 0x1a, 0x00, 0x00, +}; + +static unsigned short _adv_asc3550_size = sizeof(_adv_asc3550_buf); /* 0x13AD */ +static ADV_DCNT _adv_asc3550_chksum = 0x04D52DDDUL; /* Expanded little-endian checksum. */ + +/* Microcode buffer is kept after initialization for error recovery. */ +static unsigned char _adv_asc38C0800_buf[] = { + 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x16, 0x18, 0xe4, + 0x01, 0x00, 0x48, 0xe4, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0xce, 0x19, + 0x00, 0xfa, 0xff, 0xff, 0x1c, 0x0f, 0x00, 0xf6, 0x9e, 0xe7, 0xff, 0x00, + 0x82, 0xe7, 0x00, 0xea, 0x01, 0xfa, 0x01, 0xe6, 0x09, 0xe7, 0x55, 0xf0, + 0x01, 0xf6, 0x03, 0x00, 0x04, 0x00, 0x10, 0x00, 0x1e, 0xf0, 0x85, 0xf0, + 0x18, 0xf4, 0x08, 0x00, 0xbc, 0x00, 0x38, 0x54, 0x00, 0xec, 0xd5, 0xf0, + 0x82, 0x0d, 0x00, 0xe6, 0x86, 0xf0, 0xb1, 0xf0, 0x98, 0x57, 0x01, 0xfc, + 0xb4, 0x00, 0xd4, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x3c, 0x00, 0xbb, 0x00, + 0x00, 0x10, 0xba, 0x19, 0x02, 0x80, 0x32, 0xf0, 0x7c, 0x0d, 0x02, 0x13, + 0xba, 0x13, 0x18, 0x40, 0x00, 0x57, 0x01, 0xea, 0x02, 0xfc, 0x03, 0xfc, + 0x3e, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x74, 0x01, 0x76, 0x01, 0xb9, 0x54, + 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00, 0xc0, 0x00, 0x01, 0x01, + 0x3e, 0x01, 0x7a, 0x01, 0xca, 0x08, 0xce, 0x10, 0x16, 0x11, 0x04, 0x12, + 0x08, 0x12, 0x02, 0x4a, 0xbb, 0x55, 0x3c, 0x56, 0x03, 0x58, 0x1b, 0x80, + 0x30, 0xe4, 0x4b, 0xe4, 0x5d, 0xf0, 0x02, 0xfa, 0x20, 0x00, 0x32, 0x00, + 0x40, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, + 0x70, 0x01, 0x72, 0x01, 0x78, 0x01, 0x7c, 0x01, 0x62, 0x0a, 0x86, 0x0d, + 0x06, 0x13, 0x4c, 0x1c, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, + 0x03, 0xf7, 0x0c, 0x00, 0x0f, 0x00, 0x47, 0x00, 0xbe, 0x00, 0x00, 0x01, + 0x20, 0x11, 0x5c, 0x16, 0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44, + 0x00, 0x4c, 0x04, 0xea, 0x5c, 0xf0, 0xa7, 0xf0, 0x04, 0xf6, 0x03, 0xfa, + 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01, + 0x4e, 0x01, 0x4a, 0x0b, 0x42, 0x0c, 0x12, 0x0f, 0x0c, 0x10, 0x22, 0x11, + 0x0a, 0x12, 0x04, 0x13, 0x30, 0x1c, 0x02, 0x48, 0x00, 0x4e, 0x42, 0x54, + 0x44, 0x55, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0, + 0x59, 0xf0, 0xb8, 0xf0, 0x4b, 0xf4, 0x06, 0xf7, 0x0e, 0xf7, 0x04, 0xfc, + 0x05, 0xfc, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00, 0xa4, 0x00, + 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xe2, 0x03, + 0x08, 0x0f, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, 0x0a, 0x13, 0x0c, 0x13, + 0x12, 0x13, 0x24, 0x14, 0x34, 0x14, 0x04, 0x16, 0x08, 0x16, 0xa4, 0x17, + 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44, 0x91, 0x44, + 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x3a, 0x55, 0x83, 0x55, + 0xe5, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0, + 0x0c, 0xf0, 0x04, 0xf8, 0x05, 0xf8, 0x07, 0x00, 0x0a, 0x00, 0x1c, 0x00, + 0x1e, 0x00, 0x9e, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, + 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7e, 0x01, 0xc4, 0x01, 0xc6, 0x01, + 0x80, 0x02, 0x5e, 0x03, 0xee, 0x04, 0x9a, 0x06, 0xf8, 0x07, 0x62, 0x08, + 0x68, 0x08, 0x69, 0x08, 0xd6, 0x08, 0xe9, 0x09, 0xfa, 0x0b, 0x2e, 0x0f, + 0x12, 0x10, 0x1a, 0x10, 0xed, 0x10, 0xf1, 0x10, 0x2a, 0x11, 0x06, 0x12, + 0x0c, 0x12, 0x3e, 0x12, 0x10, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x46, 0x14, + 0x76, 0x14, 0x82, 0x14, 0x36, 0x15, 0xca, 0x15, 0x6b, 0x18, 0xbe, 0x18, + 0xca, 0x18, 0xe6, 0x19, 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, + 0x0e, 0x47, 0xfe, 0x9c, 0xf0, 0x2b, 0x02, 0xfe, 0xac, 0x0d, 0xff, 0x10, + 0x00, 0x00, 0xd7, 0xfe, 0xe8, 0x19, 0x00, 0xd6, 0xfe, 0x84, 0x01, 0xff, + 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00, + 0x00, 0xfe, 0x57, 0x24, 0x00, 0xfe, 0x4c, 0x00, 0x5b, 0xff, 0x04, 0x00, + 0x00, 0x11, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x08, + 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x11, + 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00, + 0xfe, 0x04, 0xf7, 0xd6, 0x2c, 0x99, 0x0a, 0x01, 0xfe, 0xc2, 0x0f, 0xfe, + 0x04, 0xf7, 0xd6, 0x99, 0x0a, 0x42, 0x2c, 0xfe, 0x3d, 0xf0, 0xfe, 0x06, + 0x02, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x91, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, + 0x90, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, 0x8f, 0xf0, 0xa7, 0x03, 0x5d, 0x4d, + 0x02, 0xfe, 0xc8, 0x0d, 0x01, 0xfe, 0x38, 0x0e, 0xfe, 0xdd, 0x12, 0xfe, + 0xfc, 0x10, 0xfe, 0x28, 0x1c, 0x03, 0xfe, 0xa6, 0x00, 0xfe, 0xd3, 0x12, + 0x41, 0x14, 0xfe, 0xa6, 0x00, 0xc2, 0xfe, 0x48, 0xf0, 0xfe, 0x8a, 0x02, + 0xfe, 0x49, 0xf0, 0xfe, 0xa4, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc2, 0x02, + 0xfe, 0x46, 0xf0, 0xfe, 0x54, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x5a, 0x02, + 0xfe, 0x43, 0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x4c, 0x02, + 0xfe, 0x45, 0xf0, 0xfe, 0x50, 0x02, 0x18, 0x0a, 0xaa, 0x18, 0x06, 0x14, + 0xa1, 0x02, 0x2b, 0xfe, 0x00, 0x1c, 0xe7, 0xfe, 0x02, 0x1c, 0xe6, 0xfe, + 0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0xfe, 0x18, 0x18, 0xfe, 0xe7, 0x10, + 0xfe, 0x06, 0xfc, 0xce, 0x09, 0x70, 0x01, 0xa8, 0x02, 0x2b, 0x15, 0x59, + 0x39, 0xa2, 0x01, 0xfe, 0x58, 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xbd, + 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe, + 0x58, 0x1c, 0x18, 0x06, 0x14, 0xa1, 0x2c, 0x1c, 0x2b, 0xfe, 0x3d, 0xf0, + 0xfe, 0x06, 0x02, 0x23, 0xfe, 0x98, 0x02, 0xfe, 0x5a, 0x1c, 0xf8, 0xfe, + 0x14, 0x1c, 0x15, 0xfe, 0x30, 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, + 0x18, 0x06, 0x14, 0xa1, 0x02, 0xd7, 0x22, 0x20, 0x07, 0x11, 0x35, 0xfe, + 0x69, 0x10, 0x18, 0x06, 0x14, 0xa1, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0x43, + 0x13, 0x20, 0xfe, 0x05, 0xf6, 0xce, 0x01, 0xfe, 0x4a, 0x17, 0x08, 0x54, + 0x58, 0x37, 0x12, 0x2f, 0x42, 0x92, 0x01, 0xfe, 0x82, 0x16, 0x02, 0x2b, + 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x01, 0x73, 0xfe, 0x18, 0x10, + 0xfe, 0x41, 0x58, 0x09, 0xa4, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x6b, 0xfe, + 0x10, 0x03, 0x01, 0xfe, 0x82, 0x16, 0x02, 0x2b, 0x2c, 0x4f, 0xfe, 0x02, + 0xe8, 0x2a, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, + 0x27, 0xf0, 0xfe, 0xe0, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xa7, + 0xfe, 0x40, 0x1c, 0x1c, 0xd9, 0xfe, 0x26, 0xf0, 0xfe, 0x5a, 0x03, 0xfe, + 0xa0, 0xf0, 0xfe, 0x48, 0x03, 0xfe, 0x11, 0xf0, 0xa7, 0xfe, 0xef, 0x10, + 0xfe, 0x9f, 0xf0, 0xfe, 0x68, 0x03, 0xf9, 0x10, 0xfe, 0x11, 0x00, 0x02, + 0x65, 0x2c, 0xfe, 0x48, 0x1c, 0xf9, 0x08, 0x05, 0x1b, 0xfe, 0x18, 0x13, + 0x21, 0x22, 0xa3, 0xb7, 0x13, 0xa3, 0x09, 0x46, 0x01, 0x0e, 0xb7, 0x78, + 0x01, 0xfe, 0xb4, 0x16, 0x12, 0xd1, 0x1c, 0xd9, 0xfe, 0x01, 0xf0, 0xd9, + 0xfe, 0x82, 0xf0, 0xfe, 0x96, 0x03, 0xfa, 0x12, 0xfe, 0xe4, 0x00, 0x27, + 0xfe, 0xa8, 0x03, 0x1c, 0x34, 0x1d, 0xfe, 0xb8, 0x03, 0x01, 0x4b, 0xfe, + 0x06, 0xf0, 0xfe, 0xc8, 0x03, 0x95, 0x86, 0xfe, 0x0a, 0xf0, 0xfe, 0x8a, + 0x06, 0x02, 0x24, 0x03, 0x70, 0x28, 0x17, 0xfe, 0xfa, 0x04, 0x15, 0x6d, + 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, 0xd8, 0xf9, 0x2c, 0x99, 0x19, + 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c, + 0x74, 0x01, 0xaf, 0x8c, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x17, 0xda, + 0x09, 0xd1, 0x01, 0x0e, 0x8d, 0x51, 0x64, 0x79, 0x2a, 0x03, 0x70, 0x28, + 0xfe, 0x10, 0x12, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, + 0xd8, 0xc7, 0x81, 0xc8, 0x83, 0x1c, 0x24, 0x27, 0xfe, 0x40, 0x04, 0x1d, + 0xfe, 0x3c, 0x04, 0x3b, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e, + 0x12, 0x2d, 0xff, 0x02, 0x00, 0x10, 0x01, 0x0b, 0x1d, 0xfe, 0xe4, 0x04, + 0x2d, 0x01, 0x0b, 0x1d, 0x24, 0x33, 0x31, 0xde, 0xfe, 0x4c, 0x44, 0xfe, + 0x4c, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b, + 0xda, 0x4f, 0x79, 0x2a, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x62, + 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x2a, 0x13, 0x32, 0x07, 0x82, 0xfe, 0x52, + 0x13, 0xfe, 0x20, 0x10, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b, 0xda, 0xfe, + 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x40, 0x13, 0x08, 0x05, 0x1b, 0xfe, + 0x08, 0x13, 0x32, 0x07, 0x82, 0xfe, 0x30, 0x13, 0x08, 0x05, 0x1b, 0xfe, + 0x1c, 0x12, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe, 0x0d, 0x00, + 0x01, 0x36, 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x2d, 0x12, 0xfe, 0xe6, + 0x00, 0xfe, 0x1c, 0x90, 0xfe, 0x40, 0x5c, 0x04, 0x15, 0x9d, 0x01, 0x36, + 0x02, 0x2b, 0xfe, 0x42, 0x5b, 0x99, 0x19, 0xfe, 0x46, 0x59, 0xfe, 0xbf, + 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x87, 0x80, 0xfe, 0x31, 0xe4, 0x5b, 0x08, + 0x05, 0x0a, 0xfe, 0x84, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x19, 0xfe, 0x7c, + 0x12, 0x53, 0x05, 0x06, 0xfe, 0x6c, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x28, + 0x17, 0xfe, 0x90, 0x05, 0xfe, 0x31, 0xe4, 0x5a, 0x53, 0x05, 0x0a, 0xfe, + 0x56, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x28, 0xfe, 0x4e, 0x12, 0x67, 0xff, + 0x02, 0x00, 0x10, 0x27, 0xfe, 0x48, 0x05, 0x1c, 0x34, 0xfe, 0x89, 0x48, + 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x56, 0x05, 0x26, 0xfe, 0xa8, 0x05, + 0x12, 0xfe, 0xe3, 0x00, 0x21, 0x53, 0xfe, 0x4a, 0xf0, 0xfe, 0x76, 0x05, + 0xfe, 0x49, 0xf0, 0xfe, 0x70, 0x05, 0x88, 0x25, 0xfe, 0x21, 0x00, 0xab, + 0x25, 0xfe, 0x22, 0x00, 0xaa, 0x25, 0x58, 0xfe, 0x09, 0x48, 0xff, 0x02, + 0x00, 0x10, 0x27, 0xfe, 0x86, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0xfe, 0xe2, + 0x08, 0x53, 0x05, 0xcb, 0x4d, 0x01, 0xb0, 0x25, 0x06, 0x13, 0xd3, 0x39, + 0xfe, 0x27, 0x01, 0x08, 0x05, 0x1b, 0xfe, 0x22, 0x12, 0x41, 0x01, 0xb2, + 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36, + 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0xeb, + 0x03, 0x5c, 0x28, 0xfe, 0x36, 0x13, 0x41, 0x01, 0xb2, 0x26, 0xfe, 0x18, + 0x06, 0x09, 0x06, 0x53, 0x05, 0x1f, 0xfe, 0x02, 0x12, 0x50, 0x01, 0xfe, + 0x9e, 0x15, 0x1d, 0xfe, 0x0e, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe, + 0xe5, 0x00, 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x03, 0xcd, 0x28, 0xfe, 0x62, + 0x12, 0x03, 0x45, 0x28, 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x0c, 0x19, 0x01, + 0xfe, 0x76, 0x19, 0xfe, 0x43, 0x48, 0xc4, 0xcc, 0x0f, 0x71, 0xff, 0x02, + 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0x8b, 0xc4, 0x6e, 0x41, 0x01, 0xb2, + 0x26, 0xfe, 0x82, 0x06, 0x53, 0x05, 0x1a, 0xe9, 0x91, 0x09, 0x59, 0x01, + 0xfe, 0xcc, 0x15, 0x1d, 0xfe, 0x78, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, + 0xfe, 0xe5, 0x00, 0x03, 0x45, 0xc1, 0x0c, 0x45, 0x18, 0x06, 0x01, 0xb2, + 0xfa, 0x76, 0x74, 0x01, 0xaf, 0x8c, 0x12, 0xfe, 0xe2, 0x00, 0x27, 0xdb, + 0x1c, 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0xb6, 0x06, 0x94, 0xfe, 0x6c, 0x07, + 0xfe, 0x06, 0xf0, 0xfe, 0x74, 0x07, 0x95, 0x86, 0x02, 0x24, 0x08, 0x05, + 0x0a, 0xfe, 0x2e, 0x12, 0x16, 0x19, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, + 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0xfe, 0x99, 0xa4, 0x01, + 0x0b, 0x16, 0x00, 0x02, 0xfe, 0x42, 0x08, 0x68, 0x05, 0x1a, 0xfe, 0x38, + 0x12, 0x08, 0x05, 0x1a, 0xfe, 0x30, 0x13, 0x16, 0xfe, 0x1b, 0x00, 0x01, + 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, + 0x0b, 0x16, 0x06, 0x01, 0x0b, 0x16, 0x00, 0x02, 0xe2, 0x6c, 0x58, 0xbe, + 0x50, 0xfe, 0x9a, 0x81, 0x55, 0x1b, 0x7a, 0xfe, 0x42, 0x07, 0x09, 0x1b, + 0xfe, 0x09, 0x6f, 0xba, 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x69, 0x6d, + 0x8b, 0x6c, 0x7f, 0x27, 0xfe, 0x54, 0x07, 0x1c, 0x34, 0xfe, 0x0a, 0xf0, + 0xfe, 0x42, 0x07, 0x95, 0x86, 0x94, 0xfe, 0x6c, 0x07, 0x02, 0x24, 0x01, + 0x4b, 0x02, 0xdb, 0x16, 0x1f, 0x02, 0xdb, 0xfe, 0x9c, 0xf7, 0xdc, 0xfe, + 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x56, 0xfe, 0xda, 0x07, 0x0c, 0x60, 0x14, + 0x61, 0x08, 0x54, 0x5a, 0x37, 0x22, 0x20, 0x07, 0x11, 0xfe, 0x0e, 0x12, + 0x8d, 0xfe, 0x80, 0x80, 0x39, 0x20, 0x6a, 0x2a, 0xfe, 0x06, 0x10, 0xfe, + 0x83, 0xe7, 0xfe, 0x48, 0x00, 0xab, 0xfe, 0x03, 0x40, 0x08, 0x54, 0x5b, + 0x37, 0x01, 0xb3, 0xb8, 0xfe, 0x1f, 0x40, 0x13, 0x62, 0x01, 0xef, 0xfe, + 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0x88, + 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e, 0x14, 0x5f, 0xfe, 0x0c, + 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x0c, 0x3d, + 0x14, 0x3e, 0xfe, 0x4a, 0x10, 0x08, 0x05, 0x5a, 0xfe, 0x2a, 0x12, 0xfe, + 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x60, 0x14, 0x61, 0x08, 0x05, 0x5b, + 0x8b, 0x01, 0xb3, 0xfe, 0x1f, 0x80, 0x13, 0x62, 0xfe, 0x44, 0x90, 0xfe, + 0xc6, 0x90, 0x0c, 0x3f, 0x14, 0x40, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, + 0x0c, 0x5e, 0x14, 0x5f, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x3d, + 0x14, 0x3e, 0x0c, 0x2e, 0x14, 0x3c, 0x21, 0x0c, 0x49, 0x0c, 0x63, 0x08, + 0x54, 0x1f, 0x37, 0x2c, 0x0f, 0xfe, 0x4e, 0x11, 0x27, 0xdd, 0xfe, 0x9e, + 0xf0, 0xfe, 0x76, 0x08, 0xbc, 0x17, 0x34, 0x2c, 0x77, 0xe6, 0xc5, 0xfe, + 0x9a, 0x08, 0xc6, 0xfe, 0xb8, 0x08, 0x94, 0xfe, 0x8e, 0x08, 0xfe, 0x06, + 0xf0, 0xfe, 0x94, 0x08, 0x95, 0x86, 0x02, 0x24, 0x01, 0x4b, 0xfe, 0xc9, + 0x10, 0x16, 0x1f, 0xfe, 0xc9, 0x10, 0x68, 0x05, 0x06, 0xfe, 0x10, 0x12, + 0x68, 0x05, 0x0a, 0x4e, 0x08, 0x05, 0x0a, 0xfe, 0x90, 0x12, 0xfe, 0x2e, + 0x1c, 0x02, 0xfe, 0x18, 0x0b, 0x68, 0x05, 0x06, 0x4e, 0x68, 0x05, 0x0a, + 0xfe, 0x7a, 0x12, 0xfe, 0x2c, 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0xd2, 0x09, + 0xfe, 0xac, 0xf0, 0xfe, 0x00, 0x09, 0x02, 0xfe, 0xde, 0x09, 0xfe, 0xb7, + 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0x02, 0xf6, 0x1a, 0x50, 0xfe, 0x70, 0x18, + 0xfe, 0xf1, 0x18, 0xfe, 0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58, + 0xfe, 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x1c, 0x85, 0xfe, + 0x8c, 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0xac, 0xf0, 0xfe, 0xf0, 0x08, 0xb5, + 0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x0c, 0x09, 0x02, 0xfe, 0x18, + 0x0b, 0xb6, 0xfe, 0xbf, 0x10, 0xfe, 0x2b, 0xf0, 0x85, 0xf4, 0x1e, 0xfe, + 0x00, 0xfe, 0xfe, 0x1c, 0x12, 0xc2, 0xfe, 0xd2, 0xf0, 0x85, 0xfe, 0x76, + 0x18, 0x1e, 0x19, 0x17, 0x85, 0x03, 0xd2, 0x1e, 0x06, 0x17, 0x85, 0xc5, + 0x4a, 0xc6, 0x4a, 0xb5, 0xb6, 0xfe, 0x89, 0x10, 0x74, 0x67, 0x2d, 0x15, + 0x9d, 0x01, 0x36, 0x10, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x65, 0x10, + 0x80, 0x02, 0x65, 0xfe, 0x98, 0x80, 0xfe, 0x19, 0xe4, 0x0a, 0xfe, 0x1a, + 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18, 0xfe, 0x44, 0x54, 0xbe, + 0xfe, 0x19, 0x81, 0xfe, 0x74, 0x18, 0x8f, 0x90, 0x17, 0xfe, 0xce, 0x08, + 0x02, 0x4a, 0x08, 0x05, 0x5a, 0xec, 0x03, 0x2e, 0x29, 0x3c, 0x0c, 0x3f, + 0x14, 0x40, 0x9b, 0x2e, 0x9c, 0x3c, 0xfe, 0x6c, 0x18, 0xfe, 0xed, 0x18, + 0xfe, 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x3a, 0x3f, 0x3b, 0x40, 0x03, 0x49, + 0x29, 0x63, 0x8f, 0xfe, 0xe3, 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18, + 0x8f, 0xfe, 0xe3, 0x54, 0x90, 0xc0, 0x56, 0xfe, 0xce, 0x08, 0x02, 0x4a, + 0xfe, 0x37, 0xf0, 0xfe, 0xda, 0x09, 0xfe, 0x8b, 0xf0, 0xfe, 0x60, 0x09, + 0x02, 0x4a, 0x08, 0x05, 0x0a, 0x23, 0xfe, 0xfa, 0x0a, 0x3a, 0x49, 0x3b, + 0x63, 0x56, 0xfe, 0x3e, 0x0a, 0x0f, 0xfe, 0xc0, 0x07, 0x41, 0x98, 0x00, + 0xad, 0xfe, 0x01, 0x59, 0xfe, 0x52, 0xf0, 0xfe, 0x0c, 0x0a, 0x8f, 0x7a, + 0xfe, 0x24, 0x0a, 0x3a, 0x49, 0x8f, 0xfe, 0xe3, 0x54, 0x57, 0x49, 0x7d, + 0x63, 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02, 0x4a, 0x3a, 0x49, 0x3b, + 0x63, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xbe, 0x57, 0x49, 0x57, 0x63, + 0x02, 0x4a, 0x08, 0x05, 0x5a, 0xfe, 0x82, 0x12, 0x08, 0x05, 0x1f, 0xfe, + 0x66, 0x13, 0x22, 0x62, 0xb7, 0xfe, 0x03, 0xa1, 0xfe, 0x83, 0x80, 0xfe, + 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x6a, + 0x2a, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x56, 0xe0, 0x03, 0x60, 0x29, + 0x61, 0x0c, 0x7f, 0x14, 0x80, 0x57, 0x60, 0x7d, 0x61, 0x01, 0xb3, 0xb8, + 0x6a, 0x2a, 0x13, 0x62, 0x9b, 0x2e, 0x9c, 0x3c, 0x3a, 0x3f, 0x3b, 0x40, + 0x90, 0xc0, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0x01, 0xef, + 0xfe, 0x36, 0x10, 0x21, 0x0c, 0x7f, 0x0c, 0x80, 0x3a, 0x3f, 0x3b, 0x40, + 0xe4, 0x08, 0x05, 0x1f, 0x17, 0xe0, 0x3a, 0x3d, 0x3b, 0x3e, 0x08, 0x05, + 0xfe, 0xf7, 0x00, 0x37, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x10, 0x58, 0xfe, + 0x91, 0x58, 0x57, 0x49, 0x7d, 0x63, 0x02, 0xfe, 0xf4, 0x09, 0x08, 0x05, + 0x1f, 0x17, 0xe0, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0xbe, 0xfe, 0x19, + 0x81, 0x50, 0xfe, 0x10, 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd3, 0x10, 0x32, + 0x07, 0xa6, 0x17, 0xfe, 0x08, 0x09, 0x12, 0xa6, 0x08, 0x05, 0x0a, 0xfe, + 0x14, 0x13, 0x03, 0x3d, 0x29, 0x3e, 0x56, 0xfe, 0x08, 0x09, 0xfe, 0x0c, + 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x4a, 0x21, 0x41, 0xfe, 0x19, 0x80, 0xe7, + 0x08, 0x05, 0x0a, 0xfe, 0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, + 0xf4, 0xc2, 0xfe, 0xd1, 0xf0, 0xe2, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, + 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0x57, 0x3d, 0xfe, 0xed, + 0x19, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xf4, 0x1e, 0xfe, + 0x00, 0xff, 0x35, 0xfe, 0x74, 0x10, 0xc2, 0xfe, 0xd2, 0xf0, 0xfe, 0xa6, + 0x0b, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x8a, 0x03, 0xd2, 0x1e, 0x06, 0xfe, + 0x08, 0x13, 0x10, 0xfe, 0x16, 0x00, 0x02, 0x65, 0xfe, 0xd1, 0xf0, 0xfe, + 0xb8, 0x0b, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, 0x17, 0x00, 0xfe, 0x42, + 0x10, 0xfe, 0xce, 0xf0, 0xfe, 0xbe, 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, + 0xf0, 0xfe, 0xca, 0x0b, 0x10, 0xfe, 0x22, 0x00, 0x02, 0x65, 0xfe, 0xcb, + 0xf0, 0xfe, 0xd6, 0x0b, 0x10, 0xfe, 0x24, 0x00, 0x02, 0x65, 0xfe, 0xd0, + 0xf0, 0xfe, 0xe0, 0x0b, 0x10, 0x9e, 0xe5, 0xfe, 0xcf, 0xf0, 0xfe, 0xea, + 0x0b, 0x10, 0x58, 0xfe, 0x10, 0x10, 0xfe, 0xcc, 0xf0, 0xe2, 0x68, 0x05, + 0x1f, 0x4d, 0x10, 0xfe, 0x12, 0x00, 0x2c, 0x0f, 0xfe, 0x4e, 0x11, 0x27, + 0xfe, 0x00, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x14, 0x0c, 0xbc, 0x17, 0x34, + 0x2c, 0x77, 0xe6, 0xc5, 0x24, 0xc6, 0x24, 0x2c, 0xfa, 0x27, 0xfe, 0x20, + 0x0c, 0x1c, 0x34, 0x94, 0xfe, 0x3c, 0x0c, 0x95, 0x86, 0xc5, 0xdc, 0xc6, + 0xdc, 0x02, 0x24, 0x01, 0x4b, 0xfe, 0xdb, 0x10, 0x12, 0xfe, 0xe8, 0x00, + 0xb5, 0xb6, 0x74, 0xc7, 0x81, 0xc8, 0x83, 0xfe, 0x89, 0xf0, 0x24, 0x33, + 0x31, 0xe1, 0xc7, 0x81, 0xc8, 0x83, 0x27, 0xfe, 0x66, 0x0c, 0x1d, 0x24, + 0x33, 0x31, 0xdf, 0xbc, 0x4e, 0x10, 0xfe, 0x42, 0x00, 0x02, 0x65, 0x7c, + 0x06, 0xfe, 0x81, 0x49, 0x17, 0xfe, 0x2c, 0x0d, 0x08, 0x05, 0x0a, 0xfe, + 0x44, 0x13, 0x10, 0x00, 0x55, 0x0a, 0xfe, 0x54, 0x12, 0x55, 0xfe, 0x28, + 0x00, 0x23, 0xfe, 0x9a, 0x0d, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, + 0x44, 0xfe, 0x28, 0x00, 0xfe, 0xe2, 0x10, 0x01, 0xf5, 0x01, 0xf6, 0x09, + 0xa4, 0x01, 0xfe, 0x26, 0x0f, 0x64, 0x12, 0x2f, 0x01, 0x73, 0x02, 0x2b, + 0x10, 0xfe, 0x44, 0x00, 0x55, 0x0a, 0xe9, 0x44, 0x0a, 0xfe, 0xb4, 0x10, + 0x01, 0xb0, 0x44, 0x0a, 0xfe, 0xaa, 0x10, 0x01, 0xb0, 0xfe, 0x19, 0x82, + 0xfe, 0x34, 0x46, 0xac, 0x44, 0x0a, 0x10, 0xfe, 0x43, 0x00, 0xfe, 0x96, + 0x10, 0x08, 0x54, 0x0a, 0x37, 0x01, 0xf5, 0x01, 0xf6, 0x64, 0x12, 0x2f, + 0x01, 0x73, 0x99, 0x0a, 0x64, 0x42, 0x92, 0x02, 0xfe, 0x2e, 0x03, 0x08, + 0x05, 0x0a, 0x8a, 0x44, 0x0a, 0x10, 0x00, 0xfe, 0x5c, 0x10, 0x68, 0x05, + 0x1a, 0xfe, 0x58, 0x12, 0x08, 0x05, 0x1a, 0xfe, 0x50, 0x13, 0xfe, 0x1c, + 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x50, 0x0d, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, + 0xf0, 0xfe, 0x56, 0x0d, 0x08, 0x54, 0x1a, 0x37, 0xfe, 0xa9, 0x10, 0x10, + 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0a, 0x50, 0xfe, 0x2e, 0x10, 0x10, + 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x10, 0x6f, 0xab, 0x10, 0xfe, 0x41, + 0x00, 0xaa, 0x10, 0xfe, 0x24, 0x00, 0x8c, 0xb5, 0xb6, 0x74, 0x03, 0x70, + 0x28, 0x23, 0xd8, 0x50, 0xfe, 0x04, 0xe6, 0x1a, 0xfe, 0x9d, 0x41, 0xfe, + 0x1c, 0x42, 0x64, 0x01, 0xe3, 0x02, 0x2b, 0xf8, 0x15, 0x0a, 0x39, 0xa0, + 0xb4, 0x15, 0xfe, 0x31, 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, 0x02, + 0xd7, 0x42, 0xfe, 0x06, 0xec, 0xd0, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, + 0x35, 0x42, 0xfe, 0x06, 0xea, 0xd0, 0xfe, 0x47, 0x4b, 0x91, 0xfe, 0x75, + 0x57, 0x03, 0x5d, 0xfe, 0x98, 0x56, 0xfe, 0x38, 0x12, 0x09, 0x48, 0x01, + 0x0e, 0xfe, 0x44, 0x48, 0x4f, 0x08, 0x05, 0x1b, 0xfe, 0x1a, 0x13, 0x09, + 0x46, 0x01, 0x0e, 0x41, 0xfe, 0x41, 0x58, 0x09, 0xa4, 0x01, 0x0e, 0xfe, + 0x49, 0x54, 0x96, 0xfe, 0x1e, 0x0e, 0x02, 0xfe, 0x2e, 0x03, 0x09, 0x5d, + 0xfe, 0xee, 0x14, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe, + 0xce, 0x47, 0xfe, 0xad, 0x13, 0x02, 0x2b, 0x22, 0x20, 0x07, 0x11, 0xfe, + 0x9e, 0x12, 0x21, 0x13, 0x59, 0x13, 0x9f, 0x13, 0xd5, 0x22, 0x2f, 0x41, + 0x39, 0x2f, 0xbc, 0xad, 0xfe, 0xbc, 0xf0, 0xfe, 0xe0, 0x0e, 0x0f, 0x06, + 0x13, 0x59, 0x01, 0xfe, 0xda, 0x16, 0x03, 0xfe, 0x38, 0x01, 0x29, 0xfe, + 0x3a, 0x01, 0x56, 0xfe, 0xe4, 0x0e, 0xfe, 0x02, 0xec, 0xd5, 0x69, 0x00, + 0x66, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01, + 0x01, 0xfe, 0x4a, 0x17, 0xfe, 0x08, 0x90, 0xfe, 0x48, 0xf4, 0x0d, 0xfe, + 0x18, 0x13, 0xba, 0xfe, 0x02, 0xea, 0xd5, 0x69, 0x7e, 0xfe, 0xc5, 0x13, + 0x15, 0x1a, 0x39, 0xa0, 0xb4, 0xfe, 0x2e, 0x10, 0x03, 0xfe, 0x38, 0x01, + 0x1e, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x03, 0xfe, 0x3a, 0x01, + 0x0c, 0xfe, 0x62, 0x01, 0x43, 0x13, 0x20, 0x25, 0x06, 0x13, 0x2f, 0x12, + 0x2f, 0x92, 0x0f, 0x06, 0x04, 0x21, 0x04, 0x22, 0x59, 0xfe, 0xf7, 0x12, + 0x22, 0x9f, 0xb7, 0x13, 0x9f, 0x07, 0x7e, 0xfe, 0x71, 0x13, 0xfe, 0x24, + 0x1c, 0x15, 0x19, 0x39, 0xa0, 0xb4, 0xfe, 0xd9, 0x10, 0xc3, 0xfe, 0x03, + 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xc3, 0xfe, 0x03, 0xdc, + 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x21, + 0xfe, 0x00, 0xcc, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x78, 0x04, 0x08, 0x05, + 0x58, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13, + 0xfe, 0x1e, 0x80, 0xed, 0xfe, 0x1d, 0x80, 0xae, 0xfe, 0x0c, 0x90, 0xfe, + 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xac, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, + 0x0a, 0xfe, 0x3c, 0x50, 0xaa, 0x01, 0xfe, 0x7a, 0x17, 0x32, 0x07, 0x2f, + 0xad, 0x01, 0xfe, 0xb4, 0x16, 0x08, 0x05, 0x1b, 0x4e, 0x01, 0xf5, 0x01, + 0xf6, 0x12, 0xfe, 0xe9, 0x00, 0x08, 0x05, 0x58, 0xfe, 0x2c, 0x13, 0x01, + 0xfe, 0x0c, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90, + 0x0c, 0xfe, 0x64, 0x01, 0x14, 0xfe, 0x66, 0x01, 0x08, 0x05, 0x5b, 0xfe, + 0x12, 0x12, 0xfe, 0x03, 0x80, 0x8d, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80, + 0x40, 0x13, 0x20, 0x6a, 0x2a, 0x12, 0xcf, 0x64, 0x22, 0x20, 0xfb, 0x79, + 0x20, 0x04, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58, + 0x03, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, + 0x08, 0x58, 0x03, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, + 0x25, 0x6e, 0x13, 0xd0, 0x21, 0x0c, 0x5c, 0x0c, 0x45, 0x0f, 0x46, 0x52, + 0x50, 0x18, 0x1b, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xfe, 0xfc, + 0x0f, 0x44, 0x11, 0x0f, 0x48, 0x52, 0x18, 0x58, 0xfe, 0x90, 0x4d, 0xfe, + 0x91, 0x54, 0x23, 0xe4, 0x25, 0x11, 0x13, 0x20, 0x7c, 0x6f, 0x4f, 0x22, + 0x20, 0xfb, 0x79, 0x20, 0x12, 0xcf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, + 0xfe, 0x26, 0x10, 0xf8, 0x74, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, + 0x18, 0x1c, 0x04, 0x42, 0xfe, 0x0c, 0x14, 0xfc, 0xfe, 0x07, 0xe6, 0x1b, + 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x04, 0x01, 0xb0, 0x7c, 0x6f, 0x4f, + 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0x32, 0x07, 0x2f, + 0xfe, 0x34, 0x13, 0x09, 0x48, 0x01, 0x0e, 0xbb, 0xfe, 0x36, 0x12, 0xfe, + 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, + 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, 0x84, 0x01, 0x0e, 0xfe, + 0x80, 0x5c, 0x01, 0x73, 0xfe, 0x0e, 0x10, 0x07, 0x82, 0x4e, 0xfe, 0x14, + 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x60, 0x10, 0x04, 0xfe, 0x44, 0x58, 0x8d, + 0xfe, 0x01, 0xec, 0xa2, 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, + 0x9c, 0xe7, 0x1a, 0x79, 0x2a, 0x01, 0xe3, 0xfe, 0xdd, 0x10, 0x2c, 0xc7, + 0x81, 0xc8, 0x83, 0x33, 0x31, 0xde, 0x07, 0x1a, 0xfe, 0x48, 0x12, 0x07, + 0x0a, 0xfe, 0x56, 0x12, 0x07, 0x19, 0xfe, 0x30, 0x12, 0x07, 0xc9, 0x17, + 0xfe, 0x32, 0x12, 0x07, 0xfe, 0x23, 0x00, 0x17, 0xeb, 0x07, 0x06, 0x17, + 0xfe, 0x9c, 0x12, 0x07, 0x1f, 0xfe, 0x12, 0x12, 0x07, 0x00, 0x17, 0x24, + 0x15, 0xc9, 0x01, 0x36, 0xa9, 0x2d, 0x01, 0x0b, 0x94, 0x4b, 0x04, 0x2d, + 0xdd, 0x09, 0xd1, 0x01, 0xfe, 0x26, 0x0f, 0x12, 0x82, 0x02, 0x2b, 0x2d, + 0x32, 0x07, 0xa6, 0xfe, 0xd9, 0x13, 0x3a, 0x3d, 0x3b, 0x3e, 0x56, 0xfe, + 0xf0, 0x11, 0x08, 0x05, 0x5a, 0xfe, 0x72, 0x12, 0x9b, 0x2e, 0x9c, 0x3c, + 0x90, 0xc0, 0x96, 0xfe, 0xba, 0x11, 0x22, 0x62, 0xfe, 0x26, 0x13, 0x03, + 0x7f, 0x29, 0x80, 0x56, 0xfe, 0x76, 0x0d, 0x0c, 0x60, 0x14, 0x61, 0x21, + 0x0c, 0x7f, 0x0c, 0x80, 0x01, 0xb3, 0x25, 0x6e, 0x77, 0x13, 0x62, 0x01, + 0xef, 0x9b, 0x2e, 0x9c, 0x3c, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, + 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0xfe, 0x91, 0x10, 0x03, 0x3f, + 0x29, 0x40, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x3f, 0x14, 0x40, + 0x88, 0x9b, 0x2e, 0x9c, 0x3c, 0x90, 0xc0, 0x03, 0x5e, 0x29, 0x5f, 0xfe, + 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x0c, 0x5e, 0x14, 0x5f, 0x08, 0x05, 0x5a, + 0xfe, 0x1e, 0x12, 0x22, 0x62, 0xfe, 0x1f, 0x40, 0x03, 0x60, 0x29, 0x61, + 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x03, 0x3f, 0x29, 0x40, 0xfe, 0x44, + 0x50, 0xfe, 0xc6, 0x50, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x08, 0x50, 0xfe, + 0x8a, 0x50, 0x03, 0x3d, 0x29, 0x3e, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, + 0x02, 0x89, 0x25, 0x06, 0x13, 0xd4, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1d, + 0x4c, 0x33, 0x31, 0xde, 0x07, 0x06, 0x23, 0x4c, 0x32, 0x07, 0xa6, 0x23, + 0x72, 0x01, 0xaf, 0x1e, 0x43, 0x17, 0x4c, 0x08, 0x05, 0x0a, 0xee, 0x3a, + 0x3d, 0x3b, 0x3e, 0xfe, 0x0a, 0x55, 0x35, 0xfe, 0x8b, 0x55, 0x57, 0x3d, + 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x02, 0x72, 0xfe, 0x19, + 0x81, 0xba, 0xfe, 0x19, 0x41, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1c, 0x34, + 0x1d, 0xe8, 0x33, 0x31, 0xe1, 0x55, 0x19, 0xfe, 0xa6, 0x12, 0x55, 0x0a, + 0x4d, 0x02, 0x4c, 0x01, 0x0b, 0x1c, 0x34, 0x1d, 0xe8, 0x33, 0x31, 0xdf, + 0x07, 0x19, 0x23, 0x4c, 0x01, 0x0b, 0x1d, 0xe8, 0x33, 0x31, 0xfe, 0xe8, + 0x09, 0xfe, 0xc2, 0x49, 0x51, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0x8a, 0x53, + 0x05, 0x1f, 0x35, 0xa9, 0xfe, 0xbb, 0x45, 0x55, 0x00, 0x4e, 0x44, 0x06, + 0x7c, 0x43, 0xfe, 0xda, 0x14, 0x01, 0xaf, 0x8c, 0xfe, 0x4b, 0x45, 0xee, + 0x32, 0x07, 0xa5, 0xed, 0x03, 0xcd, 0x28, 0x8a, 0x03, 0x45, 0x28, 0x35, + 0x67, 0x02, 0x72, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17, + 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, + 0xfe, 0x9e, 0x15, 0x02, 0x89, 0x01, 0x0b, 0x1c, 0x34, 0x1d, 0x4c, 0x33, + 0x31, 0xdf, 0x07, 0x06, 0x23, 0x4c, 0x01, 0xf1, 0xfe, 0x42, 0x58, 0xf1, + 0xfe, 0xa4, 0x14, 0x8c, 0xfe, 0x4a, 0xf4, 0x0a, 0x17, 0x4c, 0xfe, 0x4a, + 0xf4, 0x06, 0xea, 0x32, 0x07, 0xa5, 0x8b, 0x02, 0x72, 0x03, 0x45, 0xc1, + 0x0c, 0x45, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, 0xfe, 0xcc, 0x15, + 0x02, 0x89, 0x0f, 0x06, 0x27, 0xfe, 0xbe, 0x13, 0x26, 0xfe, 0xd4, 0x13, + 0x76, 0xfe, 0x89, 0x48, 0x01, 0x0b, 0x21, 0x76, 0x04, 0x7b, 0xfe, 0xd0, + 0x13, 0x1c, 0xfe, 0xd0, 0x13, 0x1d, 0xfe, 0xbe, 0x13, 0x67, 0x2d, 0x01, + 0x0b, 0xfe, 0xd5, 0x10, 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, + 0x1e, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x04, 0x0f, + 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0xfe, 0x30, 0x56, + 0xfe, 0x00, 0x5c, 0x04, 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, + 0x04, 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0xfe, 0x0b, 0x58, + 0x04, 0x09, 0x5c, 0x01, 0x87, 0x09, 0x45, 0x01, 0x87, 0x04, 0xfe, 0x03, + 0xa1, 0x1e, 0x11, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x1f, 0x52, + 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, + 0x6a, 0x2a, 0x0c, 0x5e, 0x14, 0x5f, 0x57, 0x3f, 0x7d, 0x40, 0x04, 0xdd, + 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x8d, 0x04, 0x01, + 0xfe, 0x0c, 0x19, 0xfe, 0x42, 0x48, 0x50, 0x51, 0x91, 0x01, 0x0b, 0x1d, + 0xfe, 0x96, 0x15, 0x33, 0x31, 0xe1, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15, + 0x33, 0x31, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x03, 0xcd, 0x28, 0xfe, + 0xcc, 0x12, 0x53, 0x05, 0x1a, 0xfe, 0xc4, 0x13, 0x21, 0x69, 0x1a, 0xee, + 0x55, 0xca, 0x6b, 0xfe, 0xdc, 0x14, 0x4d, 0x0f, 0x06, 0x18, 0xca, 0x7c, + 0x30, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xab, 0xff, 0x02, 0x83, + 0x55, 0x69, 0x19, 0xae, 0x98, 0xfe, 0x30, 0x00, 0x96, 0xf2, 0x18, 0x6d, + 0x0f, 0x06, 0xfe, 0x56, 0x10, 0x69, 0x0a, 0xed, 0x98, 0xfe, 0x64, 0x00, + 0x96, 0xf2, 0x09, 0xfe, 0x64, 0x00, 0x18, 0x9e, 0x0f, 0x06, 0xfe, 0x28, + 0x10, 0x69, 0x06, 0xfe, 0x60, 0x13, 0x98, 0xfe, 0xc8, 0x00, 0x96, 0xf2, + 0x09, 0xfe, 0xc8, 0x00, 0x18, 0x59, 0x0f, 0x06, 0x88, 0x98, 0xfe, 0x90, + 0x01, 0x7a, 0xfe, 0x42, 0x15, 0x91, 0xe4, 0xfe, 0x43, 0xf4, 0x9f, 0xfe, + 0x56, 0xf0, 0xfe, 0x54, 0x15, 0xfe, 0x04, 0xf4, 0x71, 0xfe, 0x43, 0xf4, + 0x9e, 0xfe, 0xf3, 0x10, 0xfe, 0x40, 0x5c, 0x01, 0xfe, 0x16, 0x14, 0x1e, + 0x43, 0xec, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x6e, 0x7a, 0xfe, 0x90, + 0x15, 0xc4, 0x6e, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, + 0xcc, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0xcc, 0x88, 0x51, 0x21, 0xfe, 0x4d, + 0xf4, 0x00, 0xe9, 0x91, 0x0f, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, + 0x04, 0x51, 0x0f, 0x0a, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xf3, 0x16, + 0x0a, 0x01, 0x0b, 0x26, 0xf3, 0x16, 0x19, 0x01, 0x0b, 0x26, 0xf3, 0x76, + 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1, + 0x16, 0x19, 0x01, 0x0b, 0x26, 0xb1, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1, + 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x26, 0xb1, 0x76, 0xfe, 0x89, 0x4a, 0x01, + 0x0b, 0x04, 0x51, 0x04, 0x22, 0xd3, 0x07, 0x06, 0xfe, 0x48, 0x13, 0xb8, + 0x13, 0xd3, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x76, 0xa9, 0x67, 0xfe, 0x01, + 0xec, 0xfe, 0x27, 0x01, 0xfe, 0x89, 0x48, 0xff, 0x02, 0x00, 0x10, 0x27, + 0xfe, 0x2e, 0x16, 0x32, 0x07, 0xfe, 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1d, + 0xfe, 0x52, 0x16, 0x21, 0x13, 0xd4, 0x01, 0x4b, 0x22, 0xd4, 0x07, 0x06, + 0x4e, 0x08, 0x54, 0x06, 0x37, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfb, 0x8e, + 0x07, 0x11, 0xae, 0x09, 0x84, 0x01, 0x0e, 0x8e, 0x09, 0x5d, 0x01, 0xa8, + 0x04, 0x09, 0x84, 0x01, 0x0e, 0x8e, 0xfe, 0x80, 0xe7, 0x11, 0x07, 0x11, + 0x8a, 0xfe, 0x45, 0x58, 0x01, 0xf0, 0x8e, 0x04, 0x09, 0x48, 0x01, 0x0e, + 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x80, + 0x80, 0xfe, 0x80, 0x4c, 0xfe, 0x49, 0xe4, 0x11, 0xae, 0x09, 0x84, 0x01, + 0x0e, 0xfe, 0x80, 0x4c, 0x09, 0x5d, 0x01, 0x87, 0x04, 0x18, 0x11, 0x75, + 0x6c, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24, + 0x1c, 0xfe, 0x1d, 0xf7, 0x1b, 0x97, 0xfe, 0xee, 0x16, 0x01, 0xfe, 0xf4, + 0x17, 0xad, 0x9a, 0x1b, 0x6c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x04, + 0xb9, 0x23, 0xfe, 0xde, 0x16, 0xfe, 0xda, 0x10, 0x18, 0x11, 0x75, 0x03, + 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1f, 0xfe, 0x18, 0x58, 0x03, 0xfe, + 0x66, 0x01, 0xfe, 0x19, 0x58, 0x9a, 0x1f, 0xfe, 0x3c, 0x90, 0xfe, 0x30, + 0xf4, 0x06, 0xfe, 0x3c, 0x50, 0x6c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, + 0xfe, 0x1c, 0xf7, 0x1f, 0x97, 0xfe, 0x38, 0x17, 0xfe, 0xb6, 0x14, 0x35, + 0x04, 0xb9, 0x23, 0xfe, 0x10, 0x17, 0xfe, 0x9c, 0x10, 0x18, 0x11, 0x75, + 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, + 0x2e, 0x97, 0xfe, 0x5a, 0x17, 0xfe, 0x94, 0x14, 0xec, 0x9a, 0x2e, 0x6c, + 0x1a, 0xfe, 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00, 0x04, 0xb9, 0x23, 0xfe, + 0x4e, 0x17, 0xfe, 0x6c, 0x10, 0x18, 0x11, 0x75, 0xfe, 0x30, 0xbc, 0xfe, + 0xb2, 0xbc, 0x9a, 0xcb, 0x6c, 0x1a, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, + 0xcb, 0x97, 0xfe, 0x92, 0x17, 0xfe, 0x5c, 0x14, 0x35, 0x04, 0xb9, 0x23, + 0xfe, 0x7e, 0x17, 0xfe, 0x42, 0x10, 0xfe, 0x02, 0xf6, 0x11, 0x75, 0xfe, + 0x18, 0xfe, 0x60, 0xfe, 0x19, 0xfe, 0x61, 0xfe, 0x03, 0xa1, 0xfe, 0x1d, + 0xf7, 0x5b, 0x97, 0xfe, 0xb8, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, + 0x9a, 0x5b, 0x41, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, + 0x11, 0xfe, 0x81, 0xe7, 0x11, 0x12, 0xfe, 0xdd, 0x00, 0x6a, 0x2a, 0x04, + 0x6a, 0x2a, 0xfe, 0x12, 0x45, 0x23, 0xfe, 0xa8, 0x17, 0x15, 0x06, 0x39, + 0xa0, 0xb4, 0x02, 0x2b, 0xfe, 0x39, 0xf0, 0xfe, 0xfc, 0x17, 0x21, 0x04, + 0xfe, 0x7e, 0x18, 0x1e, 0x19, 0x66, 0x0f, 0x0d, 0x04, 0x75, 0x03, 0xd2, + 0x1e, 0x06, 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x7c, 0x6f, 0x4f, 0x32, + 0x07, 0x2f, 0xfe, 0x3c, 0x13, 0xf1, 0xfe, 0x42, 0x13, 0x42, 0x92, 0x09, + 0x48, 0x01, 0x0e, 0xbb, 0xeb, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, + 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, + 0xac, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c, 0x01, 0x73, 0xfe, 0x16, + 0x10, 0x07, 0x82, 0x8b, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12, 0xfe, 0x14, + 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x1c, 0x18, 0x18, 0x0a, 0x04, 0xfe, 0x9c, + 0xe7, 0x0a, 0x10, 0xfe, 0x15, 0x00, 0x64, 0x79, 0x2a, 0x01, 0xe3, 0x18, + 0x06, 0x04, 0x42, 0x92, 0x08, 0x54, 0x1b, 0x37, 0x12, 0x2f, 0x01, 0x73, + 0x18, 0x06, 0x04, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x3a, 0xce, 0x3b, + 0xcf, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x04, 0x22, 0xa3, 0x77, + 0x13, 0xa3, 0x04, 0x09, 0xa4, 0x01, 0x0e, 0xfe, 0x41, 0x48, 0x09, 0x46, + 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x17, 0xfe, 0xe8, 0x18, 0x77, 0x78, 0x04, + 0x09, 0x48, 0x01, 0x0e, 0x07, 0x11, 0x4e, 0x09, 0x5d, 0x01, 0xa8, 0x09, + 0x46, 0x01, 0x0e, 0x77, 0x78, 0x04, 0xfe, 0x4e, 0xe4, 0x19, 0x6b, 0xfe, + 0x1c, 0x19, 0x03, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, + 0xfe, 0x4e, 0xe4, 0xc9, 0x6b, 0xfe, 0x2e, 0x19, 0x03, 0xfe, 0x92, 0x00, + 0xfe, 0x02, 0xe6, 0x1a, 0xe5, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x6b, + 0xfe, 0x40, 0x19, 0x03, 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x1f, 0xfe, + 0x08, 0x10, 0x03, 0xfe, 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x6d, 0xfe, 0x4e, + 0x45, 0xea, 0xba, 0xff, 0x04, 0x68, 0x54, 0xe7, 0x1e, 0x6e, 0xfe, 0x08, + 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe, 0x1a, 0xf4, 0xfe, 0x00, + 0x04, 0xea, 0xfe, 0x48, 0xf4, 0x19, 0x7a, 0xfe, 0x74, 0x19, 0x0f, 0x19, + 0x04, 0x07, 0x7e, 0xfe, 0x5a, 0xf0, 0xfe, 0x84, 0x19, 0x25, 0xfe, 0x09, + 0x00, 0xfe, 0x34, 0x10, 0x07, 0x1a, 0xfe, 0x5a, 0xf0, 0xfe, 0x92, 0x19, + 0x25, 0xca, 0xfe, 0x26, 0x10, 0x07, 0x19, 0x66, 0x25, 0x6d, 0xe5, 0x07, + 0x0a, 0x66, 0x25, 0x9e, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x66, 0x25, 0x59, + 0xa9, 0xb8, 0x04, 0x15, 0xfe, 0x09, 0x00, 0x01, 0x36, 0xfe, 0x04, 0xfe, + 0x81, 0x03, 0x83, 0xfe, 0x40, 0x5c, 0x04, 0x1c, 0xf7, 0xfe, 0x14, 0xf0, + 0x0b, 0x27, 0xfe, 0xd6, 0x19, 0x1c, 0xf7, 0x7b, 0xf7, 0xfe, 0x82, 0xf0, + 0xfe, 0xda, 0x19, 0x04, 0xff, 0xcc, 0x00, 0x00, +}; + +static unsigned short _adv_asc38C0800_size = sizeof(_adv_asc38C0800_buf); /* 0x14E1 */ +static ADV_DCNT _adv_asc38C0800_chksum = 0x050D3FD8UL; /* Expanded little-endian checksum. */ + +/* Microcode buffer is kept after initialization for error recovery. */ +static unsigned char _adv_asc38C1600_buf[] = { + 0x00, 0x00, 0x00, 0xf2, 0x00, 0x16, 0x00, 0xfc, 0x00, 0x10, 0x00, 0xf0, + 0x18, 0xe4, 0x01, 0x00, 0x04, 0x1e, 0x48, 0xe4, 0x03, 0xf6, 0xf7, 0x13, + 0x2e, 0x1e, 0x02, 0x00, 0x07, 0x17, 0xc0, 0x5f, 0x00, 0xfa, 0xff, 0xff, + 0x04, 0x00, 0x00, 0xf6, 0x09, 0xe7, 0x82, 0xe7, 0x85, 0xf0, 0x86, 0xf0, + 0x4e, 0x10, 0x9e, 0xe7, 0xff, 0x00, 0x55, 0xf0, 0x01, 0xf6, 0x03, 0x00, + 0x98, 0x57, 0x01, 0xe6, 0x00, 0xea, 0x00, 0xec, 0x01, 0xfa, 0x18, 0xf4, + 0x08, 0x00, 0xf0, 0x1d, 0x38, 0x54, 0x32, 0xf0, 0x10, 0x00, 0xc2, 0x0e, + 0x1e, 0xf0, 0xd5, 0xf0, 0xbc, 0x00, 0x4b, 0xe4, 0x00, 0xe6, 0xb1, 0xf0, + 0xb4, 0x00, 0x02, 0x13, 0x3e, 0x1c, 0xc8, 0x47, 0x3e, 0x00, 0xd8, 0x01, + 0x06, 0x13, 0x0c, 0x1c, 0x5e, 0x1e, 0x00, 0x57, 0xc8, 0x57, 0x01, 0xfc, + 0xbc, 0x0e, 0xa2, 0x12, 0xb9, 0x54, 0x00, 0x80, 0x62, 0x0a, 0x5a, 0x12, + 0xc8, 0x15, 0x3e, 0x1e, 0x18, 0x40, 0xbd, 0x56, 0x03, 0xe6, 0x01, 0xea, + 0x5c, 0xf0, 0x0f, 0x00, 0x20, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12, + 0x04, 0x13, 0xbb, 0x55, 0x3c, 0x56, 0x3e, 0x57, 0x03, 0x58, 0x4a, 0xe4, + 0x40, 0x00, 0xb6, 0x00, 0xbb, 0x00, 0xc0, 0x00, 0x00, 0x01, 0x01, 0x01, + 0x3e, 0x01, 0x58, 0x0a, 0x44, 0x10, 0x0a, 0x12, 0x4c, 0x1c, 0x4e, 0x1c, + 0x02, 0x4a, 0x30, 0xe4, 0x05, 0xe6, 0x0c, 0x00, 0x3c, 0x00, 0x80, 0x00, + 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, + 0x74, 0x01, 0x76, 0x01, 0x78, 0x01, 0x7c, 0x01, 0xc6, 0x0e, 0x0c, 0x10, + 0xac, 0x12, 0xae, 0x12, 0x16, 0x1a, 0x32, 0x1c, 0x6e, 0x1e, 0x02, 0x48, + 0x3a, 0x55, 0xc9, 0x57, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x06, 0xf7, + 0x03, 0xfc, 0x06, 0x00, 0x1e, 0x00, 0xbe, 0x00, 0xe1, 0x00, 0x0c, 0x12, + 0x18, 0x1a, 0x70, 0x1a, 0x30, 0x1c, 0x38, 0x1c, 0x10, 0x44, 0x00, 0x4c, + 0xb0, 0x57, 0x40, 0x5c, 0x4d, 0xe4, 0x04, 0xea, 0x5d, 0xf0, 0xa7, 0xf0, + 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x09, 0x00, 0x19, 0x00, 0x32, 0x00, + 0x33, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00, 0x9e, 0x00, 0xcc, 0x00, + 0x20, 0x01, 0x4e, 0x01, 0x79, 0x01, 0x3c, 0x09, 0x68, 0x0d, 0x02, 0x10, + 0x04, 0x10, 0x3a, 0x10, 0x08, 0x12, 0x0a, 0x13, 0x40, 0x16, 0x50, 0x16, + 0x00, 0x17, 0x4a, 0x19, 0x00, 0x4e, 0x00, 0x54, 0x01, 0x58, 0x00, 0xdc, + 0x05, 0xf0, 0x09, 0xf0, 0x59, 0xf0, 0xb8, 0xf0, 0x48, 0xf4, 0x0e, 0xf7, + 0x0a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, + 0xd0, 0x00, 0xe7, 0x00, 0xf0, 0x03, 0x69, 0x08, 0xe9, 0x09, 0x5c, 0x0c, + 0xb6, 0x12, 0xbc, 0x19, 0xd8, 0x1b, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, + 0x42, 0x1d, 0x08, 0x44, 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, + 0x89, 0x48, 0x68, 0x54, 0x83, 0x55, 0x83, 0x59, 0x31, 0xe4, 0x02, 0xe6, + 0x07, 0xf0, 0x08, 0xf0, 0x0b, 0xf0, 0x0c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, + 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, + 0xa8, 0x00, 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0x22, 0x01, + 0x26, 0x01, 0x60, 0x01, 0x7a, 0x01, 0x82, 0x01, 0xc8, 0x01, 0xca, 0x01, + 0x86, 0x02, 0x6a, 0x03, 0x18, 0x05, 0xb2, 0x07, 0x68, 0x08, 0x10, 0x0d, + 0x06, 0x10, 0x0a, 0x10, 0x0e, 0x10, 0x12, 0x10, 0x60, 0x10, 0xed, 0x10, + 0xf3, 0x10, 0x06, 0x12, 0x10, 0x12, 0x1e, 0x12, 0x0c, 0x13, 0x0e, 0x13, + 0x10, 0x13, 0xfe, 0x9c, 0xf0, 0x35, 0x05, 0xfe, 0xec, 0x0e, 0xff, 0x10, + 0x00, 0x00, 0xe9, 0xfe, 0x34, 0x1f, 0x00, 0xe8, 0xfe, 0x88, 0x01, 0xff, + 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00, + 0x00, 0xfe, 0x57, 0x24, 0x00, 0xfe, 0x4c, 0x00, 0x65, 0xff, 0x04, 0x00, + 0x00, 0x1a, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x08, + 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x13, + 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00, + 0xfe, 0x04, 0xf7, 0xe8, 0x37, 0x7d, 0x0d, 0x01, 0xfe, 0x4a, 0x11, 0xfe, + 0x04, 0xf7, 0xe8, 0x7d, 0x0d, 0x51, 0x37, 0xfe, 0x3d, 0xf0, 0xfe, 0x0c, + 0x02, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x91, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, + 0x90, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x8f, 0xf0, 0xbc, 0x03, 0x67, 0x4d, + 0x05, 0xfe, 0x08, 0x0f, 0x01, 0xfe, 0x78, 0x0f, 0xfe, 0xdd, 0x12, 0x05, + 0xfe, 0x0e, 0x03, 0xfe, 0x28, 0x1c, 0x03, 0xfe, 0xa6, 0x00, 0xfe, 0xd1, + 0x12, 0x3e, 0x22, 0xfe, 0xa6, 0x00, 0xac, 0xfe, 0x48, 0xf0, 0xfe, 0x90, + 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0xaa, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc8, + 0x02, 0xfe, 0x46, 0xf0, 0xfe, 0x5a, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x60, + 0x02, 0xfe, 0x43, 0xf0, 0xfe, 0x4e, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x52, + 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x56, 0x02, 0x1c, 0x0d, 0xa2, 0x1c, 0x07, + 0x22, 0xb7, 0x05, 0x35, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02, + 0x1c, 0xf5, 0xfe, 0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0x5f, 0xfe, 0xe7, + 0x10, 0xfe, 0x06, 0xfc, 0xde, 0x0a, 0x81, 0x01, 0xa3, 0x05, 0x35, 0x1f, + 0x95, 0x47, 0xb8, 0x01, 0xfe, 0xe4, 0x11, 0x0a, 0x81, 0x01, 0x5c, 0xfe, + 0xbd, 0x10, 0x0a, 0x81, 0x01, 0x5c, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, + 0xfe, 0x58, 0x1c, 0x1c, 0x07, 0x22, 0xb7, 0x37, 0x2a, 0x35, 0xfe, 0x3d, + 0xf0, 0xfe, 0x0c, 0x02, 0x2b, 0xfe, 0x9e, 0x02, 0xfe, 0x5a, 0x1c, 0xfe, + 0x12, 0x1c, 0xfe, 0x14, 0x1c, 0x1f, 0xfe, 0x30, 0x00, 0x47, 0xb8, 0x01, + 0xfe, 0xd4, 0x11, 0x1c, 0x07, 0x22, 0xb7, 0x05, 0xe9, 0x21, 0x2c, 0x09, + 0x1a, 0x31, 0xfe, 0x69, 0x10, 0x1c, 0x07, 0x22, 0xb7, 0xfe, 0x04, 0xec, + 0x2c, 0x60, 0x01, 0xfe, 0x1e, 0x1e, 0x20, 0x2c, 0xfe, 0x05, 0xf6, 0xde, + 0x01, 0xfe, 0x62, 0x1b, 0x01, 0x0c, 0x61, 0x4a, 0x44, 0x15, 0x56, 0x51, + 0x01, 0xfe, 0x9e, 0x1e, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x0a, 0x57, + 0x01, 0x18, 0x09, 0x00, 0x36, 0x01, 0x85, 0xfe, 0x18, 0x10, 0xfe, 0x41, + 0x58, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0xc8, 0x54, 0x7b, 0xfe, 0x1c, 0x03, + 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x37, 0x60, 0xfe, 0x02, 0xe8, 0x30, + 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, 0x27, 0xf0, + 0xfe, 0xe4, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x40, + 0x1c, 0x2a, 0xeb, 0xfe, 0x26, 0xf0, 0xfe, 0x66, 0x03, 0xfe, 0xa0, 0xf0, + 0xfe, 0x54, 0x03, 0xfe, 0x11, 0xf0, 0xbc, 0xfe, 0xef, 0x10, 0xfe, 0x9f, + 0xf0, 0xfe, 0x74, 0x03, 0xfe, 0x46, 0x1c, 0x19, 0xfe, 0x11, 0x00, 0x05, + 0x70, 0x37, 0xfe, 0x48, 0x1c, 0xfe, 0x46, 0x1c, 0x01, 0x0c, 0x06, 0x28, + 0xfe, 0x18, 0x13, 0x26, 0x21, 0xb9, 0xc7, 0x20, 0xb9, 0x0a, 0x57, 0x01, + 0x18, 0xc7, 0x89, 0x01, 0xfe, 0xc8, 0x1a, 0x15, 0xe1, 0x2a, 0xeb, 0xfe, + 0x01, 0xf0, 0xeb, 0xfe, 0x82, 0xf0, 0xfe, 0xa4, 0x03, 0xfe, 0x9c, 0x32, + 0x15, 0xfe, 0xe4, 0x00, 0x2f, 0xfe, 0xb6, 0x03, 0x2a, 0x3c, 0x16, 0xfe, + 0xc6, 0x03, 0x01, 0x41, 0xfe, 0x06, 0xf0, 0xfe, 0xd6, 0x03, 0xaf, 0xa0, + 0xfe, 0x0a, 0xf0, 0xfe, 0xa2, 0x07, 0x05, 0x29, 0x03, 0x81, 0x1e, 0x1b, + 0xfe, 0x24, 0x05, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, 0x05, + 0xea, 0xfe, 0x46, 0x1c, 0x37, 0x7d, 0x1d, 0xfe, 0x67, 0x1b, 0xfe, 0xbf, + 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c, 0x75, 0x01, 0xa6, 0x86, 0x0a, + 0x57, 0x01, 0x18, 0x09, 0x00, 0x1b, 0xec, 0x0a, 0xe1, 0x01, 0x18, 0x77, + 0x50, 0x40, 0x8d, 0x30, 0x03, 0x81, 0x1e, 0xf8, 0x1f, 0x63, 0x01, 0x42, + 0x8f, 0xfe, 0x70, 0x02, 0x05, 0xea, 0xd7, 0x99, 0xd8, 0x9c, 0x2a, 0x29, + 0x2f, 0xfe, 0x4e, 0x04, 0x16, 0xfe, 0x4a, 0x04, 0x7e, 0xfe, 0xa0, 0x00, + 0xfe, 0x9b, 0x57, 0xfe, 0x54, 0x12, 0x32, 0xff, 0x02, 0x00, 0x10, 0x01, + 0x08, 0x16, 0xfe, 0x02, 0x05, 0x32, 0x01, 0x08, 0x16, 0x29, 0x27, 0x25, + 0xee, 0xfe, 0x4c, 0x44, 0xfe, 0x58, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x13, + 0x34, 0xfe, 0x4c, 0x54, 0x7b, 0xec, 0x60, 0x8d, 0x30, 0x01, 0xfe, 0x4e, + 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x7c, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xfe, + 0x32, 0x13, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x68, 0x13, 0xfe, 0x26, 0x10, + 0x13, 0x34, 0xfe, 0x4c, 0x54, 0x7b, 0xec, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, + 0x48, 0x47, 0xfe, 0x54, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xa5, 0x01, 0x43, + 0x09, 0x9b, 0xfe, 0x40, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xf9, 0x1f, 0x7f, + 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, 0x8f, + 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x32, 0x15, 0xfe, 0xe6, 0x00, 0x0f, 0xfe, + 0x1c, 0x90, 0x04, 0xfe, 0x9c, 0x93, 0x3a, 0x0b, 0x0e, 0x8b, 0x02, 0x1f, + 0x7f, 0x01, 0x42, 0x05, 0x35, 0xfe, 0x42, 0x5b, 0x7d, 0x1d, 0xfe, 0x46, + 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0x0f, 0xfe, 0x87, 0x80, 0x04, + 0xfe, 0x87, 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0xd0, 0x65, 0x01, 0x0c, + 0x06, 0x0d, 0xfe, 0x98, 0x13, 0x0f, 0xfe, 0x20, 0x80, 0x04, 0xfe, 0xa0, + 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x1d, 0xfe, 0x84, 0x12, 0x01, 0x38, 0x06, + 0x07, 0xfe, 0x70, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x1e, 0x1b, 0xfe, 0xda, + 0x05, 0xd0, 0x54, 0x01, 0x38, 0x06, 0x0d, 0xfe, 0x58, 0x13, 0x03, 0xfe, + 0xa0, 0x00, 0x1e, 0xfe, 0x50, 0x12, 0x5e, 0xff, 0x02, 0x00, 0x10, 0x2f, + 0xfe, 0x90, 0x05, 0x2a, 0x3c, 0xcc, 0xff, 0x02, 0x00, 0x10, 0x2f, 0xfe, + 0x9e, 0x05, 0x17, 0xfe, 0xf4, 0x05, 0x15, 0xfe, 0xe3, 0x00, 0x26, 0x01, + 0x38, 0xfe, 0x4a, 0xf0, 0xfe, 0xc0, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0xba, + 0x05, 0x71, 0x2e, 0xfe, 0x21, 0x00, 0xf1, 0x2e, 0xfe, 0x22, 0x00, 0xa2, + 0x2e, 0x4a, 0xfe, 0x09, 0x48, 0xff, 0x02, 0x00, 0x10, 0x2f, 0xfe, 0xd0, + 0x05, 0x17, 0xfe, 0xf4, 0x05, 0xfe, 0xe2, 0x08, 0x01, 0x38, 0x06, 0xfe, + 0x1c, 0x00, 0x4d, 0x01, 0xa7, 0x2e, 0x07, 0x20, 0xe4, 0x47, 0xfe, 0x27, + 0x01, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x24, 0x12, 0x3e, 0x01, 0x84, 0x1f, + 0x7f, 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, + 0x8f, 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x03, 0xe6, 0x1e, 0xfe, 0xca, 0x13, + 0x03, 0xb6, 0x1e, 0xfe, 0x40, 0x12, 0x03, 0x66, 0x1e, 0xfe, 0x38, 0x13, + 0x3e, 0x01, 0x84, 0x17, 0xfe, 0x72, 0x06, 0x0a, 0x07, 0x01, 0x38, 0x06, + 0x24, 0xfe, 0x02, 0x12, 0x4f, 0x01, 0xfe, 0x56, 0x19, 0x16, 0xfe, 0x68, + 0x06, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x66, 0x8a, 0x10, 0x66, + 0x03, 0x9a, 0x1e, 0xfe, 0x70, 0x12, 0x03, 0x55, 0x1e, 0xfe, 0x68, 0x13, + 0x01, 0xc6, 0x09, 0x12, 0x48, 0xfe, 0x92, 0x06, 0x2e, 0x12, 0x01, 0xfe, + 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0x13, 0x58, 0xff, 0x02, 0x00, + 0x57, 0x52, 0xad, 0x23, 0x3f, 0x4e, 0x62, 0x49, 0x3e, 0x01, 0x84, 0x17, + 0xfe, 0xea, 0x06, 0x01, 0x38, 0x06, 0x12, 0xf7, 0x45, 0x0a, 0x95, 0x01, + 0xfe, 0x84, 0x19, 0x16, 0xfe, 0xe0, 0x06, 0x15, 0x82, 0x01, 0x41, 0x15, + 0xe2, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x1c, 0x07, 0x01, 0x84, 0xfe, 0xae, + 0x10, 0x03, 0x6f, 0x1e, 0xfe, 0x9e, 0x13, 0x3e, 0x01, 0x84, 0x03, 0x9a, + 0x1e, 0xfe, 0x1a, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfc, 0x01, 0xc6, 0x01, + 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0xf0, 0x45, 0x0a, 0x95, + 0x03, 0xb6, 0x1e, 0xf8, 0x01, 0x38, 0x06, 0x24, 0x36, 0xfe, 0x02, 0xf6, + 0x07, 0x71, 0x78, 0x8c, 0x00, 0x4d, 0x62, 0x49, 0x3e, 0x2d, 0x93, 0x4e, + 0xd0, 0x0d, 0x17, 0xfe, 0x9a, 0x07, 0x01, 0xfe, 0xc0, 0x19, 0x16, 0xfe, + 0x90, 0x07, 0x26, 0x20, 0x9e, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x21, + 0x9e, 0x09, 0x07, 0xfb, 0x03, 0xe6, 0xfe, 0x58, 0x57, 0x10, 0xe6, 0x05, + 0xfe, 0x2a, 0x06, 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x1c, 0x07, 0x01, 0x84, + 0xfe, 0x9c, 0x32, 0x5f, 0x75, 0x01, 0xa6, 0x86, 0x15, 0xfe, 0xe2, 0x00, + 0x2f, 0xed, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe, 0xce, 0x07, 0xae, 0xfe, + 0x96, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x9e, 0x08, 0xaf, 0xa0, 0x05, 0x29, + 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x2e, 0x12, 0x14, 0x1d, 0x01, 0x08, 0x14, + 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0xfe, + 0x99, 0xa4, 0x01, 0x08, 0x14, 0x00, 0x05, 0xfe, 0xc6, 0x09, 0x01, 0x76, + 0x06, 0x12, 0xfe, 0x3a, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x30, 0x13, + 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00, + 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x07, 0x01, 0x08, 0x14, 0x00, + 0x05, 0xef, 0x7c, 0x4a, 0x78, 0x4f, 0x0f, 0xfe, 0x9a, 0x81, 0x04, 0xfe, + 0x9a, 0x83, 0xfe, 0xcb, 0x47, 0x0b, 0x0e, 0x2d, 0x28, 0x48, 0xfe, 0x6c, + 0x08, 0x0a, 0x28, 0xfe, 0x09, 0x6f, 0xca, 0xfe, 0xca, 0x45, 0xfe, 0x32, + 0x12, 0x53, 0x63, 0x4e, 0x7c, 0x97, 0x2f, 0xfe, 0x7e, 0x08, 0x2a, 0x3c, + 0xfe, 0x0a, 0xf0, 0xfe, 0x6c, 0x08, 0xaf, 0xa0, 0xae, 0xfe, 0x96, 0x08, + 0x05, 0x29, 0x01, 0x41, 0x05, 0xed, 0x14, 0x24, 0x05, 0xed, 0xfe, 0x9c, + 0xf7, 0x9f, 0x01, 0xfe, 0xae, 0x1e, 0xfe, 0x18, 0x58, 0x01, 0xfe, 0xbe, + 0x1e, 0xfe, 0x99, 0x58, 0xfe, 0x78, 0x18, 0xfe, 0xf9, 0x18, 0x8e, 0xfe, + 0x16, 0x09, 0x10, 0x6a, 0x22, 0x6b, 0x01, 0x0c, 0x61, 0x54, 0x44, 0x21, + 0x2c, 0x09, 0x1a, 0xf8, 0x77, 0x01, 0xfe, 0x7e, 0x1e, 0x47, 0x2c, 0x7a, + 0x30, 0xf0, 0xfe, 0x83, 0xe7, 0xfe, 0x3f, 0x00, 0x71, 0xfe, 0x03, 0x40, + 0x01, 0x0c, 0x61, 0x65, 0x44, 0x01, 0xc2, 0xc8, 0xfe, 0x1f, 0x40, 0x20, + 0x6e, 0x01, 0xfe, 0x6a, 0x16, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, + 0x44, 0x51, 0xfe, 0xc6, 0x51, 0xfe, 0x10, 0x10, 0x01, 0xfe, 0xce, 0x1e, + 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x01, 0xfe, 0xee, 0x1e, + 0x01, 0xfe, 0xfe, 0x1e, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x10, 0x4b, + 0x22, 0x4c, 0xfe, 0x8a, 0x10, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0x50, 0x12, + 0x01, 0xfe, 0xae, 0x1e, 0x01, 0xfe, 0xbe, 0x1e, 0x10, 0x6a, 0x22, 0x6b, + 0x01, 0x0c, 0x06, 0x65, 0x4e, 0x01, 0xc2, 0x0f, 0xfe, 0x1f, 0x80, 0x04, + 0xfe, 0x9f, 0x83, 0x33, 0x0b, 0x0e, 0x20, 0x6e, 0x0f, 0xfe, 0x44, 0x90, + 0x04, 0xfe, 0xc4, 0x93, 0x3a, 0x0b, 0xfe, 0xc6, 0x90, 0x04, 0xfe, 0xc6, + 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x6c, 0x22, 0x6d, 0x01, 0xfe, 0xce, 0x1e, + 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x0f, 0xfe, 0x40, 0x90, + 0x04, 0xfe, 0xc0, 0x93, 0x3a, 0x0b, 0xfe, 0xc2, 0x90, 0x04, 0xfe, 0xc2, + 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x4b, 0x22, 0x4c, 0x10, 0x64, 0x22, 0x34, + 0x01, 0x0c, 0x61, 0x24, 0x44, 0x37, 0x13, 0xfe, 0x4e, 0x11, 0x2f, 0xfe, + 0xde, 0x09, 0xfe, 0x9e, 0xf0, 0xfe, 0xf2, 0x09, 0xfe, 0x01, 0x48, 0x1b, + 0x3c, 0x37, 0x88, 0xf5, 0xd4, 0xfe, 0x1e, 0x0a, 0xd5, 0xfe, 0x42, 0x0a, + 0xd2, 0xfe, 0x1e, 0x0a, 0xd3, 0xfe, 0x42, 0x0a, 0xae, 0xfe, 0x12, 0x0a, + 0xfe, 0x06, 0xf0, 0xfe, 0x18, 0x0a, 0xaf, 0xa0, 0x05, 0x29, 0x01, 0x41, + 0xfe, 0xc1, 0x10, 0x14, 0x24, 0xfe, 0xc1, 0x10, 0x01, 0x76, 0x06, 0x07, + 0xfe, 0x14, 0x12, 0x01, 0x76, 0x06, 0x0d, 0x5d, 0x01, 0x0c, 0x06, 0x0d, + 0xfe, 0x74, 0x12, 0xfe, 0x2e, 0x1c, 0x05, 0xfe, 0x1a, 0x0c, 0x01, 0x76, + 0x06, 0x07, 0x5d, 0x01, 0x76, 0x06, 0x0d, 0x41, 0xfe, 0x2c, 0x1c, 0xfe, + 0xaa, 0xf0, 0xfe, 0xce, 0x0a, 0xfe, 0xac, 0xf0, 0xfe, 0x66, 0x0a, 0xfe, + 0x92, 0x10, 0xc4, 0xf6, 0xfe, 0xad, 0xf0, 0xfe, 0x72, 0x0a, 0x05, 0xfe, + 0x1a, 0x0c, 0xc5, 0xfe, 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0xbf, 0xfe, 0x6b, + 0x18, 0x23, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12, 0xac, 0xfe, 0xd2, 0xf0, + 0xbf, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x1b, 0xbf, 0x03, 0xe3, 0x23, 0x07, + 0x1b, 0xbf, 0xd4, 0x5b, 0xd5, 0x5b, 0xd2, 0x5b, 0xd3, 0x5b, 0xc4, 0xc5, + 0xfe, 0xa9, 0x10, 0x75, 0x5e, 0x32, 0x1f, 0x7f, 0x01, 0x42, 0x19, 0xfe, + 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x70, 0x19, 0x98, 0x05, 0x70, 0xfe, 0x74, + 0x18, 0x23, 0xfe, 0x00, 0xf8, 0x1b, 0x5b, 0x7d, 0x12, 0x01, 0xfe, 0x78, + 0x0f, 0x4d, 0x01, 0xfe, 0x96, 0x1a, 0x21, 0x30, 0x77, 0x7d, 0x1d, 0x05, + 0x5b, 0x01, 0x0c, 0x06, 0x0d, 0x2b, 0xfe, 0xe2, 0x0b, 0x01, 0x0c, 0x06, + 0x54, 0xfe, 0xa6, 0x12, 0x01, 0x0c, 0x06, 0x24, 0xfe, 0x88, 0x13, 0x21, + 0x6e, 0xc7, 0x01, 0xfe, 0x1e, 0x1f, 0x0f, 0xfe, 0x83, 0x80, 0x04, 0xfe, + 0x83, 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0xfe, 0xc8, 0x44, 0xfe, 0x42, + 0x13, 0x0f, 0xfe, 0x04, 0x91, 0x04, 0xfe, 0x84, 0x93, 0xfe, 0xca, 0x57, + 0x0b, 0xfe, 0x86, 0x91, 0x04, 0xfe, 0x86, 0x93, 0xfe, 0xcb, 0x57, 0x0b, + 0x0e, 0x7a, 0x30, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x8e, 0x40, 0x03, + 0x6a, 0x3b, 0x6b, 0x10, 0x97, 0x22, 0x98, 0xd9, 0x6a, 0xda, 0x6b, 0x01, + 0xc2, 0xc8, 0x7a, 0x30, 0x20, 0x6e, 0xdb, 0x64, 0xdc, 0x34, 0x91, 0x6c, + 0x7e, 0x6d, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55, 0xfe, 0x04, 0xfa, 0x64, + 0xfe, 0x05, 0xfa, 0x34, 0x01, 0xfe, 0x6a, 0x16, 0xa3, 0x26, 0x10, 0x97, + 0x10, 0x98, 0x91, 0x6c, 0x7e, 0x6d, 0xfe, 0x14, 0x10, 0x01, 0x0c, 0x06, + 0x24, 0x1b, 0x40, 0x91, 0x4b, 0x7e, 0x4c, 0x01, 0x0c, 0x06, 0xfe, 0xf7, + 0x00, 0x44, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, + 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x24, + 0x1b, 0x40, 0x01, 0x0c, 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x78, 0x01, 0xfe, + 0x8e, 0x1e, 0x4f, 0x0f, 0xfe, 0x10, 0x90, 0x04, 0xfe, 0x90, 0x93, 0x3a, + 0x0b, 0xfe, 0x92, 0x90, 0x04, 0xfe, 0x92, 0x93, 0x79, 0x0b, 0x0e, 0xfe, + 0xbd, 0x10, 0x01, 0x43, 0x09, 0xbb, 0x1b, 0xfe, 0x6e, 0x0a, 0x15, 0xbb, + 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x14, 0x13, 0x03, 0x4b, 0x3b, 0x4c, 0x8e, + 0xfe, 0x6e, 0x0a, 0xfe, 0x0c, 0x58, 0xfe, 0x8d, 0x58, 0x05, 0x5b, 0x26, + 0x3e, 0x0f, 0xfe, 0x19, 0x80, 0x04, 0xfe, 0x99, 0x83, 0x33, 0x0b, 0x0e, + 0xfe, 0xe5, 0x10, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1a, 0x12, 0xfe, 0x6c, + 0x19, 0xfe, 0x19, 0x41, 0xfe, 0x6b, 0x18, 0xac, 0xfe, 0xd1, 0xf0, 0xef, + 0x1f, 0x92, 0x01, 0x42, 0x19, 0xfe, 0x44, 0x00, 0xfe, 0x90, 0x10, 0xfe, + 0x6c, 0x19, 0xd9, 0x4b, 0xfe, 0xed, 0x19, 0xda, 0x4c, 0xfe, 0x0c, 0x51, + 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xff, 0x31, 0xfe, + 0x76, 0x10, 0xac, 0xfe, 0xd2, 0xf0, 0xfe, 0xba, 0x0c, 0xfe, 0x76, 0x18, + 0x23, 0x1d, 0x5d, 0x03, 0xe3, 0x23, 0x07, 0xfe, 0x08, 0x13, 0x19, 0xfe, + 0x16, 0x00, 0x05, 0x70, 0xfe, 0xd1, 0xf0, 0xfe, 0xcc, 0x0c, 0x1f, 0x92, + 0x01, 0x42, 0x19, 0xfe, 0x17, 0x00, 0x5c, 0xfe, 0xce, 0xf0, 0xfe, 0xd2, + 0x0c, 0xfe, 0x3e, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xde, 0x0c, 0x19, 0xfe, + 0x22, 0x00, 0x05, 0x70, 0xfe, 0xcb, 0xf0, 0xfe, 0xea, 0x0c, 0x19, 0xfe, + 0x24, 0x00, 0x05, 0x70, 0xfe, 0xd0, 0xf0, 0xfe, 0xf4, 0x0c, 0x19, 0x94, + 0xfe, 0x1c, 0x10, 0xfe, 0xcf, 0xf0, 0xfe, 0xfe, 0x0c, 0x19, 0x4a, 0xf3, + 0xfe, 0xcc, 0xf0, 0xef, 0x01, 0x76, 0x06, 0x24, 0x4d, 0x19, 0xfe, 0x12, + 0x00, 0x37, 0x13, 0xfe, 0x4e, 0x11, 0x2f, 0xfe, 0x16, 0x0d, 0xfe, 0x9e, + 0xf0, 0xfe, 0x2a, 0x0d, 0xfe, 0x01, 0x48, 0x1b, 0x3c, 0x37, 0x88, 0xf5, + 0xd4, 0x29, 0xd5, 0x29, 0xd2, 0x29, 0xd3, 0x29, 0x37, 0xfe, 0x9c, 0x32, + 0x2f, 0xfe, 0x3e, 0x0d, 0x2a, 0x3c, 0xae, 0xfe, 0x62, 0x0d, 0xaf, 0xa0, + 0xd4, 0x9f, 0xd5, 0x9f, 0xd2, 0x9f, 0xd3, 0x9f, 0x05, 0x29, 0x01, 0x41, + 0xfe, 0xd3, 0x10, 0x15, 0xfe, 0xe8, 0x00, 0xc4, 0xc5, 0x75, 0xd7, 0x99, + 0xd8, 0x9c, 0xfe, 0x89, 0xf0, 0x29, 0x27, 0x25, 0xbe, 0xd7, 0x99, 0xd8, + 0x9c, 0x2f, 0xfe, 0x8c, 0x0d, 0x16, 0x29, 0x27, 0x25, 0xbd, 0xfe, 0x01, + 0x48, 0xa4, 0x19, 0xfe, 0x42, 0x00, 0x05, 0x70, 0x90, 0x07, 0xfe, 0x81, + 0x49, 0x1b, 0xfe, 0x64, 0x0e, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x44, 0x13, + 0x19, 0x00, 0x2d, 0x0d, 0xfe, 0x54, 0x12, 0x2d, 0xfe, 0x28, 0x00, 0x2b, + 0xfe, 0xda, 0x0e, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, 0x36, 0x46, 0xfe, + 0x28, 0x00, 0xfe, 0xfa, 0x10, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe, 0x00, + 0x1d, 0x0a, 0xba, 0x01, 0xfe, 0x58, 0x10, 0x40, 0x15, 0x56, 0x01, 0x85, + 0x05, 0x35, 0x19, 0xfe, 0x44, 0x00, 0x2d, 0x0d, 0xf7, 0x46, 0x0d, 0xfe, + 0xcc, 0x10, 0x01, 0xa7, 0x46, 0x0d, 0xfe, 0xc2, 0x10, 0x01, 0xa7, 0x0f, + 0xfe, 0x19, 0x82, 0x04, 0xfe, 0x99, 0x83, 0xfe, 0xcc, 0x47, 0x0b, 0x0e, + 0xfe, 0x34, 0x46, 0xa5, 0x46, 0x0d, 0x19, 0xfe, 0x43, 0x00, 0xfe, 0xa2, + 0x10, 0x01, 0x0c, 0x61, 0x0d, 0x44, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe, + 0x00, 0x1d, 0x40, 0x15, 0x56, 0x01, 0x85, 0x7d, 0x0d, 0x40, 0x51, 0x01, + 0xfe, 0x9e, 0x1e, 0x05, 0xfe, 0x3a, 0x03, 0x01, 0x0c, 0x06, 0x0d, 0x5d, + 0x46, 0x0d, 0x19, 0x00, 0xfe, 0x62, 0x10, 0x01, 0x76, 0x06, 0x12, 0xfe, + 0x5c, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x52, 0x13, 0xfe, 0x1c, 0x1c, + 0xfe, 0x9d, 0xf0, 0xfe, 0x8e, 0x0e, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, + 0xfe, 0x94, 0x0e, 0x01, 0x0c, 0x61, 0x12, 0x44, 0xfe, 0x9f, 0x10, 0x19, + 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0d, 0x4f, 0xfe, 0x2e, 0x10, 0x19, + 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x19, 0xfe, 0x47, 0x00, 0xf1, 0x19, + 0xfe, 0x41, 0x00, 0xa2, 0x19, 0xfe, 0x24, 0x00, 0x86, 0xc4, 0xc5, 0x75, + 0x03, 0x81, 0x1e, 0x2b, 0xea, 0x4f, 0xfe, 0x04, 0xe6, 0x12, 0xfe, 0x9d, + 0x41, 0xfe, 0x1c, 0x42, 0x40, 0x01, 0xf4, 0x05, 0x35, 0xfe, 0x12, 0x1c, + 0x1f, 0x0d, 0x47, 0xb5, 0xc3, 0x1f, 0xfe, 0x31, 0x00, 0x47, 0xb8, 0x01, + 0xfe, 0xd4, 0x11, 0x05, 0xe9, 0x51, 0xfe, 0x06, 0xec, 0xe0, 0xfe, 0x0e, + 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0x06, 0xea, 0xe0, + 0xfe, 0x47, 0x4b, 0x45, 0xfe, 0x75, 0x57, 0x03, 0x67, 0xfe, 0x98, 0x56, + 0xfe, 0x38, 0x12, 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x44, 0x48, 0x60, 0x01, + 0x0c, 0x06, 0x28, 0xfe, 0x18, 0x13, 0x0a, 0x57, 0x01, 0x18, 0x3e, 0xfe, + 0x41, 0x58, 0x0a, 0xba, 0xfe, 0xfa, 0x14, 0xfe, 0x49, 0x54, 0xb0, 0xfe, + 0x5e, 0x0f, 0x05, 0xfe, 0x3a, 0x03, 0x0a, 0x67, 0xfe, 0xe0, 0x14, 0xfe, + 0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0xce, 0x47, + 0xfe, 0xad, 0x13, 0x05, 0x35, 0x21, 0x2c, 0x09, 0x1a, 0xfe, 0x98, 0x12, + 0x26, 0x20, 0x96, 0x20, 0xe7, 0xfe, 0x08, 0x1c, 0xfe, 0x7c, 0x19, 0xfe, + 0xfd, 0x19, 0xfe, 0x0a, 0x1c, 0x03, 0xe5, 0xfe, 0x48, 0x55, 0xa5, 0x3b, + 0xfe, 0x62, 0x01, 0xfe, 0xc9, 0x55, 0x31, 0xfe, 0x74, 0x10, 0x01, 0xfe, + 0xf0, 0x1a, 0x03, 0xfe, 0x38, 0x01, 0x3b, 0xfe, 0x3a, 0x01, 0x8e, 0xfe, + 0x1e, 0x10, 0xfe, 0x02, 0xec, 0xe7, 0x53, 0x00, 0x36, 0xfe, 0x04, 0xec, + 0x2c, 0x60, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x62, 0x1b, + 0x01, 0xfe, 0xce, 0x1e, 0xb2, 0x11, 0xfe, 0x18, 0x13, 0xca, 0xfe, 0x02, + 0xea, 0xe7, 0x53, 0x92, 0xfe, 0xc3, 0x13, 0x1f, 0x12, 0x47, 0xb5, 0xc3, + 0xfe, 0x2a, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x23, 0xfe, 0xf0, 0xff, 0x10, + 0xe5, 0x03, 0xfe, 0x3a, 0x01, 0x10, 0xfe, 0x62, 0x01, 0x01, 0xfe, 0x1e, + 0x1e, 0x20, 0x2c, 0x15, 0x56, 0x01, 0xfe, 0x9e, 0x1e, 0x13, 0x07, 0x02, + 0x26, 0x02, 0x21, 0x96, 0xc7, 0x20, 0x96, 0x09, 0x92, 0xfe, 0x79, 0x13, + 0x1f, 0x1d, 0x47, 0xb5, 0xc3, 0xfe, 0xe1, 0x10, 0xcf, 0xfe, 0x03, 0xdc, + 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xcf, 0xfe, 0x03, 0xdc, 0xfe, + 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x26, 0xfe, + 0x00, 0xcc, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x89, 0x02, 0x01, 0x0c, 0x06, + 0x4a, 0xfe, 0x4e, 0x13, 0x0f, 0xfe, 0x1c, 0x80, 0x04, 0xfe, 0x9c, 0x83, + 0x33, 0x0b, 0x0e, 0x09, 0x07, 0xfe, 0x3a, 0x13, 0x0f, 0xfe, 0x1e, 0x80, + 0x04, 0xfe, 0x9e, 0x83, 0x33, 0x0b, 0x0e, 0xfe, 0x2a, 0x13, 0x0f, 0xfe, + 0x1d, 0x80, 0x04, 0xfe, 0x9d, 0x83, 0xfe, 0xf9, 0x13, 0x0e, 0xfe, 0x1c, + 0x13, 0x01, 0xfe, 0xee, 0x1e, 0xac, 0xfe, 0x14, 0x13, 0x01, 0xfe, 0xfe, + 0x1e, 0xfe, 0x81, 0x58, 0xfa, 0x01, 0xfe, 0x0e, 0x1f, 0xfe, 0x30, 0xf4, + 0x0d, 0xfe, 0x3c, 0x50, 0xa2, 0x01, 0xfe, 0x92, 0x1b, 0x01, 0x43, 0x09, + 0x56, 0xfb, 0x01, 0xfe, 0xc8, 0x1a, 0x01, 0x0c, 0x06, 0x28, 0xa4, 0x01, + 0xfe, 0xf4, 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x15, 0xfe, 0xe9, 0x00, 0x01, + 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x01, 0xfe, 0x22, 0x1b, 0xfe, 0x1e, + 0x1c, 0x0f, 0xfe, 0x14, 0x90, 0x04, 0xfe, 0x94, 0x93, 0x3a, 0x0b, 0xfe, + 0x96, 0x90, 0x04, 0xfe, 0x96, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0xfe, 0x64, + 0x01, 0x22, 0xfe, 0x66, 0x01, 0x01, 0x0c, 0x06, 0x65, 0xf9, 0x0f, 0xfe, + 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b, 0x0e, 0x77, 0xfe, 0x01, + 0xec, 0x2c, 0xfe, 0x80, 0x40, 0x20, 0x2c, 0x7a, 0x30, 0x15, 0xdf, 0x40, + 0x21, 0x2c, 0xfe, 0x00, 0x40, 0x8d, 0x2c, 0x02, 0xfe, 0x08, 0x1c, 0x03, + 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58, 0x03, 0xfe, 0xae, 0x00, 0xfe, 0x07, + 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe, 0xb2, 0x00, + 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x2e, 0x49, 0x20, 0xe0, 0x26, 0x10, + 0x66, 0x10, 0x55, 0x10, 0x6f, 0x13, 0x57, 0x52, 0x4f, 0x1c, 0x28, 0xfe, + 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x2b, 0xfe, 0x88, 0x11, 0x46, 0x1a, 0x13, + 0x5a, 0x52, 0x1c, 0x4a, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x2b, 0xfe, + 0x9e, 0x11, 0x2e, 0x1a, 0x20, 0x2c, 0x90, 0x34, 0x60, 0x21, 0x2c, 0xfe, + 0x00, 0x40, 0x8d, 0x2c, 0x15, 0xdf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, + 0xfe, 0xb2, 0x11, 0xfe, 0x12, 0x1c, 0x75, 0xfe, 0x14, 0x1c, 0xfe, 0x10, + 0x1c, 0xfe, 0x18, 0x1c, 0x02, 0x51, 0xfe, 0x0c, 0x14, 0xfe, 0x0e, 0x47, + 0xfe, 0x07, 0xe6, 0x28, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x02, 0x01, + 0xa7, 0x90, 0x34, 0x60, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, + 0x13, 0xfe, 0x02, 0x80, 0x09, 0x56, 0xfe, 0x34, 0x13, 0x0a, 0x5a, 0x01, + 0x18, 0xcb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, + 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, 0x89, + 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x5c, 0x01, 0x85, + 0xf2, 0x09, 0x9b, 0xa4, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xec, + 0x11, 0x02, 0xfe, 0x44, 0x58, 0x77, 0xfe, 0x01, 0xec, 0xb8, 0xfe, 0x9e, + 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x12, 0x8d, 0x30, 0x01, + 0xf4, 0xfe, 0xdd, 0x10, 0x37, 0xd7, 0x99, 0xd8, 0x9c, 0x27, 0x25, 0xee, + 0x09, 0x12, 0xfe, 0x48, 0x12, 0x09, 0x0d, 0xfe, 0x56, 0x12, 0x09, 0x1d, + 0xfe, 0x30, 0x12, 0x09, 0xdd, 0x1b, 0xfe, 0xc4, 0x13, 0x09, 0xfe, 0x23, + 0x00, 0x1b, 0xfe, 0xd0, 0x13, 0x09, 0x07, 0x1b, 0xfe, 0x34, 0x14, 0x09, + 0x24, 0xfe, 0x12, 0x12, 0x09, 0x00, 0x1b, 0x29, 0x1f, 0xdd, 0x01, 0x42, + 0xa1, 0x32, 0x01, 0x08, 0xae, 0x41, 0x02, 0x32, 0xfe, 0x62, 0x08, 0x0a, + 0xe1, 0x01, 0xfe, 0x58, 0x10, 0x15, 0x9b, 0x05, 0x35, 0x32, 0x01, 0x43, + 0x09, 0xbb, 0xfe, 0xd7, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0x8e, 0xfe, 0x80, + 0x13, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0x72, 0x12, 0xdb, 0x64, 0xdc, 0x34, + 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55, 0xb0, 0xfe, 0x4a, 0x13, 0x21, 0x6e, + 0xfe, 0x26, 0x13, 0x03, 0x97, 0x3b, 0x98, 0x8e, 0xfe, 0xb6, 0x0e, 0x10, + 0x6a, 0x22, 0x6b, 0x26, 0x10, 0x97, 0x10, 0x98, 0x01, 0xc2, 0x2e, 0x49, + 0x88, 0x20, 0x6e, 0x01, 0xfe, 0x6a, 0x16, 0xdb, 0x64, 0xdc, 0x34, 0xfe, + 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x64, 0xfe, 0x05, 0xfa, + 0x34, 0xfe, 0x8f, 0x10, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x40, 0x56, 0xfe, + 0xe1, 0x56, 0x10, 0x6c, 0x22, 0x6d, 0x71, 0xdb, 0x64, 0xdc, 0x34, 0xfe, + 0x44, 0x55, 0xfe, 0xe5, 0x55, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x00, 0x56, + 0xfe, 0xa1, 0x56, 0x10, 0x68, 0x22, 0x69, 0x01, 0x0c, 0x06, 0x54, 0xf9, + 0x21, 0x6e, 0xfe, 0x1f, 0x40, 0x03, 0x6a, 0x3b, 0x6b, 0xfe, 0x2c, 0x50, + 0xfe, 0xae, 0x50, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x44, 0x50, 0xfe, 0xc6, + 0x50, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, + 0x4b, 0x3b, 0x4c, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x05, 0x73, 0x2e, + 0x07, 0x20, 0x9e, 0x05, 0x72, 0x32, 0x01, 0x08, 0x16, 0x3d, 0x27, 0x25, + 0xee, 0x09, 0x07, 0x2b, 0x3d, 0x01, 0x43, 0x09, 0xbb, 0x2b, 0x72, 0x01, + 0xa6, 0x23, 0x3f, 0x1b, 0x3d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1e, 0x13, + 0x91, 0x4b, 0x7e, 0x4c, 0xfe, 0x0a, 0x55, 0x31, 0xfe, 0x8b, 0x55, 0xd9, + 0x4b, 0xda, 0x4c, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x05, 0x72, 0x01, + 0xfe, 0x8e, 0x1e, 0xca, 0xfe, 0x19, 0x41, 0x05, 0x72, 0x32, 0x01, 0x08, + 0x2a, 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbe, 0x2d, 0x1d, 0xc0, 0x2d, 0x0d, + 0x83, 0x2d, 0x7f, 0x1b, 0xfe, 0x66, 0x15, 0x05, 0x3d, 0x01, 0x08, 0x2a, + 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbd, 0x09, 0x1d, 0x2b, 0x3d, 0x01, 0x08, + 0x16, 0xc0, 0x27, 0x25, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x50, 0x03, + 0xb6, 0x1e, 0x83, 0x01, 0x38, 0x06, 0x24, 0x31, 0xa1, 0xfe, 0xbb, 0x45, + 0x2d, 0x00, 0xa4, 0x46, 0x07, 0x90, 0x3f, 0x01, 0xfe, 0xf8, 0x15, 0x01, + 0xa6, 0x86, 0xfe, 0x4b, 0x45, 0xfe, 0x20, 0x13, 0x01, 0x43, 0x09, 0x82, + 0xfe, 0x16, 0x13, 0x03, 0x9a, 0x1e, 0x5d, 0x03, 0x55, 0x1e, 0x31, 0x5e, + 0x05, 0x72, 0xfe, 0xc0, 0x5d, 0x01, 0xa7, 0xfe, 0x03, 0x17, 0x03, 0x66, + 0x8a, 0x10, 0x66, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01, 0xfe, 0x56, + 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d, 0x27, 0x25, 0xbd, + 0x09, 0x07, 0x2b, 0x3d, 0x01, 0xfe, 0xbe, 0x16, 0xfe, 0x42, 0x58, 0xfe, + 0xe8, 0x14, 0x01, 0xa6, 0x86, 0xfe, 0x4a, 0xf4, 0x0d, 0x1b, 0x3d, 0xfe, + 0x4a, 0xf4, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09, 0x82, 0x4e, 0x05, + 0x72, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, + 0x01, 0xfe, 0x84, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d, + 0x27, 0x25, 0xbd, 0x09, 0x12, 0x2b, 0x3d, 0x01, 0xfe, 0xe8, 0x17, 0x8b, + 0xfe, 0xaa, 0x14, 0xfe, 0xb6, 0x14, 0x86, 0xa8, 0xb2, 0x0d, 0x1b, 0x3d, + 0xb2, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09, 0x82, 0x4e, 0x05, 0x72, + 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01, + 0xfe, 0xc0, 0x19, 0x05, 0x73, 0x13, 0x07, 0x2f, 0xfe, 0xcc, 0x15, 0x17, + 0xfe, 0xe2, 0x15, 0x5f, 0xcc, 0x01, 0x08, 0x26, 0x5f, 0x02, 0x8f, 0xfe, + 0xde, 0x15, 0x2a, 0xfe, 0xde, 0x15, 0x16, 0xfe, 0xcc, 0x15, 0x5e, 0x32, + 0x01, 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, + 0xad, 0x23, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, + 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xad, 0x23, 0x3f, 0xfe, 0x30, + 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, + 0xad, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xfe, 0x00, 0x5e, + 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xad, 0xfe, 0x0b, 0x58, + 0x02, 0x0a, 0x66, 0x01, 0x5c, 0x0a, 0x55, 0x01, 0x5c, 0x0a, 0x6f, 0x01, + 0x5c, 0x02, 0x01, 0xfe, 0x1e, 0x1f, 0x23, 0x1a, 0xff, 0x03, 0x00, 0x54, + 0xfe, 0x00, 0xf4, 0x24, 0x52, 0x0f, 0xfe, 0x00, 0x7c, 0x04, 0xfe, 0x07, + 0x7c, 0x3a, 0x0b, 0x0e, 0xfe, 0x00, 0x71, 0xfe, 0xf9, 0x18, 0xfe, 0x7a, + 0x19, 0xfe, 0xfb, 0x19, 0xfe, 0x1a, 0xf7, 0x00, 0xfe, 0x1b, 0xf7, 0x00, + 0x7a, 0x30, 0x10, 0x68, 0x22, 0x69, 0xd9, 0x6c, 0xda, 0x6d, 0x02, 0xfe, + 0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x77, + 0x02, 0x01, 0xc6, 0xfe, 0x42, 0x48, 0x4f, 0x50, 0x45, 0x01, 0x08, 0x16, + 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xbe, 0x01, 0x08, 0x16, 0xfe, 0xe0, 0x17, + 0x27, 0x25, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x03, 0x9a, 0x1e, 0xfe, + 0xda, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfe, 0xd0, 0x13, 0x26, 0x53, 0x12, + 0x48, 0xfe, 0x08, 0x17, 0xd1, 0x12, 0x53, 0x12, 0xfe, 0x1e, 0x13, 0x2d, + 0xb4, 0x7b, 0xfe, 0x26, 0x17, 0x4d, 0x13, 0x07, 0x1c, 0xb4, 0x90, 0x04, + 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xf1, 0xff, 0x02, 0x83, 0x55, + 0x53, 0x1d, 0xfe, 0x12, 0x13, 0xd6, 0xfe, 0x30, 0x00, 0xb0, 0xfe, 0x80, + 0x17, 0x1c, 0x63, 0x13, 0x07, 0xfe, 0x56, 0x10, 0x53, 0x0d, 0xfe, 0x16, + 0x13, 0xd6, 0xfe, 0x64, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0x64, + 0x00, 0x1c, 0x94, 0x13, 0x07, 0xfe, 0x28, 0x10, 0x53, 0x07, 0xfe, 0x60, + 0x13, 0xd6, 0xfe, 0xc8, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0xc8, + 0x00, 0x1c, 0x95, 0x13, 0x07, 0x71, 0xd6, 0xfe, 0x90, 0x01, 0x48, 0xfe, + 0x8c, 0x17, 0x45, 0xf3, 0xfe, 0x43, 0xf4, 0x96, 0xfe, 0x56, 0xf0, 0xfe, + 0x9e, 0x17, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x43, 0xf4, 0x94, 0xf6, 0x8b, + 0x01, 0xfe, 0x24, 0x16, 0x23, 0x3f, 0xfc, 0xa8, 0x8c, 0x49, 0x48, 0xfe, + 0xda, 0x17, 0x62, 0x49, 0xfe, 0x1c, 0x10, 0xa8, 0x8c, 0x80, 0x48, 0xfe, + 0xda, 0x17, 0x62, 0x80, 0x71, 0x50, 0x26, 0xfe, 0x4d, 0xf4, 0x00, 0xf7, + 0x45, 0x13, 0x07, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x02, 0x50, 0x13, + 0x0d, 0x02, 0x50, 0x3e, 0x78, 0x4f, 0x45, 0x01, 0x08, 0x16, 0xa9, 0x27, + 0x25, 0xbe, 0xfe, 0x03, 0xea, 0xfe, 0x7e, 0x01, 0x01, 0x08, 0x16, 0xa9, + 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, + 0xe9, 0x0a, 0xfe, 0x05, 0xea, 0xfe, 0x7f, 0x01, 0x01, 0x08, 0x16, 0xa9, + 0x27, 0x25, 0xfe, 0x69, 0x09, 0xfe, 0x02, 0xea, 0xfe, 0x80, 0x01, 0x01, + 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, 0xe8, 0x08, 0x47, 0xfe, 0x81, 0x01, + 0x03, 0xb6, 0x1e, 0x83, 0x01, 0x38, 0x06, 0x24, 0x31, 0xa2, 0x78, 0xf2, + 0x53, 0x07, 0x36, 0xfe, 0x34, 0xf4, 0x3f, 0xa1, 0x78, 0x03, 0x9a, 0x1e, + 0x83, 0x01, 0x38, 0x06, 0x12, 0x31, 0xf0, 0x4f, 0x45, 0xfe, 0x90, 0x10, + 0xfe, 0x40, 0x5a, 0x23, 0x3f, 0xfb, 0x8c, 0x49, 0x48, 0xfe, 0xaa, 0x18, + 0x62, 0x49, 0x71, 0x8c, 0x80, 0x48, 0xfe, 0xaa, 0x18, 0x62, 0x80, 0xfe, + 0xb4, 0x56, 0xfe, 0x40, 0x5d, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe, + 0x02, 0x17, 0xfe, 0xc8, 0x45, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0, 0x18, 0xfe, + 0x43, 0x48, 0x2d, 0x93, 0x36, 0xfe, 0x34, 0xf4, 0xfe, 0x00, 0x11, 0xfe, + 0x40, 0x10, 0x2d, 0xb4, 0x36, 0xfe, 0x34, 0xf4, 0x04, 0xfe, 0x34, 0x10, + 0x2d, 0xfe, 0x0b, 0x00, 0x36, 0x46, 0x63, 0xfe, 0x28, 0x10, 0xfe, 0xc0, + 0x49, 0xff, 0x02, 0x00, 0x54, 0xb2, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0xfa, + 0x18, 0x45, 0xfe, 0x1c, 0xf4, 0x3f, 0xf3, 0xfe, 0x40, 0xf4, 0x96, 0xfe, + 0x56, 0xf0, 0xfe, 0x0c, 0x19, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x40, 0xf4, + 0x94, 0xf6, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d, 0x21, 0xfe, 0x7f, 0x01, + 0xfe, 0xc8, 0x46, 0xfe, 0x24, 0x13, 0x8c, 0x00, 0x5d, 0x26, 0x21, 0xfe, + 0x7e, 0x01, 0xfe, 0xc8, 0x45, 0xfe, 0x14, 0x13, 0x21, 0xfe, 0x80, 0x01, + 0xfe, 0x48, 0x45, 0xfa, 0x21, 0xfe, 0x81, 0x01, 0xfe, 0xc8, 0x44, 0x4e, + 0x26, 0x02, 0x13, 0x07, 0x02, 0x78, 0x45, 0x50, 0x13, 0x0d, 0x02, 0x14, + 0x07, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, 0x0d, 0x01, 0x08, 0x17, + 0xfe, 0x82, 0x19, 0x14, 0x1d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x5f, + 0xfe, 0x89, 0x49, 0x01, 0x08, 0x02, 0x14, 0x07, 0x01, 0x08, 0x17, 0xc1, + 0x14, 0x1d, 0x01, 0x08, 0x17, 0xc1, 0x14, 0x07, 0x01, 0x08, 0x17, 0xc1, + 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0xc1, 0x5f, 0xfe, 0x89, 0x4a, 0x01, + 0x08, 0x02, 0x50, 0x02, 0x14, 0x07, 0x01, 0x08, 0x17, 0x74, 0x14, 0x7f, + 0x01, 0x08, 0x17, 0x74, 0x14, 0x12, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x89, + 0x49, 0x01, 0x08, 0x17, 0x74, 0x14, 0x00, 0x01, 0x08, 0x17, 0x74, 0xfe, + 0x89, 0x4a, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x09, 0x49, 0x01, 0x08, 0x17, + 0x74, 0x5f, 0xcc, 0x01, 0x08, 0x02, 0x21, 0xe4, 0x09, 0x07, 0xfe, 0x4c, + 0x13, 0xc8, 0x20, 0xe4, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x5f, 0xa1, 0x5e, + 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xcc, 0xff, 0x02, 0x00, 0x10, 0x2f, + 0xfe, 0x3e, 0x1a, 0x01, 0x43, 0x09, 0xfe, 0xe3, 0x00, 0xfe, 0x22, 0x13, + 0x16, 0xfe, 0x64, 0x1a, 0x26, 0x20, 0x9e, 0x01, 0x41, 0x21, 0x9e, 0x09, + 0x07, 0x5d, 0x01, 0x0c, 0x61, 0x07, 0x44, 0x02, 0x0a, 0x5a, 0x01, 0x18, + 0xfe, 0x00, 0x40, 0xaa, 0x09, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, + 0x18, 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x9d, 0x01, 0x18, 0xaa, + 0xfe, 0x80, 0xe7, 0x1a, 0x09, 0x1a, 0x5d, 0xfe, 0x45, 0x58, 0x01, 0xfe, + 0xb2, 0x16, 0xaa, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0xaa, 0x0a, 0x67, 0x01, + 0xa3, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x01, 0xfe, 0x7e, 0x1e, 0xfe, 0x80, + 0x4c, 0xfe, 0x49, 0xe4, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, 0x18, + 0xfe, 0x80, 0x4c, 0x0a, 0x67, 0x01, 0x5c, 0x02, 0x1c, 0x1a, 0x87, 0x7c, + 0xe5, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24, 0x1c, 0xfe, 0x1d, + 0xf7, 0x28, 0xb1, 0xfe, 0x04, 0x1b, 0x01, 0xfe, 0x2a, 0x1c, 0xfa, 0xb3, + 0x28, 0x7c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x02, 0xc9, 0x2b, 0xfe, + 0xf4, 0x1a, 0xfe, 0xfa, 0x10, 0x1c, 0x1a, 0x87, 0x03, 0xfe, 0x64, 0x01, + 0xfe, 0x00, 0xf4, 0x24, 0xfe, 0x18, 0x58, 0x03, 0xfe, 0x66, 0x01, 0xfe, + 0x19, 0x58, 0xb3, 0x24, 0x01, 0xfe, 0x0e, 0x1f, 0xfe, 0x30, 0xf4, 0x07, + 0xfe, 0x3c, 0x50, 0x7c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, + 0xf7, 0x24, 0xb1, 0xfe, 0x50, 0x1b, 0xfe, 0xd4, 0x14, 0x31, 0x02, 0xc9, + 0x2b, 0xfe, 0x26, 0x1b, 0xfe, 0xba, 0x10, 0x1c, 0x1a, 0x87, 0xfe, 0x83, + 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x54, 0xb1, + 0xfe, 0x72, 0x1b, 0xfe, 0xb2, 0x14, 0xfc, 0xb3, 0x54, 0x7c, 0x12, 0xfe, + 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00, 0x02, 0xc9, 0x2b, 0xfe, 0x66, 0x1b, + 0xfe, 0x8a, 0x10, 0x1c, 0x1a, 0x87, 0x8b, 0x0f, 0xfe, 0x30, 0x90, 0x04, + 0xfe, 0xb0, 0x93, 0x3a, 0x0b, 0xfe, 0x18, 0x58, 0xfe, 0x32, 0x90, 0x04, + 0xfe, 0xb2, 0x93, 0x3a, 0x0b, 0xfe, 0x19, 0x58, 0x0e, 0xa8, 0xb3, 0x4a, + 0x7c, 0x12, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x4a, 0xb1, 0xfe, 0xc6, + 0x1b, 0xfe, 0x5e, 0x14, 0x31, 0x02, 0xc9, 0x2b, 0xfe, 0x96, 0x1b, 0x5c, + 0xfe, 0x02, 0xf6, 0x1a, 0x87, 0xfe, 0x18, 0xfe, 0x6a, 0xfe, 0x19, 0xfe, + 0x6b, 0x01, 0xfe, 0x1e, 0x1f, 0xfe, 0x1d, 0xf7, 0x65, 0xb1, 0xfe, 0xee, + 0x1b, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0xb3, 0x65, 0x3e, 0xfe, 0x83, + 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x1a, 0xfe, 0x81, 0xe7, 0x1a, + 0x15, 0xfe, 0xdd, 0x00, 0x7a, 0x30, 0x02, 0x7a, 0x30, 0xfe, 0x12, 0x45, + 0x2b, 0xfe, 0xdc, 0x1b, 0x1f, 0x07, 0x47, 0xb5, 0xc3, 0x05, 0x35, 0xfe, + 0x39, 0xf0, 0x75, 0x26, 0x02, 0xfe, 0x7e, 0x18, 0x23, 0x1d, 0x36, 0x13, + 0x11, 0x02, 0x87, 0x03, 0xe3, 0x23, 0x07, 0xfe, 0xef, 0x12, 0xfe, 0xe1, + 0x10, 0x90, 0x34, 0x60, 0xfe, 0x02, 0x80, 0x09, 0x56, 0xfe, 0x3c, 0x13, + 0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x51, 0xfe, 0x06, 0x83, 0x0a, 0x5a, + 0x01, 0x18, 0xcb, 0xfe, 0x3e, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, + 0x01, 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, + 0x89, 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x4c, 0x01, + 0x85, 0xfe, 0x16, 0x10, 0x09, 0x9b, 0x4e, 0xfe, 0x40, 0x14, 0xfe, 0x24, + 0x12, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x52, 0x1c, 0x1c, 0x0d, + 0x02, 0xfe, 0x9c, 0xe7, 0x0d, 0x19, 0xfe, 0x15, 0x00, 0x40, 0x8d, 0x30, + 0x01, 0xf4, 0x1c, 0x07, 0x02, 0x51, 0xfe, 0x06, 0x83, 0xfe, 0x18, 0x80, + 0x61, 0x28, 0x44, 0x15, 0x56, 0x01, 0x85, 0x1c, 0x07, 0x02, 0xfe, 0x38, + 0x90, 0xfe, 0xba, 0x90, 0x91, 0xde, 0x7e, 0xdf, 0xfe, 0x48, 0x55, 0x31, + 0xfe, 0xc9, 0x55, 0x02, 0x21, 0xb9, 0x88, 0x20, 0xb9, 0x02, 0x0a, 0xba, + 0x01, 0x18, 0xfe, 0x41, 0x48, 0x0a, 0x57, 0x01, 0x18, 0xfe, 0x49, 0x44, + 0x1b, 0xfe, 0x1e, 0x1d, 0x88, 0x89, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x09, + 0x1a, 0xa4, 0x0a, 0x67, 0x01, 0xa3, 0x0a, 0x57, 0x01, 0x18, 0x88, 0x89, + 0x02, 0xfe, 0x4e, 0xe4, 0x1d, 0x7b, 0xfe, 0x52, 0x1d, 0x03, 0xfe, 0x90, + 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xdd, 0x7b, + 0xfe, 0x64, 0x1d, 0x03, 0xfe, 0x92, 0x00, 0xd1, 0x12, 0xfe, 0x1a, 0x10, + 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x7b, 0xfe, 0x76, 0x1d, 0x03, 0xfe, + 0x94, 0x00, 0xd1, 0x24, 0xfe, 0x08, 0x10, 0x03, 0xfe, 0x96, 0x00, 0xd1, + 0x63, 0xfe, 0x4e, 0x45, 0x83, 0xca, 0xff, 0x04, 0x68, 0x54, 0xfe, 0xf1, + 0x10, 0x23, 0x49, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, + 0xfe, 0x1a, 0xf4, 0xfe, 0x00, 0x04, 0x83, 0xb2, 0x1d, 0x48, 0xfe, 0xaa, + 0x1d, 0x13, 0x1d, 0x02, 0x09, 0x92, 0xfe, 0x5a, 0xf0, 0xfe, 0xba, 0x1d, + 0x2e, 0x93, 0xfe, 0x34, 0x10, 0x09, 0x12, 0xfe, 0x5a, 0xf0, 0xfe, 0xc8, + 0x1d, 0x2e, 0xb4, 0xfe, 0x26, 0x10, 0x09, 0x1d, 0x36, 0x2e, 0x63, 0xfe, + 0x1a, 0x10, 0x09, 0x0d, 0x36, 0x2e, 0x94, 0xf2, 0x09, 0x07, 0x36, 0x2e, + 0x95, 0xa1, 0xc8, 0x02, 0x1f, 0x93, 0x01, 0x42, 0xfe, 0x04, 0xfe, 0x99, + 0x03, 0x9c, 0x8b, 0x02, 0x2a, 0xfe, 0x1c, 0x1e, 0xfe, 0x14, 0xf0, 0x08, + 0x2f, 0xfe, 0x0c, 0x1e, 0x2a, 0xfe, 0x1c, 0x1e, 0x8f, 0xfe, 0x1c, 0x1e, + 0xfe, 0x82, 0xf0, 0xfe, 0x10, 0x1e, 0x02, 0x0f, 0x3f, 0x04, 0xfe, 0x80, + 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x18, 0x80, 0x04, 0xfe, 0x98, + 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x02, 0x80, 0x04, 0xfe, 0x82, + 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x80, 0x04, 0xfe, 0x86, + 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x1b, 0x80, 0x04, 0xfe, 0x9b, + 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x04, 0x80, 0x04, 0xfe, 0x84, + 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x80, 0x80, 0x04, 0xfe, 0x80, + 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x19, 0x81, 0x04, + 0xfe, 0x99, 0x83, 0xfe, 0xca, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, + 0x83, 0x04, 0xfe, 0x86, 0x83, 0xfe, 0xce, 0x47, 0x0b, 0x0e, 0x02, 0x0f, + 0xfe, 0x2c, 0x90, 0x04, 0xfe, 0xac, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f, + 0xfe, 0xae, 0x90, 0x04, 0xfe, 0xae, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f, + 0xfe, 0x08, 0x90, 0x04, 0xfe, 0x88, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f, + 0xfe, 0x8a, 0x90, 0x04, 0xfe, 0x8a, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f, + 0xfe, 0x0c, 0x90, 0x04, 0xfe, 0x8c, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f, + 0xfe, 0x8e, 0x90, 0x04, 0xfe, 0x8e, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f, + 0xfe, 0x3c, 0x90, 0x04, 0xfe, 0xbc, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x8b, + 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b, 0x77, 0x0e, + 0xa8, 0x02, 0xff, 0x66, 0x00, 0x00, +}; + +static unsigned short _adv_asc38C1600_size = sizeof(_adv_asc38C1600_buf); /* 0x1673 */ +static ADV_DCNT _adv_asc38C1600_chksum = 0x0604EF77UL; /* Expanded little-endian checksum. */ + +static void AscInitQLinkVar(ASC_DVC_VAR *asc_dvc) +{ + PortAddr iop_base; + int i; + ushort lram_addr; + + iop_base = asc_dvc->iop_base; + AscPutRiscVarFreeQHead(iop_base, 1); + AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng); + AscPutVarFreeQHead(iop_base, 1); + AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng); + AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B, + (uchar)((int)asc_dvc->max_total_qng + 1)); + AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B, + (uchar)((int)asc_dvc->max_total_qng + 2)); + AscWriteLramByte(iop_base, (ushort)ASCV_TOTAL_READY_Q_B, + asc_dvc->max_total_qng); + AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0); + AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); + AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0); + AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0); + AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0); + AscPutQDoneInProgress(iop_base, 0); + lram_addr = ASC_QADR_BEG; + for (i = 0; i < 32; i++, lram_addr += 2) { + AscWriteLramWord(iop_base, lram_addr, 0); } -#ifdef CONFIG_ISA - if ((bus_type & ASC_IS_EISA) != 0) { - cfg_lsw = AscGetEisaChipCfg(iop_base); - cfg_lsw &= 0x000F; - bios_addr = (ushort)(ASC_BIOS_MIN_ADDR + - (cfg_lsw * ASC_BIOS_BANK_SIZE)); - return (bios_addr); - } /* if */ -#endif /* CONFIG_ISA */ +} - cfg_lsw = AscGetChipCfgLsw(iop_base); +static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc) +{ + int i; + ushort warn_code; + PortAddr iop_base; + ASC_PADDR phy_addr; + ASC_DCNT phy_size; + struct asc_board *board = asc_dvc_to_board(asc_dvc); - /* - * ISA PnP uses the top bit as the 32K BIOS flag - */ - if (bus_type == ASC_IS_ISAPNP) { - cfg_lsw &= 0x7FFF; + iop_base = asc_dvc->iop_base; + warn_code = 0; + for (i = 0; i <= ASC_MAX_TID; i++) { + AscPutMCodeInitSDTRAtID(iop_base, i, + asc_dvc->cfg->sdtr_period_offset[i]); } - /* if */ - bios_addr = (ushort)(((cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE) + - ASC_BIOS_MIN_ADDR); - return (bios_addr); + + AscInitQLinkVar(asc_dvc); + AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B, + asc_dvc->cfg->disc_enable); + AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B, + ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id)); + + /* Ensure overrun buffer is aligned on an 8 byte boundary. */ + BUG_ON((unsigned long)asc_dvc->overrun_buf & 7); + asc_dvc->overrun_dma = dma_map_single(board->dev, asc_dvc->overrun_buf, + ASC_OVERRUN_BSIZE, DMA_FROM_DEVICE); + phy_addr = cpu_to_le32(asc_dvc->overrun_dma); + AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D, + (uchar *)&phy_addr, 1); + phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE); + AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D, + (uchar *)&phy_size, 1); + + asc_dvc->cfg->mcode_date = + AscReadLramWord(iop_base, (ushort)ASCV_MC_DATE_W); + asc_dvc->cfg->mcode_version = + AscReadLramWord(iop_base, (ushort)ASCV_MC_VER_W); + + AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR); + if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) { + asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR; + return warn_code; + } + if (AscStartChip(iop_base) != 1) { + asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP; + return warn_code; + } + + return warn_code; } -/* - * --- Functions Required by the Adv Library - */ +static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc) +{ + ushort warn_code; + PortAddr iop_base; + + iop_base = asc_dvc->iop_base; + warn_code = 0; + if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) && + !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) { + AscResetChipAndScsiBus(asc_dvc); + mdelay(asc_dvc->scsi_reset_wait * 1000); /* XXX: msleep? */ + } + asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC; + if (asc_dvc->err_code != 0) + return UW_ERR; + if (!AscFindSignature(asc_dvc->iop_base)) { + asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE; + return warn_code; + } + AscDisableInterrupt(iop_base); + warn_code |= AscInitLram(asc_dvc); + if (asc_dvc->err_code != 0) + return UW_ERR; + ASC_DBG(1, "_asc_mcode_chksum 0x%lx\n", (ulong)_asc_mcode_chksum); + if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf, + _asc_mcode_size) != _asc_mcode_chksum) { + asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM; + return warn_code; + } + warn_code |= AscInitMicroCodeVar(asc_dvc); + asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC; + AscEnableInterrupt(iop_base); + return warn_code; +} /* - * DvcGetPhyAddr() + * Load the Microcode + * + * Write the microcode image to RISC memory starting at address 0. + * + * The microcode is stored compressed in the following format: * - * Return the physical address of 'vaddr' and set '*lenp' to the - * number of physically contiguous bytes that follow 'vaddr'. - * 'flag' indicates the type of structure whose physical address - * is being translated. + * 254 word (508 byte) table indexed by byte code followed + * by the following byte codes: * - * Note: Because Linux currently doesn't page the kernel and all - * kernel buffers are physically contiguous, leave '*lenp' unchanged. + * 1-Byte Code: + * 00: Emit word 0 in table. + * 01: Emit word 1 in table. + * . + * FD: Emit word 253 in table. + * + * Multi-Byte Code: + * FE WW WW: (3 byte code) Word to emit is the next word WW WW. + * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW. + * + * Returns 0 or an error if the checksum doesn't match */ -ADV_PADDR -DvcGetPhyAddr(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq, - uchar *vaddr, ADV_SDCNT *lenp, int flag) +static int AdvLoadMicrocode(AdvPortAddr iop_base, unsigned char *buf, int size, + int memsize, int chksum) { - ADV_PADDR paddr; + int i, j, end, len = 0; + ADV_DCNT sum; + + AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0); - paddr = virt_to_bus(vaddr); + for (i = 253 * 2; i < size; i++) { + if (buf[i] == 0xff) { + unsigned short word = (buf[i + 3] << 8) | buf[i + 2]; + for (j = 0; j < buf[i + 1]; j++) { + AdvWriteWordAutoIncLram(iop_base, word); + len += 2; + } + i += 3; + } else if (buf[i] == 0xfe) { + unsigned short word = (buf[i + 2] << 8) | buf[i + 1]; + AdvWriteWordAutoIncLram(iop_base, word); + i += 2; + len += 2; + } else { + unsigned char off = buf[i] * 2; + unsigned short word = (buf[off + 1] << 8) | buf[off]; + AdvWriteWordAutoIncLram(iop_base, word); + len += 2; + } + } - ASC_DBG4(4, - "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n", - (ulong)vaddr, (ulong)lenp, (ulong)*((ulong *)lenp), - (ulong)paddr); + end = len; - return paddr; + while (len < memsize) { + AdvWriteWordAutoIncLram(iop_base, 0); + len += 2; + } + + /* Verify the microcode checksum. */ + sum = 0; + AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0); + + for (len = 0; len < end; len += 2) { + sum += AdvReadWordAutoIncLram(iop_base); + } + + if (sum != chksum) + return ASC_IERR_MCODE_CHKSUM; + + return 0; } -/* - * Read a PCI configuration byte. - */ -static uchar __init DvcAdvReadPCIConfigByte(ADV_DVC_VAR *asc_dvc, ushort offset) +static void AdvBuildCarrierFreelist(struct adv_dvc_var *asc_dvc) { -#ifdef CONFIG_PCI - uchar byte_data; - pci_read_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, &byte_data); - return byte_data; -#else /* CONFIG_PCI */ - return 0; -#endif /* CONFIG_PCI */ + ADV_CARR_T *carrp; + ADV_SDCNT buf_size; + ADV_PADDR carr_paddr; + + carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf); + asc_dvc->carr_freelist = NULL; + if (carrp == asc_dvc->carrier_buf) { + buf_size = ADV_CARRIER_BUFSIZE; + } else { + buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T); + } + + do { + /* Get physical address of the carrier 'carrp'. */ + carr_paddr = cpu_to_le32(virt_to_bus(carrp)); + + buf_size -= sizeof(ADV_CARR_T); + + carrp->carr_pa = carr_paddr; + carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp)); + + /* + * Insert the carrier at the beginning of the freelist. + */ + carrp->next_vpa = + cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist)); + asc_dvc->carr_freelist = carrp; + + carrp++; + } while (buf_size > 0); } /* - * Write a PCI configuration byte. + * Send an idle command to the chip and wait for completion. + * + * Command completion is polled for once per microsecond. + * + * The function can be called from anywhere including an interrupt handler. + * But the function is not re-entrant, so it uses the DvcEnter/LeaveCritical() + * functions to prevent reentrancy. + * + * Return Values: + * ADV_TRUE - command completed successfully + * ADV_FALSE - command failed + * ADV_ERROR - command timed out */ -static void __init -DvcAdvWritePCIConfigByte(ADV_DVC_VAR *asc_dvc, ushort offset, uchar byte_data) +static int +AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc, + ushort idle_cmd, ADV_DCNT idle_cmd_parameter) { -#ifdef CONFIG_PCI - pci_write_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, byte_data); -#else /* CONFIG_PCI */ - return; -#endif /* CONFIG_PCI */ + int result; + ADV_DCNT i, j; + AdvPortAddr iop_base; + + iop_base = asc_dvc->iop_base; + + /* + * Clear the idle command status which is set by the microcode + * to a non-zero value to indicate when the command is completed. + * The non-zero result is one of the IDLE_CMD_STATUS_* values + */ + AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort)0); + + /* + * Write the idle command value after the idle command parameter + * has been written to avoid a race condition. If the order is not + * followed, the microcode may process the idle command before the + * parameters have been written to LRAM. + */ + AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER, + cpu_to_le32(idle_cmd_parameter)); + AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd); + + /* + * Tickle the RISC to tell it to process the idle command. + */ + AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B); + if (asc_dvc->chip_type == ADV_CHIP_ASC3550) { + /* + * Clear the tickle value. In the ASC-3550 the RISC flag + * command 'clr_tickle_b' does not work unless the host + * value is cleared. + */ + AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP); + } + + /* Wait for up to 100 millisecond for the idle command to timeout. */ + for (i = 0; i < SCSI_WAIT_100_MSEC; i++) { + /* Poll once each microsecond for command completion. */ + for (j = 0; j < SCSI_US_PER_MSEC; j++) { + AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, + result); + if (result != 0) + return result; + udelay(1); + } + } + + BUG(); /* The idle command should never timeout. */ + return ADV_ERROR; } /* - * --- Tracing and Debugging Functions + * Reset SCSI Bus and purge all outstanding requests. + * + * Return Value: + * ADV_TRUE(1) - All requests are purged and SCSI Bus is reset. + * ADV_FALSE(0) - Microcode command failed. + * ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC + * may be hung which requires driver recovery. */ +static int AdvResetSB(ADV_DVC_VAR *asc_dvc) +{ + int status; + + /* + * Send the SCSI Bus Reset idle start idle command which asserts + * the SCSI Bus Reset signal. + */ + status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_START, 0L); + if (status != ADV_TRUE) { + return status; + } + + /* + * Delay for the specified SCSI Bus Reset hold time. + * + * The hold time delay is done on the host because the RISC has no + * microsecond accurate timer. + */ + udelay(ASC_SCSI_RESET_HOLD_TIME_US); + + /* + * Send the SCSI Bus Reset end idle command which de-asserts + * the SCSI Bus Reset signal and purges any pending requests. + */ + status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_END, 0L); + if (status != ADV_TRUE) { + return status; + } + + mdelay(asc_dvc->scsi_reset_wait * 1000); /* XXX: msleep? */ + + return status; +} -#ifdef ADVANSYS_STATS -#ifdef CONFIG_PROC_FS /* - * asc_prt_board_stats() + * Initialize the ASC-3550. * - * Note: no single line should be greater than ASC_PRTLINE_SIZE, - * cf. asc_prt_line(). + * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. * - * Return the number of characters copied into 'cp'. No more than - * 'cplen' characters will be copied to 'cp'. + * For a non-fatal error return a warning code. If there are no warnings + * then 0 is returned. + * + * Needed after initialization for error recovery. */ -static int asc_prt_board_stats(struct Scsi_Host *shost, char *cp, int cplen) +static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc) { - int leftlen; - int totlen; - int len; - struct asc_stats *s; - asc_board_t *boardp; + AdvPortAddr iop_base; + ushort warn_code; + int begin_addr; + int end_addr; + ushort code_sum; + int word; + int i; + ushort scsi_cfg1; + uchar tid; + ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */ + ushort wdtr_able = 0, sdtr_able, tagqng_able; + uchar max_cmd[ADV_MAX_TID + 1]; - leftlen = cplen; - totlen = len = 0; + /* If there is already an error, don't continue. */ + if (asc_dvc->err_code != 0) + return ADV_ERROR; - boardp = ASC_BOARDP(shost); - s = &boardp->asc_stats; + /* + * The caller must set 'chip_type' to ADV_CHIP_ASC3550. + */ + if (asc_dvc->chip_type != ADV_CHIP_ASC3550) { + asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE; + return ADV_ERROR; + } - len = asc_prt_line(cp, leftlen, - "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n", - shost->host_no); - ASC_PRT_NEXT(); + warn_code = 0; + iop_base = asc_dvc->iop_base; - len = asc_prt_line(cp, leftlen, - " queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n", - s->queuecommand, s->reset, s->biosparam, - s->interrupt); - ASC_PRT_NEXT(); + /* + * Save the RISC memory BIOS region before writing the microcode. + * The BIOS may already be loaded and using its RISC LRAM region + * so its region must be saved and restored. + * + * Note: This code makes the assumption, which is currently true, + * that a chip reset does not clear RISC LRAM. + */ + for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) { + AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), + bios_mem[i]); + } - len = asc_prt_line(cp, leftlen, - " callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n", - s->callback, s->done, s->build_error, - s->adv_build_noreq, s->adv_build_nosg); - ASC_PRT_NEXT(); + /* + * Save current per TID negotiated values. + */ + if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == 0x55AA) { + ushort bios_version, major, minor; - len = asc_prt_line(cp, leftlen, - " exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n", - s->exe_noerror, s->exe_busy, s->exe_error, - s->exe_unknown); - ASC_PRT_NEXT(); + bios_version = + bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM) / 2]; + major = (bios_version >> 12) & 0xF; + minor = (bios_version >> 8) & 0xF; + if (major < 3 || (major == 3 && minor == 1)) { + /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */ + AdvReadWordLram(iop_base, 0x120, wdtr_able); + } else { + AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); + } + } + AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); + AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); + for (tid = 0; tid <= ADV_MAX_TID; tid++) { + AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, + max_cmd[tid]); + } + + asc_dvc->err_code = AdvLoadMicrocode(iop_base, _adv_asc3550_buf, + _adv_asc3550_size, ADV_3550_MEMSIZE, + _adv_asc3550_chksum); + if (asc_dvc->err_code) + return ADV_ERROR; /* - * Display data transfer statistics. + * Restore the RISC memory BIOS region. */ - if (s->cont_cnt > 0) { - len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt); - ASC_PRT_NEXT(); + for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) { + AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), + bios_mem[i]); + } - len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ", - s->cont_xfer / 2, - ASC_TENTHS(s->cont_xfer, 2)); - ASC_PRT_NEXT(); + /* + * Calculate and write the microcode code checksum to the microcode + * code checksum location ASC_MC_CODE_CHK_SUM (0x2C). + */ + AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr); + AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr); + code_sum = 0; + AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr); + for (word = begin_addr; word < end_addr; word += 2) { + code_sum += AdvReadWordAutoIncLram(iop_base); + } + AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum); - /* Contiguous transfer average size */ - len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kb\n", - (s->cont_xfer / 2) / s->cont_cnt, - ASC_TENTHS((s->cont_xfer / 2), s->cont_cnt)); - ASC_PRT_NEXT(); + /* + * Read and save microcode version and date. + */ + AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, + asc_dvc->cfg->mcode_date); + AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, + asc_dvc->cfg->mcode_version); + + /* + * Set the chip type to indicate the ASC3550. + */ + AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550); + + /* + * If the PCI Configuration Command Register "Parity Error Response + * Control" Bit was clear (0), then set the microcode variable + * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode + * to ignore DMA parity errors. + */ + if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) { + AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); + word |= CONTROL_FLAG_IGNORE_PERR; + AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); } - if (s->sg_cnt > 0) { + /* + * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO + * threshold of 128 bytes. This register is only accessible to the host. + */ + AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0, + START_CTL_EMFU | READ_CMD_MRM); - len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ", - s->sg_cnt, s->sg_elem); - ASC_PRT_NEXT(); + /* + * Microcode operating variables for WDTR, SDTR, and command tag + * queuing will be set in slave_configure() based on what a + * device reports it is capable of in Inquiry byte 7. + * + * If SCSI Bus Resets have been disabled, then directly set + * SDTR and WDTR from the EEPROM configuration. This will allow + * the BIOS and warm boot to work without a SCSI bus hang on + * the Inquiry caused by host and target mismatched DTR values. + * Without the SCSI Bus Reset, before an Inquiry a device can't + * be assumed to be in Asynchronous, Narrow mode. + */ + if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) { + AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, + asc_dvc->wdtr_able); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, + asc_dvc->sdtr_able); + } - len = asc_prt_line(cp, leftlen, "sg_xfer %lu.%01lu kb\n", - s->sg_xfer / 2, ASC_TENTHS(s->sg_xfer, 2)); - ASC_PRT_NEXT(); + /* + * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2, + * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID + * bitmask. These values determine the maximum SDTR speed negotiated + * with a device. + * + * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2, + * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them + * without determining here whether the device supports SDTR. + * + * 4-bit speed SDTR speed name + * =========== =============== + * 0000b (0x0) SDTR disabled + * 0001b (0x1) 5 Mhz + * 0010b (0x2) 10 Mhz + * 0011b (0x3) 20 Mhz (Ultra) + * 0100b (0x4) 40 Mhz (LVD/Ultra2) + * 0101b (0x5) 80 Mhz (LVD2/Ultra3) + * 0110b (0x6) Undefined + * . + * 1111b (0xF) Undefined + */ + word = 0; + for (tid = 0; tid <= ADV_MAX_TID; tid++) { + if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) { + /* Set Ultra speed for TID 'tid'. */ + word |= (0x3 << (4 * (tid % 4))); + } else { + /* Set Fast speed for TID 'tid'. */ + word |= (0x2 << (4 * (tid % 4))); + } + if (tid == 3) { /* Check if done with sdtr_speed1. */ + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word); + word = 0; + } else if (tid == 7) { /* Check if done with sdtr_speed2. */ + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word); + word = 0; + } else if (tid == 11) { /* Check if done with sdtr_speed3. */ + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word); + word = 0; + } else if (tid == 15) { /* Check if done with sdtr_speed4. */ + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word); + /* End of loop. */ + } + } - /* Scatter gather transfer statistics */ - len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ", - s->sg_elem / s->sg_cnt, - ASC_TENTHS(s->sg_elem, s->sg_cnt)); - ASC_PRT_NEXT(); + /* + * Set microcode operating variable for the disconnect per TID bitmask. + */ + AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, + asc_dvc->cfg->disc_enable); - len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ", - (s->sg_xfer / 2) / s->sg_elem, - ASC_TENTHS((s->sg_xfer / 2), s->sg_elem)); - ASC_PRT_NEXT(); + /* + * Set SCSI_CFG0 Microcode Default Value. + * + * The microcode will set the SCSI_CFG0 register using this value + * after it is started below. + */ + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0, + PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN | + asc_dvc->chip_scsi_id); - len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n", - (s->sg_xfer / 2) / s->sg_cnt, - ASC_TENTHS((s->sg_xfer / 2), s->sg_cnt)); - ASC_PRT_NEXT(); + /* + * Determine SCSI_CFG1 Microcode Default Value. + * + * The microcode will set the SCSI_CFG1 register using this value + * after it is started below. + */ + + /* Read current SCSI_CFG1 Register value. */ + scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1); + + /* + * If all three connectors are in use, return an error. + */ + if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 || + (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) { + asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION; + return ADV_ERROR; } /* - * Display request queuing statistics. + * If the internal narrow cable is reversed all of the SCSI_CTRL + * register signals will be set. Check for and return an error if + * this condition is found. */ - len = asc_prt_line(cp, leftlen, - " Active and Waiting Request Queues (Time Unit: %d HZ):\n", - HZ); - ASC_PRT_NEXT(); + if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) { + asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE; + return ADV_ERROR; + } - return totlen; + /* + * If this is a differential board and a single-ended device + * is attached to one of the connectors, return an error. + */ + if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) { + asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE; + return ADV_ERROR; + } + + /* + * If automatic termination control is enabled, then set the + * termination value based on a table listed in a_condor.h. + * + * If manual termination was specified with an EEPROM setting + * then 'termination' was set-up in AdvInitFrom3550EEPROM() and + * is ready to be 'ored' into SCSI_CFG1. + */ + if (asc_dvc->cfg->termination == 0) { + /* + * The software always controls termination by setting TERM_CTL_SEL. + * If TERM_CTL_SEL were set to 0, the hardware would set termination. + */ + asc_dvc->cfg->termination |= TERM_CTL_SEL; + + switch (scsi_cfg1 & CABLE_DETECT) { + /* TERM_CTL_H: on, TERM_CTL_L: on */ + case 0x3: + case 0x7: + case 0xB: + case 0xD: + case 0xE: + case 0xF: + asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L); + break; + + /* TERM_CTL_H: on, TERM_CTL_L: off */ + case 0x1: + case 0x5: + case 0x9: + case 0xA: + case 0xC: + asc_dvc->cfg->termination |= TERM_CTL_H; + break; + + /* TERM_CTL_H: off, TERM_CTL_L: off */ + case 0x2: + case 0x6: + break; + } + } + + /* + * Clear any set TERM_CTL_H and TERM_CTL_L bits. + */ + scsi_cfg1 &= ~TERM_CTL; + + /* + * Invert the TERM_CTL_H and TERM_CTL_L bits and then + * set 'scsi_cfg1'. The TERM_POL bit does not need to be + * referenced, because the hardware internally inverts + * the Termination High and Low bits if TERM_POL is set. + */ + scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL)); + + /* + * Set SCSI_CFG1 Microcode Default Value + * + * Set filter value and possibly modified termination control + * bits in the Microcode SCSI_CFG1 Register Value. + * + * The microcode will set the SCSI_CFG1 register using this value + * after it is started below. + */ + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, + FLTR_DISABLE | scsi_cfg1); + + /* + * Set MEM_CFG Microcode Default Value + * + * The microcode will set the MEM_CFG register using this value + * after it is started below. + * + * MEM_CFG may be accessed as a word or byte, but only bits 0-7 + * are defined. + * + * ASC-3550 has 8KB internal memory. + */ + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG, + BIOS_EN | RAM_SZ_8KB); + + /* + * Set SEL_MASK Microcode Default Value + * + * The microcode will set the SEL_MASK register using this value + * after it is started below. + */ + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK, + ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id)); + + AdvBuildCarrierFreelist(asc_dvc); + + /* + * Set-up the Host->RISC Initiator Command Queue (ICQ). + */ + + if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) { + asc_dvc->err_code |= ASC_IERR_NO_CARRIER; + return ADV_ERROR; + } + asc_dvc->carr_freelist = (ADV_CARR_T *) + ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa)); + + /* + * The first command issued will be placed in the stopper carrier. + */ + asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); + + /* + * Set RISC ICQ physical address start value. + */ + AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa); + + /* + * Set-up the RISC->Host Initiator Response Queue (IRQ). + */ + if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) { + asc_dvc->err_code |= ASC_IERR_NO_CARRIER; + return ADV_ERROR; + } + asc_dvc->carr_freelist = (ADV_CARR_T *) + ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa)); + + /* + * The first command completed by the RISC will be placed in + * the stopper. + * + * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is + * completed the RISC will set the ASC_RQ_STOPPER bit. + */ + asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); + + /* + * Set RISC IRQ physical address start value. + */ + AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa); + asc_dvc->carr_pending_cnt = 0; + + AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES, + (ADV_INTR_ENABLE_HOST_INTR | + ADV_INTR_ENABLE_GLOBAL_INTR)); + + AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word); + AdvWriteWordRegister(iop_base, IOPW_PC, word); + + /* finally, finally, gentlemen, start your engine */ + AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN); + + /* + * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus + * Resets should be performed. The RISC has to be running + * to issue a SCSI Bus Reset. + */ + if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) { + /* + * If the BIOS Signature is present in memory, restore the + * BIOS Handshake Configuration Table and do not perform + * a SCSI Bus Reset. + */ + if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == + 0x55AA) { + /* + * Restore per TID negotiated values. + */ + AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); + AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, + tagqng_able); + for (tid = 0; tid <= ADV_MAX_TID; tid++) { + AdvWriteByteLram(iop_base, + ASC_MC_NUMBER_OF_MAX_CMD + tid, + max_cmd[tid]); + } + } else { + if (AdvResetSB(asc_dvc) != ADV_TRUE) { + warn_code = ASC_WARN_BUSRESET_ERROR; + } + } + } + + return warn_code; } /* - * asc_prt_target_stats() + * Initialize the ASC-38C0800. * - * Note: no single line should be greater than ASC_PRTLINE_SIZE, - * cf. asc_prt_line(). + * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. * - * This is separated from asc_prt_board_stats because a full set - * of targets will overflow ASC_PRTBUF_SIZE. + * For a non-fatal error return a warning code. If there are no warnings + * then 0 is returned. * - * Return the number of characters copied into 'cp'. No more than - * 'cplen' characters will be copied to 'cp'. + * Needed after initialization for error recovery. */ -static int -asc_prt_target_stats(struct Scsi_Host *shost, int tgt_id, char *cp, int cplen) +static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc) { - int leftlen; - int totlen; - int len; - struct asc_stats *s; - ushort chip_scsi_id; - asc_board_t *boardp; - asc_queue_t *active; - asc_queue_t *waiting; + AdvPortAddr iop_base; + ushort warn_code; + int begin_addr; + int end_addr; + ushort code_sum; + int word; + int i; + ushort scsi_cfg1; + uchar byte; + uchar tid; + ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */ + ushort wdtr_able, sdtr_able, tagqng_able; + uchar max_cmd[ADV_MAX_TID + 1]; - leftlen = cplen; - totlen = len = 0; + /* If there is already an error, don't continue. */ + if (asc_dvc->err_code != 0) + return ADV_ERROR; - boardp = ASC_BOARDP(shost); - s = &boardp->asc_stats; + /* + * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800. + */ + if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) { + asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE; + return ADV_ERROR; + } - active = &ASC_BOARDP(shost)->active; - waiting = &ASC_BOARDP(shost)->waiting; + warn_code = 0; + iop_base = asc_dvc->iop_base; - if (ASC_NARROW_BOARD(boardp)) { - chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id; - } else { - chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id; + /* + * Save the RISC memory BIOS region before writing the microcode. + * The BIOS may already be loaded and using its RISC LRAM region + * so its region must be saved and restored. + * + * Note: This code makes the assumption, which is currently true, + * that a chip reset does not clear RISC LRAM. + */ + for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) { + AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), + bios_mem[i]); } - if ((chip_scsi_id == tgt_id) || - ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(tgt_id)) == 0)) { - return 0; + /* + * Save current per TID negotiated values. + */ + AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); + AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); + AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); + for (tid = 0; tid <= ADV_MAX_TID; tid++) { + AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, + max_cmd[tid]); } - do { - if (active->q_tot_cnt[tgt_id] > 0 - || waiting->q_tot_cnt[tgt_id] > 0) { - len = asc_prt_line(cp, leftlen, " target %d\n", tgt_id); - ASC_PRT_NEXT(); + /* + * RAM BIST (RAM Built-In Self Test) + * + * Address : I/O base + offset 0x38h register (byte). + * Function: Bit 7-6(RW) : RAM mode + * Normal Mode : 0x00 + * Pre-test Mode : 0x40 + * RAM Test Mode : 0x80 + * Bit 5 : unused + * Bit 4(RO) : Done bit + * Bit 3-0(RO) : Status + * Host Error : 0x08 + * Int_RAM Error : 0x04 + * RISC Error : 0x02 + * SCSI Error : 0x01 + * No Error : 0x00 + * + * Note: RAM BIST code should be put right here, before loading the + * microcode and after saving the RISC memory BIOS region. + */ - len = asc_prt_line(cp, leftlen, - " active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n", - active->q_cur_cnt[tgt_id], - active->q_max_cnt[tgt_id], - active->q_tot_cnt[tgt_id], - active->q_min_tim[tgt_id], - active->q_max_tim[tgt_id], - (active->q_tot_cnt[tgt_id] == - 0) ? 0 : (active-> - q_tot_tim[tgt_id] / - active-> - q_tot_cnt[tgt_id]), - (active->q_tot_cnt[tgt_id] == - 0) ? 0 : ASC_TENTHS(active-> - q_tot_tim - [tgt_id], - active-> - q_tot_cnt - [tgt_id])); - ASC_PRT_NEXT(); + /* + * LRAM Pre-test + * + * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds. + * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return + * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset + * to NORMAL_MODE, return an error too. + */ + for (i = 0; i < 2; i++) { + AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE); + mdelay(10); /* Wait for 10ms before reading back. */ + byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST); + if ((byte & RAM_TEST_DONE) == 0 + || (byte & 0x0F) != PRE_TEST_VALUE) { + asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST; + return ADV_ERROR; + } - len = asc_prt_line(cp, leftlen, - " waiting: cnt [cur %d, max %d, tot %u], time [min %u, max %u, avg %lu.%01lu]\n", - waiting->q_cur_cnt[tgt_id], - waiting->q_max_cnt[tgt_id], - waiting->q_tot_cnt[tgt_id], - waiting->q_min_tim[tgt_id], - waiting->q_max_tim[tgt_id], - (waiting->q_tot_cnt[tgt_id] == - 0) ? 0 : (waiting-> - q_tot_tim[tgt_id] / - waiting-> - q_tot_cnt[tgt_id]), - (waiting->q_tot_cnt[tgt_id] == - 0) ? 0 : ASC_TENTHS(waiting-> - q_tot_tim - [tgt_id], - waiting-> - q_tot_cnt - [tgt_id])); - ASC_PRT_NEXT(); + AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE); + mdelay(10); /* Wait for 10ms before reading back. */ + if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST) + != NORMAL_VALUE) { + asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST; + return ADV_ERROR; } - } while (0); + } - return totlen; -} -#endif /* CONFIG_PROC_FS */ -#endif /* ADVANSYS_STATS */ + /* + * LRAM Test - It takes about 1.5 ms to run through the test. + * + * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds. + * If Done bit not set or Status not 0, save register byte, set the + * err_code, and return an error. + */ + AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE); + mdelay(10); /* Wait for 10ms before checking status. */ -#ifdef ADVANSYS_DEBUG -/* - * asc_prt_scsi_host() - */ -static void asc_prt_scsi_host(struct Scsi_Host *s) -{ - asc_board_t *boardp; + byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST); + if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) { + /* Get here if Done bit not set or Status not 0. */ + asc_dvc->bist_err_code = byte; /* for BIOS display message */ + asc_dvc->err_code = ASC_IERR_BIST_RAM_TEST; + return ADV_ERROR; + } - boardp = ASC_BOARDP(s); + /* We need to reset back to normal mode after LRAM test passes. */ + AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE); - printk("Scsi_Host at addr 0x%lx\n", (ulong)s); - printk(" host_busy %u, host_no %d, last_reset %d,\n", - s->host_busy, s->host_no, (unsigned)s->last_reset); + asc_dvc->err_code = AdvLoadMicrocode(iop_base, _adv_asc38C0800_buf, + _adv_asc38C0800_size, ADV_38C0800_MEMSIZE, + _adv_asc38C0800_chksum); + if (asc_dvc->err_code) + return ADV_ERROR; - printk(" base 0x%lx, io_port 0x%lx, n_io_port %u, irq 0x%x,\n", - (ulong)s->base, (ulong)s->io_port, s->n_io_port, s->irq); + /* + * Restore the RISC memory BIOS region. + */ + for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) { + AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), + bios_mem[i]); + } - printk(" dma_channel %d, this_id %d, can_queue %d,\n", - s->dma_channel, s->this_id, s->can_queue); + /* + * Calculate and write the microcode code checksum to the microcode + * code checksum location ASC_MC_CODE_CHK_SUM (0x2C). + */ + AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr); + AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr); + code_sum = 0; + AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr); + for (word = begin_addr; word < end_addr; word += 2) { + code_sum += AdvReadWordAutoIncLram(iop_base); + } + AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum); - printk(" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n", - s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma); + /* + * Read microcode version and date. + */ + AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, + asc_dvc->cfg->mcode_date); + AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, + asc_dvc->cfg->mcode_version); - if (ASC_NARROW_BOARD(boardp)) { - asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var); - asc_prt_asc_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.asc_dvc_cfg); - } else { - asc_prt_adv_dvc_var(&ASC_BOARDP(s)->dvc_var.adv_dvc_var); - asc_prt_adv_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.adv_dvc_cfg); + /* + * Set the chip type to indicate the ASC38C0800. + */ + AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800); + + /* + * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register. + * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current + * cable detection and then we are able to read C_DET[3:0]. + * + * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1 + * Microcode Default Value' section below. + */ + scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1); + AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1, + scsi_cfg1 | DIS_TERM_DRV); + + /* + * If the PCI Configuration Command Register "Parity Error Response + * Control" Bit was clear (0), then set the microcode variable + * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode + * to ignore DMA parity errors. + */ + if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) { + AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); + word |= CONTROL_FLAG_IGNORE_PERR; + AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); } -} -/* - * asc_prt_scsi_cmnd() - */ -static void asc_prt_scsi_cmnd(struct scsi_cmnd *s) -{ - printk("struct scsi_cmnd at addr 0x%lx\n", (ulong)s); + /* + * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2] + * bits for the default FIFO threshold. + * + * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes. + * + * For DMA Errata #4 set the BC_THRESH_ENB bit. + */ + AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0, + BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH | + READ_CMD_MRM); - printk(" host 0x%lx, device 0x%lx, target %u, lun %u, channel %u,\n", - (ulong)s->device->host, (ulong)s->device, s->device->id, - s->device->lun, s->device->channel); + /* + * Microcode operating variables for WDTR, SDTR, and command tag + * queuing will be set in slave_configure() based on what a + * device reports it is capable of in Inquiry byte 7. + * + * If SCSI Bus Resets have been disabled, then directly set + * SDTR and WDTR from the EEPROM configuration. This will allow + * the BIOS and warm boot to work without a SCSI bus hang on + * the Inquiry caused by host and target mismatched DTR values. + * Without the SCSI Bus Reset, before an Inquiry a device can't + * be assumed to be in Asynchronous, Narrow mode. + */ + if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) { + AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, + asc_dvc->wdtr_able); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, + asc_dvc->sdtr_able); + } - asc_prt_hex(" CDB", s->cmnd, s->cmd_len); + /* + * Set microcode operating variables for DISC and SDTR_SPEED1, + * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM + * configuration values. + * + * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2, + * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them + * without determining here whether the device supports SDTR. + */ + AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, + asc_dvc->cfg->disc_enable); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4); - printk("sc_data_direction %u, resid %d\n", - s->sc_data_direction, s->resid); + /* + * Set SCSI_CFG0 Microcode Default Value. + * + * The microcode will set the SCSI_CFG0 register using this value + * after it is started below. + */ + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0, + PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN | + asc_dvc->chip_scsi_id); - printk(" use_sg %u, sglist_len %u\n", s->use_sg, s->sglist_len); + /* + * Determine SCSI_CFG1 Microcode Default Value. + * + * The microcode will set the SCSI_CFG1 register using this value + * after it is started below. + */ - printk(" serial_number 0x%x, retries %d, allowed %d\n", - (unsigned)s->serial_number, s->retries, s->allowed); + /* Read current SCSI_CFG1 Register value. */ + scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1); - printk(" timeout_per_command %d\n", s->timeout_per_command); + /* + * If the internal narrow cable is reversed all of the SCSI_CTRL + * register signals will be set. Check for and return an error if + * this condition is found. + */ + if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) { + asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE; + return ADV_ERROR; + } - printk - (" scsi_done 0x%lx, done 0x%lx, host_scribble 0x%lx, result 0x%x\n", - (ulong)s->scsi_done, (ulong)s->done, (ulong)s->host_scribble, - s->result); + /* + * All kind of combinations of devices attached to one of four + * connectors are acceptable except HVD device attached. For example, + * LVD device can be attached to SE connector while SE device attached + * to LVD connector. If LVD device attached to SE connector, it only + * runs up to Ultra speed. + * + * If an HVD device is attached to one of LVD connectors, return an + * error. However, there is no way to detect HVD device attached to + * SE connectors. + */ + if (scsi_cfg1 & HVD) { + asc_dvc->err_code = ASC_IERR_HVD_DEVICE; + return ADV_ERROR; + } - printk(" tag %u, pid %u\n", (unsigned)s->tag, (unsigned)s->pid); -} + /* + * If either SE or LVD automatic termination control is enabled, then + * set the termination value based on a table listed in a_condor.h. + * + * If manual termination was specified with an EEPROM setting then + * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready + * to be 'ored' into SCSI_CFG1. + */ + if ((asc_dvc->cfg->termination & TERM_SE) == 0) { + /* SE automatic termination control is enabled. */ + switch (scsi_cfg1 & C_DET_SE) { + /* TERM_SE_HI: on, TERM_SE_LO: on */ + case 0x1: + case 0x2: + case 0x3: + asc_dvc->cfg->termination |= TERM_SE; + break; -/* - * asc_prt_asc_dvc_var() - */ -static void asc_prt_asc_dvc_var(ASC_DVC_VAR *h) -{ - printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong)h); + /* TERM_SE_HI: on, TERM_SE_LO: off */ + case 0x0: + asc_dvc->cfg->termination |= TERM_SE_HI; + break; + } + } - printk - (" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl %d,\n", - h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl); + if ((asc_dvc->cfg->termination & TERM_LVD) == 0) { + /* LVD automatic termination control is enabled. */ + switch (scsi_cfg1 & C_DET_LVD) { + /* TERM_LVD_HI: on, TERM_LVD_LO: on */ + case 0x4: + case 0x8: + case 0xC: + asc_dvc->cfg->termination |= TERM_LVD; + break; - printk - (" bus_type %d, isr_callback 0x%lx, exe_callback 0x%lx, init_sdtr 0x%x,\n", - h->bus_type, (ulong)h->isr_callback, (ulong)h->exe_callback, - (unsigned)h->init_sdtr); + /* TERM_LVD_HI: off, TERM_LVD_LO: off */ + case 0x0: + break; + } + } - printk - (" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, chip_no 0x%x,\n", - (unsigned)h->sdtr_done, (unsigned)h->use_tagged_qng, - (unsigned)h->unit_not_ready, (unsigned)h->chip_no); + /* + * Clear any set TERM_SE and TERM_LVD bits. + */ + scsi_cfg1 &= (~TERM_SE & ~TERM_LVD); - printk - (" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait %u,\n", - (unsigned)h->queue_full_or_busy, (unsigned)h->start_motor, - (unsigned)h->scsi_reset_wait); + /* + * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'. + */ + scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0); - printk - (" is_in_int %u, max_total_qng %u, cur_total_qng %u, in_critical_cnt %u,\n", - (unsigned)h->is_in_int, (unsigned)h->max_total_qng, - (unsigned)h->cur_total_qng, (unsigned)h->in_critical_cnt); + /* + * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE + * bits and set possibly modified termination control bits in the + * Microcode SCSI_CFG1 Register Value. + */ + scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE); - printk - (" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, pci_fix_asyn_xfer 0x%x,\n", - (unsigned)h->last_q_shortage, (unsigned)h->init_state, - (unsigned)h->no_scam, (unsigned)h->pci_fix_asyn_xfer); + /* + * Set SCSI_CFG1 Microcode Default Value + * + * Set possibly modified termination control and reset DIS_TERM_DRV + * bits in the Microcode SCSI_CFG1 Register Value. + * + * The microcode will set the SCSI_CFG1 register using this value + * after it is started below. + */ + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1); - printk(" cfg 0x%lx, irq_no 0x%x\n", (ulong)h->cfg, (unsigned)h->irq_no); -} + /* + * Set MEM_CFG Microcode Default Value + * + * The microcode will set the MEM_CFG register using this value + * after it is started below. + * + * MEM_CFG may be accessed as a word or byte, but only bits 0-7 + * are defined. + * + * ASC-38C0800 has 16KB internal memory. + */ + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG, + BIOS_EN | RAM_SZ_16KB); -/* - * asc_prt_asc_dvc_cfg() - */ -static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h) -{ - printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong)h); + /* + * Set SEL_MASK Microcode Default Value + * + * The microcode will set the SEL_MASK register using this value + * after it is started below. + */ + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK, + ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id)); - printk(" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n", - h->can_tagged_qng, h->cmd_qng_enabled); - printk(" disc_enable 0x%x, sdtr_enable 0x%x,\n", - h->disc_enable, h->sdtr_enable); + AdvBuildCarrierFreelist(asc_dvc); - printk - (" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n", - h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel, - h->chip_version); + /* + * Set-up the Host->RISC Initiator Command Queue (ICQ). + */ - printk - (" pci_device_id %d, lib_serial_no %u, lib_version %u, mcode_date 0x%x,\n", - to_pci_dev(h->dev)->device, h->lib_serial_no, h->lib_version, - h->mcode_date); + if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) { + asc_dvc->err_code |= ASC_IERR_NO_CARRIER; + return ADV_ERROR; + } + asc_dvc->carr_freelist = (ADV_CARR_T *) + ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa)); - printk(" mcode_version %d, overrun_buf 0x%lx\n", - h->mcode_version, (ulong)h->overrun_buf); + /* + * The first command issued will be placed in the stopper carrier. + */ + asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); + + /* + * Set RISC ICQ physical address start value. + * carr_pa is LE, must be native before write + */ + AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa); + + /* + * Set-up the RISC->Host Initiator Response Queue (IRQ). + */ + if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) { + asc_dvc->err_code |= ASC_IERR_NO_CARRIER; + return ADV_ERROR; + } + asc_dvc->carr_freelist = (ADV_CARR_T *) + ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa)); + + /* + * The first command completed by the RISC will be placed in + * the stopper. + * + * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is + * completed the RISC will set the ASC_RQ_STOPPER bit. + */ + asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); + + /* + * Set RISC IRQ physical address start value. + * + * carr_pa is LE, must be native before write * + */ + AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa); + asc_dvc->carr_pending_cnt = 0; + + AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES, + (ADV_INTR_ENABLE_HOST_INTR | + ADV_INTR_ENABLE_GLOBAL_INTR)); + + AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word); + AdvWriteWordRegister(iop_base, IOPW_PC, word); + + /* finally, finally, gentlemen, start your engine */ + AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN); + + /* + * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus + * Resets should be performed. The RISC has to be running + * to issue a SCSI Bus Reset. + */ + if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) { + /* + * If the BIOS Signature is present in memory, restore the + * BIOS Handshake Configuration Table and do not perform + * a SCSI Bus Reset. + */ + if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == + 0x55AA) { + /* + * Restore per TID negotiated values. + */ + AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); + AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, + tagqng_able); + for (tid = 0; tid <= ADV_MAX_TID; tid++) { + AdvWriteByteLram(iop_base, + ASC_MC_NUMBER_OF_MAX_CMD + tid, + max_cmd[tid]); + } + } else { + if (AdvResetSB(asc_dvc) != ADV_TRUE) { + warn_code = ASC_WARN_BUSRESET_ERROR; + } + } + } + + return warn_code; } /* - * asc_prt_asc_scsi_q() + * Initialize the ASC-38C1600. + * + * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR. + * + * For a non-fatal error return a warning code. If there are no warnings + * then 0 is returned. + * + * Needed after initialization for error recovery. */ -static void asc_prt_asc_scsi_q(ASC_SCSI_Q *q) +static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc) { - ASC_SG_HEAD *sgp; + AdvPortAddr iop_base; + ushort warn_code; + int begin_addr; + int end_addr; + ushort code_sum; + long word; int i; + ushort scsi_cfg1; + uchar byte; + uchar tid; + ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */ + ushort wdtr_able, sdtr_able, ppr_able, tagqng_able; + uchar max_cmd[ASC_MAX_TID + 1]; - printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong)q); + /* If there is already an error, don't continue. */ + if (asc_dvc->err_code != 0) { + return ADV_ERROR; + } - printk - (" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n", - q->q2.target_ix, q->q1.target_lun, (ulong)q->q2.srb_ptr, - q->q2.tag_code); + /* + * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600. + */ + if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600) { + asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE; + return ADV_ERROR; + } - printk - (" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n", - (ulong)le32_to_cpu(q->q1.data_addr), - (ulong)le32_to_cpu(q->q1.data_cnt), - (ulong)le32_to_cpu(q->q1.sense_addr), q->q1.sense_len); + warn_code = 0; + iop_base = asc_dvc->iop_base; - printk(" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n", - (ulong)q->cdbptr, q->q2.cdb_len, - (ulong)q->sg_head, q->q1.sg_queue_cnt); + /* + * Save the RISC memory BIOS region before writing the microcode. + * The BIOS may already be loaded and using its RISC LRAM region + * so its region must be saved and restored. + * + * Note: This code makes the assumption, which is currently true, + * that a chip reset does not clear RISC LRAM. + */ + for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) { + AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), + bios_mem[i]); + } - if (q->sg_head) { - sgp = q->sg_head; - printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong)sgp); - printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt, - sgp->queue_cnt); - for (i = 0; i < sgp->entry_cnt; i++) { - printk(" [%u]: addr 0x%lx, bytes %lu\n", - i, (ulong)le32_to_cpu(sgp->sg_list[i].addr), - (ulong)le32_to_cpu(sgp->sg_list[i].bytes)); + /* + * Save current per TID negotiated values. + */ + AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); + AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); + AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able); + AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); + for (tid = 0; tid <= ASC_MAX_TID; tid++) { + AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, + max_cmd[tid]); + } + + /* + * RAM BIST (Built-In Self Test) + * + * Address : I/O base + offset 0x38h register (byte). + * Function: Bit 7-6(RW) : RAM mode + * Normal Mode : 0x00 + * Pre-test Mode : 0x40 + * RAM Test Mode : 0x80 + * Bit 5 : unused + * Bit 4(RO) : Done bit + * Bit 3-0(RO) : Status + * Host Error : 0x08 + * Int_RAM Error : 0x04 + * RISC Error : 0x02 + * SCSI Error : 0x01 + * No Error : 0x00 + * + * Note: RAM BIST code should be put right here, before loading the + * microcode and after saving the RISC memory BIOS region. + */ + + /* + * LRAM Pre-test + * + * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds. + * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return + * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset + * to NORMAL_MODE, return an error too. + */ + for (i = 0; i < 2; i++) { + AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE); + mdelay(10); /* Wait for 10ms before reading back. */ + byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST); + if ((byte & RAM_TEST_DONE) == 0 + || (byte & 0x0F) != PRE_TEST_VALUE) { + asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST; + return ADV_ERROR; } + AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE); + mdelay(10); /* Wait for 10ms before reading back. */ + if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST) + != NORMAL_VALUE) { + asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST; + return ADV_ERROR; + } } -} -/* - * asc_prt_asc_qdone_info() - */ -static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *q) -{ - printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong)q); - printk(" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n", - (ulong)q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len, - q->d2.tag_code); - printk - (" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n", - q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg); -} + /* + * LRAM Test - It takes about 1.5 ms to run through the test. + * + * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds. + * If Done bit not set or Status not 0, save register byte, set the + * err_code, and return an error. + */ + AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE); + mdelay(10); /* Wait for 10ms before checking status. */ -/* - * asc_prt_adv_dvc_var() - * - * Display an ADV_DVC_VAR structure. - */ -static void asc_prt_adv_dvc_var(ADV_DVC_VAR *h) -{ - printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong)h); + byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST); + if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) { + /* Get here if Done bit not set or Status not 0. */ + asc_dvc->bist_err_code = byte; /* for BIOS display message */ + asc_dvc->err_code = ASC_IERR_BIST_RAM_TEST; + return ADV_ERROR; + } - printk(" iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n", - (ulong)h->iop_base, h->err_code, (unsigned)h->ultra_able); + /* We need to reset back to normal mode after LRAM test passes. */ + AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE); - printk(" isr_callback 0x%lx, sdtr_able 0x%x, wdtr_able 0x%x\n", - (ulong)h->isr_callback, (unsigned)h->sdtr_able, - (unsigned)h->wdtr_able); + asc_dvc->err_code = AdvLoadMicrocode(iop_base, _adv_asc38C1600_buf, + _adv_asc38C1600_size, ADV_38C1600_MEMSIZE, + _adv_asc38C1600_chksum); + if (asc_dvc->err_code) + return ADV_ERROR; - printk(" start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n", - (unsigned)h->start_motor, - (unsigned)h->scsi_reset_wait, (unsigned)h->irq_no); + /* + * Restore the RISC memory BIOS region. + */ + for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) { + AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), + bios_mem[i]); + } - printk(" max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n", - (unsigned)h->max_host_qng, (unsigned)h->max_dvc_qng, - (ulong)h->carr_freelist); + /* + * Calculate and write the microcode code checksum to the microcode + * code checksum location ASC_MC_CODE_CHK_SUM (0x2C). + */ + AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr); + AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr); + code_sum = 0; + AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr); + for (word = begin_addr; word < end_addr; word += 2) { + code_sum += AdvReadWordAutoIncLram(iop_base); + } + AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum); - printk(" icq_sp 0x%lx, irq_sp 0x%lx\n", - (ulong)h->icq_sp, (ulong)h->irq_sp); + /* + * Read microcode version and date. + */ + AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, + asc_dvc->cfg->mcode_date); + AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, + asc_dvc->cfg->mcode_version); - printk(" no_scam 0x%x, tagqng_able 0x%x\n", - (unsigned)h->no_scam, (unsigned)h->tagqng_able); + /* + * Set the chip type to indicate the ASC38C1600. + */ + AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600); - printk(" chip_scsi_id 0x%x, cfg 0x%lx\n", - (unsigned)h->chip_scsi_id, (ulong)h->cfg); -} + /* + * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register. + * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current + * cable detection and then we are able to read C_DET[3:0]. + * + * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1 + * Microcode Default Value' section below. + */ + scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1); + AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1, + scsi_cfg1 | DIS_TERM_DRV); -/* - * asc_prt_adv_dvc_cfg() - * - * Display an ADV_DVC_CFG structure. - */ -static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h) -{ - printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong)h); + /* + * If the PCI Configuration Command Register "Parity Error Response + * Control" Bit was clear (0), then set the microcode variable + * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode + * to ignore DMA parity errors. + */ + if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) { + AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); + word |= CONTROL_FLAG_IGNORE_PERR; + AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); + } - printk(" disc_enable 0x%x, termination 0x%x\n", - h->disc_enable, h->termination); + /* + * If the BIOS control flag AIPP (Asynchronous Information + * Phase Protection) disable bit is not set, then set the firmware + * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable + * AIPP checking and encoding. + */ + if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) { + AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); + word |= CONTROL_FLAG_ENABLE_AIPP; + AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); + } - printk(" chip_version 0x%x, mcode_date 0x%x\n", - h->chip_version, h->mcode_date); + /* + * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4], + * and START_CTL_TH [3:2]. + */ + AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0, + FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM); - printk(" mcode_version 0x%x, pci_device_id 0x%x, lib_version %u\n", - h->mcode_version, to_pci_dev(h->dev)->device, h->lib_version); + /* + * Microcode operating variables for WDTR, SDTR, and command tag + * queuing will be set in slave_configure() based on what a + * device reports it is capable of in Inquiry byte 7. + * + * If SCSI Bus Resets have been disabled, then directly set + * SDTR and WDTR from the EEPROM configuration. This will allow + * the BIOS and warm boot to work without a SCSI bus hang on + * the Inquiry caused by host and target mismatched DTR values. + * Without the SCSI Bus Reset, before an Inquiry a device can't + * be assumed to be in Asynchronous, Narrow mode. + */ + if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) { + AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, + asc_dvc->wdtr_able); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, + asc_dvc->sdtr_able); + } - printk(" control_flag 0x%x, pci_slot_info 0x%x\n", - h->control_flag, h->pci_slot_info); -} + /* + * Set microcode operating variables for DISC and SDTR_SPEED1, + * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM + * configuration values. + * + * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2, + * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them + * without determining here whether the device supports SDTR. + */ + AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, + asc_dvc->cfg->disc_enable); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4); -/* - * asc_prt_adv_scsi_req_q() - * - * Display an ADV_SCSI_REQ_Q structure. - */ -static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q) -{ - int sg_blk_cnt; - struct asc_sg_block *sg_ptr; + /* + * Set SCSI_CFG0 Microcode Default Value. + * + * The microcode will set the SCSI_CFG0 register using this value + * after it is started below. + */ + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0, + PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN | + asc_dvc->chip_scsi_id); - printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong)q); + /* + * Calculate SCSI_CFG1 Microcode Default Value. + * + * The microcode will set the SCSI_CFG1 register using this value + * after it is started below. + * + * Each ASC-38C1600 function has only two cable detect bits. + * The bus mode override bits are in IOPB_SOFT_OVER_WR. + */ + scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1); - printk(" target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n", - q->target_id, q->target_lun, (ulong)q->srb_ptr, q->a_flag); + /* + * If the cable is reversed all of the SCSI_CTRL register signals + * will be set. Check for and return an error if this condition is + * found. + */ + if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) { + asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE; + return ADV_ERROR; + } - printk(" cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n", - q->cntl, (ulong)le32_to_cpu(q->data_addr), (ulong)q->vdata_addr); + /* + * Each ASC-38C1600 function has two connectors. Only an HVD device + * can not be connected to either connector. An LVD device or SE device + * may be connected to either connecor. If an SE device is connected, + * then at most Ultra speed (20 Mhz) can be used on both connectors. + * + * If an HVD device is attached, return an error. + */ + if (scsi_cfg1 & HVD) { + asc_dvc->err_code |= ASC_IERR_HVD_DEVICE; + return ADV_ERROR; + } - printk(" data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n", - (ulong)le32_to_cpu(q->data_cnt), - (ulong)le32_to_cpu(q->sense_addr), q->sense_len); + /* + * Each function in the ASC-38C1600 uses only the SE cable detect and + * termination because there are two connectors for each function. Each + * function may use either LVD or SE mode. Corresponding the SE automatic + * termination control EEPROM bits are used for each function. Each + * function has its own EEPROM. If SE automatic control is enabled for + * the function, then set the termination value based on a table listed + * in a_condor.h. + * + * If manual termination is specified in the EEPROM for the function, + * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is + * ready to be 'ored' into SCSI_CFG1. + */ + if ((asc_dvc->cfg->termination & TERM_SE) == 0) { + struct pci_dev *pdev = adv_dvc_to_pdev(asc_dvc); + /* SE automatic termination control is enabled. */ + switch (scsi_cfg1 & C_DET_SE) { + /* TERM_SE_HI: on, TERM_SE_LO: on */ + case 0x1: + case 0x2: + case 0x3: + asc_dvc->cfg->termination |= TERM_SE; + break; - printk - (" cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n", - q->cdb_len, q->done_status, q->host_status, q->scsi_status); + case 0x0: + if (PCI_FUNC(pdev->devfn) == 0) { + /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */ + } else { + /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */ + asc_dvc->cfg->termination |= TERM_SE_HI; + } + break; + } + } - printk(" sg_working_ix 0x%x, target_cmd %u\n", - q->sg_working_ix, q->target_cmd); + /* + * Clear any set TERM_SE bits. + */ + scsi_cfg1 &= ~TERM_SE; - printk(" scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n", - (ulong)le32_to_cpu(q->scsiq_rptr), - (ulong)le32_to_cpu(q->sg_real_addr), (ulong)q->sg_list_ptr); + /* + * Invert the TERM_SE bits and then set 'scsi_cfg1'. + */ + scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE); - /* Display the request's ADV_SG_BLOCK structures. */ - if (q->sg_list_ptr != NULL) { - sg_blk_cnt = 0; - while (1) { + /* + * Clear Big Endian and Terminator Polarity bits and set possibly + * modified termination control bits in the Microcode SCSI_CFG1 + * Register Value. + * + * Big Endian bit is not used even on big endian machines. + */ + scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL); + + /* + * Set SCSI_CFG1 Microcode Default Value + * + * Set possibly modified termination control bits in the Microcode + * SCSI_CFG1 Register Value. + * + * The microcode will set the SCSI_CFG1 register using this value + * after it is started below. + */ + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1); + + /* + * Set MEM_CFG Microcode Default Value + * + * The microcode will set the MEM_CFG register using this value + * after it is started below. + * + * MEM_CFG may be accessed as a word or byte, but only bits 0-7 + * are defined. + * + * ASC-38C1600 has 32KB internal memory. + * + * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come + * out a special 16K Adv Library and Microcode version. After the issue + * resolved, we should turn back to the 32K support. Both a_condor.h and + * mcode.sas files also need to be updated. + * + * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG, + * BIOS_EN | RAM_SZ_32KB); + */ + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG, + BIOS_EN | RAM_SZ_16KB); + + /* + * Set SEL_MASK Microcode Default Value + * + * The microcode will set the SEL_MASK register using this value + * after it is started below. + */ + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK, + ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id)); + + AdvBuildCarrierFreelist(asc_dvc); + + /* + * Set-up the Host->RISC Initiator Command Queue (ICQ). + */ + if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) { + asc_dvc->err_code |= ASC_IERR_NO_CARRIER; + return ADV_ERROR; + } + asc_dvc->carr_freelist = (ADV_CARR_T *) + ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa)); + + /* + * The first command issued will be placed in the stopper carrier. + */ + asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); + + /* + * Set RISC ICQ physical address start value. Initialize the + * COMMA register to the same value otherwise the RISC will + * prematurely detect a command is available. + */ + AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa); + AdvWriteDWordRegister(iop_base, IOPDW_COMMA, + le32_to_cpu(asc_dvc->icq_sp->carr_pa)); + + /* + * Set-up the RISC->Host Initiator Response Queue (IRQ). + */ + if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) { + asc_dvc->err_code |= ASC_IERR_NO_CARRIER; + return ADV_ERROR; + } + asc_dvc->carr_freelist = (ADV_CARR_T *) + ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa)); + + /* + * The first command completed by the RISC will be placed in + * the stopper. + * + * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is + * completed the RISC will set the ASC_RQ_STOPPER bit. + */ + asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); + + /* + * Set RISC IRQ physical address start value. + */ + AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa); + asc_dvc->carr_pending_cnt = 0; + + AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES, + (ADV_INTR_ENABLE_HOST_INTR | + ADV_INTR_ENABLE_GLOBAL_INTR)); + AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word); + AdvWriteWordRegister(iop_base, IOPW_PC, word); + + /* finally, finally, gentlemen, start your engine */ + AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN); + + /* + * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus + * Resets should be performed. The RISC has to be running + * to issue a SCSI Bus Reset. + */ + if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) { + /* + * If the BIOS Signature is present in memory, restore the + * per TID microcode operating variables. + */ + if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == + 0x55AA) { /* - * 'sg_ptr' is a physical address. Convert it to a virtual - * address by indexing 'sg_blk_cnt' into the virtual address - * array 'sg_list_ptr'. - * - * XXX - Assumes all SG physical blocks are virtually contiguous. + * Restore per TID negotiated values. */ - sg_ptr = - &(((ADV_SG_BLOCK *)(q->sg_list_ptr))[sg_blk_cnt]); - asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr); - if (sg_ptr->sg_ptr == 0) { - break; + AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); + AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able); + AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, + tagqng_able); + for (tid = 0; tid <= ASC_MAX_TID; tid++) { + AdvWriteByteLram(iop_base, + ASC_MC_NUMBER_OF_MAX_CMD + tid, + max_cmd[tid]); + } + } else { + if (AdvResetSB(asc_dvc) != ADV_TRUE) { + warn_code = ASC_WARN_BUSRESET_ERROR; } - sg_blk_cnt++; } } + + return warn_code; } /* - * asc_prt_adv_sgblock() + * Reset chip and SCSI Bus. * - * Display an ADV_SG_BLOCK structure. + * Return Value: + * ADV_TRUE(1) - Chip re-initialization and SCSI Bus Reset successful. + * ADV_FALSE(0) - Chip re-initialization and SCSI Bus Reset failure. */ -static void asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b) +static int AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc) { - int i; + int status; + ushort wdtr_able, sdtr_able, tagqng_able; + ushort ppr_able = 0; + uchar tid, max_cmd[ADV_MAX_TID + 1]; + AdvPortAddr iop_base; + ushort bios_sig; - printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n", - (ulong)b, sgblockno); - printk(" sg_cnt %u, sg_ptr 0x%lx\n", - b->sg_cnt, (ulong)le32_to_cpu(b->sg_ptr)); - ASC_ASSERT(b->sg_cnt <= NO_OF_SG_PER_BLOCK); - if (b->sg_ptr != 0) { - ASC_ASSERT(b->sg_cnt == NO_OF_SG_PER_BLOCK); + iop_base = asc_dvc->iop_base; + + /* + * Save current per TID negotiated values. + */ + AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); + AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); + if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) { + AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able); } - for (i = 0; i < b->sg_cnt; i++) { - printk(" [%u]: sg_addr 0x%lx, sg_count 0x%lx\n", - i, (ulong)b->sg_list[i].sg_addr, - (ulong)b->sg_list[i].sg_count); + AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); + for (tid = 0; tid <= ADV_MAX_TID; tid++) { + AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, + max_cmd[tid]); } -} -/* - * asc_prt_hex() - * - * Print hexadecimal output in 4 byte groupings 32 bytes - * or 8 double-words per line. - */ -static void asc_prt_hex(char *f, uchar *s, int l) -{ - int i; - int j; - int k; - int m; - - printk("%s: (%d bytes)\n", f, l); + /* + * Force the AdvInitAsc3550/38C0800Driver() function to + * perform a SCSI Bus Reset by clearing the BIOS signature word. + * The initialization functions assumes a SCSI Bus Reset is not + * needed if the BIOS signature word is present. + */ + AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig); + AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0); - for (i = 0; i < l; i += 32) { + /* + * Stop chip and reset it. + */ + AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP); + AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET); + mdelay(100); + AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, + ADV_CTRL_REG_CMD_WR_IO_REG); - /* Display a maximum of 8 double-words per line. */ - if ((k = (l - i) / 4) >= 8) { - k = 8; - m = 0; - } else { - m = (l - i) % 4; - } + /* + * Reset Adv Library error code, if any, and try + * re-initializing the chip. + */ + asc_dvc->err_code = 0; + if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) { + status = AdvInitAsc38C1600Driver(asc_dvc); + } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) { + status = AdvInitAsc38C0800Driver(asc_dvc); + } else { + status = AdvInitAsc3550Driver(asc_dvc); + } - for (j = 0; j < k; j++) { - printk(" %2.2X%2.2X%2.2X%2.2X", - (unsigned)s[i + (j * 4)], - (unsigned)s[i + (j * 4) + 1], - (unsigned)s[i + (j * 4) + 2], - (unsigned)s[i + (j * 4) + 3]); - } + /* Translate initialization return value to status value. */ + if (status == 0) { + status = ADV_TRUE; + } else { + status = ADV_FALSE; + } - switch (m) { - case 0: - default: - break; - case 1: - printk(" %2.2X", (unsigned)s[i + (j * 4)]); - break; - case 2: - printk(" %2.2X%2.2X", - (unsigned)s[i + (j * 4)], - (unsigned)s[i + (j * 4) + 1]); - break; - case 3: - printk(" %2.2X%2.2X%2.2X", - (unsigned)s[i + (j * 4) + 1], - (unsigned)s[i + (j * 4) + 2], - (unsigned)s[i + (j * 4) + 3]); - break; - } + /* + * Restore the BIOS signature word. + */ + AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig); - printk("\n"); + /* + * Restore per TID negotiated values. + */ + AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); + if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) { + AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able); + } + AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); + for (tid = 0; tid <= ADV_MAX_TID; tid++) { + AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, + max_cmd[tid]); } + + return status; } -#endif /* ADVANSYS_DEBUG */ /* - * --- Asc Library Functions + * adv_async_callback() - Adv Library asynchronous event callback function. */ - -static ushort __init AscGetEisaChipCfg(PortAddr iop_base) +static void adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code) { - PortAddr eisa_cfg_iop; + switch (code) { + case ADV_ASYNC_SCSI_BUS_RESET_DET: + /* + * The firmware detected a SCSI Bus reset. + */ + ASC_DBG(0, "ADV_ASYNC_SCSI_BUS_RESET_DET\n"); + break; - eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) | - (PortAddr) (ASC_EISA_CFG_IOP_MASK); - return (inpw(eisa_cfg_iop)); -} + case ADV_ASYNC_RDMA_FAILURE: + /* + * Handle RDMA failure by resetting the SCSI Bus and + * possibly the chip if it is unresponsive. Log the error + * with a unique code. + */ + ASC_DBG(0, "ADV_ASYNC_RDMA_FAILURE\n"); + AdvResetChipAndSB(adv_dvc_varp); + break; -static uchar __init AscSetChipScsiID(PortAddr iop_base, uchar new_host_id) -{ - ushort cfg_lsw; + case ADV_HOST_SCSI_BUS_RESET: + /* + * Host generated SCSI bus reset occurred. + */ + ASC_DBG(0, "ADV_HOST_SCSI_BUS_RESET\n"); + break; - if (AscGetChipScsiID(iop_base) == new_host_id) { - return (new_host_id); + default: + ASC_DBG(0, "unknown code 0x%x\n", code); + break; } - cfg_lsw = AscGetChipCfgLsw(iop_base); - cfg_lsw &= 0xF8FF; - cfg_lsw |= (ushort)((new_host_id & ASC_MAX_TID) << 8); - AscSetChipCfgLsw(iop_base, cfg_lsw); - return (AscGetChipScsiID(iop_base)); } -static uchar __init AscGetChipScsiCtrl(PortAddr iop_base) +/* + * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR(). + * + * Callback function for the Wide SCSI Adv Library. + */ +static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp) { - uchar sc; + struct asc_board *boardp; + adv_req_t *reqp; + adv_sgblk_t *sgblkp; + struct scsi_cmnd *scp; + struct Scsi_Host *shost; + ADV_DCNT resid_cnt; - AscSetBank(iop_base, 1); - sc = inp(iop_base + IOP_REG_SC); - AscSetBank(iop_base, 0); - return (sc); -} + ASC_DBG(1, "adv_dvc_varp 0x%lx, scsiqp 0x%lx\n", + (ulong)adv_dvc_varp, (ulong)scsiqp); + ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp); -static uchar __init AscGetChipVersion(PortAddr iop_base, ushort bus_type) -{ - if ((bus_type & ASC_IS_EISA) != 0) { - PortAddr eisa_iop; - uchar revision; - eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) | - (PortAddr) ASC_EISA_REV_IOP_MASK; - revision = inp(eisa_iop); - return ((uchar)((ASC_CHIP_MIN_VER_EISA - 1) + revision)); + /* + * Get the adv_req_t structure for the command that has been + * completed. The adv_req_t structure actually contains the + * completed ADV_SCSI_REQ_Q structure. + */ + reqp = (adv_req_t *)ADV_U32_TO_VADDR(scsiqp->srb_ptr); + ASC_DBG(1, "reqp 0x%lx\n", (ulong)reqp); + if (reqp == NULL) { + ASC_PRINT("adv_isr_callback: reqp is NULL\n"); + return; } - return (AscGetChipVerNo(iop_base)); -} -static ushort __init AscGetChipBusType(PortAddr iop_base) -{ - ushort chip_ver; - - chip_ver = AscGetChipVerNo(iop_base); - if ((chip_ver >= ASC_CHIP_MIN_VER_VL) - && (chip_ver <= ASC_CHIP_MAX_VER_VL) - ) { - if (((iop_base & 0x0C30) == 0x0C30) - || ((iop_base & 0x0C50) == 0x0C50) - ) { - return (ASC_IS_EISA); - } - return (ASC_IS_VL); + /* + * Get the struct scsi_cmnd structure and Scsi_Host structure for the + * command that has been completed. + * + * Note: The adv_req_t request structure and adv_sgblk_t structure, + * if any, are dropped, because a board structure pointer can not be + * determined. + */ + scp = reqp->cmndp; + ASC_DBG(1, "scp 0x%p\n", scp); + if (scp == NULL) { + ASC_PRINT + ("adv_isr_callback: scp is NULL; adv_req_t dropped.\n"); + return; } - if ((chip_ver >= ASC_CHIP_MIN_VER_ISA) && - (chip_ver <= ASC_CHIP_MAX_VER_ISA)) { - if (chip_ver >= ASC_CHIP_MIN_VER_ISA_PNP) { - return (ASC_IS_ISAPNP); + ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len); + + shost = scp->device->host; + ASC_STATS(shost, callback); + ASC_DBG(1, "shost 0x%p\n", shost); + + boardp = shost_priv(shost); + BUG_ON(adv_dvc_varp != &boardp->dvc_var.adv_dvc_var); + + /* + * 'done_status' contains the command's ending status. + */ + switch (scsiqp->done_status) { + case QD_NO_ERROR: + ASC_DBG(2, "QD_NO_ERROR\n"); + scp->result = 0; + + /* + * Check for an underrun condition. + * + * If there was no error and an underrun condition, then + * then return the number of underrun bytes. + */ + resid_cnt = le32_to_cpu(scsiqp->data_cnt); + if (scsi_bufflen(scp) != 0 && resid_cnt != 0 && + resid_cnt <= scsi_bufflen(scp)) { + ASC_DBG(1, "underrun condition %lu bytes\n", + (ulong)resid_cnt); + scsi_set_resid(scp, resid_cnt); } - return (ASC_IS_ISA); - } else if ((chip_ver >= ASC_CHIP_MIN_VER_PCI) && - (chip_ver <= ASC_CHIP_MAX_VER_PCI)) { - return (ASC_IS_PCI); + break; + + case QD_WITH_ERROR: + ASC_DBG(2, "QD_WITH_ERROR\n"); + switch (scsiqp->host_status) { + case QHSTA_NO_ERROR: + if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) { + ASC_DBG(2, "SAM_STAT_CHECK_CONDITION\n"); + ASC_DBG_PRT_SENSE(2, scp->sense_buffer, + sizeof(scp->sense_buffer)); + /* + * Note: The 'status_byte()' macro used by + * target drivers defined in scsi.h shifts the + * status byte returned by host drivers right + * by 1 bit. This is why target drivers also + * use right shifted status byte definitions. + * For instance target drivers use + * CHECK_CONDITION, defined to 0x1, instead of + * the SCSI defined check condition value of + * 0x2. Host drivers are supposed to return + * the status byte as it is defined by SCSI. + */ + scp->result = DRIVER_BYTE(DRIVER_SENSE) | + STATUS_BYTE(scsiqp->scsi_status); + } else { + scp->result = STATUS_BYTE(scsiqp->scsi_status); + } + break; + + default: + /* Some other QHSTA error occurred. */ + ASC_DBG(1, "host_status 0x%x\n", scsiqp->host_status); + scp->result = HOST_BYTE(DID_BAD_TARGET); + break; + } + break; + + case QD_ABORTED_BY_HOST: + ASC_DBG(1, "QD_ABORTED_BY_HOST\n"); + scp->result = + HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status); + break; + + default: + ASC_DBG(1, "done_status 0x%x\n", scsiqp->done_status); + scp->result = + HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status); + break; } - return (0); -} -static ASC_DCNT -AscLoadMicroCode(PortAddr iop_base, - ushort s_addr, uchar *mcode_buf, ushort mcode_size) -{ - ASC_DCNT chksum; - ushort mcode_word_size; - ushort mcode_chksum; + /* + * If the 'init_tidmask' bit isn't already set for the target and the + * current request finished normally, then set the bit for the target + * to indicate that a device is present. + */ + if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 && + scsiqp->done_status == QD_NO_ERROR && + scsiqp->host_status == QHSTA_NO_ERROR) { + boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id); + } - /* Write the microcode buffer starting at LRAM address 0. */ - mcode_word_size = (ushort)(mcode_size >> 1); - AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size); - AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size); + asc_scsi_done(scp); - chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size); - ASC_DBG1(1, "AscLoadMicroCode: chksum 0x%lx\n", (ulong)chksum); - mcode_chksum = (ushort)AscMemSumLramWord(iop_base, - (ushort)ASC_CODE_SEC_BEG, - (ushort)((mcode_size - - s_addr - (ushort) - ASC_CODE_SEC_BEG) / - 2)); - ASC_DBG1(1, "AscLoadMicroCode: mcode_chksum 0x%lx\n", - (ulong)mcode_chksum); - AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum); - AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size); - return (chksum); + /* + * Free all 'adv_sgblk_t' structures allocated for the request. + */ + while ((sgblkp = reqp->sgblkp) != NULL) { + /* Remove 'sgblkp' from the request list. */ + reqp->sgblkp = sgblkp->next_sgblkp; + + /* Add 'sgblkp' to the board free list. */ + sgblkp->next_sgblkp = boardp->adv_sgblkp; + boardp->adv_sgblkp = sgblkp; + } + + /* + * Free the adv_req_t structure used with the command by adding + * it back to the board free list. + */ + reqp->next_reqp = boardp->adv_reqp; + boardp->adv_reqp = reqp; + + ASC_DBG(1, "done\n"); } -static int AscFindSignature(PortAddr iop_base) +/* + * Adv Library Interrupt Service Routine + * + * This function is called by a driver's interrupt service routine. + * The function disables and re-enables interrupts. + * + * When a microcode idle command is completed, the ADV_DVC_VAR + * 'idle_cmd_done' field is set to ADV_TRUE. + * + * Note: AdvISR() can be called when interrupts are disabled or even + * when there is no hardware interrupt condition present. It will + * always check for completed idle commands and microcode requests. + * This is an important feature that shouldn't be changed because it + * allows commands to be completed from polling mode loops. + * + * Return: + * ADV_TRUE(1) - interrupt was pending + * ADV_FALSE(0) - no interrupt was pending + */ +static int AdvISR(ADV_DVC_VAR *asc_dvc) { - ushort sig_word; + AdvPortAddr iop_base; + uchar int_stat; + ushort target_bit; + ADV_CARR_T *free_carrp; + ADV_VADDR irq_next_vpa; + ADV_SCSI_REQ_Q *scsiq; - ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureByte(0x%x) 0x%x\n", - iop_base, AscGetChipSignatureByte(iop_base)); - if (AscGetChipSignatureByte(iop_base) == (uchar)ASC_1000_ID1B) { - ASC_DBG2(1, - "AscFindSignature: AscGetChipSignatureWord(0x%x) 0x%x\n", - iop_base, AscGetChipSignatureWord(iop_base)); - sig_word = AscGetChipSignatureWord(iop_base); - if ((sig_word == (ushort)ASC_1000_ID0W) || - (sig_word == (ushort)ASC_1000_ID0W_FIX)) { - return (1); - } + iop_base = asc_dvc->iop_base; + + /* Reading the register clears the interrupt. */ + int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG); + + if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB | + ADV_INTR_STATUS_INTRC)) == 0) { + return ADV_FALSE; } - return (0); -} -static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __initdata = { - 0x100, ASC_IOADR_1, 0x120, ASC_IOADR_2, 0x140, ASC_IOADR_3, ASC_IOADR_4, - ASC_IOADR_5, ASC_IOADR_6, ASC_IOADR_7, ASC_IOADR_8 -}; + /* + * Notify the driver of an asynchronous microcode condition by + * calling the adv_async_callback function. The function + * is passed the microcode ASC_MC_INTRB_CODE byte value. + */ + if (int_stat & ADV_INTR_STATUS_INTRB) { + uchar intrb_code; -#ifdef CONFIG_ISA -static uchar _isa_pnp_inited __initdata = 0; + AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code); -static PortAddr __init AscSearchIOPortAddr(PortAddr iop_beg, ushort bus_type) -{ - if (bus_type & ASC_IS_VL) { - while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) { - if (AscGetChipVersion(iop_beg, bus_type) <= - ASC_CHIP_MAX_VER_VL) { - return (iop_beg); + if (asc_dvc->chip_type == ADV_CHIP_ASC3550 || + asc_dvc->chip_type == ADV_CHIP_ASC38C0800) { + if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE && + asc_dvc->carr_pending_cnt != 0) { + AdvWriteByteRegister(iop_base, IOPB_TICKLE, + ADV_TICKLE_A); + if (asc_dvc->chip_type == ADV_CHIP_ASC3550) { + AdvWriteByteRegister(iop_base, + IOPB_TICKLE, + ADV_TICKLE_NOP); + } } } - return (0); + + adv_async_callback(asc_dvc, intrb_code); } - if (bus_type & ASC_IS_ISA) { - if (_isa_pnp_inited == 0) { - AscSetISAPNPWaitForKey(); - _isa_pnp_inited++; - } - while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) { - if ((AscGetChipVersion(iop_beg, bus_type) & - ASC_CHIP_VER_ISA_BIT) != 0) { - return (iop_beg); - } + + /* + * Check if the IRQ stopper carrier contains a completed request. + */ + while (((irq_next_vpa = + le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0) { + /* + * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure. + * The RISC will have set 'areq_vpa' to a virtual address. + * + * The firmware will have copied the ASC_SCSI_REQ_Q.scsiq_ptr + * field to the carrier ADV_CARR_T.areq_vpa field. The conversion + * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr' + * in AdvExeScsiQueue(). + */ + scsiq = (ADV_SCSI_REQ_Q *) + ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa)); + + /* + * Request finished with good status and the queue was not + * DMAed to host memory by the firmware. Set all status fields + * to indicate good status. + */ + if ((irq_next_vpa & ASC_RQ_GOOD) != 0) { + scsiq->done_status = QD_NO_ERROR; + scsiq->host_status = scsiq->scsi_status = 0; + scsiq->data_cnt = 0L; } - return (0); + + /* + * Advance the stopper pointer to the next carrier + * ignoring the lower four bits. Free the previous + * stopper carrier. + */ + free_carrp = asc_dvc->irq_sp; + asc_dvc->irq_sp = (ADV_CARR_T *) + ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa)); + + free_carrp->next_vpa = + cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist)); + asc_dvc->carr_freelist = free_carrp; + asc_dvc->carr_pending_cnt--; + + target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id); + + /* + * Clear request microcode control flag. + */ + scsiq->cntl = 0; + + /* + * Notify the driver of the completed request by passing + * the ADV_SCSI_REQ_Q pointer to its callback function. + */ + scsiq->a_flag |= ADV_SCSIQ_DONE; + adv_isr_callback(asc_dvc, scsiq); + /* + * Note: After the driver callback function is called, 'scsiq' + * can no longer be referenced. + * + * Fall through and continue processing other completed + * requests... + */ } - if (bus_type & ASC_IS_EISA) { - if ((iop_beg = AscSearchIOPortAddrEISA(iop_beg)) != 0) { - return (iop_beg); - } - return (0); + return ADV_TRUE; +} + +static int AscSetLibErrorCode(ASC_DVC_VAR *asc_dvc, ushort err_code) +{ + if (asc_dvc->err_code == 0) { + asc_dvc->err_code = err_code; + AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W, + err_code); } - return (0); + return err_code; } -static PortAddr __init AscSearchIOPortAddr11(PortAddr s_addr) +static void AscAckInterrupt(PortAddr iop_base) { - int i; - PortAddr iop_base; + uchar host_flag; + uchar risc_flag; + ushort loop; - for (i = 0; i < ASC_IOADR_TABLE_MAX_IX; i++) { - if (_asc_def_iop_base[i] > s_addr) { + loop = 0; + do { + risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B); + if (loop++ > 0x7FFF) { break; } - } - for (; i < ASC_IOADR_TABLE_MAX_IX; i++) { - iop_base = _asc_def_iop_base[i]; - if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) { - ASC_DBG1(1, - "AscSearchIOPortAddr11: check_region() failed I/O port 0x%x\n", - iop_base); - continue; - } - ASC_DBG1(1, "AscSearchIOPortAddr11: probing I/O port 0x%x\n", - iop_base); - release_region(iop_base, ASC_IOADR_GAP); - if (AscFindSignature(iop_base)) { - return (iop_base); + } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0); + host_flag = + AscReadLramByte(iop_base, + ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT); + AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, + (uchar)(host_flag | ASC_HOST_FLAG_ACK_INT)); + AscSetChipStatus(iop_base, CIW_INT_ACK); + loop = 0; + while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) { + AscSetChipStatus(iop_base, CIW_INT_ACK); + if (loop++ > 3) { + break; } } - return (0); + AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag); } -static void __init AscSetISAPNPWaitForKey(void) +static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *asc_dvc, uchar syn_time) { - outp(ASC_ISA_PNP_PORT_ADDR, 0x02); - outp(ASC_ISA_PNP_PORT_WRITE, 0x02); - return; + const uchar *period_table; + int max_index; + int min_index; + int i; + + period_table = asc_dvc->sdtr_period_tbl; + max_index = (int)asc_dvc->max_sdtr_index; + min_index = (int)asc_dvc->min_sdtr_index; + if ((syn_time <= period_table[max_index])) { + for (i = min_index; i < (max_index - 1); i++) { + if (syn_time <= period_table[i]) { + return (uchar)i; + } + } + return (uchar)max_index; + } else { + return (uchar)(max_index + 1); + } } -#endif /* CONFIG_ISA */ -static void __init AscToggleIRQAct(PortAddr iop_base) +static uchar +AscMsgOutSDTR(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar sdtr_offset) { - AscSetChipStatus(iop_base, CIW_IRQ_ACT); - AscSetChipStatus(iop_base, 0); - return; + EXT_MSG sdtr_buf; + uchar sdtr_period_index; + PortAddr iop_base; + + iop_base = asc_dvc->iop_base; + sdtr_buf.msg_type = EXTENDED_MESSAGE; + sdtr_buf.msg_len = MS_SDTR_LEN; + sdtr_buf.msg_req = EXTENDED_SDTR; + sdtr_buf.xfer_period = sdtr_period; + sdtr_offset &= ASC_SYN_MAX_OFFSET; + sdtr_buf.req_ack_offset = sdtr_offset; + sdtr_period_index = AscGetSynPeriodIndex(asc_dvc, sdtr_period); + if (sdtr_period_index <= asc_dvc->max_sdtr_index) { + AscMemWordCopyPtrToLram(iop_base, ASCV_MSGOUT_BEG, + (uchar *)&sdtr_buf, + sizeof(EXT_MSG) >> 1); + return ((sdtr_period_index << 4) | sdtr_offset); + } else { + sdtr_buf.req_ack_offset = 0; + AscMemWordCopyPtrToLram(iop_base, ASCV_MSGOUT_BEG, + (uchar *)&sdtr_buf, + sizeof(EXT_MSG) >> 1); + return 0; + } } -static uchar __init AscGetChipIRQ(PortAddr iop_base, ushort bus_type) +static uchar +AscCalSDTRData(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar syn_offset) { - ushort cfg_lsw; - uchar chip_irq; + uchar byte; + uchar sdtr_period_ix; - if ((bus_type & ASC_IS_EISA) != 0) { - cfg_lsw = AscGetEisaChipCfg(iop_base); - chip_irq = (uchar)(((cfg_lsw >> 8) & 0x07) + 10); - if ((chip_irq == 13) || (chip_irq > 15)) { - return (0); - } - return (chip_irq); - } - if ((bus_type & ASC_IS_VL) != 0) { - cfg_lsw = AscGetChipCfgLsw(iop_base); - chip_irq = (uchar)(((cfg_lsw >> 2) & 0x07)); - if ((chip_irq == 0) || (chip_irq == 4) || (chip_irq == 7)) { - return (0); - } - return ((uchar)(chip_irq + (ASC_MIN_IRQ_NO - 1))); - } - cfg_lsw = AscGetChipCfgLsw(iop_base); - chip_irq = (uchar)(((cfg_lsw >> 2) & 0x03)); - if (chip_irq == 3) - chip_irq += (uchar)2; - return ((uchar)(chip_irq + ASC_MIN_IRQ_NO)); + sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period); + if (sdtr_period_ix > asc_dvc->max_sdtr_index) + return 0xFF; + byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET); + return byte; } -static uchar __init -AscSetChipIRQ(PortAddr iop_base, uchar irq_no, ushort bus_type) +static int AscSetChipSynRegAtID(PortAddr iop_base, uchar id, uchar sdtr_data) { - ushort cfg_lsw; + ASC_SCSI_BIT_ID_TYPE org_id; + int i; + int sta = TRUE; - if ((bus_type & ASC_IS_VL) != 0) { - if (irq_no != 0) { - if ((irq_no < ASC_MIN_IRQ_NO) - || (irq_no > ASC_MAX_IRQ_NO)) { - irq_no = 0; - } else { - irq_no -= (uchar)((ASC_MIN_IRQ_NO - 1)); - } + AscSetBank(iop_base, 1); + org_id = AscReadChipDvcID(iop_base); + for (i = 0; i <= ASC_MAX_TID; i++) { + if (org_id == (0x01 << i)) + break; + } + org_id = (ASC_SCSI_BIT_ID_TYPE) i; + AscWriteChipDvcID(iop_base, id); + if (AscReadChipDvcID(iop_base) == (0x01 << id)) { + AscSetBank(iop_base, 0); + AscSetChipSyn(iop_base, sdtr_data); + if (AscGetChipSyn(iop_base) != sdtr_data) { + sta = FALSE; } - cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE3); - cfg_lsw |= (ushort)0x0010; - AscSetChipCfgLsw(iop_base, cfg_lsw); - AscToggleIRQAct(iop_base); - cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE0); - cfg_lsw |= (ushort)((irq_no & 0x07) << 2); - AscSetChipCfgLsw(iop_base, cfg_lsw); - AscToggleIRQAct(iop_base); - return (AscGetChipIRQ(iop_base, bus_type)); - } - if ((bus_type & (ASC_IS_ISA)) != 0) { - if (irq_no == 15) - irq_no -= (uchar)2; - irq_no -= (uchar)ASC_MIN_IRQ_NO; - cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFF3); - cfg_lsw |= (ushort)((irq_no & 0x03) << 2); - AscSetChipCfgLsw(iop_base, cfg_lsw); - return (AscGetChipIRQ(iop_base, bus_type)); + } else { + sta = FALSE; } - return (0); + AscSetBank(iop_base, 1); + AscWriteChipDvcID(iop_base, org_id); + AscSetBank(iop_base, 0); + return (sta); } -#ifdef CONFIG_ISA -static void __init AscEnableIsaDma(uchar dma_channel) +static void AscSetChipSDTR(PortAddr iop_base, uchar sdtr_data, uchar tid_no) { - if (dma_channel < 4) { - outp(0x000B, (ushort)(0xC0 | dma_channel)); - outp(0x000A, dma_channel); - } else if (dma_channel < 8) { - outp(0x00D6, (ushort)(0xC0 | (dma_channel - 4))); - outp(0x00D4, (ushort)(dma_channel - 4)); - } - return; + AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data); + AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data); } -#endif /* CONFIG_ISA */ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc) { @@ -8528,9 +8597,9 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc) uchar cur_dvc_qng; uchar asyn_sdtr; uchar scsi_status; - asc_board_t *boardp; + struct asc_board *boardp; - ASC_ASSERT(asc_dvc->drv_ptr != NULL); + BUG_ON(!asc_dvc->drv_ptr); boardp = asc_dvc->drv_ptr; iop_base = asc_dvc->iop_base; @@ -8541,8 +8610,7 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc) target_ix = AscReadLramByte(iop_base, (ushort)(halt_q_addr + (ushort)ASC_SCSIQ_B_TARGET_IX)); - q_cntl = - AscReadLramByte(iop_base, + q_cntl = AscReadLramByte(iop_base, (ushort)(halt_q_addr + (ushort)ASC_SCSIQ_B_CNTL)); tid_no = ASC_TIX_TO_TID(target_ix); target_id = (uchar)ASC_TID_TO_TARGET_ID(tid_no); @@ -8566,14 +8634,13 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc) AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); return (0); } else if (int_halt_code == ASC_HALT_EXTMSG_IN) { - AscMemWordCopyPtrFromLram(iop_base, ASCV_MSGIN_BEG, (uchar *)&ext_msg, sizeof(EXT_MSG) >> 1); - if (ext_msg.msg_type == MS_EXTEND && - ext_msg.msg_req == MS_SDTR_CODE && + if (ext_msg.msg_type == EXTENDED_MESSAGE && + ext_msg.msg_req == EXTENDED_SDTR && ext_msg.msg_len == MS_SDTR_LEN) { sdtr_accept = TRUE; if ((ext_msg.req_ack_offset > ASC_SYN_MAX_OFFSET)) { @@ -8582,15 +8649,14 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc) ext_msg.req_ack_offset = ASC_SYN_MAX_OFFSET; } if ((ext_msg.xfer_period < - asc_dvc->sdtr_period_tbl[asc_dvc-> - host_init_sdtr_index]) + asc_dvc->sdtr_period_tbl[asc_dvc->min_sdtr_index]) || (ext_msg.xfer_period > asc_dvc->sdtr_period_tbl[asc_dvc-> max_sdtr_index])) { sdtr_accept = FALSE; ext_msg.xfer_period = asc_dvc->sdtr_period_tbl[asc_dvc-> - host_init_sdtr_index]; + min_sdtr_index]; } if (sdtr_accept) { sdtr_data = @@ -8614,7 +8680,6 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc) AscSetChipSDTR(iop_base, asyn_sdtr, tid_no); } else { if (sdtr_accept && (q_cntl & QC_MSG_OUT)) { - q_cntl &= ~QC_MSG_OUT; asc_dvc->sdtr_done |= target_id; asc_dvc->init_sdtr |= target_id; @@ -8629,7 +8694,6 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc) tid_no); boardp->sdtr_data[tid_no] = sdtr_data; } else { - q_cntl |= QC_MSG_OUT; AscMsgOutSDTR(asc_dvc, ext_msg.xfer_period, @@ -8655,8 +8719,8 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc) q_cntl); AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); return (0); - } else if (ext_msg.msg_type == MS_EXTEND && - ext_msg.msg_req == MS_WDTR_CODE && + } else if (ext_msg.msg_type == EXTENDED_MESSAGE && + ext_msg.msg_req == EXTENDED_WDTR && ext_msg.msg_len == MS_WDTR_LEN) { ext_msg.wdtr_width = 0; @@ -8749,9 +8813,9 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc) (uchar *)&out_msg, sizeof(EXT_MSG) >> 1); - if ((out_msg.msg_type == MS_EXTEND) && + if ((out_msg.msg_type == EXTENDED_MESSAGE) && (out_msg.msg_len == MS_SDTR_LEN) && - (out_msg.msg_req == MS_SDTR_CODE)) { + (out_msg.msg_req == EXTENDED_SDTR)) { asc_dvc->init_sdtr &= ~target_id; asc_dvc->sdtr_done &= ~target_id; @@ -8797,9 +8861,9 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc) cur_dvc_qng); /* - * Set the device queue depth to the number of - * active requests when the QUEUE FULL condition - * was encountered. + * Set the device queue depth to the + * number of active requests when the + * QUEUE FULL condition was encountered. */ boardp->queue_full |= target_id; boardp->queue_full_cnt[tid_no] = @@ -8825,9 +8889,8 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc) int i; q_no = AscReadLramByte(iop_base, (ushort)ASCV_REQ_SG_LIST_QP); - if (q_no == ASC_QLINK_END) { - return (0); - } + if (q_no == ASC_QLINK_END) + return 0; q_addr = ASC_QNO_TO_QADDR(q_no); @@ -8879,8 +8942,8 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc) sg_entry_cnt = ASC_MAX_SG_LIST - 1; /* - * Keep track of remaining number of SG elements that will - * need to be handled on the next interrupt. + * Keep track of remaining number of SG elements that + * will need to be handled on the next interrupt. */ scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1); } else { @@ -8971,6 +9034,34 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc) return (0); } +/* + * void + * DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words) + * + * Calling/Exit State: + * none + * + * Description: + * Input an ASC_QDONE_INFO structure from the chip + */ +static void +DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words) +{ + int i; + ushort word; + + AscSetChipLramAddr(iop_base, s_addr); + for (i = 0; i < 2 * words; i += 2) { + if (i == 10) { + continue; + } + word = inpw(iop_base + IOP_RAM_DATA); + inbuf[i] = word & 0xff; + inbuf[i + 1] = (word >> 8) & 0xff; + } + ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words); +} + static uchar _AscCopyLramScsiDoneQ(PortAddr iop_base, ushort q_addr, @@ -9014,7 +9105,124 @@ _AscCopyLramScsiDoneQ(PortAddr iop_base, ASC_SCSIQ_DW_REMAIN_XFER_CNT)); scsiq->remain_bytes &= max_dma_count; - return (sg_queue_cnt); + return sg_queue_cnt; +} + +/* + * asc_isr_callback() - Second Level Interrupt Handler called by AscISR(). + * + * Interrupt callback function for the Narrow SCSI Asc Library. + */ +static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep) +{ + struct asc_board *boardp; + struct scsi_cmnd *scp; + struct Scsi_Host *shost; + + ASC_DBG(1, "asc_dvc_varp 0x%p, qdonep 0x%p\n", asc_dvc_varp, qdonep); + ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep); + + scp = advansys_srb_to_ptr(asc_dvc_varp, qdonep->d2.srb_ptr); + if (!scp) + return; + + ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len); + + shost = scp->device->host; + ASC_STATS(shost, callback); + ASC_DBG(1, "shost 0x%p\n", shost); + + boardp = shost_priv(shost); + BUG_ON(asc_dvc_varp != &boardp->dvc_var.asc_dvc_var); + + dma_unmap_single(boardp->dev, scp->SCp.dma_handle, + sizeof(scp->sense_buffer), DMA_FROM_DEVICE); + /* + * 'qdonep' contains the command's ending status. + */ + switch (qdonep->d3.done_stat) { + case QD_NO_ERROR: + ASC_DBG(2, "QD_NO_ERROR\n"); + scp->result = 0; + + /* + * Check for an underrun condition. + * + * If there was no error and an underrun condition, then + * return the number of underrun bytes. + */ + if (scsi_bufflen(scp) != 0 && qdonep->remain_bytes != 0 && + qdonep->remain_bytes <= scsi_bufflen(scp)) { + ASC_DBG(1, "underrun condition %u bytes\n", + (unsigned)qdonep->remain_bytes); + scsi_set_resid(scp, qdonep->remain_bytes); + } + break; + + case QD_WITH_ERROR: + ASC_DBG(2, "QD_WITH_ERROR\n"); + switch (qdonep->d3.host_stat) { + case QHSTA_NO_ERROR: + if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) { + ASC_DBG(2, "SAM_STAT_CHECK_CONDITION\n"); + ASC_DBG_PRT_SENSE(2, scp->sense_buffer, + sizeof(scp->sense_buffer)); + /* + * Note: The 'status_byte()' macro used by + * target drivers defined in scsi.h shifts the + * status byte returned by host drivers right + * by 1 bit. This is why target drivers also + * use right shifted status byte definitions. + * For instance target drivers use + * CHECK_CONDITION, defined to 0x1, instead of + * the SCSI defined check condition value of + * 0x2. Host drivers are supposed to return + * the status byte as it is defined by SCSI. + */ + scp->result = DRIVER_BYTE(DRIVER_SENSE) | + STATUS_BYTE(qdonep->d3.scsi_stat); + } else { + scp->result = STATUS_BYTE(qdonep->d3.scsi_stat); + } + break; + + default: + /* QHSTA error occurred */ + ASC_DBG(1, "host_stat 0x%x\n", qdonep->d3.host_stat); + scp->result = HOST_BYTE(DID_BAD_TARGET); + break; + } + break; + + case QD_ABORTED_BY_HOST: + ASC_DBG(1, "QD_ABORTED_BY_HOST\n"); + scp->result = + HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3. + scsi_msg) | + STATUS_BYTE(qdonep->d3.scsi_stat); + break; + + default: + ASC_DBG(1, "done_stat 0x%x\n", qdonep->d3.done_stat); + scp->result = + HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3. + scsi_msg) | + STATUS_BYTE(qdonep->d3.scsi_stat); + break; + } + + /* + * If the 'init_tidmask' bit isn't already set for the target and the + * current request finished normally, then set the bit for the target + * to indicate that a device is present. + */ + if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 && + qdonep->d3.done_stat == QD_NO_ERROR && + qdonep->d3.host_stat == QHSTA_NO_ERROR) { + boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id); + } + + asc_scsi_done(scp); } static int AscIsrQDone(ASC_DVC_VAR *asc_dvc) @@ -9035,10 +9243,8 @@ static int AscIsrQDone(ASC_DVC_VAR *asc_dvc) ASC_QDONE_INFO scsiq_buf; ASC_QDONE_INFO *scsiq; int false_overrun; - ASC_ISR_CALLBACK asc_isr_callback; iop_base = asc_dvc->iop_base; - asc_isr_callback = asc_dvc->isr_callback; n_q_used = 1; scsiq = (ASC_QDONE_INFO *)&scsiq_buf; done_q_tail = (uchar)AscGetVarDoneQTail(iop_base); @@ -9141,7 +9347,7 @@ static int AscIsrQDone(ASC_DVC_VAR *asc_dvc) AscSetChipControl(iop_base, (uchar)(CC_SCSI_RESET | CC_HALT)); - DvcDelayNanoSecond(asc_dvc, 60000); + udelay(60); AscSetChipControl(iop_base, CC_HALT); AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT); @@ -9150,7 +9356,7 @@ static int AscIsrQDone(ASC_DVC_VAR *asc_dvc) } } if ((scsiq->cntl & QC_NO_CALLBACK) == 0) { - (*asc_isr_callback) (asc_dvc, scsiq); + asc_isr_callback(asc_dvc, scsiq); } else { if ((AscReadLramByte(iop_base, (ushort)(q_addr + (ushort) @@ -9168,7 +9374,7 @@ static int AscIsrQDone(ASC_DVC_VAR *asc_dvc) AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS); FATAL_ERR_QDONE: if ((scsiq->cntl & QC_NO_CALLBACK) == 0) { - (*asc_isr_callback) (asc_dvc, scsiq); + asc_isr_callback(asc_dvc, scsiq); } return (0x80); } @@ -9190,22 +9396,19 @@ static int AscISR(ASC_DVC_VAR *asc_dvc) iop_base = asc_dvc->iop_base; int_pending = FALSE; - if (AscIsIntPending(iop_base) == 0) { + if (AscIsIntPending(iop_base) == 0) return int_pending; - } - if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0) - || (asc_dvc->isr_callback == 0) - ) { - return (ERR); + if ((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0) { + return ERR; } if (asc_dvc->in_critical_cnt != 0) { AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL); - return (ERR); + return ERR; } if (asc_dvc->is_in_int) { AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY); - return (ERR); + return ERR; } asc_dvc->is_in_int = TRUE; ctrl_reg = AscGetChipControl(iop_base); @@ -9220,7 +9423,7 @@ static int AscISR(ASC_DVC_VAR *asc_dvc) saved_ctrl_reg &= (uchar)(~CC_HALT); while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) && (i-- > 0)) { - DvcSleepMilliSecond(100); + mdelay(100); } AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT)); AscSetChipControl(iop_base, CC_HALT); @@ -9235,9 +9438,7 @@ static int AscISR(ASC_DVC_VAR *asc_dvc) (uchar)(~ASC_HOST_FLAG_IN_ISR); AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, (uchar)(host_flag | (uchar)ASC_HOST_FLAG_IN_ISR)); - if ((chipstat & CSW_INT_PENDING) - || (int_pending) - ) { + if ((chipstat & CSW_INT_PENDING) || (int_pending)) { AscAckInterrupt(iop_base); int_pending = TRUE; if ((chipstat & CSW_HALTED) && (ctrl_reg & CC_SINGLE_STEP)) { @@ -9268,615 +9469,767 @@ static int AscISR(ASC_DVC_VAR *asc_dvc) AscSetChipLramAddr(iop_base, saved_ram_addr); AscSetChipControl(iop_base, saved_ctrl_reg); asc_dvc->is_in_int = FALSE; - return (int_pending); + return int_pending; } -/* Microcode buffer is kept after initialization for error recovery. */ -static uchar _asc_mcode_buf[] = { - 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xC3, 0x12, 0x0D, 0x05, 0x01, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF, - 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x88, - 0x00, 0x00, 0x00, 0x00, - 0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73, - 0x03, 0x23, 0x36, 0x40, - 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2, - 0xC2, 0x00, 0x92, 0x80, - 0x1E, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xDF, 0x23, 0x36, 0x60, - 0xB6, 0x00, 0x92, 0x80, - 0x4F, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00, - 0x92, 0x80, 0x80, 0x62, - 0x92, 0x80, 0x00, 0x46, 0x15, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8, - 0xCD, 0x04, 0x4D, 0x00, - 0x00, 0xA3, 0xD6, 0x00, 0xA6, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01, - 0xE6, 0x84, 0xD2, 0xC1, - 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x01, 0xA6, 0x97, - 0xC6, 0x81, 0xC2, 0x88, - 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0xFE, 0x00, 0x4F, 0x00, - 0x84, 0x97, 0x07, 0xA6, - 0x08, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x01, 0xDE, - 0xC2, 0x88, 0xCE, 0x00, - 0x69, 0x60, 0xCE, 0x00, 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x78, 0x01, - 0x80, 0x63, 0x07, 0xA6, - 0x24, 0x01, 0x78, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6, - 0x34, 0x01, 0x00, 0x33, - 0x04, 0x00, 0xC2, 0x88, 0x03, 0x07, 0x02, 0x01, 0x04, 0xCA, 0x0D, 0x23, - 0x68, 0x98, 0x4D, 0x04, - 0x04, 0x85, 0x05, 0xD8, 0x0D, 0x23, 0x68, 0x98, 0xCD, 0x04, 0x15, 0x23, - 0xF8, 0x88, 0xFB, 0x23, - 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x62, 0x01, - 0x00, 0x33, 0x0A, 0x00, - 0xC2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x6E, 0x01, 0x00, 0x33, 0x0B, 0x00, - 0xC2, 0x88, 0xCD, 0x04, - 0x36, 0x2D, 0x00, 0x33, 0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x88, 0x81, - 0x06, 0xAB, 0x82, 0x01, - 0x88, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x92, 0x01, 0x50, 0x00, 0x00, 0xA3, - 0x3C, 0x01, 0x00, 0x05, - 0x7C, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6, 0x04, 0x23, 0xA0, 0x01, - 0x15, 0x23, 0xA1, 0x01, - 0xBE, 0x81, 0xFD, 0x23, 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00, - 0x06, 0x61, 0x00, 0xA0, - 0xB4, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00, - 0xC2, 0x88, 0x06, 0x23, - 0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01, 0x00, 0xA2, 0xD4, 0x01, - 0x57, 0x60, 0x00, 0xA0, - 0xDA, 0x01, 0xE6, 0x84, 0x80, 0x23, 0xA0, 0x01, 0xE6, 0x84, 0x80, 0x73, - 0x4B, 0x00, 0x06, 0x61, - 0x00, 0xA2, 0x00, 0x02, 0x04, 0x01, 0x0C, 0xDE, 0x02, 0x01, 0x03, 0xCC, - 0x4F, 0x00, 0x84, 0x97, - 0xFC, 0x81, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, 0x4F, 0x00, 0x62, 0x97, - 0x48, 0x04, 0x84, 0x80, - 0xF0, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00, - 0x81, 0x73, 0x06, 0x29, - 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x6B, 0xEB, 0x11, 0x23, 0xF8, 0x88, - 0x04, 0x98, 0xF0, 0x80, - 0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x2A, 0x02, 0x7C, 0x95, 0x06, 0xA6, - 0x34, 0x02, 0x03, 0xA6, - 0x4C, 0x04, 0x46, 0x82, 0x04, 0x01, 0x03, 0xD8, 0xB4, 0x98, 0x6A, 0x96, - 0x46, 0x82, 0xFE, 0x95, - 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x6C, 0x02, - 0x07, 0xA6, 0x5A, 0x02, - 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x62, 0x02, 0xC2, 0x88, 0x7C, 0x95, - 0x48, 0x82, 0x60, 0x96, - 0x48, 0x82, 0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84, - 0x04, 0x01, 0x0C, 0xDC, - 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01, - 0x6F, 0x00, 0xA5, 0x01, - 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, 0x1C, 0x01, - 0x02, 0xA6, 0xAA, 0x02, - 0x07, 0xA6, 0x5A, 0x02, 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x20, 0x04, - 0x01, 0xA6, 0xB4, 0x02, - 0x00, 0xA6, 0xB4, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E, - 0x80, 0x63, 0x00, 0x43, - 0x00, 0xA0, 0x8C, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, 0xE7, 0x23, - 0x04, 0x61, 0x84, 0x01, - 0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F, - 0x00, 0x00, 0xEA, 0x82, - 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0xA2, 0xC8, - 0x00, 0x33, 0x1F, 0x00, - 0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x7E, 0x98, - 0xB6, 0x2D, 0x01, 0xA6, - 0x14, 0x03, 0x00, 0xA6, 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6, - 0x10, 0x03, 0x03, 0xA6, - 0x20, 0x04, 0x02, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88, - 0x7C, 0x95, 0xEE, 0x82, - 0x60, 0x96, 0xEE, 0x82, 0x82, 0x98, 0x80, 0x42, 0x7E, 0x98, 0x64, 0xE4, - 0x04, 0x01, 0x2D, 0xC8, - 0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01, - 0x05, 0x05, 0x86, 0x98, - 0x7E, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6, - 0x3C, 0x04, 0x06, 0xA6, - 0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33, 0x25, 0x00, 0xC2, 0x88, - 0x7C, 0x95, 0x32, 0x83, - 0x60, 0x96, 0x32, 0x83, 0x04, 0x01, 0x10, 0xCE, 0x07, 0xC8, 0x05, 0x05, - 0xEB, 0x04, 0x00, 0x33, - 0x00, 0x20, 0xC0, 0x20, 0x81, 0x62, 0x72, 0x83, 0x00, 0x01, 0x05, 0x05, - 0xFF, 0xA2, 0x7A, 0x03, - 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83, 0x05, 0x05, 0x15, 0x01, - 0x00, 0xA2, 0x9A, 0x03, - 0xEC, 0x00, 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, - 0x01, 0xA6, 0x96, 0x03, - 0x00, 0xA6, 0x96, 0x03, 0x10, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6, - 0xA4, 0x03, 0x00, 0xA6, - 0xBC, 0x03, 0x10, 0x84, 0xA8, 0x98, 0x80, 0x42, 0x01, 0xA6, 0xA4, 0x03, - 0x07, 0xA6, 0xB2, 0x03, - 0xD4, 0x83, 0x7C, 0x95, 0xA8, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC2, 0x88, - 0xA8, 0x98, 0x80, 0x42, - 0x00, 0xA6, 0xBC, 0x03, 0x07, 0xA6, 0xCA, 0x03, 0xD4, 0x83, 0x7C, 0x95, - 0xC0, 0x83, 0x00, 0x33, - 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, 0x04, 0x23, - 0xA0, 0x01, 0x12, 0x23, - 0xA1, 0x01, 0x10, 0x84, 0x07, 0xF0, 0x06, 0xA4, 0xF4, 0x03, 0x80, 0x6B, - 0x80, 0x67, 0x05, 0x23, - 0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x0E, 0x04, 0x07, 0xA6, 0x06, 0x04, - 0x06, 0xA6, 0x0A, 0x04, - 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0xF4, 0x83, 0x60, 0x96, - 0xF4, 0x83, 0x20, 0x84, - 0x07, 0xF0, 0x06, 0xA4, 0x20, 0x04, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23, - 0x83, 0x03, 0x80, 0x63, - 0xB6, 0x2D, 0x03, 0xA6, 0x3C, 0x04, 0x07, 0xA6, 0x34, 0x04, 0x06, 0xA6, - 0x38, 0x04, 0x00, 0x33, - 0x30, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x20, 0x84, 0x60, 0x96, 0x20, 0x84, - 0x1D, 0x01, 0x06, 0xCC, - 0x00, 0x33, 0x00, 0x84, 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62, - 0xA2, 0x0D, 0x80, 0x63, - 0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03, - 0x80, 0x63, 0xA3, 0x01, - 0x07, 0xA4, 0x64, 0x04, 0x23, 0x01, 0x00, 0xA2, 0x86, 0x04, 0x0A, 0xA0, - 0x76, 0x04, 0xE0, 0x00, - 0x00, 0x33, 0x1D, 0x00, 0xC2, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00, - 0x00, 0x33, 0x1E, 0x00, - 0xC2, 0x88, 0x42, 0x23, 0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04, - 0x08, 0x23, 0x22, 0xA3, - 0xA2, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xAE, 0x04, 0x02, 0x23, 0x22, 0xA3, - 0xC4, 0x04, 0x42, 0x23, - 0xF8, 0x88, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23, - 0xF8, 0x88, 0x04, 0x98, - 0x00, 0xA2, 0xC0, 0x04, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20, - 0x81, 0x62, 0xE8, 0x81, - 0x47, 0x23, 0xF8, 0x88, 0x04, 0x01, 0x0B, 0xDE, 0x04, 0x98, 0xB4, 0x98, - 0x00, 0x33, 0x00, 0x81, - 0xC0, 0x20, 0x81, 0x62, 0x14, 0x01, 0x00, 0xA0, 0x00, 0x02, 0x43, 0x23, - 0xF8, 0x88, 0x04, 0x23, - 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3, - 0xF4, 0x04, 0x00, 0x33, - 0x27, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01, - 0x04, 0x23, 0xA0, 0x01, - 0x04, 0x98, 0x26, 0x95, 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00, - 0x00, 0xA3, 0x22, 0x05, - 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x1C, 0x05, 0x0A, 0x85, - 0x46, 0x97, 0xCD, 0x04, - 0x24, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23, - 0x82, 0x01, 0x34, 0x85, - 0x02, 0x23, 0xA0, 0x01, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x40, 0x05, - 0x1D, 0x01, 0x04, 0xD6, - 0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01, - 0x49, 0x00, 0x81, 0x01, - 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01, 0xF7, 0x04, 0x03, 0x01, - 0x49, 0x04, 0x80, 0x01, - 0xC9, 0x00, 0x00, 0x05, 0x00, 0x01, 0xFF, 0xA0, 0x60, 0x05, 0x77, 0x04, - 0x01, 0x23, 0xEA, 0x00, - 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63, - 0x07, 0xA4, 0xF8, 0x05, - 0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85, 0x00, 0x33, 0x2D, 0x00, - 0xC2, 0x88, 0x04, 0xA0, - 0xB8, 0x05, 0x80, 0x63, 0x00, 0x23, 0xDF, 0x00, 0x4A, 0x00, 0x06, 0x61, - 0x00, 0xA2, 0xA4, 0x05, - 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00, - 0x62, 0x97, 0x04, 0x85, - 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0x04, 0x85, 0x08, 0xA0, 0xBE, 0x05, - 0xF4, 0x85, 0x03, 0xA0, - 0xC4, 0x05, 0xF4, 0x85, 0x01, 0xA0, 0xCE, 0x05, 0x88, 0x00, 0x80, 0x63, - 0xCC, 0x86, 0x07, 0xA0, - 0xEE, 0x05, 0x5F, 0x00, 0x00, 0x2B, 0xDF, 0x08, 0x00, 0xA2, 0xE6, 0x05, - 0x80, 0x67, 0x80, 0x63, - 0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23, 0x68, 0x98, 0x48, 0x23, - 0xF8, 0x88, 0x07, 0x23, - 0x80, 0x00, 0x06, 0x87, 0x80, 0x63, 0x7C, 0x85, 0x00, 0x23, 0xDF, 0x00, - 0x00, 0x63, 0x4A, 0x00, - 0x06, 0x61, 0x00, 0xA2, 0x36, 0x06, 0x1D, 0x01, 0x16, 0xD4, 0xC0, 0x23, - 0x07, 0x41, 0x83, 0x03, - 0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33, 0x37, 0x00, 0xC2, 0x88, - 0x1D, 0x01, 0x01, 0xD6, - 0x20, 0x23, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x02, 0x23, 0xDF, 0x00, - 0x07, 0xA6, 0x7C, 0x05, - 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00, - 0x52, 0x00, 0x06, 0x61, - 0x00, 0xA2, 0x4E, 0x06, 0x1D, 0x01, 0x03, 0xCA, 0xC0, 0x23, 0x07, 0x41, - 0x00, 0x63, 0x1D, 0x01, - 0x04, 0xCC, 0x00, 0x33, 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23, - 0x07, 0x41, 0x00, 0x63, - 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x01, 0x23, - 0xDF, 0x00, 0x06, 0xA6, - 0x84, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x80, 0x63, 0x00, 0x33, - 0x00, 0x40, 0xC0, 0x20, - 0x81, 0x62, 0x00, 0x63, 0x00, 0x00, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63, - 0x06, 0xA6, 0x94, 0x06, - 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x00, 0x01, 0xA0, 0x14, 0x07, 0x00, 0x2B, - 0x40, 0x0E, 0x80, 0x63, - 0x01, 0x00, 0x06, 0xA6, 0xAA, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x40, 0x0E, - 0x80, 0x63, 0x00, 0x43, - 0x00, 0xA0, 0xA2, 0x06, 0x06, 0xA6, 0xBC, 0x06, 0x07, 0xA6, 0x7C, 0x05, - 0x80, 0x67, 0x40, 0x0E, - 0x80, 0x63, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63, - 0x07, 0xA6, 0xD6, 0x06, - 0x00, 0x33, 0x2A, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x80, 0x63, 0x89, 0x00, - 0x0A, 0x2B, 0x07, 0xA6, - 0xE8, 0x06, 0x00, 0x33, 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, 0x00, 0xA2, - 0xF4, 0x06, 0xC0, 0x0E, - 0x80, 0x63, 0xDE, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20, - 0x81, 0x62, 0x04, 0x01, - 0x02, 0xDA, 0x80, 0x63, 0x7C, 0x85, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, - 0x8C, 0x06, 0x00, 0x33, - 0x2C, 0x00, 0xC2, 0x88, 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03, - 0x80, 0x63, 0x06, 0xA6, - 0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88, - 0x00, 0x00, 0x80, 0x67, - 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x44, 0x07, 0x07, 0xA6, 0x7C, 0x05, - 0xBF, 0x23, 0x04, 0x61, - 0x84, 0x01, 0xE6, 0x84, 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00, - 0x00, 0x01, 0xF2, 0x00, - 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04, - 0x80, 0x05, 0x81, 0x05, - 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x01, 0x01, 0xF1, 0x00, - 0x70, 0x00, 0x81, 0x01, - 0x70, 0x04, 0x71, 0x00, 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04, - 0x70, 0x00, 0x80, 0x01, - 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01, - 0xF1, 0x00, 0x70, 0x00, - 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01, 0x72, 0x00, 0x81, 0x01, - 0x71, 0x04, 0x70, 0x00, - 0x81, 0x01, 0x70, 0x04, 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05, - 0xA3, 0x01, 0xA2, 0x01, - 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1, - 0xC4, 0x07, 0x00, 0x33, - 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8, - 0x48, 0x00, 0xB0, 0x01, - 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43, - 0x00, 0xA2, 0xE4, 0x07, - 0x00, 0x05, 0xDA, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01, - 0x05, 0x05, 0x00, 0x63, - 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x80, 0x43, - 0x76, 0x08, 0x80, 0x02, - 0x77, 0x04, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, - 0x00, 0x02, 0x00, 0xA0, - 0x14, 0x08, 0x16, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04, - 0x00, 0x63, 0xF3, 0x04, - 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43, 0xF4, 0x00, 0xCF, 0x40, - 0x00, 0xA2, 0x44, 0x08, - 0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1, - 0x24, 0x08, 0x04, 0x98, - 0x26, 0x95, 0x24, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04, - 0x5A, 0x88, 0x02, 0x01, - 0x04, 0xD8, 0x46, 0x97, 0x04, 0x98, 0x26, 0x95, 0x4A, 0x88, 0x75, 0x00, - 0x00, 0xA3, 0x64, 0x08, - 0x00, 0x05, 0x4E, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, - 0x06, 0xA6, 0x76, 0x08, - 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, - 0x00, 0x63, 0x38, 0x2B, - 0x9C, 0x88, 0x38, 0x2B, 0x92, 0x88, 0x32, 0x09, 0x31, 0x05, 0x92, 0x98, - 0x05, 0x05, 0xB2, 0x09, - 0x00, 0x63, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63, - 0x80, 0x32, 0x80, 0x36, - 0x80, 0x3A, 0x80, 0x3E, 0xB4, 0x3D, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32, - 0x40, 0x36, 0x40, 0x3A, - 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0xB4, 0x08, - 0x5D, 0x00, 0xFE, 0xC3, - 0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73, - 0xFF, 0xFD, 0x80, 0x73, - 0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01, - 0xA1, 0x23, 0xA1, 0x01, - 0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2, - 0x80, 0x00, 0x03, 0xC2, - 0xF1, 0xC7, 0x41, 0x23, 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23, - 0xA0, 0x01, 0xE6, 0x84, -}; +/* + * advansys_reset() + * + * Reset the bus associated with the command 'scp'. + * + * This function runs its own thread. Interrupts must be blocked but + * sleeping is allowed and no locking other than for host structures is + * required. Returns SUCCESS or FAILED. + */ +static int advansys_reset(struct scsi_cmnd *scp) +{ + struct Scsi_Host *shost = scp->device->host; + struct asc_board *boardp = shost_priv(shost); + unsigned long flags; + int status; + int ret = SUCCESS; -static ushort _asc_mcode_size = sizeof(_asc_mcode_buf); -static ADV_DCNT _asc_mcode_chksum = 0x012C453FUL; + ASC_DBG(1, "0x%p\n", scp); -#define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16 -static uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = { - INQUIRY, - REQUEST_SENSE, - READ_CAPACITY, - READ_TOC, - MODE_SELECT, - MODE_SENSE, - MODE_SELECT_10, - MODE_SENSE_10, - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0xFF -}; + ASC_STATS(shost, reset); -static int AscExeScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq) -{ - PortAddr iop_base; - ulong last_int_level; - int sta; - int n_q_required; - int disable_syn_offset_one_fix; - int i; - ASC_PADDR addr; - ASC_EXE_CALLBACK asc_exe_callback; - ushort sg_entry_cnt = 0; - ushort sg_entry_cnt_minus_one = 0; - uchar target_ix; - uchar tid_no; - uchar sdtr_data; - uchar extra_bytes; - uchar scsi_cmd; - uchar disable_cmd; - ASC_SG_HEAD *sg_head; - ASC_DCNT data_cnt; + scmd_printk(KERN_INFO, scp, "SCSI bus reset started...\n"); - iop_base = asc_dvc->iop_base; - sg_head = scsiq->sg_head; - asc_exe_callback = asc_dvc->exe_callback; - if (asc_dvc->err_code != 0) - return (ERR); - if (scsiq == (ASC_SCSI_Q *)0L) { - AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_NULL_PTR); - return (ERR); - } - scsiq->q1.q_no = 0; - if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) { - scsiq->q1.extra_bytes = 0; - } - sta = 0; - target_ix = scsiq->q2.target_ix; - tid_no = ASC_TIX_TO_TID(target_ix); - n_q_required = 1; - if (scsiq->cdbptr[0] == REQUEST_SENSE) { - if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) { - asc_dvc->sdtr_done &= ~scsiq->q1.target_id; - sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no); - AscMsgOutSDTR(asc_dvc, - asc_dvc-> - sdtr_period_tbl[(sdtr_data >> 4) & - (uchar)(asc_dvc-> - max_sdtr_index - - 1)], - (uchar)(sdtr_data & (uchar) - ASC_SYN_MAX_OFFSET)); - scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT); + if (ASC_NARROW_BOARD(boardp)) { + ASC_DVC_VAR *asc_dvc = &boardp->dvc_var.asc_dvc_var; + + /* Reset the chip and SCSI bus. */ + ASC_DBG(1, "before AscInitAsc1000Driver()\n"); + status = AscInitAsc1000Driver(asc_dvc); + + /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */ + if (asc_dvc->err_code) { + scmd_printk(KERN_INFO, scp, "SCSI bus reset error: " + "0x%x\n", asc_dvc->err_code); + ret = FAILED; + } else if (status) { + scmd_printk(KERN_INFO, scp, "SCSI bus reset warning: " + "0x%x\n", status); + } else { + scmd_printk(KERN_INFO, scp, "SCSI bus reset " + "successful\n"); + } + + ASC_DBG(1, "after AscInitAsc1000Driver()\n"); + spin_lock_irqsave(shost->host_lock, flags); + } else { + /* + * If the suggest reset bus flags are set, then reset the bus. + * Otherwise only reset the device. + */ + ADV_DVC_VAR *adv_dvc = &boardp->dvc_var.adv_dvc_var; + + /* + * Reset the target's SCSI bus. + */ + ASC_DBG(1, "before AdvResetChipAndSB()\n"); + switch (AdvResetChipAndSB(adv_dvc)) { + case ASC_TRUE: + scmd_printk(KERN_INFO, scp, "SCSI bus reset " + "successful\n"); + break; + case ASC_FALSE: + default: + scmd_printk(KERN_INFO, scp, "SCSI bus reset error\n"); + ret = FAILED; + break; } + spin_lock_irqsave(shost->host_lock, flags); + AdvISR(adv_dvc); } - last_int_level = DvcEnterCritical(); - if (asc_dvc->in_critical_cnt != 0) { - DvcLeaveCritical(last_int_level); - AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY); - return (ERR); + + /* Save the time of the most recently completed reset. */ + boardp->last_reset = jiffies; + spin_unlock_irqrestore(shost->host_lock, flags); + + ASC_DBG(1, "ret %d\n", ret); + + return ret; +} + +/* + * advansys_biosparam() + * + * Translate disk drive geometry if the "BIOS greater than 1 GB" + * support is enabled for a drive. + * + * ip (information pointer) is an int array with the following definition: + * ip[0]: heads + * ip[1]: sectors + * ip[2]: cylinders + */ +static int +advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev, + sector_t capacity, int ip[]) +{ + struct asc_board *boardp = shost_priv(sdev->host); + + ASC_DBG(1, "begin\n"); + ASC_STATS(sdev->host, biosparam); + if (ASC_NARROW_BOARD(boardp)) { + if ((boardp->dvc_var.asc_dvc_var.dvc_cntl & + ASC_CNTL_BIOS_GT_1GB) && capacity > 0x200000) { + ip[0] = 255; + ip[1] = 63; + } else { + ip[0] = 64; + ip[1] = 32; + } + } else { + if ((boardp->dvc_var.adv_dvc_var.bios_ctrl & + BIOS_CTRL_EXTENDED_XLAT) && capacity > 0x200000) { + ip[0] = 255; + ip[1] = 63; + } else { + ip[0] = 64; + ip[1] = 32; + } } - asc_dvc->in_critical_cnt++; - if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) { - if ((sg_entry_cnt = sg_head->entry_cnt) == 0) { - asc_dvc->in_critical_cnt--; - DvcLeaveCritical(last_int_level); - return (ERR); + ip[2] = (unsigned long)capacity / (ip[0] * ip[1]); + ASC_DBG(1, "end\n"); + return 0; +} + +/* + * First-level interrupt handler. + * + * 'dev_id' is a pointer to the interrupting adapter's Scsi_Host. + */ +static irqreturn_t advansys_interrupt(int irq, void *dev_id) +{ + struct Scsi_Host *shost = dev_id; + struct asc_board *boardp = shost_priv(shost); + irqreturn_t result = IRQ_NONE; + + ASC_DBG(2, "boardp 0x%p\n", boardp); + spin_lock(shost->host_lock); + if (ASC_NARROW_BOARD(boardp)) { + if (AscIsIntPending(shost->io_port)) { + result = IRQ_HANDLED; + ASC_STATS(shost, interrupt); + ASC_DBG(1, "before AscISR()\n"); + AscISR(&boardp->dvc_var.asc_dvc_var); } -#if !CC_VERY_LONG_SG_LIST - if (sg_entry_cnt > ASC_MAX_SG_LIST) { - asc_dvc->in_critical_cnt--; - DvcLeaveCritical(last_int_level); - return (ERR); + } else { + ASC_DBG(1, "before AdvISR()\n"); + if (AdvISR(&boardp->dvc_var.adv_dvc_var)) { + result = IRQ_HANDLED; + ASC_STATS(shost, interrupt); } -#endif /* !CC_VERY_LONG_SG_LIST */ - if (sg_entry_cnt == 1) { - scsiq->q1.data_addr = - (ADV_PADDR)sg_head->sg_list[0].addr; - scsiq->q1.data_cnt = - (ADV_DCNT)sg_head->sg_list[0].bytes; - scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE); + } + spin_unlock(shost->host_lock); + + ASC_DBG(1, "end\n"); + return result; +} + +static int AscHostReqRiscHalt(PortAddr iop_base) +{ + int count = 0; + int sta = 0; + uchar saved_stop_code; + + if (AscIsChipHalted(iop_base)) + return (1); + saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B); + AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, + ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP); + do { + if (AscIsChipHalted(iop_base)) { + sta = 1; + break; } - sg_entry_cnt_minus_one = sg_entry_cnt - 1; + mdelay(100); + } while (count++ < 20); + AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code); + return (sta); +} + +static int +AscSetRunChipSynRegAtID(PortAddr iop_base, uchar tid_no, uchar sdtr_data) +{ + int sta = FALSE; + + if (AscHostReqRiscHalt(iop_base)) { + sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data); + AscStartChip(iop_base); } - scsi_cmd = scsiq->cdbptr[0]; - disable_syn_offset_one_fix = FALSE; - if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) && - !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) { - if (scsiq->q1.cntl & QC_SG_HEAD) { - data_cnt = 0; - for (i = 0; i < sg_entry_cnt; i++) { - data_cnt += - (ADV_DCNT)le32_to_cpu(sg_head->sg_list[i]. - bytes); - } + return sta; +} + +static void AscAsyncFix(ASC_DVC_VAR *asc_dvc, struct scsi_device *sdev) +{ + char type = sdev->type; + ASC_SCSI_BIT_ID_TYPE tid_bits = 1 << sdev->id; + + if (!(asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN)) + return; + if (asc_dvc->init_sdtr & tid_bits) + return; + + if ((type == TYPE_ROM) && (strncmp(sdev->vendor, "HP ", 3) == 0)) + asc_dvc->pci_fix_asyn_xfer_always |= tid_bits; + + asc_dvc->pci_fix_asyn_xfer |= tid_bits; + if ((type == TYPE_PROCESSOR) || (type == TYPE_SCANNER) || + (type == TYPE_ROM) || (type == TYPE_TAPE)) + asc_dvc->pci_fix_asyn_xfer &= ~tid_bits; + + if (asc_dvc->pci_fix_asyn_xfer & tid_bits) + AscSetRunChipSynRegAtID(asc_dvc->iop_base, sdev->id, + ASYN_SDTR_DATA_FIX_PCI_REV_AB); +} + +static void +advansys_narrow_slave_configure(struct scsi_device *sdev, ASC_DVC_VAR *asc_dvc) +{ + ASC_SCSI_BIT_ID_TYPE tid_bit = 1 << sdev->id; + ASC_SCSI_BIT_ID_TYPE orig_use_tagged_qng = asc_dvc->use_tagged_qng; + + if (sdev->lun == 0) { + ASC_SCSI_BIT_ID_TYPE orig_init_sdtr = asc_dvc->init_sdtr; + if ((asc_dvc->cfg->sdtr_enable & tid_bit) && sdev->sdtr) { + asc_dvc->init_sdtr |= tid_bit; } else { - data_cnt = le32_to_cpu(scsiq->q1.data_cnt); + asc_dvc->init_sdtr &= ~tid_bit; } - if (data_cnt != 0UL) { - if (data_cnt < 512UL) { - disable_syn_offset_one_fix = TRUE; - } else { - for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST; - i++) { - disable_cmd = - _syn_offset_one_disable_cmd[i]; - if (disable_cmd == 0xFF) { - break; - } - if (scsi_cmd == disable_cmd) { - disable_syn_offset_one_fix = - TRUE; - break; - } - } + + if (orig_init_sdtr != asc_dvc->init_sdtr) + AscAsyncFix(asc_dvc, sdev); + } + + if (sdev->tagged_supported) { + if (asc_dvc->cfg->cmd_qng_enabled & tid_bit) { + if (sdev->lun == 0) { + asc_dvc->cfg->can_tagged_qng |= tid_bit; + asc_dvc->use_tagged_qng |= tid_bit; } + scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, + asc_dvc->max_dvc_qng[sdev->id]); + } + } else { + if (sdev->lun == 0) { + asc_dvc->cfg->can_tagged_qng &= ~tid_bit; + asc_dvc->use_tagged_qng &= ~tid_bit; } + scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); } - if (disable_syn_offset_one_fix) { - scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG; - scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX | - ASC_TAG_FLAG_DISABLE_DISCONNECT); + + if ((sdev->lun == 0) && + (orig_use_tagged_qng != asc_dvc->use_tagged_qng)) { + AscWriteLramByte(asc_dvc->iop_base, ASCV_DISC_ENABLE_B, + asc_dvc->cfg->disc_enable); + AscWriteLramByte(asc_dvc->iop_base, ASCV_USE_TAGGED_QNG_B, + asc_dvc->use_tagged_qng); + AscWriteLramByte(asc_dvc->iop_base, ASCV_CAN_TAGGED_QNG_B, + asc_dvc->cfg->can_tagged_qng); + + asc_dvc->max_dvc_qng[sdev->id] = + asc_dvc->cfg->max_tag_qng[sdev->id]; + AscWriteLramByte(asc_dvc->iop_base, + (ushort)(ASCV_MAX_DVC_QNG_BEG + sdev->id), + asc_dvc->max_dvc_qng[sdev->id]); + } +} + +/* + * Wide Transfers + * + * If the EEPROM enabled WDTR for the device and the device supports wide + * bus (16 bit) transfers, then turn on the device's 'wdtr_able' bit and + * write the new value to the microcode. + */ +static void +advansys_wide_enable_wdtr(AdvPortAddr iop_base, unsigned short tidmask) +{ + unsigned short cfg_word; + AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word); + if ((cfg_word & tidmask) != 0) + return; + + cfg_word |= tidmask; + AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word); + + /* + * Clear the microcode SDTR and WDTR negotiation done indicators for + * the target to cause it to negotiate with the new setting set above. + * WDTR when accepted causes the target to enter asynchronous mode, so + * SDTR must be negotiated. + */ + AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word); + cfg_word &= ~tidmask; + AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word); + AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word); + cfg_word &= ~tidmask; + AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word); +} + +/* + * Synchronous Transfers + * + * If the EEPROM enabled SDTR for the device and the device + * supports synchronous transfers, then turn on the device's + * 'sdtr_able' bit. Write the new value to the microcode. + */ +static void +advansys_wide_enable_sdtr(AdvPortAddr iop_base, unsigned short tidmask) +{ + unsigned short cfg_word; + AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word); + if ((cfg_word & tidmask) != 0) + return; + + cfg_word |= tidmask; + AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word); + + /* + * Clear the microcode "SDTR negotiation" done indicator for the + * target to cause it to negotiate with the new setting set above. + */ + AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word); + cfg_word &= ~tidmask; + AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word); +} + +/* + * PPR (Parallel Protocol Request) Capable + * + * If the device supports DT mode, then it must be PPR capable. + * The PPR message will be used in place of the SDTR and WDTR + * messages to negotiate synchronous speed and offset, transfer + * width, and protocol options. + */ +static void advansys_wide_enable_ppr(ADV_DVC_VAR *adv_dvc, + AdvPortAddr iop_base, unsigned short tidmask) +{ + AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able); + adv_dvc->ppr_able |= tidmask; + AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able); +} + +static void +advansys_wide_slave_configure(struct scsi_device *sdev, ADV_DVC_VAR *adv_dvc) +{ + AdvPortAddr iop_base = adv_dvc->iop_base; + unsigned short tidmask = 1 << sdev->id; + + if (sdev->lun == 0) { + /* + * Handle WDTR, SDTR, and Tag Queuing. If the feature + * is enabled in the EEPROM and the device supports the + * feature, then enable it in the microcode. + */ + + if ((adv_dvc->wdtr_able & tidmask) && sdev->wdtr) + advansys_wide_enable_wdtr(iop_base, tidmask); + if ((adv_dvc->sdtr_able & tidmask) && sdev->sdtr) + advansys_wide_enable_sdtr(iop_base, tidmask); + if (adv_dvc->chip_type == ADV_CHIP_ASC38C1600 && sdev->ppr) + advansys_wide_enable_ppr(adv_dvc, iop_base, tidmask); + + /* + * Tag Queuing is disabled for the BIOS which runs in polled + * mode and would see no benefit from Tag Queuing. Also by + * disabling Tag Queuing in the BIOS devices with Tag Queuing + * bugs will at least work with the BIOS. + */ + if ((adv_dvc->tagqng_able & tidmask) && + sdev->tagged_supported) { + unsigned short cfg_word; + AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word); + cfg_word |= tidmask; + AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, + cfg_word); + AdvWriteByteLram(iop_base, + ASC_MC_NUMBER_OF_MAX_CMD + sdev->id, + adv_dvc->max_dvc_qng); + } + } + + if ((adv_dvc->tagqng_able & tidmask) && sdev->tagged_supported) { + scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, + adv_dvc->max_dvc_qng); } else { - scsiq->q2.tag_code &= 0x27; + scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); } - if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) { - if (asc_dvc->bug_fix_cntl) { - if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) { - if ((scsi_cmd == READ_6) || - (scsi_cmd == READ_10)) { - addr = - (ADV_PADDR)le32_to_cpu(sg_head-> - sg_list - [sg_entry_cnt_minus_one]. - addr) + - (ADV_DCNT)le32_to_cpu(sg_head-> - sg_list - [sg_entry_cnt_minus_one]. - bytes); - extra_bytes = - (uchar)((ushort)addr & 0x0003); - if ((extra_bytes != 0) - && - ((scsiq->q2. - tag_code & - ASC_TAG_FLAG_EXTRA_BYTES) - == 0)) { - scsiq->q2.tag_code |= - ASC_TAG_FLAG_EXTRA_BYTES; - scsiq->q1.extra_bytes = - extra_bytes; - data_cnt = - le32_to_cpu(sg_head-> - sg_list - [sg_entry_cnt_minus_one]. - bytes); - data_cnt -= - (ASC_DCNT) extra_bytes; - sg_head-> - sg_list - [sg_entry_cnt_minus_one]. - bytes = - cpu_to_le32(data_cnt); - } - } - } +} + +/* + * Set the number of commands to queue per device for the + * specified host adapter. + */ +static int advansys_slave_configure(struct scsi_device *sdev) +{ + struct asc_board *boardp = shost_priv(sdev->host); + + if (ASC_NARROW_BOARD(boardp)) + advansys_narrow_slave_configure(sdev, + &boardp->dvc_var.asc_dvc_var); + else + advansys_wide_slave_configure(sdev, + &boardp->dvc_var.adv_dvc_var); + + return 0; +} + +static __le32 advansys_get_sense_buffer_dma(struct scsi_cmnd *scp) +{ + struct asc_board *board = shost_priv(scp->device->host); + scp->SCp.dma_handle = dma_map_single(board->dev, scp->sense_buffer, + sizeof(scp->sense_buffer), DMA_FROM_DEVICE); + dma_cache_sync(board->dev, scp->sense_buffer, + sizeof(scp->sense_buffer), DMA_FROM_DEVICE); + return cpu_to_le32(scp->SCp.dma_handle); +} + +static int asc_build_req(struct asc_board *boardp, struct scsi_cmnd *scp, + struct asc_scsi_q *asc_scsi_q) +{ + struct asc_dvc_var *asc_dvc = &boardp->dvc_var.asc_dvc_var; + int use_sg; + + memset(asc_scsi_q, 0, sizeof(*asc_scsi_q)); + + /* + * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'. + */ + asc_scsi_q->q2.srb_ptr = advansys_ptr_to_srb(asc_dvc, scp); + if (asc_scsi_q->q2.srb_ptr == BAD_SRB) { + scp->result = HOST_BYTE(DID_SOFT_ERROR); + return ASC_ERROR; + } + + /* + * Build the ASC_SCSI_Q request. + */ + asc_scsi_q->cdbptr = &scp->cmnd[0]; + asc_scsi_q->q2.cdb_len = scp->cmd_len; + asc_scsi_q->q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id); + asc_scsi_q->q1.target_lun = scp->device->lun; + asc_scsi_q->q2.target_ix = + ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun); + asc_scsi_q->q1.sense_addr = advansys_get_sense_buffer_dma(scp); + asc_scsi_q->q1.sense_len = sizeof(scp->sense_buffer); + + /* + * If there are any outstanding requests for the current target, + * then every 255th request send an ORDERED request. This heuristic + * tries to retain the benefit of request sorting while preventing + * request starvation. 255 is the max number of tags or pending commands + * a device may have outstanding. + * + * The request count is incremented below for every successfully + * started request. + * + */ + if ((asc_dvc->cur_dvc_qng[scp->device->id] > 0) && + (boardp->reqcnt[scp->device->id] % 255) == 0) { + asc_scsi_q->q2.tag_code = MSG_ORDERED_TAG; + } else { + asc_scsi_q->q2.tag_code = MSG_SIMPLE_TAG; + } + + /* Build ASC_SCSI_Q */ + use_sg = scsi_dma_map(scp); + if (use_sg != 0) { + int sgcnt; + struct scatterlist *slp; + struct asc_sg_head *asc_sg_head; + + if (use_sg > scp->device->host->sg_tablesize) { + scmd_printk(KERN_ERR, scp, "use_sg %d > " + "sg_tablesize %d\n", use_sg, + scp->device->host->sg_tablesize); + scsi_dma_unmap(scp); + scp->result = HOST_BYTE(DID_ERROR); + return ASC_ERROR; } - sg_head->entry_to_copy = sg_head->entry_cnt; -#if CC_VERY_LONG_SG_LIST + + asc_sg_head = kzalloc(sizeof(asc_scsi_q->sg_head) + + use_sg * sizeof(struct asc_sg_list), GFP_ATOMIC); + if (!asc_sg_head) { + scsi_dma_unmap(scp); + scp->result = HOST_BYTE(DID_SOFT_ERROR); + return ASC_ERROR; + } + + asc_scsi_q->q1.cntl |= QC_SG_HEAD; + asc_scsi_q->sg_head = asc_sg_head; + asc_scsi_q->q1.data_cnt = 0; + asc_scsi_q->q1.data_addr = 0; + /* This is a byte value, otherwise it would need to be swapped. */ + asc_sg_head->entry_cnt = asc_scsi_q->q1.sg_queue_cnt = use_sg; + ASC_STATS_ADD(scp->device->host, xfer_elem, + asc_sg_head->entry_cnt); + /* - * Set the sg_entry_cnt to the maximum possible. The rest of - * the SG elements will be copied when the RISC completes the - * SG elements that fit and halts. + * Convert scatter-gather list into ASC_SG_HEAD list. */ - if (sg_entry_cnt > ASC_MAX_SG_LIST) { - sg_entry_cnt = ASC_MAX_SG_LIST; + scsi_for_each_sg(scp, slp, use_sg, sgcnt) { + asc_sg_head->sg_list[sgcnt].addr = + cpu_to_le32(sg_dma_address(slp)); + asc_sg_head->sg_list[sgcnt].bytes = + cpu_to_le32(sg_dma_len(slp)); + ASC_STATS_ADD(scp->device->host, xfer_sect, + DIV_ROUND_UP(sg_dma_len(slp), 512)); } -#endif /* CC_VERY_LONG_SG_LIST */ - n_q_required = AscSgListToQueue(sg_entry_cnt); - if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >= - (uint) n_q_required) - || ((scsiq->q1.cntl & QC_URGENT) != 0)) { - if ((sta = - AscSendScsiQueue(asc_dvc, scsiq, - n_q_required)) == 1) { - asc_dvc->in_critical_cnt--; - if (asc_exe_callback != 0) { - (*asc_exe_callback) (asc_dvc, scsiq); - } - DvcLeaveCritical(last_int_level); - return (sta); + } + + ASC_STATS(scp->device->host, xfer_cnt); + + ASC_DBG_PRT_ASC_SCSI_Q(2, asc_scsi_q); + ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len); + + return ASC_NOERROR; +} + +/* + * Build scatter-gather list for Adv Library (Wide Board). + * + * Additional ADV_SG_BLOCK structures will need to be allocated + * if the total number of scatter-gather elements exceeds + * NO_OF_SG_PER_BLOCK (15). The ADV_SG_BLOCK structures are + * assumed to be physically contiguous. + * + * Return: + * ADV_SUCCESS(1) - SG List successfully created + * ADV_ERROR(-1) - SG List creation failed + */ +static int +adv_get_sglist(struct asc_board *boardp, adv_req_t *reqp, struct scsi_cmnd *scp, + int use_sg) +{ + adv_sgblk_t *sgblkp; + ADV_SCSI_REQ_Q *scsiqp; + struct scatterlist *slp; + int sg_elem_cnt; + ADV_SG_BLOCK *sg_block, *prev_sg_block; + ADV_PADDR sg_block_paddr; + int i; + + scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q); + slp = scsi_sglist(scp); + sg_elem_cnt = use_sg; + prev_sg_block = NULL; + reqp->sgblkp = NULL; + + for (;;) { + /* + * Allocate a 'adv_sgblk_t' structure from the board free + * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK + * (15) scatter-gather elements. + */ + if ((sgblkp = boardp->adv_sgblkp) == NULL) { + ASC_DBG(1, "no free adv_sgblk_t\n"); + ASC_STATS(scp->device->host, adv_build_nosg); + + /* + * Allocation failed. Free 'adv_sgblk_t' structures + * already allocated for the request. + */ + while ((sgblkp = reqp->sgblkp) != NULL) { + /* Remove 'sgblkp' from the request list. */ + reqp->sgblkp = sgblkp->next_sgblkp; + + /* Add 'sgblkp' to the board free list. */ + sgblkp->next_sgblkp = boardp->adv_sgblkp; + boardp->adv_sgblkp = sgblkp; } + return ASC_BUSY; } - } else { - if (asc_dvc->bug_fix_cntl) { - if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) { - if ((scsi_cmd == READ_6) || - (scsi_cmd == READ_10)) { - addr = - le32_to_cpu(scsiq->q1.data_addr) + - le32_to_cpu(scsiq->q1.data_cnt); - extra_bytes = - (uchar)((ushort)addr & 0x0003); - if ((extra_bytes != 0) - && - ((scsiq->q2. - tag_code & - ASC_TAG_FLAG_EXTRA_BYTES) - == 0)) { - data_cnt = - le32_to_cpu(scsiq->q1. - data_cnt); - if (((ushort)data_cnt & 0x01FF) - == 0) { - scsiq->q2.tag_code |= - ASC_TAG_FLAG_EXTRA_BYTES; - data_cnt -= (ASC_DCNT) - extra_bytes; - scsiq->q1.data_cnt = - cpu_to_le32 - (data_cnt); - scsiq->q1.extra_bytes = - extra_bytes; - } - } - } - } + + /* Complete 'adv_sgblk_t' board allocation. */ + boardp->adv_sgblkp = sgblkp->next_sgblkp; + sgblkp->next_sgblkp = NULL; + + /* + * Get 8 byte aligned virtual and physical addresses + * for the allocated ADV_SG_BLOCK structure. + */ + sg_block = (ADV_SG_BLOCK *)ADV_8BALIGN(&sgblkp->sg_block); + sg_block_paddr = virt_to_bus(sg_block); + + /* + * Check if this is the first 'adv_sgblk_t' for the + * request. + */ + if (reqp->sgblkp == NULL) { + /* Request's first scatter-gather block. */ + reqp->sgblkp = sgblkp; + + /* + * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical + * address pointers. + */ + scsiqp->sg_list_ptr = sg_block; + scsiqp->sg_real_addr = cpu_to_le32(sg_block_paddr); + } else { + /* Request's second or later scatter-gather block. */ + sgblkp->next_sgblkp = reqp->sgblkp; + reqp->sgblkp = sgblkp; + + /* + * Point the previous ADV_SG_BLOCK structure to + * the newly allocated ADV_SG_BLOCK structure. + */ + prev_sg_block->sg_ptr = cpu_to_le32(sg_block_paddr); } - n_q_required = 1; - if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) || - ((scsiq->q1.cntl & QC_URGENT) != 0)) { - if ((sta = AscSendScsiQueue(asc_dvc, scsiq, - n_q_required)) == 1) { - asc_dvc->in_critical_cnt--; - if (asc_exe_callback != 0) { - (*asc_exe_callback) (asc_dvc, scsiq); - } - DvcLeaveCritical(last_int_level); - return (sta); + + for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) { + sg_block->sg_list[i].sg_addr = + cpu_to_le32(sg_dma_address(slp)); + sg_block->sg_list[i].sg_count = + cpu_to_le32(sg_dma_len(slp)); + ASC_STATS_ADD(scp->device->host, xfer_sect, + DIV_ROUND_UP(sg_dma_len(slp), 512)); + + if (--sg_elem_cnt == 0) { /* Last ADV_SG_BLOCK and scatter-gather entry. */ + sg_block->sg_cnt = i + 1; + sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */ + return ADV_SUCCESS; } + slp++; } + sg_block->sg_cnt = NO_OF_SG_PER_BLOCK; + prev_sg_block = sg_block; } - asc_dvc->in_critical_cnt--; - DvcLeaveCritical(last_int_level); - return (sta); } +/* + * Build a request structure for the Adv Library (Wide Board). + * + * If an adv_req_t can not be allocated to issue the request, + * then return ASC_BUSY. If an error occurs, then return ASC_ERROR. + * + * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the + * microcode for DMA addresses or math operations are byte swapped + * to little-endian order. + */ static int -AscSendScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar n_q_required) +adv_build_req(struct asc_board *boardp, struct scsi_cmnd *scp, + ADV_SCSI_REQ_Q **adv_scsiqpp) { - PortAddr iop_base; - uchar free_q_head; - uchar next_qp; - uchar tid_no; - uchar target_ix; - int sta; + adv_req_t *reqp; + ADV_SCSI_REQ_Q *scsiqp; + int i; + int ret; + int use_sg; - iop_base = asc_dvc->iop_base; - target_ix = scsiq->q2.target_ix; - tid_no = ASC_TIX_TO_TID(target_ix); - sta = 0; - free_q_head = (uchar)AscGetVarFreeQHead(iop_base); - if (n_q_required > 1) { - if ((next_qp = AscAllocMultipleFreeQueue(iop_base, - free_q_head, (uchar) - (n_q_required))) - != (uchar)ASC_QLINK_END) { - asc_dvc->last_q_shortage = 0; - scsiq->sg_head->queue_cnt = n_q_required - 1; - scsiq->q1.q_no = free_q_head; - if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq, - free_q_head)) == 1) { - AscPutVarFreeQHead(iop_base, next_qp); - asc_dvc->cur_total_qng += (uchar)(n_q_required); - asc_dvc->cur_dvc_qng[tid_no]++; - } - return (sta); + /* + * Allocate an adv_req_t structure from the board to execute + * the command. + */ + if (boardp->adv_reqp == NULL) { + ASC_DBG(1, "no free adv_req_t\n"); + ASC_STATS(scp->device->host, adv_build_noreq); + return ASC_BUSY; + } else { + reqp = boardp->adv_reqp; + boardp->adv_reqp = reqp->next_reqp; + reqp->next_reqp = NULL; + } + + /* + * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers. + */ + scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q); + + /* + * Initialize the structure. + */ + scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0; + + /* + * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure. + */ + scsiqp->srb_ptr = ADV_VADDR_TO_U32(reqp); + + /* + * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure. + */ + reqp->cmndp = scp; + + /* + * Build the ADV_SCSI_REQ_Q request. + */ + + /* Set CDB length and copy it to the request structure. */ + scsiqp->cdb_len = scp->cmd_len; + /* Copy first 12 CDB bytes to cdb[]. */ + for (i = 0; i < scp->cmd_len && i < 12; i++) { + scsiqp->cdb[i] = scp->cmnd[i]; + } + /* Copy last 4 CDB bytes, if present, to cdb16[]. */ + for (; i < scp->cmd_len; i++) { + scsiqp->cdb16[i - 12] = scp->cmnd[i]; + } + + scsiqp->target_id = scp->device->id; + scsiqp->target_lun = scp->device->lun; + + scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0])); + scsiqp->sense_len = sizeof(scp->sense_buffer); + + /* Build ADV_SCSI_REQ_Q */ + + use_sg = scsi_dma_map(scp); + if (use_sg == 0) { + /* Zero-length transfer */ + reqp->sgblkp = NULL; + scsiqp->data_cnt = 0; + scsiqp->vdata_addr = NULL; + + scsiqp->data_addr = 0; + scsiqp->sg_list_ptr = NULL; + scsiqp->sg_real_addr = 0; + } else { + if (use_sg > ADV_MAX_SG_LIST) { + scmd_printk(KERN_ERR, scp, "use_sg %d > " + "ADV_MAX_SG_LIST %d\n", use_sg, + scp->device->host->sg_tablesize); + scsi_dma_unmap(scp); + scp->result = HOST_BYTE(DID_ERROR); + + /* + * Free the 'adv_req_t' structure by adding it back + * to the board free list. + */ + reqp->next_reqp = boardp->adv_reqp; + boardp->adv_reqp = reqp; + + return ASC_ERROR; } - } else if (n_q_required == 1) { - if ((next_qp = AscAllocFreeQueue(iop_base, - free_q_head)) != - ASC_QLINK_END) { - scsiq->q1.q_no = free_q_head; - if ((sta = AscPutReadyQueue(asc_dvc, scsiq, - free_q_head)) == 1) { - AscPutVarFreeQHead(iop_base, next_qp); - asc_dvc->cur_total_qng++; - asc_dvc->cur_dvc_qng[tid_no]++; - } - return (sta); + + scsiqp->data_cnt = cpu_to_le32(scsi_bufflen(scp)); + + ret = adv_get_sglist(boardp, reqp, scp, use_sg); + if (ret != ADV_SUCCESS) { + /* + * Free the adv_req_t structure by adding it back to + * the board free list. + */ + reqp->next_reqp = boardp->adv_reqp; + boardp->adv_reqp = reqp; + + return ret; } + + ASC_STATS_ADD(scp->device->host, xfer_elem, use_sg); } - return (sta); + + ASC_STATS(scp->device->host, xfer_cnt); + + ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp); + ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len); + + *adv_scsiqpp = scsiqp; + + return ASC_NOERROR; } static int AscSgListToQueue(int sg_list) @@ -9886,7 +10239,7 @@ static int AscSgListToQueue(int sg_list) n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q); if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0) n_sg_list_qs++; - return (n_sg_list_qs + 1); + return n_sg_list_qs + 1; } static uint @@ -9901,7 +10254,7 @@ AscGetNumOfFreeQueue(ASC_DVC_VAR *asc_dvc, uchar target_ix, uchar n_qs) tid_no = ASC_TIX_TO_TID(target_ix); if ((asc_dvc->unit_not_ready & target_id) || (asc_dvc->queue_full_or_busy & target_id)) { - return (0); + return 0; } if (n_qs == 1) { cur_used_qs = (uint) asc_dvc->cur_total_qng + @@ -9914,9 +10267,9 @@ AscGetNumOfFreeQueue(ASC_DVC_VAR *asc_dvc, uchar target_ix, uchar n_qs) cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs; if (asc_dvc->cur_dvc_qng[tid_no] >= asc_dvc->max_dvc_qng[tid_no]) { - return (0); + return 0; } - return (cur_free_qs); + return cur_free_qs; } if (n_qs > 1) { if ((n_qs > asc_dvc->last_q_shortage) @@ -9924,7 +10277,62 @@ AscGetNumOfFreeQueue(ASC_DVC_VAR *asc_dvc, uchar target_ix, uchar n_qs) asc_dvc->last_q_shortage = n_qs; } } - return (0); + return 0; +} + +static uchar AscAllocFreeQueue(PortAddr iop_base, uchar free_q_head) +{ + ushort q_addr; + uchar next_qp; + uchar q_status; + + q_addr = ASC_QNO_TO_QADDR(free_q_head); + q_status = (uchar)AscReadLramByte(iop_base, + (ushort)(q_addr + + ASC_SCSIQ_B_STATUS)); + next_qp = AscReadLramByte(iop_base, (ushort)(q_addr + ASC_SCSIQ_B_FWD)); + if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END)) + return next_qp; + return ASC_QLINK_END; +} + +static uchar +AscAllocMultipleFreeQueue(PortAddr iop_base, uchar free_q_head, uchar n_free_q) +{ + uchar i; + + for (i = 0; i < n_free_q; i++) { + free_q_head = AscAllocFreeQueue(iop_base, free_q_head); + if (free_q_head == ASC_QLINK_END) + break; + } + return free_q_head; +} + +/* + * void + * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words) + * + * Calling/Exit State: + * none + * + * Description: + * Output an ASC_SCSI_Q structure to the chip + */ +static void +DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words) +{ + int i; + + ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words); + AscSetChipLramAddr(iop_base, s_addr); + for (i = 0; i < 2 * words; i += 2) { + if (i == 4 || i == 20) { + continue; + } + outpw(iop_base + IOP_RAM_DATA, + ((ushort)outbuf[i + 1] << 8) | outbuf[i]); + } } static int AscPutReadyQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no) @@ -9966,7 +10374,7 @@ static int AscPutReadyQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no) (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS), (ushort)(((ushort)scsiq->q1. q_no << 8) | (ushort)QS_READY)); - return (1); + return 1; } static int @@ -10104,491 +10512,651 @@ AscPutReadySgListQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no) } static int -AscSetRunChipSynRegAtID(PortAddr iop_base, uchar tid_no, uchar sdtr_data) +AscSendScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar n_q_required) { - int sta = FALSE; + PortAddr iop_base; + uchar free_q_head; + uchar next_qp; + uchar tid_no; + uchar target_ix; + int sta; - if (AscHostReqRiscHalt(iop_base)) { - sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data); - AscStartChip(iop_base); - return (sta); + iop_base = asc_dvc->iop_base; + target_ix = scsiq->q2.target_ix; + tid_no = ASC_TIX_TO_TID(target_ix); + sta = 0; + free_q_head = (uchar)AscGetVarFreeQHead(iop_base); + if (n_q_required > 1) { + next_qp = AscAllocMultipleFreeQueue(iop_base, free_q_head, + (uchar)n_q_required); + if (next_qp != ASC_QLINK_END) { + asc_dvc->last_q_shortage = 0; + scsiq->sg_head->queue_cnt = n_q_required - 1; + scsiq->q1.q_no = free_q_head; + sta = AscPutReadySgListQueue(asc_dvc, scsiq, + free_q_head); + } + } else if (n_q_required == 1) { + next_qp = AscAllocFreeQueue(iop_base, free_q_head); + if (next_qp != ASC_QLINK_END) { + scsiq->q1.q_no = free_q_head; + sta = AscPutReadyQueue(asc_dvc, scsiq, free_q_head); + } } - return (sta); + if (sta == 1) { + AscPutVarFreeQHead(iop_base, next_qp); + asc_dvc->cur_total_qng += n_q_required; + asc_dvc->cur_dvc_qng[tid_no]++; + } + return sta; } -static int AscSetChipSynRegAtID(PortAddr iop_base, uchar id, uchar sdtr_data) +#define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16 +static uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = { + INQUIRY, + REQUEST_SENSE, + READ_CAPACITY, + READ_TOC, + MODE_SELECT, + MODE_SENSE, + MODE_SELECT_10, + MODE_SENSE_10, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF +}; + +static int AscExeScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq) { - ASC_SCSI_BIT_ID_TYPE org_id; + PortAddr iop_base; + int sta; + int n_q_required; + int disable_syn_offset_one_fix; int i; - int sta = TRUE; + ASC_PADDR addr; + ushort sg_entry_cnt = 0; + ushort sg_entry_cnt_minus_one = 0; + uchar target_ix; + uchar tid_no; + uchar sdtr_data; + uchar extra_bytes; + uchar scsi_cmd; + uchar disable_cmd; + ASC_SG_HEAD *sg_head; + ASC_DCNT data_cnt; - AscSetBank(iop_base, 1); - org_id = AscReadChipDvcID(iop_base); - for (i = 0; i <= ASC_MAX_TID; i++) { - if (org_id == (0x01 << i)) - break; + iop_base = asc_dvc->iop_base; + sg_head = scsiq->sg_head; + if (asc_dvc->err_code != 0) + return (ERR); + scsiq->q1.q_no = 0; + if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) { + scsiq->q1.extra_bytes = 0; } - org_id = (ASC_SCSI_BIT_ID_TYPE) i; - AscWriteChipDvcID(iop_base, id); - if (AscReadChipDvcID(iop_base) == (0x01 << id)) { - AscSetBank(iop_base, 0); - AscSetChipSyn(iop_base, sdtr_data); - if (AscGetChipSyn(iop_base) != sdtr_data) { - sta = FALSE; + sta = 0; + target_ix = scsiq->q2.target_ix; + tid_no = ASC_TIX_TO_TID(target_ix); + n_q_required = 1; + if (scsiq->cdbptr[0] == REQUEST_SENSE) { + if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) { + asc_dvc->sdtr_done &= ~scsiq->q1.target_id; + sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no); + AscMsgOutSDTR(asc_dvc, + asc_dvc-> + sdtr_period_tbl[(sdtr_data >> 4) & + (uchar)(asc_dvc-> + max_sdtr_index - + 1)], + (uchar)(sdtr_data & (uchar) + ASC_SYN_MAX_OFFSET)); + scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT); } + } + if (asc_dvc->in_critical_cnt != 0) { + AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY); + return (ERR); + } + asc_dvc->in_critical_cnt++; + if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) { + if ((sg_entry_cnt = sg_head->entry_cnt) == 0) { + asc_dvc->in_critical_cnt--; + return (ERR); + } +#if !CC_VERY_LONG_SG_LIST + if (sg_entry_cnt > ASC_MAX_SG_LIST) { + asc_dvc->in_critical_cnt--; + return (ERR); + } +#endif /* !CC_VERY_LONG_SG_LIST */ + if (sg_entry_cnt == 1) { + scsiq->q1.data_addr = + (ADV_PADDR)sg_head->sg_list[0].addr; + scsiq->q1.data_cnt = + (ADV_DCNT)sg_head->sg_list[0].bytes; + scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE); + } + sg_entry_cnt_minus_one = sg_entry_cnt - 1; + } + scsi_cmd = scsiq->cdbptr[0]; + disable_syn_offset_one_fix = FALSE; + if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) && + !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) { + if (scsiq->q1.cntl & QC_SG_HEAD) { + data_cnt = 0; + for (i = 0; i < sg_entry_cnt; i++) { + data_cnt += + (ADV_DCNT)le32_to_cpu(sg_head->sg_list[i]. + bytes); + } + } else { + data_cnt = le32_to_cpu(scsiq->q1.data_cnt); + } + if (data_cnt != 0UL) { + if (data_cnt < 512UL) { + disable_syn_offset_one_fix = TRUE; + } else { + for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST; + i++) { + disable_cmd = + _syn_offset_one_disable_cmd[i]; + if (disable_cmd == 0xFF) { + break; + } + if (scsi_cmd == disable_cmd) { + disable_syn_offset_one_fix = + TRUE; + break; + } + } + } + } + } + if (disable_syn_offset_one_fix) { + scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG; + scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX | + ASC_TAG_FLAG_DISABLE_DISCONNECT); } else { - sta = FALSE; + scsiq->q2.tag_code &= 0x27; } - AscSetBank(iop_base, 1); - AscWriteChipDvcID(iop_base, org_id); - AscSetBank(iop_base, 0); + if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) { + if (asc_dvc->bug_fix_cntl) { + if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) { + if ((scsi_cmd == READ_6) || + (scsi_cmd == READ_10)) { + addr = + (ADV_PADDR)le32_to_cpu(sg_head-> + sg_list + [sg_entry_cnt_minus_one]. + addr) + + (ADV_DCNT)le32_to_cpu(sg_head-> + sg_list + [sg_entry_cnt_minus_one]. + bytes); + extra_bytes = + (uchar)((ushort)addr & 0x0003); + if ((extra_bytes != 0) + && + ((scsiq->q2. + tag_code & + ASC_TAG_FLAG_EXTRA_BYTES) + == 0)) { + scsiq->q2.tag_code |= + ASC_TAG_FLAG_EXTRA_BYTES; + scsiq->q1.extra_bytes = + extra_bytes; + data_cnt = + le32_to_cpu(sg_head-> + sg_list + [sg_entry_cnt_minus_one]. + bytes); + data_cnt -= + (ASC_DCNT) extra_bytes; + sg_head-> + sg_list + [sg_entry_cnt_minus_one]. + bytes = + cpu_to_le32(data_cnt); + } + } + } + } + sg_head->entry_to_copy = sg_head->entry_cnt; +#if CC_VERY_LONG_SG_LIST + /* + * Set the sg_entry_cnt to the maximum possible. The rest of + * the SG elements will be copied when the RISC completes the + * SG elements that fit and halts. + */ + if (sg_entry_cnt > ASC_MAX_SG_LIST) { + sg_entry_cnt = ASC_MAX_SG_LIST; + } +#endif /* CC_VERY_LONG_SG_LIST */ + n_q_required = AscSgListToQueue(sg_entry_cnt); + if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >= + (uint) n_q_required) + || ((scsiq->q1.cntl & QC_URGENT) != 0)) { + if ((sta = + AscSendScsiQueue(asc_dvc, scsiq, + n_q_required)) == 1) { + asc_dvc->in_critical_cnt--; + return (sta); + } + } + } else { + if (asc_dvc->bug_fix_cntl) { + if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) { + if ((scsi_cmd == READ_6) || + (scsi_cmd == READ_10)) { + addr = + le32_to_cpu(scsiq->q1.data_addr) + + le32_to_cpu(scsiq->q1.data_cnt); + extra_bytes = + (uchar)((ushort)addr & 0x0003); + if ((extra_bytes != 0) + && + ((scsiq->q2. + tag_code & + ASC_TAG_FLAG_EXTRA_BYTES) + == 0)) { + data_cnt = + le32_to_cpu(scsiq->q1. + data_cnt); + if (((ushort)data_cnt & 0x01FF) + == 0) { + scsiq->q2.tag_code |= + ASC_TAG_FLAG_EXTRA_BYTES; + data_cnt -= (ASC_DCNT) + extra_bytes; + scsiq->q1.data_cnt = + cpu_to_le32 + (data_cnt); + scsiq->q1.extra_bytes = + extra_bytes; + } + } + } + } + } + n_q_required = 1; + if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) || + ((scsiq->q1.cntl & QC_URGENT) != 0)) { + if ((sta = AscSendScsiQueue(asc_dvc, scsiq, + n_q_required)) == 1) { + asc_dvc->in_critical_cnt--; + return (sta); + } + } + } + asc_dvc->in_critical_cnt--; return (sta); } -static ushort AscInitLram(ASC_DVC_VAR *asc_dvc) +/* + * AdvExeScsiQueue() - Send a request to the RISC microcode program. + * + * Allocate a carrier structure, point the carrier to the ADV_SCSI_REQ_Q, + * add the carrier to the ICQ (Initiator Command Queue), and tickle the + * RISC to notify it a new command is ready to be executed. + * + * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be + * set to SCSI_MAX_RETRY. + * + * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the microcode + * for DMA addresses or math operations are byte swapped to little-endian + * order. + * + * Return: + * ADV_SUCCESS(1) - The request was successfully queued. + * ADV_BUSY(0) - Resource unavailable; Retry again after pending + * request completes. + * ADV_ERROR(-1) - Invalid ADV_SCSI_REQ_Q request structure + * host IC error. + */ +static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq) { - uchar i; - ushort s_addr; - PortAddr iop_base; - ushort warn_code; + AdvPortAddr iop_base; + ADV_PADDR req_paddr; + ADV_CARR_T *new_carrp; - iop_base = asc_dvc->iop_base; - warn_code = 0; - AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0, - (ushort)(((int)(asc_dvc->max_total_qng + 2 + 1) * - 64) >> 1) - ); - i = ASC_MIN_ACTIVE_QNO; - s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE; - AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD), - (uchar)(i + 1)); - AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD), - (uchar)(asc_dvc->max_total_qng)); - AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO), - (uchar)i); - i++; - s_addr += ASC_QBLK_SIZE; - for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) { - AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD), - (uchar)(i + 1)); - AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD), - (uchar)(i - 1)); - AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO), - (uchar)i); - } - AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD), - (uchar)ASC_QLINK_END); - AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD), - (uchar)(asc_dvc->max_total_qng - 1)); - AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO), - (uchar)asc_dvc->max_total_qng); - i++; - s_addr += ASC_QBLK_SIZE; - for (; i <= (uchar)(asc_dvc->max_total_qng + 3); - i++, s_addr += ASC_QBLK_SIZE) { - AscWriteLramByte(iop_base, - (ushort)(s_addr + (ushort)ASC_SCSIQ_B_FWD), i); - AscWriteLramByte(iop_base, - (ushort)(s_addr + (ushort)ASC_SCSIQ_B_BWD), i); - AscWriteLramByte(iop_base, - (ushort)(s_addr + (ushort)ASC_SCSIQ_B_QNO), i); + /* + * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID. + */ + if (scsiq->target_id > ADV_MAX_TID) { + scsiq->host_status = QHSTA_M_INVALID_DEVICE; + scsiq->done_status = QD_WITH_ERROR; + return ADV_ERROR; } - return (warn_code); -} - -static ushort AscInitQLinkVar(ASC_DVC_VAR *asc_dvc) -{ - PortAddr iop_base; - int i; - ushort lram_addr; iop_base = asc_dvc->iop_base; - AscPutRiscVarFreeQHead(iop_base, 1); - AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng); - AscPutVarFreeQHead(iop_base, 1); - AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng); - AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B, - (uchar)((int)asc_dvc->max_total_qng + 1)); - AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B, - (uchar)((int)asc_dvc->max_total_qng + 2)); - AscWriteLramByte(iop_base, (ushort)ASCV_TOTAL_READY_Q_B, - asc_dvc->max_total_qng); - AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0); - AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); - AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0); - AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0); - AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0); - AscPutQDoneInProgress(iop_base, 0); - lram_addr = ASC_QADR_BEG; - for (i = 0; i < 32; i++, lram_addr += 2) { - AscWriteLramWord(iop_base, lram_addr, 0); - } - return (0); -} -static int AscSetLibErrorCode(ASC_DVC_VAR *asc_dvc, ushort err_code) -{ - if (asc_dvc->err_code == 0) { - asc_dvc->err_code = err_code; - AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W, - err_code); + /* + * Allocate a carrier ensuring at least one carrier always + * remains on the freelist and initialize fields. + */ + if ((new_carrp = asc_dvc->carr_freelist) == NULL) { + return ADV_BUSY; } - return (err_code); -} + asc_dvc->carr_freelist = (ADV_CARR_T *) + ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa)); + asc_dvc->carr_pending_cnt++; -static uchar -AscMsgOutSDTR(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar sdtr_offset) -{ - EXT_MSG sdtr_buf; - uchar sdtr_period_index; - PortAddr iop_base; + /* + * Set the carrier to be a stopper by setting 'next_vpa' + * to the stopper value. The current stopper will be changed + * below to point to the new stopper. + */ + new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); - iop_base = asc_dvc->iop_base; - sdtr_buf.msg_type = MS_EXTEND; - sdtr_buf.msg_len = MS_SDTR_LEN; - sdtr_buf.msg_req = MS_SDTR_CODE; - sdtr_buf.xfer_period = sdtr_period; - sdtr_offset &= ASC_SYN_MAX_OFFSET; - sdtr_buf.req_ack_offset = sdtr_offset; - if ((sdtr_period_index = - AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <= - asc_dvc->max_sdtr_index) { - AscMemWordCopyPtrToLram(iop_base, - ASCV_MSGOUT_BEG, - (uchar *)&sdtr_buf, - sizeof(EXT_MSG) >> 1); - return ((sdtr_period_index << 4) | sdtr_offset); - } else { + /* + * Clear the ADV_SCSI_REQ_Q done flag. + */ + scsiq->a_flag &= ~ADV_SCSIQ_DONE; - sdtr_buf.req_ack_offset = 0; - AscMemWordCopyPtrToLram(iop_base, - ASCV_MSGOUT_BEG, - (uchar *)&sdtr_buf, - sizeof(EXT_MSG) >> 1); - return (0); - } -} + req_paddr = virt_to_bus(scsiq); + BUG_ON(req_paddr & 31); + /* Wait for assertion before making little-endian */ + req_paddr = cpu_to_le32(req_paddr); -static uchar -AscCalSDTRData(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar syn_offset) -{ - uchar byte; - uchar sdtr_period_ix; + /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */ + scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq)); + scsiq->scsiq_rptr = req_paddr; - sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period); - if ((sdtr_period_ix > asc_dvc->max_sdtr_index) - ) { - return (0xFF); - } - byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET); - return (byte); -} + scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp)); + /* + * Every ADV_CARR_T.carr_pa is byte swapped to little-endian + * order during initialization. + */ + scsiq->carr_pa = asc_dvc->icq_sp->carr_pa; -static void AscSetChipSDTR(PortAddr iop_base, uchar sdtr_data, uchar tid_no) -{ - AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data); - AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data); - return; -} + /* + * Use the current stopper to send the ADV_SCSI_REQ_Q command to + * the microcode. The newly allocated stopper will become the new + * stopper. + */ + asc_dvc->icq_sp->areq_vpa = req_paddr; -static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *asc_dvc, uchar syn_time) -{ - uchar *period_table; - int max_index; - int min_index; - int i; + /* + * Set the 'next_vpa' pointer for the old stopper to be the + * physical address of the new stopper. The RISC can only + * follow physical addresses. + */ + asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa; - period_table = asc_dvc->sdtr_period_tbl; - max_index = (int)asc_dvc->max_sdtr_index; - min_index = (int)asc_dvc->host_init_sdtr_index; - if ((syn_time <= period_table[max_index])) { - for (i = min_index; i < (max_index - 1); i++) { - if (syn_time <= period_table[i]) { - return ((uchar)i); - } + /* + * Set the host adapter stopper pointer to point to the new carrier. + */ + asc_dvc->icq_sp = new_carrp; + + if (asc_dvc->chip_type == ADV_CHIP_ASC3550 || + asc_dvc->chip_type == ADV_CHIP_ASC38C0800) { + /* + * Tickle the RISC to tell it to read its Command Queue Head pointer. + */ + AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A); + if (asc_dvc->chip_type == ADV_CHIP_ASC3550) { + /* + * Clear the tickle value. In the ASC-3550 the RISC flag + * command 'clr_tickle_a' does not work unless the host + * value is cleared. + */ + AdvWriteByteRegister(iop_base, IOPB_TICKLE, + ADV_TICKLE_NOP); } - return ((uchar)max_index); - } else { - return ((uchar)(max_index + 1)); + } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) { + /* + * Notify the RISC a carrier is ready by writing the physical + * address of the new carrier stopper to the COMMA register. + */ + AdvWriteDWordRegister(iop_base, IOPDW_COMMA, + le32_to_cpu(new_carrp->carr_pa)); } + + return ADV_SUCCESS; } -static uchar AscAllocFreeQueue(PortAddr iop_base, uchar free_q_head) +/* + * Execute a single 'Scsi_Cmnd'. + */ +static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp) { - ushort q_addr; - uchar next_qp; - uchar q_status; + int ret, err_code; + struct asc_board *boardp = shost_priv(scp->device->host); - q_addr = ASC_QNO_TO_QADDR(free_q_head); - q_status = (uchar)AscReadLramByte(iop_base, - (ushort)(q_addr + - ASC_SCSIQ_B_STATUS)); - next_qp = AscReadLramByte(iop_base, (ushort)(q_addr + ASC_SCSIQ_B_FWD)); - if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END)) { - return (next_qp); - } - return (ASC_QLINK_END); -} + ASC_DBG(1, "scp 0x%p\n", scp); -static uchar -AscAllocMultipleFreeQueue(PortAddr iop_base, uchar free_q_head, uchar n_free_q) -{ - uchar i; + if (ASC_NARROW_BOARD(boardp)) { + ASC_DVC_VAR *asc_dvc = &boardp->dvc_var.asc_dvc_var; + struct asc_scsi_q asc_scsi_q; - for (i = 0; i < n_free_q; i++) { - if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head)) - == ASC_QLINK_END) { - return (ASC_QLINK_END); + /* asc_build_req() can not return ASC_BUSY. */ + ret = asc_build_req(boardp, scp, &asc_scsi_q); + if (ret == ASC_ERROR) { + ASC_STATS(scp->device->host, build_error); + return ASC_ERROR; } - } - return (free_q_head); -} -static int AscHostReqRiscHalt(PortAddr iop_base) -{ - int count = 0; - int sta = 0; - uchar saved_stop_code; + ret = AscExeScsiQueue(asc_dvc, &asc_scsi_q); + kfree(asc_scsi_q.sg_head); + err_code = asc_dvc->err_code; + } else { + ADV_DVC_VAR *adv_dvc = &boardp->dvc_var.adv_dvc_var; + ADV_SCSI_REQ_Q *adv_scsiqp; - if (AscIsChipHalted(iop_base)) - return (1); - saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B); - AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, - ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP); - do { - if (AscIsChipHalted(iop_base)) { - sta = 1; + switch (adv_build_req(boardp, scp, &adv_scsiqp)) { + case ASC_NOERROR: + ASC_DBG(3, "adv_build_req ASC_NOERROR\n"); break; + case ASC_BUSY: + ASC_DBG(1, "adv_build_req ASC_BUSY\n"); + /* + * The asc_stats fields 'adv_build_noreq' and + * 'adv_build_nosg' count wide board busy conditions. + * They are updated in adv_build_req and + * adv_get_sglist, respectively. + */ + return ASC_BUSY; + case ASC_ERROR: + default: + ASC_DBG(1, "adv_build_req ASC_ERROR\n"); + ASC_STATS(scp->device->host, build_error); + return ASC_ERROR; } - DvcSleepMilliSecond(100); - } while (count++ < 20); - AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code); - return (sta); -} -static int AscStopQueueExe(PortAddr iop_base) -{ - int count = 0; + ret = AdvExeScsiQueue(adv_dvc, adv_scsiqp); + err_code = adv_dvc->err_code; + } - if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) { - AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, - ASC_STOP_REQ_RISC_STOP); - do { - if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) & - ASC_STOP_ACK_RISC_STOP) { - return (1); - } - DvcSleepMilliSecond(100); - } while (count++ < 20); + switch (ret) { + case ASC_NOERROR: + ASC_STATS(scp->device->host, exe_noerror); + /* + * Increment monotonically increasing per device + * successful request counter. Wrapping doesn't matter. + */ + boardp->reqcnt[scp->device->id]++; + ASC_DBG(1, "ExeScsiQueue() ASC_NOERROR\n"); + break; + case ASC_BUSY: + ASC_STATS(scp->device->host, exe_busy); + break; + case ASC_ERROR: + scmd_printk(KERN_ERR, scp, "ExeScsiQueue() ASC_ERROR, " + "err_code 0x%x\n", err_code); + ASC_STATS(scp->device->host, exe_error); + scp->result = HOST_BYTE(DID_ERROR); + break; + default: + scmd_printk(KERN_ERR, scp, "ExeScsiQueue() unknown, " + "err_code 0x%x\n", err_code); + ASC_STATS(scp->device->host, exe_unknown); + scp->result = HOST_BYTE(DID_ERROR); + break; } - return (0); -} -static void DvcDelayMicroSecond(ADV_DVC_VAR *asc_dvc, ushort micro_sec) -{ - udelay(micro_sec); + ASC_DBG(1, "end\n"); + return ret; } -static void DvcDelayNanoSecond(ASC_DVC_VAR *asc_dvc, ASC_DCNT nano_sec) +/* + * advansys_queuecommand() - interrupt-driven I/O entrypoint. + * + * This function always returns 0. Command return status is saved + * in the 'scp' result field. + */ +static int +advansys_queuecommand(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *)) { - udelay((nano_sec + 999) / 1000); -} + struct Scsi_Host *shost = scp->device->host; + int asc_res, result = 0; -#ifdef CONFIG_ISA -static ASC_DCNT __init AscGetEisaProductID(PortAddr iop_base) -{ - PortAddr eisa_iop; - ushort product_id_high, product_id_low; - ASC_DCNT product_id; - - eisa_iop = ASC_GET_EISA_SLOT(iop_base) | ASC_EISA_PID_IOP_MASK; - product_id_low = inpw(eisa_iop); - product_id_high = inpw(eisa_iop + 2); - product_id = ((ASC_DCNT) product_id_high << 16) | - (ASC_DCNT) product_id_low; - return (product_id); -} + ASC_STATS(shost, queuecommand); + scp->scsi_done = done; -static PortAddr __init AscSearchIOPortAddrEISA(PortAddr iop_base) -{ - ASC_DCNT eisa_product_id; + asc_res = asc_execute_scsi_cmnd(scp); - if (iop_base == 0) { - iop_base = ASC_EISA_MIN_IOP_ADDR; - } else { - if (iop_base == ASC_EISA_MAX_IOP_ADDR) - return (0); - if ((iop_base & 0x0050) == 0x0050) { - iop_base += ASC_EISA_BIG_IOP_GAP; - } else { - iop_base += ASC_EISA_SMALL_IOP_GAP; - } - } - while (iop_base <= ASC_EISA_MAX_IOP_ADDR) { - eisa_product_id = AscGetEisaProductID(iop_base); - if ((eisa_product_id == ASC_EISA_ID_740) || - (eisa_product_id == ASC_EISA_ID_750)) { - if (AscFindSignature(iop_base)) { - inpw(iop_base + 4); - return (iop_base); - } - } - if (iop_base == ASC_EISA_MAX_IOP_ADDR) - return (0); - if ((iop_base & 0x0050) == 0x0050) { - iop_base += ASC_EISA_BIG_IOP_GAP; - } else { - iop_base += ASC_EISA_SMALL_IOP_GAP; - } + switch (asc_res) { + case ASC_NOERROR: + break; + case ASC_BUSY: + result = SCSI_MLQUEUE_HOST_BUSY; + break; + case ASC_ERROR: + default: + asc_scsi_done(scp); + break; } - return (0); + + return result; } -#endif /* CONFIG_ISA */ -static int AscStartChip(PortAddr iop_base) +static ushort __devinit AscGetEisaChipCfg(PortAddr iop_base) { - AscSetChipControl(iop_base, 0); - if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) { - return (0); - } - return (1); + PortAddr eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) | + (PortAddr) (ASC_EISA_CFG_IOP_MASK); + return inpw(eisa_cfg_iop); } -static int AscStopChip(PortAddr iop_base) +/* + * Return the BIOS address of the adapter at the specified + * I/O port and with the specified bus type. + */ +static unsigned short __devinit +AscGetChipBiosAddress(PortAddr iop_base, unsigned short bus_type) { - uchar cc_val; + unsigned short cfg_lsw; + unsigned short bios_addr; - cc_val = - AscGetChipControl(iop_base) & - (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG)); - AscSetChipControl(iop_base, (uchar)(cc_val | CC_HALT)); - AscSetChipIH(iop_base, INS_HALT); - AscSetChipIH(iop_base, INS_RFLAG_WTM); - if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) { - return (0); - } - return (1); -} + /* + * The PCI BIOS is re-located by the motherboard BIOS. Because + * of this the driver can not determine where a PCI BIOS is + * loaded and executes. + */ + if (bus_type & ASC_IS_PCI) + return 0; -static int AscIsChipHalted(PortAddr iop_base) -{ - if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) { - if ((AscGetChipControl(iop_base) & CC_HALT) != 0) { - return (1); - } + if ((bus_type & ASC_IS_EISA) != 0) { + cfg_lsw = AscGetEisaChipCfg(iop_base); + cfg_lsw &= 0x000F; + bios_addr = ASC_BIOS_MIN_ADDR + cfg_lsw * ASC_BIOS_BANK_SIZE; + return bios_addr; } - return (0); -} -static void AscSetChipIH(PortAddr iop_base, ushort ins_code) -{ - AscSetBank(iop_base, 1); - AscWriteChipIH(iop_base, ins_code); - AscSetBank(iop_base, 0); - return; + cfg_lsw = AscGetChipCfgLsw(iop_base); + + /* + * ISA PnP uses the top bit as the 32K BIOS flag + */ + if (bus_type == ASC_IS_ISAPNP) + cfg_lsw &= 0x7FFF; + bios_addr = ASC_BIOS_MIN_ADDR + (cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE; + return bios_addr; } -static void AscAckInterrupt(PortAddr iop_base) +static uchar __devinit AscSetChipScsiID(PortAddr iop_base, uchar new_host_id) { - uchar host_flag; - uchar risc_flag; - ushort loop; + ushort cfg_lsw; - loop = 0; - do { - risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B); - if (loop++ > 0x7FFF) { - break; - } - } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0); - host_flag = - AscReadLramByte(iop_base, - ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT); - AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, - (uchar)(host_flag | ASC_HOST_FLAG_ACK_INT)); - AscSetChipStatus(iop_base, CIW_INT_ACK); - loop = 0; - while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) { - AscSetChipStatus(iop_base, CIW_INT_ACK); - if (loop++ > 3) { - break; - } + if (AscGetChipScsiID(iop_base) == new_host_id) { + return (new_host_id); } - AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag); - return; + cfg_lsw = AscGetChipCfgLsw(iop_base); + cfg_lsw &= 0xF8FF; + cfg_lsw |= (ushort)((new_host_id & ASC_MAX_TID) << 8); + AscSetChipCfgLsw(iop_base, cfg_lsw); + return (AscGetChipScsiID(iop_base)); } -static void AscDisableInterrupt(PortAddr iop_base) +static unsigned char __devinit AscGetChipScsiCtrl(PortAddr iop_base) { - ushort cfg; + unsigned char sc; - cfg = AscGetChipCfgLsw(iop_base); - AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON)); - return; + AscSetBank(iop_base, 1); + sc = inp(iop_base + IOP_REG_SC); + AscSetBank(iop_base, 0); + return sc; } -static void AscEnableInterrupt(PortAddr iop_base) +static unsigned char __devinit +AscGetChipVersion(PortAddr iop_base, unsigned short bus_type) { - ushort cfg; - - cfg = AscGetChipCfgLsw(iop_base); - AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON); - return; + if (bus_type & ASC_IS_EISA) { + PortAddr eisa_iop; + unsigned char revision; + eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) | + (PortAddr) ASC_EISA_REV_IOP_MASK; + revision = inp(eisa_iop); + return ASC_CHIP_MIN_VER_EISA - 1 + revision; + } + return AscGetChipVerNo(iop_base); } -static void AscSetBank(PortAddr iop_base, uchar bank) +#ifdef CONFIG_ISA +static void __devinit AscEnableIsaDma(uchar dma_channel) { - uchar val; - - val = AscGetChipControl(iop_base) & - (~ - (CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET | - CC_CHIP_RESET)); - if (bank == 1) { - val |= CC_BANK_ONE; - } else if (bank == 2) { - val |= CC_DIAG | CC_BANK_ONE; - } else { - val &= ~CC_BANK_ONE; + if (dma_channel < 4) { + outp(0x000B, (ushort)(0xC0 | dma_channel)); + outp(0x000A, dma_channel); + } else if (dma_channel < 8) { + outp(0x00D6, (ushort)(0xC0 | (dma_channel - 4))); + outp(0x00D4, (ushort)(dma_channel - 4)); } - AscSetChipControl(iop_base, val); - return; } +#endif /* CONFIG_ISA */ -static int AscResetChipAndScsiBus(ASC_DVC_VAR *asc_dvc) +static int AscStopQueueExe(PortAddr iop_base) { - PortAddr iop_base; - int i = 10; + int count = 0; - iop_base = asc_dvc->iop_base; - while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) - && (i-- > 0)) { - DvcSleepMilliSecond(100); + if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) { + AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, + ASC_STOP_REQ_RISC_STOP); + do { + if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) & + ASC_STOP_ACK_RISC_STOP) { + return (1); + } + mdelay(100); + } while (count++ < 20); } - AscStopChip(iop_base); - AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT); - DvcDelayNanoSecond(asc_dvc, 60000); - AscSetChipIH(iop_base, INS_RFLAG_WTM); - AscSetChipIH(iop_base, INS_HALT); - AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT); - AscSetChipControl(iop_base, CC_HALT); - DvcSleepMilliSecond(200); - AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT); - AscSetChipStatus(iop_base, 0); - return (AscIsChipHalted(iop_base)); + return (0); } -static ASC_DCNT __init AscGetMaxDmaCount(ushort bus_type) +static ASC_DCNT __devinit AscGetMaxDmaCount(ushort bus_type) { if (bus_type & ASC_IS_ISA) - return (ASC_MAX_ISA_DMA_COUNT); + return ASC_MAX_ISA_DMA_COUNT; else if (bus_type & (ASC_IS_EISA | ASC_IS_VL)) - return (ASC_MAX_VL_DMA_COUNT); - return (ASC_MAX_PCI_DMA_COUNT); + return ASC_MAX_VL_DMA_COUNT; + return ASC_MAX_PCI_DMA_COUNT; } #ifdef CONFIG_ISA -static ushort __init AscGetIsaDmaChannel(PortAddr iop_base) +static ushort __devinit AscGetIsaDmaChannel(PortAddr iop_base) { ushort channel; @@ -10600,7 +11168,7 @@ static ushort __init AscGetIsaDmaChannel(PortAddr iop_base) return (channel + 4); } -static ushort __init AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel) +static ushort __devinit AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel) { ushort cfg_lsw; uchar value; @@ -10615,19 +11183,10 @@ static ushort __init AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel) AscSetChipCfgLsw(iop_base, cfg_lsw); return (AscGetIsaDmaChannel(iop_base)); } - return (0); -} - -static uchar __init AscSetIsaDmaSpeed(PortAddr iop_base, uchar speed_value) -{ - speed_value &= 0x07; - AscSetBank(iop_base, 1); - AscWriteChipDmaSpeed(iop_base, speed_value); - AscSetBank(iop_base, 0); - return (AscGetIsaDmaSpeed(iop_base)); + return 0; } -static uchar __init AscGetIsaDmaSpeed(PortAddr iop_base) +static uchar __devinit AscGetIsaDmaSpeed(PortAddr iop_base) { uchar speed_value; @@ -10635,223 +11194,20 @@ static uchar __init AscGetIsaDmaSpeed(PortAddr iop_base) speed_value = AscReadChipDmaSpeed(iop_base); speed_value &= 0x07; AscSetBank(iop_base, 0); - return (speed_value); + return speed_value; } -#endif /* CONFIG_ISA */ -static ushort __init -AscReadPCIConfigWord(ASC_DVC_VAR *asc_dvc, ushort pci_config_offset) +static uchar __devinit AscSetIsaDmaSpeed(PortAddr iop_base, uchar speed_value) { - uchar lsb, msb; - - lsb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset); - msb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset + 1); - return ((ushort)((msb << 8) | lsb)); -} - -static ushort __init AscInitGetConfig(ASC_DVC_VAR *asc_dvc) -{ - ushort warn_code; - PortAddr iop_base; - ushort PCIDeviceID; - ushort PCIVendorID; - uchar PCIRevisionID; - uchar prevCmdRegBits; - - warn_code = 0; - iop_base = asc_dvc->iop_base; - asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG; - if (asc_dvc->err_code != 0) { - return (UW_ERR); - } - if (asc_dvc->bus_type == ASC_IS_PCI) { - PCIVendorID = AscReadPCIConfigWord(asc_dvc, - AscPCIConfigVendorIDRegister); - - PCIDeviceID = AscReadPCIConfigWord(asc_dvc, - AscPCIConfigDeviceIDRegister); - - PCIRevisionID = DvcReadPCIConfigByte(asc_dvc, - AscPCIConfigRevisionIDRegister); - - if (PCIVendorID != PCI_VENDOR_ID_ASP) { - warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE; - } - prevCmdRegBits = DvcReadPCIConfigByte(asc_dvc, - AscPCIConfigCommandRegister); - - if ((prevCmdRegBits & AscPCICmdRegBits_IOMemBusMaster) != - AscPCICmdRegBits_IOMemBusMaster) { - DvcWritePCIConfigByte(asc_dvc, - AscPCIConfigCommandRegister, - (prevCmdRegBits | - AscPCICmdRegBits_IOMemBusMaster)); - - if ((DvcReadPCIConfigByte(asc_dvc, - AscPCIConfigCommandRegister) - & AscPCICmdRegBits_IOMemBusMaster) - != AscPCICmdRegBits_IOMemBusMaster) { - warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE; - } - } - if ((PCIDeviceID == PCI_DEVICE_ID_ASP_1200A) || - (PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940)) { - DvcWritePCIConfigByte(asc_dvc, - AscPCIConfigLatencyTimer, 0x00); - if (DvcReadPCIConfigByte - (asc_dvc, AscPCIConfigLatencyTimer) - != 0x00) { - warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE; - } - } else if (PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940U) { - if (DvcReadPCIConfigByte(asc_dvc, - AscPCIConfigLatencyTimer) < - 0x20) { - DvcWritePCIConfigByte(asc_dvc, - AscPCIConfigLatencyTimer, - 0x20); - - if (DvcReadPCIConfigByte(asc_dvc, - AscPCIConfigLatencyTimer) - < 0x20) { - warn_code |= - ASC_WARN_SET_PCI_CONFIG_SPACE; - } - } - } - } - - if (AscFindSignature(iop_base)) { - warn_code |= AscInitAscDvcVar(asc_dvc); - warn_code |= AscInitFromEEP(asc_dvc); - asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG; - if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT) { - asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT; - } - } else { - asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE; - } - return (warn_code); -} - -static ushort __init AscInitSetConfig(ASC_DVC_VAR *asc_dvc) -{ - ushort warn_code = 0; - - asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG; - if (asc_dvc->err_code != 0) - return (UW_ERR); - if (AscFindSignature(asc_dvc->iop_base)) { - warn_code |= AscInitFromAscDvcVar(asc_dvc); - asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG; - } else { - asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE; - } - return (warn_code); + speed_value &= 0x07; + AscSetBank(iop_base, 1); + AscWriteChipDmaSpeed(iop_base, speed_value); + AscSetBank(iop_base, 0); + return AscGetIsaDmaSpeed(iop_base); } - -static ushort __init AscInitFromAscDvcVar(ASC_DVC_VAR *asc_dvc) -{ - PortAddr iop_base; - ushort cfg_msw; - ushort warn_code; - ushort pci_device_id = 0; - - iop_base = asc_dvc->iop_base; -#ifdef CONFIG_PCI - if (asc_dvc->cfg->dev) - pci_device_id = to_pci_dev(asc_dvc->cfg->dev)->device; -#endif - warn_code = 0; - cfg_msw = AscGetChipCfgMsw(iop_base); - if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) { - cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK)); - warn_code |= ASC_WARN_CFG_MSW_RECOVER; - AscSetChipCfgMsw(iop_base, cfg_msw); - } - if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) != - asc_dvc->cfg->cmd_qng_enabled) { - asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled; - warn_code |= ASC_WARN_CMD_QNG_CONFLICT; - } - if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) { - warn_code |= ASC_WARN_AUTO_CONFIG; - } - if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) { - if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type) - != asc_dvc->irq_no) { - asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO; - } - } - if (asc_dvc->bus_type & ASC_IS_PCI) { - cfg_msw &= 0xFFC0; - AscSetChipCfgMsw(iop_base, cfg_msw); - if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) { - } else { - if ((pci_device_id == PCI_DEVICE_ID_ASP_1200A) || - (pci_device_id == PCI_DEVICE_ID_ASP_ABP940)) { - asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB; - asc_dvc->bug_fix_cntl |= - ASC_BUG_FIX_ASYN_USE_SYN; - } - } - } else if (asc_dvc->bus_type == ASC_IS_ISAPNP) { - if (AscGetChipVersion(iop_base, asc_dvc->bus_type) - == ASC_CHIP_VER_ASYN_BUG) { - asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN; - } - } - if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) != - asc_dvc->cfg->chip_scsi_id) { - asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID; - } -#ifdef CONFIG_ISA - if (asc_dvc->bus_type & ASC_IS_ISA) { - AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel); - AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed); - } #endif /* CONFIG_ISA */ - return (warn_code); -} - -static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc) -{ - ushort warn_code; - PortAddr iop_base; - - iop_base = asc_dvc->iop_base; - warn_code = 0; - if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) && - !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) { - AscResetChipAndScsiBus(asc_dvc); - DvcSleepMilliSecond((ASC_DCNT) - ((ushort)asc_dvc->scsi_reset_wait * 1000)); - } - asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC; - if (asc_dvc->err_code != 0) - return (UW_ERR); - if (!AscFindSignature(asc_dvc->iop_base)) { - asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE; - return (warn_code); - } - AscDisableInterrupt(iop_base); - warn_code |= AscInitLram(asc_dvc); - if (asc_dvc->err_code != 0) - return (UW_ERR); - ASC_DBG1(1, "AscInitAsc1000Driver: _asc_mcode_chksum 0x%lx\n", - (ulong)_asc_mcode_chksum); - if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf, - _asc_mcode_size) != _asc_mcode_chksum) { - asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM; - return (warn_code); - } - warn_code |= AscInitMicroCodeVar(asc_dvc); - asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC; - AscEnableInterrupt(iop_base); - return (warn_code); -} -static ushort __init AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc) +static ushort __devinit AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc) { int i; PortAddr iop_base; @@ -10882,7 +11238,7 @@ static ushort __init AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc) asc_dvc->queue_full_or_busy = 0; asc_dvc->redo_scam = 0; asc_dvc->res2 = 0; - asc_dvc->host_init_sdtr_index = 0; + asc_dvc->min_sdtr_index = 0; asc_dvc->cfg->can_tagged_qng = 0; asc_dvc->cfg->cmd_qng_enabled = 0; asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL; @@ -10894,39 +11250,14 @@ static ushort __init AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc) asc_dvc->cfg->sdtr_enable = ASC_SCSI_WIDTH_BIT_SET; asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET; asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID; - asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER; - asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) | - ASC_LIB_VERSION_MINOR; chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type); asc_dvc->cfg->chip_version = chip_version; - asc_dvc->sdtr_period_tbl[0] = SYN_XFER_NS_0; - asc_dvc->sdtr_period_tbl[1] = SYN_XFER_NS_1; - asc_dvc->sdtr_period_tbl[2] = SYN_XFER_NS_2; - asc_dvc->sdtr_period_tbl[3] = SYN_XFER_NS_3; - asc_dvc->sdtr_period_tbl[4] = SYN_XFER_NS_4; - asc_dvc->sdtr_period_tbl[5] = SYN_XFER_NS_5; - asc_dvc->sdtr_period_tbl[6] = SYN_XFER_NS_6; - asc_dvc->sdtr_period_tbl[7] = SYN_XFER_NS_7; + asc_dvc->sdtr_period_tbl = asc_syn_xfer_period; asc_dvc->max_sdtr_index = 7; if ((asc_dvc->bus_type & ASC_IS_PCI) && (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3150)) { asc_dvc->bus_type = ASC_IS_PCI_ULTRA; - asc_dvc->sdtr_period_tbl[0] = SYN_ULTRA_XFER_NS_0; - asc_dvc->sdtr_period_tbl[1] = SYN_ULTRA_XFER_NS_1; - asc_dvc->sdtr_period_tbl[2] = SYN_ULTRA_XFER_NS_2; - asc_dvc->sdtr_period_tbl[3] = SYN_ULTRA_XFER_NS_3; - asc_dvc->sdtr_period_tbl[4] = SYN_ULTRA_XFER_NS_4; - asc_dvc->sdtr_period_tbl[5] = SYN_ULTRA_XFER_NS_5; - asc_dvc->sdtr_period_tbl[6] = SYN_ULTRA_XFER_NS_6; - asc_dvc->sdtr_period_tbl[7] = SYN_ULTRA_XFER_NS_7; - asc_dvc->sdtr_period_tbl[8] = SYN_ULTRA_XFER_NS_8; - asc_dvc->sdtr_period_tbl[9] = SYN_ULTRA_XFER_NS_9; - asc_dvc->sdtr_period_tbl[10] = SYN_ULTRA_XFER_NS_10; - asc_dvc->sdtr_period_tbl[11] = SYN_ULTRA_XFER_NS_11; - asc_dvc->sdtr_period_tbl[12] = SYN_ULTRA_XFER_NS_12; - asc_dvc->sdtr_period_tbl[13] = SYN_ULTRA_XFER_NS_13; - asc_dvc->sdtr_period_tbl[14] = SYN_ULTRA_XFER_NS_14; - asc_dvc->sdtr_period_tbl[15] = SYN_ULTRA_XFER_NS_15; + asc_dvc->sdtr_period_tbl = asc_syn_ultra_xfer_period; asc_dvc->max_sdtr_index = 15; if (chip_version == ASC_CHIP_VER_PCI_ULTRA_3150) { AscSetExtraControl(iop_base, @@ -10943,12 +11274,12 @@ static ushort __init AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc) } asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED; - if (AscGetChipBusType(iop_base) == ASC_IS_ISAPNP) { - AscSetChipIFC(iop_base, IFC_INIT_DEFAULT); - asc_dvc->bus_type = ASC_IS_ISAPNP; - } #ifdef CONFIG_ISA if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) { + if (chip_version >= ASC_CHIP_MIN_VER_ISA_PNP) { + AscSetChipIFC(iop_base, IFC_INIT_DEFAULT); + asc_dvc->bus_type = ASC_IS_ISAPNP; + } asc_dvc->cfg->isa_dma_channel = (uchar)AscGetIsaDmaChannel(iop_base); } @@ -10960,231 +11291,92 @@ static ushort __init AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc) asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q *)0L; asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG; } - return (warn_code); + return warn_code; } -static ushort __init AscInitFromEEP(ASC_DVC_VAR *asc_dvc) +static int __devinit AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg) { - ASCEEP_CONFIG eep_config_buf; - ASCEEP_CONFIG *eep_config; - PortAddr iop_base; - ushort chksum; - ushort warn_code; - ushort cfg_msw, cfg_lsw; - int i; - int write_eep = 0; - - iop_base = asc_dvc->iop_base; - warn_code = 0; - AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE); - AscStopQueueExe(iop_base); - if ((AscStopChip(iop_base) == FALSE) || - (AscGetChipScsiCtrl(iop_base) != 0)) { - asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE; - AscResetChipAndScsiBus(asc_dvc); - DvcSleepMilliSecond((ASC_DCNT) - ((ushort)asc_dvc->scsi_reset_wait * 1000)); - } - if (AscIsChipHalted(iop_base) == FALSE) { - asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP; - return (warn_code); - } - AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR); - if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) { - asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR; - return (warn_code); - } - eep_config = (ASCEEP_CONFIG *)&eep_config_buf; - cfg_msw = AscGetChipCfgMsw(iop_base); - cfg_lsw = AscGetChipCfgLsw(iop_base); - if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) { - cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK)); - warn_code |= ASC_WARN_CFG_MSW_RECOVER; - AscSetChipCfgMsw(iop_base, cfg_msw); - } - chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type); - ASC_DBG1(1, "AscInitFromEEP: chksum 0x%x\n", chksum); - if (chksum == 0) { - chksum = 0xaa55; - } - if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) { - warn_code |= ASC_WARN_AUTO_CONFIG; - if (asc_dvc->cfg->chip_version == 3) { - if (eep_config->cfg_lsw != cfg_lsw) { - warn_code |= ASC_WARN_EEPROM_RECOVER; - eep_config->cfg_lsw = - AscGetChipCfgLsw(iop_base); - } - if (eep_config->cfg_msw != cfg_msw) { - warn_code |= ASC_WARN_EEPROM_RECOVER; - eep_config->cfg_msw = - AscGetChipCfgMsw(iop_base); - } - } - } - eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK; - eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON; - ASC_DBG1(1, "AscInitFromEEP: eep_config->chksum 0x%x\n", - eep_config->chksum); - if (chksum != eep_config->chksum) { - if (AscGetChipVersion(iop_base, asc_dvc->bus_type) == - ASC_CHIP_VER_PCI_ULTRA_3050) { - ASC_DBG(1, - "AscInitFromEEP: chksum error ignored; EEPROM-less board\n"); - eep_config->init_sdtr = 0xFF; - eep_config->disc_enable = 0xFF; - eep_config->start_motor = 0xFF; - eep_config->use_cmd_qng = 0; - eep_config->max_total_qng = 0xF0; - eep_config->max_tag_qng = 0x20; - eep_config->cntl = 0xBFFF; - ASC_EEP_SET_CHIP_ID(eep_config, 7); - eep_config->no_scam = 0; - eep_config->adapter_info[0] = 0; - eep_config->adapter_info[1] = 0; - eep_config->adapter_info[2] = 0; - eep_config->adapter_info[3] = 0; - eep_config->adapter_info[4] = 0; - /* Indicate EEPROM-less board. */ - eep_config->adapter_info[5] = 0xBB; - } else { - ASC_PRINT - ("AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n"); - write_eep = 1; - warn_code |= ASC_WARN_EEPROM_CHKSUM; - } - } - asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr; - asc_dvc->cfg->disc_enable = eep_config->disc_enable; - asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng; - asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config); - asc_dvc->start_motor = eep_config->start_motor; - asc_dvc->dvc_cntl = eep_config->cntl; - asc_dvc->no_scam = eep_config->no_scam; - asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0]; - asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1]; - asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2]; - asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3]; - asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4]; - asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5]; - if (!AscTestExternalLram(asc_dvc)) { - if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == - ASC_IS_PCI_ULTRA)) { - eep_config->max_total_qng = - ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG; - eep_config->max_tag_qng = - ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG; - } else { - eep_config->cfg_msw |= 0x0800; - cfg_msw |= 0x0800; - AscSetChipCfgMsw(iop_base, cfg_msw); - eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG; - eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG; - } - } else { - } - if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) { - eep_config->max_total_qng = ASC_MIN_TOTAL_QNG; - } - if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) { - eep_config->max_total_qng = ASC_MAX_TOTAL_QNG; - } - if (eep_config->max_tag_qng > eep_config->max_total_qng) { - eep_config->max_tag_qng = eep_config->max_total_qng; - } - if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) { - eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC; - } - asc_dvc->max_total_qng = eep_config->max_total_qng; - if ((eep_config->use_cmd_qng & eep_config->disc_enable) != - eep_config->use_cmd_qng) { - eep_config->disc_enable = eep_config->use_cmd_qng; - warn_code |= ASC_WARN_CMD_QNG_CONFLICT; - } - if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) { - asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type); - } - ASC_EEP_SET_CHIP_ID(eep_config, - ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID); - asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config); - if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) && - !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) { - asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX; - } + int retry; - for (i = 0; i <= ASC_MAX_TID; i++) { - asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i]; - asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng; - asc_dvc->cfg->sdtr_period_offset[i] = - (uchar)(ASC_DEF_SDTR_OFFSET | - (asc_dvc->host_init_sdtr_index << 4)); - } - eep_config->cfg_msw = AscGetChipCfgMsw(iop_base); - if (write_eep) { - if ((i = - AscSetEEPConfig(iop_base, eep_config, - asc_dvc->bus_type)) != 0) { - ASC_PRINT1 - ("AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n", - i); - } else { - ASC_PRINT - ("AscInitFromEEP: Successfully re-wrote EEPROM.\n"); - } + for (retry = 0; retry < ASC_EEP_MAX_RETRY; retry++) { + unsigned char read_back; + AscSetChipEEPCmd(iop_base, cmd_reg); + mdelay(1); + read_back = AscGetChipEEPCmd(iop_base); + if (read_back == cmd_reg) + return 1; } - return (warn_code); + return 0; } -static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc) +static void __devinit AscWaitEEPRead(void) { - int i; - ushort warn_code; - PortAddr iop_base; - ASC_PADDR phy_addr; - ASC_DCNT phy_size; - - iop_base = asc_dvc->iop_base; - warn_code = 0; - for (i = 0; i <= ASC_MAX_TID; i++) { - AscPutMCodeInitSDTRAtID(iop_base, i, - asc_dvc->cfg->sdtr_period_offset[i] - ); - } + mdelay(1); +} - AscInitQLinkVar(asc_dvc); - AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B, - asc_dvc->cfg->disc_enable); - AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B, - ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id)); +static ushort __devinit AscReadEEPWord(PortAddr iop_base, uchar addr) +{ + ushort read_wval; + uchar cmd_reg; - /* Align overrun buffer on an 8 byte boundary. */ - phy_addr = virt_to_bus(asc_dvc->cfg->overrun_buf); - phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7); - AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D, - (uchar *)&phy_addr, 1); - phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE - 8); - AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D, - (uchar *)&phy_size, 1); + AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE); + AscWaitEEPRead(); + cmd_reg = addr | ASC_EEP_CMD_READ; + AscWriteEEPCmdReg(iop_base, cmd_reg); + AscWaitEEPRead(); + read_wval = AscGetChipEEPData(iop_base); + AscWaitEEPRead(); + return read_wval; +} - asc_dvc->cfg->mcode_date = - AscReadLramWord(iop_base, (ushort)ASCV_MC_DATE_W); - asc_dvc->cfg->mcode_version = - AscReadLramWord(iop_base, (ushort)ASCV_MC_VER_W); +static ushort __devinit +AscGetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type) +{ + ushort wval; + ushort sum; + ushort *wbuf; + int cfg_beg; + int cfg_end; + int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2; + int s_addr; - AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR); - if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) { - asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR; - return (warn_code); + wbuf = (ushort *)cfg_buf; + sum = 0; + /* Read two config words; Byte-swapping done by AscReadEEPWord(). */ + for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { + *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr); + sum += *wbuf; } - if (AscStartChip(iop_base) != 1) { - asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP; - return (warn_code); + if (bus_type & ASC_IS_VL) { + cfg_beg = ASC_EEP_DVC_CFG_BEG_VL; + cfg_end = ASC_EEP_MAX_DVC_ADDR_VL; + } else { + cfg_beg = ASC_EEP_DVC_CFG_BEG; + cfg_end = ASC_EEP_MAX_DVC_ADDR; } - - return (warn_code); + for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) { + wval = AscReadEEPWord(iop_base, (uchar)s_addr); + if (s_addr <= uchar_end_in_config) { + /* + * Swap all char fields - must unswap bytes already swapped + * by AscReadEEPWord(). + */ + *wbuf = le16_to_cpu(wval); + } else { + /* Don't swap word field at the end - cntl field. */ + *wbuf = wval; + } + sum += wval; /* Checksum treats all EEPROM data as words. */ + } + /* + * Read the checksum word which will be compared against 'sum' + * by the caller. Word field already swapped. + */ + *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr); + return sum; } -static int __init AscTestExternalLram(ASC_DVC_VAR *asc_dvc) +static int __devinit AscTestExternalLram(ASC_DVC_VAR *asc_dvc) { PortAddr iop_base; ushort q_addr; @@ -11197,7 +11389,7 @@ static int __init AscTestExternalLram(ASC_DVC_VAR *asc_dvc) saved_word = AscReadLramWord(iop_base, q_addr); AscSetChipLramAddr(iop_base, q_addr); AscSetChipLramData(iop_base, 0x55AA); - DvcSleepMilliSecond(10); + mdelay(10); AscSetChipLramAddr(iop_base, q_addr); if (AscGetChipLramData(iop_base) == 0x55AA) { sta = 1; @@ -11206,26 +11398,12 @@ static int __init AscTestExternalLram(ASC_DVC_VAR *asc_dvc) return (sta); } -static int __init AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg) +static void __devinit AscWaitEEPWrite(void) { - uchar read_back; - int retry; - - retry = 0; - while (TRUE) { - AscSetChipEEPCmd(iop_base, cmd_reg); - DvcSleepMilliSecond(1); - read_back = AscGetChipEEPCmd(iop_base); - if (read_back == cmd_reg) { - return (1); - } - if (retry++ > ASC_EEP_MAX_RETRY) { - return (0); - } - } + mdelay(20); } -static int __init AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg) +static int __devinit AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg) { ushort read_back; int retry; @@ -11233,7 +11411,7 @@ static int __init AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg) retry = 0; while (TRUE) { AscSetChipEEPData(iop_base, data_reg); - DvcSleepMilliSecond(1); + mdelay(1); read_back = AscGetChipEEPData(iop_base); if (read_back == data_reg) { return (1); @@ -11244,34 +11422,7 @@ static int __init AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg) } } -static void __init AscWaitEEPRead(void) -{ - DvcSleepMilliSecond(1); - return; -} - -static void __init AscWaitEEPWrite(void) -{ - DvcSleepMilliSecond(20); - return; -} - -static ushort __init AscReadEEPWord(PortAddr iop_base, uchar addr) -{ - ushort read_wval; - uchar cmd_reg; - - AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE); - AscWaitEEPRead(); - cmd_reg = addr | ASC_EEP_CMD_READ; - AscWriteEEPCmdReg(iop_base, cmd_reg); - AscWaitEEPRead(); - read_wval = AscGetChipEEPData(iop_base); - AscWaitEEPRead(); - return (read_wval); -} - -static ushort __init +static ushort __devinit AscWriteEEPWord(PortAddr iop_base, uchar addr, ushort word_val) { ushort read_wval; @@ -11292,54 +11443,7 @@ AscWriteEEPWord(PortAddr iop_base, uchar addr, ushort word_val) return (read_wval); } -static ushort __init -AscGetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type) -{ - ushort wval; - ushort sum; - ushort *wbuf; - int cfg_beg; - int cfg_end; - int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2; - int s_addr; - - wbuf = (ushort *)cfg_buf; - sum = 0; - /* Read two config words; Byte-swapping done by AscReadEEPWord(). */ - for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { - *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr); - sum += *wbuf; - } - if (bus_type & ASC_IS_VL) { - cfg_beg = ASC_EEP_DVC_CFG_BEG_VL; - cfg_end = ASC_EEP_MAX_DVC_ADDR_VL; - } else { - cfg_beg = ASC_EEP_DVC_CFG_BEG; - cfg_end = ASC_EEP_MAX_DVC_ADDR; - } - for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) { - wval = AscReadEEPWord(iop_base, (uchar)s_addr); - if (s_addr <= uchar_end_in_config) { - /* - * Swap all char fields - must unswap bytes already swapped - * by AscReadEEPWord(). - */ - *wbuf = le16_to_cpu(wval); - } else { - /* Don't swap word field at the end - cntl field. */ - *wbuf = wval; - } - sum += wval; /* Checksum treats all EEPROM data as words. */ - } - /* - * Read the checksum word which will be compared against 'sum' - * by the caller. Word field already swapped. - */ - *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr); - return (sum); -} - -static int __init +static int __devinit AscSetEEPConfigOnce(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type) { int n_error; @@ -11432,10 +11536,10 @@ AscSetEEPConfigOnce(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type) if (AscReadEEPWord(iop_base, (uchar)s_addr) != sum) { n_error++; } - return (n_error); + return n_error; } -static int __init +static int __devinit AscSetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type) { int retry; @@ -11451,2386 +11555,326 @@ AscSetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type) break; } } - return (n_error); + return n_error; } -static void -AscAsyncFix(ASC_DVC_VAR *asc_dvc, uchar tid_no, ASC_SCSI_INQUIRY *inq) +static ushort __devinit AscInitFromEEP(ASC_DVC_VAR *asc_dvc) { - uchar dvc_type; - ASC_SCSI_BIT_ID_TYPE tid_bits; - - dvc_type = ASC_INQ_DVC_TYPE(inq); - tid_bits = ASC_TIX_TO_TARGET_ID(tid_no); - - if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) { - if (!(asc_dvc->init_sdtr & tid_bits)) { - if ((dvc_type == TYPE_ROM) && - (AscCompareString((uchar *)inq->vendor_id, - (uchar *)"HP ", 3) == 0)) { - asc_dvc->pci_fix_asyn_xfer_always |= tid_bits; - } - asc_dvc->pci_fix_asyn_xfer |= tid_bits; - if ((dvc_type == TYPE_PROCESSOR) || - (dvc_type == TYPE_SCANNER) || - (dvc_type == TYPE_ROM) || (dvc_type == TYPE_TAPE)) { - asc_dvc->pci_fix_asyn_xfer &= ~tid_bits; - } + ASCEEP_CONFIG eep_config_buf; + ASCEEP_CONFIG *eep_config; + PortAddr iop_base; + ushort chksum; + ushort warn_code; + ushort cfg_msw, cfg_lsw; + int i; + int write_eep = 0; - if (asc_dvc->pci_fix_asyn_xfer & tid_bits) { - AscSetRunChipSynRegAtID(asc_dvc->iop_base, - tid_no, - ASYN_SDTR_DATA_FIX_PCI_REV_AB); + iop_base = asc_dvc->iop_base; + warn_code = 0; + AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE); + AscStopQueueExe(iop_base); + if ((AscStopChip(iop_base) == FALSE) || + (AscGetChipScsiCtrl(iop_base) != 0)) { + asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE; + AscResetChipAndScsiBus(asc_dvc); + mdelay(asc_dvc->scsi_reset_wait * 1000); /* XXX: msleep? */ + } + if (AscIsChipHalted(iop_base) == FALSE) { + asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP; + return (warn_code); + } + AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR); + if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) { + asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR; + return (warn_code); + } + eep_config = (ASCEEP_CONFIG *)&eep_config_buf; + cfg_msw = AscGetChipCfgMsw(iop_base); + cfg_lsw = AscGetChipCfgLsw(iop_base); + if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) { + cfg_msw &= ~ASC_CFG_MSW_CLR_MASK; + warn_code |= ASC_WARN_CFG_MSW_RECOVER; + AscSetChipCfgMsw(iop_base, cfg_msw); + } + chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type); + ASC_DBG(1, "chksum 0x%x\n", chksum); + if (chksum == 0) { + chksum = 0xaa55; + } + if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) { + warn_code |= ASC_WARN_AUTO_CONFIG; + if (asc_dvc->cfg->chip_version == 3) { + if (eep_config->cfg_lsw != cfg_lsw) { + warn_code |= ASC_WARN_EEPROM_RECOVER; + eep_config->cfg_lsw = + AscGetChipCfgLsw(iop_base); + } + if (eep_config->cfg_msw != cfg_msw) { + warn_code |= ASC_WARN_EEPROM_RECOVER; + eep_config->cfg_msw = + AscGetChipCfgMsw(iop_base); } } } - return; -} - -static int AscTagQueuingSafe(ASC_SCSI_INQUIRY *inq) -{ - if ((inq->add_len >= 32) && - (AscCompareString((uchar *)inq->vendor_id, - (uchar *)"QUANTUM XP34301", 15) == 0) && - (AscCompareString((uchar *)inq->product_rev_level, - (uchar *)"1071", 4) == 0)) { - return 0; - } - return 1; -} - -static void -AscInquiryHandling(ASC_DVC_VAR *asc_dvc, uchar tid_no, ASC_SCSI_INQUIRY *inq) -{ - ASC_SCSI_BIT_ID_TYPE tid_bit = ASC_TIX_TO_TARGET_ID(tid_no); - ASC_SCSI_BIT_ID_TYPE orig_init_sdtr, orig_use_tagged_qng; - - orig_init_sdtr = asc_dvc->init_sdtr; - orig_use_tagged_qng = asc_dvc->use_tagged_qng; - - asc_dvc->init_sdtr &= ~tid_bit; - asc_dvc->cfg->can_tagged_qng &= ~tid_bit; - asc_dvc->use_tagged_qng &= ~tid_bit; - - if (ASC_INQ_RESPONSE_FMT(inq) >= 2 || ASC_INQ_ANSI_VER(inq) >= 2) { - if ((asc_dvc->cfg->sdtr_enable & tid_bit) && ASC_INQ_SYNC(inq)) { - asc_dvc->init_sdtr |= tid_bit; + eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK; + eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON; + ASC_DBG(1, "eep_config->chksum 0x%x\n", eep_config->chksum); + if (chksum != eep_config->chksum) { + if (AscGetChipVersion(iop_base, asc_dvc->bus_type) == + ASC_CHIP_VER_PCI_ULTRA_3050) { + ASC_DBG(1, "chksum error ignored; EEPROM-less board\n"); + eep_config->init_sdtr = 0xFF; + eep_config->disc_enable = 0xFF; + eep_config->start_motor = 0xFF; + eep_config->use_cmd_qng = 0; + eep_config->max_total_qng = 0xF0; + eep_config->max_tag_qng = 0x20; + eep_config->cntl = 0xBFFF; + ASC_EEP_SET_CHIP_ID(eep_config, 7); + eep_config->no_scam = 0; + eep_config->adapter_info[0] = 0; + eep_config->adapter_info[1] = 0; + eep_config->adapter_info[2] = 0; + eep_config->adapter_info[3] = 0; + eep_config->adapter_info[4] = 0; + /* Indicate EEPROM-less board. */ + eep_config->adapter_info[5] = 0xBB; + } else { + ASC_PRINT + ("AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n"); + write_eep = 1; + warn_code |= ASC_WARN_EEPROM_CHKSUM; } - if ((asc_dvc->cfg->cmd_qng_enabled & tid_bit) && - ASC_INQ_CMD_QUEUE(inq)) { - if (AscTagQueuingSafe(inq)) { - asc_dvc->use_tagged_qng |= tid_bit; - asc_dvc->cfg->can_tagged_qng |= tid_bit; - } + } + asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr; + asc_dvc->cfg->disc_enable = eep_config->disc_enable; + asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng; + asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config); + asc_dvc->start_motor = eep_config->start_motor; + asc_dvc->dvc_cntl = eep_config->cntl; + asc_dvc->no_scam = eep_config->no_scam; + asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0]; + asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1]; + asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2]; + asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3]; + asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4]; + asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5]; + if (!AscTestExternalLram(asc_dvc)) { + if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == + ASC_IS_PCI_ULTRA)) { + eep_config->max_total_qng = + ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG; + eep_config->max_tag_qng = + ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG; + } else { + eep_config->cfg_msw |= 0x0800; + cfg_msw |= 0x0800; + AscSetChipCfgMsw(iop_base, cfg_msw); + eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG; + eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG; } + } else { } - if (orig_use_tagged_qng != asc_dvc->use_tagged_qng) { - AscWriteLramByte(asc_dvc->iop_base, ASCV_DISC_ENABLE_B, - asc_dvc->cfg->disc_enable); - AscWriteLramByte(asc_dvc->iop_base, ASCV_USE_TAGGED_QNG_B, - asc_dvc->use_tagged_qng); - AscWriteLramByte(asc_dvc->iop_base, ASCV_CAN_TAGGED_QNG_B, - asc_dvc->cfg->can_tagged_qng); - - asc_dvc->max_dvc_qng[tid_no] = - asc_dvc->cfg->max_tag_qng[tid_no]; - AscWriteLramByte(asc_dvc->iop_base, - (ushort)(ASCV_MAX_DVC_QNG_BEG + tid_no), - asc_dvc->max_dvc_qng[tid_no]); + if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) { + eep_config->max_total_qng = ASC_MIN_TOTAL_QNG; } - if (orig_init_sdtr != asc_dvc->init_sdtr) { - AscAsyncFix(asc_dvc, tid_no, inq); + if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) { + eep_config->max_total_qng = ASC_MAX_TOTAL_QNG; } - return; -} - -static int AscCompareString(uchar *str1, uchar *str2, int len) -{ - int i; - int diff; - - for (i = 0; i < len; i++) { - diff = (int)(str1[i] - str2[i]); - if (diff != 0) - return (diff); + if (eep_config->max_tag_qng > eep_config->max_total_qng) { + eep_config->max_tag_qng = eep_config->max_total_qng; } - return (0); -} - -static uchar AscReadLramByte(PortAddr iop_base, ushort addr) -{ - uchar byte_data; - ushort word_data; - - if (isodd_word(addr)) { - AscSetChipLramAddr(iop_base, addr - 1); - word_data = AscGetChipLramData(iop_base); - byte_data = (uchar)((word_data >> 8) & 0xFF); - } else { - AscSetChipLramAddr(iop_base, addr); - word_data = AscGetChipLramData(iop_base); - byte_data = (uchar)(word_data & 0xFF); + if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) { + eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC; + } + asc_dvc->max_total_qng = eep_config->max_total_qng; + if ((eep_config->use_cmd_qng & eep_config->disc_enable) != + eep_config->use_cmd_qng) { + eep_config->disc_enable = eep_config->use_cmd_qng; + warn_code |= ASC_WARN_CMD_QNG_CONFLICT; + } + ASC_EEP_SET_CHIP_ID(eep_config, + ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID); + asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config); + if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) && + !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) { + asc_dvc->min_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX; } - return (byte_data); -} - -static ushort AscReadLramWord(PortAddr iop_base, ushort addr) -{ - ushort word_data; - - AscSetChipLramAddr(iop_base, addr); - word_data = AscGetChipLramData(iop_base); - return (word_data); -} - -#if CC_VERY_LONG_SG_LIST -static ASC_DCNT AscReadLramDWord(PortAddr iop_base, ushort addr) -{ - ushort val_low, val_high; - ASC_DCNT dword_data; - AscSetChipLramAddr(iop_base, addr); - val_low = AscGetChipLramData(iop_base); - val_high = AscGetChipLramData(iop_base); - dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low; - return (dword_data); + for (i = 0; i <= ASC_MAX_TID; i++) { + asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i]; + asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng; + asc_dvc->cfg->sdtr_period_offset[i] = + (uchar)(ASC_DEF_SDTR_OFFSET | + (asc_dvc->min_sdtr_index << 4)); + } + eep_config->cfg_msw = AscGetChipCfgMsw(iop_base); + if (write_eep) { + if ((i = AscSetEEPConfig(iop_base, eep_config, + asc_dvc->bus_type)) != 0) { + ASC_PRINT1 + ("AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n", + i); + } else { + ASC_PRINT + ("AscInitFromEEP: Successfully re-wrote EEPROM.\n"); + } + } + return (warn_code); } -#endif /* CC_VERY_LONG_SG_LIST */ -static void AscWriteLramWord(PortAddr iop_base, ushort addr, ushort word_val) +static int __devinit AscInitGetConfig(struct Scsi_Host *shost) { - AscSetChipLramAddr(iop_base, addr); - AscSetChipLramData(iop_base, word_val); - return; -} + struct asc_board *board = shost_priv(shost); + ASC_DVC_VAR *asc_dvc = &board->dvc_var.asc_dvc_var; + unsigned short warn_code = 0; -static void AscWriteLramByte(PortAddr iop_base, ushort addr, uchar byte_val) -{ - ushort word_data; + asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG; + if (asc_dvc->err_code != 0) + return asc_dvc->err_code; - if (isodd_word(addr)) { - addr--; - word_data = AscReadLramWord(iop_base, addr); - word_data &= 0x00FF; - word_data |= (((ushort)byte_val << 8) & 0xFF00); + if (AscFindSignature(asc_dvc->iop_base)) { + warn_code |= AscInitAscDvcVar(asc_dvc); + warn_code |= AscInitFromEEP(asc_dvc); + asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG; + if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT) + asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT; } else { - word_data = AscReadLramWord(iop_base, addr); - word_data &= 0xFF00; - word_data |= ((ushort)byte_val & 0x00FF); + asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE; } - AscWriteLramWord(iop_base, addr, word_data); - return; -} -/* - * Copy 2 bytes to LRAM. - * - * The source data is assumed to be in little-endian order in memory - * and is maintained in little-endian order when written to LRAM. - */ -static void -AscMemWordCopyPtrToLram(PortAddr iop_base, - ushort s_addr, uchar *s_buffer, int words) -{ - int i; - - AscSetChipLramAddr(iop_base, s_addr); - for (i = 0; i < 2 * words; i += 2) { - /* - * On a little-endian system the second argument below - * produces a little-endian ushort which is written to - * LRAM in little-endian order. On a big-endian system - * the second argument produces a big-endian ushort which - * is "transparently" byte-swapped by outpw() and written - * in little-endian order to LRAM. - */ - outpw(iop_base + IOP_RAM_DATA, - ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]); + switch (warn_code) { + case 0: /* No error */ + break; + case ASC_WARN_IO_PORT_ROTATE: + shost_printk(KERN_WARNING, shost, "I/O port address " + "modified\n"); + break; + case ASC_WARN_AUTO_CONFIG: + shost_printk(KERN_WARNING, shost, "I/O port increment switch " + "enabled\n"); + break; + case ASC_WARN_EEPROM_CHKSUM: + shost_printk(KERN_WARNING, shost, "EEPROM checksum error\n"); + break; + case ASC_WARN_IRQ_MODIFIED: + shost_printk(KERN_WARNING, shost, "IRQ modified\n"); + break; + case ASC_WARN_CMD_QNG_CONFLICT: + shost_printk(KERN_WARNING, shost, "tag queuing enabled w/o " + "disconnects\n"); + break; + default: + shost_printk(KERN_WARNING, shost, "unknown warning: 0x%x\n", + warn_code); + break; } - return; -} -/* - * Copy 4 bytes to LRAM. - * - * The source data is assumed to be in little-endian order in memory - * and is maintained in little-endian order when writen to LRAM. - */ -static void -AscMemDWordCopyPtrToLram(PortAddr iop_base, - ushort s_addr, uchar *s_buffer, int dwords) -{ - int i; + if (asc_dvc->err_code != 0) + shost_printk(KERN_ERR, shost, "error 0x%x at init_state " + "0x%x\n", asc_dvc->err_code, asc_dvc->init_state); - AscSetChipLramAddr(iop_base, s_addr); - for (i = 0; i < 4 * dwords; i += 4) { - outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]); /* LSW */ - outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 3] << 8) | s_buffer[i + 2]); /* MSW */ - } - return; + return asc_dvc->err_code; } -/* - * Copy 2 bytes from LRAM. - * - * The source data is assumed to be in little-endian order in LRAM - * and is maintained in little-endian order when written to memory. - */ -static void -AscMemWordCopyPtrFromLram(PortAddr iop_base, - ushort s_addr, uchar *d_buffer, int words) +static int __devinit AscInitSetConfig(struct pci_dev *pdev, struct Scsi_Host *shost) { - int i; - ushort word; + struct asc_board *board = shost_priv(shost); + ASC_DVC_VAR *asc_dvc = &board->dvc_var.asc_dvc_var; + PortAddr iop_base = asc_dvc->iop_base; + unsigned short cfg_msw; + unsigned short warn_code = 0; - AscSetChipLramAddr(iop_base, s_addr); - for (i = 0; i < 2 * words; i += 2) { - word = inpw(iop_base + IOP_RAM_DATA); - d_buffer[i] = word & 0xff; - d_buffer[i + 1] = (word >> 8) & 0xff; + asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG; + if (asc_dvc->err_code != 0) + return asc_dvc->err_code; + if (!AscFindSignature(asc_dvc->iop_base)) { + asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE; + return asc_dvc->err_code; } - return; -} - -static ASC_DCNT AscMemSumLramWord(PortAddr iop_base, ushort s_addr, int words) -{ - ASC_DCNT sum; - int i; - sum = 0L; - for (i = 0; i < words; i++, s_addr += 2) { - sum += AscReadLramWord(iop_base, s_addr); + cfg_msw = AscGetChipCfgMsw(iop_base); + if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) { + cfg_msw &= ~ASC_CFG_MSW_CLR_MASK; + warn_code |= ASC_WARN_CFG_MSW_RECOVER; + AscSetChipCfgMsw(iop_base, cfg_msw); } - return (sum); -} - -static void -AscMemWordSetLram(PortAddr iop_base, ushort s_addr, ushort set_wval, int words) -{ - int i; - - AscSetChipLramAddr(iop_base, s_addr); - for (i = 0; i < words; i++) { - AscSetChipLramData(iop_base, set_wval); + if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) != + asc_dvc->cfg->cmd_qng_enabled) { + asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled; + warn_code |= ASC_WARN_CMD_QNG_CONFLICT; } - return; -} - -/* - * --- Adv Library Functions - */ - -/* a_mcode.h */ - -/* Microcode buffer is kept after initialization for error recovery. */ -static unsigned char _adv_asc3550_buf[] = { - 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x18, 0xe4, 0x00, 0xfc, - 0x01, 0x00, 0x48, 0xe4, - 0xbe, 0x18, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0x00, 0xfa, 0xff, 0xff, - 0x28, 0x0e, 0x9e, 0xe7, - 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x00, 0xf6, 0x01, 0xe6, 0x09, 0xe7, - 0x55, 0xf0, 0x01, 0xf6, - 0x01, 0xfa, 0x08, 0x00, 0x03, 0x00, 0x04, 0x00, 0x18, 0xf4, 0x10, 0x00, - 0x00, 0xec, 0x85, 0xf0, - 0xbc, 0x00, 0xd5, 0xf0, 0x8e, 0x0c, 0x38, 0x54, 0x00, 0xe6, 0x1e, 0xf0, - 0x86, 0xf0, 0xb4, 0x00, - 0x98, 0x57, 0xd0, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x0c, 0x00, 0xbb, 0x00, - 0xaa, 0x18, 0x02, 0x80, - 0x32, 0xf0, 0x01, 0xfc, 0x88, 0x0c, 0xc6, 0x12, 0x02, 0x13, 0x18, 0x40, - 0x00, 0x57, 0x01, 0xea, - 0x3c, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12, 0x3e, 0x57, 0x00, 0x80, - 0x03, 0xe6, 0xb6, 0x00, - 0xc0, 0x00, 0x01, 0x01, 0x3e, 0x01, 0xda, 0x0f, 0x22, 0x10, 0x08, 0x12, - 0x02, 0x4a, 0xb9, 0x54, - 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x20, 0x00, 0x32, 0x00, - 0x3e, 0x00, 0x80, 0x00, - 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, - 0x74, 0x01, 0x76, 0x01, - 0x78, 0x01, 0x62, 0x0a, 0x92, 0x0c, 0x2c, 0x10, 0x2e, 0x10, 0x06, 0x13, - 0x4c, 0x1c, 0xbb, 0x55, - 0x3c, 0x56, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0xb1, 0xf0, - 0x03, 0xf7, 0x06, 0xf7, - 0x03, 0xfc, 0x0f, 0x00, 0x40, 0x00, 0xbe, 0x00, 0x00, 0x01, 0xb0, 0x08, - 0x30, 0x13, 0x64, 0x15, - 0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44, 0x02, 0x48, 0x00, 0x4c, - 0x04, 0xea, 0x5d, 0xf0, - 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00, - 0xcc, 0x00, 0x20, 0x01, - 0x4e, 0x01, 0x4e, 0x0b, 0x1e, 0x0e, 0x0c, 0x10, 0x0a, 0x12, 0x04, 0x13, - 0x40, 0x13, 0x30, 0x1c, - 0x00, 0x4e, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0, - 0x59, 0xf0, 0xa7, 0xf0, - 0xb8, 0xf0, 0x0e, 0xf7, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00, - 0xa4, 0x00, 0xb5, 0x00, - 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xde, 0x03, 0x56, 0x0a, - 0x14, 0x0e, 0x02, 0x10, - 0x04, 0x10, 0x0a, 0x10, 0x36, 0x10, 0x0a, 0x13, 0x12, 0x13, 0x52, 0x13, - 0x10, 0x15, 0x14, 0x15, - 0xac, 0x16, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44, - 0x91, 0x44, 0x0a, 0x45, - 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x83, 0x55, 0xb0, 0x57, 0x01, 0x58, - 0x83, 0x59, 0x05, 0xe6, - 0x0b, 0xf0, 0x0c, 0xf0, 0x5c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, 0x05, 0xf8, - 0x02, 0xfa, 0x03, 0xfa, - 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x1c, 0x00, - 0x9e, 0x00, 0xa8, 0x00, - 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, - 0x7a, 0x01, 0xc0, 0x01, - 0xc2, 0x01, 0x7c, 0x02, 0x5a, 0x03, 0xea, 0x04, 0xe8, 0x07, 0x68, 0x08, - 0x69, 0x08, 0xba, 0x08, - 0xe9, 0x09, 0x06, 0x0b, 0x3a, 0x0e, 0x00, 0x10, 0x1a, 0x10, 0xed, 0x10, - 0xf1, 0x10, 0x06, 0x12, - 0x0c, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x82, 0x13, 0x42, 0x14, 0xd6, 0x14, - 0x8a, 0x15, 0xc6, 0x17, - 0xd2, 0x17, 0x6b, 0x18, 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, - 0x0e, 0x47, 0x48, 0x47, - 0x41, 0x48, 0x89, 0x48, 0x80, 0x4c, 0x00, 0x54, 0x44, 0x55, 0xe5, 0x55, - 0x14, 0x56, 0x77, 0x57, - 0xbf, 0x57, 0x40, 0x5c, 0x06, 0x80, 0x08, 0x90, 0x03, 0xa1, 0xfe, 0x9c, - 0xf0, 0x29, 0x02, 0xfe, - 0xb8, 0x0c, 0xff, 0x10, 0x00, 0x00, 0xd0, 0xfe, 0xcc, 0x18, 0x00, 0xcf, - 0xfe, 0x80, 0x01, 0xff, - 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00, - 0x00, 0xfe, 0x57, 0x24, - 0x00, 0xfe, 0x48, 0x00, 0x4f, 0xff, 0x04, 0x00, 0x00, 0x10, 0xff, 0x09, - 0x00, 0x00, 0xff, 0x08, - 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, - 0xff, 0xff, 0xff, 0x0f, - 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00, - 0xfe, 0x04, 0xf7, 0xcf, - 0x2a, 0x67, 0x0b, 0x01, 0xfe, 0xce, 0x0e, 0xfe, 0x04, 0xf7, 0xcf, 0x67, - 0x0b, 0x3c, 0x2a, 0xfe, - 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x91, 0xf0, - 0xfe, 0xf0, 0x01, 0xfe, - 0x90, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, 0x8f, 0xf0, 0x9c, 0x05, 0x51, 0x3b, - 0x02, 0xfe, 0xd4, 0x0c, - 0x01, 0xfe, 0x44, 0x0d, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28, - 0x1c, 0x05, 0xfe, 0xa6, - 0x00, 0xfe, 0xd3, 0x12, 0x47, 0x18, 0xfe, 0xa6, 0x00, 0xb5, 0xfe, 0x48, - 0xf0, 0xfe, 0x86, 0x02, - 0xfe, 0x49, 0xf0, 0xfe, 0xa0, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xbe, 0x02, - 0xfe, 0x46, 0xf0, 0xfe, - 0x50, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x56, 0x02, 0xfe, 0x43, 0xf0, 0xfe, - 0x44, 0x02, 0xfe, 0x44, - 0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x4c, 0x02, 0x17, 0x0b, - 0xa0, 0x17, 0x06, 0x18, - 0x96, 0x02, 0x29, 0xfe, 0x00, 0x1c, 0xde, 0xfe, 0x02, 0x1c, 0xdd, 0xfe, - 0x1e, 0x1c, 0xfe, 0xe9, - 0x10, 0x01, 0xfe, 0x20, 0x17, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xc7, - 0x0a, 0x6b, 0x01, 0x9e, - 0x02, 0x29, 0x14, 0x4d, 0x37, 0x97, 0x01, 0xfe, 0x64, 0x0f, 0x0a, 0x6b, - 0x01, 0x82, 0xfe, 0xbd, - 0x10, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe, - 0x58, 0x1c, 0x17, 0x06, - 0x18, 0x96, 0x2a, 0x25, 0x29, 0xfe, 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0x21, - 0xfe, 0x94, 0x02, 0xfe, - 0x5a, 0x1c, 0xea, 0xfe, 0x14, 0x1c, 0x14, 0xfe, 0x30, 0x00, 0x37, 0x97, - 0x01, 0xfe, 0x54, 0x0f, - 0x17, 0x06, 0x18, 0x96, 0x02, 0xd0, 0x1e, 0x20, 0x07, 0x10, 0x34, 0xfe, - 0x69, 0x10, 0x17, 0x06, - 0x18, 0x96, 0xfe, 0x04, 0xec, 0x20, 0x46, 0x3d, 0x12, 0x20, 0xfe, 0x05, - 0xf6, 0xc7, 0x01, 0xfe, - 0x52, 0x16, 0x09, 0x4a, 0x4c, 0x35, 0x11, 0x2d, 0x3c, 0x8a, 0x01, 0xe6, - 0x02, 0x29, 0x0a, 0x40, - 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x01, 0x6f, 0xfe, 0x18, 0x10, 0xfe, 0x41, - 0x58, 0x0a, 0x99, 0x01, - 0x0e, 0xfe, 0xc8, 0x54, 0x64, 0xfe, 0x0c, 0x03, 0x01, 0xe6, 0x02, 0x29, - 0x2a, 0x46, 0xfe, 0x02, - 0xe8, 0x27, 0xf8, 0xfe, 0x9e, 0x43, 0xf7, 0xfe, 0x27, 0xf0, 0xfe, 0xdc, - 0x01, 0xfe, 0x07, 0x4b, - 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x40, 0x1c, 0x25, 0xd2, 0xfe, 0x26, 0xf0, - 0xfe, 0x56, 0x03, 0xfe, - 0xa0, 0xf0, 0xfe, 0x44, 0x03, 0xfe, 0x11, 0xf0, 0x9c, 0xfe, 0xef, 0x10, - 0xfe, 0x9f, 0xf0, 0xfe, - 0x64, 0x03, 0xeb, 0x0f, 0xfe, 0x11, 0x00, 0x02, 0x5a, 0x2a, 0xfe, 0x48, - 0x1c, 0xeb, 0x09, 0x04, - 0x1d, 0xfe, 0x18, 0x13, 0x23, 0x1e, 0x98, 0xac, 0x12, 0x98, 0x0a, 0x40, - 0x01, 0x0e, 0xac, 0x75, - 0x01, 0xfe, 0xbc, 0x15, 0x11, 0xca, 0x25, 0xd2, 0xfe, 0x01, 0xf0, 0xd2, - 0xfe, 0x82, 0xf0, 0xfe, - 0x92, 0x03, 0xec, 0x11, 0xfe, 0xe4, 0x00, 0x65, 0xfe, 0xa4, 0x03, 0x25, - 0x32, 0x1f, 0xfe, 0xb4, - 0x03, 0x01, 0x43, 0xfe, 0x06, 0xf0, 0xfe, 0xc4, 0x03, 0x8d, 0x81, 0xfe, - 0x0a, 0xf0, 0xfe, 0x7a, - 0x06, 0x02, 0x22, 0x05, 0x6b, 0x28, 0x16, 0xfe, 0xf6, 0x04, 0x14, 0x2c, - 0x01, 0x33, 0x8f, 0xfe, - 0x66, 0x02, 0x02, 0xd1, 0xeb, 0x2a, 0x67, 0x1a, 0xfe, 0x67, 0x1b, 0xf8, - 0xf7, 0xfe, 0x48, 0x1c, - 0x70, 0x01, 0x6e, 0x87, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x16, 0xd3, - 0x0a, 0xca, 0x01, 0x0e, - 0x74, 0x60, 0x59, 0x76, 0x27, 0x05, 0x6b, 0x28, 0xfe, 0x10, 0x12, 0x14, - 0x2c, 0x01, 0x33, 0x8f, - 0xfe, 0x66, 0x02, 0x02, 0xd1, 0xbc, 0x7d, 0xbd, 0x7f, 0x25, 0x22, 0x65, - 0xfe, 0x3c, 0x04, 0x1f, - 0xfe, 0x38, 0x04, 0x68, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e, - 0x12, 0x2b, 0xff, 0x02, - 0x00, 0x10, 0x01, 0x08, 0x1f, 0xfe, 0xe0, 0x04, 0x2b, 0x01, 0x08, 0x1f, - 0x22, 0x30, 0x2e, 0xd5, - 0xfe, 0x4c, 0x44, 0xfe, 0x4c, 0x12, 0x60, 0xfe, 0x44, 0x48, 0x13, 0x2c, - 0xfe, 0x4c, 0x54, 0x64, - 0xd3, 0x46, 0x76, 0x27, 0xfa, 0xef, 0xfe, 0x62, 0x13, 0x09, 0x04, 0x1d, - 0xfe, 0x2a, 0x13, 0x2f, - 0x07, 0x7e, 0xa5, 0xfe, 0x20, 0x10, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64, - 0xd3, 0xfa, 0xef, 0x86, - 0x09, 0x04, 0x1d, 0xfe, 0x08, 0x13, 0x2f, 0x07, 0x7e, 0x6e, 0x09, 0x04, - 0x1d, 0xfe, 0x1c, 0x12, - 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, - 0x70, 0x0c, 0x02, 0x22, - 0x2b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90, 0xf9, 0x03, 0x14, 0x92, - 0x01, 0x33, 0x02, 0x29, - 0xfe, 0x42, 0x5b, 0x67, 0x1a, 0xfe, 0x46, 0x59, 0xf8, 0xf7, 0xfe, 0x87, - 0x80, 0xfe, 0x31, 0xe4, - 0x4f, 0x09, 0x04, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x1a, - 0xfe, 0x70, 0x12, 0x49, - 0x04, 0x06, 0xfe, 0x60, 0x13, 0x05, 0xfe, 0xa2, 0x00, 0x28, 0x16, 0xfe, - 0x80, 0x05, 0xfe, 0x31, - 0xe4, 0x6a, 0x49, 0x04, 0x0b, 0xfe, 0x4a, 0x13, 0x05, 0xfe, 0xa0, 0x00, - 0x28, 0xfe, 0x42, 0x12, - 0x5e, 0x01, 0x08, 0x25, 0x32, 0xf1, 0x01, 0x08, 0x26, 0xfe, 0x98, 0x05, - 0x11, 0xfe, 0xe3, 0x00, - 0x23, 0x49, 0xfe, 0x4a, 0xf0, 0xfe, 0x6a, 0x05, 0xfe, 0x49, 0xf0, 0xfe, - 0x64, 0x05, 0x83, 0x24, - 0xfe, 0x21, 0x00, 0xa1, 0x24, 0xfe, 0x22, 0x00, 0xa0, 0x24, 0x4c, 0xfe, - 0x09, 0x48, 0x01, 0x08, - 0x26, 0xfe, 0x98, 0x05, 0xfe, 0xe2, 0x08, 0x49, 0x04, 0xc5, 0x3b, 0x01, - 0x86, 0x24, 0x06, 0x12, - 0xcc, 0x37, 0xfe, 0x27, 0x01, 0x09, 0x04, 0x1d, 0xfe, 0x22, 0x12, 0x47, - 0x01, 0xa7, 0x14, 0x92, - 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c, - 0x02, 0x22, 0x05, 0xfe, - 0x9c, 0x00, 0x28, 0xfe, 0x3e, 0x12, 0x05, 0x50, 0x28, 0xfe, 0x36, 0x13, - 0x47, 0x01, 0xa7, 0x26, - 0xfe, 0x08, 0x06, 0x0a, 0x06, 0x49, 0x04, 0x19, 0xfe, 0x02, 0x12, 0x5f, - 0x01, 0xfe, 0xaa, 0x14, - 0x1f, 0xfe, 0xfe, 0x05, 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00, - 0x05, 0x50, 0xb4, 0x0c, - 0x50, 0x05, 0xc6, 0x28, 0xfe, 0x62, 0x12, 0x05, 0x3f, 0x28, 0xfe, 0x5a, - 0x13, 0x01, 0xfe, 0x14, - 0x18, 0x01, 0xfe, 0x66, 0x18, 0xfe, 0x43, 0x48, 0xb7, 0x19, 0x13, 0x6c, - 0xff, 0x02, 0x00, 0x57, - 0x48, 0x8b, 0x1c, 0x3d, 0x85, 0xb7, 0x69, 0x47, 0x01, 0xa7, 0x26, 0xfe, - 0x72, 0x06, 0x49, 0x04, - 0x1b, 0xdf, 0x89, 0x0a, 0x4d, 0x01, 0xfe, 0xd8, 0x14, 0x1f, 0xfe, 0x68, - 0x06, 0x11, 0x9a, 0x01, - 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x3f, 0xb4, 0x0c, 0x3f, 0x17, 0x06, - 0x01, 0xa7, 0xec, 0x72, - 0x70, 0x01, 0x6e, 0x87, 0x11, 0xfe, 0xe2, 0x00, 0x01, 0x08, 0x25, 0x32, - 0xfe, 0x0a, 0xf0, 0xfe, - 0xa6, 0x06, 0x8c, 0xfe, 0x5c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, 0x64, 0x07, - 0x8d, 0x81, 0x02, 0x22, - 0x09, 0x04, 0x0b, 0xfe, 0x2e, 0x12, 0x15, 0x1a, 0x01, 0x08, 0x15, 0x00, - 0x01, 0x08, 0x15, 0x00, - 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x15, - 0x00, 0x02, 0xfe, 0x32, - 0x08, 0x61, 0x04, 0x1b, 0xfe, 0x38, 0x12, 0x09, 0x04, 0x1b, 0x6e, 0x15, - 0xfe, 0x1b, 0x00, 0x01, - 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, - 0x08, 0x15, 0x06, 0x01, - 0x08, 0x15, 0x00, 0x02, 0xd9, 0x66, 0x4c, 0xfe, 0x3a, 0x55, 0x5f, 0xfe, - 0x9a, 0x81, 0x4b, 0x1d, - 0xba, 0xfe, 0x32, 0x07, 0x0a, 0x1d, 0xfe, 0x09, 0x6f, 0xaf, 0xfe, 0xca, - 0x45, 0xfe, 0x32, 0x12, - 0x62, 0x2c, 0x85, 0x66, 0x7b, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0, - 0xfe, 0x32, 0x07, 0x8d, - 0x81, 0x8c, 0xfe, 0x5c, 0x07, 0x02, 0x22, 0x01, 0x43, 0x02, 0xfe, 0x8a, - 0x06, 0x15, 0x19, 0x02, - 0xfe, 0x8a, 0x06, 0xfe, 0x9c, 0xf7, 0xd4, 0xfe, 0x2c, 0x90, 0xfe, 0xae, - 0x90, 0x77, 0xfe, 0xca, - 0x07, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x4a, 0x6a, 0x35, 0x1e, 0x20, 0x07, - 0x10, 0xfe, 0x0e, 0x12, - 0x74, 0xfe, 0x80, 0x80, 0x37, 0x20, 0x63, 0x27, 0xfe, 0x06, 0x10, 0xfe, - 0x83, 0xe7, 0xc4, 0xa1, - 0xfe, 0x03, 0x40, 0x09, 0x4a, 0x4f, 0x35, 0x01, 0xa8, 0xad, 0xfe, 0x1f, - 0x40, 0x12, 0x58, 0x01, - 0xa5, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, - 0x51, 0x83, 0xfb, 0xfe, - 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90, - 0xfe, 0x40, 0x50, 0xfe, - 0xc2, 0x50, 0x0c, 0x39, 0x18, 0x3a, 0xfe, 0x4a, 0x10, 0x09, 0x04, 0x6a, - 0xfe, 0x2a, 0x12, 0xfe, - 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x04, 0x4f, - 0x85, 0x01, 0xa8, 0xfe, - 0x1f, 0x80, 0x12, 0x58, 0xfe, 0x44, 0x90, 0xfe, 0xc6, 0x90, 0x0c, 0x56, - 0x18, 0x57, 0xfb, 0xfe, - 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, - 0x0c, 0x39, 0x18, 0x3a, - 0x0c, 0x38, 0x18, 0x4e, 0x09, 0x4a, 0x19, 0x35, 0x2a, 0x13, 0xfe, 0x4e, - 0x11, 0x65, 0xfe, 0x48, - 0x08, 0xfe, 0x9e, 0xf0, 0xfe, 0x5c, 0x08, 0xb1, 0x16, 0x32, 0x2a, 0x73, - 0xdd, 0xb8, 0xfe, 0x80, - 0x08, 0xb9, 0xfe, 0x9e, 0x08, 0x8c, 0xfe, 0x74, 0x08, 0xfe, 0x06, 0xf0, - 0xfe, 0x7a, 0x08, 0x8d, - 0x81, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xc9, 0x10, 0x15, 0x19, 0xfe, 0xc9, - 0x10, 0x61, 0x04, 0x06, - 0xfe, 0x10, 0x12, 0x61, 0x04, 0x0b, 0x45, 0x09, 0x04, 0x0b, 0xfe, 0x68, - 0x12, 0xfe, 0x2e, 0x1c, - 0x02, 0xfe, 0x24, 0x0a, 0x61, 0x04, 0x06, 0x45, 0x61, 0x04, 0x0b, 0xfe, - 0x52, 0x12, 0xfe, 0x2c, - 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x1e, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0xbe, - 0x08, 0xfe, 0x8a, 0x10, - 0xaa, 0xfe, 0xf3, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0xca, 0x08, 0x02, 0xfe, - 0x24, 0x0a, 0xab, 0xfe, - 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0x9d, 0xe9, 0x1c, 0xfe, 0x00, 0xfe, 0xfe, - 0x1c, 0x12, 0xb5, 0xfe, - 0xd2, 0xf0, 0x9d, 0xfe, 0x76, 0x18, 0x1c, 0x1a, 0x16, 0x9d, 0x05, 0xcb, - 0x1c, 0x06, 0x16, 0x9d, - 0xb8, 0x6d, 0xb9, 0x6d, 0xaa, 0xab, 0xfe, 0xb1, 0x10, 0x70, 0x5e, 0x2b, - 0x14, 0x92, 0x01, 0x33, - 0x0f, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x5a, 0x0f, 0x7c, 0x02, 0x5a, - 0xfe, 0x74, 0x18, 0x1c, - 0xfe, 0x00, 0xf8, 0x16, 0x6d, 0x67, 0x1b, 0x01, 0xfe, 0x44, 0x0d, 0x3b, - 0x01, 0xe6, 0x1e, 0x27, - 0x74, 0x67, 0x1a, 0x02, 0x6d, 0x09, 0x04, 0x0b, 0x21, 0xfe, 0x06, 0x0a, - 0x09, 0x04, 0x6a, 0xfe, - 0x82, 0x12, 0x09, 0x04, 0x19, 0xfe, 0x66, 0x13, 0x1e, 0x58, 0xac, 0xfc, - 0xfe, 0x83, 0x80, 0xfe, - 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x63, - 0x27, 0xfe, 0x40, 0x59, - 0xfe, 0xc1, 0x59, 0x77, 0xd7, 0x05, 0x54, 0x31, 0x55, 0x0c, 0x7b, 0x18, - 0x7c, 0xbe, 0x54, 0xbf, - 0x55, 0x01, 0xa8, 0xad, 0x63, 0x27, 0x12, 0x58, 0xc0, 0x38, 0xc1, 0x4e, - 0x79, 0x56, 0x68, 0x57, - 0xf4, 0xf5, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05, 0xfa, 0x4e, 0x01, 0xa5, - 0xa2, 0x23, 0x0c, 0x7b, - 0x0c, 0x7c, 0x79, 0x56, 0x68, 0x57, 0xfe, 0x12, 0x10, 0x09, 0x04, 0x19, - 0x16, 0xd7, 0x79, 0x39, - 0x68, 0x3a, 0x09, 0x04, 0xfe, 0xf7, 0x00, 0x35, 0x05, 0x52, 0x31, 0x53, - 0xfe, 0x10, 0x58, 0xfe, - 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x02, 0x6d, 0x09, 0x04, - 0x19, 0x16, 0xd7, 0x09, - 0x04, 0xfe, 0xf7, 0x00, 0x35, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x5f, - 0xfe, 0x10, 0x90, 0xfe, - 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x2f, 0x07, 0x9b, 0x16, 0xfe, 0xc6, 0x08, - 0x11, 0x9b, 0x09, 0x04, - 0x0b, 0xfe, 0x14, 0x13, 0x05, 0x39, 0x31, 0x3a, 0x77, 0xfe, 0xc6, 0x08, - 0xfe, 0x0c, 0x58, 0xfe, - 0x8d, 0x58, 0x02, 0x6d, 0x23, 0x47, 0xfe, 0x19, 0x80, 0xde, 0x09, 0x04, - 0x0b, 0xfe, 0x1a, 0x12, - 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xe9, 0xb5, 0xfe, 0xd1, 0xf0, 0xd9, - 0x14, 0x7a, 0x01, 0x33, - 0x0f, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0xbe, 0x39, - 0xfe, 0xed, 0x19, 0xbf, - 0x3a, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xe9, 0x1c, 0xfe, 0x00, 0xff, - 0x34, 0xfe, 0x74, 0x10, - 0xb5, 0xfe, 0xd2, 0xf0, 0xfe, 0xb2, 0x0a, 0xfe, 0x76, 0x18, 0x1c, 0x1a, - 0x84, 0x05, 0xcb, 0x1c, - 0x06, 0xfe, 0x08, 0x13, 0x0f, 0xfe, 0x16, 0x00, 0x02, 0x5a, 0xfe, 0xd1, - 0xf0, 0xfe, 0xc4, 0x0a, - 0x14, 0x7a, 0x01, 0x33, 0x0f, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe, - 0xce, 0xf0, 0xfe, 0xca, - 0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x0f, 0xfe, - 0x22, 0x00, 0x02, 0x5a, - 0xfe, 0xcb, 0xf0, 0xfe, 0xe2, 0x0a, 0x0f, 0xfe, 0x24, 0x00, 0x02, 0x5a, - 0xfe, 0xd0, 0xf0, 0xfe, - 0xec, 0x0a, 0x0f, 0x93, 0xdc, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x0f, - 0x4c, 0xfe, 0x10, 0x10, - 0xfe, 0xcc, 0xf0, 0xd9, 0x61, 0x04, 0x19, 0x3b, 0x0f, 0xfe, 0x12, 0x00, - 0x2a, 0x13, 0xfe, 0x4e, - 0x11, 0x65, 0xfe, 0x0c, 0x0b, 0xfe, 0x9e, 0xf0, 0xfe, 0x20, 0x0b, 0xb1, - 0x16, 0x32, 0x2a, 0x73, - 0xdd, 0xb8, 0x22, 0xb9, 0x22, 0x2a, 0xec, 0x65, 0xfe, 0x2c, 0x0b, 0x25, - 0x32, 0x8c, 0xfe, 0x48, - 0x0b, 0x8d, 0x81, 0xb8, 0xd4, 0xb9, 0xd4, 0x02, 0x22, 0x01, 0x43, 0xfe, - 0xdb, 0x10, 0x11, 0xfe, - 0xe8, 0x00, 0xaa, 0xab, 0x70, 0xbc, 0x7d, 0xbd, 0x7f, 0xfe, 0x89, 0xf0, - 0x22, 0x30, 0x2e, 0xd8, - 0xbc, 0x7d, 0xbd, 0x7f, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd6, 0xb1, - 0x45, 0x0f, 0xfe, 0x42, - 0x00, 0x02, 0x5a, 0x78, 0x06, 0xfe, 0x81, 0x49, 0x16, 0xfe, 0x38, 0x0c, - 0x09, 0x04, 0x0b, 0xfe, - 0x44, 0x13, 0x0f, 0x00, 0x4b, 0x0b, 0xfe, 0x54, 0x12, 0x4b, 0xfe, 0x28, - 0x00, 0x21, 0xfe, 0xa6, - 0x0c, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x3e, 0xfe, 0x28, 0x00, - 0xfe, 0xe2, 0x10, 0x01, - 0xe7, 0x01, 0xe8, 0x0a, 0x99, 0x01, 0xfe, 0x32, 0x0e, 0x59, 0x11, 0x2d, - 0x01, 0x6f, 0x02, 0x29, - 0x0f, 0xfe, 0x44, 0x00, 0x4b, 0x0b, 0xdf, 0x3e, 0x0b, 0xfe, 0xb4, 0x10, - 0x01, 0x86, 0x3e, 0x0b, - 0xfe, 0xaa, 0x10, 0x01, 0x86, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xa3, - 0x3e, 0x0b, 0x0f, 0xfe, - 0x43, 0x00, 0xfe, 0x96, 0x10, 0x09, 0x4a, 0x0b, 0x35, 0x01, 0xe7, 0x01, - 0xe8, 0x59, 0x11, 0x2d, - 0x01, 0x6f, 0x67, 0x0b, 0x59, 0x3c, 0x8a, 0x02, 0xfe, 0x2a, 0x03, 0x09, - 0x04, 0x0b, 0x84, 0x3e, - 0x0b, 0x0f, 0x00, 0xfe, 0x5c, 0x10, 0x61, 0x04, 0x1b, 0xfe, 0x58, 0x12, - 0x09, 0x04, 0x1b, 0xfe, - 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x5c, 0x0c, 0xfe, - 0x1c, 0x1c, 0xfe, 0x9d, - 0xf0, 0xfe, 0x62, 0x0c, 0x09, 0x4a, 0x1b, 0x35, 0xfe, 0xa9, 0x10, 0x0f, - 0xfe, 0x15, 0x00, 0xfe, - 0x04, 0xe6, 0x0b, 0x5f, 0x5c, 0x0f, 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, - 0x0f, 0xfe, 0x47, 0x00, - 0xa1, 0x0f, 0xfe, 0x41, 0x00, 0xa0, 0x0f, 0xfe, 0x24, 0x00, 0x87, 0xaa, - 0xab, 0x70, 0x05, 0x6b, - 0x28, 0x21, 0xd1, 0x5f, 0xfe, 0x04, 0xe6, 0x1b, 0xfe, 0x9d, 0x41, 0xfe, - 0x1c, 0x42, 0x59, 0x01, - 0xda, 0x02, 0x29, 0xea, 0x14, 0x0b, 0x37, 0x95, 0xa9, 0x14, 0xfe, 0x31, - 0x00, 0x37, 0x97, 0x01, - 0xfe, 0x54, 0x0f, 0x02, 0xd0, 0x3c, 0xfe, 0x06, 0xec, 0xc9, 0xee, 0x3e, - 0x1d, 0xfe, 0xce, 0x45, - 0x34, 0x3c, 0xfe, 0x06, 0xea, 0xc9, 0xfe, 0x47, 0x4b, 0x89, 0xfe, 0x75, - 0x57, 0x05, 0x51, 0xfe, - 0x98, 0x56, 0xfe, 0x38, 0x12, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x44, 0x48, - 0x46, 0x09, 0x04, 0x1d, - 0xfe, 0x1a, 0x13, 0x0a, 0x40, 0x01, 0x0e, 0x47, 0xfe, 0x41, 0x58, 0x0a, - 0x99, 0x01, 0x0e, 0xfe, - 0x49, 0x54, 0x8e, 0xfe, 0x2a, 0x0d, 0x02, 0xfe, 0x2a, 0x03, 0x0a, 0x51, - 0xfe, 0xee, 0x14, 0xee, - 0x3e, 0x1d, 0xfe, 0xce, 0x45, 0x34, 0x3c, 0xfe, 0xce, 0x47, 0xfe, 0xad, - 0x13, 0x02, 0x29, 0x1e, - 0x20, 0x07, 0x10, 0xfe, 0x9e, 0x12, 0x23, 0x12, 0x4d, 0x12, 0x94, 0x12, - 0xce, 0x1e, 0x2d, 0x47, - 0x37, 0x2d, 0xb1, 0xe0, 0xfe, 0xbc, 0xf0, 0xfe, 0xec, 0x0d, 0x13, 0x06, - 0x12, 0x4d, 0x01, 0xfe, - 0xe2, 0x15, 0x05, 0xfe, 0x38, 0x01, 0x31, 0xfe, 0x3a, 0x01, 0x77, 0xfe, - 0xf0, 0x0d, 0xfe, 0x02, - 0xec, 0xce, 0x62, 0x00, 0x5d, 0xfe, 0x04, 0xec, 0x20, 0x46, 0xfe, 0x05, - 0xf6, 0xfe, 0x34, 0x01, - 0x01, 0xfe, 0x52, 0x16, 0xfb, 0xfe, 0x48, 0xf4, 0x0d, 0xfe, 0x18, 0x13, - 0xaf, 0xfe, 0x02, 0xea, - 0xce, 0x62, 0x7a, 0xfe, 0xc5, 0x13, 0x14, 0x1b, 0x37, 0x95, 0xa9, 0x5c, - 0x05, 0xfe, 0x38, 0x01, - 0x1c, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x05, 0xfe, 0x3a, 0x01, - 0x0c, 0xfe, 0x62, 0x01, - 0x3d, 0x12, 0x20, 0x24, 0x06, 0x12, 0x2d, 0x11, 0x2d, 0x8a, 0x13, 0x06, - 0x03, 0x23, 0x03, 0x1e, - 0x4d, 0xfe, 0xf7, 0x12, 0x1e, 0x94, 0xac, 0x12, 0x94, 0x07, 0x7a, 0xfe, - 0x71, 0x13, 0xfe, 0x24, - 0x1c, 0x14, 0x1a, 0x37, 0x95, 0xa9, 0xfe, 0xd9, 0x10, 0xb6, 0xfe, 0x03, - 0xdc, 0xfe, 0x73, 0x57, - 0xfe, 0x80, 0x5d, 0x03, 0xb6, 0xfe, 0x03, 0xdc, 0xfe, 0x5b, 0x57, 0xfe, - 0x80, 0x5d, 0x03, 0xfe, - 0x03, 0x57, 0xb6, 0x23, 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0xb6, - 0x75, 0x03, 0x09, 0x04, - 0x4c, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13, - 0xfe, 0x1e, 0x80, 0xe1, - 0xfe, 0x1d, 0x80, 0xa4, 0xfe, 0x0c, 0x90, 0xfe, 0x0e, 0x13, 0xfe, 0x0e, - 0x90, 0xa3, 0xfe, 0x3c, - 0x90, 0xfe, 0x30, 0xf4, 0x0b, 0xfe, 0x3c, 0x50, 0xa0, 0x01, 0xfe, 0x82, - 0x16, 0x2f, 0x07, 0x2d, - 0xe0, 0x01, 0xfe, 0xbc, 0x15, 0x09, 0x04, 0x1d, 0x45, 0x01, 0xe7, 0x01, - 0xe8, 0x11, 0xfe, 0xe9, - 0x00, 0x09, 0x04, 0x4c, 0xfe, 0x2c, 0x13, 0x01, 0xfe, 0x14, 0x16, 0xfe, - 0x1e, 0x1c, 0xfe, 0x14, - 0x90, 0xfe, 0x96, 0x90, 0x0c, 0xfe, 0x64, 0x01, 0x18, 0xfe, 0x66, 0x01, - 0x09, 0x04, 0x4f, 0xfe, - 0x12, 0x12, 0xfe, 0x03, 0x80, 0x74, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80, - 0x40, 0x12, 0x20, 0x63, - 0x27, 0x11, 0xc8, 0x59, 0x1e, 0x20, 0xed, 0x76, 0x20, 0x03, 0xfe, 0x08, - 0x1c, 0x05, 0xfe, 0xac, - 0x00, 0xfe, 0x06, 0x58, 0x05, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x05, - 0xfe, 0xb0, 0x00, 0xfe, - 0x08, 0x58, 0x05, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, - 0x24, 0x69, 0x12, 0xc9, - 0x23, 0x0c, 0x50, 0x0c, 0x3f, 0x13, 0x40, 0x48, 0x5f, 0x17, 0x1d, 0xfe, - 0x90, 0x4d, 0xfe, 0x91, - 0x54, 0x21, 0xfe, 0x08, 0x0f, 0x3e, 0x10, 0x13, 0x42, 0x48, 0x17, 0x4c, - 0xfe, 0x90, 0x4d, 0xfe, - 0x91, 0x54, 0x21, 0xfe, 0x1e, 0x0f, 0x24, 0x10, 0x12, 0x20, 0x78, 0x2c, - 0x46, 0x1e, 0x20, 0xed, - 0x76, 0x20, 0x11, 0xc8, 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x32, 0x0f, 0xea, - 0x70, 0xfe, 0x14, 0x1c, - 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x03, 0x3c, 0xfe, 0x0c, 0x14, 0xee, - 0xfe, 0x07, 0xe6, 0x1d, - 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x86, 0x78, 0x2c, 0x46, - 0xfa, 0xef, 0xfe, 0x42, - 0x13, 0x2f, 0x07, 0x2d, 0xfe, 0x34, 0x13, 0x0a, 0x42, 0x01, 0x0e, 0xb0, - 0xfe, 0x36, 0x12, 0xf0, - 0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13, - 0x3d, 0x75, 0x07, 0x10, - 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x6f, 0xfe, 0x0e, - 0x10, 0x07, 0x7e, 0x45, - 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x6c, 0x0f, 0x03, 0xfe, 0x44, 0x58, 0x74, - 0xfe, 0x01, 0xec, 0x97, - 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1b, 0x76, - 0x27, 0x01, 0xda, 0xfe, - 0xdd, 0x10, 0x2a, 0xbc, 0x7d, 0xbd, 0x7f, 0x30, 0x2e, 0xd5, 0x07, 0x1b, - 0xfe, 0x48, 0x12, 0x07, - 0x0b, 0xfe, 0x56, 0x12, 0x07, 0x1a, 0xfe, 0x30, 0x12, 0x07, 0xc2, 0x16, - 0xfe, 0x3e, 0x11, 0x07, - 0xfe, 0x23, 0x00, 0x16, 0xfe, 0x4a, 0x11, 0x07, 0x06, 0x16, 0xfe, 0xa8, - 0x11, 0x07, 0x19, 0xfe, - 0x12, 0x12, 0x07, 0x00, 0x16, 0x22, 0x14, 0xc2, 0x01, 0x33, 0x9f, 0x2b, - 0x01, 0x08, 0x8c, 0x43, - 0x03, 0x2b, 0xfe, 0x62, 0x08, 0x0a, 0xca, 0x01, 0xfe, 0x32, 0x0e, 0x11, - 0x7e, 0x02, 0x29, 0x2b, - 0x2f, 0x07, 0x9b, 0xfe, 0xd9, 0x13, 0x79, 0x39, 0x68, 0x3a, 0x77, 0xfe, - 0xfc, 0x10, 0x09, 0x04, - 0x6a, 0xfe, 0x72, 0x12, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x8e, 0xfe, - 0xc6, 0x10, 0x1e, 0x58, - 0xfe, 0x26, 0x13, 0x05, 0x7b, 0x31, 0x7c, 0x77, 0xfe, 0x82, 0x0c, 0x0c, - 0x54, 0x18, 0x55, 0x23, - 0x0c, 0x7b, 0x0c, 0x7c, 0x01, 0xa8, 0x24, 0x69, 0x73, 0x12, 0x58, 0x01, - 0xa5, 0xc0, 0x38, 0xc1, - 0x4e, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x38, 0xfe, - 0x05, 0xfa, 0x4e, 0xfe, - 0x91, 0x10, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, - 0x0c, 0x56, 0x18, 0x57, - 0x83, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x05, 0x52, 0x31, 0x53, 0xfe, - 0x00, 0x56, 0xfe, 0xa1, - 0x56, 0x0c, 0x52, 0x18, 0x53, 0x09, 0x04, 0x6a, 0xfe, 0x1e, 0x12, 0x1e, - 0x58, 0xfe, 0x1f, 0x40, - 0x05, 0x54, 0x31, 0x55, 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x05, 0x56, - 0x31, 0x57, 0xfe, 0x44, - 0x50, 0xfe, 0xc6, 0x50, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x08, 0x50, 0xfe, - 0x8a, 0x50, 0x05, 0x39, - 0x31, 0x3a, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x5c, 0x24, 0x06, - 0x12, 0xcd, 0x02, 0x5b, - 0x2b, 0x01, 0x08, 0x1f, 0x44, 0x30, 0x2e, 0xd5, 0x07, 0x06, 0x21, 0x44, - 0x2f, 0x07, 0x9b, 0x21, - 0x5b, 0x01, 0x6e, 0x1c, 0x3d, 0x16, 0x44, 0x09, 0x04, 0x0b, 0xe2, 0x79, - 0x39, 0x68, 0x3a, 0xfe, - 0x0a, 0x55, 0x34, 0xfe, 0x8b, 0x55, 0xbe, 0x39, 0xbf, 0x3a, 0xfe, 0x0c, - 0x51, 0xfe, 0x8e, 0x51, - 0x02, 0x5b, 0xfe, 0x19, 0x81, 0xaf, 0xfe, 0x19, 0x41, 0x02, 0x5b, 0x2b, - 0x01, 0x08, 0x25, 0x32, - 0x1f, 0xa2, 0x30, 0x2e, 0xd8, 0x4b, 0x1a, 0xfe, 0xa6, 0x12, 0x4b, 0x0b, - 0x3b, 0x02, 0x44, 0x01, - 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, 0xd6, 0x07, 0x1a, 0x21, 0x44, - 0x01, 0x08, 0x1f, 0xa2, - 0x30, 0x2e, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x60, 0x05, 0xfe, 0x9c, - 0x00, 0x28, 0x84, 0x49, - 0x04, 0x19, 0x34, 0x9f, 0xfe, 0xbb, 0x45, 0x4b, 0x00, 0x45, 0x3e, 0x06, - 0x78, 0x3d, 0xfe, 0xda, - 0x14, 0x01, 0x6e, 0x87, 0xfe, 0x4b, 0x45, 0xe2, 0x2f, 0x07, 0x9a, 0xe1, - 0x05, 0xc6, 0x28, 0x84, - 0x05, 0x3f, 0x28, 0x34, 0x5e, 0x02, 0x5b, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, - 0x14, 0xfe, 0x03, 0x17, - 0x05, 0x50, 0xb4, 0x0c, 0x50, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, - 0xfe, 0xaa, 0x14, 0x02, - 0x5c, 0x01, 0x08, 0x25, 0x32, 0x1f, 0x44, 0x30, 0x2e, 0xd6, 0x07, 0x06, - 0x21, 0x44, 0x01, 0xfe, - 0x8e, 0x13, 0xfe, 0x42, 0x58, 0xfe, 0x82, 0x14, 0xfe, 0xa4, 0x14, 0x87, - 0xfe, 0x4a, 0xf4, 0x0b, - 0x16, 0x44, 0xfe, 0x4a, 0xf4, 0x06, 0xfe, 0x0c, 0x12, 0x2f, 0x07, 0x9a, - 0x85, 0x02, 0x5b, 0x05, - 0x3f, 0xb4, 0x0c, 0x3f, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe, - 0xd8, 0x14, 0x02, 0x5c, - 0x13, 0x06, 0x65, 0xfe, 0xca, 0x12, 0x26, 0xfe, 0xe0, 0x12, 0x72, 0xf1, - 0x01, 0x08, 0x23, 0x72, - 0x03, 0x8f, 0xfe, 0xdc, 0x12, 0x25, 0xfe, 0xdc, 0x12, 0x1f, 0xfe, 0xca, - 0x12, 0x5e, 0x2b, 0x01, - 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, - 0x1c, 0xfe, 0xff, 0x7f, - 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, - 0x57, 0x48, 0x8b, 0x1c, - 0x3d, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, - 0x00, 0x57, 0x48, 0x8b, - 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0xfe, 0x0b, 0x58, - 0x03, 0x0a, 0x50, 0x01, - 0x82, 0x0a, 0x3f, 0x01, 0x82, 0x03, 0xfc, 0x1c, 0x10, 0xff, 0x03, 0x00, - 0x54, 0xfe, 0x00, 0xf4, - 0x19, 0x48, 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, - 0x03, 0x7c, 0x63, 0x27, - 0x0c, 0x52, 0x18, 0x53, 0xbe, 0x56, 0xbf, 0x57, 0x03, 0xfe, 0x62, 0x08, - 0xfe, 0x82, 0x4a, 0xfe, - 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x74, 0x03, 0x01, 0xfe, 0x14, 0x18, 0xfe, - 0x42, 0x48, 0x5f, 0x60, - 0x89, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14, 0x30, 0x2e, 0xd8, 0x01, 0x08, - 0x1f, 0xfe, 0xa2, 0x14, - 0x30, 0x2e, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x05, 0xc6, 0x28, 0xfe, - 0xcc, 0x12, 0x49, 0x04, - 0x1b, 0xfe, 0xc4, 0x13, 0x23, 0x62, 0x1b, 0xe2, 0x4b, 0xc3, 0x64, 0xfe, - 0xe8, 0x13, 0x3b, 0x13, - 0x06, 0x17, 0xc3, 0x78, 0xdb, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, - 0xa1, 0xff, 0x02, 0x83, - 0x55, 0x62, 0x1a, 0xa4, 0xbb, 0xfe, 0x30, 0x00, 0x8e, 0xe4, 0x17, 0x2c, - 0x13, 0x06, 0xfe, 0x56, - 0x10, 0x62, 0x0b, 0xe1, 0xbb, 0xfe, 0x64, 0x00, 0x8e, 0xe4, 0x0a, 0xfe, - 0x64, 0x00, 0x17, 0x93, - 0x13, 0x06, 0xfe, 0x28, 0x10, 0x62, 0x06, 0xfe, 0x60, 0x13, 0xbb, 0xfe, - 0xc8, 0x00, 0x8e, 0xe4, - 0x0a, 0xfe, 0xc8, 0x00, 0x17, 0x4d, 0x13, 0x06, 0x83, 0xbb, 0xfe, 0x90, - 0x01, 0xba, 0xfe, 0x4e, - 0x14, 0x89, 0xfe, 0x12, 0x10, 0xfe, 0x43, 0xf4, 0x94, 0xfe, 0x56, 0xf0, - 0xfe, 0x60, 0x14, 0xfe, - 0x04, 0xf4, 0x6c, 0xfe, 0x43, 0xf4, 0x93, 0xfe, 0xf3, 0x10, 0xf9, 0x01, - 0xfe, 0x22, 0x13, 0x1c, - 0x3d, 0xfe, 0x10, 0x13, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x69, 0xba, - 0xfe, 0x9c, 0x14, 0xb7, - 0x69, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x19, 0xba, - 0xfe, 0x9c, 0x14, 0xb7, - 0x19, 0x83, 0x60, 0x23, 0xfe, 0x4d, 0xf4, 0x00, 0xdf, 0x89, 0x13, 0x06, - 0xfe, 0xb4, 0x56, 0xfe, - 0xc3, 0x58, 0x03, 0x60, 0x13, 0x0b, 0x03, 0x15, 0x06, 0x01, 0x08, 0x26, - 0xe5, 0x15, 0x0b, 0x01, - 0x08, 0x26, 0xe5, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xe5, 0x72, 0xfe, 0x89, - 0x49, 0x01, 0x08, 0x03, - 0x15, 0x06, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xa6, - 0x15, 0x06, 0x01, 0x08, - 0x26, 0xa6, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x26, 0xa6, 0x72, 0xfe, 0x89, - 0x4a, 0x01, 0x08, 0x03, - 0x60, 0x03, 0x1e, 0xcc, 0x07, 0x06, 0xfe, 0x44, 0x13, 0xad, 0x12, 0xcc, - 0xfe, 0x49, 0xf4, 0x00, - 0x3b, 0x72, 0x9f, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01, - 0x08, 0x2f, 0x07, 0xfe, - 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0x5a, 0x15, 0x23, 0x12, 0xcd, - 0x01, 0x43, 0x1e, 0xcd, - 0x07, 0x06, 0x45, 0x09, 0x4a, 0x06, 0x35, 0x03, 0x0a, 0x42, 0x01, 0x0e, - 0xed, 0x88, 0x07, 0x10, - 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, - 0x80, 0x01, 0x0e, 0x88, - 0xfe, 0x80, 0xe7, 0x10, 0x07, 0x10, 0x84, 0xfe, 0x45, 0x58, 0x01, 0xe3, - 0x88, 0x03, 0x0a, 0x42, - 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x42, 0x01, 0x0e, - 0xfe, 0x80, 0x80, 0xf2, - 0xfe, 0x49, 0xe4, 0x10, 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x0a, 0x51, - 0x01, 0x82, 0x03, 0x17, - 0x10, 0x71, 0x66, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, - 0xfe, 0x24, 0x1c, 0xfe, - 0x1d, 0xf7, 0x1d, 0x90, 0xfe, 0xf6, 0x15, 0x01, 0xfe, 0xfc, 0x16, 0xe0, - 0x91, 0x1d, 0x66, 0xfe, - 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x03, 0xae, 0x21, 0xfe, 0xe6, 0x15, 0xfe, - 0xda, 0x10, 0x17, 0x10, - 0x71, 0x05, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58, - 0x05, 0xfe, 0x66, 0x01, - 0xfe, 0x19, 0x58, 0x91, 0x19, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x06, - 0xfe, 0x3c, 0x50, 0x66, - 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x90, 0xfe, - 0x40, 0x16, 0xfe, 0xb6, - 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x18, 0x16, 0xfe, 0x9c, 0x10, 0x17, - 0x10, 0x71, 0xfe, 0x83, - 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x38, 0x90, - 0xfe, 0x62, 0x16, 0xfe, - 0x94, 0x14, 0xfe, 0x10, 0x13, 0x91, 0x38, 0x66, 0x1b, 0xfe, 0xaf, 0x19, - 0xfe, 0x98, 0xe7, 0x00, - 0x03, 0xae, 0x21, 0xfe, 0x56, 0x16, 0xfe, 0x6c, 0x10, 0x17, 0x10, 0x71, - 0xfe, 0x30, 0xbc, 0xfe, - 0xb2, 0xbc, 0x91, 0xc5, 0x66, 0x1b, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, - 0xc5, 0x90, 0xfe, 0x9a, - 0x16, 0xfe, 0x5c, 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x86, 0x16, 0xfe, - 0x42, 0x10, 0xfe, 0x02, - 0xf6, 0x10, 0x71, 0xfe, 0x18, 0xfe, 0x54, 0xfe, 0x19, 0xfe, 0x55, 0xfc, - 0xfe, 0x1d, 0xf7, 0x4f, - 0x90, 0xfe, 0xc0, 0x16, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0x91, 0x4f, - 0x47, 0xfe, 0x83, 0x58, - 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11, - 0xfe, 0xdd, 0x00, 0x63, - 0x27, 0x03, 0x63, 0x27, 0xfe, 0x12, 0x45, 0x21, 0xfe, 0xb0, 0x16, 0x14, - 0x06, 0x37, 0x95, 0xa9, - 0x02, 0x29, 0xfe, 0x39, 0xf0, 0xfe, 0x04, 0x17, 0x23, 0x03, 0xfe, 0x7e, - 0x18, 0x1c, 0x1a, 0x5d, - 0x13, 0x0d, 0x03, 0x71, 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0xef, 0x12, 0xfe, - 0xe1, 0x10, 0x78, 0x2c, - 0x46, 0x2f, 0x07, 0x2d, 0xfe, 0x3c, 0x13, 0xfe, 0x82, 0x14, 0xfe, 0x42, - 0x13, 0x3c, 0x8a, 0x0a, - 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x3e, 0x12, 0xf0, 0xfe, 0x45, 0x48, 0x01, - 0xe3, 0xfe, 0x00, 0xcc, - 0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10, 0xa3, 0x0a, 0x80, 0x01, - 0x0e, 0xf2, 0x01, 0x6f, - 0xfe, 0x16, 0x10, 0x07, 0x7e, 0x85, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12, - 0xf6, 0xfe, 0xd6, 0xf0, - 0xfe, 0x24, 0x17, 0x17, 0x0b, 0x03, 0xfe, 0x9c, 0xe7, 0x0b, 0x0f, 0xfe, - 0x15, 0x00, 0x59, 0x76, - 0x27, 0x01, 0xda, 0x17, 0x06, 0x03, 0x3c, 0x8a, 0x09, 0x4a, 0x1d, 0x35, - 0x11, 0x2d, 0x01, 0x6f, - 0x17, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x79, 0xc7, 0x68, - 0xc8, 0xfe, 0x48, 0x55, - 0x34, 0xfe, 0xc9, 0x55, 0x03, 0x1e, 0x98, 0x73, 0x12, 0x98, 0x03, 0x0a, - 0x99, 0x01, 0x0e, 0xf0, - 0x0a, 0x40, 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x16, 0xfe, 0xf0, 0x17, 0x73, - 0x75, 0x03, 0x0a, 0x42, - 0x01, 0x0e, 0x07, 0x10, 0x45, 0x0a, 0x51, 0x01, 0x9e, 0x0a, 0x40, 0x01, - 0x0e, 0x73, 0x75, 0x03, - 0xfe, 0x4e, 0xe4, 0x1a, 0x64, 0xfe, 0x24, 0x18, 0x05, 0xfe, 0x90, 0x00, - 0xfe, 0x3a, 0x45, 0x5b, - 0xfe, 0x4e, 0xe4, 0xc2, 0x64, 0xfe, 0x36, 0x18, 0x05, 0xfe, 0x92, 0x00, - 0xfe, 0x02, 0xe6, 0x1b, - 0xdc, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x64, 0xfe, 0x48, 0x18, 0x05, - 0xfe, 0x94, 0x00, 0xfe, - 0x02, 0xe6, 0x19, 0xfe, 0x08, 0x10, 0x05, 0xfe, 0x96, 0x00, 0xfe, 0x02, - 0xe6, 0x2c, 0xfe, 0x4e, - 0x45, 0xfe, 0x0c, 0x12, 0xaf, 0xff, 0x04, 0x68, 0x54, 0xde, 0x1c, 0x69, - 0x03, 0x07, 0x7a, 0xfe, - 0x5a, 0xf0, 0xfe, 0x74, 0x18, 0x24, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10, - 0x07, 0x1b, 0xfe, 0x5a, - 0xf0, 0xfe, 0x82, 0x18, 0x24, 0xc3, 0xfe, 0x26, 0x10, 0x07, 0x1a, 0x5d, - 0x24, 0x2c, 0xdc, 0x07, - 0x0b, 0x5d, 0x24, 0x93, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x5d, 0x24, 0x4d, - 0x9f, 0xad, 0x03, 0x14, - 0xfe, 0x09, 0x00, 0x01, 0x33, 0xfe, 0x04, 0xfe, 0x7d, 0x05, 0x7f, 0xf9, - 0x03, 0x25, 0xfe, 0xca, - 0x18, 0xfe, 0x14, 0xf0, 0x08, 0x65, 0xfe, 0xc6, 0x18, 0x03, 0xff, 0x1a, - 0x00, 0x00, -}; - -static unsigned short _adv_asc3550_size = sizeof(_adv_asc3550_buf); /* 0x13AD */ -static ADV_DCNT _adv_asc3550_chksum = 0x04D52DDDUL; /* Expanded little-endian checksum. */ - -/* Microcode buffer is kept after initialization for error recovery. */ -static unsigned char _adv_asc38C0800_buf[] = { - 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x16, 0x18, 0xe4, - 0x01, 0x00, 0x48, 0xe4, - 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0xce, 0x19, 0x00, 0xfa, 0xff, 0xff, - 0x1c, 0x0f, 0x00, 0xf6, - 0x9e, 0xe7, 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x01, 0xfa, 0x01, 0xe6, - 0x09, 0xe7, 0x55, 0xf0, - 0x01, 0xf6, 0x03, 0x00, 0x04, 0x00, 0x10, 0x00, 0x1e, 0xf0, 0x85, 0xf0, - 0x18, 0xf4, 0x08, 0x00, - 0xbc, 0x00, 0x38, 0x54, 0x00, 0xec, 0xd5, 0xf0, 0x82, 0x0d, 0x00, 0xe6, - 0x86, 0xf0, 0xb1, 0xf0, - 0x98, 0x57, 0x01, 0xfc, 0xb4, 0x00, 0xd4, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, - 0x3c, 0x00, 0xbb, 0x00, - 0x00, 0x10, 0xba, 0x19, 0x02, 0x80, 0x32, 0xf0, 0x7c, 0x0d, 0x02, 0x13, - 0xba, 0x13, 0x18, 0x40, - 0x00, 0x57, 0x01, 0xea, 0x02, 0xfc, 0x03, 0xfc, 0x3e, 0x00, 0x6c, 0x01, - 0x6e, 0x01, 0x74, 0x01, - 0x76, 0x01, 0xb9, 0x54, 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00, - 0xc0, 0x00, 0x01, 0x01, - 0x3e, 0x01, 0x7a, 0x01, 0xca, 0x08, 0xce, 0x10, 0x16, 0x11, 0x04, 0x12, - 0x08, 0x12, 0x02, 0x4a, - 0xbb, 0x55, 0x3c, 0x56, 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, - 0x5d, 0xf0, 0x02, 0xfa, - 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01, - 0x68, 0x01, 0x6a, 0x01, - 0x70, 0x01, 0x72, 0x01, 0x78, 0x01, 0x7c, 0x01, 0x62, 0x0a, 0x86, 0x0d, - 0x06, 0x13, 0x4c, 0x1c, - 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x0c, 0x00, - 0x0f, 0x00, 0x47, 0x00, - 0xbe, 0x00, 0x00, 0x01, 0x20, 0x11, 0x5c, 0x16, 0x32, 0x1c, 0x38, 0x1c, - 0x4e, 0x1c, 0x10, 0x44, - 0x00, 0x4c, 0x04, 0xea, 0x5c, 0xf0, 0xa7, 0xf0, 0x04, 0xf6, 0x03, 0xfa, - 0x05, 0x00, 0x34, 0x00, - 0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x4a, 0x0b, - 0x42, 0x0c, 0x12, 0x0f, - 0x0c, 0x10, 0x22, 0x11, 0x0a, 0x12, 0x04, 0x13, 0x30, 0x1c, 0x02, 0x48, - 0x00, 0x4e, 0x42, 0x54, - 0x44, 0x55, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0, - 0x59, 0xf0, 0xb8, 0xf0, - 0x4b, 0xf4, 0x06, 0xf7, 0x0e, 0xf7, 0x04, 0xfc, 0x05, 0xfc, 0x06, 0x00, - 0x19, 0x00, 0x33, 0x00, - 0x9b, 0x00, 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, - 0xe7, 0x00, 0xe2, 0x03, - 0x08, 0x0f, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, 0x0a, 0x13, 0x0c, 0x13, - 0x12, 0x13, 0x24, 0x14, - 0x34, 0x14, 0x04, 0x16, 0x08, 0x16, 0xa4, 0x17, 0x20, 0x1c, 0x34, 0x1c, - 0x36, 0x1c, 0x08, 0x44, - 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, - 0x3a, 0x55, 0x83, 0x55, - 0xe5, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0, - 0x0c, 0xf0, 0x04, 0xf8, - 0x05, 0xf8, 0x07, 0x00, 0x0a, 0x00, 0x1c, 0x00, 0x1e, 0x00, 0x9e, 0x00, - 0xa8, 0x00, 0xaa, 0x00, - 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7e, 0x01, - 0xc4, 0x01, 0xc6, 0x01, - 0x80, 0x02, 0x5e, 0x03, 0xee, 0x04, 0x9a, 0x06, 0xf8, 0x07, 0x62, 0x08, - 0x68, 0x08, 0x69, 0x08, - 0xd6, 0x08, 0xe9, 0x09, 0xfa, 0x0b, 0x2e, 0x0f, 0x12, 0x10, 0x1a, 0x10, - 0xed, 0x10, 0xf1, 0x10, - 0x2a, 0x11, 0x06, 0x12, 0x0c, 0x12, 0x3e, 0x12, 0x10, 0x13, 0x16, 0x13, - 0x1e, 0x13, 0x46, 0x14, - 0x76, 0x14, 0x82, 0x14, 0x36, 0x15, 0xca, 0x15, 0x6b, 0x18, 0xbe, 0x18, - 0xca, 0x18, 0xe6, 0x19, - 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0xfe, 0x9c, - 0xf0, 0x2b, 0x02, 0xfe, - 0xac, 0x0d, 0xff, 0x10, 0x00, 0x00, 0xd7, 0xfe, 0xe8, 0x19, 0x00, 0xd6, - 0xfe, 0x84, 0x01, 0xff, - 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00, - 0x00, 0xfe, 0x57, 0x24, - 0x00, 0xfe, 0x4c, 0x00, 0x5b, 0xff, 0x04, 0x00, 0x00, 0x11, 0xff, 0x09, - 0x00, 0x00, 0xff, 0x08, - 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, - 0xff, 0xff, 0xff, 0x11, - 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00, - 0xfe, 0x04, 0xf7, 0xd6, - 0x2c, 0x99, 0x0a, 0x01, 0xfe, 0xc2, 0x0f, 0xfe, 0x04, 0xf7, 0xd6, 0x99, - 0x0a, 0x42, 0x2c, 0xfe, - 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x91, 0xf0, - 0xfe, 0xf4, 0x01, 0xfe, - 0x90, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, 0x8f, 0xf0, 0xa7, 0x03, 0x5d, 0x4d, - 0x02, 0xfe, 0xc8, 0x0d, - 0x01, 0xfe, 0x38, 0x0e, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28, - 0x1c, 0x03, 0xfe, 0xa6, - 0x00, 0xfe, 0xd3, 0x12, 0x41, 0x14, 0xfe, 0xa6, 0x00, 0xc2, 0xfe, 0x48, - 0xf0, 0xfe, 0x8a, 0x02, - 0xfe, 0x49, 0xf0, 0xfe, 0xa4, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc2, 0x02, - 0xfe, 0x46, 0xf0, 0xfe, - 0x54, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x5a, 0x02, 0xfe, 0x43, 0xf0, 0xfe, - 0x48, 0x02, 0xfe, 0x44, - 0xf0, 0xfe, 0x4c, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x50, 0x02, 0x18, 0x0a, - 0xaa, 0x18, 0x06, 0x14, - 0xa1, 0x02, 0x2b, 0xfe, 0x00, 0x1c, 0xe7, 0xfe, 0x02, 0x1c, 0xe6, 0xfe, - 0x1e, 0x1c, 0xfe, 0xe9, - 0x10, 0x01, 0xfe, 0x18, 0x18, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xce, - 0x09, 0x70, 0x01, 0xa8, - 0x02, 0x2b, 0x15, 0x59, 0x39, 0xa2, 0x01, 0xfe, 0x58, 0x10, 0x09, 0x70, - 0x01, 0x87, 0xfe, 0xbd, - 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe, - 0x58, 0x1c, 0x18, 0x06, - 0x14, 0xa1, 0x2c, 0x1c, 0x2b, 0xfe, 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0x23, - 0xfe, 0x98, 0x02, 0xfe, - 0x5a, 0x1c, 0xf8, 0xfe, 0x14, 0x1c, 0x15, 0xfe, 0x30, 0x00, 0x39, 0xa2, - 0x01, 0xfe, 0x48, 0x10, - 0x18, 0x06, 0x14, 0xa1, 0x02, 0xd7, 0x22, 0x20, 0x07, 0x11, 0x35, 0xfe, - 0x69, 0x10, 0x18, 0x06, - 0x14, 0xa1, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0x43, 0x13, 0x20, 0xfe, 0x05, - 0xf6, 0xce, 0x01, 0xfe, - 0x4a, 0x17, 0x08, 0x54, 0x58, 0x37, 0x12, 0x2f, 0x42, 0x92, 0x01, 0xfe, - 0x82, 0x16, 0x02, 0x2b, - 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x01, 0x73, 0xfe, 0x18, 0x10, - 0xfe, 0x41, 0x58, 0x09, - 0xa4, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x6b, 0xfe, 0x10, 0x03, 0x01, 0xfe, - 0x82, 0x16, 0x02, 0x2b, - 0x2c, 0x4f, 0xfe, 0x02, 0xe8, 0x2a, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, - 0xfe, 0x77, 0x57, 0xfe, - 0x27, 0xf0, 0xfe, 0xe0, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xa7, - 0xfe, 0x40, 0x1c, 0x1c, - 0xd9, 0xfe, 0x26, 0xf0, 0xfe, 0x5a, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x48, - 0x03, 0xfe, 0x11, 0xf0, - 0xa7, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x68, 0x03, 0xf9, 0x10, - 0xfe, 0x11, 0x00, 0x02, - 0x65, 0x2c, 0xfe, 0x48, 0x1c, 0xf9, 0x08, 0x05, 0x1b, 0xfe, 0x18, 0x13, - 0x21, 0x22, 0xa3, 0xb7, - 0x13, 0xa3, 0x09, 0x46, 0x01, 0x0e, 0xb7, 0x78, 0x01, 0xfe, 0xb4, 0x16, - 0x12, 0xd1, 0x1c, 0xd9, - 0xfe, 0x01, 0xf0, 0xd9, 0xfe, 0x82, 0xf0, 0xfe, 0x96, 0x03, 0xfa, 0x12, - 0xfe, 0xe4, 0x00, 0x27, - 0xfe, 0xa8, 0x03, 0x1c, 0x34, 0x1d, 0xfe, 0xb8, 0x03, 0x01, 0x4b, 0xfe, - 0x06, 0xf0, 0xfe, 0xc8, - 0x03, 0x95, 0x86, 0xfe, 0x0a, 0xf0, 0xfe, 0x8a, 0x06, 0x02, 0x24, 0x03, - 0x70, 0x28, 0x17, 0xfe, - 0xfa, 0x04, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, 0xd8, - 0xf9, 0x2c, 0x99, 0x19, - 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c, - 0x74, 0x01, 0xaf, 0x8c, - 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x17, 0xda, 0x09, 0xd1, 0x01, 0x0e, - 0x8d, 0x51, 0x64, 0x79, - 0x2a, 0x03, 0x70, 0x28, 0xfe, 0x10, 0x12, 0x15, 0x6d, 0x01, 0x36, 0x7b, - 0xfe, 0x6a, 0x02, 0x02, - 0xd8, 0xc7, 0x81, 0xc8, 0x83, 0x1c, 0x24, 0x27, 0xfe, 0x40, 0x04, 0x1d, - 0xfe, 0x3c, 0x04, 0x3b, - 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e, 0x12, 0x2d, 0xff, 0x02, - 0x00, 0x10, 0x01, 0x0b, - 0x1d, 0xfe, 0xe4, 0x04, 0x2d, 0x01, 0x0b, 0x1d, 0x24, 0x33, 0x31, 0xde, - 0xfe, 0x4c, 0x44, 0xfe, - 0x4c, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b, - 0xda, 0x4f, 0x79, 0x2a, - 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x62, 0x13, 0x08, 0x05, 0x1b, - 0xfe, 0x2a, 0x13, 0x32, - 0x07, 0x82, 0xfe, 0x52, 0x13, 0xfe, 0x20, 0x10, 0x0f, 0x6f, 0xfe, 0x4c, - 0x54, 0x6b, 0xda, 0xfe, - 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x40, 0x13, 0x08, 0x05, 0x1b, 0xfe, - 0x08, 0x13, 0x32, 0x07, - 0x82, 0xfe, 0x30, 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x1c, 0x12, 0x15, 0x9d, - 0x08, 0x05, 0x06, 0x4d, - 0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36, 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, - 0x2d, 0x12, 0xfe, 0xe6, - 0x00, 0xfe, 0x1c, 0x90, 0xfe, 0x40, 0x5c, 0x04, 0x15, 0x9d, 0x01, 0x36, - 0x02, 0x2b, 0xfe, 0x42, - 0x5b, 0x99, 0x19, 0xfe, 0x46, 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, - 0xfe, 0x87, 0x80, 0xfe, - 0x31, 0xe4, 0x5b, 0x08, 0x05, 0x0a, 0xfe, 0x84, 0x13, 0xfe, 0x20, 0x80, - 0x07, 0x19, 0xfe, 0x7c, - 0x12, 0x53, 0x05, 0x06, 0xfe, 0x6c, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x28, - 0x17, 0xfe, 0x90, 0x05, - 0xfe, 0x31, 0xe4, 0x5a, 0x53, 0x05, 0x0a, 0xfe, 0x56, 0x13, 0x03, 0xfe, - 0xa0, 0x00, 0x28, 0xfe, - 0x4e, 0x12, 0x67, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x48, 0x05, 0x1c, - 0x34, 0xfe, 0x89, 0x48, - 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x56, 0x05, 0x26, 0xfe, 0xa8, 0x05, - 0x12, 0xfe, 0xe3, 0x00, - 0x21, 0x53, 0xfe, 0x4a, 0xf0, 0xfe, 0x76, 0x05, 0xfe, 0x49, 0xf0, 0xfe, - 0x70, 0x05, 0x88, 0x25, - 0xfe, 0x21, 0x00, 0xab, 0x25, 0xfe, 0x22, 0x00, 0xaa, 0x25, 0x58, 0xfe, - 0x09, 0x48, 0xff, 0x02, - 0x00, 0x10, 0x27, 0xfe, 0x86, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0xfe, 0xe2, - 0x08, 0x53, 0x05, 0xcb, - 0x4d, 0x01, 0xb0, 0x25, 0x06, 0x13, 0xd3, 0x39, 0xfe, 0x27, 0x01, 0x08, - 0x05, 0x1b, 0xfe, 0x22, - 0x12, 0x41, 0x01, 0xb2, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe, - 0x0d, 0x00, 0x01, 0x36, - 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0xeb, - 0x03, 0x5c, 0x28, 0xfe, - 0x36, 0x13, 0x41, 0x01, 0xb2, 0x26, 0xfe, 0x18, 0x06, 0x09, 0x06, 0x53, - 0x05, 0x1f, 0xfe, 0x02, - 0x12, 0x50, 0x01, 0xfe, 0x9e, 0x15, 0x1d, 0xfe, 0x0e, 0x06, 0x12, 0xa5, - 0x01, 0x4b, 0x12, 0xfe, - 0xe5, 0x00, 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x03, 0xcd, 0x28, 0xfe, 0x62, - 0x12, 0x03, 0x45, 0x28, - 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x0c, 0x19, 0x01, 0xfe, 0x76, 0x19, 0xfe, - 0x43, 0x48, 0xc4, 0xcc, - 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0x8b, 0xc4, - 0x6e, 0x41, 0x01, 0xb2, - 0x26, 0xfe, 0x82, 0x06, 0x53, 0x05, 0x1a, 0xe9, 0x91, 0x09, 0x59, 0x01, - 0xfe, 0xcc, 0x15, 0x1d, - 0xfe, 0x78, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe, 0xe5, 0x00, 0x03, - 0x45, 0xc1, 0x0c, 0x45, - 0x18, 0x06, 0x01, 0xb2, 0xfa, 0x76, 0x74, 0x01, 0xaf, 0x8c, 0x12, 0xfe, - 0xe2, 0x00, 0x27, 0xdb, - 0x1c, 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0xb6, 0x06, 0x94, 0xfe, 0x6c, 0x07, - 0xfe, 0x06, 0xf0, 0xfe, - 0x74, 0x07, 0x95, 0x86, 0x02, 0x24, 0x08, 0x05, 0x0a, 0xfe, 0x2e, 0x12, - 0x16, 0x19, 0x01, 0x0b, - 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, - 0xfe, 0x99, 0xa4, 0x01, - 0x0b, 0x16, 0x00, 0x02, 0xfe, 0x42, 0x08, 0x68, 0x05, 0x1a, 0xfe, 0x38, - 0x12, 0x08, 0x05, 0x1a, - 0xfe, 0x30, 0x13, 0x16, 0xfe, 0x1b, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, - 0x0b, 0x16, 0x00, 0x01, - 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x06, 0x01, 0x0b, 0x16, 0x00, 0x02, - 0xe2, 0x6c, 0x58, 0xbe, - 0x50, 0xfe, 0x9a, 0x81, 0x55, 0x1b, 0x7a, 0xfe, 0x42, 0x07, 0x09, 0x1b, - 0xfe, 0x09, 0x6f, 0xba, - 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x69, 0x6d, 0x8b, 0x6c, 0x7f, 0x27, - 0xfe, 0x54, 0x07, 0x1c, - 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0x42, 0x07, 0x95, 0x86, 0x94, 0xfe, 0x6c, - 0x07, 0x02, 0x24, 0x01, - 0x4b, 0x02, 0xdb, 0x16, 0x1f, 0x02, 0xdb, 0xfe, 0x9c, 0xf7, 0xdc, 0xfe, - 0x2c, 0x90, 0xfe, 0xae, - 0x90, 0x56, 0xfe, 0xda, 0x07, 0x0c, 0x60, 0x14, 0x61, 0x08, 0x54, 0x5a, - 0x37, 0x22, 0x20, 0x07, - 0x11, 0xfe, 0x0e, 0x12, 0x8d, 0xfe, 0x80, 0x80, 0x39, 0x20, 0x6a, 0x2a, - 0xfe, 0x06, 0x10, 0xfe, - 0x83, 0xe7, 0xfe, 0x48, 0x00, 0xab, 0xfe, 0x03, 0x40, 0x08, 0x54, 0x5b, - 0x37, 0x01, 0xb3, 0xb8, - 0xfe, 0x1f, 0x40, 0x13, 0x62, 0x01, 0xef, 0xfe, 0x08, 0x50, 0xfe, 0x8a, - 0x50, 0xfe, 0x44, 0x51, - 0xfe, 0xc6, 0x51, 0x88, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e, - 0x14, 0x5f, 0xfe, 0x0c, - 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x0c, 0x3d, - 0x14, 0x3e, 0xfe, 0x4a, - 0x10, 0x08, 0x05, 0x5a, 0xfe, 0x2a, 0x12, 0xfe, 0x2c, 0x90, 0xfe, 0xae, - 0x90, 0x0c, 0x60, 0x14, - 0x61, 0x08, 0x05, 0x5b, 0x8b, 0x01, 0xb3, 0xfe, 0x1f, 0x80, 0x13, 0x62, - 0xfe, 0x44, 0x90, 0xfe, - 0xc6, 0x90, 0x0c, 0x3f, 0x14, 0x40, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, - 0x0c, 0x5e, 0x14, 0x5f, - 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x3d, 0x14, 0x3e, 0x0c, 0x2e, - 0x14, 0x3c, 0x21, 0x0c, - 0x49, 0x0c, 0x63, 0x08, 0x54, 0x1f, 0x37, 0x2c, 0x0f, 0xfe, 0x4e, 0x11, - 0x27, 0xdd, 0xfe, 0x9e, - 0xf0, 0xfe, 0x76, 0x08, 0xbc, 0x17, 0x34, 0x2c, 0x77, 0xe6, 0xc5, 0xfe, - 0x9a, 0x08, 0xc6, 0xfe, - 0xb8, 0x08, 0x94, 0xfe, 0x8e, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x94, 0x08, - 0x95, 0x86, 0x02, 0x24, - 0x01, 0x4b, 0xfe, 0xc9, 0x10, 0x16, 0x1f, 0xfe, 0xc9, 0x10, 0x68, 0x05, - 0x06, 0xfe, 0x10, 0x12, - 0x68, 0x05, 0x0a, 0x4e, 0x08, 0x05, 0x0a, 0xfe, 0x90, 0x12, 0xfe, 0x2e, - 0x1c, 0x02, 0xfe, 0x18, - 0x0b, 0x68, 0x05, 0x06, 0x4e, 0x68, 0x05, 0x0a, 0xfe, 0x7a, 0x12, 0xfe, - 0x2c, 0x1c, 0xfe, 0xaa, - 0xf0, 0xfe, 0xd2, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0x00, 0x09, 0x02, 0xfe, - 0xde, 0x09, 0xfe, 0xb7, - 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0x02, 0xf6, 0x1a, 0x50, 0xfe, 0x70, 0x18, - 0xfe, 0xf1, 0x18, 0xfe, - 0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe, - 0x14, 0x59, 0xfe, 0x95, - 0x59, 0x1c, 0x85, 0xfe, 0x8c, 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0xac, 0xf0, - 0xfe, 0xf0, 0x08, 0xb5, - 0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x0c, 0x09, 0x02, 0xfe, 0x18, - 0x0b, 0xb6, 0xfe, 0xbf, - 0x10, 0xfe, 0x2b, 0xf0, 0x85, 0xf4, 0x1e, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, - 0x12, 0xc2, 0xfe, 0xd2, - 0xf0, 0x85, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x17, 0x85, 0x03, 0xd2, 0x1e, - 0x06, 0x17, 0x85, 0xc5, - 0x4a, 0xc6, 0x4a, 0xb5, 0xb6, 0xfe, 0x89, 0x10, 0x74, 0x67, 0x2d, 0x15, - 0x9d, 0x01, 0x36, 0x10, - 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x65, 0x10, 0x80, 0x02, 0x65, 0xfe, - 0x98, 0x80, 0xfe, 0x19, - 0xe4, 0x0a, 0xfe, 0x1a, 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18, - 0xfe, 0x44, 0x54, 0xbe, - 0xfe, 0x19, 0x81, 0xfe, 0x74, 0x18, 0x8f, 0x90, 0x17, 0xfe, 0xce, 0x08, - 0x02, 0x4a, 0x08, 0x05, - 0x5a, 0xec, 0x03, 0x2e, 0x29, 0x3c, 0x0c, 0x3f, 0x14, 0x40, 0x9b, 0x2e, - 0x9c, 0x3c, 0xfe, 0x6c, - 0x18, 0xfe, 0xed, 0x18, 0xfe, 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x3a, 0x3f, - 0x3b, 0x40, 0x03, 0x49, - 0x29, 0x63, 0x8f, 0xfe, 0xe3, 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18, - 0x8f, 0xfe, 0xe3, 0x54, - 0x90, 0xc0, 0x56, 0xfe, 0xce, 0x08, 0x02, 0x4a, 0xfe, 0x37, 0xf0, 0xfe, - 0xda, 0x09, 0xfe, 0x8b, - 0xf0, 0xfe, 0x60, 0x09, 0x02, 0x4a, 0x08, 0x05, 0x0a, 0x23, 0xfe, 0xfa, - 0x0a, 0x3a, 0x49, 0x3b, - 0x63, 0x56, 0xfe, 0x3e, 0x0a, 0x0f, 0xfe, 0xc0, 0x07, 0x41, 0x98, 0x00, - 0xad, 0xfe, 0x01, 0x59, - 0xfe, 0x52, 0xf0, 0xfe, 0x0c, 0x0a, 0x8f, 0x7a, 0xfe, 0x24, 0x0a, 0x3a, - 0x49, 0x8f, 0xfe, 0xe3, - 0x54, 0x57, 0x49, 0x7d, 0x63, 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02, - 0x4a, 0x3a, 0x49, 0x3b, - 0x63, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xbe, 0x57, 0x49, 0x57, 0x63, - 0x02, 0x4a, 0x08, 0x05, - 0x5a, 0xfe, 0x82, 0x12, 0x08, 0x05, 0x1f, 0xfe, 0x66, 0x13, 0x22, 0x62, - 0xb7, 0xfe, 0x03, 0xa1, - 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, - 0xfe, 0x86, 0x91, 0x6a, - 0x2a, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x56, 0xe0, 0x03, 0x60, 0x29, - 0x61, 0x0c, 0x7f, 0x14, - 0x80, 0x57, 0x60, 0x7d, 0x61, 0x01, 0xb3, 0xb8, 0x6a, 0x2a, 0x13, 0x62, - 0x9b, 0x2e, 0x9c, 0x3c, - 0x3a, 0x3f, 0x3b, 0x40, 0x90, 0xc0, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, - 0xfa, 0x3c, 0x01, 0xef, - 0xfe, 0x36, 0x10, 0x21, 0x0c, 0x7f, 0x0c, 0x80, 0x3a, 0x3f, 0x3b, 0x40, - 0xe4, 0x08, 0x05, 0x1f, - 0x17, 0xe0, 0x3a, 0x3d, 0x3b, 0x3e, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, - 0x03, 0x5e, 0x29, 0x5f, - 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0x57, 0x49, 0x7d, 0x63, 0x02, 0xfe, - 0xf4, 0x09, 0x08, 0x05, - 0x1f, 0x17, 0xe0, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0xbe, 0xfe, 0x19, - 0x81, 0x50, 0xfe, 0x10, - 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd3, 0x10, 0x32, 0x07, 0xa6, 0x17, 0xfe, - 0x08, 0x09, 0x12, 0xa6, - 0x08, 0x05, 0x0a, 0xfe, 0x14, 0x13, 0x03, 0x3d, 0x29, 0x3e, 0x56, 0xfe, - 0x08, 0x09, 0xfe, 0x0c, - 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x4a, 0x21, 0x41, 0xfe, 0x19, 0x80, 0xe7, - 0x08, 0x05, 0x0a, 0xfe, - 0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xf4, 0xc2, 0xfe, 0xd1, - 0xf0, 0xe2, 0x15, 0x7e, - 0x01, 0x36, 0x10, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, - 0x57, 0x3d, 0xfe, 0xed, - 0x19, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xf4, 0x1e, 0xfe, - 0x00, 0xff, 0x35, 0xfe, - 0x74, 0x10, 0xc2, 0xfe, 0xd2, 0xf0, 0xfe, 0xa6, 0x0b, 0xfe, 0x76, 0x18, - 0x1e, 0x19, 0x8a, 0x03, - 0xd2, 0x1e, 0x06, 0xfe, 0x08, 0x13, 0x10, 0xfe, 0x16, 0x00, 0x02, 0x65, - 0xfe, 0xd1, 0xf0, 0xfe, - 0xb8, 0x0b, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, 0x17, 0x00, 0xfe, 0x42, - 0x10, 0xfe, 0xce, 0xf0, - 0xfe, 0xbe, 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xca, 0x0b, - 0x10, 0xfe, 0x22, 0x00, - 0x02, 0x65, 0xfe, 0xcb, 0xf0, 0xfe, 0xd6, 0x0b, 0x10, 0xfe, 0x24, 0x00, - 0x02, 0x65, 0xfe, 0xd0, - 0xf0, 0xfe, 0xe0, 0x0b, 0x10, 0x9e, 0xe5, 0xfe, 0xcf, 0xf0, 0xfe, 0xea, - 0x0b, 0x10, 0x58, 0xfe, - 0x10, 0x10, 0xfe, 0xcc, 0xf0, 0xe2, 0x68, 0x05, 0x1f, 0x4d, 0x10, 0xfe, - 0x12, 0x00, 0x2c, 0x0f, - 0xfe, 0x4e, 0x11, 0x27, 0xfe, 0x00, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x14, - 0x0c, 0xbc, 0x17, 0x34, - 0x2c, 0x77, 0xe6, 0xc5, 0x24, 0xc6, 0x24, 0x2c, 0xfa, 0x27, 0xfe, 0x20, - 0x0c, 0x1c, 0x34, 0x94, - 0xfe, 0x3c, 0x0c, 0x95, 0x86, 0xc5, 0xdc, 0xc6, 0xdc, 0x02, 0x24, 0x01, - 0x4b, 0xfe, 0xdb, 0x10, - 0x12, 0xfe, 0xe8, 0x00, 0xb5, 0xb6, 0x74, 0xc7, 0x81, 0xc8, 0x83, 0xfe, - 0x89, 0xf0, 0x24, 0x33, - 0x31, 0xe1, 0xc7, 0x81, 0xc8, 0x83, 0x27, 0xfe, 0x66, 0x0c, 0x1d, 0x24, - 0x33, 0x31, 0xdf, 0xbc, - 0x4e, 0x10, 0xfe, 0x42, 0x00, 0x02, 0x65, 0x7c, 0x06, 0xfe, 0x81, 0x49, - 0x17, 0xfe, 0x2c, 0x0d, - 0x08, 0x05, 0x0a, 0xfe, 0x44, 0x13, 0x10, 0x00, 0x55, 0x0a, 0xfe, 0x54, - 0x12, 0x55, 0xfe, 0x28, - 0x00, 0x23, 0xfe, 0x9a, 0x0d, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, - 0x44, 0xfe, 0x28, 0x00, - 0xfe, 0xe2, 0x10, 0x01, 0xf5, 0x01, 0xf6, 0x09, 0xa4, 0x01, 0xfe, 0x26, - 0x0f, 0x64, 0x12, 0x2f, - 0x01, 0x73, 0x02, 0x2b, 0x10, 0xfe, 0x44, 0x00, 0x55, 0x0a, 0xe9, 0x44, - 0x0a, 0xfe, 0xb4, 0x10, - 0x01, 0xb0, 0x44, 0x0a, 0xfe, 0xaa, 0x10, 0x01, 0xb0, 0xfe, 0x19, 0x82, - 0xfe, 0x34, 0x46, 0xac, - 0x44, 0x0a, 0x10, 0xfe, 0x43, 0x00, 0xfe, 0x96, 0x10, 0x08, 0x54, 0x0a, - 0x37, 0x01, 0xf5, 0x01, - 0xf6, 0x64, 0x12, 0x2f, 0x01, 0x73, 0x99, 0x0a, 0x64, 0x42, 0x92, 0x02, - 0xfe, 0x2e, 0x03, 0x08, - 0x05, 0x0a, 0x8a, 0x44, 0x0a, 0x10, 0x00, 0xfe, 0x5c, 0x10, 0x68, 0x05, - 0x1a, 0xfe, 0x58, 0x12, - 0x08, 0x05, 0x1a, 0xfe, 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, - 0xfe, 0x50, 0x0d, 0xfe, - 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x56, 0x0d, 0x08, 0x54, 0x1a, 0x37, - 0xfe, 0xa9, 0x10, 0x10, - 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0a, 0x50, 0xfe, 0x2e, 0x10, 0x10, - 0xfe, 0x13, 0x00, 0xfe, - 0x10, 0x10, 0x10, 0x6f, 0xab, 0x10, 0xfe, 0x41, 0x00, 0xaa, 0x10, 0xfe, - 0x24, 0x00, 0x8c, 0xb5, - 0xb6, 0x74, 0x03, 0x70, 0x28, 0x23, 0xd8, 0x50, 0xfe, 0x04, 0xe6, 0x1a, - 0xfe, 0x9d, 0x41, 0xfe, - 0x1c, 0x42, 0x64, 0x01, 0xe3, 0x02, 0x2b, 0xf8, 0x15, 0x0a, 0x39, 0xa0, - 0xb4, 0x15, 0xfe, 0x31, - 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, 0x02, 0xd7, 0x42, 0xfe, 0x06, - 0xec, 0xd0, 0xfc, 0x44, - 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe, 0x06, 0xea, 0xd0, 0xfe, 0x47, - 0x4b, 0x91, 0xfe, 0x75, - 0x57, 0x03, 0x5d, 0xfe, 0x98, 0x56, 0xfe, 0x38, 0x12, 0x09, 0x48, 0x01, - 0x0e, 0xfe, 0x44, 0x48, - 0x4f, 0x08, 0x05, 0x1b, 0xfe, 0x1a, 0x13, 0x09, 0x46, 0x01, 0x0e, 0x41, - 0xfe, 0x41, 0x58, 0x09, - 0xa4, 0x01, 0x0e, 0xfe, 0x49, 0x54, 0x96, 0xfe, 0x1e, 0x0e, 0x02, 0xfe, - 0x2e, 0x03, 0x09, 0x5d, - 0xfe, 0xee, 0x14, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe, - 0xce, 0x47, 0xfe, 0xad, - 0x13, 0x02, 0x2b, 0x22, 0x20, 0x07, 0x11, 0xfe, 0x9e, 0x12, 0x21, 0x13, - 0x59, 0x13, 0x9f, 0x13, - 0xd5, 0x22, 0x2f, 0x41, 0x39, 0x2f, 0xbc, 0xad, 0xfe, 0xbc, 0xf0, 0xfe, - 0xe0, 0x0e, 0x0f, 0x06, - 0x13, 0x59, 0x01, 0xfe, 0xda, 0x16, 0x03, 0xfe, 0x38, 0x01, 0x29, 0xfe, - 0x3a, 0x01, 0x56, 0xfe, - 0xe4, 0x0e, 0xfe, 0x02, 0xec, 0xd5, 0x69, 0x00, 0x66, 0xfe, 0x04, 0xec, - 0x20, 0x4f, 0xfe, 0x05, - 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x4a, 0x17, 0xfe, 0x08, 0x90, 0xfe, - 0x48, 0xf4, 0x0d, 0xfe, - 0x18, 0x13, 0xba, 0xfe, 0x02, 0xea, 0xd5, 0x69, 0x7e, 0xfe, 0xc5, 0x13, - 0x15, 0x1a, 0x39, 0xa0, - 0xb4, 0xfe, 0x2e, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x1e, 0xfe, 0xf0, 0xff, - 0x0c, 0xfe, 0x60, 0x01, - 0x03, 0xfe, 0x3a, 0x01, 0x0c, 0xfe, 0x62, 0x01, 0x43, 0x13, 0x20, 0x25, - 0x06, 0x13, 0x2f, 0x12, - 0x2f, 0x92, 0x0f, 0x06, 0x04, 0x21, 0x04, 0x22, 0x59, 0xfe, 0xf7, 0x12, - 0x22, 0x9f, 0xb7, 0x13, - 0x9f, 0x07, 0x7e, 0xfe, 0x71, 0x13, 0xfe, 0x24, 0x1c, 0x15, 0x19, 0x39, - 0xa0, 0xb4, 0xfe, 0xd9, - 0x10, 0xc3, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x04, - 0xc3, 0xfe, 0x03, 0xdc, - 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x21, - 0xfe, 0x00, 0xcc, 0x04, - 0xfe, 0x03, 0x57, 0xc3, 0x78, 0x04, 0x08, 0x05, 0x58, 0xfe, 0x22, 0x13, - 0xfe, 0x1c, 0x80, 0x07, - 0x06, 0xfe, 0x1a, 0x13, 0xfe, 0x1e, 0x80, 0xed, 0xfe, 0x1d, 0x80, 0xae, - 0xfe, 0x0c, 0x90, 0xfe, - 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xac, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, - 0x0a, 0xfe, 0x3c, 0x50, - 0xaa, 0x01, 0xfe, 0x7a, 0x17, 0x32, 0x07, 0x2f, 0xad, 0x01, 0xfe, 0xb4, - 0x16, 0x08, 0x05, 0x1b, - 0x4e, 0x01, 0xf5, 0x01, 0xf6, 0x12, 0xfe, 0xe9, 0x00, 0x08, 0x05, 0x58, - 0xfe, 0x2c, 0x13, 0x01, - 0xfe, 0x0c, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90, - 0x0c, 0xfe, 0x64, 0x01, - 0x14, 0xfe, 0x66, 0x01, 0x08, 0x05, 0x5b, 0xfe, 0x12, 0x12, 0xfe, 0x03, - 0x80, 0x8d, 0xfe, 0x01, - 0xec, 0x20, 0xfe, 0x80, 0x40, 0x13, 0x20, 0x6a, 0x2a, 0x12, 0xcf, 0x64, - 0x22, 0x20, 0xfb, 0x79, - 0x20, 0x04, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58, - 0x03, 0xfe, 0xae, 0x00, + if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) { + warn_code |= ASC_WARN_AUTO_CONFIG; + } +#ifdef CONFIG_PCI + if (asc_dvc->bus_type & ASC_IS_PCI) { + cfg_msw &= 0xFFC0; + AscSetChipCfgMsw(iop_base, cfg_msw); + if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) { + } else { + if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) || + (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) { + asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB; + asc_dvc->bug_fix_cntl |= + ASC_BUG_FIX_ASYN_USE_SYN; + } + } + } else +#endif /* CONFIG_PCI */ + if (asc_dvc->bus_type == ASC_IS_ISAPNP) { + if (AscGetChipVersion(iop_base, asc_dvc->bus_type) + == ASC_CHIP_VER_ASYN_BUG) { + asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN; + } + } + if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) != + asc_dvc->cfg->chip_scsi_id) { + asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID; + } +#ifdef CONFIG_ISA + if (asc_dvc->bus_type & ASC_IS_ISA) { + AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel); + AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed); + } +#endif /* CONFIG_ISA */ - 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe, - 0xb2, 0x00, 0xfe, 0x09, - 0x58, 0xfe, 0x0a, 0x1c, 0x25, 0x6e, 0x13, 0xd0, 0x21, 0x0c, 0x5c, 0x0c, - 0x45, 0x0f, 0x46, 0x52, - 0x50, 0x18, 0x1b, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xfe, 0xfc, - 0x0f, 0x44, 0x11, 0x0f, - 0x48, 0x52, 0x18, 0x58, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xe4, - 0x25, 0x11, 0x13, 0x20, - 0x7c, 0x6f, 0x4f, 0x22, 0x20, 0xfb, 0x79, 0x20, 0x12, 0xcf, 0xfe, 0x14, - 0x56, 0xfe, 0xd6, 0xf0, - 0xfe, 0x26, 0x10, 0xf8, 0x74, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, - 0x18, 0x1c, 0x04, 0x42, - 0xfe, 0x0c, 0x14, 0xfc, 0xfe, 0x07, 0xe6, 0x1b, 0xfe, 0xce, 0x47, 0xfe, - 0xf5, 0x13, 0x04, 0x01, - 0xb0, 0x7c, 0x6f, 0x4f, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, - 0x13, 0x32, 0x07, 0x2f, - 0xfe, 0x34, 0x13, 0x09, 0x48, 0x01, 0x0e, 0xbb, 0xfe, 0x36, 0x12, 0xfe, - 0x41, 0x48, 0xfe, 0x45, - 0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, - 0x07, 0x11, 0xac, 0x09, - 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x73, 0xfe, 0x0e, 0x10, 0x07, - 0x82, 0x4e, 0xfe, 0x14, - 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x60, 0x10, 0x04, 0xfe, 0x44, 0x58, 0x8d, - 0xfe, 0x01, 0xec, 0xa2, - 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1a, 0x79, - 0x2a, 0x01, 0xe3, 0xfe, - 0xdd, 0x10, 0x2c, 0xc7, 0x81, 0xc8, 0x83, 0x33, 0x31, 0xde, 0x07, 0x1a, - 0xfe, 0x48, 0x12, 0x07, - 0x0a, 0xfe, 0x56, 0x12, 0x07, 0x19, 0xfe, 0x30, 0x12, 0x07, 0xc9, 0x17, - 0xfe, 0x32, 0x12, 0x07, - 0xfe, 0x23, 0x00, 0x17, 0xeb, 0x07, 0x06, 0x17, 0xfe, 0x9c, 0x12, 0x07, - 0x1f, 0xfe, 0x12, 0x12, - 0x07, 0x00, 0x17, 0x24, 0x15, 0xc9, 0x01, 0x36, 0xa9, 0x2d, 0x01, 0x0b, - 0x94, 0x4b, 0x04, 0x2d, - 0xdd, 0x09, 0xd1, 0x01, 0xfe, 0x26, 0x0f, 0x12, 0x82, 0x02, 0x2b, 0x2d, - 0x32, 0x07, 0xa6, 0xfe, - 0xd9, 0x13, 0x3a, 0x3d, 0x3b, 0x3e, 0x56, 0xfe, 0xf0, 0x11, 0x08, 0x05, - 0x5a, 0xfe, 0x72, 0x12, - 0x9b, 0x2e, 0x9c, 0x3c, 0x90, 0xc0, 0x96, 0xfe, 0xba, 0x11, 0x22, 0x62, - 0xfe, 0x26, 0x13, 0x03, - 0x7f, 0x29, 0x80, 0x56, 0xfe, 0x76, 0x0d, 0x0c, 0x60, 0x14, 0x61, 0x21, - 0x0c, 0x7f, 0x0c, 0x80, - 0x01, 0xb3, 0x25, 0x6e, 0x77, 0x13, 0x62, 0x01, 0xef, 0x9b, 0x2e, 0x9c, - 0x3c, 0xfe, 0x04, 0x55, - 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0xfe, - 0x91, 0x10, 0x03, 0x3f, - 0x29, 0x40, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x3f, 0x14, 0x40, - 0x88, 0x9b, 0x2e, 0x9c, - 0x3c, 0x90, 0xc0, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x00, 0x56, 0xfe, 0xa1, - 0x56, 0x0c, 0x5e, 0x14, - 0x5f, 0x08, 0x05, 0x5a, 0xfe, 0x1e, 0x12, 0x22, 0x62, 0xfe, 0x1f, 0x40, - 0x03, 0x60, 0x29, 0x61, - 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x03, 0x3f, 0x29, 0x40, 0xfe, 0x44, - 0x50, 0xfe, 0xc6, 0x50, - 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x3d, - 0x29, 0x3e, 0xfe, 0x40, - 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x89, 0x25, 0x06, 0x13, 0xd4, 0x02, 0x72, - 0x2d, 0x01, 0x0b, 0x1d, - 0x4c, 0x33, 0x31, 0xde, 0x07, 0x06, 0x23, 0x4c, 0x32, 0x07, 0xa6, 0x23, - 0x72, 0x01, 0xaf, 0x1e, - 0x43, 0x17, 0x4c, 0x08, 0x05, 0x0a, 0xee, 0x3a, 0x3d, 0x3b, 0x3e, 0xfe, - 0x0a, 0x55, 0x35, 0xfe, - 0x8b, 0x55, 0x57, 0x3d, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, - 0x02, 0x72, 0xfe, 0x19, - 0x81, 0xba, 0xfe, 0x19, 0x41, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1c, 0x34, - 0x1d, 0xe8, 0x33, 0x31, - 0xe1, 0x55, 0x19, 0xfe, 0xa6, 0x12, 0x55, 0x0a, 0x4d, 0x02, 0x4c, 0x01, - 0x0b, 0x1c, 0x34, 0x1d, - 0xe8, 0x33, 0x31, 0xdf, 0x07, 0x19, 0x23, 0x4c, 0x01, 0x0b, 0x1d, 0xe8, - 0x33, 0x31, 0xfe, 0xe8, - 0x09, 0xfe, 0xc2, 0x49, 0x51, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0x8a, 0x53, - 0x05, 0x1f, 0x35, 0xa9, - 0xfe, 0xbb, 0x45, 0x55, 0x00, 0x4e, 0x44, 0x06, 0x7c, 0x43, 0xfe, 0xda, - 0x14, 0x01, 0xaf, 0x8c, - 0xfe, 0x4b, 0x45, 0xee, 0x32, 0x07, 0xa5, 0xed, 0x03, 0xcd, 0x28, 0x8a, - 0x03, 0x45, 0x28, 0x35, - 0x67, 0x02, 0x72, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17, - 0x03, 0x5c, 0xc1, 0x0c, - 0x5c, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, 0xfe, 0x9e, 0x15, 0x02, - 0x89, 0x01, 0x0b, 0x1c, - 0x34, 0x1d, 0x4c, 0x33, 0x31, 0xdf, 0x07, 0x06, 0x23, 0x4c, 0x01, 0xf1, - 0xfe, 0x42, 0x58, 0xf1, - 0xfe, 0xa4, 0x14, 0x8c, 0xfe, 0x4a, 0xf4, 0x0a, 0x17, 0x4c, 0xfe, 0x4a, - 0xf4, 0x06, 0xea, 0x32, - 0x07, 0xa5, 0x8b, 0x02, 0x72, 0x03, 0x45, 0xc1, 0x0c, 0x45, 0x67, 0x2d, - 0x01, 0x0b, 0x26, 0x89, - 0x01, 0xfe, 0xcc, 0x15, 0x02, 0x89, 0x0f, 0x06, 0x27, 0xfe, 0xbe, 0x13, - 0x26, 0xfe, 0xd4, 0x13, - 0x76, 0xfe, 0x89, 0x48, 0x01, 0x0b, 0x21, 0x76, 0x04, 0x7b, 0xfe, 0xd0, - 0x13, 0x1c, 0xfe, 0xd0, - 0x13, 0x1d, 0xfe, 0xbe, 0x13, 0x67, 0x2d, 0x01, 0x0b, 0xfe, 0xd5, 0x10, - 0x0f, 0x71, 0xff, 0x02, - 0x00, 0x57, 0x52, 0x93, 0x1e, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, - 0x00, 0x5c, 0x04, 0x0f, - 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0xfe, 0x30, 0x56, - 0xfe, 0x00, 0x5c, 0x04, - 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x04, 0x0f, 0x71, 0xff, - 0x02, 0x00, 0x57, 0x52, - 0x93, 0xfe, 0x0b, 0x58, 0x04, 0x09, 0x5c, 0x01, 0x87, 0x09, 0x45, 0x01, - 0x87, 0x04, 0xfe, 0x03, - 0xa1, 0x1e, 0x11, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x1f, 0x52, - 0xfe, 0x00, 0x7d, 0xfe, - 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x6a, 0x2a, 0x0c, 0x5e, - 0x14, 0x5f, 0x57, 0x3f, - 0x7d, 0x40, 0x04, 0xdd, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, - 0x5a, 0x8d, 0x04, 0x01, - 0xfe, 0x0c, 0x19, 0xfe, 0x42, 0x48, 0x50, 0x51, 0x91, 0x01, 0x0b, 0x1d, - 0xfe, 0x96, 0x15, 0x33, - 0x31, 0xe1, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15, 0x33, 0x31, 0xfe, 0xe8, - 0x0a, 0xfe, 0xc1, 0x59, - 0x03, 0xcd, 0x28, 0xfe, 0xcc, 0x12, 0x53, 0x05, 0x1a, 0xfe, 0xc4, 0x13, - 0x21, 0x69, 0x1a, 0xee, - 0x55, 0xca, 0x6b, 0xfe, 0xdc, 0x14, 0x4d, 0x0f, 0x06, 0x18, 0xca, 0x7c, - 0x30, 0xfe, 0x78, 0x10, - 0xff, 0x02, 0x83, 0x55, 0xab, 0xff, 0x02, 0x83, 0x55, 0x69, 0x19, 0xae, - 0x98, 0xfe, 0x30, 0x00, - 0x96, 0xf2, 0x18, 0x6d, 0x0f, 0x06, 0xfe, 0x56, 0x10, 0x69, 0x0a, 0xed, - 0x98, 0xfe, 0x64, 0x00, - 0x96, 0xf2, 0x09, 0xfe, 0x64, 0x00, 0x18, 0x9e, 0x0f, 0x06, 0xfe, 0x28, - 0x10, 0x69, 0x06, 0xfe, - 0x60, 0x13, 0x98, 0xfe, 0xc8, 0x00, 0x96, 0xf2, 0x09, 0xfe, 0xc8, 0x00, - 0x18, 0x59, 0x0f, 0x06, - 0x88, 0x98, 0xfe, 0x90, 0x01, 0x7a, 0xfe, 0x42, 0x15, 0x91, 0xe4, 0xfe, - 0x43, 0xf4, 0x9f, 0xfe, - 0x56, 0xf0, 0xfe, 0x54, 0x15, 0xfe, 0x04, 0xf4, 0x71, 0xfe, 0x43, 0xf4, - 0x9e, 0xfe, 0xf3, 0x10, - 0xfe, 0x40, 0x5c, 0x01, 0xfe, 0x16, 0x14, 0x1e, 0x43, 0xec, 0xfe, 0x00, - 0x17, 0xfe, 0x4d, 0xe4, - 0x6e, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0x6e, 0xfe, 0x1c, 0x10, 0xfe, 0x00, - 0x17, 0xfe, 0x4d, 0xe4, - 0xcc, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0xcc, 0x88, 0x51, 0x21, 0xfe, 0x4d, - 0xf4, 0x00, 0xe9, 0x91, - 0x0f, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x04, 0x51, 0x0f, 0x0a, - 0x04, 0x16, 0x06, 0x01, - 0x0b, 0x26, 0xf3, 0x16, 0x0a, 0x01, 0x0b, 0x26, 0xf3, 0x16, 0x19, 0x01, - 0x0b, 0x26, 0xf3, 0x76, - 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1, - 0x16, 0x19, 0x01, 0x0b, - 0x26, 0xb1, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1, 0xfe, 0x89, 0x49, 0x01, - 0x0b, 0x26, 0xb1, 0x76, - 0xfe, 0x89, 0x4a, 0x01, 0x0b, 0x04, 0x51, 0x04, 0x22, 0xd3, 0x07, 0x06, - 0xfe, 0x48, 0x13, 0xb8, - 0x13, 0xd3, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x76, 0xa9, 0x67, 0xfe, 0x01, - 0xec, 0xfe, 0x27, 0x01, - 0xfe, 0x89, 0x48, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x2e, 0x16, 0x32, - 0x07, 0xfe, 0xe3, 0x00, - 0xfe, 0x20, 0x13, 0x1d, 0xfe, 0x52, 0x16, 0x21, 0x13, 0xd4, 0x01, 0x4b, - 0x22, 0xd4, 0x07, 0x06, - 0x4e, 0x08, 0x54, 0x06, 0x37, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfb, 0x8e, - 0x07, 0x11, 0xae, 0x09, - 0x84, 0x01, 0x0e, 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x84, 0x01, - 0x0e, 0x8e, 0xfe, 0x80, - 0xe7, 0x11, 0x07, 0x11, 0x8a, 0xfe, 0x45, 0x58, 0x01, 0xf0, 0x8e, 0x04, - 0x09, 0x48, 0x01, 0x0e, - 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x80, - 0x80, 0xfe, 0x80, 0x4c, - 0xfe, 0x49, 0xe4, 0x11, 0xae, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c, - 0x09, 0x5d, 0x01, 0x87, - 0x04, 0x18, 0x11, 0x75, 0x6c, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, - 0x19, 0xde, 0xfe, 0x24, - 0x1c, 0xfe, 0x1d, 0xf7, 0x1b, 0x97, 0xfe, 0xee, 0x16, 0x01, 0xfe, 0xf4, - 0x17, 0xad, 0x9a, 0x1b, - 0x6c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x04, 0xb9, 0x23, 0xfe, 0xde, - 0x16, 0xfe, 0xda, 0x10, - 0x18, 0x11, 0x75, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1f, 0xfe, - 0x18, 0x58, 0x03, 0xfe, - 0x66, 0x01, 0xfe, 0x19, 0x58, 0x9a, 0x1f, 0xfe, 0x3c, 0x90, 0xfe, 0x30, - 0xf4, 0x06, 0xfe, 0x3c, - 0x50, 0x6c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x1f, - 0x97, 0xfe, 0x38, 0x17, - 0xfe, 0xb6, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x10, 0x17, 0xfe, 0x9c, - 0x10, 0x18, 0x11, 0x75, - 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, - 0x2e, 0x97, 0xfe, 0x5a, - 0x17, 0xfe, 0x94, 0x14, 0xec, 0x9a, 0x2e, 0x6c, 0x1a, 0xfe, 0xaf, 0x19, - 0xfe, 0x98, 0xe7, 0x00, - 0x04, 0xb9, 0x23, 0xfe, 0x4e, 0x17, 0xfe, 0x6c, 0x10, 0x18, 0x11, 0x75, - 0xfe, 0x30, 0xbc, 0xfe, - 0xb2, 0xbc, 0x9a, 0xcb, 0x6c, 0x1a, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, - 0xcb, 0x97, 0xfe, 0x92, - 0x17, 0xfe, 0x5c, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x7e, 0x17, 0xfe, - 0x42, 0x10, 0xfe, 0x02, - 0xf6, 0x11, 0x75, 0xfe, 0x18, 0xfe, 0x60, 0xfe, 0x19, 0xfe, 0x61, 0xfe, - 0x03, 0xa1, 0xfe, 0x1d, - 0xf7, 0x5b, 0x97, 0xfe, 0xb8, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, - 0x9a, 0x5b, 0x41, 0xfe, - 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x11, 0xfe, 0x81, 0xe7, - 0x11, 0x12, 0xfe, 0xdd, - 0x00, 0x6a, 0x2a, 0x04, 0x6a, 0x2a, 0xfe, 0x12, 0x45, 0x23, 0xfe, 0xa8, - 0x17, 0x15, 0x06, 0x39, - 0xa0, 0xb4, 0x02, 0x2b, 0xfe, 0x39, 0xf0, 0xfe, 0xfc, 0x17, 0x21, 0x04, - 0xfe, 0x7e, 0x18, 0x1e, - 0x19, 0x66, 0x0f, 0x0d, 0x04, 0x75, 0x03, 0xd2, 0x1e, 0x06, 0xfe, 0xef, - 0x12, 0xfe, 0xe1, 0x10, - 0x7c, 0x6f, 0x4f, 0x32, 0x07, 0x2f, 0xfe, 0x3c, 0x13, 0xf1, 0xfe, 0x42, - 0x13, 0x42, 0x92, 0x09, - 0x48, 0x01, 0x0e, 0xbb, 0xeb, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, - 0xf0, 0xfe, 0x00, 0xcc, - 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, 0x84, 0x01, - 0x0e, 0xfe, 0x80, 0x4c, - 0x01, 0x73, 0xfe, 0x16, 0x10, 0x07, 0x82, 0x8b, 0xfe, 0x40, 0x14, 0xfe, - 0x24, 0x12, 0xfe, 0x14, - 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x1c, 0x18, 0x18, 0x0a, 0x04, 0xfe, 0x9c, - 0xe7, 0x0a, 0x10, 0xfe, - 0x15, 0x00, 0x64, 0x79, 0x2a, 0x01, 0xe3, 0x18, 0x06, 0x04, 0x42, 0x92, - 0x08, 0x54, 0x1b, 0x37, - 0x12, 0x2f, 0x01, 0x73, 0x18, 0x06, 0x04, 0xfe, 0x38, 0x90, 0xfe, 0xba, - 0x90, 0x3a, 0xce, 0x3b, - 0xcf, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x04, 0x22, 0xa3, 0x77, - 0x13, 0xa3, 0x04, 0x09, - 0xa4, 0x01, 0x0e, 0xfe, 0x41, 0x48, 0x09, 0x46, 0x01, 0x0e, 0xfe, 0x49, - 0x44, 0x17, 0xfe, 0xe8, - 0x18, 0x77, 0x78, 0x04, 0x09, 0x48, 0x01, 0x0e, 0x07, 0x11, 0x4e, 0x09, - 0x5d, 0x01, 0xa8, 0x09, - 0x46, 0x01, 0x0e, 0x77, 0x78, 0x04, 0xfe, 0x4e, 0xe4, 0x19, 0x6b, 0xfe, - 0x1c, 0x19, 0x03, 0xfe, - 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xc9, - 0x6b, 0xfe, 0x2e, 0x19, - 0x03, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1a, 0xe5, 0xfe, 0x4e, 0xe4, - 0xfe, 0x0b, 0x00, 0x6b, - 0xfe, 0x40, 0x19, 0x03, 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x1f, 0xfe, - 0x08, 0x10, 0x03, 0xfe, - 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x6d, 0xfe, 0x4e, 0x45, 0xea, 0xba, 0xff, - 0x04, 0x68, 0x54, 0xe7, - 0x1e, 0x6e, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe, - 0x1a, 0xf4, 0xfe, 0x00, - 0x04, 0xea, 0xfe, 0x48, 0xf4, 0x19, 0x7a, 0xfe, 0x74, 0x19, 0x0f, 0x19, - 0x04, 0x07, 0x7e, 0xfe, - 0x5a, 0xf0, 0xfe, 0x84, 0x19, 0x25, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10, - 0x07, 0x1a, 0xfe, 0x5a, - 0xf0, 0xfe, 0x92, 0x19, 0x25, 0xca, 0xfe, 0x26, 0x10, 0x07, 0x19, 0x66, - 0x25, 0x6d, 0xe5, 0x07, - 0x0a, 0x66, 0x25, 0x9e, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x66, 0x25, 0x59, - 0xa9, 0xb8, 0x04, 0x15, - 0xfe, 0x09, 0x00, 0x01, 0x36, 0xfe, 0x04, 0xfe, 0x81, 0x03, 0x83, 0xfe, - 0x40, 0x5c, 0x04, 0x1c, - 0xf7, 0xfe, 0x14, 0xf0, 0x0b, 0x27, 0xfe, 0xd6, 0x19, 0x1c, 0xf7, 0x7b, - 0xf7, 0xfe, 0x82, 0xf0, - 0xfe, 0xda, 0x19, 0x04, 0xff, 0xcc, 0x00, 0x00, -}; + asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG; -static unsigned short _adv_asc38C0800_size = sizeof(_adv_asc38C0800_buf); /* 0x14E1 */ -static ADV_DCNT _adv_asc38C0800_chksum = 0x050D3FD8UL; /* Expanded little-endian checksum. */ + switch (warn_code) { + case 0: /* No error. */ + break; + case ASC_WARN_IO_PORT_ROTATE: + shost_printk(KERN_WARNING, shost, "I/O port address " + "modified\n"); + break; + case ASC_WARN_AUTO_CONFIG: + shost_printk(KERN_WARNING, shost, "I/O port increment switch " + "enabled\n"); + break; + case ASC_WARN_EEPROM_CHKSUM: + shost_printk(KERN_WARNING, shost, "EEPROM checksum error\n"); + break; + case ASC_WARN_IRQ_MODIFIED: + shost_printk(KERN_WARNING, shost, "IRQ modified\n"); + break; + case ASC_WARN_CMD_QNG_CONFLICT: + shost_printk(KERN_WARNING, shost, "tag queuing w/o " + "disconnects\n"); + break; + default: + shost_printk(KERN_WARNING, shost, "unknown warning: 0x%x\n", + warn_code); + break; + } -/* Microcode buffer is kept after initialization for error recovery. */ -static unsigned char _adv_asc38C1600_buf[] = { - 0x00, 0x00, 0x00, 0xf2, 0x00, 0x16, 0x00, 0xfc, 0x00, 0x10, 0x00, 0xf0, - 0x18, 0xe4, 0x01, 0x00, - 0x04, 0x1e, 0x48, 0xe4, 0x03, 0xf6, 0xf7, 0x13, 0x2e, 0x1e, 0x02, 0x00, - 0x07, 0x17, 0xc0, 0x5f, - 0x00, 0xfa, 0xff, 0xff, 0x04, 0x00, 0x00, 0xf6, 0x09, 0xe7, 0x82, 0xe7, - 0x85, 0xf0, 0x86, 0xf0, - 0x4e, 0x10, 0x9e, 0xe7, 0xff, 0x00, 0x55, 0xf0, 0x01, 0xf6, 0x03, 0x00, - 0x98, 0x57, 0x01, 0xe6, - 0x00, 0xea, 0x00, 0xec, 0x01, 0xfa, 0x18, 0xf4, 0x08, 0x00, 0xf0, 0x1d, - 0x38, 0x54, 0x32, 0xf0, - 0x10, 0x00, 0xc2, 0x0e, 0x1e, 0xf0, 0xd5, 0xf0, 0xbc, 0x00, 0x4b, 0xe4, - 0x00, 0xe6, 0xb1, 0xf0, - 0xb4, 0x00, 0x02, 0x13, 0x3e, 0x1c, 0xc8, 0x47, 0x3e, 0x00, 0xd8, 0x01, - 0x06, 0x13, 0x0c, 0x1c, - 0x5e, 0x1e, 0x00, 0x57, 0xc8, 0x57, 0x01, 0xfc, 0xbc, 0x0e, 0xa2, 0x12, - 0xb9, 0x54, 0x00, 0x80, - 0x62, 0x0a, 0x5a, 0x12, 0xc8, 0x15, 0x3e, 0x1e, 0x18, 0x40, 0xbd, 0x56, - 0x03, 0xe6, 0x01, 0xea, - 0x5c, 0xf0, 0x0f, 0x00, 0x20, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12, - 0x04, 0x13, 0xbb, 0x55, - 0x3c, 0x56, 0x3e, 0x57, 0x03, 0x58, 0x4a, 0xe4, 0x40, 0x00, 0xb6, 0x00, - 0xbb, 0x00, 0xc0, 0x00, - 0x00, 0x01, 0x01, 0x01, 0x3e, 0x01, 0x58, 0x0a, 0x44, 0x10, 0x0a, 0x12, - 0x4c, 0x1c, 0x4e, 0x1c, - 0x02, 0x4a, 0x30, 0xe4, 0x05, 0xe6, 0x0c, 0x00, 0x3c, 0x00, 0x80, 0x00, - 0x24, 0x01, 0x3c, 0x01, - 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01, - 0x78, 0x01, 0x7c, 0x01, - 0xc6, 0x0e, 0x0c, 0x10, 0xac, 0x12, 0xae, 0x12, 0x16, 0x1a, 0x32, 0x1c, - 0x6e, 0x1e, 0x02, 0x48, - 0x3a, 0x55, 0xc9, 0x57, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x06, 0xf7, - 0x03, 0xfc, 0x06, 0x00, - 0x1e, 0x00, 0xbe, 0x00, 0xe1, 0x00, 0x0c, 0x12, 0x18, 0x1a, 0x70, 0x1a, - 0x30, 0x1c, 0x38, 0x1c, - 0x10, 0x44, 0x00, 0x4c, 0xb0, 0x57, 0x40, 0x5c, 0x4d, 0xe4, 0x04, 0xea, - 0x5d, 0xf0, 0xa7, 0xf0, - 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x09, 0x00, 0x19, 0x00, 0x32, 0x00, - 0x33, 0x00, 0x34, 0x00, - 0x36, 0x00, 0x98, 0x00, 0x9e, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, - 0x79, 0x01, 0x3c, 0x09, - 0x68, 0x0d, 0x02, 0x10, 0x04, 0x10, 0x3a, 0x10, 0x08, 0x12, 0x0a, 0x13, - 0x40, 0x16, 0x50, 0x16, - 0x00, 0x17, 0x4a, 0x19, 0x00, 0x4e, 0x00, 0x54, 0x01, 0x58, 0x00, 0xdc, - 0x05, 0xf0, 0x09, 0xf0, - 0x59, 0xf0, 0xb8, 0xf0, 0x48, 0xf4, 0x0e, 0xf7, 0x0a, 0x00, 0x9b, 0x00, - 0x9c, 0x00, 0xa4, 0x00, - 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe7, 0x00, 0xf0, 0x03, 0x69, 0x08, - 0xe9, 0x09, 0x5c, 0x0c, - 0xb6, 0x12, 0xbc, 0x19, 0xd8, 0x1b, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, - 0x42, 0x1d, 0x08, 0x44, - 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x89, 0x48, 0x68, 0x54, - 0x83, 0x55, 0x83, 0x59, - 0x31, 0xe4, 0x02, 0xe6, 0x07, 0xf0, 0x08, 0xf0, 0x0b, 0xf0, 0x0c, 0xf0, - 0x4b, 0xf4, 0x04, 0xf8, - 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, - 0xa8, 0x00, 0xaa, 0x00, - 0xb9, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0x22, 0x01, 0x26, 0x01, 0x60, 0x01, - 0x7a, 0x01, 0x82, 0x01, - 0xc8, 0x01, 0xca, 0x01, 0x86, 0x02, 0x6a, 0x03, 0x18, 0x05, 0xb2, 0x07, - 0x68, 0x08, 0x10, 0x0d, - 0x06, 0x10, 0x0a, 0x10, 0x0e, 0x10, 0x12, 0x10, 0x60, 0x10, 0xed, 0x10, - 0xf3, 0x10, 0x06, 0x12, - 0x10, 0x12, 0x1e, 0x12, 0x0c, 0x13, 0x0e, 0x13, 0x10, 0x13, 0xfe, 0x9c, - 0xf0, 0x35, 0x05, 0xfe, - 0xec, 0x0e, 0xff, 0x10, 0x00, 0x00, 0xe9, 0xfe, 0x34, 0x1f, 0x00, 0xe8, - 0xfe, 0x88, 0x01, 0xff, - 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00, - 0x00, 0xfe, 0x57, 0x24, - 0x00, 0xfe, 0x4c, 0x00, 0x65, 0xff, 0x04, 0x00, 0x00, 0x1a, 0xff, 0x09, - 0x00, 0x00, 0xff, 0x08, - 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, - 0xff, 0xff, 0xff, 0x13, - 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00, - 0xfe, 0x04, 0xf7, 0xe8, - 0x37, 0x7d, 0x0d, 0x01, 0xfe, 0x4a, 0x11, 0xfe, 0x04, 0xf7, 0xe8, 0x7d, - 0x0d, 0x51, 0x37, 0xfe, - 0x3d, 0xf0, 0xfe, 0x0c, 0x02, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x91, 0xf0, - 0xfe, 0xf8, 0x01, 0xfe, - 0x90, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x8f, 0xf0, 0xbc, 0x03, 0x67, 0x4d, - 0x05, 0xfe, 0x08, 0x0f, - 0x01, 0xfe, 0x78, 0x0f, 0xfe, 0xdd, 0x12, 0x05, 0xfe, 0x0e, 0x03, 0xfe, - 0x28, 0x1c, 0x03, 0xfe, - 0xa6, 0x00, 0xfe, 0xd1, 0x12, 0x3e, 0x22, 0xfe, 0xa6, 0x00, 0xac, 0xfe, - 0x48, 0xf0, 0xfe, 0x90, - 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0xaa, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc8, - 0x02, 0xfe, 0x46, 0xf0, - 0xfe, 0x5a, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x60, 0x02, 0xfe, 0x43, 0xf0, - 0xfe, 0x4e, 0x02, 0xfe, - 0x44, 0xf0, 0xfe, 0x52, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x56, 0x02, 0x1c, - 0x0d, 0xa2, 0x1c, 0x07, - 0x22, 0xb7, 0x05, 0x35, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02, - 0x1c, 0xf5, 0xfe, 0x1e, - 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0x5f, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, - 0xde, 0x0a, 0x81, 0x01, - 0xa3, 0x05, 0x35, 0x1f, 0x95, 0x47, 0xb8, 0x01, 0xfe, 0xe4, 0x11, 0x0a, - 0x81, 0x01, 0x5c, 0xfe, - 0xbd, 0x10, 0x0a, 0x81, 0x01, 0x5c, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, - 0xfe, 0x58, 0x1c, 0x1c, - 0x07, 0x22, 0xb7, 0x37, 0x2a, 0x35, 0xfe, 0x3d, 0xf0, 0xfe, 0x0c, 0x02, - 0x2b, 0xfe, 0x9e, 0x02, - 0xfe, 0x5a, 0x1c, 0xfe, 0x12, 0x1c, 0xfe, 0x14, 0x1c, 0x1f, 0xfe, 0x30, - 0x00, 0x47, 0xb8, 0x01, - 0xfe, 0xd4, 0x11, 0x1c, 0x07, 0x22, 0xb7, 0x05, 0xe9, 0x21, 0x2c, 0x09, - 0x1a, 0x31, 0xfe, 0x69, - 0x10, 0x1c, 0x07, 0x22, 0xb7, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0x01, 0xfe, - 0x1e, 0x1e, 0x20, 0x2c, - 0xfe, 0x05, 0xf6, 0xde, 0x01, 0xfe, 0x62, 0x1b, 0x01, 0x0c, 0x61, 0x4a, - 0x44, 0x15, 0x56, 0x51, - 0x01, 0xfe, 0x9e, 0x1e, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x0a, 0x57, - 0x01, 0x18, 0x09, 0x00, - 0x36, 0x01, 0x85, 0xfe, 0x18, 0x10, 0xfe, 0x41, 0x58, 0x0a, 0xba, 0x01, - 0x18, 0xfe, 0xc8, 0x54, - 0x7b, 0xfe, 0x1c, 0x03, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x37, 0x60, - 0xfe, 0x02, 0xe8, 0x30, - 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, 0x27, 0xf0, - 0xfe, 0xe4, 0x01, 0xfe, - 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x40, 0x1c, 0x2a, 0xeb, 0xfe, - 0x26, 0xf0, 0xfe, 0x66, - 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x54, 0x03, 0xfe, 0x11, 0xf0, 0xbc, 0xfe, - 0xef, 0x10, 0xfe, 0x9f, - 0xf0, 0xfe, 0x74, 0x03, 0xfe, 0x46, 0x1c, 0x19, 0xfe, 0x11, 0x00, 0x05, - 0x70, 0x37, 0xfe, 0x48, - 0x1c, 0xfe, 0x46, 0x1c, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x18, 0x13, 0x26, - 0x21, 0xb9, 0xc7, 0x20, - 0xb9, 0x0a, 0x57, 0x01, 0x18, 0xc7, 0x89, 0x01, 0xfe, 0xc8, 0x1a, 0x15, - 0xe1, 0x2a, 0xeb, 0xfe, - 0x01, 0xf0, 0xeb, 0xfe, 0x82, 0xf0, 0xfe, 0xa4, 0x03, 0xfe, 0x9c, 0x32, - 0x15, 0xfe, 0xe4, 0x00, - 0x2f, 0xfe, 0xb6, 0x03, 0x2a, 0x3c, 0x16, 0xfe, 0xc6, 0x03, 0x01, 0x41, - 0xfe, 0x06, 0xf0, 0xfe, - 0xd6, 0x03, 0xaf, 0xa0, 0xfe, 0x0a, 0xf0, 0xfe, 0xa2, 0x07, 0x05, 0x29, - 0x03, 0x81, 0x1e, 0x1b, - 0xfe, 0x24, 0x05, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, 0x05, - 0xea, 0xfe, 0x46, 0x1c, - 0x37, 0x7d, 0x1d, 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, - 0xfe, 0x48, 0x1c, 0x75, - 0x01, 0xa6, 0x86, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, 0x1b, 0xec, 0x0a, - 0xe1, 0x01, 0x18, 0x77, - 0x50, 0x40, 0x8d, 0x30, 0x03, 0x81, 0x1e, 0xf8, 0x1f, 0x63, 0x01, 0x42, - 0x8f, 0xfe, 0x70, 0x02, - 0x05, 0xea, 0xd7, 0x99, 0xd8, 0x9c, 0x2a, 0x29, 0x2f, 0xfe, 0x4e, 0x04, - 0x16, 0xfe, 0x4a, 0x04, - 0x7e, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x54, 0x12, 0x32, 0xff, - 0x02, 0x00, 0x10, 0x01, - 0x08, 0x16, 0xfe, 0x02, 0x05, 0x32, 0x01, 0x08, 0x16, 0x29, 0x27, 0x25, - 0xee, 0xfe, 0x4c, 0x44, - 0xfe, 0x58, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x13, 0x34, 0xfe, 0x4c, 0x54, - 0x7b, 0xec, 0x60, 0x8d, - 0x30, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x7c, 0x13, 0x01, - 0x0c, 0x06, 0x28, 0xfe, - 0x32, 0x13, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x68, 0x13, 0xfe, 0x26, 0x10, - 0x13, 0x34, 0xfe, 0x4c, - 0x54, 0x7b, 0xec, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x54, - 0x13, 0x01, 0x0c, 0x06, - 0x28, 0xa5, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x40, 0x13, 0x01, 0x0c, 0x06, - 0x28, 0xf9, 0x1f, 0x7f, - 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, 0x8f, - 0xfe, 0xa4, 0x0e, 0x05, - 0x29, 0x32, 0x15, 0xfe, 0xe6, 0x00, 0x0f, 0xfe, 0x1c, 0x90, 0x04, 0xfe, - 0x9c, 0x93, 0x3a, 0x0b, - 0x0e, 0x8b, 0x02, 0x1f, 0x7f, 0x01, 0x42, 0x05, 0x35, 0xfe, 0x42, 0x5b, - 0x7d, 0x1d, 0xfe, 0x46, - 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0x0f, 0xfe, 0x87, 0x80, 0x04, - 0xfe, 0x87, 0x83, 0xfe, - 0xc9, 0x47, 0x0b, 0x0e, 0xd0, 0x65, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x98, - 0x13, 0x0f, 0xfe, 0x20, - 0x80, 0x04, 0xfe, 0xa0, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x1d, 0xfe, 0x84, - 0x12, 0x01, 0x38, 0x06, - 0x07, 0xfe, 0x70, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x1e, 0x1b, 0xfe, 0xda, - 0x05, 0xd0, 0x54, 0x01, - 0x38, 0x06, 0x0d, 0xfe, 0x58, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x1e, 0xfe, - 0x50, 0x12, 0x5e, 0xff, - 0x02, 0x00, 0x10, 0x2f, 0xfe, 0x90, 0x05, 0x2a, 0x3c, 0xcc, 0xff, 0x02, - 0x00, 0x10, 0x2f, 0xfe, - 0x9e, 0x05, 0x17, 0xfe, 0xf4, 0x05, 0x15, 0xfe, 0xe3, 0x00, 0x26, 0x01, - 0x38, 0xfe, 0x4a, 0xf0, - 0xfe, 0xc0, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0xba, 0x05, 0x71, 0x2e, 0xfe, - 0x21, 0x00, 0xf1, 0x2e, - 0xfe, 0x22, 0x00, 0xa2, 0x2e, 0x4a, 0xfe, 0x09, 0x48, 0xff, 0x02, 0x00, - 0x10, 0x2f, 0xfe, 0xd0, - 0x05, 0x17, 0xfe, 0xf4, 0x05, 0xfe, 0xe2, 0x08, 0x01, 0x38, 0x06, 0xfe, - 0x1c, 0x00, 0x4d, 0x01, - 0xa7, 0x2e, 0x07, 0x20, 0xe4, 0x47, 0xfe, 0x27, 0x01, 0x01, 0x0c, 0x06, - 0x28, 0xfe, 0x24, 0x12, - 0x3e, 0x01, 0x84, 0x1f, 0x7f, 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, - 0x0d, 0x00, 0x01, 0x42, - 0x8f, 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x03, 0xe6, 0x1e, 0xfe, 0xca, 0x13, - 0x03, 0xb6, 0x1e, 0xfe, - 0x40, 0x12, 0x03, 0x66, 0x1e, 0xfe, 0x38, 0x13, 0x3e, 0x01, 0x84, 0x17, - 0xfe, 0x72, 0x06, 0x0a, - 0x07, 0x01, 0x38, 0x06, 0x24, 0xfe, 0x02, 0x12, 0x4f, 0x01, 0xfe, 0x56, - 0x19, 0x16, 0xfe, 0x68, - 0x06, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x66, 0x8a, 0x10, 0x66, - 0x03, 0x9a, 0x1e, 0xfe, - 0x70, 0x12, 0x03, 0x55, 0x1e, 0xfe, 0x68, 0x13, 0x01, 0xc6, 0x09, 0x12, - 0x48, 0xfe, 0x92, 0x06, - 0x2e, 0x12, 0x01, 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0x13, - 0x58, 0xff, 0x02, 0x00, - 0x57, 0x52, 0xad, 0x23, 0x3f, 0x4e, 0x62, 0x49, 0x3e, 0x01, 0x84, 0x17, - 0xfe, 0xea, 0x06, 0x01, - 0x38, 0x06, 0x12, 0xf7, 0x45, 0x0a, 0x95, 0x01, 0xfe, 0x84, 0x19, 0x16, - 0xfe, 0xe0, 0x06, 0x15, - 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x1c, 0x07, - 0x01, 0x84, 0xfe, 0xae, - 0x10, 0x03, 0x6f, 0x1e, 0xfe, 0x9e, 0x13, 0x3e, 0x01, 0x84, 0x03, 0x9a, - 0x1e, 0xfe, 0x1a, 0x12, - 0x01, 0x38, 0x06, 0x12, 0xfc, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe, - 0x43, 0x48, 0x62, 0x80, - 0xf0, 0x45, 0x0a, 0x95, 0x03, 0xb6, 0x1e, 0xf8, 0x01, 0x38, 0x06, 0x24, - 0x36, 0xfe, 0x02, 0xf6, - 0x07, 0x71, 0x78, 0x8c, 0x00, 0x4d, 0x62, 0x49, 0x3e, 0x2d, 0x93, 0x4e, - 0xd0, 0x0d, 0x17, 0xfe, - 0x9a, 0x07, 0x01, 0xfe, 0xc0, 0x19, 0x16, 0xfe, 0x90, 0x07, 0x26, 0x20, - 0x9e, 0x15, 0x82, 0x01, - 0x41, 0x15, 0xe2, 0x21, 0x9e, 0x09, 0x07, 0xfb, 0x03, 0xe6, 0xfe, 0x58, - 0x57, 0x10, 0xe6, 0x05, - 0xfe, 0x2a, 0x06, 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x1c, 0x07, 0x01, 0x84, - 0xfe, 0x9c, 0x32, 0x5f, - 0x75, 0x01, 0xa6, 0x86, 0x15, 0xfe, 0xe2, 0x00, 0x2f, 0xed, 0x2a, 0x3c, - 0xfe, 0x0a, 0xf0, 0xfe, - 0xce, 0x07, 0xae, 0xfe, 0x96, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x9e, 0x08, - 0xaf, 0xa0, 0x05, 0x29, - 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x2e, 0x12, 0x14, 0x1d, 0x01, 0x08, 0x14, - 0x00, 0x01, 0x08, 0x14, - 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, - 0x14, 0x00, 0x05, 0xfe, - 0xc6, 0x09, 0x01, 0x76, 0x06, 0x12, 0xfe, 0x3a, 0x12, 0x01, 0x0c, 0x06, - 0x12, 0xfe, 0x30, 0x13, - 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00, - 0x01, 0x08, 0x14, 0x00, - 0x01, 0x08, 0x14, 0x07, 0x01, 0x08, 0x14, 0x00, 0x05, 0xef, 0x7c, 0x4a, - 0x78, 0x4f, 0x0f, 0xfe, - 0x9a, 0x81, 0x04, 0xfe, 0x9a, 0x83, 0xfe, 0xcb, 0x47, 0x0b, 0x0e, 0x2d, - 0x28, 0x48, 0xfe, 0x6c, - 0x08, 0x0a, 0x28, 0xfe, 0x09, 0x6f, 0xca, 0xfe, 0xca, 0x45, 0xfe, 0x32, - 0x12, 0x53, 0x63, 0x4e, - 0x7c, 0x97, 0x2f, 0xfe, 0x7e, 0x08, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe, - 0x6c, 0x08, 0xaf, 0xa0, - 0xae, 0xfe, 0x96, 0x08, 0x05, 0x29, 0x01, 0x41, 0x05, 0xed, 0x14, 0x24, - 0x05, 0xed, 0xfe, 0x9c, - 0xf7, 0x9f, 0x01, 0xfe, 0xae, 0x1e, 0xfe, 0x18, 0x58, 0x01, 0xfe, 0xbe, - 0x1e, 0xfe, 0x99, 0x58, - 0xfe, 0x78, 0x18, 0xfe, 0xf9, 0x18, 0x8e, 0xfe, 0x16, 0x09, 0x10, 0x6a, - 0x22, 0x6b, 0x01, 0x0c, - 0x61, 0x54, 0x44, 0x21, 0x2c, 0x09, 0x1a, 0xf8, 0x77, 0x01, 0xfe, 0x7e, - 0x1e, 0x47, 0x2c, 0x7a, - 0x30, 0xf0, 0xfe, 0x83, 0xe7, 0xfe, 0x3f, 0x00, 0x71, 0xfe, 0x03, 0x40, - 0x01, 0x0c, 0x61, 0x65, - 0x44, 0x01, 0xc2, 0xc8, 0xfe, 0x1f, 0x40, 0x20, 0x6e, 0x01, 0xfe, 0x6a, - 0x16, 0xfe, 0x08, 0x50, - 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0xfe, 0x10, 0x10, - 0x01, 0xfe, 0xce, 0x1e, - 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x01, 0xfe, 0xee, 0x1e, - 0x01, 0xfe, 0xfe, 0x1e, - 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x10, 0x4b, 0x22, 0x4c, 0xfe, 0x8a, - 0x10, 0x01, 0x0c, 0x06, - 0x54, 0xfe, 0x50, 0x12, 0x01, 0xfe, 0xae, 0x1e, 0x01, 0xfe, 0xbe, 0x1e, - 0x10, 0x6a, 0x22, 0x6b, - 0x01, 0x0c, 0x06, 0x65, 0x4e, 0x01, 0xc2, 0x0f, 0xfe, 0x1f, 0x80, 0x04, - 0xfe, 0x9f, 0x83, 0x33, - 0x0b, 0x0e, 0x20, 0x6e, 0x0f, 0xfe, 0x44, 0x90, 0x04, 0xfe, 0xc4, 0x93, - 0x3a, 0x0b, 0xfe, 0xc6, - 0x90, 0x04, 0xfe, 0xc6, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x6c, 0x22, 0x6d, - 0x01, 0xfe, 0xce, 0x1e, - 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x0f, 0xfe, 0x40, 0x90, - 0x04, 0xfe, 0xc0, 0x93, - 0x3a, 0x0b, 0xfe, 0xc2, 0x90, 0x04, 0xfe, 0xc2, 0x93, 0x79, 0x0b, 0x0e, - 0x10, 0x4b, 0x22, 0x4c, - 0x10, 0x64, 0x22, 0x34, 0x01, 0x0c, 0x61, 0x24, 0x44, 0x37, 0x13, 0xfe, - 0x4e, 0x11, 0x2f, 0xfe, - 0xde, 0x09, 0xfe, 0x9e, 0xf0, 0xfe, 0xf2, 0x09, 0xfe, 0x01, 0x48, 0x1b, - 0x3c, 0x37, 0x88, 0xf5, - 0xd4, 0xfe, 0x1e, 0x0a, 0xd5, 0xfe, 0x42, 0x0a, 0xd2, 0xfe, 0x1e, 0x0a, - 0xd3, 0xfe, 0x42, 0x0a, - 0xae, 0xfe, 0x12, 0x0a, 0xfe, 0x06, 0xf0, 0xfe, 0x18, 0x0a, 0xaf, 0xa0, - 0x05, 0x29, 0x01, 0x41, - 0xfe, 0xc1, 0x10, 0x14, 0x24, 0xfe, 0xc1, 0x10, 0x01, 0x76, 0x06, 0x07, - 0xfe, 0x14, 0x12, 0x01, - 0x76, 0x06, 0x0d, 0x5d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x74, 0x12, 0xfe, - 0x2e, 0x1c, 0x05, 0xfe, - 0x1a, 0x0c, 0x01, 0x76, 0x06, 0x07, 0x5d, 0x01, 0x76, 0x06, 0x0d, 0x41, - 0xfe, 0x2c, 0x1c, 0xfe, - 0xaa, 0xf0, 0xfe, 0xce, 0x0a, 0xfe, 0xac, 0xf0, 0xfe, 0x66, 0x0a, 0xfe, - 0x92, 0x10, 0xc4, 0xf6, - 0xfe, 0xad, 0xf0, 0xfe, 0x72, 0x0a, 0x05, 0xfe, 0x1a, 0x0c, 0xc5, 0xfe, - 0xe7, 0x10, 0xfe, 0x2b, - 0xf0, 0xbf, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12, - 0xac, 0xfe, 0xd2, 0xf0, - 0xbf, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x1b, 0xbf, 0x03, 0xe3, 0x23, 0x07, - 0x1b, 0xbf, 0xd4, 0x5b, - 0xd5, 0x5b, 0xd2, 0x5b, 0xd3, 0x5b, 0xc4, 0xc5, 0xfe, 0xa9, 0x10, 0x75, - 0x5e, 0x32, 0x1f, 0x7f, - 0x01, 0x42, 0x19, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x70, 0x19, 0x98, - 0x05, 0x70, 0xfe, 0x74, - 0x18, 0x23, 0xfe, 0x00, 0xf8, 0x1b, 0x5b, 0x7d, 0x12, 0x01, 0xfe, 0x78, - 0x0f, 0x4d, 0x01, 0xfe, - 0x96, 0x1a, 0x21, 0x30, 0x77, 0x7d, 0x1d, 0x05, 0x5b, 0x01, 0x0c, 0x06, - 0x0d, 0x2b, 0xfe, 0xe2, - 0x0b, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0xa6, 0x12, 0x01, 0x0c, 0x06, 0x24, - 0xfe, 0x88, 0x13, 0x21, - 0x6e, 0xc7, 0x01, 0xfe, 0x1e, 0x1f, 0x0f, 0xfe, 0x83, 0x80, 0x04, 0xfe, - 0x83, 0x83, 0xfe, 0xc9, - 0x47, 0x0b, 0x0e, 0xfe, 0xc8, 0x44, 0xfe, 0x42, 0x13, 0x0f, 0xfe, 0x04, - 0x91, 0x04, 0xfe, 0x84, - 0x93, 0xfe, 0xca, 0x57, 0x0b, 0xfe, 0x86, 0x91, 0x04, 0xfe, 0x86, 0x93, - 0xfe, 0xcb, 0x57, 0x0b, - 0x0e, 0x7a, 0x30, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x8e, 0x40, 0x03, - 0x6a, 0x3b, 0x6b, 0x10, - 0x97, 0x22, 0x98, 0xd9, 0x6a, 0xda, 0x6b, 0x01, 0xc2, 0xc8, 0x7a, 0x30, - 0x20, 0x6e, 0xdb, 0x64, - 0xdc, 0x34, 0x91, 0x6c, 0x7e, 0x6d, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55, - 0xfe, 0x04, 0xfa, 0x64, - 0xfe, 0x05, 0xfa, 0x34, 0x01, 0xfe, 0x6a, 0x16, 0xa3, 0x26, 0x10, 0x97, - 0x10, 0x98, 0x91, 0x6c, - 0x7e, 0x6d, 0xfe, 0x14, 0x10, 0x01, 0x0c, 0x06, 0x24, 0x1b, 0x40, 0x91, - 0x4b, 0x7e, 0x4c, 0x01, - 0x0c, 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x10, - 0x58, 0xfe, 0x91, 0x58, - 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x24, - 0x1b, 0x40, 0x01, 0x0c, - 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x78, 0x01, 0xfe, 0x8e, 0x1e, 0x4f, 0x0f, - 0xfe, 0x10, 0x90, 0x04, - 0xfe, 0x90, 0x93, 0x3a, 0x0b, 0xfe, 0x92, 0x90, 0x04, 0xfe, 0x92, 0x93, - 0x79, 0x0b, 0x0e, 0xfe, - 0xbd, 0x10, 0x01, 0x43, 0x09, 0xbb, 0x1b, 0xfe, 0x6e, 0x0a, 0x15, 0xbb, - 0x01, 0x0c, 0x06, 0x0d, - 0xfe, 0x14, 0x13, 0x03, 0x4b, 0x3b, 0x4c, 0x8e, 0xfe, 0x6e, 0x0a, 0xfe, - 0x0c, 0x58, 0xfe, 0x8d, - 0x58, 0x05, 0x5b, 0x26, 0x3e, 0x0f, 0xfe, 0x19, 0x80, 0x04, 0xfe, 0x99, - 0x83, 0x33, 0x0b, 0x0e, - 0xfe, 0xe5, 0x10, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1a, 0x12, 0xfe, 0x6c, - 0x19, 0xfe, 0x19, 0x41, - 0xfe, 0x6b, 0x18, 0xac, 0xfe, 0xd1, 0xf0, 0xef, 0x1f, 0x92, 0x01, 0x42, - 0x19, 0xfe, 0x44, 0x00, - 0xfe, 0x90, 0x10, 0xfe, 0x6c, 0x19, 0xd9, 0x4b, 0xfe, 0xed, 0x19, 0xda, - 0x4c, 0xfe, 0x0c, 0x51, - 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xff, 0x31, 0xfe, - 0x76, 0x10, 0xac, 0xfe, - 0xd2, 0xf0, 0xfe, 0xba, 0x0c, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x5d, 0x03, - 0xe3, 0x23, 0x07, 0xfe, - 0x08, 0x13, 0x19, 0xfe, 0x16, 0x00, 0x05, 0x70, 0xfe, 0xd1, 0xf0, 0xfe, - 0xcc, 0x0c, 0x1f, 0x92, - 0x01, 0x42, 0x19, 0xfe, 0x17, 0x00, 0x5c, 0xfe, 0xce, 0xf0, 0xfe, 0xd2, - 0x0c, 0xfe, 0x3e, 0x10, - 0xfe, 0xcd, 0xf0, 0xfe, 0xde, 0x0c, 0x19, 0xfe, 0x22, 0x00, 0x05, 0x70, - 0xfe, 0xcb, 0xf0, 0xfe, - 0xea, 0x0c, 0x19, 0xfe, 0x24, 0x00, 0x05, 0x70, 0xfe, 0xd0, 0xf0, 0xfe, - 0xf4, 0x0c, 0x19, 0x94, - 0xfe, 0x1c, 0x10, 0xfe, 0xcf, 0xf0, 0xfe, 0xfe, 0x0c, 0x19, 0x4a, 0xf3, - 0xfe, 0xcc, 0xf0, 0xef, - 0x01, 0x76, 0x06, 0x24, 0x4d, 0x19, 0xfe, 0x12, 0x00, 0x37, 0x13, 0xfe, - 0x4e, 0x11, 0x2f, 0xfe, - 0x16, 0x0d, 0xfe, 0x9e, 0xf0, 0xfe, 0x2a, 0x0d, 0xfe, 0x01, 0x48, 0x1b, - 0x3c, 0x37, 0x88, 0xf5, - 0xd4, 0x29, 0xd5, 0x29, 0xd2, 0x29, 0xd3, 0x29, 0x37, 0xfe, 0x9c, 0x32, - 0x2f, 0xfe, 0x3e, 0x0d, - 0x2a, 0x3c, 0xae, 0xfe, 0x62, 0x0d, 0xaf, 0xa0, 0xd4, 0x9f, 0xd5, 0x9f, - 0xd2, 0x9f, 0xd3, 0x9f, - 0x05, 0x29, 0x01, 0x41, 0xfe, 0xd3, 0x10, 0x15, 0xfe, 0xe8, 0x00, 0xc4, - 0xc5, 0x75, 0xd7, 0x99, - 0xd8, 0x9c, 0xfe, 0x89, 0xf0, 0x29, 0x27, 0x25, 0xbe, 0xd7, 0x99, 0xd8, - 0x9c, 0x2f, 0xfe, 0x8c, - 0x0d, 0x16, 0x29, 0x27, 0x25, 0xbd, 0xfe, 0x01, 0x48, 0xa4, 0x19, 0xfe, - 0x42, 0x00, 0x05, 0x70, - 0x90, 0x07, 0xfe, 0x81, 0x49, 0x1b, 0xfe, 0x64, 0x0e, 0x01, 0x0c, 0x06, - 0x0d, 0xfe, 0x44, 0x13, - 0x19, 0x00, 0x2d, 0x0d, 0xfe, 0x54, 0x12, 0x2d, 0xfe, 0x28, 0x00, 0x2b, - 0xfe, 0xda, 0x0e, 0x0a, - 0x57, 0x01, 0x18, 0x09, 0x00, 0x36, 0x46, 0xfe, 0x28, 0x00, 0xfe, 0xfa, - 0x10, 0x01, 0xfe, 0xf4, - 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x0a, 0xba, 0x01, 0xfe, 0x58, 0x10, 0x40, - 0x15, 0x56, 0x01, 0x85, - 0x05, 0x35, 0x19, 0xfe, 0x44, 0x00, 0x2d, 0x0d, 0xf7, 0x46, 0x0d, 0xfe, - 0xcc, 0x10, 0x01, 0xa7, - 0x46, 0x0d, 0xfe, 0xc2, 0x10, 0x01, 0xa7, 0x0f, 0xfe, 0x19, 0x82, 0x04, - 0xfe, 0x99, 0x83, 0xfe, - 0xcc, 0x47, 0x0b, 0x0e, 0xfe, 0x34, 0x46, 0xa5, 0x46, 0x0d, 0x19, 0xfe, - 0x43, 0x00, 0xfe, 0xa2, - 0x10, 0x01, 0x0c, 0x61, 0x0d, 0x44, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe, - 0x00, 0x1d, 0x40, 0x15, - 0x56, 0x01, 0x85, 0x7d, 0x0d, 0x40, 0x51, 0x01, 0xfe, 0x9e, 0x1e, 0x05, - 0xfe, 0x3a, 0x03, 0x01, - 0x0c, 0x06, 0x0d, 0x5d, 0x46, 0x0d, 0x19, 0x00, 0xfe, 0x62, 0x10, 0x01, - 0x76, 0x06, 0x12, 0xfe, - 0x5c, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x52, 0x13, 0xfe, 0x1c, 0x1c, - 0xfe, 0x9d, 0xf0, 0xfe, - 0x8e, 0x0e, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x94, 0x0e, 0x01, - 0x0c, 0x61, 0x12, 0x44, - 0xfe, 0x9f, 0x10, 0x19, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0d, 0x4f, - 0xfe, 0x2e, 0x10, 0x19, - 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x19, 0xfe, 0x47, 0x00, 0xf1, 0x19, - 0xfe, 0x41, 0x00, 0xa2, - 0x19, 0xfe, 0x24, 0x00, 0x86, 0xc4, 0xc5, 0x75, 0x03, 0x81, 0x1e, 0x2b, - 0xea, 0x4f, 0xfe, 0x04, - 0xe6, 0x12, 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x40, 0x01, 0xf4, 0x05, - 0x35, 0xfe, 0x12, 0x1c, - 0x1f, 0x0d, 0x47, 0xb5, 0xc3, 0x1f, 0xfe, 0x31, 0x00, 0x47, 0xb8, 0x01, - 0xfe, 0xd4, 0x11, 0x05, - 0xe9, 0x51, 0xfe, 0x06, 0xec, 0xe0, 0xfe, 0x0e, 0x47, 0x46, 0x28, 0xfe, - 0xce, 0x45, 0x31, 0x51, - 0xfe, 0x06, 0xea, 0xe0, 0xfe, 0x47, 0x4b, 0x45, 0xfe, 0x75, 0x57, 0x03, - 0x67, 0xfe, 0x98, 0x56, - 0xfe, 0x38, 0x12, 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x44, 0x48, 0x60, 0x01, - 0x0c, 0x06, 0x28, 0xfe, - 0x18, 0x13, 0x0a, 0x57, 0x01, 0x18, 0x3e, 0xfe, 0x41, 0x58, 0x0a, 0xba, - 0xfe, 0xfa, 0x14, 0xfe, - 0x49, 0x54, 0xb0, 0xfe, 0x5e, 0x0f, 0x05, 0xfe, 0x3a, 0x03, 0x0a, 0x67, - 0xfe, 0xe0, 0x14, 0xfe, - 0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0xce, 0x47, - 0xfe, 0xad, 0x13, 0x05, - 0x35, 0x21, 0x2c, 0x09, 0x1a, 0xfe, 0x98, 0x12, 0x26, 0x20, 0x96, 0x20, - 0xe7, 0xfe, 0x08, 0x1c, - 0xfe, 0x7c, 0x19, 0xfe, 0xfd, 0x19, 0xfe, 0x0a, 0x1c, 0x03, 0xe5, 0xfe, - 0x48, 0x55, 0xa5, 0x3b, - 0xfe, 0x62, 0x01, 0xfe, 0xc9, 0x55, 0x31, 0xfe, 0x74, 0x10, 0x01, 0xfe, - 0xf0, 0x1a, 0x03, 0xfe, - 0x38, 0x01, 0x3b, 0xfe, 0x3a, 0x01, 0x8e, 0xfe, 0x1e, 0x10, 0xfe, 0x02, - 0xec, 0xe7, 0x53, 0x00, - 0x36, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01, - 0x01, 0xfe, 0x62, 0x1b, - 0x01, 0xfe, 0xce, 0x1e, 0xb2, 0x11, 0xfe, 0x18, 0x13, 0xca, 0xfe, 0x02, - 0xea, 0xe7, 0x53, 0x92, - 0xfe, 0xc3, 0x13, 0x1f, 0x12, 0x47, 0xb5, 0xc3, 0xfe, 0x2a, 0x10, 0x03, - 0xfe, 0x38, 0x01, 0x23, - 0xfe, 0xf0, 0xff, 0x10, 0xe5, 0x03, 0xfe, 0x3a, 0x01, 0x10, 0xfe, 0x62, - 0x01, 0x01, 0xfe, 0x1e, - 0x1e, 0x20, 0x2c, 0x15, 0x56, 0x01, 0xfe, 0x9e, 0x1e, 0x13, 0x07, 0x02, - 0x26, 0x02, 0x21, 0x96, - 0xc7, 0x20, 0x96, 0x09, 0x92, 0xfe, 0x79, 0x13, 0x1f, 0x1d, 0x47, 0xb5, - 0xc3, 0xfe, 0xe1, 0x10, - 0xcf, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xcf, - 0xfe, 0x03, 0xdc, 0xfe, - 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x26, 0xfe, - 0x00, 0xcc, 0x02, 0xfe, - 0x03, 0x57, 0xcf, 0x89, 0x02, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, - 0x0f, 0xfe, 0x1c, 0x80, - 0x04, 0xfe, 0x9c, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x07, 0xfe, 0x3a, 0x13, - 0x0f, 0xfe, 0x1e, 0x80, - 0x04, 0xfe, 0x9e, 0x83, 0x33, 0x0b, 0x0e, 0xfe, 0x2a, 0x13, 0x0f, 0xfe, - 0x1d, 0x80, 0x04, 0xfe, - 0x9d, 0x83, 0xfe, 0xf9, 0x13, 0x0e, 0xfe, 0x1c, 0x13, 0x01, 0xfe, 0xee, - 0x1e, 0xac, 0xfe, 0x14, - 0x13, 0x01, 0xfe, 0xfe, 0x1e, 0xfe, 0x81, 0x58, 0xfa, 0x01, 0xfe, 0x0e, - 0x1f, 0xfe, 0x30, 0xf4, - 0x0d, 0xfe, 0x3c, 0x50, 0xa2, 0x01, 0xfe, 0x92, 0x1b, 0x01, 0x43, 0x09, - 0x56, 0xfb, 0x01, 0xfe, - 0xc8, 0x1a, 0x01, 0x0c, 0x06, 0x28, 0xa4, 0x01, 0xfe, 0xf4, 0x1c, 0x01, - 0xfe, 0x00, 0x1d, 0x15, - 0xfe, 0xe9, 0x00, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x01, 0xfe, - 0x22, 0x1b, 0xfe, 0x1e, - 0x1c, 0x0f, 0xfe, 0x14, 0x90, 0x04, 0xfe, 0x94, 0x93, 0x3a, 0x0b, 0xfe, - 0x96, 0x90, 0x04, 0xfe, - 0x96, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0xfe, 0x64, 0x01, 0x22, 0xfe, 0x66, - 0x01, 0x01, 0x0c, 0x06, - 0x65, 0xf9, 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b, - 0x0e, 0x77, 0xfe, 0x01, - 0xec, 0x2c, 0xfe, 0x80, 0x40, 0x20, 0x2c, 0x7a, 0x30, 0x15, 0xdf, 0x40, - 0x21, 0x2c, 0xfe, 0x00, - 0x40, 0x8d, 0x2c, 0x02, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, - 0x06, 0x58, 0x03, 0xfe, - 0xae, 0x00, 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, - 0x03, 0xfe, 0xb2, 0x00, - 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x2e, 0x49, 0x20, 0xe0, 0x26, 0x10, - 0x66, 0x10, 0x55, 0x10, - 0x6f, 0x13, 0x57, 0x52, 0x4f, 0x1c, 0x28, 0xfe, 0x90, 0x4d, 0xfe, 0x91, - 0x54, 0x2b, 0xfe, 0x88, - 0x11, 0x46, 0x1a, 0x13, 0x5a, 0x52, 0x1c, 0x4a, 0xfe, 0x90, 0x4d, 0xfe, - 0x91, 0x54, 0x2b, 0xfe, - 0x9e, 0x11, 0x2e, 0x1a, 0x20, 0x2c, 0x90, 0x34, 0x60, 0x21, 0x2c, 0xfe, - 0x00, 0x40, 0x8d, 0x2c, - 0x15, 0xdf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xb2, 0x11, 0xfe, - 0x12, 0x1c, 0x75, 0xfe, - 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x02, 0x51, 0xfe, 0x0c, - 0x14, 0xfe, 0x0e, 0x47, - 0xfe, 0x07, 0xe6, 0x28, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x02, 0x01, - 0xa7, 0x90, 0x34, 0x60, - 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0xfe, 0x02, 0x80, - 0x09, 0x56, 0xfe, 0x34, - 0x13, 0x0a, 0x5a, 0x01, 0x18, 0xcb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48, - 0xfe, 0x45, 0x48, 0x01, - 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, 0x89, - 0x09, 0x1a, 0xa5, 0x0a, - 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x5c, 0x01, 0x85, 0xf2, 0x09, 0x9b, 0xa4, - 0xfe, 0x14, 0x56, 0xfe, - 0xd6, 0xf0, 0xfe, 0xec, 0x11, 0x02, 0xfe, 0x44, 0x58, 0x77, 0xfe, 0x01, - 0xec, 0xb8, 0xfe, 0x9e, - 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x12, 0x8d, 0x30, 0x01, - 0xf4, 0xfe, 0xdd, 0x10, - 0x37, 0xd7, 0x99, 0xd8, 0x9c, 0x27, 0x25, 0xee, 0x09, 0x12, 0xfe, 0x48, - 0x12, 0x09, 0x0d, 0xfe, - 0x56, 0x12, 0x09, 0x1d, 0xfe, 0x30, 0x12, 0x09, 0xdd, 0x1b, 0xfe, 0xc4, - 0x13, 0x09, 0xfe, 0x23, - 0x00, 0x1b, 0xfe, 0xd0, 0x13, 0x09, 0x07, 0x1b, 0xfe, 0x34, 0x14, 0x09, - 0x24, 0xfe, 0x12, 0x12, - 0x09, 0x00, 0x1b, 0x29, 0x1f, 0xdd, 0x01, 0x42, 0xa1, 0x32, 0x01, 0x08, - 0xae, 0x41, 0x02, 0x32, - 0xfe, 0x62, 0x08, 0x0a, 0xe1, 0x01, 0xfe, 0x58, 0x10, 0x15, 0x9b, 0x05, - 0x35, 0x32, 0x01, 0x43, - 0x09, 0xbb, 0xfe, 0xd7, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0x8e, 0xfe, 0x80, - 0x13, 0x01, 0x0c, 0x06, - 0x54, 0xfe, 0x72, 0x12, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x44, 0x55, 0xfe, - 0xe5, 0x55, 0xb0, 0xfe, - 0x4a, 0x13, 0x21, 0x6e, 0xfe, 0x26, 0x13, 0x03, 0x97, 0x3b, 0x98, 0x8e, - 0xfe, 0xb6, 0x0e, 0x10, - 0x6a, 0x22, 0x6b, 0x26, 0x10, 0x97, 0x10, 0x98, 0x01, 0xc2, 0x2e, 0x49, - 0x88, 0x20, 0x6e, 0x01, - 0xfe, 0x6a, 0x16, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x04, 0x55, 0xfe, 0xa5, - 0x55, 0xfe, 0x04, 0xfa, - 0x64, 0xfe, 0x05, 0xfa, 0x34, 0xfe, 0x8f, 0x10, 0x03, 0x6c, 0x3b, 0x6d, - 0xfe, 0x40, 0x56, 0xfe, - 0xe1, 0x56, 0x10, 0x6c, 0x22, 0x6d, 0x71, 0xdb, 0x64, 0xdc, 0x34, 0xfe, - 0x44, 0x55, 0xfe, 0xe5, - 0x55, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x10, - 0x68, 0x22, 0x69, 0x01, - 0x0c, 0x06, 0x54, 0xf9, 0x21, 0x6e, 0xfe, 0x1f, 0x40, 0x03, 0x6a, 0x3b, - 0x6b, 0xfe, 0x2c, 0x50, - 0xfe, 0xae, 0x50, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x44, 0x50, 0xfe, 0xc6, - 0x50, 0x03, 0x68, 0x3b, - 0x69, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x4b, 0x3b, 0x4c, 0xfe, - 0x40, 0x50, 0xfe, 0xc2, - 0x50, 0x05, 0x73, 0x2e, 0x07, 0x20, 0x9e, 0x05, 0x72, 0x32, 0x01, 0x08, - 0x16, 0x3d, 0x27, 0x25, - 0xee, 0x09, 0x07, 0x2b, 0x3d, 0x01, 0x43, 0x09, 0xbb, 0x2b, 0x72, 0x01, - 0xa6, 0x23, 0x3f, 0x1b, - 0x3d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1e, 0x13, 0x91, 0x4b, 0x7e, 0x4c, - 0xfe, 0x0a, 0x55, 0x31, - 0xfe, 0x8b, 0x55, 0xd9, 0x4b, 0xda, 0x4c, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, - 0x51, 0x05, 0x72, 0x01, - 0xfe, 0x8e, 0x1e, 0xca, 0xfe, 0x19, 0x41, 0x05, 0x72, 0x32, 0x01, 0x08, - 0x2a, 0x3c, 0x16, 0xc0, - 0x27, 0x25, 0xbe, 0x2d, 0x1d, 0xc0, 0x2d, 0x0d, 0x83, 0x2d, 0x7f, 0x1b, - 0xfe, 0x66, 0x15, 0x05, - 0x3d, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbd, 0x09, 0x1d, - 0x2b, 0x3d, 0x01, 0x08, - 0x16, 0xc0, 0x27, 0x25, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x50, 0x03, - 0xb6, 0x1e, 0x83, 0x01, - 0x38, 0x06, 0x24, 0x31, 0xa1, 0xfe, 0xbb, 0x45, 0x2d, 0x00, 0xa4, 0x46, - 0x07, 0x90, 0x3f, 0x01, - 0xfe, 0xf8, 0x15, 0x01, 0xa6, 0x86, 0xfe, 0x4b, 0x45, 0xfe, 0x20, 0x13, - 0x01, 0x43, 0x09, 0x82, - 0xfe, 0x16, 0x13, 0x03, 0x9a, 0x1e, 0x5d, 0x03, 0x55, 0x1e, 0x31, 0x5e, - 0x05, 0x72, 0xfe, 0xc0, - 0x5d, 0x01, 0xa7, 0xfe, 0x03, 0x17, 0x03, 0x66, 0x8a, 0x10, 0x66, 0x5e, - 0x32, 0x01, 0x08, 0x17, - 0x73, 0x01, 0xfe, 0x56, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, - 0x3d, 0x27, 0x25, 0xbd, - 0x09, 0x07, 0x2b, 0x3d, 0x01, 0xfe, 0xbe, 0x16, 0xfe, 0x42, 0x58, 0xfe, - 0xe8, 0x14, 0x01, 0xa6, - 0x86, 0xfe, 0x4a, 0xf4, 0x0d, 0x1b, 0x3d, 0xfe, 0x4a, 0xf4, 0x07, 0xfe, - 0x0e, 0x12, 0x01, 0x43, - 0x09, 0x82, 0x4e, 0x05, 0x72, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x5e, 0x32, - 0x01, 0x08, 0x17, 0x73, - 0x01, 0xfe, 0x84, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d, - 0x27, 0x25, 0xbd, 0x09, - 0x12, 0x2b, 0x3d, 0x01, 0xfe, 0xe8, 0x17, 0x8b, 0xfe, 0xaa, 0x14, 0xfe, - 0xb6, 0x14, 0x86, 0xa8, - 0xb2, 0x0d, 0x1b, 0x3d, 0xb2, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09, - 0x82, 0x4e, 0x05, 0x72, - 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01, - 0xfe, 0xc0, 0x19, 0x05, - 0x73, 0x13, 0x07, 0x2f, 0xfe, 0xcc, 0x15, 0x17, 0xfe, 0xe2, 0x15, 0x5f, - 0xcc, 0x01, 0x08, 0x26, - 0x5f, 0x02, 0x8f, 0xfe, 0xde, 0x15, 0x2a, 0xfe, 0xde, 0x15, 0x16, 0xfe, - 0xcc, 0x15, 0x5e, 0x32, - 0x01, 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, - 0xad, 0x23, 0xfe, 0xff, - 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02, - 0x00, 0x57, 0x52, 0xad, - 0x23, 0x3f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, - 0x02, 0x00, 0x57, 0x52, - 0xad, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xfe, 0x00, 0x5e, - 0x02, 0x13, 0x58, 0xff, - 0x02, 0x00, 0x57, 0x52, 0xad, 0xfe, 0x0b, 0x58, 0x02, 0x0a, 0x66, 0x01, - 0x5c, 0x0a, 0x55, 0x01, - 0x5c, 0x0a, 0x6f, 0x01, 0x5c, 0x02, 0x01, 0xfe, 0x1e, 0x1f, 0x23, 0x1a, - 0xff, 0x03, 0x00, 0x54, - 0xfe, 0x00, 0xf4, 0x24, 0x52, 0x0f, 0xfe, 0x00, 0x7c, 0x04, 0xfe, 0x07, - 0x7c, 0x3a, 0x0b, 0x0e, - 0xfe, 0x00, 0x71, 0xfe, 0xf9, 0x18, 0xfe, 0x7a, 0x19, 0xfe, 0xfb, 0x19, - 0xfe, 0x1a, 0xf7, 0x00, - 0xfe, 0x1b, 0xf7, 0x00, 0x7a, 0x30, 0x10, 0x68, 0x22, 0x69, 0xd9, 0x6c, - 0xda, 0x6d, 0x02, 0xfe, - 0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x77, - 0x02, 0x01, 0xc6, 0xfe, - 0x42, 0x48, 0x4f, 0x50, 0x45, 0x01, 0x08, 0x16, 0xfe, 0xe0, 0x17, 0x27, - 0x25, 0xbe, 0x01, 0x08, - 0x16, 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, - 0x03, 0x9a, 0x1e, 0xfe, - 0xda, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfe, 0xd0, 0x13, 0x26, 0x53, 0x12, - 0x48, 0xfe, 0x08, 0x17, - 0xd1, 0x12, 0x53, 0x12, 0xfe, 0x1e, 0x13, 0x2d, 0xb4, 0x7b, 0xfe, 0x26, - 0x17, 0x4d, 0x13, 0x07, - 0x1c, 0xb4, 0x90, 0x04, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xf1, - 0xff, 0x02, 0x83, 0x55, - 0x53, 0x1d, 0xfe, 0x12, 0x13, 0xd6, 0xfe, 0x30, 0x00, 0xb0, 0xfe, 0x80, - 0x17, 0x1c, 0x63, 0x13, - 0x07, 0xfe, 0x56, 0x10, 0x53, 0x0d, 0xfe, 0x16, 0x13, 0xd6, 0xfe, 0x64, - 0x00, 0xb0, 0xfe, 0x80, - 0x17, 0x0a, 0xfe, 0x64, 0x00, 0x1c, 0x94, 0x13, 0x07, 0xfe, 0x28, 0x10, - 0x53, 0x07, 0xfe, 0x60, - 0x13, 0xd6, 0xfe, 0xc8, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0xc8, - 0x00, 0x1c, 0x95, 0x13, - 0x07, 0x71, 0xd6, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0x8c, 0x17, 0x45, 0xf3, - 0xfe, 0x43, 0xf4, 0x96, - 0xfe, 0x56, 0xf0, 0xfe, 0x9e, 0x17, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x43, - 0xf4, 0x94, 0xf6, 0x8b, - 0x01, 0xfe, 0x24, 0x16, 0x23, 0x3f, 0xfc, 0xa8, 0x8c, 0x49, 0x48, 0xfe, - 0xda, 0x17, 0x62, 0x49, - 0xfe, 0x1c, 0x10, 0xa8, 0x8c, 0x80, 0x48, 0xfe, 0xda, 0x17, 0x62, 0x80, - 0x71, 0x50, 0x26, 0xfe, - 0x4d, 0xf4, 0x00, 0xf7, 0x45, 0x13, 0x07, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, - 0x58, 0x02, 0x50, 0x13, - 0x0d, 0x02, 0x50, 0x3e, 0x78, 0x4f, 0x45, 0x01, 0x08, 0x16, 0xa9, 0x27, - 0x25, 0xbe, 0xfe, 0x03, - 0xea, 0xfe, 0x7e, 0x01, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, 0xe9, - 0x0a, 0x01, 0x08, 0x16, - 0xa9, 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0xfe, 0x05, 0xea, 0xfe, 0x7f, 0x01, - 0x01, 0x08, 0x16, 0xa9, - 0x27, 0x25, 0xfe, 0x69, 0x09, 0xfe, 0x02, 0xea, 0xfe, 0x80, 0x01, 0x01, - 0x08, 0x16, 0xa9, 0x27, - 0x25, 0xfe, 0xe8, 0x08, 0x47, 0xfe, 0x81, 0x01, 0x03, 0xb6, 0x1e, 0x83, - 0x01, 0x38, 0x06, 0x24, - 0x31, 0xa2, 0x78, 0xf2, 0x53, 0x07, 0x36, 0xfe, 0x34, 0xf4, 0x3f, 0xa1, - 0x78, 0x03, 0x9a, 0x1e, - 0x83, 0x01, 0x38, 0x06, 0x12, 0x31, 0xf0, 0x4f, 0x45, 0xfe, 0x90, 0x10, - 0xfe, 0x40, 0x5a, 0x23, - 0x3f, 0xfb, 0x8c, 0x49, 0x48, 0xfe, 0xaa, 0x18, 0x62, 0x49, 0x71, 0x8c, - 0x80, 0x48, 0xfe, 0xaa, - 0x18, 0x62, 0x80, 0xfe, 0xb4, 0x56, 0xfe, 0x40, 0x5d, 0x01, 0xc6, 0x01, - 0xfe, 0xac, 0x1d, 0xfe, - 0x02, 0x17, 0xfe, 0xc8, 0x45, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0, 0x18, 0xfe, - 0x43, 0x48, 0x2d, 0x93, - 0x36, 0xfe, 0x34, 0xf4, 0xfe, 0x00, 0x11, 0xfe, 0x40, 0x10, 0x2d, 0xb4, - 0x36, 0xfe, 0x34, 0xf4, - 0x04, 0xfe, 0x34, 0x10, 0x2d, 0xfe, 0x0b, 0x00, 0x36, 0x46, 0x63, 0xfe, - 0x28, 0x10, 0xfe, 0xc0, - 0x49, 0xff, 0x02, 0x00, 0x54, 0xb2, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0xfa, - 0x18, 0x45, 0xfe, 0x1c, - 0xf4, 0x3f, 0xf3, 0xfe, 0x40, 0xf4, 0x96, 0xfe, 0x56, 0xf0, 0xfe, 0x0c, - 0x19, 0xfe, 0x04, 0xf4, - 0x58, 0xfe, 0x40, 0xf4, 0x94, 0xf6, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d, - 0x21, 0xfe, 0x7f, 0x01, - 0xfe, 0xc8, 0x46, 0xfe, 0x24, 0x13, 0x8c, 0x00, 0x5d, 0x26, 0x21, 0xfe, - 0x7e, 0x01, 0xfe, 0xc8, - 0x45, 0xfe, 0x14, 0x13, 0x21, 0xfe, 0x80, 0x01, 0xfe, 0x48, 0x45, 0xfa, - 0x21, 0xfe, 0x81, 0x01, - 0xfe, 0xc8, 0x44, 0x4e, 0x26, 0x02, 0x13, 0x07, 0x02, 0x78, 0x45, 0x50, - 0x13, 0x0d, 0x02, 0x14, - 0x07, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, 0x0d, 0x01, 0x08, 0x17, - 0xfe, 0x82, 0x19, 0x14, - 0x1d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x5f, 0xfe, 0x89, 0x49, 0x01, - 0x08, 0x02, 0x14, 0x07, - 0x01, 0x08, 0x17, 0xc1, 0x14, 0x1d, 0x01, 0x08, 0x17, 0xc1, 0x14, 0x07, - 0x01, 0x08, 0x17, 0xc1, - 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0xc1, 0x5f, 0xfe, 0x89, 0x4a, 0x01, - 0x08, 0x02, 0x50, 0x02, - 0x14, 0x07, 0x01, 0x08, 0x17, 0x74, 0x14, 0x7f, 0x01, 0x08, 0x17, 0x74, - 0x14, 0x12, 0x01, 0x08, - 0x17, 0x74, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0x74, 0x14, 0x00, 0x01, - 0x08, 0x17, 0x74, 0xfe, - 0x89, 0x4a, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x09, 0x49, 0x01, 0x08, 0x17, - 0x74, 0x5f, 0xcc, 0x01, - 0x08, 0x02, 0x21, 0xe4, 0x09, 0x07, 0xfe, 0x4c, 0x13, 0xc8, 0x20, 0xe4, - 0xfe, 0x49, 0xf4, 0x00, - 0x4d, 0x5f, 0xa1, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xcc, 0xff, - 0x02, 0x00, 0x10, 0x2f, - 0xfe, 0x3e, 0x1a, 0x01, 0x43, 0x09, 0xfe, 0xe3, 0x00, 0xfe, 0x22, 0x13, - 0x16, 0xfe, 0x64, 0x1a, - 0x26, 0x20, 0x9e, 0x01, 0x41, 0x21, 0x9e, 0x09, 0x07, 0x5d, 0x01, 0x0c, - 0x61, 0x07, 0x44, 0x02, - 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x00, 0x40, 0xaa, 0x09, 0x1a, 0xfe, 0x12, - 0x13, 0x0a, 0x9d, 0x01, - 0x18, 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x9d, 0x01, 0x18, 0xaa, - 0xfe, 0x80, 0xe7, 0x1a, - 0x09, 0x1a, 0x5d, 0xfe, 0x45, 0x58, 0x01, 0xfe, 0xb2, 0x16, 0xaa, 0x02, - 0x0a, 0x5a, 0x01, 0x18, - 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x01, 0xfe, - 0x7e, 0x1e, 0xfe, 0x80, - 0x4c, 0xfe, 0x49, 0xe4, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, 0x18, - 0xfe, 0x80, 0x4c, 0x0a, - 0x67, 0x01, 0x5c, 0x02, 0x1c, 0x1a, 0x87, 0x7c, 0xe5, 0xfe, 0x18, 0xdf, - 0xfe, 0x19, 0xde, 0xfe, - 0x24, 0x1c, 0xfe, 0x1d, 0xf7, 0x28, 0xb1, 0xfe, 0x04, 0x1b, 0x01, 0xfe, - 0x2a, 0x1c, 0xfa, 0xb3, - 0x28, 0x7c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x02, 0xc9, 0x2b, 0xfe, - 0xf4, 0x1a, 0xfe, 0xfa, - 0x10, 0x1c, 0x1a, 0x87, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x24, - 0xfe, 0x18, 0x58, 0x03, - 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0xb3, 0x24, 0x01, 0xfe, 0x0e, 0x1f, - 0xfe, 0x30, 0xf4, 0x07, - 0xfe, 0x3c, 0x50, 0x7c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, - 0xf7, 0x24, 0xb1, 0xfe, - 0x50, 0x1b, 0xfe, 0xd4, 0x14, 0x31, 0x02, 0xc9, 0x2b, 0xfe, 0x26, 0x1b, - 0xfe, 0xba, 0x10, 0x1c, - 0x1a, 0x87, 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, - 0x1d, 0xf7, 0x54, 0xb1, - 0xfe, 0x72, 0x1b, 0xfe, 0xb2, 0x14, 0xfc, 0xb3, 0x54, 0x7c, 0x12, 0xfe, - 0xaf, 0x19, 0xfe, 0x98, - 0xe7, 0x00, 0x02, 0xc9, 0x2b, 0xfe, 0x66, 0x1b, 0xfe, 0x8a, 0x10, 0x1c, - 0x1a, 0x87, 0x8b, 0x0f, - 0xfe, 0x30, 0x90, 0x04, 0xfe, 0xb0, 0x93, 0x3a, 0x0b, 0xfe, 0x18, 0x58, - 0xfe, 0x32, 0x90, 0x04, - 0xfe, 0xb2, 0x93, 0x3a, 0x0b, 0xfe, 0x19, 0x58, 0x0e, 0xa8, 0xb3, 0x4a, - 0x7c, 0x12, 0xfe, 0x0f, - 0x79, 0xfe, 0x1c, 0xf7, 0x4a, 0xb1, 0xfe, 0xc6, 0x1b, 0xfe, 0x5e, 0x14, - 0x31, 0x02, 0xc9, 0x2b, - 0xfe, 0x96, 0x1b, 0x5c, 0xfe, 0x02, 0xf6, 0x1a, 0x87, 0xfe, 0x18, 0xfe, - 0x6a, 0xfe, 0x19, 0xfe, - 0x6b, 0x01, 0xfe, 0x1e, 0x1f, 0xfe, 0x1d, 0xf7, 0x65, 0xb1, 0xfe, 0xee, - 0x1b, 0xfe, 0x36, 0x14, - 0xfe, 0x1c, 0x13, 0xb3, 0x65, 0x3e, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19, - 0xfe, 0x80, 0xe7, 0x1a, - 0xfe, 0x81, 0xe7, 0x1a, 0x15, 0xfe, 0xdd, 0x00, 0x7a, 0x30, 0x02, 0x7a, - 0x30, 0xfe, 0x12, 0x45, - 0x2b, 0xfe, 0xdc, 0x1b, 0x1f, 0x07, 0x47, 0xb5, 0xc3, 0x05, 0x35, 0xfe, - 0x39, 0xf0, 0x75, 0x26, - 0x02, 0xfe, 0x7e, 0x18, 0x23, 0x1d, 0x36, 0x13, 0x11, 0x02, 0x87, 0x03, - 0xe3, 0x23, 0x07, 0xfe, - 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x90, 0x34, 0x60, 0xfe, 0x02, 0x80, 0x09, - 0x56, 0xfe, 0x3c, 0x13, - 0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x51, 0xfe, 0x06, 0x83, 0x0a, 0x5a, - 0x01, 0x18, 0xcb, 0xfe, - 0x3e, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xfe, 0xb2, 0x16, - 0xfe, 0x00, 0xcc, 0xcb, - 0xfe, 0xf3, 0x13, 0x3f, 0x89, 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18, - 0xfe, 0x80, 0x4c, 0x01, - 0x85, 0xfe, 0x16, 0x10, 0x09, 0x9b, 0x4e, 0xfe, 0x40, 0x14, 0xfe, 0x24, - 0x12, 0xfe, 0x14, 0x56, - 0xfe, 0xd6, 0xf0, 0xfe, 0x52, 0x1c, 0x1c, 0x0d, 0x02, 0xfe, 0x9c, 0xe7, - 0x0d, 0x19, 0xfe, 0x15, - 0x00, 0x40, 0x8d, 0x30, 0x01, 0xf4, 0x1c, 0x07, 0x02, 0x51, 0xfe, 0x06, - 0x83, 0xfe, 0x18, 0x80, - 0x61, 0x28, 0x44, 0x15, 0x56, 0x01, 0x85, 0x1c, 0x07, 0x02, 0xfe, 0x38, - 0x90, 0xfe, 0xba, 0x90, - 0x91, 0xde, 0x7e, 0xdf, 0xfe, 0x48, 0x55, 0x31, 0xfe, 0xc9, 0x55, 0x02, - 0x21, 0xb9, 0x88, 0x20, - 0xb9, 0x02, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0x41, 0x48, 0x0a, 0x57, 0x01, - 0x18, 0xfe, 0x49, 0x44, - 0x1b, 0xfe, 0x1e, 0x1d, 0x88, 0x89, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x09, - 0x1a, 0xa4, 0x0a, 0x67, - 0x01, 0xa3, 0x0a, 0x57, 0x01, 0x18, 0x88, 0x89, 0x02, 0xfe, 0x4e, 0xe4, - 0x1d, 0x7b, 0xfe, 0x52, - 0x1d, 0x03, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, - 0x4e, 0xe4, 0xdd, 0x7b, - 0xfe, 0x64, 0x1d, 0x03, 0xfe, 0x92, 0x00, 0xd1, 0x12, 0xfe, 0x1a, 0x10, - 0xfe, 0x4e, 0xe4, 0xfe, - 0x0b, 0x00, 0x7b, 0xfe, 0x76, 0x1d, 0x03, 0xfe, 0x94, 0x00, 0xd1, 0x24, - 0xfe, 0x08, 0x10, 0x03, - 0xfe, 0x96, 0x00, 0xd1, 0x63, 0xfe, 0x4e, 0x45, 0x83, 0xca, 0xff, 0x04, - 0x68, 0x54, 0xfe, 0xf1, - 0x10, 0x23, 0x49, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, - 0xfe, 0x1a, 0xf4, 0xfe, - 0x00, 0x04, 0x83, 0xb2, 0x1d, 0x48, 0xfe, 0xaa, 0x1d, 0x13, 0x1d, 0x02, - 0x09, 0x92, 0xfe, 0x5a, - 0xf0, 0xfe, 0xba, 0x1d, 0x2e, 0x93, 0xfe, 0x34, 0x10, 0x09, 0x12, 0xfe, - 0x5a, 0xf0, 0xfe, 0xc8, - 0x1d, 0x2e, 0xb4, 0xfe, 0x26, 0x10, 0x09, 0x1d, 0x36, 0x2e, 0x63, 0xfe, - 0x1a, 0x10, 0x09, 0x0d, - 0x36, 0x2e, 0x94, 0xf2, 0x09, 0x07, 0x36, 0x2e, 0x95, 0xa1, 0xc8, 0x02, - 0x1f, 0x93, 0x01, 0x42, - 0xfe, 0x04, 0xfe, 0x99, 0x03, 0x9c, 0x8b, 0x02, 0x2a, 0xfe, 0x1c, 0x1e, - 0xfe, 0x14, 0xf0, 0x08, - 0x2f, 0xfe, 0x0c, 0x1e, 0x2a, 0xfe, 0x1c, 0x1e, 0x8f, 0xfe, 0x1c, 0x1e, - 0xfe, 0x82, 0xf0, 0xfe, - 0x10, 0x1e, 0x02, 0x0f, 0x3f, 0x04, 0xfe, 0x80, 0x83, 0x33, 0x0b, 0x0e, - 0x02, 0x0f, 0xfe, 0x18, - 0x80, 0x04, 0xfe, 0x98, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x02, - 0x80, 0x04, 0xfe, 0x82, - 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x80, 0x04, 0xfe, 0x86, - 0x83, 0x33, 0x0b, 0x0e, - 0x02, 0x0f, 0xfe, 0x1b, 0x80, 0x04, 0xfe, 0x9b, 0x83, 0x33, 0x0b, 0x0e, - 0x02, 0x0f, 0xfe, 0x04, - 0x80, 0x04, 0xfe, 0x84, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x80, - 0x80, 0x04, 0xfe, 0x80, - 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x19, 0x81, 0x04, - 0xfe, 0x99, 0x83, 0xfe, - 0xca, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x83, 0x04, 0xfe, 0x86, - 0x83, 0xfe, 0xce, 0x47, - 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x2c, 0x90, 0x04, 0xfe, 0xac, 0x93, 0x3a, - 0x0b, 0x0e, 0x02, 0x0f, - 0xfe, 0xae, 0x90, 0x04, 0xfe, 0xae, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f, - 0xfe, 0x08, 0x90, 0x04, - 0xfe, 0x88, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x8a, 0x90, 0x04, - 0xfe, 0x8a, 0x93, 0x79, - 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x0c, 0x90, 0x04, 0xfe, 0x8c, 0x93, 0x3a, - 0x0b, 0x0e, 0x02, 0x0f, - 0xfe, 0x8e, 0x90, 0x04, 0xfe, 0x8e, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f, - 0xfe, 0x3c, 0x90, 0x04, - 0xfe, 0xbc, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x8b, 0x0f, 0xfe, 0x03, 0x80, - 0x04, 0xfe, 0x83, 0x83, - 0x33, 0x0b, 0x77, 0x0e, 0xa8, 0x02, 0xff, 0x66, 0x00, 0x00, -}; + if (asc_dvc->err_code != 0) + shost_printk(KERN_ERR, shost, "error 0x%x at init_state " + "0x%x\n", asc_dvc->err_code, asc_dvc->init_state); -static unsigned short _adv_asc38C1600_size = sizeof(_adv_asc38C1600_buf); /* 0x1673 */ -static ADV_DCNT _adv_asc38C1600_chksum = 0x0604EF77UL; /* Expanded little-endian checksum. */ + return asc_dvc->err_code; +} -/* a_init.c */ /* * EEPROM Configuration. * @@ -13847,7 +11891,7 @@ static ADV_DCNT _adv_asc38C1600_chksum = 0x0604EF77UL; /* Expanded little-endian * on big-endian platforms so char fields read as words are actually being * unswapped on big-endian platforms. */ -static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __initdata = { +static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __devinitdata = { ADV_EEPROM_BIOS_ENABLE, /* cfg_lsw */ 0x0000, /* cfg_msw */ 0xFFFF, /* disc_enable */ @@ -13885,7 +11929,7 @@ static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __initdata = { 0 /* num_of_err */ }; -static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __initdata = { +static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __devinitdata = { 0, /* cfg_lsw */ 0, /* cfg_msw */ 0, /* -disc_enable */ @@ -13923,7 +11967,7 @@ static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __initdata = { 0 /* num_of_err */ }; -static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __initdata = { +static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __devinitdata = { ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */ 0x0000, /* 01 cfg_msw */ 0xFFFF, /* 02 disc_enable */ @@ -13988,7 +12032,7 @@ static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __initdata = { 0 /* 63 reserved */ }; -static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __initdata = { +static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __devinitdata = { 0, /* 00 cfg_lsw */ 0, /* 01 cfg_msw */ 0, /* 02 disc_enable */ @@ -14053,7 +12097,7 @@ static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __initdata = { 0 /* 63 reserved */ }; -static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __initdata = { +static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __devinitdata = { ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */ 0x0000, /* 01 cfg_msw */ 0xFFFF, /* 02 disc_enable */ @@ -14118,7 +12162,7 @@ static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __initdata = { 0 /* 63 reserved */ }; -static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __initdata = { +static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __devinitdata = { 0, /* 00 cfg_lsw */ 0, /* 01 cfg_msw */ 0, /* 02 disc_enable */ @@ -14183,1944 +12227,365 @@ static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __initdata = { 0 /* 63 reserved */ }; +#ifdef CONFIG_PCI /* - * Initialize the ADV_DVC_VAR structure. - * - * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. - * - * For a non-fatal error return a warning code. If there are no warnings - * then 0 is returned. + * Wait for EEPROM command to complete */ -static int __init AdvInitGetConfig(ADV_DVC_VAR *asc_dvc) +static void __devinit AdvWaitEEPCmd(AdvPortAddr iop_base) { - ushort warn_code; - AdvPortAddr iop_base; - uchar pci_cmd_reg; - int status; - - warn_code = 0; - asc_dvc->err_code = 0; - iop_base = asc_dvc->iop_base; - - /* - * PCI Command Register - * - * Note: AscPCICmdRegBits_BusMastering definition (0x0007) includes - * I/O Space Control, Memory Space Control and Bus Master Control bits. - */ - - if (((pci_cmd_reg = DvcAdvReadPCIConfigByte(asc_dvc, - AscPCIConfigCommandRegister)) - & AscPCICmdRegBits_BusMastering) - != AscPCICmdRegBits_BusMastering) { - pci_cmd_reg |= AscPCICmdRegBits_BusMastering; - - DvcAdvWritePCIConfigByte(asc_dvc, - AscPCIConfigCommandRegister, - pci_cmd_reg); - - if (((DvcAdvReadPCIConfigByte - (asc_dvc, AscPCIConfigCommandRegister)) - & AscPCICmdRegBits_BusMastering) - != AscPCICmdRegBits_BusMastering) { - warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE; - } - } - - /* - * PCI Latency Timer - * - * If the "latency timer" register is 0x20 or above, then we don't need - * to change it. Otherwise, set it to 0x20 (i.e. set it to 0x20 if it - * comes up less than 0x20). - */ - if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) < 0x20) { - DvcAdvWritePCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer, - 0x20); - if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) < - 0x20) { - warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE; - } - } - - /* - * Save the state of the PCI Configuration Command Register - * "Parity Error Response Control" Bit. If the bit is clear (0), - * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore - * DMA parity errors. - */ - asc_dvc->cfg->control_flag = 0; - if (((DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigCommandRegister) - & AscPCICmdRegBits_ParErrRespCtrl)) == 0) { - asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR; - } - - asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) | - ADV_LIB_VERSION_MINOR; - asc_dvc->cfg->chip_version = - AdvGetChipVersion(iop_base, asc_dvc->bus_type); - - ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: 0x%x 0x%x\n", - (ushort)AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1), - (ushort)ADV_CHIP_ID_BYTE); - - ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: 0x%x 0x%x\n", - (ushort)AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0), - (ushort)ADV_CHIP_ID_WORD); - - /* - * Reset the chip to start and allow register writes. - */ - if (AdvFindSignature(iop_base) == 0) { - asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE; - return ADV_ERROR; - } else { - /* - * The caller must set 'chip_type' to a valid setting. - */ - if (asc_dvc->chip_type != ADV_CHIP_ASC3550 && - asc_dvc->chip_type != ADV_CHIP_ASC38C0800 && - asc_dvc->chip_type != ADV_CHIP_ASC38C1600) { - asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE; - return ADV_ERROR; - } - - /* - * Reset Chip. - */ - AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, - ADV_CTRL_REG_CMD_RESET); - DvcSleepMilliSecond(100); - AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, - ADV_CTRL_REG_CMD_WR_IO_REG); + int eep_delay_ms; - if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) { - if ((status = - AdvInitFrom38C1600EEP(asc_dvc)) == ADV_ERROR) { - return ADV_ERROR; - } - } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) { - if ((status = - AdvInitFrom38C0800EEP(asc_dvc)) == ADV_ERROR) { - return ADV_ERROR; - } - } else { - if ((status = AdvInitFrom3550EEP(asc_dvc)) == ADV_ERROR) { - return ADV_ERROR; - } + for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++) { + if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) & + ASC_EEP_CMD_DONE) { + break; } - warn_code |= status; + mdelay(1); } - - return warn_code; + if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) == + 0) + BUG(); } /* - * Initialize the ASC-3550. - * - * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. - * - * For a non-fatal error return a warning code. If there are no warnings - * then 0 is returned. - * - * Needed after initialization for error recovery. + * Read the EEPROM from specified location */ -static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc) +static ushort __devinit AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr) { - AdvPortAddr iop_base; - ushort warn_code; - ADV_DCNT sum; - int begin_addr; - int end_addr; - ushort code_sum; - int word; - int j; - int adv_asc3550_expanded_size; - ADV_CARR_T *carrp; - ADV_DCNT contig_len; - ADV_SDCNT buf_size; - ADV_PADDR carr_paddr; - int i; - ushort scsi_cfg1; - uchar tid; - ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */ - ushort wdtr_able = 0, sdtr_able, tagqng_able; - uchar max_cmd[ADV_MAX_TID + 1]; - - /* If there is already an error, don't continue. */ - if (asc_dvc->err_code != 0) { - return ADV_ERROR; - } + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, + ASC_EEP_CMD_READ | eep_word_addr); + AdvWaitEEPCmd(iop_base); + return AdvReadWordRegister(iop_base, IOPW_EE_DATA); +} - /* - * The caller must set 'chip_type' to ADV_CHIP_ASC3550. - */ - if (asc_dvc->chip_type != ADV_CHIP_ASC3550) { - asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE; - return ADV_ERROR; - } +/* + * Write the EEPROM from 'cfg_buf'. + */ +void __devinit +AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf) +{ + ushort *wbuf; + ushort addr, chksum; + ushort *charfields; - warn_code = 0; - iop_base = asc_dvc->iop_base; + wbuf = (ushort *)cfg_buf; + charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar; + chksum = 0; - /* - * Save the RISC memory BIOS region before writing the microcode. - * The BIOS may already be loaded and using its RISC LRAM region - * so its region must be saved and restored. - * - * Note: This code makes the assumption, which is currently true, - * that a chip reset does not clear RISC LRAM. - */ - for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) { - AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), - bios_mem[i]); - } + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE); + AdvWaitEEPCmd(iop_base); /* - * Save current per TID negotiated values. + * Write EEPROM from word 0 to word 20. */ - if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == 0x55AA) { - ushort bios_version, major, minor; - - bios_version = - bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM) / 2]; - major = (bios_version >> 12) & 0xF; - minor = (bios_version >> 8) & 0xF; - if (major < 3 || (major == 3 && minor == 1)) { - /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */ - AdvReadWordLram(iop_base, 0x120, wdtr_able); - } else { - AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); - } - } - AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); - AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); - for (tid = 0; tid <= ADV_MAX_TID; tid++) { - AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, - max_cmd[tid]); - } + for (addr = ADV_EEP_DVC_CFG_BEGIN; + addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) { + ushort word; - /* - * Load the Microcode - * - * Write the microcode image to RISC memory starting at address 0. - */ - AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0); - /* Assume the following compressed format of the microcode buffer: - * - * 254 word (508 byte) table indexed by byte code followed - * by the following byte codes: - * - * 1-Byte Code: - * 00: Emit word 0 in table. - * 01: Emit word 1 in table. - * . - * FD: Emit word 253 in table. - * - * Multi-Byte Code: - * FE WW WW: (3 byte code) Word to emit is the next word WW WW. - * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW. - */ - word = 0; - for (i = 253 * 2; i < _adv_asc3550_size; i++) { - if (_adv_asc3550_buf[i] == 0xff) { - for (j = 0; j < _adv_asc3550_buf[i + 1]; j++) { - AdvWriteWordAutoIncLram(iop_base, (((ushort) - _adv_asc3550_buf - [i + - 3] << 8) | - _adv_asc3550_buf - [i + 2])); - word++; - } - i += 3; - } else if (_adv_asc3550_buf[i] == 0xfe) { - AdvWriteWordAutoIncLram(iop_base, (((ushort) - _adv_asc3550_buf[i + - 2] - << 8) | - _adv_asc3550_buf[i + - 1])); - i += 2; - word++; + if (*charfields++) { + word = cpu_to_le16(*wbuf); } else { - AdvWriteWordAutoIncLram(iop_base, (((ushort) - _adv_asc3550_buf[(_adv_asc3550_buf[i] * 2) + 1] << 8) | _adv_asc3550_buf[_adv_asc3550_buf[i] * 2])); - word++; + word = *wbuf; } + chksum += *wbuf; /* Checksum is calculated from word values. */ + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word); + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, + ASC_EEP_CMD_WRITE | addr); + AdvWaitEEPCmd(iop_base); + mdelay(ADV_EEP_DELAY_MS); } /* - * Set 'word' for later use to clear the rest of memory and save - * the expanded mcode size. - */ - word *= 2; - adv_asc3550_expanded_size = word; - - /* - * Clear the rest of ASC-3550 Internal RAM (8KB). - */ - for (; word < ADV_3550_MEMSIZE; word += 2) { - AdvWriteWordAutoIncLram(iop_base, 0); - } - - /* - * Verify the microcode checksum. - */ - sum = 0; - AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0); - - for (word = 0; word < adv_asc3550_expanded_size; word += 2) { - sum += AdvReadWordAutoIncLram(iop_base); - } - - if (sum != _adv_asc3550_chksum) { - asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM; - return ADV_ERROR; - } - - /* - * Restore the RISC memory BIOS region. - */ - for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) { - AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), - bios_mem[i]); - } - - /* - * Calculate and write the microcode code checksum to the microcode - * code checksum location ASC_MC_CODE_CHK_SUM (0x2C). - */ - AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr); - AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr); - code_sum = 0; - AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr); - for (word = begin_addr; word < end_addr; word += 2) { - code_sum += AdvReadWordAutoIncLram(iop_base); - } - AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum); - - /* - * Read and save microcode version and date. - */ - AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, - asc_dvc->cfg->mcode_date); - AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, - asc_dvc->cfg->mcode_version); - - /* - * Set the chip type to indicate the ASC3550. - */ - AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550); - - /* - * If the PCI Configuration Command Register "Parity Error Response - * Control" Bit was clear (0), then set the microcode variable - * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode - * to ignore DMA parity errors. - */ - if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) { - AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); - word |= CONTROL_FLAG_IGNORE_PERR; - AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); - } - - /* - * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO - * threshold of 128 bytes. This register is only accessible to the host. + * Write EEPROM checksum at word 21. */ - AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0, - START_CTL_EMFU | READ_CMD_MRM); + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum); + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); + AdvWaitEEPCmd(iop_base); + wbuf++; + charfields++; /* - * Microcode operating variables for WDTR, SDTR, and command tag - * queuing will be set in AdvInquiryHandling() based on what a - * device reports it is capable of in Inquiry byte 7. - * - * If SCSI Bus Resets have been disabled, then directly set - * SDTR and WDTR from the EEPROM configuration. This will allow - * the BIOS and warm boot to work without a SCSI bus hang on - * the Inquiry caused by host and target mismatched DTR values. - * Without the SCSI Bus Reset, before an Inquiry a device can't - * be assumed to be in Asynchronous, Narrow mode. + * Write EEPROM OEM name at words 22 to 29. */ - if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) { - AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, - asc_dvc->wdtr_able); - AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, - asc_dvc->sdtr_able); - } + for (addr = ADV_EEP_DVC_CTL_BEGIN; + addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) { + ushort word; - /* - * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2, - * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID - * bitmask. These values determine the maximum SDTR speed negotiated - * with a device. - * - * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2, - * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them - * without determining here whether the device supports SDTR. - * - * 4-bit speed SDTR speed name - * =========== =============== - * 0000b (0x0) SDTR disabled - * 0001b (0x1) 5 Mhz - * 0010b (0x2) 10 Mhz - * 0011b (0x3) 20 Mhz (Ultra) - * 0100b (0x4) 40 Mhz (LVD/Ultra2) - * 0101b (0x5) 80 Mhz (LVD2/Ultra3) - * 0110b (0x6) Undefined - * . - * 1111b (0xF) Undefined - */ - word = 0; - for (tid = 0; tid <= ADV_MAX_TID; tid++) { - if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) { - /* Set Ultra speed for TID 'tid'. */ - word |= (0x3 << (4 * (tid % 4))); + if (*charfields++) { + word = cpu_to_le16(*wbuf); } else { - /* Set Fast speed for TID 'tid'. */ - word |= (0x2 << (4 * (tid % 4))); - } - if (tid == 3) { /* Check if done with sdtr_speed1. */ - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word); - word = 0; - } else if (tid == 7) { /* Check if done with sdtr_speed2. */ - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word); - word = 0; - } else if (tid == 11) { /* Check if done with sdtr_speed3. */ - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word); - word = 0; - } else if (tid == 15) { /* Check if done with sdtr_speed4. */ - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word); - /* End of loop. */ - } - } - - /* - * Set microcode operating variable for the disconnect per TID bitmask. - */ - AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, - asc_dvc->cfg->disc_enable); - - /* - * Set SCSI_CFG0 Microcode Default Value. - * - * The microcode will set the SCSI_CFG0 register using this value - * after it is started below. - */ - AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0, - PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN | - asc_dvc->chip_scsi_id); - - /* - * Determine SCSI_CFG1 Microcode Default Value. - * - * The microcode will set the SCSI_CFG1 register using this value - * after it is started below. - */ - - /* Read current SCSI_CFG1 Register value. */ - scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1); - - /* - * If all three connectors are in use, return an error. - */ - if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 || - (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) { - asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION; - return ADV_ERROR; - } - - /* - * If the internal narrow cable is reversed all of the SCSI_CTRL - * register signals will be set. Check for and return an error if - * this condition is found. - */ - if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) { - asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE; - return ADV_ERROR; - } - - /* - * If this is a differential board and a single-ended device - * is attached to one of the connectors, return an error. - */ - if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) { - asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE; - return ADV_ERROR; - } - - /* - * If automatic termination control is enabled, then set the - * termination value based on a table listed in a_condor.h. - * - * If manual termination was specified with an EEPROM setting - * then 'termination' was set-up in AdvInitFrom3550EEPROM() and - * is ready to be 'ored' into SCSI_CFG1. - */ - if (asc_dvc->cfg->termination == 0) { - /* - * The software always controls termination by setting TERM_CTL_SEL. - * If TERM_CTL_SEL were set to 0, the hardware would set termination. - */ - asc_dvc->cfg->termination |= TERM_CTL_SEL; - - switch (scsi_cfg1 & CABLE_DETECT) { - /* TERM_CTL_H: on, TERM_CTL_L: on */ - case 0x3: - case 0x7: - case 0xB: - case 0xD: - case 0xE: - case 0xF: - asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L); - break; - - /* TERM_CTL_H: on, TERM_CTL_L: off */ - case 0x1: - case 0x5: - case 0x9: - case 0xA: - case 0xC: - asc_dvc->cfg->termination |= TERM_CTL_H; - break; - - /* TERM_CTL_H: off, TERM_CTL_L: off */ - case 0x2: - case 0x6: - break; + word = *wbuf; } + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word); + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, + ASC_EEP_CMD_WRITE | addr); + AdvWaitEEPCmd(iop_base); } + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE); + AdvWaitEEPCmd(iop_base); +} - /* - * Clear any set TERM_CTL_H and TERM_CTL_L bits. - */ - scsi_cfg1 &= ~TERM_CTL; - - /* - * Invert the TERM_CTL_H and TERM_CTL_L bits and then - * set 'scsi_cfg1'. The TERM_POL bit does not need to be - * referenced, because the hardware internally inverts - * the Termination High and Low bits if TERM_POL is set. - */ - scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL)); - - /* - * Set SCSI_CFG1 Microcode Default Value - * - * Set filter value and possibly modified termination control - * bits in the Microcode SCSI_CFG1 Register Value. - * - * The microcode will set the SCSI_CFG1 register using this value - * after it is started below. - */ - AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, - FLTR_DISABLE | scsi_cfg1); +/* + * Write the EEPROM from 'cfg_buf'. + */ +void __devinit +AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf) +{ + ushort *wbuf; + ushort *charfields; + ushort addr, chksum; - /* - * Set MEM_CFG Microcode Default Value - * - * The microcode will set the MEM_CFG register using this value - * after it is started below. - * - * MEM_CFG may be accessed as a word or byte, but only bits 0-7 - * are defined. - * - * ASC-3550 has 8KB internal memory. - */ - AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG, - BIOS_EN | RAM_SZ_8KB); + wbuf = (ushort *)cfg_buf; + charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar; + chksum = 0; - /* - * Set SEL_MASK Microcode Default Value - * - * The microcode will set the SEL_MASK register using this value - * after it is started below. - */ - AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK, - ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id)); + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE); + AdvWaitEEPCmd(iop_base); /* - * Build carrier freelist. - * - * Driver must have already allocated memory and set 'carrier_buf'. + * Write EEPROM from word 0 to word 20. */ - ASC_ASSERT(asc_dvc->carrier_buf != NULL); - - carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf); - asc_dvc->carr_freelist = NULL; - if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) { - buf_size = ADV_CARRIER_BUFSIZE; - } else { - buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T); - } - - do { - /* - * Get physical address of the carrier 'carrp'. - */ - contig_len = sizeof(ADV_CARR_T); - carr_paddr = - cpu_to_le32(DvcGetPhyAddr - (asc_dvc, NULL, (uchar *)carrp, - (ADV_SDCNT *)&contig_len, - ADV_IS_CARRIER_FLAG)); - - buf_size -= sizeof(ADV_CARR_T); + for (addr = ADV_EEP_DVC_CFG_BEGIN; + addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) { + ushort word; - /* - * If the current carrier is not physically contiguous, then - * maybe there was a page crossing. Try the next carrier aligned - * start address. - */ - if (contig_len < sizeof(ADV_CARR_T)) { - carrp++; - continue; + if (*charfields++) { + word = cpu_to_le16(*wbuf); + } else { + word = *wbuf; } - - carrp->carr_pa = carr_paddr; - carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp)); - - /* - * Insert the carrier at the beginning of the freelist. - */ - carrp->next_vpa = - cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist)); - asc_dvc->carr_freelist = carrp; - - carrp++; - } - while (buf_size > 0); - - /* - * Set-up the Host->RISC Initiator Command Queue (ICQ). - */ - - if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) { - asc_dvc->err_code |= ASC_IERR_NO_CARRIER; - return ADV_ERROR; - } - asc_dvc->carr_freelist = (ADV_CARR_T *) - ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa)); - - /* - * The first command issued will be placed in the stopper carrier. - */ - asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); - - /* - * Set RISC ICQ physical address start value. - */ - AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa); - - /* - * Set-up the RISC->Host Initiator Response Queue (IRQ). - */ - if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) { - asc_dvc->err_code |= ASC_IERR_NO_CARRIER; - return ADV_ERROR; + chksum += *wbuf; /* Checksum is calculated from word values. */ + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word); + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, + ASC_EEP_CMD_WRITE | addr); + AdvWaitEEPCmd(iop_base); + mdelay(ADV_EEP_DELAY_MS); } - asc_dvc->carr_freelist = (ADV_CARR_T *) - ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa)); /* - * The first command completed by the RISC will be placed in - * the stopper. - * - * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is - * completed the RISC will set the ASC_RQ_STOPPER bit. + * Write EEPROM checksum at word 21. */ - asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum); + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); + AdvWaitEEPCmd(iop_base); + wbuf++; + charfields++; /* - * Set RISC IRQ physical address start value. + * Write EEPROM OEM name at words 22 to 29. */ - AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa); - asc_dvc->carr_pending_cnt = 0; - - AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES, - (ADV_INTR_ENABLE_HOST_INTR | - ADV_INTR_ENABLE_GLOBAL_INTR)); - - AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word); - AdvWriteWordRegister(iop_base, IOPW_PC, word); - - /* finally, finally, gentlemen, start your engine */ - AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN); + for (addr = ADV_EEP_DVC_CTL_BEGIN; + addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) { + ushort word; - /* - * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus - * Resets should be performed. The RISC has to be running - * to issue a SCSI Bus Reset. - */ - if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) { - /* - * If the BIOS Signature is present in memory, restore the - * BIOS Handshake Configuration Table and do not perform - * a SCSI Bus Reset. - */ - if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == - 0x55AA) { - /* - * Restore per TID negotiated values. - */ - AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); - AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); - AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, - tagqng_able); - for (tid = 0; tid <= ADV_MAX_TID; tid++) { - AdvWriteByteLram(iop_base, - ASC_MC_NUMBER_OF_MAX_CMD + tid, - max_cmd[tid]); - } + if (*charfields++) { + word = cpu_to_le16(*wbuf); } else { - if (AdvResetSB(asc_dvc) != ADV_TRUE) { - warn_code = ASC_WARN_BUSRESET_ERROR; - } + word = *wbuf; } + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word); + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, + ASC_EEP_CMD_WRITE | addr); + AdvWaitEEPCmd(iop_base); } - - return warn_code; + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE); + AdvWaitEEPCmd(iop_base); } /* - * Initialize the ASC-38C0800. - * - * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. - * - * For a non-fatal error return a warning code. If there are no warnings - * then 0 is returned. - * - * Needed after initialization for error recovery. + * Write the EEPROM from 'cfg_buf'. */ -static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc) +void __devinit +AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf) { - AdvPortAddr iop_base; - ushort warn_code; - ADV_DCNT sum; - int begin_addr; - int end_addr; - ushort code_sum; - int word; - int j; - int adv_asc38C0800_expanded_size; - ADV_CARR_T *carrp; - ADV_DCNT contig_len; - ADV_SDCNT buf_size; - ADV_PADDR carr_paddr; - int i; - ushort scsi_cfg1; - uchar byte; - uchar tid; - ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */ - ushort wdtr_able, sdtr_able, tagqng_able; - uchar max_cmd[ADV_MAX_TID + 1]; - - /* If there is already an error, don't continue. */ - if (asc_dvc->err_code != 0) { - return ADV_ERROR; - } - - /* - * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800. - */ - if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) { - asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE; - return ADV_ERROR; - } - - warn_code = 0; - iop_base = asc_dvc->iop_base; - - /* - * Save the RISC memory BIOS region before writing the microcode. - * The BIOS may already be loaded and using its RISC LRAM region - * so its region must be saved and restored. - * - * Note: This code makes the assumption, which is currently true, - * that a chip reset does not clear RISC LRAM. - */ - for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) { - AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), - bios_mem[i]); - } - - /* - * Save current per TID negotiated values. - */ - AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); - AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); - AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); - for (tid = 0; tid <= ADV_MAX_TID; tid++) { - AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, - max_cmd[tid]); - } - - /* - * RAM BIST (RAM Built-In Self Test) - * - * Address : I/O base + offset 0x38h register (byte). - * Function: Bit 7-6(RW) : RAM mode - * Normal Mode : 0x00 - * Pre-test Mode : 0x40 - * RAM Test Mode : 0x80 - * Bit 5 : unused - * Bit 4(RO) : Done bit - * Bit 3-0(RO) : Status - * Host Error : 0x08 - * Int_RAM Error : 0x04 - * RISC Error : 0x02 - * SCSI Error : 0x01 - * No Error : 0x00 - * - * Note: RAM BIST code should be put right here, before loading the - * microcode and after saving the RISC memory BIOS region. - */ - - /* - * LRAM Pre-test - * - * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds. - * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return - * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset - * to NORMAL_MODE, return an error too. - */ - for (i = 0; i < 2; i++) { - AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE); - DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */ - byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST); - if ((byte & RAM_TEST_DONE) == 0 - || (byte & 0x0F) != PRE_TEST_VALUE) { - asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST; - return ADV_ERROR; - } - - AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE); - DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */ - if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST) - != NORMAL_VALUE) { - asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST; - return ADV_ERROR; - } - } - - /* - * LRAM Test - It takes about 1.5 ms to run through the test. - * - * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds. - * If Done bit not set or Status not 0, save register byte, set the - * err_code, and return an error. - */ - AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE); - DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */ + ushort *wbuf; + ushort *charfields; + ushort addr, chksum; - byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST); - if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) { - /* Get here if Done bit not set or Status not 0. */ - asc_dvc->bist_err_code = byte; /* for BIOS display message */ - asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST; - return ADV_ERROR; - } + wbuf = (ushort *)cfg_buf; + charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar; + chksum = 0; - /* We need to reset back to normal mode after LRAM test passes. */ - AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE); + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE); + AdvWaitEEPCmd(iop_base); /* - * Load the Microcode - * - * Write the microcode image to RISC memory starting at address 0. - * + * Write EEPROM from word 0 to word 20. */ - AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0); + for (addr = ADV_EEP_DVC_CFG_BEGIN; + addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) { + ushort word; - /* Assume the following compressed format of the microcode buffer: - * - * 254 word (508 byte) table indexed by byte code followed - * by the following byte codes: - * - * 1-Byte Code: - * 00: Emit word 0 in table. - * 01: Emit word 1 in table. - * . - * FD: Emit word 253 in table. - * - * Multi-Byte Code: - * FE WW WW: (3 byte code) Word to emit is the next word WW WW. - * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW. - */ - word = 0; - for (i = 253 * 2; i < _adv_asc38C0800_size; i++) { - if (_adv_asc38C0800_buf[i] == 0xff) { - for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++) { - AdvWriteWordAutoIncLram(iop_base, (((ushort) - _adv_asc38C0800_buf - [i + - 3] << 8) | - _adv_asc38C0800_buf - [i + 2])); - word++; - } - i += 3; - } else if (_adv_asc38C0800_buf[i] == 0xfe) { - AdvWriteWordAutoIncLram(iop_base, (((ushort) - _adv_asc38C0800_buf - [i + - 2] << 8) | - _adv_asc38C0800_buf[i - + - 1])); - i += 2; - word++; + if (*charfields++) { + word = cpu_to_le16(*wbuf); } else { - AdvWriteWordAutoIncLram(iop_base, (((ushort) - _adv_asc38C0800_buf[(_adv_asc38C0800_buf[i] * 2) + 1] << 8) | _adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2])); - word++; - } - } - - /* - * Set 'word' for later use to clear the rest of memory and save - * the expanded mcode size. - */ - word *= 2; - adv_asc38C0800_expanded_size = word; - - /* - * Clear the rest of ASC-38C0800 Internal RAM (16KB). - */ - for (; word < ADV_38C0800_MEMSIZE; word += 2) { - AdvWriteWordAutoIncLram(iop_base, 0); - } - - /* - * Verify the microcode checksum. - */ - sum = 0; - AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0); - - for (word = 0; word < adv_asc38C0800_expanded_size; word += 2) { - sum += AdvReadWordAutoIncLram(iop_base); - } - ASC_DBG2(1, "AdvInitAsc38C0800Driver: word %d, i %d\n", word, i); - - ASC_DBG2(1, - "AdvInitAsc38C0800Driver: sum 0x%lx, _adv_asc38C0800_chksum 0x%lx\n", - (ulong)sum, (ulong)_adv_asc38C0800_chksum); - - if (sum != _adv_asc38C0800_chksum) { - asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM; - return ADV_ERROR; - } - - /* - * Restore the RISC memory BIOS region. - */ - for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) { - AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), - bios_mem[i]); - } - - /* - * Calculate and write the microcode code checksum to the microcode - * code checksum location ASC_MC_CODE_CHK_SUM (0x2C). - */ - AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr); - AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr); - code_sum = 0; - AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr); - for (word = begin_addr; word < end_addr; word += 2) { - code_sum += AdvReadWordAutoIncLram(iop_base); - } - AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum); - - /* - * Read microcode version and date. - */ - AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, - asc_dvc->cfg->mcode_date); - AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, - asc_dvc->cfg->mcode_version); - - /* - * Set the chip type to indicate the ASC38C0800. - */ - AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800); - - /* - * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register. - * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current - * cable detection and then we are able to read C_DET[3:0]. - * - * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1 - * Microcode Default Value' section below. - */ - scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1); - AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1, - scsi_cfg1 | DIS_TERM_DRV); - - /* - * If the PCI Configuration Command Register "Parity Error Response - * Control" Bit was clear (0), then set the microcode variable - * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode - * to ignore DMA parity errors. - */ - if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) { - AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); - word |= CONTROL_FLAG_IGNORE_PERR; - AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); - } - - /* - * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2] - * bits for the default FIFO threshold. - * - * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes. - * - * For DMA Errata #4 set the BC_THRESH_ENB bit. - */ - AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0, - BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH | - READ_CMD_MRM); - - /* - * Microcode operating variables for WDTR, SDTR, and command tag - * queuing will be set in AdvInquiryHandling() based on what a - * device reports it is capable of in Inquiry byte 7. - * - * If SCSI Bus Resets have been disabled, then directly set - * SDTR and WDTR from the EEPROM configuration. This will allow - * the BIOS and warm boot to work without a SCSI bus hang on - * the Inquiry caused by host and target mismatched DTR values. - * Without the SCSI Bus Reset, before an Inquiry a device can't - * be assumed to be in Asynchronous, Narrow mode. - */ - if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) { - AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, - asc_dvc->wdtr_able); - AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, - asc_dvc->sdtr_able); - } - - /* - * Set microcode operating variables for DISC and SDTR_SPEED1, - * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM - * configuration values. - * - * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2, - * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them - * without determining here whether the device supports SDTR. - */ - AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, - asc_dvc->cfg->disc_enable); - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1); - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2); - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3); - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4); - - /* - * Set SCSI_CFG0 Microcode Default Value. - * - * The microcode will set the SCSI_CFG0 register using this value - * after it is started below. - */ - AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0, - PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN | - asc_dvc->chip_scsi_id); - - /* - * Determine SCSI_CFG1 Microcode Default Value. - * - * The microcode will set the SCSI_CFG1 register using this value - * after it is started below. - */ - - /* Read current SCSI_CFG1 Register value. */ - scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1); - - /* - * If the internal narrow cable is reversed all of the SCSI_CTRL - * register signals will be set. Check for and return an error if - * this condition is found. - */ - if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) { - asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE; - return ADV_ERROR; - } - - /* - * All kind of combinations of devices attached to one of four connectors - * are acceptable except HVD device attached. For example, LVD device can - * be attached to SE connector while SE device attached to LVD connector. - * If LVD device attached to SE connector, it only runs up to Ultra speed. - * - * If an HVD device is attached to one of LVD connectors, return an error. - * However, there is no way to detect HVD device attached to SE connectors. - */ - if (scsi_cfg1 & HVD) { - asc_dvc->err_code |= ASC_IERR_HVD_DEVICE; - return ADV_ERROR; - } - - /* - * If either SE or LVD automatic termination control is enabled, then - * set the termination value based on a table listed in a_condor.h. - * - * If manual termination was specified with an EEPROM setting then - * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready to - * be 'ored' into SCSI_CFG1. - */ - if ((asc_dvc->cfg->termination & TERM_SE) == 0) { - /* SE automatic termination control is enabled. */ - switch (scsi_cfg1 & C_DET_SE) { - /* TERM_SE_HI: on, TERM_SE_LO: on */ - case 0x1: - case 0x2: - case 0x3: - asc_dvc->cfg->termination |= TERM_SE; - break; - - /* TERM_SE_HI: on, TERM_SE_LO: off */ - case 0x0: - asc_dvc->cfg->termination |= TERM_SE_HI; - break; - } - } - - if ((asc_dvc->cfg->termination & TERM_LVD) == 0) { - /* LVD automatic termination control is enabled. */ - switch (scsi_cfg1 & C_DET_LVD) { - /* TERM_LVD_HI: on, TERM_LVD_LO: on */ - case 0x4: - case 0x8: - case 0xC: - asc_dvc->cfg->termination |= TERM_LVD; - break; - - /* TERM_LVD_HI: off, TERM_LVD_LO: off */ - case 0x0: - break; - } - } - - /* - * Clear any set TERM_SE and TERM_LVD bits. - */ - scsi_cfg1 &= (~TERM_SE & ~TERM_LVD); - - /* - * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'. - */ - scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0); - - /* - * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE bits - * and set possibly modified termination control bits in the Microcode - * SCSI_CFG1 Register Value. - */ - scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE); - - /* - * Set SCSI_CFG1 Microcode Default Value - * - * Set possibly modified termination control and reset DIS_TERM_DRV - * bits in the Microcode SCSI_CFG1 Register Value. - * - * The microcode will set the SCSI_CFG1 register using this value - * after it is started below. - */ - AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1); - - /* - * Set MEM_CFG Microcode Default Value - * - * The microcode will set the MEM_CFG register using this value - * after it is started below. - * - * MEM_CFG may be accessed as a word or byte, but only bits 0-7 - * are defined. - * - * ASC-38C0800 has 16KB internal memory. - */ - AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG, - BIOS_EN | RAM_SZ_16KB); - - /* - * Set SEL_MASK Microcode Default Value - * - * The microcode will set the SEL_MASK register using this value - * after it is started below. - */ - AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK, - ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id)); - - /* - * Build the carrier freelist. - * - * Driver must have already allocated memory and set 'carrier_buf'. - */ - ASC_ASSERT(asc_dvc->carrier_buf != NULL); - - carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf); - asc_dvc->carr_freelist = NULL; - if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) { - buf_size = ADV_CARRIER_BUFSIZE; - } else { - buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T); - } - - do { - /* - * Get physical address for the carrier 'carrp'. - */ - contig_len = sizeof(ADV_CARR_T); - carr_paddr = - cpu_to_le32(DvcGetPhyAddr - (asc_dvc, NULL, (uchar *)carrp, - (ADV_SDCNT *)&contig_len, - ADV_IS_CARRIER_FLAG)); - - buf_size -= sizeof(ADV_CARR_T); - - /* - * If the current carrier is not physically contiguous, then - * maybe there was a page crossing. Try the next carrier aligned - * start address. - */ - if (contig_len < sizeof(ADV_CARR_T)) { - carrp++; - continue; + word = *wbuf; } - - carrp->carr_pa = carr_paddr; - carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp)); - - /* - * Insert the carrier at the beginning of the freelist. - */ - carrp->next_vpa = - cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist)); - asc_dvc->carr_freelist = carrp; - - carrp++; - } - while (buf_size > 0); - - /* - * Set-up the Host->RISC Initiator Command Queue (ICQ). - */ - - if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) { - asc_dvc->err_code |= ASC_IERR_NO_CARRIER; - return ADV_ERROR; - } - asc_dvc->carr_freelist = (ADV_CARR_T *) - ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa)); - - /* - * The first command issued will be placed in the stopper carrier. - */ - asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); - - /* - * Set RISC ICQ physical address start value. - * carr_pa is LE, must be native before write - */ - AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa); - - /* - * Set-up the RISC->Host Initiator Response Queue (IRQ). - */ - if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) { - asc_dvc->err_code |= ASC_IERR_NO_CARRIER; - return ADV_ERROR; + chksum += *wbuf; /* Checksum is calculated from word values. */ + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word); + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, + ASC_EEP_CMD_WRITE | addr); + AdvWaitEEPCmd(iop_base); + mdelay(ADV_EEP_DELAY_MS); } - asc_dvc->carr_freelist = (ADV_CARR_T *) - ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa)); /* - * The first command completed by the RISC will be placed in - * the stopper. - * - * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is - * completed the RISC will set the ASC_RQ_STOPPER bit. + * Write EEPROM checksum at word 21. */ - asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum); + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); + AdvWaitEEPCmd(iop_base); + wbuf++; + charfields++; /* - * Set RISC IRQ physical address start value. - * - * carr_pa is LE, must be native before write * + * Write EEPROM OEM name at words 22 to 29. */ - AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa); - asc_dvc->carr_pending_cnt = 0; - - AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES, - (ADV_INTR_ENABLE_HOST_INTR | - ADV_INTR_ENABLE_GLOBAL_INTR)); - - AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word); - AdvWriteWordRegister(iop_base, IOPW_PC, word); - - /* finally, finally, gentlemen, start your engine */ - AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN); + for (addr = ADV_EEP_DVC_CTL_BEGIN; + addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) { + ushort word; - /* - * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus - * Resets should be performed. The RISC has to be running - * to issue a SCSI Bus Reset. - */ - if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) { - /* - * If the BIOS Signature is present in memory, restore the - * BIOS Handshake Configuration Table and do not perform - * a SCSI Bus Reset. - */ - if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == - 0x55AA) { - /* - * Restore per TID negotiated values. - */ - AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); - AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); - AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, - tagqng_able); - for (tid = 0; tid <= ADV_MAX_TID; tid++) { - AdvWriteByteLram(iop_base, - ASC_MC_NUMBER_OF_MAX_CMD + tid, - max_cmd[tid]); - } + if (*charfields++) { + word = cpu_to_le16(*wbuf); } else { - if (AdvResetSB(asc_dvc) != ADV_TRUE) { - warn_code = ASC_WARN_BUSRESET_ERROR; - } + word = *wbuf; } + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word); + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, + ASC_EEP_CMD_WRITE | addr); + AdvWaitEEPCmd(iop_base); } - - return warn_code; + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE); + AdvWaitEEPCmd(iop_base); } /* - * Initialize the ASC-38C1600. - * - * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR. - * - * For a non-fatal error return a warning code. If there are no warnings - * then 0 is returned. + * Read EEPROM configuration into the specified buffer. * - * Needed after initialization for error recovery. + * Return a checksum based on the EEPROM configuration read. */ -static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc) +static ushort __devinit +AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf) { - AdvPortAddr iop_base; - ushort warn_code; - ADV_DCNT sum; - int begin_addr; - int end_addr; - ushort code_sum; - long word; - int j; - int adv_asc38C1600_expanded_size; - ADV_CARR_T *carrp; - ADV_DCNT contig_len; - ADV_SDCNT buf_size; - ADV_PADDR carr_paddr; - int i; - ushort scsi_cfg1; - uchar byte; - uchar tid; - ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */ - ushort wdtr_able, sdtr_able, ppr_able, tagqng_able; - uchar max_cmd[ASC_MAX_TID + 1]; - - /* If there is already an error, don't continue. */ - if (asc_dvc->err_code != 0) { - return ADV_ERROR; - } - - /* - * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600. - */ - if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600) { - asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE; - return ADV_ERROR; - } - - warn_code = 0; - iop_base = asc_dvc->iop_base; - - /* - * Save the RISC memory BIOS region before writing the microcode. - * The BIOS may already be loaded and using its RISC LRAM region - * so its region must be saved and restored. - * - * Note: This code makes the assumption, which is currently true, - * that a chip reset does not clear RISC LRAM. - */ - for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) { - AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), - bios_mem[i]); - } - - /* - * Save current per TID negotiated values. - */ - AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); - AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); - AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able); - AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); - for (tid = 0; tid <= ASC_MAX_TID; tid++) { - AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, - max_cmd[tid]); - } - - /* - * RAM BIST (Built-In Self Test) - * - * Address : I/O base + offset 0x38h register (byte). - * Function: Bit 7-6(RW) : RAM mode - * Normal Mode : 0x00 - * Pre-test Mode : 0x40 - * RAM Test Mode : 0x80 - * Bit 5 : unused - * Bit 4(RO) : Done bit - * Bit 3-0(RO) : Status - * Host Error : 0x08 - * Int_RAM Error : 0x04 - * RISC Error : 0x02 - * SCSI Error : 0x01 - * No Error : 0x00 - * - * Note: RAM BIST code should be put right here, before loading the - * microcode and after saving the RISC memory BIOS region. - */ + ushort wval, chksum; + ushort *wbuf; + int eep_addr; + ushort *charfields; - /* - * LRAM Pre-test - * - * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds. - * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return - * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset - * to NORMAL_MODE, return an error too. - */ - for (i = 0; i < 2; i++) { - AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE); - DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */ - byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST); - if ((byte & RAM_TEST_DONE) == 0 - || (byte & 0x0F) != PRE_TEST_VALUE) { - asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST; - return ADV_ERROR; - } + charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar; + wbuf = (ushort *)cfg_buf; + chksum = 0; - AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE); - DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */ - if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST) - != NORMAL_VALUE) { - asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST; - return ADV_ERROR; + for (eep_addr = ADV_EEP_DVC_CFG_BEGIN; + eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) { + wval = AdvReadEEPWord(iop_base, eep_addr); + chksum += wval; /* Checksum is calculated from word values. */ + if (*charfields++) { + *wbuf = le16_to_cpu(wval); + } else { + *wbuf = wval; } } + /* Read checksum word. */ + *wbuf = AdvReadEEPWord(iop_base, eep_addr); + wbuf++; + charfields++; - /* - * LRAM Test - It takes about 1.5 ms to run through the test. - * - * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds. - * If Done bit not set or Status not 0, save register byte, set the - * err_code, and return an error. - */ - AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE); - DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */ - - byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST); - if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) { - /* Get here if Done bit not set or Status not 0. */ - asc_dvc->bist_err_code = byte; /* for BIOS display message */ - asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST; - return ADV_ERROR; + /* Read rest of EEPROM not covered by the checksum. */ + for (eep_addr = ADV_EEP_DVC_CTL_BEGIN; + eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) { + *wbuf = AdvReadEEPWord(iop_base, eep_addr); + if (*charfields++) { + *wbuf = le16_to_cpu(*wbuf); + } } + return chksum; +} - /* We need to reset back to normal mode after LRAM test passes. */ - AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE); +/* + * Read EEPROM configuration into the specified buffer. + * + * Return a checksum based on the EEPROM configuration read. + */ +static ushort __devinit +AdvGet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf) +{ + ushort wval, chksum; + ushort *wbuf; + int eep_addr; + ushort *charfields; - /* - * Load the Microcode - * - * Write the microcode image to RISC memory starting at address 0. - * - */ - AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0); + charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar; + wbuf = (ushort *)cfg_buf; + chksum = 0; - /* - * Assume the following compressed format of the microcode buffer: - * - * 254 word (508 byte) table indexed by byte code followed - * by the following byte codes: - * - * 1-Byte Code: - * 00: Emit word 0 in table. - * 01: Emit word 1 in table. - * . - * FD: Emit word 253 in table. - * - * Multi-Byte Code: - * FE WW WW: (3 byte code) Word to emit is the next word WW WW. - * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW. - */ - word = 0; - for (i = 253 * 2; i < _adv_asc38C1600_size; i++) { - if (_adv_asc38C1600_buf[i] == 0xff) { - for (j = 0; j < _adv_asc38C1600_buf[i + 1]; j++) { - AdvWriteWordAutoIncLram(iop_base, (((ushort) - _adv_asc38C1600_buf - [i + - 3] << 8) | - _adv_asc38C1600_buf - [i + 2])); - word++; - } - i += 3; - } else if (_adv_asc38C1600_buf[i] == 0xfe) { - AdvWriteWordAutoIncLram(iop_base, (((ushort) - _adv_asc38C1600_buf - [i + - 2] << 8) | - _adv_asc38C1600_buf[i - + - 1])); - i += 2; - word++; + for (eep_addr = ADV_EEP_DVC_CFG_BEGIN; + eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) { + wval = AdvReadEEPWord(iop_base, eep_addr); + chksum += wval; /* Checksum is calculated from word values. */ + if (*charfields++) { + *wbuf = le16_to_cpu(wval); } else { - AdvWriteWordAutoIncLram(iop_base, (((ushort) - _adv_asc38C1600_buf[(_adv_asc38C1600_buf[i] * 2) + 1] << 8) | _adv_asc38C1600_buf[_adv_asc38C1600_buf[i] * 2])); - word++; + *wbuf = wval; } } + /* Read checksum word. */ + *wbuf = AdvReadEEPWord(iop_base, eep_addr); + wbuf++; + charfields++; - /* - * Set 'word' for later use to clear the rest of memory and save - * the expanded mcode size. - */ - word *= 2; - adv_asc38C1600_expanded_size = word; - - /* - * Clear the rest of ASC-38C1600 Internal RAM (32KB). - */ - for (; word < ADV_38C1600_MEMSIZE; word += 2) { - AdvWriteWordAutoIncLram(iop_base, 0); - } - - /* - * Verify the microcode checksum. - */ - sum = 0; - AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0); - - for (word = 0; word < adv_asc38C1600_expanded_size; word += 2) { - sum += AdvReadWordAutoIncLram(iop_base); - } - - if (sum != _adv_asc38C1600_chksum) { - asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM; - return ADV_ERROR; - } - - /* - * Restore the RISC memory BIOS region. - */ - for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) { - AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), - bios_mem[i]); - } - - /* - * Calculate and write the microcode code checksum to the microcode - * code checksum location ASC_MC_CODE_CHK_SUM (0x2C). - */ - AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr); - AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr); - code_sum = 0; - AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr); - for (word = begin_addr; word < end_addr; word += 2) { - code_sum += AdvReadWordAutoIncLram(iop_base); - } - AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum); - - /* - * Read microcode version and date. - */ - AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, - asc_dvc->cfg->mcode_date); - AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, - asc_dvc->cfg->mcode_version); - - /* - * Set the chip type to indicate the ASC38C1600. - */ - AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600); - - /* - * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register. - * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current - * cable detection and then we are able to read C_DET[3:0]. - * - * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1 - * Microcode Default Value' section below. - */ - scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1); - AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1, - scsi_cfg1 | DIS_TERM_DRV); - - /* - * If the PCI Configuration Command Register "Parity Error Response - * Control" Bit was clear (0), then set the microcode variable - * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode - * to ignore DMA parity errors. - */ - if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) { - AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); - word |= CONTROL_FLAG_IGNORE_PERR; - AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); - } - - /* - * If the BIOS control flag AIPP (Asynchronous Information - * Phase Protection) disable bit is not set, then set the firmware - * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable - * AIPP checking and encoding. - */ - if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) { - AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); - word |= CONTROL_FLAG_ENABLE_AIPP; - AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); - } - - /* - * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4], - * and START_CTL_TH [3:2]. - */ - AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0, - FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM); - - /* - * Microcode operating variables for WDTR, SDTR, and command tag - * queuing will be set in AdvInquiryHandling() based on what a - * device reports it is capable of in Inquiry byte 7. - * - * If SCSI Bus Resets have been disabled, then directly set - * SDTR and WDTR from the EEPROM configuration. This will allow - * the BIOS and warm boot to work without a SCSI bus hang on - * the Inquiry caused by host and target mismatched DTR values. - * Without the SCSI Bus Reset, before an Inquiry a device can't - * be assumed to be in Asynchronous, Narrow mode. - */ - if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) { - AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, - asc_dvc->wdtr_able); - AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, - asc_dvc->sdtr_able); - } - - /* - * Set microcode operating variables for DISC and SDTR_SPEED1, - * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM - * configuration values. - * - * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2, - * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them - * without determining here whether the device supports SDTR. - */ - AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, - asc_dvc->cfg->disc_enable); - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1); - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2); - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3); - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4); - - /* - * Set SCSI_CFG0 Microcode Default Value. - * - * The microcode will set the SCSI_CFG0 register using this value - * after it is started below. - */ - AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0, - PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN | - asc_dvc->chip_scsi_id); - - /* - * Calculate SCSI_CFG1 Microcode Default Value. - * - * The microcode will set the SCSI_CFG1 register using this value - * after it is started below. - * - * Each ASC-38C1600 function has only two cable detect bits. - * The bus mode override bits are in IOPB_SOFT_OVER_WR. - */ - scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1); - - /* - * If the cable is reversed all of the SCSI_CTRL register signals - * will be set. Check for and return an error if this condition is - * found. - */ - if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) { - asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE; - return ADV_ERROR; - } - - /* - * Each ASC-38C1600 function has two connectors. Only an HVD device - * can not be connected to either connector. An LVD device or SE device - * may be connected to either connecor. If an SE device is connected, - * then at most Ultra speed (20 Mhz) can be used on both connectors. - * - * If an HVD device is attached, return an error. - */ - if (scsi_cfg1 & HVD) { - asc_dvc->err_code |= ASC_IERR_HVD_DEVICE; - return ADV_ERROR; - } - - /* - * Each function in the ASC-38C1600 uses only the SE cable detect and - * termination because there are two connectors for each function. Each - * function may use either LVD or SE mode. Corresponding the SE automatic - * termination control EEPROM bits are used for each function. Each - * function has its own EEPROM. If SE automatic control is enabled for - * the function, then set the termination value based on a table listed - * in a_condor.h. - * - * If manual termination is specified in the EEPROM for the function, - * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is - * ready to be 'ored' into SCSI_CFG1. - */ - if ((asc_dvc->cfg->termination & TERM_SE) == 0) { - /* SE automatic termination control is enabled. */ - switch (scsi_cfg1 & C_DET_SE) { - /* TERM_SE_HI: on, TERM_SE_LO: on */ - case 0x1: - case 0x2: - case 0x3: - asc_dvc->cfg->termination |= TERM_SE; - break; - - case 0x0: - if (ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) == 0) { - /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */ - } else { - /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */ - asc_dvc->cfg->termination |= TERM_SE_HI; - } - break; + /* Read rest of EEPROM not covered by the checksum. */ + for (eep_addr = ADV_EEP_DVC_CTL_BEGIN; + eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) { + *wbuf = AdvReadEEPWord(iop_base, eep_addr); + if (*charfields++) { + *wbuf = le16_to_cpu(*wbuf); } } + return chksum; +} - /* - * Clear any set TERM_SE bits. - */ - scsi_cfg1 &= ~TERM_SE; - - /* - * Invert the TERM_SE bits and then set 'scsi_cfg1'. - */ - scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE); - - /* - * Clear Big Endian and Terminator Polarity bits and set possibly - * modified termination control bits in the Microcode SCSI_CFG1 - * Register Value. - * - * Big Endian bit is not used even on big endian machines. - */ - scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL); - - /* - * Set SCSI_CFG1 Microcode Default Value - * - * Set possibly modified termination control bits in the Microcode - * SCSI_CFG1 Register Value. - * - * The microcode will set the SCSI_CFG1 register using this value - * after it is started below. - */ - AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1); - - /* - * Set MEM_CFG Microcode Default Value - * - * The microcode will set the MEM_CFG register using this value - * after it is started below. - * - * MEM_CFG may be accessed as a word or byte, but only bits 0-7 - * are defined. - * - * ASC-38C1600 has 32KB internal memory. - * - * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come - * out a special 16K Adv Library and Microcode version. After the issue - * resolved, we should turn back to the 32K support. Both a_condor.h and - * mcode.sas files also need to be updated. - * - * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG, - * BIOS_EN | RAM_SZ_32KB); - */ - AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG, - BIOS_EN | RAM_SZ_16KB); - - /* - * Set SEL_MASK Microcode Default Value - * - * The microcode will set the SEL_MASK register using this value - * after it is started below. - */ - AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK, - ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id)); - - /* - * Build the carrier freelist. - * - * Driver must have already allocated memory and set 'carrier_buf'. - */ - - ASC_ASSERT(asc_dvc->carrier_buf != NULL); - - carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf); - asc_dvc->carr_freelist = NULL; - if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) { - buf_size = ADV_CARRIER_BUFSIZE; - } else { - buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T); - } - - do { - /* - * Get physical address for the carrier 'carrp'. - */ - contig_len = sizeof(ADV_CARR_T); - carr_paddr = - cpu_to_le32(DvcGetPhyAddr - (asc_dvc, NULL, (uchar *)carrp, - (ADV_SDCNT *)&contig_len, - ADV_IS_CARRIER_FLAG)); +/* + * Read EEPROM configuration into the specified buffer. + * + * Return a checksum based on the EEPROM configuration read. + */ +static ushort __devinit +AdvGet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf) +{ + ushort wval, chksum; + ushort *wbuf; + int eep_addr; + ushort *charfields; - buf_size -= sizeof(ADV_CARR_T); + charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar; + wbuf = (ushort *)cfg_buf; + chksum = 0; - /* - * If the current carrier is not physically contiguous, then - * maybe there was a page crossing. Try the next carrier aligned - * start address. - */ - if (contig_len < sizeof(ADV_CARR_T)) { - carrp++; - continue; + for (eep_addr = ADV_EEP_DVC_CFG_BEGIN; + eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) { + wval = AdvReadEEPWord(iop_base, eep_addr); + chksum += wval; /* Checksum is calculated from word values. */ + if (*charfields++) { + *wbuf = le16_to_cpu(wval); + } else { + *wbuf = wval; } - - carrp->carr_pa = carr_paddr; - carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp)); - - /* - * Insert the carrier at the beginning of the freelist. - */ - carrp->next_vpa = - cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist)); - asc_dvc->carr_freelist = carrp; - - carrp++; - } - while (buf_size > 0); - - /* - * Set-up the Host->RISC Initiator Command Queue (ICQ). - */ - if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) { - asc_dvc->err_code |= ASC_IERR_NO_CARRIER; - return ADV_ERROR; } - asc_dvc->carr_freelist = (ADV_CARR_T *) - ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa)); - - /* - * The first command issued will be placed in the stopper carrier. - */ - asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); - - /* - * Set RISC ICQ physical address start value. Initialize the - * COMMA register to the same value otherwise the RISC will - * prematurely detect a command is available. - */ - AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa); - AdvWriteDWordRegister(iop_base, IOPDW_COMMA, - le32_to_cpu(asc_dvc->icq_sp->carr_pa)); - - /* - * Set-up the RISC->Host Initiator Response Queue (IRQ). - */ - if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) { - asc_dvc->err_code |= ASC_IERR_NO_CARRIER; - return ADV_ERROR; - } - asc_dvc->carr_freelist = (ADV_CARR_T *) - ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa)); - - /* - * The first command completed by the RISC will be placed in - * the stopper. - * - * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is - * completed the RISC will set the ASC_RQ_STOPPER bit. - */ - asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); - - /* - * Set RISC IRQ physical address start value. - */ - AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa); - asc_dvc->carr_pending_cnt = 0; - - AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES, - (ADV_INTR_ENABLE_HOST_INTR | - ADV_INTR_ENABLE_GLOBAL_INTR)); - AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word); - AdvWriteWordRegister(iop_base, IOPW_PC, word); - - /* finally, finally, gentlemen, start your engine */ - AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN); + /* Read checksum word. */ + *wbuf = AdvReadEEPWord(iop_base, eep_addr); + wbuf++; + charfields++; - /* - * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus - * Resets should be performed. The RISC has to be running - * to issue a SCSI Bus Reset. - */ - if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) { - /* - * If the BIOS Signature is present in memory, restore the - * per TID microcode operating variables. - */ - if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == - 0x55AA) { - /* - * Restore per TID negotiated values. - */ - AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); - AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); - AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able); - AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, - tagqng_able); - for (tid = 0; tid <= ASC_MAX_TID; tid++) { - AdvWriteByteLram(iop_base, - ASC_MC_NUMBER_OF_MAX_CMD + tid, - max_cmd[tid]); - } - } else { - if (AdvResetSB(asc_dvc) != ADV_TRUE) { - warn_code = ASC_WARN_BUSRESET_ERROR; - } + /* Read rest of EEPROM not covered by the checksum. */ + for (eep_addr = ADV_EEP_DVC_CTL_BEGIN; + eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) { + *wbuf = AdvReadEEPWord(iop_base, eep_addr); + if (*charfields++) { + *wbuf = le16_to_cpu(*wbuf); } } - - return warn_code; + return chksum; } /* @@ -16135,12 +12600,11 @@ static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc) * * Note: Chip is stopped on entry. */ -static int __init AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc) +static int __devinit AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc) { AdvPortAddr iop_base; ushort warn_code; ADVEEP_3550_CONFIG eep_config; - int i; iop_base = asc_dvc->iop_base; @@ -16157,15 +12621,12 @@ static int __init AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc) /* * Set EEPROM default values. */ - for (i = 0; i < sizeof(ADVEEP_3550_CONFIG); i++) { - *((uchar *)&eep_config + i) = - *((uchar *)&Default_3550_EEPROM_Config + i); - } + memcpy(&eep_config, &Default_3550_EEPROM_Config, + sizeof(ADVEEP_3550_CONFIG)); /* - * Assume the 6 byte board serial number that was read - * from EEPROM is correct even if the EEPROM checksum - * failed. + * Assume the 6 byte board serial number that was read from + * EEPROM is correct even if the EEPROM checksum failed. */ eep_config.serial_number_word3 = AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1); @@ -16289,12 +12750,11 @@ static int __init AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc) * * Note: Chip is stopped on entry. */ -static int __init AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc) +static int __devinit AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc) { AdvPortAddr iop_base; ushort warn_code; ADVEEP_38C0800_CONFIG eep_config; - int i; uchar tid, termination; ushort sdtr_speed = 0; @@ -16314,15 +12774,12 @@ static int __init AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc) /* * Set EEPROM default values. */ - for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++) { - *((uchar *)&eep_config + i) = - *((uchar *)&Default_38C0800_EEPROM_Config + i); - } + memcpy(&eep_config, &Default_38C0800_EEPROM_Config, + sizeof(ADVEEP_38C0800_CONFIG)); /* - * Assume the 6 byte board serial number that was read - * from EEPROM is correct even if the EEPROM checksum - * failed. + * Assume the 6 byte board serial number that was read from + * EEPROM is correct even if the EEPROM checksum failed. */ eep_config.serial_number_word3 = AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1); @@ -16492,12 +12949,11 @@ static int __init AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc) * * Note: Chip is stopped on entry. */ -static int __init AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc) +static int __devinit AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc) { AdvPortAddr iop_base; ushort warn_code; ADVEEP_38C1600_CONFIG eep_config; - int i; uchar tid, termination; ushort sdtr_speed = 0; @@ -16512,75 +12968,52 @@ static int __init AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc) */ if (AdvGet38C1600EEPConfig(iop_base, &eep_config) != eep_config.check_sum) { + struct pci_dev *pdev = adv_dvc_to_pdev(asc_dvc); warn_code |= ASC_WARN_EEPROM_CHKSUM; /* * Set EEPROM default values. */ - for (i = 0; i < sizeof(ADVEEP_38C1600_CONFIG); i++) { - if (i == 1 - && ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) != - 0) { - /* - * Set Function 1 EEPROM Word 0 MSB - * - * Clear the BIOS_ENABLE (bit 14) and INTAB (bit 11) - * EEPROM bits. - * - * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60 and - * old Mac system booting problem. The Expansion ROM must - * be disabled in Function 1 for these systems. - * - */ - *((uchar *)&eep_config + i) = - ((* - ((uchar *)&Default_38C1600_EEPROM_Config - + - i)) & - (~ - (((ADV_EEPROM_BIOS_ENABLE | - ADV_EEPROM_INTAB) >> 8) & 0xFF))); + memcpy(&eep_config, &Default_38C1600_EEPROM_Config, + sizeof(ADVEEP_38C1600_CONFIG)); - /* - * Set the INTAB (bit 11) if the GPIO 0 input indicates - * the Function 1 interrupt line is wired to INTA. - * - * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input: - * 1 - Function 1 interrupt line wired to INT A. - * 0 - Function 1 interrupt line wired to INT B. - * - * Note: Adapter boards always have Function 0 wired to INTA. - * Put all 5 GPIO bits in input mode and then read - * their input values. - */ - AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL, - 0); - if (AdvReadByteRegister - (iop_base, IOPB_GPIO_DATA) & 0x01) { - /* Function 1 interrupt wired to INTA; Set EEPROM bit. */ - *((uchar *)&eep_config + i) |= - ((ADV_EEPROM_INTAB >> 8) & 0xFF); - } - } else { - *((uchar *)&eep_config + i) = - *((uchar *)&Default_38C1600_EEPROM_Config - + i); - } + if (PCI_FUNC(pdev->devfn) != 0) { + u8 ints; + /* + * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60 + * and old Mac system booting problem. The Expansion + * ROM must be disabled in Function 1 for these systems + */ + eep_config.cfg_lsw &= ~ADV_EEPROM_BIOS_ENABLE; + /* + * Clear the INTAB (bit 11) if the GPIO 0 input + * indicates the Function 1 interrupt line is wired + * to INTB. + * + * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input: + * 1 - Function 1 interrupt line wired to INT A. + * 0 - Function 1 interrupt line wired to INT B. + * + * Note: Function 0 is always wired to INTA. + * Put all 5 GPIO bits in input mode and then read + * their input values. + */ + AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL, 0); + ints = AdvReadByteRegister(iop_base, IOPB_GPIO_DATA); + if ((ints & 0x01) == 0) + eep_config.cfg_lsw &= ~ADV_EEPROM_INTAB; } /* - * Assume the 6 byte board serial number that was read - * from EEPROM is correct even if the EEPROM checksum - * failed. + * Assume the 6 byte board serial number that was read from + * EEPROM is correct even if the EEPROM checksum failed. */ eep_config.serial_number_word3 = - AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1); - + AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1); eep_config.serial_number_word2 = - AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2); - + AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2); eep_config.serial_number_word1 = - AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3); + AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3); AdvSet38C1600EEPConfig(iop_base, &eep_config); } @@ -16729,1176 +13162,281 @@ static int __init AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc) } /* - * Read EEPROM configuration into the specified buffer. - * - * Return a checksum based on the EEPROM configuration read. - */ -static ushort __init -AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf) -{ - ushort wval, chksum; - ushort *wbuf; - int eep_addr; - ushort *charfields; - - charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar; - wbuf = (ushort *)cfg_buf; - chksum = 0; - - for (eep_addr = ADV_EEP_DVC_CFG_BEGIN; - eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) { - wval = AdvReadEEPWord(iop_base, eep_addr); - chksum += wval; /* Checksum is calculated from word values. */ - if (*charfields++) { - *wbuf = le16_to_cpu(wval); - } else { - *wbuf = wval; - } - } - /* Read checksum word. */ - *wbuf = AdvReadEEPWord(iop_base, eep_addr); - wbuf++; - charfields++; - - /* Read rest of EEPROM not covered by the checksum. */ - for (eep_addr = ADV_EEP_DVC_CTL_BEGIN; - eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) { - *wbuf = AdvReadEEPWord(iop_base, eep_addr); - if (*charfields++) { - *wbuf = le16_to_cpu(*wbuf); - } - } - return chksum; -} - -/* - * Read EEPROM configuration into the specified buffer. + * Initialize the ADV_DVC_VAR structure. * - * Return a checksum based on the EEPROM configuration read. - */ -static ushort __init -AdvGet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf) -{ - ushort wval, chksum; - ushort *wbuf; - int eep_addr; - ushort *charfields; - - charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar; - wbuf = (ushort *)cfg_buf; - chksum = 0; - - for (eep_addr = ADV_EEP_DVC_CFG_BEGIN; - eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) { - wval = AdvReadEEPWord(iop_base, eep_addr); - chksum += wval; /* Checksum is calculated from word values. */ - if (*charfields++) { - *wbuf = le16_to_cpu(wval); - } else { - *wbuf = wval; - } - } - /* Read checksum word. */ - *wbuf = AdvReadEEPWord(iop_base, eep_addr); - wbuf++; - charfields++; - - /* Read rest of EEPROM not covered by the checksum. */ - for (eep_addr = ADV_EEP_DVC_CTL_BEGIN; - eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) { - *wbuf = AdvReadEEPWord(iop_base, eep_addr); - if (*charfields++) { - *wbuf = le16_to_cpu(*wbuf); - } - } - return chksum; -} - -/* - * Read EEPROM configuration into the specified buffer. + * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. * - * Return a checksum based on the EEPROM configuration read. - */ -static ushort __init -AdvGet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf) -{ - ushort wval, chksum; - ushort *wbuf; - int eep_addr; - ushort *charfields; - - charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar; - wbuf = (ushort *)cfg_buf; - chksum = 0; - - for (eep_addr = ADV_EEP_DVC_CFG_BEGIN; - eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) { - wval = AdvReadEEPWord(iop_base, eep_addr); - chksum += wval; /* Checksum is calculated from word values. */ - if (*charfields++) { - *wbuf = le16_to_cpu(wval); - } else { - *wbuf = wval; - } - } - /* Read checksum word. */ - *wbuf = AdvReadEEPWord(iop_base, eep_addr); - wbuf++; - charfields++; - - /* Read rest of EEPROM not covered by the checksum. */ - for (eep_addr = ADV_EEP_DVC_CTL_BEGIN; - eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) { - *wbuf = AdvReadEEPWord(iop_base, eep_addr); - if (*charfields++) { - *wbuf = le16_to_cpu(*wbuf); - } - } - return chksum; -} - -/* - * Read the EEPROM from specified location - */ -static ushort __init AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr) -{ - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, - ASC_EEP_CMD_READ | eep_word_addr); - AdvWaitEEPCmd(iop_base); - return AdvReadWordRegister(iop_base, IOPW_EE_DATA); -} - -/* - * Wait for EEPROM command to complete - */ -static void __init AdvWaitEEPCmd(AdvPortAddr iop_base) -{ - int eep_delay_ms; - - for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++) { - if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) & - ASC_EEP_CMD_DONE) { - break; - } - DvcSleepMilliSecond(1); - } - if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) == - 0) { - ASC_ASSERT(0); - } - return; -} - -/* - * Write the EEPROM from 'cfg_buf'. + * For a non-fatal error return a warning code. If there are no warnings + * then 0 is returned. */ -void __init -AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf) +static int __devinit +AdvInitGetConfig(struct pci_dev *pdev, struct Scsi_Host *shost) { - ushort *wbuf; - ushort addr, chksum; - ushort *charfields; - - wbuf = (ushort *)cfg_buf; - charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar; - chksum = 0; - - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE); - AdvWaitEEPCmd(iop_base); - - /* - * Write EEPROM from word 0 to word 20. - */ - for (addr = ADV_EEP_DVC_CFG_BEGIN; - addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) { - ushort word; - - if (*charfields++) { - word = cpu_to_le16(*wbuf); - } else { - word = *wbuf; - } - chksum += *wbuf; /* Checksum is calculated from word values. */ - AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word); - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, - ASC_EEP_CMD_WRITE | addr); - AdvWaitEEPCmd(iop_base); - DvcSleepMilliSecond(ADV_EEP_DELAY_MS); - } + struct asc_board *board = shost_priv(shost); + ADV_DVC_VAR *asc_dvc = &board->dvc_var.adv_dvc_var; + unsigned short warn_code = 0; + AdvPortAddr iop_base = asc_dvc->iop_base; + u16 cmd; + int status; - /* - * Write EEPROM checksum at word 21. - */ - AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum); - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); - AdvWaitEEPCmd(iop_base); - wbuf++; - charfields++; + asc_dvc->err_code = 0; /* - * Write EEPROM OEM name at words 22 to 29. + * Save the state of the PCI Configuration Command Register + * "Parity Error Response Control" Bit. If the bit is clear (0), + * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore + * DMA parity errors. */ - for (addr = ADV_EEP_DVC_CTL_BEGIN; - addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) { - ushort word; - - if (*charfields++) { - word = cpu_to_le16(*wbuf); - } else { - word = *wbuf; - } - AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word); - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, - ASC_EEP_CMD_WRITE | addr); - AdvWaitEEPCmd(iop_base); - } - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE); - AdvWaitEEPCmd(iop_base); - return; -} - -/* - * Write the EEPROM from 'cfg_buf'. - */ -void __init -AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf) -{ - ushort *wbuf; - ushort *charfields; - ushort addr, chksum; - - wbuf = (ushort *)cfg_buf; - charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar; - chksum = 0; - - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE); - AdvWaitEEPCmd(iop_base); + asc_dvc->cfg->control_flag = 0; + pci_read_config_word(pdev, PCI_COMMAND, &cmd); + if ((cmd & PCI_COMMAND_PARITY) == 0) + asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR; - /* - * Write EEPROM from word 0 to word 20. - */ - for (addr = ADV_EEP_DVC_CFG_BEGIN; - addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) { - ushort word; + asc_dvc->cfg->chip_version = + AdvGetChipVersion(iop_base, asc_dvc->bus_type); - if (*charfields++) { - word = cpu_to_le16(*wbuf); - } else { - word = *wbuf; - } - chksum += *wbuf; /* Checksum is calculated from word values. */ - AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word); - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, - ASC_EEP_CMD_WRITE | addr); - AdvWaitEEPCmd(iop_base); - DvcSleepMilliSecond(ADV_EEP_DELAY_MS); - } + ASC_DBG(1, "iopb_chip_id_1: 0x%x 0x%x\n", + (ushort)AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1), + (ushort)ADV_CHIP_ID_BYTE); - /* - * Write EEPROM checksum at word 21. - */ - AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum); - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); - AdvWaitEEPCmd(iop_base); - wbuf++; - charfields++; + ASC_DBG(1, "iopw_chip_id_0: 0x%x 0x%x\n", + (ushort)AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0), + (ushort)ADV_CHIP_ID_WORD); /* - * Write EEPROM OEM name at words 22 to 29. + * Reset the chip to start and allow register writes. */ - for (addr = ADV_EEP_DVC_CTL_BEGIN; - addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) { - ushort word; - - if (*charfields++) { - word = cpu_to_le16(*wbuf); - } else { - word = *wbuf; + if (AdvFindSignature(iop_base) == 0) { + asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE; + return ADV_ERROR; + } else { + /* + * The caller must set 'chip_type' to a valid setting. + */ + if (asc_dvc->chip_type != ADV_CHIP_ASC3550 && + asc_dvc->chip_type != ADV_CHIP_ASC38C0800 && + asc_dvc->chip_type != ADV_CHIP_ASC38C1600) { + asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE; + return ADV_ERROR; } - AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word); - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, - ASC_EEP_CMD_WRITE | addr); - AdvWaitEEPCmd(iop_base); - } - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE); - AdvWaitEEPCmd(iop_base); - return; -} -/* - * Write the EEPROM from 'cfg_buf'. - */ -void __init -AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf) -{ - ushort *wbuf; - ushort *charfields; - ushort addr, chksum; - - wbuf = (ushort *)cfg_buf; - charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar; - chksum = 0; - - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE); - AdvWaitEEPCmd(iop_base); - - /* - * Write EEPROM from word 0 to word 20. - */ - for (addr = ADV_EEP_DVC_CFG_BEGIN; - addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) { - ushort word; + /* + * Reset Chip. + */ + AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, + ADV_CTRL_REG_CMD_RESET); + mdelay(100); + AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, + ADV_CTRL_REG_CMD_WR_IO_REG); - if (*charfields++) { - word = cpu_to_le16(*wbuf); + if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) { + status = AdvInitFrom38C1600EEP(asc_dvc); + } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) { + status = AdvInitFrom38C0800EEP(asc_dvc); } else { - word = *wbuf; + status = AdvInitFrom3550EEP(asc_dvc); } - chksum += *wbuf; /* Checksum is calculated from word values. */ - AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word); - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, - ASC_EEP_CMD_WRITE | addr); - AdvWaitEEPCmd(iop_base); - DvcSleepMilliSecond(ADV_EEP_DELAY_MS); + warn_code |= status; } - /* - * Write EEPROM checksum at word 21. - */ - AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum); - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); - AdvWaitEEPCmd(iop_base); - wbuf++; - charfields++; + if (warn_code != 0) + shost_printk(KERN_WARNING, shost, "warning: 0x%x\n", warn_code); - /* - * Write EEPROM OEM name at words 22 to 29. - */ - for (addr = ADV_EEP_DVC_CTL_BEGIN; - addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) { - ushort word; + if (asc_dvc->err_code) + shost_printk(KERN_ERR, shost, "error code 0x%x\n", + asc_dvc->err_code); - if (*charfields++) { - word = cpu_to_le16(*wbuf); - } else { - word = *wbuf; - } - AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word); - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, - ASC_EEP_CMD_WRITE | addr); - AdvWaitEEPCmd(iop_base); - } - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE); - AdvWaitEEPCmd(iop_base); - return; + return asc_dvc->err_code; } +#endif -/* a_advlib.c */ -/* - * AdvExeScsiQueue() - Send a request to the RISC microcode program. - * - * Allocate a carrier structure, point the carrier to the ADV_SCSI_REQ_Q, - * add the carrier to the ICQ (Initiator Command Queue), and tickle the - * RISC to notify it a new command is ready to be executed. - * - * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be - * set to SCSI_MAX_RETRY. - * - * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the microcode - * for DMA addresses or math operations are byte swapped to little-endian - * order. - * - * Return: - * ADV_SUCCESS(1) - The request was successfully queued. - * ADV_BUSY(0) - Resource unavailable; Retry again after pending - * request completes. - * ADV_ERROR(-1) - Invalid ADV_SCSI_REQ_Q request structure - * host IC error. - */ -static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq) -{ - ulong last_int_level; - AdvPortAddr iop_base; - ADV_DCNT req_size; - ADV_PADDR req_paddr; - ADV_CARR_T *new_carrp; - - ASC_ASSERT(scsiq != NULL); /* 'scsiq' should never be NULL. */ - - /* - * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID. - */ - if (scsiq->target_id > ADV_MAX_TID) { - scsiq->host_status = QHSTA_M_INVALID_DEVICE; - scsiq->done_status = QD_WITH_ERROR; - return ADV_ERROR; - } - - iop_base = asc_dvc->iop_base; - - last_int_level = DvcEnterCritical(); - - /* - * Allocate a carrier ensuring at least one carrier always - * remains on the freelist and initialize fields. - */ - if ((new_carrp = asc_dvc->carr_freelist) == NULL) { - DvcLeaveCritical(last_int_level); - return ADV_BUSY; - } - asc_dvc->carr_freelist = (ADV_CARR_T *) - ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa)); - asc_dvc->carr_pending_cnt++; - - /* - * Set the carrier to be a stopper by setting 'next_vpa' - * to the stopper value. The current stopper will be changed - * below to point to the new stopper. - */ - new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); - - /* - * Clear the ADV_SCSI_REQ_Q done flag. - */ - scsiq->a_flag &= ~ADV_SCSIQ_DONE; - - req_size = sizeof(ADV_SCSI_REQ_Q); - req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *)scsiq, - (ADV_SDCNT *)&req_size, ADV_IS_SCSIQ_FLAG); - - ASC_ASSERT(ADV_32BALIGN(req_paddr) == req_paddr); - ASC_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q)); - - /* Wait for assertion before making little-endian */ - req_paddr = cpu_to_le32(req_paddr); - - /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */ - scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq)); - scsiq->scsiq_rptr = req_paddr; - - scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp)); - /* - * Every ADV_CARR_T.carr_pa is byte swapped to little-endian - * order during initialization. - */ - scsiq->carr_pa = asc_dvc->icq_sp->carr_pa; - - /* - * Use the current stopper to send the ADV_SCSI_REQ_Q command to - * the microcode. The newly allocated stopper will become the new - * stopper. - */ - asc_dvc->icq_sp->areq_vpa = req_paddr; - +static struct scsi_host_template advansys_template = { + .proc_name = DRV_NAME, +#ifdef CONFIG_PROC_FS + .proc_info = advansys_proc_info, +#endif + .name = DRV_NAME, + .info = advansys_info, + .queuecommand = advansys_queuecommand, + .eh_bus_reset_handler = advansys_reset, + .bios_param = advansys_biosparam, + .slave_configure = advansys_slave_configure, /* - * Set the 'next_vpa' pointer for the old stopper to be the - * physical address of the new stopper. The RISC can only - * follow physical addresses. + * Because the driver may control an ISA adapter 'unchecked_isa_dma' + * must be set. The flag will be cleared in advansys_board_found + * for non-ISA adapters. */ - asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa; - + .unchecked_isa_dma = 1, /* - * Set the host adapter stopper pointer to point to the new carrier. + * All adapters controlled by this driver are capable of large + * scatter-gather lists. According to the mid-level SCSI documentation + * this obviates any performance gain provided by setting + * 'use_clustering'. But empirically while CPU utilization is increased + * by enabling clustering, I/O throughput increases as well. */ - asc_dvc->icq_sp = new_carrp; - - if (asc_dvc->chip_type == ADV_CHIP_ASC3550 || - asc_dvc->chip_type == ADV_CHIP_ASC38C0800) { - /* - * Tickle the RISC to tell it to read its Command Queue Head pointer. - */ - AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A); - if (asc_dvc->chip_type == ADV_CHIP_ASC3550) { - /* - * Clear the tickle value. In the ASC-3550 the RISC flag - * command 'clr_tickle_a' does not work unless the host - * value is cleared. - */ - AdvWriteByteRegister(iop_base, IOPB_TICKLE, - ADV_TICKLE_NOP); - } - } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) { - /* - * Notify the RISC a carrier is ready by writing the physical - * address of the new carrier stopper to the COMMA register. - */ - AdvWriteDWordRegister(iop_base, IOPDW_COMMA, - le32_to_cpu(new_carrp->carr_pa)); - } - - DvcLeaveCritical(last_int_level); - - return ADV_SUCCESS; -} + .use_clustering = ENABLE_CLUSTERING, +}; -/* - * Reset SCSI Bus and purge all outstanding requests. - * - * Return Value: - * ADV_TRUE(1) - All requests are purged and SCSI Bus is reset. - * ADV_FALSE(0) - Microcode command failed. - * ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC - * may be hung which requires driver recovery. - */ -static int AdvResetSB(ADV_DVC_VAR *asc_dvc) +static int __devinit advansys_wide_init_chip(struct Scsi_Host *shost) { - int status; + struct asc_board *board = shost_priv(shost); + struct adv_dvc_var *adv_dvc = &board->dvc_var.adv_dvc_var; + int req_cnt = 0; + adv_req_t *reqp = NULL; + int sg_cnt = 0; + adv_sgblk_t *sgp; + int warn_code, err_code; /* - * Send the SCSI Bus Reset idle start idle command which asserts - * the SCSI Bus Reset signal. + * Allocate buffer carrier structures. The total size + * is about 4 KB, so allocate all at once. */ - status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_START, 0L); - if (status != ADV_TRUE) { - return status; - } + adv_dvc->carrier_buf = kmalloc(ADV_CARRIER_BUFSIZE, GFP_KERNEL); + ASC_DBG(1, "carrier_buf 0x%p\n", adv_dvc->carrier_buf); - /* - * Delay for the specified SCSI Bus Reset hold time. - * - * The hold time delay is done on the host because the RISC has no - * microsecond accurate timer. - */ - DvcDelayMicroSecond(asc_dvc, (ushort)ASC_SCSI_RESET_HOLD_TIME_US); + if (!adv_dvc->carrier_buf) + goto kmalloc_failed; /* - * Send the SCSI Bus Reset end idle command which de-asserts - * the SCSI Bus Reset signal and purges any pending requests. + * Allocate up to 'max_host_qng' request structures for the Wide + * board. The total size is about 16 KB, so allocate all at once. + * If the allocation fails decrement and try again. */ - status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_END, 0L); - if (status != ADV_TRUE) { - return status; - } - - DvcSleepMilliSecond((ADV_DCNT)asc_dvc->scsi_reset_wait * 1000); - - return status; -} - -/* - * Reset chip and SCSI Bus. - * - * Return Value: - * ADV_TRUE(1) - Chip re-initialization and SCSI Bus Reset successful. - * ADV_FALSE(0) - Chip re-initialization and SCSI Bus Reset failure. - */ -static int AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc) -{ - int status; - ushort wdtr_able, sdtr_able, tagqng_able; - ushort ppr_able = 0; - uchar tid, max_cmd[ADV_MAX_TID + 1]; - AdvPortAddr iop_base; - ushort bios_sig; + for (req_cnt = adv_dvc->max_host_qng; req_cnt > 0; req_cnt--) { + reqp = kmalloc(sizeof(adv_req_t) * req_cnt, GFP_KERNEL); - iop_base = asc_dvc->iop_base; + ASC_DBG(1, "reqp 0x%p, req_cnt %d, bytes %lu\n", reqp, req_cnt, + (ulong)sizeof(adv_req_t) * req_cnt); - /* - * Save current per TID negotiated values. - */ - AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); - AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); - if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) { - AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able); - } - AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); - for (tid = 0; tid <= ADV_MAX_TID; tid++) { - AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, - max_cmd[tid]); + if (reqp) + break; } - /* - * Force the AdvInitAsc3550/38C0800Driver() function to - * perform a SCSI Bus Reset by clearing the BIOS signature word. - * The initialization functions assumes a SCSI Bus Reset is not - * needed if the BIOS signature word is present. - */ - AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig); - AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0); + if (!reqp) + goto kmalloc_failed; - /* - * Stop chip and reset it. - */ - AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP); - AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET); - DvcSleepMilliSecond(100); - AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, - ADV_CTRL_REG_CMD_WR_IO_REG); + adv_dvc->orig_reqp = reqp; /* - * Reset Adv Library error code, if any, and try - * re-initializing the chip. + * Allocate up to ADV_TOT_SG_BLOCK request structures for + * the Wide board. Each structure is about 136 bytes. */ - asc_dvc->err_code = 0; - if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) { - status = AdvInitAsc38C1600Driver(asc_dvc); - } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) { - status = AdvInitAsc38C0800Driver(asc_dvc); - } else { - status = AdvInitAsc3550Driver(asc_dvc); - } + board->adv_sgblkp = NULL; + for (sg_cnt = 0; sg_cnt < ADV_TOT_SG_BLOCK; sg_cnt++) { + sgp = kmalloc(sizeof(adv_sgblk_t), GFP_KERNEL); - /* Translate initialization return value to status value. */ - if (status == 0) { - status = ADV_TRUE; - } else { - status = ADV_FALSE; - } + if (!sgp) + break; - /* - * Restore the BIOS signature word. - */ - AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig); + sgp->next_sgblkp = board->adv_sgblkp; + board->adv_sgblkp = sgp; - /* - * Restore per TID negotiated values. - */ - AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); - AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); - if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) { - AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able); } - AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); - for (tid = 0; tid <= ADV_MAX_TID; tid++) { - AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, - max_cmd[tid]); - } - - return status; -} - -/* - * Adv Library Interrupt Service Routine - * - * This function is called by a driver's interrupt service routine. - * The function disables and re-enables interrupts. - * - * When a microcode idle command is completed, the ADV_DVC_VAR - * 'idle_cmd_done' field is set to ADV_TRUE. - * - * Note: AdvISR() can be called when interrupts are disabled or even - * when there is no hardware interrupt condition present. It will - * always check for completed idle commands and microcode requests. - * This is an important feature that shouldn't be changed because it - * allows commands to be completed from polling mode loops. - * - * Return: - * ADV_TRUE(1) - interrupt was pending - * ADV_FALSE(0) - no interrupt was pending - */ -static int AdvISR(ADV_DVC_VAR *asc_dvc) -{ - AdvPortAddr iop_base; - uchar int_stat; - ushort target_bit; - ADV_CARR_T *free_carrp; - ADV_VADDR irq_next_vpa; - int flags; - ADV_SCSI_REQ_Q *scsiq; - - flags = DvcEnterCritical(); - - iop_base = asc_dvc->iop_base; - /* Reading the register clears the interrupt. */ - int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG); + ASC_DBG(1, "sg_cnt %d * %lu = %lu bytes\n", sg_cnt, sizeof(adv_sgblk_t), + sizeof(adv_sgblk_t) * sg_cnt); - if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB | - ADV_INTR_STATUS_INTRC)) == 0) { - DvcLeaveCritical(flags); - return ADV_FALSE; - } + if (!board->adv_sgblkp) + goto kmalloc_failed; /* - * Notify the driver of an asynchronous microcode condition by - * calling the ADV_DVC_VAR.async_callback function. The function - * is passed the microcode ASC_MC_INTRB_CODE byte value. + * Point 'adv_reqp' to the request structures and + * link them together. */ - if (int_stat & ADV_INTR_STATUS_INTRB) { - uchar intrb_code; - - AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code); - - if (asc_dvc->chip_type == ADV_CHIP_ASC3550 || - asc_dvc->chip_type == ADV_CHIP_ASC38C0800) { - if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE && - asc_dvc->carr_pending_cnt != 0) { - AdvWriteByteRegister(iop_base, IOPB_TICKLE, - ADV_TICKLE_A); - if (asc_dvc->chip_type == ADV_CHIP_ASC3550) { - AdvWriteByteRegister(iop_base, - IOPB_TICKLE, - ADV_TICKLE_NOP); - } - } - } - - if (asc_dvc->async_callback != 0) { - (*asc_dvc->async_callback) (asc_dvc, intrb_code); - } + req_cnt--; + reqp[req_cnt].next_reqp = NULL; + for (; req_cnt > 0; req_cnt--) { + reqp[req_cnt - 1].next_reqp = &reqp[req_cnt]; } + board->adv_reqp = &reqp[0]; - /* - * Check if the IRQ stopper carrier contains a completed request. - */ - while (((irq_next_vpa = - le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0) { - /* - * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure. - * The RISC will have set 'areq_vpa' to a virtual address. - * - * The firmware will have copied the ASC_SCSI_REQ_Q.scsiq_ptr - * field to the carrier ADV_CARR_T.areq_vpa field. The conversion - * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr' - * in AdvExeScsiQueue(). - */ - scsiq = (ADV_SCSI_REQ_Q *) - ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa)); - - /* - * Request finished with good status and the queue was not - * DMAed to host memory by the firmware. Set all status fields - * to indicate good status. - */ - if ((irq_next_vpa & ASC_RQ_GOOD) != 0) { - scsiq->done_status = QD_NO_ERROR; - scsiq->host_status = scsiq->scsi_status = 0; - scsiq->data_cnt = 0L; - } - - /* - * Advance the stopper pointer to the next carrier - * ignoring the lower four bits. Free the previous - * stopper carrier. - */ - free_carrp = asc_dvc->irq_sp; - asc_dvc->irq_sp = (ADV_CARR_T *) - ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa)); - - free_carrp->next_vpa = - cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist)); - asc_dvc->carr_freelist = free_carrp; - asc_dvc->carr_pending_cnt--; - - ASC_ASSERT(scsiq != NULL); - target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id); - - /* - * Clear request microcode control flag. - */ - scsiq->cntl = 0; - - /* - * If the command that completed was a SCSI INQUIRY and - * LUN 0 was sent the command, then process the INQUIRY - * command information for the device. - * - * Note: If data returned were either VPD or CmdDt data, - * don't process the INQUIRY command information for - * the device, otherwise may erroneously set *_able bits. - */ - if (scsiq->done_status == QD_NO_ERROR && - scsiq->cdb[0] == INQUIRY && - scsiq->target_lun == 0 && - (scsiq->cdb[1] & ADV_INQ_RTN_VPD_AND_CMDDT) - == ADV_INQ_RTN_STD_INQUIRY_DATA) { - AdvInquiryHandling(asc_dvc, scsiq); - } - - /* - * Notify the driver of the completed request by passing - * the ADV_SCSI_REQ_Q pointer to its callback function. - */ - scsiq->a_flag |= ADV_SCSIQ_DONE; - (*asc_dvc->isr_callback) (asc_dvc, scsiq); - /* - * Note: After the driver callback function is called, 'scsiq' - * can no longer be referenced. - * - * Fall through and continue processing other completed - * requests... - */ - - /* - * Disable interrupts again in case the driver inadvertently - * enabled interrupts in its callback function. - * - * The DvcEnterCritical() return value is ignored, because - * the 'flags' saved when AdvISR() was first entered will be - * used to restore the interrupt flag on exit. - */ - (void)DvcEnterCritical(); + if (adv_dvc->chip_type == ADV_CHIP_ASC3550) { + ASC_DBG(2, "AdvInitAsc3550Driver()\n"); + warn_code = AdvInitAsc3550Driver(adv_dvc); + } else if (adv_dvc->chip_type == ADV_CHIP_ASC38C0800) { + ASC_DBG(2, "AdvInitAsc38C0800Driver()\n"); + warn_code = AdvInitAsc38C0800Driver(adv_dvc); + } else { + ASC_DBG(2, "AdvInitAsc38C1600Driver()\n"); + warn_code = AdvInitAsc38C1600Driver(adv_dvc); } - DvcLeaveCritical(flags); - return ADV_TRUE; -} + err_code = adv_dvc->err_code; -/* - * Send an idle command to the chip and wait for completion. - * - * Command completion is polled for once per microsecond. - * - * The function can be called from anywhere including an interrupt handler. - * But the function is not re-entrant, so it uses the DvcEnter/LeaveCritical() - * functions to prevent reentrancy. - * - * Return Values: - * ADV_TRUE - command completed successfully - * ADV_FALSE - command failed - * ADV_ERROR - command timed out - */ -static int -AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc, - ushort idle_cmd, ADV_DCNT idle_cmd_parameter) -{ - ulong last_int_level; - int result; - ADV_DCNT i, j; - AdvPortAddr iop_base; - - last_int_level = DvcEnterCritical(); - - iop_base = asc_dvc->iop_base; - - /* - * Clear the idle command status which is set by the microcode - * to a non-zero value to indicate when the command is completed. - * The non-zero result is one of the IDLE_CMD_STATUS_* values - * defined in a_advlib.h. - */ - AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort)0); - - /* - * Write the idle command value after the idle command parameter - * has been written to avoid a race condition. If the order is not - * followed, the microcode may process the idle command before the - * parameters have been written to LRAM. - */ - AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER, - cpu_to_le32(idle_cmd_parameter)); - AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd); - - /* - * Tickle the RISC to tell it to process the idle command. - */ - AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B); - if (asc_dvc->chip_type == ADV_CHIP_ASC3550) { - /* - * Clear the tickle value. In the ASC-3550 the RISC flag - * command 'clr_tickle_b' does not work unless the host - * value is cleared. - */ - AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP); + if (warn_code || err_code) { + shost_printk(KERN_WARNING, shost, "error: warn 0x%x, error " + "0x%x\n", warn_code, err_code); } - /* Wait for up to 100 millisecond for the idle command to timeout. */ - for (i = 0; i < SCSI_WAIT_100_MSEC; i++) { - /* Poll once each microsecond for command completion. */ - for (j = 0; j < SCSI_US_PER_MSEC; j++) { - AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, - result); - if (result != 0) { - DvcLeaveCritical(last_int_level); - return result; - } - DvcDelayMicroSecond(asc_dvc, (ushort)1); - } - } + goto exit; - ASC_ASSERT(0); /* The idle command should never timeout. */ - DvcLeaveCritical(last_int_level); - return ADV_ERROR; + kmalloc_failed: + shost_printk(KERN_ERR, shost, "error: kmalloc() failed\n"); + err_code = ADV_ERROR; + exit: + return err_code; } -/* - * Inquiry Information Byte 7 Handling - * - * Handle SCSI Inquiry Command information for a device by setting - * microcode operating variables that affect WDTR, SDTR, and Tag - * Queuing. - */ -static void AdvInquiryHandling(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq) +static void advansys_wide_free_mem(struct asc_board *board) { - AdvPortAddr iop_base; - uchar tid; - ADV_SCSI_INQUIRY *inq; - ushort tidmask; - ushort cfg_word; - - /* - * AdvInquiryHandling() requires up to INQUIRY information Byte 7 - * to be available. - * - * If less than 8 bytes of INQUIRY information were requested or less - * than 8 bytes were transferred, then return. cdb[4] is the request - * length and the ADV_SCSI_REQ_Q 'data_cnt' field is set by the - * microcode to the transfer residual count. - */ - - if (scsiq->cdb[4] < 8 || - (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) < 8) { - return; - } - - iop_base = asc_dvc->iop_base; - tid = scsiq->target_id; - - inq = (ADV_SCSI_INQUIRY *) scsiq->vdata_addr; - - /* - * WDTR, SDTR, and Tag Queuing cannot be enabled for old devices. - */ - if (ADV_INQ_RESPONSE_FMT(inq) < 2 && ADV_INQ_ANSI_VER(inq) < 2) { - return; - } else { - /* - * INQUIRY Byte 7 Handling - * - * Use a device's INQUIRY byte 7 to determine whether it - * supports WDTR, SDTR, and Tag Queuing. If the feature - * is enabled in the EEPROM and the device supports the - * feature, then enable it in the microcode. - */ - - tidmask = ADV_TID_TO_TIDMASK(tid); - - /* - * Wide Transfers - * - * If the EEPROM enabled WDTR for the device and the device - * supports wide bus (16 bit) transfers, then turn on the - * device's 'wdtr_able' bit and write the new value to the - * microcode. - */ - if ((asc_dvc->wdtr_able & tidmask) && ADV_INQ_WIDE16(inq)) { - AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word); - if ((cfg_word & tidmask) == 0) { - cfg_word |= tidmask; - AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, - cfg_word); - - /* - * Clear the microcode "SDTR negotiation" and "WDTR - * negotiation" done indicators for the target to cause - * it to negotiate with the new setting set above. - * WDTR when accepted causes the target to enter - * asynchronous mode, so SDTR must be negotiated. - */ - AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, - cfg_word); - cfg_word &= ~tidmask; - AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, - cfg_word); - AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, - cfg_word); - cfg_word &= ~tidmask; - AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE, - cfg_word); - } - } - - /* - * Synchronous Transfers - * - * If the EEPROM enabled SDTR for the device and the device - * supports synchronous transfers, then turn on the device's - * 'sdtr_able' bit. Write the new value to the microcode. - */ - if ((asc_dvc->sdtr_able & tidmask) && ADV_INQ_SYNC(inq)) { - AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word); - if ((cfg_word & tidmask) == 0) { - cfg_word |= tidmask; - AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, - cfg_word); - - /* - * Clear the microcode "SDTR negotiation" done indicator - * for the target to cause it to negotiate with the new - * setting set above. - */ - AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, - cfg_word); - cfg_word &= ~tidmask; - AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, - cfg_word); - } - } - /* - * If the Inquiry data included enough space for the SPI-3 - * Clocking field, then check if DT mode is supported. - */ - if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600 && - (scsiq->cdb[4] >= 57 || - (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) >= 57)) { - /* - * PPR (Parallel Protocol Request) Capable - * - * If the device supports DT mode, then it must be PPR capable. - * The PPR message will be used in place of the SDTR and WDTR - * messages to negotiate synchronous speed and offset, transfer - * width, and protocol options. - */ - if (ADV_INQ_CLOCKING(inq) & ADV_INQ_CLOCKING_DT_ONLY) { - AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, - asc_dvc->ppr_able); - asc_dvc->ppr_able |= tidmask; - AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, - asc_dvc->ppr_able); - } - } - - /* - * If the EEPROM enabled Tag Queuing for the device and the - * device supports Tag Queueing, then turn on the device's - * 'tagqng_enable' bit in the microcode and set the microcode - * maximum command count to the ADV_DVC_VAR 'max_dvc_qng' - * value. - * - * Tag Queuing is disabled for the BIOS which runs in polled - * mode and would see no benefit from Tag Queuing. Also by - * disabling Tag Queuing in the BIOS devices with Tag Queuing - * bugs will at least work with the BIOS. - */ - if ((asc_dvc->tagqng_able & tidmask) && ADV_INQ_CMD_QUEUE(inq)) { - AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word); - cfg_word |= tidmask; - AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, - cfg_word); - - AdvWriteByteLram(iop_base, - ASC_MC_NUMBER_OF_MAX_CMD + tid, - asc_dvc->max_dvc_qng); - } + struct adv_dvc_var *adv_dvc = &board->dvc_var.adv_dvc_var; + kfree(adv_dvc->carrier_buf); + adv_dvc->carrier_buf = NULL; + kfree(adv_dvc->orig_reqp); + adv_dvc->orig_reqp = board->adv_reqp = NULL; + while (board->adv_sgblkp) { + adv_sgblk_t *sgp = board->adv_sgblkp; + board->adv_sgblkp = sgp->next_sgblkp; + kfree(sgp); } } -MODULE_LICENSE("Dual BSD/GPL"); - -static struct Scsi_Host *__devinit -advansys_board_found(int iop, struct device *dev, int bus_type) +static int __devinit advansys_board_found(struct Scsi_Host *shost, + unsigned int iop, int bus_type) { - struct Scsi_Host *shost; - struct pci_dev *pdev = bus_type == ASC_IS_PCI ? to_pci_dev(dev) : NULL; - asc_board_t *boardp; + struct pci_dev *pdev; + struct asc_board *boardp = shost_priv(shost); ASC_DVC_VAR *asc_dvc_varp = NULL; ADV_DVC_VAR *adv_dvc_varp = NULL; - adv_sgblk_t *sgp = NULL; - int share_irq = FALSE; - int iolen = 0; - ADV_PADDR pci_memory_address; - int warn_code, err_code; - int ret; + int share_irq, warn_code, ret; - /* - * Adapter found. - * - * Register the adapter, get its configuration, and - * initialize it. - */ - ASC_DBG(2, "advansys_board_found: scsi_register()\n"); - shost = scsi_register(&driver_template, sizeof(asc_board_t)); - - if (!shost) - return NULL; - - /* Save a pointer to the Scsi_Host of each board found. */ - asc_host[asc_board_count++] = shost; - - /* Initialize private per board data */ - boardp = ASC_BOARDP(shost); - memset(boardp, 0, sizeof(asc_board_t)); - boardp->id = asc_board_count - 1; - - /* Initialize spinlock. */ - spin_lock_init(&boardp->lock); - - /* - * Handle both narrow and wide boards. - * - * If a Wide board was detected, set the board structure - * wide board flag. Set-up the board structure based on - * the board type. - */ -#ifdef CONFIG_PCI - if (bus_type == ASC_IS_PCI && - (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW || - pdev->device == PCI_DEVICE_ID_38C0800_REV1 || - pdev->device == PCI_DEVICE_ID_38C1600_REV1)) { - boardp->flags |= ASC_IS_WIDE_BOARD; - } -#endif /* CONFIG_PCI */ + pdev = (bus_type == ASC_IS_PCI) ? to_pci_dev(boardp->dev) : NULL; if (ASC_NARROW_BOARD(boardp)) { - ASC_DBG(1, "advansys_board_found: narrow board\n"); + ASC_DBG(1, "narrow board\n"); asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; asc_dvc_varp->bus_type = bus_type; asc_dvc_varp->drv_ptr = boardp; asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg; - asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0]; asc_dvc_varp->iop_base = iop; - asc_dvc_varp->isr_callback = asc_isr_callback; } else { - ASC_DBG(1, "advansys_board_found: wide board\n"); +#ifdef CONFIG_PCI adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; adv_dvc_varp->drv_ptr = boardp; adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg; - adv_dvc_varp->isr_callback = adv_isr_callback; - adv_dvc_varp->async_callback = adv_async_callback; -#ifdef CONFIG_PCI if (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW) { - ASC_DBG(1, "advansys_board_found: ASC-3550\n"); + ASC_DBG(1, "wide board ASC-3550\n"); adv_dvc_varp->chip_type = ADV_CHIP_ASC3550; } else if (pdev->device == PCI_DEVICE_ID_38C0800_REV1) { - ASC_DBG(1, "advansys_board_found: ASC-38C0800\n"); + ASC_DBG(1, "wide board ASC-38C0800\n"); adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800; } else { - ASC_DBG(1, "advansys_board_found: ASC-38C1600\n"); + ASC_DBG(1, "wide board ASC-38C1600\n"); adv_dvc_varp->chip_type = ADV_CHIP_ASC38C1600; } -#endif /* CONFIG_PCI */ - /* - * Map the board's registers into virtual memory for - * PCI slave access. Only memory accesses are used to - * access the board's registers. - * - * Note: The PCI register base address is not always - * page aligned, but the address passed to ioremap() - * must be page aligned. It is guaranteed that the - * PCI register base address will not cross a page - * boundary. - */ - if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { - iolen = ADV_3550_IOLEN; - } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { - iolen = ADV_38C0800_IOLEN; - } else { - iolen = ADV_38C1600_IOLEN; - } -#ifdef CONFIG_PCI - pci_memory_address = pci_resource_start(pdev, 1); - ASC_DBG1(1, - "advansys_board_found: pci_memory_address: 0x%lx\n", - (ulong)pci_memory_address); - if ((boardp->ioremap_addr = - ioremap(pci_memory_address & PAGE_MASK, PAGE_SIZE)) == 0) { - ASC_PRINT3 - ("advansys_board_found: board %d: ioremap(%x, %d) returned NULL\n", - boardp->id, pci_memory_address, iolen); - scsi_unregister(shost); - asc_board_count--; - return NULL; + boardp->asc_n_io_port = pci_resource_len(pdev, 1); + boardp->ioremap_addr = ioremap(pci_resource_start(pdev, 1), + boardp->asc_n_io_port); + if (!boardp->ioremap_addr) { + shost_printk(KERN_ERR, shost, "ioremap(%lx, %d) " + "returned NULL\n", + (long)pci_resource_start(pdev, 1), + boardp->asc_n_io_port); + ret = -ENODEV; + goto err_shost; } - ASC_DBG1(1, - "advansys_board_found: ioremap_addr: 0x%lx\n", - (ulong)boardp->ioremap_addr); - adv_dvc_varp->iop_base = (AdvPortAddr) - (boardp->ioremap_addr + - (pci_memory_address - (pci_memory_address & PAGE_MASK))); - ASC_DBG1(1, - "advansys_board_found: iop_base: 0x%lx\n", - adv_dvc_varp->iop_base); -#endif /* CONFIG_PCI */ + adv_dvc_varp->iop_base = (AdvPortAddr)boardp->ioremap_addr; + ASC_DBG(1, "iop_base: 0x%p\n", adv_dvc_varp->iop_base); /* * Even though it isn't used to access wide boards, other @@ -17907,9 +13445,9 @@ advansys_board_found(int iop, struct device *dev, int bus_type) */ boardp->ioport = iop; - ASC_DBG2(1, - "advansys_board_found: iopb_chip_id_1 0x%x, iopw_chip_id_0 0x%x\n", - (ushort)inp(iop + 1), (ushort)inpw(iop)); + ASC_DBG(1, "iopb_chip_id_1 0x%x, iopw_chip_id_0 0x%x\n", + (ushort)inp(iop + 1), (ushort)inpw(iop)); +#endif /* CONFIG_PCI */ } #ifdef CONFIG_PROC_FS @@ -17917,18 +13455,16 @@ advansys_board_found(int iop, struct device *dev, int bus_type) * Allocate buffer for printing information from * /proc/scsi/advansys/[0...]. */ - if ((boardp->prtbuf = kmalloc(ASC_PRTBUF_SIZE, GFP_ATOMIC)) == NULL) { - ASC_PRINT3 - ("advansys_board_found: board %d: kmalloc(%d, %d) returned NULL\n", - boardp->id, ASC_PRTBUF_SIZE, GFP_ATOMIC); - scsi_unregister(shost); - asc_board_count--; - return NULL; + boardp->prtbuf = kmalloc(ASC_PRTBUF_SIZE, GFP_KERNEL); + if (!boardp->prtbuf) { + shost_printk(KERN_ERR, shost, "kmalloc(%d) returned NULL\n", + ASC_PRTBUF_SIZE); + ret = -ENOMEM; + goto err_unmap; } #endif /* CONFIG_PROC_FS */ if (ASC_NARROW_BOARD(boardp)) { - asc_dvc_varp->cfg->dev = dev; /* * Set the board bus type and PCI IRQ before * calling AscInitGetConfig(). @@ -17937,127 +13473,56 @@ advansys_board_found(int iop, struct device *dev, int bus_type) #ifdef CONFIG_ISA case ASC_IS_ISA: shost->unchecked_isa_dma = TRUE; - share_irq = FALSE; + share_irq = 0; break; case ASC_IS_VL: shost->unchecked_isa_dma = FALSE; - share_irq = FALSE; + share_irq = 0; break; case ASC_IS_EISA: shost->unchecked_isa_dma = FALSE; - share_irq = TRUE; + share_irq = IRQF_SHARED; break; #endif /* CONFIG_ISA */ #ifdef CONFIG_PCI case ASC_IS_PCI: - shost->irq = asc_dvc_varp->irq_no = pdev->irq; - asc_dvc_varp->cfg->pci_slot_info = - ASC_PCI_MKID(pdev->bus->number, - PCI_SLOT(pdev->devfn), - PCI_FUNC(pdev->devfn)); shost->unchecked_isa_dma = FALSE; - share_irq = TRUE; + share_irq = IRQF_SHARED; break; #endif /* CONFIG_PCI */ default: - ASC_PRINT2 - ("advansys_board_found: board %d: unknown adapter type: %d\n", - boardp->id, asc_dvc_varp->bus_type); + shost_printk(KERN_ERR, shost, "unknown adapter type: " + "%d\n", asc_dvc_varp->bus_type); shost->unchecked_isa_dma = TRUE; - share_irq = FALSE; + share_irq = 0; break; } - } else { - adv_dvc_varp->cfg->dev = dev; - /* - * For Wide boards set PCI information before calling - * AdvInitGetConfig(). - */ -#ifdef CONFIG_PCI - shost->irq = adv_dvc_varp->irq_no = pdev->irq; - adv_dvc_varp->cfg->pci_slot_info = - ASC_PCI_MKID(pdev->bus->number, - PCI_SLOT(pdev->devfn), - PCI_FUNC(pdev->devfn)); - shost->unchecked_isa_dma = FALSE; - share_irq = TRUE; -#endif /* CONFIG_PCI */ - } - /* - * Read the board configuration. - */ - if (ASC_NARROW_BOARD(boardp)) { /* * NOTE: AscInitGetConfig() may change the board's * bus_type value. The bus_type value should no * longer be used. If the bus_type field must be * referenced only use the bit-wise AND operator "&". */ - ASC_DBG(2, "advansys_board_found: AscInitGetConfig()\n"); - switch (ret = AscInitGetConfig(asc_dvc_varp)) { - case 0: /* No error */ - break; - case ASC_WARN_IO_PORT_ROTATE: - ASC_PRINT1 - ("AscInitGetConfig: board %d: I/O port address modified\n", - boardp->id); - break; - case ASC_WARN_AUTO_CONFIG: - ASC_PRINT1 - ("AscInitGetConfig: board %d: I/O port increment switch enabled\n", - boardp->id); - break; - case ASC_WARN_EEPROM_CHKSUM: - ASC_PRINT1 - ("AscInitGetConfig: board %d: EEPROM checksum error\n", - boardp->id); - break; - case ASC_WARN_IRQ_MODIFIED: - ASC_PRINT1 - ("AscInitGetConfig: board %d: IRQ modified\n", - boardp->id); - break; - case ASC_WARN_CMD_QNG_CONFLICT: - ASC_PRINT1 - ("AscInitGetConfig: board %d: tag queuing enabled w/o disconnects\n", - boardp->id); - break; - default: - ASC_PRINT2 - ("AscInitGetConfig: board %d: unknown warning: 0x%x\n", - boardp->id, ret); - break; - } - if ((err_code = asc_dvc_varp->err_code) != 0) { - ASC_PRINT3 - ("AscInitGetConfig: board %d error: init_state 0x%x, err_code 0x%x\n", - boardp->id, - asc_dvc_varp->init_state, asc_dvc_varp->err_code); - } + ASC_DBG(2, "AscInitGetConfig()\n"); + ret = AscInitGetConfig(shost) ? -ENODEV : 0; } else { - ASC_DBG(2, "advansys_board_found: AdvInitGetConfig()\n"); - if ((ret = AdvInitGetConfig(adv_dvc_varp)) != 0) { - ASC_PRINT2 - ("AdvInitGetConfig: board %d: warning: 0x%x\n", - boardp->id, ret); - } - if ((err_code = adv_dvc_varp->err_code) != 0) { - ASC_PRINT2 - ("AdvInitGetConfig: board %d error: err_code 0x%x\n", - boardp->id, adv_dvc_varp->err_code); - } - } +#ifdef CONFIG_PCI + /* + * For Wide boards set PCI information before calling + * AdvInitGetConfig(). + */ + shost->unchecked_isa_dma = FALSE; + share_irq = IRQF_SHARED; + ASC_DBG(2, "AdvInitGetConfig()\n"); - if (err_code != 0) { -#ifdef CONFIG_PROC_FS - kfree(boardp->prtbuf); -#endif /* CONFIG_PROC_FS */ - scsi_unregister(shost); - asc_board_count--; - return NULL; + ret = AdvInitGetConfig(pdev, shost) ? -ENODEV : 0; +#endif /* CONFIG_PCI */ } + if (ret) + goto err_free_proc; + /* * Save the EEPROM configuration so that it can be displayed * from /proc/scsi/advansys/[0...]. @@ -18098,61 +13563,10 @@ advansys_board_found(int iop, struct device *dev, int bus_type) /* * Modify board configuration. */ - ASC_DBG(2, "advansys_board_found: AscInitSetConfig()\n"); - switch (ret = AscInitSetConfig(asc_dvc_varp)) { - case 0: /* No error. */ - break; - case ASC_WARN_IO_PORT_ROTATE: - ASC_PRINT1 - ("AscInitSetConfig: board %d: I/O port address modified\n", - boardp->id); - break; - case ASC_WARN_AUTO_CONFIG: - ASC_PRINT1 - ("AscInitSetConfig: board %d: I/O port increment switch enabled\n", - boardp->id); - break; - case ASC_WARN_EEPROM_CHKSUM: - ASC_PRINT1 - ("AscInitSetConfig: board %d: EEPROM checksum error\n", - boardp->id); - break; - case ASC_WARN_IRQ_MODIFIED: - ASC_PRINT1 - ("AscInitSetConfig: board %d: IRQ modified\n", - boardp->id); - break; - case ASC_WARN_CMD_QNG_CONFLICT: - ASC_PRINT1 - ("AscInitSetConfig: board %d: tag queuing w/o disconnects\n", - boardp->id); - break; - default: - ASC_PRINT2 - ("AscInitSetConfig: board %d: unknown warning: 0x%x\n", - boardp->id, ret); - break; - } - if (asc_dvc_varp->err_code != 0) { - ASC_PRINT3 - ("AscInitSetConfig: board %d error: init_state 0x%x, err_code 0x%x\n", - boardp->id, - asc_dvc_varp->init_state, asc_dvc_varp->err_code); -#ifdef CONFIG_PROC_FS - kfree(boardp->prtbuf); -#endif /* CONFIG_PROC_FS */ - scsi_unregister(shost); - asc_board_count--; - return NULL; - } - - /* - * Finish initializing the 'Scsi_Host' structure. - */ - /* AscInitSetConfig() will set the IRQ for non-PCI boards. */ - if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) { - shost->irq = asc_dvc_varp->irq_no; - } + ASC_DBG(2, "AscInitSetConfig()\n"); + ret = AscInitSetConfig(pdev, shost) ? -ENODEV : 0; + if (ret) + goto err_free_proc; } else { ADVEEP_3550_CONFIG *ep_3550; ADVEEP_38C0800_CONFIG *ep_38C0800; @@ -18246,11 +13660,6 @@ advansys_board_found(int iop, struct device *dev, int bus_type) */ boardp->init_tidmask |= ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id); - - /* - * Finish initializing the 'Scsi_Host' structure. - */ - shost->irq = adv_dvc_varp->irq_no; } /* @@ -18262,6 +13671,7 @@ advansys_board_found(int iop, struct device *dev, int bus_type) if (ASC_NARROW_BOARD(boardp)) { shost->max_id = ASC_MAX_TID + 1; shost->max_lun = ASC_MAX_LUN + 1; + shost->max_cmd_len = ASC_MAX_CDB_LEN; shost->io_port = asc_dvc_varp->iop_base; boardp->asc_n_io_port = ASC_IOADR_GAP; @@ -18272,6 +13682,7 @@ advansys_board_found(int iop, struct device *dev, int bus_type) } else { shost->max_id = ADV_MAX_TID + 1; shost->max_lun = ADV_MAX_LUN + 1; + shost->max_cmd_len = ADV_MAX_CDB_LEN; /* * Save the I/O Port address and length even though @@ -18280,7 +13691,6 @@ advansys_board_found(int iop, struct device *dev, int bus_type) * PCI Memory Mapped I/O. */ shost->io_port = iop; - boardp->asc_n_io_port = iolen; shost->this_id = adv_dvc_varp->chip_scsi_id; @@ -18289,15 +13699,6 @@ advansys_board_found(int iop, struct device *dev, int bus_type) } /* - * 'n_io_port' currently is one byte. - * - * Set a value to 'n_io_port', but never referenced it because - * it may be truncated. - */ - shost->n_io_port = boardp->asc_n_io_port <= 255 ? - boardp->asc_n_io_port : 255; - - /* * Following v1.3.89, 'cmd_per_lun' is no longer needed * and should be set to zero. * @@ -18343,14 +13744,12 @@ advansys_board_found(int iop, struct device *dev, int bus_type) shost->sg_tablesize = SG_ALL; } - ASC_DBG1(1, "advansys_board_found: sg_tablesize: %d\n", shost->sg_tablesize); + ASC_DBG(1, "sg_tablesize: %d\n", shost->sg_tablesize); /* BIOS start address. */ if (ASC_NARROW_BOARD(boardp)) { - shost->base = ((ulong) - AscGetChipBiosAddress(asc_dvc_varp-> - iop_base, - asc_dvc_varp->bus_type)); + shost->base = AscGetChipBiosAddress(asc_dvc_varp->iop_base, + asc_dvc_varp->bus_type); } else { /* * Fill-in BIOS board variables. The Wide BIOS saves @@ -18365,12 +13764,10 @@ advansys_board_found(int iop, struct device *dev, int bus_type) AdvReadWordLram(adv_dvc_varp->iop_base, BIOS_CODELEN, boardp->bios_codelen); - ASC_DBG2(1, - "advansys_board_found: bios_signature 0x%x, bios_version 0x%x\n", + ASC_DBG(1, "bios_signature 0x%x, bios_version 0x%x\n", boardp->bios_signature, boardp->bios_version); - ASC_DBG2(1, - "advansys_board_found: bios_codeseg 0x%x, bios_codelen 0x%x\n", + ASC_DBG(1, "bios_codeseg 0x%x, bios_codelen 0x%x\n", boardp->bios_codeseg, boardp->bios_codelen); /* @@ -18392,30 +13789,6 @@ advansys_board_found(int iop, struct device *dev, int bus_type) * Register Board Resources - I/O Port, DMA, IRQ */ - /* - * Register I/O port range. - * - * For Wide boards the I/O ports are not used to access - * the board, but request the region anyway. - * - * 'shost->n_io_port' is not referenced, because it may be truncated. - */ - ASC_DBG2(2, - "advansys_board_found: request_region port 0x%lx, len 0x%x\n", - (ulong)shost->io_port, boardp->asc_n_io_port); - if (request_region(shost->io_port, boardp->asc_n_io_port, - "advansys") == NULL) { - ASC_PRINT3 - ("advansys_board_found: board %d: request_region() failed, port 0x%lx, len 0x%x\n", - boardp->id, (ulong)shost->io_port, boardp->asc_n_io_port); -#ifdef CONFIG_PROC_FS - kfree(boardp->prtbuf); -#endif /* CONFIG_PROC_FS */ - scsi_unregister(shost); - asc_board_count--; - return NULL; - } - /* Register DMA Channel for Narrow boards. */ shost->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */ #ifdef CONFIG_ISA @@ -18423,19 +13796,12 @@ advansys_board_found(int iop, struct device *dev, int bus_type) /* Register DMA channel for ISA bus. */ if (asc_dvc_varp->bus_type & ASC_IS_ISA) { shost->dma_channel = asc_dvc_varp->cfg->isa_dma_channel; - if ((ret = - request_dma(shost->dma_channel, "advansys")) != 0) { - ASC_PRINT3 - ("advansys_board_found: board %d: request_dma() %d failed %d\n", - boardp->id, shost->dma_channel, ret); - release_region(shost->io_port, - boardp->asc_n_io_port); -#ifdef CONFIG_PROC_FS - kfree(boardp->prtbuf); -#endif /* CONFIG_PROC_FS */ - scsi_unregister(shost); - asc_board_count--; - return NULL; + ret = request_dma(shost->dma_channel, DRV_NAME); + if (ret) { + shost_printk(KERN_ERR, shost, "request_dma() " + "%d failed %d\n", + shost->dma_channel, ret); + goto err_free_proc; } AscEnableIsaDma(shost->dma_channel); } @@ -18443,573 +13809,392 @@ advansys_board_found(int iop, struct device *dev, int bus_type) #endif /* CONFIG_ISA */ /* Register IRQ Number. */ - ASC_DBG1(2, "advansys_board_found: request_irq() %d\n", shost->irq); - /* - * If request_irq() fails with the IRQF_DISABLED flag set, - * then try again without the IRQF_DISABLED flag set. This - * allows IRQ sharing to work even with other drivers that - * do not set the IRQF_DISABLED flag. - * - * If IRQF_DISABLED is not set, then interrupts are enabled - * before the driver interrupt function is called. - */ - if (((ret = request_irq(shost->irq, advansys_interrupt, - IRQF_DISABLED | (share_irq == - TRUE ? - IRQF_SHARED : - 0), "advansys", boardp)) != 0) - && - ((ret = - request_irq(shost->irq, advansys_interrupt, - (share_irq == TRUE ? IRQF_SHARED : 0), - "advansys", boardp)) != 0)) { + ASC_DBG(2, "request_irq(%d, %p)\n", boardp->irq, shost); + + ret = request_irq(boardp->irq, advansys_interrupt, share_irq, + DRV_NAME, shost); + + if (ret) { if (ret == -EBUSY) { - ASC_PRINT2 - ("advansys_board_found: board %d: request_irq(): IRQ 0x%x already in use.\n", - boardp->id, shost->irq); + shost_printk(KERN_ERR, shost, "request_irq(): IRQ 0x%x " + "already in use\n", boardp->irq); } else if (ret == -EINVAL) { - ASC_PRINT2 - ("advansys_board_found: board %d: request_irq(): IRQ 0x%x not valid.\n", - boardp->id, shost->irq); + shost_printk(KERN_ERR, shost, "request_irq(): IRQ 0x%x " + "not valid\n", boardp->irq); } else { - ASC_PRINT3 - ("advansys_board_found: board %d: request_irq(): IRQ 0x%x failed with %d\n", - boardp->id, shost->irq, ret); + shost_printk(KERN_ERR, shost, "request_irq(): IRQ 0x%x " + "failed with %d\n", boardp->irq, ret); } - release_region(shost->io_port, boardp->asc_n_io_port); - iounmap(boardp->ioremap_addr); - if (shost->dma_channel != NO_ISA_DMA) { - free_dma(shost->dma_channel); - } -#ifdef CONFIG_PROC_FS - kfree(boardp->prtbuf); -#endif /* CONFIG_PROC_FS */ - scsi_unregister(shost); - asc_board_count--; - return NULL; + goto err_free_dma; } /* * Initialize board RISC chip and enable interrupts. */ if (ASC_NARROW_BOARD(boardp)) { - ASC_DBG(2, "advansys_board_found: AscInitAsc1000Driver()\n"); + ASC_DBG(2, "AscInitAsc1000Driver()\n"); warn_code = AscInitAsc1000Driver(asc_dvc_varp); - err_code = asc_dvc_varp->err_code; - if (warn_code || err_code) { - ASC_PRINT4 - ("advansys_board_found: board %d error: init_state 0x%x, warn 0x%x, error 0x%x\n", - boardp->id, - asc_dvc_varp->init_state, warn_code, err_code); + if (warn_code || asc_dvc_varp->err_code) { + shost_printk(KERN_ERR, shost, "error: init_state 0x%x, " + "warn 0x%x, error 0x%x\n", + asc_dvc_varp->init_state, warn_code, + asc_dvc_varp->err_code); + if (asc_dvc_varp->err_code) + ret = -ENODEV; } } else { - ADV_CARR_T *carrp; - int req_cnt = 0; - adv_req_t *reqp = NULL; - int sg_cnt = 0; - - /* - * Allocate buffer carrier structures. The total size - * is about 4 KB, so allocate all at once. - */ - carrp = (ADV_CARR_T *) kmalloc(ADV_CARRIER_BUFSIZE, GFP_ATOMIC); - ASC_DBG1(1, "advansys_board_found: carrp 0x%lx\n", (ulong)carrp); - - if (carrp == NULL) { - goto kmalloc_error; - } + if (advansys_wide_init_chip(shost)) + ret = -ENODEV; + } - /* - * Allocate up to 'max_host_qng' request structures for - * the Wide board. The total size is about 16 KB, so - * allocate all at once. If the allocation fails decrement - * and try again. - */ - for (req_cnt = adv_dvc_varp->max_host_qng; - req_cnt > 0; req_cnt--) { + if (ret) + goto err_free_wide_mem; - reqp = (adv_req_t *) - kmalloc(sizeof(adv_req_t) * req_cnt, GFP_ATOMIC); + ASC_DBG_PRT_SCSI_HOST(2, shost); - ASC_DBG3(1, - "advansys_board_found: reqp 0x%lx, req_cnt %d, bytes %lu\n", - (ulong)reqp, req_cnt, - (ulong)sizeof(adv_req_t) * req_cnt); + ret = scsi_add_host(shost, boardp->dev); + if (ret) + goto err_free_wide_mem; - if (reqp != NULL) { - break; - } - } - if (reqp == NULL) { - goto kmalloc_error; - } + scsi_scan_host(shost); + return 0; - /* - * Allocate up to ADV_TOT_SG_BLOCK request structures for - * the Wide board. Each structure is about 136 bytes. - */ - boardp->adv_sgblkp = NULL; - for (sg_cnt = 0; sg_cnt < ADV_TOT_SG_BLOCK; sg_cnt++) { + err_free_wide_mem: + advansys_wide_free_mem(boardp); + free_irq(boardp->irq, shost); + err_free_dma: + if (shost->dma_channel != NO_ISA_DMA) + free_dma(shost->dma_channel); + err_free_proc: + kfree(boardp->prtbuf); + err_unmap: + if (boardp->ioremap_addr) + iounmap(boardp->ioremap_addr); + err_shost: + return ret; +} - sgp = (adv_sgblk_t *) - kmalloc(sizeof(adv_sgblk_t), GFP_ATOMIC); +/* + * advansys_release() + * + * Release resources allocated for a single AdvanSys adapter. + */ +static int advansys_release(struct Scsi_Host *shost) +{ + struct asc_board *board = shost_priv(shost); + ASC_DBG(1, "begin\n"); + scsi_remove_host(shost); + free_irq(board->irq, shost); + if (shost->dma_channel != NO_ISA_DMA) { + ASC_DBG(1, "free_dma()\n"); + free_dma(shost->dma_channel); + } + if (ASC_NARROW_BOARD(board)) { + dma_unmap_single(board->dev, + board->dvc_var.asc_dvc_var.overrun_dma, + ASC_OVERRUN_BSIZE, DMA_FROM_DEVICE); + } else { + iounmap(board->ioremap_addr); + advansys_wide_free_mem(board); + } + kfree(board->prtbuf); + scsi_host_put(shost); + ASC_DBG(1, "end\n"); + return 0; +} - if (sgp == NULL) { - break; - } +#define ASC_IOADR_TABLE_MAX_IX 11 - sgp->next_sgblkp = boardp->adv_sgblkp; - boardp->adv_sgblkp = sgp; +static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __devinitdata = { + 0x100, 0x0110, 0x120, 0x0130, 0x140, 0x0150, 0x0190, + 0x0210, 0x0230, 0x0250, 0x0330 +}; - } - ASC_DBG3(1, - "advansys_board_found: sg_cnt %d * %u = %u bytes\n", - sg_cnt, sizeof(adv_sgblk_t), - (unsigned)(sizeof(adv_sgblk_t) * sg_cnt)); +/* + * The ISA IRQ number is found in bits 2 and 3 of the CfgLsw. It decodes as: + * 00: 10 + * 01: 11 + * 10: 12 + * 11: 15 + */ +static unsigned int __devinit advansys_isa_irq_no(PortAddr iop_base) +{ + unsigned short cfg_lsw = AscGetChipCfgLsw(iop_base); + unsigned int chip_irq = ((cfg_lsw >> 2) & 0x03) + 10; + if (chip_irq == 13) + chip_irq = 15; + return chip_irq; +} - /* - * If no request structures or scatter-gather structures could - * be allocated, then return an error. Otherwise continue with - * initialization. - */ - kmalloc_error: - if (carrp == NULL) { - ASC_PRINT1 - ("advansys_board_found: board %d error: failed to kmalloc() carrier buffer.\n", - boardp->id); - err_code = ADV_ERROR; - } else if (reqp == NULL) { - kfree(carrp); - ASC_PRINT1 - ("advansys_board_found: board %d error: failed to kmalloc() adv_req_t buffer.\n", - boardp->id); - err_code = ADV_ERROR; - } else if (boardp->adv_sgblkp == NULL) { - kfree(carrp); - kfree(reqp); - ASC_PRINT1 - ("advansys_board_found: board %d error: failed to kmalloc() adv_sgblk_t buffers.\n", - boardp->id); - err_code = ADV_ERROR; - } else { +static int __devinit advansys_isa_probe(struct device *dev, unsigned int id) +{ + int err = -ENODEV; + PortAddr iop_base = _asc_def_iop_base[id]; + struct Scsi_Host *shost; + struct asc_board *board; - /* Save carrier buffer pointer. */ - boardp->orig_carrp = carrp; + if (!request_region(iop_base, ASC_IOADR_GAP, DRV_NAME)) { + ASC_DBG(1, "I/O port 0x%x busy\n", iop_base); + return -ENODEV; + } + ASC_DBG(1, "probing I/O port 0x%x\n", iop_base); + if (!AscFindSignature(iop_base)) + goto release_region; + if (!(AscGetChipVersion(iop_base, ASC_IS_ISA) & ASC_CHIP_VER_ISA_BIT)) + goto release_region; - /* - * Save original pointer for kfree() in case the - * driver is built as a module and can be unloaded. - */ - boardp->orig_reqp = reqp; + err = -ENOMEM; + shost = scsi_host_alloc(&advansys_template, sizeof(*board)); + if (!shost) + goto release_region; - adv_dvc_varp->carrier_buf = carrp; + board = shost_priv(shost); + board->irq = advansys_isa_irq_no(iop_base); + board->dev = dev; - /* - * Point 'adv_reqp' to the request structures and - * link them together. - */ - req_cnt--; - reqp[req_cnt].next_reqp = NULL; - for (; req_cnt > 0; req_cnt--) { - reqp[req_cnt - 1].next_reqp = &reqp[req_cnt]; - } - boardp->adv_reqp = &reqp[0]; - - if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { - ASC_DBG(2, - "advansys_board_found: AdvInitAsc3550Driver()\n"); - warn_code = AdvInitAsc3550Driver(adv_dvc_varp); - } else if (adv_dvc_varp->chip_type == - ADV_CHIP_ASC38C0800) { - ASC_DBG(2, - "advansys_board_found: AdvInitAsc38C0800Driver()\n"); - warn_code = - AdvInitAsc38C0800Driver(adv_dvc_varp); - } else { - ASC_DBG(2, - "advansys_board_found: AdvInitAsc38C1600Driver()\n"); - warn_code = - AdvInitAsc38C1600Driver(adv_dvc_varp); - } - err_code = adv_dvc_varp->err_code; + err = advansys_board_found(shost, iop_base, ASC_IS_ISA); + if (err) + goto free_host; - if (warn_code || err_code) { - ASC_PRINT3 - ("advansys_board_found: board %d error: warn 0x%x, error 0x%x\n", - boardp->id, warn_code, err_code); - } - } - } + dev_set_drvdata(dev, shost); + return 0; - if (err_code != 0) { - release_region(shost->io_port, boardp->asc_n_io_port); - if (ASC_WIDE_BOARD(boardp)) { - iounmap(boardp->ioremap_addr); - kfree(boardp->orig_carrp); - boardp->orig_carrp = NULL; - if (boardp->orig_reqp) { - kfree(boardp->orig_reqp); - boardp->orig_reqp = boardp->adv_reqp = NULL; - } - while ((sgp = boardp->adv_sgblkp) != NULL) { - boardp->adv_sgblkp = sgp->next_sgblkp; - kfree(sgp); - } - } - if (shost->dma_channel != NO_ISA_DMA) { - free_dma(shost->dma_channel); - } -#ifdef CONFIG_PROC_FS - kfree(boardp->prtbuf); -#endif /* CONFIG_PROC_FS */ - free_irq(shost->irq, boardp); - scsi_unregister(shost); - asc_board_count--; - return NULL; - } - ASC_DBG_PRT_SCSI_HOST(2, shost); + free_host: + scsi_host_put(shost); + release_region: + release_region(iop_base, ASC_IOADR_GAP); + return err; +} - return shost; +static int __devexit advansys_isa_remove(struct device *dev, unsigned int id) +{ + int ioport = _asc_def_iop_base[id]; + advansys_release(dev_get_drvdata(dev)); + release_region(ioport, ASC_IOADR_GAP); + return 0; } +static struct isa_driver advansys_isa_driver = { + .probe = advansys_isa_probe, + .remove = __devexit_p(advansys_isa_remove), + .driver = { + .owner = THIS_MODULE, + .name = DRV_NAME, + }, +}; + /* - * advansys_detect() - * - * Detect function for AdvanSys adapters. - * - * Argument is a pointer to the host driver's scsi_hosts entry. - * - * Return number of adapters found. - * - * Note: Because this function is called during system initialization - * it must not call SCSI mid-level functions including scsi_malloc() - * and scsi_free(). + * The VLB IRQ number is found in bits 2 to 4 of the CfgLsw. It decodes as: + * 000: invalid + * 001: 10 + * 010: 11 + * 011: 12 + * 100: invalid + * 101: 14 + * 110: 15 + * 111: invalid */ -static int __init advansys_detect(struct scsi_host_template *tpnt) +static unsigned int __devinit advansys_vlb_irq_no(PortAddr iop_base) { - static int detect_called = ASC_FALSE; - int iop; - int bus; - int ioport = 0; - struct device *dev = NULL; -#ifdef CONFIG_PCI - int pci_init_search = 0; - struct pci_dev *pci_devicep[ASC_NUM_BOARD_SUPPORTED]; - int pci_card_cnt_max = 0; - int pci_card_cnt = 0; - struct pci_dev *pdev = NULL; - int pci_device_id_cnt = 0; - unsigned int pci_device_id[ASC_PCI_DEVICE_ID_CNT] = { - PCI_DEVICE_ID_ASP_1200A, - PCI_DEVICE_ID_ASP_ABP940, - PCI_DEVICE_ID_ASP_ABP940U, - PCI_DEVICE_ID_ASP_ABP940UW, - PCI_DEVICE_ID_38C0800_REV1, - PCI_DEVICE_ID_38C1600_REV1 - }; -#endif /* CONFIG_PCI */ - - if (detect_called == ASC_FALSE) { - detect_called = ASC_TRUE; - } else { - printk - ("AdvanSys SCSI: advansys_detect() multiple calls ignored\n"); + unsigned short cfg_lsw = AscGetChipCfgLsw(iop_base); + unsigned int chip_irq = ((cfg_lsw >> 2) & 0x07) + 9; + if ((chip_irq < 10) || (chip_irq == 13) || (chip_irq > 15)) return 0; - } - - ASC_DBG(1, "advansys_detect: begin\n"); + return chip_irq; +} - asc_board_count = 0; +static int __devinit advansys_vlb_probe(struct device *dev, unsigned int id) +{ + int err = -ENODEV; + PortAddr iop_base = _asc_def_iop_base[id]; + struct Scsi_Host *shost; + struct asc_board *board; + if (!request_region(iop_base, ASC_IOADR_GAP, DRV_NAME)) { + ASC_DBG(1, "I/O port 0x%x busy\n", iop_base); + return -ENODEV; + } + ASC_DBG(1, "probing I/O port 0x%x\n", iop_base); + if (!AscFindSignature(iop_base)) + goto release_region; /* - * If I/O port probing has been modified, then verify and - * clean-up the 'asc_ioport' list. + * I don't think this condition can actually happen, but the old + * driver did it, and the chances of finding a VLB setup in 2007 + * to do testing with is slight to none. */ - if (asc_iopflag == ASC_TRUE) { - for (ioport = 0; ioport < ASC_NUM_IOPORT_PROBE; ioport++) { - ASC_DBG2(1, "advansys_detect: asc_ioport[%d] 0x%x\n", - ioport, asc_ioport[ioport]); - if (asc_ioport[ioport] != 0) { - for (iop = 0; iop < ASC_IOADR_TABLE_MAX_IX; - iop++) { - if (_asc_def_iop_base[iop] == - asc_ioport[ioport]) { - break; - } - } - if (iop == ASC_IOADR_TABLE_MAX_IX) { - printk - ("AdvanSys SCSI: specified I/O Port 0x%X is invalid\n", - asc_ioport[ioport]); - asc_ioport[ioport] = 0; - } - } - } - ioport = 0; - } + if (AscGetChipVersion(iop_base, ASC_IS_VL) > ASC_CHIP_MAX_VER_VL) + goto release_region; - for (bus = 0; bus < ASC_NUM_BUS; bus++) { + err = -ENOMEM; + shost = scsi_host_alloc(&advansys_template, sizeof(*board)); + if (!shost) + goto release_region; - ASC_DBG2(1, "advansys_detect: bus search type %d (%s)\n", - bus, asc_bus_name[bus]); - iop = 0; + board = shost_priv(shost); + board->irq = advansys_vlb_irq_no(iop_base); + board->dev = dev; - while (asc_board_count < ASC_NUM_BOARD_SUPPORTED) { + err = advansys_board_found(shost, iop_base, ASC_IS_VL); + if (err) + goto free_host; - ASC_DBG1(2, "advansys_detect: asc_board_count %d\n", - asc_board_count); + dev_set_drvdata(dev, shost); + return 0; - switch (asc_bus[bus]) { - case ASC_IS_ISA: - case ASC_IS_VL: -#ifdef CONFIG_ISA - if (asc_iopflag == ASC_FALSE) { - iop = - AscSearchIOPortAddr(iop, - asc_bus[bus]); - } else { - /* - * ISA and VL I/O port scanning has either been - * eliminated or limited to selected ports on - * the LILO command line, /etc/lilo.conf, or - * by setting variables when the module was loaded. - */ - ASC_DBG(1, - "advansys_detect: I/O port scanning modified\n"); - ioport_try_again: - iop = 0; - for (; ioport < ASC_NUM_IOPORT_PROBE; - ioport++) { - if ((iop = - asc_ioport[ioport]) != 0) { - break; - } - } - if (iop) { - ASC_DBG1(1, - "advansys_detect: probing I/O port 0x%x...\n", - iop); - if (!request_region - (iop, ASC_IOADR_GAP, - "advansys")) { - printk - ("AdvanSys SCSI: specified I/O Port 0x%X is busy\n", - iop); - /* Don't try this I/O port twice. */ - asc_ioport[ioport] = 0; - goto ioport_try_again; - } else if (AscFindSignature(iop) - == ASC_FALSE) { - printk - ("AdvanSys SCSI: specified I/O Port 0x%X has no adapter\n", - iop); - /* Don't try this I/O port twice. */ - release_region(iop, - ASC_IOADR_GAP); - asc_ioport[ioport] = 0; - goto ioport_try_again; - } else { - /* - * If this isn't an ISA board, then it must be - * a VL board. If currently looking an ISA - * board is being looked for then try for - * another ISA board in 'asc_ioport'. - */ - if (asc_bus[bus] == - ASC_IS_ISA - && - (AscGetChipVersion - (iop, - ASC_IS_ISA) & - ASC_CHIP_VER_ISA_BIT) - == 0) { - /* - * Don't clear 'asc_ioport[ioport]'. Try - * this board again for VL. Increment - * 'ioport' past this board. - */ - ioport++; - release_region - (iop, - ASC_IOADR_GAP); - goto ioport_try_again; - } - } - /* - * This board appears good, don't try the I/O port - * again by clearing its value. Increment 'ioport' - * for the next iteration. - */ - asc_ioport[ioport++] = 0; - } - } -#endif /* CONFIG_ISA */ - break; + free_host: + scsi_host_put(shost); + release_region: + release_region(iop_base, ASC_IOADR_GAP); + return -ENODEV; +} - case ASC_IS_EISA: -#ifdef CONFIG_ISA - iop = AscSearchIOPortAddr(iop, asc_bus[bus]); -#endif /* CONFIG_ISA */ - break; +static struct isa_driver advansys_vlb_driver = { + .probe = advansys_vlb_probe, + .remove = __devexit_p(advansys_isa_remove), + .driver = { + .owner = THIS_MODULE, + .name = "advansys_vlb", + }, +}; - case ASC_IS_PCI: -#ifdef CONFIG_PCI - if (pci_init_search == 0) { - int i, j; - - pci_init_search = 1; - - /* Find all PCI cards. */ - while (pci_device_id_cnt < - ASC_PCI_DEVICE_ID_CNT) { - if ((pdev = - pci_find_device - (PCI_VENDOR_ID_ASP, - pci_device_id - [pci_device_id_cnt], - pdev)) == NULL) { - pci_device_id_cnt++; - } else { - if (pci_enable_device - (pdev) == 0) { - pci_devicep - [pci_card_cnt_max++] - = pdev; - } - } - } +static struct eisa_device_id advansys_eisa_table[] __devinitdata = { + { "ABP7401" }, + { "ABP7501" }, + { "" } +}; - /* - * Sort PCI cards in ascending order by PCI Bus, Slot, - * and Device Number. - */ - for (i = 0; i < pci_card_cnt_max - 1; - i++) { - for (j = i + 1; - j < pci_card_cnt_max; - j++) { - if ((pci_devicep[j]-> - bus->number < - pci_devicep[i]-> - bus->number) - || - ((pci_devicep[j]-> - bus->number == - pci_devicep[i]-> - bus->number) - && - (pci_devicep[j]-> - devfn < - pci_devicep[i]-> - devfn))) { - pdev = - pci_devicep - [i]; - pci_devicep[i] = - pci_devicep - [j]; - pci_devicep[j] = - pdev; - } - } - } +MODULE_DEVICE_TABLE(eisa, advansys_eisa_table); - pci_card_cnt = 0; - } else { - pci_card_cnt++; - } +/* + * EISA is a little more tricky than PCI; each EISA device may have two + * channels, and this driver is written to make each channel its own Scsi_Host + */ +struct eisa_scsi_data { + struct Scsi_Host *host[2]; +}; - if (pci_card_cnt == pci_card_cnt_max) { - iop = 0; - } else { - pdev = pci_devicep[pci_card_cnt]; - - ASC_DBG2(2, - "advansys_detect: devfn %d, bus number %d\n", - pdev->devfn, - pdev->bus->number); - iop = pci_resource_start(pdev, 0); - ASC_DBG2(1, - "advansys_detect: vendorID %X, deviceID %X\n", - pdev->vendor, - pdev->device); - ASC_DBG2(2, - "advansys_detect: iop %X, irqLine %d\n", - iop, pdev->irq); - } - if (pdev) - dev = &pdev->dev; +/* + * The EISA IRQ number is found in bits 8 to 10 of the CfgLsw. It decodes as: + * 000: 10 + * 001: 11 + * 010: 12 + * 011: invalid + * 100: 14 + * 101: 15 + * 110: invalid + * 111: invalid + */ +static unsigned int __devinit advansys_eisa_irq_no(struct eisa_device *edev) +{ + unsigned short cfg_lsw = inw(edev->base_addr + 0xc86); + unsigned int chip_irq = ((cfg_lsw >> 8) & 0x07) + 10; + if ((chip_irq == 13) || (chip_irq > 15)) + return 0; + return chip_irq; +} -#endif /* CONFIG_PCI */ - break; +static int __devinit advansys_eisa_probe(struct device *dev) +{ + int i, ioport, irq = 0; + int err; + struct eisa_device *edev = to_eisa_device(dev); + struct eisa_scsi_data *data; - default: - ASC_PRINT1 - ("advansys_detect: unknown bus type: %d\n", - asc_bus[bus]); - break; - } - ASC_DBG1(1, "advansys_detect: iop 0x%x\n", iop); + err = -ENOMEM; + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + goto fail; + ioport = edev->base_addr + 0xc30; - /* - * Adapter not found, try next bus type. - */ - if (iop == 0) { - break; - } + err = -ENODEV; + for (i = 0; i < 2; i++, ioport += 0x20) { + struct asc_board *board; + struct Scsi_Host *shost; + if (!request_region(ioport, ASC_IOADR_GAP, DRV_NAME)) { + printk(KERN_WARNING "Region %x-%x busy\n", ioport, + ioport + ASC_IOADR_GAP - 1); + continue; + } + if (!AscFindSignature(ioport)) { + release_region(ioport, ASC_IOADR_GAP); + continue; + } - advansys_board_found(iop, dev, asc_bus[bus]); + /* + * I don't know why we need to do this for EISA chips, but + * not for any others. It looks to be equivalent to + * AscGetChipCfgMsw, but I may have overlooked something, + * so I'm not converting it until I get an EISA board to + * test with. + */ + inw(ioport + 4); + + if (!irq) + irq = advansys_eisa_irq_no(edev); + + err = -ENOMEM; + shost = scsi_host_alloc(&advansys_template, sizeof(*board)); + if (!shost) + goto release_region; + + board = shost_priv(shost); + board->irq = irq; + board->dev = dev; + + err = advansys_board_found(shost, ioport, ASC_IS_EISA); + if (!err) { + data->host[i] = shost; + continue; } + + scsi_host_put(shost); + release_region: + release_region(ioport, ASC_IOADR_GAP); + break; } - ASC_DBG1(1, "advansys_detect: done: asc_board_count %d\n", - asc_board_count); - return asc_board_count; + if (err) + goto free_data; + dev_set_drvdata(dev, data); + return 0; + + free_data: + kfree(data->host[0]); + kfree(data->host[1]); + kfree(data); + fail: + return err; } -/* - * advansys_release() - * - * Release resources allocated for a single AdvanSys adapter. - */ -static int advansys_release(struct Scsi_Host *shost) +static __devexit int advansys_eisa_remove(struct device *dev) { - asc_board_t *boardp; + int i; + struct eisa_scsi_data *data = dev_get_drvdata(dev); - ASC_DBG(1, "advansys_release: begin\n"); - boardp = ASC_BOARDP(shost); - free_irq(shost->irq, boardp); - if (shost->dma_channel != NO_ISA_DMA) { - ASC_DBG(1, "advansys_release: free_dma()\n"); - free_dma(shost->dma_channel); + for (i = 0; i < 2; i++) { + int ioport; + struct Scsi_Host *shost = data->host[i]; + if (!shost) + continue; + ioport = shost->io_port; + advansys_release(shost); + release_region(ioport, ASC_IOADR_GAP); } - release_region(shost->io_port, boardp->asc_n_io_port); - if (ASC_WIDE_BOARD(boardp)) { - adv_sgblk_t *sgp = NULL; - iounmap(boardp->ioremap_addr); - kfree(boardp->orig_carrp); - boardp->orig_carrp = NULL; - if (boardp->orig_reqp) { - kfree(boardp->orig_reqp); - boardp->orig_reqp = boardp->adv_reqp = NULL; - } - while ((sgp = boardp->adv_sgblkp) != NULL) { - boardp->adv_sgblkp = sgp->next_sgblkp; - kfree(sgp); - } - } -#ifdef CONFIG_PROC_FS - ASC_ASSERT(boardp->prtbuf != NULL); - kfree(boardp->prtbuf); -#endif /* CONFIG_PROC_FS */ - scsi_unregister(shost); - ASC_DBG(1, "advansys_release: end\n"); + kfree(data); return 0; } -#ifdef CONFIG_PCI +static struct eisa_driver advansys_eisa_driver = { + .id_table = advansys_eisa_table, + .driver = { + .name = DRV_NAME, + .probe = advansys_eisa_probe, + .remove = __devexit_p(advansys_eisa_remove), + } +}; + /* PCI Devices supported by this driver */ static struct pci_device_id advansys_pci_tbl[] __devinitdata = { {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A, @@ -19028,4 +14213,131 @@ static struct pci_device_id advansys_pci_tbl[] __devinitdata = { }; MODULE_DEVICE_TABLE(pci, advansys_pci_tbl); -#endif /* CONFIG_PCI */ + +static void __devinit advansys_set_latency(struct pci_dev *pdev) +{ + if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) || + (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) { + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0); + } else { + u8 latency; + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency); + if (latency < 0x20) + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x20); + } +} + +static int __devinit +advansys_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int err, ioport; + struct Scsi_Host *shost; + struct asc_board *board; + + err = pci_enable_device(pdev); + if (err) + goto fail; + err = pci_request_regions(pdev, DRV_NAME); + if (err) + goto disable_device; + pci_set_master(pdev); + advansys_set_latency(pdev); + + err = -ENODEV; + if (pci_resource_len(pdev, 0) == 0) + goto release_region; + + ioport = pci_resource_start(pdev, 0); + + err = -ENOMEM; + shost = scsi_host_alloc(&advansys_template, sizeof(*board)); + if (!shost) + goto release_region; + + board = shost_priv(shost); + board->irq = pdev->irq; + board->dev = &pdev->dev; + + if (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW || + pdev->device == PCI_DEVICE_ID_38C0800_REV1 || + pdev->device == PCI_DEVICE_ID_38C1600_REV1) { + board->flags |= ASC_IS_WIDE_BOARD; + } + + err = advansys_board_found(shost, ioport, ASC_IS_PCI); + if (err) + goto free_host; + + pci_set_drvdata(pdev, shost); + return 0; + + free_host: + scsi_host_put(shost); + release_region: + pci_release_regions(pdev); + disable_device: + pci_disable_device(pdev); + fail: + return err; +} + +static void __devexit advansys_pci_remove(struct pci_dev *pdev) +{ + advansys_release(pci_get_drvdata(pdev)); + pci_release_regions(pdev); + pci_disable_device(pdev); +} + +static struct pci_driver advansys_pci_driver = { + .name = DRV_NAME, + .id_table = advansys_pci_tbl, + .probe = advansys_pci_probe, + .remove = __devexit_p(advansys_pci_remove), +}; + +static int __init advansys_init(void) +{ + int error; + + error = isa_register_driver(&advansys_isa_driver, + ASC_IOADR_TABLE_MAX_IX); + if (error) + goto fail; + + error = isa_register_driver(&advansys_vlb_driver, + ASC_IOADR_TABLE_MAX_IX); + if (error) + goto unregister_isa; + + error = eisa_driver_register(&advansys_eisa_driver); + if (error) + goto unregister_vlb; + + error = pci_register_driver(&advansys_pci_driver); + if (error) + goto unregister_eisa; + + return 0; + + unregister_eisa: + eisa_driver_unregister(&advansys_eisa_driver); + unregister_vlb: + isa_unregister_driver(&advansys_vlb_driver); + unregister_isa: + isa_unregister_driver(&advansys_isa_driver); + fail: + return error; +} + +static void __exit advansys_exit(void) +{ + pci_unregister_driver(&advansys_pci_driver); + eisa_driver_unregister(&advansys_eisa_driver); + isa_unregister_driver(&advansys_vlb_driver); + isa_unregister_driver(&advansys_isa_driver); +} + +module_init(advansys_init); +module_exit(advansys_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index d30a30786dda..f08e71e0205a 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -907,9 +907,10 @@ out_host_put: void aha152x_release(struct Scsi_Host *shpnt) { - if(!shpnt) + if (!shpnt) return; + scsi_remove_host(shpnt); if (shpnt->irq) free_irq(shpnt->irq, shpnt); @@ -923,7 +924,6 @@ void aha152x_release(struct Scsi_Host *shpnt) pnp_device_detach(HOSTDATA(shpnt)->pnpdev); #endif - scsi_remove_host(shpnt); list_del(&HOSTDATA(shpnt)->host_list); scsi_host_put(shpnt); } diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c index 4998bb850c49..1a71b0236c97 100644 --- a/drivers/scsi/aic7xxx_old.c +++ b/drivers/scsi/aic7xxx_old.c @@ -8416,10 +8416,9 @@ aic7xxx_alloc(struct scsi_host_template *sht, struct aic7xxx_host *temp) *p = *temp; p->host = host; - p->scb_data = kmalloc(sizeof(scb_data_type), GFP_ATOMIC); - if (p->scb_data != NULL) + p->scb_data = kzalloc(sizeof(scb_data_type), GFP_ATOMIC); + if (!p->scb_data) { - memset(p->scb_data, 0, sizeof(scb_data_type)); scbq_init (&p->scb_data->free_scbs); } else @@ -9196,10 +9195,9 @@ aic7xxx_detect(struct scsi_host_template *template) printk(KERN_INFO " this driver, we are ignoring it.\n"); } } - else if ( (temp_p = kmalloc(sizeof(struct aic7xxx_host), + else if ( (temp_p = kzalloc(sizeof(struct aic7xxx_host), GFP_ATOMIC)) != NULL ) { - memset(temp_p, 0, sizeof(struct aic7xxx_host)); temp_p->chip = aic_pdevs[i].chip | AHC_PCI; temp_p->flags = aic_pdevs[i].flags; temp_p->features = aic_pdevs[i].features; diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.h b/drivers/scsi/aic94xx/aic94xx_hwi.h index c6c3d18222fa..491e5d8a98bc 100644 --- a/drivers/scsi/aic94xx/aic94xx_hwi.h +++ b/drivers/scsi/aic94xx/aic94xx_hwi.h @@ -40,18 +40,6 @@ #define ASD_MAX_PHYS 8 #define ASD_PCBA_SN_SIZE 12 -/* Those are to be further named properly, the "RAZORx" part, and - * subsequently included in include/linux/pci_ids.h. - */ -#define PCI_DEVICE_ID_ADAPTEC2_RAZOR10 0x410 -#define PCI_DEVICE_ID_ADAPTEC2_RAZOR12 0x412 -#define PCI_DEVICE_ID_ADAPTEC2_RAZOR1E 0x41E -#define PCI_DEVICE_ID_ADAPTEC2_RAZOR1F 0x41F -#define PCI_DEVICE_ID_ADAPTEC2_RAZOR30 0x430 -#define PCI_DEVICE_ID_ADAPTEC2_RAZOR32 0x432 -#define PCI_DEVICE_ID_ADAPTEC2_RAZOR3E 0x43E -#define PCI_DEVICE_ID_ADAPTEC2_RAZOR3F 0x43F - struct asd_ha_addrspace { void __iomem *addr; unsigned long start; /* pci resource start */ diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index 63bcde246447..b70d6e7f96e9 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c @@ -583,7 +583,7 @@ static int __devinit asd_pci_probe(struct pci_dev *dev, asd_ha = kzalloc(sizeof(*asd_ha), GFP_KERNEL); if (!asd_ha) { asd_printk("out of memory\n"); - goto Err; + goto Err_put; } asd_ha->pcidev = dev; asd_ha->sas_ha.dev = &asd_ha->pcidev->dev; @@ -600,14 +600,12 @@ static int __devinit asd_pci_probe(struct pci_dev *dev, shost->max_cmd_len = 16; err = scsi_add_host(shost, &dev->dev); - if (err) { - scsi_host_put(shost); + if (err) goto Err_free; - } err = asd_dev->setup(asd_ha); if (err) - goto Err_free; + goto Err_remove; err = -ENODEV; if (!pci_set_dma_mask(dev, DMA_64BIT_MASK) @@ -618,14 +616,14 @@ static int __devinit asd_pci_probe(struct pci_dev *dev, ; else { asd_printk("no suitable DMA mask for %s\n", pci_name(dev)); - goto Err_free; + goto Err_remove; } pci_set_drvdata(dev, asd_ha); err = asd_map_ha(asd_ha); if (err) - goto Err_free; + goto Err_remove; err = asd_create_ha_caches(asd_ha); if (err) @@ -692,9 +690,12 @@ Err_free_cache: asd_destroy_ha_caches(asd_ha); Err_unmap: asd_unmap_ha(asd_ha); +Err_remove: + scsi_remove_host(shost); Err_free: kfree(asd_ha); - scsi_remove_host(shost); +Err_put: + scsi_host_put(shost); Err: pci_disable_device(dev); return err; @@ -829,22 +830,15 @@ static struct sas_domain_function_template aic94xx_transport_functions = { }; static const struct pci_device_id aic94xx_pci_table[] __devinitdata = { - {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR10), - 0, 0, 1}, - {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR12), - 0, 0, 1}, - {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR1E), - 0, 0, 1}, - {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR1F), - 0, 0, 1}, - {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR30), - 0, 0, 2}, - {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR32), - 0, 0, 2}, - {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR3E), - 0, 0, 2}, - {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR3F), - 0, 0, 2}, + {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x410),0, 0, 1}, + {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x412),0, 0, 1}, + {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x416),0, 0, 1}, + {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x41E),0, 0, 1}, + {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x41F),0, 0, 1}, + {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x430),0, 0, 2}, + {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x432),0, 0, 2}, + {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x43E),0, 0, 2}, + {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x43F),0, 0, 2}, {} }; diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c index ab13824df856..f2b23e01401a 100644 --- a/drivers/scsi/aic94xx/aic94xx_task.c +++ b/drivers/scsi/aic94xx/aic94xx_task.c @@ -207,7 +207,7 @@ static void asd_get_response_tasklet(struct asd_ascb *ascb, "stat(0x%x) is not CHECK_CONDITION" "\n", SAS_ADDR(task->dev->sas_addr), - ts->stat); + iu->status); } } } else { diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h index f0b8bf4534f0..ace7a15b413e 100644 --- a/drivers/scsi/arcmsr/arcmsr.h +++ b/drivers/scsi/arcmsr/arcmsr.h @@ -9,7 +9,7 @@ ** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved. ** ** Web site: www.areca.com.tw -** E-mail: erich@areca.com.tw +** E-mail: support@areca.com.tw ** ** 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 @@ -45,19 +45,26 @@ #include <linux/interrupt.h> struct class_device_attribute; - -#define ARCMSR_MAX_OUTSTANDING_CMD 256 -#define ARCMSR_MAX_FREECCB_NUM 288 -#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.14" +/*The limit of outstanding scsi command that firmware can handle*/ +#define ARCMSR_MAX_OUTSTANDING_CMD 256 +#define ARCMSR_MAX_FREECCB_NUM 320 +#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2007/08/30" #define ARCMSR_SCSI_INITIATOR_ID 255 #define ARCMSR_MAX_XFER_SECTORS 512 -#define ARCMSR_MAX_XFER_SECTORS_B 4096 -#define ARCMSR_MAX_TARGETID 17 -#define ARCMSR_MAX_TARGETLUN 8 -#define ARCMSR_MAX_CMD_PERLUN ARCMSR_MAX_OUTSTANDING_CMD -#define ARCMSR_MAX_QBUFFER 4096 -#define ARCMSR_MAX_SG_ENTRIES 38 - +#define ARCMSR_MAX_XFER_SECTORS_B 4096 +#define ARCMSR_MAX_TARGETID 17 +#define ARCMSR_MAX_TARGETLUN 8 +#define ARCMSR_MAX_CMD_PERLUN ARCMSR_MAX_OUTSTANDING_CMD +#define ARCMSR_MAX_QBUFFER 4096 +#define ARCMSR_MAX_SG_ENTRIES 38 +#define ARCMSR_MAX_HBB_POSTQUEUE 264 +/* +********************************************************************************** +** +********************************************************************************** +*/ +#define ARC_SUCCESS 0 +#define ARC_FAILURE 1 /* ******************************************************************************* ** split 64bits dma addressing @@ -90,7 +97,7 @@ struct CMD_MESSAGE_FIELD uint8_t messagedatabuffer[1032]; }; /* IOP message transfer */ -#define ARCMSR_MESSAGE_FAIL 0x0001 +#define ARCMSR_MESSAGE_FAIL 0x0001 /* DeviceType */ #define ARECA_SATA_RAID 0x90000000 /* FunctionCode */ @@ -163,27 +170,27 @@ struct QBUFFER }; /* ******************************************************************************* -** FIRMWARE INFO +** FIRMWARE INFO for Intel IOP R 80331 processor (Type A) ******************************************************************************* */ struct FIRMWARE_INFO { - uint32_t signature; /*0, 00-03*/ - uint32_t request_len; /*1, 04-07*/ - uint32_t numbers_queue; /*2, 08-11*/ + uint32_t signature; /*0, 00-03*/ + uint32_t request_len; /*1, 04-07*/ + uint32_t numbers_queue; /*2, 08-11*/ uint32_t sdram_size; /*3, 12-15*/ - uint32_t ide_channels; /*4, 16-19*/ - char vendor[40]; /*5, 20-59*/ - char model[8]; /*15, 60-67*/ - char firmware_ver[16]; /*17, 68-83*/ - char device_map[16]; /*21, 84-99*/ + uint32_t ide_channels; /*4, 16-19*/ + char vendor[40]; /*5, 20-59*/ + char model[8]; /*15, 60-67*/ + char firmware_ver[16]; /*17, 68-83*/ + char device_map[16]; /*21, 84-99*/ }; /* signature of set and get firmware config */ -#define ARCMSR_SIGNATURE_GET_CONFIG 0x87974060 -#define ARCMSR_SIGNATURE_SET_CONFIG 0x87974063 +#define ARCMSR_SIGNATURE_GET_CONFIG 0x87974060 +#define ARCMSR_SIGNATURE_SET_CONFIG 0x87974063 /* message code of inbound message register */ -#define ARCMSR_INBOUND_MESG0_NOP 0x00000000 -#define ARCMSR_INBOUND_MESG0_GET_CONFIG 0x00000001 +#define ARCMSR_INBOUND_MESG0_NOP 0x00000000 +#define ARCMSR_INBOUND_MESG0_GET_CONFIG 0x00000001 #define ARCMSR_INBOUND_MESG0_SET_CONFIG 0x00000002 #define ARCMSR_INBOUND_MESG0_ABORT_CMD 0x00000003 #define ARCMSR_INBOUND_MESG0_STOP_BGRB 0x00000004 @@ -203,6 +210,60 @@ struct FIRMWARE_INFO #define ARCMSR_CCBREPLY_FLAG_ERROR 0x10000000 /* outbound firmware ok */ #define ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK 0x80000000 + +/* +************************************************************************ +** SPEC. for Areca Type B adapter +************************************************************************ +*/ +/* ARECA HBB COMMAND for its FIRMWARE */ +/* window of "instruction flags" from driver to iop */ +#define ARCMSR_DRV2IOP_DOORBELL 0x00020400 +#define ARCMSR_DRV2IOP_DOORBELL_MASK 0x00020404 +/* window of "instruction flags" from iop to driver */ +#define ARCMSR_IOP2DRV_DOORBELL 0x00020408 +#define ARCMSR_IOP2DRV_DOORBELL_MASK 0x0002040C +/* ARECA FLAG LANGUAGE */ +/* ioctl transfer */ +#define ARCMSR_IOP2DRV_DATA_WRITE_OK 0x00000001 +/* ioctl transfer */ +#define ARCMSR_IOP2DRV_DATA_READ_OK 0x00000002 +#define ARCMSR_IOP2DRV_CDB_DONE 0x00000004 +#define ARCMSR_IOP2DRV_MESSAGE_CMD_DONE 0x00000008 + +#define ARCMSR_DOORBELL_HANDLE_INT 0x0000000F +#define ARCMSR_DOORBELL_INT_CLEAR_PATTERN 0xFF00FFF0 +#define ARCMSR_MESSAGE_INT_CLEAR_PATTERN 0xFF00FFF7 +/* (ARCMSR_INBOUND_MESG0_GET_CONFIG<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */ +#define ARCMSR_MESSAGE_GET_CONFIG 0x00010008 +/* (ARCMSR_INBOUND_MESG0_SET_CONFIG<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */ +#define ARCMSR_MESSAGE_SET_CONFIG 0x00020008 +/* (ARCMSR_INBOUND_MESG0_ABORT_CMD<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */ +#define ARCMSR_MESSAGE_ABORT_CMD 0x00030008 +/* (ARCMSR_INBOUND_MESG0_STOP_BGRB<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */ +#define ARCMSR_MESSAGE_STOP_BGRB 0x00040008 +/* (ARCMSR_INBOUND_MESG0_FLUSH_CACHE<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */ +#define ARCMSR_MESSAGE_FLUSH_CACHE 0x00050008 +/* (ARCMSR_INBOUND_MESG0_START_BGRB<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */ +#define ARCMSR_MESSAGE_START_BGRB 0x00060008 +#define ARCMSR_MESSAGE_START_DRIVER_MODE 0x000E0008 +#define ARCMSR_MESSAGE_SET_POST_WINDOW 0x000F0008 +/* ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK */ +#define ARCMSR_MESSAGE_FIRMWARE_OK 0x80000000 +/* ioctl transfer */ +#define ARCMSR_DRV2IOP_DATA_WRITE_OK 0x00000001 +/* ioctl transfer */ +#define ARCMSR_DRV2IOP_DATA_READ_OK 0x00000002 +#define ARCMSR_DRV2IOP_CDB_POSTED 0x00000004 +#define ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED 0x00000008 + +/* data tunnel buffer between user space program and its firmware */ +/* user space data to iop 128bytes */ +#define ARCMSR_IOCTL_WBUFFER 0x0000fe00 +/* iop data to user space 128bytes */ +#define ARCMSR_IOCTL_RBUFFER 0x0000ff00 +/* iop message_rwbuffer for message command */ +#define ARCMSR_MSGCODE_RWBUFFER 0x0000fa00 /* ******************************************************************************* ** ARECA SCSI COMMAND DESCRIPTOR BLOCK size 0x1F8 (504) @@ -214,7 +275,6 @@ struct ARCMSR_CDB uint8_t TargetID; uint8_t LUN; uint8_t Function; - uint8_t CdbLength; uint8_t sgcount; uint8_t Flags; @@ -224,20 +284,18 @@ struct ARCMSR_CDB #define ARCMSR_CDB_FLAG_SIMPLEQ 0x00 #define ARCMSR_CDB_FLAG_HEADQ 0x08 #define ARCMSR_CDB_FLAG_ORDEREDQ 0x10 - uint8_t Reserved1; + uint8_t Reserved1; uint32_t Context; uint32_t DataLength; - uint8_t Cdb[16]; - uint8_t DeviceStatus; -#define ARCMSR_DEV_CHECK_CONDITION 0x02 -#define ARCMSR_DEV_SELECT_TIMEOUT 0xF0 -#define ARCMSR_DEV_ABORTED 0xF1 -#define ARCMSR_DEV_INIT_FAIL 0xF2 - uint8_t SenseData[15]; +#define ARCMSR_DEV_CHECK_CONDITION 0x02 +#define ARCMSR_DEV_SELECT_TIMEOUT 0xF0 +#define ARCMSR_DEV_ABORTED 0xF1 +#define ARCMSR_DEV_INIT_FAIL 0xF2 + uint8_t SenseData[15]; union { struct SG32ENTRY sg32entry[ARCMSR_MAX_SG_ENTRIES]; @@ -246,10 +304,10 @@ struct ARCMSR_CDB }; /* ******************************************************************************* -** Messaging Unit (MU) of the Intel R 80331 I/O processor (80331) +** Messaging Unit (MU) of the Intel R 80331 I/O processor(Type A) and Type B processor ******************************************************************************* */ -struct MessageUnit +struct MessageUnit_A { uint32_t resrved0[4]; /*0000 000F*/ uint32_t inbound_msgaddr0; /*0010 0013*/ @@ -274,6 +332,30 @@ struct MessageUnit uint32_t message_rbuffer[32]; /*0F00 0F7F 32*/ uint32_t reserved6[32]; /*0F80 0FFF 32*/ }; + +struct MessageUnit_B +{ + uint32_t post_qbuffer[ARCMSR_MAX_HBB_POSTQUEUE]; + uint32_t done_qbuffer[ARCMSR_MAX_HBB_POSTQUEUE]; + uint32_t postq_index; + uint32_t doneq_index; + uint32_t *drv2iop_doorbell_reg; + uint32_t *drv2iop_doorbell_mask_reg; + uint32_t *iop2drv_doorbell_reg; + uint32_t *iop2drv_doorbell_mask_reg; + uint32_t *msgcode_rwbuffer_reg; + uint32_t *ioctl_wbuffer_reg; + uint32_t *ioctl_rbuffer_reg; +}; + +struct MessageUnit +{ + union + { + struct MessageUnit_A pmu_A; + struct MessageUnit_B pmu_B; + } u; +}; /* ******************************************************************************* ** Adapter Control Block @@ -281,37 +363,45 @@ struct MessageUnit */ struct AdapterControlBlock { + uint32_t adapter_type; /* adapter A,B..... */ + #define ACB_ADAPTER_TYPE_A 0x00000001 /* hba I IOP */ + #define ACB_ADAPTER_TYPE_B 0x00000002 /* hbb M IOP */ + #define ACB_ADAPTER_TYPE_C 0x00000004 /* hbc P IOP */ + #define ACB_ADAPTER_TYPE_D 0x00000008 /* hbd A IOP */ struct pci_dev * pdev; struct Scsi_Host * host; unsigned long vir2phy_offset; /* Offset is used in making arc cdb physical to virtual calculations */ uint32_t outbound_int_enable; - struct MessageUnit __iomem * pmu; + struct MessageUnit * pmu; /* message unit ATU inbound base address0 */ uint32_t acb_flags; -#define ACB_F_SCSISTOPADAPTER 0x0001 -#define ACB_F_MSG_STOP_BGRB 0x0002 + #define ACB_F_SCSISTOPADAPTER 0x0001 + #define ACB_F_MSG_STOP_BGRB 0x0002 /* stop RAID background rebuild */ -#define ACB_F_MSG_START_BGRB 0x0004 + #define ACB_F_MSG_START_BGRB 0x0004 /* stop RAID background rebuild */ -#define ACB_F_IOPDATA_OVERFLOW 0x0008 + #define ACB_F_IOPDATA_OVERFLOW 0x0008 /* iop message data rqbuffer overflow */ -#define ACB_F_MESSAGE_WQBUFFER_CLEARED 0x0010 + #define ACB_F_MESSAGE_WQBUFFER_CLEARED 0x0010 /* message clear wqbuffer */ -#define ACB_F_MESSAGE_RQBUFFER_CLEARED 0x0020 + #define ACB_F_MESSAGE_RQBUFFER_CLEARED 0x0020 /* message clear rqbuffer */ -#define ACB_F_MESSAGE_WQBUFFER_READED 0x0040 -#define ACB_F_BUS_RESET 0x0080 -#define ACB_F_IOP_INITED 0x0100 + #define ACB_F_MESSAGE_WQBUFFER_READED 0x0040 + #define ACB_F_BUS_RESET 0x0080 + #define ACB_F_IOP_INITED 0x0100 /* iop init */ struct CommandControlBlock * pccb_pool[ARCMSR_MAX_FREECCB_NUM]; /* used for memory free */ struct list_head ccb_free_list; /* head of free ccb list */ + atomic_t ccboutstandingcount; + /*The present outstanding command number that in the IOP that + waiting for being handled by FW*/ void * dma_coherent; /* dma_coherent used for memory free */ @@ -353,7 +443,7 @@ struct CommandControlBlock { struct ARCMSR_CDB arcmsr_cdb; /* - ** 0-503 (size of CDB=504): + ** 0-503 (size of CDB = 504): ** arcmsr messenger scsi command descriptor size 504 bytes */ uint32_t cdb_shifted_phyaddr; @@ -466,7 +556,9 @@ struct SENSE_DATA #define ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE 0x01 #define ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE 0x1F -extern void arcmsr_post_Qbuffer(struct AdapterControlBlock *acb); +extern void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *); +extern void arcmsr_iop_message_read(struct AdapterControlBlock *); +extern struct QBUFFER *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *); extern struct class_device_attribute *arcmsr_host_attrs[]; -extern int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *acb); +extern int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *); void arcmsr_free_sysfs_attr(struct AdapterControlBlock *acb); diff --git a/drivers/scsi/arcmsr/arcmsr_attr.c b/drivers/scsi/arcmsr/arcmsr_attr.c index 06c0dce3b839..d04d1aa28fa4 100644 --- a/drivers/scsi/arcmsr/arcmsr_attr.c +++ b/drivers/scsi/arcmsr/arcmsr_attr.c @@ -8,7 +8,7 @@ ** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved ** ** Web site: www.areca.com.tw -** E-mail: erich@areca.com.tw +** E-mail: support@areca.com.tw ** ** 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 @@ -49,6 +49,7 @@ #include <linux/init.h> #include <linux/errno.h> #include <linux/delay.h> +#include <linux/pci.h> #include <scsi/scsi_cmnd.h> #include <scsi/scsi_device.h> @@ -58,15 +59,14 @@ struct class_device_attribute *arcmsr_host_attrs[]; -static ssize_t -arcmsr_sysfs_iop_message_read(struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) +static ssize_t arcmsr_sysfs_iop_message_read(struct kobject *kobj, + struct bin_attribute *bin, + char *buf, loff_t off, + size_t count) { struct class_device *cdev = container_of(kobj,struct class_device,kobj); struct Scsi_Host *host = class_to_shost(cdev); struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; - struct MessageUnit __iomem *reg = acb->pmu; uint8_t *pQbuffer,*ptmpQbuffer; int32_t allxfer_len = 0; @@ -85,12 +85,13 @@ arcmsr_sysfs_iop_message_read(struct kobject *kobj, allxfer_len++; } if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { - struct QBUFFER __iomem * prbuffer = (struct QBUFFER __iomem *) - ®->message_rbuffer; - uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data; + struct QBUFFER *prbuffer; + uint8_t *iop_data; int32_t iop_len; acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; + prbuffer = arcmsr_get_iop_rqbuffer(acb); + iop_data = (uint8_t *)prbuffer->data; iop_len = readl(&prbuffer->data_len); while (iop_len > 0) { acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data); @@ -99,16 +100,15 @@ arcmsr_sysfs_iop_message_read(struct kobject *kobj, iop_data++; iop_len--; } - writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, - ®->inbound_doorbell); + arcmsr_iop_message_read(acb); } return (allxfer_len); } -static ssize_t -arcmsr_sysfs_iop_message_write(struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) +static ssize_t arcmsr_sysfs_iop_message_write(struct kobject *kobj, + struct bin_attribute *bin, + char *buf, loff_t off, + size_t count) { struct class_device *cdev = container_of(kobj,struct class_device,kobj); struct Scsi_Host *host = class_to_shost(cdev); @@ -126,7 +126,7 @@ arcmsr_sysfs_iop_message_write(struct kobject *kobj, wqbuf_lastindex = acb->wqbuf_lastindex; wqbuf_firstindex = acb->wqbuf_firstindex; if (wqbuf_lastindex != wqbuf_firstindex) { - arcmsr_post_Qbuffer(acb); + arcmsr_post_ioctldata2iop(acb); return 0; /*need retry*/ } else { my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1) @@ -144,7 +144,7 @@ arcmsr_sysfs_iop_message_write(struct kobject *kobj, if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) { acb->acb_flags &= ~ACB_F_MESSAGE_WQBUFFER_CLEARED; - arcmsr_post_Qbuffer(acb); + arcmsr_post_ioctldata2iop(acb); } return count; } else { @@ -153,15 +153,14 @@ arcmsr_sysfs_iop_message_write(struct kobject *kobj, } } -static ssize_t -arcmsr_sysfs_iop_message_clear(struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) +static ssize_t arcmsr_sysfs_iop_message_clear(struct kobject *kobj, + struct bin_attribute *bin, + char *buf, loff_t off, + size_t count) { struct class_device *cdev = container_of(kobj,struct class_device,kobj); struct Scsi_Host *host = class_to_shost(cdev); struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; - struct MessageUnit __iomem *reg = acb->pmu; uint8_t *pQbuffer; if (!capable(CAP_SYS_ADMIN)) @@ -169,8 +168,7 @@ arcmsr_sysfs_iop_message_clear(struct kobject *kobj, if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; - writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK - , ®->inbound_doorbell); + arcmsr_iop_message_read(acb); } acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED @@ -191,6 +189,7 @@ static struct bin_attribute arcmsr_sysfs_message_read_attr = { .attr = { .name = "mu_read", .mode = S_IRUSR , + .owner = THIS_MODULE, }, .size = 1032, .read = arcmsr_sysfs_iop_message_read, @@ -200,6 +199,7 @@ static struct bin_attribute arcmsr_sysfs_message_write_attr = { .attr = { .name = "mu_write", .mode = S_IWUSR, + .owner = THIS_MODULE, }, .size = 1032, .write = arcmsr_sysfs_iop_message_write, @@ -209,6 +209,7 @@ static struct bin_attribute arcmsr_sysfs_message_clear_attr = { .attr = { .name = "mu_clear", .mode = S_IWUSR, + .owner = THIS_MODULE, }, .size = 1, .write = arcmsr_sysfs_iop_message_clear, @@ -219,31 +220,26 @@ int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *acb) struct Scsi_Host *host = acb->host; int error; - error = sysfs_create_bin_file(&host->shost_classdev.kobj, - &arcmsr_sysfs_message_read_attr); + error = sysfs_create_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_read_attr); if (error) { printk(KERN_ERR "arcmsr: alloc sysfs mu_read failed\n"); goto error_bin_file_message_read; } - error = sysfs_create_bin_file(&host->shost_classdev.kobj, - &arcmsr_sysfs_message_write_attr); + error = sysfs_create_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_write_attr); if (error) { printk(KERN_ERR "arcmsr: alloc sysfs mu_write failed\n"); goto error_bin_file_message_write; } - error = sysfs_create_bin_file(&host->shost_classdev.kobj, - &arcmsr_sysfs_message_clear_attr); + error = sysfs_create_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_clear_attr); if (error) { printk(KERN_ERR "arcmsr: alloc sysfs mu_clear failed\n"); goto error_bin_file_message_clear; } return 0; error_bin_file_message_clear: - sysfs_remove_bin_file(&host->shost_classdev.kobj, - &arcmsr_sysfs_message_write_attr); + sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_write_attr); error_bin_file_message_write: - sysfs_remove_bin_file(&host->shost_classdev.kobj, - &arcmsr_sysfs_message_read_attr); + sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_read_attr); error_bin_file_message_read: return error; } @@ -252,12 +248,9 @@ void arcmsr_free_sysfs_attr(struct AdapterControlBlock *acb) { struct Scsi_Host *host = acb->host; - sysfs_remove_bin_file(&host->shost_classdev.kobj, - &arcmsr_sysfs_message_clear_attr); - sysfs_remove_bin_file(&host->shost_classdev.kobj, - &arcmsr_sysfs_message_write_attr); - sysfs_remove_bin_file(&host->shost_classdev.kobj, - &arcmsr_sysfs_message_read_attr); + sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_clear_attr); + sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_write_attr); + sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_read_attr); } diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index 0ddfc21e9f7d..cfcf40159eab 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -9,7 +9,7 @@ ** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved ** ** Web site: www.areca.com.tw -** E-mail: erich@areca.com.tw +** E-mail: support@areca.com.tw ** ** 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 @@ -71,33 +71,34 @@ #include <scsi/scsicam.h> #include "arcmsr.h" -MODULE_AUTHOR("Erich Chen <erich@areca.com.tw>"); +MODULE_AUTHOR("Erich Chen <support@areca.com.tw>"); MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/13xx/16xx) SATA/SAS RAID HOST Adapter"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION(ARCMSR_DRIVER_VERSION); -static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_cmnd *cmd); +static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, + struct scsi_cmnd *cmd); +static int arcmsr_iop_confirm(struct AdapterControlBlock *acb); static int arcmsr_abort(struct scsi_cmnd *); static int arcmsr_bus_reset(struct scsi_cmnd *); static int arcmsr_bios_param(struct scsi_device *sdev, - struct block_device *bdev, sector_t capacity, int *info); -static int arcmsr_queue_command(struct scsi_cmnd * cmd, - void (*done) (struct scsi_cmnd *)); + struct block_device *bdev, sector_t capacity, int *info); +static int arcmsr_queue_command(struct scsi_cmnd *cmd, + void (*done) (struct scsi_cmnd *)); static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id); static void arcmsr_remove(struct pci_dev *pdev); static void arcmsr_shutdown(struct pci_dev *pdev); static void arcmsr_iop_init(struct AdapterControlBlock *acb); static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb); +static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb); static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb); -static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb); -static uint8_t arcmsr_wait_msgint_ready(struct AdapterControlBlock *acb); +static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb); +static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb); static const char *arcmsr_info(struct Scsi_Host *); static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb); -static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev, - pci_channel_state_t state); -static pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev); -static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, int queue_depth) +static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, + int queue_depth) { if (queue_depth > ARCMSR_MAX_CMD_PERLUN) queue_depth = ARCMSR_MAX_CMD_PERLUN; @@ -123,17 +124,25 @@ static struct scsi_host_template arcmsr_scsi_host_template = { .use_clustering = ENABLE_CLUSTERING, .shost_attrs = arcmsr_host_attrs, }; +#ifdef CONFIG_SCSI_ARCMSR_AER +static pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev); +static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev, + pci_channel_state_t state); + static struct pci_error_handlers arcmsr_pci_error_handlers = { .error_detected = arcmsr_pci_error_detected, .slot_reset = arcmsr_pci_slot_reset, }; - +#endif static struct pci_device_id arcmsr_device_id_table[] = { {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1110)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1120)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1130)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1160)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1170)}, + {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1200)}, + {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1201)}, + {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1202)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1210)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1220)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1230)}, @@ -153,20 +162,20 @@ static struct pci_driver arcmsr_pci_driver = { .probe = arcmsr_probe, .remove = arcmsr_remove, .shutdown = arcmsr_shutdown, + #ifdef CONFIG_SCSI_ARCMSR_AER .err_handler = &arcmsr_pci_error_handlers, + #endif }; static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id) { irqreturn_t handle_state; - struct AdapterControlBlock *acb; - unsigned long flags; + struct AdapterControlBlock *acb = dev_id; - acb = (struct AdapterControlBlock *)dev_id; - - spin_lock_irqsave(acb->host->host_lock, flags); + spin_lock(acb->host->host_lock); handle_state = arcmsr_interrupt(acb); - spin_unlock_irqrestore(acb->host->host_lock, flags); + spin_unlock(acb->host->host_lock); + return handle_state; } @@ -198,68 +207,159 @@ static int arcmsr_bios_param(struct scsi_device *sdev, return 0; } -static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) +static void arcmsr_define_adapter_type(struct AdapterControlBlock *acb) { struct pci_dev *pdev = acb->pdev; - struct MessageUnit __iomem *reg = acb->pmu; - u32 ccb_phyaddr_hi32; - void *dma_coherent; - dma_addr_t dma_coherent_handle, dma_addr; - struct CommandControlBlock *ccb_tmp; - int i, j; + u16 dev_id; + pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id); + switch (dev_id) { + case 0x1201 : { + acb->adapter_type = ACB_ADAPTER_TYPE_B; + } + break; + + default : acb->adapter_type = ACB_ADAPTER_TYPE_A; + } +} + +static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) +{ + + switch (acb->adapter_type) { + + case ACB_ADAPTER_TYPE_A: { + struct pci_dev *pdev = acb->pdev; + void *dma_coherent; + dma_addr_t dma_coherent_handle, dma_addr; + struct CommandControlBlock *ccb_tmp; + uint32_t intmask_org; + int i, j; + + acb->pmu = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); + if (!acb->pmu) { + printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", + acb->host->host_no); + } - dma_coherent = dma_alloc_coherent(&pdev->dev, + dma_coherent = dma_alloc_coherent(&pdev->dev, ARCMSR_MAX_FREECCB_NUM * sizeof (struct CommandControlBlock) + 0x20, &dma_coherent_handle, GFP_KERNEL); - if (!dma_coherent) - return -ENOMEM; + if (!dma_coherent) + return -ENOMEM; - acb->dma_coherent = dma_coherent; - acb->dma_coherent_handle = dma_coherent_handle; + acb->dma_coherent = dma_coherent; + acb->dma_coherent_handle = dma_coherent_handle; - if (((unsigned long)dma_coherent & 0x1F)) { - dma_coherent = dma_coherent + - (0x20 - ((unsigned long)dma_coherent & 0x1F)); - dma_coherent_handle = dma_coherent_handle + - (0x20 - ((unsigned long)dma_coherent_handle & 0x1F)); - } + if (((unsigned long)dma_coherent & 0x1F)) { + dma_coherent = dma_coherent + + (0x20 - ((unsigned long)dma_coherent & 0x1F)); + dma_coherent_handle = dma_coherent_handle + + (0x20 - ((unsigned long)dma_coherent_handle & 0x1F)); + } - dma_addr = dma_coherent_handle; - ccb_tmp = (struct CommandControlBlock *)dma_coherent; - for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { - ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5; - ccb_tmp->acb = acb; - acb->pccb_pool[i] = ccb_tmp; - list_add_tail(&ccb_tmp->list, &acb->ccb_free_list); - dma_addr = dma_addr + sizeof (struct CommandControlBlock); - ccb_tmp++; - } + dma_addr = dma_coherent_handle; + ccb_tmp = (struct CommandControlBlock *)dma_coherent; + for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { + ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5; + ccb_tmp->acb = acb; + acb->pccb_pool[i] = ccb_tmp; + list_add_tail(&ccb_tmp->list, &acb->ccb_free_list); + dma_addr = dma_addr + sizeof(struct CommandControlBlock); + ccb_tmp++; + } - acb->vir2phy_offset = (unsigned long)ccb_tmp - - (unsigned long)dma_addr; - for (i = 0; i < ARCMSR_MAX_TARGETID; i++) - for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++) - acb->devstate[i][j] = ARECA_RAID_GOOD; + acb->vir2phy_offset = (unsigned long)ccb_tmp -(unsigned long)dma_addr; + for (i = 0; i < ARCMSR_MAX_TARGETID; i++) + for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++) + acb->devstate[i][j] = ARECA_RAID_GONE; - /* - ** here we need to tell iop 331 our ccb_tmp.HighPart - ** if ccb_tmp.HighPart is not zero - */ - ccb_phyaddr_hi32 = (uint32_t) ((dma_coherent_handle >> 16) >> 16); - if (ccb_phyaddr_hi32 != 0) { - writel(ARCMSR_SIGNATURE_SET_CONFIG, ®->message_rwbuffer[0]); - writel(ccb_phyaddr_hi32, ®->message_rwbuffer[1]); - writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, ®->inbound_msgaddr0); - if (arcmsr_wait_msgint_ready(acb)) - printk(KERN_NOTICE "arcmsr%d: " - "'set ccb high part physical address' timeout\n", - acb->host->host_no); - } + /* + ** here we need to tell iop 331 our ccb_tmp.HighPart + ** if ccb_tmp.HighPart is not zero + */ + intmask_org = arcmsr_disable_outbound_ints(acb); + } + break; + + case ACB_ADAPTER_TYPE_B: { + + struct pci_dev *pdev = acb->pdev; + struct MessageUnit_B *reg; + void *mem_base0, *mem_base1; + void *dma_coherent; + dma_addr_t dma_coherent_handle, dma_addr; + uint32_t intmask_org; + struct CommandControlBlock *ccb_tmp; + int i, j; + + dma_coherent = dma_alloc_coherent(&pdev->dev, + ((ARCMSR_MAX_FREECCB_NUM * + sizeof(struct CommandControlBlock) + 0x20) + + sizeof(struct MessageUnit_B)), + &dma_coherent_handle, GFP_KERNEL); + if (!dma_coherent) + return -ENOMEM; - writel(readl(®->outbound_intmask) | - ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE, - ®->outbound_intmask); + acb->dma_coherent = dma_coherent; + acb->dma_coherent_handle = dma_coherent_handle; + + if (((unsigned long)dma_coherent & 0x1F)) { + dma_coherent = dma_coherent + + (0x20 - ((unsigned long)dma_coherent & 0x1F)); + dma_coherent_handle = dma_coherent_handle + + (0x20 - ((unsigned long)dma_coherent_handle & 0x1F)); + } + + reg = (struct MessageUnit_B *)(dma_coherent + + ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock)); + + dma_addr = dma_coherent_handle; + ccb_tmp = (struct CommandControlBlock *)dma_coherent; + for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { + ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5; + ccb_tmp->acb = acb; + acb->pccb_pool[i] = ccb_tmp; + list_add_tail(&ccb_tmp->list, &acb->ccb_free_list); + dma_addr = dma_addr + sizeof(struct CommandControlBlock); + ccb_tmp++; + } + + reg = (struct MessageUnit_B *)(dma_coherent + + ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock)); + acb->pmu = (struct MessageUnit *)reg; + mem_base0 = ioremap(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + mem_base1 = ioremap(pci_resource_start(pdev, 2), + pci_resource_len(pdev, 2)); + reg->drv2iop_doorbell_reg = (uint32_t *)((char *)mem_base0 + + ARCMSR_DRV2IOP_DOORBELL); + reg->drv2iop_doorbell_mask_reg = (uint32_t *)((char *)mem_base0 + + ARCMSR_DRV2IOP_DOORBELL_MASK); + reg->iop2drv_doorbell_reg = (uint32_t *)((char *)mem_base0 + + ARCMSR_IOP2DRV_DOORBELL); + reg->iop2drv_doorbell_mask_reg = (uint32_t *)((char *)mem_base0 + + ARCMSR_IOP2DRV_DOORBELL_MASK); + reg->ioctl_wbuffer_reg = (uint32_t *)((char *)mem_base1 + + ARCMSR_IOCTL_WBUFFER); + reg->ioctl_rbuffer_reg = (uint32_t *)((char *)mem_base1 + + ARCMSR_IOCTL_RBUFFER); + reg->msgcode_rwbuffer_reg = (uint32_t *)((char *)mem_base1 + + ARCMSR_MSGCODE_RWBUFFER); + + acb->vir2phy_offset = (unsigned long)ccb_tmp -(unsigned long)dma_addr; + for (i = 0; i < ARCMSR_MAX_TARGETID; i++) + for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++) + acb->devstate[i][j] = ARECA_RAID_GOOD; + + /* + ** here we need to tell iop 331 our ccb_tmp.HighPart + ** if ccb_tmp.HighPart is not zero + */ + intmask_org = arcmsr_disable_outbound_ints(acb); + } + break; + } return 0; } @@ -310,16 +410,11 @@ static int arcmsr_probe(struct pci_dev *pdev, host->unique_id = (bus << 8) | dev_fun; host->irq = pdev->irq; error = pci_request_regions(pdev, "arcmsr"); - if (error) + if (error) { goto out_host_put; - - acb->pmu = ioremap(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - if (!acb->pmu) { - printk(KERN_NOTICE "arcmsr%d: memory" - " mapping region fail \n", acb->host->host_no); - goto out_release_regions; } + arcmsr_define_adapter_type(acb); + acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED | ACB_F_MESSAGE_RQBUFFER_CLEARED | ACB_F_MESSAGE_WQBUFFER_READED); @@ -328,10 +423,10 @@ static int arcmsr_probe(struct pci_dev *pdev, error = arcmsr_alloc_ccb_pool(acb); if (error) - goto out_iounmap; + goto out_release_regions; error = request_irq(pdev->irq, arcmsr_do_interrupt, - IRQF_DISABLED | IRQF_SHARED, "arcmsr", acb); + IRQF_SHARED, "arcmsr", acb); if (error) goto out_free_ccb_pool; @@ -349,14 +444,15 @@ static int arcmsr_probe(struct pci_dev *pdev, goto out_free_sysfs; scsi_scan_host(host); + #ifdef CONFIG_SCSI_ARCMSR_AER pci_enable_pcie_error_reporting(pdev); + #endif return 0; out_free_sysfs: out_free_irq: free_irq(pdev->irq, acb); out_free_ccb_pool: arcmsr_free_ccb_pool(acb); - out_iounmap: iounmap(acb->pmu); out_release_regions: pci_release_regions(pdev); @@ -368,17 +464,84 @@ static int arcmsr_probe(struct pci_dev *pdev, return error; } -static void arcmsr_abort_allcmd(struct AdapterControlBlock *acb) +static uint8_t arcmsr_hba_wait_msgint_ready(struct AdapterControlBlock *acb) +{ + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; + uint32_t Index; + uint8_t Retries = 0x00; + + do { + for (Index = 0; Index < 100; Index++) { + if (readl(®->outbound_intstatus) & + ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { + writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT, + ®->outbound_intstatus); + return 0x00; + } + msleep(10); + }/*max 1 seconds*/ + + } while (Retries++ < 20);/*max 20 sec*/ + return 0xff; +} + +static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb) { - struct MessageUnit __iomem *reg = acb->pmu; + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + uint32_t Index; + uint8_t Retries = 0x00; + + do { + for (Index = 0; Index < 100; Index++) { + if (readl(reg->iop2drv_doorbell_reg) + & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) { + writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN + , reg->iop2drv_doorbell_reg); + return 0x00; + } + msleep(10); + }/*max 1 seconds*/ + + } while (Retries++ < 20);/*max 20 sec*/ + return 0xff; +} + +static void arcmsr_abort_hba_allcmd(struct AdapterControlBlock *acb) +{ + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, ®->inbound_msgaddr0); - if (arcmsr_wait_msgint_ready(acb)) + if (arcmsr_hba_wait_msgint_ready(acb)) + printk(KERN_NOTICE + "arcmsr%d: wait 'abort all outstanding command' timeout \n" + , acb->host->host_no); +} + +static void arcmsr_abort_hbb_allcmd(struct AdapterControlBlock *acb) +{ + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + + writel(ARCMSR_MESSAGE_ABORT_CMD, reg->drv2iop_doorbell_reg); + if (arcmsr_hbb_wait_msgint_ready(acb)) printk(KERN_NOTICE "arcmsr%d: wait 'abort all outstanding command' timeout \n" , acb->host->host_no); } +static void arcmsr_abort_allcmd(struct AdapterControlBlock *acb) +{ + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_A: { + arcmsr_abort_hba_allcmd(acb); + } + break; + + case ACB_ADAPTER_TYPE_B: { + arcmsr_abort_hbb_allcmd(acb); + } + } +} + static void arcmsr_pci_unmap_dma(struct CommandControlBlock *ccb) { struct scsi_cmnd *pcmd = ccb->pcmd; @@ -400,28 +563,239 @@ static void arcmsr_ccb_complete(struct CommandControlBlock *ccb, int stand_flag) pcmd->scsi_done(pcmd); } +static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb) +{ + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; + int retry_count = 30; + + writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, ®->inbound_msgaddr0); + do { + if (!arcmsr_hba_wait_msgint_ready(acb)) + break; + else { + retry_count--; + printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \ + timeout, retry count down = %d \n", acb->host->host_no, retry_count); + } + } while (retry_count != 0); +} + +static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb) +{ + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + int retry_count = 30; + + writel(ARCMSR_MESSAGE_FLUSH_CACHE, reg->drv2iop_doorbell_reg); + do { + if (!arcmsr_hbb_wait_msgint_ready(acb)) + break; + else { + retry_count--; + printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \ + timeout,retry count down = %d \n", acb->host->host_no, retry_count); + } + } while (retry_count != 0); +} + +static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb) +{ + switch (acb->adapter_type) { + + case ACB_ADAPTER_TYPE_A: { + arcmsr_flush_hba_cache(acb); + } + break; + + case ACB_ADAPTER_TYPE_B: { + arcmsr_flush_hbb_cache(acb); + } + } +} + +static void arcmsr_report_sense_info(struct CommandControlBlock *ccb) +{ + + struct scsi_cmnd *pcmd = ccb->pcmd; + struct SENSE_DATA *sensebuffer = (struct SENSE_DATA *)pcmd->sense_buffer; + + pcmd->result = DID_OK << 16; + if (sensebuffer) { + int sense_data_length = + sizeof(struct SENSE_DATA) < sizeof(pcmd->sense_buffer) + ? sizeof(struct SENSE_DATA) : sizeof(pcmd->sense_buffer); + memset(sensebuffer, 0, sizeof(pcmd->sense_buffer)); + memcpy(sensebuffer, ccb->arcmsr_cdb.SenseData, sense_data_length); + sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS; + sensebuffer->Valid = 1; + } +} + +static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb) +{ + u32 orig_mask = 0; + switch (acb->adapter_type) { + + case ACB_ADAPTER_TYPE_A : { + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; + orig_mask = readl(®->outbound_intmask)|\ + ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE; + writel(orig_mask|ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE, \ + ®->outbound_intmask); + } + break; + + case ACB_ADAPTER_TYPE_B : { + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + orig_mask = readl(reg->iop2drv_doorbell_mask_reg) & \ + (~ARCMSR_IOP2DRV_MESSAGE_CMD_DONE); + writel(0, reg->iop2drv_doorbell_mask_reg); + } + break; + } + return orig_mask; +} + +static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb, \ + struct CommandControlBlock *ccb, uint32_t flag_ccb) +{ + + uint8_t id, lun; + id = ccb->pcmd->device->id; + lun = ccb->pcmd->device->lun; + if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) { + if (acb->devstate[id][lun] == ARECA_RAID_GONE) + acb->devstate[id][lun] = ARECA_RAID_GOOD; + ccb->pcmd->result = DID_OK << 16; + arcmsr_ccb_complete(ccb, 1); + } else { + switch (ccb->arcmsr_cdb.DeviceStatus) { + case ARCMSR_DEV_SELECT_TIMEOUT: { + acb->devstate[id][lun] = ARECA_RAID_GONE; + ccb->pcmd->result = DID_NO_CONNECT << 16; + arcmsr_ccb_complete(ccb, 1); + } + break; + + case ARCMSR_DEV_ABORTED: + + case ARCMSR_DEV_INIT_FAIL: { + acb->devstate[id][lun] = ARECA_RAID_GONE; + ccb->pcmd->result = DID_BAD_TARGET << 16; + arcmsr_ccb_complete(ccb, 1); + } + break; + + case ARCMSR_DEV_CHECK_CONDITION: { + acb->devstate[id][lun] = ARECA_RAID_GOOD; + arcmsr_report_sense_info(ccb); + arcmsr_ccb_complete(ccb, 1); + } + break; + + default: + printk(KERN_NOTICE + "arcmsr%d: scsi id = %d lun = %d" + " isr get command error done, " + "but got unknown DeviceStatus = 0x%x \n" + , acb->host->host_no + , id + , lun + , ccb->arcmsr_cdb.DeviceStatus); + acb->devstate[id][lun] = ARECA_RAID_GONE; + ccb->pcmd->result = DID_NO_CONNECT << 16; + arcmsr_ccb_complete(ccb, 1); + break; + } + } +} + +static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, uint32_t flag_ccb) + +{ + struct CommandControlBlock *ccb; + + ccb = (struct CommandControlBlock *)(acb->vir2phy_offset + (flag_ccb << 5)); + if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { + if (ccb->startdone == ARCMSR_CCB_ABORTED) { + struct scsi_cmnd *abortcmd = ccb->pcmd; + if (abortcmd) { + abortcmd->result |= DID_ABORT << 16; + arcmsr_ccb_complete(ccb, 1); + printk(KERN_NOTICE "arcmsr%d: ccb ='0x%p' \ + isr got aborted command \n", acb->host->host_no, ccb); + } + } + printk(KERN_NOTICE "arcmsr%d: isr get an illegal ccb command \ + done acb = '0x%p'" + "ccb = '0x%p' ccbacb = '0x%p' startdone = 0x%x" + " ccboutstandingcount = %d \n" + , acb->host->host_no + , acb + , ccb + , ccb->acb + , ccb->startdone + , atomic_read(&acb->ccboutstandingcount)); + } + arcmsr_report_ccb_state(acb, ccb, flag_ccb); +} + +static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb) +{ + int i = 0; + uint32_t flag_ccb; + + switch (acb->adapter_type) { + + case ACB_ADAPTER_TYPE_A: { + struct MessageUnit_A __iomem *reg = \ + (struct MessageUnit_A *)acb->pmu; + uint32_t outbound_intstatus; + outbound_intstatus = readl(®->outbound_intstatus) & \ + acb->outbound_int_enable; + /*clear and abort all outbound posted Q*/ + writel(outbound_intstatus, ®->outbound_intstatus);/*clear interrupt*/ + while (((flag_ccb = readl(®->outbound_queueport)) != 0xFFFFFFFF) \ + && (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) { + arcmsr_drain_donequeue(acb, flag_ccb); + } + } + break; + + case ACB_ADAPTER_TYPE_B: { + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + /*clear all outbound posted Q*/ + for (i = 0; i < ARCMSR_MAX_HBB_POSTQUEUE; i++) { + if ((flag_ccb = readl(®->done_qbuffer[i])) != 0) { + writel(0, ®->done_qbuffer[i]); + arcmsr_drain_donequeue(acb, flag_ccb); + } + writel(0, ®->post_qbuffer[i]); + } + reg->doneq_index = 0; + reg->postq_index = 0; + } + break; + } +} static void arcmsr_remove(struct pci_dev *pdev) { struct Scsi_Host *host = pci_get_drvdata(pdev); struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; - struct MessageUnit __iomem *reg = acb->pmu; int poll_count = 0; arcmsr_free_sysfs_attr(acb); scsi_remove_host(host); arcmsr_stop_adapter_bgrb(acb); arcmsr_flush_adapter_cache(acb); - writel(readl(®->outbound_intmask) | - ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE, - ®->outbound_intmask); + arcmsr_disable_outbound_ints(acb); acb->acb_flags |= ACB_F_SCSISTOPADAPTER; acb->acb_flags &= ~ACB_F_IOP_INITED; - for (poll_count = 0; poll_count < 256; poll_count++) { + for (poll_count = 0; poll_count < ARCMSR_MAX_OUTSTANDING_CMD; poll_count++) { if (!atomic_read(&acb->ccboutstandingcount)) break; - arcmsr_interrupt(acb); + arcmsr_interrupt(acb);/* FIXME: need spinlock */ msleep(25); } @@ -429,8 +803,7 @@ static void arcmsr_remove(struct pci_dev *pdev) int i; arcmsr_abort_allcmd(acb); - for (i = 0; i < ARCMSR_MAX_OUTSTANDING_CMD; i++) - readl(®->outbound_queueport); + arcmsr_done4abort_postqueue(acb); for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { struct CommandControlBlock *ccb = acb->pccb_pool[i]; if (ccb->startdone == ARCMSR_CCB_START) { @@ -477,75 +850,32 @@ static void arcmsr_module_exit(void) module_init(arcmsr_module_init); module_exit(arcmsr_module_exit); -static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb) -{ - struct MessageUnit __iomem *reg = acb->pmu; - u32 orig_mask = readl(®->outbound_intmask); - - writel(orig_mask | ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE, - ®->outbound_intmask); - return orig_mask; -} - -static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb, - u32 orig_mask) +static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb, \ + u32 intmask_org) { - struct MessageUnit __iomem *reg = acb->pmu; u32 mask; - mask = orig_mask & ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE | - ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE); - writel(mask, ®->outbound_intmask); -} + switch (acb->adapter_type) { -static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb) -{ - struct MessageUnit __iomem *reg = acb->pmu; - - writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, ®->inbound_msgaddr0); - if (arcmsr_wait_msgint_ready(acb)) - printk(KERN_NOTICE - "arcmsr%d: wait 'flush adapter cache' timeout \n" - , acb->host->host_no); -} - -static void arcmsr_report_sense_info(struct CommandControlBlock *ccb) -{ - struct scsi_cmnd *pcmd = ccb->pcmd; - struct SENSE_DATA *sensebuffer = (struct SENSE_DATA *)pcmd->sense_buffer; + case ACB_ADAPTER_TYPE_A : { + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; + mask = intmask_org & ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE | + ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE); + writel(mask, ®->outbound_intmask); + acb->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff; + } + break; - pcmd->result = DID_OK << 16; - if (sensebuffer) { - int sense_data_length = - sizeof (struct SENSE_DATA) < sizeof (pcmd->sense_buffer) - ? sizeof (struct SENSE_DATA) : sizeof (pcmd->sense_buffer); - memset(sensebuffer, 0, sizeof (pcmd->sense_buffer)); - memcpy(sensebuffer, ccb->arcmsr_cdb.SenseData, sense_data_length); - sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS; - sensebuffer->Valid = 1; + case ACB_ADAPTER_TYPE_B : { + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + mask = intmask_org | (ARCMSR_IOP2DRV_DATA_WRITE_OK | \ + ARCMSR_IOP2DRV_DATA_READ_OK | ARCMSR_IOP2DRV_CDB_DONE); + writel(mask, reg->iop2drv_doorbell_mask_reg); + acb->outbound_int_enable = (intmask_org | mask) & 0x0000000f; + } } } -static uint8_t arcmsr_wait_msgint_ready(struct AdapterControlBlock *acb) -{ - struct MessageUnit __iomem *reg = acb->pmu; - uint32_t Index; - uint8_t Retries = 0x00; - - do { - for (Index = 0; Index < 100; Index++) { - if (readl(®->outbound_intstatus) - & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { - writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT - , ®->outbound_intstatus); - return 0x00; - } - msleep_interruptible(10); - }/*max 1 seconds*/ - } while (Retries++ < 20);/*max 20 sec*/ - return 0xff; -} - static void arcmsr_build_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb, struct scsi_cmnd *pcmd) { @@ -556,7 +886,7 @@ static void arcmsr_build_ccb(struct AdapterControlBlock *acb, int nseg; ccb->pcmd = pcmd; - memset(arcmsr_cdb, 0, sizeof (struct ARCMSR_CDB)); + memset(arcmsr_cdb, 0, sizeof(struct ARCMSR_CDB)); arcmsr_cdb->Bus = 0; arcmsr_cdb->TargetID = pcmd->device->id; arcmsr_cdb->LUN = pcmd->device->lun; @@ -609,52 +939,85 @@ static void arcmsr_build_ccb(struct AdapterControlBlock *acb, static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb) { - struct MessageUnit __iomem *reg = acb->pmu; uint32_t cdb_shifted_phyaddr = ccb->cdb_shifted_phyaddr; struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb; - atomic_inc(&acb->ccboutstandingcount); ccb->startdone = ARCMSR_CCB_START; - if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) - writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE, + + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_A: { + struct MessageUnit_A *reg = (struct MessageUnit_A *)acb->pmu; + + if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) + writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE, ®->inbound_queueport); - else - writel(cdb_shifted_phyaddr, ®->inbound_queueport); -} + else { + writel(cdb_shifted_phyaddr, ®->inbound_queueport); + } + } + break; -void arcmsr_post_Qbuffer(struct AdapterControlBlock *acb) -{ - struct MessageUnit __iomem *reg = acb->pmu; - struct QBUFFER __iomem *pwbuffer = (struct QBUFFER __iomem *) ®->message_wbuffer; - uint8_t __iomem *iop_data = (uint8_t __iomem *) pwbuffer->data; - int32_t allxfer_len = 0; + case ACB_ADAPTER_TYPE_B: { + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + uint32_t ending_index, index = reg->postq_index; - if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) { - acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED); - while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex) - && (allxfer_len < 124)) { - writeb(acb->wqbuffer[acb->wqbuf_firstindex], iop_data); - acb->wqbuf_firstindex++; - acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER; - iop_data++; - allxfer_len++; + ending_index = ((index + 1) % ARCMSR_MAX_HBB_POSTQUEUE); + writel(0, ®->post_qbuffer[ending_index]); + if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) { + writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,\ + ®->post_qbuffer[index]); + } + else { + writel(cdb_shifted_phyaddr, ®->post_qbuffer[index]); } - writel(allxfer_len, &pwbuffer->data_len); - writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK - , ®->inbound_doorbell); + index++; + index %= ARCMSR_MAX_HBB_POSTQUEUE;/*if last index number set it to 0 */ + reg->postq_index = index; + writel(ARCMSR_DRV2IOP_CDB_POSTED, reg->drv2iop_doorbell_reg); + } + break; } } -static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb) +static void arcmsr_stop_hba_bgrb(struct AdapterControlBlock *acb) { - struct MessageUnit __iomem *reg = acb->pmu; - + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; acb->acb_flags &= ~ACB_F_MSG_START_BGRB; writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, ®->inbound_msgaddr0); - if (arcmsr_wait_msgint_ready(acb)) + + if (arcmsr_hba_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d: wait 'stop adapter background rebulid' timeout \n" , acb->host->host_no); + } +} + +static void arcmsr_stop_hbb_bgrb(struct AdapterControlBlock *acb) +{ + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + acb->acb_flags &= ~ACB_F_MSG_START_BGRB; + writel(ARCMSR_MESSAGE_STOP_BGRB, reg->drv2iop_doorbell_reg); + + if (arcmsr_hbb_wait_msgint_ready(acb)) { + printk(KERN_NOTICE + "arcmsr%d: wait 'stop adapter background rebulid' timeout \n" + , acb->host->host_no); + } +} + +static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb) +{ + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_A: { + arcmsr_stop_hba_bgrb(acb); + } + break; + + case ACB_ADAPTER_TYPE_B: { + arcmsr_stop_hbb_bgrb(acb); + } + break; + } } static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb) @@ -665,151 +1028,260 @@ static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb) acb->dma_coherent_handle); } -static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb) +void arcmsr_iop_message_read(struct AdapterControlBlock *acb) { - struct MessageUnit __iomem *reg = acb->pmu; - struct CommandControlBlock *ccb; - uint32_t flag_ccb, outbound_intstatus, outbound_doorbell; + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_A: { + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; + writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, ®->inbound_doorbell); + } + break; - outbound_intstatus = readl(®->outbound_intstatus) - & acb->outbound_int_enable; - writel(outbound_intstatus, ®->outbound_intstatus); - if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT) { - outbound_doorbell = readl(®->outbound_doorbell); - writel(outbound_doorbell, ®->outbound_doorbell); - if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) { - struct QBUFFER __iomem * prbuffer = - (struct QBUFFER __iomem *) ®->message_rbuffer; - uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data; - int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex; - - rqbuf_lastindex = acb->rqbuf_lastindex; - rqbuf_firstindex = acb->rqbuf_firstindex; - iop_len = readl(&prbuffer->data_len); - my_empty_len = (rqbuf_firstindex - rqbuf_lastindex - 1) - &(ARCMSR_MAX_QBUFFER - 1); - if (my_empty_len >= iop_len) { - while (iop_len > 0) { - acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data); - acb->rqbuf_lastindex++; - acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; - iop_data++; - iop_len--; - } - writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, - ®->inbound_doorbell); - } else - acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW; - } - if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) { - acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READED; - if (acb->wqbuf_firstindex != acb->wqbuf_lastindex) { - struct QBUFFER __iomem * pwbuffer = - (struct QBUFFER __iomem *) ®->message_wbuffer; - uint8_t __iomem * iop_data = (uint8_t __iomem *) pwbuffer->data; - int32_t allxfer_len = 0; - - acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED); - while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex) - && (allxfer_len < 124)) { - writeb(acb->wqbuffer[acb->wqbuf_firstindex], iop_data); - acb->wqbuf_firstindex++; - acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER; - iop_data++; - allxfer_len++; - } - writel(allxfer_len, &pwbuffer->data_len); - writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK, - ®->inbound_doorbell); - } - if (acb->wqbuf_firstindex == acb->wqbuf_lastindex) - acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_CLEARED; + case ACB_ADAPTER_TYPE_B: { + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell_reg); } + break; } - if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) { - int id, lun; +} + +static void arcmsr_iop_message_wrote(struct AdapterControlBlock *acb) +{ + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_A: { + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; /* - **************************************************************** - ** areca cdb command done - **************************************************************** + ** push inbound doorbell tell iop, driver data write ok + ** and wait reply on next hwinterrupt for next Qbuffer post */ - while (1) { - if ((flag_ccb = readl(®->outbound_queueport)) == 0xFFFFFFFF) - break;/*chip FIFO no ccb for completion already*/ - /* check if command done with no error*/ - ccb = (struct CommandControlBlock *)(acb->vir2phy_offset + - (flag_ccb << 5)); - if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { - if (ccb->startdone == ARCMSR_CCB_ABORTED) { - struct scsi_cmnd *abortcmd = ccb->pcmd; - if (abortcmd) { - abortcmd->result |= DID_ABORT >> 16; - arcmsr_ccb_complete(ccb, 1); - printk(KERN_NOTICE - "arcmsr%d: ccb ='0x%p' isr got aborted command \n" - , acb->host->host_no, ccb); - } - continue; - } - printk(KERN_NOTICE - "arcmsr%d: isr get an illegal ccb command done acb = '0x%p'" - "ccb = '0x%p' ccbacb = '0x%p' startdone = 0x%x" - " ccboutstandingcount = %d \n" - , acb->host->host_no - , acb - , ccb - , ccb->acb - , ccb->startdone - , atomic_read(&acb->ccboutstandingcount)); - continue; - } - id = ccb->pcmd->device->id; - lun = ccb->pcmd->device->lun; - if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) { - if (acb->devstate[id][lun] == ARECA_RAID_GONE) - acb->devstate[id][lun] = ARECA_RAID_GOOD; - ccb->pcmd->result = DID_OK << 16; - arcmsr_ccb_complete(ccb, 1); - } else { - switch(ccb->arcmsr_cdb.DeviceStatus) { - case ARCMSR_DEV_SELECT_TIMEOUT: { - acb->devstate[id][lun] = ARECA_RAID_GONE; - ccb->pcmd->result = DID_NO_CONNECT << 16; - arcmsr_ccb_complete(ccb, 1); - } - break; - case ARCMSR_DEV_ABORTED: - case ARCMSR_DEV_INIT_FAIL: { - acb->devstate[id][lun] = ARECA_RAID_GONE; - ccb->pcmd->result = DID_BAD_TARGET << 16; - arcmsr_ccb_complete(ccb, 1); - } - break; - case ARCMSR_DEV_CHECK_CONDITION: { - acb->devstate[id][lun] = ARECA_RAID_GOOD; - arcmsr_report_sense_info(ccb); - arcmsr_ccb_complete(ccb, 1); - } - break; - default: - printk(KERN_NOTICE - "arcmsr%d: scsi id = %d lun = %d" - " isr get command error done, " - "but got unknown DeviceStatus = 0x%x \n" - , acb->host->host_no - , id - , lun - , ccb->arcmsr_cdb.DeviceStatus); - acb->devstate[id][lun] = ARECA_RAID_GONE; - ccb->pcmd->result = DID_NO_CONNECT << 16; - arcmsr_ccb_complete(ccb, 1); - break; - } - } - }/*drain reply FIFO*/ + writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK, ®->inbound_doorbell); + } + break; + + case ACB_ADAPTER_TYPE_B: { + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + /* + ** push inbound doorbell tell iop, driver data write ok + ** and wait reply on next hwinterrupt for next Qbuffer post + */ + writel(ARCMSR_DRV2IOP_DATA_WRITE_OK, reg->drv2iop_doorbell_reg); + } + break; + } +} + +struct QBUFFER *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *acb) +{ + static struct QBUFFER *qbuffer; + + switch (acb->adapter_type) { + + case ACB_ADAPTER_TYPE_A: { + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; + qbuffer = (struct QBUFFER __iomem *) ®->message_rbuffer; + } + break; + + case ACB_ADAPTER_TYPE_B: { + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + qbuffer = (struct QBUFFER __iomem *) reg->ioctl_rbuffer_reg; + } + break; + } + return qbuffer; +} + +static struct QBUFFER *arcmsr_get_iop_wqbuffer(struct AdapterControlBlock *acb) +{ + static struct QBUFFER *pqbuffer; + + switch (acb->adapter_type) { + + case ACB_ADAPTER_TYPE_A: { + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; + pqbuffer = (struct QBUFFER *) ®->message_wbuffer; + } + break; + + case ACB_ADAPTER_TYPE_B: { + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + pqbuffer = (struct QBUFFER __iomem *)reg->ioctl_wbuffer_reg; + } + break; + } + return pqbuffer; +} + +static void arcmsr_iop2drv_data_wrote_handle(struct AdapterControlBlock *acb) +{ + struct QBUFFER *prbuffer; + struct QBUFFER *pQbuffer; + uint8_t *iop_data; + int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex; + + rqbuf_lastindex = acb->rqbuf_lastindex; + rqbuf_firstindex = acb->rqbuf_firstindex; + prbuffer = arcmsr_get_iop_rqbuffer(acb); + iop_data = (uint8_t *)prbuffer->data; + iop_len = prbuffer->data_len; + my_empty_len = (rqbuf_firstindex - rqbuf_lastindex -1)&(ARCMSR_MAX_QBUFFER -1); + + if (my_empty_len >= iop_len) + { + while (iop_len > 0) { + pQbuffer = (struct QBUFFER *)&acb->rqbuffer[rqbuf_lastindex]; + memcpy(pQbuffer, iop_data,1); + rqbuf_lastindex++; + rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; + iop_data++; + iop_len--; + } + acb->rqbuf_lastindex = rqbuf_lastindex; + arcmsr_iop_message_read(acb); + } + + else { + acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW; + } +} + +static void arcmsr_iop2drv_data_read_handle(struct AdapterControlBlock *acb) +{ + acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READED; + if (acb->wqbuf_firstindex != acb->wqbuf_lastindex) { + uint8_t *pQbuffer; + struct QBUFFER *pwbuffer; + uint8_t *iop_data; + int32_t allxfer_len = 0; + + acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED); + pwbuffer = arcmsr_get_iop_wqbuffer(acb); + iop_data = (uint8_t __iomem *)pwbuffer->data; + + while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex) && \ + (allxfer_len < 124)) { + pQbuffer = &acb->wqbuffer[acb->wqbuf_firstindex]; + memcpy(iop_data, pQbuffer, 1); + acb->wqbuf_firstindex++; + acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER; + iop_data++; + allxfer_len++; + } + pwbuffer->data_len = allxfer_len; + + arcmsr_iop_message_wrote(acb); + } + + if (acb->wqbuf_firstindex == acb->wqbuf_lastindex) { + acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_CLEARED; + } +} + +static void arcmsr_hba_doorbell_isr(struct AdapterControlBlock *acb) +{ + uint32_t outbound_doorbell; + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; + + outbound_doorbell = readl(®->outbound_doorbell); + writel(outbound_doorbell, ®->outbound_doorbell); + if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) { + arcmsr_iop2drv_data_wrote_handle(acb); + } + + if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) { + arcmsr_iop2drv_data_read_handle(acb); + } +} + +static void arcmsr_hba_postqueue_isr(struct AdapterControlBlock *acb) +{ + uint32_t flag_ccb; + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; + + while ((flag_ccb = readl(®->outbound_queueport)) != 0xFFFFFFFF) { + arcmsr_drain_donequeue(acb, flag_ccb); + } +} + +static void arcmsr_hbb_postqueue_isr(struct AdapterControlBlock *acb) +{ + uint32_t index; + uint32_t flag_ccb; + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + + index = reg->doneq_index; + + while ((flag_ccb = readl(®->done_qbuffer[index])) != 0) { + writel(0, ®->done_qbuffer[index]); + arcmsr_drain_donequeue(acb, flag_ccb); + index++; + index %= ARCMSR_MAX_HBB_POSTQUEUE; + reg->doneq_index = index; + } +} + +static int arcmsr_handle_hba_isr(struct AdapterControlBlock *acb) +{ + uint32_t outbound_intstatus; + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; + + outbound_intstatus = readl(®->outbound_intstatus) & \ + acb->outbound_int_enable; + if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT)) { + return 1; + } + writel(outbound_intstatus, ®->outbound_intstatus); + if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT) { + arcmsr_hba_doorbell_isr(acb); + } + if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) { + arcmsr_hba_postqueue_isr(acb); + } + return 0; +} + +static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb) +{ + uint32_t outbound_doorbell; + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + + outbound_doorbell = readl(reg->iop2drv_doorbell_reg) & \ + acb->outbound_int_enable; + if (!outbound_doorbell) + return 1; + + writel(~outbound_doorbell, reg->iop2drv_doorbell_reg); + + if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) { + arcmsr_iop2drv_data_wrote_handle(acb); + } + if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_READ_OK) { + arcmsr_iop2drv_data_read_handle(acb); + } + if (outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE) { + arcmsr_hbb_postqueue_isr(acb); + } + + return 0; +} + +static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb) +{ + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_A: { + if (arcmsr_handle_hba_isr(acb)) { + return IRQ_NONE; + } + } + break; + + case ACB_ADAPTER_TYPE_B: { + if (arcmsr_handle_hbb_isr(acb)) { + return IRQ_NONE; + } + } + break; } - if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT)) - return IRQ_NONE; return IRQ_HANDLED; } @@ -818,16 +1290,47 @@ static void arcmsr_iop_parking(struct AdapterControlBlock *acb) if (acb) { /* stop adapter background rebuild */ if (acb->acb_flags & ACB_F_MSG_START_BGRB) { + uint32_t intmask_org; acb->acb_flags &= ~ACB_F_MSG_START_BGRB; + intmask_org = arcmsr_disable_outbound_ints(acb); arcmsr_stop_adapter_bgrb(acb); arcmsr_flush_adapter_cache(acb); + arcmsr_enable_outbound_ints(acb, intmask_org); } } } -static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_cmnd *cmd) +void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *acb) +{ + int32_t wqbuf_firstindex, wqbuf_lastindex; + uint8_t *pQbuffer; + struct QBUFFER *pwbuffer; + uint8_t *iop_data; + int32_t allxfer_len = 0; + + pwbuffer = arcmsr_get_iop_wqbuffer(acb); + iop_data = (uint8_t __iomem *)pwbuffer->data; + if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) { + acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED); + wqbuf_firstindex = acb->wqbuf_firstindex; + wqbuf_lastindex = acb->wqbuf_lastindex; + while ((wqbuf_firstindex != wqbuf_lastindex) && (allxfer_len < 124)) { + pQbuffer = &acb->wqbuffer[wqbuf_firstindex]; + memcpy(iop_data, pQbuffer, 1); + wqbuf_firstindex++; + wqbuf_firstindex %= ARCMSR_MAX_QBUFFER; + iop_data++; + allxfer_len++; + } + acb->wqbuf_firstindex = wqbuf_firstindex; + pwbuffer->data_len = allxfer_len; + arcmsr_iop_message_wrote(acb); + } +} + +static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \ + struct scsi_cmnd *cmd) { - struct MessageUnit __iomem *reg = acb->pmu; struct CMD_MESSAGE_FIELD *pcmdmessagefld; int retvalue = 0, transfer_len = 0; char *buffer; @@ -836,7 +1339,7 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_ (uint32_t ) cmd->cmnd[6] << 16 | (uint32_t ) cmd->cmnd[7] << 8 | (uint32_t ) cmd->cmnd[8]; - /* 4 bytes: Areca io control code */ + /* 4 bytes: Areca io control code */ sg = scsi_sglist(cmd); buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset; @@ -852,194 +1355,199 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_ } pcmdmessagefld = (struct CMD_MESSAGE_FIELD *) buffer; switch(controlcode) { + case ARCMSR_MESSAGE_READ_RQBUFFER: { - unsigned long *ver_addr; - dma_addr_t buf_handle; - uint8_t *pQbuffer, *ptmpQbuffer; - int32_t allxfer_len = 0; + unsigned long *ver_addr; + dma_addr_t buf_handle; + uint8_t *pQbuffer, *ptmpQbuffer; + int32_t allxfer_len = 0; + + ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle); + if (!ver_addr) { + retvalue = ARCMSR_MESSAGE_FAIL; + goto message_out; + } + ptmpQbuffer = (uint8_t *) ver_addr; + while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex) + && (allxfer_len < 1031)) { + pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex]; + memcpy(ptmpQbuffer, pQbuffer, 1); + acb->rqbuf_firstindex++; + acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER; + ptmpQbuffer++; + allxfer_len++; + } + if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { - ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle); - if (!ver_addr) { - retvalue = ARCMSR_MESSAGE_FAIL; - goto message_out; - } - ptmpQbuffer = (uint8_t *) ver_addr; - while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex) - && (allxfer_len < 1031)) { - pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex]; - memcpy(ptmpQbuffer, pQbuffer, 1); - acb->rqbuf_firstindex++; - acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER; - ptmpQbuffer++; - allxfer_len++; - } - if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { - struct QBUFFER __iomem * prbuffer = (struct QBUFFER __iomem *) - ®->message_rbuffer; - uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data; - int32_t iop_len; - - acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; - iop_len = readl(&prbuffer->data_len); - while (iop_len > 0) { - acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data); - acb->rqbuf_lastindex++; - acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; - iop_data++; - iop_len--; - } - writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, - ®->inbound_doorbell); + struct QBUFFER *prbuffer; + uint8_t *iop_data; + int32_t iop_len; + + acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; + prbuffer = arcmsr_get_iop_rqbuffer(acb); + iop_data = (uint8_t *)prbuffer->data; + iop_len = readl(&prbuffer->data_len); + while (iop_len > 0) { + acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data); + acb->rqbuf_lastindex++; + acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; + iop_data++; + iop_len--; } - memcpy(pcmdmessagefld->messagedatabuffer, - (uint8_t *)ver_addr, allxfer_len); - pcmdmessagefld->cmdmessage.Length = allxfer_len; - pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; - pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle); + arcmsr_iop_message_read(acb); + } + memcpy(pcmdmessagefld->messagedatabuffer, (uint8_t *)ver_addr, allxfer_len); + pcmdmessagefld->cmdmessage.Length = allxfer_len; + pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; + pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle); } break; - case ARCMSR_MESSAGE_WRITE_WQBUFFER: { - unsigned long *ver_addr; - dma_addr_t buf_handle; - int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex; - uint8_t *pQbuffer, *ptmpuserbuffer; - ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle); - if (!ver_addr) { - retvalue = ARCMSR_MESSAGE_FAIL; - goto message_out; - } - ptmpuserbuffer = (uint8_t *)ver_addr; - user_len = pcmdmessagefld->cmdmessage.Length; - memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, user_len); - wqbuf_lastindex = acb->wqbuf_lastindex; - wqbuf_firstindex = acb->wqbuf_firstindex; - if (wqbuf_lastindex != wqbuf_firstindex) { + case ARCMSR_MESSAGE_WRITE_WQBUFFER: { + unsigned long *ver_addr; + dma_addr_t buf_handle; + int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex; + uint8_t *pQbuffer, *ptmpuserbuffer; + + ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle); + if (!ver_addr) { + retvalue = ARCMSR_MESSAGE_FAIL; + goto message_out; + } + ptmpuserbuffer = (uint8_t *)ver_addr; + user_len = pcmdmessagefld->cmdmessage.Length; + memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, user_len); + wqbuf_lastindex = acb->wqbuf_lastindex; + wqbuf_firstindex = acb->wqbuf_firstindex; + if (wqbuf_lastindex != wqbuf_firstindex) { + struct SENSE_DATA *sensebuffer = + (struct SENSE_DATA *)cmd->sense_buffer; + arcmsr_post_ioctldata2iop(acb); + /* has error report sensedata */ + sensebuffer->ErrorCode = 0x70; + sensebuffer->SenseKey = ILLEGAL_REQUEST; + sensebuffer->AdditionalSenseLength = 0x0A; + sensebuffer->AdditionalSenseCode = 0x20; + sensebuffer->Valid = 1; + retvalue = ARCMSR_MESSAGE_FAIL; + } else { + my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1) + &(ARCMSR_MAX_QBUFFER - 1); + if (my_empty_len >= user_len) { + while (user_len > 0) { + pQbuffer = + &acb->wqbuffer[acb->wqbuf_lastindex]; + memcpy(pQbuffer, ptmpuserbuffer, 1); + acb->wqbuf_lastindex++; + acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER; + ptmpuserbuffer++; + user_len--; + } + if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) { + acb->acb_flags &= + ~ACB_F_MESSAGE_WQBUFFER_CLEARED; + arcmsr_post_ioctldata2iop(acb); + } + } else { + /* has error report sensedata */ struct SENSE_DATA *sensebuffer = (struct SENSE_DATA *)cmd->sense_buffer; - arcmsr_post_Qbuffer(acb); - /* has error report sensedata */ sensebuffer->ErrorCode = 0x70; sensebuffer->SenseKey = ILLEGAL_REQUEST; sensebuffer->AdditionalSenseLength = 0x0A; sensebuffer->AdditionalSenseCode = 0x20; sensebuffer->Valid = 1; retvalue = ARCMSR_MESSAGE_FAIL; - } else { - my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1) - &(ARCMSR_MAX_QBUFFER - 1); - if (my_empty_len >= user_len) { - while (user_len > 0) { - pQbuffer = - &acb->wqbuffer[acb->wqbuf_lastindex]; - memcpy(pQbuffer, ptmpuserbuffer, 1); - acb->wqbuf_lastindex++; - acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER; - ptmpuserbuffer++; - user_len--; - } - if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) { - acb->acb_flags &= - ~ACB_F_MESSAGE_WQBUFFER_CLEARED; - arcmsr_post_Qbuffer(acb); - } - } else { - /* has error report sensedata */ - struct SENSE_DATA *sensebuffer = - (struct SENSE_DATA *)cmd->sense_buffer; - sensebuffer->ErrorCode = 0x70; - sensebuffer->SenseKey = ILLEGAL_REQUEST; - sensebuffer->AdditionalSenseLength = 0x0A; - sensebuffer->AdditionalSenseCode = 0x20; - sensebuffer->Valid = 1; - retvalue = ARCMSR_MESSAGE_FAIL; - } + } } pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle); } break; + case ARCMSR_MESSAGE_CLEAR_RQBUFFER: { - uint8_t *pQbuffer = acb->rqbuffer; + uint8_t *pQbuffer = acb->rqbuffer; - if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { - acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; - writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, - ®->inbound_doorbell); - } - acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED; - acb->rqbuf_firstindex = 0; - acb->rqbuf_lastindex = 0; - memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); - pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_OK; + if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { + acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; + arcmsr_iop_message_read(acb); + } + acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED; + acb->rqbuf_firstindex = 0; + acb->rqbuf_lastindex = 0; + memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); + pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; } break; + case ARCMSR_MESSAGE_CLEAR_WQBUFFER: { - uint8_t *pQbuffer = acb->wqbuffer; + uint8_t *pQbuffer = acb->wqbuffer; - if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { - acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; - writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK - , ®->inbound_doorbell); - } - acb->acb_flags |= - (ACB_F_MESSAGE_WQBUFFER_CLEARED | - ACB_F_MESSAGE_WQBUFFER_READED); - acb->wqbuf_firstindex = 0; - acb->wqbuf_lastindex = 0; - memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); - pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_OK; + if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { + acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; + arcmsr_iop_message_read(acb); + } + acb->acb_flags |= + (ACB_F_MESSAGE_WQBUFFER_CLEARED | + ACB_F_MESSAGE_WQBUFFER_READED); + acb->wqbuf_firstindex = 0; + acb->wqbuf_lastindex = 0; + memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); + pcmdmessagefld->cmdmessage.ReturnCode = + ARCMSR_MESSAGE_RETURNCODE_OK; } break; + case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: { - uint8_t *pQbuffer; + uint8_t *pQbuffer; - if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { - acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; - writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK - , ®->inbound_doorbell); - } - acb->acb_flags |= - (ACB_F_MESSAGE_WQBUFFER_CLEARED - | ACB_F_MESSAGE_RQBUFFER_CLEARED - | ACB_F_MESSAGE_WQBUFFER_READED); - acb->rqbuf_firstindex = 0; - acb->rqbuf_lastindex = 0; - acb->wqbuf_firstindex = 0; - acb->wqbuf_lastindex = 0; - pQbuffer = acb->rqbuffer; - memset(pQbuffer, 0, sizeof (struct QBUFFER)); - pQbuffer = acb->wqbuffer; - memset(pQbuffer, 0, sizeof (struct QBUFFER)); - pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; + if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { + acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; + arcmsr_iop_message_read(acb); + } + acb->acb_flags |= + (ACB_F_MESSAGE_WQBUFFER_CLEARED + | ACB_F_MESSAGE_RQBUFFER_CLEARED + | ACB_F_MESSAGE_WQBUFFER_READED); + acb->rqbuf_firstindex = 0; + acb->rqbuf_lastindex = 0; + acb->wqbuf_firstindex = 0; + acb->wqbuf_lastindex = 0; + pQbuffer = acb->rqbuffer; + memset(pQbuffer, 0, sizeof(struct QBUFFER)); + pQbuffer = acb->wqbuffer; + memset(pQbuffer, 0, sizeof(struct QBUFFER)); + pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; } break; + case ARCMSR_MESSAGE_RETURN_CODE_3F: { - pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_3F; + pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_3F; } break; + case ARCMSR_MESSAGE_SAY_HELLO: { - int8_t * hello_string = "Hello! I am ARCMSR"; + int8_t *hello_string = "Hello! I am ARCMSR"; - memcpy(pcmdmessagefld->messagedatabuffer, hello_string - , (int16_t)strlen(hello_string)); - pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; + memcpy(pcmdmessagefld->messagedatabuffer, hello_string + , (int16_t)strlen(hello_string)); + pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; } break; + case ARCMSR_MESSAGE_SAY_GOODBYE: arcmsr_iop_parking(acb); break; + case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE: arcmsr_flush_adapter_cache(acb); break; + default: retvalue = ARCMSR_MESSAGE_FAIL; } - message_out: + message_out: sg = scsi_sglist(cmd); kunmap_atomic(buffer - sg->offset, KM_IRQ0); - return retvalue; } @@ -1109,8 +1617,7 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *)) { struct Scsi_Host *host = cmd->device->host; - struct AdapterControlBlock *acb = - (struct AdapterControlBlock *) host->hostdata; + struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; struct CommandControlBlock *ccb; int target = cmd->device->id; int lun = cmd->device->lun; @@ -1153,26 +1660,27 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd, ccb = arcmsr_get_freeccb(acb); if (!ccb) return SCSI_MLQUEUE_HOST_BUSY; + arcmsr_build_ccb(acb, ccb, cmd); arcmsr_post_ccb(acb, ccb); return 0; } -static void arcmsr_get_firmware_spec(struct AdapterControlBlock *acb) +static void arcmsr_get_hba_config(struct AdapterControlBlock *acb) { - struct MessageUnit __iomem *reg = acb->pmu; + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; char *acb_firm_model = acb->firm_model; char *acb_firm_version = acb->firm_version; - char __iomem *iop_firm_model = (char __iomem *) ®->message_rwbuffer[15]; - char __iomem *iop_firm_version = (char __iomem *) ®->message_rwbuffer[17]; + char *iop_firm_model = (char *) (®->message_rwbuffer[15]); + char *iop_firm_version = (char *) (®->message_rwbuffer[17]); int count; writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0); - if (arcmsr_wait_msgint_ready(acb)) - printk(KERN_NOTICE - "arcmsr%d: wait " - "'get adapter firmware miscellaneous data' timeout \n" - , acb->host->host_no); + if (arcmsr_hba_wait_msgint_ready(acb)) { + printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \ + miscellaneous data' timeout \n", acb->host->host_no); + } + count = 8; while (count) { *acb_firm_model = readb(iop_firm_model); @@ -1180,6 +1688,7 @@ static void arcmsr_get_firmware_spec(struct AdapterControlBlock *acb) iop_firm_model++; count--; } + count = 16; while (count) { *acb_firm_version = readb(iop_firm_version); @@ -1187,28 +1696,93 @@ static void arcmsr_get_firmware_spec(struct AdapterControlBlock *acb) iop_firm_version++; count--; } - printk(KERN_INFO - "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n" + + printk(KERN_INFO "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n" , acb->host->host_no , acb->firm_version); + acb->firm_request_len = readl(®->message_rwbuffer[1]); acb->firm_numbers_queue = readl(®->message_rwbuffer[2]); acb->firm_sdram_size = readl(®->message_rwbuffer[3]); acb->firm_hd_channels = readl(®->message_rwbuffer[4]); } -static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, +static void arcmsr_get_hbb_config(struct AdapterControlBlock *acb) +{ + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + uint32_t *lrwbuffer = reg->msgcode_rwbuffer_reg; + char *acb_firm_model = acb->firm_model; + char *acb_firm_version = acb->firm_version; + char *iop_firm_model = (char *) (&lrwbuffer[15]); + /*firm_model,15,60-67*/ + char *iop_firm_version = (char *) (&lrwbuffer[17]); + /*firm_version,17,68-83*/ + int count; + + writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell_reg); + if (arcmsr_hbb_wait_msgint_ready(acb)) { + printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \ + miscellaneous data' timeout \n", acb->host->host_no); + } + + count = 8; + while (count) + { + *acb_firm_model = readb(iop_firm_model); + acb_firm_model++; + iop_firm_model++; + count--; + } + + count = 16; + while (count) + { + *acb_firm_version = readb(iop_firm_version); + acb_firm_version++; + iop_firm_version++; + count--; + } + + printk(KERN_INFO "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n", + acb->host->host_no, + acb->firm_version); + + lrwbuffer++; + acb->firm_request_len = readl(lrwbuffer++); + /*firm_request_len,1,04-07*/ + acb->firm_numbers_queue = readl(lrwbuffer++); + /*firm_numbers_queue,2,08-11*/ + acb->firm_sdram_size = readl(lrwbuffer++); + /*firm_sdram_size,3,12-15*/ + acb->firm_hd_channels = readl(lrwbuffer); + /*firm_ide_channels,4,16-19*/ +} + +static void arcmsr_get_firmware_spec(struct AdapterControlBlock *acb) +{ + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_A: { + arcmsr_get_hba_config(acb); + } + break; + + case ACB_ADAPTER_TYPE_B: { + arcmsr_get_hbb_config(acb); + } + break; + } +} + +static void arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_ccb) { - struct MessageUnit __iomem *reg = acb->pmu; + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; struct CommandControlBlock *ccb; uint32_t flag_ccb, outbound_intstatus, poll_ccb_done = 0, poll_count = 0; - int id, lun; - polling_ccb_retry: + polling_hba_ccb_retry: poll_count++; - outbound_intstatus = readl(®->outbound_intstatus) - & acb->outbound_int_enable; + outbound_intstatus = readl(®->outbound_intstatus) & acb->outbound_int_enable; writel(outbound_intstatus, ®->outbound_intstatus);/*clear interrupt*/ while (1) { if ((flag_ccb = readl(®->outbound_queueport)) == 0xFFFFFFFF) { @@ -1218,17 +1792,14 @@ static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, msleep(25); if (poll_count > 100) break; - goto polling_ccb_retry; + goto polling_hba_ccb_retry; } } - ccb = (struct CommandControlBlock *) - (acb->vir2phy_offset + (flag_ccb << 5)); - if ((ccb->acb != acb) || - (ccb->startdone != ARCMSR_CCB_START)) { - if ((ccb->startdone == ARCMSR_CCB_ABORTED) || - (ccb == poll_ccb)) { - printk(KERN_NOTICE - "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'" + ccb = (struct CommandControlBlock *)(acb->vir2phy_offset + (flag_ccb << 5)); + poll_ccb_done = (ccb == poll_ccb) ? 1:0; + if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { + if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) { + printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'" " poll command abort successfully \n" , acb->host->host_no , ccb->pcmd->device->id @@ -1239,176 +1810,280 @@ static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, poll_ccb_done = 1; continue; } - printk(KERN_NOTICE - "arcmsr%d: polling get an illegal ccb" - " command done ccb ='0x%p'" + printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb" + " command done ccb = '0x%p'" "ccboutstandingcount = %d \n" , acb->host->host_no , ccb , atomic_read(&acb->ccboutstandingcount)); continue; } - id = ccb->pcmd->device->id; - lun = ccb->pcmd->device->lun; - if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) { - if (acb->devstate[id][lun] == ARECA_RAID_GONE) - acb->devstate[id][lun] = ARECA_RAID_GOOD; - ccb->pcmd->result = DID_OK << 16; - arcmsr_ccb_complete(ccb, 1); - } else { - switch(ccb->arcmsr_cdb.DeviceStatus) { - case ARCMSR_DEV_SELECT_TIMEOUT: { - acb->devstate[id][lun] = ARECA_RAID_GONE; - ccb->pcmd->result = DID_NO_CONNECT << 16; - arcmsr_ccb_complete(ccb, 1); - } - break; - case ARCMSR_DEV_ABORTED: - case ARCMSR_DEV_INIT_FAIL: { - acb->devstate[id][lun] = ARECA_RAID_GONE; - ccb->pcmd->result = DID_BAD_TARGET << 16; - arcmsr_ccb_complete(ccb, 1); + arcmsr_report_ccb_state(acb, ccb, flag_ccb); + } +} + +static void arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, \ + struct CommandControlBlock *poll_ccb) +{ + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + struct CommandControlBlock *ccb; + uint32_t flag_ccb, poll_ccb_done = 0, poll_count = 0; + int index; + + polling_hbb_ccb_retry: + poll_count++; + /* clear doorbell interrupt */ + writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell_reg); + while (1) { + index = reg->doneq_index; + if ((flag_ccb = readl(®->done_qbuffer[index])) == 0) { + if (poll_ccb_done) + break; + else { + msleep(25); + if (poll_count > 100) + break; + goto polling_hbb_ccb_retry; } - break; - case ARCMSR_DEV_CHECK_CONDITION: { - acb->devstate[id][lun] = ARECA_RAID_GOOD; - arcmsr_report_sense_info(ccb); + } + writel(0, ®->done_qbuffer[index]); + index++; + /*if last index number set it to 0 */ + index %= ARCMSR_MAX_HBB_POSTQUEUE; + reg->doneq_index = index; + /* check ifcommand done with no error*/ + ccb = (struct CommandControlBlock *)\ + (acb->vir2phy_offset + (flag_ccb << 5));/*frame must be 32 bytes aligned*/ + poll_ccb_done = (ccb == poll_ccb) ? 1:0; + if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { + if (ccb->startdone == ARCMSR_CCB_ABORTED) { + printk(KERN_NOTICE "arcmsr%d: \ + scsi id = %d lun = %d ccb = '0x%p' poll command abort successfully \n" + ,acb->host->host_no + ,ccb->pcmd->device->id + ,ccb->pcmd->device->lun + ,ccb); + ccb->pcmd->result = DID_ABORT << 16; arcmsr_ccb_complete(ccb, 1); + continue; } - break; - default: - printk(KERN_NOTICE - "arcmsr%d: scsi id = %d lun = %d" - " polling and getting command error done" - "but got unknown DeviceStatus = 0x%x \n" + printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb" + " command done ccb = '0x%p'" + "ccboutstandingcount = %d \n" , acb->host->host_no - , id - , lun - , ccb->arcmsr_cdb.DeviceStatus); - acb->devstate[id][lun] = ARECA_RAID_GONE; - ccb->pcmd->result = DID_BAD_TARGET << 16; - arcmsr_ccb_complete(ccb, 1); - break; + , ccb + , atomic_read(&acb->ccboutstandingcount)); + continue; } + arcmsr_report_ccb_state(acb, ccb, flag_ccb); + } /*drain reply FIFO*/ +} + +static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, \ + struct CommandControlBlock *poll_ccb) +{ + switch (acb->adapter_type) { + + case ACB_ADAPTER_TYPE_A: { + arcmsr_polling_hba_ccbdone(acb,poll_ccb); + } + break; + + case ACB_ADAPTER_TYPE_B: { + arcmsr_polling_hbb_ccbdone(acb,poll_ccb); } } } -static void arcmsr_done4_abort_postqueue(struct AdapterControlBlock *acb) + +static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) { - int i = 0, found = 0; - int id, lun; - uint32_t flag_ccb, outbound_intstatus; - struct MessageUnit __iomem *reg = acb->pmu; - struct CommandControlBlock *ccb; - /*clear and abort all outbound posted Q*/ - - while (((flag_ccb = readl(®->outbound_queueport)) != 0xFFFFFFFF) && -(i++ < 256)){ - ccb = (struct CommandControlBlock *)(acb->vir2phy_offset + -(flag_ccb << 5)); - if (ccb){ - if ((ccb->acb != acb)||(ccb->startdone != \ -ARCMSR_CCB_START)){ - printk(KERN_NOTICE "arcmsr%d: polling get \ -an illegal ccb" "command done ccb = '0x%p'""ccboutstandingcount = %d \n", - acb->host->host_no, ccb, - atomic_read(&acb->ccboutstandingcount)); - continue; + uint32_t cdb_phyaddr, ccb_phyaddr_hi32; + dma_addr_t dma_coherent_handle; + /* + ******************************************************************** + ** here we need to tell iop 331 our freeccb.HighPart + ** if freeccb.HighPart is not zero + ******************************************************************** + */ + dma_coherent_handle = acb->dma_coherent_handle; + cdb_phyaddr = (uint32_t)(dma_coherent_handle); + ccb_phyaddr_hi32 = (uint32_t)((cdb_phyaddr >> 16) >> 16); + /* + *********************************************************************** + ** if adapter type B, set window of "post command Q" + *********************************************************************** + */ + switch (acb->adapter_type) { + + case ACB_ADAPTER_TYPE_A: { + if (ccb_phyaddr_hi32 != 0) { + struct MessageUnit_A __iomem *reg = \ + (struct MessageUnit_A *)acb->pmu; + uint32_t intmask_org; + intmask_org = arcmsr_disable_outbound_ints(acb); + writel(ARCMSR_SIGNATURE_SET_CONFIG, \ + ®->message_rwbuffer[0]); + writel(ccb_phyaddr_hi32, ®->message_rwbuffer[1]); + writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, \ + ®->inbound_msgaddr0); + if (arcmsr_hba_wait_msgint_ready(acb)) { + printk(KERN_NOTICE "arcmsr%d: ""set ccb high \ + part physical address timeout\n", + acb->host->host_no); + return 1; } + arcmsr_enable_outbound_ints(acb, intmask_org); + } + } + break; - id = ccb->pcmd->device->id; - lun = ccb->pcmd->device->lun; - if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)){ - if (acb->devstate[id][lun] == ARECA_RAID_GONE) - acb->devstate[id][lun] = ARECA_RAID_GOOD; - ccb->pcmd->result = DID_OK << 16; - arcmsr_ccb_complete(ccb, 1); - } - else { - switch(ccb->arcmsr_cdb.DeviceStatus) { - case ARCMSR_DEV_SELECT_TIMEOUT: { - acb->devstate[id][lun] = ARECA_RAID_GONE; - ccb->pcmd->result = DID_NO_CONNECT << 16; - arcmsr_ccb_complete(ccb, 1); - } - break; + case ACB_ADAPTER_TYPE_B: { + unsigned long post_queue_phyaddr; + uint32_t *rwbuffer; - case ARCMSR_DEV_ABORTED: + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + uint32_t intmask_org; + intmask_org = arcmsr_disable_outbound_ints(acb); + reg->postq_index = 0; + reg->doneq_index = 0; + writel(ARCMSR_MESSAGE_SET_POST_WINDOW, reg->drv2iop_doorbell_reg); + if (arcmsr_hbb_wait_msgint_ready(acb)) { + printk(KERN_NOTICE "arcmsr%d:can not set diver mode\n", \ + acb->host->host_no); + return 1; + } + post_queue_phyaddr = cdb_phyaddr + ARCMSR_MAX_FREECCB_NUM * \ + sizeof(struct CommandControlBlock) + offsetof(struct MessageUnit_B, post_qbuffer) ; + rwbuffer = reg->msgcode_rwbuffer_reg; + /* driver "set config" signature */ + writel(ARCMSR_SIGNATURE_SET_CONFIG, rwbuffer++); + /* normal should be zero */ + writel(ccb_phyaddr_hi32, rwbuffer++); + /* postQ size (256 + 8)*4 */ + writel(post_queue_phyaddr, rwbuffer++); + /* doneQ size (256 + 8)*4 */ + writel(post_queue_phyaddr + 1056, rwbuffer++); + /* ccb maxQ size must be --> [(256 + 8)*4]*/ + writel(1056, rwbuffer); + + writel(ARCMSR_MESSAGE_SET_CONFIG, reg->drv2iop_doorbell_reg); + if (arcmsr_hbb_wait_msgint_ready(acb)) { + printk(KERN_NOTICE "arcmsr%d: 'set command Q window' \ + timeout \n",acb->host->host_no); + return 1; + } - case ARCMSR_DEV_INIT_FAIL: { - acb->devstate[id][lun] = - ARECA_RAID_GONE; - ccb->pcmd->result = - DID_BAD_TARGET << 16; - arcmsr_ccb_complete(ccb, 1); - } - break; + writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell_reg); + if (arcmsr_hbb_wait_msgint_ready(acb)) { + printk(KERN_NOTICE "arcmsr%d: 'can not set diver mode \n"\ + ,acb->host->host_no); + return 1; + } + arcmsr_enable_outbound_ints(acb, intmask_org); + } + break; + } + return 0; +} - case ARCMSR_DEV_CHECK_CONDITION: { - acb->devstate[id][lun] = - ARECA_RAID_GOOD; - arcmsr_report_sense_info(ccb); - arcmsr_ccb_complete(ccb, 1); - } - break; +static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb) +{ + uint32_t firmware_state = 0; - default: - printk(KERN_NOTICE - "arcmsr%d: scsi id = %d \ - lun = %d""polling and \ - getting command error \ - done""but got unknown \ - DeviceStatus = 0x%x \n", - acb->host->host_no, id, - lun, ccb->arcmsr_cdb.DeviceStatus); - acb->devstate[id][lun] = - ARECA_RAID_GONE; - ccb->pcmd->result = - DID_BAD_TARGET << 16; - arcmsr_ccb_complete(ccb, 1); - break; - } - } - found = 1; - } + switch (acb->adapter_type) { + + case ACB_ADAPTER_TYPE_A: { + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; + do { + firmware_state = readl(®->outbound_msgaddr1); + } while ((firmware_state & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0); + } + break; + + case ACB_ADAPTER_TYPE_B: { + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + do { + firmware_state = readl(reg->iop2drv_doorbell_reg); + } while ((firmware_state & ARCMSR_MESSAGE_FIRMWARE_OK) == 0); + } + break; } - if (found){ - outbound_intstatus = readl(®->outbound_intstatus) & \ - acb->outbound_int_enable; - writel(outbound_intstatus, ®->outbound_intstatus); - /*clear interrupt*/ +} + +static void arcmsr_start_hba_bgrb(struct AdapterControlBlock *acb) +{ + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; + acb->acb_flags |= ACB_F_MSG_START_BGRB; + writel(ARCMSR_INBOUND_MESG0_START_BGRB, ®->inbound_msgaddr0); + if (arcmsr_hba_wait_msgint_ready(acb)) { + printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \ + rebulid' timeout \n", acb->host->host_no); } - return; } +static void arcmsr_start_hbb_bgrb(struct AdapterControlBlock *acb) +{ + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + acb->acb_flags |= ACB_F_MSG_START_BGRB; + writel(ARCMSR_MESSAGE_START_BGRB, reg->drv2iop_doorbell_reg); + if (arcmsr_hbb_wait_msgint_ready(acb)) { + printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \ + rebulid' timeout \n",acb->host->host_no); + } +} -static void arcmsr_iop_init(struct AdapterControlBlock *acb) +static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb) { - struct MessageUnit __iomem *reg = acb->pmu; - uint32_t intmask_org, mask, outbound_doorbell, firmware_state = 0; + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_A: + arcmsr_start_hba_bgrb(acb); + break; + case ACB_ADAPTER_TYPE_B: + arcmsr_start_hbb_bgrb(acb); + break; + } +} - do { - firmware_state = readl(®->outbound_msgaddr1); - } while (!(firmware_state & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK)); - intmask_org = readl(®->outbound_intmask) - | ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE; - arcmsr_get_firmware_spec(acb); +static void arcmsr_clear_doorbell_queue_buffer(struct AdapterControlBlock *acb) +{ + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_A: { + struct MessageUnit_A *reg = (struct MessageUnit_A *)acb->pmu; + uint32_t outbound_doorbell; + /* empty doorbell Qbuffer if door bell ringed */ + outbound_doorbell = readl(®->outbound_doorbell); + /*clear doorbell interrupt */ + writel(outbound_doorbell, ®->outbound_doorbell); + writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, ®->inbound_doorbell); + } + break; - acb->acb_flags |= ACB_F_MSG_START_BGRB; - writel(ARCMSR_INBOUND_MESG0_START_BGRB, ®->inbound_msgaddr0); - if (arcmsr_wait_msgint_ready(acb)) { - printk(KERN_NOTICE "arcmsr%d: " - "wait 'start adapter background rebulid' timeout\n", - acb->host->host_no); + case ACB_ADAPTER_TYPE_B: { + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + /*clear interrupt and message state*/ + writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell_reg); + writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell_reg); + /* let IOP know data has been read */ + } + break; } +} - outbound_doorbell = readl(®->outbound_doorbell); - writel(outbound_doorbell, ®->outbound_doorbell); - writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, ®->inbound_doorbell); - mask = ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE - | ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE); - writel(intmask_org & mask, ®->outbound_intmask); - acb->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff; +static void arcmsr_iop_init(struct AdapterControlBlock *acb) +{ + uint32_t intmask_org; + + arcmsr_wait_firmware_ready(acb); + arcmsr_iop_confirm(acb); + /* disable all outbound interrupt */ + intmask_org = arcmsr_disable_outbound_ints(acb); + arcmsr_get_firmware_spec(acb); + /*start background rebuild*/ + arcmsr_start_adapter_bgrb(acb); + /* empty doorbell Qbuffer if door bell ringed */ + arcmsr_clear_doorbell_queue_buffer(acb); + /* enable outbound Post Queue,outbound doorbell Interrupt */ + arcmsr_enable_outbound_ints(acb, intmask_org); acb->acb_flags |= ACB_F_IOP_INITED; } @@ -1421,22 +2096,24 @@ static void arcmsr_iop_reset(struct AdapterControlBlock *acb) if (atomic_read(&acb->ccboutstandingcount) != 0) { /* talk to iop 331 outstanding command aborted */ arcmsr_abort_allcmd(acb); + /* wait for 3 sec for all command aborted*/ - msleep_interruptible(3000); + ssleep(3); + /* disable all outbound interrupt */ intmask_org = arcmsr_disable_outbound_ints(acb); /* clear all outbound posted Q */ - arcmsr_done4_abort_postqueue(acb); + arcmsr_done4abort_postqueue(acb); for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { ccb = acb->pccb_pool[i]; if (ccb->startdone == ARCMSR_CCB_START) { ccb->startdone = ARCMSR_CCB_ABORTED; + arcmsr_ccb_complete(ccb, 1); } } /* enable all outbound interrupt */ arcmsr_enable_outbound_ints(acb, intmask_org); } - } static int arcmsr_bus_reset(struct scsi_cmnd *cmd) @@ -1450,7 +2127,7 @@ static int arcmsr_bus_reset(struct scsi_cmnd *cmd) for (i = 0; i < 400; i++) { if (!atomic_read(&acb->ccboutstandingcount)) break; - arcmsr_interrupt(acb); + arcmsr_interrupt(acb);/* FIXME: need spinlock */ msleep(25); } arcmsr_iop_reset(acb); @@ -1468,7 +2145,7 @@ static void arcmsr_abort_one_cmd(struct AdapterControlBlock *acb, /* ** Wait for 3 sec for all command done. */ - msleep_interruptible(3000); + ssleep(3); intmask = arcmsr_disable_outbound_ints(acb); arcmsr_polling_ccbdone(acb, ccb); @@ -1515,6 +2192,8 @@ static const char *arcmsr_info(struct Scsi_Host *host) switch (acb->pdev->device) { case PCI_DEVICE_ID_ARECA_1110: + case PCI_DEVICE_ID_ARECA_1200: + case PCI_DEVICE_ID_ARECA_1202: case PCI_DEVICE_ID_ARECA_1210: raid6 = 0; /*FALLTHRU*/ @@ -1522,6 +2201,7 @@ static const char *arcmsr_info(struct Scsi_Host *host) case PCI_DEVICE_ID_ARECA_1130: case PCI_DEVICE_ID_ARECA_1160: case PCI_DEVICE_ID_ARECA_1170: + case PCI_DEVICE_ID_ARECA_1201: case PCI_DEVICE_ID_ARECA_1220: case PCI_DEVICE_ID_ARECA_1230: case PCI_DEVICE_ID_ARECA_1260: @@ -1544,287 +2224,82 @@ static const char *arcmsr_info(struct Scsi_Host *host) ARCMSR_DRIVER_VERSION); return buf; } - +#ifdef CONFIG_SCSI_ARCMSR_AER static pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev) { - struct Scsi_Host *host; - struct AdapterControlBlock *acb; - uint8_t bus, dev_fun; - int error; - - error = pci_enable_device(pdev); - if (error) - return PCI_ERS_RESULT_DISCONNECT; - pci_set_master(pdev); - - host = scsi_host_alloc(&arcmsr_scsi_host_template, sizeof \ -(struct AdapterControlBlock)); - if (!host) - return PCI_ERS_RESULT_DISCONNECT; - acb = (struct AdapterControlBlock *)host->hostdata; - memset(acb, 0, sizeof (struct AdapterControlBlock)); - - error = pci_set_dma_mask(pdev, DMA_64BIT_MASK); - if (error) { - error = pci_set_dma_mask(pdev, DMA_32BIT_MASK); - if (error) { - printk(KERN_WARNING - "scsi%d: No suitable DMA mask available\n", - host->host_no); - return PCI_ERS_RESULT_DISCONNECT; - } - } - bus = pdev->bus->number; - dev_fun = pdev->devfn; - acb = (struct AdapterControlBlock *) host->hostdata; - memset(acb, 0, sizeof(struct AdapterControlBlock)); - acb->pdev = pdev; - acb->host = host; - host->max_sectors = ARCMSR_MAX_XFER_SECTORS; - host->max_lun = ARCMSR_MAX_TARGETLUN; - host->max_id = ARCMSR_MAX_TARGETID;/*16:8*/ - host->max_cmd_len = 16; /*this is issue of 64bit LBA, over 2T byte*/ - host->sg_tablesize = ARCMSR_MAX_SG_ENTRIES; - host->can_queue = ARCMSR_MAX_FREECCB_NUM; /* max simultaneous cmds */ - host->cmd_per_lun = ARCMSR_MAX_CMD_PERLUN; - host->this_id = ARCMSR_SCSI_INITIATOR_ID; - host->unique_id = (bus << 8) | dev_fun; - host->irq = pdev->irq; - error = pci_request_regions(pdev, "arcmsr"); - if (error) - return PCI_ERS_RESULT_DISCONNECT; + struct Scsi_Host *host = pci_get_drvdata(pdev); + struct AdapterControlBlock *acb = + (struct AdapterControlBlock *) host->hostdata; + uint32_t intmask_org; + int i, j; - acb->pmu = ioremap(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - if (!acb->pmu) { - printk(KERN_NOTICE "arcmsr%d: memory" - " mapping region fail \n", acb->host->host_no); + if (pci_enable_device(pdev)) { return PCI_ERS_RESULT_DISCONNECT; } + pci_set_master(pdev); + intmask_org = arcmsr_disable_outbound_ints(acb); acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED | ACB_F_MESSAGE_RQBUFFER_CLEARED | ACB_F_MESSAGE_WQBUFFER_READED); acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER; - INIT_LIST_HEAD(&acb->ccb_free_list); - - error = arcmsr_alloc_ccb_pool(acb); - if (error) - return PCI_ERS_RESULT_DISCONNECT; - - error = request_irq(pdev->irq, arcmsr_do_interrupt, - IRQF_DISABLED | IRQF_SHARED, "arcmsr", acb); - if (error) - return PCI_ERS_RESULT_DISCONNECT; - - arcmsr_iop_init(acb); - if (strncmp(acb->firm_version, "V1.42", 5) >= 0) - host->max_sectors = ARCMSR_MAX_XFER_SECTORS_B; - - pci_set_drvdata(pdev, host); - - error = scsi_add_host(host, &pdev->dev); - if (error) - return PCI_ERS_RESULT_DISCONNECT; + for (i = 0; i < ARCMSR_MAX_TARGETID; i++) + for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++) + acb->devstate[i][j] = ARECA_RAID_GONE; - error = arcmsr_alloc_sysfs_attr(acb); - if (error) - return PCI_ERS_RESULT_DISCONNECT; + arcmsr_wait_firmware_ready(acb); + arcmsr_iop_confirm(acb); + /* disable all outbound interrupt */ + arcmsr_get_firmware_spec(acb); + /*start background rebuild*/ + arcmsr_start_adapter_bgrb(acb); + /* empty doorbell Qbuffer if door bell ringed */ + arcmsr_clear_doorbell_queue_buffer(acb); + /* enable outbound Post Queue,outbound doorbell Interrupt */ + arcmsr_enable_outbound_ints(acb, intmask_org); + acb->acb_flags |= ACB_F_IOP_INITED; - scsi_scan_host(host); + pci_enable_pcie_error_reporting(pdev); return PCI_ERS_RESULT_RECOVERED; } static void arcmsr_pci_ers_need_reset_forepart(struct pci_dev *pdev) { struct Scsi_Host *host = pci_get_drvdata(pdev); - struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; - struct MessageUnit __iomem *reg = acb->pmu; + struct AdapterControlBlock *acb = (struct AdapterControlBlock *)host->hostdata; struct CommandControlBlock *ccb; - /*clear and abort all outbound posted Q*/ - int i = 0, found = 0; - int id, lun; - uint32_t flag_ccb, outbound_intstatus; - - while (((flag_ccb = readl(®->outbound_queueport)) != 0xFFFFFFFF) && - (i++ < 256)){ - ccb = (struct CommandControlBlock *)(acb->vir2phy_offset - + (flag_ccb << 5)); - if (ccb){ - if ((ccb->acb != acb)||(ccb->startdone != - ARCMSR_CCB_START)){ - printk(KERN_NOTICE "arcmsr%d: polling \ - get an illegal ccb"" command done ccb = '0x%p'" - "ccboutstandingcount = %d \n", - acb->host->host_no, ccb, - atomic_read(&acb->ccboutstandingcount)); - continue; - } - - id = ccb->pcmd->device->id; - lun = ccb->pcmd->device->lun; - if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) { - if (acb->devstate[id][lun] == - ARECA_RAID_GONE) - acb->devstate[id][lun] = - ARECA_RAID_GOOD; - ccb->pcmd->result = DID_OK << 16; - arcmsr_ccb_complete(ccb, 1); - } - else { - switch(ccb->arcmsr_cdb.DeviceStatus) { - case ARCMSR_DEV_SELECT_TIMEOUT: { - acb->devstate[id][lun] = - ARECA_RAID_GONE; - ccb->pcmd->result = - DID_NO_CONNECT << 16; - arcmsr_ccb_complete(ccb, 1); - } - break; - - case ARCMSR_DEV_ABORTED: - - case ARCMSR_DEV_INIT_FAIL: { - acb->devstate[id][lun] = - ARECA_RAID_GONE; - ccb->pcmd->result = - DID_BAD_TARGET << 16; - arcmsr_ccb_complete(ccb, 1); - } - break; - - case ARCMSR_DEV_CHECK_CONDITION: { - acb->devstate[id][lun] = - ARECA_RAID_GOOD; - arcmsr_report_sense_info(ccb); - arcmsr_ccb_complete(ccb, 1); - } - break; + uint32_t intmask_org; + int i = 0; - default: - printk(KERN_NOTICE - "arcmsr%d: scsi \ - id = %d lun = %d" - " polling and \ - getting command \ - error done" - "but got unknown \ - DeviceStatus = 0x%x \n" - , acb->host->host_no, - id, lun, - ccb->arcmsr_cdb.DeviceStatus); - acb->devstate[id][lun] = - ARECA_RAID_GONE; - ccb->pcmd->result = - DID_BAD_TARGET << 16; - arcmsr_ccb_complete(ccb, 1); - break; - } - } - found = 1; + if (atomic_read(&acb->ccboutstandingcount) != 0) { + /* talk to iop 331 outstanding command aborted */ + arcmsr_abort_allcmd(acb); + /* wait for 3 sec for all command aborted*/ + ssleep(3); + /* disable all outbound interrupt */ + intmask_org = arcmsr_disable_outbound_ints(acb); + /* clear all outbound posted Q */ + arcmsr_done4abort_postqueue(acb); + for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { + ccb = acb->pccb_pool[i]; + if (ccb->startdone == ARCMSR_CCB_START) { + ccb->startdone = ARCMSR_CCB_ABORTED; + arcmsr_ccb_complete(ccb, 1); } } - if (found){ - outbound_intstatus = readl(®->outbound_intstatus) & - acb->outbound_int_enable; - writel(outbound_intstatus, ®->outbound_intstatus); - /*clear interrupt*/ - } - return; + /* enable all outbound interrupt */ + arcmsr_enable_outbound_ints(acb, intmask_org); + } + pci_disable_device(pdev); } - static void arcmsr_pci_ers_disconnect_forepart(struct pci_dev *pdev) { - struct Scsi_Host *host = pci_get_drvdata(pdev); - struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; - struct MessageUnit __iomem *reg = acb->pmu; - struct CommandControlBlock *ccb; - /*clear and abort all outbound posted Q*/ - int i = 0, found = 0; - int id, lun; - uint32_t flag_ccb, outbound_intstatus; - - while (((flag_ccb = readl(®->outbound_queueport)) != 0xFFFFFFFF) && - (i++ < 256)){ - ccb = (struct CommandControlBlock *)(acb->vir2phy_offset + - (flag_ccb << 5)); - if (ccb){ - if ((ccb->acb != acb)||(ccb->startdone != - ARCMSR_CCB_START)){ - printk(KERN_NOTICE - "arcmsr%d: polling get an illegal ccb" - " command done ccb = '0x%p'" - "ccboutstandingcount = %d \n", - acb->host->host_no, ccb, - atomic_read(&acb->ccboutstandingcount)); - continue; - } - - id = ccb->pcmd->device->id; - lun = ccb->pcmd->device->lun; - if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) { - if (acb->devstate[id][lun] == ARECA_RAID_GONE) - acb->devstate[id][lun] = ARECA_RAID_GOOD; - ccb->pcmd->result = DID_OK << 16; - arcmsr_ccb_complete(ccb, 1); - } - else { - switch(ccb->arcmsr_cdb.DeviceStatus) { - case ARCMSR_DEV_SELECT_TIMEOUT: { - acb->devstate[id][lun] = - ARECA_RAID_GONE; - ccb->pcmd->result = - DID_NO_CONNECT << 16; - arcmsr_ccb_complete(ccb, 1); - } - break; - - case ARCMSR_DEV_ABORTED: - - case ARCMSR_DEV_INIT_FAIL: { - acb->devstate[id][lun] = - ARECA_RAID_GONE; - ccb->pcmd->result = - DID_BAD_TARGET << 16; - arcmsr_ccb_complete(ccb, 1); - } - break; + struct Scsi_Host *host = pci_get_drvdata(pdev); + struct AdapterControlBlock *acb = \ + (struct AdapterControlBlock *)host->hostdata; - case ARCMSR_DEV_CHECK_CONDITION: { - acb->devstate[id][lun] = - ARECA_RAID_GOOD; - arcmsr_report_sense_info(ccb); - arcmsr_ccb_complete(ccb, 1); - } - break; - - default: - printk(KERN_NOTICE "arcmsr%d: \ - scsi id = %d lun = %d" - " polling and \ - getting command error done" - "but got unknown \ - DeviceStatus = 0x%x \n" - , acb->host->host_no, - id, lun, ccb->arcmsr_cdb.DeviceStatus); - acb->devstate[id][lun] = - ARECA_RAID_GONE; - ccb->pcmd->result = - DID_BAD_TARGET << 16; - arcmsr_ccb_complete(ccb, 1); - break; - } - } - found = 1; - } - } - if (found){ - outbound_intstatus = readl(®->outbound_intstatus) & - acb->outbound_int_enable; - writel(outbound_intstatus, ®->outbound_intstatus); - /*clear interrupt*/ - } - return; + arcmsr_stop_adapter_bgrb(acb); + arcmsr_flush_adapter_cache(acb); } static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev, @@ -1840,5 +2315,6 @@ static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev, break; default: return PCI_ERS_RESULT_NEED_RESET; - } + } } +#endif diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c index 03dbe60c264a..52d0b87e9aa4 100644 --- a/drivers/scsi/atari_NCR5380.c +++ b/drivers/scsi/atari_NCR5380.c @@ -2041,7 +2041,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) sink = 1; do_abort(instance); cmd->result = DID_ERROR << 16; - cmd->done(cmd); + cmd->scsi_done(cmd); return; #endif case PHASE_DATAIN: @@ -2100,7 +2100,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) sink = 1; do_abort(instance); cmd->result = DID_ERROR << 16; - cmd->done(cmd); + cmd->scsi_done(cmd); /* XXX - need to source or sink data here, as appropriate */ } else { #ifdef REAL_DMA @@ -2235,24 +2235,17 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); #ifdef AUTOSENSE + if ((cmd->cmnd[0] == REQUEST_SENSE) && + hostdata->ses.cmd_len) { + scsi_eh_restore_cmnd(cmd, &hostdata->ses); + hostdata->ses.cmd_len = 0 ; + } + if ((cmd->cmnd[0] != REQUEST_SENSE) && (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) { + scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0); + ASEN_PRINTK("scsi%d: performing request sense\n", HOSTNO); - cmd->cmnd[0] = REQUEST_SENSE; - cmd->cmnd[1] &= 0xe0; - cmd->cmnd[2] = 0; - cmd->cmnd[3] = 0; - cmd->cmnd[4] = sizeof(cmd->sense_buffer); - cmd->cmnd[5] = 0; - cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]); - - cmd->use_sg = 0; - /* this is initialized from initialize_SCp - cmd->SCp.buffer = NULL; - cmd->SCp.buffers_residual = 0; - */ - cmd->request_buffer = (char *) cmd->sense_buffer; - cmd->request_bufflen = sizeof(cmd->sense_buffer); local_irq_save(flags); LIST(cmd,hostdata->issue_queue); diff --git a/drivers/scsi/bvme6000_scsi.c b/drivers/scsi/bvme6000_scsi.c index cac354086737..d858f3d41274 100644 --- a/drivers/scsi/bvme6000_scsi.c +++ b/drivers/scsi/bvme6000_scsi.c @@ -36,19 +36,18 @@ static struct platform_device *bvme6000_scsi_device; static __devinit int bvme6000_probe(struct device *dev) { - struct Scsi_Host * host = NULL; + struct Scsi_Host *host; struct NCR_700_Host_Parameters *hostdata; if (!MACH_IS_BVME6000) goto out; - hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL); - if (hostdata == NULL) { + hostdata = kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL); + if (!hostdata) { printk(KERN_ERR "bvme6000-scsi: " "Failed to allocate host data\n"); goto out; } - memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters)); /* Fill in the required pieces of hostdata */ hostdata->base = (void __iomem *)BVME_NCR53C710_BASE; diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c index 2a458d66b6ff..024553f9c247 100644 --- a/drivers/scsi/constants.c +++ b/drivers/scsi/constants.c @@ -1235,7 +1235,21 @@ scsi_print_sense_hdr(const char *name, struct scsi_sense_hdr *sshdr) } EXPORT_SYMBOL(scsi_print_sense_hdr); +/* + * Print normalized SCSI sense header with device information and a prefix. + */ void +scsi_cmd_print_sense_hdr(struct scsi_cmnd *scmd, const char *desc, + struct scsi_sense_hdr *sshdr) +{ + scmd_printk(KERN_INFO, scmd, "%s: ", desc); + scsi_show_sense_hdr(sshdr); + scmd_printk(KERN_INFO, scmd, "%s: ", desc); + scsi_show_extd_sense(sshdr->asc, sshdr->ascq); +} +EXPORT_SYMBOL(scsi_cmd_print_sense_hdr); + +static void scsi_decode_sense_buffer(const unsigned char *sense_buffer, int sense_len, struct scsi_sense_hdr *sshdr) { @@ -1258,7 +1272,7 @@ scsi_decode_sense_buffer(const unsigned char *sense_buffer, int sense_len, } } -void +static void scsi_decode_sense_extras(const unsigned char *sense_buffer, int sense_len, struct scsi_sense_hdr *sshdr) { diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index 7b8a3457b696..1591824cf4b3 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -778,7 +778,7 @@ static void srb_waiting_insert(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) { dprintkdbg(DBG_0, "srb_waiting_insert: (pid#%li) <%02i-%i> srb=%p\n", - srb->cmd->pid, dcb->target_id, dcb->target_lun, srb); + srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb); list_add(&srb->list, &dcb->srb_waiting_list); } @@ -787,7 +787,7 @@ static void srb_waiting_append(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) { dprintkdbg(DBG_0, "srb_waiting_append: (pid#%li) <%02i-%i> srb=%p\n", - srb->cmd->pid, dcb->target_id, dcb->target_lun, srb); + srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb); list_add_tail(&srb->list, &dcb->srb_waiting_list); } @@ -795,7 +795,7 @@ static void srb_waiting_append(struct DeviceCtlBlk *dcb, static void srb_going_append(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) { dprintkdbg(DBG_0, "srb_going_append: (pid#%li) <%02i-%i> srb=%p\n", - srb->cmd->pid, dcb->target_id, dcb->target_lun, srb); + srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb); list_add_tail(&srb->list, &dcb->srb_going_list); } @@ -805,7 +805,7 @@ static void srb_going_remove(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) struct ScsiReqBlk *i; struct ScsiReqBlk *tmp; dprintkdbg(DBG_0, "srb_going_remove: (pid#%li) <%02i-%i> srb=%p\n", - srb->cmd->pid, dcb->target_id, dcb->target_lun, srb); + srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb); list_for_each_entry_safe(i, tmp, &dcb->srb_going_list, list) if (i == srb) { @@ -821,7 +821,7 @@ static void srb_waiting_remove(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *i; struct ScsiReqBlk *tmp; dprintkdbg(DBG_0, "srb_waiting_remove: (pid#%li) <%02i-%i> srb=%p\n", - srb->cmd->pid, dcb->target_id, dcb->target_lun, srb); + srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb); list_for_each_entry_safe(i, tmp, &dcb->srb_waiting_list, list) if (i == srb) { @@ -836,7 +836,7 @@ static void srb_going_to_waiting_move(struct DeviceCtlBlk *dcb, { dprintkdbg(DBG_0, "srb_going_to_waiting_move: (pid#%li) <%02i-%i> srb=%p\n", - srb->cmd->pid, dcb->target_id, dcb->target_lun, srb); + srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb); list_move(&srb->list, &dcb->srb_waiting_list); } @@ -846,7 +846,7 @@ static void srb_waiting_to_going_move(struct DeviceCtlBlk *dcb, { dprintkdbg(DBG_0, "srb_waiting_to_going_move: (pid#%li) <%02i-%i> srb=%p\n", - srb->cmd->pid, dcb->target_id, dcb->target_lun, srb); + srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb); list_move(&srb->list, &dcb->srb_going_list); } @@ -982,7 +982,7 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb, int nseg; enum dma_data_direction dir = cmd->sc_data_direction; dprintkdbg(DBG_0, "build_srb: (pid#%li) <%02i-%i>\n", - cmd->pid, dcb->target_id, dcb->target_lun); + cmd->serial_number, dcb->target_id, dcb->target_lun); srb->dcb = dcb; srb->cmd = cmd; @@ -1086,7 +1086,7 @@ static int dc395x_queue_command(struct scsi_cmnd *cmd, void (*done)(struct scsi_ struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)cmd->device->host->hostdata; dprintkdbg(DBG_0, "queue_command: (pid#%li) <%02i-%i> cmnd=0x%02x\n", - cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); + cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); /* Assume BAD_TARGET; will be cleared later */ cmd->result = DID_BAD_TARGET << 16; @@ -1139,7 +1139,7 @@ static int dc395x_queue_command(struct scsi_cmnd *cmd, void (*done)(struct scsi_ /* process immediately */ send_srb(acb, srb); } - dprintkdbg(DBG_1, "queue_command: (pid#%li) done\n", cmd->pid); + dprintkdbg(DBG_1, "queue_command: (pid#%li) done\n", cmd->serial_number); return 0; complete: @@ -1203,7 +1203,7 @@ static void dump_register_info(struct AdapterCtlBlk *acb, else dprintkl(KERN_INFO, "dump: srb=%p cmd=%p (pid#%li) " "cmnd=0x%02x <%02i-%i>\n", - srb, srb->cmd, srb->cmd->pid, + srb, srb->cmd, srb->cmd->serial_number, srb->cmd->cmnd[0], srb->cmd->device->id, srb->cmd->device->lun); printk(" sglist=%p cnt=%i idx=%i len=%zu\n", @@ -1300,7 +1300,7 @@ static int __dc395x_eh_bus_reset(struct scsi_cmnd *cmd) (struct AdapterCtlBlk *)cmd->device->host->hostdata; dprintkl(KERN_INFO, "eh_bus_reset: (pid#%li) target=<%02i-%i> cmd=%p\n", - cmd->pid, cmd->device->id, cmd->device->lun, cmd); + cmd->serial_number, cmd->device->id, cmd->device->lun, cmd); if (timer_pending(&acb->waiting_timer)) del_timer(&acb->waiting_timer); @@ -1367,7 +1367,7 @@ static int dc395x_eh_abort(struct scsi_cmnd *cmd) struct DeviceCtlBlk *dcb; struct ScsiReqBlk *srb; dprintkl(KERN_INFO, "eh_abort: (pid#%li) target=<%02i-%i> cmd=%p\n", - cmd->pid, cmd->device->id, cmd->device->lun, cmd); + cmd->serial_number, cmd->device->id, cmd->device->lun, cmd); dcb = find_dcb(acb, cmd->device->id, cmd->device->lun); if (!dcb) { @@ -1494,7 +1494,7 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, u8 s_stat, scsicommand, i, identify_message; u8 *ptr; dprintkdbg(DBG_0, "start_scsi: (pid#%li) <%02i-%i> srb=%p\n", - srb->cmd->pid, dcb->target_id, dcb->target_lun, srb); + srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb); srb->tag_number = TAG_NONE; /* acb->tag_max_num: had error read in eeprom */ @@ -1504,7 +1504,7 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, #if 1 if (s_stat & 0x20 /* s_stat2 & 0x02000 */ ) { dprintkdbg(DBG_KG, "start_scsi: (pid#%li) BUSY %02x %04x\n", - srb->cmd->pid, s_stat, s_stat2); + srb->cmd->serial_number, s_stat, s_stat2); /* * Try anyway? * @@ -1522,14 +1522,14 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, if (acb->active_dcb) { dprintkl(KERN_DEBUG, "start_scsi: (pid#%li) Attempt to start a" "command while another command (pid#%li) is active.", - srb->cmd->pid, + srb->cmd->serial_number, acb->active_dcb->active_srb ? - acb->active_dcb->active_srb->cmd->pid : 0); + acb->active_dcb->active_srb->cmd->serial_number : 0); return 1; } if (DC395x_read16(acb, TRM_S1040_SCSI_STATUS) & SCSIINTERRUPT) { dprintkdbg(DBG_KG, "start_scsi: (pid#%li) Failed (busy)\n", - srb->cmd->pid); + srb->cmd->serial_number); return 1; } /* Allow starting of SCSI commands half a second before we allow the mid-level @@ -1603,7 +1603,7 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, if (tag_number >= dcb->max_command) { dprintkl(KERN_WARNING, "start_scsi: (pid#%li) " "Out of tags target=<%02i-%i>)\n", - srb->cmd->pid, srb->cmd->device->id, + srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun); srb->state = SRB_READY; DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, @@ -1622,7 +1622,7 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, /*polling:*/ /* Send CDB ..command block ......... */ dprintkdbg(DBG_KG, "start_scsi: (pid#%li) <%02i-%i> cmnd=0x%02x tag=%i\n", - srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun, + srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun, srb->cmd->cmnd[0], srb->tag_number); if (srb->flag & AUTO_REQSENSE) { DC395x_write8(acb, TRM_S1040_SCSI_FIFO, REQUEST_SENSE); @@ -1647,7 +1647,7 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, * : Let's process it first! */ dprintkdbg(DBG_0, "start_scsi: (pid#%li) <%02i-%i> Failed - busy\n", - srb->cmd->pid, dcb->target_id, dcb->target_lun); + srb->cmd->serial_number, dcb->target_id, dcb->target_lun); srb->state = SRB_READY; free_tag(dcb, srb); srb->msg_count = 0; @@ -1842,7 +1842,7 @@ static irqreturn_t dc395x_interrupt(int irq, void *dev_id) static void msgout_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { - dprintkdbg(DBG_0, "msgout_phase0: (pid#%li)\n", srb->cmd->pid); + dprintkdbg(DBG_0, "msgout_phase0: (pid#%li)\n", srb->cmd->serial_number); if (srb->state & (SRB_UNEXPECT_RESEL + SRB_ABORT_SENT)) *pscsi_status = PH_BUS_FREE; /*.. initial phase */ @@ -1856,18 +1856,18 @@ static void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, { u16 i; u8 *ptr; - dprintkdbg(DBG_0, "msgout_phase1: (pid#%li)\n", srb->cmd->pid); + dprintkdbg(DBG_0, "msgout_phase1: (pid#%li)\n", srb->cmd->serial_number); clear_fifo(acb, "msgout_phase1"); if (!(srb->state & SRB_MSGOUT)) { srb->state |= SRB_MSGOUT; dprintkl(KERN_DEBUG, "msgout_phase1: (pid#%li) Phase unexpected\n", - srb->cmd->pid); /* So what ? */ + srb->cmd->serial_number); /* So what ? */ } if (!srb->msg_count) { dprintkdbg(DBG_0, "msgout_phase1: (pid#%li) NOP msg\n", - srb->cmd->pid); + srb->cmd->serial_number); DC395x_write8(acb, TRM_S1040_SCSI_FIFO, MSG_NOP); DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT); @@ -1887,7 +1887,7 @@ static void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, static void command_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { - dprintkdbg(DBG_0, "command_phase0: (pid#%li)\n", srb->cmd->pid); + dprintkdbg(DBG_0, "command_phase0: (pid#%li)\n", srb->cmd->serial_number); DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); } @@ -1898,7 +1898,7 @@ static void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, struct DeviceCtlBlk *dcb; u8 *ptr; u16 i; - dprintkdbg(DBG_0, "command_phase1: (pid#%li)\n", srb->cmd->pid); + dprintkdbg(DBG_0, "command_phase1: (pid#%li)\n", srb->cmd->serial_number); clear_fifo(acb, "command_phase1"); DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_CLRATN); @@ -2042,7 +2042,7 @@ static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 scsi_status = *pscsi_status; u32 d_left_counter = 0; dprintkdbg(DBG_0, "data_out_phase0: (pid#%li) <%02i-%i>\n", - srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun); + srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun); /* * KG: We need to drain the buffers before we draw any conclusions! @@ -2172,7 +2172,7 @@ static void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { dprintkdbg(DBG_0, "data_out_phase1: (pid#%li) <%02i-%i>\n", - srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun); + srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun); clear_fifo(acb, "data_out_phase1"); /* do prepare before transfer when data out phase */ data_io_transfer(acb, srb, XFERDATAOUT); @@ -2184,7 +2184,7 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 scsi_status = *pscsi_status; dprintkdbg(DBG_0, "data_in_phase0: (pid#%li) <%02i-%i>\n", - srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun); + srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun); /* * KG: DataIn is much more tricky than DataOut. When the device is finished @@ -2205,7 +2205,7 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, if (scsi_status & PARITYERROR) { dprintkl(KERN_INFO, "data_in_phase0: (pid#%li) " - "Parity Error\n", srb->cmd->pid); + "Parity Error\n", srb->cmd->serial_number); srb->status |= PARITY_ERROR; } /* @@ -2395,7 +2395,7 @@ static void data_in_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { dprintkdbg(DBG_0, "data_in_phase1: (pid#%li) <%02i-%i>\n", - srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun); + srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun); data_io_transfer(acb, srb, XFERDATAIN); } @@ -2407,7 +2407,7 @@ static void data_io_transfer(struct AdapterCtlBlk *acb, u8 bval; dprintkdbg(DBG_0, "data_io_transfer: (pid#%li) <%02i-%i> %c len=%i, sg=(%i/%i)\n", - srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun, + srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun, ((io_dir & DMACMD_DIR) ? 'r' : 'w'), srb->total_xfer_length, srb->sg_index, srb->sg_count); if (srb == acb->tmp_srb) @@ -2580,7 +2580,7 @@ static void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { dprintkdbg(DBG_0, "status_phase0: (pid#%li) <%02i-%i>\n", - srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun); + srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun); srb->target_status = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); srb->end_message = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); /* get message */ srb->state = SRB_COMPLETED; @@ -2594,7 +2594,7 @@ static void status_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { dprintkdbg(DBG_0, "status_phase1: (pid#%li) <%02i-%i>\n", - srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun); + srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun); srb->state = SRB_STATUS; DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_COMP); @@ -2636,7 +2636,7 @@ static struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb = NULL; struct ScsiReqBlk *i; dprintkdbg(DBG_0, "msgin_qtag: (pid#%li) tag=%i srb=%p\n", - srb->cmd->pid, tag, srb); + srb->cmd->serial_number, tag, srb); if (!(dcb->tag_mask & (1 << tag))) dprintkl(KERN_DEBUG, @@ -2655,7 +2655,7 @@ static struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb, goto mingx0; dprintkdbg(DBG_0, "msgin_qtag: (pid#%li) <%02i-%i>\n", - srb->cmd->pid, srb->dcb->target_id, srb->dcb->target_lun); + srb->cmd->serial_number, srb->dcb->target_id, srb->dcb->target_lun); if (dcb->flag & ABORT_DEV_) { /*srb->state = SRB_ABORT_SENT; */ enable_msgout_abort(acb, srb); @@ -2865,7 +2865,7 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { struct DeviceCtlBlk *dcb = acb->active_dcb; - dprintkdbg(DBG_0, "msgin_phase0: (pid#%li)\n", srb->cmd->pid); + dprintkdbg(DBG_0, "msgin_phase0: (pid#%li)\n", srb->cmd->serial_number); srb->msgin_buf[acb->msg_len++] = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); if (msgin_completed(srb->msgin_buf, acb->msg_len)) { @@ -2933,7 +2933,7 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, */ dprintkdbg(DBG_0, "msgin_phase0: (pid#%li) " "SAVE POINTER rem=%i Ignore\n", - srb->cmd->pid, srb->total_xfer_length); + srb->cmd->serial_number, srb->total_xfer_length); break; case RESTORE_POINTERS: @@ -2943,7 +2943,7 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, case ABORT: dprintkdbg(DBG_0, "msgin_phase0: (pid#%li) " "<%02i-%i> ABORT msg\n", - srb->cmd->pid, dcb->target_id, + srb->cmd->serial_number, dcb->target_id, dcb->target_lun); dcb->flag |= ABORT_DEV_; enable_msgout_abort(acb, srb); @@ -2975,7 +2975,7 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, static void msgin_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { - dprintkdbg(DBG_0, "msgin_phase1: (pid#%li)\n", srb->cmd->pid); + dprintkdbg(DBG_0, "msgin_phase1: (pid#%li)\n", srb->cmd->serial_number); clear_fifo(acb, "msgin_phase1"); DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 1); if (!(srb->state & SRB_MSGIN)) { @@ -3041,7 +3041,7 @@ static void disconnect(struct AdapterCtlBlk *acb) } srb = dcb->active_srb; acb->active_dcb = NULL; - dprintkdbg(DBG_0, "disconnect: (pid#%li)\n", srb->cmd->pid); + dprintkdbg(DBG_0, "disconnect: (pid#%li)\n", srb->cmd->serial_number); srb->scsi_phase = PH_BUS_FREE; /* initial phase */ clear_fifo(acb, "disconnect"); @@ -3072,13 +3072,13 @@ static void disconnect(struct AdapterCtlBlk *acb) srb->state = SRB_READY; dprintkl(KERN_DEBUG, "disconnect: (pid#%li) Unexpected\n", - srb->cmd->pid); + srb->cmd->serial_number); srb->target_status = SCSI_STAT_SEL_TIMEOUT; goto disc1; } else { /* Normal selection timeout */ dprintkdbg(DBG_KG, "disconnect: (pid#%li) " - "<%02i-%i> SelTO\n", srb->cmd->pid, + "<%02i-%i> SelTO\n", srb->cmd->serial_number, dcb->target_id, dcb->target_lun); if (srb->retry_count++ > DC395x_MAX_RETRIES || acb->scan_devices) { @@ -3090,7 +3090,7 @@ static void disconnect(struct AdapterCtlBlk *acb) srb_going_to_waiting_move(dcb, srb); dprintkdbg(DBG_KG, "disconnect: (pid#%li) Retry\n", - srb->cmd->pid); + srb->cmd->serial_number); waiting_set_timer(acb, HZ / 20); } } else if (srb->state & SRB_DISCONNECT) { @@ -3144,7 +3144,7 @@ static void reselect(struct AdapterCtlBlk *acb) if (!acb->scan_devices) { dprintkdbg(DBG_KG, "reselect: (pid#%li) <%02i-%i> " "Arb lost but Resel win rsel=%i stat=0x%04x\n", - srb->cmd->pid, dcb->target_id, + srb->cmd->serial_number, dcb->target_id, dcb->target_lun, rsel_tar_lun_id, DC395x_read16(acb, TRM_S1040_SCSI_STATUS)); arblostflag = 1; @@ -3318,7 +3318,7 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, enum dma_data_direction dir = cmd->sc_data_direction; int ckc_only = 1; - dprintkdbg(DBG_1, "srb_done: (pid#%li) <%02i-%i>\n", srb->cmd->pid, + dprintkdbg(DBG_1, "srb_done: (pid#%li) <%02i-%i>\n", srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun); dprintkdbg(DBG_SG, "srb_done: srb=%p sg=%i(%i/%i) buf=%p\n", srb, scsi_sg_count(cmd), srb->sg_index, srb->sg_count, @@ -3499,7 +3499,7 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, if (srb->total_xfer_length) dprintkdbg(DBG_KG, "srb_done: (pid#%li) <%02i-%i> " "cmnd=0x%02x Missed %i bytes\n", - cmd->pid, cmd->device->id, cmd->device->lun, + cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0], srb->total_xfer_length); } @@ -3509,7 +3509,7 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, dprintkl(KERN_ERR, "srb_done: ERROR! Completed cmd with tmp_srb\n"); else { dprintkdbg(DBG_0, "srb_done: (pid#%li) done result=0x%08x\n", - cmd->pid, cmd->result); + cmd->serial_number, cmd->result); srb_free_insert(acb, srb); } pci_unmap_srb(acb, srb); @@ -3538,7 +3538,7 @@ static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag, p = srb->cmd; dir = p->sc_data_direction; result = MK_RES(0, did_flag, 0, 0); - printk("G:%li(%02i-%i) ", p->pid, + printk("G:%li(%02i-%i) ", p->serial_number, p->device->id, p->device->lun); srb_going_remove(dcb, srb); free_tag(dcb, srb); @@ -3568,7 +3568,7 @@ static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag, p = srb->cmd; result = MK_RES(0, did_flag, 0, 0); - printk("W:%li<%02i-%i>", p->pid, p->device->id, + printk("W:%li<%02i-%i>", p->serial_number, p->device->id, p->device->lun); srb_waiting_remove(dcb, srb); srb_free_insert(acb, srb); @@ -3678,7 +3678,7 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, { struct scsi_cmnd *cmd = srb->cmd; dprintkdbg(DBG_1, "request_sense: (pid#%li) <%02i-%i>\n", - cmd->pid, cmd->device->id, cmd->device->lun); + cmd->serial_number, cmd->device->id, cmd->device->lun); srb->flag |= AUTO_REQSENSE; srb->adapter_status = 0; @@ -3709,7 +3709,7 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, if (start_scsi(acb, dcb, srb)) { /* Should only happen, if sb. else grabs the bus */ dprintkl(KERN_DEBUG, "request_sense: (pid#%li) failed <%02i-%i>\n", - srb->cmd->pid, dcb->target_id, dcb->target_lun); + srb->cmd->serial_number, dcb->target_id, dcb->target_lun); srb_going_to_waiting_move(dcb, srb); waiting_set_timer(acb, HZ / 100); } @@ -4717,13 +4717,13 @@ static int dc395x_proc_info(struct Scsi_Host *host, char *buffer, dcb->target_id, dcb->target_lun, list_size(&dcb->srb_waiting_list)); list_for_each_entry(srb, &dcb->srb_waiting_list, list) - SPRINTF(" %li", srb->cmd->pid); + SPRINTF(" %li", srb->cmd->serial_number); if (!list_empty(&dcb->srb_going_list)) SPRINTF("\nDCB (%02i-%i): Going : %i:", dcb->target_id, dcb->target_lun, list_size(&dcb->srb_going_list)); list_for_each_entry(srb, &dcb->srb_going_list, list) - SPRINTF(" %li", srb->cmd->pid); + SPRINTF(" %li", srb->cmd->serial_number); if (!list_empty(&dcb->srb_waiting_list) || !list_empty(&dcb->srb_going_list)) SPRINTF("\n"); } diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index 502732ac270d..bea9d659af15 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -949,16 +949,14 @@ static int adpt_install_hba(struct pci_dev* pDev) } // Allocate and zero the data structure - pHba = kmalloc(sizeof(adpt_hba), GFP_KERNEL); - if( pHba == NULL) { - if(msg_addr_virt != base_addr_virt){ + pHba = kzalloc(sizeof(adpt_hba), GFP_KERNEL); + if (!pHba) { + if (msg_addr_virt != base_addr_virt) iounmap(msg_addr_virt); - } iounmap(base_addr_virt); pci_release_regions(pDev); return -ENOMEM; } - memset(pHba, 0, sizeof(adpt_hba)); mutex_lock(&adpt_configuration_lock); @@ -2622,14 +2620,13 @@ static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba) msg=(u32 __iomem *)(pHba->msg_addr_virt+m); - status = kmalloc(4,GFP_KERNEL|ADDR32); - if (status==NULL) { + status = kzalloc(4, GFP_KERNEL|ADDR32); + if (!status) { adpt_send_nop(pHba, m); printk(KERN_WARNING"%s: IOP reset failed - no free memory.\n", pHba->name); return -ENOMEM; } - memset(status, 0, 4); writel(EIGHT_WORD_MSG_SIZE| SGL_OFFSET_6, &msg[0]); writel(I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID, &msg[1]); @@ -2668,12 +2665,11 @@ static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba) kfree(pHba->reply_pool); - pHba->reply_pool = kmalloc(pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4, GFP_KERNEL|ADDR32); - if(!pHba->reply_pool){ - printk(KERN_ERR"%s: Could not allocate reply pool\n",pHba->name); - return -1; + pHba->reply_pool = kzalloc(pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4, GFP_KERNEL|ADDR32); + if (!pHba->reply_pool) { + printk(KERN_ERR "%s: Could not allocate reply pool\n", pHba->name); + return -ENOMEM; } - memset(pHba->reply_pool, 0 , pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4); ptr = pHba->reply_pool; for(i = 0; i < pHba->reply_fifo_size; i++) { @@ -2884,12 +2880,11 @@ static int adpt_i2o_build_sys_table(void) kfree(sys_tbl); - sys_tbl = kmalloc(sys_tbl_len, GFP_KERNEL|ADDR32); - if(!sys_tbl) { + sys_tbl = kzalloc(sys_tbl_len, GFP_KERNEL|ADDR32); + if (!sys_tbl) { printk(KERN_WARNING "SysTab Set failed. Out of memory.\n"); return -ENOMEM; } - memset(sys_tbl, 0, sys_tbl_len); sys_tbl->num_entries = hba_count; sys_tbl->version = I2OVERSION; @@ -3351,7 +3346,7 @@ static int __init adpt_init(void) return count > 0 ? 0 : -ENODEV; } -static void __exit adpt_exit(void) +static void adpt_exit(void) { while (hba_chain) adpt_release(hba_chain); diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c index 9d52e45c7d36..2596165096d3 100644 --- a/drivers/scsi/dtc.c +++ b/drivers/scsi/dtc.c @@ -137,11 +137,9 @@ static struct override { #ifdef OVERRIDE [] __initdata = OVERRIDE; #else -[4] __initdata = { { -0, IRQ_AUTO}, { -0, IRQ_AUTO}, { -0, IRQ_AUTO}, { -0, IRQ_AUTO}}; +[4] __initdata = { + { 0, IRQ_AUTO }, { 0, IRQ_AUTO }, { 0, IRQ_AUTO }, { 0, IRQ_AUTO } +}; #endif #define NO_OVERRIDES ARRAY_SIZE(overrides) @@ -176,7 +174,7 @@ static const struct signature { * Inputs : str - unused, ints - array of integer parameters with ints[0] * equal to the number of ints. * -*/ + */ static void __init dtc_setup(char *str, int *ints) { @@ -233,7 +231,7 @@ static int __init dtc_detect(struct scsi_host_template * tpnt) } else for (; !addr && (current_base < NO_BASES); ++current_base) { #if (DTCDEBUG & DTCDEBUG_INIT) - printk("scsi-dtc : probing address %08x\n", bases[current_base].address); + printk(KERN_DEBUG "scsi-dtc : probing address %08x\n", bases[current_base].address); #endif if (bases[current_base].noauto) continue; @@ -244,7 +242,7 @@ static int __init dtc_detect(struct scsi_host_template * tpnt) if (check_signature(base + signatures[sig].offset, signatures[sig].string, strlen(signatures[sig].string))) { addr = bases[current_base].address; #if (DTCDEBUG & DTCDEBUG_INIT) - printk("scsi-dtc : detected board.\n"); + printk(KERN_DEBUG "scsi-dtc : detected board.\n"); #endif goto found; } @@ -253,7 +251,7 @@ static int __init dtc_detect(struct scsi_host_template * tpnt) } #if defined(DTCDEBUG) && (DTCDEBUG & DTCDEBUG_INIT) - printk("scsi-dtc : base = %08x\n", addr); + printk(KERN_DEBUG "scsi-dtc : base = %08x\n", addr); #endif if (!addr) diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c index a83e9f150b97..ec2233114bc9 100644 --- a/drivers/scsi/eata.c +++ b/drivers/scsi/eata.c @@ -1758,7 +1758,7 @@ static int eata2x_queuecommand(struct scsi_cmnd *SCpnt, if (SCpnt->host_scribble) panic("%s: qcomm, pid %ld, SCpnt %p already active.\n", - ha->board_name, SCpnt->pid, SCpnt); + ha->board_name, SCpnt->serial_number, SCpnt); /* i is the mailbox number, look for the first free mailbox starting from last_cp_used */ @@ -1792,7 +1792,7 @@ static int eata2x_queuecommand(struct scsi_cmnd *SCpnt, if (do_trace) scmd_printk(KERN_INFO, SCpnt, - "qcomm, mbox %d, pid %ld.\n", i, SCpnt->pid); + "qcomm, mbox %d, pid %ld.\n", i, SCpnt->serial_number); cpp->reqsen = 1; cpp->dispri = 1; @@ -1825,7 +1825,7 @@ static int eata2x_queuecommand(struct scsi_cmnd *SCpnt, unmap_dma(i, ha); SCpnt->host_scribble = NULL; scmd_printk(KERN_INFO, SCpnt, - "qcomm, pid %ld, adapter busy.\n", SCpnt->pid); + "qcomm, pid %ld, adapter busy.\n", SCpnt->serial_number); return 1; } @@ -1841,13 +1841,13 @@ static int eata2x_eh_abort(struct scsi_cmnd *SCarg) if (SCarg->host_scribble == NULL) { scmd_printk(KERN_INFO, SCarg, - "abort, pid %ld inactive.\n", SCarg->pid); + "abort, pid %ld inactive.\n", SCarg->serial_number); return SUCCESS; } i = *(unsigned int *)SCarg->host_scribble; scmd_printk(KERN_WARNING, SCarg, - "abort, mbox %d, pid %ld.\n", i, SCarg->pid); + "abort, mbox %d, pid %ld.\n", i, SCarg->serial_number); if (i >= shost->can_queue) panic("%s: abort, invalid SCarg->host_scribble.\n", ha->board_name); @@ -1892,7 +1892,7 @@ static int eata2x_eh_abort(struct scsi_cmnd *SCarg) SCarg->host_scribble = NULL; ha->cp_stat[i] = FREE; printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n", - ha->board_name, i, SCarg->pid); + ha->board_name, i, SCarg->serial_number); SCarg->scsi_done(SCarg); return SUCCESS; } @@ -1909,12 +1909,12 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg) struct hostdata *ha = (struct hostdata *)shost->hostdata; scmd_printk(KERN_INFO, SCarg, - "reset, enter, pid %ld.\n", SCarg->pid); + "reset, enter, pid %ld.\n", SCarg->serial_number); spin_lock_irq(shost->host_lock); if (SCarg->host_scribble == NULL) - printk("%s: reset, pid %ld inactive.\n", ha->board_name, SCarg->pid); + printk("%s: reset, pid %ld inactive.\n", ha->board_name, SCarg->serial_number); if (ha->in_reset) { printk("%s: reset, exit, already in reset.\n", ha->board_name); @@ -1954,13 +1954,13 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg) if (ha->cp_stat[i] == READY || ha->cp_stat[i] == ABORTING) { ha->cp_stat[i] = ABORTING; printk("%s: reset, mbox %d aborting, pid %ld.\n", - ha->board_name, i, SCpnt->pid); + ha->board_name, i, SCpnt->serial_number); } else { ha->cp_stat[i] = IN_RESET; printk("%s: reset, mbox %d in reset, pid %ld.\n", - ha->board_name, i, SCpnt->pid); + ha->board_name, i, SCpnt->serial_number); } if (SCpnt->host_scribble == NULL) @@ -2015,7 +2015,7 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg) printk ("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n", - ha->board_name, i, SCpnt->pid); + ha->board_name, i, SCpnt->serial_number); } else if (ha->cp_stat[i] == ABORTING) { @@ -2029,7 +2029,7 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg) printk ("%s, reset, mbox %d aborting, DID_RESET, pid %ld done.\n", - ha->board_name, i, SCpnt->pid); + ha->board_name, i, SCpnt->serial_number); } else @@ -2043,7 +2043,7 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg) do_trace = 0; if (arg_done) - printk("%s: reset, exit, pid %ld done.\n", ha->board_name, SCarg->pid); + printk("%s: reset, exit, pid %ld done.\n", ha->board_name, SCarg->serial_number); else printk("%s: reset, exit.\n", ha->board_name); @@ -2182,7 +2182,7 @@ static int reorder(struct hostdata *ha, unsigned long cursec, cpp = &ha->cp[k]; SCpnt = cpp->SCpnt; ll[n] = SCpnt->request->nr_sectors; - pl[n] = SCpnt->pid; + pl[n] = SCpnt->serial_number; if (!n) continue; @@ -2230,7 +2230,7 @@ static int reorder(struct hostdata *ha, unsigned long cursec, "%s pid %ld mb %d fc %d nr %d sec %ld ns %ld" " cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n", (ihdlr ? "ihdlr" : "qcomm"), - SCpnt->pid, k, flushcount, + SCpnt->serial_number, k, flushcount, n_ready, SCpnt->request->sector, SCpnt->request->nr_sectors, cursec, YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only), @@ -2277,7 +2277,7 @@ static void flush_dev(struct scsi_device *dev, unsigned long cursec, "%s, pid %ld, mbox %d, adapter" " busy, will abort.\n", (ihdlr ? "ihdlr" : "qcomm"), - SCpnt->pid, k); + SCpnt->serial_number, k); ha->cp_stat[k] = ABORTING; continue; } @@ -2391,11 +2391,11 @@ static irqreturn_t ihdlr(int irq, struct Scsi_Host *shost) if (SCpnt->host_scribble == NULL) panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n", ha->board_name, - i, SCpnt->pid, SCpnt); + i, SCpnt->serial_number, SCpnt); if (*(unsigned int *)SCpnt->host_scribble != i) panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n", - ha->board_name, i, SCpnt->pid, + ha->board_name, i, SCpnt->serial_number, *(unsigned int *)SCpnt->host_scribble); sync_dma(i, ha); @@ -2445,12 +2445,12 @@ static irqreturn_t ihdlr(int irq, struct Scsi_Host *shost) "target_status 0x%x, sense key 0x%x.\n", ha->board_name, SCpnt->device->channel, SCpnt->device->id, - SCpnt->device->lun, SCpnt->pid, + SCpnt->device->lun, SCpnt->serial_number, spp->target_status, SCpnt->sense_buffer[2]); ha->target_to[SCpnt->device->id][SCpnt->device->channel] = 0; - if (ha->last_retried_pid == SCpnt->pid) + if (ha->last_retried_pid == SCpnt->serial_number) ha->retries = 0; break; @@ -2485,7 +2485,7 @@ static irqreturn_t ihdlr(int irq, struct Scsi_Host *shost) #endif ha->retries++; - ha->last_retried_pid = SCpnt->pid; + ha->last_retried_pid = SCpnt->serial_number; } else status = DID_ERROR << 16; @@ -2516,7 +2516,7 @@ static irqreturn_t ihdlr(int irq, struct Scsi_Host *shost) scmd_printk(KERN_INFO, SCpnt, "ihdlr, mbox %2d, err 0x%x:%x," " pid %ld, reg 0x%x, count %d.\n", i, spp->adapter_status, spp->target_status, - SCpnt->pid, reg, ha->iocount); + SCpnt->serial_number, reg, ha->iocount); unmap_dma(i, ha); diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c index f33ad01064a9..96180bb47e41 100644 --- a/drivers/scsi/eata_pio.c +++ b/drivers/scsi/eata_pio.c @@ -107,59 +107,44 @@ static struct scsi_host_template driver_template; static int eata_pio_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset, int length, int rw) { - static u8 buff[512]; - int size, len = 0; - off_t begin = 0, pos = 0; + int len = 0; + off_t begin = 0, pos = 0; - if (rw) - return -ENOSYS; - if (offset == 0) - memset(buff, 0, sizeof(buff)); + if (rw) + return -ENOSYS; - size = sprintf(buffer+len, "EATA (Extended Attachment) PIO driver version: " + len += sprintf(buffer+len, "EATA (Extended Attachment) PIO driver version: " "%d.%d%s\n",VER_MAJOR, VER_MINOR, VER_SUB); - len += size; pos = begin + len; - size = sprintf(buffer + len, "queued commands: %10ld\n" + len += sprintf(buffer + len, "queued commands: %10ld\n" "processed interrupts:%10ld\n", queue_counter, int_counter); - len += size; pos = begin + len; - - size = sprintf(buffer + len, "\nscsi%-2d: HBA %.10s\n", + len += sprintf(buffer + len, "\nscsi%-2d: HBA %.10s\n", shost->host_no, SD(shost)->name); - len += size; - pos = begin + len; - size = sprintf(buffer + len, "Firmware revision: v%s\n", + len += sprintf(buffer + len, "Firmware revision: v%s\n", SD(shost)->revision); - len += size; - pos = begin + len; - size = sprintf(buffer + len, "IO: PIO\n"); - len += size; - pos = begin + len; - size = sprintf(buffer + len, "Base IO : %#.4x\n", (u32) shost->base); - len += size; - pos = begin + len; - size = sprintf(buffer + len, "Host Bus: %s\n", + len += sprintf(buffer + len, "IO: PIO\n"); + len += sprintf(buffer + len, "Base IO : %#.4x\n", (u32) shost->base); + len += sprintf(buffer + len, "Host Bus: %s\n", (SD(shost)->bustype == 'P')?"PCI ": (SD(shost)->bustype == 'E')?"EISA":"ISA "); - len += size; - pos = begin + len; + pos = begin + len; - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset + length) - goto stop_output; + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > offset + length) + goto stop_output; - stop_output: - DBG(DBG_PROC, printk("2pos: %ld offset: %ld len: %d\n", pos, offset, len)); - *start=buffer+(offset-begin); /* Start of wanted data */ - len-=(offset-begin); /* Start slop */ - if(len>length) - len = length; /* Ending slop */ - DBG(DBG_PROC, printk("3pos: %ld offset: %ld len: %d\n", pos, offset, len)); +stop_output: + DBG(DBG_PROC, printk("2pos: %ld offset: %ld len: %d\n", pos, offset, len)); + *start = buffer + (offset - begin); /* Start of wanted data */ + len -= (offset - begin); /* Start slop */ + if (len > length) + len = length; /* Ending slop */ + DBG(DBG_PROC, printk("3pos: %ld offset: %ld len: %d\n", pos, offset, len)); - return (len); + return len; } static int eata_pio_release(struct Scsi_Host *sh) @@ -390,7 +375,7 @@ static int eata_pio_queue(struct scsi_cmnd *cmd, DBG(DBG_QUEUE, scmd_printk(KERN_DEBUG, cmd, "eata_pio_queue pid %ld, y %d\n", - cmd->pid, y)); + cmd->serial_number, y)); cmd->scsi_done = (void *) done; @@ -435,10 +420,10 @@ static int eata_pio_queue(struct scsi_cmnd *cmd, cmd->result = DID_BUS_BUSY << 16; scmd_printk(KERN_NOTICE, cmd, "eata_pio_queue pid %ld, HBA busy, " - "returning DID_BUS_BUSY, done.\n", cmd->pid); + "returning DID_BUS_BUSY, done.\n", cmd->serial_number); done(cmd); cp->status = FREE; - return (0); + return 0; } /* FIXME: timeout */ while (!(inb(base + HA_RSTATUS) & HA_SDRQ)) @@ -450,9 +435,9 @@ static int eata_pio_queue(struct scsi_cmnd *cmd, DBG(DBG_QUEUE, scmd_printk(KERN_DEBUG, cmd, "Queued base %#.4lx pid: %ld " - "slot %d irq %d\n", sh->base, cmd->pid, y, sh->irq)); + "slot %d irq %d\n", sh->base, cmd->serial_number, y, sh->irq)); - return (0); + return 0; } static int eata_pio_abort(struct scsi_cmnd *cmd) @@ -461,7 +446,7 @@ static int eata_pio_abort(struct scsi_cmnd *cmd) DBG(DBG_ABNORM, scmd_printk(KERN_WARNING, cmd, "eata_pio_abort called pid: %ld\n", - cmd->pid)); + cmd->serial_number)); while (inb(cmd->device->host->base + HA_RAUXSTAT) & HA_ABUSY) if (--loop == 0) { @@ -497,7 +482,7 @@ static int eata_pio_host_reset(struct scsi_cmnd *cmd) DBG(DBG_ABNORM, scmd_printk(KERN_WARNING, cmd, "eata_pio_reset called pid:%ld\n", - cmd->pid)); + cmd->serial_number)); spin_lock_irq(host->host_lock); @@ -516,7 +501,7 @@ static int eata_pio_host_reset(struct scsi_cmnd *cmd) sp = HD(cmd)->ccb[x].cmd; HD(cmd)->ccb[x].status = RESET; - printk(KERN_WARNING "eata_pio_reset: slot %d in reset, pid %ld.\n", x, sp->pid); + printk(KERN_WARNING "eata_pio_reset: slot %d in reset, pid %ld.\n", x, sp->serial_number); if (sp == NULL) panic("eata_pio_reset: slot %d, sp==NULL.\n", x); @@ -589,23 +574,28 @@ static char *get_pio_board_data(unsigned long base, unsigned int irq, unsigned i cp.cp_cdb[5] = 0; if (eata_pio_send_command(base, EATA_CMD_PIO_SEND_CP)) - return (NULL); - while (!(inb(base + HA_RSTATUS) & HA_SDRQ)); + return NULL; + + while (!(inb(base + HA_RSTATUS) & HA_SDRQ)) + cpu_relax(); + outsw(base + HA_RDATA, &cp, cplen); outb(EATA_CMD_PIO_TRUNC, base + HA_WCOMMAND); for (z = 0; z < cppadlen; z++) outw(0, base + HA_RDATA); - while (inb(base + HA_RSTATUS) & HA_SBUSY); + while (inb(base + HA_RSTATUS) & HA_SBUSY) + cpu_relax(); + if (inb(base + HA_RSTATUS) & HA_SERROR) - return (NULL); + return NULL; else if (!(inb(base + HA_RSTATUS) & HA_SDRQ)) - return (NULL); + return NULL; else { insw(base + HA_RDATA, &buff, 127); while (inb(base + HA_RSTATUS) & HA_SDRQ) inw(base + HA_RDATA); - return (buff); + return buff; } } diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index 95cf7b6cd622..4ed3a5297066 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c @@ -2138,7 +2138,7 @@ irqreturn_t scsi_esp_intr(int irq, void *dev_id) } EXPORT_SYMBOL(scsi_esp_intr); -static void __devinit esp_get_revision(struct esp *esp) +static void esp_get_revision(struct esp *esp) { u8 val; @@ -2187,7 +2187,7 @@ static void __devinit esp_get_revision(struct esp *esp) } } -static void __devinit esp_init_swstate(struct esp *esp) +static void esp_init_swstate(struct esp *esp) { int i; @@ -2233,7 +2233,7 @@ static void esp_bootup_reset(struct esp *esp) esp_read8(ESP_INTRPT); } -static void __devinit esp_set_clock_params(struct esp *esp) +static void esp_set_clock_params(struct esp *esp) { int fmhz; u8 ccf; @@ -2306,7 +2306,7 @@ static const char *esp_chip_names[] = { static struct scsi_transport_template *esp_transport_template; -int __devinit scsi_esp_register(struct esp *esp, struct device *dev) +int scsi_esp_register(struct esp *esp, struct device *dev) { static int instance; int err; @@ -2346,7 +2346,7 @@ int __devinit scsi_esp_register(struct esp *esp, struct device *dev) } EXPORT_SYMBOL(scsi_esp_register); -void __devexit scsi_esp_unregister(struct esp *esp) +void scsi_esp_unregister(struct esp *esp) { scsi_remove_host(esp->host); } diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c index 36169d597e98..5d282e6a6ae1 100644 --- a/drivers/scsi/fdomain.c +++ b/drivers/scsi/fdomain.c @@ -387,7 +387,9 @@ static void __iomem * bios_mem; static int bios_major; static int bios_minor; static int PCI_bus; +#ifdef CONFIG_PCI static struct pci_dev *PCI_dev; +#endif static int Quantum; /* Quantum board variant */ static int interrupt_level; static volatile int in_command; @@ -1764,6 +1766,7 @@ struct scsi_host_template fdomain_driver_template = { }; #ifndef PCMCIA +#ifdef CONFIG_PCI static struct pci_device_id fdomain_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70, @@ -1771,7 +1774,7 @@ static struct pci_device_id fdomain_pci_tbl[] __devinitdata = { { } }; MODULE_DEVICE_TABLE(pci, fdomain_pci_tbl); - +#endif #define driver_template fdomain_driver_template #include "scsi_module.c" diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c index 880f70d24e65..607336f56d55 100644 --- a/drivers/scsi/g_NCR5380.c +++ b/drivers/scsi/g_NCR5380.c @@ -556,7 +556,7 @@ generic_NCR5380_biosparam(struct scsi_device *sdev, struct block_device *bdev, } #endif -#if NCR53C400_PSEUDO_DMA +#ifdef NCR53C400_PSEUDO_DMA /** * NCR5380_pread - pseudo DMA read diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index 55e4d2dc2bbe..3ac080ee6e2f 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -27,280 +27,8 @@ * along with this kernel; if not, write to the Free Software * * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * * - * Linux kernel 2.4.x, 2.6.x supported * + * Linux kernel 2.6.x supported * * * - * $Log: gdth.c,v $ - * Revision 1.74 2006/04/10 13:44:47 achim - * Community changes for 2.6.x - * Kernel 2.2.x no longer supported - * scsi_request interface removed, thanks to Christoph Hellwig - * - * Revision 1.73 2004/03/31 13:33:03 achim - * Special command 0xfd implemented to detect 64-bit DMA support - * - * Revision 1.72 2004/03/17 08:56:04 achim - * 64-bit DMA only enabled if FW >= x.43 - * - * Revision 1.71 2004/03/05 15:51:29 achim - * Screen service: separate message buffer, bugfixes - * - * Revision 1.70 2004/02/27 12:19:07 achim - * Bugfix: Reset bit in config (0xfe) call removed - * - * Revision 1.69 2004/02/20 09:50:24 achim - * Compatibility changes for kernels < 2.4.20 - * Bugfix screen service command size - * pci_set_dma_mask() error handling added - * - * Revision 1.68 2004/02/19 15:46:54 achim - * 64-bit DMA bugfixes - * Drive size bugfix for drives > 1TB - * - * Revision 1.67 2004/01/14 13:11:57 achim - * Tool access over /proc no longer supported - * Bugfixes IOCTLs - * - * Revision 1.66 2003/12/19 15:04:06 achim - * Bugfixes support for drives > 2TB - * - * Revision 1.65 2003/12/15 11:21:56 achim - * 64-bit DMA support added - * Support for drives > 2 TB implemented - * Kernels 2.2.x, 2.4.x, 2.6.x supported - * - * Revision 1.64 2003/09/17 08:30:26 achim - * EISA/ISA controller scan disabled - * Command line switch probe_eisa_isa added - * - * Revision 1.63 2003/07/12 14:01:00 Daniele Bellucci <bellucda@tiscali.it> - * Minor cleanups in gdth_ioctl. - * - * Revision 1.62 2003/02/27 15:01:59 achim - * Dynamic DMA mapping implemented - * New (character device) IOCTL interface added - * Other controller related changes made - * - * Revision 1.61 2002/11/08 13:09:52 boji - * Added support for XSCALE based RAID Controllers - * Fixed SCREENSERVICE initialization in SMP cases - * Added checks for gdth_polling before GDTH_HA_LOCK - * - * Revision 1.60 2002/02/05 09:35:22 achim - * MODULE_LICENSE only if kernel >= 2.4.11 - * - * Revision 1.59 2002/01/30 09:46:33 achim - * Small changes - * - * Revision 1.58 2002/01/29 15:30:02 achim - * Set default value of shared_access to Y - * New status S_CACHE_RESERV for clustering added - * - * Revision 1.57 2001/08/21 11:16:35 achim - * Bugfix free_irq() - * - * Revision 1.56 2001/08/09 11:19:39 achim - * Scsi_Host_Template changes - * - * Revision 1.55 2001/08/09 10:11:28 achim - * Command HOST_UNFREEZE_IO before cache service init. - * - * Revision 1.54 2001/07/20 13:48:12 achim - * Expand: gdth_analyse_hdrive() removed - * - * Revision 1.53 2001/07/17 09:52:49 achim - * Small OEM related change - * - * Revision 1.52 2001/06/19 15:06:20 achim - * New host command GDT_UNFREEZE_IO added - * - * Revision 1.51 2001/05/22 06:42:37 achim - * PCI: Subdevice ID added - * - * Revision 1.50 2001/05/17 13:42:16 achim - * Support for Intel Storage RAID Controllers added - * - * Revision 1.50 2001/05/17 12:12:34 achim - * Support for Intel Storage RAID Controllers added - * - * Revision 1.49 2001/03/15 15:07:17 achim - * New __setup interface for boot command line options added - * - * Revision 1.48 2001/02/06 12:36:28 achim - * Bugfix Cluster protocol - * - * Revision 1.47 2001/01/10 14:42:06 achim - * New switch shared_access added - * - * Revision 1.46 2001/01/09 08:11:35 achim - * gdth_command() removed - * meaning of Scsi_Pointer members changed - * - * Revision 1.45 2000/11/16 12:02:24 achim - * Changes for kernel 2.4 - * - * Revision 1.44 2000/10/11 08:44:10 achim - * Clustering changes: New flag media_changed added - * - * Revision 1.43 2000/09/20 12:59:01 achim - * DPMEM remap functions for all PCI controller types implemented - * Small changes for ia64 platform - * - * Revision 1.42 2000/07/20 09:04:50 achim - * Small changes for kernel 2.4 - * - * Revision 1.41 2000/07/04 14:11:11 achim - * gdth_analyse_hdrive() added to rescan drives after online expansion - * - * Revision 1.40 2000/06/27 11:24:16 achim - * Changes Clustering, Screenservice - * - * Revision 1.39 2000/06/15 13:09:04 achim - * Changes for gdth_do_cmd() - * - * Revision 1.38 2000/06/15 12:08:43 achim - * Bugfix gdth_sync_event(), service SCREENSERVICE - * Data direction for command 0xc2 changed to DOU - * - * Revision 1.37 2000/05/25 13:50:10 achim - * New driver parameter virt_ctr added - * - * Revision 1.36 2000/05/04 08:50:46 achim - * Event buffer now in gdth_ha_str - * - * Revision 1.35 2000/03/03 10:44:08 achim - * New event_string only valid for the RP controller family - * - * Revision 1.34 2000/03/02 14:55:29 achim - * New mechanism for async. event handling implemented - * - * Revision 1.33 2000/02/21 15:37:37 achim - * Bugfix Alpha platform + DPMEM above 4GB - * - * Revision 1.32 2000/02/14 16:17:37 achim - * Bugfix sense_buffer[] + raw devices - * - * Revision 1.31 2000/02/10 10:29:00 achim - * Delete sense_buffer[0], if command OK - * - * Revision 1.30 1999/11/02 13:42:39 achim - * ARRAY_DRV_LIST2 implemented - * Now 255 log. and 100 host drives supported - * - * Revision 1.29 1999/10/05 13:28:47 achim - * GDT_CLUST_RESET added - * - * Revision 1.28 1999/08/12 13:44:54 achim - * MOUNTALL removed - * Cluster drives -> removeable drives - * - * Revision 1.27 1999/06/22 07:22:38 achim - * Small changes - * - * Revision 1.26 1999/06/10 16:09:12 achim - * Cluster Host Drive support: Bugfixes - * - * Revision 1.25 1999/06/01 16:03:56 achim - * gdth_init_pci(): Manipulate config. space to start RP controller - * - * Revision 1.24 1999/05/26 11:53:06 achim - * Cluster Host Drive support added - * - * Revision 1.23 1999/03/26 09:12:31 achim - * Default value for hdr_channel set to 0 - * - * Revision 1.22 1999/03/22 16:27:16 achim - * Bugfix: gdth_store_event() must not be locked with GDTH_LOCK_HA() - * - * Revision 1.21 1999/03/16 13:40:34 achim - * Problems with reserved drives solved - * gdth_eh_bus_reset() implemented - * - * Revision 1.20 1999/03/10 09:08:13 achim - * Bugfix: Corrections in gdth_direction_tab[] made - * Bugfix: Increase command timeout (gdth_update_timeout()) NOT in gdth_putq() - * - * Revision 1.19 1999/03/05 14:38:16 achim - * Bugfix: Heads/Sectors mapping for reserved devices possibly wrong - * -> gdth_eval_mapping() implemented, changes in gdth_bios_param() - * INIT_RETRIES set to 100s to avoid DEINIT-Timeout for controllers - * with BIOS disabled and memory test set to Intensive - * Enhanced /proc support - * - * Revision 1.18 1999/02/24 09:54:33 achim - * Command line parameter hdr_channel implemented - * Bugfix for EISA controllers + Linux 2.2.x - * - * Revision 1.17 1998/12/17 15:58:11 achim - * Command line parameters implemented - * Changes for Alpha platforms - * PCI controller scan changed - * SMP support improved (spin_lock_irqsave(),...) - * New async. events, new scan/reserve commands included - * - * Revision 1.16 1998/09/28 16:08:46 achim - * GDT_PCIMPR: DPMEM remapping, if required - * mdelay() added - * - * Revision 1.15 1998/06/03 14:54:06 achim - * gdth_delay(), gdth_flush() implemented - * Bugfix: gdth_release() changed - * - * Revision 1.14 1998/05/22 10:01:17 achim - * mj: pcibios_strerror() removed - * Improved SMP support (if version >= 2.1.95) - * gdth_halt(): halt_called flag added (if version < 2.1) - * - * Revision 1.13 1998/04/16 09:14:57 achim - * Reserve drives (for raw service) implemented - * New error handling code enabled - * Get controller name from board_info() IOCTL - * Final round of PCI device driver patches by Martin Mares - * - * Revision 1.12 1998/03/03 09:32:37 achim - * Fibre channel controller support added - * - * Revision 1.11 1998/01/27 16:19:14 achim - * SA_SHIRQ added - * add_timer()/del_timer() instead of GDTH_TIMER - * scsi_add_timer()/scsi_del_timer() instead of SCSI_TIMER - * New error handling included - * - * Revision 1.10 1997/10/31 12:29:57 achim - * Read heads/sectors from host drive - * - * Revision 1.9 1997/09/04 10:07:25 achim - * IO-mapping with virt_to_bus(), gdth_readb(), gdth_writeb(), ... - * register_reboot_notifier() to get a notify on shutown used - * - * Revision 1.8 1997/04/02 12:14:30 achim - * Version 1.00 (see gdth.h), tested with kernel 2.0.29 - * - * Revision 1.7 1997/03/12 13:33:37 achim - * gdth_reset() changed, new async. events - * - * Revision 1.6 1997/03/04 14:01:11 achim - * Shutdown routine gdth_halt() implemented - * - * Revision 1.5 1997/02/21 09:08:36 achim - * New controller included (RP, RP1, RP2 series) - * IOCTL interface implemented - * - * Revision 1.4 1996/07/05 12:48:55 achim - * Function gdth_bios_param() implemented - * New constant GDTH_MAXC_P_L inserted - * GDT_WRITE_THR, GDT_EXT_INFO implemented - * Function gdth_reset() changed - * - * Revision 1.3 1996/05/10 09:04:41 achim - * Small changes for Linux 1.2.13 - * - * Revision 1.2 1996/05/09 12:45:27 achim - * Loadable module support implemented - * /proc support corrections made - * - * Revision 1.1 1996/04/11 07:35:57 achim - * Initial revision - * ************************************************************************/ /* All GDT Disk Array Controllers are fully supported by this driver. @@ -328,8 +56,6 @@ * max_ids:x x - target ID count per channel (1..MAXID) * rescan:Y rescan all channels/IDs * rescan:N use all devices found until now - * virt_ctr:Y map every channel to a virtual controller - * virt_ctr:N use multi channel support * hdr_channel:x x - number of virtual bus for host drives * shared_access:Y disable driver reserve/release protocol to * access a shared resource from several nodes, @@ -341,7 +67,7 @@ * force_dma32:N use 64 bit DMA mode, if supported * * The default values are: "gdth=disable:N,reserve_mode:1,reverse_scan:N, - * max_ids:127,rescan:N,virt_ctr:N,hdr_channel:0, + * max_ids:127,rescan:N,hdr_channel:0, * shared_access:Y,probe_eisa_isa:N,force_dma32:N". * Here is another example: "gdth=reserve_list:0,1,2,0,0,1,3,0,rescan:Y". * @@ -352,22 +78,22 @@ * '1' in place of 'Y' and '0' in place of 'N'. * * Default: "modprobe gdth disable=0 reserve_mode=1 reverse_scan=0 - * max_ids=127 rescan=0 virt_ctr=0 hdr_channel=0 shared_access=0 + * max_ids=127 rescan=0 hdr_channel=0 shared_access=0 * probe_eisa_isa=0 force_dma32=0" * The other example: "modprobe gdth reserve_list=0,1,2,0,0,1,3,0 rescan=1". */ /* The meaning of the Scsi_Pointer members in this driver is as follows: * ptr: Chaining - * this_residual: Command priority - * buffer: phys. DMA sense buffer - * dma_handle: phys. DMA buffer (kernel >= 2.4.0) - * buffers_residual: Timeout value - * Status: Command status (gdth_do_cmd()), DMA mem. mappings - * Message: Additional info (gdth_do_cmd()), DMA direction - * have_data_in: Flag for gdth_wait_completion() - * sent_command: Opcode special command - * phase: Service/parameter/return code special command + * this_residual: gdth_bufflen + * buffer: gdth_sglist + * dma_handle: unused + * buffers_residual: gdth_sg_count + * Status: unused + * Message: unused + * have_data_in: unused + * sent_command: unused + * phase: unused */ @@ -392,12 +118,8 @@ #include <linux/proc_fs.h> #include <linux/time.h> #include <linux/timer.h> -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,6) #include <linux/dma-mapping.h> -#else -#define DMA_32BIT_MASK 0x00000000ffffffffULL -#define DMA_64BIT_MASK 0xffffffffffffffffULL -#endif +#include <linux/list.h> #ifdef GDTH_RTC #include <linux/mc146818rtc.h> @@ -409,29 +131,27 @@ #include <asm/io.h> #include <asm/uaccess.h> #include <linux/spinlock.h> -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) #include <linux/blkdev.h> -#else -#include <linux/blk.h> -#include "sd.h" -#endif +#include <linux/scatterlist.h> #include "scsi.h" #include <scsi/scsi_host.h> -#include "gdth_kcompat.h" #include "gdth.h" static void gdth_delay(int milliseconds); static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs); static irqreturn_t gdth_interrupt(int irq, void *dev_id); -static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp); -static int gdth_async_event(int hanum); +static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq, + int gdth_from_wait, int* pIndex); +static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index, + Scsi_Cmnd *scp); +static int gdth_async_event(gdth_ha_str *ha); static void gdth_log_event(gdth_evt_data *dvr, char *buffer); -static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority); -static void gdth_next(int hanum); -static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b); -static int gdth_special_cmd(int hanum,Scsi_Cmnd *scp); +static void gdth_putq(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar priority); +static void gdth_next(gdth_ha_str *ha); +static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b); +static int gdth_special_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp); static gdth_evt_str *gdth_store_event(gdth_ha_str *ha, ushort source, ushort idx, gdth_evt_data *evt); static int gdth_read_event(gdth_ha_str *ha, int handle, gdth_evt_str *estr); @@ -439,42 +159,34 @@ static void gdth_readapp_event(gdth_ha_str *ha, unchar application, gdth_evt_str *estr); static void gdth_clear_events(void); -static void gdth_copy_internal_data(int hanum,Scsi_Cmnd *scp, - char *buffer,ushort count); -static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp); -static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive); +static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp, + char *buffer, ushort count, int to_buffer); +static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp); +static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive); -static int gdth_search_eisa(ushort eisa_adr); -static int gdth_search_isa(ulong32 bios_adr); -static int gdth_search_pci(gdth_pci_str *pcistr); -static void gdth_search_dev(gdth_pci_str *pcistr, ushort *cnt, - ushort vendor, ushort dev); -static void gdth_sort_pci(gdth_pci_str *pcistr, int cnt); -static int gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha); -static int gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha); -static int gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha); - -static void gdth_enable_int(int hanum); -static int gdth_get_status(unchar *pIStatus,int irq); -static int gdth_test_busy(int hanum); -static int gdth_get_cmd_index(int hanum); -static void gdth_release_event(int hanum); -static int gdth_wait(int hanum,int index,ulong32 time); -static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1, - ulong64 p2,ulong64 p3); -static int gdth_search_drives(int hanum); -static int gdth_analyse_hdrive(int hanum, ushort hdrive); - -static const char *gdth_ctr_name(int hanum); +static void gdth_enable_int(gdth_ha_str *ha); +static unchar gdth_get_status(gdth_ha_str *ha, int irq); +static int gdth_test_busy(gdth_ha_str *ha); +static int gdth_get_cmd_index(gdth_ha_str *ha); +static void gdth_release_event(gdth_ha_str *ha); +static int gdth_wait(gdth_ha_str *ha, int index,ulong32 time); +static int gdth_internal_cmd(gdth_ha_str *ha, unchar service, ushort opcode, + ulong32 p1, ulong64 p2,ulong64 p3); +static int gdth_search_drives(gdth_ha_str *ha); +static int gdth_analyse_hdrive(gdth_ha_str *ha, ushort hdrive); + +static const char *gdth_ctr_name(gdth_ha_str *ha); static int gdth_open(struct inode *inode, struct file *filep); static int gdth_close(struct inode *inode, struct file *filep); static int gdth_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg); -static void gdth_flush(int hanum); +static void gdth_flush(gdth_ha_str *ha); static int gdth_halt(struct notifier_block *nb, ulong event, void *buf); static int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *)); +static int __gdth_queuecommand(gdth_ha_str *ha, struct scsi_cmnd *scp, + struct gdth_cmndinfo *cmndinfo); static void gdth_scsi_done(struct scsi_cmnd *scp); #ifdef DEBUG_GDTH @@ -571,29 +283,17 @@ static struct timer_list gdth_timer; #define GDTOFFSOF(a,b) (size_t)&(((a*)0)->b) #define INDEX_OK(i,t) ((i)<ARRAY_SIZE(t)) -#define NUMDATA(a) ( (gdth_num_str *)((a)->hostdata)) -#define HADATA(a) (&((gdth_ext_str *)((a)->hostdata))->haext) -#define CMDDATA(a) (&((gdth_ext_str *)((a)->hostdata))->cmdext) - #define BUS_L2P(a,b) ((b)>(a)->virt_bus ? (b-1):(b)) -#define gdth_readb(addr) readb(addr) -#define gdth_readw(addr) readw(addr) -#define gdth_readl(addr) readl(addr) -#define gdth_writeb(b,addr) writeb((b),(addr)) -#define gdth_writew(b,addr) writew((b),(addr)) -#define gdth_writel(b,addr) writel((b),(addr)) - +#ifdef CONFIG_ISA static unchar gdth_drq_tab[4] = {5,6,7,7}; /* DRQ table */ +#endif +#if defined(CONFIG_EISA) || defined(CONFIG_ISA) static unchar gdth_irq_tab[6] = {0,10,11,12,14,0}; /* IRQ table */ +#endif static unchar gdth_polling; /* polling if TRUE */ -static unchar gdth_from_wait = FALSE; /* gdth_wait() */ -static int wait_index,wait_hanum; /* gdth_wait() */ static int gdth_ctr_count = 0; /* controller count */ -static int gdth_ctr_vcount = 0; /* virt. ctr. count */ -static int gdth_ctr_released = 0; /* gdth_release() */ -static struct Scsi_Host *gdth_ctr_tab[MAXHA]; /* controller table */ -static struct Scsi_Host *gdth_ctr_vtab[MAXHA*MAXBUS]; /* virt. ctr. table */ +static LIST_HEAD(gdth_instances); /* controller list */ static unchar gdth_write_through = FALSE; /* write through */ static gdth_evt_str ebuffer[MAX_EVENTS]; /* event buffer */ static int elastidx; @@ -645,8 +345,6 @@ static int hdr_channel = 0; static int max_ids = MAXID; /* rescan all IDs */ static int rescan = 0; -/* map channels to virtual controllers */ -static int virt_ctr = 0; /* shared access */ static int shared_access = 1; /* enable support for EISA and ISA controllers */ @@ -655,7 +353,6 @@ static int probe_eisa_isa = 0; static int force_dma32 = 0; /* parameters for modprobe/insmod */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11) module_param_array(irq, int, NULL, 0); module_param(disable, int, 0); module_param(reserve_mode, int, 0); @@ -664,24 +361,9 @@ module_param(reverse_scan, int, 0); module_param(hdr_channel, int, 0); module_param(max_ids, int, 0); module_param(rescan, int, 0); -module_param(virt_ctr, int, 0); module_param(shared_access, int, 0); module_param(probe_eisa_isa, int, 0); module_param(force_dma32, int, 0); -#else -MODULE_PARM(irq, "i"); -MODULE_PARM(disable, "i"); -MODULE_PARM(reserve_mode, "i"); -MODULE_PARM(reserve_list, "4-" __MODULE_STRING(MAX_RES_ARGS) "i"); -MODULE_PARM(reverse_scan, "i"); -MODULE_PARM(hdr_channel, "i"); -MODULE_PARM(max_ids, "i"); -MODULE_PARM(rescan, "i"); -MODULE_PARM(virt_ctr, "i"); -MODULE_PARM(shared_access, "i"); -MODULE_PARM(probe_eisa_isa, "i"); -MODULE_PARM(force_dma32, "i"); -#endif MODULE_AUTHOR("Achim Leubner"); MODULE_LICENSE("GPL"); @@ -692,6 +374,47 @@ static const struct file_operations gdth_fops = { .release = gdth_close, }; +/* + * gdth scsi_command access wrappers. + * below 6 functions are used throughout the driver to access scsi_command's + * io parameters. The reason we do not use the regular accessors from + * scsi_cmnd.h is because of gdth_execute(). Since it is unrecommended for + * llds to directly set scsi_cmnd's IO members. This driver will use SCp + * members for IO parameters, and will copy scsi_cmnd's members to Scp + * members in queuecommand. For internal commands through gdth_execute() + * SCp's members will be set directly. + */ +static inline unsigned gdth_bufflen(struct scsi_cmnd *cmd) +{ + return (unsigned)cmd->SCp.this_residual; +} + +static inline void gdth_set_bufflen(struct scsi_cmnd *cmd, unsigned bufflen) +{ + cmd->SCp.this_residual = bufflen; +} + +static inline unsigned gdth_sg_count(struct scsi_cmnd *cmd) +{ + return (unsigned)cmd->SCp.buffers_residual; +} + +static inline void gdth_set_sg_count(struct scsi_cmnd *cmd, unsigned sg_count) +{ + cmd->SCp.buffers_residual = sg_count; +} + +static inline struct scatterlist *gdth_sglist(struct scsi_cmnd *cmd) +{ + return cmd->SCp.buffer; +} + +static inline void gdth_set_sglist(struct scsi_cmnd *cmd, + struct scatterlist *sglist) +{ + cmd->SCp.buffer = sglist; +} + #include "gdth_proc.h" #include "gdth_proc.c" @@ -701,6 +424,45 @@ static struct notifier_block gdth_notifier = { }; static int notifier_disabled = 0; +static gdth_ha_str *gdth_find_ha(int hanum) +{ + gdth_ha_str *ha; + + list_for_each_entry(ha, &gdth_instances, list) + if (hanum == ha->hanum) + return ha; + + return NULL; +} + +static struct gdth_cmndinfo *gdth_get_cmndinfo(gdth_ha_str *ha) +{ + struct gdth_cmndinfo *priv = NULL; + ulong flags; + int i; + + spin_lock_irqsave(&ha->smp_lock, flags); + + for (i=0; i<GDTH_MAXCMDS; ++i) { + if (ha->cmndinfo[i].index == 0) { + priv = &ha->cmndinfo[i]; + priv->index = i+1; + memset(priv, 0, sizeof(*priv)); + break; + } + } + + spin_unlock_irqrestore(&ha->smp_lock, flags); + + return priv; +} + +static void gdth_put_cmndinfo(struct gdth_cmndinfo *priv) +{ + BUG_ON(!priv); + priv->index = 0; +} + static void gdth_delay(int milliseconds) { if (milliseconds == 0) { @@ -710,80 +472,62 @@ static void gdth_delay(int milliseconds) } } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) static void gdth_scsi_done(struct scsi_cmnd *scp) { - TRACE2(("gdth_scsi_done()\n")); + struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); + int internal_command = cmndinfo->internal_command; + + TRACE2(("gdth_scsi_done()\n")); - if (scp->request) - complete((struct completion *)scp->request); + gdth_put_cmndinfo(cmndinfo); + scp->host_scribble = NULL; + + if (internal_command) + complete((struct completion *)scp->request); + else + scp->scsi_done(scp); } int __gdth_execute(struct scsi_device *sdev, gdth_cmd_str *gdtcmd, char *cmnd, int timeout, u32 *info) { + gdth_ha_str *ha = shost_priv(sdev->host); Scsi_Cmnd *scp; + struct gdth_cmndinfo cmndinfo; + struct scatterlist one_sg; DECLARE_COMPLETION_ONSTACK(wait); int rval; - scp = kmalloc(sizeof(*scp), GFP_KERNEL); + scp = kzalloc(sizeof(*scp), GFP_KERNEL); if (!scp) return -ENOMEM; - memset(scp, 0, sizeof(*scp)); + scp->device = sdev; + memset(&cmndinfo, 0, sizeof(cmndinfo)); + /* use request field to save the ptr. to completion struct. */ scp->request = (struct request *)&wait; scp->timeout_per_command = timeout*HZ; - scp->request_buffer = gdtcmd; + sg_init_one(&one_sg, gdtcmd, sizeof(*gdtcmd)); + gdth_set_sglist(scp, &one_sg); + gdth_set_sg_count(scp, 1); + gdth_set_bufflen(scp, sizeof(*gdtcmd)); scp->cmd_len = 12; memcpy(scp->cmnd, cmnd, 12); - scp->SCp.this_residual = IOCTL_PRI; /* priority */ - scp->done = gdth_scsi_done; /* some fn. test this */ - gdth_queuecommand(scp, gdth_scsi_done); - wait_for_completion(&wait); - - rval = scp->SCp.Status; - if (info) - *info = scp->SCp.Message; - kfree(scp); - return rval; -} -#else -static void gdth_scsi_done(Scsi_Cmnd *scp) -{ - TRACE2(("gdth_scsi_done()\n")); - - scp->request.rq_status = RQ_SCSI_DONE; - if (scp->request.waiting) - complete(scp->request.waiting); -} + cmndinfo.priority = IOCTL_PRI; + cmndinfo.internal_command = 1; -int __gdth_execute(struct scsi_device *sdev, gdth_cmd_str *gdtcmd, char *cmnd, - int timeout, u32 *info) -{ - Scsi_Cmnd *scp = scsi_allocate_device(sdev, 1, FALSE); - unsigned bufflen = gdtcmd ? sizeof(gdth_cmd_str) : 0; - DECLARE_COMPLETION_ONSTACK(wait); - int rval; + TRACE(("__gdth_execute() cmd 0x%x\n", scp->cmnd[0])); + __gdth_queuecommand(ha, scp, &cmndinfo); - if (!scp) - return -ENOMEM; - scp->cmd_len = 12; - scp->use_sg = 0; - scp->SCp.this_residual = IOCTL_PRI; /* priority */ - scp->request.rq_status = RQ_SCSI_BUSY; - scp->request.waiting = &wait; - scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1); wait_for_completion(&wait); - rval = scp->SCp.Status; + rval = cmndinfo.status; if (info) - *info = scp->SCp.Message; - - scsi_release_command(scp); + *info = cmndinfo.info; + kfree(scp); return rval; } -#endif int gdth_execute(struct Scsi_Host *shost, gdth_cmd_str *gdtcmd, char *cmnd, int timeout, u32 *info) @@ -815,7 +559,7 @@ static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs } /* controller search and initialization functions */ - +#ifdef CONFIG_EISA static int __init gdth_search_eisa(ushort eisa_adr) { ulong32 id; @@ -832,8 +576,9 @@ static int __init gdth_search_eisa(ushort eisa_adr) return 0; } +#endif /* CONFIG_EISA */ - +#ifdef CONFIG_ISA static int __init gdth_search_isa(ulong32 bios_adr) { void __iomem *addr; @@ -841,14 +586,18 @@ static int __init gdth_search_isa(ulong32 bios_adr) TRACE(("gdth_search_isa() bios adr. %x\n",bios_adr)); if ((addr = ioremap(bios_adr+BIOS_ID_OFFS, sizeof(ulong32))) != NULL) { - id = gdth_readl(addr); + id = readl(addr); iounmap(addr); if (id == GDT2_ID) /* GDT2000 */ return 1; } return 0; } +#endif /* CONFIG_ISA */ +#ifdef CONFIG_PCI +static void gdth_search_dev(gdth_pci_str *pcistr, ushort *cnt, + ushort vendor, ushort dev); static int __init gdth_search_pci(gdth_pci_str *pcistr) { @@ -928,7 +677,6 @@ static void __init gdth_search_dev(gdth_pci_str *pcistr, ushort *cnt, } } - static void __init gdth_sort_pci(gdth_pci_str *pcistr, int cnt) { gdth_pci_str temp; @@ -965,8 +713,9 @@ static void __init gdth_sort_pci(gdth_pci_str *pcistr, int cnt) } } while (changed); } +#endif /* CONFIG_PCI */ - +#ifdef CONFIG_EISA static int __init gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha) { ulong32 retries,id; @@ -1058,8 +807,9 @@ static int __init gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha) ha->dma64_support = 0; return 1; } +#endif /* CONFIG_EISA */ - +#ifdef CONFIG_ISA static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha) { register gdt2_dpram_str __iomem *dp2_ptr; @@ -1075,22 +825,22 @@ static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha) return 0; } dp2_ptr = ha->brd; - gdth_writeb(1, &dp2_ptr->io.memlock); /* switch off write protection */ + writeb(1, &dp2_ptr->io.memlock); /* switch off write protection */ /* reset interface area */ memset_io(&dp2_ptr->u, 0, sizeof(dp2_ptr->u)); - if (gdth_readl(&dp2_ptr->u) != 0) { + if (readl(&dp2_ptr->u) != 0) { printk("GDT-ISA: Initialization error (DPMEM write error)\n"); iounmap(ha->brd); return 0; } /* disable board interrupts, read DRQ and IRQ */ - gdth_writeb(0xff, &dp2_ptr->io.irqdel); - gdth_writeb(0x00, &dp2_ptr->io.irqen); - gdth_writeb(0x00, &dp2_ptr->u.ic.S_Status); - gdth_writeb(0x00, &dp2_ptr->u.ic.Cmd_Index); + writeb(0xff, &dp2_ptr->io.irqdel); + writeb(0x00, &dp2_ptr->io.irqen); + writeb(0x00, &dp2_ptr->u.ic.S_Status); + writeb(0x00, &dp2_ptr->u.ic.Cmd_Index); - irq_drq = gdth_readb(&dp2_ptr->io.rq); + irq_drq = readb(&dp2_ptr->io.rq); for (i=0; i<3; ++i) { if ((irq_drq & 1)==0) break; @@ -1098,7 +848,7 @@ static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha) } ha->drq = gdth_drq_tab[i]; - irq_drq = gdth_readb(&dp2_ptr->io.rq) >> 3; + irq_drq = readb(&dp2_ptr->io.rq) >> 3; for (i=1; i<5; ++i) { if ((irq_drq & 1)==0) break; @@ -1107,12 +857,12 @@ static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha) ha->irq = gdth_irq_tab[i]; /* deinitialize services */ - gdth_writel(bios_adr, &dp2_ptr->u.ic.S_Info[0]); - gdth_writeb(0xff, &dp2_ptr->u.ic.S_Cmd_Indx); - gdth_writeb(0, &dp2_ptr->io.event); + writel(bios_adr, &dp2_ptr->u.ic.S_Info[0]); + writeb(0xff, &dp2_ptr->u.ic.S_Cmd_Indx); + writeb(0, &dp2_ptr->io.event); retries = INIT_RETRIES; gdth_delay(20); - while (gdth_readb(&dp2_ptr->u.ic.S_Status) != 0xff) { + while (readb(&dp2_ptr->u.ic.S_Status) != 0xff) { if (--retries == 0) { printk("GDT-ISA: Initialization error (DEINIT failed)\n"); iounmap(ha->brd); @@ -1120,9 +870,9 @@ static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha) } gdth_delay(1); } - prot_ver = (unchar)gdth_readl(&dp2_ptr->u.ic.S_Info[0]); - gdth_writeb(0, &dp2_ptr->u.ic.Status); - gdth_writeb(0xff, &dp2_ptr->io.irqdel); + prot_ver = (unchar)readl(&dp2_ptr->u.ic.S_Info[0]); + writeb(0, &dp2_ptr->u.ic.Status); + writeb(0xff, &dp2_ptr->io.irqdel); if (prot_ver != PROTOCOL_VERSION) { printk("GDT-ISA: Illegal protocol version\n"); iounmap(ha->brd); @@ -1136,15 +886,15 @@ static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha) ha->brd_phys = bios_adr >> 4; /* special request to controller BIOS */ - gdth_writel(0x00, &dp2_ptr->u.ic.S_Info[0]); - gdth_writel(0x00, &dp2_ptr->u.ic.S_Info[1]); - gdth_writel(0x01, &dp2_ptr->u.ic.S_Info[2]); - gdth_writel(0x00, &dp2_ptr->u.ic.S_Info[3]); - gdth_writeb(0xfe, &dp2_ptr->u.ic.S_Cmd_Indx); - gdth_writeb(0, &dp2_ptr->io.event); + writel(0x00, &dp2_ptr->u.ic.S_Info[0]); + writel(0x00, &dp2_ptr->u.ic.S_Info[1]); + writel(0x01, &dp2_ptr->u.ic.S_Info[2]); + writel(0x00, &dp2_ptr->u.ic.S_Info[3]); + writeb(0xfe, &dp2_ptr->u.ic.S_Cmd_Indx); + writeb(0, &dp2_ptr->io.event); retries = INIT_RETRIES; gdth_delay(20); - while (gdth_readb(&dp2_ptr->u.ic.S_Status) != 0xfe) { + while (readb(&dp2_ptr->u.ic.S_Status) != 0xfe) { if (--retries == 0) { printk("GDT-ISA: Initialization error\n"); iounmap(ha->brd); @@ -1152,14 +902,15 @@ static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha) } gdth_delay(1); } - gdth_writeb(0, &dp2_ptr->u.ic.Status); - gdth_writeb(0xff, &dp2_ptr->io.irqdel); + writeb(0, &dp2_ptr->u.ic.Status); + writeb(0xff, &dp2_ptr->io.irqdel); ha->dma64_support = 0; return 1; } +#endif /* CONFIG_ISA */ - +#ifdef CONFIG_PCI static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) { register gdt6_dpram_str __iomem *dp6_ptr; @@ -1190,8 +941,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) } /* check and reset interface area */ dp6_ptr = ha->brd; - gdth_writel(DPMEM_MAGIC, &dp6_ptr->u); - if (gdth_readl(&dp6_ptr->u) != DPMEM_MAGIC) { + writel(DPMEM_MAGIC, &dp6_ptr->u); + if (readl(&dp6_ptr->u) != DPMEM_MAGIC) { printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", pcistr->dpmem); found = FALSE; @@ -1202,7 +953,7 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); return 0; } - if (gdth_readw(ha->brd) != 0xffff) { + if (readw(ha->brd) != 0xffff) { TRACE2(("init_pci_old() address 0x%x busy\n", i)); continue; } @@ -1215,8 +966,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) return 0; } dp6_ptr = ha->brd; - gdth_writel(DPMEM_MAGIC, &dp6_ptr->u); - if (gdth_readl(&dp6_ptr->u) == DPMEM_MAGIC) { + writel(DPMEM_MAGIC, &dp6_ptr->u); + if (readl(&dp6_ptr->u) == DPMEM_MAGIC) { printk("GDT-PCI: Use free address at 0x%x\n", i); found = TRUE; break; @@ -1229,24 +980,24 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) } } memset_io(&dp6_ptr->u, 0, sizeof(dp6_ptr->u)); - if (gdth_readl(&dp6_ptr->u) != 0) { + if (readl(&dp6_ptr->u) != 0) { printk("GDT-PCI: Initialization error (DPMEM write error)\n"); iounmap(ha->brd); return 0; } /* disable board interrupts, deinit services */ - gdth_writeb(0xff, &dp6_ptr->io.irqdel); - gdth_writeb(0x00, &dp6_ptr->io.irqen); - gdth_writeb(0x00, &dp6_ptr->u.ic.S_Status); - gdth_writeb(0x00, &dp6_ptr->u.ic.Cmd_Index); - - gdth_writel(pcistr->dpmem, &dp6_ptr->u.ic.S_Info[0]); - gdth_writeb(0xff, &dp6_ptr->u.ic.S_Cmd_Indx); - gdth_writeb(0, &dp6_ptr->io.event); + writeb(0xff, &dp6_ptr->io.irqdel); + writeb(0x00, &dp6_ptr->io.irqen); + writeb(0x00, &dp6_ptr->u.ic.S_Status); + writeb(0x00, &dp6_ptr->u.ic.Cmd_Index); + + writel(pcistr->dpmem, &dp6_ptr->u.ic.S_Info[0]); + writeb(0xff, &dp6_ptr->u.ic.S_Cmd_Indx); + writeb(0, &dp6_ptr->io.event); retries = INIT_RETRIES; gdth_delay(20); - while (gdth_readb(&dp6_ptr->u.ic.S_Status) != 0xff) { + while (readb(&dp6_ptr->u.ic.S_Status) != 0xff) { if (--retries == 0) { printk("GDT-PCI: Initialization error (DEINIT failed)\n"); iounmap(ha->brd); @@ -1254,9 +1005,9 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) } gdth_delay(1); } - prot_ver = (unchar)gdth_readl(&dp6_ptr->u.ic.S_Info[0]); - gdth_writeb(0, &dp6_ptr->u.ic.S_Status); - gdth_writeb(0xff, &dp6_ptr->io.irqdel); + prot_ver = (unchar)readl(&dp6_ptr->u.ic.S_Info[0]); + writeb(0, &dp6_ptr->u.ic.S_Status); + writeb(0xff, &dp6_ptr->io.irqdel); if (prot_ver != PROTOCOL_VERSION) { printk("GDT-PCI: Illegal protocol version\n"); iounmap(ha->brd); @@ -1267,15 +1018,15 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) ha->ic_all_size = sizeof(dp6_ptr->u); /* special command to controller BIOS */ - gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[0]); - gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[1]); - gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[2]); - gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[3]); - gdth_writeb(0xfe, &dp6_ptr->u.ic.S_Cmd_Indx); - gdth_writeb(0, &dp6_ptr->io.event); + writel(0x00, &dp6_ptr->u.ic.S_Info[0]); + writel(0x00, &dp6_ptr->u.ic.S_Info[1]); + writel(0x00, &dp6_ptr->u.ic.S_Info[2]); + writel(0x00, &dp6_ptr->u.ic.S_Info[3]); + writeb(0xfe, &dp6_ptr->u.ic.S_Cmd_Indx); + writeb(0, &dp6_ptr->io.event); retries = INIT_RETRIES; gdth_delay(20); - while (gdth_readb(&dp6_ptr->u.ic.S_Status) != 0xfe) { + while (readb(&dp6_ptr->u.ic.S_Status) != 0xfe) { if (--retries == 0) { printk("GDT-PCI: Initialization error\n"); iounmap(ha->brd); @@ -1283,8 +1034,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) } gdth_delay(1); } - gdth_writeb(0, &dp6_ptr->u.ic.S_Status); - gdth_writeb(0xff, &dp6_ptr->io.irqdel); + writeb(0, &dp6_ptr->u.ic.S_Status); + writeb(0xff, &dp6_ptr->io.irqdel); ha->dma64_support = 0; @@ -1300,8 +1051,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) } /* check and reset interface area */ dp6c_ptr = ha->brd; - gdth_writel(DPMEM_MAGIC, &dp6c_ptr->u); - if (gdth_readl(&dp6c_ptr->u) != DPMEM_MAGIC) { + writel(DPMEM_MAGIC, &dp6c_ptr->u); + if (readl(&dp6c_ptr->u) != DPMEM_MAGIC) { printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", pcistr->dpmem); found = FALSE; @@ -1312,7 +1063,7 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); return 0; } - if (gdth_readw(ha->brd) != 0xffff) { + if (readw(ha->brd) != 0xffff) { TRACE2(("init_pci_plx() address 0x%x busy\n", i)); continue; } @@ -1325,8 +1076,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) return 0; } dp6c_ptr = ha->brd; - gdth_writel(DPMEM_MAGIC, &dp6c_ptr->u); - if (gdth_readl(&dp6c_ptr->u) == DPMEM_MAGIC) { + writel(DPMEM_MAGIC, &dp6c_ptr->u); + if (readl(&dp6c_ptr->u) == DPMEM_MAGIC) { printk("GDT-PCI: Use free address at 0x%x\n", i); found = TRUE; break; @@ -1339,7 +1090,7 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) } } memset_io(&dp6c_ptr->u, 0, sizeof(dp6c_ptr->u)); - if (gdth_readl(&dp6c_ptr->u) != 0) { + if (readl(&dp6c_ptr->u) != 0) { printk("GDT-PCI: Initialization error (DPMEM write error)\n"); iounmap(ha->brd); return 0; @@ -1349,17 +1100,17 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) outb(0x00,PTR2USHORT(&ha->plx->control1)); outb(0xff,PTR2USHORT(&ha->plx->edoor_reg)); - gdth_writeb(0x00, &dp6c_ptr->u.ic.S_Status); - gdth_writeb(0x00, &dp6c_ptr->u.ic.Cmd_Index); + writeb(0x00, &dp6c_ptr->u.ic.S_Status); + writeb(0x00, &dp6c_ptr->u.ic.Cmd_Index); - gdth_writel(pcistr->dpmem, &dp6c_ptr->u.ic.S_Info[0]); - gdth_writeb(0xff, &dp6c_ptr->u.ic.S_Cmd_Indx); + writel(pcistr->dpmem, &dp6c_ptr->u.ic.S_Info[0]); + writeb(0xff, &dp6c_ptr->u.ic.S_Cmd_Indx); outb(1,PTR2USHORT(&ha->plx->ldoor_reg)); retries = INIT_RETRIES; gdth_delay(20); - while (gdth_readb(&dp6c_ptr->u.ic.S_Status) != 0xff) { + while (readb(&dp6c_ptr->u.ic.S_Status) != 0xff) { if (--retries == 0) { printk("GDT-PCI: Initialization error (DEINIT failed)\n"); iounmap(ha->brd); @@ -1367,8 +1118,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) } gdth_delay(1); } - prot_ver = (unchar)gdth_readl(&dp6c_ptr->u.ic.S_Info[0]); - gdth_writeb(0, &dp6c_ptr->u.ic.Status); + prot_ver = (unchar)readl(&dp6c_ptr->u.ic.S_Info[0]); + writeb(0, &dp6c_ptr->u.ic.Status); if (prot_ver != PROTOCOL_VERSION) { printk("GDT-PCI: Illegal protocol version\n"); iounmap(ha->brd); @@ -1379,17 +1130,17 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) ha->ic_all_size = sizeof(dp6c_ptr->u); /* special command to controller BIOS */ - gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[0]); - gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[1]); - gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[2]); - gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[3]); - gdth_writeb(0xfe, &dp6c_ptr->u.ic.S_Cmd_Indx); + writel(0x00, &dp6c_ptr->u.ic.S_Info[0]); + writel(0x00, &dp6c_ptr->u.ic.S_Info[1]); + writel(0x00, &dp6c_ptr->u.ic.S_Info[2]); + writel(0x00, &dp6c_ptr->u.ic.S_Info[3]); + writeb(0xfe, &dp6c_ptr->u.ic.S_Cmd_Indx); outb(1,PTR2USHORT(&ha->plx->ldoor_reg)); retries = INIT_RETRIES; gdth_delay(20); - while (gdth_readb(&dp6c_ptr->u.ic.S_Status) != 0xfe) { + while (readb(&dp6c_ptr->u.ic.S_Status) != 0xfe) { if (--retries == 0) { printk("GDT-PCI: Initialization error\n"); iounmap(ha->brd); @@ -1397,7 +1148,7 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) } gdth_delay(1); } - gdth_writeb(0, &dp6c_ptr->u.ic.S_Status); + writeb(0, &dp6c_ptr->u.ic.S_Status); ha->dma64_support = 0; @@ -1425,12 +1176,12 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) /* Ensure that it is safe to access the non HW portions of DPMEM. * Aditional check needed for Xscale based RAID controllers */ - while( ((int)gdth_readb(&dp6m_ptr->i960r.sema0_reg) ) & 3 ) + while( ((int)readb(&dp6m_ptr->i960r.sema0_reg) ) & 3 ) gdth_delay(1); /* check and reset interface area */ - gdth_writel(DPMEM_MAGIC, &dp6m_ptr->u); - if (gdth_readl(&dp6m_ptr->u) != DPMEM_MAGIC) { + writel(DPMEM_MAGIC, &dp6m_ptr->u); + if (readl(&dp6m_ptr->u) != DPMEM_MAGIC) { printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", pcistr->dpmem); found = FALSE; @@ -1441,7 +1192,7 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); return 0; } - if (gdth_readw(ha->brd) != 0xffff) { + if (readw(ha->brd) != 0xffff) { TRACE2(("init_pci_mpr() address 0x%x busy\n", i)); continue; } @@ -1454,8 +1205,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) return 0; } dp6m_ptr = ha->brd; - gdth_writel(DPMEM_MAGIC, &dp6m_ptr->u); - if (gdth_readl(&dp6m_ptr->u) == DPMEM_MAGIC) { + writel(DPMEM_MAGIC, &dp6m_ptr->u); + if (readl(&dp6m_ptr->u) == DPMEM_MAGIC) { printk("GDT-PCI: Use free address at 0x%x\n", i); found = TRUE; break; @@ -1470,18 +1221,18 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) memset_io(&dp6m_ptr->u, 0, sizeof(dp6m_ptr->u)); /* disable board interrupts, deinit services */ - gdth_writeb(gdth_readb(&dp6m_ptr->i960r.edoor_en_reg) | 4, + writeb(readb(&dp6m_ptr->i960r.edoor_en_reg) | 4, &dp6m_ptr->i960r.edoor_en_reg); - gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg); - gdth_writeb(0x00, &dp6m_ptr->u.ic.S_Status); - gdth_writeb(0x00, &dp6m_ptr->u.ic.Cmd_Index); + writeb(0xff, &dp6m_ptr->i960r.edoor_reg); + writeb(0x00, &dp6m_ptr->u.ic.S_Status); + writeb(0x00, &dp6m_ptr->u.ic.Cmd_Index); - gdth_writel(pcistr->dpmem, &dp6m_ptr->u.ic.S_Info[0]); - gdth_writeb(0xff, &dp6m_ptr->u.ic.S_Cmd_Indx); - gdth_writeb(1, &dp6m_ptr->i960r.ldoor_reg); + writel(pcistr->dpmem, &dp6m_ptr->u.ic.S_Info[0]); + writeb(0xff, &dp6m_ptr->u.ic.S_Cmd_Indx); + writeb(1, &dp6m_ptr->i960r.ldoor_reg); retries = INIT_RETRIES; gdth_delay(20); - while (gdth_readb(&dp6m_ptr->u.ic.S_Status) != 0xff) { + while (readb(&dp6m_ptr->u.ic.S_Status) != 0xff) { if (--retries == 0) { printk("GDT-PCI: Initialization error (DEINIT failed)\n"); iounmap(ha->brd); @@ -1489,8 +1240,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) } gdth_delay(1); } - prot_ver = (unchar)gdth_readl(&dp6m_ptr->u.ic.S_Info[0]); - gdth_writeb(0, &dp6m_ptr->u.ic.S_Status); + prot_ver = (unchar)readl(&dp6m_ptr->u.ic.S_Info[0]); + writeb(0, &dp6m_ptr->u.ic.S_Status); if (prot_ver != PROTOCOL_VERSION) { printk("GDT-PCI: Illegal protocol version\n"); iounmap(ha->brd); @@ -1501,15 +1252,15 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) ha->ic_all_size = sizeof(dp6m_ptr->u); /* special command to controller BIOS */ - gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[0]); - gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[1]); - gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[2]); - gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[3]); - gdth_writeb(0xfe, &dp6m_ptr->u.ic.S_Cmd_Indx); - gdth_writeb(1, &dp6m_ptr->i960r.ldoor_reg); + writel(0x00, &dp6m_ptr->u.ic.S_Info[0]); + writel(0x00, &dp6m_ptr->u.ic.S_Info[1]); + writel(0x00, &dp6m_ptr->u.ic.S_Info[2]); + writel(0x00, &dp6m_ptr->u.ic.S_Info[3]); + writeb(0xfe, &dp6m_ptr->u.ic.S_Cmd_Indx); + writeb(1, &dp6m_ptr->i960r.ldoor_reg); retries = INIT_RETRIES; gdth_delay(20); - while (gdth_readb(&dp6m_ptr->u.ic.S_Status) != 0xfe) { + while (readb(&dp6m_ptr->u.ic.S_Status) != 0xfe) { if (--retries == 0) { printk("GDT-PCI: Initialization error\n"); iounmap(ha->brd); @@ -1517,14 +1268,14 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) } gdth_delay(1); } - gdth_writeb(0, &dp6m_ptr->u.ic.S_Status); + writeb(0, &dp6m_ptr->u.ic.S_Status); /* read FW version to detect 64-bit DMA support */ - gdth_writeb(0xfd, &dp6m_ptr->u.ic.S_Cmd_Indx); - gdth_writeb(1, &dp6m_ptr->i960r.ldoor_reg); + writeb(0xfd, &dp6m_ptr->u.ic.S_Cmd_Indx); + writeb(1, &dp6m_ptr->i960r.ldoor_reg); retries = INIT_RETRIES; gdth_delay(20); - while (gdth_readb(&dp6m_ptr->u.ic.S_Status) != 0xfd) { + while (readb(&dp6m_ptr->u.ic.S_Status) != 0xfd) { if (--retries == 0) { printk("GDT-PCI: Initialization error (DEINIT failed)\n"); iounmap(ha->brd); @@ -1532,8 +1283,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) } gdth_delay(1); } - prot_ver = (unchar)(gdth_readl(&dp6m_ptr->u.ic.S_Info[0]) >> 16); - gdth_writeb(0, &dp6m_ptr->u.ic.S_Status); + prot_ver = (unchar)(readl(&dp6m_ptr->u.ic.S_Info[0]) >> 16); + writeb(0, &dp6m_ptr->u.ic.S_Status); if (prot_ver < 0x2b) /* FW < x.43: no 64-bit DMA support */ ha->dma64_support = 0; else @@ -1542,20 +1293,18 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) return 1; } - +#endif /* CONFIG_PCI */ /* controller protocol functions */ -static void __init gdth_enable_int(int hanum) +static void __init gdth_enable_int(gdth_ha_str *ha) { - gdth_ha_str *ha; ulong flags; gdt2_dpram_str __iomem *dp2_ptr; gdt6_dpram_str __iomem *dp6_ptr; gdt6m_dpram_str __iomem *dp6m_ptr; - TRACE(("gdth_enable_int() hanum %d\n",hanum)); - ha = HADATA(gdth_ctr_tab[hanum]); + TRACE(("gdth_enable_int() hanum %d\n",ha->hanum)); spin_lock_irqsave(&ha->smp_lock, flags); if (ha->type == GDT_EISA) { @@ -1564,93 +1313,80 @@ static void __init gdth_enable_int(int hanum) outb(0x01, ha->bmic + EINTENABREG); } else if (ha->type == GDT_ISA) { dp2_ptr = ha->brd; - gdth_writeb(1, &dp2_ptr->io.irqdel); - gdth_writeb(0, &dp2_ptr->u.ic.Cmd_Index); - gdth_writeb(1, &dp2_ptr->io.irqen); + writeb(1, &dp2_ptr->io.irqdel); + writeb(0, &dp2_ptr->u.ic.Cmd_Index); + writeb(1, &dp2_ptr->io.irqen); } else if (ha->type == GDT_PCI) { dp6_ptr = ha->brd; - gdth_writeb(1, &dp6_ptr->io.irqdel); - gdth_writeb(0, &dp6_ptr->u.ic.Cmd_Index); - gdth_writeb(1, &dp6_ptr->io.irqen); + writeb(1, &dp6_ptr->io.irqdel); + writeb(0, &dp6_ptr->u.ic.Cmd_Index); + writeb(1, &dp6_ptr->io.irqen); } else if (ha->type == GDT_PCINEW) { outb(0xff, PTR2USHORT(&ha->plx->edoor_reg)); outb(0x03, PTR2USHORT(&ha->plx->control1)); } else if (ha->type == GDT_PCIMPR) { dp6m_ptr = ha->brd; - gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg); - gdth_writeb(gdth_readb(&dp6m_ptr->i960r.edoor_en_reg) & ~4, + writeb(0xff, &dp6m_ptr->i960r.edoor_reg); + writeb(readb(&dp6m_ptr->i960r.edoor_en_reg) & ~4, &dp6m_ptr->i960r.edoor_en_reg); } spin_unlock_irqrestore(&ha->smp_lock, flags); } - -static int gdth_get_status(unchar *pIStatus,int irq) +/* return IStatus if interrupt was from this card else 0 */ +static unchar gdth_get_status(gdth_ha_str *ha, int irq) { - register gdth_ha_str *ha; - int i; + unchar IStatus = 0; + + TRACE(("gdth_get_status() irq %d ctr_count %d\n", irq, gdth_ctr_count)); - TRACE(("gdth_get_status() irq %d ctr_count %d\n", - irq,gdth_ctr_count)); - - *pIStatus = 0; - for (i=0; i<gdth_ctr_count; ++i) { - ha = HADATA(gdth_ctr_tab[i]); if (ha->irq != (unchar)irq) /* check IRQ */ - continue; + return false; if (ha->type == GDT_EISA) - *pIStatus = inb((ushort)ha->bmic + EDOORREG); + IStatus = inb((ushort)ha->bmic + EDOORREG); else if (ha->type == GDT_ISA) - *pIStatus = - gdth_readb(&((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index); + IStatus = + readb(&((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index); else if (ha->type == GDT_PCI) - *pIStatus = - gdth_readb(&((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index); + IStatus = + readb(&((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index); else if (ha->type == GDT_PCINEW) - *pIStatus = inb(PTR2USHORT(&ha->plx->edoor_reg)); + IStatus = inb(PTR2USHORT(&ha->plx->edoor_reg)); else if (ha->type == GDT_PCIMPR) - *pIStatus = - gdth_readb(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.edoor_reg); - - if (*pIStatus) - return i; /* board found */ - } - return -1; + IStatus = + readb(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.edoor_reg); + + return IStatus; } - - -static int gdth_test_busy(int hanum) + +static int gdth_test_busy(gdth_ha_str *ha) { - register gdth_ha_str *ha; register int gdtsema0 = 0; - TRACE(("gdth_test_busy() hanum %d\n",hanum)); - - ha = HADATA(gdth_ctr_tab[hanum]); + TRACE(("gdth_test_busy() hanum %d\n", ha->hanum)); + if (ha->type == GDT_EISA) gdtsema0 = (int)inb(ha->bmic + SEMA0REG); else if (ha->type == GDT_ISA) - gdtsema0 = (int)gdth_readb(&((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Sema0); + gdtsema0 = (int)readb(&((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Sema0); else if (ha->type == GDT_PCI) - gdtsema0 = (int)gdth_readb(&((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Sema0); + gdtsema0 = (int)readb(&((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Sema0); else if (ha->type == GDT_PCINEW) gdtsema0 = (int)inb(PTR2USHORT(&ha->plx->sema0_reg)); else if (ha->type == GDT_PCIMPR) gdtsema0 = - (int)gdth_readb(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.sema0_reg); + (int)readb(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.sema0_reg); return (gdtsema0 & 1); } -static int gdth_get_cmd_index(int hanum) +static int gdth_get_cmd_index(gdth_ha_str *ha) { - register gdth_ha_str *ha; int i; - TRACE(("gdth_get_cmd_index() hanum %d\n",hanum)); + TRACE(("gdth_get_cmd_index() hanum %d\n", ha->hanum)); - ha = HADATA(gdth_ctr_tab[hanum]); for (i=0; i<GDTH_MAXCMDS; ++i) { if (ha->cmd_tab[i].cmnd == UNUSED_CMND) { ha->cmd_tab[i].cmnd = ha->pccb->RequestBuffer; @@ -1663,30 +1399,26 @@ static int gdth_get_cmd_index(int hanum) } -static void gdth_set_sema0(int hanum) +static void gdth_set_sema0(gdth_ha_str *ha) { - register gdth_ha_str *ha; - - TRACE(("gdth_set_sema0() hanum %d\n",hanum)); + TRACE(("gdth_set_sema0() hanum %d\n", ha->hanum)); - ha = HADATA(gdth_ctr_tab[hanum]); if (ha->type == GDT_EISA) { outb(1, ha->bmic + SEMA0REG); } else if (ha->type == GDT_ISA) { - gdth_writeb(1, &((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Sema0); + writeb(1, &((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Sema0); } else if (ha->type == GDT_PCI) { - gdth_writeb(1, &((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Sema0); + writeb(1, &((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Sema0); } else if (ha->type == GDT_PCINEW) { outb(1, PTR2USHORT(&ha->plx->sema0_reg)); } else if (ha->type == GDT_PCIMPR) { - gdth_writeb(1, &((gdt6m_dpram_str __iomem *)ha->brd)->i960r.sema0_reg); + writeb(1, &((gdt6m_dpram_str __iomem *)ha->brd)->i960r.sema0_reg); } } -static void gdth_copy_command(int hanum) +static void gdth_copy_command(gdth_ha_str *ha) { - register gdth_ha_str *ha; register gdth_cmd_str *cmd_ptr; register gdt6m_dpram_str __iomem *dp6m_ptr; register gdt6c_dpram_str __iomem *dp6c_ptr; @@ -1694,9 +1426,8 @@ static void gdth_copy_command(int hanum) gdt2_dpram_str __iomem *dp2_ptr; ushort cp_count,dp_offset,cmd_no; - TRACE(("gdth_copy_command() hanum %d\n",hanum)); + TRACE(("gdth_copy_command() hanum %d\n", ha->hanum)); - ha = HADATA(gdth_ctr_tab[hanum]); cp_count = ha->cmd_len; dp_offset= ha->cmd_offs_dpmem; cmd_no = ha->cmd_cnt; @@ -1715,42 +1446,39 @@ static void gdth_copy_command(int hanum) /* set offset and service, copy command to DPMEM */ if (ha->type == GDT_ISA) { dp2_ptr = ha->brd; - gdth_writew(dp_offset + DPMEM_COMMAND_OFFSET, + writew(dp_offset + DPMEM_COMMAND_OFFSET, &dp2_ptr->u.ic.comm_queue[cmd_no].offset); - gdth_writew((ushort)cmd_ptr->Service, + writew((ushort)cmd_ptr->Service, &dp2_ptr->u.ic.comm_queue[cmd_no].serv_id); memcpy_toio(&dp2_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count); } else if (ha->type == GDT_PCI) { dp6_ptr = ha->brd; - gdth_writew(dp_offset + DPMEM_COMMAND_OFFSET, + writew(dp_offset + DPMEM_COMMAND_OFFSET, &dp6_ptr->u.ic.comm_queue[cmd_no].offset); - gdth_writew((ushort)cmd_ptr->Service, + writew((ushort)cmd_ptr->Service, &dp6_ptr->u.ic.comm_queue[cmd_no].serv_id); memcpy_toio(&dp6_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count); } else if (ha->type == GDT_PCINEW) { dp6c_ptr = ha->brd; - gdth_writew(dp_offset + DPMEM_COMMAND_OFFSET, + writew(dp_offset + DPMEM_COMMAND_OFFSET, &dp6c_ptr->u.ic.comm_queue[cmd_no].offset); - gdth_writew((ushort)cmd_ptr->Service, + writew((ushort)cmd_ptr->Service, &dp6c_ptr->u.ic.comm_queue[cmd_no].serv_id); memcpy_toio(&dp6c_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count); } else if (ha->type == GDT_PCIMPR) { dp6m_ptr = ha->brd; - gdth_writew(dp_offset + DPMEM_COMMAND_OFFSET, + writew(dp_offset + DPMEM_COMMAND_OFFSET, &dp6m_ptr->u.ic.comm_queue[cmd_no].offset); - gdth_writew((ushort)cmd_ptr->Service, + writew((ushort)cmd_ptr->Service, &dp6m_ptr->u.ic.comm_queue[cmd_no].serv_id); memcpy_toio(&dp6m_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count); } } -static void gdth_release_event(int hanum) +static void gdth_release_event(gdth_ha_str *ha) { - register gdth_ha_str *ha; - - TRACE(("gdth_release_event() hanum %d\n",hanum)); - ha = HADATA(gdth_ctr_tab[hanum]); + TRACE(("gdth_release_event() hanum %d\n", ha->hanum)); #ifdef GDTH_STATISTICS { @@ -1774,56 +1502,50 @@ static void gdth_release_event(int hanum) outl(ha->ccb_phys, ha->bmic + MAILBOXREG); outb(ha->pccb->Service, ha->bmic + LDOORREG); } else if (ha->type == GDT_ISA) { - gdth_writeb(0, &((gdt2_dpram_str __iomem *)ha->brd)->io.event); + writeb(0, &((gdt2_dpram_str __iomem *)ha->brd)->io.event); } else if (ha->type == GDT_PCI) { - gdth_writeb(0, &((gdt6_dpram_str __iomem *)ha->brd)->io.event); + writeb(0, &((gdt6_dpram_str __iomem *)ha->brd)->io.event); } else if (ha->type == GDT_PCINEW) { outb(1, PTR2USHORT(&ha->plx->ldoor_reg)); } else if (ha->type == GDT_PCIMPR) { - gdth_writeb(1, &((gdt6m_dpram_str __iomem *)ha->brd)->i960r.ldoor_reg); + writeb(1, &((gdt6m_dpram_str __iomem *)ha->brd)->i960r.ldoor_reg); } } - -static int gdth_wait(int hanum,int index,ulong32 time) +static int gdth_wait(gdth_ha_str *ha, int index, ulong32 time) { - gdth_ha_str *ha; int answer_found = FALSE; + int wait_index = 0; - TRACE(("gdth_wait() hanum %d index %d time %d\n",hanum,index,time)); + TRACE(("gdth_wait() hanum %d index %d time %d\n", ha->hanum, index, time)); - ha = HADATA(gdth_ctr_tab[hanum]); if (index == 0) return 1; /* no wait required */ - gdth_from_wait = TRUE; do { - gdth_interrupt((int)ha->irq,ha); - if (wait_hanum==hanum && wait_index==index) { + __gdth_interrupt(ha, (int)ha->irq, true, &wait_index); + if (wait_index == index) { answer_found = TRUE; break; } gdth_delay(1); } while (--time); - gdth_from_wait = FALSE; - - while (gdth_test_busy(hanum)) + + while (gdth_test_busy(ha)) gdth_delay(0); return (answer_found); } -static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1, - ulong64 p2,ulong64 p3) +static int gdth_internal_cmd(gdth_ha_str *ha, unchar service, ushort opcode, + ulong32 p1, ulong64 p2, ulong64 p3) { - register gdth_ha_str *ha; register gdth_cmd_str *cmd_ptr; int retries,index; TRACE2(("gdth_internal_cmd() service %d opcode %d\n",service,opcode)); - ha = HADATA(gdth_ctr_tab[hanum]); cmd_ptr = ha->pccb; memset((char*)cmd_ptr,0,sizeof(gdth_cmd_str)); @@ -1831,11 +1553,11 @@ static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1, for (retries = INIT_RETRIES;;) { cmd_ptr->Service = service; cmd_ptr->RequestBuffer = INTERNAL_CMND; - if (!(index=gdth_get_cmd_index(hanum))) { + if (!(index=gdth_get_cmd_index(ha))) { TRACE(("GDT: No free command index found\n")); return 0; } - gdth_set_sema0(hanum); + gdth_set_sema0(ha); cmd_ptr->OpCode = opcode; cmd_ptr->BoardNode = LOCALBOARD; if (service == CACHESERVICE) { @@ -1875,10 +1597,10 @@ static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1, ha->cmd_len = sizeof(gdth_cmd_str); ha->cmd_offs_dpmem = 0; ha->cmd_cnt = 0; - gdth_copy_command(hanum); - gdth_release_event(hanum); + gdth_copy_command(ha); + gdth_release_event(ha); gdth_delay(20); - if (!gdth_wait(hanum,index,INIT_TIMEOUT)) { + if (!gdth_wait(ha, index, INIT_TIMEOUT)) { printk("GDT: Initialization error (timeout service %d)\n",service); return 0; } @@ -1893,9 +1615,8 @@ static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1, /* search for devices */ -static int __init gdth_search_drives(int hanum) +static int __init gdth_search_drives(gdth_ha_str *ha) { - register gdth_ha_str *ha; ushort cdev_cnt, i; int ok; ulong32 bus_no, drv_cnt, drv_no, j; @@ -1915,22 +1636,21 @@ static int __init gdth_search_drives(int hanum) ulong flags; #endif - TRACE(("gdth_search_drives() hanum %d\n",hanum)); - ha = HADATA(gdth_ctr_tab[hanum]); + TRACE(("gdth_search_drives() hanum %d\n", ha->hanum)); ok = 0; /* initialize controller services, at first: screen service */ ha->screen_feat = 0; if (!force_dma32) { - ok = gdth_internal_cmd(hanum,SCREENSERVICE,GDT_X_INIT_SCR,0,0,0); + ok = gdth_internal_cmd(ha, SCREENSERVICE, GDT_X_INIT_SCR, 0, 0, 0); if (ok) ha->screen_feat = GDT_64BIT; } if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC)) - ok = gdth_internal_cmd(hanum,SCREENSERVICE,GDT_INIT,0,0,0); + ok = gdth_internal_cmd(ha, SCREENSERVICE, GDT_INIT, 0, 0, 0); if (!ok) { printk("GDT-HA %d: Initialization error screen service (code %d)\n", - hanum, ha->status); + ha->hanum, ha->status); return 0; } TRACE2(("gdth_search_drives(): SCREENSERVICE initialized\n")); @@ -1954,25 +1674,26 @@ static int __init gdth_search_drives(int hanum) TRACE2(("gdth_search_drives(): RTC: %x/%x/%x\n",*(ulong32 *)&rtc[0], *(ulong32 *)&rtc[4], *(ulong32 *)&rtc[8])); /* 3. send to controller firmware */ - gdth_internal_cmd(hanum,SCREENSERVICE,GDT_REALTIME, *(ulong32 *)&rtc[0], + gdth_internal_cmd(ha, SCREENSERVICE, GDT_REALTIME, *(ulong32 *)&rtc[0], *(ulong32 *)&rtc[4], *(ulong32 *)&rtc[8]); #endif /* unfreeze all IOs */ - gdth_internal_cmd(hanum,CACHESERVICE,GDT_UNFREEZE_IO,0,0,0); + gdth_internal_cmd(ha, CACHESERVICE, GDT_UNFREEZE_IO, 0, 0, 0); /* initialize cache service */ ha->cache_feat = 0; if (!force_dma32) { - ok = gdth_internal_cmd(hanum,CACHESERVICE,GDT_X_INIT_HOST,LINUX_OS,0,0); + ok = gdth_internal_cmd(ha, CACHESERVICE, GDT_X_INIT_HOST, LINUX_OS, + 0, 0); if (ok) ha->cache_feat = GDT_64BIT; } if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC)) - ok = gdth_internal_cmd(hanum,CACHESERVICE,GDT_INIT,LINUX_OS,0,0); + ok = gdth_internal_cmd(ha, CACHESERVICE, GDT_INIT, LINUX_OS, 0, 0); if (!ok) { printk("GDT-HA %d: Initialization error cache service (code %d)\n", - hanum, ha->status); + ha->hanum, ha->status); return 0; } TRACE2(("gdth_search_drives(): CACHESERVICE initialized\n")); @@ -2001,9 +1722,9 @@ static int __init gdth_search_drives(int hanum) pmod->cmd_buff_size = 0; pmod->reserved1 = 0; pmod->reserved2 = 0; - if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,SET_PERF_MODES, + if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, SET_PERF_MODES, INVALID_CHANNEL,sizeof(gdth_perf_modes))) { - printk("GDT-HA %d: Interrupt coalescing activated\n", hanum); + printk("GDT-HA %d: Interrupt coalescing activated\n", ha->hanum); } } #endif @@ -2015,7 +1736,7 @@ static int __init gdth_search_drives(int hanum) iocr->hdr.first_chan = 0; iocr->hdr.last_chan = MAXBUS-1; iocr->hdr.list_offset = GDTOFFSOF(gdth_raw_iochan_str, list[0]); - if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,IOCHAN_RAW_DESC, + if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, IOCHAN_RAW_DESC, INVALID_CHANNEL,sizeof(gdth_raw_iochan_str))) { TRACE2(("IOCHAN_RAW_DESC supported!\n")); ha->bus_cnt = iocr->hdr.chan_count; @@ -2030,13 +1751,13 @@ static int __init gdth_search_drives(int hanum) chn = (gdth_getch_str *)ha->pscratch; for (bus_no = 0; bus_no < MAXBUS; ++bus_no) { chn->channel_no = bus_no; - if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL, + if (!gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, SCSI_CHAN_CNT | L_CTRL_PATTERN, IO_CHANNEL | INVALID_CHANNEL, sizeof(gdth_getch_str))) { if (bus_no == 0) { printk("GDT-HA %d: Error detecting channel count (0x%x)\n", - hanum, ha->status); + ha->hanum, ha->status); return 0; } break; @@ -2051,10 +1772,10 @@ static int __init gdth_search_drives(int hanum) TRACE2(("gdth_search_drives() %d channels\n",ha->bus_cnt)); /* read cache configuration */ - if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,CACHE_INFO, + if (!gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, CACHE_INFO, INVALID_CHANNEL,sizeof(gdth_cinfo_str))) { printk("GDT-HA %d: Initialization error cache service (code %d)\n", - hanum, ha->status); + ha->hanum, ha->status); return 0; } ha->cpar = ((gdth_cinfo_str *)ha->pscratch)->cpar; @@ -2064,11 +1785,11 @@ static int __init gdth_search_drives(int hanum) /* read board info and features */ ha->more_proc = FALSE; - if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,BOARD_INFO, + if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, BOARD_INFO, INVALID_CHANNEL,sizeof(gdth_binfo_str))) { memcpy(&ha->binfo, (gdth_binfo_str *)ha->pscratch, sizeof(gdth_binfo_str)); - if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,BOARD_FEATURES, + if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, BOARD_FEATURES, INVALID_CHANNEL,sizeof(gdth_bfeat_str))) { TRACE2(("BOARD_INFO/BOARD_FEATURES supported\n")); ha->bfeat = *(gdth_bfeat_str *)ha->pscratch; @@ -2076,7 +1797,7 @@ static int __init gdth_search_drives(int hanum) } } else { TRACE2(("BOARD_INFO requires firmware >= 1.10/2.08\n")); - strcpy(ha->binfo.type_string, gdth_ctr_name(hanum)); + strcpy(ha->binfo.type_string, gdth_ctr_name(ha)); } TRACE2(("Controller name: %s\n",ha->binfo.type_string)); @@ -2089,7 +1810,7 @@ static int __init gdth_search_drives(int hanum) ioc->hdr.first_chan = 0; ioc->hdr.last_chan = MAXBUS-1; ioc->hdr.list_offset = GDTOFFSOF(gdth_iochan_str, list[0]); - if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,IOCHAN_DESC, + if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, IOCHAN_DESC, INVALID_CHANNEL,sizeof(gdth_iochan_str))) { for (bus_no = 0; bus_no < ha->bus_cnt; ++bus_no) { ha->raw[bus_no].address = ioc->list[bus_no].address; @@ -2104,7 +1825,7 @@ static int __init gdth_search_drives(int hanum) for (bus_no = 0; bus_no < ha->bus_cnt; ++bus_no) { chn = (gdth_getch_str *)ha->pscratch; chn->channel_no = ha->raw[bus_no].local_no; - if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL, + if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, SCSI_CHAN_CNT | L_CTRL_PATTERN, ha->raw[bus_no].address | INVALID_CHANNEL, sizeof(gdth_getch_str))) { @@ -2116,7 +1837,7 @@ static int __init gdth_search_drives(int hanum) drl = (gdth_drlist_str *)ha->pscratch; drl->sc_no = ha->raw[bus_no].local_no; drl->sc_cnt = ha->raw[bus_no].pdev_cnt; - if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL, + if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, SCSI_DR_LIST | L_CTRL_PATTERN, ha->raw[bus_no].address | INVALID_CHANNEL, sizeof(gdth_drlist_str))) { @@ -2129,10 +1850,10 @@ static int __init gdth_search_drives(int hanum) } /* logical drives */ - if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,CACHE_DRV_CNT, + if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, CACHE_DRV_CNT, INVALID_CHANNEL,sizeof(ulong32))) { drv_cnt = *(ulong32 *)ha->pscratch; - if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,CACHE_DRV_LIST, + if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, CACHE_DRV_LIST, INVALID_CHANNEL,drv_cnt * sizeof(ulong32))) { for (j = 0; j < drv_cnt; ++j) { drv_no = ((ulong32 *)ha->pscratch)[j]; @@ -2146,7 +1867,7 @@ static int __init gdth_search_drives(int hanum) alst->entries_avail = MAX_LDRIVES; alst->first_entry = 0; alst->list_offset = GDTOFFSOF(gdth_arcdl_str, list[0]); - if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL, + if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, ARRAY_DRV_LIST2 | LA_CTRL_PATTERN, INVALID_CHANNEL, sizeof(gdth_arcdl_str) + (alst->entries_avail-1) * sizeof(gdth_alist_str))) { @@ -2157,7 +1878,7 @@ static int __init gdth_search_drives(int hanum) ha->hdr[j].is_hotfix = alst->list[j].is_hotfix; ha->hdr[j].master_no = alst->list[j].cd_handle; } - } else if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL, + } else if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, ARRAY_DRV_LIST | LA_CTRL_PATTERN, 0, 35 * sizeof(gdth_alist_str))) { for (j = 0; j < 35; ++j) { @@ -2175,24 +1896,24 @@ static int __init gdth_search_drives(int hanum) /* initialize raw service */ ha->raw_feat = 0; if (!force_dma32) { - ok = gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_X_INIT_RAW,0,0,0); + ok = gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_X_INIT_RAW, 0, 0, 0); if (ok) ha->raw_feat = GDT_64BIT; } if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC)) - ok = gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_INIT,0,0,0); + ok = gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_INIT, 0, 0, 0); if (!ok) { printk("GDT-HA %d: Initialization error raw service (code %d)\n", - hanum, ha->status); + ha->hanum, ha->status); return 0; } TRACE2(("gdth_search_drives(): RAWSERVICE initialized\n")); /* set/get features raw service (scatter/gather) */ - if (gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_SET_FEAT,SCATTER_GATHER, - 0,0)) { + if (gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_SET_FEAT, SCATTER_GATHER, + 0, 0)) { TRACE2(("gdth_search_drives(): set features RAWSERVICE OK\n")); - if (gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_GET_FEAT,0,0,0)) { + if (gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_GET_FEAT, 0, 0, 0)) { TRACE2(("gdth_search_dr(): get feat RAWSERVICE %d\n", ha->info)); ha->raw_feat |= (ushort)ha->info; @@ -2200,10 +1921,10 @@ static int __init gdth_search_drives(int hanum) } /* set/get features cache service (equal to raw service) */ - if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_SET_FEAT,0, + if (gdth_internal_cmd(ha, CACHESERVICE, GDT_SET_FEAT, 0, SCATTER_GATHER,0)) { TRACE2(("gdth_search_drives(): set features CACHESERVICE OK\n")); - if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_GET_FEAT,0,0,0)) { + if (gdth_internal_cmd(ha, CACHESERVICE, GDT_GET_FEAT, 0, 0, 0)) { TRACE2(("gdth_search_dr(): get feat CACHESERV. %d\n", ha->info)); ha->cache_feat |= (ushort)ha->info; @@ -2212,22 +1933,22 @@ static int __init gdth_search_drives(int hanum) /* reserve drives for raw service */ if (reserve_mode != 0) { - gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_RESERVE_ALL, + gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_RESERVE_ALL, reserve_mode == 1 ? 1 : 3, 0, 0); TRACE2(("gdth_search_drives(): RESERVE_ALL code %d\n", ha->status)); } for (i = 0; i < MAX_RES_ARGS; i += 4) { - if (reserve_list[i] == hanum && reserve_list[i+1] < ha->bus_cnt && + if (reserve_list[i] == ha->hanum && reserve_list[i+1] < ha->bus_cnt && reserve_list[i+2] < ha->tid_cnt && reserve_list[i+3] < MAXLUN) { TRACE2(("gdth_search_drives(): reserve ha %d bus %d id %d lun %d\n", reserve_list[i], reserve_list[i+1], reserve_list[i+2], reserve_list[i+3])); - if (!gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_RESERVE,0, + if (!gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_RESERVE, 0, reserve_list[i+1], reserve_list[i+2] | (reserve_list[i+3] << 8))) { printk("GDT-HA %d: Error raw service (RESERVE, code %d)\n", - hanum, ha->status); + ha->hanum, ha->status); } } } @@ -2236,58 +1957,44 @@ static int __init gdth_search_drives(int hanum) oemstr = (gdth_oem_str_ioctl *)ha->pscratch; oemstr->params.ctl_version = 0x01; oemstr->params.buffer_size = sizeof(oemstr->text); - if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL, + if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, CACHE_READ_OEM_STRING_RECORD,INVALID_CHANNEL, sizeof(gdth_oem_str_ioctl))) { TRACE2(("gdth_search_drives(): CACHE_READ_OEM_STRING_RECORD OK\n")); printk("GDT-HA %d: Vendor: %s Name: %s\n", - hanum,oemstr->text.oem_company_name,ha->binfo.type_string); + ha->hanum, oemstr->text.oem_company_name, ha->binfo.type_string); /* Save the Host Drive inquiry data */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) strlcpy(ha->oem_name,oemstr->text.scsi_host_drive_inquiry_vendor_id, sizeof(ha->oem_name)); -#else - strncpy(ha->oem_name,oemstr->text.scsi_host_drive_inquiry_vendor_id,7); - ha->oem_name[7] = '\0'; -#endif } else { /* Old method, based on PCI ID */ TRACE2(("gdth_search_drives(): CACHE_READ_OEM_STRING_RECORD failed\n")); printk("GDT-HA %d: Name: %s\n", - hanum,ha->binfo.type_string); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + ha->hanum, ha->binfo.type_string); if (ha->oem_id == OEM_ID_INTEL) strlcpy(ha->oem_name,"Intel ", sizeof(ha->oem_name)); else strlcpy(ha->oem_name,"ICP ", sizeof(ha->oem_name)); -#else - if (ha->oem_id == OEM_ID_INTEL) - strcpy(ha->oem_name,"Intel "); - else - strcpy(ha->oem_name,"ICP "); -#endif } /* scanning for host drives */ for (i = 0; i < cdev_cnt; ++i) - gdth_analyse_hdrive(hanum,i); + gdth_analyse_hdrive(ha, i); TRACE(("gdth_search_drives() OK\n")); return 1; } -static int gdth_analyse_hdrive(int hanum,ushort hdrive) +static int gdth_analyse_hdrive(gdth_ha_str *ha, ushort hdrive) { - register gdth_ha_str *ha; ulong32 drv_cyls; int drv_hds, drv_secs; - TRACE(("gdth_analyse_hdrive() hanum %d drive %d\n",hanum,hdrive)); + TRACE(("gdth_analyse_hdrive() hanum %d drive %d\n", ha->hanum, hdrive)); if (hdrive >= MAX_HDRIVES) return 0; - ha = HADATA(gdth_ctr_tab[hanum]); - if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_INFO,hdrive,0,0)) + if (!gdth_internal_cmd(ha, CACHESERVICE, GDT_INFO, hdrive, 0, 0)) return 0; ha->hdr[hdrive].present = TRUE; ha->hdr[hdrive].size = ha->info; @@ -2307,7 +2014,7 @@ static int gdth_analyse_hdrive(int hanum,ushort hdrive) ha->hdr[hdrive].size = drv_cyls * drv_hds * drv_secs; if (ha->cache_feat & GDT_64BIT) { - if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_X_INFO,hdrive,0,0) + if (gdth_internal_cmd(ha, CACHESERVICE, GDT_X_INFO, hdrive, 0, 0) && ha->info2 != 0) { ha->hdr[hdrive].size = ((ulong64)ha->info2 << 32) | ha->info; } @@ -2316,14 +2023,14 @@ static int gdth_analyse_hdrive(int hanum,ushort hdrive) hdrive,ha->hdr[hdrive].size,drv_hds,drv_secs)); /* get informations about device */ - if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_DEVTYPE,hdrive,0,0)) { + if (gdth_internal_cmd(ha, CACHESERVICE, GDT_DEVTYPE, hdrive, 0, 0)) { TRACE2(("gdth_search_dr() cache drive %d devtype %d\n", hdrive,ha->info)); ha->hdr[hdrive].devtype = (ushort)ha->info; } /* cluster info */ - if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_CLUST_INFO,hdrive,0,0)) { + if (gdth_internal_cmd(ha, CACHESERVICE, GDT_CLUST_INFO, hdrive, 0, 0)) { TRACE2(("gdth_search_dr() cache drive %d cluster info %d\n", hdrive,ha->info)); if (!shared_access) @@ -2331,7 +2038,7 @@ static int gdth_analyse_hdrive(int hanum,ushort hdrive) } /* R/W attributes */ - if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_RW_ATTRIBS,hdrive,0,0)) { + if (gdth_internal_cmd(ha, CACHESERVICE, GDT_RW_ATTRIBS, hdrive, 0, 0)) { TRACE2(("gdth_search_dr() cache drive %d r/w attrib. %d\n", hdrive,ha->info)); ha->hdr[hdrive].rw_attribs = (unchar)ha->info; @@ -2343,27 +2050,26 @@ static int gdth_analyse_hdrive(int hanum,ushort hdrive) /* command queueing/sending functions */ -static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority) +static void gdth_putq(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar priority) { - register gdth_ha_str *ha; + struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); register Scsi_Cmnd *pscp; register Scsi_Cmnd *nscp; ulong flags; unchar b, t; TRACE(("gdth_putq() priority %d\n",priority)); - ha = HADATA(gdth_ctr_tab[hanum]); spin_lock_irqsave(&ha->smp_lock, flags); - if (scp->done != gdth_scsi_done) { - scp->SCp.this_residual = (int)priority; - b = virt_ctr ? NUMDATA(scp->device->host)->busnum:scp->device->channel; + if (!cmndinfo->internal_command) { + cmndinfo->priority = priority; + b = scp->device->channel; t = scp->device->id; if (priority >= DEFAULT_PRI) { if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha,b)].lock) || (b==ha->virt_bus && t<MAX_HDRIVES && ha->hdr[t].lock)) { TRACE2(("gdth_putq(): locked IO ->update_timeout()\n")); - scp->SCp.buffers_residual = gdth_update_timeout(hanum, scp, 0); + cmndinfo->timeout = gdth_update_timeout(scp, 0); } } } @@ -2375,7 +2081,7 @@ static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority) pscp = ha->req_first; nscp = (Scsi_Cmnd *)pscp->SCp.ptr; /* priority: 0-highest,..,0xff-lowest */ - while (nscp && (unchar)nscp->SCp.this_residual <= priority) { + while (nscp && gdth_cmnd_priv(nscp)->priority <= priority) { pscp = nscp; nscp = (Scsi_Cmnd *)pscp->SCp.ptr; } @@ -2395,9 +2101,8 @@ static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority) #endif } -static void gdth_next(int hanum) +static void gdth_next(gdth_ha_str *ha) { - register gdth_ha_str *ha; register Scsi_Cmnd *pscp; register Scsi_Cmnd *nscp; unchar b, t, l, firsttime; @@ -2405,8 +2110,7 @@ static void gdth_next(int hanum) ulong flags = 0; int cmd_index; - TRACE(("gdth_next() hanum %d\n",hanum)); - ha = HADATA(gdth_ctr_tab[hanum]); + TRACE(("gdth_next() hanum %d\n", ha->hanum)); if (!gdth_polling) spin_lock_irqsave(&ha->smp_lock, flags); @@ -2416,14 +2120,14 @@ static void gdth_next(int hanum) cmd_index = 0; for (nscp = pscp = ha->req_first; nscp; nscp = (Scsi_Cmnd *)nscp->SCp.ptr) { + struct gdth_cmndinfo *nscp_cmndinfo = gdth_cmnd_priv(nscp); if (nscp != pscp && nscp != (Scsi_Cmnd *)pscp->SCp.ptr) pscp = (Scsi_Cmnd *)pscp->SCp.ptr; - if (nscp->done != gdth_scsi_done) { - b = virt_ctr ? - NUMDATA(nscp->device->host)->busnum : nscp->device->channel; + if (!nscp_cmndinfo->internal_command) { + b = nscp->device->channel; t = nscp->device->id; l = nscp->device->lun; - if (nscp->SCp.this_residual >= DEFAULT_PRI) { + if (nscp_cmndinfo->priority >= DEFAULT_PRI) { if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha,b)].lock) || (b == ha->virt_bus && t < MAX_HDRIVES && ha->hdr[t].lock)) continue; @@ -2432,21 +2136,21 @@ static void gdth_next(int hanum) b = t = l = 0; if (firsttime) { - if (gdth_test_busy(hanum)) { /* controller busy ? */ - TRACE(("gdth_next() controller %d busy !\n",hanum)); + if (gdth_test_busy(ha)) { /* controller busy ? */ + TRACE(("gdth_next() controller %d busy !\n", ha->hanum)); if (!gdth_polling) { spin_unlock_irqrestore(&ha->smp_lock, flags); return; } - while (gdth_test_busy(hanum)) + while (gdth_test_busy(ha)) gdth_delay(1); } firsttime = FALSE; } - if (nscp->done != gdth_scsi_done) { - if (nscp->SCp.phase == -1) { - nscp->SCp.phase = CACHESERVICE; /* default: cache svc. */ + if (!nscp_cmndinfo->internal_command) { + if (nscp_cmndinfo->phase == -1) { + nscp_cmndinfo->phase = CACHESERVICE; /* default: cache svc. */ if (nscp->cmnd[0] == TEST_UNIT_READY) { TRACE2(("TEST_UNIT_READY Bus %d Id %d LUN %d\n", b, t, l)); @@ -2459,8 +2163,8 @@ static void gdth_next(int hanum) } else if ((ha->scan_mode & 0x0f) == 1) { if (b == 0 && ((t == 0 && l == 1) || (t == 1 && l == 0))) { - nscp->SCp.sent_command = GDT_SCAN_START; - nscp->SCp.phase = ((ha->scan_mode & 0x10 ? 1:0) << 8) + nscp_cmndinfo->OpCode = GDT_SCAN_START; + nscp_cmndinfo->phase = ((ha->scan_mode & 0x10 ? 1:0) << 8) | SCSIRAWSERVICE; ha->scan_mode = 0x12; TRACE2(("Scan mode: 0x%x (SCAN_START)\n", @@ -2471,8 +2175,8 @@ static void gdth_next(int hanum) } } else if (ha->scan_mode == 0x12) { if (b == ha->bus_cnt && t == ha->tid_cnt-1) { - nscp->SCp.phase = SCSIRAWSERVICE; - nscp->SCp.sent_command = GDT_SCAN_END; + nscp_cmndinfo->phase = SCSIRAWSERVICE; + nscp_cmndinfo->OpCode = GDT_SCAN_END; ha->scan_mode &= 0x10; TRACE2(("Scan mode: 0x%x (SCAN_END)\n", ha->scan_mode)); @@ -2483,18 +2187,18 @@ static void gdth_next(int hanum) nscp->cmnd[0] != READ_CAPACITY && nscp->cmnd[0] != MODE_SENSE && (ha->hdr[t].cluster_type & CLUSTER_DRIVE)) { /* always GDT_CLUST_INFO! */ - nscp->SCp.sent_command = GDT_CLUST_INFO; + nscp_cmndinfo->OpCode = GDT_CLUST_INFO; } } } - if (nscp->SCp.sent_command != -1) { - if ((nscp->SCp.phase & 0xff) == CACHESERVICE) { - if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t))) + if (nscp_cmndinfo->OpCode != -1) { + if ((nscp_cmndinfo->phase & 0xff) == CACHESERVICE) { + if (!(cmd_index=gdth_fill_cache_cmd(ha, nscp, t))) this_cmd = FALSE; next_cmd = FALSE; - } else if ((nscp->SCp.phase & 0xff) == SCSIRAWSERVICE) { - if (!(cmd_index=gdth_fill_raw_cmd(hanum,nscp,BUS_L2P(ha,b)))) + } else if ((nscp_cmndinfo->phase & 0xff) == SCSIRAWSERVICE) { + if (!(cmd_index=gdth_fill_raw_cmd(ha, nscp, BUS_L2P(ha, b)))) this_cmd = FALSE; next_cmd = FALSE; } else { @@ -2502,18 +2206,18 @@ static void gdth_next(int hanum) nscp->sense_buffer[0] = 0x70; nscp->sense_buffer[2] = NOT_READY; nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); - if (!nscp->SCp.have_data_in) - nscp->SCp.have_data_in++; + if (!nscp_cmndinfo->wait_for_completion) + nscp_cmndinfo->wait_for_completion++; else - nscp->scsi_done(nscp); + gdth_scsi_done(nscp); } - } else if (nscp->done == gdth_scsi_done) { - if (!(cmd_index=gdth_special_cmd(hanum,nscp))) + } else if (gdth_cmnd_priv(nscp)->internal_command) { + if (!(cmd_index=gdth_special_cmd(ha, nscp))) this_cmd = FALSE; next_cmd = FALSE; } else if (b != ha->virt_bus) { if (ha->raw[BUS_L2P(ha,b)].io_cnt[t] >= GDTH_MAX_RAW || - !(cmd_index=gdth_fill_raw_cmd(hanum,nscp,BUS_L2P(ha,b)))) + !(cmd_index=gdth_fill_raw_cmd(ha, nscp, BUS_L2P(ha, b)))) this_cmd = FALSE; else ha->raw[BUS_L2P(ha,b)].io_cnt[t]++; @@ -2521,10 +2225,10 @@ static void gdth_next(int hanum) TRACE2(("Command 0x%x to bus %d id %d lun %d -> IGNORE\n", nscp->cmnd[0], b, t, l)); nscp->result = DID_BAD_TARGET << 16; - if (!nscp->SCp.have_data_in) - nscp->SCp.have_data_in++; + if (!nscp_cmndinfo->wait_for_completion) + nscp_cmndinfo->wait_for_completion++; else - nscp->scsi_done(nscp); + gdth_scsi_done(nscp); } else { switch (nscp->cmnd[0]) { case TEST_UNIT_READY: @@ -2547,12 +2251,12 @@ static void gdth_next(int hanum) nscp->sense_buffer[0] = 0x70; nscp->sense_buffer[2] = UNIT_ATTENTION; nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); - if (!nscp->SCp.have_data_in) - nscp->SCp.have_data_in++; + if (!nscp_cmndinfo->wait_for_completion) + nscp_cmndinfo->wait_for_completion++; else - nscp->scsi_done(nscp); - } else if (gdth_internal_cache_cmd(hanum,nscp)) - nscp->scsi_done(nscp); + gdth_scsi_done(nscp); + } else if (gdth_internal_cache_cmd(ha, nscp)) + gdth_scsi_done(nscp); break; case ALLOW_MEDIUM_REMOVAL: @@ -2563,15 +2267,15 @@ static void gdth_next(int hanum) TRACE(("Prevent r. nonremov. drive->do nothing\n")); nscp->result = DID_OK << 16; nscp->sense_buffer[0] = 0; - if (!nscp->SCp.have_data_in) - nscp->SCp.have_data_in++; + if (!nscp_cmndinfo->wait_for_completion) + nscp_cmndinfo->wait_for_completion++; else - nscp->scsi_done(nscp); + gdth_scsi_done(nscp); } else { nscp->cmnd[3] = (ha->hdr[t].devtype&1) ? 1:0; TRACE(("Prevent/allow r. %d rem. drive %d\n", nscp->cmnd[4],nscp->cmnd[3])); - if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t))) + if (!(cmd_index=gdth_fill_cache_cmd(ha, nscp, t))) this_cmd = FALSE; } break; @@ -2580,7 +2284,7 @@ static void gdth_next(int hanum) case RELEASE: TRACE2(("cache cmd %s\n",nscp->cmnd[0] == RESERVE ? "RESERVE" : "RELEASE")); - if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t))) + if (!(cmd_index=gdth_fill_cache_cmd(ha, nscp, t))) this_cmd = FALSE; break; @@ -2599,11 +2303,11 @@ static void gdth_next(int hanum) nscp->sense_buffer[0] = 0x70; nscp->sense_buffer[2] = UNIT_ATTENTION; nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); - if (!nscp->SCp.have_data_in) - nscp->SCp.have_data_in++; + if (!nscp_cmndinfo->wait_for_completion) + nscp_cmndinfo->wait_for_completion++; else - nscp->scsi_done(nscp); - } else if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t))) + gdth_scsi_done(nscp); + } else if (!(cmd_index=gdth_fill_cache_cmd(ha, nscp, t))) this_cmd = FALSE; break; @@ -2612,12 +2316,12 @@ static void gdth_next(int hanum) nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3], nscp->cmnd[4],nscp->cmnd[5])); printk("GDT-HA %d: Unknown SCSI command 0x%x to cache service !\n", - hanum, nscp->cmnd[0]); + ha->hanum, nscp->cmnd[0]); nscp->result = DID_ABORT << 16; - if (!nscp->SCp.have_data_in) - nscp->SCp.have_data_in++; + if (!nscp_cmndinfo->wait_for_completion) + nscp_cmndinfo->wait_for_completion++; else - nscp->scsi_done(nscp); + gdth_scsi_done(nscp); break; } } @@ -2633,79 +2337,77 @@ static void gdth_next(int hanum) } if (ha->cmd_cnt > 0) { - gdth_release_event(hanum); + gdth_release_event(ha); } if (!gdth_polling) spin_unlock_irqrestore(&ha->smp_lock, flags); if (gdth_polling && ha->cmd_cnt > 0) { - if (!gdth_wait(hanum,cmd_index,POLL_TIMEOUT)) + if (!gdth_wait(ha, cmd_index, POLL_TIMEOUT)) printk("GDT-HA %d: Command %d timed out !\n", - hanum,cmd_index); + ha->hanum, cmd_index); } } - -static void gdth_copy_internal_data(int hanum,Scsi_Cmnd *scp, - char *buffer,ushort count) + +/* + * gdth_copy_internal_data() - copy to/from a buffer onto a scsi_cmnd's + * buffers, kmap_atomic() as needed. + */ +static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp, + char *buffer, ushort count, int to_buffer) { - ushort cpcount,i; + ushort cpcount,i, max_sg = gdth_sg_count(scp); ushort cpsum,cpnow; struct scatterlist *sl; - gdth_ha_str *ha; char *address; - cpcount = count<=(ushort)scp->request_bufflen ? count:(ushort)scp->request_bufflen; - ha = HADATA(gdth_ctr_tab[hanum]); + cpcount = min_t(ushort, count, gdth_bufflen(scp)); - if (scp->use_sg) { - sl = (struct scatterlist *)scp->request_buffer; - for (i=0,cpsum=0; i<scp->use_sg; ++i,++sl) { + if (cpcount) { + cpsum=0; + scsi_for_each_sg(scp, sl, max_sg, i) { unsigned long flags; cpnow = (ushort)sl->length; TRACE(("copy_internal() now %d sum %d count %d %d\n", - cpnow,cpsum,cpcount,(ushort)scp->bufflen)); + cpnow, cpsum, cpcount, gdth_bufflen(scp))); if (cpsum+cpnow > cpcount) cpnow = cpcount - cpsum; cpsum += cpnow; if (!sl->page) { printk("GDT-HA %d: invalid sc/gt element in gdth_copy_internal_data()\n", - hanum); + ha->hanum); return; } local_irq_save(flags); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) address = kmap_atomic(sl->page, KM_BIO_SRC_IRQ) + sl->offset; - memcpy(address,buffer,cpnow); + if (to_buffer) + memcpy(buffer, address, cpnow); + else + memcpy(address, buffer, cpnow); flush_dcache_page(sl->page); kunmap_atomic(address, KM_BIO_SRC_IRQ); -#else - address = kmap_atomic(sl->page, KM_BH_IRQ) + sl->offset; - memcpy(address,buffer,cpnow); - flush_dcache_page(sl->page); - kunmap_atomic(address, KM_BH_IRQ); -#endif local_irq_restore(flags); if (cpsum == cpcount) break; buffer += cpnow; } - } else { - TRACE(("copy_internal() count %d\n",cpcount)); - memcpy((char*)scp->request_buffer,buffer,cpcount); + } else if (count) { + printk("GDT-HA %d: SCSI command with no buffers but data transfer expected!\n", + ha->hanum); + WARN_ON(1); } } -static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp) +static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp) { - register gdth_ha_str *ha; unchar t; gdth_inq_data inq; gdth_rdcap_data rdc; gdth_sense_data sd; gdth_modep_data mpd; + struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); - ha = HADATA(gdth_ctr_tab[hanum]); t = scp->device->id; TRACE(("gdth_internal_cache_cmd() cmd 0x%x hdrive %d\n", scp->cmnd[0],t)); @@ -2736,7 +2438,7 @@ static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp) strcpy(inq.vendor,ha->oem_name); sprintf(inq.product,"Host Drive #%02d",t); strcpy(inq.revision," "); - gdth_copy_internal_data(hanum,scp,(char*)&inq,sizeof(gdth_inq_data)); + gdth_copy_internal_data(ha, scp, (char*)&inq, sizeof(gdth_inq_data), 0); break; case REQUEST_SENSE: @@ -2746,7 +2448,7 @@ static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp) sd.key = NO_SENSE; sd.info = 0; sd.add_length= 0; - gdth_copy_internal_data(hanum,scp,(char*)&sd,sizeof(gdth_sense_data)); + gdth_copy_internal_data(ha, scp, (char*)&sd, sizeof(gdth_sense_data), 0); break; case MODE_SENSE: @@ -2758,7 +2460,7 @@ static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp) mpd.bd.block_length[0] = (SECTOR_SIZE & 0x00ff0000) >> 16; mpd.bd.block_length[1] = (SECTOR_SIZE & 0x0000ff00) >> 8; mpd.bd.block_length[2] = (SECTOR_SIZE & 0x000000ff); - gdth_copy_internal_data(hanum,scp,(char*)&mpd,sizeof(gdth_modep_data)); + gdth_copy_internal_data(ha, scp, (char*)&mpd, sizeof(gdth_modep_data), 0); break; case READ_CAPACITY: @@ -2768,7 +2470,7 @@ static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp) else rdc.last_block_no = cpu_to_be32(ha->hdr[t].size-1); rdc.block_length = cpu_to_be32(SECTOR_SIZE); - gdth_copy_internal_data(hanum,scp,(char*)&rdc,sizeof(gdth_rdcap_data)); + gdth_copy_internal_data(ha, scp, (char*)&rdc, sizeof(gdth_rdcap_data), 0); break; case SERVICE_ACTION_IN: @@ -2779,7 +2481,8 @@ static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp) TRACE2(("Read capacity (16) hdrive %d\n",t)); rdc16.last_block_no = cpu_to_be64(ha->hdr[t].size-1); rdc16.block_length = cpu_to_be32(SECTOR_SIZE); - gdth_copy_internal_data(hanum,scp,(char*)&rdc16,sizeof(gdth_rdcap16_data)); + gdth_copy_internal_data(ha, scp, (char*)&rdc16, + sizeof(gdth_rdcap16_data), 0); } else { scp->result = DID_ABORT << 16; } @@ -2790,27 +2493,22 @@ static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp) break; } - if (!scp->SCp.have_data_in) - scp->SCp.have_data_in++; + if (!cmndinfo->wait_for_completion) + cmndinfo->wait_for_completion++; else return 1; return 0; } - -static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive) + +static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive) { - register gdth_ha_str *ha; register gdth_cmd_str *cmdp; - struct scatterlist *sl; + struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); ulong32 cnt, blockcnt; ulong64 no, blockno; - dma_addr_t phys_addr; int i, cmd_index, read_write, sgcnt, mode64; - struct page *page; - ulong offset; - ha = HADATA(gdth_ctr_tab[hanum]); cmdp = ha->pccb; TRACE(("gdth_fill_cache_cmd() cmd 0x%x cmdsize %d hdrive %d\n", scp->cmnd[0],scp->cmd_len,hdrive)); @@ -2826,18 +2524,18 @@ static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive) cmdp->Service = CACHESERVICE; cmdp->RequestBuffer = scp; /* search free command index */ - if (!(cmd_index=gdth_get_cmd_index(hanum))) { + if (!(cmd_index=gdth_get_cmd_index(ha))) { TRACE(("GDT: No free command index found\n")); return 0; } /* if it's the first command, set command semaphore */ if (ha->cmd_cnt == 0) - gdth_set_sema0(hanum); + gdth_set_sema0(ha); /* fill command */ read_write = 0; - if (scp->SCp.sent_command != -1) - cmdp->OpCode = scp->SCp.sent_command; /* special cache cmd. */ + if (cmndinfo->OpCode != -1) + cmdp->OpCode = cmndinfo->OpCode; /* special cache cmd. */ else if (scp->cmnd[0] == RESERVE) cmdp->OpCode = GDT_RESERVE_DRV; else if (scp->cmnd[0] == RELEASE) @@ -2898,17 +2596,17 @@ static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive) cmdp->u.cache.BlockCnt = blockcnt; } - if (scp->use_sg) { - sl = (struct scatterlist *)scp->request_buffer; - sgcnt = scp->use_sg; - scp->SCp.Status = GDTH_MAP_SG; - scp->SCp.Message = (read_write == 1 ? + if (gdth_bufflen(scp)) { + cmndinfo->dma_dir = (read_write == 1 ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); - sgcnt = pci_map_sg(ha->pdev,sl,scp->use_sg,scp->SCp.Message); + sgcnt = pci_map_sg(ha->pdev, gdth_sglist(scp), gdth_sg_count(scp), + cmndinfo->dma_dir); if (mode64) { + struct scatterlist *sl; + cmdp->u.cache64.DestAddr= (ulong64)-1; cmdp->u.cache64.sg_canz = sgcnt; - for (i=0; i<sgcnt; ++i,++sl) { + scsi_for_each_sg(scp, sl, sgcnt, i) { cmdp->u.cache64.sg_lst[i].sg_ptr = sg_dma_address(sl); #ifdef GDTH_DMA_STATISTICS if (cmdp->u.cache64.sg_lst[i].sg_ptr > (ulong64)0xffffffff) @@ -2919,9 +2617,11 @@ static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive) cmdp->u.cache64.sg_lst[i].sg_len = sg_dma_len(sl); } } else { + struct scatterlist *sl; + cmdp->u.cache.DestAddr= 0xffffffff; cmdp->u.cache.sg_canz = sgcnt; - for (i=0; i<sgcnt; ++i,++sl) { + scsi_for_each_sg(scp, sl, sgcnt, i) { cmdp->u.cache.sg_lst[i].sg_ptr = sg_dma_address(sl); #ifdef GDTH_DMA_STATISTICS ha->dma32_cnt++; @@ -2937,38 +2637,6 @@ static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive) } #endif - } else if (scp->request_bufflen) { - scp->SCp.Status = GDTH_MAP_SINGLE; - scp->SCp.Message = (read_write == 1 ? - PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); - page = virt_to_page(scp->request_buffer); - offset = (ulong)scp->request_buffer & ~PAGE_MASK; - phys_addr = pci_map_page(ha->pdev,page,offset, - scp->request_bufflen,scp->SCp.Message); - scp->SCp.dma_handle = phys_addr; - if (mode64) { - if (ha->cache_feat & SCATTER_GATHER) { - cmdp->u.cache64.DestAddr = (ulong64)-1; - cmdp->u.cache64.sg_canz = 1; - cmdp->u.cache64.sg_lst[0].sg_ptr = phys_addr; - cmdp->u.cache64.sg_lst[0].sg_len = scp->request_bufflen; - cmdp->u.cache64.sg_lst[1].sg_len = 0; - } else { - cmdp->u.cache64.DestAddr = phys_addr; - cmdp->u.cache64.sg_canz= 0; - } - } else { - if (ha->cache_feat & SCATTER_GATHER) { - cmdp->u.cache.DestAddr = 0xffffffff; - cmdp->u.cache.sg_canz = 1; - cmdp->u.cache.sg_lst[0].sg_ptr = phys_addr; - cmdp->u.cache.sg_lst[0].sg_len = scp->request_bufflen; - cmdp->u.cache.sg_lst[1].sg_len = 0; - } else { - cmdp->u.cache.DestAddr = phys_addr; - cmdp->u.cache.sg_canz= 0; - } - } } } /* evaluate command size, check space */ @@ -3004,23 +2672,21 @@ static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive) } /* copy command */ - gdth_copy_command(hanum); + gdth_copy_command(ha); return cmd_index; } -static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b) +static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b) { - register gdth_ha_str *ha; register gdth_cmd_str *cmdp; - struct scatterlist *sl; ushort i; - dma_addr_t phys_addr, sense_paddr; + dma_addr_t sense_paddr; int cmd_index, sgcnt, mode64; unchar t,l; struct page *page; ulong offset; + struct gdth_cmndinfo *cmndinfo; - ha = HADATA(gdth_ctr_tab[hanum]); t = scp->device->id; l = scp->device->lun; cmdp = ha->pccb; @@ -3035,26 +2701,27 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b) cmdp->Service = SCSIRAWSERVICE; cmdp->RequestBuffer = scp; /* search free command index */ - if (!(cmd_index=gdth_get_cmd_index(hanum))) { + if (!(cmd_index=gdth_get_cmd_index(ha))) { TRACE(("GDT: No free command index found\n")); return 0; } /* if it's the first command, set command semaphore */ if (ha->cmd_cnt == 0) - gdth_set_sema0(hanum); + gdth_set_sema0(ha); + cmndinfo = gdth_cmnd_priv(scp); /* fill command */ - if (scp->SCp.sent_command != -1) { - cmdp->OpCode = scp->SCp.sent_command; /* special raw cmd. */ + if (cmndinfo->OpCode != -1) { + cmdp->OpCode = cmndinfo->OpCode; /* special raw cmd. */ cmdp->BoardNode = LOCALBOARD; if (mode64) { - cmdp->u.raw64.direction = (scp->SCp.phase >> 8); + cmdp->u.raw64.direction = (cmndinfo->phase >> 8); TRACE2(("special raw cmd 0x%x param 0x%x\n", cmdp->OpCode, cmdp->u.raw64.direction)); /* evaluate command size */ ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw64.sg_lst); } else { - cmdp->u.raw.direction = (scp->SCp.phase >> 8); + cmdp->u.raw.direction = (cmndinfo->phase >> 8); TRACE2(("special raw cmd 0x%x param 0x%x\n", cmdp->OpCode, cmdp->u.raw.direction)); /* evaluate command size */ @@ -3066,9 +2733,8 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b) offset = (ulong)scp->sense_buffer & ~PAGE_MASK; sense_paddr = pci_map_page(ha->pdev,page,offset, 16,PCI_DMA_FROMDEVICE); - *(ulong32 *)&scp->SCp.buffer = (ulong32)sense_paddr; - /* high part, if 64bit */ - *(ulong32 *)&scp->host_scribble = (ulong32)((ulong64)sense_paddr >> 32); + + cmndinfo->sense_paddr = sense_paddr; cmdp->OpCode = GDT_WRITE; /* always */ cmdp->BoardNode = LOCALBOARD; if (mode64) { @@ -3080,7 +2746,7 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b) cmdp->u.raw64.lun = l; cmdp->u.raw64.bus = b; cmdp->u.raw64.priority = 0; - cmdp->u.raw64.sdlen = scp->request_bufflen; + cmdp->u.raw64.sdlen = gdth_bufflen(scp); cmdp->u.raw64.sense_len = 16; cmdp->u.raw64.sense_data = sense_paddr; cmdp->u.raw64.direction = @@ -3097,7 +2763,7 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b) cmdp->u.raw.bus = b; cmdp->u.raw.priority = 0; cmdp->u.raw.link_p = 0; - cmdp->u.raw.sdlen = scp->request_bufflen; + cmdp->u.raw.sdlen = gdth_bufflen(scp); cmdp->u.raw.sense_len = 16; cmdp->u.raw.sense_data = sense_paddr; cmdp->u.raw.direction = @@ -3106,16 +2772,16 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b) cmdp->u.raw.sg_ranz = 0; } - if (scp->use_sg) { - sl = (struct scatterlist *)scp->request_buffer; - sgcnt = scp->use_sg; - scp->SCp.Status = GDTH_MAP_SG; - scp->SCp.Message = PCI_DMA_BIDIRECTIONAL; - sgcnt = pci_map_sg(ha->pdev,sl,scp->use_sg,scp->SCp.Message); + if (gdth_bufflen(scp)) { + cmndinfo->dma_dir = PCI_DMA_BIDIRECTIONAL; + sgcnt = pci_map_sg(ha->pdev, gdth_sglist(scp), gdth_sg_count(scp), + cmndinfo->dma_dir); if (mode64) { + struct scatterlist *sl; + cmdp->u.raw64.sdata = (ulong64)-1; cmdp->u.raw64.sg_ranz = sgcnt; - for (i=0; i<sgcnt; ++i,++sl) { + scsi_for_each_sg(scp, sl, sgcnt, i) { cmdp->u.raw64.sg_lst[i].sg_ptr = sg_dma_address(sl); #ifdef GDTH_DMA_STATISTICS if (cmdp->u.raw64.sg_lst[i].sg_ptr > (ulong64)0xffffffff) @@ -3126,9 +2792,11 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b) cmdp->u.raw64.sg_lst[i].sg_len = sg_dma_len(sl); } } else { + struct scatterlist *sl; + cmdp->u.raw.sdata = 0xffffffff; cmdp->u.raw.sg_ranz = sgcnt; - for (i=0; i<sgcnt; ++i,++sl) { + scsi_for_each_sg(scp, sl, sgcnt, i) { cmdp->u.raw.sg_lst[i].sg_ptr = sg_dma_address(sl); #ifdef GDTH_DMA_STATISTICS ha->dma32_cnt++; @@ -3144,38 +2812,6 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b) } #endif - } else if (scp->request_bufflen) { - scp->SCp.Status = GDTH_MAP_SINGLE; - scp->SCp.Message = PCI_DMA_BIDIRECTIONAL; - page = virt_to_page(scp->request_buffer); - offset = (ulong)scp->request_buffer & ~PAGE_MASK; - phys_addr = pci_map_page(ha->pdev,page,offset, - scp->request_bufflen,scp->SCp.Message); - scp->SCp.dma_handle = phys_addr; - - if (mode64) { - if (ha->raw_feat & SCATTER_GATHER) { - cmdp->u.raw64.sdata = (ulong64)-1; - cmdp->u.raw64.sg_ranz= 1; - cmdp->u.raw64.sg_lst[0].sg_ptr = phys_addr; - cmdp->u.raw64.sg_lst[0].sg_len = scp->request_bufflen; - cmdp->u.raw64.sg_lst[1].sg_len = 0; - } else { - cmdp->u.raw64.sdata = phys_addr; - cmdp->u.raw64.sg_ranz= 0; - } - } else { - if (ha->raw_feat & SCATTER_GATHER) { - cmdp->u.raw.sdata = 0xffffffff; - cmdp->u.raw.sg_ranz= 1; - cmdp->u.raw.sg_lst[0].sg_ptr = phys_addr; - cmdp->u.raw.sg_lst[0].sg_len = scp->request_bufflen; - cmdp->u.raw.sg_lst[1].sg_len = 0; - } else { - cmdp->u.raw.sdata = phys_addr; - cmdp->u.raw.sg_ranz= 0; - } - } } if (mode64) { TRACE(("raw cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n", @@ -3209,35 +2845,33 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b) } /* copy command */ - gdth_copy_command(hanum); + gdth_copy_command(ha); return cmd_index; } -static int gdth_special_cmd(int hanum,Scsi_Cmnd *scp) +static int gdth_special_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp) { - register gdth_ha_str *ha; register gdth_cmd_str *cmdp; int cmd_index; - ha = HADATA(gdth_ctr_tab[hanum]); cmdp= ha->pccb; TRACE2(("gdth_special_cmd(): ")); if (ha->type==GDT_EISA && ha->cmd_cnt>0) return 0; - memcpy( cmdp, scp->request_buffer, sizeof(gdth_cmd_str)); + gdth_copy_internal_data(ha, scp, (char *)cmdp, sizeof(gdth_cmd_str), 1); cmdp->RequestBuffer = scp; /* search free command index */ - if (!(cmd_index=gdth_get_cmd_index(hanum))) { + if (!(cmd_index=gdth_get_cmd_index(ha))) { TRACE(("GDT: No free command index found\n")); return 0; } /* if it's the first command, set command semaphore */ if (ha->cmd_cnt == 0) - gdth_set_sema0(hanum); + gdth_set_sema0(ha); /* evaluate command size, check space */ if (cmdp->OpCode == GDT_IOCTL) { @@ -3275,7 +2909,7 @@ static int gdth_special_cmd(int hanum,Scsi_Cmnd *scp) } /* copy command */ - gdth_copy_command(hanum); + gdth_copy_command(ha); return cmd_index; } @@ -3402,15 +3036,14 @@ static void gdth_clear_events(void) /* SCSI interface functions */ -static irqreturn_t gdth_interrupt(int irq,void *dev_id) +static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq, + int gdth_from_wait, int* pIndex) { - gdth_ha_str *ha2 = (gdth_ha_str *)dev_id; - register gdth_ha_str *ha; gdt6m_dpram_str __iomem *dp6m_ptr = NULL; gdt6_dpram_str __iomem *dp6_ptr; gdt2_dpram_str __iomem *dp2_ptr; Scsi_Cmnd *scp; - int hanum, rval, i; + int rval, i; unchar IStatus; ushort Service; ulong flags = 0; @@ -3431,17 +3064,15 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id) } if (!gdth_polling) - spin_lock_irqsave(&ha2->smp_lock, flags); - wait_index = 0; + spin_lock_irqsave(&ha->smp_lock, flags); /* search controller */ - if ((hanum = gdth_get_status(&IStatus,irq)) == -1) { + if (0 == (IStatus = gdth_get_status(ha, irq))) { /* spurious interrupt */ if (!gdth_polling) - spin_unlock_irqrestore(&ha2->smp_lock, flags); - return IRQ_HANDLED; + spin_unlock_irqrestore(&ha->smp_lock, flags); + return IRQ_HANDLED; } - ha = HADATA(gdth_ctr_tab[hanum]); #ifdef GDTH_STATISTICS ++act_ints; @@ -3482,32 +3113,32 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id) dp2_ptr = ha->brd; if (IStatus & 0x80) { /* error flag */ IStatus &= ~0x80; - ha->status = gdth_readw(&dp2_ptr->u.ic.Status); + ha->status = readw(&dp2_ptr->u.ic.Status); TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status)); } else /* no error */ ha->status = S_OK; - ha->info = gdth_readl(&dp2_ptr->u.ic.Info[0]); - ha->service = gdth_readw(&dp2_ptr->u.ic.Service); - ha->info2 = gdth_readl(&dp2_ptr->u.ic.Info[1]); + ha->info = readl(&dp2_ptr->u.ic.Info[0]); + ha->service = readw(&dp2_ptr->u.ic.Service); + ha->info2 = readl(&dp2_ptr->u.ic.Info[1]); - gdth_writeb(0xff, &dp2_ptr->io.irqdel); /* acknowledge interrupt */ - gdth_writeb(0, &dp2_ptr->u.ic.Cmd_Index);/* reset command index */ - gdth_writeb(0, &dp2_ptr->io.Sema1); /* reset status semaphore */ + writeb(0xff, &dp2_ptr->io.irqdel); /* acknowledge interrupt */ + writeb(0, &dp2_ptr->u.ic.Cmd_Index);/* reset command index */ + writeb(0, &dp2_ptr->io.Sema1); /* reset status semaphore */ } else if (ha->type == GDT_PCI) { dp6_ptr = ha->brd; if (IStatus & 0x80) { /* error flag */ IStatus &= ~0x80; - ha->status = gdth_readw(&dp6_ptr->u.ic.Status); + ha->status = readw(&dp6_ptr->u.ic.Status); TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status)); } else /* no error */ ha->status = S_OK; - ha->info = gdth_readl(&dp6_ptr->u.ic.Info[0]); - ha->service = gdth_readw(&dp6_ptr->u.ic.Service); - ha->info2 = gdth_readl(&dp6_ptr->u.ic.Info[1]); + ha->info = readl(&dp6_ptr->u.ic.Info[0]); + ha->service = readw(&dp6_ptr->u.ic.Service); + ha->info2 = readl(&dp6_ptr->u.ic.Info[1]); - gdth_writeb(0xff, &dp6_ptr->io.irqdel); /* acknowledge interrupt */ - gdth_writeb(0, &dp6_ptr->u.ic.Cmd_Index);/* reset command index */ - gdth_writeb(0, &dp6_ptr->io.Sema1); /* reset status semaphore */ + writeb(0xff, &dp6_ptr->io.irqdel); /* acknowledge interrupt */ + writeb(0, &dp6_ptr->u.ic.Cmd_Index);/* reset command index */ + writeb(0, &dp6_ptr->io.Sema1); /* reset status semaphore */ } else if (ha->type == GDT_PCINEW) { if (IStatus & 0x80) { /* error flag */ IStatus &= ~0x80; @@ -3530,7 +3161,7 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id) ha->status = pcs->ext_status & 0xffff; else #endif - ha->status = gdth_readw(&dp6m_ptr->i960r.status); + ha->status = readw(&dp6m_ptr->i960r.status); TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status)); } else /* no error */ ha->status = S_OK; @@ -3543,18 +3174,18 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id) } else #endif { - ha->info = gdth_readl(&dp6m_ptr->i960r.info[0]); - ha->service = gdth_readw(&dp6m_ptr->i960r.service); - ha->info2 = gdth_readl(&dp6m_ptr->i960r.info[1]); + ha->info = readl(&dp6m_ptr->i960r.info[0]); + ha->service = readw(&dp6m_ptr->i960r.service); + ha->info2 = readl(&dp6m_ptr->i960r.info[1]); } /* event string */ if (IStatus == ASYNCINDEX) { if (ha->service != SCREENSERVICE && (ha->fw_vers & 0xff) >= 0x1a) { - ha->dvr.severity = gdth_readb + ha->dvr.severity = readb (&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.severity); for (i = 0; i < 256; ++i) { - ha->dvr.event_string[i] = gdth_readb + ha->dvr.event_string[i] = readb (&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.evt_str[i]); if (ha->dvr.event_string[i] == 0) break; @@ -3567,13 +3198,13 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id) if (!coalesced) #endif { - gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg); - gdth_writeb(0, &dp6m_ptr->i960r.sema1_reg); + writeb(0xff, &dp6m_ptr->i960r.edoor_reg); + writeb(0, &dp6m_ptr->i960r.sema1_reg); } } else { TRACE2(("gdth_interrupt() unknown controller type\n")); if (!gdth_polling) - spin_unlock_irqrestore(&ha2->smp_lock, flags); + spin_unlock_irqrestore(&ha->smp_lock, flags); return IRQ_HANDLED; } @@ -3581,26 +3212,25 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id) IStatus,ha->status,ha->info)); if (gdth_from_wait) { - wait_hanum = hanum; - wait_index = (int)IStatus; + *pIndex = (int)IStatus; } if (IStatus == ASYNCINDEX) { TRACE2(("gdth_interrupt() async. event\n")); - gdth_async_event(hanum); + gdth_async_event(ha); if (!gdth_polling) - spin_unlock_irqrestore(&ha2->smp_lock, flags); - gdth_next(hanum); + spin_unlock_irqrestore(&ha->smp_lock, flags); + gdth_next(ha); return IRQ_HANDLED; } if (IStatus == SPEZINDEX) { TRACE2(("Service unknown or not initialized !\n")); ha->dvr.size = sizeof(ha->dvr.eu.driver); - ha->dvr.eu.driver.ionode = hanum; + ha->dvr.eu.driver.ionode = ha->hanum; gdth_store_event(ha, ES_DRIVER, 4, &ha->dvr); if (!gdth_polling) - spin_unlock_irqrestore(&ha2->smp_lock, flags); + spin_unlock_irqrestore(&ha->smp_lock, flags); return IRQ_HANDLED; } scp = ha->cmd_tab[IStatus-2].cmnd; @@ -3609,28 +3239,28 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id) if (scp == UNUSED_CMND) { TRACE2(("gdth_interrupt() index to unused command (%d)\n",IStatus)); ha->dvr.size = sizeof(ha->dvr.eu.driver); - ha->dvr.eu.driver.ionode = hanum; + ha->dvr.eu.driver.ionode = ha->hanum; ha->dvr.eu.driver.index = IStatus; gdth_store_event(ha, ES_DRIVER, 1, &ha->dvr); if (!gdth_polling) - spin_unlock_irqrestore(&ha2->smp_lock, flags); + spin_unlock_irqrestore(&ha->smp_lock, flags); return IRQ_HANDLED; } if (scp == INTERNAL_CMND) { TRACE(("gdth_interrupt() answer to internal command\n")); if (!gdth_polling) - spin_unlock_irqrestore(&ha2->smp_lock, flags); + spin_unlock_irqrestore(&ha->smp_lock, flags); return IRQ_HANDLED; } TRACE(("gdth_interrupt() sync. status\n")); - rval = gdth_sync_event(hanum,Service,IStatus,scp); + rval = gdth_sync_event(ha,Service,IStatus,scp); if (!gdth_polling) - spin_unlock_irqrestore(&ha2->smp_lock, flags); + spin_unlock_irqrestore(&ha->smp_lock, flags); if (rval == 2) { - gdth_putq(hanum,scp,scp->SCp.this_residual); + gdth_putq(ha, scp, gdth_cmnd_priv(scp)->priority); } else if (rval == 1) { - scp->scsi_done(scp); + gdth_scsi_done(scp); } #ifdef INT_COAL @@ -3653,23 +3283,30 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id) /* coalescing only for new GDT_PCIMPR controllers available */ if (ha->type == GDT_PCIMPR && coalesced) { - gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg); - gdth_writeb(0, &dp6m_ptr->i960r.sema1_reg); + writeb(0xff, &dp6m_ptr->i960r.edoor_reg); + writeb(0, &dp6m_ptr->i960r.sema1_reg); } #endif - gdth_next(hanum); + gdth_next(ha); return IRQ_HANDLED; } -static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp) +static irqreturn_t gdth_interrupt(int irq, void *dev_id) +{ + gdth_ha_str *ha = (gdth_ha_str *)dev_id; + + return __gdth_interrupt(ha, irq, false, NULL); +} + +static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index, + Scsi_Cmnd *scp) { - register gdth_ha_str *ha; gdth_msg_str *msg; gdth_cmd_str *cmdp; unchar b, t; + struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); - ha = HADATA(gdth_ctr_tab[hanum]); cmdp = ha->pccb; TRACE(("gdth_sync_event() serv %d status %d\n", service,ha->status)); @@ -3687,12 +3324,12 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp) } if (msg->msg_ext && !msg->msg_answer) { - while (gdth_test_busy(hanum)) + while (gdth_test_busy(ha)) gdth_delay(0); cmdp->Service = SCREENSERVICE; cmdp->RequestBuffer = SCREEN_CMND; - gdth_get_cmd_index(hanum); - gdth_set_sema0(hanum); + gdth_get_cmd_index(ha); + gdth_set_sema0(ha); cmdp->OpCode = GDT_READ; cmdp->BoardNode = LOCALBOARD; cmdp->u.screen.reserved = 0; @@ -3702,8 +3339,8 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp) ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) + sizeof(ulong64); ha->cmd_cnt = 0; - gdth_copy_command(hanum); - gdth_release_event(hanum); + gdth_copy_command(ha); + gdth_release_event(ha); return 0; } @@ -3721,12 +3358,12 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp) } msg->msg_ext = 0; msg->msg_answer = 0; - while (gdth_test_busy(hanum)) + while (gdth_test_busy(ha)) gdth_delay(0); cmdp->Service = SCREENSERVICE; cmdp->RequestBuffer = SCREEN_CMND; - gdth_get_cmd_index(hanum); - gdth_set_sema0(hanum); + gdth_get_cmd_index(ha); + gdth_set_sema0(ha); cmdp->OpCode = GDT_WRITE; cmdp->BoardNode = LOCALBOARD; cmdp->u.screen.reserved = 0; @@ -3736,74 +3373,67 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp) ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) + sizeof(ulong64); ha->cmd_cnt = 0; - gdth_copy_command(hanum); - gdth_release_event(hanum); + gdth_copy_command(ha); + gdth_release_event(ha); return 0; } printk("\n"); } else { - b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel; + b = scp->device->channel; t = scp->device->id; - if (scp->SCp.sent_command == -1 && b != ha->virt_bus) { + if (cmndinfo->OpCode == -1 && b != ha->virt_bus) { ha->raw[BUS_L2P(ha,b)].io_cnt[t]--; } /* cache or raw service */ if (ha->status == S_BSY) { TRACE2(("Controller busy -> retry !\n")); - if (scp->SCp.sent_command == GDT_MOUNT) - scp->SCp.sent_command = GDT_CLUST_INFO; + if (cmndinfo->OpCode == GDT_MOUNT) + cmndinfo->OpCode = GDT_CLUST_INFO; /* retry */ return 2; } - if (scp->SCp.Status == GDTH_MAP_SG) - pci_unmap_sg(ha->pdev,scp->request_buffer, - scp->use_sg,scp->SCp.Message); - else if (scp->SCp.Status == GDTH_MAP_SINGLE) - pci_unmap_page(ha->pdev,scp->SCp.dma_handle, - scp->request_bufflen,scp->SCp.Message); - if (scp->SCp.buffer) { - dma_addr_t addr; - addr = (dma_addr_t)*(ulong32 *)&scp->SCp.buffer; - if (scp->host_scribble) - addr += (dma_addr_t) - ((ulong64)(*(ulong32 *)&scp->host_scribble) << 32); - pci_unmap_page(ha->pdev,addr,16,PCI_DMA_FROMDEVICE); - } + if (gdth_bufflen(scp)) + pci_unmap_sg(ha->pdev, gdth_sglist(scp), gdth_sg_count(scp), + cmndinfo->dma_dir); + + if (cmndinfo->sense_paddr) + pci_unmap_page(ha->pdev, cmndinfo->sense_paddr, 16, + PCI_DMA_FROMDEVICE); if (ha->status == S_OK) { - scp->SCp.Status = S_OK; - scp->SCp.Message = ha->info; - if (scp->SCp.sent_command != -1) { + cmndinfo->status = S_OK; + cmndinfo->info = ha->info; + if (cmndinfo->OpCode != -1) { TRACE2(("gdth_sync_event(): special cmd 0x%x OK\n", - scp->SCp.sent_command)); + cmndinfo->OpCode)); /* special commands GDT_CLUST_INFO/GDT_MOUNT ? */ - if (scp->SCp.sent_command == GDT_CLUST_INFO) { + if (cmndinfo->OpCode == GDT_CLUST_INFO) { ha->hdr[t].cluster_type = (unchar)ha->info; if (!(ha->hdr[t].cluster_type & CLUSTER_MOUNTED)) { /* NOT MOUNTED -> MOUNT */ - scp->SCp.sent_command = GDT_MOUNT; + cmndinfo->OpCode = GDT_MOUNT; if (ha->hdr[t].cluster_type & CLUSTER_RESERVED) { /* cluster drive RESERVED (on the other node) */ - scp->SCp.phase = -2; /* reservation conflict */ + cmndinfo->phase = -2; /* reservation conflict */ } } else { - scp->SCp.sent_command = -1; + cmndinfo->OpCode = -1; } } else { - if (scp->SCp.sent_command == GDT_MOUNT) { + if (cmndinfo->OpCode == GDT_MOUNT) { ha->hdr[t].cluster_type |= CLUSTER_MOUNTED; ha->hdr[t].media_changed = TRUE; - } else if (scp->SCp.sent_command == GDT_UNMOUNT) { + } else if (cmndinfo->OpCode == GDT_UNMOUNT) { ha->hdr[t].cluster_type &= ~CLUSTER_MOUNTED; ha->hdr[t].media_changed = TRUE; } - scp->SCp.sent_command = -1; + cmndinfo->OpCode = -1; } /* retry */ - scp->SCp.this_residual = HIGH_PRI; + cmndinfo->priority = HIGH_PRI; return 2; } else { /* RESERVE/RELEASE ? */ @@ -3816,17 +3446,17 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp) scp->sense_buffer[0] = 0; } } else { - scp->SCp.Status = ha->status; - scp->SCp.Message = ha->info; + cmndinfo->status = ha->status; + cmndinfo->info = ha->info; - if (scp->SCp.sent_command != -1) { + if (cmndinfo->OpCode != -1) { TRACE2(("gdth_sync_event(): special cmd 0x%x error 0x%x\n", - scp->SCp.sent_command, ha->status)); - if (scp->SCp.sent_command == GDT_SCAN_START || - scp->SCp.sent_command == GDT_SCAN_END) { - scp->SCp.sent_command = -1; + cmndinfo->OpCode, ha->status)); + if (cmndinfo->OpCode == GDT_SCAN_START || + cmndinfo->OpCode == GDT_SCAN_END) { + cmndinfo->OpCode = -1; /* retry */ - scp->SCp.this_residual = HIGH_PRI; + cmndinfo->priority = HIGH_PRI; return 2; } memset((char*)scp->sense_buffer,0,16); @@ -3848,9 +3478,9 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp) scp->sense_buffer[2] = NOT_READY; scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); } - if (scp->done != gdth_scsi_done) { + if (!cmndinfo->internal_command) { ha->dvr.size = sizeof(ha->dvr.eu.sync); - ha->dvr.eu.sync.ionode = hanum; + ha->dvr.eu.sync.ionode = ha->hanum; ha->dvr.eu.sync.service = service; ha->dvr.eu.sync.status = ha->status; ha->dvr.eu.sync.info = ha->info; @@ -3869,8 +3499,8 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp) } } } - if (!scp->SCp.have_data_in) - scp->SCp.have_data_in++; + if (!cmndinfo->wait_for_completion) + cmndinfo->wait_for_completion++; else return 1; } @@ -4034,25 +3664,23 @@ static char *async_cache_tab[] = { }; -static int gdth_async_event(int hanum) +static int gdth_async_event(gdth_ha_str *ha) { - gdth_ha_str *ha; gdth_cmd_str *cmdp; int cmd_index; - ha = HADATA(gdth_ctr_tab[hanum]); cmdp= ha->pccb; TRACE2(("gdth_async_event() ha %d serv %d\n", - hanum,ha->service)); + ha->hanum, ha->service)); if (ha->service == SCREENSERVICE) { if (ha->status == MSG_REQUEST) { - while (gdth_test_busy(hanum)) + while (gdth_test_busy(ha)) gdth_delay(0); cmdp->Service = SCREENSERVICE; cmdp->RequestBuffer = SCREEN_CMND; - cmd_index = gdth_get_cmd_index(hanum); - gdth_set_sema0(hanum); + cmd_index = gdth_get_cmd_index(ha); + gdth_set_sema0(ha); cmdp->OpCode = GDT_READ; cmdp->BoardNode = LOCALBOARD; cmdp->u.screen.reserved = 0; @@ -4062,7 +3690,7 @@ static int gdth_async_event(int hanum) ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) + sizeof(ulong64); ha->cmd_cnt = 0; - gdth_copy_command(hanum); + gdth_copy_command(ha); if (ha->type == GDT_EISA) printk("[EISA slot %d] ",(ushort)ha->brd_phys); else if (ha->type == GDT_ISA) @@ -4070,19 +3698,19 @@ static int gdth_async_event(int hanum) else printk("[PCI %d/%d] ",(ushort)(ha->brd_phys>>8), (ushort)((ha->brd_phys>>3)&0x1f)); - gdth_release_event(hanum); + gdth_release_event(ha); } } else { if (ha->type == GDT_PCIMPR && (ha->fw_vers & 0xff) >= 0x1a) { ha->dvr.size = 0; - ha->dvr.eu.async.ionode = hanum; + ha->dvr.eu.async.ionode = ha->hanum; ha->dvr.eu.async.status = ha->status; /* severity and event_string already set! */ } else { ha->dvr.size = sizeof(ha->dvr.eu.async); - ha->dvr.eu.async.ionode = hanum; + ha->dvr.eu.async.ionode = ha->hanum; ha->dvr.eu.async.service = ha->service; ha->dvr.eu.async.status = ha->status; ha->dvr.eu.async.info = ha->info; @@ -4164,9 +3792,8 @@ static void gdth_timeout(ulong data) Scsi_Cmnd *nscp; gdth_ha_str *ha; ulong flags; - int hanum = 0; - ha = HADATA(gdth_ctr_tab[hanum]); + ha = list_first_entry(&gdth_instances, gdth_ha_str, list); spin_lock_irqsave(&ha->smp_lock, flags); for (act_stats=0,i=0; i<GDTH_MAXCMDS; ++i) @@ -4229,8 +3856,6 @@ static void __init internal_setup(char *str,int *ints) max_ids = val; else if (!strncmp(argv, "rescan:", 7)) rescan = val; - else if (!strncmp(argv, "virt_ctr:", 9)) - virt_ctr = val; else if (!strncmp(argv, "shared_access:", 14)) shared_access = val; else if (!strncmp(argv, "probe_eisa_isa:", 15)) @@ -4277,523 +3902,10 @@ int __init option_setup(char *str) return 1; } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) -static int __init gdth_detect(struct scsi_host_template *shtp) -#else -static int __init gdth_detect(Scsi_Host_Template *shtp) -#endif +static const char *gdth_ctr_name(gdth_ha_str *ha) { - struct Scsi_Host *shp; - gdth_pci_str pcistr[MAXHA]; - gdth_ha_str *ha; - ulong32 isa_bios; - ushort eisa_slot; - int i,hanum,cnt,ctr,err; - unchar b; - - -#ifdef DEBUG_GDTH - printk("GDT: This driver contains debugging information !! Trace level = %d\n", - DebugState); - printk(" Destination of debugging information: "); -#ifdef __SERIAL__ -#ifdef __COM2__ - printk("Serial port COM2\n"); -#else - printk("Serial port COM1\n"); -#endif -#else - printk("Console\n"); -#endif - gdth_delay(3000); -#endif - - TRACE(("gdth_detect()\n")); - - if (disable) { - printk("GDT-HA: Controller driver disabled from command line !\n"); - return 0; - } - - printk("GDT-HA: Storage RAID Controller Driver. Version: %s\n",GDTH_VERSION_STR); - /* initializations */ - gdth_polling = TRUE; b = 0; - gdth_clear_events(); - - /* As default we do not probe for EISA or ISA controllers */ - if (probe_eisa_isa) { - /* scanning for controllers, at first: ISA controller */ - for (isa_bios=0xc8000UL; isa_bios<=0xd8000UL; isa_bios+=0x8000UL) { - dma_addr_t scratch_dma_handle; - scratch_dma_handle = 0; - - if (gdth_ctr_count >= MAXHA) - break; - if (gdth_search_isa(isa_bios)) { /* controller found */ - shp = scsi_register(shtp,sizeof(gdth_ext_str)); - if (shp == NULL) - continue; - - ha = HADATA(shp); - if (!gdth_init_isa(isa_bios,ha)) { - scsi_unregister(shp); - continue; - } -#ifdef __ia64__ - break; -#else - /* controller found and initialized */ - printk("Configuring GDT-ISA HA at BIOS 0x%05X IRQ %u DRQ %u\n", - isa_bios,ha->irq,ha->drq); - - if (request_irq(ha->irq,gdth_interrupt,IRQF_DISABLED,"gdth",ha)) { - printk("GDT-ISA: Unable to allocate IRQ\n"); - scsi_unregister(shp); - continue; - } - if (request_dma(ha->drq,"gdth")) { - printk("GDT-ISA: Unable to allocate DMA channel\n"); - free_irq(ha->irq,ha); - scsi_unregister(shp); - continue; - } - set_dma_mode(ha->drq,DMA_MODE_CASCADE); - enable_dma(ha->drq); - shp->unchecked_isa_dma = 1; - shp->irq = ha->irq; - shp->dma_channel = ha->drq; - hanum = gdth_ctr_count; - gdth_ctr_tab[gdth_ctr_count++] = shp; - gdth_ctr_vtab[gdth_ctr_vcount++] = shp; - - NUMDATA(shp)->hanum = (ushort)hanum; - NUMDATA(shp)->busnum= 0; - - ha->pccb = CMDDATA(shp); - ha->ccb_phys = 0L; - ha->pdev = NULL; - ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH, - &scratch_dma_handle); - ha->scratch_phys = scratch_dma_handle; - ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str), - &scratch_dma_handle); - ha->msg_phys = scratch_dma_handle; -#ifdef INT_COAL - ha->coal_stat = (gdth_coal_status *) - pci_alloc_consistent(ha->pdev, sizeof(gdth_coal_status) * - MAXOFFSETS, &scratch_dma_handle); - ha->coal_stat_phys = scratch_dma_handle; -#endif - - ha->scratch_busy = FALSE; - ha->req_first = NULL; - ha->tid_cnt = MAX_HDRIVES; - if (max_ids > 0 && max_ids < ha->tid_cnt) - ha->tid_cnt = max_ids; - for (i=0; i<GDTH_MAXCMDS; ++i) - ha->cmd_tab[i].cmnd = UNUSED_CMND; - ha->scan_mode = rescan ? 0x10 : 0; - - if (ha->pscratch == NULL || ha->pmsg == NULL || - !gdth_search_drives(hanum)) { - printk("GDT-ISA: Error during device scan\n"); - --gdth_ctr_count; - --gdth_ctr_vcount; - -#ifdef INT_COAL - if (ha->coal_stat) - pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) * - MAXOFFSETS, ha->coal_stat, - ha->coal_stat_phys); -#endif - if (ha->pscratch) - pci_free_consistent(ha->pdev, GDTH_SCRATCH, - ha->pscratch, ha->scratch_phys); - if (ha->pmsg) - pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), - ha->pmsg, ha->msg_phys); - - free_irq(ha->irq,ha); - scsi_unregister(shp); - continue; - } - if (hdr_channel < 0 || hdr_channel > ha->bus_cnt) - hdr_channel = ha->bus_cnt; - ha->virt_bus = hdr_channel; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) && \ - LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - shp->highmem_io = 0; -#endif - if (ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT) - shp->max_cmd_len = 16; - - shp->max_id = ha->tid_cnt; - shp->max_lun = MAXLUN; - shp->max_channel = virt_ctr ? 0 : ha->bus_cnt; - if (virt_ctr) { - virt_ctr = 1; - /* register addit. SCSI channels as virtual controllers */ - for (b = 1; b < ha->bus_cnt + 1; ++b) { - shp = scsi_register(shtp,sizeof(gdth_num_str)); - shp->unchecked_isa_dma = 1; - shp->irq = ha->irq; - shp->dma_channel = ha->drq; - gdth_ctr_vtab[gdth_ctr_vcount++] = shp; - NUMDATA(shp)->hanum = (ushort)hanum; - NUMDATA(shp)->busnum = b; - } - } - - spin_lock_init(&ha->smp_lock); - gdth_enable_int(hanum); -#endif /* !__ia64__ */ - } - } - - /* scanning for EISA controllers */ - for (eisa_slot=0x1000; eisa_slot<=0x8000; eisa_slot+=0x1000) { - dma_addr_t scratch_dma_handle; - scratch_dma_handle = 0; - - if (gdth_ctr_count >= MAXHA) - break; - if (gdth_search_eisa(eisa_slot)) { /* controller found */ - shp = scsi_register(shtp,sizeof(gdth_ext_str)); - if (shp == NULL) - continue; - - ha = HADATA(shp); - if (!gdth_init_eisa(eisa_slot,ha)) { - scsi_unregister(shp); - continue; - } - /* controller found and initialized */ - printk("Configuring GDT-EISA HA at Slot %d IRQ %u\n", - eisa_slot>>12,ha->irq); - - if (request_irq(ha->irq,gdth_interrupt,IRQF_DISABLED,"gdth",ha)) { - printk("GDT-EISA: Unable to allocate IRQ\n"); - scsi_unregister(shp); - continue; - } - shp->unchecked_isa_dma = 0; - shp->irq = ha->irq; - shp->dma_channel = 0xff; - hanum = gdth_ctr_count; - gdth_ctr_tab[gdth_ctr_count++] = shp; - gdth_ctr_vtab[gdth_ctr_vcount++] = shp; - - NUMDATA(shp)->hanum = (ushort)hanum; - NUMDATA(shp)->busnum= 0; - TRACE2(("EISA detect Bus 0: hanum %d\n", - NUMDATA(shp)->hanum)); - - ha->pccb = CMDDATA(shp); - ha->ccb_phys = 0L; - - ha->pdev = NULL; - ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH, - &scratch_dma_handle); - ha->scratch_phys = scratch_dma_handle; - ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str), - &scratch_dma_handle); - ha->msg_phys = scratch_dma_handle; -#ifdef INT_COAL - ha->coal_stat = (gdth_coal_status *) - pci_alloc_consistent(ha->pdev, sizeof(gdth_coal_status) * - MAXOFFSETS, &scratch_dma_handle); - ha->coal_stat_phys = scratch_dma_handle; -#endif - ha->ccb_phys = - pci_map_single(ha->pdev,ha->pccb, - sizeof(gdth_cmd_str),PCI_DMA_BIDIRECTIONAL); - ha->scratch_busy = FALSE; - ha->req_first = NULL; - ha->tid_cnt = MAX_HDRIVES; - if (max_ids > 0 && max_ids < ha->tid_cnt) - ha->tid_cnt = max_ids; - for (i=0; i<GDTH_MAXCMDS; ++i) - ha->cmd_tab[i].cmnd = UNUSED_CMND; - ha->scan_mode = rescan ? 0x10 : 0; - - if (ha->pscratch == NULL || ha->pmsg == NULL || - !gdth_search_drives(hanum)) { - printk("GDT-EISA: Error during device scan\n"); - --gdth_ctr_count; - --gdth_ctr_vcount; -#ifdef INT_COAL - if (ha->coal_stat) - pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) * - MAXOFFSETS, ha->coal_stat, - ha->coal_stat_phys); -#endif - if (ha->pscratch) - pci_free_consistent(ha->pdev, GDTH_SCRATCH, - ha->pscratch, ha->scratch_phys); - if (ha->pmsg) - pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), - ha->pmsg, ha->msg_phys); - if (ha->ccb_phys) - pci_unmap_single(ha->pdev,ha->ccb_phys, - sizeof(gdth_cmd_str),PCI_DMA_BIDIRECTIONAL); - free_irq(ha->irq,ha); - scsi_unregister(shp); - continue; - } - if (hdr_channel < 0 || hdr_channel > ha->bus_cnt) - hdr_channel = ha->bus_cnt; - ha->virt_bus = hdr_channel; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) && \ - LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - shp->highmem_io = 0; -#endif - if (ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT) - shp->max_cmd_len = 16; - - shp->max_id = ha->tid_cnt; - shp->max_lun = MAXLUN; - shp->max_channel = virt_ctr ? 0 : ha->bus_cnt; - if (virt_ctr) { - virt_ctr = 1; - /* register addit. SCSI channels as virtual controllers */ - for (b = 1; b < ha->bus_cnt + 1; ++b) { - shp = scsi_register(shtp,sizeof(gdth_num_str)); - shp->unchecked_isa_dma = 0; - shp->irq = ha->irq; - shp->dma_channel = 0xff; - gdth_ctr_vtab[gdth_ctr_vcount++] = shp; - NUMDATA(shp)->hanum = (ushort)hanum; - NUMDATA(shp)->busnum = b; - } - } - - spin_lock_init(&ha->smp_lock); - gdth_enable_int(hanum); - } - } - } - - /* scanning for PCI controllers */ - cnt = gdth_search_pci(pcistr); - printk("GDT-HA: Found %d PCI Storage RAID Controllers\n",cnt); - gdth_sort_pci(pcistr,cnt); - for (ctr = 0; ctr < cnt; ++ctr) { - dma_addr_t scratch_dma_handle; - scratch_dma_handle = 0; - - if (gdth_ctr_count >= MAXHA) - break; - shp = scsi_register(shtp,sizeof(gdth_ext_str)); - if (shp == NULL) - continue; - - ha = HADATA(shp); - if (!gdth_init_pci(&pcistr[ctr],ha)) { - scsi_unregister(shp); - continue; - } - /* controller found and initialized */ - printk("Configuring GDT-PCI HA at %d/%d IRQ %u\n", - pcistr[ctr].pdev->bus->number, - PCI_SLOT(pcistr[ctr].pdev->devfn), ha->irq); - - if (request_irq(ha->irq, gdth_interrupt, - IRQF_DISABLED|IRQF_SHARED, "gdth", ha)) - { - printk("GDT-PCI: Unable to allocate IRQ\n"); - scsi_unregister(shp); - continue; - } - shp->unchecked_isa_dma = 0; - shp->irq = ha->irq; - shp->dma_channel = 0xff; - hanum = gdth_ctr_count; - gdth_ctr_tab[gdth_ctr_count++] = shp; - gdth_ctr_vtab[gdth_ctr_vcount++] = shp; - - NUMDATA(shp)->hanum = (ushort)hanum; - NUMDATA(shp)->busnum= 0; - - ha->pccb = CMDDATA(shp); - ha->ccb_phys = 0L; - - ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH, - &scratch_dma_handle); - ha->scratch_phys = scratch_dma_handle; - ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str), - &scratch_dma_handle); - ha->msg_phys = scratch_dma_handle; -#ifdef INT_COAL - ha->coal_stat = (gdth_coal_status *) - pci_alloc_consistent(ha->pdev, sizeof(gdth_coal_status) * - MAXOFFSETS, &scratch_dma_handle); - ha->coal_stat_phys = scratch_dma_handle; -#endif - ha->scratch_busy = FALSE; - ha->req_first = NULL; - ha->tid_cnt = pcistr[ctr].pdev->device >= 0x200 ? MAXID : MAX_HDRIVES; - if (max_ids > 0 && max_ids < ha->tid_cnt) - ha->tid_cnt = max_ids; - for (i=0; i<GDTH_MAXCMDS; ++i) - ha->cmd_tab[i].cmnd = UNUSED_CMND; - ha->scan_mode = rescan ? 0x10 : 0; - - err = FALSE; - if (ha->pscratch == NULL || ha->pmsg == NULL || - !gdth_search_drives(hanum)) { - err = TRUE; - } else { - if (hdr_channel < 0 || hdr_channel > ha->bus_cnt) - hdr_channel = ha->bus_cnt; - ha->virt_bus = hdr_channel; - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - scsi_set_pci_device(shp, pcistr[ctr].pdev); -#endif - if (!(ha->cache_feat & ha->raw_feat & ha->screen_feat &GDT_64BIT)|| - /* 64-bit DMA only supported from FW >= x.43 */ - (!ha->dma64_support)) { - if (pci_set_dma_mask(pcistr[ctr].pdev, DMA_32BIT_MASK)) { - printk(KERN_WARNING "GDT-PCI %d: Unable to set 32-bit DMA\n", hanum); - err = TRUE; - } - } else { - shp->max_cmd_len = 16; - if (!pci_set_dma_mask(pcistr[ctr].pdev, DMA_64BIT_MASK)) { - printk("GDT-PCI %d: 64-bit DMA enabled\n", hanum); - } else if (pci_set_dma_mask(pcistr[ctr].pdev, DMA_32BIT_MASK)) { - printk(KERN_WARNING "GDT-PCI %d: Unable to set 64/32-bit DMA\n", hanum); - err = TRUE; - } - } - } - - if (err) { - printk("GDT-PCI %d: Error during device scan\n", hanum); - --gdth_ctr_count; - --gdth_ctr_vcount; -#ifdef INT_COAL - if (ha->coal_stat) - pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) * - MAXOFFSETS, ha->coal_stat, - ha->coal_stat_phys); -#endif - if (ha->pscratch) - pci_free_consistent(ha->pdev, GDTH_SCRATCH, - ha->pscratch, ha->scratch_phys); - if (ha->pmsg) - pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), - ha->pmsg, ha->msg_phys); - free_irq(ha->irq,ha); - scsi_unregister(shp); - continue; - } - - shp->max_id = ha->tid_cnt; - shp->max_lun = MAXLUN; - shp->max_channel = virt_ctr ? 0 : ha->bus_cnt; - if (virt_ctr) { - virt_ctr = 1; - /* register addit. SCSI channels as virtual controllers */ - for (b = 1; b < ha->bus_cnt + 1; ++b) { - shp = scsi_register(shtp,sizeof(gdth_num_str)); - shp->unchecked_isa_dma = 0; - shp->irq = ha->irq; - shp->dma_channel = 0xff; - gdth_ctr_vtab[gdth_ctr_vcount++] = shp; - NUMDATA(shp)->hanum = (ushort)hanum; - NUMDATA(shp)->busnum = b; - } - } - - spin_lock_init(&ha->smp_lock); - gdth_enable_int(hanum); - } - - TRACE2(("gdth_detect() %d controller detected\n",gdth_ctr_count)); - if (gdth_ctr_count > 0) { -#ifdef GDTH_STATISTICS - TRACE2(("gdth_detect(): Initializing timer !\n")); - init_timer(&gdth_timer); - gdth_timer.expires = jiffies + HZ; - gdth_timer.data = 0L; - gdth_timer.function = gdth_timeout; - add_timer(&gdth_timer); -#endif - major = register_chrdev(0,"gdth",&gdth_fops); - notifier_disabled = 0; - register_reboot_notifier(&gdth_notifier); - } - gdth_polling = FALSE; - return gdth_ctr_vcount; -} - -static int gdth_release(struct Scsi_Host *shp) -{ - int hanum; - gdth_ha_str *ha; - - TRACE2(("gdth_release()\n")); - if (NUMDATA(shp)->busnum == 0) { - hanum = NUMDATA(shp)->hanum; - ha = HADATA(gdth_ctr_tab[hanum]); - if (ha->sdev) { - scsi_free_host_dev(ha->sdev); - ha->sdev = NULL; - } - gdth_flush(hanum); - - if (shp->irq) { - free_irq(shp->irq,ha); - } -#ifndef __ia64__ - if (shp->dma_channel != 0xff) { - free_dma(shp->dma_channel); - } -#endif -#ifdef INT_COAL - if (ha->coal_stat) - pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) * - MAXOFFSETS, ha->coal_stat, ha->coal_stat_phys); -#endif - if (ha->pscratch) - pci_free_consistent(ha->pdev, GDTH_SCRATCH, - ha->pscratch, ha->scratch_phys); - if (ha->pmsg) - pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), - ha->pmsg, ha->msg_phys); - if (ha->ccb_phys) - pci_unmap_single(ha->pdev,ha->ccb_phys, - sizeof(gdth_cmd_str),PCI_DMA_BIDIRECTIONAL); - gdth_ctr_released++; - TRACE2(("gdth_release(): HA %d of %d\n", - gdth_ctr_released, gdth_ctr_count)); - - if (gdth_ctr_released == gdth_ctr_count) { -#ifdef GDTH_STATISTICS - del_timer(&gdth_timer); -#endif - unregister_chrdev(major,"gdth"); - unregister_reboot_notifier(&gdth_notifier); - } - } - - scsi_unregister(shp); - return 0; -} - - -static const char *gdth_ctr_name(int hanum) -{ - gdth_ha_str *ha; - TRACE2(("gdth_ctr_name()\n")); - ha = HADATA(gdth_ctr_tab[hanum]); - if (ha->type == GDT_EISA) { switch (ha->stype) { case GDT3_ID: @@ -4820,29 +3932,23 @@ static const char *gdth_ctr_name(int hanum) static const char *gdth_info(struct Scsi_Host *shp) { - int hanum; - gdth_ha_str *ha; + gdth_ha_str *ha = shost_priv(shp); TRACE2(("gdth_info()\n")); - hanum = NUMDATA(shp)->hanum; - ha = HADATA(gdth_ctr_tab[hanum]); - return ((const char *)ha->binfo.type_string); } static int gdth_eh_bus_reset(Scsi_Cmnd *scp) { - int i, hanum; - gdth_ha_str *ha; + gdth_ha_str *ha = shost_priv(scp->device->host); + int i; ulong flags; Scsi_Cmnd *cmnd; unchar b; TRACE2(("gdth_eh_bus_reset()\n")); - hanum = NUMDATA(scp->device->host)->hanum; - b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel; - ha = HADATA(gdth_ctr_tab[hanum]); + b = scp->device->channel; /* clear command tab */ spin_lock_irqsave(&ha->smp_lock, flags); @@ -4859,9 +3965,9 @@ static int gdth_eh_bus_reset(Scsi_Cmnd *scp) if (ha->hdr[i].present) { spin_lock_irqsave(&ha->smp_lock, flags); gdth_polling = TRUE; - while (gdth_test_busy(hanum)) + while (gdth_test_busy(ha)) gdth_delay(0); - if (gdth_internal_cmd(hanum, CACHESERVICE, + if (gdth_internal_cmd(ha, CACHESERVICE, GDT_CLUST_RESET, i, 0, 0)) ha->hdr[i].cluster_type &= ~CLUSTER_RESERVED; gdth_polling = FALSE; @@ -4874,9 +3980,9 @@ static int gdth_eh_bus_reset(Scsi_Cmnd *scp) for (i = 0; i < MAXID; ++i) ha->raw[BUS_L2P(ha,b)].io_cnt[i] = 0; gdth_polling = TRUE; - while (gdth_test_busy(hanum)) + while (gdth_test_busy(ha)) gdth_delay(0); - gdth_internal_cmd(hanum, SCSIRAWSERVICE, GDT_RESET_BUS, + gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_RESET_BUS, BUS_L2P(ha,b), 0, 0); gdth_polling = FALSE; spin_unlock_irqrestore(&ha->smp_lock, flags); @@ -4884,30 +3990,18 @@ static int gdth_eh_bus_reset(Scsi_Cmnd *scp) return SUCCESS; } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) static int gdth_bios_param(struct scsi_device *sdev,struct block_device *bdev,sector_t cap,int *ip) -#else -static int gdth_bios_param(Disk *disk,kdev_t dev,int *ip) -#endif { unchar b, t; - int hanum; - gdth_ha_str *ha; + gdth_ha_str *ha = shost_priv(sdev->host); struct scsi_device *sd; unsigned capacity; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) sd = sdev; capacity = cap; -#else - sd = disk->device; - capacity = disk->capacity; -#endif - hanum = NUMDATA(sd->host)->hanum; - b = virt_ctr ? NUMDATA(sd->host)->busnum : sd->channel; + b = sd->channel; t = sd->id; - TRACE2(("gdth_bios_param() ha %d bus %d target %d\n", hanum, b, t)); - ha = HADATA(gdth_ctr_tab[hanum]); + TRACE2(("gdth_bios_param() ha %d bus %d target %d\n", ha->hanum, b, t)); if (b != ha->virt_bus || ha->hdr[t].heads == 0) { /* raw device or host drive without mapping information */ @@ -4925,33 +4019,42 @@ static int gdth_bios_param(Disk *disk,kdev_t dev,int *ip) } -static int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *)) +static int gdth_queuecommand(struct scsi_cmnd *scp, + void (*done)(struct scsi_cmnd *)) { - int hanum; - int priority; + gdth_ha_str *ha = shost_priv(scp->device->host); + struct gdth_cmndinfo *cmndinfo; TRACE(("gdth_queuecommand() cmd 0x%x\n", scp->cmnd[0])); - - scp->scsi_done = (void *)done; - scp->SCp.have_data_in = 1; - scp->SCp.phase = -1; - scp->SCp.sent_command = -1; - scp->SCp.Status = GDTH_MAP_NONE; - scp->SCp.buffer = (struct scatterlist *)NULL; - - hanum = NUMDATA(scp->device->host)->hanum; + + cmndinfo = gdth_get_cmndinfo(ha); + BUG_ON(!cmndinfo); + + scp->scsi_done = done; + gdth_update_timeout(scp, scp->timeout_per_command * 6); + cmndinfo->priority = DEFAULT_PRI; + + gdth_set_bufflen(scp, scsi_bufflen(scp)); + gdth_set_sg_count(scp, scsi_sg_count(scp)); + gdth_set_sglist(scp, scsi_sglist(scp)); + + return __gdth_queuecommand(ha, scp, cmndinfo); +} + +static int __gdth_queuecommand(gdth_ha_str *ha, struct scsi_cmnd *scp, + struct gdth_cmndinfo *cmndinfo) +{ + scp->host_scribble = (unsigned char *)cmndinfo; + cmndinfo->wait_for_completion = 1; + cmndinfo->phase = -1; + cmndinfo->OpCode = -1; + #ifdef GDTH_STATISTICS ++act_ios; #endif - priority = DEFAULT_PRI; - if (scp->done == gdth_scsi_done) - priority = scp->SCp.this_residual; - else - gdth_update_timeout(hanum, scp, scp->timeout_per_command * 6); - - gdth_putq( hanum, scp, priority ); - gdth_next( hanum ); + gdth_putq(ha, scp, cmndinfo->priority); + gdth_next(ha); return 0; } @@ -4959,12 +4062,10 @@ static int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *)) static int gdth_open(struct inode *inode, struct file *filep) { gdth_ha_str *ha; - int i; - for (i = 0; i < gdth_ctr_count; i++) { - ha = HADATA(gdth_ctr_tab[i]); + list_for_each_entry(ha, &gdth_instances, list) { if (!ha->sdev) - ha->sdev = scsi_get_host_dev(gdth_ctr_tab[i]); + ha->sdev = scsi_get_host_dev(ha->shost); } TRACE(("gdth_open()\n")); @@ -4983,10 +4084,11 @@ static int ioc_event(void __user *arg) gdth_ha_str *ha; ulong flags; - if (copy_from_user(&evt, arg, sizeof(gdth_ioctl_event)) || - evt.ionode >= gdth_ctr_count) + if (copy_from_user(&evt, arg, sizeof(gdth_ioctl_event))) + return -EFAULT; + ha = gdth_find_ha(evt.ionode); + if (!ha) return -EFAULT; - ha = HADATA(gdth_ctr_tab[evt.ionode]); if (evt.erase == 0xff) { if (evt.event.event_source == ES_TEST) @@ -5020,11 +4122,12 @@ static int ioc_lockdrv(void __user *arg) ulong flags; gdth_ha_str *ha; - if (copy_from_user(&ldrv, arg, sizeof(gdth_ioctl_lockdrv)) || - ldrv.ionode >= gdth_ctr_count) + if (copy_from_user(&ldrv, arg, sizeof(gdth_ioctl_lockdrv))) return -EFAULT; - ha = HADATA(gdth_ctr_tab[ldrv.ionode]); - + ha = gdth_find_ha(ldrv.ionode); + if (!ha) + return -EFAULT; + for (i = 0; i < ldrv.drive_cnt && i < MAX_HDRIVES; ++i) { j = ldrv.drives[i]; if (j >= MAX_HDRIVES || !ha->hdr[j].present) @@ -5033,14 +4136,14 @@ static int ioc_lockdrv(void __user *arg) spin_lock_irqsave(&ha->smp_lock, flags); ha->hdr[j].lock = 1; spin_unlock_irqrestore(&ha->smp_lock, flags); - gdth_wait_completion(ldrv.ionode, ha->bus_cnt, j); - gdth_stop_timeout(ldrv.ionode, ha->bus_cnt, j); + gdth_wait_completion(ha, ha->bus_cnt, j); + gdth_stop_timeout(ha, ha->bus_cnt, j); } else { spin_lock_irqsave(&ha->smp_lock, flags); ha->hdr[j].lock = 0; spin_unlock_irqrestore(&ha->smp_lock, flags); - gdth_start_timeout(ldrv.ionode, ha->bus_cnt, j); - gdth_next(ldrv.ionode); + gdth_start_timeout(ha, ha->bus_cnt, j); + gdth_next(ha); } } return 0; @@ -5050,16 +4153,16 @@ static int ioc_resetdrv(void __user *arg, char *cmnd) { gdth_ioctl_reset res; gdth_cmd_str cmd; - int hanum; gdth_ha_str *ha; int rval; if (copy_from_user(&res, arg, sizeof(gdth_ioctl_reset)) || - res.ionode >= gdth_ctr_count || res.number >= MAX_HDRIVES) + res.number >= MAX_HDRIVES) return -EFAULT; - hanum = res.ionode; - ha = HADATA(gdth_ctr_tab[hanum]); - + ha = gdth_find_ha(res.ionode); + if (!ha) + return -EFAULT; + if (!ha->hdr[res.number].present) return 0; memset(&cmd, 0, sizeof(gdth_cmd_str)); @@ -5085,22 +4188,21 @@ static int ioc_general(void __user *arg, char *cmnd) gdth_ioctl_general gen; char *buf = NULL; ulong64 paddr; - int hanum; gdth_ha_str *ha; int rval; - - if (copy_from_user(&gen, arg, sizeof(gdth_ioctl_general)) || - gen.ionode >= gdth_ctr_count) + + if (copy_from_user(&gen, arg, sizeof(gdth_ioctl_general))) + return -EFAULT; + ha = gdth_find_ha(gen.ionode); + if (!ha) return -EFAULT; - hanum = gen.ionode; - ha = HADATA(gdth_ctr_tab[hanum]); if (gen.data_len + gen.sense_len != 0) { - if (!(buf = gdth_ioctl_alloc(hanum, gen.data_len + gen.sense_len, + if (!(buf = gdth_ioctl_alloc(ha, gen.data_len + gen.sense_len, FALSE, &paddr))) return -EFAULT; if (copy_from_user(buf, arg + sizeof(gdth_ioctl_general), gen.data_len + gen.sense_len)) { - gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr); + gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr); return -EFAULT; } @@ -5174,7 +4276,7 @@ static int ioc_general(void __user *arg, char *cmnd) gen.command.u.raw.sense_data = (ulong32)paddr + gen.data_len; } } else { - gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr); + gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr); return -EFAULT; } } @@ -5186,15 +4288,15 @@ static int ioc_general(void __user *arg, char *cmnd) if (copy_to_user(arg + sizeof(gdth_ioctl_general), buf, gen.data_len + gen.sense_len)) { - gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr); + gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr); return -EFAULT; } if (copy_to_user(arg, &gen, sizeof(gdth_ioctl_general) - sizeof(gdth_cmd_str))) { - gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr); + gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr); return -EFAULT; } - gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr); + gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr); return 0; } @@ -5204,7 +4306,7 @@ static int ioc_hdrlist(void __user *arg, char *cmnd) gdth_cmd_str *cmd; gdth_ha_str *ha; unchar i; - int hanum, rc = -ENOMEM; + int rc = -ENOMEM; u32 cluster_type = 0; rsc = kmalloc(sizeof(*rsc), GFP_KERNEL); @@ -5213,12 +4315,10 @@ static int ioc_hdrlist(void __user *arg, char *cmnd) goto free_fail; if (copy_from_user(rsc, arg, sizeof(gdth_ioctl_rescan)) || - rsc->ionode >= gdth_ctr_count) { + (NULL == (ha = gdth_find_ha(rsc->ionode)))) { rc = -EFAULT; goto free_fail; } - hanum = rsc->ionode; - ha = HADATA(gdth_ctr_tab[hanum]); memset(cmd, 0, sizeof(gdth_cmd_str)); for (i = 0; i < MAX_HDRIVES; ++i) { @@ -5259,7 +4359,7 @@ static int ioc_rescan(void __user *arg, char *cmnd) gdth_cmd_str *cmd; ushort i, status, hdr_cnt; ulong32 info; - int hanum, cyls, hds, secs; + int cyls, hds, secs; int rc = -ENOMEM; ulong flags; gdth_ha_str *ha; @@ -5270,12 +4370,10 @@ static int ioc_rescan(void __user *arg, char *cmnd) goto free_fail; if (copy_from_user(rsc, arg, sizeof(gdth_ioctl_rescan)) || - rsc->ionode >= gdth_ctr_count) { + (NULL == (ha = gdth_find_ha(rsc->ionode)))) { rc = -EFAULT; goto free_fail; } - hanum = rsc->ionode; - ha = HADATA(gdth_ctr_tab[hanum]); memset(cmd, 0, sizeof(gdth_cmd_str)); if (rsc->flag == 0) { @@ -5432,9 +4530,9 @@ static int gdth_ioctl(struct inode *inode, struct file *filep, gdth_ioctl_ctrtype ctrt; if (copy_from_user(&ctrt, argp, sizeof(gdth_ioctl_ctrtype)) || - ctrt.ionode >= gdth_ctr_count) + (NULL == (ha = gdth_find_ha(ctrt.ionode)))) return -EFAULT; - ha = HADATA(gdth_ctr_tab[ctrt.ionode]); + if (ha->type == GDT_ISA || ha->type == GDT_EISA) { ctrt.type = (unchar)((ha->stype>>20) - 0x10); } else { @@ -5473,10 +4571,9 @@ static int gdth_ioctl(struct inode *inode, struct file *filep, unchar i, j; if (copy_from_user(&lchn, argp, sizeof(gdth_ioctl_lockchn)) || - lchn.ionode >= gdth_ctr_count) + (NULL == (ha = gdth_find_ha(lchn.ionode)))) return -EFAULT; - ha = HADATA(gdth_ctr_tab[lchn.ionode]); - + i = lchn.channel; if (i < ha->bus_cnt) { if (lchn.lock) { @@ -5484,16 +4581,16 @@ static int gdth_ioctl(struct inode *inode, struct file *filep, ha->raw[i].lock = 1; spin_unlock_irqrestore(&ha->smp_lock, flags); for (j = 0; j < ha->tid_cnt; ++j) { - gdth_wait_completion(lchn.ionode, i, j); - gdth_stop_timeout(lchn.ionode, i, j); + gdth_wait_completion(ha, i, j); + gdth_stop_timeout(ha, i, j); } } else { spin_lock_irqsave(&ha->smp_lock, flags); ha->raw[i].lock = 0; spin_unlock_irqrestore(&ha->smp_lock, flags); for (j = 0; j < ha->tid_cnt; ++j) { - gdth_start_timeout(lchn.ionode, i, j); - gdth_next(lchn.ionode); + gdth_start_timeout(ha, i, j); + gdth_next(ha); } } } @@ -5509,37 +4606,22 @@ static int gdth_ioctl(struct inode *inode, struct file *filep, case GDTIOCTL_RESET_BUS: { gdth_ioctl_reset res; - int hanum, rval; + int rval; if (copy_from_user(&res, argp, sizeof(gdth_ioctl_reset)) || - res.ionode >= gdth_ctr_count) + (NULL == (ha = gdth_find_ha(res.ionode)))) return -EFAULT; - hanum = res.ionode; - ha = HADATA(gdth_ctr_tab[hanum]); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) - scp = kmalloc(sizeof(*scp), GFP_KERNEL); + scp = kzalloc(sizeof(*scp), GFP_KERNEL); if (!scp) return -ENOMEM; - memset(scp, 0, sizeof(*scp)); scp->device = ha->sdev; scp->cmd_len = 12; - scp->use_sg = 0; - scp->device->channel = virt_ctr ? 0 : res.number; + scp->device->channel = res.number; rval = gdth_eh_bus_reset(scp); res.status = (rval == SUCCESS ? S_OK : S_GENERR); kfree(scp); -#else - scp = scsi_allocate_device(ha->sdev, 1, FALSE); - if (!scp) - return -ENOMEM; - scp->cmd_len = 12; - scp->use_sg = 0; - scp->channel = virt_ctr ? 0 : res.number; - rval = gdth_eh_bus_reset(scp); - res.status = (rval == SUCCESS ? S_OK : S_GENERR); - scsi_release_command(scp); -#endif + if (copy_to_user(argp, &res, sizeof(gdth_ioctl_reset))) return -EFAULT; break; @@ -5556,16 +4638,14 @@ static int gdth_ioctl(struct inode *inode, struct file *filep, /* flush routine */ -static void gdth_flush(int hanum) +static void gdth_flush(gdth_ha_str *ha) { int i; - gdth_ha_str *ha; gdth_cmd_str gdtcmd; char cmnd[MAX_COMMAND_SIZE]; memset(cmnd, 0xff, MAX_COMMAND_SIZE); - TRACE2(("gdth_flush() hanum %d\n",hanum)); - ha = HADATA(gdth_ctr_tab[hanum]); + TRACE2(("gdth_flush() hanum %d\n", ha->hanum)); for (i = 0; i < MAX_HDRIVES; ++i) { if (ha->hdr[i].present) { @@ -5581,9 +4661,9 @@ static void gdth_flush(int hanum) gdtcmd.u.cache.BlockNo = 1; gdtcmd.u.cache.sg_canz = 0; } - TRACE2(("gdth_flush(): flush ha %d drive %d\n", hanum, i)); + TRACE2(("gdth_flush(): flush ha %d drive %d\n", ha->hanum, i)); - gdth_execute(gdth_ctr_tab[hanum], &gdtcmd, cmnd, 30, NULL); + gdth_execute(ha->shost, &gdtcmd, cmnd, 30, NULL); } } } @@ -5591,7 +4671,7 @@ static void gdth_flush(int hanum) /* shutdown routine */ static int gdth_halt(struct notifier_block *nb, ulong event, void *buf) { - int hanum; + gdth_ha_str *ha; #ifndef __alpha__ gdth_cmd_str gdtcmd; char cmnd[MAX_COMMAND_SIZE]; @@ -5606,8 +4686,8 @@ static int gdth_halt(struct notifier_block *nb, ulong event, void *buf) notifier_disabled = 1; printk("GDT-HA: Flushing all host drives .. "); - for (hanum = 0; hanum < gdth_ctr_count; ++hanum) { - gdth_flush(hanum); + list_for_each_entry(ha, &gdth_instances, list) { + gdth_flush(ha); #ifndef __alpha__ /* controller reset */ @@ -5615,8 +4695,8 @@ static int gdth_halt(struct notifier_block *nb, ulong event, void *buf) gdtcmd.BoardNode = LOCALBOARD; gdtcmd.Service = CACHESERVICE; gdtcmd.OpCode = GDT_RESET; - TRACE2(("gdth_halt(): reset controller %d\n", hanum)); - gdth_execute(gdth_ctr_tab[hanum], &gdtcmd, cmnd, 10, NULL); + TRACE2(("gdth_halt(): reset controller %d\n", ha->hanum)); + gdth_execute(ha->shost, &gdtcmd, cmnd, 10, NULL); #endif } printk("Done.\n"); @@ -5627,7 +4707,6 @@ static int gdth_halt(struct notifier_block *nb, ulong event, void *buf) return NOTIFY_OK; } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) /* configure lun */ static int gdth_slave_configure(struct scsi_device *sdev) { @@ -5636,40 +4715,540 @@ static int gdth_slave_configure(struct scsi_device *sdev) sdev->skip_ms_page_8 = 1; return 0; } -#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) -static struct scsi_host_template driver_template = { -#else -static Scsi_Host_Template driver_template = { -#endif - .proc_name = "gdth", - .proc_info = gdth_proc_info, +static struct scsi_host_template gdth_template = { .name = "GDT SCSI Disk Array Controller", - .detect = gdth_detect, - .release = gdth_release, .info = gdth_info, .queuecommand = gdth_queuecommand, .eh_bus_reset_handler = gdth_eh_bus_reset, + .slave_configure = gdth_slave_configure, .bios_param = gdth_bios_param, + .proc_info = gdth_proc_info, + .proc_name = "gdth", .can_queue = GDTH_MAXCMDS, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) - .slave_configure = gdth_slave_configure, -#endif .this_id = -1, .sg_tablesize = GDTH_MAXSG, .cmd_per_lun = GDTH_MAXC_P_L, .unchecked_isa_dma = 1, .use_clustering = ENABLE_CLUSTERING, -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - .use_new_eh_code = 1, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) - .highmem_io = 1, +}; + +#ifdef CONFIG_ISA +static int gdth_isa_probe_one(ulong32 isa_bios) +{ + struct Scsi_Host *shp; + gdth_ha_str *ha; + dma_addr_t scratch_dma_handle = 0; + int error, i; + + if (!gdth_search_isa(isa_bios)) + return -ENXIO; + + shp = scsi_host_alloc(&gdth_template, sizeof(gdth_ha_str)); + if (!shp) + return -ENOMEM; + ha = shost_priv(shp); + + error = -ENODEV; + if (!gdth_init_isa(isa_bios,ha)) + goto out_host_put; + + /* controller found and initialized */ + printk("Configuring GDT-ISA HA at BIOS 0x%05X IRQ %u DRQ %u\n", + isa_bios, ha->irq, ha->drq); + + error = request_irq(ha->irq, gdth_interrupt, IRQF_DISABLED, "gdth", ha); + if (error) { + printk("GDT-ISA: Unable to allocate IRQ\n"); + goto out_host_put; + } + + error = request_dma(ha->drq, "gdth"); + if (error) { + printk("GDT-ISA: Unable to allocate DMA channel\n"); + goto out_free_irq; + } + + set_dma_mode(ha->drq,DMA_MODE_CASCADE); + enable_dma(ha->drq); + shp->unchecked_isa_dma = 1; + shp->irq = ha->irq; + shp->dma_channel = ha->drq; + + ha->hanum = gdth_ctr_count++; + ha->shost = shp; + + ha->pccb = &ha->cmdext; + ha->ccb_phys = 0L; + ha->pdev = NULL; + + error = -ENOMEM; + + ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH, + &scratch_dma_handle); + if (!ha->pscratch) + goto out_dec_counters; + ha->scratch_phys = scratch_dma_handle; + + ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str), + &scratch_dma_handle); + if (!ha->pmsg) + goto out_free_pscratch; + ha->msg_phys = scratch_dma_handle; + +#ifdef INT_COAL + ha->coal_stat = pci_alloc_consistent(ha->pdev, + sizeof(gdth_coal_status) * MAXOFFSETS, + &scratch_dma_handle); + if (!ha->coal_stat) + goto out_free_pmsg; + ha->coal_stat_phys = scratch_dma_handle; #endif + + ha->scratch_busy = FALSE; + ha->req_first = NULL; + ha->tid_cnt = MAX_HDRIVES; + if (max_ids > 0 && max_ids < ha->tid_cnt) + ha->tid_cnt = max_ids; + for (i = 0; i < GDTH_MAXCMDS; ++i) + ha->cmd_tab[i].cmnd = UNUSED_CMND; + ha->scan_mode = rescan ? 0x10 : 0; + + error = -ENODEV; + if (!gdth_search_drives(ha)) { + printk("GDT-ISA: Error during device scan\n"); + goto out_free_coal_stat; + } + + if (hdr_channel < 0 || hdr_channel > ha->bus_cnt) + hdr_channel = ha->bus_cnt; + ha->virt_bus = hdr_channel; + + if (ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT) + shp->max_cmd_len = 16; + + shp->max_id = ha->tid_cnt; + shp->max_lun = MAXLUN; + shp->max_channel = ha->bus_cnt; + + spin_lock_init(&ha->smp_lock); + gdth_enable_int(ha); + + error = scsi_add_host(shp, NULL); + if (error) + goto out_free_coal_stat; + list_add_tail(&ha->list, &gdth_instances); + return 0; + + out_free_coal_stat: +#ifdef INT_COAL + pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) * MAXOFFSETS, + ha->coal_stat, ha->coal_stat_phys); + out_free_pmsg: #endif -}; + pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), + ha->pmsg, ha->msg_phys); + out_free_pscratch: + pci_free_consistent(ha->pdev, GDTH_SCRATCH, + ha->pscratch, ha->scratch_phys); + out_dec_counters: + gdth_ctr_count--; + out_free_irq: + free_irq(ha->irq, ha); + out_host_put: + scsi_host_put(shp); + return error; +} +#endif /* CONFIG_ISA */ + +#ifdef CONFIG_EISA +static int gdth_eisa_probe_one(ushort eisa_slot) +{ + struct Scsi_Host *shp; + gdth_ha_str *ha; + dma_addr_t scratch_dma_handle = 0; + int error, i; + + if (!gdth_search_eisa(eisa_slot)) + return -ENXIO; + + shp = scsi_host_alloc(&gdth_template, sizeof(gdth_ha_str)); + if (!shp) + return -ENOMEM; + ha = shost_priv(shp); + + error = -ENODEV; + if (!gdth_init_eisa(eisa_slot,ha)) + goto out_host_put; + + /* controller found and initialized */ + printk("Configuring GDT-EISA HA at Slot %d IRQ %u\n", + eisa_slot >> 12, ha->irq); + + error = request_irq(ha->irq, gdth_interrupt, IRQF_DISABLED, "gdth", ha); + if (error) { + printk("GDT-EISA: Unable to allocate IRQ\n"); + goto out_host_put; + } + + shp->unchecked_isa_dma = 0; + shp->irq = ha->irq; + shp->dma_channel = 0xff; + + ha->hanum = gdth_ctr_count++; + ha->shost = shp; + + TRACE2(("EISA detect Bus 0: hanum %d\n", ha->hanum)); + + ha->pccb = &ha->cmdext; + ha->ccb_phys = 0L; + + error = -ENOMEM; + + ha->pdev = NULL; + ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH, + &scratch_dma_handle); + if (!ha->pscratch) + goto out_free_irq; + ha->scratch_phys = scratch_dma_handle; + + ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str), + &scratch_dma_handle); + if (!ha->pmsg) + goto out_free_pscratch; + ha->msg_phys = scratch_dma_handle; + +#ifdef INT_COAL + ha->coal_stat = pci_alloc_consistent(ha->pdev, + sizeof(gdth_coal_status) * MAXOFFSETS, + &scratch_dma_handle); + if (!ha->coal_stat) + goto out_free_pmsg; + ha->coal_stat_phys = scratch_dma_handle; +#endif + + ha->ccb_phys = pci_map_single(ha->pdev,ha->pccb, + sizeof(gdth_cmd_str), PCI_DMA_BIDIRECTIONAL); + if (!ha->ccb_phys) + goto out_free_coal_stat; + + ha->scratch_busy = FALSE; + ha->req_first = NULL; + ha->tid_cnt = MAX_HDRIVES; + if (max_ids > 0 && max_ids < ha->tid_cnt) + ha->tid_cnt = max_ids; + for (i = 0; i < GDTH_MAXCMDS; ++i) + ha->cmd_tab[i].cmnd = UNUSED_CMND; + ha->scan_mode = rescan ? 0x10 : 0; + + if (!gdth_search_drives(ha)) { + printk("GDT-EISA: Error during device scan\n"); + error = -ENODEV; + goto out_free_ccb_phys; + } + + if (hdr_channel < 0 || hdr_channel > ha->bus_cnt) + hdr_channel = ha->bus_cnt; + ha->virt_bus = hdr_channel; + + if (ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT) + shp->max_cmd_len = 16; + + shp->max_id = ha->tid_cnt; + shp->max_lun = MAXLUN; + shp->max_channel = ha->bus_cnt; + + spin_lock_init(&ha->smp_lock); + gdth_enable_int(ha); + + error = scsi_add_host(shp, NULL); + if (error) + goto out_free_coal_stat; + list_add_tail(&ha->list, &gdth_instances); + return 0; + + out_free_ccb_phys: + pci_unmap_single(ha->pdev,ha->ccb_phys, sizeof(gdth_cmd_str), + PCI_DMA_BIDIRECTIONAL); + out_free_coal_stat: +#ifdef INT_COAL + pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) * MAXOFFSETS, + ha->coal_stat, ha->coal_stat_phys); + out_free_pmsg: +#endif + pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), + ha->pmsg, ha->msg_phys); + out_free_pscratch: + pci_free_consistent(ha->pdev, GDTH_SCRATCH, + ha->pscratch, ha->scratch_phys); + out_free_irq: + free_irq(ha->irq, ha); + gdth_ctr_count--; + out_host_put: + scsi_host_put(shp); + return error; +} +#endif /* CONFIG_EISA */ + +#ifdef CONFIG_PCI +static int gdth_pci_probe_one(gdth_pci_str *pcistr, int ctr) +{ + struct Scsi_Host *shp; + gdth_ha_str *ha; + dma_addr_t scratch_dma_handle = 0; + int error, i; + + shp = scsi_host_alloc(&gdth_template, sizeof(gdth_ha_str)); + if (!shp) + return -ENOMEM; + ha = shost_priv(shp); + + error = -ENODEV; + if (!gdth_init_pci(&pcistr[ctr],ha)) + goto out_host_put; + + /* controller found and initialized */ + printk("Configuring GDT-PCI HA at %d/%d IRQ %u\n", + pcistr[ctr].pdev->bus->number, + PCI_SLOT(pcistr[ctr].pdev->devfn), + ha->irq); + + error = request_irq(ha->irq, gdth_interrupt, + IRQF_DISABLED|IRQF_SHARED, "gdth", ha); + if (error) { + printk("GDT-PCI: Unable to allocate IRQ\n"); + goto out_host_put; + } + + shp->unchecked_isa_dma = 0; + shp->irq = ha->irq; + shp->dma_channel = 0xff; + + ha->hanum = gdth_ctr_count++; + ha->shost = shp; + + ha->pccb = &ha->cmdext; + ha->ccb_phys = 0L; + + error = -ENOMEM; + + ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH, + &scratch_dma_handle); + if (!ha->pscratch) + goto out_free_irq; + ha->scratch_phys = scratch_dma_handle; + + ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str), + &scratch_dma_handle); + if (!ha->pmsg) + goto out_free_pscratch; + ha->msg_phys = scratch_dma_handle; + +#ifdef INT_COAL + ha->coal_stat = pci_alloc_consistent(ha->pdev, + sizeof(gdth_coal_status) * MAXOFFSETS, + &scratch_dma_handle); + if (!ha->coal_stat) + goto out_free_pmsg; + ha->coal_stat_phys = scratch_dma_handle; +#endif + + ha->scratch_busy = FALSE; + ha->req_first = NULL; + ha->tid_cnt = pcistr[ctr].pdev->device >= 0x200 ? MAXID : MAX_HDRIVES; + if (max_ids > 0 && max_ids < ha->tid_cnt) + ha->tid_cnt = max_ids; + for (i = 0; i < GDTH_MAXCMDS; ++i) + ha->cmd_tab[i].cmnd = UNUSED_CMND; + ha->scan_mode = rescan ? 0x10 : 0; + + error = -ENODEV; + if (!gdth_search_drives(ha)) { + printk("GDT-PCI %d: Error during device scan\n", ha->hanum); + goto out_free_coal_stat; + } + + if (hdr_channel < 0 || hdr_channel > ha->bus_cnt) + hdr_channel = ha->bus_cnt; + ha->virt_bus = hdr_channel; + + /* 64-bit DMA only supported from FW >= x.43 */ + if (!(ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT) || + !ha->dma64_support) { + if (pci_set_dma_mask(pcistr[ctr].pdev, DMA_32BIT_MASK)) { + printk(KERN_WARNING "GDT-PCI %d: " + "Unable to set 32-bit DMA\n", ha->hanum); + goto out_free_coal_stat; + } + } else { + shp->max_cmd_len = 16; + if (!pci_set_dma_mask(pcistr[ctr].pdev, DMA_64BIT_MASK)) { + printk("GDT-PCI %d: 64-bit DMA enabled\n", ha->hanum); + } else if (pci_set_dma_mask(pcistr[ctr].pdev, DMA_32BIT_MASK)) { + printk(KERN_WARNING "GDT-PCI %d: " + "Unable to set 64/32-bit DMA\n", ha->hanum); + goto out_free_coal_stat; + } + } + + shp->max_id = ha->tid_cnt; + shp->max_lun = MAXLUN; + shp->max_channel = ha->bus_cnt; + + spin_lock_init(&ha->smp_lock); + gdth_enable_int(ha); + + error = scsi_add_host(shp, &pcistr[ctr].pdev->dev); + if (error) + goto out_free_coal_stat; + list_add_tail(&ha->list, &gdth_instances); + return 0; + + out_free_coal_stat: +#ifdef INT_COAL + pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) * MAXOFFSETS, + ha->coal_stat, ha->coal_stat_phys); + out_free_pmsg: +#endif + pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), + ha->pmsg, ha->msg_phys); + out_free_pscratch: + pci_free_consistent(ha->pdev, GDTH_SCRATCH, + ha->pscratch, ha->scratch_phys); + out_free_irq: + free_irq(ha->irq, ha); + gdth_ctr_count--; + out_host_put: + scsi_host_put(shp); + return error; +} +#endif /* CONFIG_PCI */ + +static void gdth_remove_one(gdth_ha_str *ha) +{ + struct Scsi_Host *shp = ha->shost; + + TRACE2(("gdth_remove_one()\n")); + + scsi_remove_host(shp); + + if (ha->sdev) { + scsi_free_host_dev(ha->sdev); + ha->sdev = NULL; + } + + gdth_flush(ha); + + if (shp->irq) + free_irq(shp->irq,ha); + +#ifdef CONFIG_ISA + if (shp->dma_channel != 0xff) + free_dma(shp->dma_channel); +#endif +#ifdef INT_COAL + if (ha->coal_stat) + pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) * + MAXOFFSETS, ha->coal_stat, ha->coal_stat_phys); +#endif + if (ha->pscratch) + pci_free_consistent(ha->pdev, GDTH_SCRATCH, + ha->pscratch, ha->scratch_phys); + if (ha->pmsg) + pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), + ha->pmsg, ha->msg_phys); + if (ha->ccb_phys) + pci_unmap_single(ha->pdev,ha->ccb_phys, + sizeof(gdth_cmd_str),PCI_DMA_BIDIRECTIONAL); + + scsi_host_put(shp); +} + +static int __init gdth_init(void) +{ + if (disable) { + printk("GDT-HA: Controller driver disabled from" + " command line !\n"); + return 0; + } + + printk("GDT-HA: Storage RAID Controller Driver. Version: %s\n", + GDTH_VERSION_STR); + + /* initializations */ + gdth_polling = TRUE; + gdth_clear_events(); + + /* As default we do not probe for EISA or ISA controllers */ + if (probe_eisa_isa) { + /* scanning for controllers, at first: ISA controller */ +#ifdef CONFIG_ISA + ulong32 isa_bios; + for (isa_bios = 0xc8000UL; isa_bios <= 0xd8000UL; + isa_bios += 0x8000UL) + gdth_isa_probe_one(isa_bios); +#endif +#ifdef CONFIG_EISA + { + ushort eisa_slot; + for (eisa_slot = 0x1000; eisa_slot <= 0x8000; + eisa_slot += 0x1000) + gdth_eisa_probe_one(eisa_slot); + } +#endif + } + +#ifdef CONFIG_PCI + /* scanning for PCI controllers */ + { + gdth_pci_str pcistr[MAXHA]; + int cnt,ctr; + + cnt = gdth_search_pci(pcistr); + printk("GDT-HA: Found %d PCI Storage RAID Controllers\n", cnt); + gdth_sort_pci(pcistr,cnt); + for (ctr = 0; ctr < cnt; ++ctr) + gdth_pci_probe_one(pcistr, ctr); + } +#endif /* CONFIG_PCI */ + + TRACE2(("gdth_detect() %d controller detected\n", gdth_ctr_count)); + + if (list_empty(&gdth_instances)) + return -ENODEV; + +#ifdef GDTH_STATISTICS + TRACE2(("gdth_detect(): Initializing timer !\n")); + init_timer(&gdth_timer); + gdth_timer.expires = jiffies + HZ; + gdth_timer.data = 0L; + gdth_timer.function = gdth_timeout; + add_timer(&gdth_timer); +#endif + major = register_chrdev(0,"gdth", &gdth_fops); + notifier_disabled = 0; + register_reboot_notifier(&gdth_notifier); + gdth_polling = FALSE; + return 0; +} + +static void __exit gdth_exit(void) +{ + gdth_ha_str *ha; + + list_for_each_entry(ha, &gdth_instances, list) + gdth_remove_one(ha); + +#ifdef GDTH_STATISTICS + del_timer(&gdth_timer); +#endif + unregister_chrdev(major,"gdth"); + unregister_reboot_notifier(&gdth_notifier); +} + +module_init(gdth_init); +module_exit(gdth_exit); -#include "scsi_module.c" #ifndef MODULE __setup("gdth=", option_setup); #endif diff --git a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h index 37423300592e..1434c6b0297c 100644 --- a/drivers/scsi/gdth.h +++ b/drivers/scsi/gdth.h @@ -13,7 +13,6 @@ * $Id: gdth.h,v 1.58 2006/01/11 16:14:09 achim Exp $ */ -#include <linux/version.h> #include <linux/types.h> #ifndef TRUE @@ -304,15 +303,8 @@ #define MAILBOXREG 0x0c90 /* mailbox reg. (16 bytes) */ #define EISAREG 0x0cc0 /* EISA configuration */ -/* DMA memory mappings */ -#define GDTH_MAP_NONE 0 -#define GDTH_MAP_SINGLE 1 -#define GDTH_MAP_SG 2 -#define GDTH_MAP_IOCTL 3 - /* other defines */ #define LINUX_OS 8 /* used for cache optim. */ -#define SCATTER_GATHER 1 /* s/g feature */ #define SECS32 0x1f /* round capacity */ #define BIOS_ID_OFFS 0x10 /* offset contr-ID in ISABIOS */ #define LOCALBOARD 0 /* board node always 0 */ @@ -854,6 +846,9 @@ typedef struct { /* controller information structure */ typedef struct { + struct Scsi_Host *shost; + struct list_head list; + ushort hanum; ushort oem_id; /* OEM */ ushort type; /* controller class */ ulong32 stype; /* subtype (PCI: device ID) */ @@ -865,6 +860,7 @@ typedef struct { void __iomem *brd; /* DPRAM address */ ulong32 brd_phys; /* slot number/BIOS address */ gdt6c_plx_regs *plx; /* PLX regs (new PCI contr.) */ + gdth_cmd_str cmdext; gdth_cmd_str *pccb; /* address command structure */ ulong32 ccb_phys; /* phys. address */ #ifdef INT_COAL @@ -916,6 +912,19 @@ typedef struct { Scsi_Cmnd *cmnd; /* pending request */ ushort service; /* service */ } cmd_tab[GDTH_MAXCMDS]; /* table of pend. requests */ + struct gdth_cmndinfo { /* per-command private info */ + int index; + int internal_command; /* don't call scsi_done */ + dma_addr_t sense_paddr; /* sense dma-addr */ + unchar priority; + int timeout; + volatile int wait_for_completion; + ushort status; + ulong32 info; + enum dma_data_direction dma_dir; + int phase; /* ???? */ + int OpCode; + } cmndinfo[GDTH_MAXCMDS]; /* index==0 is free */ unchar bus_cnt; /* SCSI bus count */ unchar tid_cnt; /* Target ID count */ unchar bus_id[MAXBUS]; /* IOP IDs */ @@ -938,19 +947,10 @@ typedef struct { struct scsi_device *sdev; } gdth_ha_str; -/* structure for scsi_register(), SCSI bus != 0 */ -typedef struct { - ushort hanum; - ushort busnum; -} gdth_num_str; - -/* structure for scsi_register() */ -typedef struct { - gdth_num_str numext; /* must be the first element */ - gdth_ha_str haext; - gdth_cmd_str cmdext; -} gdth_ext_str; - +static inline struct gdth_cmndinfo *gdth_cmnd_priv(struct scsi_cmnd* cmd) +{ + return (struct gdth_cmndinfo *)cmd->host_scribble; +} /* INQUIRY data format */ typedef struct { diff --git a/drivers/scsi/gdth_kcompat.h b/drivers/scsi/gdth_kcompat.h deleted file mode 100644 index 2a302eee669a..000000000000 --- a/drivers/scsi/gdth_kcompat.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef IRQ_HANDLED -typedef void irqreturn_t; -#define IRQ_NONE -#define IRQ_HANDLED -#endif - -#ifndef MODULE_LICENSE -#define MODULE_LICENSE(x) -#endif - -#ifndef __iomem -#define __iomem -#endif - -#ifndef __attribute_used__ -#define __attribute_used__ __devinitdata -#endif - -#ifndef __user -#define __user -#endif - -#ifndef SERVICE_ACTION_IN -#define SERVICE_ACTION_IN 0x9e -#endif -#ifndef READ_16 -#define READ_16 0x88 -#endif -#ifndef WRITE_16 -#define WRITE_16 0x8a -#endif diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c index 32982eb75c84..de5773443c62 100644 --- a/drivers/scsi/gdth_proc.c +++ b/drivers/scsi/gdth_proc.c @@ -4,62 +4,32 @@ #include <linux/completion.h> -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) int gdth_proc_info(struct Scsi_Host *host, char *buffer,char **start,off_t offset,int length, int inout) { - int hanum,busnum; + gdth_ha_str *ha = shost_priv(host); TRACE2(("gdth_proc_info() length %d offs %d inout %d\n", length,(int)offset,inout)); - hanum = NUMDATA(host)->hanum; - busnum= NUMDATA(host)->busnum; - - if (inout) - return(gdth_set_info(buffer,length,host,hanum,busnum)); - else - return(gdth_get_info(buffer,start,offset,length,host,hanum,busnum)); -} -#else -int gdth_proc_info(char *buffer,char **start,off_t offset,int length,int hostno, - int inout) -{ - int hanum,busnum,i; - - TRACE2(("gdth_proc_info() length %d offs %d inout %d\n", - length,(int)offset,inout)); - - for (i = 0; i < gdth_ctr_vcount; ++i) { - if (gdth_ctr_vtab[i]->host_no == hostno) - break; - } - if (i == gdth_ctr_vcount) - return(-EINVAL); - - hanum = NUMDATA(gdth_ctr_vtab[i])->hanum; - busnum= NUMDATA(gdth_ctr_vtab[i])->busnum; - if (inout) - return(gdth_set_info(buffer,length,gdth_ctr_vtab[i],hanum,busnum)); + return(gdth_set_info(buffer,length,host,ha)); else - return(gdth_get_info(buffer,start,offset,length, - gdth_ctr_vtab[i],hanum,busnum)); + return(gdth_get_info(buffer,start,offset,length,host,ha)); } -#endif static int gdth_set_info(char *buffer,int length,struct Scsi_Host *host, - int hanum,int busnum) + gdth_ha_str *ha) { int ret_val = -EINVAL; - TRACE2(("gdth_set_info() ha %d bus %d\n",hanum,busnum)); + TRACE2(("gdth_set_info() ha %d\n",ha->hanum,)); if (length >= 4) { if (strncmp(buffer,"gdth",4) == 0) { buffer += 5; length -= 5; - ret_val = gdth_set_asc_info(host, buffer, length, hanum); + ret_val = gdth_set_asc_info(host, buffer, length, ha); } } @@ -67,11 +37,10 @@ static int gdth_set_info(char *buffer,int length,struct Scsi_Host *host, } static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer, - int length,int hanum) + int length, gdth_ha_str *ha) { int orig_length, drive, wb_mode; int i, found; - gdth_ha_str *ha; gdth_cmd_str gdtcmd; gdth_cpar_str *pcpar; ulong64 paddr; @@ -80,8 +49,7 @@ static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer, memset(cmnd, 0xff, 12); memset(&gdtcmd, 0, sizeof(gdth_cmd_str)); - TRACE2(("gdth_set_asc_info() ha %d\n",hanum)); - ha = HADATA(gdth_ctr_tab[hanum]); + TRACE2(("gdth_set_asc_info() ha %d\n",ha->hanum)); orig_length = length + 5; drive = -1; wb_mode = 0; @@ -157,7 +125,7 @@ static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer, } if (wb_mode) { - if (!gdth_ioctl_alloc(hanum, sizeof(gdth_cpar_str), TRUE, &paddr)) + if (!gdth_ioctl_alloc(ha, sizeof(gdth_cpar_str), TRUE, &paddr)) return(-EBUSY); pcpar = (gdth_cpar_str *)ha->pscratch; memcpy( pcpar, &ha->cpar, sizeof(gdth_cpar_str) ); @@ -171,7 +139,7 @@ static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer, gdth_execute(host, &gdtcmd, cmnd, 30, NULL); - gdth_ioctl_free(hanum, GDTH_SCRATCH, ha->pscratch, paddr); + gdth_ioctl_free(ha, GDTH_SCRATCH, ha->pscratch, paddr); printk("Done.\n"); return(orig_length); } @@ -181,11 +149,10 @@ static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer, } static int gdth_get_info(char *buffer,char **start,off_t offset,int length, - struct Scsi_Host *host,int hanum,int busnum) + struct Scsi_Host *host, gdth_ha_str *ha) { int size = 0,len = 0; off_t begin = 0,pos = 0; - gdth_ha_str *ha; int id, i, j, k, sec, flag; int no_mdrv = 0, drv_no, is_mirr; ulong32 cnt; @@ -214,8 +181,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length, memset(cmnd, 0xff, 12); memset(gdtcmd, 0, sizeof(gdth_cmd_str)); - TRACE2(("gdth_get_info() ha %d bus %d\n",hanum,busnum)); - ha = HADATA(gdth_ctr_tab[hanum]); + TRACE2(("gdth_get_info() ha %d\n",ha->hanum)); /* request is i.e. "cat /proc/scsi/gdth/0" */ @@ -245,13 +211,10 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length, /* controller information */ size = sprintf(buffer+len,"\nDisk Array Controller Information:\n"); len += size; pos = begin + len; - if (virt_ctr) - sprintf(hrec, "%s (Bus %d)", ha->binfo.type_string, busnum); - else - strcpy(hrec, ha->binfo.type_string); + strcpy(hrec, ha->binfo.type_string); size = sprintf(buffer+len, " Number: \t%d \tName: \t%s\n", - hanum, hrec); + ha->hanum, hrec); len += size; pos = begin + len; if (ha->more_proc) @@ -301,7 +264,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length, len += size; pos = begin + len; flag = FALSE; - buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr); + buf = gdth_ioctl_alloc(ha, GDTH_SCRATCH, FALSE, &paddr); if (!buf) goto stop_output; for (i = 0; i < ha->bus_cnt; ++i) { @@ -404,7 +367,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length, goto stop_output; } } - gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr); + gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr); if (!flag) { size = sprintf(buffer+len, "\n --\n"); @@ -416,7 +379,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length, len += size; pos = begin + len; flag = FALSE; - buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr); + buf = gdth_ioctl_alloc(ha, GDTH_SCRATCH, FALSE, &paddr); if (!buf) goto stop_output; for (i = 0; i < MAX_LDRIVES; ++i) { @@ -510,7 +473,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length, if (pos > offset + length) goto stop_output; } - gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr); + gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr); if (!flag) { size = sprintf(buffer+len, "\n --\n"); @@ -522,7 +485,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length, len += size; pos = begin + len; flag = FALSE; - buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr); + buf = gdth_ioctl_alloc(ha, GDTH_SCRATCH, FALSE, &paddr); if (!buf) goto stop_output; for (i = 0; i < MAX_LDRIVES; ++i) { @@ -581,7 +544,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length, goto stop_output; } } - gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr); + gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr); if (!flag) { size = sprintf(buffer+len, "\n --\n"); @@ -593,7 +556,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length, len += size; pos = begin + len; flag = FALSE; - buf = gdth_ioctl_alloc(hanum, sizeof(gdth_hget_str), FALSE, &paddr); + buf = gdth_ioctl_alloc(ha, sizeof(gdth_hget_str), FALSE, &paddr); if (!buf) goto stop_output; for (i = 0; i < MAX_LDRIVES; ++i) { @@ -626,7 +589,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length, } } } - gdth_ioctl_free(hanum, sizeof(gdth_hget_str), buf, paddr); + gdth_ioctl_free(ha, sizeof(gdth_hget_str), buf, paddr); for (i = 0; i < MAX_HDRIVES; ++i) { if (!(ha->hdr[i].present)) @@ -664,7 +627,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length, id = gdth_read_event(ha, id, estr); if (estr->event_source == 0) break; - if (estr->event_data.eu.driver.ionode == hanum && + if (estr->event_data.eu.driver.ionode == ha->hanum && estr->event_source == ES_ASYNC) { gdth_log_event(&estr->event_data, hrec); do_gettimeofday(&tv); @@ -699,17 +662,15 @@ free_fail: return rc; } -static char *gdth_ioctl_alloc(int hanum, int size, int scratch, +static char *gdth_ioctl_alloc(gdth_ha_str *ha, int size, int scratch, ulong64 *paddr) { - gdth_ha_str *ha; ulong flags; char *ret_val; if (size == 0) return NULL; - ha = HADATA(gdth_ctr_tab[hanum]); spin_lock_irqsave(&ha->smp_lock, flags); if (!ha->scratch_busy && size <= GDTH_SCRATCH) { @@ -729,12 +690,10 @@ static char *gdth_ioctl_alloc(int hanum, int size, int scratch, return ret_val; } -static void gdth_ioctl_free(int hanum, int size, char *buf, ulong64 paddr) +static void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, ulong64 paddr) { - gdth_ha_str *ha; ulong flags; - ha = HADATA(gdth_ctr_tab[hanum]); spin_lock_irqsave(&ha->smp_lock, flags); if (buf == ha->pscratch) { @@ -747,13 +706,11 @@ static void gdth_ioctl_free(int hanum, int size, char *buf, ulong64 paddr) } #ifdef GDTH_IOCTL_PROC -static int gdth_ioctl_check_bin(int hanum, ushort size) +static int gdth_ioctl_check_bin(gdth_ha_str *ha, ushort size) { - gdth_ha_str *ha; ulong flags; int ret_val; - ha = HADATA(gdth_ctr_tab[hanum]); spin_lock_irqsave(&ha->smp_lock, flags); ret_val = FALSE; @@ -766,27 +723,27 @@ static int gdth_ioctl_check_bin(int hanum, ushort size) } #endif -static void gdth_wait_completion(int hanum, int busnum, int id) +static void gdth_wait_completion(gdth_ha_str *ha, int busnum, int id) { - gdth_ha_str *ha; ulong flags; int i; Scsi_Cmnd *scp; + struct gdth_cmndinfo *cmndinfo; unchar b, t; - ha = HADATA(gdth_ctr_tab[hanum]); spin_lock_irqsave(&ha->smp_lock, flags); for (i = 0; i < GDTH_MAXCMDS; ++i) { scp = ha->cmd_tab[i].cmnd; + cmndinfo = gdth_cmnd_priv(scp); - b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel; + b = scp->device->channel; t = scp->device->id; if (!SPECIAL_SCP(scp) && t == (unchar)id && b == (unchar)busnum) { - scp->SCp.have_data_in = 0; + cmndinfo->wait_for_completion = 0; spin_unlock_irqrestore(&ha->smp_lock, flags); - while (!scp->SCp.have_data_in) + while (!cmndinfo->wait_for_completion) barrier(); spin_lock_irqsave(&ha->smp_lock, flags); } @@ -794,55 +751,51 @@ static void gdth_wait_completion(int hanum, int busnum, int id) spin_unlock_irqrestore(&ha->smp_lock, flags); } -static void gdth_stop_timeout(int hanum, int busnum, int id) +static void gdth_stop_timeout(gdth_ha_str *ha, int busnum, int id) { - gdth_ha_str *ha; ulong flags; Scsi_Cmnd *scp; unchar b, t; - ha = HADATA(gdth_ctr_tab[hanum]); spin_lock_irqsave(&ha->smp_lock, flags); for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) { - if (scp->done != gdth_scsi_done) { - b = virt_ctr ? - NUMDATA(scp->device->host)->busnum : scp->device->channel; + struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); + if (!cmndinfo->internal_command) { + b = scp->device->channel; t = scp->device->id; if (t == (unchar)id && b == (unchar)busnum) { TRACE2(("gdth_stop_timeout(): update_timeout()\n")); - scp->SCp.buffers_residual = gdth_update_timeout(hanum, scp, 0); + cmndinfo->timeout = gdth_update_timeout(scp, 0); } } } spin_unlock_irqrestore(&ha->smp_lock, flags); } -static void gdth_start_timeout(int hanum, int busnum, int id) +static void gdth_start_timeout(gdth_ha_str *ha, int busnum, int id) { - gdth_ha_str *ha; ulong flags; Scsi_Cmnd *scp; unchar b, t; - ha = HADATA(gdth_ctr_tab[hanum]); spin_lock_irqsave(&ha->smp_lock, flags); for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) { - if (scp->done != gdth_scsi_done) { - b = virt_ctr ? - NUMDATA(scp->device->host)->busnum : scp->device->channel; + struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); + if (!cmndinfo->internal_command) { + b = scp->device->channel; t = scp->device->id; if (t == (unchar)id && b == (unchar)busnum) { TRACE2(("gdth_start_timeout(): update_timeout()\n")); - gdth_update_timeout(hanum, scp, scp->SCp.buffers_residual); + gdth_update_timeout(scp, cmndinfo->timeout); } } } spin_unlock_irqrestore(&ha->smp_lock, flags); } -static int gdth_update_timeout(int hanum, Scsi_Cmnd *scp, int timeout) +static int gdth_update_timeout(Scsi_Cmnd *scp, int timeout) { int oldto; diff --git a/drivers/scsi/gdth_proc.h b/drivers/scsi/gdth_proc.h index a679eeb6820b..45e6fdacf36e 100644 --- a/drivers/scsi/gdth_proc.h +++ b/drivers/scsi/gdth_proc.h @@ -9,20 +9,20 @@ int gdth_execute(struct Scsi_Host *shost, gdth_cmd_str *gdtcmd, char *cmnd, int timeout, u32 *info); static int gdth_set_info(char *buffer,int length,struct Scsi_Host *host, - int hanum,int busnum); + gdth_ha_str *ha); static int gdth_get_info(char *buffer,char **start,off_t offset,int length, - struct Scsi_Host *host,int hanum,int busnum); + struct Scsi_Host *host, gdth_ha_str *ha); static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer, - int length, int hanum); + int length, gdth_ha_str *ha); -static char *gdth_ioctl_alloc(int hanum, int size, int scratch, - ulong64 *paddr); -static void gdth_ioctl_free(int hanum, int size, char *buf, ulong64 paddr); -static void gdth_wait_completion(int hanum, int busnum, int id); -static void gdth_stop_timeout(int hanum, int busnum, int id); -static void gdth_start_timeout(int hanum, int busnum, int id); -static int gdth_update_timeout(int hanum, Scsi_Cmnd *scp, int timeout); +static char *gdth_ioctl_alloc(gdth_ha_str *ha, int size, int scratch, + ulong64 *paddr); +static void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, ulong64 paddr); +static void gdth_wait_completion(gdth_ha_str *ha, int busnum, int id); +static void gdth_stop_timeout(gdth_ha_str *ha, int busnum, int id); +static void gdth_start_timeout(gdth_ha_str *ha, int busnum, int id); +static int gdth_update_timeout(Scsi_Cmnd *scp, int timeout); #endif diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 96bc31266c98..adc9559cb6f4 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -342,6 +342,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) shost->unchecked_isa_dma = sht->unchecked_isa_dma; shost->use_clustering = sht->use_clustering; shost->ordered_tag = sht->ordered_tag; + shost->active_mode = sht->supported_mode; if (sht->max_host_blocked) shost->max_host_blocked = sht->max_host_blocked; diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c index 0e579ca45814..8b384fa7f048 100644 --- a/drivers/scsi/hptiop.c +++ b/drivers/scsi/hptiop.c @@ -1,6 +1,6 @@ /* * HighPoint RR3xxx controller driver for Linux - * Copyright (C) 2006 HighPoint Technologies, Inc. All Rights Reserved. + * Copyright (C) 2006-2007 HighPoint Technologies, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -42,7 +42,7 @@ MODULE_DESCRIPTION("HighPoint RocketRAID 3xxx SATA Controller Driver"); static char driver_name[] = "hptiop"; static const char driver_name_long[] = "RocketRAID 3xxx SATA Controller driver"; -static const char driver_ver[] = "v1.0 (060426)"; +static const char driver_ver[] = "v1.2 (070830)"; static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 tag); static void hptiop_iop_request_callback(struct hptiop_hba *hba, u32 tag); @@ -76,7 +76,7 @@ static int iop_wait_ready(struct hpt_iopmu __iomem *iop, u32 millisec) static void hptiop_request_callback(struct hptiop_hba *hba, u32 tag) { - if ((tag & IOPMU_QUEUE_MASK_HOST_BITS) == IOPMU_QUEUE_ADDR_HOST_BIT) + if (tag & IOPMU_QUEUE_ADDR_HOST_BIT) return hptiop_host_request_callback(hba, tag & ~IOPMU_QUEUE_ADDR_HOST_BIT); else @@ -323,12 +323,22 @@ static inline void free_req(struct hptiop_hba *hba, struct hptiop_request *req) hba->req_list = req; } -static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 tag) +static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 _tag) { struct hpt_iop_request_scsi_command *req; struct scsi_cmnd *scp; + u32 tag; + + if (hba->iopintf_v2) { + tag = _tag & ~ IOPMU_QUEUE_REQUEST_RESULT_BIT; + req = hba->reqs[tag].req_virt; + if (likely(_tag & IOPMU_QUEUE_REQUEST_RESULT_BIT)) + req->header.result = IOP_RESULT_SUCCESS; + } else { + tag = _tag; + req = hba->reqs[tag].req_virt; + } - req = (struct hpt_iop_request_scsi_command *)hba->reqs[tag].req_virt; dprintk("hptiop_host_request_callback: req=%p, type=%d, " "result=%d, context=0x%x tag=%d\n", req, req->header.type, req->header.result, @@ -497,7 +507,7 @@ static int hptiop_queuecommand(struct scsi_cmnd *scp, goto cmd_done; } - req = (struct hpt_iop_request_scsi_command *)_req->req_virt; + req = _req->req_virt; /* build S/G table */ sg_count = hptiop_buildsgl(scp, req->sg_list); @@ -521,8 +531,19 @@ static int hptiop_queuecommand(struct scsi_cmnd *scp, memcpy(req->cdb, scp->cmnd, sizeof(req->cdb)); - writel(IOPMU_QUEUE_ADDR_HOST_BIT | _req->req_shifted_phy, - &hba->iop->inbound_queue); + if (hba->iopintf_v2) { + u32 size_bits; + if (req->header.size < 256) + size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT; + else if (req->header.size < 512) + size_bits = IOPMU_QUEUE_ADDR_HOST_BIT; + else + size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT | + IOPMU_QUEUE_ADDR_HOST_BIT; + writel(_req->req_shifted_phy | size_bits, &hba->iop->inbound_queue); + } else + writel(_req->req_shifted_phy | IOPMU_QUEUE_ADDR_HOST_BIT, + &hba->iop->inbound_queue); return 0; @@ -688,6 +709,7 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev, hba->pcidev = pcidev; hba->host = host; hba->initialized = 0; + hba->iopintf_v2 = 0; atomic_set(&hba->resetting, 0); atomic_set(&hba->reset_count, 0); @@ -722,8 +744,13 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev, hba->max_request_size = le32_to_cpu(iop_config.request_size); hba->max_sg_descriptors = le32_to_cpu(iop_config.max_sg_count); hba->firmware_version = le32_to_cpu(iop_config.firmware_version); + hba->interface_version = le32_to_cpu(iop_config.interface_version); hba->sdram_size = le32_to_cpu(iop_config.sdram_size); + if (hba->firmware_version > 0x01020000 || + hba->interface_version > 0x01020000) + hba->iopintf_v2 = 1; + host->max_sectors = le32_to_cpu(iop_config.data_transfer_length) >> 9; host->max_id = le32_to_cpu(iop_config.max_devices); host->sg_tablesize = le32_to_cpu(iop_config.max_sg_count); @@ -731,8 +758,15 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev, host->cmd_per_lun = le32_to_cpu(iop_config.max_requests); host->max_cmd_len = 16; - set_config.vbus_id = cpu_to_le32(host->host_no); + req_size = sizeof(struct hpt_iop_request_scsi_command) + + sizeof(struct hpt_iopsg) * (hba->max_sg_descriptors - 1); + if ((req_size & 0x1f) != 0) + req_size = (req_size + 0x1f) & ~0x1f; + + memset(&set_config, 0, sizeof(struct hpt_iop_request_set_config)); set_config.iop_id = cpu_to_le32(host->host_no); + set_config.vbus_id = cpu_to_le16(host->host_no); + set_config.max_host_request_size = cpu_to_le16(req_size); if (iop_set_config(hba, &set_config)) { printk(KERN_ERR "scsi%d: set config failed\n", @@ -750,10 +784,6 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev, } /* Allocate request mem */ - req_size = sizeof(struct hpt_iop_request_scsi_command) - + sizeof(struct hpt_iopsg) * (hba->max_sg_descriptors - 1); - if ((req_size& 0x1f) != 0) - req_size = (req_size + 0x1f) & ~0x1f; dprintk("req_size=%d, max_requests=%d\n", req_size, hba->max_requests); @@ -879,8 +909,10 @@ static void hptiop_remove(struct pci_dev *pcidev) } static struct pci_device_id hptiop_id_table[] = { - { PCI_DEVICE(0x1103, 0x3220) }, - { PCI_DEVICE(0x1103, 0x3320) }, + { PCI_VDEVICE(TTI, 0x3220) }, + { PCI_VDEVICE(TTI, 0x3320) }, + { PCI_VDEVICE(TTI, 0x3520) }, + { PCI_VDEVICE(TTI, 0x4320) }, {}, }; @@ -910,3 +942,4 @@ module_init(hptiop_module_init); module_exit(hptiop_module_exit); MODULE_LICENSE("GPL"); + diff --git a/drivers/scsi/hptiop.h b/drivers/scsi/hptiop.h index f04f7e81d1ae..2a5e46e001cb 100644 --- a/drivers/scsi/hptiop.h +++ b/drivers/scsi/hptiop.h @@ -1,6 +1,6 @@ /* * HighPoint RR3xxx controller driver for Linux - * Copyright (C) 2006 HighPoint Technologies, Inc. All Rights Reserved. + * Copyright (C) 2006-2007 HighPoint Technologies, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,219 +18,6 @@ #ifndef _HPTIOP_H_ #define _HPTIOP_H_ -/* - * logical device type. - * Identify array (logical device) and physical device. - */ -#define LDT_ARRAY 1 -#define LDT_DEVICE 2 - -/* - * Array types - */ -#define AT_UNKNOWN 0 -#define AT_RAID0 1 -#define AT_RAID1 2 -#define AT_RAID5 3 -#define AT_RAID6 4 -#define AT_JBOD 7 - -#define MAX_NAME_LENGTH 36 -#define MAX_ARRAYNAME_LEN 16 - -#define MAX_ARRAY_MEMBERS_V1 8 -#define MAX_ARRAY_MEMBERS_V2 16 - -/* keep definition for source code compatiblity */ -#define MAX_ARRAY_MEMBERS MAX_ARRAY_MEMBERS_V1 - -/* - * array flags - */ -#define ARRAY_FLAG_DISABLED 0x00000001 /* The array is disabled */ -#define ARRAY_FLAG_NEEDBUILDING 0x00000002 /* need to be rebuilt */ -#define ARRAY_FLAG_REBUILDING 0x00000004 /* in rebuilding process */ -#define ARRAY_FLAG_BROKEN 0x00000008 /* broken but still working */ -#define ARRAY_FLAG_BOOTDISK 0x00000010 /* has a active partition */ -#define ARRAY_FLAG_BOOTMARK 0x00000040 /* array has boot mark set */ -#define ARRAY_FLAG_NEED_AUTOREBUILD 0x00000080 /* auto-rebuild should start */ -#define ARRAY_FLAG_VERIFYING 0x00000100 /* is being verified */ -#define ARRAY_FLAG_INITIALIZING 0x00000200 /* is being initialized */ -#define ARRAY_FLAG_TRANSFORMING 0x00000400 /* tranform in progress */ -#define ARRAY_FLAG_NEEDTRANSFORM 0x00000800 /* array need tranform */ -#define ARRAY_FLAG_NEEDINITIALIZING 0x00001000 /* initialization not done */ -#define ARRAY_FLAG_BROKEN_REDUNDANT 0x00002000 /* broken but redundant */ - -/* - * device flags - */ -#define DEVICE_FLAG_DISABLED 0x00000001 /* device is disabled */ -#define DEVICE_FLAG_UNINITIALIZED 0x00010000 /* device is not initialized */ -#define DEVICE_FLAG_LEGACY 0x00020000 /* lagacy drive */ -#define DEVICE_FLAG_IS_SPARE 0x80000000 /* is a spare disk */ - -/* - * ioctl codes - */ -#define HPT_CTL_CODE(x) (x+0xFF00) -#define HPT_CTL_CODE_LINUX_TO_IOP(x) ((x)-0xff00) - -#define HPT_IOCTL_GET_CONTROLLER_INFO HPT_CTL_CODE(2) -#define HPT_IOCTL_GET_CHANNEL_INFO HPT_CTL_CODE(3) -#define HPT_IOCTL_GET_LOGICAL_DEVICES HPT_CTL_CODE(4) -#define HPT_IOCTL_GET_DRIVER_CAPABILITIES HPT_CTL_CODE(19) -#define HPT_IOCTL_GET_DEVICE_INFO_V3 HPT_CTL_CODE(46) -#define HPT_IOCTL_GET_CONTROLLER_INFO_V2 HPT_CTL_CODE(47) - -/* - * Controller information. - */ -struct hpt_controller_info { - u8 chip_type; /* chip type */ - u8 interrupt_level; /* IRQ level */ - u8 num_buses; /* bus count */ - u8 chip_flags; - - u8 product_id[MAX_NAME_LENGTH];/* product name */ - u8 vendor_id[MAX_NAME_LENGTH]; /* vendor name */ -} -__attribute__((packed)); - -/* - * Channel information. - */ -struct hpt_channel_info { - __le32 io_port; /* IDE Base Port Address */ - __le32 control_port; /* IDE Control Port Address */ - __le32 devices[2]; /* device connected to this channel */ -} -__attribute__((packed)); - -/* - * Array information. - */ -struct hpt_array_info_v3 { - u8 name[MAX_ARRAYNAME_LEN]; /* array name */ - u8 description[64]; /* array description */ - u8 create_manager[16]; /* who created it */ - __le32 create_time; /* when created it */ - - u8 array_type; /* array type */ - u8 block_size_shift; /* stripe size */ - u8 ndisk; /* Number of ID in Members[] */ - u8 reserved; - - __le32 flags; /* working flags, see ARRAY_FLAG_XXX */ - __le32 members[MAX_ARRAY_MEMBERS_V2]; /* member array/disks */ - - __le32 rebuilding_progress; - __le64 rebuilt_sectors; /* rebuilding point (LBA) for single member */ - - __le32 transform_source; - __le32 transform_target; /* destination device ID */ - __le32 transforming_progress; - __le32 signature; /* persistent identification*/ - __le16 critical_members; /* bit mask of critical members */ - __le16 reserve2; - __le32 reserve; -} -__attribute__((packed)); - -/* - * physical device information. - */ -#define MAX_PARENTS_PER_DISK 8 - -struct hpt_device_info_v2 { - u8 ctlr_id; /* controller id */ - u8 path_id; /* bus */ - u8 target_id; /* id */ - u8 device_mode_setting; /* Current Data Transfer mode: 0-4 PIO0-4 */ - /* 5-7 MW DMA0-2, 8-13 UDMA0-5 */ - u8 device_type; /* device type */ - u8 usable_mode; /* highest usable mode */ - -#ifdef __BIG_ENDIAN_BITFIELD - u8 NCQ_enabled: 1; - u8 NCQ_supported: 1; - u8 TCQ_enabled: 1; - u8 TCQ_supported: 1; - u8 write_cache_enabled: 1; - u8 write_cache_supported: 1; - u8 read_ahead_enabled: 1; - u8 read_ahead_supported: 1; - u8 reserved6: 6; - u8 spin_up_mode: 2; -#else - u8 read_ahead_supported: 1; - u8 read_ahead_enabled: 1; - u8 write_cache_supported: 1; - u8 write_cache_enabled: 1; - u8 TCQ_supported: 1; - u8 TCQ_enabled: 1; - u8 NCQ_supported: 1; - u8 NCQ_enabled: 1; - u8 spin_up_mode: 2; - u8 reserved6: 6; -#endif - - __le32 flags; /* working flags, see DEVICE_FLAG_XXX */ - u8 ident[150]; /* (partitial) Identify Data of this device */ - - __le64 total_free; - __le64 max_free; - __le64 bad_sectors; - __le32 parent_arrays[MAX_PARENTS_PER_DISK]; -} -__attribute__((packed)); - -/* - * Logical device information. - */ -#define INVALID_TARGET_ID 0xFF -#define INVALID_BUS_ID 0xFF - -struct hpt_logical_device_info_v3 { - u8 type; /* LDT_ARRAY or LDT_DEVICE */ - u8 cache_policy; /* refer to CACHE_POLICY_xxx */ - u8 vbus_id; /* vbus sequence in vbus_list */ - u8 target_id; /* OS target id. 0xFF is invalid */ - /* OS name: DISK $VBusId_$TargetId */ - __le64 capacity; /* array capacity */ - __le32 parent_array; /* don't use this field for physical - device. use ParentArrays field in - hpt_device_info_v2 */ - /* reserved statistic fields */ - __le32 stat1; - __le32 stat2; - __le32 stat3; - __le32 stat4; - - union { - struct hpt_array_info_v3 array; - struct hpt_device_info_v2 device; - } __attribute__((packed)) u; - -} -__attribute__((packed)); - -/* - * ioctl structure - */ -#define HPT_IOCTL_MAGIC 0xA1B2C3D4 - -struct hpt_ioctl_u { - u32 magic; /* used to check if it's a valid ioctl packet */ - u32 ioctl_code; /* operation control code */ - void __user *inbuf; /* input data buffer */ - u32 inbuf_size; /* size of input data buffer */ - void __user *outbuf; /* output data buffer */ - u32 outbuf_size; /* size of output data buffer */ - void __user *bytes_returned; /* count of bytes returned */ -} -__attribute__((packed)); - - struct hpt_iopmu { __le32 resrved0[4]; @@ -252,6 +39,8 @@ struct hpt_iopmu #define IOPMU_QUEUE_EMPTY 0xffffffff #define IOPMU_QUEUE_MASK_HOST_BITS 0xf0000000 #define IOPMU_QUEUE_ADDR_HOST_BIT 0x80000000 +#define IOPMU_QUEUE_REQUEST_SIZE_BIT 0x40000000 +#define IOPMU_QUEUE_REQUEST_RESULT_BIT 0x40000000 #define IOPMU_OUTBOUND_INT_MSG0 1 #define IOPMU_OUTBOUND_INT_MSG1 2 @@ -336,7 +125,8 @@ struct hpt_iop_request_set_config { struct hpt_iop_request_header header; __le32 iop_id; - __le32 vbus_id; + __le16 vbus_id; + __le16 max_host_request_size; __le32 reserve[6]; }; @@ -412,9 +202,8 @@ struct hptiop_hba { struct Scsi_Host * host; struct pci_dev * pcidev; - struct list_head link; - /* IOP config info */ + u32 interface_version; u32 firmware_version; u32 sdram_size; u32 max_devices; @@ -423,8 +212,10 @@ struct hptiop_hba { u32 max_sg_descriptors; u32 req_size; /* host-allocated request buffer size */ - int initialized; - int msg_done; + + int iopintf_v2: 1; + int initialized: 1; + int msg_done: 1; struct hptiop_request * req_list; struct hptiop_request reqs[HPTIOP_MAX_REQUESTS]; diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c index 4275d1b04ced..1a924e9b0271 100644 --- a/drivers/scsi/ibmmca.c +++ b/drivers/scsi/ibmmca.c @@ -460,13 +460,6 @@ module_param(boot_options, charp, 0); module_param_array(io_port, int, NULL, 0); module_param_array(scsi_id, int, NULL, 0); -#if 0 /* FIXME: No longer exist? --RR */ -MODULE_PARM(display, "1i"); -MODULE_PARM(adisplay, "1i"); -MODULE_PARM(normal, "1i"); -MODULE_PARM(ansi, "1i"); -#endif - MODULE_LICENSE("GPL"); #endif /*counter of concurrent disk read/writes, to turn on/off disk led */ @@ -1693,6 +1686,7 @@ static int __devexit ibmmca_remove(struct device *dev) scsi_remove_host(shpnt); release_region(shpnt->io_port, shpnt->n_io_port); free_irq(shpnt->irq, dev); + scsi_host_put(shpnt); return 0; } diff --git a/drivers/scsi/ibmvscsi/Makefile b/drivers/scsi/ibmvscsi/Makefile index f67d9efc7a99..6ac0633d5452 100644 --- a/drivers/scsi/ibmvscsi/Makefile +++ b/drivers/scsi/ibmvscsi/Makefile @@ -1,9 +1,7 @@ obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsic.o ibmvscsic-y += ibmvscsi.o -ifndef CONFIG_PPC_PSERIES ibmvscsic-$(CONFIG_PPC_ISERIES) += iseries_vscsi.o -endif ibmvscsic-$(CONFIG_PPC_PSERIES) += rpa_vscsi.o obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvstgt.o diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 5ecc63d1b436..cda0cc3d182f 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -70,11 +70,13 @@ #include <linux/moduleparam.h> #include <linux/dma-mapping.h> #include <linux/delay.h> +#include <asm/firmware.h> #include <asm/vio.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> #include <scsi/scsi_host.h> #include <scsi/scsi_device.h> +#include <scsi/scsi_transport_srp.h> #include "ibmvscsi.h" /* The values below are somewhat arbitrary default values, but @@ -87,8 +89,12 @@ static int max_channel = 3; static int init_timeout = 5; static int max_requests = IBMVSCSI_MAX_REQUESTS_DEFAULT; +static struct scsi_transport_template *ibmvscsi_transport_template; + #define IBMVSCSI_VERSION "1.5.8" +static struct ibmvscsi_ops *ibmvscsi_ops; + MODULE_DESCRIPTION("IBM Virtual SCSI"); MODULE_AUTHOR("Dave Boutcher"); MODULE_LICENSE("GPL"); @@ -506,8 +512,8 @@ static void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata) atomic_set(&hostdata->request_limit, 0); purge_requests(hostdata, DID_ERROR); - if ((ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata)) || - (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0)) || + if ((ibmvscsi_ops->reset_crq_queue(&hostdata->queue, hostdata)) || + (ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0)) || (vio_enable_interrupts(to_vio_dev(hostdata->dev)))) { atomic_set(&hostdata->request_limit, -1); dev_err(hostdata->dev, "error after reset\n"); @@ -612,7 +618,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, } if ((rc = - ibmvscsi_send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) { + ibmvscsi_ops->send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) { list_del(&evt_struct->list); del_timer(&evt_struct->timer); @@ -1211,8 +1217,8 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq, case 0x01: /* Initialization message */ dev_info(hostdata->dev, "partner initialized\n"); /* Send back a response */ - if ((rc = ibmvscsi_send_crq(hostdata, - 0xC002000000000000LL, 0)) == 0) { + if ((rc = ibmvscsi_ops->send_crq(hostdata, + 0xC002000000000000LL, 0)) == 0) { /* Now login */ send_srp_login(hostdata); } else { @@ -1237,10 +1243,10 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq, /* We need to re-setup the interpartition connection */ dev_info(hostdata->dev, "Re-enabling adapter!\n"); purge_requests(hostdata, DID_REQUEUE); - if ((ibmvscsi_reenable_crq_queue(&hostdata->queue, - hostdata)) || - (ibmvscsi_send_crq(hostdata, - 0xC001000000000000LL, 0))) { + if ((ibmvscsi_ops->reenable_crq_queue(&hostdata->queue, + hostdata)) || + (ibmvscsi_ops->send_crq(hostdata, + 0xC001000000000000LL, 0))) { atomic_set(&hostdata->request_limit, -1); dev_err(hostdata->dev, "error after enable\n"); @@ -1250,10 +1256,10 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq, crq->format); purge_requests(hostdata, DID_ERROR); - if ((ibmvscsi_reset_crq_queue(&hostdata->queue, - hostdata)) || - (ibmvscsi_send_crq(hostdata, - 0xC001000000000000LL, 0))) { + if ((ibmvscsi_ops->reset_crq_queue(&hostdata->queue, + hostdata)) || + (ibmvscsi_ops->send_crq(hostdata, + 0xC001000000000000LL, 0))) { atomic_set(&hostdata->request_limit, -1); dev_err(hostdata->dev, "error after reset\n"); @@ -1553,6 +1559,8 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) struct ibmvscsi_host_data *hostdata; struct Scsi_Host *host; struct device *dev = &vdev->dev; + struct srp_rport_identifiers ids; + struct srp_rport *rport; unsigned long wait_switch = 0; int rc; @@ -1565,6 +1573,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) goto scsi_host_alloc_failed; } + host->transportt = ibmvscsi_transport_template; hostdata = shost_priv(host); memset(hostdata, 0x00, sizeof(*hostdata)); INIT_LIST_HEAD(&hostdata->sent); @@ -1573,7 +1582,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) atomic_set(&hostdata->request_limit, -1); hostdata->host->max_sectors = 32 * 8; /* default max I/O 32 pages */ - rc = ibmvscsi_init_crq_queue(&hostdata->queue, hostdata, max_requests); + rc = ibmvscsi_ops->init_crq_queue(&hostdata->queue, hostdata, max_requests); if (rc != 0 && rc != H_RESOURCE) { dev_err(&vdev->dev, "couldn't initialize crq. rc=%d\n", rc); goto init_crq_failed; @@ -1590,11 +1599,19 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) if (scsi_add_host(hostdata->host, hostdata->dev)) goto add_host_failed; + /* we don't have a proper target_port_id so let's use the fake one */ + memcpy(ids.port_id, hostdata->madapter_info.partition_name, + sizeof(ids.port_id)); + ids.roles = SRP_RPORT_ROLE_TARGET; + rport = srp_rport_add(host, &ids); + if (IS_ERR(rport)) + goto add_srp_port_failed; + /* Try to send an initialization message. Note that this is allowed * to fail if the other end is not acive. In that case we don't * want to scan */ - if (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0) == 0 + if (ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0) == 0 || rc == H_RESOURCE) { /* * Wait around max init_timeout secs for the adapter to finish @@ -1617,10 +1634,12 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) vdev->dev.driver_data = hostdata; return 0; + add_srp_port_failed: + scsi_remove_host(hostdata->host); add_host_failed: release_event_pool(&hostdata->pool, hostdata); init_pool_failed: - ibmvscsi_release_crq_queue(&hostdata->queue, hostdata, max_requests); + ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, max_requests); init_crq_failed: scsi_host_put(host); scsi_host_alloc_failed: @@ -1631,9 +1650,10 @@ static int ibmvscsi_remove(struct vio_dev *vdev) { struct ibmvscsi_host_data *hostdata = vdev->dev.driver_data; release_event_pool(&hostdata->pool, hostdata); - ibmvscsi_release_crq_queue(&hostdata->queue, hostdata, - max_requests); - + ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, + max_requests); + + srp_remove_host(hostdata->host); scsi_remove_host(hostdata->host); scsi_host_put(hostdata->host); @@ -1660,14 +1680,35 @@ static struct vio_driver ibmvscsi_driver = { } }; +static struct srp_function_template ibmvscsi_transport_functions = { +}; + int __init ibmvscsi_module_init(void) { - return vio_register_driver(&ibmvscsi_driver); + int ret; + + if (firmware_has_feature(FW_FEATURE_ISERIES)) + ibmvscsi_ops = &iseriesvscsi_ops; + else if (firmware_has_feature(FW_FEATURE_VIO)) + ibmvscsi_ops = &rpavscsi_ops; + else + return -ENODEV; + + ibmvscsi_transport_template = + srp_attach_transport(&ibmvscsi_transport_functions); + if (!ibmvscsi_transport_template) + return -ENOMEM; + + ret = vio_register_driver(&ibmvscsi_driver); + if (ret) + srp_release_transport(ibmvscsi_transport_template); + return ret; } void __exit ibmvscsi_module_exit(void) { vio_unregister_driver(&ibmvscsi_driver); + srp_release_transport(ibmvscsi_transport_template); } module_init(ibmvscsi_module_init); diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h index b19c2e26c2a5..46e850e302c7 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.h +++ b/drivers/scsi/ibmvscsi/ibmvscsi.h @@ -98,21 +98,25 @@ struct ibmvscsi_host_data { }; /* routines for managing a command/response queue */ -int ibmvscsi_init_crq_queue(struct crq_queue *queue, - struct ibmvscsi_host_data *hostdata, - int max_requests); -void ibmvscsi_release_crq_queue(struct crq_queue *queue, - struct ibmvscsi_host_data *hostdata, - int max_requests); -int ibmvscsi_reset_crq_queue(struct crq_queue *queue, - struct ibmvscsi_host_data *hostdata); - -int ibmvscsi_reenable_crq_queue(struct crq_queue *queue, - struct ibmvscsi_host_data *hostdata); - void ibmvscsi_handle_crq(struct viosrp_crq *crq, struct ibmvscsi_host_data *hostdata); -int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, - u64 word1, u64 word2); + +struct ibmvscsi_ops { + int (*init_crq_queue)(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata, + int max_requests); + void (*release_crq_queue)(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata, + int max_requests); + int (*reset_crq_queue)(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata); + int (*reenable_crq_queue)(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata); + int (*send_crq)(struct ibmvscsi_host_data *hostdata, + u64 word1, u64 word2); +}; + +extern struct ibmvscsi_ops iseriesvscsi_ops; +extern struct ibmvscsi_ops rpavscsi_ops; #endif /* IBMVSCSI_H */ diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c index 8ba7dd09d01d..82bcab688b44 100644 --- a/drivers/scsi/ibmvscsi/ibmvstgt.c +++ b/drivers/scsi/ibmvscsi/ibmvstgt.c @@ -25,6 +25,7 @@ #include <linux/module.h> #include <scsi/scsi.h> #include <scsi/scsi_host.h> +#include <scsi/scsi_transport_srp.h> #include <scsi/scsi_tgt.h> #include <scsi/libsrp.h> #include <asm/hvcall.h> @@ -68,9 +69,12 @@ struct vio_port { unsigned long liobn; unsigned long riobn; struct srp_target *target; + + struct srp_rport *rport; }; static struct workqueue_struct *vtgtd; +static struct scsi_transport_template *ibmvstgt_transport_template; /* * These are fixed for the system and come from the Open Firmware device tree. @@ -188,6 +192,7 @@ static int send_rsp(struct iu_entry *iue, struct scsi_cmnd *sc, static void handle_cmd_queue(struct srp_target *target) { struct Scsi_Host *shost = target->shost; + struct srp_rport *rport = target_to_port(target)->rport; struct iu_entry *iue; struct srp_cmd *cmd; unsigned long flags; @@ -200,7 +205,8 @@ retry: if (!test_and_set_bit(V_FLYING, &iue->flags)) { spin_unlock_irqrestore(&target->lock, flags); cmd = iue->sbuf->buf; - err = srp_cmd_queue(shost, cmd, iue, 0); + err = srp_cmd_queue(shost, cmd, iue, + (unsigned long)rport, 0); if (err) { eprintk("cannot queue cmd %p %d\n", cmd, err); srp_iu_put(iue); @@ -359,6 +365,16 @@ static void process_login(struct iu_entry *iue) union viosrp_iu *iu = vio_iu(iue); struct srp_login_rsp *rsp = &iu->srp.login_rsp; uint64_t tag = iu->srp.rsp.tag; + struct Scsi_Host *shost = iue->target->shost; + struct srp_target *target = host_to_srp_target(shost); + struct vio_port *vport = target_to_port(target); + struct srp_rport_identifiers ids; + + memset(&ids, 0, sizeof(ids)); + sprintf(ids.port_id, "%x", vport->dma_dev->unit_address); + ids.roles = SRP_RPORT_ROLE_INITIATOR; + if (!vport->rport) + vport->rport = srp_rport_add(shost, &ids); /* TODO handle case that requested size is wrong and * buffer format is wrong @@ -412,7 +428,9 @@ static int process_tsk_mgmt(struct iu_entry *iue) fn = 0; } if (fn) - scsi_tgt_tsk_mgmt_request(iue->target->shost, fn, + scsi_tgt_tsk_mgmt_request(iue->target->shost, + (unsigned long)iue->target->shost, + fn, iu->srp.tsk_mgmt.task_tag, (struct scsi_lun *) &iu->srp.tsk_mgmt.lun, iue); @@ -721,7 +739,8 @@ static int ibmvstgt_eh_abort_handler(struct scsi_cmnd *sc) return 0; } -static int ibmvstgt_tsk_mgmt_response(u64 mid, int result) +static int ibmvstgt_tsk_mgmt_response(struct Scsi_Host *shost, + u64 itn_id, u64 mid, int result) { struct iu_entry *iue = (struct iu_entry *) ((void *) mid); union viosrp_iu *iu = vio_iu(iue); @@ -747,6 +766,20 @@ static int ibmvstgt_tsk_mgmt_response(u64 mid, int result) return 0; } +static int ibmvstgt_it_nexus_response(struct Scsi_Host *shost, u64 itn_id, + int result) +{ + struct srp_target *target = host_to_srp_target(shost); + struct vio_port *vport = target_to_port(target); + + if (result) { + eprintk("%p %d\n", shost, result); + srp_rport_del(vport->rport); + vport->rport = NULL; + } + return 0; +} + static ssize_t system_id_show(struct class_device *cdev, char *buf) { return snprintf(buf, PAGE_SIZE, "%s\n", system_id); @@ -785,9 +818,9 @@ static struct scsi_host_template ibmvstgt_sht = { .max_sectors = DEFAULT_MAX_SECTORS, .transfer_response = ibmvstgt_cmd_done, .eh_abort_handler = ibmvstgt_eh_abort_handler, - .tsk_mgmt_response = ibmvstgt_tsk_mgmt_response, .shost_attrs = ibmvstgt_attrs, .proc_name = TGT_NAME, + .supported_mode = MODE_TARGET, }; static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id) @@ -804,6 +837,7 @@ static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id) shost = scsi_host_alloc(&ibmvstgt_sht, sizeof(struct srp_target)); if (!shost) goto free_vport; + shost->transportt = ibmvstgt_transport_template; err = scsi_tgt_alloc_queue(shost); if (err) goto put_host; @@ -837,8 +871,8 @@ static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id) err = scsi_add_host(shost, target->dev); if (err) goto destroy_queue; - return 0; + return 0; destroy_queue: crq_queue_destroy(target); free_srp_target: @@ -857,6 +891,7 @@ static int ibmvstgt_remove(struct vio_dev *dev) struct vio_port *vport = target->ldata; crq_queue_destroy(target); + srp_remove_host(shost); scsi_remove_host(shost); scsi_tgt_free_queue(shost); srp_target_free(target); @@ -909,15 +944,25 @@ static int get_system_info(void) return 0; } +static struct srp_function_template ibmvstgt_transport_functions = { + .tsk_mgmt_response = ibmvstgt_tsk_mgmt_response, + .it_nexus_response = ibmvstgt_it_nexus_response, +}; + static int ibmvstgt_init(void) { int err = -ENOMEM; printk("IBM eServer i/pSeries Virtual SCSI Target Driver\n"); + ibmvstgt_transport_template = + srp_attach_transport(&ibmvstgt_transport_functions); + if (!ibmvstgt_transport_template) + return err; + vtgtd = create_workqueue("ibmvtgtd"); if (!vtgtd) - return err; + goto release_transport; err = get_system_info(); if (err) @@ -928,9 +973,10 @@ static int ibmvstgt_init(void) goto destroy_wq; return 0; - destroy_wq: destroy_workqueue(vtgtd); +release_transport: + srp_release_transport(ibmvstgt_transport_template); return err; } @@ -940,6 +986,7 @@ static void ibmvstgt_exit(void) destroy_workqueue(vtgtd); vio_unregister_driver(&ibmvstgt_driver); + srp_release_transport(ibmvstgt_transport_template); } MODULE_DESCRIPTION("IBM Virtual SCSI Target"); diff --git a/drivers/scsi/ibmvscsi/iseries_vscsi.c b/drivers/scsi/ibmvscsi/iseries_vscsi.c index 6aeb5f003c3c..0775fdee5fa8 100644 --- a/drivers/scsi/ibmvscsi/iseries_vscsi.c +++ b/drivers/scsi/ibmvscsi/iseries_vscsi.c @@ -53,7 +53,7 @@ struct srp_lp_event { /** * standard interface for handling logical partition events. */ -static void ibmvscsi_handle_event(struct HvLpEvent *lpevt) +static void iseriesvscsi_handle_event(struct HvLpEvent *lpevt) { struct srp_lp_event *evt = (struct srp_lp_event *)lpevt; @@ -74,9 +74,9 @@ static void ibmvscsi_handle_event(struct HvLpEvent *lpevt) /* ------------------------------------------------------------ * Routines for driver initialization */ -int ibmvscsi_init_crq_queue(struct crq_queue *queue, - struct ibmvscsi_host_data *hostdata, - int max_requests) +static int iseriesvscsi_init_crq_queue(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata, + int max_requests) { int rc; @@ -88,7 +88,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue, goto viopath_open_failed; } - rc = vio_setHandler(viomajorsubtype_scsi, ibmvscsi_handle_event); + rc = vio_setHandler(viomajorsubtype_scsi, iseriesvscsi_handle_event); if (rc < 0) { printk("vio_setHandler failed with rc %d in open_event_path\n", rc); @@ -102,9 +102,9 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue, return -1; } -void ibmvscsi_release_crq_queue(struct crq_queue *queue, - struct ibmvscsi_host_data *hostdata, - int max_requests) +static void iseriesvscsi_release_crq_queue(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata, + int max_requests) { vio_clearHandler(viomajorsubtype_scsi); viopath_close(viopath_hostLp, viomajorsubtype_scsi, max_requests); @@ -117,8 +117,8 @@ void ibmvscsi_release_crq_queue(struct crq_queue *queue, * * no-op for iSeries */ -int ibmvscsi_reset_crq_queue(struct crq_queue *queue, - struct ibmvscsi_host_data *hostdata) +static int iseriesvscsi_reset_crq_queue(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata) { return 0; } @@ -130,19 +130,20 @@ int ibmvscsi_reset_crq_queue(struct crq_queue *queue, * * no-op for iSeries */ -int ibmvscsi_reenable_crq_queue(struct crq_queue *queue, - struct ibmvscsi_host_data *hostdata) +static int iseriesvscsi_reenable_crq_queue(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata) { return 0; } /** - * ibmvscsi_send_crq: - Send a CRQ + * iseriesvscsi_send_crq: - Send a CRQ * @hostdata: the adapter * @word1: the first 64 bits of the data * @word2: the second 64 bits of the data */ -int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2) +static int iseriesvscsi_send_crq(struct ibmvscsi_host_data *hostdata, + u64 word1, u64 word2) { single_host_data = hostdata; return HvCallEvent_signalLpEventFast(viopath_hostLp, @@ -156,3 +157,11 @@ int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2) VIOVERSION << 16, word1, word2, 0, 0); } + +struct ibmvscsi_ops iseriesvscsi_ops = { + .init_crq_queue = iseriesvscsi_init_crq_queue, + .release_crq_queue = iseriesvscsi_release_crq_queue, + .reset_crq_queue = iseriesvscsi_reset_crq_queue, + .reenable_crq_queue = iseriesvscsi_reenable_crq_queue, + .send_crq = iseriesvscsi_send_crq, +}; diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c index 9c14e789df5f..182146100dc1 100644 --- a/drivers/scsi/ibmvscsi/rpa_vscsi.c +++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c @@ -42,14 +42,14 @@ static unsigned int partition_number = -1; * Routines for managing the command/response queue */ /** - * ibmvscsi_handle_event: - Interrupt handler for crq events + * rpavscsi_handle_event: - Interrupt handler for crq events * @irq: number of irq to handle, not used * @dev_instance: ibmvscsi_host_data of host that received interrupt * * Disables interrupts and schedules srp_task * Always returns IRQ_HANDLED */ -static irqreturn_t ibmvscsi_handle_event(int irq, void *dev_instance) +static irqreturn_t rpavscsi_handle_event(int irq, void *dev_instance) { struct ibmvscsi_host_data *hostdata = (struct ibmvscsi_host_data *)dev_instance; @@ -66,9 +66,9 @@ static irqreturn_t ibmvscsi_handle_event(int irq, void *dev_instance) * Frees irq, deallocates a page for messages, unmaps dma, and unregisters * the crq with the hypervisor. */ -void ibmvscsi_release_crq_queue(struct crq_queue *queue, - struct ibmvscsi_host_data *hostdata, - int max_requests) +static void rpavscsi_release_crq_queue(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata, + int max_requests) { long rc; struct vio_dev *vdev = to_vio_dev(hostdata->dev); @@ -108,12 +108,13 @@ static struct viosrp_crq *crq_queue_next_crq(struct crq_queue *queue) } /** - * ibmvscsi_send_crq: - Send a CRQ + * rpavscsi_send_crq: - Send a CRQ * @hostdata: the adapter * @word1: the first 64 bits of the data * @word2: the second 64 bits of the data */ -int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2) +static int rpavscsi_send_crq(struct ibmvscsi_host_data *hostdata, + u64 word1, u64 word2) { struct vio_dev *vdev = to_vio_dev(hostdata->dev); @@ -121,10 +122,10 @@ int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2) } /** - * ibmvscsi_task: - Process srps asynchronously + * rpavscsi_task: - Process srps asynchronously * @data: ibmvscsi_host_data of host */ -static void ibmvscsi_task(void *data) +static void rpavscsi_task(void *data) { struct ibmvscsi_host_data *hostdata = (struct ibmvscsi_host_data *)data; struct vio_dev *vdev = to_vio_dev(hostdata->dev); @@ -190,6 +191,42 @@ static void set_adapter_info(struct ibmvscsi_host_data *hostdata) } /** + * reset_crq_queue: - resets a crq after a failure + * @queue: crq_queue to initialize and register + * @hostdata: ibmvscsi_host_data of host + * + */ +static int rpavscsi_reset_crq_queue(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata) +{ + int rc; + struct vio_dev *vdev = to_vio_dev(hostdata->dev); + + /* Close the CRQ */ + do { + rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); + } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc))); + + /* Clean out the queue */ + memset(queue->msgs, 0x00, PAGE_SIZE); + queue->cur = 0; + + set_adapter_info(hostdata); + + /* And re-open it again */ + rc = plpar_hcall_norets(H_REG_CRQ, + vdev->unit_address, + queue->msg_token, PAGE_SIZE); + if (rc == 2) { + /* Adapter is good, but other end is not ready */ + dev_warn(hostdata->dev, "Partner adapter not ready\n"); + } else if (rc != 0) { + dev_warn(hostdata->dev, "couldn't register crq--rc 0x%x\n", rc); + } + return rc; +} + +/** * initialize_crq_queue: - Initializes and registers CRQ with hypervisor * @queue: crq_queue to initialize and register * @hostdata: ibmvscsi_host_data of host @@ -198,9 +235,9 @@ static void set_adapter_info(struct ibmvscsi_host_data *hostdata) * the crq with the hypervisor. * Returns zero on success. */ -int ibmvscsi_init_crq_queue(struct crq_queue *queue, - struct ibmvscsi_host_data *hostdata, - int max_requests) +static int rpavscsi_init_crq_queue(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata, + int max_requests) { int rc; int retrc; @@ -227,7 +264,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue, queue->msg_token, PAGE_SIZE); if (rc == H_RESOURCE) /* maybe kexecing and resource is busy. try a reset */ - rc = ibmvscsi_reset_crq_queue(queue, + rc = rpavscsi_reset_crq_queue(queue, hostdata); if (rc == 2) { @@ -240,7 +277,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue, } if (request_irq(vdev->irq, - ibmvscsi_handle_event, + rpavscsi_handle_event, 0, "ibmvscsi", (void *)hostdata) != 0) { dev_err(hostdata->dev, "couldn't register irq 0x%x\n", vdev->irq); @@ -256,7 +293,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue, queue->cur = 0; spin_lock_init(&queue->lock); - tasklet_init(&hostdata->srp_task, (void *)ibmvscsi_task, + tasklet_init(&hostdata->srp_task, (void *)rpavscsi_task, (unsigned long)hostdata); return retrc; @@ -281,8 +318,8 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue, * @hostdata: ibmvscsi_host_data of host * */ -int ibmvscsi_reenable_crq_queue(struct crq_queue *queue, - struct ibmvscsi_host_data *hostdata) +static int rpavscsi_reenable_crq_queue(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata) { int rc; struct vio_dev *vdev = to_vio_dev(hostdata->dev); @@ -297,38 +334,10 @@ int ibmvscsi_reenable_crq_queue(struct crq_queue *queue, return rc; } -/** - * reset_crq_queue: - resets a crq after a failure - * @queue: crq_queue to initialize and register - * @hostdata: ibmvscsi_host_data of host - * - */ -int ibmvscsi_reset_crq_queue(struct crq_queue *queue, - struct ibmvscsi_host_data *hostdata) -{ - int rc; - struct vio_dev *vdev = to_vio_dev(hostdata->dev); - - /* Close the CRQ */ - do { - rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); - } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc))); - - /* Clean out the queue */ - memset(queue->msgs, 0x00, PAGE_SIZE); - queue->cur = 0; - - set_adapter_info(hostdata); - - /* And re-open it again */ - rc = plpar_hcall_norets(H_REG_CRQ, - vdev->unit_address, - queue->msg_token, PAGE_SIZE); - if (rc == 2) { - /* Adapter is good, but other end is not ready */ - dev_warn(hostdata->dev, "Partner adapter not ready\n"); - } else if (rc != 0) { - dev_warn(hostdata->dev, "couldn't register crq--rc 0x%x\n", rc); - } - return rc; -} +struct ibmvscsi_ops rpavscsi_ops = { + .init_crq_queue = rpavscsi_init_crq_queue, + .release_crq_queue = rpavscsi_release_crq_queue, + .reset_crq_queue = rpavscsi_reset_crq_queue, + .reenable_crq_queue = rpavscsi_reenable_crq_queue, + .send_crq = rpavscsi_send_crq, +}; diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index 1cc01acc2808..d81bb076a15a 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -82,14 +82,12 @@ typedef struct idescsi_pc_s { */ #define PC_DMA_IN_PROGRESS 0 /* 1 while DMA in progress */ #define PC_WRITING 1 /* Data direction */ -#define PC_TRANSFORM 2 /* transform SCSI commands */ #define PC_TIMEDOUT 3 /* command timed out */ #define PC_DMA_OK 4 /* Use DMA */ /* * SCSI command transformation layer */ -#define IDESCSI_TRANSFORM 0 /* Enable/Disable transformation */ #define IDESCSI_SG_TRANSFORM 1 /* /dev/sg transformation */ /* @@ -175,7 +173,8 @@ static void idescsi_input_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsigne char *buf; while (bcount) { - if (pc->sg - (struct scatterlist *) pc->scsi_cmd->request_buffer > pc->scsi_cmd->use_sg) { + if (pc->sg - scsi_sglist(pc->scsi_cmd) > + scsi_sg_count(pc->scsi_cmd)) { printk (KERN_ERR "ide-scsi: scatter gather table too small, discarding data\n"); idescsi_discard_data (drive, bcount); return; @@ -210,7 +209,8 @@ static void idescsi_output_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsign char *buf; while (bcount) { - if (pc->sg - (struct scatterlist *) pc->scsi_cmd->request_buffer > pc->scsi_cmd->use_sg) { + if (pc->sg - scsi_sglist(pc->scsi_cmd) > + scsi_sg_count(pc->scsi_cmd)) { printk (KERN_ERR "ide-scsi: scatter gather table too small, padding with zeros\n"); idescsi_output_zeros (drive, bcount); return; @@ -239,77 +239,6 @@ static void idescsi_output_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsign } } -/* - * Most of the SCSI commands are supported directly by ATAPI devices. - * idescsi_transform_pc handles the few exceptions. - */ -static inline void idescsi_transform_pc1 (ide_drive_t *drive, idescsi_pc_t *pc) -{ - u8 *c = pc->c, *scsi_buf = pc->buffer, *sc = pc->scsi_cmd->cmnd; - char *atapi_buf; - - if (!test_bit(PC_TRANSFORM, &pc->flags)) - return; - if (drive->media == ide_cdrom || drive->media == ide_optical) { - if (c[0] == READ_6 || c[0] == WRITE_6) { - c[8] = c[4]; c[5] = c[3]; c[4] = c[2]; - c[3] = c[1] & 0x1f; c[2] = 0; c[1] &= 0xe0; - c[0] += (READ_10 - READ_6); - } - if (c[0] == MODE_SENSE || c[0] == MODE_SELECT) { - unsigned short new_len; - if (!scsi_buf) - return; - if ((atapi_buf = kmalloc(pc->buffer_size + 4, GFP_ATOMIC)) == NULL) - return; - memset(atapi_buf, 0, pc->buffer_size + 4); - memset (c, 0, 12); - c[0] = sc[0] | 0x40; - c[1] = sc[1]; - c[2] = sc[2]; - new_len = sc[4] + 4; - c[8] = new_len; - c[7] = new_len >> 8; - c[9] = sc[5]; - if (c[0] == MODE_SELECT_10) { - atapi_buf[1] = scsi_buf[0]; /* Mode data length */ - atapi_buf[2] = scsi_buf[1]; /* Medium type */ - atapi_buf[3] = scsi_buf[2]; /* Device specific parameter */ - atapi_buf[7] = scsi_buf[3]; /* Block descriptor length */ - memcpy(atapi_buf + 8, scsi_buf + 4, pc->buffer_size - 4); - } - pc->buffer = atapi_buf; - pc->request_transfer += 4; - pc->buffer_size += 4; - } - } -} - -static inline void idescsi_transform_pc2 (ide_drive_t *drive, idescsi_pc_t *pc) -{ - u8 *atapi_buf = pc->buffer; - u8 *sc = pc->scsi_cmd->cmnd; - u8 *scsi_buf = pc->scsi_cmd->request_buffer; - - if (!test_bit(PC_TRANSFORM, &pc->flags)) - return; - if (drive->media == ide_cdrom || drive->media == ide_optical) { - if (pc->c[0] == MODE_SENSE_10 && sc[0] == MODE_SENSE) { - scsi_buf[0] = atapi_buf[1]; /* Mode data length */ - scsi_buf[1] = atapi_buf[2]; /* Medium type */ - scsi_buf[2] = atapi_buf[3]; /* Device specific parameter */ - scsi_buf[3] = atapi_buf[7]; /* Block descriptor length */ - memcpy(scsi_buf + 4, atapi_buf + 8, pc->request_transfer - 8); - } - if (pc->c[0] == INQUIRY) { - scsi_buf[2] |= 2; /* ansi_revision */ - scsi_buf[3] = (scsi_buf[3] & 0xf0) | 2; /* response data format */ - } - } - if (atapi_buf && atapi_buf != scsi_buf) - kfree(atapi_buf); -} - static void hexdump(u8 *x, int len) { int i; @@ -393,7 +322,6 @@ static int idescsi_end_request (ide_drive_t *drive, int uptodate, int nrsecs) idescsi_pc_t *pc = (idescsi_pc_t *) rq->special; int log = test_bit(IDESCSI_LOG_CMD, &scsi->log); struct Scsi_Host *host; - u8 *scsi_buf; int errors = rq->errors; unsigned long flags; @@ -434,15 +362,6 @@ static int idescsi_end_request (ide_drive_t *drive, int uptodate, int nrsecs) pc->scsi_cmd->result = (CHECK_CONDITION << 1) | (DID_OK << 16); } else { pc->scsi_cmd->result = DID_OK << 16; - idescsi_transform_pc2 (drive, pc); - if (log) { - printk ("ide-scsi: %s: suc %lu", drive->name, pc->scsi_cmd->serial_number); - if (!test_bit(PC_WRITING, &pc->flags) && pc->actually_transferred && pc->actually_transferred <= 1024 && pc->buffer) { - printk(", rst = "); - scsi_buf = pc->scsi_cmd->request_buffer; - hexdump(scsi_buf, min_t(unsigned, 16, pc->scsi_cmd->request_bufflen)); - } else printk("\n"); - } } host = pc->scsi_cmd->device->host; spin_lock_irqsave(host->host_lock, flags); @@ -637,19 +556,14 @@ static int idescsi_map_sg(ide_drive_t *drive, idescsi_pc_t *pc) return 1; sg = hwif->sg_table; - scsi_sg = pc->scsi_cmd->request_buffer; - segments = pc->scsi_cmd->use_sg; + scsi_sg = scsi_sglist(pc->scsi_cmd); + segments = scsi_sg_count(pc->scsi_cmd); if (segments > hwif->sg_max_nents) return 1; - if (!segments) { - hwif->sg_nents = 1; - sg_init_one(sg, pc->scsi_cmd->request_buffer, pc->request_transfer); - } else { - hwif->sg_nents = segments; - memcpy(sg, scsi_sg, sizeof(*sg) * segments); - } + hwif->sg_nents = segments; + memcpy(sg, scsi_sg, sizeof(*sg) * segments); return 0; } @@ -744,7 +658,6 @@ static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi) { if (drive->id && (drive->id->config & 0x0060) == 0x20) set_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags); - set_bit(IDESCSI_TRANSFORM, &scsi->transform); clear_bit(IDESCSI_SG_TRANSFORM, &scsi->transform); #if IDESCSI_DEBUG_LOG set_bit(IDESCSI_LOG_CMD, &scsi->log); @@ -758,6 +671,7 @@ static void ide_scsi_remove(ide_drive_t *drive) struct ide_scsi_obj *scsi = scsihost_to_idescsi(scsihost); struct gendisk *g = scsi->disk; + scsi_remove_host(scsihost); ide_proc_unregister_driver(drive, scsi->driver); ide_unregister_region(g); @@ -766,7 +680,6 @@ static void ide_scsi_remove(ide_drive_t *drive) g->private_data = NULL; put_disk(g); - scsi_remove_host(scsihost); ide_scsi_put(scsi); } @@ -838,6 +751,8 @@ static struct block_device_operations idescsi_ops = { static int idescsi_slave_configure(struct scsi_device * sdp) { /* Configure detected device */ + sdp->use_10_for_rw = 1; + sdp->use_10_for_ms = 1; scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, sdp->host->cmd_per_lun); return 0; } @@ -862,24 +777,6 @@ static int idescsi_ioctl (struct scsi_device *dev, int cmd, void __user *arg) return -EINVAL; } -static inline int should_transform(ide_drive_t *drive, struct scsi_cmnd *cmd) -{ - idescsi_scsi_t *scsi = drive_to_idescsi(drive); - - /* this was a layering violation and we can't support it - anymore, sorry. */ -#if 0 - struct gendisk *disk = cmd->request->rq_disk; - - if (disk) { - struct struct scsi_device_Template **p = disk->private_data; - if (strcmp((*p)->scsi_driverfs_driver.name, "sg") == 0) - return test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform); - } -#endif - return test_bit(IDESCSI_TRANSFORM, &scsi->transform); -} - static int idescsi_queue (struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) { @@ -905,23 +802,14 @@ static int idescsi_queue (struct scsi_cmnd *cmd, pc->flags = 0; pc->rq = rq; memcpy (pc->c, cmd->cmnd, cmd->cmd_len); - if (cmd->use_sg) { - pc->buffer = NULL; - pc->sg = cmd->request_buffer; - } else { - pc->buffer = cmd->request_buffer; - pc->sg = NULL; - } + pc->buffer = NULL; + pc->sg = scsi_sglist(cmd); pc->b_count = 0; - pc->request_transfer = pc->buffer_size = cmd->request_bufflen; + pc->request_transfer = pc->buffer_size = scsi_bufflen(cmd); pc->scsi_cmd = cmd; pc->done = done; pc->timeout = jiffies + cmd->timeout_per_command; - if (should_transform(drive, cmd)) - set_bit(PC_TRANSFORM, &pc->flags); - idescsi_transform_pc1 (drive, pc); - if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) { printk ("ide-scsi: %s: que %lu, cmd = ", drive->name, cmd->serial_number); hexdump(cmd->cmnd, cmd->cmd_len); diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c index 005d2b05f32d..74cdc1f0a78f 100644 --- a/drivers/scsi/imm.c +++ b/drivers/scsi/imm.c @@ -740,10 +740,6 @@ static void imm_interrupt(struct work_struct *work) struct Scsi_Host *host = cmd->device->host; unsigned long flags; - if (!cmd) { - printk("IMM: bug in imm_interrupt\n"); - return; - } if (imm_engine(dev, cmd)) { schedule_delayed_work(&dev->imm_tq, 1); return; diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c index 312190a69389..ab7cbf3449ce 100644 --- a/drivers/scsi/in2000.c +++ b/drivers/scsi/in2000.c @@ -343,7 +343,7 @@ static int in2000_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) instance = cmd->device->host; hostdata = (struct IN2000_hostdata *) instance->hostdata; - DB(DB_QUEUE_COMMAND, scmd_printk(KERN_DEBUG, cmd, "Q-%02x-%ld(", cmd->cmnd[0], cmd->pid)) + DB(DB_QUEUE_COMMAND, scmd_printk(KERN_DEBUG, cmd, "Q-%02x-%ld(", cmd->cmnd[0], cmd->serial_number)) /* Set up a few fields in the Scsi_Cmnd structure for our own use: * - host_scribble is the pointer to the next cmd in the input queue @@ -427,7 +427,7 @@ static int in2000_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) in2000_execute(cmd->device->host); - DB(DB_QUEUE_COMMAND, printk(")Q-%ld ", cmd->pid)) + DB(DB_QUEUE_COMMAND, printk(")Q-%ld ", cmd->serial_number)) return 0; } @@ -703,7 +703,7 @@ static void in2000_execute(struct Scsi_Host *instance) * to search the input_Q again... */ - DB(DB_EXECUTE, printk("%s%ld)EX-2 ", (cmd->SCp.phase) ? "d:" : "", cmd->pid)) + DB(DB_EXECUTE, printk("%s%ld)EX-2 ", (cmd->SCp.phase) ? "d:" : "", cmd->serial_number)) } @@ -1147,7 +1147,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id) case CSR_XFER_DONE | PHS_COMMAND: case CSR_UNEXP | PHS_COMMAND: case CSR_SRV_REQ | PHS_COMMAND: - DB(DB_INTR, printk("CMND-%02x,%ld", cmd->cmnd[0], cmd->pid)) + DB(DB_INTR, printk("CMND-%02x,%ld", cmd->cmnd[0], cmd->serial_number)) transfer_pio(cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR, hostdata); hostdata->state = S_CONNECTED; break; @@ -1189,7 +1189,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id) switch (msg) { case COMMAND_COMPLETE: - DB(DB_INTR, printk("CCMP-%ld", cmd->pid)) + DB(DB_INTR, printk("CCMP-%ld", cmd->serial_number)) write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK); hostdata->state = S_PRE_CMP_DISC; break; @@ -1327,7 +1327,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id) write_3393(hostdata, WD_SOURCE_ID, SRCID_ER); if (phs == 0x60) { - DB(DB_INTR, printk("SX-DONE-%ld", cmd->pid)) + DB(DB_INTR, printk("SX-DONE-%ld", cmd->serial_number)) cmd->SCp.Message = COMMAND_COMPLETE; lun = read_3393(hostdata, WD_TARGET_LUN); DB(DB_INTR, printk(":%d.%d", cmd->SCp.Status, lun)) @@ -1348,7 +1348,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id) in2000_execute(instance); } else { - printk("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---", asr, sr, phs, cmd->pid); + printk("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---", asr, sr, phs, cmd->serial_number); } break; @@ -1415,7 +1415,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id) spin_unlock_irqrestore(instance->host_lock, flags); return IRQ_HANDLED; } - DB(DB_INTR, printk("UNEXP_DISC-%ld", cmd->pid)) + DB(DB_INTR, printk("UNEXP_DISC-%ld", cmd->serial_number)) hostdata->connected = NULL; hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); hostdata->state = S_UNCONNECTED; @@ -1440,7 +1440,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id) */ write_3393(hostdata, WD_SOURCE_ID, SRCID_ER); - DB(DB_INTR, printk("DISC-%ld", cmd->pid)) + DB(DB_INTR, printk("DISC-%ld", cmd->serial_number)) if (cmd == NULL) { printk(" - Already disconnected! "); hostdata->state = S_UNCONNECTED; @@ -1573,7 +1573,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id) } else hostdata->state = S_CONNECTED; - DB(DB_INTR, printk("-%ld", cmd->pid)) + DB(DB_INTR, printk("-%ld", cmd->serial_number)) break; default: @@ -1702,7 +1702,7 @@ static int __in2000_abort(Scsi_Cmnd * cmd) prev->host_scribble = cmd->host_scribble; cmd->host_scribble = NULL; cmd->result = DID_ABORT << 16; - printk(KERN_WARNING "scsi%d: Abort - removing command %ld from input_Q. ", instance->host_no, cmd->pid); + printk(KERN_WARNING "scsi%d: Abort - removing command %ld from input_Q. ", instance->host_no, cmd->serial_number); cmd->scsi_done(cmd); return SUCCESS; } @@ -1723,7 +1723,7 @@ static int __in2000_abort(Scsi_Cmnd * cmd) if (hostdata->connected == cmd) { - printk(KERN_WARNING "scsi%d: Aborting connected command %ld - ", instance->host_no, cmd->pid); + printk(KERN_WARNING "scsi%d: Aborting connected command %ld - ", instance->host_no, cmd->serial_number); printk("sending wd33c93 ABORT command - "); write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); @@ -2268,7 +2268,7 @@ static int in2000_proc_info(struct Scsi_Host *instance, char *buf, char **start, strcat(bp, "\nconnected: "); if (hd->connected) { cmd = (Scsi_Cmnd *) hd->connected; - sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); + sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); strcat(bp, tbuf); } } @@ -2276,7 +2276,7 @@ static int in2000_proc_info(struct Scsi_Host *instance, char *buf, char **start, strcat(bp, "\ninput_Q: "); cmd = (Scsi_Cmnd *) hd->input_Q; while (cmd) { - sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); + sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); strcat(bp, tbuf); cmd = (Scsi_Cmnd *) cmd->host_scribble; } @@ -2285,7 +2285,7 @@ static int in2000_proc_info(struct Scsi_Host *instance, char *buf, char **start, strcat(bp, "\ndisconnected_Q:"); cmd = (Scsi_Cmnd *) hd->disconnected_Q; while (cmd) { - sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); + sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); strcat(bp, tbuf); cmd = (Scsi_Cmnd *) cmd->host_scribble; } diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index f142eafb6fc7..b41dfb539021 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -3829,18 +3829,18 @@ static int ipr_device_reset(struct ipr_ioa_cfg *ioa_cfg, /** * ipr_sata_reset - Reset the SATA port - * @ap: SATA port to reset + * @link: SATA link to reset * @classes: class of the attached device * - * This function issues a SATA phy reset to the affected ATA port. + * This function issues a SATA phy reset to the affected ATA link. * * Return value: * 0 on success / non-zero on failure **/ -static int ipr_sata_reset(struct ata_port *ap, unsigned int *classes, +static int ipr_sata_reset(struct ata_link *link, unsigned int *classes, unsigned long deadline) { - struct ipr_sata_port *sata_port = ap->private_data; + struct ipr_sata_port *sata_port = link->ap->private_data; struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg; struct ipr_resource_entry *res; unsigned long lock_flags = 0; @@ -4981,22 +4981,22 @@ static void ipr_ata_phy_reset(struct ata_port *ap) rc = ipr_device_reset(ioa_cfg, res); if (rc) { - ap->ops->port_disable(ap); + ata_port_disable(ap); goto out_unlock; } switch(res->cfgte.proto) { case IPR_PROTO_SATA: case IPR_PROTO_SAS_STP: - ap->device[0].class = ATA_DEV_ATA; + ap->link.device[0].class = ATA_DEV_ATA; break; case IPR_PROTO_SATA_ATAPI: case IPR_PROTO_SAS_STP_ATAPI: - ap->device[0].class = ATA_DEV_ATAPI; + ap->link.device[0].class = ATA_DEV_ATAPI; break; default: - ap->device[0].class = ATA_DEV_UNKNOWN; - ap->ops->port_disable(ap); + ap->link.device[0].class = ATA_DEV_UNKNOWN; + ata_port_disable(ap); break; }; @@ -5262,7 +5262,6 @@ static u8 ipr_ata_check_altstatus(struct ata_port *ap) } static struct ata_port_operations ipr_sata_ops = { - .port_disable = ata_port_disable, .check_status = ipr_ata_check_status, .check_altstatus = ipr_ata_check_altstatus, .dev_select = ata_noop_dev_select, diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index 492a51bd6aa8..2ed099e2c20d 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -204,8 +204,8 @@ module_param(ips, charp, 0); /* * DRIVER_VER */ -#define IPS_VERSION_HIGH "7.12" -#define IPS_VERSION_LOW ".05 " +#define IPS_VERSION_HIGH IPS_VER_MAJOR_STRING "." IPS_VER_MINOR_STRING +#define IPS_VERSION_LOW "." IPS_VER_BUILD_STRING " " #if !defined(__i386__) && !defined(__ia64__) && !defined(__x86_64__) #warning "This driver has only been tested on the x86/ia64/x86_64 platforms" @@ -656,6 +656,8 @@ ips_release(struct Scsi_Host *sh) METHOD_TRACE("ips_release", 1); + scsi_remove_host(sh); + for (i = 0; i < IPS_MAX_ADAPTERS && ips_sh[i] != sh; i++) ; if (i == IPS_MAX_ADAPTERS) { @@ -707,7 +709,6 @@ ips_release(struct Scsi_Host *sh) /* free IRQ */ free_irq(ha->irq, ha); - scsi_remove_host(sh); scsi_host_put(sh); ips_released_controllers++; @@ -6946,7 +6947,7 @@ module_exit(ips_module_exit); static int __devinit ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent) { - int index; + int uninitialized_var(index); int rc; METHOD_TRACE("ips_insert_device", 1); diff --git a/drivers/scsi/ips.h b/drivers/scsi/ips.h index 24123d537c58..3bcbd9ff056b 100644 --- a/drivers/scsi/ips.h +++ b/drivers/scsi/ips.h @@ -1172,12 +1172,13 @@ typedef struct { *************************************************************************/ #define IPS_VER_MAJOR 7 -#define IPS_VER_MAJOR_STRING "7" +#define IPS_VER_MAJOR_STRING __stringify(IPS_VER_MAJOR) #define IPS_VER_MINOR 12 -#define IPS_VER_MINOR_STRING "12" -#define IPS_VER_BUILD 02 -#define IPS_VER_BUILD_STRING "02" -#define IPS_VER_STRING "7.12.02" +#define IPS_VER_MINOR_STRING __stringify(IPS_VER_MINOR) +#define IPS_VER_BUILD 05 +#define IPS_VER_BUILD_STRING __stringify(IPS_VER_BUILD) +#define IPS_VER_STRING IPS_VER_MAJOR_STRING "." \ + IPS_VER_MINOR_STRING "." IPS_VER_BUILD_STRING #define IPS_RELEASE_ID 0x00020000 #define IPS_BUILD_IDENT 761 #define IPS_LEGALCOPYRIGHT_STRING "(C) Copyright IBM Corp. 1994, 2002. All Rights Reserved." diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 5e573efcf0a7..0829b55c64d2 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -249,17 +249,17 @@ static void sas_ata_phy_reset(struct ata_port *ap) switch (dev->sata_dev.command_set) { case ATA_COMMAND_SET: SAS_DPRINTK("%s: Found ATA device.\n", __FUNCTION__); - ap->device[0].class = ATA_DEV_ATA; + ap->link.device[0].class = ATA_DEV_ATA; break; case ATAPI_COMMAND_SET: SAS_DPRINTK("%s: Found ATAPI device.\n", __FUNCTION__); - ap->device[0].class = ATA_DEV_ATAPI; + ap->link.device[0].class = ATA_DEV_ATAPI; break; default: SAS_DPRINTK("%s: Unknown SATA command set: %d.\n", __FUNCTION__, dev->sata_dev.command_set); - ap->device[0].class = ATA_DEV_UNKNOWN; + ap->link.device[0].class = ATA_DEV_UNKNOWN; break; } @@ -317,7 +317,7 @@ static int sas_ata_scr_write(struct ata_port *ap, unsigned int sc_reg_in, dev->sata_dev.serror = val; break; case SCR_ACTIVE: - dev->sata_dev.ap->sactive = val; + dev->sata_dev.ap->link.sactive = val; break; default: return -EINVAL; @@ -342,7 +342,7 @@ static int sas_ata_scr_read(struct ata_port *ap, unsigned int sc_reg_in, *val = dev->sata_dev.serror; return 0; case SCR_ACTIVE: - *val = dev->sata_dev.ap->sactive; + *val = dev->sata_dev.ap->link.sactive; return 0; default: return -EINVAL; @@ -350,7 +350,6 @@ static int sas_ata_scr_read(struct ata_port *ap, unsigned int sc_reg_in, } static struct ata_port_operations sas_sata_ops = { - .port_disable = ata_port_disable, .check_status = sas_ata_check_status, .check_altstatus = sas_ata_check_status, .dev_select = ata_noop_dev_select, diff --git a/drivers/scsi/libsrp.c b/drivers/scsi/libsrp.c index 732446e63963..2ad0a27dbaab 100644 --- a/drivers/scsi/libsrp.c +++ b/drivers/scsi/libsrp.c @@ -392,7 +392,7 @@ static int vscsis_data_length(struct srp_cmd *cmd, enum dma_data_direction dir) } int srp_cmd_queue(struct Scsi_Host *shost, struct srp_cmd *cmd, void *info, - u64 addr) + u64 itn_id, u64 addr) { enum dma_data_direction dir; struct scsi_cmnd *sc; @@ -428,7 +428,8 @@ int srp_cmd_queue(struct Scsi_Host *shost, struct srp_cmd *cmd, void *info, sc->request_bufflen = len; sc->request_buffer = (void *) (unsigned long) addr; sc->tag = tag; - err = scsi_tgt_queue_command(sc, (struct scsi_lun *) &cmd->lun, cmd->tag); + err = scsi_tgt_queue_command(sc, itn_id, (struct scsi_lun *)&cmd->lun, + cmd->tag); if (err) scsi_host_put_command(shost, sc); diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 2e3c01bebed6..149fdd25f8e8 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -43,7 +43,6 @@ #include "lpfc_crtn.h" #include "lpfc_vport.h" #include "lpfc_version.h" -#include "lpfc_vport.h" #include "lpfc_debugfs.h" #ifdef CONFIG_LPFC_DEBUG_FS @@ -902,7 +901,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) } } - vport->disc_trc = kmalloc( + vport->disc_trc = kmzlloc( (sizeof(struct lpfc_debugfs_trc) * lpfc_debugfs_max_disc_trc), GFP_KERNEL); @@ -913,8 +912,6 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) goto debug_failed; } atomic_set(&vport->disc_trc_cnt, 0); - memset(vport->disc_trc, 0, - (sizeof(struct lpfc_debugfs_trc) * lpfc_debugfs_max_disc_trc)); snprintf(name, sizeof(name), "discovery_trace"); vport->debug_disc_trc = diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 414350ab584e..ecebdfa00470 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -43,7 +43,6 @@ #include "lpfc_crtn.h" #include "lpfc_vport.h" #include "lpfc_version.h" -#include "lpfc_vport.h" static int lpfc_parse_vpd(struct lpfc_hba *, uint8_t *, int); static void lpfc_get_hba_model_desc(struct lpfc_hba *, uint8_t *, uint8_t *); @@ -1266,11 +1265,10 @@ lpfc_hba_init(struct lpfc_hba *phba, uint32_t *hbainit) uint32_t *HashWorking; uint32_t *pwwnn = (uint32_t *) phba->wwnn; - HashWorking = kmalloc(80 * sizeof(uint32_t), GFP_KERNEL); + HashWorking = kcalloc(80, sizeof(uint32_t), GFP_KERNEL); if (!HashWorking) return; - memset(HashWorking, 0, (80 * sizeof(uint32_t))); HashWorking[0] = HashWorking[78] = *pwwnn++; HashWorking[1] = HashWorking[79] = *pwwnn; diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 17d7dc05149b..cd674938ccd5 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -202,10 +202,9 @@ lpfc_new_scsi_buf(struct lpfc_vport *vport) dma_addr_t pdma_phys; uint16_t iotag; - psb = kmalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL); + psb = kzalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL); if (!psb) return NULL; - memset(psb, 0, sizeof (struct lpfc_scsi_buf)); /* * Get memory from the pci pool to map the virt space to pci bus space diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index ce5ff2bccba6..e5337ad4121e 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -675,7 +675,7 @@ lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag) uint32_t hbqno; hbqno = tag >> 16; - if (hbqno > LPFC_MAX_HBQS) + if (hbqno >= LPFC_MAX_HBQS) return NULL; list_for_each_entry(d_buf, &phba->hbqs[hbqno].hbq_buffer_list, list) { diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index da56163c30a8..e7e11f282c8f 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -4416,8 +4416,7 @@ mega_internal_command(adapter_t *adapter, megacmd_t *mc, mega_passthru *pthru) scmd = &adapter->int_scmd; memset(scmd, 0, sizeof(Scsi_Cmnd)); - sdev = kmalloc(sizeof(struct scsi_device), GFP_KERNEL); - memset(sdev, 0, sizeof(struct scsi_device)); + sdev = kzalloc(sizeof(struct scsi_device), GFP_KERNEL); scmd->device = sdev; scmd->device->host = adapter->host; diff --git a/drivers/scsi/mvme16x_scsi.c b/drivers/scsi/mvme16x_scsi.c index 1bdddad48571..b264b499d982 100644 --- a/drivers/scsi/mvme16x_scsi.c +++ b/drivers/scsi/mvme16x_scsi.c @@ -48,13 +48,12 @@ mvme16x_probe(struct device *dev) goto out; } - hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL); + hostdata = kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL); if (hostdata == NULL) { printk(KERN_ERR "mvme16x-scsi: " "Failed to allocate host data\n"); goto out; } - memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters)); /* Fill in the required pieces of hostdata */ hostdata->base = (void __iomem *)0xfff47000UL; diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index 030ba49f33ff..016c462bc771 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -8143,12 +8143,7 @@ static int ncr53c8xx_abort(struct scsi_cmnd *cmd) unsigned long flags; struct scsi_cmnd *done_list; -#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS - printk("ncr53c8xx_abort: pid=%lu serial_number=%ld\n", - cmd->pid, cmd->serial_number); -#else - printk("ncr53c8xx_abort: command pid %lu\n", cmd->pid); -#endif + printk("ncr53c8xx_abort: command pid %lu\n", cmd->serial_number); NCR_LOCK_NCB(np, flags); @@ -8528,18 +8523,15 @@ struct Scsi_Host * __init ncr_attach(struct scsi_host_template *tpnt, } -int ncr53c8xx_release(struct Scsi_Host *host) +void ncr53c8xx_release(struct Scsi_Host *host) { - struct host_data *host_data; + struct host_data *host_data = shost_priv(host); #ifdef DEBUG_NCR53C8XX printk("ncr53c8xx: release\n"); #endif - if (!host) - return 1; - host_data = (struct host_data *)host->hostdata; - if (host_data && host_data->ncb) + if (host_data->ncb) ncr_detach(host_data->ncb); - return 1; + scsi_host_put(host); } static void ncr53c8xx_set_period(struct scsi_target *starget, int period) diff --git a/drivers/scsi/ncr53c8xx.h b/drivers/scsi/ncr53c8xx.h index b39357d9af8d..0e008dacf679 100644 --- a/drivers/scsi/ncr53c8xx.h +++ b/drivers/scsi/ncr53c8xx.h @@ -1321,7 +1321,7 @@ struct ncr_device { }; extern struct Scsi_Host *ncr_attach(struct scsi_host_template *tpnt, int unit, struct ncr_device *device); -extern int ncr53c8xx_release(struct Scsi_Host *host); +extern void ncr53c8xx_release(struct Scsi_Host *host); irqreturn_t ncr53c8xx_intr(int irq, void *dev_id); extern int ncr53c8xx_init(void); extern void ncr53c8xx_exit(void); diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index 08060fb478b6..331b789937c4 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -3298,7 +3298,7 @@ static ssize_t osst_write(struct file * filp, const char __user * buf, size_t co char * name = tape_name(STp); - if (down_interruptible(&STp->lock)) + if (mutex_lock_interruptible(&STp->lock)) return (-ERESTARTSYS); /* @@ -3600,7 +3600,7 @@ if (SRpnt) printk(KERN_ERR "%s:A: Not supposed to have SRpnt at line %d\n", name out: if (SRpnt != NULL) osst_release_request(SRpnt); - up(&STp->lock); + mutex_unlock(&STp->lock); return retval; } @@ -3619,7 +3619,7 @@ static ssize_t osst_read(struct file * filp, char __user * buf, size_t count, lo char * name = tape_name(STp); - if (down_interruptible(&STp->lock)) + if (mutex_lock_interruptible(&STp->lock)) return (-ERESTARTSYS); /* @@ -3785,7 +3785,7 @@ static ssize_t osst_read(struct file * filp, char __user * buf, size_t count, lo out: if (SRpnt != NULL) osst_release_request(SRpnt); - up(&STp->lock); + mutex_unlock(&STp->lock); return retval; } @@ -4852,7 +4852,7 @@ static int osst_ioctl(struct inode * inode,struct file * file, char * name = tape_name(STp); void __user * p = (void __user *)arg; - if (down_interruptible(&STp->lock)) + if (mutex_lock_interruptible(&STp->lock)) return -ERESTARTSYS; #if DEBUG @@ -5163,14 +5163,14 @@ static int osst_ioctl(struct inode * inode,struct file * file, } if (SRpnt) osst_release_request(SRpnt); - up(&STp->lock); + mutex_unlock(&STp->lock); return scsi_ioctl(STp->device, cmd_in, p); out: if (SRpnt) osst_release_request(SRpnt); - up(&STp->lock); + mutex_unlock(&STp->lock); return retval; } @@ -5778,13 +5778,12 @@ static int osst_probe(struct device *dev) dev_num = i; /* allocate a struct osst_tape for this device */ - tpnt = kmalloc(sizeof(struct osst_tape), GFP_ATOMIC); - if (tpnt == NULL) { + tpnt = kzalloc(sizeof(struct osst_tape), GFP_ATOMIC); + if (!tpnt) { write_unlock(&os_scsi_tapes_lock); printk(KERN_ERR "osst :E: Can't allocate device descriptor, device not attached.\n"); goto out_put_disk; } - memset(tpnt, 0, sizeof(struct osst_tape)); /* allocate a buffer for this device */ i = SDp->host->sg_tablesize; @@ -5866,7 +5865,7 @@ static int osst_probe(struct device *dev) tpnt->modes[2].defined = 1; tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = 0; - init_MUTEX(&tpnt->lock); + mutex_init(&tpnt->lock); osst_nr_dev++; write_unlock(&os_scsi_tapes_lock); diff --git a/drivers/scsi/osst.h b/drivers/scsi/osst.h index 2cc7b5a1606a..5aa22740b5df 100644 --- a/drivers/scsi/osst.h +++ b/drivers/scsi/osst.h @@ -4,6 +4,7 @@ #include <asm/byteorder.h> #include <linux/completion.h> +#include <linux/mutex.h> /* FIXME - rename and use the following two types or delete them! * and the types really should go to st.h anyway... @@ -532,7 +533,7 @@ struct osst_tape { struct scsi_driver *driver; unsigned capacity; struct scsi_device *device; - struct semaphore lock; /* for serialization */ + struct mutex lock; /* for serialization */ struct completion wait; /* for SCSI commands */ struct osst_buffer * buffer; diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index 445cfbbca9b3..a45d89b14147 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -25,8 +25,6 @@ ***********************************************************************/ -/* $Id: nsp_cs.c,v 1.23 2003/08/18 11:09:19 elca Exp $ */ - #include <linux/version.h> #include <linux/module.h> #include <linux/kernel.h> @@ -59,7 +57,7 @@ #include "nsp_cs.h" MODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>"); -MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module $Revision: 1.23 $"); +MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module"); MODULE_SUPPORTED_DEVICE("sd,sr,sg,st"); #ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); @@ -83,10 +81,6 @@ static struct scsi_host_template nsp_driver_template = { .proc_name = "nsp_cs", .proc_info = nsp_proc_info, .name = "WorkBit NinjaSCSI-3/32Bi(16bit)", -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) - .detect = nsp_detect_old, - .release = nsp_release_old, -#endif .info = nsp_info, .queuecommand = nsp_queuecommand, /* .eh_abort_handler = nsp_eh_abort,*/ @@ -97,9 +91,6 @@ static struct scsi_host_template nsp_driver_template = { .sg_tablesize = SG_ALL, .cmd_per_lun = 1, .use_clustering = DISABLE_CLUSTERING, -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,2)) - .use_new_eh_code = 1, -#endif }; static nsp_hw_data nsp_data_base; /* attach <-> detect glue */ @@ -1313,11 +1304,7 @@ static struct Scsi_Host *nsp_detect(struct scsi_host_template *sht) nsp_hw_data *data_b = &nsp_data_base, *data; nsp_dbg(NSP_DEBUG_INIT, "this_id=%d", sht->this_id); -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) host = scsi_host_alloc(&nsp_driver_template, sizeof(nsp_hw_data)); -#else - host = scsi_register(sht, sizeof(nsp_hw_data)); -#endif if (host == NULL) { nsp_dbg(NSP_DEBUG_INIT, "host failed"); return NULL; @@ -1354,37 +1341,6 @@ static struct Scsi_Host *nsp_detect(struct scsi_host_template *sht) return host; /* detect done. */ } -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) -static int nsp_detect_old(struct scsi_host_template *sht) -{ - if (nsp_detect(sht) == NULL) { - return 0; - } else { - //MOD_INC_USE_COUNT; - return 1; - } -} - - -static int nsp_release_old(struct Scsi_Host *shpnt) -{ - //nsp_hw_data *data = (nsp_hw_data *)shpnt->hostdata; - - /* PCMCIA Card Service dose same things below. */ - /* So we do nothing. */ - //if (shpnt->irq) { - // free_irq(shpnt->irq, data->ScsiInfo); - //} - //if (shpnt->io_port) { - // release_region(shpnt->io_port, shpnt->n_io_port); - //} - - //MOD_DEC_USE_COUNT; - - return 0; -} -#endif - /*----------------------------------------------------------------*/ /* return info string */ /*----------------------------------------------------------------*/ @@ -1403,19 +1359,9 @@ static const char *nsp_info(struct Scsi_Host *shpnt) nsp_dbg(NSP_DEBUG_PROC, "buffer=0x%p pos=0x%p length=%d %d\n", buffer, pos, length, length - (pos - buffer));\ } \ } while(0) -static int -nsp_proc_info( -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) - struct Scsi_Host *host, -#endif - char *buffer, - char **start, - off_t offset, - int length, -#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) - int hostno, -#endif - int inout) + +static int nsp_proc_info(struct Scsi_Host *host, char *buffer, char **start, + off_t offset, int length, int inout) { int id; char *pos = buffer; @@ -1423,24 +1369,13 @@ nsp_proc_info( int speed; unsigned long flags; nsp_hw_data *data; -#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) - struct Scsi_Host *host; -#else int hostno; -#endif + if (inout) { return -EINVAL; } -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) hostno = host->host_no; -#else - /* search this HBA host */ - host = scsi_host_hn_get(hostno); - if (host == NULL) { - return -ESRCH; - } -#endif data = (nsp_hw_data *)host->hostdata; @@ -1675,10 +1610,6 @@ static int nsp_cs_config(struct pcmcia_device *link) cistpl_cftable_entry_t dflt = { 0 }; struct Scsi_Host *host; nsp_hw_data *data = &nsp_data_base; -#if !(LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,74)) - struct scsi_device *dev; - dev_node_t **tail, *node; -#endif nsp_dbg(NSP_DEBUG_INIT, "in"); @@ -1811,17 +1742,7 @@ static int nsp_cs_config(struct pcmcia_device *link) goto cs_failed; } -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)) host = nsp_detect(&nsp_driver_template); -#else - scsi_register_host(&nsp_driver_template); - for (host = scsi_host_get_next(NULL); host != NULL; - host = scsi_host_get_next(host)) { - if (host->hostt == &nsp_driver_template) { - break; - } - } -#endif if (host == NULL) { nsp_dbg(NSP_DEBUG_INIT, "detect failed"); @@ -1829,7 +1750,6 @@ static int nsp_cs_config(struct pcmcia_device *link) } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,74)) ret = scsi_add_host (host, NULL); if (ret) goto cs_failed; @@ -1840,52 +1760,6 @@ static int nsp_cs_config(struct pcmcia_device *link) link->dev_node = &info->node; info->host = host; -#else - nsp_dbg(NSP_DEBUG_INIT, "GET_SCSI_INFO"); - tail = &link->dev_node; - info->ndev = 0; - - nsp_dbg(NSP_DEBUG_INIT, "host=0x%p", host); - - for (dev = host->host_queue; dev != NULL; dev = dev->next) { - unsigned long id; - id = (dev->id & 0x0f) + ((dev->lun & 0x0f) << 4) + - ((dev->channel & 0x0f) << 8) + - ((dev->host->host_no & 0x0f) << 12); - node = &info->node[info->ndev]; - node->minor = 0; - switch (dev->type) { - case TYPE_TAPE: - node->major = SCSI_TAPE_MAJOR; - snprintf(node->dev_name, sizeof(node->dev_name), "st#%04lx", id); - break; - case TYPE_DISK: - case TYPE_MOD: - node->major = SCSI_DISK0_MAJOR; - snprintf(node->dev_name, sizeof(node->dev_name), "sd#%04lx", id); - break; - case TYPE_ROM: - case TYPE_WORM: - node->major = SCSI_CDROM_MAJOR; - snprintf(node->dev_name, sizeof(node->dev_name), "sr#%04lx", id); - break; - default: - node->major = SCSI_GENERIC_MAJOR; - snprintf(node->dev_name, sizeof(node->dev_name), "sg#%04lx", id); - break; - } - *tail = node; tail = &node->next; - info->ndev++; - info->host = dev->host; - } - - *tail = NULL; - if (info->ndev == 0) { - nsp_msg(KERN_INFO, "no SCSI devices found"); - } - nsp_dbg(NSP_DEBUG_INIT, "host=0x%p", host); -#endif - /* Finally, report what we've done */ printk(KERN_INFO "nsp_cs: index 0x%02x: ", link->conf.ConfigIndex); @@ -1938,13 +1812,9 @@ static void nsp_cs_release(struct pcmcia_device *link) nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link); /* Unlink the device chain */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,2)) if (info->host != NULL) { scsi_remove_host(info->host); } -#else - scsi_unregister_host(&nsp_driver_template); -#endif link->dev_node = NULL; if (link->win) { @@ -1954,11 +1824,9 @@ static void nsp_cs_release(struct pcmcia_device *link) } pcmcia_disable_device(link); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,2)) if (info->host != NULL) { scsi_host_put(info->host); } -#endif } /* nsp_cs_release */ static int nsp_cs_suspend(struct pcmcia_device *link) @@ -2005,7 +1873,6 @@ static int nsp_cs_resume(struct pcmcia_device *link) /*======================================================================* * module entry point *====================================================================*/ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,68)) static struct pcmcia_device_id nsp_cs_ids[] = { PCMCIA_DEVICE_PROD_ID123("IO DATA", "CBSC16 ", "1", 0x547e66dc, 0x0d63a3fd, 0x51de003a), PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-001", "1", 0x534c02bc, 0x52008408, 0x51de003a), @@ -2029,28 +1896,12 @@ static struct pcmcia_driver nsp_driver = { .suspend = nsp_cs_suspend, .resume = nsp_cs_resume, }; -#endif static int __init nsp_cs_init(void) { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,68)) nsp_msg(KERN_INFO, "loading..."); return pcmcia_register_driver(&nsp_driver); -#else - servinfo_t serv; - - nsp_msg(KERN_INFO, "loading..."); - pcmcia_get_card_services_info(&serv); - if (serv.Revision != CS_RELEASE_CODE) { - nsp_msg(KERN_DEBUG, "Card Services release does not match!"); - return -EINVAL; - } - register_pcmcia_driver(&dev_info, &nsp_cs_attach, &nsp_cs_detach); - - nsp_dbg(NSP_DEBUG_INIT, "out"); - return 0; -#endif } static void __exit nsp_cs_exit(void) diff --git a/drivers/scsi/pcmcia/nsp_cs.h b/drivers/scsi/pcmcia/nsp_cs.h index 9102cbdf1359..b7f0fa246413 100644 --- a/drivers/scsi/pcmcia/nsp_cs.h +++ b/drivers/scsi/pcmcia/nsp_cs.h @@ -10,8 +10,6 @@ =========================================================*/ -/* $Id: nsp_cs.h,v 1.19 2003/08/18 11:09:19 elca Exp $ */ - #ifndef __nsp_cs__ #define __nsp_cs__ @@ -227,13 +225,7 @@ typedef struct scsi_info_t { struct pcmcia_device *p_dev; struct Scsi_Host *host; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,74)) dev_node_t node; -#else - int ndev; - dev_node_t node[8]; - struct bus_operations *bus; -#endif int stop; } scsi_info_t; diff --git a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c index d953d43fe2e6..0363c1cd68c1 100644 --- a/drivers/scsi/pluto.c +++ b/drivers/scsi/pluto.c @@ -111,13 +111,12 @@ int __init pluto_detect(struct scsi_host_template *tpnt) #endif return 0; } - fcs = kmalloc(sizeof (struct ctrl_inquiry) * fcscount, GFP_DMA); + fcs = kcalloc(fcscount, sizeof (struct ctrl_inquiry), GFP_DMA); if (!fcs) { printk ("PLUTO: Not enough memory to probe\n"); return 0; } - memset (fcs, 0, sizeof (struct ctrl_inquiry) * fcscount); memset (&dev, 0, sizeof(dev)); atomic_set (&fcss, fcscount); @@ -161,7 +160,6 @@ int __init pluto_detect(struct scsi_host_template *tpnt) SCpnt->request->cmd_flags &= ~REQ_STARTED; - SCpnt->done = pluto_detect_done; SCpnt->request_bufflen = 256; SCpnt->request_buffer = fcs[i].inquiry; PLD(("set up %d %08lx\n", i, (long)SCpnt)) @@ -196,7 +194,7 @@ int __init pluto_detect(struct scsi_host_template *tpnt) SCpnt = &(fcs[i].cmd); /* Let FC mid-level free allocated resources */ - SCpnt->done (SCpnt); + pluto_detect_scsi_done(SCpnt); if (!SCpnt->result) { struct pluto_inquiry *inq; @@ -211,7 +209,7 @@ int __init pluto_detect(struct scsi_host_template *tpnt) char *p; long *ages; - ages = kmalloc (((inq->channels + 1) * inq->targets) * sizeof(long), GFP_KERNEL); + ages = kcalloc((inq->channels + 1) * inq->targets, sizeof(long), GFP_KERNEL); if (!ages) continue; host = scsi_register (tpnt, sizeof (struct pluto)); @@ -238,7 +236,6 @@ int __init pluto_detect(struct scsi_host_template *tpnt) fc->channels = inq->channels + 1; fc->targets = inq->targets; fc->ages = ages; - memset (ages, 0, ((inq->channels + 1) * inq->targets) * sizeof(long)); pluto->fc = fc; memcpy (pluto->rev_str, inq->revision, 4); @@ -260,7 +257,7 @@ int __init pluto_detect(struct scsi_host_template *tpnt) } else fc->fcp_register(fc, TYPE_SCSI_FCP, 1); } - kfree((char *)fcs); + kfree(fcs); if (nplutos) printk ("PLUTO: Total of %d SparcSTORAGE Arrays found\n", nplutos); return nplutos; diff --git a/drivers/scsi/ps3rom.c b/drivers/scsi/ps3rom.c index b50f1e14f2a5..0f43d1d046d9 100644 --- a/drivers/scsi/ps3rom.c +++ b/drivers/scsi/ps3rom.c @@ -100,16 +100,16 @@ static int fill_from_dev_buffer(struct scsi_cmnd *cmd, const void *buf) struct scatterlist *sgpnt; unsigned int buflen; - buflen = cmd->request_bufflen; + buflen = scsi_bufflen(cmd); if (!buflen) return 0; - if (!cmd->request_buffer) + if (!scsi_sglist(cmd)) return -1; - sgpnt = cmd->request_buffer; active = 1; - for (k = 0, req_len = 0, act_len = 0; k < cmd->use_sg; ++k, ++sgpnt) { + req_len = act_len = 0; + scsi_for_each_sg(cmd, sgpnt, scsi_sg_count(cmd), k) { if (active) { kaddr = kmap_atomic(sgpnt->page, KM_IRQ0); len = sgpnt->length; @@ -124,7 +124,7 @@ static int fill_from_dev_buffer(struct scsi_cmnd *cmd, const void *buf) } req_len += sgpnt->length; } - cmd->resid = req_len - act_len; + scsi_set_resid(cmd, req_len - act_len); return 0; } @@ -138,15 +138,15 @@ static int fetch_to_dev_buffer(struct scsi_cmnd *cmd, void *buf) struct scatterlist *sgpnt; unsigned int buflen; - buflen = cmd->request_bufflen; + buflen = scsi_bufflen(cmd); if (!buflen) return 0; - if (!cmd->request_buffer) + if (!scsi_sglist(cmd)) return -1; - sgpnt = cmd->request_buffer; - for (k = 0, req_len = 0, fin = 0; k < cmd->use_sg; ++k, ++sgpnt) { + req_len = fin = 0; + scsi_for_each_sg(cmd, sgpnt, scsi_sg_count(cmd), k) { kaddr = kmap_atomic(sgpnt->page, KM_IRQ0); len = sgpnt->length; if ((req_len + len) > buflen) { @@ -177,12 +177,12 @@ static int ps3rom_atapi_request(struct ps3_storage_device *dev, memcpy(&atapi_cmnd.pkt, cmd->cmnd, 12); atapi_cmnd.pktlen = 12; atapi_cmnd.block_size = 1; /* transfer size is block_size * blocks */ - atapi_cmnd.blocks = atapi_cmnd.arglen = cmd->request_bufflen; + atapi_cmnd.blocks = atapi_cmnd.arglen = scsi_bufflen(cmd); atapi_cmnd.buffer = dev->bounce_lpar; switch (cmd->sc_data_direction) { case DMA_FROM_DEVICE: - if (cmd->request_bufflen >= CD_FRAMESIZE) + if (scsi_bufflen(cmd) >= CD_FRAMESIZE) atapi_cmnd.proto = DMA_PROTO; else atapi_cmnd.proto = PIO_DATA_IN_PROTO; @@ -190,7 +190,7 @@ static int ps3rom_atapi_request(struct ps3_storage_device *dev, break; case DMA_TO_DEVICE: - if (cmd->request_bufflen >= CD_FRAMESIZE) + if (scsi_bufflen(cmd) >= CD_FRAMESIZE) atapi_cmnd.proto = DMA_PROTO; else atapi_cmnd.proto = PIO_DATA_OUT_PROTO; diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 54d8bdf86852..fba8aa8a81b5 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -4086,7 +4086,7 @@ __qla1280_print_scsi_cmd(struct scsi_cmnd *cmd) } */ printk(" tag=%d, transfersize=0x%x \n", cmd->tag, cmd->transfersize); - printk(" Pid=%li, SP=0x%p\n", cmd->pid, CMD_SP(cmd)); + printk(" Pid=%li, SP=0x%p\n", cmd->serial_number, CMD_SP(cmd)); printk(" underflow size = 0x%x, direction=0x%x\n", cmd->underflow, cmd->sc_data_direction); } diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 0f2a9f5d801c..05fa7796a559 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -18,7 +18,7 @@ qla2x00_sysfs_read_fw_dump(struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { - struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, + struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj, struct device, kobj))); char *rbuf = (char *)ha->fw_dump; @@ -39,7 +39,7 @@ qla2x00_sysfs_write_fw_dump(struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { - struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, + struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj, struct device, kobj))); int reading; @@ -89,7 +89,7 @@ qla2x00_sysfs_read_nvram(struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { - struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, + struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj, struct device, kobj))); int size = ha->nvram_size; char *nvram_cache = ha->nvram; @@ -112,7 +112,7 @@ qla2x00_sysfs_write_nvram(struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { - struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, + struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj, struct device, kobj))); unsigned long flags; uint16_t cnt; @@ -146,7 +146,7 @@ qla2x00_sysfs_write_nvram(struct kobject *kobj, /* Write NVRAM. */ spin_lock_irqsave(&ha->hardware_lock, flags); ha->isp_ops->write_nvram(ha, (uint8_t *)buf, ha->nvram_base, count); - ha->isp_ops->read_nvram(ha, (uint8_t *)&ha->nvram, ha->nvram_base, + ha->isp_ops->read_nvram(ha, (uint8_t *)ha->nvram, ha->nvram_base, count); spin_unlock_irqrestore(&ha->hardware_lock, flags); @@ -170,15 +170,15 @@ qla2x00_sysfs_read_optrom(struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { - struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, + struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj, struct device, kobj))); if (ha->optrom_state != QLA_SREADING) return 0; - if (off > ha->optrom_size) + if (off > ha->optrom_region_size) return 0; - if (off + count > ha->optrom_size) - count = ha->optrom_size - off; + if (off + count > ha->optrom_region_size) + count = ha->optrom_region_size - off; memcpy(buf, &ha->optrom_buffer[off], count); @@ -190,15 +190,15 @@ qla2x00_sysfs_write_optrom(struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { - struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, + struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj, struct device, kobj))); if (ha->optrom_state != QLA_SWRITING) return -EINVAL; - if (off > ha->optrom_size) + if (off > ha->optrom_region_size) return -ERANGE; - if (off + count > ha->optrom_size) - count = ha->optrom_size - off; + if (off + count > ha->optrom_region_size) + count = ha->optrom_region_size - off; memcpy(&ha->optrom_buffer[off], buf, count); @@ -220,14 +220,18 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { - struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, + struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj, struct device, kobj))); - int val; + uint32_t start = 0; + uint32_t size = ha->optrom_size; + int val, valid; if (off) return 0; - if (sscanf(buf, "%d", &val) != 1) + if (sscanf(buf, "%d:%x:%x", &val, &start, &size) < 1) + return -EINVAL; + if (start > ha->optrom_size) return -EINVAL; switch (val) { @@ -237,6 +241,11 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj, break; ha->optrom_state = QLA_SWAITING; + + DEBUG2(qla_printk(KERN_INFO, ha, + "Freeing flash region allocation -- 0x%x bytes.\n", + ha->optrom_region_size)); + vfree(ha->optrom_buffer); ha->optrom_buffer = NULL; break; @@ -244,44 +253,107 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj, if (ha->optrom_state != QLA_SWAITING) break; + if (start & 0xfff) { + qla_printk(KERN_WARNING, ha, + "Invalid start region 0x%x/0x%x.\n", start, size); + return -EINVAL; + } + + ha->optrom_region_start = start; + ha->optrom_region_size = start + size > ha->optrom_size ? + ha->optrom_size - start : size; + ha->optrom_state = QLA_SREADING; - ha->optrom_buffer = (uint8_t *)vmalloc(ha->optrom_size); + ha->optrom_buffer = vmalloc(ha->optrom_region_size); if (ha->optrom_buffer == NULL) { qla_printk(KERN_WARNING, ha, "Unable to allocate memory for optrom retrieval " - "(%x).\n", ha->optrom_size); + "(%x).\n", ha->optrom_region_size); ha->optrom_state = QLA_SWAITING; return count; } - memset(ha->optrom_buffer, 0, ha->optrom_size); - ha->isp_ops->read_optrom(ha, ha->optrom_buffer, 0, - ha->optrom_size); + DEBUG2(qla_printk(KERN_INFO, ha, + "Reading flash region -- 0x%x/0x%x.\n", + ha->optrom_region_start, ha->optrom_region_size)); + + memset(ha->optrom_buffer, 0, ha->optrom_region_size); + ha->isp_ops->read_optrom(ha, ha->optrom_buffer, + ha->optrom_region_start, ha->optrom_region_size); break; case 2: if (ha->optrom_state != QLA_SWAITING) break; + /* + * We need to be more restrictive on which FLASH regions are + * allowed to be updated via user-space. Regions accessible + * via this method include: + * + * ISP21xx/ISP22xx/ISP23xx type boards: + * + * 0x000000 -> 0x020000 -- Boot code. + * + * ISP2322/ISP24xx type boards: + * + * 0x000000 -> 0x07ffff -- Boot code. + * 0x080000 -> 0x0fffff -- Firmware. + * + * ISP25xx type boards: + * + * 0x000000 -> 0x07ffff -- Boot code. + * 0x080000 -> 0x0fffff -- Firmware. + * 0x120000 -> 0x12ffff -- VPD and HBA parameters. + */ + valid = 0; + if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0) + valid = 1; + else if (start == (FA_BOOT_CODE_ADDR*4) || + start == (FA_RISC_CODE_ADDR*4)) + valid = 1; + else if (IS_QLA25XX(ha) && start == (FA_VPD_NVRAM_ADDR*4)) + valid = 1; + if (!valid) { + qla_printk(KERN_WARNING, ha, + "Invalid start region 0x%x/0x%x.\n", start, size); + return -EINVAL; + } + + ha->optrom_region_start = start; + ha->optrom_region_size = start + size > ha->optrom_size ? + ha->optrom_size - start : size; + ha->optrom_state = QLA_SWRITING; - ha->optrom_buffer = (uint8_t *)vmalloc(ha->optrom_size); + ha->optrom_buffer = vmalloc(ha->optrom_region_size); if (ha->optrom_buffer == NULL) { qla_printk(KERN_WARNING, ha, "Unable to allocate memory for optrom update " - "(%x).\n", ha->optrom_size); + "(%x).\n", ha->optrom_region_size); ha->optrom_state = QLA_SWAITING; return count; } - memset(ha->optrom_buffer, 0, ha->optrom_size); + + DEBUG2(qla_printk(KERN_INFO, ha, + "Staging flash region write -- 0x%x/0x%x.\n", + ha->optrom_region_start, ha->optrom_region_size)); + + memset(ha->optrom_buffer, 0, ha->optrom_region_size); break; case 3: if (ha->optrom_state != QLA_SWRITING) break; - ha->isp_ops->write_optrom(ha, ha->optrom_buffer, 0, - ha->optrom_size); + DEBUG2(qla_printk(KERN_INFO, ha, + "Writing flash region -- 0x%x/0x%x.\n", + ha->optrom_region_start, ha->optrom_region_size)); + + ha->isp_ops->write_optrom(ha, ha->optrom_buffer, + ha->optrom_region_start, ha->optrom_region_size); break; + default: + count = -EINVAL; } return count; } @@ -300,7 +372,7 @@ qla2x00_sysfs_read_vpd(struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { - struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, + struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj, struct device, kobj))); int size = ha->vpd_size; char *vpd_cache = ha->vpd; @@ -323,7 +395,7 @@ qla2x00_sysfs_write_vpd(struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { - struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, + struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj, struct device, kobj))); unsigned long flags; @@ -354,7 +426,7 @@ qla2x00_sysfs_read_sfp(struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { - struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, + struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj, struct device, kobj))); uint16_t iter, addr, offset; int rval; @@ -459,7 +531,7 @@ qla2x00_drvr_version_show(struct class_device *cdev, char *buf) static ssize_t qla2x00_fw_version_show(struct class_device *cdev, char *buf) { - scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev)); char fw_str[30]; return snprintf(buf, PAGE_SIZE, "%s\n", @@ -469,7 +541,7 @@ qla2x00_fw_version_show(struct class_device *cdev, char *buf) static ssize_t qla2x00_serial_num_show(struct class_device *cdev, char *buf) { - scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev)); uint32_t sn; sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | ha->serial1; @@ -480,14 +552,14 @@ qla2x00_serial_num_show(struct class_device *cdev, char *buf) static ssize_t qla2x00_isp_name_show(struct class_device *cdev, char *buf) { - scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev)); return snprintf(buf, PAGE_SIZE, "ISP%04X\n", ha->pdev->device); } static ssize_t qla2x00_isp_id_show(struct class_device *cdev, char *buf) { - scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev)); return snprintf(buf, PAGE_SIZE, "%04x %04x %04x %04x\n", ha->product_id[0], ha->product_id[1], ha->product_id[2], ha->product_id[3]); @@ -496,14 +568,14 @@ qla2x00_isp_id_show(struct class_device *cdev, char *buf) static ssize_t qla2x00_model_name_show(struct class_device *cdev, char *buf) { - scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev)); return snprintf(buf, PAGE_SIZE, "%s\n", ha->model_number); } static ssize_t qla2x00_model_desc_show(struct class_device *cdev, char *buf) { - scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev)); return snprintf(buf, PAGE_SIZE, "%s\n", ha->model_desc ? ha->model_desc: ""); } @@ -511,7 +583,7 @@ qla2x00_model_desc_show(struct class_device *cdev, char *buf) static ssize_t qla2x00_pci_info_show(struct class_device *cdev, char *buf) { - scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev)); char pci_info[30]; return snprintf(buf, PAGE_SIZE, "%s\n", @@ -521,7 +593,7 @@ qla2x00_pci_info_show(struct class_device *cdev, char *buf) static ssize_t qla2x00_state_show(struct class_device *cdev, char *buf) { - scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev)); int len = 0; if (atomic_read(&ha->loop_state) == LOOP_DOWN || @@ -559,7 +631,7 @@ qla2x00_state_show(struct class_device *cdev, char *buf) static ssize_t qla2x00_zio_show(struct class_device *cdev, char *buf) { - scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev)); int len = 0; switch (ha->zio_mode) { @@ -576,7 +648,7 @@ qla2x00_zio_show(struct class_device *cdev, char *buf) static ssize_t qla2x00_zio_store(struct class_device *cdev, const char *buf, size_t count) { - scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev)); int val = 0; uint16_t zio_mode; @@ -602,7 +674,7 @@ qla2x00_zio_store(struct class_device *cdev, const char *buf, size_t count) static ssize_t qla2x00_zio_timer_show(struct class_device *cdev, char *buf) { - scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev)); return snprintf(buf, PAGE_SIZE, "%d us\n", ha->zio_timer * 100); } @@ -611,7 +683,7 @@ static ssize_t qla2x00_zio_timer_store(struct class_device *cdev, const char *buf, size_t count) { - scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev)); int val = 0; uint16_t zio_timer; @@ -629,7 +701,7 @@ qla2x00_zio_timer_store(struct class_device *cdev, const char *buf, static ssize_t qla2x00_beacon_show(struct class_device *cdev, char *buf) { - scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev)); int len = 0; if (ha->beacon_blink_led) @@ -643,7 +715,7 @@ static ssize_t qla2x00_beacon_store(struct class_device *cdev, const char *buf, size_t count) { - scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev)); int val = 0; int rval; @@ -673,7 +745,7 @@ qla2x00_beacon_store(struct class_device *cdev, const char *buf, static ssize_t qla2x00_optrom_bios_version_show(struct class_device *cdev, char *buf) { - scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev)); return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->bios_revision[1], ha->bios_revision[0]); @@ -682,7 +754,7 @@ qla2x00_optrom_bios_version_show(struct class_device *cdev, char *buf) static ssize_t qla2x00_optrom_efi_version_show(struct class_device *cdev, char *buf) { - scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev)); return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->efi_revision[1], ha->efi_revision[0]); @@ -691,7 +763,7 @@ qla2x00_optrom_efi_version_show(struct class_device *cdev, char *buf) static ssize_t qla2x00_optrom_fcode_version_show(struct class_device *cdev, char *buf) { - scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev)); return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->fcode_revision[1], ha->fcode_revision[0]); @@ -700,7 +772,7 @@ qla2x00_optrom_fcode_version_show(struct class_device *cdev, char *buf) static ssize_t qla2x00_optrom_fw_version_show(struct class_device *cdev, char *buf) { - scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev)); return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d %d\n", ha->fw_revision[0], ha->fw_revision[1], ha->fw_revision[2], @@ -757,7 +829,7 @@ struct class_device_attribute *qla2x00_host_attrs[] = { static void qla2x00_get_host_port_id(struct Scsi_Host *shost) { - scsi_qla_host_t *ha = to_qla_host(shost); + scsi_qla_host_t *ha = shost_priv(shost); fc_host_port_id(shost) = ha->d_id.b.domain << 16 | ha->d_id.b.area << 8 | ha->d_id.b.al_pa; @@ -766,7 +838,7 @@ qla2x00_get_host_port_id(struct Scsi_Host *shost) static void qla2x00_get_host_speed(struct Scsi_Host *shost) { - scsi_qla_host_t *ha = to_qla_host(shost); + scsi_qla_host_t *ha = shost_priv(shost); uint32_t speed = 0; switch (ha->link_data_rate) { @@ -786,7 +858,7 @@ qla2x00_get_host_speed(struct Scsi_Host *shost) static void qla2x00_get_host_port_type(struct Scsi_Host *shost) { - scsi_qla_host_t *ha = to_qla_host(shost); + scsi_qla_host_t *ha = shost_priv(shost); uint32_t port_type = FC_PORTTYPE_UNKNOWN; switch (ha->current_topology) { @@ -810,7 +882,7 @@ static void qla2x00_get_starget_node_name(struct scsi_target *starget) { struct Scsi_Host *host = dev_to_shost(starget->dev.parent); - scsi_qla_host_t *ha = to_qla_host(host); + scsi_qla_host_t *ha = shost_priv(host); fc_port_t *fcport; u64 node_name = 0; @@ -828,7 +900,7 @@ static void qla2x00_get_starget_port_name(struct scsi_target *starget) { struct Scsi_Host *host = dev_to_shost(starget->dev.parent); - scsi_qla_host_t *ha = to_qla_host(host); + scsi_qla_host_t *ha = shost_priv(host); fc_port_t *fcport; u64 port_name = 0; @@ -846,7 +918,7 @@ static void qla2x00_get_starget_port_id(struct scsi_target *starget) { struct Scsi_Host *host = dev_to_shost(starget->dev.parent); - scsi_qla_host_t *ha = to_qla_host(host); + scsi_qla_host_t *ha = shost_priv(host); fc_port_t *fcport; uint32_t port_id = ~0U; @@ -865,7 +937,7 @@ static void qla2x00_get_rport_loss_tmo(struct fc_rport *rport) { struct Scsi_Host *host = rport_to_shost(rport); - scsi_qla_host_t *ha = to_qla_host(host); + scsi_qla_host_t *ha = shost_priv(host); rport->dev_loss_tmo = ha->port_down_retry_count + 5; } @@ -874,7 +946,7 @@ static void qla2x00_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout) { struct Scsi_Host *host = rport_to_shost(rport); - scsi_qla_host_t *ha = to_qla_host(host); + scsi_qla_host_t *ha = shost_priv(host); if (timeout) ha->port_down_retry_count = timeout; @@ -887,7 +959,7 @@ qla2x00_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout) static int qla2x00_issue_lip(struct Scsi_Host *shost) { - scsi_qla_host_t *ha = to_qla_host(shost); + scsi_qla_host_t *ha = shost_priv(shost); set_bit(LOOP_RESET_NEEDED, &ha->dpc_flags); return 0; @@ -896,7 +968,7 @@ qla2x00_issue_lip(struct Scsi_Host *shost) static struct fc_host_statistics * qla2x00_get_fc_host_stats(struct Scsi_Host *shost) { - scsi_qla_host_t *ha = to_qla_host(shost); + scsi_qla_host_t *ha = shost_priv(shost); int rval; uint16_t mb_stat[1]; link_stat_t stat_buf; @@ -934,7 +1006,7 @@ done: static void qla2x00_get_host_symbolic_name(struct Scsi_Host *shost) { - scsi_qla_host_t *ha = to_qla_host(shost); + scsi_qla_host_t *ha = shost_priv(shost); qla2x00_get_sym_node_name(ha, fc_host_symbolic_name(shost)); } @@ -942,7 +1014,7 @@ qla2x00_get_host_symbolic_name(struct Scsi_Host *shost) static void qla2x00_set_host_system_hostname(struct Scsi_Host *shost) { - scsi_qla_host_t *ha = to_qla_host(shost); + scsi_qla_host_t *ha = shost_priv(shost); set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags); } @@ -950,7 +1022,7 @@ qla2x00_set_host_system_hostname(struct Scsi_Host *shost) static void qla2x00_get_host_fabric_name(struct Scsi_Host *shost) { - scsi_qla_host_t *ha = to_qla_host(shost); + scsi_qla_host_t *ha = shost_priv(shost); u64 node_name; if (ha->device_flags & SWITCH_FOUND) @@ -964,7 +1036,7 @@ qla2x00_get_host_fabric_name(struct Scsi_Host *shost) static void qla2x00_get_host_port_state(struct Scsi_Host *shost) { - scsi_qla_host_t *ha = to_qla_host(shost); + scsi_qla_host_t *ha = shost_priv(shost); if (!ha->flags.online) fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE; @@ -978,7 +1050,7 @@ static int qla24xx_vport_create(struct fc_vport *fc_vport, bool disable) { int ret = 0; - scsi_qla_host_t *ha = (scsi_qla_host_t *) fc_vport->shost->hostdata; + scsi_qla_host_t *ha = shost_priv(fc_vport->shost); scsi_qla_host_t *vha; ret = qla24xx_vport_create_req_sanity_check(fc_vport); @@ -1047,7 +1119,7 @@ vport_create_failed_2: int qla24xx_vport_delete(struct fc_vport *fc_vport) { - scsi_qla_host_t *ha = (scsi_qla_host_t *) fc_vport->shost->hostdata; + scsi_qla_host_t *ha = shost_priv(fc_vport->shost); scsi_qla_host_t *vha = fc_vport->dd_data; qla24xx_disable_vp(vha); @@ -1178,6 +1250,6 @@ qla2x00_init_host_attr(scsi_qla_host_t *ha) fc_host_node_name(ha->host) = wwn_to_u64(ha->node_name); fc_host_port_name(ha->host) = wwn_to_u64(ha->port_name); fc_host_supported_classes(ha->host) = FC_COS_CLASS3; - fc_host_max_npiv_vports(ha->host) = MAX_NUM_VPORT_FABRIC; + fc_host_max_npiv_vports(ha->host) = ha->max_npiv_vports;; fc_host_npiv_vports_inuse(ha->host) = ha->cur_vport_count; } diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index c6680348b648..eaa04dabcdf6 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -38,7 +38,7 @@ qla2xxx_copy_queues(scsi_qla_host_t *ha, void *ptr) } static int -qla2xxx_dump_memory(scsi_qla_host_t *ha, uint32_t *code_ram, +qla24xx_dump_memory(scsi_qla_host_t *ha, uint32_t *code_ram, uint32_t cram_size, uint32_t *ext_mem, void **nxt) { int rval; @@ -152,6 +152,103 @@ qla2xxx_dump_memory(scsi_qla_host_t *ha, uint32_t *code_ram, return rval; } +static uint32_t * +qla24xx_read_window(struct device_reg_24xx __iomem *reg, uint32_t iobase, + uint32_t count, uint32_t *buf) +{ + uint32_t __iomem *dmp_reg; + + WRT_REG_DWORD(®->iobase_addr, iobase); + dmp_reg = ®->iobase_window; + while (count--) + *buf++ = htonl(RD_REG_DWORD(dmp_reg++)); + + return buf; +} + +static inline int +qla24xx_pause_risc(struct device_reg_24xx __iomem *reg) +{ + int rval = QLA_SUCCESS; + uint32_t cnt; + + if (RD_REG_DWORD(®->hccr) & HCCRX_RISC_PAUSE) + return rval; + + WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_PAUSE); + for (cnt = 30000; (RD_REG_DWORD(®->hccr) & HCCRX_RISC_PAUSE) == 0 && + rval == QLA_SUCCESS; cnt--) { + if (cnt) + udelay(100); + else + rval = QLA_FUNCTION_TIMEOUT; + } + + return rval; +} + +static int +qla24xx_soft_reset(scsi_qla_host_t *ha) +{ + int rval = QLA_SUCCESS; + uint32_t cnt; + uint16_t mb0, wd; + struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; + + /* Reset RISC. */ + WRT_REG_DWORD(®->ctrl_status, CSRX_DMA_SHUTDOWN|MWB_4096_BYTES); + for (cnt = 0; cnt < 30000; cnt++) { + if ((RD_REG_DWORD(®->ctrl_status) & CSRX_DMA_ACTIVE) == 0) + break; + + udelay(10); + } + + WRT_REG_DWORD(®->ctrl_status, + CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES); + pci_read_config_word(ha->pdev, PCI_COMMAND, &wd); + + udelay(100); + /* Wait for firmware to complete NVRAM accesses. */ + mb0 = (uint32_t) RD_REG_WORD(®->mailbox0); + for (cnt = 10000 ; cnt && mb0; cnt--) { + udelay(5); + mb0 = (uint32_t) RD_REG_WORD(®->mailbox0); + barrier(); + } + + /* Wait for soft-reset to complete. */ + for (cnt = 0; cnt < 30000; cnt++) { + if ((RD_REG_DWORD(®->ctrl_status) & + CSRX_ISP_SOFT_RESET) == 0) + break; + + udelay(10); + } + WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_RESET); + RD_REG_DWORD(®->hccr); /* PCI Posting. */ + + for (cnt = 30000; RD_REG_WORD(®->mailbox0) != 0 && + rval == QLA_SUCCESS; cnt--) { + if (cnt) + udelay(100); + else + rval = QLA_FUNCTION_TIMEOUT; + } + + return rval; +} + +static inline void +qla2xxx_read_window(struct device_reg_2xxx __iomem *reg, uint32_t count, + uint16_t *buf) +{ + uint16_t __iomem *dmp_reg = ®->u.isp2300.fb_cmd; + + while (count--) + *buf++ = htons(RD_REG_WORD(dmp_reg++)); +} + /** * qla2300_fw_dump() - Dumps binary data from the 2300 firmware. * @ha: HA context @@ -214,88 +311,61 @@ qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked) } if (rval == QLA_SUCCESS) { - dmp_reg = (uint16_t __iomem *)(reg + 0); + dmp_reg = ®->flash_address; for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++) fw->pbiu_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x10); + dmp_reg = ®->u.isp2300.req_q_in; for (cnt = 0; cnt < sizeof(fw->risc_host_reg) / 2; cnt++) fw->risc_host_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x40); + dmp_reg = ®->u.isp2300.mailbox0; for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++) fw->mailbox_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x40); - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); - for (cnt = 0; cnt < sizeof(fw->resp_dma_reg) / 2; cnt++) - fw->resp_dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); + qla2xxx_read_window(reg, 32, fw->resp_dma_reg); WRT_REG_WORD(®->ctrl_status, 0x50); - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); - for (cnt = 0; cnt < sizeof(fw->dma_reg) / 2; cnt++) - fw->dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); + qla2xxx_read_window(reg, 48, fw->dma_reg); WRT_REG_WORD(®->ctrl_status, 0x00); - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0xA0); + dmp_reg = ®->risc_hw; for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++) fw->risc_hdw_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2000); - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); - for (cnt = 0; cnt < sizeof(fw->risc_gp0_reg) / 2; cnt++) - fw->risc_gp0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); + qla2xxx_read_window(reg, 16, fw->risc_gp0_reg); WRT_REG_WORD(®->pcr, 0x2200); - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); - for (cnt = 0; cnt < sizeof(fw->risc_gp1_reg) / 2; cnt++) - fw->risc_gp1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); + qla2xxx_read_window(reg, 16, fw->risc_gp1_reg); WRT_REG_WORD(®->pcr, 0x2400); - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); - for (cnt = 0; cnt < sizeof(fw->risc_gp2_reg) / 2; cnt++) - fw->risc_gp2_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); + qla2xxx_read_window(reg, 16, fw->risc_gp2_reg); WRT_REG_WORD(®->pcr, 0x2600); - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); - for (cnt = 0; cnt < sizeof(fw->risc_gp3_reg) / 2; cnt++) - fw->risc_gp3_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); + qla2xxx_read_window(reg, 16, fw->risc_gp3_reg); WRT_REG_WORD(®->pcr, 0x2800); - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); - for (cnt = 0; cnt < sizeof(fw->risc_gp4_reg) / 2; cnt++) - fw->risc_gp4_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); + qla2xxx_read_window(reg, 16, fw->risc_gp4_reg); WRT_REG_WORD(®->pcr, 0x2A00); - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); - for (cnt = 0; cnt < sizeof(fw->risc_gp5_reg) / 2; cnt++) - fw->risc_gp5_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); + qla2xxx_read_window(reg, 16, fw->risc_gp5_reg); WRT_REG_WORD(®->pcr, 0x2C00); - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); - for (cnt = 0; cnt < sizeof(fw->risc_gp6_reg) / 2; cnt++) - fw->risc_gp6_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); + qla2xxx_read_window(reg, 16, fw->risc_gp6_reg); WRT_REG_WORD(®->pcr, 0x2E00); - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); - for (cnt = 0; cnt < sizeof(fw->risc_gp7_reg) / 2; cnt++) - fw->risc_gp7_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); + qla2xxx_read_window(reg, 16, fw->risc_gp7_reg); WRT_REG_WORD(®->ctrl_status, 0x10); - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); - for (cnt = 0; cnt < sizeof(fw->frame_buf_hdw_reg) / 2; cnt++) - fw->frame_buf_hdw_reg[cnt] = - htons(RD_REG_WORD(dmp_reg++)); + qla2xxx_read_window(reg, 64, fw->frame_buf_hdw_reg); WRT_REG_WORD(®->ctrl_status, 0x20); - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); - for (cnt = 0; cnt < sizeof(fw->fpm_b0_reg) / 2; cnt++) - fw->fpm_b0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); + qla2xxx_read_window(reg, 64, fw->fpm_b0_reg); WRT_REG_WORD(®->ctrl_status, 0x30); - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); - for (cnt = 0; cnt < sizeof(fw->fpm_b1_reg) / 2; cnt++) - fw->fpm_b1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); + qla2xxx_read_window(reg, 64, fw->fpm_b1_reg); /* Reset RISC. */ WRT_REG_WORD(®->ctrl_status, CSR_ISP_SOFT_RESET); @@ -567,83 +637,59 @@ qla2100_fw_dump(scsi_qla_host_t *ha, int hardware_locked) rval = QLA_FUNCTION_TIMEOUT; } if (rval == QLA_SUCCESS) { - dmp_reg = (uint16_t __iomem *)(reg + 0); + dmp_reg = ®->flash_address; for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++) fw->pbiu_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x10); + dmp_reg = ®->u.isp2100.mailbox0; for (cnt = 0; cnt < ha->mbx_count; cnt++) { - if (cnt == 8) { - dmp_reg = (uint16_t __iomem *) - ((uint8_t __iomem *)reg + 0xe0); - } + if (cnt == 8) + dmp_reg = ®->u_end.isp2200.mailbox8; + fw->mailbox_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); } - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x20); + dmp_reg = ®->u.isp2100.unused_2[0]; for (cnt = 0; cnt < sizeof(fw->dma_reg) / 2; cnt++) fw->dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x00); - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0xA0); + dmp_reg = ®->risc_hw; for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++) fw->risc_hdw_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2000); - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); - for (cnt = 0; cnt < sizeof(fw->risc_gp0_reg) / 2; cnt++) - fw->risc_gp0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); + qla2xxx_read_window(reg, 16, fw->risc_gp0_reg); WRT_REG_WORD(®->pcr, 0x2100); - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); - for (cnt = 0; cnt < sizeof(fw->risc_gp1_reg) / 2; cnt++) - fw->risc_gp1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); + qla2xxx_read_window(reg, 16, fw->risc_gp1_reg); WRT_REG_WORD(®->pcr, 0x2200); - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); - for (cnt = 0; cnt < sizeof(fw->risc_gp2_reg) / 2; cnt++) - fw->risc_gp2_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); + qla2xxx_read_window(reg, 16, fw->risc_gp2_reg); WRT_REG_WORD(®->pcr, 0x2300); - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); - for (cnt = 0; cnt < sizeof(fw->risc_gp3_reg) / 2; cnt++) - fw->risc_gp3_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); + qla2xxx_read_window(reg, 16, fw->risc_gp3_reg); WRT_REG_WORD(®->pcr, 0x2400); - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); - for (cnt = 0; cnt < sizeof(fw->risc_gp4_reg) / 2; cnt++) - fw->risc_gp4_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); + qla2xxx_read_window(reg, 16, fw->risc_gp4_reg); WRT_REG_WORD(®->pcr, 0x2500); - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); - for (cnt = 0; cnt < sizeof(fw->risc_gp5_reg) / 2; cnt++) - fw->risc_gp5_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); + qla2xxx_read_window(reg, 16, fw->risc_gp5_reg); WRT_REG_WORD(®->pcr, 0x2600); - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); - for (cnt = 0; cnt < sizeof(fw->risc_gp6_reg) / 2; cnt++) - fw->risc_gp6_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); + qla2xxx_read_window(reg, 16, fw->risc_gp6_reg); WRT_REG_WORD(®->pcr, 0x2700); - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); - for (cnt = 0; cnt < sizeof(fw->risc_gp7_reg) / 2; cnt++) - fw->risc_gp7_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); + qla2xxx_read_window(reg, 16, fw->risc_gp7_reg); WRT_REG_WORD(®->ctrl_status, 0x10); - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); - for (cnt = 0; cnt < sizeof(fw->frame_buf_hdw_reg) / 2; cnt++) - fw->frame_buf_hdw_reg[cnt] = - htons(RD_REG_WORD(dmp_reg++)); + qla2xxx_read_window(reg, 16, fw->frame_buf_hdw_reg); WRT_REG_WORD(®->ctrl_status, 0x20); - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); - for (cnt = 0; cnt < sizeof(fw->fpm_b0_reg) / 2; cnt++) - fw->fpm_b0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); + qla2xxx_read_window(reg, 64, fw->fpm_b0_reg); WRT_REG_WORD(®->ctrl_status, 0x30); - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); - for (cnt = 0; cnt < sizeof(fw->fpm_b1_reg) / 2; cnt++) - fw->fpm_b1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); + qla2xxx_read_window(reg, 64, fw->fpm_b1_reg); /* Reset the ISP. */ WRT_REG_WORD(®->ctrl_status, CSR_ISP_SOFT_RESET); @@ -750,7 +796,6 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked) int rval; uint32_t cnt; uint32_t risc_address; - uint16_t mb0, wd; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; uint32_t __iomem *dmp_reg; @@ -782,547 +827,198 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked) fw = &ha->fw_dump->isp.isp24; qla2xxx_prep_dump(ha, ha->fw_dump); - rval = QLA_SUCCESS; fw->host_status = htonl(RD_REG_DWORD(®->host_status)); /* Pause RISC. */ - if ((RD_REG_DWORD(®->hccr) & HCCRX_RISC_PAUSE) == 0) { - WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_RESET | - HCCRX_CLR_HOST_INT); - RD_REG_DWORD(®->hccr); /* PCI Posting. */ - WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_PAUSE); - for (cnt = 30000; - (RD_REG_DWORD(®->hccr) & HCCRX_RISC_PAUSE) == 0 && - rval == QLA_SUCCESS; cnt--) { - if (cnt) - udelay(100); - else - rval = QLA_FUNCTION_TIMEOUT; - } - } - - if (rval == QLA_SUCCESS) { - /* Host interface registers. */ - dmp_reg = (uint32_t __iomem *)(reg + 0); - for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++) - fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); - - /* Disable interrupts. */ - WRT_REG_DWORD(®->ictrl, 0); - RD_REG_DWORD(®->ictrl); - - /* Shadow registers. */ - WRT_REG_DWORD(®->iobase_addr, 0x0F70); - RD_REG_DWORD(®->iobase_addr); - WRT_REG_DWORD(®->iobase_select, 0xB0000000); - fw->shadow_reg[0] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0100000); - fw->shadow_reg[1] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0200000); - fw->shadow_reg[2] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0300000); - fw->shadow_reg[3] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0400000); - fw->shadow_reg[4] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0500000); - fw->shadow_reg[5] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0600000); - fw->shadow_reg[6] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - /* Mailbox registers. */ - mbx_reg = ®->mailbox0; - for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++) - fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++)); - - /* Transfer sequence registers. */ - iter_reg = fw->xseq_gp_reg; - WRT_REG_DWORD(®->iobase_addr, 0xBF00); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xBF10); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xBF20); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xBF30); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xBF40); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xBF50); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xBF60); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xBF70); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xBFE0); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < sizeof(fw->xseq_0_reg) / 4; cnt++) - fw->xseq_0_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xBFF0); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < sizeof(fw->xseq_1_reg) / 4; cnt++) - fw->xseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); - - /* Receive sequence registers. */ - iter_reg = fw->rseq_gp_reg; - WRT_REG_DWORD(®->iobase_addr, 0xFF00); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xFF10); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xFF20); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xFF30); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xFF40); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xFF50); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xFF60); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xFF70); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xFFD0); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < sizeof(fw->rseq_0_reg) / 4; cnt++) - fw->rseq_0_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xFFE0); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < sizeof(fw->rseq_1_reg) / 4; cnt++) - fw->rseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xFFF0); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < sizeof(fw->rseq_2_reg) / 4; cnt++) - fw->rseq_2_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); - - /* Command DMA registers. */ - WRT_REG_DWORD(®->iobase_addr, 0x7100); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < sizeof(fw->cmd_dma_reg) / 4; cnt++) - fw->cmd_dma_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); - - /* Queues. */ - iter_reg = fw->req0_dma_reg; - WRT_REG_DWORD(®->iobase_addr, 0x7200); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 8; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - dmp_reg = ®->iobase_q; - for (cnt = 0; cnt < 7; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - iter_reg = fw->resp0_dma_reg; - WRT_REG_DWORD(®->iobase_addr, 0x7300); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 8; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - dmp_reg = ®->iobase_q; - for (cnt = 0; cnt < 7; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - iter_reg = fw->req1_dma_reg; - WRT_REG_DWORD(®->iobase_addr, 0x7400); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 8; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - dmp_reg = ®->iobase_q; - for (cnt = 0; cnt < 7; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - /* Transmit DMA registers. */ - iter_reg = fw->xmt0_dma_reg; - WRT_REG_DWORD(®->iobase_addr, 0x7600); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x7610); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - iter_reg = fw->xmt1_dma_reg; - WRT_REG_DWORD(®->iobase_addr, 0x7620); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x7630); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - iter_reg = fw->xmt2_dma_reg; - WRT_REG_DWORD(®->iobase_addr, 0x7640); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x7650); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - iter_reg = fw->xmt3_dma_reg; - WRT_REG_DWORD(®->iobase_addr, 0x7660); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x7670); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - iter_reg = fw->xmt4_dma_reg; - WRT_REG_DWORD(®->iobase_addr, 0x7680); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x7690); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x76A0); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < sizeof(fw->xmt_data_dma_reg) / 4; cnt++) - fw->xmt_data_dma_reg[cnt] = - htonl(RD_REG_DWORD(dmp_reg++)); - - /* Receive DMA registers. */ - iter_reg = fw->rcvt0_data_dma_reg; - WRT_REG_DWORD(®->iobase_addr, 0x7700); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x7710); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - iter_reg = fw->rcvt1_data_dma_reg; - WRT_REG_DWORD(®->iobase_addr, 0x7720); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x7730); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - /* RISC registers. */ - iter_reg = fw->risc_gp_reg; - WRT_REG_DWORD(®->iobase_addr, 0x0F00); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x0F10); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x0F20); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x0F30); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x0F40); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x0F50); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x0F60); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x0F70); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - /* Local memory controller registers. */ - iter_reg = fw->lmc_reg; - WRT_REG_DWORD(®->iobase_addr, 0x3000); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x3010); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x3020); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x3030); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x3040); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x3050); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x3060); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - /* Fibre Protocol Module registers. */ - iter_reg = fw->fpm_hdw_reg; - WRT_REG_DWORD(®->iobase_addr, 0x4000); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x4010); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x4020); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x4030); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x4040); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x4050); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x4060); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x4070); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x4080); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x4090); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x40A0); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x40B0); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - /* Frame Buffer registers. */ - iter_reg = fw->fb_hdw_reg; - WRT_REG_DWORD(®->iobase_addr, 0x6000); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x6010); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x6020); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x6030); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x6040); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x6100); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x6130); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x6150); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x6170); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x6190); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x61B0); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - /* Reset RISC. */ - WRT_REG_DWORD(®->ctrl_status, - CSRX_DMA_SHUTDOWN|MWB_4096_BYTES); - for (cnt = 0; cnt < 30000; cnt++) { - if ((RD_REG_DWORD(®->ctrl_status) & - CSRX_DMA_ACTIVE) == 0) - break; - - udelay(10); - } - - WRT_REG_DWORD(®->ctrl_status, - CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES); - pci_read_config_word(ha->pdev, PCI_COMMAND, &wd); - - udelay(100); - /* Wait for firmware to complete NVRAM accesses. */ - mb0 = (uint32_t) RD_REG_WORD(®->mailbox0); - for (cnt = 10000 ; cnt && mb0; cnt--) { - udelay(5); - mb0 = (uint32_t) RD_REG_WORD(®->mailbox0); - barrier(); - } - - /* Wait for soft-reset to complete. */ - for (cnt = 0; cnt < 30000; cnt++) { - if ((RD_REG_DWORD(®->ctrl_status) & - CSRX_ISP_SOFT_RESET) == 0) - break; - - udelay(10); - } - WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_RESET); - RD_REG_DWORD(®->hccr); /* PCI Posting. */ - } - - for (cnt = 30000; RD_REG_WORD(®->mailbox0) != 0 && - rval == QLA_SUCCESS; cnt--) { - if (cnt) - udelay(100); - else - rval = QLA_FUNCTION_TIMEOUT; - } - - if (rval == QLA_SUCCESS) - rval = qla2xxx_dump_memory(ha, fw->code_ram, - sizeof(fw->code_ram), fw->ext_mem, &nxt); - - if (rval == QLA_SUCCESS) { - nxt = qla2xxx_copy_queues(ha, nxt); - if (ha->eft) - memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size)); - } - + rval = qla24xx_pause_risc(reg); + if (rval != QLA_SUCCESS) + goto qla24xx_fw_dump_failed_0; + + /* Host interface registers. */ + dmp_reg = ®->flash_addr; + for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++) + fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); + + /* Disable interrupts. */ + WRT_REG_DWORD(®->ictrl, 0); + RD_REG_DWORD(®->ictrl); + + /* Shadow registers. */ + WRT_REG_DWORD(®->iobase_addr, 0x0F70); + RD_REG_DWORD(®->iobase_addr); + WRT_REG_DWORD(®->iobase_select, 0xB0000000); + fw->shadow_reg[0] = htonl(RD_REG_DWORD(®->iobase_sdata)); + + WRT_REG_DWORD(®->iobase_select, 0xB0100000); + fw->shadow_reg[1] = htonl(RD_REG_DWORD(®->iobase_sdata)); + + WRT_REG_DWORD(®->iobase_select, 0xB0200000); + fw->shadow_reg[2] = htonl(RD_REG_DWORD(®->iobase_sdata)); + + WRT_REG_DWORD(®->iobase_select, 0xB0300000); + fw->shadow_reg[3] = htonl(RD_REG_DWORD(®->iobase_sdata)); + + WRT_REG_DWORD(®->iobase_select, 0xB0400000); + fw->shadow_reg[4] = htonl(RD_REG_DWORD(®->iobase_sdata)); + + WRT_REG_DWORD(®->iobase_select, 0xB0500000); + fw->shadow_reg[5] = htonl(RD_REG_DWORD(®->iobase_sdata)); + + WRT_REG_DWORD(®->iobase_select, 0xB0600000); + fw->shadow_reg[6] = htonl(RD_REG_DWORD(®->iobase_sdata)); + + /* Mailbox registers. */ + mbx_reg = ®->mailbox0; + for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++) + fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++)); + + /* Transfer sequence registers. */ + iter_reg = fw->xseq_gp_reg; + iter_reg = qla24xx_read_window(reg, 0xBF00, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xBF10, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xBF20, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xBF30, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xBF40, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xBF50, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xBF60, 16, iter_reg); + qla24xx_read_window(reg, 0xBF70, 16, iter_reg); + + qla24xx_read_window(reg, 0xBFE0, 16, fw->xseq_0_reg); + qla24xx_read_window(reg, 0xBFF0, 16, fw->xseq_1_reg); + + /* Receive sequence registers. */ + iter_reg = fw->rseq_gp_reg; + iter_reg = qla24xx_read_window(reg, 0xFF00, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xFF10, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xFF20, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xFF30, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xFF40, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xFF50, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xFF60, 16, iter_reg); + qla24xx_read_window(reg, 0xFF70, 16, iter_reg); + + qla24xx_read_window(reg, 0xFFD0, 16, fw->rseq_0_reg); + qla24xx_read_window(reg, 0xFFE0, 16, fw->rseq_1_reg); + qla24xx_read_window(reg, 0xFFF0, 16, fw->rseq_2_reg); + + /* Command DMA registers. */ + qla24xx_read_window(reg, 0x7100, 16, fw->cmd_dma_reg); + + /* Queues. */ + iter_reg = fw->req0_dma_reg; + iter_reg = qla24xx_read_window(reg, 0x7200, 8, iter_reg); + dmp_reg = ®->iobase_q; + for (cnt = 0; cnt < 7; cnt++) + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); + + iter_reg = fw->resp0_dma_reg; + iter_reg = qla24xx_read_window(reg, 0x7300, 8, iter_reg); + dmp_reg = ®->iobase_q; + for (cnt = 0; cnt < 7; cnt++) + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); + + iter_reg = fw->req1_dma_reg; + iter_reg = qla24xx_read_window(reg, 0x7400, 8, iter_reg); + dmp_reg = ®->iobase_q; + for (cnt = 0; cnt < 7; cnt++) + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); + + /* Transmit DMA registers. */ + iter_reg = fw->xmt0_dma_reg; + iter_reg = qla24xx_read_window(reg, 0x7600, 16, iter_reg); + qla24xx_read_window(reg, 0x7610, 16, iter_reg); + + iter_reg = fw->xmt1_dma_reg; + iter_reg = qla24xx_read_window(reg, 0x7620, 16, iter_reg); + qla24xx_read_window(reg, 0x7630, 16, iter_reg); + + iter_reg = fw->xmt2_dma_reg; + iter_reg = qla24xx_read_window(reg, 0x7640, 16, iter_reg); + qla24xx_read_window(reg, 0x7650, 16, iter_reg); + + iter_reg = fw->xmt3_dma_reg; + iter_reg = qla24xx_read_window(reg, 0x7660, 16, iter_reg); + qla24xx_read_window(reg, 0x7670, 16, iter_reg); + + iter_reg = fw->xmt4_dma_reg; + iter_reg = qla24xx_read_window(reg, 0x7680, 16, iter_reg); + qla24xx_read_window(reg, 0x7690, 16, iter_reg); + + qla24xx_read_window(reg, 0x76A0, 16, fw->xmt_data_dma_reg); + + /* Receive DMA registers. */ + iter_reg = fw->rcvt0_data_dma_reg; + iter_reg = qla24xx_read_window(reg, 0x7700, 16, iter_reg); + qla24xx_read_window(reg, 0x7710, 16, iter_reg); + + iter_reg = fw->rcvt1_data_dma_reg; + iter_reg = qla24xx_read_window(reg, 0x7720, 16, iter_reg); + qla24xx_read_window(reg, 0x7730, 16, iter_reg); + + /* RISC registers. */ + iter_reg = fw->risc_gp_reg; + iter_reg = qla24xx_read_window(reg, 0x0F00, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x0F10, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x0F20, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x0F30, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x0F40, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x0F50, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x0F60, 16, iter_reg); + qla24xx_read_window(reg, 0x0F70, 16, iter_reg); + + /* Local memory controller registers. */ + iter_reg = fw->lmc_reg; + iter_reg = qla24xx_read_window(reg, 0x3000, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x3010, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x3020, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x3030, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x3040, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x3050, 16, iter_reg); + qla24xx_read_window(reg, 0x3060, 16, iter_reg); + + /* Fibre Protocol Module registers. */ + iter_reg = fw->fpm_hdw_reg; + iter_reg = qla24xx_read_window(reg, 0x4000, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x4010, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x4020, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x4030, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x4040, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x4050, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x4060, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x4070, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x4080, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x4090, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x40A0, 16, iter_reg); + qla24xx_read_window(reg, 0x40B0, 16, iter_reg); + + /* Frame Buffer registers. */ + iter_reg = fw->fb_hdw_reg; + iter_reg = qla24xx_read_window(reg, 0x6000, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x6010, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x6020, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x6030, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x6040, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x6100, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x6130, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x6150, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x6170, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x6190, 16, iter_reg); + qla24xx_read_window(reg, 0x61B0, 16, iter_reg); + + rval = qla24xx_soft_reset(ha); + if (rval != QLA_SUCCESS) + goto qla24xx_fw_dump_failed_0; + + rval = qla24xx_dump_memory(ha, fw->code_ram, sizeof(fw->code_ram), + fw->ext_mem, &nxt); + if (rval != QLA_SUCCESS) + goto qla24xx_fw_dump_failed_0; + + nxt = qla2xxx_copy_queues(ha, nxt); + if (ha->eft) + memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size)); + +qla24xx_fw_dump_failed_0: if (rval != QLA_SUCCESS) { qla_printk(KERN_WARNING, ha, "Failed to dump firmware (%x)!!!\n", rval); @@ -1346,7 +1042,6 @@ qla25xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked) int rval; uint32_t cnt; uint32_t risc_address; - uint16_t mb0, wd; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; uint32_t __iomem *dmp_reg; @@ -1377,655 +1072,260 @@ qla25xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked) } fw = &ha->fw_dump->isp.isp25; qla2xxx_prep_dump(ha, ha->fw_dump); + ha->fw_dump->version = __constant_htonl(2); - rval = QLA_SUCCESS; fw->host_status = htonl(RD_REG_DWORD(®->host_status)); /* Pause RISC. */ - if ((RD_REG_DWORD(®->hccr) & HCCRX_RISC_PAUSE) == 0) { - WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_RESET | - HCCRX_CLR_HOST_INT); - RD_REG_DWORD(®->hccr); /* PCI Posting. */ - WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_PAUSE); - for (cnt = 30000; - (RD_REG_DWORD(®->hccr) & HCCRX_RISC_PAUSE) == 0 && - rval == QLA_SUCCESS; cnt--) { - if (cnt) - udelay(100); - else - rval = QLA_FUNCTION_TIMEOUT; - } - } - - if (rval == QLA_SUCCESS) { - /* Host interface registers. */ - dmp_reg = (uint32_t __iomem *)(reg + 0); - for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++) - fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); - - /* Disable interrupts. */ - WRT_REG_DWORD(®->ictrl, 0); - RD_REG_DWORD(®->ictrl); - - /* Shadow registers. */ - WRT_REG_DWORD(®->iobase_addr, 0x0F70); - RD_REG_DWORD(®->iobase_addr); - WRT_REG_DWORD(®->iobase_select, 0xB0000000); - fw->shadow_reg[0] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0100000); - fw->shadow_reg[1] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0200000); - fw->shadow_reg[2] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0300000); - fw->shadow_reg[3] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0400000); - fw->shadow_reg[4] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0500000); - fw->shadow_reg[5] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0600000); - fw->shadow_reg[6] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0700000); - fw->shadow_reg[7] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0800000); - fw->shadow_reg[8] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0900000); - fw->shadow_reg[9] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0A00000); - fw->shadow_reg[10] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - /* RISC I/O register. */ - WRT_REG_DWORD(®->iobase_addr, 0x0010); - RD_REG_DWORD(®->iobase_addr); - fw->risc_io_reg = htonl(RD_REG_DWORD(®->iobase_window)); - - /* Mailbox registers. */ - mbx_reg = ®->mailbox0; - for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++) - fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++)); - - /* Transfer sequence registers. */ - iter_reg = fw->xseq_gp_reg; - WRT_REG_DWORD(®->iobase_addr, 0xBF00); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xBF10); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xBF20); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xBF30); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xBF40); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xBF50); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xBF60); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xBF70); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - iter_reg = fw->xseq_0_reg; - WRT_REG_DWORD(®->iobase_addr, 0xBFC0); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xBFD0); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xBFE0); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xBFF0); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < sizeof(fw->xseq_1_reg) / 4; cnt++) - fw->xseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); - - /* Receive sequence registers. */ - iter_reg = fw->rseq_gp_reg; - WRT_REG_DWORD(®->iobase_addr, 0xFF00); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xFF10); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xFF20); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xFF30); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xFF40); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xFF50); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xFF60); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xFF70); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - iter_reg = fw->rseq_0_reg; - WRT_REG_DWORD(®->iobase_addr, 0xFFC0); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xFFD0); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xFFE0); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < sizeof(fw->rseq_1_reg) / 4; cnt++) - fw->rseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xFFF0); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < sizeof(fw->rseq_2_reg) / 4; cnt++) - fw->rseq_2_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); - - /* Auxiliary sequence registers. */ - iter_reg = fw->aseq_gp_reg; - WRT_REG_DWORD(®->iobase_addr, 0xB000); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xB010); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xB020); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xB030); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xB040); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xB050); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xB060); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xB070); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - iter_reg = fw->aseq_0_reg; - WRT_REG_DWORD(®->iobase_addr, 0xB0C0); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xB0D0); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xB0E0); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < sizeof(fw->aseq_1_reg) / 4; cnt++) - fw->aseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0xB0F0); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < sizeof(fw->aseq_2_reg) / 4; cnt++) - fw->aseq_2_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); - - /* Command DMA registers. */ - WRT_REG_DWORD(®->iobase_addr, 0x7100); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < sizeof(fw->cmd_dma_reg) / 4; cnt++) - fw->cmd_dma_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); - - /* Queues. */ - iter_reg = fw->req0_dma_reg; - WRT_REG_DWORD(®->iobase_addr, 0x7200); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 8; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - dmp_reg = ®->iobase_q; - for (cnt = 0; cnt < 7; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - iter_reg = fw->resp0_dma_reg; - WRT_REG_DWORD(®->iobase_addr, 0x7300); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 8; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - dmp_reg = ®->iobase_q; - for (cnt = 0; cnt < 7; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - iter_reg = fw->req1_dma_reg; - WRT_REG_DWORD(®->iobase_addr, 0x7400); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 8; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - dmp_reg = ®->iobase_q; - for (cnt = 0; cnt < 7; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - /* Transmit DMA registers. */ - iter_reg = fw->xmt0_dma_reg; - WRT_REG_DWORD(®->iobase_addr, 0x7600); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x7610); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - iter_reg = fw->xmt1_dma_reg; - WRT_REG_DWORD(®->iobase_addr, 0x7620); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x7630); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - iter_reg = fw->xmt2_dma_reg; - WRT_REG_DWORD(®->iobase_addr, 0x7640); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x7650); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - iter_reg = fw->xmt3_dma_reg; - WRT_REG_DWORD(®->iobase_addr, 0x7660); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x7670); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - iter_reg = fw->xmt4_dma_reg; - WRT_REG_DWORD(®->iobase_addr, 0x7680); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x7690); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x76A0); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < sizeof(fw->xmt_data_dma_reg) / 4; cnt++) - fw->xmt_data_dma_reg[cnt] = - htonl(RD_REG_DWORD(dmp_reg++)); - - /* Receive DMA registers. */ - iter_reg = fw->rcvt0_data_dma_reg; - WRT_REG_DWORD(®->iobase_addr, 0x7700); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x7710); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - iter_reg = fw->rcvt1_data_dma_reg; - WRT_REG_DWORD(®->iobase_addr, 0x7720); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x7730); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - /* RISC registers. */ - iter_reg = fw->risc_gp_reg; - WRT_REG_DWORD(®->iobase_addr, 0x0F00); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x0F10); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x0F20); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x0F30); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x0F40); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x0F50); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x0F60); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x0F70); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - /* Local memory controller registers. */ - iter_reg = fw->lmc_reg; - WRT_REG_DWORD(®->iobase_addr, 0x3000); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x3010); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x3020); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x3030); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x3040); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x3050); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x3060); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x3070); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - /* Fibre Protocol Module registers. */ - iter_reg = fw->fpm_hdw_reg; - WRT_REG_DWORD(®->iobase_addr, 0x4000); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x4010); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x4020); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x4030); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x4040); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x4050); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x4060); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x4070); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x4080); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x4090); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x40A0); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x40B0); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - /* Frame Buffer registers. */ - iter_reg = fw->fb_hdw_reg; - WRT_REG_DWORD(®->iobase_addr, 0x6000); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x6010); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x6020); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x6030); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x6040); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x6100); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x6130); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x6150); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x6170); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x6190); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x61B0); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - WRT_REG_DWORD(®->iobase_addr, 0x6F00); - dmp_reg = ®->iobase_window; - for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - /* Reset RISC. */ - WRT_REG_DWORD(®->ctrl_status, - CSRX_DMA_SHUTDOWN|MWB_4096_BYTES); - for (cnt = 0; cnt < 30000; cnt++) { - if ((RD_REG_DWORD(®->ctrl_status) & - CSRX_DMA_ACTIVE) == 0) - break; - - udelay(10); - } - - WRT_REG_DWORD(®->ctrl_status, - CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES); - pci_read_config_word(ha->pdev, PCI_COMMAND, &wd); - - udelay(100); - /* Wait for firmware to complete NVRAM accesses. */ - mb0 = (uint32_t) RD_REG_WORD(®->mailbox0); - for (cnt = 10000 ; cnt && mb0; cnt--) { - udelay(5); - mb0 = (uint32_t) RD_REG_WORD(®->mailbox0); - barrier(); - } - - /* Wait for soft-reset to complete. */ - for (cnt = 0; cnt < 30000; cnt++) { - if ((RD_REG_DWORD(®->ctrl_status) & - CSRX_ISP_SOFT_RESET) == 0) - break; - - udelay(10); - } - WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_RESET); - RD_REG_DWORD(®->hccr); /* PCI Posting. */ - } - - for (cnt = 30000; RD_REG_WORD(®->mailbox0) != 0 && - rval == QLA_SUCCESS; cnt--) { - if (cnt) - udelay(100); - else - rval = QLA_FUNCTION_TIMEOUT; - } - - if (rval == QLA_SUCCESS) - rval = qla2xxx_dump_memory(ha, fw->code_ram, - sizeof(fw->code_ram), fw->ext_mem, &nxt); - - if (rval == QLA_SUCCESS) { - nxt = qla2xxx_copy_queues(ha, nxt); - if (ha->eft) - memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size)); - } - + rval = qla24xx_pause_risc(reg); + if (rval != QLA_SUCCESS) + goto qla25xx_fw_dump_failed_0; + + /* Host/Risc registers. */ + iter_reg = fw->host_risc_reg; + iter_reg = qla24xx_read_window(reg, 0x7000, 16, iter_reg); + qla24xx_read_window(reg, 0x7010, 16, iter_reg); + + /* PCIe registers. */ + WRT_REG_DWORD(®->iobase_addr, 0x7C00); + RD_REG_DWORD(®->iobase_addr); + WRT_REG_DWORD(®->iobase_window, 0x01); + dmp_reg = ®->iobase_c4; + fw->pcie_regs[0] = htonl(RD_REG_DWORD(dmp_reg++)); + fw->pcie_regs[1] = htonl(RD_REG_DWORD(dmp_reg++)); + fw->pcie_regs[2] = htonl(RD_REG_DWORD(dmp_reg)); + fw->pcie_regs[3] = htonl(RD_REG_DWORD(®->iobase_window)); + WRT_REG_DWORD(®->iobase_window, 0x00); + RD_REG_DWORD(®->iobase_window); + + /* Host interface registers. */ + dmp_reg = ®->flash_addr; + for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++) + fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); + + /* Disable interrupts. */ + WRT_REG_DWORD(®->ictrl, 0); + RD_REG_DWORD(®->ictrl); + + /* Shadow registers. */ + WRT_REG_DWORD(®->iobase_addr, 0x0F70); + RD_REG_DWORD(®->iobase_addr); + WRT_REG_DWORD(®->iobase_select, 0xB0000000); + fw->shadow_reg[0] = htonl(RD_REG_DWORD(®->iobase_sdata)); + + WRT_REG_DWORD(®->iobase_select, 0xB0100000); + fw->shadow_reg[1] = htonl(RD_REG_DWORD(®->iobase_sdata)); + + WRT_REG_DWORD(®->iobase_select, 0xB0200000); + fw->shadow_reg[2] = htonl(RD_REG_DWORD(®->iobase_sdata)); + + WRT_REG_DWORD(®->iobase_select, 0xB0300000); + fw->shadow_reg[3] = htonl(RD_REG_DWORD(®->iobase_sdata)); + + WRT_REG_DWORD(®->iobase_select, 0xB0400000); + fw->shadow_reg[4] = htonl(RD_REG_DWORD(®->iobase_sdata)); + + WRT_REG_DWORD(®->iobase_select, 0xB0500000); + fw->shadow_reg[5] = htonl(RD_REG_DWORD(®->iobase_sdata)); + + WRT_REG_DWORD(®->iobase_select, 0xB0600000); + fw->shadow_reg[6] = htonl(RD_REG_DWORD(®->iobase_sdata)); + + WRT_REG_DWORD(®->iobase_select, 0xB0700000); + fw->shadow_reg[7] = htonl(RD_REG_DWORD(®->iobase_sdata)); + + WRT_REG_DWORD(®->iobase_select, 0xB0800000); + fw->shadow_reg[8] = htonl(RD_REG_DWORD(®->iobase_sdata)); + + WRT_REG_DWORD(®->iobase_select, 0xB0900000); + fw->shadow_reg[9] = htonl(RD_REG_DWORD(®->iobase_sdata)); + + WRT_REG_DWORD(®->iobase_select, 0xB0A00000); + fw->shadow_reg[10] = htonl(RD_REG_DWORD(®->iobase_sdata)); + + /* RISC I/O register. */ + WRT_REG_DWORD(®->iobase_addr, 0x0010); + fw->risc_io_reg = htonl(RD_REG_DWORD(®->iobase_window)); + + /* Mailbox registers. */ + mbx_reg = ®->mailbox0; + for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++) + fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++)); + + /* Transfer sequence registers. */ + iter_reg = fw->xseq_gp_reg; + iter_reg = qla24xx_read_window(reg, 0xBF00, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xBF10, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xBF20, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xBF30, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xBF40, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xBF50, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xBF60, 16, iter_reg); + qla24xx_read_window(reg, 0xBF70, 16, iter_reg); + + iter_reg = fw->xseq_0_reg; + iter_reg = qla24xx_read_window(reg, 0xBFC0, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xBFD0, 16, iter_reg); + qla24xx_read_window(reg, 0xBFE0, 16, iter_reg); + + qla24xx_read_window(reg, 0xBFF0, 16, fw->xseq_1_reg); + + /* Receive sequence registers. */ + iter_reg = fw->rseq_gp_reg; + iter_reg = qla24xx_read_window(reg, 0xFF00, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xFF10, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xFF20, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xFF30, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xFF40, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xFF50, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xFF60, 16, iter_reg); + qla24xx_read_window(reg, 0xFF70, 16, iter_reg); + + iter_reg = fw->rseq_0_reg; + iter_reg = qla24xx_read_window(reg, 0xFFC0, 16, iter_reg); + qla24xx_read_window(reg, 0xFFD0, 16, iter_reg); + + qla24xx_read_window(reg, 0xFFE0, 16, fw->rseq_1_reg); + qla24xx_read_window(reg, 0xFFF0, 16, fw->rseq_2_reg); + + /* Auxiliary sequence registers. */ + iter_reg = fw->aseq_gp_reg; + iter_reg = qla24xx_read_window(reg, 0xB000, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xB010, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xB020, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xB030, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xB040, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xB050, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xB060, 16, iter_reg); + qla24xx_read_window(reg, 0xB070, 16, iter_reg); + + iter_reg = fw->aseq_0_reg; + iter_reg = qla24xx_read_window(reg, 0xB0C0, 16, iter_reg); + qla24xx_read_window(reg, 0xB0D0, 16, iter_reg); + + qla24xx_read_window(reg, 0xB0E0, 16, fw->aseq_1_reg); + qla24xx_read_window(reg, 0xB0F0, 16, fw->aseq_2_reg); + + /* Command DMA registers. */ + qla24xx_read_window(reg, 0x7100, 16, fw->cmd_dma_reg); + + /* Queues. */ + iter_reg = fw->req0_dma_reg; + iter_reg = qla24xx_read_window(reg, 0x7200, 8, iter_reg); + dmp_reg = ®->iobase_q; + for (cnt = 0; cnt < 7; cnt++) + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); + + iter_reg = fw->resp0_dma_reg; + iter_reg = qla24xx_read_window(reg, 0x7300, 8, iter_reg); + dmp_reg = ®->iobase_q; + for (cnt = 0; cnt < 7; cnt++) + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); + + iter_reg = fw->req1_dma_reg; + iter_reg = qla24xx_read_window(reg, 0x7400, 8, iter_reg); + dmp_reg = ®->iobase_q; + for (cnt = 0; cnt < 7; cnt++) + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); + + /* Transmit DMA registers. */ + iter_reg = fw->xmt0_dma_reg; + iter_reg = qla24xx_read_window(reg, 0x7600, 16, iter_reg); + qla24xx_read_window(reg, 0x7610, 16, iter_reg); + + iter_reg = fw->xmt1_dma_reg; + iter_reg = qla24xx_read_window(reg, 0x7620, 16, iter_reg); + qla24xx_read_window(reg, 0x7630, 16, iter_reg); + + iter_reg = fw->xmt2_dma_reg; + iter_reg = qla24xx_read_window(reg, 0x7640, 16, iter_reg); + qla24xx_read_window(reg, 0x7650, 16, iter_reg); + + iter_reg = fw->xmt3_dma_reg; + iter_reg = qla24xx_read_window(reg, 0x7660, 16, iter_reg); + qla24xx_read_window(reg, 0x7670, 16, iter_reg); + + iter_reg = fw->xmt4_dma_reg; + iter_reg = qla24xx_read_window(reg, 0x7680, 16, iter_reg); + qla24xx_read_window(reg, 0x7690, 16, iter_reg); + + qla24xx_read_window(reg, 0x76A0, 16, fw->xmt_data_dma_reg); + + /* Receive DMA registers. */ + iter_reg = fw->rcvt0_data_dma_reg; + iter_reg = qla24xx_read_window(reg, 0x7700, 16, iter_reg); + qla24xx_read_window(reg, 0x7710, 16, iter_reg); + + iter_reg = fw->rcvt1_data_dma_reg; + iter_reg = qla24xx_read_window(reg, 0x7720, 16, iter_reg); + qla24xx_read_window(reg, 0x7730, 16, iter_reg); + + /* RISC registers. */ + iter_reg = fw->risc_gp_reg; + iter_reg = qla24xx_read_window(reg, 0x0F00, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x0F10, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x0F20, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x0F30, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x0F40, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x0F50, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x0F60, 16, iter_reg); + qla24xx_read_window(reg, 0x0F70, 16, iter_reg); + + /* Local memory controller registers. */ + iter_reg = fw->lmc_reg; + iter_reg = qla24xx_read_window(reg, 0x3000, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x3010, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x3020, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x3030, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x3040, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x3050, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x3060, 16, iter_reg); + qla24xx_read_window(reg, 0x3070, 16, iter_reg); + + /* Fibre Protocol Module registers. */ + iter_reg = fw->fpm_hdw_reg; + iter_reg = qla24xx_read_window(reg, 0x4000, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x4010, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x4020, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x4030, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x4040, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x4050, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x4060, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x4070, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x4080, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x4090, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x40A0, 16, iter_reg); + qla24xx_read_window(reg, 0x40B0, 16, iter_reg); + + /* Frame Buffer registers. */ + iter_reg = fw->fb_hdw_reg; + iter_reg = qla24xx_read_window(reg, 0x6000, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x6010, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x6020, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x6030, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x6040, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x6100, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x6130, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x6150, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x6170, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x6190, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x61B0, 16, iter_reg); + qla24xx_read_window(reg, 0x6F00, 16, iter_reg); + + rval = qla24xx_soft_reset(ha); + if (rval != QLA_SUCCESS) + goto qla25xx_fw_dump_failed_0; + + rval = qla24xx_dump_memory(ha, fw->code_ram, sizeof(fw->code_ram), + fw->ext_mem, &nxt); + if (rval != QLA_SUCCESS) + goto qla25xx_fw_dump_failed_0; + + nxt = qla2xxx_copy_queues(ha, nxt); + if (ha->eft) + memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size)); + +qla25xx_fw_dump_failed_0: if (rval != QLA_SUCCESS) { qla_printk(KERN_WARNING, ha, "Failed to dump firmware (%x)!!!\n", rval); @@ -2102,7 +1402,7 @@ qla2x00_print_scsi_cmd(struct scsi_cmnd * cmd) struct scsi_qla_host *ha; srb_t *sp; - ha = (struct scsi_qla_host *)cmd->device->host->hostdata; + ha = shost_priv(cmd->device->host); sp = (srb_t *) cmd->SCp.ptr; printk("SCSI Command @=0x%p, Handle=0x%p\n", cmd, cmd->host_scribble); diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h index cca4b0d8253e..a50ecf0b7c84 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.h +++ b/drivers/scsi/qla2xxx/qla_dbg.h @@ -215,6 +215,8 @@ struct qla24xx_fw_dump { struct qla25xx_fw_dump { uint32_t host_status; + uint32_t host_risc_reg[32]; + uint32_t pcie_regs[4]; uint32_t host_reg[32]; uint32_t shadow_reg[11]; uint32_t risc_io_reg; diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index c1964866a423..1900fbf6cd74 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -23,6 +23,7 @@ #include <linux/interrupt.h> #include <linux/workqueue.h> #include <linux/firmware.h> +#include <linux/aer.h> #include <asm/semaphore.h> #include <scsi/scsi.h> @@ -184,8 +185,6 @@ * SCSI Request Block */ typedef struct srb { - struct list_head list; - struct scsi_qla_host *ha; /* HA the SP is queued on */ struct fc_port *fcport; @@ -316,7 +315,9 @@ struct device_reg_2xxx { } u; uint16_t fpm_diag_config; - uint16_t unused_5[0x6]; /* Gap */ + uint16_t unused_5[0x4]; /* Gap */ + uint16_t risc_hw; + uint16_t unused_5_1; /* Gap */ uint16_t pcr; /* Processor Control Register. */ uint16_t unused_6[0x5]; /* Gap */ uint16_t mctr; /* Memory Configuration and Timing. */ @@ -1702,7 +1703,7 @@ struct ct_fdmi_hba_attributes { /* * Port attribute types. */ -#define FDMI_PORT_ATTR_COUNT 5 +#define FDMI_PORT_ATTR_COUNT 6 #define FDMI_PORT_FC4_TYPES 1 #define FDMI_PORT_SUPPORT_SPEED 2 #define FDMI_PORT_CURRENT_SPEED 3 @@ -2476,6 +2477,8 @@ typedef struct scsi_qla_host { #define QLA_SWAITING 0 #define QLA_SREADING 1 #define QLA_SWRITING 2 + uint32_t optrom_region_start; + uint32_t optrom_region_size; /* PCI expansion ROM image information. */ #define ROM_CODE_TYPE_BIOS 0 @@ -2529,7 +2532,7 @@ typedef struct scsi_qla_host { #define VP_ERR_FAB_NORESOURCES 3 #define VP_ERR_FAB_LOGOUT 4 #define VP_ERR_ADAP_NORESOURCES 5 - int max_npiv_vports; /* 63 or 125 per topoloty */ + uint16_t max_npiv_vports; /* 63 or 125 per topoloty */ int cur_vport_count; } scsi_qla_host_t; @@ -2542,8 +2545,6 @@ typedef struct scsi_qla_host { test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) || \ atomic_read(&ha->loop_state) == LOOP_DOWN) -#define to_qla_host(x) ((scsi_qla_host_t *) (x)->hostdata) - #define qla_printk(level, ha, format, arg...) \ dev_printk(level , &((ha)->pdev->dev) , format , ## arg) diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index 99fe49618d61..25364b1aaf12 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -779,6 +779,8 @@ struct device_reg_24xx { #define FA_NVRAM_VPD_SIZE 0x200 #define FA_NVRAM_VPD0_ADDR 0x00 #define FA_NVRAM_VPD1_ADDR 0x100 + +#define FA_BOOT_CODE_ADDR 0x00000 /* * RISC code begins at offset 512KB * within flash. Consisting of two @@ -940,7 +942,9 @@ struct device_reg_24xx { uint16_t mailbox31; uint32_t iobase_window; - uint32_t unused_4[8]; /* Gap. */ + uint32_t iobase_c4; + uint32_t iobase_c8; + uint32_t unused_4_1[6]; /* Gap. */ uint32_t iobase_q; uint32_t unused_5[2]; /* Gap. */ uint32_t iobase_select; diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index aa1e41152283..09cb2a908059 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -134,6 +134,9 @@ extern int qla2x00_load_ram(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t); extern int +qla2x00_dump_ram(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t); + +extern int qla2x00_execute_fw(scsi_qla_host_t *, uint32_t); extern void @@ -212,8 +215,8 @@ extern int qla2x00_get_id_list(scsi_qla_host_t *, void *, dma_addr_t, uint16_t *); extern int -qla2x00_get_resource_cnts(scsi_qla_host_t *, uint16_t *, uint16_t *, uint16_t *, - uint16_t *); +qla2x00_get_resource_cnts(scsi_qla_host_t *, uint16_t *, uint16_t *, + uint16_t *, uint16_t *, uint16_t *); extern int qla2x00_get_fcal_position_map(scsi_qla_host_t *ha, char *pos_map); @@ -302,6 +305,8 @@ extern uint8_t *qla24xx_read_optrom_data(struct scsi_qla_host *, uint8_t *, uint32_t, uint32_t); extern int qla24xx_write_optrom_data(struct scsi_qla_host *, uint8_t *, uint32_t, uint32_t); +extern uint8_t *qla25xx_read_optrom_data(struct scsi_qla_host *, uint8_t *, + uint32_t, uint32_t); extern int qla2x00_get_flash_version(scsi_qla_host_t *, void *); extern int qla24xx_get_flash_version(scsi_qla_host_t *, void *); diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index a7e23583f899..eb0784c9ff83 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -1517,7 +1517,7 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha) /* Attributes */ ct_req->req.rpa.attrs.count = - __constant_cpu_to_be32(FDMI_PORT_ATTR_COUNT); + __constant_cpu_to_be32(FDMI_PORT_ATTR_COUNT - 1); entries = ct_req->req.rpa.port_name; /* FC4 types. */ @@ -1600,7 +1600,7 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha) /* OS device name. */ eiter = (struct ct_fdmi_port_attr *) (entries + size); eiter->type = __constant_cpu_to_be16(FDMI_PORT_OS_DEVICE_NAME); - sprintf(eiter->a.os_dev_name, "/proc/scsi/qla2xxx/%ld", ha->host_no); + strcpy(eiter->a.os_dev_name, QLA2XXX_DRIVER_NAME); alen = strlen(eiter->a.os_dev_name); alen += (alen & 3) ? (4 - (alen & 3)) : 4; eiter->len = cpu_to_be16(4 + alen); @@ -1611,6 +1611,8 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha) /* Hostname. */ if (strlen(fc_host_system_hostname(ha->host))) { + ct_req->req.rpa.attrs.count = + __constant_cpu_to_be32(FDMI_PORT_ATTR_COUNT); eiter = (struct ct_fdmi_port_attr *) (entries + size); eiter->type = __constant_cpu_to_be16(FDMI_PORT_HOST_NAME); snprintf(eiter->a.host_name, sizeof(eiter->a.host_name), diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 1a058ec9bd0c..191dafd89be0 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -849,7 +849,8 @@ qla2x00_resize_request_q(scsi_qla_host_t *ha) return; /* Retrieve IOCB counts available to the firmware. */ - rval = qla2x00_get_resource_cnts(ha, NULL, NULL, NULL, &fw_iocb_cnt); + rval = qla2x00_get_resource_cnts(ha, NULL, NULL, NULL, &fw_iocb_cnt, + &ha->max_npiv_vports); if (rval) return; /* No point in continuing if current settings are sufficient. */ @@ -916,9 +917,15 @@ qla2x00_setup_chip(scsi_qla_host_t *ha) &ha->fw_attributes, &ha->fw_memory_size); qla2x00_resize_request_q(ha); ha->flags.npiv_supported = 0; - if (IS_QLA24XX(ha) && - (ha->fw_attributes & BIT_2)) + if ((IS_QLA24XX(ha) || IS_QLA25XX(ha)) && + (ha->fw_attributes & BIT_2)) { ha->flags.npiv_supported = 1; + if ((!ha->max_npiv_vports) || + ((ha->max_npiv_vports + 1) % + MAX_MULTI_ID_FABRIC)) + ha->max_npiv_vports = + MAX_NUM_VPORT_FABRIC; + } if (ql2xallocfwdump) qla2x00_alloc_fw_dump(ha); @@ -1155,8 +1162,7 @@ qla2x00_init_rings(scsi_qla_host_t *ha) DEBUG(printk("scsi(%ld): Issue init firmware.\n", ha->host_no)); - mid_init_cb->count = MAX_NUM_VPORT_FABRIC; - ha->max_npiv_vports = MAX_NUM_VPORT_FABRIC; + mid_init_cb->count = ha->max_npiv_vports; rval = qla2x00_init_firmware(ha, ha->init_cb_size); if (rval) { @@ -1786,12 +1792,11 @@ qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags) { fc_port_t *fcport; - fcport = kmalloc(sizeof(fc_port_t), flags); - if (fcport == NULL) - return (fcport); + fcport = kzalloc(sizeof(fc_port_t), flags); + if (!fcport) + return NULL; /* Setup fcport template structure. */ - memset(fcport, 0, sizeof (fc_port_t)); fcport->ha = ha; fcport->vp_idx = ha->vp_idx; fcport->port_type = FCT_UNKNOWN; @@ -1801,7 +1806,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags) fcport->supported_classes = FC_COS_UNSPECIFIED; spin_lock_init(&fcport->rport_lock); - return (fcport); + return fcport; } /* @@ -2127,15 +2132,9 @@ qla2x00_iidma_fcport(scsi_qla_host_t *ha, fc_port_t *fcport) if (!IS_IIDMA_CAPABLE(ha)) return; - if (fcport->fp_speed == PORT_SPEED_UNKNOWN) { - DEBUG2(printk("scsi(%ld): %02x%02x%02x%02x%02x%02x%02x%02x -- " - "unsupported FM port operating speed.\n", - ha->host_no, fcport->port_name[0], fcport->port_name[1], - fcport->port_name[2], fcport->port_name[3], - fcport->port_name[4], fcport->port_name[5], - fcport->port_name[6], fcport->port_name[7])); + if (fcport->fp_speed == PORT_SPEED_UNKNOWN || + fcport->fp_speed > ha->link_data_rate) return; - } rval = qla2x00_set_idma_speed(ha, fcport->loop_id, fcport->fp_speed, mb); @@ -2473,13 +2472,12 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports) rval = QLA_SUCCESS; /* Try GID_PT to get device list, else GAN. */ - swl = kmalloc(sizeof(sw_info_t) * MAX_FIBRE_DEVICES, GFP_ATOMIC); - if (swl == NULL) { + swl = kcalloc(MAX_FIBRE_DEVICES, sizeof(sw_info_t), GFP_ATOMIC); + if (!swl) { /*EMPTY*/ DEBUG2(printk("scsi(%ld): GID_PT allocations failed, fallback " "on GA_NXT\n", ha->host_no)); } else { - memset(swl, 0, sizeof(sw_info_t) * MAX_FIBRE_DEVICES); if (qla2x00_gid_pt(ha, swl) != QLA_SUCCESS) { kfree(swl); swl = NULL; diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 3a5e78cb6b3f..7f6a89bd94f3 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -308,7 +308,7 @@ qla2x00_start_scsi(srb_t *sp) handle++; if (handle == MAX_OUTSTANDING_COMMANDS) handle = 1; - if (ha->outstanding_cmds[handle] == 0) + if (!ha->outstanding_cmds[handle]) break; } if (index == MAX_OUTSTANDING_COMMANDS) @@ -711,7 +711,7 @@ qla24xx_start_scsi(srb_t *sp) handle++; if (handle == MAX_OUTSTANDING_COMMANDS) handle = 1; - if (ha->outstanding_cmds[handle] == 0) + if (!ha->outstanding_cmds[handle]) break; } if (index == MAX_OUTSTANDING_COMMANDS) diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index eecae9905ece..c4768c4f3990 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -6,6 +6,7 @@ */ #include "qla_def.h" +#include <linux/delay.h> #include <scsi/scsi_tcq.h> static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t); @@ -34,6 +35,7 @@ qla2100_intr_handler(int irq, void *dev_id) int status; unsigned long flags; unsigned long iter; + uint16_t hccr; uint16_t mb[4]; ha = (scsi_qla_host_t *) dev_id; @@ -48,7 +50,23 @@ qla2100_intr_handler(int irq, void *dev_id) spin_lock_irqsave(&ha->hardware_lock, flags); for (iter = 50; iter--; ) { - if ((RD_REG_WORD(®->istatus) & ISR_RISC_INT) == 0) + hccr = RD_REG_WORD(®->hccr); + if (hccr & HCCR_RISC_PAUSE) { + if (pci_channel_offline(ha->pdev)) + break; + + /* + * Issue a "HARD" reset in order for the RISC interrupt + * bit to be cleared. Schedule a big hammmer to get + * out of the RISC PAUSED state. + */ + WRT_REG_WORD(®->hccr, HCCR_RESET_RISC); + RD_REG_WORD(®->hccr); + + ha->isp_ops->fw_dump(ha, 1); + set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); + break; + } else if ((RD_REG_WORD(®->istatus) & ISR_RISC_INT) == 0) break; if (RD_REG_WORD(®->semaphore) & BIT_0) { @@ -127,6 +145,9 @@ qla2300_intr_handler(int irq, void *dev_id) for (iter = 50; iter--; ) { stat = RD_REG_DWORD(®->u.isp2300.host_status); if (stat & HSR_RISC_PAUSED) { + if (pci_channel_offline(ha->pdev)) + break; + hccr = RD_REG_WORD(®->hccr); if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8)) qla_printk(KERN_INFO, ha, "Parity error -- " @@ -1464,6 +1485,52 @@ qla24xx_process_response_queue(struct scsi_qla_host *ha) WRT_REG_DWORD(®->rsp_q_out, ha->rsp_ring_index); } +static void +qla2xxx_check_risc_status(scsi_qla_host_t *ha) +{ + int rval; + uint32_t cnt; + struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; + + if (!IS_QLA25XX(ha)) + return; + + rval = QLA_SUCCESS; + WRT_REG_DWORD(®->iobase_addr, 0x7C00); + RD_REG_DWORD(®->iobase_addr); + WRT_REG_DWORD(®->iobase_window, 0x0001); + for (cnt = 10000; (RD_REG_DWORD(®->iobase_window) & BIT_0) == 0 && + rval == QLA_SUCCESS; cnt--) { + if (cnt) { + WRT_REG_DWORD(®->iobase_window, 0x0001); + udelay(10); + } else + rval = QLA_FUNCTION_TIMEOUT; + } + if (rval == QLA_SUCCESS) + goto next_test; + + WRT_REG_DWORD(®->iobase_window, 0x0003); + for (cnt = 100; (RD_REG_DWORD(®->iobase_window) & BIT_0) == 0 && + rval == QLA_SUCCESS; cnt--) { + if (cnt) { + WRT_REG_DWORD(®->iobase_window, 0x0003); + udelay(10); + } else + rval = QLA_FUNCTION_TIMEOUT; + } + if (rval != QLA_SUCCESS) + goto done; + +next_test: + if (RD_REG_DWORD(®->iobase_c8) & BIT_3) + qla_printk(KERN_INFO, ha, "Additional code -- 0x55AA.\n"); + +done: + WRT_REG_DWORD(®->iobase_window, 0x0000); + RD_REG_DWORD(®->iobase_window); +} + /** * qla24xx_intr_handler() - Process interrupts for the ISP23xx and ISP63xx. * @irq: @@ -1499,10 +1566,16 @@ qla24xx_intr_handler(int irq, void *dev_id) for (iter = 50; iter--; ) { stat = RD_REG_DWORD(®->host_status); if (stat & HSRX_RISC_PAUSED) { + if (pci_channel_offline(ha->pdev)) + break; + hccr = RD_REG_DWORD(®->hccr); qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, " "Dumping firmware!\n", hccr); + + qla2xxx_check_risc_status(ha); + ha->isp_ops->fw_dump(ha, 1); set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); break; @@ -1606,7 +1679,6 @@ qla24xx_msix_rsp_q(int irq, void *dev_id) qla24xx_process_response_queue(ha); WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); - RD_REG_DWORD_RELAXED(®->hccr); spin_unlock_irqrestore(&ha->hardware_lock, flags); @@ -1620,7 +1692,6 @@ qla24xx_msix_default(int irq, void *dev_id) struct device_reg_24xx __iomem *reg; int status; unsigned long flags; - unsigned long iter; uint32_t stat; uint32_t hccr; uint16_t mb[4]; @@ -1630,13 +1701,19 @@ qla24xx_msix_default(int irq, void *dev_id) status = 0; spin_lock_irqsave(&ha->hardware_lock, flags); - for (iter = 50; iter--; ) { + do { stat = RD_REG_DWORD(®->host_status); if (stat & HSRX_RISC_PAUSED) { + if (pci_channel_offline(ha->pdev)) + break; + hccr = RD_REG_DWORD(®->hccr); qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, " "Dumping firmware!\n", hccr); + + qla2xxx_check_risc_status(ha); + ha->isp_ops->fw_dump(ha, 1); set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); break; @@ -1669,8 +1746,7 @@ qla24xx_msix_default(int irq, void *dev_id) break; } WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); - RD_REG_DWORD_RELAXED(®->hccr); - } + } while (0); spin_unlock_irqrestore(&ha->hardware_lock, flags); if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index d3746ec80a85..c53ec67c47f4 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -391,7 +391,8 @@ qla2x00_execute_fw(scsi_qla_host_t *ha, uint32_t risc_addr) mcp->mb[1] = MSW(risc_addr); mcp->mb[2] = LSW(risc_addr); mcp->mb[3] = 0; - mcp->out_mb |= MBX_3|MBX_2|MBX_1; + mcp->mb[4] = 0; + mcp->out_mb |= MBX_4|MBX_3|MBX_2|MBX_1; mcp->in_mb |= MBX_1; } else { mcp->mb[1] = LSW(risc_addr); @@ -1919,7 +1920,8 @@ qla2x00_get_id_list(scsi_qla_host_t *ha, void *id_list, dma_addr_t id_list_dma, */ int qla2x00_get_resource_cnts(scsi_qla_host_t *ha, uint16_t *cur_xchg_cnt, - uint16_t *orig_xchg_cnt, uint16_t *cur_iocb_cnt, uint16_t *orig_iocb_cnt) + uint16_t *orig_xchg_cnt, uint16_t *cur_iocb_cnt, + uint16_t *orig_iocb_cnt, uint16_t *max_npiv_vports) { int rval; mbx_cmd_t mc; @@ -1929,7 +1931,7 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *ha, uint16_t *cur_xchg_cnt, mcp->mb[0] = MBC_GET_RESOURCE_COUNTS; mcp->out_mb = MBX_0; - mcp->in_mb = MBX_10|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_11|MBX_10|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; mcp->tov = 30; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -1940,9 +1942,9 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *ha, uint16_t *cur_xchg_cnt, ha->host_no, mcp->mb[0])); } else { DEBUG11(printk("%s(%ld): done. mb1=%x mb2=%x mb3=%x mb6=%x " - "mb7=%x mb10=%x.\n", __func__, ha->host_no, + "mb7=%x mb10=%x mb11=%x.\n", __func__, ha->host_no, mcp->mb[1], mcp->mb[2], mcp->mb[3], mcp->mb[6], mcp->mb[7], - mcp->mb[10])); + mcp->mb[10], mcp->mb[11])); if (cur_xchg_cnt) *cur_xchg_cnt = mcp->mb[3]; @@ -1952,6 +1954,8 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *ha, uint16_t *cur_xchg_cnt, *cur_iocb_cnt = mcp->mb[7]; if (orig_iocb_cnt) *orig_iocb_cnt = mcp->mb[10]; + if (max_npiv_vports) + *max_npiv_vports = mcp->mb[11]; } return (rval); @@ -2980,3 +2984,51 @@ qla2x00_send_change_request(scsi_qla_host_t *ha, uint16_t format, return rval; } + +int +qla2x00_dump_ram(scsi_qla_host_t *ha, dma_addr_t req_dma, uint32_t addr, + uint32_t size) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); + + if (MSW(addr) || IS_FWI2_CAPABLE(ha)) { + mcp->mb[0] = MBC_DUMP_RISC_RAM_EXTENDED; + mcp->mb[8] = MSW(addr); + mcp->out_mb = MBX_8|MBX_0; + } else { + mcp->mb[0] = MBC_DUMP_RISC_RAM; + mcp->out_mb = MBX_0; + } + mcp->mb[1] = LSW(addr); + mcp->mb[2] = MSW(req_dma); + mcp->mb[3] = LSW(req_dma); + mcp->mb[6] = MSW(MSD(req_dma)); + mcp->mb[7] = LSW(MSD(req_dma)); + mcp->out_mb |= MBX_7|MBX_6|MBX_3|MBX_2|MBX_1; + if (IS_FWI2_CAPABLE(ha)) { + mcp->mb[4] = MSW(size); + mcp->mb[5] = LSW(size); + mcp->out_mb |= MBX_5|MBX_4; + } else { + mcp->mb[4] = LSW(size); + mcp->out_mb |= MBX_4; + } + + mcp->in_mb = MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x.\n", __func__, + ha->host_no, rval, mcp->mb[0])); + } else { + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); + } + + return rval; +} diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index 54dc415d8b53..821ee74aadc6 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -104,7 +104,7 @@ qla24xx_find_vhost_by_name(scsi_qla_host_t *ha, uint8_t *port_name) * * Context: */ -void +static void qla2x00_mark_vp_devices_dead(scsi_qla_host_t *vha) { fc_port_t *fcport; @@ -179,37 +179,7 @@ enable_failed: return 1; } -/** - * qla24xx_modify_vport() - Modifies the virtual fabric port's configuration - * @ha: HA context - * @vp: pointer to buffer of virtual port parameters. - * @ret_code: return error code: - * - * Returns the virtual port id, or MAX_VSAN_ID, if couldn't create. - */ -uint32_t -qla24xx_modify_vhba(scsi_qla_host_t *ha, vport_params_t *vp, uint32_t *vp_id) -{ - scsi_qla_host_t *vha; - - vha = qla24xx_find_vhost_by_name(ha, vp->port_name); - if (!vha) { - *vp_id = MAX_NUM_VPORT_LOOP; - return VP_RET_CODE_WWPN; - } - - if (qla24xx_enable_vp(vha)) { - scsi_host_put(vha->host); - qla2x00_mem_free(vha); - *vp_id = MAX_NUM_VPORT_LOOP; - return VP_RET_CODE_RESOURCES; - } - - *vp_id = vha->vp_idx; - return VP_RET_CODE_OK; -} - -void +static void qla24xx_configure_vp(scsi_qla_host_t *vha) { struct fc_vport *fc_vport; @@ -363,7 +333,7 @@ qla2x00_do_dpc_all_vps(scsi_qla_host_t *ha) int qla24xx_vport_create_req_sanity_check(struct fc_vport *fc_vport) { - scsi_qla_host_t *ha = (scsi_qla_host_t *) fc_vport->shost->hostdata; + scsi_qla_host_t *ha = shost_priv(fc_vport->shost); scsi_qla_host_t *vha; uint8_t port_name[WWN_SIZE]; @@ -397,7 +367,7 @@ qla24xx_vport_create_req_sanity_check(struct fc_vport *fc_vport) scsi_qla_host_t * qla24xx_create_vhost(struct fc_vport *fc_vport) { - scsi_qla_host_t *ha = (scsi_qla_host_t *) fc_vport->shost->hostdata; + scsi_qla_host_t *ha = shost_priv(fc_vport->shost); scsi_qla_host_t *vha; struct Scsi_Host *host; @@ -409,7 +379,7 @@ qla24xx_create_vhost(struct fc_vport *fc_vport) return(NULL); } - vha = (scsi_qla_host_t *)host->hostdata; + vha = shost_priv(host); /* clone the parent hba */ memcpy(vha, ha, sizeof (scsi_qla_host_t)); diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index acca898ce0a2..a6bb8d0ecf13 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -379,12 +379,17 @@ qla2x00_get_new_sp(scsi_qla_host_t *ha, fc_port_t *fcport, static int qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) { - scsi_qla_host_t *ha = to_qla_host(cmd->device->host); + scsi_qla_host_t *ha = shost_priv(cmd->device->host); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device)); srb_t *sp; int rval; + if (unlikely(pci_channel_offline(ha->pdev))) { + cmd->result = DID_REQUEUE << 16; + goto qc_fail_command; + } + rval = fc_remote_port_chkready(rport); if (rval) { cmd->result = rval; @@ -440,13 +445,18 @@ qc_fail_command: static int qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) { - scsi_qla_host_t *ha = to_qla_host(cmd->device->host); + scsi_qla_host_t *ha = shost_priv(cmd->device->host); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device)); srb_t *sp; int rval; scsi_qla_host_t *pha = to_qla_parent(ha); + if (unlikely(pci_channel_offline(ha->pdev))) { + cmd->result = DID_REQUEUE << 16; + goto qc24_fail_command; + } + rval = fc_remote_port_chkready(rport); if (rval) { cmd->result = rval; @@ -653,7 +663,7 @@ qla2x00_block_error_handler(struct scsi_cmnd *cmnd) static int qla2xxx_eh_abort(struct scsi_cmnd *cmd) { - scsi_qla_host_t *ha = to_qla_host(cmd->device->host); + scsi_qla_host_t *ha = shost_priv(cmd->device->host); srb_t *sp; int ret, i; unsigned int id, lun; @@ -793,7 +803,7 @@ qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t) static int qla2xxx_eh_device_reset(struct scsi_cmnd *cmd) { - scsi_qla_host_t *ha = to_qla_host(cmd->device->host); + scsi_qla_host_t *ha = shost_priv(cmd->device->host); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; int ret = FAILED; unsigned int id, lun; @@ -922,7 +932,7 @@ qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha) static int qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd) { - scsi_qla_host_t *ha = to_qla_host(cmd->device->host); + scsi_qla_host_t *ha = shost_priv(cmd->device->host); scsi_qla_host_t *pha = to_qla_parent(ha); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; int ret = FAILED; @@ -982,7 +992,7 @@ eh_bus_reset_done: static int qla2xxx_eh_host_reset(struct scsi_cmnd *cmd) { - scsi_qla_host_t *ha = to_qla_host(cmd->device->host); + scsi_qla_host_t *ha = shost_priv(cmd->device->host); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; int ret = FAILED; unsigned int id, lun; @@ -1132,7 +1142,7 @@ qla2xxx_slave_alloc(struct scsi_device *sdev) static int qla2xxx_slave_configure(struct scsi_device *sdev) { - scsi_qla_host_t *ha = to_qla_host(sdev->host); + scsi_qla_host_t *ha = shost_priv(sdev->host); struct fc_rport *rport = starget_to_rport(sdev->sdev_target); if (sdev->tagged_supported) @@ -1384,7 +1394,7 @@ static struct isp_operations qla25xx_isp_ops = { .beacon_on = qla24xx_beacon_on, .beacon_off = qla24xx_beacon_off, .beacon_blink = qla24xx_beacon_blink, - .read_optrom = qla24xx_read_optrom_data, + .read_optrom = qla25xx_read_optrom_data, .write_optrom = qla24xx_write_optrom_data, .get_flash_version = qla24xx_get_flash_version, }; @@ -1533,7 +1543,7 @@ iospace_error_exit: static void qla2xxx_scan_start(struct Scsi_Host *shost) { - scsi_qla_host_t *ha = (scsi_qla_host_t *)shost->hostdata; + scsi_qla_host_t *ha = shost_priv(shost); set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags); set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags); @@ -1543,7 +1553,7 @@ qla2xxx_scan_start(struct Scsi_Host *shost) static int qla2xxx_scan_finished(struct Scsi_Host *shost, unsigned long time) { - scsi_qla_host_t *ha = (scsi_qla_host_t *)shost->hostdata; + scsi_qla_host_t *ha = shost_priv(shost); if (!ha->host) return 1; @@ -1571,6 +1581,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) if (pci_enable_device(pdev)) goto probe_out; + if (pci_find_aer_capability(pdev)) + if (pci_enable_pcie_error_reporting(pdev)) + goto probe_out; + sht = &qla2x00_driver_template; if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 || pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432 || @@ -1586,7 +1600,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) } /* Clear our data area */ - ha = (scsi_qla_host_t *)host->hostdata; + ha = shost_priv(host); memset(ha, 0, sizeof(scsi_qla_host_t)); ha->pdev = pdev; @@ -2423,7 +2437,6 @@ qla2x00_do_dpc(void *data) if (atomic_read(&fcport->state) != FCS_ONLINE && fcport->login_retry) { - fcport->login_retry--; if (fcport->flags & FCF_FABRIC_DEVICE) { if (fcport->flags & FCF_TAPE_PRESENT) @@ -2439,6 +2452,7 @@ qla2x00_do_dpc(void *data) qla2x00_local_device_login( ha, fcport); + fcport->login_retry--; if (status == QLA_SUCCESS) { fcport->old_loop_id = fcport->loop_id; @@ -2456,6 +2470,8 @@ qla2x00_do_dpc(void *data) } else { fcport->login_retry = 0; } + if (fcport->login_retry == 0) + fcport->loop_id = FC_NO_LOOP_ID; } if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) break; @@ -2814,6 +2830,105 @@ qla2x00_release_firmware(void) up(&qla_fw_lock); } +static pci_ers_result_t +qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) +{ + switch (state) { + case pci_channel_io_normal: + return PCI_ERS_RESULT_CAN_RECOVER; + case pci_channel_io_frozen: + pci_disable_device(pdev); + return PCI_ERS_RESULT_NEED_RESET; + case pci_channel_io_perm_failure: + qla2x00_remove_one(pdev); + return PCI_ERS_RESULT_DISCONNECT; + } + return PCI_ERS_RESULT_NEED_RESET; +} + +static pci_ers_result_t +qla2xxx_pci_mmio_enabled(struct pci_dev *pdev) +{ + int risc_paused = 0; + uint32_t stat; + unsigned long flags; + scsi_qla_host_t *ha = pci_get_drvdata(pdev); + struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; + struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24; + + spin_lock_irqsave(&ha->hardware_lock, flags); + if (IS_QLA2100(ha) || IS_QLA2200(ha)){ + stat = RD_REG_DWORD(®->hccr); + if (stat & HCCR_RISC_PAUSE) + risc_paused = 1; + } else if (IS_QLA23XX(ha)) { + stat = RD_REG_DWORD(®->u.isp2300.host_status); + if (stat & HSR_RISC_PAUSED) + risc_paused = 1; + } else if (IS_FWI2_CAPABLE(ha)) { + stat = RD_REG_DWORD(®24->host_status); + if (stat & HSRX_RISC_PAUSED) + risc_paused = 1; + } + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + if (risc_paused) { + qla_printk(KERN_INFO, ha, "RISC paused -- mmio_enabled, " + "Dumping firmware!\n"); + ha->isp_ops->fw_dump(ha, 0); + + return PCI_ERS_RESULT_NEED_RESET; + } else + return PCI_ERS_RESULT_RECOVERED; +} + +static pci_ers_result_t +qla2xxx_pci_slot_reset(struct pci_dev *pdev) +{ + pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT; + scsi_qla_host_t *ha = pci_get_drvdata(pdev); + + if (pci_enable_device(pdev)) { + qla_printk(KERN_WARNING, ha, + "Can't re-enable PCI device after reset.\n"); + + return ret; + } + pci_set_master(pdev); + + if (ha->isp_ops->pci_config(ha)) + return ret; + + set_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags); + if (qla2x00_abort_isp(ha)== QLA_SUCCESS) + ret = PCI_ERS_RESULT_RECOVERED; + clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags); + + return ret; +} + +static void +qla2xxx_pci_resume(struct pci_dev *pdev) +{ + scsi_qla_host_t *ha = pci_get_drvdata(pdev); + int ret; + + ret = qla2x00_wait_for_hba_online(ha); + if (ret != QLA_SUCCESS) { + qla_printk(KERN_ERR, ha, + "the device failed to resume I/O " + "from slot/link_reset"); + } + pci_cleanup_aer_uncorrect_error_status(pdev); +} + +static struct pci_error_handlers qla2xxx_err_handler = { + .error_detected = qla2xxx_pci_error_detected, + .mmio_enabled = qla2xxx_pci_mmio_enabled, + .slot_reset = qla2xxx_pci_slot_reset, + .resume = qla2xxx_pci_resume, +}; + static struct pci_device_id qla2xxx_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2100) }, { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2200) }, @@ -2839,6 +2954,7 @@ static struct pci_driver qla2xxx_pci_driver = { .id_table = qla2xxx_pci_tbl, .probe = qla2x00_probe_one, .remove = __devexit_p(qla2x00_remove_one), + .err_handler = &qla2xxx_err_handler, }; /** diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index a925a3f179f9..40b059fc1981 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -425,6 +425,9 @@ qla2x00_set_nvram_protection(scsi_qla_host_t *ha, int stat) /* Flash Manipulation Routines */ /*****************************************************************************/ +#define OPTROM_BURST_SIZE 0x1000 +#define OPTROM_BURST_DWORDS (OPTROM_BURST_SIZE / 4) + static inline uint32_t flash_conf_to_access_addr(uint32_t faddr) { @@ -544,41 +547,59 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, uint32_t dwords) { int ret; - uint32_t liter; - uint32_t sec_mask, rest_addr, conf_addr, sec_end_mask; + uint32_t liter, miter; + uint32_t sec_mask, rest_addr, conf_addr; uint32_t fdata, findex ; uint8_t man_id, flash_id; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; + dma_addr_t optrom_dma; + void *optrom = NULL; + uint32_t *s, *d; ret = QLA_SUCCESS; + /* Prepare burst-capable write on supported ISPs. */ + if (IS_QLA25XX(ha) && !(faddr & 0xfff) && + dwords > OPTROM_BURST_DWORDS) { + optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, + &optrom_dma, GFP_KERNEL); + if (!optrom) { + qla_printk(KERN_DEBUG, ha, + "Unable to allocate memory for optrom burst write " + "(%x KB).\n", OPTROM_BURST_SIZE / 1024); + } + } + qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id); DEBUG9(printk("%s(%ld): Flash man_id=%d flash_id=%d\n", __func__, ha->host_no, man_id, flash_id)); - sec_end_mask = 0; conf_addr = flash_conf_to_access_addr(0x03d8); switch (man_id) { case 0xbf: /* STT flash. */ - rest_addr = 0x1fff; - sec_mask = 0x3e000; + if (flash_id == 0x8e) { + rest_addr = 0x3fff; + sec_mask = 0x7c000; + } else { + rest_addr = 0x1fff; + sec_mask = 0x7e000; + } if (flash_id == 0x80) conf_addr = flash_conf_to_access_addr(0x0352); break; case 0x13: /* ST M25P80. */ rest_addr = 0x3fff; - sec_mask = 0x3c000; + sec_mask = 0x7c000; break; case 0x1f: // Atmel 26DF081A - rest_addr = 0x0fff; - sec_mask = 0xff000; - sec_end_mask = 0x003ff; + rest_addr = 0x3fff; + sec_mask = 0x7c000; conf_addr = flash_conf_to_access_addr(0x0320); break; default: /* Default to 64 kb sector size. */ rest_addr = 0x3fff; - sec_mask = 0x3c000; + sec_mask = 0x7c000; break; } @@ -592,56 +613,81 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, /* Some flash parts need an additional zero-write to clear bits.*/ qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0); - do { /* Loop once to provide quick error exit. */ - for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) { - if (man_id == 0x1f) { - findex = faddr << 2; - fdata = findex & sec_mask; - } else { - findex = faddr; - fdata = (findex & sec_mask) << 2; - } + for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) { + if (man_id == 0x1f) { + findex = faddr << 2; + fdata = findex & sec_mask; + } else { + findex = faddr; + fdata = (findex & sec_mask) << 2; + } - /* Are we at the beginning of a sector? */ - if ((findex & rest_addr) == 0) { - /* - * Do sector unprotect at 4K boundry for Atmel - * part. - */ - if (man_id == 0x1f) - qla24xx_write_flash_dword(ha, - flash_conf_to_access_addr(0x0339), - (fdata & 0xff00) | ((fdata << 16) & - 0xff0000) | ((fdata >> 16) & 0xff)); - ret = qla24xx_write_flash_dword(ha, conf_addr, - (fdata & 0xff00) |((fdata << 16) & + /* Are we at the beginning of a sector? */ + if ((findex & rest_addr) == 0) { + /* Do sector unprotect at 4K boundry for Atmel part. */ + if (man_id == 0x1f) + qla24xx_write_flash_dword(ha, + flash_conf_to_access_addr(0x0339), + (fdata & 0xff00) | ((fdata << 16) & 0xff0000) | ((fdata >> 16) & 0xff)); - if (ret != QLA_SUCCESS) { - DEBUG9(printk("%s(%ld) Unable to flash " - "sector: address=%x.\n", __func__, - ha->host_no, faddr)); - break; - } + ret = qla24xx_write_flash_dword(ha, conf_addr, + (fdata & 0xff00) |((fdata << 16) & + 0xff0000) | ((fdata >> 16) & 0xff)); + if (ret != QLA_SUCCESS) { + DEBUG9(printk("%s(%ld) Unable to flash " + "sector: address=%x.\n", __func__, + ha->host_no, faddr)); + break; } - ret = qla24xx_write_flash_dword(ha, + } + + /* Go with burst-write. */ + if (optrom && (liter + OPTROM_BURST_DWORDS) < dwords) { + /* Copy data to DMA'ble buffer. */ + for (miter = 0, s = optrom, d = dwptr; + miter < OPTROM_BURST_DWORDS; miter++, s++, d++) + *s = cpu_to_le32(*d); + + ret = qla2x00_load_ram(ha, optrom_dma, flash_data_to_access_addr(faddr), - cpu_to_le32(*dwptr)); + OPTROM_BURST_DWORDS); if (ret != QLA_SUCCESS) { - DEBUG9(printk("%s(%ld) Unable to program flash " - "address=%x data=%x.\n", __func__, - ha->host_no, faddr, *dwptr)); - break; + qla_printk(KERN_WARNING, ha, + "Unable to burst-write optrom segment " + "(%x/%x/%llx).\n", ret, + flash_data_to_access_addr(faddr), + optrom_dma); + qla_printk(KERN_WARNING, ha, + "Reverting to slow-write.\n"); + + dma_free_coherent(&ha->pdev->dev, + OPTROM_BURST_SIZE, optrom, optrom_dma); + optrom = NULL; + } else { + liter += OPTROM_BURST_DWORDS - 1; + faddr += OPTROM_BURST_DWORDS - 1; + dwptr += OPTROM_BURST_DWORDS - 1; + continue; } + } - /* Do sector protect at 4K boundry for Atmel part. */ - if (man_id == 0x1f && - ((faddr & sec_end_mask) == 0x3ff)) - qla24xx_write_flash_dword(ha, - flash_conf_to_access_addr(0x0336), - (fdata & 0xff00) | ((fdata << 16) & - 0xff0000) | ((fdata >> 16) & 0xff)); + ret = qla24xx_write_flash_dword(ha, + flash_data_to_access_addr(faddr), cpu_to_le32(*dwptr)); + if (ret != QLA_SUCCESS) { + DEBUG9(printk("%s(%ld) Unable to program flash " + "address=%x data=%x.\n", __func__, + ha->host_no, faddr, *dwptr)); + break; } - } while (0); + + /* Do sector protect at 4K boundry for Atmel part. */ + if (man_id == 0x1f && + ((faddr & rest_addr) == rest_addr)) + qla24xx_write_flash_dword(ha, + flash_conf_to_access_addr(0x0336), + (fdata & 0xff00) | ((fdata << 16) & + 0xff0000) | ((fdata >> 16) & 0xff)); + } /* Enable flash write-protection. */ qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0x9c); @@ -651,6 +697,10 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE); RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ + if (optrom) + dma_free_coherent(&ha->pdev->dev, + OPTROM_BURST_SIZE, optrom, optrom_dma); + return ret; } @@ -1728,7 +1778,6 @@ qla24xx_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf, { /* Suspend HBA. */ scsi_block_requests(ha->host); - ha->isp_ops->disable_intrs(ha); set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags); /* Go with read. */ @@ -1736,7 +1785,6 @@ qla24xx_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf, /* Resume HBA. */ clear_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags); - ha->isp_ops->enable_intrs(ha); scsi_unblock_requests(ha->host); return buf; @@ -1750,7 +1798,6 @@ qla24xx_write_optrom_data(struct scsi_qla_host *ha, uint8_t *buf, /* Suspend HBA. */ scsi_block_requests(ha->host); - ha->isp_ops->disable_intrs(ha); set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags); /* Go with write. */ @@ -1767,6 +1814,70 @@ qla24xx_write_optrom_data(struct scsi_qla_host *ha, uint8_t *buf, return rval; } +uint8_t * +qla25xx_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf, + uint32_t offset, uint32_t length) +{ + int rval; + dma_addr_t optrom_dma; + void *optrom; + uint8_t *pbuf; + uint32_t faddr, left, burst; + + if (offset & 0xfff) + goto slow_read; + if (length < OPTROM_BURST_SIZE) + goto slow_read; + + optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, + &optrom_dma, GFP_KERNEL); + if (!optrom) { + qla_printk(KERN_DEBUG, ha, + "Unable to allocate memory for optrom burst read " + "(%x KB).\n", OPTROM_BURST_SIZE / 1024); + + goto slow_read; + } + + pbuf = buf; + faddr = offset >> 2; + left = length >> 2; + burst = OPTROM_BURST_DWORDS; + while (left != 0) { + if (burst > left) + burst = left; + + rval = qla2x00_dump_ram(ha, optrom_dma, + flash_data_to_access_addr(faddr), burst); + if (rval) { + qla_printk(KERN_WARNING, ha, + "Unable to burst-read optrom segment " + "(%x/%x/%llx).\n", rval, + flash_data_to_access_addr(faddr), optrom_dma); + qla_printk(KERN_WARNING, ha, + "Reverting to slow-read.\n"); + + dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, + optrom, optrom_dma); + goto slow_read; + } + + memcpy(pbuf, optrom, burst * 4); + + left -= burst; + faddr += burst; + pbuf += burst * 4; + } + + dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, optrom, + optrom_dma); + + return buf; + +slow_read: + return qla24xx_read_optrom_data(ha, buf, offset, length); +} + /** * qla2x00_get_fcode_version() - Determine an FCODE image's version. * @ha: HA context diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 18095b9b76f4..2d551a3006f6 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.02.00-k3" +#define QLA2XXX_VERSION "8.02.00-k4" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 2 diff --git a/drivers/scsi/qlogicfas.c b/drivers/scsi/qlogicfas.c index 94baca840efe..1e874f1fb5c6 100644 --- a/drivers/scsi/qlogicfas.c +++ b/drivers/scsi/qlogicfas.c @@ -166,6 +166,7 @@ static int qlogicfas_release(struct Scsi_Host *shost) { struct qlogicfas408_priv *priv = get_priv_by_host(shost); + scsi_remove_host(shost); if (shost->irq) { qlogicfas408_disable_ints(priv); free_irq(shost->irq, shost); @@ -174,7 +175,6 @@ static int qlogicfas_release(struct Scsi_Host *shost) free_dma(shost->dma_channel); if (shost->io_port && shost->n_io_port) release_region(shost->io_port, shost->n_io_port); - scsi_remove_host(shost); scsi_host_put(shost); return 0; diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index 594887205b0f..e93f80316a19 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -310,8 +310,6 @@ static inline void qlogicpti_set_hostdev_defaults(struct qlogicpti *qpti) } qpti->dev_param[i].device_enable = 1; } - /* this is very important to set! */ - qpti->sbits = 1 << qpti->scsi_id; } static int qlogicpti_reset_hardware(struct Scsi_Host *host) @@ -951,153 +949,35 @@ static inline void update_can_queue(struct Scsi_Host *host, u_int in_ptr, u_int host->sg_tablesize = QLOGICPTI_MAX_SG(num_free); } -static unsigned int scsi_rbuf_get(struct scsi_cmnd *cmd, unsigned char **buf_out) +static int qlogicpti_slave_configure(struct scsi_device *sdev) { - unsigned char *buf; - unsigned int buflen; - - if (cmd->use_sg) { - struct scatterlist *sg; + struct qlogicpti *qpti = shost_priv(sdev->host); + int tgt = sdev->id; + u_short param[6]; - sg = (struct scatterlist *) cmd->request_buffer; - buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset; - buflen = sg->length; + /* tags handled in midlayer */ + /* enable sync mode? */ + if (sdev->sdtr) { + qpti->dev_param[tgt].device_flags |= 0x10; } else { - buf = cmd->request_buffer; - buflen = cmd->request_bufflen; + qpti->dev_param[tgt].synchronous_offset = 0; + qpti->dev_param[tgt].synchronous_period = 0; } - - *buf_out = buf; - return buflen; -} - -static void scsi_rbuf_put(struct scsi_cmnd *cmd, unsigned char *buf) -{ - if (cmd->use_sg) { - struct scatterlist *sg; - - sg = (struct scatterlist *) cmd->request_buffer; - kunmap_atomic(buf - sg->offset, KM_IRQ0); - } -} - -/* - * Until we scan the entire bus with inquiries, go throught this fella... - */ -static void ourdone(struct scsi_cmnd *Cmnd) -{ - struct qlogicpti *qpti = (struct qlogicpti *) Cmnd->device->host->hostdata; - int tgt = Cmnd->device->id; - void (*done) (struct scsi_cmnd *); - - /* This grot added by DaveM, blame him for ugliness. - * The issue is that in the 2.3.x driver we use the - * host_scribble portion of the scsi command as a - * completion linked list at interrupt service time, - * so we have to store the done function pointer elsewhere. - */ - done = (void (*)(struct scsi_cmnd *)) - (((unsigned long) Cmnd->SCp.Message) -#ifdef __sparc_v9__ - | ((unsigned long) Cmnd->SCp.Status << 32UL) -#endif - ); - - if ((qpti->sbits & (1 << tgt)) == 0) { - int ok = host_byte(Cmnd->result) == DID_OK; - if (Cmnd->cmnd[0] == 0x12 && ok) { - unsigned char *iqd; - unsigned int iqd_len; - - iqd_len = scsi_rbuf_get(Cmnd, &iqd); - - /* tags handled in midlayer */ - /* enable sync mode? */ - if (iqd[7] & 0x10) { - qpti->dev_param[tgt].device_flags |= 0x10; - } else { - qpti->dev_param[tgt].synchronous_offset = 0; - qpti->dev_param[tgt].synchronous_period = 0; - } - /* are we wide capable? */ - if (iqd[7] & 0x20) { - qpti->dev_param[tgt].device_flags |= 0x20; - } - - scsi_rbuf_put(Cmnd, iqd); - - qpti->sbits |= (1 << tgt); - } else if (!ok) { - qpti->sbits |= (1 << tgt); - } - } - done(Cmnd); -} - -static int qlogicpti_queuecommand(struct scsi_cmnd *Cmnd, void (*done)(struct scsi_cmnd *)); - -static int qlogicpti_queuecommand_slow(struct scsi_cmnd *Cmnd, - void (*done)(struct scsi_cmnd *)) -{ - struct qlogicpti *qpti = (struct qlogicpti *) Cmnd->device->host->hostdata; - - /* - * done checking this host adapter? - * If not, then rewrite the command - * to finish through ourdone so we - * can peek at Inquiry data results. - */ - if (qpti->sbits && qpti->sbits != 0xffff) { - /* See above about in ourdone this ugliness... */ - Cmnd->SCp.Message = ((unsigned long)done) & 0xffffffff; -#ifdef CONFIG_SPARC64 - Cmnd->SCp.Status = ((unsigned long)done >> 32UL) & 0xffffffff; -#endif - return qlogicpti_queuecommand(Cmnd, ourdone); - } - - /* - * We've peeked at all targets for this bus- time - * to set parameters for devices for real now. - */ - if (qpti->sbits == 0xffff) { - int i; - for(i = 0; i < MAX_TARGETS; i++) { - u_short param[6]; - param[0] = MBOX_SET_TARGET_PARAMS; - param[1] = (i << 8); - param[2] = (qpti->dev_param[i].device_flags << 8); - if (qpti->dev_param[i].device_flags & 0x10) { - param[3] = (qpti->dev_param[i].synchronous_offset << 8) | - qpti->dev_param[i].synchronous_period; - } else { - param[3] = 0; - } - (void) qlogicpti_mbox_command(qpti, param, 0); - } - /* - * set to zero so any traverse through ourdone - * doesn't start the whole process again, - */ - qpti->sbits = 0; - } - - /* check to see if we're done with all adapters... */ - for (qpti = qptichain; qpti != NULL; qpti = qpti->next) { - if (qpti->sbits) { - break; - } + /* are we wide capable? */ + if (sdev->wdtr) + qpti->dev_param[tgt].device_flags |= 0x20; + + param[0] = MBOX_SET_TARGET_PARAMS; + param[1] = (tgt << 8); + param[2] = (qpti->dev_param[tgt].device_flags << 8); + if (qpti->dev_param[tgt].device_flags & 0x10) { + param[3] = (qpti->dev_param[tgt].synchronous_offset << 8) | + qpti->dev_param[tgt].synchronous_period; + } else { + param[3] = 0; } - - /* - * if we hit the end of the chain w/o finding adapters still - * capability-configuring, then we're done with all adapters - * and can rock on.. - */ - if (qpti == NULL) - Cmnd->device->host->hostt->queuecommand = qlogicpti_queuecommand; - - return qlogicpti_queuecommand(Cmnd, done); + qlogicpti_mbox_command(qpti, param, 0); + return 0; } /* @@ -1390,7 +1270,8 @@ static struct scsi_host_template qpti_template = { .module = THIS_MODULE, .name = "qlogicpti", .info = qlogicpti_info, - .queuecommand = qlogicpti_queuecommand_slow, + .queuecommand = qlogicpti_queuecommand, + .slave_configure = qlogicpti_slave_configure, .eh_abort_handler = qlogicpti_abort, .eh_bus_reset_handler = qlogicpti_reset, .can_queue = QLOGICPTI_REQ_QUEUE_LEN, diff --git a/drivers/scsi/qlogicpti.h b/drivers/scsi/qlogicpti.h index 6cd1c0771d29..ef6da2df584b 100644 --- a/drivers/scsi/qlogicpti.h +++ b/drivers/scsi/qlogicpti.h @@ -380,8 +380,7 @@ struct qlogicpti { unsigned char swsreg; unsigned int gotirq : 1, /* this instance got an irq */ - is_pti : 1, /* Non-zero if this is a PTI board. */ - sbits : 16; /* syncmode known bits */ + is_pti : 1; /* Non-zero if this is a PTI board. */ }; /* How to twiddle them bits... */ diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index a5de1a829a76..192948822455 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -59,6 +59,7 @@ #include <scsi/scsi_cmnd.h> #include <scsi/scsi_dbg.h> #include <scsi/scsi_device.h> +#include <scsi/scsi_driver.h> #include <scsi/scsi_eh.h> #include <scsi/scsi_host.h> #include <scsi/scsi_tcq.h> @@ -367,9 +368,8 @@ void scsi_log_send(struct scsi_cmnd *cmd) scsi_print_command(cmd); if (level > 3) { printk(KERN_INFO "buffer = 0x%p, bufflen = %d," - " done = 0x%p, queuecommand 0x%p\n", + " queuecommand 0x%p\n", scsi_sglist(cmd), scsi_bufflen(cmd), - cmd->done, cmd->device->host->hostt->queuecommand); } @@ -442,7 +442,7 @@ void scsi_log_completion(struct scsi_cmnd *cmd, int disposition) #endif /* - * Assign a serial number and pid to the request for error recovery + * Assign a serial number to the request for error recovery * and debugging purposes. Protected by the Host_Lock of host. */ static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd *cmd) @@ -450,10 +450,6 @@ static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd cmd->serial_number = host->cmd_serial_number++; if (cmd->serial_number == 0) cmd->serial_number = host->cmd_serial_number++; - - cmd->pid = host->cmd_pid++; - if (cmd->pid == 0) - cmd->pid = host->cmd_pid++; } /* @@ -658,6 +654,12 @@ void __scsi_done(struct scsi_cmnd *cmd) blk_complete_request(rq); } +/* Move this to a header if it becomes more generally useful */ +static struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd) +{ + return *(struct scsi_driver **)cmd->request->rq_disk->private_data; +} + /* * Function: scsi_finish_command * @@ -669,6 +671,8 @@ void scsi_finish_command(struct scsi_cmnd *cmd) { struct scsi_device *sdev = cmd->device; struct Scsi_Host *shost = sdev->host; + struct scsi_driver *drv; + unsigned int good_bytes; scsi_device_unbusy(sdev); @@ -694,7 +698,13 @@ void scsi_finish_command(struct scsi_cmnd *cmd) "Notifying upper driver of completion " "(result %x)\n", cmd->result)); - cmd->done(cmd); + good_bytes = cmd->request_bufflen; + if (cmd->request->cmd_type != REQ_TYPE_BLOCK_PC) { + drv = scsi_cmd_to_driver(cmd); + if (drv->done) + good_bytes = drv->done(cmd); + } + scsi_io_completion(cmd, good_bytes); } EXPORT_SYMBOL(scsi_finish_command); diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index e2ea739e33df..348cc5a6e3cd 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -214,6 +214,7 @@ static struct { {"PIONEER", "CD-ROM DRM-604X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, {"PIONEER", "CD-ROM DRM-624X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, {"Promise", "", NULL, BLIST_SPARSELUN}, + {"QUANTUM", "XP34301", "1071", BLIST_NOTQ}, {"REGAL", "CDC-4X", NULL, BLIST_MAX5LUN | BLIST_SINGLELUN}, {"SanDisk", "ImageMate CF-SD1", NULL, BLIST_FORCELUN}, {"SEAGATE", "ST34555N", "0930", BLIST_NOTQ}, /* Chokes on tagged INQUIRY */ diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 8a525abda30f..d29f8464b74f 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -37,6 +37,7 @@ #include "scsi_priv.h" #include "scsi_logging.h" +#include "scsi_transport_api.h" #define SENSE_TIMEOUT (10*HZ) @@ -589,39 +590,23 @@ static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd) } /** - * scsi_send_eh_cmnd - submit a scsi command as part of error recory + * scsi_eh_prep_cmnd - Save a scsi command info as part of error recory * @scmd: SCSI command structure to hijack - * @cmnd: CDB to send + * @ses: structure to save restore information + * @cmnd: CDB to send. Can be NULL if no new cmnd is needed * @cmnd_size: size in bytes of @cmnd - * @timeout: timeout for this request - * @copy_sense: request sense data if set to 1 - * - * This function is used to send a scsi command down to a target device - * as part of the error recovery process. If @copy_sense is 0 the command - * sent must be one that does not transfer any data. If @copy_sense is 1 - * the command must be REQUEST_SENSE and this functions copies out the - * sense buffer it got into @scmd->sense_buffer. + * @sense_bytes: size of sense data to copy. or 0 (if != 0 @cmnd is ignored) * - * Return value: - * SUCCESS or FAILED or NEEDS_RETRY + * This function is used to save a scsi command information before re-execution + * as part of the error recovery process. If @sense_bytes is 0 the command + * sent must be one that does not transfer any data. If @sense_bytes != 0 + * @cmnd is ignored and this functions sets up a REQUEST_SENSE command + * and cmnd buffers to read @sense_bytes into @scmd->sense_buffer. **/ -static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd, - int cmnd_size, int timeout, int copy_sense) +void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses, + unsigned char *cmnd, int cmnd_size, unsigned sense_bytes) { struct scsi_device *sdev = scmd->device; - struct Scsi_Host *shost = sdev->host; - int old_result = scmd->result; - DECLARE_COMPLETION_ONSTACK(done); - unsigned long timeleft; - unsigned long flags; - struct scatterlist sgl; - unsigned char old_cmnd[MAX_COMMAND_SIZE]; - enum dma_data_direction old_data_direction; - unsigned short old_use_sg; - unsigned char old_cmd_len; - unsigned old_bufflen; - void *old_buffer; - int rtn; /* * We need saved copies of a number of fields - this is because @@ -630,35 +615,42 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd, * we will need to restore these values prior to running the actual * command. */ - old_buffer = scmd->request_buffer; - old_bufflen = scmd->request_bufflen; - memcpy(old_cmnd, scmd->cmnd, sizeof(scmd->cmnd)); - old_data_direction = scmd->sc_data_direction; - old_cmd_len = scmd->cmd_len; - old_use_sg = scmd->use_sg; - - memset(scmd->cmnd, 0, sizeof(scmd->cmnd)); - memcpy(scmd->cmnd, cmnd, cmnd_size); - - if (copy_sense) { - sg_init_one(&sgl, scmd->sense_buffer, - sizeof(scmd->sense_buffer)); - + ses->cmd_len = scmd->cmd_len; + memcpy(ses->cmnd, scmd->cmnd, sizeof(scmd->cmnd)); + ses->data_direction = scmd->sc_data_direction; + ses->bufflen = scmd->request_bufflen; + ses->buffer = scmd->request_buffer; + ses->use_sg = scmd->use_sg; + ses->resid = scmd->resid; + ses->result = scmd->result; + + if (sense_bytes) { + scmd->request_bufflen = min_t(unsigned, + sizeof(scmd->sense_buffer), sense_bytes); + sg_init_one(&ses->sense_sgl, scmd->sense_buffer, + scmd->request_bufflen); + scmd->request_buffer = &ses->sense_sgl; scmd->sc_data_direction = DMA_FROM_DEVICE; - scmd->request_bufflen = sgl.length; - scmd->request_buffer = &sgl; scmd->use_sg = 1; + memset(scmd->cmnd, 0, sizeof(scmd->cmnd)); + scmd->cmnd[0] = REQUEST_SENSE; + scmd->cmnd[4] = scmd->request_bufflen; + scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]); } else { scmd->request_buffer = NULL; scmd->request_bufflen = 0; scmd->sc_data_direction = DMA_NONE; scmd->use_sg = 0; + if (cmnd) { + memset(scmd->cmnd, 0, sizeof(scmd->cmnd)); + memcpy(scmd->cmnd, cmnd, cmnd_size); + scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]); + } } scmd->underflow = 0; - scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]); - if (sdev->scsi_level <= SCSI_2) + if (sdev->scsi_level <= SCSI_2 && sdev->scsi_level != SCSI_UNKNOWN) scmd->cmnd[1] = (scmd->cmnd[1] & 0x1f) | (sdev->lun << 5 & 0xe0); @@ -667,7 +659,58 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd, * untransferred sense data should be interpreted as being zero. */ memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer)); +} +EXPORT_SYMBOL(scsi_eh_prep_cmnd); + +/** + * scsi_eh_restore_cmnd - Restore a scsi command info as part of error recory + * @scmd: SCSI command structure to restore + * @ses: saved information from a coresponding call to scsi_prep_eh_cmnd + * + * Undo any damage done by above scsi_prep_eh_cmnd(). + **/ +void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses) +{ + /* + * Restore original data + */ + scmd->cmd_len = ses->cmd_len; + memcpy(scmd->cmnd, ses->cmnd, sizeof(scmd->cmnd)); + scmd->sc_data_direction = ses->data_direction; + scmd->request_bufflen = ses->bufflen; + scmd->request_buffer = ses->buffer; + scmd->use_sg = ses->use_sg; + scmd->resid = ses->resid; + scmd->result = ses->result; +} +EXPORT_SYMBOL(scsi_eh_restore_cmnd); +/** + * scsi_send_eh_cmnd - submit a scsi command as part of error recory + * @scmd: SCSI command structure to hijack + * @cmnd: CDB to send + * @cmnd_size: size in bytes of @cmnd + * @timeout: timeout for this request + * @sense_bytes: size of sense data to copy or 0 + * + * This function is used to send a scsi command down to a target device + * as part of the error recovery process. See also scsi_eh_prep_cmnd() above. + * + * Return value: + * SUCCESS or FAILED or NEEDS_RETRY + **/ +static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd, + int cmnd_size, int timeout, unsigned sense_bytes) +{ + struct scsi_device *sdev = scmd->device; + struct Scsi_Host *shost = sdev->host; + DECLARE_COMPLETION_ONSTACK(done); + unsigned long timeleft; + unsigned long flags; + struct scsi_eh_save ses; + int rtn; + + scsi_eh_prep_cmnd(scmd, &ses, cmnd, cmnd_size, sense_bytes); shost->eh_action = &done; spin_lock_irqsave(shost->host_lock, flags); @@ -711,17 +754,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd, rtn = FAILED; } - - /* - * Restore original data - */ - scmd->request_buffer = old_buffer; - scmd->request_bufflen = old_bufflen; - memcpy(scmd->cmnd, old_cmnd, sizeof(scmd->cmnd)); - scmd->sc_data_direction = old_data_direction; - scmd->cmd_len = old_cmd_len; - scmd->use_sg = old_use_sg; - scmd->result = old_result; + scsi_eh_restore_cmnd(scmd, &ses); return rtn; } @@ -736,10 +769,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd, **/ static int scsi_request_sense(struct scsi_cmnd *scmd) { - static unsigned char generic_sense[6] = - {REQUEST_SENSE, 0, 0, 0, 252, 0}; - - return scsi_send_eh_cmnd(scmd, generic_sense, 6, SENSE_TIMEOUT, 1); + return scsi_send_eh_cmnd(scmd, NULL, 0, SENSE_TIMEOUT, ~0); } /** @@ -1136,9 +1166,8 @@ static void scsi_eh_offline_sdevs(struct list_head *work_q, struct scsi_cmnd *scmd, *next; list_for_each_entry_safe(scmd, next, work_q, eh_entry) { - sdev_printk(KERN_INFO, scmd->device, - "scsi: Device offlined - not" - " ready after error recovery\n"); + sdev_printk(KERN_INFO, scmd->device, "Device offlined - " + "not ready after error recovery\n"); scsi_device_set_state(scmd->device, SDEV_OFFLINE); if (scmd->eh_eflags & SCSI_EH_CANCEL_CMD) { /* @@ -1671,7 +1700,6 @@ scsi_reset_provider(struct scsi_device *dev, int flag) memset(&scmd->cmnd, '\0', sizeof(scmd->cmnd)); scmd->scsi_done = scsi_reset_provider_done_command; - scmd->done = NULL; scmd->request_buffer = NULL; scmd->request_bufflen = 0; @@ -1681,12 +1709,6 @@ scsi_reset_provider(struct scsi_device *dev, int flag) init_timer(&scmd->eh_timeout); - /* - * Sometimes the command can get back into the timer chain, - * so use the pid as an identifier. - */ - scmd->pid = 0; - spin_lock_irqsave(shost->host_lock, flags); shost->tmf_in_progress = 1; spin_unlock_irqrestore(shost->host_lock, flags); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 604f4d717933..207f1aa08869 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -288,7 +288,7 @@ static int scsi_req_map_sg(struct request *rq, struct scatterlist *sgl, { struct request_queue *q = rq->q; int nr_pages = (bufflen + sgl[0].offset + PAGE_SIZE - 1) >> PAGE_SHIFT; - unsigned int data_len = 0, len, bytes, off; + unsigned int data_len = bufflen, len, bytes, off; struct page *page; struct bio *bio = NULL; int i, err, nr_vecs = 0; @@ -297,10 +297,15 @@ static int scsi_req_map_sg(struct request *rq, struct scatterlist *sgl, page = sgl[i].page; off = sgl[i].offset; len = sgl[i].length; - data_len += len; - while (len > 0) { + while (len > 0 && data_len > 0) { + /* + * sg sends a scatterlist that is larger than + * the data_len it wants transferred for certain + * IO sizes + */ bytes = min_t(unsigned int, len, PAGE_SIZE - off); + bytes = min(bytes, data_len); if (!bio) { nr_vecs = min_t(int, BIO_MAX_PAGES, nr_pages); @@ -332,12 +337,13 @@ static int scsi_req_map_sg(struct request *rq, struct scatterlist *sgl, page++; len -= bytes; + data_len -=bytes; off = 0; } } rq->buffer = rq->data = NULL; - rq->data_len = data_len; + rq->data_len = bufflen; return 0; free_bios: @@ -430,6 +436,7 @@ EXPORT_SYMBOL_GPL(scsi_execute_async); static void scsi_init_cmd_errh(struct scsi_cmnd *cmd) { cmd->serial_number = 0; + cmd->resid = 0; memset(cmd->sense_buffer, 0, sizeof cmd->sense_buffer); if (cmd->cmd_len == 0) cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]); @@ -924,11 +931,11 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) break; } } - if (!(req->cmd_flags & REQ_QUIET)) { - scmd_printk(KERN_INFO, cmd, - "Device not ready: "); - scsi_print_sense_hdr("", &sshdr); - } + if (!(req->cmd_flags & REQ_QUIET)) + scsi_cmd_print_sense_hdr(cmd, + "Device not ready", + &sshdr); + scsi_end_request(cmd, 0, this_count, 1); return; case VOLUME_OVERFLOW: @@ -962,7 +969,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) } scsi_end_request(cmd, 0, this_count, !result); } -EXPORT_SYMBOL(scsi_io_completion); /* * Function: scsi_init_io() @@ -1019,9 +1025,6 @@ static int scsi_init_io(struct scsi_cmnd *cmd) printk(KERN_ERR "req nr_sec %lu, cur_nr_sec %u\n", req->nr_sectors, req->current_nr_sectors); - /* release the command and kill it */ - scsi_release_buffers(cmd); - scsi_put_command(cmd); return BLKPREP_KILL; } @@ -1046,21 +1049,13 @@ static struct scsi_cmnd *scsi_get_cmd_from_req(struct scsi_device *sdev, return cmd; } -static void scsi_blk_pc_done(struct scsi_cmnd *cmd) -{ - BUG_ON(!blk_pc_request(cmd->request)); - /* - * This will complete the whole command with uptodate=1 so - * as far as the block layer is concerned the command completed - * successfully. Since this is a REQ_BLOCK_PC command the - * caller should check the request's errors value - */ - scsi_io_completion(cmd, cmd->request_bufflen); -} - -static int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req) +int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req) { struct scsi_cmnd *cmd; + int ret = scsi_prep_state_check(sdev, req); + + if (ret != BLKPREP_OK) + return ret; cmd = scsi_get_cmd_from_req(sdev, req); if (unlikely(!cmd)) @@ -1103,21 +1098,22 @@ static int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req) cmd->transfersize = req->data_len; cmd->allowed = req->retries; cmd->timeout_per_command = req->timeout; - cmd->done = scsi_blk_pc_done; return BLKPREP_OK; } +EXPORT_SYMBOL(scsi_setup_blk_pc_cmnd); /* * Setup a REQ_TYPE_FS command. These are simple read/write request * from filesystems that still need to be translated to SCSI CDBs from * the ULD. */ -static int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req) +int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req) { struct scsi_cmnd *cmd; - struct scsi_driver *drv; - int ret; + int ret = scsi_prep_state_check(sdev, req); + if (ret != BLKPREP_OK) + return ret; /* * Filesystem requests must transfer data. */ @@ -1127,26 +1123,12 @@ static int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req) if (unlikely(!cmd)) return BLKPREP_DEFER; - ret = scsi_init_io(cmd); - if (unlikely(ret)) - return ret; - - /* - * Initialize the actual SCSI command for this request. - */ - drv = *(struct scsi_driver **)req->rq_disk->private_data; - if (unlikely(!drv->init_command(cmd))) { - scsi_release_buffers(cmd); - scsi_put_command(cmd); - return BLKPREP_KILL; - } - - return BLKPREP_OK; + return scsi_init_io(cmd); } +EXPORT_SYMBOL(scsi_setup_fs_cmnd); -static int scsi_prep_fn(struct request_queue *q, struct request *req) +int scsi_prep_state_check(struct scsi_device *sdev, struct request *req) { - struct scsi_device *sdev = q->queuedata; int ret = BLKPREP_OK; /* @@ -1192,35 +1174,25 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req) ret = BLKPREP_KILL; break; } - - if (ret != BLKPREP_OK) - goto out; } + return ret; +} +EXPORT_SYMBOL(scsi_prep_state_check); - switch (req->cmd_type) { - case REQ_TYPE_BLOCK_PC: - ret = scsi_setup_blk_pc_cmnd(sdev, req); - break; - case REQ_TYPE_FS: - ret = scsi_setup_fs_cmnd(sdev, req); - break; - default: - /* - * All other command types are not supported. - * - * Note that these days the SCSI subsystem does not use - * REQ_TYPE_SPECIAL requests anymore. These are only used - * (directly or via blk_insert_request) by non-SCSI drivers. - */ - blk_dump_rq_flags(req, "SCSI bad req"); - ret = BLKPREP_KILL; - break; - } +int scsi_prep_return(struct request_queue *q, struct request *req, int ret) +{ + struct scsi_device *sdev = q->queuedata; - out: switch (ret) { case BLKPREP_KILL: req->errors = DID_NO_CONNECT << 16; + /* release the command and kill it */ + if (req->special) { + struct scsi_cmnd *cmd = req->special; + scsi_release_buffers(cmd); + scsi_put_command(cmd); + req->special = NULL; + } break; case BLKPREP_DEFER: /* @@ -1237,6 +1209,17 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req) return ret; } +EXPORT_SYMBOL(scsi_prep_return); + +static int scsi_prep_fn(struct request_queue *q, struct request *req) +{ + struct scsi_device *sdev = q->queuedata; + int ret = BLKPREP_KILL; + + if (req->cmd_type == REQ_TYPE_BLOCK_PC) + ret = scsi_setup_blk_pc_cmnd(sdev, req); + return scsi_prep_return(q, req, ret); +} /* * scsi_dev_queue_ready: if we can send requests to sdev, return 1 else diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index ee8efe849bf4..eff005951895 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -68,6 +68,7 @@ extern int scsi_maybe_unblock_host(struct scsi_device *sdev); extern void scsi_device_unbusy(struct scsi_device *sdev); extern int scsi_queue_insert(struct scsi_cmnd *cmd, int reason); extern void scsi_next_command(struct scsi_cmnd *cmd); +extern void scsi_io_completion(struct scsi_cmnd *, unsigned int); extern void scsi_run_host_queues(struct Scsi_Host *shost); extern struct request_queue *scsi_alloc_queue(struct scsi_device *sdev); extern void scsi_free_queue(struct request_queue *q); diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index a86e62f4b3ba..b53c5f67e372 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -85,7 +85,7 @@ static unsigned int max_scsi_luns = MAX_SCSI_LUNS; static unsigned int max_scsi_luns = 1; #endif -module_param_named(max_luns, max_scsi_luns, int, S_IRUGO|S_IWUSR); +module_param_named(max_luns, max_scsi_luns, uint, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(max_luns, "last scsi LUN (should be between 1 and 2^32-1)"); @@ -109,18 +109,19 @@ MODULE_PARM_DESC(scan, "sync, async or none"); */ static unsigned int max_scsi_report_luns = 511; -module_param_named(max_report_luns, max_scsi_report_luns, int, S_IRUGO|S_IWUSR); +module_param_named(max_report_luns, max_scsi_report_luns, uint, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(max_report_luns, "REPORT LUNS maximum number of LUNS received (should be" " between 1 and 16384)"); static unsigned int scsi_inq_timeout = SCSI_TIMEOUT/HZ+3; -module_param_named(inq_timeout, scsi_inq_timeout, int, S_IRUGO|S_IWUSR); +module_param_named(inq_timeout, scsi_inq_timeout, uint, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(inq_timeout, "Timeout (in seconds) waiting for devices to answer INQUIRY." " Default is 5. Some non-compliant devices need more."); +/* This lock protects only this list */ static DEFINE_SPINLOCK(async_scan_lock); static LIST_HEAD(scanning_hosts); @@ -1466,14 +1467,14 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel, if (strncmp(scsi_scan_type, "none", 4) == 0) return ERR_PTR(-ENODEV); - if (!shost->async_scan) - scsi_complete_async_scans(); - starget = scsi_alloc_target(parent, channel, id); if (!starget) return ERR_PTR(-ENOMEM); mutex_lock(&shost->scan_mutex); + if (!shost->async_scan) + scsi_complete_async_scans(); + if (scsi_host_scan_allowed(shost)) scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata); mutex_unlock(&shost->scan_mutex); @@ -1586,10 +1587,10 @@ void scsi_scan_target(struct device *parent, unsigned int channel, if (strncmp(scsi_scan_type, "none", 4) == 0) return; + mutex_lock(&shost->scan_mutex); if (!shost->async_scan) scsi_complete_async_scans(); - mutex_lock(&shost->scan_mutex); if (scsi_host_scan_allowed(shost)) __scsi_scan_target(parent, channel, id, lun, rescan); mutex_unlock(&shost->scan_mutex); @@ -1634,15 +1635,15 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel, "%s: <%u:%u:%u>\n", __FUNCTION__, channel, id, lun)); - if (!shost->async_scan) - scsi_complete_async_scans(); - if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) || ((id != SCAN_WILD_CARD) && (id >= shost->max_id)) || ((lun != SCAN_WILD_CARD) && (lun > shost->max_lun))) return -EINVAL; mutex_lock(&shost->scan_mutex); + if (!shost->async_scan) + scsi_complete_async_scans(); + if (scsi_host_scan_allowed(shost)) { if (channel == SCAN_WILD_CARD) for (channel = 0; channel <= shost->max_channel; @@ -1661,7 +1662,8 @@ static void scsi_sysfs_add_devices(struct Scsi_Host *shost) { struct scsi_device *sdev; shost_for_each_device(sdev, shost) { - if (scsi_sysfs_add_sdev(sdev) != 0) + if (!scsi_host_scan_allowed(shost) || + scsi_sysfs_add_sdev(sdev) != 0) scsi_destroy_sdev(sdev); } } @@ -1679,6 +1681,7 @@ static void scsi_sysfs_add_devices(struct Scsi_Host *shost) static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost) { struct async_scan_data *data; + unsigned long flags; if (strncmp(scsi_scan_type, "sync", 4) == 0) return NULL; @@ -1698,8 +1701,13 @@ static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost) goto err; init_completion(&data->prev_finished); - spin_lock(&async_scan_lock); + mutex_lock(&shost->scan_mutex); + spin_lock_irqsave(shost->host_lock, flags); shost->async_scan = 1; + spin_unlock_irqrestore(shost->host_lock, flags); + mutex_unlock(&shost->scan_mutex); + + spin_lock(&async_scan_lock); if (list_empty(&scanning_hosts)) complete(&data->prev_finished); list_add_tail(&data->list, &scanning_hosts); @@ -1723,11 +1731,15 @@ static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost) static void scsi_finish_async_scan(struct async_scan_data *data) { struct Scsi_Host *shost; + unsigned long flags; if (!data) return; shost = data->shost; + + mutex_lock(&shost->scan_mutex); + if (!shost->async_scan) { printk("%s called twice for host %d", __FUNCTION__, shost->host_no); @@ -1739,8 +1751,13 @@ static void scsi_finish_async_scan(struct async_scan_data *data) scsi_sysfs_add_devices(shost); - spin_lock(&async_scan_lock); + spin_lock_irqsave(shost->host_lock, flags); shost->async_scan = 0; + spin_unlock_irqrestore(shost->host_lock, flags); + + mutex_unlock(&shost->scan_mutex); + + spin_lock(&async_scan_lock); list_del(&data->list); if (!list_empty(&scanning_hosts)) { struct async_scan_data *next = list_entry(scanning_hosts.next, @@ -1782,6 +1799,7 @@ static int do_scan_async(void *_data) **/ void scsi_scan_host(struct Scsi_Host *shost) { + struct task_struct *p; struct async_scan_data *data; if (strncmp(scsi_scan_type, "none", 4) == 0) @@ -1793,7 +1811,9 @@ void scsi_scan_host(struct Scsi_Host *shost) return; } - kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no); + p = kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no); + if (unlikely(IS_ERR(p))) + do_scan_async(data); } EXPORT_SYMBOL(scsi_scan_host); diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 34cdce6738a6..daed37df00b1 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -190,6 +190,46 @@ show_shost_state(struct class_device *class_dev, char *buf) static CLASS_DEVICE_ATTR(state, S_IRUGO | S_IWUSR, show_shost_state, store_shost_state); +static ssize_t +show_shost_mode(unsigned int mode, char *buf) +{ + ssize_t len = 0; + + if (mode & MODE_INITIATOR) + len = sprintf(buf, "%s", "Initiator"); + + if (mode & MODE_TARGET) + len += sprintf(buf + len, "%s%s", len ? ", " : "", "Target"); + + len += sprintf(buf + len, "\n"); + + return len; +} + +static ssize_t show_shost_supported_mode(struct class_device *class_dev, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(class_dev); + + if (shost->hostt->supported_mode == MODE_UNKNOWN) + return snprintf(buf, 20, "unknown\n"); + else + return show_shost_mode(shost->hostt->supported_mode, buf); +} + +static CLASS_DEVICE_ATTR(supported_mode, S_IRUGO | S_IWUSR, show_shost_supported_mode, NULL); + +static ssize_t show_shost_active_mode(struct class_device *class_dev, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(class_dev); + + if (shost->active_mode == MODE_UNKNOWN) + return snprintf(buf, 20, "unknown\n"); + else + return show_shost_mode(shost->active_mode, buf); +} + +static CLASS_DEVICE_ATTR(active_mode, S_IRUGO | S_IWUSR, show_shost_active_mode, NULL); + shost_rd_attr(unique_id, "%u\n"); shost_rd_attr(host_busy, "%hu\n"); shost_rd_attr(cmd_per_lun, "%hd\n"); @@ -208,6 +248,8 @@ static struct class_device_attribute *scsi_sysfs_shost_attrs[] = { &class_device_attr_proc_name, &class_device_attr_scan, &class_device_attr_state, + &class_device_attr_supported_mode, + &class_device_attr_active_mode, NULL }; @@ -277,16 +319,11 @@ static int scsi_bus_match(struct device *dev, struct device_driver *gendrv) return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0; } -static int scsi_bus_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int scsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { struct scsi_device *sdev = to_scsi_device(dev); - int i = 0; - int length = 0; - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type); - envp[i] = NULL; + add_uevent_var(env, "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type); return 0; } @@ -576,24 +613,31 @@ sdev_show_modalias(struct device *dev, struct device_attribute *attr, char *buf) static DEVICE_ATTR(modalias, S_IRUGO, sdev_show_modalias, NULL); /* Default template for device attributes. May NOT be modified */ -static struct device_attribute *scsi_sysfs_sdev_attrs[] = { - &dev_attr_device_blocked, - &dev_attr_queue_depth, - &dev_attr_queue_type, - &dev_attr_type, - &dev_attr_scsi_level, - &dev_attr_vendor, - &dev_attr_model, - &dev_attr_rev, - &dev_attr_rescan, - &dev_attr_delete, - &dev_attr_state, - &dev_attr_timeout, - &dev_attr_iocounterbits, - &dev_attr_iorequest_cnt, - &dev_attr_iodone_cnt, - &dev_attr_ioerr_cnt, - &dev_attr_modalias, +static struct attribute *scsi_sdev_attrs[] = { + &dev_attr_device_blocked.attr, + &dev_attr_type.attr, + &dev_attr_scsi_level.attr, + &dev_attr_vendor.attr, + &dev_attr_model.attr, + &dev_attr_rev.attr, + &dev_attr_rescan.attr, + &dev_attr_delete.attr, + &dev_attr_state.attr, + &dev_attr_timeout.attr, + &dev_attr_iocounterbits.attr, + &dev_attr_iorequest_cnt.attr, + &dev_attr_iodone_cnt.attr, + &dev_attr_ioerr_cnt.attr, + &dev_attr_modalias.attr, + NULL +}; + +static struct attribute_group scsi_sdev_attr_group = { + .attrs = scsi_sdev_attrs, +}; + +static struct attribute_group *scsi_sdev_attr_groups[] = { + &scsi_sdev_attr_group, NULL }; @@ -655,56 +699,6 @@ static struct device_attribute sdev_attr_queue_type_rw = __ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field, sdev_store_queue_type_rw); -static struct device_attribute *attr_changed_internally( - struct Scsi_Host *shost, - struct device_attribute * attr) -{ - if (!strcmp("queue_depth", attr->attr.name) - && shost->hostt->change_queue_depth) - return &sdev_attr_queue_depth_rw; - else if (!strcmp("queue_type", attr->attr.name) - && shost->hostt->change_queue_type) - return &sdev_attr_queue_type_rw; - return attr; -} - - -static struct device_attribute *attr_overridden( - struct device_attribute **attrs, - struct device_attribute *attr) -{ - int i; - - if (!attrs) - return NULL; - for (i = 0; attrs[i]; i++) - if (!strcmp(attrs[i]->attr.name, attr->attr.name)) - return attrs[i]; - return NULL; -} - -static int attr_add(struct device *dev, struct device_attribute *attr) -{ - struct device_attribute *base_attr; - - /* - * Spare the caller from having to copy things it's not interested in. - */ - base_attr = attr_overridden(scsi_sysfs_sdev_attrs, attr); - if (base_attr) { - /* extend permissions */ - attr->attr.mode |= base_attr->attr.mode; - - /* override null show/store with default */ - if (!attr->show) - attr->show = base_attr->show; - if (!attr->store) - attr->store = base_attr->store; - } - - return device_create_file(dev, attr); -} - /** * scsi_sysfs_add_sdev - add scsi device to sysfs * @sdev: scsi_device to add @@ -736,6 +730,24 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) * released by the sdev_class .release */ get_device(&sdev->sdev_gendev); + /* create queue files, which may be writable, depending on the host */ + if (sdev->host->hostt->change_queue_depth) + error = device_create_file(&sdev->sdev_gendev, &sdev_attr_queue_depth_rw); + else + error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_depth); + if (error) { + __scsi_remove_device(sdev); + goto out; + } + if (sdev->host->hostt->change_queue_type) + error = device_create_file(&sdev->sdev_gendev, &sdev_attr_queue_type_rw); + else + error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_type); + if (error) { + __scsi_remove_device(sdev); + goto out; + } + error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL); if (error) @@ -746,9 +758,10 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) * nothing went wrong */ error = 0; + /* add additional host specific attributes */ if (sdev->host->hostt->sdev_attrs) { for (i = 0; sdev->host->hostt->sdev_attrs[i]; i++) { - error = attr_add(&sdev->sdev_gendev, + error = device_create_file(&sdev->sdev_gendev, sdev->host->hostt->sdev_attrs[i]); if (error) { __scsi_remove_device(sdev); @@ -756,20 +769,6 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) } } } - - for (i = 0; scsi_sysfs_sdev_attrs[i]; i++) { - if (!attr_overridden(sdev->host->hostt->sdev_attrs, - scsi_sysfs_sdev_attrs[i])) { - struct device_attribute * attr = - attr_changed_internally(sdev->host, - scsi_sysfs_sdev_attrs[i]); - error = device_create_file(&sdev->sdev_gendev, attr); - if (error) { - __scsi_remove_device(sdev); - goto out; - } - } - } transport_add_device(&sdev->sdev_gendev); out: @@ -956,6 +955,12 @@ int scsi_sysfs_add_host(struct Scsi_Host *shost) return 0; } +static struct device_type scsi_dev_type = { + .name = "scsi_device", + .release = scsi_device_dev_release, + .groups = scsi_sdev_attr_groups, +}; + void scsi_sysfs_device_initialize(struct scsi_device *sdev) { unsigned long flags; @@ -964,7 +969,7 @@ void scsi_sysfs_device_initialize(struct scsi_device *sdev) device_initialize(&sdev->sdev_gendev); sdev->sdev_gendev.bus = &scsi_bus_type; - sdev->sdev_gendev.release = scsi_device_dev_release; + sdev->sdev_gendev.type = &scsi_dev_type; sprintf(sdev->sdev_gendev.bus_id,"%d:%d:%d:%d", sdev->host->host_no, sdev->channel, sdev->id, sdev->lun); @@ -985,7 +990,7 @@ void scsi_sysfs_device_initialize(struct scsi_device *sdev) int scsi_is_sdev_device(const struct device *dev) { - return dev->release == scsi_device_dev_release; + return dev->type == &scsi_dev_type; } EXPORT_SYMBOL(scsi_is_sdev_device); diff --git a/drivers/scsi/scsi_tgt_if.c b/drivers/scsi/scsi_tgt_if.c index ca22ddf81746..9815a1a2db24 100644 --- a/drivers/scsi/scsi_tgt_if.c +++ b/drivers/scsi/scsi_tgt_if.c @@ -102,7 +102,8 @@ static int tgt_uspace_send_event(u32 type, struct tgt_event *p) return 0; } -int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun, u64 tag) +int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, u64 itn_id, + struct scsi_lun *lun, u64 tag) { struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd); struct tgt_event ev; @@ -110,6 +111,7 @@ int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun, u64 ta memset(&ev, 0, sizeof(ev)); ev.p.cmd_req.host_no = shost->host_no; + ev.p.cmd_req.itn_id = itn_id; ev.p.cmd_req.data_len = cmd->request_bufflen; memcpy(ev.p.cmd_req.scb, cmd->cmnd, sizeof(ev.p.cmd_req.scb)); memcpy(ev.p.cmd_req.lun, lun, sizeof(ev.p.cmd_req.lun)); @@ -127,7 +129,7 @@ int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun, u64 ta return err; } -int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag) +int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 itn_id, u64 tag) { struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd); struct tgt_event ev; @@ -135,6 +137,7 @@ int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag) memset(&ev, 0, sizeof(ev)); ev.p.cmd_done.host_no = shost->host_no; + ev.p.cmd_done.itn_id = itn_id; ev.p.cmd_done.tag = tag; ev.p.cmd_done.result = cmd->result; @@ -149,14 +152,15 @@ int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag) return err; } -int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag, - struct scsi_lun *scsilun, void *data) +int scsi_tgt_uspace_send_tsk_mgmt(int host_no, u64 itn_id, int function, + u64 tag, struct scsi_lun *scsilun, void *data) { struct tgt_event ev; int err; memset(&ev, 0, sizeof(ev)); ev.p.tsk_mgmt_req.host_no = host_no; + ev.p.tsk_mgmt_req.itn_id = itn_id; ev.p.tsk_mgmt_req.function = function; ev.p.tsk_mgmt_req.tag = tag; memcpy(ev.p.tsk_mgmt_req.lun, scsilun, sizeof(ev.p.tsk_mgmt_req.lun)); @@ -172,6 +176,29 @@ int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag, return err; } +int scsi_tgt_uspace_send_it_nexus_request(int host_no, u64 itn_id, + int function, char *initiator_id) +{ + struct tgt_event ev; + int err; + + memset(&ev, 0, sizeof(ev)); + ev.p.it_nexus_req.host_no = host_no; + ev.p.it_nexus_req.function = function; + ev.p.it_nexus_req.itn_id = itn_id; + if (initiator_id) + strncpy(ev.p.it_nexus_req.initiator_id, initiator_id, + sizeof(ev.p.it_nexus_req.initiator_id)); + + dprintk("%d %x %llx\n", host_no, function, (unsigned long long)itn_id); + + err = tgt_uspace_send_event(TGT_KEVENT_IT_NEXUS_REQ, &ev); + if (err) + eprintk("tx buf is full, could not send\n"); + + return err; +} + static int event_recv_msg(struct tgt_event *ev) { int err = 0; @@ -179,6 +206,7 @@ static int event_recv_msg(struct tgt_event *ev) switch (ev->hdr.type) { case TGT_UEVENT_CMD_RSP: err = scsi_tgt_kspace_exec(ev->p.cmd_rsp.host_no, + ev->p.cmd_rsp.itn_id, ev->p.cmd_rsp.result, ev->p.cmd_rsp.tag, ev->p.cmd_rsp.uaddr, @@ -189,9 +217,15 @@ static int event_recv_msg(struct tgt_event *ev) break; case TGT_UEVENT_TSK_MGMT_RSP: err = scsi_tgt_kspace_tsk_mgmt(ev->p.tsk_mgmt_rsp.host_no, + ev->p.tsk_mgmt_rsp.itn_id, ev->p.tsk_mgmt_rsp.mid, ev->p.tsk_mgmt_rsp.result); break; + case TGT_UEVENT_IT_NEXUS_RSP: + err = scsi_tgt_kspace_it_nexus_rsp(ev->p.it_nexus_rsp.host_no, + ev->p.it_nexus_rsp.itn_id, + ev->p.it_nexus_rsp.result); + break; default: eprintk("unknown type %d\n", ev->hdr.type); err = -EINVAL; diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c index 371b69c110bc..66c692ffa305 100644 --- a/drivers/scsi/scsi_tgt_lib.c +++ b/drivers/scsi/scsi_tgt_lib.c @@ -27,6 +27,7 @@ #include <scsi/scsi_cmnd.h> #include <scsi/scsi_device.h> #include <scsi/scsi_host.h> +#include <scsi/scsi_transport.h> #include <scsi/scsi_tgt.h> #include "scsi_tgt_priv.h" @@ -46,6 +47,7 @@ struct scsi_tgt_cmd { struct list_head hash_list; struct request *rq; + u64 itn_id; u64 tag; }; @@ -185,12 +187,13 @@ static void scsi_tgt_cmd_destroy(struct work_struct *work) } static void init_scsi_tgt_cmd(struct request *rq, struct scsi_tgt_cmd *tcmd, - u64 tag) + u64 itn_id, u64 tag) { struct scsi_tgt_queuedata *qdata = rq->q->queuedata; unsigned long flags; struct list_head *head; + tcmd->itn_id = itn_id; tcmd->tag = tag; tcmd->bio = NULL; INIT_WORK(&tcmd->work, scsi_tgt_cmd_destroy); @@ -234,7 +237,7 @@ int scsi_tgt_alloc_queue(struct Scsi_Host *shost) * command as is recvd to userspace. uspace can then make * sure we do not overload the HBA */ - q->nr_requests = shost->hostt->can_queue; + q->nr_requests = shost->can_queue; /* * We currently only support software LLDs so this does * not matter for now. Do we need this for the cards we support? @@ -301,14 +304,14 @@ EXPORT_SYMBOL_GPL(scsi_tgt_cmd_to_host); * @scsilun: scsi lun * @tag: unique value to identify this command for tmf */ -int scsi_tgt_queue_command(struct scsi_cmnd *cmd, struct scsi_lun *scsilun, - u64 tag) +int scsi_tgt_queue_command(struct scsi_cmnd *cmd, u64 itn_id, + struct scsi_lun *scsilun, u64 tag) { struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data; int err; - init_scsi_tgt_cmd(cmd->request, tcmd, tag); - err = scsi_tgt_uspace_send_cmd(cmd, scsilun, tag); + init_scsi_tgt_cmd(cmd->request, tcmd, itn_id, tag); + err = scsi_tgt_uspace_send_cmd(cmd, itn_id, scsilun, tag); if (err) cmd_hashlist_del(cmd); @@ -326,7 +329,7 @@ static void scsi_tgt_cmd_done(struct scsi_cmnd *cmd) dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request)); - scsi_tgt_uspace_send_status(cmd, tcmd->tag); + scsi_tgt_uspace_send_status(cmd, tcmd->itn_id, tcmd->tag); if (cmd->request_buffer) scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len); @@ -459,7 +462,7 @@ static struct request *tgt_cmd_hash_lookup(struct request_queue *q, u64 tag) return rq; } -int scsi_tgt_kspace_exec(int host_no, int result, u64 tag, +int scsi_tgt_kspace_exec(int host_no, u64 itn_id, int result, u64 tag, unsigned long uaddr, u32 len, unsigned long sense_uaddr, u32 sense_len, u8 rw) { @@ -541,21 +544,22 @@ done: return err; } -int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *shost, int function, u64 tag, - struct scsi_lun *scsilun, void *data) +int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *shost, u64 itn_id, + int function, u64 tag, struct scsi_lun *scsilun, + void *data) { int err; /* TODO: need to retry if this fails. */ - err = scsi_tgt_uspace_send_tsk_mgmt(shost->host_no, function, - tag, scsilun, data); + err = scsi_tgt_uspace_send_tsk_mgmt(shost->host_no, itn_id, + function, tag, scsilun, data); if (err < 0) eprintk("The task management request lost!\n"); return err; } EXPORT_SYMBOL_GPL(scsi_tgt_tsk_mgmt_request); -int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 mid, int result) +int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 itn_id, u64 mid, int result) { struct Scsi_Host *shost; int err = -EINVAL; @@ -573,7 +577,60 @@ int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 mid, int result) goto done; } - err = shost->hostt->tsk_mgmt_response(mid, result); + err = shost->transportt->tsk_mgmt_response(shost, itn_id, mid, result); +done: + scsi_host_put(shost); + return err; +} + +int scsi_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id, + char *initiator) +{ + int err; + + /* TODO: need to retry if this fails. */ + err = scsi_tgt_uspace_send_it_nexus_request(shost->host_no, itn_id, 0, + initiator); + if (err < 0) + eprintk("The i_t_neuxs request lost, %d %llx!\n", + shost->host_no, (unsigned long long)itn_id); + return err; +} +EXPORT_SYMBOL_GPL(scsi_tgt_it_nexus_create); + +int scsi_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id) +{ + int err; + + /* TODO: need to retry if this fails. */ + err = scsi_tgt_uspace_send_it_nexus_request(shost->host_no, + itn_id, 1, NULL); + if (err < 0) + eprintk("The i_t_neuxs request lost, %d %llx!\n", + shost->host_no, (unsigned long long)itn_id); + return err; +} +EXPORT_SYMBOL_GPL(scsi_tgt_it_nexus_destroy); + +int scsi_tgt_kspace_it_nexus_rsp(int host_no, u64 itn_id, int result) +{ + struct Scsi_Host *shost; + int err = -EINVAL; + + dprintk("%d %d %llx\n", host_no, result, (unsigned long long) mid); + + shost = scsi_host_lookup(host_no); + if (IS_ERR(shost)) { + printk(KERN_ERR "Could not find host no %d\n", host_no); + return err; + } + + if (!shost->uspace_req_q) { + printk(KERN_ERR "Not target scsi host %d\n", host_no); + goto done; + } + + err = shost->transportt->it_nexus_response(shost, itn_id, result); done: scsi_host_put(shost); return err; diff --git a/drivers/scsi/scsi_tgt_priv.h b/drivers/scsi/scsi_tgt_priv.h index e9e6db1c417f..cb92888948f9 100644 --- a/drivers/scsi/scsi_tgt_priv.h +++ b/drivers/scsi/scsi_tgt_priv.h @@ -15,12 +15,18 @@ do { \ extern void scsi_tgt_if_exit(void); extern int scsi_tgt_if_init(void); -extern int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun, - u64 tag); -extern int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag); -extern int scsi_tgt_kspace_exec(int host_no, int result, u64 tag, - unsigned long uaddr, u32 len, unsigned long sense_uaddr, - u32 sense_len, u8 rw); -extern int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag, +extern int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, u64 it_nexus_id, + struct scsi_lun *lun, u64 tag); +extern int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 it_nexus_id, + u64 tag); +extern int scsi_tgt_kspace_exec(int host_no, u64 it_nexus_id, int result, u64 tag, + unsigned long uaddr, u32 len, + unsigned long sense_uaddr, u32 sense_len, u8 rw); +extern int scsi_tgt_uspace_send_tsk_mgmt(int host_no, u64 it_nexus_id, + int function, u64 tag, struct scsi_lun *scsilun, void *data); -extern int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 mid, int result); +extern int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 it_nexus_id, + u64 mid, int result); +extern int scsi_tgt_uspace_send_it_nexus_request(int host_no, u64 it_nexus_id, + int function, char *initiator); +extern int scsi_tgt_kspace_it_nexus_rsp(int host_no, u64 it_nexus_id, int result); diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 47057254850d..7a7cfe583b2a 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -36,6 +36,7 @@ #include <net/netlink.h> #include <scsi/scsi_netlink_fc.h> #include "scsi_priv.h" +#include "scsi_transport_fc_internal.h" static int fc_queue_work(struct Scsi_Host *, struct work_struct *); static void fc_vport_sched_delete(struct work_struct *work); @@ -473,7 +474,7 @@ static DECLARE_TRANSPORT_CLASS(fc_vport_class, */ static unsigned int fc_dev_loss_tmo = 60; /* seconds */ -module_param_named(dev_loss_tmo, fc_dev_loss_tmo, int, S_IRUGO|S_IWUSR); +module_param_named(dev_loss_tmo, fc_dev_loss_tmo, uint, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(dev_loss_tmo, "Maximum number of seconds that the FC transport should" " insulate the loss of a remote port. Once this value is" @@ -1956,6 +1957,19 @@ static int fc_user_scan(struct Scsi_Host *shost, uint channel, return 0; } +static int fc_tsk_mgmt_response(struct Scsi_Host *shost, u64 nexus, u64 tm_id, + int result) +{ + struct fc_internal *i = to_fc_internal(shost->transportt); + return i->f->tsk_mgmt_response(shost, nexus, tm_id, result); +} + +static int fc_it_nexus_response(struct Scsi_Host *shost, u64 nexus, int result) +{ + struct fc_internal *i = to_fc_internal(shost->transportt); + return i->f->it_nexus_response(shost, nexus, result); +} + struct scsi_transport_template * fc_attach_transport(struct fc_function_template *ft) { @@ -1999,6 +2013,10 @@ fc_attach_transport(struct fc_function_template *ft) i->t.user_scan = fc_user_scan; + /* target-mode drivers' functions */ + i->t.tsk_mgmt_response = fc_tsk_mgmt_response; + i->t.it_nexus_response = fc_it_nexus_response; + /* * Setup SCSI Target Attributes. */ @@ -2756,6 +2774,10 @@ fc_remote_port_delete(struct fc_rport *rport) spin_unlock_irqrestore(shost->host_lock, flags); + if (rport->roles & FC_PORT_ROLE_FCP_INITIATOR && + shost->active_mode & MODE_TARGET) + fc_tgt_it_nexus_destroy(shost, (unsigned long)rport); + scsi_target_block(&rport->dev); /* see if we need to kill io faster than waiting for device loss */ @@ -2796,6 +2818,7 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles) struct fc_host_attrs *fc_host = shost_to_fc_host(shost); unsigned long flags; int create = 0; + int ret; spin_lock_irqsave(shost->host_lock, flags); if (roles & FC_PORT_ROLE_FCP_TARGET) { @@ -2804,6 +2827,12 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles) create = 1; } else if (!(rport->roles & FC_PORT_ROLE_FCP_TARGET)) create = 1; + } else if (shost->active_mode & MODE_TARGET) { + ret = fc_tgt_it_nexus_create(shost, (unsigned long)rport, + (char *)&rport->node_name); + if (ret) + printk(KERN_ERR "FC Remore Port tgt nexus failed %d\n", + ret); } rport->roles = roles; @@ -2988,10 +3017,12 @@ fc_scsi_scan_rport(struct work_struct *work) struct fc_rport *rport = container_of(work, struct fc_rport, scan_work); struct Scsi_Host *shost = rport_to_shost(rport); + struct fc_internal *i = to_fc_internal(shost->transportt); unsigned long flags; if ((rport->port_state == FC_PORTSTATE_ONLINE) && - (rport->roles & FC_PORT_ROLE_FCP_TARGET)) { + (rport->roles & FC_PORT_ROLE_FCP_TARGET) && + !(i->f->disable_target_scan)) { scsi_scan_target(&rport->dev, rport->channel, rport->scsi_target_id, SCAN_WILD_CARD, 1); } diff --git a/drivers/scsi/scsi_transport_fc_internal.h b/drivers/scsi/scsi_transport_fc_internal.h new file mode 100644 index 000000000000..e7bfbe751c1f --- /dev/null +++ b/drivers/scsi/scsi_transport_fc_internal.h @@ -0,0 +1,26 @@ +#include <scsi/scsi_tgt.h> + +#ifdef CONFIG_SCSI_FC_TGT_ATTRS +static inline int fc_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id, + char *initiator) +{ + return scsi_tgt_it_nexus_create(shost, itn_id, initiator); +} + +static inline int fc_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id) +{ + return scsi_tgt_it_nexus_destroy(shost, itn_id); +} +#else +static inline int fc_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id, + char *initiator) +{ + return 0; +} + +static inline int fc_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id) +{ + return 0; +} + +#endif diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c new file mode 100644 index 000000000000..44a340bd937b --- /dev/null +++ b/drivers/scsi/scsi_transport_srp.c @@ -0,0 +1,381 @@ +/* + * SCSI RDMA (SRP) transport class + * + * Copyright (C) 2007 FUJITA Tomonori <tomof@acm.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + * + * 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 St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/jiffies.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/string.h> + +#include <scsi/scsi.h> +#include <scsi/scsi_device.h> +#include <scsi/scsi_host.h> +#include <scsi/scsi_transport.h> +#include <scsi/scsi_transport_srp.h> +#include "scsi_transport_srp_internal.h" + +struct srp_host_attrs { + atomic_t next_port_id; +}; +#define to_srp_host_attrs(host) ((struct srp_host_attrs *)(host)->shost_data) + +#define SRP_HOST_ATTRS 0 +#define SRP_RPORT_ATTRS 2 + +struct srp_internal { + struct scsi_transport_template t; + struct srp_function_template *f; + + struct class_device_attribute *host_attrs[SRP_HOST_ATTRS + 1]; + + struct class_device_attribute *rport_attrs[SRP_RPORT_ATTRS + 1]; + struct class_device_attribute private_rport_attrs[SRP_RPORT_ATTRS]; + struct transport_container rport_attr_cont; +}; + +#define to_srp_internal(tmpl) container_of(tmpl, struct srp_internal, t) + +#define dev_to_rport(d) container_of(d, struct srp_rport, dev) +#define transport_class_to_srp_rport(cdev) dev_to_rport((cdev)->dev) + +static int srp_host_setup(struct transport_container *tc, struct device *dev, + struct class_device *cdev) +{ + struct Scsi_Host *shost = dev_to_shost(dev); + struct srp_host_attrs *srp_host = to_srp_host_attrs(shost); + + atomic_set(&srp_host->next_port_id, 0); + return 0; +} + +static DECLARE_TRANSPORT_CLASS(srp_host_class, "srp_host", srp_host_setup, + NULL, NULL); + +static DECLARE_TRANSPORT_CLASS(srp_rport_class, "srp_remote_ports", + NULL, NULL, NULL); + +#define SETUP_TEMPLATE(attrb, field, perm, test, ro_test, ro_perm) \ + i->private_##attrb[count] = class_device_attr_##field; \ + i->private_##attrb[count].attr.mode = perm; \ + if (ro_test) { \ + i->private_##attrb[count].attr.mode = ro_perm; \ + i->private_##attrb[count].store = NULL; \ + } \ + i->attrb[count] = &i->private_##attrb[count]; \ + if (test) \ + count++ + +#define SETUP_RPORT_ATTRIBUTE_RD(field) \ + SETUP_TEMPLATE(rport_attrs, field, S_IRUGO, 1, 0, 0) + +#define SETUP_RPORT_ATTRIBUTE_RW(field) \ + SETUP_TEMPLATE(rport_attrs, field, S_IRUGO | S_IWUSR, \ + 1, 1, S_IRUGO) + +#define SRP_PID(p) \ + (p)->port_id[0], (p)->port_id[1], (p)->port_id[2], (p)->port_id[3], \ + (p)->port_id[4], (p)->port_id[5], (p)->port_id[6], (p)->port_id[7], \ + (p)->port_id[8], (p)->port_id[9], (p)->port_id[10], (p)->port_id[11], \ + (p)->port_id[12], (p)->port_id[13], (p)->port_id[14], (p)->port_id[15] + +#define SRP_PID_FMT "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:" \ + "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x" + +static ssize_t +show_srp_rport_id(struct class_device *cdev, char *buf) +{ + struct srp_rport *rport = transport_class_to_srp_rport(cdev); + return sprintf(buf, SRP_PID_FMT "\n", SRP_PID(rport)); +} + +static CLASS_DEVICE_ATTR(port_id, S_IRUGO, show_srp_rport_id, NULL); + +static const struct { + u32 value; + char *name; +} srp_rport_role_names[] = { + {SRP_RPORT_ROLE_INITIATOR, "SRP Initiator"}, + {SRP_RPORT_ROLE_TARGET, "SRP Target"}, +}; + +static ssize_t +show_srp_rport_roles(struct class_device *cdev, char *buf) +{ + struct srp_rport *rport = transport_class_to_srp_rport(cdev); + int i; + char *name = NULL; + + for (i = 0; i < ARRAY_SIZE(srp_rport_role_names); i++) + if (srp_rport_role_names[i].value == rport->roles) { + name = srp_rport_role_names[i].name; + break; + } + return sprintf(buf, "%s\n", name ? : "unknown"); +} + +static CLASS_DEVICE_ATTR(roles, S_IRUGO, show_srp_rport_roles, NULL); + +static void srp_rport_release(struct device *dev) +{ + struct srp_rport *rport = dev_to_rport(dev); + + put_device(dev->parent); + kfree(rport); +} + +static int scsi_is_srp_rport(const struct device *dev) +{ + return dev->release == srp_rport_release; +} + +static int srp_rport_match(struct attribute_container *cont, + struct device *dev) +{ + struct Scsi_Host *shost; + struct srp_internal *i; + + if (!scsi_is_srp_rport(dev)) + return 0; + + shost = dev_to_shost(dev->parent); + if (!shost->transportt) + return 0; + if (shost->transportt->host_attrs.ac.class != &srp_host_class.class) + return 0; + + i = to_srp_internal(shost->transportt); + return &i->rport_attr_cont.ac == cont; +} + +static int srp_host_match(struct attribute_container *cont, struct device *dev) +{ + struct Scsi_Host *shost; + struct srp_internal *i; + + if (!scsi_is_host_device(dev)) + return 0; + + shost = dev_to_shost(dev); + if (!shost->transportt) + return 0; + if (shost->transportt->host_attrs.ac.class != &srp_host_class.class) + return 0; + + i = to_srp_internal(shost->transportt); + return &i->t.host_attrs.ac == cont; +} + +/** + * srp_rport_add - add a SRP remote port to the device hierarchy + * + * @shost: scsi host the remote port is connected to. + * @ids: The port id for the remote port. + * + * publishes a port to the rest of the system + */ +struct srp_rport *srp_rport_add(struct Scsi_Host *shost, + struct srp_rport_identifiers *ids) +{ + struct srp_rport *rport; + struct device *parent = &shost->shost_gendev; + int id, ret; + + rport = kzalloc(sizeof(*rport), GFP_KERNEL); + if (!rport) + return ERR_PTR(-ENOMEM); + + device_initialize(&rport->dev); + + rport->dev.parent = get_device(parent); + rport->dev.release = srp_rport_release; + + memcpy(rport->port_id, ids->port_id, sizeof(rport->port_id)); + rport->roles = ids->roles; + + id = atomic_inc_return(&to_srp_host_attrs(shost)->next_port_id); + sprintf(rport->dev.bus_id, "port-%d:%d", shost->host_no, id); + + transport_setup_device(&rport->dev); + + ret = device_add(&rport->dev); + if (ret) { + transport_destroy_device(&rport->dev); + put_device(&rport->dev); + return ERR_PTR(ret); + } + + if (shost->active_mode & MODE_TARGET && + ids->roles == SRP_RPORT_ROLE_INITIATOR) { + ret = srp_tgt_it_nexus_create(shost, (unsigned long)rport, + rport->port_id); + if (ret) { + device_del(&rport->dev); + transport_destroy_device(&rport->dev); + put_device(&rport->dev); + return ERR_PTR(ret); + } + } + + transport_add_device(&rport->dev); + transport_configure_device(&rport->dev); + + return rport; +} +EXPORT_SYMBOL_GPL(srp_rport_add); + +/** + * srp_rport_del -- remove a SRP remote port + * @port: SRP remote port to remove + * + * Removes the specified SRP remote port. + */ +void srp_rport_del(struct srp_rport *rport) +{ + struct device *dev = &rport->dev; + struct Scsi_Host *shost = dev_to_shost(dev->parent); + + if (shost->active_mode & MODE_TARGET && + rport->roles == SRP_RPORT_ROLE_INITIATOR) + srp_tgt_it_nexus_destroy(shost, (unsigned long)rport); + + transport_remove_device(dev); + device_del(dev); + transport_destroy_device(dev); + put_device(dev); +} +EXPORT_SYMBOL_GPL(srp_rport_del); + +static int do_srp_rport_del(struct device *dev, void *data) +{ + srp_rport_del(dev_to_rport(dev)); + return 0; +} + +/** + * srp_remove_host -- tear down a Scsi_Host's SRP data structures + * @shost: Scsi Host that is torn down + * + * Removes all SRP remote ports for a given Scsi_Host. + * Must be called just before scsi_remove_host for SRP HBAs. + */ +void srp_remove_host(struct Scsi_Host *shost) +{ + device_for_each_child(&shost->shost_gendev, NULL, do_srp_rport_del); +} +EXPORT_SYMBOL_GPL(srp_remove_host); + +static int srp_tsk_mgmt_response(struct Scsi_Host *shost, u64 nexus, u64 tm_id, + int result) +{ + struct srp_internal *i = to_srp_internal(shost->transportt); + return i->f->tsk_mgmt_response(shost, nexus, tm_id, result); +} + +static int srp_it_nexus_response(struct Scsi_Host *shost, u64 nexus, int result) +{ + struct srp_internal *i = to_srp_internal(shost->transportt); + return i->f->it_nexus_response(shost, nexus, result); +} + +/** + * srp_attach_transport -- instantiate SRP transport template + * @ft: SRP transport class function template + */ +struct scsi_transport_template * +srp_attach_transport(struct srp_function_template *ft) +{ + int count; + struct srp_internal *i; + + i = kzalloc(sizeof(*i), GFP_KERNEL); + if (!i) + return NULL; + + i->t.tsk_mgmt_response = srp_tsk_mgmt_response; + i->t.it_nexus_response = srp_it_nexus_response; + + i->t.host_size = sizeof(struct srp_host_attrs); + i->t.host_attrs.ac.attrs = &i->host_attrs[0]; + i->t.host_attrs.ac.class = &srp_host_class.class; + i->t.host_attrs.ac.match = srp_host_match; + i->host_attrs[0] = NULL; + transport_container_register(&i->t.host_attrs); + + i->rport_attr_cont.ac.attrs = &i->rport_attrs[0]; + i->rport_attr_cont.ac.class = &srp_rport_class.class; + i->rport_attr_cont.ac.match = srp_rport_match; + transport_container_register(&i->rport_attr_cont); + + count = 0; + SETUP_RPORT_ATTRIBUTE_RD(port_id); + SETUP_RPORT_ATTRIBUTE_RD(roles); + i->rport_attrs[count] = NULL; + + i->f = ft; + + return &i->t; +} +EXPORT_SYMBOL_GPL(srp_attach_transport); + +/** + * srp_release_transport -- release SRP transport template instance + * @t: transport template instance + */ +void srp_release_transport(struct scsi_transport_template *t) +{ + struct srp_internal *i = to_srp_internal(t); + + transport_container_unregister(&i->t.host_attrs); + transport_container_unregister(&i->rport_attr_cont); + + kfree(i); +} +EXPORT_SYMBOL_GPL(srp_release_transport); + +static __init int srp_transport_init(void) +{ + int ret; + + ret = transport_class_register(&srp_host_class); + if (ret) + return ret; + ret = transport_class_register(&srp_rport_class); + if (ret) + goto unregister_host_class; + + return 0; +unregister_host_class: + transport_class_unregister(&srp_host_class); + return ret; +} + +static void __exit srp_transport_exit(void) +{ + transport_class_unregister(&srp_host_class); + transport_class_unregister(&srp_rport_class); +} + +MODULE_AUTHOR("FUJITA Tomonori"); +MODULE_DESCRIPTION("SRP Transport Attributes"); +MODULE_LICENSE("GPL"); + +module_init(srp_transport_init); +module_exit(srp_transport_exit); diff --git a/drivers/scsi/scsi_transport_srp_internal.h b/drivers/scsi/scsi_transport_srp_internal.h new file mode 100644 index 000000000000..8a79747f9f3d --- /dev/null +++ b/drivers/scsi/scsi_transport_srp_internal.h @@ -0,0 +1,25 @@ +#include <scsi/scsi_tgt.h> + +#ifdef CONFIG_SCSI_SRP_TGT_ATTRS +static inline int srp_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id, + char *initiator) +{ + return scsi_tgt_it_nexus_create(shost, itn_id, initiator); +} + +static inline int srp_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id) +{ + return scsi_tgt_it_nexus_destroy(shost, itn_id); +} + +#else +static inline int srp_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id, + char *initiator) +{ + return 0; +} +static inline int srp_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id) +{ + return 0; +} +#endif diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 2c6116fd4578..0a3a528212c2 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -86,6 +86,19 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_DISK); MODULE_ALIAS_SCSI_DEVICE(TYPE_MOD); MODULE_ALIAS_SCSI_DEVICE(TYPE_RBC); +static int sd_revalidate_disk(struct gendisk *); +static int sd_probe(struct device *); +static int sd_remove(struct device *); +static void sd_shutdown(struct device *); +static int sd_suspend(struct device *, pm_message_t state); +static int sd_resume(struct device *); +static void sd_rescan(struct device *); +static int sd_done(struct scsi_cmnd *); +static void sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer); +static void scsi_disk_release(struct class_device *cdev); +static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *); +static void sd_print_result(struct scsi_disk *, int); + static DEFINE_IDR(sd_index_idr); static DEFINE_SPINLOCK(sd_index_lock); @@ -240,7 +253,7 @@ static struct scsi_driver sd_template = { .shutdown = sd_shutdown, }, .rescan = sd_rescan, - .init_command = sd_init_command, + .done = sd_done, }; /* @@ -331,14 +344,31 @@ static void scsi_disk_put(struct scsi_disk *sdkp) * * Returns 1 if successful and 0 if error (or cannot be done now). **/ -static int sd_init_command(struct scsi_cmnd * SCpnt) +static int sd_prep_fn(struct request_queue *q, struct request *rq) { - struct scsi_device *sdp = SCpnt->device; - struct request *rq = SCpnt->request; + struct scsi_cmnd *SCpnt; + struct scsi_device *sdp = q->queuedata; struct gendisk *disk = rq->rq_disk; sector_t block = rq->sector; - unsigned int this_count = SCpnt->request_bufflen >> 9; + unsigned int this_count = rq->nr_sectors; unsigned int timeout = sdp->timeout; + int ret; + + if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { + ret = scsi_setup_blk_pc_cmnd(sdp, rq); + goto out; + } else if (rq->cmd_type != REQ_TYPE_FS) { + ret = BLKPREP_KILL; + goto out; + } + ret = scsi_setup_fs_cmnd(sdp, rq); + if (ret != BLKPREP_OK) + goto out; + SCpnt = rq->special; + + /* from here on until we're complete, any goto out + * is used for a killable error condition */ + ret = BLKPREP_KILL; SCSI_LOG_HLQUEUE(1, scmd_printk(KERN_INFO, SCpnt, "sd_init_command: block=%llu, " @@ -353,7 +383,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt) rq->nr_sectors)); SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "Retry with 0x%p\n", SCpnt)); - return 0; + goto out; } if (sdp->changed) { @@ -362,8 +392,9 @@ static int sd_init_command(struct scsi_cmnd * SCpnt) * the changed bit has been reset */ /* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */ - return 0; + goto out; } + SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n", (unsigned long long)block)); @@ -382,7 +413,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt) if ((block & 1) || (rq->nr_sectors & 1)) { scmd_printk(KERN_ERR, SCpnt, "Bad block number requested\n"); - return 0; + goto out; } else { block = block >> 1; this_count = this_count >> 1; @@ -392,7 +423,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt) if ((block & 3) || (rq->nr_sectors & 3)) { scmd_printk(KERN_ERR, SCpnt, "Bad block number requested\n"); - return 0; + goto out; } else { block = block >> 2; this_count = this_count >> 2; @@ -402,7 +433,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt) if ((block & 7) || (rq->nr_sectors & 7)) { scmd_printk(KERN_ERR, SCpnt, "Bad block number requested\n"); - return 0; + goto out; } else { block = block >> 3; this_count = this_count >> 3; @@ -410,7 +441,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt) } if (rq_data_dir(rq) == WRITE) { if (!sdp->writeable) { - return 0; + goto out; } SCpnt->cmnd[0] = WRITE_6; SCpnt->sc_data_direction = DMA_TO_DEVICE; @@ -419,7 +450,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt) SCpnt->sc_data_direction = DMA_FROM_DEVICE; } else { scmd_printk(KERN_ERR, SCpnt, "Unknown command %x\n", rq->cmd_flags); - return 0; + goto out; } SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, @@ -470,7 +501,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt) */ scmd_printk(KERN_ERR, SCpnt, "FUA write on READ/WRITE(6) drive\n"); - return 0; + goto out; } SCpnt->cmnd[1] |= (unsigned char) ((block >> 16) & 0x1f); @@ -492,16 +523,12 @@ static int sd_init_command(struct scsi_cmnd * SCpnt) SCpnt->timeout_per_command = timeout; /* - * This is the completion routine we use. This is matched in terms - * of capability to this function. - */ - SCpnt->done = sd_rw_intr; - - /* * This indicates that the command is ready from our end to be * queued. */ - return 1; + ret = BLKPREP_OK; + out: + return scsi_prep_return(q, rq, ret); } /** @@ -889,13 +916,13 @@ static struct block_device_operations sd_fops = { }; /** - * sd_rw_intr - bottom half handler: called when the lower level + * sd_done - bottom half handler: called when the lower level * driver has completed (successfully or otherwise) a scsi command. * @SCpnt: mid-level's per command structure. * * Note: potentially run from within an ISR. Must not block. **/ -static void sd_rw_intr(struct scsi_cmnd * SCpnt) +static int sd_done(struct scsi_cmnd *SCpnt) { int result = SCpnt->result; unsigned int xfer_size = SCpnt->request_bufflen; @@ -916,7 +943,7 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) SCSI_LOG_HLCOMPLETE(1, scsi_print_result(SCpnt)); if (sense_valid) { SCSI_LOG_HLCOMPLETE(1, scmd_printk(KERN_INFO, SCpnt, - "sd_rw_intr: sb[respc,sk,asc," + "sd_done: sb[respc,sk,asc," "ascq]=%x,%x,%x,%x\n", sshdr.response_code, sshdr.sense_key, sshdr.asc, @@ -988,7 +1015,7 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) break; } out: - scsi_io_completion(SCpnt, good_bytes); + return good_bytes; } static int media_not_present(struct scsi_disk *sdkp, @@ -1669,6 +1696,7 @@ static int sd_probe(struct device *dev) sd_revalidate_disk(gd); + blk_queue_prep_rq(sdp->request_queue, sd_prep_fn); blk_queue_issue_flush_fn(sdp->request_queue, sd_issue_flush); gd->driverfs_dev = &sdp->sdev_gendev; diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 85d38940a6c9..f6f5fc7d0cee 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -43,6 +43,7 @@ static int sg_version_num = 30534; /* 2 digits for each component */ #include <linux/poll.h> #include <linux/moduleparam.h> #include <linux/cdev.h> +#include <linux/idr.h> #include <linux/seq_file.h> #include <linux/blkdev.h> #include <linux/delay.h> @@ -99,12 +100,11 @@ static int scatter_elem_sz_prev = SG_SCATTER_SZ; #define SG_SECTOR_SZ 512 #define SG_SECTOR_MSK (SG_SECTOR_SZ - 1) -#define SG_DEV_ARR_LUMP 32 /* amount to over allocate sg_dev_arr by */ - static int sg_add(struct class_device *, struct class_interface *); static void sg_remove(struct class_device *, struct class_interface *); -static DEFINE_RWLOCK(sg_dev_arr_lock); /* Also used to lock +static DEFINE_IDR(sg_index_idr); +static DEFINE_RWLOCK(sg_index_lock); /* Also used to lock file descriptor list for device */ static struct class_interface sg_interface = { @@ -114,7 +114,7 @@ static struct class_interface sg_interface = { typedef struct sg_scatter_hold { /* holding area for scsi scatter gather info */ unsigned short k_use_sg; /* Count of kernel scatter-gather pieces */ - unsigned short sglist_len; /* size of malloc'd scatter-gather list ++ */ + unsigned sglist_len; /* size of malloc'd scatter-gather list ++ */ unsigned bufflen; /* Size of (aggregate) data buffer */ unsigned b_malloc_len; /* actual len malloc'ed in buffer */ struct scatterlist *buffer;/* scatter list */ @@ -162,6 +162,7 @@ typedef struct sg_device { /* holds the state of each scsi generic device */ struct scsi_device *device; wait_queue_head_t o_excl_wait; /* queue open() when O_EXCL in use */ int sg_tablesize; /* adapter's max scatter-gather table size */ + u32 index; /* device index number */ Sg_fd *headfp; /* first open fd belonging to this device */ volatile char detached; /* 0->attached, 1->detached pending removal */ volatile char exclude; /* opened for exclusive access */ @@ -209,10 +210,6 @@ static Sg_device *sg_get_dev(int dev); static int sg_last_dev(void); #endif -static Sg_device **sg_dev_arr = NULL; -static int sg_dev_max; -static int sg_nr_dev; - #define SZ_SG_HEADER sizeof(struct sg_header) #define SZ_SG_IO_HDR sizeof(sg_io_hdr_t) #define SZ_SG_IOVEC sizeof(sg_iovec_t) @@ -1331,40 +1328,35 @@ static struct class *sg_sysfs_class; static int sg_sysfs_valid = 0; -static int sg_alloc(struct gendisk *disk, struct scsi_device *scsidp) +static Sg_device *sg_alloc(struct gendisk *disk, struct scsi_device *scsidp) { struct request_queue *q = scsidp->request_queue; Sg_device *sdp; unsigned long iflags; - void *old_sg_dev_arr = NULL; - int k, error; + int error; + u32 k; sdp = kzalloc(sizeof(Sg_device), GFP_KERNEL); if (!sdp) { printk(KERN_WARNING "kmalloc Sg_device failure\n"); - return -ENOMEM; + return ERR_PTR(-ENOMEM); + } + error = -ENOMEM; + if (!idr_pre_get(&sg_index_idr, GFP_KERNEL)) { + printk(KERN_WARNING "idr expansion Sg_device failure\n"); + goto out; } - write_lock_irqsave(&sg_dev_arr_lock, iflags); - if (unlikely(sg_nr_dev >= sg_dev_max)) { /* try to resize */ - Sg_device **tmp_da; - int tmp_dev_max = sg_nr_dev + SG_DEV_ARR_LUMP; - write_unlock_irqrestore(&sg_dev_arr_lock, iflags); - - tmp_da = kzalloc(tmp_dev_max * sizeof(Sg_device *), GFP_KERNEL); - if (unlikely(!tmp_da)) - goto expand_failed; + write_lock_irqsave(&sg_index_lock, iflags); + error = idr_get_new(&sg_index_idr, sdp, &k); + write_unlock_irqrestore(&sg_index_lock, iflags); - write_lock_irqsave(&sg_dev_arr_lock, iflags); - memcpy(tmp_da, sg_dev_arr, sg_dev_max * sizeof(Sg_device *)); - old_sg_dev_arr = sg_dev_arr; - sg_dev_arr = tmp_da; - sg_dev_max = tmp_dev_max; + if (error) { + printk(KERN_WARNING "idr allocation Sg_device failure: %d\n", + error); + goto out; } - for (k = 0; k < sg_dev_max; k++) - if (!sg_dev_arr[k]) - break; if (unlikely(k >= SG_MAX_DEVS)) goto overflow; @@ -1375,25 +1367,17 @@ static int sg_alloc(struct gendisk *disk, struct scsi_device *scsidp) sdp->device = scsidp; init_waitqueue_head(&sdp->o_excl_wait); sdp->sg_tablesize = min(q->max_hw_segments, q->max_phys_segments); + sdp->index = k; - sg_nr_dev++; - sg_dev_arr[k] = sdp; - write_unlock_irqrestore(&sg_dev_arr_lock, iflags); - error = k; - + error = 0; out: - if (error < 0) + if (error) { kfree(sdp); - kfree(old_sg_dev_arr); - return error; - - expand_failed: - printk(KERN_WARNING "sg_alloc: device array cannot be resized\n"); - error = -ENOMEM; - goto out; + return ERR_PTR(error); + } + return sdp; overflow: - write_unlock_irqrestore(&sg_dev_arr_lock, iflags); sdev_printk(KERN_WARNING, scsidp, "Unable to attach sg device type=%d, minor " "number exceeds %d\n", scsidp->type, SG_MAX_DEVS - 1); @@ -1408,7 +1392,7 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf) struct gendisk *disk; Sg_device *sdp = NULL; struct cdev * cdev = NULL; - int error, k; + int error; unsigned long iflags; disk = alloc_disk(1); @@ -1427,15 +1411,15 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf) cdev->owner = THIS_MODULE; cdev->ops = &sg_fops; - error = sg_alloc(disk, scsidp); - if (error < 0) { + sdp = sg_alloc(disk, scsidp); + if (IS_ERR(sdp)) { printk(KERN_WARNING "sg_alloc failed\n"); + error = PTR_ERR(sdp); goto out; } - k = error; - sdp = sg_dev_arr[k]; - error = cdev_add(cdev, MKDEV(SCSI_GENERIC_MAJOR, k), 1); + class_set_devdata(cl_dev, sdp); + error = cdev_add(cdev, MKDEV(SCSI_GENERIC_MAJOR, sdp->index), 1); if (error) goto cdev_add_err; @@ -1444,8 +1428,8 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf) struct class_device * sg_class_member; sg_class_member = class_device_create(sg_sysfs_class, NULL, - MKDEV(SCSI_GENERIC_MAJOR, k), - cl_dev->dev, "%s", + MKDEV(SCSI_GENERIC_MAJOR, sdp->index), + cl_dev->dev, "%s", disk->disk_name); if (IS_ERR(sg_class_member)) printk(KERN_WARNING "sg_add: " @@ -1455,21 +1439,21 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf) &sg_class_member->kobj, "generic"); if (error) printk(KERN_ERR "sg_add: unable to make symlink " - "'generic' back to sg%d\n", k); + "'generic' back to sg%d\n", sdp->index); } else - printk(KERN_WARNING "sg_add: sg_sys INvalid\n"); + printk(KERN_WARNING "sg_add: sg_sys Invalid\n"); sdev_printk(KERN_NOTICE, scsidp, - "Attached scsi generic sg%d type %d\n", k,scsidp->type); + "Attached scsi generic sg%d type %d\n", sdp->index, + scsidp->type); return 0; cdev_add_err: - write_lock_irqsave(&sg_dev_arr_lock, iflags); - kfree(sg_dev_arr[k]); - sg_dev_arr[k] = NULL; - sg_nr_dev--; - write_unlock_irqrestore(&sg_dev_arr_lock, iflags); + write_lock_irqsave(&sg_index_lock, iflags); + idr_remove(&sg_index_idr, sdp->index); + write_unlock_irqrestore(&sg_index_lock, iflags); + kfree(sdp); out: put_disk(disk); @@ -1482,64 +1466,56 @@ static void sg_remove(struct class_device *cl_dev, struct class_interface *cl_intf) { struct scsi_device *scsidp = to_scsi_device(cl_dev->dev); - Sg_device *sdp = NULL; + Sg_device *sdp = class_get_devdata(cl_dev); unsigned long iflags; Sg_fd *sfp; Sg_fd *tsfp; Sg_request *srp; Sg_request *tsrp; - int k, delay; + int delay; - if (NULL == sg_dev_arr) + if (!sdp) return; + delay = 0; - write_lock_irqsave(&sg_dev_arr_lock, iflags); - for (k = 0; k < sg_dev_max; k++) { - sdp = sg_dev_arr[k]; - if ((NULL == sdp) || (sdp->device != scsidp)) - continue; /* dirty but lowers nesting */ - if (sdp->headfp) { - sdp->detached = 1; - for (sfp = sdp->headfp; sfp; sfp = tsfp) { - tsfp = sfp->nextfp; - for (srp = sfp->headrp; srp; srp = tsrp) { - tsrp = srp->nextrp; - if (sfp->closed || (0 == sg_srp_done(srp, sfp))) - sg_finish_rem_req(srp); - } - if (sfp->closed) { - scsi_device_put(sdp->device); - __sg_remove_sfp(sdp, sfp); - } else { - delay = 1; - wake_up_interruptible(&sfp->read_wait); - kill_fasync(&sfp->async_qp, SIGPOLL, - POLL_HUP); - } + write_lock_irqsave(&sg_index_lock, iflags); + if (sdp->headfp) { + sdp->detached = 1; + for (sfp = sdp->headfp; sfp; sfp = tsfp) { + tsfp = sfp->nextfp; + for (srp = sfp->headrp; srp; srp = tsrp) { + tsrp = srp->nextrp; + if (sfp->closed || (0 == sg_srp_done(srp, sfp))) + sg_finish_rem_req(srp); } - SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d, dirty\n", k)); - if (NULL == sdp->headfp) { - sg_dev_arr[k] = NULL; + if (sfp->closed) { + scsi_device_put(sdp->device); + __sg_remove_sfp(sdp, sfp); + } else { + delay = 1; + wake_up_interruptible(&sfp->read_wait); + kill_fasync(&sfp->async_qp, SIGPOLL, + POLL_HUP); } - } else { /* nothing active, simple case */ - SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d\n", k)); - sg_dev_arr[k] = NULL; } - sg_nr_dev--; - break; - } - write_unlock_irqrestore(&sg_dev_arr_lock, iflags); - - if (sdp) { - sysfs_remove_link(&scsidp->sdev_gendev.kobj, "generic"); - class_device_destroy(sg_sysfs_class, MKDEV(SCSI_GENERIC_MAJOR, k)); - cdev_del(sdp->cdev); - sdp->cdev = NULL; - put_disk(sdp->disk); - sdp->disk = NULL; - if (NULL == sdp->headfp) - kfree((char *) sdp); - } + SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d, dirty\n", sdp->index)); + if (NULL == sdp->headfp) { + idr_remove(&sg_index_idr, sdp->index); + } + } else { /* nothing active, simple case */ + SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d\n", sdp->index)); + idr_remove(&sg_index_idr, sdp->index); + } + write_unlock_irqrestore(&sg_index_lock, iflags); + + sysfs_remove_link(&scsidp->sdev_gendev.kobj, "generic"); + class_device_destroy(sg_sysfs_class, MKDEV(SCSI_GENERIC_MAJOR, sdp->index)); + cdev_del(sdp->cdev); + sdp->cdev = NULL; + put_disk(sdp->disk); + sdp->disk = NULL; + if (NULL == sdp->headfp) + kfree(sdp); if (delay) msleep(10); /* dirty detach so delay device destruction */ @@ -1609,9 +1585,7 @@ exit_sg(void) sg_sysfs_valid = 0; unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), SG_MAX_DEVS); - kfree((char *)sg_dev_arr); - sg_dev_arr = NULL; - sg_dev_max = 0; + idr_destroy(&sg_index_idr); } static int @@ -2331,10 +2305,10 @@ sg_get_nth_sfp(Sg_device * sdp, int nth) unsigned long iflags; int k; - read_lock_irqsave(&sg_dev_arr_lock, iflags); + read_lock_irqsave(&sg_index_lock, iflags); for (k = 0, resp = sdp->headfp; resp && (k < nth); ++k, resp = resp->nextfp) ; - read_unlock_irqrestore(&sg_dev_arr_lock, iflags); + read_unlock_irqrestore(&sg_index_lock, iflags); return resp; } #endif @@ -2361,7 +2335,7 @@ sg_add_sfp(Sg_device * sdp, int dev) sfp->cmd_q = SG_DEF_COMMAND_Q; sfp->keep_orphan = SG_DEF_KEEP_ORPHAN; sfp->parentdp = sdp; - write_lock_irqsave(&sg_dev_arr_lock, iflags); + write_lock_irqsave(&sg_index_lock, iflags); if (!sdp->headfp) sdp->headfp = sfp; else { /* add to tail of existing list */ @@ -2370,7 +2344,7 @@ sg_add_sfp(Sg_device * sdp, int dev) pfp = pfp->nextfp; pfp->nextfp = sfp; } - write_unlock_irqrestore(&sg_dev_arr_lock, iflags); + write_unlock_irqrestore(&sg_index_lock, iflags); SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p\n", sfp)); if (unlikely(sg_big_buff != def_reserved_size)) sg_big_buff = def_reserved_size; @@ -2431,22 +2405,14 @@ sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp) if (0 == dirty) { unsigned long iflags; - write_lock_irqsave(&sg_dev_arr_lock, iflags); + write_lock_irqsave(&sg_index_lock, iflags); __sg_remove_sfp(sdp, sfp); if (sdp->detached && (NULL == sdp->headfp)) { - int k, maxd; - - maxd = sg_dev_max; - for (k = 0; k < maxd; ++k) { - if (sdp == sg_dev_arr[k]) - break; - } - if (k < maxd) - sg_dev_arr[k] = NULL; - kfree((char *) sdp); + idr_remove(&sg_index_idr, sdp->index); + kfree(sdp); res = 1; } - write_unlock_irqrestore(&sg_dev_arr_lock, iflags); + write_unlock_irqrestore(&sg_index_lock, iflags); } else { /* MOD_INC's to inhibit unloading sg and associated adapter driver */ /* only bump the access_count if we actually succeeded in @@ -2546,16 +2512,25 @@ sg_allow_access(unsigned char opcode, char dev_type) #ifdef CONFIG_SCSI_PROC_FS static int +sg_idr_max_id(int id, void *p, void *data) +{ + int *k = data; + + if (*k < id) + *k = id; + + return 0; +} + +static int sg_last_dev(void) { - int k; + int k = 0; unsigned long iflags; - read_lock_irqsave(&sg_dev_arr_lock, iflags); - for (k = sg_dev_max - 1; k >= 0; --k) - if (sg_dev_arr[k] && sg_dev_arr[k]->device) - break; - read_unlock_irqrestore(&sg_dev_arr_lock, iflags); + read_lock_irqsave(&sg_index_lock, iflags); + idr_for_each(&sg_index_idr, sg_idr_max_id, &k); + read_unlock_irqrestore(&sg_index_lock, iflags); return k + 1; /* origin 1 */ } #endif @@ -2563,15 +2538,13 @@ sg_last_dev(void) static Sg_device * sg_get_dev(int dev) { - Sg_device *sdp = NULL; + Sg_device *sdp; unsigned long iflags; - if (sg_dev_arr && (dev >= 0)) { - read_lock_irqsave(&sg_dev_arr_lock, iflags); - if (dev < sg_dev_max) - sdp = sg_dev_arr[dev]; - read_unlock_irqrestore(&sg_dev_arr_lock, iflags); - } + read_lock_irqsave(&sg_index_lock, iflags); + sdp = idr_find(&sg_index_idr, dev); + read_unlock_irqrestore(&sg_index_lock, iflags); + return sdp; } @@ -2805,8 +2778,6 @@ static void * dev_seq_start(struct seq_file *s, loff_t *pos) if (! it) return NULL; - if (NULL == sg_dev_arr) - return NULL; it->index = *pos; it->max = sg_last_dev(); if (it->index >= it->max) @@ -2942,8 +2913,8 @@ static int sg_proc_seq_show_debug(struct seq_file *s, void *v) Sg_device *sdp; if (it && (0 == it->index)) { - seq_printf(s, "dev_max(currently)=%d max_active_device=%d " - "(origin 1)\n", sg_dev_max, (int)it->max); + seq_printf(s, "max_active_device=%d(origin 1)\n", + (int)it->max); seq_printf(s, " def_reserved_size=%d\n", sg_big_buff); } sdp = it ? sg_get_dev(it->index) : NULL; diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 902eb11ffe8a..c61999031141 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -78,7 +78,7 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_WORM); static int sr_probe(struct device *); static int sr_remove(struct device *); -static int sr_init_command(struct scsi_cmnd *); +static int sr_done(struct scsi_cmnd *); static struct scsi_driver sr_template = { .owner = THIS_MODULE, @@ -87,7 +87,7 @@ static struct scsi_driver sr_template = { .probe = sr_probe, .remove = sr_remove, }, - .init_command = sr_init_command, + .done = sr_done, }; static unsigned long sr_index_bits[SR_DISKS / BITS_PER_LONG]; @@ -210,12 +210,12 @@ static int sr_media_change(struct cdrom_device_info *cdi, int slot) } /* - * rw_intr is the interrupt routine for the device driver. + * sr_done is the interrupt routine for the device driver. * - * It will be notified on the end of a SCSI read / write, and will take on + * It will be notified on the end of a SCSI read / write, and will take one * of several actions based on success or failure. */ -static void rw_intr(struct scsi_cmnd * SCpnt) +static int sr_done(struct scsi_cmnd *SCpnt) { int result = SCpnt->result; int this_count = SCpnt->request_bufflen; @@ -288,27 +288,42 @@ static void rw_intr(struct scsi_cmnd * SCpnt) } } - /* - * This calls the generic completion function, now that we know - * how many actual sectors finished, and how many sectors we need - * to say have failed. - */ - scsi_io_completion(SCpnt, good_bytes); + return good_bytes; } -static int sr_init_command(struct scsi_cmnd * SCpnt) +static int sr_prep_fn(struct request_queue *q, struct request *rq) { int block=0, this_count, s_size, timeout = SR_TIMEOUT; - struct scsi_cd *cd = scsi_cd(SCpnt->request->rq_disk); + struct scsi_cd *cd; + struct scsi_cmnd *SCpnt; + struct scsi_device *sdp = q->queuedata; + int ret; + + if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { + ret = scsi_setup_blk_pc_cmnd(sdp, rq); + goto out; + } else if (rq->cmd_type != REQ_TYPE_FS) { + ret = BLKPREP_KILL; + goto out; + } + ret = scsi_setup_fs_cmnd(sdp, rq); + if (ret != BLKPREP_OK) + goto out; + SCpnt = rq->special; + cd = scsi_cd(rq->rq_disk); + + /* from here on until we're complete, any goto out + * is used for a killable error condition */ + ret = BLKPREP_KILL; SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %s, block = %d\n", cd->disk->disk_name, block)); if (!cd->device || !scsi_device_online(cd->device)) { SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n", - SCpnt->request->nr_sectors)); + rq->nr_sectors)); SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt)); - return 0; + goto out; } if (cd->device->changed) { @@ -316,7 +331,7 @@ static int sr_init_command(struct scsi_cmnd * SCpnt) * quietly refuse to do anything to a changed disc until the * changed bit has been reset */ - return 0; + goto out; } /* @@ -333,21 +348,21 @@ static int sr_init_command(struct scsi_cmnd * SCpnt) if (s_size != 512 && s_size != 1024 && s_size != 2048) { scmd_printk(KERN_ERR, SCpnt, "bad sector size %d\n", s_size); - return 0; + goto out; } - if (rq_data_dir(SCpnt->request) == WRITE) { + if (rq_data_dir(rq) == WRITE) { if (!cd->device->writeable) - return 0; + goto out; SCpnt->cmnd[0] = WRITE_10; SCpnt->sc_data_direction = DMA_TO_DEVICE; cd->cdi.media_written = 1; - } else if (rq_data_dir(SCpnt->request) == READ) { + } else if (rq_data_dir(rq) == READ) { SCpnt->cmnd[0] = READ_10; SCpnt->sc_data_direction = DMA_FROM_DEVICE; } else { - blk_dump_rq_flags(SCpnt->request, "Unknown sr command"); - return 0; + blk_dump_rq_flags(rq, "Unknown sr command"); + goto out; } { @@ -368,10 +383,10 @@ static int sr_init_command(struct scsi_cmnd * SCpnt) /* * request doesn't start on hw block boundary, add scatter pads */ - if (((unsigned int)SCpnt->request->sector % (s_size >> 9)) || + if (((unsigned int)rq->sector % (s_size >> 9)) || (SCpnt->request_bufflen % s_size)) { scmd_printk(KERN_NOTICE, SCpnt, "unaligned transfer\n"); - return 0; + goto out; } this_count = (SCpnt->request_bufflen >> 9) / (s_size >> 9); @@ -379,12 +394,12 @@ static int sr_init_command(struct scsi_cmnd * SCpnt) SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n", cd->cdi.name, - (rq_data_dir(SCpnt->request) == WRITE) ? + (rq_data_dir(rq) == WRITE) ? "writing" : "reading", - this_count, SCpnt->request->nr_sectors)); + this_count, rq->nr_sectors)); SCpnt->cmnd[1] = 0; - block = (unsigned int)SCpnt->request->sector / (s_size >> 9); + block = (unsigned int)rq->sector / (s_size >> 9); if (this_count > 0xffff) { this_count = 0xffff; @@ -410,16 +425,12 @@ static int sr_init_command(struct scsi_cmnd * SCpnt) SCpnt->timeout_per_command = timeout; /* - * This is the completion routine we use. This is matched in terms - * of capability to this function. - */ - SCpnt->done = rw_intr; - - /* * This indicates that the command is ready from our end to be * queued. */ - return 1; + ret = BLKPREP_OK; + out: + return scsi_prep_return(q, rq, ret); } static int sr_block_open(struct inode *inode, struct file *file) @@ -590,6 +601,7 @@ static int sr_probe(struct device *dev) /* FIXME: need to handle a get_capabilities failure properly ?? */ get_capabilities(cd); + blk_queue_prep_rq(sdev->request_queue, sr_prep_fn); sr_vendor_init(cd); disk->driverfs_dev = &sdev->sdev_gendev; diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c index 98e3fe10c1dc..dc15a22105f7 100644 --- a/drivers/scsi/sun3_NCR5380.c +++ b/drivers/scsi/sun3_NCR5380.c @@ -2055,7 +2055,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) sink = 1; do_abort(instance); cmd->result = DID_ERROR << 16; - cmd->done(cmd); + cmd->scsi_done(cmd); return; #endif case PHASE_DATAIN: @@ -2115,7 +2115,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) sink = 1; do_abort(instance); cmd->result = DID_ERROR << 16; - cmd->done(cmd); + cmd->scsi_done(cmd); /* XXX - need to source or sink data here, as appropriate */ } else { #ifdef REAL_DMA @@ -2254,25 +2254,21 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); #ifdef AUTOSENSE + if ((cmd->cmnd[0] == REQUEST_SENSE) && + hostdata->ses.cmd_len) { + scsi_eh_restore_cmnd(cmd, &hostdata->ses); + hostdata->ses.cmd_len = 0 ; + } + if ((cmd->cmnd[0] != REQUEST_SENSE) && (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) { + scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0); ASEN_PRINTK("scsi%d: performing request sense\n", HOSTNO); - cmd->cmnd[0] = REQUEST_SENSE; - cmd->cmnd[1] &= 0xe0; - cmd->cmnd[2] = 0; - cmd->cmnd[3] = 0; - cmd->cmnd[4] = sizeof(cmd->sense_buffer); - cmd->cmnd[5] = 0; - cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]); - - cmd->use_sg = 0; /* this is initialized from initialize_SCp cmd->SCp.buffer = NULL; cmd->SCp.buffers_residual = 0; */ - cmd->request_buffer = (char *) cmd->sense_buffer; - cmd->request_bufflen = sizeof(cmd->sense_buffer); local_irq_save(flags); LIST(cmd,hostdata->issue_queue); diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c index 5db1520f8ba9..5c72ca31a47a 100644 --- a/drivers/scsi/tmscsim.c +++ b/drivers/scsi/tmscsim.c @@ -567,12 +567,12 @@ dc390_StartSCSI( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_sr pDCB->TagMask |= 1 << tag[1]; pSRB->TagNumber = tag[1]; DC390_write8(ScsiFifo, tag[1]); - DEBUG1(printk(KERN_INFO "DC390: Select w/DisCn for Cmd %li (SRB %p), block tag %02x\n", scmd->pid, pSRB, tag[1])); + DEBUG1(printk(KERN_INFO "DC390: Select w/DisCn for Cmd %li (SRB %p), block tag %02x\n", scmd->serial_number, pSRB, tag[1])); cmd = SEL_W_ATN3; } else { /* No TagQ */ //no_tag: - DEBUG1(printk(KERN_INFO "DC390: Select w%s/DisCn for Cmd %li (SRB %p), No TagQ\n", disc_allowed ? "" : "o", scmd->pid, pSRB)); + DEBUG1(printk(KERN_INFO "DC390: Select w%s/DisCn for Cmd %li (SRB %p), No TagQ\n", disc_allowed ? "" : "o", scmd->serial_number, pSRB)); } pSRB->SRBState = SRB_START_; @@ -623,7 +623,7 @@ dc390_StartSCSI( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_sr { dc390_freetag (pDCB, pSRB); DEBUG0(printk ("DC390: Interrupt during Start SCSI (pid %li, target %02i-%02i)\n", - scmd->pid, scmd->device->id, scmd->device->lun)); + scmd->serial_number, scmd->device->id, scmd->device->lun)); pSRB->SRBState = SRB_READY; //DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); pACB->SelLost++; @@ -1708,7 +1708,7 @@ dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* status = pSRB->TargetStatus; DEBUG0(printk (" SRBdone (%02x,%08x), SRB %p, pid %li\n", status, pcmd->result,\ - pSRB, pcmd->pid)); + pSRB, pcmd->serial_number)); if(pSRB->SRBFlag & AUTO_REQSENSE) { /* Last command was a Request Sense */ pSRB->SRBFlag &= ~AUTO_REQSENSE; @@ -1729,7 +1729,7 @@ dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* } else { SET_RES_DRV(pcmd->result, DRIVER_SENSE); //pSRB->ScsiCmdLen = (u8) (pSRB->Segment1[0] >> 8); - DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->pid, pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun)); + DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->serial_number, pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun)); pSRB->TotalXferredLen = 0; SET_RES_DID(pcmd->result, DID_SOFT_ERROR); } @@ -1749,7 +1749,7 @@ dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* else if (status == SAM_STAT_TASK_SET_FULL) { scsi_track_queue_full(pcmd->device, pDCB->GoingSRBCnt - 1); - DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->pid, pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun)); + DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->serial_number, pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun)); pSRB->TotalXferredLen = 0; SET_RES_DID(pcmd->result, DID_SOFT_ERROR); } @@ -1803,7 +1803,7 @@ cmd_done: /* Add to free list */ dc390_Free_insert (pACB, pSRB); - DEBUG0(printk (KERN_DEBUG "DC390: SRBdone: done pid %li\n", pcmd->pid)); + DEBUG0(printk (KERN_DEBUG "DC390: SRBdone: done pid %li\n", pcmd->serial_number)); pcmd->scsi_done (pcmd); return; @@ -1998,7 +1998,7 @@ static int DC390_abort(struct scsi_cmnd *cmd) struct dc390_dcb *pDCB = (struct dc390_dcb*) cmd->device->hostdata; scmd_printk(KERN_WARNING, cmd, - "DC390: Abort command (pid %li)\n", cmd->pid); + "DC390: Abort command (pid %li)\n", cmd->serial_number); /* abort() is too stupid for already sent commands at the moment. * If it's called we are in trouble anyway, so let's dump some info @@ -2006,7 +2006,7 @@ static int DC390_abort(struct scsi_cmnd *cmd) dc390_dumpinfo(pACB, pDCB, NULL); pDCB->DCBFlag |= ABORT_DEV_; - printk(KERN_INFO "DC390: Aborted pid %li\n", cmd->pid); + printk(KERN_INFO "DC390: Aborted pid %li\n", cmd->serial_number); return FAILED; } diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c index 9e8232a1f169..fc9f51818e8f 100644 --- a/drivers/scsi/u14-34f.c +++ b/drivers/scsi/u14-34f.c @@ -1254,7 +1254,7 @@ static int u14_34f_queuecommand(struct scsi_cmnd *SCpnt, void (*done)(struct scs if (SCpnt->host_scribble) panic("%s: qcomm, pid %ld, SCpnt %p already active.\n", - BN(j), SCpnt->pid, SCpnt); + BN(j), SCpnt->serial_number, SCpnt); /* i is the mailbox number, look for the first free mailbox starting from last_cp_used */ @@ -1285,7 +1285,7 @@ static int u14_34f_queuecommand(struct scsi_cmnd *SCpnt, void (*done)(struct scs if (do_trace) printk("%s: qcomm, mbox %d, target %d.%d:%d, pid %ld.\n", BN(j), i, SCpnt->device->channel, SCpnt->device->id, - SCpnt->device->lun, SCpnt->pid); + SCpnt->device->lun, SCpnt->serial_number); cpp->opcode = OP_SCSI; cpp->channel = SCpnt->device->channel; @@ -1312,7 +1312,7 @@ static int u14_34f_queuecommand(struct scsi_cmnd *SCpnt, void (*done)(struct scs unmap_dma(i, j); SCpnt->host_scribble = NULL; scmd_printk(KERN_INFO, SCpnt, - "qcomm, pid %ld, adapter busy.\n", SCpnt->pid); + "qcomm, pid %ld, adapter busy.\n", SCpnt->serial_number); return 1; } @@ -1333,13 +1333,13 @@ static int u14_34f_eh_abort(struct scsi_cmnd *SCarg) { if (SCarg->host_scribble == NULL) { scmd_printk(KERN_INFO, SCarg, "abort, pid %ld inactive.\n", - SCarg->pid); + SCarg->serial_number); return SUCCESS; } i = *(unsigned int *)SCarg->host_scribble; scmd_printk(KERN_INFO, SCarg, "abort, mbox %d, pid %ld.\n", - i, SCarg->pid); + i, SCarg->serial_number); if (i >= sh[j]->can_queue) panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j)); @@ -1383,7 +1383,7 @@ static int u14_34f_eh_abort(struct scsi_cmnd *SCarg) { SCarg->host_scribble = NULL; HD(j)->cp_stat[i] = FREE; printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n", - BN(j), i, SCarg->pid); + BN(j), i, SCarg->serial_number); SCarg->scsi_done(SCarg); return SUCCESS; } @@ -1397,12 +1397,12 @@ static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) { struct scsi_cmnd *SCpnt; j = ((struct hostdata *) SCarg->device->host->hostdata)->board_number; - scmd_printk(KERN_INFO, SCarg, "reset, enter, pid %ld.\n", SCarg->pid); + scmd_printk(KERN_INFO, SCarg, "reset, enter, pid %ld.\n", SCarg->serial_number); spin_lock_irq(sh[j]->host_lock); if (SCarg->host_scribble == NULL) - printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->pid); + printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->serial_number); if (HD(j)->in_reset) { printk("%s: reset, exit, already in reset.\n", BN(j)); @@ -1440,13 +1440,13 @@ static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) { if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) { HD(j)->cp_stat[i] = ABORTING; printk("%s: reset, mbox %d aborting, pid %ld.\n", - BN(j), i, SCpnt->pid); + BN(j), i, SCpnt->serial_number); } else { HD(j)->cp_stat[i] = IN_RESET; printk("%s: reset, mbox %d in reset, pid %ld.\n", - BN(j), i, SCpnt->pid); + BN(j), i, SCpnt->serial_number); } if (SCpnt->host_scribble == NULL) @@ -1495,7 +1495,7 @@ static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) { HD(j)->cp_stat[i] = LOCKED; printk("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n", - BN(j), i, SCpnt->pid); + BN(j), i, SCpnt->serial_number); } else if (HD(j)->cp_stat[i] == ABORTING) { @@ -1508,7 +1508,7 @@ static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) { HD(j)->cp_stat[i] = FREE; printk("%s, reset, mbox %d aborting, DID_RESET, pid %ld done.\n", - BN(j), i, SCpnt->pid); + BN(j), i, SCpnt->serial_number); } else @@ -1522,7 +1522,7 @@ static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) { HD(j)->in_reset = FALSE; do_trace = FALSE; - if (arg_done) printk("%s: reset, exit, pid %ld done.\n", BN(j), SCarg->pid); + if (arg_done) printk("%s: reset, exit, pid %ld done.\n", BN(j), SCarg->serial_number); else printk("%s: reset, exit.\n", BN(j)); spin_unlock_irq(sh[j]->host_lock); @@ -1639,7 +1639,7 @@ static int reorder(unsigned int j, unsigned long cursec, if (!input_only) for (n = 0; n < n_ready; n++) { k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt; - ll[n] = SCpnt->request->nr_sectors; pl[n] = SCpnt->pid; + ll[n] = SCpnt->request->nr_sectors; pl[n] = SCpnt->serial_number; if (!n) continue; @@ -1666,7 +1666,7 @@ static int reorder(unsigned int j, unsigned long cursec, printk("%s %d.%d:%d pid %ld mb %d fc %d nr %d sec %ld ns %ld"\ " cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n", (ihdlr ? "ihdlr" : "qcomm"), SCpnt->channel, SCpnt->target, - SCpnt->lun, SCpnt->pid, k, flushcount, n_ready, + SCpnt->lun, SCpnt->serial_number, k, flushcount, n_ready, SCpnt->request->sector, SCpnt->request->nr_sectors, cursec, YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only), YESNO(overlap), cpp->xdir); @@ -1703,7 +1703,7 @@ static void flush_dev(struct scsi_device *dev, unsigned long cursec, unsigned in scmd_printk(KERN_INFO, SCpnt, "%s, pid %ld, mbox %d, adapter" " busy, will abort.\n", (ihdlr ? "ihdlr" : "qcomm"), - SCpnt->pid, k); + SCpnt->serial_number, k); HD(j)->cp_stat[k] = ABORTING; continue; } @@ -1787,11 +1787,11 @@ static irqreturn_t ihdlr(int irq, unsigned int j) { if (SCpnt->host_scribble == NULL) panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n", BN(j), i, - SCpnt->pid, SCpnt); + SCpnt->serial_number, SCpnt); if (*(unsigned int *)SCpnt->host_scribble != i) panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n", - BN(j), i, SCpnt->pid, *(unsigned int *)SCpnt->host_scribble); + BN(j), i, SCpnt->serial_number, *(unsigned int *)SCpnt->host_scribble); sync_dma(i, j); @@ -1835,12 +1835,12 @@ static irqreturn_t ihdlr(int irq, unsigned int j) { (SCpnt->sense_buffer[2] & 0xf) == NOT_READY))) scmd_printk(KERN_INFO, SCpnt, "ihdlr, pid %ld, target_status 0x%x, sense key 0x%x.\n", - SCpnt->pid, spp->target_status, + SCpnt->serial_number, spp->target_status, SCpnt->sense_buffer[2]); HD(j)->target_to[scmd_id(SCpnt)][scmd_channel(SCpnt)] = 0; - if (HD(j)->last_retried_pid == SCpnt->pid) HD(j)->retries = 0; + if (HD(j)->last_retried_pid == SCpnt->serial_number) HD(j)->retries = 0; break; case ASST: /* Selection Time Out */ @@ -1877,7 +1877,7 @@ static irqreturn_t ihdlr(int irq, unsigned int j) { #endif HD(j)->retries++; - HD(j)->last_retried_pid = SCpnt->pid; + HD(j)->last_retried_pid = SCpnt->serial_number; } else status = DID_ERROR << 16; @@ -1907,7 +1907,7 @@ static irqreturn_t ihdlr(int irq, unsigned int j) { #endif scmd_printk(KERN_INFO, SCpnt, "ihdlr, mbox %2d, err 0x%x:%x,"\ " pid %ld, reg 0x%x, count %d.\n", - i, spp->adapter_status, spp->target_status, SCpnt->pid, + i, spp->adapter_status, spp->target_status, SCpnt->serial_number, reg, HD(j)->iocount); unmap_dma(i, j); diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c index b92ff047af38..0e8e642fd3b0 100644 --- a/drivers/scsi/wd33c93.c +++ b/drivers/scsi/wd33c93.c @@ -381,7 +381,7 @@ wd33c93_queuecommand(struct scsi_cmnd *cmd, hostdata = (struct WD33C93_hostdata *) cmd->device->host->hostdata; DB(DB_QUEUE_COMMAND, - printk("Q-%d-%02x-%ld( ", cmd->device->id, cmd->cmnd[0], cmd->pid)) + printk("Q-%d-%02x-%ld( ", cmd->device->id, cmd->cmnd[0], cmd->serial_number)) /* Set up a few fields in the scsi_cmnd structure for our own use: * - host_scribble is the pointer to the next cmd in the input queue @@ -463,7 +463,7 @@ wd33c93_queuecommand(struct scsi_cmnd *cmd, wd33c93_execute(cmd->device->host); - DB(DB_QUEUE_COMMAND, printk(")Q-%ld ", cmd->pid)) + DB(DB_QUEUE_COMMAND, printk(")Q-%ld ", cmd->serial_number)) spin_unlock_irq(&hostdata->lock); return 0; @@ -686,7 +686,7 @@ wd33c93_execute(struct Scsi_Host *instance) */ DB(DB_EXECUTE, - printk("%s%ld)EX-2 ", (cmd->SCp.phase) ? "d:" : "", cmd->pid)) + printk("%s%ld)EX-2 ", (cmd->SCp.phase) ? "d:" : "", cmd->serial_number)) } static void @@ -963,7 +963,7 @@ wd33c93_intr(struct Scsi_Host *instance) case CSR_XFER_DONE | PHS_COMMAND: case CSR_UNEXP | PHS_COMMAND: case CSR_SRV_REQ | PHS_COMMAND: - DB(DB_INTR, printk("CMND-%02x,%ld", cmd->cmnd[0], cmd->pid)) + DB(DB_INTR, printk("CMND-%02x,%ld", cmd->cmnd[0], cmd->serial_number)) transfer_pio(regs, cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR, hostdata); hostdata->state = S_CONNECTED; @@ -1007,7 +1007,7 @@ wd33c93_intr(struct Scsi_Host *instance) switch (msg) { case COMMAND_COMPLETE: - DB(DB_INTR, printk("CCMP-%ld", cmd->pid)) + DB(DB_INTR, printk("CCMP-%ld", cmd->serial_number)) write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK); hostdata->state = S_PRE_CMP_DISC; break; @@ -1174,7 +1174,7 @@ wd33c93_intr(struct Scsi_Host *instance) write_wd33c93(regs, WD_SOURCE_ID, SRCID_ER); if (phs == 0x60) { - DB(DB_INTR, printk("SX-DONE-%ld", cmd->pid)) + DB(DB_INTR, printk("SX-DONE-%ld", cmd->serial_number)) cmd->SCp.Message = COMMAND_COMPLETE; lun = read_wd33c93(regs, WD_TARGET_LUN); DB(DB_INTR, printk(":%d.%d", cmd->SCp.Status, lun)) @@ -1201,7 +1201,7 @@ wd33c93_intr(struct Scsi_Host *instance) } else { printk ("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---", - asr, sr, phs, cmd->pid); + asr, sr, phs, cmd->serial_number); spin_unlock_irqrestore(&hostdata->lock, flags); } break; @@ -1266,7 +1266,7 @@ wd33c93_intr(struct Scsi_Host *instance) spin_unlock_irqrestore(&hostdata->lock, flags); return; } - DB(DB_INTR, printk("UNEXP_DISC-%ld", cmd->pid)) + DB(DB_INTR, printk("UNEXP_DISC-%ld", cmd->serial_number)) hostdata->connected = NULL; hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); hostdata->state = S_UNCONNECTED; @@ -1292,7 +1292,7 @@ wd33c93_intr(struct Scsi_Host *instance) */ write_wd33c93(regs, WD_SOURCE_ID, SRCID_ER); - DB(DB_INTR, printk("DISC-%ld", cmd->pid)) + DB(DB_INTR, printk("DISC-%ld", cmd->serial_number)) if (cmd == NULL) { printk(" - Already disconnected! "); hostdata->state = S_UNCONNECTED; @@ -1491,7 +1491,7 @@ wd33c93_intr(struct Scsi_Host *instance) } else hostdata->state = S_CONNECTED; - DB(DB_INTR, printk("-%ld", cmd->pid)) + DB(DB_INTR, printk("-%ld", cmd->serial_number)) spin_unlock_irqrestore(&hostdata->lock, flags); break; @@ -1638,7 +1638,7 @@ wd33c93_abort(struct scsi_cmnd * cmd) cmd->result = DID_ABORT << 16; printk ("scsi%d: Abort - removing command %ld from input_Q. ", - instance->host_no, cmd->pid); + instance->host_no, cmd->serial_number); enable_irq(cmd->device->host->irq); cmd->scsi_done(cmd); return SUCCESS; @@ -1663,7 +1663,7 @@ wd33c93_abort(struct scsi_cmnd * cmd) unsigned long timeout; printk("scsi%d: Aborting connected command %ld - ", - instance->host_no, cmd->pid); + instance->host_no, cmd->serial_number); printk("stopping DMA - "); if (hostdata->dma == D_DMA_RUNNING) { @@ -1730,7 +1730,7 @@ wd33c93_abort(struct scsi_cmnd * cmd) if (tmp == cmd) { printk ("scsi%d: Abort - command %ld found on disconnected_Q - ", - instance->host_no, cmd->pid); + instance->host_no, cmd->serial_number); printk("Abort SNOOZE. "); enable_irq(cmd->device->host->irq); return FAILED; @@ -2184,7 +2184,7 @@ wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off if (hd->connected) { cmd = (struct scsi_cmnd *) hd->connected; sprintf(tbuf, " %ld-%d:%d(%02x)", - cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); + cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); strcat(bp, tbuf); } } @@ -2193,7 +2193,7 @@ wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off cmd = (struct scsi_cmnd *) hd->input_Q; while (cmd) { sprintf(tbuf, " %ld-%d:%d(%02x)", - cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); + cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); strcat(bp, tbuf); cmd = (struct scsi_cmnd *) cmd->host_scribble; } @@ -2203,7 +2203,7 @@ wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off cmd = (struct scsi_cmnd *) hd->disconnected_Q; while (cmd) { sprintf(tbuf, " %ld-%d:%d(%02x)", - cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); + cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); strcat(bp, tbuf); cmd = (struct scsi_cmnd *) cmd->host_scribble; } diff --git a/drivers/scsi/zorro7xx.c b/drivers/scsi/zorro7xx.c index c822debc2668..ac67394c7373 100644 --- a/drivers/scsi/zorro7xx.c +++ b/drivers/scsi/zorro7xx.c @@ -69,7 +69,7 @@ static struct zorro_device_id zorro7xx_zorro_tbl[] __devinitdata = { static int __devinit zorro7xx_init_one(struct zorro_dev *z, const struct zorro_device_id *ent) { - struct Scsi_Host * host = NULL; + struct Scsi_Host *host; struct NCR_700_Host_Parameters *hostdata; struct zorro_driver_data *zdd; unsigned long board, ioaddr; @@ -89,14 +89,12 @@ static int __devinit zorro7xx_init_one(struct zorro_dev *z, return -EBUSY; } - hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL); - if (hostdata == NULL) { + hostdata = kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL); + if (!hostdata) { printk(KERN_ERR "zorro7xx: Failed to allocate host data\n"); goto out_release; } - memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters)); - /* Fill in the required pieces of hostdata */ if (ioaddr > 0x01000000) hostdata->base = ioremap(ioaddr, zorro_resource_len(z)); diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index 035cca028199..ec36ad78d2fe 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c @@ -756,8 +756,8 @@ mpc52xx_console_setup(struct console *co, char *options) if (port->membase == NULL) return -EINVAL; - pr_debug("mpc52xx-psc uart at %lx, mapped to %p, irq=%x, freq=%i\n", - port->mapbase, port->membase, port->irq, port->uartclk); + pr_debug("mpc52xx-psc uart at %p, mapped to %p, irq=%x, freq=%i\n", + (void*)port->mapbase, port->membase, port->irq, port->uartclk); /* Setup the port parameters accoding to options */ if (options) @@ -974,8 +974,8 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match) port->mapbase = res.start; port->irq = irq_of_parse_and_map(op->node, 0); - dev_dbg(&op->dev, "mpc52xx-psc uart at %lx, irq=%x, freq=%i\n", - port->mapbase, port->irq, port->uartclk); + dev_dbg(&op->dev, "mpc52xx-psc uart at %p, irq=%x, freq=%i\n", + (void*)port->mapbase, port->irq, port->uartclk); if ((port->irq==NO_IRQ) || !port->mapbase) { printk(KERN_ERR "Could not allocate resources for PSC\n"); diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 053fca41b08a..73440e26834b 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -4,6 +4,7 @@ * SuperH on-chip serial module support. (SCI with no FIFO / with FIFO) * * Copyright (C) 2002 - 2006 Paul Mundt + * Modified to support SH7720 SCIF. Markus Brunner, Mark Jonas (Jul 2007). * * based off of the old drivers/char/sh-sci.c by: * @@ -301,6 +302,38 @@ static void sci_init_pins_scif(struct uart_port* port, unsigned int cflag) } sci_out(port, SCFCR, fcr_val); } +#elif defined(CONFIG_CPU_SUBTYPE_SH7720) +static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) +{ + unsigned int fcr_val = 0; + unsigned short data; + + if (cflag & CRTSCTS) { + /* enable RTS/CTS */ + if (port->mapbase == 0xa4430000) { /* SCIF0 */ + /* Clear PTCR bit 9-2; enable all scif pins but sck */ + data = ctrl_inw(PORT_PTCR); + ctrl_outw((data & 0xfc03), PORT_PTCR); + } else if (port->mapbase == 0xa4438000) { /* SCIF1 */ + /* Clear PVCR bit 9-2 */ + data = ctrl_inw(PORT_PVCR); + ctrl_outw((data & 0xfc03), PORT_PVCR); + } + fcr_val |= SCFCR_MCE; + } else { + if (port->mapbase == 0xa4430000) { /* SCIF0 */ + /* Clear PTCR bit 5-2; enable only tx and rx */ + data = ctrl_inw(PORT_PTCR); + ctrl_outw((data & 0xffc3), PORT_PTCR); + } else if (port->mapbase == 0xa4438000) { /* SCIF1 */ + /* Clear PVCR bit 5-2 */ + data = ctrl_inw(PORT_PVCR); + ctrl_outw((data & 0xffc3), PORT_PVCR); + } + } + sci_out(port, SCFCR, fcr_val); +} + #elif defined(CONFIG_CPU_SH3) /* For SH7705, SH7706, SH7707, SH7709, SH7709A, SH7729 */ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) @@ -1276,7 +1309,7 @@ static int __init sci_console_init(void) console_initcall(sci_console_init); #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */ -#ifdef CONFIG_SH_KGDB +#ifdef CONFIG_SH_KGDB_CONSOLE /* * FIXME: Most of this can go away.. at the moment, we rely on * arch/sh/kernel/setup.c to do the command line parsing for kgdb, though @@ -1334,9 +1367,7 @@ int __init kgdb_console_setup(struct console *co, char *options) return uart_set_options(port, co, baud, parity, bits, flow); } -#endif /* CONFIG_SH_KGDB */ -#ifdef CONFIG_SH_KGDB_CONSOLE static struct console kgdb_console = { .name = "ttySC", .device = uart_console_device, @@ -1432,7 +1463,7 @@ static int __devinit sci_probe(struct platform_device *dev) #ifdef CONFIG_CPU_FREQ cpufreq_register_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER); - dev_info(&dev->dev, "sci: CPU frequency notifier registered\n"); + dev_info(&dev->dev, "CPU frequency notifier registered\n"); #endif #ifdef CONFIG_SH_STANDARD_BIOS diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index cf75466ebf57..e89ae29645d6 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h @@ -10,19 +10,19 @@ * Modified to support SH7300(SH-Mobile) SCIF. Takashi Kusuda (Jun 2003). * Modified to support H8/300 Series Yoshinori Sato (Feb 2004). * Removed SH7300 support (Jul 2007). + * Modified to support SH7720 SCIF. Markus Brunner, Mark Jonas (Aug 2007). */ #include <linux/serial_core.h> #include <asm/io.h> -#if defined(__H8300H__) || defined(__H8300S__) #include <asm/gpio.h> + #if defined(CONFIG_H83007) || defined(CONFIG_H83068) #include <asm/regs306x.h> #endif #if defined(CONFIG_H8S2678) #include <asm/regs267x.h> #endif -#endif #if defined(CONFIG_CPU_SUBTYPE_SH7706) || \ defined(CONFIG_CPU_SUBTYPE_SH7707) || \ @@ -46,6 +46,10 @@ */ # define SCSCR_INIT(port) (port->mapbase == SCIF2) ? 0xF3 : 0xF0 # define SCIF_ONLY +#elif defined(CONFIG_CPU_SUBTYPE_SH7720) +# define SCSCR_INIT(port) 0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */ +# define SCIF_ONLY +#define SCIF_ORER 0x0200 /* overrun error bit */ #elif defined(CONFIG_SH_RTS7751R2D) # define SCSPTR2 0xFFE80020 /* 16 bit SCIF */ # define SCIF_ORER 0x0001 /* overrun error bit */ @@ -217,7 +221,8 @@ #define SCIF_RDF 0x0002 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */ #define SCIF_DR 0x0001 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */ -#if defined(CONFIG_CPU_SUBTYPE_SH7705) +#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ + defined(CONFIG_CPU_SUBTYPE_SH7720) #define SCIF_ORER 0x0200 #define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK | SCIF_ORER) #define SCIF_RFDC_MASK 0x007f @@ -254,7 +259,8 @@ # define SCxSR_FER(port) SCIF_FER # define SCxSR_PER(port) SCIF_PER # define SCxSR_BRK(port) SCIF_BRK -#if defined(CONFIG_CPU_SUBTYPE_SH7705) +#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ + defined(CONFIG_CPU_SUBTYPE_SH7720) # define SCxSR_RDxF_CLEAR(port) (sci_in(port,SCxSR)&0xfffc) # define SCxSR_ERROR_CLEAR(port) (sci_in(port,SCxSR)&0xfd73) # define SCxSR_TDxE_CLEAR(port) (sci_in(port,SCxSR)&0xffdf) @@ -362,7 +368,8 @@ CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size) #define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) -#elif defined(CONFIG_CPU_SUBTYPE_SH7705) +#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \ + defined(CONFIG_CPU_SUBTYPE_SH7720) #define SCIF_FNS(name, scif_offset, scif_size) \ CPU_SCIF_FNS(name, scif_offset, scif_size) #else @@ -388,7 +395,8 @@ CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) #endif -#if defined(CONFIG_CPU_SUBTYPE_SH7705) +#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ + defined(CONFIG_CPU_SUBTYPE_SH7720) SCIF_FNS(SCSMR, 0x00, 16) SCIF_FNS(SCBRR, 0x04, 8) @@ -510,7 +518,15 @@ static inline void set_sh771x_scif_pfc(struct uart_port *port) return; } } - +#elif defined(CONFIG_CPU_SUBTYPE_SH7720) +static inline int sci_rxd_in(struct uart_port *port) +{ + if (port->mapbase == 0xa4430000) + return sci_in(port, SCxSR) & 0x0003 ? 1 : 0; + else if (port->mapbase == 0xa4438000) + return sci_in(port, SCxSR) & 0x0003 ? 1 : 0; + return 1; +} #elif defined(CONFIG_CPU_SUBTYPE_SH7750) || \ defined(CONFIG_CPU_SUBTYPE_SH7751) || \ defined(CONFIG_CPU_SUBTYPE_SH7751R) || \ @@ -653,6 +669,7 @@ static inline int sci_rxd_in(struct uart_port *port) return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */ if (port->mapbase == 0xffc60000) return ctrl_inw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */ + return 1; } #endif @@ -691,7 +708,8 @@ static inline int sci_rxd_in(struct uart_port *port) #if defined(CONFIG_CPU_SUBTYPE_SH7780) || \ defined(CONFIG_CPU_SUBTYPE_SH7785) #define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(16*bps)-1) -#elif defined(CONFIG_CPU_SUBTYPE_SH7705) +#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \ + defined(CONFIG_CPU_SUBTYPE_SH7720) #define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1) #elif defined(__H8300H__) || defined(__H8300S__) #define SCBRR_VALUE(bps) (((CONFIG_CPU_CLOCK*1000/32)/bps)-1) diff --git a/drivers/sh/Makefile b/drivers/sh/Makefile index 8a143894e33f..a96f4a8cfeb8 100644 --- a/drivers/sh/Makefile +++ b/drivers/sh/Makefile @@ -2,5 +2,5 @@ # Makefile for the SuperH specific drivers. # -obj-$(CONFIG_SUPERHYWAY) += superhyway/ - +obj-$(CONFIG_SUPERHYWAY) += superhyway/ +obj-$(CONFIG_MAPLE) += maple/ diff --git a/drivers/sh/maple/Makefile b/drivers/sh/maple/Makefile new file mode 100644 index 000000000000..65dfeeb610ef --- /dev/null +++ b/drivers/sh/maple/Makefile @@ -0,0 +1,3 @@ +# Makefile for Maple Bus + +obj-$(CONFIG_MAPLE) := maple.o diff --git a/drivers/sh/maple/maple.c b/drivers/sh/maple/maple.c new file mode 100644 index 000000000000..161d1021b7eb --- /dev/null +++ b/drivers/sh/maple/maple.c @@ -0,0 +1,735 @@ +/* + * Core maple bus functionality + * + * Copyright (C) 2007 Adrian McMenamin + * + * Based on 2.4 code by: + * + * Copyright (C) 2000-2001 YAEGASHI Takeshi + * Copyright (C) 2001 M. R. Brown + * Copyright (C) 2001 Paul Mundt + * + * and others. + * + * 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. + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/maple.h> +#include <linux/dma-mapping.h> +#include <asm/cacheflush.h> +#include <asm/dma.h> +#include <asm/io.h> +#include <asm/mach/dma.h> +#include <asm/mach/sysasic.h> +#include <asm/mach/maple.h> + +MODULE_AUTHOR("Yaegshi Takeshi, Paul Mundt, M.R. Brown, Adrian McMenamin"); +MODULE_DESCRIPTION("Maple bus driver for Dreamcast"); +MODULE_LICENSE("GPL v2"); +MODULE_SUPPORTED_DEVICE("{{SEGA, Dreamcast/Maple}}"); + +static void maple_dma_handler(struct work_struct *work); +static void maple_vblank_handler(struct work_struct *work); + +static DECLARE_WORK(maple_dma_process, maple_dma_handler); +static DECLARE_WORK(maple_vblank_process, maple_vblank_handler); + +static LIST_HEAD(maple_waitq); +static LIST_HEAD(maple_sentq); + +static DEFINE_MUTEX(maple_list_lock); + +static struct maple_driver maple_dummy_driver; +static struct device maple_bus; +static int subdevice_map[MAPLE_PORTS]; +static unsigned long *maple_sendbuf, *maple_sendptr, *maple_lastptr; +static unsigned long maple_pnp_time; +static int started, scanning, liststatus; +static struct kmem_cache *maple_queue_cache; + +struct maple_device_specify { + int port; + int unit; +}; + +/** + * maple_driver_register - register a device driver + * automatically makes the driver bus a maple bus + * @drv: the driver to be registered + */ +int maple_driver_register(struct device_driver *drv) +{ + if (!drv) + return -EINVAL; + drv->bus = &maple_bus_type; + return driver_register(drv); +} +EXPORT_SYMBOL_GPL(maple_driver_register); + +/* set hardware registers to enable next round of dma */ +static void maplebus_dma_reset(void) +{ + ctrl_outl(MAPLE_MAGIC, MAPLE_RESET); + /* set trig type to 0 for software trigger, 1 for hardware (VBLANK) */ + ctrl_outl(1, MAPLE_TRIGTYPE); + ctrl_outl(MAPLE_2MBPS | MAPLE_TIMEOUT(50000), MAPLE_SPEED); + ctrl_outl(PHYSADDR(maple_sendbuf), MAPLE_DMAADDR); + ctrl_outl(1, MAPLE_ENABLE); +} + +/** + * maple_getcond_callback - setup handling MAPLE_COMMAND_GETCOND + * @dev: device responding + * @callback: handler callback + * @interval: interval in jiffies between callbacks + * @function: the function code for the device + */ +void maple_getcond_callback(struct maple_device *dev, + void (*callback) (struct mapleq * mq), + unsigned long interval, unsigned long function) +{ + dev->callback = callback; + dev->interval = interval; + dev->function = cpu_to_be32(function); + dev->when = jiffies; +} +EXPORT_SYMBOL_GPL(maple_getcond_callback); + +static int maple_dma_done(void) +{ + return (ctrl_inl(MAPLE_STATE) & 1) == 0; +} + +static void maple_release_device(struct device *dev) +{ + if (dev->type) { + kfree(dev->type->name); + kfree(dev->type); + } +} + +/** + * maple_add_packet - add a single instruction to the queue + * @mq: instruction to add to waiting queue + */ +void maple_add_packet(struct mapleq *mq) +{ + mutex_lock(&maple_list_lock); + list_add(&mq->list, &maple_waitq); + mutex_unlock(&maple_list_lock); +} +EXPORT_SYMBOL_GPL(maple_add_packet); + +static struct mapleq *maple_allocq(struct maple_device *dev) +{ + struct mapleq *mq; + + mq = kmalloc(sizeof(*mq), GFP_KERNEL); + if (!mq) + return NULL; + + mq->dev = dev; + mq->recvbufdcsp = kmem_cache_zalloc(maple_queue_cache, GFP_KERNEL); + mq->recvbuf = (void *) P2SEGADDR(mq->recvbufdcsp); + if (!mq->recvbuf) { + kfree(mq); + return NULL; + } + + return mq; +} + +static struct maple_device *maple_alloc_dev(int port, int unit) +{ + struct maple_device *dev; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return NULL; + + dev->port = port; + dev->unit = unit; + dev->mq = maple_allocq(dev); + + if (!dev->mq) { + kfree(dev); + return NULL; + } + + return dev; +} + +static void maple_free_dev(struct maple_device *mdev) +{ + if (!mdev) + return; + if (mdev->mq) { + kmem_cache_free(maple_queue_cache, mdev->mq->recvbufdcsp); + kfree(mdev->mq); + } + kfree(mdev); +} + +/* process the command queue into a maple command block + * terminating command has bit 32 of first long set to 0 + */ +static void maple_build_block(struct mapleq *mq) +{ + int port, unit, from, to, len; + unsigned long *lsendbuf = mq->sendbuf; + + port = mq->dev->port & 3; + unit = mq->dev->unit; + len = mq->length; + from = port << 6; + to = (port << 6) | (unit > 0 ? (1 << (unit - 1)) & 0x1f : 0x20); + + *maple_lastptr &= 0x7fffffff; + maple_lastptr = maple_sendptr; + + *maple_sendptr++ = (port << 16) | len | 0x80000000; + *maple_sendptr++ = PHYSADDR(mq->recvbuf); + *maple_sendptr++ = + mq->command | (to << 8) | (from << 16) | (len << 24); + + while (len-- > 0) + *maple_sendptr++ = *lsendbuf++; +} + +/* build up command queue */ +static void maple_send(void) +{ + int i; + int maple_packets; + struct mapleq *mq, *nmq; + + if (!list_empty(&maple_sentq)) + return; + if (list_empty(&maple_waitq) || !maple_dma_done()) + return; + maple_packets = 0; + maple_sendptr = maple_lastptr = maple_sendbuf; + list_for_each_entry_safe(mq, nmq, &maple_waitq, list) { + maple_build_block(mq); + list_move(&mq->list, &maple_sentq); + if (maple_packets++ > MAPLE_MAXPACKETS) + break; + } + if (maple_packets > 0) { + for (i = 0; i < (1 << MAPLE_DMA_PAGES); i++) + dma_cache_sync(0, maple_sendbuf + i * PAGE_SIZE, + PAGE_SIZE, DMA_BIDIRECTIONAL); + } +} + +static int attach_matching_maple_driver(struct device_driver *driver, + void *devptr) +{ + struct maple_driver *maple_drv; + struct maple_device *mdev; + + mdev = devptr; + maple_drv = to_maple_driver(driver); + if (mdev->devinfo.function & be32_to_cpu(maple_drv->function)) { + if (maple_drv->connect(mdev) == 0) { + mdev->driver = maple_drv; + return 1; + } + } + return 0; +} + +static void maple_detach_driver(struct maple_device *mdev) +{ + if (!mdev) + return; + if (mdev->driver) { + if (mdev->driver->disconnect) + mdev->driver->disconnect(mdev); + } + mdev->driver = NULL; + if (mdev->registered) { + maple_release_device(&mdev->dev); + device_unregister(&mdev->dev); + } + mdev->registered = 0; + maple_free_dev(mdev); +} + +/* process initial MAPLE_COMMAND_DEVINFO for each device or port */ +static void maple_attach_driver(struct maple_device *dev) +{ + char *p; + + char *recvbuf; + unsigned long function; + int matched, retval; + + recvbuf = dev->mq->recvbuf; + memcpy(&dev->devinfo, recvbuf + 4, sizeof(dev->devinfo)); + memcpy(dev->product_name, dev->devinfo.product_name, 30); + memcpy(dev->product_licence, dev->devinfo.product_licence, 60); + dev->product_name[30] = '\0'; + dev->product_licence[60] = '\0'; + + for (p = dev->product_name + 29; dev->product_name <= p; p--) + if (*p == ' ') + *p = '\0'; + else + break; + + for (p = dev->product_licence + 59; dev->product_licence <= p; p--) + if (*p == ' ') + *p = '\0'; + else + break; + + function = be32_to_cpu(dev->devinfo.function); + + if (function > 0x200) { + /* Do this silently - as not a real device */ + function = 0; + dev->driver = &maple_dummy_driver; + sprintf(dev->dev.bus_id, "%d:0.port", dev->port); + } else { + printk(KERN_INFO + "Maple bus at (%d, %d): Connected function 0x%lX\n", + dev->port, dev->unit, function); + + matched = + bus_for_each_drv(&maple_bus_type, NULL, dev, + attach_matching_maple_driver); + + if (matched == 0) { + /* Driver does not exist yet */ + printk(KERN_INFO + "No maple driver found for this device\n"); + dev->driver = &maple_dummy_driver; + } + + sprintf(dev->dev.bus_id, "%d:0%d.%lX", dev->port, + dev->unit, function); + } + dev->function = function; + dev->dev.bus = &maple_bus_type; + dev->dev.parent = &maple_bus; + dev->dev.release = &maple_release_device; + retval = device_register(&dev->dev); + if (retval) { + printk(KERN_INFO + "Maple bus: Attempt to register device (%x, %x) failed.\n", + dev->port, dev->unit); + maple_free_dev(dev); + } + dev->registered = 1; +} + +/* + * if device has been registered for the given + * port and unit then return 1 - allows identification + * of which devices need to be attached or detached + */ +static int detach_maple_device(struct device *device, void *portptr) +{ + struct maple_device_specify *ds; + struct maple_device *mdev; + + ds = portptr; + mdev = to_maple_dev(device); + if (mdev->port == ds->port && mdev->unit == ds->unit) + return 1; + return 0; +} + +static int setup_maple_commands(struct device *device, void *ignored) +{ + struct maple_device *maple_dev = to_maple_dev(device); + + if ((maple_dev->interval > 0) + && time_after(jiffies, maple_dev->when)) { + maple_dev->when = jiffies + maple_dev->interval; + maple_dev->mq->command = MAPLE_COMMAND_GETCOND; + maple_dev->mq->sendbuf = &maple_dev->function; + maple_dev->mq->length = 1; + maple_add_packet(maple_dev->mq); + liststatus++; + } else { + if (time_after(jiffies, maple_pnp_time)) { + maple_dev->mq->command = MAPLE_COMMAND_DEVINFO; + maple_dev->mq->length = 0; + maple_add_packet(maple_dev->mq); + liststatus++; + } + } + + return 0; +} + +/* VBLANK bottom half - implemented via workqueue */ +static void maple_vblank_handler(struct work_struct *work) +{ + if (!maple_dma_done()) + return; + if (!list_empty(&maple_sentq)) + return; + ctrl_outl(0, MAPLE_ENABLE); + liststatus = 0; + bus_for_each_dev(&maple_bus_type, NULL, NULL, + setup_maple_commands); + if (time_after(jiffies, maple_pnp_time)) + maple_pnp_time = jiffies + MAPLE_PNP_INTERVAL; + if (liststatus && list_empty(&maple_sentq)) { + INIT_LIST_HEAD(&maple_sentq); + maple_send(); + } + maplebus_dma_reset(); +} + +/* handle devices added via hotplugs - placing them on queue for DEVINFO*/ +static void maple_map_subunits(struct maple_device *mdev, int submask) +{ + int retval, k, devcheck; + struct maple_device *mdev_add; + struct maple_device_specify ds; + + for (k = 0; k < 5; k++) { + ds.port = mdev->port; + ds.unit = k + 1; + retval = + bus_for_each_dev(&maple_bus_type, NULL, &ds, + detach_maple_device); + if (retval) { + submask = submask >> 1; + continue; + } + devcheck = submask & 0x01; + if (devcheck) { + mdev_add = maple_alloc_dev(mdev->port, k + 1); + if (!mdev_add) + return; + mdev_add->mq->command = MAPLE_COMMAND_DEVINFO; + mdev_add->mq->length = 0; + maple_add_packet(mdev_add->mq); + scanning = 1; + } + submask = submask >> 1; + } +} + +/* mark a device as removed */ +static void maple_clean_submap(struct maple_device *mdev) +{ + int killbit; + + killbit = (mdev->unit > 0 ? (1 << (mdev->unit - 1)) & 0x1f : 0x20); + killbit = ~killbit; + killbit &= 0xFF; + subdevice_map[mdev->port] = subdevice_map[mdev->port] & killbit; +} + +/* handle empty port or hotplug removal */ +static void maple_response_none(struct maple_device *mdev, + struct mapleq *mq) +{ + if (mdev->unit != 0) { + list_del(&mq->list); + maple_clean_submap(mdev); + printk(KERN_INFO + "Maple bus device detaching at (%d, %d)\n", + mdev->port, mdev->unit); + maple_detach_driver(mdev); + return; + } + if (!started) { + printk(KERN_INFO "No maple devices attached to port %d\n", + mdev->port); + return; + } + maple_clean_submap(mdev); +} + +/* preprocess hotplugs or scans */ +static void maple_response_devinfo(struct maple_device *mdev, + char *recvbuf) +{ + char submask; + if ((!started) || (scanning == 2)) { + maple_attach_driver(mdev); + return; + } + if (mdev->unit == 0) { + submask = recvbuf[2] & 0x1F; + if (submask ^ subdevice_map[mdev->port]) { + maple_map_subunits(mdev, submask); + subdevice_map[mdev->port] = submask; + } + } +} + +/* maple dma end bottom half - implemented via workqueue */ +static void maple_dma_handler(struct work_struct *work) +{ + struct mapleq *mq, *nmq; + struct maple_device *dev; + char *recvbuf; + enum maple_code code; + + if (!maple_dma_done()) + return; + ctrl_outl(0, MAPLE_ENABLE); + if (!list_empty(&maple_sentq)) { + list_for_each_entry_safe(mq, nmq, &maple_sentq, list) { + recvbuf = mq->recvbuf; + code = recvbuf[0]; + dev = mq->dev; + switch (code) { + case MAPLE_RESPONSE_NONE: + maple_response_none(dev, mq); + break; + + case MAPLE_RESPONSE_DEVINFO: + maple_response_devinfo(dev, recvbuf); + break; + + case MAPLE_RESPONSE_DATATRF: + if (dev->callback) + dev->callback(mq); + break; + + case MAPLE_RESPONSE_FILEERR: + case MAPLE_RESPONSE_AGAIN: + case MAPLE_RESPONSE_BADCMD: + case MAPLE_RESPONSE_BADFUNC: + printk(KERN_DEBUG + "Maple non-fatal error 0x%X\n", + code); + break; + + case MAPLE_RESPONSE_ALLINFO: + printk(KERN_DEBUG + "Maple - extended device information not supported\n"); + break; + + case MAPLE_RESPONSE_OK: + break; + + default: + break; + } + } + INIT_LIST_HEAD(&maple_sentq); + if (scanning == 1) { + maple_send(); + scanning = 2; + } else + scanning = 0; + + if (started == 0) + started = 1; + } + maplebus_dma_reset(); +} + +static irqreturn_t maplebus_dma_interrupt(int irq, void *dev_id) +{ + /* Load everything into the bottom half */ + schedule_work(&maple_dma_process); + return IRQ_HANDLED; +} + +static irqreturn_t maplebus_vblank_interrupt(int irq, void *dev_id) +{ + schedule_work(&maple_vblank_process); + return IRQ_HANDLED; +} + +static struct irqaction maple_dma_irq = { + .name = "maple bus DMA handler", + .handler = maplebus_dma_interrupt, + .flags = IRQF_SHARED, +}; + +static struct irqaction maple_vblank_irq = { + .name = "maple bus VBLANK handler", + .handler = maplebus_vblank_interrupt, + .flags = IRQF_SHARED, +}; + +static int maple_set_dma_interrupt_handler(void) +{ + return setup_irq(HW_EVENT_MAPLE_DMA, &maple_dma_irq); +} + +static int maple_set_vblank_interrupt_handler(void) +{ + return setup_irq(HW_EVENT_VSYNC, &maple_vblank_irq); +} + +static int maple_get_dma_buffer(void) +{ + maple_sendbuf = + (void *) __get_free_pages(GFP_KERNEL | __GFP_ZERO, + MAPLE_DMA_PAGES); + if (!maple_sendbuf) + return -ENOMEM; + return 0; +} + +static int match_maple_bus_driver(struct device *devptr, + struct device_driver *drvptr) +{ + struct maple_driver *maple_drv; + struct maple_device *maple_dev; + + maple_drv = container_of(drvptr, struct maple_driver, drv); + maple_dev = container_of(devptr, struct maple_device, dev); + /* Trap empty port case */ + if (maple_dev->devinfo.function == 0xFFFFFFFF) + return 0; + else if (maple_dev->devinfo.function & + be32_to_cpu(maple_drv->function)) + return 1; + return 0; +} + +static int maple_bus_uevent(struct device *dev, char **envp, + int num_envp, char *buffer, int buffer_size) +{ + return 0; +} + +static void maple_bus_release(struct device *dev) +{ +} + +static struct maple_driver maple_dummy_driver = { + .drv = { + .name = "maple_dummy_driver", + .bus = &maple_bus_type, + }, +}; + +struct bus_type maple_bus_type = { + .name = "maple", + .match = match_maple_bus_driver, + .uevent = maple_bus_uevent, +}; +EXPORT_SYMBOL_GPL(maple_bus_type); + +static struct device maple_bus = { + .bus_id = "maple", + .release = maple_bus_release, +}; + +static int __init maple_bus_init(void) +{ + int retval, i; + struct maple_device *mdev[MAPLE_PORTS]; + ctrl_outl(0, MAPLE_STATE); + + retval = device_register(&maple_bus); + if (retval) + goto cleanup; + + retval = bus_register(&maple_bus_type); + if (retval) + goto cleanup_device; + + retval = driver_register(&maple_dummy_driver.drv); + + if (retval) + goto cleanup_bus; + + /* allocate memory for maple bus dma */ + retval = maple_get_dma_buffer(); + if (retval) { + printk(KERN_INFO + "Maple bus: Failed to allocate Maple DMA buffers\n"); + goto cleanup_basic; + } + + /* set up DMA interrupt handler */ + retval = maple_set_dma_interrupt_handler(); + if (retval) { + printk(KERN_INFO + "Maple bus: Failed to grab maple DMA IRQ\n"); + goto cleanup_dma; + } + + /* set up VBLANK interrupt handler */ + retval = maple_set_vblank_interrupt_handler(); + if (retval) { + printk(KERN_INFO "Maple bus: Failed to grab VBLANK IRQ\n"); + goto cleanup_irq; + } + + maple_queue_cache = + kmem_cache_create("maple_queue_cache", 0x400, 0, + SLAB_HWCACHE_ALIGN, NULL); + + if (!maple_queue_cache) + goto cleanup_bothirqs; + + /* setup maple ports */ + for (i = 0; i < MAPLE_PORTS; i++) { + mdev[i] = maple_alloc_dev(i, 0); + if (!mdev[i]) { + while (i-- > 0) + maple_free_dev(mdev[i]); + goto cleanup_cache; + } + mdev[i]->registered = 0; + mdev[i]->mq->command = MAPLE_COMMAND_DEVINFO; + mdev[i]->mq->length = 0; + maple_attach_driver(mdev[i]); + maple_add_packet(mdev[i]->mq); + subdevice_map[i] = 0; + } + + /* setup maplebus hardware */ + maplebus_dma_reset(); + + /* initial detection */ + maple_send(); + + maple_pnp_time = jiffies; + + printk(KERN_INFO "Maple bus core now registered.\n"); + + return 0; + +cleanup_cache: + kmem_cache_destroy(maple_queue_cache); + +cleanup_bothirqs: + free_irq(HW_EVENT_VSYNC, 0); + +cleanup_irq: + free_irq(HW_EVENT_MAPLE_DMA, 0); + +cleanup_dma: + free_pages((unsigned long) maple_sendbuf, MAPLE_DMA_PAGES); + +cleanup_basic: + driver_unregister(&maple_dummy_driver.drv); + +cleanup_bus: + bus_unregister(&maple_bus_type); + +cleanup_device: + device_unregister(&maple_bus); + +cleanup: + printk(KERN_INFO "Maple bus registration failed\n"); + return retval; +} +subsys_initcall(maple_bus_init); diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index e84d21597943..bcb8dd5fb0b4 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -67,14 +67,11 @@ static int spi_match_device(struct device *dev, struct device_driver *drv) return strncmp(spi->modalias, drv->name, BUS_ID_SIZE) == 0; } -static int spi_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int spi_uevent(struct device *dev, struct kobj_uevent_env *env) { const struct spi_device *spi = to_spi_device(dev); - envp[0] = buffer; - snprintf(buffer, buffer_size, "MODALIAS=%s", spi->modalias); - envp[1] = NULL; + add_uevent_var(env, "MODALIAS=%s", spi->modalias); return 0; } diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 74d5182db4b2..c12a741b5574 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -11,6 +11,7 @@ #include "ssb_private.h" #include <linux/delay.h> +#include <linux/io.h> #include <linux/ssb/ssb.h> #include <linux/ssb/ssb_regs.h> #include <linux/dma-mapping.h> @@ -320,23 +321,17 @@ static int ssb_bus_match(struct device *dev, struct device_driver *drv) return 0; } -static int ssb_device_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int ssb_device_uevent(struct device *dev, struct kobj_uevent_env *env) { struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); - int ret, i = 0, length = 0; if (!dev) return -ENODEV; - ret = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, + return add_uevent_var(env, "MODALIAS=ssb:v%04Xid%04Xrev%02X", ssb_dev->id.vendor, ssb_dev->id.coreid, ssb_dev->id.revision); - envp[i] = NULL; - - return ret; } static struct bus_type ssb_bustype = { diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c index 7c773603b402..b6abee846f02 100644 --- a/drivers/ssb/pcmcia.c +++ b/drivers/ssb/pcmcia.c @@ -10,6 +10,7 @@ #include <linux/ssb/ssb.h> #include <linux/delay.h> +#include <linux/io.h> #include <pcmcia/cs_types.h> #include <pcmcia/cs.h> diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index ac49b15fa768..516a6400db43 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -28,27 +28,7 @@ obj-$(CONFIG_USB_MICROTEK) += image/ obj-$(CONFIG_USB_SERIAL) += serial/ -obj-$(CONFIG_USB_ADUTUX) += misc/ -obj-$(CONFIG_USB_APPLEDISPLAY) += misc/ -obj-$(CONFIG_USB_AUERSWALD) += misc/ -obj-$(CONFIG_USB_BERRY_CHARGE) += misc/ -obj-$(CONFIG_USB_CYPRESS_CY7C63)+= misc/ -obj-$(CONFIG_USB_CYTHERM) += misc/ -obj-$(CONFIG_USB_EMI26) += misc/ -obj-$(CONFIG_USB_EMI62) += misc/ -obj-$(CONFIG_USB_FTDI_ELAN) += misc/ -obj-$(CONFIG_USB_IDMOUSE) += misc/ -obj-$(CONFIG_USB_LCD) += misc/ -obj-$(CONFIG_USB_LD) += misc/ -obj-$(CONFIG_USB_LED) += misc/ -obj-$(CONFIG_USB_LEGOTOWER) += misc/ -obj-$(CONFIG_USB_PHIDGETSERVO) += misc/ -obj-$(CONFIG_USB_RIO500) += misc/ -obj-$(CONFIG_USB_SISUSBVGA) += misc/ -obj-$(CONFIG_USB_TEST) += misc/ -obj-$(CONFIG_USB_TRANCEVIBRATOR)+= misc/ -obj-$(CONFIG_USB_USS720) += misc/ -obj-$(CONFIG_USB_IOWARRIOR) += misc/ +obj-$(CONFIG_USB) += misc/ obj-$(CONFIG_USB_ATM) += atm/ obj-$(CONFIG_USB_SPEEDTOUCH) += atm/ diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index a73e714288e5..a51eeedc18d4 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -482,7 +482,9 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm, int rbuflen = ((rsize - 1) / stride + 1) * CMD_PACKET_SIZE; if (wbuflen > PAGE_SIZE || rbuflen > PAGE_SIZE) { - dbg("too big transfer requested"); + if (printk_ratelimit()) + usb_err(instance->usbatm, "requested transfer size too large (%d, %d)\n", + wbuflen, rbuflen); ret = -ENOMEM; goto fail; } @@ -493,8 +495,9 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm, init_completion(&instance->rcv_done); ret = usb_submit_urb(instance->rcv_urb, GFP_KERNEL); if (ret < 0) { - dbg("submitting read urb for cm %#x failed", cm); - ret = ret; + if (printk_ratelimit()) + usb_err(instance->usbatm, "submit of read urb for cm %#x failed (%d)\n", + cm, ret); goto fail; } @@ -510,27 +513,29 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm, init_completion(&instance->snd_done); ret = usb_submit_urb(instance->snd_urb, GFP_KERNEL); if (ret < 0) { - dbg("submitting write urb for cm %#x failed", cm); - ret = ret; + if (printk_ratelimit()) + usb_err(instance->usbatm, "submit of write urb for cm %#x failed (%d)\n", + cm, ret); goto fail; } ret = cxacru_start_wait_urb(instance->snd_urb, &instance->snd_done, NULL); if (ret < 0) { - dbg("sending cm %#x failed", cm); - ret = ret; + if (printk_ratelimit()) + usb_err(instance->usbatm, "send of cm %#x failed (%d)\n", cm, ret); goto fail; } ret = cxacru_start_wait_urb(instance->rcv_urb, &instance->rcv_done, &actlen); if (ret < 0) { - dbg("receiving cm %#x failed", cm); - ret = ret; + if (printk_ratelimit()) + usb_err(instance->usbatm, "receive of cm %#x failed (%d)\n", cm, ret); goto fail; } if (actlen % CMD_PACKET_SIZE || !actlen) { - dbg("response is not a positive multiple of %d: %#x", - CMD_PACKET_SIZE, actlen); + if (printk_ratelimit()) + usb_err(instance->usbatm, "invalid response length to cm %#x: %d\n", + cm, actlen); ret = -EIO; goto fail; } @@ -538,12 +543,16 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm, /* check the return status and copy the data to the output buffer, if needed */ for (offb = offd = 0; offd < rsize && offb < actlen; offb += CMD_PACKET_SIZE) { if (rbuf[offb] != cm) { - dbg("wrong cm %#x in response", rbuf[offb]); + if (printk_ratelimit()) + usb_err(instance->usbatm, "wrong cm %#x in response to cm %#x\n", + rbuf[offb], cm); ret = -EIO; goto fail; } if (rbuf[offb + 1] != CM_STATUS_SUCCESS) { - dbg("response failed: %#x", rbuf[offb + 1]); + if (printk_ratelimit()) + usb_err(instance->usbatm, "response to cm %#x failed: %#x\n", + cm, rbuf[offb + 1]); ret = -EIO; goto fail; } @@ -582,14 +591,18 @@ static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_requ for (offb = 0; offb < len; ) { int l = le32_to_cpu(buf[offb++]); if (l > stride || l > (len - offb) / 2) { - dbg("wrong data length %#x in response", l); + if (printk_ratelimit()) + usb_err(instance->usbatm, "invalid data length from cm %#x: %d\n", + cm, l); ret = -EIO; goto cleanup; } while (l--) { offd = le32_to_cpu(buf[offb++]); if (offd >= size) { - dbg("wrong index %#x in response", offd); + if (printk_ratelimit()) + usb_err(instance->usbatm, "wrong index #%x in response to cm #%x\n", + offd, cm); ret = -EIO; goto cleanup; } diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index eb0615abff68..7d27c9cf3c43 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -88,7 +88,7 @@ static const unsigned char DEFAULT_MODEM_OPTION[MODEM_OPTION_LENGTH] = { static unsigned int BMaxDSL = DEFAULT_B_MAX_DSL; static unsigned char ModemMode = DEFAULT_MODEM_MODE; static unsigned char ModemOption[MODEM_OPTION_LENGTH]; -static int num_ModemOption; +static unsigned int num_ModemOption; module_param(altsetting, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(altsetting, @@ -251,7 +251,6 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance, { unsigned char *buffer; struct usbatm_data *usbatm = instance->usbatm; - struct usb_interface *intf; struct usb_device *usb_dev = usbatm->usb_dev; int actual_length; int ret = 0; @@ -265,7 +264,7 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance, goto out; } - if (!(intf = usb_ifnum_to_if(usb_dev, 2))) { + if (!usb_ifnum_to_if(usb_dev, 2)) { ret = -ENODEV; usb_dbg(usbatm, "%s: interface not found!\n", __func__); goto out_free; diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 29807d048b04..389c5b164eb2 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -2,7 +2,8 @@ * Copyright (c) 2003, 2004 * Damien Bergamini <damien.bergamini@free.fr>. All rights reserved. * - * Copyright (c) 2005 Matthieu Castet <castet.matthieu@free.fr> + * Copyright (c) 2005-2007 Matthieu Castet <castet.matthieu@free.fr> + * Copyright (c) 2005-2007 Stanislaw Gruszka <stf_xl@wp.pl> * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -107,18 +108,51 @@ #define uea_info(usb_dev, format,args...) \ dev_info(&(usb_dev)->dev ,"[ueagle-atm] " format, ##args) -struct uea_cmvs { +struct intr_pkt; + +/* cmv's from firmware */ +struct uea_cmvs_v1 { u32 address; u16 offset; u32 data; } __attribute__ ((packed)); +struct uea_cmvs_v2 { + u32 group; + u32 address; + u32 offset; + u32 data; +} __attribute__ ((packed)); + +/* information about currently processed cmv */ +struct cmv_dsc_e1 { + u8 function; + u16 idx; + u32 address; + u16 offset; +}; + +struct cmv_dsc_e4 { + u16 function; + u16 offset; + u16 address; + u16 group; +}; + +union cmv_dsc { + struct cmv_dsc_e1 e1; + struct cmv_dsc_e4 e4; +}; + struct uea_softc { struct usb_device *usb_dev; struct usbatm_data *usbatm; int modem_index; unsigned int driver_info; + int annex; +#define ANNEXA 0 +#define ANNEXB 1 int booting; int reset; @@ -127,20 +161,23 @@ struct uea_softc { struct task_struct *kthread; u32 data; - wait_queue_head_t cmv_ack_wait; + u32 data1; + int cmv_ack; + union cmv_dsc cmv_dsc; struct work_struct task; + struct workqueue_struct *work_q; u16 pageno; u16 ovl; const struct firmware *dsp_firm; struct urb *urb_int; - u8 cmv_function; - u16 cmv_idx; - u32 cmv_address; - u16 cmv_offset; + void (*dispatch_cmv) (struct uea_softc *, struct intr_pkt *); + void (*schedule_load_page) (struct uea_softc *, struct intr_pkt *); + int (*stat) (struct uea_softc *); + int (*send_cmvs) (struct uea_softc *); /* keep in sync with eaglectl */ struct uea_stats { @@ -174,10 +211,34 @@ struct uea_softc { #define ELSA_PID_PSTFIRM 0x3350 #define ELSA_PID_PREFIRM 0x3351 +#define ELSA_PID_A_PREFIRM 0x3352 +#define ELSA_PID_A_PSTFIRM 0x3353 +#define ELSA_PID_B_PREFIRM 0x3362 +#define ELSA_PID_B_PSTFIRM 0x3363 + /* - * Sagem USB IDs + * Devolo IDs : pots if (pid & 0x10) */ -#define EAGLE_VID 0x1110 +#define DEVOLO_VID 0x1039 +#define DEVOLO_EAGLE_I_A_PID_PSTFIRM 0x2110 +#define DEVOLO_EAGLE_I_A_PID_PREFIRM 0x2111 + +#define DEVOLO_EAGLE_I_B_PID_PSTFIRM 0x2100 +#define DEVOLO_EAGLE_I_B_PID_PREFIRM 0x2101 + +#define DEVOLO_EAGLE_II_A_PID_PSTFIRM 0x2130 +#define DEVOLO_EAGLE_II_A_PID_PREFIRM 0x2131 + +#define DEVOLO_EAGLE_II_B_PID_PSTFIRM 0x2120 +#define DEVOLO_EAGLE_II_B_PID_PREFIRM 0x2121 + +/* + * Reference design USB IDs + */ +#define ANALOG_VID 0x1110 +#define ADI930_PID_PREFIRM 0x9001 +#define ADI930_PID_PSTFIRM 0x9000 + #define EAGLE_I_PID_PREFIRM 0x9010 /* Eagle I */ #define EAGLE_I_PID_PSTFIRM 0x900F /* Eagle I */ @@ -187,12 +248,12 @@ struct uea_softc { #define EAGLE_II_PID_PREFIRM 0x9022 /* Eagle II */ #define EAGLE_II_PID_PSTFIRM 0x9021 /* Eagle II */ -/* - * Eagle III Pid - */ #define EAGLE_III_PID_PREFIRM 0x9032 /* Eagle III */ #define EAGLE_III_PID_PSTFIRM 0x9031 /* Eagle III */ +#define EAGLE_IV_PID_PREFIRM 0x9042 /* Eagle IV */ +#define EAGLE_IV_PID_PSTFIRM 0x9041 /* Eagle IV */ + /* * USR USB IDs */ @@ -208,11 +269,15 @@ struct uea_softc { #define PREFIRM 0 #define PSTFIRM (1<<7) +#define AUTO_ANNEX_A (1<<8) +#define AUTO_ANNEX_B (1<<9) + enum { ADI930 = 0, EAGLE_I, EAGLE_II, - EAGLE_III + EAGLE_III, + EAGLE_IV }; /* macros for both struct usb_device_id and struct uea_softc */ @@ -221,15 +286,18 @@ enum { #define UEA_CHIP_VERSION(x) \ ((x)->driver_info & 0xf) -#define IS_ISDN(usb_dev) \ - (le16_to_cpu((usb_dev)->descriptor.bcdDevice) & 0x80) +#define IS_ISDN(x) \ + ((x)->annex & ANNEXB) #define INS_TO_USBDEV(ins) ins->usb_dev #define GET_STATUS(data) \ ((data >> 8) & 0xf) + #define IS_OPERATIONAL(sc) \ - (GET_STATUS(sc->stats.phy.state) == 2) + ((UEA_CHIP_VERSION(sc) != EAGLE_IV) ? \ + (GET_STATUS(sc->stats.phy.state) == 2) : \ + (sc->stats.phy.state == 7)) /* * Set of macros to handle unaligned data in the firmware blob. @@ -259,7 +327,8 @@ enum { #define UEA_INTR_PIPE 0x04 #define UEA_ISO_DATA_PIPE 0x08 -#define UEA_SET_BLOCK 0x0001 +#define UEA_E1_SET_BLOCK 0x0001 +#define UEA_E4_SET_BLOCK 0x002c #define UEA_SET_MODE 0x0003 #define UEA_SET_2183_DATA 0x0004 #define UEA_SET_TIMEOUT 0x0011 @@ -275,71 +344,179 @@ enum { #define UEA_MPTX_MAILBOX (0x3fd6 | 0x4000) #define UEA_MPRX_MAILBOX (0x3fdf | 0x4000) -/* structure describing a block within a DSP page */ -struct block_info { +/* block information in eagle4 dsp firmware */ +struct block_index { + __le32 PageOffset; + __le32 NotLastBlock; + __le32 dummy; + __le32 PageSize; + __le32 PageAddress; + __le16 dummy1; + __le16 PageNumber; +} __attribute__ ((packed)); + +#define E4_IS_BOOT_PAGE(PageSize) ((le32_to_cpu(PageSize)) & 0x80000000) +#define E4_PAGE_BYTES(PageSize) ((le32_to_cpu(PageSize) & 0x7fffffff) * 4) + +#define E4_L1_STRING_HEADER 0x10 +#define E4_MAX_PAGE_NUMBER 0x58 +#define E4_NO_SWAPPAGE_HEADERS 0x31 + +/* l1_code is eagle4 dsp firmware format */ +struct l1_code { + u8 string_header[E4_L1_STRING_HEADER]; + u8 page_number_to_block_index[E4_MAX_PAGE_NUMBER]; + struct block_index page_header[E4_NO_SWAPPAGE_HEADERS]; + u8 code [0]; +} __attribute__ ((packed)); + +/* structures describing a block within a DSP page */ +struct block_info_e1 { __le16 wHdr; -#define UEA_BIHDR 0xabcd __le16 wAddress; __le16 wSize; __le16 wOvlOffset; __le16 wOvl; /* overlay */ __le16 wLast; } __attribute__ ((packed)); -#define BLOCK_INFO_SIZE 12 +#define E1_BLOCK_INFO_SIZE 12 + +struct block_info_e4 { + __be16 wHdr; + __u8 bBootPage; + __u8 bPageNumber; + __be32 dwSize; + __be32 dwAddress; + __be16 wReserved; +} __attribute__ ((packed)); +#define E4_BLOCK_INFO_SIZE 14 -/* structure representing a CMV (Configuration and Management Variable) */ -struct cmv { - __le16 wPreamble; -#define PREAMBLE 0x535c - __u8 bDirection; -#define MODEMTOHOST 0x01 -#define HOSTTOMODEM 0x10 - __u8 bFunction; -#define FUNCTION_TYPE(f) ((f) >> 4) -#define MEMACCESS 0x1 -#define ADSLDIRECTIVE 0x7 +#define UEA_BIHDR 0xabcd +#define UEA_RESERVED 0xffff + +/* constants describing cmv type */ +#define E1_PREAMBLE 0x535c +#define E1_MODEMTOHOST 0x01 +#define E1_HOSTTOMODEM 0x10 + +#define E1_MEMACCESS 0x1 +#define E1_ADSLDIRECTIVE 0x7 +#define E1_FUNCTION_TYPE(f) ((f) >> 4) +#define E1_FUNCTION_SUBTYPE(f) ((f) & 0x0f) + +#define E4_MEMACCESS 0 +#define E4_ADSLDIRECTIVE 0xf +#define E4_FUNCTION_TYPE(f) ((f) >> 8) +#define E4_FUNCTION_SIZE(f) ((f) & 0x0f) +#define E4_FUNCTION_SUBTYPE(f) (((f) >> 4) & 0x0f) -#define FUNCTION_SUBTYPE(f) ((f) & 0x0f) /* for MEMACCESS */ -#define REQUESTREAD 0x0 -#define REQUESTWRITE 0x1 -#define REPLYREAD 0x2 -#define REPLYWRITE 0x3 +#define E1_REQUESTREAD 0x0 +#define E1_REQUESTWRITE 0x1 +#define E1_REPLYREAD 0x2 +#define E1_REPLYWRITE 0x3 + +#define E4_REQUESTREAD 0x0 +#define E4_REQUESTWRITE 0x4 +#define E4_REPLYREAD (E4_REQUESTREAD | 1) +#define E4_REPLYWRITE (E4_REQUESTWRITE | 1) + /* for ADSLDIRECTIVE */ -#define KERNELREADY 0x0 -#define MODEMREADY 0x1 +#define E1_KERNELREADY 0x0 +#define E1_MODEMREADY 0x1 -#define MAKEFUNCTION(t, s) (((t) & 0xf) << 4 | ((s) & 0xf)) - __le16 wIndex; - __le32 dwSymbolicAddress; -#define MAKESA(a, b, c, d) \ +#define E4_KERNELREADY 0x0 +#define E4_MODEMREADY 0x1 + +#define E1_MAKEFUNCTION(t, s) (((t) & 0xf) << 4 | ((s) & 0xf)) +#define E4_MAKEFUNCTION(t, st, s) (((t) & 0xf) << 8 | ((st) & 0xf) << 4 | ((s) & 0xf)) + +#define E1_MAKESA(a, b, c, d) \ (((c) & 0xff) << 24 | \ ((d) & 0xff) << 16 | \ ((a) & 0xff) << 8 | \ ((b) & 0xff)) -#define GETSA1(a) ((a >> 8) & 0xff) -#define GETSA2(a) (a & 0xff) -#define GETSA3(a) ((a >> 24) & 0xff) -#define GETSA4(a) ((a >> 16) & 0xff) - -#define SA_CNTL MAKESA('C', 'N', 'T', 'L') -#define SA_DIAG MAKESA('D', 'I', 'A', 'G') -#define SA_INFO MAKESA('I', 'N', 'F', 'O') -#define SA_OPTN MAKESA('O', 'P', 'T', 'N') -#define SA_RATE MAKESA('R', 'A', 'T', 'E') -#define SA_STAT MAKESA('S', 'T', 'A', 'T') + +#define E1_GETSA1(a) ((a >> 8) & 0xff) +#define E1_GETSA2(a) (a & 0xff) +#define E1_GETSA3(a) ((a >> 24) & 0xff) +#define E1_GETSA4(a) ((a >> 16) & 0xff) + +#define E1_SA_CNTL E1_MAKESA('C', 'N', 'T', 'L') +#define E1_SA_DIAG E1_MAKESA('D', 'I', 'A', 'G') +#define E1_SA_INFO E1_MAKESA('I', 'N', 'F', 'O') +#define E1_SA_OPTN E1_MAKESA('O', 'P', 'T', 'N') +#define E1_SA_RATE E1_MAKESA('R', 'A', 'T', 'E') +#define E1_SA_STAT E1_MAKESA('S', 'T', 'A', 'T') + +#define E4_SA_CNTL 1 +#define E4_SA_STAT 2 +#define E4_SA_INFO 3 +#define E4_SA_TEST 4 +#define E4_SA_OPTN 5 +#define E4_SA_RATE 6 +#define E4_SA_DIAG 7 +#define E4_SA_CNFG 8 + +/* structures representing a CMV (Configuration and Management Variable) */ +struct cmv_e1 { + __le16 wPreamble; + __u8 bDirection; + __u8 bFunction; + __le16 wIndex; + __le32 dwSymbolicAddress; __le16 wOffsetAddress; __le32 dwData; } __attribute__ ((packed)); -#define CMV_SIZE 16 -/* structure representing swap information */ -struct swap_info { +struct cmv_e4 { + __be16 wGroup; + __be16 wFunction; + __be16 wOffset; + __be16 wAddress; + __be32 dwData [6]; +} __attribute__ ((packed)); + +/* structures representing swap information */ +struct swap_info_e1 { __u8 bSwapPageNo; __u8 bOvl; /* overlay */ } __attribute__ ((packed)); -/* structure representing interrupt data */ +struct swap_info_e4 { + __u8 bSwapPageNo; +} __attribute__ ((packed)); + +/* structures representing interrupt data */ +#define e1_bSwapPageNo u.e1.s1.swapinfo.bSwapPageNo +#define e1_bOvl u.e1.s1.swapinfo.bOvl +#define e4_bSwapPageNo u.e4.s1.swapinfo.bSwapPageNo + +#define INT_LOADSWAPPAGE 0x0001 +#define INT_INCOMINGCMV 0x0002 + +union intr_data_e1 { + struct { + struct swap_info_e1 swapinfo; + __le16 wDataSize; + } __attribute__ ((packed)) s1; + struct { + struct cmv_e1 cmv; + __le16 wDataSize; + } __attribute__ ((packed)) s2; +} __attribute__ ((packed)); + +union intr_data_e4 { + struct { + struct swap_info_e4 swapinfo; + __le16 wDataSize; + } __attribute__ ((packed)) s1; + struct { + struct cmv_e4 cmv; + __le16 wDataSize; + } __attribute__ ((packed)) s2; +} __attribute__ ((packed)); + struct intr_pkt { __u8 bType; __u8 bNotification; @@ -347,43 +524,48 @@ struct intr_pkt { __le16 wIndex; __le16 wLength; __le16 wInterrupt; -#define INT_LOADSWAPPAGE 0x0001 -#define INT_INCOMINGCMV 0x0002 union { - struct { - struct swap_info swapinfo; - __le16 wDataSize; - } __attribute__ ((packed)) s1; - - struct { - struct cmv cmv; - __le16 wDataSize; - } __attribute__ ((packed)) s2; - } __attribute__ ((packed)) u; -#define bSwapPageNo u.s1.swapinfo.bSwapPageNo -#define bOvl u.s1.swapinfo.bOvl + union intr_data_e1 e1; + union intr_data_e4 e4; + } u; } __attribute__ ((packed)); -#define INTR_PKT_SIZE 28 + +#define E1_INTR_PKT_SIZE 28 +#define E4_INTR_PKT_SIZE 64 static struct usb_driver uea_driver; static DEFINE_MUTEX(uea_mutex); -static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III"}; +static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III", "Eagle IV"}; static int modem_index; static unsigned int debug; -static int use_iso[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = 1}; +static unsigned int altsetting[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = FASTEST_ISO_INTF}; static int sync_wait[NB_MODEM]; static char *cmv_file[NB_MODEM]; +static int annex[NB_MODEM]; module_param(debug, uint, 0644); MODULE_PARM_DESC(debug, "module debug level (0=off,1=on,2=verbose)"); -module_param_array(use_iso, bool, NULL, 0644); -MODULE_PARM_DESC(use_iso, "use isochronous usb pipe for incoming traffic"); +module_param_array(altsetting, uint, NULL, 0644); +MODULE_PARM_DESC(altsetting, "alternate setting for incoming traffic: 0=bulk, " + "1=isoc slowest, ... , 8=isoc fastest (default)"); module_param_array(sync_wait, bool, NULL, 0644); MODULE_PARM_DESC(sync_wait, "wait the synchronisation before starting ATM"); module_param_array(cmv_file, charp, NULL, 0644); MODULE_PARM_DESC(cmv_file, "file name with configuration and management variables"); +module_param_array(annex, uint, NULL, 0644); +MODULE_PARM_DESC(annex, + "manually set annex a/b (0=auto, 1=annex a, 2=annex b)"); + +#define uea_wait(sc, cond, timeo) \ +({ \ + int _r = wait_event_interruptible_timeout(sc->sync_q, \ + (cond) || kthread_should_stop(), timeo); \ + if (kthread_should_stop()) \ + _r = -ENODEV; \ + _r; \ +}) #define UPDATE_ATM_STAT(type, val) \ do { \ @@ -519,6 +701,9 @@ static int uea_load_firmware(struct usb_device *usb, unsigned int ver) case EAGLE_III: fw_name = FW_DIR "eagleIII.fw"; break; + case EAGLE_IV: + fw_name = FW_DIR "eagleIV.fw"; + break; } ret = request_firmware_nowait(THIS_MODULE, 1, fw_name, &usb->dev, usb, uea_upload_pre_firmware); @@ -537,7 +722,7 @@ static int uea_load_firmware(struct usb_device *usb, unsigned int ver) /* * Make sure that the DSP code provided is safe to use. */ -static int check_dsp(u8 *dsp, unsigned int len) +static int check_dsp_e1(u8 *dsp, unsigned int len) { u8 pagecount, blockcount; u16 blocksize; @@ -588,6 +773,51 @@ static int check_dsp(u8 *dsp, unsigned int len) return 0; } +static int check_dsp_e4(u8 *dsp, int len) +{ + int i; + struct l1_code *p = (struct l1_code *) dsp; + unsigned int sum = p->code - dsp; + + if (len < sum) + return 1; + + if (strcmp("STRATIPHY ANEXA", p->string_header) != 0 && + strcmp("STRATIPHY ANEXB", p->string_header) != 0) + return 1; + + for (i = 0; i < E4_MAX_PAGE_NUMBER; i++) { + struct block_index *blockidx; + u8 blockno = p->page_number_to_block_index[i]; + if (blockno >= E4_NO_SWAPPAGE_HEADERS) + continue; + + do { + u64 l; + + if (blockno >= E4_NO_SWAPPAGE_HEADERS) + return 1; + + blockidx = &p->page_header[blockno++]; + if ((u8 *)(blockidx + 1) - dsp >= len) + return 1; + + if (le16_to_cpu(blockidx->PageNumber) != i) + return 1; + + l = E4_PAGE_BYTES(blockidx->PageSize); + sum += l; + l += le32_to_cpu(blockidx->PageOffset); + if (l > len) + return 1; + + /* zero is zero regardless endianes */ + } while (blockidx->NotLastBlock); + } + + return (sum == len) ? 0 : 1; +} + /* * send data to the idma pipe * */ @@ -624,13 +854,18 @@ static int request_dsp(struct uea_softc *sc) int ret; char *dsp_name; - if (UEA_CHIP_VERSION(sc) == ADI930) { - if (IS_ISDN(sc->usb_dev)) + if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { + if (IS_ISDN(sc)) + dsp_name = FW_DIR "DSP4i.bin"; + else + dsp_name = FW_DIR "DSP4p.bin"; + } else if (UEA_CHIP_VERSION(sc) == ADI930) { + if (IS_ISDN(sc)) dsp_name = FW_DIR "DSP9i.bin"; else dsp_name = FW_DIR "DSP9p.bin"; } else { - if (IS_ISDN(sc->usb_dev)) + if (IS_ISDN(sc)) dsp_name = FW_DIR "DSPei.bin"; else dsp_name = FW_DIR "DSPep.bin"; @@ -640,11 +875,16 @@ static int request_dsp(struct uea_softc *sc) if (ret < 0) { uea_err(INS_TO_USBDEV(sc), "requesting firmware %s failed with error %d\n", - dsp_name, ret); + dsp_name, ret); return ret; } - if (check_dsp(sc->dsp_firm->data, sc->dsp_firm->size)) { + if (UEA_CHIP_VERSION(sc) == EAGLE_IV) + ret = check_dsp_e4(sc->dsp_firm->data, sc->dsp_firm->size); + else + ret = check_dsp_e1(sc->dsp_firm->data, sc->dsp_firm->size); + + if (ret) { uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", dsp_name); release_firmware(sc->dsp_firm); @@ -658,12 +898,12 @@ static int request_dsp(struct uea_softc *sc) /* * The uea_load_page() function must be called within a process context */ -static void uea_load_page(struct work_struct *work) +static void uea_load_page_e1(struct work_struct *work) { struct uea_softc *sc = container_of(work, struct uea_softc, task); u16 pageno = sc->pageno; u16 ovl = sc->ovl; - struct block_info bi; + struct block_info_e1 bi; u8 *p; u8 pagecount, blockcount; @@ -716,7 +956,7 @@ static void uea_load_page(struct work_struct *work) bi.wLast = cpu_to_le16((i == blockcount - 1) ? 1 : 0); /* send block info through the IDMA pipe */ - if (uea_idma_write(sc, &bi, BLOCK_INFO_SIZE)) + if (uea_idma_write(sc, &bi, E1_BLOCK_INFO_SIZE)) goto bad2; /* send block data through the IDMA pipe */ @@ -735,17 +975,114 @@ bad1: uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno); } +static void __uea_load_page_e4(struct uea_softc *sc, u8 pageno, int boot) +{ + struct block_info_e4 bi; + struct block_index *blockidx; + struct l1_code *p = (struct l1_code *) sc->dsp_firm->data; + u8 blockno = p->page_number_to_block_index[pageno]; + + bi.wHdr = cpu_to_be16(UEA_BIHDR); + bi.bBootPage = boot; + bi.bPageNumber = pageno; + bi.wReserved = cpu_to_be16(UEA_RESERVED); + + do { + u8 *blockoffset; + unsigned int blocksize; + + blockidx = &p->page_header[blockno]; + blocksize = E4_PAGE_BYTES(blockidx->PageSize); + blockoffset = sc->dsp_firm->data + le32_to_cpu(blockidx->PageOffset); + + bi.dwSize = cpu_to_be32(blocksize); + bi.dwAddress = swab32(blockidx->PageAddress); + + uea_dbg(INS_TO_USBDEV(sc), + "sending block %u for DSP page %u size %u adress %x\n", + blockno, pageno, blocksize, le32_to_cpu(blockidx->PageAddress)); + + /* send block info through the IDMA pipe */ + if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE)) + goto bad; + + /* send block data through the IDMA pipe */ + if (uea_idma_write(sc, blockoffset, blocksize)) + goto bad; + + blockno++; + } while (blockidx->NotLastBlock); + + return; + +bad: + uea_err(INS_TO_USBDEV(sc), "sending DSP block %u failed\n", blockno); + return; +} + +static void uea_load_page_e4(struct work_struct *work) +{ + struct uea_softc *sc = container_of(work, struct uea_softc, task); + u8 pageno = sc->pageno; + int i; + struct block_info_e4 bi; + struct l1_code *p; + + uea_dbg(INS_TO_USBDEV(sc), "sending DSP page %u\n", pageno); + + /* reload firmware when reboot start and it's loaded already */ + if (pageno == 0 && sc->dsp_firm) { + release_firmware(sc->dsp_firm); + sc->dsp_firm = NULL; + } + + if (sc->dsp_firm == NULL && request_dsp(sc) < 0) + return; + + p = (struct l1_code *) sc->dsp_firm->data; + if (pageno >= p->page_header[0].PageNumber) { + uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno); + return; + } + + if (pageno != 0) { + __uea_load_page_e4(sc, pageno, 0); + return; + } + + uea_dbg(INS_TO_USBDEV(sc), + "sending Main DSP page %u\n", p->page_header[0].PageNumber); + + for (i = 0; i < le16_to_cpu(p->page_header[0].PageNumber); i++) { + if (E4_IS_BOOT_PAGE(p->page_header[i].PageSize)) + __uea_load_page_e4(sc, i, 1); + } + + uea_dbg(INS_TO_USBDEV(sc),"sending start bi\n"); + + bi.wHdr = cpu_to_be16(UEA_BIHDR); + bi.bBootPage = 0; + bi.bPageNumber = 0xff; + bi.wReserved = cpu_to_be16(UEA_RESERVED); + bi.dwSize = cpu_to_be32(E4_PAGE_BYTES(p->page_header[0].PageSize)); + bi.dwAddress = swab32(p->page_header[0].PageAddress); + + /* send block info through the IDMA pipe */ + if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE)) + uea_err(INS_TO_USBDEV(sc), "sending DSP start bi failed\n"); +} + static inline void wake_up_cmv_ack(struct uea_softc *sc) { BUG_ON(sc->cmv_ack); sc->cmv_ack = 1; - wake_up(&sc->cmv_ack_wait); + wake_up(&sc->sync_q); } static inline int wait_cmv_ack(struct uea_softc *sc) { - int ret = wait_event_interruptible_timeout(sc->cmv_ack_wait, - sc->cmv_ack, ACK_TIMEOUT); + int ret = uea_wait(sc, sc->cmv_ack , ACK_TIMEOUT); + sc->cmv_ack = 0; uea_dbg(INS_TO_USBDEV(sc), "wait_event_timeout : %d ms\n", @@ -792,33 +1129,68 @@ static int uea_request(struct uea_softc *sc, return 0; } -static int uea_cmv(struct uea_softc *sc, +static int uea_cmv_e1(struct uea_softc *sc, u8 function, u32 address, u16 offset, u32 data) { - struct cmv cmv; + struct cmv_e1 cmv; int ret; uea_enters(INS_TO_USBDEV(sc)); uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Address : %c%c%c%c, " "offset : 0x%04x, data : 0x%08x\n", - FUNCTION_TYPE(function), FUNCTION_SUBTYPE(function), - GETSA1(address), GETSA2(address), GETSA3(address), - GETSA4(address), offset, data); + E1_FUNCTION_TYPE(function), E1_FUNCTION_SUBTYPE(function), + E1_GETSA1(address), E1_GETSA2(address), E1_GETSA3(address), + E1_GETSA4(address), offset, data); + /* we send a request, but we expect a reply */ - sc->cmv_function = function | 0x2; - sc->cmv_idx++; - sc->cmv_address = address; - sc->cmv_offset = offset; + sc->cmv_dsc.e1.function = function | 0x2; + sc->cmv_dsc.e1.idx++; + sc->cmv_dsc.e1.address = address; + sc->cmv_dsc.e1.offset = offset; - cmv.wPreamble = cpu_to_le16(PREAMBLE); - cmv.bDirection = HOSTTOMODEM; + cmv.wPreamble = cpu_to_le16(E1_PREAMBLE); + cmv.bDirection = E1_HOSTTOMODEM; cmv.bFunction = function; - cmv.wIndex = cpu_to_le16(sc->cmv_idx); + cmv.wIndex = cpu_to_le16(sc->cmv_dsc.e1.idx); put_unaligned(cpu_to_le32(address), &cmv.dwSymbolicAddress); cmv.wOffsetAddress = cpu_to_le16(offset); put_unaligned(cpu_to_le32(data >> 16 | data << 16), &cmv.dwData); - ret = uea_request(sc, UEA_SET_BLOCK, UEA_MPTX_START, CMV_SIZE, &cmv); + ret = uea_request(sc, UEA_E1_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv); + if (ret < 0) + return ret; + ret = wait_cmv_ack(sc); + uea_leaves(INS_TO_USBDEV(sc)); + return ret; +} + +static int uea_cmv_e4(struct uea_softc *sc, + u16 function, u16 group, u16 address, u16 offset, u32 data) +{ + struct cmv_e4 cmv; + int ret; + + uea_enters(INS_TO_USBDEV(sc)); + memset(&cmv, 0, sizeof(cmv)); + + uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Group : 0x%04x, " + "Address : 0x%04x, offset : 0x%04x, data : 0x%08x\n", + E4_FUNCTION_TYPE(function), E4_FUNCTION_SUBTYPE(function), + group, address, offset, data); + + /* we send a request, but we expect a reply */ + sc->cmv_dsc.e4.function = function | (0x1 << 4); + sc->cmv_dsc.e4.offset = offset; + sc->cmv_dsc.e4.address = address; + sc->cmv_dsc.e4.group = group; + + cmv.wFunction = cpu_to_be16(function); + cmv.wGroup = cpu_to_be16(group); + cmv.wAddress = cpu_to_be16(address); + cmv.wOffset = cpu_to_be16(offset); + cmv.dwData[0] = cpu_to_be32(data); + + ret = uea_request(sc, UEA_E4_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv); if (ret < 0) return ret; ret = wait_cmv_ack(sc); @@ -826,10 +1198,10 @@ static int uea_cmv(struct uea_softc *sc, return ret; } -static inline int uea_read_cmv(struct uea_softc *sc, +static inline int uea_read_cmv_e1(struct uea_softc *sc, u32 address, u16 offset, u32 *data) { - int ret = uea_cmv(sc, MAKEFUNCTION(MEMACCESS, REQUESTREAD), + int ret = uea_cmv_e1(sc, E1_MAKEFUNCTION(E1_MEMACCESS, E1_REQUESTREAD), address, offset, 0); if (ret < 0) uea_err(INS_TO_USBDEV(sc), @@ -840,10 +1212,27 @@ static inline int uea_read_cmv(struct uea_softc *sc, return ret; } -static inline int uea_write_cmv(struct uea_softc *sc, +static inline int uea_read_cmv_e4(struct uea_softc *sc, + u8 size, u16 group, u16 address, u16 offset, u32 *data) +{ + int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, E4_REQUESTREAD, size), + group, address, offset, 0); + if (ret < 0) + uea_err(INS_TO_USBDEV(sc), + "reading cmv failed with error %d\n", ret); + else { + *data = sc->data; + /* size is in 16-bit word quantities */ + if (size > 2) + *(data + 1) = sc->data1; + } + return ret; +} + +static inline int uea_write_cmv_e1(struct uea_softc *sc, u32 address, u16 offset, u32 data) { - int ret = uea_cmv(sc, MAKEFUNCTION(MEMACCESS, REQUESTWRITE), + int ret = uea_cmv_e1(sc, E1_MAKEFUNCTION(E1_MEMACCESS, E1_REQUESTWRITE), address, offset, data); if (ret < 0) uea_err(INS_TO_USBDEV(sc), @@ -852,12 +1241,48 @@ static inline int uea_write_cmv(struct uea_softc *sc, return ret; } +static inline int uea_write_cmv_e4(struct uea_softc *sc, + u8 size, u16 group, u16 address, u16 offset, u32 data) +{ + int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, E4_REQUESTWRITE, size), + group, address, offset, data); + if (ret < 0) + uea_err(INS_TO_USBDEV(sc), + "writing cmv failed with error %d\n", ret); + + return ret; +} + +static void uea_set_bulk_timeout(struct uea_softc *sc, u32 dsrate) +{ + int ret; + u16 timeout; + + /* in bulk mode the modem have problem with high rate + * changing internal timing could improve things, but the + * value is misterious. + * ADI930 don't support it (-EPIPE error). + */ + + if (UEA_CHIP_VERSION(sc) == ADI930 || + altsetting[sc->modem_index] > 0 || + sc->stats.phy.dsrate == dsrate) + return; + + /* Original timming (1Mbit/s) from ADI (used in windows driver) */ + timeout = (dsrate <= 1024*1024) ? 0 : 1; + ret = uea_request(sc, UEA_SET_TIMEOUT, timeout, 0, NULL); + uea_info(INS_TO_USBDEV(sc), "setting new timeout %d%s\n", + timeout, ret < 0 ? " failed" : ""); + +} + /* * Monitor the modem and update the stat * return 0 if everything is ok * return < 0 if an error occurs (-EAGAIN reboot needed) */ -static int uea_stat(struct uea_softc *sc) +static int uea_stat_e1(struct uea_softc *sc) { u32 data; int ret; @@ -865,7 +1290,7 @@ static int uea_stat(struct uea_softc *sc) uea_enters(INS_TO_USBDEV(sc)); data = sc->stats.phy.state; - ret = uea_read_cmv(sc, SA_STAT, 0, &sc->stats.phy.state); + ret = uea_read_cmv_e1(sc, E1_SA_STAT, 0, &sc->stats.phy.state); if (ret < 0) return ret; @@ -885,7 +1310,7 @@ static int uea_stat(struct uea_softc *sc) case 3: /* fail ... */ uea_info(INS_TO_USBDEV(sc), "modem synchronization failed" - " (may be try other cmv/dsp)\n"); + " (may be try other cmv/dsp)\n"); return -EAGAIN; case 4 ... 6: /* test state */ @@ -923,7 +1348,7 @@ static int uea_stat(struct uea_softc *sc) /* wake up processes waiting for synchronization */ wake_up(&sc->sync_q); - ret = uea_read_cmv(sc, SA_DIAG, 2, &sc->stats.phy.flags); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 2, &sc->stats.phy.flags); if (ret < 0) return ret; sc->stats.phy.mflags |= sc->stats.phy.flags; @@ -937,105 +1362,223 @@ static int uea_stat(struct uea_softc *sc) return 0; } - ret = uea_read_cmv(sc, SA_RATE, 0, &data); + ret = uea_read_cmv_e1(sc, E1_SA_RATE, 0, &data); if (ret < 0) return ret; - /* in bulk mode the modem have problem with high rate - * changing internal timing could improve things, but the - * value is misterious. - * ADI930 don't support it (-EPIPE error). - */ - if (UEA_CHIP_VERSION(sc) != ADI930 - && !use_iso[sc->modem_index] - && sc->stats.phy.dsrate != (data >> 16) * 32) { - /* Original timming from ADI(used in windows driver) - * 0x20ffff>>16 * 32 = 32 * 32 = 1Mbits - */ - u16 timeout = (data <= 0x20ffff) ? 0 : 1; - ret = uea_request(sc, UEA_SET_TIMEOUT, timeout, 0, NULL); - uea_info(INS_TO_USBDEV(sc), - "setting new timeout %d%s\n", timeout, - ret < 0?" failed":""); - } + uea_set_bulk_timeout(sc, (data >> 16) * 32); sc->stats.phy.dsrate = (data >> 16) * 32; sc->stats.phy.usrate = (data & 0xffff) * 32; UPDATE_ATM_STAT(link_rate, sc->stats.phy.dsrate * 1000 / 424); - ret = uea_read_cmv(sc, SA_DIAG, 23, &data); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 23, &data); if (ret < 0) return ret; sc->stats.phy.dsattenuation = (data & 0xff) / 2; - ret = uea_read_cmv(sc, SA_DIAG, 47, &data); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 47, &data); if (ret < 0) return ret; sc->stats.phy.usattenuation = (data & 0xff) / 2; - ret = uea_read_cmv(sc, SA_DIAG, 25, &sc->stats.phy.dsmargin); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 25, &sc->stats.phy.dsmargin); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_DIAG, 49, &sc->stats.phy.usmargin); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 49, &sc->stats.phy.usmargin); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_DIAG, 51, &sc->stats.phy.rxflow); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 51, &sc->stats.phy.rxflow); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_DIAG, 52, &sc->stats.phy.txflow); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 52, &sc->stats.phy.txflow); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_DIAG, 54, &sc->stats.phy.dsunc); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 54, &sc->stats.phy.dsunc); if (ret < 0) return ret; /* only for atu-c */ - ret = uea_read_cmv(sc, SA_DIAG, 58, &sc->stats.phy.usunc); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 58, &sc->stats.phy.usunc); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_DIAG, 53, &sc->stats.phy.dscorr); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 53, &sc->stats.phy.dscorr); if (ret < 0) return ret; /* only for atu-c */ - ret = uea_read_cmv(sc, SA_DIAG, 57, &sc->stats.phy.uscorr); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 57, &sc->stats.phy.uscorr); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_INFO, 8, &sc->stats.phy.vidco); + ret = uea_read_cmv_e1(sc, E1_SA_INFO, 8, &sc->stats.phy.vidco); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_INFO, 13, &sc->stats.phy.vidcpe); + ret = uea_read_cmv_e1(sc, E1_SA_INFO, 13, &sc->stats.phy.vidcpe); if (ret < 0) return ret; return 0; } -static int request_cmvs(struct uea_softc *sc, - struct uea_cmvs **cmvs, const struct firmware **fw) +static int uea_stat_e4(struct uea_softc *sc) { - int ret, size; - u8 *data; + u32 data; + u32 tmp_arr[2]; + int ret; + + uea_enters(INS_TO_USBDEV(sc)); + data = sc->stats.phy.state; + + /* XXX only need to be done before operationnal... */ + ret = uea_read_cmv_e4(sc, 1, E4_SA_STAT, 0, 0, &sc->stats.phy.state); + if (ret < 0) + return ret; + + switch (sc->stats.phy.state) { + case 0x0: /* not yet synchronized */ + case 0x1: + case 0x3: + case 0x4: + uea_dbg(INS_TO_USBDEV(sc), "modem not yet synchronized\n"); + return 0; + case 0x5: /* initialization */ + case 0x6: + case 0x9: + case 0xa: + uea_dbg(INS_TO_USBDEV(sc), "modem initializing\n"); + return 0; + case 0x2: /* fail ... */ + uea_info(INS_TO_USBDEV(sc), "modem synchronization failed" + " (may be try other cmv/dsp)\n"); + return -EAGAIN; + case 0x7: /* operational */ + break; + default: + uea_warn(INS_TO_USBDEV(sc), "unknown state: %x\n", sc->stats.phy.state); + return 0; + } + + if (data != 7) { + uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_OFF, 0, NULL); + uea_info(INS_TO_USBDEV(sc), "modem operational\n"); + + /* release the dsp firmware as it is not needed until + * the next failure + */ + if (sc->dsp_firm) { + release_firmware(sc->dsp_firm); + sc->dsp_firm = NULL; + } + } + + /* always update it as atm layer could not be init when we switch to + * operational state + */ + UPDATE_ATM_STAT(signal, ATM_PHY_SIG_FOUND); + + /* wake up processes waiting for synchronization */ + wake_up(&sc->sync_q); + + /* TODO improve this state machine : + * we need some CMV info : what they do and their unit + * we should find the equivalent of eagle3- CMV + */ + /* check flags */ + ret = uea_read_cmv_e4(sc, 1, E4_SA_DIAG, 0, 0, &sc->stats.phy.flags); + if (ret < 0) + return ret; + sc->stats.phy.mflags |= sc->stats.phy.flags; + + /* in case of a flags ( for example delineation LOSS (& 0x10)), + * we check the status again in order to detect the failure earlier + */ + if (sc->stats.phy.flags) { + uea_dbg(INS_TO_USBDEV(sc), "Stat flag = 0x%x\n", + sc->stats.phy.flags); + if (sc->stats.phy.flags & 1) //delineation LOSS + return -EAGAIN; + if (sc->stats.phy.flags & 0x4000) //Reset Flag + return -EAGAIN; + return 0; + } + + /* rate data may be in upper or lower half of 64 bit word, strange */ + ret = uea_read_cmv_e4(sc, 4, E4_SA_RATE, 0, 0, tmp_arr); + if (ret < 0) + return ret; + data = (tmp_arr[0]) ? tmp_arr[0] : tmp_arr[1]; + sc->stats.phy.usrate = data / 1000; + + ret = uea_read_cmv_e4(sc, 4, E4_SA_RATE, 1, 0, tmp_arr); + if (ret < 0) + return ret; + data = (tmp_arr[0]) ? tmp_arr[0] : tmp_arr[1]; + uea_set_bulk_timeout(sc, data / 1000); + sc->stats.phy.dsrate = data / 1000; + UPDATE_ATM_STAT(link_rate, sc->stats.phy.dsrate * 1000 / 424); + + ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 68, 1, &data); + if (ret < 0) + return ret; + sc->stats.phy.dsattenuation = data / 10; + + ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 69, 1, &data); + if (ret < 0) + return ret; + sc->stats.phy.usattenuation = data / 10; + + ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 68, 3, &data); + if (ret < 0) + return ret; + sc->stats.phy.dsmargin = data / 2; + + ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 69, 3, &data); + if (ret < 0) + return ret; + sc->stats.phy.usmargin = data / 10; + + return 0; +} + +static void cmvs_file_name(struct uea_softc *sc, char *const cmv_name, int ver) +{ + char file_arr[] = "CMVxy.bin"; char *file; - char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */ + /* set proper name corresponding modem version and line type */ if (cmv_file[sc->modem_index] == NULL) { if (UEA_CHIP_VERSION(sc) == ADI930) - file = (IS_ISDN(sc->usb_dev)) ? "CMV9i.bin" : "CMV9p.bin"; + file_arr[3] = '9'; + else if (UEA_CHIP_VERSION(sc) == EAGLE_IV) + file_arr[3] = '4'; else - file = (IS_ISDN(sc->usb_dev)) ? "CMVei.bin" : "CMVep.bin"; + file_arr[3] = 'e'; + + file_arr[4] = IS_ISDN(sc) ? 'i' : 'p'; + file = file_arr; } else file = cmv_file[sc->modem_index]; strcpy(cmv_name, FW_DIR); - strlcat(cmv_name, file, sizeof(cmv_name)); + strlcat(cmv_name, file, FIRMWARE_NAME_MAX); + if (ver == 2) + strlcat(cmv_name, ".v2", FIRMWARE_NAME_MAX); +} + +static int request_cmvs_old(struct uea_softc *sc, + void **cmvs, const struct firmware **fw) +{ + int ret, size; + u8 *data; + char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */ + cmvs_file_name(sc, cmv_name, 1); ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev); if (ret < 0) { uea_err(INS_TO_USBDEV(sc), @@ -1045,16 +1588,197 @@ static int request_cmvs(struct uea_softc *sc, } data = (u8 *) (*fw)->data; - size = *data * sizeof(struct uea_cmvs) + 1; - if (size != (*fw)->size) { - uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", - cmv_name); - release_firmware(*fw); - return -EILSEQ; + size = (*fw)->size; + if (size < 1) + goto err_fw_corrupted; + + if (size != *data * sizeof(struct uea_cmvs_v1) + 1) + goto err_fw_corrupted; + + *cmvs = (void *)(data + 1); + return *data; + +err_fw_corrupted: + uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", cmv_name); + release_firmware(*fw); + return -EILSEQ; +} + +static int request_cmvs(struct uea_softc *sc, + void **cmvs, const struct firmware **fw, int *ver) +{ + int ret, size; + u32 crc; + u8 *data; + char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */ + + cmvs_file_name(sc, cmv_name, 2); + ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev); + if (ret < 0) { + /* if caller can handle old version, try to provide it */ + if (*ver == 1) { + uea_warn(INS_TO_USBDEV(sc), "requesting firmware %s failed, " + "try to get older cmvs\n", cmv_name); + return request_cmvs_old(sc, cmvs, fw); + } + uea_err(INS_TO_USBDEV(sc), + "requesting firmware %s failed with error %d\n", + cmv_name, ret); + return ret; + } + + size = (*fw)->size; + data = (u8 *) (*fw)->data; + if (size < 4 || strncmp(data, "cmv2", 4) != 0) { + if (*ver == 1) { + uea_warn(INS_TO_USBDEV(sc), "firmware %s is corrupted, " + "try to get older cmvs\n", cmv_name); + release_firmware(*fw); + return request_cmvs_old(sc, cmvs, fw); + } + goto err_fw_corrupted; } - *cmvs = (struct uea_cmvs *)(data + 1); + *ver = 2; + + data += 4; + size -= 4; + if (size < 5) + goto err_fw_corrupted; + + crc = FW_GET_LONG(data); + data += 4; + size -= 4; + if (crc32_be(0, data, size) != crc) + goto err_fw_corrupted; + + if (size != *data * sizeof(struct uea_cmvs_v2) + 1) + goto err_fw_corrupted; + + *cmvs = (void *) (data + 1); return *data; + +err_fw_corrupted: + uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", cmv_name); + release_firmware(*fw); + return -EILSEQ; +} + +static int uea_send_cmvs_e1(struct uea_softc *sc) +{ + int i, ret, len; + void *cmvs_ptr; + const struct firmware *cmvs_fw; + int ver = 1; // we can handle v1 cmv firmware version; + + /* Enter in R-IDLE (cmv) until instructed otherwise */ + ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 1); + if (ret < 0) + return ret; + + /* Dump firmware version */ + ret = uea_read_cmv_e1(sc, E1_SA_INFO, 10, &sc->stats.phy.firmid); + if (ret < 0) + return ret; + uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n", + sc->stats.phy.firmid); + + /* get options */ + ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver); + if (ret < 0) + return ret; + + /* send options */ + if (ver == 1) { + struct uea_cmvs_v1 *cmvs_v1 = cmvs_ptr; + + uea_warn(INS_TO_USBDEV(sc), "use deprecated cmvs version, " + "please update your firmware\n"); + + for (i = 0; i < len; i++) { + ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v1[i].address), + FW_GET_WORD(&cmvs_v1[i].offset), + FW_GET_LONG(&cmvs_v1[i].data)); + if (ret < 0) + goto out; + } + } else if (ver == 2) { + struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr; + + for (i = 0; i < len; i++) { + ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v2[i].address), + (u16) FW_GET_LONG(&cmvs_v2[i].offset), + FW_GET_LONG(&cmvs_v2[i].data)); + if (ret < 0) + goto out; + } + } else { + /* This realy should not happen */ + uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver); + goto out; + } + + /* Enter in R-ACT-REQ */ + ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 2); + uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n"); + uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n"); +out: + release_firmware(cmvs_fw); + return ret; +} + +static int uea_send_cmvs_e4(struct uea_softc *sc) +{ + int i, ret, len; + void *cmvs_ptr; + const struct firmware *cmvs_fw; + int ver = 2; // we can only handle v2 cmv firmware version; + + /* Enter in R-IDLE (cmv) until instructed otherwise */ + ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 1); + if (ret < 0) + return ret; + + /* Dump firmware version */ + /* XXX don't read the 3th byte as it is always 6 */ + ret = uea_read_cmv_e4(sc, 2, E4_SA_INFO, 55, 0, &sc->stats.phy.firmid); + if (ret < 0) + return ret; + uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n", + sc->stats.phy.firmid); + + + /* get options */ + ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver); + if (ret < 0) + return ret; + + /* send options */ + if (ver == 2) { + struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr; + + for (i = 0; i < len; i++) { + ret = uea_write_cmv_e4(sc, 1, + FW_GET_LONG(&cmvs_v2[i].group), + FW_GET_LONG(&cmvs_v2[i].address), + FW_GET_LONG(&cmvs_v2[i].offset), + FW_GET_LONG(&cmvs_v2[i].data)); + if (ret < 0) + goto out; + } + } else { + /* This realy should not happen */ + uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver); + goto out; + } + + /* Enter in R-ACT-REQ */ + ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 2); + uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n"); + uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n"); +out: + release_firmware(cmvs_fw); + return ret; } /* Start boot post firmware modem: @@ -1066,9 +1790,7 @@ static int request_cmvs(struct uea_softc *sc, static int uea_start_reset(struct uea_softc *sc) { u16 zero = 0; /* ;-) */ - int i, len, ret; - struct uea_cmvs *cmvs; - const struct firmware *cmvs_fw; + int ret; uea_enters(INS_TO_USBDEV(sc)); uea_info(INS_TO_USBDEV(sc), "(re)booting started\n"); @@ -1093,25 +1815,36 @@ static int uea_start_reset(struct uea_softc *sc) uea_request(sc, UEA_SET_MODE, UEA_START_RESET, 0, NULL); /* original driver use 200ms, but windows driver use 100ms */ - msleep(100); + ret = uea_wait(sc, 0, msecs_to_jiffies(100)); + if (ret < 0) + return ret; /* leave reset mode */ uea_request(sc, UEA_SET_MODE, UEA_END_RESET, 0, NULL); - /* clear tx and rx mailboxes */ - uea_request(sc, UEA_SET_2183_DATA, UEA_MPTX_MAILBOX, 2, &zero); - uea_request(sc, UEA_SET_2183_DATA, UEA_MPRX_MAILBOX, 2, &zero); - uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero); + if (UEA_CHIP_VERSION(sc) != EAGLE_IV) { + /* clear tx and rx mailboxes */ + uea_request(sc, UEA_SET_2183_DATA, UEA_MPTX_MAILBOX, 2, &zero); + uea_request(sc, UEA_SET_2183_DATA, UEA_MPRX_MAILBOX, 2, &zero); + uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero); + } + + ret = uea_wait(sc, 0, msecs_to_jiffies(1000)); + if (ret < 0) + return ret; + + if (UEA_CHIP_VERSION(sc) == EAGLE_IV) + sc->cmv_dsc.e4.function = E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1); + else + sc->cmv_dsc.e1.function = E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY); - msleep(1000); - sc->cmv_function = MAKEFUNCTION(ADSLDIRECTIVE, MODEMREADY); /* demask interrupt */ sc->booting = 0; /* start loading DSP */ sc->pageno = 0; sc->ovl = 0; - schedule_work(&sc->task); + queue_work(sc->work_q, &sc->task); /* wait for modem ready CMV */ ret = wait_cmv_ack(sc); @@ -1120,38 +1853,10 @@ static int uea_start_reset(struct uea_softc *sc) uea_vdbg(INS_TO_USBDEV(sc), "Ready CMV received\n"); - /* Enter in R-IDLE (cmv) until instructed otherwise */ - ret = uea_write_cmv(sc, SA_CNTL, 0, 1); - if (ret < 0) - return ret; - - /* Dump firmware version */ - ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid); + ret = sc->send_cmvs(sc); if (ret < 0) return ret; - uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n", - sc->stats.phy.firmid); - /* get options */ - ret = len = request_cmvs(sc, &cmvs, &cmvs_fw); - if (ret < 0) - return ret; - - /* send options */ - for (i = 0; i < len; i++) { - ret = uea_write_cmv(sc, FW_GET_LONG(&cmvs[i].address), - FW_GET_WORD(&cmvs[i].offset), - FW_GET_LONG(&cmvs[i].data)); - if (ret < 0) - goto out; - } - /* Enter in R-ACT-REQ */ - ret = uea_write_cmv(sc, SA_CNTL, 0, 2); - uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n"); - uea_info(INS_TO_USBDEV(sc), "Modem started, " - "waiting synchronization\n"); -out: - release_firmware(cmvs_fw); sc->reset = 0; uea_leaves(INS_TO_USBDEV(sc)); return ret; @@ -1174,12 +1879,10 @@ static int uea_kthread(void *data) if (ret < 0 || sc->reset) ret = uea_start_reset(sc); if (!ret) - ret = uea_stat(sc); + ret = sc->stat(sc); if (ret != -EAGAIN) - msleep_interruptible(1000); - if (try_to_freeze()) - uea_err(INS_TO_USBDEV(sc), "suspend/resume not supported, " - "please unplug/replug your modem\n"); + uea_wait(sc, 0, msecs_to_jiffies(1000)); + try_to_freeze(); } uea_leaves(INS_TO_USBDEV(sc)); return ret; @@ -1234,7 +1937,6 @@ static int load_XILINX_firmware(struct uea_softc *sc) if (ret < 0) uea_err(sc->usb_dev, "elsa de-assert failed with error %d\n", ret); - err1: release_firmware(fw_entry); err0: @@ -1243,40 +1945,41 @@ err0: } /* The modem send us an ack. First with check if it right */ -static void uea_dispatch_cmv(struct uea_softc *sc, struct cmv* cmv) +static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr) { + struct cmv_dsc_e1 *dsc = &sc->cmv_dsc.e1; + struct cmv_e1 *cmv = &intr->u.e1.s2.cmv; + uea_enters(INS_TO_USBDEV(sc)); - if (le16_to_cpu(cmv->wPreamble) != PREAMBLE) + if (le16_to_cpu(cmv->wPreamble) != E1_PREAMBLE) goto bad1; - if (cmv->bDirection != MODEMTOHOST) + if (cmv->bDirection != E1_MODEMTOHOST) goto bad1; /* FIXME : ADI930 reply wrong preambule (func = 2, sub = 2) to * the first MEMACESS cmv. Ignore it... */ - if (cmv->bFunction != sc->cmv_function) { + if (cmv->bFunction != dsc->function) { if (UEA_CHIP_VERSION(sc) == ADI930 - && cmv->bFunction == MAKEFUNCTION(2, 2)) { - cmv->wIndex = cpu_to_le16(sc->cmv_idx); - put_unaligned(cpu_to_le32(sc->cmv_address), &cmv->dwSymbolicAddress); - cmv->wOffsetAddress = cpu_to_le16(sc->cmv_offset); - } - else + && cmv->bFunction == E1_MAKEFUNCTION(2, 2)) { + cmv->wIndex = cpu_to_le16(dsc->idx); + put_unaligned(cpu_to_le32(dsc->address), &cmv->dwSymbolicAddress); + cmv->wOffsetAddress = cpu_to_le16(dsc->offset); + } else goto bad2; } - if (cmv->bFunction == MAKEFUNCTION(ADSLDIRECTIVE, MODEMREADY)) { + if (cmv->bFunction == E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY)) { wake_up_cmv_ack(sc); uea_leaves(INS_TO_USBDEV(sc)); return; } /* in case of MEMACCESS */ - if (le16_to_cpu(cmv->wIndex) != sc->cmv_idx || - le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) != - sc->cmv_address - || le16_to_cpu(cmv->wOffsetAddress) != sc->cmv_offset) + if (le16_to_cpu(cmv->wIndex) != dsc->idx || + le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) != dsc->address || + le16_to_cpu(cmv->wOffsetAddress) != dsc->offset) goto bad2; sc->data = le32_to_cpu(get_unaligned(&cmv->dwData)); @@ -1289,8 +1992,8 @@ static void uea_dispatch_cmv(struct uea_softc *sc, struct cmv* cmv) bad2: uea_err(INS_TO_USBDEV(sc), "unexpected cmv received," "Function : %d, Subfunction : %d\n", - FUNCTION_TYPE(cmv->bFunction), - FUNCTION_SUBTYPE(cmv->bFunction)); + E1_FUNCTION_TYPE(cmv->bFunction), + E1_FUNCTION_SUBTYPE(cmv->bFunction)); uea_leaves(INS_TO_USBDEV(sc)); return; @@ -1301,6 +2004,61 @@ bad1: uea_leaves(INS_TO_USBDEV(sc)); } +/* The modem send us an ack. First with check if it right */ +static void uea_dispatch_cmv_e4(struct uea_softc *sc, struct intr_pkt *intr) +{ + struct cmv_dsc_e4 *dsc = &sc->cmv_dsc.e4; + struct cmv_e4 *cmv = &intr->u.e4.s2.cmv; + + uea_enters(INS_TO_USBDEV(sc)); + uea_dbg(INS_TO_USBDEV(sc), "cmv %x %x %x %x %x %x\n", + be16_to_cpu(cmv->wGroup), be16_to_cpu(cmv->wFunction), + be16_to_cpu(cmv->wOffset), be16_to_cpu(cmv->wAddress), + be32_to_cpu(cmv->dwData[0]), be32_to_cpu(cmv->dwData[1])); + + if (be16_to_cpu(cmv->wFunction) != dsc->function) + goto bad2; + + if (be16_to_cpu(cmv->wFunction) == E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1)) { + wake_up_cmv_ack(sc); + uea_leaves(INS_TO_USBDEV(sc)); + return; + } + + /* in case of MEMACCESS */ + if (be16_to_cpu(cmv->wOffset) != dsc->offset || + be16_to_cpu(cmv->wGroup) != dsc->group || + be16_to_cpu(cmv->wAddress) != dsc->address) + goto bad2; + + sc->data = be32_to_cpu(cmv->dwData[0]); + sc->data1 = be32_to_cpu(cmv->dwData[1]); + wake_up_cmv_ack(sc); + uea_leaves(INS_TO_USBDEV(sc)); + return; + +bad2: + uea_err(INS_TO_USBDEV(sc), "unexpected cmv received," + "Function : %d, Subfunction : %d\n", + E4_FUNCTION_TYPE(cmv->wFunction), + E4_FUNCTION_SUBTYPE(cmv->wFunction)); + uea_leaves(INS_TO_USBDEV(sc)); + return; +} + +static void uea_schedule_load_page_e1(struct uea_softc *sc, struct intr_pkt *intr) +{ + sc->pageno = intr->e1_bSwapPageNo; + sc->ovl = intr->e1_bOvl >> 4 | intr->e1_bOvl << 4; + queue_work(sc->work_q, &sc->task); +} + +static void uea_schedule_load_page_e4(struct uea_softc *sc, struct intr_pkt *intr) +{ + sc->pageno = intr->e4_bSwapPageNo; + queue_work(sc->work_q, &sc->task); +} + /* * interrupt handler */ @@ -1326,13 +2084,11 @@ static void uea_intr(struct urb *urb) switch (le16_to_cpu(intr->wInterrupt)) { case INT_LOADSWAPPAGE: - sc->pageno = intr->bSwapPageNo; - sc->ovl = intr->bOvl >> 4 | intr->bOvl << 4; - schedule_work(&sc->task); + sc->schedule_load_page(sc, intr); break; case INT_INCOMINGCMV: - uea_dispatch_cmv(sc, &intr->u.s2.cmv); + sc->dispatch_cmv(sc, intr); break; default: @@ -1349,35 +2105,55 @@ resubmit: */ static int uea_boot(struct uea_softc *sc) { - int ret; + int ret, size; struct intr_pkt *intr; uea_enters(INS_TO_USBDEV(sc)); - INIT_WORK(&sc->task, uea_load_page); + if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { + size = E4_INTR_PKT_SIZE; + sc->dispatch_cmv = uea_dispatch_cmv_e4; + sc->schedule_load_page = uea_schedule_load_page_e4; + sc->stat = uea_stat_e4; + sc->send_cmvs = uea_send_cmvs_e4; + INIT_WORK(&sc->task, uea_load_page_e4); + } else { + size = E1_INTR_PKT_SIZE; + sc->dispatch_cmv = uea_dispatch_cmv_e1; + sc->schedule_load_page = uea_schedule_load_page_e1; + sc->stat = uea_stat_e1; + sc->send_cmvs = uea_send_cmvs_e1; + INIT_WORK(&sc->task, uea_load_page_e1); + } + init_waitqueue_head(&sc->sync_q); - init_waitqueue_head(&sc->cmv_ack_wait); + + sc->work_q = create_workqueue("ueagle-dsp"); + if (!sc->work_q) { + uea_err(INS_TO_USBDEV(sc), "cannot allocate workqueue\n"); + uea_leaves(INS_TO_USBDEV(sc)); + return -ENOMEM; + } if (UEA_CHIP_VERSION(sc) == ADI930) load_XILINX_firmware(sc); - intr = kmalloc(INTR_PKT_SIZE, GFP_KERNEL); + intr = kmalloc(size, GFP_KERNEL); if (!intr) { uea_err(INS_TO_USBDEV(sc), "cannot allocate interrupt package\n"); - uea_leaves(INS_TO_USBDEV(sc)); - return -ENOMEM; + goto err0; } sc->urb_int = usb_alloc_urb(0, GFP_KERNEL); if (!sc->urb_int) { uea_err(INS_TO_USBDEV(sc), "cannot allocate interrupt URB\n"); - goto err; + goto err1; } usb_fill_int_urb(sc->urb_int, sc->usb_dev, usb_rcvintpipe(sc->usb_dev, UEA_INTR_PIPE), - intr, INTR_PKT_SIZE, uea_intr, sc, + intr, size, uea_intr, sc, sc->usb_dev->actconfig->interface[0]->altsetting[0]. endpoint[0].desc.bInterval); @@ -1385,7 +2161,7 @@ static int uea_boot(struct uea_softc *sc) if (ret < 0) { uea_err(INS_TO_USBDEV(sc), "urb submition failed with error %d\n", ret); - goto err; + goto err1; } sc->kthread = kthread_run(uea_kthread, sc, "ueagle-atm"); @@ -1399,10 +2175,12 @@ static int uea_boot(struct uea_softc *sc) err2: usb_kill_urb(sc->urb_int); -err: +err1: usb_free_urb(sc->urb_int); sc->urb_int = NULL; kfree(intr); +err0: + destroy_workqueue(sc->work_q); uea_leaves(INS_TO_USBDEV(sc)); return -ENOMEM; } @@ -1417,15 +2195,15 @@ static void uea_stop(struct uea_softc *sc) ret = kthread_stop(sc->kthread); uea_dbg(INS_TO_USBDEV(sc), "kthread finish with status %d\n", ret); - /* stop any pending boot process */ - flush_scheduled_work(); - uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_ON, 0, NULL); usb_kill_urb(sc->urb_int); kfree(sc->urb_int->transfer_buffer); usb_free_urb(sc->urb_int); + /* stop any pending boot process, when no one can schedule work */ + destroy_workqueue(sc->work_q); + if (sc->dsp_firm) release_firmware(sc->dsp_firm); uea_leaves(INS_TO_USBDEV(sc)); @@ -1487,6 +2265,7 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at char *buf) { int ret = -ENODEV; + int modem_state; struct uea_softc *sc; mutex_lock(&uea_mutex); @@ -1494,7 +2273,34 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at if (!sc) goto out; - switch (GET_STATUS(sc->stats.phy.state)) { + if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { + switch (sc->stats.phy.state) { + case 0x0: /* not yet synchronized */ + case 0x1: + case 0x3: + case 0x4: + modem_state = 0; + break; + case 0x5: /* initialization */ + case 0x6: + case 0x9: + case 0xa: + modem_state = 1; + break; + case 0x7: /* operational */ + modem_state = 2; + break; + case 0x2: /* fail ... */ + modem_state = 3; + break; + default: /* unknown */ + modem_state = 4; + break; + } + } else + modem_state = GET_STATUS(sc->stats.phy.state); + + switch (modem_state) { case 0: ret = sprintf(buf, "Modem is booting\n"); break; @@ -1504,9 +2310,12 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at case 2: ret = sprintf(buf, "Modem is operational\n"); break; - default: + case 3: ret = sprintf(buf, "Modem synchronization failed\n"); break; + default: + ret = sprintf(buf, "Modem state is unknown\n"); + break; } out: mutex_unlock(&uea_mutex); @@ -1520,18 +2329,26 @@ static ssize_t read_delin(struct device *dev, struct device_attribute *attr, { int ret = -ENODEV; struct uea_softc *sc; + char *delin = "GOOD"; mutex_lock(&uea_mutex); sc = dev_to_uea(dev); if (!sc) goto out; - if (sc->stats.phy.flags & 0x0C00) - ret = sprintf(buf, "ERROR\n"); - else if (sc->stats.phy.flags & 0x0030) - ret = sprintf(buf, "LOSS\n"); - else - ret = sprintf(buf, "GOOD\n"); + if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { + if (sc->stats.phy.flags & 0x4000) + delin = "RESET"; + else if (sc->stats.phy.flags & 0x0001) + delin = "LOSS"; + } else { + if (sc->stats.phy.flags & 0x0C00) + delin = "ERROR"; + else if (sc->stats.phy.flags & 0x0030) + delin = "LOSS"; + } + + ret = sprintf(buf, "%s\n", delin); out: mutex_unlock(&uea_mutex); return ret; @@ -1662,6 +2479,7 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf, struct usb_device *usb = interface_to_usbdev(intf); struct uea_softc *sc; int ret, ifnum = intf->altsetting->desc.bInterfaceNumber; + unsigned int alt; uea_enters(usb); @@ -1696,22 +2514,29 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf, sc->modem_index = (modem_index < NB_MODEM) ? modem_index++ : 0; sc->driver_info = id->driver_info; - /* ADI930 don't support iso */ - if (UEA_CHIP_VERSION(id) != ADI930 && use_iso[sc->modem_index]) { - int i; - - /* try set fastest alternate for inbound traffic interface */ - for (i = FASTEST_ISO_INTF; i > 0; i--) - if (usb_set_interface(usb, UEA_DS_IFACE_NO, i) == 0) - break; + /* first try to use module parameter */ + if (annex[sc->modem_index] == 1) + sc->annex = ANNEXA; + else if (annex[sc->modem_index] == 2) + sc->annex = ANNEXB; + /* try to autodetect annex */ + else if (sc->driver_info & AUTO_ANNEX_A) + sc->annex = ANNEXA; + else if (sc->driver_info & AUTO_ANNEX_B) + sc->annex = ANNEXB; + else + sc->annex = (le16_to_cpu(sc->usb_dev->descriptor.bcdDevice) & 0x80)?ANNEXB:ANNEXA; - if (i > 0) { - uea_dbg(usb, "set alternate %d for 2 interface\n", i); + alt = altsetting[sc->modem_index]; + /* ADI930 don't support iso */ + if (UEA_CHIP_VERSION(id) != ADI930 && alt > 0) { + if (alt <= 8 && usb_set_interface(usb, UEA_DS_IFACE_NO, alt) == 0) { + uea_dbg(usb, "set alternate %u for 2 interface\n", alt); uea_info(usb, "using iso mode\n"); usbatm->flags |= UDSL_USE_ISOC | UDSL_IGNORE_EILSEQ; } else { - uea_err(usb, "setting any alternate failed for " - "2 interface, using bulk mode\n"); + uea_err(usb, "setting alternate %u failed for " + "2 interface, using bulk mode\n", alt); } } @@ -1757,10 +2582,11 @@ static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id) struct usb_device *usb = interface_to_usbdev(intf); uea_enters(usb); - uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s %s\n", - le16_to_cpu(usb->descriptor.idVendor), - le16_to_cpu(usb->descriptor.idProduct), - chip_name[UEA_CHIP_VERSION(id)], IS_ISDN(usb)?"isdn":"pots"); + uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) Rev (%#X): %s\n", + le16_to_cpu(usb->descriptor.idVendor), + le16_to_cpu(usb->descriptor.idProduct), + le16_to_cpu(usb->descriptor.bcdDevice), + chip_name[UEA_CHIP_VERSION(id)]); usb_reset_device(usb); @@ -1793,24 +2619,40 @@ static void uea_disconnect(struct usb_interface *intf) * List of supported VID/PID */ static const struct usb_device_id uea_ids[] = { + {USB_DEVICE(ANALOG_VID, ADI930_PID_PREFIRM), .driver_info = ADI930 | PREFIRM}, + {USB_DEVICE(ANALOG_VID, ADI930_PID_PSTFIRM), .driver_info = ADI930 | PSTFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_I_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_I_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_II_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_II_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_IIC_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_IIC_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_III_PID_PREFIRM), .driver_info = EAGLE_III | PREFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_III_PID_PSTFIRM), .driver_info = EAGLE_III | PSTFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_IV_PID_PREFIRM), .driver_info = EAGLE_IV | PREFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_IV_PID_PSTFIRM), .driver_info = EAGLE_IV | PSTFIRM}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_A_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_B_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_B_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_A_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_A_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_A}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_B_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_B_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_B}, {USB_DEVICE(ELSA_VID, ELSA_PID_PREFIRM), .driver_info = ADI930 | PREFIRM}, {USB_DEVICE(ELSA_VID, ELSA_PID_PSTFIRM), .driver_info = ADI930 | PSTFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_I_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_I_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_II_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_II_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_IIC_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_IIC_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_III_PID_PREFIRM), .driver_info = EAGLE_III | PREFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_III_PID_PSTFIRM), .driver_info = EAGLE_III | PSTFIRM}, + {USB_DEVICE(ELSA_VID, ELSA_PID_A_PREFIRM), .driver_info = ADI930 | PREFIRM}, + {USB_DEVICE(ELSA_VID, ELSA_PID_A_PSTFIRM), .driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_A}, + {USB_DEVICE(ELSA_VID, ELSA_PID_B_PREFIRM), .driver_info = ADI930 | PREFIRM}, + {USB_DEVICE(ELSA_VID, ELSA_PID_B_PSTFIRM), .driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_B}, {USB_DEVICE(USR_VID, MILLER_A_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(USR_VID, MILLER_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM}, + {USB_DEVICE(USR_VID, MILLER_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A}, {USB_DEVICE(USR_VID, MILLER_B_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(USR_VID, MILLER_B_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM}, + {USB_DEVICE(USR_VID, MILLER_B_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B}, {USB_DEVICE(USR_VID, HEINEKEN_A_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(USR_VID, HEINEKEN_A_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM}, + {USB_DEVICE(USR_VID, HEINEKEN_A_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A}, {USB_DEVICE(USR_VID, HEINEKEN_B_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(USR_VID, HEINEKEN_B_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM}, + {USB_DEVICE(USR_VID, HEINEKEN_B_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B}, {} }; diff --git a/drivers/usb/atm/xusbatm.c b/drivers/usb/atm/xusbatm.c index 70125c6d3be4..8472543eee81 100644 --- a/drivers/usb/atm/xusbatm.c +++ b/drivers/usb/atm/xusbatm.c @@ -29,7 +29,7 @@ #define XUSBATM_PARM(name, type, parmtype, desc) \ static type name[XUSBATM_DRIVERS_MAX]; \ - static int num_##name; \ + static unsigned int num_##name; \ module_param_array(name, parmtype, &num_##name, 0444); \ MODULE_PARM_DESC(name, desc) diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 5192cd9356de..ad632f2d6f94 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -28,6 +28,7 @@ * v0.12 - add hpoj.sourceforge.net ioctls (David Paschal) * v0.13 - alloc space for statusbuf (<status> not on stack); * use usb_buffer_alloc() for read buf & write buf; + * none - Maintained in Linux kernel after v0.13 */ /* @@ -69,7 +70,6 @@ #define USBLP_DEVICE_ID_SIZE 1024 /* ioctls: */ -#define LPGETSTATUS 0x060b /* same as in drivers/char/lp.c */ #define IOCNR_GET_DEVICE_ID 1 #define IOCNR_GET_PROTOCOLS 2 #define IOCNR_SET_PROTOCOL 3 @@ -115,7 +115,7 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H #define USBLP_MINORS 16 #define USBLP_MINOR_BASE 0 -#define USBLP_WRITE_TIMEOUT (5000) /* 5 seconds */ +#define USBLP_CTL_TIMEOUT 5000 /* 5 seconds */ #define USBLP_FIRST_PROTOCOL 1 #define USBLP_LAST_PROTOCOL 3 @@ -159,10 +159,12 @@ struct usblp { int wstatus; /* bytes written or error */ int rstatus; /* bytes ready or error */ unsigned int quirks; /* quirks flags */ + unsigned int flags; /* mode flags */ unsigned char used; /* True if open */ unsigned char present; /* True if not disconnected */ unsigned char bidir; /* interface is bidirectional */ unsigned char sleeping; /* interface is suspended */ + unsigned char no_paper; /* Paper Out happened */ unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */ /* first 2 bytes are (big-endian) length */ }; @@ -259,7 +261,7 @@ static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, i retval = usb_control_msg(usblp->dev, dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0), - request, type | dir | recip, value, index, buf, len, USBLP_WRITE_TIMEOUT); + request, type | dir | recip, value, index, buf, len, USBLP_CTL_TIMEOUT); dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d", request, !!dir, recip, value, index, len, retval); return retval < 0 ? retval : 0; @@ -325,13 +327,11 @@ static void usblp_bulk_write(struct urb *urb) usblp->wstatus = status; else usblp->wstatus = urb->actual_length; + usblp->no_paper = 0; usblp->wcomplete = 1; wake_up(&usblp->wwait); spin_unlock(&usblp->lock); - /* XXX Use usb_setup_bulk_urb when available. Talk to Marcel. */ - kfree(urb->transfer_buffer); - urb->transfer_buffer = NULL; /* Not refcounted, so to be safe... */ usb_free_urb(urb); } @@ -346,16 +346,17 @@ static int usblp_check_status(struct usblp *usblp, int err) unsigned char status, newerr = 0; int error; - error = usblp_read_status (usblp, usblp->statusbuf); - if (error < 0) { + mutex_lock(&usblp->mut); + if ((error = usblp_read_status(usblp, usblp->statusbuf)) < 0) { + mutex_unlock(&usblp->mut); if (printk_ratelimit()) printk(KERN_ERR "usblp%d: error %d reading printer status\n", usblp->minor, error); return 0; } - status = *usblp->statusbuf; + mutex_unlock(&usblp->mut); if (~status & LP_PERRORP) newerr = 3; @@ -411,18 +412,10 @@ static int usblp_open(struct inode *inode, struct file *file) goto out; /* - * TODO: need to implement LP_ABORTOPEN + O_NONBLOCK as in drivers/char/lp.c ??? - * This is #if 0-ed because we *don't* want to fail an open - * just because the printer is off-line. + * We do not implement LP_ABORTOPEN/LPABORTOPEN for two reasons: + * - We do not want persistent state which close(2) does not clear + * - It is not used anyway, according to CUPS people */ -#if 0 - if ((retval = usblp_check_status(usblp, 0))) { - retval = retval > 1 ? -EIO : -ENOSPC; - goto out; - } -#else - retval = 0; -#endif retval = usb_autopm_get_interface(intf); if (retval < 0) @@ -463,6 +456,8 @@ static int usblp_release(struct inode *inode, struct file *file) { struct usblp *usblp = file->private_data; + usblp->flags &= ~LP_ABORT; + mutex_lock (&usblp_mutex); usblp->used = 0; if (usblp->present) { @@ -485,8 +480,8 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait poll_wait(file, &usblp->rwait, wait); poll_wait(file, &usblp->wwait, wait); spin_lock_irqsave(&usblp->lock, flags); - ret = ((!usblp->bidir || !usblp->rcomplete) ? 0 : POLLIN | POLLRDNORM) - | (!usblp->wcomplete ? 0 : POLLOUT | POLLWRNORM); + ret = ((usblp->bidir && usblp->rcomplete) ? POLLIN | POLLRDNORM : 0) | + ((usblp->no_paper || usblp->wcomplete) ? POLLOUT | POLLWRNORM : 0); spin_unlock_irqrestore(&usblp->lock, flags); return ret; } @@ -675,6 +670,13 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; + case LPABORT: + if (arg) + usblp->flags |= LP_ABORT; + else + usblp->flags &= ~LP_ABORT; + break; + default: retval = -ENOTTY; } @@ -684,10 +686,30 @@ done: return retval; } +static struct urb *usblp_new_writeurb(struct usblp *usblp, int transfer_length) +{ + struct urb *urb; + char *writebuf; + + if ((writebuf = kmalloc(transfer_length, GFP_KERNEL)) == NULL) + return NULL; + if ((urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) { + kfree(writebuf); + return NULL; + } + + usb_fill_bulk_urb(urb, usblp->dev, + usb_sndbulkpipe(usblp->dev, + usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress), + writebuf, transfer_length, usblp_bulk_write, usblp); + urb->transfer_flags |= URB_FREE_BUFFER; + + return urb; +} + static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { struct usblp *usblp = file->private_data; - char *writebuf; struct urb *writeurb; int rv; int transfer_length; @@ -708,17 +730,11 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t transfer_length = USBLP_BUF_SIZE; rv = -ENOMEM; - if ((writebuf = kmalloc(USBLP_BUF_SIZE, GFP_KERNEL)) == NULL) - goto raise_buf; - if ((writeurb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) + if ((writeurb = usblp_new_writeurb(usblp, transfer_length)) == NULL) goto raise_urb; - usb_fill_bulk_urb(writeurb, usblp->dev, - usb_sndbulkpipe(usblp->dev, - usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress), - writebuf, transfer_length, usblp_bulk_write, usblp); usb_anchor_urb(writeurb, &usblp->urbs); - if (copy_from_user(writebuf, + if (copy_from_user(writeurb->transfer_buffer, buffer + writecount, transfer_length)) { rv = -EFAULT; goto raise_badaddr; @@ -730,6 +746,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t if ((rv = usb_submit_urb(writeurb, GFP_KERNEL)) < 0) { usblp->wstatus = 0; spin_lock_irq(&usblp->lock); + usblp->no_paper = 0; usblp->wcomplete = 1; wake_up(&usblp->wwait); spin_unlock_irq(&usblp->lock); @@ -747,12 +764,17 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t /* Presume that it's going to complete well. */ writecount += transfer_length; } + if (rv == -ENOSPC) { + spin_lock_irq(&usblp->lock); + usblp->no_paper = 1; /* Mark for poll(2) */ + spin_unlock_irq(&usblp->lock); + writecount += transfer_length; + } /* Leave URB dangling, to be cleaned on close. */ goto collect_error; } if (usblp->wstatus < 0) { - usblp_check_status(usblp, 0); rv = -EIO; goto collect_error; } @@ -771,8 +793,6 @@ raise_badaddr: usb_unanchor_urb(writeurb); usb_free_urb(writeurb); raise_urb: - kfree(writebuf); -raise_buf: raise_wait: collect_error: /* Out of raise sequence */ mutex_unlock(&usblp->wmut); @@ -838,32 +858,36 @@ done: * when O_NONBLOCK is set. So, applications setting O_NONBLOCK must use * select(2) or poll(2) to wait for the buffer to drain before closing. * Alternatively, set blocking mode with fcntl and issue a zero-size write. - * - * Old v0.13 code had a non-functional timeout for wait_event(). Someone forgot - * to check the return code for timeout expiration, so it had no effect. - * Apparently, it was intended to check for error conditons, such as out - * of paper. It is going to return when we settle things with CUPS. XXX */ static int usblp_wwait(struct usblp *usblp, int nonblock) { DECLARE_WAITQUEUE(waita, current); int rc; + int err = 0; add_wait_queue(&usblp->wwait, &waita); for (;;) { + set_current_state(TASK_INTERRUPTIBLE); if (mutex_lock_interruptible(&usblp->mut)) { rc = -EINTR; break; } - set_current_state(TASK_INTERRUPTIBLE); - if ((rc = usblp_wtest(usblp, nonblock)) < 0) { - mutex_unlock(&usblp->mut); - break; - } + rc = usblp_wtest(usblp, nonblock); mutex_unlock(&usblp->mut); - if (rc == 0) + if (rc <= 0) break; - schedule(); + + if (usblp->flags & LP_ABORT) { + if (schedule_timeout(msecs_to_jiffies(5000)) == 0) { + err = usblp_check_status(usblp, err); + if (err == 1) { /* Paper out */ + rc = -ENOSPC; + break; + } + } + } else { + schedule(); + } } set_current_state(TASK_RUNNING); remove_wait_queue(&usblp->wwait, &waita); diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index cb69aa1e02e8..1a8edcee7f30 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -507,18 +507,30 @@ void usb_destroy_configuration(struct usb_device *dev) } -// hub-only!! ... and only in reset path, or usb_new_device() -// (used by real hubs and virtual root hubs) +/* + * Get the USB config descriptors, cache and parse'em + * + * hub-only!! ... and only in reset path, or usb_new_device() + * (used by real hubs and virtual root hubs) + * + * NOTE: if this is a WUSB device and is not authorized, we skip the + * whole thing. A non-authorized USB device has no + * configurations. + */ int usb_get_configuration(struct usb_device *dev) { struct device *ddev = &dev->dev; int ncfg = dev->descriptor.bNumConfigurations; - int result = -ENOMEM; + int result = 0; unsigned int cfgno, length; unsigned char *buffer; unsigned char *bigbuffer; struct usb_config_descriptor *desc; + cfgno = 0; + if (dev->authorized == 0) /* Not really an error */ + goto out_not_authorized; + result = -ENOMEM; if (ncfg > USB_MAXCONFIG) { dev_warn(ddev, "too many configurations: %d, " "using maximum allowed: %d\n", ncfg, USB_MAXCONFIG); @@ -545,14 +557,15 @@ int usb_get_configuration(struct usb_device *dev) goto err2; desc = (struct usb_config_descriptor *)buffer; - for (cfgno = 0; cfgno < ncfg; cfgno++) { + result = 0; + for (; cfgno < ncfg; cfgno++) { /* We grab just the first descriptor so we know how long * the whole configuration is */ result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, USB_DT_CONFIG_SIZE); if (result < 0) { dev_err(ddev, "unable to read config index %d " - "descriptor/%s\n", cfgno, "start"); + "descriptor/%s: %d\n", cfgno, "start", result); dev_err(ddev, "chopping to %d config(s)\n", cfgno); dev->descriptor.bNumConfigurations = cfgno; break; @@ -599,6 +612,7 @@ int usb_get_configuration(struct usb_device *dev) err: kfree(buffer); +out_not_authorized: dev->descriptor.bNumConfigurations = cfgno; err2: if (result == -ENOMEM) diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 927a181120a9..f013b4012c9a 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -71,6 +71,7 @@ struct async { void __user *userbuffer; void __user *userurb; struct urb *urb; + int status; u32 secid; }; @@ -289,10 +290,8 @@ static void snoop_urb(struct urb *urb, void __user *userurb) if (!usbfs_snoop) return; - if (urb->pipe & USB_DIR_IN) - dev_info(&urb->dev->dev, "direction=IN\n"); - else - dev_info(&urb->dev->dev, "direction=OUT\n"); + dev_info(&urb->dev->dev, "direction=%s\n", + usb_urb_dir_in(urb) ? "IN" : "OUT"); dev_info(&urb->dev->dev, "userurb=%p\n", userurb); dev_info(&urb->dev->dev, "transfer_buffer_length=%d\n", urb->transfer_buffer_length); @@ -312,9 +311,10 @@ static void async_completed(struct urb *urb) spin_lock(&ps->lock); list_move_tail(&as->asynclist, &ps->async_completed); spin_unlock(&ps->lock); + as->status = urb->status; if (as->signr) { sinfo.si_signo = as->signr; - sinfo.si_errno = as->urb->status; + sinfo.si_errno = as->status; sinfo.si_code = SI_ASYNCIO; sinfo.si_addr = as->userurb; kill_pid_info_as_uid(as->signr, &sinfo, as->pid, as->uid, @@ -910,6 +910,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, struct usb_ctrlrequest *dr = NULL; unsigned int u, totlen, isofrmlen; int ret, ifnum = -1; + int is_in; if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK| URB_NO_FSBR|URB_ZERO_PACKET)) @@ -924,16 +925,18 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, if ((ret = checkintf(ps, ifnum))) return ret; } - if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) - ep = ps->dev->ep_in [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; - else - ep = ps->dev->ep_out [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; + if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) { + is_in = 1; + ep = ps->dev->ep_in[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; + } else { + is_in = 0; + ep = ps->dev->ep_out[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; + } if (!ep) return -ENOENT; switch(uurb->type) { case USBDEVFS_URB_TYPE_CONTROL: - if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - != USB_ENDPOINT_XFER_CONTROL) + if (!usb_endpoint_xfer_control(&ep->desc)) return -EINVAL; /* min 8 byte setup packet, max 8 byte setup plus an arbitrary data stage */ if (uurb->buffer_length < 8 || uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE)) @@ -952,23 +955,32 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, kfree(dr); return ret; } - uurb->endpoint = (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->bRequestType & USB_ENDPOINT_DIR_MASK); uurb->number_of_packets = 0; uurb->buffer_length = le16_to_cpup(&dr->wLength); uurb->buffer += 8; - if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) { + if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) { + is_in = 1; + uurb->endpoint |= USB_DIR_IN; + } else { + is_in = 0; + uurb->endpoint &= ~USB_DIR_IN; + } + if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, + uurb->buffer, uurb->buffer_length)) { kfree(dr); return -EFAULT; } snoop(&ps->dev->dev, "control urb: bRequest=%02x " "bRrequestType=%02x wValue=%04x " "wIndex=%04x wLength=%04x\n", - dr->bRequest, dr->bRequestType, dr->wValue, - dr->wIndex, dr->wLength); + dr->bRequest, dr->bRequestType, + __le16_to_cpup(&dr->wValue), + __le16_to_cpup(&dr->wIndex), + __le16_to_cpup(&dr->wLength)); break; case USBDEVFS_URB_TYPE_BULK: - switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + switch (usb_endpoint_type(&ep->desc)) { case USB_ENDPOINT_XFER_CONTROL: case USB_ENDPOINT_XFER_ISOC: return -EINVAL; @@ -977,7 +989,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, uurb->number_of_packets = 0; if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) return -EINVAL; - if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) + if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, + uurb->buffer, uurb->buffer_length)) return -EFAULT; snoop(&ps->dev->dev, "bulk urb\n"); break; @@ -986,8 +999,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, /* arbitrary limit */ if (uurb->number_of_packets < 1 || uurb->number_of_packets > 128) return -EINVAL; - if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - != USB_ENDPOINT_XFER_ISOC) + if (!usb_endpoint_xfer_isoc(&ep->desc)) return -EINVAL; isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb->number_of_packets; if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL))) @@ -1014,12 +1026,12 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, case USBDEVFS_URB_TYPE_INTERRUPT: uurb->number_of_packets = 0; - if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - != USB_ENDPOINT_XFER_INT) + if (!usb_endpoint_xfer_int(&ep->desc)) return -EINVAL; if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) return -EINVAL; - if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) + if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, + uurb->buffer, uurb->buffer_length)) return -EFAULT; snoop(&ps->dev->dev, "interrupt urb\n"); break; @@ -1039,8 +1051,11 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, return -ENOMEM; } as->urb->dev = ps->dev; - as->urb->pipe = (uurb->type << 30) | __create_pipe(ps->dev, uurb->endpoint & 0xf) | (uurb->endpoint & USB_DIR_IN); - as->urb->transfer_flags = uurb->flags; + as->urb->pipe = (uurb->type << 30) | + __create_pipe(ps->dev, uurb->endpoint & 0xf) | + (uurb->endpoint & USB_DIR_IN); + as->urb->transfer_flags = uurb->flags | + (is_in ? URB_DIR_IN : URB_DIR_OUT); as->urb->transfer_buffer_length = uurb->buffer_length; as->urb->setup_packet = (unsigned char*)dr; as->urb->start_frame = uurb->start_frame; @@ -1070,13 +1085,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, as->uid = current->uid; as->euid = current->euid; security_task_getsecid(current, &as->secid); - if (!(uurb->endpoint & USB_DIR_IN)) { - if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, as->urb->transfer_buffer_length)) { + if (!is_in) { + if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, + as->urb->transfer_buffer_length)) { free_async(as); return -EFAULT; } } - snoop(&as->urb->dev->dev, "submit urb\n"); snoop_urb(as->urb, as->userurb); async_newpending(as); if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) { @@ -1119,14 +1134,14 @@ static int processcompl(struct async *as, void __user * __user *arg) if (as->userbuffer) if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length)) return -EFAULT; - if (put_user(urb->status, &userurb->status)) + if (put_user(as->status, &userurb->status)) return -EFAULT; if (put_user(urb->actual_length, &userurb->actual_length)) return -EFAULT; if (put_user(urb->error_count, &userurb->error_count)) return -EFAULT; - if (usb_pipeisoc(urb->pipe)) { + if (usb_endpoint_xfer_isoc(&urb->ep->desc)) { for (i = 0; i < urb->number_of_packets; i++) { if (put_user(urb->iso_frame_desc[i].actual_length, &userurb->iso_frame_desc[i].actual_length)) @@ -1233,14 +1248,14 @@ static int processcompl_compat(struct async *as, void __user * __user *arg) if (as->userbuffer) if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length)) return -EFAULT; - if (put_user(urb->status, &userurb->status)) + if (put_user(as->status, &userurb->status)) return -EFAULT; if (put_user(urb->actual_length, &userurb->actual_length)) return -EFAULT; if (put_user(urb->error_count, &userurb->error_count)) return -EFAULT; - if (usb_pipeisoc(urb->pipe)) { + if (usb_endpoint_xfer_isoc(&urb->ep->desc)) { for (i = 0; i < urb->number_of_packets; i++) { if (put_user(urb->iso_frame_desc[i].actual_length, &userurb->iso_frame_desc[i].actual_length)) @@ -1576,6 +1591,7 @@ static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wai } const struct file_operations usbdev_file_operations = { + .owner = THIS_MODULE, .llseek = usbdev_lseek, .read = usbdev_read, .poll = usbdev_poll, @@ -1625,10 +1641,7 @@ static struct notifier_block usbdev_nb = { }; #endif -static struct cdev usb_device_cdev = { - .kobj = {.name = "usb_device", }, - .owner = THIS_MODULE, -}; +static struct cdev usb_device_cdev; int __init usb_devio_init(void) { diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 63b1243a9139..8586817698ad 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -202,6 +202,11 @@ static int usb_probe_interface(struct device *dev) intf = to_usb_interface(dev); udev = interface_to_usbdev(intf); + if (udev->authorized == 0) { + dev_err(&intf->dev, "Device is not authorized for usage\n"); + return -ENODEV; + } + id = usb_match_id(intf, driver->id_table); if (!id) id = usb_match_dynamic_id(intf, driver); @@ -576,12 +581,9 @@ static int usb_device_match(struct device *dev, struct device_driver *drv) } #ifdef CONFIG_HOTPLUG -static int usb_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int usb_uevent(struct device *dev, struct kobj_uevent_env *env) { struct usb_device *usb_dev; - int i = 0; - int length = 0; if (!dev) return -ENODEV; @@ -610,51 +612,39 @@ static int usb_uevent(struct device *dev, char **envp, int num_envp, * all the device descriptors we don't tell them about. Or * act as usermode drivers. */ - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEVICE=/proc/bus/usb/%03d/%03d", + if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d", usb_dev->bus->busnum, usb_dev->devnum)) return -ENOMEM; #endif /* per-device configurations are common */ - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PRODUCT=%x/%x/%x", + if (add_uevent_var(env, "PRODUCT=%x/%x/%x", le16_to_cpu(usb_dev->descriptor.idVendor), le16_to_cpu(usb_dev->descriptor.idProduct), le16_to_cpu(usb_dev->descriptor.bcdDevice))) return -ENOMEM; /* class-based driver binding models */ - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "TYPE=%d/%d/%d", + if (add_uevent_var(env, "TYPE=%d/%d/%d", usb_dev->descriptor.bDeviceClass, usb_dev->descriptor.bDeviceSubClass, usb_dev->descriptor.bDeviceProtocol)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "BUSNUM=%03d", + if (add_uevent_var(env, "BUSNUM=%03d", usb_dev->bus->busnum)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEVNUM=%03d", + if (add_uevent_var(env, "DEVNUM=%03d", usb_dev->devnum)) return -ENOMEM; - envp[i] = NULL; return 0; } #else -static int usb_uevent(struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size) +static int usb_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } @@ -945,11 +935,11 @@ done: #ifdef CONFIG_USB_SUSPEND /* Internal routine to check whether we may autosuspend a device. */ -static int autosuspend_check(struct usb_device *udev) +static int autosuspend_check(struct usb_device *udev, int reschedule) { int i; struct usb_interface *intf; - unsigned long suspend_time; + unsigned long suspend_time, j; /* For autosuspend, fail fast if anything is in use or autosuspend * is disabled. Also fail if any interfaces require remote wakeup @@ -991,20 +981,20 @@ static int autosuspend_check(struct usb_device *udev) } /* If everything is okay but the device hasn't been idle for long - * enough, queue a delayed autosuspend request. + * enough, queue a delayed autosuspend request. If the device + * _has_ been idle for long enough and the reschedule flag is set, + * likewise queue a delayed (1 second) autosuspend request. */ - if (time_after(suspend_time, jiffies)) { + j = jiffies; + if (time_before(j, suspend_time)) + reschedule = 1; + else + suspend_time = j + HZ; + if (reschedule) { if (!timer_pending(&udev->autosuspend.timer)) { - - /* The value of jiffies may change between the - * time_after() comparison above and the subtraction - * below. That's okay; the system behaves sanely - * when a timer is registered for the present moment - * or for the past. - */ queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, - round_jiffies_relative(suspend_time - jiffies)); - } + round_jiffies_relative(suspend_time - j)); + } return -EAGAIN; } return 0; @@ -1012,7 +1002,7 @@ static int autosuspend_check(struct usb_device *udev) #else -static inline int autosuspend_check(struct usb_device *udev) +static inline int autosuspend_check(struct usb_device *udev, int reschedule) { return 0; } @@ -1069,7 +1059,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) udev->do_remote_wakeup = device_may_wakeup(&udev->dev); if (udev->auto_pm) { - status = autosuspend_check(udev); + status = autosuspend_check(udev, 0); if (status < 0) goto done; } @@ -1083,15 +1073,8 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) break; } } - if (status == 0) { - - /* Non-root devices don't need to do anything for FREEZE - * or PRETHAW. */ - if (udev->parent && (msg.event == PM_EVENT_FREEZE || - msg.event == PM_EVENT_PRETHAW)) - goto done; + if (status == 0) status = usb_suspend_device(udev, msg); - } /* If the suspend failed, resume interfaces that did get suspended */ if (status != 0) { @@ -1102,12 +1085,24 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) /* Try another autosuspend when the interfaces aren't busy */ if (udev->auto_pm) - autosuspend_check(udev); + autosuspend_check(udev, status == -EBUSY); - /* If the suspend succeeded, propagate it up the tree */ + /* If the suspend succeeded then prevent any more URB submissions, + * flush any outstanding URBs, and propagate the suspend up the tree. + */ } else { cancel_delayed_work(&udev->autosuspend); - if (parent) + udev->can_submit = 0; + for (i = 0; i < 16; ++i) { + usb_hcd_flush_endpoint(udev, udev->ep_out[i]); + usb_hcd_flush_endpoint(udev, udev->ep_in[i]); + } + + /* If this is just a FREEZE or a PRETHAW, udev might + * not really be suspended. Only true suspends get + * propagated up the device tree. + */ + if (parent && udev->state == USB_STATE_SUSPENDED) usb_autosuspend_device(parent); } @@ -1156,6 +1151,7 @@ static int usb_resume_both(struct usb_device *udev) status = -ENODEV; goto done; } + udev->can_submit = 1; /* Propagate the resume up the tree, if necessary */ if (udev->state == USB_STATE_SUSPENDED) { @@ -1529,9 +1525,21 @@ int usb_external_resume_device(struct usb_device *udev) static int usb_suspend(struct device *dev, pm_message_t message) { + struct usb_device *udev; + if (!is_usb_device(dev)) /* Ignore PM for interfaces */ return 0; - return usb_external_suspend_device(to_usb_device(dev), message); + udev = to_usb_device(dev); + + /* If udev is already suspended, we can skip this suspend and + * we should also skip the upcoming system resume. */ + if (udev->state == USB_STATE_SUSPENDED) { + udev->skip_sys_resume = 1; + return 0; + } + + udev->skip_sys_resume = 0; + return usb_external_suspend_device(udev, message); } static int usb_resume(struct device *dev) @@ -1542,13 +1550,14 @@ static int usb_resume(struct device *dev) return 0; udev = to_usb_device(dev); - /* If autoresume is disabled then we also want to prevent resume - * during system wakeup. However, a "persistent-device" reset-resume - * after power loss counts as a wakeup event. So allow a - * reset-resume to occur if remote wakeup is enabled. */ - if (udev->autoresume_disabled) { + /* If udev->skip_sys_resume is set then udev was already suspended + * when the system suspend started, so we don't want to resume + * udev during this system wakeup. However a reset-resume counts + * as a wakeup event, so allow a reset-resume to occur if remote + * wakeup is enabled. */ + if (udev->skip_sys_resume) { if (!(udev->reset_resume && udev->do_remote_wakeup)) - return -EPERM; + return -EHOSTUNREACH; } return usb_external_resume_device(udev); } diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c index e0ec7045e865..7dc123d6b2d0 100644 --- a/drivers/usb/core/endpoint.c +++ b/drivers/usb/core/endpoint.c @@ -267,7 +267,6 @@ static void ep_device_release(struct device *dev) { struct ep_device *ep_dev = to_ep_device(dev); - dev_dbg(dev, "%s called for %s\n", __FUNCTION__, dev->bus_id); endpoint_free_minor(ep_dev); kfree(ep_dev); } diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index b2fc2b115256..c1cb94e9f242 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -40,7 +40,7 @@ static int is_activesync(struct usb_interface_descriptor *desc) && desc->bInterfaceProtocol == 1; } -static int choose_configuration(struct usb_device *udev) +int usb_choose_configuration(struct usb_device *udev) { int i; int num_configs; @@ -161,17 +161,20 @@ static int generic_probe(struct usb_device *udev) /* Choose and set the configuration. This registers the interfaces * with the driver core and lets interface drivers bind to them. */ - c = choose_configuration(udev); - if (c >= 0) { - err = usb_set_configuration(udev, c); - if (err) { - dev_err(&udev->dev, "can't set config #%d, error %d\n", + if (udev->authorized == 0) + dev_err(&udev->dev, "Device is not authorized for usage\n"); + else { + c = usb_choose_configuration(udev); + if (c >= 0) { + err = usb_set_configuration(udev, c); + if (err) { + dev_err(&udev->dev, "can't set config #%d, error %d\n", c, err); - /* This need not be fatal. The user can try to - * set other configurations. */ + /* This need not be fatal. The user can try to + * set other configurations. */ + } } } - /* USB device state == configured ... usable */ usb_notify_add_device(udev); @@ -203,8 +206,13 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg) */ if (!udev->parent) rc = hcd_bus_suspend(udev); + + /* Non-root devices don't need to do anything for FREEZE or PRETHAW */ + else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW) + rc = 0; else rc = usb_port_suspend(udev); + return rc; } diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 42ef1d5f6c8a..3dd997df8505 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -356,10 +356,18 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) const u8 *bufp = tbuf; int len = 0; int patch_wakeup = 0; - unsigned long flags; - int status = 0; + int status; int n; + might_sleep(); + + spin_lock_irq(&hcd_root_hub_lock); + status = usb_hcd_link_urb_to_ep(hcd, urb); + spin_unlock_irq(&hcd_root_hub_lock); + if (status) + return status; + urb->hcpriv = hcd; /* Indicate it's queued */ + cmd = (struct usb_ctrlrequest *) urb->setup_packet; typeReq = (cmd->bRequestType << 8) | cmd->bRequest; wValue = le16_to_cpu (cmd->wValue); @@ -523,13 +531,18 @@ error: } /* any errors get returned through the urb completion */ - local_irq_save (flags); - spin_lock (&urb->lock); - if (urb->status == -EINPROGRESS) - urb->status = status; - spin_unlock (&urb->lock); - usb_hcd_giveback_urb (hcd, urb); - local_irq_restore (flags); + spin_lock_irq(&hcd_root_hub_lock); + usb_hcd_unlink_urb_from_ep(hcd, urb); + + /* This peculiar use of spinlocks echoes what real HC drivers do. + * Avoiding calls to local_irq_disable/enable makes the code + * RT-friendly. + */ + spin_unlock(&hcd_root_hub_lock); + usb_hcd_giveback_urb(hcd, urb, status); + spin_lock(&hcd_root_hub_lock); + + spin_unlock_irq(&hcd_root_hub_lock); return 0; } @@ -559,31 +572,23 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd) if (length > 0) { /* try to complete the status urb */ - local_irq_save (flags); - spin_lock(&hcd_root_hub_lock); + spin_lock_irqsave(&hcd_root_hub_lock, flags); urb = hcd->status_urb; if (urb) { - spin_lock(&urb->lock); - if (urb->status == -EINPROGRESS) { - hcd->poll_pending = 0; - hcd->status_urb = NULL; - urb->status = 0; - urb->hcpriv = NULL; - urb->actual_length = length; - memcpy(urb->transfer_buffer, buffer, length); - } else /* urb has been unlinked */ - length = 0; - spin_unlock(&urb->lock); - } else - length = 0; - spin_unlock(&hcd_root_hub_lock); + hcd->poll_pending = 0; + hcd->status_urb = NULL; + urb->actual_length = length; + memcpy(urb->transfer_buffer, buffer, length); - /* local irqs are always blocked in completions */ - if (length > 0) - usb_hcd_giveback_urb (hcd, urb); - else + usb_hcd_unlink_urb_from_ep(hcd, urb); + spin_unlock(&hcd_root_hub_lock); + usb_hcd_giveback_urb(hcd, urb, 0); + spin_lock(&hcd_root_hub_lock); + } else { + length = 0; hcd->poll_pending = 1; - local_irq_restore (flags); + } + spin_unlock_irqrestore(&hcd_root_hub_lock, flags); } /* The USB 2.0 spec says 256 ms. This is close enough and won't @@ -611,33 +616,35 @@ static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb) int len = 1 + (urb->dev->maxchild / 8); spin_lock_irqsave (&hcd_root_hub_lock, flags); - if (urb->status != -EINPROGRESS) /* already unlinked */ - retval = urb->status; - else if (hcd->status_urb || urb->transfer_buffer_length < len) { + if (hcd->status_urb || urb->transfer_buffer_length < len) { dev_dbg (hcd->self.controller, "not queuing rh status urb\n"); retval = -EINVAL; - } else { - hcd->status_urb = urb; - urb->hcpriv = hcd; /* indicate it's queued */ + goto done; + } - if (!hcd->uses_new_polling) - mod_timer (&hcd->rh_timer, - (jiffies/(HZ/4) + 1) * (HZ/4)); + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval) + goto done; - /* If a status change has already occurred, report it ASAP */ - else if (hcd->poll_pending) - mod_timer (&hcd->rh_timer, jiffies); - retval = 0; - } + hcd->status_urb = urb; + urb->hcpriv = hcd; /* indicate it's queued */ + if (!hcd->uses_new_polling) + mod_timer(&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4)); + + /* If a status change has already occurred, report it ASAP */ + else if (hcd->poll_pending) + mod_timer(&hcd->rh_timer, jiffies); + retval = 0; + done: spin_unlock_irqrestore (&hcd_root_hub_lock, flags); return retval; } static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb) { - if (usb_pipeint (urb->pipe)) + if (usb_endpoint_xfer_int(&urb->ep->desc)) return rh_queue_status (hcd, urb); - if (usb_pipecontrol (urb->pipe)) + if (usb_endpoint_xfer_control(&urb->ep->desc)) return rh_call_control (hcd, urb); return -EINVAL; } @@ -647,32 +654,96 @@ static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb) /* Unlinks of root-hub control URBs are legal, but they don't do anything * since these URBs always execute synchronously. */ -static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) +static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { unsigned long flags; + int rc; + + spin_lock_irqsave(&hcd_root_hub_lock, flags); + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) + goto done; - if (usb_pipeendpoint(urb->pipe) == 0) { /* Control URB */ + if (usb_endpoint_num(&urb->ep->desc) == 0) { /* Control URB */ ; /* Do nothing */ } else { /* Status URB */ if (!hcd->uses_new_polling) del_timer (&hcd->rh_timer); - local_irq_save (flags); - spin_lock (&hcd_root_hub_lock); if (urb == hcd->status_urb) { hcd->status_urb = NULL; - urb->hcpriv = NULL; - } else - urb = NULL; /* wasn't fully queued */ - spin_unlock (&hcd_root_hub_lock); - if (urb) - usb_hcd_giveback_urb (hcd, urb); - local_irq_restore (flags); + usb_hcd_unlink_urb_from_ep(hcd, urb); + + spin_unlock(&hcd_root_hub_lock); + usb_hcd_giveback_urb(hcd, urb, status); + spin_lock(&hcd_root_hub_lock); + } } + done: + spin_unlock_irqrestore(&hcd_root_hub_lock, flags); + return rc; +} - return 0; + + +/* + * Show & store the current value of authorized_default + */ +static ssize_t usb_host_authorized_default_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct usb_device *rh_usb_dev = to_usb_device(dev); + struct usb_bus *usb_bus = rh_usb_dev->bus; + struct usb_hcd *usb_hcd; + + if (usb_bus == NULL) /* FIXME: not sure if this case is possible */ + return -ENODEV; + usb_hcd = bus_to_hcd(usb_bus); + return snprintf(buf, PAGE_SIZE, "%u\n", usb_hcd->authorized_default); +} + +static ssize_t usb_host_authorized_default_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + ssize_t result; + unsigned val; + struct usb_device *rh_usb_dev = to_usb_device(dev); + struct usb_bus *usb_bus = rh_usb_dev->bus; + struct usb_hcd *usb_hcd; + + if (usb_bus == NULL) /* FIXME: not sure if this case is possible */ + return -ENODEV; + usb_hcd = bus_to_hcd(usb_bus); + result = sscanf(buf, "%u\n", &val); + if (result == 1) { + usb_hcd->authorized_default = val? 1 : 0; + result = size; + } + else + result = -EINVAL; + return result; } +static DEVICE_ATTR(authorized_default, 0644, + usb_host_authorized_default_show, + usb_host_authorized_default_store); + + +/* Group all the USB bus attributes */ +static struct attribute *usb_bus_attrs[] = { + &dev_attr_authorized_default.attr, + NULL, +}; + +static struct attribute_group usb_bus_attr_group = { + .name = NULL, /* we want them in the same directory */ + .attrs = usb_bus_attrs, +}; + + + /*-------------------------------------------------------------------------*/ static struct class *usb_host_class; @@ -726,27 +797,23 @@ static void usb_bus_init (struct usb_bus *bus) */ static int usb_register_bus(struct usb_bus *bus) { + int result = -E2BIG; int busnum; mutex_lock(&usb_bus_list_lock); busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1); - if (busnum < USB_MAXBUS) { - set_bit (busnum, busmap.busmap); - bus->busnum = busnum; - } else { + if (busnum >= USB_MAXBUS) { printk (KERN_ERR "%s: too many buses\n", usbcore_name); - mutex_unlock(&usb_bus_list_lock); - return -E2BIG; + goto error_find_busnum; } - + set_bit (busnum, busmap.busmap); + bus->busnum = busnum; bus->class_dev = class_device_create(usb_host_class, NULL, MKDEV(0,0), - bus->controller, "usb_host%d", busnum); - if (IS_ERR(bus->class_dev)) { - clear_bit(busnum, busmap.busmap); - mutex_unlock(&usb_bus_list_lock); - return PTR_ERR(bus->class_dev); - } - + bus->controller, "usb_host%d", + busnum); + result = PTR_ERR(bus->class_dev); + if (IS_ERR(bus->class_dev)) + goto error_create_class_dev; class_set_devdata(bus->class_dev, bus); /* Add it to the local list of buses */ @@ -755,8 +822,15 @@ static int usb_register_bus(struct usb_bus *bus) usb_notify_add_bus(bus); - dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum); + dev_info (bus->controller, "new USB bus registered, assigned bus " + "number %d\n", bus->busnum); return 0; + +error_create_class_dev: + clear_bit(busnum, busmap.busmap); +error_find_busnum: + mutex_unlock(&usb_bus_list_lock); + return result; } /** @@ -908,103 +982,145 @@ EXPORT_SYMBOL (usb_calc_bus_time); /*-------------------------------------------------------------------------*/ -static void urb_unlink(struct usb_hcd *hcd, struct urb *urb) +/** + * usb_hcd_link_urb_to_ep - add an URB to its endpoint queue + * @hcd: host controller to which @urb was submitted + * @urb: URB being submitted + * + * Host controller drivers should call this routine in their enqueue() + * method. The HCD's private spinlock must be held and interrupts must + * be disabled. The actions carried out here are required for URB + * submission, as well as for endpoint shutdown and for usb_kill_urb. + * + * Returns 0 for no error, otherwise a negative error code (in which case + * the enqueue() method must fail). If no error occurs but enqueue() fails + * anyway, it must call usb_hcd_unlink_urb_from_ep() before releasing + * the private spinlock and returning. + */ +int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb) { - unsigned long flags; + int rc = 0; - /* clear all state linking urb to this dev (and hcd) */ - spin_lock_irqsave(&hcd_urb_list_lock, flags); - list_del_init (&urb->urb_list); - spin_unlock_irqrestore(&hcd_urb_list_lock, flags); + spin_lock(&hcd_urb_list_lock); - if (hcd->self.uses_dma && !is_root_hub(urb->dev)) { - if (usb_pipecontrol (urb->pipe) - && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) - dma_unmap_single (hcd->self.controller, urb->setup_dma, - sizeof (struct usb_ctrlrequest), - DMA_TO_DEVICE); - if (urb->transfer_buffer_length != 0 - && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) - dma_unmap_single (hcd->self.controller, - urb->transfer_dma, - urb->transfer_buffer_length, - usb_pipein (urb->pipe) - ? DMA_FROM_DEVICE - : DMA_TO_DEVICE); + /* Check that the URB isn't being killed */ + if (unlikely(urb->reject)) { + rc = -EPERM; + goto done; } -} - -/* may be called in any context with a valid urb->dev usecount - * caller surrenders "ownership" of urb - * expects usb_submit_urb() to have sanity checked and conditioned all - * inputs in the urb - */ -int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) -{ - int status; - struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus); - struct usb_host_endpoint *ep; - unsigned long flags; - if (!hcd) - return -ENODEV; + if (unlikely(!urb->ep->enabled)) { + rc = -ENOENT; + goto done; + } - usbmon_urb_submit(&hcd->self, urb); + if (unlikely(!urb->dev->can_submit)) { + rc = -EHOSTUNREACH; + goto done; + } /* - * Atomically queue the urb, first to our records, then to the HCD. - * Access to urb->status is controlled by urb->lock ... changes on - * i/o completion (normal or fault) or unlinking. + * Check the host controller's state and add the URB to the + * endpoint's queue. */ - - // FIXME: verify that quiescing hc works right (RH cleans up) - - spin_lock_irqsave(&hcd_urb_list_lock, flags); - ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out) - [usb_pipeendpoint(urb->pipe)]; - if (unlikely (!ep)) - status = -ENOENT; - else if (unlikely (urb->reject)) - status = -EPERM; - else switch (hcd->state) { + switch (hcd->state) { case HC_STATE_RUNNING: case HC_STATE_RESUMING: - list_add_tail (&urb->urb_list, &ep->urb_list); - status = 0; + urb->unlinked = 0; + list_add_tail(&urb->urb_list, &urb->ep->urb_list); break; default: - status = -ESHUTDOWN; - break; + rc = -ESHUTDOWN; + goto done; } - spin_unlock_irqrestore(&hcd_urb_list_lock, flags); - if (status) { - INIT_LIST_HEAD (&urb->urb_list); - usbmon_urb_submit_error(&hcd->self, urb, status); - return status; + done: + spin_unlock(&hcd_urb_list_lock); + return rc; +} +EXPORT_SYMBOL_GPL(usb_hcd_link_urb_to_ep); + +/** + * usb_hcd_check_unlink_urb - check whether an URB may be unlinked + * @hcd: host controller to which @urb was submitted + * @urb: URB being checked for unlinkability + * @status: error code to store in @urb if the unlink succeeds + * + * Host controller drivers should call this routine in their dequeue() + * method. The HCD's private spinlock must be held and interrupts must + * be disabled. The actions carried out here are required for making + * sure than an unlink is valid. + * + * Returns 0 for no error, otherwise a negative error code (in which case + * the dequeue() method must fail). The possible error codes are: + * + * -EIDRM: @urb was not submitted or has already completed. + * The completion function may not have been called yet. + * + * -EBUSY: @urb has already been unlinked. + */ +int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb, + int status) +{ + struct list_head *tmp; + + /* insist the urb is still queued */ + list_for_each(tmp, &urb->ep->urb_list) { + if (tmp == &urb->urb_list) + break; } + if (tmp != &urb->urb_list) + return -EIDRM; - /* increment urb's reference count as part of giving it to the HCD - * (which now controls it). HCD guarantees that it either returns - * an error or calls giveback(), but not both. + /* Any status except -EINPROGRESS means something already started to + * unlink this URB from the hardware. So there's no more work to do. */ - urb = usb_get_urb (urb); - atomic_inc (&urb->use_count); - - if (is_root_hub(urb->dev)) { - /* NOTE: requirement on hub callers (usbfs and the hub - * driver, for now) that URBs' urb->transfer_buffer be - * valid and usb_buffer_{sync,unmap}() not be needed, since - * they could clobber root hub response data. - */ - status = rh_urb_enqueue (hcd, urb); - goto done; + if (urb->unlinked) + return -EBUSY; + urb->unlinked = status; + + /* IRQ setup can easily be broken so that USB controllers + * never get completion IRQs ... maybe even the ones we need to + * finish unlinking the initial failed usb_set_address() + * or device descriptor fetch. + */ + if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) && + !is_root_hub(urb->dev)) { + dev_warn(hcd->self.controller, "Unlink after no-IRQ? " + "Controller is probably using the wrong IRQ.\n"); + set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); } - /* lower level hcd code should use *_dma exclusively, + return 0; +} +EXPORT_SYMBOL_GPL(usb_hcd_check_unlink_urb); + +/** + * usb_hcd_unlink_urb_from_ep - remove an URB from its endpoint queue + * @hcd: host controller to which @urb was submitted + * @urb: URB being unlinked + * + * Host controller drivers should call this routine before calling + * usb_hcd_giveback_urb(). The HCD's private spinlock must be held and + * interrupts must be disabled. The actions carried out here are required + * for URB completion. + */ +void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb) +{ + /* clear all state linking urb to this dev (and hcd) */ + spin_lock(&hcd_urb_list_lock); + list_del_init(&urb->urb_list); + spin_unlock(&hcd_urb_list_lock); +} +EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep); + +static void map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) +{ + /* Map the URB's buffers for DMA access. + * Lower level HCD code should use *_dma exclusively, * unless it uses pio or talks to another transport. */ - if (hcd->self.uses_dma) { - if (usb_pipecontrol (urb->pipe) + if (hcd->self.uses_dma && !is_root_hub(urb->dev)) { + if (usb_endpoint_xfer_control(&urb->ep->desc) && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) urb->setup_dma = dma_map_single ( hcd->self.controller, @@ -1017,20 +1133,75 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) hcd->self.controller, urb->transfer_buffer, urb->transfer_buffer_length, - usb_pipein (urb->pipe) + usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } +} - status = hcd->driver->urb_enqueue (hcd, ep, urb, mem_flags); -done: - if (unlikely (status)) { - urb_unlink(hcd, urb); - atomic_dec (&urb->use_count); - if (urb->reject) - wake_up (&usb_kill_urb_queue); +static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) +{ + if (hcd->self.uses_dma && !is_root_hub(urb->dev)) { + if (usb_endpoint_xfer_control(&urb->ep->desc) + && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) + dma_unmap_single(hcd->self.controller, urb->setup_dma, + sizeof(struct usb_ctrlrequest), + DMA_TO_DEVICE); + if (urb->transfer_buffer_length != 0 + && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) + dma_unmap_single(hcd->self.controller, + urb->transfer_dma, + urb->transfer_buffer_length, + usb_urb_dir_in(urb) + ? DMA_FROM_DEVICE + : DMA_TO_DEVICE); + } +} + +/*-------------------------------------------------------------------------*/ + +/* may be called in any context with a valid urb->dev usecount + * caller surrenders "ownership" of urb + * expects usb_submit_urb() to have sanity checked and conditioned all + * inputs in the urb + */ +int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) +{ + int status; + struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus); + + /* increment urb's reference count as part of giving it to the HCD + * (which will control it). HCD guarantees that it either returns + * an error or calls giveback(), but not both. + */ + usb_get_urb(urb); + atomic_inc(&urb->use_count); + atomic_inc(&urb->dev->urbnum); + usbmon_urb_submit(&hcd->self, urb); + + /* NOTE requirements on root-hub callers (usbfs and the hub + * driver, for now): URBs' urb->transfer_buffer must be + * valid and usb_buffer_{sync,unmap}() not be needed, since + * they could clobber root hub response data. Also, control + * URBs must be submitted in process context with interrupts + * enabled. + */ + map_urb_for_dma(hcd, urb); + if (is_root_hub(urb->dev)) + status = rh_urb_enqueue(hcd, urb); + else + status = hcd->driver->urb_enqueue(hcd, urb, mem_flags); + + if (unlikely(status)) { usbmon_urb_submit_error(&hcd->self, urb, status); - usb_put_urb (urb); + unmap_urb_for_dma(hcd, urb); + urb->hcpriv = NULL; + INIT_LIST_HEAD(&urb->urb_list); + atomic_dec(&urb->use_count); + atomic_dec(&urb->dev->urbnum); + if (urb->reject) + wake_up(&usb_kill_urb_queue); + usb_put_urb(urb); } return status; } @@ -1042,24 +1213,19 @@ done: * soon as practical. we've already set up the urb's return status, * but we can't know if the callback completed already. */ -static int -unlink1 (struct usb_hcd *hcd, struct urb *urb) +static int unlink1(struct usb_hcd *hcd, struct urb *urb, int status) { int value; if (is_root_hub(urb->dev)) - value = usb_rh_urb_dequeue (hcd, urb); + value = usb_rh_urb_dequeue(hcd, urb, status); else { /* The only reason an HCD might fail this call is if * it has not yet fully queued the urb to begin with. * Such failures should be harmless. */ - value = hcd->driver->urb_dequeue (hcd, urb); + value = hcd->driver->urb_dequeue(hcd, urb, status); } - - if (value != 0) - dev_dbg (hcd->self.controller, "dequeue %p --> %d\n", - urb, value); return value; } @@ -1071,88 +1237,17 @@ unlink1 (struct usb_hcd *hcd, struct urb *urb) */ int usb_hcd_unlink_urb (struct urb *urb, int status) { - struct usb_host_endpoint *ep; - struct usb_hcd *hcd = NULL; - struct device *sys = NULL; - unsigned long flags; - struct list_head *tmp; - int retval; - - if (!urb) - return -EINVAL; - if (!urb->dev || !urb->dev->bus) - return -ENODEV; - ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out) - [usb_pipeendpoint(urb->pipe)]; - if (!ep) - return -ENODEV; - - /* - * we contend for urb->status with the hcd core, - * which changes it while returning the urb. - * - * Caller guaranteed that the urb pointer hasn't been freed, and - * that it was submitted. But as a rule it can't know whether or - * not it's already been unlinked ... so we respect the reversed - * lock sequence needed for the usb_hcd_giveback_urb() code paths - * (urb lock, then hcd_urb_list_lock) in case some other CPU is now - * unlinking it. - */ - spin_lock_irqsave (&urb->lock, flags); - spin_lock(&hcd_urb_list_lock); + struct usb_hcd *hcd; + int retval; - sys = &urb->dev->dev; hcd = bus_to_hcd(urb->dev->bus); - if (hcd == NULL) { - retval = -ENODEV; - goto done; - } + retval = unlink1(hcd, urb, status); - /* insist the urb is still queued */ - list_for_each(tmp, &ep->urb_list) { - if (tmp == &urb->urb_list) - break; - } - if (tmp != &urb->urb_list) { - retval = -EIDRM; - goto done; - } - - /* Any status except -EINPROGRESS means something already started to - * unlink this URB from the hardware. So there's no more work to do. - */ - if (urb->status != -EINPROGRESS) { - retval = -EBUSY; - goto done; - } - - /* IRQ setup can easily be broken so that USB controllers - * never get completion IRQs ... maybe even the ones we need to - * finish unlinking the initial failed usb_set_address() - * or device descriptor fetch. - */ - if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) && - !is_root_hub(urb->dev)) { - dev_warn (hcd->self.controller, "Unlink after no-IRQ? " - "Controller is probably using the wrong IRQ.\n"); - set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); - } - - urb->status = status; - - spin_unlock(&hcd_urb_list_lock); - spin_unlock_irqrestore (&urb->lock, flags); - - retval = unlink1 (hcd, urb); if (retval == 0) retval = -EINPROGRESS; - return retval; - -done: - spin_unlock(&hcd_urb_list_lock); - spin_unlock_irqrestore (&urb->lock, flags); - if (retval != -EIDRM && sys && sys->driver) - dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval); + else if (retval != -EIDRM && retval != -EBUSY) + dev_dbg(&urb->dev->dev, "hcd_unlink_urb %p fail %d\n", + urb, retval); return retval; } @@ -1162,6 +1257,7 @@ done: * usb_hcd_giveback_urb - return URB from HCD to device driver * @hcd: host controller returning the URB * @urb: urb being returned to the USB device driver. + * @status: completion status code for the URB. * Context: in_interrupt() * * This hands the URB from HCD to its USB device driver, using its @@ -1169,14 +1265,27 @@ done: * (and is done using urb->hcpriv). It also released all HCD locks; * the device driver won't cause problems if it frees, modifies, * or resubmits this URB. + * + * If @urb was unlinked, the value of @status will be overridden by + * @urb->unlinked. Erroneous short transfers are detected in case + * the HCD hasn't checked for them. */ -void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) +void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status) { - urb_unlink(hcd, urb); - usbmon_urb_complete (&hcd->self, urb); + urb->hcpriv = NULL; + if (unlikely(urb->unlinked)) + status = urb->unlinked; + else if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) && + urb->actual_length < urb->transfer_buffer_length && + !status)) + status = -EREMOTEIO; + + unmap_urb_for_dma(hcd, urb); + usbmon_urb_complete(&hcd->self, urb, status); usb_unanchor_urb(urb); /* pass ownership to the completion handler */ + urb->status = status; urb->complete (urb); atomic_dec (&urb->use_count); if (unlikely (urb->reject)) @@ -1187,78 +1296,61 @@ EXPORT_SYMBOL (usb_hcd_giveback_urb); /*-------------------------------------------------------------------------*/ -/* disables the endpoint: cancels any pending urbs, then synchronizes with - * the hcd to make sure all endpoint state is gone from hardware, and then - * waits until the endpoint's queue is completely drained. use for - * set_configuration, set_interface, driver removal, physical disconnect. - * - * example: a qh stored in ep->hcpriv, holding state related to endpoint - * type, maxpacket size, toggle, halt status, and scheduling. +/* Cancel all URBs pending on this endpoint and wait for the endpoint's + * queue to drain completely. The caller must first insure that no more + * URBs can be submitted for this endpoint. */ -void usb_hcd_endpoint_disable (struct usb_device *udev, +void usb_hcd_flush_endpoint(struct usb_device *udev, struct usb_host_endpoint *ep) { struct usb_hcd *hcd; struct urb *urb; + if (!ep) + return; + might_sleep(); hcd = bus_to_hcd(udev->bus); - local_irq_disable (); - /* ep is already gone from udev->ep_{in,out}[]; no more submits */ + /* No more submits can occur */ rescan: - spin_lock(&hcd_urb_list_lock); + spin_lock_irq(&hcd_urb_list_lock); list_for_each_entry (urb, &ep->urb_list, urb_list) { - int tmp; + int is_in; - /* the urb may already have been unlinked */ - if (urb->status != -EINPROGRESS) + if (urb->unlinked) continue; usb_get_urb (urb); + is_in = usb_urb_dir_in(urb); spin_unlock(&hcd_urb_list_lock); - spin_lock (&urb->lock); - tmp = urb->status; - if (tmp == -EINPROGRESS) - urb->status = -ESHUTDOWN; - spin_unlock (&urb->lock); - - /* kick hcd unless it's already returning this */ - if (tmp == -EINPROGRESS) { - tmp = urb->pipe; - unlink1 (hcd, urb); - dev_dbg (hcd->self.controller, - "shutdown urb %p pipe %08x ep%d%s%s\n", - urb, tmp, usb_pipeendpoint (tmp), - (tmp & USB_DIR_IN) ? "in" : "out", - ({ char *s; \ - switch (usb_pipetype (tmp)) { \ - case PIPE_CONTROL: s = ""; break; \ - case PIPE_BULK: s = "-bulk"; break; \ - case PIPE_INTERRUPT: s = "-intr"; break; \ - default: s = "-iso"; break; \ - }; s;})); - } + /* kick hcd */ + unlink1(hcd, urb, -ESHUTDOWN); + dev_dbg (hcd->self.controller, + "shutdown urb %p ep%d%s%s\n", + urb, usb_endpoint_num(&ep->desc), + is_in ? "in" : "out", + ({ char *s; + + switch (usb_endpoint_type(&ep->desc)) { + case USB_ENDPOINT_XFER_CONTROL: + s = ""; break; + case USB_ENDPOINT_XFER_BULK: + s = "-bulk"; break; + case USB_ENDPOINT_XFER_INT: + s = "-intr"; break; + default: + s = "-iso"; break; + }; + s; + })); usb_put_urb (urb); /* list contents may have changed */ goto rescan; } - spin_unlock(&hcd_urb_list_lock); - local_irq_enable (); - - /* synchronize with the hardware, so old configuration state - * clears out immediately (and will be freed). - */ - might_sleep (); - if (hcd->driver->endpoint_disable) - hcd->driver->endpoint_disable (hcd, ep); + spin_unlock_irq(&hcd_urb_list_lock); - /* Wait until the endpoint queue is completely empty. Most HCDs - * will have done this already in their endpoint_disable method, - * but some might not. And there could be root-hub control URBs - * still pending since they aren't affected by the HCDs' - * endpoint_disable methods. - */ + /* Wait until the endpoint queue is completely empty */ while (!list_empty (&ep->urb_list)) { spin_lock_irq(&hcd_urb_list_lock); @@ -1278,6 +1370,25 @@ rescan: } } +/* Disables the endpoint: synchronizes with the hcd to make sure all + * endpoint state is gone from hardware. usb_hcd_flush_endpoint() must + * have been called previously. Use for set_configuration, set_interface, + * driver removal, physical disconnect. + * + * example: a qh stored in ep->hcpriv, holding state related to endpoint + * type, maxpacket size, toggle, halt status, and scheduling. + */ +void usb_hcd_disable_endpoint(struct usb_device *udev, + struct usb_host_endpoint *ep) +{ + struct usb_hcd *hcd; + + might_sleep(); + hcd = bus_to_hcd(udev->bus); + if (hcd->driver->endpoint_disable) + hcd->driver->endpoint_disable(hcd, ep); +} + /*-------------------------------------------------------------------------*/ /* called in any context */ @@ -1525,7 +1636,6 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, hcd->driver = driver; hcd->product_desc = (driver->product_desc) ? driver->product_desc : "USB Host Controller"; - return hcd; } EXPORT_SYMBOL (usb_create_hcd); @@ -1570,6 +1680,7 @@ int usb_add_hcd(struct usb_hcd *hcd, dev_info(hcd->self.controller, "%s\n", hcd->product_desc); + hcd->authorized_default = hcd->wireless? 0 : 1; set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); /* HC is in reset state, but accessible. Now do the one-time init, @@ -1646,10 +1757,20 @@ int usb_add_hcd(struct usb_hcd *hcd, if ((retval = register_root_hub(hcd)) != 0) goto err_register_root_hub; + retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group); + if (retval < 0) { + printk(KERN_ERR "Cannot register USB bus sysfs attributes: %d\n", + retval); + goto error_create_attr_group; + } if (hcd->uses_new_polling && hcd->poll_rh) usb_hcd_poll_rh_status(hcd); return retval; +error_create_attr_group: + mutex_lock(&usb_bus_list_lock); + usb_disconnect(&hcd->self.root_hub); + mutex_unlock(&usb_bus_list_lock); err_register_root_hub: hcd->driver->stop(hcd); err_hcd_driver_start: @@ -1691,6 +1812,7 @@ void usb_remove_hcd(struct usb_hcd *hcd) cancel_work_sync(&hcd->wakeup_work); #endif + sysfs_remove_group(&hcd->self.root_hub->dev.kobj, &usb_bus_attr_group); mutex_lock(&usb_bus_list_lock); usb_disconnect(&hcd->self.root_hub); mutex_unlock(&usb_bus_list_lock); diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index b5ebb73c2332..98e24194a4ab 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -19,6 +19,8 @@ #ifdef __KERNEL__ +#include <linux/rwsem.h> + /* This file contains declarations of usbcore internals that are mostly * used or exposed by Host Controller Drivers. */ @@ -51,6 +53,12 @@ * * Since "struct usb_bus" is so thin, you can't share much code in it. * This framework is a layer over that, and should be more sharable. + * + * @authorized_default: Specifies if new devices are authorized to + * connect by default or they require explicit + * user space authorization; this bit is settable + * through /sys/class/usb_host/X/authorized_default. + * For the rest is RO, so we don't lock to r/w it. */ /*-------------------------------------------------------------------------*/ @@ -90,6 +98,7 @@ struct usb_hcd { unsigned poll_rh:1; /* poll for rh status? */ unsigned poll_pending:1; /* status has changed? */ unsigned wireless:1; /* Wireless USB HCD */ + unsigned authorized_default:1; int irq; /* irq allocated */ void __iomem *regs; /* device memory/io */ @@ -182,11 +191,10 @@ struct hc_driver { int (*get_frame_number) (struct usb_hcd *hcd); /* manage i/o requests, device state */ - int (*urb_enqueue) (struct usb_hcd *hcd, - struct usb_host_endpoint *ep, - struct urb *urb, - gfp_t mem_flags); - int (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb); + int (*urb_enqueue)(struct usb_hcd *hcd, + struct urb *urb, gfp_t mem_flags); + int (*urb_dequeue)(struct usb_hcd *hcd, + struct urb *urb, int status); /* hw synch, freeing endpoint resources that urb_dequeue can't */ void (*endpoint_disable)(struct usb_hcd *hcd, @@ -204,10 +212,18 @@ struct hc_driver { /* Needed only if port-change IRQs are level-triggered */ }; +extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb); +extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb, + int status); +extern void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb); + extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags); extern int usb_hcd_unlink_urb (struct urb *urb, int status); -extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb); -extern void usb_hcd_endpoint_disable (struct usb_device *udev, +extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, + int status); +extern void usb_hcd_flush_endpoint(struct usb_device *udev, + struct usb_host_endpoint *ep); +extern void usb_hcd_disable_endpoint(struct usb_device *udev, struct usb_host_endpoint *ep); extern int usb_hcd_get_frame_number (struct usb_device *udev); @@ -402,7 +418,7 @@ static inline void usbfs_cleanup(void) { } struct usb_mon_operations { void (*urb_submit)(struct usb_bus *bus, struct urb *urb); void (*urb_submit_error)(struct usb_bus *bus, struct urb *urb, int err); - void (*urb_complete)(struct usb_bus *bus, struct urb *urb); + void (*urb_complete)(struct usb_bus *bus, struct urb *urb, int status); /* void (*urb_unlink)(struct usb_bus *bus, struct urb *urb); */ }; @@ -421,10 +437,11 @@ static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb, (*mon_ops->urb_submit_error)(bus, urb, error); } -static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) +static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb, + int status) { if (bus->monitored) - (*mon_ops->urb_complete)(bus, urb); + (*mon_ops->urb_complete)(bus, urb, status); } int usb_mon_register(struct usb_mon_operations *ops); @@ -435,7 +452,8 @@ void usb_mon_deregister(void); static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb) {} static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb, int error) {} -static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {} +static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb, + int status) {} #endif /* CONFIG_USB_MON */ @@ -454,5 +472,9 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {} : (in_interrupt () ? "in_interrupt" : "can sleep")) -#endif /* __KERNEL__ */ +/* This rwsem is for use only by the hub driver and ehci-hcd. + * Nobody else should touch it. + */ +extern struct rw_semaphore ehci_cf_port_reset_rwsem; +#endif /* __KERNEL__ */ diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index f7b337feb3ea..d20cb545a6e4 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -125,6 +125,12 @@ MODULE_PARM_DESC(use_both_schemes, "try the other device initialization scheme if the " "first one fails"); +/* Mutual exclusion for EHCI CF initialization. This interferes with + * port reset on some companion controllers. + */ +DECLARE_RWSEM(ehci_cf_port_reset_rwsem); +EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem); + static inline char *portspeed(int portstatus) { @@ -347,11 +353,11 @@ void usb_kick_khubd(struct usb_device *hdev) static void hub_irq(struct urb *urb) { struct usb_hub *hub = urb->context; - int status; + int status = urb->status; int i; unsigned long bits; - switch (urb->status) { + switch (status) { case -ENOENT: /* synchronous unlink */ case -ECONNRESET: /* async unlink */ case -ESHUTDOWN: /* hardware going away */ @@ -359,10 +365,10 @@ static void hub_irq(struct urb *urb) default: /* presumably an error */ /* Cause a hub reset after 10 consecutive errors */ - dev_dbg (hub->intfdev, "transfer --> %d\n", urb->status); + dev_dbg (hub->intfdev, "transfer --> %d\n", status); if ((++hub->nerrors < 10) || hub->error) goto resubmit; - hub->error = urb->status; + hub->error = status; /* FALL THROUGH */ /* let khubd handle things */ @@ -1220,54 +1226,14 @@ static inline void show_string(struct usb_device *udev, char *id, char *string) #endif /** - * usb_new_device - perform initial device setup (usbcore-internal) + * usb_configure_device_otg - FIXME (usbcore-internal) * @udev: newly addressed device (in ADDRESS state) * - * This is called with devices which have been enumerated, but not yet - * configured. The device descriptor is available, but not descriptors - * for any device configuration. The caller must have locked either - * the parent hub (if udev is a normal device) or else the - * usb_bus_list_lock (if udev is a root hub). The parent's pointer to - * udev has already been installed, but udev is not yet visible through - * sysfs or other filesystem code. - * - * It will return if the device is configured properly or not. Zero if - * the interface was registered with the driver core; else a negative - * errno value. - * - * This call is synchronous, and may not be used in an interrupt context. - * - * Only the hub driver or root-hub registrar should ever call this. + * Do configuration for On-The-Go devices */ -int usb_new_device(struct usb_device *udev) +static int usb_configure_device_otg(struct usb_device *udev) { - int err; - - /* 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", - err); - goto fail; - } - - /* read the standard strings and cache them if present */ - udev->product = usb_cache_string(udev, udev->descriptor.iProduct); - udev->manufacturer = usb_cache_string(udev, - udev->descriptor.iManufacturer); - udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); - - /* Tell the world! */ - dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, " - "SerialNumber=%d\n", - udev->descriptor.iManufacturer, - udev->descriptor.iProduct, - udev->descriptor.iSerialNumber); - show_string(udev, "Product", udev->product); - show_string(udev, "Manufacturer", udev->manufacturer); - show_string(udev, "SerialNumber", udev->serial); + int err = 0; #ifdef CONFIG_USB_OTG /* @@ -1329,8 +1295,82 @@ int usb_new_device(struct usb_device *udev) err = -ENOTSUPP; goto fail; } +fail: #endif + return err; +} + + +/** + * usb_configure_device - Detect and probe device intfs/otg (usbcore-internal) + * @udev: newly addressed device (in ADDRESS state) + * + * This is only called by usb_new_device() and usb_authorize_device() + * and FIXME -- all comments that apply to them apply here wrt to + * environment. + * + * If the device is WUSB and not authorized, we don't attempt to read + * the string descriptors, as they will be errored out by the device + * until it has been authorized. + */ +static int usb_configure_device(struct usb_device *udev) +{ + int err; + if (udev->config == NULL) { + err = usb_get_configuration(udev); + if (err < 0) { + dev_err(&udev->dev, "can't read configurations, error %d\n", + err); + goto fail; + } + } + if (udev->wusb == 1 && udev->authorized == 0) { + udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL); + udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL); + udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL); + } + else { + /* read the standard strings and cache them if present */ + udev->product = usb_cache_string(udev, udev->descriptor.iProduct); + udev->manufacturer = usb_cache_string(udev, + udev->descriptor.iManufacturer); + udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); + } + err = usb_configure_device_otg(udev); +fail: + return err; +} + + +/** + * usb_new_device - perform initial device setup (usbcore-internal) + * @udev: newly addressed device (in ADDRESS state) + * + * This is called with devices which have been enumerated, but not yet + * configured. The device descriptor is available, but not descriptors + * for any device configuration. The caller must have locked either + * the parent hub (if udev is a normal device) or else the + * usb_bus_list_lock (if udev is a root hub). The parent's pointer to + * udev has already been installed, but udev is not yet visible through + * sysfs or other filesystem code. + * + * It will return if the device is configured properly or not. Zero if + * the interface was registered with the driver core; else a negative + * errno value. + * + * This call is synchronous, and may not be used in an interrupt context. + * + * Only the hub driver or root-hub registrar should ever call this. + */ +int usb_new_device(struct usb_device *udev) +{ + int err; + + usb_detect_quirks(udev); /* Determine quirks */ + err = usb_configure_device(udev); /* detect & probe dev/intfs */ + if (err < 0) + goto fail; /* export the usbdev device-node for libusb */ udev->dev.devt = MKDEV(USB_DEVICE_MAJOR, (((udev->bus->busnum-1) * 128) + (udev->devnum-1))); @@ -1346,19 +1386,106 @@ int usb_new_device(struct usb_device *udev) err = device_add(&udev->dev); if (err) { dev_err(&udev->dev, "can't device_add, error %d\n", err); - if (udev->parent) - usb_autosuspend_device(udev->parent); goto fail; } -exit: + /* Tell the world! */ + dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, " + "SerialNumber=%d\n", + udev->descriptor.iManufacturer, + udev->descriptor.iProduct, + udev->descriptor.iSerialNumber); + show_string(udev, "Product", udev->product); + show_string(udev, "Manufacturer", udev->manufacturer); + show_string(udev, "SerialNumber", udev->serial); return err; fail: usb_set_device_state(udev, USB_STATE_NOTATTACHED); - goto exit; + return err; } + +/** + * Similar to usb_disconnect() + * + * We share a lock (that we have) with device_del(), so we need to + * defer its call. + */ +int usb_deauthorize_device(struct usb_device *usb_dev) +{ + unsigned cnt; + usb_lock_device(usb_dev); + if (usb_dev->authorized == 0) + goto out_unauthorized; + usb_dev->authorized = 0; + usb_set_configuration(usb_dev, -1); + usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL); + usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL); + usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL); + kfree(usb_dev->config); + usb_dev->config = NULL; + for (cnt = 0; cnt < usb_dev->descriptor.bNumConfigurations; cnt++) + kfree(usb_dev->rawdescriptors[cnt]); + usb_dev->descriptor.bNumConfigurations = 0; + kfree(usb_dev->rawdescriptors); +out_unauthorized: + usb_unlock_device(usb_dev); + return 0; +} + + +int usb_authorize_device(struct usb_device *usb_dev) +{ + int result = 0, c; + usb_lock_device(usb_dev); + if (usb_dev->authorized == 1) + goto out_authorized; + kfree(usb_dev->product); + usb_dev->product = NULL; + kfree(usb_dev->manufacturer); + usb_dev->manufacturer = NULL; + kfree(usb_dev->serial); + usb_dev->serial = NULL; + result = usb_autoresume_device(usb_dev); + if (result < 0) { + dev_err(&usb_dev->dev, + "can't autoresume for authorization: %d\n", result); + goto error_autoresume; + } + result = usb_get_device_descriptor(usb_dev, sizeof(usb_dev->descriptor)); + if (result < 0) { + dev_err(&usb_dev->dev, "can't re-read device descriptor for " + "authorization: %d\n", result); + goto error_device_descriptor; + } + usb_dev->authorized = 1; + result = usb_configure_device(usb_dev); + if (result < 0) + goto error_configure; + /* Choose and set the configuration. This registers the interfaces + * with the driver core and lets interface drivers bind to them. + */ + c = usb_choose_configuration(usb_dev); + if (c >= 0) { + result = usb_set_configuration(usb_dev, c); + if (result) { + dev_err(&usb_dev->dev, + "can't set config #%d, error %d\n", c, result); + /* This need not be fatal. The user can try to + * set other configurations. */ + } + } + dev_info(&usb_dev->dev, "authorized to connect\n"); +error_configure: +error_device_descriptor: +error_autoresume: +out_authorized: + usb_unlock_device(usb_dev); // complements locktree + return result; +} + + static int hub_port_status(struct usb_hub *hub, int port1, u16 *status, u16 *change) { @@ -1460,6 +1587,11 @@ static int hub_port_reset(struct usb_hub *hub, int port1, { int i, status; + /* Block EHCI CF initialization during the port reset. + * Some companion controllers don't like it when they mix. + */ + down_read(&ehci_cf_port_reset_rwsem); + /* Reset the port */ for (i = 0; i < PORT_RESET_TRIES; i++) { status = set_port_feature(hub->hdev, @@ -1481,6 +1613,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1, case 0: /* TRSTRCY = 10 ms; plus some extra */ msleep(10 + 40); + udev->devnum = 0; /* Device now at address 0 */ /* FALL THROUGH */ case -ENOTCONN: case -ENODEV: @@ -1490,7 +1623,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1, usb_set_device_state(udev, status ? USB_STATE_NOTATTACHED : USB_STATE_DEFAULT); - return status; + goto done; } dev_dbg (hub->intfdev, @@ -1503,6 +1636,8 @@ static int hub_port_reset(struct usb_hub *hub, int port1, "Cannot enable port %i. Maybe the USB cable is bad?\n", port1); + done: + up_read(&ehci_cf_port_reset_rwsem); return status; } @@ -1833,14 +1968,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) struct usb_device *udev; udev = hdev->children [port1-1]; - if (udev && msg.event == PM_EVENT_SUSPEND && -#ifdef CONFIG_USB_SUSPEND - udev->state != USB_STATE_SUSPENDED -#else - udev->dev.power.power_state.event - == PM_EVENT_ON -#endif - ) { + if (udev && udev->can_submit) { if (!hdev->auto_pm) dev_dbg(&intf->dev, "port %d nyet suspended\n", port1); @@ -1999,26 +2127,27 @@ static void ep0_reinit(struct usb_device *udev) { usb_disable_endpoint(udev, 0 + USB_DIR_IN); usb_disable_endpoint(udev, 0 + USB_DIR_OUT); - udev->ep_in[0] = udev->ep_out[0] = &udev->ep0; + usb_enable_endpoint(udev, &udev->ep0); } #define usb_sndaddr0pipe() (PIPE_CONTROL << 30) #define usb_rcvaddr0pipe() ((PIPE_CONTROL << 30) | USB_DIR_IN) -static int hub_set_address(struct usb_device *udev) +static int hub_set_address(struct usb_device *udev, int devnum) { int retval; - if (udev->devnum == 0) + if (devnum <= 1) return -EINVAL; if (udev->state == USB_STATE_ADDRESS) return 0; if (udev->state != USB_STATE_DEFAULT) return -EINVAL; retval = usb_control_msg(udev, usb_sndaddr0pipe(), - USB_REQ_SET_ADDRESS, 0, udev->devnum, 0, + USB_REQ_SET_ADDRESS, 0, devnum, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); if (retval == 0) { + udev->devnum = devnum; /* Device now using proper address */ usb_set_device_state(udev, USB_STATE_ADDRESS); ep0_reinit(udev); } @@ -2045,6 +2174,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, unsigned delay = HUB_SHORT_RESET_TIME; enum usb_device_speed oldspeed = udev->speed; char *speed, *type; + int devnum = udev->devnum; /* root hub ports have a slightly longer reset period * (from USB 2.0 spec, section 7.1.7.5) @@ -2074,7 +2204,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, goto fail; } oldspeed = udev->speed; - + /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ... * it's fixed size except for full speed devices. * For Wireless USB devices, ep0 max packet is always 512 (tho @@ -2115,7 +2245,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, dev_info (&udev->dev, "%s %s speed %sUSB device using %s and address %d\n", (udev->config) ? "reset" : "new", speed, type, - udev->bus->controller->driver->name, udev->devnum); + udev->bus->controller->driver->name, devnum); /* Set up TT records, if needed */ if (hdev->tt) { @@ -2202,7 +2332,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, } for (j = 0; j < SET_ADDRESS_TRIES; ++j) { - retval = hub_set_address(udev); + retval = hub_set_address(udev, devnum); if (retval >= 0) break; msleep(200); @@ -2210,7 +2340,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, if (retval < 0) { dev_err(&udev->dev, "device not accepting address %d, error %d\n", - udev->devnum, retval); + devnum, retval); goto fail; } @@ -2263,8 +2393,10 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, retval = 0; fail: - if (retval) + if (retval) { hub_port_disable(hub, port1, 0); + udev->devnum = devnum; /* for disconnect processing */ + } mutex_unlock(&usb_address0_mutex); return retval; } @@ -2699,9 +2831,9 @@ static void hub_events(void) clear_hub_feature(hdev, C_HUB_LOCAL_POWER); if (hubstatus & HUB_STATUS_LOCAL_POWER) /* FIXME: Is this always true? */ - hub->limited_power = 0; - else hub->limited_power = 1; + else + hub->limited_power = 0; } if (hubchange & HUB_CHANGE_OVERCURRENT) { dev_dbg (hub_dev, "overcurrent change\n"); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index d8f7b089a8f0..c021af390372 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -59,8 +59,8 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length) dev_dbg(&urb->dev->dev, "%s timed out on ep%d%s len=%d/%d\n", current->comm, - usb_pipeendpoint(urb->pipe), - usb_pipein(urb->pipe) ? "in" : "out", + usb_endpoint_num(&urb->ep->desc), + usb_urb_dir_in(urb) ? "in" : "out", urb->actual_length, urb->transfer_buffer_length); } else @@ -250,7 +250,8 @@ static void sg_clean (struct usb_sg_request *io) io->urbs = NULL; } if (io->dev->dev.dma_mask != NULL) - usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents); + usb_buffer_unmap_sg (io->dev, usb_pipein(io->pipe), + io->sg, io->nents); io->dev = NULL; } @@ -278,8 +279,8 @@ static void sg_complete (struct urb *urb) dev_err (io->dev->bus->controller, "dev %s ep%d%s scatterlist error %d/%d\n", io->dev->devpath, - usb_pipeendpoint (urb->pipe), - usb_pipein (urb->pipe) ? "in" : "out", + usb_endpoint_num(&urb->ep->desc), + usb_urb_dir_in(urb) ? "in" : "out", status, io->status); // BUG (); } @@ -379,7 +380,8 @@ int usb_sg_init ( */ dma = (dev->dev.dma_mask != NULL); if (dma) - io->entries = usb_buffer_map_sg (dev, pipe, sg, nents); + io->entries = usb_buffer_map_sg(dev, usb_pipein(pipe), + sg, nents); else io->entries = nents; @@ -1013,8 +1015,11 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr) ep = dev->ep_in[epnum]; dev->ep_in[epnum] = NULL; } - if (ep && dev->bus) - usb_hcd_endpoint_disable(dev, ep); + if (ep) { + ep->enabled = 0; + usb_hcd_flush_endpoint(dev, ep); + usb_hcd_disable_endpoint(dev, ep); + } } /** @@ -1096,23 +1101,21 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) * Resets the endpoint toggle, and sets dev->ep_{in,out} pointers. * For control endpoints, both the input and output sides are handled. */ -static void -usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep) +void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep) { - unsigned int epaddr = ep->desc.bEndpointAddress; - unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK; - int is_control; + int epnum = usb_endpoint_num(&ep->desc); + int is_out = usb_endpoint_dir_out(&ep->desc); + int is_control = usb_endpoint_xfer_control(&ep->desc); - is_control = ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_CONTROL); - if (usb_endpoint_out(epaddr) || is_control) { + if (is_out || is_control) { usb_settoggle(dev, epnum, 1, 0); dev->ep_out[epnum] = ep; } - if (!usb_endpoint_out(epaddr) || is_control) { + if (!is_out || is_control) { usb_settoggle(dev, epnum, 0, 0); dev->ep_in[epnum] = ep; } + ep->enabled = 1; } /* @@ -1171,6 +1174,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) struct usb_host_interface *alt; int ret; int manual = 0; + int changed; if (dev->state == USB_STATE_SUSPENDED) return -EHOSTUNREACH; @@ -1210,7 +1214,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) */ /* prevent submissions using previous endpoint settings */ - if (device_is_registered(&iface->dev)) + changed = (iface->cur_altsetting != alt); + if (changed && device_is_registered(&iface->dev)) usb_remove_sysfs_intf_files(iface); usb_disable_interface(dev, iface); @@ -1247,7 +1252,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) * (Likewise, EP0 never "halts" on well designed devices.) */ usb_enable_interface(dev, iface); - if (device_is_registered(&iface->dev)) + if (changed && device_is_registered(&iface->dev)) usb_create_sysfs_intf_files(iface); return 0; @@ -1328,7 +1333,7 @@ int usb_reset_configuration(struct usb_device *dev) return 0; } -void usb_release_interface(struct device *dev) +static void usb_release_interface(struct device *dev) { struct usb_interface *intf = to_usb_interface(dev); struct usb_interface_cache *intfc = @@ -1339,14 +1344,11 @@ void usb_release_interface(struct device *dev) } #ifdef CONFIG_HOTPLUG -static int usb_if_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env) { struct usb_device *usb_dev; struct usb_interface *intf; struct usb_host_interface *alt; - int i = 0; - int length = 0; if (!dev) return -ENODEV; @@ -1359,39 +1361,30 @@ static int usb_if_uevent(struct device *dev, char **envp, int num_envp, alt = intf->cur_altsetting; #ifdef CONFIG_USB_DEVICEFS - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEVICE=/proc/bus/usb/%03d/%03d", + if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d", usb_dev->bus->busnum, usb_dev->devnum)) return -ENOMEM; #endif - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PRODUCT=%x/%x/%x", + if (add_uevent_var(env, "PRODUCT=%x/%x/%x", le16_to_cpu(usb_dev->descriptor.idVendor), le16_to_cpu(usb_dev->descriptor.idProduct), le16_to_cpu(usb_dev->descriptor.bcdDevice))) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "TYPE=%d/%d/%d", + if (add_uevent_var(env, "TYPE=%d/%d/%d", usb_dev->descriptor.bDeviceClass, usb_dev->descriptor.bDeviceSubClass, usb_dev->descriptor.bDeviceProtocol)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "INTERFACE=%d/%d/%d", + if (add_uevent_var(env, "INTERFACE=%d/%d/%d", alt->desc.bInterfaceClass, alt->desc.bInterfaceSubClass, alt->desc.bInterfaceProtocol)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, + if (add_uevent_var(env, "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X", le16_to_cpu(usb_dev->descriptor.idVendor), le16_to_cpu(usb_dev->descriptor.idProduct), @@ -1404,14 +1397,12 @@ static int usb_if_uevent(struct device *dev, char **envp, int num_envp, alt->desc.bInterfaceProtocol)) return -ENOMEM; - envp[i] = NULL; return 0; } #else -static int usb_if_uevent(struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size) +static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } @@ -1481,6 +1472,9 @@ static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev, * channels are available independently; and choosing between open * standard device protocols (like CDC) or proprietary ones. * + * Note that a non-authorized device (dev->authorized == 0) will only + * be put in unconfigured mode. + * * Note that USB has an additional level of device configurability, * associated with interfaces. That configurability is accessed using * usb_set_interface(). @@ -1502,7 +1496,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration) struct usb_interface **new_interfaces = NULL; int n, nintf; - if (configuration == -1) + if (dev->authorized == 0 || configuration == -1) configuration = 0; else { for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index ebf3dc20110a..d42c561c75f1 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -32,52 +32,6 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME }, /* HP 5300/5370C scanner */ { USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 }, - /* Hewlett-Packard PhotoSmart 720 / PhotoSmart 935 (storage) */ - { USB_DEVICE(0x03f0, 0x4002), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* SGS Thomson Microelectronics 4in1 card reader */ - { USB_DEVICE(0x0483, 0x0321), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* Acer Peripherals Inc. (now BenQ Corp.) Prisa 640BU */ - { USB_DEVICE(0x04a5, 0x207e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Benq S2W 3300U */ - { USB_DEVICE(0x04a5, 0x20b0), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Canon, Inc. CanoScan N1240U/LiDE30 */ - { USB_DEVICE(0x04a9, 0x220e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Canon, Inc. CanoScan N650U/N656U */ - { USB_DEVICE(0x04a9, 0x2206), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Canon, Inc. CanoScan 1220U */ - { USB_DEVICE(0x04a9, 0x2207), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Canon, Inc. CanoScan N670U/N676U/LiDE 20 */ - { USB_DEVICE(0x04a9, 0x220d), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* old Cannon scanner */ - { USB_DEVICE(0x04a9, 0x2220), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Seiko Epson Corp. Perfection 1200 */ - { USB_DEVICE(0x04b8, 0x0104), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Seiko Epson Corp. Perfection 660 */ - { USB_DEVICE(0x04b8, 0x0114), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Epson Perfection 1260 Photo */ - { USB_DEVICE(0x04b8, 0x011d), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Seiko Epson Corp - Perfection 1670 */ - { USB_DEVICE(0x04b8, 0x011f), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* EPSON Perfection 2480 */ - { USB_DEVICE(0x04b8, 0x0121), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Seiko Epson Corp.*/ - { USB_DEVICE(0x04b8, 0x0122), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Samsung ML-2010 printer */ - { USB_DEVICE(0x04e8, 0x326c), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Samsung ML-2510 Series printer */ - { USB_DEVICE(0x04e8, 0x327e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Elsa MicroLink 56k (V.250) */ - { USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Ultima Electronics Corp.*/ - { USB_DEVICE(0x05d8, 0x4005), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* Genesys USB-to-IDE */ - { USB_DEVICE(0x0503, 0x0702), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* USB Graphical LCD - EEH Datalink GmbH */ - { USB_DEVICE(0x060c, 0x04eb), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, /* INTEL VALUE SSD */ { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME }, @@ -85,44 +39,15 @@ static const struct usb_device_id usb_quirk_list[] = { /* M-Systems Flash Disk Pioneers */ { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME }, - /* Agfa Snapscan1212u */ - { USB_DEVICE(0x06bd, 0x2061), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Seagate RSS LLC */ - { USB_DEVICE(0x0bc2, 0x3000), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Umax [hex] Astra 3400U */ - { USB_DEVICE(0x1606, 0x0060), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Philips PSC805 audio device */ { USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME }, - /* Alcor multi-card reader */ - { USB_DEVICE(0x058f, 0x6366), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* Canon EOS 5D in PC Connection mode */ - { USB_DEVICE(0x04a9, 0x3101), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* RIM Blackberry */ - { USB_DEVICE(0x0fca, 0x0001), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - { USB_DEVICE(0x0fca, 0x0004), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - { USB_DEVICE(0x0fca, 0x0006), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* Apple iPhone */ - { USB_DEVICE(0x05ac, 0x1290), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* SKYMEDI USB_DRIVE */ { USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME }, { } /* 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_disabled = 1; -#endif -} - static const struct usb_device_id *find_id(struct usb_device *udev) { const struct usb_device_id *id = usb_quirk_list; @@ -149,13 +74,9 @@ void usb_detect_quirks(struct usb_device *udev) 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); - /* By default, disable autosuspend for all non-hubs */ #ifdef CONFIG_USB_SUSPEND if (udev->descriptor.bDeviceClass != USB_CLASS_HUB) - udev->autosuspend_delay = -1; + udev->autosuspend_disabled = 1; #endif } diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 2ab222be8fd1..b04afd06e502 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -169,6 +169,16 @@ show_quirks(struct device *dev, struct device_attribute *attr, char *buf) } static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL); +static ssize_t +show_urbnum(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct usb_device *udev; + + udev = to_usb_device(dev); + return sprintf(buf, "%d\n", atomic_read(&udev->urbnum)); +} +static DEVICE_ATTR(urbnum, S_IRUGO, show_urbnum, NULL); + #if defined(CONFIG_USB_PERSIST) || defined(CONFIG_USB_SUSPEND) static const char power_group[] = "power"; @@ -413,6 +423,44 @@ usb_descriptor_attr(bDeviceProtocol, "%02x\n") usb_descriptor_attr(bNumConfigurations, "%d\n") usb_descriptor_attr(bMaxPacketSize0, "%d\n") + + +/* show if the device is authorized (1) or not (0) */ +static ssize_t usb_dev_authorized_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct usb_device *usb_dev = to_usb_device(dev); + return snprintf(buf, PAGE_SIZE, "%u\n", usb_dev->authorized); +} + + +/* + * Authorize a device to be used in the system + * + * Writing a 0 deauthorizes the device, writing a 1 authorizes it. + */ +static ssize_t usb_dev_authorized_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + ssize_t result; + struct usb_device *usb_dev = to_usb_device(dev); + unsigned val; + result = sscanf(buf, "%u\n", &val); + if (result != 1) + result = -EINVAL; + else if (val == 0) + result = usb_deauthorize_device(usb_dev); + else + result = usb_authorize_device(usb_dev); + return result < 0? result : size; +} + +static DEVICE_ATTR(authorized, 0644, + usb_dev_authorized_show, usb_dev_authorized_store); + + static struct attribute *dev_attrs[] = { /* current configuration's attributes */ &dev_attr_configuration.attr, @@ -420,6 +468,7 @@ static struct attribute *dev_attrs[] = { &dev_attr_bConfigurationValue.attr, &dev_attr_bmAttributes.attr, &dev_attr_bMaxPower.attr, + &dev_attr_urbnum.attr, /* device attributes */ &dev_attr_idVendor.attr, &dev_attr_idProduct.attr, @@ -435,6 +484,7 @@ static struct attribute *dev_attrs[] = { &dev_attr_version.attr, &dev_attr_maxchild.attr, &dev_attr_quirks.attr, + &dev_attr_authorized.attr, NULL, }; static struct attribute_group dev_attr_grp = { diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index be630228461c..c20c03aaf012 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -3,6 +3,7 @@ #include <linux/bitops.h> #include <linux/slab.h> #include <linux/init.h> +#include <linux/log2.h> #include <linux/usb.h> #include <linux/wait.h> #include "hcd.h" @@ -38,7 +39,6 @@ void usb_init_urb(struct urb *urb) if (urb) { memset(urb, 0, sizeof(*urb)); kref_init(&urb->kref); - spin_lock_init(&urb->lock); INIT_LIST_HEAD(&urb->anchor_list); } } @@ -277,44 +277,58 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb); */ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) { - int pipe, temp, max; - struct usb_device *dev; - int is_out; + int xfertype, max; + struct usb_device *dev; + struct usb_host_endpoint *ep; + int is_out; if (!urb || urb->hcpriv || !urb->complete) return -EINVAL; - if (!(dev = urb->dev) || - (dev->state < USB_STATE_DEFAULT) || - (!dev->bus) || (dev->devnum <= 0)) + if (!(dev = urb->dev) || dev->state < USB_STATE_DEFAULT) return -ENODEV; - if (dev->bus->controller->power.power_state.event != PM_EVENT_ON - || dev->state == USB_STATE_SUSPENDED) - return -EHOSTUNREACH; + /* For now, get the endpoint from the pipe. Eventually drivers + * will be required to set urb->ep directly and we will eliminate + * urb->pipe. + */ + ep = (usb_pipein(urb->pipe) ? dev->ep_in : dev->ep_out) + [usb_pipeendpoint(urb->pipe)]; + if (!ep) + return -ENOENT; + + urb->ep = ep; urb->status = -EINPROGRESS; urb->actual_length = 0; /* Lots of sanity checks, so HCDs can rely on clean data * and don't need to duplicate tests */ - pipe = urb->pipe; - temp = usb_pipetype(pipe); - is_out = usb_pipeout(pipe); + xfertype = usb_endpoint_type(&ep->desc); + if (xfertype == USB_ENDPOINT_XFER_CONTROL) { + struct usb_ctrlrequest *setup = + (struct usb_ctrlrequest *) urb->setup_packet; + + if (!setup) + return -ENOEXEC; + is_out = !(setup->bRequestType & USB_DIR_IN) || + !setup->wLength; + } else { + is_out = usb_endpoint_dir_out(&ep->desc); + } - if (!usb_pipecontrol(pipe) && dev->state < USB_STATE_CONFIGURED) - return -ENODEV; + /* Cache the direction for later use */ + urb->transfer_flags = (urb->transfer_flags & ~URB_DIR_MASK) | + (is_out ? URB_DIR_OUT : URB_DIR_IN); - /* FIXME there should be a sharable lock protecting us against - * config/altsetting changes and disconnects, kicking in here. - * (here == before maxpacket, and eventually endpoint type, - * checks get made.) - */ + if (xfertype != USB_ENDPOINT_XFER_CONTROL && + dev->state < USB_STATE_CONFIGURED) + return -ENODEV; - max = usb_maxpacket(dev, pipe, is_out); + max = le16_to_cpu(ep->desc.wMaxPacketSize); if (max <= 0) { dev_dbg(&dev->dev, "bogus endpoint ep%d%s in %s (bad maxpacket %d)\n", - usb_pipeendpoint(pipe), is_out ? "out" : "in", + usb_endpoint_num(&ep->desc), is_out ? "out" : "in", __FUNCTION__, max); return -EMSGSIZE; } @@ -323,7 +337,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) * but drivers only control those sizes for ISO. * while we're checking, initialize return status. */ - if (temp == PIPE_ISOCHRONOUS) { + if (xfertype == USB_ENDPOINT_XFER_ISOC) { int n, len; /* "high bandwidth" mode, 1-3 packets/uframe? */ @@ -358,20 +372,20 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) /* enforce simple/standard policy */ allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP | - URB_NO_INTERRUPT); - switch (temp) { - case PIPE_BULK: + URB_NO_INTERRUPT | URB_DIR_MASK); + switch (xfertype) { + case USB_ENDPOINT_XFER_BULK: if (is_out) allowed |= URB_ZERO_PACKET; /* FALLTHROUGH */ - case PIPE_CONTROL: + case USB_ENDPOINT_XFER_CONTROL: allowed |= URB_NO_FSBR; /* only affects UHCI */ /* FALLTHROUGH */ default: /* all non-iso endpoints */ if (!is_out) allowed |= URB_SHORT_NOT_OK; break; - case PIPE_ISOCHRONOUS: + case USB_ENDPOINT_XFER_ISOC: allowed |= URB_ISO_ASAP; break; } @@ -393,9 +407,9 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) * supports different values... this uses EHCI/UHCI defaults (and * EHCI can use smaller non-default values). */ - switch (temp) { - case PIPE_ISOCHRONOUS: - case PIPE_INTERRUPT: + switch (xfertype) { + case USB_ENDPOINT_XFER_ISOC: + case USB_ENDPOINT_XFER_INT: /* too small? */ if (urb->interval <= 0) return -EINVAL; @@ -405,29 +419,27 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) // NOTE usb handles 2^15 if (urb->interval > (1024 * 8)) urb->interval = 1024 * 8; - temp = 1024 * 8; + max = 1024 * 8; break; case USB_SPEED_FULL: /* units are frames/msec */ case USB_SPEED_LOW: - if (temp == PIPE_INTERRUPT) { + if (xfertype == USB_ENDPOINT_XFER_INT) { if (urb->interval > 255) return -EINVAL; // NOTE ohci only handles up to 32 - temp = 128; + max = 128; } else { if (urb->interval > 1024) urb->interval = 1024; // NOTE usb and ohci handle up to 2^15 - temp = 1024; + max = 1024; } break; default: return -EINVAL; } - /* power of two? */ - while (temp > urb->interval) - temp >>= 1; - urb->interval = temp; + /* Round down to a power of 2, no more than max */ + urb->interval = min(max, 1 << ilog2(urb->interval)); } return usb_hcd_submit_urb(urb, mem_flags); @@ -496,8 +508,10 @@ int usb_unlink_urb(struct urb *urb) { if (!urb) return -EINVAL; - if (!(urb->dev && urb->dev->bus)) + if (!urb->dev) return -ENODEV; + if (!urb->ep) + return -EIDRM; return usb_hcd_unlink_urb(urb, -ECONNRESET); } @@ -523,19 +537,21 @@ int usb_unlink_urb(struct urb *urb) */ void usb_kill_urb(struct urb *urb) { + static DEFINE_MUTEX(reject_mutex); + might_sleep(); - if (!(urb && urb->dev && urb->dev->bus)) + if (!(urb && urb->dev && urb->ep)) return; - spin_lock_irq(&urb->lock); + mutex_lock(&reject_mutex); ++urb->reject; - spin_unlock_irq(&urb->lock); + mutex_unlock(&reject_mutex); usb_hcd_unlink_urb(urb, -ENOENT); wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0); - spin_lock_irq(&urb->lock); + mutex_lock(&reject_mutex); --urb->reject; - spin_unlock_irq(&urb->lock); + mutex_unlock(&reject_mutex); } /** diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 0fee5c66fd64..c99938d5f78e 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -223,6 +223,15 @@ static void ksuspend_usb_cleanup(void) #endif /* CONFIG_PM */ + +/* Returns 1 if @usb_bus is WUSB, 0 otherwise */ +static unsigned usb_bus_is_wusb(struct usb_bus *bus) +{ + struct usb_hcd *hcd = container_of(bus, struct usb_hcd, self); + return hcd->wireless; +} + + /** * usb_alloc_dev - usb device constructor (usbcore-internal) * @parent: hub to which device is connected; null to allocate a root hub @@ -239,6 +248,8 @@ struct usb_device * usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) { struct usb_device *dev; + struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self); + unsigned root_hub = 0; dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) @@ -255,12 +266,14 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) dev->dev.dma_mask = bus->controller->dma_mask; set_dev_node(&dev->dev, dev_to_node(bus->controller)); dev->state = USB_STATE_ATTACHED; + atomic_set(&dev->urbnum, 0); INIT_LIST_HEAD(&dev->ep0.urb_list); dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE; dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT; /* ep0 maxpacket comes later, from device descriptor */ - dev->ep_in[0] = dev->ep_out[0] = &dev->ep0; + usb_enable_endpoint(dev, &dev->ep0); + dev->can_submit = 1; /* Save readable and stable topology id, distinguishing devices * by location for diagnostics, tools, driver model, etc. The @@ -275,6 +288,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) dev->dev.parent = bus->controller; sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum); + root_hub = 1; } else { /* match any labeling on the hubs; it's one-based */ if (parent->devpath[0] == '0') @@ -301,6 +315,12 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work); dev->autosuspend_delay = usb_autosuspend_delay * HZ; #endif + if (root_hub) /* Root hub always ok [and always wired] */ + dev->authorized = 1; + else { + dev->authorized = usb_hcd->authorized_default; + dev->wusb = usb_bus_is_wusb(bus)? 1 : 0; + } return dev; } @@ -748,7 +768,7 @@ void usb_buffer_unmap(struct urb *urb) /** * usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint * @dev: device to which the scatterlist will be mapped - * @pipe: endpoint defining the mapping direction + * @is_in: mapping transfer direction * @sg: the scatterlist to map * @nents: the number of entries in the scatterlist * @@ -771,14 +791,13 @@ void usb_buffer_unmap(struct urb *urb) * * Reverse the effect of this call with usb_buffer_unmap_sg(). */ -int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe, +int usb_buffer_map_sg(const struct usb_device *dev, int is_in, struct scatterlist *sg, int nents) { struct usb_bus *bus; struct device *controller; if (!dev - || usb_pipecontrol(pipe) || !(bus = dev->bus) || !(controller = bus->controller) || !controller->dma_mask) @@ -786,7 +805,7 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe, // FIXME generic api broken like pci, can't report errors return dma_map_sg(controller, sg, nents, - usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } /* XXX DISABLED, no users currently. If you wish to re-enable this @@ -799,14 +818,14 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe, /** * usb_buffer_dmasync_sg - synchronize DMA and CPU view of scatterlist buffer(s) * @dev: device to which the scatterlist will be mapped - * @pipe: endpoint defining the mapping direction + * @is_in: mapping transfer direction * @sg: the scatterlist to synchronize * @n_hw_ents: the positive return value from usb_buffer_map_sg * * Use this when you are re-using a scatterlist's data buffers for * another USB request. */ -void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe, +void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in, struct scatterlist *sg, int n_hw_ents) { struct usb_bus *bus; @@ -819,20 +838,20 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe, return; dma_sync_sg(controller, sg, n_hw_ents, - usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } #endif /** * usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist * @dev: device to which the scatterlist will be mapped - * @pipe: endpoint defining the mapping direction + * @is_in: mapping transfer direction * @sg: the scatterlist to unmap * @n_hw_ents: the positive return value from usb_buffer_map_sg * * Reverses the effect of usb_buffer_map_sg(). */ -void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe, +void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in, struct scatterlist *sg, int n_hw_ents) { struct usb_bus *bus; @@ -845,7 +864,7 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe, return; dma_unmap_sg(controller, sg, n_hw_ents, - usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } /* format to disable USB on kernel command line is: nousb */ diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index ad5fa0338f49..c52626c51f70 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -8,17 +8,22 @@ extern int usb_create_ep_files(struct device *parent, struct usb_host_endpoint * struct usb_device *udev); extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint); +extern void usb_enable_endpoint(struct usb_device *dev, + struct usb_host_endpoint *ep); extern void usb_disable_endpoint (struct usb_device *dev, unsigned int epaddr); 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 int usb_deauthorize_device (struct usb_device *); +extern int usb_authorize_device (struct usb_device *); extern void usb_detect_quirks(struct usb_device *udev); extern int usb_get_device_descriptor(struct usb_device *dev, unsigned int size); extern char *usb_cache_string(struct usb_device *udev, int index); extern int usb_set_configuration(struct usb_device *dev, int configuration); +extern int usb_choose_configuration(struct usb_device *udev); extern void usb_kick_khubd(struct usb_device *dev); extern int usb_match_device(struct usb_device *dev, diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 767aed5b4bea..f81d08d6538b 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -67,6 +67,17 @@ config USB_GADGET_DEBUG_FILES driver on a new board. Enable these files by choosing "Y" here. If in doubt, or to conserve kernel memory, say "N". +config USB_GADGET_DEBUG_FS + boolean "Debugging information files in debugfs" + depends on USB_GADGET && DEBUG_FS + help + Some of the drivers in the "gadget" framework can expose + debugging information in files under /sys/kernel/debug/. + The information in these files may help when you're + troubleshooting or bringing up a driver on a new board. + Enable these files by choosing "Y" here. If in doubt, or + to conserve kernel memory, say "N". + config USB_GADGET_SELECTED boolean @@ -103,6 +114,20 @@ config USB_AMD5536UDC default USB_GADGET select USB_GADGET_SELECTED +config USB_GADGET_ATMEL_USBA + boolean "Atmel USBA" + select USB_GADGET_DUALSPEED + depends on AVR32 + help + USBA is the integrated high-speed USB Device controller on + the AT32AP700x processors from Atmel. + +config USB_ATMEL_USBA + tristate + depends on USB_GADGET_ATMEL_USBA + default USB_GADGET + select USB_GADGET_SELECTED + config USB_GADGET_FSL_USB2 boolean "Freescale Highspeed USB DR Peripheral Controller" depends on MPC834x || PPC_MPC831x @@ -228,7 +253,6 @@ config USB_LH7A40X default USB_GADGET select USB_GADGET_SELECTED - config USB_GADGET_OMAP boolean "OMAP USB Device Controller" depends on ARCH_OMAP diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 1bc0f03550ce..904e57bf6112 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_USB_OMAP) += omap_udc.o obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o obj-$(CONFIG_USB_S3C2410) += s3c2410_udc.o obj-$(CONFIG_USB_AT91) += at91_udc.o +obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o obj-$(CONFIG_USB_M66592) += m66592-udc.o diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index 714156ca8fe4..1c8040602525 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -69,7 +69,7 @@ /* gadget stack */ #include <linux/usb/ch9.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> /* udc specific */ #include "amd5536udc.h" @@ -3244,7 +3244,6 @@ static int udc_pci_probe( retval = -ENOMEM; goto finished; } - memset(dev, 0, sizeof(struct udc)); /* pci setup */ if (pci_enable_device(pdev) < 0) { @@ -3286,14 +3285,12 @@ static int udc_pci_probe( pci_set_drvdata(pdev, dev); - /* chip revision */ - dev->chiprev = 0; + /* chip revision for Hs AMD5536 */ + dev->chiprev = pdev->revision; pci_set_master(pdev); pci_set_mwi(pdev); - /* chip rev for Hs AMD5536 */ - pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) &dev->chiprev); /* init dma pools */ if (use_dma) { retval = init_dma_pools(dev); diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 63d7d6568699..a6adf7e0f6f8 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -38,7 +38,7 @@ #include <linux/proc_fs.h> #include <linux/clk.h> #include <linux/usb/ch9.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> #include <asm/byteorder.h> #include <asm/hardware.h> diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c new file mode 100644 index 000000000000..4fb5ff469574 --- /dev/null +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -0,0 +1,2077 @@ +/* + * Driver for the Atmel USBA high speed USB device controller + * + * Copyright (C) 2005-2007 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/list.h> +#include <linux/platform_device.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/delay.h> + +#include <asm/gpio.h> +#include <asm/arch/board.h> + +#include "atmel_usba_udc.h" + + +static struct usba_udc the_udc; + +#ifdef CONFIG_USB_GADGET_DEBUG_FS +#include <linux/debugfs.h> +#include <linux/uaccess.h> + +static int queue_dbg_open(struct inode *inode, struct file *file) +{ + struct usba_ep *ep = inode->i_private; + struct usba_request *req, *req_copy; + struct list_head *queue_data; + + queue_data = kmalloc(sizeof(*queue_data), GFP_KERNEL); + if (!queue_data) + return -ENOMEM; + INIT_LIST_HEAD(queue_data); + + spin_lock_irq(&ep->udc->lock); + list_for_each_entry(req, &ep->queue, queue) { + req_copy = kmalloc(sizeof(*req_copy), GFP_ATOMIC); + if (!req_copy) + goto fail; + memcpy(req_copy, req, sizeof(*req_copy)); + list_add_tail(&req_copy->queue, queue_data); + } + spin_unlock_irq(&ep->udc->lock); + + file->private_data = queue_data; + return 0; + +fail: + spin_unlock_irq(&ep->udc->lock); + list_for_each_entry_safe(req, req_copy, queue_data, queue) { + list_del(&req->queue); + kfree(req); + } + kfree(queue_data); + return -ENOMEM; +} + +/* + * bbbbbbbb llllllll IZS sssss nnnn FDL\n\0 + * + * b: buffer address + * l: buffer length + * I/i: interrupt/no interrupt + * Z/z: zero/no zero + * S/s: short ok/short not ok + * s: status + * n: nr_packets + * F/f: submitted/not submitted to FIFO + * D/d: using/not using DMA + * L/l: last transaction/not last transaction + */ +static ssize_t queue_dbg_read(struct file *file, char __user *buf, + size_t nbytes, loff_t *ppos) +{ + struct list_head *queue = file->private_data; + struct usba_request *req, *tmp_req; + size_t len, remaining, actual = 0; + char tmpbuf[38]; + + if (!access_ok(VERIFY_WRITE, buf, nbytes)) + return -EFAULT; + + mutex_lock(&file->f_dentry->d_inode->i_mutex); + list_for_each_entry_safe(req, tmp_req, queue, queue) { + len = snprintf(tmpbuf, sizeof(tmpbuf), + "%8p %08x %c%c%c %5d %c%c%c\n", + req->req.buf, req->req.length, + req->req.no_interrupt ? 'i' : 'I', + req->req.zero ? 'Z' : 'z', + req->req.short_not_ok ? 's' : 'S', + req->req.status, + req->submitted ? 'F' : 'f', + req->using_dma ? 'D' : 'd', + req->last_transaction ? 'L' : 'l'); + len = min(len, sizeof(tmpbuf)); + if (len > nbytes) + break; + + list_del(&req->queue); + kfree(req); + + remaining = __copy_to_user(buf, tmpbuf, len); + actual += len - remaining; + if (remaining) + break; + + nbytes -= len; + buf += len; + } + mutex_unlock(&file->f_dentry->d_inode->i_mutex); + + return actual; +} + +static int queue_dbg_release(struct inode *inode, struct file *file) +{ + struct list_head *queue_data = file->private_data; + struct usba_request *req, *tmp_req; + + list_for_each_entry_safe(req, tmp_req, queue_data, queue) { + list_del(&req->queue); + kfree(req); + } + kfree(queue_data); + return 0; +} + +static int regs_dbg_open(struct inode *inode, struct file *file) +{ + struct usba_udc *udc; + unsigned int i; + u32 *data; + int ret = -ENOMEM; + + mutex_lock(&inode->i_mutex); + udc = inode->i_private; + data = kmalloc(inode->i_size, GFP_KERNEL); + if (!data) + goto out; + + spin_lock_irq(&udc->lock); + for (i = 0; i < inode->i_size / 4; i++) + data[i] = __raw_readl(udc->regs + i * 4); + spin_unlock_irq(&udc->lock); + + file->private_data = data; + ret = 0; + +out: + mutex_unlock(&inode->i_mutex); + + return ret; +} + +static ssize_t regs_dbg_read(struct file *file, char __user *buf, + size_t nbytes, loff_t *ppos) +{ + struct inode *inode = file->f_dentry->d_inode; + int ret; + + mutex_lock(&inode->i_mutex); + ret = simple_read_from_buffer(buf, nbytes, ppos, + file->private_data, + file->f_dentry->d_inode->i_size); + mutex_unlock(&inode->i_mutex); + + return ret; +} + +static int regs_dbg_release(struct inode *inode, struct file *file) +{ + kfree(file->private_data); + return 0; +} + +const struct file_operations queue_dbg_fops = { + .owner = THIS_MODULE, + .open = queue_dbg_open, + .llseek = no_llseek, + .read = queue_dbg_read, + .release = queue_dbg_release, +}; + +const struct file_operations regs_dbg_fops = { + .owner = THIS_MODULE, + .open = regs_dbg_open, + .llseek = generic_file_llseek, + .read = regs_dbg_read, + .release = regs_dbg_release, +}; + +static void usba_ep_init_debugfs(struct usba_udc *udc, + struct usba_ep *ep) +{ + struct dentry *ep_root; + + ep_root = debugfs_create_dir(ep->ep.name, udc->debugfs_root); + if (!ep_root) + goto err_root; + ep->debugfs_dir = ep_root; + + ep->debugfs_queue = debugfs_create_file("queue", 0400, ep_root, + ep, &queue_dbg_fops); + if (!ep->debugfs_queue) + goto err_queue; + + if (ep->can_dma) { + ep->debugfs_dma_status + = debugfs_create_u32("dma_status", 0400, ep_root, + &ep->last_dma_status); + if (!ep->debugfs_dma_status) + goto err_dma_status; + } + if (ep_is_control(ep)) { + ep->debugfs_state + = debugfs_create_u32("state", 0400, ep_root, + &ep->state); + if (!ep->debugfs_state) + goto err_state; + } + + return; + +err_state: + if (ep->can_dma) + debugfs_remove(ep->debugfs_dma_status); +err_dma_status: + debugfs_remove(ep->debugfs_queue); +err_queue: + debugfs_remove(ep_root); +err_root: + dev_err(&ep->udc->pdev->dev, + "failed to create debugfs directory for %s\n", ep->ep.name); +} + +static void usba_ep_cleanup_debugfs(struct usba_ep *ep) +{ + debugfs_remove(ep->debugfs_queue); + debugfs_remove(ep->debugfs_dma_status); + debugfs_remove(ep->debugfs_state); + debugfs_remove(ep->debugfs_dir); + ep->debugfs_dma_status = NULL; + ep->debugfs_dir = NULL; +} + +static void usba_init_debugfs(struct usba_udc *udc) +{ + struct dentry *root, *regs; + struct resource *regs_resource; + + root = debugfs_create_dir(udc->gadget.name, NULL); + if (IS_ERR(root) || !root) + goto err_root; + udc->debugfs_root = root; + + regs = debugfs_create_file("regs", 0400, root, udc, ®s_dbg_fops); + if (!regs) + goto err_regs; + + regs_resource = platform_get_resource(udc->pdev, IORESOURCE_MEM, + CTRL_IOMEM_ID); + regs->d_inode->i_size = regs_resource->end - regs_resource->start + 1; + udc->debugfs_regs = regs; + + usba_ep_init_debugfs(udc, to_usba_ep(udc->gadget.ep0)); + + return; + +err_regs: + debugfs_remove(root); +err_root: + udc->debugfs_root = NULL; + dev_err(&udc->pdev->dev, "debugfs is not available\n"); +} + +static void usba_cleanup_debugfs(struct usba_udc *udc) +{ + usba_ep_cleanup_debugfs(to_usba_ep(udc->gadget.ep0)); + debugfs_remove(udc->debugfs_regs); + debugfs_remove(udc->debugfs_root); + udc->debugfs_regs = NULL; + udc->debugfs_root = NULL; +} +#else +static inline void usba_ep_init_debugfs(struct usba_udc *udc, + struct usba_ep *ep) +{ + +} + +static inline void usba_ep_cleanup_debugfs(struct usba_ep *ep) +{ + +} + +static inline void usba_init_debugfs(struct usba_udc *udc) +{ + +} + +static inline void usba_cleanup_debugfs(struct usba_udc *udc) +{ + +} +#endif + +static int vbus_is_present(struct usba_udc *udc) +{ + if (udc->vbus_pin != -1) + return gpio_get_value(udc->vbus_pin); + + /* No Vbus detection: Assume always present */ + return 1; +} + +static void copy_to_fifo(void __iomem *fifo, const void *buf, int len) +{ + unsigned long tmp; + + DBG(DBG_FIFO, "copy to FIFO (len %d):\n", len); + for (; len > 0; len -= 4, buf += 4, fifo += 4) { + tmp = *(unsigned long *)buf; + if (len >= 4) { + DBG(DBG_FIFO, " -> %08lx\n", tmp); + __raw_writel(tmp, fifo); + } else { + do { + DBG(DBG_FIFO, " -> %02lx\n", tmp >> 24); + __raw_writeb(tmp >> 24, fifo); + fifo++; + tmp <<= 8; + } while (--len); + break; + } + } +} + +static void copy_from_fifo(void *buf, void __iomem *fifo, int len) +{ + union { + unsigned long *w; + unsigned char *b; + } p; + unsigned long tmp; + + DBG(DBG_FIFO, "copy from FIFO (len %d):\n", len); + for (p.w = buf; len > 0; len -= 4, p.w++, fifo += 4) { + if (len >= 4) { + tmp = __raw_readl(fifo); + *p.w = tmp; + DBG(DBG_FIFO, " -> %08lx\n", tmp); + } else { + do { + tmp = __raw_readb(fifo); + *p.b = tmp; + DBG(DBG_FIFO, " -> %02lx\n", tmp); + fifo++, p.b++; + } while (--len); + } + } +} + +static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req) +{ + unsigned int transaction_len; + + transaction_len = req->req.length - req->req.actual; + req->last_transaction = 1; + if (transaction_len > ep->ep.maxpacket) { + transaction_len = ep->ep.maxpacket; + req->last_transaction = 0; + } else if (transaction_len == ep->ep.maxpacket && req->req.zero) + req->last_transaction = 0; + + DBG(DBG_QUEUE, "%s: submit_transaction, req %p (length %d)%s\n", + ep->ep.name, req, transaction_len, + req->last_transaction ? ", done" : ""); + + copy_to_fifo(ep->fifo, req->req.buf + req->req.actual, transaction_len); + usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); + req->req.actual += transaction_len; +} + +static void submit_request(struct usba_ep *ep, struct usba_request *req) +{ + DBG(DBG_QUEUE, "%s: submit_request: req %p (length %d)\n", + ep->ep.name, req, req->req.length); + + req->req.actual = 0; + req->submitted = 1; + + if (req->using_dma) { + if (req->req.length == 0) { + usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY); + return; + } + + if (req->req.zero) + usba_ep_writel(ep, CTL_ENB, USBA_SHORT_PACKET); + else + usba_ep_writel(ep, CTL_DIS, USBA_SHORT_PACKET); + + usba_dma_writel(ep, ADDRESS, req->req.dma); + usba_dma_writel(ep, CONTROL, req->ctrl); + } else { + next_fifo_transaction(ep, req); + if (req->last_transaction) { + usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY); + usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE); + } else { + usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); + usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY); + } + } +} + +static void submit_next_request(struct usba_ep *ep) +{ + struct usba_request *req; + + if (list_empty(&ep->queue)) { + usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY | USBA_RX_BK_RDY); + return; + } + + req = list_entry(ep->queue.next, struct usba_request, queue); + if (!req->submitted) + submit_request(ep, req); +} + +static void send_status(struct usba_udc *udc, struct usba_ep *ep) +{ + ep->state = STATUS_STAGE_IN; + usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); + usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE); +} + +static void receive_data(struct usba_ep *ep) +{ + struct usba_udc *udc = ep->udc; + struct usba_request *req; + unsigned long status; + unsigned int bytecount, nr_busy; + int is_complete = 0; + + status = usba_ep_readl(ep, STA); + nr_busy = USBA_BFEXT(BUSY_BANKS, status); + + DBG(DBG_QUEUE, "receive data: nr_busy=%u\n", nr_busy); + + while (nr_busy > 0) { + if (list_empty(&ep->queue)) { + usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); + break; + } + req = list_entry(ep->queue.next, + struct usba_request, queue); + + bytecount = USBA_BFEXT(BYTE_COUNT, status); + + if (status & (1 << 31)) + is_complete = 1; + if (req->req.actual + bytecount >= req->req.length) { + is_complete = 1; + bytecount = req->req.length - req->req.actual; + } + + copy_from_fifo(req->req.buf + req->req.actual, + ep->fifo, bytecount); + req->req.actual += bytecount; + + usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY); + + if (is_complete) { + DBG(DBG_QUEUE, "%s: request done\n", ep->ep.name); + req->req.status = 0; + list_del_init(&req->queue); + usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); + spin_unlock(&udc->lock); + req->req.complete(&ep->ep, &req->req); + spin_lock(&udc->lock); + } + + status = usba_ep_readl(ep, STA); + nr_busy = USBA_BFEXT(BUSY_BANKS, status); + + if (is_complete && ep_is_control(ep)) { + send_status(udc, ep); + break; + } + } +} + +static void +request_complete(struct usba_ep *ep, struct usba_request *req, int status) +{ + struct usba_udc *udc = ep->udc; + + WARN_ON(!list_empty(&req->queue)); + + if (req->req.status == -EINPROGRESS) + req->req.status = status; + + if (req->mapped) { + dma_unmap_single( + &udc->pdev->dev, req->req.dma, req->req.length, + ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + req->req.dma = DMA_ADDR_INVALID; + req->mapped = 0; + } + + DBG(DBG_GADGET | DBG_REQ, + "%s: req %p complete: status %d, actual %u\n", + ep->ep.name, req, req->req.status, req->req.actual); + + spin_unlock(&udc->lock); + req->req.complete(&ep->ep, &req->req); + spin_lock(&udc->lock); +} + +static void +request_complete_list(struct usba_ep *ep, struct list_head *list, int status) +{ + struct usba_request *req, *tmp_req; + + list_for_each_entry_safe(req, tmp_req, list, queue) { + list_del_init(&req->queue); + request_complete(ep, req, status); + } +} + +static int +usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) +{ + struct usba_ep *ep = to_usba_ep(_ep); + struct usba_udc *udc = ep->udc; + unsigned long flags, ept_cfg, maxpacket; + unsigned int nr_trans; + + DBG(DBG_GADGET, "%s: ep_enable: desc=%p\n", ep->ep.name, desc); + + maxpacket = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff; + + if (((desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) != ep->index) + || ep->index == 0 + || desc->bDescriptorType != USB_DT_ENDPOINT + || maxpacket == 0 + || maxpacket > ep->fifo_size) { + DBG(DBG_ERR, "ep_enable: Invalid argument"); + return -EINVAL; + } + + ep->is_isoc = 0; + ep->is_in = 0; + + if (maxpacket <= 8) + ept_cfg = USBA_BF(EPT_SIZE, USBA_EPT_SIZE_8); + else + /* LSB is bit 1, not 0 */ + ept_cfg = USBA_BF(EPT_SIZE, fls(maxpacket - 1) - 3); + + DBG(DBG_HW, "%s: EPT_SIZE = %lu (maxpacket = %lu)\n", + ep->ep.name, ept_cfg, maxpacket); + + if ((desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { + ep->is_in = 1; + ept_cfg |= USBA_EPT_DIR_IN; + } + + switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_CONTROL: + ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL); + ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE); + break; + case USB_ENDPOINT_XFER_ISOC: + if (!ep->can_isoc) { + DBG(DBG_ERR, "ep_enable: %s is not isoc capable\n", + ep->ep.name); + return -EINVAL; + } + + /* + * Bits 11:12 specify number of _additional_ + * transactions per microframe. + */ + nr_trans = ((le16_to_cpu(desc->wMaxPacketSize) >> 11) & 3) + 1; + if (nr_trans > 3) + return -EINVAL; + + ep->is_isoc = 1; + ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_ISO); + + /* + * Do triple-buffering on high-bandwidth iso endpoints. + */ + if (nr_trans > 1 && ep->nr_banks == 3) + ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_TRIPLE); + else + ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE); + ept_cfg |= USBA_BF(NB_TRANS, nr_trans); + break; + case USB_ENDPOINT_XFER_BULK: + ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK); + ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE); + break; + case USB_ENDPOINT_XFER_INT: + ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_INT); + ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE); + break; + } + + spin_lock_irqsave(&ep->udc->lock, flags); + + if (ep->desc) { + spin_unlock_irqrestore(&ep->udc->lock, flags); + DBG(DBG_ERR, "ep%d already enabled\n", ep->index); + return -EBUSY; + } + + ep->desc = desc; + ep->ep.maxpacket = maxpacket; + + usba_ep_writel(ep, CFG, ept_cfg); + usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE); + + if (ep->can_dma) { + u32 ctrl; + + usba_writel(udc, INT_ENB, + (usba_readl(udc, INT_ENB) + | USBA_BF(EPT_INT, 1 << ep->index) + | USBA_BF(DMA_INT, 1 << ep->index))); + ctrl = USBA_AUTO_VALID | USBA_INTDIS_DMA; + usba_ep_writel(ep, CTL_ENB, ctrl); + } else { + usba_writel(udc, INT_ENB, + (usba_readl(udc, INT_ENB) + | USBA_BF(EPT_INT, 1 << ep->index))); + } + + spin_unlock_irqrestore(&udc->lock, flags); + + DBG(DBG_HW, "EPT_CFG%d after init: %#08lx\n", ep->index, + (unsigned long)usba_ep_readl(ep, CFG)); + DBG(DBG_HW, "INT_ENB after init: %#08lx\n", + (unsigned long)usba_readl(udc, INT_ENB)); + + return 0; +} + +static int usba_ep_disable(struct usb_ep *_ep) +{ + struct usba_ep *ep = to_usba_ep(_ep); + struct usba_udc *udc = ep->udc; + LIST_HEAD(req_list); + unsigned long flags; + + DBG(DBG_GADGET, "ep_disable: %s\n", ep->ep.name); + + spin_lock_irqsave(&udc->lock, flags); + + if (!ep->desc) { + spin_unlock_irqrestore(&udc->lock, flags); + DBG(DBG_ERR, "ep_disable: %s not enabled\n", ep->ep.name); + return -EINVAL; + } + ep->desc = NULL; + + list_splice_init(&ep->queue, &req_list); + if (ep->can_dma) { + usba_dma_writel(ep, CONTROL, 0); + usba_dma_writel(ep, ADDRESS, 0); + usba_dma_readl(ep, STATUS); + } + usba_ep_writel(ep, CTL_DIS, USBA_EPT_ENABLE); + usba_writel(udc, INT_ENB, + usba_readl(udc, INT_ENB) + & ~USBA_BF(EPT_INT, 1 << ep->index)); + + request_complete_list(ep, &req_list, -ESHUTDOWN); + + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static struct usb_request * +usba_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) +{ + struct usba_request *req; + + DBG(DBG_GADGET, "ep_alloc_request: %p, 0x%x\n", _ep, gfp_flags); + + req = kzalloc(sizeof(*req), gfp_flags); + if (!req) + return NULL; + + INIT_LIST_HEAD(&req->queue); + req->req.dma = DMA_ADDR_INVALID; + + return &req->req; +} + +static void +usba_ep_free_request(struct usb_ep *_ep, struct usb_request *_req) +{ + struct usba_request *req = to_usba_req(_req); + + DBG(DBG_GADGET, "ep_free_request: %p, %p\n", _ep, _req); + + kfree(req); +} + +static int queue_dma(struct usba_udc *udc, struct usba_ep *ep, + struct usba_request *req, gfp_t gfp_flags) +{ + unsigned long flags; + int ret; + + DBG(DBG_DMA, "%s: req l/%u d/%08x %c%c%c\n", + ep->ep.name, req->req.length, req->req.dma, + req->req.zero ? 'Z' : 'z', + req->req.short_not_ok ? 'S' : 's', + req->req.no_interrupt ? 'I' : 'i'); + + if (req->req.length > 0x10000) { + /* Lengths from 0 to 65536 (inclusive) are supported */ + DBG(DBG_ERR, "invalid request length %u\n", req->req.length); + return -EINVAL; + } + + req->using_dma = 1; + + if (req->req.dma == DMA_ADDR_INVALID) { + req->req.dma = dma_map_single( + &udc->pdev->dev, req->req.buf, req->req.length, + ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + req->mapped = 1; + } else { + dma_sync_single_for_device( + &udc->pdev->dev, req->req.dma, req->req.length, + ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + req->mapped = 0; + } + + req->ctrl = USBA_BF(DMA_BUF_LEN, req->req.length) + | USBA_DMA_CH_EN | USBA_DMA_END_BUF_IE + | USBA_DMA_END_TR_EN | USBA_DMA_END_TR_IE; + + if (ep->is_in) + req->ctrl |= USBA_DMA_END_BUF_EN; + + /* + * Add this request to the queue and submit for DMA if + * possible. Check if we're still alive first -- we may have + * received a reset since last time we checked. + */ + ret = -ESHUTDOWN; + spin_lock_irqsave(&udc->lock, flags); + if (ep->desc) { + if (list_empty(&ep->queue)) + submit_request(ep, req); + + list_add_tail(&req->queue, &ep->queue); + ret = 0; + } + spin_unlock_irqrestore(&udc->lock, flags); + + return ret; +} + +static int +usba_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) +{ + struct usba_request *req = to_usba_req(_req); + struct usba_ep *ep = to_usba_ep(_ep); + struct usba_udc *udc = ep->udc; + unsigned long flags; + int ret; + + DBG(DBG_GADGET | DBG_QUEUE | DBG_REQ, "%s: queue req %p, len %u\n", + ep->ep.name, req, _req->length); + + if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN || !ep->desc) + return -ESHUTDOWN; + + req->submitted = 0; + req->using_dma = 0; + req->last_transaction = 0; + + _req->status = -EINPROGRESS; + _req->actual = 0; + + if (ep->can_dma) + return queue_dma(udc, ep, req, gfp_flags); + + /* May have received a reset since last time we checked */ + ret = -ESHUTDOWN; + spin_lock_irqsave(&udc->lock, flags); + if (ep->desc) { + list_add_tail(&req->queue, &ep->queue); + + if (ep->is_in || (ep_is_control(ep) + && (ep->state == DATA_STAGE_IN + || ep->state == STATUS_STAGE_IN))) + usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY); + else + usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY); + ret = 0; + } + spin_unlock_irqrestore(&udc->lock, flags); + + return ret; +} + +static void +usba_update_req(struct usba_ep *ep, struct usba_request *req, u32 status) +{ + req->req.actual = req->req.length - USBA_BFEXT(DMA_BUF_LEN, status); +} + +static int stop_dma(struct usba_ep *ep, u32 *pstatus) +{ + unsigned int timeout; + u32 status; + + /* + * Stop the DMA controller. When writing both CH_EN + * and LINK to 0, the other bits are not affected. + */ + usba_dma_writel(ep, CONTROL, 0); + + /* Wait for the FIFO to empty */ + for (timeout = 40; timeout; --timeout) { + status = usba_dma_readl(ep, STATUS); + if (!(status & USBA_DMA_CH_EN)) + break; + udelay(1); + } + + if (pstatus) + *pstatus = status; + + if (timeout == 0) { + dev_err(&ep->udc->pdev->dev, + "%s: timed out waiting for DMA FIFO to empty\n", + ep->ep.name); + return -ETIMEDOUT; + } + + return 0; +} + +static int usba_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct usba_ep *ep = to_usba_ep(_ep); + struct usba_udc *udc = ep->udc; + struct usba_request *req = to_usba_req(_req); + unsigned long flags; + u32 status; + + DBG(DBG_GADGET | DBG_QUEUE, "ep_dequeue: %s, req %p\n", + ep->ep.name, req); + + spin_lock_irqsave(&udc->lock, flags); + + if (req->using_dma) { + /* + * If this request is currently being transferred, + * stop the DMA controller and reset the FIFO. + */ + if (ep->queue.next == &req->queue) { + status = usba_dma_readl(ep, STATUS); + if (status & USBA_DMA_CH_EN) + stop_dma(ep, &status); + +#ifdef CONFIG_USB_GADGET_DEBUG_FS + ep->last_dma_status = status; +#endif + + usba_writel(udc, EPT_RST, 1 << ep->index); + + usba_update_req(ep, req, status); + } + } + + /* + * Errors should stop the queue from advancing until the + * completion function returns. + */ + list_del_init(&req->queue); + + request_complete(ep, req, -ECONNRESET); + + /* Process the next request if any */ + submit_next_request(ep); + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static int usba_ep_set_halt(struct usb_ep *_ep, int value) +{ + struct usba_ep *ep = to_usba_ep(_ep); + struct usba_udc *udc = ep->udc; + unsigned long flags; + int ret = 0; + + DBG(DBG_GADGET, "endpoint %s: %s HALT\n", ep->ep.name, + value ? "set" : "clear"); + + if (!ep->desc) { + DBG(DBG_ERR, "Attempted to halt uninitialized ep %s\n", + ep->ep.name); + return -ENODEV; + } + if (ep->is_isoc) { + DBG(DBG_ERR, "Attempted to halt isochronous ep %s\n", + ep->ep.name); + return -ENOTTY; + } + + spin_lock_irqsave(&udc->lock, flags); + + /* + * We can't halt IN endpoints while there are still data to be + * transferred + */ + if (!list_empty(&ep->queue) + || ((value && ep->is_in && (usba_ep_readl(ep, STA) + & USBA_BF(BUSY_BANKS, -1L))))) { + ret = -EAGAIN; + } else { + if (value) + usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL); + else + usba_ep_writel(ep, CLR_STA, + USBA_FORCE_STALL | USBA_TOGGLE_CLR); + usba_ep_readl(ep, STA); + } + + spin_unlock_irqrestore(&udc->lock, flags); + + return ret; +} + +static int usba_ep_fifo_status(struct usb_ep *_ep) +{ + struct usba_ep *ep = to_usba_ep(_ep); + + return USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA)); +} + +static void usba_ep_fifo_flush(struct usb_ep *_ep) +{ + struct usba_ep *ep = to_usba_ep(_ep); + struct usba_udc *udc = ep->udc; + + usba_writel(udc, EPT_RST, 1 << ep->index); +} + +static const struct usb_ep_ops usba_ep_ops = { + .enable = usba_ep_enable, + .disable = usba_ep_disable, + .alloc_request = usba_ep_alloc_request, + .free_request = usba_ep_free_request, + .queue = usba_ep_queue, + .dequeue = usba_ep_dequeue, + .set_halt = usba_ep_set_halt, + .fifo_status = usba_ep_fifo_status, + .fifo_flush = usba_ep_fifo_flush, +}; + +static int usba_udc_get_frame(struct usb_gadget *gadget) +{ + struct usba_udc *udc = to_usba_udc(gadget); + + return USBA_BFEXT(FRAME_NUMBER, usba_readl(udc, FNUM)); +} + +static int usba_udc_wakeup(struct usb_gadget *gadget) +{ + struct usba_udc *udc = to_usba_udc(gadget); + unsigned long flags; + u32 ctrl; + int ret = -EINVAL; + + spin_lock_irqsave(&udc->lock, flags); + if (udc->devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) { + ctrl = usba_readl(udc, CTRL); + usba_writel(udc, CTRL, ctrl | USBA_REMOTE_WAKE_UP); + ret = 0; + } + spin_unlock_irqrestore(&udc->lock, flags); + + return ret; +} + +static int +usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered) +{ + struct usba_udc *udc = to_usba_udc(gadget); + unsigned long flags; + + spin_lock_irqsave(&udc->lock, flags); + if (is_selfpowered) + udc->devstatus |= 1 << USB_DEVICE_SELF_POWERED; + else + udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED); + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static const struct usb_gadget_ops usba_udc_ops = { + .get_frame = usba_udc_get_frame, + .wakeup = usba_udc_wakeup, + .set_selfpowered = usba_udc_set_selfpowered, +}; + +#define EP(nam, idx, maxpkt, maxbk, dma, isoc) \ +{ \ + .ep = { \ + .ops = &usba_ep_ops, \ + .name = nam, \ + .maxpacket = maxpkt, \ + }, \ + .udc = &the_udc, \ + .queue = LIST_HEAD_INIT(usba_ep[idx].queue), \ + .fifo_size = maxpkt, \ + .nr_banks = maxbk, \ + .index = idx, \ + .can_dma = dma, \ + .can_isoc = isoc, \ +} + +static struct usba_ep usba_ep[] = { + EP("ep0", 0, 64, 1, 0, 0), + EP("ep1in-bulk", 1, 512, 2, 1, 1), + EP("ep2out-bulk", 2, 512, 2, 1, 1), + EP("ep3in-int", 3, 64, 3, 1, 0), + EP("ep4out-int", 4, 64, 3, 1, 0), + EP("ep5in-iso", 5, 1024, 3, 1, 1), + EP("ep6out-iso", 6, 1024, 3, 1, 1), +}; +#undef EP + +static struct usb_endpoint_descriptor usba_ep0_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0, + .bmAttributes = USB_ENDPOINT_XFER_CONTROL, + .wMaxPacketSize = __constant_cpu_to_le16(64), + /* FIXME: I have no idea what to put here */ + .bInterval = 1, +}; + +static void nop_release(struct device *dev) +{ + +} + +static struct usba_udc the_udc = { + .gadget = { + .ops = &usba_udc_ops, + .ep0 = &usba_ep[0].ep, + .ep_list = LIST_HEAD_INIT(the_udc.gadget.ep_list), + .is_dualspeed = 1, + .name = "atmel_usba_udc", + .dev = { + .bus_id = "gadget", + .release = nop_release, + }, + }, + + .lock = SPIN_LOCK_UNLOCKED, +}; + +/* + * Called with interrupts disabled and udc->lock held. + */ +static void reset_all_endpoints(struct usba_udc *udc) +{ + struct usba_ep *ep; + struct usba_request *req, *tmp_req; + + usba_writel(udc, EPT_RST, ~0UL); + + ep = to_usba_ep(udc->gadget.ep0); + list_for_each_entry_safe(req, tmp_req, &ep->queue, queue) { + list_del_init(&req->queue); + request_complete(ep, req, -ECONNRESET); + } + + list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { + if (ep->desc) { + spin_unlock(&udc->lock); + usba_ep_disable(&ep->ep); + spin_lock(&udc->lock); + } + } +} + +static struct usba_ep *get_ep_by_addr(struct usba_udc *udc, u16 wIndex) +{ + struct usba_ep *ep; + + if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0) + return to_usba_ep(udc->gadget.ep0); + + list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) { + u8 bEndpointAddress; + + if (!ep->desc) + continue; + bEndpointAddress = ep->desc->bEndpointAddress; + if ((wIndex ^ bEndpointAddress) & USB_DIR_IN) + continue; + if ((bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) + == (wIndex & USB_ENDPOINT_NUMBER_MASK)) + return ep; + } + + return NULL; +} + +/* Called with interrupts disabled and udc->lock held */ +static inline void set_protocol_stall(struct usba_udc *udc, struct usba_ep *ep) +{ + usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL); + ep->state = WAIT_FOR_SETUP; +} + +static inline int is_stalled(struct usba_udc *udc, struct usba_ep *ep) +{ + if (usba_ep_readl(ep, STA) & USBA_FORCE_STALL) + return 1; + return 0; +} + +static inline void set_address(struct usba_udc *udc, unsigned int addr) +{ + u32 regval; + + DBG(DBG_BUS, "setting address %u...\n", addr); + regval = usba_readl(udc, CTRL); + regval = USBA_BFINS(DEV_ADDR, addr, regval); + usba_writel(udc, CTRL, regval); +} + +static int do_test_mode(struct usba_udc *udc) +{ + static const char test_packet_buffer[] = { + /* JKJKJKJK * 9 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* JJKKJJKK * 8 */ + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + /* JJKKJJKK * 8 */ + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, + /* JJJJJJJKKKKKKK * 8 */ + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + /* JJJJJJJK * 8 */ + 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, + /* {JKKKKKKK * 10}, JK */ + 0xFC, 0x7E, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0x7E + }; + struct usba_ep *ep; + struct device *dev = &udc->pdev->dev; + int test_mode; + + test_mode = udc->test_mode; + + /* Start from a clean slate */ + reset_all_endpoints(udc); + + switch (test_mode) { + case 0x0100: + /* Test_J */ + usba_writel(udc, TST, USBA_TST_J_MODE); + dev_info(dev, "Entering Test_J mode...\n"); + break; + case 0x0200: + /* Test_K */ + usba_writel(udc, TST, USBA_TST_K_MODE); + dev_info(dev, "Entering Test_K mode...\n"); + break; + case 0x0300: + /* + * Test_SE0_NAK: Force high-speed mode and set up ep0 + * for Bulk IN transfers + */ + ep = &usba_ep[0]; + usba_writel(udc, TST, + USBA_BF(SPEED_CFG, USBA_SPEED_CFG_FORCE_HIGH)); + usba_ep_writel(ep, CFG, + USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64) + | USBA_EPT_DIR_IN + | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK) + | USBA_BF(BK_NUMBER, 1)); + if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) { + set_protocol_stall(udc, ep); + dev_err(dev, "Test_SE0_NAK: ep0 not mapped\n"); + } else { + usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE); + dev_info(dev, "Entering Test_SE0_NAK mode...\n"); + } + break; + case 0x0400: + /* Test_Packet */ + ep = &usba_ep[0]; + usba_ep_writel(ep, CFG, + USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64) + | USBA_EPT_DIR_IN + | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK) + | USBA_BF(BK_NUMBER, 1)); + if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) { + set_protocol_stall(udc, ep); + dev_err(dev, "Test_Packet: ep0 not mapped\n"); + } else { + usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE); + usba_writel(udc, TST, USBA_TST_PKT_MODE); + copy_to_fifo(ep->fifo, test_packet_buffer, + sizeof(test_packet_buffer)); + usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); + dev_info(dev, "Entering Test_Packet mode...\n"); + } + break; + default: + dev_err(dev, "Invalid test mode: 0x%04x\n", test_mode); + return -EINVAL; + } + + return 0; +} + +/* Avoid overly long expressions */ +static inline bool feature_is_dev_remote_wakeup(struct usb_ctrlrequest *crq) +{ + if (crq->wValue == __constant_cpu_to_le16(USB_DEVICE_REMOTE_WAKEUP)) + return true; + return false; +} + +static inline bool feature_is_dev_test_mode(struct usb_ctrlrequest *crq) +{ + if (crq->wValue == __constant_cpu_to_le16(USB_DEVICE_TEST_MODE)) + return true; + return false; +} + +static inline bool feature_is_ep_halt(struct usb_ctrlrequest *crq) +{ + if (crq->wValue == __constant_cpu_to_le16(USB_ENDPOINT_HALT)) + return true; + return false; +} + +static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep, + struct usb_ctrlrequest *crq) +{ + int retval = 0;; + + switch (crq->bRequest) { + case USB_REQ_GET_STATUS: { + u16 status; + + if (crq->bRequestType == (USB_DIR_IN | USB_RECIP_DEVICE)) { + status = cpu_to_le16(udc->devstatus); + } else if (crq->bRequestType + == (USB_DIR_IN | USB_RECIP_INTERFACE)) { + status = __constant_cpu_to_le16(0); + } else if (crq->bRequestType + == (USB_DIR_IN | USB_RECIP_ENDPOINT)) { + struct usba_ep *target; + + target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex)); + if (!target) + goto stall; + + status = 0; + if (is_stalled(udc, target)) + status |= __constant_cpu_to_le16(1); + } else + goto delegate; + + /* Write directly to the FIFO. No queueing is done. */ + if (crq->wLength != __constant_cpu_to_le16(sizeof(status))) + goto stall; + ep->state = DATA_STAGE_IN; + __raw_writew(status, ep->fifo); + usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); + break; + } + + case USB_REQ_CLEAR_FEATURE: { + if (crq->bRequestType == USB_RECIP_DEVICE) { + if (feature_is_dev_remote_wakeup(crq)) + udc->devstatus + &= ~(1 << USB_DEVICE_REMOTE_WAKEUP); + else + /* Can't CLEAR_FEATURE TEST_MODE */ + goto stall; + } else if (crq->bRequestType == USB_RECIP_ENDPOINT) { + struct usba_ep *target; + + if (crq->wLength != __constant_cpu_to_le16(0) + || !feature_is_ep_halt(crq)) + goto stall; + target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex)); + if (!target) + goto stall; + + usba_ep_writel(target, CLR_STA, USBA_FORCE_STALL); + if (target->index != 0) + usba_ep_writel(target, CLR_STA, + USBA_TOGGLE_CLR); + } else { + goto delegate; + } + + send_status(udc, ep); + break; + } + + case USB_REQ_SET_FEATURE: { + if (crq->bRequestType == USB_RECIP_DEVICE) { + if (feature_is_dev_test_mode(crq)) { + send_status(udc, ep); + ep->state = STATUS_STAGE_TEST; + udc->test_mode = le16_to_cpu(crq->wIndex); + return 0; + } else if (feature_is_dev_remote_wakeup(crq)) { + udc->devstatus |= 1 << USB_DEVICE_REMOTE_WAKEUP; + } else { + goto stall; + } + } else if (crq->bRequestType == USB_RECIP_ENDPOINT) { + struct usba_ep *target; + + if (crq->wLength != __constant_cpu_to_le16(0) + || !feature_is_ep_halt(crq)) + goto stall; + + target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex)); + if (!target) + goto stall; + + usba_ep_writel(target, SET_STA, USBA_FORCE_STALL); + } else + goto delegate; + + send_status(udc, ep); + break; + } + + case USB_REQ_SET_ADDRESS: + if (crq->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE)) + goto delegate; + + set_address(udc, le16_to_cpu(crq->wValue)); + send_status(udc, ep); + ep->state = STATUS_STAGE_ADDR; + break; + + default: +delegate: + spin_unlock(&udc->lock); + retval = udc->driver->setup(&udc->gadget, crq); + spin_lock(&udc->lock); + } + + return retval; + +stall: + printk(KERN_ERR + "udc: %s: Invalid setup request: %02x.%02x v%04x i%04x l%d, " + "halting endpoint...\n", + ep->ep.name, crq->bRequestType, crq->bRequest, + le16_to_cpu(crq->wValue), le16_to_cpu(crq->wIndex), + le16_to_cpu(crq->wLength)); + set_protocol_stall(udc, ep); + return -1; +} + +static void usba_control_irq(struct usba_udc *udc, struct usba_ep *ep) +{ + struct usba_request *req; + u32 epstatus; + u32 epctrl; + +restart: + epstatus = usba_ep_readl(ep, STA); + epctrl = usba_ep_readl(ep, CTL); + + DBG(DBG_INT, "%s [%d]: s/%08x c/%08x\n", + ep->ep.name, ep->state, epstatus, epctrl); + + req = NULL; + if (!list_empty(&ep->queue)) + req = list_entry(ep->queue.next, + struct usba_request, queue); + + if ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) { + if (req->submitted) + next_fifo_transaction(ep, req); + else + submit_request(ep, req); + + if (req->last_transaction) { + usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY); + usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE); + } + goto restart; + } + if ((epstatus & epctrl) & USBA_TX_COMPLETE) { + usba_ep_writel(ep, CLR_STA, USBA_TX_COMPLETE); + + switch (ep->state) { + case DATA_STAGE_IN: + usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY); + usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); + ep->state = STATUS_STAGE_OUT; + break; + case STATUS_STAGE_ADDR: + /* Activate our new address */ + usba_writel(udc, CTRL, (usba_readl(udc, CTRL) + | USBA_FADDR_EN)); + usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); + ep->state = WAIT_FOR_SETUP; + break; + case STATUS_STAGE_IN: + if (req) { + list_del_init(&req->queue); + request_complete(ep, req, 0); + submit_next_request(ep); + } + usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); + ep->state = WAIT_FOR_SETUP; + break; + case STATUS_STAGE_TEST: + usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); + ep->state = WAIT_FOR_SETUP; + if (do_test_mode(udc)) + set_protocol_stall(udc, ep); + break; + default: + printk(KERN_ERR + "udc: %s: TXCOMP: Invalid endpoint state %d, " + "halting endpoint...\n", + ep->ep.name, ep->state); + set_protocol_stall(udc, ep); + break; + } + + goto restart; + } + if ((epstatus & epctrl) & USBA_RX_BK_RDY) { + switch (ep->state) { + case STATUS_STAGE_OUT: + usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY); + usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); + + if (req) { + list_del_init(&req->queue); + request_complete(ep, req, 0); + } + ep->state = WAIT_FOR_SETUP; + break; + + case DATA_STAGE_OUT: + receive_data(ep); + break; + + default: + usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY); + usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); + printk(KERN_ERR + "udc: %s: RXRDY: Invalid endpoint state %d, " + "halting endpoint...\n", + ep->ep.name, ep->state); + set_protocol_stall(udc, ep); + break; + } + + goto restart; + } + if (epstatus & USBA_RX_SETUP) { + union { + struct usb_ctrlrequest crq; + unsigned long data[2]; + } crq; + unsigned int pkt_len; + int ret; + + if (ep->state != WAIT_FOR_SETUP) { + /* + * Didn't expect a SETUP packet at this + * point. Clean up any pending requests (which + * may be successful). + */ + int status = -EPROTO; + + /* + * RXRDY and TXCOMP are dropped when SETUP + * packets arrive. Just pretend we received + * the status packet. + */ + if (ep->state == STATUS_STAGE_OUT + || ep->state == STATUS_STAGE_IN) { + usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); + status = 0; + } + + if (req) { + list_del_init(&req->queue); + request_complete(ep, req, status); + } + } + + pkt_len = USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA)); + DBG(DBG_HW, "Packet length: %u\n", pkt_len); + if (pkt_len != sizeof(crq)) { + printk(KERN_WARNING "udc: Invalid packet length %u " + "(expected %lu)\n", pkt_len, sizeof(crq)); + set_protocol_stall(udc, ep); + return; + } + + DBG(DBG_FIFO, "Copying ctrl request from 0x%p:\n", ep->fifo); + copy_from_fifo(crq.data, ep->fifo, sizeof(crq)); + + /* Free up one bank in the FIFO so that we can + * generate or receive a reply right away. */ + usba_ep_writel(ep, CLR_STA, USBA_RX_SETUP); + + /* printk(KERN_DEBUG "setup: %d: %02x.%02x\n", + ep->state, crq.crq.bRequestType, + crq.crq.bRequest); */ + + if (crq.crq.bRequestType & USB_DIR_IN) { + /* + * The USB 2.0 spec states that "if wLength is + * zero, there is no data transfer phase." + * However, testusb #14 seems to actually + * expect a data phase even if wLength = 0... + */ + ep->state = DATA_STAGE_IN; + } else { + if (crq.crq.wLength != __constant_cpu_to_le16(0)) + ep->state = DATA_STAGE_OUT; + else + ep->state = STATUS_STAGE_IN; + } + + ret = -1; + if (ep->index == 0) + ret = handle_ep0_setup(udc, ep, &crq.crq); + else { + spin_unlock(&udc->lock); + ret = udc->driver->setup(&udc->gadget, &crq.crq); + spin_lock(&udc->lock); + } + + DBG(DBG_BUS, "req %02x.%02x, length %d, state %d, ret %d\n", + crq.crq.bRequestType, crq.crq.bRequest, + le16_to_cpu(crq.crq.wLength), ep->state, ret); + + if (ret < 0) { + /* Let the host know that we failed */ + set_protocol_stall(udc, ep); + } + } +} + +static void usba_ep_irq(struct usba_udc *udc, struct usba_ep *ep) +{ + struct usba_request *req; + u32 epstatus; + u32 epctrl; + + epstatus = usba_ep_readl(ep, STA); + epctrl = usba_ep_readl(ep, CTL); + + DBG(DBG_INT, "%s: interrupt, status: 0x%08x\n", ep->ep.name, epstatus); + + while ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) { + DBG(DBG_BUS, "%s: TX PK ready\n", ep->ep.name); + + if (list_empty(&ep->queue)) { + dev_warn(&udc->pdev->dev, "ep_irq: queue empty\n"); + usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY); + return; + } + + req = list_entry(ep->queue.next, struct usba_request, queue); + + if (req->using_dma) { + /* Send a zero-length packet */ + usba_ep_writel(ep, SET_STA, + USBA_TX_PK_RDY); + usba_ep_writel(ep, CTL_DIS, + USBA_TX_PK_RDY); + list_del_init(&req->queue); + submit_next_request(ep); + request_complete(ep, req, 0); + } else { + if (req->submitted) + next_fifo_transaction(ep, req); + else + submit_request(ep, req); + + if (req->last_transaction) { + list_del_init(&req->queue); + submit_next_request(ep); + request_complete(ep, req, 0); + } + } + + epstatus = usba_ep_readl(ep, STA); + epctrl = usba_ep_readl(ep, CTL); + } + if ((epstatus & epctrl) & USBA_RX_BK_RDY) { + DBG(DBG_BUS, "%s: RX data ready\n", ep->ep.name); + receive_data(ep); + usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY); + } +} + +static void usba_dma_irq(struct usba_udc *udc, struct usba_ep *ep) +{ + struct usba_request *req; + u32 status, control, pending; + + status = usba_dma_readl(ep, STATUS); + control = usba_dma_readl(ep, CONTROL); +#ifdef CONFIG_USB_GADGET_DEBUG_FS + ep->last_dma_status = status; +#endif + pending = status & control; + DBG(DBG_INT | DBG_DMA, "dma irq, s/%#08x, c/%#08x\n", status, control); + + if (status & USBA_DMA_CH_EN) { + dev_err(&udc->pdev->dev, + "DMA_CH_EN is set after transfer is finished!\n"); + dev_err(&udc->pdev->dev, + "status=%#08x, pending=%#08x, control=%#08x\n", + status, pending, control); + + /* + * try to pretend nothing happened. We might have to + * do something here... + */ + } + + if (list_empty(&ep->queue)) + /* Might happen if a reset comes along at the right moment */ + return; + + if (pending & (USBA_DMA_END_TR_ST | USBA_DMA_END_BUF_ST)) { + req = list_entry(ep->queue.next, struct usba_request, queue); + usba_update_req(ep, req, status); + + list_del_init(&req->queue); + submit_next_request(ep); + request_complete(ep, req, 0); + } +} + +static irqreturn_t usba_udc_irq(int irq, void *devid) +{ + struct usba_udc *udc = devid; + u32 status; + u32 dma_status; + u32 ep_status; + + spin_lock(&udc->lock); + + status = usba_readl(udc, INT_STA); + DBG(DBG_INT, "irq, status=%#08x\n", status); + + if (status & USBA_DET_SUSPEND) { + usba_writel(udc, INT_CLR, USBA_DET_SUSPEND); + DBG(DBG_BUS, "Suspend detected\n"); + if (udc->gadget.speed != USB_SPEED_UNKNOWN + && udc->driver && udc->driver->suspend) { + spin_unlock(&udc->lock); + udc->driver->suspend(&udc->gadget); + spin_lock(&udc->lock); + } + } + + if (status & USBA_WAKE_UP) { + usba_writel(udc, INT_CLR, USBA_WAKE_UP); + DBG(DBG_BUS, "Wake Up CPU detected\n"); + } + + if (status & USBA_END_OF_RESUME) { + usba_writel(udc, INT_CLR, USBA_END_OF_RESUME); + DBG(DBG_BUS, "Resume detected\n"); + if (udc->gadget.speed != USB_SPEED_UNKNOWN + && udc->driver && udc->driver->resume) { + spin_unlock(&udc->lock); + udc->driver->resume(&udc->gadget); + spin_lock(&udc->lock); + } + } + + dma_status = USBA_BFEXT(DMA_INT, status); + if (dma_status) { + int i; + + for (i = 1; i < USBA_NR_ENDPOINTS; i++) + if (dma_status & (1 << i)) + usba_dma_irq(udc, &usba_ep[i]); + } + + ep_status = USBA_BFEXT(EPT_INT, status); + if (ep_status) { + int i; + + for (i = 0; i < USBA_NR_ENDPOINTS; i++) + if (ep_status & (1 << i)) { + if (ep_is_control(&usba_ep[i])) + usba_control_irq(udc, &usba_ep[i]); + else + usba_ep_irq(udc, &usba_ep[i]); + } + } + + if (status & USBA_END_OF_RESET) { + struct usba_ep *ep0; + + usba_writel(udc, INT_CLR, USBA_END_OF_RESET); + reset_all_endpoints(udc); + + if (status & USBA_HIGH_SPEED) { + DBG(DBG_BUS, "High-speed bus reset detected\n"); + udc->gadget.speed = USB_SPEED_HIGH; + } else { + DBG(DBG_BUS, "Full-speed bus reset detected\n"); + udc->gadget.speed = USB_SPEED_FULL; + } + + ep0 = &usba_ep[0]; + ep0->desc = &usba_ep0_desc; + ep0->state = WAIT_FOR_SETUP; + usba_ep_writel(ep0, CFG, + (USBA_BF(EPT_SIZE, EP0_EPT_SIZE) + | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL) + | USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE))); + usba_ep_writel(ep0, CTL_ENB, + USBA_EPT_ENABLE | USBA_RX_SETUP); + usba_writel(udc, INT_ENB, + (usba_readl(udc, INT_ENB) + | USBA_BF(EPT_INT, 1) + | USBA_DET_SUSPEND + | USBA_END_OF_RESUME)); + + if (!(usba_ep_readl(ep0, CFG) & USBA_EPT_MAPPED)) + dev_warn(&udc->pdev->dev, + "WARNING: EP0 configuration is invalid!\n"); + } + + spin_unlock(&udc->lock); + + return IRQ_HANDLED; +} + +static irqreturn_t usba_vbus_irq(int irq, void *devid) +{ + struct usba_udc *udc = devid; + int vbus; + + /* debounce */ + udelay(10); + + spin_lock(&udc->lock); + + /* May happen if Vbus pin toggles during probe() */ + if (!udc->driver) + goto out; + + vbus = gpio_get_value(udc->vbus_pin); + if (vbus != udc->vbus_prev) { + if (vbus) { + usba_writel(udc, CTRL, USBA_EN_USBA); + usba_writel(udc, INT_ENB, USBA_END_OF_RESET); + } else { + udc->gadget.speed = USB_SPEED_UNKNOWN; + reset_all_endpoints(udc); + usba_writel(udc, CTRL, 0); + spin_unlock(&udc->lock); + udc->driver->disconnect(&udc->gadget); + spin_lock(&udc->lock); + } + udc->vbus_prev = vbus; + } + +out: + spin_unlock(&udc->lock); + + return IRQ_HANDLED; +} + +int usb_gadget_register_driver(struct usb_gadget_driver *driver) +{ + struct usba_udc *udc = &the_udc; + unsigned long flags; + int ret; + + if (!udc->pdev) + return -ENODEV; + + spin_lock_irqsave(&udc->lock, flags); + if (udc->driver) { + spin_unlock_irqrestore(&udc->lock, flags); + return -EBUSY; + } + + udc->devstatus = 1 << USB_DEVICE_SELF_POWERED; + udc->driver = driver; + udc->gadget.dev.driver = &driver->driver; + spin_unlock_irqrestore(&udc->lock, flags); + + clk_enable(udc->pclk); + clk_enable(udc->hclk); + + ret = driver->bind(&udc->gadget); + if (ret) { + DBG(DBG_ERR, "Could not bind to driver %s: error %d\n", + driver->driver.name, ret); + goto err_driver_bind; + } + + DBG(DBG_GADGET, "registered driver `%s'\n", driver->driver.name); + + udc->vbus_prev = 0; + if (udc->vbus_pin != -1) + enable_irq(gpio_to_irq(udc->vbus_pin)); + + /* If Vbus is present, enable the controller and wait for reset */ + spin_lock_irqsave(&udc->lock, flags); + if (vbus_is_present(udc) && udc->vbus_prev == 0) { + usba_writel(udc, CTRL, USBA_EN_USBA); + usba_writel(udc, INT_ENB, USBA_END_OF_RESET); + } + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; + +err_driver_bind: + udc->driver = NULL; + udc->gadget.dev.driver = NULL; + return ret; +} +EXPORT_SYMBOL(usb_gadget_register_driver); + +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +{ + struct usba_udc *udc = &the_udc; + unsigned long flags; + + if (!udc->pdev) + return -ENODEV; + if (driver != udc->driver) + return -EINVAL; + + if (udc->vbus_pin != -1) + disable_irq(gpio_to_irq(udc->vbus_pin)); + + spin_lock_irqsave(&udc->lock, flags); + udc->gadget.speed = USB_SPEED_UNKNOWN; + reset_all_endpoints(udc); + spin_unlock_irqrestore(&udc->lock, flags); + + /* This will also disable the DP pullup */ + usba_writel(udc, CTRL, 0); + + driver->unbind(&udc->gadget); + udc->gadget.dev.driver = NULL; + udc->driver = NULL; + + clk_disable(udc->hclk); + clk_disable(udc->pclk); + + DBG(DBG_GADGET, "unregistered driver `%s'\n", driver->driver.name); + + return 0; +} +EXPORT_SYMBOL(usb_gadget_unregister_driver); + +static int __init usba_udc_probe(struct platform_device *pdev) +{ + struct usba_platform_data *pdata = pdev->dev.platform_data; + struct resource *regs, *fifo; + struct clk *pclk, *hclk; + struct usba_udc *udc = &the_udc; + int irq, ret, i; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, CTRL_IOMEM_ID); + fifo = platform_get_resource(pdev, IORESOURCE_MEM, FIFO_IOMEM_ID); + if (!regs || !fifo) + return -ENXIO; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + pclk = clk_get(&pdev->dev, "pclk"); + if (IS_ERR(pclk)) + return PTR_ERR(pclk); + hclk = clk_get(&pdev->dev, "hclk"); + if (IS_ERR(hclk)) { + ret = PTR_ERR(hclk); + goto err_get_hclk; + } + + udc->pdev = pdev; + udc->pclk = pclk; + udc->hclk = hclk; + udc->vbus_pin = -1; + + ret = -ENOMEM; + udc->regs = ioremap(regs->start, regs->end - regs->start + 1); + if (!udc->regs) { + dev_err(&pdev->dev, "Unable to map I/O memory, aborting.\n"); + goto err_map_regs; + } + dev_info(&pdev->dev, "MMIO registers at 0x%08lx mapped at %p\n", + (unsigned long)regs->start, udc->regs); + udc->fifo = ioremap(fifo->start, fifo->end - fifo->start + 1); + if (!udc->fifo) { + dev_err(&pdev->dev, "Unable to map FIFO, aborting.\n"); + goto err_map_fifo; + } + dev_info(&pdev->dev, "FIFO at 0x%08lx mapped at %p\n", + (unsigned long)fifo->start, udc->fifo); + + device_initialize(&udc->gadget.dev); + udc->gadget.dev.parent = &pdev->dev; + udc->gadget.dev.dma_mask = pdev->dev.dma_mask; + + platform_set_drvdata(pdev, udc); + + /* Make sure we start from a clean slate */ + clk_enable(pclk); + usba_writel(udc, CTRL, 0); + clk_disable(pclk); + + INIT_LIST_HEAD(&usba_ep[0].ep.ep_list); + usba_ep[0].ep_regs = udc->regs + USBA_EPT_BASE(0); + usba_ep[0].dma_regs = udc->regs + USBA_DMA_BASE(0); + usba_ep[0].fifo = udc->fifo + USBA_FIFO_BASE(0); + for (i = 1; i < ARRAY_SIZE(usba_ep); i++) { + struct usba_ep *ep = &usba_ep[i]; + + ep->ep_regs = udc->regs + USBA_EPT_BASE(i); + ep->dma_regs = udc->regs + USBA_DMA_BASE(i); + ep->fifo = udc->fifo + USBA_FIFO_BASE(i); + + list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); + } + + ret = request_irq(irq, usba_udc_irq, 0, "atmel_usba_udc", udc); + if (ret) { + dev_err(&pdev->dev, "Cannot request irq %d (error %d)\n", + irq, ret); + goto err_request_irq; + } + udc->irq = irq; + + ret = device_add(&udc->gadget.dev); + if (ret) { + dev_dbg(&pdev->dev, "Could not add gadget: %d\n", ret); + goto err_device_add; + } + + if (pdata && pdata->vbus_pin != GPIO_PIN_NONE) { + if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) { + udc->vbus_pin = pdata->vbus_pin; + + ret = request_irq(gpio_to_irq(udc->vbus_pin), + usba_vbus_irq, 0, + "atmel_usba_udc", udc); + if (ret) { + gpio_free(udc->vbus_pin); + udc->vbus_pin = -1; + dev_warn(&udc->pdev->dev, + "failed to request vbus irq; " + "assuming always on\n"); + } else { + disable_irq(gpio_to_irq(udc->vbus_pin)); + } + } + } + + usba_init_debugfs(udc); + for (i = 1; i < ARRAY_SIZE(usba_ep); i++) + usba_ep_init_debugfs(udc, &usba_ep[i]); + + return 0; + +err_device_add: + free_irq(irq, udc); +err_request_irq: + iounmap(udc->fifo); +err_map_fifo: + iounmap(udc->regs); +err_map_regs: + clk_put(hclk); +err_get_hclk: + clk_put(pclk); + + platform_set_drvdata(pdev, NULL); + + return ret; +} + +static int __exit usba_udc_remove(struct platform_device *pdev) +{ + struct usba_udc *udc; + int i; + + udc = platform_get_drvdata(pdev); + + for (i = 1; i < ARRAY_SIZE(usba_ep); i++) + usba_ep_cleanup_debugfs(&usba_ep[i]); + usba_cleanup_debugfs(udc); + + if (udc->vbus_pin != -1) + gpio_free(udc->vbus_pin); + + free_irq(udc->irq, udc); + iounmap(udc->fifo); + iounmap(udc->regs); + clk_put(udc->hclk); + clk_put(udc->pclk); + + device_unregister(&udc->gadget.dev); + + return 0; +} + +static struct platform_driver udc_driver = { + .remove = __exit_p(usba_udc_remove), + .driver = { + .name = "atmel_usba_udc", + }, +}; + +static int __init udc_init(void) +{ + return platform_driver_probe(&udc_driver, usba_udc_probe); +} +module_init(udc_init); + +static void __exit udc_exit(void) +{ + platform_driver_unregister(&udc_driver); +} +module_exit(udc_exit); + +MODULE_DESCRIPTION("Atmel USBA UDC driver"); +MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h new file mode 100644 index 000000000000..a68304e31a68 --- /dev/null +++ b/drivers/usb/gadget/atmel_usba_udc.h @@ -0,0 +1,352 @@ +/* + * Driver for the Atmel USBA high speed USB device controller + * + * Copyright (C) 2005-2007 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __LINUX_USB_GADGET_USBA_UDC_H__ +#define __LINUX_USB_GADGET_USBA_UDC_H__ + +/* USB register offsets */ +#define USBA_CTRL 0x0000 +#define USBA_FNUM 0x0004 +#define USBA_INT_ENB 0x0010 +#define USBA_INT_STA 0x0014 +#define USBA_INT_CLR 0x0018 +#define USBA_EPT_RST 0x001c +#define USBA_TST 0x00e0 + +/* USB endpoint register offsets */ +#define USBA_EPT_CFG 0x0000 +#define USBA_EPT_CTL_ENB 0x0004 +#define USBA_EPT_CTL_DIS 0x0008 +#define USBA_EPT_CTL 0x000c +#define USBA_EPT_SET_STA 0x0014 +#define USBA_EPT_CLR_STA 0x0018 +#define USBA_EPT_STA 0x001c + +/* USB DMA register offsets */ +#define USBA_DMA_NXT_DSC 0x0000 +#define USBA_DMA_ADDRESS 0x0004 +#define USBA_DMA_CONTROL 0x0008 +#define USBA_DMA_STATUS 0x000c + +/* Bitfields in CTRL */ +#define USBA_DEV_ADDR_OFFSET 0 +#define USBA_DEV_ADDR_SIZE 7 +#define USBA_FADDR_EN (1 << 7) +#define USBA_EN_USBA (1 << 8) +#define USBA_DETACH (1 << 9) +#define USBA_REMOTE_WAKE_UP (1 << 10) + +/* Bitfields in FNUM */ +#define USBA_MICRO_FRAME_NUM_OFFSET 0 +#define USBA_MICRO_FRAME_NUM_SIZE 3 +#define USBA_FRAME_NUMBER_OFFSET 3 +#define USBA_FRAME_NUMBER_SIZE 11 +#define USBA_FRAME_NUM_ERROR (1 << 31) + +/* Bitfields in INT_ENB/INT_STA/INT_CLR */ +#define USBA_HIGH_SPEED (1 << 0) +#define USBA_DET_SUSPEND (1 << 1) +#define USBA_MICRO_SOF (1 << 2) +#define USBA_SOF (1 << 3) +#define USBA_END_OF_RESET (1 << 4) +#define USBA_WAKE_UP (1 << 5) +#define USBA_END_OF_RESUME (1 << 6) +#define USBA_UPSTREAM_RESUME (1 << 7) +#define USBA_EPT_INT_OFFSET 8 +#define USBA_EPT_INT_SIZE 16 +#define USBA_DMA_INT_OFFSET 24 +#define USBA_DMA_INT_SIZE 8 + +/* Bitfields in EPT_RST */ +#define USBA_RST_OFFSET 0 +#define USBA_RST_SIZE 16 + +/* Bitfields in USBA_TST */ +#define USBA_SPEED_CFG_OFFSET 0 +#define USBA_SPEED_CFG_SIZE 2 +#define USBA_TST_J_MODE (1 << 2) +#define USBA_TST_K_MODE (1 << 3) +#define USBA_TST_PKT_MODE (1 << 4) +#define USBA_OPMODE2 (1 << 5) + +/* Bitfields in EPT_CFG */ +#define USBA_EPT_SIZE_OFFSET 0 +#define USBA_EPT_SIZE_SIZE 3 +#define USBA_EPT_DIR_IN (1 << 3) +#define USBA_EPT_TYPE_OFFSET 4 +#define USBA_EPT_TYPE_SIZE 2 +#define USBA_BK_NUMBER_OFFSET 6 +#define USBA_BK_NUMBER_SIZE 2 +#define USBA_NB_TRANS_OFFSET 8 +#define USBA_NB_TRANS_SIZE 2 +#define USBA_EPT_MAPPED (1 << 31) + +/* Bitfields in EPT_CTL/EPT_CTL_ENB/EPT_CTL_DIS */ +#define USBA_EPT_ENABLE (1 << 0) +#define USBA_AUTO_VALID (1 << 1) +#define USBA_INTDIS_DMA (1 << 3) +#define USBA_NYET_DIS (1 << 4) +#define USBA_DATAX_RX (1 << 6) +#define USBA_MDATA_RX (1 << 7) +/* Bits 8-15 and 31 enable interrupts for respective bits in EPT_STA */ +#define USBA_BUSY_BANK_IE (1 << 18) + +/* Bitfields in EPT_SET_STA/EPT_CLR_STA/EPT_STA */ +#define USBA_FORCE_STALL (1 << 5) +#define USBA_TOGGLE_CLR (1 << 6) +#define USBA_TOGGLE_SEQ_OFFSET 6 +#define USBA_TOGGLE_SEQ_SIZE 2 +#define USBA_ERR_OVFLW (1 << 8) +#define USBA_RX_BK_RDY (1 << 9) +#define USBA_KILL_BANK (1 << 9) +#define USBA_TX_COMPLETE (1 << 10) +#define USBA_TX_PK_RDY (1 << 11) +#define USBA_ISO_ERR_TRANS (1 << 11) +#define USBA_RX_SETUP (1 << 12) +#define USBA_ISO_ERR_FLOW (1 << 12) +#define USBA_STALL_SENT (1 << 13) +#define USBA_ISO_ERR_CRC (1 << 13) +#define USBA_ISO_ERR_NBTRANS (1 << 13) +#define USBA_NAK_IN (1 << 14) +#define USBA_ISO_ERR_FLUSH (1 << 14) +#define USBA_NAK_OUT (1 << 15) +#define USBA_CURRENT_BANK_OFFSET 16 +#define USBA_CURRENT_BANK_SIZE 2 +#define USBA_BUSY_BANKS_OFFSET 18 +#define USBA_BUSY_BANKS_SIZE 2 +#define USBA_BYTE_COUNT_OFFSET 20 +#define USBA_BYTE_COUNT_SIZE 11 +#define USBA_SHORT_PACKET (1 << 31) + +/* Bitfields in DMA_CONTROL */ +#define USBA_DMA_CH_EN (1 << 0) +#define USBA_DMA_LINK (1 << 1) +#define USBA_DMA_END_TR_EN (1 << 2) +#define USBA_DMA_END_BUF_EN (1 << 3) +#define USBA_DMA_END_TR_IE (1 << 4) +#define USBA_DMA_END_BUF_IE (1 << 5) +#define USBA_DMA_DESC_LOAD_IE (1 << 6) +#define USBA_DMA_BURST_LOCK (1 << 7) +#define USBA_DMA_BUF_LEN_OFFSET 16 +#define USBA_DMA_BUF_LEN_SIZE 16 + +/* Bitfields in DMA_STATUS */ +#define USBA_DMA_CH_ACTIVE (1 << 1) +#define USBA_DMA_END_TR_ST (1 << 4) +#define USBA_DMA_END_BUF_ST (1 << 5) +#define USBA_DMA_DESC_LOAD_ST (1 << 6) + +/* Constants for SPEED_CFG */ +#define USBA_SPEED_CFG_NORMAL 0 +#define USBA_SPEED_CFG_FORCE_HIGH 2 +#define USBA_SPEED_CFG_FORCE_FULL 3 + +/* Constants for EPT_SIZE */ +#define USBA_EPT_SIZE_8 0 +#define USBA_EPT_SIZE_16 1 +#define USBA_EPT_SIZE_32 2 +#define USBA_EPT_SIZE_64 3 +#define USBA_EPT_SIZE_128 4 +#define USBA_EPT_SIZE_256 5 +#define USBA_EPT_SIZE_512 6 +#define USBA_EPT_SIZE_1024 7 + +/* Constants for EPT_TYPE */ +#define USBA_EPT_TYPE_CONTROL 0 +#define USBA_EPT_TYPE_ISO 1 +#define USBA_EPT_TYPE_BULK 2 +#define USBA_EPT_TYPE_INT 3 + +/* Constants for BK_NUMBER */ +#define USBA_BK_NUMBER_ZERO 0 +#define USBA_BK_NUMBER_ONE 1 +#define USBA_BK_NUMBER_DOUBLE 2 +#define USBA_BK_NUMBER_TRIPLE 3 + +/* Bit manipulation macros */ +#define USBA_BF(name, value) \ + (((value) & ((1 << USBA_##name##_SIZE) - 1)) \ + << USBA_##name##_OFFSET) +#define USBA_BFEXT(name, value) \ + (((value) >> USBA_##name##_OFFSET) \ + & ((1 << USBA_##name##_SIZE) - 1)) +#define USBA_BFINS(name, value, old) \ + (((old) & ~(((1 << USBA_##name##_SIZE) - 1) \ + << USBA_##name##_OFFSET)) \ + | USBA_BF(name, value)) + +/* Register access macros */ +#define usba_readl(udc, reg) \ + __raw_readl((udc)->regs + USBA_##reg) +#define usba_writel(udc, reg, value) \ + __raw_writel((value), (udc)->regs + USBA_##reg) +#define usba_ep_readl(ep, reg) \ + __raw_readl((ep)->ep_regs + USBA_EPT_##reg) +#define usba_ep_writel(ep, reg, value) \ + __raw_writel((value), (ep)->ep_regs + USBA_EPT_##reg) +#define usba_dma_readl(ep, reg) \ + __raw_readl((ep)->dma_regs + USBA_DMA_##reg) +#define usba_dma_writel(ep, reg, value) \ + __raw_writel((value), (ep)->dma_regs + USBA_DMA_##reg) + +/* Calculate base address for a given endpoint or DMA controller */ +#define USBA_EPT_BASE(x) (0x100 + (x) * 0x20) +#define USBA_DMA_BASE(x) (0x300 + (x) * 0x10) +#define USBA_FIFO_BASE(x) ((x) << 16) + +/* Synth parameters */ +#define USBA_NR_ENDPOINTS 7 + +#define EP0_FIFO_SIZE 64 +#define EP0_EPT_SIZE USBA_EPT_SIZE_64 +#define EP0_NR_BANKS 1 + +/* + * REVISIT: Try to eliminate this value. Can we rely on req->mapped to + * provide this information? + */ +#define DMA_ADDR_INVALID (~(dma_addr_t)0) + +#define FIFO_IOMEM_ID 0 +#define CTRL_IOMEM_ID 1 + +#ifdef DEBUG +#define DBG_ERR 0x0001 /* report all error returns */ +#define DBG_HW 0x0002 /* debug hardware initialization */ +#define DBG_GADGET 0x0004 /* calls to/from gadget driver */ +#define DBG_INT 0x0008 /* interrupts */ +#define DBG_BUS 0x0010 /* report changes in bus state */ +#define DBG_QUEUE 0x0020 /* debug request queue processing */ +#define DBG_FIFO 0x0040 /* debug FIFO contents */ +#define DBG_DMA 0x0080 /* debug DMA handling */ +#define DBG_REQ 0x0100 /* print out queued request length */ +#define DBG_ALL 0xffff +#define DBG_NONE 0x0000 + +#define DEBUG_LEVEL (DBG_ERR) +#define DBG(level, fmt, ...) \ + do { \ + if ((level) & DEBUG_LEVEL) \ + printk(KERN_DEBUG "udc: " fmt, ## __VA_ARGS__); \ + } while (0) +#else +#define DBG(level, fmt...) +#endif + +enum usba_ctrl_state { + WAIT_FOR_SETUP, + DATA_STAGE_IN, + DATA_STAGE_OUT, + STATUS_STAGE_IN, + STATUS_STAGE_OUT, + STATUS_STAGE_ADDR, + STATUS_STAGE_TEST, +}; +/* + EP_STATE_IDLE, + EP_STATE_SETUP, + EP_STATE_IN_DATA, + EP_STATE_OUT_DATA, + EP_STATE_SET_ADDR_STATUS, + EP_STATE_RX_STATUS, + EP_STATE_TX_STATUS, + EP_STATE_HALT, +*/ + +struct usba_dma_desc { + dma_addr_t next; + dma_addr_t addr; + u32 ctrl; +}; + +struct usba_ep { + int state; + void __iomem *ep_regs; + void __iomem *dma_regs; + void __iomem *fifo; + struct usb_ep ep; + struct usba_udc *udc; + + struct list_head queue; + const struct usb_endpoint_descriptor *desc; + + u16 fifo_size; + u8 nr_banks; + u8 index; + unsigned int can_dma:1; + unsigned int can_isoc:1; + unsigned int is_isoc:1; + unsigned int is_in:1; + +#ifdef CONFIG_USB_GADGET_DEBUG_FS + u32 last_dma_status; + struct dentry *debugfs_dir; + struct dentry *debugfs_queue; + struct dentry *debugfs_dma_status; + struct dentry *debugfs_state; +#endif +}; + +struct usba_request { + struct usb_request req; + struct list_head queue; + + u32 ctrl; + + unsigned int submitted:1; + unsigned int last_transaction:1; + unsigned int using_dma:1; + unsigned int mapped:1; +}; + +struct usba_udc { + /* Protect hw registers from concurrent modifications */ + spinlock_t lock; + + void __iomem *regs; + void __iomem *fifo; + + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + struct platform_device *pdev; + int irq; + int vbus_pin; + struct clk *pclk; + struct clk *hclk; + + u16 devstatus; + + u16 test_mode; + int vbus_prev; + +#ifdef CONFIG_USB_GADGET_DEBUG_FS + struct dentry *debugfs_root; + struct dentry *debugfs_regs; +#endif +}; + +static inline struct usba_ep *to_usba_ep(struct usb_ep *ep) +{ + return container_of(ep, struct usba_ep, ep); +} + +static inline struct usba_request *to_usba_req(struct usb_request *req) +{ + return container_of(req, struct usba_request, req); +} + +static inline struct usba_udc *to_usba_udc(struct usb_gadget *gadget) +{ + return container_of(gadget, struct usba_udc, gadget); +} + +#define ep_is_control(ep) ((ep)->index == 0) +#define ep_is_idle(ep) ((ep)->state == EP_STATE_IDLE) + +#endif /* __LINUX_USB_GADGET_USBA_UDC_H */ diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c index c6760aee1e5c..a4e54b2743f0 100644 --- a/drivers/usb/gadget/config.c +++ b/drivers/usb/gadget/config.c @@ -25,7 +25,7 @@ #include <linux/device.h> #include <linux/usb/ch9.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> /** diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index d008d1360a7a..9db2482bdfa2 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -46,7 +46,7 @@ #include <linux/interrupt.h> #include <linux/platform_device.h> #include <linux/usb.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> #include <asm/byteorder.h> #include <asm/io.h> @@ -962,13 +962,13 @@ static struct platform_driver dummy_udc_driver = { static int dummy_urb_enqueue ( struct usb_hcd *hcd, - struct usb_host_endpoint *ep, struct urb *urb, gfp_t mem_flags ) { struct dummy *dum; struct urbp *urbp; unsigned long flags; + int rc; if (!urb->transfer_buffer && urb->transfer_buffer_length) return -EINVAL; @@ -980,6 +980,11 @@ static int dummy_urb_enqueue ( dum = hcd_to_dummy (hcd); spin_lock_irqsave (&dum->lock, flags); + rc = usb_hcd_link_urb_to_ep(hcd, urb); + if (rc) { + kfree(urbp); + goto done; + } if (!dum->udev) { dum->udev = urb->dev; @@ -996,36 +1001,35 @@ static int dummy_urb_enqueue ( if (!timer_pending (&dum->timer)) mod_timer (&dum->timer, jiffies + 1); - spin_unlock_irqrestore (&dum->lock, flags); - return 0; + done: + spin_unlock_irqrestore(&dum->lock, flags); + return rc; } -static int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) +static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct dummy *dum; unsigned long flags; + int rc; /* giveback happens automatically in timer callback, * so make sure the callback happens */ dum = hcd_to_dummy (hcd); spin_lock_irqsave (&dum->lock, flags); - if (dum->rh_state != DUMMY_RH_RUNNING && !list_empty(&dum->urbp_list)) + + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (!rc && dum->rh_state != DUMMY_RH_RUNNING && + !list_empty(&dum->urbp_list)) mod_timer (&dum->timer, jiffies); - spin_unlock_irqrestore (&dum->lock, flags); - return 0; -} -static void maybe_set_status (struct urb *urb, int status) -{ - spin_lock (&urb->lock); - if (urb->status == -EINPROGRESS) - urb->status = status; - spin_unlock (&urb->lock); + spin_unlock_irqrestore (&dum->lock, flags); + return rc; } /* transfer up to a frame's worth; caller must own lock */ static int -transfer (struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit) +transfer(struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit, + int *status) { struct dummy_request *req; @@ -1088,24 +1092,20 @@ top: * * partially filling a buffer optionally blocks queue advances * (so completion handlers can clean up the queue) but we don't - * need to emulate such data-in-flight. so we only show part - * of the URB_SHORT_NOT_OK effect: completion status. + * need to emulate such data-in-flight. */ if (is_short) { if (host_len == dev_len) { req->req.status = 0; - maybe_set_status (urb, 0); + *status = 0; } else if (to_host) { req->req.status = 0; if (dev_len > host_len) - maybe_set_status (urb, -EOVERFLOW); + *status = -EOVERFLOW; else - maybe_set_status (urb, - (urb->transfer_flags - & URB_SHORT_NOT_OK) - ? -EREMOTEIO : 0); + *status = 0; } else if (!to_host) { - maybe_set_status (urb, 0); + *status = 0; if (host_len > dev_len) req->req.status = -EOVERFLOW; else @@ -1119,9 +1119,8 @@ top: req->req.status = 0; if (urb->transfer_buffer_length == urb->actual_length && !(urb->transfer_flags - & URB_ZERO_PACKET)) { - maybe_set_status (urb, 0); - } + & URB_ZERO_PACKET)) + *status = 0; } /* device side completion --> continuable */ @@ -1137,7 +1136,7 @@ top: } /* host side completion --> terminate */ - if (urb->status != -EINPROGRESS) + if (*status != -EINPROGRESS) break; /* rescan to continue with any other queued i/o */ @@ -1248,12 +1247,12 @@ restart: u8 address; struct dummy_ep *ep = NULL; int type; + int status = -EINPROGRESS; urb = urbp->urb; - if (urb->status != -EINPROGRESS) { - /* likely it was just unlinked */ + if (urb->unlinked) goto return_urb; - } else if (dum->rh_state != DUMMY_RH_RUNNING) + else if (dum->rh_state != DUMMY_RH_RUNNING) continue; type = usb_pipetype (urb->pipe); @@ -1274,7 +1273,7 @@ restart: dev_dbg (dummy_dev(dum), "no ep configured for urb %p\n", urb); - maybe_set_status (urb, -EPROTO); + status = -EPROTO; goto return_urb; } @@ -1289,7 +1288,7 @@ restart: /* NOTE: must not be iso! */ dev_dbg (dummy_dev(dum), "ep %s halted, urb %p\n", ep->ep.name, urb); - maybe_set_status (urb, -EPIPE); + status = -EPIPE; goto return_urb; } /* FIXME make sure both ends agree on maxpacket */ @@ -1307,7 +1306,7 @@ restart: w_value = le16_to_cpu(setup.wValue); if (le16_to_cpu(setup.wLength) != urb->transfer_buffer_length) { - maybe_set_status (urb, -EOVERFLOW); + status = -EOVERFLOW; goto return_urb; } @@ -1337,7 +1336,7 @@ restart: if (setup.bRequestType != Dev_Request) break; dum->address = w_value; - maybe_set_status (urb, 0); + status = 0; dev_dbg (udc_dev(dum), "set_address = %d\n", w_value); value = 0; @@ -1364,7 +1363,7 @@ restart: if (value == 0) { dum->devstatus |= (1 << w_value); - maybe_set_status (urb, 0); + status = 0; } } else if (setup.bRequestType == Ep_Request) { @@ -1376,7 +1375,7 @@ restart: } ep2->halted = 1; value = 0; - maybe_set_status (urb, 0); + status = 0; } break; case USB_REQ_CLEAR_FEATURE: @@ -1386,7 +1385,7 @@ restart: dum->devstatus &= ~(1 << USB_DEVICE_REMOTE_WAKEUP); value = 0; - maybe_set_status (urb, 0); + status = 0; break; default: value = -EOPNOTSUPP; @@ -1401,7 +1400,7 @@ restart: } ep2->halted = 0; value = 0; - maybe_set_status (urb, 0); + status = 0; } break; case USB_REQ_GET_STATUS: @@ -1438,7 +1437,7 @@ restart: urb->actual_length = min (2, urb->transfer_buffer_length); value = 0; - maybe_set_status (urb, 0); + status = 0; } break; } @@ -1465,7 +1464,7 @@ restart: dev_dbg (udc_dev(dum), "setup --> %d\n", value); - maybe_set_status (urb, -EPIPE); + status = -EPIPE; urb->actual_length = 0; } @@ -1482,7 +1481,7 @@ restart: * report random errors, to debug drivers. */ limit = max (limit, periodic_bytes (dum, ep)); - maybe_set_status (urb, -ENOSYS); + status = -ENOSYS; break; case PIPE_INTERRUPT: @@ -1496,23 +1495,23 @@ restart: default: treat_control_like_bulk: ep->last_io = jiffies; - total = transfer (dum, urb, ep, limit); + total = transfer(dum, urb, ep, limit, &status); break; } /* incomplete transfer? */ - if (urb->status == -EINPROGRESS) + if (status == -EINPROGRESS) continue; return_urb: - urb->hcpriv = NULL; list_del (&urbp->urbp_list); kfree (urbp); if (ep) ep->already_seen = ep->setup_stage = 0; + usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb); spin_unlock (&dum->lock); - usb_hcd_giveback_urb (dummy_to_hcd(dum), urb); + usb_hcd_giveback_urb(dummy_to_hcd(dum), urb, status); spin_lock (&dum->lock); goto restart; diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 3aa46cfa66ba..f9d07108bc30 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -28,7 +28,7 @@ #include <linux/string.h> #include <linux/usb/ch9.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> #include "gadget_chips.h" diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index f70055473a00..9e732bff9df0 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -19,40 +19,18 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* #define VERBOSE_DEBUG */ -// #define DEBUG 1 -// #define VERBOSE - -#include <linux/module.h> #include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/ioport.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/timer.h> -#include <linux/list.h> -#include <linux/interrupt.h> #include <linux/utsname.h> #include <linux/device.h> -#include <linux/moduleparam.h> #include <linux/ctype.h> - -#include <asm/byteorder.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/system.h> -#include <asm/uaccess.h> -#include <asm/unaligned.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> #include <linux/usb/ch9.h> #include <linux/usb/cdc.h> -#include <linux/usb_gadget.h> - -#include <linux/random.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/ethtool.h> +#include <linux/usb/gadget.h> #include "gadget_chips.h" @@ -356,15 +334,15 @@ module_param (qmult, uint, S_IRUGO|S_IWUSR); #define qlen(gadget) \ (DEFAULT_QLEN*((gadget->speed == USB_SPEED_HIGH) ? qmult : 1)) -/* also defer IRQs on highspeed TX */ -#define TX_DELAY qmult - static inline int BITRATE(struct usb_gadget *g) { return (g->speed == USB_SPEED_HIGH) ? HS_BPS : FS_BPS; } #else /* full speed (low speed doesn't do bulk) */ + +#define qmult 1 + #define DEVSPEED USB_SPEED_FULL #define qlen(gadget) DEFAULT_QLEN @@ -390,7 +368,7 @@ static inline int BITRATE(struct usb_gadget *g) do { } while (0) #endif /* DEBUG */ -#ifdef VERBOSE +#ifdef VERBOSE_DEBUG #define VDEBUG DEBUG #else #define VDEBUG(dev,fmt,args...) \ @@ -830,8 +808,6 @@ static const struct usb_descriptor_header *fs_rndis_function [] = { }; #endif -#ifdef CONFIG_USB_GADGET_DUALSPEED - /* * usb 2.0 devices need to expose both high speed and full speed * descriptors, unless they only run at full speed. @@ -934,18 +910,15 @@ static const struct usb_descriptor_header *hs_rndis_function [] = { /* maxpacket and other transfer characteristics vary by speed. */ -#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs)) - -#else - -/* if there's no high speed support, maxpacket doesn't change. */ -#define ep_desc(g,hs,fs) (((void)(g)), (fs)) - -static inline void __init hs_subset_descriptors(void) +static inline struct usb_endpoint_descriptor * +ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs, + struct usb_endpoint_descriptor *fs) { + if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + return hs; + return fs; } -#endif /* !CONFIG_USB_GADGET_DUALSPEED */ /*-------------------------------------------------------------------------*/ @@ -989,22 +962,19 @@ static struct usb_gadget_strings stringtab = { * complications: class descriptors, and an altsetting. */ static int -config_buf (enum usb_device_speed speed, - u8 *buf, u8 type, - unsigned index, int is_otg) +config_buf(struct usb_gadget *g, u8 *buf, u8 type, unsigned index, int is_otg) { int len; const struct usb_config_descriptor *config; const struct usb_descriptor_header **function; -#ifdef CONFIG_USB_GADGET_DUALSPEED - int hs = (speed == USB_SPEED_HIGH); + int hs = 0; - if (type == USB_DT_OTHER_SPEED_CONFIG) - hs = !hs; + if (gadget_is_dualspeed(g)) { + hs = (g->speed == USB_SPEED_HIGH); + if (type == USB_DT_OTHER_SPEED_CONFIG) + hs = !hs; + } #define which_fn(t) (hs ? hs_ ## t ## _function : fs_ ## t ## _function) -#else -#define which_fn(t) (fs_ ## t ## _function) -#endif if (index >= device_desc.bNumConfigurations) return -EINVAL; @@ -1217,7 +1187,7 @@ eth_set_config (struct eth_dev *dev, unsigned number, gfp_t gfp_flags) if (number) eth_reset_config (dev); usb_gadget_vbus_draw(dev->gadget, - dev->gadget->is_otg ? 8 : 100); + gadget_is_otg(dev->gadget) ? 8 : 100); } else { char *speed; unsigned power; @@ -1399,24 +1369,22 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) value = min (wLength, (u16) sizeof device_desc); memcpy (req->buf, &device_desc, value); break; -#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; value = min (wLength, (u16) sizeof dev_qualifier); memcpy (req->buf, &dev_qualifier, value); break; case USB_DT_OTHER_SPEED_CONFIG: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; // FALLTHROUGH -#endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: - value = config_buf (gadget->speed, req->buf, + value = config_buf(gadget, req->buf, wValue >> 8, wValue & 0xff, - gadget->is_otg); + gadget_is_otg(gadget)); if (value >= 0) value = min (wLength, (u16) value); break; @@ -1585,12 +1553,12 @@ done_set_intf: && rndis_control_intf.bInterfaceNumber == wIndex) { u8 *buf; + u32 n; /* return the result */ - buf = rndis_get_next_response (dev->rndis_config, - &value); + buf = rndis_get_next_response(dev->rndis_config, &n); if (buf) { - memcpy (req->buf, buf, value); + memcpy(req->buf, buf, n); req->complete = rndis_response_complete; rndis_free_response(dev->rndis_config, buf); } @@ -1989,8 +1957,20 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) } spin_lock_irqsave(&dev->req_lock, flags); + /* + * this freelist can be empty if an interrupt triggered disconnect() + * and reconfigured the gadget (shutting down this queue) after the + * network stack decided to xmit but before we got the spinlock. + */ + if (list_empty(&dev->tx_reqs)) { + spin_unlock_irqrestore(&dev->req_lock, flags); + return 1; + } + req = container_of (dev->tx_reqs.next, struct usb_request, list); list_del (&req->list); + + /* temporarily stop TX queue when the freelist empties */ if (list_empty (&dev->tx_reqs)) netif_stop_queue (net); spin_unlock_irqrestore(&dev->req_lock, flags); @@ -2026,12 +2006,11 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) req->length = length; -#ifdef CONFIG_USB_GADGET_DUALSPEED /* throttle highspeed IRQ rate back slightly */ - req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH) - ? ((atomic_read (&dev->tx_qlen) % TX_DELAY) != 0) - : 0; -#endif + if (gadget_is_dualspeed(dev->gadget)) + req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH) + ? ((atomic_read(&dev->tx_qlen) % qmult) != 0) + : 0; retval = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC); switch (retval) { @@ -2188,8 +2167,7 @@ static int eth_stop (struct net_device *net) } if (rndis_active(dev)) { - rndis_set_param_medium (dev->rndis_config, - NDIS_MEDIUM_802_3, 0); + rndis_set_param_medium(dev->rndis_config, NDIS_MEDIUM_802_3, 0); (void) rndis_signal_disconnect (dev->rndis_config); } @@ -2443,26 +2421,28 @@ autoconf_fail: if (rndis) device_desc.bNumConfigurations = 2; -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (rndis) - dev_qualifier.bNumConfigurations = 2; - else if (!cdc) - dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC; + if (gadget_is_dualspeed(gadget)) { + if (rndis) + dev_qualifier.bNumConfigurations = 2; + else if (!cdc) + dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC; - /* assumes ep0 uses the same value for both speeds ... */ - dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; + /* assumes ep0 uses the same value for both speeds ... */ + dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; - /* and that all endpoints are dual-speed */ - hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; - hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; + /* and that all endpoints are dual-speed */ + hs_source_desc.bEndpointAddress = + fs_source_desc.bEndpointAddress; + hs_sink_desc.bEndpointAddress = + fs_sink_desc.bEndpointAddress; #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) - if (status_ep) - hs_status_desc.bEndpointAddress = - fs_status_desc.bEndpointAddress; + if (status_ep) + hs_status_desc.bEndpointAddress = + fs_status_desc.bEndpointAddress; #endif -#endif /* DUALSPEED */ + } - if (gadget->is_otg) { + if (gadget_is_otg(gadget)) { otg_descriptor.bmAttributes |= USB_OTG_HNP, eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; eth_config.bMaxPower = 4; @@ -2598,12 +2578,11 @@ fail0: if (rndis_set_param_dev (dev->rndis_config, dev->net, &dev->stats, &dev->cdc_filter)) goto fail0; - if (rndis_set_param_vendor (dev->rndis_config, vendorID, - manufacturer)) + if (rndis_set_param_vendor(dev->rndis_config, vendorID, + manufacturer)) goto fail0; - if (rndis_set_param_medium (dev->rndis_config, - NDIS_MEDIUM_802_3, - 0)) + if (rndis_set_param_medium(dev->rndis_config, + NDIS_MEDIUM_802_3, 0)) goto fail0; INFO (dev, "RNDIS ready\n"); } diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 965ad7bec7b7..73726c570a6e 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -1,7 +1,7 @@ /* * file_storage.c -- File-backed USB Storage Gadget, for USB development * - * Copyright (C) 2003-2005 Alan Stern + * Copyright (C) 2003-2007 Alan Stern * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -217,17 +217,11 @@ */ -#undef DEBUG -#undef VERBOSE -#undef DUMP_MSGS - +/* #define VERBOSE_DEBUG */ +/* #define DUMP_MSGS */ -#include <asm/system.h> -#include <asm/uaccess.h> -#include <linux/bitops.h> #include <linux/blkdev.h> -#include <linux/compiler.h> #include <linux/completion.h> #include <linux/dcache.h> #include <linux/delay.h> @@ -235,18 +229,10 @@ #include <linux/fcntl.h> #include <linux/file.h> #include <linux/fs.h> -#include <linux/init.h> -#include <linux/kernel.h> #include <linux/kref.h> #include <linux/kthread.h> #include <linux/limits.h> -#include <linux/list.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/pagemap.h> #include <linux/rwsem.h> -#include <linux/sched.h> -#include <linux/signal.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/string.h> @@ -254,7 +240,7 @@ #include <linux/utsname.h> #include <linux/usb/ch9.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> #include "gadget_chips.h" @@ -263,7 +249,7 @@ #define DRIVER_DESC "File-backed Storage Gadget" #define DRIVER_NAME "g_file_storage" -#define DRIVER_VERSION "28 November 2005" +#define DRIVER_VERSION "7 August 2007" static const char longname[] = DRIVER_DESC; static const char shortname[] = DRIVER_NAME; @@ -289,57 +275,48 @@ MODULE_LICENSE("Dual BSD/GPL"); /*-------------------------------------------------------------------------*/ -#define xprintk(f,level,fmt,args...) \ - dev_printk(level , &(f)->gadget->dev , fmt , ## args) -#define yprintk(l,level,fmt,args...) \ - dev_printk(level , &(l)->dev , fmt , ## args) - #ifdef DEBUG -#define DBG(fsg,fmt,args...) \ - xprintk(fsg , KERN_DEBUG , fmt , ## args) #define LDBG(lun,fmt,args...) \ - yprintk(lun , KERN_DEBUG , fmt , ## args) + dev_dbg(&(lun)->dev , fmt , ## args) #define MDBG(fmt,args...) \ printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args) #else -#define DBG(fsg,fmt,args...) \ - do { } while (0) #define LDBG(lun,fmt,args...) \ do { } while (0) #define MDBG(fmt,args...) \ do { } while (0) -#undef VERBOSE +#undef VERBOSE_DEBUG #undef DUMP_MSGS #endif /* DEBUG */ -#ifdef VERBOSE -#define VDBG DBG +#ifdef VERBOSE_DEBUG #define VLDBG LDBG #else -#define VDBG(fsg,fmt,args...) \ - do { } while (0) #define VLDBG(lun,fmt,args...) \ do { } while (0) -#endif /* VERBOSE */ +#endif /* VERBOSE_DEBUG */ -#define ERROR(fsg,fmt,args...) \ - xprintk(fsg , KERN_ERR , fmt , ## args) #define LERROR(lun,fmt,args...) \ - yprintk(lun , KERN_ERR , fmt , ## args) - -#define WARN(fsg,fmt,args...) \ - xprintk(fsg , KERN_WARNING , fmt , ## args) + dev_err(&(lun)->dev , fmt , ## args) #define LWARN(lun,fmt,args...) \ - yprintk(lun , KERN_WARNING , fmt , ## args) - -#define INFO(fsg,fmt,args...) \ - xprintk(fsg , KERN_INFO , fmt , ## args) + dev_warn(&(lun)->dev , fmt , ## args) #define LINFO(lun,fmt,args...) \ - yprintk(lun , KERN_INFO , fmt , ## args) + dev_info(&(lun)->dev , fmt , ## args) #define MINFO(fmt,args...) \ printk(KERN_INFO DRIVER_NAME ": " fmt , ## args) +#define DBG(d, fmt, args...) \ + dev_dbg(&(d)->gadget->dev , fmt , ## args) +#define VDBG(d, fmt, args...) \ + dev_vdbg(&(d)->gadget->dev , fmt , ## args) +#define ERROR(d, fmt, args...) \ + dev_err(&(d)->gadget->dev , fmt , ## args) +#define WARN(d, fmt, args...) \ + dev_warn(&(d)->gadget->dev , fmt , ## args) +#define INFO(d, fmt, args...) \ + dev_info(&(d)->gadget->dev , fmt , ## args) + /*-------------------------------------------------------------------------*/ @@ -350,8 +327,8 @@ MODULE_LICENSE("Dual BSD/GPL"); static struct { char *file[MAX_LUNS]; int ro[MAX_LUNS]; - int num_filenames; - int num_ros; + unsigned int num_filenames; + unsigned int num_ros; unsigned int nluns; int removable; @@ -578,7 +555,7 @@ struct lun { #define backing_file_is_open(curlun) ((curlun)->filp != NULL) -static inline struct lun *dev_to_lun(struct device *dev) +static struct lun *dev_to_lun(struct device *dev) { return container_of(dev, struct lun, dev); } @@ -711,13 +688,13 @@ struct fsg_dev { typedef void (*fsg_routine_t)(struct fsg_dev *); -static int inline exception_in_progress(struct fsg_dev *fsg) +static int exception_in_progress(struct fsg_dev *fsg) { return (fsg->state > FSG_STATE_IDLE); } /* Make bulk-out requests be divisible by the maxpacket size */ -static void inline set_bulk_out_req_length(struct fsg_dev *fsg, +static void set_bulk_out_req_length(struct fsg_dev *fsg, struct fsg_buffhd *bh, unsigned int length) { unsigned int rem; @@ -743,50 +720,36 @@ static void close_all_backing_files(struct fsg_dev *fsg); static void dump_msg(struct fsg_dev *fsg, const char *label, const u8 *buf, unsigned int length) { - unsigned int start, num, i; - char line[52], *p; - - if (length >= 512) - return; - DBG(fsg, "%s, length %u:\n", label, length); - - start = 0; - while (length > 0) { - num = min(length, 16u); - p = line; - for (i = 0; i < num; ++i) { - if (i == 8) - *p++ = ' '; - sprintf(p, " %02x", buf[i]); - p += 3; - } - *p = 0; - printk(KERN_DEBUG "%6x: %s\n", start, line); - buf += num; - start += num; - length -= num; + if (length < 512) { + DBG(fsg, "%s, length %u:\n", label, length); + print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, + 16, 1, buf, length, 0); } } -static void inline dump_cdb(struct fsg_dev *fsg) +static void dump_cdb(struct fsg_dev *fsg) {} #else -static void inline dump_msg(struct fsg_dev *fsg, const char *label, +static void dump_msg(struct fsg_dev *fsg, const char *label, const u8 *buf, unsigned int length) {} -static void inline dump_cdb(struct fsg_dev *fsg) -{ - int i; - char cmdbuf[3*MAX_COMMAND_SIZE + 1]; +#ifdef VERBOSE_DEBUG - for (i = 0; i < fsg->cmnd_size; ++i) - sprintf(cmdbuf + i*3, " %02x", fsg->cmnd[i]); - VDBG(fsg, "SCSI CDB: %s\n", cmdbuf); +static void dump_cdb(struct fsg_dev *fsg) +{ + print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE, + 16, 1, fsg->cmnd, fsg->cmnd_size, 0); } +#else + +static void dump_cdb(struct fsg_dev *fsg) +{} + +#endif /* VERBOSE_DEBUG */ #endif /* DUMP_MSGS */ @@ -809,24 +772,24 @@ static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep) /* Routines for unaligned data access */ -static u16 inline get_be16(u8 *buf) +static u16 get_be16(u8 *buf) { return ((u16) buf[0] << 8) | ((u16) buf[1]); } -static u32 inline get_be32(u8 *buf) +static u32 get_be32(u8 *buf) { return ((u32) buf[0] << 24) | ((u32) buf[1] << 16) | ((u32) buf[2] << 8) | ((u32) buf[3]); } -static void inline put_be16(u8 *buf, u16 val) +static void put_be16(u8 *buf, u16 val) { buf[0] = val >> 8; buf[1] = val; } -static void inline put_be32(u8 *buf, u32 val) +static void put_be32(u8 *buf, u32 val) { buf[0] = val >> 24; buf[1] = val >> 16; @@ -950,8 +913,6 @@ static const struct usb_descriptor_header *fs_function[] = { #define FS_FUNCTION_PRE_EP_ENTRIES 2 -#ifdef CONFIG_USB_GADGET_DUALSPEED - /* * USB 2.0 devices need to expose both high speed and full speed * descriptors, unless they only run at full speed. @@ -1014,14 +975,14 @@ static const struct usb_descriptor_header *hs_function[] = { #define HS_FUNCTION_PRE_EP_ENTRIES 2 /* Maxpacket and other transfer characteristics vary by speed. */ -#define ep_desc(g,fs,hs) (((g)->speed==USB_SPEED_HIGH) ? (hs) : (fs)) - -#else - -/* If there's no high speed support, always use the full-speed descriptor. */ -#define ep_desc(g,fs,hs) fs - -#endif /* !CONFIG_USB_GADGET_DUALSPEED */ +static struct usb_endpoint_descriptor * +ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs, + struct usb_endpoint_descriptor *hs) +{ + if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + return hs; + return fs; +} /* The CBI specification limits the serial string to 12 uppercase hexadecimal @@ -1053,26 +1014,22 @@ static struct usb_gadget_strings stringtab = { static int populate_config_buf(struct usb_gadget *gadget, u8 *buf, u8 type, unsigned index) { -#ifdef CONFIG_USB_GADGET_DUALSPEED enum usb_device_speed speed = gadget->speed; -#endif int len; const struct usb_descriptor_header **function; if (index > 0) return -EINVAL; -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (type == USB_DT_OTHER_SPEED_CONFIG) + if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG) speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed; - if (speed == USB_SPEED_HIGH) + if (gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH) function = hs_function; else -#endif function = fs_function; /* for now, don't advertise srp-only devices */ - if (!gadget->is_otg) + if (!gadget_is_otg(gadget)) function++; len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function); @@ -1394,10 +1351,9 @@ static int standard_setup_req(struct fsg_dev *fsg, value = sizeof device_desc; memcpy(req->buf, &device_desc, value); break; -#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: VDBG(fsg, "get device qualifier\n"); - if (!fsg->gadget->is_dualspeed) + if (!gadget_is_dualspeed(fsg->gadget)) break; value = sizeof dev_qualifier; memcpy(req->buf, &dev_qualifier, value); @@ -1405,15 +1361,12 @@ static int standard_setup_req(struct fsg_dev *fsg, case USB_DT_OTHER_SPEED_CONFIG: VDBG(fsg, "get other-speed config descriptor\n"); - if (!fsg->gadget->is_dualspeed) + if (!gadget_is_dualspeed(fsg->gadget)) break; goto get_config; -#endif case USB_DT_CONFIG: VDBG(fsg, "get configuration descriptor\n"); -#ifdef CONFIG_USB_GADGET_DUALSPEED - get_config: -#endif +get_config: value = populate_config_buf(fsg->gadget, req->buf, w_value >> 8, @@ -1646,7 +1599,8 @@ static int do_read(struct fsg_dev *fsg) /* Wait for the next buffer to become available */ bh = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } @@ -1885,7 +1839,8 @@ static int do_write(struct fsg_dev *fsg) } /* Wait for something to happen */ - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } @@ -2369,7 +2324,8 @@ static int pad_with_zeros(struct fsg_dev *fsg) /* Wait for the next buffer to be free */ while (bh->state != BUF_STATE_EMPTY) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } @@ -2429,7 +2385,8 @@ static int throw_away_data(struct fsg_dev *fsg) } /* Otherwise wait for something to happen */ - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } return 0; @@ -2551,7 +2508,8 @@ static int send_status(struct fsg_dev *fsg) /* Wait for the next buffer to become available */ bh = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } @@ -2771,9 +2729,10 @@ static int do_scsi_command(struct fsg_dev *fsg) /* Wait for the next buffer to become available for data or status */ bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; - } + } fsg->phase_error = 0; fsg->short_packet_received = 0; @@ -3005,7 +2964,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) /* Is the CBW meaningful? */ if (cbw->Lun >= MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG || - cbw->Length < 6 || cbw->Length > MAX_COMMAND_SIZE) { + cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) { DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, " "cmdlen %u\n", cbw->Lun, cbw->Flags, cbw->Length); @@ -3045,9 +3004,10 @@ static int get_next_command(struct fsg_dev *fsg) /* Wait for the next buffer to become available */ bh = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; - } + } /* Queue a request to read a Bulk-only CBW */ set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN); @@ -3061,9 +3021,10 @@ static int get_next_command(struct fsg_dev *fsg) /* Wait for the CBW to arrive */ while (bh->state != BUF_STATE_FULL) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; - } + } smp_rmb(); rc = received_cbw(fsg, bh); bh->state = BUF_STATE_EMPTY; @@ -3072,9 +3033,10 @@ static int get_next_command(struct fsg_dev *fsg) /* Wait for the next command to arrive */ while (fsg->cbbuf_cmnd_size == 0) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; - } + } /* Is the previous status interrupt request still busy? * The host is allowed to skip reading the status, @@ -3595,7 +3557,8 @@ static ssize_t show_ro(struct device *dev, struct device_attribute *attr, char * return sprintf(buf, "%d\n", curlun->ro); } -static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_file(struct device *dev, struct device_attribute *attr, + char *buf) { struct lun *curlun = dev_to_lun(dev); struct fsg_dev *fsg = dev_get_drvdata(dev); @@ -3604,8 +3567,8 @@ static ssize_t show_file(struct device *dev, struct device_attribute *attr, char down_read(&fsg->filesem); if (backing_file_is_open(curlun)) { // Get the complete pathname - p = d_path(curlun->filp->f_path.dentry, curlun->filp->f_path.mnt, - buf, PAGE_SIZE - 1); + p = d_path(curlun->filp->f_path.dentry, + curlun->filp->f_path.mnt, buf, PAGE_SIZE - 1); if (IS_ERR(p)) rc = PTR_ERR(p); else { @@ -3623,7 +3586,8 @@ static ssize_t show_file(struct device *dev, struct device_attribute *attr, char } -static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t store_ro(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { ssize_t rc = count; struct lun *curlun = dev_to_lun(dev); @@ -3647,7 +3611,8 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const return rc; } -static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t store_file(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct lun *curlun = dev_to_lun(dev); struct fsg_dev *fsg = dev_get_drvdata(dev); @@ -3859,7 +3824,7 @@ static int __init fsg_bind(struct usb_gadget *gadget) /* Find out how many LUNs there should be */ i = mod_data.nluns; if (i == 0) - i = max(mod_data.num_filenames, 1); + i = max(mod_data.num_filenames, 1u); if (i > MAX_LUNS) { ERROR(fsg, "invalid number of LUNs: %d\n", i); rc = -EINVAL; @@ -3944,21 +3909,23 @@ static int __init fsg_bind(struct usb_gadget *gadget) intf_desc.bInterfaceProtocol = mod_data.transport_type; fs_function[i + FS_FUNCTION_PRE_EP_ENTRIES] = NULL; -#ifdef CONFIG_USB_GADGET_DUALSPEED - hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL; + if (gadget_is_dualspeed(gadget)) { + hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL; - /* Assume ep0 uses the same maxpacket value for both speeds */ - dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket; + /* Assume ep0 uses the same maxpacket value for both speeds */ + dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket; - /* Assume that all endpoint addresses are the same for both speeds */ - hs_bulk_in_desc.bEndpointAddress = fs_bulk_in_desc.bEndpointAddress; - hs_bulk_out_desc.bEndpointAddress = fs_bulk_out_desc.bEndpointAddress; - hs_intr_in_desc.bEndpointAddress = fs_intr_in_desc.bEndpointAddress; -#endif + /* Assume endpoint addresses are the same for both speeds */ + hs_bulk_in_desc.bEndpointAddress = + fs_bulk_in_desc.bEndpointAddress; + hs_bulk_out_desc.bEndpointAddress = + fs_bulk_out_desc.bEndpointAddress; + hs_intr_in_desc.bEndpointAddress = + fs_intr_in_desc.bEndpointAddress; + } - if (gadget->is_otg) { + if (gadget_is_otg(gadget)) otg_desc.bmAttributes |= USB_OTG_HNP; - } rc = -ENOMEM; diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c index d57bcfbc08a5..9bb7f64a85cd 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.c +++ b/drivers/usb/gadget/fsl_usb2_udc.c @@ -35,7 +35,7 @@ #include <linux/moduleparam.h> #include <linux/device.h> #include <linux/usb/ch9.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> #include <linux/usb/otg.h> #include <linux/dma-mapping.h> #include <linux/platform_device.h> @@ -1090,14 +1090,11 @@ static int fsl_vbus_session(struct usb_gadget *gadget, int is_active) */ static int fsl_vbus_draw(struct usb_gadget *gadget, unsigned mA) { -#ifdef CONFIG_USB_OTG struct fsl_udc *udc; udc = container_of(gadget, struct fsl_udc, gadget); - if (udc->transceiver) return otg_set_power(udc->transceiver, mA); -#endif return -ENOTSUPP; } @@ -1120,7 +1117,7 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on) return 0; } -/* defined in usb_gadget.h */ +/* defined in gadget.h */ static struct usb_gadget_ops fsl_gadget_ops = { .get_frame = fsl_get_frame, .wakeup = fsl_wakeup, @@ -1321,7 +1318,7 @@ static void setup_received_irq(struct fsl_udc *udc, | USB_TYPE_STANDARD)) { /* Note: The driver has not include OTG support yet. * This will be set when OTG support is added */ - if (!udc->gadget.is_otg) + if (!gadget_is_otg(udc->gadget)) break; else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE) udc->gadget.b_hnp_enable = 1; @@ -1330,6 +1327,8 @@ static void setup_received_irq(struct fsl_udc *udc, else if (setup->bRequest == USB_DEVICE_A_ALT_HNP_SUPPORT) udc->gadget.a_alt_hnp_support = 1; + else + break; rc = 0; } else break; @@ -1840,10 +1839,8 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) if (!driver || driver != udc_controller->driver || !driver->unbind) return -EINVAL; -#ifdef CONFIG_USB_OTG if (udc_controller->transceiver) (void)otg_set_peripheral(udc_controller->transceiver, 0); -#endif /* stop DR, disable intr */ dr_controller_stop(udc_controller); diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index 1c5aa49d7432..0689189550bc 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -18,17 +18,11 @@ * http://www.usb.org/developers/devclass_docs/midi10.pdf */ -#define DEBUG 1 -// #define VERBOSE +/* #define VERBOSE_DEBUG */ -#include <linux/module.h> #include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/errno.h> -#include <linux/init.h> #include <linux/utsname.h> #include <linux/device.h> -#include <linux/moduleparam.h> #include <sound/driver.h> #include <sound/core.h> @@ -36,7 +30,7 @@ #include <sound/rawmidi.h> #include <linux/usb/ch9.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> #include <linux/usb/audio.h> #include <linux/usb/midi.h> @@ -139,30 +133,16 @@ struct gmidi_device { static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req); -#define xprintk(d,level,fmt,args...) \ - dev_printk(level , &(d)->gadget->dev , fmt , ## args) - -#ifdef DEBUG -#define DBG(dev,fmt,args...) \ - xprintk(dev , KERN_DEBUG , fmt , ## args) -#else -#define DBG(dev,fmt,args...) \ - do { } while (0) -#endif /* DEBUG */ - -#ifdef VERBOSE -#define VDBG DBG -#else -#define VDBG(dev,fmt,args...) \ - do { } while (0) -#endif /* VERBOSE */ - -#define ERROR(dev,fmt,args...) \ - xprintk(dev , KERN_ERR , fmt , ## args) -#define WARN(dev,fmt,args...) \ - xprintk(dev , KERN_WARNING , fmt , ## args) -#define INFO(dev,fmt,args...) \ - xprintk(dev , KERN_INFO , fmt , ## args) +#define DBG(d, fmt, args...) \ + dev_dbg(&(d)->gadget->dev , fmt , ## args) +#define VDBG(d, fmt, args...) \ + dev_vdbg(&(d)->gadget->dev , fmt , ## args) +#define ERROR(d, fmt, args...) \ + dev_err(&(d)->gadget->dev , fmt , ## args) +#define WARN(d, fmt, args...) \ + dev_warn(&(d)->gadget->dev , fmt , ## args) +#define INFO(d, fmt, args...) \ + dev_info(&(d)->gadget->dev , fmt , ## args) static unsigned buflen = 256; @@ -425,7 +405,7 @@ static int config_buf(struct usb_gadget *gadget, return len; } -static struct usb_request* alloc_ep_req(struct usb_ep *ep, unsigned length) +static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length) { struct usb_request *req; @@ -455,7 +435,7 @@ static const uint8_t gmidi_cin_length[] = { * Receives a chunk of MIDI data. */ static void gmidi_read_data(struct usb_ep *ep, int cable, - uint8_t* data, int length) + uint8_t *data, int length) { struct gmidi_device *dev = ep->driver_data; /* cable is ignored, because for now we only have one. */ @@ -541,7 +521,7 @@ static int set_gmidi_config(struct gmidi_device *dev, gfp_t gfp_flags) { int err = 0; struct usb_request *req; - struct usb_ep* ep; + struct usb_ep *ep; unsigned i; err = usb_ep_enable(dev->in_ep, &bulk_in_desc); @@ -628,7 +608,7 @@ gmidi_set_config(struct gmidi_device *dev, unsigned number, gfp_t gfp_flags) if (gadget_is_sa1100(gadget) && dev->config) { /* tx fifo is full, but we can't clear it...*/ - INFO(dev, "can't change configurations\n"); + ERROR(dev, "can't change configurations\n"); return -ESPIPE; } gmidi_reset_config(dev); @@ -843,7 +823,7 @@ static void gmidi_disconnect(struct usb_gadget *gadget) static void /* __init_or_exit */ gmidi_unbind(struct usb_gadget *gadget) { struct gmidi_device *dev = get_gadget_data(gadget); - struct snd_card* card; + struct snd_card *card; DBG(dev, "unbind\n"); @@ -867,12 +847,12 @@ static int gmidi_snd_free(struct snd_device *device) return 0; } -static void gmidi_transmit_packet(struct usb_request* req, uint8_t p0, +static void gmidi_transmit_packet(struct usb_request *req, uint8_t p0, uint8_t p1, uint8_t p2, uint8_t p3) { unsigned length = req->length; + u8 *buf = (u8 *)req->buf + length; - uint8_t* buf = (uint8_t*)req->buf + length; buf[0] = p0; buf[1] = p1; buf[2] = p2; @@ -883,8 +863,8 @@ static void gmidi_transmit_packet(struct usb_request* req, uint8_t p0, /* * Converts MIDI commands to USB MIDI packets. */ -static void gmidi_transmit_byte(struct usb_request* req, - struct gmidi_in_port* port, uint8_t b) +static void gmidi_transmit_byte(struct usb_request *req, + struct gmidi_in_port *port, uint8_t b) { uint8_t p0 = port->cable; @@ -981,10 +961,10 @@ static void gmidi_transmit_byte(struct usb_request* req, } } -static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req) +static void gmidi_transmit(struct gmidi_device *dev, struct usb_request *req) { - struct usb_ep* ep = dev->in_ep; - struct gmidi_in_port* port = &dev->in_port; + struct usb_ep *ep = dev->in_ep; + struct gmidi_in_port *port = &dev->in_port; if (!ep) { return; @@ -1020,14 +1000,14 @@ static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req) static void gmidi_in_tasklet(unsigned long data) { - struct gmidi_device* dev = (struct gmidi_device*)data; + struct gmidi_device *dev = (struct gmidi_device *)data; gmidi_transmit(dev, NULL); } static int gmidi_in_open(struct snd_rawmidi_substream *substream) { - struct gmidi_device* dev = substream->rmidi->private_data; + struct gmidi_device *dev = substream->rmidi->private_data; VDBG(dev, "gmidi_in_open\n"); dev->in_substream = substream; @@ -1037,13 +1017,15 @@ static int gmidi_in_open(struct snd_rawmidi_substream *substream) static int gmidi_in_close(struct snd_rawmidi_substream *substream) { + struct gmidi_device *dev = substream->rmidi->private_data; + VDBG(dev, "gmidi_in_close\n"); return 0; } static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up) { - struct gmidi_device* dev = substream->rmidi->private_data; + struct gmidi_device *dev = substream->rmidi->private_data; VDBG(dev, "gmidi_in_trigger %d\n", up); dev->in_port.active = up; @@ -1054,7 +1036,7 @@ static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up) static int gmidi_out_open(struct snd_rawmidi_substream *substream) { - struct gmidi_device* dev = substream->rmidi->private_data; + struct gmidi_device *dev = substream->rmidi->private_data; VDBG(dev, "gmidi_out_open\n"); dev->out_substream = substream; @@ -1063,13 +1045,15 @@ static int gmidi_out_open(struct snd_rawmidi_substream *substream) static int gmidi_out_close(struct snd_rawmidi_substream *substream) { + struct gmidi_device *dev = substream->rmidi->private_data; + VDBG(dev, "gmidi_out_close\n"); return 0; } static void gmidi_out_trigger(struct snd_rawmidi_substream *substream, int up) { - struct gmidi_device* dev = substream->rmidi->private_data; + struct gmidi_device *dev = substream->rmidi->private_data; VDBG(dev, "gmidi_out_trigger %d\n", up); if (up) { diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 349b8166f34a..2ec9d196a8cf 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -37,7 +37,7 @@ #include <linux/proc_fs.h> #include <linux/device.h> #include <linux/usb/ch9.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> #include <asm/byteorder.h> #include <asm/io.h> diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 173004f60fea..47ef8bd58a00 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -20,8 +20,7 @@ */ -// #define DEBUG /* data to help fault diagnosis */ -// #define VERBOSE /* extra debug messages (success too) */ +/* #define VERBOSE_DEBUG */ #include <linux/init.h> #include <linux/module.h> @@ -38,7 +37,7 @@ #include <linux/moduleparam.h> #include <linux/usb/gadgetfs.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> /* @@ -253,7 +252,7 @@ static const char *CHIP; do { } while (0) #endif /* DEBUG */ -#ifdef VERBOSE +#ifdef VERBOSE_DEBUG #define VDEBUG DBG #else #define VDEBUG(dev,fmt,args...) \ @@ -1010,11 +1009,12 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) /* assume that was SET_CONFIGURATION */ if (dev->current_config) { unsigned power; -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (dev->gadget->speed == USB_SPEED_HIGH) + + if (gadget_is_dualspeed(dev->gadget) + && (dev->gadget->speed + == USB_SPEED_HIGH)) power = dev->hs_config->bMaxPower; else -#endif power = dev->config->bMaxPower; usb_gadget_vbus_draw(dev->gadget, 2 * power); } @@ -1355,24 +1355,21 @@ static int config_buf (struct dev_data *dev, u8 type, unsigned index) { int len; -#ifdef CONFIG_USB_GADGET_DUALSPEED - int hs; -#endif + int hs = 0; /* only one configuration */ if (index > 0) return -EINVAL; -#ifdef CONFIG_USB_GADGET_DUALSPEED - hs = (dev->gadget->speed == USB_SPEED_HIGH); - if (type == USB_DT_OTHER_SPEED_CONFIG) - hs = !hs; + if (gadget_is_dualspeed(dev->gadget)) { + hs = (dev->gadget->speed == USB_SPEED_HIGH); + if (type == USB_DT_OTHER_SPEED_CONFIG) + hs = !hs; + } if (hs) { dev->req->buf = dev->hs_config; len = le16_to_cpu(dev->hs_config->wTotalLength); - } else -#endif - { + } else { dev->req->buf = dev->config; len = le16_to_cpu(dev->config->wTotalLength); } @@ -1393,13 +1390,13 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) spin_lock (&dev->lock); dev->setup_abort = 0; if (dev->state == STATE_DEV_UNCONNECTED) { -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (gadget->speed == USB_SPEED_HIGH && dev->hs_config == NULL) { + if (gadget_is_dualspeed(gadget) + && gadget->speed == USB_SPEED_HIGH + && dev->hs_config == NULL) { spin_unlock(&dev->lock); ERROR (dev, "no high speed config??\n"); return -EINVAL; } -#endif /* CONFIG_USB_GADGET_DUALSPEED */ dev->state = STATE_DEV_CONNECTED; dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket; @@ -1469,13 +1466,12 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) // user mode expected to disable endpoints } else { u8 config, power; -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (gadget->speed == USB_SPEED_HIGH) { + + if (gadget_is_dualspeed(gadget) + && gadget->speed == USB_SPEED_HIGH) { config = dev->hs_config->bConfigurationValue; power = dev->hs_config->bMaxPower; - } else -#endif - { + } else { config = dev->config->bConfigurationValue; power = dev->config->bMaxPower; } diff --git a/drivers/usb/gadget/lh7a40x_udc.h b/drivers/usb/gadget/lh7a40x_udc.h index b3fe197e1eeb..1ecfd6366b9a 100644 --- a/drivers/usb/gadget/lh7a40x_udc.h +++ b/drivers/usb/gadget/lh7a40x_udc.h @@ -50,7 +50,7 @@ #include <asm/hardware.h> #include <linux/usb/ch9.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> /* * Memory map diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 4b27d12f049d..ebc5536aa271 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -27,7 +27,7 @@ #include <linux/platform_device.h> #include <linux/usb/ch9.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> #include "m66592-udc.h" diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index c3d364ecd4f8..d5d473f8144b 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -62,7 +62,7 @@ #include <linux/moduleparam.h> #include <linux/device.h> #include <linux/usb/ch9.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> #include <asm/byteorder.h> #include <asm/io.h> diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 9b0f0925dddf..87c4f50dfb61 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -38,7 +38,7 @@ #include <linux/moduleparam.h> #include <linux/platform_device.h> #include <linux/usb/ch9.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> #include <linux/usb/otg.h> #include <linux/dma-mapping.h> #include <linux/clk.h> @@ -1241,19 +1241,15 @@ static void pullup_enable(struct omap_udc *udc) udc->gadget.dev.parent->power.power_state = PMSG_ON; udc->gadget.dev.power.power_state = PMSG_ON; UDC_SYSCON1_REG |= UDC_PULLUP_EN; -#ifndef CONFIG_USB_OTG - if (!cpu_is_omap15xx()) + if (!gadget_is_otg(udc->gadget) && !cpu_is_omap15xx()) OTG_CTRL_REG |= OTG_BSESSVLD; -#endif UDC_IRQ_EN_REG = UDC_DS_CHG_IE; } static void pullup_disable(struct omap_udc *udc) { -#ifndef CONFIG_USB_OTG - if (!cpu_is_omap15xx()) + if (!gadget_is_otg(udc->gadget) && !cpu_is_omap15xx()) OTG_CTRL_REG &= ~OTG_BSESSVLD; -#endif UDC_IRQ_EN_REG = UDC_DS_CHG_IE; UDC_SYSCON1_REG &= ~UDC_PULLUP_EN; } @@ -1390,7 +1386,7 @@ static void update_otg(struct omap_udc *udc) { u16 devstat; - if (!udc->gadget.is_otg) + if (!gadget_is_otg(udc->gadget)) return; if (OTG_CTRL_REG & OTG_ID) diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index 90d0d086b9b8..3173b39f0bfd 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -56,7 +56,7 @@ #include <asm/hardware.h> #include <linux/usb/ch9.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> #include <asm/mach/udc_pxa2xx.h> diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index 0be80c635c48..e3e90f8a75e7 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -42,7 +42,7 @@ #include <linux/seq_file.h> #include <linux/usb.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> #include <asm/byteorder.h> #include <asm/io.h> diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index ce4d2e09633d..f5738eb8e765 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -17,34 +17,15 @@ * */ -#include <linux/module.h> #include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/ioport.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/timer.h> -#include <linux/list.h> -#include <linux/interrupt.h> #include <linux/utsname.h> -#include <linux/wait.h> -#include <linux/proc_fs.h> #include <linux/device.h> #include <linux/tty.h> #include <linux/tty_flip.h> -#include <linux/mutex.h> - -#include <asm/byteorder.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/system.h> -#include <asm/unaligned.h> -#include <asm/uaccess.h> #include <linux/usb/ch9.h> #include <linux/usb/cdc.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> #include "gadget_chips.h" @@ -89,30 +70,29 @@ #define GS_DEFAULT_PARITY USB_CDC_NO_PARITY #define GS_DEFAULT_CHAR_FORMAT USB_CDC_1_STOP_BITS -/* select highspeed/fullspeed, hiding highspeed if not configured */ -#ifdef CONFIG_USB_GADGET_DUALSPEED -#define GS_SPEED_SELECT(is_hs,hs,fs) ((is_hs) ? (hs) : (fs)) -#else -#define GS_SPEED_SELECT(is_hs,hs,fs) (fs) -#endif /* CONFIG_USB_GADGET_DUALSPEED */ +/* maxpacket and other transfer characteristics vary by speed. */ +static inline struct usb_endpoint_descriptor * +choose_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs, + struct usb_endpoint_descriptor *fs) +{ + if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + return hs; + return fs; +} + /* debug settings */ -#ifdef GS_DEBUG +#ifdef DEBUG static int debug = 1; +#else +#define debug 0 +#endif #define gs_debug(format, arg...) \ do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0) #define gs_debug_level(level, format, arg...) \ do { if (debug>=level) printk(KERN_DEBUG format, ## arg); } while(0) -#else - -#define gs_debug(format, arg...) \ - do { } while(0) -#define gs_debug_level(level, format, arg...) \ - do { } while(0) - -#endif /* GS_DEBUG */ /* Thanks to NetChip Technologies for donating this product ID. * @@ -147,10 +127,10 @@ struct gs_req_entry { /* the port structure holds info for each port, one for each minor number */ struct gs_port { - struct gs_dev *port_dev; /* pointer to device struct */ + struct gs_dev *port_dev; /* pointer to device struct */ struct tty_struct *port_tty; /* pointer to tty struct */ spinlock_t port_lock; - int port_num; + int port_num; int port_open_count; int port_in_use; /* open/close in progress */ wait_queue_head_t port_write_wait;/* waiting to write */ @@ -188,7 +168,7 @@ static void __exit gs_module_exit(void); /* tty driver */ static int gs_open(struct tty_struct *tty, struct file *file); static void gs_close(struct tty_struct *tty, struct file *file); -static int gs_write(struct tty_struct *tty, +static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count); static void gs_put_char(struct tty_struct *tty, unsigned char ch); static void gs_flush_chars(struct tty_struct *tty); @@ -222,7 +202,7 @@ static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req); static void gs_disconnect(struct usb_gadget *gadget); static int gs_set_config(struct gs_dev *dev, unsigned config); static void gs_reset_config(struct gs_dev *dev); -static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed, +static int gs_build_config_buf(u8 *buf, struct usb_gadget *g, u8 type, unsigned int index, int is_otg); static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len, @@ -415,18 +395,18 @@ static const struct usb_cdc_header_desc gs_header_desc = { }; static const struct usb_cdc_call_mgmt_descriptor gs_call_mgmt_descriptor = { - .bLength = sizeof(gs_call_mgmt_descriptor), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE, - .bmCapabilities = 0, - .bDataInterface = 1, /* index of data interface */ + .bLength = sizeof(gs_call_mgmt_descriptor), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE, + .bmCapabilities = 0, + .bDataInterface = 1, /* index of data interface */ }; static struct usb_cdc_acm_descriptor gs_acm_descriptor = { - .bLength = sizeof(gs_acm_descriptor), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_ACM_TYPE, - .bmCapabilities = 0, + .bLength = sizeof(gs_acm_descriptor), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_ACM_TYPE, + .bmCapabilities = 0, }; static const struct usb_cdc_union_desc gs_union_desc = { @@ -436,7 +416,7 @@ static const struct usb_cdc_union_desc gs_union_desc = { .bMasterInterface0 = 0, /* index of control interface */ .bSlaveInterface0 = 1, /* index of data interface */ }; - + static struct usb_endpoint_descriptor gs_fullspeed_notify_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -482,7 +462,6 @@ static const struct usb_descriptor_header *gs_acm_fullspeed_function[] = { NULL, }; -#ifdef CONFIG_USB_GADGET_DUALSPEED static struct usb_endpoint_descriptor gs_highspeed_notify_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -536,15 +515,13 @@ static const struct usb_descriptor_header *gs_acm_highspeed_function[] = { NULL, }; -#endif /* CONFIG_USB_GADGET_DUALSPEED */ - /* Module */ MODULE_DESCRIPTION(GS_LONG_NAME); MODULE_AUTHOR("Al Borchers"); MODULE_LICENSE("GPL"); -#ifdef GS_DEBUG +#ifdef DEBUG module_param(debug, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on"); #endif @@ -915,7 +892,8 @@ static void gs_put_char(struct tty_struct *tty, unsigned char ch) return; } - gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p, %p, %p\n", port->port_num, tty, ch, __builtin_return_address(0), __builtin_return_address(1), __builtin_return_address(2)); + gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p\n", + port->port_num, tty, ch, __builtin_return_address(0)); spin_lock_irqsave(&port->port_lock, flags); @@ -1116,7 +1094,11 @@ static int gs_send(struct gs_dev *dev) len = gs_send_packet(dev, req->buf, ep->maxpacket); if (len > 0) { -gs_debug_level(3, "gs_send: len=%d, 0x%2.2x 0x%2.2x 0x%2.2x ...\n", len, *((unsigned char *)req->buf), *((unsigned char *)req->buf+1), *((unsigned char *)req->buf+2)); + gs_debug_level(3, "gs_send: len=%d, 0x%2.2x " + "0x%2.2x 0x%2.2x ...\n", len, + *((unsigned char *)req->buf), + *((unsigned char *)req->buf+1), + *((unsigned char *)req->buf+2)); list_del(&req_entry->re_entry); req->length = len; spin_unlock_irqrestore(&dev->dev_lock, flags); @@ -1269,7 +1251,7 @@ static void gs_read_complete(struct usb_ep *ep, struct usb_request *req) switch(req->status) { case 0: - /* normal completion */ + /* normal completion */ gs_recv_packet(dev, req->buf, req->actual); requeue: req->length = ep->maxpacket; @@ -1406,23 +1388,24 @@ static int __init gs_bind(struct usb_gadget *gadget) ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC; gs_device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; -#ifdef CONFIG_USB_GADGET_DUALSPEED - gs_qualifier_desc.bDeviceClass = use_acm - ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC; - /* assume ep0 uses the same packet size for both speeds */ - gs_qualifier_desc.bMaxPacketSize0 = gs_device_desc.bMaxPacketSize0; - /* assume endpoints are dual-speed */ - gs_highspeed_notify_desc.bEndpointAddress = - gs_fullspeed_notify_desc.bEndpointAddress; - gs_highspeed_in_desc.bEndpointAddress = - gs_fullspeed_in_desc.bEndpointAddress; - gs_highspeed_out_desc.bEndpointAddress = - gs_fullspeed_out_desc.bEndpointAddress; -#endif /* CONFIG_USB_GADGET_DUALSPEED */ + if (gadget_is_dualspeed(gadget)) { + gs_qualifier_desc.bDeviceClass = use_acm + ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC; + /* assume ep0 uses the same packet size for both speeds */ + gs_qualifier_desc.bMaxPacketSize0 = + gs_device_desc.bMaxPacketSize0; + /* assume endpoints are dual-speed */ + gs_highspeed_notify_desc.bEndpointAddress = + gs_fullspeed_notify_desc.bEndpointAddress; + gs_highspeed_in_desc.bEndpointAddress = + gs_fullspeed_in_desc.bEndpointAddress; + gs_highspeed_out_desc.bEndpointAddress = + gs_fullspeed_out_desc.bEndpointAddress; + } usb_gadget_set_selfpowered(gadget); - if (gadget->is_otg) { + if (gadget_is_otg(gadget)) { gs_otg_descriptor.bmAttributes |= USB_OTG_HNP, gs_bulk_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP; gs_acm_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP; @@ -1487,6 +1470,12 @@ static void /* __init_or_exit */ gs_unbind(struct usb_gadget *gadget) dev->dev_ctrl_req = NULL; } gs_free_ports(dev); + if (dev->dev_notify_ep) + usb_ep_disable(dev->dev_notify_ep); + if (dev->dev_in_ep) + usb_ep_disable(dev->dev_in_ep); + if (dev->dev_out_ep) + usb_ep_disable(dev->dev_out_ep); kfree(dev); set_gadget_data(gadget, NULL); } @@ -1570,9 +1559,8 @@ static int gs_setup_standard(struct usb_gadget *gadget, memcpy(req->buf, &gs_device_desc, ret); break; -#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; ret = min(wLength, (u16)sizeof(struct usb_qualifier_descriptor)); @@ -1580,14 +1568,13 @@ static int gs_setup_standard(struct usb_gadget *gadget, break; case USB_DT_OTHER_SPEED_CONFIG: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; /* fall through */ -#endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: - ret = gs_build_config_buf(req->buf, gadget->speed, + ret = gs_build_config_buf(req->buf, gadget, wValue >> 8, wValue & 0xff, - gadget->is_otg); + gadget_is_otg(gadget)); if (ret >= 0) ret = min(wLength, (u16)ret); break; @@ -1827,8 +1814,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) if (EP_NOTIFY_NAME && strcmp(ep->name, EP_NOTIFY_NAME) == 0) { - ep_desc = GS_SPEED_SELECT( - gadget->speed == USB_SPEED_HIGH, + ep_desc = choose_ep_desc(gadget, &gs_highspeed_notify_desc, &gs_fullspeed_notify_desc); ret = usb_ep_enable(ep,ep_desc); @@ -1844,9 +1830,8 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) } else if (strcmp(ep->name, EP_IN_NAME) == 0) { - ep_desc = GS_SPEED_SELECT( - gadget->speed == USB_SPEED_HIGH, - &gs_highspeed_in_desc, + ep_desc = choose_ep_desc(gadget, + &gs_highspeed_in_desc, &gs_fullspeed_in_desc); ret = usb_ep_enable(ep,ep_desc); if (ret == 0) { @@ -1861,8 +1846,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) } else if (strcmp(ep->name, EP_OUT_NAME) == 0) { - ep_desc = GS_SPEED_SELECT( - gadget->speed == USB_SPEED_HIGH, + ep_desc = choose_ep_desc(gadget, &gs_highspeed_out_desc, &gs_fullspeed_out_desc); ret = usb_ep_enable(ep,ep_desc); @@ -1981,11 +1965,11 @@ static void gs_reset_config(struct gs_dev *dev) * Builds the config descriptors in the given buffer and returns the * length, or a negative error number. */ -static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed, +static int gs_build_config_buf(u8 *buf, struct usb_gadget *g, u8 type, unsigned int index, int is_otg) { int len; - int high_speed; + int high_speed = 0; const struct usb_config_descriptor *config_desc; const struct usb_descriptor_header **function; @@ -1993,20 +1977,22 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed, return -EINVAL; /* other speed switches high and full speed */ - high_speed = (speed == USB_SPEED_HIGH); - if (type == USB_DT_OTHER_SPEED_CONFIG) - high_speed = !high_speed; + if (gadget_is_dualspeed(g)) { + high_speed = (g->speed == USB_SPEED_HIGH); + if (type == USB_DT_OTHER_SPEED_CONFIG) + high_speed = !high_speed; + } if (use_acm) { config_desc = &gs_acm_config_desc; - function = GS_SPEED_SELECT(high_speed, - gs_acm_highspeed_function, - gs_acm_fullspeed_function); + function = high_speed + ? gs_acm_highspeed_function + : gs_acm_fullspeed_function; } else { config_desc = &gs_bulk_config_desc; - function = GS_SPEED_SELECT(high_speed, - gs_bulk_highspeed_function, - gs_bulk_fullspeed_function); + function = high_speed + ? gs_bulk_highspeed_function + : gs_bulk_fullspeed_function; } /* for now, don't advertise srp-only devices */ diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c index 3459ea6c6c0b..878e428a0ec1 100644 --- a/drivers/usb/gadget/usbstring.c +++ b/drivers/usb/gadget/usbstring.c @@ -15,7 +15,7 @@ #include <linux/init.h> #include <linux/usb/ch9.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> #include <asm/unaligned.h> diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index fcfe869acb94..fcde5d9c87df 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -1,38 +1,22 @@ /* * zero.c -- Gadget Zero, for USB development * - * Copyright (C) 2003-2004 David Brownell + * Copyright (C) 2003-2007 David Brownell * All rights reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. + * 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. * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation, either version 2 of that 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. * - * 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 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. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -57,40 +41,28 @@ * Many drivers will only have one configuration, letting them be much * simpler if they also don't support high speed operation (like this * driver does). + * + * Why is *this* driver using two configurations, rather than setting up + * two interfaces with different functions? To help verify that multiple + * configuration infrastucture is working correctly; also, so that it can + * work with low capability USB controllers without four bulk endpoints. */ -#define DEBUG 1 -// #define VERBOSE +/* #define VERBOSE_DEBUG */ -#include <linux/module.h> #include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/ioport.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/timer.h> -#include <linux/list.h> -#include <linux/interrupt.h> #include <linux/utsname.h> #include <linux/device.h> -#include <linux/moduleparam.h> - -#include <asm/byteorder.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/system.h> -#include <asm/unaligned.h> #include <linux/usb/ch9.h> -#include <linux/usb_gadget.h> +#include <linux/usb/gadget.h> #include "gadget_chips.h" /*-------------------------------------------------------------------------*/ -#define DRIVER_VERSION "St Patrick's Day 2004" +#define DRIVER_VERSION "Lughnasadh, 2007" static const char shortname [] = "zero"; static const char longname [] = "Gadget Zero"; @@ -131,30 +103,16 @@ struct zero_dev { struct timer_list resume; }; -#define xprintk(d,level,fmt,args...) \ - dev_printk(level , &(d)->gadget->dev , fmt , ## args) - -#ifdef DEBUG -#define DBG(dev,fmt,args...) \ - xprintk(dev , KERN_DEBUG , fmt , ## args) -#else -#define DBG(dev,fmt,args...) \ - do { } while (0) -#endif /* DEBUG */ - -#ifdef VERBOSE -#define VDBG DBG -#else -#define VDBG(dev,fmt,args...) \ - do { } while (0) -#endif /* VERBOSE */ - -#define ERROR(dev,fmt,args...) \ - xprintk(dev , KERN_ERR , fmt , ## args) -#define WARN(dev,fmt,args...) \ - xprintk(dev , KERN_WARNING , fmt , ## args) -#define INFO(dev,fmt,args...) \ - xprintk(dev , KERN_INFO , fmt , ## args) +#define DBG(d, fmt, args...) \ + dev_dbg(&(d)->gadget->dev , fmt , ## args) +#define VDBG(d, fmt, args...) \ + dev_vdbg(&(d)->gadget->dev , fmt , ## args) +#define ERROR(d, fmt, args...) \ + dev_err(&(d)->gadget->dev , fmt , ## args) +#define WARN(d, fmt, args...) \ + dev_warn(&(d)->gadget->dev , fmt , ## args) +#define INFO(d, fmt, args...) \ + dev_info(&(d)->gadget->dev , fmt , ## args) /*-------------------------------------------------------------------------*/ @@ -326,8 +284,6 @@ static const struct usb_descriptor_header *fs_loopback_function [] = { NULL, }; -#ifdef CONFIG_USB_GADGET_DUALSPEED - /* * usb 2.0 devices need to expose both high speed and full speed * descriptors, unless they only run at full speed. @@ -383,17 +339,20 @@ static const struct usb_descriptor_header *hs_loopback_function [] = { }; /* maxpacket and other transfer characteristics vary by speed. */ -#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs)) - -#else +static inline struct usb_endpoint_descriptor * +ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs, + struct usb_endpoint_descriptor *fs) +{ + if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + return hs; + return fs; +} -/* if there's no high speed support, maxpacket doesn't change. */ -#define ep_desc(g,hs,fs) fs +static char manufacturer[50]; -#endif /* !CONFIG_USB_GADGET_DUALSPEED */ +/* default serial number takes at least two packets */ +static char serial[] = "0123456789.0123456789.0123456789"; -static char manufacturer [50]; -static char serial [40]; /* static strings, in UTF-8 */ static struct usb_string strings [] = { @@ -435,30 +394,29 @@ config_buf (struct usb_gadget *gadget, int is_source_sink; int len; const struct usb_descriptor_header **function; -#ifdef CONFIG_USB_GADGET_DUALSPEED - int hs = (gadget->speed == USB_SPEED_HIGH); -#endif + int hs = 0; /* two configurations will always be index 0 and index 1 */ if (index > 1) return -EINVAL; is_source_sink = loopdefault ? (index == 1) : (index == 0); -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (type == USB_DT_OTHER_SPEED_CONFIG) - hs = !hs; + if (gadget_is_dualspeed(gadget)) { + hs = (gadget->speed == USB_SPEED_HIGH); + if (type == USB_DT_OTHER_SPEED_CONFIG) + hs = !hs; + } if (hs) function = is_source_sink ? hs_source_sink_function : hs_loopback_function; else -#endif function = is_source_sink ? fs_source_sink_function : fs_loopback_function; /* for now, don't advertise srp-only devices */ - if (!gadget->is_otg) + if (!gadget_is_otg(gadget)) function++; len = usb_gadget_config_buf (is_source_sink @@ -498,6 +456,19 @@ static void free_ep_req (struct usb_ep *ep, struct usb_request *req) /*-------------------------------------------------------------------------*/ +/* + * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripherals, + * this just sinks bulk packets OUT to the peripheral and sources them IN + * to the host, optionally with specific data patterns. + * + * In terms of control messaging, this supports all the standard requests + * plus two that support control-OUT tests. + * + * Note that because this doesn't queue more than one request at a time, + * some other function must be used to test queueing logic. The network + * link (g_ether) is probably the best option for that. + */ + /* optionally require specific source/sink data patterns */ static int @@ -534,12 +505,7 @@ check_read_data ( return 0; } -static void -reinit_write_data ( - struct zero_dev *dev, - struct usb_ep *ep, - struct usb_request *req -) +static void reinit_write_data(struct usb_ep *ep, struct usb_request *req) { unsigned i; u8 *buf = req->buf; @@ -566,16 +532,16 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req) switch (status) { - case 0: /* normal completion? */ + case 0: /* normal completion? */ if (ep == dev->out_ep) { check_read_data (dev, ep, req); memset (req->buf, 0x55, req->length); } else - reinit_write_data (dev, ep, req); + reinit_write_data(ep, req); break; /* this endpoint is normally active while we're configured */ - case -ECONNABORTED: /* hardware forced ep reset */ + case -ECONNABORTED: /* hardware forced ep reset */ case -ECONNRESET: /* request dequeued */ case -ESHUTDOWN: /* disconnect from host */ VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status, @@ -607,8 +573,7 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req) } } -static struct usb_request * -source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags) +static struct usb_request *source_sink_start_ep(struct usb_ep *ep) { struct usb_request *req; int status; @@ -621,11 +586,11 @@ source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags) req->complete = source_sink_complete; if (strcmp (ep->name, EP_IN_NAME) == 0) - reinit_write_data (ep->driver_data, ep, req); + reinit_write_data(ep, req); else memset (req->buf, 0x55, req->length); - status = usb_ep_queue (ep, req, gfp_flags); + status = usb_ep_queue(ep, req, GFP_ATOMIC); if (status) { struct zero_dev *dev = ep->driver_data; @@ -637,8 +602,7 @@ source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags) return req; } -static int -set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags) +static int set_source_sink_config(struct zero_dev *dev) { int result = 0; struct usb_ep *ep; @@ -653,8 +617,7 @@ set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags) result = usb_ep_enable (ep, d); if (result == 0) { ep->driver_data = dev; - if (source_sink_start_ep(ep, gfp_flags) - != NULL) { + if (source_sink_start_ep(ep) != NULL) { dev->in_ep = ep; continue; } @@ -668,8 +631,7 @@ set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags) result = usb_ep_enable (ep, d); if (result == 0) { ep->driver_data = dev; - if (source_sink_start_ep(ep, gfp_flags) - != NULL) { + if (source_sink_start_ep(ep) != NULL) { dev->out_ep = ep; continue; } @@ -701,7 +663,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req) switch (status) { - case 0: /* normal completion? */ + case 0: /* normal completion? */ if (ep == dev->out_ep) { /* loop this OUT packet back IN to the host */ req->zero = (req->actual < req->length); @@ -735,7 +697,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req) * rely on the hardware driver to clean up on disconnect or * endpoint disable. */ - case -ECONNABORTED: /* hardware forced ep reset */ + case -ECONNABORTED: /* hardware forced ep reset */ case -ECONNRESET: /* request dequeued */ case -ESHUTDOWN: /* disconnect from host */ free_ep_req (ep, req); @@ -743,8 +705,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req) } } -static int -set_loopback_config (struct zero_dev *dev, gfp_t gfp_flags) +static int set_loopback_config(struct zero_dev *dev) { int result = 0; struct usb_ep *ep; @@ -844,8 +805,7 @@ static void zero_reset_config (struct zero_dev *dev) * code can do, perhaps by disallowing more than one configuration or * by limiting configuration choices (like the pxa2xx). */ -static int -zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags) +static int zero_set_config(struct zero_dev *dev, unsigned number) { int result = 0; struct usb_gadget *gadget = dev->gadget; @@ -855,17 +815,17 @@ zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags) if (gadget_is_sa1100 (gadget) && dev->config) { /* tx fifo is full, but we can't clear it...*/ - INFO (dev, "can't change configurations\n"); + ERROR(dev, "can't change configurations\n"); return -ESPIPE; } zero_reset_config (dev); switch (number) { case CONFIG_SOURCE_SINK: - result = set_source_sink_config (dev, gfp_flags); + result = set_source_sink_config(dev); break; case CONFIG_LOOPBACK: - result = set_loopback_config (dev, gfp_flags); + result = set_loopback_config(dev); break; default: result = -EINVAL; @@ -885,7 +845,7 @@ zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags) case USB_SPEED_LOW: speed = "low"; break; case USB_SPEED_FULL: speed = "full"; break; case USB_SPEED_HIGH: speed = "high"; break; - default: speed = "?"; break; + default: speed = "?"; break; } dev->config = number; @@ -938,19 +898,17 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) value = min (w_length, (u16) sizeof device_desc); memcpy (req->buf, &device_desc, value); break; -#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; value = min (w_length, (u16) sizeof dev_qualifier); memcpy (req->buf, &dev_qualifier, value); break; case USB_DT_OTHER_SPEED_CONFIG: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; // FALLTHROUGH -#endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: value = config_buf (gadget, req->buf, w_value >> 8, @@ -984,7 +942,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) else VDBG (dev, "HNP inactive\n"); spin_lock (&dev->lock); - value = zero_set_config (dev, w_value, GFP_ATOMIC); + value = zero_set_config(dev, w_value); spin_unlock (&dev->lock); break; case USB_REQ_GET_CONFIGURATION: @@ -1013,7 +971,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) * use this "reset the config" shortcut. */ zero_reset_config (dev); - zero_set_config (dev, config, GFP_ATOMIC); + zero_set_config(dev, config); value = 0; } spin_unlock (&dev->lock); @@ -1163,7 +1121,7 @@ autoconf_fail: } EP_IN_NAME = ep->name; ep->driver_data = ep; /* claim */ - + ep = usb_ep_autoconfig (gadget, &fs_sink_desc); if (!ep) goto autoconf_fail; @@ -1207,16 +1165,18 @@ autoconf_fail: device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; -#ifdef CONFIG_USB_GADGET_DUALSPEED - /* assume ep0 uses the same value for both speeds ... */ - dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; + if (gadget_is_dualspeed(gadget)) { + /* assume ep0 uses the same value for both speeds ... */ + dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; - /* and that all endpoints are dual-speed */ - hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; - hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; -#endif + /* and that all endpoints are dual-speed */ + hs_source_desc.bEndpointAddress = + fs_source_desc.bEndpointAddress; + hs_sink_desc.bEndpointAddress = + fs_sink_desc.bEndpointAddress; + } - if (gadget->is_otg) { + if (gadget_is_otg(gadget)) { otg_descriptor.bmAttributes |= USB_OTG_HNP, source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; @@ -1294,23 +1254,18 @@ static struct usb_gadget_driver zero_driver = { .suspend = zero_suspend, .resume = zero_resume, - .driver = { + .driver = { .name = (char *) shortname, .owner = THIS_MODULE, }, }; -MODULE_AUTHOR ("David Brownell"); -MODULE_LICENSE ("Dual BSD/GPL"); +MODULE_AUTHOR("David Brownell"); +MODULE_LICENSE("GPL"); static int __init init (void) { - /* a real value would likely come through some id prom - * or module option. this one takes at least two packets. - */ - strlcpy (serial, "0123456789.0123456789.0123456789", sizeof serial); - return usb_gadget_register_driver (&zero_driver); } module_init (init); diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 565d6ef4c4cf..c978d622fa8a 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -154,6 +154,19 @@ config USB_OHCI_HCD_PCI Enables support for PCI-bus plug-in USB controller cards. If unsure, say Y. +config USB_OHCI_HCD_SSB + bool "OHCI support for Broadcom SSB OHCI core" + depends on USB_OHCI_HCD && SSB && EXPERIMENTAL + default n + ---help--- + Support for the Sonics Silicon Backplane (SSB) attached + Broadcom USB OHCI core. + + This device is present in some embedded devices with + Broadcom based SSB bus. + + If unsure, say N. + config USB_OHCI_BIG_ENDIAN_DESC bool depends on USB_OHCI_HCD diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c index b1d19268cb23..766ef68a0b43 100644 --- a/drivers/usb/host/ehci-au1xxx.c +++ b/drivers/usb/host/ehci-au1xxx.c @@ -220,10 +220,8 @@ static const struct hc_driver ehci_au1xxx_hc_driver = { */ .hub_status_data = ehci_hub_status_data, .hub_control = ehci_hub_control, -#ifdef CONFIG_PM - .hub_suspend = ehci_hub_suspend, - .hub_resume = ehci_hub_resume, -#endif + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 35cdba10411b..c1514442883e 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -570,10 +570,18 @@ static int ehci_run (struct usb_hcd *hcd) * are explicitly handed to companion controller(s), so no TT is * involved with the root hub. (Except where one is integrated, * and there's no companion controller unless maybe for USB OTG.) + * + * Turning on the CF flag will transfer ownership of all ports + * from the companions to the EHCI controller. If any of the + * companions are in the middle of a port reset at the time, it + * could cause trouble. Write-locking ehci_cf_port_reset_rwsem + * guarantees that no resets are in progress. */ + down_write(&ehci_cf_port_reset_rwsem); hcd->state = HC_STATE_RUNNING; ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ + up_write(&ehci_cf_port_reset_rwsem); temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase)); ehci_info (ehci, @@ -719,7 +727,6 @@ dead: */ static int ehci_urb_enqueue ( struct usb_hcd *hcd, - struct usb_host_endpoint *ep, struct urb *urb, gfp_t mem_flags ) { @@ -734,12 +741,12 @@ static int ehci_urb_enqueue ( default: if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags)) return -ENOMEM; - return submit_async (ehci, ep, urb, &qtd_list, mem_flags); + return submit_async(ehci, urb, &qtd_list, mem_flags); case PIPE_INTERRUPT: if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags)) return -ENOMEM; - return intr_submit (ehci, ep, urb, &qtd_list, mem_flags); + return intr_submit(ehci, urb, &qtd_list, mem_flags); case PIPE_ISOCHRONOUS: if (urb->dev->speed == USB_SPEED_HIGH) @@ -777,13 +784,18 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) * completions normally happen asynchronously */ -static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) +static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct ehci_qh *qh; unsigned long flags; + int rc; spin_lock_irqsave (&ehci->lock, flags); + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) + goto done; + switch (usb_pipetype (urb->pipe)) { // case PIPE_CONTROL: // case PIPE_BULK: @@ -838,7 +850,7 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) } done: spin_unlock_irqrestore (&ehci->lock, flags); - return 0; + return rc; } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index a7816e392a85..ad0d4965f2fb 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -58,8 +58,6 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev) if (!retval) ehci_dbg(ehci, "MWI active\n"); - ehci_port_power(ehci, 0); - return 0; } @@ -156,8 +154,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd) break; } - if (ehci_is_TDI(ehci)) - ehci_reset(ehci); + ehci_reset(ehci); /* at least the Genesys GL880S needs fixup here */ temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params); diff --git a/drivers/usb/host/ehci-ppc-soc.c b/drivers/usb/host/ehci-ppc-soc.c index 4f99b0eb27bc..452d4b1bc859 100644 --- a/drivers/usb/host/ehci-ppc-soc.c +++ b/drivers/usb/host/ehci-ppc-soc.c @@ -160,10 +160,8 @@ static const struct hc_driver ehci_ppc_soc_hc_driver = { */ .hub_status_data = ehci_hub_status_data, .hub_control = ehci_hub_control, -#ifdef CONFIG_PM - .hub_suspend = ehci_hub_suspend, - .hub_resume = ehci_hub_resume, -#endif + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, }; static int ehci_hcd_ppc_soc_drv_probe(struct platform_device *pdev) diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c index 829fe649a981..03a6b2f4e6ed 100644 --- a/drivers/usb/host/ehci-ps3.c +++ b/drivers/usb/host/ehci-ps3.c @@ -47,7 +47,7 @@ static int ps3_ehci_hc_reset(struct usb_hcd *hcd) if (result) return result; - ehci_port_power(ehci, 0); + ehci_reset(ehci); return result; } diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 140bfa423e07..b10f39c047e9 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -139,63 +139,65 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh) /*-------------------------------------------------------------------------*/ -static void qtd_copy_status ( +static int qtd_copy_status ( struct ehci_hcd *ehci, struct urb *urb, size_t length, u32 token ) { + int status = -EINPROGRESS; + /* count IN/OUT bytes, not SETUP (even short packets) */ if (likely (QTD_PID (token) != 2)) urb->actual_length += length - QTD_LENGTH (token); /* don't modify error codes */ - if (unlikely (urb->status != -EINPROGRESS)) - return; + if (unlikely(urb->unlinked)) + return status; /* force cleanup after short read; not always an error */ if (unlikely (IS_SHORT_READ (token))) - urb->status = -EREMOTEIO; + status = -EREMOTEIO; /* serious "can't proceed" faults reported by the hardware */ if (token & QTD_STS_HALT) { if (token & QTD_STS_BABBLE) { /* FIXME "must" disable babbling device's port too */ - urb->status = -EOVERFLOW; + status = -EOVERFLOW; } else if (token & QTD_STS_MMF) { /* fs/ls interrupt xfer missed the complete-split */ - urb->status = -EPROTO; + status = -EPROTO; } else if (token & QTD_STS_DBE) { - urb->status = (QTD_PID (token) == 1) /* IN ? */ + status = (QTD_PID (token) == 1) /* IN ? */ ? -ENOSR /* hc couldn't read data */ : -ECOMM; /* hc couldn't write data */ } else if (token & QTD_STS_XACT) { /* timeout, bad crc, wrong PID, etc; retried */ if (QTD_CERR (token)) - urb->status = -EPIPE; + status = -EPIPE; else { ehci_dbg (ehci, "devpath %s ep%d%s 3strikes\n", urb->dev->devpath, usb_pipeendpoint (urb->pipe), usb_pipein (urb->pipe) ? "in" : "out"); - urb->status = -EPROTO; + status = -EPROTO; } /* CERR nonzero + no errors + halt --> stall */ } else if (QTD_CERR (token)) - urb->status = -EPIPE; + status = -EPIPE; else /* unknown */ - urb->status = -EPROTO; + status = -EPROTO; ehci_vdbg (ehci, "dev%d ep%d%s qtd token %08x --> status %d\n", usb_pipedevice (urb->pipe), usb_pipeendpoint (urb->pipe), usb_pipein (urb->pipe) ? "in" : "out", - token, urb->status); + token, status); /* if async CSPLIT failed, try cleaning out the TT buffer */ - if (urb->status != -EPIPE + if (status != -EPIPE && urb->dev->tt && !usb_pipeint (urb->pipe) && ((token & QTD_STS_MMF) != 0 || QTD_CERR(token) == 0) @@ -212,10 +214,12 @@ static void qtd_copy_status ( usb_hub_tt_clear_buffer (urb->dev, urb->pipe); } } + + return status; } static void -ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb) +ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status) __releases(ehci->lock) __acquires(ehci->lock) { @@ -231,25 +235,13 @@ __acquires(ehci->lock) qh_put (qh); } - spin_lock (&urb->lock); - urb->hcpriv = NULL; - switch (urb->status) { - case -EINPROGRESS: /* success */ - urb->status = 0; - default: /* fault */ - COUNT (ehci->stats.complete); - break; - case -EREMOTEIO: /* fault or normal */ - if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) - urb->status = 0; - COUNT (ehci->stats.complete); - break; - case -ECONNRESET: /* canceled */ - case -ENOENT: - COUNT (ehci->stats.unlink); - break; + if (unlikely(urb->unlinked)) { + COUNT(ehci->stats.unlink); + } else { + if (likely(status == -EINPROGRESS)) + status = 0; + COUNT(ehci->stats.complete); } - spin_unlock (&urb->lock); #ifdef EHCI_URB_TRACE ehci_dbg (ehci, @@ -257,13 +249,14 @@ __acquires(ehci->lock) __FUNCTION__, urb->dev->devpath, urb, usb_pipeendpoint (urb->pipe), usb_pipein (urb->pipe) ? "in" : "out", - urb->status, + status, urb->actual_length, urb->transfer_buffer_length); #endif /* complete() can reenter this HCD */ + usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); spin_unlock (&ehci->lock); - usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb); + usb_hcd_giveback_urb(ehci_to_hcd(ehci), urb, status); spin_lock (&ehci->lock); } @@ -283,6 +276,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) { struct ehci_qtd *last = NULL, *end = qh->dummy; struct list_head *entry, *tmp; + int last_status = -EINPROGRESS; int stopped; unsigned count = 0; int do_status = 0; @@ -311,6 +305,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) struct ehci_qtd *qtd; struct urb *urb; u32 token = 0; + int qtd_status; qtd = list_entry (entry, struct ehci_qtd, qtd_list); urb = qtd->urb; @@ -318,11 +313,12 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) /* clean up any state from previous QTD ...*/ if (last) { if (likely (last->urb != urb)) { - ehci_urb_done (ehci, last->urb); + ehci_urb_done(ehci, last->urb, last_status); count++; } ehci_qtd_free (ehci, last); last = NULL; + last_status = -EINPROGRESS; } /* ignore urbs submitted during completions we reported */ @@ -358,13 +354,14 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) stopped = 1; if (unlikely (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))) - urb->status = -ESHUTDOWN; + last_status = -ESHUTDOWN; /* ignore active urbs unless some previous qtd * for the urb faulted (including short read) or * its urb was canceled. we may patch qh or qtds. */ - if (likely (urb->status == -EINPROGRESS)) + if (likely(last_status == -EINPROGRESS && + !urb->unlinked)) continue; /* issue status after short control reads */ @@ -392,11 +389,14 @@ halt: } /* remove it from the queue */ - spin_lock (&urb->lock); - qtd_copy_status (ehci, urb, qtd->length, token); - do_status = (urb->status == -EREMOTEIO) - && usb_pipecontrol (urb->pipe); - spin_unlock (&urb->lock); + qtd_status = qtd_copy_status(ehci, urb, qtd->length, token); + if (unlikely(qtd_status == -EREMOTEIO)) { + do_status = (!urb->unlinked && + usb_pipecontrol(urb->pipe)); + qtd_status = 0; + } + if (likely(last_status == -EINPROGRESS)) + last_status = qtd_status; if (stopped && qtd->qtd_list.prev != &qh->qtd_list) { last = list_entry (qtd->qtd_list.prev, @@ -409,7 +409,7 @@ halt: /* last urb's completion might still need calling */ if (likely (last != NULL)) { - ehci_urb_done (ehci, last->urb); + ehci_urb_done(ehci, last->urb, last_status); count++; ehci_qtd_free (ehci, last); } @@ -913,7 +913,6 @@ static struct ehci_qh *qh_append_tds ( static int submit_async ( struct ehci_hcd *ehci, - struct usb_host_endpoint *ep, struct urb *urb, struct list_head *qtd_list, gfp_t mem_flags @@ -922,10 +921,10 @@ submit_async ( int epnum; unsigned long flags; struct ehci_qh *qh = NULL; - int rc = 0; + int rc; qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list); - epnum = ep->desc.bEndpointAddress; + epnum = urb->ep->desc.bEndpointAddress; #ifdef EHCI_URB_TRACE ehci_dbg (ehci, @@ -933,7 +932,7 @@ submit_async ( __FUNCTION__, urb->dev->devpath, urb, epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out", urb->transfer_buffer_length, - qtd, ep->hcpriv); + qtd, urb->ep->hcpriv); #endif spin_lock_irqsave (&ehci->lock, flags); @@ -942,9 +941,13 @@ submit_async ( rc = -ESHUTDOWN; goto done; } + rc = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb); + if (unlikely(rc)) + goto done; - qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv); + qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv); if (unlikely(qh == NULL)) { + usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); rc = -ENOMEM; goto done; } diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index e682f2342ef8..80d99bce2b38 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -797,7 +797,6 @@ done: static int intr_submit ( struct ehci_hcd *ehci, - struct usb_host_endpoint *ep, struct urb *urb, struct list_head *qtd_list, gfp_t mem_flags @@ -805,23 +804,26 @@ static int intr_submit ( unsigned epnum; unsigned long flags; struct ehci_qh *qh; - int status = 0; + int status; struct list_head empty; /* get endpoint and transfer/schedule data */ - epnum = ep->desc.bEndpointAddress; + epnum = urb->ep->desc.bEndpointAddress; spin_lock_irqsave (&ehci->lock, flags); if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &ehci_to_hcd(ehci)->flags))) { status = -ESHUTDOWN; - goto done; + goto done_not_linked; } + status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb); + if (unlikely(status)) + goto done_not_linked; /* get qh and force any scheduling errors */ INIT_LIST_HEAD (&empty); - qh = qh_append_tds (ehci, urb, &empty, epnum, &ep->hcpriv); + qh = qh_append_tds(ehci, urb, &empty, epnum, &urb->ep->hcpriv); if (qh == NULL) { status = -ENOMEM; goto done; @@ -832,13 +834,16 @@ static int intr_submit ( } /* then queue the urb's tds to the qh */ - qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv); + qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv); BUG_ON (qh == NULL); /* ... update usbfs periodic stats */ ehci_to_hcd(ehci)->self.bandwidth_int_reqs++; done: + if (unlikely(status)) + usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); +done_not_linked: spin_unlock_irqrestore (&ehci->lock, flags); if (status) qtd_list_free (ehci, urb, qtd_list); @@ -1622,7 +1627,7 @@ itd_complete ( /* give urb back to the driver ... can be out-of-order */ dev = urb->dev; - ehci_urb_done (ehci, urb); + ehci_urb_done(ehci, urb, 0); urb = NULL; /* defer stopping schedule; completion can submit */ @@ -1686,12 +1691,19 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, /* schedule ... need to lock */ spin_lock_irqsave (&ehci->lock, flags); if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, - &ehci_to_hcd(ehci)->flags))) + &ehci_to_hcd(ehci)->flags))) { status = -ESHUTDOWN; - else - status = iso_stream_schedule (ehci, urb, stream); + goto done_not_linked; + } + status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb); + if (unlikely(status)) + goto done_not_linked; + status = iso_stream_schedule(ehci, urb, stream); if (likely (status == 0)) itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); + else + usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); +done_not_linked: spin_unlock_irqrestore (&ehci->lock, flags); done: @@ -1988,7 +2000,7 @@ sitd_complete ( /* give urb back to the driver */ dev = urb->dev; - ehci_urb_done (ehci, urb); + ehci_urb_done(ehci, urb, 0); urb = NULL; /* defer stopping schedule; completion can submit */ @@ -2049,12 +2061,19 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, /* schedule ... need to lock */ spin_lock_irqsave (&ehci->lock, flags); if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, - &ehci_to_hcd(ehci)->flags))) + &ehci_to_hcd(ehci)->flags))) { status = -ESHUTDOWN; - else - status = iso_stream_schedule (ehci, urb, stream); + goto done_not_linked; + } + status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb); + if (unlikely(status)) + goto done_not_linked; + status = iso_stream_schedule(ehci, urb, stream); if (status == 0) sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); + else + usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); +done_not_linked: spin_unlock_irqrestore (&ehci->lock, flags); done: diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 5c851a36de72..c27417f5b9d8 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -277,12 +277,11 @@ static void preproc_atl_queue(struct isp116x *isp116x) processed urbs. */ static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep, - struct urb *urb) + struct urb *urb, int status) __releases(isp116x->lock) __acquires(isp116x->lock) { unsigned i; - urb->hcpriv = NULL; ep->error_count = 0; if (usb_pipecontrol(urb->pipe)) @@ -290,8 +289,9 @@ __releases(isp116x->lock) __acquires(isp116x->lock) urb_dbg(urb, "Finish"); + usb_hcd_unlink_urb_from_ep(isp116x_to_hcd(isp116x), urb); spin_unlock(&isp116x->lock); - usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb); + usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb, status); spin_lock(&isp116x->lock); /* take idle endpoints out of the schedule */ @@ -445,12 +445,7 @@ static void postproc_atl_queue(struct isp116x *isp116x) if (PTD_GET_ACTIVE(ptd) || (cc != TD_CC_NOERROR && cc < 0x0E)) break; - if ((urb->transfer_flags & URB_SHORT_NOT_OK) && - urb->actual_length < - urb->transfer_buffer_length) - status = -EREMOTEIO; - else - status = 0; + status = 0; ep->nextpid = 0; break; default: @@ -458,14 +453,8 @@ static void postproc_atl_queue(struct isp116x *isp116x) } done: - if (status != -EINPROGRESS) { - spin_lock(&urb->lock); - if (urb->status == -EINPROGRESS) - urb->status = status; - spin_unlock(&urb->lock); - } - if (urb->status != -EINPROGRESS) - finish_request(isp116x, ep, urb); + if (status != -EINPROGRESS || urb->unlinked) + finish_request(isp116x, ep, urb, status); } } @@ -673,7 +662,7 @@ static int balance(struct isp116x *isp116x, u16 period, u16 load) /*-----------------------------------------------------------------*/ static int isp116x_urb_enqueue(struct usb_hcd *hcd, - struct usb_host_endpoint *hep, struct urb *urb, + struct urb *urb, gfp_t mem_flags) { struct isp116x *isp116x = hcd_to_isp116x(hcd); @@ -682,6 +671,7 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, int is_out = !usb_pipein(pipe); int type = usb_pipetype(pipe); int epnum = usb_pipeendpoint(pipe); + struct usb_host_endpoint *hep = urb->ep; struct isp116x_ep *ep = NULL; unsigned long flags; int i; @@ -705,7 +695,12 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, if (!HC_IS_RUNNING(hcd->state)) { kfree(ep); ret = -ENODEV; - goto fail; + goto fail_not_linked; + } + ret = usb_hcd_link_urb_to_ep(hcd, urb); + if (ret) { + kfree(ep); + goto fail_not_linked; } if (hep->hcpriv) @@ -808,16 +803,13 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, } } - /* in case of unlink-during-submit */ - if (urb->status != -EINPROGRESS) { - finish_request(isp116x, ep, urb); - ret = 0; - goto fail; - } urb->hcpriv = hep; start_atl_transfers(isp116x); fail: + if (ret) + usb_hcd_unlink_urb_from_ep(hcd, urb); + fail_not_linked: spin_unlock_irqrestore(&isp116x->lock, flags); return ret; } @@ -825,20 +817,21 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, /* Dequeue URBs. */ -static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, + int status) { struct isp116x *isp116x = hcd_to_isp116x(hcd); struct usb_host_endpoint *hep; struct isp116x_ep *ep, *ep_act; unsigned long flags; + int rc; spin_lock_irqsave(&isp116x->lock, flags); + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) + goto done; + hep = urb->hcpriv; - /* URB already unlinked (or never linked)? */ - if (!hep) { - spin_unlock_irqrestore(&isp116x->lock, flags); - return 0; - } ep = hep->hcpriv; WARN_ON(hep != ep->hep); @@ -855,10 +848,10 @@ static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) } if (urb) - finish_request(isp116x, ep, urb); - + finish_request(isp116x, ep, urb, status); + done: spin_unlock_irqrestore(&isp116x->lock, flags); - return 0; + return rc; } static void isp116x_endpoint_disable(struct usb_hcd *hcd, diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c index f61c6cdd06f2..ebab5ce8f5ce 100644 --- a/drivers/usb/host/ohci-dbg.c +++ b/drivers/usb/host/ohci-dbg.c @@ -24,7 +24,7 @@ * small: 0) header + data packets 1) just header */ static void __maybe_unused -urb_print (struct urb * urb, char * str, int small) +urb_print(struct urb * urb, char * str, int small, int status) { unsigned int pipe= urb->pipe; @@ -34,7 +34,7 @@ urb_print (struct urb * urb, char * str, int small) } #ifndef OHCI_VERBOSE_DEBUG - if (urb->status != 0) + if (status != 0) #endif dbg("%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d", str, @@ -46,7 +46,7 @@ urb_print (struct urb * urb, char * str, int small) urb->transfer_flags, urb->actual_length, urb->transfer_buffer_length, - urb->status); + status); #ifdef OHCI_VERBOSE_DEBUG if (!small) { @@ -66,7 +66,7 @@ urb_print (struct urb * urb, char * str, int small) urb->transfer_buffer_length: urb->actual_length; for (i = 0; i < 16 && i < len; i++) printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]); - printk ("%s stat:%d\n", i < len? "...": "", urb->status); + printk ("%s stat:%d\n", i < len? "...": "", status); } } #endif diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 6edf4097d2d2..240c7f507541 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -81,7 +81,6 @@ static void ohci_dump (struct ohci_hcd *ohci, int verbose); static int ohci_init (struct ohci_hcd *ohci); static void ohci_stop (struct usb_hcd *hcd); static int ohci_restart (struct ohci_hcd *ohci); -static void ohci_quirk_nec_worker (struct work_struct *work); #include "ohci-hub.c" #include "ohci-dbg.c" @@ -118,7 +117,6 @@ MODULE_PARM_DESC (no_handshake, "true (not default) disables BIOS handshake"); */ static int ohci_urb_enqueue ( struct usb_hcd *hcd, - struct usb_host_endpoint *ep, struct urb *urb, gfp_t mem_flags ) { @@ -131,11 +129,11 @@ static int ohci_urb_enqueue ( int retval = 0; #ifdef OHCI_VERBOSE_DEBUG - urb_print (urb, "SUB", usb_pipein (pipe)); + urb_print(urb, "SUB", usb_pipein(pipe), -EINPROGRESS); #endif /* every endpoint has a ed, locate and maybe (re)initialize it */ - if (! (ed = ed_get (ohci, ep, urb->dev, pipe, urb->interval))) + if (! (ed = ed_get (ohci, urb->ep, urb->dev, pipe, urb->interval))) return -ENOMEM; /* for the private part of the URB we need the number of TDs (size) */ @@ -200,22 +198,17 @@ static int ohci_urb_enqueue ( retval = -ENODEV; goto fail; } - - /* in case of unlink-during-submit */ - spin_lock (&urb->lock); - if (urb->status != -EINPROGRESS) { - spin_unlock (&urb->lock); - urb->hcpriv = urb_priv; - finish_urb (ohci, urb); - retval = 0; + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval) goto fail; - } /* schedule the ed if needed */ if (ed->state == ED_IDLE) { retval = ed_schedule (ohci, ed); - if (retval < 0) - goto fail0; + if (retval < 0) { + usb_hcd_unlink_urb_from_ep(hcd, urb); + goto fail; + } if (ed->type == PIPE_ISOCHRONOUS) { u16 frame = ohci_frame_no(ohci); @@ -239,8 +232,6 @@ static int ohci_urb_enqueue ( urb->hcpriv = urb_priv; td_submit_urb (ohci, urb); -fail0: - spin_unlock (&urb->lock); fail: if (retval) urb_free_priv (ohci, urb_priv); @@ -249,22 +240,26 @@ fail: } /* - * decouple the URB from the HC queues (TDs, urb_priv); it's - * already marked using urb->status. reporting is always done + * decouple the URB from the HC queues (TDs, urb_priv). + * reporting is always done * asynchronously, and we might be dealing with an urb that's * partially transferred, or an ED with other urbs being unlinked. */ -static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) +static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); unsigned long flags; + int rc; #ifdef OHCI_VERBOSE_DEBUG - urb_print (urb, "UNLINK", 1); + urb_print(urb, "UNLINK", 1, status); #endif spin_lock_irqsave (&ohci->lock, flags); - if (HC_IS_RUNNING(hcd->state)) { + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) { + ; /* Do nothing */ + } else if (HC_IS_RUNNING(hcd->state)) { urb_priv_t *urb_priv; /* Unless an IRQ completed the unlink while it was being @@ -282,10 +277,10 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) * any more ... just clean up every urb's memory. */ if (urb->hcpriv) - finish_urb (ohci, urb); + finish_urb(ohci, urb, status); } spin_unlock_irqrestore (&ohci->lock, flags); - return 0; + return rc; } /*-------------------------------------------------------------------------*/ @@ -314,6 +309,8 @@ rescan: if (!HC_IS_RUNNING (hcd->state)) { sanitize: ed->state = ED_IDLE; + if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT) + ohci->eds_scheduled--; finish_unlinks (ohci, 0); } @@ -321,7 +318,12 @@ sanitize: case ED_UNLINK: /* wait for hw to finish? */ /* major IRQ delivery trouble loses INTR_SF too... */ if (limit-- == 0) { - ohci_warn (ohci, "IRQ INTR_SF lossage\n"); + ohci_warn(ohci, "ED unlink timeout\n"); + if (quirk_zfmicro(ohci)) { + ohci_warn(ohci, "Attempting ZF TD recovery\n"); + ohci->ed_to_check = ed; + ohci->zf_delay = 2; + } goto sanitize; } spin_unlock_irqrestore (&ohci->lock, flags); @@ -379,6 +381,93 @@ ohci_shutdown (struct usb_hcd *hcd) (void) ohci_readl (ohci, &ohci->regs->control); } +static int check_ed(struct ohci_hcd *ohci, struct ed *ed) +{ + return (hc32_to_cpu(ohci, ed->hwINFO) & ED_IN) != 0 + && (hc32_to_cpu(ohci, ed->hwHeadP) & TD_MASK) + == (hc32_to_cpu(ohci, ed->hwTailP) & TD_MASK) + && !list_empty(&ed->td_list); +} + +/* ZF Micro watchdog timer callback. The ZF Micro chipset sometimes completes + * an interrupt TD but neglects to add it to the donelist. On systems with + * this chipset, we need to periodically check the state of the queues to look + * for such "lost" TDs. + */ +static void unlink_watchdog_func(unsigned long _ohci) +{ + long flags; + unsigned max; + unsigned seen_count = 0; + unsigned i; + struct ed **seen = NULL; + struct ohci_hcd *ohci = (struct ohci_hcd *) _ohci; + + spin_lock_irqsave(&ohci->lock, flags); + max = ohci->eds_scheduled; + if (!max) + goto done; + + if (ohci->ed_to_check) + goto out; + + seen = kcalloc(max, sizeof *seen, GFP_ATOMIC); + if (!seen) + goto out; + + for (i = 0; i < NUM_INTS; i++) { + struct ed *ed = ohci->periodic[i]; + + while (ed) { + unsigned temp; + + /* scan this branch of the periodic schedule tree */ + for (temp = 0; temp < seen_count; temp++) { + if (seen[temp] == ed) { + /* we've checked it and what's after */ + ed = NULL; + break; + } + } + if (!ed) + break; + seen[seen_count++] = ed; + if (!check_ed(ohci, ed)) { + ed = ed->ed_next; + continue; + } + + /* HC's TD list is empty, but HCD sees at least one + * TD that's not been sent through the donelist. + */ + ohci->ed_to_check = ed; + ohci->zf_delay = 2; + + /* The HC may wait until the next frame to report the + * TD as done through the donelist and INTR_WDH. (We + * just *assume* it's not a multi-TD interrupt URB; + * those could defer the IRQ more than one frame, using + * DI...) Check again after the next INTR_SF. + */ + ohci_writel(ohci, OHCI_INTR_SF, + &ohci->regs->intrstatus); + ohci_writel(ohci, OHCI_INTR_SF, + &ohci->regs->intrenable); + + /* flush those writes */ + (void) ohci_readl(ohci, &ohci->regs->control); + + goto out; + } + } +out: + kfree(seen); + if (ohci->eds_scheduled) + mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ)); +done: + spin_unlock_irqrestore(&ohci->lock, flags); +} + /*-------------------------------------------------------------------------* * HC functions *-------------------------------------------------------------------------*/ @@ -616,6 +705,15 @@ retry: mdelay ((temp >> 23) & 0x1fe); hcd->state = HC_STATE_RUNNING; + if (quirk_zfmicro(ohci)) { + /* Create timer to watch for bad queue state on ZF Micro */ + setup_timer(&ohci->unlink_watchdog, unlink_watchdog_func, + (unsigned long) ohci); + + ohci->eds_scheduled = 0; + ohci->ed_to_check = NULL; + } + ohci_dump (ohci, 1); return 0; @@ -629,10 +727,11 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ohci_regs __iomem *regs = ohci->regs; - int ints; + int ints; /* we can eliminate a (slow) ohci_readl() - if _only_ WDH caused this irq */ + * if _only_ WDH caused this irq + */ if ((ohci->hcca->done_head != 0) && ! (hc32_to_cpup (ohci, &ohci->hcca->done_head) & 0x01)) { @@ -651,7 +750,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) if (ints & OHCI_INTR_UE) { // e.g. due to PCI Master/Target Abort - if (ohci->flags & OHCI_QUIRK_NEC) { + if (quirk_nec(ohci)) { /* Workaround for a silicon bug in some NEC chips used * in Apple's PowerBooks. Adapted from Darwin code. */ @@ -713,6 +812,31 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrenable); } + if (quirk_zfmicro(ohci) && (ints & OHCI_INTR_SF)) { + spin_lock(&ohci->lock); + if (ohci->ed_to_check) { + struct ed *ed = ohci->ed_to_check; + + if (check_ed(ohci, ed)) { + /* HC thinks the TD list is empty; HCD knows + * at least one TD is outstanding + */ + if (--ohci->zf_delay == 0) { + struct td *td = list_entry( + ed->td_list.next, + struct td, td_list); + ohci_warn(ohci, + "Reclaiming orphan TD %p\n", + td); + takeback_td(ohci, td); + ohci->ed_to_check = NULL; + } + } else + ohci->ed_to_check = NULL; + } + spin_unlock(&ohci->lock); + } + /* could track INTR_SO to reduce available PCI/... bandwidth */ /* handle any pending URB/ED unlinks, leaving INTR_SF enabled @@ -721,7 +845,9 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) spin_lock (&ohci->lock); if (ohci->ed_rm_list) finish_unlinks (ohci, ohci_frame_no(ohci)); - if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list + if ((ints & OHCI_INTR_SF) != 0 + && !ohci->ed_rm_list + && !ohci->ed_to_check && HC_IS_RUNNING(hcd->state)) ohci_writel (ohci, OHCI_INTR_SF, ®s->intrdisable); spin_unlock (&ohci->lock); @@ -751,6 +877,9 @@ static void ohci_stop (struct usb_hcd *hcd) free_irq(hcd->irq, hcd); hcd->irq = -1; + if (quirk_zfmicro(ohci)) + del_timer(&ohci->unlink_watchdog); + remove_debug_files (ohci); ohci_mem_cleanup (ohci); if (ohci->hcca) { @@ -798,9 +927,8 @@ static int ohci_restart (struct ohci_hcd *ohci) ed, ed->state); } - spin_lock (&urb->lock); - urb->status = -ESHUTDOWN; - spin_unlock (&urb->lock); + if (!urb->unlinked) + urb->unlinked = -ESHUTDOWN; } finish_unlinks (ohci, 0); spin_unlock_irq(&ohci->lock); @@ -828,27 +956,6 @@ static int ohci_restart (struct ohci_hcd *ohci) /*-------------------------------------------------------------------------*/ -/* NEC workaround */ -static void ohci_quirk_nec_worker(struct work_struct *work) -{ - struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work); - int status; - - status = ohci_init(ohci); - if (status != 0) { - ohci_err(ohci, "Restarting NEC controller failed " - "in ohci_init, %d\n", status); - return; - } - - status = ohci_restart(ohci); - if (status != 0) - ohci_err(ohci, "Restarting NEC controller failed " - "in ohci_restart, %d\n", status); -} - -/*-------------------------------------------------------------------------*/ - #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC MODULE_AUTHOR (DRIVER_AUTHOR); @@ -926,11 +1033,17 @@ MODULE_LICENSE ("GPL"); #define PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver #endif +#ifdef CONFIG_USB_OHCI_HCD_SSB +#include "ohci-ssb.c" +#define SSB_OHCI_DRIVER ssb_ohci_driver +#endif + #if !defined(PCI_DRIVER) && \ !defined(PLATFORM_DRIVER) && \ !defined(OF_PLATFORM_DRIVER) && \ !defined(SA1111_DRIVER) && \ - !defined(PS3_SYSTEM_BUS_DRIVER) + !defined(PS3_SYSTEM_BUS_DRIVER) && \ + !defined(SSB_OHCI_DRIVER) #error "missing bus glue for ohci-hcd" #endif @@ -975,10 +1088,20 @@ static int __init ohci_hcd_mod_init(void) goto error_pci; #endif +#ifdef SSB_OHCI_DRIVER + retval = ssb_driver_register(&SSB_OHCI_DRIVER); + if (retval) + goto error_ssb; +#endif + return retval; /* Error path */ +#ifdef SSB_OHCI_DRIVER + error_ssb: +#endif #ifdef PCI_DRIVER + pci_unregister_driver(&PCI_DRIVER); error_pci: #endif #ifdef SA1111_DRIVER @@ -1003,6 +1126,9 @@ module_init(ohci_hcd_mod_init); static void __exit ohci_hcd_mod_exit(void) { +#ifdef SSB_OHCI_DRIVER + ssb_driver_unregister(&SSB_OHCI_DRIVER); +#endif #ifdef PCI_DRIVER pci_unregister_driver(&PCI_DRIVER); #endif diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c index 450c7b460c5a..2f20d3dc895b 100644 --- a/drivers/usb/host/ohci-mem.c +++ b/drivers/usb/host/ohci-mem.c @@ -28,7 +28,6 @@ static void ohci_hcd_init (struct ohci_hcd *ohci) ohci->next_statechange = jiffies; spin_lock_init (&ohci->lock); INIT_LIST_HEAD (&ohci->pending); - INIT_WORK (&ohci->nec_work, ohci_quirk_nec_worker); } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index a5e2eb85d073..d0360f65ebd9 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -84,7 +84,7 @@ static int ohci_quirk_zfmicro(struct usb_hcd *hcd) struct ohci_hcd *ohci = hcd_to_ohci (hcd); ohci->flags |= OHCI_QUIRK_ZFMICRO; - ohci_dbg (ohci, "enabled Compaq ZFMicro chipset quirk\n"); + ohci_dbg(ohci, "enabled Compaq ZFMicro chipset quirks\n"); return 0; } @@ -113,11 +113,31 @@ static int ohci_quirk_toshiba_scc(struct usb_hcd *hcd) /* Check for NEC chip and apply quirk for allegedly lost interrupts. */ + +static void ohci_quirk_nec_worker(struct work_struct *work) +{ + struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work); + int status; + + status = ohci_init(ohci); + if (status != 0) { + ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n", + "ohci_init", status); + return; + } + + status = ohci_restart(ohci); + if (status != 0) + ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n", + "ohci_restart", status); +} + static int ohci_quirk_nec(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); ohci->flags |= OHCI_QUIRK_NEC; + INIT_WORK(&ohci->nec_work, ohci_quirk_nec_worker); ohci_dbg (ohci, "enabled NEC chipset lost interrupt quirk\n"); return 0; diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c index c43b66acd4d5..0a7426920150 100644 --- a/drivers/usb/host/ohci-ppc-of.c +++ b/drivers/usb/host/ohci-ppc-of.c @@ -134,8 +134,11 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match) } ohci = hcd_to_ohci(hcd); - if (is_bigendian) + if (is_bigendian) { ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC; + if (of_device_is_compatible(dn, "mpc5200-ohci")) + ohci->flags |= OHCI_QUIRK_FRAME_NO; + } ohci_hcd_init(ohci); diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c index 1a2e1777ca61..f95be1896b0d 100644 --- a/drivers/usb/host/ohci-ppc-soc.c +++ b/drivers/usb/host/ohci-ppc-soc.c @@ -73,6 +73,11 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver, ohci = hcd_to_ohci(hcd); ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC; + +#ifdef CONFIG_PPC_MPC52xx + /* MPC52xx doesn't need frame_no shift */ + ohci->flags |= OHCI_QUIRK_FRAME_NO; +#endif ohci_hcd_init(ohci); retval = usb_add_hcd(hcd, irq, IRQF_DISABLED); diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 830a3fe8615e..51817322232b 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -36,29 +36,15 @@ static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv) * PRECONDITION: ohci lock held, irqs blocked. */ static void -finish_urb (struct ohci_hcd *ohci, struct urb *urb) +finish_urb(struct ohci_hcd *ohci, struct urb *urb, int status) __releases(ohci->lock) __acquires(ohci->lock) { // ASSERT (urb->hcpriv != 0); urb_free_priv (ohci, urb->hcpriv); - urb->hcpriv = NULL; - - spin_lock (&urb->lock); - if (likely (urb->status == -EINPROGRESS)) - urb->status = 0; - /* report short control reads right even though the data TD always - * has TD_R set. (much simpler, but creates the 1-td limit.) - */ - if (unlikely (urb->transfer_flags & URB_SHORT_NOT_OK) - && unlikely (usb_pipecontrol (urb->pipe)) - && urb->actual_length < urb->transfer_buffer_length - && usb_pipein (urb->pipe) - && urb->status == 0) { - urb->status = -EREMOTEIO; - } - spin_unlock (&urb->lock); + if (likely(status == -EINPROGRESS)) + status = 0; switch (usb_pipetype (urb->pipe)) { case PIPE_ISOCHRONOUS: @@ -70,12 +56,13 @@ __acquires(ohci->lock) } #ifdef OHCI_VERBOSE_DEBUG - urb_print (urb, "RET", usb_pipeout (urb->pipe)); + urb_print(urb, "RET", usb_pipeout (urb->pipe), status); #endif /* urb->complete() can reenter this HCD */ + usb_hcd_unlink_urb_from_ep(ohci_to_hcd(ohci), urb); spin_unlock (&ohci->lock); - usb_hcd_giveback_urb (ohci_to_hcd(ohci), urb); + usb_hcd_giveback_urb(ohci_to_hcd(ohci), urb, status); spin_lock (&ohci->lock); /* stop periodic dma if it's not needed */ @@ -179,6 +166,10 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed) ed->ed_prev = NULL; ed->ed_next = NULL; ed->hwNextED = 0; + if (quirk_zfmicro(ohci) + && (ed->type == PIPE_INTERRUPT) + && !(ohci->eds_scheduled++)) + mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ)); wmb (); /* we care about rm_list when setting CLE/BLE in case the HC was at @@ -708,19 +699,18 @@ static void td_submit_urb ( * Done List handling functions *-------------------------------------------------------------------------*/ -/* calculate transfer length/status and update the urb - * PRECONDITION: irqsafe (only for urb->status locking) - */ -static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) +/* calculate transfer length/status and update the urb */ +static int td_done(struct ohci_hcd *ohci, struct urb *urb, struct td *td) { u32 tdINFO = hc32_to_cpup (ohci, &td->hwINFO); int cc = 0; + int status = -EINPROGRESS; list_del (&td->td_list); /* ISO ... drivers see per-TD length/status */ if (tdINFO & TD_ISO) { - u16 tdPSW = ohci_hwPSW (ohci, td, 0); + u16 tdPSW = ohci_hwPSW(ohci, td, 0); int dlen = 0; /* NOTE: assumes FC in tdINFO == 0, and that @@ -729,7 +719,7 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) cc = (tdPSW >> 12) & 0xF; if (tdINFO & TD_CC) /* hc didn't touch? */ - return; + return status; if (usb_pipeout (urb->pipe)) dlen = urb->iso_frame_desc [td->index].length; @@ -762,12 +752,8 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) if (cc == TD_DATAUNDERRUN && !(urb->transfer_flags & URB_SHORT_NOT_OK)) cc = TD_CC_NOERROR; - if (cc != TD_CC_NOERROR && cc < 0x0E) { - spin_lock (&urb->lock); - if (urb->status == -EINPROGRESS) - urb->status = cc_to_error [cc]; - spin_unlock (&urb->lock); - } + if (cc != TD_CC_NOERROR && cc < 0x0E) + status = cc_to_error[cc]; /* count all non-empty packets except control SETUP packet */ if ((type != PIPE_CONTROL || td->index != 0) && tdBE != 0) { @@ -786,14 +772,15 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) urb->actual_length, urb->transfer_buffer_length); } + return status; } /*-------------------------------------------------------------------------*/ -static inline struct td * -ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) +static void ed_halted(struct ohci_hcd *ohci, struct td *td, int cc) { struct urb *urb = td->urb; + urb_priv_t *urb_priv = urb->hcpriv; struct ed *ed = td->ed; struct list_head *tmp = td->td_list.next; __hc32 toggle = ed->hwHeadP & cpu_to_hc32 (ohci, ED_C); @@ -805,13 +792,12 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) wmb (); ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_H); - /* put any later tds from this urb onto the donelist, after 'td', - * order won't matter here: no errors, and nothing was transferred. - * also patch the ed so it looks as if those tds completed normally. + /* Get rid of all later tds from this urb. We don't have + * to be careful: no errors and nothing was transferred. + * Also patch the ed so it looks as if those tds completed normally. */ while (tmp != &ed->td_list) { struct td *next; - __hc32 info; next = list_entry (tmp, struct td, td_list); tmp = next->td_list.next; @@ -826,14 +812,9 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) * then we need to leave the control STATUS packet queued * and clear ED_SKIP. */ - info = next->hwINFO; - info |= cpu_to_hc32 (ohci, TD_DONE); - info &= ~cpu_to_hc32 (ohci, TD_CC); - next->hwINFO = info; - - next->next_dl_td = rev; - rev = next; + list_del(&next->td_list); + urb_priv->td_cnt++; ed->hwHeadP = next->hwNextTD | toggle; } @@ -859,8 +840,6 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) hc32_to_cpu (ohci, td->hwINFO), cc, cc_to_error [cc]); } - - return rev; } /* replies to the request have to be on a FIFO basis so @@ -897,7 +876,7 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci) */ if (cc != TD_CC_NOERROR && (td->ed->hwHeadP & cpu_to_hc32 (ohci, ED_H))) - td_rev = ed_halted (ohci, td, cc, td_rev); + ed_halted(ohci, td, cc); td->next_dl_td = td_rev; td_rev = td; @@ -940,8 +919,12 @@ skip_ed: TD_MASK; /* INTR_WDH may need to clean up first */ - if (td->td_dma != head) - goto skip_ed; + if (td->td_dma != head) { + if (ed == ohci->ed_to_check) + ohci->ed_to_check = NULL; + else + goto skip_ed; + } } } @@ -974,7 +957,7 @@ rescan_this: urb = td->urb; urb_priv = td->urb->hcpriv; - if (urb->status == -EINPROGRESS) { + if (!urb->unlinked) { prev = &td->hwNextTD; continue; } @@ -990,7 +973,7 @@ rescan_this: /* if URB is done, clean up */ if (urb_priv->td_cnt == urb_priv->length) { modified = completed = 1; - finish_urb (ohci, urb); + finish_urb(ohci, urb, 0); } } if (completed && !list_empty (&ed->td_list)) @@ -998,6 +981,8 @@ rescan_this: /* ED's now officially unlinked, hc doesn't see */ ed->state = ED_IDLE; + if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT) + ohci->eds_scheduled--; ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H); ed->hwNextED = 0; wmb (); @@ -1021,7 +1006,7 @@ rescan_this: if (ohci->ed_controltail) { command |= OHCI_CLF; - if (ohci->flags & OHCI_QUIRK_ZFMICRO) + if (quirk_zfmicro(ohci)) mdelay(1); if (!(ohci->hc_control & OHCI_CTRL_CLE)) { control |= OHCI_CTRL_CLE; @@ -1031,7 +1016,7 @@ rescan_this: } if (ohci->ed_bulktail) { command |= OHCI_BLF; - if (ohci->flags & OHCI_QUIRK_ZFMICRO) + if (quirk_zfmicro(ohci)) mdelay(1); if (!(ohci->hc_control & OHCI_CTRL_BLE)) { control |= OHCI_CTRL_BLE; @@ -1043,13 +1028,13 @@ rescan_this: /* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */ if (control) { ohci->hc_control |= control; - if (ohci->flags & OHCI_QUIRK_ZFMICRO) + if (quirk_zfmicro(ohci)) mdelay(1); ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); } if (command) { - if (ohci->flags & OHCI_QUIRK_ZFMICRO) + if (quirk_zfmicro(ohci)) mdelay(1); ohci_writel (ohci, command, &ohci->regs->cmdstatus); } @@ -1061,11 +1046,60 @@ rescan_this: /*-------------------------------------------------------------------------*/ /* + * Used to take back a TD from the host controller. This would normally be + * called from within dl_done_list, however it may be called directly if the + * HC no longer sees the TD and it has not appeared on the donelist (after + * two frames). This bug has been observed on ZF Micro systems. + */ +static void takeback_td(struct ohci_hcd *ohci, struct td *td) +{ + struct urb *urb = td->urb; + urb_priv_t *urb_priv = urb->hcpriv; + struct ed *ed = td->ed; + int status; + + /* update URB's length and status from TD */ + status = td_done(ohci, urb, td); + urb_priv->td_cnt++; + + /* If all this urb's TDs are done, call complete() */ + if (urb_priv->td_cnt == urb_priv->length) + finish_urb(ohci, urb, status); + + /* clean schedule: unlink EDs that are no longer busy */ + if (list_empty(&ed->td_list)) { + if (ed->state == ED_OPER) + start_ed_unlink(ohci, ed); + + /* ... reenabling halted EDs only after fault cleanup */ + } else if ((ed->hwINFO & cpu_to_hc32(ohci, ED_SKIP | ED_DEQUEUE)) + == cpu_to_hc32(ohci, ED_SKIP)) { + td = list_entry(ed->td_list.next, struct td, td_list); + if (!(td->hwINFO & cpu_to_hc32(ohci, TD_DONE))) { + ed->hwINFO &= ~cpu_to_hc32(ohci, ED_SKIP); + /* ... hc may need waking-up */ + switch (ed->type) { + case PIPE_CONTROL: + ohci_writel(ohci, OHCI_CLF, + &ohci->regs->cmdstatus); + break; + case PIPE_BULK: + ohci_writel(ohci, OHCI_BLF, + &ohci->regs->cmdstatus); + break; + } + } + } +} + +/* * Process normal completions (error or success) and clean the schedules. * * This is the main path for handing urbs back to drivers. The only other - * path is finish_unlinks(), which unlinks URBs using ed_rm_list, instead of - * scanning the (re-reversed) donelist as this does. + * normal path is finish_unlinks(), which unlinks URBs using ed_rm_list, + * instead of scanning the (re-reversed) donelist as this does. There's + * an abnormal path too, handling a quirk in some Compaq silicon: URBs + * with TDs that appear to be orphaned are directly reclaimed. */ static void dl_done_list (struct ohci_hcd *ohci) @@ -1074,44 +1108,7 @@ dl_done_list (struct ohci_hcd *ohci) while (td) { struct td *td_next = td->next_dl_td; - struct urb *urb = td->urb; - urb_priv_t *urb_priv = urb->hcpriv; - struct ed *ed = td->ed; - - /* update URB's length and status from TD */ - td_done (ohci, urb, td); - urb_priv->td_cnt++; - - /* If all this urb's TDs are done, call complete() */ - if (urb_priv->td_cnt == urb_priv->length) - finish_urb (ohci, urb); - - /* clean schedule: unlink EDs that are no longer busy */ - if (list_empty (&ed->td_list)) { - if (ed->state == ED_OPER) - start_ed_unlink (ohci, ed); - - /* ... reenabling halted EDs only after fault cleanup */ - } else if ((ed->hwINFO & cpu_to_hc32 (ohci, - ED_SKIP | ED_DEQUEUE)) - == cpu_to_hc32 (ohci, ED_SKIP)) { - td = list_entry (ed->td_list.next, struct td, td_list); - if (!(td->hwINFO & cpu_to_hc32 (ohci, TD_DONE))) { - ed->hwINFO &= ~cpu_to_hc32 (ohci, ED_SKIP); - /* ... hc may need waking-up */ - switch (ed->type) { - case PIPE_CONTROL: - ohci_writel (ohci, OHCI_CLF, - &ohci->regs->cmdstatus); - break; - case PIPE_BULK: - ohci_writel (ohci, OHCI_BLF, - &ohci->regs->cmdstatus); - break; - } - } - } - + takeback_td(ohci, td); td = td_next; } } diff --git a/drivers/usb/host/ohci-ssb.c b/drivers/usb/host/ohci-ssb.c new file mode 100644 index 000000000000..fe70e72340de --- /dev/null +++ b/drivers/usb/host/ohci-ssb.c @@ -0,0 +1,249 @@ +/* + * Sonics Silicon Backplane + * Broadcom USB-core OHCI driver + * + * Copyright 2007 Michael Buesch <mb@bu3sch.de> + * + * Derived from the OHCI-PCI driver + * Copyright 1999 Roman Weissgaerber + * Copyright 2000-2002 David Brownell + * Copyright 1999 Linus Torvalds + * Copyright 1999 Gregory P. Smith + * + * Derived from the USBcore related parts of Broadcom-SB + * Copyright 2005 Broadcom Corporation + * + * Licensed under the GNU/GPL. See COPYING for details. + */ +#include <linux/ssb/ssb.h> + + +#define SSB_OHCI_TMSLOW_HOSTMODE (1 << 29) + +struct ssb_ohci_device { + struct ohci_hcd ohci; /* _must_ be at the beginning. */ + + u32 enable_flags; +}; + +static inline +struct ssb_ohci_device *hcd_to_ssb_ohci(struct usb_hcd *hcd) +{ + return (struct ssb_ohci_device *)(hcd->hcd_priv); +} + + +static int ssb_ohci_reset(struct usb_hcd *hcd) +{ + struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); + struct ohci_hcd *ohci = &ohcidev->ohci; + int err; + + ohci_hcd_init(ohci); + err = ohci_init(ohci); + + return err; +} + +static int ssb_ohci_start(struct usb_hcd *hcd) +{ + struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); + struct ohci_hcd *ohci = &ohcidev->ohci; + int err; + + err = ohci_run(ohci); + if (err < 0) { + ohci_err(ohci, "can't start\n"); + ohci_stop(hcd); + } + + return err; +} + +#ifdef CONFIG_PM +static int ssb_ohci_hcd_suspend(struct usb_hcd *hcd, pm_message_t message) +{ + struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); + struct ohci_hcd *ohci = &ohcidev->ohci; + unsigned long flags; + + spin_lock_irqsave(&ohci->lock, flags); + + ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); + ohci_readl(ohci, &ohci->regs->intrdisable); /* commit write */ + + /* make sure snapshot being resumed re-enumerates everything */ + if (message.event == PM_EVENT_PRETHAW) + ohci_usb_reset(ohci); + + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + + spin_unlock_irqrestore(&ohci->lock, flags); + return 0; +} + +static int ssb_ohci_hcd_resume(struct usb_hcd *hcd) +{ + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + usb_hcd_resume_root_hub(hcd); + return 0; +} +#endif /* CONFIG_PM */ + +static const struct hc_driver ssb_ohci_hc_driver = { + .description = "ssb-usb-ohci", + .product_desc = "SSB OHCI Controller", + .hcd_priv_size = sizeof(struct ssb_ohci_device), + + .irq = ohci_irq, + .flags = HCD_MEMORY | HCD_USB11, + + .reset = ssb_ohci_reset, + .start = ssb_ohci_start, + .stop = ohci_stop, + .shutdown = ohci_shutdown, + +#ifdef CONFIG_PM + .suspend = ssb_ohci_hcd_suspend, + .resume = ssb_ohci_hcd_resume, +#endif + + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + .get_frame_number = ohci_get_frame, + + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, + .hub_irq_enable = ohci_rhsc_enable, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, +#endif + + .start_port_reset = ohci_start_port_reset, +}; + +static void ssb_ohci_detach(struct ssb_device *dev) +{ + struct usb_hcd *hcd = ssb_get_drvdata(dev); + + usb_remove_hcd(hcd); + iounmap(hcd->regs); + usb_put_hcd(hcd); + ssb_device_disable(dev, 0); +} + +static int ssb_ohci_attach(struct ssb_device *dev) +{ + struct ssb_ohci_device *ohcidev; + struct usb_hcd *hcd; + int err = -ENOMEM; + u32 tmp, flags = 0; + + if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) + flags |= SSB_OHCI_TMSLOW_HOSTMODE; + + ssb_device_enable(dev, flags); + + hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev, + dev->dev->bus_id); + if (!hcd) + goto err_dev_disable; + ohcidev = hcd_to_ssb_ohci(hcd); + ohcidev->enable_flags = flags; + + tmp = ssb_read32(dev, SSB_ADMATCH0); + hcd->rsrc_start = ssb_admatch_base(tmp); + hcd->rsrc_len = ssb_admatch_size(tmp); + hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); + if (!hcd->regs) + goto err_put_hcd; + err = usb_add_hcd(hcd, dev->irq, IRQF_SHARED); + if (err) + goto err_iounmap; + + ssb_set_drvdata(dev, hcd); + + return err; + +err_iounmap: + iounmap(hcd->regs); +err_put_hcd: + usb_put_hcd(hcd); +err_dev_disable: + ssb_device_disable(dev, flags); + return err; +} + +static int ssb_ohci_probe(struct ssb_device *dev, + const struct ssb_device_id *id) +{ + int err; + u16 chipid_top; + + /* USBcores are only connected on embedded devices. */ + chipid_top = (dev->bus->chip_id & 0xFF00); + if (chipid_top != 0x4700 && chipid_top != 0x5300) + return -ENODEV; + + /* TODO: Probably need checks here; is the core connected? */ + + if (usb_disabled()) + return -ENODEV; + + /* We currently always attach SSB_DEV_USB11_HOSTDEV + * as HOST OHCI. If we want to attach it as Client device, + * we must branch here and call into the (yet to + * be written) Client mode driver. Same for remove(). */ + + err = ssb_ohci_attach(dev); + + return err; +} + +static void ssb_ohci_remove(struct ssb_device *dev) +{ + ssb_ohci_detach(dev); +} + +#ifdef CONFIG_PM + +static int ssb_ohci_suspend(struct ssb_device *dev, pm_message_t state) +{ + ssb_device_disable(dev, 0); + + return 0; +} + +static int ssb_ohci_resume(struct ssb_device *dev) +{ + struct usb_hcd *hcd = ssb_get_drvdata(dev); + struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); + + ssb_device_enable(dev, ohcidev->enable_flags); + + return 0; +} + +#else /* !CONFIG_PM */ +#define ssb_ohci_suspend NULL +#define ssb_ohci_resume NULL +#endif /* CONFIG_PM */ + +static const struct ssb_device_id ssb_ohci_table[] = { + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV), + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV), + SSB_DEVTABLE_END +}; +MODULE_DEVICE_TABLE(ssb, ssb_ohci_table); + +static struct ssb_driver ssb_ohci_driver = { + .name = KBUILD_MODNAME, + .id_table = ssb_ohci_table, + .probe = ssb_ohci_probe, + .remove = ssb_ohci_remove, + .suspend = ssb_ohci_suspend, + .resume = ssb_ohci_resume, +}; diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 4ada43cf1387..47c5c66a282c 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -398,11 +398,38 @@ struct ohci_hcd { #define OHCI_QUIRK_BE_MMIO 0x10 /* BE registers */ #define OHCI_QUIRK_ZFMICRO 0x20 /* Compaq ZFMicro chipset*/ #define OHCI_QUIRK_NEC 0x40 /* lost interrupts */ +#define OHCI_QUIRK_FRAME_NO 0x80 /* no big endian frame_no shift */ // there are also chip quirks/bugs in init logic struct work_struct nec_work; /* Worker for NEC quirk */ + + /* Needed for ZF Micro quirk */ + struct timer_list unlink_watchdog; + unsigned eds_scheduled; + struct ed *ed_to_check; + unsigned zf_delay; }; +#ifdef CONFIG_PCI +static inline int quirk_nec(struct ohci_hcd *ohci) +{ + return ohci->flags & OHCI_QUIRK_NEC; +} +static inline int quirk_zfmicro(struct ohci_hcd *ohci) +{ + return ohci->flags & OHCI_QUIRK_ZFMICRO; +} +#else +static inline int quirk_nec(struct ohci_hcd *ohci) +{ + return 0; +} +static inline int quirk_zfmicro(struct ohci_hcd *ohci) +{ + return 0; +} +#endif + /* convert between an hcd pointer and the corresponding ohci_hcd */ static inline struct ohci_hcd *hcd_to_ohci (struct usb_hcd *hcd) { @@ -607,15 +634,12 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x) /* HCCA frame number is 16 bits, but is accessed as 32 bits since not all * hardware handles 16 bit reads. That creates a different confusion on * some big-endian SOC implementations. Same thing happens with PSW access. - * - * FIXME: Deal with that as a runtime quirk when STB03xxx is ported over - * to arch/powerpc */ -#ifdef CONFIG_STB03xxx -#define OHCI_BE_FRAME_NO_SHIFT 16 +#ifdef CONFIG_PPC_MPC52xx +#define big_endian_frame_no_quirk(ohci) (ohci->flags & OHCI_QUIRK_FRAME_NO) #else -#define OHCI_BE_FRAME_NO_SHIFT 0 +#define big_endian_frame_no_quirk(ohci) 0 #endif static inline u16 ohci_frame_no(const struct ohci_hcd *ohci) @@ -623,7 +647,8 @@ static inline u16 ohci_frame_no(const struct ohci_hcd *ohci) u32 tmp; if (big_endian_desc(ohci)) { tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no); - tmp >>= OHCI_BE_FRAME_NO_SHIFT; + if (!big_endian_frame_no_quirk(ohci)) + tmp >>= 16; } else tmp = le32_to_cpup((__force __le32 *)&ohci->hcca->frame_no); diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 40a1de4c256e..ae8ec4474eb8 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -782,10 +782,12 @@ static void force_dequeue(struct r8a66597 *r8a66597, u16 pipenum, u16 address) kfree(td); if (urb) { - urb->status = -ENODEV; - urb->hcpriv = NULL; + usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), + urb); + spin_unlock(&r8a66597->lock); - usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb); + usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb, + -ENODEV); spin_lock(&r8a66597->lock); } break; @@ -832,7 +834,7 @@ static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb, info.pipenum = get_empty_pipenum(r8a66597, ep); info.address = get_urb_to_r8a66597_addr(r8a66597, urb); info.epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - info.maxpacket = ep->wMaxPacketSize; + info.maxpacket = le16_to_cpu(ep->wMaxPacketSize); info.type = get_r8a66597_type(ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); info.bufnum = get_bufnum(info.pipenum); @@ -923,7 +925,7 @@ static void prepare_setup_packet(struct r8a66597 *r8a66597, r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1); for (i = 0; i < 4; i++) { - r8a66597_write(r8a66597, p[i], setup_addr); + r8a66597_write(r8a66597, cpu_to_le16(p[i]), setup_addr); setup_addr += 2; } r8a66597_write(r8a66597, SUREQ, DCPCTR); @@ -1032,6 +1034,15 @@ static void prepare_status_packet(struct r8a66597 *r8a66597, pipe_start(r8a66597, td->pipe); } +static int is_set_address(unsigned char *setup_packet) +{ + if (((setup_packet[0] & USB_TYPE_MASK) == USB_TYPE_STANDARD) && + setup_packet[1] == USB_REQ_SET_ADDRESS) + return 1; + else + return 0; +} + /* this function must be called with interrupt disabled */ static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td) { @@ -1039,7 +1050,7 @@ static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td) switch (td->type) { case USB_PID_SETUP: - if (td->urb->setup_packet[1] == USB_REQ_SET_ADDRESS) { + if (is_set_address(td->urb->setup_packet)) { td->set_address = 1; td->urb->setup_packet[2] = alloc_usb_address(r8a66597, td->urb); @@ -1106,8 +1117,9 @@ static void set_td_timer(struct r8a66597 *r8a66597, struct r8a66597_td *td) } /* this function must be called with interrupt disabled */ -static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td, - u16 pipenum, struct urb *urb) +static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td, + u16 pipenum, struct urb *urb, int status) +__releases(r8a66597->lock) __acquires(r8a66597->lock) { int restart = 0; struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597); @@ -1115,7 +1127,7 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td, r8a66597->timeout_map &= ~(1 << pipenum); if (likely(td)) { - if (td->set_address && urb->status != 0) + if (td->set_address && (status != 0 || urb->unlinked)) r8a66597->address_map &= ~(1 << urb->setup_packet[2]); pipe_toggle_save(r8a66597, td->pipe, urb); @@ -1130,9 +1142,9 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td, if (usb_pipeisoc(urb->pipe)) urb->start_frame = r8a66597_get_frame(hcd); - urb->hcpriv = NULL; + usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb); spin_unlock(&r8a66597->lock); - usb_hcd_giveback_urb(hcd, urb); + usb_hcd_giveback_urb(hcd, urb, status); spin_lock(&r8a66597->lock); } @@ -1146,14 +1158,6 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td, } } -/* this function must be called with interrupt disabled */ -static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td, - u16 pipenum, struct urb *urb) -__releases(r8a66597->lock) __acquires(r8a66597->lock) -{ - done(r8a66597, td, pipenum, urb); -} - static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) { u16 tmp; @@ -1162,6 +1166,7 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum); struct urb *urb; int finish = 0; + int status = 0; if (unlikely(!td)) return; @@ -1170,17 +1175,15 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) fifo_change_from_pipe(r8a66597, td->pipe); tmp = r8a66597_read(r8a66597, td->pipe->fifoctr); if (unlikely((tmp & FRDY) == 0)) { - urb->status = -EPIPE; pipe_stop(r8a66597, td->pipe); pipe_irq_disable(r8a66597, pipenum); err("in fifo not ready (%d)", pipenum); - finish_request(r8a66597, td, pipenum, td->urb); + finish_request(r8a66597, td, pipenum, td->urb, -EPIPE); return; } /* prepare parameters */ rcv_len = tmp & DTLN; - bufsize = td->maxpacket; if (usb_pipeisoc(urb->pipe)) { buf = (u16 *)(urb->transfer_buffer + urb->iso_frame_desc[td->iso_cnt].offset); @@ -1189,29 +1192,31 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) buf = (void *)urb->transfer_buffer + urb->actual_length; urb_len = urb->transfer_buffer_length - urb->actual_length; } - if (rcv_len < bufsize) - size = min(rcv_len, urb_len); - else - size = min(bufsize, urb_len); + bufsize = min(urb_len, (int) td->maxpacket); + if (rcv_len <= bufsize) { + size = rcv_len; + } else { + size = bufsize; + status = -EOVERFLOW; + finish = 1; + } /* update parameters */ urb->actual_length += size; if (rcv_len == 0) td->zero_packet = 1; - if ((size % td->maxpacket) > 0) { + if (rcv_len < bufsize) { td->short_packet = 1; - if (urb->transfer_buffer_length != urb->actual_length && - urb->transfer_flags & URB_SHORT_NOT_OK) - td->urb->status = -EREMOTEIO; } if (usb_pipeisoc(urb->pipe)) { urb->iso_frame_desc[td->iso_cnt].actual_length = size; - urb->iso_frame_desc[td->iso_cnt].status = 0; + urb->iso_frame_desc[td->iso_cnt].status = status; td->iso_cnt++; + finish = 0; } /* check transfer finish */ - if (check_transfer_finish(td, urb)) { + if (finish || check_transfer_finish(td, urb)) { pipe_stop(r8a66597, td->pipe); pipe_irq_disable(r8a66597, pipenum); finish = 1; @@ -1226,11 +1231,8 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) buf, size); } - if (finish && pipenum != 0) { - if (td->urb->status == -EINPROGRESS) - td->urb->status = 0; - finish_request(r8a66597, td, pipenum, urb); - } + if (finish && pipenum != 0) + finish_request(r8a66597, td, pipenum, urb, status); } static void packet_write(struct r8a66597 *r8a66597, u16 pipenum) @@ -1248,11 +1250,10 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum) fifo_change_from_pipe(r8a66597, td->pipe); tmp = r8a66597_read(r8a66597, td->pipe->fifoctr); if (unlikely((tmp & FRDY) == 0)) { - urb->status = -EPIPE; pipe_stop(r8a66597, td->pipe); pipe_irq_disable(r8a66597, pipenum); err("out write fifo not ready. (%d)", pipenum); - finish_request(r8a66597, td, pipenum, td->urb); + finish_request(r8a66597, td, pipenum, urb, -EPIPE); return; } @@ -1297,7 +1298,7 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum) } -static void check_next_phase(struct r8a66597 *r8a66597) +static void check_next_phase(struct r8a66597 *r8a66597, int status) { struct r8a66597_td *td = r8a66597_get_td(r8a66597, 0); struct urb *urb; @@ -1310,49 +1311,41 @@ static void check_next_phase(struct r8a66597 *r8a66597) switch (td->type) { case USB_PID_IN: case USB_PID_OUT: - if (urb->status != -EINPROGRESS) { - finish = 1; - break; - } if (check_transfer_finish(td, urb)) td->type = USB_PID_ACK; break; case USB_PID_SETUP: - if (urb->status != -EINPROGRESS) - finish = 1; - else if (urb->transfer_buffer_length == urb->actual_length) { + if (urb->transfer_buffer_length == urb->actual_length) td->type = USB_PID_ACK; - urb->status = 0; - } else if (usb_pipeout(urb->pipe)) + else if (usb_pipeout(urb->pipe)) td->type = USB_PID_OUT; else td->type = USB_PID_IN; break; case USB_PID_ACK: finish = 1; - if (urb->status == -EINPROGRESS) - urb->status = 0; break; } - if (finish) - finish_request(r8a66597, td, 0, urb); + if (finish || status != 0 || urb->unlinked) + finish_request(r8a66597, td, 0, urb, status); else start_transfer(r8a66597, td); } -static void set_urb_error(struct r8a66597 *r8a66597, u16 pipenum) +static int get_urb_error(struct r8a66597 *r8a66597, u16 pipenum) { struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum); - if (td && td->urb) { + if (td) { u16 pid = r8a66597_read(r8a66597, td->pipe->pipectr) & PID; if (pid == PID_NAK) - td->urb->status = -ECONNRESET; + return -ECONNRESET; else - td->urb->status = -EPIPE; + return -EPIPE; } + return 0; } static void irq_pipe_ready(struct r8a66597 *r8a66597) @@ -1371,7 +1364,7 @@ static void irq_pipe_ready(struct r8a66597 *r8a66597) packet_read(r8a66597, 0); else pipe_irq_disable(r8a66597, 0); - check_next_phase(r8a66597); + check_next_phase(r8a66597, 0); } for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) { @@ -1405,7 +1398,7 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597) td = r8a66597_get_td(r8a66597, 0); if (td && td->type != USB_PID_OUT) disable_irq_empty(r8a66597, 0); - check_next_phase(r8a66597); + check_next_phase(r8a66597, 0); } for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) { @@ -1420,9 +1413,8 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597) if ((tmp & INBUFM) == 0) { disable_irq_empty(r8a66597, pipenum); pipe_irq_disable(r8a66597, pipenum); - if (td->urb->status == -EINPROGRESS) - td->urb->status = 0; - finish_request(r8a66597, td, pipenum, td->urb); + finish_request(r8a66597, td, pipenum, td->urb, + 0); } } } @@ -1433,15 +1425,16 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597) u16 check; u16 pipenum; u16 mask; + int status; mask = r8a66597_read(r8a66597, NRDYSTS) & r8a66597_read(r8a66597, NRDYENB); r8a66597_write(r8a66597, ~mask, NRDYSTS); if (mask & NRDY0) { cfifo_change(r8a66597, 0); - set_urb_error(r8a66597, 0); + status = get_urb_error(r8a66597, 0); pipe_irq_disable(r8a66597, 0); - check_next_phase(r8a66597); + check_next_phase(r8a66597, status); } for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) { @@ -1452,10 +1445,10 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597) if (unlikely(!td)) continue; - set_urb_error(r8a66597, pipenum); + status = get_urb_error(r8a66597, pipenum); pipe_irq_disable(r8a66597, pipenum); pipe_stop(r8a66597, td->pipe); - finish_request(r8a66597, td, pipenum, td->urb); + finish_request(r8a66597, td, pipenum, td->urb, status); } } } @@ -1475,6 +1468,7 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd) u16 intsts0, intsts1, intsts2; u16 intenb0, intenb1, intenb2; u16 mask0, mask1, mask2; + int status; spin_lock(&r8a66597->lock); @@ -1518,12 +1512,12 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd) } if (mask1 & SIGN) { r8a66597_write(r8a66597, ~SIGN, INTSTS1); - set_urb_error(r8a66597, 0); - check_next_phase(r8a66597); + status = get_urb_error(r8a66597, 0); + check_next_phase(r8a66597, status); } if (mask1 & SACK) { r8a66597_write(r8a66597, ~SACK, INTSTS1); - check_next_phase(r8a66597); + check_next_phase(r8a66597, 0); } } if (mask0) { @@ -1722,21 +1716,25 @@ static struct r8a66597_td *r8a66597_make_td(struct r8a66597 *r8a66597, } static int r8a66597_urb_enqueue(struct usb_hcd *hcd, - struct usb_host_endpoint *hep, struct urb *urb, gfp_t mem_flags) { + struct usb_host_endpoint *hep = urb->ep; struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd); struct r8a66597_td *td = NULL; - int ret = 0, request = 0; + int ret, request = 0; unsigned long flags; spin_lock_irqsave(&r8a66597->lock, flags); if (!get_urb_to_r8a66597_dev(r8a66597, urb)) { ret = -ENODEV; - goto error; + goto error_not_linked; } + ret = usb_hcd_link_urb_to_ep(hcd, urb); + if (ret) + goto error_not_linked; + if (!hep->hcpriv) { hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe), GFP_ATOMIC); @@ -1761,15 +1759,7 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd, if (list_empty(&r8a66597->pipe_queue[td->pipenum])) request = 1; list_add_tail(&td->queue, &r8a66597->pipe_queue[td->pipenum]); - - spin_lock(&urb->lock); - if (urb->status != -EINPROGRESS) { - spin_unlock(&urb->lock); - ret = -EPIPE; - goto error; - } urb->hcpriv = td; - spin_unlock(&urb->lock); if (request) { ret = start_transfer(r8a66597, td); @@ -1781,26 +1771,36 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd, set_td_timer(r8a66597, td); error: + if (ret) + usb_hcd_unlink_urb_from_ep(hcd, urb); +error_not_linked: spin_unlock_irqrestore(&r8a66597->lock, flags); return ret; } -static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, + int status) { struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd); struct r8a66597_td *td; unsigned long flags; + int rc; spin_lock_irqsave(&r8a66597->lock, flags); + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) + goto done; + if (urb->hcpriv) { td = urb->hcpriv; pipe_stop(r8a66597, td->pipe); pipe_irq_disable(r8a66597, td->pipenum); disable_irq_empty(r8a66597, td->pipenum); - done(r8a66597, td, td->pipenum, urb); + finish_request(r8a66597, td, td->pipenum, urb, status); } + done: spin_unlock_irqrestore(&r8a66597->lock, flags); - return 0; + return rc; } static void r8a66597_endpoint_disable(struct usb_hcd *hcd, @@ -1830,7 +1830,7 @@ static void r8a66597_endpoint_disable(struct usb_hcd *hcd, td = r8a66597_get_td(r8a66597, pipenum); if (td) urb = td->urb; - done(r8a66597, td, pipenum, urb); + finish_request(r8a66597, td, pipenum, urb, -ESHUTDOWN); kfree(hep->hcpriv); hep->hcpriv = NULL; spin_unlock_irqrestore(&r8a66597->lock, flags); @@ -2027,7 +2027,7 @@ static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, case GetPortStatus: if (wIndex > R8A66597_MAX_ROOT_HUB) goto error; - *(u32 *)buf = rh->port; + *(u32 *)buf = cpu_to_le32(rh->port); break; case SetPortFeature: if (wIndex > R8A66597_MAX_ROOT_HUB) @@ -2126,8 +2126,8 @@ static int __init_or_module r8a66597_remove(struct platform_device *pdev) struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597); del_timer_sync(&r8a66597->rh_timer); - iounmap((void *)r8a66597->reg); usb_remove_hcd(hcd); + iounmap((void *)r8a66597->reg); usb_put_hcd(hcd); return 0; } diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 4cfa3ff2c993..94d859aa73f8 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -435,14 +435,9 @@ static void finish_request( if (usb_pipecontrol(urb->pipe)) ep->nextpid = USB_PID_SETUP; - spin_lock(&urb->lock); - if (urb->status == -EINPROGRESS) - urb->status = status; - urb->hcpriv = NULL; - spin_unlock(&urb->lock); - + usb_hcd_unlink_urb_from_ep(sl811_to_hcd(sl811), urb); spin_unlock(&sl811->lock); - usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb); + usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb, status); spin_lock(&sl811->lock); /* leave active endpoints in the schedule */ @@ -538,35 +533,21 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank) bank + SL11H_XFERCNTREG); if (len > ep->length) { len = ep->length; - urb->status = -EOVERFLOW; + urbstat = -EOVERFLOW; } urb->actual_length += len; sl811_read_buf(sl811, SL811HS_PACKET_BUF(bank == 0), buf, len); usb_dotoggle(udev, ep->epnum, 0); - if (urb->actual_length == urb->transfer_buffer_length) - urbstat = 0; - else if (len < ep->maxpacket) { - if (urb->transfer_flags & URB_SHORT_NOT_OK) - urbstat = -EREMOTEIO; + if (urbstat == -EINPROGRESS && + (len < ep->maxpacket || + urb->actual_length == + urb->transfer_buffer_length)) { + if (usb_pipecontrol(urb->pipe)) + ep->nextpid = USB_PID_ACK; else urbstat = 0; } - if (usb_pipecontrol(urb->pipe) - && (urbstat == -EREMOTEIO - || urbstat == 0)) { - - /* NOTE if the status stage STALLs (why?), - * this reports the wrong urb status. - */ - spin_lock(&urb->lock); - if (urb->status == -EINPROGRESS) - urb->status = urbstat; - spin_unlock(&urb->lock); - - urb = NULL; - ep->nextpid = USB_PID_ACK; - } break; case USB_PID_SETUP: // PACKET("...ACK/setup_%02x qh%p\n", bank, ep); @@ -605,7 +586,7 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank) bank, status, ep, urbstat); } - if (urb && (urbstat != -EINPROGRESS || urb->status != -EINPROGRESS)) + if (urbstat != -EINPROGRESS || urb->unlinked) finish_request(sl811, ep, urb, urbstat); } @@ -807,7 +788,6 @@ static int balance(struct sl811 *sl811, u16 period, u16 load) static int sl811h_urb_enqueue( struct usb_hcd *hcd, - struct usb_host_endpoint *hep, struct urb *urb, gfp_t mem_flags ) { @@ -820,7 +800,8 @@ static int sl811h_urb_enqueue( struct sl811h_ep *ep = NULL; unsigned long flags; int i; - int retval = 0; + int retval; + struct usb_host_endpoint *hep = urb->ep; #ifdef DISABLE_ISO if (type == PIPE_ISOCHRONOUS) @@ -838,7 +819,12 @@ static int sl811h_urb_enqueue( || !HC_IS_RUNNING(hcd->state)) { retval = -ENODEV; kfree(ep); - goto fail; + goto fail_not_linked; + } + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval) { + kfree(ep); + goto fail_not_linked; } if (hep->hcpriv) { @@ -951,37 +937,31 @@ static int sl811h_urb_enqueue( sofirq_on(sl811); } - /* in case of unlink-during-submit */ - spin_lock(&urb->lock); - if (urb->status != -EINPROGRESS) { - spin_unlock(&urb->lock); - finish_request(sl811, ep, urb, 0); - retval = 0; - goto fail; - } urb->hcpriv = hep; - spin_unlock(&urb->lock); - start_transfer(sl811); sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable); fail: + if (retval) + usb_hcd_unlink_urb_from_ep(hcd, urb); +fail_not_linked: spin_unlock_irqrestore(&sl811->lock, flags); return retval; } -static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct sl811 *sl811 = hcd_to_sl811(hcd); struct usb_host_endpoint *hep; unsigned long flags; struct sl811h_ep *ep; - int retval = 0; + int retval; spin_lock_irqsave(&sl811->lock, flags); - hep = urb->hcpriv; - if (!hep) + retval = usb_hcd_check_unlink_urb(hcd, urb, status); + if (retval) goto fail; + hep = urb->hcpriv; ep = hep->hcpriv; if (ep) { /* finish right away if this urb can't be active ... @@ -1029,8 +1009,8 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) VDBG("dequeue, urb %p active %s; wait4irq\n", urb, (sl811->active_a == ep) ? "A" : "B"); } else -fail: retval = -EINVAL; + fail: spin_unlock_irqrestore(&sl811->lock, flags); return retval; } diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index b88eb3c62c02..ac283b09a63f 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -51,7 +51,6 @@ #include <linux/usb.h> #include <linux/workqueue.h> #include <linux/platform_device.h> -#include <linux/pci_ids.h> #include <linux/mutex.h> #include <asm/io.h> #include <asm/irq.h> @@ -184,7 +183,7 @@ struct u132_ring { struct u132 { struct kref kref; struct list_head u132_list; - struct semaphore sw_lock; + struct mutex sw_lock; struct semaphore scheduler_lock; struct u132_platform_data *board; struct platform_device *platform_dev; @@ -493,20 +492,20 @@ static void u132_hcd_monitor_work(struct work_struct *work) return; } else { int retval; - down(&u132->sw_lock); + mutex_lock(&u132->sw_lock); retval = read_roothub_info(u132); if (retval) { struct usb_hcd *hcd = u132_to_hcd(u132); u132_disable(u132); u132->going = 1; - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); usb_hc_died(hcd); ftdi_elan_gone_away(u132->platform_dev); u132_monitor_put_kref(u132); return; } else { u132_monitor_requeue_work(u132, 500); - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); return; } } @@ -519,9 +518,8 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp, unsigned long irqs; struct usb_hcd *hcd = u132_to_hcd(u132); urb->error_count = 0; - urb->status = status; - urb->hcpriv = NULL; spin_lock_irqsave(&endp->queue_lock.slock, irqs); + usb_hcd_unlink_urb_from_ep(hcd, urb); endp->queue_next += 1; if (ENDP_QUEUE_SIZE > --endp->queue_size) { endp->active = 0; @@ -543,7 +541,7 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp, u132_ring_queue_work(u132, ring, 0); up(&u132->scheduler_lock); u132_endp_put_kref(u132, endp); - usb_hcd_giveback_urb(hcd, urb); + usb_hcd_giveback_urb(hcd, urb, status); return; } @@ -559,9 +557,8 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp, unsigned long irqs; struct usb_hcd *hcd = u132_to_hcd(u132); urb->error_count = 0; - urb->status = status; - urb->hcpriv = NULL; spin_lock_irqsave(&endp->queue_lock.slock, irqs); + usb_hcd_unlink_urb_from_ep(hcd, urb); endp->queue_next += 1; if (ENDP_QUEUE_SIZE > --endp->queue_size) { endp->active = 0; @@ -576,7 +573,7 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp, endp->active = 0; spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); kfree(urbq); - } usb_hcd_giveback_urb(hcd, urb); + } usb_hcd_giveback_urb(hcd, urb, status); return; } @@ -646,12 +643,12 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { struct u132_ring *ring = endp->ring; u8 *u = urb->transfer_buffer + urb->actual_length; u8 *b = buf; @@ -717,10 +714,10 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf, return; } } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -745,12 +742,12 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { struct u132_ring *ring = endp->ring; urb->actual_length += len; endp->toggle_bits = toggle_bits; @@ -769,10 +766,10 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf, return; } } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -798,12 +795,12 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { struct u132_ring *ring = endp->ring; u8 *u = urb->transfer_buffer + urb->actual_length; u8 *b = buf; @@ -872,10 +869,10 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf, return; } } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -899,20 +896,20 @@ static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -937,12 +934,12 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { struct u132_ring *ring = endp->ring; u8 *u = urb->transfer_buffer; u8 *b = buf; @@ -981,10 +978,10 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf, return; } } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1008,20 +1005,20 @@ static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1046,12 +1043,12 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { if (usb_pipein(urb->pipe)) { int retval; struct u132_ring *ring = endp->ring; @@ -1078,10 +1075,10 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf, return; } } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1107,22 +1104,22 @@ static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { u132->addr[0].address = 0; endp->usb_addr = udev->usb_addr; up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1146,12 +1143,12 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { int retval; struct u132_ring *ring = endp->ring; up(&u132->scheduler_lock); @@ -1163,10 +1160,10 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb, u132_hcd_giveback_urb(u132, endp, urb, retval); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1190,20 +1187,20 @@ static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1228,12 +1225,12 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { int retval; struct u132_ring *ring = endp->ring; u8 *u = urb->transfer_buffer; @@ -1252,10 +1249,10 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, retval); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1280,12 +1277,12 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { int retval; struct u132_ring *ring = endp->ring; up(&u132->scheduler_lock); @@ -1297,10 +1294,10 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, retval); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1805,10 +1802,10 @@ static void u132_hcd_stop(struct usb_hcd *hcd) dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov" "ed\n", hcd); } else { - down(&u132->sw_lock); + mutex_lock(&u132->sw_lock); msleep(100); u132_power(u132, 0); - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); } } @@ -1830,7 +1827,7 @@ static int u132_hcd_start(struct usb_hcd *hcd) (pdev->dev.platform_data))->vendor; u16 device = ((struct u132_platform_data *) (pdev->dev.platform_data))->device; - down(&u132->sw_lock); + mutex_lock(&u132->sw_lock); msleep(10); if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) { u132->flags = OHCI_QUIRK_AMD756; @@ -1845,7 +1842,7 @@ static int u132_hcd_start(struct usb_hcd *hcd) u132->going = 1; } msleep(100); - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); return retval; } else { dev_err(&u132->platform_dev->dev, "platform_device missing\n"); @@ -1865,32 +1862,44 @@ static int u132_hcd_reset(struct usb_hcd *hcd) return -ESHUTDOWN; } else { int retval; - down(&u132->sw_lock); + mutex_lock(&u132->sw_lock); retval = u132_init(u132); if (retval) { u132_disable(u132); u132->going = 1; } - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); return retval; } } static int create_endpoint_and_queue_int(struct u132 *u132, - struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb, + struct u132_udev *udev, struct urb *urb, struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address, gfp_t mem_flags) { struct u132_ring *ring; unsigned long irqs; - u8 endp_number = ++u132->num_endpoints; - struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] = - kmalloc(sizeof(struct u132_endp), mem_flags); + int rc; + u8 endp_number; + struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags); + if (!endp) { return -ENOMEM; } + + spin_lock_init(&endp->queue_lock.slock); + spin_lock_irqsave(&endp->queue_lock.slock, irqs); + rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb); + if (rc) { + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + kfree(endp); + return rc; + } + + endp_number = ++u132->num_endpoints; + urb->ep->hcpriv = u132->endp[endp_number - 1] = endp; INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); - spin_lock_init(&endp->queue_lock.slock); INIT_LIST_HEAD(&endp->urb_more); ring = endp->ring = &u132->ring[0]; if (ring->curr_endp) { @@ -1906,7 +1915,7 @@ static int create_endpoint_and_queue_int(struct u132 *u132, endp->delayed = 0; endp->endp_number = endp_number; endp->u132 = u132; - endp->hep = hep; + endp->hep = urb->ep; endp->pipetype = usb_pipetype(urb->pipe); u132_endp_init_kref(u132, endp); if (usb_pipein(urb->pipe)) { @@ -1925,7 +1934,6 @@ static int create_endpoint_and_queue_int(struct u132 *u132, u132_udev_get_kref(u132, udev); } urb->hcpriv = u132; - spin_lock_irqsave(&endp->queue_lock.slock, irqs); endp->delayed = 1; endp->jiffies = jiffies + msecs_to_jiffies(urb->interval); endp->udev_number = address; @@ -1940,8 +1948,8 @@ static int create_endpoint_and_queue_int(struct u132 *u132, return 0; } -static int queue_int_on_old_endpoint(struct u132 *u132, struct u132_udev *udev, - struct usb_host_endpoint *hep, struct urb *urb, +static int queue_int_on_old_endpoint(struct u132 *u132, + struct u132_udev *udev, struct urb *urb, struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, u8 usb_endp, u8 address) { @@ -1965,21 +1973,33 @@ static int queue_int_on_old_endpoint(struct u132 *u132, struct u132_udev *udev, } static int create_endpoint_and_queue_bulk(struct u132 *u132, - struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb, + struct u132_udev *udev, struct urb *urb, struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address, gfp_t mem_flags) { int ring_number; struct u132_ring *ring; unsigned long irqs; - u8 endp_number = ++u132->num_endpoints; - struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] = - kmalloc(sizeof(struct u132_endp), mem_flags); + int rc; + u8 endp_number; + struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags); + if (!endp) { return -ENOMEM; } + + spin_lock_init(&endp->queue_lock.slock); + spin_lock_irqsave(&endp->queue_lock.slock, irqs); + rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb); + if (rc) { + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + kfree(endp); + return rc; + } + + endp_number = ++u132->num_endpoints; + urb->ep->hcpriv = u132->endp[endp_number - 1] = endp; INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); - spin_lock_init(&endp->queue_lock.slock); INIT_LIST_HEAD(&endp->urb_more); endp->dequeueing = 0; endp->edset_flush = 0; @@ -1987,7 +2007,7 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132, endp->delayed = 0; endp->endp_number = endp_number; endp->u132 = u132; - endp->hep = hep; + endp->hep = urb->ep; endp->pipetype = usb_pipetype(urb->pipe); u132_endp_init_kref(u132, endp); if (usb_pipein(urb->pipe)) { @@ -2016,7 +2036,6 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132, } ring->length += 1; urb->hcpriv = u132; - spin_lock_irqsave(&endp->queue_lock.slock, irqs); endp->udev_number = address; endp->usb_addr = usb_addr; endp->usb_endp = usb_endp; @@ -2030,7 +2049,7 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132, } static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev, - struct usb_host_endpoint *hep, struct urb *urb, + struct urb *urb, struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, u8 usb_endp, u8 address) { @@ -2052,19 +2071,32 @@ static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev, } static int create_endpoint_and_queue_control(struct u132 *u132, - struct usb_host_endpoint *hep, struct urb *urb, + struct urb *urb, struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, gfp_t mem_flags) { struct u132_ring *ring; - u8 endp_number = ++u132->num_endpoints; - struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] = - kmalloc(sizeof(struct u132_endp), mem_flags); + unsigned long irqs; + int rc; + u8 endp_number; + struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags); + if (!endp) { return -ENOMEM; } + + spin_lock_init(&endp->queue_lock.slock); + spin_lock_irqsave(&endp->queue_lock.slock, irqs); + rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb); + if (rc) { + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + kfree(endp); + return rc; + } + + endp_number = ++u132->num_endpoints; + urb->ep->hcpriv = u132->endp[endp_number - 1] = endp; INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); - spin_lock_init(&endp->queue_lock.slock); INIT_LIST_HEAD(&endp->urb_more); ring = endp->ring = &u132->ring[0]; if (ring->curr_endp) { @@ -2080,11 +2112,10 @@ static int create_endpoint_and_queue_control(struct u132 *u132, endp->delayed = 0; endp->endp_number = endp_number; endp->u132 = u132; - endp->hep = hep; + endp->hep = urb->ep; u132_endp_init_kref(u132, endp); u132_endp_get_kref(u132, endp); if (usb_addr == 0) { - unsigned long irqs; u8 address = u132->addr[usb_addr].address; struct u132_udev *udev = &u132->udev[address]; endp->udev_number = address; @@ -2098,7 +2129,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132, udev->endp_number_in[usb_endp] = endp_number; udev->endp_number_out[usb_endp] = endp_number; urb->hcpriv = u132; - spin_lock_irqsave(&endp->queue_lock.slock, irqs); endp->queue_size = 1; endp->queue_last = 0; endp->queue_next = 0; @@ -2107,7 +2137,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132, u132_endp_queue_work(u132, endp, 0); return 0; } else { /*(usb_addr > 0) */ - unsigned long irqs; u8 address = u132->addr[usb_addr].address; struct u132_udev *udev = &u132->udev[address]; endp->udev_number = address; @@ -2121,7 +2150,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132, udev->endp_number_in[usb_endp] = endp_number; udev->endp_number_out[usb_endp] = endp_number; urb->hcpriv = u132; - spin_lock_irqsave(&endp->queue_lock.slock, irqs); endp->queue_size = 1; endp->queue_last = 0; endp->queue_next = 0; @@ -2133,7 +2161,7 @@ static int create_endpoint_and_queue_control(struct u132 *u132, } static int queue_control_on_old_endpoint(struct u132 *u132, - struct usb_host_endpoint *hep, struct urb *urb, + struct urb *urb, struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, u8 usb_endp) { @@ -2233,8 +2261,8 @@ static int queue_control_on_old_endpoint(struct u132 *u132, } } -static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, - struct urb *urb, gfp_t mem_flags) +static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, + gfp_t mem_flags) { struct u132 *u132 = hcd_to_u132(hcd); if (irqs_disabled()) { @@ -2249,8 +2277,8 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, , u132->going); return -ENODEV; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); return -ESHUTDOWN; } else { u8 usb_addr = usb_pipedevice(urb->pipe); @@ -2259,16 +2287,24 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { u8 address = u132->addr[usb_addr].address; struct u132_udev *udev = &u132->udev[address]; - struct u132_endp *endp = hep->hcpriv; + struct u132_endp *endp = urb->ep->hcpriv; urb->actual_length = 0; if (endp) { unsigned long irqs; int retval; spin_lock_irqsave(&endp->queue_lock.slock, irqs); - retval = queue_int_on_old_endpoint(u132, udev, - hep, urb, usb_dev, endp, usb_addr, - usb_endp, address); + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval == 0) { + retval = queue_int_on_old_endpoint( + u132, udev, urb, + usb_dev, endp, + usb_addr, usb_endp, + address); + if (retval) + usb_hcd_unlink_urb_from_ep( + hcd, urb); + } spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); if (retval) { @@ -2283,8 +2319,8 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, return -EINVAL; } else { /*(endp == NULL) */ return create_endpoint_and_queue_int(u132, udev, - hep, urb, usb_dev, usb_addr, usb_endp, - address, mem_flags); + urb, usb_dev, usb_addr, + usb_endp, address, mem_flags); } } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { dev_err(&u132->platform_dev->dev, "the hardware does no" @@ -2293,16 +2329,24 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, } else if (usb_pipetype(urb->pipe) == PIPE_BULK) { u8 address = u132->addr[usb_addr].address; struct u132_udev *udev = &u132->udev[address]; - struct u132_endp *endp = hep->hcpriv; + struct u132_endp *endp = urb->ep->hcpriv; urb->actual_length = 0; if (endp) { unsigned long irqs; int retval; spin_lock_irqsave(&endp->queue_lock.slock, irqs); - retval = queue_bulk_on_old_endpoint(u132, udev, - hep, urb, usb_dev, endp, usb_addr, - usb_endp, address); + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval == 0) { + retval = queue_bulk_on_old_endpoint( + u132, udev, urb, + usb_dev, endp, + usb_addr, usb_endp, + address); + if (retval) + usb_hcd_unlink_urb_from_ep( + hcd, urb); + } spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); if (retval) { @@ -2315,10 +2359,10 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, return -EINVAL; } else return create_endpoint_and_queue_bulk(u132, - udev, hep, urb, usb_dev, usb_addr, + udev, urb, usb_dev, usb_addr, usb_endp, address, mem_flags); } else { - struct u132_endp *endp = hep->hcpriv; + struct u132_endp *endp = urb->ep->hcpriv; u16 urb_size = 8; u8 *b = urb->setup_packet; int i = 0; @@ -2341,9 +2385,16 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, int retval; spin_lock_irqsave(&endp->queue_lock.slock, irqs); - retval = queue_control_on_old_endpoint(u132, - hep, urb, usb_dev, endp, usb_addr, - usb_endp); + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval == 0) { + retval = queue_control_on_old_endpoint( + u132, urb, usb_dev, + endp, usb_addr, + usb_endp); + if (retval) + usb_hcd_unlink_urb_from_ep( + hcd, urb); + } spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); if (retval) { @@ -2356,7 +2407,7 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, return -EINVAL; } else return create_endpoint_and_queue_control(u132, - hep, urb, usb_dev, usb_addr, usb_endp, + urb, usb_dev, usb_addr, usb_endp, mem_flags); } } @@ -2375,8 +2426,7 @@ static int dequeue_from_overflow_chain(struct u132 *u132, list_del(scan); endp->queue_size -= 1; urb->error_count = 0; - urb->hcpriv = NULL; - usb_hcd_giveback_urb(hcd, urb); + usb_hcd_giveback_urb(hcd, urb, 0); return 0; } else continue; @@ -2391,10 +2441,17 @@ static int dequeue_from_overflow_chain(struct u132 *u132, } static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, - struct urb *urb) + struct urb *urb, int status) { unsigned long irqs; + int rc; + spin_lock_irqsave(&endp->queue_lock.slock, irqs); + rc = usb_hcd_check_unlink_urb(u132_to_hcd(u132), urb, status); + if (rc) { + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + return rc; + } if (endp->queue_size == 0) { dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]" "=%p ring[%d] %c%c usb_endp=%d usb_addr=%d\n", urb, @@ -2410,11 +2467,10 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, endp->edset_flush = 1; u132_endp_queue_work(u132, endp, 0); spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - urb->hcpriv = NULL; return 0; } else { spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - u132_hcd_abandon_urb(u132, endp, urb, urb->status); + u132_hcd_abandon_urb(u132, endp, urb, status); return 0; } } else { @@ -2439,6 +2495,8 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, } if (urb_slot) { struct usb_hcd *hcd = u132_to_hcd(u132); + + usb_hcd_unlink_urb_from_ep(hcd, urb); endp->queue_size -= 1; if (list_empty(&endp->urb_more)) { spin_unlock_irqrestore(&endp->queue_lock.slock, @@ -2453,8 +2511,7 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, irqs); kfree(urbq); } urb->error_count = 0; - urb->hcpriv = NULL; - usb_hcd_giveback_urb(hcd, urb); + usb_hcd_giveback_urb(hcd, urb, status); return 0; } else if (list_empty(&endp->urb_more)) { dev_err(&u132->platform_dev->dev, "urb=%p not found in " @@ -2468,7 +2525,10 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); return -EINVAL; } else { - int retval = dequeue_from_overflow_chain(u132, endp, + int retval; + + usb_hcd_unlink_urb_from_ep(u132_to_hcd(u132), urb); + retval = dequeue_from_overflow_chain(u132, endp, urb); spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); return retval; @@ -2476,7 +2536,7 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, } } -static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct u132 *u132 = hcd_to_u132(hcd); if (u132->going > 2) { @@ -2491,11 +2551,11 @@ static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) if (usb_pipein(urb->pipe)) { u8 endp_number = udev->endp_number_in[usb_endp]; struct u132_endp *endp = u132->endp[endp_number - 1]; - return u132_endp_urb_dequeue(u132, endp, urb); + return u132_endp_urb_dequeue(u132, endp, urb, status); } else { u8 endp_number = udev->endp_number_out[usb_endp]; struct u132_endp *endp = u132->endp[endp_number - 1]; - return u132_endp_urb_dequeue(u132, endp, urb); + return u132_endp_urb_dequeue(u132, endp, urb, status); } } } @@ -2805,7 +2865,7 @@ static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, return -ESHUTDOWN; } else { int retval = 0; - down(&u132->sw_lock); + mutex_lock(&u132->sw_lock); switch (typeReq) { case ClearHubFeature: switch (wValue) { @@ -2868,7 +2928,7 @@ static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, stall:retval = -EPIPE; break; } - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); return retval; } } @@ -3004,7 +3064,7 @@ static int __devexit u132_remove(struct platform_device *pdev) dev_err(&u132->platform_dev->dev, "removing device u132" ".%d\n", u132->sequence_num); msleep(100); - down(&u132->sw_lock); + mutex_lock(&u132->sw_lock); u132_monitor_cancel_work(u132); while (rings-- > 0) { struct u132_ring *ring = &u132->ring[rings]; @@ -3017,7 +3077,7 @@ static int __devexit u132_remove(struct platform_device *pdev) u132->going += 1; printk(KERN_INFO "removing device u132.%d\n", u132->sequence_num); - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); usb_remove_hcd(hcd); u132_u132_put_kref(u132); return 0; @@ -3037,7 +3097,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev) u132->platform_dev = pdev; u132->power = 0; u132->reset = 0; - init_MUTEX(&u132->sw_lock); + mutex_init(&u132->sw_lock); init_MUTEX(&u132->scheduler_lock); while (rings-- > 0) { struct u132_ring *ring = &u132->ring[rings]; @@ -3047,7 +3107,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev) ring->curr_endp = NULL; INIT_DELAYED_WORK(&ring->scheduler, u132_hcd_ring_work_scheduler); - } down(&u132->sw_lock); + } mutex_lock(&u132->sw_lock); INIT_DELAYED_WORK(&u132->monitor, u132_hcd_monitor_work); while (ports-- > 0) { struct u132_port *port = &u132->port[ports]; @@ -3077,7 +3137,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev) while (endps-- > 0) { u132->endp[endps] = NULL; } - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); return; } diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index 1497371583b9..20cc58b97807 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c @@ -120,8 +120,8 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space) out += sprintf(out, "%s%s", ptype, (urbp->fsbr ? " FSBR" : "")); out += sprintf(out, " Actlen=%d", urbp->urb->actual_length); - if (urbp->urb->status != -EINPROGRESS) - out += sprintf(out, " Status=%d", urbp->urb->status); + if (urbp->urb->unlinked) + out += sprintf(out, " Unlinked=%d", urbp->urb->unlinked); out += sprintf(out, "\n"); i = nactive = ninactive = 0; diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 1b3d23406ac4..340d6ed3e6e9 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -146,7 +146,6 @@ struct uhci_qh { short phase; /* Between 0 and period-1 */ short load; /* Periodic time requirement, in us */ unsigned int iso_frame; /* Frame # for iso_packet_desc */ - int iso_status; /* Status for Isochronous URBs */ int state; /* QH_STATE_xxx; see above */ int type; /* Queue type (control, bulk, etc) */ @@ -457,21 +456,6 @@ struct urb_priv { }; -/* - * Locking in uhci.c - * - * Almost everything relating to the hardware schedule and processing - * of URBs is protected by uhci->lock. urb->status is protected by - * urb->lock; that's the one exception. - * - * To prevent deadlocks, never lock uhci->lock while holding urb->lock. - * The safe order of locking is: - * - * #1 uhci->lock - * #2 urb->lock - */ - - /* Some special IDs */ #define PCI_VENDOR_ID_GENESYS 0x17a0 diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 3bb908ca38e9..e5d60d5b105a 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -757,7 +757,6 @@ static void uhci_free_urb_priv(struct uhci_hcd *uhci, uhci_free_td(uhci, td); } - urbp->urb->hcpriv = NULL; kmem_cache_free(uhci_up_cachep, urbp); } @@ -1324,7 +1323,6 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, if (list_empty(&qh->queue)) { qh->iso_packet_desc = &urb->iso_frame_desc[0]; qh->iso_frame = urb->start_frame; - qh->iso_status = 0; } qh->skel = SKEL_ISO; @@ -1361,22 +1359,18 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) qh->iso_packet_desc->actual_length = actlength; qh->iso_packet_desc->status = status; } - - if (status) { + if (status) urb->error_count++; - qh->iso_status = status; - } uhci_remove_td_from_urbp(td); uhci_free_td(uhci, td); qh->iso_frame += qh->period; ++qh->iso_packet_desc; } - return qh->iso_status; + return 0; } static int uhci_urb_enqueue(struct usb_hcd *hcd, - struct usb_host_endpoint *hep, struct urb *urb, gfp_t mem_flags) { int ret; @@ -1387,19 +1381,19 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, spin_lock_irqsave(&uhci->lock, flags); - ret = urb->status; - if (ret != -EINPROGRESS) /* URB already unlinked! */ - goto done; + ret = usb_hcd_link_urb_to_ep(hcd, urb); + if (ret) + goto done_not_linked; ret = -ENOMEM; urbp = uhci_alloc_urb_priv(uhci, urb); if (!urbp) goto done; - if (hep->hcpriv) - qh = (struct uhci_qh *) hep->hcpriv; + if (urb->ep->hcpriv) + qh = urb->ep->hcpriv; else { - qh = uhci_alloc_qh(uhci, urb->dev, hep); + qh = uhci_alloc_qh(uhci, urb->dev, urb->ep); if (!qh) goto err_no_qh; } @@ -1440,27 +1434,29 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, err_submit_failed: if (qh->state == QH_STATE_IDLE) uhci_make_qh_idle(uhci, qh); /* Reclaim unused QH */ - err_no_qh: uhci_free_urb_priv(uhci, urbp); - done: + if (ret) + usb_hcd_unlink_urb_from_ep(hcd, urb); +done_not_linked: spin_unlock_irqrestore(&uhci->lock, flags); return ret; } -static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); unsigned long flags; - struct urb_priv *urbp; struct uhci_qh *qh; + int rc; spin_lock_irqsave(&uhci->lock, flags); - urbp = urb->hcpriv; - if (!urbp) /* URB was never linked! */ + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) goto done; - qh = urbp->qh; + + qh = ((struct urb_priv *) urb->hcpriv)->qh; /* Remove Isochronous TDs from the frame list ASAP */ if (qh->type == USB_ENDPOINT_XFER_ISOC) { @@ -1477,14 +1473,14 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) done: spin_unlock_irqrestore(&uhci->lock, flags); - return 0; + return rc; } /* * Finish unlinking an URB and give it back */ static void uhci_giveback_urb(struct uhci_hcd *uhci, struct uhci_qh *qh, - struct urb *urb) + struct urb *urb, int status) __releases(uhci->lock) __acquires(uhci->lock) { @@ -1497,13 +1493,6 @@ __acquires(uhci->lock) * unlinked first. Regardless, don't confuse people with a * negative length. */ urb->actual_length = max(urb->actual_length, 0); - - /* Report erroneous short transfers */ - if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) && - urb->actual_length < - urb->transfer_buffer_length && - urb->status == 0)) - urb->status = -EREMOTEIO; } /* When giving back the first URB in an Isochronous queue, @@ -1516,7 +1505,6 @@ __acquires(uhci->lock) qh->iso_packet_desc = &nurb->iso_frame_desc[0]; qh->iso_frame = nurb->start_frame; - qh->iso_status = 0; } /* Take the URB off the QH's queue. If the queue is now empty, @@ -1529,9 +1517,10 @@ __acquires(uhci->lock) } uhci_free_urb_priv(uhci, urbp); + usb_hcd_unlink_urb_from_ep(uhci_to_hcd(uhci), urb); spin_unlock(&uhci->lock); - usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb); + usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb, status); spin_lock(&uhci->lock); /* If the queue is now empty, we can unlink the QH and give up its @@ -1567,24 +1556,17 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) if (status == -EINPROGRESS) break; - spin_lock(&urb->lock); - if (urb->status == -EINPROGRESS) /* Not dequeued */ - urb->status = status; - else - status = ECONNRESET; /* Not -ECONNRESET */ - spin_unlock(&urb->lock); - /* Dequeued but completed URBs can't be given back unless * the QH is stopped or has finished unlinking. */ - if (status == ECONNRESET) { + if (urb->unlinked) { if (QH_FINISHED_UNLINKING(qh)) qh->is_stopped = 1; else if (!qh->is_stopped) return; } - uhci_giveback_urb(uhci, qh, urb); - if (status < 0 && qh->type != USB_ENDPOINT_XFER_ISOC) + uhci_giveback_urb(uhci, qh, urb, status); + if (status < 0) break; } @@ -1599,7 +1581,7 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) restart: list_for_each_entry(urbp, &qh->queue, node) { urb = urbp->urb; - if (urb->status != -EINPROGRESS) { + if (urb->unlinked) { /* Fix up the TD links and save the toggles for * non-Isochronous queues. For Isochronous queues, @@ -1608,7 +1590,7 @@ restart: qh->is_stopped = 0; return; } - uhci_giveback_urb(uhci, qh, urb); + uhci_giveback_urb(uhci, qh, urb, 0); goto restart; } } diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c index 768b2c11a231..e7d982a71548 100644 --- a/drivers/usb/image/microtek.c +++ b/drivers/usb/image/microtek.c @@ -446,7 +446,8 @@ static void mts_data_done( struct urb* transfer ) MTS_INT_INIT(); if ( context->data_length != transfer->actual_length ) { - context->srb->resid = context->data_length - transfer->actual_length; + scsi_set_resid(context->srb, context->data_length - + transfer->actual_length); } else if ( unlikely(status) ) { context->srb->result = (status == -ENOENT ? DID_ABORT : DID_ERROR)<<16; } @@ -490,7 +491,8 @@ static void mts_command_done( struct urb *transfer ) context->data_pipe, context->data, context->data_length, - context->srb->use_sg > 1 ? mts_do_sg : mts_data_done); + scsi_sg_count(context->srb) > 1 ? + mts_do_sg : mts_data_done); } else { mts_get_status(transfer); } @@ -505,21 +507,23 @@ static void mts_do_sg (struct urb* transfer) int status = transfer->status; MTS_INT_INIT(); - MTS_DEBUG("Processing fragment %d of %d\n", context->fragment,context->srb->use_sg); + MTS_DEBUG("Processing fragment %d of %d\n", context->fragment, + scsi_sg_count(context->srb)); if (unlikely(status)) { context->srb->result = (status == -ENOENT ? DID_ABORT : DID_ERROR)<<16; mts_transfer_cleanup(transfer); } - sg = context->srb->request_buffer; + sg = scsi_sglist(context->srb); context->fragment++; mts_int_submit_urb(transfer, context->data_pipe, page_address(sg[context->fragment].page) + sg[context->fragment].offset, sg[context->fragment].length, - context->fragment + 1 == context->srb->use_sg ? mts_data_done : mts_do_sg); + context->fragment + 1 == scsi_sg_count(context->srb) ? + mts_data_done : mts_do_sg); return; } @@ -547,20 +551,12 @@ mts_build_transfer_context(struct scsi_cmnd *srb, struct mts_desc* desc) desc->context.srb = srb; desc->context.fragment = 0; - if (!srb->use_sg) { - if ( !srb->request_bufflen ){ - desc->context.data = NULL; - desc->context.data_length = 0; - return; - } else { - desc->context.data = srb->request_buffer; - desc->context.data_length = srb->request_bufflen; - MTS_DEBUG("length = %d or %d\n", - srb->request_bufflen, srb->bufflen); - } + if (!scsi_bufflen(srb)) { + desc->context.data = NULL; + desc->context.data_length = 0; + return; } else { - MTS_DEBUG("Using scatter/gather\n"); - sg = srb->request_buffer; + sg = scsi_sglist(srb); desc->context.data = page_address(sg[0].page) + sg[0].offset; desc->context.data_length = sg[0].length; } diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index e9fdbc8997b3..5131cbfb2f52 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -188,7 +188,8 @@ static void adu_interrupt_in_callback(struct urb *urb) spin_lock(&dev->buflock); if (status != 0) { - if ((status != -ENOENT) && (status != -ECONNRESET)) { + if ((status != -ENOENT) && (status != -ECONNRESET) && + (status != -ESHUTDOWN)) { dbg(1," %s : nonzero status received: %d", __FUNCTION__, status); } diff --git a/drivers/usb/misc/berry_charge.c b/drivers/usb/misc/berry_charge.c index 92c1d2768df9..24e2dc3148a4 100644 --- a/drivers/usb/misc/berry_charge.c +++ b/drivers/usb/misc/berry_charge.c @@ -71,7 +71,7 @@ static int magic_charge(struct usb_device *udev) if (retval != 2) { dev_err(&udev->dev, "First magic command failed: %d.\n", retval); - return retval; + goto exit; } dbg(&udev->dev, "Sending second magic command\n"); @@ -80,7 +80,7 @@ static int magic_charge(struct usb_device *udev) if (retval != 0) { dev_err(&udev->dev, "Second magic command failed: %d.\n", retval); - return retval; + goto exit; } dbg(&udev->dev, "Calling set_configuration\n"); @@ -88,6 +88,8 @@ static int magic_charge(struct usb_device *udev) if (retval) dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval); +exit: + kfree(dummy_buffer); return retval; } @@ -112,6 +114,7 @@ static int magic_dual_mode(struct usb_device *udev) if (retval) dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval); + kfree(dummy_buffer); return retval; } diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index 538b535e955b..d3d8cd6ff103 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -2777,12 +2777,14 @@ static int ftdi_elan_probe(struct usb_interface *interface, size_t buffer_size; int i; int retval = -ENOMEM; - struct usb_ftdi *ftdi = kmalloc(sizeof(struct usb_ftdi), GFP_KERNEL); - if (ftdi == NULL) { + struct usb_ftdi *ftdi; + + ftdi = kzalloc(sizeof(struct usb_ftdi), GFP_KERNEL); + if (!ftdi) { printk(KERN_ERR "Out of memory\n"); return -ENOMEM; } - memset(ftdi, 0x00, sizeof(struct usb_ftdi)); + mutex_lock(&ftdi_module_lock); list_add_tail(&ftdi->ftdi_list, &ftdi_static_list); ftdi->sequence_num = ++ftdi_instances; diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index b64ca91d9b02..9244d067cec1 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -32,7 +32,7 @@ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Author: Thomas Winischhofer <thomas@winischhofer.net> + * Author: Thomas Winischhofer <thomas@winischhofer.net> * */ @@ -962,12 +962,12 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, packet.address = 0x00000194; packet.data = addr; ret = sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); + &packet, 0); packet.header = 0x001f; packet.address = 0x00000190; packet.data = (length & ~3); ret |= sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); + &packet, 0); if (sisusb->flagb0 != 0x16) { packet.header = 0x001f; packet.address = 0x00000180; @@ -1003,23 +1003,17 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, if (ret) { msgcount++; if (msgcount < 500) - printk(KERN_ERR - "sisusbvga[%d]: Wrote %zd of " - "%d bytes, error %d\n", - sisusb->minor, *bytes_written, - length, ret); + dev_err(&sisusb->sisusb_dev->dev, "Wrote %zd of %d bytes, error %d\n", + *bytes_written, length, ret); else if (msgcount == 500) - printk(KERN_ERR - "sisusbvga[%d]: Too many errors" - ", logging stopped\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Too many errors, logging stopped\n"); } addr += (*bytes_written); length -= (*bytes_written); } if (ret) - break; + break; } @@ -1261,51 +1255,10 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, addr += 4; length -= 4; } -#if 0 /* That does not work, as EP 2 is an OUT EP! */ - default: - CLEARPACKET(&packet); - packet.header = 0x001f; - packet.address = 0x000001a0; - packet.data = 0x00000006; - ret |= sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); - packet.header = 0x001f; - packet.address = 0x000001b0; - packet.data = (length & ~3) | 0x40000000; - ret |= sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); - packet.header = 0x001f; - packet.address = 0x000001b4; - packet.data = addr; - ret |= sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); - packet.header = 0x001f; - packet.address = 0x000001a4; - packet.data = 0x00000001; - ret |= sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); - if (userbuffer) { - ret |= sisusb_recv_bulk_msg(sisusb, - SISUSB_EP_GFX_BULK_IN, - (length & ~3), - NULL, userbuffer, - bytes_read, 0); - if (!ret) userbuffer += (*bytes_read); - } else { - ret |= sisusb_recv_bulk_msg(sisusb, - SISUSB_EP_GFX_BULK_IN, - (length & ~3), - kernbuffer, NULL, - bytes_read, 0); - if (!ret) kernbuffer += (*bytes_read); - } - addr += (*bytes_read); - length -= (*bytes_read); -#endif } if (ret) - break; + break; } return ret; @@ -1401,22 +1354,6 @@ sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data) return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data)); } -#if 0 - -int -sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data) -{ - return(sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data)); -} - -int -sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data) -{ - return(sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data)); -} - -#endif /* 0 */ - int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src, u32 dest, int length, size_t *bytes_written) @@ -1446,10 +1383,10 @@ sisusb_testreadwrite(struct sisusb_usb_data *sisusb) sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy); for(i = 1; i <= 7; i++) { - printk(KERN_DEBUG "sisusb: rwtest %d bytes\n", i); + dev_dbg(&sisusb->sisusb_dev->dev, "sisusb: rwtest %d bytes\n", i); sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i, &dummy); for(j = 0; j < i; j++) { - printk(KERN_DEBUG "sisusb: rwtest read[%d] = %x\n", j, destbuffer[j]); + dev_dbg(&sisusb->sisusb_dev->dev, "rwtest read[%d] = %x\n", j, destbuffer[j]); } } } @@ -1533,9 +1470,9 @@ sisusb_clear_vram(struct sisusb_usb_data *sisusb, u32 address, int length) #define SETIREGAND(r,i,a) sisusb_setidxregand(sisusb, r, i, a) #define SETIREGANDOR(r,i,a,o) sisusb_setidxregandor(sisusb, r, i, a, o) #define READL(a,d) sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, a, d) -#define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d) +#define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d) #define READB(a,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d) -#define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d) +#define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d) static int sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype) @@ -2008,7 +1945,7 @@ sisusb_set_default_mode(struct sisusb_usb_data *sisusb, int touchengines) SETIREG(SISSR, 0x26, 0x00); } - SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */ + SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */ return ret; } @@ -2168,17 +2105,12 @@ sisusb_init_gfxcore(struct sisusb_usb_data *sisusb) if (ramtype <= 1) { ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab); if (iret) { - printk(KERN_ERR "sisusbvga[%d]: RAM size " - "detection failed, " - "assuming 8MB video RAM\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev,"RAM size detection failed, assuming 8MB video RAM\n"); ret |= SETIREG(SISSR,0x14,0x31); /* TODO */ } } else { - printk(KERN_ERR "sisusbvga[%d]: DDR RAM device found, " - "assuming 8MB video RAM\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "DDR RAM device found, assuming 8MB video RAM\n"); ret |= SETIREG(SISSR,0x14,0x31); /* *** TODO *** */ } @@ -2249,8 +2181,7 @@ sisusb_get_ramconfig(struct sisusb_usb_data *sisusb) break; } - printk(KERN_INFO "sisusbvga[%d]: %dMB %s %s, bus width %d\n", - sisusb->minor, (sisusb->vramsize >> 20), ramtypetext1, + dev_info(&sisusb->sisusb_dev->dev, "%dMB %s %s, bus width %d\n", (sisusb->vramsize >> 20), ramtypetext1, ramtypetext2[ramtype], bw); } @@ -2509,11 +2440,8 @@ sisusb_open(struct inode *inode, struct file *file) struct usb_interface *interface; int subminor = iminor(inode); - if (!(interface = usb_find_interface(&sisusb_driver, subminor))) { - printk(KERN_ERR "sisusb[%d]: Failed to find interface\n", - subminor); + if (!(interface = usb_find_interface(&sisusb_driver, subminor))) return -ENODEV; - } if (!(sisusb = usb_get_intfdata(interface))) return -ENODEV; @@ -2534,18 +2462,12 @@ sisusb_open(struct inode *inode, struct file *file) if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) { if (sisusb_init_gfxdevice(sisusb, 0)) { mutex_unlock(&sisusb->lock); - printk(KERN_ERR - "sisusbvga[%d]: Failed to initialize " - "device\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to initialize device\n"); return -EIO; } } else { mutex_unlock(&sisusb->lock); - printk(KERN_ERR - "sisusbvga[%d]: Device not attached to " - "USB 2.0 hub\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Device not attached to USB 2.0 hub\n"); return -EIO; } } @@ -2586,7 +2508,6 @@ static int sisusb_release(struct inode *inode, struct file *file) { struct sisusb_usb_data *sisusb; - int myminor; if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) return -ENODEV; @@ -2599,8 +2520,6 @@ sisusb_release(struct inode *inode, struct file *file) sisusb_kill_all_busy(sisusb); } - myminor = sisusb->minor; - sisusb->isopen = 0; file->private_data = NULL; @@ -2942,7 +2861,7 @@ static int sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y, unsigned long arg) { - int retval, port, length; + int retval, port, length; u32 address; /* All our commands require the device @@ -3065,12 +2984,12 @@ sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y, static int sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) + unsigned long arg) { struct sisusb_usb_data *sisusb; struct sisusb_info x; struct sisusb_command y; - int retval = 0; + int retval = 0; u32 __user *argp = (u32 __user *)arg; if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) @@ -3095,7 +3014,7 @@ sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, case SISUSB_GET_CONFIG: - x.sisusb_id = SISUSB_ID; + x.sisusb_id = SISUSB_ID; x.sisusb_version = SISUSB_VERSION; x.sisusb_revision = SISUSB_REVISION; x.sisusb_patchlevel = SISUSB_PATCHLEVEL; @@ -3164,7 +3083,7 @@ static const struct file_operations usb_sisusb_fops = { .release = sisusb_release, .read = sisusb_read, .write = sisusb_write, - .llseek = sisusb_lseek, + .llseek = sisusb_lseek, #ifdef SISUSB_NEW_CONFIG_COMPAT .compat_ioctl = sisusb_compat_ioctl, #endif @@ -3183,17 +3102,13 @@ static int sisusb_probe(struct usb_interface *intf, struct usb_device *dev = interface_to_usbdev(intf); struct sisusb_usb_data *sisusb; int retval = 0, i; - const char *memfail = - KERN_ERR - "sisusbvga[%d]: Failed to allocate memory for %s buffer\n"; - printk(KERN_INFO "sisusb: USB2VGA dongle found at address %d\n", + dev_info(&dev->dev, "USB2VGA dongle found at address %d\n", dev->devnum); /* Allocate memory for our private */ if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) { - printk(KERN_ERR - "sisusb: Failed to allocate memory for private data\n"); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for private data\n"); return -ENOMEM; } kref_init(&sisusb->kref); @@ -3202,8 +3117,7 @@ static int sisusb_probe(struct usb_interface *intf, /* Register device */ if ((retval = usb_register_dev(intf, &usb_sisusb_class))) { - printk(KERN_ERR - "sisusb: Failed to get a minor for device %d\n", + dev_err(&sisusb->sisusb_dev->dev, "Failed to get a minor for device %d\n", dev->devnum); retval = -ENODEV; goto error_1; @@ -3221,7 +3135,7 @@ static int sisusb_probe(struct usb_interface *intf, sisusb->ibufsize = SISUSB_IBUF_SIZE; if (!(sisusb->ibuf = usb_buffer_alloc(dev, SISUSB_IBUF_SIZE, GFP_KERNEL, &sisusb->transfer_dma_in))) { - printk(memfail, "input", sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for input buffer"); retval = -ENOMEM; goto error_2; } @@ -3233,7 +3147,7 @@ static int sisusb_probe(struct usb_interface *intf, GFP_KERNEL, &sisusb->transfer_dma_out[i]))) { if (i == 0) { - printk(memfail, "output", sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for output buffer\n"); retval = -ENOMEM; goto error_3; } @@ -3245,9 +3159,7 @@ static int sisusb_probe(struct usb_interface *intf, /* Allocate URBs */ if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) { - printk(KERN_ERR - "sisusbvga[%d]: Failed to allocate URBs\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n"); retval = -ENOMEM; goto error_3; } @@ -3255,9 +3167,7 @@ static int sisusb_probe(struct usb_interface *intf, for (i = 0; i < sisusb->numobufs; i++) { if (!(sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL))) { - printk(KERN_ERR - "sisusbvga[%d]: Failed to allocate URBs\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n"); retval = -ENOMEM; goto error_4; } @@ -3266,15 +3176,12 @@ static int sisusb_probe(struct usb_interface *intf, sisusb->urbstatus[i] = 0; } - printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n", - sisusb->minor, sisusb->numobufs); + dev_info(&sisusb->sisusb_dev->dev, "Allocated %d output buffers\n", sisusb->numobufs); #ifdef INCL_SISUSB_CON /* Allocate our SiS_Pr */ if (!(sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL))) { - printk(KERN_ERR - "sisusbvga[%d]: Failed to allocate SiS_Pr\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate SiS_Pr\n"); } #endif @@ -3296,10 +3203,7 @@ static int sisusb_probe(struct usb_interface *intf, ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG, NULL); ret |= register_ioctl32_conversion(SISUSB_COMMAND, NULL); if (ret) - printk(KERN_ERR - "sisusbvga[%d]: Error registering ioctl32 " - "translations\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Error registering ioctl32 translations\n"); else sisusb->ioctl32registered = 1; } @@ -3315,23 +3219,17 @@ static int sisusb_probe(struct usb_interface *intf, initscreen = 0; #endif if (sisusb_init_gfxdevice(sisusb, initscreen)) - printk(KERN_ERR - "sisusbvga[%d]: Failed to early " - "initialize device\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to early initialize device\n"); } else - printk(KERN_INFO - "sisusbvga[%d]: Not attached to USB 2.0 hub, " - "deferring init\n", - sisusb->minor); + dev_info(&sisusb->sisusb_dev->dev, "Not attached to USB 2.0 hub, deferring init\n"); sisusb->ready = 1; #ifdef SISUSBENDIANTEST - printk(KERN_DEBUG "sisusb: *** RWTEST ***\n"); + dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST ***\n"); sisusb_testreadwrite(sisusb); - printk(KERN_DEBUG "sisusb: *** RWTEST END ***\n"); + dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST END ***\n"); #endif #ifdef INCL_SISUSB_CON @@ -3354,7 +3252,6 @@ error_1: static void sisusb_disconnect(struct usb_interface *intf) { struct sisusb_usb_data *sisusb; - int minor; /* This should *not* happen */ if (!(sisusb = usb_get_intfdata(intf))) @@ -3364,8 +3261,6 @@ static void sisusb_disconnect(struct usb_interface *intf) sisusb_console_exit(sisusb); #endif - minor = sisusb->minor; - usb_deregister_dev(intf, &usb_sisusb_class); mutex_lock(&sisusb->lock); @@ -3384,10 +3279,7 @@ static void sisusb_disconnect(struct usb_interface *intf) ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG); ret |= unregister_ioctl32_conversion(SISUSB_COMMAND); if (ret) { - printk(KERN_ERR - "sisusbvga[%d]: Error unregistering " - "ioctl32 translations\n", - minor); + dev_err(&sisusb->sisusb_dev->dev, "Error unregistering ioctl32 translations\n"); } } #endif @@ -3400,7 +3292,7 @@ static void sisusb_disconnect(struct usb_interface *intf) /* decrement our usage count */ kref_put(&sisusb->kref, sisusb_delete); - printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor); + dev_info(&sisusb->sisusb_dev->dev, "Disconnected\n"); } static struct usb_device_id sisusb_table [] = { @@ -3424,22 +3316,12 @@ static struct usb_driver sisusb_driver = { static int __init usb_sisusb_init(void) { - int retval; #ifdef INCL_SISUSB_CON sisusb_init_concode(); #endif - if (!(retval = usb_register(&sisusb_driver))) { - - printk(KERN_INFO "sisusb: Driver version %d.%d.%d\n", - SISUSB_VERSION, SISUSB_REVISION, SISUSB_PATCHLEVEL); - printk(KERN_INFO - "sisusb: Copyright (C) 2005 Thomas Winischhofer\n"); - - } - - return retval; + return usb_register(&sisusb_driver); } static void __exit usb_sisusb_exit(void) diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h index 8e1120a64806..d2d7872cd022 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.h +++ b/drivers/usb/misc/sisusbvga/sisusb.h @@ -8,29 +8,29 @@ * * Otherwise, the following license terms apply: * - * * Redistribution and use in source and binary forms, with or without - * * modification, are permitted provided that the following conditions - * * are met: - * * 1) Redistributions of source code must retain the above copyright - * * notice, this list of conditions and the following disclaimer. - * * 2) Redistributions in binary form must reproduce the above copyright - * * notice, this list of conditions and the following disclaimer in the - * * documentation and/or other materials provided with the distribution. - * * 3) The name of the author may not be used to endorse or promote products - * * derived from this software without specific prior written permission. - * * - * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED 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 AUTHOR 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. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1) Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2) Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3) The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. * - * Author: Thomas Winischhofer <thomas@winischhofer.net> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED 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 AUTHOR 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. + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> * */ @@ -44,16 +44,14 @@ #include <linux/mutex.h> /* For older kernels, support for text consoles is by default - * off. To ensable text console support, change the following: + * off. To enable text console support, change the following: */ -#if 0 -#define CONFIG_USB_SISUSBVGA_CON -#endif +/* #define CONFIG_USB_SISUSBVGA_CON */ /* Version Information */ #define SISUSB_VERSION 0 -#define SISUSB_REVISION 0 +#define SISUSB_REVISION 0 #define SISUSB_PATCHLEVEL 8 /* Include console and mode switching code? */ @@ -74,7 +72,7 @@ #define SISUSB_IBUF_SIZE 0x01000 #define SISUSB_OBUF_SIZE 0x10000 /* fixed */ -#define NUMOBUFS 8 /* max number of output buffers/output URBs */ +#define NUMOBUFS 8 /* max number of output buffers/output URBs */ /* About endianness: * @@ -93,7 +91,7 @@ */ #ifdef __BIG_ENDIAN -#define SISUSB_CORRECT_ENDIANNESS_PACKET(p) \ +#define SISUSB_CORRECT_ENDIANNESS_PACKET(p) \ do { \ p->header = cpu_to_le16(p->header); \ p->address = cpu_to_le32(p->address); \ @@ -105,7 +103,7 @@ struct sisusb_usb_data; -struct sisusb_urb_context { /* urb->context for outbound bulk URBs */ +struct sisusb_urb_context { /* urb->context for outbound bulk URBs */ struct sisusb_usb_data *sisusb; int urbindex; int *actual_length; @@ -116,16 +114,16 @@ struct sisusb_usb_data { struct usb_interface *interface; struct kref kref; wait_queue_head_t wait_q; /* for syncind and timeouts */ - struct mutex lock; /* general race avoidance */ - unsigned int ifnum; /* interface number of the USB device */ - int minor; /* minor (for logging clarity) */ - int isopen; /* !=0 if open */ - int present; /* !=0 if device is present on the bus */ - int ready; /* !=0 if device is ready for userland */ + struct mutex lock; /* general race avoidance */ + unsigned int ifnum; /* interface number of the USB device */ + int minor; /* minor (for logging clarity) */ + int isopen; /* !=0 if open */ + int present; /* !=0 if device is present on the bus */ + int ready; /* !=0 if device is ready for userland */ #ifdef SISUSB_OLD_CONFIG_COMPAT int ioctl32registered; #endif - int numobufs; /* number of obufs = number of out urbs */ + int numobufs; /* number of obufs = number of out urbs */ char *obuf[NUMOBUFS], *ibuf; /* transfer buffers */ int obufsize, ibufsize; dma_addr_t transfer_dma_out[NUMOBUFS]; @@ -136,13 +134,13 @@ struct sisusb_usb_data { unsigned char completein; struct sisusb_urb_context urbout_context[NUMOBUFS]; unsigned long flagb0; - unsigned long vrambase; /* framebuffer base */ - unsigned int vramsize; /* framebuffer size (bytes) */ + unsigned long vrambase; /* framebuffer base */ + unsigned int vramsize; /* framebuffer size (bytes) */ unsigned long mmiobase; unsigned int mmiosize; unsigned long ioportbase; - unsigned char devinit; /* device initialized? */ - unsigned char gfxinit; /* graphics core initialized? */ + unsigned char devinit; /* device initialized? */ + unsigned char gfxinit; /* graphics core initialized? */ unsigned short chipid, chipvendor; unsigned short chiprevision; #ifdef INCL_SISUSB_CON @@ -152,7 +150,7 @@ struct sisusb_usb_data { int haveconsole, con_first, con_last; int havethisconsole[MAX_NR_CONSOLES]; int textmodedestroyed; - unsigned int sisusb_num_columns; /* real number, not vt's idea */ + unsigned int sisusb_num_columns; /* real number, not vt's idea */ int cur_start_addr, con_rolled_over; int sisusb_cursor_loc, bad_cursor_pos; int sisusb_cursor_size_from; @@ -197,7 +195,7 @@ struct sisusb_packet { unsigned short header; u32 address; u32 data; -} __attribute__((__packed__)); +} __attribute__ ((__packed__)); #define CLEARPACKET(packet) memset(packet, 0, 10) @@ -265,36 +263,36 @@ struct sisusb_packet { /* Structure argument for SISUSB_GET_INFO ioctl */ struct sisusb_info { - __u32 sisusb_id; /* for identifying sisusb */ -#define SISUSB_ID 0x53495355 /* Identify myself with 'SISU' */ - __u8 sisusb_version; - __u8 sisusb_revision; - __u8 sisusb_patchlevel; - __u8 sisusb_gfxinit; /* graphics core initialized? */ + __u32 sisusb_id; /* for identifying sisusb */ +#define SISUSB_ID 0x53495355 /* Identify myself with 'SISU' */ + __u8 sisusb_version; + __u8 sisusb_revision; + __u8 sisusb_patchlevel; + __u8 sisusb_gfxinit; /* graphics core initialized? */ - __u32 sisusb_vrambase; - __u32 sisusb_mmiobase; - __u32 sisusb_iobase; - __u32 sisusb_pcibase; + __u32 sisusb_vrambase; + __u32 sisusb_mmiobase; + __u32 sisusb_iobase; + __u32 sisusb_pcibase; - __u32 sisusb_vramsize; /* framebuffer size in bytes */ + __u32 sisusb_vramsize; /* framebuffer size in bytes */ - __u32 sisusb_minor; + __u32 sisusb_minor; - __u32 sisusb_fbdevactive; /* != 0 if framebuffer device active */ + __u32 sisusb_fbdevactive; /* != 0 if framebuffer device active */ - __u32 sisusb_conactive; /* != 0 if console driver active */ + __u32 sisusb_conactive; /* != 0 if console driver active */ - __u8 sisusb_reserved[28]; /* for future use */ + __u8 sisusb_reserved[28]; /* for future use */ }; struct sisusb_command { - __u8 operation; /* see below */ - __u8 data0; /* operation dependent */ - __u8 data1; /* operation dependent */ - __u8 data2; /* operation dependent */ - __u32 data3; /* operation dependent */ - __u32 data4; /* for future use */ + __u8 operation; /* see below */ + __u8 data0; /* operation dependent */ + __u8 data1; /* operation dependent */ + __u8 data2; /* operation dependent */ + __u32 data3; /* operation dependent */ + __u32 data4; /* for future use */ }; #define SUCMD_GET 0x01 /* for all: data0 = index, data3 = port */ @@ -306,7 +304,7 @@ struct sisusb_command { #define SUCMD_CLRSCR 0x07 /* data0:1:2 = length, data3 = address */ -#define SUCMD_HANDLETEXTMODE 0x08 /* Reset/destroy text mode */ +#define SUCMD_HANDLETEXTMODE 0x08 /* Reset/destroy text mode */ #define SUCMD_SETMODE 0x09 /* Set a display mode (data3 = SiS mode) */ #define SUCMD_SETVESAMODE 0x0a /* Set a display mode (data3 = VESA mode) */ @@ -315,6 +313,4 @@ struct sisusb_command { #define SISUSB_GET_CONFIG_SIZE _IOR(0xF3,0x3E,__u32) #define SISUSB_GET_CONFIG _IOR(0xF3,0x3F,struct sisusb_info) - #endif /* SISUSB_H */ - diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index 8d0edc867f33..43722e5a49d1 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -52,6 +52,7 @@ #include <linux/kernel.h> #include <linux/signal.h> #include <linux/fs.h> +#include <linux/usb.h> #include <linux/tty.h> #include <linux/console.h> #include <linux/string.h> @@ -373,14 +374,6 @@ sisusbcon_putc(struct vc_data *c, int ch, int y, int x) return; /* sisusb->lock is down */ - - /* Don't need to put the character into buffer ourselves, - * because the vt does this BEFORE calling us. - */ -#if 0 - sisusbcon_writew(ch, SISUSB_VADDR(x, y)); -#endif - if (sisusb_is_inactive(c, sisusb)) { mutex_unlock(&sisusb->lock); return; @@ -490,10 +483,6 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx, struct sisusb_usb_data *sisusb; ssize_t written; int cols, length; -#if 0 - u16 *src, *dest; - int i; -#endif if (width <= 0 || height <= 0) return; @@ -505,41 +494,6 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx, cols = sisusb->sisusb_num_columns; - /* Don't need to move data outselves, because - * vt does this BEFORE calling us. - * This is only used by vt's insert/deletechar. - */ -#if 0 - if (sx == 0 && dx == 0 && width >= c->vc_cols && width <= cols) { - - sisusbcon_memmovew(SISUSB_VADDR(0, dy), SISUSB_VADDR(0, sy), - height * width * 2); - - } else if (dy < sy || (dy == sy && dx < sx)) { - - src = SISUSB_VADDR(sx, sy); - dest = SISUSB_VADDR(dx, dy); - - for (i = height; i > 0; i--) { - sisusbcon_memmovew(dest, src, width * 2); - src += cols; - dest += cols; - } - - } else { - - src = SISUSB_VADDR(sx, sy + height - 1); - dest = SISUSB_VADDR(dx, dy + height - 1); - - for (i = height; i > 0; i--) { - sisusbcon_memmovew(dest, src, width * 2); - src -= cols; - dest -= cols; - } - - } -#endif - if (sisusb_is_inactive(c, sisusb)) { mutex_unlock(&sisusb->lock); return; @@ -584,7 +538,7 @@ sisusbcon_switch(struct vc_data *c) */ if (c->vc_origin == (unsigned long)c->vc_screenbuf) { mutex_unlock(&sisusb->lock); - printk(KERN_DEBUG "sisusb: ASSERT ORIGIN != SCREENBUF!\n"); + dev_dbg(&sisusb->sisusb_dev->dev, "ASSERT ORIGIN != SCREENBUF!\n"); return 0; } @@ -1475,7 +1429,7 @@ static const struct consw sisusb_dummy_con = { int sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last) { - int i, ret, minor = sisusb->minor; + int i, ret; mutex_lock(&sisusb->lock); @@ -1508,9 +1462,7 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last) /* Set up text mode (and upload default font) */ if (sisusb_reset_text_mode(sisusb, 1)) { mutex_unlock(&sisusb->lock); - printk(KERN_ERR - "sisusbvga[%d]: Failed to set up text mode\n", - minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to set up text mode\n"); return 1; } @@ -1531,9 +1483,7 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last) /* Allocate screen buffer */ if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) { mutex_unlock(&sisusb->lock); - printk(KERN_ERR - "sisusbvga[%d]: Failed to allocate screen buffer\n", - minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate screen buffer\n"); return 1; } diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.c b/drivers/usb/misc/sisusbvga/sisusb_init.c index 9b30f8962814..273de5d0934e 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_init.c +++ b/drivers/usb/misc/sisusbvga/sisusb_init.c @@ -32,7 +32,7 @@ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Author: Thomas Winischhofer <thomas@winischhofer.net> + * Author: Thomas Winischhofer <thomas@winischhofer.net> * */ @@ -55,109 +55,18 @@ /* POINTER INITIALIZATION */ /*********************************************/ -static void -SiSUSB_InitPtr(struct SiS_Private *SiS_Pr) +static void SiSUSB_InitPtr(struct SiS_Private *SiS_Pr) { - SiS_Pr->SiS_ModeResInfo = SiSUSB_ModeResInfo; - SiS_Pr->SiS_StandTable = SiSUSB_StandTable; - - SiS_Pr->SiS_SModeIDTable = SiSUSB_SModeIDTable; - SiS_Pr->SiS_EModeIDTable = SiSUSB_EModeIDTable; - SiS_Pr->SiS_RefIndex = SiSUSB_RefIndex; - SiS_Pr->SiS_CRT1Table = SiSUSB_CRT1Table; - - SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData; -} - -/*********************************************/ -/* HELPER: Get ModeID */ -/*********************************************/ + SiS_Pr->SiS_ModeResInfo = SiSUSB_ModeResInfo; + SiS_Pr->SiS_StandTable = SiSUSB_StandTable; -#if 0 -unsigned short -SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth) -{ - unsigned short ModeIndex = 0; - - switch (HDisplay) - { - case 320: - if (VDisplay == 200) - ModeIndex = ModeIndex_320x200[Depth]; - else if (VDisplay == 240) - ModeIndex = ModeIndex_320x240[Depth]; - break; - case 400: - if (VDisplay == 300) - ModeIndex = ModeIndex_400x300[Depth]; - break; - case 512: - if (VDisplay == 384) - ModeIndex = ModeIndex_512x384[Depth]; - break; - case 640: - if (VDisplay == 480) - ModeIndex = ModeIndex_640x480[Depth]; - else if (VDisplay == 400) - ModeIndex = ModeIndex_640x400[Depth]; - break; - case 720: - if (VDisplay == 480) - ModeIndex = ModeIndex_720x480[Depth]; - else if (VDisplay == 576) - ModeIndex = ModeIndex_720x576[Depth]; - break; - case 768: - if (VDisplay == 576) - ModeIndex = ModeIndex_768x576[Depth]; - break; - case 800: - if (VDisplay == 600) - ModeIndex = ModeIndex_800x600[Depth]; - else if (VDisplay == 480) - ModeIndex = ModeIndex_800x480[Depth]; - break; - case 848: - if (VDisplay == 480) - ModeIndex = ModeIndex_848x480[Depth]; - break; - case 856: - if (VDisplay == 480) - ModeIndex = ModeIndex_856x480[Depth]; - break; - case 960: - if (VDisplay == 540) - ModeIndex = ModeIndex_960x540[Depth]; - else if (VDisplay == 600) - ModeIndex = ModeIndex_960x600[Depth]; - break; - case 1024: - if (VDisplay == 576) - ModeIndex = ModeIndex_1024x576[Depth]; - else if (VDisplay == 768) - ModeIndex = ModeIndex_1024x768[Depth]; - break; - case 1152: - if (VDisplay == 864) - ModeIndex = ModeIndex_1152x864[Depth]; - break; - case 1280: - switch (VDisplay) { - case 720: - ModeIndex = ModeIndex_1280x720[Depth]; - break; - case 768: - ModeIndex = ModeIndex_1280x768[Depth]; - break; - case 1024: - ModeIndex = ModeIndex_1280x1024[Depth]; - break; - } - } + SiS_Pr->SiS_SModeIDTable = SiSUSB_SModeIDTable; + SiS_Pr->SiS_EModeIDTable = SiSUSB_EModeIDTable; + SiS_Pr->SiS_RefIndex = SiSUSB_RefIndex; + SiS_Pr->SiS_CRT1Table = SiSUSB_CRT1Table; - return ModeIndex; + SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData; } -#endif /* 0 */ /*********************************************/ /* HELPER: SetReg, GetReg */ @@ -165,21 +74,20 @@ SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth) static void SiS_SetReg(struct SiS_Private *SiS_Pr, unsigned long port, - unsigned short index, unsigned short data) + unsigned short index, unsigned short data) { sisusb_setidxreg(SiS_Pr->sisusb, port, index, data); } static void SiS_SetRegByte(struct SiS_Private *SiS_Pr, unsigned long port, - unsigned short data) + unsigned short data) { sisusb_setreg(SiS_Pr->sisusb, port, data); } static unsigned char -SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port, - unsigned short index) +SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port, unsigned short index) { u8 data; @@ -200,22 +108,22 @@ SiS_GetRegByte(struct SiS_Private *SiS_Pr, unsigned long port) static void SiS_SetRegANDOR(struct SiS_Private *SiS_Pr, unsigned long port, - unsigned short index, unsigned short DataAND, - unsigned short DataOR) + unsigned short index, unsigned short DataAND, + unsigned short DataOR) { sisusb_setidxregandor(SiS_Pr->sisusb, port, index, DataAND, DataOR); } static void SiS_SetRegAND(struct SiS_Private *SiS_Pr, unsigned long port, - unsigned short index, unsigned short DataAND) + unsigned short index, unsigned short DataAND) { sisusb_setidxregand(SiS_Pr->sisusb, port, index, DataAND); } static void -SiS_SetRegOR(struct SiS_Private *SiS_Pr,unsigned long port, - unsigned short index, unsigned short DataOR) +SiS_SetRegOR(struct SiS_Private *SiS_Pr, unsigned long port, + unsigned short index, unsigned short DataOR) { sisusb_setidxregor(SiS_Pr->sisusb, port, index, DataOR); } @@ -224,8 +132,7 @@ SiS_SetRegOR(struct SiS_Private *SiS_Pr,unsigned long port, /* HELPER: DisplayOn, DisplayOff */ /*********************************************/ -static void -SiS_DisplayOn(struct SiS_Private *SiS_Pr) +static void SiS_DisplayOn(struct SiS_Private *SiS_Pr) { SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, 0xDF); } @@ -234,8 +141,7 @@ SiS_DisplayOn(struct SiS_Private *SiS_Pr) /* HELPER: Init Port Addresses */ /*********************************************/ -static void -SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr) +static void SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr) { SiS_Pr->SiS_P3c4 = BaseAddr + 0x14; SiS_Pr->SiS_P3d4 = BaseAddr + 0x24; @@ -258,8 +164,7 @@ SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr) /* HELPER: GetSysFlags */ /*********************************************/ -static void -SiS_GetSysFlags(struct SiS_Private *SiS_Pr) +static void SiS_GetSysFlags(struct SiS_Private *SiS_Pr) { SiS_Pr->SiS_MyCR63 = 0x63; } @@ -268,8 +173,7 @@ SiS_GetSysFlags(struct SiS_Private *SiS_Pr) /* HELPER: Init PCI & Engines */ /*********************************************/ -static void -SiSInitPCIetc(struct SiS_Private *SiS_Pr) +static void SiSInitPCIetc(struct SiS_Private *SiS_Pr) { SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x20, 0xa1); /* - Enable 2D (0x40) @@ -285,8 +189,7 @@ SiSInitPCIetc(struct SiS_Private *SiS_Pr) /* HELPER: SET SEGMENT REGISTERS */ /*********************************************/ -static void -SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value) +static void SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value) { unsigned short temp; @@ -299,8 +202,7 @@ SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value) SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp); } -static void -SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value) +static void SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value) { unsigned short temp; @@ -313,15 +215,13 @@ SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value) SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp); } -static void -SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value) +static void SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value) { SiS_SetSegRegLower(SiS_Pr, value); SiS_SetSegRegUpper(SiS_Pr, value); } -static void -SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr) +static void SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr) { SiS_SetSegmentReg(SiS_Pr, 0); } @@ -337,14 +237,12 @@ SiS_SetSegmentRegOver(struct SiS_Private *SiS_Pr, unsigned short value) SiS_SetSegmentReg(SiS_Pr, value); } -static void -SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr) +static void SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr) { SiS_SetSegmentRegOver(SiS_Pr, 0); } -static void -SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr) +static void SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr) { SiS_ResetSegmentReg(SiS_Pr); SiS_ResetSegmentRegOver(SiS_Pr); @@ -356,7 +254,7 @@ SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr) static int SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo, - unsigned short *ModeIdIndex) + unsigned short *ModeIdIndex) { if ((*ModeNo) <= 0x13) { @@ -367,12 +265,14 @@ SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo, } else { - for(*ModeIdIndex = 0; ;(*ModeIdIndex)++) { + for (*ModeIdIndex = 0;; (*ModeIdIndex)++) { - if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == (*ModeNo)) + if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == + (*ModeNo)) break; - if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF) + if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == + 0xFF) return 0; } @@ -385,8 +285,7 @@ SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo, /* HELPER: ENABLE CRT1 */ /*********************************************/ -static void -SiS_HandleCRT1(struct SiS_Private *SiS_Pr) +static void SiS_HandleCRT1(struct SiS_Private *SiS_Pr) { /* Enable CRT1 gating */ SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, SiS_Pr->SiS_MyCR63, 0xbf); @@ -398,9 +297,9 @@ SiS_HandleCRT1(struct SiS_Private *SiS_Pr) static unsigned short SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex) + unsigned short ModeIdIndex) { - static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8}; + static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8 }; unsigned short modeflag; short index; @@ -411,7 +310,8 @@ SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo, } index = (modeflag & ModeTypeMask) - ModeEGA; - if (index < 0) index = 0; + if (index < 0) + index = 0; return ColorDepth[index]; } @@ -421,7 +321,7 @@ SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static unsigned short SiS_GetOffset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex, unsigned short rrti) + unsigned short ModeIdIndex, unsigned short rrti) { unsigned short xres, temp, colordepth, infoflag; @@ -458,8 +358,8 @@ SiS_SetSeqRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0] | 0x20; SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, SRdata); - for(i = 2; i <= 4; i++) { - SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i-1]; + for (i = 2; i <= 4; i++) { + SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i - 1]; SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, SRdata); } } @@ -488,7 +388,7 @@ SiS_SetCRTCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f); - for(i = 0; i <= 0x18; i++) { + for (i = 0; i <= 0x18; i++) { CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i]; SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, i, CRTCdata); } @@ -504,7 +404,7 @@ SiS_SetATTRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) unsigned char ARdata; unsigned short i; - for(i = 0; i <= 0x13; i++) { + for (i = 0; i <= 0x13; i++) { ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i]; SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da); SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, i); @@ -529,7 +429,7 @@ SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) unsigned char GRdata; unsigned short i; - for(i = 0; i <= 0x08; i++) { + for (i = 0; i <= 0x08; i++) { GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i]; SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3ce, i, GRdata); } @@ -544,12 +444,11 @@ SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) /* CLEAR EXTENDED REGISTERS */ /*********************************************/ -static void -SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo) +static void SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo) { int i; - for(i = 0x0A; i <= 0x0E; i++) { + for (i = 0x0A; i <= 0x0E; i++) { SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, 0x00); } @@ -562,15 +461,16 @@ SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo) static unsigned short SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex) + unsigned short ModeIdIndex) { unsigned short rrti, i, index, temp; if (ModeNo <= 0x13) return 0xFFFF; - index = SiS_GetReg(SiS_Pr,SiS_Pr->SiS_P3d4, 0x33) & 0x0F; - if (index > 0) index--; + index = SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x33) & 0x0F; + if (index > 0) + index--; rrti = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; ModeNo = SiS_Pr->SiS_RefIndex[rrti].ModeID; @@ -580,13 +480,14 @@ SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, if (SiS_Pr->SiS_RefIndex[rrti + i].ModeID != ModeNo) break; - temp = SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask; + temp = + SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask; if (temp < SiS_Pr->SiS_ModeType) break; i++; index--; - } while(index != 0xFFFF); + } while (index != 0xFFFF); i--; @@ -597,8 +498,7 @@ SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, /* SYNC */ /*********************************************/ -static void -SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti) +static void SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti) { unsigned short sync = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag >> 8; sync &= 0xC0; @@ -612,39 +512,40 @@ SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti) static void SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex, unsigned short rrti) + unsigned short ModeIdIndex, unsigned short rrti) { - unsigned char index; + unsigned char index; unsigned short temp, i, j, modeflag; - SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4,0x11,0x7f); + SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f); modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRT1CRTC; - for(i = 0,j = 0; i <= 7; i++, j++) { + for (i = 0, j = 0; i <= 7; i++, j++) { SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j, - SiS_Pr->SiS_CRT1Table[index].CR[i]); + SiS_Pr->SiS_CRT1Table[index].CR[i]); } - for(j = 0x10; i <= 10; i++, j++) { + for (j = 0x10; i <= 10; i++, j++) { SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j, - SiS_Pr->SiS_CRT1Table[index].CR[i]); + SiS_Pr->SiS_CRT1Table[index].CR[i]); } - for(j = 0x15; i <= 12; i++, j++) { + for (j = 0x15; i <= 12; i++, j++) { SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j, - SiS_Pr->SiS_CRT1Table[index].CR[i]); + SiS_Pr->SiS_CRT1Table[index].CR[i]); } - for(j = 0x0A; i <= 15; i++, j++) { + for (j = 0x0A; i <= 15; i++, j++) { SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, j, - SiS_Pr->SiS_CRT1Table[index].CR[i]); + SiS_Pr->SiS_CRT1Table[index].CR[i]); } temp = SiS_Pr->SiS_CRT1Table[index].CR[16] & 0xE0; - SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4, 0x0E, temp); + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0E, temp); temp = ((SiS_Pr->SiS_CRT1Table[index].CR[16]) & 0x01) << 5; - if (modeflag & DoubleScanMode) temp |= 0x80; + if (modeflag & DoubleScanMode) + temp |= 0x80; SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3d4, 0x09, 0x5F, temp); if (SiS_Pr->SiS_ModeType > ModeVGA) @@ -659,10 +560,10 @@ SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static void SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex, unsigned short rrti) + unsigned short ModeIdIndex, unsigned short rrti) { unsigned short du = SiS_GetOffset(SiS_Pr, ModeNo, ModeIdIndex, rrti); - unsigned short infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag; + unsigned short infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag; unsigned short temp; temp = (du >> 8) & 0x0f; @@ -670,11 +571,13 @@ SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x13, (du & 0xFF)); - if (infoflag & InterlaceMode) du >>= 1; + if (infoflag & InterlaceMode) + du >>= 1; du <<= 5; temp = (du >> 8) & 0xff; - if (du & 0xff) temp++; + if (du & 0xff) + temp++; temp++; SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x10, temp); } @@ -685,17 +588,17 @@ SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static void SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short rrti) + unsigned short rrti) { unsigned short index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRTVCLK; unsigned short clka = SiS_Pr->SiS_VCLKData[index].SR2B; unsigned short clkb = SiS_Pr->SiS_VCLKData[index].SR2C; - SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4,0x31,0xCF); + SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x31, 0xCF); - SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2B,clka); - SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2C,clkb); - SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2D,0x01); + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2B, clka); + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2C, clkb); + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2D, 0x01); } /*********************************************/ @@ -704,7 +607,7 @@ SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static void SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short mi) + unsigned short mi) { unsigned short modeflag = SiS_Pr->SiS_EModeIDTable[mi].Ext_ModeFlag; @@ -729,7 +632,7 @@ SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static void SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short rrti) + unsigned short rrti) { unsigned short data = 0, VCLK = 0, index = 0; @@ -738,7 +641,8 @@ SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo, VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK; } - if (VCLK >= 166) data |= 0x0c; + if (VCLK >= 166) + data |= 0x0c; SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x32, 0xf3, data); if (VCLK >= 166) @@ -758,7 +662,7 @@ SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static void SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex, unsigned short rrti) + unsigned short ModeIdIndex, unsigned short rrti) { unsigned short data, infoflag = 0, modeflag; @@ -778,17 +682,22 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, data |= 0x02; data |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2); } - if (infoflag & InterlaceMode) data |= 0x20; + if (infoflag & InterlaceMode) + data |= 0x20; } SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x06, 0xC0, data); data = 0; if (infoflag & InterlaceMode) { /* data = (Hsync / 8) - ((Htotal / 8) / 2) + 3 */ - unsigned short hrs = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) | - ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2)) - 3; - unsigned short hto = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) | - ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8)) + 5; + unsigned short hrs = + (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) | + ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2)) + - 3; + unsigned short hto = + (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) | + ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8)) + + 5; data = hrs - (hto >> 1) + 3; } SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x19, (data & 0xFF)); @@ -829,20 +738,26 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static void SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData, - unsigned short shiftflag, unsigned short dl, unsigned short ah, - unsigned short al, unsigned short dh) + unsigned short shiftflag, unsigned short dl, unsigned short ah, + unsigned short al, unsigned short dh) { unsigned short d1, d2, d3; switch (dl) { - case 0: - d1 = dh; d2 = ah; d3 = al; - break; - case 1: - d1 = ah; d2 = al; d3 = dh; - break; - default: - d1 = al; d2 = dh; d3 = ah; + case 0: + d1 = dh; + d2 = ah; + d3 = al; + break; + case 1: + d1 = ah; + d2 = al; + d3 = dh; + break; + default: + d1 = al; + d2 = dh; + d3 = ah; } SiS_SetRegByte(SiS_Pr, DACData, (d1 << shiftflag)); SiS_SetRegByte(SiS_Pr, DACData, (d2 << shiftflag)); @@ -850,7 +765,8 @@ SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData, } static void -SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi) +SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short mi) { unsigned short data, data2, time, i, j, k, m, n, o; unsigned short si, di, bx, sf; @@ -884,41 +800,45 @@ SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi SiS_SetRegByte(SiS_Pr, DACAddr, 0x00); - for(i = 0; i < j; i++) { + for (i = 0; i < j; i++) { data = table[i]; - for(k = 0; k < 3; k++) { + for (k = 0; k < 3; k++) { data2 = 0; - if (data & 0x01) data2 += 0x2A; - if (data & 0x02) data2 += 0x15; + if (data & 0x01) + data2 += 0x2A; + if (data & 0x02) + data2 += 0x15; SiS_SetRegByte(SiS_Pr, DACData, (data2 << sf)); data >>= 2; } } if (time == 256) { - for(i = 16; i < 32; i++) { + for (i = 16; i < 32; i++) { data = table[i] << sf; - for(k = 0; k < 3; k++) + for (k = 0; k < 3; k++) SiS_SetRegByte(SiS_Pr, DACData, data); } si = 32; - for(m = 0; m < 9; m++) { + for (m = 0; m < 9; m++) { di = si; bx = si + 4; - for(n = 0; n < 3; n++) { - for(o = 0; o < 5; o++) { + for (n = 0; n < 3; n++) { + for (o = 0; o < 5; o++) { SiS_WriteDAC(SiS_Pr, DACData, sf, n, - table[di], table[bx], table[si]); + table[di], table[bx], + table[si]); si++; } si -= 2; - for(o = 0; o < 3; o++) { + for (o = 0; o < 3; o++) { SiS_WriteDAC(SiS_Pr, DACData, sf, n, - table[di], table[si], table[bx]); + table[di], table[si], + table[bx]); si--; } } - si += 5; + si += 5; } } } @@ -929,7 +849,7 @@ SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi static void SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex) + unsigned short ModeIdIndex) { unsigned short StandTableIndex, rrti; @@ -970,11 +890,10 @@ SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo, /* SiSSetMode() */ /*********************************************/ -int -SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) +int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) { unsigned short ModeIdIndex; - unsigned long BaseAddr = SiS_Pr->IOAddress; + unsigned long BaseAddr = SiS_Pr->IOAddress; SiSUSB_InitPtr(SiS_Pr); SiSUSBRegInit(SiS_Pr, BaseAddr); @@ -990,7 +909,7 @@ SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) ModeNo &= 0x7f; SiS_Pr->SiS_ModeType = - SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask; + SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask; SiS_Pr->SiS_SetFlag = LowModeTests; @@ -1008,8 +927,7 @@ SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) return 1; } -int -SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo) +int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo) { unsigned short ModeNo = 0; int i; @@ -1041,7 +959,3 @@ SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo) } #endif /* INCL_SISUSB_CON */ - - - - diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.h b/drivers/usb/misc/sisusbvga/sisusb_init.h index 864bc0e96591..c46ce42d4489 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_init.h +++ b/drivers/usb/misc/sisusbvga/sisusb_init.h @@ -46,7 +46,7 @@ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Author: Thomas Winischhofer <thomas@winischhofer.net> + * Author: Thomas Winischhofer <thomas@winischhofer.net> * */ @@ -76,21 +76,21 @@ #define CRT2Mode 0x0800 #define HalfDCLK 0x1000 #define NoSupportSimuTV 0x2000 -#define NoSupportLCDScale 0x4000 /* SiS bridge: No scaling possible (no matter what panel) */ +#define NoSupportLCDScale 0x4000 /* SiS bridge: No scaling possible (no matter what panel) */ #define DoubleScanMode 0x8000 /* Infoflag */ #define SupportTV 0x0008 #define SupportTV1024 0x0800 -#define SupportCHTV 0x0800 -#define Support64048060Hz 0x0800 /* Special for 640x480 LCD */ +#define SupportCHTV 0x0800 +#define Support64048060Hz 0x0800 /* Special for 640x480 LCD */ #define SupportHiVision 0x0010 #define SupportYPbPr750p 0x1000 #define SupportLCD 0x0020 #define SupportRAMDAC2 0x0040 /* All (<= 100Mhz) */ -#define SupportRAMDAC2_135 0x0100 /* All except DH (<= 135Mhz) */ -#define SupportRAMDAC2_162 0x0200 /* B, C (<= 162Mhz) */ -#define SupportRAMDAC2_202 0x0400 /* C (<= 202Mhz) */ +#define SupportRAMDAC2_135 0x0100 /* All except DH (<= 135Mhz) */ +#define SupportRAMDAC2_162 0x0200 /* B, C (<= 162Mhz) */ +#define SupportRAMDAC2_202 0x0400 /* C (<= 202Mhz) */ #define InterlaceMode 0x0080 #define SyncPP 0x0000 #define SyncPN 0x4000 @@ -129,7 +129,7 @@ #define SIS_RI_856x480 19 #define SIS_RI_1280x768 20 #define SIS_RI_1400x1050 21 -#define SIS_RI_1152x864 22 /* Up to here SiS conforming */ +#define SIS_RI_1152x864 22 /* Up to here SiS conforming */ #define SIS_RI_848x480 23 #define SIS_RI_1360x768 24 #define SIS_RI_1024x600 25 @@ -147,691 +147,691 @@ #define SIS_CRT2_PORT_04 0x04 - 0x30 /* Mode numbers */ -static const unsigned short ModeIndex_320x200[] = {0x59, 0x41, 0x00, 0x4f}; -static const unsigned short ModeIndex_320x240[] = {0x50, 0x56, 0x00, 0x53}; -static const unsigned short ModeIndex_400x300[] = {0x51, 0x57, 0x00, 0x54}; -static const unsigned short ModeIndex_512x384[] = {0x52, 0x58, 0x00, 0x5c}; -static const unsigned short ModeIndex_640x400[] = {0x2f, 0x5d, 0x00, 0x5e}; -static const unsigned short ModeIndex_640x480[] = {0x2e, 0x44, 0x00, 0x62}; -static const unsigned short ModeIndex_720x480[] = {0x31, 0x33, 0x00, 0x35}; -static const unsigned short ModeIndex_720x576[] = {0x32, 0x34, 0x00, 0x36}; -static const unsigned short ModeIndex_768x576[] = {0x5f, 0x60, 0x00, 0x61}; -static const unsigned short ModeIndex_800x480[] = {0x70, 0x7a, 0x00, 0x76}; -static const unsigned short ModeIndex_800x600[] = {0x30, 0x47, 0x00, 0x63}; -static const unsigned short ModeIndex_848x480[] = {0x39, 0x3b, 0x00, 0x3e}; -static const unsigned short ModeIndex_856x480[] = {0x3f, 0x42, 0x00, 0x45}; -static const unsigned short ModeIndex_960x540[] = {0x1d, 0x1e, 0x00, 0x1f}; -static const unsigned short ModeIndex_960x600[] = {0x20, 0x21, 0x00, 0x22}; -static const unsigned short ModeIndex_1024x768[] = {0x38, 0x4a, 0x00, 0x64}; -static const unsigned short ModeIndex_1024x576[] = {0x71, 0x74, 0x00, 0x77}; -static const unsigned short ModeIndex_1152x864[] = {0x29, 0x2a, 0x00, 0x2b}; -static const unsigned short ModeIndex_1280x720[] = {0x79, 0x75, 0x00, 0x78}; -static const unsigned short ModeIndex_1280x768[] = {0x23, 0x24, 0x00, 0x25}; -static const unsigned short ModeIndex_1280x1024[] = {0x3a, 0x4d, 0x00, 0x65}; +static const unsigned short ModeIndex_320x200[] = { 0x59, 0x41, 0x00, 0x4f }; +static const unsigned short ModeIndex_320x240[] = { 0x50, 0x56, 0x00, 0x53 }; +static const unsigned short ModeIndex_400x300[] = { 0x51, 0x57, 0x00, 0x54 }; +static const unsigned short ModeIndex_512x384[] = { 0x52, 0x58, 0x00, 0x5c }; +static const unsigned short ModeIndex_640x400[] = { 0x2f, 0x5d, 0x00, 0x5e }; +static const unsigned short ModeIndex_640x480[] = { 0x2e, 0x44, 0x00, 0x62 }; +static const unsigned short ModeIndex_720x480[] = { 0x31, 0x33, 0x00, 0x35 }; +static const unsigned short ModeIndex_720x576[] = { 0x32, 0x34, 0x00, 0x36 }; +static const unsigned short ModeIndex_768x576[] = { 0x5f, 0x60, 0x00, 0x61 }; +static const unsigned short ModeIndex_800x480[] = { 0x70, 0x7a, 0x00, 0x76 }; +static const unsigned short ModeIndex_800x600[] = { 0x30, 0x47, 0x00, 0x63 }; +static const unsigned short ModeIndex_848x480[] = { 0x39, 0x3b, 0x00, 0x3e }; +static const unsigned short ModeIndex_856x480[] = { 0x3f, 0x42, 0x00, 0x45 }; +static const unsigned short ModeIndex_960x540[] = { 0x1d, 0x1e, 0x00, 0x1f }; +static const unsigned short ModeIndex_960x600[] = { 0x20, 0x21, 0x00, 0x22 }; +static const unsigned short ModeIndex_1024x768[] = { 0x38, 0x4a, 0x00, 0x64 }; +static const unsigned short ModeIndex_1024x576[] = { 0x71, 0x74, 0x00, 0x77 }; +static const unsigned short ModeIndex_1152x864[] = { 0x29, 0x2a, 0x00, 0x2b }; +static const unsigned short ModeIndex_1280x720[] = { 0x79, 0x75, 0x00, 0x78 }; +static const unsigned short ModeIndex_1280x768[] = { 0x23, 0x24, 0x00, 0x25 }; +static const unsigned short ModeIndex_1280x1024[] = { 0x3a, 0x4d, 0x00, 0x65 }; -static const unsigned char SiS_MDA_DAC[] = -{ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, - 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, - 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, - 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, - 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F +static const unsigned char SiS_MDA_DAC[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F }; -static const unsigned char SiS_CGA_DAC[] = -{ - 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, - 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, - 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, - 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F +static const unsigned char SiS_CGA_DAC[] = { + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F }; -static const unsigned char SiS_EGA_DAC[] = -{ - 0x00,0x10,0x04,0x14,0x01,0x11,0x05,0x15, - 0x20,0x30,0x24,0x34,0x21,0x31,0x25,0x35, - 0x08,0x18,0x0C,0x1C,0x09,0x19,0x0D,0x1D, - 0x28,0x38,0x2C,0x3C,0x29,0x39,0x2D,0x3D, - 0x02,0x12,0x06,0x16,0x03,0x13,0x07,0x17, - 0x22,0x32,0x26,0x36,0x23,0x33,0x27,0x37, - 0x0A,0x1A,0x0E,0x1E,0x0B,0x1B,0x0F,0x1F, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F +static const unsigned char SiS_EGA_DAC[] = { + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x05, 0x15, + 0x20, 0x30, 0x24, 0x34, 0x21, 0x31, 0x25, 0x35, + 0x08, 0x18, 0x0C, 0x1C, 0x09, 0x19, 0x0D, 0x1D, + 0x28, 0x38, 0x2C, 0x3C, 0x29, 0x39, 0x2D, 0x3D, + 0x02, 0x12, 0x06, 0x16, 0x03, 0x13, 0x07, 0x17, + 0x22, 0x32, 0x26, 0x36, 0x23, 0x33, 0x27, 0x37, + 0x0A, 0x1A, 0x0E, 0x1E, 0x0B, 0x1B, 0x0F, 0x1F, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F }; -static const unsigned char SiS_VGA_DAC[] = -{ - 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, - 0x00,0x05,0x08,0x0B,0x0E,0x11,0x14,0x18, - 0x1C,0x20,0x24,0x28,0x2D,0x32,0x38,0x3F, - 0x00,0x10,0x1F,0x2F,0x3F,0x1F,0x27,0x2F, - 0x37,0x3F,0x2D,0x31,0x36,0x3A,0x3F,0x00, - 0x07,0x0E,0x15,0x1C,0x0E,0x11,0x15,0x18, - 0x1C,0x14,0x16,0x18,0x1A,0x1C,0x00,0x04, - 0x08,0x0C,0x10,0x08,0x0A,0x0C,0x0E,0x10, - 0x0B,0x0C,0x0D,0x0F,0x10 +static const unsigned char SiS_VGA_DAC[] = { + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x00, 0x05, 0x08, 0x0B, 0x0E, 0x11, 0x14, 0x18, + 0x1C, 0x20, 0x24, 0x28, 0x2D, 0x32, 0x38, 0x3F, + 0x00, 0x10, 0x1F, 0x2F, 0x3F, 0x1F, 0x27, 0x2F, + 0x37, 0x3F, 0x2D, 0x31, 0x36, 0x3A, 0x3F, 0x00, + 0x07, 0x0E, 0x15, 0x1C, 0x0E, 0x11, 0x15, 0x18, + 0x1C, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x00, 0x04, + 0x08, 0x0C, 0x10, 0x08, 0x0A, 0x0C, 0x0E, 0x10, + 0x0B, 0x0C, 0x0D, 0x0F, 0x10 }; -static const struct SiS_St SiSUSB_SModeIDTable[] = -{ - {0x03,0x0010,0x18,0x02,0x02,0x00,0x01,0x03,0x40}, - {0xff,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00} +static const struct SiS_St SiSUSB_SModeIDTable[] = { + {0x03, 0x0010, 0x18, 0x02, 0x02, 0x00, 0x01, 0x03, 0x40}, + {0xff, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }; -static const struct SiS_StResInfo_S SiSUSB_StResInfo[] = -{ - { 640,400}, - { 640,350}, - { 720,400}, - { 720,350}, - { 640,480} +static const struct SiS_StResInfo_S SiSUSB_StResInfo[] = { + {640, 400}, + {640, 350}, + {720, 400}, + {720, 350}, + {640, 480} }; -static const struct SiS_ModeResInfo SiSUSB_ModeResInfo[] = -{ - { 320, 200, 8, 8}, /* 0x00 */ - { 320, 240, 8, 8}, /* 0x01 */ - { 320, 400, 8, 8}, /* 0x02 */ - { 400, 300, 8, 8}, /* 0x03 */ - { 512, 384, 8, 8}, /* 0x04 */ - { 640, 400, 8,16}, /* 0x05 */ - { 640, 480, 8,16}, /* 0x06 */ - { 800, 600, 8,16}, /* 0x07 */ - { 1024, 768, 8,16}, /* 0x08 */ - { 1280,1024, 8,16}, /* 0x09 */ - { 1600,1200, 8,16}, /* 0x0a */ - { 1920,1440, 8,16}, /* 0x0b */ - { 2048,1536, 8,16}, /* 0x0c */ - { 720, 480, 8,16}, /* 0x0d */ - { 720, 576, 8,16}, /* 0x0e */ - { 1280, 960, 8,16}, /* 0x0f */ - { 800, 480, 8,16}, /* 0x10 */ - { 1024, 576, 8,16}, /* 0x11 */ - { 1280, 720, 8,16}, /* 0x12 */ - { 856, 480, 8,16}, /* 0x13 */ - { 1280, 768, 8,16}, /* 0x14 */ - { 1400,1050, 8,16}, /* 0x15 */ - { 1152, 864, 8,16}, /* 0x16 */ - { 848, 480, 8,16}, /* 0x17 */ - { 1360, 768, 8,16}, /* 0x18 */ - { 1024, 600, 8,16}, /* 0x19 */ - { 1152, 768, 8,16}, /* 0x1a */ - { 768, 576, 8,16}, /* 0x1b */ - { 1360,1024, 8,16}, /* 0x1c */ - { 1680,1050, 8,16}, /* 0x1d */ - { 1280, 800, 8,16}, /* 0x1e */ - { 1920,1080, 8,16}, /* 0x1f */ - { 960, 540, 8,16}, /* 0x20 */ - { 960, 600, 8,16} /* 0x21 */ +static const struct SiS_ModeResInfo SiSUSB_ModeResInfo[] = { + {320, 200, 8, 8}, /* 0x00 */ + {320, 240, 8, 8}, /* 0x01 */ + {320, 400, 8, 8}, /* 0x02 */ + {400, 300, 8, 8}, /* 0x03 */ + {512, 384, 8, 8}, /* 0x04 */ + {640, 400, 8, 16}, /* 0x05 */ + {640, 480, 8, 16}, /* 0x06 */ + {800, 600, 8, 16}, /* 0x07 */ + {1024, 768, 8, 16}, /* 0x08 */ + {1280, 1024, 8, 16}, /* 0x09 */ + {1600, 1200, 8, 16}, /* 0x0a */ + {1920, 1440, 8, 16}, /* 0x0b */ + {2048, 1536, 8, 16}, /* 0x0c */ + {720, 480, 8, 16}, /* 0x0d */ + {720, 576, 8, 16}, /* 0x0e */ + {1280, 960, 8, 16}, /* 0x0f */ + {800, 480, 8, 16}, /* 0x10 */ + {1024, 576, 8, 16}, /* 0x11 */ + {1280, 720, 8, 16}, /* 0x12 */ + {856, 480, 8, 16}, /* 0x13 */ + {1280, 768, 8, 16}, /* 0x14 */ + {1400, 1050, 8, 16}, /* 0x15 */ + {1152, 864, 8, 16}, /* 0x16 */ + {848, 480, 8, 16}, /* 0x17 */ + {1360, 768, 8, 16}, /* 0x18 */ + {1024, 600, 8, 16}, /* 0x19 */ + {1152, 768, 8, 16}, /* 0x1a */ + {768, 576, 8, 16}, /* 0x1b */ + {1360, 1024, 8, 16}, /* 0x1c */ + {1680, 1050, 8, 16}, /* 0x1d */ + {1280, 800, 8, 16}, /* 0x1e */ + {1920, 1080, 8, 16}, /* 0x1f */ + {960, 540, 8, 16}, /* 0x20 */ + {960, 600, 8, 16} /* 0x21 */ }; -static const struct SiS_StandTable SiSUSB_StandTable[] = -{ +static const struct SiS_StandTable SiSUSB_StandTable[] = { /* MD_3_400 - mode 0x03 - 400 */ { - 0x50,0x18,0x10,0x1000, - { 0x00,0x03,0x00,0x02 }, - 0x67, - { 0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, - 0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00, - 0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3, - 0xff }, - { 0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, - 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, - 0x0c,0x00,0x0f,0x08 }, - { 0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, 0xff } - }, + 0x50, 0x18, 0x10, 0x1000, + {0x00, 0x03, 0x00, 0x02}, + 0x67, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x0c, 0x00, 0x0f, 0x08}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff} + }, /* Generic for VGA and higher */ { - 0x00,0x00,0x00,0x0000, - { 0x01,0x0f,0x00,0x0e }, - 0x23, - { 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e, - 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, - 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3, - 0xff }, - { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, - 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, - 0x01,0x00,0x00,0x00 }, - { 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f, 0xff } - } + 0x00, 0x00, 0x00, 0x0000, + {0x01, 0x0f, 0x00, 0x0e}, + 0x23, + {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x01, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff} + } }; -static const struct SiS_Ext SiSUSB_EModeIDTable[] = -{ - {0x2e,0x0a1b,0x0101,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x8 */ - {0x2f,0x0a1b,0x0100,SIS_RI_640x400, 0x00,0x00,0x05,0x05,0x10, 0}, /* 640x400x8 */ - {0x30,0x2a1b,0x0103,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x8 */ - {0x31,0x4a1b,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x8 */ - {0x32,0x4a1b,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x8 */ - {0x33,0x4a1d,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x16 */ - {0x34,0x6a1d,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x16 */ - {0x35,0x4a1f,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x32 */ - {0x36,0x6a1f,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x32 */ - {0x38,0x0a1b,0x0105,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x8 */ - {0x3a,0x0e3b,0x0107,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x8 */ - {0x41,0x9a1d,0x010e,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x16 */ - {0x44,0x0a1d,0x0111,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x16 */ - {0x47,0x2a1d,0x0114,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x16 */ - {0x4a,0x0a3d,0x0117,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x16 */ - {0x4d,0x0e7d,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x16 */ - {0x50,0x9a1b,0x0132,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x8 */ - {0x51,0xba1b,0x0133,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x8 */ - {0x52,0xba1b,0x0134,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x8 */ - {0x56,0x9a1d,0x0135,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x16 */ - {0x57,0xba1d,0x0136,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x16 */ - {0x58,0xba1d,0x0137,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x16 */ - {0x59,0x9a1b,0x0138,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x8 */ - {0x5c,0xba1f,0x0000,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x32 */ - {0x5d,0x0a1d,0x0139,SIS_RI_640x400, 0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x16 */ - {0x5e,0x0a1f,0x0000,SIS_RI_640x400, 0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x32 */ - {0x62,0x0a3f,0x013a,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x32 */ - {0x63,0x2a3f,0x013b,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x32 */ - {0x64,0x0a7f,0x013c,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x32 */ - {0x65,0x0eff,0x013d,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x32 */ - {0x70,0x6a1b,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x8 */ - {0x71,0x4a1b,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x8 */ - {0x74,0x4a1d,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x16 */ - {0x75,0x0a3d,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x16 */ - {0x76,0x6a1f,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x32 */ - {0x77,0x4a1f,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x32 */ - {0x78,0x0a3f,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x32 */ - {0x79,0x0a3b,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x8 */ - {0x7a,0x6a1d,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x16 */ - {0x23,0x0e3b,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x8 */ - {0x24,0x0e7d,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x16 */ - {0x25,0x0eff,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x32 */ - {0x39,0x6a1b,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x28,-1}, /* 848x480 */ - {0x3b,0x6a3d,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x28,-1}, - {0x3e,0x6a7f,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x28,-1}, - {0x3f,0x6a1b,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x2a,-1}, /* 856x480 */ - {0x42,0x6a3d,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x2a,-1}, - {0x45,0x6a7f,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x2a,-1}, - {0x4f,0x9a1f,0x0000,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x32 */ - {0x53,0x9a1f,0x0000,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x32 */ - {0x54,0xba1f,0x0000,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x32 */ - {0x5f,0x6a1b,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x2c,-1}, /* 768x576 */ - {0x60,0x6a1d,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x2c,-1}, - {0x61,0x6a3f,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x2c,-1}, - {0x1d,0x6a1b,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x2d,-1}, /* 960x540 */ - {0x1e,0x6a3d,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x2d,-1}, - {0x1f,0x6a7f,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x2d,-1}, - {0x20,0x6a1b,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x2e,-1}, /* 960x600 */ - {0x21,0x6a3d,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x2e,-1}, - {0x22,0x6a7f,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x2e,-1}, - {0x29,0x4e1b,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1}, /* 1152x864 */ - {0x2a,0x4e3d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1}, - {0x2b,0x4e7f,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1}, - {0xff,0x0000,0x0000,0, 0x00,0x00,0x00,0x00,0x00,-1} +static const struct SiS_Ext SiSUSB_EModeIDTable[] = { + {0x2e, 0x0a1b, 0x0101, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x8 */ + {0x2f, 0x0a1b, 0x0100, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x05, 0x10, 0}, /* 640x400x8 */ + {0x30, 0x2a1b, 0x0103, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x8 */ + {0x31, 0x4a1b, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x8 */ + {0x32, 0x4a1b, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x8 */ + {0x33, 0x4a1d, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x16 */ + {0x34, 0x6a1d, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x16 */ + {0x35, 0x4a1f, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x32 */ + {0x36, 0x6a1f, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x32 */ + {0x38, 0x0a1b, 0x0105, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x8 */ + {0x3a, 0x0e3b, 0x0107, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x8 */ + {0x41, 0x9a1d, 0x010e, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x16 */ + {0x44, 0x0a1d, 0x0111, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x16 */ + {0x47, 0x2a1d, 0x0114, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x16 */ + {0x4a, 0x0a3d, 0x0117, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x16 */ + {0x4d, 0x0e7d, 0x011a, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x16 */ + {0x50, 0x9a1b, 0x0132, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x8 */ + {0x51, 0xba1b, 0x0133, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x8 */ + {0x52, 0xba1b, 0x0134, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x8 */ + {0x56, 0x9a1d, 0x0135, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x16 */ + {0x57, 0xba1d, 0x0136, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x16 */ + {0x58, 0xba1d, 0x0137, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x16 */ + {0x59, 0x9a1b, 0x0138, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x8 */ + {0x5c, 0xba1f, 0x0000, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x32 */ + {0x5d, 0x0a1d, 0x0139, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0}, /* 640x400x16 */ + {0x5e, 0x0a1f, 0x0000, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0}, /* 640x400x32 */ + {0x62, 0x0a3f, 0x013a, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x32 */ + {0x63, 0x2a3f, 0x013b, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x32 */ + {0x64, 0x0a7f, 0x013c, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x32 */ + {0x65, 0x0eff, 0x013d, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x32 */ + {0x70, 0x6a1b, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x8 */ + {0x71, 0x4a1b, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x8 */ + {0x74, 0x4a1d, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x16 */ + {0x75, 0x0a3d, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x16 */ + {0x76, 0x6a1f, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x32 */ + {0x77, 0x4a1f, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x32 */ + {0x78, 0x0a3f, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x32 */ + {0x79, 0x0a3b, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x8 */ + {0x7a, 0x6a1d, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x16 */ + {0x23, 0x0e3b, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x8 */ + {0x24, 0x0e7d, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x16 */ + {0x25, 0x0eff, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x32 */ + {0x39, 0x6a1b, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, -1}, /* 848x480 */ + {0x3b, 0x6a3d, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, + -1}, + {0x3e, 0x6a7f, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, + -1}, + {0x3f, 0x6a1b, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, -1}, /* 856x480 */ + {0x42, 0x6a3d, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, + -1}, + {0x45, 0x6a7f, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, + -1}, + {0x4f, 0x9a1f, 0x0000, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x32 */ + {0x53, 0x9a1f, 0x0000, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x32 */ + {0x54, 0xba1f, 0x0000, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x32 */ + {0x5f, 0x6a1b, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, -1}, /* 768x576 */ + {0x60, 0x6a1d, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, + -1}, + {0x61, 0x6a3f, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, + -1}, + {0x1d, 0x6a1b, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, -1}, /* 960x540 */ + {0x1e, 0x6a3d, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, + -1}, + {0x1f, 0x6a7f, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, + -1}, + {0x20, 0x6a1b, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, -1}, /* 960x600 */ + {0x21, 0x6a3d, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, + -1}, + {0x22, 0x6a7f, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, + -1}, + {0x29, 0x4e1b, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, -1}, /* 1152x864 */ + {0x2a, 0x4e3d, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, + -1}, + {0x2b, 0x4e7f, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, + -1}, + {0xff, 0x0000, 0x0000, 0, 0x00, 0x00, 0x00, 0x00, 0x00, -1} }; -static const struct SiS_Ext2 SiSUSB_RefIndex[] = -{ - {0x085f,0x0d,0x03,0x05,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x0 */ - {0x0067,0x0e,0x04,0x05,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x1 */ - {0x0067,0x0f,0x08,0x48,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x2 */ - {0x0067,0x10,0x07,0x8b,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x3 */ - {0x0047,0x11,0x0a,0x00,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x4 */ - {0x0047,0x12,0x0d,0x00,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x5 */ - {0x0047,0x13,0x13,0x00,0x05,0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x6 */ - {0x0107,0x14,0x1c,0x00,0x05,0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x7 */ - {0xc85f,0x05,0x00,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x8 */ - {0xc067,0x06,0x02,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x9 */ - {0xc067,0x07,0x02,0x47,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xa */ - {0xc067,0x08,0x03,0x8a,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xb */ - {0xc047,0x09,0x05,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xc */ - {0xc047,0x0a,0x09,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xd */ - {0xc047,0x0b,0x0e,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xe */ - {0xc047,0x0c,0x15,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xf */ - {0x487f,0x04,0x00,0x00,0x00,0x2f, 640, 400, 0x30, 0x55, 0x6e}, /* 0x10 */ - {0xc06f,0x3c,0x01,0x06,0x13,0x31, 720, 480, 0x30, 0x00, 0x00}, /* 0x11 */ - {0x006f,0x3d,0x6f,0x06,0x14,0x32, 720, 576, 0x30, 0x00, 0x00}, /* 0x12 (6f was 03) */ - {0x0087,0x15,0x06,0x00,0x06,0x38,1024, 768, 0x30, 0x00, 0x00}, /* 0x13 */ - {0xc877,0x16,0x0b,0x06,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x14 */ - {0xc067,0x17,0x0f,0x49,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x15 */ - {0x0067,0x18,0x11,0x00,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x16 */ - {0x0047,0x19,0x16,0x8c,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x17 */ - {0x0107,0x1a,0x1b,0x00,0x06,0x38,1024, 768, 0x10, 0x00, 0x00}, /* 0x18 */ - {0x0107,0x1b,0x1f,0x00,0x06,0x38,1024, 768, 0x10, 0x00, 0x00}, /* 0x19 */ - {0x407f,0x00,0x00,0x00,0x00,0x41, 320, 200, 0x30, 0x56, 0x4e}, /* 0x1a */ - {0xc07f,0x01,0x00,0x04,0x04,0x50, 320, 240, 0x30, 0x00, 0x00}, /* 0x1b */ - {0x007f,0x02,0x04,0x05,0x05,0x51, 400, 300, 0x30, 0x00, 0x00}, /* 0x1c */ - {0xc077,0x03,0x0b,0x06,0x06,0x52, 512, 384, 0x30, 0x00, 0x00}, /* 0x1d */ - {0x0077,0x32,0x40,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1e */ - {0x0047,0x33,0x07,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1f */ - {0x0047,0x34,0x0a,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x20 */ - {0x0077,0x35,0x0b,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x21 */ - {0x0047,0x36,0x11,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x22 */ - {0x0047,0x37,0x16,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x23 */ - {0x1137,0x38,0x19,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x24 */ - {0x1107,0x39,0x1e,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x25 */ - {0x1307,0x3a,0x20,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x26 */ - {0x0077,0x42,0x5b,0x08,0x11,0x23,1280, 768, 0x30, 0x00, 0x00}, /* 0x27 */ - {0x0087,0x45,0x57,0x00,0x16,0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x28 38Hzi */ - {0xc067,0x46,0x55,0x0b,0x16,0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x29 848x480-60Hz */ - {0x0087,0x47,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2a 856x480-38Hzi */ - {0xc067,0x48,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2b 856x480-60Hz */ - {0x006f,0x4d,0x71,0x06,0x15,0x5f, 768, 576, 0x30, 0x00, 0x00}, /* 0x2c 768x576-56Hz */ - {0x0067,0x52,0x6a,0x00,0x1c,0x1d, 960, 540, 0x30, 0x00, 0x00}, /* 0x2d 960x540 60Hz */ - {0x0077,0x53,0x6b,0x0b,0x1d,0x20, 960, 600, 0x30, 0x00, 0x00}, /* 0x2e 960x600 60Hz */ - {0x0087,0x1c,0x11,0x00,0x07,0x3a,1280,1024, 0x30, 0x00, 0x00}, /* 0x2f */ - {0x0137,0x1d,0x19,0x07,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x30 */ - {0x0107,0x1e,0x1e,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x31 */ - {0x0207,0x1f,0x20,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x32 */ - {0x0127,0x54,0x6d,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x33 1152x864-60Hz */ - {0x0127,0x44,0x19,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x34 1152x864-75Hz */ - {0x0127,0x4a,0x1e,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x35 1152x864-85Hz */ - {0xffff,0x00,0x00,0x00,0x00,0x00, 0, 0, 0, 0x00, 0x00} +static const struct SiS_Ext2 SiSUSB_RefIndex[] = { + {0x085f, 0x0d, 0x03, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x0 */ + {0x0067, 0x0e, 0x04, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x1 */ + {0x0067, 0x0f, 0x08, 0x48, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x2 */ + {0x0067, 0x10, 0x07, 0x8b, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x3 */ + {0x0047, 0x11, 0x0a, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x4 */ + {0x0047, 0x12, 0x0d, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x5 */ + {0x0047, 0x13, 0x13, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x6 */ + {0x0107, 0x14, 0x1c, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x7 */ + {0xc85f, 0x05, 0x00, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x8 */ + {0xc067, 0x06, 0x02, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x9 */ + {0xc067, 0x07, 0x02, 0x47, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xa */ + {0xc067, 0x08, 0x03, 0x8a, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xb */ + {0xc047, 0x09, 0x05, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xc */ + {0xc047, 0x0a, 0x09, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xd */ + {0xc047, 0x0b, 0x0e, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xe */ + {0xc047, 0x0c, 0x15, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xf */ + {0x487f, 0x04, 0x00, 0x00, 0x00, 0x2f, 640, 400, 0x30, 0x55, 0x6e}, /* 0x10 */ + {0xc06f, 0x3c, 0x01, 0x06, 0x13, 0x31, 720, 480, 0x30, 0x00, 0x00}, /* 0x11 */ + {0x006f, 0x3d, 0x6f, 0x06, 0x14, 0x32, 720, 576, 0x30, 0x00, 0x00}, /* 0x12 (6f was 03) */ + {0x0087, 0x15, 0x06, 0x00, 0x06, 0x38, 1024, 768, 0x30, 0x00, 0x00}, /* 0x13 */ + {0xc877, 0x16, 0x0b, 0x06, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x14 */ + {0xc067, 0x17, 0x0f, 0x49, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x15 */ + {0x0067, 0x18, 0x11, 0x00, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x16 */ + {0x0047, 0x19, 0x16, 0x8c, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x17 */ + {0x0107, 0x1a, 0x1b, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00}, /* 0x18 */ + {0x0107, 0x1b, 0x1f, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00}, /* 0x19 */ + {0x407f, 0x00, 0x00, 0x00, 0x00, 0x41, 320, 200, 0x30, 0x56, 0x4e}, /* 0x1a */ + {0xc07f, 0x01, 0x00, 0x04, 0x04, 0x50, 320, 240, 0x30, 0x00, 0x00}, /* 0x1b */ + {0x007f, 0x02, 0x04, 0x05, 0x05, 0x51, 400, 300, 0x30, 0x00, 0x00}, /* 0x1c */ + {0xc077, 0x03, 0x0b, 0x06, 0x06, 0x52, 512, 384, 0x30, 0x00, 0x00}, /* 0x1d */ + {0x0077, 0x32, 0x40, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1e */ + {0x0047, 0x33, 0x07, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1f */ + {0x0047, 0x34, 0x0a, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x20 */ + {0x0077, 0x35, 0x0b, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x21 */ + {0x0047, 0x36, 0x11, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x22 */ + {0x0047, 0x37, 0x16, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x23 */ + {0x1137, 0x38, 0x19, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x24 */ + {0x1107, 0x39, 0x1e, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x25 */ + {0x1307, 0x3a, 0x20, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x26 */ + {0x0077, 0x42, 0x5b, 0x08, 0x11, 0x23, 1280, 768, 0x30, 0x00, 0x00}, /* 0x27 */ + {0x0087, 0x45, 0x57, 0x00, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x28 38Hzi */ + {0xc067, 0x46, 0x55, 0x0b, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x29 848x480-60Hz */ + {0x0087, 0x47, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2a 856x480-38Hzi */ + {0xc067, 0x48, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2b 856x480-60Hz */ + {0x006f, 0x4d, 0x71, 0x06, 0x15, 0x5f, 768, 576, 0x30, 0x00, 0x00}, /* 0x2c 768x576-56Hz */ + {0x0067, 0x52, 0x6a, 0x00, 0x1c, 0x1d, 960, 540, 0x30, 0x00, 0x00}, /* 0x2d 960x540 60Hz */ + {0x0077, 0x53, 0x6b, 0x0b, 0x1d, 0x20, 960, 600, 0x30, 0x00, 0x00}, /* 0x2e 960x600 60Hz */ + {0x0087, 0x1c, 0x11, 0x00, 0x07, 0x3a, 1280, 1024, 0x30, 0x00, 0x00}, /* 0x2f */ + {0x0137, 0x1d, 0x19, 0x07, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x30 */ + {0x0107, 0x1e, 0x1e, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x31 */ + {0x0207, 0x1f, 0x20, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x32 */ + {0x0127, 0x54, 0x6d, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x33 1152x864-60Hz */ + {0x0127, 0x44, 0x19, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x34 1152x864-75Hz */ + {0x0127, 0x4a, 0x1e, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x35 1152x864-85Hz */ + {0xffff, 0x00, 0x00, 0x00, 0x00, 0x00, 0, 0, 0, 0x00, 0x00} }; -static const struct SiS_CRT1Table SiSUSB_CRT1Table[] = -{ - {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f, - 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00, - 0x00}}, /* 0x0 */ - {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e, - 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00, - 0x00}}, /* 0x1 */ - {{0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0, - 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05, - 0x01}}, /* 0x2 */ - {{0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5, - 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01, - 0x01}}, /* 0x3 */ - {{0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, - 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x05, - 0x00}}, /* 0x4 */ - {{0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e, - 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05, - 0x00}}, /* 0x5 */ - {{0x63,0x4f,0x4f,0x87,0x56,0x9b,0x06,0x3e, - 0xe8,0x8a,0xdf,0xe7,0x07,0x00,0x00,0x01, - 0x00}}, /* 0x6 */ - {{0x64,0x4f,0x4f,0x88,0x55,0x9d,0xf2,0x1f, - 0xe0,0x83,0xdf,0xdf,0xf3,0x10,0x00,0x01, - 0x00}}, /* 0x7 */ - {{0x63,0x4f,0x4f,0x87,0x5a,0x81,0xfb,0x1f, - 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05, - 0x00}}, /* 0x8 */ - {{0x65,0x4f,0x4f,0x89,0x58,0x80,0xfb,0x1f, - 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05, - 0x61}}, /* 0x9 */ - {{0x65,0x4f,0x4f,0x89,0x58,0x80,0x01,0x3e, - 0xe0,0x83,0xdf,0xdf,0x02,0x00,0x00,0x05, - 0x61}}, /* 0xa */ - {{0x67,0x4f,0x4f,0x8b,0x58,0x81,0x0d,0x3e, - 0xe0,0x83,0xdf,0xdf,0x0e,0x00,0x00,0x05, - 0x61}}, /* 0xb */ - {{0x65,0x4f,0x4f,0x89,0x57,0x9f,0xfb,0x1f, - 0xe6,0x8a,0xdf,0xdf,0xfc,0x10,0x00,0x01, - 0x00}}, /* 0xc */ - {{0x7b,0x63,0x63,0x9f,0x6a,0x93,0x6f,0xf0, - 0x58,0x8a,0x57,0x57,0x70,0x20,0x00,0x05, - 0x01}}, /* 0xd */ - {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xf0, - 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x06, - 0x01}}, /* 0xe */ - {{0x7d,0x63,0x63,0x81,0x6e,0x1d,0x98,0xf0, - 0x7c,0x82,0x57,0x57,0x99,0x00,0x00,0x06, - 0x01}}, /* 0xf */ - {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xf0, - 0x58,0x8b,0x57,0x57,0x70,0x20,0x00,0x06, - 0x01}}, /* 0x10 */ - {{0x7e,0x63,0x63,0x82,0x6b,0x13,0x75,0xf0, - 0x58,0x8b,0x57,0x57,0x76,0x20,0x00,0x06, - 0x01}}, /* 0x11 */ - {{0x81,0x63,0x63,0x85,0x6d,0x18,0x7a,0xf0, - 0x58,0x8b,0x57,0x57,0x7b,0x20,0x00,0x06, - 0x61}}, /* 0x12 */ - {{0x83,0x63,0x63,0x87,0x6e,0x19,0x81,0xf0, - 0x58,0x8b,0x57,0x57,0x82,0x20,0x00,0x06, - 0x61}}, /* 0x13 */ - {{0x85,0x63,0x63,0x89,0x6f,0x1a,0x91,0xf0, - 0x58,0x8b,0x57,0x57,0x92,0x20,0x00,0x06, - 0x61}}, /* 0x14 */ - {{0x99,0x7f,0x7f,0x9d,0x84,0x1a,0x96,0x1f, - 0x7f,0x83,0x7f,0x7f,0x97,0x10,0x00,0x02, - 0x00}}, /* 0x15 */ - {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5, - 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, - 0x01}}, /* 0x16 */ - {{0xa1,0x7f,0x7f,0x85,0x86,0x97,0x24,0xf5, - 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, - 0x01}}, /* 0x17 */ - {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf5, - 0x00,0x83,0xff,0xff,0x1f,0x10,0x00,0x02, - 0x01}}, /* 0x18 */ - {{0xa7,0x7f,0x7f,0x8b,0x89,0x95,0x26,0xf5, - 0x00,0x83,0xff,0xff,0x27,0x10,0x00,0x02, - 0x01}}, /* 0x19 */ - {{0xa9,0x7f,0x7f,0x8d,0x8c,0x9a,0x2c,0xf5, - 0x00,0x83,0xff,0xff,0x2d,0x14,0x00,0x02, - 0x62}}, /* 0x1a */ - {{0xab,0x7f,0x7f,0x8f,0x8d,0x9b,0x35,0xf5, - 0x00,0x83,0xff,0xff,0x36,0x14,0x00,0x02, - 0x62}}, /* 0x1b */ - {{0xcf,0x9f,0x9f,0x93,0xb2,0x01,0x14,0xba, - 0x00,0x83,0xff,0xff,0x15,0x00,0x00,0x03, - 0x00}}, /* 0x1c */ - {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0x5a, - 0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07, - 0x01}}, /* 0x1d */ - {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0x5a, - 0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07, - 0x01}}, /* 0x1e */ - {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0x5a, - 0x00,0x83,0xff,0xff,0x2f,0x09,0x00,0x07, - 0x01}}, /* 0x1f */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x20 */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x21 */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x22 */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x23 */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x24 */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x25 */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x26 */ - {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, - 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, - 0x00}}, /* 0x27 */ - {{0x43,0xef,0xef,0x87,0x06,0x00,0xd4,0x1f, - 0xa0,0x83,0x9f,0x9f,0xd5,0x1f,0x41,0x05, - 0x63}}, /* 0x28 */ - {{0x45,0xef,0xef,0x89,0x07,0x01,0xd9,0x1f, - 0xa0,0x83,0x9f,0x9f,0xda,0x1f,0x41,0x05, - 0x63}}, /* 0x29 */ - {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, - 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, - 0x00}}, /* 0x2a */ - {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, - 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, - 0x00}}, /* 0x2b */ - {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, - 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, - 0x00}}, /* 0x2c */ - {{0x59,0xff,0xff,0x9d,0x17,0x13,0x33,0xba, - 0x00,0x83,0xff,0xff,0x34,0x0f,0x41,0x05, - 0x44}}, /* 0x2d */ - {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x38,0xba, - 0x00,0x83,0xff,0xff,0x39,0x0f,0x41,0x05, - 0x44}}, /* 0x2e */ - {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x3d,0xba, - 0x00,0x83,0xff,0xff,0x3e,0x0f,0x41,0x05, - 0x44}}, /* 0x2f */ - {{0x5d,0xff,0xff,0x81,0x19,0x95,0x41,0xba, - 0x00,0x84,0xff,0xff,0x42,0x0f,0x41,0x05, - 0x44}}, /* 0x30 */ - {{0x55,0xff,0xff,0x99,0x0d,0x0c,0x3e,0xba, - 0x00,0x84,0xff,0xff,0x3f,0x0f,0x41,0x05, - 0x00}}, /* 0x31 */ - {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba, - 0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06, - 0x01}}, /* 0x32 */ - {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba, - 0x26,0x89,0xdf,0xdf,0x6f,0x00,0x00,0x06, - 0x01}}, /* 0x33 */ - {{0x7f,0x63,0x63,0x82,0x6b,0x13,0x75,0xba, - 0x29,0x8c,0xdf,0xdf,0x75,0x00,0x00,0x06, - 0x01}}, /* 0x34 */ - {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf1, - 0xaf,0x85,0x3f,0x3f,0x25,0x30,0x00,0x02, - 0x01}}, /* 0x35 */ - {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1, - 0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02, - 0x01}}, /* 0x36 */ - {{0xa7,0x7f,0x7f,0x88,0x89,0x95,0x26,0xf1, - 0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02, - 0x01}}, /* 0x37 */ - {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4, - 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07, - 0x01}}, /* 0x38 */ - {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xd4, - 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07, - 0x01}}, /* 0x39 */ - {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xd4, - 0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07, - 0x01}}, /* 0x3a */ - {{0xdc,0x9f,0x9f,0x80,0xaf,0x9d,0xe6,0xff, - 0xc0,0x83,0xbf,0xbf,0xe7,0x10,0x00,0x07, - 0x01}}, /* 0x3b */ - {{0x6b,0x59,0x59,0x8f,0x5e,0x8c,0x0b,0x3e, - 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05, - 0x00}}, /* 0x3c */ - {{0x6d,0x59,0x59,0x91,0x60,0x89,0x53,0xf0, - 0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05, - 0x41}}, /* 0x3d */ - {{0x86,0x6a,0x6a,0x8a,0x74,0x06,0x8c,0x15, - 0x4f,0x83,0xef,0xef,0x8d,0x30,0x00,0x02, - 0x00}}, /* 0x3e */ - {{0x81,0x6a,0x6a,0x85,0x70,0x00,0x0f,0x3e, - 0xeb,0x8e,0xdf,0xdf,0x10,0x00,0x00,0x02, - 0x00}}, /* 0x3f */ - {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1, - 0xae,0x85,0x57,0x57,0x1f,0x30,0x00,0x02, - 0x01}}, /* 0x40 */ - {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5, - 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, - 0x01}}, /* 0x41 */ - {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x20,0xf5, - 0x03,0x88,0xff,0xff,0x21,0x10,0x00,0x07, - 0x01}}, /* 0x42 */ - {{0xe6,0xae,0xae,0x8a,0xbd,0x90,0x3d,0x10, - 0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x00,0x03, - 0x00}}, /* 0x43 */ - {{0xc3,0x8f,0x8f,0x87,0x9b,0x0b,0x82,0xef, - 0x60,0x83,0x5f,0x5f,0x83,0x10,0x00,0x07, - 0x01}}, /* 0x44 */ - {{0x86,0x69,0x69,0x8A,0x74,0x06,0x8C,0x15, - 0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02, - 0x00}}, /* 0x45 */ - {{0x83,0x69,0x69,0x87,0x6f,0x1d,0x03,0x3E, - 0xE5,0x8d,0xDF,0xe4,0x04,0x00,0x00,0x06, - 0x00}}, /* 0x46 */ - {{0x86,0x6A,0x6A,0x8A,0x74,0x06,0x8C,0x15, - 0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02, - 0x00}}, /* 0x47 */ - {{0x81,0x6A,0x6A,0x85,0x70,0x00,0x0F,0x3E, - 0xEB,0x8E,0xDF,0xDF,0x10,0x00,0x00,0x02, - 0x00}}, /* 0x48 */ - {{0xdd,0xa9,0xa9,0x81,0xb4,0x97,0x26,0xfd, - 0x01,0x8d,0xff,0x00,0x27,0x10,0x00,0x03, - 0x01}}, /* 0x49 */ - {{0xd9,0x8f,0x8f,0x9d,0xba,0x0a,0x8a,0xff, - 0x60,0x8b,0x5f,0x5f,0x8b,0x10,0x00,0x03, - 0x01}}, /* 0x4a */ - {{0xea,0xae,0xae,0x8e,0xba,0x82,0x40,0x10, - 0x1b,0x87,0x19,0x1a,0x41,0x0f,0x00,0x03, - 0x00}}, /* 0x4b */ - {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0xf1,0xff, - 0xc0,0x83,0xbf,0xbf,0xf2,0x10,0x00,0x07, - 0x01}}, /* 0x4c */ - {{0x75,0x5f,0x5f,0x99,0x66,0x90,0x53,0xf0, - 0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05, - 0x41}}, - {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e, - 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00, - 0x00}}, /* 0x4e */ - {{0xcd,0x9f,0x9f,0x91,0xab,0x1c,0x3a,0xff, - 0x20,0x83,0x1f,0x1f,0x3b,0x10,0x00,0x07, - 0x21}}, /* 0x4f */ - {{0x15,0xd1,0xd1,0x99,0xe2,0x19,0x3d,0x10, - 0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x01,0x0c, - 0x20}}, /* 0x50 */ - {{0x0e,0xef,0xef,0x92,0xfe,0x03,0x30,0xf0, - 0x1e,0x83,0x1b,0x1c,0x31,0x00,0x01,0x00, - 0x61}}, /* 0x51 */ - {{0x85,0x77,0x77,0x89,0x7d,0x01,0x31,0xf0, - 0x1e,0x84,0x1b,0x1c,0x32,0x00,0x00,0x02, - 0x41}}, /* 0x52 */ - {{0x87,0x77,0x77,0x8b,0x81,0x0b,0x68,0xf0, - 0x5a,0x80,0x57,0x57,0x69,0x00,0x00,0x02, - 0x01}}, /* 0x53 */ - {{0xcd,0x8f,0x8f,0x91,0x9b,0x1b,0x7a,0xff, - 0x64,0x8c,0x5f,0x62,0x7b,0x10,0x00,0x07, - 0x41}} /* 0x54 */ +static const struct SiS_CRT1Table SiSUSB_CRT1Table[] = { + {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f, + 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x00, + 0x00}}, /* 0x0 */ + {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00, + 0x00}}, /* 0x1 */ + {{0x3d, 0x31, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x05, + 0x01}}, /* 0x2 */ + {{0x4f, 0x3f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x01, + 0x01}}, /* 0x3 */ + {{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x05, + 0x00}}, /* 0x4 */ + {{0x5f, 0x4f, 0x4f, 0x83, 0x55, 0x81, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe8, 0x0c, 0x00, 0x00, 0x05, + 0x00}}, /* 0x5 */ + {{0x63, 0x4f, 0x4f, 0x87, 0x56, 0x9b, 0x06, 0x3e, + 0xe8, 0x8a, 0xdf, 0xe7, 0x07, 0x00, 0x00, 0x01, + 0x00}}, /* 0x6 */ + {{0x64, 0x4f, 0x4f, 0x88, 0x55, 0x9d, 0xf2, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xf3, 0x10, 0x00, 0x01, + 0x00}}, /* 0x7 */ + {{0x63, 0x4f, 0x4f, 0x87, 0x5a, 0x81, 0xfb, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05, + 0x00}}, /* 0x8 */ + {{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0xfb, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05, + 0x61}}, /* 0x9 */ + {{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0x01, 0x3e, + 0xe0, 0x83, 0xdf, 0xdf, 0x02, 0x00, 0x00, 0x05, + 0x61}}, /* 0xa */ + {{0x67, 0x4f, 0x4f, 0x8b, 0x58, 0x81, 0x0d, 0x3e, + 0xe0, 0x83, 0xdf, 0xdf, 0x0e, 0x00, 0x00, 0x05, + 0x61}}, /* 0xb */ + {{0x65, 0x4f, 0x4f, 0x89, 0x57, 0x9f, 0xfb, 0x1f, + 0xe6, 0x8a, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x01, + 0x00}}, /* 0xc */ + {{0x7b, 0x63, 0x63, 0x9f, 0x6a, 0x93, 0x6f, 0xf0, + 0x58, 0x8a, 0x57, 0x57, 0x70, 0x20, 0x00, 0x05, + 0x01}}, /* 0xd */ + {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x06, + 0x01}}, /* 0xe */ + {{0x7d, 0x63, 0x63, 0x81, 0x6e, 0x1d, 0x98, 0xf0, + 0x7c, 0x82, 0x57, 0x57, 0x99, 0x00, 0x00, 0x06, + 0x01}}, /* 0xf */ + {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x70, 0x20, 0x00, 0x06, + 0x01}}, /* 0x10 */ + {{0x7e, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x76, 0x20, 0x00, 0x06, + 0x01}}, /* 0x11 */ + {{0x81, 0x63, 0x63, 0x85, 0x6d, 0x18, 0x7a, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x7b, 0x20, 0x00, 0x06, + 0x61}}, /* 0x12 */ + {{0x83, 0x63, 0x63, 0x87, 0x6e, 0x19, 0x81, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x82, 0x20, 0x00, 0x06, + 0x61}}, /* 0x13 */ + {{0x85, 0x63, 0x63, 0x89, 0x6f, 0x1a, 0x91, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x92, 0x20, 0x00, 0x06, + 0x61}}, /* 0x14 */ + {{0x99, 0x7f, 0x7f, 0x9d, 0x84, 0x1a, 0x96, 0x1f, + 0x7f, 0x83, 0x7f, 0x7f, 0x97, 0x10, 0x00, 0x02, + 0x00}}, /* 0x15 */ + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}}, /* 0x16 */ + {{0xa1, 0x7f, 0x7f, 0x85, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}}, /* 0x17 */ + {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x1f, 0x10, 0x00, 0x02, + 0x01}}, /* 0x18 */ + {{0xa7, 0x7f, 0x7f, 0x8b, 0x89, 0x95, 0x26, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x27, 0x10, 0x00, 0x02, + 0x01}}, /* 0x19 */ + {{0xa9, 0x7f, 0x7f, 0x8d, 0x8c, 0x9a, 0x2c, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x2d, 0x14, 0x00, 0x02, + 0x62}}, /* 0x1a */ + {{0xab, 0x7f, 0x7f, 0x8f, 0x8d, 0x9b, 0x35, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x36, 0x14, 0x00, 0x02, + 0x62}}, /* 0x1b */ + {{0xcf, 0x9f, 0x9f, 0x93, 0xb2, 0x01, 0x14, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x15, 0x00, 0x00, 0x03, + 0x00}}, /* 0x1c */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07, + 0x01}}, /* 0x1d */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07, + 0x01}}, /* 0x1e */ + {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x2f, 0x09, 0x00, 0x07, + 0x01}}, /* 0x1f */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x20 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x21 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x22 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x23 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x24 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x25 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x26 */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x27 */ + {{0x43, 0xef, 0xef, 0x87, 0x06, 0x00, 0xd4, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xd5, 0x1f, 0x41, 0x05, + 0x63}}, /* 0x28 */ + {{0x45, 0xef, 0xef, 0x89, 0x07, 0x01, 0xd9, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xda, 0x1f, 0x41, 0x05, + 0x63}}, /* 0x29 */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x2a */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x2b */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x2c */ + {{0x59, 0xff, 0xff, 0x9d, 0x17, 0x13, 0x33, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x34, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x2d */ + {{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x38, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x39, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x2e */ + {{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x3d, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x3e, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x2f */ + {{0x5d, 0xff, 0xff, 0x81, 0x19, 0x95, 0x41, 0xba, + 0x00, 0x84, 0xff, 0xff, 0x42, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x30 */ + {{0x55, 0xff, 0xff, 0x99, 0x0d, 0x0c, 0x3e, 0xba, + 0x00, 0x84, 0xff, 0xff, 0x3f, 0x0f, 0x41, 0x05, + 0x00}}, /* 0x31 */ + {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xba, + 0x27, 0x8b, 0xdf, 0xdf, 0x73, 0x00, 0x00, 0x06, + 0x01}}, /* 0x32 */ + {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xba, + 0x26, 0x89, 0xdf, 0xdf, 0x6f, 0x00, 0x00, 0x06, + 0x01}}, /* 0x33 */ + {{0x7f, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xba, + 0x29, 0x8c, 0xdf, 0xdf, 0x75, 0x00, 0x00, 0x06, + 0x01}}, /* 0x34 */ + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf1, + 0xaf, 0x85, 0x3f, 0x3f, 0x25, 0x30, 0x00, 0x02, + 0x01}}, /* 0x35 */ + {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf1, + 0xad, 0x81, 0x3f, 0x3f, 0x1f, 0x30, 0x00, 0x02, + 0x01}}, /* 0x36 */ + {{0xa7, 0x7f, 0x7f, 0x88, 0x89, 0x95, 0x26, 0xf1, + 0xb1, 0x85, 0x3f, 0x3f, 0x27, 0x30, 0x00, 0x02, + 0x01}}, /* 0x37 */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0xc4, + 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07, + 0x01}}, /* 0x38 */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0xd4, + 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07, + 0x01}}, /* 0x39 */ + {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0xd4, + 0x7d, 0x81, 0xcf, 0xcf, 0x2f, 0x21, 0x00, 0x07, + 0x01}}, /* 0x3a */ + {{0xdc, 0x9f, 0x9f, 0x80, 0xaf, 0x9d, 0xe6, 0xff, + 0xc0, 0x83, 0xbf, 0xbf, 0xe7, 0x10, 0x00, 0x07, + 0x01}}, /* 0x3b */ + {{0x6b, 0x59, 0x59, 0x8f, 0x5e, 0x8c, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x05, + 0x00}}, /* 0x3c */ + {{0x6d, 0x59, 0x59, 0x91, 0x60, 0x89, 0x53, 0xf0, + 0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05, + 0x41}}, /* 0x3d */ + {{0x86, 0x6a, 0x6a, 0x8a, 0x74, 0x06, 0x8c, 0x15, + 0x4f, 0x83, 0xef, 0xef, 0x8d, 0x30, 0x00, 0x02, + 0x00}}, /* 0x3e */ + {{0x81, 0x6a, 0x6a, 0x85, 0x70, 0x00, 0x0f, 0x3e, + 0xeb, 0x8e, 0xdf, 0xdf, 0x10, 0x00, 0x00, 0x02, + 0x00}}, /* 0x3f */ + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x1e, 0xf1, + 0xae, 0x85, 0x57, 0x57, 0x1f, 0x30, 0x00, 0x02, + 0x01}}, /* 0x40 */ + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}}, /* 0x41 */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x20, 0xf5, + 0x03, 0x88, 0xff, 0xff, 0x21, 0x10, 0x00, 0x07, + 0x01}}, /* 0x42 */ + {{0xe6, 0xae, 0xae, 0x8a, 0xbd, 0x90, 0x3d, 0x10, + 0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x00, 0x03, + 0x00}}, /* 0x43 */ + {{0xc3, 0x8f, 0x8f, 0x87, 0x9b, 0x0b, 0x82, 0xef, + 0x60, 0x83, 0x5f, 0x5f, 0x83, 0x10, 0x00, 0x07, + 0x01}}, /* 0x44 */ + {{0x86, 0x69, 0x69, 0x8A, 0x74, 0x06, 0x8C, 0x15, + 0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02, + 0x00}}, /* 0x45 */ + {{0x83, 0x69, 0x69, 0x87, 0x6f, 0x1d, 0x03, 0x3E, + 0xE5, 0x8d, 0xDF, 0xe4, 0x04, 0x00, 0x00, 0x06, + 0x00}}, /* 0x46 */ + {{0x86, 0x6A, 0x6A, 0x8A, 0x74, 0x06, 0x8C, 0x15, + 0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02, + 0x00}}, /* 0x47 */ + {{0x81, 0x6A, 0x6A, 0x85, 0x70, 0x00, 0x0F, 0x3E, + 0xEB, 0x8E, 0xDF, 0xDF, 0x10, 0x00, 0x00, 0x02, + 0x00}}, /* 0x48 */ + {{0xdd, 0xa9, 0xa9, 0x81, 0xb4, 0x97, 0x26, 0xfd, + 0x01, 0x8d, 0xff, 0x00, 0x27, 0x10, 0x00, 0x03, + 0x01}}, /* 0x49 */ + {{0xd9, 0x8f, 0x8f, 0x9d, 0xba, 0x0a, 0x8a, 0xff, + 0x60, 0x8b, 0x5f, 0x5f, 0x8b, 0x10, 0x00, 0x03, + 0x01}}, /* 0x4a */ + {{0xea, 0xae, 0xae, 0x8e, 0xba, 0x82, 0x40, 0x10, + 0x1b, 0x87, 0x19, 0x1a, 0x41, 0x0f, 0x00, 0x03, + 0x00}}, /* 0x4b */ + {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0xf1, 0xff, + 0xc0, 0x83, 0xbf, 0xbf, 0xf2, 0x10, 0x00, 0x07, + 0x01}}, /* 0x4c */ + {{0x75, 0x5f, 0x5f, 0x99, 0x66, 0x90, 0x53, 0xf0, + 0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05, + 0x41}}, + {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00, + 0x00}}, /* 0x4e */ + {{0xcd, 0x9f, 0x9f, 0x91, 0xab, 0x1c, 0x3a, 0xff, + 0x20, 0x83, 0x1f, 0x1f, 0x3b, 0x10, 0x00, 0x07, + 0x21}}, /* 0x4f */ + {{0x15, 0xd1, 0xd1, 0x99, 0xe2, 0x19, 0x3d, 0x10, + 0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x01, 0x0c, + 0x20}}, /* 0x50 */ + {{0x0e, 0xef, 0xef, 0x92, 0xfe, 0x03, 0x30, 0xf0, + 0x1e, 0x83, 0x1b, 0x1c, 0x31, 0x00, 0x01, 0x00, + 0x61}}, /* 0x51 */ + {{0x85, 0x77, 0x77, 0x89, 0x7d, 0x01, 0x31, 0xf0, + 0x1e, 0x84, 0x1b, 0x1c, 0x32, 0x00, 0x00, 0x02, + 0x41}}, /* 0x52 */ + {{0x87, 0x77, 0x77, 0x8b, 0x81, 0x0b, 0x68, 0xf0, + 0x5a, 0x80, 0x57, 0x57, 0x69, 0x00, 0x00, 0x02, + 0x01}}, /* 0x53 */ + {{0xcd, 0x8f, 0x8f, 0x91, 0x9b, 0x1b, 0x7a, 0xff, + 0x64, 0x8c, 0x5f, 0x62, 0x7b, 0x10, 0x00, 0x07, + 0x41}} /* 0x54 */ }; -static const struct SiS_VCLKData SiSUSB_VCLKData[] = -{ - { 0x1b,0xe1, 25}, /* 0x00 */ - { 0x4e,0xe4, 28}, /* 0x01 */ - { 0x57,0xe4, 31}, /* 0x02 */ - { 0xc3,0xc8, 36}, /* 0x03 */ - { 0x42,0xe2, 40}, /* 0x04 */ - { 0xfe,0xcd, 43}, /* 0x05 */ - { 0x5d,0xc4, 44}, /* 0x06 */ - { 0x52,0xe2, 49}, /* 0x07 */ - { 0x53,0xe2, 50}, /* 0x08 */ - { 0x74,0x67, 52}, /* 0x09 */ - { 0x6d,0x66, 56}, /* 0x0a */ - { 0x5a,0x64, 65}, /* 0x0b */ - { 0x46,0x44, 67}, /* 0x0c */ - { 0xb1,0x46, 68}, /* 0x0d */ - { 0xd3,0x4a, 72}, /* 0x0e */ - { 0x29,0x61, 75}, /* 0x0f */ - { 0x6e,0x46, 76}, /* 0x10 */ - { 0x2b,0x61, 78}, /* 0x11 */ - { 0x31,0x42, 79}, /* 0x12 */ - { 0xab,0x44, 83}, /* 0x13 */ - { 0x46,0x25, 84}, /* 0x14 */ - { 0x78,0x29, 86}, /* 0x15 */ - { 0x62,0x44, 94}, /* 0x16 */ - { 0x2b,0x41,104}, /* 0x17 */ - { 0x3a,0x23,105}, /* 0x18 */ - { 0x70,0x44,108}, /* 0x19 */ - { 0x3c,0x23,109}, /* 0x1a */ - { 0x5e,0x43,113}, /* 0x1b */ - { 0xbc,0x44,116}, /* 0x1c */ - { 0xe0,0x46,132}, /* 0x1d */ - { 0x54,0x42,135}, /* 0x1e */ - { 0xea,0x2a,139}, /* 0x1f */ - { 0x41,0x22,157}, /* 0x20 */ - { 0x70,0x24,162}, /* 0x21 */ - { 0x30,0x21,175}, /* 0x22 */ - { 0x4e,0x22,189}, /* 0x23 */ - { 0xde,0x26,194}, /* 0x24 */ - { 0x62,0x06,202}, /* 0x25 */ - { 0x3f,0x03,229}, /* 0x26 */ - { 0xb8,0x06,234}, /* 0x27 */ - { 0x34,0x02,253}, /* 0x28 */ - { 0x58,0x04,255}, /* 0x29 */ - { 0x24,0x01,265}, /* 0x2a */ - { 0x9b,0x02,267}, /* 0x2b */ - { 0x70,0x05,270}, /* 0x2c */ - { 0x25,0x01,272}, /* 0x2d */ - { 0x9c,0x02,277}, /* 0x2e */ - { 0x27,0x01,286}, /* 0x2f */ - { 0x3c,0x02,291}, /* 0x30 */ - { 0xef,0x0a,292}, /* 0x31 */ - { 0xf6,0x0a,310}, /* 0x32 */ - { 0x95,0x01,315}, /* 0x33 */ - { 0xf0,0x09,324}, /* 0x34 */ - { 0xfe,0x0a,331}, /* 0x35 */ - { 0xf3,0x09,332}, /* 0x36 */ - { 0xea,0x08,340}, /* 0x37 */ - { 0xe8,0x07,376}, /* 0x38 */ - { 0xde,0x06,389}, /* 0x39 */ - { 0x52,0x2a, 54}, /* 0x3a 301 TV */ - { 0x52,0x6a, 27}, /* 0x3b 301 TV */ - { 0x62,0x24, 70}, /* 0x3c 301 TV */ - { 0x62,0x64, 70}, /* 0x3d 301 TV */ - { 0xa8,0x4c, 30}, /* 0x3e 301 TV */ - { 0x20,0x26, 33}, /* 0x3f 301 TV */ - { 0x31,0xc2, 39}, /* 0x40 */ - { 0x60,0x36, 30}, /* 0x41 Chrontel */ - { 0x40,0x4a, 28}, /* 0x42 Chrontel */ - { 0x9f,0x46, 44}, /* 0x43 Chrontel */ - { 0x97,0x2c, 26}, /* 0x44 */ - { 0x44,0xe4, 25}, /* 0x45 Chrontel */ - { 0x7e,0x32, 47}, /* 0x46 Chrontel */ - { 0x8a,0x24, 31}, /* 0x47 Chrontel */ - { 0x97,0x2c, 26}, /* 0x48 Chrontel */ - { 0xce,0x3c, 39}, /* 0x49 */ - { 0x52,0x4a, 36}, /* 0x4a Chrontel */ - { 0x34,0x61, 95}, /* 0x4b */ - { 0x78,0x27,108}, /* 0x4c - was 102 */ - { 0x66,0x43,123}, /* 0x4d Modes 0x26-0x28 (1400x1050) */ - { 0x41,0x4e, 21}, /* 0x4e */ - { 0xa1,0x4a, 29}, /* 0x4f Chrontel */ - { 0x19,0x42, 42}, /* 0x50 */ - { 0x54,0x46, 58}, /* 0x51 Chrontel */ - { 0x25,0x42, 61}, /* 0x52 */ - { 0x44,0x44, 66}, /* 0x53 Chrontel */ - { 0x3a,0x62, 70}, /* 0x54 Chrontel */ - { 0x62,0xc6, 34}, /* 0x55 848x480-60 */ - { 0x6a,0xc6, 37}, /* 0x56 848x480-75 - TEMP */ - { 0xbf,0xc8, 35}, /* 0x57 856x480-38i,60 */ - { 0x30,0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */ - { 0x52,0x07,149}, /* 0x59 1280x960-85 */ - { 0x56,0x07,156}, /* 0x5a 1400x1050-75 */ - { 0x70,0x29, 81}, /* 0x5b 1280x768 LCD */ - { 0x45,0x25, 83}, /* 0x5c 1280x800 */ - { 0x70,0x0a,147}, /* 0x5d 1680x1050 */ - { 0x70,0x24,162}, /* 0x5e 1600x1200 */ - { 0x5a,0x64, 65}, /* 0x5f 1280x720 - temp */ - { 0x63,0x46, 68}, /* 0x60 1280x768_2 */ - { 0x31,0x42, 79}, /* 0x61 1280x768_3 - temp */ - { 0, 0, 0}, /* 0x62 - custom (will be filled out at run-time) */ - { 0x5a,0x64, 65}, /* 0x63 1280x720 (LCD LVDS) */ - { 0x70,0x28, 90}, /* 0x64 1152x864@60 */ - { 0x41,0xc4, 32}, /* 0x65 848x480@60 */ - { 0x5c,0xc6, 32}, /* 0x66 856x480@60 */ - { 0x76,0xe7, 27}, /* 0x67 720x480@60 */ - { 0x5f,0xc6, 33}, /* 0x68 720/768x576@60 */ - { 0x52,0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced */ - { 0x7c,0x6b, 38}, /* 0x6a 960x540@60 */ - { 0xe3,0x56, 41}, /* 0x6b 960x600@60 */ - { 0x45,0x25, 83}, /* 0x6c 1280x800 */ - { 0x70,0x28, 90}, /* 0x6d 1152x864@60 */ - { 0x15,0xe1, 20}, /* 0x6e 640x400@60 (fake, not actually used) */ - { 0x5f,0xc6, 33}, /* 0x6f 720x576@60 */ - { 0x37,0x5a, 10}, /* 0x70 320x200@60 (fake, not actually used) */ - { 0x2b,0xc2, 35} /* 0x71 768@576@60 */ +static const struct SiS_VCLKData SiSUSB_VCLKData[] = { + {0x1b, 0xe1, 25}, /* 0x00 */ + {0x4e, 0xe4, 28}, /* 0x01 */ + {0x57, 0xe4, 31}, /* 0x02 */ + {0xc3, 0xc8, 36}, /* 0x03 */ + {0x42, 0xe2, 40}, /* 0x04 */ + {0xfe, 0xcd, 43}, /* 0x05 */ + {0x5d, 0xc4, 44}, /* 0x06 */ + {0x52, 0xe2, 49}, /* 0x07 */ + {0x53, 0xe2, 50}, /* 0x08 */ + {0x74, 0x67, 52}, /* 0x09 */ + {0x6d, 0x66, 56}, /* 0x0a */ + {0x5a, 0x64, 65}, /* 0x0b */ + {0x46, 0x44, 67}, /* 0x0c */ + {0xb1, 0x46, 68}, /* 0x0d */ + {0xd3, 0x4a, 72}, /* 0x0e */ + {0x29, 0x61, 75}, /* 0x0f */ + {0x6e, 0x46, 76}, /* 0x10 */ + {0x2b, 0x61, 78}, /* 0x11 */ + {0x31, 0x42, 79}, /* 0x12 */ + {0xab, 0x44, 83}, /* 0x13 */ + {0x46, 0x25, 84}, /* 0x14 */ + {0x78, 0x29, 86}, /* 0x15 */ + {0x62, 0x44, 94}, /* 0x16 */ + {0x2b, 0x41, 104}, /* 0x17 */ + {0x3a, 0x23, 105}, /* 0x18 */ + {0x70, 0x44, 108}, /* 0x19 */ + {0x3c, 0x23, 109}, /* 0x1a */ + {0x5e, 0x43, 113}, /* 0x1b */ + {0xbc, 0x44, 116}, /* 0x1c */ + {0xe0, 0x46, 132}, /* 0x1d */ + {0x54, 0x42, 135}, /* 0x1e */ + {0xea, 0x2a, 139}, /* 0x1f */ + {0x41, 0x22, 157}, /* 0x20 */ + {0x70, 0x24, 162}, /* 0x21 */ + {0x30, 0x21, 175}, /* 0x22 */ + {0x4e, 0x22, 189}, /* 0x23 */ + {0xde, 0x26, 194}, /* 0x24 */ + {0x62, 0x06, 202}, /* 0x25 */ + {0x3f, 0x03, 229}, /* 0x26 */ + {0xb8, 0x06, 234}, /* 0x27 */ + {0x34, 0x02, 253}, /* 0x28 */ + {0x58, 0x04, 255}, /* 0x29 */ + {0x24, 0x01, 265}, /* 0x2a */ + {0x9b, 0x02, 267}, /* 0x2b */ + {0x70, 0x05, 270}, /* 0x2c */ + {0x25, 0x01, 272}, /* 0x2d */ + {0x9c, 0x02, 277}, /* 0x2e */ + {0x27, 0x01, 286}, /* 0x2f */ + {0x3c, 0x02, 291}, /* 0x30 */ + {0xef, 0x0a, 292}, /* 0x31 */ + {0xf6, 0x0a, 310}, /* 0x32 */ + {0x95, 0x01, 315}, /* 0x33 */ + {0xf0, 0x09, 324}, /* 0x34 */ + {0xfe, 0x0a, 331}, /* 0x35 */ + {0xf3, 0x09, 332}, /* 0x36 */ + {0xea, 0x08, 340}, /* 0x37 */ + {0xe8, 0x07, 376}, /* 0x38 */ + {0xde, 0x06, 389}, /* 0x39 */ + {0x52, 0x2a, 54}, /* 0x3a 301 TV */ + {0x52, 0x6a, 27}, /* 0x3b 301 TV */ + {0x62, 0x24, 70}, /* 0x3c 301 TV */ + {0x62, 0x64, 70}, /* 0x3d 301 TV */ + {0xa8, 0x4c, 30}, /* 0x3e 301 TV */ + {0x20, 0x26, 33}, /* 0x3f 301 TV */ + {0x31, 0xc2, 39}, /* 0x40 */ + {0x60, 0x36, 30}, /* 0x41 Chrontel */ + {0x40, 0x4a, 28}, /* 0x42 Chrontel */ + {0x9f, 0x46, 44}, /* 0x43 Chrontel */ + {0x97, 0x2c, 26}, /* 0x44 */ + {0x44, 0xe4, 25}, /* 0x45 Chrontel */ + {0x7e, 0x32, 47}, /* 0x46 Chrontel */ + {0x8a, 0x24, 31}, /* 0x47 Chrontel */ + {0x97, 0x2c, 26}, /* 0x48 Chrontel */ + {0xce, 0x3c, 39}, /* 0x49 */ + {0x52, 0x4a, 36}, /* 0x4a Chrontel */ + {0x34, 0x61, 95}, /* 0x4b */ + {0x78, 0x27, 108}, /* 0x4c - was 102 */ + {0x66, 0x43, 123}, /* 0x4d Modes 0x26-0x28 (1400x1050) */ + {0x41, 0x4e, 21}, /* 0x4e */ + {0xa1, 0x4a, 29}, /* 0x4f Chrontel */ + {0x19, 0x42, 42}, /* 0x50 */ + {0x54, 0x46, 58}, /* 0x51 Chrontel */ + {0x25, 0x42, 61}, /* 0x52 */ + {0x44, 0x44, 66}, /* 0x53 Chrontel */ + {0x3a, 0x62, 70}, /* 0x54 Chrontel */ + {0x62, 0xc6, 34}, /* 0x55 848x480-60 */ + {0x6a, 0xc6, 37}, /* 0x56 848x480-75 - TEMP */ + {0xbf, 0xc8, 35}, /* 0x57 856x480-38i,60 */ + {0x30, 0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */ + {0x52, 0x07, 149}, /* 0x59 1280x960-85 */ + {0x56, 0x07, 156}, /* 0x5a 1400x1050-75 */ + {0x70, 0x29, 81}, /* 0x5b 1280x768 LCD */ + {0x45, 0x25, 83}, /* 0x5c 1280x800 */ + {0x70, 0x0a, 147}, /* 0x5d 1680x1050 */ + {0x70, 0x24, 162}, /* 0x5e 1600x1200 */ + {0x5a, 0x64, 65}, /* 0x5f 1280x720 - temp */ + {0x63, 0x46, 68}, /* 0x60 1280x768_2 */ + {0x31, 0x42, 79}, /* 0x61 1280x768_3 - temp */ + {0, 0, 0}, /* 0x62 - custom (will be filled out at run-time) */ + {0x5a, 0x64, 65}, /* 0x63 1280x720 (LCD LVDS) */ + {0x70, 0x28, 90}, /* 0x64 1152x864@60 */ + {0x41, 0xc4, 32}, /* 0x65 848x480@60 */ + {0x5c, 0xc6, 32}, /* 0x66 856x480@60 */ + {0x76, 0xe7, 27}, /* 0x67 720x480@60 */ + {0x5f, 0xc6, 33}, /* 0x68 720/768x576@60 */ + {0x52, 0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced */ + {0x7c, 0x6b, 38}, /* 0x6a 960x540@60 */ + {0xe3, 0x56, 41}, /* 0x6b 960x600@60 */ + {0x45, 0x25, 83}, /* 0x6c 1280x800 */ + {0x70, 0x28, 90}, /* 0x6d 1152x864@60 */ + {0x15, 0xe1, 20}, /* 0x6e 640x400@60 (fake, not actually used) */ + {0x5f, 0xc6, 33}, /* 0x6f 720x576@60 */ + {0x37, 0x5a, 10}, /* 0x70 320x200@60 (fake, not actually used) */ + {0x2b, 0xc2, 35} /* 0x71 768@576@60 */ }; -int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo); -int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo); +int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo); +int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo); -extern int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data); -extern int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data); -extern int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, - u8 index, u8 data); -extern int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, - u8 index, u8 *data); -extern int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, - u8 idx, u8 myand, u8 myor); -extern int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, - u8 index, u8 myor); -extern int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, - u8 idx, u8 myand); +extern int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data); +extern int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 * data); +extern int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, + u8 index, u8 data); +extern int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, + u8 index, u8 * data); +extern int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, + u8 idx, u8 myand, u8 myor); +extern int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, + u8 index, u8 myor); +extern int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, + u8 idx, u8 myand); void sisusb_delete(struct kref *kref); int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data); -int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data); +int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 * data); int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src, - u32 dest, int length, size_t *bytes_written); + u32 dest, int length, size_t * bytes_written); int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init); int sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot, - u8 *arg, int cmapsz, int ch512, int dorecalc, + u8 * arg, int cmapsz, int ch512, int dorecalc, struct vc_data *c, int fh, int uplock); void sisusb_set_cursor(struct sisusb_usb_data *sisusb, unsigned int location); int sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last); @@ -839,4 +839,3 @@ void sisusb_console_exit(struct sisusb_usb_data *sisusb); void sisusb_init_concode(void); #endif - diff --git a/drivers/usb/misc/sisusbvga/sisusb_struct.h b/drivers/usb/misc/sisusbvga/sisusb_struct.h index f325ecb29a61..1c4240e802c1 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_struct.h +++ b/drivers/usb/misc/sisusbvga/sisusb_struct.h @@ -44,7 +44,7 @@ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Author: Thomas Winischhofer <thomas@winischhofer.net> + * Author: Thomas Winischhofer <thomas@winischhofer.net> * */ @@ -52,85 +52,78 @@ #define _SISUSB_STRUCT_H_ struct SiS_St { - unsigned char St_ModeID; - unsigned short St_ModeFlag; - unsigned char St_StTableIndex; - unsigned char St_CRT2CRTC; - unsigned char St_ResInfo; - unsigned char VB_StTVFlickerIndex; - unsigned char VB_StTVEdgeIndex; - unsigned char VB_StTVYFilterIndex; - unsigned char St_PDC; + unsigned char St_ModeID; + unsigned short St_ModeFlag; + unsigned char St_StTableIndex; + unsigned char St_CRT2CRTC; + unsigned char St_ResInfo; + unsigned char VB_StTVFlickerIndex; + unsigned char VB_StTVEdgeIndex; + unsigned char VB_StTVYFilterIndex; + unsigned char St_PDC; }; -struct SiS_StandTable -{ - unsigned char CRT_COLS; - unsigned char ROWS; - unsigned char CHAR_HEIGHT; - unsigned short CRT_LEN; - unsigned char SR[4]; - unsigned char MISC; - unsigned char CRTC[0x19]; - unsigned char ATTR[0x14]; - unsigned char GRC[9]; +struct SiS_StandTable { + unsigned char CRT_COLS; + unsigned char ROWS; + unsigned char CHAR_HEIGHT; + unsigned short CRT_LEN; + unsigned char SR[4]; + unsigned char MISC; + unsigned char CRTC[0x19]; + unsigned char ATTR[0x14]; + unsigned char GRC[9]; }; struct SiS_StResInfo_S { - unsigned short HTotal; - unsigned short VTotal; + unsigned short HTotal; + unsigned short VTotal; }; -struct SiS_Ext -{ - unsigned char Ext_ModeID; - unsigned short Ext_ModeFlag; - unsigned short Ext_VESAID; - unsigned char Ext_RESINFO; - unsigned char VB_ExtTVFlickerIndex; - unsigned char VB_ExtTVEdgeIndex; - unsigned char VB_ExtTVYFilterIndex; - unsigned char VB_ExtTVYFilterIndexROM661; - unsigned char REFindex; - char ROMMODEIDX661; +struct SiS_Ext { + unsigned char Ext_ModeID; + unsigned short Ext_ModeFlag; + unsigned short Ext_VESAID; + unsigned char Ext_RESINFO; + unsigned char VB_ExtTVFlickerIndex; + unsigned char VB_ExtTVEdgeIndex; + unsigned char VB_ExtTVYFilterIndex; + unsigned char VB_ExtTVYFilterIndexROM661; + unsigned char REFindex; + char ROMMODEIDX661; }; -struct SiS_Ext2 -{ - unsigned short Ext_InfoFlag; - unsigned char Ext_CRT1CRTC; - unsigned char Ext_CRTVCLK; - unsigned char Ext_CRT2CRTC; - unsigned char Ext_CRT2CRTC_NS; - unsigned char ModeID; - unsigned short XRes; - unsigned short YRes; - unsigned char Ext_PDC; - unsigned char Ext_FakeCRT2CRTC; - unsigned char Ext_FakeCRT2Clk; +struct SiS_Ext2 { + unsigned short Ext_InfoFlag; + unsigned char Ext_CRT1CRTC; + unsigned char Ext_CRTVCLK; + unsigned char Ext_CRT2CRTC; + unsigned char Ext_CRT2CRTC_NS; + unsigned char ModeID; + unsigned short XRes; + unsigned short YRes; + unsigned char Ext_PDC; + unsigned char Ext_FakeCRT2CRTC; + unsigned char Ext_FakeCRT2Clk; }; -struct SiS_CRT1Table -{ - unsigned char CR[17]; +struct SiS_CRT1Table { + unsigned char CR[17]; }; -struct SiS_VCLKData -{ - unsigned char SR2B,SR2C; - unsigned short CLOCK; +struct SiS_VCLKData { + unsigned char SR2B, SR2C; + unsigned short CLOCK; }; -struct SiS_ModeResInfo -{ - unsigned short HTotal; - unsigned short VTotal; - unsigned char XChar; - unsigned char YChar; +struct SiS_ModeResInfo { + unsigned short HTotal; + unsigned short VTotal; + unsigned char XChar; + unsigned char YChar; }; -struct SiS_Private -{ +struct SiS_Private { void *sisusb; unsigned long IOAddress; @@ -151,19 +144,18 @@ struct SiS_Private unsigned long SiS_P3da; unsigned long SiS_Part1Port; - unsigned char SiS_MyCR63; - unsigned short SiS_CRT1Mode; - unsigned short SiS_ModeType; - unsigned short SiS_SetFlag; - - const struct SiS_StandTable *SiS_StandTable; - const struct SiS_St *SiS_SModeIDTable; - const struct SiS_Ext *SiS_EModeIDTable; - const struct SiS_Ext2 *SiS_RefIndex; - const struct SiS_CRT1Table *SiS_CRT1Table; - const struct SiS_VCLKData *SiS_VCLKData; - const struct SiS_ModeResInfo *SiS_ModeResInfo; + unsigned char SiS_MyCR63; + unsigned short SiS_CRT1Mode; + unsigned short SiS_ModeType; + unsigned short SiS_SetFlag; + + const struct SiS_StandTable *SiS_StandTable; + const struct SiS_St *SiS_SModeIDTable; + const struct SiS_Ext *SiS_EModeIDTable; + const struct SiS_Ext2 *SiS_RefIndex; + const struct SiS_CRT1Table *SiS_CRT1Table; + const struct SiS_VCLKData *SiS_VCLKData; + const struct SiS_ModeResInfo *SiS_ModeResInfo; }; #endif - diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index c03dfd7a9d36..f06e4e2b49d3 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -172,6 +172,10 @@ static inline struct mon_bin_hdr *MON_OFF2HDR(const struct mon_reader_bin *rp, #define MON_RING_EMPTY(rp) ((rp)->b_cnt == 0) +static unsigned char xfer_to_pipe[4] = { + PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT +}; + static struct class *mon_bin_class; static dev_t mon_bin_dev0; static struct cdev mon_bin_cdev; @@ -354,13 +358,9 @@ static inline char mon_bin_get_setup(unsigned char *setupb, const struct urb *urb, char ev_type) { - if (!usb_pipecontrol(urb->pipe) || ev_type != 'S') + if (!usb_endpoint_xfer_control(&urb->ep->desc) || ev_type != 'S') return '-'; - if (urb->dev->bus->uses_dma && - (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) { - return mon_dmapeek(setupb, urb->setup_dma, SETUP_LEN); - } if (urb->setup_packet == NULL) return 'Z'; @@ -386,13 +386,15 @@ static char mon_bin_get_data(const struct mon_reader_bin *rp, } static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, - char ev_type) + char ev_type, int status) { + const struct usb_endpoint_descriptor *epd = &urb->ep->desc; unsigned long flags; struct timeval ts; unsigned int urb_length; unsigned int offset; unsigned int length; + unsigned char dir; struct mon_bin_hdr *ep; char data_tag = 0; @@ -410,16 +412,19 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, if (length >= rp->b_size/5) length = rp->b_size/5; - if (usb_pipein(urb->pipe)) { + if (usb_urb_dir_in(urb)) { if (ev_type == 'S') { length = 0; data_tag = '<'; } + /* Cannot rely on endpoint number in case of control ep.0 */ + dir = USB_DIR_IN; } else { if (ev_type == 'C') { length = 0; data_tag = '>'; } + dir = 0; } if (rp->mmap_active) @@ -440,15 +445,14 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, */ memset(ep, 0, PKT_SIZE); ep->type = ev_type; - ep->xfer_type = usb_pipetype(urb->pipe); - /* We use the fact that usb_pipein() returns 0x80 */ - ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe); - ep->devnum = usb_pipedevice(urb->pipe); + ep->xfer_type = xfer_to_pipe[usb_endpoint_type(epd)]; + ep->epnum = dir | usb_endpoint_num(epd); + ep->devnum = urb->dev->devnum; ep->busnum = urb->dev->bus->busnum; ep->id = (unsigned long) urb; ep->ts_sec = ts.tv_sec; ep->ts_usec = ts.tv_usec; - ep->status = urb->status; + ep->status = status; ep->len_urb = urb_length; ep->len_cap = length; @@ -471,13 +475,13 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, static void mon_bin_submit(void *data, struct urb *urb) { struct mon_reader_bin *rp = data; - mon_bin_event(rp, urb, 'S'); + mon_bin_event(rp, urb, 'S', -EINPROGRESS); } -static void mon_bin_complete(void *data, struct urb *urb) +static void mon_bin_complete(void *data, struct urb *urb, int status) { struct mon_reader_bin *rp = data; - mon_bin_event(rp, urb, 'C'); + mon_bin_event(rp, urb, 'C', status); } static void mon_bin_error(void *data, struct urb *urb, int error) @@ -500,10 +504,10 @@ static void mon_bin_error(void *data, struct urb *urb, int error) memset(ep, 0, PKT_SIZE); ep->type = 'E'; - ep->xfer_type = usb_pipetype(urb->pipe); - /* We use the fact that usb_pipein() returns 0x80 */ - ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe); - ep->devnum = usb_pipedevice(urb->pipe); + ep->xfer_type = xfer_to_pipe[usb_endpoint_type(&urb->ep->desc)]; + ep->epnum = usb_urb_dir_in(urb) ? USB_DIR_IN : 0; + ep->epnum |= usb_endpoint_num(&urb->ep->desc); + ep->devnum = urb->dev->devnum; ep->busnum = urb->dev->bus->busnum; ep->id = (unsigned long) urb; ep->status = error; diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c index ce61d8b0fd86..b371ffd39d36 100644 --- a/drivers/usb/mon/mon_main.c +++ b/drivers/usb/mon/mon_main.c @@ -129,7 +129,8 @@ static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error) /* */ -static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb) +static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb, + int status) { unsigned long flags; struct list_head *pos; @@ -139,28 +140,18 @@ static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb) mbus->cnt_events++; list_for_each (pos, &mbus->r_list) { r = list_entry(pos, struct mon_reader, r_link); - r->rnf_complete(r->r_data, urb); + r->rnf_complete(r->r_data, urb, status); } spin_unlock_irqrestore(&mbus->lock, flags); } -static void mon_complete(struct usb_bus *ubus, struct urb *urb) +static void mon_complete(struct usb_bus *ubus, struct urb *urb, int status) { struct mon_bus *mbus; - mbus = ubus->mon_bus; - if (mbus == NULL) { - /* - * This should not happen. - * At this point we do not even know the bus number... - */ - printk(KERN_ERR TAG ": Null mon bus in URB, pipe 0x%x\n", - urb->pipe); - return; - } - - mon_bus_complete(mbus, urb); - mon_bus_complete(&mon_bus0, urb); + if ((mbus = ubus->mon_bus) != NULL) + mon_bus_complete(mbus, urb, status); + mon_bus_complete(&mon_bus0, urb, status); } /* int (*unlink_urb) (struct urb *urb, int status); */ @@ -170,7 +161,7 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb) */ static void mon_stop(struct mon_bus *mbus) { - struct usb_bus *ubus = mbus->u_bus; + struct usb_bus *ubus; struct list_head *p; if (mbus == &mon_bus0) { diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 8f27a9e1c36b..ebb04ac4857b 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -50,10 +50,13 @@ struct mon_iso_desc { struct mon_event_text { struct list_head e_link; int type; /* submit, complete, etc. */ - unsigned int pipe; /* Pipe */ unsigned long id; /* From pointer, most of the time */ unsigned int tstamp; int busnum; + char devnum; + char epnum; + char is_in; + char xfertype; int length; /* Depends on type: xfer length or act length */ int status; int interval; @@ -121,13 +124,9 @@ static inline char mon_text_get_setup(struct mon_event_text *ep, struct urb *urb, char ev_type, struct mon_bus *mbus) { - if (!usb_pipecontrol(urb->pipe) || ev_type != 'S') + if (ep->xfertype != USB_ENDPOINT_XFER_CONTROL || ev_type != 'S') return '-'; - if (urb->dev->bus->uses_dma && - (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) { - return mon_dmapeek(ep->setup, urb->setup_dma, SETUP_MAX); - } if (urb->setup_packet == NULL) return 'Z'; /* '0' would be not as pretty. */ @@ -138,14 +137,12 @@ static inline char mon_text_get_setup(struct mon_event_text *ep, static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb, int len, char ev_type, struct mon_bus *mbus) { - int pipe = urb->pipe; - if (len <= 0) return 'L'; if (len >= DATA_MAX) len = DATA_MAX; - if (usb_pipein(pipe)) { + if (ep->is_in) { if (ev_type != 'C') return '<'; } else { @@ -186,7 +183,7 @@ static inline unsigned int mon_get_timestamp(void) } static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, - char ev_type) + char ev_type, int status) { struct mon_event_text *ep; unsigned int stamp; @@ -203,24 +200,28 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, } ep->type = ev_type; - ep->pipe = urb->pipe; ep->id = (unsigned long) urb; ep->busnum = urb->dev->bus->busnum; + ep->devnum = urb->dev->devnum; + ep->epnum = usb_endpoint_num(&urb->ep->desc); + ep->xfertype = usb_endpoint_type(&urb->ep->desc); + ep->is_in = usb_urb_dir_in(urb); ep->tstamp = stamp; ep->length = (ev_type == 'S') ? urb->transfer_buffer_length : urb->actual_length; /* Collecting status makes debugging sense for submits, too */ - ep->status = urb->status; + ep->status = status; - if (usb_pipeint(urb->pipe)) { + if (ep->xfertype == USB_ENDPOINT_XFER_INT) { ep->interval = urb->interval; - } else if (usb_pipeisoc(urb->pipe)) { + } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) { ep->interval = urb->interval; ep->start_frame = urb->start_frame; ep->error_count = urb->error_count; } ep->numdesc = urb->number_of_packets; - if (usb_pipeisoc(urb->pipe) && urb->number_of_packets > 0) { + if (ep->xfertype == USB_ENDPOINT_XFER_ISOC && + urb->number_of_packets > 0) { if ((ndesc = urb->number_of_packets) > ISODESC_MAX) ndesc = ISODESC_MAX; fp = urb->iso_frame_desc; @@ -247,13 +248,13 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, static void mon_text_submit(void *data, struct urb *urb) { struct mon_reader_text *rp = data; - mon_text_event(rp, urb, 'S'); + mon_text_event(rp, urb, 'S', -EINPROGRESS); } -static void mon_text_complete(void *data, struct urb *urb) +static void mon_text_complete(void *data, struct urb *urb, int status) { struct mon_reader_text *rp = data; - mon_text_event(rp, urb, 'C'); + mon_text_event(rp, urb, 'C', status); } static void mon_text_error(void *data, struct urb *urb, int error) @@ -268,9 +269,12 @@ static void mon_text_error(void *data, struct urb *urb, int error) } ep->type = 'E'; - ep->pipe = urb->pipe; ep->id = (unsigned long) urb; ep->busnum = 0; + ep->devnum = urb->dev->devnum; + ep->epnum = usb_endpoint_num(&urb->ep->desc); + ep->xfertype = usb_endpoint_type(&urb->ep->desc); + ep->is_in = usb_urb_dir_in(urb); ep->tstamp = 0; ep->length = 0; ep->status = error; @@ -413,10 +417,10 @@ static ssize_t mon_text_read_u(struct file *file, char __user *buf, mon_text_read_head_u(rp, &ptr, ep); if (ep->type == 'E') { mon_text_read_statset(rp, &ptr, ep); - } else if (usb_pipeisoc(ep->pipe)) { + } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) { mon_text_read_isostat(rp, &ptr, ep); mon_text_read_isodesc(rp, &ptr, ep); - } else if (usb_pipeint(ep->pipe)) { + } else if (ep->xfertype == USB_ENDPOINT_XFER_INT) { mon_text_read_intstat(rp, &ptr, ep); } else { mon_text_read_statset(rp, &ptr, ep); @@ -468,18 +472,17 @@ static void mon_text_read_head_t(struct mon_reader_text *rp, { char udir, utype; - udir = usb_pipein(ep->pipe) ? 'i' : 'o'; - switch (usb_pipetype(ep->pipe)) { - case PIPE_ISOCHRONOUS: utype = 'Z'; break; - case PIPE_INTERRUPT: utype = 'I'; break; - case PIPE_CONTROL: utype = 'C'; break; + udir = (ep->is_in ? 'i' : 'o'); + switch (ep->xfertype) { + case USB_ENDPOINT_XFER_ISOC: utype = 'Z'; break; + case USB_ENDPOINT_XFER_INT: utype = 'I'; break; + case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break; default: /* PIPE_BULK */ utype = 'B'; } p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, "%lx %u %c %c%c:%03u:%02u", ep->id, ep->tstamp, ep->type, - utype, udir, - usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe)); + utype, udir, ep->devnum, ep->epnum); } static void mon_text_read_head_u(struct mon_reader_text *rp, @@ -487,18 +490,17 @@ static void mon_text_read_head_u(struct mon_reader_text *rp, { char udir, utype; - udir = usb_pipein(ep->pipe) ? 'i' : 'o'; - switch (usb_pipetype(ep->pipe)) { - case PIPE_ISOCHRONOUS: utype = 'Z'; break; - case PIPE_INTERRUPT: utype = 'I'; break; - case PIPE_CONTROL: utype = 'C'; break; + udir = (ep->is_in ? 'i' : 'o'); + switch (ep->xfertype) { + case USB_ENDPOINT_XFER_ISOC: utype = 'Z'; break; + case USB_ENDPOINT_XFER_INT: utype = 'I'; break; + case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break; default: /* PIPE_BULK */ utype = 'B'; } p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, "%lx %u %c %c%c:%d:%03u:%u", ep->id, ep->tstamp, ep->type, - utype, udir, - ep->busnum, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe)); + utype, udir, ep->busnum, ep->devnum, ep->epnum); } static void mon_text_read_statset(struct mon_reader_text *rp, diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h index f68ad6d99ad7..f5d84ff8c101 100644 --- a/drivers/usb/mon/usb_mon.h +++ b/drivers/usb/mon/usb_mon.h @@ -46,7 +46,7 @@ struct mon_reader { void (*rnf_submit)(void *data, struct urb *urb); void (*rnf_error)(void *data, struct urb *urb, int error); - void (*rnf_complete)(void *data, struct urb *urb); + void (*rnf_complete)(void *data, struct urb *urb, int status); }; void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r); diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 43d6db696f90..99fefed77919 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -92,6 +92,16 @@ config USB_SERIAL_BELKIN To compile this driver as a module, choose M here: the module will be called belkin_sa. +config USB_SERIAL_CH341 + tristate "USB Winchiphead CH341 Single Port Serial Driver" + depends on USB_SERIAL + help + Say Y here if you want to use a Winchiphead CH341 single port + USB to serial adapter. + + To compile this driver as a module, choose M here: the + module will be called ch341. + config USB_SERIAL_WHITEHEAT tristate "USB ConnectTech WhiteHEAT Serial Driver" depends on USB_SERIAL diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index 07a976eca6b7..d6fb384e52b2 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_USB_SERIAL_AIRCABLE) += aircable.o obj-$(CONFIG_USB_SERIAL_AIRPRIME) += airprime.o obj-$(CONFIG_USB_SERIAL_ARK3116) += ark3116.o obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o +obj-$(CONFIG_USB_SERIAL_CH341) += ch341.o obj-$(CONFIG_USB_SERIAL_CP2101) += cp2101.o obj-$(CONFIG_USB_SERIAL_CYBERJACK) += cyberjack.o obj-$(CONFIG_USB_SERIAL_CYPRESS_M8) += cypress_m8.o diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index c9fd486c1c7d..2a8e537cb046 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -172,11 +172,6 @@ static void ark3116_set_termios(struct usb_serial_port *port, dbg("%s - port %d", __FUNCTION__, port->number); - if (!port->tty || !port->tty->termios) { - dbg("%s - no tty structures", __FUNCTION__); - return; - } - spin_lock_irqsave(&priv->lock, flags); if (!priv->termios_initialized) { *(port->tty->termios) = tty_std_termios; diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index a47a24f8820d..0b14aea8ebd5 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c @@ -36,6 +36,16 @@ static int usb_serial_device_match (struct device *dev, struct device_driver *dr return 0; } +static ssize_t show_port_number(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_serial_port *port = to_usb_serial_port(dev); + + return sprintf(buf, "%d\n", port->number - port->serial->minor); +} + +static DEVICE_ATTR(port_number, S_IRUGO, show_port_number, NULL); + static int usb_serial_device_probe (struct device *dev) { struct usb_serial_driver *driver; @@ -62,6 +72,10 @@ static int usb_serial_device_probe (struct device *dev) goto exit; } + retval = device_create_file(dev, &dev_attr_port_number); + if (retval) + goto exit; + minor = port->number; tty_register_device (usb_serial_tty_driver, minor, dev); dev_info(&port->serial->dev->dev, @@ -84,6 +98,8 @@ static int usb_serial_device_remove (struct device *dev) return -ENODEV; } + device_remove_file(&port->dev, &dev_attr_port_number); + driver = port->serial->type; if (driver->port_remove) { if (!try_module_get(driver->driver.owner)) { diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c new file mode 100644 index 000000000000..6b252ceb39a8 --- /dev/null +++ b/drivers/usb/serial/ch341.c @@ -0,0 +1,354 @@ +/* + * Copyright 2007, Frank A Kingswood <frank@kingswood-consulting.co.uk> + * + * ch341.c implements a serial port driver for the Winchiphead CH341. + * + * The CH341 device can be used to implement an RS232 asynchronous + * serial port, an IEEE-1284 parallel printer port or a memory-like + * interface. In all cases the CH341 supports an I2C interface as well. + * This driver only supports the asynchronous serial interface. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/tty.h> +#include <linux/module.h> +#include <linux/usb.h> +#include <linux/usb/serial.h> +#include <linux/serial.h> + +#define DEFAULT_BAUD_RATE 2400 +#define DEFAULT_TIMEOUT 1000 + +static int debug; + +static struct usb_device_id id_table [] = { + { USB_DEVICE(0x4348, 0x5523) }, + { }, +}; +MODULE_DEVICE_TABLE(usb, id_table); + +struct ch341_private { + unsigned baud_rate; + u8 dtr; + u8 rts; +}; + +static int ch341_control_out(struct usb_device *dev, u8 request, + u16 value, u16 index) +{ + int r; + dbg("ch341_control_out(%02x,%02x,%04x,%04x)", USB_DIR_OUT|0x40, + (int)request, (int)value, (int)index); + + r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + value, index, NULL, 0, DEFAULT_TIMEOUT); + + return r; +} + +static int ch341_control_in(struct usb_device *dev, + u8 request, u16 value, u16 index, + char *buf, unsigned bufsize) +{ + int r; + dbg("ch341_control_in(%02x,%02x,%04x,%04x,%p,%u)", USB_DIR_IN|0x40, + (int)request, (int)value, (int)index, buf, (int)bufsize); + + r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + value, index, buf, bufsize, DEFAULT_TIMEOUT); + return r; +} + +static int ch341_set_baudrate(struct usb_device *dev, + struct ch341_private *priv) +{ + short a, b; + int r; + + dbg("ch341_set_baudrate(%d)", priv->baud_rate); + switch (priv->baud_rate) { + case 2400: + a = 0xd901; + b = 0x0038; + break; + case 4800: + a = 0x6402; + b = 0x001f; + break; + case 9600: + a = 0xb202; + b = 0x0013; + break; + case 19200: + a = 0xd902; + b = 0x000d; + break; + case 38400: + a = 0x6403; + b = 0x000a; + break; + case 115200: + a = 0xcc03; + b = 0x0008; + break; + default: + return -EINVAL; + } + + r = ch341_control_out(dev, 0x9a, 0x1312, a); + if (!r) + r = ch341_control_out(dev, 0x9a, 0x0f2c, b); + + return r; +} + +static int ch341_set_handshake(struct usb_device *dev, + struct ch341_private *priv) +{ + dbg("ch341_set_handshake(%d,%d)", priv->dtr, priv->rts); + return ch341_control_out(dev, 0xa4, + ~((priv->dtr?1<<5:0)|(priv->rts?1<<6:0)), 0); +} + +static int ch341_get_status(struct usb_device *dev) +{ + char *buffer; + int r; + const unsigned size = 8; + + dbg("ch341_get_status()"); + + buffer = kmalloc(size, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + r = ch341_control_in(dev, 0x95, 0x0706, 0, buffer, size); + if ( r < 0) + goto out; + + /* Not having the datasheet for the CH341, we ignore the bytes returned + * from the device. Return error if the device did not respond in time. + */ + r = 0; + +out: kfree(buffer); + return r; +} + +/* -------------------------------------------------------------------------- */ + +static int ch341_configure(struct usb_device *dev, struct ch341_private *priv) +{ + char *buffer; + int r; + const unsigned size = 8; + + dbg("ch341_configure()"); + + buffer = kmalloc(size, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + /* expect two bytes 0x27 0x00 */ + r = ch341_control_in(dev, 0x5f, 0, 0, buffer, size); + if (r < 0) + goto out; + + r = ch341_control_out(dev, 0xa1, 0, 0); + if (r < 0) + goto out; + + r = ch341_set_baudrate(dev, priv); + if (r < 0) + goto out; + + /* expect two bytes 0x56 0x00 */ + r = ch341_control_in(dev, 0x95, 0x2518, 0, buffer, size); + if (r < 0) + goto out; + + r = ch341_control_out(dev, 0x9a, 0x2518, 0x0050); + if (r < 0) + goto out; + + /* expect 0xff 0xee */ + r = ch341_get_status(dev); + if (r < 0) + goto out; + + r = ch341_control_out(dev, 0xa1, 0x501f, 0xd90a); + if (r < 0) + goto out; + + r = ch341_set_baudrate(dev, priv); + if (r < 0) + goto out; + + r = ch341_set_handshake(dev, priv); + if (r < 0) + goto out; + + /* expect 0x9f 0xee */ + r = ch341_get_status(dev); + +out: kfree(buffer); + return r; +} + +/* allocate private data */ +static int ch341_attach(struct usb_serial *serial) +{ + struct ch341_private *priv; + int r; + + dbg("ch341_attach()"); + + /* private data */ + priv = kzalloc(sizeof(struct ch341_private), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->baud_rate = DEFAULT_BAUD_RATE; + priv->dtr = 1; + priv->rts = 1; + + r = ch341_configure(serial->dev, priv); + if (r < 0) + goto error; + + usb_set_serial_port_data(serial->port[0], priv); + return 0; + +error: kfree(priv); + return r; +} + +/* open this device, set default parameters */ +static int ch341_open(struct usb_serial_port *port, struct file *filp) +{ + struct usb_serial *serial = port->serial; + struct ch341_private *priv = usb_get_serial_port_data(serial->port[0]); + int r; + + dbg("ch341_open()"); + + priv->baud_rate = DEFAULT_BAUD_RATE; + priv->dtr = 1; + priv->rts = 1; + + r = ch341_configure(serial->dev, priv); + if (r) + goto out; + + r = ch341_set_handshake(serial->dev, priv); + if (r) + goto out; + + r = ch341_set_baudrate(serial->dev, priv); + if (r) + goto out; + + r = usb_serial_generic_open(port, filp); + +out: return r; +} + +/* Old_termios contains the original termios settings and + * tty->termios contains the new setting to be used. + */ +static void ch341_set_termios(struct usb_serial_port *port, + struct ktermios *old_termios) +{ + struct ch341_private *priv = usb_get_serial_port_data(port); + struct tty_struct *tty = port->tty; + unsigned baud_rate; + + dbg("ch341_set_termios()"); + + if (!tty || !tty->termios) + return; + + baud_rate = tty_get_baud_rate(tty); + + switch (baud_rate) { + case 2400: + case 4800: + case 9600: + case 19200: + case 38400: + case 115200: + priv->baud_rate = baud_rate; + break; + default: + dbg("Rate %d not supported, using %d", + baud_rate, DEFAULT_BAUD_RATE); + priv->baud_rate = DEFAULT_BAUD_RATE; + } + + ch341_set_baudrate(port->serial->dev, priv); + + /* Unimplemented: + * (cflag & CSIZE) : data bits [5, 8] + * (cflag & PARENB) : parity {NONE, EVEN, ODD} + * (cflag & CSTOPB) : stop bits [1, 2] + */ +} + +static struct usb_driver ch341_driver = { + .name = "ch341", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table, + .no_dynamic_id = 1, +}; + +static struct usb_serial_driver ch341_device = { + .driver = { + .owner = THIS_MODULE, + .name = "ch341-uart", + }, + .id_table = id_table, + .usb_driver = &ch341_driver, + .num_interrupt_in = NUM_DONT_CARE, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_ports = 1, + .open = ch341_open, + .set_termios = ch341_set_termios, + .attach = ch341_attach, +}; + +static int __init ch341_init(void) +{ + int retval; + + retval = usb_serial_register(&ch341_device); + if (retval) + return retval; + retval = usb_register(&ch341_driver); + if (retval) + usb_serial_deregister(&ch341_device); + return retval; +} + +static void __exit ch341_exit(void) +{ + usb_deregister(&ch341_driver); + usb_serial_deregister(&ch341_device); +} + +module_init(ch341_init); +module_exit(ch341_exit); +MODULE_LICENSE("GPL"); + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + +/* EOF ch341.c */ diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index 33f6ee50b8d3..eb7df1835c11 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -53,6 +53,7 @@ static void cp2101_shutdown(struct usb_serial*); static int debug; static struct usb_device_id id_table [] = { + { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */ { USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */ { USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */ { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */ @@ -521,7 +522,7 @@ static void cp2101_set_termios (struct usb_serial_port *port, dbg("%s - port %d", __FUNCTION__, port->number); - if ((!port->tty) || (!port->tty->termios)) { + if (!port->tty || !port->tty->termios) { dbg("%s - no tty structures", __FUNCTION__); return; } diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 2d045857b181..e4c248c98e84 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1169,7 +1169,9 @@ static void remove_sysfs_attrs(struct usb_serial_port *port) /* XXX see create_sysfs_attrs */ if (priv->chip_type != SIO) { device_remove_file(&port->dev, &dev_attr_event_char); - if (priv->chip_type == FT232BM || priv->chip_type == FT2232C) { + if (priv->chip_type == FT232BM || + priv->chip_type == FT2232C || + priv->chip_type == FT232RL) { device_remove_file(&port->dev, &dev_attr_latency_timer); } } @@ -2102,6 +2104,7 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file) case FT8U232AM: case FT232BM: case FT2232C: + case FT232RL: /* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same format as the data returned from the in point */ if ((ret = usb_control_msg(port->serial->dev, diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c index 4092f6dc9efd..b5194dc7d3bb 100644 --- a/drivers/usb/serial/funsoft.c +++ b/drivers/usb/serial/funsoft.c @@ -24,26 +24,6 @@ static struct usb_device_id id_table [] = { }; MODULE_DEVICE_TABLE(usb, id_table); -static int funsoft_ioctl(struct usb_serial_port *port, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct ktermios t; - - dbg("%s - port %d, cmd 0x%04x", __FUNCTION__, port->number, cmd); - - if (cmd == TCSETSF) { - if (user_termios_to_kernel_termios(&t, (struct termios __user *)arg)) - return -EFAULT; - - dbg("%s - iflag:%x oflag:%x cflag:%x lflag:%x", __FUNCTION__, - t.c_iflag, t.c_oflag, t.c_cflag, t.c_lflag); - - if (!(t.c_lflag & ICANON)) - return -EINVAL; - } - return -ENOIOCTLCMD; -} - static struct usb_driver funsoft_driver = { .name = "funsoft", .probe = usb_serial_probe, @@ -63,7 +43,6 @@ static struct usb_serial_driver funsoft_device = { .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, .num_ports = 1, - .ioctl = funsoft_ioctl, }; static int __init funsoft_init(void) diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 6a3a704b5849..e836ad07fdb9 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -256,6 +256,7 @@ static struct usb_device_id ipaq_id_table [] = { { USB_DEVICE(0x04DD, 0x9121) }, /* SHARP WS004SH USB Modem */ { USB_DEVICE(0x04DD, 0x9123) }, /* SHARP WS007SH USB Modem */ { USB_DEVICE(0x04DD, 0x9151) }, /* SHARP S01SH USB Modem */ + { USB_DEVICE(0x04DD, 0x91AC) }, /* SHARP WS011SH USB Modem */ { USB_DEVICE(0x04E8, 0x5F00) }, /* Samsung NEXiO USB Sync */ { USB_DEVICE(0x04E8, 0x5F01) }, /* Samsung NEXiO USB Sync */ { USB_DEVICE(0x04E8, 0x5F02) }, /* Samsung NEXiO USB Sync */ @@ -646,11 +647,13 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp) kfree(port->bulk_out_buffer); port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL); if (port->bulk_in_buffer == NULL) { + port->bulk_out_buffer = NULL; /* prevent double free */ goto enomem; } port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL); if (port->bulk_out_buffer == NULL) { kfree(port->bulk_in_buffer); + port->bulk_in_buffer = NULL; goto enomem; } port->read_urb->transfer_buffer = port->bulk_in_buffer; diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 5a4127e62c4a..90e3216abd1f 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -728,24 +728,32 @@ static void klsi_105_set_termios (struct usb_serial_port *port, #endif } - switch(cflag & CBAUD) { - case B0: /* handled below */ + switch(tty_get_baud_rate(port->tty)) { + case 0: /* handled below */ break; - case B1200: priv->cfg.baudrate = kl5kusb105a_sio_b1200; + case 1200: + priv->cfg.baudrate = kl5kusb105a_sio_b1200; break; - case B2400: priv->cfg.baudrate = kl5kusb105a_sio_b2400; + case 2400: + priv->cfg.baudrate = kl5kusb105a_sio_b2400; break; - case B4800: priv->cfg.baudrate = kl5kusb105a_sio_b4800; + case 4800: + priv->cfg.baudrate = kl5kusb105a_sio_b4800; break; - case B9600: priv->cfg.baudrate = kl5kusb105a_sio_b9600; + case 9600: + priv->cfg.baudrate = kl5kusb105a_sio_b9600; break; - case B19200: priv->cfg.baudrate = kl5kusb105a_sio_b19200; + case 19200: + priv->cfg.baudrate = kl5kusb105a_sio_b19200; break; - case B38400: priv->cfg.baudrate = kl5kusb105a_sio_b38400; + case 38400: + priv->cfg.baudrate = kl5kusb105a_sio_b38400; break; - case B57600: priv->cfg.baudrate = kl5kusb105a_sio_b57600; + case 57600: + priv->cfg.baudrate = kl5kusb105a_sio_b57600; break; - case B115200: priv->cfg.baudrate = kl5kusb105a_sio_b115200; + case 115200: + priv->cfg.baudrate = kl5kusb105a_sio_b115200; break; default: err("KLSI USB->Serial converter:" diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index 02a86dbc0e97..6f224195bd25 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -82,6 +82,7 @@ static int kobil_tiocmset(struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear); static void kobil_read_int_callback( struct urb *urb ); static void kobil_write_callback( struct urb *purb ); +static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old); static struct usb_device_id id_table [] = { @@ -119,6 +120,7 @@ static struct usb_serial_driver kobil_device = { .attach = kobil_startup, .shutdown = kobil_shutdown, .ioctl = kobil_ioctl, + .set_termios = kobil_set_termios, .tiocmget = kobil_tiocmget, .tiocmset = kobil_tiocmset, .open = kobil_open, @@ -137,7 +139,6 @@ struct kobil_private { int cur_pos; // index of the next char to send in buf __u16 device_type; int line_state; - struct ktermios internal_termios; }; @@ -216,7 +217,7 @@ static void kobil_shutdown (struct usb_serial *serial) static int kobil_open (struct usb_serial_port *port, struct file *filp) { - int i, result = 0; + int result = 0; struct kobil_private *priv; unsigned char *transfer_buffer; int transfer_buffer_length = 8; @@ -242,16 +243,6 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp) port->tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF; port->tty->termios->c_oflag &= ~ONLCR; // do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) - // set up internal termios structure - priv->internal_termios.c_iflag = port->tty->termios->c_iflag; - priv->internal_termios.c_oflag = port->tty->termios->c_oflag; - priv->internal_termios.c_cflag = port->tty->termios->c_cflag; - priv->internal_termios.c_lflag = port->tty->termios->c_lflag; - - for (i=0; i<NCCS; i++) { - priv->internal_termios.c_cc[i] = port->tty->termios->c_cc[i]; - } - // allocate memory for transfer buffer transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL); if (! transfer_buffer) { @@ -607,102 +598,79 @@ static int kobil_tiocmset(struct usb_serial_port *port, struct file *file, return (result < 0) ? result : 0; } - -static int kobil_ioctl(struct usb_serial_port *port, struct file *file, - unsigned int cmd, unsigned long arg) +static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old) { struct kobil_private * priv; int result; unsigned short urb_val = 0; - unsigned char *transfer_buffer; - int transfer_buffer_length = 8; - char *settings; - void __user *user_arg = (void __user *)arg; + int c_cflag = port->tty->termios->c_cflag; + speed_t speed; + void * settings; priv = usb_get_serial_port_data(port); - if ((priv->device_type == KOBIL_USBTWIN_PRODUCT_ID) || (priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)) { + if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) // This device doesn't support ioctl calls - return 0; - } - - switch (cmd) { - case TCGETS: // 0x5401 - if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct ktermios))) { - dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number); - return -EFAULT; - } - if (kernel_termios_to_user_termios((struct ktermios __user *)arg, - &priv->internal_termios)) - return -EFAULT; - return 0; - - case TCSETS: // 0x5402 - if (!(port->tty->termios)) { - dbg("%s - port %d Error: port->tty->termios is NULL", __FUNCTION__, port->number); - return -ENOTTY; - } - if (!access_ok(VERIFY_READ, user_arg, sizeof(struct ktermios))) { - dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number); - return -EFAULT; - } - if (user_termios_to_kernel_termios(&priv->internal_termios, - (struct ktermios __user *)arg)) - return -EFAULT; - - settings = kzalloc(50, GFP_KERNEL); - if (! settings) { - return -ENOBUFS; - } + return; - switch (priv->internal_termios.c_cflag & CBAUD) { - case B1200: + switch (speed = tty_get_baud_rate(port->tty)) { + case 1200: urb_val = SUSBCR_SBR_1200; - strcat(settings, "1200 "); break; - case B9600: + case 9600: default: urb_val = SUSBCR_SBR_9600; - strcat(settings, "9600 "); break; - } + } + urb_val |= (c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit; + + settings = kzalloc(50, GFP_KERNEL); + if (! settings) + return; - urb_val |= (priv->internal_termios.c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit; - strcat(settings, (priv->internal_termios.c_cflag & CSTOPB) ? "2 StopBits " : "1 StopBit "); + sprintf(settings, "%d ", speed); - if (priv->internal_termios.c_cflag & PARENB) { - if (priv->internal_termios.c_cflag & PARODD) { - urb_val |= SUSBCR_SPASB_OddParity; - strcat(settings, "Odd Parity"); - } else { - urb_val |= SUSBCR_SPASB_EvenParity; - strcat(settings, "Even Parity"); - } + if (c_cflag & PARENB) { + if (c_cflag & PARODD) { + urb_val |= SUSBCR_SPASB_OddParity; + strcat(settings, "Odd Parity"); } else { - urb_val |= SUSBCR_SPASB_NoParity; - strcat(settings, "No Parity"); + urb_val |= SUSBCR_SPASB_EvenParity; + strcat(settings, "Even Parity"); } - dbg("%s - port %d setting port to: %s", __FUNCTION__, port->number, settings ); + } else { + urb_val |= SUSBCR_SPASB_NoParity; + strcat(settings, "No Parity"); + } - result = usb_control_msg( port->serial->dev, - usb_rcvctrlpipe(port->serial->dev, 0 ), - SUSBCRequest_SetBaudRateParityAndStopBits, - USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, - urb_val, - 0, - settings, - 0, - KOBIL_TIMEOUT - ); + result = usb_control_msg( port->serial->dev, + usb_rcvctrlpipe(port->serial->dev, 0 ), + SUSBCRequest_SetBaudRateParityAndStopBits, + USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, + urb_val, + 0, + settings, + 0, + KOBIL_TIMEOUT + ); + kfree(settings); +} - dbg("%s - port %d Send set_baudrate URB returns: %i", __FUNCTION__, port->number, result); - kfree(settings); +static int kobil_ioctl(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg) +{ + struct kobil_private * priv = usb_get_serial_port_data(port); + unsigned char *transfer_buffer; + int transfer_buffer_length = 8; + int result; + + if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) + // This device doesn't support ioctl calls return 0; + switch (cmd) { case TCFLSH: // 0x540B transfer_buffer = kmalloc(transfer_buffer_length, GFP_KERNEL); - if (! transfer_buffer) { + if (! transfer_buffer) return -ENOBUFS; - } result = usb_control_msg( port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0 ), @@ -716,15 +684,13 @@ static int kobil_ioctl(struct usb_serial_port *port, struct file *file, ); dbg("%s - port %d Send reset_all_queues (FLUSH) URB returns: %i", __FUNCTION__, port->number, result); - kfree(transfer_buffer); - return ((result < 0) ? -EFAULT : 0); - + return (result < 0) ? -EFAULT : 0; + default: + return -ENOIOCTLCMD; } - return -ENOIOCTLCMD; } - static int __init kobil_init (void) { int retval; diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index e08c9bb403d8..0dc99f75bb09 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -206,20 +206,20 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value } } else { switch (value) { - case 300: break; - case 600: break; - case 1200: break; - case 2400: break; - case 4800: break; - case 9600: break; - case 19200: break; - case 38400: break; - case 57600: break; - case 115200: break; - default: - err("MCT USB-RS232: unsupported baudrate request 0x%x," - " using default of B9600", value); - value = 9600; + case 300: break; + case 600: break; + case 1200: break; + case 2400: break; + case 4800: break; + case 9600: break; + case 19200: break; + case 38400: break; + case 57600: break; + case 115200: break; + default: + err("MCT USB-RS232: unsupported baudrate request 0x%x," + " using default of B9600", value); + value = 9600; } return 115200/value; } diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index 64f3f66a7a35..d19861166b50 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -1144,7 +1144,7 @@ static struct pl2303_buf *pl2303_buf_alloc(unsigned int size) if (size == 0) return NULL; - pb = (struct pl2303_buf *)kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL); + pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL); if (pb == NULL) return NULL; diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index f9f85f56f0db..1da57fd9ea23 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -73,6 +73,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) }, { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) }, { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) }, { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) }, { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) }, { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) }, diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index f9a71d0c102e..c39bace5cbcc 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -59,6 +59,7 @@ #define SIEMENS_PRODUCT_ID_SX1 0x0001 #define SIEMENS_PRODUCT_ID_X65 0x0003 #define SIEMENS_PRODUCT_ID_X75 0x0004 +#define SIEMENS_PRODUCT_ID_EF81 0x0005 #define SYNTECH_VENDOR_ID 0x0745 #define SYNTECH_PRODUCT_ID 0x0001 diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c index 51669b7622bb..4e6dcc199be9 100644 --- a/drivers/usb/serial/safe_serial.c +++ b/drivers/usb/serial/safe_serial.c @@ -90,18 +90,12 @@ MODULE_AUTHOR (DRIVER_AUTHOR); MODULE_DESCRIPTION (DRIVER_DESC); MODULE_LICENSE("GPL"); -#if defined(CONFIG_USBD_SAFE_SERIAL_VENDOR) && !defined(CONFIG_USBD_SAFE_SERIAL_PRODUCT) -#error "SAFE_SERIAL_VENDOR defined without SAFE_SERIAL_PRODUCT" -#endif - -#if ! defined(CONFIG_USBD_SAFE_SERIAL_VENDOR) static __u16 vendor; // no default static __u16 product; // no default module_param(vendor, ushort, 0); MODULE_PARM_DESC(vendor, "User specified USB idVendor (required)"); module_param(product, ushort, 0); MODULE_PARM_DESC(product, "User specified USB idProduct (required)"); -#endif module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); @@ -145,11 +139,6 @@ static struct usb_device_id id_table[] = { {MY_USB_DEVICE (0x4dd, 0x8003, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Collie {MY_USB_DEVICE (0x4dd, 0x8004, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Collie {MY_USB_DEVICE (0x5f9, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Sharp tmp -#if defined(CONFIG_USB_SAFE_SERIAL_VENDOR) - {MY_USB_DEVICE - (CONFIG_USB_SAFE_SERIAL_VENDOR, CONFIG_USB_SAFE_SERIAL_PRODUCT, CDC_DEVICE_CLASS, - LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, -#endif // extra null entry for module // vendor/produc parameters {MY_USB_DEVICE (0, 0, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index f98626ae75fe..1f0149495fb4 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -214,13 +214,13 @@ static int debug; static int low_latency = TI_DEFAULT_LOW_LATENCY; static int closing_wait = TI_DEFAULT_CLOSING_WAIT; static ushort vendor_3410[TI_EXTRA_VID_PID_COUNT]; -static int vendor_3410_count; +static unsigned int vendor_3410_count; static ushort product_3410[TI_EXTRA_VID_PID_COUNT]; -static int product_3410_count; +static unsigned int product_3410_count; static ushort vendor_5052[TI_EXTRA_VID_PID_COUNT]; -static int vendor_5052_count; +static unsigned int vendor_5052_count; static ushort product_5052[TI_EXTRA_VID_PID_COUNT]; -static int product_5052_count; +static unsigned int product_5052_count; /* supported devices */ /* the array dimension is the number of default entries plus */ diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 9bf01a5efc84..4b1bd7def4a5 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -578,6 +578,17 @@ static void kill_traffic(struct usb_serial_port *port) { usb_kill_urb(port->read_urb); usb_kill_urb(port->write_urb); + /* + * This is tricky. + * Some drivers submit the read_urb in the + * handler for the write_urb or vice versa + * this order determines the order in which + * usb_kill_urb() must be used to reliably + * kill the URBs. As it is unknown here, + * both orders must be used in turn. + * The call below is not redundant. + */ + usb_kill_urb(port->read_urb); usb_kill_urb(port->interrupt_in_urb); usb_kill_urb(port->interrupt_out_urb); } @@ -651,16 +662,14 @@ exit: static struct usb_serial_driver *search_serial_device(struct usb_interface *iface) { - struct list_head *p; const struct usb_device_id *id; - struct usb_serial_driver *t; + struct usb_serial_driver *drv; /* Check if the usb id matches a known device */ - list_for_each(p, &usb_serial_driver_list) { - t = list_entry(p, struct usb_serial_driver, driver_list); - id = get_iface_id(t, iface); + list_for_each_entry(drv, &usb_serial_driver_list, driver_list) { + id = get_iface_id(drv, iface); if (id) - return t; + return drv; } return NULL; @@ -800,9 +809,6 @@ int usb_serial_probe(struct usb_interface *interface, /* END HORRIBLE HACK FOR PL2303 */ #endif - /* found all that we need */ - dev_info(&interface->dev, "%s converter detected\n", type->description); - #ifdef CONFIG_USB_SERIAL_GENERIC if (type == &usb_serial_generic_device) { num_ports = num_bulk_out; @@ -836,6 +842,24 @@ int usb_serial_probe(struct usb_interface *interface, serial->num_interrupt_in = num_interrupt_in; serial->num_interrupt_out = num_interrupt_out; + /* check that the device meets the driver's requirements */ + if ((type->num_interrupt_in != NUM_DONT_CARE && + type->num_interrupt_in != num_interrupt_in) + || (type->num_interrupt_out != NUM_DONT_CARE && + type->num_interrupt_out != num_interrupt_out) + || (type->num_bulk_in != NUM_DONT_CARE && + type->num_bulk_in != num_bulk_in) + || (type->num_bulk_out != NUM_DONT_CARE && + type->num_bulk_out != num_bulk_out)) { + dbg("wrong number of endpoints"); + kfree(serial); + return -EIO; + } + + /* found all that we need */ + dev_info(&interface->dev, "%s converter detected\n", + type->description); + /* create our ports, we need as many as the max endpoints */ /* we don't use num_ports here cauz some devices have more endpoint pairs than ports */ max_endpoints = max(num_bulk_in, num_bulk_out); diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 30e08c0bcdc2..7ee087fed913 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -46,7 +46,6 @@ static int visor_probe (struct usb_serial *serial, const struct usb_device_id static int visor_calc_num_ports(struct usb_serial *serial); static void visor_shutdown (struct usb_serial *serial); static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); -static void visor_set_termios (struct usb_serial_port *port, struct ktermios *old_termios); static void visor_write_bulk_callback (struct urb *urb); static void visor_read_bulk_callback (struct urb *urb); static void visor_read_int_callback (struct urb *urb); @@ -203,7 +202,6 @@ static struct usb_serial_driver handspring_device = { .calc_num_ports = visor_calc_num_ports, .shutdown = visor_shutdown, .ioctl = visor_ioctl, - .set_termios = visor_set_termios, .write = visor_write, .write_room = visor_write_room, .chars_in_buffer = visor_chars_in_buffer, @@ -234,7 +232,6 @@ static struct usb_serial_driver clie_5_device = { .calc_num_ports = visor_calc_num_ports, .shutdown = visor_shutdown, .ioctl = visor_ioctl, - .set_termios = visor_set_termios, .write = visor_write, .write_room = visor_write_room, .chars_in_buffer = visor_chars_in_buffer, @@ -262,7 +259,6 @@ static struct usb_serial_driver clie_3_5_device = { .unthrottle = visor_unthrottle, .attach = clie_3_5_startup, .ioctl = visor_ioctl, - .set_termios = visor_set_termios, .write = visor_write, .write_room = visor_write_room, .chars_in_buffer = visor_chars_in_buffer, @@ -936,66 +932,6 @@ static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsign return -ENOIOCTLCMD; } - -/* This function is all nice and good, but we don't change anything based on it :) */ -static void visor_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) -{ - unsigned int cflag; - - dbg("%s - port %d", __FUNCTION__, port->number); - - if ((!port->tty) || (!port->tty->termios)) { - dbg("%s - no tty structures", __FUNCTION__); - return; - } - - cflag = port->tty->termios->c_cflag; - - /* get the byte size */ - switch (cflag & CSIZE) { - case CS5: dbg("%s - data bits = 5", __FUNCTION__); break; - case CS6: dbg("%s - data bits = 6", __FUNCTION__); break; - case CS7: dbg("%s - data bits = 7", __FUNCTION__); break; - default: - case CS8: dbg("%s - data bits = 8", __FUNCTION__); break; - } - - /* determine the parity */ - if (cflag & PARENB) - if (cflag & PARODD) - dbg("%s - parity = odd", __FUNCTION__); - else - dbg("%s - parity = even", __FUNCTION__); - else - dbg("%s - parity = none", __FUNCTION__); - - /* figure out the stop bits requested */ - if (cflag & CSTOPB) - dbg("%s - stop bits = 2", __FUNCTION__); - else - dbg("%s - stop bits = 1", __FUNCTION__); - - - /* figure out the flow control settings */ - if (cflag & CRTSCTS) - dbg("%s - RTS/CTS is enabled", __FUNCTION__); - else - dbg("%s - RTS/CTS is disabled", __FUNCTION__); - - /* determine software flow control */ - if (I_IXOFF(port->tty)) - dbg("%s - XON/XOFF is enabled, XON = %2x, XOFF = %2x", - __FUNCTION__, START_CHAR(port->tty), STOP_CHAR(port->tty)); - else - dbg("%s - XON/XOFF is disabled", __FUNCTION__); - - /* get the baud rate wanted */ - dbg("%s - baud rate = %d", __FUNCTION__, tty_get_baud_rate(port->tty)); - - return; -} - - static int __init visor_init (void) { int i, retval; diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c index 3a41740cad97..ee5b42aa5363 100644 --- a/drivers/usb/storage/initializers.c +++ b/drivers/usb/storage/initializers.c @@ -90,3 +90,17 @@ int usb_stor_ucr61s2b_init(struct us_data *us) return (res ? -1 : 0); } + +/* This places the HUAWEI E220 devices in multi-port mode */ +int usb_stor_huawei_e220_init(struct us_data *us) +{ + int result; + + us->iobuf[0] = 0x1; + result = usb_stor_control_msg(us, us->send_ctrl_pipe, + USB_REQ_SET_FEATURE, + USB_TYPE_STANDARD | USB_RECIP_DEVICE, + 0x01, 0x0, us->iobuf, 0x1, 1000); + US_DEBUGP("usb_control_msg performing result is %d\n", result); + return (result ? 0 : -1); +} diff --git a/drivers/usb/storage/initializers.h b/drivers/usb/storage/initializers.h index e2967a4d48a2..ad3ffd4236c2 100644 --- a/drivers/usb/storage/initializers.h +++ b/drivers/usb/storage/initializers.h @@ -47,3 +47,6 @@ int usb_stor_euscsi_init(struct us_data *us); /* This function is required to activate all four slots on the UCR-61S2B * flash reader */ int usb_stor_ucr61s2b_init(struct us_data *us); + +/* This places the HUAWEI E220 devices in multi-port mode */ +int usb_stor_huawei_e220_init(struct us_data *us); diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c index 5e27297c0175..17ca4d73577b 100644 --- a/drivers/usb/storage/shuttle_usbat.c +++ b/drivers/usb/storage/shuttle_usbat.c @@ -190,9 +190,6 @@ static int usbat_check_status(struct us_data *us) unsigned char *reply = us->iobuf; int rc; - if (!us) - return USB_STOR_TRANSPORT_ERROR; - rc = usbat_get_status(us, reply); if (rc != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_FAILED; diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 323293a3e61f..c646750ccc30 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -50,7 +50,7 @@ #include <linux/slab.h> #include <scsi/scsi.h> -#include <scsi/scsi_cmnd.h> +#include <scsi/scsi_eh.h> #include <scsi/scsi_device.h> #include "usb.h" @@ -580,25 +580,11 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) /* Now, if we need to do the auto-sense, let's do it */ if (need_auto_sense) { int temp_result; - void* old_request_buffer; - unsigned short old_sg; - unsigned old_request_bufflen; - unsigned char old_sc_data_direction; - unsigned char old_cmd_len; - unsigned char old_cmnd[MAX_COMMAND_SIZE]; - int old_resid; + struct scsi_eh_save ses; US_DEBUGP("Issuing auto-REQUEST_SENSE\n"); - /* save the old command */ - memcpy(old_cmnd, srb->cmnd, MAX_COMMAND_SIZE); - old_cmd_len = srb->cmd_len; - - /* set the command and the LUN */ - memset(srb->cmnd, 0, MAX_COMMAND_SIZE); - srb->cmnd[0] = REQUEST_SENSE; - srb->cmnd[1] = old_cmnd[1] & 0xE0; - srb->cmnd[4] = 18; + scsi_eh_prep_cmnd(srb, &ses, NULL, 0, US_SENSE_SIZE); /* FIXME: we must do the protocol translation here */ if (us->subclass == US_SC_RBC || us->subclass == US_SC_SCSI) @@ -606,36 +592,12 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) else srb->cmd_len = 12; - /* set the transfer direction */ - old_sc_data_direction = srb->sc_data_direction; - srb->sc_data_direction = DMA_FROM_DEVICE; - - /* use the new buffer we have */ - old_request_buffer = srb->request_buffer; - srb->request_buffer = us->sensebuf; - - /* set the buffer length for transfer */ - old_request_bufflen = srb->request_bufflen; - srb->request_bufflen = US_SENSE_SIZE; - - /* set up for no scatter-gather use */ - old_sg = srb->use_sg; - srb->use_sg = 0; - /* issue the auto-sense command */ - old_resid = srb->resid; srb->resid = 0; temp_result = us->transport(us->srb, us); /* let's clean up right away */ - memcpy(srb->sense_buffer, us->sensebuf, US_SENSE_SIZE); - srb->resid = old_resid; - srb->request_buffer = old_request_buffer; - srb->request_bufflen = old_request_bufflen; - srb->use_sg = old_sg; - srb->sc_data_direction = old_sc_data_direction; - srb->cmd_len = old_cmd_len; - memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE); + scsi_eh_restore_cmnd(srb, &ses); if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) { US_DEBUGP("-- auto-sense aborted\n"); diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index c6b78ba815ea..9b656ec427d0 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -198,7 +198,7 @@ UNUSUAL_DEV( 0x0421, 0x044e, 0x0100, 0x0100, US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), /* Reported by Bardur Arantsson <bardur@scientician.net> */ -UNUSUAL_DEV( 0x0421, 0x047c, 0x0370, 0x0370, +UNUSUAL_DEV( 0x0421, 0x047c, 0x0370, 0x0610, "Nokia", "6131", US_SC_DEVICE, US_PR_DEVICE, NULL, @@ -341,6 +341,13 @@ UNUSUAL_DEV( 0x04b0, 0x040d, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY), +/* Reported by Graber and Mike Pagano <mpagano-kernel@mpagano.com> */ +UNUSUAL_DEV( 0x04b0, 0x040f, 0x0200, 0x0200, + "NIKON", + "NIKON DSC D200", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY), + /* Reported by Emil Larsson <emil@swip.net> */ UNUSUAL_DEV( 0x04b0, 0x0411, 0x0100, 0x0101, "NIKON", @@ -355,6 +362,20 @@ UNUSUAL_DEV( 0x04b0, 0x0413, 0x0110, 0x0110, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY), +/* Reported by Paul Check <paul@openstreet.com> */ +UNUSUAL_DEV( 0x04b0, 0x0415, 0x0100, 0x0100, + "NIKON", + "NIKON DSC D2Xs", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY), + +/* Reported by Shan Destromp (shansan@gmail.com) */ +UNUSUAL_DEV( 0x04b0, 0x0417, 0x0100, 0x0100, + "NIKON", + "NIKON DSC D40X", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY), + /* BENQ DC5330 * Reported by Manuel Fombuena <mfombuena@ya.com> and * Frank Copeland <fjc@thingy.apana.org.au> */ @@ -1463,6 +1484,17 @@ UNUSUAL_DEV( 0x1210, 0x0003, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), +/* Reported by fangxiaozhi <fangxiaozhi60675@huawei.com> + * and by linlei <linlei83@huawei.com> + * Patch reworked by Johann Wilhelm <johann.wilhelm@student.tugraz.at> + * This brings the HUAWEI E220 devices into multi-port mode + */ +UNUSUAL_DEV( 0x12d1, 0x1003, 0x0000, 0x0000, + "HUAWEI MOBILE", + "Mass Storage", + US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init, + 0), + /* Reported by Vilius Bilinkevicius <vilisas AT xxx DOT lt) */ UNUSUAL_DEV( 0x132b, 0x000b, 0x0001, 0x0001, "Minolta", diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 59181667066c..3451e8d03ab0 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -960,6 +960,10 @@ static int storage_probe(struct usb_interface *intf, return -ENOMEM; } + /* + * Allow 16-byte CDBs and thus > 2TB + */ + host->max_cmd_len = 16; us = host_to_us(host); memset(us, 0, sizeof(struct us_data)); mutex_init(&(us->dev_mutex)); diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index 8de11deb5d14..c815a40e167f 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -125,6 +125,7 @@ static int skel_open(struct inode *inode, struct file *file) /* save our object in the file's private structure */ file->private_data = dev; + mutex_unlock(&dev->io_mutex); exit: return retval; diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c index 0899fccbd570..fbea2bd129c7 100644 --- a/drivers/video/backlight/hp680_bl.c +++ b/drivers/video/backlight/hp680_bl.c @@ -125,8 +125,8 @@ static int hp680bl_remove(struct platform_device *pdev) { struct backlight_device *bd = platform_get_drvdata(pdev); - hp680bl_data.brightness = 0; - hp680bl_data.power = 0; + bd->props.brightness = 0; + bd->props.power = 0; hp680bl_send_intensity(bd); backlight_device_unregister(bd); diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c index ee9046db9c7d..549891d76ef5 100644 --- a/drivers/video/cg6.c +++ b/drivers/video/cg6.c @@ -19,7 +19,6 @@ #include <linux/mm.h> #include <asm/io.h> -#include <asm/prom.h> #include <asm/of_device.h> #include <asm/fbio.h> @@ -38,6 +37,7 @@ static void cg6_fillrect(struct fb_info *, const struct fb_fillrect *); static int cg6_sync(struct fb_info *); static int cg6_mmap(struct fb_info *, struct vm_area_struct *); static int cg6_ioctl(struct fb_info *, unsigned int, unsigned long); +static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area); /* * Frame buffer operations @@ -48,7 +48,7 @@ static struct fb_ops cg6_ops = { .fb_setcolreg = cg6_setcolreg, .fb_blank = cg6_blank, .fb_fillrect = cg6_fillrect, - .fb_copyarea = cfb_copyarea, + .fb_copyarea = cg6_copyarea, .fb_imageblit = cg6_imageblit, .fb_sync = cg6_sync, .fb_mmap = cg6_mmap, @@ -65,41 +65,41 @@ static struct fb_ops cg6_ops = { * The FBC could be the frame buffer control * The FHC could is the frame buffer hardware control. */ -#define CG6_ROM_OFFSET 0x0UL -#define CG6_BROOKTREE_OFFSET 0x200000UL -#define CG6_DHC_OFFSET 0x240000UL -#define CG6_ALT_OFFSET 0x280000UL -#define CG6_FHC_OFFSET 0x300000UL -#define CG6_THC_OFFSET 0x301000UL -#define CG6_FBC_OFFSET 0x700000UL -#define CG6_TEC_OFFSET 0x701000UL -#define CG6_RAM_OFFSET 0x800000UL +#define CG6_ROM_OFFSET 0x0UL +#define CG6_BROOKTREE_OFFSET 0x200000UL +#define CG6_DHC_OFFSET 0x240000UL +#define CG6_ALT_OFFSET 0x280000UL +#define CG6_FHC_OFFSET 0x300000UL +#define CG6_THC_OFFSET 0x301000UL +#define CG6_FBC_OFFSET 0x700000UL +#define CG6_TEC_OFFSET 0x701000UL +#define CG6_RAM_OFFSET 0x800000UL /* FHC definitions */ -#define CG6_FHC_FBID_SHIFT 24 -#define CG6_FHC_FBID_MASK 255 -#define CG6_FHC_REV_SHIFT 20 -#define CG6_FHC_REV_MASK 15 -#define CG6_FHC_FROP_DISABLE (1 << 19) -#define CG6_FHC_ROW_DISABLE (1 << 18) -#define CG6_FHC_SRC_DISABLE (1 << 17) -#define CG6_FHC_DST_DISABLE (1 << 16) -#define CG6_FHC_RESET (1 << 15) -#define CG6_FHC_LITTLE_ENDIAN (1 << 13) -#define CG6_FHC_RES_MASK (3 << 11) -#define CG6_FHC_1024 (0 << 11) -#define CG6_FHC_1152 (1 << 11) -#define CG6_FHC_1280 (2 << 11) -#define CG6_FHC_1600 (3 << 11) -#define CG6_FHC_CPU_MASK (3 << 9) -#define CG6_FHC_CPU_SPARC (0 << 9) -#define CG6_FHC_CPU_68020 (1 << 9) -#define CG6_FHC_CPU_386 (2 << 9) -#define CG6_FHC_TEST (1 << 8) -#define CG6_FHC_TEST_X_SHIFT 4 -#define CG6_FHC_TEST_X_MASK 15 -#define CG6_FHC_TEST_Y_SHIFT 0 -#define CG6_FHC_TEST_Y_MASK 15 +#define CG6_FHC_FBID_SHIFT 24 +#define CG6_FHC_FBID_MASK 255 +#define CG6_FHC_REV_SHIFT 20 +#define CG6_FHC_REV_MASK 15 +#define CG6_FHC_FROP_DISABLE (1 << 19) +#define CG6_FHC_ROW_DISABLE (1 << 18) +#define CG6_FHC_SRC_DISABLE (1 << 17) +#define CG6_FHC_DST_DISABLE (1 << 16) +#define CG6_FHC_RESET (1 << 15) +#define CG6_FHC_LITTLE_ENDIAN (1 << 13) +#define CG6_FHC_RES_MASK (3 << 11) +#define CG6_FHC_1024 (0 << 11) +#define CG6_FHC_1152 (1 << 11) +#define CG6_FHC_1280 (2 << 11) +#define CG6_FHC_1600 (3 << 11) +#define CG6_FHC_CPU_MASK (3 << 9) +#define CG6_FHC_CPU_SPARC (0 << 9) +#define CG6_FHC_CPU_68020 (1 << 9) +#define CG6_FHC_CPU_386 (2 << 9) +#define CG6_FHC_TEST (1 << 8) +#define CG6_FHC_TEST_X_SHIFT 4 +#define CG6_FHC_TEST_X_MASK 15 +#define CG6_FHC_TEST_Y_SHIFT 0 +#define CG6_FHC_TEST_Y_MASK 15 /* FBC mode definitions */ #define CG6_FBC_BLIT_IGNORE 0x00000000 @@ -150,17 +150,17 @@ static struct fb_ops cg6_ops = { #define CG6_FBC_INDEX_MASK 0x00000030 /* THC definitions */ -#define CG6_THC_MISC_REV_SHIFT 16 -#define CG6_THC_MISC_REV_MASK 15 -#define CG6_THC_MISC_RESET (1 << 12) -#define CG6_THC_MISC_VIDEO (1 << 10) -#define CG6_THC_MISC_SYNC (1 << 9) -#define CG6_THC_MISC_VSYNC (1 << 8) -#define CG6_THC_MISC_SYNC_ENAB (1 << 7) -#define CG6_THC_MISC_CURS_RES (1 << 6) -#define CG6_THC_MISC_INT_ENAB (1 << 5) -#define CG6_THC_MISC_INT (1 << 4) -#define CG6_THC_MISC_INIT 0x9f +#define CG6_THC_MISC_REV_SHIFT 16 +#define CG6_THC_MISC_REV_MASK 15 +#define CG6_THC_MISC_RESET (1 << 12) +#define CG6_THC_MISC_VIDEO (1 << 10) +#define CG6_THC_MISC_SYNC (1 << 9) +#define CG6_THC_MISC_VSYNC (1 << 8) +#define CG6_THC_MISC_SYNC_ENAB (1 << 7) +#define CG6_THC_MISC_CURS_RES (1 << 6) +#define CG6_THC_MISC_INT_ENAB (1 << 5) +#define CG6_THC_MISC_INT (1 << 4) +#define CG6_THC_MISC_INIT 0x9f /* The contents are unknown */ struct cg6_tec { @@ -170,25 +170,25 @@ struct cg6_tec { }; struct cg6_thc { - u32 thc_pad0[512]; - u32 thc_hs; /* hsync timing */ - u32 thc_hsdvs; - u32 thc_hd; - u32 thc_vs; /* vsync timing */ - u32 thc_vd; - u32 thc_refresh; - u32 thc_misc; - u32 thc_pad1[56]; - u32 thc_cursxy; /* cursor x,y position (16 bits each) */ - u32 thc_cursmask[32]; /* cursor mask bits */ - u32 thc_cursbits[32]; /* what to show where mask enabled */ + u32 thc_pad0[512]; + u32 thc_hs; /* hsync timing */ + u32 thc_hsdvs; + u32 thc_hd; + u32 thc_vs; /* vsync timing */ + u32 thc_vd; + u32 thc_refresh; + u32 thc_misc; + u32 thc_pad1[56]; + u32 thc_cursxy; /* cursor x,y position (16 bits each) */ + u32 thc_cursmask[32]; /* cursor mask bits */ + u32 thc_cursbits[32]; /* what to show where mask enabled */ }; struct cg6_fbc { u32 xxx0[1]; u32 mode; u32 clip; - u32 xxx1[1]; + u32 xxx1[1]; u32 s; u32 draw; u32 blit; @@ -243,10 +243,10 @@ struct cg6_fbc { }; struct bt_regs { - u32 addr; - u32 color_map; - u32 control; - u32 cursor; + u32 addr; + u32 color_map; + u32 control; + u32 cursor; }; struct cg6_par { @@ -267,7 +267,7 @@ struct cg6_par { static int cg6_sync(struct fb_info *info) { - struct cg6_par *par = (struct cg6_par *) info->par; + struct cg6_par *par = (struct cg6_par *)info->par; struct cg6_fbc __iomem *fbc = par->fbc; int limit = 10000; @@ -281,24 +281,24 @@ static int cg6_sync(struct fb_info *info) } /** - * cg6_fillrect - REQUIRED function. Can use generic routines if - * non acclerated hardware and packed pixel based. - * Draws a rectangle on the screen. + * cg6_fillrect - Draws a rectangle on the screen. * - * @info: frame buffer structure that represents a single frame buffer - * @rect: structure defining the rectagle and operation. + * @info: frame buffer structure that represents a single frame buffer + * @rect: structure defining the rectagle and operation. */ static void cg6_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { - struct cg6_par *par = (struct cg6_par *) info->par; + struct cg6_par *par = (struct cg6_par *)info->par; struct cg6_fbc __iomem *fbc = par->fbc; unsigned long flags; s32 val; - /* XXX doesn't handle ROP_XOR */ + /* CG6 doesn't handle ROP_XOR */ spin_lock_irqsave(&par->lock, flags); + cg6_sync(info); + sbus_writel(rect->color, &fbc->fg); sbus_writel(~(u32)0, &fbc->pixelm); sbus_writel(0xea80ff00, &fbc->alu); @@ -316,16 +316,56 @@ static void cg6_fillrect(struct fb_info *info, const struct fb_fillrect *rect) } /** - * cg6_imageblit - REQUIRED function. Can use generic routines if - * non acclerated hardware and packed pixel based. - * Copies a image from system memory to the screen. + * cg6_copyarea - Copies one area of the screen to another area. + * + * @info: frame buffer structure that represents a single frame buffer + * @area: Structure providing the data to copy the framebuffer contents + * from one region to another. + * + * This drawing operation copies a rectangular area from one area of the + * screen to another area. + */ +static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area) +{ + struct cg6_par *par = (struct cg6_par *)info->par; + struct cg6_fbc __iomem *fbc = par->fbc; + unsigned long flags; + int i; + + spin_lock_irqsave(&par->lock, flags); + + cg6_sync(info); + + sbus_writel(0xff, &fbc->fg); + sbus_writel(0x00, &fbc->bg); + sbus_writel(~0, &fbc->pixelm); + sbus_writel(0xe880cccc, &fbc->alu); + sbus_writel(0, &fbc->s); + sbus_writel(0, &fbc->clip); + + sbus_writel(area->sy, &fbc->y0); + sbus_writel(area->sx, &fbc->x0); + sbus_writel(area->sy + area->height - 1, &fbc->y1); + sbus_writel(area->sx + area->width - 1, &fbc->x1); + sbus_writel(area->dy, &fbc->y2); + sbus_writel(area->dx, &fbc->x2); + sbus_writel(area->dy + area->height - 1, &fbc->y3); + sbus_writel(area->dx + area->width - 1, &fbc->x3); + do { + i = sbus_readl(&fbc->blit); + } while (i < 0 && (i & 0x20000000)); + spin_unlock_irqrestore(&par->lock, flags); +} + +/** + * cg6_imageblit - Copies a image from system memory to the screen. * - * @info: frame buffer structure that represents a single frame buffer - * @image: structure defining the image. + * @info: frame buffer structure that represents a single frame buffer + * @image: structure defining the image. */ static void cg6_imageblit(struct fb_info *info, const struct fb_image *image) { - struct cg6_par *par = (struct cg6_par *) info->par; + struct cg6_par *par = (struct cg6_par *)info->par; struct cg6_fbc __iomem *fbc = par->fbc; const u8 *data = image->data; unsigned long flags; @@ -363,7 +403,7 @@ static void cg6_imageblit(struct fb_info *info, const struct fb_image *image) sbus_writel(y, &fbc->y0); sbus_writel(x, &fbc->x0); sbus_writel(x + 32 - 1, &fbc->x1); - + val = ((u32)data[0] << 24) | ((u32)data[1] << 16) | ((u32)data[2] << 8) | @@ -404,19 +444,20 @@ static void cg6_imageblit(struct fb_info *info, const struct fb_image *image) } /** - * cg6_setcolreg - Optional function. Sets a color register. - * @regno: boolean, 0 copy local, 1 get_user() function - * @red: frame buffer colormap structure - * @green: The green value which can be up to 16 bits wide - * @blue: The blue value which can be up to 16 bits wide. - * @transp: If supported the alpha value which can be up to 16 bits wide. - * @info: frame buffer info structure + * cg6_setcolreg - Sets a color register. + * + * @regno: boolean, 0 copy local, 1 get_user() function + * @red: frame buffer colormap structure + * @green: The green value which can be up to 16 bits wide + * @blue: The blue value which can be up to 16 bits wide. + * @transp: If supported the alpha value which can be up to 16 bits wide. + * @info: frame buffer info structure */ static int cg6_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info) { - struct cg6_par *par = (struct cg6_par *) info->par; + struct cg6_par *par = (struct cg6_par *)info->par; struct bt_regs __iomem *bt = par->bt; unsigned long flags; @@ -440,25 +481,24 @@ static int cg6_setcolreg(unsigned regno, } /** - * cg6_blank - Optional function. Blanks the display. - * @blank_mode: the blank mode we want. - * @info: frame buffer structure that represents a single frame buffer + * cg6_blank - Blanks the display. + * + * @blank_mode: the blank mode we want. + * @info: frame buffer structure that represents a single frame buffer */ -static int -cg6_blank(int blank, struct fb_info *info) +static int cg6_blank(int blank, struct fb_info *info) { - struct cg6_par *par = (struct cg6_par *) info->par; + struct cg6_par *par = (struct cg6_par *)info->par; struct cg6_thc __iomem *thc = par->thc; unsigned long flags; u32 val; spin_lock_irqsave(&par->lock, flags); + val = sbus_readl(&thc->thc_misc); switch (blank) { case FB_BLANK_UNBLANK: /* Unblanking */ - val = sbus_readl(&thc->thc_misc); val |= CG6_THC_MISC_VIDEO; - sbus_writel(val, &thc->thc_misc); par->flags &= ~CG6_FLAG_BLANKED; break; @@ -466,13 +506,12 @@ cg6_blank(int blank, struct fb_info *info) case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */ case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */ case FB_BLANK_POWERDOWN: /* Poweroff */ - val = sbus_readl(&thc->thc_misc); val &= ~CG6_THC_MISC_VIDEO; - sbus_writel(val, &thc->thc_misc); par->flags |= CG6_FLAG_BLANKED; break; } + sbus_writel(val, &thc->thc_misc); spin_unlock_irqrestore(&par->lock, flags); return 0; @@ -533,7 +572,7 @@ static int cg6_mmap(struct fb_info *info, struct vm_area_struct *vma) static int cg6_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { - struct cg6_par *par = (struct cg6_par *) info->par; + struct cg6_par *par = (struct cg6_par *)info->par; return sbusfb_ioctl_helper(cmd, arg, info, FBTYPE_SUNFAST_COLOR, 8, par->fbsize); @@ -543,15 +582,14 @@ static int cg6_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) * Initialisation */ -static void -cg6_init_fix(struct fb_info *info, int linebytes) +static void __devinit cg6_init_fix(struct fb_info *info, int linebytes) { struct cg6_par *par = (struct cg6_par *)info->par; const char *cg6_cpu_name, *cg6_card_name; u32 conf; conf = sbus_readl(par->fhc); - switch(conf & CG6_FHC_CPU_MASK) { + switch (conf & CG6_FHC_CPU_MASK) { case CG6_FHC_CPU_SPARC: cg6_cpu_name = "sparc"; break; @@ -563,21 +601,19 @@ cg6_init_fix(struct fb_info *info, int linebytes) break; }; if (((conf >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK) >= 11) { - if (par->fbsize <= 0x100000) { + if (par->fbsize <= 0x100000) cg6_card_name = "TGX"; - } else { + else cg6_card_name = "TGX+"; - } } else { - if (par->fbsize <= 0x100000) { + if (par->fbsize <= 0x100000) cg6_card_name = "GX"; - } else { + else cg6_card_name = "GX+"; - } } sprintf(info->fix.id, "%s %s", cg6_card_name, cg6_cpu_name); - info->fix.id[sizeof(info->fix.id)-1] = 0; + info->fix.id[sizeof(info->fix.id) - 1] = 0; info->fix.type = FB_TYPE_PACKED_PIXELS; info->fix.visual = FB_VISUAL_PSEUDOCOLOR; @@ -588,28 +624,28 @@ cg6_init_fix(struct fb_info *info, int linebytes) } /* Initialize Brooktree DAC */ -static void cg6_bt_init(struct cg6_par *par) +static void __devinit cg6_bt_init(struct cg6_par *par) { struct bt_regs __iomem *bt = par->bt; - sbus_writel(0x04 << 24, &bt->addr); /* color planes */ + sbus_writel(0x04 << 24, &bt->addr); /* color planes */ sbus_writel(0xff << 24, &bt->control); sbus_writel(0x05 << 24, &bt->addr); sbus_writel(0x00 << 24, &bt->control); - sbus_writel(0x06 << 24, &bt->addr); /* overlay plane */ + sbus_writel(0x06 << 24, &bt->addr); /* overlay plane */ sbus_writel(0x73 << 24, &bt->control); sbus_writel(0x07 << 24, &bt->addr); sbus_writel(0x00 << 24, &bt->control); } -static void cg6_chip_init(struct fb_info *info) +static void __devinit cg6_chip_init(struct fb_info *info) { - struct cg6_par *par = (struct cg6_par *) info->par; + struct cg6_par *par = (struct cg6_par *)info->par; struct cg6_tec __iomem *tec = par->tec; struct cg6_fbc __iomem *fbc = par->fbc; u32 rev, conf, mode; int i; - + /* Turn off stuff in the Transform Engine. */ sbus_writel(0, &tec->tec_matrix); sbus_writel(0, &tec->tec_clip); @@ -635,13 +671,13 @@ static void cg6_chip_init(struct fb_info *info) i = sbus_readl(&fbc->s); } while (i & 0x10000000); mode &= ~(CG6_FBC_BLIT_MASK | CG6_FBC_MODE_MASK | - CG6_FBC_DRAW_MASK | CG6_FBC_BWRITE0_MASK | - CG6_FBC_BWRITE1_MASK | CG6_FBC_BREAD_MASK | - CG6_FBC_BDISP_MASK); + CG6_FBC_DRAW_MASK | CG6_FBC_BWRITE0_MASK | + CG6_FBC_BWRITE1_MASK | CG6_FBC_BREAD_MASK | + CG6_FBC_BDISP_MASK); mode |= (CG6_FBC_BLIT_SRC | CG6_FBC_MODE_COLOR8 | - CG6_FBC_DRAW_RENDER | CG6_FBC_BWRITE0_ENABLE | - CG6_FBC_BWRITE1_DISABLE | CG6_FBC_BREAD_0 | - CG6_FBC_BDISP_0); + CG6_FBC_DRAW_RENDER | CG6_FBC_BWRITE0_ENABLE | + CG6_FBC_BWRITE1_DISABLE | CG6_FBC_BREAD_0 | + CG6_FBC_BDISP_0); sbus_writel(mode, &fbc->mode); sbus_writel(0, &fbc->clip); @@ -671,7 +707,8 @@ static void cg6_unmap_regs(struct of_device *op, struct fb_info *info, of_iounmap(&op->resource[0], info->screen_base, par->fbsize); } -static int __devinit cg6_probe(struct of_device *op, const struct of_device_id *match) +static int __devinit cg6_probe(struct of_device *op, + const struct of_device_id *match) { struct device_node *dp = op->node; struct fb_info *info; @@ -705,22 +742,23 @@ static int __devinit cg6_probe(struct of_device *op, const struct of_device_id * par->fbsize *= 4; par->fbc = of_ioremap(&op->resource[0], CG6_FBC_OFFSET, - 4096, "cgsix fbc"); + 4096, "cgsix fbc"); par->tec = of_ioremap(&op->resource[0], CG6_TEC_OFFSET, - sizeof(struct cg6_tec), "cgsix tec"); + sizeof(struct cg6_tec), "cgsix tec"); par->thc = of_ioremap(&op->resource[0], CG6_THC_OFFSET, - sizeof(struct cg6_thc), "cgsix thc"); + sizeof(struct cg6_thc), "cgsix thc"); par->bt = of_ioremap(&op->resource[0], CG6_BROOKTREE_OFFSET, - sizeof(struct bt_regs), "cgsix dac"); + sizeof(struct bt_regs), "cgsix dac"); par->fhc = of_ioremap(&op->resource[0], CG6_FHC_OFFSET, - sizeof(u32), "cgsix fhc"); + sizeof(u32), "cgsix fhc"); info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_IMAGEBLIT | - FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT; + FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT | + FBINFO_READS_FAST; info->fbops = &cg6_ops; - info->screen_base = of_ioremap(&op->resource[0], CG6_RAM_OFFSET, - par->fbsize, "cgsix ram"); + info->screen_base = of_ioremap(&op->resource[0], CG6_RAM_OFFSET, + par->fbsize, "cgsix ram"); if (!par->fbc || !par->tec || !par->thc || !par->bt || !par->fhc || !info->screen_base) goto out_unmap_regs; diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c index 4b520b573911..d7e24889650e 100644 --- a/drivers/video/ffb.c +++ b/drivers/video/ffb.c @@ -171,17 +171,17 @@ static struct fb_ops ffb_ops = { #define FFB_PPC_CS_VAR 0x000002 #define FFB_PPC_CS_CONST 0x000003 -#define FFB_ROP_NEW 0x83 -#define FFB_ROP_OLD 0x85 -#define FFB_ROP_NEW_XOR_OLD 0x86 - -#define FFB_UCSR_FIFO_MASK 0x00000fff -#define FFB_UCSR_FB_BUSY 0x01000000 -#define FFB_UCSR_RP_BUSY 0x02000000 -#define FFB_UCSR_ALL_BUSY (FFB_UCSR_RP_BUSY|FFB_UCSR_FB_BUSY) -#define FFB_UCSR_READ_ERR 0x40000000 -#define FFB_UCSR_FIFO_OVFL 0x80000000 -#define FFB_UCSR_ALL_ERRORS (FFB_UCSR_READ_ERR|FFB_UCSR_FIFO_OVFL) +#define FFB_ROP_NEW 0x83 +#define FFB_ROP_OLD 0x85 +#define FFB_ROP_NEW_XOR_OLD 0x86 + +#define FFB_UCSR_FIFO_MASK 0x00000fff +#define FFB_UCSR_FB_BUSY 0x01000000 +#define FFB_UCSR_RP_BUSY 0x02000000 +#define FFB_UCSR_ALL_BUSY (FFB_UCSR_RP_BUSY|FFB_UCSR_FB_BUSY) +#define FFB_UCSR_READ_ERR 0x40000000 +#define FFB_UCSR_FIFO_OVFL 0x80000000 +#define FFB_UCSR_ALL_ERRORS (FFB_UCSR_READ_ERR|FFB_UCSR_FIFO_OVFL) struct ffb_fbc { /* Next vertex registers */ @@ -197,7 +197,7 @@ struct ffb_fbc { u32 ryf; u32 rxf; u32 xxx3[2]; - + u32 dmyf; u32 dmxf; u32 xxx4[2]; @@ -211,13 +211,13 @@ struct ffb_fbc { u32 bh; u32 bw; u32 xxx6[2]; - + u32 xxx7[32]; - + /* Setup unit vertex state register */ u32 suvtx; u32 xxx8[63]; - + /* Control registers */ u32 ppc; u32 wid; @@ -235,7 +235,7 @@ struct ffb_fbc { u32 dcsb; u32 dczf; u32 dczb; - + u32 xxx9; u32 blendc; u32 blendc1; @@ -252,7 +252,7 @@ struct ffb_fbc { u32 fbcfg1; u32 fbcfg2; u32 fbcfg3; - + u32 ppcfg; u32 pick; u32 fillmode; @@ -269,7 +269,7 @@ struct ffb_fbc { u32 clip2max; u32 clip3min; u32 clip3max; - + /* New 3dRAM III support regs */ u32 rawblend2; u32 rawpreblend; @@ -287,7 +287,7 @@ struct ffb_fbc { u32 rawcmp; u32 rawwac; u32 fbramid; - + u32 drawop; u32 xxx10[2]; u32 fontlpat; @@ -302,7 +302,7 @@ struct ffb_fbc { u32 stencil; u32 stencilctl; - u32 xxx13[4]; + u32 xxx13[4]; u32 dcss1; u32 dcss2; u32 dcss3; @@ -315,17 +315,17 @@ struct ffb_fbc { u32 dcd3; u32 dcd4; u32 xxx15; - + u32 pattern[32]; - + u32 xxx16[256]; - + u32 devid; u32 xxx17[63]; - + u32 ucsr; u32 xxx18[31]; - + u32 mer; }; @@ -336,20 +336,20 @@ struct ffb_dac { u32 value2; }; -#define FFB_DAC_UCTRL 0x1001 /* User Control */ -#define FFB_DAC_UCTRL_MANREV 0x00000f00 /* 4-bit Manufacturing Revision */ -#define FFB_DAC_UCTRL_MANREV_SHIFT 8 -#define FFB_DAC_TGEN 0x6000 /* Timing Generator */ -#define FFB_DAC_TGEN_VIDE 0x00000001 /* Video Enable */ -#define FFB_DAC_DID 0x8000 /* Device Identification */ -#define FFB_DAC_DID_PNUM 0x0ffff000 /* Device Part Number */ -#define FFB_DAC_DID_PNUM_SHIFT 12 -#define FFB_DAC_DID_REV 0xf0000000 /* Device Revision */ -#define FFB_DAC_DID_REV_SHIFT 28 +#define FFB_DAC_UCTRL 0x1001 /* User Control */ +#define FFB_DAC_UCTRL_MANREV 0x00000f00 /* 4-bit Manufacturing Revision */ +#define FFB_DAC_UCTRL_MANREV_SHIFT 8 +#define FFB_DAC_TGEN 0x6000 /* Timing Generator */ +#define FFB_DAC_TGEN_VIDE 0x00000001 /* Video Enable */ +#define FFB_DAC_DID 0x8000 /* Device Identification */ +#define FFB_DAC_DID_PNUM 0x0ffff000 /* Device Part Number */ +#define FFB_DAC_DID_PNUM_SHIFT 12 +#define FFB_DAC_DID_REV 0xf0000000 /* Device Revision */ +#define FFB_DAC_DID_REV_SHIFT 28 #define FFB_DAC_CUR_CTRL 0x100 -#define FFB_DAC_CUR_CTRL_P0 0x00000001 -#define FFB_DAC_CUR_CTRL_P1 0x00000002 +#define FFB_DAC_CUR_CTRL_P0 0x00000001 +#define FFB_DAC_CUR_CTRL_P1 0x00000002 struct ffb_par { spinlock_t lock; @@ -382,7 +382,9 @@ static void FFBFifo(struct ffb_par *par, int n) if (cache - n < 0) { fbc = par->fbc; - do { cache = (upa_readl(&fbc->ucsr) & FFB_UCSR_FIFO_MASK) - 8; + do { + cache = (upa_readl(&fbc->ucsr) & FFB_UCSR_FIFO_MASK); + cache -= 8; } while (cache - n < 0); } par->fifo_cache = cache - n; @@ -401,12 +403,12 @@ static void FFBWait(struct ffb_par *par) upa_writel(FFB_UCSR_ALL_ERRORS, &fbc->ucsr); } udelay(10); - } while(--limit > 0); + } while (--limit > 0); } static int ffb_sync(struct fb_info *p) { - struct ffb_par *par = (struct ffb_par *) p->par; + struct ffb_par *par = (struct ffb_par *)p->par; FFBWait(par); return 0; @@ -431,8 +433,8 @@ static void ffb_switch_from_graph(struct ffb_par *par) FFBWait(par); par->fifo_cache = 0; FFBFifo(par, 7); - upa_writel(FFB_PPC_VCE_DISABLE|FFB_PPC_TBE_OPAQUE| - FFB_PPC_APE_DISABLE|FFB_PPC_CS_CONST, + upa_writel(FFB_PPC_VCE_DISABLE | FFB_PPC_TBE_OPAQUE | + FFB_PPC_APE_DISABLE | FFB_PPC_CS_CONST, &fbc->ppc); upa_writel(0x2000707f, &fbc->fbc); upa_writel(par->rop_cache, &fbc->rop); @@ -455,7 +457,7 @@ static void ffb_switch_from_graph(struct ffb_par *par) static int ffb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { - struct ffb_par *par = (struct ffb_par *) info->par; + struct ffb_par *par = (struct ffb_par *)info->par; /* We just use this to catch switches out of * graphics mode. @@ -468,16 +470,14 @@ static int ffb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) } /** - * ffb_fillrect - REQUIRED function. Can use generic routines if - * non acclerated hardware and packed pixel based. - * Draws a rectangle on the screen. + * ffb_fillrect - Draws a rectangle on the screen. * - * @info: frame buffer structure that represents a single frame buffer - * @rect: structure defining the rectagle and operation. + * @info: frame buffer structure that represents a single frame buffer + * @rect: structure defining the rectagle and operation. */ static void ffb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { - struct ffb_par *par = (struct ffb_par *) info->par; + struct ffb_par *par = (struct ffb_par *)info->par; struct ffb_fbc __iomem *fbc = par->fbc; unsigned long flags; u32 fg; @@ -494,9 +494,9 @@ static void ffb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) par->fg_cache = fg; } - ffb_rop(par, (rect->rop == ROP_COPY ? - FFB_ROP_NEW : - FFB_ROP_NEW_XOR_OLD)); + ffb_rop(par, rect->rop == ROP_COPY ? + FFB_ROP_NEW : + FFB_ROP_NEW_XOR_OLD); FFBFifo(par, 5); upa_writel(FFB_DRAWOP_RECTANGLE, &fbc->drawop); @@ -509,18 +509,15 @@ static void ffb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) } /** - * ffb_copyarea - REQUIRED function. Can use generic routines if - * non acclerated hardware and packed pixel based. - * Copies on area of the screen to another area. + * ffb_copyarea - Copies on area of the screen to another area. * - * @info: frame buffer structure that represents a single frame buffer - * @area: structure defining the source and destination. + * @info: frame buffer structure that represents a single frame buffer + * @area: structure defining the source and destination. */ -static void -ffb_copyarea(struct fb_info *info, const struct fb_copyarea *area) +static void ffb_copyarea(struct fb_info *info, const struct fb_copyarea *area) { - struct ffb_par *par = (struct ffb_par *) info->par; + struct ffb_par *par = (struct ffb_par *)info->par; struct ffb_fbc __iomem *fbc = par->fbc; unsigned long flags; @@ -547,16 +544,14 @@ ffb_copyarea(struct fb_info *info, const struct fb_copyarea *area) } /** - * ffb_imageblit - REQUIRED function. Can use generic routines if - * non acclerated hardware and packed pixel based. - * Copies a image from system memory to the screen. + * ffb_imageblit - Copies a image from system memory to the screen. * - * @info: frame buffer structure that represents a single frame buffer - * @image: structure defining the image. + * @info: frame buffer structure that represents a single frame buffer + * @image: structure defining the image. */ static void ffb_imageblit(struct fb_info *info, const struct fb_image *image) { - struct ffb_par *par = (struct ffb_par *) info->par; + struct ffb_par *par = (struct ffb_par *)info->par; struct ffb_fbc __iomem *fbc = par->fbc; const u8 *data = image->data; unsigned long flags; @@ -644,13 +639,14 @@ static void ffb_fixup_var_rgb(struct fb_var_screeninfo *var) } /** - * ffb_setcolreg - Optional function. Sets a color register. - * @regno: boolean, 0 copy local, 1 get_user() function - * @red: frame buffer colormap structure - * @green: The green value which can be up to 16 bits wide - * @blue: The blue value which can be up to 16 bits wide. - * @transp: If supported the alpha value which can be up to 16 bits wide. - * @info: frame buffer info structure + * ffb_setcolreg - Sets a color register. + * + * @regno: boolean, 0 copy local, 1 get_user() function + * @red: frame buffer colormap structure + * @green: The green value which can be up to 16 bits wide + * @blue: The blue value which can be up to 16 bits wide. + * @transp: If supported the alpha value which can be up to 16 bits wide. + * @info: frame buffer info structure */ static int ffb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, @@ -672,14 +668,13 @@ static int ffb_setcolreg(unsigned regno, } /** - * ffb_blank - Optional function. Blanks the display. - * @blank_mode: the blank mode we want. - * @info: frame buffer structure that represents a single frame buffer + * ffb_blank - Optional function. Blanks the display. + * @blank_mode: the blank mode we want. + * @info: frame buffer structure that represents a single frame buffer */ -static int -ffb_blank(int blank, struct fb_info *info) +static int ffb_blank(int blank, struct fb_info *info) { - struct ffb_par *par = (struct ffb_par *) info->par; + struct ffb_par *par = (struct ffb_par *)info->par; struct ffb_dac __iomem *dac = par->dac; unsigned long flags; u32 val; @@ -867,7 +862,7 @@ static int ffb_mmap(struct fb_info *info, struct vm_area_struct *vma) static int ffb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { - struct ffb_par *par = (struct ffb_par *) info->par; + struct ffb_par *par = (struct ffb_par *)info->par; return sbusfb_ioctl_helper(cmd, arg, info, FBTYPE_CREATOR, 24, par->fbsize); @@ -877,8 +872,7 @@ static int ffb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) * Initialisation */ -static void -ffb_init_fix(struct fb_info *info) +static void ffb_init_fix(struct fb_info *info) { struct ffb_par *par = (struct ffb_par *)info->par; const char *ffb_type_name; @@ -902,7 +896,8 @@ ffb_init_fix(struct fb_info *info) info->fix.accel = FB_ACCEL_SUN_CREATOR; } -static int __devinit ffb_probe(struct of_device *op, const struct of_device_id *match) +static int __devinit ffb_probe(struct of_device *op, + const struct of_device_id *match) { struct device_node *dp = op->node; struct ffb_fbc __iomem *fbc; diff --git a/drivers/video/output.c b/drivers/video/output.c index 1473f2c892d2..f2df5519c9c4 100644 --- a/drivers/video/output.c +++ b/drivers/video/output.c @@ -31,7 +31,8 @@ MODULE_DESCRIPTION("Display Output Switcher Lowlevel Control Abstraction"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Luming Yu <luming.yu@intel.com>"); -static ssize_t video_output_show_state(struct class_device *dev,char *buf) +static ssize_t video_output_show_state(struct device *dev, + struct device_attribute *attr, char *buf) { ssize_t ret_size = 0; struct output_device *od = to_output_device(dev); @@ -40,8 +41,9 @@ static ssize_t video_output_show_state(struct class_device *dev,char *buf) return ret_size; } -static ssize_t video_output_store_state(struct class_device *dev, - const char *buf,size_t count) +static ssize_t video_output_store_state(struct device *dev, + struct device_attribute *attr, + const char *buf,size_t count) { char *endp; struct output_device *od = to_output_device(dev); @@ -60,21 +62,22 @@ static ssize_t video_output_store_state(struct class_device *dev, return count; } -static void video_output_class_release(struct class_device *dev) +static void video_output_release(struct device *dev) { struct output_device *od = to_output_device(dev); kfree(od); } -static struct class_device_attribute video_output_attributes[] = { +static struct device_attribute video_output_attributes[] = { __ATTR(state, 0644, video_output_show_state, video_output_store_state), __ATTR_NULL, }; + static struct class video_output_class = { .name = "video_output", - .release = video_output_class_release, - .class_dev_attrs = video_output_attributes, + .dev_release = video_output_release, + .dev_attrs = video_output_attributes, }; struct output_device *video_output_register(const char *name, @@ -91,11 +94,11 @@ struct output_device *video_output_register(const char *name, goto error_return; } new_dev->props = op; - new_dev->class_dev.class = &video_output_class; - new_dev->class_dev.dev = dev; - strlcpy(new_dev->class_dev.class_id,name,KOBJ_NAME_LEN); - class_set_devdata(&new_dev->class_dev,devdata); - ret_code = class_device_register(&new_dev->class_dev); + new_dev->dev.class = &video_output_class; + new_dev->dev.parent = dev; + strlcpy(new_dev->dev.bus_id,name, BUS_ID_SIZE); + dev_set_drvdata(&new_dev->dev, devdata); + ret_code = device_register(&new_dev->dev); if (ret_code) { kfree(new_dev); goto error_return; @@ -111,7 +114,7 @@ void video_output_unregister(struct output_device *dev) { if (!dev) return; - class_device_unregister(&dev->class_dev); + device_unregister(&dev->dev); } EXPORT_SYMBOL(video_output_unregister); diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c index 7d6c29800d14..06805c9b237b 100644 --- a/drivers/video/pvr2fb.c +++ b/drivers/video/pvr2fb.c @@ -667,6 +667,8 @@ static int pvr2_init_cable(void) related */ if (cable_type == CT_COMPOSITE) fb_writel(3 << 8, VOUTC); + else if (cable_type == CT_RGB) + fb_writel(1 << 9, VOUTC); else fb_writel(0, VOUTC); @@ -890,7 +892,7 @@ static int __init pvr2fb_dc_init(void) pvr2_fix.mmio_start = 0xa05f8000; /* registers start here */ pvr2_fix.mmio_len = 0x2000; - if (request_irq(HW_EVENT_VSYNC, pvr2fb_interrupt, 0, + if (request_irq(HW_EVENT_VSYNC, pvr2fb_interrupt, IRQF_SHARED, "pvr2 VBL handler", fb_info)) { return -EBUSY; } diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index 6ef99b2d13ca..e38d3b7c3ad7 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -84,7 +84,7 @@ static struct xilinxfb_platform_data xilinx_fb_default_pdata = { .xres = 640, .yres = 480, .xvirt = 1024, - .yvirt = 480; + .yvirt = 480, }; /* diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index a593f900eff4..070217322c9f 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -197,7 +197,7 @@ static struct w1_family w1_default_family = { .fops = &w1_default_fops, }; -static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size); +static int w1_uevent(struct device *dev, struct kobj_uevent_env *env); static struct bus_type w1_bus_type = { .name = "w1", @@ -396,13 +396,12 @@ static void w1_destroy_master_attributes(struct w1_master *master) } #ifdef CONFIG_HOTPLUG -static int w1_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int w1_uevent(struct device *dev, struct kobj_uevent_env *env) { struct w1_master *md = NULL; struct w1_slave *sl = NULL; char *event_owner, *name; - int err, cur_index=0, cur_len=0; + int err; if (dev->driver == &w1_master_driver) { md = container_of(dev, struct w1_master, dev); @@ -423,23 +422,19 @@ static int w1_uevent(struct device *dev, char **envp, int num_envp, if (dev->driver != &w1_slave_driver || !sl) return 0; - err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size, - &cur_len, "W1_FID=%02X", sl->reg_num.family); + err = add_uevent_var(env, "W1_FID=%02X", sl->reg_num.family); if (err) return err; - err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size, - &cur_len, "W1_SLAVE_ID=%024LX", - (unsigned long long)sl->reg_num.id); - envp[cur_index] = NULL; + err = add_uevent_var(env, "W1_SLAVE_ID=%024LX", + (unsigned long long)sl->reg_num.id); if (err) return err; return 0; }; #else -static int w1_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int w1_uevent(struct device *dev, struct kobj_uevent_env *env) { return 0; } |