From a0c36a1f0fbab42590dab3c13c10fa7d20e6c2cd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 22 Jun 2009 22:41:15 -0300 Subject: i7core_edac: Add an EDAC memory controller driver for Nehalem chipsets This driver is meant to support i7 core/i7core extreme desktop processors and Xeon 35xx/55xx series with integrated memory controller. It is likely that it can be expanded in the future to work with other processor series based at the same Memory Controller design. For now, it has just a few MCH status reads. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/Kconfig | 7 + drivers/edac/Makefile | 1 + drivers/edac/i7core_edac.c | 462 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 470 insertions(+) create mode 100644 drivers/edac/i7core_edac.c (limited to 'drivers') diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 55c9c59b3f71..391ddbfb2a34 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -166,6 +166,13 @@ config EDAC_I5400 Support for error detection and correction the Intel i5400 MCH chipset (Seaburg). +config EDAC_I7CORE + tristate "Intel i7 Core (Nehalem) processors" + depends on EDAC_MM_EDAC && PCI && X86 + help + Support for error detection and correction the Intel + i7 Core (Nehalem) Integrated Memory Controller + config EDAC_I82860 tristate "Intel 82860" depends on EDAC_MM_EDAC && PCI && X86_32 diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index bc5dc232a0fb..b9996195b233 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_EDAC_CPC925) += cpc925_edac.o obj-$(CONFIG_EDAC_I5000) += i5000_edac.o obj-$(CONFIG_EDAC_I5100) += i5100_edac.o obj-$(CONFIG_EDAC_I5400) += i5400_edac.o +obj-$(CONFIG_EDAC_I7CORE) += i7core_edac.o obj-$(CONFIG_EDAC_E7XXX) += e7xxx_edac.o obj-$(CONFIG_EDAC_E752X) += e752x_edac.o obj-$(CONFIG_EDAC_I82443BXGX) += i82443bxgx_edac.o diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c new file mode 100644 index 000000000000..7ecf15e66a3f --- /dev/null +++ b/drivers/edac/i7core_edac.c @@ -0,0 +1,462 @@ +/* Intel 7 core Memory Controller kernel module (Nehalem) + * + * This file may be distributed under the terms of the + * GNU General Public License version 2 only. + * + * Copyright (c) 2009 by: + * Mauro Carvalho Chehab + * + * Red Hat Inc. http://www.redhat.com + * + * Forked and adapted from the i5400_edac driver + * + * Based on the following public Intel datasheets: + * Intel Core i7 Processor Extreme Edition and Intel Core i7 Processor + * Datasheet, Volume 2: + * http://download.intel.com/design/processor/datashts/320835.pdf + * Intel Xeon Processor 5500 Series Datasheet Volume 2 + * http://www.intel.com/Assets/PDF/datasheet/321322.pdf + * also available at: + * http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include "edac_core.h" + + +/* + * Alter this version for the module when modifications are made + */ +#define I7CORE_REVISION " Ver: 1.0.0 " __DATE__ +#define EDAC_MOD_STR "i7core_edac" + +/* HACK: temporary, just to enable all logs, for now */ +#undef debugf0 +#define debugf0(fmt, arg...) edac_printk(KERN_INFO, "i7core", fmt, ##arg) + +/* + * Debug macros + */ +#define i7core_printk(level, fmt, arg...) \ + edac_printk(level, "i7core", fmt, ##arg) + +#define i7core_mc_printk(mci, level, fmt, arg...) \ + edac_mc_chipset_printk(mci, level, "i7core", fmt, ##arg) + +/* + * i7core Memory Controller Registers + */ + + /* OFFSETS for Device 3 Function 0 */ + +#define MC_CONTROL 0x48 +#define MC_STATUS 0x4c +#define MC_MAX_DOD 0x64 + + /* OFFSETS for Devices 4,5 and 6 Function 0 */ + +#define MC_CHANNEL_ADDR_MATCH 0xf0 + +#define MC_MASK_DIMM (1 << 41) +#define MC_MASK_RANK (1 << 40) +#define MC_MASK_BANK (1 << 39) +#define MC_MASK_PAGE (1 << 38) +#define MC_MASK_COL (1 << 37) + +/* + * i7core structs + */ + +#define NUM_CHANS 3 +#define NUM_FUNCS 1 + +struct i7core_info { + u32 mc_control; + u32 mc_status; + u32 max_dod; +}; + +struct i7core_pvt { + struct pci_dev *pci_mcr; /* Dev 3:0 */ + struct pci_dev *pci_ch[NUM_CHANS][NUM_FUNCS]; + struct i7core_info info; +}; + +/* Device name and register DID (Device ID) */ +struct i7core_dev_info { + const char *ctl_name; /* name for this device */ + u16 fsb_mapping_errors; /* DID for the branchmap,control */ +}; + +static int chan_pci_ids[NUM_CHANS] = { + PCI_DEVICE_ID_INTEL_I7_MC_CH0_CTRL, /* Dev 4 */ + PCI_DEVICE_ID_INTEL_I7_MC_CH1_CTRL, /* Dev 5 */ + PCI_DEVICE_ID_INTEL_I7_MC_CH2_CTRL, /* Dev 6 */ +}; + +/* Table of devices attributes supported by this driver */ +static const struct i7core_dev_info i7core_devs[] = { + { + .ctl_name = "i7 Core", + .fsb_mapping_errors = PCI_DEVICE_ID_INTEL_I7_MCR, + }, +}; + +static struct edac_pci_ctl_info *i7core_pci; + +/**************************************************************************** + Anciliary status routines + ****************************************************************************/ + + /* MC_CONTROL bits */ +#define CH2_ACTIVE(pvt) ((pvt)->info.mc_control & 1 << 10) +#define CH1_ACTIVE(pvt) ((pvt)->info.mc_control & 1 << 9) +#define CH0_ACTIVE(pvt) ((pvt)->info.mc_control & 1 << 8) +#define ECCx8(pvt) ((pvt)->info.mc_control & 1 << 1) + + /* MC_STATUS bits */ +#define ECC_ENABLED(pvt) ((pvt)->info.mc_status & 1 << 3) +#define CH2_DISABLED(pvt) ((pvt)->info.mc_status & 1 << 2) +#define CH1_DISABLED(pvt) ((pvt)->info.mc_status & 1 << 1) +#define CH0_DISABLED(pvt) ((pvt)->info.mc_status & 1 << 0) + + /* MC_MAX_DOD read functions */ +static inline int maxnumdimms(struct i7core_pvt *pvt) +{ + return (pvt->info.max_dod & 0x3) + 1; +} + +static inline int maxnumrank(struct i7core_pvt *pvt) +{ + static int ranks[4] = { 1, 2, 4, -EINVAL }; + + return ranks[(pvt->info.max_dod >> 2) & 0x3]; +} + +static inline int maxnumbank(struct i7core_pvt *pvt) +{ + static int banks[4] = { 4, 8, 16, -EINVAL }; + + return banks[(pvt->info.max_dod >> 4) & 0x3]; +} + +static inline int maxnumrow(struct i7core_pvt *pvt) +{ + static int rows[8] = { + 1 << 12, 1 << 13, 1 << 14, 1 << 15, + 1 << 16, -EINVAL, -EINVAL, -EINVAL, + }; + + return rows[((pvt->info.max_dod >> 6) & 0x7)]; +} + +static inline int maxnumcol(struct i7core_pvt *pvt) +{ + static int cols[8] = { + 1 << 10, 1 << 11, 1 << 12, -EINVAL, + }; + return cols[((pvt->info.max_dod >> 9) & 0x3) << 12]; +} + +/**************************************************************************** + Memory check routines + ****************************************************************************/ +static int get_dimm_config(struct mem_ctl_info *mci) +{ + struct i7core_pvt *pvt = mci->pvt_info; + + pci_read_config_dword(pvt->pci_mcr, MC_CONTROL, &pvt->info.mc_control); + pci_read_config_dword(pvt->pci_mcr, MC_STATUS, &pvt->info.mc_status); + pci_read_config_dword(pvt->pci_mcr, MC_MAX_DOD, &pvt->info.max_dod); + + debugf0("Channels active [%c][%c][%c] - enabled [%c][%c][%c]\n", + CH0_ACTIVE(pvt)?'0':'-', + CH1_ACTIVE(pvt)?'1':'-', + CH2_ACTIVE(pvt)?'2':'-', + CH0_DISABLED(pvt)?'-':'0', + CH1_DISABLED(pvt)?'-':'1', + CH2_DISABLED(pvt)?'-':'2'); + + if (ECC_ENABLED(pvt)) + debugf0("ECC enabled with x%d SDCC\n", ECCx8(pvt)?8:4); + else + debugf0("ECC disabled\n"); + + /* FIXME: need to handle the error codes */ + debugf0("DOD Maximum limits: DIMMS: %d, %d-ranked, %d-banked\n", + maxnumdimms(pvt), maxnumrank(pvt), maxnumbank(pvt)); + debugf0("DOD Maximum rows x colums = 0x%x x 0x%x\n", + maxnumrow(pvt), maxnumcol(pvt)); + + return 0; +} + +/**************************************************************************** + Device initialization routines: put/get, init/exit + ****************************************************************************/ + +/* + * i7core_put_devices 'put' all the devices that we have + * reserved via 'get' + */ +static void i7core_put_devices(struct mem_ctl_info *mci) +{ + struct i7core_pvt *pvt = mci->pvt_info; + int i, n; + + pci_dev_put(pvt->pci_mcr); + + /* Release all PCI device functions at MTR channel controllers */ + for (i = 0; i < NUM_CHANS; i++) + for (n = 0; n < NUM_FUNCS; n++) + pci_dev_put(pvt->pci_ch[i][n]); +} + +/* + * i7core_get_devices Find and perform 'get' operation on the MCH's + * device/functions we want to reference for this driver + * + * Need to 'get' device 16 func 1 and func 2 + */ +static int i7core_get_devices(struct mem_ctl_info *mci, int dev_idx) +{ + struct i7core_pvt *pvt; + struct pci_dev *pdev; + int i, n, func; + + pvt = mci->pvt_info; + memset(pvt, 0, sizeof(*pvt)); + + pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_MCR, + NULL); + if (!pdev) { + i7core_printk(KERN_ERR, + "Couldn't get PCI ID %04x:%04x function 0\n", + PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_MCR); + return -ENODEV; + } + pvt->pci_mcr=pdev; + + /* Get dimm basic config */ + get_dimm_config(mci); + + /* Retrieve all needed functions at MTR channel controllers */ + for (i = 0; i < NUM_CHANS; i++) { + pdev = NULL; + for (n = 0; n < NUM_FUNCS; n++) { + pdev = pci_get_device(PCI_VENDOR_ID_INTEL, + chan_pci_ids[i], pdev); + if (!pdev) { + /* End of list, leave */ + i7core_printk(KERN_ERR, + "Device not found: PCI ID %04x:%04x " + "found only %d functions " + "(broken BIOS?)\n", + PCI_VENDOR_ID_INTEL, + chan_pci_ids[i], n); + i7core_put_devices(mci); + return -ENODEV; + } + func = PCI_FUNC(pdev->devfn); + pvt->pci_ch[i][func] = pdev; + } + } + i7core_printk(KERN_INFO, "Driver loaded.\n"); + + return 0; +} + +/* + * i7core_probe Probe for ONE instance of device to see if it is + * present. + * return: + * 0 for FOUND a device + * < 0 for error code + */ +static int __devinit i7core_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct mem_ctl_info *mci; + struct i7core_pvt *pvt; + int rc; + int num_channels; + int num_csrows; + int num_dimms_per_channel; + int dev_idx = id->driver_data; + + if (dev_idx >= ARRAY_SIZE(i7core_devs)) + return -EINVAL; + + /* wake up device */ + rc = pci_enable_device(pdev); + if (rc == -EIO) + return rc; + + debugf0("MC: " __FILE__ ": %s(), pdev bus %u dev=0x%x fn=0x%x\n", + __func__, + pdev->bus->number, + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); + + /* We only are looking for func 0 of the set */ + if (PCI_FUNC(pdev->devfn) != 0) + return -ENODEV; + + num_channels = NUM_CHANS; + + /* FIXME: FAKE data, since we currently don't now how to get this */ + num_dimms_per_channel = 4; + num_csrows = num_dimms_per_channel; + + /* allocate a new MC control structure */ + mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); + if (mci == NULL) + return -ENOMEM; + + debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); + + mci->dev = &pdev->dev; /* record ptr to the generic device */ + dev_set_drvdata(mci->dev, mci); + + pvt = mci->pvt_info; +// pvt->system_address = pdev; /* Record this device in our private */ +// pvt->maxch = num_channels; +// pvt->maxdimmperch = num_dimms_per_channel; + + /* 'get' the pci devices we want to reserve for our use */ + if (i7core_get_devices(mci, dev_idx)) + goto fail0; + + mci->mc_idx = 0; + mci->mtype_cap = MEM_FLAG_FB_DDR2; /* FIXME: it uses DDR3 */ + mci->edac_ctl_cap = EDAC_FLAG_NONE; + mci->edac_cap = EDAC_FLAG_NONE; + mci->mod_name = "i7core_edac.c"; + mci->mod_ver = I7CORE_REVISION; + mci->ctl_name = i7core_devs[dev_idx].ctl_name; + mci->dev_name = pci_name(pdev); + mci->ctl_page_to_phys = NULL; + + /* add this new MC control structure to EDAC's list of MCs */ + if (edac_mc_add_mc(mci)) { + debugf0("MC: " __FILE__ + ": %s(): failed edac_mc_add_mc()\n", __func__); + /* FIXME: perhaps some code should go here that disables error + * reporting if we just enabled it + */ + goto fail1; + } + + /* allocating generic PCI control info */ + i7core_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); + if (!i7core_pci) { + printk(KERN_WARNING + "%s(): Unable to create PCI control\n", + __func__); + printk(KERN_WARNING + "%s(): PCI error report via EDAC not setup\n", + __func__); + } + + return 0; + +fail1: + i7core_put_devices(mci); + +fail0: + edac_mc_free(mci); + return -ENODEV; +} + +/* + * i7core_remove destructor for one instance of device + * + */ +static void __devexit i7core_remove(struct pci_dev *pdev) +{ + struct mem_ctl_info *mci; + + debugf0(__FILE__ ": %s()\n", __func__); + + if (i7core_pci) + edac_pci_release_generic_ctl(i7core_pci); + + mci = edac_mc_del_mc(&pdev->dev); + if (!mci) + return; + + /* retrieve references to resources, and free those resources */ + i7core_put_devices(mci); + + edac_mc_free(mci); +} + +/* + * pci_device_id table for which devices we are looking for + * + * The "E500P" device is the first device supported. + */ +static const struct pci_device_id i7core_pci_tbl[] __devinitdata = { + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_MCR)}, + {0,} /* 0 terminated list. */ +}; + +MODULE_DEVICE_TABLE(pci, i7core_pci_tbl); + +/* + * i7core_driver pci_driver structure for this module + * + */ +static struct pci_driver i7core_driver = { + .name = "i7core_edac", + .probe = i7core_probe, + .remove = __devexit_p(i7core_remove), + .id_table = i7core_pci_tbl, +}; + +/* + * i7core_init Module entry function + * Try to initialize this module for its devices + */ +static int __init i7core_init(void) +{ + int pci_rc; + + debugf2("MC: " __FILE__ ": %s()\n", __func__); + + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + + pci_rc = pci_register_driver(&i7core_driver); + + return (pci_rc < 0) ? pci_rc : 0; +} + +/* + * i7core_exit() Module exit function + * Unregister the driver + */ +static void __exit i7core_exit(void) +{ + debugf2("MC: " __FILE__ ": %s()\n", __func__); + pci_unregister_driver(&i7core_driver); +} + +module_init(i7core_init); +module_exit(i7core_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); +MODULE_DESCRIPTION("MC Driver for Intel i7 Core memory controllers - " + I7CORE_REVISION); + +module_param(edac_op_state, int, 0444); +MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); -- cgit v1.2.3 From 194a40feabb7cab38911a357c86e968e98024281 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 22 Jun 2009 22:48:28 -0300 Subject: i7core_edac: Add error insertion code for Nehalem Implements set_inject_error() with the low-level code needed to inject memory errors at Nehalem, and adds some sysfs nodes to allow error injection The next patch will add an API for error injection. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 427 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 419 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 7ecf15e66a3f..b590f8468693 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -20,7 +20,6 @@ * http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf */ - #include #include #include @@ -64,12 +63,16 @@ /* OFFSETS for Devices 4,5 and 6 Function 0 */ #define MC_CHANNEL_ADDR_MATCH 0xf0 - -#define MC_MASK_DIMM (1 << 41) -#define MC_MASK_RANK (1 << 40) -#define MC_MASK_BANK (1 << 39) -#define MC_MASK_PAGE (1 << 38) -#define MC_MASK_COL (1 << 37) +#define MC_CHANNEL_ERROR_MASK 0xf8 +#define MC_CHANNEL_ERROR_INJECT 0xfc + #define INJECT_ADDR_PARITY 0x10 + #define INJECT_ECC 0x08 + #define MASK_CACHELINE 0x06 + #define MASK_FULL_CACHELINE 0x06 + #define MASK_MSB32_CACHELINE 0x04 + #define MASK_LSB32_CACHELINE 0x02 + #define NO_MASK_CACHELINE 0x00 + #define REPEAT_EN 0x01 /* * i7core structs @@ -84,10 +87,23 @@ struct i7core_info { u32 max_dod; }; + +struct i7core_inject { + int enable; + + u32 section; + u32 type; + u32 eccmask; + + /* Error address mask */ + int channel, dimm, rank, bank, page, col; +}; + struct i7core_pvt { struct pci_dev *pci_mcr; /* Dev 3:0 */ struct pci_dev *pci_ch[NUM_CHANS][NUM_FUNCS]; struct i7core_info info; + struct i7core_inject inject; }; /* Device name and register DID (Device ID) */ @@ -166,6 +182,7 @@ static inline int maxnumcol(struct i7core_pvt *pvt) return cols[((pvt->info.max_dod >> 9) & 0x3) << 12]; } + /**************************************************************************** Memory check routines ****************************************************************************/ @@ -199,6 +216,390 @@ static int get_dimm_config(struct mem_ctl_info *mci) return 0; } +/**************************************************************************** + Error insertion routines + ****************************************************************************/ + +/* The i7core has independent error injection features per channel. + However, to have a simpler code, we don't allow enabling error injection + on more than one channel. + Also, since a change at an inject parameter will be applied only at enable, + we're disabling error injection on all write calls to the sysfs nodes that + controls the error code injection. + */ +static void disable_inject(struct mem_ctl_info *mci) +{ + struct i7core_pvt *pvt = mci->pvt_info; + + pvt->inject.enable = 0; + + pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], + MC_CHANNEL_ERROR_MASK, 0); +} + +/* + * i7core inject inject.section + * + * accept and store error injection inject.section value + * bit 0 - refers to the lower 32-byte half cacheline + * bit 1 - refers to the upper 32-byte half cacheline + */ +static ssize_t i7core_inject_section_store(struct mem_ctl_info *mci, + const char *data, size_t count) +{ + struct i7core_pvt *pvt = mci->pvt_info; + unsigned long value; + int rc; + + if (pvt->inject.enable) + disable_inject(mci); + + rc = strict_strtoul(data, 10, &value); + if ((rc < 0) || (value > 3)) + return 0; + + pvt->inject.section = (u32) value; + return count; +} + +static ssize_t i7core_inject_section_show(struct mem_ctl_info *mci, + char *data) +{ + struct i7core_pvt *pvt = mci->pvt_info; + return sprintf(data, "0x%08x\n", pvt->inject.section); +} + +/* + * i7core inject.type + * + * accept and store error injection inject.section value + * bit 0 - repeat enable - Enable error repetition + * bit 1 - inject ECC error + * bit 2 - inject parity error + */ +static ssize_t i7core_inject_type_store(struct mem_ctl_info *mci, + const char *data, size_t count) +{ + struct i7core_pvt *pvt = mci->pvt_info; + unsigned long value; + int rc; + + if (pvt->inject.enable) + disable_inject(mci); + + rc = strict_strtoul(data, 10, &value); + if ((rc < 0) || (value > 7)) + return 0; + + pvt->inject.type = (u32) value; + return count; +} + +static ssize_t i7core_inject_type_show(struct mem_ctl_info *mci, + char *data) +{ + struct i7core_pvt *pvt = mci->pvt_info; + return sprintf(data, "0x%08x\n", pvt->inject.type); +} + +/* + * i7core_inject_inject.eccmask_store + * + * The type of error (UE/CE) will depend on the inject.eccmask value: + * Any bits set to a 1 will flip the corresponding ECC bit + * Correctable errors can be injected by flipping 1 bit or the bits within + * a symbol pair (2 consecutive aligned 8-bit pairs - i.e. 7:0 and 15:8 or + * 23:16 and 31:24). Flipping bits in two symbol pairs will cause an + * uncorrectable error to be injected. + */ +static ssize_t i7core_inject_eccmask_store(struct mem_ctl_info *mci, + const char *data, size_t count) +{ + struct i7core_pvt *pvt = mci->pvt_info; + unsigned long value; + int rc; + + if (pvt->inject.enable) + disable_inject(mci); + + rc = strict_strtoul(data, 10, &value); + if (rc < 0) + return 0; + + pvt->inject.eccmask = (u32) value; + return count; +} + +static ssize_t i7core_inject_eccmask_show(struct mem_ctl_info *mci, + char *data) +{ + struct i7core_pvt *pvt = mci->pvt_info; + return sprintf(data, "0x%08x\n", pvt->inject.eccmask); +} + +/* + * i7core_addrmatch + * + * The type of error (UE/CE) will depend on the inject.eccmask value: + * Any bits set to a 1 will flip the corresponding ECC bit + * Correctable errors can be injected by flipping 1 bit or the bits within + * a symbol pair (2 consecutive aligned 8-bit pairs - i.e. 7:0 and 15:8 or + * 23:16 and 31:24). Flipping bits in two symbol pairs will cause an + * uncorrectable error to be injected. + */ +static ssize_t i7core_inject_addrmatch_store(struct mem_ctl_info *mci, + const char *data, size_t count) +{ + struct i7core_pvt *pvt = mci->pvt_info; + char *cmd, *val; + long value; + int rc; + + if (pvt->inject.enable) + disable_inject(mci); + + do { + cmd = strsep((char **) &data, ":"); + if (!cmd) + break; + val = strsep((char **) &data, " \n\t"); + if (!val) + return cmd - data; + + if (!strcasecmp(val,"any")) + value = -1; + else { + rc = strict_strtol(val, 10, &value); + if ((rc < 0) || (value < 0)) + return cmd - data; + } + + if (!strcasecmp(cmd,"channel")) { + if (value < 3) + pvt->inject.channel = value; + else + return cmd - data; + } else if (!strcasecmp(cmd,"dimm")) { + if (value < 4) + pvt->inject.dimm = value; + else + return cmd - data; + } else if (!strcasecmp(cmd,"rank")) { + if (value < 4) + pvt->inject.rank = value; + else + return cmd - data; + } else if (!strcasecmp(cmd,"bank")) { + if (value < 4) + pvt->inject.bank = value; + else + return cmd - data; + } else if (!strcasecmp(cmd,"page")) { + if (value <= 0xffff) + pvt->inject.page = value; + else + return cmd - data; + } else if (!strcasecmp(cmd,"col") || + !strcasecmp(cmd,"column")) { + if (value <= 0x3fff) + pvt->inject.col = value; + else + return cmd - data; + } + } while (1); + + return count; +} + +static ssize_t i7core_inject_addrmatch_show(struct mem_ctl_info *mci, + char *data) +{ + struct i7core_pvt *pvt = mci->pvt_info; + char channel[4], dimm[4], bank[4], rank[4], page[7], col[7]; + + if (pvt->inject.channel < 0) + sprintf(channel, "any"); + else + sprintf(channel, "%d", pvt->inject.channel); + if (pvt->inject.dimm < 0) + sprintf(dimm, "any"); + else + sprintf(dimm, "%d", pvt->inject.dimm); + if (pvt->inject.bank < 0) + sprintf(bank, "any"); + else + sprintf(bank, "%d", pvt->inject.bank); + if (pvt->inject.rank < 0) + sprintf(rank, "any"); + else + sprintf(rank, "%d", pvt->inject.rank); + if (pvt->inject.page < 0) + sprintf(page, "any"); + else + sprintf(page, "0x%04x", pvt->inject.page); + if (pvt->inject.col < 0) + sprintf(col, "any"); + else + sprintf(col, "0x%04x", pvt->inject.col); + + return sprintf(data, "channel: %s\ndimm: %s\nbank: %s\n" + "rank: %s\npage: %s\ncolumn: %s\n", + channel, dimm, bank, rank, page, col); +} + +/* + * This routine prepares the Memory Controller for error injection. + * The error will be injected when some process tries to write to the + * memory that matches the given criteria. + * The criteria can be set in terms of a mask where dimm, rank, bank, page + * and col can be specified. + * A -1 value for any of the mask items will make the MCU to ignore + * that matching criteria for error injection. + * + * It should be noticed that the error will only happen after a write operation + * on a memory that matches the condition. if REPEAT_EN is not enabled at + * inject mask, then it will produce just one error. Otherwise, it will repeat + * until the injectmask would be cleaned. + * + * FIXME: This routine assumes that MAXNUMDIMMS value of MC_MAX_DOD + * is reliable enough to check if the MC is using the + * three channels. However, this is not clear at the datasheet. + */ +static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, + const char *data, size_t count) +{ + struct i7core_pvt *pvt = mci->pvt_info; + u32 injectmask; + u64 mask = 0; + int rc; + long enable; + + rc = strict_strtoul(data, 10, &enable); + if ((rc < 0)) + return 0; + + if (enable) { + pvt->inject.enable = 1; + } else { + disable_inject(mci); + return count; + } + + /* Sets pvt->inject.dimm mask */ + if (pvt->inject.dimm < 0) + mask |= 1l << 41; + else { + if (maxnumdimms(pvt) > 2) + mask |= (pvt->inject.dimm & 0x3l) << 35; + else + mask |= (pvt->inject.dimm & 0x1l) << 36; + } + + /* Sets pvt->inject.rank mask */ + if (pvt->inject.rank < 0) + mask |= 1l << 40; + else { + if (maxnumdimms(pvt) > 2) + mask |= (pvt->inject.rank & 0x1l) << 34; + else + mask |= (pvt->inject.rank & 0x3l) << 34; + } + + /* Sets pvt->inject.bank mask */ + if (pvt->inject.bank < 0) + mask |= 1l << 39; + else + mask |= (pvt->inject.bank & 0x15l) << 30; + + /* Sets pvt->inject.page mask */ + if (pvt->inject.page < 0) + mask |= 1l << 38; + else + mask |= (pvt->inject.page & 0xffffl) << 14; + + /* Sets pvt->inject.column mask */ + if (pvt->inject.col < 0) + mask |= 1l << 37; + else + mask |= (pvt->inject.col & 0x3fffl); + + pci_write_config_qword(pvt->pci_ch[pvt->inject.channel][0], + MC_CHANNEL_ADDR_MATCH, mask); + + pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], + MC_CHANNEL_ERROR_MASK, pvt->inject.eccmask); + + /* + * bit 0: REPEAT_EN + * bits 1-2: MASK_HALF_CACHELINE + * bit 3: INJECT_ECC + * bit 4: INJECT_ADDR_PARITY + */ + + injectmask = (pvt->inject.type & 1) && + (pvt->inject.section & 0x3) << 1 && + (pvt->inject.type & 0x6) << (3 - 1); + + pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], + MC_CHANNEL_ERROR_MASK, injectmask); + + + debugf0("Error inject addr match 0x%016llx, ecc 0x%08x, inject 0x%08x\n", + mask, pvt->inject.eccmask, injectmask); + + return count; +} + +static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci, + char *data) +{ + struct i7core_pvt *pvt = mci->pvt_info; + return sprintf(data, "%d\n", pvt->inject.enable); +} + +/* + * Sysfs struct + */ +static struct mcidev_sysfs_attribute i7core_inj_attrs[] = { + + { + .attr = { + .name = "inject_section", + .mode = (S_IRUGO | S_IWUSR) + }, + .show = i7core_inject_section_show, + .store = i7core_inject_section_store, + }, { + .attr = { + .name = "inject_type", + .mode = (S_IRUGO | S_IWUSR) + }, + .show = i7core_inject_type_show, + .store = i7core_inject_type_store, + }, { + .attr = { + .name = "inject_eccmask", + .mode = (S_IRUGO | S_IWUSR) + }, + .show = i7core_inject_eccmask_show, + .store = i7core_inject_eccmask_store, + }, { + .attr = { + .name = "inject_addrmatch", + .mode = (S_IRUGO | S_IWUSR) + }, + .show = i7core_inject_addrmatch_show, + .store = i7core_inject_addrmatch_store, + }, { + .attr = { + .name = "inject_enable", + .mode = (S_IRUGO | S_IWUSR) + }, + .show = i7core_inject_enable_show, + .store = i7core_inject_enable_store, + }, +}; + /**************************************************************************** Device initialization routines: put/get, init/exit ****************************************************************************/ @@ -322,10 +723,11 @@ static int __devinit i7core_probe(struct pci_dev *pdev, debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); - mci->dev = &pdev->dev; /* record ptr to the generic device */ + mci->dev = &pdev->dev; /* record ptr to the generic device */ dev_set_drvdata(mci->dev, mci); pvt = mci->pvt_info; + // pvt->system_address = pdev; /* Record this device in our private */ // pvt->maxch = num_channels; // pvt->maxdimmperch = num_dimms_per_channel; @@ -343,6 +745,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, mci->ctl_name = i7core_devs[dev_idx].ctl_name; mci->dev_name = pci_name(pdev); mci->ctl_page_to_phys = NULL; + mci->mc_driver_sysfs_attributes = i7core_inj_attrs; /* add this new MC control structure to EDAC's list of MCs */ if (edac_mc_add_mc(mci)) { @@ -365,6 +768,14 @@ static int __devinit i7core_probe(struct pci_dev *pdev, __func__); } + /* Default error mask is any memory */ + pvt->inject.channel = -1; + pvt->inject.dimm = -1; + pvt->inject.rank = -1; + pvt->inject.bank = -1; + pvt->inject.page = -1; + pvt->inject.col = -1; + return 0; fail1: -- cgit v1.2.3 From 0b2b7b7ec06ce615acd11374bf9a512e166dabb0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 22 Jun 2009 22:48:29 -0300 Subject: i7core_edac: Add more status functions to EDAC driver This patch were co-authored with Aristeu Rozanski. Signed-off-by: Aristeu Sergio Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 114 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 95 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index b590f8468693..da40730bf9c9 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -62,6 +62,15 @@ /* OFFSETS for Devices 4,5 and 6 Function 0 */ +#define MC_CHANNEL_DIMM_INIT_PARAMS 0x58 + #define THREE_DIMMS_PRESENT (1 << 24) + #define SINGLE_QUAD_RANK_PRESENT (1 << 23) + #define QUAD_RANK_PRESENT (1 << 22) + #define REGISTERED_DIMM (1 << 15) + +#define MC_CHANNEL_RANK_PRESENT 0x7c + #define RANK_PRESENT_MASK 0xffff + #define MC_CHANNEL_ADDR_MATCH 0xf0 #define MC_CHANNEL_ERROR_MASK 0xf8 #define MC_CHANNEL_ERROR_INJECT 0xfc @@ -74,6 +83,46 @@ #define NO_MASK_CACHELINE 0x00 #define REPEAT_EN 0x01 + /* OFFSETS for Devices 4,5 and 6 Function 1 */ +#define MC_DOD_CH_DIMM0 0x48 +#define MC_DOD_CH_DIMM1 0x4c +#define MC_DOD_CH_DIMM2 0x50 + #define RANKOFFSET_MASK ((1 << 12) | (1 << 11) | (1 << 10)) + #define RANKOFFSET(x) ((x & RANKOFFSET_MASK) >> 10) + #define DIMM_PRESENT_MASK (1 << 9) + #define DIMM_PRESENT(x) (((x) & DIMM_PRESENT_MASK) >> 9) + #define NUMBANK_MASK ((1 << 8) | (1 << 7)) + #define NUMBANK(x) (((x) & NUMBANK_MASK) >> 7) + #define NUMRANK_MASK ((1 << 6) | (1 << 5)) + #define NUMRANK(x) (((x) & NUMRANK_MASK) >> 5) + #define NUMROW_MASK ((1 << 4) | (1 << 3)) + #define NUMROW(x) (((x) & NUMROW_MASK) >> 3) + #define NUMCOL_MASK 3 + #define NUMCOL(x) ((x) & NUMCOL_MASK) + +#define MC_SAG_CH_0 0x80 +#define MC_SAG_CH_1 0x84 +#define MC_SAG_CH_2 0x88 +#define MC_SAG_CH_3 0x8c +#define MC_SAG_CH_4 0x90 +#define MC_SAG_CH_5 0x94 +#define MC_SAG_CH_6 0x98 +#define MC_SAG_CH_7 0x9c + +#define MC_RIR_LIMIT_CH_0 0x40 +#define MC_RIR_LIMIT_CH_1 0x44 +#define MC_RIR_LIMIT_CH_2 0x48 +#define MC_RIR_LIMIT_CH_3 0x4C +#define MC_RIR_LIMIT_CH_4 0x50 +#define MC_RIR_LIMIT_CH_5 0x54 +#define MC_RIR_LIMIT_CH_6 0x58 +#define MC_RIR_LIMIT_CH_7 0x5C +#define MC_RIR_LIMIT_MASK ((1 << 10) - 1) + +#define MC_RIR_WAY_CH 0x80 + #define MC_RIR_WAY_OFFSET_MASK (((1 << 14) - 1) & ~0x7) + #define MC_RIR_WAY_RANK_MASK 0x7 + /* * i7core structs */ @@ -99,11 +148,17 @@ struct i7core_inject { int channel, dimm, rank, bank, page, col; }; +struct i7core_channel { + u32 ranks; + u32 dimms; +}; + struct i7core_pvt { struct pci_dev *pci_mcr; /* Dev 3:0 */ struct pci_dev *pci_ch[NUM_CHANS][NUM_FUNCS]; struct i7core_info info; struct i7core_inject inject; + struct i7core_channel channel[NUM_CHANS]; }; /* Device name and register DID (Device ID) */ @@ -133,16 +188,12 @@ static struct edac_pci_ctl_info *i7core_pci; ****************************************************************************/ /* MC_CONTROL bits */ -#define CH2_ACTIVE(pvt) ((pvt)->info.mc_control & 1 << 10) -#define CH1_ACTIVE(pvt) ((pvt)->info.mc_control & 1 << 9) -#define CH0_ACTIVE(pvt) ((pvt)->info.mc_control & 1 << 8) +#define CH_ACTIVE(pvt, ch) ((pvt)->info.mc_control & 1 << (8 + ch)) #define ECCx8(pvt) ((pvt)->info.mc_control & 1 << 1) /* MC_STATUS bits */ #define ECC_ENABLED(pvt) ((pvt)->info.mc_status & 1 << 3) -#define CH2_DISABLED(pvt) ((pvt)->info.mc_status & 1 << 2) -#define CH1_DISABLED(pvt) ((pvt)->info.mc_status & 1 << 1) -#define CH0_DISABLED(pvt) ((pvt)->info.mc_status & 1 << 0) +#define CH_DISABLED(pvt, ch) ((pvt)->info.mc_status & 1 << ch) /* MC_MAX_DOD read functions */ static inline int maxnumdimms(struct i7core_pvt *pvt) @@ -189,19 +240,12 @@ static inline int maxnumcol(struct i7core_pvt *pvt) static int get_dimm_config(struct mem_ctl_info *mci) { struct i7core_pvt *pvt = mci->pvt_info; + int i; pci_read_config_dword(pvt->pci_mcr, MC_CONTROL, &pvt->info.mc_control); pci_read_config_dword(pvt->pci_mcr, MC_STATUS, &pvt->info.mc_status); pci_read_config_dword(pvt->pci_mcr, MC_MAX_DOD, &pvt->info.max_dod); - debugf0("Channels active [%c][%c][%c] - enabled [%c][%c][%c]\n", - CH0_ACTIVE(pvt)?'0':'-', - CH1_ACTIVE(pvt)?'1':'-', - CH2_ACTIVE(pvt)?'2':'-', - CH0_DISABLED(pvt)?'-':'0', - CH1_DISABLED(pvt)?'-':'1', - CH2_DISABLED(pvt)?'-':'2'); - if (ECC_ENABLED(pvt)) debugf0("ECC enabled with x%d SDCC\n", ECCx8(pvt)?8:4); else @@ -213,6 +257,38 @@ static int get_dimm_config(struct mem_ctl_info *mci) debugf0("DOD Maximum rows x colums = 0x%x x 0x%x\n", maxnumrow(pvt), maxnumcol(pvt)); + debugf0("Memory channel configuration:\n"); + + for (i = 0; i < NUM_CHANS; i++) { + u32 data; + + if (!CH_ACTIVE(pvt, i)) { + debugf0("Channel %i is not active\n", i); + continue; + } + if (CH_DISABLED(pvt, i)) { + debugf0("Channel %i is disabled\n", i); + continue; + } + + pci_read_config_dword(pvt->pci_ch[i][0], + MC_CHANNEL_DIMM_INIT_PARAMS, &data); + + pvt->channel[i].ranks = (data & QUAD_RANK_PRESENT)? 4 : 2; + + if (data & THREE_DIMMS_PRESENT) + pvt->channel[i].dimms = 3; + else if (data & SINGLE_QUAD_RANK_PRESENT) + pvt->channel[i].dimms = 1; + else + pvt->channel[i].dimms = 2; + + debugf0("Channel %d (0x%08x): %d ranks, %d dimms " + "(%sregistered)\n", i, data, + pvt->channel[i].ranks, pvt->channel[i].dimms, + (data & REGISTERED_DIMM)? "" : "un" ); + } + return 0; } @@ -489,7 +565,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, if (pvt->inject.dimm < 0) mask |= 1l << 41; else { - if (maxnumdimms(pvt) > 2) + if (pvt->channel[pvt->inject.channel].dimms > 2) mask |= (pvt->inject.dimm & 0x3l) << 35; else mask |= (pvt->inject.dimm & 0x1l) << 36; @@ -499,7 +575,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, if (pvt->inject.rank < 0) mask |= 1l << 40; else { - if (maxnumdimms(pvt) > 2) + if (pvt->channel[pvt->inject.channel].dimms > 2) mask |= (pvt->inject.rank & 0x1l) << 34; else mask |= (pvt->inject.rank & 0x3l) << 34; @@ -646,9 +722,6 @@ static int i7core_get_devices(struct mem_ctl_info *mci, int dev_idx) } pvt->pci_mcr=pdev; - /* Get dimm basic config */ - get_dimm_config(mci); - /* Retrieve all needed functions at MTR channel controllers */ for (i = 0; i < NUM_CHANS; i++) { pdev = NULL; @@ -672,6 +745,9 @@ static int i7core_get_devices(struct mem_ctl_info *mci, int dev_idx) } i7core_printk(KERN_INFO, "Driver loaded.\n"); + /* Get dimm basic config */ + get_dimm_config(mci); + return 0; } -- cgit v1.2.3 From 8f331907578623f90a134261a559fa3249142caa Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 22 Jun 2009 22:48:29 -0300 Subject: i7core_edac: Registers all supported MC functions Now, it will try to register on all supported Memory Controller functions. It should be noticed that dev3, function 2 is present only on chips with Registered DIMM's, according to the datasheet. So, the driver doesn't return -ENODEV is all functions but this one were successfully registered and enabled: EDAC i7core: Registered device 8086:2c18 fn=3 0 EDAC i7core: Registered device 8086:2c19 fn=3 1 EDAC i7core: Device not found: PCI ID 8086:2c1a (dev 3, func 2) EDAC i7core: Registered device 8086:2c1c fn=3 4 EDAC i7core: Registered device 8086:2c20 fn=4 0 EDAC i7core: Registered device 8086:2c21 fn=4 1 EDAC i7core: Registered device 8086:2c22 fn=4 2 EDAC i7core: Registered device 8086:2c23 fn=4 3 EDAC i7core: Registered device 8086:2c28 fn=5 0 EDAC i7core: Registered device 8086:2c29 fn=5 1 EDAC i7core: Registered device 8086:2c2a fn=5 2 EDAC i7core: Registered device 8086:2c2b fn=5 3 EDAC i7core: Registered device 8086:2c30 fn=6 0 EDAC i7core: Registered device 8086:2c31 fn=6 1 EDAC i7core: Registered device 8086:2c32 fn=6 2 EDAC i7core: Registered device 8086:2c33 fn=6 3 EDAC i7core: Driver loaded. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 217 +++++++++++++++++++++++++++------------------ 1 file changed, 131 insertions(+), 86 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index da40730bf9c9..79aa84eaa12d 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -128,7 +128,8 @@ */ #define NUM_CHANS 3 -#define NUM_FUNCS 1 +#define NUM_MCR_FUNCS 4 +#define NUM_CHAN_FUNCS 3 struct i7core_info { u32 mc_control; @@ -153,9 +154,16 @@ struct i7core_channel { u32 dimms; }; +struct pci_id_descr { + int dev; + int func; + int dev_id; + struct pci_dev *pdev; +}; + struct i7core_pvt { - struct pci_dev *pci_mcr; /* Dev 3:0 */ - struct pci_dev *pci_ch[NUM_CHANS][NUM_FUNCS]; + struct pci_dev *pci_mcr[NUM_MCR_FUNCS]; + struct pci_dev *pci_ch[NUM_CHANS][NUM_CHAN_FUNCS]; struct i7core_info info; struct i7core_inject inject; struct i7core_channel channel[NUM_CHANS]; @@ -167,11 +175,47 @@ struct i7core_dev_info { u16 fsb_mapping_errors; /* DID for the branchmap,control */ }; -static int chan_pci_ids[NUM_CHANS] = { - PCI_DEVICE_ID_INTEL_I7_MC_CH0_CTRL, /* Dev 4 */ - PCI_DEVICE_ID_INTEL_I7_MC_CH1_CTRL, /* Dev 5 */ - PCI_DEVICE_ID_INTEL_I7_MC_CH2_CTRL, /* Dev 6 */ +#define PCI_DESCR(device, function, device_id) \ + .dev = (device), \ + .func = (function), \ + .dev_id = (device_id) + +struct pci_id_descr pci_devs[] = { + /* Memory controller */ + { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_I7_MCR) }, + { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_I7_MC_TAD) }, + { PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_I7_MC_RAS) }, /* if RDIMM is supported */ + { PCI_DESCR(3, 4, PCI_DEVICE_ID_INTEL_I7_MC_TEST) }, + + /* Channel 0 */ + { PCI_DESCR(4, 0, PCI_DEVICE_ID_INTEL_I7_MC_CH0_CTRL) }, + { PCI_DESCR(4, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH0_ADDR) }, + { PCI_DESCR(4, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH0_RANK) }, + { PCI_DESCR(4, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH0_TC) }, + + /* Channel 1 */ + { PCI_DESCR(5, 0, PCI_DEVICE_ID_INTEL_I7_MC_CH1_CTRL) }, + { PCI_DESCR(5, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH1_ADDR) }, + { PCI_DESCR(5, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH1_RANK) }, + { PCI_DESCR(5, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH1_TC) }, + + /* Channel 2 */ + { PCI_DESCR(6, 0, PCI_DEVICE_ID_INTEL_I7_MC_CH2_CTRL) }, + { PCI_DESCR(6, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH2_ADDR) }, + { PCI_DESCR(6, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH2_RANK) }, + { PCI_DESCR(6, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH2_TC) }, }; +#define N_DEVS ARRAY_SIZE(pci_devs) + +/* + * pci_device_id table for which devices we are looking for + * This should match the first device at pci_devs table + */ +static const struct pci_device_id i7core_pci_tbl[] __devinitdata = { + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_MCR)}, + {0,} /* 0 terminated list. */ +}; + /* Table of devices attributes supported by this driver */ static const struct i7core_dev_info i7core_devs[] = { @@ -242,9 +286,12 @@ static int get_dimm_config(struct mem_ctl_info *mci) struct i7core_pvt *pvt = mci->pvt_info; int i; - pci_read_config_dword(pvt->pci_mcr, MC_CONTROL, &pvt->info.mc_control); - pci_read_config_dword(pvt->pci_mcr, MC_STATUS, &pvt->info.mc_status); - pci_read_config_dword(pvt->pci_mcr, MC_MAX_DOD, &pvt->info.max_dod); + if (!pvt->pci_mcr[0]) + return -ENODEV; + + pci_read_config_dword(pvt->pci_mcr[0], MC_CONTROL, &pvt->info.mc_control); + pci_read_config_dword(pvt->pci_mcr[0], MC_STATUS, &pvt->info.mc_status); + pci_read_config_dword(pvt->pci_mcr[0], MC_MAX_DOD, &pvt->info.max_dod); if (ECC_ENABLED(pvt)) debugf0("ECC enabled with x%d SDCC\n", ECCx8(pvt)?8:4); @@ -303,14 +350,19 @@ static int get_dimm_config(struct mem_ctl_info *mci) we're disabling error injection on all write calls to the sysfs nodes that controls the error code injection. */ -static void disable_inject(struct mem_ctl_info *mci) +static int disable_inject(struct mem_ctl_info *mci) { struct i7core_pvt *pvt = mci->pvt_info; pvt->inject.enable = 0; + if (!pvt->pci_ch[pvt->inject.channel][0]) + return -ENODEV; + pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], MC_CHANNEL_ERROR_MASK, 0); + + return 0; } /* @@ -550,6 +602,9 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, int rc; long enable; + if (!pvt->pci_ch[pvt->inject.channel][0]) + return 0; + rc = strict_strtoul(data, 10, &enable); if ((rc < 0)) return 0; @@ -684,17 +739,12 @@ static struct mcidev_sysfs_attribute i7core_inj_attrs[] = { * i7core_put_devices 'put' all the devices that we have * reserved via 'get' */ -static void i7core_put_devices(struct mem_ctl_info *mci) +static void i7core_put_devices(void) { - struct i7core_pvt *pvt = mci->pvt_info; - int i, n; - - pci_dev_put(pvt->pci_mcr); + int i; - /* Release all PCI device functions at MTR channel controllers */ - for (i = 0; i < NUM_CHANS; i++) - for (n = 0; n < NUM_FUNCS; n++) - pci_dev_put(pvt->pci_ch[i][n]); + for (i = 0; i < N_DEVS; i++) + pci_dev_put(pci_devs[i].pdev); } /* @@ -703,50 +753,67 @@ static void i7core_put_devices(struct mem_ctl_info *mci) * * Need to 'get' device 16 func 1 and func 2 */ -static int i7core_get_devices(struct mem_ctl_info *mci, int dev_idx) +static int i7core_get_devices(struct mem_ctl_info *mci, struct pci_dev *mcidev) { - struct i7core_pvt *pvt; - struct pci_dev *pdev; - int i, n, func; + struct i7core_pvt *pvt = mci->pvt_info; + int rc, i,func; + struct pci_dev *pdev = NULL; pvt = mci->pvt_info; memset(pvt, 0, sizeof(*pvt)); - pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_MCR, - NULL); - if (!pdev) { - i7core_printk(KERN_ERR, - "Couldn't get PCI ID %04x:%04x function 0\n", - PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_MCR); - return -ENODEV; - } - pvt->pci_mcr=pdev; + for (i = 0; i < N_DEVS; i++) { + pdev = pci_get_device(PCI_VENDOR_ID_INTEL, + pci_devs[i].dev_id, NULL); + if (!pdev) { + /* End of list, leave */ + i7core_printk(KERN_ERR, + "Device not found: PCI ID %04x:%04x " + "(dev %d, func %d)\n", + PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, + pci_devs[i].dev,pci_devs[i].func); + if ((pci_devs[i].dev == 3) && (pci_devs[i].func == 2)) + continue; /* Only on chips with RDIMMs */ + else + i7core_put_devices(); + } + pci_devs[i].pdev = pdev; + + rc = pci_enable_device(pdev); + if (rc < 0) { + i7core_printk(KERN_ERR, + "Couldn't enable PCI ID %04x:%04x " + "(dev %d, func %d)\n", + PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, + pci_devs[i].dev, pci_devs[i].func); + i7core_put_devices(); + return rc; + } + /* Sanity check */ + if (PCI_FUNC(pdev->devfn) != pci_devs[i].func) { + i7core_printk(KERN_ERR, + "Device PCI ID %04x:%04x " + "has function %d instead of %d\n", + PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, + PCI_FUNC(pdev->devfn), pci_devs[i].func); + i7core_put_devices(); + return -EINVAL; + } - /* Retrieve all needed functions at MTR channel controllers */ - for (i = 0; i < NUM_CHANS; i++) { - pdev = NULL; - for (n = 0; n < NUM_FUNCS; n++) { - pdev = pci_get_device(PCI_VENDOR_ID_INTEL, - chan_pci_ids[i], pdev); - if (!pdev) { - /* End of list, leave */ - i7core_printk(KERN_ERR, - "Device not found: PCI ID %04x:%04x " - "found only %d functions " - "(broken BIOS?)\n", - PCI_VENDOR_ID_INTEL, - chan_pci_ids[i], n); - i7core_put_devices(mci); - return -ENODEV; - } - func = PCI_FUNC(pdev->devfn); - pvt->pci_ch[i][func] = pdev; + i7core_printk(KERN_INFO, + "Registered device %0x:%0x fn=%0x %0x\n", + PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); + + func = PCI_FUNC(pdev->devfn); + if (pci_devs[i].dev < 4) { + pvt->pci_mcr[func] = pdev; + } else { + pvt->pci_ch[pci_devs[i].dev - 4][func] = pdev; } } - i7core_printk(KERN_INFO, "Driver loaded.\n"); - /* Get dimm basic config */ - get_dimm_config(mci); + i7core_printk(KERN_INFO, "Driver loaded.\n"); return 0; } @@ -763,7 +830,6 @@ static int __devinit i7core_probe(struct pci_dev *pdev, { struct mem_ctl_info *mci; struct i7core_pvt *pvt; - int rc; int num_channels; int num_csrows; int num_dimms_per_channel; @@ -772,20 +838,6 @@ static int __devinit i7core_probe(struct pci_dev *pdev, if (dev_idx >= ARRAY_SIZE(i7core_devs)) return -EINVAL; - /* wake up device */ - rc = pci_enable_device(pdev); - if (rc == -EIO) - return rc; - - debugf0("MC: " __FILE__ ": %s(), pdev bus %u dev=0x%x fn=0x%x\n", - __func__, - pdev->bus->number, - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); - - /* We only are looking for func 0 of the set */ - if (PCI_FUNC(pdev->devfn) != 0) - return -ENODEV; - num_channels = NUM_CHANS; /* FIXME: FAKE data, since we currently don't now how to get this */ @@ -808,10 +860,6 @@ static int __devinit i7core_probe(struct pci_dev *pdev, // pvt->maxch = num_channels; // pvt->maxdimmperch = num_dimms_per_channel; - /* 'get' the pci devices we want to reserve for our use */ - if (i7core_get_devices(mci, dev_idx)) - goto fail0; - mci->mc_idx = 0; mci->mtype_cap = MEM_FLAG_FB_DDR2; /* FIXME: it uses DDR3 */ mci->edac_ctl_cap = EDAC_FLAG_NONE; @@ -823,6 +871,10 @@ static int __devinit i7core_probe(struct pci_dev *pdev, mci->ctl_page_to_phys = NULL; mci->mc_driver_sysfs_attributes = i7core_inj_attrs; + /* 'get' the pci devices we want to reserve for our use */ + if (i7core_get_devices(mci, pdev)) + goto fail0; + /* add this new MC control structure to EDAC's list of MCs */ if (edac_mc_add_mc(mci)) { debugf0("MC: " __FILE__ @@ -852,10 +904,13 @@ static int __devinit i7core_probe(struct pci_dev *pdev, pvt->inject.page = -1; pvt->inject.col = -1; + /* Get dimm basic config */ + get_dimm_config(mci); + return 0; fail1: - i7core_put_devices(mci); + i7core_put_devices(); fail0: edac_mc_free(mci); @@ -880,21 +935,11 @@ static void __devexit i7core_remove(struct pci_dev *pdev) return; /* retrieve references to resources, and free those resources */ - i7core_put_devices(mci); + i7core_put_devices(); edac_mc_free(mci); } -/* - * pci_device_id table for which devices we are looking for - * - * The "E500P" device is the first device supported. - */ -static const struct pci_device_id i7core_pci_tbl[] __devinitdata = { - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_MCR)}, - {0,} /* 0 terminated list. */ -}; - MODULE_DEVICE_TABLE(pci, i7core_pci_tbl); /* -- cgit v1.2.3 From f122a89222510e8f57e8e0b9b5cdd3ec8863fe4c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 22 Jun 2009 22:48:29 -0300 Subject: i7core_edac: Show read/write virtual/physical channel association Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 79aa84eaa12d..09a0998e1c3f 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -68,6 +68,10 @@ #define QUAD_RANK_PRESENT (1 << 22) #define REGISTERED_DIMM (1 << 15) +#define MC_CHANNEL_MAPPER 0x60 + #define RDLCH(r, ch) ((((r) >> (3 + (ch * 6))) & 0x07) - 1) + #define WRLCH(r, ch) ((((r) >> (ch * 6)) & 0x07) - 1) + #define MC_CHANNEL_RANK_PRESENT 0x7c #define RANK_PRESENT_MASK 0xffff @@ -100,6 +104,8 @@ #define NUMCOL_MASK 3 #define NUMCOL(x) ((x) & NUMCOL_MASK) +#define MC_RANK_PRESENT 0x7c + #define MC_SAG_CH_0 0x80 #define MC_SAG_CH_1 0x84 #define MC_SAG_CH_2 0x88 @@ -135,6 +141,7 @@ struct i7core_info { u32 mc_control; u32 mc_status; u32 max_dod; + u32 ch_map; }; @@ -289,9 +296,19 @@ static int get_dimm_config(struct mem_ctl_info *mci) if (!pvt->pci_mcr[0]) return -ENODEV; - pci_read_config_dword(pvt->pci_mcr[0], MC_CONTROL, &pvt->info.mc_control); - pci_read_config_dword(pvt->pci_mcr[0], MC_STATUS, &pvt->info.mc_status); - pci_read_config_dword(pvt->pci_mcr[0], MC_MAX_DOD, &pvt->info.max_dod); + /* Device 3 function 0 reads */ + pci_read_config_dword(pvt->pci_mcr[0], MC_CONTROL, + &pvt->info.mc_control); + pci_read_config_dword(pvt->pci_mcr[0], MC_STATUS, + &pvt->info.mc_status); + pci_read_config_dword(pvt->pci_mcr[0], MC_MAX_DOD, + &pvt->info.max_dod); + pci_read_config_dword(pvt->pci_mcr[0], MC_CHANNEL_MAPPER, + &pvt->info.ch_map); + + debugf0("MC control=0x%08x status=0x%08x dod=0x%08x map=0x%08x\n", + pvt->info.mc_control, pvt->info.mc_status, + pvt->info.max_dod, pvt->info.ch_map); if (ECC_ENABLED(pvt)) debugf0("ECC enabled with x%d SDCC\n", ECCx8(pvt)?8:4); @@ -318,6 +335,7 @@ static int get_dimm_config(struct mem_ctl_info *mci) continue; } + /* Devices 4-6 function 0 */ pci_read_config_dword(pvt->pci_ch[i][0], MC_CHANNEL_DIMM_INIT_PARAMS, &data); @@ -330,10 +348,13 @@ static int get_dimm_config(struct mem_ctl_info *mci) else pvt->channel[i].dimms = 2; - debugf0("Channel %d (0x%08x): %d ranks, %d dimms " - "(%sregistered)\n", i, data, + debugf0("Ch%d (0x%08x): rd ch %d, wr ch %d, " + "%d ranks, %d %cDIMMs\n", + i, data, + RDLCH(pvt->info.ch_map, i), + WRLCH(pvt->info.ch_map, i), pvt->channel[i].ranks, pvt->channel[i].dimms, - (data & REGISTERED_DIMM)? "" : "un" ); + (data & REGISTERED_DIMM)? 'R' : 'U' ); } return 0; -- cgit v1.2.3 From 7b029d03c36e5b06e067884aaefcee2c1c62efc7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 22 Jun 2009 22:48:29 -0300 Subject: i7core_edac: A few fixes at error injection code Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 70 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 09a0998e1c3f..0c17db673065 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -30,6 +30,8 @@ #include "edac_core.h" +/* To use the new pci_[read/write]_config_qword instead of two dword */ +#define USE_QWORD 1 /* * Alter this version for the module when modifications are made @@ -639,44 +641,71 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, /* Sets pvt->inject.dimm mask */ if (pvt->inject.dimm < 0) - mask |= 1l << 41; + mask |= 1L << 41; else { if (pvt->channel[pvt->inject.channel].dimms > 2) - mask |= (pvt->inject.dimm & 0x3l) << 35; + mask |= (pvt->inject.dimm & 0x3L) << 35; else - mask |= (pvt->inject.dimm & 0x1l) << 36; + mask |= (pvt->inject.dimm & 0x1L) << 36; } /* Sets pvt->inject.rank mask */ if (pvt->inject.rank < 0) - mask |= 1l << 40; + mask |= 1L << 40; else { if (pvt->channel[pvt->inject.channel].dimms > 2) - mask |= (pvt->inject.rank & 0x1l) << 34; + mask |= (pvt->inject.rank & 0x1L) << 34; else - mask |= (pvt->inject.rank & 0x3l) << 34; + mask |= (pvt->inject.rank & 0x3L) << 34; } /* Sets pvt->inject.bank mask */ if (pvt->inject.bank < 0) - mask |= 1l << 39; + mask |= 1L << 39; else - mask |= (pvt->inject.bank & 0x15l) << 30; + mask |= (pvt->inject.bank & 0x15L) << 30; /* Sets pvt->inject.page mask */ if (pvt->inject.page < 0) - mask |= 1l << 38; + mask |= 1L << 38; else - mask |= (pvt->inject.page & 0xffffl) << 14; + mask |= (pvt->inject.page & 0xffffL) << 14; /* Sets pvt->inject.column mask */ if (pvt->inject.col < 0) - mask |= 1l << 37; + mask |= 1L << 37; else - mask |= (pvt->inject.col & 0x3fffl); + mask |= (pvt->inject.col & 0x3fffL); +#if USE_QWORD pci_write_config_qword(pvt->pci_ch[pvt->inject.channel][0], MC_CHANNEL_ADDR_MATCH, mask); +#else + pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], + MC_CHANNEL_ADDR_MATCH, mask); + pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], + MC_CHANNEL_ADDR_MATCH + 4, mask >> 32L); +#endif + +#if 1 +#if USE_QWORD + u64 rdmask; + pci_read_config_qword(pvt->pci_ch[pvt->inject.channel][0], + MC_CHANNEL_ADDR_MATCH, &rdmask); + debugf0("Inject addr match write 0x%016llx, read: 0x%016llx\n", + mask, rdmask); +#else + u32 rdmask1, rdmask2; + + pci_read_config_dword(pvt->pci_ch[pvt->inject.channel][0], + MC_CHANNEL_ADDR_MATCH, &rdmask1); + pci_read_config_dword(pvt->pci_ch[pvt->inject.channel][0], + MC_CHANNEL_ADDR_MATCH + 4, &rdmask2); + + debugf0("Inject addr match write 0x%016llx, read: 0x%08x%08x\n", + mask, rdmask1, rdmask2); +#endif +#endif pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], MC_CHANNEL_ERROR_MASK, pvt->inject.eccmask); @@ -688,17 +717,18 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, * bit 4: INJECT_ADDR_PARITY */ - injectmask = (pvt->inject.type & 1) && - (pvt->inject.section & 0x3) << 1 && + injectmask = (pvt->inject.type & 1) | + (pvt->inject.section & 0x3) << 1 | (pvt->inject.type & 0x6) << (3 - 1); pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], MC_CHANNEL_ERROR_MASK, injectmask); - debugf0("Error inject addr match 0x%016llx, ecc 0x%08x, inject 0x%08x\n", mask, pvt->inject.eccmask, injectmask); + + return count; } @@ -706,6 +736,16 @@ static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci, char *data) { struct i7core_pvt *pvt = mci->pvt_info; + u32 injectmask; + + pci_read_config_dword(pvt->pci_ch[pvt->inject.channel][0], + MC_CHANNEL_ERROR_MASK, &injectmask); + + debugf0("Inject error read: 0x%018x\n", injectmask); + + if (injectmask & 0x0c) + pvt->inject.enable = 1; + return sprintf(data, "%d\n", pvt->inject.enable); } -- cgit v1.2.3 From 87d1d272ba25a1863e40ebb1df4bc0eed7a8fd11 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 22 Jun 2009 22:48:29 -0300 Subject: i7core_edac: need mci->edac_check, otherwise module removal doesn't work There are some locking troubles with edac_core: if you don't declare an edac_check, module may suffer from soft lock. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 0c17db673065..190596af601a 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -879,6 +879,15 @@ static int i7core_get_devices(struct mem_ctl_info *mci, struct pci_dev *mcidev) return 0; } +/* + * i7core_check_error Retrieve and process errors reported by the + * hardware. Called by the Core module. + */ +static void i7core_check_error(struct mem_ctl_info *mci) +{ + /* FIXME: need a real code here */ +} + /* * i7core_probe Probe for ONE instance of device to see if it is * present. @@ -912,8 +921,11 @@ static int __devinit i7core_probe(struct pci_dev *pdev, debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); + /* 'get' the pci devices we want to reserve for our use */ + if (i7core_get_devices(mci, pdev)) + goto fail0; + mci->dev = &pdev->dev; /* record ptr to the generic device */ - dev_set_drvdata(mci->dev, mci); pvt = mci->pvt_info; @@ -932,9 +944,8 @@ static int __devinit i7core_probe(struct pci_dev *pdev, mci->ctl_page_to_phys = NULL; mci->mc_driver_sysfs_attributes = i7core_inj_attrs; - /* 'get' the pci devices we want to reserve for our use */ - if (i7core_get_devices(mci, pdev)) - goto fail0; + /* Set the function pointer to an actual operation function */ + mci->edac_check = i7core_check_error; /* add this new MC control structure to EDAC's list of MCs */ if (edac_mc_add_mc(mci)) { @@ -992,6 +1003,7 @@ static void __devexit i7core_remove(struct pci_dev *pdev) edac_pci_release_generic_ctl(i7core_pci); mci = edac_mc_del_mc(&pdev->dev); + if (!mci) return; -- cgit v1.2.3 From 442305b152778f07504e9fdf64815d4841279bbe Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 22 Jun 2009 22:48:29 -0300 Subject: i7core_edac: Add a memory check routine, based on device 3 function 4 This function appears only on Xeon 5500 datasheet. Yet, testing with a Xeon 3503 showed that this is also implemented on other Nehalem processors. At the first read, MC_TEST_ERR_RCV1 and MC_TEST_ERR_RCV0 can contain any value. Modify CE error logic to update the error count only after the second read. An alternative approach would be to do a write at rcv0 and rcv1 registers, but it seemed better to keep they untouched, since BIOS might eventually assume that they are exclusive for their usage. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 115 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 108 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 190596af601a..b5dbc2b83961 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -62,6 +62,18 @@ #define MC_STATUS 0x4c #define MC_MAX_DOD 0x64 +/* + * OFFSETS for Device 3 Function 4, as inicated on Xeon 5500 datasheet: + * http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf + */ + +#define MC_TEST_ERR_RCV1 0x60 + #define DIMM2_COR_ERR(r) ((r) & 0x7fff) + +#define MC_TEST_ERR_RCV0 0x64 + #define DIMM1_COR_ERR(r) (((r) >> 16) & 0x7fff) + #define DIMM0_COR_ERR(r) ((r) & 0x7fff) + /* OFFSETS for Devices 4,5 and 6 Function 0 */ #define MC_CHANNEL_DIMM_INIT_PARAMS 0x58 @@ -136,8 +148,9 @@ */ #define NUM_CHANS 3 -#define NUM_MCR_FUNCS 4 -#define NUM_CHAN_FUNCS 3 +#define MAX_DIMMS 3 /* Max DIMMS per channel */ +#define MAX_MCR_FUNC 4 +#define MAX_CHAN_FUNC 3 struct i7core_info { u32 mc_control; @@ -159,8 +172,8 @@ struct i7core_inject { }; struct i7core_channel { - u32 ranks; - u32 dimms; + u32 ranks; + u32 dimms; }; struct pci_id_descr { @@ -171,11 +184,16 @@ struct pci_id_descr { }; struct i7core_pvt { - struct pci_dev *pci_mcr[NUM_MCR_FUNCS]; - struct pci_dev *pci_ch[NUM_CHANS][NUM_CHAN_FUNCS]; + struct pci_dev *pci_mcr[MAX_MCR_FUNC + 1]; + struct pci_dev *pci_ch[NUM_CHANS][MAX_CHAN_FUNC + 1]; struct i7core_info info; struct i7core_inject inject; struct i7core_channel channel[NUM_CHANS]; + + int ce_count_available; + unsigned long ce_count[MAX_DIMMS]; /* ECC corrected errors counts per dimm */ + int last_ce_count[MAX_DIMMS]; + }; /* Device name and register DID (Device ID) */ @@ -749,6 +767,19 @@ static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci, return sprintf(data, "%d\n", pvt->inject.enable); } +static ssize_t i7core_ce_regs_show(struct mem_ctl_info *mci, char *data) +{ + struct i7core_pvt *pvt = mci->pvt_info; + + if (!pvt->ce_count_available) + return sprintf(data, "unavailable\n"); + + return sprintf(data, "dimm0: %lu\ndimm1: %lu\ndimm2: %lu\n", + pvt->ce_count[0], + pvt->ce_count[1], + pvt->ce_count[2]); +} + /* * Sysfs struct */ @@ -789,6 +820,13 @@ static struct mcidev_sysfs_attribute i7core_inj_attrs[] = { }, .show = i7core_inject_enable_show, .store = i7core_inject_enable_store, + }, { + .attr = { + .name = "corrected_error_counts", + .mode = (S_IRUGO | S_IWUSR) + }, + .show = i7core_ce_regs_show, + .store = NULL, }, }; @@ -879,13 +917,76 @@ static int i7core_get_devices(struct mem_ctl_info *mci, struct pci_dev *mcidev) return 0; } +/**************************************************************************** + Error check routines + ****************************************************************************/ + +/* This function is based on the device 3 function 4 registers as described on: + * Intel Xeon Processor 5500 Series Datasheet Volume 2 + * http://www.intel.com/Assets/PDF/datasheet/321322.pdf + * also available at: + * http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf + */ +static void check_mc_test_err(struct mem_ctl_info *mci) +{ + struct i7core_pvt *pvt = mci->pvt_info; + u32 rcv1, rcv0; + int new0, new1, new2; + + if (!pvt->pci_mcr[4]) { + debugf0("%s MCR registers not found\n",__func__); + return; + } + + /* Corrected error reads */ + pci_read_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV1, &rcv1); + pci_read_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV0, &rcv0); + + /* Store the new values */ + new2 = DIMM2_COR_ERR(rcv1); + new1 = DIMM1_COR_ERR(rcv0); + new0 = DIMM0_COR_ERR(rcv0); + + debugf2("%s CE rcv1=0x%08x rcv0=0x%08x, %d %d %d\n", + (pvt->ce_count_available ? "UPDATE" : "READ"), + rcv1, rcv0, new0, new1, new2); + + /* Updates CE counters if it is not the first time here */ + if (pvt->ce_count_available) { + /* Updates CE counters */ + int add0, add1, add2; + + add2 = new2 - pvt->last_ce_count[2]; + add1 = new1 - pvt->last_ce_count[1]; + add0 = new0 - pvt->last_ce_count[0]; + + if (add2 < 0) + add2 += 0x7fff; + pvt->ce_count[2] += add2; + + if (add1 < 0) + add1 += 0x7fff; + pvt->ce_count[1] += add1; + + if (add0 < 0) + add0 += 0x7fff; + pvt->ce_count[0] += add0; + } else + pvt->ce_count_available = 1; + + /* Store the new values */ + pvt->last_ce_count[2] = new2; + pvt->last_ce_count[1] = new1; + pvt->last_ce_count[0] = new0; +} + /* * i7core_check_error Retrieve and process errors reported by the * hardware. Called by the Core module. */ static void i7core_check_error(struct mem_ctl_info *mci) { - /* FIXME: need a real code here */ + check_mc_test_err(mci); } /* -- cgit v1.2.3 From ef708b53b98f2b53d9686a9f8f0b8d437952c295 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 22 Jun 2009 22:48:30 -0300 Subject: i7core_edac: Add additional tests for error detection Properly check the number of channels and improve probing error detection Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 199 +++++++++++++++++++++++++++++++-------------- 1 file changed, 139 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index b5dbc2b83961..bfa462f6fa0e 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -189,6 +189,7 @@ struct i7core_pvt { struct i7core_info info; struct i7core_inject inject; struct i7core_channel channel[NUM_CHANS]; + int channels; /* Number of active channels */ int ce_count_available; unsigned long ce_count[MAX_DIMMS]; /* ECC corrected errors counts per dimm */ @@ -259,12 +260,12 @@ static struct edac_pci_ctl_info *i7core_pci; ****************************************************************************/ /* MC_CONTROL bits */ -#define CH_ACTIVE(pvt, ch) ((pvt)->info.mc_control & 1 << (8 + ch)) -#define ECCx8(pvt) ((pvt)->info.mc_control & 1 << 1) +#define CH_ACTIVE(pvt, ch) ((pvt)->info.mc_control & (1 << (8 + ch))) +#define ECCx8(pvt) ((pvt)->info.mc_control & (1 << 1)) /* MC_STATUS bits */ -#define ECC_ENABLED(pvt) ((pvt)->info.mc_status & 1 << 3) -#define CH_DISABLED(pvt, ch) ((pvt)->info.mc_status & 1 << ch) +#define ECC_ENABLED(pvt) ((pvt)->info.mc_status & (1 << 3)) +#define CH_DISABLED(pvt, ch) ((pvt)->info.mc_status & (1 << ch)) /* MC_MAX_DOD read functions */ static inline int maxnumdimms(struct i7core_pvt *pvt) @@ -308,6 +309,48 @@ static inline int maxnumcol(struct i7core_pvt *pvt) /**************************************************************************** Memory check routines ****************************************************************************/ +static int i7core_get_active_channels(int *channels) +{ + struct pci_dev *pdev = NULL; + int i; + u32 status, control; + + *channels = 0; + + for (i = 0; i < N_DEVS; i++) { + if (!pci_devs[i].pdev) + continue; + + if (PCI_SLOT(pci_devs[i].pdev->devfn) == 3 && + PCI_FUNC(pci_devs[i].pdev->devfn) == 0) { + pdev = pci_devs[i].pdev; + break; + } + } + + if (!pdev) + return -ENODEV; + + /* Device 3 function 0 reads */ + pci_read_config_dword(pdev, MC_STATUS, &status); + pci_read_config_dword(pdev, MC_CONTROL, &control); + + for (i = 0; i < NUM_CHANS; i++) { + /* Check if the channel is active */ + if (!(control & (1 << (8 + i)))) + continue; + + /* Check if the channel is disabled */ + if (status & (1 << i)) { + continue; + } + + (*channels)++; + } + + return 0; +} + static int get_dimm_config(struct mem_ctl_info *mci) { struct i7core_pvt *pvt = mci->pvt_info; @@ -852,69 +895,103 @@ static void i7core_put_devices(void) * * Need to 'get' device 16 func 1 and func 2 */ -static int i7core_get_devices(struct mem_ctl_info *mci, struct pci_dev *mcidev) +static int i7core_get_devices(void) { - struct i7core_pvt *pvt = mci->pvt_info; - int rc, i,func; + int rc, i; struct pci_dev *pdev = NULL; - pvt = mci->pvt_info; - memset(pvt, 0, sizeof(*pvt)); - for (i = 0; i < N_DEVS; i++) { pdev = pci_get_device(PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, NULL); - if (!pdev) { - /* End of list, leave */ + if (likely(pdev)) + pci_devs[i].pdev = pdev; + else { i7core_printk(KERN_ERR, "Device not found: PCI ID %04x:%04x " "(dev %d, func %d)\n", PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, pci_devs[i].dev,pci_devs[i].func); + + /* Dev 3 function 2 only exists on chips with RDIMMs */ if ((pci_devs[i].dev == 3) && (pci_devs[i].func == 2)) - continue; /* Only on chips with RDIMMs */ - else - i7core_put_devices(); + continue; + + /* End of list, leave */ + rc = -ENODEV; + goto error; } - pci_devs[i].pdev = pdev; - rc = pci_enable_device(pdev); - if (rc < 0) { + /* Sanity check */ + if (unlikely(PCI_SLOT(pdev->devfn) != pci_devs[i].dev || + PCI_FUNC(pdev->devfn) != pci_devs[i].func)) { i7core_printk(KERN_ERR, - "Couldn't enable PCI ID %04x:%04x " - "(dev %d, func %d)\n", + "Device PCI ID %04x:%04x " + "has fn %d.%d instead of fn %d.%d\n", PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), pci_devs[i].dev, pci_devs[i].func); - i7core_put_devices(); - return rc; + rc = -EINVAL; + goto error; } - /* Sanity check */ - if (PCI_FUNC(pdev->devfn) != pci_devs[i].func) { + + /* Be sure that the device is enabled */ + rc = pci_enable_device(pdev); + if (unlikely(rc < 0)) { i7core_printk(KERN_ERR, - "Device PCI ID %04x:%04x " - "has function %d instead of %d\n", + "Couldn't enable PCI ID %04x:%04x " + "fn %d.%d\n", PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, - PCI_FUNC(pdev->devfn), pci_devs[i].func); - i7core_put_devices(); - return -EINVAL; + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); + goto error; } i7core_printk(KERN_INFO, - "Registered device %0x:%0x fn=%0x %0x\n", + "Registered device %0x:%0x fn %d.%d\n", PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); + } + + return 0; + +error: + i7core_put_devices(); + return -EINVAL; +} + +static int mci_bind_devs(struct mem_ctl_info *mci) +{ + struct i7core_pvt *pvt = mci->pvt_info; + struct pci_dev *pdev; + int i, func, slot; + + for (i = 0; i < N_DEVS; i++) { + pdev = pci_devs[i].pdev; + if (!pdev) + continue; func = PCI_FUNC(pdev->devfn); - if (pci_devs[i].dev < 4) { + slot = PCI_SLOT(pdev->devfn); + if (slot == 3) { + if (unlikely(func > MAX_MCR_FUNC)) + goto error; pvt->pci_mcr[func] = pdev; - } else { - pvt->pci_ch[pci_devs[i].dev - 4][func] = pdev; - } + } else if (likely(slot >= 4 && slot < 4 + NUM_CHANS)) { + if (unlikely(func > MAX_CHAN_FUNC)) + goto error; + pvt->pci_ch[slot - 4][func] = pdev; + } else + goto error; + + debugf0("Associated fn %d.%d, dev = %p\n", + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), pdev); } - - i7core_printk(KERN_INFO, "Driver loaded.\n"); - return 0; + +error: + i7core_printk(KERN_ERR, "Device %d, function %d " + "is out of the expected range\n", + slot, func); + return -EINVAL; } /**************************************************************************** @@ -1001,41 +1078,38 @@ static int __devinit i7core_probe(struct pci_dev *pdev, { struct mem_ctl_info *mci; struct i7core_pvt *pvt; - int num_channels; + int num_channels = 0; int num_csrows; - int num_dimms_per_channel; int dev_idx = id->driver_data; - if (dev_idx >= ARRAY_SIZE(i7core_devs)) + if (unlikely(dev_idx >= ARRAY_SIZE(i7core_devs))) return -EINVAL; - num_channels = NUM_CHANS; + /* get the pci devices we want to reserve for our use */ + if (unlikely(i7core_get_devices() < 0)) + return -ENODEV; + + /* Check the number of active and not disabled channels */ + if (unlikely (i7core_get_active_channels(&num_channels)) < 0) + goto fail0; - /* FIXME: FAKE data, since we currently don't now how to get this */ - num_dimms_per_channel = 4; - num_csrows = num_dimms_per_channel; + /* FIXME: we currently don't know the number of csrows */ + num_csrows = num_channels; /* allocate a new MC control structure */ mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); - if (mci == NULL) + if (unlikely (!mci)) return -ENOMEM; debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); - /* 'get' the pci devices we want to reserve for our use */ - if (i7core_get_devices(mci, pdev)) - goto fail0; - mci->dev = &pdev->dev; /* record ptr to the generic device */ pvt = mci->pvt_info; - -// pvt->system_address = pdev; /* Record this device in our private */ -// pvt->maxch = num_channels; -// pvt->maxdimmperch = num_dimms_per_channel; + memset(pvt, 0, sizeof(*pvt)); mci->mc_idx = 0; - mci->mtype_cap = MEM_FLAG_FB_DDR2; /* FIXME: it uses DDR3 */ + mci->mtype_cap = MEM_FLAG_DDR3; /* FIXME: how to handle RDDR3? */ mci->edac_ctl_cap = EDAC_FLAG_NONE; mci->edac_cap = EDAC_FLAG_NONE; mci->mod_name = "i7core_edac.c"; @@ -1044,12 +1118,18 @@ static int __devinit i7core_probe(struct pci_dev *pdev, mci->dev_name = pci_name(pdev); mci->ctl_page_to_phys = NULL; mci->mc_driver_sysfs_attributes = i7core_inj_attrs; - /* Set the function pointer to an actual operation function */ mci->edac_check = i7core_check_error; + /* Store pci devices at mci for faster access */ + if (unlikely (mci_bind_devs(mci)) < 0) + goto fail1; + + /* Get dimm basic config */ + get_dimm_config(mci); + /* add this new MC control structure to EDAC's list of MCs */ - if (edac_mc_add_mc(mci)) { + if (unlikely(edac_mc_add_mc(mci)) < 0) { debugf0("MC: " __FILE__ ": %s(): failed edac_mc_add_mc()\n", __func__); /* FIXME: perhaps some code should go here that disables error @@ -1060,7 +1140,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, /* allocating generic PCI control info */ i7core_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); - if (!i7core_pci) { + if (unlikely (!i7core_pci)) { printk(KERN_WARNING "%s(): Unable to create PCI control\n", __func__); @@ -1070,15 +1150,14 @@ static int __devinit i7core_probe(struct pci_dev *pdev, } /* Default error mask is any memory */ - pvt->inject.channel = -1; + pvt->inject.channel = 0; pvt->inject.dimm = -1; pvt->inject.rank = -1; pvt->inject.bank = -1; pvt->inject.page = -1; pvt->inject.col = -1; - /* Get dimm basic config */ - get_dimm_config(mci); + i7core_printk(KERN_INFO, "Driver loaded.\n"); return 0; -- cgit v1.2.3 From 1c6fed808f1ccd0804786e87f6b2c907dcd730fa Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 22 Jun 2009 22:48:30 -0300 Subject: i7core_edac: Properly fill struct csrow_info Thanks-to: Aristeu Rozanski for part of the code Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 48 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index bfa462f6fa0e..556a150e645b 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -348,13 +348,17 @@ static int i7core_get_active_channels(int *channels) (*channels)++; } + debugf0("Number of active channels: %d\n", *channels); + return 0; } static int get_dimm_config(struct mem_ctl_info *mci) { struct i7core_pvt *pvt = mci->pvt_info; - int i; + struct csrow_info *csr; + int i, csrow = 0; + enum edac_type mode; if (!pvt->pci_mcr[0]) return -ENODEV; @@ -365,7 +369,7 @@ static int get_dimm_config(struct mem_ctl_info *mci) pci_read_config_dword(pvt->pci_mcr[0], MC_STATUS, &pvt->info.mc_status); pci_read_config_dword(pvt->pci_mcr[0], MC_MAX_DOD, - &pvt->info.max_dod); + &pvt->info.max_dod); pci_read_config_dword(pvt->pci_mcr[0], MC_CHANNEL_MAPPER, &pvt->info.ch_map); @@ -373,10 +377,16 @@ static int get_dimm_config(struct mem_ctl_info *mci) pvt->info.mc_control, pvt->info.mc_status, pvt->info.max_dod, pvt->info.ch_map); - if (ECC_ENABLED(pvt)) + if (ECC_ENABLED(pvt)) { debugf0("ECC enabled with x%d SDCC\n", ECCx8(pvt)?8:4); - else + if (ECCx8(pvt)) + mode = EDAC_S8ECD8ED; + else + mode = EDAC_S4ECD4ED; + } else { debugf0("ECC disabled\n"); + mode = EDAC_NONE; + } /* FIXME: need to handle the error codes */ debugf0("DOD Maximum limits: DIMMS: %d, %d-ranked, %d-banked\n", @@ -411,13 +421,31 @@ static int get_dimm_config(struct mem_ctl_info *mci) else pvt->channel[i].dimms = 2; - debugf0("Ch%d (0x%08x): rd ch %d, wr ch %d, " - "%d ranks, %d %cDIMMs\n", - i, data, - RDLCH(pvt->info.ch_map, i), - WRLCH(pvt->info.ch_map, i), + debugf0("Ch%d phy rd%d, wr%d (0x%08x): " + "%d ranks, %d %cDIMMs, offset = %d\n", + i, + RDLCH(pvt->info.ch_map, i), WRLCH(pvt->info.ch_map, i), + data, pvt->channel[i].ranks, pvt->channel[i].dimms, - (data & REGISTERED_DIMM)? 'R' : 'U' ); + (data & REGISTERED_DIMM)? 'R' : 'U', + RANKOFFSET(data)); + + csr = &mci->csrows[csrow]; + csr->first_page = 0; + csr->last_page = 0; + csr->page_mask = 0; + csr->nr_pages = 0; + csr->grain = 0; + csr->csrow_idx = csrow; + csr->dtype = DEV_X8; /* FIXME: check this */ + + if (data & REGISTERED_DIMM) + csr->mtype = MEM_RDDR3; + else + csr->mtype = MEM_DDR3; + csr->edac_mode = mode; + + csrow++; } return 0; -- cgit v1.2.3 From b7c761512c5412eb30be567a0640060cccfc372f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 22 Jun 2009 22:48:30 -0300 Subject: i7core_edac: Improve error handling Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 556a150e645b..62ae472c4e27 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -328,8 +328,10 @@ static int i7core_get_active_channels(int *channels) } } - if (!pdev) + if (!pdev) { + i7core_printk(KERN_ERR, "Couldn't find fn 3.0!!!\n"); return -ENODEV; + } /* Device 3 function 0 reads */ pci_read_config_dword(pdev, MC_STATUS, &status); @@ -1109,16 +1111,19 @@ static int __devinit i7core_probe(struct pci_dev *pdev, int num_channels = 0; int num_csrows; int dev_idx = id->driver_data; + int rc; if (unlikely(dev_idx >= ARRAY_SIZE(i7core_devs))) return -EINVAL; /* get the pci devices we want to reserve for our use */ - if (unlikely(i7core_get_devices() < 0)) - return -ENODEV; + rc = i7core_get_devices(); + if (unlikely(rc < 0)) + return rc; /* Check the number of active and not disabled channels */ - if (unlikely (i7core_get_active_channels(&num_channels)) < 0) + rc = i7core_get_active_channels(&num_channels); + if (unlikely (rc < 0)) goto fail0; /* FIXME: we currently don't know the number of csrows */ @@ -1126,8 +1131,10 @@ static int __devinit i7core_probe(struct pci_dev *pdev, /* allocate a new MC control structure */ mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); - if (unlikely (!mci)) - return -ENOMEM; + if (unlikely (!mci)) { + rc = -ENOMEM; + goto fail0; + } debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); @@ -1150,19 +1157,22 @@ static int __devinit i7core_probe(struct pci_dev *pdev, mci->edac_check = i7core_check_error; /* Store pci devices at mci for faster access */ - if (unlikely (mci_bind_devs(mci)) < 0) + rc = mci_bind_devs(mci); + if (unlikely (rc < 0)) goto fail1; /* Get dimm basic config */ get_dimm_config(mci); /* add this new MC control structure to EDAC's list of MCs */ - if (unlikely(edac_mc_add_mc(mci)) < 0) { + if (unlikely(edac_mc_add_mc(mci))) { debugf0("MC: " __FILE__ ": %s(): failed edac_mc_add_mc()\n", __func__); /* FIXME: perhaps some code should go here that disables error * reporting if we just enabled it */ + + rc = -EINVAL; goto fail1; } @@ -1190,11 +1200,11 @@ static int __devinit i7core_probe(struct pci_dev *pdev, return 0; fail1: - i7core_put_devices(); + edac_mc_free(mci); fail0: - edac_mc_free(mci); - return -ENODEV; + i7core_put_devices(); + return rc; } /* -- cgit v1.2.3 From 7dd6953c5fecc44d264710e1fa158d0038215b63 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 22 Jun 2009 22:48:30 -0300 Subject: i7core_edac: Add more information about each active dimm Thanks-to: Aristeu Rozanski for part of the code Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 62ae472c4e27..a6e798349e93 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -359,21 +359,18 @@ static int get_dimm_config(struct mem_ctl_info *mci) { struct i7core_pvt *pvt = mci->pvt_info; struct csrow_info *csr; - int i, csrow = 0; + struct pci_dev *pdev = pvt->pci_mcr[0]; + int i, j, csrow = 0; enum edac_type mode; - if (!pvt->pci_mcr[0]) + if (!pdev) return -ENODEV; /* Device 3 function 0 reads */ - pci_read_config_dword(pvt->pci_mcr[0], MC_CONTROL, - &pvt->info.mc_control); - pci_read_config_dword(pvt->pci_mcr[0], MC_STATUS, - &pvt->info.mc_status); - pci_read_config_dword(pvt->pci_mcr[0], MC_MAX_DOD, - &pvt->info.max_dod); - pci_read_config_dword(pvt->pci_mcr[0], MC_CHANNEL_MAPPER, - &pvt->info.ch_map); + pci_read_config_dword(pdev, MC_CONTROL, &pvt->info.mc_control); + pci_read_config_dword(pdev, MC_STATUS, &pvt->info.mc_status); + pci_read_config_dword(pdev, MC_MAX_DOD, &pvt->info.max_dod); + pci_read_config_dword(pdev, MC_CHANNEL_MAPPER, &pvt->info.ch_map); debugf0("MC control=0x%08x status=0x%08x dod=0x%08x map=0x%08x\n", pvt->info.mc_control, pvt->info.mc_status, @@ -399,7 +396,7 @@ static int get_dimm_config(struct mem_ctl_info *mci) debugf0("Memory channel configuration:\n"); for (i = 0; i < NUM_CHANS; i++) { - u32 data; + u32 data, value[8]; if (!CH_ACTIVE(pvt, i)) { debugf0("Channel %i is not active\n", i); @@ -424,13 +421,33 @@ static int get_dimm_config(struct mem_ctl_info *mci) pvt->channel[i].dimms = 2; debugf0("Ch%d phy rd%d, wr%d (0x%08x): " - "%d ranks, %d %cDIMMs, offset = %d\n", + "%d ranks, %d %cDIMMs, offset = %d\n\t" + "present: %i, numbank: %#x, numrank: %#x, " + "numrow: %#x, numcol: %#x\n", i, RDLCH(pvt->info.ch_map, i), WRLCH(pvt->info.ch_map, i), data, pvt->channel[i].ranks, pvt->channel[i].dimms, (data & REGISTERED_DIMM)? 'R' : 'U', - RANKOFFSET(data)); + RANKOFFSET(data), + DIMM_PRESENT(data), + NUMBANK(data), NUMRANK(data), + NUMROW(data), NUMCOL(data)); + + pci_read_config_dword(pdev, MC_SAG_CH_0, &value[0]); + pci_read_config_dword(pdev, MC_SAG_CH_1, &value[1]); + pci_read_config_dword(pdev, MC_SAG_CH_2, &value[2]); + pci_read_config_dword(pdev, MC_SAG_CH_3, &value[3]); + pci_read_config_dword(pdev, MC_SAG_CH_4, &value[4]); + pci_read_config_dword(pdev, MC_SAG_CH_5, &value[5]); + pci_read_config_dword(pdev, MC_SAG_CH_6, &value[6]); + pci_read_config_dword(pdev, MC_SAG_CH_7, &value[7]); + printk("\t[%i] DIVBY3\tREMOVED\tOFFSET\n", i); + for (j = 0; j < 8; j++) + printk("\t\t%#x\t%#x\t%#x\n", + (value[j] >> 27) & 0x1, + (value[j] >> 24) & 0x7, + (value[j] && ((1 << 24) - 1))); csr = &mci->csrows[csrow]; csr->first_page = 0; -- cgit v1.2.3 From 854d3349973a7c47bd989794037f526b74af20c4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 22 Jun 2009 22:48:30 -0300 Subject: i7core_edac: Get more info about the memory DIMMs Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 170 ++++++++++++++++++++++++++++----------------- 1 file changed, 107 insertions(+), 63 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index a6e798349e93..483cca2e543b 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -109,14 +109,14 @@ #define RANKOFFSET(x) ((x & RANKOFFSET_MASK) >> 10) #define DIMM_PRESENT_MASK (1 << 9) #define DIMM_PRESENT(x) (((x) & DIMM_PRESENT_MASK) >> 9) - #define NUMBANK_MASK ((1 << 8) | (1 << 7)) - #define NUMBANK(x) (((x) & NUMBANK_MASK) >> 7) - #define NUMRANK_MASK ((1 << 6) | (1 << 5)) - #define NUMRANK(x) (((x) & NUMRANK_MASK) >> 5) - #define NUMROW_MASK ((1 << 4) | (1 << 3)) - #define NUMROW(x) (((x) & NUMROW_MASK) >> 3) - #define NUMCOL_MASK 3 - #define NUMCOL(x) ((x) & NUMCOL_MASK) + #define MC_DOD_NUMBANK_MASK ((1 << 8) | (1 << 7)) + #define MC_DOD_NUMBANK(x) (((x) & MC_DOD_NUMBANK_MASK) >> 7) + #define MC_DOD_NUMRANK_MASK ((1 << 6) | (1 << 5)) + #define MC_DOD_NUMRANK(x) (((x) & MC_DOD_NUMRANK_MASK) >> 5) + #define MC_DOD_NUMROW_MASK ((1 << 4) | (1 << 3)) + #define MC_DOD_NUMROW(x) (((x) & MC_DOD_NUMROW_MASK) >> 3) + #define MC_DOD_NUMCOL_MASK 3 + #define MC_DOD_NUMCOL(x) ((x) & MC_DOD_NUMCOL_MASK) #define MC_RANK_PRESENT 0x7c @@ -268,41 +268,41 @@ static struct edac_pci_ctl_info *i7core_pci; #define CH_DISABLED(pvt, ch) ((pvt)->info.mc_status & (1 << ch)) /* MC_MAX_DOD read functions */ -static inline int maxnumdimms(struct i7core_pvt *pvt) +static inline int numdimms(u32 dimms) { - return (pvt->info.max_dod & 0x3) + 1; + return (dimms & 0x3) + 1; } -static inline int maxnumrank(struct i7core_pvt *pvt) +static inline int numrank(u32 rank) { static int ranks[4] = { 1, 2, 4, -EINVAL }; - return ranks[(pvt->info.max_dod >> 2) & 0x3]; + return ranks[rank & 0x3]; } -static inline int maxnumbank(struct i7core_pvt *pvt) +static inline int numbank(u32 bank) { static int banks[4] = { 4, 8, 16, -EINVAL }; - return banks[(pvt->info.max_dod >> 4) & 0x3]; + return banks[bank & 0x3]; } -static inline int maxnumrow(struct i7core_pvt *pvt) +static inline int numrow(u32 row) { static int rows[8] = { 1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16, -EINVAL, -EINVAL, -EINVAL, }; - return rows[((pvt->info.max_dod >> 6) & 0x7)]; + return rows[row & 0x7]; } -static inline int maxnumcol(struct i7core_pvt *pvt) +static inline int numcol(u32 col) { static int cols[8] = { 1 << 10, 1 << 11, 1 << 12, -EINVAL, }; - return cols[((pvt->info.max_dod >> 9) & 0x3) << 12]; + return cols[col & 0x3]; } @@ -359,10 +359,13 @@ static int get_dimm_config(struct mem_ctl_info *mci) { struct i7core_pvt *pvt = mci->pvt_info; struct csrow_info *csr; - struct pci_dev *pdev = pvt->pci_mcr[0]; + struct pci_dev *pdev; int i, j, csrow = 0; enum edac_type mode; + enum mem_type mtype; + /* Get data from the MC register, function 0 */ + pdev = pvt->pci_mcr[0]; if (!pdev) return -ENODEV; @@ -388,15 +391,18 @@ static int get_dimm_config(struct mem_ctl_info *mci) } /* FIXME: need to handle the error codes */ - debugf0("DOD Maximum limits: DIMMS: %d, %d-ranked, %d-banked\n", - maxnumdimms(pvt), maxnumrank(pvt), maxnumbank(pvt)); - debugf0("DOD Maximum rows x colums = 0x%x x 0x%x\n", - maxnumrow(pvt), maxnumcol(pvt)); + debugf0("DOD Max limits: DIMMS: %d, %d-ranked, %d-banked\n", + numdimms(pvt->info.max_dod), + numrank(pvt->info.max_dod >> 2), + numbank(pvt->info.max_dod >> 4)); + debugf0("DOD Max rows x colums = 0x%x x 0x%x\n", + numrow(pvt->info.max_dod >> 6), + numcol(pvt->info.max_dod >> 9)); debugf0("Memory channel configuration:\n"); for (i = 0; i < NUM_CHANS; i++) { - u32 data, value[8]; + u32 data, dimm_dod[3], value[8]; if (!CH_ACTIVE(pvt, i)) { debugf0("Channel %i is not active\n", i); @@ -413,58 +419,96 @@ static int get_dimm_config(struct mem_ctl_info *mci) pvt->channel[i].ranks = (data & QUAD_RANK_PRESENT)? 4 : 2; + if (data & REGISTERED_DIMM) + mtype = MEM_RDDR3; + else + mtype = MEM_DDR3; +#if 0 if (data & THREE_DIMMS_PRESENT) pvt->channel[i].dimms = 3; else if (data & SINGLE_QUAD_RANK_PRESENT) pvt->channel[i].dimms = 1; else pvt->channel[i].dimms = 2; +#endif + + /* Devices 4-6 function 1 */ + pci_read_config_dword(pvt->pci_ch[i][1], + MC_DOD_CH_DIMM0, &dimm_dod[0]); + pci_read_config_dword(pvt->pci_ch[i][1], + MC_DOD_CH_DIMM1, &dimm_dod[1]); + pci_read_config_dword(pvt->pci_ch[i][1], + MC_DOD_CH_DIMM2, &dimm_dod[2]); debugf0("Ch%d phy rd%d, wr%d (0x%08x): " - "%d ranks, %d %cDIMMs, offset = %d\n\t" - "present: %i, numbank: %#x, numrank: %#x, " - "numrow: %#x, numcol: %#x\n", + "%d ranks, %cDIMMs\n", i, RDLCH(pvt->info.ch_map, i), WRLCH(pvt->info.ch_map, i), data, - pvt->channel[i].ranks, pvt->channel[i].dimms, - (data & REGISTERED_DIMM)? 'R' : 'U', - RANKOFFSET(data), - DIMM_PRESENT(data), - NUMBANK(data), NUMRANK(data), - NUMROW(data), NUMCOL(data)); - - pci_read_config_dword(pdev, MC_SAG_CH_0, &value[0]); - pci_read_config_dword(pdev, MC_SAG_CH_1, &value[1]); - pci_read_config_dword(pdev, MC_SAG_CH_2, &value[2]); - pci_read_config_dword(pdev, MC_SAG_CH_3, &value[3]); - pci_read_config_dword(pdev, MC_SAG_CH_4, &value[4]); - pci_read_config_dword(pdev, MC_SAG_CH_5, &value[5]); - pci_read_config_dword(pdev, MC_SAG_CH_6, &value[6]); - pci_read_config_dword(pdev, MC_SAG_CH_7, &value[7]); - printk("\t[%i] DIVBY3\tREMOVED\tOFFSET\n", i); - for (j = 0; j < 8; j++) - printk("\t\t%#x\t%#x\t%#x\n", - (value[j] >> 27) & 0x1, - (value[j] >> 24) & 0x7, - (value[j] && ((1 << 24) - 1))); - - csr = &mci->csrows[csrow]; - csr->first_page = 0; - csr->last_page = 0; - csr->page_mask = 0; - csr->nr_pages = 0; - csr->grain = 0; - csr->csrow_idx = csrow; - csr->dtype = DEV_X8; /* FIXME: check this */ + pvt->channel[i].ranks, + (data & REGISTERED_DIMM)? 'R' : 'U'); - if (data & REGISTERED_DIMM) - csr->mtype = MEM_RDDR3; - else - csr->mtype = MEM_DDR3; - csr->edac_mode = mode; + for (j = 0; j < 3; j++) { + u32 banks, ranks, rows, cols; + + if (!DIMM_PRESENT(dimm_dod[j])) + continue; + + banks = numbank(MC_DOD_NUMBANK(dimm_dod[j])); + ranks = numrank(MC_DOD_NUMRANK(dimm_dod[j])); + rows = numrow(MC_DOD_NUMROW(dimm_dod[j])); + cols = numcol(MC_DOD_NUMCOL(dimm_dod[j])); + + pvt->channel[i].dimms++; + + debugf0("\tdimm %d offset: %x, numbank: %#x, " + "numrank: %#x, numrow: %#x, numcol: %#x\n", + j, + RANKOFFSET(dimm_dod[j]), + banks, ranks, rows, cols); + + csr = &mci->csrows[csrow]; + csr->first_page = 0; + csr->last_page = 0; + csr->page_mask = 0; + csr->nr_pages = 0; + csr->grain = 0; + csr->csrow_idx = csrow; + + switch (banks) { + case 4: + csr->dtype = DEV_X4; + break; + case 8: + csr->dtype = DEV_X8; + break; + case 16: + csr->dtype = DEV_X16; + break; + default: + csr->dtype = DEV_UNKNOWN; + } + + csr->edac_mode = mode; + csr->mtype = mtype; + + csrow++; + } - csrow++; + pci_read_config_dword(pdev, MC_SAG_CH_0, &value[0]); + pci_read_config_dword(pdev, MC_SAG_CH_1, &value[1]); + pci_read_config_dword(pdev, MC_SAG_CH_2, &value[2]); + pci_read_config_dword(pdev, MC_SAG_CH_3, &value[3]); + pci_read_config_dword(pdev, MC_SAG_CH_4, &value[4]); + pci_read_config_dword(pdev, MC_SAG_CH_5, &value[5]); + pci_read_config_dword(pdev, MC_SAG_CH_6, &value[6]); + pci_read_config_dword(pdev, MC_SAG_CH_7, &value[7]); + printk("\t[%i] DIVBY3\tREMOVED\tOFFSET\n", i); + for (j = 0; j < 8; j++) + printk("\t\t%#x\t%#x\t%#x\n", + (value[j] >> 27) & 0x1, + (value[j] >> 24) & 0x7, + (value[j] && ((1 << 24) - 1))); } return 0; -- cgit v1.2.3 From 5566cb7c91ba4ff4447278bb27896b4a2bb7d18a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 22 Jun 2009 22:48:31 -0300 Subject: i7core_edac: Memory info fixes and preparation for properly filling cswrow data Now, memory size is properly displayed: EDAC i7core: DOD Max limits: DIMMS: 2, 1-ranked, 8-banked EDAC i7core: DOD Max rows x colums = 0x4000 x 0x400 EDAC i7core: Memory channel configuration: EDAC i7core: Ch0 phy rd0, wr0 (0x063f7c31): 2 ranks, UDIMMs EDAC i7core: dimm 0 (0x00000288) 1024 Mb offset: 0, numbank: 8, numrank: 1, numrow: 0x4000, numcol: 0x400 EDAC i7core: dimm 1 (0x00001288) 1024 Mb offset: 4, numbank: 8, numrank: 1, numrow: 0x4000, numcol: 0x400 EDAC i7core: Ch1 phy rd1, wr1 (0x063f7c31): 2 ranks, UDIMMs EDAC i7core: dimm 0 (0x00000288) 1024 Mb offset: 0, numbank: 8, numrank: 1, numrow: 0x4000, numcol: 0x400 EDAC i7core: Ch2 phy rd3, wr3 (0x063f7c31): 2 ranks, UDIMMs EDAC i7core: dimm 0 (0x00000288) 1024 Mb offset: 0, numbank: 8, numrank: 1, numrow: 0x4000, numcol: 0x400 Still, as the way to retrieve csrows info is not known, it does a mapping of what's available to csrows basic unit at edac core. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 483cca2e543b..772219fa10be 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -113,8 +113,8 @@ #define MC_DOD_NUMBANK(x) (((x) & MC_DOD_NUMBANK_MASK) >> 7) #define MC_DOD_NUMRANK_MASK ((1 << 6) | (1 << 5)) #define MC_DOD_NUMRANK(x) (((x) & MC_DOD_NUMRANK_MASK) >> 5) - #define MC_DOD_NUMROW_MASK ((1 << 4) | (1 << 3)) - #define MC_DOD_NUMROW(x) (((x) & MC_DOD_NUMROW_MASK) >> 3) + #define MC_DOD_NUMROW_MASK ((1 << 4) | (1 << 3)| (1 << 2)) + #define MC_DOD_NUMROW(x) (((x) & MC_DOD_NUMROW_MASK) >> 2) #define MC_DOD_NUMCOL_MASK 3 #define MC_DOD_NUMCOL(x) ((x) & MC_DOD_NUMCOL_MASK) @@ -361,6 +361,7 @@ static int get_dimm_config(struct mem_ctl_info *mci) struct csrow_info *csr; struct pci_dev *pdev; int i, j, csrow = 0; + unsigned long last_page = 0; enum edac_type mode; enum mem_type mtype; @@ -380,7 +381,7 @@ static int get_dimm_config(struct mem_ctl_info *mci) pvt->info.max_dod, pvt->info.ch_map); if (ECC_ENABLED(pvt)) { - debugf0("ECC enabled with x%d SDCC\n", ECCx8(pvt)?8:4); + debugf0("ECC enabled with x%d SDCC\n", ECCx8(pvt) ?8:4); if (ECCx8(pvt)) mode = EDAC_S8ECD8ED; else @@ -450,6 +451,7 @@ static int get_dimm_config(struct mem_ctl_info *mci) for (j = 0; j < 3; j++) { u32 banks, ranks, rows, cols; + u32 size, npages; if (!DIMM_PRESENT(dimm_dod[j])) continue; @@ -459,19 +461,27 @@ static int get_dimm_config(struct mem_ctl_info *mci) rows = numrow(MC_DOD_NUMROW(dimm_dod[j])); cols = numcol(MC_DOD_NUMCOL(dimm_dod[j])); + /* DDR3 has 8 I/O banks */ + size = (rows * cols * banks * ranks) >> (20 - 3); + pvt->channel[i].dimms++; - debugf0("\tdimm %d offset: %x, numbank: %#x, " - "numrank: %#x, numrow: %#x, numcol: %#x\n", - j, + debugf0("\tdimm %d (0x%08x) %d Mb offset: %x, " + "numbank: %d,\n\t\t" + "numrank: %d, numrow: %#x, numcol: %#x\n", + j, dimm_dod[j], size, RANKOFFSET(dimm_dod[j]), banks, ranks, rows, cols); + npages = cols * rows; /* FIXME */ + csr = &mci->csrows[csrow]; - csr->first_page = 0; - csr->last_page = 0; + csr->first_page = last_page + 1; + last_page += npages; + csr->last_page = last_page; + csr->nr_pages = npages; + csr->page_mask = 0; - csr->nr_pages = 0; csr->grain = 0; csr->csrow_idx = csrow; -- cgit v1.2.3 From eb94fc402f1592dfe847b245d9109c11a99a2ea1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 22 Jun 2009 22:48:31 -0300 Subject: i7core_edac: fill csrows edac sysfs info csrows is still fake, since we can't identify its representation with Nehalem registers. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 66 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 50 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 772219fa10be..e0a3b217c52b 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -309,25 +309,33 @@ static inline int numcol(u32 col) /**************************************************************************** Memory check routines ****************************************************************************/ -static int i7core_get_active_channels(int *channels) +static struct pci_dev *get_pdev_slot_func(int slot, int func) { - struct pci_dev *pdev = NULL; int i; - u32 status, control; - - *channels = 0; for (i = 0; i < N_DEVS; i++) { if (!pci_devs[i].pdev) continue; - if (PCI_SLOT(pci_devs[i].pdev->devfn) == 3 && - PCI_FUNC(pci_devs[i].pdev->devfn) == 0) { - pdev = pci_devs[i].pdev; - break; + if (PCI_SLOT(pci_devs[i].pdev->devfn) == slot && + PCI_FUNC(pci_devs[i].pdev->devfn) == func) { + return pci_devs[i].pdev; } } + return NULL; +} + +static int i7core_get_active_channels(int *channels, int *csrows) +{ + struct pci_dev *pdev = NULL; + int i, j; + u32 status, control; + + *channels = 0; + *csrows = 0; + + pdev = get_pdev_slot_func(3, 0); if (!pdev) { i7core_printk(KERN_ERR, "Couldn't find fn 3.0!!!\n"); return -ENODEV; @@ -338,6 +346,7 @@ static int i7core_get_active_channels(int *channels) pci_read_config_dword(pdev, MC_CONTROL, &control); for (i = 0; i < NUM_CHANS; i++) { + u32 dimm_dod[3]; /* Check if the channel is active */ if (!(control & (1 << (8 + i)))) continue; @@ -347,7 +356,27 @@ static int i7core_get_active_channels(int *channels) continue; } + pdev = get_pdev_slot_func(i + 4, 1); + if (!pdev) { + i7core_printk(KERN_ERR, "Couldn't find fn %d.%d!!!\n", + i + 4, 1); + return -ENODEV; + } + /* Devices 4-6 function 1 */ + pci_read_config_dword(pdev, + MC_DOD_CH_DIMM0, &dimm_dod[0]); + pci_read_config_dword(pdev, + MC_DOD_CH_DIMM1, &dimm_dod[1]); + pci_read_config_dword(pdev, + MC_DOD_CH_DIMM2, &dimm_dod[2]); + (*channels)++; + + for (j = 0; j < 3; j++) { + if (!DIMM_PRESENT(dimm_dod[j])) + continue; + (*csrows)++; + } } debugf0("Number of active channels: %d\n", *channels); @@ -473,7 +502,11 @@ static int get_dimm_config(struct mem_ctl_info *mci) RANKOFFSET(dimm_dod[j]), banks, ranks, rows, cols); - npages = cols * rows; /* FIXME */ +#if PAGE_SHIFT > 20 + npages = size >> (PAGE_SHIFT - 20); +#else + npages = size << (20 - PAGE_SHIFT); +#endif csr = &mci->csrows[csrow]; csr->first_page = last_page + 1; @@ -482,8 +515,12 @@ static int get_dimm_config(struct mem_ctl_info *mci) csr->nr_pages = npages; csr->page_mask = 0; - csr->grain = 0; + csr->grain = 8; csr->csrow_idx = csrow; + csr->nr_channels = 1; + + csr->channels[0].chan_idx = i; + csr->channels[0].ce_count = 0; switch (banks) { case 4: @@ -1179,7 +1216,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, { struct mem_ctl_info *mci; struct i7core_pvt *pvt; - int num_channels = 0; + int num_channels; int num_csrows; int dev_idx = id->driver_data; int rc; @@ -1193,13 +1230,10 @@ static int __devinit i7core_probe(struct pci_dev *pdev, return rc; /* Check the number of active and not disabled channels */ - rc = i7core_get_active_channels(&num_channels); + rc = i7core_get_active_channels(&num_channels, &num_csrows); if (unlikely (rc < 0)) goto fail0; - /* FIXME: we currently don't know the number of csrows */ - num_csrows = num_channels; - /* allocate a new MC control structure */ mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); if (unlikely (!mci)) { -- cgit v1.2.3 From 41fcb7feed70d8076f1591664314ca172fcdff7b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 22 Jun 2009 22:48:31 -0300 Subject: i7core_edac: CodingStyle fixes Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 59 +++++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index e0a3b217c52b..914914759690 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -113,7 +113,7 @@ #define MC_DOD_NUMBANK(x) (((x) & MC_DOD_NUMBANK_MASK) >> 7) #define MC_DOD_NUMRANK_MASK ((1 << 6) | (1 << 5)) #define MC_DOD_NUMRANK(x) (((x) & MC_DOD_NUMRANK_MASK) >> 5) - #define MC_DOD_NUMROW_MASK ((1 << 4) | (1 << 3)| (1 << 2)) + #define MC_DOD_NUMROW_MASK ((1 << 4) | (1 << 3) | (1 << 2)) #define MC_DOD_NUMROW(x) (((x) & MC_DOD_NUMROW_MASK) >> 2) #define MC_DOD_NUMCOL_MASK 3 #define MC_DOD_NUMCOL(x) ((x) & MC_DOD_NUMCOL_MASK) @@ -352,9 +352,8 @@ static int i7core_get_active_channels(int *channels, int *csrows) continue; /* Check if the channel is disabled */ - if (status & (1 << i)) { + if (status & (1 << i)) continue; - } pdev = get_pdev_slot_func(i + 4, 1); if (!pdev) { @@ -410,7 +409,7 @@ static int get_dimm_config(struct mem_ctl_info *mci) pvt->info.max_dod, pvt->info.ch_map); if (ECC_ENABLED(pvt)) { - debugf0("ECC enabled with x%d SDCC\n", ECCx8(pvt) ?8:4); + debugf0("ECC enabled with x%d SDCC\n", ECCx8(pvt) ? 8 : 4); if (ECCx8(pvt)) mode = EDAC_S8ECD8ED; else @@ -447,7 +446,7 @@ static int get_dimm_config(struct mem_ctl_info *mci) pci_read_config_dword(pvt->pci_ch[i][0], MC_CHANNEL_DIMM_INIT_PARAMS, &data); - pvt->channel[i].ranks = (data & QUAD_RANK_PRESENT)? 4 : 2; + pvt->channel[i].ranks = (data & QUAD_RANK_PRESENT) ? 4 : 2; if (data & REGISTERED_DIMM) mtype = MEM_RDDR3; @@ -476,7 +475,7 @@ static int get_dimm_config(struct mem_ctl_info *mci) RDLCH(pvt->info.ch_map, i), WRLCH(pvt->info.ch_map, i), data, pvt->channel[i].ranks, - (data & REGISTERED_DIMM)? 'R' : 'U'); + (data & REGISTERED_DIMM) ? 'R' : 'U'); for (j = 0; j < 3; j++) { u32 banks, ranks, rows, cols; @@ -550,9 +549,9 @@ static int get_dimm_config(struct mem_ctl_info *mci) pci_read_config_dword(pdev, MC_SAG_CH_5, &value[5]); pci_read_config_dword(pdev, MC_SAG_CH_6, &value[6]); pci_read_config_dword(pdev, MC_SAG_CH_7, &value[7]); - printk("\t[%i] DIVBY3\tREMOVED\tOFFSET\n", i); + debugf0("\t[%i] DIVBY3\tREMOVED\tOFFSET\n", i); for (j = 0; j < 8; j++) - printk("\t\t%#x\t%#x\t%#x\n", + debugf0("\t\t%#x\t%#x\t%#x\n", (value[j] >> 27) & 0x1, (value[j] >> 24) & 0x7, (value[j] && ((1 << 24) - 1))); @@ -602,7 +601,7 @@ static ssize_t i7core_inject_section_store(struct mem_ctl_info *mci, int rc; if (pvt->inject.enable) - disable_inject(mci); + disable_inject(mci); rc = strict_strtoul(data, 10, &value); if ((rc < 0) || (value > 3)) @@ -635,7 +634,7 @@ static ssize_t i7core_inject_type_store(struct mem_ctl_info *mci, int rc; if (pvt->inject.enable) - disable_inject(mci); + disable_inject(mci); rc = strict_strtoul(data, 10, &value); if ((rc < 0) || (value > 7)) @@ -670,7 +669,7 @@ static ssize_t i7core_inject_eccmask_store(struct mem_ctl_info *mci, int rc; if (pvt->inject.enable) - disable_inject(mci); + disable_inject(mci); rc = strict_strtoul(data, 10, &value); if (rc < 0) @@ -706,7 +705,7 @@ static ssize_t i7core_inject_addrmatch_store(struct mem_ctl_info *mci, int rc; if (pvt->inject.enable) - disable_inject(mci); + disable_inject(mci); do { cmd = strsep((char **) &data, ":"); @@ -716,7 +715,7 @@ static ssize_t i7core_inject_addrmatch_store(struct mem_ctl_info *mci, if (!val) return cmd - data; - if (!strcasecmp(val,"any")) + if (!strcasecmp(val, "any")) value = -1; else { rc = strict_strtol(val, 10, &value); @@ -724,33 +723,33 @@ static ssize_t i7core_inject_addrmatch_store(struct mem_ctl_info *mci, return cmd - data; } - if (!strcasecmp(cmd,"channel")) { + if (!strcasecmp(cmd, "channel")) { if (value < 3) pvt->inject.channel = value; else return cmd - data; - } else if (!strcasecmp(cmd,"dimm")) { + } else if (!strcasecmp(cmd, "dimm")) { if (value < 4) pvt->inject.dimm = value; else return cmd - data; - } else if (!strcasecmp(cmd,"rank")) { + } else if (!strcasecmp(cmd, "rank")) { if (value < 4) pvt->inject.rank = value; else return cmd - data; - } else if (!strcasecmp(cmd,"bank")) { + } else if (!strcasecmp(cmd, "bank")) { if (value < 4) pvt->inject.bank = value; else return cmd - data; - } else if (!strcasecmp(cmd,"page")) { + } else if (!strcasecmp(cmd, "page")) { if (value <= 0xffff) pvt->inject.page = value; else return cmd - data; - } else if (!strcasecmp(cmd,"col") || - !strcasecmp(cmd,"column")) { + } else if (!strcasecmp(cmd, "col") || + !strcasecmp(cmd, "column")) { if (value <= 0x3fff) pvt->inject.col = value; else @@ -923,7 +922,8 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], MC_CHANNEL_ERROR_MASK, injectmask); - debugf0("Error inject addr match 0x%016llx, ecc 0x%08x, inject 0x%08x\n", + debugf0("Error inject addr match 0x%016llx, ecc 0x%08x," + " inject 0x%08x\n", mask, pvt->inject.eccmask, injectmask); @@ -1048,7 +1048,7 @@ static int i7core_get_devices(void) "Device not found: PCI ID %04x:%04x " "(dev %d, func %d)\n", PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, - pci_devs[i].dev,pci_devs[i].func); + pci_devs[i].dev, pci_devs[i].func); /* Dev 3 function 2 only exists on chips with RDIMMs */ if ((pci_devs[i].dev == 3) && (pci_devs[i].func == 2)) @@ -1231,12 +1231,12 @@ static int __devinit i7core_probe(struct pci_dev *pdev, /* Check the number of active and not disabled channels */ rc = i7core_get_active_channels(&num_channels, &num_csrows); - if (unlikely (rc < 0)) + if (unlikely(rc < 0)) goto fail0; /* allocate a new MC control structure */ mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); - if (unlikely (!mci)) { + if (unlikely(!mci)) { rc = -ENOMEM; goto fail0; } @@ -1249,7 +1249,12 @@ static int __devinit i7core_probe(struct pci_dev *pdev, memset(pvt, 0, sizeof(*pvt)); mci->mc_idx = 0; - mci->mtype_cap = MEM_FLAG_DDR3; /* FIXME: how to handle RDDR3? */ + /* + * FIXME: how to handle RDDR3 at MCI level? It is possible to have + * Mixed RDDR3/UDDR3 with Nehalem, provided that they are on different + * memory channels + */ + mci->mtype_cap = MEM_FLAG_DDR3; mci->edac_ctl_cap = EDAC_FLAG_NONE; mci->edac_cap = EDAC_FLAG_NONE; mci->mod_name = "i7core_edac.c"; @@ -1263,7 +1268,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, /* Store pci devices at mci for faster access */ rc = mci_bind_devs(mci); - if (unlikely (rc < 0)) + if (unlikely(rc < 0)) goto fail1; /* Get dimm basic config */ @@ -1283,7 +1288,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, /* allocating generic PCI control info */ i7core_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); - if (unlikely (!i7core_pci)) { + if (unlikely(!i7core_pci)) { printk(KERN_WARNING "%s(): Unable to create PCI control\n", __func__); -- cgit v1.2.3 From 696e409dbd1ce325129c5030267365619364dfa0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 23 Jul 2009 06:57:45 -0300 Subject: edac_mce: Add an interface driver to report mce errors via edac edac_mce module is an interface module that gets mcelog data and forwards to any registered edac module that expects to receive data via mce. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/Kconfig | 8 ++++++- drivers/edac/Makefile | 1 + drivers/edac/edac_mce.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 drivers/edac/edac_mce.c (limited to 'drivers') diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 391ddbfb2a34..5b7fbc5aec87 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -69,6 +69,9 @@ config EDAC_MM_EDAC occurred so that a particular failing memory module can be replaced. If unsure, select 'Y'. +config EDAC_MCE + tristate + config EDAC_AMD64 tristate "AMD64 (Opteron, Athlon64) K8, F10h, F11h" depends on EDAC_MM_EDAC && K8_NB && X86_64 && PCI && EDAC_DECODE_MCE @@ -169,9 +172,12 @@ config EDAC_I5400 config EDAC_I7CORE tristate "Intel i7 Core (Nehalem) processors" depends on EDAC_MM_EDAC && PCI && X86 + select EDAC_MCE help Support for error detection and correction the Intel - i7 Core (Nehalem) Integrated Memory Controller + i7 Core (Nehalem) Integrated Memory Controller that exists on + newer processors like i7 Core, i7 Core Extreme, Xeon 35xx + and Xeon 55xx processors. config EDAC_I82860 tristate "Intel 82860" diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index b9996195b233..ca6b1bb24ccc 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_EDAC) := edac_stub.o obj-$(CONFIG_EDAC_MM_EDAC) += edac_core.o +obj-$(CONFIG_EDAC_MCE) += edac_mce.o edac_core-objs := edac_mc.o edac_device.o edac_mc_sysfs.o edac_pci_sysfs.o edac_core-objs += edac_module.o edac_device_sysfs.o diff --git a/drivers/edac/edac_mce.c b/drivers/edac/edac_mce.c new file mode 100644 index 000000000000..b1efa8e51921 --- /dev/null +++ b/drivers/edac/edac_mce.c @@ -0,0 +1,58 @@ +/* Provides edac interface to mcelog events + * + * This file may be distributed under the terms of the + * GNU General Public License version 2. + * + * Copyright (c) 2009 by: + * Mauro Carvalho Chehab + * + * Red Hat Inc. http://www.redhat.com + */ + +#include +#include +#include + +int edac_mce_enabled; +EXPORT_SYMBOL_GPL(edac_mce_enabled); + + +/* + * Extension interface + */ + +static LIST_HEAD(edac_mce_list); +static DEFINE_MUTEX(edac_mce_lock); + +int edac_mce_register(struct edac_mce *edac_mce) +{ + mutex_lock(&edac_mce_lock); + list_add_tail(&edac_mce->list, &edac_mce_list); + mutex_unlock(&edac_mce_lock); + return 0; +} +EXPORT_SYMBOL(edac_mce_register); + +void edac_mce_unregister(struct edac_mce *edac_mce) +{ + mutex_lock(&edac_mce_lock); + list_del(&edac_mce->list); + mutex_unlock(&edac_mce_lock); +} +EXPORT_SYMBOL(edac_mce_unregister); + + + +int edac_mce_queue(struct mce *mce) +{ + struct edac_mce *edac_mce; + + list_for_each_entry(edac_mce, &edac_mce_list, list) { + if (edac_mce->check_error(edac_mce->priv, mce)) + return 1; + } + + /* Nobody queued the error */ + return 0; +} +EXPORT_SYMBOL_GPL(edac_mce_queue); -- cgit v1.2.3 From 963c5ba35984c87963480031d1d7e2e556256ad7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 9 Jul 2009 22:04:30 -0300 Subject: edac/Kconfig: edac_mce can't be module Since mcelog is bool, edac_mce glue should also be bool, or otherwise will not work. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 5b7fbc5aec87..aedef7941b22 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -70,7 +70,7 @@ config EDAC_MM_EDAC replaced. If unsure, select 'Y'. config EDAC_MCE - tristate + bool config EDAC_AMD64 tristate "AMD64 (Opteron, Athlon64) K8, F10h, F11h" -- cgit v1.2.3 From d5381642ab01b084787925acdf26b5524d434476 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 9 Jul 2009 22:06:41 -0300 Subject: i7core_edac: Add edac_mce glue Adds a glue code to allow i7core to work with mcelog. With the glue, i7core registers itself on edac_mce. At mce, when an error is detected, it calls all registered drivers (in this case, i7core), for EDAC error handling. TODO: It currently just prints the MCE error log using about the same format as mce panic messages. The error message should be enhanced with mcelog userspace info and converted into the proper EDAC format, to feed the EDAC error counts. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/edac_mce.c | 11 +++-- drivers/edac/i7core_edac.c | 111 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 116 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/edac_mce.c b/drivers/edac/edac_mce.c index b1efa8e51921..9ccdc5b140e7 100644 --- a/drivers/edac/edac_mce.c +++ b/drivers/edac/edac_mce.c @@ -41,9 +41,7 @@ void edac_mce_unregister(struct edac_mce *edac_mce) } EXPORT_SYMBOL(edac_mce_unregister); - - -int edac_mce_queue(struct mce *mce) +int edac_mce_parse(struct mce *mce) { struct edac_mce *edac_mce; @@ -55,4 +53,9 @@ int edac_mce_queue(struct mce *mce) /* Nobody queued the error */ return 0; } -EXPORT_SYMBOL_GPL(edac_mce_queue); +EXPORT_SYMBOL_GPL(edac_mce_parse); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); +MODULE_DESCRIPTION("EDAC Driver for mcelog captured errors"); diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 914914759690..3c7bb5f405f6 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include "edac_core.h" @@ -195,6 +197,11 @@ struct i7core_pvt { unsigned long ce_count[MAX_DIMMS]; /* ECC corrected errors counts per dimm */ int last_ce_count[MAX_DIMMS]; + /* mcelog glue */ + struct edac_mce edac_mce; + struct mce mce_entry[MCE_LOG_LEN]; + unsigned mce_count; + spinlock_t mce_lock; }; /* Device name and register DID (Device ID) */ @@ -900,7 +907,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, pci_read_config_dword(pvt->pci_ch[pvt->inject.channel][0], MC_CHANNEL_ADDR_MATCH + 4, &rdmask2); - debugf0("Inject addr match write 0x%016llx, read: 0x%08x%08x\n", + debugf0("Inject addr match write 0x%016llx, read: 0x%08x 0x%08x\n", mask, rdmask1, rdmask2); #endif #endif @@ -1162,9 +1169,11 @@ static void check_mc_test_err(struct mem_ctl_info *mci) new1 = DIMM1_COR_ERR(rcv0); new0 = DIMM0_COR_ERR(rcv0); +#if 0 debugf2("%s CE rcv1=0x%08x rcv0=0x%08x, %d %d %d\n", (pvt->ce_count_available ? "UPDATE" : "READ"), rcv1, rcv0, new0, new1, new2); +#endif /* Updates CE counters if it is not the first time here */ if (pvt->ce_count_available) { @@ -1195,15 +1204,96 @@ static void check_mc_test_err(struct mem_ctl_info *mci) pvt->last_ce_count[0] = new0; } +static void i7core_mce_output_error(struct mem_ctl_info *mci, + struct mce *m) +{ + debugf0("CPU %d: Machine Check Exception: %16Lx" + "Bank %d: %016Lx\n", + m->cpu, m->mcgstatus, m->bank, m->status); + if (m->ip) { + debugf0("RIP%s %02x:<%016Lx>\n", + !(m->mcgstatus & MCG_STATUS_EIPV) ? " !INEXACT!" : "", + m->cs, m->ip); + } + printk(KERN_EMERG "TSC %llx ", m->tsc); + if (m->addr) + printk("ADDR %llx ", m->addr); + if (m->misc) + printk("MISC %llx ", m->misc); + +#if 0 + snprintf(msg, sizeof(msg), + "%s (Branch=%d DRAM-Bank=%d Buffer ID = %d RDWR=%s " + "RAS=%d CAS=%d %s Err=0x%lx (%s))", + type, branch >> 1, bank, buf_id, rdwr_str(rdwr), ras, cas, + type, allErrors, error_name[errnum]); + + /* Call the helper to output message */ + edac_mc_handle_fbd_ue(mci, rank, channel, channel + 1, msg); +#endif +} + /* * i7core_check_error Retrieve and process errors reported by the * hardware. Called by the Core module. */ static void i7core_check_error(struct mem_ctl_info *mci) { + struct i7core_pvt *pvt = mci->pvt_info; + int i; + unsigned count = 0; + struct mce *m = NULL; + unsigned long flags; + + debugf0(__FILE__ ": %s()\n", __func__); + + /* Copy all mce errors into a temporary buffer */ + spin_lock_irqsave(&pvt->mce_lock, flags); + if (pvt->mce_count) { + m = kmalloc(sizeof(*m) * pvt->mce_count, GFP_ATOMIC); + if (m) { + count = pvt->mce_count; + memcpy(m, &pvt->mce_entry, sizeof(*m) * count); + } + pvt->mce_count = 0; + } + spin_unlock_irqrestore(&pvt->mce_lock, flags); + + /* proccess mcelog errors */ + for (i = 0; i < count; i++) + i7core_mce_output_error(mci, &m[i]); + + kfree(m); + + /* check memory count errors */ check_mc_test_err(mci); } +/* + * i7core_mce_check_error Replicates mcelog routine to get errors + * This routine simply queues mcelog errors, and + * return. The error itself should be handled later + * by i7core_check_error. + */ +static int i7core_mce_check_error(void *priv, struct mce *mce) +{ + struct i7core_pvt *pvt = priv; + unsigned long flags; + + debugf0(__FILE__ ": %s()\n", __func__); + + spin_lock_irqsave(&pvt->mce_lock, flags); + if (pvt->mce_count < MCE_LOG_LEN) { + memcpy(&pvt->mce_entry[pvt->mce_count], mce, sizeof(*mce)); + pvt->mce_count++; + } + spin_unlock_irqrestore(&pvt->mce_lock, flags); + + /* Advice mcelog that the error were handled */ +// return 1; + return 0; // Let's duplicate the log +} + /* * i7core_probe Probe for ONE instance of device to see if it is * present. @@ -1305,6 +1395,18 @@ static int __devinit i7core_probe(struct pci_dev *pdev, pvt->inject.page = -1; pvt->inject.col = -1; + /* Registers on edac_mce in order to receive memory errors */ + pvt->edac_mce.priv = pvt; + pvt->edac_mce.check_error = i7core_mce_check_error; + spin_lock_init(&pvt->mce_lock); + + rc = edac_mce_register(&pvt->edac_mce); + if (unlikely (rc < 0)) { + debugf0("MC: " __FILE__ + ": %s(): failed edac_mce_register()\n", __func__); + goto fail1; + } + i7core_printk(KERN_INFO, "Driver loaded.\n"); return 0; @@ -1324,17 +1426,22 @@ fail0: static void __devexit i7core_remove(struct pci_dev *pdev) { struct mem_ctl_info *mci; + struct i7core_pvt *pvt; debugf0(__FILE__ ": %s()\n", __func__); if (i7core_pci) edac_pci_release_generic_ctl(i7core_pci); - mci = edac_mc_del_mc(&pdev->dev); + mci = edac_mc_del_mc(&pdev->dev); if (!mci) return; + /* Unregisters on edac_mce in order to receive memory errors */ + pvt = mci->pvt_info; + edac_mce_unregister(&pvt->edac_mce); + /* retrieve references to resources, and free those resources */ i7core_put_devices(); -- cgit v1.2.3 From e9bd2e73793bf0f7fcd8f94b532bb8f5c5b44171 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 9 Jul 2009 22:14:35 -0300 Subject: i7core_edac: Adds write unlock to MC registers The public Intel Xeon 5500 volume 2 datasheet describes, on page 53, session 2.6.7 a register that can lock/unlock Memory Controller the configuration register, called MC_CFG_CONTROL. Adds support for it in the hope that software error injection would work. With my tests with Xeon 35xx, there's still something missing. With a program that does sequencial bit writes at dev 0.0, sometimes, it produces error injection, after unblocking the MC_CFG_CONTROL (and, sometimes, it just locks my testing machine). I'll try later to discover by trial and error what's the register that solves this issue on Xeon 35xx. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 3c7bb5f405f6..26cd5c924d56 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -33,7 +33,7 @@ #include "edac_core.h" /* To use the new pci_[read/write]_config_qword instead of two dword */ -#define USE_QWORD 1 +#define USE_QWORD 0 /* * Alter this version for the module when modifications are made @@ -58,6 +58,10 @@ * i7core Memory Controller Registers */ + /* OFFSETS for Device 0 Function 0 */ + +#define MC_CFG_CONTROL 0x90 + /* OFFSETS for Device 3 Function 0 */ #define MC_CONTROL 0x48 @@ -186,6 +190,7 @@ struct pci_id_descr { }; struct i7core_pvt { + struct pci_dev *pci_noncore; struct pci_dev *pci_mcr[MAX_MCR_FUNC + 1]; struct pci_dev *pci_ch[NUM_CHANS][MAX_CHAN_FUNC + 1]; struct i7core_info info; @@ -222,6 +227,9 @@ struct pci_id_descr pci_devs[] = { { PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_I7_MC_RAS) }, /* if RDIMM is supported */ { PCI_DESCR(3, 4, PCI_DEVICE_ID_INTEL_I7_MC_TEST) }, + /* Generic Non-core registers */ + { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_I7_NOCORE) }, + /* Channel 0 */ { PCI_DESCR(4, 0, PCI_DEVICE_ID_INTEL_I7_MC_CH0_CTRL) }, { PCI_DESCR(4, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH0_ADDR) }, @@ -882,6 +890,16 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, else mask |= (pvt->inject.col & 0x3fffL); + /* Unlock writes to registers */ + pci_write_config_dword(pvt->pci_noncore, MC_CFG_CONTROL, 0x2); + msleep(100); + + /* Zeroes error count registers */ + pci_write_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV1, 0); + pci_write_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV0, 0); + pvt->ce_count_available = 0; + + #if USE_QWORD pci_write_config_qword(pvt->pci_ch[pvt->inject.channel][0], MC_CHANNEL_ADDR_MATCH, mask); @@ -929,12 +947,15 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], MC_CHANNEL_ERROR_MASK, injectmask); +#if 0 + /* lock writes to registers */ + pci_write_config_dword(pvt->pci_noncore, MC_CFG_CONTROL, 0); +#endif debugf0("Error inject addr match 0x%016llx, ecc 0x%08x," " inject 0x%08x\n", mask, pvt->inject.eccmask, injectmask); - return count; } @@ -1124,12 +1145,15 @@ static int mci_bind_devs(struct mem_ctl_info *mci) if (unlikely(func > MAX_CHAN_FUNC)) goto error; pvt->pci_ch[slot - 4][func] = pdev; - } else + } else if (!slot && !func) + pvt->pci_noncore = pdev; + else goto error; debugf0("Associated fn %d.%d, dev = %p\n", PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), pdev); } + return 0; error: -- cgit v1.2.3 From d1fd4fb69eeeb7db0693df58b9116db498d5bfe1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 10 Jul 2009 18:39:53 -0300 Subject: i7core_edac: Add a code to probe Xeon 55xx bus This code changes the detection procedure of i7core_edac. Instead of directly probing for MC registers, it probes for another register found on Nehalem. If found, it tries to pick the first MC PCI BUS. This should work fine with Xeon 35xx, but, on Xeon 55xx, this is at bus 254 and 255 that are not properly detected by the non-legacy PCI methods. The new detection code scans specifically at buses 254 and 255 for the Xeon 55xx devices. This code has not tested yet. After working, a change at the code will be needed, since the i7core is not yet ready for working with 2 sets of MC. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 26cd5c924d56..eec0c13c0205 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -221,15 +221,15 @@ struct i7core_dev_info { .dev_id = (device_id) struct pci_id_descr pci_devs[] = { + /* Generic Non-core registers */ + { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_I7_NOCORE) }, + /* Memory controller */ { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_I7_MCR) }, { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_I7_MC_TAD) }, { PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_I7_MC_RAS) }, /* if RDIMM is supported */ { PCI_DESCR(3, 4, PCI_DEVICE_ID_INTEL_I7_MC_TEST) }, - /* Generic Non-core registers */ - { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_I7_NOCORE) }, - /* Channel 0 */ { PCI_DESCR(4, 0, PCI_DEVICE_ID_INTEL_I7_MC_CH0_CTRL) }, { PCI_DESCR(4, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH0_ADDR) }, @@ -255,7 +255,7 @@ struct pci_id_descr pci_devs[] = { * This should match the first device at pci_devs table */ static const struct pci_device_id i7core_pci_tbl[] __devinitdata = { - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_MCR)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_X58_HUB_MGMT)}, {0,} /* 0 terminated list. */ }; @@ -1069,6 +1069,15 @@ static int i7core_get_devices(void) for (i = 0; i < N_DEVS; i++) { pdev = pci_get_device(PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, NULL); + + if (!pdev && !i) { + pcibios_scan_specific_bus(254); + pcibios_scan_specific_bus(255); + + pdev = pci_get_device(PCI_VENDOR_ID_INTEL, + pci_devs[i].dev_id, NULL); + } + if (likely(pdev)) pci_devs[i].pdev = pdev; else { -- cgit v1.2.3 From 67166af4abc11d9c0deb497ebe0b562f69c71942 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 15 Jul 2009 06:56:23 -0300 Subject: i7core_edac: add support for more than one MC socket Some Nehalem architectures have more than one MC socket. Socket 0 is located at bus 255. Currently, it is using up to 2 sockets, but increasing it to a larger number is just a matter of increasing MAX_SOCKETS definition. This seems to be required for properly support of Xeon 55xx. Still needs testing with Xeon 55xx. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 326 +++++++++++++++++++++++++++++---------------- 1 file changed, 213 insertions(+), 113 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index eec0c13c0205..69eacc1b50d7 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -155,6 +155,7 @@ #define NUM_CHANS 3 #define MAX_DIMMS 3 /* Max DIMMS per channel */ +#define NUM_SOCKETS 2 /* Max number of MC sockets */ #define MAX_MCR_FUNC 4 #define MAX_CHAN_FUNC 3 @@ -169,6 +170,7 @@ struct i7core_info { struct i7core_inject { int enable; + u8 socket; u32 section; u32 type; u32 eccmask; @@ -186,21 +188,25 @@ struct pci_id_descr { int dev; int func; int dev_id; - struct pci_dev *pdev; + struct pci_dev *pdev[NUM_SOCKETS]; }; struct i7core_pvt { - struct pci_dev *pci_noncore; - struct pci_dev *pci_mcr[MAX_MCR_FUNC + 1]; - struct pci_dev *pci_ch[NUM_CHANS][MAX_CHAN_FUNC + 1]; + struct pci_dev *pci_noncore[NUM_SOCKETS]; + struct pci_dev *pci_mcr[NUM_SOCKETS][MAX_MCR_FUNC + 1]; + struct pci_dev *pci_ch[NUM_SOCKETS][NUM_CHANS][MAX_CHAN_FUNC + 1]; + struct i7core_info info; struct i7core_inject inject; - struct i7core_channel channel[NUM_CHANS]; + struct i7core_channel channel[NUM_SOCKETS][NUM_CHANS]; + + int sockets; /* Number of sockets */ int channels; /* Number of active channels */ - int ce_count_available; - unsigned long ce_count[MAX_DIMMS]; /* ECC corrected errors counts per dimm */ - int last_ce_count[MAX_DIMMS]; + int ce_count_available[NUM_SOCKETS]; + /* ECC corrected errors counts per dimm */ + unsigned long ce_count[NUM_SOCKETS][MAX_DIMMS]; + int last_ce_count[NUM_SOCKETS][MAX_DIMMS]; /* mcelog glue */ struct edac_mce edac_mce; @@ -324,24 +330,26 @@ static inline int numcol(u32 col) /**************************************************************************** Memory check routines ****************************************************************************/ -static struct pci_dev *get_pdev_slot_func(int slot, int func) +static struct pci_dev *get_pdev_slot_func(u8 socket, unsigned slot, + unsigned func) { int i; for (i = 0; i < N_DEVS; i++) { - if (!pci_devs[i].pdev) + if (!pci_devs[i].pdev[socket]) continue; - if (PCI_SLOT(pci_devs[i].pdev->devfn) == slot && - PCI_FUNC(pci_devs[i].pdev->devfn) == func) { - return pci_devs[i].pdev; + if (PCI_SLOT(pci_devs[i].pdev[socket]->devfn) == slot && + PCI_FUNC(pci_devs[i].pdev[socket]->devfn) == func) { + return pci_devs[i].pdev[socket]; } } return NULL; } -static int i7core_get_active_channels(int *channels, int *csrows) +static int i7core_get_active_channels(u8 socket, unsigned *channels, + unsigned *csrows) { struct pci_dev *pdev = NULL; int i, j; @@ -350,9 +358,10 @@ static int i7core_get_active_channels(int *channels, int *csrows) *channels = 0; *csrows = 0; - pdev = get_pdev_slot_func(3, 0); + pdev = get_pdev_slot_func(socket, 3, 0); if (!pdev) { - i7core_printk(KERN_ERR, "Couldn't find fn 3.0!!!\n"); + i7core_printk(KERN_ERR, "Couldn't find socket %d fn 3.0!!!\n", + socket); return -ENODEV; } @@ -370,10 +379,11 @@ static int i7core_get_active_channels(int *channels, int *csrows) if (status & (1 << i)) continue; - pdev = get_pdev_slot_func(i + 4, 1); + pdev = get_pdev_slot_func(socket, i + 4, 1); if (!pdev) { - i7core_printk(KERN_ERR, "Couldn't find fn %d.%d!!!\n", - i + 4, 1); + i7core_printk(KERN_ERR, "Couldn't find socket %d " + "fn %d.%d!!!\n", + socket, i + 4, 1); return -ENODEV; } /* Devices 4-6 function 1 */ @@ -393,12 +403,13 @@ static int i7core_get_active_channels(int *channels, int *csrows) } } - debugf0("Number of active channels: %d\n", *channels); + debugf0("Number of active channels on socked %d: %d\n", + socket, *channels); return 0; } -static int get_dimm_config(struct mem_ctl_info *mci) +static int get_dimm_config(struct mem_ctl_info *mci, u8 socket) { struct i7core_pvt *pvt = mci->pvt_info; struct csrow_info *csr; @@ -409,7 +420,7 @@ static int get_dimm_config(struct mem_ctl_info *mci) enum mem_type mtype; /* Get data from the MC register, function 0 */ - pdev = pvt->pci_mcr[0]; + pdev = pvt->pci_mcr[socket][0]; if (!pdev) return -ENODEV; @@ -458,10 +469,11 @@ static int get_dimm_config(struct mem_ctl_info *mci) } /* Devices 4-6 function 0 */ - pci_read_config_dword(pvt->pci_ch[i][0], + pci_read_config_dword(pvt->pci_ch[socket][i][0], MC_CHANNEL_DIMM_INIT_PARAMS, &data); - pvt->channel[i].ranks = (data & QUAD_RANK_PRESENT) ? 4 : 2; + pvt->channel[socket][i].ranks = (data & QUAD_RANK_PRESENT) ? + 4 : 2; if (data & REGISTERED_DIMM) mtype = MEM_RDDR3; @@ -477,11 +489,11 @@ static int get_dimm_config(struct mem_ctl_info *mci) #endif /* Devices 4-6 function 1 */ - pci_read_config_dword(pvt->pci_ch[i][1], + pci_read_config_dword(pvt->pci_ch[socket][i][1], MC_DOD_CH_DIMM0, &dimm_dod[0]); - pci_read_config_dword(pvt->pci_ch[i][1], + pci_read_config_dword(pvt->pci_ch[socket][i][1], MC_DOD_CH_DIMM1, &dimm_dod[1]); - pci_read_config_dword(pvt->pci_ch[i][1], + pci_read_config_dword(pvt->pci_ch[socket][i][1], MC_DOD_CH_DIMM2, &dimm_dod[2]); debugf0("Ch%d phy rd%d, wr%d (0x%08x): " @@ -489,7 +501,7 @@ static int get_dimm_config(struct mem_ctl_info *mci) i, RDLCH(pvt->info.ch_map, i), WRLCH(pvt->info.ch_map, i), data, - pvt->channel[i].ranks, + pvt->channel[socket][i].ranks, (data & REGISTERED_DIMM) ? 'R' : 'U'); for (j = 0; j < 3; j++) { @@ -507,7 +519,7 @@ static int get_dimm_config(struct mem_ctl_info *mci) /* DDR3 has 8 I/O banks */ size = (rows * cols * banks * ranks) >> (20 - 3); - pvt->channel[i].dimms++; + pvt->channel[socket][i].dimms++; debugf0("\tdimm %d (0x%08x) %d Mb offset: %x, " "numbank: %d,\n\t\t" @@ -592,15 +604,42 @@ static int disable_inject(struct mem_ctl_info *mci) pvt->inject.enable = 0; - if (!pvt->pci_ch[pvt->inject.channel][0]) + if (!pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0]) return -ENODEV; - pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], + pci_write_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], MC_CHANNEL_ERROR_MASK, 0); return 0; } +/* + * i7core inject inject.socket + * + * accept and store error injection inject.socket value + */ +static ssize_t i7core_inject_socket_store(struct mem_ctl_info *mci, + const char *data, size_t count) +{ + struct i7core_pvt *pvt = mci->pvt_info; + unsigned long value; + int rc; + + rc = strict_strtoul(data, 10, &value); + if ((rc < 0) || (value > pvt->sockets)) + return 0; + + pvt->inject.section = (u32) value; + return count; +} + +static ssize_t i7core_inject_socket_show(struct mem_ctl_info *mci, + char *data) +{ + struct i7core_pvt *pvt = mci->pvt_info; + return sprintf(data, "%d\n", pvt->inject.socket); +} + /* * i7core inject inject.section * @@ -838,7 +877,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, int rc; long enable; - if (!pvt->pci_ch[pvt->inject.channel][0]) + if (!pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0]) return 0; rc = strict_strtoul(data, 10, &enable); @@ -856,7 +895,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, if (pvt->inject.dimm < 0) mask |= 1L << 41; else { - if (pvt->channel[pvt->inject.channel].dimms > 2) + if (pvt->channel[pvt->inject.socket][pvt->inject.channel].dimms > 2) mask |= (pvt->inject.dimm & 0x3L) << 35; else mask |= (pvt->inject.dimm & 0x1L) << 36; @@ -866,7 +905,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, if (pvt->inject.rank < 0) mask |= 1L << 40; else { - if (pvt->channel[pvt->inject.channel].dimms > 2) + if (pvt->channel[pvt->inject.socket][pvt->inject.channel].dimms > 2) mask |= (pvt->inject.rank & 0x1L) << 34; else mask |= (pvt->inject.rank & 0x3L) << 34; @@ -891,38 +930,41 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, mask |= (pvt->inject.col & 0x3fffL); /* Unlock writes to registers */ - pci_write_config_dword(pvt->pci_noncore, MC_CFG_CONTROL, 0x2); + pci_write_config_dword(pvt->pci_noncore[pvt->inject.socket], + MC_CFG_CONTROL, 0x2); msleep(100); /* Zeroes error count registers */ - pci_write_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV1, 0); - pci_write_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV0, 0); - pvt->ce_count_available = 0; + pci_write_config_dword(pvt->pci_mcr[pvt->inject.socket][4], + MC_TEST_ERR_RCV1, 0); + pci_write_config_dword(pvt->pci_mcr[pvt->inject.socket][4], + MC_TEST_ERR_RCV0, 0); + pvt->ce_count_available[pvt->inject.socket] = 0; #if USE_QWORD - pci_write_config_qword(pvt->pci_ch[pvt->inject.channel][0], + pci_write_config_qword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], MC_CHANNEL_ADDR_MATCH, mask); #else - pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], + pci_write_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], MC_CHANNEL_ADDR_MATCH, mask); - pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], + pci_write_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], MC_CHANNEL_ADDR_MATCH + 4, mask >> 32L); #endif #if 1 #if USE_QWORD u64 rdmask; - pci_read_config_qword(pvt->pci_ch[pvt->inject.channel][0], + pci_read_config_qword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], MC_CHANNEL_ADDR_MATCH, &rdmask); debugf0("Inject addr match write 0x%016llx, read: 0x%016llx\n", mask, rdmask); #else u32 rdmask1, rdmask2; - pci_read_config_dword(pvt->pci_ch[pvt->inject.channel][0], + pci_read_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], MC_CHANNEL_ADDR_MATCH, &rdmask1); - pci_read_config_dword(pvt->pci_ch[pvt->inject.channel][0], + pci_read_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], MC_CHANNEL_ADDR_MATCH + 4, &rdmask2); debugf0("Inject addr match write 0x%016llx, read: 0x%08x 0x%08x\n", @@ -930,7 +972,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, #endif #endif - pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], + pci_write_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], MC_CHANNEL_ERROR_MASK, pvt->inject.eccmask); /* @@ -944,7 +986,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, (pvt->inject.section & 0x3) << 1 | (pvt->inject.type & 0x6) << (3 - 1); - pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], + pci_write_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], MC_CHANNEL_ERROR_MASK, injectmask); #if 0 @@ -965,7 +1007,7 @@ static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci, struct i7core_pvt *pvt = mci->pvt_info; u32 injectmask; - pci_read_config_dword(pvt->pci_ch[pvt->inject.channel][0], + pci_read_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], MC_CHANNEL_ERROR_MASK, &injectmask); debugf0("Inject error read: 0x%018x\n", injectmask); @@ -978,23 +1020,38 @@ static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci, static ssize_t i7core_ce_regs_show(struct mem_ctl_info *mci, char *data) { + unsigned i, count, total = 0; struct i7core_pvt *pvt = mci->pvt_info; - if (!pvt->ce_count_available) - return sprintf(data, "unavailable\n"); + for (i = 0; i < pvt->sockets; i++) { + if (!pvt->ce_count_available[i]) + count = sprintf(data, "socket 0 data unavailable\n"); + else + count = sprintf(data, "socket %d, dimm0: %lu\n" + "dimm1: %lu\ndimm2: %lu\n", + i, + pvt->ce_count[i][0], + pvt->ce_count[i][1], + pvt->ce_count[i][2]); + data += count; + total += count; + } - return sprintf(data, "dimm0: %lu\ndimm1: %lu\ndimm2: %lu\n", - pvt->ce_count[0], - pvt->ce_count[1], - pvt->ce_count[2]); + return total; } /* * Sysfs struct */ static struct mcidev_sysfs_attribute i7core_inj_attrs[] = { - { + .attr = { + .name = "inject_socket", + .mode = (S_IRUGO | S_IWUSR) + }, + .show = i7core_inject_socket_show, + .store = i7core_inject_socket_store, + }, { .attr = { .name = "inject_section", .mode = (S_IRUGO | S_IWUSR) @@ -1049,10 +1106,11 @@ static struct mcidev_sysfs_attribute i7core_inj_attrs[] = { */ static void i7core_put_devices(void) { - int i; + int i, j; - for (i = 0; i < N_DEVS; i++) - pci_dev_put(pci_devs[i].pdev); + for (i = 0; i < NUM_SOCKETS; i++) + for (j = 0; j < N_DEVS; j++) + pci_dev_put(pci_devs[j].pdev[i]); } /* @@ -1065,6 +1123,8 @@ static int i7core_get_devices(void) { int rc, i; struct pci_dev *pdev = NULL; + u8 bus = 0; + u8 socket = 0; for (i = 0; i < N_DEVS; i++) { pdev = pci_get_device(PCI_VENDOR_ID_INTEL, @@ -1078,14 +1138,32 @@ static int i7core_get_devices(void) pci_devs[i].dev_id, NULL); } - if (likely(pdev)) - pci_devs[i].pdev = pdev; - else { + if (likely(pdev)) { + bus = pdev->bus->number; + + if (bus == 0x3f) + socket = 0; + else + socket = 255 - bus; + + if (socket >= NUM_SOCKETS) { + i7core_printk(KERN_ERR, + "Found unexpected socket for " + "dev %02x:%02x.%d PCI ID %04x:%04x\n", + bus, pci_devs[i].dev, pci_devs[i].func, + PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id); + + rc = -ENODEV; + goto error; + } + + pci_devs[i].pdev[socket] = pdev; + } else { i7core_printk(KERN_ERR, - "Device not found: PCI ID %04x:%04x " - "(dev %d, func %d)\n", - PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, - pci_devs[i].dev, pci_devs[i].func); + "Device not found: " + "dev %02x:%02x.%d PCI ID %04x:%04x\n", + bus, pci_devs[i].dev, pci_devs[i].func, + PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id); /* Dev 3 function 2 only exists on chips with RDIMMs */ if ((pci_devs[i].dev == 3) && (pci_devs[i].func == 2)) @@ -1121,9 +1199,10 @@ static int i7core_get_devices(void) } i7core_printk(KERN_INFO, - "Registered device %0x:%0x fn %d.%d\n", - PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); + "Registered socket %d " + "dev %02x:%02x.%d PCI ID %04x:%04x\n", + socket, bus, pci_devs[i].dev, pci_devs[i].func, + PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id); } return 0; @@ -1137,30 +1216,33 @@ static int mci_bind_devs(struct mem_ctl_info *mci) { struct i7core_pvt *pvt = mci->pvt_info; struct pci_dev *pdev; - int i, func, slot; + int i, j, func, slot; - for (i = 0; i < N_DEVS; i++) { - pdev = pci_devs[i].pdev; - if (!pdev) - continue; + for (i = 0; i < pvt->sockets; i++) { + for (j = 0; j < N_DEVS; j++) { + pdev = pci_devs[j].pdev[i]; + if (!pdev) + continue; - func = PCI_FUNC(pdev->devfn); - slot = PCI_SLOT(pdev->devfn); - if (slot == 3) { - if (unlikely(func > MAX_MCR_FUNC)) - goto error; - pvt->pci_mcr[func] = pdev; - } else if (likely(slot >= 4 && slot < 4 + NUM_CHANS)) { - if (unlikely(func > MAX_CHAN_FUNC)) + func = PCI_FUNC(pdev->devfn); + slot = PCI_SLOT(pdev->devfn); + if (slot == 3) { + if (unlikely(func > MAX_MCR_FUNC)) + goto error; + pvt->pci_mcr[i][func] = pdev; + } else if (likely(slot >= 4 && slot < 4 + NUM_CHANS)) { + if (unlikely(func > MAX_CHAN_FUNC)) + goto error; + pvt->pci_ch[i][slot - 4][func] = pdev; + } else if (!slot && !func) + pvt->pci_noncore[i] = pdev; + else goto error; - pvt->pci_ch[slot - 4][func] = pdev; - } else if (!slot && !func) - pvt->pci_noncore = pdev; - else - goto error; - debugf0("Associated fn %d.%d, dev = %p\n", - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), pdev); + debugf0("Associated fn %d.%d, dev = %p, socket %d\n", + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), + pdev, i); + } } return 0; @@ -1182,20 +1264,20 @@ error: * also available at: * http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf */ -static void check_mc_test_err(struct mem_ctl_info *mci) +static void check_mc_test_err(struct mem_ctl_info *mci, u8 socket) { struct i7core_pvt *pvt = mci->pvt_info; u32 rcv1, rcv0; int new0, new1, new2; - if (!pvt->pci_mcr[4]) { + if (!pvt->pci_mcr[socket][4]) { debugf0("%s MCR registers not found\n",__func__); return; } /* Corrected error reads */ - pci_read_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV1, &rcv1); - pci_read_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV0, &rcv0); + pci_read_config_dword(pvt->pci_mcr[socket][4], MC_TEST_ERR_RCV1, &rcv1); + pci_read_config_dword(pvt->pci_mcr[socket][4], MC_TEST_ERR_RCV0, &rcv0); /* Store the new values */ new2 = DIMM2_COR_ERR(rcv1); @@ -1209,32 +1291,32 @@ static void check_mc_test_err(struct mem_ctl_info *mci) #endif /* Updates CE counters if it is not the first time here */ - if (pvt->ce_count_available) { + if (pvt->ce_count_available[socket]) { /* Updates CE counters */ int add0, add1, add2; - add2 = new2 - pvt->last_ce_count[2]; - add1 = new1 - pvt->last_ce_count[1]; - add0 = new0 - pvt->last_ce_count[0]; + add2 = new2 - pvt->last_ce_count[socket][2]; + add1 = new1 - pvt->last_ce_count[socket][1]; + add0 = new0 - pvt->last_ce_count[socket][0]; if (add2 < 0) add2 += 0x7fff; - pvt->ce_count[2] += add2; + pvt->ce_count[socket][2] += add2; if (add1 < 0) add1 += 0x7fff; - pvt->ce_count[1] += add1; + pvt->ce_count[socket][1] += add1; if (add0 < 0) add0 += 0x7fff; - pvt->ce_count[0] += add0; + pvt->ce_count[socket][0] += add0; } else - pvt->ce_count_available = 1; + pvt->ce_count_available[socket] = 1; /* Store the new values */ - pvt->last_ce_count[2] = new2; - pvt->last_ce_count[1] = new1; - pvt->last_ce_count[0] = new0; + pvt->last_ce_count[socket][2] = new2; + pvt->last_ce_count[socket][1] = new1; + pvt->last_ce_count[socket][0] = new0; } static void i7core_mce_output_error(struct mem_ctl_info *mci, @@ -1299,7 +1381,8 @@ static void i7core_check_error(struct mem_ctl_info *mci) kfree(m); /* check memory count errors */ - check_mc_test_err(mci); + for (i = 0; i < pvt->sockets; i++) + check_mc_test_err(mci, i); } /* @@ -1339,10 +1422,11 @@ static int __devinit i7core_probe(struct pci_dev *pdev, { struct mem_ctl_info *mci; struct i7core_pvt *pvt; - int num_channels; - int num_csrows; + int num_channels = 0; + int num_csrows = 0; int dev_idx = id->driver_data; - int rc; + int rc, i; + u8 sockets; if (unlikely(dev_idx >= ARRAY_SIZE(i7core_devs))) return -EINVAL; @@ -1352,10 +1436,25 @@ static int __devinit i7core_probe(struct pci_dev *pdev, if (unlikely(rc < 0)) return rc; - /* Check the number of active and not disabled channels */ - rc = i7core_get_active_channels(&num_channels, &num_csrows); - if (unlikely(rc < 0)) - goto fail0; + sockets = 1; + for (i = NUM_SOCKETS - 1; i > 0; i--) + if (pci_devs[0].pdev[i]) { + sockets = i + 1; + break; + } + + for (i = 0; i < sockets; i++) { + int channels; + int csrows; + + /* Check the number of active and not disabled channels */ + rc = i7core_get_active_channels(i, &channels, &csrows); + if (unlikely(rc < 0)) + goto fail0; + + num_channels += channels; + num_csrows += csrows; + } /* allocate a new MC control structure */ mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); @@ -1367,11 +1466,11 @@ static int __devinit i7core_probe(struct pci_dev *pdev, debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); mci->dev = &pdev->dev; /* record ptr to the generic device */ - pvt = mci->pvt_info; memset(pvt, 0, sizeof(*pvt)); - + pvt->sockets = sockets; mci->mc_idx = 0; + /* * FIXME: how to handle RDDR3 at MCI level? It is possible to have * Mixed RDDR3/UDDR3 with Nehalem, provided that they are on different @@ -1395,7 +1494,8 @@ static int __devinit i7core_probe(struct pci_dev *pdev, goto fail1; /* Get dimm basic config */ - get_dimm_config(mci); + for (i = 0; i < sockets; i++) + get_dimm_config(mci, i); /* add this new MC control structure to EDAC's list of MCs */ if (unlikely(edac_mc_add_mc(mci))) { -- cgit v1.2.3 From ba6c5c62eeb877da638e43f1282f778432142eec Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 15 Jul 2009 09:02:32 -0300 Subject: i7core_edac: maps all sockets as if ther are one MC controller Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 69eacc1b50d7..a93ebdf9c121 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -409,12 +409,12 @@ static int i7core_get_active_channels(u8 socket, unsigned *channels, return 0; } -static int get_dimm_config(struct mem_ctl_info *mci, u8 socket) +static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) { struct i7core_pvt *pvt = mci->pvt_info; struct csrow_info *csr; struct pci_dev *pdev; - int i, j, csrow = 0; + int i, j; unsigned long last_page = 0; enum edac_type mode; enum mem_type mtype; @@ -534,7 +534,7 @@ static int get_dimm_config(struct mem_ctl_info *mci, u8 socket) npages = size << (20 - PAGE_SHIFT); #endif - csr = &mci->csrows[csrow]; + csr = &mci->csrows[*csrow]; csr->first_page = last_page + 1; last_page += npages; csr->last_page = last_page; @@ -542,7 +542,7 @@ static int get_dimm_config(struct mem_ctl_info *mci, u8 socket) csr->page_mask = 0; csr->grain = 8; - csr->csrow_idx = csrow; + csr->csrow_idx = *csrow; csr->nr_channels = 1; csr->channels[0].chan_idx = i; @@ -565,7 +565,7 @@ static int get_dimm_config(struct mem_ctl_info *mci, u8 socket) csr->edac_mode = mode; csr->mtype = mtype; - csrow++; + (*csrow)++; } pci_read_config_dword(pdev, MC_SAG_CH_0, &value[0]); @@ -1424,6 +1424,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, struct i7core_pvt *pvt; int num_channels = 0; int num_csrows = 0; + int csrow = 0; int dev_idx = id->driver_data; int rc, i; u8 sockets; @@ -1495,7 +1496,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, /* Get dimm basic config */ for (i = 0; i < sockets; i++) - get_dimm_config(mci, i); + get_dimm_config(mci, &csrow, i); /* add this new MC control structure to EDAC's list of MCs */ if (unlikely(edac_mc_add_mc(mci))) { -- cgit v1.2.3 From 8a2f118e3a023a4e8cbe56a6e51f7b78fa8c76a0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 15 Jul 2009 19:01:08 -0300 Subject: i7core_edac: decode mcelog error and send it via edac interface Enriches mcelog error by using the encoded information at MCE status and misc registers (IA32_MCx_STATUS, IA32_MCx_MISC). Some fixes are still needed here, in order to properly fill the EDAC fields. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 92 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 70 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index a93ebdf9c121..4397a3171c62 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1319,33 +1319,75 @@ static void check_mc_test_err(struct mem_ctl_info *mci, u8 socket) pvt->last_ce_count[socket][0] = new0; } +/* + * According with tables E-11 and E-12 of chapter E.3.3 of Intel 64 and IA-32 + * Architectures Software Developer’s Manual Volume 3B. + * The MCA registers are the following ones: + * struct mce field MCA Register + * m->status MSR_IA32_MC0_STATUS + * m->addr MSR_IA32_MC0_ADDR + * m->misc MSR_IA32_MC0_MISC + * m->mcgstatus MSR_IA32_MCG_STATUS + * In the case of Nehalem, the error information is masked at .status and .misc + * fields + */ static void i7core_mce_output_error(struct mem_ctl_info *mci, struct mce *m) { - debugf0("CPU %d: Machine Check Exception: %16Lx" - "Bank %d: %016Lx\n", - m->cpu, m->mcgstatus, m->bank, m->status); - if (m->ip) { - debugf0("RIP%s %02x:<%016Lx>\n", - !(m->mcgstatus & MCG_STATUS_EIPV) ? " !INEXACT!" : "", - m->cs, m->ip); + char *type="NON-FATAL"; + char *err, *msg; + unsigned long error = m->status & 0x1ff0000l; + u32 core_err_cnt = (m->status >> 38) && 0x7fff; + u32 dimm = (m->misc >> 16) & 0x3; + u32 channel = (m->misc >> 18) & 0x3; + u32 syndrome = m->misc >> 32; + u32 errnum = find_first_bit(&error, 32); + + switch (errnum) { + case 16: + err = "read ECC error"; + break; + case 17: + err = "RAS ECC error"; + break; + case 18: + err = "write parity error"; + break; + case 19: + err = "redundacy loss"; + break; + case 20: + err = "reserved"; + break; + case 21: + err = "memory range error"; + break; + case 22: + err = "RTID out of range"; + break; + case 23: + err = "address parity error"; + break; + case 24: + err = "byte enable parity error"; + break; + default: + err = "unknown"; } - printk(KERN_EMERG "TSC %llx ", m->tsc); - if (m->addr) - printk("ADDR %llx ", m->addr); - if (m->misc) - printk("MISC %llx ", m->misc); -#if 0 - snprintf(msg, sizeof(msg), - "%s (Branch=%d DRAM-Bank=%d Buffer ID = %d RDWR=%s " - "RAS=%d CAS=%d %s Err=0x%lx (%s))", - type, branch >> 1, bank, buf_id, rdwr_str(rdwr), ras, cas, - type, allErrors, error_name[errnum]); + msg = kasprintf(GFP_ATOMIC, + "%s (addr = 0x%08llx Bank=0x%08x, Dimm=%d, Channel=%d, " + "syndrome=0x%08x total error count=%d Err=%d (%s))\n", + type, (long long) m->addr, m->bank, dimm, channel, + syndrome, core_err_cnt,errnum, err); + + debugf0("%s", msg); /* Call the helper to output message */ - edac_mc_handle_fbd_ue(mci, rank, channel, channel + 1, msg); -#endif + edac_mc_handle_fbd_ue(mci, 0 /* FIXME: should be rank here */, + 0, 0 /* FIXME: should be channel here */, msg); + + kfree(msg); } /* @@ -1398,6 +1440,13 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) debugf0(__FILE__ ": %s()\n", __func__); + /* + * Just let mcelog handle it if the error is + * outside the memory controller + */ + if (((mce->status & 0xffff) >> 7) != 1) + return 0; + spin_lock_irqsave(&pvt->mce_lock, flags); if (pvt->mce_count < MCE_LOG_LEN) { memcpy(&pvt->mce_entry[pvt->mce_count], mce, sizeof(*mce)); @@ -1406,8 +1455,7 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) spin_unlock_irqrestore(&pvt->mce_lock, flags); /* Advice mcelog that the error were handled */ -// return 1; - return 0; // Let's duplicate the log + return 1; } /* -- cgit v1.2.3 From f237fcf2b7560be33386255042dc11167ca486d5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 15 Jul 2009 19:53:24 -0300 Subject: i7core_edac: some fixes at memory error parser m->bank is not related to the memory bank but, instead, to the MCA Error register bank. Fix it accordingly. While here, improves the comments for Nehalem bank. A later fix is needed, in order to get bank/rank information from MCA error log. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 4397a3171c62..67822976992e 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1322,12 +1322,13 @@ static void check_mc_test_err(struct mem_ctl_info *mci, u8 socket) /* * According with tables E-11 and E-12 of chapter E.3.3 of Intel 64 and IA-32 * Architectures Software Developer’s Manual Volume 3B. - * The MCA registers are the following ones: + * Nehalem are defined as family 0x06, model 0x1a + * + * The MCA registers used here are the following ones: * struct mce field MCA Register - * m->status MSR_IA32_MC0_STATUS - * m->addr MSR_IA32_MC0_ADDR - * m->misc MSR_IA32_MC0_MISC - * m->mcgstatus MSR_IA32_MCG_STATUS + * m->status MSR_IA32_MC8_STATUS + * m->addr MSR_IA32_MC8_ADDR + * m->misc MSR_IA32_MC8_MISC * In the case of Nehalem, the error information is masked at .status and .misc * fields */ @@ -1375,10 +1376,11 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, err = "unknown"; } + /* FIXME: should convert addr into bank and rank information */ msg = kasprintf(GFP_ATOMIC, - "%s (addr = 0x%08llx Bank=0x%08x, Dimm=%d, Channel=%d, " - "syndrome=0x%08x total error count=%d Err=%d (%s))\n", - type, (long long) m->addr, m->bank, dimm, channel, + "%s (addr = 0x%08llx Dimm=%d, Channel=%d, " + "syndrome=0x%08x, count=%d Err=%d (%s))\n", + type, (long long) m->addr, dimm, channel, syndrome, core_err_cnt,errnum, err); debugf0("%s", msg); @@ -1447,6 +1449,10 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) if (((mce->status & 0xffff) >> 7) != 1) return 0; + /* Bank 8 registers are the only ones that we know how to handle */ + if (mce->bank != 8) + return 0; + spin_lock_irqsave(&pvt->mce_lock, flags); if (pvt->mce_count < MCE_LOG_LEN) { memcpy(&pvt->mce_entry[pvt->mce_count], mce, sizeof(*mce)); -- cgit v1.2.3 From 310cbb7284fab9fc9cbb6bb893e51c414e15bba3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 17 Jul 2009 00:09:10 -0300 Subject: i7core: fix probing on Xeon55xx Xeon55xx fails to probe with this error message: EDAC DEBUG: in drivers/edac/i7core_edac.c, line at 1660: MC: drivers/edac/i7core_edac.c: i7core_init() EDAC i7core: Device not found: dev 00:00.0 PCI ID 8086:2c41 i7core_edac: probe of 0000:00:14.0 failed with error -22 This is due to the fact that, on Xeon35xx (and i7core), device 00.0 has PCI ID 8086:2c40. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 67822976992e..e2f6dfdca841 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -227,9 +227,6 @@ struct i7core_dev_info { .dev_id = (device_id) struct pci_id_descr pci_devs[] = { - /* Generic Non-core registers */ - { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_I7_NOCORE) }, - /* Memory controller */ { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_I7_MCR) }, { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_I7_MC_TAD) }, @@ -253,6 +250,16 @@ struct pci_id_descr pci_devs[] = { { PCI_DESCR(6, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH2_ADDR) }, { PCI_DESCR(6, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH2_RANK) }, { PCI_DESCR(6, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH2_TC) }, + + /* Generic Non-core registers */ + /* + * This is the PCI device on i7core and on Xeon 35xx (8086:2c41) + * On Xeon 55xx, however, it has a different id (8086:2c40). So, + * the probing code needs to test for the other address in case of + * failure of this one + */ + { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_I7_NOCORE) }, + }; #define N_DEVS ARRAY_SIZE(pci_devs) @@ -1138,6 +1145,16 @@ static int i7core_get_devices(void) pci_devs[i].dev_id, NULL); } + /* + * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core regs + * is at addr 8086:2c40, instead of 8086:2c41. So, we need + * to probe for the alternate address in case of failure + */ + if (pci_devs[i].dev_id == PCI_DEVICE_ID_INTEL_I7_NOCORE + && !pdev) + pdev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_I7_NOCORE_ALT, NULL); + if (likely(pdev)) { bus = pdev->bus->number; -- cgit v1.2.3 From c5d34528696acadc40d2ba7601dbf35d65b74ad5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 17 Jul 2009 10:28:15 -0300 Subject: i7core: check if the memory error is fatal or non-fatal Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index e2f6dfdca841..08149d5addff 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1352,7 +1352,7 @@ static void check_mc_test_err(struct mem_ctl_info *mci, u8 socket) static void i7core_mce_output_error(struct mem_ctl_info *mci, struct mce *m) { - char *type="NON-FATAL"; + char *type; char *err, *msg; unsigned long error = m->status & 0x1ff0000l; u32 core_err_cnt = (m->status >> 38) && 0x7fff; @@ -1361,6 +1361,11 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, u32 syndrome = m->misc >> 32; u32 errnum = find_first_bit(&error, 32); + if (m->mcgstatus & 1) + type = "FATAL"; + else + type = "NON_FATAL"; + switch (errnum) { case 16: err = "read ECC error"; @@ -1454,7 +1459,8 @@ static void i7core_check_error(struct mem_ctl_info *mci) */ static int i7core_mce_check_error(void *priv, struct mce *mce) { - struct i7core_pvt *pvt = priv; + struct mem_ctl_info *mci = priv; + struct i7core_pvt *pvt = mci->pvt_info; unsigned long flags; debugf0(__FILE__ ": %s()\n", __func__); @@ -1477,6 +1483,10 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) } spin_unlock_irqrestore(&pvt->mce_lock, flags); + /* Handle fatal errors immediately */ + if (mce->mcgstatus & 1) + i7core_check_error(mci); + /* Advice mcelog that the error were handled */ return 1; } @@ -1601,7 +1611,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, pvt->inject.col = -1; /* Registers on edac_mce in order to receive memory errors */ - pvt->edac_mce.priv = pvt; + pvt->edac_mce.priv = mci; pvt->edac_mce.check_error = i7core_mce_check_error; spin_lock_init(&pvt->mce_lock); -- cgit v1.2.3 From a639539fa28531924c6b5e0f3963cc63d060947d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 17 Jul 2009 10:54:23 -0300 Subject: i7core: enrich error information based on memory transaction type Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 08149d5addff..9f39d3d5502e 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1352,9 +1352,9 @@ static void check_mc_test_err(struct mem_ctl_info *mci, u8 socket) static void i7core_mce_output_error(struct mem_ctl_info *mci, struct mce *m) { - char *type; - char *err, *msg; + char *type, *optype, *err, *msg; unsigned long error = m->status & 0x1ff0000l; + u32 optypenum = (m->status >> 4) & 0x07; u32 core_err_cnt = (m->status >> 38) && 0x7fff; u32 dimm = (m->misc >> 16) & 0x3; u32 channel = (m->misc >> 18) & 0x3; @@ -1366,6 +1366,27 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, else type = "NON_FATAL"; + switch (optypenum) { + case 0: + optype = "generic undef request"; + break; + case 1: + optype = "read error"; + break; + case 2: + optype = "write error"; + break; + case 3: + optype = "addr/cmd error"; + break; + case 4: + optype = "scrubbing error"; + break; + default: + optype = "reserved"; + break; + } + switch (errnum) { case 16: err = "read ECC error"; @@ -1400,10 +1421,11 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, /* FIXME: should convert addr into bank and rank information */ msg = kasprintf(GFP_ATOMIC, - "%s (addr = 0x%08llx Dimm=%d, Channel=%d, " - "syndrome=0x%08x, count=%d Err=%d (%s))\n", + "%s (addr = 0x%08llx, Dimm=%d, Channel=%d, " + "syndrome=0x%08x, count=%d, Err=%08llx:%08llx (%s: %s))\n", type, (long long) m->addr, dimm, channel, - syndrome, core_err_cnt,errnum, err); + syndrome, core_err_cnt, (long long)m->status, + (long long)m->misc, optype, err); debugf0("%s", msg); -- cgit v1.2.3 From c77720b9544d8825ff5b9546d0ee038cfa4d4eb2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 18 Jul 2009 10:43:08 -0300 Subject: i7core: fix get_devices routine for Xeon55xx i7core_get_devices() were preparet to get just the first found device of each type. Due to that, on Xeon 55xx, only socket 1 were retrived. Rework i7core_get_devices() to clean it and to properly support Xeon 55xx. While here, fix a small typo. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 186 ++++++++++++++++++++++++++------------------- 1 file changed, 108 insertions(+), 78 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 9f39d3d5502e..79636b58ec52 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -410,7 +410,7 @@ static int i7core_get_active_channels(u8 socket, unsigned *channels, } } - debugf0("Number of active channels on socked %d: %d\n", + debugf0("Number of active channels on socket %d: %d\n", socket, *channels); return 0; @@ -1126,107 +1126,137 @@ static void i7core_put_devices(void) * * Need to 'get' device 16 func 1 and func 2 */ -static int i7core_get_devices(void) +int i7core_get_onedevice(struct pci_dev **prev, int devno) { - int rc, i; struct pci_dev *pdev = NULL; u8 bus = 0; u8 socket = 0; - for (i = 0; i < N_DEVS; i++) { + pdev = pci_get_device(PCI_VENDOR_ID_INTEL, + pci_devs[devno].dev_id, *prev); + + /* + * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core pci buses + * aren't announced by acpi. So, we need to use a legacy scan probing + * to detect them + */ + if (unlikely(!pdev && !devno && !prev)) { + pcibios_scan_specific_bus(254); + pcibios_scan_specific_bus(255); + pdev = pci_get_device(PCI_VENDOR_ID_INTEL, - pci_devs[i].dev_id, NULL); + pci_devs[devno].dev_id, *prev); + } - if (!pdev && !i) { - pcibios_scan_specific_bus(254); - pcibios_scan_specific_bus(255); + /* + * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core regs + * is at addr 8086:2c40, instead of 8086:2c41. So, we need + * to probe for the alternate address in case of failure + */ + if (pci_devs[devno].dev_id == PCI_DEVICE_ID_INTEL_I7_NOCORE && !pdev) + pdev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_I7_NOCORE_ALT, *prev); - pdev = pci_get_device(PCI_VENDOR_ID_INTEL, - pci_devs[i].dev_id, NULL); + if (!pdev) { + if (*prev) { + *prev = pdev; + return 0; } /* - * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core regs - * is at addr 8086:2c40, instead of 8086:2c41. So, we need - * to probe for the alternate address in case of failure + * Dev 3 function 2 only exists on chips with RDIMMs + * so, it is ok to not found it */ - if (pci_devs[i].dev_id == PCI_DEVICE_ID_INTEL_I7_NOCORE - && !pdev) - pdev = pci_get_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_I7_NOCORE_ALT, NULL); + if ((pci_devs[devno].dev == 3) && (pci_devs[devno].func == 2)) { + *prev = pdev; + return 0; + } - if (likely(pdev)) { - bus = pdev->bus->number; + i7core_printk(KERN_ERR, + "Device not found: dev %02x.%d PCI ID %04x:%04x\n", + pci_devs[devno].dev, pci_devs[devno].func, + PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id); - if (bus == 0x3f) - socket = 0; - else - socket = 255 - bus; + /* End of list, leave */ + return -ENODEV; + } + bus = pdev->bus->number; - if (socket >= NUM_SOCKETS) { - i7core_printk(KERN_ERR, - "Found unexpected socket for " - "dev %02x:%02x.%d PCI ID %04x:%04x\n", - bus, pci_devs[i].dev, pci_devs[i].func, - PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id); + if (bus == 0x3f) + socket = 0; + else + socket = 255 - bus; + + if (socket >= NUM_SOCKETS) { + i7core_printk(KERN_ERR, + "Unexpected socket for " + "dev %02x:%02x.%d PCI ID %04x:%04x\n", + bus, pci_devs[devno].dev, pci_devs[devno].func, + PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id); + pci_dev_put(pdev); + return -ENODEV; + } - rc = -ENODEV; - goto error; - } + if (pci_devs[devno].pdev[socket]) { + i7core_printk(KERN_ERR, + "Duplicated device for " + "dev %02x:%02x.%d PCI ID %04x:%04x\n", + bus, pci_devs[devno].dev, pci_devs[devno].func, + PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id); + pci_dev_put(pdev); + return -ENODEV; + } - pci_devs[i].pdev[socket] = pdev; - } else { - i7core_printk(KERN_ERR, - "Device not found: " - "dev %02x:%02x.%d PCI ID %04x:%04x\n", - bus, pci_devs[i].dev, pci_devs[i].func, - PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id); + pci_devs[devno].pdev[socket] = pdev; + + /* Sanity check */ + if (unlikely(PCI_SLOT(pdev->devfn) != pci_devs[devno].dev || + PCI_FUNC(pdev->devfn) != pci_devs[devno].func)) { + i7core_printk(KERN_ERR, + "Device PCI ID %04x:%04x " + "has dev %02x:%02x.%d instead of dev %02x:%02x.%d\n", + PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id, + bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), + bus, pci_devs[devno].dev, pci_devs[devno].func); + return -ENODEV; + } - /* Dev 3 function 2 only exists on chips with RDIMMs */ - if ((pci_devs[i].dev == 3) && (pci_devs[i].func == 2)) - continue; + /* Be sure that the device is enabled */ + if (unlikely(pci_enable_device(pdev) < 0)) { + i7core_printk(KERN_ERR, + "Couldn't enable " + "dev %02x:%02x.%d PCI ID %04x:%04x\n", + bus, pci_devs[devno].dev, pci_devs[devno].func, + PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id); + return -ENODEV; + } - /* End of list, leave */ - rc = -ENODEV; - goto error; - } + i7core_printk(KERN_INFO, + "Registered socket %d " + "dev %02x:%02x.%d PCI ID %04x:%04x\n", + socket, bus, pci_devs[devno].dev, pci_devs[devno].func, + PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id); - /* Sanity check */ - if (unlikely(PCI_SLOT(pdev->devfn) != pci_devs[i].dev || - PCI_FUNC(pdev->devfn) != pci_devs[i].func)) { - i7core_printk(KERN_ERR, - "Device PCI ID %04x:%04x " - "has fn %d.%d instead of fn %d.%d\n", - PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), - pci_devs[i].dev, pci_devs[i].func); - rc = -EINVAL; - goto error; - } + *prev = pdev; - /* Be sure that the device is enabled */ - rc = pci_enable_device(pdev); - if (unlikely(rc < 0)) { - i7core_printk(KERN_ERR, - "Couldn't enable PCI ID %04x:%04x " - "fn %d.%d\n", - PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); - goto error; - } + return 0; +} - i7core_printk(KERN_INFO, - "Registered socket %d " - "dev %02x:%02x.%d PCI ID %04x:%04x\n", - socket, bus, pci_devs[i].dev, pci_devs[i].func, - PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id); - } +static int i7core_get_devices(void) +{ + int i; + struct pci_dev *pdev = NULL; + for (i = 0; i < N_DEVS; i++) { + pdev = NULL; + do { + if (i7core_get_onedevice(&pdev, i) < 0) { + i7core_put_devices(); + return -ENODEV; + } + } while (pdev); + } return 0; - -error: - i7core_put_devices(); - return -EINVAL; } static int mci_bind_devs(struct mem_ctl_info *mci) -- cgit v1.2.3 From ec6df24c15822e671801eeeb53758e14f3b28381 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 18 Jul 2009 10:44:30 -0300 Subject: i7core: better document i7core_get_active_channels() Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 79636b58ec52..bf0374062e3d 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -333,7 +333,6 @@ static inline int numcol(u32 col) return cols[col & 0x3]; } - /**************************************************************************** Memory check routines ****************************************************************************/ @@ -355,6 +354,23 @@ static struct pci_dev *get_pdev_slot_func(u8 socket, unsigned slot, return NULL; } +/** + * i7core_get_active_channels() - gets the number of channels and csrows + * @socket: Quick Path Interconnect socket + * @channels: Number of channels that will be returned + * @csrows: Number of csrows found + * + * Since EDAC core needs to know in advance the number of available channels + * and csrows, in order to allocate memory for csrows/channels, it is needed + * to run two similar steps. At the first step, implemented on this function, + * it checks the number of csrows/channels present at one socket. + * this is used in order to properly allocate the size of mci components. + * + * It should be noticed that none of the current available datasheets explain + * or even mention how csrows are seen by the memory controller. So, we need + * to add a fake description for csrows. + * So, this driver is attributing one DIMM memory for one csrow. + */ static int i7core_get_active_channels(u8 socket, unsigned *channels, unsigned *csrows) { -- cgit v1.2.3 From 3a7dde7fcd0dd50df33e0e7070d4947551d767fc Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 18 Jul 2009 12:20:04 -0300 Subject: i7core: add socket info at the debug msg Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index bf0374062e3d..5695413c2879 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1467,9 +1467,9 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, /* FIXME: should convert addr into bank and rank information */ msg = kasprintf(GFP_ATOMIC, - "%s (addr = 0x%08llx, Dimm=%d, Channel=%d, " + "%s (addr = 0x%08llx, socket=%d, Dimm=%d, Channel=%d, " "syndrome=0x%08x, count=%d, Err=%08llx:%08llx (%s: %s))\n", - type, (long long) m->addr, dimm, channel, + type, (long long) m->addr, m->cpu, dimm, channel, syndrome, core_err_cnt, (long long)m->status, (long long)m->misc, optype, err); -- cgit v1.2.3 From 086271a0374bf0b9ce033aac9fb60530c421ad65 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 18 Jul 2009 12:22:28 -0300 Subject: i7core: remove some uneeded noisy debug messages Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 5695413c2879..fd00e0299ca1 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1494,8 +1494,6 @@ static void i7core_check_error(struct mem_ctl_info *mci) struct mce *m = NULL; unsigned long flags; - debugf0(__FILE__ ": %s()\n", __func__); - /* Copy all mce errors into a temporary buffer */ spin_lock_irqsave(&pvt->mce_lock, flags); if (pvt->mce_count) { @@ -1531,8 +1529,6 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) struct i7core_pvt *pvt = mci->pvt_info; unsigned long flags; - debugf0(__FILE__ ": %s()\n", __func__); - /* * Just let mcelog handle it if the error is * outside the memory controller -- cgit v1.2.3 From 17cb7b0cf78c14913c5410eff2ce03e1d9c8d958 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 20 Jul 2009 18:48:18 -0300 Subject: i7core_edac: Some cleanups at displayed info Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index fd00e0299ca1..86af14840b88 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -453,8 +453,8 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) pci_read_config_dword(pdev, MC_MAX_DOD, &pvt->info.max_dod); pci_read_config_dword(pdev, MC_CHANNEL_MAPPER, &pvt->info.ch_map); - debugf0("MC control=0x%08x status=0x%08x dod=0x%08x map=0x%08x\n", - pvt->info.mc_control, pvt->info.mc_status, + debugf0("QPI %d control=0x%08x status=0x%08x dod=0x%08x map=0x%08x\n", + socket, pvt->info.mc_control, pvt->info.mc_status, pvt->info.max_dod, pvt->info.ch_map); if (ECC_ENABLED(pvt)) { @@ -469,16 +469,14 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) } /* FIXME: need to handle the error codes */ - debugf0("DOD Max limits: DIMMS: %d, %d-ranked, %d-banked\n", + debugf0("DOD Max limits: DIMMS: %d, %d-ranked, %d-banked " + "x%x x 0x%x\n", numdimms(pvt->info.max_dod), numrank(pvt->info.max_dod >> 2), numbank(pvt->info.max_dod >> 4)); - debugf0("DOD Max rows x colums = 0x%x x 0x%x\n", numrow(pvt->info.max_dod >> 6), numcol(pvt->info.max_dod >> 9)); - debugf0("Memory channel configuration:\n"); - for (i = 0; i < NUM_CHANS; i++) { u32 data, dimm_dod[3], value[8]; @@ -544,10 +542,9 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) pvt->channel[socket][i].dimms++; - debugf0("\tdimm %d (0x%08x) %d Mb offset: %x, " - "numbank: %d,\n\t\t" - "numrank: %d, numrow: %#x, numcol: %#x\n", - j, dimm_dod[j], size, + debugf0("\tdimm %d %d Mb offset: %x, " + "bank: %d, rank: %d, row: %#x, col: %#x\n", + j, size, RANKOFFSET(dimm_dod[j]), banks, ranks, rows, cols); @@ -599,9 +596,9 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) pci_read_config_dword(pdev, MC_SAG_CH_5, &value[5]); pci_read_config_dword(pdev, MC_SAG_CH_6, &value[6]); pci_read_config_dword(pdev, MC_SAG_CH_7, &value[7]); - debugf0("\t[%i] DIVBY3\tREMOVED\tOFFSET\n", i); + debugf1("\t[%i] DIVBY3\tREMOVED\tOFFSET\n", i); for (j = 0; j < 8; j++) - debugf0("\t\t%#x\t%#x\t%#x\n", + debugf1("\t\t%#x\t%#x\t%#x\n", (value[j] >> 27) & 0x1, (value[j] >> 24) & 0x7, (value[j] && ((1 << 24) - 1))); -- cgit v1.2.3 From 276b824c3095b09e8cb76f5709f56e9c6818ae85 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 22 Jul 2009 21:45:50 -0300 Subject: i7core_edac: some fixes at error injection code Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 104 ++++++++++++++++++++++----------------------- 1 file changed, 51 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 86af14840b88..72859e87aeb2 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -32,9 +32,6 @@ #include "edac_core.h" -/* To use the new pci_[read/write]_config_qword instead of two dword */ -#define USE_QWORD 0 - /* * Alter this version for the module when modifications are made */ @@ -473,7 +470,7 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) "x%x x 0x%x\n", numdimms(pvt->info.max_dod), numrank(pvt->info.max_dod >> 2), - numbank(pvt->info.max_dod >> 4)); + numbank(pvt->info.max_dod >> 4), numrow(pvt->info.max_dod >> 6), numcol(pvt->info.max_dod >> 9)); @@ -646,7 +643,7 @@ static ssize_t i7core_inject_socket_store(struct mem_ctl_info *mci, int rc; rc = strict_strtoul(data, 10, &value); - if ((rc < 0) || (value > pvt->sockets)) + if ((rc < 0) || (value >= pvt->sockets)) return 0; pvt->inject.section = (u32) value; @@ -803,7 +800,7 @@ static ssize_t i7core_inject_addrmatch_store(struct mem_ctl_info *mci, else return cmd - data; } else if (!strcasecmp(cmd, "dimm")) { - if (value < 4) + if (value < 3) pvt->inject.dimm = value; else return cmd - data; @@ -813,7 +810,7 @@ static ssize_t i7core_inject_addrmatch_store(struct mem_ctl_info *mci, else return cmd - data; } else if (!strcasecmp(cmd, "bank")) { - if (value < 4) + if (value < 32) pvt->inject.bank = value; else return cmd - data; @@ -870,6 +867,28 @@ static ssize_t i7core_inject_addrmatch_show(struct mem_ctl_info *mci, channel, dimm, bank, rank, page, col); } +static int write_and_test(struct pci_dev *dev, int where, u32 val) +{ + u32 read; + int count; + + for (count = 0; count < 10; count++) { + if (count) + msleep (100); + pci_write_config_dword(dev, where, val); + pci_read_config_dword(dev, where, &read); + + if (read == val) + return 0; + } + + debugf0("Error Injection Register 0x%02x: Tried to write 0x%08x, " + "but read: 0x%08x\n", where, val, read); + + return -EINVAL; +} + + /* * This routine prepares the Memory Controller for error injection. * The error will be injected when some process tries to write to the @@ -949,70 +968,49 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, else mask |= (pvt->inject.col & 0x3fffL); - /* Unlock writes to registers */ + /* + * bit 0: REPEAT_EN + * bits 1-2: MASK_HALF_CACHELINE + * bit 3: INJECT_ECC + * bit 4: INJECT_ADDR_PARITY + */ + + injectmask = (pvt->inject.type & 1) | + (pvt->inject.section & 0x3) << 1 | + (pvt->inject.type & 0x6) << (3 - 1); + + /* Unlock writes to registers - this register is write only */ pci_write_config_dword(pvt->pci_noncore[pvt->inject.socket], MC_CFG_CONTROL, 0x2); - msleep(100); +#if 0 /* Zeroes error count registers */ pci_write_config_dword(pvt->pci_mcr[pvt->inject.socket][4], MC_TEST_ERR_RCV1, 0); pci_write_config_dword(pvt->pci_mcr[pvt->inject.socket][4], MC_TEST_ERR_RCV0, 0); pvt->ce_count_available[pvt->inject.socket] = 0; +#endif - -#if USE_QWORD - pci_write_config_qword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], + write_and_test(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], MC_CHANNEL_ADDR_MATCH, mask); -#else - pci_write_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], - MC_CHANNEL_ADDR_MATCH, mask); - pci_write_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], + write_and_test(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], MC_CHANNEL_ADDR_MATCH + 4, mask >> 32L); -#endif -#if 1 -#if USE_QWORD - u64 rdmask; - pci_read_config_qword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], - MC_CHANNEL_ADDR_MATCH, &rdmask); - debugf0("Inject addr match write 0x%016llx, read: 0x%016llx\n", - mask, rdmask); -#else - u32 rdmask1, rdmask2; - - pci_read_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], - MC_CHANNEL_ADDR_MATCH, &rdmask1); - pci_read_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], - MC_CHANNEL_ADDR_MATCH + 4, &rdmask2); - - debugf0("Inject addr match write 0x%016llx, read: 0x%08x 0x%08x\n", - mask, rdmask1, rdmask2); -#endif -#endif - - pci_write_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], + write_and_test(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], MC_CHANNEL_ERROR_MASK, pvt->inject.eccmask); + write_and_test(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], + MC_CHANNEL_ERROR_MASK, injectmask); + /* - * bit 0: REPEAT_EN - * bits 1-2: MASK_HALF_CACHELINE - * bit 3: INJECT_ECC - * bit 4: INJECT_ADDR_PARITY + * This is something undocumented, based on my tests + * Without writing 8 to this register, errors aren't injected. Not sure + * why. */ + pci_write_config_dword(pvt->pci_noncore[pvt->inject.socket], + MC_CFG_CONTROL, 8); - injectmask = (pvt->inject.type & 1) | - (pvt->inject.section & 0x3) << 1 | - (pvt->inject.type & 0x6) << (3 - 1); - - pci_write_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], - MC_CHANNEL_ERROR_MASK, injectmask); - -#if 0 - /* lock writes to registers */ - pci_write_config_dword(pvt->pci_noncore, MC_CFG_CONTROL, 0); -#endif debugf0("Error inject addr match 0x%016llx, ecc 0x%08x," " inject 0x%08x\n", mask, pvt->inject.eccmask, injectmask); -- cgit v1.2.3 From 2068def56c09f2b24e6de04a1b84757a0fb07947 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 5 Aug 2009 19:28:27 -0300 Subject: i7core_edac: fix error codes for sysfs error injection interface Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 72859e87aeb2..ab9d26ec19d7 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -644,7 +644,7 @@ static ssize_t i7core_inject_socket_store(struct mem_ctl_info *mci, rc = strict_strtoul(data, 10, &value); if ((rc < 0) || (value >= pvt->sockets)) - return 0; + return -EIO; pvt->inject.section = (u32) value; return count; @@ -676,7 +676,7 @@ static ssize_t i7core_inject_section_store(struct mem_ctl_info *mci, rc = strict_strtoul(data, 10, &value); if ((rc < 0) || (value > 3)) - return 0; + return -EIO; pvt->inject.section = (u32) value; return count; @@ -709,7 +709,7 @@ static ssize_t i7core_inject_type_store(struct mem_ctl_info *mci, rc = strict_strtoul(data, 10, &value); if ((rc < 0) || (value > 7)) - return 0; + return -EIO; pvt->inject.type = (u32) value; return count; @@ -744,7 +744,7 @@ static ssize_t i7core_inject_eccmask_store(struct mem_ctl_info *mci, rc = strict_strtoul(data, 10, &value); if (rc < 0) - return 0; + return -EIO; pvt->inject.eccmask = (u32) value; return count; -- cgit v1.2.3 From 4157d9f55435331deef01ba8a9a47f248c042fb2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 5 Aug 2009 20:27:15 -0300 Subject: i7core_edac: fix error injection There were two stupid error injection bugs introduced by wrong cut-and-paste: one at socket store, and another at the error inject register. The last one were causing the code to not work at all. While here, adds debug messages to allow seeing what registers are being set while sending error injection. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index ab9d26ec19d7..f16aac253654 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -625,7 +625,7 @@ static int disable_inject(struct mem_ctl_info *mci) return -ENODEV; pci_write_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], - MC_CHANNEL_ERROR_MASK, 0); + MC_CHANNEL_ERROR_INJECT, 0); return 0; } @@ -646,7 +646,7 @@ static ssize_t i7core_inject_socket_store(struct mem_ctl_info *mci, if ((rc < 0) || (value >= pvt->sockets)) return -EIO; - pvt->inject.section = (u32) value; + pvt->inject.socket = (u32) value; return count; } @@ -872,6 +872,10 @@ static int write_and_test(struct pci_dev *dev, int where, u32 val) u32 read; int count; + debugf0("setting pci %02x:%02x.%x reg=%02x value=%08x\n", + dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), + where, val); + for (count = 0; count < 10; count++) { if (count) msleep (100); @@ -882,8 +886,10 @@ static int write_and_test(struct pci_dev *dev, int where, u32 val) return 0; } - debugf0("Error Injection Register 0x%02x: Tried to write 0x%08x, " - "but read: 0x%08x\n", where, val, read); + i7core_printk(KERN_ERR, "Error during set pci %02x:%02x.%x reg=%02x " + "write=%08x. Read=%08x\n", + dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), + where, val, read); return -EINVAL; } @@ -983,15 +989,6 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, pci_write_config_dword(pvt->pci_noncore[pvt->inject.socket], MC_CFG_CONTROL, 0x2); -#if 0 - /* Zeroes error count registers */ - pci_write_config_dword(pvt->pci_mcr[pvt->inject.socket][4], - MC_TEST_ERR_RCV1, 0); - pci_write_config_dword(pvt->pci_mcr[pvt->inject.socket][4], - MC_TEST_ERR_RCV0, 0); - pvt->ce_count_available[pvt->inject.socket] = 0; -#endif - write_and_test(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], MC_CHANNEL_ADDR_MATCH, mask); write_and_test(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], @@ -1001,7 +998,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, MC_CHANNEL_ERROR_MASK, pvt->inject.eccmask); write_and_test(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], - MC_CHANNEL_ERROR_MASK, injectmask); + MC_CHANNEL_ERROR_INJECT, injectmask); /* * This is something undocumented, based on my tests @@ -1026,7 +1023,7 @@ static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci, u32 injectmask; pci_read_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], - MC_CHANNEL_ERROR_MASK, &injectmask); + MC_CHANNEL_ERROR_INJECT, &injectmask); debugf0("Inject error read: 0x%018x\n", injectmask); -- cgit v1.2.3 From b990538a78ea84e89551ccaddf182beb5e16e6d2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 5 Aug 2009 21:36:35 -0300 Subject: i7core_edac: CodingSyle fixes/cleanups No functional changes. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 50 +++++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index f16aac253654..86037a601b54 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -38,10 +38,6 @@ #define I7CORE_REVISION " Ver: 1.0.0 " __DATE__ #define EDAC_MOD_STR "i7core_edac" -/* HACK: temporary, just to enable all logs, for now */ -#undef debugf0 -#define debugf0(fmt, arg...) edac_printk(KERN_INFO, "i7core", fmt, ##arg) - /* * Debug macros */ @@ -105,6 +101,7 @@ #define REPEAT_EN 0x01 /* OFFSETS for Devices 4,5 and 6 Function 1 */ + #define MC_DOD_CH_DIMM0 0x48 #define MC_DOD_CH_DIMM1 0x4c #define MC_DOD_CH_DIMM2 0x50 @@ -227,7 +224,7 @@ struct pci_id_descr pci_devs[] = { /* Memory controller */ { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_I7_MCR) }, { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_I7_MC_TAD) }, - { PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_I7_MC_RAS) }, /* if RDIMM is supported */ + { PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_I7_MC_RAS) }, /* if RDIMM */ { PCI_DESCR(3, 4, PCI_DEVICE_ID_INTEL_I7_MC_TEST) }, /* Channel 0 */ @@ -878,7 +875,7 @@ static int write_and_test(struct pci_dev *dev, int where, u32 val) for (count = 0; count < 10; count++) { if (count) - msleep (100); + msleep(100); pci_write_config_dword(dev, where, val); pci_read_config_dword(dev, where, &read); @@ -894,7 +891,6 @@ static int write_and_test(struct pci_dev *dev, int where, u32 val) return -EINVAL; } - /* * This routine prepares the Memory Controller for error injection. * The error will be injected when some process tries to write to the @@ -1326,7 +1322,7 @@ static void check_mc_test_err(struct mem_ctl_info *mci, u8 socket) int new0, new1, new2; if (!pvt->pci_mcr[socket][4]) { - debugf0("%s MCR registers not found\n",__func__); + debugf0("%s MCR registers not found\n", __func__); return; } @@ -1405,24 +1401,24 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, type = "NON_FATAL"; switch (optypenum) { - case 0: - optype = "generic undef request"; - break; - case 1: - optype = "read error"; - break; - case 2: - optype = "write error"; - break; - case 3: - optype = "addr/cmd error"; - break; - case 4: - optype = "scrubbing error"; - break; - default: - optype = "reserved"; - break; + case 0: + optype = "generic undef request"; + break; + case 1: + optype = "read error"; + break; + case 2: + optype = "write error"; + break; + case 3: + optype = "addr/cmd error"; + break; + case 4: + optype = "scrubbing error"; + break; + default: + optype = "reserved"; + break; } switch (errnum) { @@ -1672,7 +1668,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, spin_lock_init(&pvt->mce_lock); rc = edac_mce_register(&pvt->edac_mce); - if (unlikely (rc < 0)) { + if (unlikely(rc < 0)) { debugf0("MC: " __FILE__ ": %s(): failed edac_mce_register()\n", __func__); goto fail1; -- cgit v1.2.3 From 3ef288a98307adc9d3f83321b26281567f348ec6 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 2 Sep 2009 23:43:33 -0300 Subject: i7core_edac: Print an error message if pci register fails Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 86037a601b54..26205e2efecf 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1743,7 +1743,13 @@ static int __init i7core_init(void) pci_rc = pci_register_driver(&i7core_driver); - return (pci_rc < 0) ? pci_rc : 0; + if (pci_rc >= 0) + return 0; + + i7core_printk(KERN_ERR, "Failed to register device with error %d.\n", + pci_rc); + + return pci_rc; } /* -- cgit v1.2.3 From 61053fdedb2080dadc18dc37abbba90d2e74bc03 Mon Sep 17 00:00:00 2001 From: Keith Mannthey Date: Wed, 2 Sep 2009 23:46:59 -0300 Subject: i7core_edac: Fix ecc enable shift From: Keith Mannthey Simple correction to a shift value. ECC_ENABLED is bit 4 of MC_STATUS, Dev 3 Fun 0 Offset 0x4c This correctly identifies the state of the ECC at the machine. Signed-off-by: Keith Mannthey Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 26205e2efecf..87d5695f5fb0 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -286,7 +286,7 @@ static struct edac_pci_ctl_info *i7core_pci; #define ECCx8(pvt) ((pvt)->info.mc_control & (1 << 1)) /* MC_STATUS bits */ -#define ECC_ENABLED(pvt) ((pvt)->info.mc_status & (1 << 3)) +#define ECC_ENABLED(pvt) ((pvt)->info.mc_status & (1 << 4)) #define CH_DISABLED(pvt, ch) ((pvt)->info.mc_status & (1 << ch)) /* MC_MAX_DOD read functions */ -- cgit v1.2.3 From b4e8f0b6eaa1e99f1a64e539466a8ee2fb521d62 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 2 Sep 2009 23:49:59 -0300 Subject: i7core_edac: Use Device 3 function 2 to report errors with RDIMM's Nehalem and upper chipsets provide an special device that has corrected memory error counters detected with registered dimms. This device is only seen if there are registered memories plugged. After this patch, on a machine fully equiped with RDIMM's, it will use the Device 3 function 2 to count corrected errors instead on relying at mcelog. For unregistered DIMMs, it will keep the old behavior, counting errors via mcelog. This patch were developed together with Keith Mannthey Signed-off-by: Keith Mannthey Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 208 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 178 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 87d5695f5fb0..4758c208f39a 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -73,6 +73,18 @@ #define DIMM1_COR_ERR(r) (((r) >> 16) & 0x7fff) #define DIMM0_COR_ERR(r) ((r) & 0x7fff) +/* OFFSETS for Device 3 Function 2, as inicated on Xeon 5500 datasheet */ +#define MC_COR_ECC_CNT_0 0x80 +#define MC_COR_ECC_CNT_1 0x84 +#define MC_COR_ECC_CNT_2 0x88 +#define MC_COR_ECC_CNT_3 0x8c +#define MC_COR_ECC_CNT_4 0x90 +#define MC_COR_ECC_CNT_5 0x94 + +#define DIMM_TOP_COR_ERR(r) (((r) >> 16) & 0x7fff) +#define DIMM_BOT_COR_ERR(r) ((r) & 0x7fff) + + /* OFFSETS for Devices 4,5 and 6 Function 0 */ #define MC_CHANNEL_DIMM_INIT_PARAMS 0x58 @@ -194,13 +206,20 @@ struct i7core_pvt { struct i7core_inject inject; struct i7core_channel channel[NUM_SOCKETS][NUM_CHANS]; + unsigned int is_registered:1; /* true if all memories are RDIMMs */ + int sockets; /* Number of sockets */ int channels; /* Number of active channels */ int ce_count_available[NUM_SOCKETS]; - /* ECC corrected errors counts per dimm */ - unsigned long ce_count[NUM_SOCKETS][MAX_DIMMS]; - int last_ce_count[NUM_SOCKETS][MAX_DIMMS]; + int csrow_map[NUM_SOCKETS][NUM_CHANS][MAX_DIMMS]; + + /* ECC corrected errors counts per udimm */ + unsigned long udimm_ce_count[NUM_SOCKETS][MAX_DIMMS]; + int udimm_last_ce_count[NUM_SOCKETS][MAX_DIMMS]; + /* ECC corrected errors counts per rdimm */ + unsigned long rdimm_ce_count[NUM_SOCKETS][NUM_CHANS][MAX_DIMMS]; + int rdimm_last_ce_count[NUM_SOCKETS][NUM_CHANS][MAX_DIMMS]; /* mcelog glue */ struct edac_mce edac_mce; @@ -471,6 +490,8 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) numrow(pvt->info.max_dod >> 6), numcol(pvt->info.max_dod >> 9)); + pvt->is_registered = 1; + for (i = 0; i < NUM_CHANS; i++) { u32 data, dimm_dod[3], value[8]; @@ -492,8 +513,14 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) if (data & REGISTERED_DIMM) mtype = MEM_RDDR3; - else + else { mtype = MEM_DDR3; + /* + * FIXME: Currently, the driver will use dev 3:2 + * counter registers only if all memories are registered + */ + pvt->is_registered = 0; + } #if 0 if (data & THREE_DIMMS_PRESENT) pvt->channel[i].dimms = 3; @@ -562,6 +589,8 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) csr->channels[0].chan_idx = i; csr->channels[0].ce_count = 0; + pvt->csrow_map[socket][i][j] = *csrow; + switch (banks) { case 4: csr->dtype = DEV_X4; @@ -1031,19 +1060,31 @@ static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci, static ssize_t i7core_ce_regs_show(struct mem_ctl_info *mci, char *data) { - unsigned i, count, total = 0; + unsigned i, j, count, total = 0; struct i7core_pvt *pvt = mci->pvt_info; for (i = 0; i < pvt->sockets; i++) { - if (!pvt->ce_count_available[i]) + if (!pvt->ce_count_available[i]) { count = sprintf(data, "socket 0 data unavailable\n"); - else + continue; + } + if (!pvt->is_registered) count = sprintf(data, "socket %d, dimm0: %lu\n" "dimm1: %lu\ndimm2: %lu\n", i, - pvt->ce_count[i][0], - pvt->ce_count[i][1], - pvt->ce_count[i][2]); + pvt->udimm_ce_count[i][0], + pvt->udimm_ce_count[i][1], + pvt->udimm_ce_count[i][2]); + else + for (j = 0; j < NUM_CHANS; j++) { + count = sprintf(data, "socket %d, channel %d" + "dimm0: %lu\n" + "dimm1: %lu\ndimm2: %lu\n", + i, j, + pvt->rdimm_ce_count[i][j][0], + pvt->rdimm_ce_count[i][j][1], + pvt->rdimm_ce_count[i][j][2]); + } data += count; total += count; } @@ -1308,6 +1349,103 @@ error: /**************************************************************************** Error check routines ****************************************************************************/ +static void i7core_rdimm_update_csrow(struct mem_ctl_info *mci, int socket, + int chan, int dimm, int add) +{ + char *msg; + struct i7core_pvt *pvt = mci->pvt_info; + int row = pvt->csrow_map[socket][chan][dimm], i; + + for (i = 0; i < add; i++) { + msg = kasprintf(GFP_KERNEL, "Corrected error " + "(Socket=%d channel=%d dimm=%d", + socket, chan, dimm); + + edac_mc_handle_fbd_ce(mci, row, 0, msg); + kfree (msg); + } +} + +static void i7core_rdimm_update_ce_count(struct mem_ctl_info *mci, + int socket, int chan, int new0, int new1, int new2) +{ + struct i7core_pvt *pvt = mci->pvt_info; + int add0 = 0, add1 = 0, add2 = 0; + /* Updates CE counters if it is not the first time here */ + if (pvt->ce_count_available[socket]) { + /* Updates CE counters */ + + add2 = new2 - pvt->rdimm_last_ce_count[socket][chan][2]; + add1 = new1 - pvt->rdimm_last_ce_count[socket][chan][1]; + add0 = new0 - pvt->rdimm_last_ce_count[socket][chan][0]; + + if (add2 < 0) + add2 += 0x7fff; + pvt->rdimm_ce_count[socket][chan][2] += add2; + + if (add1 < 0) + add1 += 0x7fff; + pvt->rdimm_ce_count[socket][chan][1] += add1; + + if (add0 < 0) + add0 += 0x7fff; + pvt->rdimm_ce_count[socket][chan][0] += add0; + } else + pvt->ce_count_available[socket] = 1; + + /* Store the new values */ + pvt->rdimm_last_ce_count[socket][chan][2] = new2; + pvt->rdimm_last_ce_count[socket][chan][1] = new1; + pvt->rdimm_last_ce_count[socket][chan][0] = new0; + + /*updated the edac core */ + if (add0 != 0) + i7core_rdimm_update_csrow(mci, socket, chan, 0, add0); + if (add1 != 0) + i7core_rdimm_update_csrow(mci, socket, chan, 1, add1); + if (add2 != 0) + i7core_rdimm_update_csrow(mci, socket, chan, 2, add2); + +} + +static void i7core_rdimm_check_mc_ecc_err(struct mem_ctl_info *mci, u8 socket) +{ + struct i7core_pvt *pvt = mci->pvt_info; + u32 rcv[3][2]; + int i, new0, new1, new2; + + /*Read DEV 3: FUN 2: MC_COR_ECC_CNT regs directly*/ + pci_read_config_dword(pvt->pci_mcr[socket][2], MC_COR_ECC_CNT_0, + &rcv[0][0]); + pci_read_config_dword(pvt->pci_mcr[socket][2], MC_COR_ECC_CNT_1, + &rcv[0][1]); + pci_read_config_dword(pvt->pci_mcr[socket][2], MC_COR_ECC_CNT_2, + &rcv[1][0]); + pci_read_config_dword(pvt->pci_mcr[socket][2], MC_COR_ECC_CNT_3, + &rcv[1][1]); + pci_read_config_dword(pvt->pci_mcr[socket][2], MC_COR_ECC_CNT_4, + &rcv[2][0]); + pci_read_config_dword(pvt->pci_mcr[socket][2], MC_COR_ECC_CNT_5, + &rcv[2][1]); + for (i = 0 ; i < 3; i++) { + debugf3("MC_COR_ECC_CNT%d = 0x%x; MC_COR_ECC_CNT%d = 0x%x\n", + (i * 2), rcv[i][0], (i * 2) + 1, rcv[i][1]); + /*if the channel has 3 dimms*/ + if (pvt->channel[socket][i].dimms > 2) { + new0 = DIMM_BOT_COR_ERR(rcv[i][0]); + new1 = DIMM_TOP_COR_ERR(rcv[i][0]); + new2 = DIMM_BOT_COR_ERR(rcv[i][1]); + } else { + new0 = DIMM_TOP_COR_ERR(rcv[i][0]) + + DIMM_BOT_COR_ERR(rcv[i][0]); + new1 = DIMM_TOP_COR_ERR(rcv[i][1]) + + DIMM_BOT_COR_ERR(rcv[i][1]); + new2 = 0; + } + + i7core_rdimm_update_ce_count(mci, socket, i, new0, new1, new2); + } +} /* This function is based on the device 3 function 4 registers as described on: * Intel Xeon Processor 5500 Series Datasheet Volume 2 @@ -1315,7 +1453,7 @@ error: * also available at: * http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf */ -static void check_mc_test_err(struct mem_ctl_info *mci, u8 socket) +static void i7core_udimm_check_mc_ecc_err(struct mem_ctl_info *mci, u8 socket) { struct i7core_pvt *pvt = mci->pvt_info; u32 rcv1, rcv0; @@ -1326,7 +1464,7 @@ static void check_mc_test_err(struct mem_ctl_info *mci, u8 socket) return; } - /* Corrected error reads */ + /* Corrected test errors */ pci_read_config_dword(pvt->pci_mcr[socket][4], MC_TEST_ERR_RCV1, &rcv1); pci_read_config_dword(pvt->pci_mcr[socket][4], MC_TEST_ERR_RCV0, &rcv0); @@ -1335,39 +1473,38 @@ static void check_mc_test_err(struct mem_ctl_info *mci, u8 socket) new1 = DIMM1_COR_ERR(rcv0); new0 = DIMM0_COR_ERR(rcv0); -#if 0 - debugf2("%s CE rcv1=0x%08x rcv0=0x%08x, %d %d %d\n", - (pvt->ce_count_available ? "UPDATE" : "READ"), - rcv1, rcv0, new0, new1, new2); -#endif - /* Updates CE counters if it is not the first time here */ if (pvt->ce_count_available[socket]) { /* Updates CE counters */ int add0, add1, add2; - add2 = new2 - pvt->last_ce_count[socket][2]; - add1 = new1 - pvt->last_ce_count[socket][1]; - add0 = new0 - pvt->last_ce_count[socket][0]; + add2 = new2 - pvt->udimm_last_ce_count[socket][2]; + add1 = new1 - pvt->udimm_last_ce_count[socket][1]; + add0 = new0 - pvt->udimm_last_ce_count[socket][0]; if (add2 < 0) add2 += 0x7fff; - pvt->ce_count[socket][2] += add2; + pvt->udimm_ce_count[socket][2] += add2; if (add1 < 0) add1 += 0x7fff; - pvt->ce_count[socket][1] += add1; + pvt->udimm_ce_count[socket][1] += add1; if (add0 < 0) add0 += 0x7fff; - pvt->ce_count[socket][0] += add0; + pvt->udimm_ce_count[socket][0] += add0; + + if (add0 | add1 | add2) + i7core_printk(KERN_ERR, "New Corrected error(s): " + "dimm0: +%d, dimm1: +%d, dimm2 +%d\n", + add0, add1, add2); } else pvt->ce_count_available[socket] = 1; /* Store the new values */ - pvt->last_ce_count[socket][2] = new2; - pvt->last_ce_count[socket][1] = new1; - pvt->last_ce_count[socket][0] = new0; + pvt->udimm_last_ce_count[socket][2] = new2; + pvt->udimm_last_ce_count[socket][1] = new1; + pvt->udimm_last_ce_count[socket][0] = new0; } /* @@ -1386,6 +1523,7 @@ static void check_mc_test_err(struct mem_ctl_info *mci, u8 socket) static void i7core_mce_output_error(struct mem_ctl_info *mci, struct mce *m) { + struct i7core_pvt *pvt = mci->pvt_info; char *type, *optype, *err, *msg; unsigned long error = m->status & 0x1ff0000l; u32 optypenum = (m->status >> 4) & 0x07; @@ -1394,6 +1532,7 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, u32 channel = (m->misc >> 18) & 0x3; u32 syndrome = m->misc >> 32; u32 errnum = find_first_bit(&error, 32); + int csrow; if (m->mcgstatus & 1) type = "FATAL"; @@ -1463,9 +1602,15 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, debugf0("%s", msg); + csrow = pvt->csrow_map[m->cpu][channel][dimm]; + /* Call the helper to output message */ - edac_mc_handle_fbd_ue(mci, 0 /* FIXME: should be rank here */, - 0, 0 /* FIXME: should be channel here */, msg); + if (m->mcgstatus & 1) + edac_mc_handle_fbd_ue(mci, csrow, 0, + 0 /* FIXME: should be channel here */, msg); + else if (!pvt->is_registered) + edac_mc_handle_fbd_ce(mci, csrow, + 0 /* FIXME: should be channel here */, msg); kfree(msg); } @@ -1502,7 +1647,10 @@ static void i7core_check_error(struct mem_ctl_info *mci) /* check memory count errors */ for (i = 0; i < pvt->sockets; i++) - check_mc_test_err(mci, i); + if (!pvt->is_registered) + i7core_udimm_check_mc_ecc_err(mci, i); + else + i7core_rdimm_check_mc_ecc_err(mci, i); } /* -- cgit v1.2.3 From 14d2c08343eecd13f6c6ec232c98b16762b97924 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 2 Sep 2009 23:52:36 -0300 Subject: i7core: Use registered memories per processor Instead of assuming that the entire machine has either registered or unregistered memories, do it at CPU socket based. While here, fix a bug at i7core_mce_output_error(), where the we're using m->cpu directly as if it would represent a socket. Instead, the proper socket_id is given by cpu_data[m->cpu].phys_proc_id. Signed-off-by: Mauro Carvalho Chehab --- --- drivers/edac/i7core_edac.c | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 4758c208f39a..9f4e9d7d4dbf 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "edac_core.h" @@ -206,8 +207,6 @@ struct i7core_pvt { struct i7core_inject inject; struct i7core_channel channel[NUM_SOCKETS][NUM_CHANS]; - unsigned int is_registered:1; /* true if all memories are RDIMMs */ - int sockets; /* Number of sockets */ int channels; /* Number of active channels */ @@ -221,6 +220,8 @@ struct i7core_pvt { unsigned long rdimm_ce_count[NUM_SOCKETS][NUM_CHANS][MAX_DIMMS]; int rdimm_last_ce_count[NUM_SOCKETS][NUM_CHANS][MAX_DIMMS]; + unsigned int is_registered[NUM_SOCKETS]; + /* mcelog glue */ struct edac_mce edac_mce; struct mce mce_entry[MCE_LOG_LEN]; @@ -490,8 +491,6 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) numrow(pvt->info.max_dod >> 6), numcol(pvt->info.max_dod >> 9)); - pvt->is_registered = 1; - for (i = 0; i < NUM_CHANS; i++) { u32 data, dimm_dod[3], value[8]; @@ -513,14 +512,8 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) if (data & REGISTERED_DIMM) mtype = MEM_RDDR3; - else { + else mtype = MEM_DDR3; - /* - * FIXME: Currently, the driver will use dev 3:2 - * counter registers only if all memories are registered - */ - pvt->is_registered = 0; - } #if 0 if (data & THREE_DIMMS_PRESENT) pvt->channel[i].dimms = 3; @@ -1068,7 +1061,7 @@ static ssize_t i7core_ce_regs_show(struct mem_ctl_info *mci, char *data) count = sprintf(data, "socket 0 data unavailable\n"); continue; } - if (!pvt->is_registered) + if (!pvt->is_registered[i]) count = sprintf(data, "socket %d, dimm0: %lu\n" "dimm1: %lu\ndimm2: %lu\n", i, @@ -1310,7 +1303,9 @@ static int mci_bind_devs(struct mem_ctl_info *mci) struct pci_dev *pdev; int i, j, func, slot; + for (i = 0; i < pvt->sockets; i++) { + pvt->is_registered[i] = 0; for (j = 0; j < N_DEVS; j++) { pdev = pci_devs[j].pdev[i]; if (!pdev) @@ -1334,6 +1329,10 @@ static int mci_bind_devs(struct mem_ctl_info *mci) debugf0("Associated fn %d.%d, dev = %p, socket %d\n", PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), pdev, i); + + if (PCI_SLOT(pdev->devfn) == 3 && + PCI_FUNC(pdev->devfn) == 2) + pvt->is_registered[i] = 1; } } @@ -1533,6 +1532,11 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, u32 syndrome = m->misc >> 32; u32 errnum = find_first_bit(&error, 32); int csrow; +#ifdef CONFIG_SMP + u32 socket_id = cpu_data[m->cpu].phys_proc_id; +#else + u32 socket_id = 0; +#endif if (m->mcgstatus & 1) type = "FATAL"; @@ -1596,19 +1600,22 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, msg = kasprintf(GFP_ATOMIC, "%s (addr = 0x%08llx, socket=%d, Dimm=%d, Channel=%d, " "syndrome=0x%08x, count=%d, Err=%08llx:%08llx (%s: %s))\n", - type, (long long) m->addr, m->cpu, dimm, channel, + type, (long long) m->addr, socket_id, dimm, channel, syndrome, core_err_cnt, (long long)m->status, (long long)m->misc, optype, err); debugf0("%s", msg); - csrow = pvt->csrow_map[m->cpu][channel][dimm]; + if (socket_id < NUM_SOCKETS) + csrow = pvt->csrow_map[socket_id][channel][dimm]; + else + csrow = -1; /* Call the helper to output message */ if (m->mcgstatus & 1) edac_mc_handle_fbd_ue(mci, csrow, 0, 0 /* FIXME: should be channel here */, msg); - else if (!pvt->is_registered) + else if (!pvt->is_registered[socket_id]) edac_mc_handle_fbd_ce(mci, csrow, 0 /* FIXME: should be channel here */, msg); @@ -1647,7 +1654,7 @@ static void i7core_check_error(struct mem_ctl_info *mci) /* check memory count errors */ for (i = 0; i < pvt->sockets; i++) - if (!pvt->is_registered) + if (!pvt->is_registered[i]) i7core_udimm_check_mc_ecc_err(mci, i); else i7core_rdimm_check_mc_ecc_err(mci, i); -- cgit v1.2.3 From bc2d7245ff1c5466c877a0c32a7ec9563187a032 Mon Sep 17 00:00:00 2001 From: Keith Mannthey Date: Thu, 3 Sep 2009 00:05:05 -0300 Subject: i7core_edac: Probe on Xeons eariler On the Xeon 55XX series cpus the pci deives are not exposed via acpi so we much explicitly probe them to make the usable as a Linux PCI device. This moves the detection of this state to before pci_register_driver is called. Its present position was not working on my systems, the driver would complain about not finding a specific device. This patch allows the driver to load on my systems. Signed-off-by: Keith Mannthey Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 9f4e9d7d4dbf..9fe7ec762e68 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1158,6 +1158,23 @@ static void i7core_put_devices(void) pci_dev_put(pci_devs[j].pdev[i]); } +static void i7core_xeon_pci_fixup(void) +{ + struct pci_dev *pdev = NULL; + int i; + /* + * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core pci buses + * aren't announced by acpi. So, we need to use a legacy scan probing + * to detect them + */ + pdev = pci_get_device(PCI_VENDOR_ID_INTEL, + pci_devs[0].dev_id, NULL); + if (unlikely(!pdev)) { + for (i = 0; i < NUM_SOCKETS; i ++) + pcibios_scan_specific_bus(255-i); + } +} + /* * i7core_get_devices Find and perform 'get' operation on the MCH's * device/functions we want to reference for this driver @@ -1173,19 +1190,6 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno) pdev = pci_get_device(PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id, *prev); - /* - * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core pci buses - * aren't announced by acpi. So, we need to use a legacy scan probing - * to detect them - */ - if (unlikely(!pdev && !devno && !prev)) { - pcibios_scan_specific_bus(254); - pcibios_scan_specific_bus(255); - - pdev = pci_get_device(PCI_VENDOR_ID_INTEL, - pci_devs[devno].dev_id, *prev); - } - /* * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core regs * is at addr 8086:2c40, instead of 8086:2c41. So, we need @@ -1896,6 +1900,8 @@ static int __init i7core_init(void) /* Ensure that the OPSTATE is set correctly for POLL or NMI */ opstate_init(); + i7core_xeon_pci_fixup(); + pci_rc = pci_register_driver(&i7core_driver); if (pci_rc >= 0) -- cgit v1.2.3 From 3a3bb4a647db4cb2468641df8da2ee9491784a9a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 3 Sep 2009 20:17:26 -0300 Subject: i7core_edac: Improve corrected_error_counts output for RDIMM Just cosmetics. instead of showing something like: socket 0, channel 2dimm0: 1 dimm1: 0 dimm2: 0 socket 1, channel 2dimm0: 0 dimm1: 0 dimm2: 0 Show: socket 0, channel 2 RDIMM0: 1 RDIMM1: 0 RDIMM2: 0 socket 0, channel 2 RDIMM0: 0 RDIMM1: 0 RDIMM2: 0 This is more synthetic and easier to parse. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 9fe7ec762e68..76f4e6d973af 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1070,9 +1070,9 @@ static ssize_t i7core_ce_regs_show(struct mem_ctl_info *mci, char *data) pvt->udimm_ce_count[i][2]); else for (j = 0; j < NUM_CHANS; j++) { - count = sprintf(data, "socket %d, channel %d" - "dimm0: %lu\n" - "dimm1: %lu\ndimm2: %lu\n", + count = sprintf(data, "socket %d, channel %d " + "RDIMM0: %lu " + "RDIMM1: %lu RDIMM2: %lu\n", i, j, pvt->rdimm_ce_count[i][j][0], pvt->rdimm_ce_count[i][j][1], -- cgit v1.2.3 From a55456f3446d19853af54b64b3840312f46b6ea5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 5 Sep 2009 00:47:21 -0300 Subject: i7core: temporary workaround to allow it to compile against 2.6.30 Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 76f4e6d973af..af222ffcfdfc 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1536,8 +1536,10 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, u32 syndrome = m->misc >> 32; u32 errnum = find_first_bit(&error, 32); int csrow; -#ifdef CONFIG_SMP - u32 socket_id = cpu_data[m->cpu].phys_proc_id; +/* FIXME */ +//#ifdef CONFIG_SMP +#if 0 + u32 socket_id = per_cpu(cpu_data, cpu).phys_proc_id; #else u32 socket_id = 0; #endif -- cgit v1.2.3 From 66607706cee7b6901aa0509198f075859c93ec6a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 5 Sep 2009 00:52:11 -0300 Subject: Dynamically allocate memory for PCI devices Instead of using a static table assuming always 2 CPU sockets, allocate space dynamically for Nehalem PCI devs. This patch is part of a series of patches that changes i7core_edac to allow more than 2 sockets and to properly report one memory controller per socket. --- drivers/edac/i7core_edac.c | 175 +++++++++++++++++++++++++++++---------------- 1 file changed, 114 insertions(+), 61 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index af222ffcfdfc..7bcb5993b501 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -192,10 +192,9 @@ struct i7core_channel { }; struct pci_id_descr { - int dev; - int func; - int dev_id; - struct pci_dev *pdev[NUM_SOCKETS]; + int dev; + int func; + int dev_id; }; struct i7core_pvt { @@ -229,6 +228,17 @@ struct i7core_pvt { spinlock_t mce_lock; }; +struct i7core_dev { + struct list_head list; + + int socket; + struct pci_dev **pdev; +}; + +/* Static vars */ +static LIST_HEAD(i7core_edac_list); +static DEFINE_MUTEX(i7core_edac_lock); + /* Device name and register DID (Device ID) */ struct i7core_dev_info { const char *ctl_name; /* name for this device */ @@ -240,7 +250,7 @@ struct i7core_dev_info { .func = (function), \ .dev_id = (device_id) -struct pci_id_descr pci_devs[] = { +struct pci_id_descr pci_dev_descr[] = { /* Memory controller */ { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_I7_MCR) }, { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_I7_MC_TAD) }, @@ -275,11 +285,10 @@ struct pci_id_descr pci_devs[] = { { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_I7_NOCORE) }, }; -#define N_DEVS ARRAY_SIZE(pci_devs) +#define N_DEVS ARRAY_SIZE(pci_dev_descr) /* * pci_device_id table for which devices we are looking for - * This should match the first device at pci_devs table */ static const struct pci_device_id i7core_pci_tbl[] __devinitdata = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_X58_HUB_MGMT)}, @@ -288,7 +297,7 @@ static const struct pci_device_id i7core_pci_tbl[] __devinitdata = { /* Table of devices attributes supported by this driver */ -static const struct i7core_dev_info i7core_devs[] = { +static const struct i7core_dev_info i7core_probe_devs[] = { { .ctl_name = "i7 Core", .fsb_mapping_errors = PCI_DEVICE_ID_INTEL_I7_MCR, @@ -347,21 +356,37 @@ static inline int numcol(u32 col) return cols[col & 0x3]; } +static struct i7core_dev *get_i7core_dev(int socket) +{ + struct i7core_dev *i7core_dev; + + list_for_each_entry(i7core_dev, &i7core_edac_list, list) { + if (i7core_dev->socket == socket) + return i7core_dev; + } + + return NULL; +} + /**************************************************************************** Memory check routines ****************************************************************************/ static struct pci_dev *get_pdev_slot_func(u8 socket, unsigned slot, unsigned func) { + struct i7core_dev *i7core_dev = get_i7core_dev(socket); int i; + if (!i7core_dev) + return NULL; + for (i = 0; i < N_DEVS; i++) { - if (!pci_devs[i].pdev[socket]) + if (!i7core_dev->pdev[i]) continue; - if (PCI_SLOT(pci_devs[i].pdev[socket]->devfn) == slot && - PCI_FUNC(pci_devs[i].pdev[socket]->devfn) == func) { - return pci_devs[i].pdev[socket]; + if (PCI_SLOT(i7core_dev->pdev[i]->devfn) == slot && + PCI_FUNC(i7core_dev->pdev[i]->devfn) == func) { + return i7core_dev->pdev[i]; } } @@ -1153,9 +1178,18 @@ static void i7core_put_devices(void) { int i, j; - for (i = 0; i < NUM_SOCKETS; i++) + for (i = 0; i < NUM_SOCKETS; i++) { + struct i7core_dev *i7core_dev = get_i7core_dev(i); + if (!i7core_dev) + continue; + for (j = 0; j < N_DEVS; j++) - pci_dev_put(pci_devs[j].pdev[i]); + pci_dev_put(i7core_dev->pdev[j]); + + list_del(&i7core_dev->list); + kfree(i7core_dev->pdev); + kfree(i7core_dev); + } } static void i7core_xeon_pci_fixup(void) @@ -1168,7 +1202,7 @@ static void i7core_xeon_pci_fixup(void) * to detect them */ pdev = pci_get_device(PCI_VENDOR_ID_INTEL, - pci_devs[0].dev_id, NULL); + pci_dev_descr[0].dev_id, NULL); if (unlikely(!pdev)) { for (i = 0; i < NUM_SOCKETS; i ++) pcibios_scan_specific_bus(255-i); @@ -1183,19 +1217,21 @@ static void i7core_xeon_pci_fixup(void) */ int i7core_get_onedevice(struct pci_dev **prev, int devno) { + struct i7core_dev *i7core_dev; + struct pci_dev *pdev = NULL; u8 bus = 0; u8 socket = 0; pdev = pci_get_device(PCI_VENDOR_ID_INTEL, - pci_devs[devno].dev_id, *prev); + pci_dev_descr[devno].dev_id, *prev); /* * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core regs * is at addr 8086:2c40, instead of 8086:2c41. So, we need * to probe for the alternate address in case of failure */ - if (pci_devs[devno].dev_id == PCI_DEVICE_ID_INTEL_I7_NOCORE && !pdev) + if (pci_dev_descr[devno].dev_id == PCI_DEVICE_ID_INTEL_I7_NOCORE && !pdev) pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_NOCORE_ALT, *prev); @@ -1209,15 +1245,15 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno) * Dev 3 function 2 only exists on chips with RDIMMs * so, it is ok to not found it */ - if ((pci_devs[devno].dev == 3) && (pci_devs[devno].func == 2)) { + if ((pci_dev_descr[devno].dev == 3) && (pci_dev_descr[devno].func == 2)) { *prev = pdev; return 0; } i7core_printk(KERN_ERR, "Device not found: dev %02x.%d PCI ID %04x:%04x\n", - pci_devs[devno].dev, pci_devs[devno].func, - PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id); + pci_dev_descr[devno].dev, pci_dev_descr[devno].func, + PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id); /* End of list, leave */ return -ENODEV; @@ -1229,37 +1265,40 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno) else socket = 255 - bus; - if (socket >= NUM_SOCKETS) { - i7core_printk(KERN_ERR, - "Unexpected socket for " - "dev %02x:%02x.%d PCI ID %04x:%04x\n", - bus, pci_devs[devno].dev, pci_devs[devno].func, - PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id); - pci_dev_put(pdev); - return -ENODEV; + i7core_dev = get_i7core_dev(socket); + if (!i7core_dev) { + i7core_dev = kzalloc(sizeof(*i7core_dev), GFP_KERNEL); + if (!i7core_dev) + return -ENOMEM; + i7core_dev->pdev = kzalloc(sizeof(*i7core_dev->pdev) * N_DEVS, + GFP_KERNEL); + if (!i7core_dev->pdev) + return -ENOMEM; + i7core_dev->socket = socket; + list_add_tail(&i7core_dev->list, &i7core_edac_list); } - if (pci_devs[devno].pdev[socket]) { + if (i7core_dev->pdev[devno]) { i7core_printk(KERN_ERR, "Duplicated device for " "dev %02x:%02x.%d PCI ID %04x:%04x\n", - bus, pci_devs[devno].dev, pci_devs[devno].func, - PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id); + bus, pci_dev_descr[devno].dev, pci_dev_descr[devno].func, + PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id); pci_dev_put(pdev); return -ENODEV; } - pci_devs[devno].pdev[socket] = pdev; + i7core_dev->pdev[devno] = pdev; /* Sanity check */ - if (unlikely(PCI_SLOT(pdev->devfn) != pci_devs[devno].dev || - PCI_FUNC(pdev->devfn) != pci_devs[devno].func)) { + if (unlikely(PCI_SLOT(pdev->devfn) != pci_dev_descr[devno].dev || + PCI_FUNC(pdev->devfn) != pci_dev_descr[devno].func)) { i7core_printk(KERN_ERR, "Device PCI ID %04x:%04x " "has dev %02x:%02x.%d instead of dev %02x:%02x.%d\n", - PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id, + PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id, bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), - bus, pci_devs[devno].dev, pci_devs[devno].func); + bus, pci_dev_descr[devno].dev, pci_dev_descr[devno].func); return -ENODEV; } @@ -1268,27 +1307,29 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno) i7core_printk(KERN_ERR, "Couldn't enable " "dev %02x:%02x.%d PCI ID %04x:%04x\n", - bus, pci_devs[devno].dev, pci_devs[devno].func, - PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id); + bus, pci_dev_descr[devno].dev, pci_dev_descr[devno].func, + PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id); return -ENODEV; } i7core_printk(KERN_INFO, "Registered socket %d " "dev %02x:%02x.%d PCI ID %04x:%04x\n", - socket, bus, pci_devs[devno].dev, pci_devs[devno].func, - PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id); + socket, bus, pci_dev_descr[devno].dev, pci_dev_descr[devno].func, + PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id); *prev = pdev; return 0; } -static int i7core_get_devices(void) +static int i7core_get_devices(u8 *sockets) { int i; struct pci_dev *pdev = NULL; + struct i7core_dev *i7core_dev = NULL; + *sockets = 0; for (i = 0; i < N_DEVS; i++) { pdev = NULL; do { @@ -1298,6 +1339,12 @@ static int i7core_get_devices(void) } } while (pdev); } + + list_for_each_entry(i7core_dev, &i7core_edac_list, list) { + if (i7core_dev->socket + 1 > *sockets) + *sockets = i7core_dev->socket + 1; + } + return 0; } @@ -1307,11 +1354,15 @@ static int mci_bind_devs(struct mem_ctl_info *mci) struct pci_dev *pdev; int i, j, func, slot; - for (i = 0; i < pvt->sockets; i++) { + struct i7core_dev *i7core_dev = get_i7core_dev(i); + + if (!i7core_dev) + continue; + pvt->is_registered[i] = 0; for (j = 0; j < N_DEVS; j++) { - pdev = pci_devs[j].pdev[i]; + pdev = i7core_dev->pdev[j]; if (!pdev) continue; @@ -1723,20 +1774,17 @@ static int __devinit i7core_probe(struct pci_dev *pdev, int rc, i; u8 sockets; - if (unlikely(dev_idx >= ARRAY_SIZE(i7core_devs))) + /* + * FIXME: All memory controllers are allocated at the first pass. + */ + if (unlikely(dev_idx >= 1)) return -EINVAL; /* get the pci devices we want to reserve for our use */ - rc = i7core_get_devices(); + mutex_lock(&i7core_edac_lock); + rc = i7core_get_devices(&sockets); if (unlikely(rc < 0)) - return rc; - - sockets = 1; - for (i = NUM_SOCKETS - 1; i > 0; i--) - if (pci_devs[0].pdev[i]) { - sockets = i + 1; - break; - } + goto fail0; for (i = 0; i < sockets; i++) { int channels; @@ -1745,7 +1793,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, /* Check the number of active and not disabled channels */ rc = i7core_get_active_channels(i, &channels, &csrows); if (unlikely(rc < 0)) - goto fail0; + goto fail1; num_channels += channels; num_csrows += csrows; @@ -1755,7 +1803,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); if (unlikely(!mci)) { rc = -ENOMEM; - goto fail0; + goto fail1; } debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); @@ -1776,7 +1824,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, mci->edac_cap = EDAC_FLAG_NONE; mci->mod_name = "i7core_edac.c"; mci->mod_ver = I7CORE_REVISION; - mci->ctl_name = i7core_devs[dev_idx].ctl_name; + mci->ctl_name = i7core_probe_devs[dev_idx].ctl_name; mci->dev_name = pci_name(pdev); mci->ctl_page_to_phys = NULL; mci->mc_driver_sysfs_attributes = i7core_inj_attrs; @@ -1786,7 +1834,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, /* Store pci devices at mci for faster access */ rc = mci_bind_devs(mci); if (unlikely(rc < 0)) - goto fail1; + goto fail2; /* Get dimm basic config */ for (i = 0; i < sockets; i++) @@ -1801,7 +1849,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, */ rc = -EINVAL; - goto fail1; + goto fail2; } /* allocating generic PCI control info */ @@ -1832,18 +1880,21 @@ static int __devinit i7core_probe(struct pci_dev *pdev, if (unlikely(rc < 0)) { debugf0("MC: " __FILE__ ": %s(): failed edac_mce_register()\n", __func__); - goto fail1; + goto fail2; } i7core_printk(KERN_INFO, "Driver loaded.\n"); + mutex_unlock(&i7core_edac_lock); return 0; -fail1: +fail2: edac_mc_free(mci); -fail0: +fail1: i7core_put_devices(); +fail0: + mutex_unlock(&i7core_edac_lock); return rc; } @@ -1871,7 +1922,9 @@ static void __devexit i7core_remove(struct pci_dev *pdev) edac_mce_unregister(&pvt->edac_mce); /* retrieve references to resources, and free those resources */ + mutex_lock(&i7core_edac_lock); i7core_put_devices(); + mutex_unlock(&i7core_edac_lock); edac_mc_free(mci); } -- cgit v1.2.3 From f47429494fd50c0b7396fe3f8a26ea638b47c5ba Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 5 Sep 2009 02:35:08 -0300 Subject: i7core_edac: create one mc per socket/QPI Instead of creating just one memory controller, create one per socket (e. g. per Quick Link Path Interconnect). This better reflects the Nehalem architecture. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 507 ++++++++++++++++++++------------------------- 1 file changed, 228 insertions(+), 279 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 7bcb5993b501..5bc316b8e805 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -29,10 +29,20 @@ #include #include #include +#include #include #include "edac_core.h" +/* + * This is used for Nehalem-EP and Nehalem-EX devices, where the non-core + * registers start at bus 255, and are not reported by BIOS. + * We currently find devices with only 2 sockets. In order to support more QPI + * Quick Path Interconnect, just increment this number. + */ +#define MAX_SOCKET_BUSES 2 + + /* * Alter this version for the module when modifications are made */ @@ -162,7 +172,6 @@ #define NUM_CHANS 3 #define MAX_DIMMS 3 /* Max DIMMS per channel */ -#define NUM_SOCKETS 2 /* Max number of MC sockets */ #define MAX_MCR_FUNC 4 #define MAX_CHAN_FUNC 3 @@ -177,7 +186,6 @@ struct i7core_info { struct i7core_inject { int enable; - u8 socket; u32 section; u32 type; u32 eccmask; @@ -197,29 +205,37 @@ struct pci_id_descr { int dev_id; }; +struct i7core_dev { + struct list_head list; + u8 socket; + struct pci_dev **pdev; + struct mem_ctl_info *mci; +}; + struct i7core_pvt { - struct pci_dev *pci_noncore[NUM_SOCKETS]; - struct pci_dev *pci_mcr[NUM_SOCKETS][MAX_MCR_FUNC + 1]; - struct pci_dev *pci_ch[NUM_SOCKETS][NUM_CHANS][MAX_CHAN_FUNC + 1]; + struct pci_dev *pci_noncore; + struct pci_dev *pci_mcr[MAX_MCR_FUNC + 1]; + struct pci_dev *pci_ch[NUM_CHANS][MAX_CHAN_FUNC + 1]; + + struct i7core_dev *i7core_dev; struct i7core_info info; struct i7core_inject inject; - struct i7core_channel channel[NUM_SOCKETS][NUM_CHANS]; + struct i7core_channel channel[NUM_CHANS]; - int sockets; /* Number of sockets */ - int channels; /* Number of active channels */ + int channels; /* Number of active channels */ - int ce_count_available[NUM_SOCKETS]; - int csrow_map[NUM_SOCKETS][NUM_CHANS][MAX_DIMMS]; + int ce_count_available; + int csrow_map[NUM_CHANS][MAX_DIMMS]; /* ECC corrected errors counts per udimm */ - unsigned long udimm_ce_count[NUM_SOCKETS][MAX_DIMMS]; - int udimm_last_ce_count[NUM_SOCKETS][MAX_DIMMS]; + unsigned long udimm_ce_count[MAX_DIMMS]; + int udimm_last_ce_count[MAX_DIMMS]; /* ECC corrected errors counts per rdimm */ - unsigned long rdimm_ce_count[NUM_SOCKETS][NUM_CHANS][MAX_DIMMS]; - int rdimm_last_ce_count[NUM_SOCKETS][NUM_CHANS][MAX_DIMMS]; + unsigned long rdimm_ce_count[NUM_CHANS][MAX_DIMMS]; + int rdimm_last_ce_count[NUM_CHANS][MAX_DIMMS]; - unsigned int is_registered[NUM_SOCKETS]; + unsigned int is_registered; /* mcelog glue */ struct edac_mce edac_mce; @@ -228,22 +244,10 @@ struct i7core_pvt { spinlock_t mce_lock; }; -struct i7core_dev { - struct list_head list; - - int socket; - struct pci_dev **pdev; -}; - /* Static vars */ static LIST_HEAD(i7core_edac_list); static DEFINE_MUTEX(i7core_edac_lock); - -/* Device name and register DID (Device ID) */ -struct i7core_dev_info { - const char *ctl_name; /* name for this device */ - u16 fsb_mapping_errors; /* DID for the branchmap,control */ -}; +static u8 max_num_sockets; #define PCI_DESCR(device, function, device_id) \ .dev = (device), \ @@ -295,15 +299,6 @@ static const struct pci_device_id i7core_pci_tbl[] __devinitdata = { {0,} /* 0 terminated list. */ }; - -/* Table of devices attributes supported by this driver */ -static const struct i7core_dev_info i7core_probe_devs[] = { - { - .ctl_name = "i7 Core", - .fsb_mapping_errors = PCI_DEVICE_ID_INTEL_I7_MCR, - }, -}; - static struct edac_pci_ctl_info *i7core_pci; /**************************************************************************** @@ -356,7 +351,7 @@ static inline int numcol(u32 col) return cols[col & 0x3]; } -static struct i7core_dev *get_i7core_dev(int socket) +static struct i7core_dev *get_i7core_dev(u8 socket) { struct i7core_dev *i7core_dev; @@ -471,18 +466,19 @@ static int i7core_get_active_channels(u8 socket, unsigned *channels, return 0; } -static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) +static int get_dimm_config(struct mem_ctl_info *mci, int *csrow) { struct i7core_pvt *pvt = mci->pvt_info; struct csrow_info *csr; struct pci_dev *pdev; int i, j; + u8 socket = pvt->i7core_dev->socket; unsigned long last_page = 0; enum edac_type mode; enum mem_type mtype; /* Get data from the MC register, function 0 */ - pdev = pvt->pci_mcr[socket][0]; + pdev = pvt->pci_mcr[0]; if (!pdev) return -ENODEV; @@ -529,10 +525,10 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) } /* Devices 4-6 function 0 */ - pci_read_config_dword(pvt->pci_ch[socket][i][0], + pci_read_config_dword(pvt->pci_ch[i][0], MC_CHANNEL_DIMM_INIT_PARAMS, &data); - pvt->channel[socket][i].ranks = (data & QUAD_RANK_PRESENT) ? + pvt->channel[i].ranks = (data & QUAD_RANK_PRESENT) ? 4 : 2; if (data & REGISTERED_DIMM) @@ -549,11 +545,11 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) #endif /* Devices 4-6 function 1 */ - pci_read_config_dword(pvt->pci_ch[socket][i][1], + pci_read_config_dword(pvt->pci_ch[i][1], MC_DOD_CH_DIMM0, &dimm_dod[0]); - pci_read_config_dword(pvt->pci_ch[socket][i][1], + pci_read_config_dword(pvt->pci_ch[i][1], MC_DOD_CH_DIMM1, &dimm_dod[1]); - pci_read_config_dword(pvt->pci_ch[socket][i][1], + pci_read_config_dword(pvt->pci_ch[i][1], MC_DOD_CH_DIMM2, &dimm_dod[2]); debugf0("Ch%d phy rd%d, wr%d (0x%08x): " @@ -561,7 +557,7 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) i, RDLCH(pvt->info.ch_map, i), WRLCH(pvt->info.ch_map, i), data, - pvt->channel[socket][i].ranks, + pvt->channel[i].ranks, (data & REGISTERED_DIMM) ? 'R' : 'U'); for (j = 0; j < 3; j++) { @@ -579,7 +575,7 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) /* DDR3 has 8 I/O banks */ size = (rows * cols * banks * ranks) >> (20 - 3); - pvt->channel[socket][i].dimms++; + pvt->channel[i].dimms++; debugf0("\tdimm %d %d Mb offset: %x, " "bank: %d, rank: %d, row: %#x, col: %#x\n", @@ -607,7 +603,7 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) csr->channels[0].chan_idx = i; csr->channels[0].ce_count = 0; - pvt->csrow_map[socket][i][j] = *csrow; + pvt->csrow_map[i][j] = *csrow; switch (banks) { case 4: @@ -665,42 +661,15 @@ static int disable_inject(struct mem_ctl_info *mci) pvt->inject.enable = 0; - if (!pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0]) + if (!pvt->pci_ch[pvt->inject.channel][0]) return -ENODEV; - pci_write_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], + pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], MC_CHANNEL_ERROR_INJECT, 0); return 0; } -/* - * i7core inject inject.socket - * - * accept and store error injection inject.socket value - */ -static ssize_t i7core_inject_socket_store(struct mem_ctl_info *mci, - const char *data, size_t count) -{ - struct i7core_pvt *pvt = mci->pvt_info; - unsigned long value; - int rc; - - rc = strict_strtoul(data, 10, &value); - if ((rc < 0) || (value >= pvt->sockets)) - return -EIO; - - pvt->inject.socket = (u32) value; - return count; -} - -static ssize_t i7core_inject_socket_show(struct mem_ctl_info *mci, - char *data) -{ - struct i7core_pvt *pvt = mci->pvt_info; - return sprintf(data, "%d\n", pvt->inject.socket); -} - /* * i7core inject inject.section * @@ -965,7 +934,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, int rc; long enable; - if (!pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0]) + if (!pvt->pci_ch[pvt->inject.channel][0]) return 0; rc = strict_strtoul(data, 10, &enable); @@ -983,7 +952,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, if (pvt->inject.dimm < 0) mask |= 1L << 41; else { - if (pvt->channel[pvt->inject.socket][pvt->inject.channel].dimms > 2) + if (pvt->channel[pvt->inject.channel].dimms > 2) mask |= (pvt->inject.dimm & 0x3L) << 35; else mask |= (pvt->inject.dimm & 0x1L) << 36; @@ -993,7 +962,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, if (pvt->inject.rank < 0) mask |= 1L << 40; else { - if (pvt->channel[pvt->inject.socket][pvt->inject.channel].dimms > 2) + if (pvt->channel[pvt->inject.channel].dimms > 2) mask |= (pvt->inject.rank & 0x1L) << 34; else mask |= (pvt->inject.rank & 0x3L) << 34; @@ -1029,18 +998,18 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, (pvt->inject.type & 0x6) << (3 - 1); /* Unlock writes to registers - this register is write only */ - pci_write_config_dword(pvt->pci_noncore[pvt->inject.socket], + pci_write_config_dword(pvt->pci_noncore, MC_CFG_CONTROL, 0x2); - write_and_test(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], + write_and_test(pvt->pci_ch[pvt->inject.channel][0], MC_CHANNEL_ADDR_MATCH, mask); - write_and_test(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], + write_and_test(pvt->pci_ch[pvt->inject.channel][0], MC_CHANNEL_ADDR_MATCH + 4, mask >> 32L); - write_and_test(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], + write_and_test(pvt->pci_ch[pvt->inject.channel][0], MC_CHANNEL_ERROR_MASK, pvt->inject.eccmask); - write_and_test(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], + write_and_test(pvt->pci_ch[pvt->inject.channel][0], MC_CHANNEL_ERROR_INJECT, injectmask); /* @@ -1048,7 +1017,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, * Without writing 8 to this register, errors aren't injected. Not sure * why. */ - pci_write_config_dword(pvt->pci_noncore[pvt->inject.socket], + pci_write_config_dword(pvt->pci_noncore, MC_CFG_CONTROL, 8); debugf0("Error inject addr match 0x%016llx, ecc 0x%08x," @@ -1065,7 +1034,7 @@ static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci, struct i7core_pvt *pvt = mci->pvt_info; u32 injectmask; - pci_read_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], + pci_read_config_dword(pvt->pci_ch[pvt->inject.channel][0], MC_CHANNEL_ERROR_INJECT, &injectmask); debugf0("Inject error read: 0x%018x\n", injectmask); @@ -1078,34 +1047,30 @@ static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci, static ssize_t i7core_ce_regs_show(struct mem_ctl_info *mci, char *data) { - unsigned i, j, count, total = 0; + unsigned i, count, total = 0; struct i7core_pvt *pvt = mci->pvt_info; - for (i = 0; i < pvt->sockets; i++) { - if (!pvt->ce_count_available[i]) { - count = sprintf(data, "socket 0 data unavailable\n"); - continue; - } - if (!pvt->is_registered[i]) - count = sprintf(data, "socket %d, dimm0: %lu\n" - "dimm1: %lu\ndimm2: %lu\n", - i, - pvt->udimm_ce_count[i][0], - pvt->udimm_ce_count[i][1], - pvt->udimm_ce_count[i][2]); - else - for (j = 0; j < NUM_CHANS; j++) { - count = sprintf(data, "socket %d, channel %d " - "RDIMM0: %lu " - "RDIMM1: %lu RDIMM2: %lu\n", - i, j, - pvt->rdimm_ce_count[i][j][0], - pvt->rdimm_ce_count[i][j][1], - pvt->rdimm_ce_count[i][j][2]); - } - data += count; - total += count; + if (!pvt->ce_count_available) { + count = sprintf(data, "data unavailable\n"); + return 0; } + if (!pvt->is_registered) + count = sprintf(data, "all channels " + "UDIMM0: %lu UDIMM1: %lu UDIMM2: %lu\n", + pvt->udimm_ce_count[0], + pvt->udimm_ce_count[1], + pvt->udimm_ce_count[2]); + else + for (i = 0; i < NUM_CHANS; i++) { + count = sprintf(data, "channel %d RDIMM0: %lu " + "RDIMM1: %lu RDIMM2: %lu\n", + i, + pvt->rdimm_ce_count[i][0], + pvt->rdimm_ce_count[i][1], + pvt->rdimm_ce_count[i][2]); + } + data += count; + total += count; return total; } @@ -1115,13 +1080,6 @@ static ssize_t i7core_ce_regs_show(struct mem_ctl_info *mci, char *data) */ static struct mcidev_sysfs_attribute i7core_inj_attrs[] = { { - .attr = { - .name = "inject_socket", - .mode = (S_IRUGO | S_IWUSR) - }, - .show = i7core_inject_socket_show, - .store = i7core_inject_socket_store, - }, { .attr = { .name = "inject_section", .mode = (S_IRUGO | S_IWUSR) @@ -1178,7 +1136,7 @@ static void i7core_put_devices(void) { int i, j; - for (i = 0; i < NUM_SOCKETS; i++) { + for (i = 0; i < max_num_sockets; i++) { struct i7core_dev *i7core_dev = get_i7core_dev(i); if (!i7core_dev) continue; @@ -1204,7 +1162,7 @@ static void i7core_xeon_pci_fixup(void) pdev = pci_get_device(PCI_VENDOR_ID_INTEL, pci_dev_descr[0].dev_id, NULL); if (unlikely(!pdev)) { - for (i = 0; i < NUM_SOCKETS; i ++) + for (i = 0; i < MAX_SOCKET_BUSES; i++) pcibios_scan_specific_bus(255-i); } } @@ -1323,13 +1281,11 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno) return 0; } -static int i7core_get_devices(u8 *sockets) +static int i7core_get_devices(void) { int i; struct pci_dev *pdev = NULL; - struct i7core_dev *i7core_dev = NULL; - *sockets = 0; for (i = 0; i < N_DEVS; i++) { pdev = NULL; do { @@ -1340,55 +1296,48 @@ static int i7core_get_devices(u8 *sockets) } while (pdev); } - list_for_each_entry(i7core_dev, &i7core_edac_list, list) { - if (i7core_dev->socket + 1 > *sockets) - *sockets = i7core_dev->socket + 1; - } - return 0; } -static int mci_bind_devs(struct mem_ctl_info *mci) +static int mci_bind_devs(struct mem_ctl_info *mci, + struct i7core_dev *i7core_dev) { struct i7core_pvt *pvt = mci->pvt_info; struct pci_dev *pdev; - int i, j, func, slot; + int i, func, slot; - for (i = 0; i < pvt->sockets; i++) { - struct i7core_dev *i7core_dev = get_i7core_dev(i); + /* Associates i7core_dev and mci for future usage */ + pvt->i7core_dev = i7core_dev; + i7core_dev->mci = mci; - if (!i7core_dev) + pvt->is_registered = 0; + for (i = 0; i < N_DEVS; i++) { + pdev = i7core_dev->pdev[i]; + if (!pdev) continue; - pvt->is_registered[i] = 0; - for (j = 0; j < N_DEVS; j++) { - pdev = i7core_dev->pdev[j]; - if (!pdev) - continue; - - func = PCI_FUNC(pdev->devfn); - slot = PCI_SLOT(pdev->devfn); - if (slot == 3) { - if (unlikely(func > MAX_MCR_FUNC)) - goto error; - pvt->pci_mcr[i][func] = pdev; - } else if (likely(slot >= 4 && slot < 4 + NUM_CHANS)) { - if (unlikely(func > MAX_CHAN_FUNC)) - goto error; - pvt->pci_ch[i][slot - 4][func] = pdev; - } else if (!slot && !func) - pvt->pci_noncore[i] = pdev; - else + func = PCI_FUNC(pdev->devfn); + slot = PCI_SLOT(pdev->devfn); + if (slot == 3) { + if (unlikely(func > MAX_MCR_FUNC)) + goto error; + pvt->pci_mcr[func] = pdev; + } else if (likely(slot >= 4 && slot < 4 + NUM_CHANS)) { + if (unlikely(func > MAX_CHAN_FUNC)) goto error; + pvt->pci_ch[slot - 4][func] = pdev; + } else if (!slot && !func) + pvt->pci_noncore = pdev; + else + goto error; - debugf0("Associated fn %d.%d, dev = %p, socket %d\n", - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), - pdev, i); + debugf0("Associated fn %d.%d, dev = %p, socket %d\n", + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), + pdev, i7core_dev->socket); - if (PCI_SLOT(pdev->devfn) == 3 && - PCI_FUNC(pdev->devfn) == 2) - pvt->is_registered[i] = 1; - } + if (PCI_SLOT(pdev->devfn) == 3 && + PCI_FUNC(pdev->devfn) == 2) + pvt->is_registered = 1; } return 0; @@ -1403,17 +1352,17 @@ error: /**************************************************************************** Error check routines ****************************************************************************/ -static void i7core_rdimm_update_csrow(struct mem_ctl_info *mci, int socket, +static void i7core_rdimm_update_csrow(struct mem_ctl_info *mci, int chan, int dimm, int add) { char *msg; struct i7core_pvt *pvt = mci->pvt_info; - int row = pvt->csrow_map[socket][chan][dimm], i; + int row = pvt->csrow_map[chan][dimm], i; for (i = 0; i < add; i++) { msg = kasprintf(GFP_KERNEL, "Corrected error " - "(Socket=%d channel=%d dimm=%d", - socket, chan, dimm); + "(Socket=%d channel=%d dimm=%d)", + pvt->i7core_dev->socket, chan, dimm); edac_mc_handle_fbd_ce(mci, row, 0, msg); kfree (msg); @@ -1421,71 +1370,71 @@ static void i7core_rdimm_update_csrow(struct mem_ctl_info *mci, int socket, } static void i7core_rdimm_update_ce_count(struct mem_ctl_info *mci, - int socket, int chan, int new0, int new1, int new2) + int chan, int new0, int new1, int new2) { struct i7core_pvt *pvt = mci->pvt_info; int add0 = 0, add1 = 0, add2 = 0; /* Updates CE counters if it is not the first time here */ - if (pvt->ce_count_available[socket]) { + if (pvt->ce_count_available) { /* Updates CE counters */ - add2 = new2 - pvt->rdimm_last_ce_count[socket][chan][2]; - add1 = new1 - pvt->rdimm_last_ce_count[socket][chan][1]; - add0 = new0 - pvt->rdimm_last_ce_count[socket][chan][0]; + add2 = new2 - pvt->rdimm_last_ce_count[chan][2]; + add1 = new1 - pvt->rdimm_last_ce_count[chan][1]; + add0 = new0 - pvt->rdimm_last_ce_count[chan][0]; if (add2 < 0) add2 += 0x7fff; - pvt->rdimm_ce_count[socket][chan][2] += add2; + pvt->rdimm_ce_count[chan][2] += add2; if (add1 < 0) add1 += 0x7fff; - pvt->rdimm_ce_count[socket][chan][1] += add1; + pvt->rdimm_ce_count[chan][1] += add1; if (add0 < 0) add0 += 0x7fff; - pvt->rdimm_ce_count[socket][chan][0] += add0; + pvt->rdimm_ce_count[chan][0] += add0; } else - pvt->ce_count_available[socket] = 1; + pvt->ce_count_available = 1; /* Store the new values */ - pvt->rdimm_last_ce_count[socket][chan][2] = new2; - pvt->rdimm_last_ce_count[socket][chan][1] = new1; - pvt->rdimm_last_ce_count[socket][chan][0] = new0; + pvt->rdimm_last_ce_count[chan][2] = new2; + pvt->rdimm_last_ce_count[chan][1] = new1; + pvt->rdimm_last_ce_count[chan][0] = new0; /*updated the edac core */ if (add0 != 0) - i7core_rdimm_update_csrow(mci, socket, chan, 0, add0); + i7core_rdimm_update_csrow(mci, chan, 0, add0); if (add1 != 0) - i7core_rdimm_update_csrow(mci, socket, chan, 1, add1); + i7core_rdimm_update_csrow(mci, chan, 1, add1); if (add2 != 0) - i7core_rdimm_update_csrow(mci, socket, chan, 2, add2); + i7core_rdimm_update_csrow(mci, chan, 2, add2); } -static void i7core_rdimm_check_mc_ecc_err(struct mem_ctl_info *mci, u8 socket) +static void i7core_rdimm_check_mc_ecc_err(struct mem_ctl_info *mci) { struct i7core_pvt *pvt = mci->pvt_info; u32 rcv[3][2]; int i, new0, new1, new2; /*Read DEV 3: FUN 2: MC_COR_ECC_CNT regs directly*/ - pci_read_config_dword(pvt->pci_mcr[socket][2], MC_COR_ECC_CNT_0, + pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_0, &rcv[0][0]); - pci_read_config_dword(pvt->pci_mcr[socket][2], MC_COR_ECC_CNT_1, + pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_1, &rcv[0][1]); - pci_read_config_dword(pvt->pci_mcr[socket][2], MC_COR_ECC_CNT_2, + pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_2, &rcv[1][0]); - pci_read_config_dword(pvt->pci_mcr[socket][2], MC_COR_ECC_CNT_3, + pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_3, &rcv[1][1]); - pci_read_config_dword(pvt->pci_mcr[socket][2], MC_COR_ECC_CNT_4, + pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_4, &rcv[2][0]); - pci_read_config_dword(pvt->pci_mcr[socket][2], MC_COR_ECC_CNT_5, + pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_5, &rcv[2][1]); for (i = 0 ; i < 3; i++) { debugf3("MC_COR_ECC_CNT%d = 0x%x; MC_COR_ECC_CNT%d = 0x%x\n", (i * 2), rcv[i][0], (i * 2) + 1, rcv[i][1]); /*if the channel has 3 dimms*/ - if (pvt->channel[socket][i].dimms > 2) { + if (pvt->channel[i].dimms > 2) { new0 = DIMM_BOT_COR_ERR(rcv[i][0]); new1 = DIMM_TOP_COR_ERR(rcv[i][0]); new2 = DIMM_BOT_COR_ERR(rcv[i][1]); @@ -1497,7 +1446,7 @@ static void i7core_rdimm_check_mc_ecc_err(struct mem_ctl_info *mci, u8 socket) new2 = 0; } - i7core_rdimm_update_ce_count(mci, socket, i, new0, new1, new2); + i7core_rdimm_update_ce_count(mci, i, new0, new1, new2); } } @@ -1507,20 +1456,20 @@ static void i7core_rdimm_check_mc_ecc_err(struct mem_ctl_info *mci, u8 socket) * also available at: * http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf */ -static void i7core_udimm_check_mc_ecc_err(struct mem_ctl_info *mci, u8 socket) +static void i7core_udimm_check_mc_ecc_err(struct mem_ctl_info *mci) { struct i7core_pvt *pvt = mci->pvt_info; u32 rcv1, rcv0; int new0, new1, new2; - if (!pvt->pci_mcr[socket][4]) { + if (!pvt->pci_mcr[4]) { debugf0("%s MCR registers not found\n", __func__); return; } /* Corrected test errors */ - pci_read_config_dword(pvt->pci_mcr[socket][4], MC_TEST_ERR_RCV1, &rcv1); - pci_read_config_dword(pvt->pci_mcr[socket][4], MC_TEST_ERR_RCV0, &rcv0); + pci_read_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV1, &rcv1); + pci_read_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV0, &rcv0); /* Store the new values */ new2 = DIMM2_COR_ERR(rcv1); @@ -1528,37 +1477,37 @@ static void i7core_udimm_check_mc_ecc_err(struct mem_ctl_info *mci, u8 socket) new0 = DIMM0_COR_ERR(rcv0); /* Updates CE counters if it is not the first time here */ - if (pvt->ce_count_available[socket]) { + if (pvt->ce_count_available) { /* Updates CE counters */ int add0, add1, add2; - add2 = new2 - pvt->udimm_last_ce_count[socket][2]; - add1 = new1 - pvt->udimm_last_ce_count[socket][1]; - add0 = new0 - pvt->udimm_last_ce_count[socket][0]; + add2 = new2 - pvt->udimm_last_ce_count[2]; + add1 = new1 - pvt->udimm_last_ce_count[1]; + add0 = new0 - pvt->udimm_last_ce_count[0]; if (add2 < 0) add2 += 0x7fff; - pvt->udimm_ce_count[socket][2] += add2; + pvt->udimm_ce_count[2] += add2; if (add1 < 0) add1 += 0x7fff; - pvt->udimm_ce_count[socket][1] += add1; + pvt->udimm_ce_count[1] += add1; if (add0 < 0) add0 += 0x7fff; - pvt->udimm_ce_count[socket][0] += add0; + pvt->udimm_ce_count[0] += add0; if (add0 | add1 | add2) i7core_printk(KERN_ERR, "New Corrected error(s): " "dimm0: +%d, dimm1: +%d, dimm2 +%d\n", add0, add1, add2); } else - pvt->ce_count_available[socket] = 1; + pvt->ce_count_available = 1; /* Store the new values */ - pvt->udimm_last_ce_count[socket][2] = new2; - pvt->udimm_last_ce_count[socket][1] = new1; - pvt->udimm_last_ce_count[socket][0] = new0; + pvt->udimm_last_ce_count[2] = new2; + pvt->udimm_last_ce_count[1] = new1; + pvt->udimm_last_ce_count[0] = new0; } /* @@ -1587,13 +1536,6 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, u32 syndrome = m->misc >> 32; u32 errnum = find_first_bit(&error, 32); int csrow; -/* FIXME */ -//#ifdef CONFIG_SMP -#if 0 - u32 socket_id = per_cpu(cpu_data, cpu).phys_proc_id; -#else - u32 socket_id = 0; -#endif if (m->mcgstatus & 1) type = "FATAL"; @@ -1655,24 +1597,21 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, /* FIXME: should convert addr into bank and rank information */ msg = kasprintf(GFP_ATOMIC, - "%s (addr = 0x%08llx, socket=%d, Dimm=%d, Channel=%d, " + "%s (addr = 0x%08llx, cpu=%d, Dimm=%d, Channel=%d, " "syndrome=0x%08x, count=%d, Err=%08llx:%08llx (%s: %s))\n", - type, (long long) m->addr, socket_id, dimm, channel, + type, (long long) m->addr, m->cpu, dimm, channel, syndrome, core_err_cnt, (long long)m->status, (long long)m->misc, optype, err); debugf0("%s", msg); - if (socket_id < NUM_SOCKETS) - csrow = pvt->csrow_map[socket_id][channel][dimm]; - else - csrow = -1; + csrow = pvt->csrow_map[channel][dimm]; /* Call the helper to output message */ if (m->mcgstatus & 1) edac_mc_handle_fbd_ue(mci, csrow, 0, 0 /* FIXME: should be channel here */, msg); - else if (!pvt->is_registered[socket_id]) + else if (!pvt->is_registered) edac_mc_handle_fbd_ce(mci, csrow, 0 /* FIXME: should be channel here */, msg); @@ -1695,12 +1634,14 @@ static void i7core_check_error(struct mem_ctl_info *mci) spin_lock_irqsave(&pvt->mce_lock, flags); if (pvt->mce_count) { m = kmalloc(sizeof(*m) * pvt->mce_count, GFP_ATOMIC); + if (m) { count = pvt->mce_count; memcpy(m, &pvt->mce_entry, sizeof(*m) * count); } pvt->mce_count = 0; } + spin_unlock_irqrestore(&pvt->mce_lock, flags); /* proccess mcelog errors */ @@ -1710,11 +1651,10 @@ static void i7core_check_error(struct mem_ctl_info *mci) kfree(m); /* check memory count errors */ - for (i = 0; i < pvt->sockets; i++) - if (!pvt->is_registered[i]) - i7core_udimm_check_mc_ecc_err(mci, i); - else - i7core_rdimm_check_mc_ecc_err(mci, i); + if (!pvt->is_registered) + i7core_udimm_check_mc_ecc_err(mci); + else + i7core_rdimm_check_mc_ecc_err(mci); } /* @@ -1740,6 +1680,10 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) if (mce->bank != 8) return 0; + /* Only handle if it is the right mc controller */ + if (cpu_data(mce->cpu).phys_proc_id != pvt->i7core_dev->socket) + return 0; + spin_lock_irqsave(&pvt->mce_lock, flags); if (pvt->mce_count < MCE_LOG_LEN) { memcpy(&pvt->mce_entry[pvt->mce_count], mce, sizeof(*mce)); @@ -1755,63 +1699,26 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) return 1; } -/* - * i7core_probe Probe for ONE instance of device to see if it is - * present. - * return: - * 0 for FOUND a device - * < 0 for error code - */ -static int __devinit i7core_probe(struct pci_dev *pdev, - const struct pci_device_id *id) +static int i7core_register_mci(struct i7core_dev *i7core_dev, + int num_channels, int num_csrows) { struct mem_ctl_info *mci; struct i7core_pvt *pvt; - int num_channels = 0; - int num_csrows = 0; int csrow = 0; - int dev_idx = id->driver_data; - int rc, i; - u8 sockets; - - /* - * FIXME: All memory controllers are allocated at the first pass. - */ - if (unlikely(dev_idx >= 1)) - return -EINVAL; - - /* get the pci devices we want to reserve for our use */ - mutex_lock(&i7core_edac_lock); - rc = i7core_get_devices(&sockets); - if (unlikely(rc < 0)) - goto fail0; - - for (i = 0; i < sockets; i++) { - int channels; - int csrows; - - /* Check the number of active and not disabled channels */ - rc = i7core_get_active_channels(i, &channels, &csrows); - if (unlikely(rc < 0)) - goto fail1; - - num_channels += channels; - num_csrows += csrows; - } + int rc; /* allocate a new MC control structure */ mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); - if (unlikely(!mci)) { - rc = -ENOMEM; - goto fail1; - } + if (unlikely(!mci)) + return -ENOMEM; debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); - mci->dev = &pdev->dev; /* record ptr to the generic device */ + /* record ptr to the generic device */ + mci->dev = &i7core_dev->pdev[0]->dev; + pvt = mci->pvt_info; memset(pvt, 0, sizeof(*pvt)); - pvt->sockets = sockets; mci->mc_idx = 0; /* @@ -1824,21 +1731,21 @@ static int __devinit i7core_probe(struct pci_dev *pdev, mci->edac_cap = EDAC_FLAG_NONE; mci->mod_name = "i7core_edac.c"; mci->mod_ver = I7CORE_REVISION; - mci->ctl_name = i7core_probe_devs[dev_idx].ctl_name; - mci->dev_name = pci_name(pdev); + mci->ctl_name = kasprintf(GFP_KERNEL, "i7 core #%d", + i7core_dev->socket); + mci->dev_name = pci_name(i7core_dev->pdev[0]); mci->ctl_page_to_phys = NULL; mci->mc_driver_sysfs_attributes = i7core_inj_attrs; /* Set the function pointer to an actual operation function */ mci->edac_check = i7core_check_error; /* Store pci devices at mci for faster access */ - rc = mci_bind_devs(mci); + rc = mci_bind_devs(mci, i7core_dev); if (unlikely(rc < 0)) - goto fail2; + goto fail; /* Get dimm basic config */ - for (i = 0; i < sockets; i++) - get_dimm_config(mci, &csrow, i); + get_dimm_config(mci, &csrow); /* add this new MC control structure to EDAC's list of MCs */ if (unlikely(edac_mc_add_mc(mci))) { @@ -1849,11 +1756,12 @@ static int __devinit i7core_probe(struct pci_dev *pdev, */ rc = -EINVAL; - goto fail2; + goto fail; } /* allocating generic PCI control info */ - i7core_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); + i7core_pci = edac_pci_create_generic_ctl(&i7core_dev->pdev[0]->dev, + EDAC_MOD_STR); if (unlikely(!i7core_pci)) { printk(KERN_WARNING "%s(): Unable to create PCI control\n", @@ -1880,7 +1788,50 @@ static int __devinit i7core_probe(struct pci_dev *pdev, if (unlikely(rc < 0)) { debugf0("MC: " __FILE__ ": %s(): failed edac_mce_register()\n", __func__); - goto fail2; + } + +fail: + edac_mc_free(mci); + return rc; +} + +/* + * i7core_probe Probe for ONE instance of device to see if it is + * present. + * return: + * 0 for FOUND a device + * < 0 for error code + */ +static int __devinit i7core_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + int dev_idx = id->driver_data; + int rc; + struct i7core_dev *i7core_dev; + + /* + * FIXME: All memory controllers are allocated at the first pass. + */ + if (unlikely(dev_idx >= 1)) + return -EINVAL; + + /* get the pci devices we want to reserve for our use */ + mutex_lock(&i7core_edac_lock); + rc = i7core_get_devices(); + if (unlikely(rc < 0)) + goto fail0; + + list_for_each_entry(i7core_dev, &i7core_edac_list, list) { + int channels; + int csrows; + + /* Check the number of active and not disabled channels */ + rc = i7core_get_active_channels(i7core_dev->socket, + &channels, &csrows); + if (unlikely(rc < 0)) + goto fail1; + + i7core_register_mci(i7core_dev, channels, csrows); } i7core_printk(KERN_INFO, "Driver loaded.\n"); @@ -1888,9 +1839,6 @@ static int __devinit i7core_probe(struct pci_dev *pdev, mutex_unlock(&i7core_edac_lock); return 0; -fail2: - edac_mc_free(mci); - fail1: i7core_put_devices(); fail0: @@ -1926,6 +1874,7 @@ static void __devexit i7core_remove(struct pci_dev *pdev) i7core_put_devices(); mutex_unlock(&i7core_edac_lock); + kfree(mci->ctl_name); edac_mc_free(mci); } -- cgit v1.2.3 From 6c6aa3afdba2460cb668d4cb65c74dfa8eb43449 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 5 Sep 2009 03:27:04 -0300 Subject: i7core_edac: sanity check: print a warning if a mcelog is ignored In thesis, the other mc controller should handle it. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 5bc316b8e805..335d9ed02c45 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1681,8 +1681,13 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) return 0; /* Only handle if it is the right mc controller */ - if (cpu_data(mce->cpu).phys_proc_id != pvt->i7core_dev->socket) + if (cpu_data(mce->cpu).phys_proc_id != pvt->i7core_dev->socket) { + debugf0("mc%d: ignoring mce log for socket %d. " + "Another mc should get it.\n", + pvt->i7core_dev->socket, + cpu_data(mce->cpu).phys_proc_id); return 0; + } spin_lock_irqsave(&pvt->mce_lock, flags); if (pvt->mce_count < MCE_LOG_LEN) { -- cgit v1.2.3 From d4c277957f4e8e6f2b626e2661cbbf9c76782e36 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 5 Sep 2009 04:12:02 -0300 Subject: i7core_edac: a few fixes for multiple mc's Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 335d9ed02c45..2c30493eae0f 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1270,11 +1270,10 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno) return -ENODEV; } - i7core_printk(KERN_INFO, - "Registered socket %d " - "dev %02x:%02x.%d PCI ID %04x:%04x\n", - socket, bus, pci_dev_descr[devno].dev, pci_dev_descr[devno].func, - PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id); + debugf0("Detected socket %d dev %02x:%02x.%d PCI ID %04x:%04x\n", + socket, bus, pci_dev_descr[devno].dev, + pci_dev_descr[devno].func, + PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id); *prev = pdev; @@ -1713,7 +1712,8 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev, int rc; /* allocate a new MC control structure */ - mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); + mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, + i7core_dev->socket); if (unlikely(!mci)) return -ENOMEM; @@ -1724,7 +1724,6 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev, pvt = mci->pvt_info; memset(pvt, 0, sizeof(*pvt)); - mci->mc_idx = 0; /* * FIXME: how to handle RDDR3 at MCI level? It is possible to have @@ -1815,7 +1814,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, struct i7core_dev *i7core_dev; /* - * FIXME: All memory controllers are allocated at the first pass. + * All memory controllers are allocated at the first pass. */ if (unlikely(dev_idx >= 1)) return -EINVAL; @@ -1836,7 +1835,9 @@ static int __devinit i7core_probe(struct pci_dev *pdev, if (unlikely(rc < 0)) goto fail1; - i7core_register_mci(i7core_dev, channels, csrows); + rc = i7core_register_mci(i7core_dev, channels, csrows); + if (unlikely(rc < 0)) + goto fail1; } i7core_printk(KERN_INFO, "Driver loaded.\n"); @@ -1876,6 +1877,8 @@ static void __devexit i7core_remove(struct pci_dev *pdev) /* retrieve references to resources, and free those resources */ mutex_lock(&i7core_edac_lock); + + /* FIXME: This should put the devices only for this mci!!! */ i7core_put_devices(); mutex_unlock(&i7core_edac_lock); -- cgit v1.2.3 From d88b85072fa7d406f54c30ceeabcd37e5a2ec21a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 5 Sep 2009 05:10:31 -0300 Subject: i7core_edac: Fix a bug when printing error counts with RDIMMs Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 2c30493eae0f..821e8a1a09cf 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1054,13 +1054,15 @@ static ssize_t i7core_ce_regs_show(struct mem_ctl_info *mci, char *data) count = sprintf(data, "data unavailable\n"); return 0; } - if (!pvt->is_registered) + if (!pvt->is_registered) { count = sprintf(data, "all channels " "UDIMM0: %lu UDIMM1: %lu UDIMM2: %lu\n", pvt->udimm_ce_count[0], pvt->udimm_ce_count[1], pvt->udimm_ce_count[2]); - else + data += count; + total += count; + } else { for (i = 0; i < NUM_CHANS; i++) { count = sprintf(data, "channel %d RDIMM0: %lu " "RDIMM1: %lu RDIMM2: %lu\n", @@ -1068,9 +1070,10 @@ static ssize_t i7core_ce_regs_show(struct mem_ctl_info *mci, char *data) pvt->rdimm_ce_count[i][0], pvt->rdimm_ce_count[i][1], pvt->rdimm_ce_count[i][2]); - } - data += count; - total += count; + data += count; + total += count; + } + } return total; } -- cgit v1.2.3 From 13d6e9b653e6f714024c67287c7d7eac54d8417b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 5 Sep 2009 12:15:20 -0300 Subject: i7core_edac: at remove, don't remove all pci devices at once Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 821e8a1a09cf..c2266f820b0f 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1135,22 +1135,24 @@ static struct mcidev_sysfs_attribute i7core_inj_attrs[] = { * i7core_put_devices 'put' all the devices that we have * reserved via 'get' */ -static void i7core_put_devices(void) +static void i7core_put_devices(struct i7core_dev *i7core_dev) { - int i, j; + int i; - for (i = 0; i < max_num_sockets; i++) { - struct i7core_dev *i7core_dev = get_i7core_dev(i); - if (!i7core_dev) - continue; + for (i = 0; i < N_DEVS; i++) + pci_dev_put(i7core_dev->pdev[i]); - for (j = 0; j < N_DEVS; j++) - pci_dev_put(i7core_dev->pdev[j]); + list_del(&i7core_dev->list); + kfree(i7core_dev->pdev); + kfree(i7core_dev); +} - list_del(&i7core_dev->list); - kfree(i7core_dev->pdev); - kfree(i7core_dev); - } +static void i7core_put_all_devices(void) +{ + struct i7core_dev *i7core_dev; + + list_for_each_entry(i7core_dev, &i7core_edac_list, list) + i7core_put_devices(i7core_dev); } static void i7core_xeon_pci_fixup(void) @@ -1292,7 +1294,7 @@ static int i7core_get_devices(void) pdev = NULL; do { if (i7core_get_onedevice(&pdev, i) < 0) { - i7core_put_devices(); + i7core_put_all_devices(); return -ENODEV; } } while (pdev); @@ -1849,7 +1851,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, return 0; fail1: - i7core_put_devices(); + i7core_put_all_devices(); fail0: mutex_unlock(&i7core_edac_lock); return rc; @@ -1863,6 +1865,7 @@ static void __devexit i7core_remove(struct pci_dev *pdev) { struct mem_ctl_info *mci; struct i7core_pvt *pvt; + struct i7core_dev *i7core_dev; debugf0(__FILE__ ": %s()\n", __func__); @@ -1876,13 +1879,12 @@ static void __devexit i7core_remove(struct pci_dev *pdev) /* Unregisters on edac_mce in order to receive memory errors */ pvt = mci->pvt_info; + i7core_dev = pvt->i7core_dev; edac_mce_unregister(&pvt->edac_mce); /* retrieve references to resources, and free those resources */ mutex_lock(&i7core_edac_lock); - - /* FIXME: This should put the devices only for this mci!!! */ - i7core_put_devices(); + i7core_put_devices(i7core_dev); mutex_unlock(&i7core_edac_lock); kfree(mci->ctl_name); -- cgit v1.2.3 From 0f062792b48dc8389fb18cbfb9318625886644c7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 5 Sep 2009 12:16:19 -0300 Subject: i7core_edac: remove static counter for max sockets The number of sockets is now fully dynamic. Get rid of this obsolete var. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index c2266f820b0f..391348bf93d2 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -247,7 +247,6 @@ struct i7core_pvt { /* Static vars */ static LIST_HEAD(i7core_edac_list); static DEFINE_MUTEX(i7core_edac_lock); -static u8 max_num_sockets; #define PCI_DESCR(device, function, device_id) \ .dev = (device), \ -- cgit v1.2.3 From 22e6bcbdcf9279321dbe646c5a234b816db12881 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 5 Sep 2009 23:06:50 -0300 Subject: i7core_edac: change remove module strategy The old remove module stragegy didn't work on devices with multiple cores, since only one PCI device is used to open all mc's, due to Nehalem nature. Also, it were based at pdev value. However, this doesn't point to the pci device used at mci->dev. So, instead, it unregisters all devices at once, deleting them from the device list. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 55 +++++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 391348bf93d2..c3fec5de3e51 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1138,11 +1138,18 @@ static void i7core_put_devices(struct i7core_dev *i7core_dev) { int i; - for (i = 0; i < N_DEVS; i++) - pci_dev_put(i7core_dev->pdev[i]); - - list_del(&i7core_dev->list); + debugf0(__FILE__ ": %s()\n", __func__); + for (i = 0; i < N_DEVS; i++) { + struct pci_dev *pdev = i7core_dev->pdev[i]; + if (!pdev) + continue; + debugf0("Removing dev %02x:%02x.%d\n", + pdev->bus->number, + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); + pci_dev_put(pdev); + } kfree(i7core_dev->pdev); + list_del(&i7core_dev->list); kfree(i7core_dev); } @@ -1863,31 +1870,39 @@ fail0: static void __devexit i7core_remove(struct pci_dev *pdev) { struct mem_ctl_info *mci; - struct i7core_pvt *pvt; - struct i7core_dev *i7core_dev; + struct i7core_dev *i7core_dev, *tmp; debugf0(__FILE__ ": %s()\n", __func__); if (i7core_pci) edac_pci_release_generic_ctl(i7core_pci); + /* + * we have a trouble here: pdev value for removal will be wrong, since + * it will point to the X58 register used to detect that the machine + * is a Nehalem or upper design. However, due to the way several PCI + * devices are grouped together to provide MC functionality, we need + * to use a different method for releasing the devices + */ - mci = edac_mc_del_mc(&pdev->dev); - if (!mci) - return; - - /* Unregisters on edac_mce in order to receive memory errors */ - pvt = mci->pvt_info; - i7core_dev = pvt->i7core_dev; - edac_mce_unregister(&pvt->edac_mce); - - /* retrieve references to resources, and free those resources */ mutex_lock(&i7core_edac_lock); - i7core_put_devices(i7core_dev); + list_for_each_entry_safe(i7core_dev, tmp, &i7core_edac_list, list) { + mci = edac_mc_del_mc(&i7core_dev->pdev[0]->dev); + if (mci) { + struct i7core_pvt *pvt = mci->pvt_info; + + i7core_dev = pvt->i7core_dev; + edac_mce_unregister(&pvt->edac_mce); + kfree(mci->ctl_name); + edac_mc_free(mci); + i7core_put_devices(i7core_dev); + } else { + i7core_printk(KERN_ERR, + "Couldn't find mci for socket %d\n", + i7core_dev->socket); + } + } mutex_unlock(&i7core_edac_lock); - - kfree(mci->ctl_name); - edac_mc_free(mci); } MODULE_DEVICE_TABLE(pci, i7core_pci_tbl); -- cgit v1.2.3 From 4253868034221db6e42dbbb61e0305fe1757f8da Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 24 Sep 2009 09:59:13 -0300 Subject: i7core_edac: We need to use list_for_each_entry_safe to avoid errors Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index c3fec5de3e51..2e4b0abf9d43 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1124,6 +1124,7 @@ static struct mcidev_sysfs_attribute i7core_inj_attrs[] = { .show = i7core_ce_regs_show, .store = NULL, }, + { .attr = { .name = NULL } } }; /**************************************************************************** @@ -1155,9 +1156,9 @@ static void i7core_put_devices(struct i7core_dev *i7core_dev) static void i7core_put_all_devices(void) { - struct i7core_dev *i7core_dev; + struct i7core_dev *i7core_dev, *tmp; - list_for_each_entry(i7core_dev, &i7core_edac_list, list) + list_for_each_entry_safe(i7core_dev, tmp, &i7core_edac_list, list) i7core_put_devices(i7core_dev); } -- cgit v1.2.3 From 4af91889e02c9933823ca8c62fc6f05dfd15f3bd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 24 Sep 2009 09:58:26 -0300 Subject: i7core_edac: Avoid printing a warning when debug is disabled Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 2e4b0abf9d43..0478cc85e920 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -471,7 +471,6 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow) struct csrow_info *csr; struct pci_dev *pdev; int i, j; - u8 socket = pvt->i7core_dev->socket; unsigned long last_page = 0; enum edac_type mode; enum mem_type mtype; @@ -488,7 +487,7 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow) pci_read_config_dword(pdev, MC_CHANNEL_MAPPER, &pvt->info.ch_map); debugf0("QPI %d control=0x%08x status=0x%08x dod=0x%08x map=0x%08x\n", - socket, pvt->info.mc_control, pvt->info.mc_status, + pvt->i7core_dev->socket, pvt->info.mc_control, pvt->info.mc_status, pvt->info.max_dod, pvt->info.ch_map); if (ECC_ENABLED(pvt)) { -- cgit v1.2.3 From 9fa2fc2e2d641df7d69dc4e06cf2552c44b58e95 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 23 Sep 2009 16:26:09 -0300 Subject: edac_core: Allow the creation of sysfs groups Currently, all sysfs nodes are stored at /sys/.*/mc. (regex) However, sometimes it is needed to create attribute groups. This patch extends edac_core to allow groups creation. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/edac_core.h | 12 ++++++- drivers/edac/edac_mc_sysfs.c | 83 ++++++++++++++++++++++++++++++-------------- 2 files changed, 67 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index 001b2e797fb3..97071ff1d22d 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h @@ -341,12 +341,22 @@ struct csrow_info { struct channel_info *channels; }; +struct mcidev_sysfs_group { + const char *name; + struct mcidev_sysfs_attribute *mcidev_attr; + struct kobject kobj; +}; + + /* mcidev_sysfs_attribute structure * used for driver sysfs attributes and in mem_ctl_info * sysfs top level entries */ struct mcidev_sysfs_attribute { - struct attribute attr; + struct attribute attr; + + struct mcidev_sysfs_group *grp; + ssize_t (*show)(struct mem_ctl_info *,char *); ssize_t (*store)(struct mem_ctl_info *, const char *,size_t); }; diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 418b65f1a1da..655aa1a1f4f9 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -728,26 +728,43 @@ void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci) /* * edac_create_mci_instance_attributes - * create MC driver specific attributes at the topmost level - * directory of this mci instance. + * create MC driver specific attributes bellow an specified kobj + * This routine calls itself recursively, in order to create an entire + * object tree. */ -static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci) +static int edac_create_mci_instance_attributes( + struct mcidev_sysfs_attribute *sysfs_attrib, + struct kobject *kobj) { int err; - struct mcidev_sysfs_attribute *sysfs_attrib; - /* point to the start of the array and iterate over it - * adding each attribute listed to this mci instance's kobject - */ - sysfs_attrib = mci->mc_driver_sysfs_attributes; + while (sysfs_attrib) { + if (sysfs_attrib->grp) { + struct kobject *newkobj = &sysfs_attrib->grp->kobj; + debugf0("%s() grp %s\n", __func__, + sysfs_attrib->grp->name); + + err = kobject_init_and_add(newkobj, NULL, + kobj, + sysfs_attrib->grp->name); + if (err) + return err; + + err = edac_create_mci_instance_attributes( + sysfs_attrib->grp->mcidev_attr, newkobj); + if (err) + return err; + } else if (sysfs_attrib->attr.name) { + debugf0("%s() file %s\n", __func__, + sysfs_attrib->attr.name); + + err = sysfs_create_file(kobj, &sysfs_attrib->attr); + } else + break; - while (sysfs_attrib && sysfs_attrib->attr.name) { - err = sysfs_create_file(&mci->edac_mci_kobj, - (struct attribute*) sysfs_attrib); if (err) { return err; } - sysfs_attrib++; } @@ -759,19 +776,28 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci) * remove MC driver specific attributes at the topmost level * directory of this mci instance. */ -static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci) +static void edac_remove_mci_instance_attributes( + struct mcidev_sysfs_attribute *sysfs_attrib, + struct kobject *kobj) { - struct mcidev_sysfs_attribute *sysfs_attrib; - - /* point to the start of the array and iterate over it - * adding each attribute listed to this mci instance's kobject - */ - sysfs_attrib = mci->mc_driver_sysfs_attributes; - /* loop if there are attributes and until we hit a NULL entry */ - while (sysfs_attrib && sysfs_attrib->attr.name) { - sysfs_remove_file(&mci->edac_mci_kobj, - (struct attribute *) sysfs_attrib); + while (sysfs_attrib) { + if (sysfs_attrib->grp) { + struct kobject *newkobj = &sysfs_attrib->grp->kobj; + + debugf0("%s() grp %s\n", __func__, + sysfs_attrib->grp->name); + + edac_remove_mci_instance_attributes( + sysfs_attrib->grp->mcidev_attr, newkobj); + + kobject_put(newkobj); + } else if (sysfs_attrib->attr.name) { + debugf0("%s() file %s\n", __func__, + sysfs_attrib->attr.name); + sysfs_remove_file(kobj, &sysfs_attrib->attr); + } else + break; sysfs_attrib++; } } @@ -806,7 +832,9 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) * then create them now for the driver. */ if (mci->mc_driver_sysfs_attributes) { - err = edac_create_mci_instance_attributes(mci); + err = edac_create_mci_instance_attributes( + mci->mc_driver_sysfs_attributes, + &mci->edac_mci_kobj); if (err) { debugf1("%s() failure to create mci attributes\n", __func__); @@ -841,7 +869,8 @@ fail1: } /* remove the mci instance's attributes, if any */ - edac_remove_mci_instance_attributes(mci); + edac_remove_mci_instance_attributes( + mci->mc_driver_sysfs_attributes, &mci->edac_mci_kobj); /* remove the symlink */ sysfs_remove_link(kobj_mci, EDAC_DEVICE_SYMLINK); @@ -875,8 +904,8 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) debugf0("%s() remove_mci_instance\n", __func__); /* remove this mci instance's attribtes */ - edac_remove_mci_instance_attributes(mci); - + edac_remove_mci_instance_attributes(mci->mc_driver_sysfs_attributes, + &mci->edac_mci_kobj); debugf0("%s() unregister this mci kobj\n", __func__); /* unregister this instance's kobject */ -- cgit v1.2.3 From a5538e531fc1e00ac7185dcfcebf33c37b5d742e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 23 Sep 2009 18:56:47 -0300 Subject: i7core_edac: Add support for sysfs addrmatch group Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 173 ++++++++++++++++++--------------------------- 1 file changed, 70 insertions(+), 103 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 0478cc85e920..afa5281e8df9 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -778,105 +778,59 @@ static ssize_t i7core_inject_eccmask_show(struct mem_ctl_info *mci, * 23:16 and 31:24). Flipping bits in two symbol pairs will cause an * uncorrectable error to be injected. */ -static ssize_t i7core_inject_addrmatch_store(struct mem_ctl_info *mci, - const char *data, size_t count) -{ - struct i7core_pvt *pvt = mci->pvt_info; - char *cmd, *val; - long value; - int rc; - - if (pvt->inject.enable) - disable_inject(mci); - - do { - cmd = strsep((char **) &data, ":"); - if (!cmd) - break; - val = strsep((char **) &data, " \n\t"); - if (!val) - return cmd - data; - - if (!strcasecmp(val, "any")) - value = -1; - else { - rc = strict_strtol(val, 10, &value); - if ((rc < 0) || (value < 0)) - return cmd - data; - } - - if (!strcasecmp(cmd, "channel")) { - if (value < 3) - pvt->inject.channel = value; - else - return cmd - data; - } else if (!strcasecmp(cmd, "dimm")) { - if (value < 3) - pvt->inject.dimm = value; - else - return cmd - data; - } else if (!strcasecmp(cmd, "rank")) { - if (value < 4) - pvt->inject.rank = value; - else - return cmd - data; - } else if (!strcasecmp(cmd, "bank")) { - if (value < 32) - pvt->inject.bank = value; - else - return cmd - data; - } else if (!strcasecmp(cmd, "page")) { - if (value <= 0xffff) - pvt->inject.page = value; - else - return cmd - data; - } else if (!strcasecmp(cmd, "col") || - !strcasecmp(cmd, "column")) { - if (value <= 0x3fff) - pvt->inject.col = value; - else - return cmd - data; - } - } while (1); - return count; +#define DECLARE_ADDR_MATCH(param, limit) \ +static ssize_t i7core_inject_store_##param( \ + struct mem_ctl_info *mci, \ + const char *data, size_t count) \ +{ \ + struct i7core_pvt *pvt = mci->pvt_info; \ + long value; \ + int rc; \ + \ + if (pvt->inject.enable) \ + disable_inject(mci); \ + \ + if (!strcasecmp(data, "any")) \ + value = -1; \ + else { \ + rc = strict_strtoul(data, 10, &value); \ + if ((rc < 0) || (value >= limit)) \ + return -EIO; \ + } \ + \ + pvt->inject.param = value; \ + \ + return count; \ +} \ + \ +static ssize_t i7core_inject_show_##param( \ + struct mem_ctl_info *mci, \ + char *data) \ +{ \ + struct i7core_pvt *pvt = mci->pvt_info; \ + if (pvt->inject.param < 0) \ + return sprintf(data, "any\n"); \ + else \ + return sprintf(data, "%d\n", pvt->inject.param);\ } -static ssize_t i7core_inject_addrmatch_show(struct mem_ctl_info *mci, - char *data) -{ - struct i7core_pvt *pvt = mci->pvt_info; - char channel[4], dimm[4], bank[4], rank[4], page[7], col[7]; - - if (pvt->inject.channel < 0) - sprintf(channel, "any"); - else - sprintf(channel, "%d", pvt->inject.channel); - if (pvt->inject.dimm < 0) - sprintf(dimm, "any"); - else - sprintf(dimm, "%d", pvt->inject.dimm); - if (pvt->inject.bank < 0) - sprintf(bank, "any"); - else - sprintf(bank, "%d", pvt->inject.bank); - if (pvt->inject.rank < 0) - sprintf(rank, "any"); - else - sprintf(rank, "%d", pvt->inject.rank); - if (pvt->inject.page < 0) - sprintf(page, "any"); - else - sprintf(page, "0x%04x", pvt->inject.page); - if (pvt->inject.col < 0) - sprintf(col, "any"); - else - sprintf(col, "0x%04x", pvt->inject.col); +#define ATTR_ADDR_MATCH(param) \ + { \ + .attr = { \ + .name = #param, \ + .mode = (S_IRUGO | S_IWUSR) \ + }, \ + .show = i7core_inject_show_##param, \ + .store = i7core_inject_store_##param, \ + } - return sprintf(data, "channel: %s\ndimm: %s\nbank: %s\n" - "rank: %s\npage: %s\ncolumn: %s\n", - channel, dimm, bank, rank, page, col); -} +DECLARE_ADDR_MATCH(channel, 3); +DECLARE_ADDR_MATCH(dimm, 3); +DECLARE_ADDR_MATCH(rank, 4); +DECLARE_ADDR_MATCH(bank, 32); +DECLARE_ADDR_MATCH(page, 0x10000); +DECLARE_ADDR_MATCH(col, 0x4000); static int write_and_test(struct pci_dev *dev, int where, u32 val) { @@ -1079,7 +1033,25 @@ static ssize_t i7core_ce_regs_show(struct mem_ctl_info *mci, char *data) /* * Sysfs struct */ -static struct mcidev_sysfs_attribute i7core_inj_attrs[] = { + + +static struct mcidev_sysfs_attribute i7core_addrmatch_attrs[] = { + ATTR_ADDR_MATCH(channel), + ATTR_ADDR_MATCH(dimm), + ATTR_ADDR_MATCH(rank), + ATTR_ADDR_MATCH(bank), + ATTR_ADDR_MATCH(page), + ATTR_ADDR_MATCH(col), + { .attr = { .name = NULL } } +}; + + +static struct mcidev_sysfs_group i7core_inject_addrmatch = { + .name = "inject_addrmatch", + .mcidev_attr = i7core_addrmatch_attrs, +}; + +static struct mcidev_sysfs_attribute i7core_sysfs_attrs[] = { { .attr = { .name = "inject_section", @@ -1102,12 +1074,7 @@ static struct mcidev_sysfs_attribute i7core_inj_attrs[] = { .show = i7core_inject_eccmask_show, .store = i7core_inject_eccmask_store, }, { - .attr = { - .name = "inject_addrmatch", - .mode = (S_IRUGO | S_IWUSR) - }, - .show = i7core_inject_addrmatch_show, - .store = i7core_inject_addrmatch_store, + .grp = &i7core_inject_addrmatch, }, { .attr = { .name = "inject_enable", @@ -1750,7 +1717,7 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev, i7core_dev->socket); mci->dev_name = pci_name(i7core_dev->pdev[0]); mci->ctl_page_to_phys = NULL; - mci->mc_driver_sysfs_attributes = i7core_inj_attrs; + mci->mc_driver_sysfs_attributes = i7core_sysfs_attrs; /* Set the function pointer to an actual operation function */ mci->edac_check = i7core_check_error; -- cgit v1.2.3 From cc301b3ae3f615fe243f023e68e22b8298a6f883 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 24 Sep 2009 16:23:42 -0300 Subject: edac: store/show methods for device groups weren't working Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/edac_core.h | 2 ++ drivers/edac/edac_mc_sysfs.c | 85 ++++++++++++++++++++++++++++++++++++++++---- drivers/edac/i7core_edac.c | 10 ++++-- 3 files changed, 88 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index 97071ff1d22d..02bbbc9696d9 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h @@ -345,6 +345,8 @@ struct mcidev_sysfs_group { const char *name; struct mcidev_sysfs_attribute *mcidev_attr; struct kobject kobj; + + struct mem_ctl_info *mci; /* the parent */ }; diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 655aa1a1f4f9..6088ae6e8ea5 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -557,6 +557,8 @@ static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr, struct mem_ctl_info *mem_ctl_info = to_mci(kobj); struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr); + debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info); + if (mcidev_attr->show) return mcidev_attr->show(mem_ctl_info, buffer); @@ -569,6 +571,8 @@ static ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr, struct mem_ctl_info *mem_ctl_info = to_mci(kobj); struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr); + debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info); + if (mcidev_attr->store) return mcidev_attr->store(mem_ctl_info, buffer, count); @@ -726,32 +730,97 @@ void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci) #define EDAC_DEVICE_SYMLINK "device" +#define grp_to_mci(k) (container_of(k, struct mcidev_sysfs_group, kobj)->mci) + +/* MCI show/store functions for top most object */ +static ssize_t inst_grp_show(struct kobject *kobj, struct attribute *attr, + char *buffer) +{ + struct mem_ctl_info *mem_ctl_info = grp_to_mci(kobj); + struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr); + + debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info); + + if (mcidev_attr->show) + return mcidev_attr->show(mem_ctl_info, buffer); + + return -EIO; +} + +static ssize_t inst_grp_store(struct kobject *kobj, struct attribute *attr, + const char *buffer, size_t count) +{ + struct mem_ctl_info *mem_ctl_info = grp_to_mci(kobj); + struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr); + + debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info); + + if (mcidev_attr->store) + return mcidev_attr->store(mem_ctl_info, buffer, count); + + return -EIO; +} + +/* No memory to release for this kobj */ +static void edac_inst_grp_release(struct kobject *kobj) +{ + struct mcidev_sysfs_group *grp; + struct mem_ctl_info *mci; + + debugf1("%s()\n", __func__); + + grp = container_of(kobj, struct mcidev_sysfs_group, kobj); + mci = grp->mci; + + kobject_put(&mci->edac_mci_kobj); +} + +/* Intermediate show/store table */ +static struct sysfs_ops inst_grp_ops = { + .show = inst_grp_show, + .store = inst_grp_store +}; + +/* the kobj_type instance for a instance group */ +static struct kobj_type ktype_inst_grp = { + .release = edac_inst_grp_release, + .sysfs_ops = &inst_grp_ops, + .default_attrs = (struct attribute **)default_csrow_attr, +}; + + /* * edac_create_mci_instance_attributes * create MC driver specific attributes bellow an specified kobj * This routine calls itself recursively, in order to create an entire * object tree. */ -static int edac_create_mci_instance_attributes( +static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci, struct mcidev_sysfs_attribute *sysfs_attrib, struct kobject *kobj) { int err; + debugf1("%s()\n", __func__); + while (sysfs_attrib) { if (sysfs_attrib->grp) { struct kobject *newkobj = &sysfs_attrib->grp->kobj; - debugf0("%s() grp %s\n", __func__, - sysfs_attrib->grp->name); + debugf0("%s() grp %s, mci %p\n", __func__, + sysfs_attrib->grp->name, mci); + + sysfs_attrib->grp->mci = mci; - err = kobject_init_and_add(newkobj, NULL, + err = kobject_init_and_add(newkobj, &ktype_inst_grp, kobj, sysfs_attrib->grp->name); if (err) return err; - err = edac_create_mci_instance_attributes( - sysfs_attrib->grp->mcidev_attr, newkobj); + err = edac_create_mci_instance_attributes(mci, + sysfs_attrib->grp->mcidev_attr, + newkobj); + if (err) return err; } else if (sysfs_attrib->attr.name) { @@ -780,6 +849,8 @@ static void edac_remove_mci_instance_attributes( struct mcidev_sysfs_attribute *sysfs_attrib, struct kobject *kobj) { + debugf1("%s()\n", __func__); + /* loop if there are attributes and until we hit a NULL entry */ while (sysfs_attrib) { if (sysfs_attrib->grp) { @@ -832,7 +903,7 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) * then create them now for the driver. */ if (mci->mc_driver_sysfs_attributes) { - err = edac_create_mci_instance_attributes( + err = edac_create_mci_instance_attributes(mci, mci->mc_driver_sysfs_attributes, &mci->edac_mci_kobj); if (err) { diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index afa5281e8df9..e013004745de 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -784,10 +784,13 @@ static ssize_t i7core_inject_store_##param( \ struct mem_ctl_info *mci, \ const char *data, size_t count) \ { \ - struct i7core_pvt *pvt = mci->pvt_info; \ + struct i7core_pvt *pvt; \ long value; \ int rc; \ \ + debugf1("%s()\n", __func__); \ + pvt = mci->pvt_info; \ + \ if (pvt->inject.enable) \ disable_inject(mci); \ \ @@ -808,7 +811,10 @@ static ssize_t i7core_inject_show_##param( \ struct mem_ctl_info *mci, \ char *data) \ { \ - struct i7core_pvt *pvt = mci->pvt_info; \ + struct i7core_pvt *pvt; \ + \ + pvt = mci->pvt_info; \ + debugf1("%s() pvt=%p\n", __func__, pvt); \ if (pvt->inject.param < 0) \ return sprintf(data, "any\n"); \ else \ -- cgit v1.2.3 From c419d921e68c54232ce6d369a3b528cd7644b2ae Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 24 Sep 2009 16:36:32 -0300 Subject: edac: Don't create csrow entries on instance groups Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/edac_mc_sysfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 6088ae6e8ea5..f689d7d6ab46 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -785,7 +785,6 @@ static struct sysfs_ops inst_grp_ops = { static struct kobj_type ktype_inst_grp = { .release = edac_inst_grp_release, .sysfs_ops = &inst_grp_ops, - .default_attrs = (struct attribute **)default_csrow_attr, }; @@ -806,13 +805,14 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci, while (sysfs_attrib) { if (sysfs_attrib->grp) { struct kobject *newkobj = &sysfs_attrib->grp->kobj; + debugf0("%s() grp %s, mci %p\n", __func__, sysfs_attrib->grp->name, mci); sysfs_attrib->grp->mci = mci; err = kobject_init_and_add(newkobj, &ktype_inst_grp, - kobj, + &mci->edac_mci_kobj, sysfs_attrib->grp->name); if (err) return err; -- cgit v1.2.3 From f338d736910edf00e8426ee4322cfda585268d50 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 24 Sep 2009 17:25:43 -0300 Subject: i7core_edac: Convert UDIMM error counters into a proper sysfs group Instead of displaying 3 values at the same var, break it into 3 different sysfs nodes: /sys/devices/system/edac/mc/mc0/all_channel_counts/udimm0 /sys/devices/system/edac/mc/mc0/all_channel_counts/udimm1 /sys/devices/system/edac/mc/mc0/all_channel_counts/udimm2 For registered dimms, however, the error counters are already being displayed at: /sys/devices/system/edac/mc/mc0/csrow*/ce_count So, there's no need to add any extra sysfs nodes. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 81 +++++++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index e013004745de..97f6d1759c99 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1003,38 +1003,32 @@ static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci, return sprintf(data, "%d\n", pvt->inject.enable); } -static ssize_t i7core_ce_regs_show(struct mem_ctl_info *mci, char *data) -{ - unsigned i, count, total = 0; - struct i7core_pvt *pvt = mci->pvt_info; +#define DECLARE_COUNTER(param) \ +static ssize_t i7core_show_counter_##param( \ + struct mem_ctl_info *mci, \ + char *data) \ +{ \ + struct i7core_pvt *pvt = mci->pvt_info; \ + \ + debugf1("%s() \n", __func__); \ + if (!pvt->ce_count_available || (pvt->is_registered)) \ + return sprintf(data, "data unavailable\n"); \ + return sprintf(data, "%lu\n", \ + pvt->udimm_ce_count[param]); \ +} - if (!pvt->ce_count_available) { - count = sprintf(data, "data unavailable\n"); - return 0; - } - if (!pvt->is_registered) { - count = sprintf(data, "all channels " - "UDIMM0: %lu UDIMM1: %lu UDIMM2: %lu\n", - pvt->udimm_ce_count[0], - pvt->udimm_ce_count[1], - pvt->udimm_ce_count[2]); - data += count; - total += count; - } else { - for (i = 0; i < NUM_CHANS; i++) { - count = sprintf(data, "channel %d RDIMM0: %lu " - "RDIMM1: %lu RDIMM2: %lu\n", - i, - pvt->rdimm_ce_count[i][0], - pvt->rdimm_ce_count[i][1], - pvt->rdimm_ce_count[i][2]); - data += count; - total += count; - } +#define ATTR_COUNTER(param) \ + { \ + .attr = { \ + .name = __stringify(udimm##param), \ + .mode = (S_IRUGO | S_IWUSR) \ + }, \ + .show = i7core_show_counter_##param \ } - return total; -} +DECLARE_COUNTER(0); +DECLARE_COUNTER(1); +DECLARE_COUNTER(2); /* * Sysfs struct @@ -1051,12 +1045,22 @@ static struct mcidev_sysfs_attribute i7core_addrmatch_attrs[] = { { .attr = { .name = NULL } } }; - static struct mcidev_sysfs_group i7core_inject_addrmatch = { .name = "inject_addrmatch", .mcidev_attr = i7core_addrmatch_attrs, }; +static struct mcidev_sysfs_attribute i7core_udimm_counters_attrs[] = { + ATTR_COUNTER(0), + ATTR_COUNTER(1), + ATTR_COUNTER(2), +}; + +static struct mcidev_sysfs_group i7core_udimm_counters = { + .name = "all_channel_counts", + .mcidev_attr = i7core_udimm_counters_attrs, +}; + static struct mcidev_sysfs_attribute i7core_sysfs_attrs[] = { { .attr = { @@ -1088,14 +1092,8 @@ static struct mcidev_sysfs_attribute i7core_sysfs_attrs[] = { }, .show = i7core_inject_enable_show, .store = i7core_inject_enable_store, - }, { - .attr = { - .name = "corrected_error_counts", - .mode = (S_IRUGO | S_IWUSR) - }, - .show = i7core_ce_regs_show, - .store = NULL, }, + { .attr = { .name = NULL } }, /* Reserved for udimm counters */ { .attr = { .name = NULL } } }; @@ -1323,6 +1321,15 @@ static int mci_bind_devs(struct mem_ctl_info *mci, pvt->is_registered = 1; } + /* + * Add extra nodes to count errors on udimm + * For registered memory, this is not needed, since the counters + * are already displayed at the standard locations + */ + if (!pvt->is_registered) + i7core_sysfs_attrs[ARRAY_SIZE(i7core_sysfs_attrs)-2].grp = + &i7core_udimm_counters; + return 0; error: -- cgit v1.2.3 From b968759ee7102f86fec5f3349f7a8ab4556884a3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 25 Sep 2009 13:42:25 -0300 Subject: edac: Create an unique instance for each kobj Current code only works when there's just one memory controller, since we need one kobj for each instance. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/edac_core.h | 21 +++++++++---- drivers/edac/edac_mc_sysfs.c | 75 +++++++++++++++++++++++++++++--------------- 2 files changed, 64 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index 02bbbc9696d9..efca9343d26a 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h @@ -342,23 +342,29 @@ struct csrow_info { }; struct mcidev_sysfs_group { - const char *name; - struct mcidev_sysfs_attribute *mcidev_attr; - struct kobject kobj; + const char *name; /* group name */ + struct mcidev_sysfs_attribute *mcidev_attr; /* group attributes */ +}; + +struct mcidev_sysfs_group_kobj { + struct list_head list; /* list for all instances within a mc */ + + struct kobject kobj; /* kobj for the group */ + struct mcidev_sysfs_group *grp; /* group description table */ struct mem_ctl_info *mci; /* the parent */ }; - /* mcidev_sysfs_attribute structure * used for driver sysfs attributes and in mem_ctl_info * sysfs top level entries */ struct mcidev_sysfs_attribute { + /* It should use either attr or grp */ struct attribute attr; + struct mcidev_sysfs_group *grp; /* Points to a group of attributes */ - struct mcidev_sysfs_group *grp; - + /* Ops for show/store values at the attribute - not used on group */ ssize_t (*show)(struct mem_ctl_info *,char *); ssize_t (*store)(struct mem_ctl_info *, const char *,size_t); }; @@ -436,6 +442,9 @@ struct mem_ctl_info { /* edac sysfs device control */ struct kobject edac_mci_kobj; + /* list for all grp instances within a mc */ + struct list_head grp_kobj_list; + /* Additional top controller level attributes, but specified * by the low level driver. * diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index f689d7d6ab46..c200c2fd43ea 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -730,7 +730,7 @@ void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci) #define EDAC_DEVICE_SYMLINK "device" -#define grp_to_mci(k) (container_of(k, struct mcidev_sysfs_group, kobj)->mci) +#define grp_to_mci(k) (container_of(k, struct mcidev_sysfs_group_kobj, kobj)->mci) /* MCI show/store functions for top most object */ static ssize_t inst_grp_show(struct kobject *kobj, struct attribute *attr, @@ -764,12 +764,12 @@ static ssize_t inst_grp_store(struct kobject *kobj, struct attribute *attr, /* No memory to release for this kobj */ static void edac_inst_grp_release(struct kobject *kobj) { - struct mcidev_sysfs_group *grp; + struct mcidev_sysfs_group_kobj *grp; struct mem_ctl_info *mci; debugf1("%s()\n", __func__); - grp = container_of(kobj, struct mcidev_sysfs_group, kobj); + grp = container_of(kobj, struct mcidev_sysfs_group_kobj, kobj); mci = grp->mci; kobject_put(&mci->edac_mci_kobj); @@ -804,22 +804,30 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci, while (sysfs_attrib) { if (sysfs_attrib->grp) { - struct kobject *newkobj = &sysfs_attrib->grp->kobj; + struct mcidev_sysfs_group_kobj *grp_kobj; + + grp_kobj = kzalloc(sizeof(*grp_kobj), GFP_KERNEL); + if (!grp_kobj) + return -ENOMEM; + + list_add_tail(&grp_kobj->list, &mci->grp_kobj_list); + + grp_kobj->grp = sysfs_attrib->grp; + grp_kobj->mci = mci; debugf0("%s() grp %s, mci %p\n", __func__, sysfs_attrib->grp->name, mci); - sysfs_attrib->grp->mci = mci; - - err = kobject_init_and_add(newkobj, &ktype_inst_grp, + err = kobject_init_and_add(&grp_kobj->kobj, + &ktype_inst_grp, &mci->edac_mci_kobj, sysfs_attrib->grp->name); if (err) return err; err = edac_create_mci_instance_attributes(mci, - sysfs_attrib->grp->mcidev_attr, - newkobj); + grp_kobj->grp->mcidev_attr, + &grp_kobj->kobj); if (err) return err; @@ -845,25 +853,27 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci, * remove MC driver specific attributes at the topmost level * directory of this mci instance. */ -static void edac_remove_mci_instance_attributes( +static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci, struct mcidev_sysfs_attribute *sysfs_attrib, - struct kobject *kobj) + struct kobject *kobj, int count) { + struct mcidev_sysfs_group_kobj *grp_kobj, *tmp; + debugf1("%s()\n", __func__); - /* loop if there are attributes and until we hit a NULL entry */ + /* + * loop if there are attributes and until we hit a NULL entry + * Remove first all the atributes + */ while (sysfs_attrib) { if (sysfs_attrib->grp) { - struct kobject *newkobj = &sysfs_attrib->grp->kobj; - - debugf0("%s() grp %s\n", __func__, - sysfs_attrib->grp->name); - - edac_remove_mci_instance_attributes( - sysfs_attrib->grp->mcidev_attr, newkobj); - - kobject_put(newkobj); - } else if (sysfs_attrib->attr.name) { + list_for_each_entry(grp_kobj, &mci->grp_kobj_list, + list) + if (grp_kobj->grp == sysfs_attrib->grp) + edac_remove_mci_instance_attributes(mci, + grp_kobj->grp->mcidev_attr, + &grp_kobj->kobj, count + 1); + } else if (sysfs_attrib->attr.name) { debugf0("%s() file %s\n", __func__, sysfs_attrib->attr.name); sysfs_remove_file(kobj, &sysfs_attrib->attr); @@ -871,6 +881,16 @@ static void edac_remove_mci_instance_attributes( break; sysfs_attrib++; } + + /* + * Now that all attributes got removed, it is save to remove all groups + */ + if (!count) + list_for_each_entry_safe(grp_kobj, tmp, &mci->grp_kobj_list, + list) { + debugf0("%s() grp %s\n", __func__, grp_kobj->grp->name); + kobject_put(&grp_kobj->kobj); + } } @@ -891,6 +911,8 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) debugf0("%s() idx=%d\n", __func__, mci->mc_idx); + INIT_LIST_HEAD(&mci->grp_kobj_list); + /* create a symlink for the device */ err = sysfs_create_link(kobj_mci, &mci->dev->kobj, EDAC_DEVICE_SYMLINK); @@ -940,8 +962,8 @@ fail1: } /* remove the mci instance's attributes, if any */ - edac_remove_mci_instance_attributes( - mci->mc_driver_sysfs_attributes, &mci->edac_mci_kobj); + edac_remove_mci_instance_attributes(mci, + mci->mc_driver_sysfs_attributes, &mci->edac_mci_kobj, 0); /* remove the symlink */ sysfs_remove_link(kobj_mci, EDAC_DEVICE_SYMLINK); @@ -975,8 +997,9 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) debugf0("%s() remove_mci_instance\n", __func__); /* remove this mci instance's attribtes */ - edac_remove_mci_instance_attributes(mci->mc_driver_sysfs_attributes, - &mci->edac_mci_kobj); + edac_remove_mci_instance_attributes(mci, + mci->mc_driver_sysfs_attributes, + &mci->edac_mci_kobj, 0); debugf0("%s() unregister this mci kobj\n", __func__); /* unregister this instance's kobject */ -- cgit v1.2.3 From ca9c90ba09ca3c9799319f46a56f397afbf617c2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 4 Oct 2009 10:15:40 -0300 Subject: i7core_edac: Use a lockless ringbuffer Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 83 ++++++++++++++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 97f6d1759c99..94aeca011ac4 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include @@ -239,9 +238,16 @@ struct i7core_pvt { /* mcelog glue */ struct edac_mce edac_mce; + + /* Fifo double buffers */ struct mce mce_entry[MCE_LOG_LEN]; - unsigned mce_count; - spinlock_t mce_lock; + struct mce mce_outentry[MCE_LOG_LEN]; + + /* Fifo in/out counters */ + unsigned mce_in, mce_out; + + /* Count indicator to show errors not got */ + unsigned mce_overrun; }; /* Static vars */ @@ -1617,30 +1623,50 @@ static void i7core_check_error(struct mem_ctl_info *mci) struct i7core_pvt *pvt = mci->pvt_info; int i; unsigned count = 0; - struct mce *m = NULL; - unsigned long flags; + struct mce *m; - /* Copy all mce errors into a temporary buffer */ - spin_lock_irqsave(&pvt->mce_lock, flags); - if (pvt->mce_count) { - m = kmalloc(sizeof(*m) * pvt->mce_count, GFP_ATOMIC); + /* + * MCE first step: Copy all mce errors into a temporary buffer + * We use a double buffering here, to reduce the risk of + * loosing an error. + */ + smp_rmb(); + count = (pvt->mce_out + sizeof(mce_entry) - pvt->mce_in) + % sizeof(mce_entry); + if (!count) + return; - if (m) { - count = pvt->mce_count; - memcpy(m, &pvt->mce_entry, sizeof(*m) * count); - } - pvt->mce_count = 0; - } + m = pvt->mce_outentry; + if (pvt->mce_in + count > sizeof(mce_entry)) { + unsigned l = sizeof(mce_entry) - pvt->mce_in; - spin_unlock_irqrestore(&pvt->mce_lock, flags); + memcpy(m, &pvt->mce_entry[pvt->mce_in], sizeof(*m) * l); + smp_wmb(); + pvt->mce_in = 0; + count -= l; + m += l; + } + memcpy(m, &pvt->mce_entry[pvt->mce_in], sizeof(*m) * count); + smp_wmb(); + pvt->mce_in += count; + + smp_rmb(); + if (pvt->mce_overrun) { + i7core_printk(KERN_ERR, "Lost %d memory errors\n", + pvt->mce_overrun); + smp_wmb(); + pvt->mce_overrun = 0; + } - /* proccess mcelog errors */ + /* + * MCE second step: parse errors and display + */ for (i = 0; i < count; i++) - i7core_mce_output_error(mci, &m[i]); + i7core_mce_output_error(mci, &pvt->mce_outentry[i]); - kfree(m); - - /* check memory count errors */ + /* + * Now, let's increment CE error counts + */ if (!pvt->is_registered) i7core_udimm_check_mc_ecc_err(mci); else @@ -1657,7 +1683,6 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) { struct mem_ctl_info *mci = priv; struct i7core_pvt *pvt = mci->pvt_info; - unsigned long flags; /* * Just let mcelog handle it if the error is @@ -1679,12 +1704,15 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) return 0; } - spin_lock_irqsave(&pvt->mce_lock, flags); - if (pvt->mce_count < MCE_LOG_LEN) { - memcpy(&pvt->mce_entry[pvt->mce_count], mce, sizeof(*mce)); - pvt->mce_count++; + smp_rmb(); + if ((pvt->mce_out + 1) % sizeof(mce_entry) == pvt->mce_in) { + smp_wmb(); + pvt->mce_overrun++; + return 0; } - spin_unlock_irqrestore(&pvt->mce_lock, flags); + smp_wmb(); + pvt->mce_out = (pvt->mce_out + 1) % sizeof(mce_entry); + memcpy(&pvt->mce_entry[pvt->mce_out], mce, sizeof(*mce)); /* Handle fatal errors immediately */ if (mce->mcgstatus & 1) @@ -1777,7 +1805,6 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev, /* Registers on edac_mce in order to receive memory errors */ pvt->edac_mce.priv = mci; pvt->edac_mce.check_error = i7core_mce_check_error; - spin_lock_init(&pvt->mce_lock); rc = edac_mce_register(&pvt->edac_mce); if (unlikely(rc < 0)) { -- cgit v1.2.3 From 4f87fad1d32fcdda448f9eb430c9c234a1939ece Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 4 Oct 2009 11:54:56 -0300 Subject: i7core_edac: Better parse "any" addrmask Instead of accepting just "any", accept also "any\n" Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 94aeca011ac4..477b62a74dbf 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -800,7 +800,7 @@ static ssize_t i7core_inject_store_##param( \ if (pvt->inject.enable) \ disable_inject(mci); \ \ - if (!strcasecmp(data, "any")) \ + if (!strcasecmp(data, "any") || !strcasecmp(data, "any\n"))\ value = -1; \ else { \ rc = strict_strtoul(data, 10, &value); \ -- cgit v1.2.3 From 6e103be1c7c4adb50f25aaf1f1e8f828833c1719 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 5 Oct 2009 09:40:09 -0300 Subject: i7core_edac: First store, then increment Fix ringbuffer store logic. While here, add a few comments to the code and remove the undesired printk that could otherwise be called during NMI time. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 477b62a74dbf..59ec44175560 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1678,6 +1678,8 @@ static void i7core_check_error(struct mem_ctl_info *mci) * This routine simply queues mcelog errors, and * return. The error itself should be handled later * by i7core_check_error. + * WARNING: As this routine should be called at NMI time, extra care should + * be taken to avoid deadlocks, and to be as fast as possible. */ static int i7core_mce_check_error(void *priv, struct mce *mce) { @@ -1696,13 +1698,8 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) return 0; /* Only handle if it is the right mc controller */ - if (cpu_data(mce->cpu).phys_proc_id != pvt->i7core_dev->socket) { - debugf0("mc%d: ignoring mce log for socket %d. " - "Another mc should get it.\n", - pvt->i7core_dev->socket, - cpu_data(mce->cpu).phys_proc_id); + if (cpu_data(mce->cpu).phys_proc_id != pvt->i7core_dev->socket) return 0; - } smp_rmb(); if ((pvt->mce_out + 1) % sizeof(mce_entry) == pvt->mce_in) { @@ -1710,9 +1707,11 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) pvt->mce_overrun++; return 0; } + + /* Copy memory error at the ringbuffer */ + memcpy(&pvt->mce_entry[pvt->mce_out], mce, sizeof(*mce)); smp_wmb(); pvt->mce_out = (pvt->mce_out + 1) % sizeof(mce_entry); - memcpy(&pvt->mce_entry[pvt->mce_out], mce, sizeof(*mce)); /* Handle fatal errors immediately */ if (mce->mcgstatus & 1) -- cgit v1.2.3 From 321ece4dda32f52d4a28d6eb11f2ca2a5c93c191 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 8 Oct 2009 13:11:08 -0300 Subject: i7core_edac: Fix ringbuffer maxsize Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 59ec44175560..c2857f60ae6a 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1631,14 +1631,14 @@ static void i7core_check_error(struct mem_ctl_info *mci) * loosing an error. */ smp_rmb(); - count = (pvt->mce_out + sizeof(mce_entry) - pvt->mce_in) - % sizeof(mce_entry); + count = (pvt->mce_out + MCE_LOG_LEN - pvt->mce_in) + % MCE_LOG_LEN; if (!count) return; m = pvt->mce_outentry; - if (pvt->mce_in + count > sizeof(mce_entry)) { - unsigned l = sizeof(mce_entry) - pvt->mce_in; + if (pvt->mce_in + count > MCE_LOG_LEN) { + unsigned l = MCE_LOG_LEN - pvt->mce_in; memcpy(m, &pvt->mce_entry[pvt->mce_in], sizeof(*m) * l); smp_wmb(); @@ -1702,7 +1702,7 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) return 0; smp_rmb(); - if ((pvt->mce_out + 1) % sizeof(mce_entry) == pvt->mce_in) { + if ((pvt->mce_out + 1) % MCE_LOG_LEN == pvt->mce_in) { smp_wmb(); pvt->mce_overrun++; return 0; @@ -1711,7 +1711,7 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) /* Copy memory error at the ringbuffer */ memcpy(&pvt->mce_entry[pvt->mce_out], mce, sizeof(*mce)); smp_wmb(); - pvt->mce_out = (pvt->mce_out + 1) % sizeof(mce_entry); + pvt->mce_out = (pvt->mce_out + 1) % MCE_LOG_LEN; /* Handle fatal errors immediately */ if (mce->mcgstatus & 1) -- cgit v1.2.3 From fd3826549db7f73d22b9c9abb80e01effb95c2ba Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 14 Oct 2009 06:07:07 -0300 Subject: i7core_edac: PCI device is called NONCORE, instead of NOCORE Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index c2857f60ae6a..bb538dfbdc6c 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -291,7 +291,7 @@ struct pci_id_descr pci_dev_descr[] = { * the probing code needs to test for the other address in case of * failure of this one */ - { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_I7_NOCORE) }, + { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_I7_NONCORE) }, }; #define N_DEVS ARRAY_SIZE(pci_dev_descr) @@ -1177,9 +1177,9 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno) * is at addr 8086:2c40, instead of 8086:2c41. So, we need * to probe for the alternate address in case of failure */ - if (pci_dev_descr[devno].dev_id == PCI_DEVICE_ID_INTEL_I7_NOCORE && !pdev) + if (pci_dev_descr[devno].dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev) pdev = pci_get_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_I7_NOCORE_ALT, *prev); + PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT, *prev); if (!pdev) { if (*prev) { -- cgit v1.2.3 From de06eeef5809a69ff4daaae2bd63977e5404553d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 14 Oct 2009 08:02:40 -0300 Subject: i7core_edac: Use a more generic approach for probing PCI devices Currently, only one PCI set of tables is allowed. This prevents using the driver for other devices like Lynnfield, with have a different set of PCI ID's. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 79 +++++++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index bb538dfbdc6c..b6fce2e38e3d 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -202,12 +202,14 @@ struct pci_id_descr { int dev; int func; int dev_id; + int optional; }; struct i7core_dev { struct list_head list; u8 socket; struct pci_dev **pdev; + int n_devs; struct mem_ctl_info *mci; }; @@ -259,11 +261,12 @@ static DEFINE_MUTEX(i7core_edac_lock); .func = (function), \ .dev_id = (device_id) -struct pci_id_descr pci_dev_descr[] = { +struct pci_id_descr pci_dev_descr_i7core[] = { /* Memory controller */ { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_I7_MCR) }, { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_I7_MC_TAD) }, - { PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_I7_MC_RAS) }, /* if RDIMM */ + /* Exists only for RDIMM */ + { PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_I7_MC_RAS), .optional = 1 }, { PCI_DESCR(3, 4, PCI_DEVICE_ID_INTEL_I7_MC_TEST) }, /* Channel 0 */ @@ -294,7 +297,6 @@ struct pci_id_descr pci_dev_descr[] = { { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_I7_NONCORE) }, }; -#define N_DEVS ARRAY_SIZE(pci_dev_descr) /* * pci_device_id table for which devices we are looking for @@ -380,7 +382,7 @@ static struct pci_dev *get_pdev_slot_func(u8 socket, unsigned slot, if (!i7core_dev) return NULL; - for (i = 0; i < N_DEVS; i++) { + for (i = 0; i < i7core_dev->n_devs; i++) { if (!i7core_dev->pdev[i]) continue; @@ -1116,7 +1118,7 @@ static void i7core_put_devices(struct i7core_dev *i7core_dev) int i; debugf0(__FILE__ ": %s()\n", __func__); - for (i = 0; i < N_DEVS; i++) { + for (i = 0; i < i7core_dev->n_devs; i++) { struct pci_dev *pdev = i7core_dev->pdev[i]; if (!pdev) continue; @@ -1138,7 +1140,7 @@ static void i7core_put_all_devices(void) i7core_put_devices(i7core_dev); } -static void i7core_xeon_pci_fixup(void) +static void i7core_xeon_pci_fixup(int dev_id) { struct pci_dev *pdev = NULL; int i; @@ -1147,8 +1149,7 @@ static void i7core_xeon_pci_fixup(void) * aren't announced by acpi. So, we need to use a legacy scan probing * to detect them */ - pdev = pci_get_device(PCI_VENDOR_ID_INTEL, - pci_dev_descr[0].dev_id, NULL); + pdev = pci_get_device(PCI_VENDOR_ID_INTEL, dev_id, NULL); if (unlikely(!pdev)) { for (i = 0; i < MAX_SOCKET_BUSES; i++) pcibios_scan_specific_bus(255-i); @@ -1161,7 +1162,8 @@ static void i7core_xeon_pci_fixup(void) * * Need to 'get' device 16 func 1 and func 2 */ -int i7core_get_onedevice(struct pci_dev **prev, int devno) +int i7core_get_onedevice(struct pci_dev **prev, int devno, + struct pci_id_descr *dev_descr, unsigned n_devs) { struct i7core_dev *i7core_dev; @@ -1170,14 +1172,14 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno) u8 socket = 0; pdev = pci_get_device(PCI_VENDOR_ID_INTEL, - pci_dev_descr[devno].dev_id, *prev); + dev_descr->dev_id, *prev); /* * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core regs * is at addr 8086:2c40, instead of 8086:2c41. So, we need * to probe for the alternate address in case of failure */ - if (pci_dev_descr[devno].dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev) + if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev) pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT, *prev); @@ -1187,19 +1189,13 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno) return 0; } - /* - * Dev 3 function 2 only exists on chips with RDIMMs - * so, it is ok to not found it - */ - if ((pci_dev_descr[devno].dev == 3) && (pci_dev_descr[devno].func == 2)) { - *prev = pdev; + if (dev_descr->optional) return 0; - } i7core_printk(KERN_ERR, "Device not found: dev %02x.%d PCI ID %04x:%04x\n", - pci_dev_descr[devno].dev, pci_dev_descr[devno].func, - PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id); + dev_descr->dev, dev_descr->func, + PCI_VENDOR_ID_INTEL, dev_descr->dev_id); /* End of list, leave */ return -ENODEV; @@ -1216,11 +1212,12 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno) i7core_dev = kzalloc(sizeof(*i7core_dev), GFP_KERNEL); if (!i7core_dev) return -ENOMEM; - i7core_dev->pdev = kzalloc(sizeof(*i7core_dev->pdev) * N_DEVS, + i7core_dev->pdev = kzalloc(sizeof(*i7core_dev->pdev) * n_devs, GFP_KERNEL); if (!i7core_dev->pdev) return -ENOMEM; i7core_dev->socket = socket; + i7core_dev->n_devs = n_devs; list_add_tail(&i7core_dev->list, &i7core_edac_list); } @@ -1228,8 +1225,8 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno) i7core_printk(KERN_ERR, "Duplicated device for " "dev %02x:%02x.%d PCI ID %04x:%04x\n", - bus, pci_dev_descr[devno].dev, pci_dev_descr[devno].func, - PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id); + bus, dev_descr->dev, dev_descr->func, + PCI_VENDOR_ID_INTEL, dev_descr->dev_id); pci_dev_put(pdev); return -ENODEV; } @@ -1237,14 +1234,14 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno) i7core_dev->pdev[devno] = pdev; /* Sanity check */ - if (unlikely(PCI_SLOT(pdev->devfn) != pci_dev_descr[devno].dev || - PCI_FUNC(pdev->devfn) != pci_dev_descr[devno].func)) { + if (unlikely(PCI_SLOT(pdev->devfn) != dev_descr->dev || + PCI_FUNC(pdev->devfn) != dev_descr->func)) { i7core_printk(KERN_ERR, "Device PCI ID %04x:%04x " "has dev %02x:%02x.%d instead of dev %02x:%02x.%d\n", - PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id, + PCI_VENDOR_ID_INTEL, dev_descr->dev_id, bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), - bus, pci_dev_descr[devno].dev, pci_dev_descr[devno].func); + bus, dev_descr->dev, dev_descr->func); return -ENODEV; } @@ -1253,30 +1250,32 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno) i7core_printk(KERN_ERR, "Couldn't enable " "dev %02x:%02x.%d PCI ID %04x:%04x\n", - bus, pci_dev_descr[devno].dev, pci_dev_descr[devno].func, - PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id); + bus, dev_descr->dev, dev_descr->func, + PCI_VENDOR_ID_INTEL, dev_descr->dev_id); return -ENODEV; } debugf0("Detected socket %d dev %02x:%02x.%d PCI ID %04x:%04x\n", - socket, bus, pci_dev_descr[devno].dev, - pci_dev_descr[devno].func, - PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id); + socket, bus, dev_descr->dev, + dev_descr->func, + PCI_VENDOR_ID_INTEL, dev_descr->dev_id); *prev = pdev; return 0; } -static int i7core_get_devices(void) +static int i7core_get_devices(struct pci_id_descr dev_descr[], unsigned n_devs) { - int i; + int i, rc; struct pci_dev *pdev = NULL; - for (i = 0; i < N_DEVS; i++) { + for (i = 0; i < n_devs; i++) { pdev = NULL; do { - if (i7core_get_onedevice(&pdev, i) < 0) { + rc = i7core_get_onedevice(&pdev, i, &dev_descr[i], + n_devs); + if (rc < 0) { i7core_put_all_devices(); return -ENODEV; } @@ -1298,7 +1297,7 @@ static int mci_bind_devs(struct mem_ctl_info *mci, i7core_dev->mci = mci; pvt->is_registered = 0; - for (i = 0; i < N_DEVS; i++) { + for (i = 0; i < i7core_dev->n_devs; i++) { pdev = i7core_dev->pdev[i]; if (!pdev) continue; @@ -1838,7 +1837,9 @@ static int __devinit i7core_probe(struct pci_dev *pdev, /* get the pci devices we want to reserve for our use */ mutex_lock(&i7core_edac_lock); - rc = i7core_get_devices(); + + rc = i7core_get_devices(pci_dev_descr_i7core, + ARRAY_SIZE(pci_dev_descr_i7core)); if (unlikely(rc < 0)) goto fail0; @@ -1937,7 +1938,7 @@ static int __init i7core_init(void) /* Ensure that the OPSTATE is set correctly for POLL or NMI */ opstate_init(); - i7core_xeon_pci_fixup(); + i7core_xeon_pci_fixup(pci_dev_descr_i7core[0].dev_id); pci_rc = pci_register_driver(&i7core_driver); -- cgit v1.2.3 From 486dd09f129da01cd02b212ba48dce987488b860 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sun, 8 Nov 2009 01:34:27 -0200 Subject: edac: i7core_edac produces undefined behaviour on 32bit Fix the shifts up Signed-off-by: Alan Cox Acked-by: Doug Thompson Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index b6fce2e38e3d..bd7c727030a3 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -916,41 +916,41 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, /* Sets pvt->inject.dimm mask */ if (pvt->inject.dimm < 0) - mask |= 1L << 41; + mask |= 1LL << 41; else { if (pvt->channel[pvt->inject.channel].dimms > 2) - mask |= (pvt->inject.dimm & 0x3L) << 35; + mask |= (pvt->inject.dimm & 0x3LL) << 35; else - mask |= (pvt->inject.dimm & 0x1L) << 36; + mask |= (pvt->inject.dimm & 0x1LL) << 36; } /* Sets pvt->inject.rank mask */ if (pvt->inject.rank < 0) - mask |= 1L << 40; + mask |= 1LL << 40; else { if (pvt->channel[pvt->inject.channel].dimms > 2) - mask |= (pvt->inject.rank & 0x1L) << 34; + mask |= (pvt->inject.rank & 0x1LL) << 34; else - mask |= (pvt->inject.rank & 0x3L) << 34; + mask |= (pvt->inject.rank & 0x3LL) << 34; } /* Sets pvt->inject.bank mask */ if (pvt->inject.bank < 0) - mask |= 1L << 39; + mask |= 1LL << 39; else - mask |= (pvt->inject.bank & 0x15L) << 30; + mask |= (pvt->inject.bank & 0x15LL) << 30; /* Sets pvt->inject.page mask */ if (pvt->inject.page < 0) - mask |= 1L << 38; + mask |= 1LL << 38; else - mask |= (pvt->inject.page & 0xffffL) << 14; + mask |= (pvt->inject.page & 0xffff) << 14; /* Sets pvt->inject.column mask */ if (pvt->inject.col < 0) - mask |= 1L << 37; + mask |= 1LL << 37; else - mask |= (pvt->inject.col & 0x3fffL); + mask |= (pvt->inject.col & 0x3fff); /* * bit 0: REPEAT_EN -- cgit v1.2.3 From 3b918c12df4f624140456d6c6f982bada8e1f095 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 8 Nov 2009 01:36:40 -0200 Subject: edac: fix i7core build Fix build warning (missing header file) and build error when CONFIG_SMP=n. drivers/edac/i7core_edac.c:860: error: implicit declaration of function 'msleep' drivers/edac/i7core_edac.c:1700: error: 'struct cpuinfo_x86' has no member named 'phys_proc_id' Signed-off-by: Randy Dunlap Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index bd7c727030a3..e944b63d9f06 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -1696,9 +1697,11 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) if (mce->bank != 8) return 0; +#ifdef CONFIG_SMP /* Only handle if it is the right mc controller */ if (cpu_data(mce->cpu).phys_proc_id != pvt->i7core_dev->socket) return 0; +#endif smp_rmb(); if ((pvt->mce_out + 1) % MCE_LOG_LEN == pvt->mce_in) { -- cgit v1.2.3 From 52a2e4fc3712d12888decd386d78ad526078a1fa Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 14 Oct 2009 11:21:58 -0300 Subject: i7core_edac: Add initial support for Lynnfield Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index e944b63d9f06..e525d571cb25 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -299,11 +299,30 @@ struct pci_id_descr pci_dev_descr_i7core[] = { }; +struct pci_id_descr pci_dev_descr_lynnfield[] = { + { PCI_DESCR( 3, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR) }, + { PCI_DESCR( 3, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD) }, + { PCI_DESCR( 3, 4, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TEST) }, + + { PCI_DESCR( 4, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_CTRL) }, + { PCI_DESCR( 4, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_ADDR) }, + { PCI_DESCR( 4, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_RANK) }, + { PCI_DESCR( 4, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_TC) }, + + { PCI_DESCR( 4, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_CTRL) }, + { PCI_DESCR( 4, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_ADDR) }, + { PCI_DESCR( 4, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK) }, + { PCI_DESCR( 4, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC) }, + + { PCI_DESCR( 0, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE) }, +}; + /* * pci_device_id table for which devices we are looking for */ static const struct pci_device_id i7core_pci_tbl[] __devinitdata = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_X58_HUB_MGMT)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE)}, {0,} /* 0 terminated list. */ }; @@ -522,6 +541,9 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow) for (i = 0; i < NUM_CHANS; i++) { u32 data, dimm_dod[3], value[8]; + if (!pvt->pci_ch[i][0]) + continue; + if (!CH_ACTIVE(pvt, i)) { debugf0("Channel %i is not active\n", i); continue; @@ -1001,6 +1023,9 @@ static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci, struct i7core_pvt *pvt = mci->pvt_info; u32 injectmask; + if (!pvt->pci_ch[pvt->inject.channel][0]) + return 0; + pci_read_config_dword(pvt->pci_ch[pvt->inject.channel][0], MC_CHANNEL_ERROR_INJECT, &injectmask); @@ -1841,8 +1866,18 @@ static int __devinit i7core_probe(struct pci_dev *pdev, /* get the pci devices we want to reserve for our use */ mutex_lock(&i7core_edac_lock); - rc = i7core_get_devices(pci_dev_descr_i7core, - ARRAY_SIZE(pci_dev_descr_i7core)); + if (pdev->device == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE) { + printk(KERN_INFO "i7core_edac: detected a " + "Lynnfield processor\n"); + rc = i7core_get_devices(pci_dev_descr_lynnfield, + ARRAY_SIZE(pci_dev_descr_lynnfield)); + } else { + printk(KERN_INFO "i7core_edac: detected a " + "Nehalem/Nehalem-EP processor\n"); + rc = i7core_get_devices(pci_dev_descr_i7core, + ARRAY_SIZE(pci_dev_descr_i7core)); + } + if (unlikely(rc < 0)) goto fail0; -- cgit v1.2.3 From f05da2f7855b3b88a831ca79e037245872549ec0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 14 Oct 2009 13:31:06 -0300 Subject: i7core: add support for Lynnfield alternate address Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index e525d571cb25..d3f5c016c5eb 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -314,6 +314,10 @@ struct pci_id_descr pci_dev_descr_lynnfield[] = { { PCI_DESCR( 4, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK) }, { PCI_DESCR( 4, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC) }, + /* + * This is the PCI device has an alternate address on some + * processors like Core i7 860 + */ { PCI_DESCR( 0, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE) }, }; @@ -322,7 +326,7 @@ struct pci_id_descr pci_dev_descr_lynnfield[] = { */ static const struct pci_device_id i7core_pci_tbl[] __devinitdata = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_X58_HUB_MGMT)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNNFIELD_QPI_LINK0)}, {0,} /* 0 terminated list. */ }; @@ -1209,6 +1213,11 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno, pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT, *prev); + if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE && !pdev) + pdev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT, + *prev); + if (!pdev) { if (*prev) { *prev = pdev; @@ -1866,7 +1875,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, /* get the pci devices we want to reserve for our use */ mutex_lock(&i7core_edac_lock); - if (pdev->device == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE) { + if (pdev->device == PCI_DEVICE_ID_INTEL_LYNNFIELD_QPI_LINK0) { printk(KERN_INFO "i7core_edac: detected a " "Lynnfield processor\n"); rc = i7core_get_devices(pci_dev_descr_lynnfield, -- cgit v1.2.3 From 508fa179f8e0da5d7241e12ad1562b96f291e800 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 14 Oct 2009 13:44:37 -0300 Subject: i7core_edac: Fix wrong device id for channel 1 devices Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index d3f5c016c5eb..4d6ecf1291b8 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -309,10 +309,10 @@ struct pci_id_descr pci_dev_descr_lynnfield[] = { { PCI_DESCR( 4, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_RANK) }, { PCI_DESCR( 4, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_TC) }, - { PCI_DESCR( 4, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_CTRL) }, - { PCI_DESCR( 4, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_ADDR) }, - { PCI_DESCR( 4, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK) }, - { PCI_DESCR( 4, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC) }, + { PCI_DESCR( 5, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_CTRL) }, + { PCI_DESCR( 5, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_ADDR) }, + { PCI_DESCR( 5, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK) }, + { PCI_DESCR( 5, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC) }, /* * This is the PCI device has an alternate address on some -- cgit v1.2.3 From 4e639fdf0d0d745648aa62228ab8a0d9c03a563f Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Thu, 25 Feb 2010 15:37:17 -0500 Subject: ibft: Update iBFT handling for v1.03 of the spec. - Use struct acpi_table_ibft instead of struct ibft_table_header - Don't do reserve_ibft_region() on UEFI machines (section 1.4.3.1) - If ibft_addr isn't initialized when ibft_init() is called, check for ACPI-based tables. - Fix compiler error when CONFIG_ACPI is not defined. Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Peter Jones Signed-off-by: Mike Christie --- drivers/firmware/iscsi_ibft.c | 30 ++++++++++++++++++------------ drivers/firmware/iscsi_ibft_find.c | 35 ++++++++++++++++++++++++++++++----- 2 files changed, 48 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/firmware/iscsi_ibft.c b/drivers/firmware/iscsi_ibft.c index ed2801c378de..b3ab24f9d78f 100644 --- a/drivers/firmware/iscsi_ibft.c +++ b/drivers/firmware/iscsi_ibft.c @@ -1,5 +1,5 @@ /* - * Copyright 2007 Red Hat, Inc. + * Copyright 2007-2010 Red Hat, Inc. * by Peter Jones * Copyright 2008 IBM, Inc. * by Konrad Rzeszutek @@ -19,6 +19,9 @@ * * Changelog: * + * 06 Jan 2010 - Peter Jones + * New changelog entries are in the git log from now on. Not here. + * * 14 Mar 2008 - Konrad Rzeszutek * Updated comments and copyrights. (v0.4.9) * @@ -78,9 +81,10 @@ #include #include #include +#include -#define IBFT_ISCSI_VERSION "0.4.9" -#define IBFT_ISCSI_DATE "2008-Mar-14" +#define IBFT_ISCSI_VERSION "0.5.0" +#define IBFT_ISCSI_DATE "2010-Feb-25" MODULE_AUTHOR("Peter Jones and \ Konrad Rzeszutek "); @@ -238,7 +242,7 @@ static const char *ibft_initiator_properties[] = */ struct ibft_kobject { - struct ibft_table_header *header; + struct acpi_table_ibft *header; union { struct ibft_initiator *initiator; struct ibft_nic *nic; @@ -536,12 +540,13 @@ static int __init ibft_check_device(void) u8 *pos; u8 csum = 0; - len = ibft_addr->length; + len = ibft_addr->header.length; /* Sanity checking of iBFT. */ - if (ibft_addr->revision != 1) { + if (ibft_addr->header.revision != 1) { printk(KERN_ERR "iBFT module supports only revision 1, " \ - "while this is %d.\n", ibft_addr->revision); + "while this is %d.\n", + ibft_addr->header.revision); return -ENOENT; } for (pos = (u8 *)ibft_addr; pos < (u8 *)ibft_addr + len; pos++) @@ -558,7 +563,7 @@ static int __init ibft_check_device(void) /* * Helper function for ibft_register_kobjects. */ -static int __init ibft_create_kobject(struct ibft_table_header *header, +static int __init ibft_create_kobject(struct acpi_table_ibft *header, struct ibft_hdr *hdr, struct list_head *list) { @@ -596,7 +601,7 @@ static int __init ibft_create_kobject(struct ibft_table_header *header, default: printk(KERN_ERR "iBFT has unknown structure type (%d). " \ "Report this bug to %.6s!\n", hdr->id, - header->oem_id); + header->header.oem_id); rc = 1; break; } @@ -649,7 +654,7 @@ out_invalid_struct: * found add them on the passed-in list. We do not support the other * fields at this point, so they are skipped. */ -static int __init ibft_register_kobjects(struct ibft_table_header *header, +static int __init ibft_register_kobjects(struct acpi_table_ibft *header, struct list_head *list) { struct ibft_control *control = NULL; @@ -660,7 +665,7 @@ static int __init ibft_register_kobjects(struct ibft_table_header *header, control = (void *)header + sizeof(*header); end = (void *)control + control->hdr.length; - eot_offset = (void *)header + header->length - (void *)control; + eot_offset = (void *)header + header->header.length - (void *)control; rc = ibft_verify_hdr("control", (struct ibft_hdr *)control, id_control, sizeof(*control)); @@ -672,7 +677,8 @@ static int __init ibft_register_kobjects(struct ibft_table_header *header, } for (ptr = &control->initiator_off; ptr < end; ptr += sizeof(u16)) { offset = *(u16 *)ptr; - if (offset && offset < header->length && offset < eot_offset) { + if (offset && offset < header->header.length && + offset < eot_offset) { rc = ibft_create_kobject(header, (void *)header + offset, list); diff --git a/drivers/firmware/iscsi_ibft_find.c b/drivers/firmware/iscsi_ibft_find.c index d6470ef36e4a..dd85555d3296 100644 --- a/drivers/firmware/iscsi_ibft_find.c +++ b/drivers/firmware/iscsi_ibft_find.c @@ -1,5 +1,5 @@ /* - * Copyright 2007 Red Hat, Inc. + * Copyright 2007-2010 Red Hat, Inc. * by Peter Jones * Copyright 2007 IBM, Inc. * by Konrad Rzeszutek @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -30,13 +31,15 @@ #include #include #include +#include +#include #include /* * Physical location of iSCSI Boot Format Table. */ -struct ibft_table_header *ibft_addr; +struct acpi_table_ibft *ibft_addr; EXPORT_SYMBOL_GPL(ibft_addr); #define IBFT_SIGN "iBFT" @@ -46,6 +49,13 @@ EXPORT_SYMBOL_GPL(ibft_addr); #define VGA_MEM 0xA0000 /* VGA buffer */ #define VGA_SIZE 0x20000 /* 128kB */ +#ifdef CONFIG_ACPI +static int __init acpi_find_ibft(struct acpi_table_header *header) +{ + ibft_addr = (struct acpi_table_ibft *)header; + return 0; +} +#endif /* CONFIG_ACPI */ /* * Routine used to find the iSCSI Boot Format Table. The logical @@ -59,6 +69,11 @@ unsigned long __init find_ibft_region(unsigned long *sizep) ibft_addr = NULL; + /* iBFT 1.03 section 1.4.3.1 mandates that UEFI machines will + * only use ACPI for this */ + if (efi_enabled) + return 0; + for (pos = IBFT_START; pos < IBFT_END; pos += 16) { /* The table can't be inside the VGA BIOS reserved space, * so skip that area */ @@ -72,14 +87,24 @@ unsigned long __init find_ibft_region(unsigned long *sizep) /* if the length of the table extends past 1M, * the table cannot be valid. */ if (pos + len <= (IBFT_END-1)) { - ibft_addr = (struct ibft_table_header *)virt; + ibft_addr = (struct acpi_table_ibft *)virt; break; } } } +#ifdef CONFIG_ACPI + /* + * One spec says "IBFT", the other says "iBFT". We have to check + * for both. + */ + if (!ibft_addr) + acpi_table_parse(ACPI_SIG_IBFT, acpi_find_ibft); + if (!ibft_addr) + acpi_table_parse("iBFT", acpi_find_ibft); +#endif /* CONFIG_ACPI */ if (ibft_addr) { - *sizep = PAGE_ALIGN(len); - return pos; + *sizep = PAGE_ALIGN(ibft_addr->header.length); + return (u64)isa_virt_to_bus(ibft_addr); } *sizep = 0; -- cgit v1.2.3 From 1303a35bfe153370cddb1b6e58e2287469e35f34 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Thu, 8 Apr 2010 12:35:55 -0400 Subject: ibft: For UEFI machines actually do scan ACPI for iBFT. For machines with IBFT 1.03 do scan the ACPI table for 'iBFT' or for 'IBFT'. If the machine is in UEFI mode, only do the ACPI table scan. For all other machines (pre IBFT 1.03) do a memory scan if not found in the ACPI tables. Signed-off-by: Peter Jones Signed-off-by: Konrad Rzeszutek Wilk Tested-by: Mike Christie --- drivers/firmware/iscsi_ibft_find.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/firmware/iscsi_ibft_find.c b/drivers/firmware/iscsi_ibft_find.c index dd85555d3296..82a7a1566290 100644 --- a/drivers/firmware/iscsi_ibft_find.c +++ b/drivers/firmware/iscsi_ibft_find.c @@ -57,23 +57,12 @@ static int __init acpi_find_ibft(struct acpi_table_header *header) } #endif /* CONFIG_ACPI */ -/* - * Routine used to find the iSCSI Boot Format Table. The logical - * kernel address is set in the ibft_addr global variable. - */ -unsigned long __init find_ibft_region(unsigned long *sizep) +static int __init find_ibft_in_mem(void) { unsigned long pos; unsigned int len = 0; void *virt; - ibft_addr = NULL; - - /* iBFT 1.03 section 1.4.3.1 mandates that UEFI machines will - * only use ACPI for this */ - if (efi_enabled) - return 0; - for (pos = IBFT_START; pos < IBFT_END; pos += 16) { /* The table can't be inside the VGA BIOS reserved space, * so skip that area */ @@ -92,6 +81,17 @@ unsigned long __init find_ibft_region(unsigned long *sizep) } } } + return len; +} +/* + * Routine used to find the iSCSI Boot Format Table. The logical + * kernel address is set in the ibft_addr global variable. + */ +unsigned long __init find_ibft_region(unsigned long *sizep) +{ + + ibft_addr = NULL; + #ifdef CONFIG_ACPI /* * One spec says "IBFT", the other says "iBFT". We have to check @@ -102,6 +102,13 @@ unsigned long __init find_ibft_region(unsigned long *sizep) if (!ibft_addr) acpi_table_parse("iBFT", acpi_find_ibft); #endif /* CONFIG_ACPI */ + + /* iBFT 1.03 section 1.4.3.1 mandates that UEFI machines will + * only use ACPI for this */ + + if (!ibft_addr && !efi_enabled) + find_ibft_in_mem(); + if (ibft_addr) { *sizep = PAGE_ALIGN(ibft_addr->header.length); return (u64)isa_virt_to_bus(ibft_addr); -- cgit v1.2.3 From ba4ee30c6c797de148dcc7254cf6d531aba71d9b Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 12 Apr 2010 18:06:17 +0000 Subject: ibft: separate ibft parsing from sysfs interface Not all iscsi drivers support ibft. For drivers like be2iscsi that do not but are bootable through a vendor firmware specific format/process this patch moves the sysfs interface from the ibft code to a lib module. This then allows userspace tools to search for iscsi boot info in a common place and in a common format. ibft iscsi boot info is exported in the same place as it was before: /sys/firmware/ibft. vendor/fw boot info gets export in /sys/firmware/iscsi_bootX, where X is the scsi host number of the HBA. Underneath these parent dirs, the target, ethernet, and initiator dirs are the same as they were before. Signed-off-by: Mike Christie Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Peter Jones --- drivers/firmware/Kconfig | 8 + drivers/firmware/Makefile | 1 + drivers/firmware/iscsi_boot_sysfs.c | 481 ++++++++++++++++++++++++++++++++++++ 3 files changed, 490 insertions(+) create mode 100644 drivers/firmware/iscsi_boot_sysfs.c (limited to 'drivers') diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 1b03ba1d0834..571d2182613d 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -122,6 +122,14 @@ config ISCSI_IBFT_FIND is necessary for iSCSI Boot Firmware Table Attributes module to work properly. +config ISCSI_BOOT_SYSFS + tristate "iSCSI Boot Sysfs Interface" + default n + help + This option enables support for exposing iSCSI boot information + via sysfs to userspace. If you wish to export this information, + say Y. Otherwise, say N. + config ISCSI_IBFT tristate "iSCSI Boot Firmware Table Attributes module" depends on ISCSI_IBFT_FIND diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 1c3c17343dbe..5fe7e1662922 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -10,4 +10,5 @@ obj-$(CONFIG_DCDBAS) += dcdbas.o obj-$(CONFIG_DMIID) += dmi-id.o obj-$(CONFIG_ISCSI_IBFT_FIND) += iscsi_ibft_find.o obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o +obj-$(CONFIG_ISCSI_BOOT_SYSFS) += iscsi_boot_sysfs.o obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o diff --git a/drivers/firmware/iscsi_boot_sysfs.c b/drivers/firmware/iscsi_boot_sysfs.c new file mode 100644 index 000000000000..df6bff7366cf --- /dev/null +++ b/drivers/firmware/iscsi_boot_sysfs.c @@ -0,0 +1,481 @@ +/* + * Export the iSCSI boot info to userland via sysfs. + * + * Copyright (C) 2010 Red Hat, Inc. All rights reserved. + * Copyright (C) 2010 Mike Christie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License v2.0 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. + */ + +#include +#include +#include +#include +#include +#include + + +MODULE_AUTHOR("Mike Christie "); +MODULE_DESCRIPTION("sysfs interface and helpers to export iSCSI boot information"); +MODULE_LICENSE("GPL"); +/* + * The kobject and attribute structures. + */ +struct iscsi_boot_attr { + struct attribute attr; + int type; + ssize_t (*show) (void *data, int type, char *buf); +}; + +/* + * The routine called for all sysfs attributes. + */ +static ssize_t iscsi_boot_show_attribute(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + struct iscsi_boot_kobj *boot_kobj = + container_of(kobj, struct iscsi_boot_kobj, kobj); + struct iscsi_boot_attr *boot_attr = + container_of(attr, struct iscsi_boot_attr, attr); + ssize_t ret = -EIO; + char *str = buf; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (boot_kobj->show) + ret = boot_kobj->show(boot_kobj->data, boot_attr->type, str); + return ret; +} + +static const struct sysfs_ops iscsi_boot_attr_ops = { + .show = iscsi_boot_show_attribute, +}; + +static void iscsi_boot_kobj_release(struct kobject *kobj) +{ + struct iscsi_boot_kobj *boot_kobj = + container_of(kobj, struct iscsi_boot_kobj, kobj); + + kfree(boot_kobj->data); + kfree(boot_kobj); +} + +static struct kobj_type iscsi_boot_ktype = { + .release = iscsi_boot_kobj_release, + .sysfs_ops = &iscsi_boot_attr_ops, +}; + +#define iscsi_boot_rd_attr(fnname, sysfs_name, attr_type) \ +static struct iscsi_boot_attr iscsi_boot_attr_##fnname = { \ + .attr = { .name = __stringify(sysfs_name), .mode = 0444 }, \ + .type = attr_type, \ +} + +/* Target attrs */ +iscsi_boot_rd_attr(tgt_index, index, ISCSI_BOOT_TGT_INDEX); +iscsi_boot_rd_attr(tgt_flags, flags, ISCSI_BOOT_TGT_FLAGS); +iscsi_boot_rd_attr(tgt_ip, ip-addr, ISCSI_BOOT_TGT_IP_ADDR); +iscsi_boot_rd_attr(tgt_port, port, ISCSI_BOOT_TGT_PORT); +iscsi_boot_rd_attr(tgt_lun, lun, ISCSI_BOOT_TGT_LUN); +iscsi_boot_rd_attr(tgt_chap, chap-type, ISCSI_BOOT_TGT_CHAP_TYPE); +iscsi_boot_rd_attr(tgt_nic, nic-assoc, ISCSI_BOOT_TGT_NIC_ASSOC); +iscsi_boot_rd_attr(tgt_name, target-name, ISCSI_BOOT_TGT_NAME); +iscsi_boot_rd_attr(tgt_chap_name, chap-name, ISCSI_BOOT_TGT_CHAP_NAME); +iscsi_boot_rd_attr(tgt_chap_secret, chap-secret, ISCSI_BOOT_TGT_CHAP_SECRET); +iscsi_boot_rd_attr(tgt_chap_rev_name, rev-chap-name, + ISCSI_BOOT_TGT_REV_CHAP_NAME); +iscsi_boot_rd_attr(tgt_chap_rev_secret, rev-chap-name-secret, + ISCSI_BOOT_TGT_REV_CHAP_SECRET); + +static struct attribute *target_attrs[] = { + &iscsi_boot_attr_tgt_index.attr, + &iscsi_boot_attr_tgt_flags.attr, + &iscsi_boot_attr_tgt_ip.attr, + &iscsi_boot_attr_tgt_port.attr, + &iscsi_boot_attr_tgt_lun.attr, + &iscsi_boot_attr_tgt_chap.attr, + &iscsi_boot_attr_tgt_nic.attr, + &iscsi_boot_attr_tgt_name.attr, + &iscsi_boot_attr_tgt_chap_name.attr, + &iscsi_boot_attr_tgt_chap_secret.attr, + &iscsi_boot_attr_tgt_chap_rev_name.attr, + &iscsi_boot_attr_tgt_chap_rev_secret.attr, + NULL +}; + +static mode_t iscsi_boot_tgt_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int i) +{ + struct iscsi_boot_kobj *boot_kobj = + container_of(kobj, struct iscsi_boot_kobj, kobj); + + if (attr == &iscsi_boot_attr_tgt_index.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_TGT_INDEX); + else if (attr == &iscsi_boot_attr_tgt_flags.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_TGT_FLAGS); + else if (attr == &iscsi_boot_attr_tgt_ip.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_TGT_IP_ADDR); + else if (attr == &iscsi_boot_attr_tgt_port.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_TGT_PORT); + else if (attr == &iscsi_boot_attr_tgt_lun.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_TGT_LUN); + else if (attr == &iscsi_boot_attr_tgt_chap.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_TGT_CHAP_TYPE); + else if (attr == &iscsi_boot_attr_tgt_nic.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_TGT_NIC_ASSOC); + else if (attr == &iscsi_boot_attr_tgt_name.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_TGT_NAME); + else if (attr == &iscsi_boot_attr_tgt_chap_name.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_TGT_CHAP_NAME); + else if (attr == &iscsi_boot_attr_tgt_chap_secret.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_TGT_CHAP_SECRET); + else if (attr == &iscsi_boot_attr_tgt_chap_rev_name.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_TGT_REV_CHAP_NAME); + else if (attr == &iscsi_boot_attr_tgt_chap_rev_secret.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_TGT_REV_CHAP_SECRET); + return 0; +} + +static struct attribute_group iscsi_boot_target_attr_group = { + .attrs = target_attrs, + .is_visible = iscsi_boot_tgt_attr_is_visible, +}; + +/* Ethernet attrs */ +iscsi_boot_rd_attr(eth_index, index, ISCSI_BOOT_ETH_INDEX); +iscsi_boot_rd_attr(eth_flags, flags, ISCSI_BOOT_ETH_FLAGS); +iscsi_boot_rd_attr(eth_ip, ip-addr, ISCSI_BOOT_ETH_IP_ADDR); +iscsi_boot_rd_attr(eth_subnet, subnet-mask, ISCSI_BOOT_ETH_SUBNET_MASK); +iscsi_boot_rd_attr(eth_origin, origin, ISCSI_BOOT_ETH_ORIGIN); +iscsi_boot_rd_attr(eth_gateway, gateway, ISCSI_BOOT_ETH_GATEWAY); +iscsi_boot_rd_attr(eth_primary_dns, primary-dns, ISCSI_BOOT_ETH_PRIMARY_DNS); +iscsi_boot_rd_attr(eth_secondary_dns, secondary-dns, + ISCSI_BOOT_ETH_SECONDARY_DNS); +iscsi_boot_rd_attr(eth_dhcp, dhcp, ISCSI_BOOT_ETH_DHCP); +iscsi_boot_rd_attr(eth_vlan, vlan, ISCSI_BOOT_ETH_VLAN); +iscsi_boot_rd_attr(eth_mac, mac, ISCSI_BOOT_ETH_MAC); +iscsi_boot_rd_attr(eth_hostname, hostname, ISCSI_BOOT_ETH_HOSTNAME); + +static struct attribute *ethernet_attrs[] = { + &iscsi_boot_attr_eth_index.attr, + &iscsi_boot_attr_eth_flags.attr, + &iscsi_boot_attr_eth_ip.attr, + &iscsi_boot_attr_eth_subnet.attr, + &iscsi_boot_attr_eth_origin.attr, + &iscsi_boot_attr_eth_gateway.attr, + &iscsi_boot_attr_eth_primary_dns.attr, + &iscsi_boot_attr_eth_secondary_dns.attr, + &iscsi_boot_attr_eth_dhcp.attr, + &iscsi_boot_attr_eth_vlan.attr, + &iscsi_boot_attr_eth_mac.attr, + &iscsi_boot_attr_eth_hostname.attr, + NULL +}; + +static mode_t iscsi_boot_eth_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int i) +{ + struct iscsi_boot_kobj *boot_kobj = + container_of(kobj, struct iscsi_boot_kobj, kobj); + + if (attr == &iscsi_boot_attr_eth_index.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_ETH_INDEX); + else if (attr == &iscsi_boot_attr_eth_flags.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_ETH_FLAGS); + else if (attr == &iscsi_boot_attr_eth_ip.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_ETH_IP_ADDR); + else if (attr == &iscsi_boot_attr_eth_subnet.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_ETH_SUBNET_MASK); + else if (attr == &iscsi_boot_attr_eth_origin.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_ETH_ORIGIN); + else if (attr == &iscsi_boot_attr_eth_gateway.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_ETH_GATEWAY); + else if (attr == &iscsi_boot_attr_eth_primary_dns.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_ETH_PRIMARY_DNS); + else if (attr == &iscsi_boot_attr_eth_secondary_dns.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_ETH_SECONDARY_DNS); + else if (attr == &iscsi_boot_attr_eth_dhcp.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_ETH_DHCP); + else if (attr == &iscsi_boot_attr_eth_vlan.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_ETH_VLAN); + else if (attr == &iscsi_boot_attr_eth_mac.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_ETH_MAC); + else if (attr == &iscsi_boot_attr_eth_hostname.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_ETH_HOSTNAME); + return 0; +} + +static struct attribute_group iscsi_boot_ethernet_attr_group = { + .attrs = ethernet_attrs, + .is_visible = iscsi_boot_eth_attr_is_visible, +}; + +/* Initiator attrs */ +iscsi_boot_rd_attr(ini_index, index, ISCSI_BOOT_INI_INDEX); +iscsi_boot_rd_attr(ini_flags, flags, ISCSI_BOOT_INI_FLAGS); +iscsi_boot_rd_attr(ini_isns, isns-server, ISCSI_BOOT_INI_ISNS_SERVER); +iscsi_boot_rd_attr(ini_slp, slp-server, ISCSI_BOOT_INI_SLP_SERVER); +iscsi_boot_rd_attr(ini_primary_radius, pri-radius-server, + ISCSI_BOOT_INI_PRI_RADIUS_SERVER); +iscsi_boot_rd_attr(ini_secondary_radius, sec-radius-server, + ISCSI_BOOT_INI_SEC_RADIUS_SERVER); +iscsi_boot_rd_attr(ini_name, initiator-name, ISCSI_BOOT_INI_INITIATOR_NAME); + +static struct attribute *initiator_attrs[] = { + &iscsi_boot_attr_ini_index.attr, + &iscsi_boot_attr_ini_flags.attr, + &iscsi_boot_attr_ini_isns.attr, + &iscsi_boot_attr_ini_slp.attr, + &iscsi_boot_attr_ini_primary_radius.attr, + &iscsi_boot_attr_ini_secondary_radius.attr, + &iscsi_boot_attr_ini_name.attr, + NULL +}; + +static mode_t iscsi_boot_ini_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int i) +{ + struct iscsi_boot_kobj *boot_kobj = + container_of(kobj, struct iscsi_boot_kobj, kobj); + + if (attr == &iscsi_boot_attr_ini_index.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_INI_INDEX); + if (attr == &iscsi_boot_attr_ini_flags.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_INI_FLAGS); + if (attr == &iscsi_boot_attr_ini_isns.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_INI_ISNS_SERVER); + if (attr == &iscsi_boot_attr_ini_slp.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_INI_SLP_SERVER); + if (attr == &iscsi_boot_attr_ini_primary_radius.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_INI_PRI_RADIUS_SERVER); + if (attr == &iscsi_boot_attr_ini_secondary_radius.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_INI_SEC_RADIUS_SERVER); + if (attr == &iscsi_boot_attr_ini_name.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_INI_INITIATOR_NAME); + + return 0; +} + +static struct attribute_group iscsi_boot_initiator_attr_group = { + .attrs = initiator_attrs, + .is_visible = iscsi_boot_ini_attr_is_visible, +}; + +static struct iscsi_boot_kobj * +iscsi_boot_create_kobj(struct iscsi_boot_kset *boot_kset, + struct attribute_group *attr_group, + const char *name, int index, void *data, + ssize_t (*show) (void *data, int type, char *buf), + mode_t (*is_visible) (void *data, int type)) +{ + struct iscsi_boot_kobj *boot_kobj; + + boot_kobj = kzalloc(sizeof(*boot_kobj), GFP_KERNEL); + if (!boot_kobj) + return NULL; + INIT_LIST_HEAD(&boot_kobj->list); + + boot_kobj->kobj.kset = boot_kset->kset; + if (kobject_init_and_add(&boot_kobj->kobj, &iscsi_boot_ktype, + NULL, name, index)) { + kfree(boot_kobj); + return NULL; + } + boot_kobj->data = data; + boot_kobj->show = show; + boot_kobj->is_visible = is_visible; + + if (sysfs_create_group(&boot_kobj->kobj, attr_group)) { + /* + * We do not want to free this because the caller + * will assume that since the creation call failed + * the boot kobj was not setup and the normal release + * path is not being run. + */ + boot_kobj->data = NULL; + kobject_put(&boot_kobj->kobj); + return NULL; + } + boot_kobj->attr_group = attr_group; + + kobject_uevent(&boot_kobj->kobj, KOBJ_ADD); + /* Nothing broke so lets add it to the list. */ + list_add_tail(&boot_kobj->list, &boot_kset->kobj_list); + return boot_kobj; +} + +static void iscsi_boot_remove_kobj(struct iscsi_boot_kobj *boot_kobj) +{ + list_del(&boot_kobj->list); + sysfs_remove_group(&boot_kobj->kobj, boot_kobj->attr_group); + kobject_put(&boot_kobj->kobj); +} + +/** + * iscsi_boot_create_target() - create boot target sysfs dir + * @boot_kset: boot kset + * @index: the target id + * @data: driver specific data for target + * @show: attr show function + * @is_visible: attr visibility function + * + * Note: The boot sysfs lib will free the data passed in for the caller + * when all refs to the target kobject have been released. + */ +struct iscsi_boot_kobj * +iscsi_boot_create_target(struct iscsi_boot_kset *boot_kset, int index, + void *data, + ssize_t (*show) (void *data, int type, char *buf), + mode_t (*is_visible) (void *data, int type)) +{ + return iscsi_boot_create_kobj(boot_kset, &iscsi_boot_target_attr_group, + "target%d", index, data, show, is_visible); +} +EXPORT_SYMBOL_GPL(iscsi_boot_create_target); + +/** + * iscsi_boot_create_initiator() - create boot initiator sysfs dir + * @boot_kset: boot kset + * @index: the initiator id + * @data: driver specific data + * @show: attr show function + * @is_visible: attr visibility function + * + * Note: The boot sysfs lib will free the data passed in for the caller + * when all refs to the initiator kobject have been released. + */ +struct iscsi_boot_kobj * +iscsi_boot_create_initiator(struct iscsi_boot_kset *boot_kset, int index, + void *data, + ssize_t (*show) (void *data, int type, char *buf), + mode_t (*is_visible) (void *data, int type)) +{ + return iscsi_boot_create_kobj(boot_kset, + &iscsi_boot_initiator_attr_group, + "initiator", index, data, show, + is_visible); +} +EXPORT_SYMBOL_GPL(iscsi_boot_create_initiator); + +/** + * iscsi_boot_create_ethernet() - create boot ethernet sysfs dir + * @boot_kset: boot kset + * @index: the ethernet device id + * @data: driver specific data + * @show: attr show function + * @is_visible: attr visibility function + * + * Note: The boot sysfs lib will free the data passed in for the caller + * when all refs to the ethernet kobject have been released. + */ +struct iscsi_boot_kobj * +iscsi_boot_create_ethernet(struct iscsi_boot_kset *boot_kset, int index, + void *data, + ssize_t (*show) (void *data, int type, char *buf), + mode_t (*is_visible) (void *data, int type)) +{ + return iscsi_boot_create_kobj(boot_kset, + &iscsi_boot_ethernet_attr_group, + "ethernet%d", index, data, show, + is_visible); +} +EXPORT_SYMBOL_GPL(iscsi_boot_create_ethernet); + +/** + * iscsi_boot_create_kset() - creates root sysfs tree + * @set_name: name of root dir + */ +struct iscsi_boot_kset *iscsi_boot_create_kset(const char *set_name) +{ + struct iscsi_boot_kset *boot_kset; + + boot_kset = kzalloc(sizeof(*boot_kset), GFP_KERNEL); + if (!boot_kset) + return NULL; + + boot_kset->kset = kset_create_and_add(set_name, NULL, firmware_kobj); + if (!boot_kset->kset) { + kfree(boot_kset); + return NULL; + } + + INIT_LIST_HEAD(&boot_kset->kobj_list); + return boot_kset; +} +EXPORT_SYMBOL_GPL(iscsi_boot_create_kset); + +/** + * iscsi_boot_create_host_kset() - creates root sysfs tree for a scsi host + * @hostno: host number of scsi host + */ +struct iscsi_boot_kset *iscsi_boot_create_host_kset(unsigned int hostno) +{ + struct iscsi_boot_kset *boot_kset; + char *set_name; + + set_name = kasprintf(GFP_KERNEL, "iscsi_boot%u", hostno); + if (!set_name) + return NULL; + + boot_kset = iscsi_boot_create_kset(set_name); + kfree(set_name); + return boot_kset; +} +EXPORT_SYMBOL_GPL(iscsi_boot_create_host_kset); + +/** + * iscsi_boot_destroy_kset() - destroy kset and kobjects under it + * @boot_kset: boot kset + * + * This will remove the kset and kobjects and attrs under it. + */ +void iscsi_boot_destroy_kset(struct iscsi_boot_kset *boot_kset) +{ + struct iscsi_boot_kobj *boot_kobj, *tmp_kobj; + + list_for_each_entry_safe(boot_kobj, tmp_kobj, + &boot_kset->kobj_list, list) + iscsi_boot_remove_kobj(boot_kobj); + + kset_unregister(boot_kset->kset); +} +EXPORT_SYMBOL_GPL(iscsi_boot_destroy_kset); -- cgit v1.2.3 From b33a84a384776fb2593dac4d77c72050f9e181b0 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 12 Apr 2010 18:06:18 +0000 Subject: ibft: convert iscsi_ibft module to iscsi boot lib This patch just converts the iscsi_ibft module to the iscsi boot sysfs lib module. Signed-off-by: Mike Christie Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Peter Jones --- drivers/firmware/Kconfig | 1 + drivers/firmware/iscsi_ibft.c | 698 +++++++++++++++--------------------------- 2 files changed, 248 insertions(+), 451 deletions(-) (limited to 'drivers') diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 571d2182613d..a6c670b8ce52 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -132,6 +132,7 @@ config ISCSI_BOOT_SYSFS config ISCSI_IBFT tristate "iSCSI Boot Firmware Table Attributes module" + select ISCSI_BOOT_SYSFS depends on ISCSI_IBFT_FIND default n help diff --git a/drivers/firmware/iscsi_ibft.c b/drivers/firmware/iscsi_ibft.c index b3ab24f9d78f..4f04ec0410a0 100644 --- a/drivers/firmware/iscsi_ibft.c +++ b/drivers/firmware/iscsi_ibft.c @@ -82,6 +82,7 @@ #include #include #include +#include #define IBFT_ISCSI_VERSION "0.5.0" #define IBFT_ISCSI_DATE "2010-Feb-25" @@ -169,74 +170,6 @@ enum ibft_id { id_end_marker, }; -/* - * We do not support the other types, hence the usage of NULL. - * This maps to the enum ibft_id. - */ -static const char *ibft_id_names[] = - {NULL, NULL, "initiator", "ethernet%d", "target%d", NULL, NULL}; - -/* - * The text attributes names for each of the kobjects. -*/ -enum ibft_eth_properties_enum { - ibft_eth_index, - ibft_eth_flags, - ibft_eth_ip_addr, - ibft_eth_subnet_mask, - ibft_eth_origin, - ibft_eth_gateway, - ibft_eth_primary_dns, - ibft_eth_secondary_dns, - ibft_eth_dhcp, - ibft_eth_vlan, - ibft_eth_mac, - /* ibft_eth_pci_bdf - this is replaced by link to the device itself. */ - ibft_eth_hostname, - ibft_eth_end_marker, -}; - -static const char *ibft_eth_properties[] = - {"index", "flags", "ip-addr", "subnet-mask", "origin", "gateway", - "primary-dns", "secondary-dns", "dhcp", "vlan", "mac", "hostname", - NULL}; - -enum ibft_tgt_properties_enum { - ibft_tgt_index, - ibft_tgt_flags, - ibft_tgt_ip_addr, - ibft_tgt_port, - ibft_tgt_lun, - ibft_tgt_chap_type, - ibft_tgt_nic_assoc, - ibft_tgt_name, - ibft_tgt_chap_name, - ibft_tgt_chap_secret, - ibft_tgt_rev_chap_name, - ibft_tgt_rev_chap_secret, - ibft_tgt_end_marker, -}; - -static const char *ibft_tgt_properties[] = - {"index", "flags", "ip-addr", "port", "lun", "chap-type", "nic-assoc", - "target-name", "chap-name", "chap-secret", "rev-chap-name", - "rev-chap-name-secret", NULL}; - -enum ibft_initiator_properties_enum { - ibft_init_index, - ibft_init_flags, - ibft_init_isns_server, - ibft_init_slp_server, - ibft_init_pri_radius_server, - ibft_init_sec_radius_server, - ibft_init_initiator_name, - ibft_init_end_marker, -}; - -static const char *ibft_initiator_properties[] = - {"index", "flags", "isns-server", "slp-server", "pri-radius-server", - "sec-radius-server", "initiator-name", NULL}; - /* * The kobject and attribute structures. */ @@ -249,29 +182,9 @@ struct ibft_kobject { struct ibft_tgt *tgt; struct ibft_hdr *hdr; }; - struct kobject kobj; - struct list_head node; }; -struct ibft_attribute { - struct attribute attr; - ssize_t (*show) (struct ibft_kobject *entry, - struct ibft_attribute *attr, char *buf); - union { - struct ibft_initiator *initiator; - struct ibft_nic *nic; - struct ibft_tgt *tgt; - struct ibft_hdr *hdr; - }; - struct kobject *kobj; - int type; /* The enum of the type. This can be any value of: - ibft_eth_properties_enum, ibft_tgt_properties_enum, - or ibft_initiator_properties_enum. */ - struct list_head node; -}; - -static LIST_HEAD(ibft_attr_list); -static LIST_HEAD(ibft_kobject_list); +static struct iscsi_boot_kset *boot_kset; static const char nulls[16]; @@ -310,35 +223,27 @@ static ssize_t sprintf_string(char *str, int len, char *buf) static int ibft_verify_hdr(char *t, struct ibft_hdr *hdr, int id, int length) { if (hdr->id != id) { - printk(KERN_ERR "iBFT error: We expected the " \ + printk(KERN_ERR "iBFT error: We expected the %s " \ "field header.id to have %d but " \ - "found %d instead!\n", id, hdr->id); + "found %d instead!\n", t, id, hdr->id); return -ENODEV; } if (hdr->length != length) { - printk(KERN_ERR "iBFT error: We expected the " \ + printk(KERN_ERR "iBFT error: We expected the %s " \ "field header.length to have %d but " \ - "found %d instead!\n", length, hdr->length); + "found %d instead!\n", t, length, hdr->length); return -ENODEV; } return 0; } -static void ibft_release(struct kobject *kobj) -{ - struct ibft_kobject *ibft = - container_of(kobj, struct ibft_kobject, kobj); - kfree(ibft); -} - /* * Routines for parsing the iBFT data to be human readable. */ -static ssize_t ibft_attr_show_initiator(struct ibft_kobject *entry, - struct ibft_attribute *attr, - char *buf) +static ssize_t ibft_attr_show_initiator(void *data, int type, char *buf) { + struct ibft_kobject *entry = data; struct ibft_initiator *initiator = entry->initiator; void *ibft_loc = entry->header; char *str = buf; @@ -346,26 +251,26 @@ static ssize_t ibft_attr_show_initiator(struct ibft_kobject *entry, if (!initiator) return 0; - switch (attr->type) { - case ibft_init_index: + switch (type) { + case ISCSI_BOOT_INI_INDEX: str += sprintf(str, "%d\n", initiator->hdr.index); break; - case ibft_init_flags: + case ISCSI_BOOT_INI_FLAGS: str += sprintf(str, "%d\n", initiator->hdr.flags); break; - case ibft_init_isns_server: + case ISCSI_BOOT_INI_ISNS_SERVER: str += sprintf_ipaddr(str, initiator->isns_server); break; - case ibft_init_slp_server: + case ISCSI_BOOT_INI_SLP_SERVER: str += sprintf_ipaddr(str, initiator->slp_server); break; - case ibft_init_pri_radius_server: + case ISCSI_BOOT_INI_PRI_RADIUS_SERVER: str += sprintf_ipaddr(str, initiator->pri_radius_server); break; - case ibft_init_sec_radius_server: + case ISCSI_BOOT_INI_SEC_RADIUS_SERVER: str += sprintf_ipaddr(str, initiator->sec_radius_server); break; - case ibft_init_initiator_name: + case ISCSI_BOOT_INI_INITIATOR_NAME: str += sprintf_string(str, initiator->initiator_name_len, (char *)ibft_loc + initiator->initiator_name_off); @@ -377,10 +282,9 @@ static ssize_t ibft_attr_show_initiator(struct ibft_kobject *entry, return str - buf; } -static ssize_t ibft_attr_show_nic(struct ibft_kobject *entry, - struct ibft_attribute *attr, - char *buf) +static ssize_t ibft_attr_show_nic(void *data, int type, char *buf) { + struct ibft_kobject *entry = data; struct ibft_nic *nic = entry->nic; void *ibft_loc = entry->header; char *str = buf; @@ -389,42 +293,42 @@ static ssize_t ibft_attr_show_nic(struct ibft_kobject *entry, if (!nic) return 0; - switch (attr->type) { - case ibft_eth_index: + switch (type) { + case ISCSI_BOOT_ETH_INDEX: str += sprintf(str, "%d\n", nic->hdr.index); break; - case ibft_eth_flags: + case ISCSI_BOOT_ETH_FLAGS: str += sprintf(str, "%d\n", nic->hdr.flags); break; - case ibft_eth_ip_addr: + case ISCSI_BOOT_ETH_IP_ADDR: str += sprintf_ipaddr(str, nic->ip_addr); break; - case ibft_eth_subnet_mask: + case ISCSI_BOOT_ETH_SUBNET_MASK: val = cpu_to_be32(~((1 << (32-nic->subnet_mask_prefix))-1)); str += sprintf(str, "%pI4", &val); break; - case ibft_eth_origin: + case ISCSI_BOOT_ETH_ORIGIN: str += sprintf(str, "%d\n", nic->origin); break; - case ibft_eth_gateway: + case ISCSI_BOOT_ETH_GATEWAY: str += sprintf_ipaddr(str, nic->gateway); break; - case ibft_eth_primary_dns: + case ISCSI_BOOT_ETH_PRIMARY_DNS: str += sprintf_ipaddr(str, nic->primary_dns); break; - case ibft_eth_secondary_dns: + case ISCSI_BOOT_ETH_SECONDARY_DNS: str += sprintf_ipaddr(str, nic->secondary_dns); break; - case ibft_eth_dhcp: + case ISCSI_BOOT_ETH_DHCP: str += sprintf_ipaddr(str, nic->dhcp); break; - case ibft_eth_vlan: + case ISCSI_BOOT_ETH_VLAN: str += sprintf(str, "%d\n", nic->vlan); break; - case ibft_eth_mac: + case ISCSI_BOOT_ETH_MAC: str += sprintf(str, "%pM\n", nic->mac); break; - case ibft_eth_hostname: + case ISCSI_BOOT_ETH_HOSTNAME: str += sprintf_string(str, nic->hostname_len, (char *)ibft_loc + nic->hostname_off); break; @@ -435,10 +339,9 @@ static ssize_t ibft_attr_show_nic(struct ibft_kobject *entry, return str - buf; }; -static ssize_t ibft_attr_show_target(struct ibft_kobject *entry, - struct ibft_attribute *attr, - char *buf) +static ssize_t ibft_attr_show_target(void *data, int type, char *buf) { + struct ibft_kobject *entry = data; struct ibft_tgt *tgt = entry->tgt; void *ibft_loc = entry->header; char *str = buf; @@ -447,48 +350,48 @@ static ssize_t ibft_attr_show_target(struct ibft_kobject *entry, if (!tgt) return 0; - switch (attr->type) { - case ibft_tgt_index: + switch (type) { + case ISCSI_BOOT_TGT_INDEX: str += sprintf(str, "%d\n", tgt->hdr.index); break; - case ibft_tgt_flags: + case ISCSI_BOOT_TGT_FLAGS: str += sprintf(str, "%d\n", tgt->hdr.flags); break; - case ibft_tgt_ip_addr: + case ISCSI_BOOT_TGT_IP_ADDR: str += sprintf_ipaddr(str, tgt->ip_addr); break; - case ibft_tgt_port: + case ISCSI_BOOT_TGT_PORT: str += sprintf(str, "%d\n", tgt->port); break; - case ibft_tgt_lun: + case ISCSI_BOOT_TGT_LUN: for (i = 0; i < 8; i++) str += sprintf(str, "%x", (u8)tgt->lun[i]); str += sprintf(str, "\n"); break; - case ibft_tgt_nic_assoc: + case ISCSI_BOOT_TGT_NIC_ASSOC: str += sprintf(str, "%d\n", tgt->nic_assoc); break; - case ibft_tgt_chap_type: + case ISCSI_BOOT_TGT_CHAP_TYPE: str += sprintf(str, "%d\n", tgt->chap_type); break; - case ibft_tgt_name: + case ISCSI_BOOT_TGT_NAME: str += sprintf_string(str, tgt->tgt_name_len, (char *)ibft_loc + tgt->tgt_name_off); break; - case ibft_tgt_chap_name: + case ISCSI_BOOT_TGT_CHAP_NAME: str += sprintf_string(str, tgt->chap_name_len, (char *)ibft_loc + tgt->chap_name_off); break; - case ibft_tgt_chap_secret: + case ISCSI_BOOT_TGT_CHAP_SECRET: str += sprintf_string(str, tgt->chap_secret_len, (char *)ibft_loc + tgt->chap_secret_off); break; - case ibft_tgt_rev_chap_name: + case ISCSI_BOOT_TGT_REV_CHAP_NAME: str += sprintf_string(str, tgt->rev_chap_name_len, (char *)ibft_loc + tgt->rev_chap_name_off); break; - case ibft_tgt_rev_chap_secret: + case ISCSI_BOOT_TGT_REV_CHAP_SECRET: str += sprintf_string(str, tgt->rev_chap_secret_len, (char *)ibft_loc + tgt->rev_chap_secret_off); @@ -500,40 +403,6 @@ static ssize_t ibft_attr_show_target(struct ibft_kobject *entry, return str - buf; } -/* - * The routine called for all sysfs attributes. - */ -static ssize_t ibft_show_attribute(struct kobject *kobj, - struct attribute *attr, - char *buf) -{ - struct ibft_kobject *dev = - container_of(kobj, struct ibft_kobject, kobj); - struct ibft_attribute *ibft_attr = - container_of(attr, struct ibft_attribute, attr); - ssize_t ret = -EIO; - char *str = buf; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - if (ibft_attr->show) - ret = ibft_attr->show(dev, ibft_attr, str); - - return ret; -} - -static const struct sysfs_ops ibft_attr_ops = { - .show = ibft_show_attribute, -}; - -static struct kobj_type ibft_ktype = { - .release = ibft_release, - .sysfs_ops = &ibft_attr_ops, -}; - -static struct kset *ibft_kset; - static int __init ibft_check_device(void) { int len; @@ -560,13 +429,150 @@ static int __init ibft_check_device(void) return 0; } +/* + * Helper routiners to check to determine if the entry is valid + * in the proper iBFT structure. + */ +static mode_t ibft_check_nic_for(void *data, int type) +{ + struct ibft_kobject *entry = data; + struct ibft_nic *nic = entry->nic; + mode_t rc = 0; + + switch (type) { + case ISCSI_BOOT_ETH_INDEX: + case ISCSI_BOOT_ETH_FLAGS: + rc = S_IRUGO; + break; + case ISCSI_BOOT_ETH_IP_ADDR: + if (memcmp(nic->ip_addr, nulls, sizeof(nic->ip_addr))) + rc = S_IRUGO; + break; + case ISCSI_BOOT_ETH_SUBNET_MASK: + if (nic->subnet_mask_prefix) + rc = S_IRUGO; + break; + case ISCSI_BOOT_ETH_ORIGIN: + rc = S_IRUGO; + break; + case ISCSI_BOOT_ETH_GATEWAY: + if (memcmp(nic->gateway, nulls, sizeof(nic->gateway))) + rc = S_IRUGO; + break; + case ISCSI_BOOT_ETH_PRIMARY_DNS: + if (memcmp(nic->primary_dns, nulls, + sizeof(nic->primary_dns))) + rc = S_IRUGO; + break; + case ISCSI_BOOT_ETH_SECONDARY_DNS: + if (memcmp(nic->secondary_dns, nulls, + sizeof(nic->secondary_dns))) + rc = S_IRUGO; + break; + case ISCSI_BOOT_ETH_DHCP: + if (memcmp(nic->dhcp, nulls, sizeof(nic->dhcp))) + rc = S_IRUGO; + break; + case ISCSI_BOOT_ETH_VLAN: + case ISCSI_BOOT_ETH_MAC: + rc = S_IRUGO; + break; + case ISCSI_BOOT_ETH_HOSTNAME: + if (nic->hostname_off) + rc = S_IRUGO; + break; + default: + break; + } + + return rc; +} + +static mode_t __init ibft_check_tgt_for(void *data, int type) +{ + struct ibft_kobject *entry = data; + struct ibft_tgt *tgt = entry->tgt; + mode_t rc = 0; + + switch (type) { + case ISCSI_BOOT_TGT_INDEX: + case ISCSI_BOOT_TGT_FLAGS: + case ISCSI_BOOT_TGT_IP_ADDR: + case ISCSI_BOOT_TGT_PORT: + case ISCSI_BOOT_TGT_LUN: + case ISCSI_BOOT_TGT_NIC_ASSOC: + case ISCSI_BOOT_TGT_CHAP_TYPE: + rc = S_IRUGO; + case ISCSI_BOOT_TGT_NAME: + if (tgt->tgt_name_len) + rc = S_IRUGO; + break; + case ISCSI_BOOT_TGT_CHAP_NAME: + case ISCSI_BOOT_TGT_CHAP_SECRET: + if (tgt->chap_name_len) + rc = S_IRUGO; + break; + case ISCSI_BOOT_TGT_REV_CHAP_NAME: + case ISCSI_BOOT_TGT_REV_CHAP_SECRET: + if (tgt->rev_chap_name_len) + rc = S_IRUGO; + break; + default: + break; + } + + return rc; +} + +static mode_t __init ibft_check_initiator_for(void *data, int type) +{ + struct ibft_kobject *entry = data; + struct ibft_initiator *init = entry->initiator; + mode_t rc = 0; + + switch (type) { + case ISCSI_BOOT_INI_INDEX: + case ISCSI_BOOT_INI_FLAGS: + rc = S_IRUGO; + break; + case ISCSI_BOOT_INI_ISNS_SERVER: + if (memcmp(init->isns_server, nulls, + sizeof(init->isns_server))) + rc = S_IRUGO; + break; + case ISCSI_BOOT_INI_SLP_SERVER: + if (memcmp(init->slp_server, nulls, + sizeof(init->slp_server))) + rc = S_IRUGO; + break; + case ISCSI_BOOT_INI_PRI_RADIUS_SERVER: + if (memcmp(init->pri_radius_server, nulls, + sizeof(init->pri_radius_server))) + rc = S_IRUGO; + break; + case ISCSI_BOOT_INI_SEC_RADIUS_SERVER: + if (memcmp(init->sec_radius_server, nulls, + sizeof(init->sec_radius_server))) + rc = S_IRUGO; + break; + case ISCSI_BOOT_INI_INITIATOR_NAME: + if (init->initiator_name_len) + rc = S_IRUGO; + break; + default: + break; + } + + return rc; +} + /* * Helper function for ibft_register_kobjects. */ static int __init ibft_create_kobject(struct acpi_table_ibft *header, - struct ibft_hdr *hdr, - struct list_head *list) + struct ibft_hdr *hdr) { + struct iscsi_boot_kobj *boot_kobj = NULL; struct ibft_kobject *ibft_kobj = NULL; struct ibft_nic *nic = (struct ibft_nic *)hdr; struct pci_dev *pci_dev; @@ -583,14 +589,47 @@ static int __init ibft_create_kobject(struct acpi_table_ibft *header, case id_initiator: rc = ibft_verify_hdr("initiator", hdr, id_initiator, sizeof(*ibft_kobj->initiator)); + if (rc) + break; + + boot_kobj = iscsi_boot_create_initiator(boot_kset, hdr->index, + ibft_kobj, + ibft_attr_show_initiator, + ibft_check_initiator_for); + if (!boot_kobj) { + rc = -ENOMEM; + goto free_ibft_obj; + } break; case id_nic: rc = ibft_verify_hdr("ethernet", hdr, id_nic, sizeof(*ibft_kobj->nic)); + if (rc) + break; + + boot_kobj = iscsi_boot_create_ethernet(boot_kset, hdr->index, + ibft_kobj, + ibft_attr_show_nic, + ibft_check_nic_for); + if (!boot_kobj) { + rc = -ENOMEM; + goto free_ibft_obj; + } break; case id_target: rc = ibft_verify_hdr("target", hdr, id_target, sizeof(*ibft_kobj->tgt)); + if (rc) + break; + + boot_kobj = iscsi_boot_create_target(boot_kset, hdr->index, + ibft_kobj, + ibft_attr_show_target, + ibft_check_tgt_for); + if (!boot_kobj) { + rc = -ENOMEM; + goto free_ibft_obj; + } break; case id_reserved: case id_control: @@ -608,22 +647,10 @@ static int __init ibft_create_kobject(struct acpi_table_ibft *header, if (rc) { /* Skip adding this kobject, but exit with non-fatal error. */ - kfree(ibft_kobj); - goto out_invalid_struct; - } - - ibft_kobj->kobj.kset = ibft_kset; - - rc = kobject_init_and_add(&ibft_kobj->kobj, &ibft_ktype, - NULL, ibft_id_names[hdr->id], hdr->index); - - if (rc) { - kfree(ibft_kobj); - goto out; + rc = 0; + goto free_ibft_obj; } - kobject_uevent(&ibft_kobj->kobj, KOBJ_ADD); - if (hdr->id == id_nic) { /* * We don't search for the device in other domains than @@ -634,19 +661,16 @@ static int __init ibft_create_kobject(struct acpi_table_ibft *header, pci_dev = pci_get_bus_and_slot((nic->pci_bdf & 0xff00) >> 8, (nic->pci_bdf & 0xff)); if (pci_dev) { - rc = sysfs_create_link(&ibft_kobj->kobj, + rc = sysfs_create_link(&boot_kobj->kobj, &pci_dev->dev.kobj, "device"); pci_dev_put(pci_dev); } } + return 0; - /* Nothing broke so lets add it to the list. */ - list_add_tail(&ibft_kobj->node, list); -out: +free_ibft_obj: + kfree(ibft_kobj); return rc; -out_invalid_struct: - /* Unsupported structs are skipped. */ - return 0; } /* @@ -654,8 +678,7 @@ out_invalid_struct: * found add them on the passed-in list. We do not support the other * fields at this point, so they are skipped. */ -static int __init ibft_register_kobjects(struct acpi_table_ibft *header, - struct list_head *list) +static int __init ibft_register_kobjects(struct acpi_table_ibft *header) { struct ibft_control *control = NULL; void *ptr, *end; @@ -680,8 +703,7 @@ static int __init ibft_register_kobjects(struct acpi_table_ibft *header, if (offset && offset < header->header.length && offset < eot_offset) { rc = ibft_create_kobject(header, - (void *)header + offset, - list); + (void *)header + offset); if (rc) break; } @@ -690,240 +712,28 @@ static int __init ibft_register_kobjects(struct acpi_table_ibft *header, return rc; } -static void ibft_unregister(struct list_head *attr_list, - struct list_head *kobj_list) +static void ibft_unregister(void) { - struct ibft_kobject *data = NULL, *n; - struct ibft_attribute *attr = NULL, *m; - - list_for_each_entry_safe(attr, m, attr_list, node) { - sysfs_remove_file(attr->kobj, &attr->attr); - list_del(&attr->node); - kfree(attr); + struct iscsi_boot_kobj *boot_kobj, *tmp_kobj; + struct ibft_kobject *ibft_kobj; + + list_for_each_entry_safe(boot_kobj, tmp_kobj, + &boot_kset->kobj_list, list) { + ibft_kobj = boot_kobj->data; + if (ibft_kobj->hdr->id == id_nic) + sysfs_remove_link(&boot_kobj->kobj, "device"); }; - list_del_init(attr_list); - - list_for_each_entry_safe(data, n, kobj_list, node) { - list_del(&data->node); - if (data->hdr->id == id_nic) - sysfs_remove_link(&data->kobj, "device"); - kobject_put(&data->kobj); - }; - list_del_init(kobj_list); } -static int __init ibft_create_attribute(struct ibft_kobject *kobj_data, - int type, - const char *name, - ssize_t (*show)(struct ibft_kobject *, - struct ibft_attribute*, - char *buf), - struct list_head *list) +static void ibft_cleanup(void) { - struct ibft_attribute *attr = NULL; - struct ibft_hdr *hdr = kobj_data->hdr; - - attr = kmalloc(sizeof(*attr), GFP_KERNEL); - if (!attr) - return -ENOMEM; - - attr->attr.name = name; - attr->attr.mode = S_IRUSR; - - attr->hdr = hdr; - attr->show = show; - attr->kobj = &kobj_data->kobj; - attr->type = type; - - list_add_tail(&attr->node, list); - - return 0; -} - -/* - * Helper routiners to check to determine if the entry is valid - * in the proper iBFT structure. - */ -static int __init ibft_check_nic_for(struct ibft_nic *nic, int entry) -{ - int rc = 0; - - switch (entry) { - case ibft_eth_index: - case ibft_eth_flags: - rc = 1; - break; - case ibft_eth_ip_addr: - if (memcmp(nic->ip_addr, nulls, sizeof(nic->ip_addr))) - rc = 1; - break; - case ibft_eth_subnet_mask: - if (nic->subnet_mask_prefix) - rc = 1; - break; - case ibft_eth_origin: - rc = 1; - break; - case ibft_eth_gateway: - if (memcmp(nic->gateway, nulls, sizeof(nic->gateway))) - rc = 1; - break; - case ibft_eth_primary_dns: - if (memcmp(nic->primary_dns, nulls, - sizeof(nic->primary_dns))) - rc = 1; - break; - case ibft_eth_secondary_dns: - if (memcmp(nic->secondary_dns, nulls, - sizeof(nic->secondary_dns))) - rc = 1; - break; - case ibft_eth_dhcp: - if (memcmp(nic->dhcp, nulls, sizeof(nic->dhcp))) - rc = 1; - break; - case ibft_eth_vlan: - case ibft_eth_mac: - rc = 1; - break; - case ibft_eth_hostname: - if (nic->hostname_off) - rc = 1; - break; - default: - break; - } - - return rc; + ibft_unregister(); + iscsi_boot_destroy_kset(boot_kset); } -static int __init ibft_check_tgt_for(struct ibft_tgt *tgt, int entry) -{ - int rc = 0; - - switch (entry) { - case ibft_tgt_index: - case ibft_tgt_flags: - case ibft_tgt_ip_addr: - case ibft_tgt_port: - case ibft_tgt_lun: - case ibft_tgt_nic_assoc: - case ibft_tgt_chap_type: - rc = 1; - case ibft_tgt_name: - if (tgt->tgt_name_len) - rc = 1; - break; - case ibft_tgt_chap_name: - case ibft_tgt_chap_secret: - if (tgt->chap_name_len) - rc = 1; - break; - case ibft_tgt_rev_chap_name: - case ibft_tgt_rev_chap_secret: - if (tgt->rev_chap_name_len) - rc = 1; - break; - default: - break; - } - - return rc; -} - -static int __init ibft_check_initiator_for(struct ibft_initiator *init, - int entry) -{ - int rc = 0; - - switch (entry) { - case ibft_init_index: - case ibft_init_flags: - rc = 1; - break; - case ibft_init_isns_server: - if (memcmp(init->isns_server, nulls, - sizeof(init->isns_server))) - rc = 1; - break; - case ibft_init_slp_server: - if (memcmp(init->slp_server, nulls, - sizeof(init->slp_server))) - rc = 1; - break; - case ibft_init_pri_radius_server: - if (memcmp(init->pri_radius_server, nulls, - sizeof(init->pri_radius_server))) - rc = 1; - break; - case ibft_init_sec_radius_server: - if (memcmp(init->sec_radius_server, nulls, - sizeof(init->sec_radius_server))) - rc = 1; - break; - case ibft_init_initiator_name: - if (init->initiator_name_len) - rc = 1; - break; - default: - break; - } - - return rc; -} - -/* - * Register the attributes for all of the kobjects. - */ -static int __init ibft_register_attributes(struct list_head *kobject_list, - struct list_head *attr_list) +static void __exit ibft_exit(void) { - int rc = 0, i = 0; - struct ibft_kobject *data = NULL; - struct ibft_attribute *attr = NULL, *m; - - list_for_each_entry(data, kobject_list, node) { - switch (data->hdr->id) { - case id_nic: - for (i = 0; i < ibft_eth_end_marker && !rc; i++) - if (ibft_check_nic_for(data->nic, i)) - rc = ibft_create_attribute(data, i, - ibft_eth_properties[i], - ibft_attr_show_nic, attr_list); - break; - case id_target: - for (i = 0; i < ibft_tgt_end_marker && !rc; i++) - if (ibft_check_tgt_for(data->tgt, i)) - rc = ibft_create_attribute(data, i, - ibft_tgt_properties[i], - ibft_attr_show_target, - attr_list); - break; - case id_initiator: - for (i = 0; i < ibft_init_end_marker && !rc; i++) - if (ibft_check_initiator_for( - data->initiator, i)) - rc = ibft_create_attribute(data, i, - ibft_initiator_properties[i], - ibft_attr_show_initiator, - attr_list); - break; - default: - break; - } - if (rc) - break; - } - list_for_each_entry_safe(attr, m, attr_list, node) { - rc = sysfs_create_file(attr->kobj, &attr->attr); - if (rc) { - list_del(&attr->node); - kfree(attr); - break; - } - } - - return rc; + ibft_cleanup(); } /* @@ -933,26 +743,20 @@ static int __init ibft_init(void) { int rc = 0; - ibft_kset = kset_create_and_add("ibft", NULL, firmware_kobj); - if (!ibft_kset) - return -ENOMEM; - if (ibft_addr) { printk(KERN_INFO "iBFT detected at 0x%llx.\n", (u64)isa_virt_to_bus(ibft_addr)); rc = ibft_check_device(); if (rc) - goto out_firmware_unregister; + return rc; - /* Scan the IBFT for data and register the kobjects. */ - rc = ibft_register_kobjects(ibft_addr, &ibft_kobject_list); - if (rc) - goto out_free; + boot_kset = iscsi_boot_create_kset("ibft"); + if (!boot_kset) + return -ENOMEM; - /* Register the attributes */ - rc = ibft_register_attributes(&ibft_kobject_list, - &ibft_attr_list); + /* Scan the IBFT for data and register the kobjects. */ + rc = ibft_register_kobjects(ibft_addr); if (rc) goto out_free; } else @@ -961,17 +765,9 @@ static int __init ibft_init(void) return 0; out_free: - ibft_unregister(&ibft_attr_list, &ibft_kobject_list); -out_firmware_unregister: - kset_unregister(ibft_kset); + ibft_cleanup(); return rc; } -static void __exit ibft_exit(void) -{ - ibft_unregister(&ibft_attr_list, &ibft_kobject_list); - kset_unregister(ibft_kset); -} - module_init(ibft_init); module_exit(ibft_exit); -- cgit v1.2.3 From 57a5f3c99c99f70f8fdfa0bbc83b98c48f56551a Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Wed, 12 May 2010 10:12:53 -0400 Subject: ibft: Use IBFT_SIGN instead of open-coding the search string. We define IBFT_SIGN to "iBFT"; may as well use it. Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Peter Jones --- drivers/firmware/iscsi_ibft_find.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/firmware/iscsi_ibft_find.c b/drivers/firmware/iscsi_ibft_find.c index 82a7a1566290..2192456dfd68 100644 --- a/drivers/firmware/iscsi_ibft_find.c +++ b/drivers/firmware/iscsi_ibft_find.c @@ -100,7 +100,7 @@ unsigned long __init find_ibft_region(unsigned long *sizep) if (!ibft_addr) acpi_table_parse(ACPI_SIG_IBFT, acpi_find_ibft); if (!ibft_addr) - acpi_table_parse("iBFT", acpi_find_ibft); + acpi_table_parse(IBFT_SIGN, acpi_find_ibft); #endif /* CONFIG_ACPI */ /* iBFT 1.03 section 1.4.3.1 mandates that UEFI machines will -- cgit v1.2.3 From 71753e0141a220ecbf9c71a66e0a8acce9705fb5 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 9 Dec 2009 16:55:15 -0300 Subject: EDAC: add __init to i7core_xeon_pci_fixup It's called only from an __init function and is the only user of pcibios_scan_specific_bus which will be marked as __devinit in the next patch. Signed-off-by: Jiri Slaby Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 4d6ecf1291b8..37ade251e9e2 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1170,7 +1170,7 @@ static void i7core_put_all_devices(void) i7core_put_devices(i7core_dev); } -static void i7core_xeon_pci_fixup(int dev_id) +static void __init i7core_xeon_pci_fixup(int dev_id) { struct pci_dev *pdev = NULL; int i; -- cgit v1.2.3 From 2a6fae326713ec84f307c045f6b497d4afaeb1d4 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Thu, 7 Jan 2010 23:27:30 -0300 Subject: i7core_edac: fix memory leak of i7core_dev Free already allocated i7core_dev. Signed-off-by: Alexander Beregalov Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 37ade251e9e2..8e93df637bca 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1249,8 +1249,10 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno, return -ENOMEM; i7core_dev->pdev = kzalloc(sizeof(*i7core_dev->pdev) * n_devs, GFP_KERNEL); - if (!i7core_dev->pdev) + if (!i7core_dev->pdev) { + kfree(i7core_dev); return -ENOMEM; + } i7core_dev->socket = socket; i7core_dev->n_devs = n_devs; list_add_tail(&i7core_dev->list, &i7core_edac_list); -- cgit v1.2.3 From 8a311e179e52d122ac203d8e88014284c18ca8ab Mon Sep 17 00:00:00 2001 From: Vernon Mauery Date: Fri, 16 Apr 2010 19:40:19 -0300 Subject: Always call i7core_[ur]dimm_check_mc_ecc_err This fixes an error in function i7core_check_error In commit ca9c90ba09ca3c9799319f46a56f397afbf617c2 which converts the driver to use double buffering, there is a change in the logic. Before, if mce_count was zero, it skipped over a couple of statements and finished out with a call to the *check_mc_ecc_err function. The current code checks to see if mce_count is 0 and then exits. This change reverts the behavior back to the original where if there are no errors to report, we skip to the end and call the *check_mc_ecc_err function. This fix allows the driver to work again on my Nehalem based blades again. Signed-off-by: Vernon Mauery Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 8e93df637bca..cd51709c4d89 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1670,7 +1670,7 @@ static void i7core_check_error(struct mem_ctl_info *mci) count = (pvt->mce_out + MCE_LOG_LEN - pvt->mce_in) % MCE_LOG_LEN; if (!count) - return; + goto check_ce_error; m = pvt->mce_outentry; if (pvt->mce_in + count > MCE_LOG_LEN) { @@ -1703,6 +1703,7 @@ static void i7core_check_error(struct mem_ctl_info *mci) /* * Now, let's increment CE error counts */ +check_ce_error: if (!pvt->is_registered) i7core_udimm_check_mc_ecc_err(mci); else -- cgit v1.2.3 From ac1ececea995fd77c8da6a1299674f22991cecaa Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 May 2010 13:00:31 -0300 Subject: i7core_edac: Add support for X5670 As reported by Vernon Mauery , X5670 (Westmere-EP) uses a different register for one of the uncore PCI devices. Add support for it. Those are the PCI ID's on this new chipset: fe:00.0 0600: 8086:2c70 (rev 02) fe:00.1 0600: 8086:2d81 (rev 02) fe:02.0 0600: 8086:2d90 (rev 02) fe:02.1 0600: 8086:2d91 (rev 02) fe:02.2 0600: 8086:2d92 (rev 02) fe:02.3 0600: 8086:2d93 (rev 02) fe:02.4 0600: 8086:2d94 (rev 02) fe:02.5 0600: 8086:2d95 (rev 02) fe:03.0 0600: 8086:2d98 (rev 02) fe:03.1 0600: 8086:2d99 (rev 02) fe:03.2 0600: 8086:2d9a (rev 02) fe:03.4 0600: 8086:2d9c (rev 02) fe:04.0 0600: 8086:2da0 (rev 02) fe:04.1 0600: 8086:2da1 (rev 02) fe:04.2 0600: 8086:2da2 (rev 02) fe:04.3 0600: 8086:2da3 (rev 02) fe:05.0 0600: 8086:2da8 (rev 02) fe:05.1 0600: 8086:2da9 (rev 02) fe:05.2 0600: 8086:2daa (rev 02) fe:05.3 0600: 8086:2dab (rev 02) fe:06.0 0600: 8086:2db0 (rev 02) fe:06.1 0600: 8086:2db1 (rev 02) fe:06.2 0600: 8086:2db2 (rev 02) fe:06.3 0600: 8086:2db3 (rev 02) (as usual, the same PCI devices repeat at ff: bus) The PCI device 8086:2c70 is shown as: fe:00.0 Host bridge: Intel Corporation QuickPath Architecture Generic Non-core Registers (rev 02) So, for this device to be recognized, it is only a matter of adding this new PCI ID to the driver. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index cd51709c4d89..82acfbd01779 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1213,10 +1213,15 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno, pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT, *prev); - if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE && !pdev) + if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE && !pdev) { pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT, *prev); + if (!pdev) + pdev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_REV2, + *prev); + } if (!pdev) { if (*prev) { -- cgit v1.2.3 From d4d1ef4515cca074d5bbe1c63420822d6b20fe63 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Tue, 18 May 2010 10:53:25 -0300 Subject: i7core_edac: don't free on success Signed-off-by: Tony Luck Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 82acfbd01779..3e2b5379bc05 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1856,7 +1856,8 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev, } fail: - edac_mc_free(mci); + if (rc < 0) + edac_mc_free(mci); return rc; } -- cgit v1.2.3 From bd9e19ca46b54fa85141c4d20afd668379d94c81 Mon Sep 17 00:00:00 2001 From: Vernon Mauery Date: Tue, 18 May 2010 19:02:50 -0300 Subject: Add support for Westmere to i7core_edac driver This adds new PCI IDs for the Westmere's memory controller devices and modifies the i7core_edac driver to be able to probe both Nehalem and Westmere processors. Signed-off-by: Vernon Mauery Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 117 +++++++++++++++++++++++++++++++-------------- 1 file changed, 80 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 3e2b5379bc05..8d63b0046480 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -206,6 +206,11 @@ struct pci_id_descr { int optional; }; +struct pci_id_table { + struct pci_id_descr *descr; + int n_devs; +}; + struct i7core_dev { struct list_head list; u8 socket; @@ -262,7 +267,7 @@ static DEFINE_MUTEX(i7core_edac_lock); .func = (function), \ .dev_id = (device_id) -struct pci_id_descr pci_dev_descr_i7core[] = { +struct pci_id_descr pci_dev_descr_i7core_nehalem[] = { /* Memory controller */ { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_I7_MCR) }, { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_I7_MC_TAD) }, @@ -321,6 +326,44 @@ struct pci_id_descr pci_dev_descr_lynnfield[] = { { PCI_DESCR( 0, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE) }, }; +struct pci_id_descr pci_dev_descr_i7core_westmere[] = { + /* Memory controller */ + { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR_REV2) }, + { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD_REV2) }, + /* Exists only for RDIMM */ + { PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_RAS_REV2), .optional = 1 }, + { PCI_DESCR(3, 4, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TEST_REV2) }, + + /* Channel 0 */ + { PCI_DESCR(4, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_CTRL_REV2) }, + { PCI_DESCR(4, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_ADDR_REV2) }, + { PCI_DESCR(4, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_RANK_REV2) }, + { PCI_DESCR(4, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_TC_REV2) }, + + /* Channel 1 */ + { PCI_DESCR(5, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_CTRL_REV2) }, + { PCI_DESCR(5, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_ADDR_REV2) }, + { PCI_DESCR(5, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK_REV2) }, + { PCI_DESCR(5, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC_REV2) }, + + /* Channel 2 */ + { PCI_DESCR(6, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_CTRL_REV2) }, + { PCI_DESCR(6, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_ADDR_REV2) }, + { PCI_DESCR(6, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_RANK_REV2) }, + { PCI_DESCR(6, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_TC_REV2) }, + + /* Generic Non-core registers */ + { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_REV2) }, + +}; + +#define PCI_ID_TABLE_ENTRY(A) { A, ARRAY_SIZE(A) } +struct pci_id_table pci_dev_table[] = { + PCI_ID_TABLE_ENTRY(pci_dev_descr_i7core_nehalem), + PCI_ID_TABLE_ENTRY(pci_dev_descr_lynnfield), + PCI_ID_TABLE_ENTRY(pci_dev_descr_i7core_westmere), +}; + /* * pci_device_id table for which devices we are looking for */ @@ -1170,7 +1213,7 @@ static void i7core_put_all_devices(void) i7core_put_devices(i7core_dev); } -static void __init i7core_xeon_pci_fixup(int dev_id) +static void __init i7core_xeon_pci_fixup(struct pci_id_table *table) { struct pci_dev *pdev = NULL; int i; @@ -1179,10 +1222,13 @@ static void __init i7core_xeon_pci_fixup(int dev_id) * aren't announced by acpi. So, we need to use a legacy scan probing * to detect them */ - pdev = pci_get_device(PCI_VENDOR_ID_INTEL, dev_id, NULL); - if (unlikely(!pdev)) { - for (i = 0; i < MAX_SOCKET_BUSES; i++) - pcibios_scan_specific_bus(255-i); + while (table && table->descr) { + pdev = pci_get_device(PCI_VENDOR_ID_INTEL, table->descr[0].dev_id, NULL); + if (unlikely(!pdev)) { + for (i = 0; i < MAX_SOCKET_BUSES; i++) + pcibios_scan_specific_bus(255-i); + } + table++; } } @@ -1213,15 +1259,10 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno, pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT, *prev); - if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE && !pdev) { + if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE && !pdev) pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT, *prev); - if (!pdev) - pdev = pci_get_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_REV2, - *prev); - } if (!pdev) { if (*prev) { @@ -1232,6 +1273,9 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno, if (dev_descr->optional) return 0; + if (devno == 0) + return -ENODEV; + i7core_printk(KERN_ERR, "Device not found: dev %02x.%d PCI ID %04x:%04x\n", dev_descr->dev, dev_descr->func, @@ -1307,24 +1351,34 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno, return 0; } -static int i7core_get_devices(struct pci_id_descr dev_descr[], unsigned n_devs) +static int i7core_get_devices(struct pci_id_table *table) { int i, rc; struct pci_dev *pdev = NULL; - - for (i = 0; i < n_devs; i++) { - pdev = NULL; - do { - rc = i7core_get_onedevice(&pdev, i, &dev_descr[i], - n_devs); - if (rc < 0) { - i7core_put_all_devices(); - return -ENODEV; - } - } while (pdev); + struct pci_id_descr *dev_descr; + + while (table && table->descr) { + dev_descr = table->descr; + for (i = 0; i < table->n_devs; i++) { + pdev = NULL; + do { + rc = i7core_get_onedevice(&pdev, i, &dev_descr[i], + table->n_devs); + if (rc < 0) { + if (i == 0) { + i = table->n_devs; + break; + } + i7core_put_all_devices(); + return -ENODEV; + } + } while (pdev); + } + table++; } return 0; + return 0; } static int mci_bind_devs(struct mem_ctl_info *mci, @@ -1884,18 +1938,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, /* get the pci devices we want to reserve for our use */ mutex_lock(&i7core_edac_lock); - if (pdev->device == PCI_DEVICE_ID_INTEL_LYNNFIELD_QPI_LINK0) { - printk(KERN_INFO "i7core_edac: detected a " - "Lynnfield processor\n"); - rc = i7core_get_devices(pci_dev_descr_lynnfield, - ARRAY_SIZE(pci_dev_descr_lynnfield)); - } else { - printk(KERN_INFO "i7core_edac: detected a " - "Nehalem/Nehalem-EP processor\n"); - rc = i7core_get_devices(pci_dev_descr_i7core, - ARRAY_SIZE(pci_dev_descr_i7core)); - } - + rc = i7core_get_devices(pci_dev_table); if (unlikely(rc < 0)) goto fail0; @@ -1994,7 +2037,7 @@ static int __init i7core_init(void) /* Ensure that the OPSTATE is set correctly for POLL or NMI */ opstate_init(); - i7core_xeon_pci_fixup(pci_dev_descr_i7core[0].dev_id); + i7core_xeon_pci_fixup(pci_dev_table); pci_rc = pci_register_driver(&i7core_driver); -- cgit v1.2.3 From 52707f918cca231f8461d45e78a60014795f20d9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 May 2010 20:43:52 -0300 Subject: i7core_edac: Better describe the supported devices Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 8d63b0046480..6b8b7b41ec5f 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1,9 +1,14 @@ -/* Intel 7 core Memory Controller kernel module (Nehalem) +/* Intel i7 core/Nehalem Memory Controller kernel module + * + * This driver supports yhe memory controllers found on the Intel + * processor families i7core, i7core 7xx/8xx, i5core, Xeon 35xx, + * Xeon 55xx and Xeon 56xx also known as Nehalem, Nehalem-EP, Lynnfield + * and Westmere-EP. * * This file may be distributed under the terms of the * GNU General Public License version 2 only. * - * Copyright (c) 2009 by: + * Copyright (c) 2009-2010 by: * Mauro Carvalho Chehab * * Red Hat Inc. http://www.redhat.com -- cgit v1.2.3 From df1f1d1cb43b4ffdef5ba5f0623e2f73e94ce030 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 22 May 2010 10:22:49 +0200 Subject: drivers/mtd: Use memdup_user Use memdup_user when user data is immediately copied into the allocated region. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression from,to,size,flag; position p; identifier l1,l2; @@ - to = \(kmalloc@p\|kzalloc@p\)(size,flag); + to = memdup_user(from,size); if ( - to==NULL + IS_ERR(to) || ...) { <+... when != goto l1; - -ENOMEM + PTR_ERR(to) ...+> } - if (copy_from_user(to, from, size) != 0) { - <+... when != goto l2; - -EFAULT - ...+> - } // Signed-off-by: Julia Lawall Signed-off-by: David Woodhouse --- drivers/mtd/mtdchar.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 8bb5e4a66328..8b223c0343ee 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -404,14 +404,9 @@ static int mtd_do_writeoob(struct file *file, struct mtd_info *mtd, if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs)) return -EINVAL; - ops.oobbuf = kmalloc(length, GFP_KERNEL); - if (!ops.oobbuf) - return -ENOMEM; - - if (copy_from_user(ops.oobbuf, ptr, length)) { - kfree(ops.oobbuf); - return -EFAULT; - } + ops.oobbuf = memdup_user(ptr, length); + if (IS_ERR(ops.oobbuf)) + return PTR_ERR(ops.oobbuf); start &= ~((uint64_t)mtd->oobsize - 1); ret = mtd->write_oob(mtd, start, &ops); -- cgit v1.2.3 From e1f42ff4f06e5feaa57a22556ad977ef62164e14 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 24 May 2010 07:53:24 +0000 Subject: fbdev: fix erroneous index in drivers/video/sh_mobile_lcdcfb.c Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_lcdcfb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index e8c769944812..12c451a711e9 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -991,13 +991,13 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) priv->ch[j].lcdc = priv; memcpy(&priv->ch[j].cfg, &pdata->ch[i], sizeof(pdata->ch[i])); - error = sh_mobile_lcdc_check_interface(&priv->ch[i]); + error = sh_mobile_lcdc_check_interface(&priv->ch[j]); if (error) { dev_err(&pdev->dev, "unsupported interface type\n"); goto err1; } - init_waitqueue_head(&priv->ch[i].frame_end_wait); - init_completion(&priv->ch[i].vsync_completion); + init_waitqueue_head(&priv->ch[j].frame_end_wait); + init_completion(&priv->ch[j].vsync_completion); priv->ch[j].pan_offset = 0; switch (pdata->ch[i].chan) { -- cgit v1.2.3 From 83efb8fe671af3c7b5613868aadc93ce973b6c3d Mon Sep 17 00:00:00 2001 From: Stefan Achatz Date: Wed, 19 May 2010 22:41:10 +0200 Subject: HID: remove unused variable from hidraw_read Removed unused variable from hidraw_read. Signed-off-by: Stefan Achatz Signed-off-by: Jiri Kosina --- drivers/hid/hidraw.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 3ccd47850677..47d70c523d93 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -46,7 +46,6 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, { struct hidraw_list *list = file->private_data; int ret = 0, len; - char *report; DECLARE_WAITQUEUE(wait, current); mutex_lock(&list->read_mutex); @@ -84,7 +83,6 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, if (ret) goto out; - report = list->buffer[list->tail].value; len = list->buffer[list->tail].len > count ? count : list->buffer[list->tail].len; -- cgit v1.2.3 From 4b3fb4e79cc3e40ec033a77f1b3d81e7851a6cf5 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 25 May 2010 19:47:12 +0900 Subject: input: serio: disable i8042 for non-cayman sh platforms. The sh64 cayman platform is the only sh board that ships with an i8042, so we just hide it for all of the others. Signed-off-by: Paul Mundt --- drivers/input/serio/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index f34f1dbeb577..3bfe8fafc6ad 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -21,7 +21,8 @@ if SERIO config SERIO_I8042 tristate "i8042 PC Keyboard controller" if EMBEDDED || !X86 default y - depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && !M68K && !BLACKFIN + depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && \ + (!SUPERH || SH_CAYMAN) && !M68K && !BLACKFIN help i8042 is the chip over which the standard AT keyboard and PS/2 mouse are connected to the computer. If you use these devices, -- cgit v1.2.3 From ff6c7341e0bc486c3e1b369ab7f3b325b98600d3 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 25 May 2010 17:37:08 -0700 Subject: n2_crypto: Fix build after of_device/of_platform_driver changes. Signed-off-by: David S. Miller --- drivers/crypto/n2_core.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c index 8566be832f51..1a5b1e709d67 100644 --- a/drivers/crypto/n2_core.c +++ b/drivers/crypto/n2_core.c @@ -1398,7 +1398,7 @@ static int find_devino_index(struct of_device *dev, struct spu_mdesc_info *ip, intr = ip->ino_table[i].intr; - dev_intrs = of_get_property(dev->node, "interrupts", NULL); + dev_intrs = of_get_property(dev->dev.of_node, "interrupts", NULL); if (!dev_intrs) return -ENODEV; @@ -1574,7 +1574,7 @@ static int spu_mdesc_walk_arcs(struct mdesc_handle *mdesc, id = mdesc_get_property(mdesc, tgt, "id", NULL); if (table[*id] != NULL) { dev_err(&dev->dev, "%s: SPU cpu slot already set.\n", - dev->node->full_name); + dev->dev.of_node->full_name); return -EINVAL; } cpu_set(*id, p->sharing); @@ -1595,7 +1595,7 @@ static int handle_exec_unit(struct spu_mdesc_info *ip, struct list_head *list, p = kzalloc(sizeof(struct spu_queue), GFP_KERNEL); if (!p) { dev_err(&dev->dev, "%s: Could not allocate SPU queue.\n", - dev->node->full_name); + dev->dev.of_node->full_name); return -ENOMEM; } @@ -1684,7 +1684,7 @@ static int __devinit grab_mdesc_irq_props(struct mdesc_handle *mdesc, const unsigned int *reg; u64 node; - reg = of_get_property(dev->node, "reg", NULL); + reg = of_get_property(dev->dev.of_node, "reg", NULL); if (!reg) return -ENODEV; @@ -1836,7 +1836,7 @@ static int __devinit n2_crypto_probe(struct of_device *dev, n2_spu_driver_version(); - full_name = dev->node->full_name; + full_name = dev->dev.of_node->full_name; pr_info("Found N2CP at %s\n", full_name); np = alloc_n2cp(); @@ -1948,7 +1948,7 @@ static int __devinit n2_mau_probe(struct of_device *dev, n2_spu_driver_version(); - full_name = dev->node->full_name; + full_name = dev->dev.of_node->full_name; pr_info("Found NCP at %s\n", full_name); mp = alloc_ncp(); @@ -2034,8 +2034,11 @@ static struct of_device_id n2_crypto_match[] = { MODULE_DEVICE_TABLE(of, n2_crypto_match); static struct of_platform_driver n2_crypto_driver = { - .name = "n2cp", - .match_table = n2_crypto_match, + .driver = { + .name = "n2cp", + .owner = THIS_MODULE, + .of_match_table = n2_crypto_match, + }, .probe = n2_crypto_probe, .remove = __devexit_p(n2_crypto_remove), }; @@ -2055,8 +2058,11 @@ static struct of_device_id n2_mau_match[] = { MODULE_DEVICE_TABLE(of, n2_mau_match); static struct of_platform_driver n2_mau_driver = { - .name = "ncp", - .match_table = n2_mau_match, + .driver = { + .name = "ncp", + .owner = THIS_MODULE, + .of_match_table = n2_mau_match, + }, .probe = n2_mau_probe, .remove = __devexit_p(n2_mau_remove), }; -- cgit v1.2.3 From 527b9525256f97ad8d092bbfc8fdc3c5409f4a4d Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sat, 22 May 2010 00:50:12 -0700 Subject: n2_crypto: Fix MAU kmem_cache name. Both the CWQ and MAU caches unintentionally had that same name. Signed-off-by: David S. Miller --- drivers/crypto/n2_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c index 1a5b1e709d67..5613b8affe11 100644 --- a/drivers/crypto/n2_core.c +++ b/drivers/crypto/n2_core.c @@ -1449,7 +1449,7 @@ static int queue_cache_init(void) { if (!queue_cache[HV_NCS_QTYPE_MAU - 1]) queue_cache[HV_NCS_QTYPE_MAU - 1] = - kmem_cache_create("cwq_queue", + kmem_cache_create("mau_queue", (MAU_NUM_ENTRIES * MAU_ENTRY_SIZE), MAU_ENTRY_SIZE, 0, NULL); -- cgit v1.2.3 From c9aa55e5271a53d28e93fa58759d318b403c15ba Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sat, 22 May 2010 01:09:04 -0700 Subject: n2_crypto: Plumb fallback ahash requests properly. Do this by putting the async fallback request at the end of an n2 specific ahash request context, then properly adjusting the request private size in our ahash ->cra_init(). We also need to put the writable state bits into the n2 request private instead of the n2 cra_ctx. With help from Herbert Xu. Signed-off-by: David S. Miller --- drivers/crypto/n2_core.c | 95 ++++++++++++++++++++++++------------------------ 1 file changed, 48 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c index 5613b8affe11..23163fda5035 100644 --- a/drivers/crypto/n2_core.c +++ b/drivers/crypto/n2_core.c @@ -251,16 +251,10 @@ static void n2_base_ctx_init(struct n2_base_ctx *ctx) struct n2_hash_ctx { struct n2_base_ctx base; - struct crypto_ahash *fallback; + struct crypto_ahash *fallback_tfm; +}; - /* These next three members must match the layout created by - * crypto_init_shash_ops_async. This allows us to properly - * plumb requests we can't do in hardware down to the fallback - * operation, providing all of the data structures and layouts - * expected by those paths. - */ - struct ahash_request fallback_req; - struct shash_desc fallback_desc; +struct n2_hash_req_ctx { union { struct md5_state md5; struct sha1_state sha1; @@ -269,56 +263,62 @@ struct n2_hash_ctx { unsigned char hash_key[64]; unsigned char keyed_zero_hash[32]; + + struct ahash_request fallback_req; }; static int n2_hash_async_init(struct ahash_request *req) { + struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); - ctx->fallback_req.base.tfm = crypto_ahash_tfm(ctx->fallback); - ctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; + ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); + rctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; - return crypto_ahash_init(&ctx->fallback_req); + return crypto_ahash_init(&rctx->fallback_req); } static int n2_hash_async_update(struct ahash_request *req) { + struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); - ctx->fallback_req.base.tfm = crypto_ahash_tfm(ctx->fallback); - ctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; - ctx->fallback_req.nbytes = req->nbytes; - ctx->fallback_req.src = req->src; + ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); + rctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; + rctx->fallback_req.nbytes = req->nbytes; + rctx->fallback_req.src = req->src; - return crypto_ahash_update(&ctx->fallback_req); + return crypto_ahash_update(&rctx->fallback_req); } static int n2_hash_async_final(struct ahash_request *req) { + struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); - ctx->fallback_req.base.tfm = crypto_ahash_tfm(ctx->fallback); - ctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; - ctx->fallback_req.result = req->result; + ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); + rctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; + rctx->fallback_req.result = req->result; - return crypto_ahash_final(&ctx->fallback_req); + return crypto_ahash_final(&rctx->fallback_req); } static int n2_hash_async_finup(struct ahash_request *req) { + struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); - ctx->fallback_req.base.tfm = crypto_ahash_tfm(ctx->fallback); - ctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; - ctx->fallback_req.nbytes = req->nbytes; - ctx->fallback_req.src = req->src; - ctx->fallback_req.result = req->result; + ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); + rctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; + rctx->fallback_req.nbytes = req->nbytes; + rctx->fallback_req.src = req->src; + rctx->fallback_req.result = req->result; - return crypto_ahash_finup(&ctx->fallback_req); + return crypto_ahash_finup(&rctx->fallback_req); } static int n2_hash_cra_init(struct crypto_tfm *tfm) @@ -338,7 +338,10 @@ static int n2_hash_cra_init(struct crypto_tfm *tfm) goto out; } - ctx->fallback = fallback_tfm; + crypto_ahash_set_reqsize(ahash, (sizeof(struct n2_hash_req_ctx) + + crypto_ahash_reqsize(fallback_tfm))); + + ctx->fallback_tfm = fallback_tfm; return 0; out: @@ -350,7 +353,7 @@ static void n2_hash_cra_exit(struct crypto_tfm *tfm) struct crypto_ahash *ahash = __crypto_ahash_cast(tfm); struct n2_hash_ctx *ctx = crypto_ahash_ctx(ahash); - crypto_free_ahash(ctx->fallback); + crypto_free_ahash(ctx->fallback_tfm); } static unsigned long wait_for_tail(struct spu_queue *qp) @@ -399,14 +402,16 @@ static int n2_hash_async_digest(struct ahash_request *req, * exceed 2^16. */ if (unlikely(req->nbytes > (1 << 16))) { - ctx->fallback_req.base.tfm = crypto_ahash_tfm(ctx->fallback); - ctx->fallback_req.base.flags = + struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); + + ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); + rctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; - ctx->fallback_req.nbytes = req->nbytes; - ctx->fallback_req.src = req->src; - ctx->fallback_req.result = req->result; + rctx->fallback_req.nbytes = req->nbytes; + rctx->fallback_req.src = req->src; + rctx->fallback_req.result = req->result; - return crypto_ahash_digest(&ctx->fallback_req); + return crypto_ahash_digest(&rctx->fallback_req); } n2_base_ctx_init(&ctx->base); @@ -472,9 +477,8 @@ out: static int n2_md5_async_digest(struct ahash_request *req) { - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); - struct md5_state *m = &ctx->u.md5; + struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); + struct md5_state *m = &rctx->u.md5; if (unlikely(req->nbytes == 0)) { static const char md5_zero[MD5_DIGEST_SIZE] = { @@ -497,9 +501,8 @@ static int n2_md5_async_digest(struct ahash_request *req) static int n2_sha1_async_digest(struct ahash_request *req) { - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); - struct sha1_state *s = &ctx->u.sha1; + struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); + struct sha1_state *s = &rctx->u.sha1; if (unlikely(req->nbytes == 0)) { static const char sha1_zero[SHA1_DIGEST_SIZE] = { @@ -524,9 +527,8 @@ static int n2_sha1_async_digest(struct ahash_request *req) static int n2_sha256_async_digest(struct ahash_request *req) { - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); - struct sha256_state *s = &ctx->u.sha256; + struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); + struct sha256_state *s = &rctx->u.sha256; if (req->nbytes == 0) { static const char sha256_zero[SHA256_DIGEST_SIZE] = { @@ -555,9 +557,8 @@ static int n2_sha256_async_digest(struct ahash_request *req) static int n2_sha224_async_digest(struct ahash_request *req) { - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); - struct sha256_state *s = &ctx->u.sha256; + struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); + struct sha256_state *s = &rctx->u.sha256; if (req->nbytes == 0) { static const char sha224_zero[SHA224_DIGEST_SIZE] = { -- cgit v1.2.3 From 65a23d6706ce2d58e302970971e41688783bf63f Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sat, 22 May 2010 01:11:03 -0700 Subject: n2_crypto: Kill n2_base_ctx and helpers. Unused, and we'll do this via the request context. Signed-off-by: David S. Miller --- drivers/crypto/n2_core.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c index 23163fda5035..3a4eed4bba2a 100644 --- a/drivers/crypto/n2_core.c +++ b/drivers/crypto/n2_core.c @@ -239,18 +239,7 @@ static inline bool n2_should_run_async(struct spu_queue *qp, int this_len) } #endif -struct n2_base_ctx { - struct list_head list; -}; - -static void n2_base_ctx_init(struct n2_base_ctx *ctx) -{ - INIT_LIST_HEAD(&ctx->list); -} - struct n2_hash_ctx { - struct n2_base_ctx base; - struct crypto_ahash *fallback_tfm; }; @@ -390,7 +379,6 @@ static int n2_hash_async_digest(struct ahash_request *req, unsigned int result_size, void *hash_loc) { struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); struct cwq_initial_entry *ent; struct crypto_hash_walk walk; struct spu_queue *qp; @@ -403,6 +391,7 @@ static int n2_hash_async_digest(struct ahash_request *req, */ if (unlikely(req->nbytes > (1 << 16))) { struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); + struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); rctx->fallback_req.base.flags = @@ -414,8 +403,6 @@ static int n2_hash_async_digest(struct ahash_request *req, return crypto_ahash_digest(&rctx->fallback_req); } - n2_base_ctx_init(&ctx->base); - nbytes = crypto_hash_walk_first(req, &walk); cpu = get_cpu(); -- cgit v1.2.3 From 38511108a37e5551b2bfe143a957132d46f9e6e7 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 19 May 2010 23:16:05 -0700 Subject: n2_crypto: Log algorithm success/failure in kernel log. Signed-off-by: David S. Miller --- drivers/crypto/n2_core.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c index 3a4eed4bba2a..77939e40e26f 100644 --- a/drivers/crypto/n2_core.c +++ b/drivers/crypto/n2_core.c @@ -1277,8 +1277,11 @@ static int __devinit __n2_register_one_cipher(const struct n2_cipher_tmpl *tmpl) list_add(&p->entry, &cipher_algs); err = crypto_register_alg(alg); if (err) { + pr_err("%s alg registration failed\n", alg->cra_name); list_del(&p->entry); kfree(p); + } else { + pr_info("%s alg registered\n", alg->cra_name); } return err; } @@ -1318,8 +1321,11 @@ static int __devinit __n2_register_one_ahash(const struct n2_hash_tmpl *tmpl) list_add(&p->entry, &ahash_algs); err = crypto_register_ahash(ahash); if (err) { + pr_err("%s alg registration failed\n", base->cra_name); list_del(&p->entry); kfree(p); + } else { + pr_info("%s alg registered\n", base->cra_name); } return err; } -- cgit v1.2.3 From 3a2c034697558602a72e51897c6d3665bc515927 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sat, 22 May 2010 02:45:56 -0700 Subject: n2_crypto: Make ahash parameterization explicit. All of the ahash ->digest() ops do essentially the same thing, just using different parameters. So instead, have a single n2_hash_async_digest() and use an n2_ahash_alg container that provides the parameters. Signed-off-by: David S. Miller --- drivers/crypto/n2_core.c | 216 ++++++++++++++++++++++------------------------- 1 file changed, 99 insertions(+), 117 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c index 77939e40e26f..d01a2afda6e9 100644 --- a/drivers/crypto/n2_core.c +++ b/drivers/crypto/n2_core.c @@ -239,6 +239,26 @@ static inline bool n2_should_run_async(struct spu_queue *qp, int this_len) } #endif +struct n2_ahash_alg { + struct list_head entry; + const char *hash_zero; + const u32 *hash_init; + u8 hw_op_hashsz; + u8 digest_size; + u8 auth_type; + struct ahash_alg alg; +}; + +static inline struct n2_ahash_alg *n2_ahash_alg(struct crypto_tfm *tfm) +{ + struct crypto_alg *alg = tfm->__crt_alg; + struct ahash_alg *ahash_alg; + + ahash_alg = container_of(alg, struct ahash_alg, halg.base); + + return container_of(ahash_alg, struct n2_ahash_alg, alg); +} + struct n2_hash_ctx { struct crypto_ahash *fallback_tfm; }; @@ -250,9 +270,6 @@ struct n2_hash_req_ctx { struct sha256_state sha256; } u; - unsigned char hash_key[64]; - unsigned char keyed_zero_hash[32]; - struct ahash_request fallback_req; }; @@ -374,9 +391,9 @@ static unsigned long submit_and_wait_for_tail(struct spu_queue *qp, return hv_ret; } -static int n2_hash_async_digest(struct ahash_request *req, - unsigned int auth_type, unsigned int digest_size, - unsigned int result_size, void *hash_loc) +static int n2_do_async_digest(struct ahash_request *req, + unsigned int auth_type, unsigned int digest_size, + unsigned int result_size, void *hash_loc) { struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct cwq_initial_entry *ent; @@ -462,114 +479,22 @@ out: return err; } -static int n2_md5_async_digest(struct ahash_request *req) -{ - struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); - struct md5_state *m = &rctx->u.md5; - - if (unlikely(req->nbytes == 0)) { - static const char md5_zero[MD5_DIGEST_SIZE] = { - 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, - 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e, - }; - - memcpy(req->result, md5_zero, MD5_DIGEST_SIZE); - return 0; - } - m->hash[0] = cpu_to_le32(0x67452301); - m->hash[1] = cpu_to_le32(0xefcdab89); - m->hash[2] = cpu_to_le32(0x98badcfe); - m->hash[3] = cpu_to_le32(0x10325476); - - return n2_hash_async_digest(req, AUTH_TYPE_MD5, - MD5_DIGEST_SIZE, MD5_DIGEST_SIZE, - m->hash); -} - -static int n2_sha1_async_digest(struct ahash_request *req) +static int n2_hash_async_digest(struct ahash_request *req) { + struct n2_ahash_alg *n2alg = n2_ahash_alg(req->base.tfm); struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); - struct sha1_state *s = &rctx->u.sha1; + int ds; + ds = n2alg->digest_size; if (unlikely(req->nbytes == 0)) { - static const char sha1_zero[SHA1_DIGEST_SIZE] = { - 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, - 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, - 0x07, 0x09 - }; - - memcpy(req->result, sha1_zero, SHA1_DIGEST_SIZE); - return 0; - } - s->state[0] = SHA1_H0; - s->state[1] = SHA1_H1; - s->state[2] = SHA1_H2; - s->state[3] = SHA1_H3; - s->state[4] = SHA1_H4; - - return n2_hash_async_digest(req, AUTH_TYPE_SHA1, - SHA1_DIGEST_SIZE, SHA1_DIGEST_SIZE, - s->state); -} - -static int n2_sha256_async_digest(struct ahash_request *req) -{ - struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); - struct sha256_state *s = &rctx->u.sha256; - - if (req->nbytes == 0) { - static const char sha256_zero[SHA256_DIGEST_SIZE] = { - 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, - 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, - 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, - 0x1b, 0x78, 0x52, 0xb8, 0x55 - }; - - memcpy(req->result, sha256_zero, SHA256_DIGEST_SIZE); - return 0; - } - s->state[0] = SHA256_H0; - s->state[1] = SHA256_H1; - s->state[2] = SHA256_H2; - s->state[3] = SHA256_H3; - s->state[4] = SHA256_H4; - s->state[5] = SHA256_H5; - s->state[6] = SHA256_H6; - s->state[7] = SHA256_H7; - - return n2_hash_async_digest(req, AUTH_TYPE_SHA256, - SHA256_DIGEST_SIZE, SHA256_DIGEST_SIZE, - s->state); -} - -static int n2_sha224_async_digest(struct ahash_request *req) -{ - struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); - struct sha256_state *s = &rctx->u.sha256; - - if (req->nbytes == 0) { - static const char sha224_zero[SHA224_DIGEST_SIZE] = { - 0xd1, 0x4a, 0x02, 0x8c, 0x2a, 0x3a, 0x2b, 0xc9, 0x47, - 0x61, 0x02, 0xbb, 0x28, 0x82, 0x34, 0xc4, 0x15, 0xa2, - 0xb0, 0x1f, 0x82, 0x8e, 0xa6, 0x2a, 0xc5, 0xb3, 0xe4, - 0x2f - }; - - memcpy(req->result, sha224_zero, SHA224_DIGEST_SIZE); + memcpy(req->result, n2alg->hash_zero, ds); return 0; } - s->state[0] = SHA224_H0; - s->state[1] = SHA224_H1; - s->state[2] = SHA224_H2; - s->state[3] = SHA224_H3; - s->state[4] = SHA224_H4; - s->state[5] = SHA224_H5; - s->state[6] = SHA224_H6; - s->state[7] = SHA224_H7; + memcpy(&rctx->u, n2alg->hash_init, n2alg->hw_op_hashsz); - return n2_hash_async_digest(req, AUTH_TYPE_SHA256, - SHA256_DIGEST_SIZE, SHA224_DIGEST_SIZE, - s->state); + return n2_do_async_digest(req, n2alg->auth_type, + n2alg->hw_op_hashsz, ds, + &rctx->u); } struct n2_cipher_context { @@ -1196,34 +1121,85 @@ static LIST_HEAD(cipher_algs); struct n2_hash_tmpl { const char *name; - int (*digest)(struct ahash_request *req); + const char *hash_zero; + const u32 *hash_init; + u8 hw_op_hashsz; u8 digest_size; u8 block_size; + u8 auth_type; +}; + +static const char md5_zero[MD5_DIGEST_SIZE] = { + 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, + 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e, +}; +static const u32 md5_init[MD5_HASH_WORDS] = { + cpu_to_le32(0x67452301), + cpu_to_le32(0xefcdab89), + cpu_to_le32(0x98badcfe), + cpu_to_le32(0x10325476), +}; +static const char sha1_zero[SHA1_DIGEST_SIZE] = { + 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, + 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, + 0x07, 0x09 +}; +static const u32 sha1_init[SHA1_DIGEST_SIZE / 4] = { + SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4, +}; +static const char sha256_zero[SHA256_DIGEST_SIZE] = { + 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, + 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, + 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, + 0x1b, 0x78, 0x52, 0xb8, 0x55 +}; +static const u32 sha256_init[SHA256_DIGEST_SIZE / 4] = { + SHA256_H0, SHA256_H1, SHA256_H2, SHA256_H3, + SHA256_H4, SHA256_H5, SHA256_H6, SHA256_H7, +}; +static const char sha224_zero[SHA224_DIGEST_SIZE] = { + 0xd1, 0x4a, 0x02, 0x8c, 0x2a, 0x3a, 0x2b, 0xc9, 0x47, + 0x61, 0x02, 0xbb, 0x28, 0x82, 0x34, 0xc4, 0x15, 0xa2, + 0xb0, 0x1f, 0x82, 0x8e, 0xa6, 0x2a, 0xc5, 0xb3, 0xe4, + 0x2f }; +static const u32 sha224_init[SHA256_DIGEST_SIZE / 4] = { + SHA224_H0, SHA224_H1, SHA224_H2, SHA224_H3, + SHA224_H4, SHA224_H5, SHA224_H6, SHA224_H7, +}; + static const struct n2_hash_tmpl hash_tmpls[] = { { .name = "md5", - .digest = n2_md5_async_digest, + .hash_zero = md5_zero, + .hash_init = md5_init, + .auth_type = AUTH_TYPE_MD5, + .hw_op_hashsz = MD5_DIGEST_SIZE, .digest_size = MD5_DIGEST_SIZE, .block_size = MD5_HMAC_BLOCK_SIZE }, { .name = "sha1", - .digest = n2_sha1_async_digest, + .hash_zero = sha1_zero, + .hash_init = sha1_init, + .auth_type = AUTH_TYPE_SHA1, + .hw_op_hashsz = SHA1_DIGEST_SIZE, .digest_size = SHA1_DIGEST_SIZE, .block_size = SHA1_BLOCK_SIZE }, { .name = "sha256", - .digest = n2_sha256_async_digest, + .hash_zero = sha256_zero, + .hash_init = sha256_init, + .auth_type = AUTH_TYPE_SHA256, + .hw_op_hashsz = SHA256_DIGEST_SIZE, .digest_size = SHA256_DIGEST_SIZE, .block_size = SHA256_BLOCK_SIZE }, { .name = "sha224", - .digest = n2_sha224_async_digest, + .hash_zero = sha224_zero, + .hash_init = sha224_init, + .auth_type = AUTH_TYPE_SHA256, + .hw_op_hashsz = SHA256_DIGEST_SIZE, .digest_size = SHA224_DIGEST_SIZE, .block_size = SHA224_BLOCK_SIZE }, }; #define NUM_HASH_TMPLS ARRAY_SIZE(hash_tmpls) -struct n2_ahash_alg { - struct list_head entry; - struct ahash_alg alg; -}; static LIST_HEAD(ahash_algs); static int algs_registered; @@ -1297,12 +1273,18 @@ static int __devinit __n2_register_one_ahash(const struct n2_hash_tmpl *tmpl) if (!p) return -ENOMEM; + p->hash_zero = tmpl->hash_zero; + p->hash_init = tmpl->hash_init; + p->auth_type = tmpl->auth_type; + p->hw_op_hashsz = tmpl->hw_op_hashsz; + p->digest_size = tmpl->digest_size; + ahash = &p->alg; ahash->init = n2_hash_async_init; ahash->update = n2_hash_async_update; ahash->final = n2_hash_async_final; ahash->finup = n2_hash_async_finup; - ahash->digest = tmpl->digest; + ahash->digest = n2_hash_async_digest; halg = &ahash->halg; halg->digestsize = tmpl->digest_size; -- cgit v1.2.3 From dc4ccfd15d4fc7a91ddf222bc5eed5cc4bcf10e6 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sat, 22 May 2010 22:53:09 -0700 Subject: n2_crypto: Add HMAC support. One note is that, unlike with non-HMAC hashes, we can't support hmac(sha224) using the HMAC_SHA256 opcode. Signed-off-by: David S. Miller --- drivers/crypto/n2_core.c | 210 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 206 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c index d01a2afda6e9..b99c38f23d61 100644 --- a/drivers/crypto/n2_core.c +++ b/drivers/crypto/n2_core.c @@ -246,6 +246,7 @@ struct n2_ahash_alg { u8 hw_op_hashsz; u8 digest_size; u8 auth_type; + u8 hmac_type; struct ahash_alg alg; }; @@ -259,10 +260,36 @@ static inline struct n2_ahash_alg *n2_ahash_alg(struct crypto_tfm *tfm) return container_of(ahash_alg, struct n2_ahash_alg, alg); } +struct n2_hmac_alg { + const char *child_alg; + struct n2_ahash_alg derived; +}; + +static inline struct n2_hmac_alg *n2_hmac_alg(struct crypto_tfm *tfm) +{ + struct crypto_alg *alg = tfm->__crt_alg; + struct ahash_alg *ahash_alg; + + ahash_alg = container_of(alg, struct ahash_alg, halg.base); + + return container_of(ahash_alg, struct n2_hmac_alg, derived.alg); +} + struct n2_hash_ctx { struct crypto_ahash *fallback_tfm; }; +#define N2_HASH_KEY_MAX 32 /* HW limit for all HMAC requests */ + +struct n2_hmac_ctx { + struct n2_hash_ctx base; + + struct crypto_shash *child_shash; + + int hash_key_len; + unsigned char hash_key[N2_HASH_KEY_MAX]; +}; + struct n2_hash_req_ctx { union { struct md5_state md5; @@ -362,6 +389,94 @@ static void n2_hash_cra_exit(struct crypto_tfm *tfm) crypto_free_ahash(ctx->fallback_tfm); } +static int n2_hmac_cra_init(struct crypto_tfm *tfm) +{ + const char *fallback_driver_name = tfm->__crt_alg->cra_name; + struct crypto_ahash *ahash = __crypto_ahash_cast(tfm); + struct n2_hmac_ctx *ctx = crypto_ahash_ctx(ahash); + struct n2_hmac_alg *n2alg = n2_hmac_alg(tfm); + struct crypto_ahash *fallback_tfm; + struct crypto_shash *child_shash; + int err; + + fallback_tfm = crypto_alloc_ahash(fallback_driver_name, 0, + CRYPTO_ALG_NEED_FALLBACK); + if (IS_ERR(fallback_tfm)) { + pr_warning("Fallback driver '%s' could not be loaded!\n", + fallback_driver_name); + err = PTR_ERR(fallback_tfm); + goto out; + } + + child_shash = crypto_alloc_shash(n2alg->child_alg, 0, 0); + if (IS_ERR(child_shash)) { + pr_warning("Child shash '%s' could not be loaded!\n", + n2alg->child_alg); + err = PTR_ERR(child_shash); + goto out_free_fallback; + } + + crypto_ahash_set_reqsize(ahash, (sizeof(struct n2_hash_req_ctx) + + crypto_ahash_reqsize(fallback_tfm))); + + ctx->child_shash = child_shash; + ctx->base.fallback_tfm = fallback_tfm; + return 0; + +out_free_fallback: + crypto_free_ahash(fallback_tfm); + +out: + return err; +} + +static void n2_hmac_cra_exit(struct crypto_tfm *tfm) +{ + struct crypto_ahash *ahash = __crypto_ahash_cast(tfm); + struct n2_hmac_ctx *ctx = crypto_ahash_ctx(ahash); + + crypto_free_ahash(ctx->base.fallback_tfm); + crypto_free_shash(ctx->child_shash); +} + +static int n2_hmac_async_setkey(struct crypto_ahash *tfm, const u8 *key, + unsigned int keylen) +{ + struct n2_hmac_ctx *ctx = crypto_ahash_ctx(tfm); + struct crypto_shash *child_shash = ctx->child_shash; + struct crypto_ahash *fallback_tfm; + struct { + struct shash_desc shash; + char ctx[crypto_shash_descsize(child_shash)]; + } desc; + int err, bs, ds; + + fallback_tfm = ctx->base.fallback_tfm; + err = crypto_ahash_setkey(fallback_tfm, key, keylen); + if (err) + return err; + + desc.shash.tfm = child_shash; + desc.shash.flags = crypto_ahash_get_flags(tfm) & + CRYPTO_TFM_REQ_MAY_SLEEP; + + bs = crypto_shash_blocksize(child_shash); + ds = crypto_shash_digestsize(child_shash); + BUG_ON(ds > N2_HASH_KEY_MAX); + if (keylen > bs) { + err = crypto_shash_digest(&desc.shash, key, keylen, + ctx->hash_key); + if (err) + return err; + keylen = ds; + } else if (keylen <= N2_HASH_KEY_MAX) + memcpy(ctx->hash_key, key, keylen); + + ctx->hash_key_len = keylen; + + return err; +} + static unsigned long wait_for_tail(struct spu_queue *qp) { unsigned long head, hv_ret; @@ -393,7 +508,8 @@ static unsigned long submit_and_wait_for_tail(struct spu_queue *qp, static int n2_do_async_digest(struct ahash_request *req, unsigned int auth_type, unsigned int digest_size, - unsigned int result_size, void *hash_loc) + unsigned int result_size, void *hash_loc, + unsigned long auth_key, unsigned int auth_key_len) { struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct cwq_initial_entry *ent; @@ -434,13 +550,13 @@ static int n2_do_async_digest(struct ahash_request *req, */ ent = qp->q + qp->tail; - ent->control = control_word_base(nbytes, 0, 0, + ent->control = control_word_base(nbytes, auth_key_len, 0, auth_type, digest_size, false, true, false, false, OPCODE_INPLACE_BIT | OPCODE_AUTH_MAC); ent->src_addr = __pa(walk.data); - ent->auth_key_addr = 0UL; + ent->auth_key_addr = auth_key; ent->auth_iv_addr = __pa(hash_loc); ent->final_auth_state_addr = 0UL; ent->enc_key_addr = 0UL; @@ -494,7 +610,40 @@ static int n2_hash_async_digest(struct ahash_request *req) return n2_do_async_digest(req, n2alg->auth_type, n2alg->hw_op_hashsz, ds, - &rctx->u); + &rctx->u, 0UL, 0); +} + +static int n2_hmac_async_digest(struct ahash_request *req) +{ + struct n2_hmac_alg *n2alg = n2_hmac_alg(req->base.tfm); + struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + struct n2_hmac_ctx *ctx = crypto_ahash_ctx(tfm); + int ds; + + ds = n2alg->derived.digest_size; + if (unlikely(req->nbytes == 0) || + unlikely(ctx->hash_key_len > N2_HASH_KEY_MAX)) { + struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); + struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); + + ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); + rctx->fallback_req.base.flags = + req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; + rctx->fallback_req.nbytes = req->nbytes; + rctx->fallback_req.src = req->src; + rctx->fallback_req.result = req->result; + + return crypto_ahash_digest(&rctx->fallback_req); + } + memcpy(&rctx->u, n2alg->derived.hash_init, + n2alg->derived.hw_op_hashsz); + + return n2_do_async_digest(req, n2alg->derived.hmac_type, + n2alg->derived.hw_op_hashsz, ds, + &rctx->u, + __pa(&ctx->hash_key), + ctx->hash_key_len); } struct n2_cipher_context { @@ -1127,6 +1276,7 @@ struct n2_hash_tmpl { u8 digest_size; u8 block_size; u8 auth_type; + u8 hmac_type; }; static const char md5_zero[MD5_DIGEST_SIZE] = { @@ -1173,6 +1323,7 @@ static const struct n2_hash_tmpl hash_tmpls[] = { .hash_zero = md5_zero, .hash_init = md5_init, .auth_type = AUTH_TYPE_MD5, + .hmac_type = AUTH_TYPE_HMAC_MD5, .hw_op_hashsz = MD5_DIGEST_SIZE, .digest_size = MD5_DIGEST_SIZE, .block_size = MD5_HMAC_BLOCK_SIZE }, @@ -1180,6 +1331,7 @@ static const struct n2_hash_tmpl hash_tmpls[] = { .hash_zero = sha1_zero, .hash_init = sha1_init, .auth_type = AUTH_TYPE_SHA1, + .hmac_type = AUTH_TYPE_HMAC_SHA1, .hw_op_hashsz = SHA1_DIGEST_SIZE, .digest_size = SHA1_DIGEST_SIZE, .block_size = SHA1_BLOCK_SIZE }, @@ -1187,6 +1339,7 @@ static const struct n2_hash_tmpl hash_tmpls[] = { .hash_zero = sha256_zero, .hash_init = sha256_init, .auth_type = AUTH_TYPE_SHA256, + .hmac_type = AUTH_TYPE_HMAC_SHA256, .hw_op_hashsz = SHA256_DIGEST_SIZE, .digest_size = SHA256_DIGEST_SIZE, .block_size = SHA256_BLOCK_SIZE }, @@ -1194,6 +1347,7 @@ static const struct n2_hash_tmpl hash_tmpls[] = { .hash_zero = sha224_zero, .hash_init = sha224_init, .auth_type = AUTH_TYPE_SHA256, + .hmac_type = AUTH_TYPE_RESERVED, .hw_op_hashsz = SHA256_DIGEST_SIZE, .digest_size = SHA224_DIGEST_SIZE, .block_size = SHA224_BLOCK_SIZE }, @@ -1201,6 +1355,7 @@ static const struct n2_hash_tmpl hash_tmpls[] = { #define NUM_HASH_TMPLS ARRAY_SIZE(hash_tmpls) static LIST_HEAD(ahash_algs); +static LIST_HEAD(hmac_algs); static int algs_registered; @@ -1208,12 +1363,18 @@ static void __n2_unregister_algs(void) { struct n2_cipher_alg *cipher, *cipher_tmp; struct n2_ahash_alg *alg, *alg_tmp; + struct n2_hmac_alg *hmac, *hmac_tmp; list_for_each_entry_safe(cipher, cipher_tmp, &cipher_algs, entry) { crypto_unregister_alg(&cipher->alg); list_del(&cipher->entry); kfree(cipher); } + list_for_each_entry_safe(hmac, hmac_tmp, &hmac_algs, derived.entry) { + crypto_unregister_ahash(&hmac->derived.alg); + list_del(&hmac->derived.entry); + kfree(hmac); + } list_for_each_entry_safe(alg, alg_tmp, &ahash_algs, entry) { crypto_unregister_ahash(&alg->alg); list_del(&alg->entry); @@ -1262,6 +1423,44 @@ static int __devinit __n2_register_one_cipher(const struct n2_cipher_tmpl *tmpl) return err; } +static int __devinit __n2_register_one_hmac(struct n2_ahash_alg *n2ahash) +{ + struct n2_hmac_alg *p = kzalloc(sizeof(*p), GFP_KERNEL); + struct ahash_alg *ahash; + struct crypto_alg *base; + int err; + + if (!p) + return -ENOMEM; + + p->child_alg = n2ahash->alg.halg.base.cra_name; + memcpy(&p->derived, n2ahash, sizeof(struct n2_ahash_alg)); + INIT_LIST_HEAD(&p->derived.entry); + + ahash = &p->derived.alg; + ahash->digest = n2_hmac_async_digest; + ahash->setkey = n2_hmac_async_setkey; + + base = &ahash->halg.base; + snprintf(base->cra_name, CRYPTO_MAX_ALG_NAME, "hmac(%s)", p->child_alg); + snprintf(base->cra_driver_name, CRYPTO_MAX_ALG_NAME, "hmac-%s-n2", p->child_alg); + + base->cra_ctxsize = sizeof(struct n2_hmac_ctx); + base->cra_init = n2_hmac_cra_init; + base->cra_exit = n2_hmac_cra_exit; + + list_add(&p->derived.entry, &hmac_algs); + err = crypto_register_ahash(ahash); + if (err) { + pr_err("%s alg registration failed\n", base->cra_name); + list_del(&p->derived.entry); + kfree(p); + } else { + pr_info("%s alg registered\n", base->cra_name); + } + return err; +} + static int __devinit __n2_register_one_ahash(const struct n2_hash_tmpl *tmpl) { struct n2_ahash_alg *p = kzalloc(sizeof(*p), GFP_KERNEL); @@ -1276,6 +1475,7 @@ static int __devinit __n2_register_one_ahash(const struct n2_hash_tmpl *tmpl) p->hash_zero = tmpl->hash_zero; p->hash_init = tmpl->hash_init; p->auth_type = tmpl->auth_type; + p->hmac_type = tmpl->hmac_type; p->hw_op_hashsz = tmpl->hw_op_hashsz; p->digest_size = tmpl->digest_size; @@ -1309,6 +1509,8 @@ static int __devinit __n2_register_one_ahash(const struct n2_hash_tmpl *tmpl) } else { pr_info("%s alg registered\n", base->cra_name); } + if (!err && p->hmac_type != AUTH_TYPE_RESERVED) + err = __n2_register_one_hmac(p); return err; } -- cgit v1.2.3 From 0efbaabd1ec91476c020e96240d6ab858e9a4871 Mon Sep 17 00:00:00 2001 From: Huang Weiyi Date: Wed, 26 May 2010 10:37:52 +1000 Subject: crypto: omap - remove unused #include Remove unused #include ('s) in drivers/crypto/omap-sham.c Signed-off-by: Huang Weiyi Signed-off-by: Herbert Xu --- drivers/crypto/omap-sham.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index 8b034337793f..7d1485676886 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -15,7 +15,6 @@ #define pr_fmt(fmt) "%s: " fmt, __func__ -#include #include #include #include -- cgit v1.2.3 From 7cc2835083aedfde42de02301005a5555e00c4b1 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 26 May 2010 10:45:22 +1000 Subject: crypto: mv_cesa - fixup error handling in mv_probe() The error handling in mv_probe() was a bit messed up. There were some gotos to the wrong labels so it ended up releasing stuff that that hadn't been aquired and not releasing stuff that was meant to be released. I shuffled it around a bit to fix it and make it clearer. Signed-off-by: Dan Carpenter Signed-off-by: Herbert Xu --- drivers/crypto/mv_cesa.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c index e095422b58dd..7d279e578df5 100644 --- a/drivers/crypto/mv_cesa.c +++ b/drivers/crypto/mv_cesa.c @@ -1055,20 +1055,20 @@ static int mv_probe(struct platform_device *pdev) cp->queue_th = kthread_run(queue_manag, cp, "mv_crypto"); if (IS_ERR(cp->queue_th)) { ret = PTR_ERR(cp->queue_th); - goto err_thread; + goto err_unmap_sram; } ret = request_irq(irq, crypto_int, IRQF_DISABLED, dev_name(&pdev->dev), cp); if (ret) - goto err_unmap_sram; + goto err_thread; writel(SEC_INT_ACCEL0_DONE, cpg->reg + SEC_ACCEL_INT_MASK); writel(SEC_CFG_STOP_DIG_ERR, cpg->reg + SEC_ACCEL_CFG); ret = crypto_register_alg(&mv_aes_alg_ecb); if (ret) - goto err_reg; + goto err_irq; ret = crypto_register_alg(&mv_aes_alg_cbc); if (ret) @@ -1091,9 +1091,9 @@ static int mv_probe(struct platform_device *pdev) return 0; err_unreg_ecb: crypto_unregister_alg(&mv_aes_alg_ecb); -err_thread: +err_irq: free_irq(irq, cp); -err_reg: +err_thread: kthread_stop(cp->queue_th); err_unmap_sram: iounmap(cp->sram); -- cgit v1.2.3 From 7c1f6afcf98fe95fb3f2b70ce01cf66f6db53b5e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 25 May 2010 23:51:17 -0700 Subject: sunserial: Don't call add_preferred_console() when console= is specified. Reported-by: Frans Pop Signed-off-by: David S. Miller --- drivers/serial/suncore.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/serial/suncore.c b/drivers/serial/suncore.c index ed7d958b0a01..544f2e25d0e5 100644 --- a/drivers/serial/suncore.c +++ b/drivers/serial/suncore.c @@ -71,7 +71,9 @@ int sunserial_console_match(struct console *con, struct device_node *dp, con->index = line; drv->cons = con; - add_preferred_console(con->name, line, NULL); + + if (!console_set_on_cmdline) + add_preferred_console(con->name, line, NULL); return 1; } -- cgit v1.2.3 From 79a78dd6266a4f3e31c800e941ec62e250770a7d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 17 May 2010 09:23:54 +0100 Subject: drm/i915: Fail to load driver if KMS request without GEM The i915's implementation of KMS requires GEM in order to manage the memory and execution domains of the framebuffer and associated resources. By the point at which we detect broken a BIOS and need to disable GEM, we have already registered ourselves as a KMS driver with several subsystems. Rather than introducing a fragile unwind and attempt to continue with UMS, spit out an error and unload the driver. References: [Bug 15754] IP: [] drm_mm_search_free+0x49/0x90 [drm] BUG: unable to handle kernel NULL pointer dereference at (null) https://bugzilla.kernel.org/show_bug.cgi?id=15754 [drm:i915_driver_load] *ERROR* Detected broken video BIOS with 262140/262144kB of video memory stolen. [drm:i915_driver_load] *ERROR* Disabling GEM. (try reducing stolen memory or updating the BIOS to fix). i915 0000:00:02.0: irq 30 for MSI/MSI-X [drm] set up 255M of stolen space BUG: unable to handle kernel NULL pointer dereference at (null) IP: [] drm_mm_search_free+0x49/0x90 [drm] PGD 69719067 PUD 69dda067 PMD 0 Oops: 0000 [#1] PREEMPT SMP last sysfs file: /sys/module/snd_seq_oss/initstate CPU 1 Pid: 867, comm: modprobe Not tainted 2.6.33-ARCH #1 G43Twins-FullHD/To Be Filled By O.E.M. RIP: 0010:[] [] drm_mm_search_free+0x49/0x90 [drm] RSP: 0018:ffff8800699f3af8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffffffffffffffff RCX: 0000000000000000 RDX: 0000000000001000 RSI: 0000000000001000 RDI: ffff8800693d0f78 RBP: ffff8800699f3b18 R08: 0000000000001000 R09: 0000000000000000 R10: 2222222222222222 R11: 0000000000000000 R12: ffff880068de70c0 R13: 0000000000001000 R14: 0000000000000000 R15: ffff8800689cb000 FS: 00007fa93f4e5700(0000) GS:ffff880001880000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000000 CR3: 00000000695a0000 CR4: 00000000000406e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process modprobe (pid: 867, threadinfo ffff8800699f2000, task ffff8800694f4740) Stack: ffff880068de73c0 ffff880068de70c0 ffff8800689cb000 0000000000001000 <0> ffff8800699f3b68 ffffffffa0299f63 ffff8800693d0f78 0000120068de70c0 <0> ffff8800689cb000 ffff880068de73c0 ffff880068de70c0 ffff8800689cb000 Call Trace: [] i915_gem_object_bind_to_gtt+0x83/0x360 [i915] [] i915_gem_object_pin+0xa5/0xb0 [i915] [] i915_gem_init_ringbuffer+0xd5/0x510 [i915] [] i915_driver_load+0x4ce/0xd00 [i915] [] ? drm_sysfs_device_add+0x87/0xb0 [drm] [] ? drm_get_minor+0x1d3/0x330 [drm] [] drm_get_dev+0x326/0x580 [drm] [] i915_pci_probe+0x10/0xd0 [i915] [] local_pci_probe+0x12/0x20 [] pci_device_probe+0x80/0xb0 [] ? driver_sysfs_add+0x5a/0x90 [] driver_probe_device+0x93/0x1a0 [] __driver_attach+0x93/0xa0 [] ? __driver_attach+0x0/0xa0 [] bus_for_each_dev+0x68/0x90 [] driver_attach+0x19/0x20 [] bus_add_driver+0xcd/0x2d0 [] driver_register+0x78/0x140 [] __pci_register_driver+0x51/0xd0 [] ? i915_init+0x0/0x52 [i915] [] drm_init+0x111/0x120 [drm] [] ? register_shrinker+0x4d/0x60 [] ? i915_init+0x0/0x52 [i915] [] i915_init+0x50/0x52 [i915] [] do_one_initcall+0x37/0x1a0 [] sys_init_module+0xd7/0x250 [] system_call_fastpath+0x16/0x1b Code: eb 29 49 8b 41 28 31 d2 49 f7 f5 85 d2 74 39 44 89 c0 29 d0 48 89 c2 48 01 f2 49 39 d2 73 29 0f 1f 00 49 89 da 4c 89 d3 4d 89 d9 <4d> 8b 19 49 39 f9 41 0f 18 0b 74 2b 4d 8b 51 30 4d 89 cc 49 39 RIP [] drm_mm_search_free+0x49/0x90 [drm] RSP CR2: 0000000000000000 Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_dma.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 2a6b5de5ae5d..22d7497e6fa6 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1672,6 +1672,13 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) dev_priv->has_gem = 0; } + if (dev_priv->has_gem == 0 && + drm_core_check_feature(dev, DRIVER_MODESET)) { + DRM_ERROR("kernel modesetting requires GEM, disabling driver.\n"); + ret = -ENODEV; + goto out_iomapfree; + } + dev->driver->get_vblank_counter = i915_get_vblank_counter; dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ if (IS_G4X(dev) || IS_IRONLAKE(dev) || IS_GEN6(dev)) { -- cgit v1.2.3 From 62fdfeaf8b1f487060b6e160e7b5cd90287607c9 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 21 May 2010 13:26:39 -0700 Subject: drm/i915: Move ringbuffer-related code to intel_ringbuffer.c. This is preparation for supporting multiple ringbuffers on Ironlake. The non-copy-and-paste changes are: - de-staticing functions - I915_GEM_GPU_DOMAINS moving to i915_drv.h to be used by both files. - i915_gem_add_request had only half its implementation copy-and-pasted out of the middle of it. --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/i915_dma.c | 77 ----- drivers/gpu/drm/i915/i915_drv.h | 18 + drivers/gpu/drm/i915/i915_gem.c | 427 +----------------------- drivers/gpu/drm/i915/i915_irq.c | 35 +- drivers/gpu/drm/i915/intel_ringbuffer.c | 568 ++++++++++++++++++++++++++++++++ 6 files changed, 592 insertions(+), 534 deletions(-) create mode 100644 drivers/gpu/drm/i915/intel_ringbuffer.c (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 95639017bdbe..da78f2c0d909 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -22,6 +22,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \ intel_fb.o \ intel_tv.o \ intel_dvo.o \ + intel_ringbuffer.o \ intel_overlay.o \ dvo_ch7xxx.o \ dvo_ch7017.o \ diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 22d7497e6fa6..a657e3315950 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -40,83 +40,6 @@ #include #include -/* Really want an OS-independent resettable timer. Would like to have - * this loop run for (eg) 3 sec, but have the timer reset every time - * the head pointer changes, so that EBUSY only happens if the ring - * actually stalls for (eg) 3 seconds. - */ -int i915_wait_ring(struct drm_device * dev, int n, const char *caller) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_ring_buffer_t *ring = &(dev_priv->ring); - u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD; - u32 last_acthd = I915_READ(acthd_reg); - u32 acthd; - u32 last_head = I915_READ(PRB0_HEAD) & HEAD_ADDR; - int i; - - trace_i915_ring_wait_begin (dev); - - for (i = 0; i < 100000; i++) { - ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; - acthd = I915_READ(acthd_reg); - ring->space = ring->head - (ring->tail + 8); - if (ring->space < 0) - ring->space += ring->Size; - if (ring->space >= n) { - trace_i915_ring_wait_end (dev); - return 0; - } - - if (dev->primary->master) { - struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; - if (master_priv->sarea_priv) - master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; - } - - - if (ring->head != last_head) - i = 0; - if (acthd != last_acthd) - i = 0; - - last_head = ring->head; - last_acthd = acthd; - msleep_interruptible(10); - - } - - trace_i915_ring_wait_end (dev); - return -EBUSY; -} - -/* As a ringbuffer is only allowed to wrap between instructions, fill - * the tail with NOOPs. - */ -int i915_wrap_ring(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - volatile unsigned int *virt; - int rem; - - rem = dev_priv->ring.Size - dev_priv->ring.tail; - if (dev_priv->ring.space < rem) { - int ret = i915_wait_ring(dev, rem, __func__); - if (ret) - return ret; - } - dev_priv->ring.space -= rem; - - virt = (unsigned int *) - (dev_priv->ring.virtual_start + dev_priv->ring.tail); - rem /= 4; - while (rem--) - *virt++ = MI_NOOP; - - dev_priv->ring.tail = 0; - - return 0; -} /** * Sets up the hardware status page for devices that need a physical address diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 7f797ef1ab39..114653aa9ae2 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -31,6 +31,7 @@ #define _I915_DRV_H_ #include "i915_reg.h" +#include "i915_drm.h" #include "intel_bios.h" #include @@ -55,6 +56,8 @@ enum plane { #define I915_NUM_PIPE 2 +#define I915_GEM_GPU_DOMAINS (~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT)) + /* Interface history: * * 1.1: Original. @@ -849,6 +852,9 @@ extern u32 gm45_get_vblank_counter(struct drm_device *dev, int crtc); extern int i915_vblank_swap(struct drm_device *dev, void *data, struct drm_file *file_priv); extern void i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask); +extern void i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask); +void ironlake_enable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask); +void ironlake_disable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask); void i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask); @@ -956,6 +962,8 @@ void i915_gem_object_flush_write_domain(struct drm_gem_object *obj); void i915_gem_shrinker_init(void); void i915_gem_shrinker_exit(void); +int i915_gem_init_pipe_control(struct drm_device *dev); +void i915_gem_cleanup_pipe_control(struct drm_device *dev); /* i915_gem_tiling.c */ void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); @@ -1006,6 +1014,16 @@ static inline void ironlake_opregion_gse_intr(struct drm_device *dev) { return; static inline void opregion_enable_asle(struct drm_device *dev) { return; } #endif +/* intel_ringbuffer.c */ +extern void i915_gem_flush(struct drm_device *dev, + uint32_t invalidate_domains, + uint32_t flush_domains); +extern int i915_dispatch_gem_execbuffer(struct drm_device *dev, + struct drm_i915_gem_execbuffer2 *exec, + struct drm_clip_rect *cliprects, + uint64_t exec_offset); +extern uint32_t i915_ring_add_request(struct drm_device *dev); + /* modesetting */ extern void intel_modeset_init(struct drm_device *dev); extern void intel_modeset_cleanup(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 112699f71fa4..4f2f5f8cdca2 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -35,8 +35,6 @@ #include #include -#define I915_GEM_GPU_DOMAINS (~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT)) - static void i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj); static void i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj); static void i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj); @@ -1592,22 +1590,6 @@ i915_gem_process_flushing_list(struct drm_device *dev, } } } - -#define PIPE_CONTROL_FLUSH(addr) \ - OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | \ - PIPE_CONTROL_DEPTH_STALL); \ - OUT_RING(addr | PIPE_CONTROL_GLOBAL_GTT); \ - OUT_RING(0); \ - OUT_RING(0); \ - -/** - * Creates a new sequence number, emitting a write of it to the status page - * plus an interrupt, which will trigger i915_user_interrupt_handler. - * - * Must be called with struct_lock held. - * - * Returned sequence numbers are nonzero on success. - */ uint32_t i915_add_request(struct drm_device *dev, struct drm_file *file_priv, uint32_t flush_domains) @@ -1617,7 +1599,6 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv, struct drm_i915_gem_request *request; uint32_t seqno; int was_empty; - RING_LOCALS; if (file_priv != NULL) i915_file_priv = file_priv->driver_priv; @@ -1626,55 +1607,7 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv, if (request == NULL) return 0; - /* Grab the seqno we're going to make this request be, and bump the - * next (skipping 0 so it can be the reserved no-seqno value). - */ - seqno = dev_priv->mm.next_gem_seqno; - dev_priv->mm.next_gem_seqno++; - if (dev_priv->mm.next_gem_seqno == 0) - dev_priv->mm.next_gem_seqno++; - - if (HAS_PIPE_CONTROL(dev)) { - u32 scratch_addr = dev_priv->seqno_gfx_addr + 128; - - /* - * Workaround qword write incoherence by flushing the - * PIPE_NOTIFY buffers out to memory before requesting - * an interrupt. - */ - BEGIN_LP_RING(32); - OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | - PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH); - OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); - OUT_RING(seqno); - OUT_RING(0); - PIPE_CONTROL_FLUSH(scratch_addr); - scratch_addr += 128; /* write to separate cachelines */ - PIPE_CONTROL_FLUSH(scratch_addr); - scratch_addr += 128; - PIPE_CONTROL_FLUSH(scratch_addr); - scratch_addr += 128; - PIPE_CONTROL_FLUSH(scratch_addr); - scratch_addr += 128; - PIPE_CONTROL_FLUSH(scratch_addr); - scratch_addr += 128; - PIPE_CONTROL_FLUSH(scratch_addr); - OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | - PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH | - PIPE_CONTROL_NOTIFY); - OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); - OUT_RING(seqno); - OUT_RING(0); - ADVANCE_LP_RING(); - } else { - BEGIN_LP_RING(4); - OUT_RING(MI_STORE_DWORD_INDEX); - OUT_RING(I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); - OUT_RING(seqno); - - OUT_RING(MI_USER_INTERRUPT); - ADVANCE_LP_RING(); - } + seqno = i915_ring_add_request(dev); DRM_DEBUG_DRIVER("%d\n", seqno); @@ -1933,78 +1866,6 @@ i915_wait_request(struct drm_device *dev, uint32_t seqno) return i915_do_wait_request(dev, seqno, 1); } -static void -i915_gem_flush(struct drm_device *dev, - uint32_t invalidate_domains, - uint32_t flush_domains) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - uint32_t cmd; - RING_LOCALS; - -#if WATCH_EXEC - DRM_INFO("%s: invalidate %08x flush %08x\n", __func__, - invalidate_domains, flush_domains); -#endif - trace_i915_gem_request_flush(dev, dev_priv->mm.next_gem_seqno, - invalidate_domains, flush_domains); - - if (flush_domains & I915_GEM_DOMAIN_CPU) - drm_agp_chipset_flush(dev); - - if ((invalidate_domains | flush_domains) & I915_GEM_GPU_DOMAINS) { - /* - * read/write caches: - * - * I915_GEM_DOMAIN_RENDER is always invalidated, but is - * only flushed if MI_NO_WRITE_FLUSH is unset. On 965, it is - * also flushed at 2d versus 3d pipeline switches. - * - * read-only caches: - * - * I915_GEM_DOMAIN_SAMPLER is flushed on pre-965 if - * MI_READ_FLUSH is set, and is always flushed on 965. - * - * I915_GEM_DOMAIN_COMMAND may not exist? - * - * I915_GEM_DOMAIN_INSTRUCTION, which exists on 965, is - * invalidated when MI_EXE_FLUSH is set. - * - * I915_GEM_DOMAIN_VERTEX, which exists on 965, is - * invalidated with every MI_FLUSH. - * - * TLBs: - * - * On 965, TLBs associated with I915_GEM_DOMAIN_COMMAND - * and I915_GEM_DOMAIN_CPU in are invalidated at PTE write and - * I915_GEM_DOMAIN_RENDER and I915_GEM_DOMAIN_SAMPLER - * are flushed at any MI_FLUSH. - */ - - cmd = MI_FLUSH | MI_NO_WRITE_FLUSH; - if ((invalidate_domains|flush_domains) & - I915_GEM_DOMAIN_RENDER) - cmd &= ~MI_NO_WRITE_FLUSH; - if (!IS_I965G(dev)) { - /* - * On the 965, the sampler cache always gets flushed - * and this bit is reserved. - */ - if (invalidate_domains & I915_GEM_DOMAIN_SAMPLER) - cmd |= MI_READ_FLUSH; - } - if (invalidate_domains & I915_GEM_DOMAIN_INSTRUCTION) - cmd |= MI_EXE_FLUSH; - -#if WATCH_EXEC - DRM_INFO("%s: queue flush %08x to ring\n", __func__, cmd); -#endif - BEGIN_LP_RING(2); - OUT_RING(cmd); - OUT_RING(MI_NOOP); - ADVANCE_LP_RING(); - } -} /** * Ensures that all rendering to the object has completed and the object is @@ -3545,62 +3406,6 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, return 0; } -/** Dispatch a batchbuffer to the ring - */ -static int -i915_dispatch_gem_execbuffer(struct drm_device *dev, - struct drm_i915_gem_execbuffer2 *exec, - struct drm_clip_rect *cliprects, - uint64_t exec_offset) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - int nbox = exec->num_cliprects; - int i = 0, count; - uint32_t exec_start, exec_len; - RING_LOCALS; - - exec_start = (uint32_t) exec_offset + exec->batch_start_offset; - exec_len = (uint32_t) exec->batch_len; - - trace_i915_gem_request_submit(dev, dev_priv->mm.next_gem_seqno + 1); - - count = nbox ? nbox : 1; - - for (i = 0; i < count; i++) { - if (i < nbox) { - int ret = i915_emit_box(dev, cliprects, i, - exec->DR1, exec->DR4); - if (ret) - return ret; - } - - if (IS_I830(dev) || IS_845G(dev)) { - BEGIN_LP_RING(4); - OUT_RING(MI_BATCH_BUFFER); - OUT_RING(exec_start | MI_BATCH_NON_SECURE); - OUT_RING(exec_start + exec_len - 4); - OUT_RING(0); - ADVANCE_LP_RING(); - } else { - BEGIN_LP_RING(2); - if (IS_I965G(dev)) { - OUT_RING(MI_BATCH_BUFFER_START | - (2 << 6) | - MI_BATCH_NON_SECURE_I965); - OUT_RING(exec_start); - } else { - OUT_RING(MI_BATCH_BUFFER_START | - (2 << 6)); - OUT_RING(exec_start | MI_BATCH_NON_SECURE); - } - ADVANCE_LP_RING(); - } - } - - /* XXX breadcrumb */ - return 0; -} - /* Throttle our rendering by waiting until the ring has completed our requests * emitted over 20 msec ago. * @@ -4615,7 +4420,7 @@ i915_gem_idle(struct drm_device *dev) * 965+ support PIPE_CONTROL commands, which provide finer grained control * over cache flushing. */ -static int +int i915_gem_init_pipe_control(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -4654,73 +4459,7 @@ err: return ret; } -static int -i915_gem_init_hws(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_gem_object *obj; - struct drm_i915_gem_object *obj_priv; - int ret; - - /* If we need a physical address for the status page, it's already - * initialized at driver load time. - */ - if (!I915_NEED_GFX_HWS(dev)) - return 0; - - obj = i915_gem_alloc_object(dev, 4096); - if (obj == NULL) { - DRM_ERROR("Failed to allocate status page\n"); - ret = -ENOMEM; - goto err; - } - obj_priv = to_intel_bo(obj); - obj_priv->agp_type = AGP_USER_CACHED_MEMORY; - - ret = i915_gem_object_pin(obj, 4096); - if (ret != 0) { - drm_gem_object_unreference(obj); - goto err_unref; - } - - dev_priv->status_gfx_addr = obj_priv->gtt_offset; - - dev_priv->hw_status_page = kmap(obj_priv->pages[0]); - if (dev_priv->hw_status_page == NULL) { - DRM_ERROR("Failed to map status page.\n"); - memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); - ret = -EINVAL; - goto err_unpin; - } - - if (HAS_PIPE_CONTROL(dev)) { - ret = i915_gem_init_pipe_control(dev); - if (ret) - goto err_unpin; - } - - dev_priv->hws_obj = obj; - memset(dev_priv->hw_status_page, 0, PAGE_SIZE); - if (IS_GEN6(dev)) { - I915_WRITE(HWS_PGA_GEN6, dev_priv->status_gfx_addr); - I915_READ(HWS_PGA_GEN6); /* posting read */ - } else { - I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr); - I915_READ(HWS_PGA); /* posting read */ - } - DRM_DEBUG_DRIVER("hws offset: 0x%08x\n", dev_priv->status_gfx_addr); - - return 0; - -err_unpin: - i915_gem_object_unpin(obj); -err_unref: - drm_gem_object_unreference(obj); -err: - return 0; -} - -static void +void i915_gem_cleanup_pipe_control(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -4737,166 +4476,6 @@ i915_gem_cleanup_pipe_control(struct drm_device *dev) dev_priv->seqno_page = NULL; } -static void -i915_gem_cleanup_hws(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_gem_object *obj; - struct drm_i915_gem_object *obj_priv; - - if (dev_priv->hws_obj == NULL) - return; - - obj = dev_priv->hws_obj; - obj_priv = to_intel_bo(obj); - - kunmap(obj_priv->pages[0]); - i915_gem_object_unpin(obj); - drm_gem_object_unreference(obj); - dev_priv->hws_obj = NULL; - - memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); - dev_priv->hw_status_page = NULL; - - if (HAS_PIPE_CONTROL(dev)) - i915_gem_cleanup_pipe_control(dev); - - /* Write high address into HWS_PGA when disabling. */ - I915_WRITE(HWS_PGA, 0x1ffff000); -} - -int -i915_gem_init_ringbuffer(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_gem_object *obj; - struct drm_i915_gem_object *obj_priv; - drm_i915_ring_buffer_t *ring = &dev_priv->ring; - int ret; - u32 head; - - ret = i915_gem_init_hws(dev); - if (ret != 0) - return ret; - - obj = i915_gem_alloc_object(dev, 128 * 1024); - if (obj == NULL) { - DRM_ERROR("Failed to allocate ringbuffer\n"); - i915_gem_cleanup_hws(dev); - return -ENOMEM; - } - obj_priv = to_intel_bo(obj); - - ret = i915_gem_object_pin(obj, 4096); - if (ret != 0) { - drm_gem_object_unreference(obj); - i915_gem_cleanup_hws(dev); - return ret; - } - - /* Set up the kernel mapping for the ring. */ - ring->Size = obj->size; - - ring->map.offset = dev->agp->base + obj_priv->gtt_offset; - ring->map.size = obj->size; - ring->map.type = 0; - ring->map.flags = 0; - ring->map.mtrr = 0; - - drm_core_ioremap_wc(&ring->map, dev); - if (ring->map.handle == NULL) { - DRM_ERROR("Failed to map ringbuffer.\n"); - memset(&dev_priv->ring, 0, sizeof(dev_priv->ring)); - i915_gem_object_unpin(obj); - drm_gem_object_unreference(obj); - i915_gem_cleanup_hws(dev); - return -EINVAL; - } - ring->ring_obj = obj; - ring->virtual_start = ring->map.handle; - - /* Stop the ring if it's running. */ - I915_WRITE(PRB0_CTL, 0); - I915_WRITE(PRB0_TAIL, 0); - I915_WRITE(PRB0_HEAD, 0); - - /* Initialize the ring. */ - I915_WRITE(PRB0_START, obj_priv->gtt_offset); - head = I915_READ(PRB0_HEAD) & HEAD_ADDR; - - /* G45 ring initialization fails to reset head to zero */ - if (head != 0) { - DRM_ERROR("Ring head not reset to zero " - "ctl %08x head %08x tail %08x start %08x\n", - I915_READ(PRB0_CTL), - I915_READ(PRB0_HEAD), - I915_READ(PRB0_TAIL), - I915_READ(PRB0_START)); - I915_WRITE(PRB0_HEAD, 0); - - DRM_ERROR("Ring head forced to zero " - "ctl %08x head %08x tail %08x start %08x\n", - I915_READ(PRB0_CTL), - I915_READ(PRB0_HEAD), - I915_READ(PRB0_TAIL), - I915_READ(PRB0_START)); - } - - I915_WRITE(PRB0_CTL, - ((obj->size - 4096) & RING_NR_PAGES) | - RING_NO_REPORT | - RING_VALID); - - head = I915_READ(PRB0_HEAD) & HEAD_ADDR; - - /* If the head is still not zero, the ring is dead */ - if (head != 0) { - DRM_ERROR("Ring initialization failed " - "ctl %08x head %08x tail %08x start %08x\n", - I915_READ(PRB0_CTL), - I915_READ(PRB0_HEAD), - I915_READ(PRB0_TAIL), - I915_READ(PRB0_START)); - return -EIO; - } - - /* Update our cache of the ring state */ - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - i915_kernel_lost_context(dev); - else { - ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; - ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR; - ring->space = ring->head - (ring->tail + 8); - if (ring->space < 0) - ring->space += ring->Size; - } - - if (IS_I9XX(dev) && !IS_GEN3(dev)) { - I915_WRITE(MI_MODE, - (VS_TIMER_DISPATCH) << 16 | VS_TIMER_DISPATCH); - } - - return 0; -} - -void -i915_gem_cleanup_ringbuffer(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - - if (dev_priv->ring.ring_obj == NULL) - return; - - drm_core_ioremapfree(&dev_priv->ring.map, dev); - - i915_gem_object_unpin(dev_priv->ring.ring_obj); - drm_gem_object_unreference(dev_priv->ring.ring_obj); - dev_priv->ring.ring_obj = NULL; - memset(&dev_priv->ring, 0, sizeof(dev_priv->ring)); - - i915_gem_cleanup_hws(dev); -} - int i915_gem_entervt_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 8c3f0802686d..896184bfeb12 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -74,7 +74,7 @@ ironlake_enable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask) } } -static inline void +void ironlake_disable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask) { if ((dev_priv->gt_irq_mask_reg & mask) != mask) { @@ -115,7 +115,7 @@ i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask) } } -static inline void +void i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask) { if ((dev_priv->irq_mask_reg & mask) != mask) { @@ -1006,37 +1006,6 @@ static int i915_emit_irq(struct drm_device * dev) return dev_priv->counter; } -void i915_user_irq_get(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); - if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1)) { - if (HAS_PCH_SPLIT(dev)) - ironlake_enable_graphics_irq(dev_priv, GT_PIPE_NOTIFY); - else - i915_enable_irq(dev_priv, I915_USER_INTERRUPT); - } - spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); -} - -void i915_user_irq_put(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); - BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0); - if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { - if (HAS_PCH_SPLIT(dev)) - ironlake_disable_graphics_irq(dev_priv, GT_PIPE_NOTIFY); - else - i915_disable_irq(dev_priv, I915_USER_INTERRUPT); - } - spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); -} - void i915_trace_irq_get(struct drm_device *dev, u32 seqno) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c new file mode 100644 index 000000000000..13a796fafaee --- /dev/null +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -0,0 +1,568 @@ +/* + * Copyright © 2008-2010 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 (including the next + * paragraph) 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: + * Eric Anholt + * Zou Nan hai + * Xiang Hai hao + * + */ + +#include "drmP.h" +#include "drm.h" +#include "i915_drm.h" +#include "i915_drv.h" +#include "i915_trace.h" +#include "intel_drv.h" + +void +i915_gem_flush(struct drm_device *dev, + uint32_t invalidate_domains, + uint32_t flush_domains) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + uint32_t cmd; + RING_LOCALS; + +#if WATCH_EXEC + DRM_INFO("%s: invalidate %08x flush %08x\n", __func__, + invalidate_domains, flush_domains); +#endif + trace_i915_gem_request_flush(dev, dev_priv->mm.next_gem_seqno, + invalidate_domains, flush_domains); + + if (flush_domains & I915_GEM_DOMAIN_CPU) + drm_agp_chipset_flush(dev); + + if ((invalidate_domains | flush_domains) & I915_GEM_GPU_DOMAINS) { + /* + * read/write caches: + * + * I915_GEM_DOMAIN_RENDER is always invalidated, but is + * only flushed if MI_NO_WRITE_FLUSH is unset. On 965, it is + * also flushed at 2d versus 3d pipeline switches. + * + * read-only caches: + * + * I915_GEM_DOMAIN_SAMPLER is flushed on pre-965 if + * MI_READ_FLUSH is set, and is always flushed on 965. + * + * I915_GEM_DOMAIN_COMMAND may not exist? + * + * I915_GEM_DOMAIN_INSTRUCTION, which exists on 965, is + * invalidated when MI_EXE_FLUSH is set. + * + * I915_GEM_DOMAIN_VERTEX, which exists on 965, is + * invalidated with every MI_FLUSH. + * + * TLBs: + * + * On 965, TLBs associated with I915_GEM_DOMAIN_COMMAND + * and I915_GEM_DOMAIN_CPU in are invalidated at PTE write and + * I915_GEM_DOMAIN_RENDER and I915_GEM_DOMAIN_SAMPLER + * are flushed at any MI_FLUSH. + */ + + cmd = MI_FLUSH | MI_NO_WRITE_FLUSH; + if ((invalidate_domains|flush_domains) & + I915_GEM_DOMAIN_RENDER) + cmd &= ~MI_NO_WRITE_FLUSH; + if (!IS_I965G(dev)) { + /* + * On the 965, the sampler cache always gets flushed + * and this bit is reserved. + */ + if (invalidate_domains & I915_GEM_DOMAIN_SAMPLER) + cmd |= MI_READ_FLUSH; + } + if (invalidate_domains & I915_GEM_DOMAIN_INSTRUCTION) + cmd |= MI_EXE_FLUSH; + +#if WATCH_EXEC + DRM_INFO("%s: queue flush %08x to ring\n", __func__, cmd); +#endif + BEGIN_LP_RING(2); + OUT_RING(cmd); + OUT_RING(MI_NOOP); + ADVANCE_LP_RING(); + } + +} +#define PIPE_CONTROL_FLUSH(addr) \ + OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | \ + PIPE_CONTROL_DEPTH_STALL); \ + OUT_RING(addr | PIPE_CONTROL_GLOBAL_GTT); \ + OUT_RING(0); \ + OUT_RING(0); \ + +/** + * Creates a new sequence number, emitting a write of it to the status page + * plus an interrupt, which will trigger i915_user_interrupt_handler. + * + * Must be called with struct_lock held. + * + * Returned sequence numbers are nonzero on success. + */ +uint32_t +i915_ring_add_request(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + uint32_t seqno; + RING_LOCALS; + + /* Grab the seqno we're going to make this request be, and bump the + * next (skipping 0 so it can be the reserved no-seqno value). + */ + seqno = dev_priv->mm.next_gem_seqno; + dev_priv->mm.next_gem_seqno++; + if (dev_priv->mm.next_gem_seqno == 0) + dev_priv->mm.next_gem_seqno++; + + if (HAS_PIPE_CONTROL(dev)) { + u32 scratch_addr = dev_priv->seqno_gfx_addr + 128; + + /* + * Workaround qword write incoherence by flushing the + * PIPE_NOTIFY buffers out to memory before requesting + * an interrupt. + */ + BEGIN_LP_RING(32); + OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | + PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH); + OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); + OUT_RING(seqno); + OUT_RING(0); + PIPE_CONTROL_FLUSH(scratch_addr); + scratch_addr += 128; /* write to separate cachelines */ + PIPE_CONTROL_FLUSH(scratch_addr); + scratch_addr += 128; + PIPE_CONTROL_FLUSH(scratch_addr); + scratch_addr += 128; + PIPE_CONTROL_FLUSH(scratch_addr); + scratch_addr += 128; + PIPE_CONTROL_FLUSH(scratch_addr); + scratch_addr += 128; + PIPE_CONTROL_FLUSH(scratch_addr); + OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | + PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH | + PIPE_CONTROL_NOTIFY); + OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); + OUT_RING(seqno); + OUT_RING(0); + ADVANCE_LP_RING(); + } else { + BEGIN_LP_RING(4); + OUT_RING(MI_STORE_DWORD_INDEX); + OUT_RING(I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); + OUT_RING(seqno); + + OUT_RING(MI_USER_INTERRUPT); + ADVANCE_LP_RING(); + } + return seqno; +} + +void i915_user_irq_get(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); + if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1)) { + if (HAS_PCH_SPLIT(dev)) + ironlake_enable_graphics_irq(dev_priv, GT_PIPE_NOTIFY); + else + i915_enable_irq(dev_priv, I915_USER_INTERRUPT); + } + spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); +} + +void i915_user_irq_put(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); + BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0); + if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { + if (HAS_PCH_SPLIT(dev)) + ironlake_disable_graphics_irq(dev_priv, GT_PIPE_NOTIFY); + else + i915_disable_irq(dev_priv, I915_USER_INTERRUPT); + } + spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); +} + +/** Dispatch a batchbuffer to the ring + */ +int +i915_dispatch_gem_execbuffer(struct drm_device *dev, + struct drm_i915_gem_execbuffer2 *exec, + struct drm_clip_rect *cliprects, + uint64_t exec_offset) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + int nbox = exec->num_cliprects; + int i = 0, count; + uint32_t exec_start, exec_len; + RING_LOCALS; + + exec_start = (uint32_t) exec_offset + exec->batch_start_offset; + exec_len = (uint32_t) exec->batch_len; + + trace_i915_gem_request_submit(dev, dev_priv->mm.next_gem_seqno + 1); + + count = nbox ? nbox : 1; + + for (i = 0; i < count; i++) { + if (i < nbox) { + int ret = i915_emit_box(dev, cliprects, i, + exec->DR1, exec->DR4); + if (ret) + return ret; + } + + if (IS_I830(dev) || IS_845G(dev)) { + BEGIN_LP_RING(4); + OUT_RING(MI_BATCH_BUFFER); + OUT_RING(exec_start | MI_BATCH_NON_SECURE); + OUT_RING(exec_start + exec_len - 4); + OUT_RING(0); + ADVANCE_LP_RING(); + } else { + BEGIN_LP_RING(2); + if (IS_I965G(dev)) { + OUT_RING(MI_BATCH_BUFFER_START | + (2 << 6) | + MI_BATCH_NON_SECURE_I965); + OUT_RING(exec_start); + } else { + OUT_RING(MI_BATCH_BUFFER_START | + (2 << 6)); + OUT_RING(exec_start | MI_BATCH_NON_SECURE); + } + ADVANCE_LP_RING(); + } + } + + /* XXX breadcrumb */ + return 0; +} + +static void +i915_gem_cleanup_hws(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_gem_object *obj; + struct drm_i915_gem_object *obj_priv; + + if (dev_priv->hws_obj == NULL) + return; + + obj = dev_priv->hws_obj; + obj_priv = to_intel_bo(obj); + + kunmap(obj_priv->pages[0]); + i915_gem_object_unpin(obj); + drm_gem_object_unreference(obj); + dev_priv->hws_obj = NULL; + + memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); + dev_priv->hw_status_page = NULL; + + if (HAS_PIPE_CONTROL(dev)) + i915_gem_cleanup_pipe_control(dev); + + /* Write high address into HWS_PGA when disabling. */ + I915_WRITE(HWS_PGA, 0x1ffff000); +} + +static int +i915_gem_init_hws(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_gem_object *obj; + struct drm_i915_gem_object *obj_priv; + int ret; + + /* If we need a physical address for the status page, it's already + * initialized at driver load time. + */ + if (!I915_NEED_GFX_HWS(dev)) + return 0; + + obj = i915_gem_alloc_object(dev, 4096); + if (obj == NULL) { + DRM_ERROR("Failed to allocate status page\n"); + ret = -ENOMEM; + goto err; + } + obj_priv = to_intel_bo(obj); + obj_priv->agp_type = AGP_USER_CACHED_MEMORY; + + ret = i915_gem_object_pin(obj, 4096); + if (ret != 0) { + drm_gem_object_unreference(obj); + goto err_unref; + } + + dev_priv->status_gfx_addr = obj_priv->gtt_offset; + + dev_priv->hw_status_page = kmap(obj_priv->pages[0]); + if (dev_priv->hw_status_page == NULL) { + DRM_ERROR("Failed to map status page.\n"); + memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); + ret = -EINVAL; + goto err_unpin; + } + + if (HAS_PIPE_CONTROL(dev)) { + ret = i915_gem_init_pipe_control(dev); + if (ret) + goto err_unpin; + } + + dev_priv->hws_obj = obj; + memset(dev_priv->hw_status_page, 0, PAGE_SIZE); + if (IS_GEN6(dev)) { + I915_WRITE(HWS_PGA_GEN6, dev_priv->status_gfx_addr); + I915_READ(HWS_PGA_GEN6); /* posting read */ + } else { + I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr); + I915_READ(HWS_PGA); /* posting read */ + } + DRM_DEBUG_DRIVER("hws offset: 0x%08x\n", dev_priv->status_gfx_addr); + + return 0; + +err_unpin: + i915_gem_object_unpin(obj); +err_unref: + drm_gem_object_unreference(obj); +err: + return 0; +} + +int +i915_gem_init_ringbuffer(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_gem_object *obj; + struct drm_i915_gem_object *obj_priv; + drm_i915_ring_buffer_t *ring = &dev_priv->ring; + int ret; + u32 head; + + ret = i915_gem_init_hws(dev); + if (ret != 0) + return ret; + + obj = i915_gem_alloc_object(dev, 128 * 1024); + if (obj == NULL) { + DRM_ERROR("Failed to allocate ringbuffer\n"); + i915_gem_cleanup_hws(dev); + return -ENOMEM; + } + obj_priv = to_intel_bo(obj); + + ret = i915_gem_object_pin(obj, 4096); + if (ret != 0) { + drm_gem_object_unreference(obj); + i915_gem_cleanup_hws(dev); + return ret; + } + + /* Set up the kernel mapping for the ring. */ + ring->Size = obj->size; + + ring->map.offset = dev->agp->base + obj_priv->gtt_offset; + ring->map.size = obj->size; + ring->map.type = 0; + ring->map.flags = 0; + ring->map.mtrr = 0; + + drm_core_ioremap_wc(&ring->map, dev); + if (ring->map.handle == NULL) { + DRM_ERROR("Failed to map ringbuffer.\n"); + memset(&dev_priv->ring, 0, sizeof(dev_priv->ring)); + i915_gem_object_unpin(obj); + drm_gem_object_unreference(obj); + i915_gem_cleanup_hws(dev); + return -EINVAL; + } + ring->ring_obj = obj; + ring->virtual_start = ring->map.handle; + + /* Stop the ring if it's running. */ + I915_WRITE(PRB0_CTL, 0); + I915_WRITE(PRB0_TAIL, 0); + I915_WRITE(PRB0_HEAD, 0); + + /* Initialize the ring. */ + I915_WRITE(PRB0_START, obj_priv->gtt_offset); + head = I915_READ(PRB0_HEAD) & HEAD_ADDR; + + /* G45 ring initialization fails to reset head to zero */ + if (head != 0) { + DRM_ERROR("Ring head not reset to zero " + "ctl %08x head %08x tail %08x start %08x\n", + I915_READ(PRB0_CTL), + I915_READ(PRB0_HEAD), + I915_READ(PRB0_TAIL), + I915_READ(PRB0_START)); + I915_WRITE(PRB0_HEAD, 0); + + DRM_ERROR("Ring head forced to zero " + "ctl %08x head %08x tail %08x start %08x\n", + I915_READ(PRB0_CTL), + I915_READ(PRB0_HEAD), + I915_READ(PRB0_TAIL), + I915_READ(PRB0_START)); + } + + I915_WRITE(PRB0_CTL, + ((obj->size - 4096) & RING_NR_PAGES) | + RING_NO_REPORT | + RING_VALID); + + head = I915_READ(PRB0_HEAD) & HEAD_ADDR; + + /* If the head is still not zero, the ring is dead */ + if (head != 0) { + DRM_ERROR("Ring initialization failed " + "ctl %08x head %08x tail %08x start %08x\n", + I915_READ(PRB0_CTL), + I915_READ(PRB0_HEAD), + I915_READ(PRB0_TAIL), + I915_READ(PRB0_START)); + return -EIO; + } + + /* Update our cache of the ring state */ + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + i915_kernel_lost_context(dev); + else { + ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; + ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR; + ring->space = ring->head - (ring->tail + 8); + if (ring->space < 0) + ring->space += ring->Size; + } + + if (IS_I9XX(dev) && !IS_GEN3(dev)) { + I915_WRITE(MI_MODE, + (VS_TIMER_DISPATCH) << 16 | VS_TIMER_DISPATCH); + } + + return 0; +} + +void +i915_gem_cleanup_ringbuffer(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + + if (dev_priv->ring.ring_obj == NULL) + return; + + drm_core_ioremapfree(&dev_priv->ring.map, dev); + + i915_gem_object_unpin(dev_priv->ring.ring_obj); + drm_gem_object_unreference(dev_priv->ring.ring_obj); + dev_priv->ring.ring_obj = NULL; + memset(&dev_priv->ring, 0, sizeof(dev_priv->ring)); + + i915_gem_cleanup_hws(dev); +} + +/* As a ringbuffer is only allowed to wrap between instructions, fill + * the tail with NOOPs. + */ +int i915_wrap_ring(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + volatile unsigned int *virt; + int rem; + + rem = dev_priv->ring.Size - dev_priv->ring.tail; + if (dev_priv->ring.space < rem) { + int ret = i915_wait_ring(dev, rem, __func__); + if (ret) + return ret; + } + dev_priv->ring.space -= rem; + + virt = (unsigned int *) + (dev_priv->ring.virtual_start + dev_priv->ring.tail); + rem /= 4; + while (rem--) + *virt++ = MI_NOOP; + + dev_priv->ring.tail = 0; + + return 0; +} + +int i915_wait_ring(struct drm_device * dev, int n, const char *caller) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_ring_buffer_t *ring = &(dev_priv->ring); + u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD; + u32 last_acthd = I915_READ(acthd_reg); + u32 acthd; + u32 last_head = I915_READ(PRB0_HEAD) & HEAD_ADDR; + int i; + + trace_i915_ring_wait_begin (dev); + + for (i = 0; i < 100000; i++) { + ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; + acthd = I915_READ(acthd_reg); + ring->space = ring->head - (ring->tail + 8); + if (ring->space < 0) + ring->space += ring->Size; + if (ring->space >= n) { + trace_i915_ring_wait_end (dev); + return 0; + } + + if (dev->primary->master) { + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; + if (master_priv->sarea_priv) + master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; + } + + + if (ring->head != last_head) + i = 0; + if (acthd != last_acthd) + i = 0; + + last_head = ring->head; + last_acthd = acthd; + msleep_interruptible(10); + + } + + trace_i915_ring_wait_end (dev); + return -EBUSY; +} -- cgit v1.2.3 From d3301d86b4bf2bcf649982ae464211d8bcf9575a Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 21 May 2010 13:55:54 -0700 Subject: drm/i915: Rename dev_priv->ring to dev_priv->render_ring. With the advent of the BSD ring, be clear about which ring this is. The docs are pretty consistent with calling this the Render engine at this point. --- drivers/gpu/drm/i915/i915_debugfs.c | 8 +++---- drivers/gpu/drm/i915/i915_dma.c | 38 ++++++++++++++++----------------- drivers/gpu/drm/i915/i915_drv.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 20 ++++++++--------- drivers/gpu/drm/i915/i915_gem.c | 2 +- drivers/gpu/drm/i915/i915_irq.c | 12 +++++------ drivers/gpu/drm/i915/intel_ringbuffer.c | 28 ++++++++++++------------ 7 files changed, 55 insertions(+), 55 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 322070c0c631..488175c70c7d 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -317,14 +317,14 @@ static int i915_ringbuffer_data(struct seq_file *m, void *data) u8 *virt; uint32_t *ptr, off; - if (!dev_priv->ring.ring_obj) { + if (!dev_priv->render_ring.ring_obj) { seq_printf(m, "No ringbuffer setup\n"); return 0; } - virt = dev_priv->ring.virtual_start; + virt = dev_priv->render_ring.virtual_start; - for (off = 0; off < dev_priv->ring.Size; off += 4) { + for (off = 0; off < dev_priv->render_ring.Size; off += 4) { ptr = (uint32_t *)(virt + off); seq_printf(m, "%08x : %08x\n", off, *ptr); } @@ -344,7 +344,7 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data) seq_printf(m, "RingHead : %08x\n", head); seq_printf(m, "RingTail : %08x\n", tail); - seq_printf(m, "RingSize : %08lx\n", dev_priv->ring.Size); + seq_printf(m, "RingSize : %08lx\n", dev_priv->render_ring.Size); seq_printf(m, "Acthd : %08x\n", I915_READ(IS_I965G(dev) ? ACTHD_I965 : ACTHD)); return 0; diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index a657e3315950..6de7eace4319 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -95,7 +95,7 @@ void i915_kernel_lost_context(struct drm_device * dev) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_master_private *master_priv; - drm_i915_ring_buffer_t *ring = &(dev_priv->ring); + drm_i915_ring_buffer_t *ring = &(dev_priv->render_ring); /* * We should never lose context on the ring with modesetting @@ -128,11 +128,11 @@ static int i915_dma_cleanup(struct drm_device * dev) if (dev->irq_enabled) drm_irq_uninstall(dev); - if (dev_priv->ring.virtual_start) { - drm_core_ioremapfree(&dev_priv->ring.map, dev); - dev_priv->ring.virtual_start = NULL; - dev_priv->ring.map.handle = NULL; - dev_priv->ring.map.size = 0; + if (dev_priv->render_ring.virtual_start) { + drm_core_ioremapfree(&dev_priv->render_ring.map, dev); + dev_priv->render_ring.virtual_start = NULL; + dev_priv->render_ring.map.handle = NULL; + dev_priv->render_ring.map.size = 0; } /* Clear the HWS virtual address at teardown */ @@ -156,24 +156,24 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) } if (init->ring_size != 0) { - if (dev_priv->ring.ring_obj != NULL) { + if (dev_priv->render_ring.ring_obj != NULL) { i915_dma_cleanup(dev); DRM_ERROR("Client tried to initialize ringbuffer in " "GEM mode\n"); return -EINVAL; } - dev_priv->ring.Size = init->ring_size; + dev_priv->render_ring.Size = init->ring_size; - dev_priv->ring.map.offset = init->ring_start; - dev_priv->ring.map.size = init->ring_size; - dev_priv->ring.map.type = 0; - dev_priv->ring.map.flags = 0; - dev_priv->ring.map.mtrr = 0; + dev_priv->render_ring.map.offset = init->ring_start; + dev_priv->render_ring.map.size = init->ring_size; + dev_priv->render_ring.map.type = 0; + dev_priv->render_ring.map.flags = 0; + dev_priv->render_ring.map.mtrr = 0; - drm_core_ioremap_wc(&dev_priv->ring.map, dev); + drm_core_ioremap_wc(&dev_priv->render_ring.map, dev); - if (dev_priv->ring.map.handle == NULL) { + if (dev_priv->render_ring.map.handle == NULL) { i915_dma_cleanup(dev); DRM_ERROR("can not ioremap virtual address for" " ring buffer\n"); @@ -181,7 +181,7 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) } } - dev_priv->ring.virtual_start = dev_priv->ring.map.handle; + dev_priv->render_ring.virtual_start = dev_priv->render_ring.map.handle; dev_priv->cpp = init->cpp; dev_priv->back_offset = init->back_offset; @@ -203,7 +203,7 @@ static int i915_dma_resume(struct drm_device * dev) DRM_DEBUG_DRIVER("%s\n", __func__); - if (dev_priv->ring.map.handle == NULL) { + if (dev_priv->render_ring.map.handle == NULL) { DRM_ERROR("can not ioremap virtual address for" " ring buffer\n"); return -ENOMEM; @@ -332,7 +332,7 @@ static int i915_emit_cmds(struct drm_device * dev, int *buffer, int dwords) int i; RING_LOCALS; - if ((dwords+1) * sizeof(int) >= dev_priv->ring.Size - 8) + if ((dwords+1) * sizeof(int) >= dev_priv->render_ring.Size - 8) return -EINVAL; BEGIN_LP_RING((dwords+1)&~1); @@ -563,7 +563,7 @@ static int i915_quiescent(struct drm_device * dev) drm_i915_private_t *dev_priv = dev->dev_private; i915_kernel_lost_context(dev); - return i915_wait_ring(dev, dev_priv->ring.Size - 8, __func__); + return i915_wait_ring(dev, dev_priv->render_ring.Size - 8, __func__); } static int i915_flush_ioctl(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 5c51e45ab68d..a1814f65fdb4 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -389,7 +389,7 @@ int i965_reset(struct drm_device *dev, u8 flags) */ if (drm_core_check_feature(dev, DRIVER_MODESET) || !dev_priv->mm.suspended) { - drm_i915_ring_buffer_t *ring = &dev_priv->ring; + drm_i915_ring_buffer_t *ring = &dev_priv->render_ring; struct drm_gem_object *obj = ring->ring_obj; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); dev_priv->mm.suspended = 0; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 114653aa9ae2..a39440cf1dee 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -244,7 +244,7 @@ typedef struct drm_i915_private { void __iomem *regs; struct pci_dev *bridge_dev; - drm_i915_ring_buffer_t ring; + drm_i915_ring_buffer_t render_ring; drm_dma_handle_t *status_page_dmah; void *hw_status_page; @@ -1044,7 +1044,7 @@ extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); * has access to the ring. */ #define RING_LOCK_TEST_WITH_RETURN(dev, file_priv) do { \ - if (((drm_i915_private_t *)dev->dev_private)->ring.ring_obj == NULL) \ + if (((drm_i915_private_t *)dev->dev_private)->render_ring.ring_obj == NULL) \ LOCK_TEST_WITH_RETURN(dev, file_priv); \ } while (0) @@ -1066,15 +1066,15 @@ extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); int bytes__ = 4*(n); \ if (I915_VERBOSE) DRM_DEBUG("BEGIN_LP_RING(%d)\n", (n)); \ /* a wrap must occur between instructions so pad beforehand */ \ - if (unlikely (dev_priv->ring.tail + bytes__ > dev_priv->ring.Size)) \ + if (unlikely (dev_priv->render_ring.tail + bytes__ > dev_priv->render_ring.Size)) \ i915_wrap_ring(dev); \ - if (unlikely (dev_priv->ring.space < bytes__)) \ + if (unlikely (dev_priv->render_ring.space < bytes__)) \ i915_wait_ring(dev, bytes__, __func__); \ ring_virt__ = (unsigned int *) \ - (dev_priv->ring.virtual_start + dev_priv->ring.tail); \ - dev_priv->ring.tail += bytes__; \ - dev_priv->ring.tail &= dev_priv->ring.Size - 1; \ - dev_priv->ring.space -= bytes__; \ + (dev_priv->render_ring.virtual_start + dev_priv->render_ring.tail); \ + dev_priv->render_ring.tail += bytes__; \ + dev_priv->render_ring.tail &= dev_priv->render_ring.Size - 1; \ + dev_priv->render_ring.space -= bytes__; \ } while (0) #define OUT_RING(n) do { \ @@ -1084,8 +1084,8 @@ extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); #define ADVANCE_LP_RING() do { \ if (I915_VERBOSE) \ - DRM_DEBUG("ADVANCE_LP_RING %x\n", dev_priv->ring.tail); \ - I915_WRITE(PRB0_TAIL, dev_priv->ring.tail); \ + DRM_DEBUG("ADVANCE_LP_RING %x\n", dev_priv->render_ring.tail); \ + I915_WRITE(PRB0_TAIL, dev_priv->render_ring.tail); \ } while(0) /** diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 4f2f5f8cdca2..95dbe5628a25 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4378,7 +4378,7 @@ i915_gem_idle(struct drm_device *dev) mutex_lock(&dev->struct_mutex); - if (dev_priv->mm.suspended || dev_priv->ring.ring_obj == NULL) { + if (dev_priv->mm.suspended || dev_priv->render_ring.ring_obj == NULL) { mutex_unlock(&dev->struct_mutex); return 0; } diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 896184bfeb12..dd91c97de968 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -536,17 +536,17 @@ i915_ringbuffer_last_batch(struct drm_device *dev) */ bbaddr = 0; head = I915_READ(PRB0_HEAD) & HEAD_ADDR; - ring = (u32 *)(dev_priv->ring.virtual_start + head); + ring = (u32 *)(dev_priv->render_ring.virtual_start + head); - while (--ring >= (u32 *)dev_priv->ring.virtual_start) { + while (--ring >= (u32 *)dev_priv->render_ring.virtual_start) { bbaddr = i915_get_bbaddr(dev, ring); if (bbaddr) break; } if (bbaddr == 0) { - ring = (u32 *)(dev_priv->ring.virtual_start + dev_priv->ring.Size); - while (--ring >= (u32 *)dev_priv->ring.virtual_start) { + ring = (u32 *)(dev_priv->render_ring.virtual_start + dev_priv->render_ring.Size); + while (--ring >= (u32 *)dev_priv->render_ring.virtual_start) { bbaddr = i915_get_bbaddr(dev, ring); if (bbaddr) break; @@ -639,7 +639,7 @@ static void i915_capture_error_state(struct drm_device *dev) error->batchbuffer[1] = i915_error_object_create(dev, batchbuffer[1]); /* Record the ringbuffer */ - error->ringbuffer = i915_error_object_create(dev, dev_priv->ring.ring_obj); + error->ringbuffer = i915_error_object_create(dev, dev_priv->render_ring.ring_obj); /* Record buffers on the active list. */ error->active_bo = NULL; @@ -1056,7 +1056,7 @@ int i915_irq_emit(struct drm_device *dev, void *data, drm_i915_irq_emit_t *emit = data; int result; - if (!dev_priv || !dev_priv->ring.virtual_start) { + if (!dev_priv || !dev_priv->render_ring.virtual_start) { DRM_ERROR("called with no initialization\n"); return -EINVAL; } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 13a796fafaee..06058ddb4eed 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -368,7 +368,7 @@ i915_gem_init_ringbuffer(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; - drm_i915_ring_buffer_t *ring = &dev_priv->ring; + drm_i915_ring_buffer_t *ring = &dev_priv->render_ring; int ret; u32 head; @@ -403,7 +403,7 @@ i915_gem_init_ringbuffer(struct drm_device *dev) drm_core_ioremap_wc(&ring->map, dev); if (ring->map.handle == NULL) { DRM_ERROR("Failed to map ringbuffer.\n"); - memset(&dev_priv->ring, 0, sizeof(dev_priv->ring)); + memset(&dev_priv->render_ring, 0, sizeof(dev_priv->render_ring)); i915_gem_object_unpin(obj); drm_gem_object_unreference(obj); i915_gem_cleanup_hws(dev); @@ -481,15 +481,15 @@ i915_gem_cleanup_ringbuffer(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; - if (dev_priv->ring.ring_obj == NULL) + if (dev_priv->render_ring.ring_obj == NULL) return; - drm_core_ioremapfree(&dev_priv->ring.map, dev); + drm_core_ioremapfree(&dev_priv->render_ring.map, dev); - i915_gem_object_unpin(dev_priv->ring.ring_obj); - drm_gem_object_unreference(dev_priv->ring.ring_obj); - dev_priv->ring.ring_obj = NULL; - memset(&dev_priv->ring, 0, sizeof(dev_priv->ring)); + i915_gem_object_unpin(dev_priv->render_ring.ring_obj); + drm_gem_object_unreference(dev_priv->render_ring.ring_obj); + dev_priv->render_ring.ring_obj = NULL; + memset(&dev_priv->render_ring, 0, sizeof(dev_priv->render_ring)); i915_gem_cleanup_hws(dev); } @@ -503,21 +503,21 @@ int i915_wrap_ring(struct drm_device *dev) volatile unsigned int *virt; int rem; - rem = dev_priv->ring.Size - dev_priv->ring.tail; - if (dev_priv->ring.space < rem) { + rem = dev_priv->render_ring.Size - dev_priv->render_ring.tail; + if (dev_priv->render_ring.space < rem) { int ret = i915_wait_ring(dev, rem, __func__); if (ret) return ret; } - dev_priv->ring.space -= rem; + dev_priv->render_ring.space -= rem; virt = (unsigned int *) - (dev_priv->ring.virtual_start + dev_priv->ring.tail); + (dev_priv->render_ring.virtual_start + dev_priv->render_ring.tail); rem /= 4; while (rem--) *virt++ = MI_NOOP; - dev_priv->ring.tail = 0; + dev_priv->render_ring.tail = 0; return 0; } @@ -525,7 +525,7 @@ int i915_wrap_ring(struct drm_device *dev) int i915_wait_ring(struct drm_device * dev, int n, const char *caller) { drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_ring_buffer_t *ring = &(dev_priv->ring); + drm_i915_ring_buffer_t *ring = &(dev_priv->render_ring); u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD; u32 last_acthd = I915_READ(acthd_reg); u32 acthd; -- cgit v1.2.3 From 8187a2b70e34c727a06617441f74f202b6fefaf9 Mon Sep 17 00:00:00 2001 From: Zou Nan hai Date: Fri, 21 May 2010 09:08:55 +0800 Subject: drm/i915: introduce intel_ring_buffer structure (V2) Introduces a more complete intel_ring_buffer structure with callbacks for setup and management of a particular ringbuffer, and converts the render ring buffer consumers to use it. Signed-off-by: Zou Nan hai Signed-off-by: Xiang Hai hao [anholt: Fixed up whitespace fail and rebased against prep patches] Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_debugfs.c | 6 +- drivers/gpu/drm/i915/i915_dma.c | 58 ++-- drivers/gpu/drm/i915/i915_drv.c | 29 +- drivers/gpu/drm/i915/i915_drv.h | 80 ++--- drivers/gpu/drm/i915/i915_gem.c | 76 ++++- drivers/gpu/drm/i915/i915_irq.c | 15 +- drivers/gpu/drm/i915/intel_display.c | 1 - drivers/gpu/drm/i915/intel_overlay.c | 8 - drivers/gpu/drm/i915/intel_ringbuffer.c | 582 +++++++++++++++++++------------- drivers/gpu/drm/i915/intel_ringbuffer.h | 124 +++++++ 10 files changed, 603 insertions(+), 376 deletions(-) create mode 100644 drivers/gpu/drm/i915/intel_ringbuffer.h (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 488175c70c7d..4fddf094deb2 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -317,14 +317,14 @@ static int i915_ringbuffer_data(struct seq_file *m, void *data) u8 *virt; uint32_t *ptr, off; - if (!dev_priv->render_ring.ring_obj) { + if (!dev_priv->render_ring.gem_object) { seq_printf(m, "No ringbuffer setup\n"); return 0; } virt = dev_priv->render_ring.virtual_start; - for (off = 0; off < dev_priv->render_ring.Size; off += 4) { + for (off = 0; off < dev_priv->render_ring.size; off += 4) { ptr = (uint32_t *)(virt + off); seq_printf(m, "%08x : %08x\n", off, *ptr); } @@ -344,7 +344,7 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data) seq_printf(m, "RingHead : %08x\n", head); seq_printf(m, "RingTail : %08x\n", tail); - seq_printf(m, "RingSize : %08lx\n", dev_priv->render_ring.Size); + seq_printf(m, "RingSize : %08lx\n", dev_priv->render_ring.size); seq_printf(m, "Acthd : %08x\n", I915_READ(IS_I965G(dev) ? ACTHD_I965 : ACTHD)); return 0; diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 6de7eace4319..2541428b2fe5 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -40,7 +40,6 @@ #include #include - /** * Sets up the hardware status page for devices that need a physical address * in the register. @@ -56,10 +55,11 @@ static int i915_init_phys_hws(struct drm_device *dev) DRM_ERROR("Can not allocate hardware status page\n"); return -ENOMEM; } - dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr; + dev_priv->render_ring.status_page.page_addr + = dev_priv->status_page_dmah->vaddr; dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr; - memset(dev_priv->hw_status_page, 0, PAGE_SIZE); + memset(dev_priv->render_ring.status_page.page_addr, 0, PAGE_SIZE); if (IS_I965G(dev)) dev_priv->dma_status_page |= (dev_priv->dma_status_page >> 28) & @@ -95,7 +95,7 @@ void i915_kernel_lost_context(struct drm_device * dev) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_master_private *master_priv; - drm_i915_ring_buffer_t *ring = &(dev_priv->render_ring); + struct intel_ring_buffer *ring = &dev_priv->render_ring; /* * We should never lose context on the ring with modesetting @@ -108,7 +108,7 @@ void i915_kernel_lost_context(struct drm_device * dev) ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR; ring->space = ring->head - (ring->tail + 8); if (ring->space < 0) - ring->space += ring->Size; + ring->space += ring->size; if (!dev->primary->master) return; @@ -128,12 +128,7 @@ static int i915_dma_cleanup(struct drm_device * dev) if (dev->irq_enabled) drm_irq_uninstall(dev); - if (dev_priv->render_ring.virtual_start) { - drm_core_ioremapfree(&dev_priv->render_ring.map, dev); - dev_priv->render_ring.virtual_start = NULL; - dev_priv->render_ring.map.handle = NULL; - dev_priv->render_ring.map.size = 0; - } + intel_cleanup_ring_buffer(dev, &dev_priv->render_ring); /* Clear the HWS virtual address at teardown */ if (I915_NEED_GFX_HWS(dev)) @@ -156,14 +151,14 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) } if (init->ring_size != 0) { - if (dev_priv->render_ring.ring_obj != NULL) { + if (dev_priv->render_ring.gem_object != NULL) { i915_dma_cleanup(dev); DRM_ERROR("Client tried to initialize ringbuffer in " "GEM mode\n"); return -EINVAL; } - dev_priv->render_ring.Size = init->ring_size; + dev_priv->render_ring.size = init->ring_size; dev_priv->render_ring.map.offset = init->ring_start; dev_priv->render_ring.map.size = init->ring_size; @@ -201,26 +196,29 @@ static int i915_dma_resume(struct drm_device * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + struct intel_ring_buffer *ring; DRM_DEBUG_DRIVER("%s\n", __func__); - if (dev_priv->render_ring.map.handle == NULL) { + ring = &dev_priv->render_ring; + + if (ring->map.handle == NULL) { DRM_ERROR("can not ioremap virtual address for" " ring buffer\n"); return -ENOMEM; } /* Program Hardware Status Page */ - if (!dev_priv->hw_status_page) { + if (!ring->status_page.page_addr) { DRM_ERROR("Can not find hardware status page\n"); return -EINVAL; } DRM_DEBUG_DRIVER("hw status page @ %p\n", - dev_priv->hw_status_page); - - if (dev_priv->status_gfx_addr != 0) - I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr); + ring->status_page.page_addr); + if (ring->status_page.gfx_addr != 0) + ring->setup_status_page(dev, ring); else I915_WRITE(HWS_PGA, dev_priv->dma_status_page); + DRM_DEBUG_DRIVER("Enabled hardware status page\n"); return 0; @@ -330,9 +328,8 @@ static int i915_emit_cmds(struct drm_device * dev, int *buffer, int dwords) { drm_i915_private_t *dev_priv = dev->dev_private; int i; - RING_LOCALS; - if ((dwords+1) * sizeof(int) >= dev_priv->render_ring.Size - 8) + if ((dwords+1) * sizeof(int) >= dev_priv->render_ring.size - 8) return -EINVAL; BEGIN_LP_RING((dwords+1)&~1); @@ -365,9 +362,7 @@ i915_emit_box(struct drm_device *dev, struct drm_clip_rect *boxes, int i, int DR1, int DR4) { - drm_i915_private_t *dev_priv = dev->dev_private; struct drm_clip_rect box = boxes[i]; - RING_LOCALS; if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) { DRM_ERROR("Bad box %d,%d..%d,%d\n", @@ -404,7 +399,6 @@ static void i915_emit_breadcrumb(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; - RING_LOCALS; dev_priv->counter++; if (dev_priv->counter > 0x7FFFFFFFUL) @@ -458,10 +452,8 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev, drm_i915_batchbuffer_t * batch, struct drm_clip_rect *cliprects) { - drm_i915_private_t *dev_priv = dev->dev_private; int nbox = batch->num_cliprects; int i = 0, count; - RING_LOCALS; if ((batch->start | batch->used) & 0x7) { DRM_ERROR("alignment"); @@ -510,7 +502,6 @@ static int i915_dispatch_flip(struct drm_device * dev) drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; - RING_LOCALS; if (!master_priv->sarea_priv) return -EINVAL; @@ -563,7 +554,8 @@ static int i915_quiescent(struct drm_device * dev) drm_i915_private_t *dev_priv = dev->dev_private; i915_kernel_lost_context(dev); - return i915_wait_ring(dev, dev_priv->render_ring.Size - 8, __func__); + return intel_wait_ring_buffer(dev, &dev_priv->render_ring, + dev_priv->render_ring.size - 8); } static int i915_flush_ioctl(struct drm_device *dev, void *data, @@ -805,6 +797,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data, { drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_hws_addr_t *hws = data; + struct intel_ring_buffer *ring = &dev_priv->render_ring; if (!I915_NEED_GFX_HWS(dev)) return -EINVAL; @@ -821,7 +814,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data, DRM_DEBUG_DRIVER("set status page addr 0x%08x\n", (u32)hws->addr); - dev_priv->status_gfx_addr = hws->addr & (0x1ffff<<12); + ring->status_page.gfx_addr = hws->addr & (0x1ffff<<12); dev_priv->hws_map.offset = dev->agp->base + hws->addr; dev_priv->hws_map.size = 4*1024; @@ -837,10 +830,10 @@ static int i915_set_status_page(struct drm_device *dev, void *data, " G33 hw status page\n"); return -ENOMEM; } - dev_priv->hw_status_page = dev_priv->hws_map.handle; + ring->status_page.page_addr = dev_priv->hws_map.handle; + memset(ring->status_page.page_addr, 0, PAGE_SIZE); + I915_WRITE(HWS_PGA, ring->status_page.gfx_addr); - memset(dev_priv->hw_status_page, 0, PAGE_SIZE); - I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr); DRM_DEBUG_DRIVER("load hws HWS_PGA with gfx mem 0x%x\n", dev_priv->status_gfx_addr); DRM_DEBUG_DRIVER("load hws at %p\n", @@ -1639,7 +1632,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) spin_lock_init(&dev_priv->user_irq_lock); spin_lock_init(&dev_priv->error_lock); - dev_priv->user_irq_refcount = 0; dev_priv->trace_irq_seqno = 0; ret = drm_vblank_init(dev, I915_NUM_PIPE); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index a1814f65fdb4..c57c54f403da 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -388,33 +388,10 @@ int i965_reset(struct drm_device *dev, u8 flags) * switched away). */ if (drm_core_check_feature(dev, DRIVER_MODESET) || - !dev_priv->mm.suspended) { - drm_i915_ring_buffer_t *ring = &dev_priv->render_ring; - struct drm_gem_object *obj = ring->ring_obj; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); + !dev_priv->mm.suspended) { + struct intel_ring_buffer *ring = &dev_priv->render_ring; dev_priv->mm.suspended = 0; - - /* Stop the ring if it's running. */ - I915_WRITE(PRB0_CTL, 0); - I915_WRITE(PRB0_TAIL, 0); - I915_WRITE(PRB0_HEAD, 0); - - /* Initialize the ring. */ - I915_WRITE(PRB0_START, obj_priv->gtt_offset); - I915_WRITE(PRB0_CTL, - ((obj->size - 4096) & RING_NR_PAGES) | - RING_NO_REPORT | - RING_VALID); - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - i915_kernel_lost_context(dev); - else { - ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; - ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR; - ring->space = ring->head - (ring->tail + 8); - if (ring->space < 0) - ring->space += ring->Size; - } - + ring->init(dev, ring); mutex_unlock(&dev->struct_mutex); drm_irq_uninstall(dev); drm_irq_install(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a39440cf1dee..6bb7933d49dc 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -31,8 +31,8 @@ #define _I915_DRV_H_ #include "i915_reg.h" -#include "i915_drm.h" #include "intel_bios.h" +#include "intel_ringbuffer.h" #include /* General customization: @@ -92,16 +92,6 @@ struct drm_i915_gem_phys_object { struct drm_gem_object *cur_obj; }; -typedef struct _drm_i915_ring_buffer { - unsigned long Size; - u8 *virtual_start; - int head; - int tail; - int space; - drm_local_map_t map; - struct drm_gem_object *ring_obj; -} drm_i915_ring_buffer_t; - struct mem_block { struct mem_block *next; struct mem_block *prev; @@ -244,7 +234,7 @@ typedef struct drm_i915_private { void __iomem *regs; struct pci_dev *bridge_dev; - drm_i915_ring_buffer_t render_ring; + struct intel_ring_buffer render_ring; drm_dma_handle_t *status_page_dmah; void *hw_status_page; @@ -270,8 +260,6 @@ typedef struct drm_i915_private { atomic_t irq_received; /** Protects user_irq_refcount and irq_mask_reg */ spinlock_t user_irq_lock; - /** Refcount for i915_user_irq_get() versus i915_user_irq_put(). */ - int user_irq_refcount; u32 trace_irq_seqno; /** Cached value of IMR to avoid reads in updating the bitfield */ u32 irq_mask_reg; @@ -832,9 +820,7 @@ 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); -void i915_user_irq_get(struct drm_device *dev); void i915_trace_irq_get(struct drm_device *dev, u32 seqno); -void i915_user_irq_put(struct drm_device *dev); extern void i915_enable_interrupt (struct drm_device *dev); extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); @@ -853,8 +839,10 @@ extern int i915_vblank_swap(struct drm_device *dev, void *data, struct drm_file *file_priv); extern void i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask); extern void i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask); -void ironlake_enable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask); -void ironlake_disable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask); +extern void ironlake_enable_graphics_irq(drm_i915_private_t *dev_priv, + u32 mask); +extern void ironlake_disable_graphics_irq(drm_i915_private_t *dev_priv, + u32 mask); void i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask); @@ -962,8 +950,6 @@ void i915_gem_object_flush_write_domain(struct drm_gem_object *obj); void i915_gem_shrinker_init(void); void i915_gem_shrinker_exit(void); -int i915_gem_init_pipe_control(struct drm_device *dev); -void i915_gem_cleanup_pipe_control(struct drm_device *dev); /* i915_gem_tiling.c */ void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); @@ -1014,16 +1000,6 @@ static inline void ironlake_opregion_gse_intr(struct drm_device *dev) { return; static inline void opregion_enable_asle(struct drm_device *dev) { return; } #endif -/* intel_ringbuffer.c */ -extern void i915_gem_flush(struct drm_device *dev, - uint32_t invalidate_domains, - uint32_t flush_domains); -extern int i915_dispatch_gem_execbuffer(struct drm_device *dev, - struct drm_i915_gem_execbuffer2 *exec, - struct drm_clip_rect *cliprects, - uint64_t exec_offset); -extern uint32_t i915_ring_add_request(struct drm_device *dev); - /* modesetting */ extern void intel_modeset_init(struct drm_device *dev); extern void intel_modeset_cleanup(struct drm_device *dev); @@ -1044,7 +1020,8 @@ extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); * has access to the ring. */ #define RING_LOCK_TEST_WITH_RETURN(dev, file_priv) do { \ - if (((drm_i915_private_t *)dev->dev_private)->render_ring.ring_obj == NULL) \ + if (((drm_i915_private_t *)dev->dev_private)->render_ring.gem_object \ + == NULL) \ LOCK_TEST_WITH_RETURN(dev, file_priv); \ } while (0) @@ -1060,32 +1037,27 @@ extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); #define I915_VERBOSE 0 -#define RING_LOCALS volatile unsigned int *ring_virt__; - -#define BEGIN_LP_RING(n) do { \ - int bytes__ = 4*(n); \ - if (I915_VERBOSE) DRM_DEBUG("BEGIN_LP_RING(%d)\n", (n)); \ - /* a wrap must occur between instructions so pad beforehand */ \ - if (unlikely (dev_priv->render_ring.tail + bytes__ > dev_priv->render_ring.Size)) \ - i915_wrap_ring(dev); \ - if (unlikely (dev_priv->render_ring.space < bytes__)) \ - i915_wait_ring(dev, bytes__, __func__); \ - ring_virt__ = (unsigned int *) \ - (dev_priv->render_ring.virtual_start + dev_priv->render_ring.tail); \ - dev_priv->render_ring.tail += bytes__; \ - dev_priv->render_ring.tail &= dev_priv->render_ring.Size - 1; \ - dev_priv->render_ring.space -= bytes__; \ +#define BEGIN_LP_RING(n) do { \ + drm_i915_private_t *dev_priv = dev->dev_private; \ + if (I915_VERBOSE) \ + DRM_DEBUG(" BEGIN_LP_RING %x\n", (int)(n)); \ + intel_ring_begin(dev, &dev_priv->render_ring, 4*(n)); \ } while (0) -#define OUT_RING(n) do { \ - if (I915_VERBOSE) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \ - *ring_virt__++ = (n); \ + +#define OUT_RING(x) do { \ + drm_i915_private_t *dev_priv = dev->dev_private; \ + if (I915_VERBOSE) \ + DRM_DEBUG(" OUT_RING %x\n", (int)(x)); \ + intel_ring_emit(dev, &dev_priv->render_ring, x); \ } while (0) #define ADVANCE_LP_RING() do { \ + drm_i915_private_t *dev_priv = dev->dev_private; \ if (I915_VERBOSE) \ - DRM_DEBUG("ADVANCE_LP_RING %x\n", dev_priv->render_ring.tail); \ - I915_WRITE(PRB0_TAIL, dev_priv->render_ring.tail); \ + DRM_DEBUG("ADVANCE_LP_RING %x\n", \ + dev_priv->render_ring.tail); \ + intel_ring_advance(dev, &dev_priv->render_ring); \ } while(0) /** @@ -1103,14 +1075,12 @@ extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); * * The area from dword 0x20 to 0x3ff is available for driver usage. */ -#define READ_HWSP(dev_priv, reg) (((volatile u32*)(dev_priv->hw_status_page))[reg]) +#define READ_HWSP(dev_priv, reg) (((volatile u32 *)\ + (dev_priv->render_ring.status_page.page_addr))[reg]) #define READ_BREADCRUMB(dev_priv) READ_HWSP(dev_priv, I915_BREADCRUMB_INDEX) #define I915_GEM_HWS_INDEX 0x20 #define I915_BREADCRUMB_INDEX 0x21 -extern int i915_wrap_ring(struct drm_device * dev); -extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); - #define INTEL_INFO(dev) (((struct drm_i915_private *) (dev)->dev_private)->info) #define IS_I830(dev) ((dev)->pci_device == 0x3577) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 95dbe5628a25..58b6e814fae1 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1590,6 +1590,7 @@ i915_gem_process_flushing_list(struct drm_device *dev, } } } + uint32_t i915_add_request(struct drm_device *dev, struct drm_file *file_priv, uint32_t flush_domains) @@ -1607,7 +1608,8 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv, if (request == NULL) return 0; - seqno = i915_ring_add_request(dev); + seqno = dev_priv->render_ring.add_request(dev, &dev_priv->render_ring, + file_priv, flush_domains); DRM_DEBUG_DRIVER("%d\n", seqno); @@ -1645,10 +1647,8 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv, static uint32_t i915_retire_commands(struct drm_device *dev) { - drm_i915_private_t *dev_priv = dev->dev_private; uint32_t cmd = MI_FLUSH | MI_NO_WRITE_FLUSH; uint32_t flush_domains = 0; - RING_LOCALS; /* The sampler always gets flushed on i965 (sigh) */ if (IS_I965G(dev)) @@ -1746,7 +1746,9 @@ i915_gem_retire_requests(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; uint32_t seqno; - if (!dev_priv->hw_status_page || list_empty(&dev_priv->mm.request_list)) + struct intel_ring_buffer *ring = &(dev_priv->render_ring); + if (!ring->status_page.page_addr + || list_empty(&dev_priv->mm.request_list)) return; seqno = i915_get_gem_seqno(dev); @@ -1773,7 +1775,8 @@ i915_gem_retire_requests(struct drm_device *dev) if (unlikely (dev_priv->trace_irq_seqno && i915_seqno_passed(dev_priv->trace_irq_seqno, seqno))) { - i915_user_irq_put(dev); + + ring->user_irq_put(dev, ring); dev_priv->trace_irq_seqno = 0; } } @@ -1803,6 +1806,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptible) u32 ier; int ret = 0; + struct intel_ring_buffer *ring = &dev_priv->render_ring; BUG_ON(seqno == 0); if (atomic_read(&dev_priv->mm.wedged)) @@ -1823,7 +1827,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptible) trace_i915_gem_request_wait_begin(dev, seqno); dev_priv->mm.waiting_gem_seqno = seqno; - i915_user_irq_get(dev); + ring->user_irq_get(dev, ring); if (interruptible) ret = wait_event_interruptible(dev_priv->irq_queue, i915_seqno_passed(i915_get_gem_seqno(dev), seqno) || @@ -1833,7 +1837,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptible) i915_seqno_passed(i915_get_gem_seqno(dev), seqno) || atomic_read(&dev_priv->mm.wedged)); - i915_user_irq_put(dev); + ring->user_irq_put(dev, ring); dev_priv->mm.waiting_gem_seqno = 0; trace_i915_gem_request_wait_end(dev, seqno); @@ -1867,6 +1871,19 @@ i915_wait_request(struct drm_device *dev, uint32_t seqno) } +static void +i915_gem_flush(struct drm_device *dev, + uint32_t invalidate_domains, + uint32_t flush_domains) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + if (flush_domains & I915_GEM_DOMAIN_CPU) + drm_agp_chipset_flush(dev); + dev_priv->render_ring.flush(dev, &dev_priv->render_ring, + invalidate_domains, + flush_domains); +} + /** * Ensures that all rendering to the object has completed and the object is * safe to unbind from the GTT or access from the CPU. @@ -3820,7 +3837,11 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, #endif /* Exec the batchbuffer */ - ret = i915_dispatch_gem_execbuffer(dev, args, cliprects, exec_offset); + ret = dev_priv->render_ring.dispatch_gem_execbuffer(dev, + &dev_priv->render_ring, + args, + cliprects, + exec_offset); if (ret) { DRM_ERROR("dispatch failed %d\n", ret); goto err; @@ -4378,7 +4399,8 @@ i915_gem_idle(struct drm_device *dev) mutex_lock(&dev->struct_mutex); - if (dev_priv->mm.suspended || dev_priv->render_ring.ring_obj == NULL) { + if (dev_priv->mm.suspended || + dev_priv->render_ring.gem_object == NULL) { mutex_unlock(&dev->struct_mutex); return 0; } @@ -4420,7 +4442,7 @@ i915_gem_idle(struct drm_device *dev) * 965+ support PIPE_CONTROL commands, which provide finer grained control * over cache flushing. */ -int +static int i915_gem_init_pipe_control(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -4459,7 +4481,8 @@ err: return ret; } -void + +static void i915_gem_cleanup_pipe_control(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -4476,6 +4499,37 @@ i915_gem_cleanup_pipe_control(struct drm_device *dev) dev_priv->seqno_page = NULL; } +int +i915_gem_init_ringbuffer(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + int ret; + dev_priv->render_ring = render_ring; + if (!I915_NEED_GFX_HWS(dev)) { + dev_priv->render_ring.status_page.page_addr + = dev_priv->status_page_dmah->vaddr; + memset(dev_priv->render_ring.status_page.page_addr, + 0, PAGE_SIZE); + } + if (HAS_PIPE_CONTROL(dev)) { + ret = i915_gem_init_pipe_control(dev); + if (ret) + return ret; + } + ret = intel_init_ring_buffer(dev, &dev_priv->render_ring); + return ret; +} + +void +i915_gem_cleanup_ringbuffer(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + + intel_cleanup_ring_buffer(dev, &dev_priv->render_ring); + if (HAS_PIPE_CONTROL(dev)) + i915_gem_cleanup_pipe_control(dev); +} + int i915_gem_entervt_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index dd91c97de968..e07c643c8365 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -545,7 +545,8 @@ i915_ringbuffer_last_batch(struct drm_device *dev) } if (bbaddr == 0) { - ring = (u32 *)(dev_priv->render_ring.virtual_start + dev_priv->render_ring.Size); + ring = (u32 *)(dev_priv->render_ring.virtual_start + + dev_priv->render_ring.size); while (--ring >= (u32 *)dev_priv->render_ring.virtual_start) { bbaddr = i915_get_bbaddr(dev, ring); if (bbaddr) @@ -639,7 +640,8 @@ static void i915_capture_error_state(struct drm_device *dev) error->batchbuffer[1] = i915_error_object_create(dev, batchbuffer[1]); /* Record the ringbuffer */ - error->ringbuffer = i915_error_object_create(dev, dev_priv->render_ring.ring_obj); + error->ringbuffer = i915_error_object_create(dev, + dev_priv->render_ring.gem_object); /* Record buffers on the active list. */ error->active_bo = NULL; @@ -984,7 +986,6 @@ static int i915_emit_irq(struct drm_device * dev) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; - RING_LOCALS; i915_kernel_lost_context(dev); @@ -1009,9 +1010,10 @@ static int i915_emit_irq(struct drm_device * dev) void i915_trace_irq_get(struct drm_device *dev, u32 seqno) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + struct intel_ring_buffer *render_ring = &dev_priv->render_ring; if (dev_priv->trace_irq_seqno == 0) - i915_user_irq_get(dev); + render_ring->user_irq_get(dev, render_ring); dev_priv->trace_irq_seqno = seqno; } @@ -1021,6 +1023,7 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; int ret = 0; + struct intel_ring_buffer *render_ring = &dev_priv->render_ring; DRM_DEBUG_DRIVER("irq_nr=%d breadcrumb=%d\n", irq_nr, READ_BREADCRUMB(dev_priv)); @@ -1034,10 +1037,10 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) if (master_priv->sarea_priv) master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; - i915_user_irq_get(dev); + render_ring->user_irq_get(dev, render_ring); DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ, READ_BREADCRUMB(dev_priv) >= irq_nr); - i915_user_irq_put(dev); + render_ring->user_irq_put(dev, render_ring); if (ret == -EBUSY) { DRM_ERROR("EBUSY -- rec: %d emitted: %d\n", diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f469a84cacfd..b867f3c78408 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4629,7 +4629,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, unsigned long flags; int pipesrc_reg = (intel_crtc->pipe == 0) ? PIPEASRC : PIPEBSRC; int ret, pipesrc; - RING_LOCALS; work = kzalloc(sizeof *work, GFP_KERNEL); if (work == NULL) diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index b0e17b06eb6e..93da83782e5e 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -211,9 +211,7 @@ static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay) static int intel_overlay_on(struct intel_overlay *overlay) { struct drm_device *dev = overlay->dev; - drm_i915_private_t *dev_priv = dev->dev_private; int ret; - RING_LOCALS; BUG_ON(overlay->active); @@ -248,7 +246,6 @@ static void intel_overlay_continue(struct intel_overlay *overlay, drm_i915_private_t *dev_priv = dev->dev_private; u32 flip_addr = overlay->flip_addr; u32 tmp; - RING_LOCALS; BUG_ON(!overlay->active); @@ -274,7 +271,6 @@ static int intel_overlay_wait_flip(struct intel_overlay *overlay) drm_i915_private_t *dev_priv = dev->dev_private; int ret; u32 tmp; - RING_LOCALS; if (overlay->last_flip_req != 0) { ret = i915_do_wait_request(dev, overlay->last_flip_req, 1); @@ -314,9 +310,7 @@ static int intel_overlay_off(struct intel_overlay *overlay) { u32 flip_addr = overlay->flip_addr; struct drm_device *dev = overlay->dev; - drm_i915_private_t *dev_priv = dev->dev_private; int ret; - RING_LOCALS; BUG_ON(!overlay->active); @@ -390,11 +384,9 @@ int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, int interruptible) { struct drm_device *dev = overlay->dev; - drm_i915_private_t *dev_priv = dev->dev_private; struct drm_gem_object *obj; u32 flip_addr; int ret; - RING_LOCALS; if (overlay->hw_wedged == HW_WEDGED) return -EIO; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 06058ddb4eed..5715c4d8cce9 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -29,30 +29,24 @@ #include "drmP.h" #include "drm.h" -#include "i915_drm.h" #include "i915_drv.h" +#include "i915_drm.h" #include "i915_trace.h" -#include "intel_drv.h" -void -i915_gem_flush(struct drm_device *dev, - uint32_t invalidate_domains, - uint32_t flush_domains) +static void +render_ring_flush(struct drm_device *dev, + struct intel_ring_buffer *ring, + u32 invalidate_domains, + u32 flush_domains) { - drm_i915_private_t *dev_priv = dev->dev_private; - uint32_t cmd; - RING_LOCALS; - #if WATCH_EXEC DRM_INFO("%s: invalidate %08x flush %08x\n", __func__, invalidate_domains, flush_domains); #endif - trace_i915_gem_request_flush(dev, dev_priv->mm.next_gem_seqno, + u32 cmd; + trace_i915_gem_request_flush(dev, ring->next_seqno, invalidate_domains, flush_domains); - if (flush_domains & I915_GEM_DOMAIN_CPU) - drm_agp_chipset_flush(dev); - if ((invalidate_domains | flush_domains) & I915_GEM_GPU_DOMAINS) { /* * read/write caches: @@ -100,19 +94,130 @@ i915_gem_flush(struct drm_device *dev, #if WATCH_EXEC DRM_INFO("%s: queue flush %08x to ring\n", __func__, cmd); #endif - BEGIN_LP_RING(2); - OUT_RING(cmd); - OUT_RING(MI_NOOP); - ADVANCE_LP_RING(); + intel_ring_begin(dev, ring, 8); + intel_ring_emit(dev, ring, cmd); + intel_ring_emit(dev, ring, MI_NOOP); + intel_ring_advance(dev, ring); } +} + +static unsigned int render_ring_get_head(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + return I915_READ(PRB0_HEAD) & HEAD_ADDR; +} +static unsigned int render_ring_get_tail(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + return I915_READ(PRB0_TAIL) & TAIL_ADDR; } + +static unsigned int render_ring_get_active_head(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD; + + return I915_READ(acthd_reg); +} + +static void render_ring_advance_ring(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + I915_WRITE(PRB0_TAIL, ring->tail); +} + +static int init_ring_common(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + u32 head; + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_gem_object *obj_priv; + obj_priv = to_intel_bo(ring->gem_object); + + /* Stop the ring if it's running. */ + I915_WRITE(ring->regs.ctl, 0); + I915_WRITE(ring->regs.head, 0); + I915_WRITE(ring->regs.tail, 0); + + /* Initialize the ring. */ + I915_WRITE(ring->regs.start, obj_priv->gtt_offset); + head = ring->get_head(dev, ring); + + /* G45 ring initialization fails to reset head to zero */ + if (head != 0) { + DRM_ERROR("%s head not reset to zero " + "ctl %08x head %08x tail %08x start %08x\n", + ring->name, + I915_READ(ring->regs.ctl), + I915_READ(ring->regs.head), + I915_READ(ring->regs.tail), + I915_READ(ring->regs.start)); + + I915_WRITE(ring->regs.head, 0); + + DRM_ERROR("%s head forced to zero " + "ctl %08x head %08x tail %08x start %08x\n", + ring->name, + I915_READ(ring->regs.ctl), + I915_READ(ring->regs.head), + I915_READ(ring->regs.tail), + I915_READ(ring->regs.start)); + } + + I915_WRITE(ring->regs.ctl, + ((ring->gem_object->size - PAGE_SIZE) & RING_NR_PAGES) + | RING_NO_REPORT | RING_VALID); + + head = I915_READ(ring->regs.head) & HEAD_ADDR; + /* If the head is still not zero, the ring is dead */ + if (head != 0) { + DRM_ERROR("%s initialization failed " + "ctl %08x head %08x tail %08x start %08x\n", + ring->name, + I915_READ(ring->regs.ctl), + I915_READ(ring->regs.head), + I915_READ(ring->regs.tail), + I915_READ(ring->regs.start)); + return -EIO; + } + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + i915_kernel_lost_context(dev); + else { + ring->head = ring->get_head(dev, ring); + ring->tail = ring->get_tail(dev, ring); + ring->space = ring->head - (ring->tail + 8); + if (ring->space < 0) + ring->space += ring->size; + } + return 0; +} + +static int init_render_ring(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + int ret = init_ring_common(dev, ring); + if (IS_I9XX(dev) && !IS_GEN3(dev)) { + I915_WRITE(MI_MODE, + (VS_TIMER_DISPATCH) << 16 | VS_TIMER_DISPATCH); + } + return ret; +} + #define PIPE_CONTROL_FLUSH(addr) \ +do { \ OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | \ PIPE_CONTROL_DEPTH_STALL); \ OUT_RING(addr | PIPE_CONTROL_GLOBAL_GTT); \ OUT_RING(0); \ OUT_RING(0); \ +} while (0) /** * Creates a new sequence number, emitting a write of it to the status page @@ -122,21 +227,15 @@ i915_gem_flush(struct drm_device *dev, * * Returned sequence numbers are nonzero on success. */ -uint32_t -i915_ring_add_request(struct drm_device *dev) +static u32 +render_ring_add_request(struct drm_device *dev, + struct intel_ring_buffer *ring, + struct drm_file *file_priv, + u32 flush_domains) { + u32 seqno; drm_i915_private_t *dev_priv = dev->dev_private; - uint32_t seqno; - RING_LOCALS; - - /* Grab the seqno we're going to make this request be, and bump the - * next (skipping 0 so it can be the reserved no-seqno value). - */ - seqno = dev_priv->mm.next_gem_seqno; - dev_priv->mm.next_gem_seqno++; - if (dev_priv->mm.next_gem_seqno == 0) - dev_priv->mm.next_gem_seqno++; - + seqno = intel_ring_get_seqno(dev, ring); if (HAS_PIPE_CONTROL(dev)) { u32 scratch_addr = dev_priv->seqno_gfx_addr + 128; @@ -181,13 +280,26 @@ i915_ring_add_request(struct drm_device *dev) return seqno; } -void i915_user_irq_get(struct drm_device *dev) +static u32 +render_ring_get_gem_seqno(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + if (HAS_PIPE_CONTROL(dev)) + return ((volatile u32 *)(dev_priv->seqno_page))[0]; + else + return intel_read_status_page(ring, I915_GEM_HWS_INDEX); +} + +static void +render_ring_get_user_irq(struct drm_device *dev, + struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; unsigned long irqflags; spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); - if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1)) { + if (dev->irq_enabled && (++ring->user_irq_refcount == 1)) { if (HAS_PCH_SPLIT(dev)) ironlake_enable_graphics_irq(dev_priv, GT_PIPE_NOTIFY); else @@ -196,14 +308,16 @@ void i915_user_irq_get(struct drm_device *dev) spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); } -void i915_user_irq_put(struct drm_device *dev) +static void +render_ring_put_user_irq(struct drm_device *dev, + struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; unsigned long irqflags; spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); - BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0); - if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { + BUG_ON(dev->irq_enabled && ring->user_irq_refcount <= 0); + if (dev->irq_enabled && (--ring->user_irq_refcount == 0)) { if (HAS_PCH_SPLIT(dev)) ironlake_disable_graphics_irq(dev_priv, GT_PIPE_NOTIFY); else @@ -212,20 +326,31 @@ void i915_user_irq_put(struct drm_device *dev) spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); } -/** Dispatch a batchbuffer to the ring - */ -int -i915_dispatch_gem_execbuffer(struct drm_device *dev, - struct drm_i915_gem_execbuffer2 *exec, - struct drm_clip_rect *cliprects, - uint64_t exec_offset) +static void render_setup_status_page(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + if (IS_GEN6(dev)) { + I915_WRITE(HWS_PGA_GEN6, ring->status_page.gfx_addr); + I915_READ(HWS_PGA_GEN6); /* posting read */ + } else { + I915_WRITE(HWS_PGA, ring->status_page.gfx_addr); + I915_READ(HWS_PGA); /* posting read */ + } + +} + +static int +render_ring_dispatch_gem_execbuffer(struct drm_device *dev, + struct intel_ring_buffer *ring, + struct drm_i915_gem_execbuffer2 *exec, + struct drm_clip_rect *cliprects, + uint64_t exec_offset) { drm_i915_private_t *dev_priv = dev->dev_private; int nbox = exec->num_cliprects; int i = 0, count; uint32_t exec_start, exec_len; - RING_LOCALS; - exec_start = (uint32_t) exec_offset + exec->batch_start_offset; exec_len = (uint32_t) exec->batch_len; @@ -242,74 +367,61 @@ i915_dispatch_gem_execbuffer(struct drm_device *dev, } if (IS_I830(dev) || IS_845G(dev)) { - BEGIN_LP_RING(4); - OUT_RING(MI_BATCH_BUFFER); - OUT_RING(exec_start | MI_BATCH_NON_SECURE); - OUT_RING(exec_start + exec_len - 4); - OUT_RING(0); - ADVANCE_LP_RING(); + intel_ring_begin(dev, ring, 4); + intel_ring_emit(dev, ring, MI_BATCH_BUFFER); + intel_ring_emit(dev, ring, + exec_start | MI_BATCH_NON_SECURE); + intel_ring_emit(dev, ring, exec_start + exec_len - 4); + intel_ring_emit(dev, ring, 0); } else { - BEGIN_LP_RING(2); + intel_ring_begin(dev, ring, 4); if (IS_I965G(dev)) { - OUT_RING(MI_BATCH_BUFFER_START | - (2 << 6) | - MI_BATCH_NON_SECURE_I965); - OUT_RING(exec_start); + intel_ring_emit(dev, ring, + MI_BATCH_BUFFER_START | (2 << 6) + | MI_BATCH_NON_SECURE_I965); + intel_ring_emit(dev, ring, exec_start); } else { - OUT_RING(MI_BATCH_BUFFER_START | - (2 << 6)); - OUT_RING(exec_start | MI_BATCH_NON_SECURE); + intel_ring_emit(dev, ring, MI_BATCH_BUFFER_START + | (2 << 6)); + intel_ring_emit(dev, ring, exec_start | + MI_BATCH_NON_SECURE); } - ADVANCE_LP_RING(); } + intel_ring_advance(dev, ring); } /* XXX breadcrumb */ return 0; } -static void -i915_gem_cleanup_hws(struct drm_device *dev) +static void cleanup_status_page(struct drm_device *dev, + struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; - if (dev_priv->hws_obj == NULL) + obj = ring->status_page.obj; + if (obj == NULL) return; - - obj = dev_priv->hws_obj; obj_priv = to_intel_bo(obj); kunmap(obj_priv->pages[0]); i915_gem_object_unpin(obj); drm_gem_object_unreference(obj); - dev_priv->hws_obj = NULL; + ring->status_page.obj = NULL; memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); - dev_priv->hw_status_page = NULL; - - if (HAS_PIPE_CONTROL(dev)) - i915_gem_cleanup_pipe_control(dev); - - /* Write high address into HWS_PGA when disabling. */ - I915_WRITE(HWS_PGA, 0x1ffff000); } -static int -i915_gem_init_hws(struct drm_device *dev) +static int init_status_page(struct drm_device *dev, + struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; int ret; - /* If we need a physical address for the status page, it's already - * initialized at driver load time. - */ - if (!I915_NEED_GFX_HWS(dev)) - return 0; - obj = i915_gem_alloc_object(dev, 4096); if (obj == NULL) { DRM_ERROR("Failed to allocate status page\n"); @@ -321,36 +433,21 @@ i915_gem_init_hws(struct drm_device *dev) ret = i915_gem_object_pin(obj, 4096); if (ret != 0) { - drm_gem_object_unreference(obj); goto err_unref; } - dev_priv->status_gfx_addr = obj_priv->gtt_offset; - - dev_priv->hw_status_page = kmap(obj_priv->pages[0]); - if (dev_priv->hw_status_page == NULL) { - DRM_ERROR("Failed to map status page.\n"); + ring->status_page.gfx_addr = obj_priv->gtt_offset; + ring->status_page.page_addr = kmap(obj_priv->pages[0]); + if (ring->status_page.page_addr == NULL) { memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); - ret = -EINVAL; goto err_unpin; } + ring->status_page.obj = obj; + memset(ring->status_page.page_addr, 0, PAGE_SIZE); - if (HAS_PIPE_CONTROL(dev)) { - ret = i915_gem_init_pipe_control(dev); - if (ret) - goto err_unpin; - } - - dev_priv->hws_obj = obj; - memset(dev_priv->hw_status_page, 0, PAGE_SIZE); - if (IS_GEN6(dev)) { - I915_WRITE(HWS_PGA_GEN6, dev_priv->status_gfx_addr); - I915_READ(HWS_PGA_GEN6); /* posting read */ - } else { - I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr); - I915_READ(HWS_PGA); /* posting read */ - } - DRM_DEBUG_DRIVER("hws offset: 0x%08x\n", dev_priv->status_gfx_addr); + ring->setup_status_page(dev, ring); + DRM_DEBUG_DRIVER("%s hws offset: 0x%08x\n", + ring->name, ring->status_page.gfx_addr); return 0; @@ -359,43 +456,42 @@ err_unpin: err_unref: drm_gem_object_unreference(obj); err: - return 0; + return ret; } -int -i915_gem_init_ringbuffer(struct drm_device *dev) + +int intel_init_ring_buffer(struct drm_device *dev, + struct intel_ring_buffer *ring) { - drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_gem_object *obj; - struct drm_i915_gem_object *obj_priv; - drm_i915_ring_buffer_t *ring = &dev_priv->render_ring; int ret; - u32 head; + struct drm_i915_gem_object *obj_priv; + struct drm_gem_object *obj; + ring->dev = dev; - ret = i915_gem_init_hws(dev); - if (ret != 0) - return ret; + if (I915_NEED_GFX_HWS(dev)) { + ret = init_status_page(dev, ring); + if (ret) + return ret; + } - obj = i915_gem_alloc_object(dev, 128 * 1024); + obj = i915_gem_alloc_object(dev, ring->size); if (obj == NULL) { DRM_ERROR("Failed to allocate ringbuffer\n"); - i915_gem_cleanup_hws(dev); - return -ENOMEM; + ret = -ENOMEM; + goto cleanup; } - obj_priv = to_intel_bo(obj); - ret = i915_gem_object_pin(obj, 4096); + ring->gem_object = obj; + + ret = i915_gem_object_pin(obj, ring->alignment); if (ret != 0) { drm_gem_object_unreference(obj); - i915_gem_cleanup_hws(dev); - return ret; + goto cleanup; } - /* Set up the kernel mapping for the ring. */ - ring->Size = obj->size; - + obj_priv = to_intel_bo(obj); + ring->map.size = ring->size; ring->map.offset = dev->agp->base + obj_priv->gtt_offset; - ring->map.size = obj->size; ring->map.type = 0; ring->map.flags = 0; ring->map.mtrr = 0; @@ -403,143 +499,85 @@ i915_gem_init_ringbuffer(struct drm_device *dev) drm_core_ioremap_wc(&ring->map, dev); if (ring->map.handle == NULL) { DRM_ERROR("Failed to map ringbuffer.\n"); - memset(&dev_priv->render_ring, 0, sizeof(dev_priv->render_ring)); i915_gem_object_unpin(obj); drm_gem_object_unreference(obj); - i915_gem_cleanup_hws(dev); - return -EINVAL; - } - ring->ring_obj = obj; - ring->virtual_start = ring->map.handle; - - /* Stop the ring if it's running. */ - I915_WRITE(PRB0_CTL, 0); - I915_WRITE(PRB0_TAIL, 0); - I915_WRITE(PRB0_HEAD, 0); - - /* Initialize the ring. */ - I915_WRITE(PRB0_START, obj_priv->gtt_offset); - head = I915_READ(PRB0_HEAD) & HEAD_ADDR; - - /* G45 ring initialization fails to reset head to zero */ - if (head != 0) { - DRM_ERROR("Ring head not reset to zero " - "ctl %08x head %08x tail %08x start %08x\n", - I915_READ(PRB0_CTL), - I915_READ(PRB0_HEAD), - I915_READ(PRB0_TAIL), - I915_READ(PRB0_START)); - I915_WRITE(PRB0_HEAD, 0); - - DRM_ERROR("Ring head forced to zero " - "ctl %08x head %08x tail %08x start %08x\n", - I915_READ(PRB0_CTL), - I915_READ(PRB0_HEAD), - I915_READ(PRB0_TAIL), - I915_READ(PRB0_START)); + ret = -EINVAL; + goto cleanup; } - I915_WRITE(PRB0_CTL, - ((obj->size - 4096) & RING_NR_PAGES) | - RING_NO_REPORT | - RING_VALID); - - head = I915_READ(PRB0_HEAD) & HEAD_ADDR; - - /* If the head is still not zero, the ring is dead */ - if (head != 0) { - DRM_ERROR("Ring initialization failed " - "ctl %08x head %08x tail %08x start %08x\n", - I915_READ(PRB0_CTL), - I915_READ(PRB0_HEAD), - I915_READ(PRB0_TAIL), - I915_READ(PRB0_START)); - return -EIO; + ring->virtual_start = ring->map.handle; + ret = ring->init(dev, ring); + if (ret != 0) { + intel_cleanup_ring_buffer(dev, ring); + return ret; } - /* Update our cache of the ring state */ if (!drm_core_check_feature(dev, DRIVER_MODESET)) i915_kernel_lost_context(dev); else { - ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; - ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR; + ring->head = ring->get_head(dev, ring); + ring->tail = ring->get_tail(dev, ring); ring->space = ring->head - (ring->tail + 8); if (ring->space < 0) - ring->space += ring->Size; + ring->space += ring->size; } - - if (IS_I9XX(dev) && !IS_GEN3(dev)) { - I915_WRITE(MI_MODE, - (VS_TIMER_DISPATCH) << 16 | VS_TIMER_DISPATCH); - } - - return 0; + INIT_LIST_HEAD(&ring->active_list); + INIT_LIST_HEAD(&ring->request_list); + return ret; +cleanup: + cleanup_status_page(dev, ring); + return ret; } -void -i915_gem_cleanup_ringbuffer(struct drm_device *dev) +void intel_cleanup_ring_buffer(struct drm_device *dev, + struct intel_ring_buffer *ring) { - drm_i915_private_t *dev_priv = dev->dev_private; - - if (dev_priv->render_ring.ring_obj == NULL) + if (ring->gem_object == NULL) return; - drm_core_ioremapfree(&dev_priv->render_ring.map, dev); - - i915_gem_object_unpin(dev_priv->render_ring.ring_obj); - drm_gem_object_unreference(dev_priv->render_ring.ring_obj); - dev_priv->render_ring.ring_obj = NULL; - memset(&dev_priv->render_ring, 0, sizeof(dev_priv->render_ring)); + drm_core_ioremapfree(&ring->map, dev); - i915_gem_cleanup_hws(dev); + i915_gem_object_unpin(ring->gem_object); + drm_gem_object_unreference(ring->gem_object); + ring->gem_object = NULL; + cleanup_status_page(dev, ring); } -/* As a ringbuffer is only allowed to wrap between instructions, fill - * the tail with NOOPs. - */ -int i915_wrap_ring(struct drm_device *dev) +int intel_wrap_ring_buffer(struct drm_device *dev, + struct intel_ring_buffer *ring) { - drm_i915_private_t *dev_priv = dev->dev_private; - volatile unsigned int *virt; + unsigned int *virt; int rem; + rem = ring->size - ring->tail; - rem = dev_priv->render_ring.Size - dev_priv->render_ring.tail; - if (dev_priv->render_ring.space < rem) { - int ret = i915_wait_ring(dev, rem, __func__); + if (ring->space < rem) { + int ret = intel_wait_ring_buffer(dev, ring, rem); if (ret) return ret; } - dev_priv->render_ring.space -= rem; - virt = (unsigned int *) - (dev_priv->render_ring.virtual_start + dev_priv->render_ring.tail); + virt = (unsigned int *)(ring->virtual_start + ring->tail); rem /= 4; while (rem--) *virt++ = MI_NOOP; - dev_priv->render_ring.tail = 0; + ring->tail = 0; return 0; } -int i915_wait_ring(struct drm_device * dev, int n, const char *caller) +int intel_wait_ring_buffer(struct drm_device *dev, + struct intel_ring_buffer *ring, int n) { - drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_ring_buffer_t *ring = &(dev_priv->render_ring); - u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD; - u32 last_acthd = I915_READ(acthd_reg); - u32 acthd; - u32 last_head = I915_READ(PRB0_HEAD) & HEAD_ADDR; - int i; + unsigned long end; trace_i915_ring_wait_begin (dev); - - for (i = 0; i < 100000; i++) { - ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; - acthd = I915_READ(acthd_reg); + end = jiffies + 3 * HZ; + do { + ring->head = ring->get_head(dev, ring); ring->space = ring->head - (ring->tail + 8); if (ring->space < 0) - ring->space += ring->Size; + ring->space += ring->size; if (ring->space >= n) { trace_i915_ring_wait_end (dev); return 0; @@ -550,19 +588,97 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller) if (master_priv->sarea_priv) master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; } + yield(); + } while (!time_after(jiffies, end)); + trace_i915_ring_wait_end (dev); + return -EBUSY; +} +void intel_ring_begin(struct drm_device *dev, + struct intel_ring_buffer *ring, int n) +{ + if (unlikely(ring->tail + n > ring->size)) + intel_wrap_ring_buffer(dev, ring); + if (unlikely(ring->space < n)) + intel_wait_ring_buffer(dev, ring, n); +} - if (ring->head != last_head) - i = 0; - if (acthd != last_acthd) - i = 0; +void intel_ring_emit(struct drm_device *dev, + struct intel_ring_buffer *ring, unsigned int data) +{ + unsigned int *virt = ring->virtual_start + ring->tail; + *virt = data; + ring->tail += 4; + ring->tail &= ring->size - 1; + ring->space -= 4; +} - last_head = ring->head; - last_acthd = acthd; - msleep_interruptible(10); +void intel_ring_advance(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + ring->advance_ring(dev, ring); +} - } +void intel_fill_struct(struct drm_device *dev, + struct intel_ring_buffer *ring, + void *data, + unsigned int len) +{ + unsigned int *virt = ring->virtual_start + ring->tail; + BUG_ON((len&~(4-1)) != 0); + intel_ring_begin(dev, ring, len); + memcpy(virt, data, len); + ring->tail += len; + ring->tail &= ring->size - 1; + ring->space -= len; + intel_ring_advance(dev, ring); +} - trace_i915_ring_wait_end (dev); - return -EBUSY; +u32 intel_ring_get_seqno(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + u32 seqno; + seqno = ring->next_seqno; + + /* reserve 0 for non-seqno */ + if (++ring->next_seqno == 0) + ring->next_seqno = 1; + return seqno; } + +struct intel_ring_buffer render_ring = { + .name = "render ring", + .regs = { + .ctl = PRB0_CTL, + .head = PRB0_HEAD, + .tail = PRB0_TAIL, + .start = PRB0_START + }, + .ring_flag = I915_EXEC_RENDER, + .size = 32 * PAGE_SIZE, + .alignment = PAGE_SIZE, + .virtual_start = NULL, + .dev = NULL, + .gem_object = NULL, + .head = 0, + .tail = 0, + .space = 0, + .next_seqno = 1, + .user_irq_refcount = 0, + .irq_gem_seqno = 0, + .waiting_gem_seqno = 0, + .setup_status_page = render_setup_status_page, + .init = init_render_ring, + .get_head = render_ring_get_head, + .get_tail = render_ring_get_tail, + .get_active_head = render_ring_get_active_head, + .advance_ring = render_ring_advance_ring, + .flush = render_ring_flush, + .add_request = render_ring_add_request, + .get_gem_seqno = render_ring_get_gem_seqno, + .user_irq_get = render_ring_get_user_irq, + .user_irq_put = render_ring_put_user_irq, + .dispatch_gem_execbuffer = render_ring_dispatch_gem_execbuffer, + .status_page = {NULL, 0, NULL}, + .map = {0,} +}; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h new file mode 100644 index 000000000000..d5568d3766de --- /dev/null +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -0,0 +1,124 @@ +#ifndef _INTEL_RINGBUFFER_H_ +#define _INTEL_RINGBUFFER_H_ + +struct intel_hw_status_page { + void *page_addr; + unsigned int gfx_addr; + struct drm_gem_object *obj; +}; + +struct drm_i915_gem_execbuffer2; +struct intel_ring_buffer { + const char *name; + struct ring_regs { + u32 ctl; + u32 head; + u32 tail; + u32 start; + } regs; + unsigned int ring_flag; + unsigned long size; + unsigned int alignment; + void *virtual_start; + struct drm_device *dev; + struct drm_gem_object *gem_object; + + unsigned int head; + unsigned int tail; + unsigned int space; + u32 next_seqno; + struct intel_hw_status_page status_page; + + u32 irq_gem_seqno; /* last seq seem at irq time */ + u32 waiting_gem_seqno; + int user_irq_refcount; + void (*user_irq_get)(struct drm_device *dev, + struct intel_ring_buffer *ring); + void (*user_irq_put)(struct drm_device *dev, + struct intel_ring_buffer *ring); + void (*setup_status_page)(struct drm_device *dev, + struct intel_ring_buffer *ring); + + int (*init)(struct drm_device *dev, + struct intel_ring_buffer *ring); + + unsigned int (*get_head)(struct drm_device *dev, + struct intel_ring_buffer *ring); + unsigned int (*get_tail)(struct drm_device *dev, + struct intel_ring_buffer *ring); + unsigned int (*get_active_head)(struct drm_device *dev, + struct intel_ring_buffer *ring); + void (*advance_ring)(struct drm_device *dev, + struct intel_ring_buffer *ring); + void (*flush)(struct drm_device *dev, + struct intel_ring_buffer *ring, + u32 invalidate_domains, + u32 flush_domains); + u32 (*add_request)(struct drm_device *dev, + struct intel_ring_buffer *ring, + struct drm_file *file_priv, + u32 flush_domains); + u32 (*get_gem_seqno)(struct drm_device *dev, + struct intel_ring_buffer *ring); + int (*dispatch_gem_execbuffer)(struct drm_device *dev, + struct intel_ring_buffer *ring, + struct drm_i915_gem_execbuffer2 *exec, + struct drm_clip_rect *cliprects, + uint64_t exec_offset); + + /** + * List of objects currently involved in rendering from the + * ringbuffer. + * + * Includes buffers having the contents of their GPU caches + * flushed, not necessarily primitives. last_rendering_seqno + * represents when the rendering involved will be completed. + * + * A reference is held on the buffer while on this list. + */ + struct list_head active_list; + + /** + * List of breadcrumbs associated with GPU requests currently + * outstanding. + */ + struct list_head request_list; + + wait_queue_head_t irq_queue; + drm_local_map_t map; +}; + +static inline u32 +intel_read_status_page(struct intel_ring_buffer *ring, + int reg) +{ + u32 *regs = ring->status_page.page_addr; + return regs[reg]; +} + +int intel_init_ring_buffer(struct drm_device *dev, + struct intel_ring_buffer *ring); +void intel_cleanup_ring_buffer(struct drm_device *dev, + struct intel_ring_buffer *ring); +int intel_wait_ring_buffer(struct drm_device *dev, + struct intel_ring_buffer *ring, int n); +int intel_wrap_ring_buffer(struct drm_device *dev, + struct intel_ring_buffer *ring); +void intel_ring_begin(struct drm_device *dev, + struct intel_ring_buffer *ring, int n); +void intel_ring_emit(struct drm_device *dev, + struct intel_ring_buffer *ring, u32 data); +void intel_fill_struct(struct drm_device *dev, + struct intel_ring_buffer *ring, + void *data, + unsigned int len); +void intel_ring_advance(struct drm_device *dev, + struct intel_ring_buffer *ring); + +u32 intel_ring_get_seqno(struct drm_device *dev, + struct intel_ring_buffer *ring); + +extern struct intel_ring_buffer render_ring; +extern struct intel_ring_buffer bsd_ring; + +#endif /* _INTEL_RINGBUFFER_H_ */ -- cgit v1.2.3 From 852835f343146a82a528c3b712b373661d4fa17a Mon Sep 17 00:00:00 2001 From: Zou Nan hai Date: Fri, 21 May 2010 09:08:56 +0800 Subject: drm/i915: convert some gem structures to per-ring V2 The active list and request list move into the ringbuffer structure, so each can track its active objects in the order they are in that ring. The flushing list does not, as it doesn't matter which ring caused data to end up in the render cache. Objects gain a pointer to the ring they are active on (if any). Signed-off-by: Zou Nan hai Signed-off-by: Xiang Hai hao Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_debugfs.c | 12 +- drivers/gpu/drm/i915/i915_dma.c | 8 +- drivers/gpu/drm/i915/i915_drv.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 39 +++---- drivers/gpu/drm/i915/i915_gem.c | 210 ++++++++++++++++++++--------------- drivers/gpu/drm/i915/i915_irq.c | 45 +++++--- drivers/gpu/drm/i915/intel_overlay.c | 44 +++++--- 7 files changed, 207 insertions(+), 153 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 4fddf094deb2..c864858d5064 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -77,7 +77,7 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) case ACTIVE_LIST: seq_printf(m, "Active:\n"); lock = &dev_priv->mm.active_list_lock; - head = &dev_priv->mm.active_list; + head = &dev_priv->render_ring.active_list; break; case INACTIVE_LIST: seq_printf(m, "Inactive:\n"); @@ -129,7 +129,8 @@ static int i915_gem_request_info(struct seq_file *m, void *data) struct drm_i915_gem_request *gem_request; seq_printf(m, "Request:\n"); - list_for_each_entry(gem_request, &dev_priv->mm.request_list, list) { + list_for_each_entry(gem_request, &dev_priv->render_ring.request_list, + list) { seq_printf(m, " %d @ %d\n", gem_request->seqno, (int) (jiffies - gem_request->emitted_jiffies)); @@ -145,7 +146,7 @@ static int i915_gem_seqno_info(struct seq_file *m, void *data) if (dev_priv->hw_status_page != NULL) { seq_printf(m, "Current sequence: %d\n", - i915_get_gem_seqno(dev)); + i915_get_gem_seqno(dev, &dev_priv->render_ring)); } else { seq_printf(m, "Current sequence: hws uninitialized\n"); } @@ -197,7 +198,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data) atomic_read(&dev_priv->irq_received)); if (dev_priv->hw_status_page != NULL) { seq_printf(m, "Current sequence: %d\n", - i915_get_gem_seqno(dev)); + i915_get_gem_seqno(dev, &dev_priv->render_ring)); } else { seq_printf(m, "Current sequence: hws uninitialized\n"); } @@ -287,7 +288,8 @@ static int i915_batchbuffer_info(struct seq_file *m, void *data) spin_lock(&dev_priv->mm.active_list_lock); - list_for_each_entry(obj_priv, &dev_priv->mm.active_list, list) { + list_for_each_entry(obj_priv, &dev_priv->render_ring.active_list, + list) { obj = &obj_priv->base; if (obj->read_domains & I915_GEM_DOMAIN_COMMAND) { ret = i915_gem_object_get_pages(obj, 0); diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 2541428b2fe5..f485880300ce 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -82,7 +82,8 @@ static void i915_free_hws(struct drm_device *dev) dev_priv->status_page_dmah = NULL; } - if (dev_priv->status_gfx_addr) { + if (dev_priv->render_ring.status_page.gfx_addr) { + dev_priv->render_ring.status_page.gfx_addr = 0; dev_priv->status_gfx_addr = 0; drm_core_ioremapfree(&dev_priv->hws_map, dev); } @@ -835,9 +836,9 @@ static int i915_set_status_page(struct drm_device *dev, void *data, I915_WRITE(HWS_PGA, ring->status_page.gfx_addr); DRM_DEBUG_DRIVER("load hws HWS_PGA with gfx mem 0x%x\n", - dev_priv->status_gfx_addr); + dev_priv->status_gfx_addr); DRM_DEBUG_DRIVER("load hws at %p\n", - dev_priv->hw_status_page); + dev_priv->hw_status_page); return 0; } @@ -1510,7 +1511,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) resource_size_t base, size; int ret = 0, mmio_bar; uint32_t agp_size, prealloc_size, prealloc_start; - /* i915 has 4 more counters */ dev->counters += 4; dev->types[6] = _DRM_STAT_IRQ; diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index c57c54f403da..d40f62d36453 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -340,7 +340,7 @@ int i965_reset(struct drm_device *dev, u8 flags) /* * Clear request list */ - i915_gem_retire_requests(dev); + i915_gem_retire_requests(dev, &dev_priv->render_ring); if (need_display) i915_save_display(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6bb7933d49dc..3f35989ba74c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -505,18 +505,7 @@ typedef struct drm_i915_private { */ struct list_head shrink_list; - /** - * List of objects currently involved in rendering from the - * ringbuffer. - * - * Includes buffers having the contents of their GPU caches - * flushed, not necessarily primitives. last_rendering_seqno - * represents when the rendering involved will be completed. - * - * A reference is held on the buffer while on this list. - */ spinlock_t active_list_lock; - struct list_head active_list; /** * List of objects which are not in the ringbuffer but which @@ -553,12 +542,6 @@ typedef struct drm_i915_private { /** LRU list of objects with fence regs on them. */ struct list_head fence_list; - /** - * List of breadcrumbs associated with GPU requests currently - * outstanding. - */ - struct list_head request_list; - /** * We leave the user IRQ off as much as possible, * but this means that requests will finish and never @@ -683,6 +666,9 @@ struct drm_i915_gem_object { */ uint32_t gtt_offset; + /* Which ring is refering to is this object */ + struct intel_ring_buffer *ring; + /** * Fake offset for use by mmap(2) */ @@ -756,6 +742,9 @@ struct drm_i915_gem_object { * an emission time with seqnos for tracking how far ahead of the GPU we are. */ struct drm_i915_gem_request { + /** On Which ring this request was generated */ + struct intel_ring_buffer *ring; + /** GEM sequence number associated with this request. */ uint32_t seqno; @@ -916,11 +905,13 @@ void i915_gem_object_unpin(struct drm_gem_object *obj); int i915_gem_object_unbind(struct drm_gem_object *obj); void i915_gem_release_mmap(struct drm_gem_object *obj); void i915_gem_lastclose(struct drm_device *dev); -uint32_t i915_get_gem_seqno(struct drm_device *dev); +uint32_t i915_get_gem_seqno(struct drm_device *dev, + struct intel_ring_buffer *ring); bool i915_seqno_passed(uint32_t seq1, uint32_t seq2); int i915_gem_object_get_fence_reg(struct drm_gem_object *obj); int i915_gem_object_put_fence_reg(struct drm_gem_object *obj); -void i915_gem_retire_requests(struct drm_device *dev); +void i915_gem_retire_requests(struct drm_device *dev, + struct intel_ring_buffer *ring); void i915_gem_retire_work_handler(struct work_struct *work); void i915_gem_clflush_object(struct drm_gem_object *obj); int i915_gem_object_set_domain(struct drm_gem_object *obj, @@ -931,9 +922,13 @@ void i915_gem_cleanup_ringbuffer(struct drm_device *dev); int i915_gem_do_init(struct drm_device *dev, unsigned long start, unsigned long end); int i915_gem_idle(struct drm_device *dev); -uint32_t i915_add_request(struct drm_device *dev, struct drm_file *file_priv, - uint32_t flush_domains); -int i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptible); +uint32_t i915_add_request(struct drm_device *dev, + struct drm_file *file_priv, + uint32_t flush_domains, + struct intel_ring_buffer *ring); +int i915_do_wait_request(struct drm_device *dev, + uint32_t seqno, int interruptible, + struct intel_ring_buffer *ring); int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 58b6e814fae1..af664ba923c5 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1482,11 +1482,14 @@ i915_gem_object_put_pages(struct drm_gem_object *obj) } static void -i915_gem_object_move_to_active(struct drm_gem_object *obj, uint32_t seqno) +i915_gem_object_move_to_active(struct drm_gem_object *obj, uint32_t seqno, + struct intel_ring_buffer *ring) { struct drm_device *dev = obj->dev; drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); + BUG_ON(ring == NULL); + obj_priv->ring = ring; /* Add a reference if we're newly entering the active list. */ if (!obj_priv->active) { @@ -1495,8 +1498,7 @@ i915_gem_object_move_to_active(struct drm_gem_object *obj, uint32_t seqno) } /* Move from whatever list we were on to the tail of execution. */ spin_lock(&dev_priv->mm.active_list_lock); - list_move_tail(&obj_priv->list, - &dev_priv->mm.active_list); + list_move_tail(&obj_priv->list, &ring->active_list); spin_unlock(&dev_priv->mm.active_list_lock); obj_priv->last_rendering_seqno = seqno; } @@ -1549,6 +1551,7 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj) BUG_ON(!list_empty(&obj_priv->gpu_write_list)); obj_priv->last_rendering_seqno = 0; + obj_priv->ring = NULL; if (obj_priv->active) { obj_priv->active = 0; drm_gem_object_unreference(obj); @@ -1558,7 +1561,8 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj) static void i915_gem_process_flushing_list(struct drm_device *dev, - uint32_t flush_domains, uint32_t seqno) + uint32_t flush_domains, uint32_t seqno, + struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv, *next; @@ -1569,12 +1573,13 @@ i915_gem_process_flushing_list(struct drm_device *dev, struct drm_gem_object *obj = &obj_priv->base; if ((obj->write_domain & flush_domains) == - obj->write_domain) { + obj->write_domain && + obj_priv->ring->ring_flag == ring->ring_flag) { uint32_t old_write_domain = obj->write_domain; obj->write_domain = 0; list_del_init(&obj_priv->gpu_write_list); - i915_gem_object_move_to_active(obj, seqno); + i915_gem_object_move_to_active(obj, seqno, ring); /* update the fence lru list */ if (obj_priv->fence_reg != I915_FENCE_REG_NONE) { @@ -1593,7 +1598,7 @@ i915_gem_process_flushing_list(struct drm_device *dev, uint32_t i915_add_request(struct drm_device *dev, struct drm_file *file_priv, - uint32_t flush_domains) + uint32_t flush_domains, struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_file_private *i915_file_priv = NULL; @@ -1608,15 +1613,14 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv, if (request == NULL) return 0; - seqno = dev_priv->render_ring.add_request(dev, &dev_priv->render_ring, - file_priv, flush_domains); - - DRM_DEBUG_DRIVER("%d\n", seqno); + seqno = ring->add_request(dev, ring, file_priv, flush_domains); request->seqno = seqno; + request->ring = ring; request->emitted_jiffies = jiffies; - was_empty = list_empty(&dev_priv->mm.request_list); - list_add_tail(&request->list, &dev_priv->mm.request_list); + was_empty = list_empty(&ring->request_list); + list_add_tail(&request->list, &ring->request_list); + if (i915_file_priv) { list_add_tail(&request->client_list, &i915_file_priv->mm.request_list); @@ -1628,7 +1632,7 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv, * domain we're flushing with our flush. */ if (flush_domains != 0) - i915_gem_process_flushing_list(dev, flush_domains, seqno); + i915_gem_process_flushing_list(dev, flush_domains, seqno, ring); if (!dev_priv->mm.suspended) { mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD); @@ -1645,18 +1649,16 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv, * before signalling the CPU */ static uint32_t -i915_retire_commands(struct drm_device *dev) +i915_retire_commands(struct drm_device *dev, struct intel_ring_buffer *ring) { - uint32_t cmd = MI_FLUSH | MI_NO_WRITE_FLUSH; uint32_t flush_domains = 0; /* The sampler always gets flushed on i965 (sigh) */ if (IS_I965G(dev)) flush_domains |= I915_GEM_DOMAIN_SAMPLER; - BEGIN_LP_RING(2); - OUT_RING(cmd); - OUT_RING(0); /* noop */ - ADVANCE_LP_RING(); + + ring->flush(dev, ring, + I915_GEM_DOMAIN_COMMAND, flush_domains); return flush_domains; } @@ -1676,11 +1678,11 @@ i915_gem_retire_request(struct drm_device *dev, * by the ringbuffer to the flushing/inactive lists as appropriate. */ spin_lock(&dev_priv->mm.active_list_lock); - while (!list_empty(&dev_priv->mm.active_list)) { + while (!list_empty(&request->ring->active_list)) { struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; - obj_priv = list_first_entry(&dev_priv->mm.active_list, + obj_priv = list_first_entry(&request->ring->active_list, struct drm_i915_gem_object, list); obj = &obj_priv->base; @@ -1727,37 +1729,33 @@ i915_seqno_passed(uint32_t seq1, uint32_t seq2) } uint32_t -i915_get_gem_seqno(struct drm_device *dev) +i915_get_gem_seqno(struct drm_device *dev, + struct intel_ring_buffer *ring) { - drm_i915_private_t *dev_priv = dev->dev_private; - - if (HAS_PIPE_CONTROL(dev)) - return ((volatile u32 *)(dev_priv->seqno_page))[0]; - else - return READ_HWSP(dev_priv, I915_GEM_HWS_INDEX); + return ring->get_gem_seqno(dev, ring); } /** * This function clears the request list as sequence numbers are passed. */ void -i915_gem_retire_requests(struct drm_device *dev) +i915_gem_retire_requests(struct drm_device *dev, + struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; uint32_t seqno; - struct intel_ring_buffer *ring = &(dev_priv->render_ring); if (!ring->status_page.page_addr - || list_empty(&dev_priv->mm.request_list)) + || list_empty(&ring->request_list)) return; - seqno = i915_get_gem_seqno(dev); + seqno = i915_get_gem_seqno(dev, ring); - while (!list_empty(&dev_priv->mm.request_list)) { + while (!list_empty(&ring->request_list)) { struct drm_i915_gem_request *request; uint32_t retiring_seqno; - request = list_first_entry(&dev_priv->mm.request_list, + request = list_first_entry(&ring->request_list, struct drm_i915_gem_request, list); retiring_seqno = request->seqno; @@ -1792,27 +1790,28 @@ i915_gem_retire_work_handler(struct work_struct *work) dev = dev_priv->dev; mutex_lock(&dev->struct_mutex); - i915_gem_retire_requests(dev); + i915_gem_retire_requests(dev, &dev_priv->render_ring); + if (!dev_priv->mm.suspended && - !list_empty(&dev_priv->mm.request_list)) + (!list_empty(&dev_priv->render_ring.request_list))) queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ); mutex_unlock(&dev->struct_mutex); } int -i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptible) +i915_do_wait_request(struct drm_device *dev, uint32_t seqno, + int interruptible, struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; u32 ier; int ret = 0; - struct intel_ring_buffer *ring = &dev_priv->render_ring; BUG_ON(seqno == 0); if (atomic_read(&dev_priv->mm.wedged)) return -EIO; - if (!i915_seqno_passed(i915_get_gem_seqno(dev), seqno)) { + if (!i915_seqno_passed(ring->get_gem_seqno(dev, ring), seqno)) { if (HAS_PCH_SPLIT(dev)) ier = I915_READ(DEIER) | I915_READ(GTIER); else @@ -1826,19 +1825,21 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptible) trace_i915_gem_request_wait_begin(dev, seqno); - dev_priv->mm.waiting_gem_seqno = seqno; + ring->waiting_gem_seqno = seqno; ring->user_irq_get(dev, ring); if (interruptible) - ret = wait_event_interruptible(dev_priv->irq_queue, - i915_seqno_passed(i915_get_gem_seqno(dev), seqno) || - atomic_read(&dev_priv->mm.wedged)); + ret = wait_event_interruptible(ring->irq_queue, + i915_seqno_passed( + ring->get_gem_seqno(dev, ring), seqno) + || atomic_read(&dev_priv->mm.wedged)); else - wait_event(dev_priv->irq_queue, - i915_seqno_passed(i915_get_gem_seqno(dev), seqno) || - atomic_read(&dev_priv->mm.wedged)); + wait_event(ring->irq_queue, + i915_seqno_passed( + ring->get_gem_seqno(dev, ring), seqno) + || atomic_read(&dev_priv->mm.wedged)); ring->user_irq_put(dev, ring); - dev_priv->mm.waiting_gem_seqno = 0; + ring->waiting_gem_seqno = 0; trace_i915_gem_request_wait_end(dev, seqno); } @@ -1847,7 +1848,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptible) if (ret && ret != -ERESTARTSYS) DRM_ERROR("%s returns %d (awaiting %d at %d)\n", - __func__, ret, seqno, i915_get_gem_seqno(dev)); + __func__, ret, seqno, ring->get_gem_seqno(dev, ring)); /* Directly dispatch request retiring. While we have the work queue * to handle this, the waiter on a request often wants an associated @@ -1855,7 +1856,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptible) * a separate wait queue to handle that. */ if (ret == 0) - i915_gem_retire_requests(dev); + i915_gem_retire_requests(dev, ring); return ret; } @@ -1865,12 +1866,12 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptible) * request and object lists appropriately for that event. */ static int -i915_wait_request(struct drm_device *dev, uint32_t seqno) +i915_wait_request(struct drm_device *dev, uint32_t seqno, + struct intel_ring_buffer *ring) { - return i915_do_wait_request(dev, seqno, 1); + return i915_do_wait_request(dev, seqno, 1, ring); } - static void i915_gem_flush(struct drm_device *dev, uint32_t invalidate_domains, @@ -1884,6 +1885,19 @@ i915_gem_flush(struct drm_device *dev, flush_domains); } +static void +i915_gem_flush_ring(struct drm_device *dev, + uint32_t invalidate_domains, + uint32_t flush_domains, + struct intel_ring_buffer *ring) +{ + if (flush_domains & I915_GEM_DOMAIN_CPU) + drm_agp_chipset_flush(dev); + ring->flush(dev, ring, + invalidate_domains, + flush_domains); +} + /** * Ensures that all rendering to the object has completed and the object is * safe to unbind from the GTT or access from the CPU. @@ -1908,7 +1922,8 @@ i915_gem_object_wait_rendering(struct drm_gem_object *obj) DRM_INFO("%s: object %p wait for seqno %08x\n", __func__, obj, obj_priv->last_rendering_seqno); #endif - ret = i915_wait_request(dev, obj_priv->last_rendering_seqno); + ret = i915_wait_request(dev, + obj_priv->last_rendering_seqno, obj_priv->ring); if (ret != 0) return ret; } @@ -2025,10 +2040,11 @@ i915_gpu_idle(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; bool lists_empty; uint32_t seqno; + int ret; spin_lock(&dev_priv->mm.active_list_lock); lists_empty = list_empty(&dev_priv->mm.flushing_list) && - list_empty(&dev_priv->mm.active_list); + list_empty(&dev_priv->render_ring.active_list); spin_unlock(&dev_priv->mm.active_list_lock); if (lists_empty) @@ -2036,11 +2052,13 @@ i915_gpu_idle(struct drm_device *dev) /* Flush everything onto the inactive list. */ i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); - seqno = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS); + seqno = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS, + &dev_priv->render_ring); if (seqno == 0) return -ENOMEM; + ret = i915_wait_request(dev, seqno, &dev_priv->render_ring); - return i915_wait_request(dev, seqno); + return ret; } static int @@ -2053,7 +2071,7 @@ i915_gem_evict_everything(struct drm_device *dev) spin_lock(&dev_priv->mm.active_list_lock); lists_empty = (list_empty(&dev_priv->mm.inactive_list) && list_empty(&dev_priv->mm.flushing_list) && - list_empty(&dev_priv->mm.active_list)); + list_empty(&dev_priv->render_ring.active_list)); spin_unlock(&dev_priv->mm.active_list_lock); if (lists_empty) @@ -2073,7 +2091,7 @@ i915_gem_evict_everything(struct drm_device *dev) spin_lock(&dev_priv->mm.active_list_lock); lists_empty = (list_empty(&dev_priv->mm.inactive_list) && list_empty(&dev_priv->mm.flushing_list) && - list_empty(&dev_priv->mm.active_list)); + list_empty(&dev_priv->render_ring.active_list)); spin_unlock(&dev_priv->mm.active_list_lock); BUG_ON(!lists_empty); @@ -2087,8 +2105,9 @@ i915_gem_evict_something(struct drm_device *dev, int min_size) struct drm_gem_object *obj; int ret; + struct intel_ring_buffer *render_ring = &dev_priv->render_ring; for (;;) { - i915_gem_retire_requests(dev); + i915_gem_retire_requests(dev, render_ring); /* If there's an inactive buffer available now, grab it * and be done. @@ -2112,14 +2131,15 @@ i915_gem_evict_something(struct drm_device *dev, int min_size) * things, wait for the next to finish and hopefully leave us * a buffer to evict. */ - if (!list_empty(&dev_priv->mm.request_list)) { + if (!list_empty(&render_ring->request_list)) { struct drm_i915_gem_request *request; - request = list_first_entry(&dev_priv->mm.request_list, + request = list_first_entry(&render_ring->request_list, struct drm_i915_gem_request, list); - ret = i915_wait_request(dev, request->seqno); + ret = i915_wait_request(dev, + request->seqno, request->ring); if (ret) return ret; @@ -2146,10 +2166,13 @@ i915_gem_evict_something(struct drm_device *dev, int min_size) if (obj != NULL) { uint32_t seqno; - i915_gem_flush(dev, + i915_gem_flush_ring(dev, + obj->write_domain, obj->write_domain, - obj->write_domain); - seqno = i915_add_request(dev, NULL, obj->write_domain); + obj_priv->ring); + seqno = i915_add_request(dev, NULL, + obj->write_domain, + obj_priv->ring); if (seqno == 0) return -ENOMEM; continue; @@ -2685,6 +2708,7 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; uint32_t old_write_domain; + struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); if ((obj->write_domain & I915_GEM_GPU_DOMAINS) == 0) return; @@ -2692,7 +2716,7 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj) /* Queue the GPU write cache flushing we need. */ old_write_domain = obj->write_domain; i915_gem_flush(dev, 0, obj->write_domain); - (void) i915_add_request(dev, NULL, obj->write_domain); + (void) i915_add_request(dev, NULL, obj->write_domain, obj_priv->ring); BUG_ON(obj->write_domain); trace_i915_gem_object_change_domain(obj, @@ -2832,7 +2856,10 @@ i915_gem_object_set_to_display_plane(struct drm_gem_object *obj) DRM_INFO("%s: object %p wait for seqno %08x\n", __func__, obj, obj_priv->last_rendering_seqno); #endif - ret = i915_do_wait_request(dev, obj_priv->last_rendering_seqno, 0); + ret = i915_do_wait_request(dev, + obj_priv->last_rendering_seqno, + 0, + obj_priv->ring); if (ret != 0) return ret; } @@ -3451,7 +3478,7 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file_priv) if (time_after_eq(request->emitted_jiffies, recent_enough)) break; - ret = i915_wait_request(dev, request->seqno); + ret = i915_wait_request(dev, request->seqno, request->ring); if (ret != 0) break; } @@ -3608,6 +3635,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, uint32_t seqno, flush_domains, reloc_index; int pin_tries, flips; + struct intel_ring_buffer *ring = NULL; + #if WATCH_EXEC DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n", (int) args->buffers_ptr, args->buffer_count, args->batch_len); @@ -3665,6 +3694,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto pre_mutex_err; } + ring = &dev_priv->render_ring; + /* Look up object handles */ flips = 0; for (i = 0; i < args->buffer_count; i++) { @@ -3798,9 +3829,12 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, i915_gem_flush(dev, dev->invalidate_domains, dev->flush_domains); - if (dev->flush_domains & I915_GEM_GPU_DOMAINS) + if (dev->flush_domains & I915_GEM_GPU_DOMAINS) { (void)i915_add_request(dev, file_priv, - dev->flush_domains); + dev->flush_domains, + &dev_priv->render_ring); + + } } for (i = 0; i < args->buffer_count; i++) { @@ -3837,11 +3871,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, #endif /* Exec the batchbuffer */ - ret = dev_priv->render_ring.dispatch_gem_execbuffer(dev, - &dev_priv->render_ring, - args, - cliprects, - exec_offset); + ret = ring->dispatch_gem_execbuffer(dev, ring, args, + cliprects, exec_offset); if (ret) { DRM_ERROR("dispatch failed %d\n", ret); goto err; @@ -3851,7 +3882,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, * Ensure that the commands in the batch buffer are * finished before the interrupt fires */ - flush_domains = i915_retire_commands(dev); + flush_domains = i915_retire_commands(dev, ring); i915_verify_inactive(dev, __FILE__, __LINE__); @@ -3862,12 +3893,13 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, * *some* interrupts representing completion of buffers that we can * wait on when trying to clear up gtt space). */ - seqno = i915_add_request(dev, file_priv, flush_domains); + seqno = i915_add_request(dev, file_priv, flush_domains, ring); BUG_ON(seqno == 0); for (i = 0; i < args->buffer_count; i++) { struct drm_gem_object *obj = object_list[i]; + obj_priv = to_intel_bo(obj); - i915_gem_object_move_to_active(obj, seqno); + i915_gem_object_move_to_active(obj, seqno, ring); #if WATCH_LRU DRM_INFO("%s: move to exec list %p\n", __func__, obj); #endif @@ -3979,7 +4011,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, exec2.DR4 = args->DR4; exec2.num_cliprects = args->num_cliprects; exec2.cliprects_ptr = args->cliprects_ptr; - exec2.flags = 0; + exec2.flags = I915_EXEC_RENDER; ret = i915_gem_do_execbuffer(dev, data, file_priv, &exec2, exec2_list); if (!ret) { @@ -4218,6 +4250,7 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, struct drm_i915_gem_busy *args = data; struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; + drm_i915_private_t *dev_priv = dev->dev_private; obj = drm_gem_object_lookup(dev, file_priv, args->handle); if (obj == NULL) { @@ -4232,7 +4265,7 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, * actually unmasked, and our working set ends up being larger than * required. */ - i915_gem_retire_requests(dev); + i915_gem_retire_requests(dev, &dev_priv->render_ring); obj_priv = to_intel_bo(obj); /* Don't count being on the flushing list against the object being @@ -4555,12 +4588,12 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data, } spin_lock(&dev_priv->mm.active_list_lock); - BUG_ON(!list_empty(&dev_priv->mm.active_list)); + BUG_ON(!list_empty(&dev_priv->render_ring.active_list)); spin_unlock(&dev_priv->mm.active_list_lock); BUG_ON(!list_empty(&dev_priv->mm.flushing_list)); BUG_ON(!list_empty(&dev_priv->mm.inactive_list)); - BUG_ON(!list_empty(&dev_priv->mm.request_list)); + BUG_ON(!list_empty(&dev_priv->render_ring.request_list)); mutex_unlock(&dev->struct_mutex); drm_irq_install(dev); @@ -4599,18 +4632,16 @@ i915_gem_load(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; spin_lock_init(&dev_priv->mm.active_list_lock); - INIT_LIST_HEAD(&dev_priv->mm.active_list); INIT_LIST_HEAD(&dev_priv->mm.flushing_list); INIT_LIST_HEAD(&dev_priv->mm.gpu_write_list); INIT_LIST_HEAD(&dev_priv->mm.inactive_list); - INIT_LIST_HEAD(&dev_priv->mm.request_list); INIT_LIST_HEAD(&dev_priv->mm.fence_list); + INIT_LIST_HEAD(&dev_priv->render_ring.active_list); + INIT_LIST_HEAD(&dev_priv->render_ring.request_list); for (i = 0; i < 16; i++) INIT_LIST_HEAD(&dev_priv->fence_regs[i].lru_list); INIT_DELAYED_WORK(&dev_priv->mm.retire_work, i915_gem_retire_work_handler); - dev_priv->mm.next_gem_seqno = 1; - spin_lock(&shrink_list_lock); list_add(&dev_priv->mm.shrink_list, &shrink_list); spin_unlock(&shrink_list_lock); @@ -4842,7 +4873,7 @@ i915_gpu_is_active(struct drm_device *dev) spin_lock(&dev_priv->mm.active_list_lock); lists_empty = list_empty(&dev_priv->mm.flushing_list) && - list_empty(&dev_priv->mm.active_list); + list_empty(&dev_priv->render_ring.active_list); spin_unlock(&dev_priv->mm.active_list_lock); return !lists_empty; @@ -4887,8 +4918,7 @@ rescan: continue; spin_unlock(&shrink_list_lock); - - i915_gem_retire_requests(dev); + i915_gem_retire_requests(dev, &dev_priv->render_ring); list_for_each_entry_safe(obj_priv, next_obj, &dev_priv->mm.inactive_list, diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index e07c643c8365..8a667f1db75a 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -331,6 +331,7 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev) int ret = IRQ_NONE; u32 de_iir, gt_iir, de_ier, pch_iir; struct drm_i915_master_private *master_priv; + struct intel_ring_buffer *render_ring = &dev_priv->render_ring; /* disable master interrupt before clearing iir */ de_ier = I915_READ(DEIER); @@ -354,10 +355,10 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev) } if (gt_iir & GT_PIPE_NOTIFY) { - u32 seqno = i915_get_gem_seqno(dev); - dev_priv->mm.irq_gem_seqno = seqno; + u32 seqno = render_ring->get_gem_seqno(dev, render_ring); + render_ring->irq_gem_seqno = seqno; trace_i915_gem_request_complete(dev, seqno); - DRM_WAKEUP(&dev_priv->irq_queue); + DRM_WAKEUP(&dev_priv->render_ring.irq_queue); dev_priv->hangcheck_count = 0; mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD); } @@ -588,7 +589,7 @@ static void i915_capture_error_state(struct drm_device *dev) return; } - error->seqno = i915_get_gem_seqno(dev); + error->seqno = i915_get_gem_seqno(dev, &dev_priv->render_ring); error->eir = I915_READ(EIR); error->pgtbl_er = I915_READ(PGTBL_ER); error->pipeastat = I915_READ(PIPEASTAT); @@ -616,7 +617,9 @@ static void i915_capture_error_state(struct drm_device *dev) batchbuffer[0] = NULL; batchbuffer[1] = NULL; count = 0; - list_for_each_entry(obj_priv, &dev_priv->mm.active_list, list) { + list_for_each_entry(obj_priv, + &dev_priv->render_ring.active_list, list) { + struct drm_gem_object *obj = &obj_priv->base; if (batchbuffer[0] == NULL && @@ -653,7 +656,8 @@ static void i915_capture_error_state(struct drm_device *dev) if (error->active_bo) { int i = 0; - list_for_each_entry(obj_priv, &dev_priv->mm.active_list, list) { + list_for_each_entry(obj_priv, + &dev_priv->render_ring.active_list, list) { struct drm_gem_object *obj = &obj_priv->base; error->active_bo[i].size = obj->size; @@ -831,7 +835,7 @@ static void i915_handle_error(struct drm_device *dev, bool wedged) /* * Wakeup waiting processes so they don't hang */ - DRM_WAKEUP(&dev_priv->irq_queue); + DRM_WAKEUP(&dev_priv->render_ring.irq_queue); } queue_work(dev_priv->wq, &dev_priv->error_work); @@ -850,6 +854,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) unsigned long irqflags; int irq_received; int ret = IRQ_NONE; + struct intel_ring_buffer *render_ring = &dev_priv->render_ring; atomic_inc(&dev_priv->irq_received); @@ -930,10 +935,11 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) } if (iir & I915_USER_INTERRUPT) { - u32 seqno = i915_get_gem_seqno(dev); - dev_priv->mm.irq_gem_seqno = seqno; + u32 seqno = + render_ring->get_gem_seqno(dev, render_ring); + render_ring->irq_gem_seqno = seqno; trace_i915_gem_request_complete(dev, seqno); - DRM_WAKEUP(&dev_priv->irq_queue); + DRM_WAKEUP(&dev_priv->render_ring.irq_queue); dev_priv->hangcheck_count = 0; mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD); } @@ -1038,7 +1044,7 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; render_ring->user_irq_get(dev, render_ring); - DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ, + DRM_WAIT_ON(ret, dev_priv->render_ring.irq_queue, 3 * DRM_HZ, READ_BREADCRUMB(dev_priv) >= irq_nr); render_ring->user_irq_put(dev, render_ring); @@ -1205,9 +1211,12 @@ int i915_vblank_swap(struct drm_device *dev, void *data, return -EINVAL; } -struct drm_i915_gem_request *i915_get_tail_request(struct drm_device *dev) { +struct drm_i915_gem_request * +i915_get_tail_request(struct drm_device *dev) +{ drm_i915_private_t *dev_priv = dev->dev_private; - return list_entry(dev_priv->mm.request_list.prev, struct drm_i915_gem_request, list); + return list_entry(dev_priv->render_ring.request_list.prev, + struct drm_i915_gem_request, list); } /** @@ -1232,8 +1241,10 @@ void i915_hangcheck_elapsed(unsigned long data) acthd = I915_READ(ACTHD_I965); /* If all work is done then ACTHD clearly hasn't advanced. */ - if (list_empty(&dev_priv->mm.request_list) || - i915_seqno_passed(i915_get_gem_seqno(dev), i915_get_tail_request(dev)->seqno)) { + if (list_empty(&dev_priv->render_ring.request_list) || + i915_seqno_passed(i915_get_gem_seqno(dev, + &dev_priv->render_ring), + i915_get_tail_request(dev)->seqno)) { dev_priv->hangcheck_count = 0; return; } @@ -1300,7 +1311,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev) (void) I915_READ(DEIER); /* user interrupt should be enabled, but masked initial */ - dev_priv->gt_irq_mask_reg = 0xffffffff; + dev_priv->gt_irq_mask_reg = ~render_mask; dev_priv->gt_irq_enable_reg = render_mask; I915_WRITE(GTIIR, I915_READ(GTIIR)); @@ -1363,7 +1374,7 @@ int i915_driver_irq_postinstall(struct drm_device *dev) u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR; u32 error_mask; - DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); + DRM_INIT_WAITQUEUE(&dev_priv->render_ring.irq_queue); dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 93da83782e5e..d7ad5139d17c 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -212,6 +212,7 @@ static int intel_overlay_on(struct intel_overlay *overlay) { struct drm_device *dev = overlay->dev; int ret; + drm_i915_private_t *dev_priv = dev->dev_private; BUG_ON(overlay->active); @@ -225,11 +226,13 @@ static int intel_overlay_on(struct intel_overlay *overlay) OUT_RING(MI_NOOP); ADVANCE_LP_RING(); - overlay->last_flip_req = i915_add_request(dev, NULL, 0); + overlay->last_flip_req = + i915_add_request(dev, NULL, 0, &dev_priv->render_ring); if (overlay->last_flip_req == 0) return -ENOMEM; - ret = i915_do_wait_request(dev, overlay->last_flip_req, 1); + ret = i915_do_wait_request(dev, + overlay->last_flip_req, 1, &dev_priv->render_ring); if (ret != 0) return ret; @@ -262,7 +265,8 @@ static void intel_overlay_continue(struct intel_overlay *overlay, OUT_RING(flip_addr); ADVANCE_LP_RING(); - overlay->last_flip_req = i915_add_request(dev, NULL, 0); + overlay->last_flip_req = + i915_add_request(dev, NULL, 0, &dev_priv->render_ring); } static int intel_overlay_wait_flip(struct intel_overlay *overlay) @@ -273,7 +277,8 @@ static int intel_overlay_wait_flip(struct intel_overlay *overlay) u32 tmp; if (overlay->last_flip_req != 0) { - ret = i915_do_wait_request(dev, overlay->last_flip_req, 1); + ret = i915_do_wait_request(dev, overlay->last_flip_req, + 1, &dev_priv->render_ring); if (ret == 0) { overlay->last_flip_req = 0; @@ -292,11 +297,13 @@ static int intel_overlay_wait_flip(struct intel_overlay *overlay) OUT_RING(MI_NOOP); ADVANCE_LP_RING(); - overlay->last_flip_req = i915_add_request(dev, NULL, 0); + overlay->last_flip_req = + i915_add_request(dev, NULL, 0, &dev_priv->render_ring); if (overlay->last_flip_req == 0) return -ENOMEM; - ret = i915_do_wait_request(dev, overlay->last_flip_req, 1); + ret = i915_do_wait_request(dev, overlay->last_flip_req, + 1, &dev_priv->render_ring); if (ret != 0) return ret; @@ -310,6 +317,7 @@ static int intel_overlay_off(struct intel_overlay *overlay) { u32 flip_addr = overlay->flip_addr; struct drm_device *dev = overlay->dev; + drm_i915_private_t *dev_priv = dev->dev_private; int ret; BUG_ON(!overlay->active); @@ -330,11 +338,13 @@ static int intel_overlay_off(struct intel_overlay *overlay) OUT_RING(MI_NOOP); ADVANCE_LP_RING(); - overlay->last_flip_req = i915_add_request(dev, NULL, 0); + overlay->last_flip_req = + i915_add_request(dev, NULL, 0, &dev_priv->render_ring); if (overlay->last_flip_req == 0) return -ENOMEM; - ret = i915_do_wait_request(dev, overlay->last_flip_req, 1); + ret = i915_do_wait_request(dev, overlay->last_flip_req, + 1, &dev_priv->render_ring); if (ret != 0) return ret; @@ -348,11 +358,13 @@ static int intel_overlay_off(struct intel_overlay *overlay) OUT_RING(MI_NOOP); ADVANCE_LP_RING(); - overlay->last_flip_req = i915_add_request(dev, NULL, 0); + overlay->last_flip_req = + i915_add_request(dev, NULL, 0, &dev_priv->render_ring); if (overlay->last_flip_req == 0) return -ENOMEM; - ret = i915_do_wait_request(dev, overlay->last_flip_req, 1); + ret = i915_do_wait_request(dev, overlay->last_flip_req, + 1, &dev_priv->render_ring); if (ret != 0) return ret; @@ -385,6 +397,7 @@ int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, { struct drm_device *dev = overlay->dev; struct drm_gem_object *obj; + drm_i915_private_t *dev_priv = dev->dev_private; u32 flip_addr; int ret; @@ -392,12 +405,14 @@ int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, return -EIO; if (overlay->last_flip_req == 0) { - overlay->last_flip_req = i915_add_request(dev, NULL, 0); + overlay->last_flip_req = + i915_add_request(dev, NULL, 0, &dev_priv->render_ring); if (overlay->last_flip_req == 0) return -ENOMEM; } - ret = i915_do_wait_request(dev, overlay->last_flip_req, interruptible); + ret = i915_do_wait_request(dev, overlay->last_flip_req, + interruptible, &dev_priv->render_ring); if (ret != 0) return ret; @@ -421,12 +436,13 @@ int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, OUT_RING(MI_NOOP); ADVANCE_LP_RING(); - overlay->last_flip_req = i915_add_request(dev, NULL, 0); + overlay->last_flip_req = i915_add_request(dev, NULL, + 0, &dev_priv->render_ring); if (overlay->last_flip_req == 0) return -ENOMEM; ret = i915_do_wait_request(dev, overlay->last_flip_req, - interruptible); + interruptible, &dev_priv->render_ring); if (ret != 0) return ret; -- cgit v1.2.3 From d1b851fc0d105caa6b6e3e7c92d2987dfb52cbe0 Mon Sep 17 00:00:00 2001 From: Zou Nan hai Date: Fri, 21 May 2010 09:08:57 +0800 Subject: drm/i915: implement BSD ring buffer V2 The BSD (bit stream decoder) ring is used for accessing the BSD engine which decodes video bitstream for H.264 and VC1 on G45+. It is asynchronous with the render ring and has access to separate parts of the GPU from it, though the render cache is coherent between the two. Signed-off-by: Zou Nan hai Signed-off-by: Xiang Hai hao Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_dma.c | 2 + drivers/gpu/drm/i915/i915_drv.h | 2 + drivers/gpu/drm/i915/i915_gem.c | 107 +++++++++++++++++++--- drivers/gpu/drm/i915/i915_irq.c | 13 ++- drivers/gpu/drm/i915/i915_reg.h | 14 +++ drivers/gpu/drm/i915/intel_ringbuffer.c | 153 ++++++++++++++++++++++++++++++++ 6 files changed, 276 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index f485880300ce..1dbed700800e 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -130,6 +130,8 @@ static int i915_dma_cleanup(struct drm_device * dev) drm_irq_uninstall(dev); intel_cleanup_ring_buffer(dev, &dev_priv->render_ring); + if (HAS_BSD(dev)) + intel_cleanup_ring_buffer(dev, &dev_priv->bsd_ring); /* Clear the HWS virtual address at teardown */ if (I915_NEED_GFX_HWS(dev)) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 3f35989ba74c..6bc0fc080f2b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -235,6 +235,7 @@ typedef struct drm_i915_private { struct pci_dev *bridge_dev; struct intel_ring_buffer render_ring; + struct intel_ring_buffer bsd_ring; drm_dma_handle_t *status_page_dmah; void *hw_status_page; @@ -1121,6 +1122,7 @@ extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); (dev)->pci_device == 0x2A42 || \ (dev)->pci_device == 0x2E42) +#define HAS_BSD(dev) (IS_IRONLAKE(dev) || IS_G4X(dev)) #define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws) /* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index af664ba923c5..c51495f15718 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1730,7 +1730,7 @@ i915_seqno_passed(uint32_t seq1, uint32_t seq2) uint32_t i915_get_gem_seqno(struct drm_device *dev, - struct intel_ring_buffer *ring) + struct intel_ring_buffer *ring) { return ring->get_gem_seqno(dev, ring); } @@ -1792,8 +1792,13 @@ i915_gem_retire_work_handler(struct work_struct *work) mutex_lock(&dev->struct_mutex); i915_gem_retire_requests(dev, &dev_priv->render_ring); + if (HAS_BSD(dev)) + i915_gem_retire_requests(dev, &dev_priv->bsd_ring); + if (!dev_priv->mm.suspended && - (!list_empty(&dev_priv->render_ring.request_list))) + (!list_empty(&dev_priv->render_ring.request_list) || + (HAS_BSD(dev) && + !list_empty(&dev_priv->bsd_ring.request_list)))) queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ); mutex_unlock(&dev->struct_mutex); } @@ -1883,6 +1888,11 @@ i915_gem_flush(struct drm_device *dev, dev_priv->render_ring.flush(dev, &dev_priv->render_ring, invalidate_domains, flush_domains); + + if (HAS_BSD(dev)) + dev_priv->bsd_ring.flush(dev, &dev_priv->bsd_ring, + invalidate_domains, + flush_domains); } static void @@ -2039,12 +2049,14 @@ i915_gpu_idle(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; bool lists_empty; - uint32_t seqno; + uint32_t seqno1, seqno2; int ret; spin_lock(&dev_priv->mm.active_list_lock); - lists_empty = list_empty(&dev_priv->mm.flushing_list) && - list_empty(&dev_priv->render_ring.active_list); + lists_empty = (list_empty(&dev_priv->mm.flushing_list) && + list_empty(&dev_priv->render_ring.active_list) && + (!HAS_BSD(dev) || + list_empty(&dev_priv->bsd_ring.active_list))); spin_unlock(&dev_priv->mm.active_list_lock); if (lists_empty) @@ -2052,11 +2064,23 @@ i915_gpu_idle(struct drm_device *dev) /* Flush everything onto the inactive list. */ i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); - seqno = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS, + seqno1 = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS, &dev_priv->render_ring); - if (seqno == 0) + if (seqno1 == 0) return -ENOMEM; - ret = i915_wait_request(dev, seqno, &dev_priv->render_ring); + ret = i915_wait_request(dev, seqno1, &dev_priv->render_ring); + + if (HAS_BSD(dev)) { + seqno2 = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS, + &dev_priv->bsd_ring); + if (seqno2 == 0) + return -ENOMEM; + + ret = i915_wait_request(dev, seqno2, &dev_priv->bsd_ring); + if (ret) + return ret; + } + return ret; } @@ -2071,7 +2095,9 @@ i915_gem_evict_everything(struct drm_device *dev) spin_lock(&dev_priv->mm.active_list_lock); lists_empty = (list_empty(&dev_priv->mm.inactive_list) && list_empty(&dev_priv->mm.flushing_list) && - list_empty(&dev_priv->render_ring.active_list)); + list_empty(&dev_priv->render_ring.active_list) && + (!HAS_BSD(dev) + || list_empty(&dev_priv->bsd_ring.active_list))); spin_unlock(&dev_priv->mm.active_list_lock); if (lists_empty) @@ -2091,7 +2117,9 @@ i915_gem_evict_everything(struct drm_device *dev) spin_lock(&dev_priv->mm.active_list_lock); lists_empty = (list_empty(&dev_priv->mm.inactive_list) && list_empty(&dev_priv->mm.flushing_list) && - list_empty(&dev_priv->render_ring.active_list)); + list_empty(&dev_priv->render_ring.active_list) && + (!HAS_BSD(dev) + || list_empty(&dev_priv->bsd_ring.active_list))); spin_unlock(&dev_priv->mm.active_list_lock); BUG_ON(!lists_empty); @@ -2106,9 +2134,13 @@ i915_gem_evict_something(struct drm_device *dev, int min_size) int ret; struct intel_ring_buffer *render_ring = &dev_priv->render_ring; + struct intel_ring_buffer *bsd_ring = &dev_priv->bsd_ring; for (;;) { i915_gem_retire_requests(dev, render_ring); + if (HAS_BSD(dev)) + i915_gem_retire_requests(dev, bsd_ring); + /* If there's an inactive buffer available now, grab it * and be done. */ @@ -2146,6 +2178,21 @@ i915_gem_evict_something(struct drm_device *dev, int min_size) continue; } + if (HAS_BSD(dev) && !list_empty(&bsd_ring->request_list)) { + struct drm_i915_gem_request *request; + + request = list_first_entry(&bsd_ring->request_list, + struct drm_i915_gem_request, + list); + + ret = i915_wait_request(dev, + request->seqno, request->ring); + if (ret) + return ret; + + continue; + } + /* If we didn't have anything on the request list but there * are buffers awaiting a flush, emit one and try again. * When we wait on it, those buffers waiting for that flush @@ -3641,6 +3688,16 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n", (int) args->buffers_ptr, args->buffer_count, args->batch_len); #endif + if (args->flags & I915_EXEC_BSD) { + if (!HAS_BSD(dev)) { + DRM_ERROR("execbuf with wrong flag\n"); + return -EINVAL; + } + ring = &dev_priv->bsd_ring; + } else { + ring = &dev_priv->render_ring; + } + if (args->buffer_count < 1) { DRM_ERROR("execbuf with %d buffers\n", args->buffer_count); @@ -3694,8 +3751,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto pre_mutex_err; } - ring = &dev_priv->render_ring; - /* Look up object handles */ flips = 0; for (i = 0; i < args->buffer_count; i++) { @@ -3834,6 +3889,10 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, dev->flush_domains, &dev_priv->render_ring); + if (HAS_BSD(dev)) + (void)i915_add_request(dev, file_priv, + dev->flush_domains, + &dev_priv->bsd_ring); } } @@ -4267,6 +4326,9 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, */ i915_gem_retire_requests(dev, &dev_priv->render_ring); + if (HAS_BSD(dev)) + i915_gem_retire_requests(dev, &dev_priv->bsd_ring); + obj_priv = to_intel_bo(obj); /* Don't count being on the flushing list against the object being * done. Otherwise, a buffer left on the flushing list but not getting @@ -4433,7 +4495,9 @@ i915_gem_idle(struct drm_device *dev) mutex_lock(&dev->struct_mutex); if (dev_priv->mm.suspended || - dev_priv->render_ring.gem_object == NULL) { + (dev_priv->render_ring.gem_object == NULL) || + (HAS_BSD(dev) && + dev_priv->bsd_ring.gem_object == NULL)) { mutex_unlock(&dev->struct_mutex); return 0; } @@ -4550,6 +4614,10 @@ i915_gem_init_ringbuffer(struct drm_device *dev) return ret; } ret = intel_init_ring_buffer(dev, &dev_priv->render_ring); + if (!ret && HAS_BSD(dev)) { + dev_priv->bsd_ring = bsd_ring; + ret = intel_init_ring_buffer(dev, &dev_priv->bsd_ring); + } return ret; } @@ -4559,6 +4627,8 @@ i915_gem_cleanup_ringbuffer(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; intel_cleanup_ring_buffer(dev, &dev_priv->render_ring); + if (HAS_BSD(dev)) + intel_cleanup_ring_buffer(dev, &dev_priv->bsd_ring); if (HAS_PIPE_CONTROL(dev)) i915_gem_cleanup_pipe_control(dev); } @@ -4589,11 +4659,13 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data, spin_lock(&dev_priv->mm.active_list_lock); BUG_ON(!list_empty(&dev_priv->render_ring.active_list)); + BUG_ON(HAS_BSD(dev) && !list_empty(&dev_priv->bsd_ring.active_list)); spin_unlock(&dev_priv->mm.active_list_lock); BUG_ON(!list_empty(&dev_priv->mm.flushing_list)); BUG_ON(!list_empty(&dev_priv->mm.inactive_list)); BUG_ON(!list_empty(&dev_priv->render_ring.request_list)); + BUG_ON(HAS_BSD(dev) && !list_empty(&dev_priv->bsd_ring.request_list)); mutex_unlock(&dev->struct_mutex); drm_irq_install(dev); @@ -4638,6 +4710,10 @@ i915_gem_load(struct drm_device *dev) INIT_LIST_HEAD(&dev_priv->mm.fence_list); INIT_LIST_HEAD(&dev_priv->render_ring.active_list); INIT_LIST_HEAD(&dev_priv->render_ring.request_list); + if (HAS_BSD(dev)) { + INIT_LIST_HEAD(&dev_priv->bsd_ring.active_list); + INIT_LIST_HEAD(&dev_priv->bsd_ring.request_list); + } for (i = 0; i < 16; i++) INIT_LIST_HEAD(&dev_priv->fence_regs[i].lru_list); INIT_DELAYED_WORK(&dev_priv->mm.retire_work, @@ -4874,6 +4950,8 @@ i915_gpu_is_active(struct drm_device *dev) spin_lock(&dev_priv->mm.active_list_lock); lists_empty = list_empty(&dev_priv->mm.flushing_list) && list_empty(&dev_priv->render_ring.active_list); + if (HAS_BSD(dev)) + lists_empty &= list_empty(&dev_priv->bsd_ring.active_list); spin_unlock(&dev_priv->mm.active_list_lock); return !lists_empty; @@ -4920,6 +4998,9 @@ rescan: spin_unlock(&shrink_list_lock); i915_gem_retire_requests(dev, &dev_priv->render_ring); + if (HAS_BSD(dev)) + i915_gem_retire_requests(dev, &dev_priv->bsd_ring); + list_for_each_entry_safe(obj_priv, next_obj, &dev_priv->mm.inactive_list, list) { diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 8a667f1db75a..0a3a5806a12e 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -53,7 +53,7 @@ I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) /** Interrupts that we mask and unmask at runtime. */ -#define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT) +#define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT | I915_BSD_USER_INTERRUPT) #define I915_PIPE_VBLANK_STATUS (PIPE_START_VBLANK_INTERRUPT_STATUS |\ PIPE_VBLANK_INTERRUPT_STATUS) @@ -362,6 +362,9 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev) dev_priv->hangcheck_count = 0; mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD); } + if (gt_iir & GT_BSD_USER_INTERRUPT) + DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue); + if (de_iir & DE_GSE) ironlake_opregion_gse_intr(dev); @@ -944,6 +947,9 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD); } + if (HAS_BSD(dev) && (iir & I915_BSD_USER_INTERRUPT)) + DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue); + if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) intel_prepare_page_flip(dev, 0); @@ -1297,7 +1303,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev) /* enable kind of interrupts always enabled */ u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT | DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE; - u32 render_mask = GT_PIPE_NOTIFY; + u32 render_mask = GT_PIPE_NOTIFY | GT_BSD_USER_INTERRUPT; u32 hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG | SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG; @@ -1376,6 +1382,9 @@ int i915_driver_irq_postinstall(struct drm_device *dev) DRM_INIT_WAITQUEUE(&dev_priv->render_ring.irq_queue); + if (HAS_BSD(dev)) + DRM_INIT_WAITQUEUE(&dev_priv->bsd_ring.irq_queue); + dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; if (HAS_PCH_SPLIT(dev)) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index f3e39cc46f0d..784cf3c914e9 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -334,6 +334,7 @@ #define I915_DEBUG_INTERRUPT (1<<2) #define I915_USER_INTERRUPT (1<<1) #define I915_ASLE_INTERRUPT (1<<0) +#define I915_BSD_USER_INTERRUPT (1<<25) #define EIR 0x020b0 #define EMR 0x020b4 #define ESR 0x020b8 @@ -368,6 +369,17 @@ #define BB_ADDR 0x02140 /* 8 bytes */ #define GFX_FLSH_CNTL 0x02170 /* 915+ only */ +/* + * BSD (bit stream decoder instruction and interrupt control register defines + * (G4X and Ironlake only) + */ + +#define BSD_RING_TAIL 0x04030 +#define BSD_RING_HEAD 0x04034 +#define BSD_RING_START 0x04038 +#define BSD_RING_CTL 0x0403c +#define BSD_RING_ACTHD 0x04074 +#define BSD_HWS_PGA 0x04080 /* * Framebuffer compression (915+ only) @@ -2355,6 +2367,8 @@ #define GT_PIPE_NOTIFY (1 << 4) #define GT_SYNC_STATUS (1 << 2) #define GT_USER_INTERRUPT (1 << 0) +#define GT_BSD_USER_INTERRUPT (1 << 5) + #define GTISR 0x44010 #define GTIMR 0x44014 diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 5715c4d8cce9..f6b84fe8099a 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -340,6 +340,119 @@ static void render_setup_status_page(struct drm_device *dev, } +void +bsd_ring_flush(struct drm_device *dev, + struct intel_ring_buffer *ring, + u32 invalidate_domains, + u32 flush_domains) +{ + intel_ring_begin(dev, ring, 8); + intel_ring_emit(dev, ring, MI_FLUSH); + intel_ring_emit(dev, ring, MI_NOOP); + intel_ring_advance(dev, ring); +} + +static inline unsigned int bsd_ring_get_head(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + return I915_READ(BSD_RING_HEAD) & HEAD_ADDR; +} + +static inline unsigned int bsd_ring_get_tail(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + return I915_READ(BSD_RING_TAIL) & TAIL_ADDR; +} + +static inline unsigned int bsd_ring_get_active_head(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + return I915_READ(BSD_RING_ACTHD); +} + +static inline void bsd_ring_advance_ring(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + I915_WRITE(BSD_RING_TAIL, ring->tail); +} + +static int init_bsd_ring(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + return init_ring_common(dev, ring); +} + +static u32 +bsd_ring_add_request(struct drm_device *dev, + struct intel_ring_buffer *ring, + struct drm_file *file_priv, + u32 flush_domains) +{ + u32 seqno; + seqno = intel_ring_get_seqno(dev, ring); + intel_ring_begin(dev, ring, 4); + intel_ring_emit(dev, ring, MI_STORE_DWORD_INDEX); + intel_ring_emit(dev, ring, + I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); + intel_ring_emit(dev, ring, seqno); + intel_ring_emit(dev, ring, MI_USER_INTERRUPT); + intel_ring_advance(dev, ring); + + DRM_DEBUG_DRIVER("%s %d\n", ring->name, seqno); + + return seqno; +} + +static void bsd_setup_status_page(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + I915_WRITE(BSD_HWS_PGA, ring->status_page.gfx_addr); + I915_READ(BSD_HWS_PGA); +} + +static void +bsd_ring_get_user_irq(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + /* do nothing */ +} +static void +bsd_ring_put_user_irq(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + /* do nothing */ +} + +static u32 +bsd_ring_get_gem_seqno(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + return intel_read_status_page(ring, I915_GEM_HWS_INDEX); +} + +static int +bsd_ring_dispatch_gem_execbuffer(struct drm_device *dev, + struct intel_ring_buffer *ring, + struct drm_i915_gem_execbuffer2 *exec, + struct drm_clip_rect *cliprects, + uint64_t exec_offset) +{ + uint32_t exec_start; + exec_start = (uint32_t) exec_offset + exec->batch_start_offset; + intel_ring_begin(dev, ring, 2); + intel_ring_emit(dev, ring, MI_BATCH_BUFFER_START | + (2 << 6) | MI_BATCH_NON_SECURE_I965); + intel_ring_emit(dev, ring, exec_start); + intel_ring_advance(dev, ring); + return 0; +} + + static int render_ring_dispatch_gem_execbuffer(struct drm_device *dev, struct intel_ring_buffer *ring, @@ -588,6 +701,7 @@ int intel_wait_ring_buffer(struct drm_device *dev, if (master_priv->sarea_priv) master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; } + yield(); } while (!time_after(jiffies, end)); trace_i915_ring_wait_end (dev); @@ -682,3 +796,42 @@ struct intel_ring_buffer render_ring = { .status_page = {NULL, 0, NULL}, .map = {0,} }; + +/* ring buffer for bit-stream decoder */ + +struct intel_ring_buffer bsd_ring = { + .name = "bsd ring", + .regs = { + .ctl = BSD_RING_CTL, + .head = BSD_RING_HEAD, + .tail = BSD_RING_TAIL, + .start = BSD_RING_START + }, + .ring_flag = I915_EXEC_BSD, + .size = 32 * PAGE_SIZE, + .alignment = PAGE_SIZE, + .virtual_start = NULL, + .dev = NULL, + .gem_object = NULL, + .head = 0, + .tail = 0, + .space = 0, + .next_seqno = 1, + .user_irq_refcount = 0, + .irq_gem_seqno = 0, + .waiting_gem_seqno = 0, + .setup_status_page = bsd_setup_status_page, + .init = init_bsd_ring, + .get_head = bsd_ring_get_head, + .get_tail = bsd_ring_get_tail, + .get_active_head = bsd_ring_get_active_head, + .advance_ring = bsd_ring_advance_ring, + .flush = bsd_ring_flush, + .add_request = bsd_ring_add_request, + .get_gem_seqno = bsd_ring_get_gem_seqno, + .user_irq_get = bsd_ring_get_user_irq, + .user_irq_put = bsd_ring_put_user_irq, + .dispatch_gem_execbuffer = bsd_ring_dispatch_gem_execbuffer, + .status_page = {NULL, 0, NULL}, + .map = {0,} +}; -- cgit v1.2.3 From 9517a92f48b08bb02cfb616825850b82b28461cc Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 21 May 2010 09:40:45 -0700 Subject: drm/i915: add timeout to FBC disable waits FBC disable on 965 can take long enough to trigger latency checks in the kernel so be sure to timeout after a reasonable period. Fixes https://bugzilla.kernel.org/show_bug.cgi?id=15015. Tested-by: James Ettle Signed-off-by: Jesse Barnes Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_display.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b867f3c78408..36afe9409964 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1029,19 +1029,28 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) void i8xx_disable_fbc(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long timeout = jiffies + msecs_to_jiffies(1); u32 fbc_ctl; if (!I915_HAS_FBC(dev)) return; + if (!(I915_READ(FBC_CONTROL) & FBC_CTL_EN)) + return; /* Already off, just return */ + /* Disable compression */ fbc_ctl = I915_READ(FBC_CONTROL); fbc_ctl &= ~FBC_CTL_EN; I915_WRITE(FBC_CONTROL, fbc_ctl); /* Wait for compressing bit to clear */ - while (I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) - ; /* nothing */ + while (I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) { + if (time_after(jiffies, timeout)) { + DRM_DEBUG_DRIVER("FBC idle timed out\n"); + break; + } + ; /* do nothing */ + } intel_wait_for_vblank(dev); -- cgit v1.2.3 From f41275e893191eeb7a88e431d594e167adbd5234 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 24 May 2010 16:25:44 +0800 Subject: drm/i915: Convert more trace events to DEFINE_EVENT Convert i915_gem_object_clflush to DEFINE_EVENT, and save ~0.5K: text data bss dec hex filename 13204 2732 12 15948 3e4c i915_trace_points.o.orig 12668 2732 12 15412 3c34 i915_trace_points.o No change in functionality. Signed-off-by: Li Zefan Acked-by: Steven Rostedt Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_trace.h | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index 9e4c45f68d6e..fab21760dd57 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -53,23 +53,6 @@ TRACE_EVENT(i915_gem_object_bind, __entry->obj, __entry->gtt_offset) ); -TRACE_EVENT(i915_gem_object_clflush, - - TP_PROTO(struct drm_gem_object *obj), - - TP_ARGS(obj), - - TP_STRUCT__entry( - __field(struct drm_gem_object *, obj) - ), - - TP_fast_assign( - __entry->obj = obj; - ), - - TP_printk("obj=%p", __entry->obj) -); - TRACE_EVENT(i915_gem_object_change_domain, TP_PROTO(struct drm_gem_object *obj, uint32_t old_read_domains, uint32_t old_write_domain), @@ -132,6 +115,13 @@ DECLARE_EVENT_CLASS(i915_gem_object, TP_printk("obj=%p", __entry->obj) ); +DEFINE_EVENT(i915_gem_object, i915_gem_object_clflush, + + TP_PROTO(struct drm_gem_object *obj), + + TP_ARGS(obj) +); + DEFINE_EVENT(i915_gem_object, i915_gem_object_unbind, TP_PROTO(struct drm_gem_object *obj), -- cgit v1.2.3 From f953c9353f5fe6e98fa7f32f51060a74d845b5f8 Mon Sep 17 00:00:00 2001 From: Daniel J Blueman Date: Mon, 17 May 2010 14:23:52 +0100 Subject: i915: fix lock imbalance on error path... While investigating Intel i5 Arrandale GPU lockups with -rc4, I noticed a lock imbalance. Signed-off-by: Daniel J Blueman Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_drv.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index d40f62d36453..c072b212979c 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -370,6 +370,7 @@ int i965_reset(struct drm_device *dev, u8 flags) } } else { DRM_ERROR("Error occurred. Don't know how to reset this chip.\n"); + mutex_unlock(&dev->struct_mutex); return -ENODEV; } -- cgit v1.2.3 From 734b4157b367d66405f7dab80085d17c9c8dd3b5 Mon Sep 17 00:00:00 2001 From: Krzysztof Halasa Date: Tue, 25 May 2010 18:41:46 +0200 Subject: drm/i915: Add support for interlaced display. This doesn't change the clock limits (minimums), i.e. it won't make it output 720x576 PAL nor 720x480 NTSC, but it will work with modes like 1080i etc. (including GLX and textured Xvideo, not sure about the overlay). Tested on i915 + analog VGA, it would be worth checking if newer chips (and which ones) still support interlaced mode. Signed-off-by: Krzysztof Halasa Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_crt.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index e16ac5a28c3c..d5c130202396 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -569,7 +569,7 @@ void intel_crt_init(struct drm_device *dev) (1 << INTEL_ANALOG_CLONE_BIT) | (1 << INTEL_SDVO_LVDS_CLONE_BIT); intel_encoder->crtc_mask = (1 << 0) | (1 << 1); - connector->interlace_allowed = 0; + connector->interlace_allowed = 1; connector->doublescan_allowed = 0; drm_encoder_helper_add(&intel_encoder->enc, &intel_crt_helper_funcs); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 36afe9409964..4c7c151114f7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2354,6 +2354,8 @@ static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, if (mode->clock * 3 > 27000 * 4) return MODE_CLOCK_HIGH; } + + drm_mode_set_crtcinfo(adjusted_mode, 0); return true; } @@ -3781,6 +3783,18 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, } } + if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) { + pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION; + /* the chip adds 2 halflines automatically */ + adjusted_mode->crtc_vdisplay -= 1; + adjusted_mode->crtc_vtotal -= 1; + adjusted_mode->crtc_vblank_start -= 1; + adjusted_mode->crtc_vblank_end -= 1; + adjusted_mode->crtc_vsync_end -= 1; + adjusted_mode->crtc_vsync_start -= 1; + } else + pipeconf &= ~PIPECONF_INTERLACE_W_FIELD_INDICATION; /* progressive */ + I915_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) | ((adjusted_mode->crtc_htotal - 1) << 16)); I915_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) | -- cgit v1.2.3 From 7a772c492fcfffae812ffca78a628e76fa57fe58 Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Mon, 24 May 2010 16:46:29 -0400 Subject: drm/i915/gen4: Extra CRT hotplug paranoia Disable the CRT plug interrupt while doing the force cycle, explicitly clear any CRT interrupt we may have generated, and restore when done. Should mitigate interrupt storms from hotplug detection. Signed-off-by: Adam Jackson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_reg.h | 1 - drivers/gpu/drm/i915/intel_crt.c | 21 ++++++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 784cf3c914e9..7a726840efa7 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1067,7 +1067,6 @@ #define CRT_HOTPLUG_DETECT_VOLTAGE_325MV (0 << 2) #define CRT_HOTPLUG_DETECT_VOLTAGE_475MV (1 << 2) #define CRT_HOTPLUG_MASK (0x3fc) /* Bits 9-2 */ -#define CRT_FORCE_HOTPLUG_MASK 0xfffffe1f #define PORT_HOTPLUG_STAT 0x61114 #define HDMIB_HOTPLUG_INT_STATUS (1 << 29) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index d5c130202396..22ff38455731 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -217,7 +217,8 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector) { struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; - u32 hotplug_en; + u32 hotplug_en, orig, stat; + bool ret = false; int i, tries = 0; if (HAS_PCH_SPLIT(dev)) @@ -232,8 +233,8 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector) tries = 2; else tries = 1; - hotplug_en = I915_READ(PORT_HOTPLUG_EN); - hotplug_en &= CRT_FORCE_HOTPLUG_MASK; + hotplug_en = orig = I915_READ(PORT_HOTPLUG_EN); + hotplug_en &= CRT_HOTPLUG_MASK; hotplug_en |= CRT_HOTPLUG_FORCE_DETECT; if (IS_G4X(dev)) @@ -255,11 +256,17 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector) } while (time_after(timeout, jiffies)); } - if ((I915_READ(PORT_HOTPLUG_STAT) & CRT_HOTPLUG_MONITOR_MASK) != - CRT_HOTPLUG_MONITOR_NONE) - return true; + stat = I915_READ(PORT_HOTPLUG_STAT); + if ((stat & CRT_HOTPLUG_MONITOR_MASK) != CRT_HOTPLUG_MONITOR_NONE) + ret = true; + + /* clear the interrupt we just generated, if any */ + I915_WRITE(PORT_HOTPLUG_STAT, CRT_HOTPLUG_INT_STATUS); - return false; + /* and put the bits back */ + I915_WRITE(PORT_HOTPLUG_EN, orig); + + return ret; } static bool intel_crt_detect_ddc(struct drm_encoder *encoder) -- cgit v1.2.3 From 7648fa99eb77a2e1a90b7beaa420e07d819b9c11 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 20 May 2010 14:28:11 -0700 Subject: drm/i915: add power monitoring support Add power monitoring support to the i915 driver for use by the IPS driver. Export the available power info to the IPS driver through a few new inter-driver hooks. When used together, the IPS driver and this patch can significantly increase graphics performance on Ironlake class chips. Signed-off-by: Jesse Barnes [anholt: Fixed 32-bit compile. stupid obfuscating div_u64()] Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_debugfs.c | 56 +++- drivers/gpu/drm/i915/i915_dma.c | 533 ++++++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/i915_drv.h | 20 +- drivers/gpu/drm/i915/i915_irq.c | 28 +- drivers/gpu/drm/i915/i915_reg.h | 41 +++ drivers/gpu/drm/i915/intel_display.c | 147 ++++++++-- 6 files changed, 772 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index c864858d5064..eb11e1e049cb 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -491,11 +491,14 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; u16 rgvswctl = I915_READ16(MEMSWCTL); + u16 rgvstat = I915_READ16(MEMSTAT_ILK); - seq_printf(m, "Last command: 0x%01x\n", (rgvswctl >> 13) & 0x3); - seq_printf(m, "Command status: %d\n", (rgvswctl >> 12) & 1); - seq_printf(m, "P%d DELAY 0x%02x\n", (rgvswctl >> 8) & 0xf, - rgvswctl & 0x3f); + seq_printf(m, "Requested P-state: %d\n", (rgvswctl >> 8) & 0xf); + seq_printf(m, "Requested VID: %d\n", rgvswctl & 0x3f); + seq_printf(m, "Current VID: %d\n", (rgvstat & MEMSTAT_VID_MASK) >> + MEMSTAT_VID_SHIFT); + seq_printf(m, "Current P-state: %d\n", + (rgvstat & MEMSTAT_PSTATE_MASK) >> MEMSTAT_PSTATE_SHIFT); return 0; } @@ -510,7 +513,8 @@ static int i915_delayfreq_table(struct seq_file *m, void *unused) for (i = 0; i < 16; i++) { delayfreq = I915_READ(PXVFREQ_BASE + i * 4); - seq_printf(m, "P%02dVIDFREQ: 0x%08x\n", i, delayfreq); + seq_printf(m, "P%02dVIDFREQ: 0x%08x (VID: %d)\n", i, delayfreq, + (delayfreq & PXVFREQ_PX_MASK) >> PXVFREQ_PX_SHIFT); } return 0; @@ -543,6 +547,8 @@ static int i915_drpc_info(struct seq_file *m, void *unused) struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; u32 rgvmodectl = I915_READ(MEMMODECTL); + u32 rstdbyctl = I915_READ(MCHBAR_RENDER_STANDBY); + u16 crstandvid = I915_READ16(CRSTANDVID); seq_printf(m, "HD boost: %s\n", (rgvmodectl & MEMMODE_BOOST_EN) ? "yes" : "no"); @@ -557,9 +563,13 @@ static int i915_drpc_info(struct seq_file *m, void *unused) rgvmodectl & MEMMODE_RCLK_GATE ? "yes" : "no"); seq_printf(m, "Starting frequency: P%d\n", (rgvmodectl & MEMMODE_FSTART_MASK) >> MEMMODE_FSTART_SHIFT); - seq_printf(m, "Max frequency: P%d\n", + seq_printf(m, "Max P-state: P%d\n", (rgvmodectl & MEMMODE_FMAX_MASK) >> MEMMODE_FMAX_SHIFT); - seq_printf(m, "Min frequency: P%d\n", (rgvmodectl & MEMMODE_FMIN_MASK)); + seq_printf(m, "Min P-state: P%d\n", (rgvmodectl & MEMMODE_FMIN_MASK)); + seq_printf(m, "RS1 VID: %d\n", (crstandvid & 0x3f)); + seq_printf(m, "RS2 VID: %d\n", ((crstandvid >> 8) & 0x3f)); + seq_printf(m, "Render standby enabled: %s\n", + (rstdbyctl & RCX_SW_EXIT) ? "no" : "yes"); return 0; } @@ -623,6 +633,36 @@ static int i915_sr_status(struct seq_file *m, void *unused) return 0; } +static int i915_emon_status(struct seq_file *m, void *unused) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + unsigned long temp, chipset, gfx; + + temp = i915_mch_val(dev_priv); + chipset = i915_chipset_val(dev_priv); + gfx = i915_gfx_val(dev_priv); + + seq_printf(m, "GMCH temp: %ld\n", temp); + seq_printf(m, "Chipset power: %ld\n", chipset); + seq_printf(m, "GFX power: %ld\n", gfx); + seq_printf(m, "Total power: %ld\n", chipset + gfx); + + return 0; +} + +static int i915_gfxec(struct seq_file *m, void *unused) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + + seq_printf(m, "GFXEC: %ld\n", (unsigned long)I915_READ(0x112f4)); + + return 0; +} + static int i915_wedged_open(struct inode *inode, struct file *filp) @@ -745,6 +785,8 @@ static struct drm_info_list i915_debugfs_list[] = { {"i915_delayfreq_table", i915_delayfreq_table, 0}, {"i915_inttoext_table", i915_inttoext_table, 0}, {"i915_drpc_info", i915_drpc_info, 0}, + {"i915_emon_status", i915_emon_status, 0}, + {"i915_gfxec", i915_gfxec, 0}, {"i915_fbc_status", i915_fbc_status, 0}, {"i915_sr_status", i915_sr_status, 0}, }; diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 1dbed700800e..12e92f2cc3a7 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1458,14 +1458,11 @@ void i915_master_destroy(struct drm_device *dev, struct drm_master *master) master->driver_priv = NULL; } -static void i915_get_mem_freq(struct drm_device *dev) +static void i915_pineview_get_mem_freq(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; u32 tmp; - if (!IS_PINEVIEW(dev)) - return; - tmp = I915_READ(CLKCFG); switch (tmp & CLKCFG_FSB_MASK) { @@ -1496,6 +1493,519 @@ static void i915_get_mem_freq(struct drm_device *dev) } } +static void i915_ironlake_get_mem_freq(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + u16 ddrpll, csipll; + + ddrpll = I915_READ16(DDRMPLL1); + csipll = I915_READ16(CSIPLL0); + + switch (ddrpll & 0xff) { + case 0xc: + dev_priv->mem_freq = 800; + break; + case 0x10: + dev_priv->mem_freq = 1066; + break; + case 0x14: + dev_priv->mem_freq = 1333; + break; + case 0x18: + dev_priv->mem_freq = 1600; + break; + default: + DRM_DEBUG_DRIVER("unknown memory frequency 0x%02x\n", + ddrpll & 0xff); + dev_priv->mem_freq = 0; + break; + } + + dev_priv->r_t = dev_priv->mem_freq; + + switch (csipll & 0x3ff) { + case 0x00c: + dev_priv->fsb_freq = 3200; + break; + case 0x00e: + dev_priv->fsb_freq = 3733; + break; + case 0x010: + dev_priv->fsb_freq = 4266; + break; + case 0x012: + dev_priv->fsb_freq = 4800; + break; + case 0x014: + dev_priv->fsb_freq = 5333; + break; + case 0x016: + dev_priv->fsb_freq = 5866; + break; + case 0x018: + dev_priv->fsb_freq = 6400; + break; + default: + DRM_DEBUG_DRIVER("unknown fsb frequency 0x%04x\n", + csipll & 0x3ff); + dev_priv->fsb_freq = 0; + break; + } + + if (dev_priv->fsb_freq == 3200) { + dev_priv->c_m = 0; + } else if (dev_priv->fsb_freq > 3200 && dev_priv->fsb_freq <= 4800) { + dev_priv->c_m = 1; + } else { + dev_priv->c_m = 2; + } +} + +struct v_table { + u8 vid; + unsigned long vd; /* in .1 mil */ + unsigned long vm; /* in .1 mil */ + u8 pvid; +}; + +static struct v_table v_table[] = { + { 0, 16125, 15000, 0x7f, }, + { 1, 16000, 14875, 0x7e, }, + { 2, 15875, 14750, 0x7d, }, + { 3, 15750, 14625, 0x7c, }, + { 4, 15625, 14500, 0x7b, }, + { 5, 15500, 14375, 0x7a, }, + { 6, 15375, 14250, 0x79, }, + { 7, 15250, 14125, 0x78, }, + { 8, 15125, 14000, 0x77, }, + { 9, 15000, 13875, 0x76, }, + { 10, 14875, 13750, 0x75, }, + { 11, 14750, 13625, 0x74, }, + { 12, 14625, 13500, 0x73, }, + { 13, 14500, 13375, 0x72, }, + { 14, 14375, 13250, 0x71, }, + { 15, 14250, 13125, 0x70, }, + { 16, 14125, 13000, 0x6f, }, + { 17, 14000, 12875, 0x6e, }, + { 18, 13875, 12750, 0x6d, }, + { 19, 13750, 12625, 0x6c, }, + { 20, 13625, 12500, 0x6b, }, + { 21, 13500, 12375, 0x6a, }, + { 22, 13375, 12250, 0x69, }, + { 23, 13250, 12125, 0x68, }, + { 24, 13125, 12000, 0x67, }, + { 25, 13000, 11875, 0x66, }, + { 26, 12875, 11750, 0x65, }, + { 27, 12750, 11625, 0x64, }, + { 28, 12625, 11500, 0x63, }, + { 29, 12500, 11375, 0x62, }, + { 30, 12375, 11250, 0x61, }, + { 31, 12250, 11125, 0x60, }, + { 32, 12125, 11000, 0x5f, }, + { 33, 12000, 10875, 0x5e, }, + { 34, 11875, 10750, 0x5d, }, + { 35, 11750, 10625, 0x5c, }, + { 36, 11625, 10500, 0x5b, }, + { 37, 11500, 10375, 0x5a, }, + { 38, 11375, 10250, 0x59, }, + { 39, 11250, 10125, 0x58, }, + { 40, 11125, 10000, 0x57, }, + { 41, 11000, 9875, 0x56, }, + { 42, 10875, 9750, 0x55, }, + { 43, 10750, 9625, 0x54, }, + { 44, 10625, 9500, 0x53, }, + { 45, 10500, 9375, 0x52, }, + { 46, 10375, 9250, 0x51, }, + { 47, 10250, 9125, 0x50, }, + { 48, 10125, 9000, 0x4f, }, + { 49, 10000, 8875, 0x4e, }, + { 50, 9875, 8750, 0x4d, }, + { 51, 9750, 8625, 0x4c, }, + { 52, 9625, 8500, 0x4b, }, + { 53, 9500, 8375, 0x4a, }, + { 54, 9375, 8250, 0x49, }, + { 55, 9250, 8125, 0x48, }, + { 56, 9125, 8000, 0x47, }, + { 57, 9000, 7875, 0x46, }, + { 58, 8875, 7750, 0x45, }, + { 59, 8750, 7625, 0x44, }, + { 60, 8625, 7500, 0x43, }, + { 61, 8500, 7375, 0x42, }, + { 62, 8375, 7250, 0x41, }, + { 63, 8250, 7125, 0x40, }, + { 64, 8125, 7000, 0x3f, }, + { 65, 8000, 6875, 0x3e, }, + { 66, 7875, 6750, 0x3d, }, + { 67, 7750, 6625, 0x3c, }, + { 68, 7625, 6500, 0x3b, }, + { 69, 7500, 6375, 0x3a, }, + { 70, 7375, 6250, 0x39, }, + { 71, 7250, 6125, 0x38, }, + { 72, 7125, 6000, 0x37, }, + { 73, 7000, 5875, 0x36, }, + { 74, 6875, 5750, 0x35, }, + { 75, 6750, 5625, 0x34, }, + { 76, 6625, 5500, 0x33, }, + { 77, 6500, 5375, 0x32, }, + { 78, 6375, 5250, 0x31, }, + { 79, 6250, 5125, 0x30, }, + { 80, 6125, 5000, 0x2f, }, + { 81, 6000, 4875, 0x2e, }, + { 82, 5875, 4750, 0x2d, }, + { 83, 5750, 4625, 0x2c, }, + { 84, 5625, 4500, 0x2b, }, + { 85, 5500, 4375, 0x2a, }, + { 86, 5375, 4250, 0x29, }, + { 87, 5250, 4125, 0x28, }, + { 88, 5125, 4000, 0x27, }, + { 89, 5000, 3875, 0x26, }, + { 90, 4875, 3750, 0x25, }, + { 91, 4750, 3625, 0x24, }, + { 92, 4625, 3500, 0x23, }, + { 93, 4500, 3375, 0x22, }, + { 94, 4375, 3250, 0x21, }, + { 95, 4250, 3125, 0x20, }, + { 96, 4125, 3000, 0x1f, }, + { 97, 4125, 3000, 0x1e, }, + { 98, 4125, 3000, 0x1d, }, + { 99, 4125, 3000, 0x1c, }, + { 100, 4125, 3000, 0x1b, }, + { 101, 4125, 3000, 0x1a, }, + { 102, 4125, 3000, 0x19, }, + { 103, 4125, 3000, 0x18, }, + { 104, 4125, 3000, 0x17, }, + { 105, 4125, 3000, 0x16, }, + { 106, 4125, 3000, 0x15, }, + { 107, 4125, 3000, 0x14, }, + { 108, 4125, 3000, 0x13, }, + { 109, 4125, 3000, 0x12, }, + { 110, 4125, 3000, 0x11, }, + { 111, 4125, 3000, 0x10, }, + { 112, 4125, 3000, 0x0f, }, + { 113, 4125, 3000, 0x0e, }, + { 114, 4125, 3000, 0x0d, }, + { 115, 4125, 3000, 0x0c, }, + { 116, 4125, 3000, 0x0b, }, + { 117, 4125, 3000, 0x0a, }, + { 118, 4125, 3000, 0x09, }, + { 119, 4125, 3000, 0x08, }, + { 120, 1125, 0, 0x07, }, + { 121, 1000, 0, 0x06, }, + { 122, 875, 0, 0x05, }, + { 123, 750, 0, 0x04, }, + { 124, 625, 0, 0x03, }, + { 125, 500, 0, 0x02, }, + { 126, 375, 0, 0x01, }, + { 127, 0, 0, 0x00, }, +}; + +struct cparams { + int i; + int t; + int m; + int c; +}; + +static struct cparams cparams[] = { + { 1, 1333, 301, 28664 }, + { 1, 1066, 294, 24460 }, + { 1, 800, 294, 25192 }, + { 0, 1333, 276, 27605 }, + { 0, 1066, 276, 27605 }, + { 0, 800, 231, 23784 }, +}; + +unsigned long i915_chipset_val(struct drm_i915_private *dev_priv) +{ + u64 total_count, diff, ret; + u32 count1, count2, count3, m = 0, c = 0; + unsigned long now = jiffies_to_msecs(jiffies), diff1; + int i; + + diff1 = now - dev_priv->last_time1; + + count1 = I915_READ(DMIEC); + count2 = I915_READ(DDREC); + count3 = I915_READ(CSIEC); + + total_count = count1 + count2 + count3; + + /* FIXME: handle per-counter overflow */ + if (total_count < dev_priv->last_count1) { + diff = ~0UL - dev_priv->last_count1; + diff += total_count; + } else { + diff = total_count - dev_priv->last_count1; + } + + for (i = 0; i < ARRAY_SIZE(cparams); i++) { + if (cparams[i].i == dev_priv->c_m && + cparams[i].t == dev_priv->r_t) { + m = cparams[i].m; + c = cparams[i].c; + break; + } + } + + div_u64(diff, diff1); + ret = ((m * diff) + c); + div_u64(ret, 10); + + dev_priv->last_count1 = total_count; + dev_priv->last_time1 = now; + + return ret; +} + +unsigned long i915_mch_val(struct drm_i915_private *dev_priv) +{ + unsigned long m, x, b; + u32 tsfs; + + tsfs = I915_READ(TSFS); + + m = ((tsfs & TSFS_SLOPE_MASK) >> TSFS_SLOPE_SHIFT); + x = I915_READ8(TR1); + + b = tsfs & TSFS_INTR_MASK; + + return ((m * x) / 127) - b; +} + +static unsigned long pvid_to_extvid(struct drm_i915_private *dev_priv, u8 pxvid) +{ + unsigned long val = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(v_table); i++) { + if (v_table[i].pvid == pxvid) { + if (IS_MOBILE(dev_priv->dev)) + val = v_table[i].vm; + else + val = v_table[i].vd; + } + } + + return val; +} + +void i915_update_gfx_val(struct drm_i915_private *dev_priv) +{ + struct timespec now, diff1; + u64 diff; + unsigned long diffms; + u32 count; + + getrawmonotonic(&now); + diff1 = timespec_sub(now, dev_priv->last_time2); + + /* Don't divide by 0 */ + diffms = diff1.tv_sec * 1000 + diff1.tv_nsec / 1000000; + if (!diffms) + return; + + count = I915_READ(GFXEC); + + if (count < dev_priv->last_count2) { + diff = ~0UL - dev_priv->last_count2; + diff += count; + } else { + diff = count - dev_priv->last_count2; + } + + dev_priv->last_count2 = count; + dev_priv->last_time2 = now; + + /* More magic constants... */ + diff = diff * 1181; + div_u64(diff, diffms * 10); + dev_priv->gfx_power = diff; +} + +unsigned long i915_gfx_val(struct drm_i915_private *dev_priv) +{ + unsigned long t, corr, state1, corr2, state2; + u32 pxvid, ext_v; + + pxvid = I915_READ(PXVFREQ_BASE + (dev_priv->cur_delay * 4)); + pxvid = (pxvid >> 24) & 0x7f; + ext_v = pvid_to_extvid(dev_priv, pxvid); + + state1 = ext_v; + + t = i915_mch_val(dev_priv); + + /* Revel in the empirically derived constants */ + + /* Correction factor in 1/100000 units */ + if (t > 80) + corr = ((t * 2349) + 135940); + else if (t >= 50) + corr = ((t * 964) + 29317); + else /* < 50 */ + corr = ((t * 301) + 1004); + + corr = corr * ((150142 * state1) / 10000 - 78642); + corr /= 100000; + corr2 = (corr * dev_priv->corr); + + state2 = (corr2 * state1) / 10000; + state2 /= 100; /* convert to mW */ + + i915_update_gfx_val(dev_priv); + + return dev_priv->gfx_power + state2; +} + +/* Global for IPS driver to get at the current i915 device */ +static struct drm_i915_private *i915_mch_dev; +/* + * Lock protecting IPS related data structures + * - i915_mch_dev + * - dev_priv->max_delay + * - dev_priv->min_delay + * - dev_priv->fmax + * - dev_priv->gpu_busy + */ +DEFINE_SPINLOCK(mchdev_lock); + +/** + * i915_read_mch_val - return value for IPS use + * + * Calculate and return a value for the IPS driver to use when deciding whether + * we have thermal and power headroom to increase CPU or GPU power budget. + */ +unsigned long i915_read_mch_val(void) +{ + struct drm_i915_private *dev_priv; + unsigned long chipset_val, graphics_val, ret = 0; + + spin_lock(&mchdev_lock); + if (!i915_mch_dev) + goto out_unlock; + dev_priv = i915_mch_dev; + + chipset_val = i915_chipset_val(dev_priv); + graphics_val = i915_gfx_val(dev_priv); + + ret = chipset_val + graphics_val; + +out_unlock: + spin_unlock(&mchdev_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(i915_read_mch_val); + +/** + * i915_gpu_raise - raise GPU frequency limit + * + * Raise the limit; IPS indicates we have thermal headroom. + */ +bool i915_gpu_raise(void) +{ + struct drm_i915_private *dev_priv; + bool ret = true; + + spin_lock(&mchdev_lock); + if (!i915_mch_dev) { + ret = false; + goto out_unlock; + } + dev_priv = i915_mch_dev; + + if (dev_priv->max_delay > dev_priv->fmax) + dev_priv->max_delay--; + +out_unlock: + spin_unlock(&mchdev_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(i915_gpu_raise); + +/** + * i915_gpu_lower - lower GPU frequency limit + * + * IPS indicates we're close to a thermal limit, so throttle back the GPU + * frequency maximum. + */ +bool i915_gpu_lower(void) +{ + struct drm_i915_private *dev_priv; + bool ret = true; + + spin_lock(&mchdev_lock); + if (!i915_mch_dev) { + ret = false; + goto out_unlock; + } + dev_priv = i915_mch_dev; + + if (dev_priv->max_delay < dev_priv->min_delay) + dev_priv->max_delay++; + +out_unlock: + spin_unlock(&mchdev_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(i915_gpu_lower); + +/** + * i915_gpu_busy - indicate GPU business to IPS + * + * Tell the IPS driver whether or not the GPU is busy. + */ +bool i915_gpu_busy(void) +{ + struct drm_i915_private *dev_priv; + bool ret = false; + + spin_lock(&mchdev_lock); + if (!i915_mch_dev) + goto out_unlock; + dev_priv = i915_mch_dev; + + ret = dev_priv->busy; + +out_unlock: + spin_unlock(&mchdev_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(i915_gpu_busy); + +/** + * i915_gpu_turbo_disable - disable graphics turbo + * + * Disable graphics turbo by resetting the max frequency and setting the + * current frequency to the default. + */ +bool i915_gpu_turbo_disable(void) +{ + struct drm_i915_private *dev_priv; + bool ret = true; + + spin_lock(&mchdev_lock); + if (!i915_mch_dev) { + ret = false; + goto out_unlock; + } + dev_priv = i915_mch_dev; + + dev_priv->max_delay = dev_priv->fstart; + + if (!ironlake_set_drps(dev_priv->dev, dev_priv->fstart)) + ret = false; + +out_unlock: + spin_unlock(&mchdev_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(i915_gpu_turbo_disable); + /** * i915_driver_load - setup chip and create an initial config * @dev: DRM device @@ -1616,7 +2126,10 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) goto out_workqueue_free; } - i915_get_mem_freq(dev); + if (IS_PINEVIEW(dev)) + i915_pineview_get_mem_freq(dev); + else if (IS_IRONLAKE(dev)) + i915_ironlake_get_mem_freq(dev); /* On the 945G/GM, the chipset reports the MSI capability on the * integrated graphics even though the support isn't actually there @@ -1662,6 +2175,12 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) setup_timer(&dev_priv->hangcheck_timer, i915_hangcheck_elapsed, (unsigned long) dev); + + spin_lock(&mchdev_lock); + i915_mch_dev = dev_priv; + dev_priv->mchdev_lock = &mchdev_lock; + spin_unlock(&mchdev_lock); + return 0; out_workqueue_free: @@ -1683,6 +2202,10 @@ int i915_driver_unload(struct drm_device *dev) i915_destroy_error_state(dev); + spin_lock(&mchdev_lock); + i915_mch_dev = NULL; + spin_unlock(&mchdev_lock); + destroy_workqueue(dev_priv->wq); del_timer_sync(&dev_priv->hangcheck_timer); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6bc0fc080f2b..91b3a1c20ef8 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -619,6 +619,18 @@ typedef struct drm_i915_private { u8 cur_delay; u8 min_delay; u8 max_delay; + u8 fmax; + u8 fstart; + + u64 last_count1; + unsigned long last_time1; + u64 last_count2; + struct timespec last_time2; + unsigned long gfx_power; + int c_m; + int r_t; + u8 corr; + spinlock_t *mchdev_lock; enum no_fbc_reason no_fbc_reason; @@ -802,6 +814,11 @@ extern int i915_emit_box(struct drm_device *dev, struct drm_clip_rect *boxes, int i, int DR1, int DR4); extern int i965_reset(struct drm_device *dev, u8 flags); +extern unsigned long i915_chipset_val(struct drm_i915_private *dev_priv); +extern unsigned long i915_mch_val(struct drm_i915_private *dev_priv); +extern unsigned long i915_gfx_val(struct drm_i915_private *dev_priv); +extern void i915_update_gfx_val(struct drm_i915_private *dev_priv); + /* i915_irq.c */ void i915_hangcheck_elapsed(unsigned long data); @@ -1005,7 +1022,7 @@ extern void g4x_disable_fbc(struct drm_device *dev); extern void intel_disable_fbc(struct drm_device *dev); extern void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval); extern bool intel_fbc_enabled(struct drm_device *dev); - +extern bool ironlake_set_drps(struct drm_device *dev, u8 val); extern void intel_detect_pch (struct drm_device *dev); extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); @@ -1030,6 +1047,7 @@ extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); #define I915_WRITE64(reg, val) writeq(val, dev_priv->regs + (reg)) #define I915_READ64(reg) readq(dev_priv->regs + (reg)) #define POSTING_READ(reg) (void)I915_READ(reg) +#define POSTING_READ16(reg) (void)I915_READ16(reg) #define I915_VERBOSE 0 diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 0a3a5806a12e..b5dba4795f6f 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -278,10 +278,9 @@ static void i915_handle_rps_change(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; u32 busy_up, busy_down, max_avg, min_avg; - u16 rgvswctl; u8 new_delay = dev_priv->cur_delay; - I915_WRITE(MEMINTRSTS, I915_READ(MEMINTRSTS) & ~MEMINT_EVAL_CHG); + I915_WRITE16(MEMINTRSTS, MEMINT_EVAL_CHG); busy_up = I915_READ(RCPREVBSYTUPAVG); busy_down = I915_READ(RCPREVBSYTDNAVG); max_avg = I915_READ(RCBMAXAVG); @@ -300,27 +299,8 @@ static void i915_handle_rps_change(struct drm_device *dev) new_delay = dev_priv->min_delay; } - DRM_DEBUG("rps change requested: %d -> %d\n", - dev_priv->cur_delay, new_delay); - - rgvswctl = I915_READ(MEMSWCTL); - if (rgvswctl & MEMCTL_CMD_STS) { - DRM_ERROR("gpu busy, RCS change rejected\n"); - return; /* still busy with another command */ - } - - /* Program the new state */ - rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) | - (new_delay << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM; - I915_WRITE(MEMSWCTL, rgvswctl); - POSTING_READ(MEMSWCTL); - - rgvswctl |= MEMCTL_CMD_STS; - I915_WRITE(MEMSWCTL, rgvswctl); - - dev_priv->cur_delay = new_delay; - - DRM_DEBUG("rps changed\n"); + if (ironlake_set_drps(dev, new_delay)) + dev_priv->cur_delay = new_delay; return; } @@ -392,7 +372,7 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev) } if (de_iir & DE_PCU_EVENT) { - I915_WRITE(MEMINTRSTS, I915_READ(MEMINTRSTS)); + I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS)); i915_handle_rps_change(dev); } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 7a726840efa7..df7224de0aed 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -838,6 +838,12 @@ #define CLKCFG_MEM_800 (3 << 4) #define CLKCFG_MEM_MASK (7 << 4) +#define TR1 0x11006 +#define TSFS 0x11020 +#define TSFS_SLOPE_MASK 0x0000ff00 +#define TSFS_SLOPE_SHIFT 8 +#define TSFS_INTR_MASK 0x000000ff + #define CRSTANDVID 0x11100 #define PXVFREQ_BASE 0x11110 /* P[0-15]VIDFREQ (0x1114c) (Ironlake) */ #define PXVFREQ_PX_MASK 0x7f000000 @@ -976,6 +982,41 @@ #define MEMSTAT_SRC_CTL_STDBY 3 #define RCPREVBSYTUPAVG 0x113b8 #define RCPREVBSYTDNAVG 0x113bc +#define SDEW 0x1124c +#define CSIEW0 0x11250 +#define CSIEW1 0x11254 +#define CSIEW2 0x11258 +#define PEW 0x1125c +#define DEW 0x11270 +#define MCHAFE 0x112c0 +#define CSIEC 0x112e0 +#define DMIEC 0x112e4 +#define DDREC 0x112e8 +#define PEG0EC 0x112ec +#define PEG1EC 0x112f0 +#define GFXEC 0x112f4 +#define RPPREVBSYTUPAVG 0x113b8 +#define RPPREVBSYTDNAVG 0x113bc +#define ECR 0x11600 +#define ECR_GPFE (1<<31) +#define ECR_IMONE (1<<30) +#define ECR_CAP_MASK 0x0000001f /* Event range, 0-31 */ +#define OGW0 0x11608 +#define OGW1 0x1160c +#define EG0 0x11610 +#define EG1 0x11614 +#define EG2 0x11618 +#define EG3 0x1161c +#define EG4 0x11620 +#define EG5 0x11624 +#define EG6 0x11628 +#define EG7 0x1162c +#define PXW 0x11664 +#define PXWL 0x11680 +#define LCFUSE02 0x116c0 +#define LCFUSE_HIV_MASK 0x000000ff +#define CSIPLL0 0x12c10 +#define DDRMPLL1 0X12c20 #define PEG_BAND_GAP_DATA 0x14d68 /* diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4c7c151114f7..e94d1db35364 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4459,6 +4459,8 @@ static void intel_idle_update(struct work_struct *work) mutex_lock(&dev->struct_mutex); + i915_update_gfx_val(dev_priv); + if (IS_I945G(dev) || IS_I945GM(dev)) { DRM_DEBUG_DRIVER("enable memory self refresh on 945\n"); I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN_MASK | FW_BLC_SELF_EN); @@ -5045,10 +5047,32 @@ err_unref: return NULL; } +bool ironlake_set_drps(struct drm_device *dev, u8 val) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u16 rgvswctl; + + rgvswctl = I915_READ16(MEMSWCTL); + if (rgvswctl & MEMCTL_CMD_STS) { + DRM_DEBUG("gpu busy, RCS change rejected\n"); + return false; /* still busy with another command */ + } + + rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) | + (val << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM; + I915_WRITE16(MEMSWCTL, rgvswctl); + POSTING_READ16(MEMSWCTL); + + rgvswctl |= MEMCTL_CMD_STS; + I915_WRITE16(MEMSWCTL, rgvswctl); + + return true; +} + void ironlake_enable_drps(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - u32 rgvmodectl = I915_READ(MEMMODECTL), rgvswctl; + u32 rgvmodectl = I915_READ(MEMMODECTL); u8 fmax, fmin, fstart, vstart; int i = 0; @@ -5067,13 +5091,21 @@ void ironlake_enable_drps(struct drm_device *dev) fmin = (rgvmodectl & MEMMODE_FMIN_MASK); fstart = (rgvmodectl & MEMMODE_FSTART_MASK) >> MEMMODE_FSTART_SHIFT; + fstart = fmax; + vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >> PXVFREQ_PX_SHIFT; - dev_priv->max_delay = fstart; /* can't go to fmax w/o IPS */ + dev_priv->fmax = fstart; /* IPS callback will increase this */ + dev_priv->fstart = fstart; + + dev_priv->max_delay = fmax; dev_priv->min_delay = fmin; dev_priv->cur_delay = fstart; + DRM_DEBUG_DRIVER("fmax: %d, fmin: %d, fstart: %d\n", fmax, fmin, + fstart); + I915_WRITE(MEMINTREN, MEMINT_CX_SUPR_EN | MEMINT_EVAL_CHG_EN); /* @@ -5095,20 +5127,19 @@ void ironlake_enable_drps(struct drm_device *dev) } msleep(1); - rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) | - (fstart << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM; - I915_WRITE(MEMSWCTL, rgvswctl); - POSTING_READ(MEMSWCTL); + ironlake_set_drps(dev, fstart); - rgvswctl |= MEMCTL_CMD_STS; - I915_WRITE(MEMSWCTL, rgvswctl); + dev_priv->last_count1 = I915_READ(0x112e4) + I915_READ(0x112e8) + + I915_READ(0x112e0); + dev_priv->last_time1 = jiffies_to_msecs(jiffies); + dev_priv->last_count2 = I915_READ(0x112f4); + getrawmonotonic(&dev_priv->last_time2); } void ironlake_disable_drps(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - u32 rgvswctl; - u8 fstart; + u16 rgvswctl = I915_READ16(MEMSWCTL); /* Ack interrupts, disable EFC interrupt */ I915_WRITE(MEMINTREN, I915_READ(MEMINTREN) & ~MEMINT_EVAL_CHG_EN); @@ -5118,11 +5149,7 @@ void ironlake_disable_drps(struct drm_device *dev) I915_WRITE(DEIMR, I915_READ(DEIMR) | DE_PCU_EVENT); /* Go back to the starting frequency */ - fstart = (I915_READ(MEMMODECTL) & MEMMODE_FSTART_MASK) >> - MEMMODE_FSTART_SHIFT; - rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) | - (fstart << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM; - I915_WRITE(MEMSWCTL, rgvswctl); + ironlake_set_drps(dev, dev_priv->fstart); msleep(1); rgvswctl |= MEMCTL_CMD_STS; I915_WRITE(MEMSWCTL, rgvswctl); @@ -5130,6 +5157,92 @@ void ironlake_disable_drps(struct drm_device *dev) } +static unsigned long intel_pxfreq(u32 vidfreq) +{ + unsigned long freq; + int div = (vidfreq & 0x3f0000) >> 16; + int post = (vidfreq & 0x3000) >> 12; + int pre = (vidfreq & 0x7); + + if (!pre) + return 0; + + freq = ((div * 133333) / ((1<dev_private; + u32 lcfuse; + u8 pxw[16]; + int i; + + /* Disable to program */ + I915_WRITE(ECR, 0); + POSTING_READ(ECR); + + /* Program energy weights for various events */ + I915_WRITE(SDEW, 0x15040d00); + I915_WRITE(CSIEW0, 0x007f0000); + I915_WRITE(CSIEW1, 0x1e220004); + I915_WRITE(CSIEW2, 0x04000004); + + for (i = 0; i < 5; i++) + I915_WRITE(PEW + (i * 4), 0); + for (i = 0; i < 3; i++) + I915_WRITE(DEW + (i * 4), 0); + + /* Program P-state weights to account for frequency power adjustment */ + for (i = 0; i < 16; i++) { + u32 pxvidfreq = I915_READ(PXVFREQ_BASE + (i * 4)); + unsigned long freq = intel_pxfreq(pxvidfreq); + unsigned long vid = (pxvidfreq & PXVFREQ_PX_MASK) >> + PXVFREQ_PX_SHIFT; + unsigned long val; + + val = vid * vid; + val *= (freq / 1000); + val *= 255; + val /= (127*127*900); + if (val > 0xff) + DRM_ERROR("bad pxval: %ld\n", val); + pxw[i] = val; + } + /* Render standby states get 0 weight */ + pxw[14] = 0; + pxw[15] = 0; + + for (i = 0; i < 4; i++) { + u32 val = (pxw[i*4] << 24) | (pxw[(i*4)+1] << 16) | + (pxw[(i*4)+2] << 8) | (pxw[(i*4)+3]); + I915_WRITE(PXW + (i * 4), val); + } + + /* Adjust magic regs to magic values (more experimental results) */ + I915_WRITE(OGW0, 0); + I915_WRITE(OGW1, 0); + I915_WRITE(EG0, 0x00007f00); + I915_WRITE(EG1, 0x0000000e); + I915_WRITE(EG2, 0x000e0000); + I915_WRITE(EG3, 0x68000300); + I915_WRITE(EG4, 0x42000000); + I915_WRITE(EG5, 0x00140031); + I915_WRITE(EG6, 0); + I915_WRITE(EG7, 0); + + for (i = 0; i < 8; i++) + I915_WRITE(PXWL + (i * 4), 0); + + /* Enable PMON + select events */ + I915_WRITE(ECR, 0x80000019); + + lcfuse = I915_READ(LCFUSE02); + + dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK); +} + void intel_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -5376,8 +5489,10 @@ void intel_modeset_init(struct drm_device *dev) intel_init_clock_gating(dev); - if (IS_IRONLAKE_M(dev)) + if (IS_IRONLAKE_M(dev)) { ironlake_enable_drps(dev); + intel_init_emon(dev); + } INIT_WORK(&dev_priv->idle_work, intel_idle_update); setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer, -- cgit v1.2.3 From 9a7e8492d17394a81d5534abf90b5b2ada7ea3c0 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Thu, 20 May 2010 10:33:46 +0200 Subject: drm/i915: Storage class should be before const qualifier The C99 specification states in section 6.11.5: The placement of a storage-class specifier other than at the beginning of the declaration specifiers in a declaration is an obsolescent feature. Signed-off-by: Tobias Klauser Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_drv.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index c072b212979c..423dc90c1e20 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -60,95 +60,95 @@ extern int intel_agp_enabled; .subdevice = PCI_ANY_ID, \ .driver_data = (unsigned long) info } -const static struct intel_device_info intel_i830_info = { +static const struct intel_device_info intel_i830_info = { .is_i8xx = 1, .is_mobile = 1, .cursor_needs_physical = 1, }; -const static struct intel_device_info intel_845g_info = { +static const struct intel_device_info intel_845g_info = { .is_i8xx = 1, }; -const static struct intel_device_info intel_i85x_info = { +static const struct intel_device_info intel_i85x_info = { .is_i8xx = 1, .is_i85x = 1, .is_mobile = 1, .cursor_needs_physical = 1, }; -const static struct intel_device_info intel_i865g_info = { +static const struct intel_device_info intel_i865g_info = { .is_i8xx = 1, }; -const static struct intel_device_info intel_i915g_info = { +static const struct intel_device_info intel_i915g_info = { .is_i915g = 1, .is_i9xx = 1, .cursor_needs_physical = 1, }; -const static struct intel_device_info intel_i915gm_info = { +static const struct intel_device_info intel_i915gm_info = { .is_i9xx = 1, .is_mobile = 1, .cursor_needs_physical = 1, }; -const static struct intel_device_info intel_i945g_info = { +static const struct intel_device_info intel_i945g_info = { .is_i9xx = 1, .has_hotplug = 1, .cursor_needs_physical = 1, }; -const static struct intel_device_info intel_i945gm_info = { +static const struct intel_device_info intel_i945gm_info = { .is_i945gm = 1, .is_i9xx = 1, .is_mobile = 1, .has_hotplug = 1, .cursor_needs_physical = 1, }; -const static struct intel_device_info intel_i965g_info = { +static const struct intel_device_info intel_i965g_info = { .is_i965g = 1, .is_i9xx = 1, .has_hotplug = 1, }; -const static struct intel_device_info intel_i965gm_info = { +static const struct intel_device_info intel_i965gm_info = { .is_i965g = 1, .is_mobile = 1, .is_i965gm = 1, .is_i9xx = 1, .is_mobile = 1, .has_fbc = 1, .has_rc6 = 1, .has_hotplug = 1, }; -const static struct intel_device_info intel_g33_info = { +static const struct intel_device_info intel_g33_info = { .is_g33 = 1, .is_i9xx = 1, .need_gfx_hws = 1, .has_hotplug = 1, }; -const static struct intel_device_info intel_g45_info = { +static const struct intel_device_info intel_g45_info = { .is_i965g = 1, .is_g4x = 1, .is_i9xx = 1, .need_gfx_hws = 1, .has_pipe_cxsr = 1, .has_hotplug = 1, }; -const static struct intel_device_info intel_gm45_info = { +static const struct intel_device_info intel_gm45_info = { .is_i965g = 1, .is_mobile = 1, .is_g4x = 1, .is_i9xx = 1, .is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1, .has_pipe_cxsr = 1, .has_hotplug = 1, }; -const static struct intel_device_info intel_pineview_info = { +static const struct intel_device_info intel_pineview_info = { .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .is_i9xx = 1, .need_gfx_hws = 1, .has_hotplug = 1, }; -const static struct intel_device_info intel_ironlake_d_info = { +static const struct intel_device_info intel_ironlake_d_info = { .is_ironlake = 1, .is_i965g = 1, .is_i9xx = 1, .need_gfx_hws = 1, .has_pipe_cxsr = 1, .has_hotplug = 1, }; -const static struct intel_device_info intel_ironlake_m_info = { +static const struct intel_device_info intel_ironlake_m_info = { .is_ironlake = 1, .is_mobile = 1, .is_i965g = 1, .is_i9xx = 1, .need_gfx_hws = 1, .has_rc6 = 1, .has_hotplug = 1, }; -const static struct intel_device_info intel_sandybridge_d_info = { +static const struct intel_device_info intel_sandybridge_d_info = { .is_i965g = 1, .is_i9xx = 1, .need_gfx_hws = 1, .has_hotplug = 1, .is_gen6 = 1, }; -const static struct intel_device_info intel_sandybridge_m_info = { +static const struct intel_device_info intel_sandybridge_m_info = { .is_i965g = 1, .is_mobile = 1, .is_i9xx = 1, .need_gfx_hws = 1, .has_hotplug = 1, .is_gen6 = 1, }; -const static struct pci_device_id pciidlist[] = { +static const struct pci_device_id pciidlist[] = { INTEL_VGA_DEVICE(0x3577, &intel_i830_info), INTEL_VGA_DEVICE(0x2562, &intel_845g_info), INTEL_VGA_DEVICE(0x3582, &intel_i85x_info), -- cgit v1.2.3 From f1befe71fa7a79ab733011b045639d8d809924ad Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 18 May 2010 12:24:51 +0100 Subject: agp/intel: Restrict GTT mapping to valid range on i915 and i945 References: Bug 15733 - Crash when accessing nonexistent GTT entries in i915 https://bugzilla.kernel.org/show_bug.cgi?id=15733 On G33 and above, the size of the GTT space is determined by the GMCH control register. Prior to this revision, the size is determined by the size of the aperture. So we must careful to map and fill the appropriate range depending on chipset. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/char/agp/intel-gtt.c | 46 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index e8ea6825822c..9344216183a4 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -1059,7 +1059,7 @@ static void intel_i9xx_setup_flush(void) } } -static int intel_i915_configure(void) +static int intel_i9xx_configure(void) { struct aper_size_info_fixed *current_size; u32 temp; @@ -1207,6 +1207,38 @@ static int intel_i9xx_fetch_size(void) return 0; } +static int intel_i915_get_gtt_size(void) +{ + int size; + + if (IS_G33) { + u16 gmch_ctrl; + + /* G33's GTT size defined in gmch_ctrl */ + pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl); + switch (gmch_ctrl & G33_PGETBL_SIZE_MASK) { + case G33_PGETBL_SIZE_1M: + size = 1024; + break; + case G33_PGETBL_SIZE_2M: + size = 2048; + break; + default: + dev_info(&agp_bridge->dev->dev, + "unknown page table size 0x%x, assuming 512KB\n", + (gmch_ctrl & G33_PGETBL_SIZE_MASK)); + size = 512; + } + } else { + /* On previous hardware, the GTT size was just what was + * required to map the aperture. + */ + size = agp_bridge->driver->fetch_size(); + } + + return KB(size); +} + /* The intel i915 automatically initializes the agp aperture during POST. * Use the memory already set aside for in the GTT. */ @@ -1216,7 +1248,7 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) struct aper_size_info_fixed *size; int num_entries; u32 temp, temp2; - int gtt_map_size = 256 * 1024; + int gtt_map_size; size = agp_bridge->current_size; page_order = size->page_order; @@ -1226,8 +1258,8 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp); pci_read_config_dword(intel_private.pcidev, I915_PTEADDR, &temp2); - if (IS_G33) - gtt_map_size = 1024 * 1024; /* 1M on G33 */ + gtt_map_size = intel_i915_get_gtt_size(); + intel_private.gtt = ioremap(temp2, gtt_map_size); if (!intel_private.gtt) return -ENOMEM; @@ -1422,7 +1454,7 @@ static const struct agp_bridge_driver intel_915_driver = { .size_type = FIXED_APER_SIZE, .num_aperture_sizes = 4, .needs_scratch_page = true, - .configure = intel_i915_configure, + .configure = intel_i9xx_configure, .fetch_size = intel_i9xx_fetch_size, .cleanup = intel_i915_cleanup, .mask_memory = intel_i810_mask_memory, @@ -1455,7 +1487,7 @@ static const struct agp_bridge_driver intel_i965_driver = { .size_type = FIXED_APER_SIZE, .num_aperture_sizes = 4, .needs_scratch_page = true, - .configure = intel_i915_configure, + .configure = intel_i9xx_configure, .fetch_size = intel_i9xx_fetch_size, .cleanup = intel_i915_cleanup, .mask_memory = intel_i965_mask_memory, @@ -1488,7 +1520,7 @@ static const struct agp_bridge_driver intel_g33_driver = { .size_type = FIXED_APER_SIZE, .num_aperture_sizes = 4, .needs_scratch_page = true, - .configure = intel_i915_configure, + .configure = intel_i9xx_configure, .fetch_size = intel_i9xx_fetch_size, .cleanup = intel_i915_cleanup, .mask_memory = intel_i965_mask_memory, -- cgit v1.2.3 From 9908ff736adf261e749b4887486a32ffa209304c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 15 May 2010 09:57:03 +0100 Subject: drm/i915: Kill dangerous pending-flip debugging We can, by virtue of a vblank interrupt firing in the middle of setting up the unpin work (i.e. after we set the unpin_work field and before we write to the ringbuffer) enter intel_finish_page_flip() prior to receiving the pending flip notification. Therefore we can expect to hit intel_finish_page_flip() under normal circumstances without a pending flip and even without installing the pending_flip_obj. This is exacerbated by aperture thrashing whilst binding the framebuffer References: Bug 28079 - "glresize" causes kernel panic in intel_finish_page_flip. https://bugs.freedesktop.org/show_bug.cgi?id=28079 Reported-by: Nick Bowler Signed-off-by: Chris Wilson Cc: Jesse Barnes Cc: stable@kernel.org Reviewed-by: Jesse Barnes Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_display.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e94d1db35364..f946332612ec 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4589,12 +4589,6 @@ void intel_finish_page_flip(struct drm_device *dev, int pipe) spin_lock_irqsave(&dev->event_lock, flags); work = intel_crtc->unpin_work; if (work == NULL || !work->pending) { - if (work && !work->pending) { - obj_priv = to_intel_bo(work->pending_flip_obj); - DRM_DEBUG_DRIVER("flip finish: %p (%d) not pending?\n", - obj_priv, - atomic_read(&obj_priv->pending_flip)); - } spin_unlock_irqrestore(&dev->event_lock, flags); return; } -- cgit v1.2.3 From 9962c9252e46eda7058067cbe73bdf1ed74b0d37 Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Thu, 13 May 2010 14:45:42 -0400 Subject: drm/i915/dp: Only enable enhanced framing if the sink supports it DisplayPort spec v1.1a, Table 2-52. Signed-off-by: Adam Jackson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_dp.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 6b1c9a27c27a..6eed9a2006d7 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -675,10 +675,9 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, dp_priv->link_configuration[1] = dp_priv->lane_count; /* - * Check for DPCD version > 1.1, - * enable enahanced frame stuff in that case + * Check for DPCD version > 1.1 and enhanced framing support */ - if (dp_priv->dpcd[0] >= 0x11) { + if (dp_priv->dpcd[0] >= 0x11 && (dp_priv->dpcd[2] & DP_ENHANCED_FRAME_CAP)) { dp_priv->link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; dp_priv->DP |= DP_ENHANCED_FRAMING; } -- cgit v1.2.3 From a7de64e540d2017a8e44dec1ca9d88a509aa7e05 Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Thu, 13 May 2010 14:45:43 -0400 Subject: drm/i915/dp: Add DPCD data to debug output Signed-off-by: Adam Jackson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_dp.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 6eed9a2006d7..0a11c657c949 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1207,6 +1207,8 @@ ironlake_dp_detect(struct drm_connector *connector) if (dp_priv->dpcd[0] != 0) status = connector_status_connected; } + DRM_DEBUG_KMS("DPCD: %hx%hx%hx%hx\n", dp_priv->dpcd[0], + dp_priv->dpcd[1], dp_priv->dpcd[2], dp_priv->dpcd[3]); return status; } -- cgit v1.2.3 From 778c35444f7bbb8f1816d40ada650e19c5da9c02 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 13 May 2010 11:49:44 +0200 Subject: drm/i915: combine all small integers into one single bitfield This saves a whooping 7 dwords. Zero functional changes. Because some of the refcounts are rather tightly calculated, I've put BUG_ONs in the code to check for overflows. Signed-off-by: Daniel Vetter Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_drv.h | 75 +++++++++++++++++++++++++++-------------- drivers/gpu/drm/i915/i915_gem.c | 5 +++ 2 files changed, 54 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 91b3a1c20ef8..cccf8019f65a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -658,19 +658,64 @@ struct drm_i915_gem_object { * (has pending rendering), and is not set if it's on inactive (ready * to be unbound). */ - int active; + unsigned int active : 1; /** * This is set if the object has been written to since last bound * to the GTT */ - int dirty; + unsigned int dirty : 1; + + /** + * Fence register bits (if any) for this object. Will be set + * as needed when mapped into the GTT. + * Protected by dev->struct_mutex. + * + * Size: 4 bits for 16 fences + sign (for FENCE_REG_NONE) + */ + int fence_reg : 5; + + /** + * Used for checking the object doesn't appear more than once + * in an execbuffer object list. + */ + unsigned int in_execbuffer : 1; + + /** + * Advice: are the backing pages purgeable? + */ + unsigned int madv : 2; + + /** + * Refcount for the pages array. With the current locking scheme, there + * are at most two concurrent users: Binding a bo to the gtt and + * pwrite/pread using physical addresses. So two bits for a maximum + * of two users are enough. + */ + unsigned int pages_refcount : 2; +#define DRM_I915_GEM_OBJECT_MAX_PAGES_REFCOUNT 0x3 + + /** + * Current tiling mode for the object. + */ + unsigned int tiling_mode : 2; + + /** How many users have pinned this object in GTT space. The following + * users can each hold at most one reference: pwrite/pread, pin_ioctl + * (via user_pin_count), execbuffer (objects are not allowed multiple + * times for the same batchbuffer), and the framebuffer code. When + * switching/pageflipping, the framebuffer code has at most two buffers + * pinned per crtc. + * + * In the worst case this is 1 + 1 + 1 + 2*2 = 7. That would fit into 3 + * bits with absolutely no headroom. So use 4 bits. */ + int pin_count : 4; +#define DRM_I915_GEM_OBJECT_MAX_PIN_COUNT 0xf /** AGP memory structure for our GTT binding. */ DRM_AGP_MEM *agp_mem; struct page **pages; - int pages_refcount; /** * Current offset of the object in GTT space. @@ -687,21 +732,10 @@ struct drm_i915_gem_object { */ uint64_t mmap_offset; - /** - * Fence register bits (if any) for this object. Will be set - * as needed when mapped into the GTT. - * Protected by dev->struct_mutex. - */ - int fence_reg; - - /** How many users have pinned this object in GTT space */ - int pin_count; - /** Breadcrumb of last rendering to the buffer. */ uint32_t last_rendering_seqno; - /** Current tiling mode for the object. */ - uint32_t tiling_mode; + /** Current tiling stride for the object, if it's tiled. */ uint32_t stride; /** Record of address bit 17 of each page at last unbind. */ @@ -723,17 +757,6 @@ struct drm_i915_gem_object { /** for phy allocated objects */ struct drm_i915_gem_phys_object *phys_obj; - /** - * Used for checking the object doesn't appear more than once - * in an execbuffer object list. - */ - int in_execbuffer; - - /** - * Advice: are the backing pages purgeable? - */ - int madv; - /** * Number of crtcs where this object is currently the fb, but * will be page flipped away on the next vblank. When it diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c51495f15718..bf703551343a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2247,6 +2247,9 @@ i915_gem_object_get_pages(struct drm_gem_object *obj, struct inode *inode; struct page *page; + BUG_ON(obj_priv->pages_refcount + == DRM_I915_GEM_OBJECT_MAX_PAGES_REFCOUNT); + if (obj_priv->pages_refcount++ != 0) return 0; @@ -4156,6 +4159,8 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment) struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); int ret; + BUG_ON(obj_priv->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT); + i915_verify_inactive(dev, __FILE__, __LINE__); if (obj_priv->gtt_space == NULL) { ret = i915_gem_object_bind_to_gtt(obj, alignment); -- cgit v1.2.3 From 467b200da78c56036e58850a7f27902937d506f7 Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Wed, 12 May 2010 11:02:14 +0800 Subject: drm/i915: Fix HDMI mode select for Cougarpoint PCH For real HDMI sink, CPT HDMI port has to set 'HDMI' mode flag in order to make HDMI audio work correctly. This is required patch for drm/i915 to enable HDMI audio on CPT PCH, ALSA patch is at http://mailman.alsa-project.org/pipermail/alsa-devel/2010-May/027601.html Tested-by: Fengguang Wu Signed-off-by: Zhenyu Wang Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_reg.h | 3 +++ drivers/gpu/drm/i915/intel_hdmi.c | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index df7224de0aed..881fbe9a17f2 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2744,6 +2744,9 @@ #define SDVO_ENCODING (0) #define TMDS_ENCODING (2 << 10) #define NULL_PACKET_VSYNC_ENABLE (1 << 9) +/* CPT */ +#define HDMI_MODE_SELECT (1 << 9) +#define DVI_MODE_SELECT (0) #define SDVOB_BORDER_ENABLE (1 << 7) #define AUDIO_ENABLE (1 << 6) #define VSYNC_ACTIVE_HIGH (1 << 4) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 65727f0a79a3..83bd764b000e 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -59,8 +59,11 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, SDVO_VSYNC_ACTIVE_HIGH | SDVO_HSYNC_ACTIVE_HIGH; - if (hdmi_priv->has_hdmi_sink) + if (hdmi_priv->has_hdmi_sink) { sdvox |= SDVO_AUDIO_ENABLE; + if (HAS_PCH_CPT(dev)) + sdvox |= HDMI_MODE_SELECT; + } if (intel_crtc->pipe == 1) { if (HAS_PCH_CPT(dev)) -- cgit v1.2.3 From 90a78e8f60f679b0937011314a6cda39c7449d1d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 7 May 2010 10:40:09 +0200 Subject: i915/intel_sdvo: remove unneeded null check The "connector" variable is used as the cursor in a list_for_each_entry() and it's always non-null so we don't need to check it. Signed-off-by: Dan Carpenter Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_sdvo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index aba72c489a2f..76993ac16cc1 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1479,7 +1479,7 @@ intel_find_analog_connector(struct drm_device *dev) intel_encoder = enc_to_intel_encoder(encoder); if (intel_encoder->type == INTEL_OUTPUT_ANALOG) { list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (connector && encoder == intel_attached_encoder(connector)) + if (encoder == intel_attached_encoder(connector)) return connector; } } -- cgit v1.2.3 From d8201ab6514f8dc1a0ccfac52c688d80976a425a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 7 May 2010 10:39:00 +0200 Subject: i915: remove unneeded null checks The "encoder" variable can never be null because it is used as loop cursor in a list_for_each_entry() loop. Signed-off-by: Dan Carpenter Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_dp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 0a11c657c949..49b54f05d3cf 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -576,7 +576,7 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, struct intel_encoder *intel_encoder; struct intel_dp_priv *dp_priv; - if (!encoder || encoder->crtc != crtc) + if (encoder->crtc != crtc) continue; intel_encoder = enc_to_intel_encoder(encoder); @@ -1353,7 +1353,7 @@ intel_trans_dp_port_sel (struct drm_crtc *crtc) struct intel_encoder *intel_encoder = NULL; list_for_each_entry(encoder, &mode_config->encoder_list, head) { - if (!encoder || encoder->crtc != crtc) + if (encoder->crtc != crtc) continue; intel_encoder = enc_to_intel_encoder(encoder); -- cgit v1.2.3 From 9553426372eef71c849499fb1d232f4b0577c0f9 Mon Sep 17 00:00:00 2001 From: Li Peng Date: Tue, 18 May 2010 18:58:44 +0800 Subject: drm/i915: Add CxSR support on Pineview DDR3 Pineview with DDR3 memory has different latencies to enable CxSR. This patch updates CxSR latency table to add Pineview DDR3 latency configuration. It also adds one flag "is_ddr3" for checking DDR3 setting in MCHBAR. Cc: Shaohua Li Cc: Zhao Yakui Signed-off-by: Li Peng Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_dma.c | 4 ++ drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_reg.h | 4 ++ drivers/gpu/drm/i915/intel_display.c | 72 ++++++++++++++++++++++-------------- 4 files changed, 53 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 12e92f2cc3a7..a5f401664845 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1491,6 +1491,10 @@ static void i915_pineview_get_mem_freq(struct drm_device *dev) dev_priv->mem_freq = 800; break; } + + /* detect pineview DDR3 setting */ + tmp = I915_READ(CSHRDDR3CTL); + dev_priv->is_ddr3 = (tmp & CSHRDDR3CTL_DDR3) ? 1 : 0; } static void i915_ironlake_get_mem_freq(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index cccf8019f65a..e6b4cab6565f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -326,7 +326,7 @@ typedef struct drm_i915_private { int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */ int num_fence_regs; /* 8 on pre-965, 16 otherwise */ - unsigned int fsb_freq, mem_freq; + unsigned int fsb_freq, mem_freq, is_ddr3; spinlock_t error_lock; struct drm_i915_error_state *first_error; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 881fbe9a17f2..af7b10853e33 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -817,6 +817,10 @@ #define DCC_CHANNEL_XOR_DISABLE (1 << 10) #define DCC_CHANNEL_XOR_BIT_17 (1 << 9) +/** Pineview MCH register contains DDR3 setting */ +#define CSHRDDR3CTL 0x101a8 +#define CSHRDDR3CTL_DDR3 (1 << 2) + /** 965 MCH register controlling DRAM channel configuration */ #define C0DRB3 0x10206 #define C1DRB3 0x10606 diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f946332612ec..cfac4dd1d483 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2640,6 +2640,7 @@ static unsigned long intel_calculate_wm(unsigned long clock_in_khz, struct cxsr_latency { int is_desktop; + int is_ddr3; unsigned long fsb_freq; unsigned long mem_freq; unsigned long display_sr; @@ -2649,33 +2650,45 @@ struct cxsr_latency { }; static struct cxsr_latency cxsr_latency_table[] = { - {1, 800, 400, 3382, 33382, 3983, 33983}, /* DDR2-400 SC */ - {1, 800, 667, 3354, 33354, 3807, 33807}, /* DDR2-667 SC */ - {1, 800, 800, 3347, 33347, 3763, 33763}, /* DDR2-800 SC */ - - {1, 667, 400, 3400, 33400, 4021, 34021}, /* DDR2-400 SC */ - {1, 667, 667, 3372, 33372, 3845, 33845}, /* DDR2-667 SC */ - {1, 667, 800, 3386, 33386, 3822, 33822}, /* DDR2-800 SC */ - - {1, 400, 400, 3472, 33472, 4173, 34173}, /* DDR2-400 SC */ - {1, 400, 667, 3443, 33443, 3996, 33996}, /* DDR2-667 SC */ - {1, 400, 800, 3430, 33430, 3946, 33946}, /* DDR2-800 SC */ - - {0, 800, 400, 3438, 33438, 4065, 34065}, /* DDR2-400 SC */ - {0, 800, 667, 3410, 33410, 3889, 33889}, /* DDR2-667 SC */ - {0, 800, 800, 3403, 33403, 3845, 33845}, /* DDR2-800 SC */ - - {0, 667, 400, 3456, 33456, 4103, 34106}, /* DDR2-400 SC */ - {0, 667, 667, 3428, 33428, 3927, 33927}, /* DDR2-667 SC */ - {0, 667, 800, 3443, 33443, 3905, 33905}, /* DDR2-800 SC */ - - {0, 400, 400, 3528, 33528, 4255, 34255}, /* DDR2-400 SC */ - {0, 400, 667, 3500, 33500, 4079, 34079}, /* DDR2-667 SC */ - {0, 400, 800, 3487, 33487, 4029, 34029}, /* DDR2-800 SC */ + {1, 0, 800, 400, 3382, 33382, 3983, 33983}, /* DDR2-400 SC */ + {1, 0, 800, 667, 3354, 33354, 3807, 33807}, /* DDR2-667 SC */ + {1, 0, 800, 800, 3347, 33347, 3763, 33763}, /* DDR2-800 SC */ + {1, 1, 800, 667, 6420, 36420, 6873, 36873}, /* DDR3-667 SC */ + {1, 1, 800, 800, 5902, 35902, 6318, 36318}, /* DDR3-800 SC */ + + {1, 0, 667, 400, 3400, 33400, 4021, 34021}, /* DDR2-400 SC */ + {1, 0, 667, 667, 3372, 33372, 3845, 33845}, /* DDR2-667 SC */ + {1, 0, 667, 800, 3386, 33386, 3822, 33822}, /* DDR2-800 SC */ + {1, 1, 667, 667, 6438, 36438, 6911, 36911}, /* DDR3-667 SC */ + {1, 1, 667, 800, 5941, 35941, 6377, 36377}, /* DDR3-800 SC */ + + {1, 0, 400, 400, 3472, 33472, 4173, 34173}, /* DDR2-400 SC */ + {1, 0, 400, 667, 3443, 33443, 3996, 33996}, /* DDR2-667 SC */ + {1, 0, 400, 800, 3430, 33430, 3946, 33946}, /* DDR2-800 SC */ + {1, 1, 400, 667, 6509, 36509, 7062, 37062}, /* DDR3-667 SC */ + {1, 1, 400, 800, 5985, 35985, 6501, 36501}, /* DDR3-800 SC */ + + {0, 0, 800, 400, 3438, 33438, 4065, 34065}, /* DDR2-400 SC */ + {0, 0, 800, 667, 3410, 33410, 3889, 33889}, /* DDR2-667 SC */ + {0, 0, 800, 800, 3403, 33403, 3845, 33845}, /* DDR2-800 SC */ + {0, 1, 800, 667, 6476, 36476, 6955, 36955}, /* DDR3-667 SC */ + {0, 1, 800, 800, 5958, 35958, 6400, 36400}, /* DDR3-800 SC */ + + {0, 0, 667, 400, 3456, 33456, 4103, 34106}, /* DDR2-400 SC */ + {0, 0, 667, 667, 3428, 33428, 3927, 33927}, /* DDR2-667 SC */ + {0, 0, 667, 800, 3443, 33443, 3905, 33905}, /* DDR2-800 SC */ + {0, 1, 667, 667, 6494, 36494, 6993, 36993}, /* DDR3-667 SC */ + {0, 1, 667, 800, 5998, 35998, 6460, 36460}, /* DDR3-800 SC */ + + {0, 0, 400, 400, 3528, 33528, 4255, 34255}, /* DDR2-400 SC */ + {0, 0, 400, 667, 3500, 33500, 4079, 34079}, /* DDR2-667 SC */ + {0, 0, 400, 800, 3487, 33487, 4029, 34029}, /* DDR2-800 SC */ + {0, 1, 400, 667, 6566, 36566, 7145, 37145}, /* DDR3-667 SC */ + {0, 1, 400, 800, 6042, 36042, 6584, 36584}, /* DDR3-800 SC */ }; -static struct cxsr_latency *intel_get_cxsr_latency(int is_desktop, int fsb, - int mem) +static struct cxsr_latency *intel_get_cxsr_latency(int is_desktop, int is_ddr3, + int fsb, int mem) { int i; struct cxsr_latency *latency; @@ -2686,6 +2699,7 @@ static struct cxsr_latency *intel_get_cxsr_latency(int is_desktop, int fsb, for (i = 0; i < ARRAY_SIZE(cxsr_latency_table); i++) { latency = &cxsr_latency_table[i]; if (is_desktop == latency->is_desktop && + is_ddr3 == latency->is_ddr3 && fsb == latency->fsb_freq && mem == latency->mem_freq) return latency; } @@ -2800,8 +2814,8 @@ static void pineview_update_wm(struct drm_device *dev, int planea_clock, struct cxsr_latency *latency; int sr_clock; - latency = intel_get_cxsr_latency(IS_PINEVIEW_G(dev), dev_priv->fsb_freq, - dev_priv->mem_freq); + latency = intel_get_cxsr_latency(IS_PINEVIEW_G(dev), dev_priv->is_ddr3, + dev_priv->fsb_freq, dev_priv->mem_freq); if (!latency) { DRM_DEBUG_KMS("Unknown FSB/MEM found, disable CxSR\n"); pineview_disable_cxsr(dev); @@ -5406,11 +5420,13 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.update_wm = NULL; } else if (IS_PINEVIEW(dev)) { if (!intel_get_cxsr_latency(IS_PINEVIEW_G(dev), + dev_priv->is_ddr3, dev_priv->fsb_freq, dev_priv->mem_freq)) { DRM_INFO("failed to find known CxSR latency " - "(found fsb freq %d, mem freq %d), " + "(found ddr%s fsb freq %d, mem freq %d), " "disabling CxSR\n", + (dev_priv->is_ddr3 == 1) ? "3": "2", dev_priv->fsb_freq, dev_priv->mem_freq); /* Disable CxSR and never update its watermark again */ pineview_disable_cxsr(dev); -- cgit v1.2.3 From e20f9c64c79e2282f9eb531509181965ec8f0a92 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 26 May 2010 14:51:06 -0700 Subject: drm/i915: Clean up leftover bits from hws move to ring structure. Fixes /debug/dri/0/i915_gem_interrupt output for status page. Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_debugfs.c | 6 +++--- drivers/gpu/drm/i915/i915_dma.c | 7 +++---- drivers/gpu/drm/i915/i915_drv.h | 3 --- 3 files changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index eb11e1e049cb..52510ad8b25d 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -144,7 +144,7 @@ static int i915_gem_seqno_info(struct seq_file *m, void *data) struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; - if (dev_priv->hw_status_page != NULL) { + if (dev_priv->render_ring.status_page.page_addr != NULL) { seq_printf(m, "Current sequence: %d\n", i915_get_gem_seqno(dev, &dev_priv->render_ring)); } else { @@ -196,7 +196,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data) } seq_printf(m, "Interrupts received: %d\n", atomic_read(&dev_priv->irq_received)); - if (dev_priv->hw_status_page != NULL) { + if (dev_priv->render_ring.status_page.page_addr != NULL) { seq_printf(m, "Current sequence: %d\n", i915_get_gem_seqno(dev, &dev_priv->render_ring)); } else { @@ -252,7 +252,7 @@ static int i915_hws_info(struct seq_file *m, void *data) int i; volatile u32 *hws; - hws = (volatile u32 *)dev_priv->hw_status_page; + hws = (volatile u32 *)dev_priv->render_ring.status_page.page_addr; if (hws == NULL) return 0; diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index a5f401664845..6577798d3441 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -84,7 +84,6 @@ static void i915_free_hws(struct drm_device *dev) if (dev_priv->render_ring.status_page.gfx_addr) { dev_priv->render_ring.status_page.gfx_addr = 0; - dev_priv->status_gfx_addr = 0; drm_core_ioremapfree(&dev_priv->hws_map, dev); } @@ -828,7 +827,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data, drm_core_ioremap_wc(&dev_priv->hws_map, dev); if (dev_priv->hws_map.handle == NULL) { i915_dma_cleanup(dev); - dev_priv->status_gfx_addr = 0; + ring->status_page.gfx_addr = 0; DRM_ERROR("can not ioremap virtual address for" " G33 hw status page\n"); return -ENOMEM; @@ -838,9 +837,9 @@ static int i915_set_status_page(struct drm_device *dev, void *data, I915_WRITE(HWS_PGA, ring->status_page.gfx_addr); DRM_DEBUG_DRIVER("load hws HWS_PGA with gfx mem 0x%x\n", - dev_priv->status_gfx_addr); + ring->status_page.gfx_addr); DRM_DEBUG_DRIVER("load hws at %p\n", - dev_priv->hw_status_page); + ring->status_page.page_addr); return 0; } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e6b4cab6565f..9ed8ecd95801 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -238,14 +238,11 @@ typedef struct drm_i915_private { struct intel_ring_buffer bsd_ring; drm_dma_handle_t *status_page_dmah; - void *hw_status_page; void *seqno_page; dma_addr_t dma_status_page; uint32_t counter; - unsigned int status_gfx_addr; unsigned int seqno_gfx_addr; drm_local_map_t hws_map; - struct drm_gem_object *hws_obj; struct drm_gem_object *seqno_obj; struct drm_gem_object *pwrctx; -- cgit v1.2.3 From 9616ff434d96303689391af3d6e1c845d233405f Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 26 May 2010 21:17:29 -0700 Subject: sunsu: Fix use after free in su_remove(). Real serial port 'up' objects are statically allocated from an array in the driver. Keyboard and mouse ports, on the other hand, are dynamically allocated. Unfortunately, we free these dynamic 'up' objects before we unmap the I/O registers. Rearrange su_remove() so that this does not happen. Noticed by Julia Lawall. Signed-off-by: David S. Miller --- drivers/serial/sunsu.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index 234459c2f012..ffbf4553f665 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c @@ -1500,20 +1500,25 @@ out_unmap: static int __devexit su_remove(struct of_device *op) { struct uart_sunsu_port *up = dev_get_drvdata(&op->dev); + bool kbdms = false; if (up->su_type == SU_PORT_MS || - up->su_type == SU_PORT_KBD) { + up->su_type == SU_PORT_KBD) + kbdms = true; + + if (kbdms) { #ifdef CONFIG_SERIO serio_unregister_port(&up->serio); #endif - kfree(up); - } else if (up->port.type != PORT_UNKNOWN) { + } else if (up->port.type != PORT_UNKNOWN) uart_remove_one_port(&sunsu_reg, &up->port); - } if (up->port.membase) of_iounmap(&op->resource[0], up->port.membase, up->reg_size); + if (kbdms) + kfree(up); + dev_set_drvdata(&op->dev, NULL); return 0; -- cgit v1.2.3 From b334f2b3b68c35fd86a0cbc90ecee40e63ba2f37 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 9 May 2010 14:49:52 +0200 Subject: drm/nouveau: allow cursor image and position to survive suspend - This isn't triggered yet on a normal kernel, because it still does a VT switch, but it seemed like a good idea to fix this now. Tested-by: Maxim Levitsky Signed-off-by: Maarten Maathuis Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_crtc.h | 2 ++ drivers/gpu/drm/nouveau/nouveau_drv.c | 29 +++++++++++++++++++++++++++++ drivers/gpu/drm/nouveau/nv04_cursor.c | 1 + drivers/gpu/drm/nouveau/nv50_cursor.c | 1 + 4 files changed, 33 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_crtc.h b/drivers/gpu/drm/nouveau/nouveau_crtc.h index 49fa7b2d257e..cb1ce2a09162 100644 --- a/drivers/gpu/drm/nouveau/nouveau_crtc.h +++ b/drivers/gpu/drm/nouveau/nouveau_crtc.h @@ -40,6 +40,8 @@ struct nouveau_crtc { int sharpness; int last_dpms; + int cursor_saved_x, cursor_saved_y; + struct { int cpp; bool blanked; diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index c6079e36669d..273770432298 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -175,6 +175,13 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state) nouveau_bo_unpin(nouveau_fb->nvbo); } + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); + + nouveau_bo_unmap(nv_crtc->cursor.nvbo); + nouveau_bo_unpin(nv_crtc->cursor.nvbo); + } + NV_INFO(dev, "Evicting buffers...\n"); ttm_bo_evict_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM); @@ -314,12 +321,34 @@ nouveau_pci_resume(struct pci_dev *pdev) nouveau_bo_pin(nouveau_fb->nvbo, TTM_PL_FLAG_VRAM); } + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); + int ret; + + ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM); + if (!ret) + ret = nouveau_bo_map(nv_crtc->cursor.nvbo); + if (ret) + NV_ERROR(dev, "Could not pin/map cursor.\n"); + } + if (dev_priv->card_type < NV_50) { nv04_display_restore(dev); NVLockVgaCrtcs(dev, false); } else nv50_display_init(dev); + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); + + nv_crtc->cursor.set_offset(nv_crtc, + nv_crtc->cursor.nvbo->bo.offset - + dev_priv->vm_vram_base); + + nv_crtc->cursor.set_pos(nv_crtc, nv_crtc->cursor_saved_x, + nv_crtc->cursor_saved_y); + } + /* Force CLUT to get re-loaded during modeset */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); diff --git a/drivers/gpu/drm/nouveau/nv04_cursor.c b/drivers/gpu/drm/nouveau/nv04_cursor.c index 89a91b9d8b25..aaf3de3bc816 100644 --- a/drivers/gpu/drm/nouveau/nv04_cursor.c +++ b/drivers/gpu/drm/nouveau/nv04_cursor.c @@ -20,6 +20,7 @@ nv04_cursor_hide(struct nouveau_crtc *nv_crtc, bool update) static void nv04_cursor_set_pos(struct nouveau_crtc *nv_crtc, int x, int y) { + nv_crtc->cursor_saved_x = x; nv_crtc->cursor_saved_y = y; NVWriteRAMDAC(nv_crtc->base.dev, nv_crtc->index, NV_PRAMDAC_CU_START_POS, XLATE(y, 0, NV_PRAMDAC_CU_START_POS_Y) | diff --git a/drivers/gpu/drm/nouveau/nv50_cursor.c b/drivers/gpu/drm/nouveau/nv50_cursor.c index 753e723adb3a..03ad7ab14f09 100644 --- a/drivers/gpu/drm/nouveau/nv50_cursor.c +++ b/drivers/gpu/drm/nouveau/nv50_cursor.c @@ -107,6 +107,7 @@ nv50_cursor_set_pos(struct nouveau_crtc *nv_crtc, int x, int y) { struct drm_device *dev = nv_crtc->base.dev; + nv_crtc->cursor_saved_x = x; nv_crtc->cursor_saved_y = y; nv_wr32(dev, NV50_PDISPLAY_CURSOR_USER_POS(nv_crtc->index), ((y & 0xFFFF) << 16) | (x & 0xFFFF)); /* Needed to make the cursor move. */ -- cgit v1.2.3 From 7fc74f17e6c9b4d86371c3a947afc32bd6bc9691 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Ko=C5=9Bcielnicki?= Date: Sun, 23 May 2010 11:36:04 +0000 Subject: drm/nouveau: Add getparam for current PTIMER time. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will be useful for computing GPU-CPU latency, including GL_ARB_timer_query extension. Signed-off-by: Marcin Kościelnicki Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_state.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index e632339c323e..a2544ffd02cc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -913,6 +913,9 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data, case NOUVEAU_GETPARAM_VM_VRAM_BASE: getparam->value = dev_priv->vm_vram_base; break; + case NOUVEAU_GETPARAM_PTIMER_TIME: + getparam->value = dev_priv->engine.timer.read(dev); + break; case NOUVEAU_GETPARAM_GRAPH_UNITS: /* NV40 and NV50 versions are quite different, but register * address is the same. User is supposed to know the card -- cgit v1.2.3 From d13102c6b4836289138431e3fbfc08e90c925ffd Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 25 May 2010 13:47:16 +1000 Subject: drm/nouveau: fix POST detection for certain chipsets We totally fail at detecting un-POSTed chipsets prior to G80. This commit changes the pre-G80 POST detection to read the programmed horizontal total from CRTC 0, and assume the card isn't POSTed if it's 0. NVIDIA use some other heuristics more similar to what we do on G80, but I wasted quite a long time trying to figure out the exact specifics of what they do so we can try this for a bit instead. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index e7e69ccce5c9..61d932261356 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -6205,6 +6205,30 @@ nouveau_bios_i2c_devices_takedown(struct drm_device *dev) nouveau_i2c_fini(dev, entry); } +static bool +nouveau_bios_posted(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + bool was_locked; + unsigned htotal; + + if (dev_priv->chipset >= NV_50) { + if (NVReadVgaCrtc(dev, 0, 0x00) == 0 && + NVReadVgaCrtc(dev, 0, 0x1a) == 0) + return false; + return true; + } + + was_locked = NVLockVgaCrtcs(dev, false); + htotal = NVReadVgaCrtc(dev, 0, 0x06); + htotal |= (NVReadVgaCrtc(dev, 0, 0x07) & 0x01) << 8; + htotal |= (NVReadVgaCrtc(dev, 0, 0x07) & 0x20) << 4; + htotal |= (NVReadVgaCrtc(dev, 0, 0x25) & 0x01) << 10; + htotal |= (NVReadVgaCrtc(dev, 0, 0x41) & 0x01) << 11; + NVLockVgaCrtcs(dev, was_locked); + return (htotal != 0); +} + int nouveau_bios_init(struct drm_device *dev) { @@ -6239,9 +6263,7 @@ nouveau_bios_init(struct drm_device *dev) bios->execute = false; /* ... unless card isn't POSTed already */ - if (dev_priv->card_type >= NV_10 && - NVReadVgaCrtc(dev, 0, 0x00) == 0 && - NVReadVgaCrtc(dev, 0, 0x1a) == 0) { + if (!nouveau_bios_posted(dev)) { NV_INFO(dev, "Adaptor not initialised\n"); if (dev_priv->card_type < NV_50) { NV_ERROR(dev, "Unable to POST this chipset\n"); -- cgit v1.2.3 From f50c0b91e7718e7deda46475cfd0ea1413daed04 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 25 May 2010 13:48:07 +1000 Subject: drm/nv40: allow cold-booting of nv4x chipsets Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 61d932261356..620cbd9767cc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -6265,7 +6265,7 @@ nouveau_bios_init(struct drm_device *dev) /* ... unless card isn't POSTed already */ if (!nouveau_bios_posted(dev)) { NV_INFO(dev, "Adaptor not initialised\n"); - if (dev_priv->card_type < NV_50) { + if (dev_priv->card_type < NV_40) { NV_ERROR(dev, "Unable to POST this chipset\n"); return -ENODEV; } -- cgit v1.2.3 From 73db4bedc5dde97adf59b5b5a07c6cf0ee56e668 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 26 May 2010 10:41:45 +1000 Subject: drm/nouveau: don't execute INIT_GPIO unless we're really running the table This resulted in accidently switching off the eDP panel on certain laptops since the default state in the GPIO table was off. Fixes rh#582621 Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 620cbd9767cc..b3c7a87e47d9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -2807,7 +2807,10 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) BIOSLOG(bios, "0x%04X: Entry: 0x%08X\n", offset, gpio->entry); - nv50_gpio_set(bios->dev, gpio->tag, gpio->state_default); + BIOSLOG(bios, "0x%04X: set gpio 0x%02x, state %d\n", + offset, gpio->tag, gpio->state_default); + if (bios->execute) + nv50_gpio_set(bios->dev, gpio->tag, gpio->state_default); /* The NVIDIA binary driver doesn't appear to actually do * any of this, my VBIOS does however. -- cgit v1.2.3 From 23484874e6bf837704bf1fa61605d33a12b174e3 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 28 May 2010 09:39:11 +1000 Subject: drm/nv50: fix duallink_possible calculation for DCB 4.0 cards Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index b3c7a87e47d9..9f30fb8eafe8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -5536,12 +5536,6 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, entry->bus = (conn >> 16) & 0xf; entry->location = (conn >> 20) & 0x3; entry->or = (conn >> 24) & 0xf; - /* - * Normal entries consist of a single bit, but dual link has the - * next most significant bit set too - */ - entry->duallink_possible = - ((1 << (ffs(entry->or) - 1)) * 3 == entry->or); switch (entry->type) { case OUTPUT_ANALOG: @@ -5625,6 +5619,16 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, break; } + if (dcb->version < 0x40) { + /* Normal entries consist of a single bit, but dual link has + * the next most significant bit set too + */ + entry->duallink_possible = + ((1 << (ffs(entry->or) - 1)) * 3 == entry->or); + } else { + entry->duallink_possible = (entry->sorconf.link == 3); + } + /* unsure what DCB version introduces this, 3.0? */ if (conf & 0x100000) entry->i2c_upper_default = true; -- cgit v1.2.3 From 2c58077541cc6859a9a9046d9c3a4d61bdbd4f18 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 28 May 2010 10:04:05 +1000 Subject: drm/nv50: obey dcb->duallink_possible It was once assumed that all G8x had dual-link TMDS everywhere, this isn't actually the case - especially considering passive DP->DVI converters and some HDMI connectors only support single-link. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 7e663a79829f..bfa65629517b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -593,8 +593,7 @@ nouveau_connector_mode_valid(struct drm_connector *connector, break; case OUTPUT_TMDS: if ((dev_priv->card_type >= NV_50 && !nouveau_duallink) || - (dev_priv->card_type < NV_50 && - !nv_encoder->dcb->duallink_possible)) + !nv_encoder->dcb->duallink_possible) max_clock = 165000; else max_clock = 330000; -- cgit v1.2.3 From 26099a74805eaf79f3058cc4097ebaa8cc55122c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 28 May 2010 10:13:16 +1000 Subject: drm/nouveau: fix dual-link displays when plugged into single-link outputs When selecting the native mode for a display we weren't taking into account whether or not it was actually supported on that particular output. This patch modifies our native mode selection to run all modes through mode_valid() first. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 31 ++++++++++++++++------------- 1 file changed, 17 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index bfa65629517b..256e82bd91dd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -431,24 +431,27 @@ nouveau_connector_set_property(struct drm_connector *connector, } static struct drm_display_mode * -nouveau_connector_native_mode(struct nouveau_connector *connector) +nouveau_connector_native_mode(struct drm_connector *connector) { - struct drm_device *dev = connector->base.dev; + struct drm_connector_helper_funcs *helper = connector->helper_private; + struct nouveau_connector *nv_connector = nouveau_connector(connector); + struct drm_device *dev = connector->dev; struct drm_display_mode *mode, *largest = NULL; int high_w = 0, high_h = 0, high_v = 0; - /* Use preferred mode if there is one.. */ - list_for_each_entry(mode, &connector->base.probed_modes, head) { + list_for_each_entry(mode, &nv_connector->base.probed_modes, head) { + if (helper->mode_valid(connector, mode) != MODE_OK) + continue; + + /* Use preferred mode if there is one.. */ if (mode->type & DRM_MODE_TYPE_PREFERRED) { NV_DEBUG_KMS(dev, "native mode from preferred\n"); return drm_mode_duplicate(dev, mode); } - } - /* Otherwise, take the resolution with the largest width, then height, - * then vertical refresh - */ - list_for_each_entry(mode, &connector->base.probed_modes, head) { + /* Otherwise, take the resolution with the largest width, then + * height, then vertical refresh + */ if (mode->hdisplay < high_w) continue; @@ -552,7 +555,7 @@ nouveau_connector_get_modes(struct drm_connector *connector) */ if (!nv_connector->native_mode) nv_connector->native_mode = - nouveau_connector_native_mode(nv_connector); + nouveau_connector_native_mode(connector); if (ret == 0 && nv_connector->native_mode) { struct drm_display_mode *mode; @@ -583,9 +586,9 @@ nouveau_connector_mode_valid(struct drm_connector *connector, switch (nv_encoder->dcb->type) { case OUTPUT_LVDS: - BUG_ON(!nv_connector->native_mode); - if (mode->hdisplay > nv_connector->native_mode->hdisplay || - mode->vdisplay > nv_connector->native_mode->vdisplay) + if (nv_connector->native_mode && + (mode->hdisplay > nv_connector->native_mode->hdisplay || + mode->vdisplay > nv_connector->native_mode->vdisplay)) return MODE_PANEL; min_clock = 0; @@ -727,7 +730,7 @@ nouveau_connector_create_lvds(struct drm_device *dev, if (ret == 0) goto out; nv_connector->detected_encoder = nv_encoder; - nv_connector->native_mode = nouveau_connector_native_mode(nv_connector); + nv_connector->native_mode = nouveau_connector_native_mode(connector); list_for_each_entry_safe(mode, temp, &connector->probed_modes, head) drm_mode_remove(connector, mode); -- cgit v1.2.3 From becd214277ed41dc6f745f5f8db39d84c6c7ffc8 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 29 May 2010 03:06:14 +1000 Subject: drm/nv50: use alternate source of SOR_MODE_CTRL for DP hack Fixes module unload+reload on Dell M4500, where the "normal" registers get reset to 0. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_sor.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nv50_sor.c b/drivers/gpu/drm/nouveau/nv50_sor.c index b11eaf9c5c7c..812778db76ac 100644 --- a/drivers/gpu/drm/nouveau/nv50_sor.c +++ b/drivers/gpu/drm/nouveau/nv50_sor.c @@ -274,7 +274,6 @@ static const struct drm_encoder_funcs nv50_sor_encoder_funcs = { int nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry) { - struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_encoder *nv_encoder = NULL; struct drm_encoder *encoder; bool dum; @@ -324,11 +323,7 @@ nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry) int or = nv_encoder->or, link = !(entry->dpconf.sor.link & 1); uint32_t tmp; - if (dev_priv->chipset < 0x90 || - dev_priv->chipset == 0x92 || dev_priv->chipset == 0xa0) - tmp = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_C(or)); - else - tmp = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_C(or)); + tmp = nv_rd32(dev, 0x61c700 + (or * 0x800)); switch ((tmp & 0x00000f00) >> 8) { case 8: -- cgit v1.2.3 From 35aed2e6be2feaa227fe5c7a0b7c286c4fe71592 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 27 May 2010 13:18:12 +0100 Subject: drm/i915: Only print an message if there was an error Only report an error if the GPU has actually detected one, otherwise we are just hung. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_irq.c | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index b5dba4795f6f..2479be001e40 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -692,24 +692,13 @@ void i915_destroy_error_state(struct drm_device *dev) i915_error_state_free(dev, error); } -/** - * i915_handle_error - handle an error interrupt - * @dev: drm device - * - * Do some basic checking of regsiter state at error interrupt time and - * dump it to the syslog. Also call i915_capture_error_state() to make - * sure we get a record and make it available in debugfs. Fire a uevent - * so userspace knows something bad happened (should trigger collection - * of a ring dump etc.). - */ -static void i915_handle_error(struct drm_device *dev, bool wedged) +static void i915_report_and_clear_eir(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; u32 eir = I915_READ(EIR); - u32 pipea_stats = I915_READ(PIPEASTAT); - u32 pipeb_stats = I915_READ(PIPEBSTAT); - i915_capture_error_state(dev); + if (!eir) + return; printk(KERN_ERR "render error detected, EIR: 0x%08x\n", eir); @@ -755,6 +744,9 @@ static void i915_handle_error(struct drm_device *dev, bool wedged) } if (eir & I915_ERROR_MEMORY_REFRESH) { + u32 pipea_stats = I915_READ(PIPEASTAT); + u32 pipeb_stats = I915_READ(PIPEBSTAT); + printk(KERN_ERR "memory refresh error\n"); printk(KERN_ERR "PIPEASTAT: 0x%08x\n", pipea_stats); @@ -811,6 +803,24 @@ static void i915_handle_error(struct drm_device *dev, bool wedged) I915_WRITE(EMR, I915_READ(EMR) | eir); I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); } +} + +/** + * i915_handle_error - handle an error interrupt + * @dev: drm device + * + * Do some basic checking of regsiter state at error interrupt time and + * dump it to the syslog. Also call i915_capture_error_state() to make + * sure we get a record and make it available in debugfs. Fire a uevent + * so userspace knows something bad happened (should trigger collection + * of a ring dump etc.). + */ +static void i915_handle_error(struct drm_device *dev, bool wedged) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + i915_capture_error_state(dev); + i915_report_and_clear_eir(dev); if (wedged) { atomic_set(&dev_priv->mm.wedged, 1); -- cgit v1.2.3 From 468f0b44ce4b002ca7d9260f802a341854752c02 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 27 May 2010 13:18:13 +0100 Subject: drm/i915: Hold the spinlock whilst resetting unpin_work along error path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Delay taking the mutex until we need to and ensure that we hold the spinlock when resetting unpin_work on the error path. Also defer the debugging print messages until after we have released the spinlock. Signed-off-by: Chris Wilson Cc: Jesse Barnes Cc: Kristian Høgsberg Reviewed-by: Jesse Barnes Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_display.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cfac4dd1d483..1845a068cca5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4667,8 +4667,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, if (work == NULL) return -ENOMEM; - mutex_lock(&dev->struct_mutex); - work->event = event; work->dev = crtc->dev; intel_fb = to_intel_framebuffer(crtc->fb); @@ -4678,10 +4676,10 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, /* We borrow the event spin lock for protecting unpin_work */ spin_lock_irqsave(&dev->event_lock, flags); if (intel_crtc->unpin_work) { - DRM_DEBUG_DRIVER("flip queue: crtc already busy\n"); spin_unlock_irqrestore(&dev->event_lock, flags); kfree(work); - mutex_unlock(&dev->struct_mutex); + + DRM_DEBUG_DRIVER("flip queue: crtc already busy\n"); return -EBUSY; } intel_crtc->unpin_work = work; @@ -4690,13 +4688,19 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, intel_fb = to_intel_framebuffer(fb); obj = intel_fb->obj; + mutex_lock(&dev->struct_mutex); ret = intel_pin_and_fence_fb_obj(dev, obj); if (ret != 0) { - DRM_DEBUG_DRIVER("flip queue: %p pin & fence failed\n", - to_intel_bo(obj)); - kfree(work); - intel_crtc->unpin_work = NULL; mutex_unlock(&dev->struct_mutex); + + spin_lock_irqsave(&dev->event_lock, flags); + intel_crtc->unpin_work = NULL; + spin_unlock_irqrestore(&dev->event_lock, flags); + + kfree(work); + + DRM_DEBUG_DRIVER("flip queue: %p pin & fence failed\n", + to_intel_bo(obj)); return ret; } -- cgit v1.2.3 From b118c1e363befe3d74469f4a014ce6353097f08a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 27 May 2010 13:18:14 +0100 Subject: drm/i915: Avoid nesting of domain changes when setting display plane Nesting domain changes will cause confusion when trying to interpret the tracepoints describing the sequence of changes for the object, as well as obscuring the order of operations for the reader of the code. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_gem.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index bf703551343a..1c65f0b591fc 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2914,18 +2914,16 @@ i915_gem_object_set_to_display_plane(struct drm_gem_object *obj) return ret; } + i915_gem_object_flush_cpu_write_domain(obj); + old_write_domain = obj->write_domain; old_read_domains = obj->read_domains; - obj->read_domains &= I915_GEM_DOMAIN_GTT; - - i915_gem_object_flush_cpu_write_domain(obj); - /* It should now be out of any other write domains, and we can update * the domain values for our changes. */ BUG_ON((obj->write_domain & ~I915_GEM_DOMAIN_GTT) != 0); - obj->read_domains |= I915_GEM_DOMAIN_GTT; + obj->read_domains = I915_GEM_DOMAIN_GTT; obj->write_domain = I915_GEM_DOMAIN_GTT; obj_priv->dirty = 1; -- cgit v1.2.3 From 808b24d6ed8b155aac17007788390ebfde263f30 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 27 May 2010 13:18:15 +0100 Subject: drm/i915: Propagate error from unbinding an unfenceable object. Signed-off-by: Chris Wilson Cc: Jesse Barnes Reviewed-by: Jesse Barnes Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_gem.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 1c65f0b591fc..6425c2a4b11f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3307,9 +3307,13 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, obj_priv->tiling_mode != I915_TILING_NONE; /* Check fence reg constraints and rebind if necessary */ - if (need_fence && !i915_gem_object_fence_offset_ok(obj, - obj_priv->tiling_mode)) - i915_gem_object_unbind(obj); + if (need_fence && + !i915_gem_object_fence_offset_ok(obj, + obj_priv->tiling_mode)) { + ret = i915_gem_object_unbind(obj); + if (ret) + return ret; + } /* Choose the GTT offset for our buffer and put it there. */ ret = i915_gem_object_pin(obj, (uint32_t) entry->alignment); -- cgit v1.2.3 From a939406fda8ddc7de69ee9186356d09dc6daaa2c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 27 May 2010 13:18:16 +0100 Subject: drm/i915: Only print "nothing to do" debug message as required. If the FBC is already disabled, then we do not even attempt to disable FBC and so there is no point emitting a debug statement at that point, having already emitted one saying why we are disabling FBC. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_display.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1845a068cca5..e504fdb4ae31 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1248,10 +1248,11 @@ static void intel_update_fbc(struct drm_crtc *crtc, return; out_disable: - DRM_DEBUG_KMS("unsupported config, disabling FBC\n"); /* Multiple disables should be harmless */ - if (intel_fbc_enabled(dev)) + if (intel_fbc_enabled(dev)) { + DRM_DEBUG_KMS("unsupported config, disabling FBC\n"); intel_disable_fbc(dev); + } } static int -- cgit v1.2.3 From a7faf32d00529b9c501e37a31d4bf8acef4f8f59 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 27 May 2010 13:18:17 +0100 Subject: drm/i915: Include pitch in set_base debug statement. Add the pitch that we about to write into the control register along with the base, offset and coordinates that go into the other control registers. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_display.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e504fdb4ae31..88a1ab7c05ce 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1396,7 +1396,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, Start = obj_priv->gtt_offset; Offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8); - DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d\n", Start, Offset, x, y); + DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n", + Start, Offset, x, y, crtc->fb->pitch); I915_WRITE(dspstride, crtc->fb->pitch); if (IS_I965G(dev)) { I915_WRITE(dspbase, Offset); -- cgit v1.2.3 From ac0c6b5ad3b3b513e1057806d4b7627fcc0ecc27 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 27 May 2010 13:18:18 +0100 Subject: drm/i915: Rebind bo if currently bound with incorrect alignment. Whilst pinning the buffer, check that that its current alignment matches the requested alignment. If it does not, rebind. This should clear up any final render errors whilst resuming, for reference: Bug 27070 - [i915] Page table errors with empty ringbuffer https://bugs.freedesktop.org/show_bug.cgi?id=27070 Bug 15502 - render error detected, EIR: 0x00000010 https://bugzilla.kernel.org/show_bug.cgi?id=15502 Bug 13844 - i915 error: "render error detected" https://bugzilla.kernel.org/show_bug.cgi?id=13844 Signed-off-by: Chris Wilson Cc: stable@kernel.org Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_gem.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 6425c2a4b11f..a5ca9599b232 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4164,6 +4164,17 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment) BUG_ON(obj_priv->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT); i915_verify_inactive(dev, __FILE__, __LINE__); + + if (obj_priv->gtt_space != NULL) { + if (alignment == 0) + alignment = i915_gem_get_gtt_alignment(obj); + if (obj_priv->gtt_offset & (alignment - 1)) { + ret = i915_gem_object_unbind(obj); + if (ret) + return ret; + } + } + if (obj_priv->gtt_space == NULL) { ret = i915_gem_object_bind_to_gtt(obj, alignment); if (ret) -- cgit v1.2.3 From 3d1cc47037f36004b10681d3436ef0942ebb279b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 27 May 2010 13:18:19 +0100 Subject: drm/i915: Remove spurious warning "Failure to install fence" This particular warning is harmless as we emit during the normal pinning process where the batch buffer requires more fences than is available without eviction. Only if we fail to evict enough fences does this become a problem, so include the requested number of fences in the ultimate *error* message. v2: Remember to compile test even trial patches to remove warnings. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_gem.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index a5ca9599b232..b87945db1021 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3327,9 +3327,6 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, if (need_fence) { ret = i915_gem_object_get_fence_reg(obj); if (ret != 0) { - if (ret != -EBUSY && ret != -ERESTARTSYS) - DRM_ERROR("Failure to install fence: %d\n", - ret); i915_gem_object_unpin(obj); return ret; } @@ -3815,11 +3812,19 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (ret != -ENOSPC || pin_tries >= 1) { if (ret != -ERESTARTSYS) { unsigned long long total_size = 0; - for (i = 0; i < args->buffer_count; i++) + int num_fences = 0; + for (i = 0; i < args->buffer_count; i++) { + obj_priv = object_list[i]->driver_private; + total_size += object_list[i]->size; - DRM_ERROR("Failed to pin buffer %d of %d, total %llu bytes: %d\n", + num_fences += + exec_list[i].flags & EXEC_OBJECT_NEEDS_FENCE && + obj_priv->tiling_mode != I915_TILING_NONE; + } + DRM_ERROR("Failed to pin buffer %d of %d, total %llu bytes, %d fences: %d\n", pinned+1, args->buffer_count, - total_size, ret); + total_size, num_fences, + ret); DRM_ERROR("%d objects [%d pinned], " "%d object bytes [%d pinned], " "%d/%d gtt bytes\n", -- cgit v1.2.3 From 85cd4612fdab4e837d7eea048a697c75d0477d3b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 27 May 2010 13:18:20 +0100 Subject: drm/i915: Check error code whilst moving buffer to GTT domain. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_fb.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 6f53cf7fbc50..f8c76e64bb77 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -105,7 +105,11 @@ static int intelfb_create(struct intel_fbdev *ifbdev, } /* Flush everything out, we'll be doing GTT only from now on */ - i915_gem_object_set_to_gtt_domain(fbo, 1); + ret = i915_gem_object_set_to_gtt_domain(fbo, 1); + if (ret) { + DRM_ERROR("failed to bind fb: %d.\n", ret); + goto out_unpin; + } info = framebuffer_alloc(0, device); if (!info) { -- cgit v1.2.3 From 654fc6073f68efa3b6c466825749e73e7fbb92cd Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 27 May 2010 13:18:21 +0100 Subject: drm/i915: Reject bind_to_gtt() early if object > aperture If the object is bigger than the entire aperture, reject it early before evicting everything in a vain attempt to find space. v2: Use E2BIG as suggested by Owain G. Ainsworth. Signed-off-by: Chris Wilson Cc: stable@kernel.org Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_gem.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b87945db1021..f84c8e982dcb 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2648,6 +2648,14 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) return -EINVAL; } + /* If the object is bigger than the entire aperture, reject it early + * before evicting everything in a vain attempt to find space. + */ + if (obj->size > dev->gtt_total) { + DRM_ERROR("Attempting to bind an object larger than the aperture\n"); + return -E2BIG; + } + search_free: free_space = drm_mm_search_free(&dev_priv->mm.gtt_space, obj->size, alignment, 0); -- cgit v1.2.3 From 68f95ba9e260516411411524c45263b5d53f393c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 27 May 2010 13:18:22 +0100 Subject: drm/i915: Cleanup after failed initialization of ringbuffers The callers expect us to cleanup any partially initialised structures before reporting the error. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_gem.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index f84c8e982dcb..42866c01540d 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4632,23 +4632,40 @@ i915_gem_init_ringbuffer(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; int ret; + dev_priv->render_ring = render_ring; + if (!I915_NEED_GFX_HWS(dev)) { dev_priv->render_ring.status_page.page_addr = dev_priv->status_page_dmah->vaddr; memset(dev_priv->render_ring.status_page.page_addr, 0, PAGE_SIZE); } + if (HAS_PIPE_CONTROL(dev)) { ret = i915_gem_init_pipe_control(dev); if (ret) return ret; } + ret = intel_init_ring_buffer(dev, &dev_priv->render_ring); - if (!ret && HAS_BSD(dev)) { + if (ret) + goto cleanup_pipe_control; + + if (HAS_BSD(dev)) { dev_priv->bsd_ring = bsd_ring; ret = intel_init_ring_buffer(dev, &dev_priv->bsd_ring); + if (ret) + goto cleanup_render_ring; } + + return 0; + +cleanup_render_ring: + intel_cleanup_ring_buffer(dev, &dev_priv->render_ring); +cleanup_pipe_control: + if (HAS_PIPE_CONTROL(dev)) + i915_gem_cleanup_pipe_control(dev); return ret; } -- cgit v1.2.3 From 9b8c4a0b215e603497daebe8ecbc9b1f0f035808 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 27 May 2010 14:21:01 +0100 Subject: drm/i915: Avoid moving from CPU domain during pwrite We can avoid an early clflush when pwriting if we use the current CPU write domain rather than moving the object to the GTT domain for the purposes of the pwrite. This has the advantage of not flushing the presumably hot data that we want to upload into the bo, and of ascribing the clflush to the execution when profiling. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_gem.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 42866c01540d..4590c78f4283 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -971,7 +971,8 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, if (obj_priv->phys_obj) ret = i915_gem_phys_pwrite(dev, obj, args, file_priv); else if (obj_priv->tiling_mode == I915_TILING_NONE && - dev->gtt_total != 0) { + dev->gtt_total != 0 && + obj->write_domain != I915_GEM_DOMAIN_CPU) { ret = i915_gem_gtt_pwrite_fast(dev, obj, args, file_priv); if (ret == -EFAULT) { ret = i915_gem_gtt_pwrite_slow(dev, obj, args, -- cgit v1.2.3 From 99a03df57c82ec20848d2634f652c07ac3504b98 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 27 May 2010 14:15:34 +0100 Subject: drm/i915: Use non-atomic kmap for slow copy paths As we do not have a requirement to be atomic and avoid sleeping whilst performing the slow copy for shmem based pread and pwrite, we can use kmap instead, thus simplifying the code. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_gem.c | 82 +++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 4590c78f4283..b8e351274493 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -167,7 +167,7 @@ static int i915_gem_object_needs_bit17_swizzle(struct drm_gem_object *obj) obj_priv->tiling_mode != I915_TILING_NONE; } -static inline int +static inline void slow_shmem_copy(struct page *dst_page, int dst_offset, struct page *src_page, @@ -176,25 +176,16 @@ slow_shmem_copy(struct page *dst_page, { char *dst_vaddr, *src_vaddr; - dst_vaddr = kmap_atomic(dst_page, KM_USER0); - if (dst_vaddr == NULL) - return -ENOMEM; - - src_vaddr = kmap_atomic(src_page, KM_USER1); - if (src_vaddr == NULL) { - kunmap_atomic(dst_vaddr, KM_USER0); - return -ENOMEM; - } + dst_vaddr = kmap(dst_page); + src_vaddr = kmap(src_page); memcpy(dst_vaddr + dst_offset, src_vaddr + src_offset, length); - kunmap_atomic(src_vaddr, KM_USER1); - kunmap_atomic(dst_vaddr, KM_USER0); - - return 0; + kunmap(src_page); + kunmap(dst_page); } -static inline int +static inline void slow_shmem_bit17_copy(struct page *gpu_page, int gpu_offset, struct page *cpu_page, @@ -214,15 +205,8 @@ slow_shmem_bit17_copy(struct page *gpu_page, cpu_page, cpu_offset, length); } - gpu_vaddr = kmap_atomic(gpu_page, KM_USER0); - if (gpu_vaddr == NULL) - return -ENOMEM; - - cpu_vaddr = kmap_atomic(cpu_page, KM_USER1); - if (cpu_vaddr == NULL) { - kunmap_atomic(gpu_vaddr, KM_USER0); - return -ENOMEM; - } + gpu_vaddr = kmap(gpu_page); + cpu_vaddr = kmap(cpu_page); /* Copy the data, XORing A6 with A17 (1). The user already knows he's * XORing with the other bits (A9 for Y, A9 and A10 for X) @@ -246,10 +230,8 @@ slow_shmem_bit17_copy(struct page *gpu_page, length -= this_length; } - kunmap_atomic(cpu_vaddr, KM_USER1); - kunmap_atomic(gpu_vaddr, KM_USER0); - - return 0; + kunmap(cpu_page); + kunmap(gpu_page); } /** @@ -425,21 +407,19 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_gem_object *obj, page_length = PAGE_SIZE - data_page_offset; if (do_bit17_swizzling) { - ret = slow_shmem_bit17_copy(obj_priv->pages[shmem_page_index], - shmem_page_offset, - user_pages[data_page_index], - data_page_offset, - page_length, - 1); - } else { - ret = slow_shmem_copy(user_pages[data_page_index], - data_page_offset, - obj_priv->pages[shmem_page_index], + slow_shmem_bit17_copy(obj_priv->pages[shmem_page_index], shmem_page_offset, - page_length); + user_pages[data_page_index], + data_page_offset, + page_length, + 1); + } else { + slow_shmem_copy(user_pages[data_page_index], + data_page_offset, + obj_priv->pages[shmem_page_index], + shmem_page_offset, + page_length); } - if (ret) - goto fail_put_pages; remain -= page_length; data_ptr += page_length; @@ -900,21 +880,19 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj, page_length = PAGE_SIZE - data_page_offset; if (do_bit17_swizzling) { - ret = slow_shmem_bit17_copy(obj_priv->pages[shmem_page_index], - shmem_page_offset, - user_pages[data_page_index], - data_page_offset, - page_length, - 0); - } else { - ret = slow_shmem_copy(obj_priv->pages[shmem_page_index], + slow_shmem_bit17_copy(obj_priv->pages[shmem_page_index], shmem_page_offset, user_pages[data_page_index], data_page_offset, - page_length); + page_length, + 0); + } else { + slow_shmem_copy(obj_priv->pages[shmem_page_index], + shmem_page_offset, + user_pages[data_page_index], + data_page_offset, + page_length); } - if (ret) - goto fail_put_pages; remain -= page_length; data_ptr += page_length; -- cgit v1.2.3 From ab34c226812588de8f341ce48eb32c3fef5155a9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 27 May 2010 14:15:35 +0100 Subject: drm/i915: Fix up address spaces in slow_kernel_write() Since we now get_user_pages() outside of the mutex prior to performing the copy, we kmap() the page inside the copy routine and so need to perform an ordinary memcpy() and not copy_from_user(). Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_gem.c | 42 +++++++++++++++++------------------------ 1 file changed, 17 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b8e351274493..9ded3dae6c87 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -509,25 +509,24 @@ fast_user_write(struct io_mapping *mapping, * page faults */ -static inline int +static inline void slow_kernel_write(struct io_mapping *mapping, loff_t gtt_base, int gtt_offset, struct page *user_page, int user_offset, int length) { - char *src_vaddr, *dst_vaddr; - unsigned long unwritten; + char __iomem *dst_vaddr; + char *src_vaddr; - dst_vaddr = io_mapping_map_atomic_wc(mapping, gtt_base); - src_vaddr = kmap_atomic(user_page, KM_USER1); - unwritten = __copy_from_user_inatomic_nocache(dst_vaddr + gtt_offset, - src_vaddr + user_offset, - length); - kunmap_atomic(src_vaddr, KM_USER1); - io_mapping_unmap_atomic(dst_vaddr); - if (unwritten) - return -EFAULT; - return 0; + dst_vaddr = io_mapping_map_wc(mapping, gtt_base); + src_vaddr = kmap(user_page); + + memcpy_toio(dst_vaddr + gtt_offset, + src_vaddr + user_offset, + length); + + kunmap(user_page); + io_mapping_unmap(dst_vaddr); } static inline int @@ -700,18 +699,11 @@ i915_gem_gtt_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj, if ((data_page_offset + page_length) > PAGE_SIZE) page_length = PAGE_SIZE - data_page_offset; - ret = slow_kernel_write(dev_priv->mm.gtt_mapping, - gtt_page_base, gtt_page_offset, - user_pages[data_page_index], - data_page_offset, - page_length); - - /* If we get a fault while copying data, then (presumably) our - * source page isn't available. Return the error and we'll - * retry in the slow path. - */ - if (ret) - goto out_unpin_object; + slow_kernel_write(dev_priv->mm.gtt_mapping, + gtt_page_base, gtt_page_offset, + user_pages[data_page_index], + data_page_offset, + page_length); remain -= page_length; offset += page_length; -- cgit v1.2.3 From ca76482e0f4b64942c704fa11c620ffd1bdd8475 Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Thu, 27 May 2010 10:26:42 +0800 Subject: drm/i915: Fix PIPE_CONTROL command on Sandybridge Sandybridge(Gen6) has new format for PIPE_CONTROL command, the flush and post-op control are in dword 1 now. This changes command length field for difference between Ironlake and Sandybridge. I tried to test this with noop request and issue PIPE_CONTROL command for each sequence and track notify interrupts, which seems work fine. Hopefully we don't need workaround like on Ironlake for Sandybridge. Signed-off-by: Zhenyu Wang Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_ringbuffer.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index f6b84fe8099a..cea4f1a8709e 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -213,7 +213,7 @@ static int init_render_ring(struct drm_device *dev, #define PIPE_CONTROL_FLUSH(addr) \ do { \ OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | \ - PIPE_CONTROL_DEPTH_STALL); \ + PIPE_CONTROL_DEPTH_STALL | 2); \ OUT_RING(addr | PIPE_CONTROL_GLOBAL_GTT); \ OUT_RING(0); \ OUT_RING(0); \ @@ -236,7 +236,19 @@ render_ring_add_request(struct drm_device *dev, u32 seqno; drm_i915_private_t *dev_priv = dev->dev_private; seqno = intel_ring_get_seqno(dev, ring); - if (HAS_PIPE_CONTROL(dev)) { + + if (IS_GEN6(dev)) { + BEGIN_LP_RING(6); + OUT_RING(GFX_OP_PIPE_CONTROL | 3); + OUT_RING(PIPE_CONTROL_QW_WRITE | + PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_IS_FLUSH | + PIPE_CONTROL_NOTIFY); + OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); + OUT_RING(seqno); + OUT_RING(0); + OUT_RING(0); + ADVANCE_LP_RING(); + } else if (HAS_PIPE_CONTROL(dev)) { u32 scratch_addr = dev_priv->seqno_gfx_addr + 128; /* -- cgit v1.2.3 From a1786bd270b08834a735e06c3d5430eeb0baf017 Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Thu, 27 May 2010 10:26:43 +0800 Subject: drm/i915: Unmask interrupt for render engine on Sandybridge With splitted engines on Sandybridge, each engine has its own interrupt control as well. This unmasks the interrupt to properly enable pipe control notify event for render engine. Signed-off-by: Zhenyu Wang Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_reg.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index af7b10853e33..64b0a3afd92b 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -369,6 +369,25 @@ #define BB_ADDR 0x02140 /* 8 bytes */ #define GFX_FLSH_CNTL 0x02170 /* 915+ only */ +/* GEN6 interrupt control */ +#define GEN6_RENDER_HWSTAM 0x2098 +#define GEN6_RENDER_IMR 0x20a8 +#define GEN6_RENDER_CONTEXT_SWITCH_INTERRUPT (1 << 8) +#define GEN6_RENDER_PPGTT_PAGE_FAULT (1 << 7) +#define GEN6_RENDER TIMEOUT_COUNTER_EXPIRED (1 << 6) +#define GEN6_RENDER_L3_PARITY_ERROR (1 << 5) +#define GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT (1 << 4) +#define GEN6_RENDER_COMMAND_PARSER_MASTER_ERROR (1 << 3) +#define GEN6_RENDER_SYNC_STATUS (1 << 2) +#define GEN6_RENDER_DEBUG_INTERRUPT (1 << 1) +#define GEN6_RENDER_USER_INTERRUPT (1 << 0) + +#define GEN6_BLITTER_HWSTAM 0x22098 +#define GEN6_BLITTER_IMR 0x220a8 +#define GEN6_BLITTER_MI_FLUSH_DW_NOTIFY_INTERRUPT (1 << 26) +#define GEN6_BLITTER_COMMAND_PARSER_MASTER_ERROR (1 << 25) +#define GEN6_BLITTER_SYNC_STATUS (1 << 24) +#define GEN6_BLITTER_USER_INTERRUPT (1 << 22) /* * BSD (bit stream decoder instruction and interrupt control register defines * (G4X and Ironlake only) -- cgit v1.2.3 From d5a64513c6a171262082c250592c062e97a2c693 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 9 Apr 2010 01:39:40 +0200 Subject: ACPI / EC / PM: Fix race between EC transactions and system suspend There still is a race that may result in suspending the system in the middle of an EC transaction in progress, which leads to problems (like the kernel thinking that the ACPI global lock is held during resume while in fact it's not). To remove the race condition, modify the ACPI platform suspend and hibernate callbacks so that EC transactions are blocked right after executing the _PTS global control method and are allowed to happen again right after the low-level wakeup. Introduce acpi_pm_freeze() that will disable GPEs, wait until the event queues are empty and block EC transactions. Use it wherever GPEs are disabled in preparation for switching local interrupts off. Introduce acpi_pm_thaw() that will allow EC transactions to happen again and enable runtime GPEs. Use it to balance acpi_pm_freeze() wherever necessary. In addition to that use acpi_ec_resume_transactions_early() to unblock EC transactions as early as reasonably possible during resume. Also unblock EC transactions in acpi_hibernation_finish() and in the analogous suspend routine to make sure that the EC transactions are enabled in all error paths. Fixes https://bugzilla.kernel.org/show_bug.cgi?id=14668 Signed-off-by: Rafael J. Wysocki Reported-and-tested-by: Maxim Levitsky Signed-off-by: Len Brown --- drivers/acpi/ec.c | 10 +++++++++ drivers/acpi/internal.h | 1 + drivers/acpi/sleep.c | 55 ++++++++++++++++++++++++++----------------------- 3 files changed, 40 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index f2234db85da0..2c2b73a2a7c2 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -485,6 +485,16 @@ void acpi_ec_resume_transactions(void) mutex_unlock(&ec->lock); } +void acpi_ec_resume_transactions_early(void) +{ + /* + * Allow transactions to happen again (this function is called from + * atomic context during wakeup, so we don't need to acquire the mutex). + */ + if (first_ec) + clear_bit(EC_FLAGS_FROZEN, &first_ec->flags); +} + static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data) { int result; diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index e28411367239..0ec48c7efa9b 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -51,6 +51,7 @@ int acpi_ec_ecdt_probe(void); int acpi_boot_ec_enable(void); void acpi_ec_suspend_transactions(void); void acpi_ec_resume_transactions(void); +void acpi_ec_resume_transactions_early(void); /*-------------------------------------------------------------------------- Suspend/Resume diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index baa76bbf244a..24741ac65897 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -110,11 +110,13 @@ void __init acpi_old_suspend_ordering(void) } /** - * acpi_pm_disable_gpes - Disable the GPEs. + * acpi_pm_freeze - Disable the GPEs and suspend EC transactions. */ -static int acpi_pm_disable_gpes(void) +static int acpi_pm_freeze(void) { acpi_disable_all_gpes(); + acpi_os_wait_events_complete(NULL); + acpi_ec_suspend_transactions(); return 0; } @@ -142,7 +144,8 @@ static int acpi_pm_prepare(void) int error = __acpi_pm_prepare(); if (!error) - acpi_disable_all_gpes(); + acpi_pm_freeze(); + return error; } @@ -275,6 +278,8 @@ static int acpi_suspend_enter(suspend_state_t pm_state) * acpi_leave_sleep_state will reenable specific GPEs later */ acpi_disable_all_gpes(); + /* Allow EC transactions to happen. */ + acpi_ec_resume_transactions_early(); local_irq_restore(flags); printk(KERN_DEBUG "Back to C!\n"); @@ -286,6 +291,12 @@ static int acpi_suspend_enter(suspend_state_t pm_state) return ACPI_SUCCESS(status) ? 0 : -EFAULT; } +static void acpi_suspend_finish(void) +{ + acpi_ec_resume_transactions(); + acpi_pm_finish(); +} + static int acpi_suspend_state_valid(suspend_state_t pm_state) { u32 acpi_state; @@ -307,7 +318,7 @@ static struct platform_suspend_ops acpi_suspend_ops = { .begin = acpi_suspend_begin, .prepare_late = acpi_pm_prepare, .enter = acpi_suspend_enter, - .wake = acpi_pm_finish, + .wake = acpi_suspend_finish, .end = acpi_pm_end, }; @@ -333,9 +344,9 @@ static int acpi_suspend_begin_old(suspend_state_t pm_state) static struct platform_suspend_ops acpi_suspend_ops_old = { .valid = acpi_suspend_state_valid, .begin = acpi_suspend_begin_old, - .prepare_late = acpi_pm_disable_gpes, + .prepare_late = acpi_pm_freeze, .enter = acpi_suspend_enter, - .wake = acpi_pm_finish, + .wake = acpi_suspend_finish, .end = acpi_pm_end, .recover = acpi_pm_finish, }; @@ -586,6 +597,7 @@ static int acpi_hibernation_enter(void) static void acpi_hibernation_finish(void) { hibernate_nvs_free(); + acpi_ec_resume_transactions(); acpi_pm_finish(); } @@ -606,17 +618,11 @@ static void acpi_hibernation_leave(void) } /* Restore the NVS memory area */ hibernate_nvs_restore(); + /* Allow EC transactions to happen. */ + acpi_ec_resume_transactions_early(); } -static int acpi_pm_pre_restore(void) -{ - acpi_disable_all_gpes(); - acpi_os_wait_events_complete(NULL); - acpi_ec_suspend_transactions(); - return 0; -} - -static void acpi_pm_restore_cleanup(void) +static void acpi_pm_thaw(void) { acpi_ec_resume_transactions(); acpi_enable_all_runtime_gpes(); @@ -630,8 +636,8 @@ static struct platform_hibernation_ops acpi_hibernation_ops = { .prepare = acpi_pm_prepare, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave, - .pre_restore = acpi_pm_pre_restore, - .restore_cleanup = acpi_pm_restore_cleanup, + .pre_restore = acpi_pm_freeze, + .restore_cleanup = acpi_pm_thaw, }; /** @@ -663,12 +669,9 @@ static int acpi_hibernation_begin_old(void) static int acpi_hibernation_pre_snapshot_old(void) { - int error = acpi_pm_disable_gpes(); - - if (!error) - hibernate_nvs_save(); - - return error; + acpi_pm_freeze(); + hibernate_nvs_save(); + return 0; } /* @@ -680,11 +683,11 @@ static struct platform_hibernation_ops acpi_hibernation_ops_old = { .end = acpi_pm_end, .pre_snapshot = acpi_hibernation_pre_snapshot_old, .finish = acpi_hibernation_finish, - .prepare = acpi_pm_disable_gpes, + .prepare = acpi_pm_freeze, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave, - .pre_restore = acpi_pm_pre_restore, - .restore_cleanup = acpi_pm_restore_cleanup, + .pre_restore = acpi_pm_freeze, + .restore_cleanup = acpi_pm_thaw, .recover = acpi_pm_finish, }; #endif /* CONFIG_HIBERNATION */ -- cgit v1.2.3 From fe955682d2153b35dffcf1673dff0491096a3f0a Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 9 Apr 2010 01:40:38 +0200 Subject: ACPI / EC / PM: Fix names of functions that block/unblock EC transactions The names of the functions used for blocking/unblocking EC transactions during suspend/hibernation suggest that the transactions are suspended and resumed by them, while in fact they are disabled and enabled. Rename the functions (and the flag used by them) to better reflect what they really do. Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/ec.c | 16 ++++++++-------- drivers/acpi/internal.h | 6 +++--- drivers/acpi/sleep.c | 12 ++++++------ 3 files changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 2c2b73a2a7c2..3f01f065b533 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -79,7 +79,7 @@ enum { EC_FLAGS_GPE_STORM, /* GPE storm detected */ EC_FLAGS_HANDLERS_INSTALLED, /* Handlers for GPE and * OpReg are installed */ - EC_FLAGS_FROZEN, /* Transactions are suspended */ + EC_FLAGS_BLOCKED, /* Transactions are blocked */ }; /* If we find an EC via the ECDT, we need to keep a ptr to its context */ @@ -293,7 +293,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) if (t->rdata) memset(t->rdata, 0, t->rlen); mutex_lock(&ec->lock); - if (test_bit(EC_FLAGS_FROZEN, &ec->flags)) { + if (test_bit(EC_FLAGS_BLOCKED, &ec->flags)) { status = -EINVAL; goto unlock; } @@ -459,7 +459,7 @@ int ec_transaction(u8 command, EXPORT_SYMBOL(ec_transaction); -void acpi_ec_suspend_transactions(void) +void acpi_ec_block_transactions(void) { struct acpi_ec *ec = first_ec; @@ -468,11 +468,11 @@ void acpi_ec_suspend_transactions(void) mutex_lock(&ec->lock); /* Prevent transactions from being carried out */ - set_bit(EC_FLAGS_FROZEN, &ec->flags); + set_bit(EC_FLAGS_BLOCKED, &ec->flags); mutex_unlock(&ec->lock); } -void acpi_ec_resume_transactions(void) +void acpi_ec_unblock_transactions(void) { struct acpi_ec *ec = first_ec; @@ -481,18 +481,18 @@ void acpi_ec_resume_transactions(void) mutex_lock(&ec->lock); /* Allow transactions to be carried out again */ - clear_bit(EC_FLAGS_FROZEN, &ec->flags); + clear_bit(EC_FLAGS_BLOCKED, &ec->flags); mutex_unlock(&ec->lock); } -void acpi_ec_resume_transactions_early(void) +void acpi_ec_unblock_transactions_early(void) { /* * Allow transactions to happen again (this function is called from * atomic context during wakeup, so we don't need to acquire the mutex). */ if (first_ec) - clear_bit(EC_FLAGS_FROZEN, &first_ec->flags); + clear_bit(EC_FLAGS_BLOCKED, &first_ec->flags); } static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data) diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 0ec48c7efa9b..f8f190ec066e 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -49,9 +49,9 @@ void acpi_early_processor_set_pdc(void); int acpi_ec_init(void); int acpi_ec_ecdt_probe(void); int acpi_boot_ec_enable(void); -void acpi_ec_suspend_transactions(void); -void acpi_ec_resume_transactions(void); -void acpi_ec_resume_transactions_early(void); +void acpi_ec_block_transactions(void); +void acpi_ec_unblock_transactions(void); +void acpi_ec_unblock_transactions_early(void); /*-------------------------------------------------------------------------- Suspend/Resume diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 24741ac65897..504a55edac49 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -116,7 +116,7 @@ static int acpi_pm_freeze(void) { acpi_disable_all_gpes(); acpi_os_wait_events_complete(NULL); - acpi_ec_suspend_transactions(); + acpi_ec_block_transactions(); return 0; } @@ -279,7 +279,7 @@ static int acpi_suspend_enter(suspend_state_t pm_state) */ acpi_disable_all_gpes(); /* Allow EC transactions to happen. */ - acpi_ec_resume_transactions_early(); + acpi_ec_unblock_transactions_early(); local_irq_restore(flags); printk(KERN_DEBUG "Back to C!\n"); @@ -293,7 +293,7 @@ static int acpi_suspend_enter(suspend_state_t pm_state) static void acpi_suspend_finish(void) { - acpi_ec_resume_transactions(); + acpi_ec_unblock_transactions(); acpi_pm_finish(); } @@ -597,7 +597,7 @@ static int acpi_hibernation_enter(void) static void acpi_hibernation_finish(void) { hibernate_nvs_free(); - acpi_ec_resume_transactions(); + acpi_ec_unblock_transactions(); acpi_pm_finish(); } @@ -619,12 +619,12 @@ static void acpi_hibernation_leave(void) /* Restore the NVS memory area */ hibernate_nvs_restore(); /* Allow EC transactions to happen. */ - acpi_ec_resume_transactions_early(); + acpi_ec_unblock_transactions_early(); } static void acpi_pm_thaw(void) { - acpi_ec_resume_transactions(); + acpi_ec_unblock_transactions(); acpi_enable_all_runtime_gpes(); } -- cgit v1.2.3 From 487d9fc5016529d7d77dfe35b666fd3a090e2953 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Tue, 18 May 2010 14:42:51 +0000 Subject: sh: prepare MMCIF driver header file Update the MMCIF driver to include register information and register access functions in the header file. The MMCIF boot code builds on top of this. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/mmc/host/sh_mmcif.c | 125 ++++++++++++++++++-------------------------- 1 file changed, 50 insertions(+), 75 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index eb97830c0344..5d3f824bb5a3 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -30,25 +30,6 @@ #define DRIVER_NAME "sh_mmcif" #define DRIVER_VERSION "2010-04-28" -#define MMCIF_CE_CMD_SET 0x00000000 -#define MMCIF_CE_ARG 0x00000008 -#define MMCIF_CE_ARG_CMD12 0x0000000C -#define MMCIF_CE_CMD_CTRL 0x00000010 -#define MMCIF_CE_BLOCK_SET 0x00000014 -#define MMCIF_CE_CLK_CTRL 0x00000018 -#define MMCIF_CE_BUF_ACC 0x0000001C -#define MMCIF_CE_RESP3 0x00000020 -#define MMCIF_CE_RESP2 0x00000024 -#define MMCIF_CE_RESP1 0x00000028 -#define MMCIF_CE_RESP0 0x0000002C -#define MMCIF_CE_RESP_CMD12 0x00000030 -#define MMCIF_CE_DATA 0x00000034 -#define MMCIF_CE_INT 0x00000040 -#define MMCIF_CE_INT_MASK 0x00000044 -#define MMCIF_CE_HOST_STS1 0x00000048 -#define MMCIF_CE_HOST_STS2 0x0000004C -#define MMCIF_CE_VERSION 0x0000007C - /* CE_CMD_SET */ #define CMD_MASK 0x3f000000 #define CMD_SET_RTYP_NO ((0 << 23) | (0 << 22)) @@ -207,27 +188,17 @@ struct sh_mmcif_host { wait_queue_head_t intr_wait; }; -static inline u32 sh_mmcif_readl(struct sh_mmcif_host *host, unsigned int reg) -{ - return readl(host->addr + reg); -} - -static inline void sh_mmcif_writel(struct sh_mmcif_host *host, - unsigned int reg, u32 val) -{ - writel(val, host->addr + reg); -} static inline void sh_mmcif_bitset(struct sh_mmcif_host *host, unsigned int reg, u32 val) { - writel(val | sh_mmcif_readl(host, reg), host->addr + reg); + writel(val | readl(host->addr + reg), host->addr + reg); } static inline void sh_mmcif_bitclr(struct sh_mmcif_host *host, unsigned int reg, u32 val) { - writel(~val & sh_mmcif_readl(host, reg), host->addr + reg); + writel(~val & readl(host->addr + reg), host->addr + reg); } @@ -253,10 +224,10 @@ static void sh_mmcif_sync_reset(struct sh_mmcif_host *host) { u32 tmp; - tmp = 0x010f0000 & sh_mmcif_readl(host, MMCIF_CE_CLK_CTRL); + tmp = 0x010f0000 & sh_mmcif_readl(host->addr, MMCIF_CE_CLK_CTRL); - sh_mmcif_writel(host, MMCIF_CE_VERSION, SOFT_RST_ON); - sh_mmcif_writel(host, MMCIF_CE_VERSION, SOFT_RST_OFF); + sh_mmcif_writel(host->addr, MMCIF_CE_VERSION, SOFT_RST_ON); + sh_mmcif_writel(host->addr, MMCIF_CE_VERSION, SOFT_RST_OFF); sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, tmp | SRSPTO_256 | SRBSYTO_29 | SRWDTO_29 | SCCSTO_29); /* byte swap on */ @@ -271,12 +242,10 @@ static int sh_mmcif_error_manage(struct sh_mmcif_host *host) host->sd_error = 0; host->wait_int = 0; - state1 = sh_mmcif_readl(host, MMCIF_CE_HOST_STS1); - state2 = sh_mmcif_readl(host, MMCIF_CE_HOST_STS2); - pr_debug("%s: ERR HOST_STS1 = %08x\n", \ - DRIVER_NAME, sh_mmcif_readl(host, MMCIF_CE_HOST_STS1)); - pr_debug("%s: ERR HOST_STS2 = %08x\n", \ - DRIVER_NAME, sh_mmcif_readl(host, MMCIF_CE_HOST_STS2)); + state1 = sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1); + state2 = sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS2); + pr_debug("%s: ERR HOST_STS1 = %08x\n", DRIVER_NAME, state1); + pr_debug("%s: ERR HOST_STS2 = %08x\n", DRIVER_NAME, state2); if (state1 & STS1_CMDSEQ) { sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, CMD_CTRL_BREAK); @@ -288,7 +257,7 @@ static int sh_mmcif_error_manage(struct sh_mmcif_host *host) "command sequence timeout err\n"); return -EIO; } - if (!(sh_mmcif_readl(host, MMCIF_CE_HOST_STS1) + if (!(sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1) & STS1_CMDSEQ)) break; mdelay(1); @@ -330,9 +299,9 @@ static int sh_mmcif_single_read(struct sh_mmcif_host *host, host->wait_int = 0; blocksize = (BLOCK_SIZE_MASK & - sh_mmcif_readl(host, MMCIF_CE_BLOCK_SET)) + 3; + sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET)) + 3; for (i = 0; i < blocksize / 4; i++) - *p++ = sh_mmcif_readl(host, MMCIF_CE_DATA); + *p++ = sh_mmcif_readl(host->addr, MMCIF_CE_DATA); /* buffer read end */ sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFRE); @@ -353,7 +322,8 @@ static int sh_mmcif_multi_read(struct sh_mmcif_host *host, long time; u32 blocksize, i, j, sec, *p; - blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host, MMCIF_CE_BLOCK_SET); + blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host->addr, + MMCIF_CE_BLOCK_SET); for (j = 0; j < data->sg_len; j++) { p = sg_virt(data->sg); host->wait_int = 0; @@ -370,7 +340,8 @@ static int sh_mmcif_multi_read(struct sh_mmcif_host *host, host->wait_int = 0; for (i = 0; i < blocksize / 4; i++) - *p++ = sh_mmcif_readl(host, MMCIF_CE_DATA); + *p++ = sh_mmcif_readl(host->addr, + MMCIF_CE_DATA); } if (j < data->sg_len - 1) data->sg++; @@ -397,9 +368,9 @@ static int sh_mmcif_single_write(struct sh_mmcif_host *host, host->wait_int = 0; blocksize = (BLOCK_SIZE_MASK & - sh_mmcif_readl(host, MMCIF_CE_BLOCK_SET)) + 3; + sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET)) + 3; for (i = 0; i < blocksize / 4; i++) - sh_mmcif_writel(host, MMCIF_CE_DATA, *p++); + sh_mmcif_writel(host->addr, MMCIF_CE_DATA, *p++); /* buffer write end */ sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MDTRANE); @@ -421,7 +392,8 @@ static int sh_mmcif_multi_write(struct sh_mmcif_host *host, long time; u32 i, sec, j, blocksize, *p; - blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host, MMCIF_CE_BLOCK_SET); + blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host->addr, + MMCIF_CE_BLOCK_SET); for (j = 0; j < data->sg_len; j++) { p = sg_virt(data->sg); @@ -439,7 +411,8 @@ static int sh_mmcif_multi_write(struct sh_mmcif_host *host, host->wait_int = 0; for (i = 0; i < blocksize / 4; i++) - sh_mmcif_writel(host, MMCIF_CE_DATA, *p++); + sh_mmcif_writel(host->addr, + MMCIF_CE_DATA, *p++); } if (j < data->sg_len - 1) data->sg++; @@ -451,18 +424,18 @@ static void sh_mmcif_get_response(struct sh_mmcif_host *host, struct mmc_command *cmd) { if (cmd->flags & MMC_RSP_136) { - cmd->resp[0] = sh_mmcif_readl(host, MMCIF_CE_RESP3); - cmd->resp[1] = sh_mmcif_readl(host, MMCIF_CE_RESP2); - cmd->resp[2] = sh_mmcif_readl(host, MMCIF_CE_RESP1); - cmd->resp[3] = sh_mmcif_readl(host, MMCIF_CE_RESP0); + cmd->resp[0] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP3); + cmd->resp[1] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP2); + cmd->resp[2] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP1); + cmd->resp[3] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP0); } else - cmd->resp[0] = sh_mmcif_readl(host, MMCIF_CE_RESP0); + cmd->resp[0] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP0); } static void sh_mmcif_get_cmd12response(struct sh_mmcif_host *host, struct mmc_command *cmd) { - cmd->resp[0] = sh_mmcif_readl(host, MMCIF_CE_RESP_CMD12); + cmd->resp[0] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP_CMD12); } static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, @@ -596,18 +569,19 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host, MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO; if (host->data) { - sh_mmcif_writel(host, MMCIF_CE_BLOCK_SET, 0); - sh_mmcif_writel(host, MMCIF_CE_BLOCK_SET, mrq->data->blksz); + sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET, 0); + sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET, + mrq->data->blksz); } opc = sh_mmcif_set_cmd(host, mrq, cmd, opc); - sh_mmcif_writel(host, MMCIF_CE_INT, 0xD80430C0); - sh_mmcif_writel(host, MMCIF_CE_INT_MASK, mask); + sh_mmcif_writel(host->addr, MMCIF_CE_INT, 0xD80430C0); + sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, mask); /* set arg */ - sh_mmcif_writel(host, MMCIF_CE_ARG, cmd->arg); + sh_mmcif_writel(host->addr, MMCIF_CE_ARG, cmd->arg); host->wait_int = 0; /* set cmd */ - sh_mmcif_writel(host, MMCIF_CE_CMD_SET, opc); + sh_mmcif_writel(host->addr, MMCIF_CE_CMD_SET, opc); time = wait_event_interruptible_timeout(host->intr_wait, host->wait_int == 1 || host->sd_error == 1, host->timeout); @@ -752,43 +726,44 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id) u32 state = 0; int err = 0; - state = sh_mmcif_readl(host, MMCIF_CE_INT); + state = sh_mmcif_readl(host->addr, MMCIF_CE_INT); if (state & INT_RBSYE) { - sh_mmcif_writel(host, MMCIF_CE_INT, ~(INT_RBSYE | INT_CRSPE)); + sh_mmcif_writel(host->addr, MMCIF_CE_INT, + ~(INT_RBSYE | INT_CRSPE)); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MRBSYE); } else if (state & INT_CRSPE) { - sh_mmcif_writel(host, MMCIF_CE_INT, ~INT_CRSPE); + sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_CRSPE); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCRSPE); } else if (state & INT_BUFREN) { - sh_mmcif_writel(host, MMCIF_CE_INT, ~INT_BUFREN); + sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_BUFREN); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); } else if (state & INT_BUFWEN) { - sh_mmcif_writel(host, MMCIF_CE_INT, ~INT_BUFWEN); + sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_BUFWEN); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); } else if (state & INT_CMD12DRE) { - sh_mmcif_writel(host, MMCIF_CE_INT, + sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~(INT_CMD12DRE | INT_CMD12RBE | INT_CMD12CRE | INT_BUFRE)); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCMD12DRE); } else if (state & INT_BUFRE) { - sh_mmcif_writel(host, MMCIF_CE_INT, ~INT_BUFRE); + sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_BUFRE); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFRE); } else if (state & INT_DTRANE) { - sh_mmcif_writel(host, MMCIF_CE_INT, ~INT_DTRANE); + sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_DTRANE); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MDTRANE); } else if (state & INT_CMD12RBE) { - sh_mmcif_writel(host, MMCIF_CE_INT, + sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~(INT_CMD12RBE | INT_CMD12CRE)); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE); } else if (state & INT_ERR_STS) { /* err interrupts */ - sh_mmcif_writel(host, MMCIF_CE_INT, ~state); + sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state); err = 1; } else { pr_debug("%s: Not support int\n", DRIVER_NAME); - sh_mmcif_writel(host, MMCIF_CE_INT, ~state); + sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state); err = 1; } @@ -894,12 +869,12 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev) goto clean_up2; } - sh_mmcif_writel(host, MMCIF_CE_INT_MASK, MASK_ALL); + sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); sh_mmcif_detect(host->mmc); pr_info("%s: driver version %s\n", DRIVER_NAME, DRIVER_VERSION); pr_debug("%s: chip ver H'%04x\n", DRIVER_NAME, - sh_mmcif_readl(host, MMCIF_CE_VERSION) & 0x0000ffff); + sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0x0000ffff); return ret; clean_up2: @@ -917,7 +892,7 @@ static int __devexit sh_mmcif_remove(struct platform_device *pdev) struct sh_mmcif_host *host = platform_get_drvdata(pdev); int irq[2]; - sh_mmcif_writel(host, MMCIF_CE_INT_MASK, MASK_ALL); + sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); irq[0] = platform_get_irq(pdev, 0); irq[1] = platform_get_irq(pdev, 1); -- cgit v1.2.3 From 597b49ec6f19b6df975e2101c42b7b1cfe168280 Mon Sep 17 00:00:00 2001 From: Stefan Achatz Date: Wed, 26 May 2010 20:50:50 +0200 Subject: HID: roccat: remove obsolete comment Removed comment that is obsolete since roccat char device is implemented Signed-off-by: Stefan Achatz Signed-off-by: Jiri Kosina --- drivers/hid/hid-roccat-kone.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c index 17f2dc04f883..3e5b5534f2ed 100644 --- a/drivers/hid/hid-roccat-kone.c +++ b/drivers/hid/hid-roccat-kone.c @@ -22,11 +22,6 @@ * Is it possible to remove and reinstall the urb in raw-event- or any * other handler, or to defer this action to be executed somewhere else? * - * TODO implement notification mechanism for overlong macro execution - * If user wants to execute an overlong macro only the names of macroset - * and macro are given. Should userland tap hidraw or is there an - * additional streaming mechanism? - * * TODO is it possible to overwrite group for sysfs attributes via udev? */ -- cgit v1.2.3 From 22d515723ff1d92eea4d7537a3f8d7674080422b Mon Sep 17 00:00:00 2001 From: Stefan Achatz Date: Wed, 26 May 2010 20:51:28 +0200 Subject: HID: roccat: fix whitespace warning from checkpatch.pl Fixed the following warning of checkpatch.pl: WARNING: space prohibited between function name and open parenthesis '(' Signed-off-by: Stefan Achatz Signed-off-by: Jiri Kosina --- drivers/hid/hid-roccat.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/hid-roccat.h b/drivers/hid/hid-roccat.h index d8aae0c1fa7e..09e864e9f79d 100644 --- a/drivers/hid/hid-roccat.h +++ b/drivers/hid/hid-roccat.h @@ -15,7 +15,7 @@ #include #include -#if defined(CONFIG_HID_ROCCAT) || defined (CONFIG_HID_ROCCAT_MODULE) +#if defined(CONFIG_HID_ROCCAT) || defined(CONFIG_HID_ROCCAT_MODULE) int roccat_connect(struct hid_device *hid); void roccat_disconnect(int minor); int roccat_report_event(int minor, u8 const *data, int len); -- cgit v1.2.3 From 33ccbc320fc38094128c68b2ee0b305884965bd4 Mon Sep 17 00:00:00 2001 From: Stefan Achatz Date: Wed, 26 May 2010 20:52:43 +0200 Subject: HID: roccat: change kone_driver_version to kone_abi_version Renamed the sysfs attribute kone_driver_version to kone_abi_version and simplified returned data to integer. Signed-off-by: Stefan Achatz Signed-off-by: Jiri Kosina --- drivers/hid/hid-roccat-kone.c | 12 ++++++------ drivers/hid/hid-roccat-kone.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c index 3e5b5534f2ed..0ab1df9d68ab 100644 --- a/drivers/hid/hid-roccat-kone.c +++ b/drivers/hid/hid-roccat-kone.c @@ -621,12 +621,12 @@ static ssize_t kone_sysfs_set_startup_profile(struct device *dev, * This file is used by userland software to find devices that are handled by * this driver. This provides a consistent way for actual and older kernels * where this driver replaced usbhid instead of generic-usb. - * Driver capabilities are determined by version number. + * Driver capabilities are determined by returned number. */ -static ssize_t kone_sysfs_show_driver_version(struct device *dev, +static ssize_t kone_sysfs_show_abi_version(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, ROCCAT_KONE_DRIVER_VERSION "\n"); + return snprintf(buf, PAGE_SIZE, ROCCAT_KONE_ABI_VERSION "\n"); } /* @@ -666,8 +666,8 @@ static DEVICE_ATTR(startup_profile, 0660, kone_sysfs_show_startup_profile, kone_sysfs_set_startup_profile); -static DEVICE_ATTR(kone_driver_version, 0440, - kone_sysfs_show_driver_version, NULL); +static DEVICE_ATTR(kone_abi_version, 0440, + kone_sysfs_show_abi_version, NULL); static struct attribute *kone_attributes[] = { &dev_attr_actual_dpi.attr, @@ -676,7 +676,7 @@ static struct attribute *kone_attributes[] = { &dev_attr_firmware_version.attr, &dev_attr_tcu.attr, &dev_attr_startup_profile.attr, - &dev_attr_kone_driver_version.attr, + &dev_attr_kone_abi_version.attr, NULL }; diff --git a/drivers/hid/hid-roccat-kone.h b/drivers/hid/hid-roccat-kone.h index 003e6f81c195..71b14fa40dce 100644 --- a/drivers/hid/hid-roccat-kone.h +++ b/drivers/hid/hid-roccat-kone.h @@ -14,7 +14,7 @@ #include -#define ROCCAT_KONE_DRIVER_VERSION "v0.3.1" +#define ROCCAT_KONE_ABI_VERSION "1" #pragma pack(push) #pragma pack(1) -- cgit v1.2.3 From fdd45ef44cfe84037f44ab386915b55c32a58bf7 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 27 May 2010 09:07:06 -0700 Subject: HID: roccat: fix modules interdependencies hid-roccat-kone calls the hid-roccat module interfaces, so the former should depend on or select the latter to prevent build errors, like: hid-roccat-kone.c:(.text+0x133ed2): undefined reference to `roccat_report_event' hid-roccat-kone.c:(.text+0x133fa8): undefined reference to `roccat_disconnect' hid-roccat-kone.c:(.text+0x1353be): undefined reference to `roccat_connect' Signed-off-by: Randy Dunlap Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 132278fa6240..434099369058 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -358,6 +358,7 @@ config HID_ROCCAT config HID_ROCCAT_KONE tristate "Roccat Kone Mouse support" depends on USB_HID + select HID_ROCCAT ---help--- Support for Roccat Kone mouse. -- cgit v1.2.3 From 829ab5b52b7ee1d92b2373662b82b6f38cae7166 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 31 May 2010 11:57:24 -0700 Subject: Input: s3c2410_ts - fix build error due to ADC Kconfig rename The name of the Kconfig symbol for the ADC has changed as a result of application to more SoCs but the select statement has not been updated, causing linker failures as the ADC core has not been built. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 6703c6b9800a..3b9d5e2105d7 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -156,7 +156,7 @@ config TOUCHSCREEN_FUJITSU config TOUCHSCREEN_S3C2410 tristate "Samsung S3C2410/generic touchscreen input driver" depends on ARCH_S3C2410 || SAMSUNG_DEV_TS - select S3C24XX_ADC + select S3C_ADC help Say Y here if you have the s3c2410 touchscreen. -- cgit v1.2.3 From fbf89f25fc4dc68ba0857aca87e70fa5d2592d81 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 31 May 2010 11:57:24 -0700 Subject: Input: s3c2410_ts - tone down logging The S3C touchscreen driver is logging at LOG_INFO on every stylus up event which spams the console needlessly. Reduce the priority of the message to debug level for some peace and quiet. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/s3c2410_ts.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/s3c2410_ts.c b/drivers/input/touchscreen/s3c2410_ts.c index ac5d0f9b0cb1..6085d12fd561 100644 --- a/drivers/input/touchscreen/s3c2410_ts.c +++ b/drivers/input/touchscreen/s3c2410_ts.c @@ -173,7 +173,7 @@ static irqreturn_t stylus_irq(int irq, void *dev_id) if (down) s3c_adc_start(ts.client, 0, 1 << ts.shift); else - dev_info(ts.dev, "%s: count=%d\n", __func__, ts.count); + dev_dbg(ts.dev, "%s: count=%d\n", __func__, ts.count); if (ts.features & FEAT_PEN_IRQ) { /* Clear pen down/up interrupt */ -- cgit v1.2.3 From 7e71f8a59e1c9adbbc3b737b4b818c8aa4169d0e Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 28 May 2010 11:21:54 +0200 Subject: drm/vmwgfx: Assume larger framebuffer max size. Signed-off-by: Jakob Bornecrantz Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index bbc7c4c30bc7..642bcd7a1500 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -765,8 +765,9 @@ int vmw_kms_init(struct vmw_private *dev_priv) dev->mode_config.funcs = &vmw_kms_funcs; dev->mode_config.min_width = 1; dev->mode_config.min_height = 1; - dev->mode_config.max_width = dev_priv->fb_max_width; - dev->mode_config.max_height = dev_priv->fb_max_height; + /* assumed largest fb size */ + dev->mode_config.max_width = 8192; + dev->mode_config.max_height = 8192; ret = vmw_kms_init_legacy_display_system(dev_priv); -- cgit v1.2.3 From 6a591a96d7315fbe81acc33e20bab4956d1f02a3 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 28 May 2010 11:21:55 +0200 Subject: drm/vmwgfx: Fix single framebuffer detection. V2: Fix a typo. Signed-off-by: Jakob Bornecrantz Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index 90891593bf6c..a348fec22137 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -130,6 +130,7 @@ static int vmw_ldu_del_active(struct vmw_private *vmw_priv, if (list_empty(&ldu->active)) return 0; + /* Must init otherwise list_empty(&ldu->active) will not work. */ list_del_init(&ldu->active); if (--(ld->num_active) == 0) { BUG_ON(!ld->fb); @@ -208,6 +209,8 @@ static int vmw_ldu_crtc_set_config(struct drm_mode_set *set) /* ldu only supports one fb active at the time */ if (dev_priv->ldu_priv->fb && vfb && + !(dev_priv->ldu_priv->num_active == 1 && + !list_empty(&ldu->active)) && dev_priv->ldu_priv->fb != vfb) { DRM_ERROR("Multiple framebuffers not supported\n"); return -EINVAL; -- cgit v1.2.3 From 04e9e94dba3e564ce810cedab88e957dfd681b4a Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 28 May 2010 11:21:56 +0200 Subject: drm/vmwgfx: Make sure to unpin old and pin new framebuffer. Signed-off-by: Jakob Bornecrantz Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index a348fec22137..e1b3cf539b4a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -150,6 +150,15 @@ static int vmw_ldu_add_active(struct vmw_private *vmw_priv, struct vmw_legacy_display_unit *entry; struct list_head *at; + BUG_ON(!ld->num_active && ld->fb); + if (vfb != ld->fb) { + if (ld->fb && ld->fb->unpin) + ld->fb->unpin(ld->fb); + if (vfb->pin) + vfb->pin(vfb); + ld->fb = vfb; + } + if (!list_empty(&ldu->active)) return 0; @@ -162,12 +171,8 @@ static int vmw_ldu_add_active(struct vmw_private *vmw_priv, } list_add(&ldu->active, at); - if (ld->num_active++ == 0) { - BUG_ON(ld->fb); - if (vfb->pin) - vfb->pin(vfb); - ld->fb = vfb; - } + + ld->num_active++; return 0; } -- cgit v1.2.3 From 1925d4565888eb313cc923372da6a08bbfb3a859 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 28 May 2010 11:21:57 +0200 Subject: drm/vmwgfx: Add kernel throttling support. Bump minor. The throttle_us member in the execbuf argument is now honored. If the member is 0, no waiting for lag will occur, which guarantees backwards compatibility with well-behaved clients. Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/Makefile | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 27 ++++- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 9 ++ drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | 173 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c | 5 +- drivers/gpu/drm/vmwgfx/vmwgfx_irq.c | 17 +++- 6 files changed, 227 insertions(+), 6 deletions(-) create mode 100644 drivers/gpu/drm/vmwgfx/vmwgfx_fence.c (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/Makefile b/drivers/gpu/drm/vmwgfx/Makefile index 1a3cb6816d1c..4505e17df3f5 100644 --- a/drivers/gpu/drm/vmwgfx/Makefile +++ b/drivers/gpu/drm/vmwgfx/Makefile @@ -4,6 +4,6 @@ ccflags-y := -Iinclude/drm vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \ vmwgfx_fb.o vmwgfx_ioctl.o vmwgfx_resource.o vmwgfx_buffer.o \ vmwgfx_fifo.o vmwgfx_irq.o vmwgfx_ldu.o vmwgfx_ttm_glue.o \ - vmwgfx_overlay.o + vmwgfx_overlay.o vmwgfx_fence.o obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 356dc935ec13..9a0a82b41c3e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -41,7 +41,7 @@ #define VMWGFX_DRIVER_DATE "20100209" #define VMWGFX_DRIVER_MAJOR 1 -#define VMWGFX_DRIVER_MINOR 0 +#define VMWGFX_DRIVER_MINOR 1 #define VMWGFX_DRIVER_PATCHLEVEL 0 #define VMWGFX_FILE_PAGE_OFFSET 0x00100000 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) @@ -102,6 +102,13 @@ struct vmw_surface { struct vmw_cursor_snooper snooper; }; +struct vmw_fence_queue { + struct list_head head; + struct timespec lag; + struct timespec lag_time; + spinlock_t lock; +}; + struct vmw_fifo_state { unsigned long reserved_size; __le32 *dynamic_buffer; @@ -115,6 +122,7 @@ struct vmw_fifo_state { uint32_t capabilities; struct mutex fifo_mutex; struct rw_semaphore rwsem; + struct vmw_fence_queue fence_queue; }; struct vmw_relocation { @@ -441,6 +449,23 @@ extern int vmw_fallback_wait(struct vmw_private *dev_priv, uint32_t sequence, bool interruptible, unsigned long timeout); +extern void vmw_update_sequence(struct vmw_private *dev_priv, + struct vmw_fifo_state *fifo_state); + + +/** + * Rudimentary fence objects currently used only for throttling - + * vmwgfx_fence.c + */ + +extern void vmw_fence_queue_init(struct vmw_fence_queue *queue); +extern void vmw_fence_queue_takedown(struct vmw_fence_queue *queue); +extern int vmw_fence_push(struct vmw_fence_queue *queue, + uint32_t sequence); +extern int vmw_fence_pull(struct vmw_fence_queue *queue, + uint32_t signaled_sequence); +extern int vmw_wait_lag(struct vmw_private *dev_priv, + struct vmw_fence_queue *queue, uint32_t us); /** * Kernel framebuffer - vmwgfx_fb.c diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index dbd36b8910cf..bdd67cf83315 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -669,6 +669,15 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data, goto out_err; vmw_apply_relocations(sw_context); + + if (arg->throttle_us) { + ret = vmw_wait_lag(dev_priv, &dev_priv->fifo.fence_queue, + arg->throttle_us); + + if (unlikely(ret != 0)) + goto out_err; + } + vmw_fifo_commit(dev_priv, arg->command_size); ret = vmw_fifo_send_fence(dev_priv, &sequence); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c new file mode 100644 index 000000000000..61eacc1b5ca3 --- /dev/null +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c @@ -0,0 +1,173 @@ +/************************************************************************** + * + * Copyright (C) 2010 VMware, Inc., Palo Alto, CA., USA + * All Rights Reserved. + * + * 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, sub license, 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 (including the + * next paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + + +#include "vmwgfx_drv.h" + +struct vmw_fence { + struct list_head head; + uint32_t sequence; + struct timespec submitted; +}; + +void vmw_fence_queue_init(struct vmw_fence_queue *queue) +{ + INIT_LIST_HEAD(&queue->head); + queue->lag = ns_to_timespec(0); + getrawmonotonic(&queue->lag_time); + spin_lock_init(&queue->lock); +} + +void vmw_fence_queue_takedown(struct vmw_fence_queue *queue) +{ + struct vmw_fence *fence, *next; + + spin_lock(&queue->lock); + list_for_each_entry_safe(fence, next, &queue->head, head) { + kfree(fence); + } + spin_unlock(&queue->lock); +} + +int vmw_fence_push(struct vmw_fence_queue *queue, + uint32_t sequence) +{ + struct vmw_fence *fence = kmalloc(sizeof(*fence), GFP_KERNEL); + + if (unlikely(!fence)) + return -ENOMEM; + + fence->sequence = sequence; + getrawmonotonic(&fence->submitted); + spin_lock(&queue->lock); + list_add_tail(&fence->head, &queue->head); + spin_unlock(&queue->lock); + + return 0; +} + +int vmw_fence_pull(struct vmw_fence_queue *queue, + uint32_t signaled_sequence) +{ + struct vmw_fence *fence, *next; + struct timespec now; + bool updated = false; + + spin_lock(&queue->lock); + getrawmonotonic(&now); + + if (list_empty(&queue->head)) { + queue->lag = ns_to_timespec(0); + queue->lag_time = now; + updated = true; + goto out_unlock; + } + + list_for_each_entry_safe(fence, next, &queue->head, head) { + if (signaled_sequence - fence->sequence > (1 << 30)) + continue; + + queue->lag = timespec_sub(now, fence->submitted); + queue->lag_time = now; + updated = true; + list_del(&fence->head); + kfree(fence); + } + +out_unlock: + spin_unlock(&queue->lock); + + return (updated) ? 0 : -EBUSY; +} + +static struct timespec vmw_timespec_add(struct timespec t1, + struct timespec t2) +{ + t1.tv_sec += t2.tv_sec; + t1.tv_nsec += t2.tv_nsec; + if (t1.tv_nsec >= 1000000000L) { + t1.tv_sec += 1; + t1.tv_nsec -= 1000000000L; + } + + return t1; +} + +static struct timespec vmw_fifo_lag(struct vmw_fence_queue *queue) +{ + struct timespec now; + + spin_lock(&queue->lock); + getrawmonotonic(&now); + queue->lag = vmw_timespec_add(queue->lag, + timespec_sub(now, queue->lag_time)); + queue->lag_time = now; + spin_unlock(&queue->lock); + return queue->lag; +} + + +static bool vmw_lag_lt(struct vmw_fence_queue *queue, + uint32_t us) +{ + struct timespec lag, cond; + + cond = ns_to_timespec((s64) us * 1000); + lag = vmw_fifo_lag(queue); + return (timespec_compare(&lag, &cond) < 1); +} + +int vmw_wait_lag(struct vmw_private *dev_priv, + struct vmw_fence_queue *queue, uint32_t us) +{ + struct vmw_fence *fence; + uint32_t sequence; + int ret; + + while (!vmw_lag_lt(queue, us)) { + spin_lock(&queue->lock); + if (list_empty(&queue->head)) + sequence = atomic_read(&dev_priv->fence_seq); + else { + fence = list_first_entry(&queue->head, + struct vmw_fence, head); + sequence = fence->sequence; + } + spin_unlock(&queue->lock); + + ret = vmw_wait_fence(dev_priv, false, sequence, true, + 3*HZ); + + if (unlikely(ret != 0)) + return ret; + + (void) vmw_fence_pull(queue, sequence); + } + return 0; +} + + diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c index 39d43a01d846..a8e5445f94ec 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c @@ -120,7 +120,7 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) atomic_set(&dev_priv->fence_seq, dev_priv->last_read_sequence); iowrite32(dev_priv->last_read_sequence, fifo_mem + SVGA_FIFO_FENCE); - + vmw_fence_queue_init(&fifo->fence_queue); return vmw_fifo_send_fence(dev_priv, &dummy); out_err: vfree(fifo->static_buffer); @@ -159,6 +159,7 @@ void vmw_fifo_release(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) dev_priv->enable_state); mutex_unlock(&dev_priv->hw_mutex); + vmw_fence_queue_takedown(&fifo->fence_queue); if (likely(fifo->last_buffer != NULL)) { vfree(fifo->last_buffer); @@ -484,6 +485,8 @@ int vmw_fifo_send_fence(struct vmw_private *dev_priv, uint32_t *sequence) fifo_state->last_buffer_add = true; vmw_fifo_commit(dev_priv, bytes); fifo_state->last_buffer_add = false; + (void) vmw_fence_push(&fifo_state->fence_queue, *sequence); + vmw_update_sequence(dev_priv, fifo_state); out_err: return ret; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c index 4d7cb5393860..e92298a6a383 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c @@ -64,22 +64,33 @@ static bool vmw_fifo_idle(struct vmw_private *dev_priv, uint32_t sequence) return (busy == 0); } +void vmw_update_sequence(struct vmw_private *dev_priv, + struct vmw_fifo_state *fifo_state) +{ + __le32 __iomem *fifo_mem = dev_priv->mmio_virt; + + uint32_t sequence = ioread32(fifo_mem + SVGA_FIFO_FENCE); + + if (dev_priv->last_read_sequence != sequence) { + dev_priv->last_read_sequence = sequence; + vmw_fence_pull(&fifo_state->fence_queue, sequence); + } +} bool vmw_fence_signaled(struct vmw_private *dev_priv, uint32_t sequence) { - __le32 __iomem *fifo_mem = dev_priv->mmio_virt; struct vmw_fifo_state *fifo_state; bool ret; if (likely(dev_priv->last_read_sequence - sequence < VMW_FENCE_WRAP)) return true; - dev_priv->last_read_sequence = ioread32(fifo_mem + SVGA_FIFO_FENCE); + fifo_state = &dev_priv->fifo; + vmw_update_sequence(dev_priv, fifo_state); if (likely(dev_priv->last_read_sequence - sequence < VMW_FENCE_WRAP)) return true; - fifo_state = &dev_priv->fifo; if (!(fifo_state->capabilities & SVGA_FIFO_CAP_FENCE) && vmw_fifo_idle(dev_priv, sequence)) return true; -- cgit v1.2.3 From 1ae1ddd5e99bbc067414ff571ac18d4312b4c8cf Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 28 May 2010 11:21:58 +0200 Subject: drm/vmwgfx: Get connector status from detection function. Also make sure the ldu::active member is properly initialized. Part of fix by Michel Daenzer . Signed-off-by: Jakob Bornecrantz Signed-off-by: Michel Daenzer Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index e1b3cf539b4a..fefef9012c4b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -456,13 +456,11 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) encoder = &ldu->base.encoder; connector = &ldu->base.connector; + INIT_LIST_HEAD(&ldu->active); + drm_connector_init(dev, connector, &vmw_legacy_connector_funcs, DRM_MODE_CONNECTOR_LVDS); - /* Initial status */ - if (unit == 0) - connector->status = connector_status_connected; - else - connector->status = connector_status_disconnected; + connector->status = vmw_ldu_connector_detect(connector); drm_encoder_init(dev, encoder, &vmw_legacy_encoder_funcs, DRM_MODE_ENCODER_LVDS); @@ -470,8 +468,6 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) encoder->possible_crtcs = (1 << unit); encoder->possible_clones = 0; - INIT_LIST_HEAD(&ldu->active); - drm_crtc_init(dev, crtc, &vmw_legacy_crtc_funcs); drm_connector_attach_property(connector, -- cgit v1.2.3 From d7e1958dbe4a7b81d4cab5fab545a068501b967e Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 28 May 2010 11:21:59 +0200 Subject: drm/vmwgfx: Support older hardware. V2: Fix a couple of typos. Signed-off-by: Jakob Bornecrantz Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 9 ++++ drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 5 +++ drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 81 +++++++++++++----------------------- drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c | 18 ++++++++ drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 72 ++++++++++++++------------------ drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 70 +++++++++++++++++++++++++------ 6 files changed, 148 insertions(+), 107 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 0c9c0811f42d..bdd87dc9e7b1 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -318,6 +318,15 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) goto out_err3; } + /* Need mmio memory to check for fifo pitchlock cap. */ + if (!(dev_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY) && + !(dev_priv->capabilities & SVGA_CAP_PITCHLOCK) && + !vmw_fifo_have_pitchlock(dev_priv)) { + ret = -ENOSYS; + DRM_ERROR("Hardware has no pitchlock\n"); + goto out_err4; + } + dev_priv->tdev = ttm_object_device_init (dev_priv->mem_global_ref.object, 12); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 9a0a82b41c3e..1341adef408d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -187,6 +187,7 @@ struct vmw_private { uint32_t vga_red_mask; uint32_t vga_blue_mask; uint32_t vga_green_mask; + uint32_t vga_pitchlock; /* * Framebuffer info. @@ -401,6 +402,7 @@ extern int vmw_fifo_send_fence(struct vmw_private *dev_priv, extern void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason); extern int vmw_fifo_mmap(struct file *filp, struct vm_area_struct *vma); extern bool vmw_fifo_have_3d(struct vmw_private *dev_priv); +extern bool vmw_fifo_have_pitchlock(struct vmw_private *dev_priv); /** * TTM glue - vmwgfx_ttm_glue.c @@ -491,6 +493,9 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf, struct ttm_object_file *tfile, struct ttm_buffer_object *bo, SVGA3dCmdHeader *header); +void vmw_kms_write_svga(struct vmw_private *vmw_priv, + unsigned width, unsigned height, unsigned pitch, + unsigned bbp, unsigned depth); /** * Overlay control - vmwgfx_overlay.c diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index 7421aaad8d09..fb66e62b8e2c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -132,16 +132,14 @@ static int vmw_fb_check_var(struct fb_var_screeninfo *var, return -EINVAL; } - /* without multimon its hard to resize */ - if (!(vmw_priv->capabilities & SVGA_CAP_MULTIMON) && - (var->xres != par->max_width || - var->yres != par->max_height)) { - DRM_ERROR("Tried to resize, but we don't have multimon\n"); + if (!(vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY) && + (var->xoffset != 0 || var->yoffset != 0)) { + DRM_ERROR("Can not handle panning without display topology\n"); return -EINVAL; } - if (var->xres > par->max_width || - var->yres > par->max_height) { + if ((var->xoffset + var->xres) > par->max_width || + (var->yoffset + var->yres) > par->max_height) { DRM_ERROR("Requested geom can not fit in framebuffer\n"); return -EINVAL; } @@ -154,8 +152,8 @@ static int vmw_fb_set_par(struct fb_info *info) struct vmw_fb_par *par = info->par; struct vmw_private *vmw_priv = par->vmw_priv; - if (vmw_priv->capabilities & SVGA_CAP_MULTIMON) { - vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1); + if (vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY) { + vmw_write(vmw_priv, SVGA_REG_ENABLE, 0); vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, 0); vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true); vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, 0); @@ -164,18 +162,11 @@ static int vmw_fb_set_par(struct fb_info *info) vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, 0); vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); - vmw_write(vmw_priv, SVGA_REG_ENABLE, 1); - vmw_write(vmw_priv, SVGA_REG_WIDTH, par->max_width); - vmw_write(vmw_priv, SVGA_REG_HEIGHT, par->max_height); - vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, par->bpp); - vmw_write(vmw_priv, SVGA_REG_DEPTH, par->depth); - vmw_write(vmw_priv, SVGA_REG_RED_MASK, 0x00ff0000); - vmw_write(vmw_priv, SVGA_REG_GREEN_MASK, 0x0000ff00); - vmw_write(vmw_priv, SVGA_REG_BLUE_MASK, 0x000000ff); + vmw_kms_write_svga(vmw_priv, info->var.xres, info->var.yres, + info->fix.line_length, + par->bpp, par->depth); /* TODO check if pitch and offset changes */ - - vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1); vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, 0); vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true); vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, info->var.xoffset); @@ -183,13 +174,22 @@ static int vmw_fb_set_par(struct fb_info *info) vmw_write(vmw_priv, SVGA_REG_DISPLAY_WIDTH, info->var.xres); vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, info->var.yres); vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); + vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1); + vmw_write(vmw_priv, SVGA_REG_ENABLE, 1); } else { - vmw_write(vmw_priv, SVGA_REG_WIDTH, info->var.xres); - vmw_write(vmw_priv, SVGA_REG_HEIGHT, info->var.yres); + vmw_write(vmw_priv, SVGA_REG_ENABLE, 0); + vmw_kms_write_svga(vmw_priv, info->var.xres, info->var.yres, + info->fix.line_length, + par->bpp, par->depth); + vmw_write(vmw_priv, SVGA_REG_ENABLE, 1); - /* TODO check if pitch and offset changes */ } + /* This is really helpful since if this fails the user + * can probably not see anything on the screen. + */ + WARN_ON(vmw_read(vmw_priv, SVGA_REG_FB_OFFSET) != 0); + return 0; } @@ -416,48 +416,23 @@ int vmw_fb_init(struct vmw_private *vmw_priv) unsigned fb_bbp, fb_depth, fb_offset, fb_pitch, fb_size; int ret; + /* XXX These shouldn't be hardcoded. */ initial_width = 800; initial_height = 600; fb_bbp = 32; fb_depth = 24; - if (vmw_priv->capabilities & SVGA_CAP_MULTIMON) { - fb_width = min(vmw_priv->fb_max_width, (unsigned)2048); - fb_height = min(vmw_priv->fb_max_height, (unsigned)2048); - } else { - fb_width = min(vmw_priv->fb_max_width, initial_width); - fb_height = min(vmw_priv->fb_max_height, initial_height); - } + /* XXX As shouldn't these be as well. */ + fb_width = min(vmw_priv->fb_max_width, (unsigned)2048); + fb_height = min(vmw_priv->fb_max_height, (unsigned)2048); initial_width = min(fb_width, initial_width); initial_height = min(fb_height, initial_height); - vmw_write(vmw_priv, SVGA_REG_WIDTH, fb_width); - vmw_write(vmw_priv, SVGA_REG_HEIGHT, fb_height); - vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, fb_bbp); - vmw_write(vmw_priv, SVGA_REG_DEPTH, fb_depth); - vmw_write(vmw_priv, SVGA_REG_RED_MASK, 0x00ff0000); - vmw_write(vmw_priv, SVGA_REG_GREEN_MASK, 0x0000ff00); - vmw_write(vmw_priv, SVGA_REG_BLUE_MASK, 0x000000ff); - - fb_size = vmw_read(vmw_priv, SVGA_REG_FB_SIZE); + fb_pitch = fb_width * fb_bbp / 8; + fb_size = fb_pitch * fb_height; fb_offset = vmw_read(vmw_priv, SVGA_REG_FB_OFFSET); - fb_pitch = vmw_read(vmw_priv, SVGA_REG_BYTES_PER_LINE); - - DRM_DEBUG("width %u\n", vmw_read(vmw_priv, SVGA_REG_MAX_WIDTH)); - DRM_DEBUG("height %u\n", vmw_read(vmw_priv, SVGA_REG_MAX_HEIGHT)); - DRM_DEBUG("width %u\n", vmw_read(vmw_priv, SVGA_REG_WIDTH)); - DRM_DEBUG("height %u\n", vmw_read(vmw_priv, SVGA_REG_HEIGHT)); - DRM_DEBUG("bpp %u\n", vmw_read(vmw_priv, SVGA_REG_BITS_PER_PIXEL)); - DRM_DEBUG("depth %u\n", vmw_read(vmw_priv, SVGA_REG_DEPTH)); - DRM_DEBUG("bpl %u\n", vmw_read(vmw_priv, SVGA_REG_BYTES_PER_LINE)); - DRM_DEBUG("r mask %08x\n", vmw_read(vmw_priv, SVGA_REG_RED_MASK)); - DRM_DEBUG("g mask %08x\n", vmw_read(vmw_priv, SVGA_REG_GREEN_MASK)); - DRM_DEBUG("b mask %08x\n", vmw_read(vmw_priv, SVGA_REG_BLUE_MASK)); - DRM_DEBUG("fb_offset 0x%08x\n", fb_offset); - DRM_DEBUG("fb_pitch %u\n", fb_pitch); - DRM_DEBUG("fb_size %u kiB\n", fb_size / 1024); info = framebuffer_alloc(sizeof(*par), device); if (!info) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c index a8e5445f94ec..e6a1eb7ea954 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c @@ -34,6 +34,9 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv) __le32 __iomem *fifo_mem = dev_priv->mmio_virt; uint32_t fifo_min, hwversion; + if (!(dev_priv->capabilities & SVGA_CAP_EXTENDED_FIFO)) + return false; + fifo_min = ioread32(fifo_mem + SVGA_FIFO_MIN); if (fifo_min <= SVGA_FIFO_3D_HWVERSION * sizeof(unsigned int)) return false; @@ -48,6 +51,21 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv) return true; } +bool vmw_fifo_have_pitchlock(struct vmw_private *dev_priv) +{ + __le32 __iomem *fifo_mem = dev_priv->mmio_virt; + uint32_t caps; + + if (!(dev_priv->capabilities & SVGA_CAP_EXTENDED_FIFO)) + return false; + + caps = ioread32(fifo_mem + SVGA_FIFO_CAPABILITIES); + if (caps & SVGA_FIFO_CAP_PITCHLOCK) + return true; + + return false; +} + int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) { __le32 __iomem *fifo_mem = dev_priv->mmio_virt; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 642bcd7a1500..c748207e9e1c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -596,31 +596,11 @@ static int vmw_framebuffer_dmabuf_pin(struct vmw_framebuffer *vfb) vmw_framebuffer_to_vfbd(&vfb->base); int ret; + vmw_overlay_pause_all(dev_priv); ret = vmw_dmabuf_to_start_of_vram(dev_priv, vfbd->buffer); - if (dev_priv->capabilities & SVGA_CAP_MULTIMON) { - vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1); - vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, 0); - vmw_write(dev_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true); - vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_X, 0); - vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_Y, 0); - vmw_write(dev_priv, SVGA_REG_DISPLAY_WIDTH, 0); - vmw_write(dev_priv, SVGA_REG_DISPLAY_HEIGHT, 0); - vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); - - vmw_write(dev_priv, SVGA_REG_ENABLE, 1); - vmw_write(dev_priv, SVGA_REG_WIDTH, vfb->base.width); - vmw_write(dev_priv, SVGA_REG_HEIGHT, vfb->base.height); - vmw_write(dev_priv, SVGA_REG_BITS_PER_PIXEL, vfb->base.bits_per_pixel); - vmw_write(dev_priv, SVGA_REG_DEPTH, vfb->base.depth); - vmw_write(dev_priv, SVGA_REG_RED_MASK, 0x00ff0000); - vmw_write(dev_priv, SVGA_REG_GREEN_MASK, 0x0000ff00); - vmw_write(dev_priv, SVGA_REG_BLUE_MASK, 0x000000ff); - } else - WARN_ON(true); - vmw_overlay_resume_all(dev_priv); return 0; @@ -668,7 +648,7 @@ int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv, /* XXX get the first 3 from the surface info */ vfbd->base.base.bits_per_pixel = 32; - vfbd->base.base.pitch = width * 32 / 4; + vfbd->base.base.pitch = width * vfbd->base.base.bits_per_pixel / 8; vfbd->base.base.depth = 24; vfbd->base.base.width = width; vfbd->base.base.height = height; @@ -827,24 +807,25 @@ out: return ret; } -int vmw_kms_save_vga(struct vmw_private *vmw_priv) +void vmw_kms_write_svga(struct vmw_private *vmw_priv, + unsigned width, unsigned height, unsigned pitch, + unsigned bbp, unsigned depth) { - /* - * setup a single multimon monitor with the size - * of 0x0, this stops the UI from resizing when we - * change the framebuffer size - */ - if (vmw_priv->capabilities & SVGA_CAP_MULTIMON) { - vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, 0); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, 0); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_Y, 0); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_WIDTH, 0); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, 0); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); - } + if (vmw_priv->capabilities & SVGA_CAP_PITCHLOCK) + vmw_write(vmw_priv, SVGA_REG_PITCHLOCK, pitch); + else if (vmw_fifo_have_pitchlock(vmw_priv)) + iowrite32(pitch, vmw_priv->mmio_virt + SVGA_FIFO_PITCHLOCK); + vmw_write(vmw_priv, SVGA_REG_WIDTH, width); + vmw_write(vmw_priv, SVGA_REG_HEIGHT, height); + vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, bbp); + vmw_write(vmw_priv, SVGA_REG_DEPTH, depth); + vmw_write(vmw_priv, SVGA_REG_RED_MASK, 0x00ff0000); + vmw_write(vmw_priv, SVGA_REG_GREEN_MASK, 0x0000ff00); + vmw_write(vmw_priv, SVGA_REG_BLUE_MASK, 0x000000ff); +} +int vmw_kms_save_vga(struct vmw_private *vmw_priv) +{ vmw_priv->vga_width = vmw_read(vmw_priv, SVGA_REG_WIDTH); vmw_priv->vga_height = vmw_read(vmw_priv, SVGA_REG_HEIGHT); vmw_priv->vga_bpp = vmw_read(vmw_priv, SVGA_REG_BITS_PER_PIXEL); @@ -853,6 +834,12 @@ int vmw_kms_save_vga(struct vmw_private *vmw_priv) vmw_priv->vga_red_mask = vmw_read(vmw_priv, SVGA_REG_RED_MASK); vmw_priv->vga_green_mask = vmw_read(vmw_priv, SVGA_REG_GREEN_MASK); vmw_priv->vga_blue_mask = vmw_read(vmw_priv, SVGA_REG_BLUE_MASK); + if (vmw_priv->capabilities & SVGA_CAP_PITCHLOCK) + vmw_priv->vga_pitchlock = + vmw_read(vmw_priv, SVGA_REG_PITCHLOCK); + else if (vmw_fifo_have_pitchlock(vmw_priv)) + vmw_priv->vga_pitchlock = + ioread32(vmw_priv->mmio_virt + SVGA_FIFO_PITCHLOCK); return 0; } @@ -867,9 +854,12 @@ int vmw_kms_restore_vga(struct vmw_private *vmw_priv) vmw_write(vmw_priv, SVGA_REG_RED_MASK, vmw_priv->vga_red_mask); vmw_write(vmw_priv, SVGA_REG_GREEN_MASK, vmw_priv->vga_green_mask); vmw_write(vmw_priv, SVGA_REG_BLUE_MASK, vmw_priv->vga_blue_mask); - - /* TODO check for multimon */ - vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 0); + if (vmw_priv->capabilities & SVGA_CAP_PITCHLOCK) + vmw_write(vmw_priv, SVGA_REG_PITCHLOCK, + vmw_priv->vga_pitchlock); + else if (vmw_fifo_have_pitchlock(vmw_priv)) + iowrite32(vmw_priv->vga_pitchlock, + vmw_priv->mmio_virt + SVGA_FIFO_PITCHLOCK); return 0; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index fefef9012c4b..8fde9bf8be41 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -38,6 +38,7 @@ struct vmw_legacy_display { struct list_head active; unsigned num_active; + unsigned last_num_active; struct vmw_framebuffer *fb; }; @@ -88,12 +89,37 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv) { struct vmw_legacy_display *lds = dev_priv->ldu_priv; struct vmw_legacy_display_unit *entry; - struct drm_crtc *crtc; + struct drm_framebuffer *fb = NULL; + struct drm_crtc *crtc = NULL; int i = 0; - /* to stop the screen from changing size on resize */ - vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 0); - for (i = 0; i < lds->num_active; i++) { + /* If there is no display topology the host just assumes + * that the guest will set the same layout as the host. + */ + if (!(dev_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY)) { + int w = 0, h = 0; + list_for_each_entry(entry, &lds->active, active) { + crtc = &entry->base.crtc; + w = max(w, crtc->x + crtc->mode.hdisplay); + h = max(h, crtc->y + crtc->mode.vdisplay); + i++; + } + + if (crtc == NULL) + return 0; + fb = entry->base.crtc.fb; + + vmw_write(dev_priv, SVGA_REG_ENABLE, 0); + vmw_kms_write_svga(dev_priv, w, h, fb->pitch, + fb->bits_per_pixel, fb->depth); + vmw_write(dev_priv, SVGA_REG_ENABLE, 1); + + return 0; + } + + vmw_write(dev_priv, SVGA_REG_ENABLE, 0); + + for (i = 0; i < lds->last_num_active; i++) { vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, i); vmw_write(dev_priv, SVGA_REG_DISPLAY_IS_PRIMARY, !i); vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_X, 0); @@ -103,8 +129,14 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv) vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); } - /* Now set the mode */ - vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, lds->num_active); + if (!list_empty(&lds->active)) { + entry = list_entry(lds->active.next, typeof(*entry), active); + fb = entry->base.crtc.fb; + + vmw_kms_write_svga(dev_priv, fb->width, fb->height, fb->pitch, + fb->bits_per_pixel, fb->depth); + } + i = 0; list_for_each_entry(entry, &lds->active, active) { crtc = &entry->base.crtc; @@ -120,6 +152,14 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv) i++; } + /* Make sure we always show something. */ + vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, i ? i : 1); + vmw_write(dev_priv, SVGA_REG_ENABLE, 1); + + BUG_ON(i != lds->num_active); + + lds->last_num_active = lds->num_active; + return 0; } @@ -491,18 +531,22 @@ int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv) INIT_LIST_HEAD(&dev_priv->ldu_priv->active); dev_priv->ldu_priv->num_active = 0; + dev_priv->ldu_priv->last_num_active = 0; dev_priv->ldu_priv->fb = NULL; drm_mode_create_dirty_info_property(dev_priv->dev); vmw_ldu_init(dev_priv, 0); - vmw_ldu_init(dev_priv, 1); - vmw_ldu_init(dev_priv, 2); - vmw_ldu_init(dev_priv, 3); - vmw_ldu_init(dev_priv, 4); - vmw_ldu_init(dev_priv, 5); - vmw_ldu_init(dev_priv, 6); - vmw_ldu_init(dev_priv, 7); + /* for old hardware without multimon only enable one display */ + if (dev_priv->capabilities & SVGA_CAP_MULTIMON) { + vmw_ldu_init(dev_priv, 1); + vmw_ldu_init(dev_priv, 2); + vmw_ldu_init(dev_priv, 3); + vmw_ldu_init(dev_priv, 4); + vmw_ldu_init(dev_priv, 5); + vmw_ldu_init(dev_priv, 6); + vmw_ldu_init(dev_priv, 7); + } return 0; } -- cgit v1.2.3 From 22ee861c816689b2566290356d54e4a01c9b2e74 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 28 May 2010 11:22:00 +0200 Subject: drm/vmwgfx: Reserve first part of VRAM for framebuffer. The host may be touching this part of VRAM at modesetting, even if we never use it ourselves, since we blit screen updates from 3D surfaces. Make sure no DMA buffers are placed in this part of VRAM. V2: Fix an error check in vmw_surface_dmabuf_pin(). Signed-off-by: Thomas Hellstrom Signed-off-by: Jakob Bornecrantz Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 41 +++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index c748207e9e1c..250282fee9c8 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -30,6 +30,8 @@ /* Might need a hrtimer here? */ #define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1) +static int vmw_surface_dmabuf_pin(struct vmw_framebuffer *vfb); +static int vmw_surface_dmabuf_unpin(struct vmw_framebuffer *vfb); void vmw_display_unit_cleanup(struct vmw_display_unit *du) { @@ -326,6 +328,7 @@ int vmw_framebuffer_create_handle(struct drm_framebuffer *fb, struct vmw_framebuffer_surface { struct vmw_framebuffer base; struct vmw_surface *surface; + struct vmw_dma_buffer *buffer; struct delayed_work d_work; struct mutex work_lock; bool present_fs; @@ -500,8 +503,8 @@ int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, vfbs->base.base.depth = 24; vfbs->base.base.width = width; vfbs->base.base.height = height; - vfbs->base.pin = NULL; - vfbs->base.unpin = NULL; + vfbs->base.pin = &vmw_surface_dmabuf_pin; + vfbs->base.unpin = &vmw_surface_dmabuf_unpin; vfbs->surface = surface; mutex_init(&vfbs->work_lock); INIT_DELAYED_WORK(&vfbs->d_work, &vmw_framebuffer_present_fs_callback); @@ -589,6 +592,40 @@ static struct drm_framebuffer_funcs vmw_framebuffer_dmabuf_funcs = { .create_handle = vmw_framebuffer_create_handle, }; +static int vmw_surface_dmabuf_pin(struct vmw_framebuffer *vfb) +{ + struct vmw_private *dev_priv = vmw_priv(vfb->base.dev); + struct vmw_framebuffer_surface *vfbs = + vmw_framebuffer_to_vfbs(&vfb->base); + unsigned long size = vfbs->base.base.pitch * vfbs->base.base.height; + int ret; + + vfbs->buffer = kzalloc(sizeof(*vfbs->buffer), GFP_KERNEL); + if (unlikely(vfbs->buffer == NULL)) + return -ENOMEM; + + vmw_overlay_pause_all(dev_priv); + ret = vmw_dmabuf_init(dev_priv, vfbs->buffer, size, + &vmw_vram_ne_placement, + false, &vmw_dmabuf_bo_free); + vmw_overlay_resume_all(dev_priv); + + return ret; +} + +static int vmw_surface_dmabuf_unpin(struct vmw_framebuffer *vfb) +{ + struct ttm_buffer_object *bo; + struct vmw_framebuffer_surface *vfbs = + vmw_framebuffer_to_vfbs(&vfb->base); + + bo = &vfbs->buffer->base; + ttm_bo_unref(&bo); + vfbs->buffer = NULL; + + return 0; +} + static int vmw_framebuffer_dmabuf_pin(struct vmw_framebuffer *vfb) { struct vmw_private *dev_priv = vmw_priv(vfb->base.dev); -- cgit v1.2.3 From bbfad33663fe8de1cce84ac776664292c46fe7ae Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 28 May 2010 11:22:01 +0200 Subject: drm/vmwgfx: Remove duplicate member from struct vmw_legacy_display_unit. Signed-off-by: Jakob Bornecrantz Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index 8fde9bf8be41..b35d7b0fd48d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -50,8 +50,6 @@ struct vmw_legacy_display_unit { struct vmw_display_unit base; struct list_head active; - - unsigned unit; }; static void vmw_ldu_destroy(struct vmw_legacy_display_unit *ldu) @@ -204,7 +202,7 @@ static int vmw_ldu_add_active(struct vmw_private *vmw_priv, at = &ld->active; list_for_each_entry(entry, &ld->active, active) { - if (entry->unit > ldu->unit) + if (entry->base.unit > ldu->base.unit) break; at = &entry->active; @@ -491,7 +489,7 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) if (!ldu) return -ENOMEM; - ldu->unit = unit; + ldu->base.unit = unit; crtc = &ldu->base.crtc; encoder = &ldu->base.encoder; connector = &ldu->base.connector; -- cgit v1.2.3 From d451f62a7c567654f74018be9ab8da8089660d3b Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 28 May 2010 11:22:02 +0200 Subject: drm/vmwgfx: Don't use SVGA_REG_ENABLE in modesetting code. We should not use SVGA_REG_ENABLE anywhere but in the fifo setup code, since it controls whether the device is active. Signed-off-by: Jakob Bornecrantz Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 4 ---- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 5 ----- 2 files changed, 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index fb66e62b8e2c..06f431442e92 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -153,7 +153,6 @@ static int vmw_fb_set_par(struct fb_info *info) struct vmw_private *vmw_priv = par->vmw_priv; if (vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY) { - vmw_write(vmw_priv, SVGA_REG_ENABLE, 0); vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, 0); vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true); vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, 0); @@ -175,13 +174,10 @@ static int vmw_fb_set_par(struct fb_info *info) vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, info->var.yres); vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1); - vmw_write(vmw_priv, SVGA_REG_ENABLE, 1); } else { - vmw_write(vmw_priv, SVGA_REG_ENABLE, 0); vmw_kms_write_svga(vmw_priv, info->var.xres, info->var.yres, info->fix.line_length, par->bpp, par->depth); - vmw_write(vmw_priv, SVGA_REG_ENABLE, 1); } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index b35d7b0fd48d..d98b1b1a8705 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -107,16 +107,12 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv) return 0; fb = entry->base.crtc.fb; - vmw_write(dev_priv, SVGA_REG_ENABLE, 0); vmw_kms_write_svga(dev_priv, w, h, fb->pitch, fb->bits_per_pixel, fb->depth); - vmw_write(dev_priv, SVGA_REG_ENABLE, 1); return 0; } - vmw_write(dev_priv, SVGA_REG_ENABLE, 0); - for (i = 0; i < lds->last_num_active; i++) { vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, i); vmw_write(dev_priv, SVGA_REG_DISPLAY_IS_PRIMARY, !i); @@ -152,7 +148,6 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv) /* Make sure we always show something. */ vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, i ? i : 1); - vmw_write(dev_priv, SVGA_REG_ENABLE, 1); BUG_ON(i != lds->num_active); -- cgit v1.2.3 From 259600d593181b8a3b1d7fe99d93233b1b113fd0 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 28 May 2010 11:22:03 +0200 Subject: drm/vmwgfx: Some modesetting cleanups and fixes. Signed-off-by: Jakob Bornecrantz Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index d98b1b1a8705..f7094dde18f9 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -113,16 +113,6 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv) return 0; } - for (i = 0; i < lds->last_num_active; i++) { - vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, i); - vmw_write(dev_priv, SVGA_REG_DISPLAY_IS_PRIMARY, !i); - vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_X, 0); - vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_Y, 0); - vmw_write(dev_priv, SVGA_REG_DISPLAY_WIDTH, 0); - vmw_write(dev_priv, SVGA_REG_DISPLAY_HEIGHT, 0); - vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); - } - if (!list_empty(&lds->active)) { entry = list_entry(lds->active.next, typeof(*entry), active); fb = entry->base.crtc.fb; @@ -131,6 +121,10 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv) fb->bits_per_pixel, fb->depth); } + /* Make sure we always show something. */ + vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, + lds->num_active ? lds->num_active : 1); + i = 0; list_for_each_entry(entry, &lds->active, active) { crtc = &entry->base.crtc; @@ -146,9 +140,6 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv) i++; } - /* Make sure we always show something. */ - vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, i ? i : 1); - BUG_ON(i != lds->num_active); lds->last_num_active = lds->num_active; -- cgit v1.2.3 From 792778e8e058471e1909b78d7c5e6ab94962ff8e Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 28 May 2010 11:22:04 +0200 Subject: drm/vmwgfx: Unpause overlay on update. The unpause codepath uses vmw_overlay_update() so we must unset the paused status. Signed-off-by: Jakob Bornecrantz Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c index ad566c85b075..df2036ed18d5 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c @@ -358,6 +358,8 @@ static int vmw_overlay_update_stream(struct vmw_private *dev_priv, if (stream->buf != buf) stream->buf = vmw_dmabuf_reference(buf); stream->saved = *arg; + /* stream is no longer stopped/paused */ + stream->paused = false; return 0; } -- cgit v1.2.3 From 316ab13ae2ad603fd5e3a909524e68d98db1b1b6 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 28 May 2010 11:22:05 +0200 Subject: drm/vmwgfx: Print warnings in kernel log about bo pinning that fails. Signed-off-by: Jakob Bornecrantz Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 4 ++++ drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 2 ++ 2 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index 06f431442e92..181f47222580 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -630,6 +630,10 @@ int vmw_dmabuf_to_start_of_vram(struct vmw_private *vmw_priv, goto err_unlock; ret = ttm_bo_validate(bo, &ne_placement, false, false, false); + + /* Could probably bug on */ + WARN_ON(bo->offset != 0); + ttm_bo_unreserve(bo); err_unlock: ttm_write_unlock(&vmw_priv->active_master->lock); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 250282fee9c8..b78dcf001858 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -640,6 +640,8 @@ static int vmw_framebuffer_dmabuf_pin(struct vmw_framebuffer *vfb) vmw_overlay_resume_all(dev_priv); + WARN_ON(ret != 0); + return 0; } -- cgit v1.2.3 From 1ca14e75caae504fdf957cf0c1c4f3aafc886a60 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 28 May 2010 11:22:06 +0200 Subject: drm/vmwgfx: Remove some leftover debug messages. Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index bdd87dc9e7b1..7597323d5a5a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -408,8 +408,6 @@ static int vmw_driver_unload(struct drm_device *dev) { struct vmw_private *dev_priv = vmw_priv(dev); - DRM_INFO(VMWGFX_DRIVER_NAME " unload.\n"); - unregister_pm_notifier(&dev_priv->pm_nb); vmw_fb_close(dev_priv); @@ -555,7 +553,6 @@ static int vmw_master_create(struct drm_device *dev, { struct vmw_master *vmaster; - DRM_INFO("Master create.\n"); vmaster = kzalloc(sizeof(*vmaster), GFP_KERNEL); if (unlikely(vmaster == NULL)) return -ENOMEM; @@ -572,7 +569,6 @@ static void vmw_master_destroy(struct drm_device *dev, { struct vmw_master *vmaster = vmw_master(master); - DRM_INFO("Master destroy.\n"); master->driver_priv = NULL; kfree(vmaster); } @@ -588,8 +584,6 @@ static int vmw_master_set(struct drm_device *dev, struct vmw_master *vmaster = vmw_master(file_priv->master); int ret = 0; - DRM_INFO("Master set.\n"); - if (active) { BUG_ON(active != &dev_priv->fbdev_master); ret = ttm_vt_lock(&active->lock, false, vmw_fp->tfile); @@ -631,8 +625,6 @@ static void vmw_master_drop(struct drm_device *dev, struct vmw_master *vmaster = vmw_master(file_priv->master); int ret; - DRM_INFO("Master drop.\n"); - /** * Make sure the master doesn't disappear while we have * it locked. -- cgit v1.2.3 From e8613c0e29d0018a80652e6ae58660c8a75ac74b Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 26 May 2010 16:21:03 +0200 Subject: drm/ttm: Fix cached TTM page allocation. This patch fixes a regression introduced with the pool page allocator in the event that there are no highmem pages (for example x86_64), in which case cached page allocation would fail. Tested with the vmwgfx driver on a 64-bit vm. Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/ttm/ttm_page_alloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c index 0d9a42c2394f..b6d152360675 100644 --- a/drivers/gpu/drm/ttm/ttm_page_alloc.c +++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c @@ -671,7 +671,7 @@ int ttm_get_pages(struct list_head *pages, int flags, if (flags & TTM_PAGE_FLAG_DMA32) gfp_flags |= GFP_DMA32; else - gfp_flags |= __GFP_HIGHMEM; + gfp_flags |= GFP_HIGHUSER; for (r = 0; r < count; ++r) { p = alloc_page(gfp_flags); -- cgit v1.2.3 From 4abe4389790d5f02569fbacdf035536ba84c7d44 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 26 May 2010 16:21:04 +0200 Subject: drm/ttm: Fix ttm_page_alloc.c Fix a number of typos misspellings and checkpatch.pl warnings. Replace "[ttm] " with TTM_PFX Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/ttm/ttm_page_alloc.c | 62 +++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c index b6d152360675..ef910694bd63 100644 --- a/drivers/gpu/drm/ttm/ttm_page_alloc.c +++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c @@ -77,7 +77,7 @@ struct ttm_page_pool { /** * Limits for the pool. They are handled without locks because only place where * they may change is in sysfs store. They won't have immediate effect anyway - * so forcing serialiazation to access them is pointless. + * so forcing serialization to access them is pointless. */ struct ttm_pool_opts { @@ -165,16 +165,18 @@ static ssize_t ttm_pool_store(struct kobject *kobj, m->options.small = val; else if (attr == &ttm_page_pool_alloc_size) { if (val > NUM_PAGES_TO_ALLOC*8) { - printk(KERN_ERR "[ttm] Setting allocation size to %lu " - "is not allowed. Recomended size is " - "%lu\n", - NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 7), - NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 10)); + printk(KERN_ERR TTM_PFX + "Setting allocation size to %lu " + "is not allowed. Recommended size is " + "%lu\n", + NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 7), + NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 10)); return size; } else if (val > NUM_PAGES_TO_ALLOC) { - printk(KERN_WARNING "[ttm] Setting allocation size to " - "larger than %lu is not recomended.\n", - NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 10)); + printk(KERN_WARNING TTM_PFX + "Setting allocation size to " + "larger than %lu is not recommended.\n", + NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 10)); } m->options.alloc_size = val; } @@ -277,7 +279,7 @@ static void ttm_pages_put(struct page *pages[], unsigned npages) { unsigned i; if (set_pages_array_wb(pages, npages)) - printk(KERN_ERR "[ttm] Failed to set %d pages to wb!\n", + printk(KERN_ERR TTM_PFX "Failed to set %d pages to wb!\n", npages); for (i = 0; i < npages; ++i) __free_page(pages[i]); @@ -313,7 +315,8 @@ static int ttm_page_pool_free(struct ttm_page_pool *pool, unsigned nr_free) pages_to_free = kmalloc(npages_to_free * sizeof(struct page *), GFP_KERNEL); if (!pages_to_free) { - printk(KERN_ERR "Failed to allocate memory for pool free operation.\n"); + printk(KERN_ERR TTM_PFX + "Failed to allocate memory for pool free operation.\n"); return 0; } @@ -390,7 +393,7 @@ static int ttm_pool_get_num_unused_pages(void) } /** - * Calback for mm to request pool to reduce number of page held. + * Callback for mm to request pool to reduce number of page held. */ static int ttm_pool_mm_shrink(int shrink_pages, gfp_t gfp_mask) { @@ -433,14 +436,16 @@ static int ttm_set_pages_caching(struct page **pages, case tt_uncached: r = set_pages_array_uc(pages, cpages); if (r) - printk(KERN_ERR "[ttm] Failed to set %d pages to uc!\n", - cpages); + printk(KERN_ERR TTM_PFX + "Failed to set %d pages to uc!\n", + cpages); break; case tt_wc: r = set_pages_array_wc(pages, cpages); if (r) - printk(KERN_ERR "[ttm] Failed to set %d pages to wc!\n", - cpages); + printk(KERN_ERR TTM_PFX + "Failed to set %d pages to wc!\n", + cpages); break; default: break; @@ -458,7 +463,7 @@ static void ttm_handle_caching_state_failure(struct list_head *pages, struct page **failed_pages, unsigned cpages) { unsigned i; - /* Failed pages has to be reed */ + /* Failed pages have to be freed */ for (i = 0; i < cpages; ++i) { list_del(&failed_pages[i]->lru); __free_page(failed_pages[i]); @@ -485,7 +490,8 @@ static int ttm_alloc_new_pages(struct list_head *pages, int gfp_flags, caching_array = kmalloc(max_cpages*sizeof(struct page *), GFP_KERNEL); if (!caching_array) { - printk(KERN_ERR "[ttm] unable to allocate table for new pages."); + printk(KERN_ERR TTM_PFX + "Unable to allocate table for new pages."); return -ENOMEM; } @@ -493,12 +499,13 @@ static int ttm_alloc_new_pages(struct list_head *pages, int gfp_flags, p = alloc_page(gfp_flags); if (!p) { - printk(KERN_ERR "[ttm] unable to get page %u\n", i); + printk(KERN_ERR TTM_PFX "Unable to get page %u.\n", i); /* store already allocated pages in the pool after * setting the caching state */ if (cpages) { - r = ttm_set_pages_caching(caching_array, cstate, cpages); + r = ttm_set_pages_caching(caching_array, + cstate, cpages); if (r) ttm_handle_caching_state_failure(pages, ttm_flags, cstate, @@ -590,7 +597,8 @@ static void ttm_page_pool_fill_locked(struct ttm_page_pool *pool, ++pool->nrefills; pool->npages += alloc_size; } else { - printk(KERN_ERR "[ttm] Failed to fill pool (%p).", pool); + printk(KERN_ERR TTM_PFX + "Failed to fill pool (%p).", pool); /* If we have any pages left put them to the pool. */ list_for_each_entry(p, &pool->list, lru) { ++cpages; @@ -677,7 +685,8 @@ int ttm_get_pages(struct list_head *pages, int flags, p = alloc_page(gfp_flags); if (!p) { - printk(KERN_ERR "[ttm] unable to allocate page."); + printk(KERN_ERR TTM_PFX + "Unable to allocate page."); return -ENOMEM; } @@ -709,8 +718,9 @@ int ttm_get_pages(struct list_head *pages, int flags, if (r) { /* If there is any pages in the list put them back to * the pool. */ - printk(KERN_ERR "[ttm] Failed to allocate extra pages " - "for large request."); + printk(KERN_ERR TTM_PFX + "Failed to allocate extra pages " + "for large request."); ttm_put_pages(pages, 0, flags, cstate); return r; } @@ -778,7 +788,7 @@ int ttm_page_alloc_init(struct ttm_mem_global *glob, unsigned max_pages) if (atomic_add_return(1, &_manager.page_alloc_inited) > 1) return 0; - printk(KERN_INFO "[ttm] Initializing pool allocator.\n"); + printk(KERN_INFO TTM_PFX "Initializing pool allocator.\n"); ttm_page_pool_init_locked(&_manager.wc_pool, GFP_HIGHUSER, "wc"); @@ -813,7 +823,7 @@ void ttm_page_alloc_fini() if (atomic_sub_return(1, &_manager.page_alloc_inited) > 0) return; - printk(KERN_INFO "[ttm] Finilizing pool allocator.\n"); + printk(KERN_INFO TTM_PFX "Finalizing pool allocator.\n"); ttm_pool_mm_shrink_fini(&_manager); for (i = 0; i < NUM_POOLS; ++i) -- cgit v1.2.3 From 8b281db596744a15b2abbfdbf655796c64e172ca Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 31 May 2010 09:04:03 +1000 Subject: drm/nv50: cast IGP memory location to u64 before shifting Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_mem.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 775a7017af64..c1fd42b0dad1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -540,7 +540,8 @@ nouveau_mem_detect(struct drm_device *dev) dev_priv->vram_size = nv_rd32(dev, NV04_FIFO_DATA); dev_priv->vram_size &= NV10_FIFO_DATA_RAM_AMOUNT_MB_MASK; if (dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac) - dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10) << 12; + dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10); + dev_priv->vram_sys_base <<= 12; } NV_INFO(dev, "Detected %dMiB VRAM\n", (int)(dev_priv->vram_size >> 20)); -- cgit v1.2.3 From afeb3e11147adb357603b071d6d7d1f30ea7f19d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 7 Apr 2010 13:55:09 +1000 Subject: drm/nouveau: attempt to get bios from ACPI v3 Some of the laptops with the switchable graphics, seem to not post the secondary GPU at all, and we can't find a copy of the BIOS anywhere except in the ACPI rom retrieval. This adds support for ACPI ROM retrieval to nouveau. Signed-off-by: Dave Airlie --- drivers/gpu/drm/nouveau/nouveau_acpi.c | 59 +++++++++++++++++++++++++++++++++- drivers/gpu/drm/nouveau/nouveau_bios.c | 20 ++++++++++++ drivers/gpu/drm/nouveau/nouveau_drv.h | 5 +++ 3 files changed, 83 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index e13f6af0037a..b3f146a811ca 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -35,6 +35,7 @@ static struct nouveau_dsm_priv { bool dsm_detected; acpi_handle dhandle; acpi_handle dsm_handle; + acpi_handle rom_handle; } nouveau_dsm_priv; static const char nouveau_dsm_muid[] = { @@ -151,12 +152,13 @@ static bool nouveau_dsm_pci_probe(struct pci_dev *pdev) dhandle = DEVICE_ACPI_HANDLE(&pdev->dev); if (!dhandle) return false; + status = acpi_get_handle(dhandle, "_DSM", &nvidia_handle); if (ACPI_FAILURE(status)) { return false; } - ret= nouveau_dsm(nvidia_handle, NOUVEAU_DSM_SUPPORTED, + ret = nouveau_dsm(nvidia_handle, NOUVEAU_DSM_SUPPORTED, NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result); if (ret < 0) return false; @@ -173,6 +175,7 @@ static bool nouveau_dsm_detect(void) struct pci_dev *pdev = NULL; int has_dsm = 0; int vga_count = 0; + while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { vga_count++; @@ -204,3 +207,57 @@ void nouveau_unregister_dsm_handler(void) { vga_switcheroo_unregister_handler(); } + +/* retrieve the ROM in 4k blocks */ +static int nouveau_rom_call(acpi_handle rom_handle, uint8_t *bios, + int offset, int len) +{ + acpi_status status; + union acpi_object rom_arg_elements[2], *obj; + struct acpi_object_list rom_arg; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL}; + + rom_arg.count = 2; + rom_arg.pointer = &rom_arg_elements[0]; + + rom_arg_elements[0].type = ACPI_TYPE_INTEGER; + rom_arg_elements[0].integer.value = offset; + + rom_arg_elements[1].type = ACPI_TYPE_INTEGER; + rom_arg_elements[1].integer.value = len; + + status = acpi_evaluate_object(rom_handle, NULL, &rom_arg, &buffer); + if (ACPI_FAILURE(status)) { + printk(KERN_INFO "failed to evaluate ROM got %s\n", acpi_format_exception(status)); + return -ENODEV; + } + obj = (union acpi_object *)buffer.pointer; + memcpy(bios+offset, obj->buffer.pointer, len); + kfree(buffer.pointer); + return len; +} + +bool nouveau_acpi_rom_supported(struct pci_dev *pdev) +{ + acpi_status status; + acpi_handle dhandle, rom_handle; + + if (!nouveau_dsm_priv.dsm_detected) + return false; + + dhandle = DEVICE_ACPI_HANDLE(&pdev->dev); + if (!dhandle) + return false; + + status = acpi_get_handle(dhandle, "_ROM", &rom_handle); + if (ACPI_FAILURE(status)) + return false; + + nouveau_dsm_priv.rom_handle = rom_handle; + return true; +} + +int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) +{ + return nouveau_rom_call(nouveau_dsm_priv.rom_handle, bios, offset, len); +} diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index e7e69ccce5c9..745ff3788e9d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -178,6 +178,25 @@ out: pci_disable_rom(dev->pdev); } +static void load_vbios_acpi(struct drm_device *dev, uint8_t *data) +{ + int i; + int ret; + int size = 64 * 1024; + + if (!nouveau_acpi_rom_supported(dev->pdev)) + return; + + for (i = 0; i < (size / ROM_BIOS_PAGE); i++) { + ret = nouveau_acpi_get_bios_chunk(data, + (i * ROM_BIOS_PAGE), + ROM_BIOS_PAGE); + if (ret <= 0) + break; + } + return; +} + struct methods { const char desc[8]; void (*loadbios)(struct drm_device *, uint8_t *); @@ -191,6 +210,7 @@ static struct methods nv04_methods[] = { }; static struct methods nv50_methods[] = { + { "ACPI", load_vbios_acpi, true }, { "PRAMIN", load_vbios_pramin, true }, { "PROM", load_vbios_prom, false }, { "PCIROM", load_vbios_pci, true }, diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 5b134438effe..c69719106489 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -851,12 +851,17 @@ extern int nouveau_dma_init(struct nouveau_channel *); extern int nouveau_dma_wait(struct nouveau_channel *, int slots, int size); /* nouveau_acpi.c */ +#define ROM_BIOS_PAGE 4096 #if defined(CONFIG_ACPI) void nouveau_register_dsm_handler(void); void nouveau_unregister_dsm_handler(void); +int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len); +bool nouveau_acpi_rom_supported(struct pci_dev *pdev); #else static inline void nouveau_register_dsm_handler(void) {} static inline void nouveau_unregister_dsm_handler(void) {} +static inline bool nouveau_acpi_rom_supported(struct pci_dev *pdev) { return false; } +static inline int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) { return -EINVAL; } #endif /* nouveau_backlight.c */ -- cgit v1.2.3 From fc5ea29d72bde1bec230538becf396caad8621b8 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 31 May 2010 17:10:52 +1000 Subject: drm/nouveau: fixup confusion over which handle the DSM is hanging off. This fixes the DSM setup correctly since vga switcheroo. Signed-off-by: Dave Airlie --- drivers/gpu/drm/nouveau/nouveau_acpi.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index b3f146a811ca..d4bcca8a5133 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -34,7 +34,6 @@ static struct nouveau_dsm_priv { bool dsm_detected; acpi_handle dhandle; - acpi_handle dsm_handle; acpi_handle rom_handle; } nouveau_dsm_priv; @@ -108,9 +107,9 @@ static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switchero static int nouveau_dsm_switchto(enum vga_switcheroo_client_id id) { if (id == VGA_SWITCHEROO_IGD) - return nouveau_dsm_switch_mux(nouveau_dsm_priv.dsm_handle, NOUVEAU_DSM_LED_STAMINA); + return nouveau_dsm_switch_mux(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_LED_STAMINA); else - return nouveau_dsm_switch_mux(nouveau_dsm_priv.dsm_handle, NOUVEAU_DSM_LED_SPEED); + return nouveau_dsm_switch_mux(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_LED_SPEED); } static int nouveau_dsm_power_state(enum vga_switcheroo_client_id id, @@ -119,7 +118,7 @@ static int nouveau_dsm_power_state(enum vga_switcheroo_client_id id, if (id == VGA_SWITCHEROO_IGD) return 0; - return nouveau_dsm_set_discrete_state(nouveau_dsm_priv.dsm_handle, state); + return nouveau_dsm_set_discrete_state(nouveau_dsm_priv.dhandle, state); } static int nouveau_dsm_init(void) @@ -158,13 +157,12 @@ static bool nouveau_dsm_pci_probe(struct pci_dev *pdev) return false; } - ret = nouveau_dsm(nvidia_handle, NOUVEAU_DSM_SUPPORTED, - NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result); + ret = nouveau_dsm(dhandle, NOUVEAU_DSM_SUPPORTED, + NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result); if (ret < 0) return false; nouveau_dsm_priv.dhandle = dhandle; - nouveau_dsm_priv.dsm_handle = nvidia_handle; return true; } @@ -183,7 +181,7 @@ static bool nouveau_dsm_detect(void) } if (vga_count == 2 && has_dsm) { - acpi_get_name(nouveau_dsm_priv.dsm_handle, ACPI_FULL_PATHNAME, &buffer); + acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer); printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n", acpi_method_name); nouveau_dsm_priv.dsm_detected = true; -- cgit v1.2.3 From fbf81762e385d3d45acad057b654d56972acf58c Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 1 Jun 2010 09:09:06 +1000 Subject: drm/kms: disable/enable poll around switcheroo on/off Because we aren't in a suspend state the poll will still run when we have switcherooed a card off. Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_crtc_helper.c | 28 ++++++++++++++++++++++------ drivers/gpu/drm/i915/i915_dma.c | 4 +++- drivers/gpu/drm/nouveau/nouveau_state.c | 3 +++ drivers/gpu/drm/radeon/radeon_device.c | 2 ++ 4 files changed, 30 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 764401951041..9b2a54117c91 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -860,19 +860,24 @@ static void output_poll_execute(struct slow_work *work) } } -void drm_kms_helper_poll_init(struct drm_device *dev) +void drm_kms_helper_poll_disable(struct drm_device *dev) +{ + if (!dev->mode_config.poll_enabled) + return; + delayed_slow_work_cancel(&dev->mode_config.output_poll_slow_work); +} +EXPORT_SYMBOL(drm_kms_helper_poll_disable); + +void drm_kms_helper_poll_enable(struct drm_device *dev) { - struct drm_connector *connector; bool poll = false; + struct drm_connector *connector; int ret; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if (connector->polled) poll = true; } - slow_work_register_user(THIS_MODULE); - delayed_slow_work_init(&dev->mode_config.output_poll_slow_work, - &output_poll_ops); if (poll) { ret = delayed_slow_work_enqueue(&dev->mode_config.output_poll_slow_work, DRM_OUTPUT_POLL_PERIOD); @@ -880,11 +885,22 @@ void drm_kms_helper_poll_init(struct drm_device *dev) DRM_ERROR("delayed enqueue failed %d\n", ret); } } +EXPORT_SYMBOL(drm_kms_helper_poll_enable); + +void drm_kms_helper_poll_init(struct drm_device *dev) +{ + slow_work_register_user(THIS_MODULE); + delayed_slow_work_init(&dev->mode_config.output_poll_slow_work, + &output_poll_ops); + dev->mode_config.poll_enabled = true; + + drm_kms_helper_poll_enable(dev); +} EXPORT_SYMBOL(drm_kms_helper_poll_init); void drm_kms_helper_poll_fini(struct drm_device *dev) { - delayed_slow_work_cancel(&dev->mode_config.output_poll_slow_work); + drm_kms_helper_poll_disable(dev); slow_work_unregister_user(THIS_MODULE); } EXPORT_SYMBOL(drm_kms_helper_poll_fini); diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 2a6b5de5ae5d..cc6e56a18edd 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1399,12 +1399,14 @@ static void i915_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_ struct drm_device *dev = pci_get_drvdata(pdev); pm_message_t pmm = { .event = PM_EVENT_SUSPEND }; if (state == VGA_SWITCHEROO_ON) { - printk(KERN_INFO "i915: switched off\n"); + printk(KERN_INFO "i915: switched on\n"); /* i915 resume handler doesn't set to D0 */ pci_set_power_state(dev->pdev, PCI_D0); i915_resume(dev); + drm_kms_helper_poll_enable(dev); } else { printk(KERN_ERR "i915: switched off\n"); + drm_kms_helper_poll_disable(dev); i915_suspend(dev, pmm); } } diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index e632339c323e..5c468a4fef9a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -376,12 +376,15 @@ out_err: static void nouveau_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state) { + struct drm_device *dev = pci_get_drvdata(pdev); pm_message_t pmm = { .event = PM_EVENT_SUSPEND }; if (state == VGA_SWITCHEROO_ON) { printk(KERN_ERR "VGA switcheroo: switched nouveau on\n"); nouveau_pci_resume(pdev); + drm_kms_helper_poll_enable(dev); } else { printk(KERN_ERR "VGA switcheroo: switched nouveau off\n"); + drm_kms_helper_poll_disable(dev); nouveau_pci_suspend(pdev, pmm); } } diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index fdc3fdf78acb..db338522191f 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -546,8 +546,10 @@ static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero /* don't suspend or resume card normally */ rdev->powered_down = false; radeon_resume_kms(dev); + drm_kms_helper_poll_enable(dev); } else { printk(KERN_INFO "radeon: switched off\n"); + drm_kms_helper_poll_disable(dev); radeon_suspend_kms(dev, pmm); /* don't suspend or resume card normally */ rdev->powered_down = true; -- cgit v1.2.3 From cb5fcbd540b438a5d311bd15dc910841d01ed140 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 28 May 2010 19:01:35 -0400 Subject: drm/radeon/kms/evergreen: add initial CS parser Advanced validation is not implemented yet. The mesa code that uses this will be released soon. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/Makefile | 7 +- drivers/gpu/drm/radeon/evergreen_cs.c | 1356 +++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/evergreen_reg.h | 3 + drivers/gpu/drm/radeon/evergreend.h | 464 ++++++++++ drivers/gpu/drm/radeon/radeon_asic.c | 4 +- drivers/gpu/drm/radeon/radeon_asic.h | 1 + drivers/gpu/drm/radeon/reg_srcs/evergreen | 611 +++++++++++++ 7 files changed, 2443 insertions(+), 3 deletions(-) create mode 100644 drivers/gpu/drm/radeon/evergreen_cs.c create mode 100644 drivers/gpu/drm/radeon/reg_srcs/evergreen (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile index 3c91312dea9a..84b1f2729d43 100644 --- a/drivers/gpu/drm/radeon/Makefile +++ b/drivers/gpu/drm/radeon/Makefile @@ -33,6 +33,9 @@ $(obj)/rs600_reg_safe.h: $(src)/reg_srcs/rs600 $(obj)/mkregtable $(obj)/r600_reg_safe.h: $(src)/reg_srcs/r600 $(obj)/mkregtable $(call if_changed,mkregtable) +$(obj)/evergreen_reg_safe.h: $(src)/reg_srcs/evergreen $(obj)/mkregtable + $(call if_changed,mkregtable) + $(obj)/r100.o: $(obj)/r100_reg_safe.h $(obj)/rn50_reg_safe.h $(obj)/r200.o: $(obj)/r200_reg_safe.h @@ -47,6 +50,8 @@ $(obj)/rs600.o: $(obj)/rs600_reg_safe.h $(obj)/r600_cs.o: $(obj)/r600_reg_safe.h +$(obj)/evergreen_cs.o: $(obj)/evergreen_reg_safe.h + radeon-y := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o \ radeon_irq.o r300_cmdbuf.o r600_cp.o # add KMS driver @@ -60,7 +65,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \ rs400.o rs600.o rs690.o rv515.o r520.o r600.o rv770.o radeon_test.o \ r200.o radeon_legacy_tv.o r600_cs.o r600_blit.o r600_blit_shaders.o \ r600_blit_kms.o radeon_pm.o atombios_dp.o r600_audio.o r600_hdmi.o \ - evergreen.o + evergreen.o evergreen_cs.o radeon-$(CONFIG_COMPAT) += radeon_ioc32.o radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c new file mode 100644 index 000000000000..64516b950891 --- /dev/null +++ b/drivers/gpu/drm/radeon/evergreen_cs.c @@ -0,0 +1,1356 @@ +/* + * Copyright 2010 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Dave Airlie + * Alex Deucher + * Jerome Glisse + */ +#include "drmP.h" +#include "radeon.h" +#include "evergreend.h" +#include "evergreen_reg_safe.h" + +static int evergreen_cs_packet_next_reloc(struct radeon_cs_parser *p, + struct radeon_cs_reloc **cs_reloc); + +struct evergreen_cs_track { + u32 group_size; + u32 nbanks; + u32 npipes; + /* value we track */ + u32 nsamples; + u32 cb_color_base_last[12]; + struct radeon_bo *cb_color_bo[12]; + u32 cb_color_bo_offset[12]; + struct radeon_bo *cb_color_fmask_bo[8]; + struct radeon_bo *cb_color_cmask_bo[8]; + u32 cb_color_info[12]; + u32 cb_color_view[12]; + u32 cb_color_pitch_idx[12]; + u32 cb_color_slice_idx[12]; + u32 cb_color_dim_idx[12]; + u32 cb_color_dim[12]; + u32 cb_color_pitch[12]; + u32 cb_color_slice[12]; + u32 cb_color_cmask_slice[8]; + u32 cb_color_fmask_slice[8]; + u32 cb_target_mask; + u32 cb_shader_mask; + u32 vgt_strmout_config; + u32 vgt_strmout_buffer_config; + u32 db_depth_control; + u32 db_depth_view; + u32 db_depth_size; + u32 db_depth_size_idx; + u32 db_z_info; + u32 db_z_idx; + u32 db_z_read_offset; + u32 db_z_write_offset; + struct radeon_bo *db_z_read_bo; + struct radeon_bo *db_z_write_bo; + u32 db_s_info; + u32 db_s_idx; + u32 db_s_read_offset; + u32 db_s_write_offset; + struct radeon_bo *db_s_read_bo; + struct radeon_bo *db_s_write_bo; +}; + +static void evergreen_cs_track_init(struct evergreen_cs_track *track) +{ + int i; + + for (i = 0; i < 8; i++) { + track->cb_color_fmask_bo[i] = NULL; + track->cb_color_cmask_bo[i] = NULL; + track->cb_color_cmask_slice[i] = 0; + track->cb_color_fmask_slice[i] = 0; + } + + for (i = 0; i < 12; i++) { + track->cb_color_base_last[i] = 0; + track->cb_color_bo[i] = NULL; + track->cb_color_bo_offset[i] = 0xFFFFFFFF; + track->cb_color_info[i] = 0; + track->cb_color_view[i] = 0; + track->cb_color_pitch_idx[i] = 0; + track->cb_color_slice_idx[i] = 0; + track->cb_color_dim[i] = 0; + track->cb_color_pitch[i] = 0; + track->cb_color_slice[i] = 0; + track->cb_color_dim[i] = 0; + } + track->cb_target_mask = 0xFFFFFFFF; + track->cb_shader_mask = 0xFFFFFFFF; + + track->db_depth_view = 0xFFFFC000; + track->db_depth_size = 0xFFFFFFFF; + track->db_depth_size_idx = 0; + track->db_depth_control = 0xFFFFFFFF; + track->db_z_info = 0xFFFFFFFF; + track->db_z_idx = 0xFFFFFFFF; + track->db_z_read_offset = 0xFFFFFFFF; + track->db_z_write_offset = 0xFFFFFFFF; + track->db_z_read_bo = NULL; + track->db_z_write_bo = NULL; + track->db_s_info = 0xFFFFFFFF; + track->db_s_idx = 0xFFFFFFFF; + track->db_s_read_offset = 0xFFFFFFFF; + track->db_s_write_offset = 0xFFFFFFFF; + track->db_s_read_bo = NULL; + track->db_s_write_bo = NULL; +} + +static inline int evergreen_cs_track_validate_cb(struct radeon_cs_parser *p, int i) +{ + /* XXX fill in */ + return 0; +} + +static int evergreen_cs_track_check(struct radeon_cs_parser *p) +{ + struct evergreen_cs_track *track = p->track; + + /* we don't support stream out buffer yet */ + if (track->vgt_strmout_config || track->vgt_strmout_buffer_config) { + dev_warn(p->dev, "this kernel doesn't support SMX output buffer\n"); + return -EINVAL; + } + + /* XXX fill in */ + return 0; +} + +/** + * evergreen_cs_packet_parse() - parse cp packet and point ib index to next packet + * @parser: parser structure holding parsing context. + * @pkt: where to store packet informations + * + * Assume that chunk_ib_index is properly set. Will return -EINVAL + * if packet is bigger than remaining ib size. or if packets is unknown. + **/ +int evergreen_cs_packet_parse(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt, + unsigned idx) +{ + struct radeon_cs_chunk *ib_chunk = &p->chunks[p->chunk_ib_idx]; + uint32_t header; + + if (idx >= ib_chunk->length_dw) { + DRM_ERROR("Can not parse packet at %d after CS end %d !\n", + idx, ib_chunk->length_dw); + return -EINVAL; + } + header = radeon_get_ib_value(p, idx); + pkt->idx = idx; + pkt->type = CP_PACKET_GET_TYPE(header); + pkt->count = CP_PACKET_GET_COUNT(header); + pkt->one_reg_wr = 0; + switch (pkt->type) { + case PACKET_TYPE0: + pkt->reg = CP_PACKET0_GET_REG(header); + break; + case PACKET_TYPE3: + pkt->opcode = CP_PACKET3_GET_OPCODE(header); + break; + case PACKET_TYPE2: + pkt->count = -1; + break; + default: + DRM_ERROR("Unknown packet type %d at %d !\n", pkt->type, idx); + return -EINVAL; + } + if ((pkt->count + 1 + pkt->idx) >= ib_chunk->length_dw) { + DRM_ERROR("Packet (%d:%d:%d) end after CS buffer (%d) !\n", + pkt->idx, pkt->type, pkt->count, ib_chunk->length_dw); + return -EINVAL; + } + return 0; +} + +/** + * evergreen_cs_packet_next_reloc() - parse next packet which should be reloc packet3 + * @parser: parser structure holding parsing context. + * @data: pointer to relocation data + * @offset_start: starting offset + * @offset_mask: offset mask (to align start offset on) + * @reloc: reloc informations + * + * Check next packet is relocation packet3, do bo validation and compute + * GPU offset using the provided start. + **/ +static int evergreen_cs_packet_next_reloc(struct radeon_cs_parser *p, + struct radeon_cs_reloc **cs_reloc) +{ + struct radeon_cs_chunk *relocs_chunk; + struct radeon_cs_packet p3reloc; + unsigned idx; + int r; + + if (p->chunk_relocs_idx == -1) { + DRM_ERROR("No relocation chunk !\n"); + return -EINVAL; + } + *cs_reloc = NULL; + relocs_chunk = &p->chunks[p->chunk_relocs_idx]; + r = evergreen_cs_packet_parse(p, &p3reloc, p->idx); + if (r) { + return r; + } + p->idx += p3reloc.count + 2; + if (p3reloc.type != PACKET_TYPE3 || p3reloc.opcode != PACKET3_NOP) { + DRM_ERROR("No packet3 for relocation for packet at %d.\n", + p3reloc.idx); + return -EINVAL; + } + idx = radeon_get_ib_value(p, p3reloc.idx + 1); + if (idx >= relocs_chunk->length_dw) { + DRM_ERROR("Relocs at %d after relocations chunk end %d !\n", + idx, relocs_chunk->length_dw); + return -EINVAL; + } + /* FIXME: we assume reloc size is 4 dwords */ + *cs_reloc = p->relocs_ptr[(idx / 4)]; + return 0; +} + +/** + * evergreen_cs_packet_next_is_pkt3_nop() - test if next packet is packet3 nop for reloc + * @parser: parser structure holding parsing context. + * + * Check next packet is relocation packet3, do bo validation and compute + * GPU offset using the provided start. + **/ +static inline int evergreen_cs_packet_next_is_pkt3_nop(struct radeon_cs_parser *p) +{ + struct radeon_cs_packet p3reloc; + int r; + + r = evergreen_cs_packet_parse(p, &p3reloc, p->idx); + if (r) { + return 0; + } + if (p3reloc.type != PACKET_TYPE3 || p3reloc.opcode != PACKET3_NOP) { + return 0; + } + return 1; +} + +/** + * evergreen_cs_packet_next_vline() - parse userspace VLINE packet + * @parser: parser structure holding parsing context. + * + * Userspace sends a special sequence for VLINE waits. + * PACKET0 - VLINE_START_END + value + * PACKET3 - WAIT_REG_MEM poll vline status reg + * RELOC (P3) - crtc_id in reloc. + * + * This function parses this and relocates the VLINE START END + * and WAIT_REG_MEM packets to the correct crtc. + * It also detects a switched off crtc and nulls out the + * wait in that case. + */ +static int evergreen_cs_packet_parse_vline(struct radeon_cs_parser *p) +{ + struct drm_mode_object *obj; + struct drm_crtc *crtc; + struct radeon_crtc *radeon_crtc; + struct radeon_cs_packet p3reloc, wait_reg_mem; + int crtc_id; + int r; + uint32_t header, h_idx, reg, wait_reg_mem_info; + volatile uint32_t *ib; + + ib = p->ib->ptr; + + /* parse the WAIT_REG_MEM */ + r = evergreen_cs_packet_parse(p, &wait_reg_mem, p->idx); + if (r) + return r; + + /* check its a WAIT_REG_MEM */ + if (wait_reg_mem.type != PACKET_TYPE3 || + wait_reg_mem.opcode != PACKET3_WAIT_REG_MEM) { + DRM_ERROR("vline wait missing WAIT_REG_MEM segment\n"); + r = -EINVAL; + return r; + } + + wait_reg_mem_info = radeon_get_ib_value(p, wait_reg_mem.idx + 1); + /* bit 4 is reg (0) or mem (1) */ + if (wait_reg_mem_info & 0x10) { + DRM_ERROR("vline WAIT_REG_MEM waiting on MEM rather than REG\n"); + r = -EINVAL; + return r; + } + /* waiting for value to be equal */ + if ((wait_reg_mem_info & 0x7) != 0x3) { + DRM_ERROR("vline WAIT_REG_MEM function not equal\n"); + r = -EINVAL; + return r; + } + if ((radeon_get_ib_value(p, wait_reg_mem.idx + 2) << 2) != EVERGREEN_VLINE_STATUS) { + DRM_ERROR("vline WAIT_REG_MEM bad reg\n"); + r = -EINVAL; + return r; + } + + if (radeon_get_ib_value(p, wait_reg_mem.idx + 5) != EVERGREEN_VLINE_STAT) { + DRM_ERROR("vline WAIT_REG_MEM bad bit mask\n"); + r = -EINVAL; + return r; + } + + /* jump over the NOP */ + r = evergreen_cs_packet_parse(p, &p3reloc, p->idx + wait_reg_mem.count + 2); + if (r) + return r; + + h_idx = p->idx - 2; + p->idx += wait_reg_mem.count + 2; + p->idx += p3reloc.count + 2; + + header = radeon_get_ib_value(p, h_idx); + crtc_id = radeon_get_ib_value(p, h_idx + 2 + 7 + 1); + reg = CP_PACKET0_GET_REG(header); + mutex_lock(&p->rdev->ddev->mode_config.mutex); + obj = drm_mode_object_find(p->rdev->ddev, crtc_id, DRM_MODE_OBJECT_CRTC); + if (!obj) { + DRM_ERROR("cannot find crtc %d\n", crtc_id); + r = -EINVAL; + goto out; + } + crtc = obj_to_crtc(obj); + radeon_crtc = to_radeon_crtc(crtc); + crtc_id = radeon_crtc->crtc_id; + + if (!crtc->enabled) { + /* if the CRTC isn't enabled - we need to nop out the WAIT_REG_MEM */ + ib[h_idx + 2] = PACKET2(0); + ib[h_idx + 3] = PACKET2(0); + ib[h_idx + 4] = PACKET2(0); + ib[h_idx + 5] = PACKET2(0); + ib[h_idx + 6] = PACKET2(0); + ib[h_idx + 7] = PACKET2(0); + ib[h_idx + 8] = PACKET2(0); + } else { + switch (reg) { + case EVERGREEN_VLINE_START_END: + header &= ~R600_CP_PACKET0_REG_MASK; + header |= (EVERGREEN_VLINE_START_END + radeon_crtc->crtc_offset) >> 2; + ib[h_idx] = header; + ib[h_idx + 4] = (EVERGREEN_VLINE_STATUS + radeon_crtc->crtc_offset) >> 2; + break; + default: + DRM_ERROR("unknown crtc reloc\n"); + r = -EINVAL; + goto out; + } + } +out: + mutex_unlock(&p->rdev->ddev->mode_config.mutex); + return r; +} + +static int evergreen_packet0_check(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt, + unsigned idx, unsigned reg) +{ + int r; + + switch (reg) { + case EVERGREEN_VLINE_START_END: + r = evergreen_cs_packet_parse_vline(p); + if (r) { + DRM_ERROR("No reloc for ib[%d]=0x%04X\n", + idx, reg); + return r; + } + break; + default: + printk(KERN_ERR "Forbidden register 0x%04X in cs at %d\n", + reg, idx); + return -EINVAL; + } + return 0; +} + +static int evergreen_cs_parse_packet0(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt) +{ + unsigned reg, i; + unsigned idx; + int r; + + idx = pkt->idx + 1; + reg = pkt->reg; + for (i = 0; i <= pkt->count; i++, idx++, reg += 4) { + r = evergreen_packet0_check(p, pkt, idx, reg); + if (r) { + return r; + } + } + return 0; +} + +/** + * evergreen_cs_check_reg() - check if register is authorized or not + * @parser: parser structure holding parsing context + * @reg: register we are testing + * @idx: index into the cs buffer + * + * This function will test against evergreen_reg_safe_bm and return 0 + * if register is safe. If register is not flag as safe this function + * will test it against a list of register needind special handling. + */ +static inline int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) +{ + struct evergreen_cs_track *track = (struct evergreen_cs_track *)p->track; + struct radeon_cs_reloc *reloc; + u32 last_reg = ARRAY_SIZE(evergreen_reg_safe_bm); + u32 m, i, tmp, *ib; + int r; + + i = (reg >> 7); + if (i > last_reg) { + dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx); + return -EINVAL; + } + m = 1 << ((reg >> 2) & 31); + if (!(evergreen_reg_safe_bm[i] & m)) + return 0; + ib = p->ib->ptr; + switch (reg) { + /* force following reg to 0 in an attemp to disable out buffer + * which will need us to better understand how it works to perform + * security check on it (Jerome) + */ + case SQ_ESGS_RING_SIZE: + case SQ_GSVS_RING_SIZE: + case SQ_ESTMP_RING_SIZE: + case SQ_GSTMP_RING_SIZE: + case SQ_HSTMP_RING_SIZE: + case SQ_LSTMP_RING_SIZE: + case SQ_PSTMP_RING_SIZE: + case SQ_VSTMP_RING_SIZE: + case SQ_ESGS_RING_ITEMSIZE: + case SQ_ESTMP_RING_ITEMSIZE: + case SQ_GSTMP_RING_ITEMSIZE: + case SQ_GSVS_RING_ITEMSIZE: + case SQ_GS_VERT_ITEMSIZE: + case SQ_GS_VERT_ITEMSIZE_1: + case SQ_GS_VERT_ITEMSIZE_2: + case SQ_GS_VERT_ITEMSIZE_3: + case SQ_GSVS_RING_OFFSET_1: + case SQ_GSVS_RING_OFFSET_2: + case SQ_GSVS_RING_OFFSET_3: + case SQ_HSTMP_RING_ITEMSIZE: + case SQ_LSTMP_RING_ITEMSIZE: + case SQ_PSTMP_RING_ITEMSIZE: + case SQ_VSTMP_RING_ITEMSIZE: + case VGT_TF_RING_SIZE: + /* get value to populate the IB don't remove */ + tmp =radeon_get_ib_value(p, idx); + ib[idx] = 0; + break; + case DB_DEPTH_CONTROL: + track->db_depth_control = radeon_get_ib_value(p, idx); + break; + case DB_Z_INFO: + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_warn(p->dev, "bad SET_CONTEXT_REG " + "0x%04X\n", reg); + return -EINVAL; + } + track->db_z_info = radeon_get_ib_value(p, idx); + ib[idx] &= ~Z_ARRAY_MODE(0xf); + track->db_z_info &= ~Z_ARRAY_MODE(0xf); + if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) { + ib[idx] |= Z_ARRAY_MODE(ARRAY_2D_TILED_THIN1); + track->db_z_info |= Z_ARRAY_MODE(ARRAY_2D_TILED_THIN1); + } else { + ib[idx] |= Z_ARRAY_MODE(ARRAY_1D_TILED_THIN1); + track->db_z_info |= Z_ARRAY_MODE(ARRAY_1D_TILED_THIN1); + } + break; + case DB_STENCIL_INFO: + track->db_s_info = radeon_get_ib_value(p, idx); + break; + case DB_DEPTH_VIEW: + track->db_depth_view = radeon_get_ib_value(p, idx); + break; + case DB_DEPTH_SIZE: + track->db_depth_size = radeon_get_ib_value(p, idx); + track->db_depth_size_idx = idx; + break; + case DB_Z_READ_BASE: + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_warn(p->dev, "bad SET_CONTEXT_REG " + "0x%04X\n", reg); + return -EINVAL; + } + track->db_z_read_offset = radeon_get_ib_value(p, idx); + ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + track->db_z_read_bo = reloc->robj; + break; + case DB_Z_WRITE_BASE: + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_warn(p->dev, "bad SET_CONTEXT_REG " + "0x%04X\n", reg); + return -EINVAL; + } + track->db_z_write_offset = radeon_get_ib_value(p, idx); + ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + track->db_z_write_bo = reloc->robj; + break; + case DB_STENCIL_READ_BASE: + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_warn(p->dev, "bad SET_CONTEXT_REG " + "0x%04X\n", reg); + return -EINVAL; + } + track->db_s_read_offset = radeon_get_ib_value(p, idx); + ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + track->db_s_read_bo = reloc->robj; + break; + case DB_STENCIL_WRITE_BASE: + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_warn(p->dev, "bad SET_CONTEXT_REG " + "0x%04X\n", reg); + return -EINVAL; + } + track->db_s_write_offset = radeon_get_ib_value(p, idx); + ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + track->db_s_write_bo = reloc->robj; + break; + case VGT_STRMOUT_CONFIG: + track->vgt_strmout_config = radeon_get_ib_value(p, idx); + break; + case VGT_STRMOUT_BUFFER_CONFIG: + track->vgt_strmout_buffer_config = radeon_get_ib_value(p, idx); + break; + case CB_TARGET_MASK: + track->cb_target_mask = radeon_get_ib_value(p, idx); + break; + case CB_SHADER_MASK: + track->cb_shader_mask = radeon_get_ib_value(p, idx); + break; + case PA_SC_AA_CONFIG: + tmp = radeon_get_ib_value(p, idx) & MSAA_NUM_SAMPLES_MASK; + track->nsamples = 1 << tmp; + break; + case CB_COLOR0_VIEW: + case CB_COLOR1_VIEW: + case CB_COLOR2_VIEW: + case CB_COLOR3_VIEW: + case CB_COLOR4_VIEW: + case CB_COLOR5_VIEW: + case CB_COLOR6_VIEW: + case CB_COLOR7_VIEW: + tmp = (reg - CB_COLOR0_VIEW) / 0x3c; + track->cb_color_view[tmp] = radeon_get_ib_value(p, idx); + break; + case CB_COLOR8_VIEW: + case CB_COLOR9_VIEW: + case CB_COLOR10_VIEW: + case CB_COLOR11_VIEW: + tmp = ((reg - CB_COLOR8_VIEW) / 0x1c) + 8; + track->cb_color_view[tmp] = radeon_get_ib_value(p, idx); + break; + case CB_COLOR0_INFO: + case CB_COLOR1_INFO: + case CB_COLOR2_INFO: + case CB_COLOR3_INFO: + case CB_COLOR4_INFO: + case CB_COLOR5_INFO: + case CB_COLOR6_INFO: + case CB_COLOR7_INFO: + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_warn(p->dev, "bad SET_CONTEXT_REG " + "0x%04X\n", reg); + return -EINVAL; + } + tmp = (reg - CB_COLOR0_INFO) / 0x3c; + track->cb_color_info[tmp] = radeon_get_ib_value(p, idx); + if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) { + ib[idx] |= CB_ARRAY_MODE(ARRAY_2D_TILED_THIN1); + track->cb_color_info[tmp] |= CB_ARRAY_MODE(ARRAY_2D_TILED_THIN1); + } else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) { + ib[idx] |= CB_ARRAY_MODE(ARRAY_1D_TILED_THIN1); + track->cb_color_info[tmp] |= CB_ARRAY_MODE(ARRAY_1D_TILED_THIN1); + } + break; + case CB_COLOR8_INFO: + case CB_COLOR9_INFO: + case CB_COLOR10_INFO: + case CB_COLOR11_INFO: + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_warn(p->dev, "bad SET_CONTEXT_REG " + "0x%04X\n", reg); + return -EINVAL; + } + tmp = ((reg - CB_COLOR8_INFO) / 0x1c) + 8; + track->cb_color_info[tmp] = radeon_get_ib_value(p, idx); + if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) { + ib[idx] |= CB_ARRAY_MODE(ARRAY_2D_TILED_THIN1); + track->cb_color_info[tmp] |= CB_ARRAY_MODE(ARRAY_2D_TILED_THIN1); + } else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) { + ib[idx] |= CB_ARRAY_MODE(ARRAY_1D_TILED_THIN1); + track->cb_color_info[tmp] |= CB_ARRAY_MODE(ARRAY_1D_TILED_THIN1); + } + break; + case CB_COLOR0_PITCH: + case CB_COLOR1_PITCH: + case CB_COLOR2_PITCH: + case CB_COLOR3_PITCH: + case CB_COLOR4_PITCH: + case CB_COLOR5_PITCH: + case CB_COLOR6_PITCH: + case CB_COLOR7_PITCH: + tmp = (reg - CB_COLOR0_PITCH) / 0x3c; + track->cb_color_pitch[tmp] = radeon_get_ib_value(p, idx); + track->cb_color_pitch_idx[tmp] = idx; + break; + case CB_COLOR8_PITCH: + case CB_COLOR9_PITCH: + case CB_COLOR10_PITCH: + case CB_COLOR11_PITCH: + tmp = ((reg - CB_COLOR8_PITCH) / 0x1c) + 8; + track->cb_color_pitch[tmp] = radeon_get_ib_value(p, idx); + track->cb_color_pitch_idx[tmp] = idx; + break; + case CB_COLOR0_SLICE: + case CB_COLOR1_SLICE: + case CB_COLOR2_SLICE: + case CB_COLOR3_SLICE: + case CB_COLOR4_SLICE: + case CB_COLOR5_SLICE: + case CB_COLOR6_SLICE: + case CB_COLOR7_SLICE: + tmp = (reg - CB_COLOR0_SLICE) / 0x3c; + track->cb_color_slice[tmp] = radeon_get_ib_value(p, idx); + track->cb_color_slice_idx[tmp] = idx; + break; + case CB_COLOR8_SLICE: + case CB_COLOR9_SLICE: + case CB_COLOR10_SLICE: + case CB_COLOR11_SLICE: + tmp = ((reg - CB_COLOR8_SLICE) / 0x1c) + 8; + track->cb_color_slice[tmp] = radeon_get_ib_value(p, idx); + track->cb_color_slice_idx[tmp] = idx; + break; + case CB_COLOR0_ATTRIB: + case CB_COLOR1_ATTRIB: + case CB_COLOR2_ATTRIB: + case CB_COLOR3_ATTRIB: + case CB_COLOR4_ATTRIB: + case CB_COLOR5_ATTRIB: + case CB_COLOR6_ATTRIB: + case CB_COLOR7_ATTRIB: + case CB_COLOR8_ATTRIB: + case CB_COLOR9_ATTRIB: + case CB_COLOR10_ATTRIB: + case CB_COLOR11_ATTRIB: + break; + case CB_COLOR0_DIM: + case CB_COLOR1_DIM: + case CB_COLOR2_DIM: + case CB_COLOR3_DIM: + case CB_COLOR4_DIM: + case CB_COLOR5_DIM: + case CB_COLOR6_DIM: + case CB_COLOR7_DIM: + tmp = (reg - CB_COLOR0_DIM) / 0x3c; + track->cb_color_dim[tmp] = radeon_get_ib_value(p, idx); + track->cb_color_dim_idx[tmp] = idx; + break; + case CB_COLOR8_DIM: + case CB_COLOR9_DIM: + case CB_COLOR10_DIM: + case CB_COLOR11_DIM: + tmp = ((reg - CB_COLOR8_DIM) / 0x1c) + 8; + track->cb_color_dim[tmp] = radeon_get_ib_value(p, idx); + track->cb_color_dim_idx[tmp] = idx; + break; + case CB_COLOR0_FMASK: + case CB_COLOR1_FMASK: + case CB_COLOR2_FMASK: + case CB_COLOR3_FMASK: + case CB_COLOR4_FMASK: + case CB_COLOR5_FMASK: + case CB_COLOR6_FMASK: + case CB_COLOR7_FMASK: + tmp = (reg - CB_COLOR0_FMASK) / 0x3c; + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg); + return -EINVAL; + } + ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + track->cb_color_fmask_bo[tmp] = reloc->robj; + break; + case CB_COLOR0_CMASK: + case CB_COLOR1_CMASK: + case CB_COLOR2_CMASK: + case CB_COLOR3_CMASK: + case CB_COLOR4_CMASK: + case CB_COLOR5_CMASK: + case CB_COLOR6_CMASK: + case CB_COLOR7_CMASK: + tmp = (reg - CB_COLOR0_CMASK) / 0x3c; + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg); + return -EINVAL; + } + ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + track->cb_color_cmask_bo[tmp] = reloc->robj; + break; + case CB_COLOR0_FMASK_SLICE: + case CB_COLOR1_FMASK_SLICE: + case CB_COLOR2_FMASK_SLICE: + case CB_COLOR3_FMASK_SLICE: + case CB_COLOR4_FMASK_SLICE: + case CB_COLOR5_FMASK_SLICE: + case CB_COLOR6_FMASK_SLICE: + case CB_COLOR7_FMASK_SLICE: + tmp = (reg - CB_COLOR0_FMASK_SLICE) / 0x3c; + track->cb_color_fmask_slice[tmp] = radeon_get_ib_value(p, idx); + break; + case CB_COLOR0_CMASK_SLICE: + case CB_COLOR1_CMASK_SLICE: + case CB_COLOR2_CMASK_SLICE: + case CB_COLOR3_CMASK_SLICE: + case CB_COLOR4_CMASK_SLICE: + case CB_COLOR5_CMASK_SLICE: + case CB_COLOR6_CMASK_SLICE: + case CB_COLOR7_CMASK_SLICE: + tmp = (reg - CB_COLOR0_CMASK_SLICE) / 0x3c; + track->cb_color_cmask_slice[tmp] = radeon_get_ib_value(p, idx); + break; + case CB_COLOR0_BASE: + case CB_COLOR1_BASE: + case CB_COLOR2_BASE: + case CB_COLOR3_BASE: + case CB_COLOR4_BASE: + case CB_COLOR5_BASE: + case CB_COLOR6_BASE: + case CB_COLOR7_BASE: + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_warn(p->dev, "bad SET_CONTEXT_REG " + "0x%04X\n", reg); + return -EINVAL; + } + tmp = (reg - CB_COLOR0_BASE) / 0x3c; + track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx); + ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + track->cb_color_base_last[tmp] = ib[idx]; + track->cb_color_bo[tmp] = reloc->robj; + break; + case CB_COLOR8_BASE: + case CB_COLOR9_BASE: + case CB_COLOR10_BASE: + case CB_COLOR11_BASE: + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_warn(p->dev, "bad SET_CONTEXT_REG " + "0x%04X\n", reg); + return -EINVAL; + } + tmp = ((reg - CB_COLOR8_BASE) / 0x1c) + 8; + track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx); + ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + track->cb_color_base_last[tmp] = ib[idx]; + track->cb_color_bo[tmp] = reloc->robj; + break; + case CB_IMMED0_BASE: + case CB_IMMED1_BASE: + case CB_IMMED2_BASE: + case CB_IMMED3_BASE: + case CB_IMMED4_BASE: + case CB_IMMED5_BASE: + case CB_IMMED6_BASE: + case CB_IMMED7_BASE: + case CB_IMMED8_BASE: + case CB_IMMED9_BASE: + case CB_IMMED10_BASE: + case CB_IMMED11_BASE: + case DB_HTILE_DATA_BASE: + case SQ_PGM_START_FS: + case SQ_PGM_START_ES: + case SQ_PGM_START_VS: + case SQ_PGM_START_GS: + case SQ_PGM_START_PS: + case SQ_PGM_START_HS: + case SQ_PGM_START_LS: + case GDS_ADDR_BASE: + case SQ_CONST_MEM_BASE: + case SQ_ALU_CONST_CACHE_GS_0: + case SQ_ALU_CONST_CACHE_GS_1: + case SQ_ALU_CONST_CACHE_GS_2: + case SQ_ALU_CONST_CACHE_GS_3: + case SQ_ALU_CONST_CACHE_GS_4: + case SQ_ALU_CONST_CACHE_GS_5: + case SQ_ALU_CONST_CACHE_GS_6: + case SQ_ALU_CONST_CACHE_GS_7: + case SQ_ALU_CONST_CACHE_GS_8: + case SQ_ALU_CONST_CACHE_GS_9: + case SQ_ALU_CONST_CACHE_GS_10: + case SQ_ALU_CONST_CACHE_GS_11: + case SQ_ALU_CONST_CACHE_GS_12: + case SQ_ALU_CONST_CACHE_GS_13: + case SQ_ALU_CONST_CACHE_GS_14: + case SQ_ALU_CONST_CACHE_GS_15: + case SQ_ALU_CONST_CACHE_PS_0: + case SQ_ALU_CONST_CACHE_PS_1: + case SQ_ALU_CONST_CACHE_PS_2: + case SQ_ALU_CONST_CACHE_PS_3: + case SQ_ALU_CONST_CACHE_PS_4: + case SQ_ALU_CONST_CACHE_PS_5: + case SQ_ALU_CONST_CACHE_PS_6: + case SQ_ALU_CONST_CACHE_PS_7: + case SQ_ALU_CONST_CACHE_PS_8: + case SQ_ALU_CONST_CACHE_PS_9: + case SQ_ALU_CONST_CACHE_PS_10: + case SQ_ALU_CONST_CACHE_PS_11: + case SQ_ALU_CONST_CACHE_PS_12: + case SQ_ALU_CONST_CACHE_PS_13: + case SQ_ALU_CONST_CACHE_PS_14: + case SQ_ALU_CONST_CACHE_PS_15: + case SQ_ALU_CONST_CACHE_VS_0: + case SQ_ALU_CONST_CACHE_VS_1: + case SQ_ALU_CONST_CACHE_VS_2: + case SQ_ALU_CONST_CACHE_VS_3: + case SQ_ALU_CONST_CACHE_VS_4: + case SQ_ALU_CONST_CACHE_VS_5: + case SQ_ALU_CONST_CACHE_VS_6: + case SQ_ALU_CONST_CACHE_VS_7: + case SQ_ALU_CONST_CACHE_VS_8: + case SQ_ALU_CONST_CACHE_VS_9: + case SQ_ALU_CONST_CACHE_VS_10: + case SQ_ALU_CONST_CACHE_VS_11: + case SQ_ALU_CONST_CACHE_VS_12: + case SQ_ALU_CONST_CACHE_VS_13: + case SQ_ALU_CONST_CACHE_VS_14: + case SQ_ALU_CONST_CACHE_VS_15: + case SQ_ALU_CONST_CACHE_HS_0: + case SQ_ALU_CONST_CACHE_HS_1: + case SQ_ALU_CONST_CACHE_HS_2: + case SQ_ALU_CONST_CACHE_HS_3: + case SQ_ALU_CONST_CACHE_HS_4: + case SQ_ALU_CONST_CACHE_HS_5: + case SQ_ALU_CONST_CACHE_HS_6: + case SQ_ALU_CONST_CACHE_HS_7: + case SQ_ALU_CONST_CACHE_HS_8: + case SQ_ALU_CONST_CACHE_HS_9: + case SQ_ALU_CONST_CACHE_HS_10: + case SQ_ALU_CONST_CACHE_HS_11: + case SQ_ALU_CONST_CACHE_HS_12: + case SQ_ALU_CONST_CACHE_HS_13: + case SQ_ALU_CONST_CACHE_HS_14: + case SQ_ALU_CONST_CACHE_HS_15: + case SQ_ALU_CONST_CACHE_LS_0: + case SQ_ALU_CONST_CACHE_LS_1: + case SQ_ALU_CONST_CACHE_LS_2: + case SQ_ALU_CONST_CACHE_LS_3: + case SQ_ALU_CONST_CACHE_LS_4: + case SQ_ALU_CONST_CACHE_LS_5: + case SQ_ALU_CONST_CACHE_LS_6: + case SQ_ALU_CONST_CACHE_LS_7: + case SQ_ALU_CONST_CACHE_LS_8: + case SQ_ALU_CONST_CACHE_LS_9: + case SQ_ALU_CONST_CACHE_LS_10: + case SQ_ALU_CONST_CACHE_LS_11: + case SQ_ALU_CONST_CACHE_LS_12: + case SQ_ALU_CONST_CACHE_LS_13: + case SQ_ALU_CONST_CACHE_LS_14: + case SQ_ALU_CONST_CACHE_LS_15: + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_warn(p->dev, "bad SET_CONTEXT_REG " + "0x%04X\n", reg); + return -EINVAL; + } + ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + break; + default: + dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx); + return -EINVAL; + } + return 0; +} + +/** + * evergreen_check_texture_resource() - check if register is authorized or not + * @p: parser structure holding parsing context + * @idx: index into the cs buffer + * @texture: texture's bo structure + * @mipmap: mipmap's bo structure + * + * This function will check that the resource has valid field and that + * the texture and mipmap bo object are big enough to cover this resource. + */ +static inline int evergreen_check_texture_resource(struct radeon_cs_parser *p, u32 idx, + struct radeon_bo *texture, + struct radeon_bo *mipmap) +{ + /* XXX fill in */ + return 0; +} + +static int evergreen_packet3_check(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt) +{ + struct radeon_cs_reloc *reloc; + struct evergreen_cs_track *track; + volatile u32 *ib; + unsigned idx; + unsigned i; + unsigned start_reg, end_reg, reg; + int r; + u32 idx_value; + + track = (struct evergreen_cs_track *)p->track; + ib = p->ib->ptr; + idx = pkt->idx + 1; + idx_value = radeon_get_ib_value(p, idx); + + switch (pkt->opcode) { + case PACKET3_CONTEXT_CONTROL: + if (pkt->count != 1) { + DRM_ERROR("bad CONTEXT_CONTROL\n"); + return -EINVAL; + } + break; + case PACKET3_INDEX_TYPE: + case PACKET3_NUM_INSTANCES: + case PACKET3_CLEAR_STATE: + if (pkt->count) { + DRM_ERROR("bad INDEX_TYPE/NUM_INSTANCES/CLEAR_STATE\n"); + return -EINVAL; + } + break; + case PACKET3_INDEX_BASE: + if (pkt->count != 1) { + DRM_ERROR("bad INDEX_BASE\n"); + return -EINVAL; + } + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad INDEX_BASE\n"); + return -EINVAL; + } + ib[idx+0] = idx_value + (u32)(reloc->lobj.gpu_offset & 0xffffffff); + ib[idx+1] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff; + r = evergreen_cs_track_check(p); + if (r) { + dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__); + return r; + } + break; + case PACKET3_DRAW_INDEX: + if (pkt->count != 3) { + DRM_ERROR("bad DRAW_INDEX\n"); + return -EINVAL; + } + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad DRAW_INDEX\n"); + return -EINVAL; + } + ib[idx+0] = idx_value + (u32)(reloc->lobj.gpu_offset & 0xffffffff); + ib[idx+1] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff; + r = evergreen_cs_track_check(p); + if (r) { + dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__); + return r; + } + break; + case PACKET3_DRAW_INDEX_2: + if (pkt->count != 4) { + DRM_ERROR("bad DRAW_INDEX_2\n"); + return -EINVAL; + } + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad DRAW_INDEX_2\n"); + return -EINVAL; + } + ib[idx+1] = idx_value + (u32)(reloc->lobj.gpu_offset & 0xffffffff); + ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff; + r = evergreen_cs_track_check(p); + if (r) { + dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__); + return r; + } + break; + case PACKET3_DRAW_INDEX_AUTO: + if (pkt->count != 1) { + DRM_ERROR("bad DRAW_INDEX_AUTO\n"); + return -EINVAL; + } + r = evergreen_cs_track_check(p); + if (r) { + dev_warn(p->dev, "%s:%d invalid cmd stream %d\n", __func__, __LINE__, idx); + return r; + } + break; + case PACKET3_DRAW_INDEX_MULTI_AUTO: + if (pkt->count != 2) { + DRM_ERROR("bad DRAW_INDEX_MULTI_AUTO\n"); + return -EINVAL; + } + r = evergreen_cs_track_check(p); + if (r) { + dev_warn(p->dev, "%s:%d invalid cmd stream %d\n", __func__, __LINE__, idx); + return r; + } + break; + case PACKET3_DRAW_INDEX_IMMD: + if (pkt->count < 2) { + DRM_ERROR("bad DRAW_INDEX_IMMD\n"); + return -EINVAL; + } + r = evergreen_cs_track_check(p); + if (r) { + dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__); + return r; + } + break; + case PACKET3_DRAW_INDEX_OFFSET: + if (pkt->count != 2) { + DRM_ERROR("bad DRAW_INDEX_OFFSET\n"); + return -EINVAL; + } + r = evergreen_cs_track_check(p); + if (r) { + dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__); + return r; + } + break; + case PACKET3_DRAW_INDEX_OFFSET_2: + if (pkt->count != 3) { + DRM_ERROR("bad DRAW_INDEX_OFFSET_2\n"); + return -EINVAL; + } + r = evergreen_cs_track_check(p); + if (r) { + dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__); + return r; + } + break; + case PACKET3_WAIT_REG_MEM: + if (pkt->count != 5) { + DRM_ERROR("bad WAIT_REG_MEM\n"); + return -EINVAL; + } + /* bit 4 is reg (0) or mem (1) */ + if (idx_value & 0x10) { + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad WAIT_REG_MEM\n"); + return -EINVAL; + } + ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff); + ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff; + } + break; + case PACKET3_SURFACE_SYNC: + if (pkt->count != 3) { + DRM_ERROR("bad SURFACE_SYNC\n"); + return -EINVAL; + } + /* 0xffffffff/0x0 is flush all cache flag */ + if (radeon_get_ib_value(p, idx + 1) != 0xffffffff || + radeon_get_ib_value(p, idx + 2) != 0) { + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad SURFACE_SYNC\n"); + return -EINVAL; + } + ib[idx+2] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + } + break; + case PACKET3_EVENT_WRITE: + if (pkt->count != 2 && pkt->count != 0) { + DRM_ERROR("bad EVENT_WRITE\n"); + return -EINVAL; + } + if (pkt->count) { + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad EVENT_WRITE\n"); + return -EINVAL; + } + ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff); + ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff; + } + break; + case PACKET3_EVENT_WRITE_EOP: + if (pkt->count != 4) { + DRM_ERROR("bad EVENT_WRITE_EOP\n"); + return -EINVAL; + } + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad EVENT_WRITE_EOP\n"); + return -EINVAL; + } + ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff); + ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff; + break; + case PACKET3_EVENT_WRITE_EOS: + if (pkt->count != 3) { + DRM_ERROR("bad EVENT_WRITE_EOS\n"); + return -EINVAL; + } + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad EVENT_WRITE_EOS\n"); + return -EINVAL; + } + ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff); + ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff; + break; + case PACKET3_SET_CONFIG_REG: + start_reg = (idx_value << 2) + PACKET3_SET_CONFIG_REG_START; + end_reg = 4 * pkt->count + start_reg - 4; + if ((start_reg < PACKET3_SET_CONFIG_REG_START) || + (start_reg >= PACKET3_SET_CONFIG_REG_END) || + (end_reg >= PACKET3_SET_CONFIG_REG_END)) { + DRM_ERROR("bad PACKET3_SET_CONFIG_REG\n"); + return -EINVAL; + } + for (i = 0; i < pkt->count; i++) { + reg = start_reg + (4 * i); + r = evergreen_cs_check_reg(p, reg, idx+1+i); + if (r) + return r; + } + break; + case PACKET3_SET_CONTEXT_REG: + start_reg = (idx_value << 2) + PACKET3_SET_CONTEXT_REG_START; + end_reg = 4 * pkt->count + start_reg - 4; + if ((start_reg < PACKET3_SET_CONTEXT_REG_START) || + (start_reg >= PACKET3_SET_CONTEXT_REG_END) || + (end_reg >= PACKET3_SET_CONTEXT_REG_END)) { + DRM_ERROR("bad PACKET3_SET_CONTEXT_REG\n"); + return -EINVAL; + } + for (i = 0; i < pkt->count; i++) { + reg = start_reg + (4 * i); + r = evergreen_cs_check_reg(p, reg, idx+1+i); + if (r) + return r; + } + break; + case PACKET3_SET_RESOURCE: + if (pkt->count % 8) { + DRM_ERROR("bad SET_RESOURCE\n"); + return -EINVAL; + } + start_reg = (idx_value << 2) + PACKET3_SET_RESOURCE_START; + end_reg = 4 * pkt->count + start_reg - 4; + if ((start_reg < PACKET3_SET_RESOURCE_START) || + (start_reg >= PACKET3_SET_RESOURCE_END) || + (end_reg >= PACKET3_SET_RESOURCE_END)) { + DRM_ERROR("bad SET_RESOURCE\n"); + return -EINVAL; + } + for (i = 0; i < (pkt->count / 8); i++) { + struct radeon_bo *texture, *mipmap; + u32 size, offset; + + switch (G__SQ_CONSTANT_TYPE(radeon_get_ib_value(p, idx+1+(i*8)+7))) { + case SQ_TEX_VTX_VALID_TEXTURE: + /* tex base */ + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad SET_RESOURCE (tex)\n"); + return -EINVAL; + } + ib[idx+1+(i*8)+3] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) + ib[idx+1+(i*8)+1] |= TEX_ARRAY_MODE(ARRAY_2D_TILED_THIN1); + else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) + ib[idx+1+(i*8)+1] |= TEX_ARRAY_MODE(ARRAY_1D_TILED_THIN1); + texture = reloc->robj; + /* tex mip base */ + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad SET_RESOURCE (tex)\n"); + return -EINVAL; + } + ib[idx+1+(i*8)+4] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + mipmap = reloc->robj; + r = evergreen_check_texture_resource(p, idx+1+(i*8), + texture, mipmap); + if (r) + return r; + break; + case SQ_TEX_VTX_VALID_BUFFER: + /* vtx base */ + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad SET_RESOURCE (vtx)\n"); + return -EINVAL; + } + offset = radeon_get_ib_value(p, idx+1+(i*8)+0); + size = radeon_get_ib_value(p, idx+1+(i*8)+1); + if (p->rdev && (size + offset) > radeon_bo_size(reloc->robj)) { + /* force size to size of the buffer */ + dev_warn(p->dev, "vbo resource seems too big for the bo\n"); + ib[idx+1+(i*8)+1] = radeon_bo_size(reloc->robj); + } + ib[idx+1+(i*8)+0] += (u32)((reloc->lobj.gpu_offset) & 0xffffffff); + ib[idx+1+(i*8)+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff; + break; + case SQ_TEX_VTX_INVALID_TEXTURE: + case SQ_TEX_VTX_INVALID_BUFFER: + default: + DRM_ERROR("bad SET_RESOURCE\n"); + return -EINVAL; + } + } + break; + case PACKET3_SET_ALU_CONST: + /* XXX fix me ALU const buffers only */ + break; + case PACKET3_SET_BOOL_CONST: + start_reg = (idx_value << 2) + PACKET3_SET_BOOL_CONST_START; + end_reg = 4 * pkt->count + start_reg - 4; + if ((start_reg < PACKET3_SET_BOOL_CONST_START) || + (start_reg >= PACKET3_SET_BOOL_CONST_END) || + (end_reg >= PACKET3_SET_BOOL_CONST_END)) { + DRM_ERROR("bad SET_BOOL_CONST\n"); + return -EINVAL; + } + break; + case PACKET3_SET_LOOP_CONST: + start_reg = (idx_value << 2) + PACKET3_SET_LOOP_CONST_START; + end_reg = 4 * pkt->count + start_reg - 4; + if ((start_reg < PACKET3_SET_LOOP_CONST_START) || + (start_reg >= PACKET3_SET_LOOP_CONST_END) || + (end_reg >= PACKET3_SET_LOOP_CONST_END)) { + DRM_ERROR("bad SET_LOOP_CONST\n"); + return -EINVAL; + } + break; + case PACKET3_SET_CTL_CONST: + start_reg = (idx_value << 2) + PACKET3_SET_CTL_CONST_START; + end_reg = 4 * pkt->count + start_reg - 4; + if ((start_reg < PACKET3_SET_CTL_CONST_START) || + (start_reg >= PACKET3_SET_CTL_CONST_END) || + (end_reg >= PACKET3_SET_CTL_CONST_END)) { + DRM_ERROR("bad SET_CTL_CONST\n"); + return -EINVAL; + } + break; + case PACKET3_SET_SAMPLER: + if (pkt->count % 3) { + DRM_ERROR("bad SET_SAMPLER\n"); + return -EINVAL; + } + start_reg = (idx_value << 2) + PACKET3_SET_SAMPLER_START; + end_reg = 4 * pkt->count + start_reg - 4; + if ((start_reg < PACKET3_SET_SAMPLER_START) || + (start_reg >= PACKET3_SET_SAMPLER_END) || + (end_reg >= PACKET3_SET_SAMPLER_END)) { + DRM_ERROR("bad SET_SAMPLER\n"); + return -EINVAL; + } + break; + case PACKET3_NOP: + break; + default: + DRM_ERROR("Packet3 opcode %x not supported\n", pkt->opcode); + return -EINVAL; + } + return 0; +} + +int evergreen_cs_parse(struct radeon_cs_parser *p) +{ + struct radeon_cs_packet pkt; + struct evergreen_cs_track *track; + int r; + + if (p->track == NULL) { + /* initialize tracker, we are in kms */ + track = kzalloc(sizeof(*track), GFP_KERNEL); + if (track == NULL) + return -ENOMEM; + evergreen_cs_track_init(track); + track->npipes = p->rdev->config.evergreen.tiling_npipes; + track->nbanks = p->rdev->config.evergreen.tiling_nbanks; + track->group_size = p->rdev->config.evergreen.tiling_group_size; + p->track = track; + } + do { + r = evergreen_cs_packet_parse(p, &pkt, p->idx); + if (r) { + kfree(p->track); + p->track = NULL; + return r; + } + p->idx += pkt.count + 2; + switch (pkt.type) { + case PACKET_TYPE0: + r = evergreen_cs_parse_packet0(p, &pkt); + break; + case PACKET_TYPE2: + break; + case PACKET_TYPE3: + r = evergreen_packet3_check(p, &pkt); + break; + default: + DRM_ERROR("Unknown packet type %d !\n", pkt.type); + kfree(p->track); + p->track = NULL; + return -EINVAL; + } + if (r) { + kfree(p->track); + p->track = NULL; + return r; + } + } while (p->idx < p->chunks[p->chunk_ib_idx].length_dw); +#if 0 + for (r = 0; r < p->ib->length_dw; r++) { + printk(KERN_INFO "%05d 0x%08X\n", r, p->ib->ptr[r]); + mdelay(1); + } +#endif + kfree(p->track); + p->track = NULL; + return 0; +} + diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h index af86af836f13..e028c1cd9d9b 100644 --- a/drivers/gpu/drm/radeon/evergreen_reg.h +++ b/drivers/gpu/drm/radeon/evergreen_reg.h @@ -151,6 +151,9 @@ #define EVERGREEN_DATA_FORMAT 0x6b00 # define EVERGREEN_INTERLEAVE_EN (1 << 0) #define EVERGREEN_DESKTOP_HEIGHT 0x6b04 +#define EVERGREEN_VLINE_START_END 0x6b08 +#define EVERGREEN_VLINE_STATUS 0x6bb8 +# define EVERGREEN_VLINE_STAT (1 << 12) #define EVERGREEN_VIEWPORT_START 0x6d70 #define EVERGREEN_VIEWPORT_SIZE 0x6d74 diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index 93e9e17ad54a..79683f6b4452 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -218,6 +218,8 @@ #define CLIP_VTX_REORDER_ENA (1 << 0) #define NUM_CLIP_SEQ(x) ((x) << 1) #define PA_SC_AA_CONFIG 0x28C04 +#define MSAA_NUM_SAMPLES_SHIFT 0 +#define MSAA_NUM_SAMPLES_MASK 0x3 #define PA_SC_CLIPRECT_RULE 0x2820C #define PA_SC_EDGERULE 0x28230 #define PA_SC_FIFO_SIZE 0x8BCC @@ -553,4 +555,466 @@ # define DC_HPDx_RX_INT_TIMER(x) ((x) << 16) # define DC_HPDx_EN (1 << 28) +/* + * PM4 + */ +#define PACKET_TYPE0 0 +#define PACKET_TYPE1 1 +#define PACKET_TYPE2 2 +#define PACKET_TYPE3 3 + +#define CP_PACKET_GET_TYPE(h) (((h) >> 30) & 3) +#define CP_PACKET_GET_COUNT(h) (((h) >> 16) & 0x3FFF) +#define CP_PACKET0_GET_REG(h) (((h) & 0xFFFF) << 2) +#define CP_PACKET3_GET_OPCODE(h) (((h) >> 8) & 0xFF) +#define PACKET0(reg, n) ((PACKET_TYPE0 << 30) | \ + (((reg) >> 2) & 0xFFFF) | \ + ((n) & 0x3FFF) << 16) +#define CP_PACKET2 0x80000000 +#define PACKET2_PAD_SHIFT 0 +#define PACKET2_PAD_MASK (0x3fffffff << 0) + +#define PACKET2(v) (CP_PACKET2 | REG_SET(PACKET2_PAD, (v))) + +#define PACKET3(op, n) ((PACKET_TYPE3 << 30) | \ + (((op) & 0xFF) << 8) | \ + ((n) & 0x3FFF) << 16) + +/* Packet 3 types */ +#define PACKET3_NOP 0x10 +#define PACKET3_SET_BASE 0x11 +#define PACKET3_CLEAR_STATE 0x12 +#define PACKET3_INDIRECT_BUFFER_SIZE 0x13 +#define PACKET3_DISPATCH_DIRECT 0x15 +#define PACKET3_DISPATCH_INDIRECT 0x16 +#define PACKET3_INDIRECT_BUFFER_END 0x17 +#define PACKET3_SET_PREDICATION 0x20 +#define PACKET3_REG_RMW 0x21 +#define PACKET3_COND_EXEC 0x22 +#define PACKET3_PRED_EXEC 0x23 +#define PACKET3_DRAW_INDIRECT 0x24 +#define PACKET3_DRAW_INDEX_INDIRECT 0x25 +#define PACKET3_INDEX_BASE 0x26 +#define PACKET3_DRAW_INDEX_2 0x27 +#define PACKET3_CONTEXT_CONTROL 0x28 +#define PACKET3_DRAW_INDEX_OFFSET 0x29 +#define PACKET3_INDEX_TYPE 0x2A +#define PACKET3_DRAW_INDEX 0x2B +#define PACKET3_DRAW_INDEX_AUTO 0x2D +#define PACKET3_DRAW_INDEX_IMMD 0x2E +#define PACKET3_NUM_INSTANCES 0x2F +#define PACKET3_DRAW_INDEX_MULTI_AUTO 0x30 +#define PACKET3_STRMOUT_BUFFER_UPDATE 0x34 +#define PACKET3_DRAW_INDEX_OFFSET_2 0x35 +#define PACKET3_DRAW_INDEX_MULTI_ELEMENT 0x36 +#define PACKET3_MEM_SEMAPHORE 0x39 +#define PACKET3_MPEG_INDEX 0x3A +#define PACKET3_WAIT_REG_MEM 0x3C +#define PACKET3_MEM_WRITE 0x3D +#define PACKET3_INDIRECT_BUFFER 0x32 +#define PACKET3_SURFACE_SYNC 0x43 +# define PACKET3_CB0_DEST_BASE_ENA (1 << 6) +# define PACKET3_CB1_DEST_BASE_ENA (1 << 7) +# define PACKET3_CB2_DEST_BASE_ENA (1 << 8) +# define PACKET3_CB3_DEST_BASE_ENA (1 << 9) +# define PACKET3_CB4_DEST_BASE_ENA (1 << 10) +# define PACKET3_CB5_DEST_BASE_ENA (1 << 11) +# define PACKET3_CB6_DEST_BASE_ENA (1 << 12) +# define PACKET3_CB7_DEST_BASE_ENA (1 << 13) +# define PACKET3_DB_DEST_BASE_ENA (1 << 14) +# define PACKET3_CB8_DEST_BASE_ENA (1 << 15) +# define PACKET3_CB9_DEST_BASE_ENA (1 << 16) +# define PACKET3_CB10_DEST_BASE_ENA (1 << 17) +# define PACKET3_CB11_DEST_BASE_ENA (1 << 17) +# define PACKET3_FULL_CACHE_ENA (1 << 20) +# define PACKET3_TC_ACTION_ENA (1 << 23) +# define PACKET3_VC_ACTION_ENA (1 << 24) +# define PACKET3_CB_ACTION_ENA (1 << 25) +# define PACKET3_DB_ACTION_ENA (1 << 26) +# define PACKET3_SH_ACTION_ENA (1 << 27) +# define PACKET3_SMX_ACTION_ENA (1 << 28) +#define PACKET3_ME_INITIALIZE 0x44 +#define PACKET3_ME_INITIALIZE_DEVICE_ID(x) ((x) << 16) +#define PACKET3_COND_WRITE 0x45 +#define PACKET3_EVENT_WRITE 0x46 +#define PACKET3_EVENT_WRITE_EOP 0x47 +#define PACKET3_EVENT_WRITE_EOS 0x48 +#define PACKET3_PREAMBLE_CNTL 0x4A +#define PACKET3_RB_OFFSET 0x4B +#define PACKET3_ALU_PS_CONST_BUFFER_COPY 0x4C +#define PACKET3_ALU_VS_CONST_BUFFER_COPY 0x4D +#define PACKET3_ALU_PS_CONST_UPDATE 0x4E +#define PACKET3_ALU_VS_CONST_UPDATE 0x4F +#define PACKET3_ONE_REG_WRITE 0x57 +#define PACKET3_SET_CONFIG_REG 0x68 +#define PACKET3_SET_CONFIG_REG_START 0x00008000 +#define PACKET3_SET_CONFIG_REG_END 0x0000ac00 +#define PACKET3_SET_CONTEXT_REG 0x69 +#define PACKET3_SET_CONTEXT_REG_START 0x00028000 +#define PACKET3_SET_CONTEXT_REG_END 0x00029000 +#define PACKET3_SET_ALU_CONST 0x6A +/* alu const buffers only; no reg file */ +#define PACKET3_SET_BOOL_CONST 0x6B +#define PACKET3_SET_BOOL_CONST_START 0x0003a500 +#define PACKET3_SET_BOOL_CONST_END 0x0003a518 +#define PACKET3_SET_LOOP_CONST 0x6C +#define PACKET3_SET_LOOP_CONST_START 0x0003a200 +#define PACKET3_SET_LOOP_CONST_END 0x0003a500 +#define PACKET3_SET_RESOURCE 0x6D +#define PACKET3_SET_RESOURCE_START 0x00030000 +#define PACKET3_SET_RESOURCE_END 0x00038000 +#define PACKET3_SET_SAMPLER 0x6E +#define PACKET3_SET_SAMPLER_START 0x0003c000 +#define PACKET3_SET_SAMPLER_END 0x0003c600 +#define PACKET3_SET_CTL_CONST 0x6F +#define PACKET3_SET_CTL_CONST_START 0x0003cff0 +#define PACKET3_SET_CTL_CONST_END 0x0003ff0c +#define PACKET3_SET_RESOURCE_OFFSET 0x70 +#define PACKET3_SET_ALU_CONST_VS 0x71 +#define PACKET3_SET_ALU_CONST_DI 0x72 +#define PACKET3_SET_CONTEXT_REG_INDIRECT 0x73 +#define PACKET3_SET_RESOURCE_INDIRECT 0x74 +#define PACKET3_SET_APPEND_CNT 0x75 + +#define SQ_RESOURCE_CONSTANT_WORD7_0 0x3001c +#define S__SQ_CONSTANT_TYPE(x) (((x) & 3) << 30) +#define G__SQ_CONSTANT_TYPE(x) (((x) >> 30) & 3) +#define SQ_TEX_VTX_INVALID_TEXTURE 0x0 +#define SQ_TEX_VTX_INVALID_BUFFER 0x1 +#define SQ_TEX_VTX_VALID_TEXTURE 0x2 +#define SQ_TEX_VTX_VALID_BUFFER 0x3 + +#define SQ_CONST_MEM_BASE 0x8df8 + +#define SQ_ESGS_RING_SIZE 0x8c44 +#define SQ_GSVS_RING_SIZE 0x8c4c +#define SQ_ESTMP_RING_SIZE 0x8c54 +#define SQ_GSTMP_RING_SIZE 0x8c5c +#define SQ_VSTMP_RING_SIZE 0x8c64 +#define SQ_PSTMP_RING_SIZE 0x8c6c +#define SQ_LSTMP_RING_SIZE 0x8e14 +#define SQ_HSTMP_RING_SIZE 0x8e1c +#define VGT_TF_RING_SIZE 0x8988 + +#define SQ_ESGS_RING_ITEMSIZE 0x28900 +#define SQ_GSVS_RING_ITEMSIZE 0x28904 +#define SQ_ESTMP_RING_ITEMSIZE 0x28908 +#define SQ_GSTMP_RING_ITEMSIZE 0x2890c +#define SQ_VSTMP_RING_ITEMSIZE 0x28910 +#define SQ_PSTMP_RING_ITEMSIZE 0x28914 +#define SQ_LSTMP_RING_ITEMSIZE 0x28830 +#define SQ_HSTMP_RING_ITEMSIZE 0x28834 + +#define SQ_GS_VERT_ITEMSIZE 0x2891c +#define SQ_GS_VERT_ITEMSIZE_1 0x28920 +#define SQ_GS_VERT_ITEMSIZE_2 0x28924 +#define SQ_GS_VERT_ITEMSIZE_3 0x28928 +#define SQ_GSVS_RING_OFFSET_1 0x2892c +#define SQ_GSVS_RING_OFFSET_2 0x28930 +#define SQ_GSVS_RING_OFFSET_3 0x28934 + +#define SQ_ALU_CONST_CACHE_PS_0 0x28940 +#define SQ_ALU_CONST_CACHE_PS_1 0x28944 +#define SQ_ALU_CONST_CACHE_PS_2 0x28948 +#define SQ_ALU_CONST_CACHE_PS_3 0x2894c +#define SQ_ALU_CONST_CACHE_PS_4 0x28950 +#define SQ_ALU_CONST_CACHE_PS_5 0x28954 +#define SQ_ALU_CONST_CACHE_PS_6 0x28958 +#define SQ_ALU_CONST_CACHE_PS_7 0x2895c +#define SQ_ALU_CONST_CACHE_PS_8 0x28960 +#define SQ_ALU_CONST_CACHE_PS_9 0x28964 +#define SQ_ALU_CONST_CACHE_PS_10 0x28968 +#define SQ_ALU_CONST_CACHE_PS_11 0x2896c +#define SQ_ALU_CONST_CACHE_PS_12 0x28970 +#define SQ_ALU_CONST_CACHE_PS_13 0x28974 +#define SQ_ALU_CONST_CACHE_PS_14 0x28978 +#define SQ_ALU_CONST_CACHE_PS_15 0x2897c +#define SQ_ALU_CONST_CACHE_VS_0 0x28980 +#define SQ_ALU_CONST_CACHE_VS_1 0x28984 +#define SQ_ALU_CONST_CACHE_VS_2 0x28988 +#define SQ_ALU_CONST_CACHE_VS_3 0x2898c +#define SQ_ALU_CONST_CACHE_VS_4 0x28990 +#define SQ_ALU_CONST_CACHE_VS_5 0x28994 +#define SQ_ALU_CONST_CACHE_VS_6 0x28998 +#define SQ_ALU_CONST_CACHE_VS_7 0x2899c +#define SQ_ALU_CONST_CACHE_VS_8 0x289a0 +#define SQ_ALU_CONST_CACHE_VS_9 0x289a4 +#define SQ_ALU_CONST_CACHE_VS_10 0x289a8 +#define SQ_ALU_CONST_CACHE_VS_11 0x289ac +#define SQ_ALU_CONST_CACHE_VS_12 0x289b0 +#define SQ_ALU_CONST_CACHE_VS_13 0x289b4 +#define SQ_ALU_CONST_CACHE_VS_14 0x289b8 +#define SQ_ALU_CONST_CACHE_VS_15 0x289bc +#define SQ_ALU_CONST_CACHE_GS_0 0x289c0 +#define SQ_ALU_CONST_CACHE_GS_1 0x289c4 +#define SQ_ALU_CONST_CACHE_GS_2 0x289c8 +#define SQ_ALU_CONST_CACHE_GS_3 0x289cc +#define SQ_ALU_CONST_CACHE_GS_4 0x289d0 +#define SQ_ALU_CONST_CACHE_GS_5 0x289d4 +#define SQ_ALU_CONST_CACHE_GS_6 0x289d8 +#define SQ_ALU_CONST_CACHE_GS_7 0x289dc +#define SQ_ALU_CONST_CACHE_GS_8 0x289e0 +#define SQ_ALU_CONST_CACHE_GS_9 0x289e4 +#define SQ_ALU_CONST_CACHE_GS_10 0x289e8 +#define SQ_ALU_CONST_CACHE_GS_11 0x289ec +#define SQ_ALU_CONST_CACHE_GS_12 0x289f0 +#define SQ_ALU_CONST_CACHE_GS_13 0x289f4 +#define SQ_ALU_CONST_CACHE_GS_14 0x289f8 +#define SQ_ALU_CONST_CACHE_GS_15 0x289fc +#define SQ_ALU_CONST_CACHE_HS_0 0x28f00 +#define SQ_ALU_CONST_CACHE_HS_1 0x28f04 +#define SQ_ALU_CONST_CACHE_HS_2 0x28f08 +#define SQ_ALU_CONST_CACHE_HS_3 0x28f0c +#define SQ_ALU_CONST_CACHE_HS_4 0x28f10 +#define SQ_ALU_CONST_CACHE_HS_5 0x28f14 +#define SQ_ALU_CONST_CACHE_HS_6 0x28f18 +#define SQ_ALU_CONST_CACHE_HS_7 0x28f1c +#define SQ_ALU_CONST_CACHE_HS_8 0x28f20 +#define SQ_ALU_CONST_CACHE_HS_9 0x28f24 +#define SQ_ALU_CONST_CACHE_HS_10 0x28f28 +#define SQ_ALU_CONST_CACHE_HS_11 0x28f2c +#define SQ_ALU_CONST_CACHE_HS_12 0x28f30 +#define SQ_ALU_CONST_CACHE_HS_13 0x28f34 +#define SQ_ALU_CONST_CACHE_HS_14 0x28f38 +#define SQ_ALU_CONST_CACHE_HS_15 0x28f3c +#define SQ_ALU_CONST_CACHE_LS_0 0x28f40 +#define SQ_ALU_CONST_CACHE_LS_1 0x28f44 +#define SQ_ALU_CONST_CACHE_LS_2 0x28f48 +#define SQ_ALU_CONST_CACHE_LS_3 0x28f4c +#define SQ_ALU_CONST_CACHE_LS_4 0x28f50 +#define SQ_ALU_CONST_CACHE_LS_5 0x28f54 +#define SQ_ALU_CONST_CACHE_LS_6 0x28f58 +#define SQ_ALU_CONST_CACHE_LS_7 0x28f5c +#define SQ_ALU_CONST_CACHE_LS_8 0x28f60 +#define SQ_ALU_CONST_CACHE_LS_9 0x28f64 +#define SQ_ALU_CONST_CACHE_LS_10 0x28f68 +#define SQ_ALU_CONST_CACHE_LS_11 0x28f6c +#define SQ_ALU_CONST_CACHE_LS_12 0x28f70 +#define SQ_ALU_CONST_CACHE_LS_13 0x28f74 +#define SQ_ALU_CONST_CACHE_LS_14 0x28f78 +#define SQ_ALU_CONST_CACHE_LS_15 0x28f7c + +#define DB_DEPTH_CONTROL 0x28800 +#define DB_DEPTH_VIEW 0x28008 +#define DB_HTILE_DATA_BASE 0x28014 +#define DB_Z_INFO 0x28040 +# define Z_ARRAY_MODE(x) ((x) << 4) +#define DB_STENCIL_INFO 0x28044 +#define DB_Z_READ_BASE 0x28048 +#define DB_STENCIL_READ_BASE 0x2804c +#define DB_Z_WRITE_BASE 0x28050 +#define DB_STENCIL_WRITE_BASE 0x28054 +#define DB_DEPTH_SIZE 0x28058 + +#define SQ_PGM_START_PS 0x28840 +#define SQ_PGM_START_VS 0x2885c +#define SQ_PGM_START_GS 0x28874 +#define SQ_PGM_START_ES 0x2888c +#define SQ_PGM_START_FS 0x288a4 +#define SQ_PGM_START_HS 0x288b8 +#define SQ_PGM_START_LS 0x288d0 + +#define VGT_STRMOUT_CONFIG 0x28b94 +#define VGT_STRMOUT_BUFFER_CONFIG 0x28b98 + +#define CB_TARGET_MASK 0x28238 +#define CB_SHADER_MASK 0x2823c + +#define GDS_ADDR_BASE 0x28720 + +#define CB_IMMED0_BASE 0x28b9c +#define CB_IMMED1_BASE 0x28ba0 +#define CB_IMMED2_BASE 0x28ba4 +#define CB_IMMED3_BASE 0x28ba8 +#define CB_IMMED4_BASE 0x28bac +#define CB_IMMED5_BASE 0x28bb0 +#define CB_IMMED6_BASE 0x28bb4 +#define CB_IMMED7_BASE 0x28bb8 +#define CB_IMMED8_BASE 0x28bbc +#define CB_IMMED9_BASE 0x28bc0 +#define CB_IMMED10_BASE 0x28bc4 +#define CB_IMMED11_BASE 0x28bc8 + +/* all 12 CB blocks have these regs */ +#define CB_COLOR0_BASE 0x28c60 +#define CB_COLOR0_PITCH 0x28c64 +#define CB_COLOR0_SLICE 0x28c68 +#define CB_COLOR0_VIEW 0x28c6c +#define CB_COLOR0_INFO 0x28c70 +# define CB_ARRAY_MODE(x) ((x) << 8) +# define ARRAY_LINEAR_GENERAL 0 +# define ARRAY_LINEAR_ALIGNED 1 +# define ARRAY_1D_TILED_THIN1 2 +# define ARRAY_2D_TILED_THIN1 4 +#define CB_COLOR0_ATTRIB 0x28c74 +#define CB_COLOR0_DIM 0x28c78 +/* only CB0-7 blocks have these regs */ +#define CB_COLOR0_CMASK 0x28c7c +#define CB_COLOR0_CMASK_SLICE 0x28c80 +#define CB_COLOR0_FMASK 0x28c84 +#define CB_COLOR0_FMASK_SLICE 0x28c88 +#define CB_COLOR0_CLEAR_WORD0 0x28c8c +#define CB_COLOR0_CLEAR_WORD1 0x28c90 +#define CB_COLOR0_CLEAR_WORD2 0x28c94 +#define CB_COLOR0_CLEAR_WORD3 0x28c98 + +#define CB_COLOR1_BASE 0x28c9c +#define CB_COLOR2_BASE 0x28cd8 +#define CB_COLOR3_BASE 0x28d14 +#define CB_COLOR4_BASE 0x28d50 +#define CB_COLOR5_BASE 0x28d8c +#define CB_COLOR6_BASE 0x28dc8 +#define CB_COLOR7_BASE 0x28e04 +#define CB_COLOR8_BASE 0x28e40 +#define CB_COLOR9_BASE 0x28e5c +#define CB_COLOR10_BASE 0x28e78 +#define CB_COLOR11_BASE 0x28e94 + +#define CB_COLOR1_PITCH 0x28ca0 +#define CB_COLOR2_PITCH 0x28cdc +#define CB_COLOR3_PITCH 0x28d18 +#define CB_COLOR4_PITCH 0x28d54 +#define CB_COLOR5_PITCH 0x28d90 +#define CB_COLOR6_PITCH 0x28dcc +#define CB_COLOR7_PITCH 0x28e08 +#define CB_COLOR8_PITCH 0x28e44 +#define CB_COLOR9_PITCH 0x28e60 +#define CB_COLOR10_PITCH 0x28e7c +#define CB_COLOR11_PITCH 0x28e98 + +#define CB_COLOR1_SLICE 0x28ca4 +#define CB_COLOR2_SLICE 0x28ce0 +#define CB_COLOR3_SLICE 0x28d1c +#define CB_COLOR4_SLICE 0x28d58 +#define CB_COLOR5_SLICE 0x28d94 +#define CB_COLOR6_SLICE 0x28dd0 +#define CB_COLOR7_SLICE 0x28e0c +#define CB_COLOR8_SLICE 0x28e48 +#define CB_COLOR9_SLICE 0x28e64 +#define CB_COLOR10_SLICE 0x28e80 +#define CB_COLOR11_SLICE 0x28e9c + +#define CB_COLOR1_VIEW 0x28ca8 +#define CB_COLOR2_VIEW 0x28ce4 +#define CB_COLOR3_VIEW 0x28d20 +#define CB_COLOR4_VIEW 0x28d5c +#define CB_COLOR5_VIEW 0x28d98 +#define CB_COLOR6_VIEW 0x28dd4 +#define CB_COLOR7_VIEW 0x28e10 +#define CB_COLOR8_VIEW 0x28e4c +#define CB_COLOR9_VIEW 0x28e68 +#define CB_COLOR10_VIEW 0x28e84 +#define CB_COLOR11_VIEW 0x28ea0 + +#define CB_COLOR1_INFO 0x28cac +#define CB_COLOR2_INFO 0x28ce8 +#define CB_COLOR3_INFO 0x28d24 +#define CB_COLOR4_INFO 0x28d60 +#define CB_COLOR5_INFO 0x28d9c +#define CB_COLOR6_INFO 0x28dd8 +#define CB_COLOR7_INFO 0x28e14 +#define CB_COLOR8_INFO 0x28e50 +#define CB_COLOR9_INFO 0x28e6c +#define CB_COLOR10_INFO 0x28e88 +#define CB_COLOR11_INFO 0x28ea4 + +#define CB_COLOR1_ATTRIB 0x28cb0 +#define CB_COLOR2_ATTRIB 0x28cec +#define CB_COLOR3_ATTRIB 0x28d28 +#define CB_COLOR4_ATTRIB 0x28d64 +#define CB_COLOR5_ATTRIB 0x28da0 +#define CB_COLOR6_ATTRIB 0x28ddc +#define CB_COLOR7_ATTRIB 0x28e18 +#define CB_COLOR8_ATTRIB 0x28e54 +#define CB_COLOR9_ATTRIB 0x28e70 +#define CB_COLOR10_ATTRIB 0x28e8c +#define CB_COLOR11_ATTRIB 0x28ea8 + +#define CB_COLOR1_DIM 0x28cb4 +#define CB_COLOR2_DIM 0x28cf0 +#define CB_COLOR3_DIM 0x28d2c +#define CB_COLOR4_DIM 0x28d68 +#define CB_COLOR5_DIM 0x28da4 +#define CB_COLOR6_DIM 0x28de0 +#define CB_COLOR7_DIM 0x28e1c +#define CB_COLOR8_DIM 0x28e58 +#define CB_COLOR9_DIM 0x28e74 +#define CB_COLOR10_DIM 0x28e90 +#define CB_COLOR11_DIM 0x28eac + +#define CB_COLOR1_CMASK 0x28cb8 +#define CB_COLOR2_CMASK 0x28cf4 +#define CB_COLOR3_CMASK 0x28d30 +#define CB_COLOR4_CMASK 0x28d6c +#define CB_COLOR5_CMASK 0x28da8 +#define CB_COLOR6_CMASK 0x28de4 +#define CB_COLOR7_CMASK 0x28e20 + +#define CB_COLOR1_CMASK_SLICE 0x28cbc +#define CB_COLOR2_CMASK_SLICE 0x28cf8 +#define CB_COLOR3_CMASK_SLICE 0x28d34 +#define CB_COLOR4_CMASK_SLICE 0x28d70 +#define CB_COLOR5_CMASK_SLICE 0x28dac +#define CB_COLOR6_CMASK_SLICE 0x28de8 +#define CB_COLOR7_CMASK_SLICE 0x28e24 + +#define CB_COLOR1_FMASK 0x28cc0 +#define CB_COLOR2_FMASK 0x28cfc +#define CB_COLOR3_FMASK 0x28d38 +#define CB_COLOR4_FMASK 0x28d74 +#define CB_COLOR5_FMASK 0x28db0 +#define CB_COLOR6_FMASK 0x28dec +#define CB_COLOR7_FMASK 0x28e28 + +#define CB_COLOR1_FMASK_SLICE 0x28cc4 +#define CB_COLOR2_FMASK_SLICE 0x28d00 +#define CB_COLOR3_FMASK_SLICE 0x28d3c +#define CB_COLOR4_FMASK_SLICE 0x28d78 +#define CB_COLOR5_FMASK_SLICE 0x28db4 +#define CB_COLOR6_FMASK_SLICE 0x28df0 +#define CB_COLOR7_FMASK_SLICE 0x28e2c + +#define CB_COLOR1_CLEAR_WORD0 0x28cc8 +#define CB_COLOR2_CLEAR_WORD0 0x28d04 +#define CB_COLOR3_CLEAR_WORD0 0x28d40 +#define CB_COLOR4_CLEAR_WORD0 0x28d7c +#define CB_COLOR5_CLEAR_WORD0 0x28db8 +#define CB_COLOR6_CLEAR_WORD0 0x28df4 +#define CB_COLOR7_CLEAR_WORD0 0x28e30 + +#define CB_COLOR1_CLEAR_WORD1 0x28ccc +#define CB_COLOR2_CLEAR_WORD1 0x28d08 +#define CB_COLOR3_CLEAR_WORD1 0x28d44 +#define CB_COLOR4_CLEAR_WORD1 0x28d80 +#define CB_COLOR5_CLEAR_WORD1 0x28dbc +#define CB_COLOR6_CLEAR_WORD1 0x28df8 +#define CB_COLOR7_CLEAR_WORD1 0x28e34 + +#define CB_COLOR1_CLEAR_WORD2 0x28cd0 +#define CB_COLOR2_CLEAR_WORD2 0x28d0c +#define CB_COLOR3_CLEAR_WORD2 0x28d48 +#define CB_COLOR4_CLEAR_WORD2 0x28d84 +#define CB_COLOR5_CLEAR_WORD2 0x28dc0 +#define CB_COLOR6_CLEAR_WORD2 0x28dfc +#define CB_COLOR7_CLEAR_WORD2 0x28e38 + +#define CB_COLOR1_CLEAR_WORD3 0x28cd4 +#define CB_COLOR2_CLEAR_WORD3 0x28d10 +#define CB_COLOR3_CLEAR_WORD3 0x28d4c +#define CB_COLOR4_CLEAR_WORD3 0x28d88 +#define CB_COLOR5_CLEAR_WORD3 0x28dc4 +#define CB_COLOR6_CLEAR_WORD3 0x28e00 +#define CB_COLOR7_CLEAR_WORD3 0x28e3c + +#define SQ_TEX_RESOURCE_WORD0_0 0x30000 +#define SQ_TEX_RESOURCE_WORD1_0 0x30004 +# define TEX_ARRAY_MODE(x) ((x) << 28) +#define SQ_TEX_RESOURCE_WORD2_0 0x30008 +#define SQ_TEX_RESOURCE_WORD3_0 0x3000C +#define SQ_TEX_RESOURCE_WORD4_0 0x30010 +#define SQ_TEX_RESOURCE_WORD5_0 0x30014 +#define SQ_TEX_RESOURCE_WORD6_0 0x30018 +#define SQ_TEX_RESOURCE_WORD7_0 0x3001c + + #endif diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index e57df08d4aeb..87f7e2cc52d4 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -724,8 +724,8 @@ static struct radeon_asic evergreen_asic = { .irq_set = &evergreen_irq_set, .irq_process = &evergreen_irq_process, .get_vblank_counter = &evergreen_get_vblank_counter, - .fence_ring_emit = NULL, - .cs_parse = NULL, + .fence_ring_emit = &r600_fence_ring_emit, + .cs_parse = &evergreen_cs_parse, .copy_blit = NULL, .copy_dma = NULL, .copy = NULL, diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 5c40a3dfaca2..c0bbaa64157a 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -314,6 +314,7 @@ void evergreen_hpd_set_polarity(struct radeon_device *rdev, u32 evergreen_get_vblank_counter(struct radeon_device *rdev, int crtc); int evergreen_irq_set(struct radeon_device *rdev); int evergreen_irq_process(struct radeon_device *rdev); +extern int evergreen_cs_parse(struct radeon_cs_parser *p); extern void evergreen_pm_misc(struct radeon_device *rdev); extern void evergreen_pm_prepare(struct radeon_device *rdev); extern void evergreen_pm_finish(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/reg_srcs/evergreen b/drivers/gpu/drm/radeon/reg_srcs/evergreen new file mode 100644 index 000000000000..b5c757f68d3c --- /dev/null +++ b/drivers/gpu/drm/radeon/reg_srcs/evergreen @@ -0,0 +1,611 @@ +evergreen 0x9400 +0x00008040 WAIT_UNTIL +0x00008044 WAIT_UNTIL_POLL_CNTL +0x00008048 WAIT_UNTIL_POLL_MASK +0x0000804c WAIT_UNTIL_POLL_REFDATA +0x000088B0 VGT_VTX_VECT_EJECT_REG +0x000088C4 VGT_CACHE_INVALIDATION +0x000088D4 VGT_GS_VERTEX_REUSE +0x00008958 VGT_PRIMITIVE_TYPE +0x0000895C VGT_INDEX_TYPE +0x00008970 VGT_NUM_INDICES +0x00008974 VGT_NUM_INSTANCES +0x00008990 VGT_COMPUTE_DIM_X +0x00008994 VGT_COMPUTE_DIM_Y +0x00008998 VGT_COMPUTE_DIM_Z +0x0000899C VGT_COMPUTE_START_X +0x000089A0 VGT_COMPUTE_START_Y +0x000089A4 VGT_COMPUTE_START_Z +0x000089AC VGT_COMPUTE_THREAD_GOURP_SIZE +0x00008A14 PA_CL_ENHANCE +0x00008A60 PA_SC_LINE_STIPPLE_VALUE +0x00008B10 PA_SC_LINE_STIPPLE_STATE +0x00008BF0 PA_SC_ENHANCE +0x00008D8C SQ_DYN_GPR_CNTL_PS_FLUSH_REQ +0x00008C00 SQ_CONFIG +0x00008C04 SQ_GPR_RESOURCE_MGMT_1 +0x00008C08 SQ_GPR_RESOURCE_MGMT_2 +0x00008C0C SQ_GPR_RESOURCE_MGMT_3 +0x00008C10 SQ_GLOBAL_GPR_RESOURCE_MGMT_1 +0x00008C14 SQ_GLOBAL_GPR_RESOURCE_MGMT_2 +0x00008C18 SQ_THREAD_RESOURCE_MGMT +0x00008C1C SQ_THREAD_RESOURCE_MGMT_2 +0x00008C20 SQ_STACK_RESOURCE_MGMT_1 +0x00008C24 SQ_STACK_RESOURCE_MGMT_2 +0x00008C28 SQ_STACK_RESOURCE_MGMT_3 +0x00008DF8 SQ_CONST_MEM_BASE +0x00008E48 SQ_EX_ALLOC_TABLE_SLOTS +0x00009100 SPI_CONFIG_CNTL +0x0000913C SPI_CONFIG_CNTL_1 +0x00009700 VC_CNTL +0x00009714 VC_ENHANCE +0x00009830 DB_DEBUG +0x00009834 DB_DEBUG2 +0x00009838 DB_DEBUG3 +0x0000983C DB_DEBUG4 +0x00009854 DB_WATERMARKS +0x0000A400 TD_PS_BORDER_COLOR_INDEX +0x0000A404 TD_PS_BORDER_COLOR_RED +0x0000A408 TD_PS_BORDER_COLOR_GREEN +0x0000A40C TD_PS_BORDER_COLOR_BLUE +0x0000A410 TD_PS_BORDER_COLOR_ALPHA +0x0000A414 TD_VS_BORDER_COLOR_INDEX +0x0000A418 TD_VS_BORDER_COLOR_RED +0x0000A41C TD_VS_BORDER_COLOR_GREEN +0x0000A420 TD_VS_BORDER_COLOR_BLUE +0x0000A424 TD_VS_BORDER_COLOR_ALPHA +0x0000A428 TD_GS_BORDER_COLOR_INDEX +0x0000A42C TD_GS_BORDER_COLOR_RED +0x0000A430 TD_GS_BORDER_COLOR_GREEN +0x0000A434 TD_GS_BORDER_COLOR_BLUE +0x0000A438 TD_GS_BORDER_COLOR_ALPHA +0x0000A43C TD_HS_BORDER_COLOR_INDEX +0x0000A440 TD_HS_BORDER_COLOR_RED +0x0000A444 TD_HS_BORDER_COLOR_GREEN +0x0000A448 TD_HS_BORDER_COLOR_BLUE +0x0000A44C TD_HS_BORDER_COLOR_ALPHA +0x0000A450 TD_LS_BORDER_COLOR_INDEX +0x0000A454 TD_LS_BORDER_COLOR_RED +0x0000A458 TD_LS_BORDER_COLOR_GREEN +0x0000A45C TD_LS_BORDER_COLOR_BLUE +0x0000A460 TD_LS_BORDER_COLOR_ALPHA +0x0000A464 TD_CS_BORDER_COLOR_INDEX +0x0000A468 TD_CS_BORDER_COLOR_RED +0x0000A46C TD_CS_BORDER_COLOR_GREEN +0x0000A470 TD_CS_BORDER_COLOR_BLUE +0x0000A474 TD_CS_BORDER_COLOR_ALPHA +0x00028000 DB_RENDER_CONTROL +0x00028004 DB_COUNT_CONTROL +0x0002800C DB_RENDER_OVERRIDE +0x00028010 DB_RENDER_OVERRIDE2 +0x00028028 DB_STENCIL_CLEAR +0x0002802C DB_DEPTH_CLEAR +0x00028034 PA_SC_SCREEN_SCISSOR_BR +0x00028030 PA_SC_SCREEN_SCISSOR_TL +0x0002805C DB_DEPTH_SLICE +0x00028140 SQ_ALU_CONST_BUFFER_SIZE_PS_0 +0x00028144 SQ_ALU_CONST_BUFFER_SIZE_PS_1 +0x00028148 SQ_ALU_CONST_BUFFER_SIZE_PS_2 +0x0002814C SQ_ALU_CONST_BUFFER_SIZE_PS_3 +0x00028150 SQ_ALU_CONST_BUFFER_SIZE_PS_4 +0x00028154 SQ_ALU_CONST_BUFFER_SIZE_PS_5 +0x00028158 SQ_ALU_CONST_BUFFER_SIZE_PS_6 +0x0002815C SQ_ALU_CONST_BUFFER_SIZE_PS_7 +0x00028160 SQ_ALU_CONST_BUFFER_SIZE_PS_8 +0x00028164 SQ_ALU_CONST_BUFFER_SIZE_PS_9 +0x00028168 SQ_ALU_CONST_BUFFER_SIZE_PS_10 +0x0002816C SQ_ALU_CONST_BUFFER_SIZE_PS_11 +0x00028170 SQ_ALU_CONST_BUFFER_SIZE_PS_12 +0x00028174 SQ_ALU_CONST_BUFFER_SIZE_PS_13 +0x00028178 SQ_ALU_CONST_BUFFER_SIZE_PS_14 +0x0002817C SQ_ALU_CONST_BUFFER_SIZE_PS_15 +0x00028180 SQ_ALU_CONST_BUFFER_SIZE_VS_0 +0x00028184 SQ_ALU_CONST_BUFFER_SIZE_VS_1 +0x00028188 SQ_ALU_CONST_BUFFER_SIZE_VS_2 +0x0002818C SQ_ALU_CONST_BUFFER_SIZE_VS_3 +0x00028190 SQ_ALU_CONST_BUFFER_SIZE_VS_4 +0x00028194 SQ_ALU_CONST_BUFFER_SIZE_VS_5 +0x00028198 SQ_ALU_CONST_BUFFER_SIZE_VS_6 +0x0002819C SQ_ALU_CONST_BUFFER_SIZE_VS_7 +0x000281A0 SQ_ALU_CONST_BUFFER_SIZE_VS_8 +0x000281A4 SQ_ALU_CONST_BUFFER_SIZE_VS_9 +0x000281A8 SQ_ALU_CONST_BUFFER_SIZE_VS_10 +0x000281AC SQ_ALU_CONST_BUFFER_SIZE_VS_11 +0x000281B0 SQ_ALU_CONST_BUFFER_SIZE_VS_12 +0x000281B4 SQ_ALU_CONST_BUFFER_SIZE_VS_13 +0x000281B8 SQ_ALU_CONST_BUFFER_SIZE_VS_14 +0x000281BC SQ_ALU_CONST_BUFFER_SIZE_VS_15 +0x000281C0 SQ_ALU_CONST_BUFFER_SIZE_GS_0 +0x000281C4 SQ_ALU_CONST_BUFFER_SIZE_GS_1 +0x000281C8 SQ_ALU_CONST_BUFFER_SIZE_GS_2 +0x000281CC SQ_ALU_CONST_BUFFER_SIZE_GS_3 +0x000281D0 SQ_ALU_CONST_BUFFER_SIZE_GS_4 +0x000281D4 SQ_ALU_CONST_BUFFER_SIZE_GS_5 +0x000281D8 SQ_ALU_CONST_BUFFER_SIZE_GS_6 +0x000281DC SQ_ALU_CONST_BUFFER_SIZE_GS_7 +0x000281E0 SQ_ALU_CONST_BUFFER_SIZE_GS_8 +0x000281E4 SQ_ALU_CONST_BUFFER_SIZE_GS_9 +0x000281E8 SQ_ALU_CONST_BUFFER_SIZE_GS_10 +0x000281EC SQ_ALU_CONST_BUFFER_SIZE_GS_11 +0x000281F0 SQ_ALU_CONST_BUFFER_SIZE_GS_12 +0x000281F4 SQ_ALU_CONST_BUFFER_SIZE_GS_13 +0x000281F8 SQ_ALU_CONST_BUFFER_SIZE_GS_14 +0x000281FC SQ_ALU_CONST_BUFFER_SIZE_GS_15 +0x00028200 PA_SC_WINDOW_OFFSET +0x00028204 PA_SC_WINDOW_SCISSOR_TL +0x00028208 PA_SC_WINDOW_SCISSOR_BR +0x0002820C PA_SC_CLIPRECT_RULE +0x00028210 PA_SC_CLIPRECT_0_TL +0x00028214 PA_SC_CLIPRECT_0_BR +0x00028218 PA_SC_CLIPRECT_1_TL +0x0002821C PA_SC_CLIPRECT_1_BR +0x00028220 PA_SC_CLIPRECT_2_TL +0x00028224 PA_SC_CLIPRECT_2_BR +0x00028228 PA_SC_CLIPRECT_3_TL +0x0002822C PA_SC_CLIPRECT_3_BR +0x00028230 PA_SC_EDGERULE +0x00028234 PA_SU_HARDWARE_SCREEN_OFFSET +0x00028240 PA_SC_GENERIC_SCISSOR_TL +0x00028244 PA_SC_GENERIC_SCISSOR_BR +0x00028250 PA_SC_VPORT_SCISSOR_0_TL +0x00028254 PA_SC_VPORT_SCISSOR_0_BR +0x00028258 PA_SC_VPORT_SCISSOR_1_TL +0x0002825C PA_SC_VPORT_SCISSOR_1_BR +0x00028260 PA_SC_VPORT_SCISSOR_2_TL +0x00028264 PA_SC_VPORT_SCISSOR_2_BR +0x00028268 PA_SC_VPORT_SCISSOR_3_TL +0x0002826C PA_SC_VPORT_SCISSOR_3_BR +0x00028270 PA_SC_VPORT_SCISSOR_4_TL +0x00028274 PA_SC_VPORT_SCISSOR_4_BR +0x00028278 PA_SC_VPORT_SCISSOR_5_TL +0x0002827C PA_SC_VPORT_SCISSOR_5_BR +0x00028280 PA_SC_VPORT_SCISSOR_6_TL +0x00028284 PA_SC_VPORT_SCISSOR_6_BR +0x00028288 PA_SC_VPORT_SCISSOR_7_TL +0x0002828C PA_SC_VPORT_SCISSOR_7_BR +0x00028290 PA_SC_VPORT_SCISSOR_8_TL +0x00028294 PA_SC_VPORT_SCISSOR_8_BR +0x00028298 PA_SC_VPORT_SCISSOR_9_TL +0x0002829C PA_SC_VPORT_SCISSOR_9_BR +0x000282A0 PA_SC_VPORT_SCISSOR_10_TL +0x000282A4 PA_SC_VPORT_SCISSOR_10_BR +0x000282A8 PA_SC_VPORT_SCISSOR_11_TL +0x000282AC PA_SC_VPORT_SCISSOR_11_BR +0x000282B0 PA_SC_VPORT_SCISSOR_12_TL +0x000282B4 PA_SC_VPORT_SCISSOR_12_BR +0x000282B8 PA_SC_VPORT_SCISSOR_13_TL +0x000282BC PA_SC_VPORT_SCISSOR_13_BR +0x000282C0 PA_SC_VPORT_SCISSOR_14_TL +0x000282C4 PA_SC_VPORT_SCISSOR_14_BR +0x000282C8 PA_SC_VPORT_SCISSOR_15_TL +0x000282CC PA_SC_VPORT_SCISSOR_15_BR +0x000282D0 PA_SC_VPORT_ZMIN_0 +0x000282D4 PA_SC_VPORT_ZMAX_0 +0x000282D8 PA_SC_VPORT_ZMIN_1 +0x000282DC PA_SC_VPORT_ZMAX_1 +0x000282E0 PA_SC_VPORT_ZMIN_2 +0x000282E4 PA_SC_VPORT_ZMAX_2 +0x000282E8 PA_SC_VPORT_ZMIN_3 +0x000282EC PA_SC_VPORT_ZMAX_3 +0x000282F0 PA_SC_VPORT_ZMIN_4 +0x000282F4 PA_SC_VPORT_ZMAX_4 +0x000282F8 PA_SC_VPORT_ZMIN_5 +0x000282FC PA_SC_VPORT_ZMAX_5 +0x00028300 PA_SC_VPORT_ZMIN_6 +0x00028304 PA_SC_VPORT_ZMAX_6 +0x00028308 PA_SC_VPORT_ZMIN_7 +0x0002830C PA_SC_VPORT_ZMAX_7 +0x00028310 PA_SC_VPORT_ZMIN_8 +0x00028314 PA_SC_VPORT_ZMAX_8 +0x00028318 PA_SC_VPORT_ZMIN_9 +0x0002831C PA_SC_VPORT_ZMAX_9 +0x00028320 PA_SC_VPORT_ZMIN_10 +0x00028324 PA_SC_VPORT_ZMAX_10 +0x00028328 PA_SC_VPORT_ZMIN_11 +0x0002832C PA_SC_VPORT_ZMAX_11 +0x00028330 PA_SC_VPORT_ZMIN_12 +0x00028334 PA_SC_VPORT_ZMAX_12 +0x00028338 PA_SC_VPORT_ZMIN_13 +0x0002833C PA_SC_VPORT_ZMAX_13 +0x00028340 PA_SC_VPORT_ZMIN_14 +0x00028344 PA_SC_VPORT_ZMAX_14 +0x00028348 PA_SC_VPORT_ZMIN_15 +0x0002834C PA_SC_VPORT_ZMAX_15 +0x00028350 SX_MISC +0x00028380 SQ_VTX_SEMANTIC_0 +0x00028384 SQ_VTX_SEMANTIC_1 +0x00028388 SQ_VTX_SEMANTIC_2 +0x0002838C SQ_VTX_SEMANTIC_3 +0x00028390 SQ_VTX_SEMANTIC_4 +0x00028394 SQ_VTX_SEMANTIC_5 +0x00028398 SQ_VTX_SEMANTIC_6 +0x0002839C SQ_VTX_SEMANTIC_7 +0x000283A0 SQ_VTX_SEMANTIC_8 +0x000283A4 SQ_VTX_SEMANTIC_9 +0x000283A8 SQ_VTX_SEMANTIC_10 +0x000283AC SQ_VTX_SEMANTIC_11 +0x000283B0 SQ_VTX_SEMANTIC_12 +0x000283B4 SQ_VTX_SEMANTIC_13 +0x000283B8 SQ_VTX_SEMANTIC_14 +0x000283BC SQ_VTX_SEMANTIC_15 +0x000283C0 SQ_VTX_SEMANTIC_16 +0x000283C4 SQ_VTX_SEMANTIC_17 +0x000283C8 SQ_VTX_SEMANTIC_18 +0x000283CC SQ_VTX_SEMANTIC_19 +0x000283D0 SQ_VTX_SEMANTIC_20 +0x000283D4 SQ_VTX_SEMANTIC_21 +0x000283D8 SQ_VTX_SEMANTIC_22 +0x000283DC SQ_VTX_SEMANTIC_23 +0x000283E0 SQ_VTX_SEMANTIC_24 +0x000283E4 SQ_VTX_SEMANTIC_25 +0x000283E8 SQ_VTX_SEMANTIC_26 +0x000283EC SQ_VTX_SEMANTIC_27 +0x000283F0 SQ_VTX_SEMANTIC_28 +0x000283F4 SQ_VTX_SEMANTIC_29 +0x000283F8 SQ_VTX_SEMANTIC_30 +0x000283FC SQ_VTX_SEMANTIC_31 +0x00028400 VGT_MAX_VTX_INDX +0x00028404 VGT_MIN_VTX_INDX +0x00028408 VGT_INDX_OFFSET +0x0002840C VGT_MULTI_PRIM_IB_RESET_INDX +0x00028410 SX_ALPHA_TEST_CONTROL +0x00028414 CB_BLEND_RED +0x00028418 CB_BLEND_GREEN +0x0002841C CB_BLEND_BLUE +0x00028420 CB_BLEND_ALPHA +0x00028430 DB_STENCILREFMASK +0x00028434 DB_STENCILREFMASK_BF +0x00028438 SX_ALPHA_REF +0x0002843C PA_CL_VPORT_XSCALE_0 +0x00028440 PA_CL_VPORT_XOFFSET_0 +0x00028444 PA_CL_VPORT_YSCALE_0 +0x00028448 PA_CL_VPORT_YOFFSET_0 +0x0002844C PA_CL_VPORT_ZSCALE_0 +0x00028450 PA_CL_VPORT_ZOFFSET_0 +0x00028454 PA_CL_VPORT_XSCALE_1 +0x00028458 PA_CL_VPORT_XOFFSET_1 +0x0002845C PA_CL_VPORT_YSCALE_1 +0x00028460 PA_CL_VPORT_YOFFSET_1 +0x00028464 PA_CL_VPORT_ZSCALE_1 +0x00028468 PA_CL_VPORT_ZOFFSET_1 +0x0002846C PA_CL_VPORT_XSCALE_2 +0x00028470 PA_CL_VPORT_XOFFSET_2 +0x00028474 PA_CL_VPORT_YSCALE_2 +0x00028478 PA_CL_VPORT_YOFFSET_2 +0x0002847C PA_CL_VPORT_ZSCALE_2 +0x00028480 PA_CL_VPORT_ZOFFSET_2 +0x00028484 PA_CL_VPORT_XSCALE_3 +0x00028488 PA_CL_VPORT_XOFFSET_3 +0x0002848C PA_CL_VPORT_YSCALE_3 +0x00028490 PA_CL_VPORT_YOFFSET_3 +0x00028494 PA_CL_VPORT_ZSCALE_3 +0x00028498 PA_CL_VPORT_ZOFFSET_3 +0x0002849C PA_CL_VPORT_XSCALE_4 +0x000284A0 PA_CL_VPORT_XOFFSET_4 +0x000284A4 PA_CL_VPORT_YSCALE_4 +0x000284A8 PA_CL_VPORT_YOFFSET_4 +0x000284AC PA_CL_VPORT_ZSCALE_4 +0x000284B0 PA_CL_VPORT_ZOFFSET_4 +0x000284B4 PA_CL_VPORT_XSCALE_5 +0x000284B8 PA_CL_VPORT_XOFFSET_5 +0x000284BC PA_CL_VPORT_YSCALE_5 +0x000284C0 PA_CL_VPORT_YOFFSET_5 +0x000284C4 PA_CL_VPORT_ZSCALE_5 +0x000284C8 PA_CL_VPORT_ZOFFSET_5 +0x000284CC PA_CL_VPORT_XSCALE_6 +0x000284D0 PA_CL_VPORT_XOFFSET_6 +0x000284D4 PA_CL_VPORT_YSCALE_6 +0x000284D8 PA_CL_VPORT_YOFFSET_6 +0x000284DC PA_CL_VPORT_ZSCALE_6 +0x000284E0 PA_CL_VPORT_ZOFFSET_6 +0x000284E4 PA_CL_VPORT_XSCALE_7 +0x000284E8 PA_CL_VPORT_XOFFSET_7 +0x000284EC PA_CL_VPORT_YSCALE_7 +0x000284F0 PA_CL_VPORT_YOFFSET_7 +0x000284F4 PA_CL_VPORT_ZSCALE_7 +0x000284F8 PA_CL_VPORT_ZOFFSET_7 +0x000284FC PA_CL_VPORT_XSCALE_8 +0x00028500 PA_CL_VPORT_XOFFSET_8 +0x00028504 PA_CL_VPORT_YSCALE_8 +0x00028508 PA_CL_VPORT_YOFFSET_8 +0x0002850C PA_CL_VPORT_ZSCALE_8 +0x00028510 PA_CL_VPORT_ZOFFSET_8 +0x00028514 PA_CL_VPORT_XSCALE_9 +0x00028518 PA_CL_VPORT_XOFFSET_9 +0x0002851C PA_CL_VPORT_YSCALE_9 +0x00028520 PA_CL_VPORT_YOFFSET_9 +0x00028524 PA_CL_VPORT_ZSCALE_9 +0x00028528 PA_CL_VPORT_ZOFFSET_9 +0x0002852C PA_CL_VPORT_XSCALE_10 +0x00028530 PA_CL_VPORT_XOFFSET_10 +0x00028534 PA_CL_VPORT_YSCALE_10 +0x00028538 PA_CL_VPORT_YOFFSET_10 +0x0002853C PA_CL_VPORT_ZSCALE_10 +0x00028540 PA_CL_VPORT_ZOFFSET_10 +0x00028544 PA_CL_VPORT_XSCALE_11 +0x00028548 PA_CL_VPORT_XOFFSET_11 +0x0002854C PA_CL_VPORT_YSCALE_11 +0x00028550 PA_CL_VPORT_YOFFSET_11 +0x00028554 PA_CL_VPORT_ZSCALE_11 +0x00028558 PA_CL_VPORT_ZOFFSET_11 +0x0002855C PA_CL_VPORT_XSCALE_12 +0x00028560 PA_CL_VPORT_XOFFSET_12 +0x00028564 PA_CL_VPORT_YSCALE_12 +0x00028568 PA_CL_VPORT_YOFFSET_12 +0x0002856C PA_CL_VPORT_ZSCALE_12 +0x00028570 PA_CL_VPORT_ZOFFSET_12 +0x00028574 PA_CL_VPORT_XSCALE_13 +0x00028578 PA_CL_VPORT_XOFFSET_13 +0x0002857C PA_CL_VPORT_YSCALE_13 +0x00028580 PA_CL_VPORT_YOFFSET_13 +0x00028584 PA_CL_VPORT_ZSCALE_13 +0x00028588 PA_CL_VPORT_ZOFFSET_13 +0x0002858C PA_CL_VPORT_XSCALE_14 +0x00028590 PA_CL_VPORT_XOFFSET_14 +0x00028594 PA_CL_VPORT_YSCALE_14 +0x00028598 PA_CL_VPORT_YOFFSET_14 +0x0002859C PA_CL_VPORT_ZSCALE_14 +0x000285A0 PA_CL_VPORT_ZOFFSET_14 +0x000285A4 PA_CL_VPORT_XSCALE_15 +0x000285A8 PA_CL_VPORT_XOFFSET_15 +0x000285AC PA_CL_VPORT_YSCALE_15 +0x000285B0 PA_CL_VPORT_YOFFSET_15 +0x000285B4 PA_CL_VPORT_ZSCALE_15 +0x000285B8 PA_CL_VPORT_ZOFFSET_15 +0x000285BC PA_CL_UCP_0_X +0x000285C0 PA_CL_UCP_0_Y +0x000285C4 PA_CL_UCP_0_Z +0x000285C8 PA_CL_UCP_0_W +0x000285CC PA_CL_UCP_1_X +0x000285D0 PA_CL_UCP_1_Y +0x000285D4 PA_CL_UCP_1_Z +0x000285D8 PA_CL_UCP_1_W +0x000285DC PA_CL_UCP_2_X +0x000285E0 PA_CL_UCP_2_Y +0x000285E4 PA_CL_UCP_2_Z +0x000285E8 PA_CL_UCP_2_W +0x000285EC PA_CL_UCP_3_X +0x000285F0 PA_CL_UCP_3_Y +0x000285F4 PA_CL_UCP_3_Z +0x000285F8 PA_CL_UCP_3_W +0x000285FC PA_CL_UCP_4_X +0x00028600 PA_CL_UCP_4_Y +0x00028604 PA_CL_UCP_4_Z +0x00028608 PA_CL_UCP_4_W +0x0002860C PA_CL_UCP_5_X +0x00028610 PA_CL_UCP_5_Y +0x00028614 PA_CL_UCP_5_Z +0x00028618 PA_CL_UCP_5_W +0x0002861C SPI_VS_OUT_ID_0 +0x00028620 SPI_VS_OUT_ID_1 +0x00028624 SPI_VS_OUT_ID_2 +0x00028628 SPI_VS_OUT_ID_3 +0x0002862C SPI_VS_OUT_ID_4 +0x00028630 SPI_VS_OUT_ID_5 +0x00028634 SPI_VS_OUT_ID_6 +0x00028638 SPI_VS_OUT_ID_7 +0x0002863C SPI_VS_OUT_ID_8 +0x00028640 SPI_VS_OUT_ID_9 +0x00028644 SPI_PS_INPUT_CNTL_0 +0x00028648 SPI_PS_INPUT_CNTL_1 +0x0002864C SPI_PS_INPUT_CNTL_2 +0x00028650 SPI_PS_INPUT_CNTL_3 +0x00028654 SPI_PS_INPUT_CNTL_4 +0x00028658 SPI_PS_INPUT_CNTL_5 +0x0002865C SPI_PS_INPUT_CNTL_6 +0x00028660 SPI_PS_INPUT_CNTL_7 +0x00028664 SPI_PS_INPUT_CNTL_8 +0x00028668 SPI_PS_INPUT_CNTL_9 +0x0002866C SPI_PS_INPUT_CNTL_10 +0x00028670 SPI_PS_INPUT_CNTL_11 +0x00028674 SPI_PS_INPUT_CNTL_12 +0x00028678 SPI_PS_INPUT_CNTL_13 +0x0002867C SPI_PS_INPUT_CNTL_14 +0x00028680 SPI_PS_INPUT_CNTL_15 +0x00028684 SPI_PS_INPUT_CNTL_16 +0x00028688 SPI_PS_INPUT_CNTL_17 +0x0002868C SPI_PS_INPUT_CNTL_18 +0x00028690 SPI_PS_INPUT_CNTL_19 +0x00028694 SPI_PS_INPUT_CNTL_20 +0x00028698 SPI_PS_INPUT_CNTL_21 +0x0002869C SPI_PS_INPUT_CNTL_22 +0x000286A0 SPI_PS_INPUT_CNTL_23 +0x000286A4 SPI_PS_INPUT_CNTL_24 +0x000286A8 SPI_PS_INPUT_CNTL_25 +0x000286AC SPI_PS_INPUT_CNTL_26 +0x000286B0 SPI_PS_INPUT_CNTL_27 +0x000286B4 SPI_PS_INPUT_CNTL_28 +0x000286B8 SPI_PS_INPUT_CNTL_29 +0x000286BC SPI_PS_INPUT_CNTL_30 +0x000286C0 SPI_PS_INPUT_CNTL_31 +0x000286C4 SPI_VS_OUT_CONFIG +0x000286C8 SPI_THREAD_GROUPING +0x000286CC SPI_PS_IN_CONTROL_0 +0x000286D0 SPI_PS_IN_CONTROL_1 +0x000286D4 SPI_INTERP_CONTROL_0 +0x000286D8 SPI_INPUT_Z +0x000286DC SPI_FOG_CNTL +0x000286E0 SPI_BARYC_CNTL +0x000286E4 SPI_PS_IN_CONTROL_2 +0x000286E8 SPI_COMPUTE_INPUT_CNTL +0x000286EC SPI_COMPUTE_NUM_THREAD_X +0x000286F0 SPI_COMPUTE_NUM_THREAD_Y +0x000286F4 SPI_COMPUTE_NUM_THREAD_Z +0x000286F8 GDS_ADDR_SIZE +0x00028780 CB_BLEND0_CONTROL +0x00028784 CB_BLEND1_CONTROL +0x00028788 CB_BLEND2_CONTROL +0x0002878C CB_BLEND3_CONTROL +0x00028790 CB_BLEND4_CONTROL +0x00028794 CB_BLEND5_CONTROL +0x00028798 CB_BLEND6_CONTROL +0x0002879C CB_BLEND7_CONTROL +0x000287CC CS_COPY_STATE +0x000287D0 GFX_COPY_STATE +0x000287D4 PA_CL_POINT_X_RAD +0x000287D8 PA_CL_POINT_Y_RAD +0x000287DC PA_CL_POINT_SIZE +0x000287E0 PA_CL_POINT_CULL_RAD +0x00028808 CB_COLOR_CONTROL +0x0002880C DB_SHADER_CONTROL +0x00028810 PA_CL_CLIP_CNTL +0x00028814 PA_SU_SC_MODE_CNTL +0x00028818 PA_CL_VTE_CNTL +0x0002881C PA_CL_VS_OUT_CNTL +0x00028820 PA_CL_NANINF_CNTL +0x00028824 PA_SU_LINE_STIPPLE_CNTL +0x00028828 PA_SU_LINE_STIPPLE_SCALE +0x0002882C PA_SU_PRIM_FILTER_CNTL +0x00028838 SQ_DYN_GPR_RESOURCE_LIMIT_1 +0x00028844 SQ_PGM_RESOURCES_PS +0x00028848 SQ_PGM_RESOURCES_2_PS +0x0002884C SQ_PGM_EXPORTS_PS +0x0002885C SQ_PGM_RESOURCES_VS +0x00028860 SQ_PGM_RESOURCES_2_VS +0x00028878 SQ_PGM_RESOURCES_GS +0x0002887C SQ_PGM_RESOURCES_2_GS +0x00028890 SQ_PGM_RESOURCES_ES +0x00028894 SQ_PGM_RESOURCES_2_ES +0x000288A8 SQ_PGM_RESOURCES_FS +0x000288BC SQ_PGM_RESOURCES_HS +0x000288C0 SQ_PGM_RESOURCES_2_HS +0x000288D0 SQ_PGM_RESOURCES_LS +0x000288D4 SQ_PGM_RESOURCES_2_LS +0x000288E8 SQ_LDS_ALLOC +0x000288EC SQ_LDS_ALLOC_PS +0x000288F0 SQ_VTX_SEMANTIC_CLEAR +0x00028A00 PA_SU_POINT_SIZE +0x00028A04 PA_SU_POINT_MINMAX +0x00028A08 PA_SU_LINE_CNTL +0x00028A0C PA_SC_LINE_STIPPLE +0x00028A10 VGT_OUTPUT_PATH_CNTL +0x00028A14 VGT_HOS_CNTL +0x00028A18 VGT_HOS_MAX_TESS_LEVEL +0x00028A1C VGT_HOS_MIN_TESS_LEVEL +0x00028A20 VGT_HOS_REUSE_DEPTH +0x00028A24 VGT_GROUP_PRIM_TYPE +0x00028A28 VGT_GROUP_FIRST_DECR +0x00028A2C VGT_GROUP_DECR +0x00028A30 VGT_GROUP_VECT_0_CNTL +0x00028A34 VGT_GROUP_VECT_1_CNTL +0x00028A38 VGT_GROUP_VECT_0_FMT_CNTL +0x00028A3C VGT_GROUP_VECT_1_FMT_CNTL +0x00028A40 VGT_GS_MODE +0x00028A48 PA_SC_MODE_CNTL_0 +0x00028A4C PA_SC_MODE_CNTL_1 +0x00028A50 VGT_ENHANCE +0x00028A54 VGT_GS_PER_ES +0x00028A58 VGT_ES_PER_GS +0x00028A5C VGT_GS_PER_VS +0x00028A6C VGT_GS_OUT_PRIM_TYPE +0x00028A84 VGT_PRIMITIVEID_EN +0x00028A94 VGT_MULTI_PRIM_IB_RESET_EN +0x00028AA0 VGT_INSTANCE_STEP_RATE_0 +0x00028AA4 VGT_INSTANCE_STEP_RATE_1 +0x00028AB4 VGT_REUSE_OFF +0x00028AB8 VGT_VTX_CNT_EN +0x00028ABC DB_HTILE_SURFACE +0x00028AC0 DB_SRESULTS_COMPARE_STATE0 +0x00028AC4 DB_SRESULTS_COMPARE_STATE1 +0x00028AC8 DB_PRELOAD_CONTROL +0x00028B38 VGT_GS_MAX_VERT_OUT +0x00028B54 VGT_SHADER_STAGES_EN +0x00028B58 VGT_LS_HS_CONFIG +0x00028B5C VGT_LS_SIZE +0x00028B60 VGT_HS_SIZE +0x00028B64 VGT_LS_HS_ALLOC +0x00028B68 VGT_HS_PATCH_CONST +0x00028B6C VGT_TF_PARAM +0x00028B70 DB_ALPHA_TO_MASK +0x00028B74 VGT_DISPATCH_INITIATOR +0x00028B78 PA_SU_POLY_OFFSET_DB_FMT_CNTL +0x00028B7C PA_SU_POLY_OFFSET_CLAMP +0x00028B80 PA_SU_POLY_OFFSET_FRONT_SCALE +0x00028B84 PA_SU_POLY_OFFSET_FRONT_OFFSET +0x00028B88 PA_SU_POLY_OFFSET_BACK_SCALE +0x00028B8C PA_SU_POLY_OFFSET_BACK_OFFSET +0x00028B74 VGT_GS_INSTANCE_CNT +0x00028C00 PA_SC_LINE_CNTL +0x00028C08 PA_SU_VTX_CNTL +0x00028C0C PA_CL_GB_VERT_CLIP_ADJ +0x00028C10 PA_CL_GB_VERT_DISC_ADJ +0x00028C14 PA_CL_GB_HORZ_CLIP_ADJ +0x00028C18 PA_CL_GB_HORZ_DISC_ADJ +0x00028C1C PA_SC_AA_SAMPLE_LOCS_0 +0x00028C20 PA_SC_AA_SAMPLE_LOCS_1 +0x00028C24 PA_SC_AA_SAMPLE_LOCS_2 +0x00028C28 PA_SC_AA_SAMPLE_LOCS_3 +0x00028C2C PA_SC_AA_SAMPLE_LOCS_4 +0x00028C30 PA_SC_AA_SAMPLE_LOCS_5 +0x00028C34 PA_SC_AA_SAMPLE_LOCS_6 +0x00028C38 PA_SC_AA_SAMPLE_LOCS_7 +0x00028C3C PA_SC_AA_MASK +0x00028C8C CB_COLOR0_CLEAR_WORD0 +0x00028C90 CB_COLOR0_CLEAR_WORD1 +0x00028C94 CB_COLOR0_CLEAR_WORD2 +0x00028C98 CB_COLOR0_CLEAR_WORD3 +0x00028CC8 CB_COLOR1_CLEAR_WORD0 +0x00028CCC CB_COLOR1_CLEAR_WORD1 +0x00028CD0 CB_COLOR1_CLEAR_WORD2 +0x00028CD4 CB_COLOR1_CLEAR_WORD3 +0x00028D04 CB_COLOR2_CLEAR_WORD0 +0x00028D08 CB_COLOR2_CLEAR_WORD1 +0x00028D0C CB_COLOR2_CLEAR_WORD2 +0x00028D10 CB_COLOR2_CLEAR_WORD3 +0x00028D40 CB_COLOR3_CLEAR_WORD0 +0x00028D44 CB_COLOR3_CLEAR_WORD1 +0x00028D48 CB_COLOR3_CLEAR_WORD2 +0x00028D4C CB_COLOR3_CLEAR_WORD3 +0x00028D7C CB_COLOR4_CLEAR_WORD0 +0x00028D80 CB_COLOR4_CLEAR_WORD1 +0x00028D84 CB_COLOR4_CLEAR_WORD2 +0x00028D88 CB_COLOR4_CLEAR_WORD3 +0x00028DB8 CB_COLOR5_CLEAR_WORD0 +0x00028DBC CB_COLOR5_CLEAR_WORD1 +0x00028DC0 CB_COLOR5_CLEAR_WORD2 +0x00028DC4 CB_COLOR5_CLEAR_WORD3 +0x00028DF4 CB_COLOR6_CLEAR_WORD0 +0x00028DF8 CB_COLOR6_CLEAR_WORD1 +0x00028DFC CB_COLOR6_CLEAR_WORD2 +0x00028E00 CB_COLOR6_CLEAR_WORD3 +0x00028E30 CB_COLOR7_CLEAR_WORD0 +0x00028E34 CB_COLOR7_CLEAR_WORD1 +0x00028E38 CB_COLOR7_CLEAR_WORD2 +0x00028E3C CB_COLOR7_CLEAR_WORD3 +0x00028F80 SQ_ALU_CONST_BUFFER_SIZE_HS_0 +0x00028F84 SQ_ALU_CONST_BUFFER_SIZE_HS_1 +0x00028F88 SQ_ALU_CONST_BUFFER_SIZE_HS_2 +0x00028F8C SQ_ALU_CONST_BUFFER_SIZE_HS_3 +0x00028F90 SQ_ALU_CONST_BUFFER_SIZE_HS_4 +0x00028F94 SQ_ALU_CONST_BUFFER_SIZE_HS_5 +0x00028F98 SQ_ALU_CONST_BUFFER_SIZE_HS_6 +0x00028F9C SQ_ALU_CONST_BUFFER_SIZE_HS_7 +0x00028FA0 SQ_ALU_CONST_BUFFER_SIZE_HS_8 +0x00028FA4 SQ_ALU_CONST_BUFFER_SIZE_HS_9 +0x00028FA8 SQ_ALU_CONST_BUFFER_SIZE_HS_10 +0x00028FAC SQ_ALU_CONST_BUFFER_SIZE_HS_11 +0x00028FB0 SQ_ALU_CONST_BUFFER_SIZE_HS_12 +0x00028FB4 SQ_ALU_CONST_BUFFER_SIZE_HS_13 +0x00028FB8 SQ_ALU_CONST_BUFFER_SIZE_HS_14 +0x00028FBC SQ_ALU_CONST_BUFFER_SIZE_HS_15 +0x00028FC0 SQ_ALU_CONST_BUFFER_SIZE_LS_0 +0x00028FC4 SQ_ALU_CONST_BUFFER_SIZE_LS_1 +0x00028FC8 SQ_ALU_CONST_BUFFER_SIZE_LS_2 +0x00028FCC SQ_ALU_CONST_BUFFER_SIZE_LS_3 +0x00028FD0 SQ_ALU_CONST_BUFFER_SIZE_LS_4 +0x00028FD4 SQ_ALU_CONST_BUFFER_SIZE_LS_5 +0x00028FD8 SQ_ALU_CONST_BUFFER_SIZE_LS_6 +0x00028FDC SQ_ALU_CONST_BUFFER_SIZE_LS_7 +0x00028FE0 SQ_ALU_CONST_BUFFER_SIZE_LS_8 +0x00028FE4 SQ_ALU_CONST_BUFFER_SIZE_LS_9 +0x00028FE8 SQ_ALU_CONST_BUFFER_SIZE_LS_10 +0x00028FEC SQ_ALU_CONST_BUFFER_SIZE_LS_11 +0x00028FF0 SQ_ALU_CONST_BUFFER_SIZE_LS_12 +0x00028FF4 SQ_ALU_CONST_BUFFER_SIZE_LS_13 +0x00028FF8 SQ_ALU_CONST_BUFFER_SIZE_LS_14 +0x00028FFC SQ_ALU_CONST_BUFFER_SIZE_LS_15 +0x0003CFF0 SQ_VTX_BASE_VTX_LOC +0x0003CFF4 SQ_VTX_START_INST_LOC +0x0003FF00 SQ_TEX_SAMPLER_CLEAR +0x0003FF04 SQ_TEX_RESOURCE_CLEAR +0x0003FF08 SQ_LOOP_BOOL_CLEAR -- cgit v1.2.3 From 483d67ff0a208b43f0b97fca91d3a142afaba7fa Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 10 May 2010 03:51:02 -0300 Subject: V4L/DVB: bw-qcam: convert to V4L2 Note: due to lack of hardware I was not able to test this conversion. But it is pretty straightforward, so I do not expect any problems. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 2 +- drivers/media/video/bw-qcam.c | 759 +++++++++++++++++++++++------------------- drivers/media/video/bw-qcam.h | 69 ---- 3 files changed, 415 insertions(+), 415 deletions(-) delete mode 100644 drivers/media/video/bw-qcam.h (limited to 'drivers') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index ad9e6f9c22e9..42d198d5a87e 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -646,7 +646,7 @@ config VIDEO_PMS config VIDEO_BWQCAM tristate "Quickcam BW Video For Linux" - depends on PARPORT && VIDEO_V4L1 + depends on PARPORT && VIDEO_V4L2 help Say Y have if you the black and white version of the QuickCam camera. See the next option for the color version. diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c index 3c9e754d73a0..935e0c9a9674 100644 --- a/drivers/media/video/bw-qcam.c +++ b/drivers/media/video/bw-qcam.c @@ -66,19 +66,58 @@ OTHER DEALINGS IN THE SOFTWARE. #include #include #include -#include #include #include #include #include #include -#include -#include -#include +#include +#include #include #include - -#include "bw-qcam.h" +#include +#include +#include + +/* One from column A... */ +#define QC_NOTSET 0 +#define QC_UNIDIR 1 +#define QC_BIDIR 2 +#define QC_SERIAL 3 + +/* ... and one from column B */ +#define QC_ANY 0x00 +#define QC_FORCE_UNIDIR 0x10 +#define QC_FORCE_BIDIR 0x20 +#define QC_FORCE_SERIAL 0x30 +/* in the port_mode member */ + +#define QC_MODE_MASK 0x07 +#define QC_FORCE_MASK 0x70 + +#define MAX_HEIGHT 243 +#define MAX_WIDTH 336 + +/* Bit fields for status flags */ +#define QC_PARAM_CHANGE 0x01 /* Camera status change has occurred */ + +struct qcam { + struct v4l2_device v4l2_dev; + struct video_device vdev; + struct pardevice *pdev; + struct parport *pport; + struct mutex lock; + int width, height; + int bpp; + int mode; + int contrast, brightness, whitebal; + int port_mode; + int transfer_scale; + int top, left; + int status; + unsigned int saved_bits; + unsigned long in_use; +}; static unsigned int maxpoll = 250; /* Maximum busy-loop count for qcam I/O */ static unsigned int yieldlines = 4; /* Yield after this many during capture */ @@ -93,22 +132,26 @@ module_param(video_nr, int, 0); * immediately attempt to initialize qcam */ module_param(force_init, int, 0); -static inline int read_lpstatus(struct qcam_device *q) +#define MAX_CAMS 4 +static struct qcam *qcams[MAX_CAMS]; +static unsigned int num_cams; + +static inline int read_lpstatus(struct qcam *q) { return parport_read_status(q->pport); } -static inline int read_lpdata(struct qcam_device *q) +static inline int read_lpdata(struct qcam *q) { return parport_read_data(q->pport); } -static inline void write_lpdata(struct qcam_device *q, int d) +static inline void write_lpdata(struct qcam *q, int d) { parport_write_data(q->pport, d); } -static inline void write_lpcontrol(struct qcam_device *q, int d) +static void write_lpcontrol(struct qcam *q, int d) { if (d & 0x20) { /* Set bidirectional mode to reverse (data in) */ @@ -124,126 +167,11 @@ static inline void write_lpcontrol(struct qcam_device *q, int d) parport_write_control(q->pport, d); } -static int qc_waithand(struct qcam_device *q, int val); -static int qc_command(struct qcam_device *q, int command); -static int qc_readparam(struct qcam_device *q); -static int qc_setscanmode(struct qcam_device *q); -static int qc_readbytes(struct qcam_device *q, char buffer[]); - -static struct video_device qcam_template; - -static int qc_calibrate(struct qcam_device *q) -{ - /* - * Bugfix by Hanno Mueller hmueller@kabel.de, Mai 21 96 - * The white balance is an individiual value for each - * quickcam. - */ - - int value; - int count = 0; - - qc_command(q, 27); /* AutoAdjustOffset */ - qc_command(q, 0); /* Dummy Parameter, ignored by the camera */ - - /* GetOffset (33) will read 255 until autocalibration */ - /* is finished. After that, a value of 1-254 will be */ - /* returned. */ - - do { - qc_command(q, 33); - value = qc_readparam(q); - mdelay(1); - schedule(); - count++; - } while (value == 0xff && count < 2048); - - q->whitebal = value; - return value; -} - -/* Initialize the QuickCam driver control structure. This is where - * defaults are set for people who don't have a config file.*/ - -static struct qcam_device *qcam_init(struct parport *port) -{ - struct qcam_device *q; - - q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL); - if (q == NULL) - return NULL; - - q->pport = port; - q->pdev = parport_register_device(port, "bw-qcam", NULL, NULL, - NULL, 0, NULL); - if (q->pdev == NULL) { - printk(KERN_ERR "bw-qcam: couldn't register for %s.\n", - port->name); - kfree(q); - return NULL; - } - - memcpy(&q->vdev, &qcam_template, sizeof(qcam_template)); - - mutex_init(&q->lock); - - q->port_mode = (QC_ANY | QC_NOTSET); - q->width = 320; - q->height = 240; - q->bpp = 4; - q->transfer_scale = 2; - q->contrast = 192; - q->brightness = 180; - q->whitebal = 105; - q->top = 1; - q->left = 14; - q->mode = -1; - q->status = QC_PARAM_CHANGE; - return q; -} - - -/* qc_command is probably a bit of a misnomer -- it's used to send - * bytes *to* the camera. Generally, these bytes are either commands - * or arguments to commands, so the name fits, but it still bugs me a - * bit. See the documentation for a list of commands. */ - -static int qc_command(struct qcam_device *q, int command) -{ - int n1, n2; - int cmd; - - write_lpdata(q, command); - write_lpcontrol(q, 6); - - n1 = qc_waithand(q, 1); - - write_lpcontrol(q, 0xe); - n2 = qc_waithand(q, 0); - - cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4); - return cmd; -} - -static int qc_readparam(struct qcam_device *q) -{ - int n1, n2; - int cmd; - - write_lpcontrol(q, 6); - n1 = qc_waithand(q, 1); - - write_lpcontrol(q, 0xe); - n2 = qc_waithand(q, 0); - - cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4); - return cmd; -} /* qc_waithand busy-waits for a handshake signal from the QuickCam. * Almost all communication with the camera requires handshaking. */ -static int qc_waithand(struct qcam_device *q, int val) +static int qc_waithand(struct qcam *q, int val) { int status; int runs = 0; @@ -286,7 +214,7 @@ static int qc_waithand(struct qcam_device *q, int val) * (bit 3 of status register). It also returns the last value read, * since this data is useful. */ -static unsigned int qc_waithand2(struct qcam_device *q, int val) +static unsigned int qc_waithand2(struct qcam *q, int val) { unsigned int status; int runs = 0; @@ -309,6 +237,43 @@ static unsigned int qc_waithand2(struct qcam_device *q, int val) return status; } +/* qc_command is probably a bit of a misnomer -- it's used to send + * bytes *to* the camera. Generally, these bytes are either commands + * or arguments to commands, so the name fits, but it still bugs me a + * bit. See the documentation for a list of commands. */ + +static int qc_command(struct qcam *q, int command) +{ + int n1, n2; + int cmd; + + write_lpdata(q, command); + write_lpcontrol(q, 6); + + n1 = qc_waithand(q, 1); + + write_lpcontrol(q, 0xe); + n2 = qc_waithand(q, 0); + + cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4); + return cmd; +} + +static int qc_readparam(struct qcam *q) +{ + int n1, n2; + int cmd; + + write_lpcontrol(q, 6); + n1 = qc_waithand(q, 1); + + write_lpcontrol(q, 0xe); + n2 = qc_waithand(q, 0); + + cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4); + return cmd; +} + /* Try to detect a QuickCam. It appears to flash the upper 4 bits of the status register at 5-10 Hz. This is only used in the autoprobe @@ -317,7 +282,7 @@ static unsigned int qc_waithand2(struct qcam_device *q, int val) almost completely safe, while their method screws up my printer if I plug it in before the camera. */ -static int qc_detect(struct qcam_device *q) +static int qc_detect(struct qcam *q) { int reg, lastreg; int count = 0; @@ -358,41 +323,6 @@ static int qc_detect(struct qcam_device *q) } } - -/* Reset the QuickCam. This uses the same sequence the Windows - * QuickPic program uses. Someone with a bi-directional port should - * check that bi-directional mode is detected right, and then - * implement bi-directional mode in qc_readbyte(). */ - -static void qc_reset(struct qcam_device *q) -{ - switch (q->port_mode & QC_FORCE_MASK) { - case QC_FORCE_UNIDIR: - q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR; - break; - - case QC_FORCE_BIDIR: - q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR; - break; - - case QC_ANY: - write_lpcontrol(q, 0x20); - write_lpdata(q, 0x75); - - if (read_lpdata(q) != 0x75) - q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR; - else - q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR; - break; - } - - write_lpcontrol(q, 0xb); - udelay(250); - write_lpcontrol(q, 0xe); - qc_setscanmode(q); /* in case port_mode changed */ -} - - /* Decide which scan mode to use. There's no real requirement that * the scanmode match the resolution in q->height and q-> width -- the * camera takes the picture at the resolution specified in the @@ -402,7 +332,7 @@ static void qc_reset(struct qcam_device *q) * returned. If the scan is smaller, then the rest of the image * returned contains garbage. */ -static int qc_setscanmode(struct qcam_device *q) +static int qc_setscanmode(struct qcam *q) { int old_mode = q->mode; @@ -442,10 +372,45 @@ static int qc_setscanmode(struct qcam_device *q) } +/* Reset the QuickCam. This uses the same sequence the Windows + * QuickPic program uses. Someone with a bi-directional port should + * check that bi-directional mode is detected right, and then + * implement bi-directional mode in qc_readbyte(). */ + +static void qc_reset(struct qcam *q) +{ + switch (q->port_mode & QC_FORCE_MASK) { + case QC_FORCE_UNIDIR: + q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR; + break; + + case QC_FORCE_BIDIR: + q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR; + break; + + case QC_ANY: + write_lpcontrol(q, 0x20); + write_lpdata(q, 0x75); + + if (read_lpdata(q) != 0x75) + q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR; + else + q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR; + break; + } + + write_lpcontrol(q, 0xb); + udelay(250); + write_lpcontrol(q, 0xe); + qc_setscanmode(q); /* in case port_mode changed */ +} + + + /* Reset the QuickCam and program for brightness, contrast, * white-balance, and resolution. */ -static void qc_set(struct qcam_device *q) +static void qc_set(struct qcam *q) { int val; int val2; @@ -499,7 +464,7 @@ static void qc_set(struct qcam_device *q) the supplied buffer. It returns the number of bytes read, or -1 on error. */ -static inline int qc_readbytes(struct qcam_device *q, char buffer[]) +static inline int qc_readbytes(struct qcam *q, char buffer[]) { int ret = 1; unsigned int hi, lo; @@ -590,7 +555,7 @@ static inline int qc_readbytes(struct qcam_device *q, char buffer[]) * n=2^(bit depth)-1. Ask me for more details if you don't understand * this. */ -static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long len) +static long qc_capture(struct qcam *q, char __user *buf, unsigned long len) { int i, j, k, yield; int bytes; @@ -674,171 +639,206 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le * Video4linux interfacing */ -static long qcam_do_ioctl(struct file *file, unsigned int cmd, void *arg) +static int qcam_querycap(struct file *file, void *priv, + struct v4l2_capability *vcap) { - struct video_device *dev = video_devdata(file); - struct qcam_device *qcam = (struct qcam_device *)dev; - - switch (cmd) { - case VIDIOCGCAP: - { - struct video_capability *b = arg; - strcpy(b->name, "Quickcam"); - b->type = VID_TYPE_CAPTURE|VID_TYPE_SCALES|VID_TYPE_MONOCHROME; - b->channels = 1; - b->audios = 0; - b->maxwidth = 320; - b->maxheight = 240; - b->minwidth = 80; - b->minheight = 60; - return 0; - } - case VIDIOCGCHAN: - { - struct video_channel *v = arg; - if (v->channel != 0) - return -EINVAL; - v->flags = 0; - v->tuners = 0; - /* Good question.. its composite or SVHS so.. */ - v->type = VIDEO_TYPE_CAMERA; - strcpy(v->name, "Camera"); - return 0; - } - case VIDIOCSCHAN: - { - struct video_channel *v = arg; - if (v->channel != 0) - return -EINVAL; - return 0; - } - case VIDIOCGTUNER: - { - struct video_tuner *v = arg; - if (v->tuner) - return -EINVAL; - strcpy(v->name, "Format"); - v->rangelow = 0; - v->rangehigh = 0; - v->flags = 0; - v->mode = VIDEO_MODE_AUTO; - return 0; - } - case VIDIOCSTUNER: - { - struct video_tuner *v = arg; - if (v->tuner) - return -EINVAL; - if (v->mode != VIDEO_MODE_AUTO) - return -EINVAL; - return 0; - } - case VIDIOCGPICT: - { - struct video_picture *p = arg; - p->colour = 0x8000; - p->hue = 0x8000; - p->brightness = qcam->brightness << 8; - p->contrast = qcam->contrast << 8; - p->whiteness = qcam->whitebal << 8; - p->depth = qcam->bpp; - p->palette = VIDEO_PALETTE_GREY; - return 0; - } - case VIDIOCSPICT: - { - struct video_picture *p = arg; - if (p->palette != VIDEO_PALETTE_GREY) - return -EINVAL; - if (p->depth != 4 && p->depth != 6) - return -EINVAL; - - /* - * Now load the camera. - */ - - qcam->brightness = p->brightness >> 8; - qcam->contrast = p->contrast >> 8; - qcam->whitebal = p->whiteness >> 8; - qcam->bpp = p->depth; - - mutex_lock(&qcam->lock); - qc_setscanmode(qcam); - mutex_unlock(&qcam->lock); - qcam->status |= QC_PARAM_CHANGE; + struct qcam *qcam = video_drvdata(file); - return 0; - } - case VIDIOCSWIN: - { - struct video_window *vw = arg; - if (vw->flags) - return -EINVAL; - if (vw->clipcount) - return -EINVAL; - if (vw->height < 60 || vw->height > 240) - return -EINVAL; - if (vw->width < 80 || vw->width > 320) - return -EINVAL; - - qcam->width = 320; - qcam->height = 240; - qcam->transfer_scale = 4; - - if (vw->width >= 160 && vw->height >= 120) - qcam->transfer_scale = 2; - if (vw->width >= 320 && vw->height >= 240) { - qcam->width = 320; - qcam->height = 240; - qcam->transfer_scale = 1; - } - mutex_lock(&qcam->lock); - qc_setscanmode(qcam); - mutex_unlock(&qcam->lock); + strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver)); + strlcpy(vcap->card, "B&W Quickcam", sizeof(vcap->card)); + strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info)); + vcap->version = KERNEL_VERSION(0, 0, 2); + vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; + return 0; +} - /* We must update the camera before we grab. We could - just have changed the grab size */ - qcam->status |= QC_PARAM_CHANGE; +static int qcam_enum_input(struct file *file, void *fh, struct v4l2_input *vin) +{ + if (vin->index > 0) + return -EINVAL; + strlcpy(vin->name, "Camera", sizeof(vin->name)); + vin->type = V4L2_INPUT_TYPE_CAMERA; + vin->audioset = 0; + vin->tuner = 0; + vin->std = 0; + vin->status = 0; + return 0; +} - /* Ok we figured out what to use from our wide choice */ - return 0; - } - case VIDIOCGWIN: - { - struct video_window *vw = arg; +static int qcam_g_input(struct file *file, void *fh, unsigned int *inp) +{ + *inp = 0; + return 0; +} - memset(vw, 0, sizeof(*vw)); - vw->width = qcam->width / qcam->transfer_scale; - vw->height = qcam->height / qcam->transfer_scale; - return 0; - } - case VIDIOCKEY: - return 0; - case VIDIOCCAPTURE: - case VIDIOCGFBUF: - case VIDIOCSFBUF: - case VIDIOCGFREQ: - case VIDIOCSFREQ: - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: - return -EINVAL; +static int qcam_s_input(struct file *file, void *fh, unsigned int inp) +{ + return (inp > 0) ? -EINVAL : 0; +} + +static int qcam_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + switch (qc->id) { + case V4L2_CID_BRIGHTNESS: + return v4l2_ctrl_query_fill(qc, 0, 255, 1, 180); + case V4L2_CID_CONTRAST: + return v4l2_ctrl_query_fill(qc, 0, 255, 1, 192); + case V4L2_CID_GAMMA: + return v4l2_ctrl_query_fill(qc, 0, 255, 1, 105); + } + return -EINVAL; +} + +static int qcam_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct qcam *qcam = video_drvdata(file); + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + ctrl->value = qcam->brightness; + break; + case V4L2_CID_CONTRAST: + ctrl->value = qcam->contrast; + break; + case V4L2_CID_GAMMA: + ctrl->value = qcam->whitebal; + break; default: - return -ENOIOCTLCMD; + ret = -EINVAL; + break; } + return ret; +} + +static int qcam_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct qcam *qcam = video_drvdata(file); + int ret = 0; + + mutex_lock(&qcam->lock); + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + qcam->brightness = ctrl->value; + break; + case V4L2_CID_CONTRAST: + qcam->contrast = ctrl->value; + break; + case V4L2_CID_GAMMA: + qcam->whitebal = ctrl->value; + break; + default: + ret = -EINVAL; + break; + } + if (ret == 0) { + qc_setscanmode(qcam); + qcam->status |= QC_PARAM_CHANGE; + } + mutex_unlock(&qcam->lock); + return ret; +} + +static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct qcam *qcam = video_drvdata(file); + struct v4l2_pix_format *pix = &fmt->fmt.pix; + + pix->width = qcam->width / qcam->transfer_scale; + pix->height = qcam->height / qcam->transfer_scale; + pix->pixelformat = (qcam->bpp == 4) ? V4L2_PIX_FMT_Y4 : V4L2_PIX_FMT_Y6; + pix->field = V4L2_FIELD_NONE; + pix->bytesperline = qcam->width; + pix->sizeimage = qcam->width * qcam->height; + /* Just a guess */ + pix->colorspace = V4L2_COLORSPACE_SRGB; + return 0; +} + +static int qcam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct v4l2_pix_format *pix = &fmt->fmt.pix; + + if (pix->height <= 60 || pix->width <= 80) { + pix->height = 60; + pix->width = 80; + } else if (pix->height <= 120 || pix->width <= 160) { + pix->height = 120; + pix->width = 160; + } else { + pix->height = 240; + pix->width = 320; + } + if (pix->pixelformat != V4L2_PIX_FMT_Y4 && + pix->pixelformat != V4L2_PIX_FMT_Y6) + pix->pixelformat = V4L2_PIX_FMT_Y4; + pix->field = V4L2_FIELD_NONE; + pix->bytesperline = pix->width; + pix->sizeimage = pix->width * pix->height; + /* Just a guess */ + pix->colorspace = V4L2_COLORSPACE_SRGB; + return 0; +} + +static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct qcam *qcam = video_drvdata(file); + struct v4l2_pix_format *pix = &fmt->fmt.pix; + int ret = qcam_try_fmt_vid_cap(file, fh, fmt); + + if (ret) + return ret; + qcam->width = 320; + qcam->height = 240; + if (pix->height == 60) + qcam->transfer_scale = 4; + else if (pix->height == 120) + qcam->transfer_scale = 2; + else + qcam->transfer_scale = 1; + if (pix->pixelformat == V4L2_PIX_FMT_Y6) + qcam->bpp = 6; + else + qcam->bpp = 4; + + mutex_lock(&qcam->lock); + qc_setscanmode(qcam); + /* We must update the camera before we grab. We could + just have changed the grab size */ + qcam->status |= QC_PARAM_CHANGE; + mutex_unlock(&qcam->lock); return 0; } -static long qcam_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) +static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) { - return video_usercopy(file, cmd, arg, qcam_do_ioctl); + static struct v4l2_fmtdesc formats[] = { + { 0, 0, 0, + "4-Bit Monochrome", V4L2_PIX_FMT_Y4, + { 0, 0, 0, 0 } + }, + { 0, 0, 0, + "6-Bit Monochrome", V4L2_PIX_FMT_Y6, + { 0, 0, 0, 0 } + }, + }; + enum v4l2_buf_type type = fmt->type; + + if (fmt->index > 1) + return -EINVAL; + + *fmt = formats[fmt->index]; + fmt->type = type; + return 0; } static ssize_t qcam_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - struct video_device *v = video_devdata(file); - struct qcam_device *qcam = (struct qcam_device *)v; + struct qcam *qcam = video_drvdata(file); int len; parport_claim_or_block(qcam->pdev); @@ -858,43 +858,112 @@ static ssize_t qcam_read(struct file *file, char __user *buf, return len; } -static int qcam_exclusive_open(struct file *file) +static const struct v4l2_file_operations qcam_fops = { + .owner = THIS_MODULE, + .ioctl = video_ioctl2, + .read = qcam_read, +}; + +static const struct v4l2_ioctl_ops qcam_ioctl_ops = { + .vidioc_querycap = qcam_querycap, + .vidioc_g_input = qcam_g_input, + .vidioc_s_input = qcam_s_input, + .vidioc_enum_input = qcam_enum_input, + .vidioc_queryctrl = qcam_queryctrl, + .vidioc_g_ctrl = qcam_g_ctrl, + .vidioc_s_ctrl = qcam_s_ctrl, + .vidioc_enum_fmt_vid_cap = qcam_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = qcam_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = qcam_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = qcam_try_fmt_vid_cap, +}; + +/* Initialize the QuickCam driver control structure. This is where + * defaults are set for people who don't have a config file.*/ + +static struct qcam *qcam_init(struct parport *port) { - struct video_device *dev = video_devdata(file); - struct qcam_device *qcam = (struct qcam_device *)dev; + struct qcam *qcam; + struct v4l2_device *v4l2_dev; + + qcam = kzalloc(sizeof(struct qcam), GFP_KERNEL); + if (qcam == NULL) + return NULL; + + v4l2_dev = &qcam->v4l2_dev; + strlcpy(v4l2_dev->name, "bw-qcam", sizeof(v4l2_dev->name)); - return test_and_set_bit(0, &qcam->in_use) ? -EBUSY : 0; + if (v4l2_device_register(NULL, v4l2_dev) < 0) { + v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); + return NULL; + } + + qcam->pport = port; + qcam->pdev = parport_register_device(port, "bw-qcam", NULL, NULL, + NULL, 0, NULL); + if (qcam->pdev == NULL) { + v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name); + kfree(qcam); + return NULL; + } + + strlcpy(qcam->vdev.name, "Connectix QuickCam", sizeof(qcam->vdev.name)); + qcam->vdev.v4l2_dev = v4l2_dev; + qcam->vdev.fops = &qcam_fops; + qcam->vdev.ioctl_ops = &qcam_ioctl_ops; + qcam->vdev.release = video_device_release_empty; + video_set_drvdata(&qcam->vdev, qcam); + + mutex_init(&qcam->lock); + + qcam->port_mode = (QC_ANY | QC_NOTSET); + qcam->width = 320; + qcam->height = 240; + qcam->bpp = 4; + qcam->transfer_scale = 2; + qcam->contrast = 192; + qcam->brightness = 180; + qcam->whitebal = 105; + qcam->top = 1; + qcam->left = 14; + qcam->mode = -1; + qcam->status = QC_PARAM_CHANGE; + return qcam; } -static int qcam_exclusive_release(struct file *file) +static int qc_calibrate(struct qcam *q) { - struct video_device *dev = video_devdata(file); - struct qcam_device *qcam = (struct qcam_device *)dev; + /* + * Bugfix by Hanno Mueller hmueller@kabel.de, Mai 21 96 + * The white balance is an individual value for each + * quickcam. + */ - clear_bit(0, &qcam->in_use); - return 0; -} + int value; + int count = 0; -static const struct v4l2_file_operations qcam_fops = { - .owner = THIS_MODULE, - .open = qcam_exclusive_open, - .release = qcam_exclusive_release, - .ioctl = qcam_ioctl, - .read = qcam_read, -}; -static struct video_device qcam_template = { - .name = "Connectix Quickcam", - .fops = &qcam_fops, - .release = video_device_release_empty, -}; + qc_command(q, 27); /* AutoAdjustOffset */ + qc_command(q, 0); /* Dummy Parameter, ignored by the camera */ -#define MAX_CAMS 4 -static struct qcam_device *qcams[MAX_CAMS]; -static unsigned int num_cams; + /* GetOffset (33) will read 255 until autocalibration */ + /* is finished. After that, a value of 1-254 will be */ + /* returned. */ + + do { + qc_command(q, 33); + value = qc_readparam(q); + mdelay(1); + schedule(); + count++; + } while (value == 0xff && count < 2048); + + q->whitebal = value; + return value; +} static int init_bwqcam(struct parport *port) { - struct qcam_device *qcam; + struct qcam *qcam; if (num_cams == MAX_CAMS) { printk(KERN_ERR "Too many Quickcams (max %d)\n", MAX_CAMS); @@ -919,7 +988,7 @@ static int init_bwqcam(struct parport *port) parport_release(qcam->pdev); - printk(KERN_INFO "Connectix Quickcam on %s\n", qcam->pport->name); + v4l2_info(&qcam->v4l2_dev, "Connectix Quickcam on %s\n", qcam->pport->name); if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { parport_unregister_device(qcam->pdev); @@ -932,7 +1001,7 @@ static int init_bwqcam(struct parport *port) return 0; } -static void close_bwqcam(struct qcam_device *qcam) +static void close_bwqcam(struct qcam *qcam) { video_unregister_device(&qcam->vdev); parport_unregister_device(qcam->pdev); @@ -983,7 +1052,7 @@ static void bwqcam_detach(struct parport *port) { int i; for (i = 0; i < num_cams; i++) { - struct qcam_device *qcam = qcams[i]; + struct qcam *qcam = qcams[i]; if (qcam && qcam->pdev->port == port) { qcams[i] = NULL; close_bwqcam(qcam); diff --git a/drivers/media/video/bw-qcam.h b/drivers/media/video/bw-qcam.h deleted file mode 100644 index 8a60c5de0935..000000000000 --- a/drivers/media/video/bw-qcam.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Video4Linux bw-qcam driver - * - * Derived from code.. - */ - -/****************************************************************** - -Copyright (C) 1996 by Scott Laird - -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 SCOTT LAIRD 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. - -******************************************************************/ - -/* One from column A... */ -#define QC_NOTSET 0 -#define QC_UNIDIR 1 -#define QC_BIDIR 2 -#define QC_SERIAL 3 - -/* ... and one from column B */ -#define QC_ANY 0x00 -#define QC_FORCE_UNIDIR 0x10 -#define QC_FORCE_BIDIR 0x20 -#define QC_FORCE_SERIAL 0x30 -/* in the port_mode member */ - -#define QC_MODE_MASK 0x07 -#define QC_FORCE_MASK 0x70 - -#define MAX_HEIGHT 243 -#define MAX_WIDTH 336 - -/* Bit fields for status flags */ -#define QC_PARAM_CHANGE 0x01 /* Camera status change has occurred */ - -struct qcam_device { - struct video_device vdev; - struct pardevice *pdev; - struct parport *pport; - struct mutex lock; - int width, height; - int bpp; - int mode; - int contrast, brightness, whitebal; - int port_mode; - int transfer_scale; - int top, left; - int status; - unsigned int saved_bits; - unsigned long in_use; -}; -- cgit v1.2.3 From d71964fb9731412ce1f86cd7d9b71f1f94a04b0d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 10 May 2010 03:55:25 -0300 Subject: V4L/DVB: c-qcam: convert to V4L2 Note: due to lack of hardware this conversion is untested. However, it is pretty straightforward so I do not expect any problems. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 2 +- drivers/media/video/c-qcam.c | 634 ++++++++++++++++++++++--------------------- 2 files changed, 331 insertions(+), 305 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 42d198d5a87e..bdbc9d305419 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -656,7 +656,7 @@ config VIDEO_BWQCAM config VIDEO_CQCAM tristate "QuickCam Colour Video For Linux (EXPERIMENTAL)" - depends on EXPERIMENTAL && PARPORT && VIDEO_V4L1 + depends on EXPERIMENTAL && PARPORT && VIDEO_V4L2 help This is the video4linux driver for the colour version of the Connectix QuickCam. If you have one of these cameras, say Y here, diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c index 8f1dd88b32a6..6e4b19698c13 100644 --- a/drivers/media/video/c-qcam.c +++ b/drivers/media/video/c-qcam.c @@ -33,15 +33,17 @@ #include #include #include -#include -#include -#include #include #include - +#include +#include #include +#include +#include +#include -struct qcam_device { +struct qcam { + struct v4l2_device v4l2_dev; struct video_device vdev; struct pardevice *pdev; struct parport *pport; @@ -51,7 +53,6 @@ struct qcam_device { int contrast, brightness, whitebal; int top, left; unsigned int bidirectional; - unsigned long in_use; struct mutex lock; }; @@ -68,33 +69,45 @@ struct qcam_device { #define QC_DECIMATION_2 2 #define QC_DECIMATION_4 4 -#define BANNER "Colour QuickCam for Video4Linux v0.05" +#define BANNER "Colour QuickCam for Video4Linux v0.06" static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 }; static int probe = 2; static int force_rgb; static int video_nr = -1; -static inline void qcam_set_ack(struct qcam_device *qcam, unsigned int i) +/* FIXME: parport=auto would never have worked, surely? --RR */ +MODULE_PARM_DESC(parport, "parport= for port detection method\n" + "probe=<0|1|2> for camera detection method\n" + "force_rgb=<0|1> for RGB data format (default BGR)"); +module_param_array(parport, int, NULL, 0); +module_param(probe, int, 0); +module_param(force_rgb, bool, 0); +module_param(video_nr, int, 0); + +static struct qcam *qcams[MAX_CAMS]; +static unsigned int num_cams; + +static inline void qcam_set_ack(struct qcam *qcam, unsigned int i) { /* note: the QC specs refer to the PCAck pin by voltage, not software level. PC ports have builtin inverters. */ parport_frob_control(qcam->pport, 8, i ? 8 : 0); } -static inline unsigned int qcam_ready1(struct qcam_device *qcam) +static inline unsigned int qcam_ready1(struct qcam *qcam) { return (parport_read_status(qcam->pport) & 0x8) ? 1 : 0; } -static inline unsigned int qcam_ready2(struct qcam_device *qcam) +static inline unsigned int qcam_ready2(struct qcam *qcam) { return (parport_read_data(qcam->pport) & 0x1) ? 1 : 0; } -static unsigned int qcam_await_ready1(struct qcam_device *qcam, - int value) +static unsigned int qcam_await_ready1(struct qcam *qcam, int value) { + struct v4l2_device *v4l2_dev = &qcam->v4l2_dev; unsigned long oldjiffies = jiffies; unsigned int i; @@ -112,14 +125,15 @@ static unsigned int qcam_await_ready1(struct qcam_device *qcam, } /* Probably somebody pulled the plug out. Not much we can do. */ - printk(KERN_ERR "c-qcam: ready1 timeout (%d) %x %x\n", value, + v4l2_err(v4l2_dev, "ready1 timeout (%d) %x %x\n", value, parport_read_status(qcam->pport), parport_read_control(qcam->pport)); return 1; } -static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value) +static unsigned int qcam_await_ready2(struct qcam *qcam, int value) { + struct v4l2_device *v4l2_dev = &qcam->v4l2_dev; unsigned long oldjiffies = jiffies; unsigned int i; @@ -137,14 +151,14 @@ static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value) } /* Probably somebody pulled the plug out. Not much we can do. */ - printk(KERN_ERR "c-qcam: ready2 timeout (%d) %x %x %x\n", value, + v4l2_err(v4l2_dev, "ready2 timeout (%d) %x %x %x\n", value, parport_read_status(qcam->pport), parport_read_control(qcam->pport), parport_read_data(qcam->pport)); return 1; } -static int qcam_read_data(struct qcam_device *qcam) +static int qcam_read_data(struct qcam *qcam) { unsigned int idata; @@ -159,21 +173,22 @@ static int qcam_read_data(struct qcam_device *qcam) return idata; } -static int qcam_write_data(struct qcam_device *qcam, unsigned int data) +static int qcam_write_data(struct qcam *qcam, unsigned int data) { + struct v4l2_device *v4l2_dev = &qcam->v4l2_dev; unsigned int idata; parport_write_data(qcam->pport, data); idata = qcam_read_data(qcam); if (data != idata) { - printk(KERN_WARNING "cqcam: sent %x but received %x\n", data, + v4l2_warn(v4l2_dev, "sent %x but received %x\n", data, idata); return 1; } return 0; } -static inline int qcam_set(struct qcam_device *qcam, unsigned int cmd, unsigned int data) +static inline int qcam_set(struct qcam *qcam, unsigned int cmd, unsigned int data) { if (qcam_write_data(qcam, cmd)) return -1; @@ -182,14 +197,14 @@ static inline int qcam_set(struct qcam_device *qcam, unsigned int cmd, unsigned return 0; } -static inline int qcam_get(struct qcam_device *qcam, unsigned int cmd) +static inline int qcam_get(struct qcam *qcam, unsigned int cmd) { if (qcam_write_data(qcam, cmd)) return -1; return qcam_read_data(qcam); } -static int qc_detect(struct qcam_device *qcam) +static int qc_detect(struct qcam *qcam) { unsigned int stat, ostat, i, count = 0; @@ -246,7 +261,7 @@ static int qc_detect(struct qcam_device *qcam) return 0; } -static void qc_reset(struct qcam_device *qcam) +static void qc_reset(struct qcam *qcam) { parport_write_control(qcam->pport, 0xc); parport_write_control(qcam->pport, 0x8); @@ -258,55 +273,55 @@ static void qc_reset(struct qcam_device *qcam) /* Reset the QuickCam and program for brightness, contrast, * white-balance, and resolution. */ -static void qc_setup(struct qcam_device *q) +static void qc_setup(struct qcam *qcam) { - qc_reset(q); + qc_reset(qcam); /* Set the brightness. */ - qcam_set(q, 11, q->brightness); + qcam_set(qcam, 11, qcam->brightness); /* Set the height and width. These refer to the actual CCD area *before* applying the selected decimation. */ - qcam_set(q, 17, q->ccd_height); - qcam_set(q, 19, q->ccd_width / 2); + qcam_set(qcam, 17, qcam->ccd_height); + qcam_set(qcam, 19, qcam->ccd_width / 2); /* Set top and left. */ - qcam_set(q, 0xd, q->top); - qcam_set(q, 0xf, q->left); + qcam_set(qcam, 0xd, qcam->top); + qcam_set(qcam, 0xf, qcam->left); /* Set contrast and white balance. */ - qcam_set(q, 0x19, q->contrast); - qcam_set(q, 0x1f, q->whitebal); + qcam_set(qcam, 0x19, qcam->contrast); + qcam_set(qcam, 0x1f, qcam->whitebal); /* Set the speed. */ - qcam_set(q, 45, 2); + qcam_set(qcam, 45, 2); } /* Read some bytes from the camera and put them in the buffer. nbytes should be a multiple of 3, because bidirectional mode gives us three bytes at a time. */ -static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, unsigned int nbytes) +static unsigned int qcam_read_bytes(struct qcam *qcam, unsigned char *buf, unsigned int nbytes) { unsigned int bytes = 0; - qcam_set_ack(q, 0); - if (q->bidirectional) { + qcam_set_ack(qcam, 0); + if (qcam->bidirectional) { /* It's a bidirectional port */ while (bytes < nbytes) { unsigned int lo1, hi1, lo2, hi2; unsigned char r, g, b; - if (qcam_await_ready2(q, 1)) + if (qcam_await_ready2(qcam, 1)) return bytes; - lo1 = parport_read_data(q->pport) >> 1; - hi1 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10; - qcam_set_ack(q, 1); - if (qcam_await_ready2(q, 0)) + lo1 = parport_read_data(qcam->pport) >> 1; + hi1 = ((parport_read_status(qcam->pport) >> 3) & 0x1f) ^ 0x10; + qcam_set_ack(qcam, 1); + if (qcam_await_ready2(qcam, 0)) return bytes; - lo2 = parport_read_data(q->pport) >> 1; - hi2 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10; - qcam_set_ack(q, 0); + lo2 = parport_read_data(qcam->pport) >> 1; + hi2 = ((parport_read_status(qcam->pport) >> 3) & 0x1f) ^ 0x10; + qcam_set_ack(qcam, 0); r = lo1 | ((hi1 & 1) << 7); g = ((hi1 & 0x1e) << 3) | ((hi2 & 0x1e) >> 1); b = lo2 | ((hi2 & 1) << 7); @@ -328,14 +343,14 @@ static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, u while (bytes < nbytes) { unsigned int hi, lo; - if (qcam_await_ready1(q, 1)) + if (qcam_await_ready1(qcam, 1)) return bytes; - hi = (parport_read_status(q->pport) & 0xf0); - qcam_set_ack(q, 1); - if (qcam_await_ready1(q, 0)) + hi = (parport_read_status(qcam->pport) & 0xf0); + qcam_set_ack(qcam, 1); + if (qcam_await_ready1(qcam, 0)) return bytes; - lo = (parport_read_status(q->pport) & 0xf0); - qcam_set_ack(q, 0); + lo = (parport_read_status(qcam->pport) & 0xf0); + qcam_set_ack(qcam, 0); /* flip some bits */ rgb[(i = bytes++ % 3)] = (hi | (lo >> 4)) ^ 0x88; if (i >= 2) { @@ -361,10 +376,11 @@ get_fragment: #define BUFSZ 150 -static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long len) +static long qc_capture(struct qcam *qcam, char __user *buf, unsigned long len) { + struct v4l2_device *v4l2_dev = &qcam->v4l2_dev; unsigned lines, pixelsperline, bitsperxfer; - unsigned int is_bi_dir = q->bidirectional; + unsigned int is_bi_dir = qcam->bidirectional; size_t wantlen, outptr = 0; char tmpbuf[BUFSZ]; @@ -373,10 +389,10 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le /* Wait for camera to become ready */ for (;;) { - int i = qcam_get(q, 41); + int i = qcam_get(qcam, 41); if (i == -1) { - qc_setup(q); + qc_setup(qcam); return -EIO; } if ((i & 0x80) == 0) @@ -384,25 +400,25 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le schedule(); } - if (qcam_set(q, 7, (q->mode | (is_bi_dir ? 1 : 0)) + 1)) + if (qcam_set(qcam, 7, (qcam->mode | (is_bi_dir ? 1 : 0)) + 1)) return -EIO; - lines = q->height; - pixelsperline = q->width; + lines = qcam->height; + pixelsperline = qcam->width; bitsperxfer = (is_bi_dir) ? 24 : 8; if (is_bi_dir) { /* Turn the port around */ - parport_data_reverse(q->pport); + parport_data_reverse(qcam->pport); mdelay(3); - qcam_set_ack(q, 0); - if (qcam_await_ready1(q, 1)) { - qc_setup(q); + qcam_set_ack(qcam, 0); + if (qcam_await_ready1(qcam, 1)) { + qc_setup(qcam); return -EIO; } - qcam_set_ack(q, 1); - if (qcam_await_ready1(q, 0)) { - qc_setup(q); + qcam_set_ack(qcam, 1); + if (qcam_await_ready1(qcam, 0)) { + qc_setup(qcam); return -EIO; } } @@ -413,7 +429,7 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le size_t t, s; s = (wantlen > BUFSZ) ? BUFSZ : wantlen; - t = qcam_read_bytes(q, tmpbuf, s); + t = qcam_read_bytes(qcam, tmpbuf, s); if (outptr < len) { size_t sz = len - outptr; @@ -432,10 +448,10 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le len = outptr; if (wantlen) { - printk(KERN_ERR "qcam: short read.\n"); + v4l2_err(v4l2_dev, "short read.\n"); if (is_bi_dir) - parport_data_forward(q->pport); - qc_setup(q); + parport_data_forward(qcam->pport); + qc_setup(qcam); return len; } @@ -443,49 +459,49 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le int l; do { - l = qcam_read_bytes(q, tmpbuf, 3); + l = qcam_read_bytes(qcam, tmpbuf, 3); cond_resched(); } while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e)); if (force_rgb) { if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf) - printk(KERN_ERR "qcam: bad EOF\n"); + v4l2_err(v4l2_dev, "bad EOF\n"); } else { if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe) - printk(KERN_ERR "qcam: bad EOF\n"); + v4l2_err(v4l2_dev, "bad EOF\n"); } - qcam_set_ack(q, 0); - if (qcam_await_ready1(q, 1)) { - printk(KERN_ERR "qcam: no ack after EOF\n"); - parport_data_forward(q->pport); - qc_setup(q); + qcam_set_ack(qcam, 0); + if (qcam_await_ready1(qcam, 1)) { + v4l2_err(v4l2_dev, "no ack after EOF\n"); + parport_data_forward(qcam->pport); + qc_setup(qcam); return len; } - parport_data_forward(q->pport); + parport_data_forward(qcam->pport); mdelay(3); - qcam_set_ack(q, 1); - if (qcam_await_ready1(q, 0)) { - printk(KERN_ERR "qcam: no ack to port turnaround\n"); - qc_setup(q); + qcam_set_ack(qcam, 1); + if (qcam_await_ready1(qcam, 0)) { + v4l2_err(v4l2_dev, "no ack to port turnaround\n"); + qc_setup(qcam); return len; } } else { int l; do { - l = qcam_read_bytes(q, tmpbuf, 1); + l = qcam_read_bytes(qcam, tmpbuf, 1); cond_resched(); } while (l && tmpbuf[0] == 0x7e); - l = qcam_read_bytes(q, tmpbuf + 1, 2); + l = qcam_read_bytes(qcam, tmpbuf + 1, 2); if (force_rgb) { if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf) - printk(KERN_ERR "qcam: bad EOF\n"); + v4l2_err(v4l2_dev, "bad EOF\n"); } else { if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe) - printk(KERN_ERR "qcam: bad EOF\n"); + v4l2_err(v4l2_dev, "bad EOF\n"); } } - qcam_write_data(q, 0); + qcam_write_data(qcam, 0); return len; } @@ -493,184 +509,202 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le * Video4linux interfacing */ -static long qcam_do_ioctl(struct file *file, unsigned int cmd, void *arg) +static int qcam_querycap(struct file *file, void *priv, + struct v4l2_capability *vcap) { - struct video_device *dev = video_devdata(file); - struct qcam_device *qcam = (struct qcam_device *)dev; + struct qcam *qcam = video_drvdata(file); - switch (cmd) { - case VIDIOCGCAP: - { - struct video_capability *b = arg; + strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver)); + strlcpy(vcap->card, "Color Quickcam", sizeof(vcap->card)); + strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info)); + vcap->version = KERNEL_VERSION(0, 0, 3); + vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; + return 0; +} - strcpy(b->name, "Quickcam"); - b->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; - b->channels = 1; - b->audios = 0; - b->maxwidth = 320; - b->maxheight = 240; - b->minwidth = 80; - b->minheight = 60; - return 0; - } - case VIDIOCGCHAN: - { - struct video_channel *v = arg; - - if (v->channel != 0) - return -EINVAL; - v->flags = 0; - v->tuners = 0; - /* Good question.. its composite or SVHS so.. */ - v->type = VIDEO_TYPE_CAMERA; - strcpy(v->name, "Camera"); - return 0; - } - case VIDIOCSCHAN: - { - struct video_channel *v = arg; +static int qcam_enum_input(struct file *file, void *fh, struct v4l2_input *vin) +{ + if (vin->index > 0) + return -EINVAL; + strlcpy(vin->name, "Camera", sizeof(vin->name)); + vin->type = V4L2_INPUT_TYPE_CAMERA; + vin->audioset = 0; + vin->tuner = 0; + vin->std = 0; + vin->status = 0; + return 0; +} - if (v->channel != 0) - return -EINVAL; - return 0; - } - case VIDIOCGTUNER: - { - struct video_tuner *v = arg; - - if (v->tuner) - return -EINVAL; - memset(v, 0, sizeof(*v)); - strcpy(v->name, "Format"); - v->mode = VIDEO_MODE_AUTO; - return 0; +static int qcam_g_input(struct file *file, void *fh, unsigned int *inp) +{ + *inp = 0; + return 0; +} + +static int qcam_s_input(struct file *file, void *fh, unsigned int inp) +{ + return (inp > 0) ? -EINVAL : 0; +} + +static int qcam_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + switch (qc->id) { + case V4L2_CID_BRIGHTNESS: + return v4l2_ctrl_query_fill(qc, 0, 255, 1, 240); + case V4L2_CID_CONTRAST: + return v4l2_ctrl_query_fill(qc, 0, 255, 1, 192); + case V4L2_CID_GAMMA: + return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128); } - case VIDIOCSTUNER: - { - struct video_tuner *v = arg; - - if (v->tuner) - return -EINVAL; - if (v->mode != VIDEO_MODE_AUTO) - return -EINVAL; - return 0; + return -EINVAL; +} + +static int qcam_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct qcam *qcam = video_drvdata(file); + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + ctrl->value = qcam->brightness; + break; + case V4L2_CID_CONTRAST: + ctrl->value = qcam->contrast; + break; + case V4L2_CID_GAMMA: + ctrl->value = qcam->whitebal; + break; + default: + ret = -EINVAL; + break; } - case VIDIOCGPICT: - { - struct video_picture *p = arg; - - p->colour = 0x8000; - p->hue = 0x8000; - p->brightness = qcam->brightness << 8; - p->contrast = qcam->contrast << 8; - p->whiteness = qcam->whitebal << 8; - p->depth = 24; - p->palette = VIDEO_PALETTE_RGB24; - return 0; + return ret; +} + +static int qcam_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct qcam *qcam = video_drvdata(file); + int ret = 0; + + mutex_lock(&qcam->lock); + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + qcam->brightness = ctrl->value; + break; + case V4L2_CID_CONTRAST: + qcam->contrast = ctrl->value; + break; + case V4L2_CID_GAMMA: + qcam->whitebal = ctrl->value; + break; + default: + ret = -EINVAL; + break; } - case VIDIOCSPICT: - { - struct video_picture *p = arg; - - /* - * Sanity check args - */ - if (p->depth != 24 || p->palette != VIDEO_PALETTE_RGB24) - return -EINVAL; - - /* - * Now load the camera. - */ - qcam->brightness = p->brightness >> 8; - qcam->contrast = p->contrast >> 8; - qcam->whitebal = p->whiteness >> 8; - - mutex_lock(&qcam->lock); + if (ret == 0) { parport_claim_or_block(qcam->pdev); qc_setup(qcam); parport_release(qcam->pdev); - mutex_unlock(&qcam->lock); - return 0; } - case VIDIOCSWIN: - { - struct video_window *vw = arg; - - if (vw->flags) - return -EINVAL; - if (vw->clipcount) - return -EINVAL; - if (vw->height < 60 || vw->height > 240) - return -EINVAL; - if (vw->width < 80 || vw->width > 320) - return -EINVAL; - - qcam->width = 80; - qcam->height = 60; - qcam->mode = QC_DECIMATION_4; + mutex_unlock(&qcam->lock); + return ret; +} - if (vw->width >= 160 && vw->height >= 120) { - qcam->width = 160; - qcam->height = 120; - qcam->mode = QC_DECIMATION_2; - } - if (vw->width >= 320 && vw->height >= 240) { - qcam->width = 320; - qcam->height = 240; - qcam->mode = QC_DECIMATION_1; - } - qcam->mode |= QC_MILLIONS; -#if 0 - if (vw->width >= 640 && vw->height >= 480) { - qcam->width = 640; - qcam->height = 480; - qcam->mode = QC_BILLIONS | QC_DECIMATION_1; - } -#endif - /* Ok we figured out what to use from our - wide choice */ - mutex_lock(&qcam->lock); - parport_claim_or_block(qcam->pdev); - qc_setup(qcam); - parport_release(qcam->pdev); - mutex_unlock(&qcam->lock); - return 0; - } - case VIDIOCGWIN: - { - struct video_window *vw = arg; - memset(vw, 0, sizeof(*vw)); - vw->width = qcam->width; - vw->height = qcam->height; - return 0; +static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct qcam *qcam = video_drvdata(file); + struct v4l2_pix_format *pix = &fmt->fmt.pix; + + pix->width = qcam->width; + pix->height = qcam->height; + pix->pixelformat = V4L2_PIX_FMT_RGB24; + pix->field = V4L2_FIELD_NONE; + pix->bytesperline = 3 * qcam->width; + pix->sizeimage = 3 * qcam->width * qcam->height; + /* Just a guess */ + pix->colorspace = V4L2_COLORSPACE_SRGB; + return 0; +} + +static int qcam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct v4l2_pix_format *pix = &fmt->fmt.pix; + + if (pix->height < 60 || pix->width < 80) { + pix->height = 60; + pix->width = 80; + } else if (pix->height < 120 || pix->width < 160) { + pix->height = 120; + pix->width = 160; + } else { + pix->height = 240; + pix->width = 320; } - case VIDIOCKEY: - return 0; - case VIDIOCCAPTURE: - case VIDIOCGFBUF: - case VIDIOCSFBUF: - case VIDIOCGFREQ: - case VIDIOCSFREQ: - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: - return -EINVAL; + pix->pixelformat = V4L2_PIX_FMT_RGB24; + pix->field = V4L2_FIELD_NONE; + pix->bytesperline = 3 * pix->width; + pix->sizeimage = 3 * pix->width * pix->height; + /* Just a guess */ + pix->colorspace = V4L2_COLORSPACE_SRGB; + return 0; +} + +static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct qcam *qcam = video_drvdata(file); + struct v4l2_pix_format *pix = &fmt->fmt.pix; + int ret = qcam_try_fmt_vid_cap(file, fh, fmt); + + if (ret) + return ret; + switch (pix->height) { + case 60: + qcam->mode = QC_DECIMATION_4; + break; + case 120: + qcam->mode = QC_DECIMATION_2; + break; default: - return -ENOIOCTLCMD; + qcam->mode = QC_DECIMATION_1; + break; } + + mutex_lock(&qcam->lock); + qcam->mode |= QC_MILLIONS; + qcam->height = pix->height; + qcam->width = pix->width; + parport_claim_or_block(qcam->pdev); + qc_setup(qcam); + parport_release(qcam->pdev); + mutex_unlock(&qcam->lock); return 0; } -static long qcam_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) +static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) { - return video_usercopy(file, cmd, arg, qcam_do_ioctl); + static struct v4l2_fmtdesc formats[] = { + { 0, 0, 0, + "RGB 8:8:8", V4L2_PIX_FMT_RGB24, + { 0, 0, 0, 0 } + }, + }; + enum v4l2_buf_type type = fmt->type; + + if (fmt->index > 0) + return -EINVAL; + + *fmt = formats[fmt->index]; + fmt->type = type; + return 0; } static ssize_t qcam_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - struct video_device *v = video_devdata(file); - struct qcam_device *qcam = (struct qcam_device *)v; + struct qcam *qcam = video_drvdata(file); int len; mutex_lock(&qcam->lock); @@ -682,81 +716,80 @@ static ssize_t qcam_read(struct file *file, char __user *buf, return len; } -static int qcam_exclusive_open(struct file *file) -{ - struct video_device *dev = video_devdata(file); - struct qcam_device *qcam = (struct qcam_device *)dev; - - return test_and_set_bit(0, &qcam->in_use) ? -EBUSY : 0; -} - -static int qcam_exclusive_release(struct file *file) -{ - struct video_device *dev = video_devdata(file); - struct qcam_device *qcam = (struct qcam_device *)dev; - - clear_bit(0, &qcam->in_use); - return 0; -} - -/* video device template */ static const struct v4l2_file_operations qcam_fops = { .owner = THIS_MODULE, - .open = qcam_exclusive_open, - .release = qcam_exclusive_release, - .ioctl = qcam_ioctl, + .ioctl = video_ioctl2, .read = qcam_read, }; -static struct video_device qcam_template = { - .name = "Colour QuickCam", - .fops = &qcam_fops, - .release = video_device_release_empty, +static const struct v4l2_ioctl_ops qcam_ioctl_ops = { + .vidioc_querycap = qcam_querycap, + .vidioc_g_input = qcam_g_input, + .vidioc_s_input = qcam_s_input, + .vidioc_enum_input = qcam_enum_input, + .vidioc_queryctrl = qcam_queryctrl, + .vidioc_g_ctrl = qcam_g_ctrl, + .vidioc_s_ctrl = qcam_s_ctrl, + .vidioc_enum_fmt_vid_cap = qcam_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = qcam_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = qcam_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = qcam_try_fmt_vid_cap, }; /* Initialize the QuickCam driver control structure. */ -static struct qcam_device *qcam_init(struct parport *port) +static struct qcam *qcam_init(struct parport *port) { - struct qcam_device *q; + struct qcam *qcam; + struct v4l2_device *v4l2_dev; - q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL); - if (q == NULL) + qcam = kzalloc(sizeof(*qcam), GFP_KERNEL); + if (qcam == NULL) return NULL; - q->pport = port; - q->pdev = parport_register_device(port, "c-qcam", NULL, NULL, + v4l2_dev = &qcam->v4l2_dev; + strlcpy(v4l2_dev->name, "c-qcam", sizeof(v4l2_dev->name)); + + if (v4l2_device_register(NULL, v4l2_dev) < 0) { + v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); + return NULL; + } + + qcam->pport = port; + qcam->pdev = parport_register_device(port, "c-qcam", NULL, NULL, NULL, 0, NULL); - q->bidirectional = (q->pport->modes & PARPORT_MODE_TRISTATE) ? 1 : 0; + qcam->bidirectional = (qcam->pport->modes & PARPORT_MODE_TRISTATE) ? 1 : 0; - if (q->pdev == NULL) { - printk(KERN_ERR "c-qcam: couldn't register for %s.\n", - port->name); - kfree(q); + if (qcam->pdev == NULL) { + v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name); + kfree(qcam); return NULL; } - memcpy(&q->vdev, &qcam_template, sizeof(qcam_template)); - - mutex_init(&q->lock); - q->width = q->ccd_width = 320; - q->height = q->ccd_height = 240; - q->mode = QC_MILLIONS | QC_DECIMATION_1; - q->contrast = 192; - q->brightness = 240; - q->whitebal = 128; - q->top = 1; - q->left = 14; - return q; + strlcpy(qcam->vdev.name, "Colour QuickCam", sizeof(qcam->vdev.name)); + qcam->vdev.v4l2_dev = v4l2_dev; + qcam->vdev.fops = &qcam_fops; + qcam->vdev.ioctl_ops = &qcam_ioctl_ops; + qcam->vdev.release = video_device_release_empty; + video_set_drvdata(&qcam->vdev, qcam); + + mutex_init(&qcam->lock); + qcam->width = qcam->ccd_width = 320; + qcam->height = qcam->ccd_height = 240; + qcam->mode = QC_MILLIONS | QC_DECIMATION_1; + qcam->contrast = 192; + qcam->brightness = 240; + qcam->whitebal = 128; + qcam->top = 1; + qcam->left = 14; + return qcam; } -static struct qcam_device *qcams[MAX_CAMS]; -static unsigned int num_cams; - static int init_cqcam(struct parport *port) { - struct qcam_device *qcam; + struct qcam *qcam; + struct v4l2_device *v4l2_dev; if (parport[0] != -1) { /* The user gave specific instructions */ @@ -777,6 +810,8 @@ static int init_cqcam(struct parport *port) if (qcam == NULL) return -ENODEV; + v4l2_dev = &qcam->v4l2_dev; + parport_claim_or_block(qcam->pdev); qc_reset(qcam); @@ -793,14 +828,14 @@ static int init_cqcam(struct parport *port) parport_release(qcam->pdev); if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { - printk(KERN_ERR "Unable to register Colour QuickCam on %s\n", + v4l2_err(v4l2_dev, "Unable to register Colour QuickCam on %s\n", qcam->pport->name); parport_unregister_device(qcam->pdev); kfree(qcam); return -ENODEV; } - printk(KERN_INFO "%s: Colour QuickCam found on %s\n", + v4l2_info(v4l2_dev, "%s: Colour QuickCam found on %s\n", video_device_node_name(&qcam->vdev), qcam->pport->name); qcams[num_cams++] = qcam; @@ -808,7 +843,7 @@ static int init_cqcam(struct parport *port) return 0; } -static void close_cqcam(struct qcam_device *qcam) +static void close_cqcam(struct qcam *qcam) { video_unregister_device(&qcam->vdev); parport_unregister_device(qcam->pdev); @@ -833,7 +868,7 @@ static struct parport_driver cqcam_driver = { static int __init cqcam_init(void) { - printk(BANNER "\n"); + printk(KERN_INFO BANNER "\n"); return parport_register_driver(&cqcam_driver); } @@ -852,14 +887,5 @@ MODULE_AUTHOR("Philip Blundell "); MODULE_DESCRIPTION(BANNER); MODULE_LICENSE("GPL"); -/* FIXME: parport=auto would never have worked, surely? --RR */ -MODULE_PARM_DESC(parport, "parport= for port detection method\n" - "probe=<0|1|2> for camera detection method\n" - "force_rgb=<0|1> for RGB data format (default BGR)"); -module_param_array(parport, int, NULL, 0); -module_param(probe, int, 0); -module_param(force_rgb, bool, 0); -module_param(video_nr, int, 0); - module_init(cqcam_init); module_exit(cqcam_cleanup); -- cgit v1.2.3 From e4425eab6b2da050bae55cffa01e573767a819a1 Mon Sep 17 00:00:00 2001 From: Abylay Ospan Date: Wed, 12 May 2010 04:24:09 -0300 Subject: V4L/DVB: cx23885: Check register errors Fix kernel Oops when number of NetUP Dual DVB-S2-CI cards more than DVB_MAX_ADAPTERS limit. [mchehab@redhat.com: move the return to the proper place] Signed-off-by: Abylay Ospan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-dvb.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 9e1460828b2f..0a199d774d9b 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -991,6 +991,8 @@ static int dvb_register(struct cx23885_tsport *port) ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port, &dev->pci->dev, adapter_nr, 0, cx23885_dvb_fe_ioctl_override); + if (!ret) + return ret; /* init CI & MAC */ switch (dev->board) { -- cgit v1.2.3 From c641a18969178ac1649e022156c85adb7c889451 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 15 May 2010 00:07:04 -0300 Subject: V4L/DVB: pvrusb2: Fix Gotview hardware support pvrusb2: Fix RF tuner problem with gotview hardware - this bug was introduced when switching over to the subdev model of driver control Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-devattr.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c index 6bc16c13ccef..3092abfd66a2 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c @@ -117,6 +117,7 @@ static const struct pvr2_device_desc pvr2_device_24xxx = { static const struct pvr2_device_client_desc pvr2_cli_gotview_2[] = { { .module_id = PVR2_CLIENT_ID_CX25840 }, { .module_id = PVR2_CLIENT_ID_TUNER }, + { .module_id = PVR2_CLIENT_ID_DEMOD }, }; static const struct pvr2_device_desc pvr2_device_gotview_2 = { -- cgit v1.2.3 From 6861800c1512ca8452c5f350a7c0af445ece773b Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 15 May 2010 00:09:47 -0300 Subject: V4L/DVB: pvrusb2: Avoid using stack allocated buffers when performing USB I/O Drivers shouldn't assume that the stack is DMA-safe. [mchehab@redhat.com: fix patch description] Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 301ef197d038..d13232d51823 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -4084,12 +4084,20 @@ void pvr2_hdw_device_reset(struct pvr2_hdw *hdw) void pvr2_hdw_cpureset_assert(struct pvr2_hdw *hdw,int val) { - char da[1]; + char *da; unsigned int pipe; int ret; if (!hdw->usb_dev) return; + da = kmalloc(16, GFP_KERNEL); + + if (da == NULL) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Unable to allocate memory to control CPU reset"); + return; + } + pvr2_trace(PVR2_TRACE_INIT,"cpureset_assert(%d)",val); da[0] = val ? 0x01 : 0x00; @@ -4103,6 +4111,8 @@ void pvr2_hdw_cpureset_assert(struct pvr2_hdw *hdw,int val) "cpureset_assert(%d) error=%d",val,ret); pvr2_hdw_render_useless(hdw); } + + kfree(da); } -- cgit v1.2.3 From 8fd0444817e557568d8bddd77828d9ae0d606e04 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 15 May 2010 00:13:35 -0300 Subject: V4L/DVB: pvrusb2: New feature to mark specific hardware support as experimental This adds a flag in the device attribute structure which can be used to mark support for a particular device as experimental. Any devices flagged in this way, when encountered at run-time, will generate a warning message to the kernel log. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-devattr.h | 5 +++++ drivers/media/video/pvrusb2/pvrusb2-hdw.c | 13 +++++++++++++ 2 files changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/drivers/media/video/pvrusb2/pvrusb2-devattr.h index e5b9594eb5f6..273c8d4b3853 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.h +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.h @@ -177,6 +177,11 @@ struct pvr2_device_desc { unsigned int flag_has_composite:1; /* Has composite input */ unsigned int flag_has_svideo:1; /* Has s-video input */ unsigned int flag_fx2_16kb:1; /* 16KB FX2 firmware OK here */ + + /* If this driver is considered experimental, i.e. not all aspects + are working correctly and/or it is untested, mark that fact + with this flag. */ + unsigned int flag_is_experimental:1; }; extern struct usb_device_id pvr2_device_table[]; diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index d13232d51823..2c3f845c3e5c 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -2459,6 +2459,19 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, hdw,hdw_desc->description); pvr2_trace(PVR2_TRACE_INFO, "Hardware description: %s", hdw_desc->description); + if (hdw_desc->flag_is_experimental) { + pvr2_trace(PVR2_TRACE_INFO, "**********"); + pvr2_trace(PVR2_TRACE_INFO, + "WARNING: Support for this device (%s) is" + " experimental.", hdw_desc->description); + pvr2_trace(PVR2_TRACE_INFO, + "Important functionality might not be" + " entirely working."); + pvr2_trace(PVR2_TRACE_INFO, + "Please consider contacting the driver author to" + " help with further stabilization of the driver."); + pvr2_trace(PVR2_TRACE_INFO, "**********"); + } if (!hdw) goto fail; init_timer(&hdw->quiescent_timer); -- cgit v1.2.3 From d72baad3f0e59041d68db7524537046e3a4121a2 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 15 May 2010 00:15:38 -0300 Subject: V4L/DVB: pvrusb2: Fix kernel oops at device unregistration pvrusb2: Fix oops caused by touching deleted memory after unregistration. This bug was introduced when we had started using video_device_node_name() - that function was being called potentially after the underlying structure (referenced by that function) had been deleted. The fix rearranges things slightly so that the function is called before destruction takes place. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-v4l2.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 5ffa0d2b0b0d..aaafa0398fd5 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -883,6 +883,17 @@ static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip) { struct pvr2_hdw *hdw = dip->v4lp->channel.mc_head->hdw; enum pvr2_config cfg = dip->config; + char msg[80]; + unsigned int mcnt; + + /* Construct the unregistration message *before* we actually + perform the unregistration step. By doing it this way we don't + have to worry about potentially touching deleted resources. */ + mcnt = scnprintf(msg, sizeof(msg) - 1, + "pvrusb2: unregistered device %s [%s]", + video_device_node_name(&dip->devbase), + pvr2_config_get_name(cfg)); + msg[mcnt] = 0; pvr2_hdw_v4l_store_minor_number(hdw,dip->minor_type,-1); @@ -894,9 +905,7 @@ static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip) are gone. */ video_unregister_device(&dip->devbase); - printk(KERN_INFO "pvrusb2: unregistered device %s [%s]\n", - video_device_node_name(&dip->devbase), - pvr2_config_get_name(cfg)); + printk(KERN_INFO "%s\n", msg); } -- cgit v1.2.3 From 28c4a5e6d32410f7c0b8fa9cc52eac424229f10a Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 15 May 2010 00:23:46 -0300 Subject: V4L/DVB: pvrusb2: Fix USB parent device reference count pvrusb2: Correctly reference count pointer to parent USB device when linked from sysfs interface. This is technically a pretty nasty problem, however as far as I know nobody had been getting burned by it (yet). Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-sysfs.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index 71f50565f637..bf478510a3b1 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c @@ -511,6 +511,7 @@ static void pvr2_sysfs_release(struct device *class_dev) static void class_dev_destroy(struct pvr2_sysfs *sfp) { + struct device *dev; if (!sfp->class_dev) return; #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC pvr2_sysfs_tear_down_debugifc(sfp); @@ -542,6 +543,9 @@ static void class_dev_destroy(struct pvr2_sysfs *sfp) } pvr2_sysfs_trace("Destroying class_dev id=%p",sfp->class_dev); dev_set_drvdata(sfp->class_dev, NULL); + dev = sfp->class_dev->parent; + sfp->class_dev->parent = NULL; + put_device(dev); device_unregister(sfp->class_dev); sfp->class_dev = NULL; } @@ -631,10 +635,11 @@ static void class_dev_create(struct pvr2_sysfs *sfp, pvr2_sysfs_trace("Creating class_dev id=%p",class_dev); class_dev->class = &class_ptr->class; + dev_set_name(class_dev, "%s", pvr2_hdw_get_device_identifier(sfp->channel.hdw)); - class_dev->parent = &usb_dev->dev; + class_dev->parent = get_device(&usb_dev->dev); sfp->class_dev = class_dev; dev_set_drvdata(class_dev, sfp); @@ -775,7 +780,8 @@ struct pvr2_sysfs_class *pvr2_sysfs_class_create(void) struct pvr2_sysfs_class *clp; clp = kzalloc(sizeof(*clp),GFP_KERNEL); if (!clp) return clp; - pvr2_sysfs_trace("Creating pvr2_sysfs_class id=%p",clp); + pvr2_sysfs_trace("Creating and registering pvr2_sysfs_class id=%p", + clp); clp->class.name = "pvrusb2"; clp->class.class_release = pvr2_sysfs_class_release; clp->class.dev_release = pvr2_sysfs_release; @@ -791,6 +797,7 @@ struct pvr2_sysfs_class *pvr2_sysfs_class_create(void) void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *clp) { + pvr2_sysfs_trace("Unregistering pvr2_sysfs_class id=%p", clp); class_unregister(&clp->class); } -- cgit v1.2.3 From 7a6ac34848226e315e0d70333bb4ab83190d9f1d Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 15 May 2010 00:28:44 -0300 Subject: V4L/DVB: pvrusb2: Fix minor internal array allocation pvrusb2: Need one extra attribute slot allocated so that worst case still has a trailing null pointer. This wasn't causing visible symptoms; it was found through inspection while investigating other issues. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index bf478510a3b1..3d7e5aab547f 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c @@ -74,7 +74,7 @@ struct pvr2_sysfs_ctl_item { int ctl_id; struct pvr2_sysfs *chptr; struct pvr2_sysfs_ctl_item *item_next; - struct attribute *attr_gen[7]; + struct attribute *attr_gen[8]; struct attribute_group grp; int created_ok; char name[80]; -- cgit v1.2.3 From e3a5ee73e7223cda78f2770572c5ad01928496d6 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 15 May 2010 00:30:29 -0300 Subject: V4L/DVB: pvrusb2: Fix kernel oops on device tear-down pvrusb2: Delete sysfs class device as the _very_ last step, after we're sure that all driver contexts have gone away first. This is important because it appears that there isn't any protection from a struct device instance reference a deleted struct class instance. The assumption in the kernel code appears to be that the class instance is assumed to be around for the life of the device. So we can't let the class instance go away until all referencing device instances are gone; this is ensured by delaying removal of the class instance until after the driver contexts have all gone away. This bug has been present for a very long time but it didn't apparently become malignant until recently (probably because of other changes in the kernel). Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c index eeacd0f67855..2254194aad57 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-main.c +++ b/drivers/media/video/pvrusb2/pvrusb2-main.c @@ -153,12 +153,12 @@ static void __exit pvr_exit(void) usb_deregister(&pvr_driver); + pvr2_context_global_done(); + #ifdef CONFIG_VIDEO_PVRUSB2_SYSFS pvr2_sysfs_class_destroy(class_ptr); #endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */ - pvr2_context_global_done(); - pvr2_trace(PVR2_TRACE_INIT,"pvr_exit complete"); } -- cgit v1.2.3 From 040000ae7d27d9229959f4a4e9d67cf6c93e8ef8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Fri, 7 May 2010 15:27:44 -0300 Subject: V4L/DVB: gspca - sonixb: Have 0c45:602e handled by sonixb instead of sn9c102 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change fixes the Debian Bug #579332 http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=579332 Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixb.c | 2 -- drivers/media/video/sn9c102/sn9c102_devtable.h | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index 785eeb4c2014..95354a339e3d 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c @@ -1453,9 +1453,7 @@ static const struct usb_device_id device_table[] __devinitconst = { {USB_DEVICE(0x0c45, 0x6029), SB(PAS106, 102)}, {USB_DEVICE(0x0c45, 0x602c), SB(OV7630, 102)}, {USB_DEVICE(0x0c45, 0x602d), SB(HV7131R, 102)}, -#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE {USB_DEVICE(0x0c45, 0x602e), SB(OV7630, 102)}, -#endif {USB_DEVICE(0x0c45, 0x608f), SB(OV7630, 103)}, #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE {USB_DEVICE(0x0c45, 0x60af), SB(PAS202, 103)}, diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h index 522ba3f4c285..b6643ca7656a 100644 --- a/drivers/media/video/sn9c102/sn9c102_devtable.h +++ b/drivers/media/video/sn9c102/sn9c102_devtable.h @@ -62,8 +62,8 @@ static const struct usb_device_id sn9c102_id_table[] = { #if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE { SN9C102_USB_DEVICE(0x0c45, 0x602c, BRIDGE_SN9C102), }, /* { SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), }, HV7131R */ -#endif { SN9C102_USB_DEVICE(0x0c45, 0x602e, BRIDGE_SN9C102), }, +#endif { SN9C102_USB_DEVICE(0x0c45, 0x6030, BRIDGE_SN9C102), }, /* SN9C103 */ { SN9C102_USB_DEVICE(0x0c45, 0x6080, BRIDGE_SN9C103), }, -- cgit v1.2.3 From 6804675e3644361b1d509cac5427bab42a0bc6da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Fri, 7 May 2010 15:35:08 -0300 Subject: V4L/DVB: gspca - sonixj: Add information about some potential JPEG webcams MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixj.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index bb923efb75bd..4bb6479dc920 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -3022,16 +3022,18 @@ static const __devinitdata struct usb_device_id device_table[] = { /* {USB_DEVICE(0x0c45, 0x60c2), BS(SN9C105, P1030xC)}, */ /* {USB_DEVICE(0x0c45, 0x60c8), BS(SN9C105, OM6802)}, */ /* {USB_DEVICE(0x0c45, 0x60cc), BS(SN9C105, HV7131GP)}, */ +/* {USB_DEVICE(0x0c45, 0x60ce), BS(SN9C105, SP80708)}, */ {USB_DEVICE(0x0c45, 0x60ec), BS(SN9C105, MO4000)}, /* {USB_DEVICE(0x0c45, 0x60ef), BS(SN9C105, ICM105C)}, */ /* {USB_DEVICE(0x0c45, 0x60fa), BS(SN9C105, OV7648)}, */ +/* {USB_DEVICE(0x0c45, 0x60f2), BS(SN9C105, OV7660)}, */ {USB_DEVICE(0x0c45, 0x60fb), BS(SN9C105, OV7660)}, #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE {USB_DEVICE(0x0c45, 0x60fc), BS(SN9C105, HV7131R)}, {USB_DEVICE(0x0c45, 0x60fe), BS(SN9C105, OV7630)}, #endif {USB_DEVICE(0x0c45, 0x6100), BS(SN9C120, MI0360)}, /*sn9c128*/ -/* {USB_DEVICE(0x0c45, 0x6102), BS(SN9C120, P1030xC)}, */ +/* {USB_DEVICE(0x0c45, 0x6102), BS(SN9C120, PO2030N)}, * / GC0305*/ /* {USB_DEVICE(0x0c45, 0x6108), BS(SN9C120, OM6802)}, */ {USB_DEVICE(0x0c45, 0x610a), BS(SN9C120, OV7648)}, /*sn9c128*/ {USB_DEVICE(0x0c45, 0x610b), BS(SN9C120, OV7660)}, /*sn9c128*/ @@ -3058,6 +3060,7 @@ static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x0c45, 0x613c), BS(SN9C120, HV7131R)}, {USB_DEVICE(0x0c45, 0x613e), BS(SN9C120, OV7630)}, {USB_DEVICE(0x0c45, 0x6142), BS(SN9C120, PO2030N)}, /*sn9c120b*/ + /* or GC0305 / GC0307 */ {USB_DEVICE(0x0c45, 0x6143), BS(SN9C120, SP80708)}, /*sn9c120b*/ {USB_DEVICE(0x0c45, 0x6148), BS(SN9C120, OM6802)}, /*sn9c120b*/ {USB_DEVICE(0x0c45, 0x614a), BS(SN9C120, ADCM1700)}, /*sn9c120b*/ -- cgit v1.2.3 From c4f95d84b8dedf28adda927561f7e09b1d5ea626 Mon Sep 17 00:00:00 2001 From: Warren Bosworth Focke Date: Fri, 7 May 2010 15:40:04 -0300 Subject: V4L/DVB: gspca - sonixj: Add webcam 0c45:60ce MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Warren Bosworth Focke Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index 4bb6479dc920..176c5b3d5e6f 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -3022,7 +3022,7 @@ static const __devinitdata struct usb_device_id device_table[] = { /* {USB_DEVICE(0x0c45, 0x60c2), BS(SN9C105, P1030xC)}, */ /* {USB_DEVICE(0x0c45, 0x60c8), BS(SN9C105, OM6802)}, */ /* {USB_DEVICE(0x0c45, 0x60cc), BS(SN9C105, HV7131GP)}, */ -/* {USB_DEVICE(0x0c45, 0x60ce), BS(SN9C105, SP80708)}, */ + {USB_DEVICE(0x0c45, 0x60ce), BS(SN9C105, SP80708)}, {USB_DEVICE(0x0c45, 0x60ec), BS(SN9C105, MO4000)}, /* {USB_DEVICE(0x0c45, 0x60ef), BS(SN9C105, ICM105C)}, */ /* {USB_DEVICE(0x0c45, 0x60fa), BS(SN9C105, OV7648)}, */ -- cgit v1.2.3 From 9d78f46071b2cbc91eaf533e1ea441af36eed06a Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Sun, 16 May 2010 05:08:49 -0300 Subject: V4L/DVB: ngene: Support new device 'Digital Devices DuoFlex S2 miniPCIe' Add subsystem id DD10/DD20 'Digital Devices DuoFlex S2 miniPCIe'. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ngene/ngene-cards.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/media/dvb/ngene/ngene-cards.c b/drivers/media/dvb/ngene/ngene-cards.c index 692c3e226e83..4692a41ad95b 100644 --- a/drivers/media/dvb/ngene/ngene-cards.c +++ b/drivers/media/dvb/ngene/ngene-cards.c @@ -217,6 +217,19 @@ static struct ngene_info ngene_info_cineS2v5 = { .fw_version = 15, }; +static struct ngene_info ngene_info_duoFlexS2 = { + .type = NGENE_SIDEWINDER, + .name = "Digital Devices DuoFlex S2 miniPCIe", + .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, + .demod_attach = {demod_attach_stv0900, demod_attach_stv0900}, + .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110}, + .fe_config = {&fe_cineS2, &fe_cineS2}, + .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1}, + .lnb = {0x0a, 0x08}, + .tsf = {3, 3}, + .fw_version = 15, +}; + static struct ngene_info ngene_info_m780 = { .type = NGENE_APP, .name = "Aver M780 ATSC/QAM-B", @@ -256,6 +269,8 @@ static const struct pci_device_id ngene_id_tbl[] __devinitdata = { NGENE_ID(0x18c3, 0xdb01, ngene_info_satixS2), NGENE_ID(0x18c3, 0xdb02, ngene_info_satixS2v2), NGENE_ID(0x18c3, 0xdd00, ngene_info_cineS2v5), + NGENE_ID(0x18c3, 0xdd10, ngene_info_duoFlexS2), + NGENE_ID(0x18c3, 0xdd20, ngene_info_duoFlexS2), NGENE_ID(0x1461, 0x062e, ngene_info_m780), {0} }; -- cgit v1.2.3 From eb05d155bc9f51ff701c09bc9b5e4b4f5a4b4d9f Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Sun, 16 May 2010 05:17:49 -0300 Subject: V4L/DVB: ngene: Do not call demuxer with interrupts disabled It is neither a good idea nor necessary to call the demuxer with interrupts disabled. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ngene/ngene-core.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c index c8b4dfa0ab5f..46749d6ef1ee 100644 --- a/drivers/media/dvb/ngene/ngene-core.c +++ b/drivers/media/dvb/ngene/ngene-core.c @@ -147,24 +147,24 @@ static void demux_tasklet(unsigned long data) } else { if (chan->HWState == HWSTATE_RUN) { u32 Flags = 0; + IBufferExchange *exch1 = chan->pBufferExchange; + IBufferExchange *exch2 = chan->pBufferExchange2; if (Cur->ngeneBuffer.SR.Flags & 0x01) Flags |= BEF_EVEN_FIELD; if (Cur->ngeneBuffer.SR.Flags & 0x20) Flags |= BEF_OVERFLOW; - if (chan->pBufferExchange) - chan->pBufferExchange(chan, - Cur->Buffer1, - chan-> - Capture1Length, - Cur->ngeneBuffer. - SR.Clock, Flags); - if (chan->pBufferExchange2) - chan->pBufferExchange2(chan, - Cur->Buffer2, - chan-> - Capture2Length, - Cur->ngeneBuffer. - SR.Clock, Flags); + spin_unlock_irq(&chan->state_lock); + if (exch1) + exch1(chan, Cur->Buffer1, + chan->Capture1Length, + Cur->ngeneBuffer.SR.Clock, + Flags); + if (exch2) + exch2(chan, Cur->Buffer2, + chan->Capture2Length, + Cur->ngeneBuffer.SR.Clock, + Flags); + spin_lock_irq(&chan->state_lock); } else if (chan->HWState != HWSTATE_STOP) chan->HWState = HWSTATE_RUN; } -- cgit v1.2.3 From 4387418129895fd9aa2e2f6368ea69e9c4ddd0f2 Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Sun, 16 May 2010 05:29:14 -0300 Subject: V4L/DVB: ngene: Implement support for MSI Add MSI support, may be enabled with firmware version 18. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ngene/ngene-core.c | 33 ++++++++++++++++++++++++++++++++- drivers/media/dvb/ngene/ngene.h | 2 ++ 2 files changed, 34 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c index 46749d6ef1ee..35bed6095b1e 100644 --- a/drivers/media/dvb/ngene/ngene-core.c +++ b/drivers/media/dvb/ngene/ngene-core.c @@ -1299,11 +1299,14 @@ static void ngene_stop(struct ngene *dev) ngwritel(0, NGENE_EVENT); ngwritel(0, NGENE_EVENT_HI); free_irq(dev->pci_dev->irq, dev); + if (dev->msi_enabled) + pci_disable_msi(dev->pci_dev); } static int ngene_start(struct ngene *dev) { int stat; + unsigned long flags; int i; pci_set_master(dev->pci_dev); @@ -1333,6 +1336,28 @@ static int ngene_start(struct ngene *dev) if (stat < 0) goto fail; +#ifdef CONFIG_PCI_MSI + /* enable MSI if kernel and card support it */ + if (dev->card_info->msi_supported) { + ngwritel(0, NGENE_INT_ENABLE); + free_irq(dev->pci_dev->irq, dev); + stat = pci_enable_msi(dev->pci_dev); + if (stat) { + printk(KERN_INFO DEVICE_NAME + ": MSI not available\n"); + flags = IRQF_SHARED; + } else { + flags = 0; + dev->msi_enabled = true; + } + stat = request_irq(dev->pci_dev->irq, irq_handler, + flags, "nGene", dev); + if (stat < 0) + goto fail2; + ngwritel(1, NGENE_INT_ENABLE); + } +#endif + stat = ngene_i2c_init(dev, 0); if (stat < 0) goto fail; @@ -1358,10 +1383,16 @@ static int ngene_start(struct ngene *dev) bconf = BUFFER_CONFIG_3333; stat = ngene_command_config_buf(dev, bconf); } - return stat; + if (!stat) + return stat; + + /* otherwise error: fall through */ fail: ngwritel(0, NGENE_INT_ENABLE); free_irq(dev->pci_dev->irq, dev); +fail2: + if (dev->msi_enabled) + pci_disable_msi(dev->pci_dev); return stat; } diff --git a/drivers/media/dvb/ngene/ngene.h b/drivers/media/dvb/ngene/ngene.h index 676fcbb79026..b951d59e3617 100644 --- a/drivers/media/dvb/ngene/ngene.h +++ b/drivers/media/dvb/ngene/ngene.h @@ -725,6 +725,7 @@ struct ngene { u32 device_version; u32 fw_interface_version; u32 icounts; + bool msi_enabled; u8 *CmdDoneByte; int BootFirmware; @@ -797,6 +798,7 @@ struct ngene_info { #define NGENE_VBOX_V2 7 int fw_version; + bool msi_supported; char *name; int io_type[MAX_STREAM]; -- cgit v1.2.3 From 5a2a1848a7d744a437f96b79a655c13b8090e74d Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Sun, 16 May 2010 06:07:07 -0300 Subject: V4L/DVB: ngene: Make command timeout workaround configurable Make command timeout workaround configurable, activate it for firmware version <= 17. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ngene/ngene-core.c | 9 ++++----- drivers/media/dvb/ngene/ngene-dvb.c | 14 +++----------- drivers/media/dvb/ngene/ngene.h | 1 + 3 files changed, 8 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c index 35bed6095b1e..2bdcf59829d1 100644 --- a/drivers/media/dvb/ngene/ngene-core.c +++ b/drivers/media/dvb/ngene/ngene-core.c @@ -53,8 +53,6 @@ MODULE_PARM_DESC(debug, "Print debugging information."); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -#define COMMAND_TIMEOUT_WORKAROUND - #define dprintk if (debug) printk #define ngwriteb(dat, adr) writeb((dat), (char *)(dev->iomem + (adr))) @@ -1252,14 +1250,17 @@ static int ngene_load_firm(struct ngene *dev) version = 15; size = 23466; fw_name = "ngene_15.fw"; + dev->cmd_timeout_workaround = true; break; case 16: size = 23498; fw_name = "ngene_16.fw"; + dev->cmd_timeout_workaround = true; break; case 17: size = 24446; fw_name = "ngene_17.fw"; + dev->cmd_timeout_workaround = true; break; } @@ -1410,10 +1411,8 @@ static void release_channel(struct ngene_channel *chan) struct ngene_info *ni = dev->card_info; int io = ni->io_type[chan->number]; -#ifdef COMMAND_TIMEOUT_WORKAROUND - if (chan->running) + if (chan->dev->cmd_timeout_workaround && chan->running) set_transfer(chan, 0); -#endif tasklet_kill(&chan->demux_tasklet); diff --git a/drivers/media/dvb/ngene/ngene-dvb.c b/drivers/media/dvb/ngene/ngene-dvb.c index 96013eb353cd..61a932c1cfff 100644 --- a/drivers/media/dvb/ngene/ngene-dvb.c +++ b/drivers/media/dvb/ngene/ngene-dvb.c @@ -44,8 +44,6 @@ #include "ngene.h" -#define COMMAND_TIMEOUT_WORKAROUND - /****************************************************************************/ /* COMMAND API interface ****************************************************/ @@ -69,9 +67,7 @@ void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) struct ngene_channel *chan = priv; -#ifdef COMMAND_TIMEOUT_WORKAROUND if (chan->users > 0) -#endif dvb_dmx_swfilter(&chan->demux, buf, len); return NULL; } @@ -106,11 +102,8 @@ int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed) struct ngene_channel *chan = dvbdmx->priv; if (chan->users == 0) { -#ifdef COMMAND_TIMEOUT_WORKAROUND - if (!chan->running) -#endif + if (!chan->dev->cmd_timeout_workaround || !chan->running) set_transfer(chan, 1); - /* msleep(10); */ } return ++chan->users; @@ -124,9 +117,8 @@ int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed) if (--chan->users) return chan->users; -#ifndef COMMAND_TIMEOUT_WORKAROUND - set_transfer(chan, 0); -#endif + if (!chan->dev->cmd_timeout_workaround) + set_transfer(chan, 0); return 0; } diff --git a/drivers/media/dvb/ngene/ngene.h b/drivers/media/dvb/ngene/ngene.h index b951d59e3617..8fb4200f83f8 100644 --- a/drivers/media/dvb/ngene/ngene.h +++ b/drivers/media/dvb/ngene/ngene.h @@ -726,6 +726,7 @@ struct ngene { u32 fw_interface_version; u32 icounts; bool msi_enabled; + bool cmd_timeout_workaround; u8 *CmdDoneByte; int BootFirmware; -- cgit v1.2.3 From 478b3a42bdcd8d1cb57c91cabdc8b6164c639e42 Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Wed, 19 May 2010 04:15:44 -0300 Subject: V4L/DVB: ngene: MSI cleanup MSI cleanup. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ngene/ngene-core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c index 2bdcf59829d1..dcf1f45ff07c 100644 --- a/drivers/media/dvb/ngene/ngene-core.c +++ b/drivers/media/dvb/ngene/ngene-core.c @@ -1300,8 +1300,10 @@ static void ngene_stop(struct ngene *dev) ngwritel(0, NGENE_EVENT); ngwritel(0, NGENE_EVENT_HI); free_irq(dev->pci_dev->irq, dev); +#ifdef CONFIG_PCI_MSI if (dev->msi_enabled) pci_disable_msi(dev->pci_dev); +#endif } static int ngene_start(struct ngene *dev) @@ -1339,7 +1341,7 @@ static int ngene_start(struct ngene *dev) #ifdef CONFIG_PCI_MSI /* enable MSI if kernel and card support it */ - if (dev->card_info->msi_supported) { + if (pci_msi_enabled() && dev->card_info->msi_supported) { ngwritel(0, NGENE_INT_ENABLE); free_irq(dev->pci_dev->irq, dev); stat = pci_enable_msi(dev->pci_dev); @@ -1391,9 +1393,11 @@ static int ngene_start(struct ngene *dev) fail: ngwritel(0, NGENE_INT_ENABLE); free_irq(dev->pci_dev->irq, dev); +#ifdef CONFIG_PCI_MSI fail2: if (dev->msi_enabled) pci_disable_msi(dev->pci_dev); +#endif return stat; } -- cgit v1.2.3 From 51ff9ef13366b3752a8ab6229c466fd1bd671d3a Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Wed, 19 May 2010 04:17:18 -0300 Subject: V4L/DVB: ngene: Remove debug message Remove debug message. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ngene/ngene-core.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c index dcf1f45ff07c..4caeb163a666 100644 --- a/drivers/media/dvb/ngene/ngene-core.c +++ b/drivers/media/dvb/ngene/ngene-core.c @@ -570,11 +570,7 @@ static int ngene_command_stream_control(struct ngene *dev, u8 stream, u16 BsSPI = ((stream & 1) ? 0x9800 : 0x9700); u16 BsSDO = 0x9B00; - /* down(&dev->stream_mutex); */ - while (down_trylock(&dev->stream_mutex)) { - printk(KERN_INFO DEVICE_NAME ": SC locked\n"); - msleep(1); - } + down(&dev->stream_mutex); memset(&com, 0, sizeof(com)); com.cmd.hdr.Opcode = CMD_CONTROL; com.cmd.hdr.Length = sizeof(struct FW_STREAM_CONTROL) - 2; -- cgit v1.2.3 From c463d93f22254f46168b49ad1149d1ec1e904711 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 9 May 2010 09:47:23 -0300 Subject: V4L/DVB: saa7115: add s_mbus_fmt op Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7115.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index 53b6fcde3800..d4cc20859975 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -1136,6 +1136,15 @@ static int saa711x_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f return 0; } +static int saa711x_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) +{ + if (fmt->code != V4L2_MBUS_FMT_FIXED) + return -EINVAL; + fmt->field = V4L2_FIELD_INTERLACED; + fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; + return saa711x_set_size(sd, fmt->width, fmt->height); +} + static int saa711x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) { if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) @@ -1558,6 +1567,7 @@ static const struct v4l2_subdev_video_ops saa711x_video_ops = { .s_crystal_freq = saa711x_s_crystal_freq, .g_fmt = saa711x_g_fmt, .s_fmt = saa711x_s_fmt, + .s_mbus_fmt = saa711x_s_mbus_fmt, .s_stream = saa711x_s_stream, .querystd = saa711x_querystd, .g_input_status = saa711x_g_input_status, -- cgit v1.2.3 From 96fd004fe40b8e3beff2a6e27ae0411a4d315f1e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 9 May 2010 09:48:50 -0300 Subject: V4L/DVB: cx25840: add support for s_mbus_fmt Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-core.c | 96 +++++++++++++++++------------- 1 file changed, 55 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 8b6fb3544376..f0cbc9d066bd 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -1025,59 +1025,72 @@ static int cx25840_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) return 0; } -static int cx25840_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) +static int cx25840_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) { struct cx25840_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); - struct v4l2_pix_format *pix; int HSC, VSC, Vsrc, Hsrc, filter, Vlines; int is_50Hz = !(state->std & V4L2_STD_525_60); - switch (fmt->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - pix = &(fmt->fmt.pix); + if (fmt->code != V4L2_MBUS_FMT_FIXED) + return -EINVAL; - Vsrc = (cx25840_read(client, 0x476) & 0x3f) << 4; - Vsrc |= (cx25840_read(client, 0x475) & 0xf0) >> 4; + fmt->field = V4L2_FIELD_INTERLACED; + fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; - Hsrc = (cx25840_read(client, 0x472) & 0x3f) << 4; - Hsrc |= (cx25840_read(client, 0x471) & 0xf0) >> 4; + Vsrc = (cx25840_read(client, 0x476) & 0x3f) << 4; + Vsrc |= (cx25840_read(client, 0x475) & 0xf0) >> 4; - Vlines = pix->height + (is_50Hz ? 4 : 7); + Hsrc = (cx25840_read(client, 0x472) & 0x3f) << 4; + Hsrc |= (cx25840_read(client, 0x471) & 0xf0) >> 4; - if ((pix->width * 16 < Hsrc) || (Hsrc < pix->width) || - (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) { - v4l_err(client, "%dx%d is not a valid size!\n", - pix->width, pix->height); - return -ERANGE; - } + Vlines = fmt->height + (is_50Hz ? 4 : 7); - HSC = (Hsrc * (1 << 20)) / pix->width - (1 << 20); - VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9)); - VSC &= 0x1fff; + if ((fmt->width * 16 < Hsrc) || (Hsrc < fmt->width) || + (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) { + v4l_err(client, "%dx%d is not a valid size!\n", + fmt->width, fmt->height); + return -ERANGE; + } - if (pix->width >= 385) - filter = 0; - else if (pix->width > 192) - filter = 1; - else if (pix->width > 96) - filter = 2; - else - filter = 3; - - v4l_dbg(1, cx25840_debug, client, "decoder set size %dx%d -> scale %ux%u\n", - pix->width, pix->height, HSC, VSC); - - /* HSCALE=HSC */ - cx25840_write(client, 0x418, HSC & 0xff); - cx25840_write(client, 0x419, (HSC >> 8) & 0xff); - cx25840_write(client, 0x41a, HSC >> 16); - /* VSCALE=VSC */ - cx25840_write(client, 0x41c, VSC & 0xff); - cx25840_write(client, 0x41d, VSC >> 8); - /* VS_INTRLACE=1 VFILT=filter */ - cx25840_write(client, 0x41e, 0x8 | filter); - break; + HSC = (Hsrc * (1 << 20)) / fmt->width - (1 << 20); + VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9)); + VSC &= 0x1fff; + + if (fmt->width >= 385) + filter = 0; + else if (fmt->width > 192) + filter = 1; + else if (fmt->width > 96) + filter = 2; + else + filter = 3; + + v4l_dbg(1, cx25840_debug, client, "decoder set size %dx%d -> scale %ux%u\n", + fmt->width, fmt->height, HSC, VSC); + + /* HSCALE=HSC */ + cx25840_write(client, 0x418, HSC & 0xff); + cx25840_write(client, 0x419, (HSC >> 8) & 0xff); + cx25840_write(client, 0x41a, HSC >> 16); + /* VSCALE=VSC */ + cx25840_write(client, 0x41c, VSC & 0xff); + cx25840_write(client, 0x41d, VSC >> 8); + /* VS_INTRLACE=1 VFILT=filter */ + cx25840_write(client, 0x41e, 0x8 | filter); + return 0; +} + +static int cx25840_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) +{ + struct v4l2_mbus_framefmt mbus_fmt; + + switch (fmt->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + mbus_fmt.width = fmt->fmt.pix.width; + mbus_fmt.height = fmt->fmt.pix.height; + mbus_fmt.code = V4L2_MBUS_FMT_FIXED; + return cx25840_s_mbus_fmt(sd, &mbus_fmt); default: return -EINVAL; @@ -1629,6 +1642,7 @@ static const struct v4l2_subdev_video_ops cx25840_video_ops = { .s_routing = cx25840_s_video_routing, .g_fmt = cx25840_g_fmt, .s_fmt = cx25840_s_fmt, + .s_mbus_fmt = cx25840_s_mbus_fmt, .s_stream = cx25840_s_stream, }; -- cgit v1.2.3 From 6c69db9de7a8934bdeb690663fab6fe046203ac4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 9 May 2010 09:50:34 -0300 Subject: V4L/DVB: saa717x: add support for s_mbus_fmt Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa717x.c | 47 ++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/saa717x.c b/drivers/media/video/saa717x.c index d521c648e157..422a3e222afa 100644 --- a/drivers/media/video/saa717x.c +++ b/drivers/media/video/saa717x.c @@ -1199,28 +1199,32 @@ static int saa717x_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register * } #endif -static int saa717x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) +static int saa717x_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) { - struct v4l2_pix_format *pix; int prescale, h_scale, v_scale; - pix = &fmt->fmt.pix; v4l2_dbg(1, debug, sd, "decoder set size\n"); + if (fmt->code != V4L2_MBUS_FMT_FIXED) + return -EINVAL; + /* FIXME need better bounds checking here */ - if (pix->width < 1 || pix->width > 1440) + if (fmt->width < 1 || fmt->width > 1440) return -EINVAL; - if (pix->height < 1 || pix->height > 960) + if (fmt->height < 1 || fmt->height > 960) return -EINVAL; + fmt->field = V4L2_FIELD_INTERLACED; + fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; + /* scaling setting */ /* NTSC and interlace only */ - prescale = SAA717X_NTSC_WIDTH / pix->width; + prescale = SAA717X_NTSC_WIDTH / fmt->width; if (prescale == 0) prescale = 1; - h_scale = 1024 * SAA717X_NTSC_WIDTH / prescale / pix->width; + h_scale = 1024 * SAA717X_NTSC_WIDTH / prescale / fmt->width; /* interlace */ - v_scale = 512 * 2 * SAA717X_NTSC_HEIGHT / pix->height; + v_scale = 512 * 2 * SAA717X_NTSC_HEIGHT / fmt->height; /* Horizontal prescaling etc */ set_h_prescale(sd, 0, prescale); @@ -1241,22 +1245,32 @@ static int saa717x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) /* set video output size */ /* video number of pixels at output */ /* TASK A */ - saa717x_write(sd, 0x5C, (u8)(pix->width & 0xFF)); - saa717x_write(sd, 0x5D, (u8)((pix->width >> 8) & 0xFF)); + saa717x_write(sd, 0x5C, (u8)(fmt->width & 0xFF)); + saa717x_write(sd, 0x5D, (u8)((fmt->width >> 8) & 0xFF)); /* TASK B */ - saa717x_write(sd, 0x9C, (u8)(pix->width & 0xFF)); - saa717x_write(sd, 0x9D, (u8)((pix->width >> 8) & 0xFF)); + saa717x_write(sd, 0x9C, (u8)(fmt->width & 0xFF)); + saa717x_write(sd, 0x9D, (u8)((fmt->width >> 8) & 0xFF)); /* video number of lines at output */ /* TASK A */ - saa717x_write(sd, 0x5E, (u8)(pix->height & 0xFF)); - saa717x_write(sd, 0x5F, (u8)((pix->height >> 8) & 0xFF)); + saa717x_write(sd, 0x5E, (u8)(fmt->height & 0xFF)); + saa717x_write(sd, 0x5F, (u8)((fmt->height >> 8) & 0xFF)); /* TASK B */ - saa717x_write(sd, 0x9E, (u8)(pix->height & 0xFF)); - saa717x_write(sd, 0x9F, (u8)((pix->height >> 8) & 0xFF)); + saa717x_write(sd, 0x9E, (u8)(fmt->height & 0xFF)); + saa717x_write(sd, 0x9F, (u8)((fmt->height >> 8) & 0xFF)); return 0; } +static int saa717x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) +{ + struct v4l2_mbus_framefmt mbus_fmt; + + mbus_fmt.width = fmt->fmt.pix.width; + mbus_fmt.height = fmt->fmt.pix.height; + mbus_fmt.code = V4L2_MBUS_FMT_FIXED; + return saa717x_s_mbus_fmt(sd, &mbus_fmt); +} + static int saa717x_s_radio(struct v4l2_subdev *sd) { struct saa717x_state *decoder = to_state(sd); @@ -1404,6 +1418,7 @@ static const struct v4l2_subdev_tuner_ops saa717x_tuner_ops = { static const struct v4l2_subdev_video_ops saa717x_video_ops = { .s_routing = saa717x_s_video_routing, .s_fmt = saa717x_s_fmt, + .s_mbus_fmt = saa717x_s_mbus_fmt, .s_stream = saa717x_s_stream, }; -- cgit v1.2.3 From 475977ac3db72c008f5aaa5f19bd991b72f26e42 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 8 May 2010 16:28:51 -0300 Subject: V4L/DVB: ivtv: convert to use s_mbus_fmt Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-controls.c | 10 +++++----- drivers/media/video/ivtv/ivtv-ioctl.c | 6 +++++- 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c index b59475bfc243..b588e30cbcf0 100644 --- a/drivers/media/video/ivtv/ivtv-controls.c +++ b/drivers/media/video/ivtv/ivtv-controls.c @@ -267,13 +267,13 @@ int ivtv_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) if (p.video_encoding != itv->params.video_encoding) { int is_mpeg1 = p.video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; - struct v4l2_format fmt; + struct v4l2_mbus_framefmt fmt; /* fix videodecoder resolution */ - fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - fmt.fmt.pix.width = itv->params.width / (is_mpeg1 ? 2 : 1); - fmt.fmt.pix.height = itv->params.height; - v4l2_subdev_call(itv->sd_video, video, s_fmt, &fmt); + fmt.width = itv->params.width / (is_mpeg1 ? 2 : 1); + fmt.height = itv->params.height; + fmt.code = V4L2_MBUS_FMT_FIXED; + v4l2_subdev_call(itv->sd_video, video, s_mbus_fmt, &fmt); } err = cx2341x_update(itv, ivtv_api_func, &itv->params, &p); if (!err && itv->params.stream_vbi_fmt != p.stream_vbi_fmt) diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index fa9f0d958f96..11ac2fa33ef7 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -569,6 +569,7 @@ static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f struct ivtv_open_id *id = fh; struct ivtv *itv = id->itv; struct cx2341x_mpeg_params *p = &itv->params; + struct v4l2_mbus_framefmt mbus_fmt; int ret = ivtv_try_fmt_vid_cap(file, fh, fmt); int w = fmt->fmt.pix.width; int h = fmt->fmt.pix.height; @@ -586,7 +587,10 @@ static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f p->height = h; if (p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) fmt->fmt.pix.width /= 2; - v4l2_subdev_call(itv->sd_video, video, s_fmt, fmt); + mbus_fmt.width = fmt->fmt.pix.width; + mbus_fmt.height = h; + mbus_fmt.code = V4L2_MBUS_FMT_FIXED; + v4l2_subdev_call(itv->sd_video, video, s_mbus_fmt, &mbus_fmt); return ivtv_g_fmt_vid_cap(file, fh, fmt); } -- cgit v1.2.3 From e17ad1de031f2d5cade70eb0469a53f17d90d7c2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 9 May 2010 09:54:58 -0300 Subject: V4L/DVB: cx18: add s_mbus_fmt support Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx18/cx18-av-core.c | 126 +++++++++++++++++--------------- 1 file changed, 69 insertions(+), 57 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c index 0e5006b14279..39f484621a45 100644 --- a/drivers/media/video/cx18/cx18-av-core.c +++ b/drivers/media/video/cx18/cx18-av-core.c @@ -1028,80 +1028,91 @@ static int cx18_av_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) return cx18_av_g_sliced_fmt(sd, &fmt->fmt.sliced); } -static int cx18_av_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) +static int cx18_av_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) { struct cx18_av_state *state = to_cx18_av_state(sd); struct cx18 *cx = v4l2_get_subdevdata(sd); - - struct v4l2_pix_format *pix; int HSC, VSC, Vsrc, Hsrc, filter, Vlines; int is_50Hz = !(state->std & V4L2_STD_525_60); - switch (fmt->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - pix = &(fmt->fmt.pix); + if (fmt->code != V4L2_MBUS_FMT_FIXED) + return -EINVAL; - Vsrc = (cx18_av_read(cx, 0x476) & 0x3f) << 4; - Vsrc |= (cx18_av_read(cx, 0x475) & 0xf0) >> 4; + fmt->field = V4L2_FIELD_INTERLACED; + fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; - Hsrc = (cx18_av_read(cx, 0x472) & 0x3f) << 4; - Hsrc |= (cx18_av_read(cx, 0x471) & 0xf0) >> 4; + Vsrc = (cx18_av_read(cx, 0x476) & 0x3f) << 4; + Vsrc |= (cx18_av_read(cx, 0x475) & 0xf0) >> 4; - /* - * This adjustment reflects the excess of vactive, set in - * cx18_av_std_setup(), above standard values: - * - * 480 + 1 for 60 Hz systems - * 576 + 3 for 50 Hz systems - */ - Vlines = pix->height + (is_50Hz ? 3 : 1); + Hsrc = (cx18_av_read(cx, 0x472) & 0x3f) << 4; + Hsrc |= (cx18_av_read(cx, 0x471) & 0xf0) >> 4; - /* - * Invalid height and width scaling requests are: - * 1. width less than 1/16 of the source width - * 2. width greater than the source width - * 3. height less than 1/8 of the source height - * 4. height greater than the source height - */ - if ((pix->width * 16 < Hsrc) || (Hsrc < pix->width) || - (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) { - CX18_ERR_DEV(sd, "%dx%d is not a valid size!\n", - pix->width, pix->height); - return -ERANGE; - } + /* + * This adjustment reflects the excess of vactive, set in + * cx18_av_std_setup(), above standard values: + * + * 480 + 1 for 60 Hz systems + * 576 + 3 for 50 Hz systems + */ + Vlines = fmt->height + (is_50Hz ? 3 : 1); - HSC = (Hsrc * (1 << 20)) / pix->width - (1 << 20); - VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9)); - VSC &= 0x1fff; + /* + * Invalid height and width scaling requests are: + * 1. width less than 1/16 of the source width + * 2. width greater than the source width + * 3. height less than 1/8 of the source height + * 4. height greater than the source height + */ + if ((fmt->width * 16 < Hsrc) || (Hsrc < fmt->width) || + (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) { + CX18_ERR_DEV(sd, "%dx%d is not a valid size!\n", + fmt->width, fmt->height); + return -ERANGE; + } - if (pix->width >= 385) - filter = 0; - else if (pix->width > 192) - filter = 1; - else if (pix->width > 96) - filter = 2; - else - filter = 3; + HSC = (Hsrc * (1 << 20)) / fmt->width - (1 << 20); + VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9)); + VSC &= 0x1fff; - CX18_DEBUG_INFO_DEV(sd, - "decoder set size %dx%d -> scale %ux%u\n", - pix->width, pix->height, HSC, VSC); - - /* HSCALE=HSC */ - cx18_av_write(cx, 0x418, HSC & 0xff); - cx18_av_write(cx, 0x419, (HSC >> 8) & 0xff); - cx18_av_write(cx, 0x41a, HSC >> 16); - /* VSCALE=VSC */ - cx18_av_write(cx, 0x41c, VSC & 0xff); - cx18_av_write(cx, 0x41d, VSC >> 8); - /* VS_INTRLACE=1 VFILT=filter */ - cx18_av_write(cx, 0x41e, 0x8 | filter); - break; + if (fmt->width >= 385) + filter = 0; + else if (fmt->width > 192) + filter = 1; + else if (fmt->width > 96) + filter = 2; + else + filter = 3; + + CX18_DEBUG_INFO_DEV(sd, + "decoder set size %dx%d -> scale %ux%u\n", + fmt->width, fmt->height, HSC, VSC); + + /* HSCALE=HSC */ + cx18_av_write(cx, 0x418, HSC & 0xff); + cx18_av_write(cx, 0x419, (HSC >> 8) & 0xff); + cx18_av_write(cx, 0x41a, HSC >> 16); + /* VSCALE=VSC */ + cx18_av_write(cx, 0x41c, VSC & 0xff); + cx18_av_write(cx, 0x41d, VSC >> 8); + /* VS_INTRLACE=1 VFILT=filter */ + cx18_av_write(cx, 0x41e, 0x8 | filter); + return 0; +} + +static int cx18_av_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) +{ + struct v4l2_mbus_framefmt mbus_fmt; + + switch (fmt->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + mbus_fmt.width = fmt->fmt.pix.width; + mbus_fmt.height = fmt->fmt.pix.height; + mbus_fmt.code = V4L2_MBUS_FMT_FIXED; + return cx18_av_s_mbus_fmt(sd, &mbus_fmt); default: return -EINVAL; } - return 0; } static int cx18_av_s_stream(struct v4l2_subdev *sd, int enable) @@ -1400,6 +1411,7 @@ static const struct v4l2_subdev_video_ops cx18_av_video_ops = { .s_stream = cx18_av_s_stream, .g_fmt = cx18_av_g_fmt, .s_fmt = cx18_av_s_fmt, + .s_mbus_fmt = cx18_av_s_mbus_fmt, }; static const struct v4l2_subdev_vbi_ops cx18_av_vbi_ops = { -- cgit v1.2.3 From 9e36eabc8a6fb87d9b97057e0d0f5195c475fbdc Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 8 May 2010 16:37:53 -0300 Subject: V4L/DVB: cx18: remove old g/s_fmt from the cx18_av subdev cx18 has now switched over completely to the new mediabus subdev ops. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx18/cx18-av-core.c | 25 ------------------------- drivers/media/video/cx18/cx18-controls.c | 11 +++++------ drivers/media/video/cx18/cx18-ioctl.c | 8 +++++--- 3 files changed, 10 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c index 39f484621a45..54371f6d6b5f 100644 --- a/drivers/media/video/cx18/cx18-av-core.c +++ b/drivers/media/video/cx18/cx18-av-core.c @@ -1021,13 +1021,6 @@ static int cx18_av_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) return -EINVAL; } -static int cx18_av_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) -{ - if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) - return -EINVAL; - return cx18_av_g_sliced_fmt(sd, &fmt->fmt.sliced); -} - static int cx18_av_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) { struct cx18_av_state *state = to_cx18_av_state(sd); @@ -1099,22 +1092,6 @@ static int cx18_av_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt return 0; } -static int cx18_av_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) -{ - struct v4l2_mbus_framefmt mbus_fmt; - - switch (fmt->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - mbus_fmt.width = fmt->fmt.pix.width; - mbus_fmt.height = fmt->fmt.pix.height; - mbus_fmt.code = V4L2_MBUS_FMT_FIXED; - return cx18_av_s_mbus_fmt(sd, &mbus_fmt); - - default: - return -EINVAL; - } -} - static int cx18_av_s_stream(struct v4l2_subdev *sd, int enable) { struct cx18 *cx = v4l2_get_subdevdata(sd); @@ -1409,8 +1386,6 @@ static const struct v4l2_subdev_audio_ops cx18_av_audio_ops = { static const struct v4l2_subdev_video_ops cx18_av_video_ops = { .s_routing = cx18_av_s_video_routing, .s_stream = cx18_av_s_stream, - .g_fmt = cx18_av_g_fmt, - .s_fmt = cx18_av_s_fmt, .s_mbus_fmt = cx18_av_s_mbus_fmt, }; diff --git a/drivers/media/video/cx18/cx18-controls.c b/drivers/media/video/cx18/cx18-controls.c index 4b4b46544d5a..67043c7b452b 100644 --- a/drivers/media/video/cx18/cx18-controls.c +++ b/drivers/media/video/cx18/cx18-controls.c @@ -297,14 +297,13 @@ int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) if (p.video_encoding != cx->params.video_encoding) { int is_mpeg1 = p.video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; - struct v4l2_format fmt; + struct v4l2_mbus_framefmt fmt; /* fix videodecoder resolution */ - fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - fmt.fmt.pix.width = cx->params.width - / (is_mpeg1 ? 2 : 1); - fmt.fmt.pix.height = cx->params.height; - v4l2_subdev_call(cx->sd_av, video, s_fmt, &fmt); + fmt.width = cx->params.width / (is_mpeg1 ? 2 : 1); + fmt.height = cx->params.height; + fmt.code = V4L2_MBUS_FMT_FIXED; + v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &fmt); } priv.cx = cx; priv.s = &cx->streams[id->type]; diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c index 2530fc54daaf..b5b221c8a725 100644 --- a/drivers/media/video/cx18/cx18-ioctl.c +++ b/drivers/media/video/cx18/cx18-ioctl.c @@ -274,6 +274,7 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh, { struct cx18_open_id *id = fh; struct cx18 *cx = id->cx; + struct v4l2_mbus_framefmt mbus_fmt; int ret; int w, h; @@ -293,9 +294,10 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh, if (atomic_read(&cx->ana_capturing) > 0) return -EBUSY; - cx->params.width = w; - cx->params.height = h; - v4l2_subdev_call(cx->sd_av, video, s_fmt, fmt); + mbus_fmt.width = cx->params.width = w; + mbus_fmt.height = cx->params.height = h; + mbus_fmt.code = V4L2_MBUS_FMT_FIXED; + v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &mbus_fmt); return cx18_g_fmt_vid_cap(file, fh, fmt); } -- cgit v1.2.3 From 60298c99f792bb2fe12137360d448c72234b2d0b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 8 May 2010 16:39:01 -0300 Subject: V4L/DVB: saa7127: remove obsolete g_fmt support Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7127.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c index 87986ad62f86..79fffcf39ba8 100644 --- a/drivers/media/video/saa7127.c +++ b/drivers/media/video/saa7127.c @@ -645,13 +645,6 @@ static int saa7127_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f return 0; } -static int saa7127_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) -{ - if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) - return -EINVAL; - return saa7127_g_sliced_fmt(sd, &fmt->fmt.sliced); -} - static int saa7127_s_vbi_data(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data) { switch (data->id) { @@ -731,7 +724,6 @@ static const struct v4l2_subdev_core_ops saa7127_core_ops = { }; static const struct v4l2_subdev_video_ops saa7127_video_ops = { - .g_fmt = saa7127_g_fmt, .s_std_output = saa7127_s_std_output, .s_routing = saa7127_s_routing, .s_stream = saa7127_s_stream, -- cgit v1.2.3 From 66e9df07d362b63a594e8663260e0430ba4a17bf Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 8 May 2010 16:40:23 -0300 Subject: V4L/DVB: saa717x: remove obsolete s_fmt op Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa717x.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/saa717x.c b/drivers/media/video/saa717x.c index 422a3e222afa..78d69950c00a 100644 --- a/drivers/media/video/saa717x.c +++ b/drivers/media/video/saa717x.c @@ -1261,16 +1261,6 @@ static int saa717x_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt return 0; } -static int saa717x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) -{ - struct v4l2_mbus_framefmt mbus_fmt; - - mbus_fmt.width = fmt->fmt.pix.width; - mbus_fmt.height = fmt->fmt.pix.height; - mbus_fmt.code = V4L2_MBUS_FMT_FIXED; - return saa717x_s_mbus_fmt(sd, &mbus_fmt); -} - static int saa717x_s_radio(struct v4l2_subdev *sd) { struct saa717x_state *decoder = to_state(sd); @@ -1417,7 +1407,6 @@ static const struct v4l2_subdev_tuner_ops saa717x_tuner_ops = { static const struct v4l2_subdev_video_ops saa717x_video_ops = { .s_routing = saa717x_s_video_routing, - .s_fmt = saa717x_s_fmt, .s_mbus_fmt = saa717x_s_mbus_fmt, .s_stream = saa717x_s_stream, }; -- cgit v1.2.3 From 51623ef9aedd8b786a12a4475201827ee85d285c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 9 May 2010 09:39:58 -0300 Subject: V4L/DVB: saa6752hs: add g/s_mbus_fmt support Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa6752hs.c | 64 +++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c index 1eabff6b2456..852040b6b5a6 100644 --- a/drivers/media/video/saa7134/saa6752hs.c +++ b/drivers/media/video/saa7134/saa6752hs.c @@ -846,24 +846,38 @@ static int saa6752hs_g_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_control return 0; } -static int saa6752hs_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +static int saa6752hs_g_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f) { struct saa6752hs_state *h = to_state(sd); if (h->video_format == SAA6752HS_VF_UNKNOWN) h->video_format = SAA6752HS_VF_D1; - f->fmt.pix.width = - v4l2_format_table[h->video_format].fmt.pix.width; - f->fmt.pix.height = - v4l2_format_table[h->video_format].fmt.pix.height; + f->width = v4l2_format_table[h->video_format].fmt.pix.width; + f->height = v4l2_format_table[h->video_format].fmt.pix.height; + f->code = V4L2_MBUS_FMT_FIXED; + f->field = V4L2_FIELD_INTERLACED; + f->colorspace = V4L2_COLORSPACE_SMPTE170M; return 0; } -static int saa6752hs_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +static int saa6752hs_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + struct v4l2_mbus_framefmt mbus_fmt; + int err = saa6752hs_g_mbus_fmt(sd, &mbus_fmt); + + f->fmt.pix.width = mbus_fmt.width; + f->fmt.pix.height = mbus_fmt.height; + return err; +} + +static int saa6752hs_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f) { struct saa6752hs_state *h = to_state(sd); int dist_352, dist_480, dist_720; + if (f->code != V4L2_MBUS_FMT_FIXED) + return -EINVAL; + /* FIXME: translate and round width/height into EMPRESS subsample type: @@ -876,31 +890,43 @@ static int saa6752hs_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) D1 | 720x576 | 720x480 */ - dist_352 = abs(f->fmt.pix.width - 352); - dist_480 = abs(f->fmt.pix.width - 480); - dist_720 = abs(f->fmt.pix.width - 720); + dist_352 = abs(f->width - 352); + dist_480 = abs(f->width - 480); + dist_720 = abs(f->width - 720); if (dist_720 < dist_480) { - f->fmt.pix.width = 720; - f->fmt.pix.height = 576; + f->width = 720; + f->height = 576; h->video_format = SAA6752HS_VF_D1; } else if (dist_480 < dist_352) { - f->fmt.pix.width = 480; - f->fmt.pix.height = 576; + f->width = 480; + f->height = 576; h->video_format = SAA6752HS_VF_2_3_D1; } else { - f->fmt.pix.width = 352; - if (abs(f->fmt.pix.height - 576) < - abs(f->fmt.pix.height - 288)) { - f->fmt.pix.height = 576; + f->width = 352; + if (abs(f->height - 576) < + abs(f->height - 288)) { + f->height = 576; h->video_format = SAA6752HS_VF_1_2_D1; } else { - f->fmt.pix.height = 288; + f->height = 288; h->video_format = SAA6752HS_VF_SIF; } } + f->field = V4L2_FIELD_INTERLACED; + f->colorspace = V4L2_COLORSPACE_SMPTE170M; return 0; } +static int saa6752hs_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + struct v4l2_mbus_framefmt mbus_fmt; + + mbus_fmt.width = f->fmt.pix.width; + mbus_fmt.height = f->fmt.pix.height; + mbus_fmt.code = V4L2_MBUS_FMT_FIXED; + return saa6752hs_s_mbus_fmt(sd, &mbus_fmt); +} + static int saa6752hs_s_std(struct v4l2_subdev *sd, v4l2_std_id std) { struct saa6752hs_state *h = to_state(sd); @@ -934,6 +960,8 @@ static const struct v4l2_subdev_core_ops saa6752hs_core_ops = { static const struct v4l2_subdev_video_ops saa6752hs_video_ops = { .s_fmt = saa6752hs_s_fmt, .g_fmt = saa6752hs_g_fmt, + .s_mbus_fmt = saa6752hs_s_mbus_fmt, + .g_mbus_fmt = saa6752hs_g_mbus_fmt, }; static const struct v4l2_subdev_ops saa6752hs_ops = { -- cgit v1.2.3 From 31bf95fb5725013fd7d95d6d5b1e45f4c88b1f56 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 9 May 2010 09:41:41 -0300 Subject: V4L/DVB: saa7134: convert to use the new mbus API Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa6752hs.c | 22 ---------------------- drivers/media/video/saa7134/saa7134-empress.c | 9 +++++++-- 2 files changed, 7 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c index 852040b6b5a6..40fd31ca7716 100644 --- a/drivers/media/video/saa7134/saa6752hs.c +++ b/drivers/media/video/saa7134/saa6752hs.c @@ -860,16 +860,6 @@ static int saa6752hs_g_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefm return 0; } -static int saa6752hs_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) -{ - struct v4l2_mbus_framefmt mbus_fmt; - int err = saa6752hs_g_mbus_fmt(sd, &mbus_fmt); - - f->fmt.pix.width = mbus_fmt.width; - f->fmt.pix.height = mbus_fmt.height; - return err; -} - static int saa6752hs_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f) { struct saa6752hs_state *h = to_state(sd); @@ -917,16 +907,6 @@ static int saa6752hs_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefm return 0; } -static int saa6752hs_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) -{ - struct v4l2_mbus_framefmt mbus_fmt; - - mbus_fmt.width = f->fmt.pix.width; - mbus_fmt.height = f->fmt.pix.height; - mbus_fmt.code = V4L2_MBUS_FMT_FIXED; - return saa6752hs_s_mbus_fmt(sd, &mbus_fmt); -} - static int saa6752hs_s_std(struct v4l2_subdev *sd, v4l2_std_id std) { struct saa6752hs_state *h = to_state(sd); @@ -958,8 +938,6 @@ static const struct v4l2_subdev_core_ops saa6752hs_core_ops = { }; static const struct v4l2_subdev_video_ops saa6752hs_video_ops = { - .s_fmt = saa6752hs_s_fmt, - .g_fmt = saa6752hs_g_fmt, .s_mbus_fmt = saa6752hs_s_mbus_fmt, .g_mbus_fmt = saa6752hs_g_mbus_fmt, }; diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index ea877a50f52d..e763f9fd0133 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -223,9 +223,11 @@ static int empress_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct saa7134_dev *dev = file->private_data; + struct v4l2_mbus_framefmt mbus_fmt; - saa_call_all(dev, video, g_fmt, f); + saa_call_all(dev, video, g_mbus_fmt, &mbus_fmt); + v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets; @@ -236,8 +238,11 @@ static int empress_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct saa7134_dev *dev = file->private_data; + struct v4l2_mbus_framefmt mbus_fmt; - saa_call_all(dev, video, s_fmt, f); + v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); + saa_call_all(dev, video, s_mbus_fmt, &mbus_fmt); + v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets; -- cgit v1.2.3 From fa190ee91fcc3800f2c5d14810dc1b48a4b5d4e5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 8 May 2010 17:16:18 -0300 Subject: V4L/DVB: pvrusb2: convert to s_mbus_fmt Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 2c3f845c3e5c..70ea578d6266 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -3069,14 +3069,14 @@ static void pvr2_subdev_update(struct pvr2_hdw *hdw) } if (hdw->res_hor_dirty || hdw->res_ver_dirty || hdw->force_dirty) { - struct v4l2_format fmt; + struct v4l2_mbus_framefmt fmt; memset(&fmt, 0, sizeof(fmt)); - fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - fmt.fmt.pix.width = hdw->res_hor_val; - fmt.fmt.pix.height = hdw->res_ver_val; + fmt.width = hdw->res_hor_val; + fmt.height = hdw->res_ver_val; + fmt.code = V4L2_MBUS_FMT_FIXED; pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_size(%dx%d)", - fmt.fmt.pix.width, fmt.fmt.pix.height); - v4l2_device_call_all(&hdw->v4l2_dev, 0, video, s_fmt, &fmt); + fmt.width, fmt.height); + v4l2_device_call_all(&hdw->v4l2_dev, 0, video, s_mbus_fmt, &fmt); } if (hdw->srate_dirty || hdw->force_dirty) { -- cgit v1.2.3 From cc99113b8cfb8b9685490db0b9bf0d26c9705ad3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 9 May 2010 10:09:28 -0300 Subject: V4L/DVB: cx23885: convert to s_mbus_fmt Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-video.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 543b854f6a62..4e44dcda3875 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -976,6 +976,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, { struct cx23885_fh *fh = priv; struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct v4l2_mbus_framefmt mbus_fmt; int err; dprintk(2, "%s()\n", __func__); @@ -989,7 +990,9 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, fh->vidq.field = f->fmt.pix.field; dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width, fh->height, fh->vidq.field); - call_all(dev, video, s_fmt, f); + v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); + call_all(dev, video, s_mbus_fmt, &mbus_fmt); + v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); return 0; } -- cgit v1.2.3 From 112cb4a8a092a6338a0e2309aac134e502f2a489 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 9 May 2010 10:11:01 -0300 Subject: V4L/DVB: cx231xx: convert to s_mbus_fmt Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx231xx/cx231xx-video.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/cx231xx/cx231xx-video.c b/drivers/media/video/cx231xx/cx231xx-video.c index 2782709b263f..e76014561aa7 100644 --- a/drivers/media/video/cx231xx/cx231xx-video.c +++ b/drivers/media/video/cx231xx/cx231xx-video.c @@ -993,6 +993,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct cx231xx *dev = fh->dev; int rc; struct cx231xx_fmt *fmt; + struct v4l2_mbus_framefmt mbus_fmt; rc = check_dev(dev); if (rc < 0) @@ -1026,7 +1027,9 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, dev->format = fmt; get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale); - call_all(dev, video, s_fmt, f); + v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); + call_all(dev, video, s_mbus_fmt, &mbus_fmt); + v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); /* Set the correct alternate setting for this resolution */ cx231xx_resolution_set(dev); -- cgit v1.2.3 From c1658cafd1910cbec1b546ecd1f76e8fc99fc513 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 8 May 2010 17:20:00 -0300 Subject: V4L/DVB: cx24850: remove obsolete g/s_fmt ops Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-core.c | 31 ------------------------------ 1 file changed, 31 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index f0cbc9d066bd..bb4872b2ceb0 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -1014,17 +1014,6 @@ static int cx25840_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) /* ----------------------------------------------------------------------- */ -static int cx25840_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) -{ - switch (fmt->type) { - case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - return cx25840_g_sliced_fmt(sd, &fmt->fmt.sliced); - default: - return -EINVAL; - } - return 0; -} - static int cx25840_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) { struct cx25840_state *state = to_state(sd); @@ -1081,24 +1070,6 @@ static int cx25840_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt return 0; } -static int cx25840_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) -{ - struct v4l2_mbus_framefmt mbus_fmt; - - switch (fmt->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - mbus_fmt.width = fmt->fmt.pix.width; - mbus_fmt.height = fmt->fmt.pix.height; - mbus_fmt.code = V4L2_MBUS_FMT_FIXED; - return cx25840_s_mbus_fmt(sd, &mbus_fmt); - - default: - return -EINVAL; - } - - return 0; -} - /* ----------------------------------------------------------------------- */ static void log_video_status(struct i2c_client *client) @@ -1640,8 +1611,6 @@ static const struct v4l2_subdev_audio_ops cx25840_audio_ops = { static const struct v4l2_subdev_video_ops cx25840_video_ops = { .s_routing = cx25840_s_video_routing, - .g_fmt = cx25840_g_fmt, - .s_fmt = cx25840_s_fmt, .s_mbus_fmt = cx25840_s_mbus_fmt, .s_stream = cx25840_s_stream, }; -- cgit v1.2.3 From 029ed3261021c76f0b8538a2f715d89506555676 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 8 May 2010 17:20:35 -0300 Subject: V4L/DVB: saa7115: remove obsolete g/s_fmt ops Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7115.c | 17 ----------------- 1 file changed, 17 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index d4cc20859975..76da74368680 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -1117,13 +1117,6 @@ static int saa711x_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f return 0; } -static int saa711x_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) -{ - if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) - return -EINVAL; - return saa711x_g_sliced_fmt(sd, &fmt->fmt.sliced); -} - static int saa711x_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt) { saa711x_set_lcr(sd, NULL); @@ -1145,14 +1138,6 @@ static int saa711x_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt return saa711x_set_size(sd, fmt->width, fmt->height); } -static int saa711x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) -{ - if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - return saa711x_set_size(sd, fmt->fmt.pix.width, fmt->fmt.pix.height); -} - /* Decode the sliced VBI data stream as created by the saa7115. The format is described in the saa7115 datasheet in Tables 25 and 26 and in Figure 33. @@ -1565,8 +1550,6 @@ static const struct v4l2_subdev_audio_ops saa711x_audio_ops = { static const struct v4l2_subdev_video_ops saa711x_video_ops = { .s_routing = saa711x_s_routing, .s_crystal_freq = saa711x_s_crystal_freq, - .g_fmt = saa711x_g_fmt, - .s_fmt = saa711x_s_fmt, .s_mbus_fmt = saa711x_s_mbus_fmt, .s_stream = saa711x_s_stream, .querystd = saa711x_querystd, -- cgit v1.2.3 From ea01b11a07961aabbaec58d572b24f3df4b8065c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 9 May 2010 10:19:25 -0300 Subject: V4L/DVB: mt9v011: add enum/try/s_mbus_fmt support Note that this driver is only used by em28xx and that em28xx does not actually call the enum/try/s_fmt ops of mt9v011. So these functions have never been tested. And in fact the driver really implements cropping instead of scaling. So it seems to be doing the wrong thing :-( Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9v011.c | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/mt9v011.c b/drivers/media/video/mt9v011.c index 72e55be0b4ab..f5e778d5ca9f 100644 --- a/drivers/media/video/mt9v011.c +++ b/drivers/media/video/mt9v011.c @@ -392,27 +392,25 @@ static int mt9v011_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) return 0; } -static int mt9v011_enum_fmt(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmt) +static int mt9v011_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, + enum v4l2_mbus_pixelcode *code) { - if (fmt->index > 0) + if (index > 0) return -EINVAL; - fmt->flags = 0; - strcpy(fmt->description, "8 bpp Bayer GRGR..BGBG"); - fmt->pixelformat = V4L2_PIX_FMT_SGRBG8; - + *code = V4L2_MBUS_FMT_SGRBG8_1X8; return 0; } -static int mt9v011_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) +static int mt9v011_try_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) { - struct v4l2_pix_format *pix = &fmt->fmt.pix; - - if (pix->pixelformat != V4L2_PIX_FMT_SGRBG8) + if (fmt->code != V4L2_MBUS_FMT_SGRBG8_1X8) return -EINVAL; - v4l_bound_align_image(&pix->width, 48, 639, 1, - &pix->height, 32, 480, 1, 0); + v4l_bound_align_image(&fmt->width, 48, 639, 1, + &fmt->height, 32, 480, 1, 0); + fmt->field = V4L2_FIELD_NONE; + fmt->colorspace = V4L2_COLORSPACE_SRGB; return 0; } @@ -455,18 +453,17 @@ static int mt9v011_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) return 0; } -static int mt9v011_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) +static int mt9v011_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) { - struct v4l2_pix_format *pix = &fmt->fmt.pix; struct mt9v011 *core = to_mt9v011(sd); int rc; - rc = mt9v011_try_fmt(sd, fmt); + rc = mt9v011_try_mbus_fmt(sd, fmt); if (rc < 0) return -EINVAL; - core->width = pix->width; - core->height = pix->height; + core->width = fmt->width; + core->height = fmt->height; set_res(sd); @@ -549,9 +546,9 @@ static const struct v4l2_subdev_core_ops mt9v011_core_ops = { }; static const struct v4l2_subdev_video_ops mt9v011_video_ops = { - .enum_fmt = mt9v011_enum_fmt, - .try_fmt = mt9v011_try_fmt, - .s_fmt = mt9v011_s_fmt, + .enum_mbus_fmt = mt9v011_enum_mbus_fmt, + .try_mbus_fmt = mt9v011_try_mbus_fmt, + .s_mbus_fmt = mt9v011_s_mbus_fmt, .g_parm = mt9v011_g_parm, .s_parm = mt9v011_s_parm, }; -- cgit v1.2.3 From 468df208e84d1e7c65b0d005dbbf09f5aea92409 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 8 May 2010 17:26:00 -0300 Subject: V4L/DVB: tvp5150: remove obsolete g/s_fmt ops Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tvp5150.c | 20 -------------------- 1 file changed, 20 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c index 47f0582d50a5..1654f65cca7c 100644 --- a/drivers/media/video/tvp5150.c +++ b/drivers/media/video/tvp5150.c @@ -934,17 +934,6 @@ static int tvp5150_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f return 0; } -static int tvp5150_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) -{ - switch (fmt->type) { - case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - return tvp5150_s_sliced_fmt(sd, &fmt->fmt.sliced); - - default: - return -EINVAL; - } -} - static int tvp5150_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi) { int i, mask = 0; @@ -960,13 +949,6 @@ static int tvp5150_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f return 0; } -static int tvp5150_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) -{ - if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) - return -EINVAL; - return tvp5150_g_sliced_fmt(sd, &fmt->fmt.sliced); -} - static int tvp5150_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) { @@ -1054,8 +1036,6 @@ static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = { static const struct v4l2_subdev_video_ops tvp5150_video_ops = { .s_routing = tvp5150_s_routing, - .g_fmt = tvp5150_g_fmt, - .s_fmt = tvp5150_s_fmt, }; static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = { -- cgit v1.2.3 From cf69b808caf8e729949cf20446bec0b9ace033b7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 9 May 2010 07:39:32 -0300 Subject: V4L/DVB: au8522_decoder: g/s_fmt doesn't do anything: remove g/s_fmt is going to disappear, so if it is not doing anything, then just remove it. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/au8522_decoder.c | 26 -------------------------- 1 file changed, 26 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/au8522_decoder.c b/drivers/media/dvb/frontends/au8522_decoder.c index 68dba3a4b4da..29cdbfe36852 100644 --- a/drivers/media/dvb/frontends/au8522_decoder.c +++ b/drivers/media/dvb/frontends/au8522_decoder.c @@ -567,30 +567,6 @@ static int au8522_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) /* ----------------------------------------------------------------------- */ -static int au8522_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) -{ - switch (fmt->type) { - default: - return -EINVAL; - } - return 0; -} - -static int au8522_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) -{ - switch (fmt->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - /* Not yet implemented */ - break; - default: - return -EINVAL; - } - - return 0; -} - -/* ----------------------------------------------------------------------- */ - #ifdef CONFIG_VIDEO_ADV_DEBUG static int au8522_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) @@ -772,8 +748,6 @@ static const struct v4l2_subdev_audio_ops au8522_audio_ops = { static const struct v4l2_subdev_video_ops au8522_video_ops = { .s_routing = au8522_s_video_routing, - .g_fmt = au8522_g_fmt, - .s_fmt = au8522_s_fmt, .s_stream = au8522_s_stream, }; -- cgit v1.2.3 From 3805f201934e5384f6e941222dc1968cb638a88c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 8 May 2010 17:55:00 -0300 Subject: V4L/DVB: v4l2-subdev.h: fix enum_mbus_fmt prototype enum_mbus_fmt received an index argument that was defined as an int instead of an unsigned int. This is now fixed. This had the knock-on effect that the index argument in the callback get_formats in soc_camera.h also had to be changed to unsigned int. Signed-off-by: Hans Verkuil Acked-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ak881x.c | 2 +- drivers/media/video/mt9m001.c | 4 ++-- drivers/media/video/mt9m111.c | 4 ++-- drivers/media/video/mt9t031.c | 2 +- drivers/media/video/mt9t112.c | 4 ++-- drivers/media/video/mt9v022.c | 4 ++-- drivers/media/video/mx3_camera.c | 4 ++-- drivers/media/video/ov772x.c | 4 ++-- drivers/media/video/ov9640.c | 4 ++-- drivers/media/video/pxa_camera.c | 4 ++-- drivers/media/video/rj54n1cb0c.c | 4 ++-- drivers/media/video/sh_mobile_ceu_camera.c | 4 ++-- drivers/media/video/soc_camera.c | 3 ++- drivers/media/video/soc_camera_platform.c | 2 +- drivers/media/video/tw9910.c | 2 +- 15 files changed, 26 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ak881x.c b/drivers/media/video/ak881x.c index 35390d4717b9..3006a2c80f47 100644 --- a/drivers/media/video/ak881x.c +++ b/drivers/media/video/ak881x.c @@ -141,7 +141,7 @@ static int ak881x_s_mbus_fmt(struct v4l2_subdev *sd, return ak881x_try_g_mbus_fmt(sd, mf); } -static int ak881x_enum_mbus_fmt(struct v4l2_subdev *sd, int index, +static int ak881x_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index, enum v4l2_mbus_pixelcode *code) { if (index) diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index b62c0bd3f8ea..992ab8cb89ae 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c @@ -701,13 +701,13 @@ static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = { #endif }; -static int mt9m001_enum_fmt(struct v4l2_subdev *sd, int index, +static int mt9m001_enum_fmt(struct v4l2_subdev *sd, unsigned int index, enum v4l2_mbus_pixelcode *code) { struct i2c_client *client = sd->priv; struct mt9m001 *mt9m001 = to_mt9m001(client); - if ((unsigned int)index >= mt9m001->num_fmts) + if (index >= mt9m001->num_fmts) return -EINVAL; *code = mt9m001->fmts[index].code; diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index d35f536f9fc3..bac0c5d4070c 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c @@ -999,10 +999,10 @@ static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = { #endif }; -static int mt9m111_enum_fmt(struct v4l2_subdev *sd, int index, +static int mt9m111_enum_fmt(struct v4l2_subdev *sd, unsigned int index, enum v4l2_mbus_pixelcode *code) { - if ((unsigned int)index >= ARRAY_SIZE(mt9m111_colour_fmts)) + if (index >= ARRAY_SIZE(mt9m111_colour_fmts)) return -EINVAL; *code = mt9m111_colour_fmts[index].code; diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c index 78b4e091d2d5..f26933a8fd8a 100644 --- a/drivers/media/video/mt9t031.c +++ b/drivers/media/video/mt9t031.c @@ -798,7 +798,7 @@ static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = { #endif }; -static int mt9t031_enum_fmt(struct v4l2_subdev *sd, int index, +static int mt9t031_enum_fmt(struct v4l2_subdev *sd, unsigned int index, enum v4l2_mbus_pixelcode *code) { if (index) diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c index 7438f8d775ba..abe5505b9f79 100644 --- a/drivers/media/video/mt9t112.c +++ b/drivers/media/video/mt9t112.c @@ -1017,10 +1017,10 @@ static int mt9t112_try_fmt(struct v4l2_subdev *sd, return 0; } -static int mt9t112_enum_fmt(struct v4l2_subdev *sd, int index, +static int mt9t112_enum_fmt(struct v4l2_subdev *sd, unsigned int index, enum v4l2_mbus_pixelcode *code) { - if ((unsigned int)index >= ARRAY_SIZE(mt9t112_cfmts)) + if (index >= ARRAY_SIZE(mt9t112_cfmts)) return -EINVAL; *code = mt9t112_cfmts[index].code; diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index e5bae4c9393b..c409d05d465a 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c @@ -838,13 +838,13 @@ static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = { #endif }; -static int mt9v022_enum_fmt(struct v4l2_subdev *sd, int index, +static int mt9v022_enum_fmt(struct v4l2_subdev *sd, unsigned int index, enum v4l2_mbus_pixelcode *code) { struct i2c_client *client = sd->priv; struct mt9v022 *mt9v022 = to_mt9v022(client); - if ((unsigned int)index >= mt9v022->num_fmts) + if (index >= mt9v022->num_fmts) return -EINVAL; *code = mt9v022->fmts[index].code; diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c index d477e3058002..a9be14c23912 100644 --- a/drivers/media/video/mx3_camera.c +++ b/drivers/media/video/mx3_camera.c @@ -672,7 +672,7 @@ static bool mx3_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt) fmt->packing == SOC_MBUS_PACKING_EXTEND16); } -static int mx3_camera_get_formats(struct soc_camera_device *icd, int idx, +static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int idx, struct soc_camera_format_xlate *xlate) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); @@ -689,7 +689,7 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, int idx, fmt = soc_mbus_get_fmtdesc(code); if (!fmt) { dev_err(icd->dev.parent, - "Invalid format code #%d: %d\n", idx, code); + "Invalid format code #%u: %d\n", idx, code); return 0; } diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c index 7f8ece30c77b..86b0186c360c 100644 --- a/drivers/media/video/ov772x.c +++ b/drivers/media/video/ov772x.c @@ -1092,10 +1092,10 @@ static struct v4l2_subdev_core_ops ov772x_subdev_core_ops = { #endif }; -static int ov772x_enum_fmt(struct v4l2_subdev *sd, int index, +static int ov772x_enum_fmt(struct v4l2_subdev *sd, unsigned int index, enum v4l2_mbus_pixelcode *code) { - if ((unsigned int)index >= ARRAY_SIZE(ov772x_cfmts)) + if (index >= ARRAY_SIZE(ov772x_cfmts)) return -EINVAL; *code = ov772x_cfmts[index].code; diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c index 36599a65f548..58811c044c6a 100644 --- a/drivers/media/video/ov9640.c +++ b/drivers/media/video/ov9640.c @@ -614,10 +614,10 @@ static int ov9640_try_fmt(struct v4l2_subdev *sd, return 0; } -static int ov9640_enum_fmt(struct v4l2_subdev *sd, int index, +static int ov9640_enum_fmt(struct v4l2_subdev *sd, unsigned int index, enum v4l2_mbus_pixelcode *code) { - if ((unsigned int)index >= ARRAY_SIZE(ov9640_codes)) + if (index >= ARRAY_SIZE(ov9640_codes)) return -EINVAL; *code = ov9640_codes[index]; diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index 7fe70e718656..fb242f6cfb1f 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c @@ -1247,7 +1247,7 @@ static bool pxa_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt) fmt->packing == SOC_MBUS_PACKING_EXTEND16); } -static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx, +static int pxa_camera_get_formats(struct soc_camera_device *icd, unsigned int idx, struct soc_camera_format_xlate *xlate) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); @@ -1264,7 +1264,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx, fmt = soc_mbus_get_fmtdesc(code); if (!fmt) { - dev_err(dev, "Invalid format code #%d: %d\n", idx, code); + dev_err(dev, "Invalid format code #%u: %d\n", idx, code); return 0; } diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c index bbd9c11e2c5a..64eb05ce5603 100644 --- a/drivers/media/video/rj54n1cb0c.c +++ b/drivers/media/video/rj54n1cb0c.c @@ -481,10 +481,10 @@ static int reg_write_multiple(struct i2c_client *client, return 0; } -static int rj54n1_enum_fmt(struct v4l2_subdev *sd, int index, +static int rj54n1_enum_fmt(struct v4l2_subdev *sd, unsigned int index, enum v4l2_mbus_pixelcode *code) { - if ((unsigned int)index >= ARRAY_SIZE(rj54n1_colour_fmts)) + if (index >= ARRAY_SIZE(rj54n1_colour_fmts)) return -EINVAL; *code = rj54n1_colour_fmts[index].code; diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 4ac3b482fbb4..961bfa2fea97 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -878,7 +878,7 @@ static bool sh_mobile_ceu_packing_supported(const struct soc_mbus_pixelfmt *fmt) static int client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect); -static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx, +static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int idx, struct soc_camera_format_xlate *xlate) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); @@ -897,7 +897,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx, fmt = soc_mbus_get_fmtdesc(code); if (!fmt) { dev_err(icd->dev.parent, - "Invalid format code #%d: %d\n", idx, code); + "Invalid format code #%u: %d\n", idx, code); return -EINVAL; } diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index db1ca0e90d76..475757bfd7ba 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -200,7 +200,8 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - int i, fmts = 0, raw_fmts = 0, ret; + unsigned int i, fmts = 0, raw_fmts = 0; + int ret; enum v4l2_mbus_pixelcode code; while (!v4l2_subdev_call(sd, video, enum_mbus_fmt, raw_fmts, &code)) diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c index 10b003a8be83..248c986f0989 100644 --- a/drivers/media/video/soc_camera_platform.c +++ b/drivers/media/video/soc_camera_platform.c @@ -71,7 +71,7 @@ static int soc_camera_platform_try_fmt(struct v4l2_subdev *sd, static struct v4l2_subdev_core_ops platform_subdev_core_ops; -static int soc_camera_platform_enum_fmt(struct v4l2_subdev *sd, int index, +static int soc_camera_platform_enum_fmt(struct v4l2_subdev *sd, unsigned int index, enum v4l2_mbus_pixelcode *code) { struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c index 76be733eabfd..2f3b1942e027 100644 --- a/drivers/media/video/tw9910.c +++ b/drivers/media/video/tw9910.c @@ -903,7 +903,7 @@ static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = { #endif }; -static int tw9910_enum_fmt(struct v4l2_subdev *sd, int index, +static int tw9910_enum_fmt(struct v4l2_subdev *sd, unsigned int index, enum v4l2_mbus_pixelcode *code) { if (index) -- cgit v1.2.3 From 2db4e78f14a5b4741b09d03e6d17610537a9af27 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 9 May 2010 06:30:15 -0300 Subject: V4L/DVB: tvp514x: do NOT change the std as a side effect Several calls (try_fmt, g_parm among others) changed the current standard as a side effect of that call. But the standard may only be changed by s_std. Signed-off-by: Hans Verkuil Reviewed-by: Vaibhav Hiremath Tested-by: Vaibhav Hiremath Acked-by: Vaibhav Hiremath Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tvp514x.c | 53 +++++++++++++------------------------------ 1 file changed, 16 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c index e826114b7fb8..40d84d73edf8 100644 --- a/drivers/media/video/tvp514x.c +++ b/drivers/media/video/tvp514x.c @@ -366,13 +366,13 @@ static int tvp514x_write_regs(struct v4l2_subdev *sd, } /** - * tvp514x_get_current_std() : Get the current standard detected by TVP5146/47 + * tvp514x_query_current_std() : Query the current standard detected by TVP5146/47 * @sd: ptr to v4l2_subdev struct * - * Get current standard detected by TVP5146/47, STD_INVALID if there is no + * Returns the current standard detected by TVP5146/47, STD_INVALID if there is no * standard detected. */ -static enum tvp514x_std tvp514x_get_current_std(struct v4l2_subdev *sd) +static enum tvp514x_std tvp514x_query_current_std(struct v4l2_subdev *sd) { u8 std, std_status; @@ -518,7 +518,7 @@ static int tvp514x_detect(struct v4l2_subdev *sd, * @std_id: standard V4L2 std_id ioctl enum * * Returns the current standard detected by TVP5146/47. If no active input is - * detected, returns -EINVAL + * detected then *std_id is set to 0 and the function returns 0. */ static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id) { @@ -530,10 +530,12 @@ static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id) if (std_id == NULL) return -EINVAL; - /* get the current standard */ - current_std = tvp514x_get_current_std(sd); + *std_id = V4L2_STD_UNKNOWN; + + /* query the current standard */ + current_std = tvp514x_query_current_std(sd); if (current_std == STD_INVALID) - return -EINVAL; + return 0; input_sel = decoder->input; @@ -575,12 +577,11 @@ static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id) /* check whether signal is locked */ sync_lock_status = tvp514x_read_reg(sd, REG_STATUS1); if (lock_mask != (sync_lock_status & lock_mask)) - return -EINVAL; /* No input detected */ + return 0; /* No input detected */ - decoder->current_std = current_std; *std_id = decoder->std_list[current_std].standard.id; - v4l2_dbg(1, debug, sd, "Current STD: %s", + v4l2_dbg(1, debug, sd, "Current STD: %s\n", decoder->std_list[current_std].standard.name); return 0; } @@ -637,7 +638,6 @@ static int tvp514x_s_routing(struct v4l2_subdev *sd, int err; enum tvp514x_input input_sel; enum tvp514x_output output_sel; - enum tvp514x_std current_std = STD_INVALID; u8 sync_lock_status, lock_mask; int try_count = LOCK_RETRY_COUNT; @@ -721,11 +721,6 @@ static int tvp514x_s_routing(struct v4l2_subdev *sd, /* Allow decoder to sync up with new input */ msleep(LOCK_RETRY_DELAY); - /* get the current standard for future reference */ - current_std = tvp514x_get_current_std(sd); - if (current_std == STD_INVALID) - continue; - sync_lock_status = tvp514x_read_reg(sd, REG_STATUS1); if (lock_mask == (sync_lock_status & lock_mask)) @@ -733,15 +728,13 @@ static int tvp514x_s_routing(struct v4l2_subdev *sd, break; } - if ((current_std == STD_INVALID) || (try_count < 0)) + if (try_count < 0) return -EINVAL; - decoder->current_std = current_std; decoder->input = input; decoder->output = output; - v4l2_dbg(1, debug, sd, "Input set to: %d, std : %d", - input_sel, current_std); + v4l2_dbg(1, debug, sd, "Input set to: %d\n", input_sel); return 0; } @@ -1018,11 +1011,8 @@ tvp514x_try_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f) pix = &f->fmt.pix; /* Calculate height and width based on current standard */ - current_std = tvp514x_get_current_std(sd); - if (current_std == STD_INVALID) - return -EINVAL; + current_std = decoder->current_std; - decoder->current_std = current_std; pix->width = decoder->std_list[current_std].width; pix->height = decoder->std_list[current_std].height; @@ -1132,15 +1122,8 @@ tvp514x_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a) /* only capture is supported */ return -EINVAL; - memset(a, 0, sizeof(*a)); - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - /* get the current standard */ - current_std = tvp514x_get_current_std(sd); - if (current_std == STD_INVALID) - return -EINVAL; - - decoder->current_std = current_std; + current_std = decoder->current_std; cparm = &a->parm.capture; cparm->capability = V4L2_CAP_TIMEPERFRAME; @@ -1175,11 +1158,7 @@ tvp514x_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a) timeperframe = &a->parm.capture.timeperframe; /* get the current standard */ - current_std = tvp514x_get_current_std(sd); - if (current_std == STD_INVALID) - return -EINVAL; - - decoder->current_std = current_std; + current_std = decoder->current_std; *timeperframe = decoder->std_list[current_std].standard.frameperiod; -- cgit v1.2.3 From a75ffc124611a535aec8f403817d382d106c68d7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 9 May 2010 06:32:47 -0300 Subject: V4L/DVB: tvp514x: make std_list const Signed-off-by: Hans Verkuil Reviewed-by: Vaibhav Hiremath Tested-by: Vaibhav Hiremath Acked-by: Vaibhav Hiremath Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tvp514x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c index 40d84d73edf8..b802da713114 100644 --- a/drivers/media/video/tvp514x.c +++ b/drivers/media/video/tvp514x.c @@ -111,7 +111,7 @@ struct tvp514x_decoder { enum tvp514x_std current_std; int num_stds; - struct tvp514x_std_info *std_list; + const struct tvp514x_std_info *std_list; /* Input and Output Routing parameters */ u32 input; u32 output; @@ -223,7 +223,7 @@ static const struct v4l2_fmtdesc tvp514x_fmt_list[] = { * Currently supports two standards only, need to add support for rest of the * modes, like SECAM, etc... */ -static struct tvp514x_std_info tvp514x_std_list[] = { +static const struct tvp514x_std_info tvp514x_std_list[] = { /* Standard: STD_NTSC_MJ */ [STD_NTSC_MJ] = { .width = NTSC_NUM_ACTIVE_PIXELS, -- cgit v1.2.3 From c2fc80961fc2059c05bf07c92decfffde2a0f9ef Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 9 May 2010 06:37:14 -0300 Subject: V4L/DVB: tvp514x: there is only one supported format, so simplify the code Get rid of unnecessary code since this driver supports only one pixel format. Removing this code will make the transition to the mbus API easier as well. Signed-off-by: Hans Verkuil Reviewed-by: Vaibhav Hiremath Tested-by: Vaibhav Hiremath Acked-by: Vaibhav Hiremath Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tvp514x.c | 45 +++++++++---------------------------------- 1 file changed, 9 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c index b802da713114..cb4284384133 100644 --- a/drivers/media/video/tvp514x.c +++ b/drivers/media/video/tvp514x.c @@ -89,8 +89,6 @@ static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable); * @ver: Chip version * @streaming: TVP5146/47 decoder streaming - enabled or disabled. * @pix: Current pixel format - * @num_fmts: Number of formats - * @fmt_list: Format list * @current_std: Current standard * @num_stds: Number of standards * @std_list: Standards list @@ -106,8 +104,6 @@ struct tvp514x_decoder { int streaming; struct v4l2_pix_format pix; - int num_fmts; - const struct v4l2_fmtdesc *fmt_list; enum tvp514x_std current_std; int num_stds; @@ -960,27 +956,18 @@ tvp514x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) static int tvp514x_enum_fmt_cap(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmt) { - struct tvp514x_decoder *decoder = to_decoder(sd); - int index; - - if (fmt == NULL) - return -EINVAL; - - index = fmt->index; - if ((index >= decoder->num_fmts) || (index < 0)) - /* Index out of bound */ + if (fmt == NULL || fmt->index) return -EINVAL; if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) /* only capture is supported */ return -EINVAL; - memcpy(fmt, &decoder->fmt_list[index], - sizeof(struct v4l2_fmtdesc)); - - v4l2_dbg(1, debug, sd, "Current FMT: index - %d (%s)", - decoder->fmt_list[index].index, - decoder->fmt_list[index].description); + /* only one format */ + fmt->flags = 0; + strlcpy(fmt->description, "8-bit UYVY 4:2:2 Format", + sizeof(fmt->description)); + fmt->pixelformat = V4L2_PIX_FMT_UYVY; return 0; } @@ -997,7 +984,6 @@ static int tvp514x_try_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f) { struct tvp514x_decoder *decoder = to_decoder(sd); - int ifmt; struct v4l2_pix_format *pix; enum tvp514x_std current_std; @@ -1013,28 +999,18 @@ tvp514x_try_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f) /* Calculate height and width based on current standard */ current_std = decoder->current_std; + pix->pixelformat = V4L2_PIX_FMT_UYVY; pix->width = decoder->std_list[current_std].width; pix->height = decoder->std_list[current_std].height; - - for (ifmt = 0; ifmt < decoder->num_fmts; ifmt++) { - if (pix->pixelformat == - decoder->fmt_list[ifmt].pixelformat) - break; - } - if (ifmt == decoder->num_fmts) - /* None of the format matched, select default */ - ifmt = 0; - pix->pixelformat = decoder->fmt_list[ifmt].pixelformat; - pix->field = V4L2_FIELD_INTERLACED; pix->bytesperline = pix->width * 2; pix->sizeimage = pix->bytesperline * pix->height; pix->colorspace = V4L2_COLORSPACE_SMPTE170M; pix->priv = 0; - v4l2_dbg(1, debug, sd, "Try FMT: pixelformat - %s, bytesperline - %d" + v4l2_dbg(1, debug, sd, "Try FMT: bytesperline - %d" "Width - %d, Height - %d", - decoder->fmt_list[ifmt].description, pix->bytesperline, + pix->bytesperline, pix->width, pix->height); return 0; } @@ -1254,9 +1230,6 @@ static const struct v4l2_subdev_ops tvp514x_ops = { static struct tvp514x_decoder tvp514x_dev = { .streaming = 0, - .fmt_list = tvp514x_fmt_list, - .num_fmts = ARRAY_SIZE(tvp514x_fmt_list), - .pix = { /* Default to NTSC 8-bit YUV 422 */ .width = NTSC_NUM_ACTIVE_PIXELS, -- cgit v1.2.3 From 3907b07294a9a87793ca9e0223c7bf66b6108ab0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 9 May 2010 06:39:44 -0300 Subject: V4L/DVB: tvp514x: add missing newlines Signed-off-by: Hans Verkuil Reviewed-by: Vaibhav Hiremath Tested-by: Vaibhav Hiremath Acked-by: Vaibhav Hiremath Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tvp514x.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c index cb4284384133..1b03d0eb20df 100644 --- a/drivers/media/video/tvp514x.c +++ b/drivers/media/video/tvp514x.c @@ -611,7 +611,7 @@ static int tvp514x_s_std(struct v4l2_subdev *sd, v4l2_std_id std_id) decoder->tvp514x_regs[REG_VIDEO_STD].val = decoder->std_list[i].video_std; - v4l2_dbg(1, debug, sd, "Standard set to: %s", + v4l2_dbg(1, debug, sd, "Standard set to: %s\n", decoder->std_list[i].standard.name); return 0; } @@ -783,7 +783,7 @@ tvp514x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qctrl) return err; } - v4l2_dbg(1, debug, sd, "Query Control:%s: Min - %d, Max - %d, Def - %d", + v4l2_dbg(1, debug, sd, "Query Control:%s: Min - %d, Max - %d, Def - %d\n", qctrl->name, qctrl->minimum, qctrl->maximum, qctrl->default_value); @@ -840,7 +840,7 @@ tvp514x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) return -EINVAL; } - v4l2_dbg(1, debug, sd, "Get Control: ID - %d - %d", + v4l2_dbg(1, debug, sd, "Get Control: ID - %d - %d\n", ctrl->id, ctrl->value); return 0; } @@ -940,7 +940,7 @@ tvp514x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) return err; } - v4l2_dbg(1, debug, sd, "Set Control: ID - %d - %d", + v4l2_dbg(1, debug, sd, "Set Control: ID - %d - %d\n", ctrl->id, ctrl->value); return err; @@ -1009,7 +1009,7 @@ tvp514x_try_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f) pix->priv = 0; v4l2_dbg(1, debug, sd, "Try FMT: bytesperline - %d" - "Width - %d, Height - %d", + "Width - %d, Height - %d\n", pix->bytesperline, pix->width, pix->height); return 0; @@ -1071,7 +1071,7 @@ tvp514x_g_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f) f->fmt.pix = decoder->pix; v4l2_dbg(1, debug, sd, "Current FMT: bytesperline - %d" - "Width - %d, Height - %d", + "Width - %d, Height - %d\n", decoder->pix.bytesperline, decoder->pix.width, decoder->pix.height); return 0; -- cgit v1.2.3 From f1a4435f3efa510760adf6acb87c62653de9a0ee Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 9 May 2010 06:40:18 -0300 Subject: V4L/DVB: tvp514x: remove obsolete fmt_list Signed-off-by: Hans Verkuil Reviewed-by: Vaibhav Hiremath Tested-by: Vaibhav Hiremath Acked-by: Vaibhav Hiremath Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tvp514x.c | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c index 1b03d0eb20df..bb5df5176377 100644 --- a/drivers/media/video/tvp514x.c +++ b/drivers/media/video/tvp514x.c @@ -198,21 +198,6 @@ static struct tvp514x_reg tvp514x_reg_list_default[] = { {TOK_TERM, 0, 0}, }; -/** - * List of image formats supported by TVP5146/47 decoder - * Currently we are using 8 bit mode only, but can be - * extended to 10/20 bit mode. - */ -static const struct v4l2_fmtdesc tvp514x_fmt_list[] = { - { - .index = 0, - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .flags = 0, - .description = "8-bit UYVY 4:2:2 Format", - .pixelformat = V4L2_PIX_FMT_UYVY, - }, -}; - /** * Supported standards - * -- cgit v1.2.3 From 283d637bbd7301c9fb2236103b990b9d66099d78 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 9 May 2010 06:44:16 -0300 Subject: V4L/DVB: tvp514x: simplify try/g/s_fmt handling Since there is only one possible format just have all three calls do the same. Signed-off-by: Hans Verkuil Reviewed-by: Vaibhav Hiremath Tested-by: Vaibhav Hiremath Acked-by: Vaibhav Hiremath Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tvp514x.c | 98 ++++--------------------------------------- 1 file changed, 9 insertions(+), 89 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c index bb5df5176377..71c73fa0d68c 100644 --- a/drivers/media/video/tvp514x.c +++ b/drivers/media/video/tvp514x.c @@ -88,7 +88,6 @@ static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable); * @pdata: Board specific * @ver: Chip version * @streaming: TVP5146/47 decoder streaming - enabled or disabled. - * @pix: Current pixel format * @current_std: Current standard * @num_stds: Number of standards * @std_list: Standards list @@ -103,8 +102,6 @@ struct tvp514x_decoder { int ver; int streaming; - struct v4l2_pix_format pix; - enum tvp514x_std current_std; int num_stds; const struct tvp514x_std_info *std_list; @@ -957,16 +954,15 @@ tvp514x_enum_fmt_cap(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmt) } /** - * tvp514x_try_fmt_cap() - V4L2 decoder interface handler for try_fmt + * tvp514x_fmt_cap() - V4L2 decoder interface handler for try/s/g_fmt * @sd: pointer to standard V4L2 sub-device structure * @f: pointer to standard V4L2 VIDIOC_TRY_FMT ioctl structure * - * Implement the VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type. This - * ioctl is used to negotiate the image capture size and pixel format - * without actually making it take effect. + * Implement the VIDIOC_TRY/S/G_FMT ioctl for the CAPTURE buffer type. This + * ioctl is used to negotiate the image capture size and pixel format. */ static int -tvp514x_try_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f) +tvp514x_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f) { struct tvp514x_decoder *decoder = to_decoder(sd); struct v4l2_pix_format *pix; @@ -976,8 +972,7 @@ tvp514x_try_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f) return -EINVAL; if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - /* only capture is supported */ - f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + return -EINVAL; pix = &f->fmt.pix; @@ -993,75 +988,13 @@ tvp514x_try_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f) pix->colorspace = V4L2_COLORSPACE_SMPTE170M; pix->priv = 0; - v4l2_dbg(1, debug, sd, "Try FMT: bytesperline - %d" + v4l2_dbg(1, debug, sd, "FMT: bytesperline - %d" "Width - %d, Height - %d\n", pix->bytesperline, pix->width, pix->height); return 0; } -/** - * tvp514x_s_fmt_cap() - V4L2 decoder interface handler for s_fmt - * @sd: pointer to standard V4L2 sub-device structure - * @f: pointer to standard V4L2 VIDIOC_S_FMT ioctl structure - * - * If the requested format is supported, configures the HW to use that - * format, returns error code if format not supported or HW can't be - * correctly configured. - */ -static int -tvp514x_s_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f) -{ - struct tvp514x_decoder *decoder = to_decoder(sd); - struct v4l2_pix_format *pix; - int rval; - - if (f == NULL) - return -EINVAL; - - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - /* only capture is supported */ - return -EINVAL; - - pix = &f->fmt.pix; - rval = tvp514x_try_fmt_cap(sd, f); - if (rval) - return rval; - - decoder->pix = *pix; - - return rval; -} - -/** - * tvp514x_g_fmt_cap() - V4L2 decoder interface handler for tvp514x_g_fmt_cap - * @sd: pointer to standard V4L2 sub-device structure - * @f: pointer to standard V4L2 v4l2_format structure - * - * Returns the decoder's current pixel format in the v4l2_format - * parameter. - */ -static int -tvp514x_g_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f) -{ - struct tvp514x_decoder *decoder = to_decoder(sd); - - if (f == NULL) - return -EINVAL; - - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - /* only capture is supported */ - return -EINVAL; - - f->fmt.pix = decoder->pix; - - v4l2_dbg(1, debug, sd, "Current FMT: bytesperline - %d" - "Width - %d, Height - %d\n", - decoder->pix.bytesperline, - decoder->pix.width, decoder->pix.height); - return 0; -} - /** * tvp514x_g_parm() - V4L2 decoder interface handler for g_parm * @sd: pointer to standard V4L2 sub-device structure @@ -1199,9 +1132,9 @@ static const struct v4l2_subdev_video_ops tvp514x_video_ops = { .s_routing = tvp514x_s_routing, .querystd = tvp514x_querystd, .enum_fmt = tvp514x_enum_fmt_cap, - .g_fmt = tvp514x_g_fmt_cap, - .try_fmt = tvp514x_try_fmt_cap, - .s_fmt = tvp514x_s_fmt_cap, + .g_fmt = tvp514x_fmt_cap, + .try_fmt = tvp514x_fmt_cap, + .s_fmt = tvp514x_fmt_cap, .g_parm = tvp514x_g_parm, .s_parm = tvp514x_s_parm, .s_stream = tvp514x_s_stream, @@ -1214,19 +1147,6 @@ static const struct v4l2_subdev_ops tvp514x_ops = { static struct tvp514x_decoder tvp514x_dev = { .streaming = 0, - - .pix = { - /* Default to NTSC 8-bit YUV 422 */ - .width = NTSC_NUM_ACTIVE_PIXELS, - .height = NTSC_NUM_ACTIVE_LINES, - .pixelformat = V4L2_PIX_FMT_UYVY, - .field = V4L2_FIELD_INTERLACED, - .bytesperline = NTSC_NUM_ACTIVE_PIXELS * 2, - .sizeimage = - NTSC_NUM_ACTIVE_PIXELS * 2 * NTSC_NUM_ACTIVE_LINES, - .colorspace = V4L2_COLORSPACE_SMPTE170M, - }, - .current_std = STD_NTSC_MJ, .std_list = tvp514x_std_list, .num_stds = ARRAY_SIZE(tvp514x_std_list), -- cgit v1.2.3 From 76952c7e598f68bf12adf307d6a9a0de3b33b985 Mon Sep 17 00:00:00 2001 From: Guy Martin Date: Fri, 7 May 2010 04:09:25 -0300 Subject: V4L/DVB: TT CT-3650 DVB-C support Add support for the DVB-C frontend of the TT CT-3650. DVB-T fe, CI and IR are not implemented. Signed-off-by: Guy Martin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + drivers/media/dvb/dvb-usb/ttusb2.c | 95 ++++++++++++++++++++++++++++++--- 2 files changed, 90 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 085c4e457e0e..b4afe6f8ed19 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -198,6 +198,7 @@ #define USB_PID_AVERMEDIA_A850 0x850a #define USB_PID_AVERMEDIA_A805 0xa805 #define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006 +#define USB_PID_TECHNOTREND_CONNECT_CT3650 0x300d #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2 0x0081 #define USB_PID_TERRATEC_CINERGY_HT_USB_XE 0x0058 diff --git a/drivers/media/dvb/dvb-usb/ttusb2.c b/drivers/media/dvb/dvb-usb/ttusb2.c index 20ca9d9ee99b..a6de489a6a39 100644 --- a/drivers/media/dvb/dvb-usb/ttusb2.c +++ b/drivers/media/dvb/dvb-usb/ttusb2.c @@ -29,6 +29,8 @@ #include "tda826x.h" #include "tda10086.h" +#include "tda1002x.h" +#include "tda827x.h" #include "lnbp21.h" /* debug */ @@ -150,7 +152,17 @@ static struct tda10086_config tda10086_config = { .xtal_freq = TDA10086_XTAL_16M, }; -static int ttusb2_frontend_attach(struct dvb_usb_adapter *adap) +static struct tda10023_config tda10023_config = { + .demod_address = 0x0c, + .invert = 0, + .xtal = 16000000, + .pll_m = 11, + .pll_p = 3, + .pll_n = 1, + .deltaf = 0xa511, +}; + +static int ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap) { if (usb_set_interface(adap->dev->udev,0,3) < 0) err("set interface to alts=3 failed"); @@ -163,7 +175,27 @@ static int ttusb2_frontend_attach(struct dvb_usb_adapter *adap) return 0; } -static int ttusb2_tuner_attach(struct dvb_usb_adapter *adap) +static int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap) +{ + if (usb_set_interface(adap->dev->udev, 0, 3) < 0) + err("set interface to alts=3 failed"); + if ((adap->fe = dvb_attach(tda10023_attach, &tda10023_config, &adap->dev->i2c_adap, 0x48)) == NULL) { + deb_info("TDA10023 attach failed\n"); + return -ENODEV; + } + return 0; +} + +static int ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter *adap) +{ + if (dvb_attach(tda827x_attach, adap->fe, 0x61, &adap->dev->i2c_adap, NULL) == NULL) { + printk(KERN_ERR "%s: No tda827x found!\n", __func__); + return -ENODEV; + } + return 0; +} + +static int ttusb2_tuner_tda826x_attach(struct dvb_usb_adapter *adap) { if (dvb_attach(tda826x_attach, adap->fe, 0x60, &adap->dev->i2c_adap, 0) == NULL) { deb_info("TDA8263 attach failed\n"); @@ -180,6 +212,7 @@ static int ttusb2_tuner_attach(struct dvb_usb_adapter *adap) /* DVB USB Driver stuff */ static struct dvb_usb_device_properties ttusb2_properties; static struct dvb_usb_device_properties ttusb2_properties_s2400; +static struct dvb_usb_device_properties ttusb2_properties_ct3650; static int ttusb2_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -187,6 +220,8 @@ static int ttusb2_probe(struct usb_interface *intf, if (0 == dvb_usb_device_init(intf, &ttusb2_properties, THIS_MODULE, NULL, adapter_nr) || 0 == dvb_usb_device_init(intf, &ttusb2_properties_s2400, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &ttusb2_properties_ct3650, THIS_MODULE, NULL, adapter_nr)) return 0; return -ENODEV; @@ -197,6 +232,8 @@ static struct usb_device_id ttusb2_table [] = { { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_450E) }, { USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_CONNECT_S2400) }, + { USB_DEVICE(USB_VID_TECHNOTREND, + USB_PID_TECHNOTREND_CONNECT_CT3650) }, {} /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, ttusb2_table); @@ -214,8 +251,8 @@ static struct dvb_usb_device_properties ttusb2_properties = { { .streaming_ctrl = NULL, // ttusb2_streaming_ctrl, - .frontend_attach = ttusb2_frontend_attach, - .tuner_attach = ttusb2_tuner_attach, + .frontend_attach = ttusb2_frontend_tda10086_attach, + .tuner_attach = ttusb2_tuner_tda826x_attach, /* parameter for the MPEG2-data transfer */ .stream = { @@ -266,8 +303,8 @@ static struct dvb_usb_device_properties ttusb2_properties_s2400 = { { .streaming_ctrl = NULL, - .frontend_attach = ttusb2_frontend_attach, - .tuner_attach = ttusb2_tuner_attach, + .frontend_attach = ttusb2_frontend_tda10086_attach, + .tuner_attach = ttusb2_tuner_tda826x_attach, /* parameter for the MPEG2-data transfer */ .stream = { @@ -301,6 +338,52 @@ static struct dvb_usb_device_properties ttusb2_properties_s2400 = { } }; +static struct dvb_usb_device_properties ttusb2_properties_ct3650 = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .size_of_priv = sizeof(struct ttusb2_state), + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = NULL, + + .frontend_attach = ttusb2_frontend_tda10023_attach, + .tuner_attach = ttusb2_tuner_tda827x_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_ISOC, + .count = 5, + .endpoint = 0x02, + .u = { + .isoc = { + .framesperurb = 4, + .framesize = 940, + .interval = 1, + } + } + } + }, + }, + + .power_ctrl = ttusb2_power_ctrl, + .identify_state = ttusb2_identify_state, + + .i2c_algo = &ttusb2_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { "Technotrend TT-connect CT-3650", + .warm_ids = { &ttusb2_table[3], NULL }, + }, + } +}; + static struct usb_driver ttusb2_driver = { .name = "dvb_usb_ttusb2", .probe = ttusb2_probe, -- cgit v1.2.3 From e65f8c4e3eef3a0946f8e8fba1fb6aabde734f50 Mon Sep 17 00:00:00 2001 From: Guy Martin Date: Fri, 7 May 2010 04:34:40 -0300 Subject: V4L/DVB: stv6110x: Fix kernel null pointer deref The following OOPS happened when plugging two TT s2-1600: [ 96.521023] saa7146: register extension 'budget dvb'. [ 96.521052] budget dvb 0000:05:00.0: PCI INT A -> GSI 16 (level, low) -> IRQ 16 [ 96.521070] IRQ 16/: IRQF_DISABLED is not guaranteed on shared IRQs [ 96.521076] saa7146: found saa7146 @ mem ffffc90011182c00 (revision 1, irq 16) (0x13c2,0x101c). [ 96.521080] saa7146 (0): dma buffer size 192512 [ 96.521081] DVB: registering new adapter (TT-Budget S2-1600 PCI) [ 96.539929] adapter has MAC addr = 00:d0:5c:cc:b0:a2 [ 96.890149] stv6110x_attach: Attaching STV6110x [ 96.912516] DVB: registering adapter 0 frontend 0 (STV090x Multistandard)... [ 96.912600] budget dvb 0000:05:01.0: PCI INT A -> GSI 17 (level, low) -> IRQ 17 [ 96.912639] IRQ 17/: IRQF_DISABLED is not guaranteed on shared IRQs [ 96.912667] saa7146: found saa7146 @ mem ffffc90011314800 (revision 1, irq 17) (0x13c2,0x101c). [ 96.912673] saa7146 (1): dma buffer size 192512 [ 96.912676] DVB: registering new adapter (TT-Budget S2-1600 PCI) [ 96.930893] adapter has MAC addr = 00:d0:5c:cc:b0:a3 [ 97.233478] BUG: unable to handle kernel NULL pointer dereference at 0000000000000010 [ 97.233647] IP: [] stv6110x_set_mode+0x70/0x80 [stv6110x] [ 97.233753] PGD 3c16f067 PUD 3c383067 PMD 0 [ 97.234147] CPU 0 [ 97.234246] Pid: 5200, comm: modprobe Not tainted 2.6.33.2 #1 P5QSE/P5Q SE [ 97.234317] RIP: 0010:[] [] stv6110x_set_mode+0x70/0x80 [stv6110x] [ 97.234456] RSP: 0018:ffff88003c125c98 EFLAGS: 00010246 [ 97.234461] RAX: ffffffffa029c460 RBX: ffff88003f84d800 RCX: ffff88003a19e140 [ 97.234461] RDX: 0000000000000000 RSI: 0000000000000001 RDI: 0000000000000000 [ 97.234461] RBP: ffff88003f84d828 R08: 0000000000000002 R09: 0000000000000004 [ 97.234461] R10: 0000000000000003 R11: 0000000000000010 R12: ffff88003f84d800 [ 97.234461] R13: ffff88003f84d828 R14: ffff88003f84d828 R15: 0000000000000001 [ 97.234461] FS: 00007f9f7253e6f0(0000) GS:ffff880001800000(0000) knlGS:0000000000000000 [ 97.234461] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [ 97.234461] CR2: 0000000000000010 CR3: 000000003c382000 CR4: 00000000000006b0 [ 97.234461] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 97.234461] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 [ 97.234461] Process modprobe (pid: 5200, threadinfo ffff88003c124000, task ffff88003e893ac0) [ 97.234461] ffff88003f84d800 ffff88003f84d828 ffff88003f84d800 ffffffffa0292343 [ 97.234461] <0> ffff88003f84d828 ffff88003ef70ae0 ffffffffa0280800 ffffffffa02934d2 [ 97.234461] <0> ffffffffa0295260 0000000000000000 ffffffffa02948b0 ffff88003df79800 [ 97.234461] [] ? stv090x_sleep+0x33/0x120 [stv090x] [ 97.234461] [] ? stv090x_attach+0x1e2/0x73c [stv090x] [ 97.234461] [] ? dma_generic_alloc_coherent+0xa5/0x160 [ 97.234461] [] ? saa7146_init_one+0x7d5/0x910 [saa7146] [ 97.234461] [] ? local_pci_probe+0x12/0x20 [ 97.234461] [] ? pci_device_probe+0x110/0x120 [ 97.234461] [] ? driver_probe_device+0x98/0x1b0 [ 97.234461] [] ? __driver_attach+0x93/0xa0 [ 97.234461] [] ? __driver_attach+0x0/0xa0 [ 97.234461] [] ? bus_for_each_dev+0x58/0x80 [ 97.234461] [] ? bus_add_driver+0x14d/0x280 [ 97.234461] [] ? budget_init+0x0/0xc [budget] [ 97.234461] [] ? driver_register+0x79/0x170 [ 97.234461] [] ? budget_init+0x0/0xc [budget] [ 97.234461] [] ? __pci_register_driver+0x58/0xe0 [ 97.234461] [] ? budget_init+0x0/0xc [budget] [ 97.234461] [] ? do_one_initcall+0x35/0x190 [ 97.234461] [] ? sys_init_module+0xe7/0x260 [ 97.234461] [] ? system_call_fastpath+0x16/0x1b [ 97.234461] RIP [] stv6110x_set_mode+0x70/0x80 [stv6110x] [ 97.234461] RSP [ 97.240074] ---[ end trace b53ecbbbbef15e99 ]--- Prevents calling stv6110x_set_mode() if fe->tuner_priv is not defined, in order to avoid the above bug. Signed-off-by: Guy Martin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/stv6110x.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/stv6110x.c b/drivers/media/dvb/frontends/stv6110x.c index 42591ce1aaad..f36cab12bdc7 100644 --- a/drivers/media/dvb/frontends/stv6110x.c +++ b/drivers/media/dvb/frontends/stv6110x.c @@ -303,7 +303,10 @@ static int stv6110x_set_mode(struct dvb_frontend *fe, enum tuner_mode mode) static int stv6110x_sleep(struct dvb_frontend *fe) { - return stv6110x_set_mode(fe, TUNER_SLEEP); + if (fe->tuner_priv) + return stv6110x_set_mode(fe, TUNER_SLEEP); + + return 0; } static int stv6110x_get_status(struct dvb_frontend *fe, u32 *status) -- cgit v1.2.3 From 9e1d9e7bac5c2bafc3c0c51db88c15f3fbcec83f Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Sat, 8 May 2010 02:23:37 -0300 Subject: V4L/DVB: saa7134: add support for Avermedia M733A This change adds support for Avermedia M733A. The original version for linux 2.6.31 was sent to me from Avermedia, original author is unknown. I ported it to current kernels, expanded and fixed key code handling for RM-K6 remote control, and added an additional pci id also supported. [mchehab@redhat.com: make checkpatch.pl happier] Signed-off-by: Herton Ronaldo Krzesinski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/IR/keymaps/Makefile | 1 + .../media/IR/keymaps/rc-avermedia-m733a-rm-k6.c | 95 ++++++++++++++++++++++ drivers/media/video/saa7134/saa7134-cards.c | 55 +++++++++++++ drivers/media/video/saa7134/saa7134-input.c | 7 ++ drivers/media/video/saa7134/saa7134.h | 1 + 5 files changed, 159 insertions(+) create mode 100644 drivers/media/IR/keymaps/rc-avermedia-m733a-rm-k6.c (limited to 'drivers') diff --git a/drivers/media/IR/keymaps/Makefile b/drivers/media/IR/keymaps/Makefile index ec25258a955f..585f75c3f376 100644 --- a/drivers/media/IR/keymaps/Makefile +++ b/drivers/media/IR/keymaps/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-avermedia-cardbus.o \ rc-avermedia-dvbt.o \ rc-avermedia-m135a-rm-jx.o \ + rc-avermedia-m733a-rm-k6.o \ rc-avertv-303.o \ rc-behold.o \ rc-behold-columbus.o \ diff --git a/drivers/media/IR/keymaps/rc-avermedia-m733a-rm-k6.c b/drivers/media/IR/keymaps/rc-avermedia-m733a-rm-k6.c new file mode 100644 index 000000000000..cf8d45717cb3 --- /dev/null +++ b/drivers/media/IR/keymaps/rc-avermedia-m733a-rm-k6.c @@ -0,0 +1,95 @@ +/* avermedia-m733a-rm-k6.h - Keytable for avermedia_m733a_rm_k6 Remote Controller + * + * Copyright (c) 2010 by Herton Ronaldo Krzesinski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include + +/* + * Avermedia M733A with IR model RM-K6 + * This is the stock remote controller used with Positivo machines with M733A + * Herton Ronaldo Krzesinski + */ + +static struct ir_scancode avermedia_m733a_rm_k6[] = { + { 0x0401, KEY_POWER2 }, + { 0x0406, KEY_MUTE }, + { 0x0408, KEY_MODE }, /* TV/FM */ + + { 0x0409, KEY_1 }, + { 0x040a, KEY_2 }, + { 0x040b, KEY_3 }, + { 0x040c, KEY_4 }, + { 0x040d, KEY_5 }, + { 0x040e, KEY_6 }, + { 0x040f, KEY_7 }, + { 0x0410, KEY_8 }, + { 0x0411, KEY_9 }, + { 0x044c, KEY_DOT }, /* '.' */ + { 0x0412, KEY_0 }, + { 0x0407, KEY_REFRESH }, /* Refresh/Reload */ + + { 0x0413, KEY_AUDIO }, + { 0x0440, KEY_SCREEN }, /* Full Screen toggle */ + { 0x0441, KEY_HOME }, + { 0x0442, KEY_BACK }, + { 0x0447, KEY_UP }, + { 0x0448, KEY_DOWN }, + { 0x0449, KEY_LEFT }, + { 0x044a, KEY_RIGHT }, + { 0x044b, KEY_OK }, + { 0x0404, KEY_VOLUMEUP }, + { 0x0405, KEY_VOLUMEDOWN }, + { 0x0402, KEY_CHANNELUP }, + { 0x0403, KEY_CHANNELDOWN }, + + { 0x0443, KEY_RED }, + { 0x0444, KEY_GREEN }, + { 0x0445, KEY_YELLOW }, + { 0x0446, KEY_BLUE }, + + { 0x0414, KEY_TEXT }, + { 0x0415, KEY_EPG }, + { 0x041a, KEY_TV2 }, /* PIP */ + { 0x041b, KEY_MHP }, /* Snapshot */ + + { 0x0417, KEY_RECORD }, + { 0x0416, KEY_PLAYPAUSE }, + { 0x0418, KEY_STOP }, + { 0x0419, KEY_PAUSE }, + + { 0x041f, KEY_PREVIOUS }, + { 0x041c, KEY_REWIND }, + { 0x041d, KEY_FORWARD }, + { 0x041e, KEY_NEXT }, +}; + +static struct rc_keymap avermedia_m733a_rm_k6_map = { + .map = { + .scan = avermedia_m733a_rm_k6, + .size = ARRAY_SIZE(avermedia_m733a_rm_k6), + .ir_type = IR_TYPE_NEC, + .name = RC_MAP_AVERMEDIA_M733A_RM_K6, + } +}; + +static int __init init_rc_map_avermedia_m733a_rm_k6(void) +{ + return ir_register_map(&avermedia_m733a_rm_k6_map); +} + +static void __exit exit_rc_map_avermedia_m733a_rm_k6(void) +{ + ir_unregister_map(&avermedia_m733a_rm_k6_map); +} + +module_init(init_rc_map_avermedia_m733a_rm_k6) +module_exit(exit_rc_map_avermedia_m733a_rm_k6) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 72700d4e3941..07f6bb8ef9d9 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -3897,6 +3897,40 @@ struct saa7134_board saa7134_boards[] = { .gpio = 0x01, }, }, + [SAA7134_BOARD_AVERMEDIA_M733A] = { + .name = "Avermedia PCI M733A", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tuner_config = 0, + .gpiomask = 0x020200000, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + }, { + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + } }, + .radio = { + .name = name_radio, + .amux = TV, + .gpio = 0x00200000, + }, + .mute = { + .name = name_mute, + .amux = TV, + .gpio = 0x01, + }, + }, [SAA7134_BOARD_BEHOLD_401] = { /* Beholder Intl. Ltd. 2008 */ /*Dmitry Belimov */ @@ -5820,6 +5854,18 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x1461, /* Avermedia Technologies Inc */ .subdevice = 0xf11d, .driver_data = SAA7134_BOARD_AVERMEDIA_M135A, + }, { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x1461, /* Avermedia Technologies Inc */ + .subdevice = 0x4155, + .driver_data = SAA7134_BOARD_AVERMEDIA_M733A, + }, { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x1461, /* Avermedia Technologies Inc */ + .subdevice = 0x4255, + .driver_data = SAA7134_BOARD_AVERMEDIA_M733A, }, { .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, @@ -6786,6 +6832,7 @@ static int saa7134_tda8290_callback(struct saa7134_dev *dev, switch (dev->board) { case SAA7134_BOARD_HAUPPAUGE_HVR1150: case SAA7134_BOARD_HAUPPAUGE_HVR1120: + case SAA7134_BOARD_AVERMEDIA_M733A: /* tda8290 + tda18271 */ ret = saa7134_tda8290_18271_callback(dev, command, arg); break; @@ -7087,6 +7134,14 @@ int saa7134_board_init1(struct saa7134_dev *dev) saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x0000C000, 0x0000C000); saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0000C000, 0x0000C000); break; + case SAA7134_BOARD_AVERMEDIA_M733A: + saa7134_set_gpio(dev, 1, 1); + msleep(10); + saa7134_set_gpio(dev, 1, 0); + msleep(10); + saa7134_set_gpio(dev, 1, 1); + dev->has_remote = SAA7134_REMOTE_GPIO; + break; } return 0; } diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index e5565e2fd426..f9ed8048894d 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -663,6 +663,13 @@ int saa7134_input_init1(struct saa7134_dev *dev) mask_keycode = 0xffff; raw_decode = 1; break; + case SAA7134_BOARD_AVERMEDIA_M733A: + ir_codes = RC_MAP_AVERMEDIA_M733A_RM_K6; + mask_keydown = 0x0040000; + mask_keyup = 0x0040000; + mask_keycode = 0xffff; + raw_decode = 1; + break; case SAA7134_BOARD_AVERMEDIA_777: case SAA7134_BOARD_AVERMEDIA_A16AR: ir_codes = RC_MAP_AVERMEDIA; diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 3962534267be..756a1ca8833d 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -303,6 +303,7 @@ struct saa7134_format { #define SAA7134_BOARD_HAWELL_HW_404M7 177 #define SAA7134_BOARD_BEHOLD_H7 178 #define SAA7134_BOARD_BEHOLD_A7 179 +#define SAA7134_BOARD_AVERMEDIA_M733A 180 #define SAA7134_MAXBOARDS 32 #define SAA7134_INPUT_MAX 8 -- cgit v1.2.3 From 0439db75c1fbb28a3b314ae354582e4f180daf52 Mon Sep 17 00:00:00 2001 From: Stefan Ringel Date: Mon, 10 May 2010 13:22:51 -0300 Subject: V4L/DVB: tm6000: add extension module support add module init over tm6000 extension Signed-off-by: Stefan Ringel Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/tm6000/tm6000-alsa.c | 25 +++++++++- drivers/staging/tm6000/tm6000-cards.c | 7 +++ drivers/staging/tm6000/tm6000-core.c | 92 +++++++++++++++++++++++++++++++++++ drivers/staging/tm6000/tm6000.h | 23 ++++++++- 4 files changed, 145 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/tm6000/tm6000-alsa.c b/drivers/staging/tm6000/tm6000-alsa.c index bc89f9d28002..ce081cd44ad4 100644 --- a/drivers/staging/tm6000/tm6000-alsa.c +++ b/drivers/staging/tm6000/tm6000-alsa.c @@ -410,5 +410,28 @@ error: snd_card_free(card); return rc; } -EXPORT_SYMBOL_GPL(tm6000_audio_init); +static int tm6000_audio_fini(struct tm6000_core *dev) +{ + return 0; +} + +struct tm6000_ops audio_ops = { + .id = TM6000_AUDIO, + .name = "TM6000 Audio Extension", + .init = tm6000_audio_init, + .fini = tm6000_audio_fini, +}; + +static int __init tm6000_alsa_register(void) +{ + return tm6000_register_extension(&audio_ops); +} + +static void __exit tm6000_alsa_unregister(void) +{ + tm6000_unregister_extension(&audio_ops); +} + +module_init(tm6000_alsa_register); +module_exit(tm6000_alsa_unregister); diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c index 6143e20d139d..ab12291e0b42 100644 --- a/drivers/staging/tm6000/tm6000-cards.c +++ b/drivers/staging/tm6000/tm6000-cards.c @@ -692,6 +692,10 @@ static int tm6000_init_dev(struct tm6000_core *dev) if (rc < 0) goto err; + tm6000_add_into_devlist(dev); + + tm6000_init_extension(dev); + if (dev->caps.has_dvb) { dev->dvb = kzalloc(sizeof(*(dev->dvb)), GFP_KERNEL); if (!dev->dvb) { @@ -931,6 +935,9 @@ static void tm6000_usb_disconnect(struct usb_interface *interface) usb_put_dev(dev->udev); + tm6000_remove_from_devlist(dev); + tm6000_close_extension(dev); + mutex_unlock(&dev->lock); kfree(dev); } diff --git a/drivers/staging/tm6000/tm6000-core.c b/drivers/staging/tm6000/tm6000-core.c index bfbc53bd2912..1259ae550547 100644 --- a/drivers/staging/tm6000/tm6000-core.c +++ b/drivers/staging/tm6000/tm6000-core.c @@ -600,3 +600,95 @@ printk("Original value=%d\n",val); return val; } EXPORT_SYMBOL_GPL(tm6000_set_audio_bitrate); + +static LIST_HEAD(tm6000_devlist); +static DEFINE_MUTEX(tm6000_devlist_mutex); + +/* + * tm6000_realease_resource() + */ + +void tm6000_remove_from_devlist(struct tm6000_core *dev) +{ + mutex_lock(&tm6000_devlist_mutex); + list_del(&dev->devlist); + mutex_unlock(&tm6000_devlist_mutex); +}; + +void tm6000_add_into_devlist(struct tm6000_core *dev) +{ + mutex_lock(&tm6000_devlist_mutex); + list_add_tail(&dev->devlist, &tm6000_devlist); + mutex_unlock(&tm6000_devlist_mutex); +}; + +/* + * Extension interface + */ + +static LIST_HEAD(tm6000_extension_devlist); +static DEFINE_MUTEX(tm6000_extension_devlist_lock); + +int tm6000_register_extension(struct tm6000_ops *ops) +{ + struct tm6000_core *dev = NULL; + + mutex_lock(&tm6000_devlist_mutex); + mutex_lock(&tm6000_extension_devlist_lock); + list_add_tail(&ops->next, &tm6000_extension_devlist); + list_for_each_entry(dev, &tm6000_devlist, devlist) { + if (dev) + ops->init(dev); + } + printk(KERN_INFO "tm6000: Initialized (%s) extension\n", ops->name); + mutex_unlock(&tm6000_extension_devlist_lock); + mutex_unlock(&tm6000_devlist_mutex); + return 0; +} +EXPORT_SYMBOL(tm6000_register_extension); + +void tm6000_unregister_extension(struct tm6000_ops *ops) +{ + struct tm6000_core *dev = NULL; + + mutex_lock(&tm6000_devlist_mutex); + list_for_each_entry(dev, &tm6000_devlist, devlist) { + if (dev) + ops->fini(dev); + } + + mutex_lock(&tm6000_extension_devlist_lock); + printk(KERN_INFO "tm6000: Remove (%s) extension\n", ops->name); + list_del(&ops->next); + mutex_unlock(&tm6000_extension_devlist_lock); + mutex_unlock(&tm6000_devlist_mutex); +} +EXPORT_SYMBOL(tm6000_unregister_extension); + +void tm6000_init_extension(struct tm6000_core *dev) +{ + struct tm6000_ops *ops = NULL; + + mutex_lock(&tm6000_extension_devlist_lock); + if (!list_empty(&tm6000_extension_devlist)) { + list_for_each_entry(ops, &tm6000_extension_devlist, next) { + if (ops->init) + ops->init(dev); + } + } + mutex_unlock(&tm6000_extension_devlist_lock); +} + +void tm6000_close_extension(struct tm6000_core *dev) +{ + struct tm6000_ops *ops = NULL; + + mutex_lock(&tm6000_extension_devlist_lock); + if (!list_empty(&tm6000_extension_devlist)) { + list_for_each_entry(ops, &tm6000_extension_devlist, next) { + if (ops->fini) + ops->fini(dev); + } + } + mutex_unlock(&tm6000_extension_devlist_lock); +} diff --git a/drivers/staging/tm6000/tm6000.h b/drivers/staging/tm6000/tm6000.h index 6812d6867d57..79ef72a3f431 100644 --- a/drivers/staging/tm6000/tm6000.h +++ b/drivers/staging/tm6000/tm6000.h @@ -168,6 +168,10 @@ struct tm6000_core { struct i2c_adapter i2c_adap; struct i2c_client i2c_client; + + /* extension */ + struct list_head devlist; + /* video for linux */ int users; @@ -203,6 +207,16 @@ struct tm6000_core { spinlock_t slock; }; +#define TM6000_AUDIO 0x10 + +struct tm6000_ops { + struct list_head next; + char *name; + int id; + int (*init)(struct tm6000_core *); + int (*fini)(struct tm6000_core *); +}; + struct tm6000_fh { struct tm6000_core *dev; @@ -246,6 +260,13 @@ int tm6000_v4l2_unregister(struct tm6000_core *dev); int tm6000_v4l2_exit(void); void tm6000_set_fourcc_format(struct tm6000_core *dev); +void tm6000_remove_from_devlist(struct tm6000_core *dev); +void tm6000_add_into_devlist(struct tm6000_core *dev); +int tm6000_register_extension(struct tm6000_ops *ops); +void tm6000_unregister_extension(struct tm6000_ops *ops); +void tm6000_init_extension(struct tm6000_core *dev); +void tm6000_close_extension(struct tm6000_core *dev); + /* In tm6000-stds.c */ void tm6000_get_std_res(struct tm6000_core *dev); int tm6000_set_standard (struct tm6000_core *dev, v4l2_std_id *norm); @@ -275,7 +296,7 @@ unsigned int tm6000_v4l2_poll(struct file *file, int tm6000_queue_init(struct tm6000_core *dev); /* In tm6000-alsa.c */ -int tm6000_audio_init(struct tm6000_core *dev, int idx); +/*int tm6000_audio_init(struct tm6000_core *dev, int idx);*/ /* Debug stuff */ -- cgit v1.2.3 From b9eb39d8f419d76e1d59febe48a6791f1fbb68c4 Mon Sep 17 00:00:00 2001 From: Stefan Ringel Date: Mon, 10 May 2010 13:22:50 -0300 Subject: V4L/DVB: tm6000: Remove an extra ; symbol Signed-off-by: Stefan Ringel Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/tm6000/tm6000-cards.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c index ab12291e0b42..33b134b521be 100644 --- a/drivers/staging/tm6000/tm6000-cards.c +++ b/drivers/staging/tm6000/tm6000-cards.c @@ -563,7 +563,7 @@ static void tm6000_config_tuner(struct tm6000_core *dev) switch (dev->tuner_type) { case TUNER_XC2028: - tun_setup.tuner_callback = tm6000_tuner_callback;; + tun_setup.tuner_callback = tm6000_tuner_callback; break; case TUNER_XC5000: tun_setup.tuner_callback = tm6000_xc5000_callback; -- cgit v1.2.3 From 2a15ac7ad625dc22885446016d730a451df1b7d4 Mon Sep 17 00:00:00 2001 From: Dmitri Belimov Date: Tue, 18 May 2010 04:23:29 -0300 Subject: V4L/DVB: tm6000, reset I2C bus function Add new function for reset I2C bus. Rework some code for use this function. Signed-off-by: Beholder Intl. Ltd. Dmitry Belimov Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/tm6000/tm6000-cards.c | 17 ++--------------- drivers/staging/tm6000/tm6000-core.c | 16 ++++++++++++++++ drivers/staging/tm6000/tm6000.h | 2 ++ 3 files changed, 20 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c index 33b134b521be..22fbd75a551d 100644 --- a/drivers/staging/tm6000/tm6000-cards.c +++ b/drivers/staging/tm6000/tm6000-cards.c @@ -363,13 +363,7 @@ int tm6000_tuner_callback(void *ptr, int component, int command, int arg) tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x02, arg); msleep(10); - rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - TM6000_GPIO_CLK, 0); - if (rc < 0) - return rc; - msleep(10); - rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - TM6000_GPIO_CLK, 1); + rc = tm6000_i2c_reset(dev, 10); break; case XC2028_TUNER_RESET: /* Reset codes during load firmware */ @@ -423,14 +417,7 @@ int tm6000_tuner_callback(void *ptr, int component, int command, int arg) break; case 2: - rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - TM6000_GPIO_CLK, 0); - if (rc < 0) - return rc; - msleep(100); - rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - TM6000_GPIO_CLK, 1); - msleep(100); + rc = tm6000_i2c_reset(dev, 100); break; } } diff --git a/drivers/staging/tm6000/tm6000-core.c b/drivers/staging/tm6000/tm6000-core.c index 1259ae550547..65feb8cb421c 100644 --- a/drivers/staging/tm6000/tm6000-core.c +++ b/drivers/staging/tm6000/tm6000-core.c @@ -153,6 +153,22 @@ int tm6000_get_reg32 (struct tm6000_core *dev, u8 req, u16 value, u16 index) return buf[3] | buf[2] << 8 | buf[1] << 16 | buf[0] << 24; } +int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep) +{ + int rc; + + rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_CLK, 0); + if (rc < 0) + return rc; + + msleep(tsleep); + + rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_CLK, 1); + msleep(tsleep); + + return rc; +} + void tm6000_set_fourcc_format(struct tm6000_core *dev) { if (dev->dev_type == TM6010) { diff --git a/drivers/staging/tm6000/tm6000.h b/drivers/staging/tm6000/tm6000.h index 79ef72a3f431..7bbaf26dea14 100644 --- a/drivers/staging/tm6000/tm6000.h +++ b/drivers/staging/tm6000/tm6000.h @@ -246,6 +246,8 @@ int tm6000_get_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index); int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index); int tm6000_get_reg32(struct tm6000_core *dev, u8 req, u16 value, u16 index); int tm6000_set_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index); +int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep); + int tm6000_init (struct tm6000_core *dev); int tm6000_init_analog_mode (struct tm6000_core *dev); -- cgit v1.2.3 From 0f9bdbc2da442a78990579cabc1554446ed784a7 Mon Sep 17 00:00:00 2001 From: Stefan Ringel Date: Wed, 19 May 2010 13:58:24 -0300 Subject: V4L/DVB: tm6000: bugfix incorrect size Signed-off-by: Stefan Ringel Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/tm6000/tm6000-video.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/tm6000/tm6000-video.c b/drivers/staging/tm6000/tm6000-video.c index f2b7fe4a3581..2adf3cc972d3 100644 --- a/drivers/staging/tm6000/tm6000-video.c +++ b/drivers/staging/tm6000/tm6000-video.c @@ -205,7 +205,11 @@ static int copy_packet(struct urb *urb, u32 header, u8 **ptr, u8 *endp, c = (header >> 24) & 0xff; /* split the header fields */ - size = (((header & 0x7e) << 1) -1) *4; + size = ((header & 0x7e) << 1); + + if (size > 0) + size -= 4; + block = (header >> 7) & 0xf; field = (header >> 11) & 0x1; line = (header >> 12) & 0x1ff; -- cgit v1.2.3 From 3569417e5a2c20764158961a2f6c514d26136e5f Mon Sep 17 00:00:00 2001 From: Stefan Ringel Date: Wed, 19 May 2010 13:58:25 -0300 Subject: V4L/DVB: tm6000: add vbi message inside the type switch add case line for vbi message Signed-off-by: Stefan Ringel Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/tm6000/tm6000-video.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/tm6000/tm6000-video.c b/drivers/staging/tm6000/tm6000-video.c index 2adf3cc972d3..02b88b550a47 100644 --- a/drivers/staging/tm6000/tm6000-video.c +++ b/drivers/staging/tm6000/tm6000-video.c @@ -311,10 +311,12 @@ static int copy_packet(struct urb *urb, u32 header, u8 **ptr, u8 *endp, case TM6000_URB_MSG_PTS: break; case TM6000_URB_MSG_AUDIO: -/* Need some code to process audio */ -printk ("%ld: cmd=%s, size=%d\n", jiffies, + /* Need some code to process audio */ + printk ("%ld: cmd=%s, size=%d\n", jiffies, tm6000_msg_type[cmd],size); break; + case TM6000_URB_MSG_VBI: + break; default: dprintk (dev, V4L2_DEBUG_ISOC, "cmd=%s, size=%d\n", tm6000_msg_type[cmd],size); -- cgit v1.2.3 From 4b6ed9fd0baf34da6912bebee46c36eda0411984 Mon Sep 17 00:00:00 2001 From: Stefan Ringel Date: Wed, 19 May 2010 13:58:26 -0300 Subject: V4L/DVB: tm6000: bugfix video image bugfix: Avoid loosing frames, causing image delays on some of the image lines. [mchehab@redhat.com: Fix compilation breakage by merging with the patch fix] Signed-off-by: Stefan Ringel Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/tm6000/tm6000-video.c | 88 ++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/tm6000/tm6000-video.c b/drivers/staging/tm6000/tm6000-video.c index 02b88b550a47..8acfebdb5cda 100644 --- a/drivers/staging/tm6000/tm6000-video.c +++ b/drivers/staging/tm6000/tm6000-video.c @@ -339,14 +339,23 @@ static int copy_packet(struct urb *urb, u32 header, u8 **ptr, u8 *endp, return rc; } -static int copy_streams(u8 *data, u8 *out_p, unsigned long len, - struct urb *urb, struct tm6000_buffer **buf) +static int copy_streams(u8 *data, unsigned long len, + struct urb *urb) { struct tm6000_dmaqueue *dma_q = urb->context; struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq); u8 *ptr=data, *endp=data+len; unsigned long header=0; int rc=0; + struct tm6000_buffer *buf; + char *outp = NULL; + + get_next_buf(dma_q, &buf); + if (buf) + outp = videobuf_to_vmalloc(&buf->vb); + + if (!outp) + return 0; for (ptr=data; ptrisoc_ctl.cmd) { @@ -394,14 +403,14 @@ static int copy_streams(u8 *data, u8 *out_p, unsigned long len, } HEADER: /* Copy or continue last copy */ - rc=copy_packet(urb,header,&ptr,endp,out_p,buf); + rc=copy_packet(urb,header,&ptr,endp,outp,&buf); if (rc<0) { buf=NULL; printk(KERN_ERR "tm6000: buffer underrun at %ld\n", jiffies); return rc; } - if (!*buf) + if (!buf) return 0; } @@ -410,31 +419,40 @@ HEADER: /* * Identify the tm5600/6000 buffer header type and properly handles */ -static int copy_multiplexed(u8 *ptr, u8 *out_p, unsigned long len, - struct urb *urb, struct tm6000_buffer **buf) +static int copy_multiplexed(u8 *ptr, unsigned long len, + struct urb *urb) { struct tm6000_dmaqueue *dma_q = urb->context; struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq); unsigned int pos=dev->isoc_ctl.pos,cpysize; int rc=1; + struct tm6000_buffer *buf; + char *outp = NULL; + + get_next_buf(dma_q, &buf); + if (buf) + outp = videobuf_to_vmalloc(&buf->vb); + + if (!outp) + return 0; while (len>0) { - cpysize=min(len,(*buf)->vb.size-pos); -//printk("Copying %d bytes (max=%lu) from %p to %p[%u]\n",cpysize,(*buf)->vb.size,ptr,out_p,pos); - memcpy(&out_p[pos], ptr, cpysize); + cpysize=min(len,buf->vb.size-pos); + //printk("Copying %d bytes (max=%lu) from %p to %p[%u]\n",cpysize,(*buf)->vb.size,ptr,out_p,pos); + memcpy(&outp[pos], ptr, cpysize); pos+=cpysize; ptr+=cpysize; len-=cpysize; - if (pos >= (*buf)->vb.size) { + if (pos >= buf->vb.size) { pos=0; /* Announces that a new buffer were filled */ - buffer_filled (dev, dma_q, *buf); + buffer_filled (dev, dma_q, buf); dprintk(dev, V4L2_DEBUG_ISOC, "new buffer filled\n"); - get_next_buf (dma_q, buf); - if (!*buf) + get_next_buf (dma_q, &buf); + if (!buf) break; - out_p = videobuf_to_vmalloc(&((*buf)->vb)); - if (!out_p) + outp = videobuf_to_vmalloc(&(buf->vb)); + if (!outp) return rc; pos = 0; } @@ -493,52 +511,36 @@ static inline int tm6000_isoc_copy(struct urb *urb) struct tm6000_dmaqueue *dma_q = urb->context; struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq); struct tm6000_buffer *buf; - int i, len=0, rc=1; - int size; - char *outp = NULL, *p; - unsigned long copied; + int i, len=0, rc=1, status; + char *p; - get_next_buf(dma_q, &buf); - if (buf) - outp = videobuf_to_vmalloc(&buf->vb); - - if (!outp) - return 0; - - size = buf->vb.size; - - copied=0; - - if (urb->status<0) { - print_err_status (dev,-1,urb->status); + if (urb->status < 0) { + print_err_status (dev, -1, urb->status); return 0; } for (i = 0; i < urb->number_of_packets; i++) { - int status = urb->iso_frame_desc[i].status; + status = urb->iso_frame_desc[i].status; if (status<0) { print_err_status (dev,i,status); continue; } - len=urb->iso_frame_desc[i].actual_length; + len = urb->iso_frame_desc[i].actual_length; -// if (len>=TM6000_URB_MSG_LEN) { - p=urb->transfer_buffer + urb->iso_frame_desc[i].offset; + if (len > 0) { + p = urb->transfer_buffer + urb->iso_frame_desc[i].offset; if (!urb->iso_frame_desc[i].status) { - if ((buf->fmt->fourcc)==V4L2_PIX_FMT_TM6000) { - rc=copy_multiplexed(p, outp, len, urb, &buf); + if ((dev->fourcc)==V4L2_PIX_FMT_TM6000) { + rc=copy_multiplexed(p, len, urb); if (rc<=0) return rc; } else { - copy_streams(p, outp, len, urb, &buf); + copy_streams(p, len, urb); } } - copied += len; - if (copied >= size || !buf) - break; -// } + } } return rc; } -- cgit v1.2.3 From 5a4b55e2c256d78fd86679ee00777c393c87c94a Mon Sep 17 00:00:00 2001 From: Stefan Ringel Date: Wed, 19 May 2010 13:58:27 -0300 Subject: V4L/DVB: tm6000: bugfix stabilizing urb data Signed-off-by: Stefan Ringel Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/tm6000/tm6000-video.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/tm6000/tm6000-video.c b/drivers/staging/tm6000/tm6000-video.c index 8acfebdb5cda..56fa371e08c8 100644 --- a/drivers/staging/tm6000/tm6000-video.c +++ b/drivers/staging/tm6000/tm6000-video.c @@ -48,7 +48,7 @@ #define TM6000_MIN_BUF 4 #define TM6000_DEF_BUF 8 -#define TM6000_MAX_ISO_PACKETS 40 /* Max number of ISO packets */ +#define TM6000_MAX_ISO_PACKETS 46 /* Max number of ISO packets */ /* Declare static vars that will be used as parameters */ static unsigned int vid_limit = 16; /* Video memory limit, in Mb */ @@ -620,7 +620,7 @@ static void tm6000_uninit_isoc(struct tm6000_core *dev) static int tm6000_prepare_isoc(struct tm6000_core *dev, unsigned int framesize) { struct tm6000_dmaqueue *dma_q = &dev->vidq; - int i, j, sb_size, pipe, size, max_packets, num_bufs = 5; + int i, j, sb_size, pipe, size, max_packets, num_bufs = 8; struct urb *urb; /* De-allocates all pending stuff */ -- cgit v1.2.3 From f36cc0342df21fc6820b53cdfba3e98ee5943f46 Mon Sep 17 00:00:00 2001 From: Stefan Ringel Date: Sun, 23 May 2010 15:29:25 -0300 Subject: V4L/DVB: tm6000: Add control to the power led Turn power led off, if device is disconnected Signed-off-by: Stefan Ringel Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/tm6000/tm6000-cards.c | 19 +++++++++++++++++++ drivers/staging/tm6000/tm6000-core.c | 13 +++++++++++++ 2 files changed, 32 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c index 22fbd75a551d..cedd9044022f 100644 --- a/drivers/staging/tm6000/tm6000-cards.c +++ b/drivers/staging/tm6000/tm6000-cards.c @@ -912,6 +912,25 @@ static void tm6000_usb_disconnect(struct usb_interface *interface) } #endif + if (dev->gpio.power_led) { + switch (dev->model) { + case TM6010_BOARD_HAUPPAUGE_900H: + case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: + case TM6010_BOARD_TWINHAN_TU501: + /* Power led off */ + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + dev->gpio.power_led, 0x01); + msleep(15); + break; + case TM6010_BOARD_BEHOLD_WANDER: + case TM6010_BOARD_BEHOLD_VOYAGER: + /* Power led off */ + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + dev->gpio.power_led, 0x00); + msleep(15); + break; + } + } tm6000_v4l2_unregister(dev); tm6000_i2c_unregister(dev); diff --git a/drivers/staging/tm6000/tm6000-core.c b/drivers/staging/tm6000/tm6000-core.c index 65feb8cb421c..27f3f551b545 100644 --- a/drivers/staging/tm6000/tm6000-core.c +++ b/drivers/staging/tm6000/tm6000-core.c @@ -339,6 +339,12 @@ int tm6000_init_analog_mode (struct tm6000_core *dev) tm6000_set_standard (dev, &dev->norm); tm6000_set_audio_bitrate (dev,48000); + /* switch dvb led off */ + if (dev->gpio.dvb_led) { + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + dev->gpio.dvb_led, 0x01); + } + return 0; } @@ -391,6 +397,13 @@ int tm6000_init_digital_mode (struct tm6000_core *dev) tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00); msleep(100); } + + /* switch dvb led on */ + if (dev->gpio.dvb_led) { + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + dev->gpio.dvb_led, 0x00); + } + return 0; } -- cgit v1.2.3 From 71d67f739e0b02995c2eb650448f031b76720307 Mon Sep 17 00:00:00 2001 From: Stefan Ringel Date: Sun, 23 May 2010 15:29:24 -0300 Subject: V4L/DVB: tm6000: Properly select the tuners Signed-off-by: Stefan Ringel Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/tm6000/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/tm6000/Kconfig b/drivers/staging/tm6000/Kconfig index 5fe759cc2ee9..3657e33e8817 100644 --- a/drivers/staging/tm6000/Kconfig +++ b/drivers/staging/tm6000/Kconfig @@ -2,7 +2,8 @@ config VIDEO_TM6000 tristate "TV Master TM5600/6000/6010 driver" depends on VIDEO_DEV && I2C && INPUT && USB && EXPERIMENTAL select VIDEO_TUNER - select TUNER_XC2028 + select MEDIA_TUNER_XC2028 + select MEDIA_TUNER_XC5000 select VIDEOBUF_VMALLOC help Support for TM5600/TM6000/TM6010 USB Device -- cgit v1.2.3 From dcf5d3aa081617a4a8aa56b7e24988d600148f50 Mon Sep 17 00:00:00 2001 From: Stefan Ringel Date: Sun, 23 May 2010 15:29:26 -0300 Subject: V4L/DVB: tm6000: set variable dev_mode in function tm6000_start_stream set variable dev_mode in function tm6000_start_stream and check mode Signed-off-by: Stefan Ringel Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/tm6000/tm6000-dvb.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/tm6000/tm6000-dvb.c b/drivers/staging/tm6000/tm6000-dvb.c index eafc89c22b6b..e6a802e9c48a 100644 --- a/drivers/staging/tm6000/tm6000-dvb.c +++ b/drivers/staging/tm6000/tm6000-dvb.c @@ -100,7 +100,10 @@ int tm6000_start_stream(struct tm6000_core *dev) printk(KERN_INFO "tm6000: got start stream request %s\n",__FUNCTION__); - tm6000_init_digital_mode(dev); + if (dev->mode != TM6000_MODE_DIGITAL) { + tm6000_init_digital_mode(dev); + dev->mode = TM6000_MODE_DIGITAL; + } dvb->bulk_urb = usb_alloc_urb(0, GFP_KERNEL); if(dvb->bulk_urb == NULL) { -- cgit v1.2.3 From 7e2d9820c37525da2469147eec897488ec141bcf Mon Sep 17 00:00:00 2001 From: Stefan Ringel Date: Sun, 23 May 2010 15:31:44 -0300 Subject: V4L/DVB: tm6000: add DVB support for tuner xc5000 [mchehab@redhat.com: Fix compilation breakage due to duplicate cfg config delaration without {}] Signed-off-by: Stefan Ringel Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/tm6000/tm6000-dvb.c | 69 ++++++++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/tm6000/tm6000-dvb.c b/drivers/staging/tm6000/tm6000-dvb.c index e6a802e9c48a..261e66acbe46 100644 --- a/drivers/staging/tm6000/tm6000-dvb.c +++ b/drivers/staging/tm6000/tm6000-dvb.c @@ -28,6 +28,7 @@ #include #include "tuner-xc2028.h" +#include "xc5000.h" static void inline print_err_status (struct tm6000_core *dev, int packet, int status) @@ -257,27 +258,55 @@ int tm6000_dvb_register(struct tm6000_core *dev) dvb->adapter.priv = dev; if (dvb->frontend) { - struct xc2028_config cfg = { - .i2c_adap = &dev->i2c_adap, - .i2c_addr = dev->tuner_addr, - }; - - dvb->frontend->callback = tm6000_tuner_callback; - ret = dvb_register_frontend(&dvb->adapter, dvb->frontend); - if (ret < 0) { - printk(KERN_ERR - "tm6000: couldn't register frontend\n"); - goto adapter_err; + switch (dev->tuner_type) { + case TUNER_XC2028: { + struct xc2028_config cfg = { + .i2c_adap = &dev->i2c_adap, + .i2c_addr = dev->tuner_addr, + }; + + dvb->frontend->callback = tm6000_tuner_callback; + ret = dvb_register_frontend(&dvb->adapter, dvb->frontend); + if (ret < 0) { + printk(KERN_ERR + "tm6000: couldn't register frontend\n"); + goto adapter_err; + } + + if (!dvb_attach(xc2028_attach, dvb->frontend, &cfg)) { + printk(KERN_ERR "tm6000: couldn't register " + "frontend (xc3028)\n"); + ret = -EINVAL; + goto frontend_err; + } + printk(KERN_INFO "tm6000: XC2028/3028 asked to be " + "attached to frontend!\n"); + break; + } + case TUNER_XC5000: { + struct xc5000_config cfg = { + .i2c_address = dev->tuner_addr, + }; + + dvb->frontend->callback = tm6000_xc5000_callback; + ret = dvb_register_frontend(&dvb->adapter, dvb->frontend); + if (ret < 0) { + printk(KERN_ERR + "tm6000: couldn't register frontend\n"); + goto adapter_err; + } + + if (!dvb_attach(xc5000_attach, dvb->frontend, &dev->i2c_adap, &cfg)) { + printk(KERN_ERR "tm6000: couldn't register " + "frontend (xc5000)\n"); + ret = -EINVAL; + goto frontend_err; + } + printk(KERN_INFO "tm6000: XC5000 asked to be " + "attached to frontend!\n"); + break; + } } - - if (!dvb_attach(xc2028_attach, dvb->frontend, &cfg)) { - printk(KERN_ERR "tm6000: couldn't register " - "frontend (xc3028)\n"); - ret = -EINVAL; - goto frontend_err; - } - printk(KERN_INFO "tm6000: XC2028/3028 asked to be " - "attached to frontend!\n"); } else { printk(KERN_ERR "tm6000: no frontend found\n"); } -- cgit v1.2.3 From 63fc31e8d0757574edb03ed73986be56e70a75c1 Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Mon, 10 May 2010 15:43:31 -0300 Subject: V4L/DVB: saa7134: add RM-K6 remote control support for Avermedia M135A This change adds support for one more remote control type for Avermedia M135A (model RM-K6), shipped with Positivo machines. Signed-off-by: Herton Ronaldo Krzesinski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/IR/keymaps/Makefile | 2 +- .../media/IR/keymaps/rc-avermedia-m135a-rm-jx.c | 90 ------------- drivers/media/IR/keymaps/rc-avermedia-m135a.c | 147 +++++++++++++++++++++ drivers/media/video/saa7134/saa7134-input.c | 2 +- 4 files changed, 149 insertions(+), 92 deletions(-) delete mode 100644 drivers/media/IR/keymaps/rc-avermedia-m135a-rm-jx.c create mode 100644 drivers/media/IR/keymaps/rc-avermedia-m135a.c (limited to 'drivers') diff --git a/drivers/media/IR/keymaps/Makefile b/drivers/media/IR/keymaps/Makefile index 585f75c3f376..aea649fbcf5a 100644 --- a/drivers/media/IR/keymaps/Makefile +++ b/drivers/media/IR/keymaps/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-avermedia.o \ rc-avermedia-cardbus.o \ rc-avermedia-dvbt.o \ - rc-avermedia-m135a-rm-jx.o \ + rc-avermedia-m135a.o \ rc-avermedia-m733a-rm-k6.o \ rc-avertv-303.o \ rc-behold.o \ diff --git a/drivers/media/IR/keymaps/rc-avermedia-m135a-rm-jx.c b/drivers/media/IR/keymaps/rc-avermedia-m135a-rm-jx.c deleted file mode 100644 index 101e7ea85941..000000000000 --- a/drivers/media/IR/keymaps/rc-avermedia-m135a-rm-jx.c +++ /dev/null @@ -1,90 +0,0 @@ -/* avermedia-m135a-rm-jx.h - Keytable for avermedia_m135a_rm_jx Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include - -/* - * Avermedia M135A with IR model RM-JX - * The same codes exist on both Positivo (BR) and original IR - * Mauro Carvalho Chehab - */ - -static struct ir_scancode avermedia_m135a_rm_jx[] = { - { 0x0200, KEY_POWER2 }, - { 0x022e, KEY_DOT }, /* '.' */ - { 0x0201, KEY_MODE }, /* TV/FM or SOURCE */ - - { 0x0205, KEY_1 }, - { 0x0206, KEY_2 }, - { 0x0207, KEY_3 }, - { 0x0209, KEY_4 }, - { 0x020a, KEY_5 }, - { 0x020b, KEY_6 }, - { 0x020d, KEY_7 }, - { 0x020e, KEY_8 }, - { 0x020f, KEY_9 }, - { 0x0211, KEY_0 }, - - { 0x0213, KEY_RIGHT }, /* -> or L */ - { 0x0212, KEY_LEFT }, /* <- or R */ - - { 0x0217, KEY_SLEEP }, /* Capturar Imagem or Snapshot */ - { 0x0210, KEY_SHUFFLE }, /* Amostra or 16 chan prev */ - - { 0x0303, KEY_CHANNELUP }, - { 0x0302, KEY_CHANNELDOWN }, - { 0x021f, KEY_VOLUMEUP }, - { 0x021e, KEY_VOLUMEDOWN }, - { 0x020c, KEY_ENTER }, /* Full Screen */ - - { 0x0214, KEY_MUTE }, - { 0x0208, KEY_AUDIO }, - - { 0x0203, KEY_TEXT }, /* Teletext */ - { 0x0204, KEY_EPG }, - { 0x022b, KEY_TV2 }, /* TV2 or PIP */ - - { 0x021d, KEY_RED }, - { 0x021c, KEY_YELLOW }, - { 0x0301, KEY_GREEN }, - { 0x0300, KEY_BLUE }, - - { 0x021a, KEY_PLAYPAUSE }, - { 0x0219, KEY_RECORD }, - { 0x0218, KEY_PLAY }, - { 0x021b, KEY_STOP }, -}; - -static struct rc_keymap avermedia_m135a_rm_jx_map = { - .map = { - .scan = avermedia_m135a_rm_jx, - .size = ARRAY_SIZE(avermedia_m135a_rm_jx), - .ir_type = IR_TYPE_NEC, - .name = RC_MAP_AVERMEDIA_M135A_RM_JX, - } -}; - -static int __init init_rc_map_avermedia_m135a_rm_jx(void) -{ - return ir_register_map(&avermedia_m135a_rm_jx_map); -} - -static void __exit exit_rc_map_avermedia_m135a_rm_jx(void) -{ - ir_unregister_map(&avermedia_m135a_rm_jx_map); -} - -module_init(init_rc_map_avermedia_m135a_rm_jx) -module_exit(exit_rc_map_avermedia_m135a_rm_jx) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff --git a/drivers/media/IR/keymaps/rc-avermedia-m135a.c b/drivers/media/IR/keymaps/rc-avermedia-m135a.c new file mode 100644 index 000000000000..e4471fb2ad1e --- /dev/null +++ b/drivers/media/IR/keymaps/rc-avermedia-m135a.c @@ -0,0 +1,147 @@ +/* avermedia-m135a.c - Keytable for Avermedia M135A Remote Controllers + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Herton Ronaldo Krzesinski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include + +/* + * Avermedia M135A with RM-JX and RM-K6 remote controls + * + * On Avermedia M135A with IR model RM-JX, the same codes exist on both + * Positivo (BR) and original IR, initial version and remote control codes + * added by Mauro Carvalho Chehab + * + * Positivo also ships Avermedia M135A with model RM-K6, extra control + * codes added by Herton Ronaldo Krzesinski + */ + +static struct ir_scancode avermedia_m135a[] = { + /* RM-JX */ + { 0x0200, KEY_POWER2 }, + { 0x022e, KEY_DOT }, /* '.' */ + { 0x0201, KEY_MODE }, /* TV/FM or SOURCE */ + + { 0x0205, KEY_1 }, + { 0x0206, KEY_2 }, + { 0x0207, KEY_3 }, + { 0x0209, KEY_4 }, + { 0x020a, KEY_5 }, + { 0x020b, KEY_6 }, + { 0x020d, KEY_7 }, + { 0x020e, KEY_8 }, + { 0x020f, KEY_9 }, + { 0x0211, KEY_0 }, + + { 0x0213, KEY_RIGHT }, /* -> or L */ + { 0x0212, KEY_LEFT }, /* <- or R */ + + { 0x0217, KEY_SLEEP }, /* Capturar Imagem or Snapshot */ + { 0x0210, KEY_SHUFFLE }, /* Amostra or 16 chan prev */ + + { 0x0303, KEY_CHANNELUP }, + { 0x0302, KEY_CHANNELDOWN }, + { 0x021f, KEY_VOLUMEUP }, + { 0x021e, KEY_VOLUMEDOWN }, + { 0x020c, KEY_ENTER }, /* Full Screen */ + + { 0x0214, KEY_MUTE }, + { 0x0208, KEY_AUDIO }, + + { 0x0203, KEY_TEXT }, /* Teletext */ + { 0x0204, KEY_EPG }, + { 0x022b, KEY_TV2 }, /* TV2 or PIP */ + + { 0x021d, KEY_RED }, + { 0x021c, KEY_YELLOW }, + { 0x0301, KEY_GREEN }, + { 0x0300, KEY_BLUE }, + + { 0x021a, KEY_PLAYPAUSE }, + { 0x0219, KEY_RECORD }, + { 0x0218, KEY_PLAY }, + { 0x021b, KEY_STOP }, + + /* RM-K6 */ + { 0x0401, KEY_POWER2 }, + { 0x0406, KEY_MUTE }, + { 0x0408, KEY_MODE }, /* TV/FM */ + + { 0x0409, KEY_1 }, + { 0x040a, KEY_2 }, + { 0x040b, KEY_3 }, + { 0x040c, KEY_4 }, + { 0x040d, KEY_5 }, + { 0x040e, KEY_6 }, + { 0x040f, KEY_7 }, + { 0x0410, KEY_8 }, + { 0x0411, KEY_9 }, + { 0x044c, KEY_DOT }, /* '.' */ + { 0x0412, KEY_0 }, + { 0x0407, KEY_REFRESH }, /* Refresh/Reload */ + + { 0x0413, KEY_AUDIO }, + { 0x0440, KEY_SCREEN }, /* Full Screen toggle */ + { 0x0441, KEY_HOME }, + { 0x0442, KEY_BACK }, + { 0x0447, KEY_UP }, + { 0x0448, KEY_DOWN }, + { 0x0449, KEY_LEFT }, + { 0x044a, KEY_RIGHT }, + { 0x044b, KEY_OK }, + { 0x0404, KEY_VOLUMEUP }, + { 0x0405, KEY_VOLUMEDOWN }, + { 0x0402, KEY_CHANNELUP }, + { 0x0403, KEY_CHANNELDOWN }, + + { 0x0443, KEY_RED }, + { 0x0444, KEY_GREEN }, + { 0x0445, KEY_YELLOW }, + { 0x0446, KEY_BLUE }, + + { 0x0414, KEY_TEXT }, + { 0x0415, KEY_EPG }, + { 0x041a, KEY_TV2 }, /* PIP */ + { 0x041b, KEY_MHP }, /* Snapshot */ + + { 0x0417, KEY_RECORD }, + { 0x0416, KEY_PLAYPAUSE }, + { 0x0418, KEY_STOP }, + { 0x0419, KEY_PAUSE }, + + { 0x041f, KEY_PREVIOUS }, + { 0x041c, KEY_REWIND }, + { 0x041d, KEY_FORWARD }, + { 0x041e, KEY_NEXT }, +}; + +static struct rc_keymap avermedia_m135a_map = { + .map = { + .scan = avermedia_m135a, + .size = ARRAY_SIZE(avermedia_m135a), + .ir_type = IR_TYPE_NEC, + .name = RC_MAP_AVERMEDIA_M135A, + } +}; + +static int __init init_rc_map_avermedia_m135a(void) +{ + return ir_register_map(&avermedia_m135a_map); +} + +static void __exit exit_rc_map_avermedia_m135a(void) +{ + ir_unregister_map(&avermedia_m135a_map); +} + +module_init(init_rc_map_avermedia_m135a) +module_exit(exit_rc_map_avermedia_m135a) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index f9ed8048894d..b36960dd7319 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -657,7 +657,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4); break; case SAA7134_BOARD_AVERMEDIA_M135A: - ir_codes = RC_MAP_AVERMEDIA_M135A_RM_JX; + ir_codes = RC_MAP_AVERMEDIA_M135A; mask_keydown = 0x0040000; /* Enable GPIO18 line on both edges */ mask_keyup = 0x0040000; mask_keycode = 0xffff; -- cgit v1.2.3 From a49ba1674b0cf507e62d97fbd91ce345a37b11a8 Mon Sep 17 00:00:00 2001 From: Prarit Bhargava Date: Wed, 12 May 2010 19:30:02 -0300 Subject: V4L/DVB: Add notification to cxusb_dualdig4_rev2_frontend_attach() error handling Add a notification to the dib7000p_i2c_enumeration() failure path in cxusb_dualdig4_rev2_frontend_attach(). Signed-off-by: Prarit Bhargava Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/cxusb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index 0eb490889162..11e9e85dac86 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -1026,8 +1026,10 @@ static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap) cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, - &cxusb_dualdig4_rev2_config) < 0) + &cxusb_dualdig4_rev2_config) < 0) { + printk(KERN_WARNING "Unable to enumerate dib7000p\n"); return -ENODEV; + } adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &cxusb_dualdig4_rev2_config); -- cgit v1.2.3 From 58aac2bff192970a1186c33fbea181efe9464dd2 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 14 May 2010 14:09:57 -0300 Subject: V4L/DVB: [-next] IR: fix ir-nec-decoder build, select BITREVERSE Fix ir-nec-decoder build: it uses bitrev library code, so select BITREVERSE in its Kconfig. ir-nec-decoder.c:(.text+0x1a2517): undefined reference to `byte_rev_table' ir-nec-decoder.c:(.text+0x1a2526): undefined reference to `byte_rev_table' ir-nec-decoder.c:(.text+0x1a2530): undefined reference to `byte_rev_table' ir-nec-decoder.c:(.text+0x1a2539): undefined reference to `byte_rev_table' Signed-off-by: Randy Dunlap Signed-off-by: Mauro Carvalho Chehab --- drivers/media/IR/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/IR/Kconfig b/drivers/media/IR/Kconfig index 195c6cf359f6..b45f3bc4a7b1 100644 --- a/drivers/media/IR/Kconfig +++ b/drivers/media/IR/Kconfig @@ -13,6 +13,7 @@ source "drivers/media/IR/keymaps/Kconfig" config IR_NEC_DECODER tristate "Enable IR raw decoder for the NEC protocol" depends on IR_CORE + select BITREVERSE default y ---help--- -- cgit v1.2.3 From 9947e98a76455cec4a64aef536d375fa37cbfc32 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 15 May 2010 13:45:21 -0300 Subject: V4L/DVB: dw2102: Select tda10023 frontend, not tda10021 Update the Kconfig selections to match the code. Signed-off-by: Ben Hutchings Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index e5f91f16ffa4..cfcbf4f15b2b 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -264,7 +264,7 @@ config DVB_USB_DW2102 select DVB_STB6000 if !DVB_FE_CUSTOMISE select DVB_CX24116 if !DVB_FE_CUSTOMISE select DVB_SI21XX if !DVB_FE_CUSTOMISE - select DVB_TDA10021 if !DVB_FE_CUSTOMISE + select DVB_TDA10023 if !DVB_FE_CUSTOMISE select DVB_MT312 if !DVB_FE_CUSTOMISE select DVB_ZL10039 if !DVB_FE_CUSTOMISE select DVB_DS3000 if !DVB_FE_CUSTOMISE -- cgit v1.2.3 From d46b36e7f927772bb72524dc9f1e384e3cb4a975 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 15 May 2010 13:45:37 -0300 Subject: V4L/DVB: budget: Select correct frontends Update the Kconfig selections to match the code. Signed-off-by: Ben Hutchings Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ttpci/Kconfig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig index d8d4214fd65f..32a7ec65ec42 100644 --- a/drivers/media/dvb/ttpci/Kconfig +++ b/drivers/media/dvb/ttpci/Kconfig @@ -68,13 +68,14 @@ config DVB_BUDGET select DVB_VES1820 if !DVB_FE_CUSTOMISE select DVB_L64781 if !DVB_FE_CUSTOMISE select DVB_TDA8083 if !DVB_FE_CUSTOMISE - select DVB_TDA10021 if !DVB_FE_CUSTOMISE - select DVB_TDA10023 if !DVB_FE_CUSTOMISE select DVB_S5H1420 if !DVB_FE_CUSTOMISE select DVB_TDA10086 if !DVB_FE_CUSTOMISE select DVB_TDA826X if !DVB_FE_CUSTOMISE select DVB_LNBP21 if !DVB_FE_CUSTOMISE select DVB_TDA1004X if !DVB_FE_CUSTOMISE + select DVB_ISL6423 if !DVB_FE_CUSTOMISE + select DVB_STV090x if !DVB_FE_CUSTOMISE + select DVB_STV6110x if !DVB_FE_CUSTOMISE help Support for simple SAA7146 based DVB cards (so called Budget- or Nova-PCI cards) without onboard MPEG2 decoder, and without -- cgit v1.2.3 From e245b0bd8253fc54dfe3b5e453af0c9841098f87 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 15 May 2010 13:45:58 -0300 Subject: V4L/DVB: dib0700: Select dib0090 frontend Update the Kconfig selections to match the code. Signed-off-by: Ben Hutchings Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index cfcbf4f15b2b..73a6e9dbbe9c 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -76,6 +76,7 @@ config DVB_USB_DIB0700 select DVB_S5H1411 if !DVB_FE_CUSTOMISE select DVB_LGDT3305 if !DVB_FE_CUSTOMISE select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE + select DVB_TUNER_DIB0090 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_MT2266 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE -- cgit v1.2.3 From 59fd08afe0f9ae3a3b793fc178a3c3677b1e716c Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 15 May 2010 13:46:16 -0300 Subject: V4L/DVB: m920x: Select simple tuner Update the Kconfig selections to match the code. Signed-off-by: Ben Hutchings Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 73a6e9dbbe9c..553b48ac1919 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -135,6 +135,7 @@ config DVB_USB_M920X select DVB_TDA1004X if !DVB_FE_CUSTOMISE select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE help Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver. Currently, only devices with a product id of -- cgit v1.2.3 From 2ef17c9fc8241e5b08c60ca82345c540bb001876 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 13 May 2010 16:59:15 -0300 Subject: V4L/DVB: drivers/media: Use kzalloc Use kzalloc rather than the combination of kmalloc and memset. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression x,size,flags; statement S; @@ -x = kmalloc(size,flags); +x = kzalloc(size,flags); if (x == NULL) S -memset(x, 0, size); // Signed-off-by: Julia Lawall Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/ds3000.c | 5 +---- drivers/media/video/omap/omap_vout.c | 3 +-- 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/ds3000.c b/drivers/media/dvb/frontends/ds3000.c index 78001e8bcdb7..fc61d9230db8 100644 --- a/drivers/media/dvb/frontends/ds3000.c +++ b/drivers/media/dvb/frontends/ds3000.c @@ -969,15 +969,12 @@ struct dvb_frontend *ds3000_attach(const struct ds3000_config *config, dprintk("%s\n", __func__); /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct ds3000_state), GFP_KERNEL); + state = kzalloc(sizeof(struct ds3000_state), GFP_KERNEL); if (state == NULL) { printk(KERN_ERR "Unable to kmalloc\n"); goto error2; } - /* setup the state */ - memset(state, 0, sizeof(struct ds3000_state)); - state->config = config; state->i2c = i2c; state->prevUCBS2 = 0; diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c index 4c0ab499228b..e7db0554949a 100644 --- a/drivers/media/video/omap/omap_vout.c +++ b/drivers/media/video/omap/omap_vout.c @@ -2371,12 +2371,11 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev) for (k = 0; k < pdev->num_resources; k++) { - vout = kmalloc(sizeof(struct omap_vout_device), GFP_KERNEL); + vout = kzalloc(sizeof(struct omap_vout_device), GFP_KERNEL); if (!vout) { dev_err(&pdev->dev, ": could not allocate memory\n"); return -ENOMEM; } - memset(vout, 0, sizeof(struct omap_vout_device)); vout->vid = k; vid_dev->vouts[k] = vout; -- cgit v1.2.3 From f137f9d0009067289a2fa6c4da9b82084cdd257e Mon Sep 17 00:00:00 2001 From: Hermann Gausterer Date: Tue, 18 May 2010 04:26:17 -0300 Subject: V4L/DVB: Technotrend S2-3200 ships with a TT 1500 remote The Technotrend Budget S2-3200 ships with the Technotrend 1500 bundled remote which is already supported. Just add the right Subsystem Device ID. Signed-off-by: Hermann Gausterer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ttpci/budget-ci.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index 461714396331..13ac9e3ab121 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -215,6 +215,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci) break; case 0x1010: case 0x1017: + case 0x1019: case 0x101a: /* for the Technotrend 1500 bundled remote */ ir_codes = RC_MAP_TT_1500; -- cgit v1.2.3 From 806b07c29b711aaf90c81d2a19711607769f8246 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 26 May 2010 10:05:11 -0300 Subject: V4L/DVB: FusionHDTV: Use quick reads for I2C IR device probing IR support on FusionHDTV cards is broken since kernel 2.6.31. One side effect of the switch to the standard binding model for IR I2C devices was to let i2c-core do the probing instead of the ir-kbd-i2c driver. There is a slight difference between the two probe methods: i2c-core uses 0-byte writes, while the ir-kbd-i2c was using 0-byte reads. As some IR I2C devices only support reads, the new probe method fails to detect them. For now, revert to letting the driver do the probe, using 0-byte reads. In the future, i2c-core will be extended to let callers of i2c_new_probed_device() provide a custom probing function. Signed-off-by: Jean Delvare Tested-by: "Timothy D. Lenz" Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-i2c.c | 12 +++++++++++- drivers/media/video/cx88/cx88-i2c.c | 16 +++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index 4172cb387420..d4746e064516 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -365,7 +365,17 @@ int cx23885_i2c_register(struct cx23885_i2c *bus) memset(&info, 0, sizeof(struct i2c_board_info)); strlcpy(info.type, "ir_video", I2C_NAME_SIZE); - i2c_new_probed_device(&bus->i2c_adap, &info, addr_list); + /* + * We can't call i2c_new_probed_device() because it uses + * quick writes for probing and the IR receiver device only + * replies to reads. + */ + if (i2c_smbus_xfer(&bus->i2c_adap, addr_list[0], 0, + I2C_SMBUS_READ, 0, I2C_SMBUS_QUICK, + NULL) >= 0) { + info.addr = addr_list[0]; + i2c_new_device(&bus->i2c_adap, &info); + } } return bus->i2c_rc; diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index ee1ca39db06a..fb39f1184558 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -188,10 +188,24 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) 0x18, 0x6b, 0x71, I2C_CLIENT_END }; + const unsigned short *addrp; memset(&info, 0, sizeof(struct i2c_board_info)); strlcpy(info.type, "ir_video", I2C_NAME_SIZE); - i2c_new_probed_device(&core->i2c_adap, &info, addr_list); + /* + * We can't call i2c_new_probed_device() because it uses + * quick writes for probing and at least some R receiver + * devices only reply to reads. + */ + for (addrp = addr_list; *addrp != I2C_CLIENT_END; addrp++) { + if (i2c_smbus_xfer(&core->i2c_adap, *addrp, 0, + I2C_SMBUS_READ, 0, + I2C_SMBUS_QUICK, NULL) >= 0) { + info.addr = *addrp; + i2c_new_device(&core->i2c_adap, &info); + break; + } + } } return core->i2c_rc; } -- cgit v1.2.3 From 1db2c22b2216718d4d9adb4a9450bb3dc70e56d2 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 20 May 2010 18:08:23 -0300 Subject: V4L/DVB: ak881x needs slab.h Add slab.h to fix ak881x build: drivers/media/video/ak881x.c:265:error: implicit declaration of function 'kzalloc' drivers/media/video/ak881x.c:265:warning: assignment makes pointer from integer without a cast drivers/media/video/ak881x.c:283:error: implicit declaration of function 'kfree' Signed-off-by: Randy Dunlap Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ak881x.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/video/ak881x.c b/drivers/media/video/ak881x.c index 3006a2c80f47..1573392f74bd 100644 --- a/drivers/media/video/ak881x.c +++ b/drivers/media/video/ak881x.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3 From 7853d408b792f9015072f7c4649bd3a5d4f6ed02 Mon Sep 17 00:00:00 2001 From: Huang Weiyi Date: Sat, 22 May 2010 14:12:06 -0300 Subject: V4L/DVB: ngene: remove unused #include Remove unused #include ('s) in drivers/media/dvb/ngene/ngene-dvb.c drivers/media/dvb/ngene/ngene-i2c.c Signed-off-by: Huang Weiyi Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ngene/ngene-dvb.c | 1 - drivers/media/dvb/ngene/ngene-i2c.c | 1 - 2 files changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ngene/ngene-dvb.c b/drivers/media/dvb/ngene/ngene-dvb.c index 61a932c1cfff..48f980b21d66 100644 --- a/drivers/media/dvb/ngene/ngene-dvb.c +++ b/drivers/media/dvb/ngene/ngene-dvb.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/dvb/ngene/ngene-i2c.c b/drivers/media/dvb/ngene/ngene-i2c.c index 2ef54ca6badd..477fe0aade86 100644 --- a/drivers/media/dvb/ngene/ngene-i2c.c +++ b/drivers/media/dvb/ngene/ngene-i2c.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From 517521e4651ac106fc2a4f7638c284f60de92bb8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 22 May 2010 16:53:27 -0300 Subject: V4L/DVB: em28xx: remove unneeded null checks The "dev" variable is used as a list cursor in a list_for_each_entry() loop and can never be null here so I removed the check. Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-core.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index 331e1cac4272..44c63cbd6dda 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -1186,8 +1186,7 @@ int em28xx_register_extension(struct em28xx_ops *ops) mutex_lock(&em28xx_devlist_mutex); list_add_tail(&ops->next, &em28xx_extension_devlist); list_for_each_entry(dev, &em28xx_devlist, devlist) { - if (dev) - ops->init(dev); + ops->init(dev); } printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name); mutex_unlock(&em28xx_devlist_mutex); @@ -1201,10 +1200,8 @@ void em28xx_unregister_extension(struct em28xx_ops *ops) mutex_lock(&em28xx_devlist_mutex); list_for_each_entry(dev, &em28xx_devlist, devlist) { - if (dev) - ops->fini(dev); + ops->fini(dev); } - printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name); list_del(&ops->next); mutex_unlock(&em28xx_devlist_mutex); -- cgit v1.2.3 From f789bf4013e5e003e5d75ec0b8fa280aa66f401f Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Mon, 24 May 2010 12:00:31 -0300 Subject: V4L/DVB: IR/imon: clean up usage of bools There was a mix of 0/1 and false/true. Pick one convention and stick with it (I picked false/true). Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/IR/imon.c | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/media/IR/imon.c b/drivers/media/IR/imon.c index 5e2045670004..2bae9ba2e40c 100644 --- a/drivers/media/IR/imon.c +++ b/drivers/media/IR/imon.c @@ -385,7 +385,7 @@ static int display_open(struct inode *inode, struct file *file) err("%s: display port is already open", __func__); retval = -EBUSY; } else { - ictx->display_isopen = 1; + ictx->display_isopen = true; file->private_data = ictx; dev_dbg(ictx->dev, "display port opened\n"); } @@ -422,7 +422,7 @@ static int display_close(struct inode *inode, struct file *file) err("%s: display is not open", __func__); retval = -EIO; } else { - ictx->display_isopen = 0; + ictx->display_isopen = false; dev_dbg(ictx->dev, "display port closed\n"); if (!ictx->dev_present_intf0) { /* @@ -491,12 +491,12 @@ static int send_packet(struct imon_context *ictx) } init_completion(&ictx->tx.finished); - ictx->tx.busy = 1; + ictx->tx.busy = true; smp_rmb(); /* ensure later readers know we're busy */ retval = usb_submit_urb(ictx->tx_urb, GFP_KERNEL); if (retval) { - ictx->tx.busy = 0; + ictx->tx.busy = false; smp_rmb(); /* ensure later readers know we're not busy */ err("%s: error submitting urb(%d)", __func__, retval); } else { @@ -682,7 +682,7 @@ static ssize_t store_associate_remote(struct device *d, return -ENODEV; mutex_lock(&ictx->lock); - ictx->rf_isassociating = 1; + ictx->rf_isassociating = true; send_associate_24g(ictx); mutex_unlock(&ictx->lock); @@ -950,7 +950,7 @@ static void usb_tx_callback(struct urb *urb) ictx->tx.status = urb->status; /* notify waiters that write has finished */ - ictx->tx.busy = 0; + ictx->tx.busy = false; smp_rmb(); /* ensure later readers know we're not busy */ complete(&ictx->tx.finished); } @@ -1215,7 +1215,7 @@ static bool imon_mouse_event(struct imon_context *ictx, { char rel_x = 0x00, rel_y = 0x00; u8 right_shift = 1; - bool mouse_input = 1; + bool mouse_input = true; int dir = 0; /* newer iMON device PAD or mouse button */ @@ -1246,7 +1246,7 @@ static bool imon_mouse_event(struct imon_context *ictx, } else if (ictx->kc == KEY_CHANNELDOWN && (buf[2] & 0x40) != 0x40) { dir = -1; } else - mouse_input = 0; + mouse_input = false; if (mouse_input) { dev_dbg(ictx->dev, "sending mouse data via input subsystem\n"); @@ -1450,7 +1450,7 @@ static void imon_incoming_packet(struct imon_context *ictx, unsigned char *buf = urb->transfer_buffer; struct device *dev = ictx->dev; u32 kc; - bool norelease = 0; + bool norelease = false; int i; u64 temp_key; u64 panel_key = 0; @@ -1517,7 +1517,7 @@ static void imon_incoming_packet(struct imon_context *ictx, !(buf[1] & 0x1 || buf[1] >> 2 & 0x1))) { len = 8; imon_pad_to_keys(ictx, buf); - norelease = 1; + norelease = true; } if (debug) { @@ -1580,7 +1580,7 @@ not_input_data: (buf[6] == 0x5E && buf[7] == 0xDF))) { /* DT */ dev_warn(dev, "%s: remote associated refid=%02X\n", __func__, buf[1]); - ictx->rf_isassociating = 0; + ictx->rf_isassociating = false; } } @@ -1790,9 +1790,9 @@ static bool imon_find_endpoints(struct imon_context *ictx, int ifnum = iface_desc->desc.bInterfaceNumber; int num_endpts = iface_desc->desc.bNumEndpoints; int i, ep_dir, ep_type; - bool ir_ep_found = 0; - bool display_ep_found = 0; - bool tx_control = 0; + bool ir_ep_found = false; + bool display_ep_found = false; + bool tx_control = false; /* * Scan the endpoint list and set: @@ -1808,13 +1808,13 @@ static bool imon_find_endpoints(struct imon_context *ictx, ep_type == USB_ENDPOINT_XFER_INT) { rx_endpoint = ep; - ir_ep_found = 1; + ir_ep_found = true; dev_dbg(ictx->dev, "%s: found IR endpoint\n", __func__); } else if (!display_ep_found && ep_dir == USB_DIR_OUT && ep_type == USB_ENDPOINT_XFER_INT) { tx_endpoint = ep; - display_ep_found = 1; + display_ep_found = true; dev_dbg(ictx->dev, "%s: found display endpoint\n", __func__); } } @@ -1835,8 +1835,8 @@ static bool imon_find_endpoints(struct imon_context *ictx, * newer iMON devices that use control urb instead of interrupt */ if (!display_ep_found) { - tx_control = 1; - display_ep_found = 1; + tx_control = true; + display_ep_found = true; dev_dbg(ictx->dev, "%s: device uses control endpoint, not " "interface OUT endpoint\n", __func__); } @@ -1847,7 +1847,7 @@ static bool imon_find_endpoints(struct imon_context *ictx, * and without... :\ */ if (ictx->display_type == IMON_DISPLAY_TYPE_NONE) { - display_ep_found = 0; + display_ep_found = false; dev_dbg(ictx->dev, "%s: device has no display\n", __func__); } @@ -1856,7 +1856,7 @@ static bool imon_find_endpoints(struct imon_context *ictx, * that refers to e.g. /dev/lcd0 (a character device LCD or VFD). */ if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) { - display_ep_found = 0; + display_ep_found = false; dev_dbg(ictx->dev, "%s: iMON Touch device found\n", __func__); } @@ -1905,7 +1905,7 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf) ictx->dev = dev; ictx->usbdev_intf0 = usb_get_dev(interface_to_usbdev(intf)); - ictx->dev_present_intf0 = 1; + ictx->dev_present_intf0 = true; ictx->rx_urb_intf0 = rx_urb; ictx->tx_urb = tx_urb; @@ -1979,7 +1979,7 @@ static struct imon_context *imon_init_intf1(struct usb_interface *intf, } ictx->usbdev_intf1 = usb_get_dev(interface_to_usbdev(intf)); - ictx->dev_present_intf1 = 1; + ictx->dev_present_intf1 = true; ictx->rx_urb_intf1 = rx_urb; ret = -ENODEV; @@ -2297,7 +2297,7 @@ static void __devexit imon_disconnect(struct usb_interface *interface) } if (ifnum == 0) { - ictx->dev_present_intf0 = 0; + ictx->dev_present_intf0 = false; usb_kill_urb(ictx->rx_urb_intf0); input_unregister_device(ictx->idev); if (ictx->display_supported) { @@ -2307,7 +2307,7 @@ static void __devexit imon_disconnect(struct usb_interface *interface) usb_deregister_dev(interface, &imon_vfd_class); } } else { - ictx->dev_present_intf1 = 0; + ictx->dev_present_intf1 = false; usb_kill_urb(ictx->rx_urb_intf1); if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) input_unregister_device(ictx->touch); -- cgit v1.2.3 From bbe4690f6caef2b36c95dd50e59bc3f4e2eaa6ad Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Mon, 24 May 2010 12:02:05 -0300 Subject: V4L/DVB: IR/imon: add auto-config for 0xffdc rf device Add auto-config support for iMON 2.4G LT RF device, based on debug output from Giulio Amodeo in Red Hat bugzilla #572288. Also flips the switch on only setting up the rf associate sysfs attr only if we think we're looking at an RF device, vs. previously, setting up the attr for all 0xffdc devices, so its possible (but a bit unlikely) there's another iMON RF device we'll have to fix up. Nb: should be applied after "IR/imon: clean up usage of bools", or there will be a slight contextual mismatch. Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/IR/imon.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/IR/imon.c b/drivers/media/IR/imon.c index 2bae9ba2e40c..4bbd45f4284c 100644 --- a/drivers/media/IR/imon.c +++ b/drivers/media/IR/imon.c @@ -94,6 +94,7 @@ struct imon_context { bool display_supported; /* not all controllers do */ bool display_isopen; /* display port has been opened */ + bool rf_device; /* true if iMON 2.4G LT/DT RF device */ bool rf_isassociating; /* RF remote associating */ bool dev_present_intf0; /* USB device presence, interface 0 */ bool dev_present_intf1; /* USB device presence, interface 1 */ @@ -1465,7 +1466,7 @@ static void imon_incoming_packet(struct imon_context *ictx, idev = ictx->idev; /* filter out junk data on the older 0xffdc imon devices */ - if ((buf[0] == 0xff) && (buf[7] == 0xff)) + if ((buf[0] == 0xff) && (buf[1] == 0xff) && (buf[2] == 0xff)) return; /* Figure out what key was pressed */ @@ -1908,6 +1909,7 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf) ictx->dev_present_intf0 = true; ictx->rx_urb_intf0 = rx_urb; ictx->tx_urb = tx_urb; + ictx->rf_device = false; ictx->vendor = le16_to_cpu(ictx->usbdev_intf0->descriptor.idVendor); ictx->product = le16_to_cpu(ictx->usbdev_intf0->descriptor.idProduct); @@ -2047,6 +2049,12 @@ static void imon_get_ffdc_type(struct imon_context *ictx) dev_info(ictx->dev, "0xffdc iMON Knob, iMON IR"); ictx->display_supported = false; break; + /* iMON 2.4G LT (usb stick), no display, iMON RF */ + case 0x4e: + dev_info(ictx->dev, "0xffdc iMON 2.4G LT, iMON RF"); + ictx->display_supported = false; + ictx->rf_device = true; + break; /* iMON VFD, no IR (does have vol knob tho) */ case 0x35: dev_info(ictx->dev, "0xffdc iMON VFD + knob, no IR"); @@ -2197,15 +2205,6 @@ static int __devinit imon_probe(struct usb_interface *interface, goto fail; } - if (product == 0xffdc) { - /* RF products *also* use 0xffdc... sigh... */ - sysfs_err = sysfs_create_group(&interface->dev.kobj, - &imon_rf_attribute_group); - if (sysfs_err) - err("%s: Could not create RF sysfs entries(%d)", - __func__, sysfs_err); - } - } else { /* this is the secondary interface on the device */ ictx = imon_init_intf1(interface, first_if_ctx); @@ -2233,6 +2232,14 @@ static int __devinit imon_probe(struct usb_interface *interface, imon_set_display_type(ictx, interface); + if (product == 0xffdc && ictx->rf_device) { + sysfs_err = sysfs_create_group(&interface->dev.kobj, + &imon_rf_attribute_group); + if (sysfs_err) + err("%s: Could not create RF sysfs entries(%d)", + __func__, sysfs_err); + } + if (ictx->display_supported) imon_init_display(ictx, interface); } -- cgit v1.2.3 From f0e5481f2f5304ffebd43d97bd5118443fac8d23 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 25 May 2010 06:21:50 -0300 Subject: V4L/DVB: video/saa7134: remove duplicate break The original code had two break statements in a row. Signed-off-by: Dan Carpenter Acked-by: Jean Delvare Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-input.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index b36960dd7319..c1240d22028a 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -822,7 +822,6 @@ int saa7134_input_init1(struct saa7134_dev *dev) mask_keyup = 0x020000; polling = 50; /* ms */ break; - break; } if (NULL == ir_codes) { printk("%s: Oops: IR config error [card=%d]\n", -- cgit v1.2.3 From 129c34d8fce443d1c43d32637abbab8433504497 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 26 May 2010 11:58:10 -0300 Subject: V4L/DVB: video/saa7134: change dprintk() to i2cdprintk() The problem is that dprintk() dereferences "dev" which is null here. The i2cdprintk() uses "ir" so that's OK. Also Jean Delvare pointed out a typo in the comment so we may as well fix that. Signed-off-by: Dan Carpenter Acked-by: Jean Delvare Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-input.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index c1240d22028a..0b336ca6d55b 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -141,8 +141,8 @@ static int get_key_flydvb_trio(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) struct saa7134_dev *dev = ir->c->adapter->algo_data; if (dev == NULL) { - dprintk("get_key_flydvb_trio: " - "gir->c->adapter->algo_data is NULL!\n"); + i2cdprintk("get_key_flydvb_trio: " + "ir->c->adapter->algo_data is NULL!\n"); return -EIO; } @@ -195,8 +195,8 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key, /* is needed to access GPIO. Used by the saa_readl macro. */ struct saa7134_dev *dev = ir->c->adapter->algo_data; if (dev == NULL) { - dprintk("get_key_msi_tvanywhere_plus: " - "gir->c->adapter->algo_data is NULL!\n"); + i2cdprintk("get_key_msi_tvanywhere_plus: " + "ir->c->adapter->algo_data is NULL!\n"); return -EIO; } -- cgit v1.2.3 From 033608c1f33bcacba8d3a960240a7b2900b1d5ff Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 26 May 2010 14:08:51 -0300 Subject: V4L/DVB: media/IR: nec-decoder needs to select BITREV Fix ir-nec-decoder build: it uses bitrev library code, so select BITREVERSE in its Kconfig. ir-nec-decoder.c:(.text+0x1a2517): undefined reference to `byte_rev_table' ir-nec-decoder.c:(.text+0x1a2526): undefined reference to `byte_rev_table' ir-nec-decoder.c:(.text+0x1a2530): undefined reference to `byte_rev_table' ir-nec-decoder.c:(.text+0x1a2539): undefined reference to `byte_rev_table' Signed-off-by: Randy Dunlap Signed-off-by: Mauro Carvalho Chehab --- drivers/media/IR/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/IR/Kconfig b/drivers/media/IR/Kconfig index b45f3bc4a7b1..d22a8ec523fc 100644 --- a/drivers/media/IR/Kconfig +++ b/drivers/media/IR/Kconfig @@ -23,6 +23,7 @@ config IR_NEC_DECODER config IR_RC5_DECODER tristate "Enable IR raw decoder for the RC-5 protocol" depends on IR_CORE + select BITREVERSE default y ---help--- -- cgit v1.2.3 From 84b14f181a36eea6591779156ef356f8d198bbfd Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Wed, 26 May 2010 23:31:21 -0300 Subject: V4L/DVB: Bug fix: make IR work again for dm1105 It makes IR to work again for dm1105 and, possibly, others. Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/IR/ir-keytable.c | 17 ++++++++++------- drivers/media/IR/ir-sysfs.c | 7 ++++--- drivers/media/dvb/dm1105/dm1105.c | 2 +- 3 files changed, 15 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/media/IR/ir-keytable.c b/drivers/media/IR/ir-keytable.c index 9374a006f43d..94a8577e72eb 100644 --- a/drivers/media/IR/ir-keytable.c +++ b/drivers/media/IR/ir-keytable.c @@ -490,11 +490,12 @@ int __ir_input_register(struct input_dev *input_dev, if (rc < 0) goto out_table; - if (ir_dev->props->driver_type == RC_DRIVER_IR_RAW) { - rc = ir_raw_event_register(input_dev); - if (rc < 0) - goto out_event; - } + if (ir_dev->props) + if (ir_dev->props->driver_type == RC_DRIVER_IR_RAW) { + rc = ir_raw_event_register(input_dev); + if (rc < 0) + goto out_event; + } IR_dprintk(1, "Registered input device on %s for %s remote.\n", driver_name, rc_tab->name); @@ -530,8 +531,10 @@ void ir_input_unregister(struct input_dev *input_dev) IR_dprintk(1, "Freed keycode table\n"); del_timer_sync(&ir_dev->timer_keyup); - if (ir_dev->props->driver_type == RC_DRIVER_IR_RAW) - ir_raw_event_unregister(input_dev); + if (ir_dev->props) + if (ir_dev->props->driver_type == RC_DRIVER_IR_RAW) + ir_raw_event_unregister(input_dev); + rc_tab = &ir_dev->rc_tab; rc_tab->size = 0; kfree(rc_tab->scan); diff --git a/drivers/media/IR/ir-sysfs.c b/drivers/media/IR/ir-sysfs.c index d7da63e16c92..2098dd1488e0 100644 --- a/drivers/media/IR/ir-sysfs.c +++ b/drivers/media/IR/ir-sysfs.c @@ -221,9 +221,10 @@ int ir_register_class(struct input_dev *input_dev) if (unlikely(devno < 0)) return devno; - if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) - ir_dev->dev.type = &rc_dev_type; - else + if (ir_dev->props) { + if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) + ir_dev->dev.type = &rc_dev_type; + } else ir_dev->dev.type = &ir_raw_dev_type; ir_dev->dev.class = &ir_input_class; diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c index b762e561a6d5..bca07c0bcd01 100644 --- a/drivers/media/dvb/dm1105/dm1105.c +++ b/drivers/media/dvb/dm1105/dm1105.c @@ -594,7 +594,7 @@ static irqreturn_t dm1105_irq(int irq, void *dev_id) int __devinit dm1105_ir_init(struct dm1105_dev *dm1105) { struct input_dev *input_dev; - char *ir_codes = NULL; + char *ir_codes = RC_MAP_DM1105_NEC; int err = -ENOMEM; input_dev = input_allocate_device(); -- cgit v1.2.3 From 5c331fc8c19e181bffab46e9d18e1637cdc47170 Mon Sep 17 00:00:00 2001 From: Ang Way Chuang Date: Thu, 27 May 2010 02:02:09 -0300 Subject: V4L/DVB: dvb-core: Fix ULE decapsulation bug Fix ULE decapsulation bug when less than 4 bytes of ULE SNDU is packed into the remaining bytes of a MPEG2-TS frame ULE (Unidirectional Lightweight Encapsulation RFC 4326) decapsulation code has a bug that incorrectly treats ULE SNDU packed into the remaining 2 or 3 bytes of a MPEG2-TS frame as having invalid pointer field on the subsequent MPEG2-TS frame. Signed-off-by: Ang Way Chuang Acked-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_net.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index f6dac2bb0ac6..6c3a8a06ccab 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -351,6 +351,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) const u8 *ts, *ts_end, *from_where = NULL; u8 ts_remain = 0, how_much = 0, new_ts = 1; struct ethhdr *ethh = NULL; + bool error = false; #ifdef ULE_DEBUG /* The code inside ULE_DEBUG keeps a history of the last 100 TS cells processed. */ @@ -460,10 +461,16 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) /* Drop partly decoded SNDU, reset state, resync on PUSI. */ if (priv->ule_skb) { - dev_kfree_skb( priv->ule_skb ); + error = true; + dev_kfree_skb(priv->ule_skb); + } + + if (error || priv->ule_sndu_remain) { dev->stats.rx_errors++; dev->stats.rx_frame_errors++; + error = false; } + reset_ule(priv); priv->need_pusi = 1; continue; @@ -535,6 +542,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) from_where += 2; } + priv->ule_sndu_remain = priv->ule_sndu_len + 2; /* * State of current TS: * ts_remain (remaining bytes in the current TS cell) @@ -544,6 +552,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) */ switch (ts_remain) { case 1: + priv->ule_sndu_remain--; priv->ule_sndu_type = from_where[0] << 8; priv->ule_sndu_type_1 = 1; /* first byte of ule_type is set. */ ts_remain -= 1; from_where += 1; @@ -557,6 +566,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) default: /* complete ULE header is present in current TS. */ /* Extract ULE type field. */ if (priv->ule_sndu_type_1) { + priv->ule_sndu_type_1 = 0; priv->ule_sndu_type |= from_where[0]; from_where += 1; /* points to payload start. */ ts_remain -= 1; -- cgit v1.2.3 From 4202066c6995200b2755a4501ea90f5d4e163e41 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 27 May 2010 09:36:45 -0300 Subject: V4L/DVB: drivers/media: Eliminate a NULL pointer dereference In each case, the print involves dereferencing a value that is NULL or is near NULL. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r exists@ expression E,E1; identifier f; statement S1,S2,S3; @@ if ((E == NULL && ...) || ...) { ... when != if (...) S1 else S2 when != E = E1 * E->f ... when any return ...; } else S3 // Signed-off-by: Julia Lawall Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/firewire/firedtv-1394.c | 2 +- drivers/media/video/hdpvr/hdpvr-video.c | 2 +- drivers/media/video/usbvision/usbvision-video.c | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/firewire/firedtv-1394.c b/drivers/media/dvb/firewire/firedtv-1394.c index 26333b4f4d3e..b34ca7afb0e6 100644 --- a/drivers/media/dvb/firewire/firedtv-1394.c +++ b/drivers/media/dvb/firewire/firedtv-1394.c @@ -58,7 +58,7 @@ static void rawiso_activity_cb(struct hpsb_iso *iso) num = hpsb_iso_n_ready(iso); if (!fdtv) { - dev_err(fdtv->device, "received at unknown iso channel\n"); + pr_err("received at unknown iso channel\n"); goto out; } diff --git a/drivers/media/video/hdpvr/hdpvr-video.c b/drivers/media/video/hdpvr/hdpvr-video.c index 7cfccfd1b870..c338f3f62e77 100644 --- a/drivers/media/video/hdpvr/hdpvr-video.c +++ b/drivers/media/video/hdpvr/hdpvr-video.c @@ -366,7 +366,7 @@ static int hdpvr_open(struct file *file) dev = (struct hdpvr_device *)video_get_drvdata(video_devdata(file)); if (!dev) { - v4l2_err(&dev->v4l2_dev, "open failing with with ENODEV\n"); + pr_err("open failing with with ENODEV\n"); retval = -ENODEV; goto err; } diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index 6248a639ba2d..c2690df33438 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -1671,8 +1671,7 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf) PDEBUG(DBG_PROBE, ""); if (usbvision == NULL) { - dev_err(&usbvision->dev->dev, - "%s: usb_get_intfdata() failed\n", __func__); + pr_err("%s: usb_get_intfdata() failed\n", __func__); return; } -- cgit v1.2.3 From 6afdeaf865b729287e02aafc61d8d013b89996ef Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Sun, 23 May 2010 18:53:35 -0300 Subject: V4L/DVB: cx18, cx23885, v4l2 doc, MAINTAINERS: Update Andy Walls' email address A trivial change to update my email address from my dead awalls@radix.net address to my current awalls@md.metrocast.net address. Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx18/cx18-alsa-main.c | 2 +- drivers/media/video/cx18/cx18-alsa-mixer.c | 2 +- drivers/media/video/cx18/cx18-alsa-mixer.h | 2 +- drivers/media/video/cx18/cx18-alsa-pcm.c | 2 +- drivers/media/video/cx18/cx18-alsa-pcm.h | 2 +- drivers/media/video/cx18/cx18-alsa.h | 2 +- drivers/media/video/cx18/cx18-av-audio.c | 2 +- drivers/media/video/cx18/cx18-av-core.c | 2 +- drivers/media/video/cx18/cx18-av-core.h | 2 +- drivers/media/video/cx18/cx18-av-firmware.c | 2 +- drivers/media/video/cx18/cx18-cards.c | 2 +- drivers/media/video/cx18/cx18-cards.h | 2 +- drivers/media/video/cx18/cx18-driver.c | 2 +- drivers/media/video/cx18/cx18-driver.h | 2 +- drivers/media/video/cx18/cx18-dvb.c | 2 +- drivers/media/video/cx18/cx18-fileops.c | 2 +- drivers/media/video/cx18/cx18-firmware.c | 2 +- drivers/media/video/cx18/cx18-gpio.c | 2 +- drivers/media/video/cx18/cx18-gpio.h | 2 +- drivers/media/video/cx18/cx18-i2c.c | 2 +- drivers/media/video/cx18/cx18-io.c | 2 +- drivers/media/video/cx18/cx18-io.h | 4 ++-- drivers/media/video/cx18/cx18-ioctl.c | 2 +- drivers/media/video/cx18/cx18-ioctl.h | 2 +- drivers/media/video/cx18/cx18-irq.c | 2 +- drivers/media/video/cx18/cx18-irq.h | 2 +- drivers/media/video/cx18/cx18-mailbox.c | 2 +- drivers/media/video/cx18/cx18-mailbox.h | 2 +- drivers/media/video/cx18/cx18-queue.c | 2 +- drivers/media/video/cx18/cx18-queue.h | 2 +- drivers/media/video/cx18/cx18-scb.c | 2 +- drivers/media/video/cx18/cx18-scb.h | 2 +- drivers/media/video/cx18/cx18-streams.c | 2 +- drivers/media/video/cx18/cx18-streams.h | 2 +- drivers/media/video/cx23885/cx23885-input.c | 2 +- drivers/media/video/cx23885/cx23885-input.h | 2 +- drivers/media/video/cx23885/cx23885-ioctl.c | 2 +- drivers/media/video/cx23885/cx23885-ioctl.h | 2 +- drivers/media/video/cx23885/cx23885-ir.c | 2 +- drivers/media/video/cx23885/cx23885-ir.h | 2 +- drivers/media/video/cx23885/cx23888-ir.c | 2 +- drivers/media/video/cx23885/cx23888-ir.h | 2 +- 42 files changed, 43 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx18/cx18-alsa-main.c b/drivers/media/video/cx18/cx18-alsa-main.c index b5d7cbf4528a..d50d69da387b 100644 --- a/drivers/media/video/cx18/cx18-alsa-main.c +++ b/drivers/media/video/cx18/cx18-alsa-main.c @@ -1,7 +1,7 @@ /* * ALSA interface to cx18 PCM capture streams * - * Copyright (C) 2009 Andy Walls + * Copyright (C) 2009 Andy Walls * Copyright (C) 2009 Devin Heitmueller * * Portions of this work were sponsored by ONELAN Limited. diff --git a/drivers/media/video/cx18/cx18-alsa-mixer.c b/drivers/media/video/cx18/cx18-alsa-mixer.c index ef21114309fe..341bddc00b77 100644 --- a/drivers/media/video/cx18/cx18-alsa-mixer.c +++ b/drivers/media/video/cx18/cx18-alsa-mixer.c @@ -2,7 +2,7 @@ * ALSA mixer controls for the * ALSA interface to cx18 PCM capture streams * - * Copyright (C) 2009 Andy Walls + * Copyright (C) 2009 Andy Walls * * 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 diff --git a/drivers/media/video/cx18/cx18-alsa-mixer.h b/drivers/media/video/cx18/cx18-alsa-mixer.h index 2d418db000fe..ec9238793f6f 100644 --- a/drivers/media/video/cx18/cx18-alsa-mixer.h +++ b/drivers/media/video/cx18/cx18-alsa-mixer.h @@ -2,7 +2,7 @@ * ALSA mixer controls for the * ALSA interface to cx18 PCM capture streams * - * Copyright (C) 2009 Andy Walls + * Copyright (C) 2009 Andy Walls * * 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 diff --git a/drivers/media/video/cx18/cx18-alsa-pcm.c b/drivers/media/video/cx18/cx18-alsa-pcm.c index 2bd312daeb1e..8f55692db36d 100644 --- a/drivers/media/video/cx18/cx18-alsa-pcm.c +++ b/drivers/media/video/cx18/cx18-alsa-pcm.c @@ -2,7 +2,7 @@ * ALSA PCM device for the * ALSA interface to cx18 PCM capture streams * - * Copyright (C) 2009 Andy Walls + * Copyright (C) 2009 Andy Walls * Copyright (C) 2009 Devin Heitmueller * * Portions of this work were sponsored by ONELAN Limited. diff --git a/drivers/media/video/cx18/cx18-alsa-pcm.h b/drivers/media/video/cx18/cx18-alsa-pcm.h index 325662c647a0..d26e51f94577 100644 --- a/drivers/media/video/cx18/cx18-alsa-pcm.h +++ b/drivers/media/video/cx18/cx18-alsa-pcm.h @@ -2,7 +2,7 @@ * ALSA PCM device for the * ALSA interface to cx18 PCM capture streams * - * Copyright (C) 2009 Andy Walls + * Copyright (C) 2009 Andy Walls * * 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 diff --git a/drivers/media/video/cx18/cx18-alsa.h b/drivers/media/video/cx18/cx18-alsa.h index 88a1cde7540b..447da374c9e8 100644 --- a/drivers/media/video/cx18/cx18-alsa.h +++ b/drivers/media/video/cx18/cx18-alsa.h @@ -1,7 +1,7 @@ /* * ALSA interface to cx18 PCM capture streams * - * Copyright (C) 2009 Andy Walls + * Copyright (C) 2009 Andy Walls * * 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 diff --git a/drivers/media/video/cx18/cx18-av-audio.c b/drivers/media/video/cx18/cx18-av-audio.c index 9e30983f2ff6..43d09a24b262 100644 --- a/drivers/media/video/cx18/cx18-av-audio.c +++ b/drivers/media/video/cx18/cx18-av-audio.c @@ -4,7 +4,7 @@ * Derived from cx25840-audio.c * * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls + * Copyright (C) 2008 Andy Walls * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c index 54371f6d6b5f..a41951cab276 100644 --- a/drivers/media/video/cx18/cx18-av-core.c +++ b/drivers/media/video/cx18/cx18-av-core.c @@ -4,7 +4,7 @@ * Derived from cx25840-core.c * * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls + * Copyright (C) 2008 Andy Walls * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/video/cx18/cx18-av-core.h b/drivers/media/video/cx18/cx18-av-core.h index c106967bdcc3..1956991795e3 100644 --- a/drivers/media/video/cx18/cx18-av-core.h +++ b/drivers/media/video/cx18/cx18-av-core.h @@ -4,7 +4,7 @@ * Derived from cx25840-core.h * * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls + * Copyright (C) 2008 Andy Walls * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/video/cx18/cx18-av-firmware.c b/drivers/media/video/cx18/cx18-av-firmware.c index b9e8cc5d264a..280aa4d22488 100644 --- a/drivers/media/video/cx18/cx18-av-firmware.c +++ b/drivers/media/video/cx18/cx18-av-firmware.c @@ -2,7 +2,7 @@ * cx18 ADEC firmware functions * * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls + * Copyright (C) 2008 Andy Walls * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c index 74e122b5fc49..6b805afe5d20 100644 --- a/drivers/media/video/cx18/cx18-cards.c +++ b/drivers/media/video/cx18/cx18-cards.c @@ -4,7 +4,7 @@ * Derived from ivtv-cards.c * * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls + * Copyright (C) 2008 Andy Walls * * 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 diff --git a/drivers/media/video/cx18/cx18-cards.h b/drivers/media/video/cx18/cx18-cards.h index 796e517300ac..3e750068f275 100644 --- a/drivers/media/video/cx18/cx18-cards.h +++ b/drivers/media/video/cx18/cx18-cards.h @@ -4,7 +4,7 @@ * Derived from ivtv-cards.c * * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls + * Copyright (C) 2008 Andy Walls * * 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 diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index c95a86ba33b0..df60f27337cf 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c @@ -4,7 +4,7 @@ * Derived from ivtv-driver.c * * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls + * Copyright (C) 2008 Andy Walls * * 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 diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h index b9728e8eee40..9bc51a99376b 100644 --- a/drivers/media/video/cx18/cx18-driver.h +++ b/drivers/media/video/cx18/cx18-driver.h @@ -4,7 +4,7 @@ * Derived from ivtv-driver.h * * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls + * Copyright (C) 2008 Andy Walls * * 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 diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c index 0ae2c2e1eab5..6d19f040d70f 100644 --- a/drivers/media/video/cx18/cx18-dvb.c +++ b/drivers/media/video/cx18/cx18-dvb.c @@ -2,7 +2,7 @@ * cx18 functions for DVB support * * Copyright (c) 2008 Steven Toth - * Copyright (C) 2008 Andy Walls + * Copyright (C) 2008 Andy Walls * * 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 diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c index e12a15020cda..9f23b90732f2 100644 --- a/drivers/media/video/cx18/cx18-fileops.c +++ b/drivers/media/video/cx18/cx18-fileops.c @@ -4,7 +4,7 @@ * Derived from ivtv-fileops.c * * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls + * Copyright (C) 2008 Andy Walls * * 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 diff --git a/drivers/media/video/cx18/cx18-firmware.c b/drivers/media/video/cx18/cx18-firmware.c index 83cd559cc609..1b3fb502e6be 100644 --- a/drivers/media/video/cx18/cx18-firmware.c +++ b/drivers/media/video/cx18/cx18-firmware.c @@ -2,7 +2,7 @@ * cx18 firmware functions * * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls + * Copyright (C) 2008 Andy Walls * * 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 diff --git a/drivers/media/video/cx18/cx18-gpio.c b/drivers/media/video/cx18/cx18-gpio.c index 86a204b5448e..5374aeb0cd22 100644 --- a/drivers/media/video/cx18/cx18-gpio.c +++ b/drivers/media/video/cx18/cx18-gpio.c @@ -4,7 +4,7 @@ * Derived from ivtv-gpio.c * * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls + * Copyright (C) 2008 Andy Walls * * 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 diff --git a/drivers/media/video/cx18/cx18-gpio.h b/drivers/media/video/cx18/cx18-gpio.h index f9a5ca3566af..4aea2ef88e8d 100644 --- a/drivers/media/video/cx18/cx18-gpio.h +++ b/drivers/media/video/cx18/cx18-gpio.h @@ -4,7 +4,7 @@ * Derived from ivtv-gpio.h * * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls + * Copyright (C) 2008 Andy Walls * * 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 diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c index cfa1f289b0f5..809f7d37129c 100644 --- a/drivers/media/video/cx18/cx18-i2c.c +++ b/drivers/media/video/cx18/cx18-i2c.c @@ -4,7 +4,7 @@ * Derived from ivtv-i2c.c * * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls + * Copyright (C) 2008 Andy Walls * * 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 diff --git a/drivers/media/video/cx18/cx18-io.c b/drivers/media/video/cx18/cx18-io.c index ec5b3d7bcc6b..49b9dbd06248 100644 --- a/drivers/media/video/cx18/cx18-io.c +++ b/drivers/media/video/cx18/cx18-io.c @@ -2,7 +2,7 @@ * cx18 driver PCI memory mapped IO access routines * * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls + * Copyright (C) 2008 Andy Walls * * 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 diff --git a/drivers/media/video/cx18/cx18-io.h b/drivers/media/video/cx18/cx18-io.h index 2635b3a8cc96..18974d886cf7 100644 --- a/drivers/media/video/cx18/cx18-io.h +++ b/drivers/media/video/cx18/cx18-io.h @@ -2,7 +2,7 @@ * cx18 driver PCI memory mapped IO access routines * * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls + * Copyright (C) 2008 Andy Walls * * 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,7 +28,7 @@ /* * Readback and retry of MMIO access for reliability: * The concept was suggested by Steve Toth . - * The implmentation is the fault of Andy Walls . + * The implmentation is the fault of Andy Walls . * * *write* functions are implied to retry the mmio unless suffixed with _noretry * *read* functions never retry the mmio (it never helps to do so) diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c index b5b221c8a725..20eaf38ba959 100644 --- a/drivers/media/video/cx18/cx18-ioctl.c +++ b/drivers/media/video/cx18/cx18-ioctl.c @@ -4,7 +4,7 @@ * Derived from ivtv-ioctl.c * * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls + * Copyright (C) 2008 Andy Walls * * 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 diff --git a/drivers/media/video/cx18/cx18-ioctl.h b/drivers/media/video/cx18/cx18-ioctl.h index e2ca0d152116..dcb2559ad520 100644 --- a/drivers/media/video/cx18/cx18-ioctl.h +++ b/drivers/media/video/cx18/cx18-ioctl.h @@ -4,7 +4,7 @@ * Derived from ivtv-ioctl.h * * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls + * Copyright (C) 2008 Andy Walls * * 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 diff --git a/drivers/media/video/cx18/cx18-irq.c b/drivers/media/video/cx18/cx18-irq.c index af2f504eda2b..80edfe93a3d8 100644 --- a/drivers/media/video/cx18/cx18-irq.c +++ b/drivers/media/video/cx18/cx18-irq.c @@ -2,7 +2,7 @@ * cx18 interrupt handling * * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls + * Copyright (C) 2008 Andy Walls * * 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 diff --git a/drivers/media/video/cx18/cx18-irq.h b/drivers/media/video/cx18/cx18-irq.h index 91f0b5278ef9..30e7eaf8cb55 100644 --- a/drivers/media/video/cx18/cx18-irq.h +++ b/drivers/media/video/cx18/cx18-irq.h @@ -2,7 +2,7 @@ * cx18 interrupt handling * * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls + * Copyright (C) 2008 Andy Walls * * 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 diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c index 6dcce297752f..956aa190ecca 100644 --- a/drivers/media/video/cx18/cx18-mailbox.c +++ b/drivers/media/video/cx18/cx18-mailbox.c @@ -2,7 +2,7 @@ * cx18 mailbox functions * * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls + * Copyright (C) 2008 Andy Walls * * 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 diff --git a/drivers/media/video/cx18/cx18-mailbox.h b/drivers/media/video/cx18/cx18-mailbox.h index 33a3491c4537..077952fcbcca 100644 --- a/drivers/media/video/cx18/cx18-mailbox.h +++ b/drivers/media/video/cx18/cx18-mailbox.h @@ -2,7 +2,7 @@ * cx18 mailbox functions * * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls + * Copyright (C) 2008 Andy Walls * * 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 diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c index aefc8c8cf3c1..8884537bd62f 100644 --- a/drivers/media/video/cx18/cx18-queue.c +++ b/drivers/media/video/cx18/cx18-queue.c @@ -4,7 +4,7 @@ * Derived from ivtv-queue.c * * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls + * Copyright (C) 2008 Andy Walls * * 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 diff --git a/drivers/media/video/cx18/cx18-queue.h b/drivers/media/video/cx18/cx18-queue.h index 88a6d34ad3bb..4201ddc16091 100644 --- a/drivers/media/video/cx18/cx18-queue.h +++ b/drivers/media/video/cx18/cx18-queue.h @@ -4,7 +4,7 @@ * Derived from ivtv-queue.h * * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls + * Copyright (C) 2008 Andy Walls * * 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 diff --git a/drivers/media/video/cx18/cx18-scb.c b/drivers/media/video/cx18/cx18-scb.c index 34b4d03c55cd..85cc59637e54 100644 --- a/drivers/media/video/cx18/cx18-scb.c +++ b/drivers/media/video/cx18/cx18-scb.c @@ -2,7 +2,7 @@ * cx18 System Control Block initialization * * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls + * Copyright (C) 2008 Andy Walls * * 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 diff --git a/drivers/media/video/cx18/cx18-scb.h b/drivers/media/video/cx18/cx18-scb.h index 368f23d08709..08877652e321 100644 --- a/drivers/media/video/cx18/cx18-scb.h +++ b/drivers/media/video/cx18/cx18-scb.h @@ -2,7 +2,7 @@ * cx18 System Control Block initialization * * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls + * Copyright (C) 2008 Andy Walls * * 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 diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c index f5c91261b2db..9045f1ece0eb 100644 --- a/drivers/media/video/cx18/cx18-streams.c +++ b/drivers/media/video/cx18/cx18-streams.c @@ -4,7 +4,7 @@ * Derived from ivtv-streams.c * * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls + * Copyright (C) 2008 Andy Walls * * 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 diff --git a/drivers/media/video/cx18/cx18-streams.h b/drivers/media/video/cx18/cx18-streams.h index 0bff0fa29763..77412bee5963 100644 --- a/drivers/media/video/cx18/cx18-streams.h +++ b/drivers/media/video/cx18/cx18-streams.h @@ -4,7 +4,7 @@ * Derived from ivtv-streams.h * * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls + * Copyright (C) 2008 Andy Walls * * 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 diff --git a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c index 8d306d8bb61c..5de6ba98f7a8 100644 --- a/drivers/media/video/cx23885/cx23885-input.c +++ b/drivers/media/video/cx23885/cx23885-input.c @@ -5,7 +5,7 @@ * * Most of this file is * - * Copyright (C) 2009 Andy Walls + * Copyright (C) 2009 Andy Walls * * However, the cx23885_input_{init,fini} functions contained herein are * derived from Linux kernel files linux/media/video/.../...-input.c marked as: diff --git a/drivers/media/video/cx23885/cx23885-input.h b/drivers/media/video/cx23885/cx23885-input.h index 3572cb1ecfc2..75ef15d3f523 100644 --- a/drivers/media/video/cx23885/cx23885-input.h +++ b/drivers/media/video/cx23885/cx23885-input.h @@ -3,7 +3,7 @@ * * Infrared remote control input device * - * Copyright (C) 2009 Andy Walls + * Copyright (C) 2009 Andy Walls * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/video/cx23885/cx23885-ioctl.c b/drivers/media/video/cx23885/cx23885-ioctl.c index dfb4627fb340..44812ca78899 100644 --- a/drivers/media/video/cx23885/cx23885-ioctl.c +++ b/drivers/media/video/cx23885/cx23885-ioctl.c @@ -3,7 +3,7 @@ * * Various common ioctl() support functions * - * Copyright (c) 2009 Andy Walls + * Copyright (c) 2009 Andy Walls * * 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 diff --git a/drivers/media/video/cx23885/cx23885-ioctl.h b/drivers/media/video/cx23885/cx23885-ioctl.h index 80b0f4923c6a..315be0ca5a04 100644 --- a/drivers/media/video/cx23885/cx23885-ioctl.h +++ b/drivers/media/video/cx23885/cx23885-ioctl.h @@ -3,7 +3,7 @@ * * Various common ioctl() support functions * - * Copyright (c) 2009 Andy Walls + * Copyright (c) 2009 Andy Walls * * 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 diff --git a/drivers/media/video/cx23885/cx23885-ir.c b/drivers/media/video/cx23885/cx23885-ir.c index 6ae982cc9856..9a677eb080af 100644 --- a/drivers/media/video/cx23885/cx23885-ir.c +++ b/drivers/media/video/cx23885/cx23885-ir.c @@ -3,7 +3,7 @@ * * Infrared device support routines - non-input, non-vl42_subdev routines * - * Copyright (C) 2009 Andy Walls + * Copyright (C) 2009 Andy Walls * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/video/cx23885/cx23885-ir.h b/drivers/media/video/cx23885/cx23885-ir.h index 9b8a6d5d1ef6..0c9d8bda9e28 100644 --- a/drivers/media/video/cx23885/cx23885-ir.h +++ b/drivers/media/video/cx23885/cx23885-ir.h @@ -3,7 +3,7 @@ * * Infrared device support routines - non-input, non-vl42_subdev routines * - * Copyright (C) 2009 Andy Walls + * Copyright (C) 2009 Andy Walls * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/video/cx23885/cx23888-ir.c b/drivers/media/video/cx23885/cx23888-ir.c index ad728d767d69..f63d378257a7 100644 --- a/drivers/media/video/cx23885/cx23888-ir.c +++ b/drivers/media/video/cx23885/cx23888-ir.c @@ -3,7 +3,7 @@ * * CX23888 Integrated Consumer Infrared Controller * - * Copyright (C) 2009 Andy Walls + * Copyright (C) 2009 Andy Walls * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/video/cx23885/cx23888-ir.h b/drivers/media/video/cx23885/cx23888-ir.h index 3d446f9eb94b..d2de41caaf1d 100644 --- a/drivers/media/video/cx23885/cx23888-ir.h +++ b/drivers/media/video/cx23885/cx23888-ir.h @@ -3,7 +3,7 @@ * * CX23888 Integrated Consumer Infrared Controller * - * Copyright (C) 2009 Andy Walls + * Copyright (C) 2009 Andy Walls * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License -- cgit v1.2.3 From 064a2485aa45956cf1e8520e716839e9d7555b90 Mon Sep 17 00:00:00 2001 From: Ian Armstrong Date: Sun, 23 May 2010 21:56:33 -0300 Subject: V4L/DVB: cx2341x: Report correct temporal setting for log-status [Andy Walls comment:] This patch from Ian removes the cx2341x module lying about the setting of the temporal filter for the log status ioctl(). Signed-off-by: Ian Armstrong Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx2341x.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c index 022b480918cd..2bf44ef10fec 100644 --- a/drivers/media/video/cx2341x.c +++ b/drivers/media/video/cx2341x.c @@ -1113,7 +1113,6 @@ invalid: void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix) { int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; - int temporal = p->video_temporal_filter; /* Stream */ printk(KERN_INFO "%s: Stream: %s", @@ -1179,14 +1178,11 @@ void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix) V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE), p->video_spatial_filter); - if (p->width != 720 || p->height != (p->is_50hz ? 576 : 480)) - temporal = 0; - printk(KERN_INFO "%s: Temporal Filter: %s, %d\n", prefix, cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE), - temporal); + p->video_temporal_filter); printk(KERN_INFO "%s: Median Filter: %s, Luma [%d, %d], Chroma [%d, %d]\n", prefix, -- cgit v1.2.3 From 5f39b9f660778c3b095fc380da178d58a040add5 Mon Sep 17 00:00:00 2001 From: Ian Armstrong Date: Sun, 23 May 2010 22:10:30 -0300 Subject: V4L/DVB: ivtvfb : Module load / unload fixes Check firmware state when loading module & if firmware is not responding exit with an error. When module is unloaded, only disable the framebuffer & not all decoder output. Signed-off-by: Ian Armstrong Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtvfb.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c index 49e1a283ed36..9ff3425891ed 100644 --- a/drivers/media/video/ivtv/ivtvfb.c +++ b/drivers/media/video/ivtv/ivtvfb.c @@ -1066,7 +1066,11 @@ static int ivtvfb_init_io(struct ivtv *itv) } mutex_unlock(&itv->serialize_lock); - ivtvfb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size); + if (ivtvfb_get_framebuffer(itv, &oi->video_rbase, + &oi->video_buffer_size) < 0) { + IVTVFB_ERR("Firmware failed to respond\n"); + return -EIO; + } /* The osd buffer size depends on the number of video buffers allocated on the PVR350 itself. For now we'll hardcode the smallest osd buffer @@ -1158,8 +1162,11 @@ static int ivtvfb_init_card(struct ivtv *itv) } /* Find & setup the OSD buffer */ - if ((rc = ivtvfb_init_io(itv))) + rc = ivtvfb_init_io(itv); + if (rc) { + ivtvfb_release_buffers(itv); return rc; + } /* Set the startup video mode information */ if ((rc = ivtvfb_init_vidmode(itv))) { @@ -1210,6 +1217,7 @@ static int ivtvfb_callback_cleanup(struct device *dev, void *p) { struct v4l2_device *v4l2_dev = dev_get_drvdata(dev); struct ivtv *itv = container_of(v4l2_dev, struct ivtv, v4l2_dev); + struct osd_info *oi = itv->osd_info; if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { if (unregister_framebuffer(&itv->osd_info->ivtvfb_info)) { @@ -1218,7 +1226,7 @@ static int ivtvfb_callback_cleanup(struct device *dev, void *p) return 0; } IVTVFB_INFO("Unregister framebuffer %d\n", itv->instance); - ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info); + ivtvfb_blank(FB_BLANK_VSYNC_SUSPEND, &oi->ivtvfb_info); ivtvfb_release_buffers(itv); itv->osd_video_pbase = 0; } -- cgit v1.2.3 From bd62307b20ff864c48541e46c3ee2bb9cc330f64 Mon Sep 17 00:00:00 2001 From: Ian Armstrong Date: Sun, 23 May 2010 22:19:11 -0300 Subject: V4L/DVB: ivtv: Avoid accidental video standard change For yuv video output, pass fake values to avoid firmware trying to change video standard. Signed-off-by: Ian Armstrong Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-streams.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index de4288cc1889..5441dc205966 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -618,12 +618,17 @@ static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s) struct ivtv *itv = s->itv; struct cx2341x_mpeg_params *p = &itv->params; int datatype; + u16 width; + u16 height; if (s->vdev == NULL) return -EINVAL; IVTV_DEBUG_INFO("Setting some initial decoder settings\n"); + width = p->width; + height = p->height; + /* set audio mode to left/stereo for dual/stereo mode. */ ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode); @@ -646,7 +651,14 @@ static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s) 2 = yuv_from_host */ switch (s->type) { case IVTV_DEC_STREAM_TYPE_YUV: - datatype = itv->output_mode == OUT_PASSTHROUGH ? 1 : 2; + if (itv->output_mode == OUT_PASSTHROUGH) { + datatype = 1; + } else { + /* Fake size to avoid switching video standard */ + datatype = 2; + width = 720; + height = itv->is_out_50hz ? 576 : 480; + } IVTV_DEBUG_INFO("Setup DEC YUV Stream data[0] = %d\n", datatype); break; case IVTV_DEC_STREAM_TYPE_MPG: @@ -655,7 +667,7 @@ static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s) break; } if (ivtv_vapi(itv, CX2341X_DEC_SET_DECODER_SOURCE, 4, datatype, - p->width, p->height, p->audio_properties)) { + width, height, p->audio_properties)) { IVTV_DEBUG_WARN("Couldn't initialize decoder source\n"); } return 0; -- cgit v1.2.3 From 666092c679f7d9eb9f5230087f960a487fda721c Mon Sep 17 00:00:00 2001 From: Ian Armstrong Date: Sun, 23 May 2010 22:27:49 -0300 Subject: V4L/DVB: ivtv: Timing tweaks and code re-order to try and improve stability Added small delay on device open & close to allow hardware to settle. Move yuv register restore to before the decoder firmware call to stop playback. Signed-off-by: Ian Armstrong Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fileops.c | 11 +++++++---- drivers/media/video/ivtv/ivtv-streams.c | 7 +++++++ 2 files changed, 14 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index abf410943cc9..3c2cc270ccd5 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -823,6 +823,12 @@ static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts) IVTV_DEBUG_FILE("close() of %s\n", s->name); + if (id->type == IVTV_DEC_STREAM_TYPE_YUV && + test_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags)) { + /* Restore registers we've changed & clean up any mess */ + ivtv_yuv_close(itv); + } + /* Stop decoding */ if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { IVTV_DEBUG_INFO("close stopping decode\n"); @@ -832,10 +838,7 @@ static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts) } clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); - if (id->type == IVTV_DEC_STREAM_TYPE_YUV && test_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags)) { - /* Restore registers we've changed & clean up any mess we've made */ - ivtv_yuv_close(itv); - } + if (itv->output_mode == OUT_UDMA_YUV && id->yuv_frames) itv->output_mode = OUT_NONE; diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 5441dc205966..9ecacab4b89b 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -670,6 +670,10 @@ static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s) width, height, p->audio_properties)) { IVTV_DEBUG_WARN("Couldn't initialize decoder source\n"); } + + /* Decoder sometimes dies here, so wait a moment */ + ivtv_msleep_timeout(10, 0); + return 0; } @@ -709,6 +713,9 @@ int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset) /* start playback */ ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, gop_offset, 0); + /* Let things settle before we actually start */ + ivtv_msleep_timeout(10, 0); + /* Clear the following Interrupt mask bits for decoding */ ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_DECODE); IVTV_DEBUG_IRQ("IRQ Mask is now: 0x%08x\n", itv->irqmask); -- cgit v1.2.3 From f07ff97b012ff9485618faeadcc9b1e5f72ceefa Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 1 Jun 2010 07:42:03 +0200 Subject: usb/gadget: Replace the old USB audio FU definitions in f_audio.c The USB audio FU definitions were renewed by the commit 65f25da44b51f55e3a74301c25f29263be2bf1ba ALSA: usb-audio: unify constants from specification Signed-off-by: Takashi Iwai --- drivers/usb/gadget/f_audio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_audio.c b/drivers/usb/gadget/f_audio.c index 43bf44514c41..b91115f84b13 100644 --- a/drivers/usb/gadget/f_audio.c +++ b/drivers/usb/gadget/f_audio.c @@ -101,7 +101,7 @@ static struct uac_feature_unit_descriptor_0 feature_unit_desc = { static struct usb_audio_control mute_control = { .list = LIST_HEAD_INIT(mute_control.list), .name = "Mute Control", - .type = UAC_MUTE_CONTROL, + .type = UAC_FU_MUTE, /* Todo: add real Mute control code */ .set = generic_set_cmd, .get = generic_get_cmd, @@ -110,7 +110,7 @@ static struct usb_audio_control mute_control = { static struct usb_audio_control volume_control = { .list = LIST_HEAD_INIT(volume_control.list), .name = "Volume Control", - .type = UAC_VOLUME_CONTROL, + .type = UAC_FU_VOLUME, /* Todo: add real Volume control code */ .set = generic_set_cmd, .get = generic_get_cmd, -- cgit v1.2.3 From b7c335713ea130d707c22d7f7c57a8eca75ded7e Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Wed, 26 May 2010 15:41:14 +0200 Subject: brd: support discard Support discard requests in brd by zeroing or deleting the underlying backing pages. This is simply to help with testing and documentation nature of brd code. Signed-off-by: Nick Piggin Signed-off-by: Jens Axboe --- drivers/block/brd.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/brd.c b/drivers/block/brd.c index 6081e81d5738..f1bf79d9bc0a 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -133,6 +133,28 @@ static struct page *brd_insert_page(struct brd_device *brd, sector_t sector) return page; } +static void brd_free_page(struct brd_device *brd, sector_t sector) +{ + struct page *page; + pgoff_t idx; + + spin_lock(&brd->brd_lock); + idx = sector >> PAGE_SECTORS_SHIFT; + page = radix_tree_delete(&brd->brd_pages, idx); + spin_unlock(&brd->brd_lock); + if (page) + __free_page(page); +} + +static void brd_zero_page(struct brd_device *brd, sector_t sector) +{ + struct page *page; + + page = brd_lookup_page(brd, sector); + if (page) + clear_highpage(page); +} + /* * Free all backing store pages and radix tree. This must only be called when * there are no other users of the device. @@ -189,6 +211,24 @@ static int copy_to_brd_setup(struct brd_device *brd, sector_t sector, size_t n) return 0; } +static void discard_from_brd(struct brd_device *brd, + sector_t sector, size_t n) +{ + while (n >= PAGE_SIZE) { + /* + * Don't want to actually discard pages here because + * re-allocating the pages can result in writeback + * deadlocks under heavy load. + */ + if (0) + brd_free_page(brd, sector); + else + brd_zero_page(brd, sector); + sector += PAGE_SIZE >> SECTOR_SHIFT; + n -= PAGE_SIZE; + } +} + /* * Copy n bytes from src to the brd starting at sector. Does not sleep. */ @@ -300,6 +340,12 @@ static int brd_make_request(struct request_queue *q, struct bio *bio) get_capacity(bdev->bd_disk)) goto out; + if (unlikely(bio_rw_flagged(bio, BIO_RW_DISCARD))) { + err = 0; + discard_from_brd(brd, sector, bio->bi_size); + goto out; + } + rw = bio_rw(bio); if (rw == READA) rw = READ; @@ -320,7 +366,7 @@ out: } #ifdef CONFIG_BLK_DEV_XIP -static int brd_direct_access (struct block_device *bdev, sector_t sector, +static int brd_direct_access(struct block_device *bdev, sector_t sector, void **kaddr, unsigned long *pfn) { struct brd_device *brd = bdev->bd_disk->private_data; @@ -437,6 +483,11 @@ static struct brd_device *brd_alloc(int i) blk_queue_max_hw_sectors(brd->brd_queue, 1024); blk_queue_bounce_limit(brd->brd_queue, BLK_BOUNCE_ANY); + brd->brd_queue->limits.discard_granularity = PAGE_SIZE; + brd->brd_queue->limits.max_discard_sectors = UINT_MAX; + brd->brd_queue->limits.discard_zeroes_data = 1; + queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, brd->brd_queue); + disk = brd->brd_disk = alloc_disk(1 << part_shift); if (!disk) goto out_free_queue; -- cgit v1.2.3 From 2c8d196759054b632788633b20e39167df36041d Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Tue, 25 May 2010 14:32:03 +0200 Subject: drbd: Revert "drbd: Create new current UUID as late as possible" The late-UUID writing is delayed until the next release. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg Signed-off-by: Jens Axboe --- drivers/block/drbd/drbd_int.h | 9 +-------- drivers/block/drbd/drbd_main.c | 34 ++++++---------------------------- drivers/block/drbd/drbd_receiver.c | 11 ----------- 3 files changed, 7 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index e9654c8d5b62..c194348a46ed 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -943,8 +943,7 @@ struct drbd_conf { struct drbd_work resync_work, unplug_work, md_sync_work, - delay_probe_work, - uuid_work; + delay_probe_work; struct timer_list resync_timer; struct timer_list md_sync_timer; struct timer_list delay_probe_timer; @@ -1069,7 +1068,6 @@ struct drbd_conf { struct timeval dps_time; /* delay-probes-start-time */ unsigned int dp_volume_last; /* send_cnt of last delay probe */ int c_sync_rate; /* current resync rate after delay_probe magic */ - atomic_t new_c_uuid; }; static inline struct drbd_conf *minor_to_mdev(unsigned int minor) @@ -2219,8 +2217,6 @@ static inline int __inc_ap_bio_cond(struct drbd_conf *mdev) return 0; if (test_bit(BITMAP_IO, &mdev->flags)) return 0; - if (atomic_read(&mdev->new_c_uuid)) - return 0; return 1; } @@ -2241,9 +2237,6 @@ static inline void inc_ap_bio(struct drbd_conf *mdev, int count) * to avoid races with the reconnect code, * we need to atomic_inc within the spinlock. */ - if (atomic_read(&mdev->new_c_uuid) && atomic_add_unless(&mdev->new_c_uuid, -1, 1)) - drbd_queue_work_front(&mdev->data.work, &mdev->uuid_work); - spin_lock_irq(&mdev->req_lock); while (!__inc_ap_bio_cond(mdev)) { prepare_to_wait(&mdev->misc_wait, &wait, TASK_UNINTERRUPTIBLE); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index be2d2da9cdba..1fcf2d1bcc39 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1215,18 +1215,17 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, ns.pdsk == D_OUTDATED)) { if (get_ldev(mdev)) { if ((ns.role == R_PRIMARY || ns.peer == R_PRIMARY) && - mdev->ldev->md.uuid[UI_BITMAP] == 0 && ns.disk >= D_UP_TO_DATE && - !atomic_read(&mdev->new_c_uuid)) - atomic_set(&mdev->new_c_uuid, 2); + mdev->ldev->md.uuid[UI_BITMAP] == 0 && ns.disk >= D_UP_TO_DATE) { + drbd_uuid_new_current(mdev); + drbd_send_uuids(mdev); + } put_ldev(mdev); } } if (ns.pdsk < D_INCONSISTENT && get_ldev(mdev)) { - /* Diskless peer becomes primary or got connected do diskless, primary peer. */ - if (ns.peer == R_PRIMARY && mdev->ldev->md.uuid[UI_BITMAP] == 0 && - !atomic_read(&mdev->new_c_uuid)) - atomic_set(&mdev->new_c_uuid, 2); + if (ns.peer == R_PRIMARY && mdev->ldev->md.uuid[UI_BITMAP] == 0) + drbd_uuid_new_current(mdev); /* D_DISKLESS Peer becomes secondary */ if (os.peer == R_PRIMARY && ns.peer == R_SECONDARY) @@ -1350,24 +1349,6 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, drbd_md_sync(mdev); } -static int w_new_current_uuid(struct drbd_conf *mdev, struct drbd_work *w, int cancel) -{ - if (get_ldev(mdev)) { - if (mdev->ldev->md.uuid[UI_BITMAP] == 0) { - drbd_uuid_new_current(mdev); - if (get_net_conf(mdev)) { - drbd_send_uuids(mdev); - put_net_conf(mdev); - } - drbd_md_sync(mdev); - } - put_ldev(mdev); - } - atomic_dec(&mdev->new_c_uuid); - wake_up(&mdev->misc_wait); - - return 1; -} static int drbd_thread_setup(void *arg) { @@ -2708,7 +2689,6 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) atomic_set(&mdev->net_cnt, 0); atomic_set(&mdev->packet_seq, 0); atomic_set(&mdev->pp_in_use, 0); - atomic_set(&mdev->new_c_uuid, 0); mutex_init(&mdev->md_io_mutex); mutex_init(&mdev->data.mutex); @@ -2739,14 +2719,12 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) INIT_LIST_HEAD(&mdev->bm_io_work.w.list); INIT_LIST_HEAD(&mdev->delay_probes); INIT_LIST_HEAD(&mdev->delay_probe_work.list); - INIT_LIST_HEAD(&mdev->uuid_work.list); mdev->resync_work.cb = w_resync_inactive; mdev->unplug_work.cb = w_send_write_hint; mdev->md_sync_work.cb = w_md_sync; mdev->bm_io_work.w.cb = w_bitmap_io; mdev->delay_probe_work.cb = w_delay_probes; - mdev->uuid_work.cb = w_new_current_uuid; init_timer(&mdev->resync_timer); init_timer(&mdev->md_sync_timer); init_timer(&mdev->delay_probe_timer); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index bc9ab7fb2cc7..a56340dd5710 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1154,17 +1154,6 @@ int drbd_submit_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e, unsigned n_bios = 0; unsigned nr_pages = (ds + PAGE_SIZE -1) >> PAGE_SHIFT; - if (atomic_read(&mdev->new_c_uuid)) { - if (atomic_add_unless(&mdev->new_c_uuid, -1, 1)) { - drbd_uuid_new_current(mdev); - drbd_md_sync(mdev); - - atomic_dec(&mdev->new_c_uuid); - wake_up(&mdev->misc_wait); - } - wait_event(mdev->misc_wait, !atomic_read(&mdev->new_c_uuid)); - } - /* In most cases, we will only need one bio. But in case the lower * level restrictions happen to be different at this offset on this * side than those of the sending peer, we may need to submit the -- cgit v1.2.3 From 344fa462e3246bd102059ccc3c59deef416676dd Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Tue, 25 May 2010 14:23:57 +0200 Subject: drbd: improve network latency, TCP_QUICKACK On Thu, Apr 29, 2010 at 04:00:50PM -0400, Eduard.Guzovsky@stratus.com wrote on drbd-dev@lists.linbit.com Subject: [Drbd-dev] DRBD small synchronous writes performance improvements > 1. TCP_QUICKACK option is set incorrectly. The goal was force TCP to > send and ACK as a "one time" event. Instead the code permanently sets > connection in the QUICKACK mode. He is right, we actually want to use an even val with TCP_QUICKACK. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg Signed-off-by: Jens Axboe --- drivers/block/drbd/drbd_int.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index c194348a46ed..6d79a76ba597 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1540,7 +1540,7 @@ static inline void drbd_tcp_nodelay(struct socket *sock) static inline void drbd_tcp_quickack(struct socket *sock) { - int __user val = 1; + int __user val = 2; (void) drbd_setsockopt(sock, SOL_TCP, TCP_QUICKACK, (char __user *)&val, sizeof(val)); } -- cgit v1.2.3 From 5dbf1673383f2f1554f0634fdfc390d59dc2c7d6 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Tue, 25 May 2010 16:18:01 +0200 Subject: drbd: need to set socket bufsize early to take effect quoting tcp(7): On individual connections, the socket buffer size must be set prior to the listen(2) or connect(2) calls in order to have it take effect. This adds a wrapper to do so, and uses it appropriately. Improves performance in certain situations. Note that because we cannot easily determine which socket will be "meta" and wich "data" (bulk) socket, we adjust both sockets. Previously, DRBD only adjusted the bufsizes of the "data" socket. Thanks again to Eduard.Guzovsky@stratus.com. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg Signed-off-by: Jens Axboe --- drivers/block/drbd/drbd_receiver.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index a56340dd5710..f9a3e199e715 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -571,6 +571,25 @@ static int drbd_recv(struct drbd_conf *mdev, void *buf, size_t size) return rv; } +/* quoting tcp(7): + * On individual connections, the socket buffer size must be set prior to the + * listen(2) or connect(2) calls in order to have it take effect. + * This is our wrapper to do so. + */ +static void drbd_setbufsize(struct socket *sock, unsigned int snd, + unsigned int rcv) +{ + /* open coded SO_SNDBUF, SO_RCVBUF */ + if (snd) { + sock->sk->sk_sndbuf = snd; + sock->sk->sk_userlocks |= SOCK_SNDBUF_LOCK; + } + if (rcv) { + sock->sk->sk_rcvbuf = rcv; + sock->sk->sk_userlocks |= SOCK_RCVBUF_LOCK; + } +} + static struct socket *drbd_try_connect(struct drbd_conf *mdev) { const char *what; @@ -592,6 +611,8 @@ static struct socket *drbd_try_connect(struct drbd_conf *mdev) sock->sk->sk_rcvtimeo = sock->sk->sk_sndtimeo = mdev->net_conf->try_connect_int*HZ; + drbd_setbufsize(sock, mdev->net_conf->sndbuf_size, + mdev->net_conf->rcvbuf_size); /* explicitly bind to the configured IP as source IP * for the outgoing connections. @@ -670,6 +691,8 @@ static struct socket *drbd_wait_for_connect(struct drbd_conf *mdev) s_listen->sk->sk_reuse = 1; /* SO_REUSEADDR */ s_listen->sk->sk_rcvtimeo = timeo; s_listen->sk->sk_sndtimeo = timeo; + drbd_setbufsize(s_listen, mdev->net_conf->sndbuf_size, + mdev->net_conf->rcvbuf_size); what = "bind before listen"; err = s_listen->ops->bind(s_listen, @@ -856,16 +879,6 @@ retry: sock->sk->sk_priority = TC_PRIO_INTERACTIVE_BULK; msock->sk->sk_priority = TC_PRIO_INTERACTIVE; - if (mdev->net_conf->sndbuf_size) { - sock->sk->sk_sndbuf = mdev->net_conf->sndbuf_size; - sock->sk->sk_userlocks |= SOCK_SNDBUF_LOCK; - } - - if (mdev->net_conf->rcvbuf_size) { - sock->sk->sk_rcvbuf = mdev->net_conf->rcvbuf_size; - sock->sk->sk_userlocks |= SOCK_RCVBUF_LOCK; - } - /* NOT YET ... * sock->sk->sk_sndtimeo = mdev->net_conf->timeout*HZ/10; * sock->sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT; -- cgit v1.2.3 From ba11ad9a3b9dd2dbb9c6686ea9d41a9a77d94327 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Tue, 25 May 2010 16:26:16 +0200 Subject: drbd: improve usage of MSG_MORE It seems to improve performance if we allow the "p_data" header in its own frame (no MSG_MORE), but sendpage all but the last page with MSG_MORE. This is also in preparation of a later zero copy receive implementation. Suggested by Eduard.Guzovsky@stratus.com on drbd-dev. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg Signed-off-by: Jens Axboe --- drivers/block/drbd/drbd_main.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 1fcf2d1bcc39..c978557b4b80 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2272,9 +2272,9 @@ static int we_should_drop_the_connection(struct drbd_conf *mdev, struct socket * * with page_count == 0 or PageSlab. */ static int _drbd_no_send_page(struct drbd_conf *mdev, struct page *page, - int offset, size_t size) + int offset, size_t size, unsigned msg_flags) { - int sent = drbd_send(mdev, mdev->data.socket, kmap(page) + offset, size, 0); + int sent = drbd_send(mdev, mdev->data.socket, kmap(page) + offset, size, msg_flags); kunmap(page); if (sent == size) mdev->send_cnt += size>>9; @@ -2282,7 +2282,7 @@ static int _drbd_no_send_page(struct drbd_conf *mdev, struct page *page, } static int _drbd_send_page(struct drbd_conf *mdev, struct page *page, - int offset, size_t size) + int offset, size_t size, unsigned msg_flags) { mm_segment_t oldfs = get_fs(); int sent, ok; @@ -2295,14 +2295,15 @@ static int _drbd_send_page(struct drbd_conf *mdev, struct page *page, * __page_cache_release a page that would actually still be referenced * by someone, leading to some obscure delayed Oops somewhere else. */ if (disable_sendpage || (page_count(page) < 1) || PageSlab(page)) - return _drbd_no_send_page(mdev, page, offset, size); + return _drbd_no_send_page(mdev, page, offset, size, msg_flags); + msg_flags |= MSG_NOSIGNAL; drbd_update_congested(mdev); set_fs(KERNEL_DS); do { sent = mdev->data.socket->ops->sendpage(mdev->data.socket, page, offset, len, - MSG_NOSIGNAL); + msg_flags); if (sent == -EAGAIN) { if (we_should_drop_the_connection(mdev, mdev->data.socket)) @@ -2331,9 +2332,11 @@ static int _drbd_send_bio(struct drbd_conf *mdev, struct bio *bio) { struct bio_vec *bvec; int i; + /* hint all but last page with MSG_MORE */ __bio_for_each_segment(bvec, bio, i, 0) { if (!_drbd_no_send_page(mdev, bvec->bv_page, - bvec->bv_offset, bvec->bv_len)) + bvec->bv_offset, bvec->bv_len, + i == bio->bi_vcnt -1 ? 0 : MSG_MORE)) return 0; } return 1; @@ -2343,12 +2346,13 @@ static int _drbd_send_zc_bio(struct drbd_conf *mdev, struct bio *bio) { struct bio_vec *bvec; int i; + /* hint all but last page with MSG_MORE */ __bio_for_each_segment(bvec, bio, i, 0) { if (!_drbd_send_page(mdev, bvec->bv_page, - bvec->bv_offset, bvec->bv_len)) + bvec->bv_offset, bvec->bv_len, + i == bio->bi_vcnt -1 ? 0 : MSG_MORE)) return 0; } - return 1; } @@ -2356,9 +2360,11 @@ static int _drbd_send_zc_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e) { struct page *page = e->pages; unsigned len = e->size; + /* hint all but last page with MSG_MORE */ page_chain_for_each(page) { unsigned l = min_t(unsigned, len, PAGE_SIZE); - if (!_drbd_send_page(mdev, page, 0, l)) + if (!_drbd_send_page(mdev, page, 0, l, + page_chain_next(page) ? MSG_MORE : 0)) return 0; len -= l; } @@ -2438,11 +2444,11 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req) p.dp_flags = cpu_to_be32(dp_flags); set_bit(UNPLUG_REMOTE, &mdev->flags); ok = (sizeof(p) == - drbd_send(mdev, mdev->data.socket, &p, sizeof(p), MSG_MORE)); + drbd_send(mdev, mdev->data.socket, &p, sizeof(p), dgs ? MSG_MORE : 0)); if (ok && dgs) { dgb = mdev->int_dig_out; drbd_csum_bio(mdev, mdev->integrity_w_tfm, req->master_bio, dgb); - ok = drbd_send(mdev, mdev->data.socket, dgb, dgs, MSG_MORE); + ok = drbd_send(mdev, mdev->data.socket, dgb, dgs, 0); } if (ok) { if (mdev->net_conf->wire_protocol == DRBD_PROT_A) @@ -2491,11 +2497,11 @@ int drbd_send_block(struct drbd_conf *mdev, enum drbd_packets cmd, return 0; ok = sizeof(p) == drbd_send(mdev, mdev->data.socket, &p, - sizeof(p), MSG_MORE); + sizeof(p), dgs ? MSG_MORE : 0); if (ok && dgs) { dgb = mdev->int_dig_out; drbd_csum_ee(mdev, mdev->integrity_w_tfm, e, dgb); - ok = drbd_send(mdev, mdev->data.socket, dgb, dgs, MSG_MORE); + ok = drbd_send(mdev, mdev->data.socket, dgb, dgs, 0); } if (ok) ok = _drbd_send_zc_ee(mdev, e); -- cgit v1.2.3 From 039e1fb65496636778e24c881a5e58ed7c39fbb3 Mon Sep 17 00:00:00 2001 From: Andrea Gelmini Date: Sun, 23 May 2010 21:48:13 +0200 Subject: drbd: removed duplicated #includes drbd/drbd_receiver.c: linux/mm.h is included more than once. Signed-off-by: Andrea Gelmini Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg Signed-off-by: Jens Axboe --- drivers/block/drbd/drbd_receiver.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index f9a3e199e715..dff48701b84d 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -42,7 +42,6 @@ #include #include #include -#include #include #include #include "drbd_int.h" -- cgit v1.2.3 From 32fa7e91f923d8b2578c42016ff3a94efc9968a2 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 26 May 2010 17:13:18 +0200 Subject: drbd: Removed the now empty w_io_error() function Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg Signed-off-by: Jens Axboe --- drivers/block/drbd/drbd_int.h | 1 - drivers/block/drbd/drbd_req.c | 27 +-------------------------- drivers/block/drbd/drbd_worker.c | 14 -------------- 3 files changed, 1 insertion(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 6d79a76ba597..86605f6d0854 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1474,7 +1474,6 @@ extern int w_e_end_ov_req(struct drbd_conf *, struct drbd_work *, int); extern int w_ov_finished(struct drbd_conf *, struct drbd_work *, int); extern int w_resync_inactive(struct drbd_conf *, struct drbd_work *, int); extern int w_resume_next_sg(struct drbd_conf *, struct drbd_work *, int); -extern int w_io_error(struct drbd_conf *, struct drbd_work *, int); extern int w_send_write_hint(struct drbd_conf *, struct drbd_work *, int); extern int w_make_resync_request(struct drbd_conf *, struct drbd_work *, int); extern int w_send_dblock(struct drbd_conf *, struct drbd_work *, int); diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 3397f11d0ba9..e6c4d579eaba 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -102,32 +102,7 @@ static void _req_is_done(struct drbd_conf *mdev, struct drbd_request *req, const } } - /* if it was a local io error, we want to notify our - * peer about that, and see if we need to - * detach the disk and stuff. - * to avoid allocating some special work - * struct, reuse the request. */ - - /* THINK - * why do we do this not when we detect the error, - * but delay it until it is "done", i.e. possibly - * until the next barrier ack? */ - - if (rw == WRITE && - ((s & RQ_LOCAL_MASK) && !(s & RQ_LOCAL_OK))) { - if (!(req->w.list.next == LIST_POISON1 || - list_empty(&req->w.list))) { - /* DEBUG ASSERT only; if this triggers, we - * probably corrupt the worker list here */ - dev_err(DEV, "req->w.list.next = %p\n", req->w.list.next); - dev_err(DEV, "req->w.list.prev = %p\n", req->w.list.prev); - } - req->w.cb = w_io_error; - drbd_queue_work(&mdev->data.work, &req->w); - /* drbd_req_free() is done in w_io_error */ - } else { - drbd_req_free(req); - } + drbd_req_free(req); } static void queue_barrier(struct drbd_conf *mdev) diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 727ff6339754..a12b447bafbd 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -257,20 +257,6 @@ void drbd_endio_pri(struct bio *bio, int error) complete_master_bio(mdev, &m); } -int w_io_error(struct drbd_conf *mdev, struct drbd_work *w, int cancel) -{ - struct drbd_request *req = container_of(w, struct drbd_request, w); - - /* NOTE: mdev->ldev can be NULL by the time we get here! */ - /* D_ASSERT(mdev->ldev->dc.on_io_error != EP_PASS_ON); */ - - /* the only way this callback is scheduled is from _req_may_be_done, - * when it is done and had a local write error, see comments there */ - drbd_req_free(req); - - return TRUE; -} - int w_read_retry_remote(struct drbd_conf *mdev, struct drbd_work *w, int cancel) { struct drbd_request *req = container_of(w, struct drbd_request, w); -- cgit v1.2.3 From d255e5ff5fc6cc6c60dd014d1261448a7bbc8134 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Thu, 27 May 2010 09:45:45 +0200 Subject: drbd: fix hang on local read errors while disconnected "canceled" w_read_retry_remote never completed, if they have been canceled after drbd_disconnect connection teardown cleanup has already run (or we are currently not connected anyways). Fixed by not queueing a remote retry if we already know it won't work (pdsk not uptodate), and cleanup ourselves on "cancel", in case we hit a race with drbd_disconnect. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg Signed-off-by: Jens Axboe --- drivers/block/drbd/drbd_req.c | 22 +++++++++++++--------- drivers/block/drbd/drbd_req.h | 1 + drivers/block/drbd/drbd_worker.c | 6 ++---- 3 files changed, 16 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index e6c4d579eaba..8915644af722 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -452,20 +452,21 @@ void __req_mod(struct drbd_request *req, enum drbd_req_event what, dev_alert(DEV, "Local READ failed sec=%llus size=%u\n", (unsigned long long)req->sector, req->size); - /* _req_mod(req,to_be_send); oops, recursion... */ D_ASSERT(!(req->rq_state & RQ_NET_MASK)); - req->rq_state |= RQ_NET_PENDING; - inc_ap_pending(mdev); __drbd_chk_io_error(mdev, FALSE); put_ldev(mdev); - /* NOTE: if we have no connection, - * or know the peer has no good data either, - * then we don't actually need to "queue_for_net_read", - * but we do so anyways, since the drbd_io_error() - * and the potential state change to "Diskless" - * needs to be done from process context */ + /* no point in retrying if there is no good remote data, + * or we have no connection. */ + if (mdev->state.pdsk != D_UP_TO_DATE) { + _req_may_be_done(req, m); + break; + } + + /* _req_mod(req,to_be_send); oops, recursion... */ + req->rq_state |= RQ_NET_PENDING; + inc_ap_pending(mdev); /* fall through: _req_mod(req,queue_for_net_read); */ case queue_for_net_read: @@ -575,6 +576,9 @@ void __req_mod(struct drbd_request *req, enum drbd_req_event what, _req_may_be_done(req, m); break; + case read_retry_remote_canceled: + req->rq_state &= ~RQ_NET_QUEUED; + /* fall through, in case we raced with drbd_disconnect */ case connection_lost_while_pending: /* transfer log cleanup after connection loss */ /* assert something? */ diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index 16119d7056cc..02d575d24518 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h @@ -91,6 +91,7 @@ enum drbd_req_event { send_failed, handed_over_to_network, connection_lost_while_pending, + read_retry_remote_canceled, recv_acked_by_peer, write_acked_by_peer, write_acked_by_peer_and_sis, /* and set_in_sync */ diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index a12b447bafbd..67371fcbc5aa 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -266,10 +266,8 @@ int w_read_retry_remote(struct drbd_conf *mdev, struct drbd_work *w, int cancel) * to give the disk the chance to relocate that block */ spin_lock_irq(&mdev->req_lock); - if (cancel || - mdev->state.conn < C_CONNECTED || - mdev->state.pdsk <= D_INCONSISTENT) { - _req_mod(req, send_canceled); + if (cancel || mdev->state.pdsk != D_UP_TO_DATE) { + _req_mod(req, read_retry_remote_canceled); spin_unlock_irq(&mdev->req_lock); dev_alert(DEV, "WE ARE LOST. Local IO failure, no peer.\n"); return 1; -- cgit v1.2.3 From 7383506c87237dbd627f0b8b72b50117f25c5ca2 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Thu, 27 May 2010 11:51:56 +0200 Subject: drbd: use drbd specific ratelimit instead of global printk_ratelimit using the global printk_ratelimit() may mask other messages. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg Signed-off-by: Jens Axboe --- drivers/block/drbd/drbd_int.h | 2 +- drivers/block/drbd/drbd_main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 86605f6d0854..485ed8c7d623 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1725,7 +1725,7 @@ static inline void __drbd_chk_io_error_(struct drbd_conf *mdev, int forcedetach, switch (mdev->ldev->dc.on_io_error) { case EP_PASS_ON: if (!forcedetach) { - if (printk_ratelimit()) + if (__ratelimit(&drbd_ratelimit_state)) dev_err(DEV, "Local IO failed in %s." "Passing error on...\n", where); break; diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index c978557b4b80..6b077f93acc6 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -3783,7 +3783,7 @@ _drbd_insert_fault(struct drbd_conf *mdev, unsigned int type) if (ret) { fault_count++; - if (printk_ratelimit()) + if (__ratelimit(&drbd_ratelimit_state)) dev_warn(DEV, "***Simulating %s failure\n", _drbd_fault_str(type)); } -- cgit v1.2.3 From 2a0ab2cd73c26835e635ed4e3868f983519048fb Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 26 May 2010 17:59:55 +0200 Subject: drbd: Reduce verbosity The "Local READ/WRITE failed" messages are too verbose. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg Signed-off-by: Jens Axboe --- drivers/block/drbd/drbd_req.c | 5 ----- drivers/block/drbd/drbd_worker.c | 4 ---- 2 files changed, 9 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 8915644af722..654f1ef5cbb0 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -428,9 +428,6 @@ void __req_mod(struct drbd_request *req, enum drbd_req_event what, req->rq_state |= RQ_LOCAL_COMPLETED; req->rq_state &= ~RQ_LOCAL_PENDING; - dev_alert(DEV, "Local WRITE failed sec=%llus size=%u\n", - (unsigned long long)req->sector, req->size); - /* and now: check how to handle local io error. */ __drbd_chk_io_error(mdev, FALSE); _req_may_be_done(req, m); put_ldev(mdev); @@ -450,8 +447,6 @@ void __req_mod(struct drbd_request *req, enum drbd_req_event what, req->rq_state |= RQ_LOCAL_COMPLETED; req->rq_state &= ~RQ_LOCAL_PENDING; - dev_alert(DEV, "Local READ failed sec=%llus size=%u\n", - (unsigned long long)req->sector, req->size); D_ASSERT(!(req->rq_state & RQ_NET_MASK)); __drbd_chk_io_error(mdev, FALSE); diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 67371fcbc5aa..b623ceee2a4a 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -224,9 +224,6 @@ void drbd_endio_pri(struct bio *bio, int error) enum drbd_req_event what; int uptodate = bio_flagged(bio, BIO_UPTODATE); - if (error) - dev_warn(DEV, "p %s: error=%d\n", - bio_data_dir(bio) == WRITE ? "write" : "read", error); if (!error && !uptodate) { dev_warn(DEV, "p %s: setting error to -EIO\n", bio_data_dir(bio) == WRITE ? "write" : "read"); @@ -269,7 +266,6 @@ int w_read_retry_remote(struct drbd_conf *mdev, struct drbd_work *w, int cancel) if (cancel || mdev->state.pdsk != D_UP_TO_DATE) { _req_mod(req, read_retry_remote_canceled); spin_unlock_irq(&mdev->req_lock); - dev_alert(DEV, "WE ARE LOST. Local IO failure, no peer.\n"); return 1; } spin_unlock_irq(&mdev->req_lock); -- cgit v1.2.3 From 713b686494a577b3c4f4f9f585a4705fc30d51c2 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 1 Jun 2010 12:17:48 +0200 Subject: cciss: call BUG() earlier I moved the range check after the increment. The current code would write past the end of the array once before calling BUG(). Signed-off-by: Dan Carpenter Signed-off-by: Jens Axboe --- drivers/block/cciss_scsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index e1d0e2cfec72..3381505c8a6c 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c @@ -188,11 +188,11 @@ scsi_cmd_free(ctlr_info_t *h, CommandList_struct *cmd) sa = h->scsi_ctlr; stk = &sa->cmd_stack; + stk->top++; if (stk->top >= CMD_STACK_SIZE) { printk("cciss: scsi_cmd_free called too many times.\n"); BUG(); } - stk->top++; stk->elem[stk->top] = (struct cciss_scsi_cmd_stack_elem_t *) cmd; } -- cgit v1.2.3 From 2e8949f09e3097c629f33323eaf280cf5c88c81a Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 1 Jun 2010 12:51:00 +0100 Subject: intel_scu_ipc: Length fix Commands with data must set the length in the message. Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/platform/x86/intel_scu_ipc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index 576c3ed92435..40658e3385b4 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -524,7 +524,7 @@ int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen, for (i = 0; i < inlen; i++) ipc_data_writel(*in++, 4 * i); - ipc_command(cmd << 12 | sub); + ipc_command((cmd << 12) | sub | (inlen << 18)); err = busy_loop(); for (i = 0; i < outlen; i++) -- cgit v1.2.3 From e29df91e67428c1a651d18df6ec047fcb30282d3 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 28 May 2010 12:33:15 +0200 Subject: SFI: do not return freed pointer We never actually use the return value of sfi_sysfs_install_table() but it still seems wrong to return a freed pointer. Signed-off-by: Dan Carpenter Signed-off-by: Len Brown --- drivers/sfi/sfi_core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/sfi/sfi_core.c b/drivers/sfi/sfi_core.c index 005195958647..ceba593dc84f 100644 --- a/drivers/sfi/sfi_core.c +++ b/drivers/sfi/sfi_core.c @@ -441,8 +441,10 @@ struct sfi_table_attr __init *sfi_sysfs_install_table(u64 pa) ret = sysfs_create_bin_file(tables_kobj, &tbl_attr->attr); - if (ret) + if (ret) { kfree(tbl_attr); + tbl_attr = NULL; + } sfi_unmap_table(th); return tbl_attr; -- cgit v1.2.3 From 9bc354998f8aa8a83b0cd430e8fcf2cbc3be7367 Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Fri, 28 May 2010 17:17:37 -0400 Subject: drm/i915: Honor sync polarity from VBT panel timing descriptors I'm actually kind of shocked that it works at all otherwise. Signed-off-by: Adam Jackson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_bios.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 4c748d8f73d6..96f75d7f6633 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -95,6 +95,16 @@ fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, panel_fixed_mode->clock = dvo_timing->clock * 10; panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED; + if (dvo_timing->hsync_positive) + panel_fixed_mode->flags |= DRM_MODE_FLAG_PHSYNC; + else + panel_fixed_mode->flags |= DRM_MODE_FLAG_NHSYNC; + + if (dvo_timing->vsync_positive) + panel_fixed_mode->flags |= DRM_MODE_FLAG_PVSYNC; + else + panel_fixed_mode->flags |= DRM_MODE_FLAG_NVSYNC; + /* Some VBTs have bogus h/vtotal values */ if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal) panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1; -- cgit v1.2.3 From e3a815fcd38043b8f1bb526123d8ab6ae01deb77 Mon Sep 17 00:00:00 2001 From: Zou Nan hai Date: Mon, 31 May 2010 13:58:47 +0800 Subject: drm/i915: add HAS_BSD check to i915_getparam This will let userland only try to use the new media decode functionality when the appropriate kernel is present. Signed-off-by: Zou Nan hai Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_dma.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 6577798d3441..84ce95602f00 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -744,6 +744,9 @@ static int i915_getparam(struct drm_device *dev, void *data, /* depends on GEM */ value = dev_priv->has_gem; break; + case I915_PARAM_HAS_BSD: + value = HAS_BSD(dev); + break; default: DRM_DEBUG_DRIVER("Unknown parameter %d\n", param->param); -- cgit v1.2.3 From f7a2e30246281944064113dafbafe3eb14cd89e3 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 1 Jun 2010 21:29:40 -0700 Subject: Input: tps6507x-ts - a couple work queue cleanups 1) Use msecs_to_jiffies() instead of calculating by hand. 2) Call cancel_delayed_work_sync() instead of cancel_delayed_work() followed by a separate flush_workqueue(). 3) Remove the "tsc->wq = 0;" Sparse complains about that because tsc->wq is a pointer, not an int. It's not needed because we just free the pointer anyway. Signed-off-by: Dan Carpenter Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tps6507x-ts.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tps6507x-ts.c b/drivers/input/touchscreen/tps6507x-ts.c index 5de80a1a730b..5b70a1419b4d 100644 --- a/drivers/input/touchscreen/tps6507x-ts.c +++ b/drivers/input/touchscreen/tps6507x-ts.c @@ -221,7 +221,7 @@ done: if (poll) { schd = queue_delayed_work(tsc->wq, &tsc->work, - tsc->poll_period * HZ / 1000); + msecs_to_jiffies(tsc->poll_period)); if (schd) tsc->polling = 1; else { @@ -326,7 +326,7 @@ static int tps6507x_ts_probe(struct platform_device *pdev) goto err2; schd = queue_delayed_work(tsc->wq, &tsc->work, - tsc->poll_period * HZ / 1000); + msecs_to_jiffies(tsc->poll_period)); if (schd) tsc->polling = 1; @@ -339,10 +339,8 @@ static int tps6507x_ts_probe(struct platform_device *pdev) return 0; err2: - cancel_delayed_work(&tsc->work); - flush_workqueue(tsc->wq); + cancel_delayed_work_sync(&tsc->work); destroy_workqueue(tsc->wq); - tsc->wq = 0; input_free_device(input_dev); err1: kfree(tsc); @@ -360,10 +358,8 @@ static int __devexit tps6507x_ts_remove(struct platform_device *pdev) if (!tsc) return 0; - cancel_delayed_work(&tsc->work); - flush_workqueue(tsc->wq); + cancel_delayed_work_sync(&tsc->work); destroy_workqueue(tsc->wq); - tsc->wq = 0; input_free_device(input_dev); -- cgit v1.2.3 From abb24f4846d1537d73605e8576de8359a98e5ced Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 2 Jun 2010 16:26:13 +0900 Subject: usb: gadget: m66592-udc pio to mmio accessor conversion. m66592-udc is erroneously using PIO routines on MMIO registers, which presently blows up for any platform that elects to either override or do away with PIO routines. This managed to work for the common cases since the PIO routines were simply wrapped to their MMIO counterparts. This switches over to using the MMIO routines directly, and enables us to kill off a lot of superfluous casting in the process. Acked-by: Yoshihiro Shimoda Signed-off-by: Paul Mundt --- drivers/usb/gadget/m66592-udc.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h index 8b960deed680..c3caf1ac73ce 100644 --- a/drivers/usb/gadget/m66592-udc.h +++ b/drivers/usb/gadget/m66592-udc.h @@ -537,35 +537,35 @@ struct m66592 { /*-------------------------------------------------------------------------*/ static inline u16 m66592_read(struct m66592 *m66592, unsigned long offset) { - return inw((unsigned long)m66592->reg + offset); + return ioread16(m66592->reg + offset); } static inline void m66592_read_fifo(struct m66592 *m66592, unsigned long offset, void *buf, unsigned long len) { - unsigned long fifoaddr = (unsigned long)m66592->reg + offset; + void __iomem *fifoaddr = m66592->reg + offset; if (m66592->pdata->on_chip) { len = (len + 3) / 4; - insl(fifoaddr, buf, len); + ioread32_rep(fifoaddr, buf, len); } else { len = (len + 1) / 2; - insw(fifoaddr, buf, len); + ioread16_rep(fifoaddr, buf, len); } } static inline void m66592_write(struct m66592 *m66592, u16 val, unsigned long offset) { - outw(val, (unsigned long)m66592->reg + offset); + iowrite16(val, m66592->reg + offset); } static inline void m66592_write_fifo(struct m66592 *m66592, unsigned long offset, void *buf, unsigned long len) { - unsigned long fifoaddr = (unsigned long)m66592->reg + offset; + void __iomem *fifoaddr = m66592->reg + offset; if (m66592->pdata->on_chip) { unsigned long count; @@ -573,25 +573,25 @@ static inline void m66592_write_fifo(struct m66592 *m66592, int i; count = len / 4; - outsl(fifoaddr, buf, count); + iowrite32_rep(fifoaddr, buf, count); if (len & 0x00000003) { pb = buf + count * 4; for (i = 0; i < (len & 0x00000003); i++) { if (m66592_read(m66592, M66592_CFBCFG)) /* le */ - outb(pb[i], fifoaddr + (3 - i)); + iowrite8(pb[i], fifoaddr + (3 - i)); else - outb(pb[i], fifoaddr + i); + iowrite8(pb[i], fifoaddr + i); } } } else { unsigned long odd = len & 0x0001; len = len / 2; - outsw(fifoaddr, buf, len); + iowrite16_rep(fifoaddr, buf, len); if (odd) { unsigned char *p = buf + len*2; - outb(*p, fifoaddr); + iowrite8(*p, fifoaddr); } } } -- cgit v1.2.3 From e8b48669de54d390644c77cd26d5c9fccbc1e0a1 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 2 Jun 2010 16:27:12 +0900 Subject: usb: gadget: r8a66597-udc pio to mmio accessor conversion. r8a66597-udc is erroneously using PIO routines on MMIO registers, which presently blows up for any platform that elects to either override or do away with PIO routines. This managed to work for the common cases since the PIO routines were simply wrapped to their MMIO counterparts. This switches over to using the MMIO routines directly, and enables us to kill off a lot of superfluous casting in the process. Acked-by: Yoshihiro Shimoda Signed-off-by: Paul Mundt --- drivers/usb/gadget/r8a66597-udc.c | 4 ++-- drivers/usb/gadget/r8a66597-udc.h | 24 ++++++++++++------------ 2 files changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 888d8f166c0b..70a817842755 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1500,7 +1500,7 @@ static int __exit r8a66597_remove(struct platform_device *pdev) struct r8a66597 *r8a66597 = dev_get_drvdata(&pdev->dev); del_timer_sync(&r8a66597->timer); - iounmap((void *)r8a66597->reg); + iounmap(r8a66597->reg); free_irq(platform_get_irq(pdev, 0), r8a66597); r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req); #ifdef CONFIG_HAVE_CLK @@ -1578,7 +1578,7 @@ static int __init r8a66597_probe(struct platform_device *pdev) init_timer(&r8a66597->timer); r8a66597->timer.function = r8a66597_timer; r8a66597->timer.data = (unsigned long)r8a66597; - r8a66597->reg = (unsigned long)reg; + r8a66597->reg = reg; #ifdef CONFIG_HAVE_CLK if (r8a66597->pdata->on_chip) { diff --git a/drivers/usb/gadget/r8a66597-udc.h b/drivers/usb/gadget/r8a66597-udc.h index 9a537aa07968..f763b5190afa 100644 --- a/drivers/usb/gadget/r8a66597-udc.h +++ b/drivers/usb/gadget/r8a66597-udc.h @@ -91,7 +91,7 @@ struct r8a66597_ep { struct r8a66597 { spinlock_t lock; - unsigned long reg; + void __iomem *reg; #ifdef CONFIG_HAVE_CLK struct clk *clk; @@ -127,7 +127,7 @@ struct r8a66597 { static inline u16 r8a66597_read(struct r8a66597 *r8a66597, unsigned long offset) { - return inw(r8a66597->reg + offset); + return ioread16(r8a66597->reg + offset); } static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597, @@ -135,7 +135,7 @@ static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597, unsigned char *buf, int len) { - unsigned long fifoaddr = r8a66597->reg + offset; + void __iomem *fifoaddr = r8a66597->reg + offset; unsigned int data; int i; @@ -144,7 +144,7 @@ static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597, /* aligned buf case */ if (len >= 4 && !((unsigned long)buf & 0x03)) { - insl(fifoaddr, buf, len / 4); + ioread32_rep(fifoaddr, buf, len / 4); buf += len & ~0x03; len &= 0x03; } @@ -152,7 +152,7 @@ static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597, /* unaligned buf case */ for (i = 0; i < len; i++) { if (!(i & 0x03)) - data = inl(fifoaddr); + data = ioread32(fifoaddr); buf[i] = (data >> ((i & 0x03) * 8)) & 0xff; } @@ -161,7 +161,7 @@ static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597, /* aligned buf case */ if (len >= 2 && !((unsigned long)buf & 0x01)) { - insw(fifoaddr, buf, len / 2); + ioread16_rep(fifoaddr, buf, len / 2); buf += len & ~0x01; len &= 0x01; } @@ -169,7 +169,7 @@ static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597, /* unaligned buf case */ for (i = 0; i < len; i++) { if (!(i & 0x01)) - data = inw(fifoaddr); + data = ioread16(fifoaddr); buf[i] = (data >> ((i & 0x01) * 8)) & 0xff; } @@ -179,7 +179,7 @@ static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597, static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val, unsigned long offset) { - outw(val, r8a66597->reg + offset); + iowrite16(val, r8a66597->reg + offset); } static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597, @@ -187,21 +187,21 @@ static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597, unsigned char *buf, int len) { - unsigned long fifoaddr = r8a66597->reg + offset; + void __iomem *fifoaddr = r8a66597->reg + offset; int adj = 0; int i; if (r8a66597->pdata->on_chip) { /* 32-bit access only if buf is 32-bit aligned */ if (len >= 4 && !((unsigned long)buf & 0x03)) { - outsl(fifoaddr, buf, len / 4); + iowrite32_rep(fifoaddr, buf, len / 4); buf += len & ~0x03; len &= 0x03; } } else { /* 16-bit access only if buf is 16-bit aligned */ if (len >= 2 && !((unsigned long)buf & 0x01)) { - outsw(fifoaddr, buf, len / 2); + iowrite16_rep(fifoaddr, buf, len / 2); buf += len & ~0x01; len &= 0x01; } @@ -216,7 +216,7 @@ static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597, } for (i = 0; i < len; i++) - outb(buf[i], fifoaddr + adj - (i & adj)); + iowrite8(buf[i], fifoaddr + adj - (i & adj)); } static inline void r8a66597_mdfy(struct r8a66597 *r8a66597, -- cgit v1.2.3 From 1c98347e613bf17ea2f18c9766ce0ab77f65a96d Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 2 Jun 2010 16:27:54 +0900 Subject: usb: r8a66597-hcd pio to mmio accessor conversion. r8a66597-hcd is erroneously using PIO routines on MMIO registers, which presently blows up for any platform that elects to either override or do away with PIO routines. This managed to work for the common cases since the PIO routines were simply wrapped to their MMIO counterparts. This switches over to using the MMIO routines directly, and enables us to kill off a lot of superfluous casting in the process. Acked-by: Yoshihiro Shimoda Signed-off-by: Paul Mundt --- drivers/usb/host/r8a66597-hcd.c | 4 ++-- drivers/usb/host/r8a66597.h | 26 +++++++++++++------------- 2 files changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 6db57ab6079d..1a2bb4ce638f 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -2404,7 +2404,7 @@ static int __init_or_module r8a66597_remove(struct platform_device *pdev) del_timer_sync(&r8a66597->rh_timer); usb_remove_hcd(hcd); - iounmap((void *)r8a66597->reg); + iounmap(r8a66597->reg); #ifdef CONFIG_HAVE_CLK if (r8a66597->pdata->on_chip) clk_put(r8a66597->clk); @@ -2496,7 +2496,7 @@ static int __devinit r8a66597_probe(struct platform_device *pdev) init_timer(&r8a66597->rh_timer); r8a66597->rh_timer.function = r8a66597_timer; r8a66597->rh_timer.data = (unsigned long)r8a66597; - r8a66597->reg = (unsigned long)reg; + r8a66597->reg = reg; /* make sure no interrupts are pending */ ret = r8a66597_clock_enable(r8a66597); diff --git a/drivers/usb/host/r8a66597.h b/drivers/usb/host/r8a66597.h index 228e3fb23854..95d0f5adfdcf 100644 --- a/drivers/usb/host/r8a66597.h +++ b/drivers/usb/host/r8a66597.h @@ -112,7 +112,7 @@ struct r8a66597_root_hub { struct r8a66597 { spinlock_t lock; - unsigned long reg; + void __iomem *reg; #ifdef CONFIG_HAVE_CLK struct clk *clk; #endif @@ -170,67 +170,67 @@ static inline struct urb *r8a66597_get_urb(struct r8a66597 *r8a66597, static inline u16 r8a66597_read(struct r8a66597 *r8a66597, unsigned long offset) { - return inw(r8a66597->reg + offset); + return ioread16(r8a66597->reg + offset); } static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597, unsigned long offset, u16 *buf, int len) { - unsigned long fifoaddr = r8a66597->reg + offset; + void __iomem *fifoaddr = r8a66597->reg + offset; unsigned long count; if (r8a66597->pdata->on_chip) { count = len / 4; - insl(fifoaddr, buf, count); + ioread32_rep(fifoaddr, buf, count); if (len & 0x00000003) { - unsigned long tmp = inl(fifoaddr); + unsigned long tmp = ioread32(fifoaddr); memcpy((unsigned char *)buf + count * 4, &tmp, len & 0x03); } } else { len = (len + 1) / 2; - insw(fifoaddr, buf, len); + ioread16_rep(fifoaddr, buf, len); } } static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val, unsigned long offset) { - outw(val, r8a66597->reg + offset); + iowrite16(val, r8a66597->reg + offset); } static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597, unsigned long offset, u16 *buf, int len) { - unsigned long fifoaddr = r8a66597->reg + offset; + void __iomem *fifoaddr = r8a66597->reg + offset; unsigned long count; unsigned char *pb; int i; if (r8a66597->pdata->on_chip) { count = len / 4; - outsl(fifoaddr, buf, count); + iowrite32_rep(fifoaddr, buf, count); if (len & 0x00000003) { pb = (unsigned char *)buf + count * 4; for (i = 0; i < (len & 0x00000003); i++) { if (r8a66597_read(r8a66597, CFIFOSEL) & BIGEND) - outb(pb[i], fifoaddr + i); + iowrite8(pb[i], fifoaddr + i); else - outb(pb[i], fifoaddr + 3 - i); + iowrite8(pb[i], fifoaddr + 3 - i); } } } else { int odd = len & 0x0001; len = len / 2; - outsw(fifoaddr, buf, len); + ioread16_rep(fifoaddr, buf, len); if (unlikely(odd)) { buf = &buf[len]; - outb((unsigned char)*buf, fifoaddr); + iowrite8((unsigned char)*buf, fifoaddr); } } } -- cgit v1.2.3 From 56960b3602be6fde9f09c7958fa06b26384307cc Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 2 Jun 2010 00:40:06 -0700 Subject: Input: ads7846 - fix compiler warning in ads7846_probe() This patch fixes the follwing warning introduced by commit 067fb2f648543894ce775082c5636f4c32b99e4f ("Input: ads7846 - return error on regulator_get() failure"): drivers/input/touchscreen/ads7846.c: In function 'ads7846_probe': drivers/input/touchscreen/ads7846.c:1167: warning: format '%ld' expects type 'long int', but argument 4 has type 'int' Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 634f6f6b9b13..a9fdf55c0238 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -1164,7 +1164,7 @@ static int __devinit ads7846_probe(struct spi_device *spi) ts->reg = regulator_get(&spi->dev, "vcc"); if (IS_ERR(ts->reg)) { err = PTR_ERR(ts->reg); - dev_err(&spi->dev, "unable to get regulator: %ld\n", err); + dev_err(&spi->dev, "unable to get regulator: %d\n", err); goto err_free_gpio; } -- cgit v1.2.3 From 83aea945c21c646184a494a32ad5524248b60226 Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Tue, 1 Jun 2010 05:58:40 +0000 Subject: powerpc/macio: Don't dereference pointer before null check Signed-off-by: Andreas Schwab Signed-off-by: Benjamin Herrenschmidt --- drivers/macintosh/macio_asic.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c index 97147804a49c..40390ac01309 100644 --- a/drivers/macintosh/macio_asic.c +++ b/drivers/macintosh/macio_asic.c @@ -492,8 +492,8 @@ static void macio_pci_add_devices(struct macio_chip *chip) } /* Add media bay devices if any */ - pnode = mbdev->ofdev.dev.of_node; - if (mbdev) + if (mbdev) { + pnode = mbdev->ofdev.dev.of_node; for (np = NULL; (np = of_get_next_child(pnode, np)) != NULL;) { if (macio_skip_device(np)) continue; @@ -502,10 +502,11 @@ static void macio_pci_add_devices(struct macio_chip *chip) mbdev, root_res) == NULL) of_node_put(np); } + } /* Add serial ports if any */ - pnode = sdev->ofdev.dev.of_node; if (sdev) { + pnode = sdev->ofdev.dev.of_node; for (np = NULL; (np = of_get_next_child(pnode, np)) != NULL;) { if (macio_skip_device(np)) continue; -- cgit v1.2.3 From 79905ad50bcf025deb81382413719ed600734941 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 1 Jun 2010 19:33:08 +0000 Subject: agp/uninorth: Fix oops caused by flushing too much This fixes a sporadic oops at boot on G5 Power Macs. The table_end variable has the address of the last byte of the table. Adding on PAGE_SIZE means we flush too much, and if the page after the table is not mapped for any reason, the kernel will oops. Instead we add on 1 because flush_dcache_range() interprets its second argument as the first byte past the range to be flushed. Signed-off-by: Paul Mackerras Signed-off-by: Benjamin Herrenschmidt --- drivers/char/agp/uninorth-agp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c index 95db71360d24..f845a8f718b3 100644 --- a/drivers/char/agp/uninorth-agp.c +++ b/drivers/char/agp/uninorth-agp.c @@ -415,7 +415,7 @@ static int uninorth_create_gatt_table(struct agp_bridge_data *bridge) bridge->gatt_table_real = (u32 *) table; /* Need to clear out any dirty data still sitting in caches */ flush_dcache_range((unsigned long)table, - (unsigned long)(table_end + PAGE_SIZE)); + (unsigned long)table_end + 1); bridge->gatt_table = vmap(pages, (1 << page_order), 0, PAGE_KERNEL_NCG); if (bridge->gatt_table == NULL) -- cgit v1.2.3 From c2cdf6aba0dfcfb54be646ab630c1bccd180e890 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 2 Jun 2010 17:09:18 +1000 Subject: powerpc/macio: Fix probing of macio devices by using the right of match table Grant patches added an of mach table to struct device_driver. However, while he changed the macio device code to use that, he left the match table pointer in struct macio_driver and didn't update drivers to use the "new" one, thus breaking the probing. This completes the change by moving all drivers to setup the "new" one, removing all traces of the old one, and while at it (since it changes the exact same locations), I also remove two other duplicates from struct driver which are the name and owner fields. Signed-off-by: Benjamin Herrenschmidt --- drivers/ata/pata_macio.c | 10 +++++----- drivers/block/swim3.c | 6 ++++-- drivers/ide/pmac.c | 7 +++++-- drivers/macintosh/macio_asic.c | 1 - drivers/macintosh/mediabay.c | 6 ++++-- drivers/macintosh/rack-meter.c | 8 +++++--- drivers/net/bmac.c | 7 +++++-- drivers/net/mace.c | 7 +++++-- drivers/net/wireless/orinoco/airport.c | 7 +++++-- drivers/scsi/mac53c94.c | 7 +++++-- drivers/scsi/mesh.c | 7 +++++-- drivers/serial/pmac_zilog.c | 7 +++++-- 12 files changed, 53 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/pata_macio.c b/drivers/ata/pata_macio.c index 76640ac76888..75b49d01780b 100644 --- a/drivers/ata/pata_macio.c +++ b/drivers/ata/pata_macio.c @@ -1355,8 +1355,11 @@ static struct of_device_id pata_macio_match[] = static struct macio_driver pata_macio_driver = { - .name = "pata-macio", - .match_table = pata_macio_match, + .driver = { + .name = "pata-macio", + .owner = THIS_MODULE, + .of_match_table = pata_macio_match, + }, .probe = pata_macio_attach, .remove = pata_macio_detach, #ifdef CONFIG_PM @@ -1366,9 +1369,6 @@ static struct macio_driver pata_macio_driver = #ifdef CONFIG_PMAC_MEDIABAY .mediabay_event = pata_macio_mb_event, #endif - .driver = { - .owner = THIS_MODULE, - }, }; static const struct pci_device_id pata_macio_pci_match[] = { diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index 52f2d11bc7b9..ed6fb91123ab 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -1159,8 +1159,10 @@ static struct of_device_id swim3_match[] = static struct macio_driver swim3_driver = { - .name = "swim3", - .match_table = swim3_match, + .driver = { + .name = "swim3", + .of_match_table = swim3_match, + }, .probe = swim3_attach, #if 0 .suspend = swim3_suspend, diff --git a/drivers/ide/pmac.c b/drivers/ide/pmac.c index 183fa38760d8..ebcf8e470a97 100644 --- a/drivers/ide/pmac.c +++ b/drivers/ide/pmac.c @@ -1400,8 +1400,11 @@ static struct of_device_id pmac_ide_macio_match[] = static struct macio_driver pmac_ide_macio_driver = { - .name = "ide-pmac", - .match_table = pmac_ide_macio_match, + .driver = { + .name = "ide-pmac", + .owner = THIS_MODULE, + .of_match_table = pmac_ide_macio_match, + }, .probe = pmac_ide_macio_attach, .suspend = pmac_ide_macio_suspend, .resume = pmac_ide_macio_resume, diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c index 40390ac01309..b6e7ddc09d76 100644 --- a/drivers/macintosh/macio_asic.c +++ b/drivers/macintosh/macio_asic.c @@ -526,7 +526,6 @@ static void macio_pci_add_devices(struct macio_chip *chip) int macio_register_driver(struct macio_driver *drv) { /* initialize common driver fields */ - drv->driver.name = drv->name; drv->driver.bus = &macio_bus_type; /* register with core */ diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c index 288acce76b74..2fd435bc542e 100644 --- a/drivers/macintosh/mediabay.c +++ b/drivers/macintosh/mediabay.c @@ -728,8 +728,10 @@ static struct of_device_id media_bay_match[] = static struct macio_driver media_bay_driver = { - .name = "media-bay", - .match_table = media_bay_match, + .driver = { + .name = "media-bay", + .of_match_table = media_bay_match, + }, .probe = media_bay_attach, .suspend = media_bay_suspend, .resume = media_bay_resume diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c index 12946c5f583f..53cce3a5da23 100644 --- a/drivers/macintosh/rack-meter.c +++ b/drivers/macintosh/rack-meter.c @@ -584,9 +584,11 @@ static struct of_device_id rackmeter_match[] = { }; static struct macio_driver rackmeter_driver = { - .name = "rackmeter", - .owner = THIS_MODULE, - .match_table = rackmeter_match, + .driver = { + .name = "rackmeter", + .owner = THIS_MODULE, + .of_match_table = rackmeter_match, + }, .probe = rackmeter_probe, .remove = __devexit_p(rackmeter_remove), .shutdown = rackmeter_shutdown, diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index 39250b2ca886..959add2410bf 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -1654,8 +1654,11 @@ MODULE_DEVICE_TABLE (of, bmac_match); static struct macio_driver bmac_driver = { - .name = "bmac", - .match_table = bmac_match, + .driver = { + .name = "bmac", + .owner = THIS_MODULE, + .of_match_table = bmac_match, + }, .probe = bmac_probe, .remove = bmac_remove, #ifdef CONFIG_PM diff --git a/drivers/net/mace.c b/drivers/net/mace.c index b6855a6476f8..1c5221f79d6f 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -997,8 +997,11 @@ MODULE_DEVICE_TABLE (of, mace_match); static struct macio_driver mace_driver = { - .name = "mace", - .match_table = mace_match, + .driver = { + .name = "mace", + .owner = THIS_MODULE, + .of_match_table = mace_match, + }, .probe = mace_probe, .remove = mace_remove, }; diff --git a/drivers/net/wireless/orinoco/airport.c b/drivers/net/wireless/orinoco/airport.c index 9bcee10c9308..4a0a0e5265c9 100644 --- a/drivers/net/wireless/orinoco/airport.c +++ b/drivers/net/wireless/orinoco/airport.c @@ -239,8 +239,11 @@ static struct of_device_id airport_match[] = MODULE_DEVICE_TABLE(of, airport_match); static struct macio_driver airport_driver = { - .name = DRIVER_NAME, - .match_table = airport_match, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = airport_match, + }, .probe = airport_attach, .remove = airport_detach, .suspend = airport_suspend, diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c index 18735b39b3d3..3ddb4dc62d5d 100644 --- a/drivers/scsi/mac53c94.c +++ b/drivers/scsi/mac53c94.c @@ -542,8 +542,11 @@ MODULE_DEVICE_TABLE (of, mac53c94_match); static struct macio_driver mac53c94_driver = { - .name = "mac53c94", - .match_table = mac53c94_match, + .driver = { + .name = "mac53c94", + .owner = THIS_MODULE, + .of_match_table = mac53c94_match, + }, .probe = mac53c94_probe, .remove = mac53c94_remove, }; diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c index a1c97e88068a..1f784fde2510 100644 --- a/drivers/scsi/mesh.c +++ b/drivers/scsi/mesh.c @@ -2036,8 +2036,11 @@ MODULE_DEVICE_TABLE (of, mesh_match); static struct macio_driver mesh_driver = { - .name = "mesh", - .match_table = mesh_match, + .driver = { + .name = "mesh", + .owner = THIS_MODULE, + .of_match_table = mesh_match, + }, .probe = mesh_probe, .remove = mesh_remove, .shutdown = mesh_shutdown, diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c index cabbdc7ba583..5b9cde79e4ea 100644 --- a/drivers/serial/pmac_zilog.c +++ b/drivers/serial/pmac_zilog.c @@ -2005,8 +2005,11 @@ static struct of_device_id pmz_match[] = MODULE_DEVICE_TABLE (of, pmz_match); static struct macio_driver pmz_driver = { - .name = "pmac_zilog", - .match_table = pmz_match, + .driver = { + .name = "pmac_zilog", + .owner = THIS_MODULE, + .of_match_table = pmz_match, + }, .probe = pmz_attach, .remove = pmz_detach, .suspend = pmz_suspend, -- cgit v1.2.3 From 66f49121ffa41a19c59965b31b046d8368fec3c7 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 31 May 2010 21:45:48 +0000 Subject: clocksource: sh_tmu: compute mult and shift before registration Since commit 98962465ed9e6ea99c38e0af63fe1dcb5a79dc25 ("nohz: Prevent clocksource wrapping during idle"), the CPU of an R2D board never goes to idle. This commit assumes that mult and shift are assigned before the clocksource is registered. As a consequence the safe maximum sleep time is negative and the CPU never goes into idle. This patch fixes the problem by moving mult and shift initialization from sh_tmu_clocksource_enable() to sh_tmu_register_clocksource(). Signed-off-by: Aurelien Jarno Cc: stable@kernel.org Signed-off-by: Paul Mundt --- drivers/clocksource/sh_tmu.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c index 8e44e14ec4c2..de715901b82a 100644 --- a/drivers/clocksource/sh_tmu.c +++ b/drivers/clocksource/sh_tmu.c @@ -199,16 +199,8 @@ static cycle_t sh_tmu_clocksource_read(struct clocksource *cs) static int sh_tmu_clocksource_enable(struct clocksource *cs) { struct sh_tmu_priv *p = cs_to_sh_tmu(cs); - int ret; - - ret = sh_tmu_enable(p); - if (ret) - return ret; - /* TODO: calculate good shift from rate and counter bit width */ - cs->shift = 10; - cs->mult = clocksource_hz2mult(p->rate, cs->shift); - return 0; + return sh_tmu_enable(p); } static void sh_tmu_clocksource_disable(struct clocksource *cs) @@ -228,6 +220,16 @@ static int sh_tmu_register_clocksource(struct sh_tmu_priv *p, cs->disable = sh_tmu_clocksource_disable; cs->mask = CLOCKSOURCE_MASK(32); cs->flags = CLOCK_SOURCE_IS_CONTINUOUS; + + /* clk_get_rate() needs an enabled clock */ + clk_enable(p->clk); + /* channel will be configured at parent clock / 4 */ + p->rate = clk_get_rate(p->clk) / 4; + clk_disable(p->clk); + /* TODO: calculate good shift from rate and counter bit width */ + cs->shift = 10; + cs->mult = clocksource_hz2mult(p->rate, cs->shift); + dev_info(&p->pdev->dev, "used as clock source\n"); clocksource_register(cs); return 0; -- cgit v1.2.3 From f4d7c3565c1692c54d9152b52090fe73f0029e37 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 2 Jun 2010 17:10:44 +0900 Subject: clocksource: sh_cmt: compute mult and shift before registration Based on the sh_tmu change in 66f49121ffa41a19c59965b31b046d8368fec3c7 ("clocksource: sh_tmu: compute mult and shift before registration"). The same issues impact the sh_cmt driver, so we take the same approach here. Cc: stable@kernel.org Signed-off-by: Paul Mundt --- drivers/clocksource/sh_cmt.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index f6677cb19789..f3d3898898ed 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -412,18 +412,10 @@ static cycle_t sh_cmt_clocksource_read(struct clocksource *cs) static int sh_cmt_clocksource_enable(struct clocksource *cs) { struct sh_cmt_priv *p = cs_to_sh_cmt(cs); - int ret; p->total_cycles = 0; - ret = sh_cmt_start(p, FLAG_CLOCKSOURCE); - if (ret) - return ret; - - /* TODO: calculate good shift from rate and counter bit width */ - cs->shift = 0; - cs->mult = clocksource_hz2mult(p->rate, cs->shift); - return 0; + return sh_cmt_start(p, FLAG_CLOCKSOURCE); } static void sh_cmt_clocksource_disable(struct clocksource *cs) @@ -450,8 +442,20 @@ static int sh_cmt_register_clocksource(struct sh_cmt_priv *p, cs->resume = sh_cmt_clocksource_resume; cs->mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8); cs->flags = CLOCK_SOURCE_IS_CONTINUOUS; + + /* clk_get_rate() needs an enabled clock */ + clk_enable(p->clk); + p->rate = clk_get_rate(p->clk) / (p->width == 16) ? 512 : 8; + clk_disable(p->clk); + + /* TODO: calculate good shift from rate and counter bit width */ + cs->shift = 10; + cs->mult = clocksource_hz2mult(p->rate, cs->shift); + dev_info(&p->pdev->dev, "used as clock source\n"); + clocksource_register(cs); + return 0; } -- cgit v1.2.3 From dfe5c7b7e710d8ed885068b0fcfa6f66ab685592 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 1 Jun 2010 16:35:15 +0200 Subject: HID: roccat: introduce missing kfree Error handling code following a kmalloc should free the allocated data. The semantic match that finds the problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @r exists@ local idexpression x; statement S; expression E; identifier f,f1,l; position p1,p2; expression *ptr != NULL; @@ x@p1 = \(kmalloc\|kzalloc\|kcalloc\)(...); ... if (x == NULL) S <... when != x when != if (...) { <+...x...+> } ( x->f1 = E | (x->f1 == NULL || ...) | f(...,x->f1,...) ) ...> ( return \(0\|<+...x...+>\|ptr\); | return@p2 ...; ) @script:python@ p1 << r.p1; p2 << r.p2; @@ print "* file: %s kmalloc %s return %s" % (p1[0].file,p1[0].line,p2[0].line) // Signed-off-by: Julia Lawall Signed-off-by: Jiri Kosina --- drivers/hid/hid-roccat.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-roccat.c b/drivers/hid/hid-roccat.c index e05d48edb66f..f6e80c7ca61e 100644 --- a/drivers/hid/hid-roccat.c +++ b/drivers/hid/hid-roccat.c @@ -168,7 +168,7 @@ static int roccat_open(struct inode *inode, struct file *file) printk(KERN_EMERG "roccat device with minor %d doesn't exist\n", minor); error = -ENODEV; - goto exit_unlock; + goto exit_err; } if (!device->open++) { @@ -178,7 +178,7 @@ static int roccat_open(struct inode *inode, struct file *file) PM_HINT_FULLON); if (error < 0) { --device->open; - goto exit_unlock; + goto exit_err; } } error = device->hid->ll_driver->open(device->hid); @@ -187,7 +187,7 @@ static int roccat_open(struct inode *inode, struct file *file) device->hid->ll_driver->power(device->hid, PM_HINT_NORMAL); --device->open; - goto exit_unlock; + goto exit_err; } } @@ -202,6 +202,9 @@ exit_unlock: mutex_unlock(&device->readers_lock); mutex_unlock(&devices_lock); return error; +exit_err: + kfree(reader); + goto exit_unlock; } static int roccat_release(struct inode *inode, struct file *file) -- cgit v1.2.3 From ac422f9443191e050c16fe99baeb5c3d74934589 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 2 Jun 2010 18:10:00 +0900 Subject: sh: Make intc messages consistent via pr_fmt. Wrapping pr_fmt to the KBUILD_MODNAME prefix seems to be the trendy thing to do these days, so just do that instead of manually tidying up the stragglers. Signed-off-by: Paul Mundt --- drivers/sh/intc.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c index c585574b9aed..e91a23e5ffd8 100644 --- a/drivers/sh/intc.c +++ b/drivers/sh/intc.c @@ -16,6 +16,8 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -855,8 +857,8 @@ static void __init intc_register_irq(struct intc_desc *desc, primary = 1; if (!data[0] && !data[1]) - pr_warning("intc: missing unique irq mask for " - "irq %d (vect 0x%04x)\n", irq, irq2evt(irq)); + pr_warning("missing unique irq mask for irq %d (vect 0x%04x)\n", + irq, irq2evt(irq)); data[0] = data[0] ? data[0] : intc_mask_data(desc, d, enum_id, 1); data[1] = data[1] ? data[1] : intc_prio_data(desc, d, enum_id, 1); @@ -952,7 +954,7 @@ int __init register_intc_controller(struct intc_desc *desc) struct intc_desc_int *d; struct resource *res; - pr_info("intc: Registered controller '%s' with %u IRQs\n", + pr_info("Registered controller '%s' with %u IRQs\n", desc->name, hw->nr_vectors); d = kzalloc(sizeof(*d), GFP_NOWAIT); @@ -1148,7 +1150,7 @@ int register_intc_userimask(unsigned long addr) if (unlikely(!uimask)) return -ENOMEM; - pr_info("intc: userimask support registered for levels 0 -> %d\n", + pr_info("userimask support registered for levels 0 -> %d\n", default_prio_level - 1); return 0; @@ -1286,7 +1288,7 @@ static int __init register_intc_sysdevs(void) } if (error) - pr_err("intc: sysdev registration error\n"); + pr_err("sysdev registration error\n"); return error; } -- cgit v1.2.3 From cc1fed00c9ba84f38717a6cab84409cd48f340e3 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Wed, 2 Jun 2010 16:01:45 +0300 Subject: mtd/r852: register IRQ as last step Otherwise, if it fires right away, it might access uninitialized spinlock Signed-off-by: Maxim Levitsky Signed-off-by: David Woodhouse --- drivers/mtd/nand/r852.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index 78a423295474..20a654a94d30 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -940,18 +940,19 @@ int r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) r852_dma_test(dev); + dev->irq = pci_dev->irq; + spin_lock_init(&dev->irqlock); + + dev->card_detected = 0; + r852_card_update_present(dev); + /*register irq handler*/ error = -ENODEV; if (request_irq(pci_dev->irq, &r852_irq, IRQF_SHARED, DRV_NAME, dev)) goto error10; - dev->irq = pci_dev->irq; - spin_lock_init(&dev->irqlock); - /* kick initial present test */ - dev->card_detected = 0; - r852_card_update_present(dev); queue_delayed_work(dev->card_workqueue, &dev->card_detect_work, 0); -- cgit v1.2.3 From 9489be8ca234c07666e88a4472e4d5f2a2425aa5 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Wed, 2 Jun 2010 16:01:46 +0300 Subject: mtd/r852: Fixes in case of DMA timeout * Don't call complete on dma completion * do a INIT_COMPLETE before using it each time * Report DMA read error via ecc 'correct' I finally managed to make my system do suspend to ram propertly, and I see that if card was inserted during suspend (while system was off), I get dma timeouts on resume. Simple card reinsert solves the issue. This patch solves a crash that would happen otherwise Signed-off-by: Maxim Levitsky Signed-off-by: David Woodhouse --- drivers/mtd/nand/r852.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index 20a654a94d30..3f219e61df7d 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -150,7 +150,6 @@ static void r852_dma_done(struct r852_device *dev, int error) if (dev->phys_dma_addr && dev->phys_dma_addr != dev->phys_bounce_buffer) pci_unmap_single(dev->pci_dev, dev->phys_dma_addr, R852_DMA_LEN, dev->dma_dir ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); - complete(&dev->dma_done); } /* @@ -182,6 +181,7 @@ static void r852_do_dma(struct r852_device *dev, uint8_t *buf, int do_read) /* Set dma direction */ dev->dma_dir = do_read; dev->dma_stage = 1; + INIT_COMPLETION(dev->dma_done); dbg_verbose("doing dma %s ", do_read ? "read" : "write"); @@ -494,6 +494,11 @@ int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat, if (dev->card_unstable) return 0; + if (dev->dma_error) { + dev->dma_error = 0; + return -1; + } + r852_write_reg(dev, R852_CTL, dev->ctlreg | R852_CTL_ECC_ACCESS); ecc_reg = r852_read_reg_dword(dev, R852_DATALINE); r852_write_reg(dev, R852_CTL, dev->ctlreg); @@ -796,6 +801,7 @@ static irqreturn_t r852_irq(int irq, void *data) if (dma_status & R852_DMA_IRQ_ERROR) { dbg("recieved dma error IRQ"); r852_dma_done(dev, -EIO); + complete(&dev->dma_done); goto out; } @@ -825,8 +831,10 @@ static irqreturn_t r852_irq(int irq, void *data) r852_dma_enable(dev); /* Operation done */ - if (dev->dma_stage == 3) + if (dev->dma_stage == 3) { r852_dma_done(dev, 0); + complete(&dev->dma_done); + } goto out; } @@ -1082,7 +1090,7 @@ int r852_resume(struct device *device) dev->card_detected ? "added" : "removed"); queue_delayed_work(dev->card_workqueue, - &dev->card_detect_work, 1000); + &dev->card_detect_work, msecs_to_jiffies(1000)); return 0; } -- cgit v1.2.3 From ac373f7e2286ed3690e8a93ebf9f6f1ae0c7d4a9 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Wed, 2 Jun 2010 16:01:47 +0300 Subject: mtd/r852: update card detect early. This turns out to be the reason for DMA timeouts on resume, if card was inserted while system was suspended Signed-off-by: Maxim Levitsky Signed-off-by: David Woodhouse --- drivers/mtd/nand/r852.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index 3f219e61df7d..bcfc851fe550 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -712,6 +712,7 @@ void r852_card_detect_work(struct work_struct *work) container_of(work, struct r852_device, card_detect_work.work); r852_card_update_present(dev); + r852_update_card_detect(dev); dev->card_unstable = 0; /* False alarm */ @@ -727,7 +728,6 @@ void r852_card_detect_work(struct work_struct *work) else r852_unregister_nand_device(dev); exit: - /* Update detection logic */ r852_update_card_detect(dev); } -- cgit v1.2.3 From 10389536742cefbedecb67a5b2906f155cf3a1c3 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sun, 30 May 2010 19:43:52 +0200 Subject: firewire: core: check for 1394a compliant IRM, fix inaccessibility of Sony camcorder Per IEEE 1394 clause 8.4.2.3, a contender for the IRM role shall check whether the current IRM complies to 1394a-2000 or later. If not force a compliant node (e.g. itself) to become IRM. This was implemented in the older ieee1394 driver but not yet in firewire-core. An older Sony camcorder (Sony DCR-TRV25) which implements 1394-1995 IRM but neither 1394a-2000 IRM nor BM was now found to cause an interoperability bug: - Camcorder becomes root node when plugged in, hence gets IRM role. - firewire-core successfully contends for BM role, proceeds to perform gap count optimization and resets the bus. - Sony camcorder ignores presence of a BM (against the spec, this is a firmware bug), performs its idea of gap count optimization and resets the bus. - Preceding two steps are repeated endlessly, bus never settles, regular I/O is practically impossible. http://thread.gmane.org/gmane.linux.kernel.firewire.user/3913 This is an interoperability regression from the old to the new drivers. Fix it indirectly by adding the 1394a IRM check. The spec suggests three and a half methods to determine 1394a compliance of a remote IRM; we choose the method of testing the Config_ROM.Bus_Info.generation field. This is data that firewire-core should have readily available at this point, i.e. does not require extra I/O. Reported-by: Clemens Ladisch (missing 1394a check) Reported-by: H. S. (issue with Sony DCR-TRV25) Tested-by: H. S. Cc: # .32.x and newer Signed-off-by: Stefan Richter --- drivers/firewire/core-card.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c index 9dcb30466ec0..371713ff0266 100644 --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c @@ -231,7 +231,7 @@ void fw_schedule_bm_work(struct fw_card *card, unsigned long delay) static void fw_card_bm_work(struct work_struct *work) { struct fw_card *card = container_of(work, struct fw_card, work.work); - struct fw_device *root_device; + struct fw_device *root_device, *irm_device; struct fw_node *root_node; unsigned long flags; int root_id, new_root_id, irm_id, local_id; @@ -239,6 +239,7 @@ static void fw_card_bm_work(struct work_struct *work) bool do_reset = false; bool root_device_is_running; bool root_device_is_cmc; + bool irm_is_1394_1995_only; spin_lock_irqsave(&card->lock, flags); @@ -248,12 +249,18 @@ static void fw_card_bm_work(struct work_struct *work) } generation = card->generation; + root_node = card->root_node; fw_node_get(root_node); root_device = root_node->data; root_device_is_running = root_device && atomic_read(&root_device->state) == FW_DEVICE_RUNNING; root_device_is_cmc = root_device && root_device->cmc; + + irm_device = card->irm_node->data; + irm_is_1394_1995_only = irm_device && irm_device->config_rom && + (irm_device->config_rom[2] & 0x000000f0) == 0; + root_id = root_node->node_id; irm_id = card->irm_node->node_id; local_id = card->local_node->node_id; @@ -276,8 +283,15 @@ static void fw_card_bm_work(struct work_struct *work) if (!card->irm_node->link_on) { new_root_id = local_id; - fw_notify("IRM has link off, making local node (%02x) root.\n", - new_root_id); + fw_notify("%s, making local node (%02x) root.\n", + "IRM has link off", new_root_id); + goto pick_me; + } + + if (irm_is_1394_1995_only) { + new_root_id = local_id; + fw_notify("%s, making local node (%02x) root.\n", + "IRM is not 1394a compliant", new_root_id); goto pick_me; } @@ -316,8 +330,8 @@ static void fw_card_bm_work(struct work_struct *work) * root, and thus, IRM. */ new_root_id = local_id; - fw_notify("BM lock failed, making local node (%02x) root.\n", - new_root_id); + fw_notify("%s, making local node (%02x) root.\n", + "BM lock failed", new_root_id); goto pick_me; } } else if (card->bm_generation != generation) { -- cgit v1.2.3 From 8b27ff4cf6d15964aa2987aeb58db4dfb1f87a19 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 31 May 2010 16:26:48 +0200 Subject: sata_via: magic vt6421 fix for transmission problems w/ WD drives vt6421 has problems talking to recent WD drives. It causes a lot of transmission errors while high bandwidth transfer as reported in the following bugzilla entry. https://bugzilla.kernel.org/show_bug.cgi?id=15173 Joseph Chan provided the following fix. I don't have any idea what it does but I can verify the issue is gone with the patch applied. Signed-off-by: Tejun Heo Originally-from: Joseph Chan Reported-by: Jorrit Tijben Cc: stable@kernel.org Signed-off-by: Jeff Garzik --- drivers/ata/sata_via.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 101d8c219caf..0ecd0f6aa2c0 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -575,6 +575,19 @@ static void svia_configure(struct pci_dev *pdev) tmp8 |= NATIVE_MODE_ALL; pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8); } + + /* + * vt6421 has problems talking to some drives. The following + * is the magic fix from Joseph Chan . + * Please add proper documentation if possible. + * + * https://bugzilla.kernel.org/show_bug.cgi?id=15173 + */ + if (pdev->device == 0x3249) { + pci_read_config_byte(pdev, 0x52, &tmp8); + tmp8 |= 1 << 2; + pci_write_config_byte(pdev, 0x52, tmp8); + } } static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) -- cgit v1.2.3 From f3faf8fc3fab45c3526efe8c9e99bb23f8723350 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 1 Jun 2010 17:29:21 +0200 Subject: sata_nv: don't diddle with nIEN on mcp55 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On mcp55, nIEN gets stuck once set and liteon blueray rom iHOS104-08 violates ATA specification and fails to set I on D2H Reg FIS if nIEN is set when the command was issued. When the other party is following the spec, both devices can work fine but when the two flaws are put together, they can't talk to each other. mcp55 has its own IRQ masking mechanism and there's no reason to mess with nIEN in the first place. Fix it by dropping nIEN diddling from nv_mcp55_freeze/thaw(). This was originally reported by Cengiz. Although Cengiz hasn't verified the fix yet, I could reproduce this problem and verfiy the fix. Even if Cengiz is experiencing different or additional problems, this patch is needed. Signed-off-by: Tejun Heo Reported-by: Cengiz Günay Cc: stable@kernel.org Signed-off-by: Jeff Garzik --- drivers/ata/sata_nv.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 6fd114784116..21161136cad0 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -1669,7 +1669,6 @@ static void nv_mcp55_freeze(struct ata_port *ap) mask = readl(mmio_base + NV_INT_ENABLE_MCP55); mask &= ~(NV_INT_ALL_MCP55 << shift); writel(mask, mmio_base + NV_INT_ENABLE_MCP55); - ata_sff_freeze(ap); } static void nv_mcp55_thaw(struct ata_port *ap) @@ -1683,7 +1682,6 @@ static void nv_mcp55_thaw(struct ata_port *ap) mask = readl(mmio_base + NV_INT_ENABLE_MCP55); mask |= (NV_INT_MASK_MCP55 << shift); writel(mask, mmio_base + NV_INT_ENABLE_MCP55); - ata_sff_thaw(ap); } static void nv_adma_error_handler(struct ata_port *ap) -- cgit v1.2.3 From ed4e2f801cf1484a68c4b41878353f26e6554c6a Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sat, 29 May 2010 12:47:45 +0200 Subject: libata-sff: trivial corrections to Kconfig help text Signed-off-by: Stefan Richter Signed-off-by: Jeff Garzik --- drivers/ata/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 73f883333a0d..aa85a98d3a4f 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -168,10 +168,10 @@ config ATA_BMDMA default y help This option adds support for SFF ATA controllers with BMDMA - capability. BMDMA stands for bus-master DMA and the - de-facto DMA interface for SFF controllers. + capability. BMDMA stands for bus-master DMA and is the + de facto DMA interface for SFF controllers. - If unuser, say Y. + If unsure, say Y. if ATA_BMDMA -- cgit v1.2.3 From 72ec24bd7725545bc149d80cbd21a7578d9aa206 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 15 May 2010 20:09:32 +0200 Subject: SCSI: implement sd_unlock_native_capacity() Implement sd_unlock_native_capacity() method which calls into hostt->unlock_native_capacity() if implemented. This will be invoked by block layer if partitions extend beyond the end of the device and can be used to implement, for example, on-demand ATA host protected area unlocking. Signed-off-by: Tejun Heo Cc: Ben Hutchings Signed-off-by: Jeff Garzik --- drivers/scsi/sd.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 829cc37abc41..8802e48bc063 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -97,6 +97,7 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_RBC); #endif static int sd_revalidate_disk(struct gendisk *); +static void sd_unlock_native_capacity(struct gendisk *disk); static int sd_probe(struct device *); static int sd_remove(struct device *); static void sd_shutdown(struct device *); @@ -1101,6 +1102,7 @@ static const struct block_device_operations sd_fops = { #endif .media_changed = sd_media_changed, .revalidate_disk = sd_revalidate_disk, + .unlock_native_capacity = sd_unlock_native_capacity, }; static unsigned int sd_completed_bytes(struct scsi_cmnd *scmd) @@ -2120,6 +2122,26 @@ static int sd_revalidate_disk(struct gendisk *disk) return 0; } +/** + * sd_unlock_native_capacity - unlock native capacity + * @disk: struct gendisk to set capacity for + * + * Block layer calls this function if it detects that partitions + * on @disk reach beyond the end of the device. If the SCSI host + * implements ->unlock_native_capacity() method, it's invoked to + * give it a chance to adjust the device capacity. + * + * CONTEXT: + * Defined by block layer. Might sleep. + */ +static void sd_unlock_native_capacity(struct gendisk *disk) +{ + struct scsi_device *sdev = scsi_disk(disk)->device; + + if (sdev->host->hostt->unlock_native_capacity) + sdev->host->hostt->unlock_native_capacity(sdev); +} + /** * sd_format_disk_name - format disk name * @prefix: name prefix - ie. "sd" for SCSI disks -- cgit v1.2.3 From 68939ce5fc17ee9c03ef6e543d4f82bd9f5583d4 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 15 May 2010 20:09:33 +0200 Subject: libata: use the enlarged capacity after late HPA unlock After late HPA unlock, libata kept using the original capacity ignoring the new larger native capacity. Enlarging device on the fly doesn't cause any harm. Use the larger native capacity instead. This will enable on-demand HPA unlocking. Signed-off-by: Tejun Heo Cc: Ben Hutchings Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 06b7e49e039c..1e5d0a36a0a4 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4119,9 +4119,8 @@ int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class, dev->n_sectors > n_sectors && dev->n_sectors == n_native_sectors) { ata_dev_printk(dev, KERN_WARNING, "new n_sectors matches native, probably " - "late HPA unlock, continuing\n"); - /* keep using the old n_sectors */ - dev->n_sectors = n_sectors; + "late HPA unlock, n_sectors updated\n"); + /* use the larger n_sectors */ return 0; } -- cgit v1.2.3 From d8d9129ea28e2177749627c82962feb26e8d11e9 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 15 May 2010 20:09:34 +0200 Subject: libata: implement on-demand HPA unlocking Implement ata_scsi_unlock_native_capacity() which will be called through SCSI layer when block layer notices that partitions on a device extend beyond the end of the device. It requests EH to unlock HPA, waits for completion and returns the current device capacity. This allows libata to unlock HPA on demand instead of having to decide whether to unlock upfront. Unlocking on demand is safer than unlocking by upfront because some BIOSes write private data to the area beyond HPA limit. This was suggested by Ben Hutchings. Signed-off-by: Tejun Heo Suggested-by: Ben Hutchings Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 1 + drivers/ata/libata-scsi.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 1e5d0a36a0a4..ddf8e4862787 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6668,6 +6668,7 @@ EXPORT_SYMBOL_GPL(ata_dummy_port_info); EXPORT_SYMBOL_GPL(ata_link_next); EXPORT_SYMBOL_GPL(ata_dev_next); EXPORT_SYMBOL_GPL(ata_std_bios_param); +EXPORT_SYMBOL_GPL(ata_scsi_unlock_native_capacity); EXPORT_SYMBOL_GPL(ata_host_init); EXPORT_SYMBOL_GPL(ata_host_alloc); EXPORT_SYMBOL_GPL(ata_host_alloc_pinfo); diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index cfa9dd3d7253..a54273d2c3c6 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -414,6 +414,35 @@ int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev, return 0; } +/** + * ata_scsi_unlock_native_capacity - unlock native capacity + * @sdev: SCSI device to adjust device capacity for + * + * This function is called if a partition on @sdev extends beyond + * the end of the device. It requests EH to unlock HPA. + * + * LOCKING: + * Defined by the SCSI layer. Might sleep. + */ +void ata_scsi_unlock_native_capacity(struct scsi_device *sdev) +{ + struct ata_port *ap = ata_shost_to_port(sdev->host); + struct ata_device *dev; + unsigned long flags; + + spin_lock_irqsave(ap->lock, flags); + + dev = ata_scsi_find_dev(ap, sdev); + if (dev && dev->n_sectors < dev->n_native_sectors) { + dev->flags |= ATA_DFLAG_UNLOCK_HPA; + dev->link->eh_info.action |= ATA_EH_RESET; + ata_port_schedule_eh(ap); + } + + spin_unlock_irqrestore(ap->lock, flags); + ata_port_wait_eh(ap); +} + /** * ata_get_identity - Handler for HDIO_GET_IDENTITY ioctl * @ap: target port -- cgit v1.2.3 From ffabc9a6e8b34151a97fc91fcbef827f07504f75 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Wed, 2 Jun 2010 13:35:02 -0600 Subject: of/usb: fix build error due to of_node pointer move Fix driver to use new location of of_node pointer (introduced by commit use new location of of_node pointer (introduced by commit 61c7a080a5a061c976988fd4b844dfb468dda255; of: Always use 'struct device.of_node' to get device node pointer) Signed-off-by: Grant Likely Reported-by: John Linn CC: Greg Kroah-Hartman CC: Alan Stern CC: linux-usb@vger.kernel.org CC: devicetree-discuss@lists.ozlabs.org --- drivers/usb/host/ehci-xilinx-of.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-xilinx-of.c b/drivers/usb/host/ehci-xilinx-of.c index 013972bbde57..4899f451add9 100644 --- a/drivers/usb/host/ehci-xilinx-of.c +++ b/drivers/usb/host/ehci-xilinx-of.c @@ -151,7 +151,7 @@ static const struct hc_driver ehci_xilinx_of_hc_driver = { static int __devinit ehci_hcd_xilinx_of_probe(struct of_device *op, const struct of_device_id *match) { - struct device_node *dn = op->node; + struct device_node *dn = op->dev.of_node; struct usb_hcd *hcd; struct ehci_hcd *ehci; struct resource res; -- cgit v1.2.3 From b53550781b7d51036aea3b3ee63ece3c6c8f4597 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 25 May 2010 23:24:02 -0600 Subject: of/spi: Fix build failure on spi_ppc4xx.c This patch fixes a build error caused by the OF device_node pointer being moved into struct device. Fixes bug introduced by commit 61c7a080a5a061c976988fd4b844dfb468dda255 (of: Always use 'struct device.of_node' to get device node pointer) Signed-off-by: Grant Likely CC: Sean MacLennan CC: spi-devel-general@lists.sourceforge.net CC: devicetree-discuss@lists.ozlabs.org --- drivers/spi/spi_ppc4xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi_ppc4xx.c b/drivers/spi/spi_ppc4xx.c index 19c0b3b34fce..d53466a249d9 100644 --- a/drivers/spi/spi_ppc4xx.c +++ b/drivers/spi/spi_ppc4xx.c @@ -397,7 +397,7 @@ static int __init spi_ppc4xx_of_probe(struct of_device *op, struct spi_master *master; struct spi_bitbang *bbp; struct resource resource; - struct device_node *np = op->node; + struct device_node *np = op->dev.of_node; struct device *dev = &op->dev; struct device_node *opbnp; int ret; -- cgit v1.2.3 From de2b606c24f178038b95a831f21a35a29faa6eab Mon Sep 17 00:00:00 2001 From: Michael Guntsche Date: Wed, 2 Jun 2010 02:25:52 -0600 Subject: watchdog: Fix build failure with OF changes commit 61c7a080a5a061c976988fd4b844dfb468dda255 ( of: Always use 'struct device.of_node' to get device node pointer.) missed drivers/watchdog/mpc8xxx_wdt.c. This patch fixes it Signed-off-by: Michael Guntsche Signed-off-by: Grant Likely --- drivers/watchdog/mpc8xxx_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c index 6622335773bb..4cda64dd309c 100644 --- a/drivers/watchdog/mpc8xxx_wdt.c +++ b/drivers/watchdog/mpc8xxx_wdt.c @@ -189,7 +189,7 @@ static int __devinit mpc8xxx_wdt_probe(struct of_device *ofdev, const struct of_device_id *match) { int ret; - struct device_node *np = ofdev->node; + struct device_node *np = ofdev->dev.of_node; struct mpc8xxx_wdt_type *wdt_type = match->data; u32 freq = fsl_get_sys_freq(); bool enabled; -- cgit v1.2.3 From ef7f2e831c3a563505c9bc5b16ef4bcae3cf4b53 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Mon, 31 May 2010 18:34:54 +0200 Subject: of/spi: mpc512x_psc_spi.c: Fix build failures Fixes build errors caused by the: - OF device_node pointer being moved into struct device - removal of the match_table field from struct of_platform_driver Signed-off-by: Anatolij Gustschin Signed-off-by: Grant Likely --- drivers/spi/mpc512x_psc_spi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/mpc512x_psc_spi.c b/drivers/spi/mpc512x_psc_spi.c index 28a126d2742b..2534b1ec3edd 100644 --- a/drivers/spi/mpc512x_psc_spi.c +++ b/drivers/spi/mpc512x_psc_spi.c @@ -512,29 +512,29 @@ static int __init mpc512x_psc_spi_of_probe(struct of_device *op, u64 regaddr64, size64; s16 id = -1; - regaddr_p = of_get_address(op->node, 0, &size64, NULL); + regaddr_p = of_get_address(op->dev.of_node, 0, &size64, NULL); if (!regaddr_p) { dev_err(&op->dev, "Invalid PSC address\n"); return -EINVAL; } - regaddr64 = of_translate_address(op->node, regaddr_p); + regaddr64 = of_translate_address(op->dev.of_node, regaddr_p); /* get PSC id (0..11, used by port_config) */ if (op->dev.platform_data == NULL) { const u32 *psc_nump; - psc_nump = of_get_property(op->node, "cell-index", NULL); + psc_nump = of_get_property(op->dev.of_node, "cell-index", NULL); if (!psc_nump || *psc_nump > 11) { dev_err(&op->dev, "mpc512x_psc_spi: Device node %s " "has invalid cell-index property\n", - op->node->full_name); + op->dev.of_node->full_name); return -EINVAL; } id = *psc_nump; } return mpc512x_psc_spi_do_probe(&op->dev, (u32) regaddr64, (u32) size64, - irq_of_parse_and_map(op->node, 0), id); + irq_of_parse_and_map(op->dev.of_node, 0), id); } static int __exit mpc512x_psc_spi_of_remove(struct of_device *op) @@ -550,12 +550,12 @@ static struct of_device_id mpc512x_psc_spi_of_match[] = { MODULE_DEVICE_TABLE(of, mpc512x_psc_spi_of_match); static struct of_platform_driver mpc512x_psc_spi_of_driver = { - .match_table = mpc512x_psc_spi_of_match, .probe = mpc512x_psc_spi_of_probe, .remove = __exit_p(mpc512x_psc_spi_of_remove), .driver = { .name = "mpc512x-psc-spi", .owner = THIS_MODULE, + .of_match_table = mpc512x_psc_spi_of_match, }, }; -- cgit v1.2.3 From 14acbbf8bada18f19930d38ce33c3947b2c718e0 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Mon, 31 May 2010 18:37:15 +0200 Subject: of/mtd/nand: mpc5121_nfc.c: Fix build failures Fixes build errors caused by the: - OF device_node pointer being moved into struct device - removal of the match_table field from struct of_platform_driver Signed-off-by: Anatolij Gustschin Signed-off-by: Grant Likely --- drivers/mtd/nand/mpc5121_nfc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index 3d0867d829cb..0a130dcaa129 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -650,7 +650,7 @@ static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd) static int __devinit mpc5121_nfc_probe(struct of_device *op, const struct of_device_id *match) { - struct device_node *rootnode, *dn = op->node; + struct device_node *rootnode, *dn = op->dev.of_node; struct device *dev = &op->dev; struct mpc5121_nfc_prv *prv; struct resource res; @@ -889,12 +889,12 @@ static struct of_device_id mpc5121_nfc_match[] __devinitdata = { }; static struct of_platform_driver mpc5121_nfc_driver = { - .match_table = mpc5121_nfc_match, .probe = mpc5121_nfc_probe, .remove = __devexit_p(mpc5121_nfc_remove), .driver = { - .name = DRV_NAME, - .owner = THIS_MODULE, + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = mpc5121_nfc_match, }, }; -- cgit v1.2.3 From b4a75c91b8a6cb80ba7772f69613025ddf75ebc2 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Mon, 31 May 2010 18:39:13 +0200 Subject: of/dma: mpc512x_dma.c: Fix build failures Fixes build errors caused by the: - OF device_node pointer being moved into struct device - removal of the match_table field from struct of_platform_driver Signed-off-by: Anatolij Gustschin Signed-off-by: Grant Likely --- drivers/dma/mpc512x_dma.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c index 201e6e19c344..14a8c0f1698e 100644 --- a/drivers/dma/mpc512x_dma.c +++ b/drivers/dma/mpc512x_dma.c @@ -630,7 +630,7 @@ mpc_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src, static int __devinit mpc_dma_probe(struct of_device *op, const struct of_device_id *match) { - struct device_node *dn = op->node; + struct device_node *dn = op->dev.of_node; struct device *dev = &op->dev; struct dma_device *dma; struct mpc_dma *mdma; @@ -771,12 +771,12 @@ static struct of_device_id mpc_dma_match[] = { }; static struct of_platform_driver mpc_dma_driver = { - .match_table = mpc_dma_match, .probe = mpc_dma_probe, .remove = __devexit_p(mpc_dma_remove), - .driver = { - .name = DRV_NAME, - .owner = THIS_MODULE, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = mpc_dma_match, }, }; -- cgit v1.2.3 From 295bdd9c52e57daf995fe80eff8c53938443fa2f Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Wed, 2 Jun 2010 14:06:09 -0600 Subject: of/rtc: rtc-mpc5121.c: Fix build failures Fixes build errors caused by the: - OF device_node pointer being moved into struct device - removal of the match_table field from struct of_platform_driver Signed-off-by: Grant Likely CC: Paul Gortmaker CC: Alessandro Zummo CC: Wolfgang Denk CC: Tejun Heo CC: Anatolij Gustschin CC: rtc-linux@googlegroups.com CC: devicetree-discuss@lists.ozlabs.org --- drivers/rtc/rtc-mpc5121.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c index f0dbf9cb8f9c..db5d8c416d26 100644 --- a/drivers/rtc/rtc-mpc5121.c +++ b/drivers/rtc/rtc-mpc5121.c @@ -279,7 +279,7 @@ static int __devinit mpc5121_rtc_probe(struct of_device *op, if (!rtc) return -ENOMEM; - rtc->regs = of_iomap(op->node, 0); + rtc->regs = of_iomap(op->dev.of_node, 0); if (!rtc->regs) { dev_err(&op->dev, "%s: couldn't map io space\n", __func__); err = -ENOSYS; @@ -290,7 +290,7 @@ static int __devinit mpc5121_rtc_probe(struct of_device *op, dev_set_drvdata(&op->dev, rtc); - rtc->irq = irq_of_parse_and_map(op->node, 1); + rtc->irq = irq_of_parse_and_map(op->dev.of_node, 1); err = request_irq(rtc->irq, mpc5121_rtc_handler, IRQF_DISABLED, "mpc5121-rtc", &op->dev); if (err) { @@ -299,7 +299,7 @@ static int __devinit mpc5121_rtc_probe(struct of_device *op, goto out_dispose; } - rtc->irq_periodic = irq_of_parse_and_map(op->node, 0); + rtc->irq_periodic = irq_of_parse_and_map(op->dev.of_node, 0); err = request_irq(rtc->irq_periodic, mpc5121_rtc_handler_upd, IRQF_DISABLED, "mpc5121-rtc_upd", &op->dev); if (err) { @@ -365,9 +365,11 @@ static struct of_device_id mpc5121_rtc_match[] __devinitdata = { }; static struct of_platform_driver mpc5121_rtc_driver = { - .owner = THIS_MODULE, - .name = "mpc5121-rtc", - .match_table = mpc5121_rtc_match, + .driver = { + .name = "mpc5121-rtc", + .owner = THIS_MODULE, + .of_match_table = mpc5121_rtc_match, + }, .probe = mpc5121_rtc_probe, .remove = __devexit_p(mpc5121_rtc_remove), }; -- cgit v1.2.3 From 0d7168bcf45fa5b6307726091ea77fd4ab16d1ab Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Mon, 17 May 2010 09:46:05 -0700 Subject: Revert "drm/i915: Don't enable pipe/plane/VCO early (wait for DPMS on)." This reverts commit cfecde435dda78248d6fcdc424bed68d5db6be0b. The commit was first created as an attempt to fix LVDS initialiazation on Ironlake. Testing revealed that it didn't fix that, but it was assumed to still be correct anyway. Subsequent testing has revealed that this commit has caused other regressions: * Change in VBlank interrupt frequency causing 60% 3D performance regression http://bugs.freedesktop.org/show_bug.cgi?id=27698 * Black screen on G45 http://bugs.freedesktop.org/show_bug.cgi?id=27733 So revert this buggy code for now to revisit later when we can fix actual bugs without causing these regressions. Signed-off-by: Carl Worth Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_display.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 88a1ab7c05ce..b40155fe5122 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3653,6 +3653,11 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, pipeconf &= ~PIPEACONF_DOUBLE_WIDE; } + dspcntr |= DISPLAY_PLANE_ENABLE; + pipeconf |= PIPEACONF_ENABLE; + dpll |= DPLL_VCO_ENABLE; + + /* Disable the panel fitter if it was on our pipe */ if (!HAS_PCH_SPLIT(dev) && intel_panel_fitter_pipe(dev) == pipe) I915_WRITE(PFIT_CONTROL, 0); -- cgit v1.2.3 From 382fe70fddf54114802c935264f1d5baf8d3d174 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 2 Jun 2010 08:41:44 +0100 Subject: drm/i915: Move non-phys cursors into the GTT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cursors need to be in the GTT domain when being accessed by the GPU. Previously this was a fortuitous byproduct of userspace using pwrite() to upload the image data into the cursor. The redundant clflush was removed in commit 9b8c4a and so the image was no longer being flushed out of the caches into main memory. One could also devise a scenario where the cursor was rendered by the GPU, prior to being attached as the cursor, resulting in similar corruption due to the missing MI_FLUSH. Fixes: Bug 28335 - Cursor corruption caused by commit 9b8c4a0b21 https://bugs.freedesktop.org/show_bug.cgi?id=28335 Signed-off-by: Chris Wilson Tested-by: Arkadiusz Miśkiewicz Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_display.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b40155fe5122..a8d65b7cb72a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3978,6 +3978,13 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, DRM_ERROR("failed to pin cursor bo\n"); goto fail_locked; } + + ret = i915_gem_object_set_to_gtt_domain(bo, 0); + if (ret) { + DRM_ERROR("failed to move cursor bo into the GTT\n"); + goto fail_unpin; + } + addr = obj_priv->gtt_offset; } else { ret = i915_gem_attach_phys_object(dev, bo, (pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1); @@ -4021,6 +4028,8 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, intel_crtc->cursor_bo = bo; return 0; +fail_unpin: + i915_gem_object_unpin(bo); fail_locked: mutex_unlock(&dev->struct_mutex); fail: -- cgit v1.2.3 From a57ee627499d116f6872a5634ea4f015da0eacd2 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Wed, 2 Jun 2010 11:09:04 -0400 Subject: Fix colors for Mach64 Use the same color-calculating algorithm as in atyfb_imageblit in this driver or in generic cfb_fillrect. This patch fixes bad colors when using an accelerator in 15-bit and 16-bit modes. Signed-off-by: Mikulas Patocka Signed-off-by: Linus Torvalds --- drivers/video/aty/mach64_accel.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/video/aty/mach64_accel.c b/drivers/video/aty/mach64_accel.c index 51fcc0a2c94a..e45833ce975b 100644 --- a/drivers/video/aty/mach64_accel.c +++ b/drivers/video/aty/mach64_accel.c @@ -242,7 +242,7 @@ void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { struct atyfb_par *par = (struct atyfb_par *) info->par; - u32 color = rect->color, dx = rect->dx, width = rect->width, rotation = 0; + u32 color, dx = rect->dx, width = rect->width, rotation = 0; if (par->asleep) return; @@ -253,8 +253,11 @@ void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) return; } - color |= (rect->color << 8); - color |= (rect->color << 16); + if (info->fix.visual == FB_VISUAL_TRUECOLOR || + info->fix.visual == FB_VISUAL_DIRECTCOLOR) + color = ((u32 *)(info->pseudo_palette))[rect->color]; + else + color = rect->color; if (info->var.bits_per_pixel == 24) { /* In 24 bpp, the engine is in 8 bpp - this requires that all */ -- cgit v1.2.3 From 2005ce3521b7a38f12085e0420f405a8ee06f606 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Thu, 3 Jun 2010 01:38:57 +0200 Subject: of/pcmcia: m8xx_pcmcia.c: Fix build failures Fixes build errors caused by the: - OF device_node pointer being moved into struct device - typo in match_table field in the struct device_driver (which shoud be of_match_table) Signed-off-by: Anatolij Gustschin Signed-off-by: Grant Likely --- drivers/pcmcia/m8xx_pcmcia.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c index 1a648b90b634..25e5e30a18af 100644 --- a/drivers/pcmcia/m8xx_pcmcia.c +++ b/drivers/pcmcia/m8xx_pcmcia.c @@ -1157,7 +1157,7 @@ static int __init m8xx_probe(struct of_device *ofdev, unsigned int i, m, hwirq; pcmconf8xx_t *pcmcia; int status; - struct device_node *np = ofdev->node; + struct device_node *np = ofdev->dev.of_node; pcmcia_info("%s\n", version); @@ -1301,7 +1301,7 @@ static struct of_platform_driver m8xx_pcmcia_driver = { .driver = { .name = driver_name, .owner = THIS_MODULE, - .match_table = m8xx_pcmcia_match, + .of_match_table = m8xx_pcmcia_match, }, .probe = m8xx_probe, .remove = m8xx_remove, -- cgit v1.2.3 From d4b8b2c2c0b980fa756267e43e39e5ac3c894857 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Thu, 3 Jun 2010 02:20:44 +0200 Subject: of/video: fix build breakage in FB drivers Fixes build errors in a number of framebuffer drivers caused by the OF device_node pointer being moved into struct device Signed-off-by: Anatolij Gustschin Signed-off-by: Grant Likely --- drivers/video/bw2.c | 2 +- drivers/video/cg14.c | 2 +- drivers/video/cg3.c | 2 +- drivers/video/leo.c | 2 +- drivers/video/mb862xx/mb862xxfb.c | 2 +- drivers/video/p9100.c | 2 +- drivers/video/tcx.c | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c index 2c371c07f0da..09f1b9b462f4 100644 --- a/drivers/video/bw2.c +++ b/drivers/video/bw2.c @@ -275,7 +275,7 @@ static int __devinit bw2_do_default_mode(struct bw2_par *par, static int __devinit bw2_probe(struct of_device *op, const struct of_device_id *match) { - struct device_node *dp = op->node; + struct device_node *dp = op->dev.of_node; struct fb_info *info; struct bw2_par *par; int linebytes, err; diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c index d12e05b6e63f..e5dc2241194f 100644 --- a/drivers/video/cg14.c +++ b/drivers/video/cg14.c @@ -465,7 +465,7 @@ static void cg14_unmap_regs(struct of_device *op, struct fb_info *info, static int __devinit cg14_probe(struct of_device *op, const struct of_device_id *match) { - struct device_node *dp = op->node; + struct device_node *dp = op->dev.of_node; struct fb_info *info; struct cg14_par *par; int is_8mb, linebytes, i, err; diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c index b98f93f7f663..558d73a948a0 100644 --- a/drivers/video/cg3.c +++ b/drivers/video/cg3.c @@ -349,7 +349,7 @@ static int __devinit cg3_do_default_mode(struct cg3_par *par) static int __devinit cg3_probe(struct of_device *op, const struct of_device_id *match) { - struct device_node *dp = op->node; + struct device_node *dp = op->dev.of_node; struct fb_info *info; struct cg3_par *par; int linebytes, err; diff --git a/drivers/video/leo.c b/drivers/video/leo.c index 3d7895316eaf..9e8bf7d5e249 100644 --- a/drivers/video/leo.c +++ b/drivers/video/leo.c @@ -550,7 +550,7 @@ static void leo_unmap_regs(struct of_device *op, struct fb_info *info, static int __devinit leo_probe(struct of_device *op, const struct of_device_id *match) { - struct device_node *dp = op->node; + struct device_node *dp = op->dev.of_node; struct fb_info *info; struct leo_par *par; int linebytes, err; diff --git a/drivers/video/mb862xx/mb862xxfb.c b/drivers/video/mb862xx/mb862xxfb.c index 0540de4f5cb4..4e2b8cc3d460 100644 --- a/drivers/video/mb862xx/mb862xxfb.c +++ b/drivers/video/mb862xx/mb862xxfb.c @@ -553,7 +553,7 @@ static int mb862xx_gdc_init(struct mb862xxfb_par *par) static int __devinit of_platform_mb862xx_probe(struct of_device *ofdev, const struct of_device_id *id) { - struct device_node *np = ofdev->node; + struct device_node *np = ofdev->dev.of_node; struct device *dev = &ofdev->dev; struct mb862xxfb_par *par; struct fb_info *info; diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c index c85dd408a9b8..6552751e81aa 100644 --- a/drivers/video/p9100.c +++ b/drivers/video/p9100.c @@ -251,7 +251,7 @@ static void p9100_init_fix(struct fb_info *info, int linebytes, struct device_no static int __devinit p9100_probe(struct of_device *op, const struct of_device_id *match) { - struct device_node *dp = op->node; + struct device_node *dp = op->dev.of_node; struct fb_info *info; struct p9100_par *par; int linebytes, err; diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c index ef7a7bd8b503..cc039b33d2d8 100644 --- a/drivers/video/tcx.c +++ b/drivers/video/tcx.c @@ -365,7 +365,7 @@ static void tcx_unmap_regs(struct of_device *op, struct fb_info *info, static int __devinit tcx_probe(struct of_device *op, const struct of_device_id *match) { - struct device_node *dp = op->node; + struct device_node *dp = op->dev.of_node; struct fb_info *info; struct tcx_par *par; int linebytes, i, err; -- cgit v1.2.3 From c8a4d0fd2ac2ce6b3409f51fcf918dcb3617ec97 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Thu, 3 Jun 2010 02:37:17 +0200 Subject: of/mtd: nand: fix build breakage in drivers Fixes build errors in drivers caused by the OF device_node pointer being moved into struct device Signed-off-by: Anatolij Gustschin Signed-off-by: Grant Likely --- drivers/mtd/nand/fsl_upm.c | 17 +++++++++-------- drivers/mtd/nand/socrates_nand.c | 4 ++-- 2 files changed, 11 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c index 00aea6f7d1f1..1312eda57ba6 100644 --- a/drivers/mtd/nand/fsl_upm.c +++ b/drivers/mtd/nand/fsl_upm.c @@ -232,7 +232,7 @@ static int __devinit fun_probe(struct of_device *ofdev, if (!fun) return -ENOMEM; - ret = of_address_to_resource(ofdev->node, 0, &io_res); + ret = of_address_to_resource(ofdev->dev.of_node, 0, &io_res); if (ret) { dev_err(&ofdev->dev, "can't get IO base\n"); goto err1; @@ -244,7 +244,8 @@ static int __devinit fun_probe(struct of_device *ofdev, goto err1; } - prop = of_get_property(ofdev->node, "fsl,upm-addr-offset", &size); + prop = of_get_property(ofdev->dev.of_node, "fsl,upm-addr-offset", + &size); if (!prop || size != sizeof(uint32_t)) { dev_err(&ofdev->dev, "can't get UPM address offset\n"); ret = -EINVAL; @@ -252,7 +253,7 @@ static int __devinit fun_probe(struct of_device *ofdev, } fun->upm_addr_offset = *prop; - prop = of_get_property(ofdev->node, "fsl,upm-cmd-offset", &size); + prop = of_get_property(ofdev->dev.of_node, "fsl,upm-cmd-offset", &size); if (!prop || size != sizeof(uint32_t)) { dev_err(&ofdev->dev, "can't get UPM command offset\n"); ret = -EINVAL; @@ -260,7 +261,7 @@ static int __devinit fun_probe(struct of_device *ofdev, } fun->upm_cmd_offset = *prop; - prop = of_get_property(ofdev->node, + prop = of_get_property(ofdev->dev.of_node, "fsl,upm-addr-line-cs-offsets", &size); if (prop && (size / sizeof(uint32_t)) > 0) { fun->mchip_count = size / sizeof(uint32_t); @@ -276,7 +277,7 @@ static int __devinit fun_probe(struct of_device *ofdev, for (i = 0; i < fun->mchip_count; i++) { fun->rnb_gpio[i] = -1; - rnb_gpio = of_get_gpio(ofdev->node, i); + rnb_gpio = of_get_gpio(ofdev->dev.of_node, i); if (rnb_gpio >= 0) { ret = gpio_request(rnb_gpio, dev_name(&ofdev->dev)); if (ret) { @@ -292,13 +293,13 @@ static int __devinit fun_probe(struct of_device *ofdev, } } - prop = of_get_property(ofdev->node, "chip-delay", NULL); + prop = of_get_property(ofdev->dev.of_node, "chip-delay", NULL); if (prop) fun->chip_delay = *prop; else fun->chip_delay = 50; - prop = of_get_property(ofdev->node, "fsl,upm-wait-flags", &size); + prop = of_get_property(ofdev->dev.of_node, "fsl,upm-wait-flags", &size); if (prop && size == sizeof(uint32_t)) fun->wait_flags = *prop; else @@ -315,7 +316,7 @@ static int __devinit fun_probe(struct of_device *ofdev, fun->dev = &ofdev->dev; fun->last_ctrl = NAND_CLE; - ret = fun_chip_init(fun, ofdev->node, &io_res); + ret = fun_chip_init(fun, ofdev->dev.of_node, &io_res); if (ret) goto err2; diff --git a/drivers/mtd/nand/socrates_nand.c b/drivers/mtd/nand/socrates_nand.c index 884852dc7eb4..cc728b12de82 100644 --- a/drivers/mtd/nand/socrates_nand.c +++ b/drivers/mtd/nand/socrates_nand.c @@ -183,7 +183,7 @@ static int __devinit socrates_nand_probe(struct of_device *ofdev, return -ENOMEM; } - host->io_base = of_iomap(ofdev->node, 0); + host->io_base = of_iomap(ofdev->dev.of_node, 0); if (host->io_base == NULL) { printk(KERN_ERR "socrates_nand: ioremap failed\n"); kfree(host); @@ -244,7 +244,7 @@ static int __devinit socrates_nand_probe(struct of_device *ofdev, #ifdef CONFIG_MTD_OF_PARTS if (num_partitions == 0) { num_partitions = of_mtd_parse_partitions(&ofdev->dev, - ofdev->node, + ofdev->dev.of_node, &partitions); if (num_partitions < 0) { res = num_partitions; -- cgit v1.2.3 From 05c02542c20aa00dc9a66f4bfb1a89d1131457f2 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Thu, 3 Jun 2010 02:46:37 +0200 Subject: of/dma: fix build breakage in ppc4xx adma driver Fixes build error caused by the OF device_node pointer being moved into struct device Signed-off-by: Anatolij Gustschin Signed-off-by: Grant Likely --- drivers/dma/ppc4xx/adma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ppc4xx/adma.c b/drivers/dma/ppc4xx/adma.c index fa98abe4686f..5a22ca6927e5 100644 --- a/drivers/dma/ppc4xx/adma.c +++ b/drivers/dma/ppc4xx/adma.c @@ -4394,7 +4394,7 @@ static void ppc440spe_adma_release_irqs(struct ppc440spe_adma_device *adev, static int __devinit ppc440spe_adma_probe(struct of_device *ofdev, const struct of_device_id *match) { - struct device_node *np = ofdev->node; + struct device_node *np = ofdev->dev.of_node; struct resource res; struct ppc440spe_adma_device *adev; struct ppc440spe_adma_chan *chan; @@ -4626,7 +4626,7 @@ out: static int __devexit ppc440spe_adma_remove(struct of_device *ofdev) { struct ppc440spe_adma_device *adev = dev_get_drvdata(&ofdev->dev); - struct device_node *np = ofdev->node; + struct device_node *np = ofdev->dev.of_node; struct resource res; struct dma_chan *chan, *_chan; struct ppc_dma_chan_ref *ref, *_ref; -- cgit v1.2.3 From 7cea8cc4705d25d9c7baee06efd665db27481242 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Thu, 3 Jun 2010 02:53:18 +0200 Subject: of/crypto: crypto4xx_core.c: fix build breakage Fixes build error caused by the OF device_node pointer being moved into struct device Signed-off-by: Anatolij Gustschin Signed-off-by: Grant Likely --- drivers/crypto/amcc/crypto4xx_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index 9d65b371de64..983530ba04a7 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -1158,7 +1158,7 @@ static int __init crypto4xx_probe(struct of_device *ofdev, struct device *dev = &ofdev->dev; struct crypto4xx_core_device *core_dev; - rc = of_address_to_resource(ofdev->node, 0, &res); + rc = of_address_to_resource(ofdev->dev.of_node, 0, &res); if (rc) return -ENODEV; @@ -1215,13 +1215,13 @@ static int __init crypto4xx_probe(struct of_device *ofdev, (unsigned long) dev); /* Register for Crypto isr, Crypto Engine IRQ */ - core_dev->irq = irq_of_parse_and_map(ofdev->node, 0); + core_dev->irq = irq_of_parse_and_map(ofdev->dev.of_node, 0); rc = request_irq(core_dev->irq, crypto4xx_ce_interrupt_handler, 0, core_dev->dev->name, dev); if (rc) goto err_request_irq; - core_dev->dev->ce_base = of_iomap(ofdev->node, 0); + core_dev->dev->ce_base = of_iomap(ofdev->dev.of_node, 0); if (!core_dev->dev->ce_base) { dev_err(dev, "failed to of_iomap\n"); goto err_iomap; -- cgit v1.2.3 From 3ed3880230288c3eba1174b865ea7cdfbcb20033 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Thu, 3 Jun 2010 02:59:55 +0200 Subject: of/usb: fsl_qe_udc.c: fix build breakage Fixes build error caused by the OF device_node pointer being moved into struct device Signed-off-by: Anatolij Gustschin Signed-off-by: Grant Likely --- drivers/usb/gadget/fsl_qe_udc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c index 2928523268b5..82506ca297d5 100644 --- a/drivers/usb/gadget/fsl_qe_udc.c +++ b/drivers/usb/gadget/fsl_qe_udc.c @@ -2400,7 +2400,7 @@ EXPORT_SYMBOL(usb_gadget_unregister_driver); static struct qe_udc __devinit *qe_udc_config(struct of_device *ofdev) { struct qe_udc *udc; - struct device_node *np = ofdev->node; + struct device_node *np = ofdev->dev.of_node; unsigned int tmp_addr = 0; struct usb_device_para __iomem *usbpram; unsigned int i; @@ -2525,7 +2525,7 @@ static void qe_udc_release(struct device *dev) static int __devinit qe_udc_probe(struct of_device *ofdev, const struct of_device_id *match) { - struct device_node *np = ofdev->node; + struct device_node *np = ofdev->dev.of_node; struct qe_ep *ep; unsigned int ret = 0; unsigned int i; -- cgit v1.2.3 From 4eecb17825a9cd2ea750c177487000fab4c19ea2 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Thu, 3 Jun 2010 03:06:54 +0200 Subject: of/net: fs_enet/mii-bitbang.c: fix build breakage Fixes build error caused by the OF device_node pointer being moved into struct device Signed-off-by: Anatolij Gustschin Signed-off-by: Grant Likely --- drivers/net/fs_enet/mii-bitbang.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c index 0f90685d3d19..3607340f3da7 100644 --- a/drivers/net/fs_enet/mii-bitbang.c +++ b/drivers/net/fs_enet/mii-bitbang.c @@ -169,7 +169,7 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev, new_bus->name = "CPM2 Bitbanged MII", - ret = fs_mii_bitbang_init(new_bus, ofdev->node); + ret = fs_mii_bitbang_init(new_bus, ofdev->dev.of_node); if (ret) goto out_free_bus; @@ -181,7 +181,7 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev, new_bus->parent = &ofdev->dev; dev_set_drvdata(&ofdev->dev, new_bus); - ret = of_mdiobus_register(new_bus, ofdev->node); + ret = of_mdiobus_register(new_bus, ofdev->dev.of_node); if (ret) goto out_free_irqs; -- cgit v1.2.3 From a26f95fed31d917eee616d1cd6360e4ce782e3dc Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Thu, 3 Jun 2010 03:17:42 +0200 Subject: of/edac: fix build breakage in drivers Fixes build errors in EDAC drivers caused by the OF device_node pointer being moved into struct device Signed-off-by: Anatolij Gustschin Signed-off-by: Grant Likely --- drivers/edac/mpc85xx_edac.c | 12 ++++++------ drivers/edac/ppc4xx_edac.c | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index 6c1886b497ff..52ca09bf4726 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c @@ -229,7 +229,7 @@ static int __devinit mpc85xx_pci_err_probe(struct of_device *op, pdata->edac_idx = edac_pci_idx++; - res = of_address_to_resource(op->node, 0, &r); + res = of_address_to_resource(op->dev.of_node, 0, &r); if (res) { printk(KERN_ERR "%s: Unable to get resource for " "PCI err regs\n", __func__); @@ -274,7 +274,7 @@ static int __devinit mpc85xx_pci_err_probe(struct of_device *op, } if (edac_op_state == EDAC_OPSTATE_INT) { - pdata->irq = irq_of_parse_and_map(op->node, 0); + pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0); res = devm_request_irq(&op->dev, pdata->irq, mpc85xx_pci_isr, IRQF_DISABLED, "[EDAC] PCI err", pci); @@ -529,7 +529,7 @@ static int __devinit mpc85xx_l2_err_probe(struct of_device *op, edac_dev->ctl_name = pdata->name; edac_dev->dev_name = pdata->name; - res = of_address_to_resource(op->node, 0, &r); + res = of_address_to_resource(op->dev.of_node, 0, &r); if (res) { printk(KERN_ERR "%s: Unable to get resource for " "L2 err regs\n", __func__); @@ -576,7 +576,7 @@ static int __devinit mpc85xx_l2_err_probe(struct of_device *op, } if (edac_op_state == EDAC_OPSTATE_INT) { - pdata->irq = irq_of_parse_and_map(op->node, 0); + pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0); res = devm_request_irq(&op->dev, pdata->irq, mpc85xx_l2_isr, IRQF_DISABLED, "[EDAC] L2 err", edac_dev); @@ -978,7 +978,7 @@ static int __devinit mpc85xx_mc_err_probe(struct of_device *op, mci->ctl_name = pdata->name; mci->dev_name = pdata->name; - res = of_address_to_resource(op->node, 0, &r); + res = of_address_to_resource(op->dev.of_node, 0, &r); if (res) { printk(KERN_ERR "%s: Unable to get resource for MC err regs\n", __func__); @@ -1052,7 +1052,7 @@ static int __devinit mpc85xx_mc_err_probe(struct of_device *op, out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_SBE, 0x10000); /* register interrupts */ - pdata->irq = irq_of_parse_and_map(op->node, 0); + pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0); res = devm_request_irq(&op->dev, pdata->irq, mpc85xx_mc_isr, IRQF_DISABLED | IRQF_SHARED, diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c index 9d6f6783328c..e78839e89a06 100644 --- a/drivers/edac/ppc4xx_edac.c +++ b/drivers/edac/ppc4xx_edac.c @@ -1022,7 +1022,7 @@ ppc4xx_edac_mc_init(struct mem_ctl_info *mci, int status = 0; const u32 memcheck = (mcopt1 & SDRAM_MCOPT1_MCHK_MASK); struct ppc4xx_edac_pdata *pdata = NULL; - const struct device_node *np = op->node; + const struct device_node *np = op->dev.of_node; if (match == NULL) return -EINVAL; @@ -1113,7 +1113,7 @@ ppc4xx_edac_register_irq(struct of_device *op, struct mem_ctl_info *mci) int status = 0; int ded_irq, sec_irq; struct ppc4xx_edac_pdata *pdata = mci->pvt_info; - struct device_node *np = op->node; + struct device_node *np = op->dev.of_node; ded_irq = irq_of_parse_and_map(np, INTMAP_ECCDED_INDEX); sec_irq = irq_of_parse_and_map(np, INTMAP_ECCSEC_INDEX); @@ -1243,7 +1243,7 @@ ppc4xx_edac_probe(struct of_device *op, const struct of_device_id *match) int status = 0; u32 mcopt1, memcheck; dcr_host_t dcr_host; - const struct device_node *np = op->node; + const struct device_node *np = op->dev.of_node; struct mem_ctl_info *mci = NULL; static int ppc4xx_edac_instance; -- cgit v1.2.3 From b74dbf2aed8d8c4f93ac2c44bab5c81f65be62a0 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Thu, 3 Jun 2010 03:30:31 +0200 Subject: of/watchdog: gef_wdt.c: fix build breakage Fixes build error caused by the OF device_node pointer being moved into struct device Signed-off-by: Anatolij Gustschin Signed-off-by: Grant Likely --- drivers/watchdog/gef_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/watchdog/gef_wdt.c b/drivers/watchdog/gef_wdt.c index ca0f4c6cf5ab..1df284f9c2a1 100644 --- a/drivers/watchdog/gef_wdt.c +++ b/drivers/watchdog/gef_wdt.c @@ -273,7 +273,7 @@ static int __devinit gef_wdt_probe(struct of_device *dev, bus_clk = freq; /* Map devices registers into memory */ - gef_wdt_regs = of_iomap(dev->node, 0); + gef_wdt_regs = of_iomap(dev->dev.of_node, 0); if (gef_wdt_regs == NULL) return -ENOMEM; -- cgit v1.2.3 From 7ac9aa5a1f1b87adb69bcbec2b89e228f074103a Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 27 May 2010 19:25:54 -0400 Subject: drm/radeon/kms/pm: add support for SetVoltage cmd table (V2) - This enables voltage adjustment on r6xx+ and certain r5xx asics. - Voltage drop support is already available for most r1xx-r5xx asics. V2: endian fix for voltage table. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600.c | 6 ++++++ drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_atombios.c | 36 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/rs600.c | 3 ++- 4 files changed, 45 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 44e96a2ae25a..e14f59748e65 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -475,6 +475,12 @@ void r600_pm_init_profile(struct radeon_device *rdev) void r600_pm_misc(struct radeon_device *rdev) { + int requested_index = rdev->pm.requested_power_state_index; + struct radeon_power_state *ps = &rdev->pm.power_state[requested_index]; + struct radeon_voltage *voltage = &ps->clock_info[0].voltage; + + if ((voltage->type == VOLTAGE_SW) && voltage->voltage) + radeon_atom_set_voltage(rdev, voltage->voltage); } diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 669feb689bfc..5f96fe871b3f 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -176,6 +176,7 @@ void radeon_pm_suspend(struct radeon_device *rdev); void radeon_pm_resume(struct radeon_device *rdev); void radeon_combios_get_power_modes(struct radeon_device *rdev); void radeon_atombios_get_power_modes(struct radeon_device *rdev); +void radeon_atom_set_voltage(struct radeon_device *rdev, u16 level); /* * Fences. diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 24ea683f7cf5..24ebb4ea7984 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1998,6 +1998,42 @@ void radeon_atom_set_memory_clock(struct radeon_device *rdev, atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } +union set_voltage { + struct _SET_VOLTAGE_PS_ALLOCATION alloc; + struct _SET_VOLTAGE_PARAMETERS v1; + struct _SET_VOLTAGE_PARAMETERS_V2 v2; +}; + +void radeon_atom_set_voltage(struct radeon_device *rdev, u16 level) +{ + union set_voltage args; + int index = GetIndexIntoMasterTable(COMMAND, SetVoltage); + u8 frev, crev, volt_index = level; + + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) + return; + + switch (crev) { + case 1: + args.v1.ucVoltageType = SET_VOLTAGE_TYPE_ASIC_VDDC; + args.v1.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_ALL_SOURCE; + args.v1.ucVoltageIndex = volt_index; + break; + case 2: + args.v2.ucVoltageType = SET_VOLTAGE_TYPE_ASIC_VDDC; + args.v2.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_SET_VOLTAGE; + args.v2.usVoltageLevel = cpu_to_le16(level); + break; + default: + DRM_ERROR("Unknown table version %d, %d\n", frev, crev); + return; + } + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); +} + + + void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev) { struct radeon_device *rdev = dev->dev_private; diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 79887cac5b54..7bb4c3e52f3b 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -74,7 +74,8 @@ void rs600_pm_misc(struct radeon_device *rdev) if (voltage->delay) udelay(voltage->delay); } - } + } else if (voltage->type == VOLTAGE_VDDC) + radeon_atom_set_voltage(rdev, voltage->vddc_id); dyn_pwrmgt_sclk_length = RREG32_PLL(DYN_PWRMGT_SCLK_LENGTH); dyn_pwrmgt_sclk_length &= ~REDUCED_POWER_SCLK_HILEN(0xf); -- cgit v1.2.3 From 9349d5cc920c10845693f906ebd67f394f1d0d04 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 28 May 2010 19:35:01 -0400 Subject: drm/radeon/kms/pm: enable SetVoltage on r7xx/evergreen I missed these in the r6xx commit. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 5 +++++ drivers/gpu/drm/radeon/rv770.c | 5 +++++ 2 files changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 8c8e4d3cbaa3..0440c0939bdd 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -41,7 +41,12 @@ void evergreen_fini(struct radeon_device *rdev); void evergreen_pm_misc(struct radeon_device *rdev) { + int requested_index = rdev->pm.requested_power_state_index; + struct radeon_power_state *ps = &rdev->pm.power_state[requested_index]; + struct radeon_voltage *voltage = &ps->clock_info[0].voltage; + if ((voltage->type == VOLTAGE_SW) && voltage->voltage) + radeon_atom_set_voltage(rdev, voltage->voltage); } void evergreen_pm_prepare(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 253f24aec031..33952da65340 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -44,7 +44,12 @@ void rv770_fini(struct radeon_device *rdev); void rv770_pm_misc(struct radeon_device *rdev) { + int requested_index = rdev->pm.requested_power_state_index; + struct radeon_power_state *ps = &rdev->pm.power_state[requested_index]; + struct radeon_voltage *voltage = &ps->clock_info[0].voltage; + if ((voltage->type == VOLTAGE_SW) && voltage->voltage) + radeon_atom_set_voltage(rdev, voltage->voltage); } /* -- cgit v1.2.3 From c5e8ce61d64995f4076c6a9b2f8b4b71e0be2e37 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 27 May 2010 17:01:40 -0400 Subject: drm/radeon/kms/pm: patch default power state with default clocks/voltages on r6xx+ The default power state does not always match the default clocks and voltage for a particular card. The information in the firmware info table is correct and should be used in preference to the info the default power state. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_atombios.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 24ebb4ea7984..42bcaf41b8c4 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1755,9 +1755,22 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].misc2 = 0; } } else { + int fw_index = GetIndexIntoMasterTable(DATA, FirmwareInfo); + uint8_t fw_frev, fw_crev; + uint16_t fw_data_offset, vddc = 0; + union firmware_info *firmware_info; + ATOM_PPLIB_THERMALCONTROLLER *controller = &power_info->info_4.sThermalController; + + if (atom_parse_data_header(mode_info->atom_context, fw_index, NULL, + &fw_frev, &fw_crev, &fw_data_offset)) { + firmware_info = + (union firmware_info *)(mode_info->atom_context->bios + + fw_data_offset); + vddc = firmware_info->info_14.usBootUpVDDCVoltage; + } + /* add the i2c bus for thermal/fan chip */ /* no support for internal controller yet */ - ATOM_PPLIB_THERMALCONTROLLER *controller = &power_info->info_4.sThermalController; if (controller->ucType > 0) { if ((controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) || (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV770) || @@ -1904,6 +1917,16 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.default_power_state_index = state_index; rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[mode_index - 1]; + /* patch the table values with the default slck/mclk from firmware info */ + for (j = 0; j < mode_index; j++) { + rdev->pm.power_state[state_index].clock_info[j].mclk = + rdev->clock.default_mclk; + rdev->pm.power_state[state_index].clock_info[j].sclk = + rdev->clock.default_sclk; + if (vddc) + rdev->pm.power_state[state_index].clock_info[j].voltage.voltage = + vddc; + } } state_index++; } -- cgit v1.2.3 From 92645879d07a48897fe8888c2e37607aa1189cc9 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 27 May 2010 17:01:41 -0400 Subject: drm/radeon/kms/pm: radeon_set_power_state fixes - wait for vbl for both profile and dynpm - unify profile and dynpm code paths more - call pm_misc before of after clocks to make sure voltage is changed in the proper order. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_pm.c | 75 +++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index a8d162c6f829..02281269a881 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -151,6 +151,7 @@ static void radeon_sync_with_vblank(struct radeon_device *rdev) static void radeon_set_power_state(struct radeon_device *rdev) { u32 sclk, mclk; + bool misc_after = false; if ((rdev->pm.requested_clock_mode_index == rdev->pm.current_clock_mode_index) && (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index)) @@ -167,55 +168,47 @@ static void radeon_set_power_state(struct radeon_device *rdev) if (mclk > rdev->clock.default_mclk) mclk = rdev->clock.default_mclk; - /* voltage, pcie lanes, etc.*/ - radeon_pm_misc(rdev); + /* upvolt before raising clocks, downvolt after lowering clocks */ + if (sclk < rdev->pm.current_sclk) + misc_after = true; - if (rdev->pm.pm_method == PM_METHOD_DYNPM) { - radeon_sync_with_vblank(rdev); + radeon_sync_with_vblank(rdev); + if (rdev->pm.pm_method == PM_METHOD_DYNPM) { if (!radeon_pm_in_vbl(rdev)) return; + } - radeon_pm_prepare(rdev); - /* set engine clock */ - if (sclk != rdev->pm.current_sclk) { - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_engine_clock(rdev, sclk); - radeon_pm_debug_check_in_vbl(rdev, true); - rdev->pm.current_sclk = sclk; - DRM_DEBUG("Setting: e: %d\n", sclk); - } + radeon_pm_prepare(rdev); - /* set memory clock */ - if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_memory_clock(rdev, mclk); - radeon_pm_debug_check_in_vbl(rdev, true); - rdev->pm.current_mclk = mclk; - DRM_DEBUG("Setting: m: %d\n", mclk); - } - radeon_pm_finish(rdev); - } else { - /* set engine clock */ - if (sclk != rdev->pm.current_sclk) { - radeon_sync_with_vblank(rdev); - radeon_pm_prepare(rdev); - radeon_set_engine_clock(rdev, sclk); - radeon_pm_finish(rdev); - rdev->pm.current_sclk = sclk; - DRM_DEBUG("Setting: e: %d\n", sclk); - } - /* set memory clock */ - if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { - radeon_sync_with_vblank(rdev); - radeon_pm_prepare(rdev); - radeon_set_memory_clock(rdev, mclk); - radeon_pm_finish(rdev); - rdev->pm.current_mclk = mclk; - DRM_DEBUG("Setting: m: %d\n", mclk); - } + if (!misc_after) + /* voltage, pcie lanes, etc.*/ + radeon_pm_misc(rdev); + + /* set engine clock */ + if (sclk != rdev->pm.current_sclk) { + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_set_engine_clock(rdev, sclk); + radeon_pm_debug_check_in_vbl(rdev, true); + rdev->pm.current_sclk = sclk; + DRM_DEBUG("Setting: e: %d\n", sclk); + } + + /* set memory clock */ + if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_set_memory_clock(rdev, mclk); + radeon_pm_debug_check_in_vbl(rdev, true); + rdev->pm.current_mclk = mclk; + DRM_DEBUG("Setting: m: %d\n", mclk); } + if (misc_after) + /* voltage, pcie lanes, etc.*/ + radeon_pm_misc(rdev); + + radeon_pm_finish(rdev); + rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index; } else -- cgit v1.2.3 From 84d88f4c92763f519b9e081cdd685a44de14f8c0 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 27 May 2010 17:01:42 -0400 Subject: drm/radeon/kms/pm: voltage fixes - Enable GPIO voltage for non pm modes as well so resetting the default voltage works. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_atombios.c | 9 ++++++--- drivers/gpu/drm/radeon/radeon_combios.c | 7 ++++++- 2 files changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 42bcaf41b8c4..4305cd55d0ac 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1538,7 +1538,8 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].pcie_lanes = power_info->info.asPowerPlayInfo[i].ucNumPciELanes; misc = le32_to_cpu(power_info->info.asPowerPlayInfo[i].ulMiscInfo); - if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) { + if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) || + (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) { rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_GPIO; rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = @@ -1605,7 +1606,8 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) power_info->info_2.asPowerPlayInfo[i].ucNumPciELanes; misc = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo); misc2 = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo2); - if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) { + if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) || + (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) { rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_GPIO; rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = @@ -1679,7 +1681,8 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) power_info->info_3.asPowerPlayInfo[i].ucNumPciELanes; misc = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo); misc2 = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo2); - if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) { + if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) || + (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) { rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_GPIO; rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 7b5e10d3e9c9..102c744eaf5a 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -2454,7 +2454,12 @@ default_mode: rdev->pm.power_state[state_index].clock_info[0].mclk = rdev->clock.default_mclk; rdev->pm.power_state[state_index].clock_info[0].sclk = rdev->clock.default_sclk; rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[0]; - rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; + if ((state_index > 0) && + (rdev->pm.power_state[0].clock_info[0].voltage.type = VOLTAGE_GPIO)) + rdev->pm.power_state[state_index].clock_info[0].voltage = + rdev->pm.power_state[0].clock_info[0].voltage; + else + rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; rdev->pm.power_state[state_index].pcie_lanes = 16; rdev->pm.power_state[state_index].flags = 0; rdev->pm.default_power_state_index = state_index; -- cgit v1.2.3 From 2d6e9b91971034103ac51b20fa692258bf6bdd40 Mon Sep 17 00:00:00 2001 From: Tiago Vignatti Date: Mon, 24 May 2010 18:24:30 +0300 Subject: vgaarb: convert pr_devel() to pr_debug() We want to be able to use CONFIG_DYNAMIC_DEBUG in arbiter code, switch the few existing pr_devel() calls to pr_debug(). Also, add one more debug information regarding decoding count. Signed-off-by: Tiago Vignatti Signed-off-by: Dave Airlie --- drivers/gpu/vga/vgaarb.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c index 441e38c95a85..290b0ccea63d 100644 --- a/drivers/gpu/vga/vgaarb.c +++ b/drivers/gpu/vga/vgaarb.c @@ -155,8 +155,8 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev, (vgadev->decodes & VGA_RSRC_LEGACY_MEM)) rsrc |= VGA_RSRC_LEGACY_MEM; - pr_devel("%s: %d\n", __func__, rsrc); - pr_devel("%s: owns: %d\n", __func__, vgadev->owns); + pr_debug("%s: %d\n", __func__, rsrc); + pr_debug("%s: owns: %d\n", __func__, vgadev->owns); /* Check what resources we need to acquire */ wants = rsrc & ~vgadev->owns; @@ -268,7 +268,7 @@ static void __vga_put(struct vga_device *vgadev, unsigned int rsrc) { unsigned int old_locks = vgadev->locks; - pr_devel("%s\n", __func__); + pr_debug("%s\n", __func__); /* Update our counters, and account for equivalent legacy resources * if we decode them @@ -575,6 +575,7 @@ static inline void vga_update_device_decodes(struct vga_device *vgadev, else vga_decode_count--; } + pr_debug("vgaarb: decoding count now is: %d\n", vga_decode_count); } void __vga_set_legacy_decoding(struct pci_dev *pdev, unsigned int decodes, bool userspace) @@ -831,7 +832,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf, curr_pos += 5; remaining -= 5; - pr_devel("client 0x%p called 'lock'\n", priv); + pr_debug("client 0x%p called 'lock'\n", priv); if (!vga_str_to_iostate(curr_pos, remaining, &io_state)) { ret_val = -EPROTO; @@ -867,7 +868,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf, curr_pos += 7; remaining -= 7; - pr_devel("client 0x%p called 'unlock'\n", priv); + pr_debug("client 0x%p called 'unlock'\n", priv); if (strncmp(curr_pos, "all", 3) == 0) io_state = VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM; @@ -917,7 +918,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf, curr_pos += 8; remaining -= 8; - pr_devel("client 0x%p called 'trylock'\n", priv); + pr_debug("client 0x%p called 'trylock'\n", priv); if (!vga_str_to_iostate(curr_pos, remaining, &io_state)) { ret_val = -EPROTO; @@ -961,7 +962,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf, curr_pos += 7; remaining -= 7; - pr_devel("client 0x%p called 'target'\n", priv); + pr_debug("client 0x%p called 'target'\n", priv); /* if target is default */ if (!strncmp(curr_pos, "default", 7)) pdev = pci_dev_get(vga_default_device()); @@ -971,11 +972,11 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf, ret_val = -EPROTO; goto done; } - pr_devel("vgaarb: %s ==> %x:%x:%x.%x\n", curr_pos, + pr_debug("vgaarb: %s ==> %x:%x:%x.%x\n", curr_pos, domain, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); pbus = pci_find_bus(domain, bus); - pr_devel("vgaarb: pbus %p\n", pbus); + pr_debug("vgaarb: pbus %p\n", pbus); if (pbus == NULL) { pr_err("vgaarb: invalid PCI domain and/or bus address %x:%x\n", domain, bus); @@ -983,7 +984,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf, goto done; } pdev = pci_get_slot(pbus, devfn); - pr_devel("vgaarb: pdev %p\n", pdev); + pr_debug("vgaarb: pdev %p\n", pdev); if (!pdev) { pr_err("vgaarb: invalid PCI address %x:%x\n", bus, devfn); @@ -993,7 +994,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf, } vgadev = vgadev_find(pdev); - pr_devel("vgaarb: vgadev %p\n", vgadev); + pr_debug("vgaarb: vgadev %p\n", vgadev); if (vgadev == NULL) { pr_err("vgaarb: this pci device is not a vga device\n"); pci_dev_put(pdev); @@ -1029,7 +1030,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf, } else if (strncmp(curr_pos, "decodes ", 8) == 0) { curr_pos += 8; remaining -= 8; - pr_devel("vgaarb: client 0x%p called 'decodes'\n", priv); + pr_debug("vgaarb: client 0x%p called 'decodes'\n", priv); if (!vga_str_to_iostate(curr_pos, remaining, &io_state)) { ret_val = -EPROTO; @@ -1058,7 +1059,7 @@ static unsigned int vga_arb_fpoll(struct file *file, poll_table * wait) { struct vga_arb_private *priv = file->private_data; - pr_devel("%s\n", __func__); + pr_debug("%s\n", __func__); if (priv == NULL) return -ENODEV; @@ -1071,7 +1072,7 @@ static int vga_arb_open(struct inode *inode, struct file *file) struct vga_arb_private *priv; unsigned long flags; - pr_devel("%s\n", __func__); + pr_debug("%s\n", __func__); priv = kmalloc(sizeof(struct vga_arb_private), GFP_KERNEL); if (priv == NULL) @@ -1101,7 +1102,7 @@ static int vga_arb_release(struct inode *inode, struct file *file) unsigned long flags; int i; - pr_devel("%s\n", __func__); + pr_debug("%s\n", __func__); if (priv == NULL) return -ENODEV; @@ -1112,7 +1113,7 @@ static int vga_arb_release(struct inode *inode, struct file *file) uc = &priv->cards[i]; if (uc->pdev == NULL) continue; - pr_devel("uc->io_cnt == %d, uc->mem_cnt == %d\n", + pr_debug("uc->io_cnt == %d, uc->mem_cnt == %d\n", uc->io_cnt, uc->mem_cnt); while (uc->io_cnt--) vga_put(uc->pdev, VGA_RSRC_LEGACY_IO); @@ -1165,7 +1166,7 @@ static int pci_notify(struct notifier_block *nb, unsigned long action, struct pci_dev *pdev = to_pci_dev(dev); bool notify = false; - pr_devel("%s\n", __func__); + pr_debug("%s\n", __func__); /* For now we're only intereted in devices added and removed. I didn't * test this thing here, so someone needs to double check for the -- cgit v1.2.3 From c0db9cbc73338d8e2987a19a02388d67aeec0bfe Mon Sep 17 00:00:00 2001 From: Tiago Vignatti Date: Mon, 24 May 2010 18:24:31 +0300 Subject: vgaarb: use MIT license Signed-off-by: Tiago Vignatti Cc: Henry Zhao Signed-off-by: Dave Airlie --- drivers/gpu/vga/vgaarb.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c index 290b0ccea63d..b87569e96b16 100644 --- a/drivers/gpu/vga/vgaarb.c +++ b/drivers/gpu/vga/vgaarb.c @@ -1,12 +1,32 @@ /* - * vgaarb.c + * vgaarb.c: Implements the VGA arbitration. For details refer to + * Documentation/vgaarbiter.txt + * * * (C) Copyright 2005 Benjamin Herrenschmidt * (C) Copyright 2007 Paulo R. Zanoni * (C) Copyright 2007, 2009 Tiago Vignatti * - * Implements the VGA arbitration. For details refer to - * Documentation/vgaarbiter.txt + * 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 (including the next + * paragraph) 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. + * */ #include -- cgit v1.2.3 From 7c4f77801f103c9eb0465bf42313d5e1721d2991 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 1 Jun 2010 11:38:17 +0200 Subject: drm/vmwgfx: Fix vga save / restore with display topology. vga save / restore previously didn't handle the display topology case. Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 15 +++++++++++- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 48 ++++++++++++++++++++++++++++++++----- 2 files changed, 56 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 1341adef408d..e577af5bb3d6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -47,6 +47,7 @@ #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) #define VMWGFX_MAX_RELOCATIONS 2048 #define VMWGFX_MAX_GMRS 2048 +#define VMWGFX_MAX_DISPLAYS 16 struct vmw_fpriv { struct drm_master *locked_master; @@ -152,6 +153,14 @@ struct vmw_master { struct ttm_lock lock; }; +struct vmw_vga_topology_state { + uint32_t width; + uint32_t height; + uint32_t primary; + uint32_t pos_x; + uint32_t pos_y; +}; + struct vmw_private { struct ttm_bo_device bdev; struct ttm_bo_global_ref bo_global_ref; @@ -179,16 +188,20 @@ struct vmw_private { * VGA registers. */ + struct vmw_vga_topology_state vga_save[VMWGFX_MAX_DISPLAYS]; uint32_t vga_width; uint32_t vga_height; uint32_t vga_depth; uint32_t vga_bpp; uint32_t vga_pseudo; uint32_t vga_red_mask; - uint32_t vga_blue_mask; uint32_t vga_green_mask; + uint32_t vga_blue_mask; + uint32_t vga_bpl; uint32_t vga_pitchlock; + uint32_t num_displays; + /* * Framebuffer info. */ diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index b78dcf001858..648ba044f6f8 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -865,30 +865,52 @@ void vmw_kms_write_svga(struct vmw_private *vmw_priv, int vmw_kms_save_vga(struct vmw_private *vmw_priv) { + struct vmw_vga_topology_state *save; + uint32_t i; + vmw_priv->vga_width = vmw_read(vmw_priv, SVGA_REG_WIDTH); vmw_priv->vga_height = vmw_read(vmw_priv, SVGA_REG_HEIGHT); - vmw_priv->vga_bpp = vmw_read(vmw_priv, SVGA_REG_BITS_PER_PIXEL); vmw_priv->vga_depth = vmw_read(vmw_priv, SVGA_REG_DEPTH); + vmw_priv->vga_bpp = vmw_read(vmw_priv, SVGA_REG_BITS_PER_PIXEL); vmw_priv->vga_pseudo = vmw_read(vmw_priv, SVGA_REG_PSEUDOCOLOR); vmw_priv->vga_red_mask = vmw_read(vmw_priv, SVGA_REG_RED_MASK); - vmw_priv->vga_green_mask = vmw_read(vmw_priv, SVGA_REG_GREEN_MASK); vmw_priv->vga_blue_mask = vmw_read(vmw_priv, SVGA_REG_BLUE_MASK); + vmw_priv->vga_green_mask = vmw_read(vmw_priv, SVGA_REG_GREEN_MASK); if (vmw_priv->capabilities & SVGA_CAP_PITCHLOCK) vmw_priv->vga_pitchlock = - vmw_read(vmw_priv, SVGA_REG_PITCHLOCK); + vmw_read(vmw_priv, SVGA_REG_PITCHLOCK); else if (vmw_fifo_have_pitchlock(vmw_priv)) - vmw_priv->vga_pitchlock = - ioread32(vmw_priv->mmio_virt + SVGA_FIFO_PITCHLOCK); + vmw_priv->vga_pitchlock = ioread32(vmw_priv->mmio_virt + + SVGA_FIFO_PITCHLOCK); + + if (!(vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY)) + return 0; + vmw_priv->num_displays = vmw_read(vmw_priv, + SVGA_REG_NUM_GUEST_DISPLAYS); + + for (i = 0; i < vmw_priv->num_displays; ++i) { + save = &vmw_priv->vga_save[i]; + vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, i); + save->primary = vmw_read(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY); + save->pos_x = vmw_read(vmw_priv, SVGA_REG_DISPLAY_POSITION_X); + save->pos_y = vmw_read(vmw_priv, SVGA_REG_DISPLAY_POSITION_Y); + save->width = vmw_read(vmw_priv, SVGA_REG_DISPLAY_WIDTH); + save->height = vmw_read(vmw_priv, SVGA_REG_DISPLAY_HEIGHT); + vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); + } return 0; } int vmw_kms_restore_vga(struct vmw_private *vmw_priv) { + struct vmw_vga_topology_state *save; + uint32_t i; + vmw_write(vmw_priv, SVGA_REG_WIDTH, vmw_priv->vga_width); vmw_write(vmw_priv, SVGA_REG_HEIGHT, vmw_priv->vga_height); - vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, vmw_priv->vga_bpp); vmw_write(vmw_priv, SVGA_REG_DEPTH, vmw_priv->vga_depth); + vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, vmw_priv->vga_bpp); vmw_write(vmw_priv, SVGA_REG_PSEUDOCOLOR, vmw_priv->vga_pseudo); vmw_write(vmw_priv, SVGA_REG_RED_MASK, vmw_priv->vga_red_mask); vmw_write(vmw_priv, SVGA_REG_GREEN_MASK, vmw_priv->vga_green_mask); @@ -900,5 +922,19 @@ int vmw_kms_restore_vga(struct vmw_private *vmw_priv) iowrite32(vmw_priv->vga_pitchlock, vmw_priv->mmio_virt + SVGA_FIFO_PITCHLOCK); + if (!(vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY)) + return 0; + + for (i = 0; i < vmw_priv->num_displays; ++i) { + save = &vmw_priv->vga_save[i]; + vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, i); + vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, save->primary); + vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, save->pos_x); + vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_Y, save->pos_y); + vmw_write(vmw_priv, SVGA_REG_DISPLAY_WIDTH, save->width); + vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, save->height); + vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); + } + return 0; } -- cgit v1.2.3 From 991b7b44f8cfa1b9beff8c4c2f2ec888b925c2a7 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 1 Jun 2010 11:38:16 +0200 Subject: drm/vmwgfx: Fix framebuffer modesetting Must set SVGA_NUM_REG_GUEST_DISPLAY before setting up the display information. Signed-off-by: Jakob Bornecrantz Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index 181f47222580..b0866f04ec76 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -152,20 +152,12 @@ static int vmw_fb_set_par(struct fb_info *info) struct vmw_fb_par *par = info->par; struct vmw_private *vmw_priv = par->vmw_priv; + vmw_kms_write_svga(vmw_priv, info->var.xres, info->var.yres, + info->fix.line_length, + par->bpp, par->depth); if (vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY) { - vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, 0); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, 0); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_Y, 0); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_WIDTH, 0); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, 0); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); - - vmw_kms_write_svga(vmw_priv, info->var.xres, info->var.yres, - info->fix.line_length, - par->bpp, par->depth); - /* TODO check if pitch and offset changes */ + vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1); vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, 0); vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true); vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, info->var.xoffset); @@ -173,12 +165,6 @@ static int vmw_fb_set_par(struct fb_info *info) vmw_write(vmw_priv, SVGA_REG_DISPLAY_WIDTH, info->var.xres); vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, info->var.yres); vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); - vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1); - } else { - vmw_kms_write_svga(vmw_priv, info->var.xres, info->var.yres, - info->fix.line_length, - par->bpp, par->depth); - } /* This is really helpful since if this fails the user -- cgit v1.2.3 From d8bd19d2aff95e52c7f356cc2fc722584a656065 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 1 Jun 2010 11:54:20 +0200 Subject: drm/vmwgfx: Allow userspace to change default layout. Bump minor. The host may change the layout and, since the change is communicated to the master, the master needs a way to communicate the change to the kernel driver. The minor version number is bumped to advertize the availability of this feature. Signed-off-by: Jakob Bornecrantz Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 7 +++- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 4 +- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 45 ++++++++++++++++++++ drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 4 +- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 83 ++++++++++++++++++++++++++++++++++--- 5 files changed, 134 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 7597323d5a5a..b793c8c9acb3 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -88,6 +88,9 @@ #define DRM_IOCTL_VMW_FENCE_WAIT \ DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_FENCE_WAIT, \ struct drm_vmw_fence_wait_arg) +#define DRM_IOCTL_VMW_UPDATE_LAYOUT \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_UPDATE_LAYOUT, \ + struct drm_vmw_update_layout_arg) /** @@ -135,7 +138,9 @@ static struct drm_ioctl_desc vmw_ioctls[] = { VMW_IOCTL_DEF(DRM_IOCTL_VMW_FIFO_DEBUG, vmw_fifo_debug_ioctl, DRM_AUTH | DRM_ROOT_ONLY | DRM_MASTER | DRM_UNLOCKED), VMW_IOCTL_DEF(DRM_IOCTL_VMW_FENCE_WAIT, vmw_fence_wait_ioctl, - DRM_AUTH | DRM_UNLOCKED) + DRM_AUTH | DRM_UNLOCKED), + VMW_IOCTL_DEF(DRM_IOCTL_VMW_UPDATE_LAYOUT, vmw_kms_update_layout_ioctl, + DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED) }; static struct pci_device_id vmw_pci_id_list[] = { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index e577af5bb3d6..eaad52095339 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -41,7 +41,7 @@ #define VMWGFX_DRIVER_DATE "20100209" #define VMWGFX_DRIVER_MAJOR 1 -#define VMWGFX_DRIVER_MINOR 1 +#define VMWGFX_DRIVER_MINOR 2 #define VMWGFX_DRIVER_PATCHLEVEL 0 #define VMWGFX_FILE_PAGE_OFFSET 0x00100000 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) @@ -509,6 +509,8 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf, void vmw_kms_write_svga(struct vmw_private *vmw_priv, unsigned width, unsigned height, unsigned pitch, unsigned bbp, unsigned depth); +int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); /** * Overlay control - vmwgfx_overlay.c diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 648ba044f6f8..f1d626112415 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -938,3 +938,48 @@ int vmw_kms_restore_vga(struct vmw_private *vmw_priv) return 0; } + +int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct vmw_private *dev_priv = vmw_priv(dev); + struct drm_vmw_update_layout_arg *arg = + (struct drm_vmw_update_layout_arg *)data; + struct vmw_master *vmaster = vmw_master(file_priv->master); + void __user *user_rects; + struct drm_vmw_rect *rects; + unsigned rects_size; + int ret; + + ret = ttm_read_lock(&vmaster->lock, true); + if (unlikely(ret != 0)) + return ret; + + if (!arg->num_outputs) { + struct drm_vmw_rect def_rect = {0, 0, 800, 600}; + vmw_kms_ldu_update_layout(dev_priv, 1, &def_rect); + goto out_unlock; + } + + rects_size = arg->num_outputs * sizeof(struct drm_vmw_rect); + rects = kzalloc(rects_size, GFP_KERNEL); + if (unlikely(!rects)) { + ret = -ENOMEM; + goto out_unlock; + } + + user_rects = (void __user *)(unsigned long)arg->rects; + ret = copy_from_user(rects, user_rects, rects_size); + if (unlikely(ret != 0)) { + DRM_ERROR("Failed to get rects.\n"); + goto out_free; + } + + vmw_kms_ldu_update_layout(dev_priv, arg->num_outputs, rects); + +out_free: + kfree(rects); +out_unlock: + ttm_read_unlock(&vmaster->lock); + return ret; +} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 8b95249f0531..8a398a0339b6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -94,9 +94,11 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y); /* - * Legacy display unit functions - vmwgfx_ldu.h + * Legacy display unit functions - vmwgfx_ldu.c */ int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv); int vmw_kms_close_legacy_display_system(struct vmw_private *dev_priv); +int vmw_kms_ldu_update_layout(struct vmw_private *dev_priv, unsigned num, + struct drm_vmw_rect *rects); #endif diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index f7094dde18f9..cfaf690a5b2f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -49,6 +49,11 @@ struct vmw_legacy_display { struct vmw_legacy_display_unit { struct vmw_display_unit base; + unsigned pref_width; + unsigned pref_height; + bool pref_active; + struct drm_display_mode *pref_mode; + struct list_head active; }; @@ -332,8 +337,7 @@ static void vmw_ldu_connector_restore(struct drm_connector *connector) static enum drm_connector_status vmw_ldu_connector_detect(struct drm_connector *connector) { - /* XXX vmwctrl should control connection status */ - if (vmw_connector_to_ldu(connector)->base.unit == 0) + if (vmw_connector_to_ldu(connector)->pref_active) return connector_status_connected; return connector_status_disconnected; } @@ -344,10 +348,9 @@ static struct drm_display_mode vmw_ldu_connector_builtin[] = { 752, 800, 0, 480, 489, 492, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 800x600@60Hz */ - { DRM_MODE("800x600", - DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, - 40000, 800, 840, 968, 1056, 0, 600, 601, 605, 628, - 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840, + 968, 1056, 0, 600, 601, 605, 628, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1024x768@60Hz */ { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048, 1184, 1344, 0, 768, 771, 777, 806, 0, @@ -419,10 +422,34 @@ static struct drm_display_mode vmw_ldu_connector_builtin[] = { static int vmw_ldu_connector_fill_modes(struct drm_connector *connector, uint32_t max_width, uint32_t max_height) { + struct vmw_legacy_display_unit *ldu = vmw_connector_to_ldu(connector); struct drm_device *dev = connector->dev; struct drm_display_mode *mode = NULL; + struct drm_display_mode prefmode = { DRM_MODE("preferred", + DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) + }; int i; + /* Add preferred mode */ + { + mode = drm_mode_duplicate(dev, &prefmode); + if (!mode) + return 0; + mode->hdisplay = ldu->pref_width; + mode->vdisplay = ldu->pref_height; + mode->vrefresh = drm_mode_vrefresh(mode); + drm_mode_probed_add(connector, mode); + + if (ldu->pref_mode) { + list_del_init(&ldu->pref_mode->head); + drm_mode_destroy(dev, ldu->pref_mode); + } + + ldu->pref_mode = mode; + } + for (i = 0; vmw_ldu_connector_builtin[i].type != 0; i++) { if (vmw_ldu_connector_builtin[i].hdisplay > max_width || vmw_ldu_connector_builtin[i].vdisplay > max_height) @@ -482,6 +509,11 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) INIT_LIST_HEAD(&ldu->active); + ldu->pref_active = (unit == 0); + ldu->pref_width = 800; + ldu->pref_height = 600; + ldu->pref_mode = NULL; + drm_connector_init(dev, connector, &vmw_legacy_connector_funcs, DRM_MODE_CONNECTOR_LVDS); connector->status = vmw_ldu_connector_detect(connector); @@ -546,3 +578,42 @@ int vmw_kms_close_legacy_display_system(struct vmw_private *dev_priv) return 0; } + +int vmw_kms_ldu_update_layout(struct vmw_private *dev_priv, unsigned num, + struct drm_vmw_rect *rects) +{ + struct drm_device *dev = dev_priv->dev; + struct vmw_legacy_display_unit *ldu; + struct drm_connector *con; + int i; + + mutex_lock(&dev->mode_config.mutex); + +#if 0 + DRM_INFO("%s: new layout ", __func__); + for (i = 0; i < (int)num; i++) + DRM_INFO("(%i, %i %ux%u) ", rects[i].x, rects[i].y, + rects[i].w, rects[i].h); + DRM_INFO("\n"); +#else + (void)i; +#endif + + list_for_each_entry(con, &dev->mode_config.connector_list, head) { + ldu = vmw_connector_to_ldu(con); + if (num > ldu->base.unit) { + ldu->pref_width = rects[ldu->base.unit].w; + ldu->pref_height = rects[ldu->base.unit].h; + ldu->pref_active = true; + } else { + ldu->pref_width = 800; + ldu->pref_height = 600; + ldu->pref_active = false; + } + con->status = vmw_ldu_connector_detect(con); + } + + mutex_unlock(&dev->mode_config.mutex); + + return 0; +} -- cgit v1.2.3 From d8dcaa1dc50f5aecd38d34180cd99d6af8566c88 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 2 Jun 2010 12:08:41 -0400 Subject: drm/radeon/kms: make sure display hw is disabled when suspending Disable the display hw when suspending. Should fix bug: https://bugzilla.redhat.com/show_bug.cgi?id=522393 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_device.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index db338522191f..f10faed21567 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -713,6 +713,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state) { struct radeon_device *rdev; struct drm_crtc *crtc; + struct drm_connector *connector; int r; if (dev == NULL || dev->dev_private == NULL) { @@ -725,6 +726,12 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state) if (rdev->powered_down) return 0; + + /* turn off display hw */ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); + } + /* unpin the front buffers */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->fb); -- cgit v1.2.3 From 5869d2c387e75814334697c9d702d91b7c63a308 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Wed, 2 Jun 2010 18:22:48 +0300 Subject: mtd: Fix NAND submenu Move MTD_NAND_ECC and MTD_NAND_ECC_SMC above NAND memuconfig, to unbreak display in xconfig. This shouldn't change any dependencies. Signed-off-by: Maxim Levitsky Signed-off-by: David Woodhouse --- drivers/mtd/nand/Kconfig | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 98a04b3c9526..ffc3720929f1 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -1,13 +1,3 @@ -menuconfig MTD_NAND - tristate "NAND Device Support" - depends on MTD - select MTD_NAND_IDS - select MTD_NAND_ECC - help - This enables support for accessing all type of NAND flash - devices. For further information see - . - config MTD_NAND_ECC tristate @@ -19,6 +9,17 @@ config MTD_NAND_ECC_SMC Software ECC according to the Smart Media Specification. The original Linux implementation had byte 0 and 1 swapped. + +menuconfig MTD_NAND + tristate "NAND Device Support" + depends on MTD + select MTD_NAND_IDS + select MTD_NAND_ECC + help + This enables support for accessing all type of NAND flash + devices. For further information see + . + if MTD_NAND config MTD_NAND_VERIFY_WRITE -- cgit v1.2.3 From 0f0a8fa735bbde4b0bc3e96e4bb2e5b380a324db Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Thu, 3 Jun 2010 16:53:49 +1000 Subject: crypto: crypto4xx - Fix build breakage Fixes build error caused by the OF device_node pointer being moved into struct device Signed-off-by: Anatolij Gustschin Signed-off-by: Herbert Xu --- drivers/crypto/amcc/crypto4xx_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index 9d65b371de64..983530ba04a7 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -1158,7 +1158,7 @@ static int __init crypto4xx_probe(struct of_device *ofdev, struct device *dev = &ofdev->dev; struct crypto4xx_core_device *core_dev; - rc = of_address_to_resource(ofdev->node, 0, &res); + rc = of_address_to_resource(ofdev->dev.of_node, 0, &res); if (rc) return -ENODEV; @@ -1215,13 +1215,13 @@ static int __init crypto4xx_probe(struct of_device *ofdev, (unsigned long) dev); /* Register for Crypto isr, Crypto Engine IRQ */ - core_dev->irq = irq_of_parse_and_map(ofdev->node, 0); + core_dev->irq = irq_of_parse_and_map(ofdev->dev.of_node, 0); rc = request_irq(core_dev->irq, crypto4xx_ce_interrupt_handler, 0, core_dev->dev->name, dev); if (rc) goto err_request_irq; - core_dev->dev->ce_base = of_iomap(ofdev->node, 0); + core_dev->dev->ce_base = of_iomap(ofdev->dev.of_node, 0); if (!core_dev->dev->ce_base) { dev_err(dev, "failed to of_iomap\n"); goto err_iomap; -- cgit v1.2.3 From b3831cb55d383e8eb55d3b56c715fb48459b87c9 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Tue, 25 May 2010 10:45:35 +0100 Subject: xen: avoid allocation causing potential swap activity on the resume path Since the device we are resuming could be the device containing the swap device we should ensure that the allocation cannot cause IO. On resume, this path is triggered when the running system tries to continue using its devices. If it cannot then the resume will fail; to try to avoid this we let it dip into the emergency pools. The majority of these changes were made when linux-2.6.18-xen.hg changeset e8b49cfbdac0 was ported upstream in a144ff09bc52ef3f3684ed23eadc9c7c0e57b3aa but somehow this hunk was dropped. Signed-off-by: Ian Campbell Acked-by: Jeremy Fitzhardinge Cc: Stable Kernel # .32.x --- drivers/xen/xenbus/xenbus_xs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c index eab33f1dbdf7..7b547f53f65e 100644 --- a/drivers/xen/xenbus/xenbus_xs.c +++ b/drivers/xen/xenbus/xenbus_xs.c @@ -499,7 +499,7 @@ int xenbus_printf(struct xenbus_transaction t, #define PRINTF_BUFFER_SIZE 4096 char *printf_buffer; - printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL); + printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_NOIO | __GFP_HIGH); if (printf_buffer == NULL) return -ENOMEM; -- cgit v1.2.3 From 63e4e80218803ff506b3ea4f2349b17916a35730 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 3 Jun 2010 11:33:51 +0200 Subject: i2c: Share the I2C device presence detection code Use the same I2C device presence detection code for legacy and new device detection functions. This is more consistent and makes the code smaller. Signed-off-by: Jean Delvare Cc: Matthieu Castet --- drivers/i2c/i2c-core.c | 80 +++++++++++++++++++++++++------------------------- 1 file changed, 40 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index e0f833cca3f1..f744f73e3ff5 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1277,6 +1277,41 @@ EXPORT_SYMBOL(i2c_master_recv); * ---------------------------------------------------- */ +/* + * Legacy default probe function, mostly relevant for SMBus. The default + * probe method is a quick write, but it is known to corrupt the 24RF08 + * EEPROMs due to a state machine bug, and could also irreversibly + * write-protect some EEPROMs, so for address ranges 0x30-0x37 and 0x50-0x5f, + * we use a short byte read instead. Also, some bus drivers don't implement + * quick write, so we fallback to a byte read in that case too. + * On x86, there is another special case for FSC hardware monitoring chips, + * which want regular byte reads (address 0x73.) Fortunately, these are the + * only known chips using this I2C address on PC hardware. + * Returns 1 if probe succeeded, 0 if not. + */ +static int i2c_default_probe(struct i2c_adapter *adap, unsigned short addr) +{ + int err; + union i2c_smbus_data dummy; + +#ifdef CONFIG_X86 + if (addr == 0x73 && (adap->class & I2C_CLASS_HWMON) + && i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_BYTE_DATA)) + err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_READ, 0, + I2C_SMBUS_BYTE_DATA, &dummy); + else +#endif + if ((addr & ~0x07) == 0x30 || (addr & ~0x0f) == 0x50 + || !i2c_check_functionality(adap, I2C_FUNC_SMBUS_QUICK)) + err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_READ, 0, + I2C_SMBUS_BYTE, &dummy); + else + err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_WRITE, 0, + I2C_SMBUS_QUICK, NULL); + + return err >= 0; +} + static int i2c_detect_address(struct i2c_client *temp_client, struct i2c_driver *driver) { @@ -1297,23 +1332,8 @@ static int i2c_detect_address(struct i2c_client *temp_client, return 0; /* Make sure there is something at this address */ - if (addr == 0x73 && (adapter->class & I2C_CLASS_HWMON)) { - /* Special probe for FSC hwmon chips */ - union i2c_smbus_data dummy; - - if (i2c_smbus_xfer(adapter, addr, 0, I2C_SMBUS_READ, 0, - I2C_SMBUS_BYTE_DATA, &dummy) < 0) - return 0; - } else { - if (i2c_smbus_xfer(adapter, addr, 0, I2C_SMBUS_WRITE, 0, - I2C_SMBUS_QUICK, NULL) < 0) - return 0; - - /* Prevent 24RF08 corruption */ - if ((addr & ~0x0f) == 0x50) - i2c_smbus_xfer(adapter, addr, 0, I2C_SMBUS_WRITE, 0, - I2C_SMBUS_QUICK, NULL); - } + if (!i2c_default_probe(adapter, addr)) + return 0; /* Finally call the custom detection function */ memset(&info, 0, sizeof(struct i2c_board_info)); @@ -1420,29 +1440,9 @@ i2c_new_probed_device(struct i2c_adapter *adap, continue; } - /* Test address responsiveness - The default probe method is a quick write, but it is known - to corrupt the 24RF08 EEPROMs due to a state machine bug, - and could also irreversibly write-protect some EEPROMs, so - for address ranges 0x30-0x37 and 0x50-0x5f, we use a byte - read instead. Also, some bus drivers don't implement - quick write, so we fallback to a byte read it that case - too. */ - if ((addr_list[i] & ~0x07) == 0x30 - || (addr_list[i] & ~0x0f) == 0x50 - || !i2c_check_functionality(adap, I2C_FUNC_SMBUS_QUICK)) { - union i2c_smbus_data data; - - if (i2c_smbus_xfer(adap, addr_list[i], 0, - I2C_SMBUS_READ, 0, - I2C_SMBUS_BYTE, &data) >= 0) - break; - } else { - if (i2c_smbus_xfer(adap, addr_list[i], 0, - I2C_SMBUS_WRITE, 0, - I2C_SMBUS_QUICK, NULL) >= 0) - break; - } + /* Test address responsiveness */ + if (i2c_default_probe(adap, addr_list[i])) + break; } if (addr_list[i] == I2C_CLIENT_END) { -- cgit v1.2.3 From 3a89db5f30576654bf1b0036af9b50ed5ab1b6c5 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 3 Jun 2010 11:33:52 +0200 Subject: i2c: Check for address validity on client registration Do basic address validity checks when a client is being registered. We already had checks in place for devices which are being detected, but not for devices which are simply instantiated. This is a very basic check. We don't want to do strict checking here because some devices are known to infringe the I2C address constraints (e.g. IR receivers at 7-bit address 0x7a while this value is supposedly reserved for 10-bit addresses.) So we assume the caller knows what it is doing. Signed-off-by: Jean Delvare Cc: Matthieu Castet --- drivers/i2c/i2c-core.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index f744f73e3ff5..96f01331544d 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -371,6 +371,22 @@ struct i2c_client *i2c_verify_client(struct device *dev) EXPORT_SYMBOL(i2c_verify_client); +/* This is a permissive address validity check, I2C address map constraints + * are purposedly not enforced, except for the general call address. */ +static int i2c_check_client_addr_validity(const struct i2c_client *client) +{ + if (client->flags & I2C_CLIENT_TEN) { + /* 10-bit address, all values are valid */ + if (client->addr > 0x3ff) + return -EINVAL; + } else { + /* 7-bit address, reject the general call address */ + if (client->addr == 0x00 || client->addr > 0x7f) + return -EINVAL; + } + return 0; +} + /** * i2c_new_device - instantiate an i2c device * @adap: the adapter managing the device @@ -410,6 +426,14 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) strlcpy(client->name, info->type, sizeof(client->name)); + /* Check for address validity */ + status = i2c_check_client_addr_validity(client); + if (status) { + dev_err(&adap->dev, "Invalid %d-bit I2C address 0x%02hx\n", + client->flags & I2C_CLIENT_TEN ? 10 : 7, client->addr); + goto out_err_silent; + } + /* Check for address business */ status = i2c_check_addr(adap, client->addr); if (status) @@ -436,6 +460,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) out_err: dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x " "(%d)\n", client->name, client->addr, status); +out_err_silent: kfree(client); return NULL; } @@ -561,15 +586,9 @@ i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr, return -EINVAL; } - if (info.addr < 0x03 || info.addr > 0x77) { - dev_err(dev, "%s: Invalid I2C address 0x%hx\n", "new_device", - info.addr); - return -EINVAL; - } - client = i2c_new_device(adap, &info); if (!client) - return -EEXIST; + return -EINVAL; /* Keep track of the added device */ i2c_lock_adapter(adap); -- cgit v1.2.3 From 656b8761ab21715eb1a35bb078dfd05e901be4ec Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 3 Jun 2010 11:33:53 +0200 Subject: i2c: Document reserved I2C addresses Move strict I2C address validity check to a single function, and document the reserved I2C addresses there. Signed-off-by: Jean Delvare Cc: Hans Verkuil --- drivers/i2c/i2c-core.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 96f01331544d..af5172486fab 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -387,6 +387,27 @@ static int i2c_check_client_addr_validity(const struct i2c_client *client) return 0; } +/* And this is a strict address validity check, used when probing. If a + * device uses a reserved address, then it shouldn't be probed. 7-bit + * addressing is assumed, 10-bit address devices are rare and should be + * explicitly enumerated. */ +static int i2c_check_addr_validity(unsigned short addr) +{ + /* + * Reserved addresses per I2C specification: + * 0x00 General call address / START byte + * 0x01 CBUS address + * 0x02 Reserved for different bus format + * 0x03 Reserved for future purposes + * 0x04-0x07 Hs-mode master code + * 0x78-0x7b 10-bit slave addressing + * 0x7c-0x7f Reserved for future purposes + */ + if (addr < 0x08 || addr > 0x77) + return -EINVAL; + return 0; +} + /** * i2c_new_device - instantiate an i2c device * @adap: the adapter managing the device @@ -1340,10 +1361,11 @@ static int i2c_detect_address(struct i2c_client *temp_client, int err; /* Make sure the address is valid */ - if (addr < 0x03 || addr > 0x77) { + err = i2c_check_addr_validity(addr); + if (err) { dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n", addr); - return -EINVAL; + return err; } /* Skip if already in use */ @@ -1446,7 +1468,7 @@ i2c_new_probed_device(struct i2c_adapter *adap, for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) { /* Check address validity */ - if (addr_list[i] < 0x03 || addr_list[i] > 0x77) { + if (i2c_check_addr_validity(addr_list[i]) < 0) { dev_warn(&adap->dev, "Invalid 7-bit address " "0x%02x\n", addr_list[i]); continue; -- cgit v1.2.3 From 3b5f794b8b647409155cade4eac2825bc49b4a66 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 3 Jun 2010 11:33:55 +0200 Subject: i2c: Rename i2c_check_addr to i2c_check_addr_busy Otherwise it's not clear what it is checking. Also move the function to save a forward declaration. Signed-off-by: Jean Delvare --- drivers/i2c/i2c-core.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index af5172486fab..1cca2631e5b3 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -47,7 +47,6 @@ static DEFINE_MUTEX(core_lock); static DEFINE_IDR(i2c_adapter_idr); static struct device_type i2c_client_type; -static int i2c_check_addr(struct i2c_adapter *adapter, int addr); static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver); /* ------------------------------------------------------------------------- */ @@ -408,6 +407,22 @@ static int i2c_check_addr_validity(unsigned short addr) return 0; } +static int __i2c_check_addr_busy(struct device *dev, void *addrp) +{ + struct i2c_client *client = i2c_verify_client(dev); + int addr = *(int *)addrp; + + if (client && client->addr == addr) + return -EBUSY; + return 0; +} + +static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr) +{ + return device_for_each_child(&adapter->dev, &addr, + __i2c_check_addr_busy); +} + /** * i2c_new_device - instantiate an i2c device * @adap: the adapter managing the device @@ -456,7 +471,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) } /* Check for address business */ - status = i2c_check_addr(adap, client->addr); + status = i2c_check_addr_busy(adap, client->addr); if (status) goto out_err; @@ -1064,21 +1079,6 @@ EXPORT_SYMBOL(i2c_del_driver); /* ------------------------------------------------------------------------- */ -static int __i2c_check_addr(struct device *dev, void *addrp) -{ - struct i2c_client *client = i2c_verify_client(dev); - int addr = *(int *)addrp; - - if (client && client->addr == addr) - return -EBUSY; - return 0; -} - -static int i2c_check_addr(struct i2c_adapter *adapter, int addr) -{ - return device_for_each_child(&adapter->dev, &addr, __i2c_check_addr); -} - /** * i2c_use_client - increments the reference count of the i2c client structure * @client: the client being referenced @@ -1369,7 +1369,7 @@ static int i2c_detect_address(struct i2c_client *temp_client, } /* Skip if already in use */ - if (i2c_check_addr(adapter, addr)) + if (i2c_check_addr_busy(adapter, addr)) return 0; /* Make sure there is something at this address */ @@ -1475,7 +1475,7 @@ i2c_new_probed_device(struct i2c_adapter *adap, } /* Check address availability */ - if (i2c_check_addr(adap, addr_list[i])) { + if (i2c_check_addr_busy(adap, addr_list[i])) { dev_dbg(&adap->dev, "Address 0x%02x already in " "use, not probing\n", addr_list[i]); continue; -- cgit v1.2.3 From 35bfc353dcaecc99c277e3646564f3f785760bde Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 3 Jun 2010 11:33:56 +0200 Subject: i2c/busses: Move two drivers to embedded section And fix a typo while we are here Signed-off-by: Wolfram Sang Signed-off-by: Jean Delvare --- drivers/i2c/busses/Kconfig | 40 ++++++++++++++++++++-------------------- drivers/i2c/busses/Makefile | 6 +++--- 2 files changed, 23 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 87ab0568bb0e..bceafbfa7268 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -475,6 +475,26 @@ config I2C_PASEMI help Supports the PA Semi PWRficient on-chip SMBus interfaces. +config I2C_PCA_PLATFORM + tristate "PCA9564/PCA9665 as platform device" + select I2C_ALGOPCA + default n + help + This driver supports a memory mapped Philips PCA9564/PCA9665 + parallel bus to I2C bus controller. + + This driver can also be built as a module. If so, the module + will be called i2c-pca-platform. + +config I2C_PMCMSP + tristate "PMC MSP I2C TWI Controller" + depends on PMC_MSP + help + This driver supports the PMC TWI controller on MSP devices. + + This driver can also be built as module. If so, the module + will be called i2c-pmcmsp. + config I2C_PNX tristate "I2C bus support for Philips PNX targets" depends on ARCH_PNX4008 @@ -711,26 +731,6 @@ config I2C_PCA_ISA delays when I2C/SMBus chip drivers are loaded (e.g. at boot time). If unsure, say N. -config I2C_PCA_PLATFORM - tristate "PCA9564/PCA9665 as platform device" - select I2C_ALGOPCA - default n - help - This driver supports a memory mapped Philips PCA9564/PCA9665 - parallel bus to I2C bus controller. - - This driver can also be built as a module. If so, the module - will be called i2c-pca-platform. - -config I2C_PMCMSP - tristate "PMC MSP I2C TWI Controller" - depends on PMC_MSP - help - This driver supports the PMC TWI controller on MSP devices. - - This driver can also be built as module. If so, the module - will be called i2c-pmcmsp. - config I2C_SIBYTE tristate "SiByte SMBus interface" depends on SIBYTE_SB1xxx_SOC diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 097236f631e8..936880bd1dc5 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -27,7 +27,7 @@ obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o -# Embebbed system I2C/SMBus host controller drivers +# Embedded system I2C/SMBus host controller drivers obj-$(CONFIG_I2C_AT91) += i2c-at91.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o @@ -46,6 +46,8 @@ obj-$(CONFIG_I2C_NOMADIK) += i2c-nomadik.o obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o obj-$(CONFIG_I2C_OMAP) += i2c-omap.o obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o +obj-$(CONFIG_I2C_PCA_PLATFORM) += i2c-pca-platform.o +obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o obj-$(CONFIG_I2C_PNX) += i2c-pnx.o obj-$(CONFIG_I2C_PXA) += i2c-pxa.o obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o @@ -68,8 +70,6 @@ obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o -obj-$(CONFIG_I2C_PCA_PLATFORM) += i2c-pca-platform.o -obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o obj-$(CONFIG_I2C_STUB) += i2c-stub.o obj-$(CONFIG_SCx200_ACB) += scx200_acb.o -- cgit v1.2.3 From fbae3fb1546e199ab0cd185348f8124411a1ca9d Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 3 Jun 2010 11:33:58 +0200 Subject: i2c: Remove all i2c_set_clientdata(client, NULL) in drivers I2C drivers can use the clientdata-pointer to point to private data. As I2C devices are not really unregistered, but merely detached from their driver, it used to be the drivers obligation to clear this pointer during remove() or a failed probe(). As a couple of drivers forgot to do this, it was agreed that it was cleaner if the i2c-core does this clearance when appropriate, as there is no guarantee for the lifetime of the clientdata-pointer after remove() anyhow. This feature was added to the core with commit e4a7b9b04de15f6b63da5ccdd373ffa3057a3681 to fix the faulty drivers. As there is no need anymore to clear the clientdata-pointer, remove all current occurrences in the drivers to simplify the code and prevent confusion. Signed-off-by: Wolfram Sang Acked-by: Mark Brown Acked-by: Greg Kroah-Hartman Acked-by: Richard Purdie Acked-by: Dmitry Torokhov Signed-off-by: Jean Delvare --- drivers/hwmon/adt7411.c | 2 -- drivers/hwmon/asc7621.c | 2 -- drivers/hwmon/f75375s.c | 2 -- drivers/hwmon/g760a.c | 2 -- drivers/hwmon/lm73.c | 1 - drivers/hwmon/lm75.c | 2 -- drivers/hwmon/lm95241.c | 1 - drivers/hwmon/tmp102.c | 2 -- drivers/hwmon/tmp421.c | 2 -- drivers/hwmon/w83781d.c | 2 -- drivers/i2c/i2c-smbus.c | 1 - drivers/input/keyboard/adp5588-keys.c | 1 - drivers/input/keyboard/lm8323.c | 2 -- drivers/input/keyboard/max7359_keypad.c | 1 - drivers/input/keyboard/qt2160.c | 1 - drivers/input/keyboard/tca6416-keypad.c | 2 -- drivers/input/misc/ad714x-i2c.c | 1 - drivers/input/misc/pcf8574_keypad.c | 2 -- drivers/input/mouse/synaptics_i2c.c | 1 - drivers/input/touchscreen/ad7879.c | 5 +---- drivers/input/touchscreen/eeti_ts.c | 2 -- drivers/input/touchscreen/mcs5000_ts.c | 1 - drivers/input/touchscreen/tsc2007.c | 2 -- drivers/leds/leds-bd2802.c | 2 -- drivers/leds/leds-lp3944.c | 1 - drivers/leds/leds-pca9532.c | 5 +---- drivers/leds/leds-pca955x.c | 2 -- drivers/macintosh/therm_adt746x.c | 2 -- drivers/macintosh/windfarm_lm75_sensor.c | 5 +---- drivers/macintosh/windfarm_max6690_sensor.c | 1 - drivers/macintosh/windfarm_smu_sat.c | 1 - drivers/media/radio/si470x/radio-si470x-i2c.c | 1 - drivers/media/video/mt9m001.c | 2 -- drivers/media/video/mt9m111.c | 2 -- drivers/media/video/mt9t031.c | 2 -- drivers/media/video/mt9t112.c | 2 -- drivers/media/video/mt9v022.c | 2 -- drivers/media/video/ov772x.c | 2 -- drivers/media/video/ov9640.c | 2 -- drivers/media/video/rj54n1cb0c.c | 2 -- drivers/media/video/tcm825x.c | 8 +------- drivers/media/video/tw9910.c | 2 -- drivers/mfd/88pm860x-i2c.c | 2 -- drivers/mfd/ab3100-core.c | 2 -- drivers/mfd/ab3550-core.c | 1 - drivers/mfd/adp5520.c | 2 -- drivers/mfd/da903x.c | 2 -- drivers/mfd/max8925-i2c.c | 1 - drivers/mfd/menelaus.c | 2 -- drivers/mfd/pcf50633-core.c | 2 -- drivers/mfd/tc35892.c | 2 -- drivers/mfd/tps65010.c | 1 - drivers/mfd/wm8350-i2c.c | 2 -- drivers/mfd/wm8400-core.c | 2 -- drivers/misc/eeprom/at24.c | 1 - drivers/mtd/maps/pismo.c | 2 -- drivers/power/max17040_battery.c | 2 -- drivers/regulator/lp3971.c | 2 -- drivers/regulator/max1586.c | 1 - drivers/regulator/max8649.c | 2 -- drivers/regulator/max8660.c | 1 - drivers/regulator/tps65023-regulator.c | 3 --- drivers/rtc/rtc-ds1374.c | 2 -- drivers/rtc/rtc-rx8025.c | 2 -- drivers/rtc/rtc-s35390a.c | 2 -- drivers/staging/dream/synaptics_i2c_rmi.c | 2 -- drivers/staging/go7007/wis-saa7113.c | 2 -- drivers/staging/go7007/wis-saa7115.c | 2 -- drivers/staging/go7007/wis-sony-tuner.c | 1 - drivers/staging/go7007/wis-tw2804.c | 1 - drivers/staging/go7007/wis-tw9903.c | 2 -- drivers/staging/iio/adc/max1363_core.c | 2 -- drivers/staging/iio/light/tsl2563.c | 2 -- drivers/video/backlight/adp8860_bl.c | 2 -- drivers/video/backlight/tosa_bl.c | 2 -- 75 files changed, 4 insertions(+), 141 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/adt7411.c b/drivers/hwmon/adt7411.c index 4086c7257f91..f13c843a2964 100644 --- a/drivers/hwmon/adt7411.c +++ b/drivers/hwmon/adt7411.c @@ -316,7 +316,6 @@ static int __devinit adt7411_probe(struct i2c_client *client, exit_remove: sysfs_remove_group(&client->dev.kobj, &adt7411_attr_grp); exit_free: - i2c_set_clientdata(client, NULL); kfree(data); return ret; } @@ -327,7 +326,6 @@ static int __devexit adt7411_remove(struct i2c_client *client) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &adt7411_attr_grp); - i2c_set_clientdata(client, NULL); kfree(data); return 0; } diff --git a/drivers/hwmon/asc7621.c b/drivers/hwmon/asc7621.c index 0f388adc6187..3b973f30b1f6 100644 --- a/drivers/hwmon/asc7621.c +++ b/drivers/hwmon/asc7621.c @@ -1141,7 +1141,6 @@ exit_remove: &(asc7621_params[i].sda.dev_attr)); } - i2c_set_clientdata(client, NULL); kfree(data); return err; } @@ -1196,7 +1195,6 @@ static int asc7621_remove(struct i2c_client *client) &(asc7621_params[i].sda.dev_attr)); } - i2c_set_clientdata(client, NULL); kfree(data); return 0; } diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c index bad2cf3ef4a4..0f58ecc5334d 100644 --- a/drivers/hwmon/f75375s.c +++ b/drivers/hwmon/f75375s.c @@ -662,7 +662,6 @@ exit_remove: sysfs_remove_group(&client->dev.kobj, &f75375_group); exit_free: kfree(data); - i2c_set_clientdata(client, NULL); return err; } @@ -672,7 +671,6 @@ static int f75375_remove(struct i2c_client *client) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &f75375_group); kfree(data); - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/hwmon/g760a.c b/drivers/hwmon/g760a.c index 09ea12e0a551..1f63d1a3af5e 100644 --- a/drivers/hwmon/g760a.c +++ b/drivers/hwmon/g760a.c @@ -236,7 +236,6 @@ error_hwmon_device_register: sysfs_remove_group(&client->dev.kobj, &g760a_group); error_sysfs_create_group: kfree(data); - i2c_set_clientdata(client, NULL); return err; } @@ -247,7 +246,6 @@ static int g760a_remove(struct i2c_client *client) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &g760a_group); kfree(data); - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/hwmon/lm73.c b/drivers/hwmon/lm73.c index 4d1b76bc8148..29b9030d42c3 100644 --- a/drivers/hwmon/lm73.c +++ b/drivers/hwmon/lm73.c @@ -136,7 +136,6 @@ static int lm73_remove(struct i2c_client *client) hwmon_device_unregister(hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm73_group); - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 56463428a419..393f354f92a4 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -192,7 +192,6 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) exit_remove: sysfs_remove_group(&client->dev.kobj, &lm75_group); exit_free: - i2c_set_clientdata(client, NULL); kfree(data); return status; } @@ -204,7 +203,6 @@ static int lm75_remove(struct i2c_client *client) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm75_group); lm75_write_value(client, LM75_REG_CONF, data->orig_conf); - i2c_set_clientdata(client, NULL); kfree(data); return 0; } diff --git a/drivers/hwmon/lm95241.c b/drivers/hwmon/lm95241.c index 8fc8eb8cba47..94741d42112d 100644 --- a/drivers/hwmon/lm95241.c +++ b/drivers/hwmon/lm95241.c @@ -399,7 +399,6 @@ static int lm95241_remove(struct i2c_client *client) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm95241_group); - i2c_set_clientdata(client, NULL); kfree(data); return 0; } diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c index 8013895a1faf..93187c3cb5e7 100644 --- a/drivers/hwmon/tmp102.c +++ b/drivers/hwmon/tmp102.c @@ -224,7 +224,6 @@ fail_remove_sysfs: fail_restore_config: tmp102_write_reg(client, TMP102_CONF_REG, tmp102->config_orig); fail_free: - i2c_set_clientdata(client, NULL); kfree(tmp102); return status; @@ -247,7 +246,6 @@ static int __devexit tmp102_remove(struct i2c_client *client) config | TMP102_CONF_SD); } - i2c_set_clientdata(client, NULL); kfree(tmp102); return 0; diff --git a/drivers/hwmon/tmp421.c b/drivers/hwmon/tmp421.c index 738c472ece27..6b4165c12092 100644 --- a/drivers/hwmon/tmp421.c +++ b/drivers/hwmon/tmp421.c @@ -295,7 +295,6 @@ exit_remove: sysfs_remove_group(&client->dev.kobj, &tmp421_group); exit_free: - i2c_set_clientdata(client, NULL); kfree(data); return err; @@ -308,7 +307,6 @@ static int tmp421_remove(struct i2c_client *client) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &tmp421_group); - i2c_set_clientdata(client, NULL); kfree(data); return 0; diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index 32d4adee73db..c84b9b4e6960 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -1197,7 +1197,6 @@ ERROR4: if (data->lm75[1]) i2c_unregister_device(data->lm75[1]); ERROR3: - i2c_set_clientdata(client, NULL); kfree(data); ERROR1: return err; @@ -1219,7 +1218,6 @@ w83781d_remove(struct i2c_client *client) if (data->lm75[1]) i2c_unregister_device(data->lm75[1]); - i2c_set_clientdata(client, NULL); kfree(data); return 0; diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c index a24e0bfe9201..f61ccc1e5ea3 100644 --- a/drivers/i2c/i2c-smbus.c +++ b/drivers/i2c/i2c-smbus.c @@ -173,7 +173,6 @@ static int smbalert_remove(struct i2c_client *ara) cancel_work_sync(&alert->alert); - i2c_set_clientdata(ara, NULL); kfree(alert); return 0; } diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c index 4771ab172b59..744600eff222 100644 --- a/drivers/input/keyboard/adp5588-keys.c +++ b/drivers/input/keyboard/adp5588-keys.c @@ -287,7 +287,6 @@ static int __devexit adp5588_remove(struct i2c_client *client) free_irq(client->irq, kpad); cancel_delayed_work_sync(&kpad->work); input_unregister_device(kpad->input); - i2c_set_clientdata(client, NULL); kfree(kpad); return 0; diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c index bc696931fed7..40b032f0e32c 100644 --- a/drivers/input/keyboard/lm8323.c +++ b/drivers/input/keyboard/lm8323.c @@ -778,8 +778,6 @@ static int __devexit lm8323_remove(struct i2c_client *client) struct lm8323_chip *lm = i2c_get_clientdata(client); int i; - i2c_set_clientdata(client, NULL); - disable_irq_wake(client->irq); free_irq(client->irq, lm); cancel_work_sync(&lm->work); diff --git a/drivers/input/keyboard/max7359_keypad.c b/drivers/input/keyboard/max7359_keypad.c index 7fc8185e5c1b..9091ff5ea808 100644 --- a/drivers/input/keyboard/max7359_keypad.c +++ b/drivers/input/keyboard/max7359_keypad.c @@ -265,7 +265,6 @@ static int __devexit max7359_remove(struct i2c_client *client) free_irq(client->irq, keypad); input_unregister_device(keypad->input_dev); - i2c_set_clientdata(client, NULL); kfree(keypad); return 0; diff --git a/drivers/input/keyboard/qt2160.c b/drivers/input/keyboard/qt2160.c index 31f30087b591..fac695157e8a 100644 --- a/drivers/input/keyboard/qt2160.c +++ b/drivers/input/keyboard/qt2160.c @@ -358,7 +358,6 @@ static int __devexit qt2160_remove(struct i2c_client *client) input_unregister_device(qt2160->input); kfree(qt2160); - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/input/keyboard/tca6416-keypad.c b/drivers/input/keyboard/tca6416-keypad.c index 493c93f25e2a..00137bebcf97 100644 --- a/drivers/input/keyboard/tca6416-keypad.c +++ b/drivers/input/keyboard/tca6416-keypad.c @@ -316,8 +316,6 @@ static int __devexit tca6416_keypad_remove(struct i2c_client *client) input_unregister_device(chip->input); kfree(chip); - i2c_set_clientdata(client, NULL); - return 0; } diff --git a/drivers/input/misc/ad714x-i2c.c b/drivers/input/misc/ad714x-i2c.c index e9adbe49f6a4..2bef8fa56c94 100644 --- a/drivers/input/misc/ad714x-i2c.c +++ b/drivers/input/misc/ad714x-i2c.c @@ -97,7 +97,6 @@ static int __devexit ad714x_i2c_remove(struct i2c_client *client) struct ad714x_chip *chip = i2c_get_clientdata(client); ad714x_remove(chip); - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/input/misc/pcf8574_keypad.c b/drivers/input/misc/pcf8574_keypad.c index 5c3ac4e0b055..0ac47d2898ec 100644 --- a/drivers/input/misc/pcf8574_keypad.c +++ b/drivers/input/misc/pcf8574_keypad.c @@ -168,8 +168,6 @@ static int __devexit pcf8574_kp_remove(struct i2c_client *client) input_unregister_device(lp->idev); kfree(lp); - i2c_set_clientdata(client, NULL); - return 0; } diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c index 8291e7399ffa..0ae62f0bcb32 100644 --- a/drivers/input/mouse/synaptics_i2c.c +++ b/drivers/input/mouse/synaptics_i2c.c @@ -613,7 +613,6 @@ static int __devexit synaptics_i2c_remove(struct i2c_client *client) free_irq(client->irq, touch); input_unregister_device(touch->input); - i2c_set_clientdata(client, NULL); kfree(touch); return 0; diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c index 794d070c6900..4b32fb4704cd 100644 --- a/drivers/input/touchscreen/ad7879.c +++ b/drivers/input/touchscreen/ad7879.c @@ -812,10 +812,8 @@ static int __devinit ad7879_probe(struct i2c_client *client, ts->bus = client; error = ad7879_construct(client, ts); - if (error) { - i2c_set_clientdata(client, NULL); + if (error) kfree(ts); - } return error; } @@ -825,7 +823,6 @@ static int __devexit ad7879_remove(struct i2c_client *client) struct ad7879 *ts = dev_get_drvdata(&client->dev); ad7879_destroy(client, ts); - i2c_set_clientdata(client, NULL); kfree(ts); return 0; diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index 75f8b73010fa..7a3a916f84a8 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -238,7 +238,6 @@ err2: input = NULL; /* so we dont try to free it below */ err1: input_free_device(input); - i2c_set_clientdata(client, NULL); kfree(priv); err0: return err; @@ -256,7 +255,6 @@ static int __devexit eeti_ts_remove(struct i2c_client *client) enable_irq(priv->irq); input_unregister_device(priv->input); - i2c_set_clientdata(client, NULL); kfree(priv); return 0; diff --git a/drivers/input/touchscreen/mcs5000_ts.c b/drivers/input/touchscreen/mcs5000_ts.c index ce8ab0269f6f..1fb0c2f06a44 100644 --- a/drivers/input/touchscreen/mcs5000_ts.c +++ b/drivers/input/touchscreen/mcs5000_ts.c @@ -256,7 +256,6 @@ static int __devexit mcs5000_ts_remove(struct i2c_client *client) free_irq(client->irq, data); input_unregister_device(data->input_dev); kfree(data); - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index 769b479fcaa6..be23780e8a3e 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -347,8 +347,6 @@ static int __devexit tsc2007_remove(struct i2c_client *client) struct tsc2007 *ts = i2c_get_clientdata(client); struct tsc2007_platform_data *pdata = client->dev.platform_data; - i2c_set_clientdata(client, NULL); - tsc2007_free_irq(ts); if (pdata->exit_platform_hw) diff --git a/drivers/leds/leds-bd2802.c b/drivers/leds/leds-bd2802.c index 286b501a3573..5dcdf9d69b3a 100644 --- a/drivers/leds/leds-bd2802.c +++ b/drivers/leds/leds-bd2802.c @@ -742,7 +742,6 @@ failed_unregister_dev_file: for (i--; i >= 0; i--) device_remove_file(&led->client->dev, bd2802_attributes[i]); failed_free: - i2c_set_clientdata(client, NULL); kfree(led); return ret; @@ -759,7 +758,6 @@ static int __exit bd2802_remove(struct i2c_client *client) bd2802_disable_adv_conf(led); for (i = 0; i < ARRAY_SIZE(bd2802_attributes); i++) device_remove_file(&led->client->dev, bd2802_attributes[i]); - i2c_set_clientdata(client, NULL); kfree(led); return 0; diff --git a/drivers/leds/leds-lp3944.c b/drivers/leds/leds-lp3944.c index 932a58da76c4..9010c054615e 100644 --- a/drivers/leds/leds-lp3944.c +++ b/drivers/leds/leds-lp3944.c @@ -432,7 +432,6 @@ static int __devexit lp3944_remove(struct i2c_client *client) } kfree(data); - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c index 6682175fa9f7..43d08756d823 100644 --- a/drivers/leds/leds-pca9532.c +++ b/drivers/leds/leds-pca9532.c @@ -320,10 +320,8 @@ static int pca9532_probe(struct i2c_client *client, mutex_init(&data->update_lock); err = pca9532_configure(client, data, pca9532_pdata); - if (err) { + if (err) kfree(data); - i2c_set_clientdata(client, NULL); - } return err; } @@ -351,7 +349,6 @@ static int pca9532_remove(struct i2c_client *client) } kfree(data); - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c index 8ff50f234190..66aa3e8e786f 100644 --- a/drivers/leds/leds-pca955x.c +++ b/drivers/leds/leds-pca955x.c @@ -342,7 +342,6 @@ exit: } kfree(pca955x); - i2c_set_clientdata(client, NULL); return err; } @@ -358,7 +357,6 @@ static int __devexit pca955x_remove(struct i2c_client *client) } kfree(pca955x); - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index 16d82f17ae82..c42eeb43042d 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c @@ -182,7 +182,6 @@ remove_thermostat(struct i2c_client *client) thermostat = NULL; - i2c_set_clientdata(client, NULL); kfree(th); return 0; @@ -400,7 +399,6 @@ static int probe_thermostat(struct i2c_client *client, rc = read_reg(th, CONFIG_REG); if (rc < 0) { dev_err(&client->dev, "Thermostat failed to read config!\n"); - i2c_set_clientdata(client, NULL); kfree(th); return -ENODEV; } diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c index d8257d35afde..647c6add2193 100644 --- a/drivers/macintosh/windfarm_lm75_sensor.c +++ b/drivers/macintosh/windfarm_lm75_sensor.c @@ -107,10 +107,8 @@ static int wf_lm75_probe(struct i2c_client *client, i2c_set_clientdata(client, lm); rc = wf_register_sensor(&lm->sens); - if (rc) { - i2c_set_clientdata(client, NULL); + if (rc) kfree(lm); - } return rc; } @@ -216,7 +214,6 @@ static int wf_lm75_remove(struct i2c_client *client) /* release sensor */ wf_unregister_sensor(&lm->sens); - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/macintosh/windfarm_max6690_sensor.c b/drivers/macintosh/windfarm_max6690_sensor.c index b486eb929fde..8204113268f4 100644 --- a/drivers/macintosh/windfarm_max6690_sensor.c +++ b/drivers/macintosh/windfarm_max6690_sensor.c @@ -81,7 +81,6 @@ static int wf_max6690_probe(struct i2c_client *client, rc = wf_register_sensor(&max->sens); if (rc) { - i2c_set_clientdata(client, NULL); kfree(max); } diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c index e20330a28959..65a8ff3e1f8e 100644 --- a/drivers/macintosh/windfarm_smu_sat.c +++ b/drivers/macintosh/windfarm_smu_sat.c @@ -376,7 +376,6 @@ static int wf_sat_remove(struct i2c_client *client) /* XXX TODO */ sat->i2c = NULL; - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index a5844d08d8b7..67a4ec8768a6 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -482,7 +482,6 @@ static __devexit int si470x_i2c_remove(struct i2c_client *client) cancel_work_sync(&radio->radio_work); video_unregister_device(radio->videodev); kfree(radio); - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index b62c0bd3f8ea..e3b9a8ab37f4 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c @@ -785,7 +785,6 @@ static int mt9m001_probe(struct i2c_client *client, ret = mt9m001_video_probe(icd, client); if (ret) { icd->ops = NULL; - i2c_set_clientdata(client, NULL); kfree(mt9m001); } @@ -799,7 +798,6 @@ static int mt9m001_remove(struct i2c_client *client) icd->ops = NULL; mt9m001_video_remove(icd); - i2c_set_clientdata(client, NULL); client->driver = NULL; kfree(mt9m001); diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index d35f536f9fc3..e42162c50f0a 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c @@ -1068,7 +1068,6 @@ static int mt9m111_probe(struct i2c_client *client, ret = mt9m111_video_probe(icd, client); if (ret) { icd->ops = NULL; - i2c_set_clientdata(client, NULL); kfree(mt9m111); } @@ -1081,7 +1080,6 @@ static int mt9m111_remove(struct i2c_client *client) struct soc_camera_device *icd = client->dev.platform_data; icd->ops = NULL; - i2c_set_clientdata(client, NULL); client->driver = NULL; kfree(mt9m111); diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c index 78b4e091d2d5..9f5ff2547f19 100644 --- a/drivers/media/video/mt9t031.c +++ b/drivers/media/video/mt9t031.c @@ -883,7 +883,6 @@ static int mt9t031_probe(struct i2c_client *client, if (ret) { if (icd) icd->ops = NULL; - i2c_set_clientdata(client, NULL); kfree(mt9t031); } @@ -897,7 +896,6 @@ static int mt9t031_remove(struct i2c_client *client) if (icd) icd->ops = NULL; - i2c_set_clientdata(client, NULL); client->driver = NULL; kfree(mt9t031); diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c index 7438f8d775ba..aa4fce95098f 100644 --- a/drivers/media/video/mt9t112.c +++ b/drivers/media/video/mt9t112.c @@ -1119,7 +1119,6 @@ static int mt9t112_probe(struct i2c_client *client, ret = mt9t112_camera_probe(icd, client); if (ret) { icd->ops = NULL; - i2c_set_clientdata(client, NULL); kfree(priv); } @@ -1132,7 +1131,6 @@ static int mt9t112_remove(struct i2c_client *client) struct soc_camera_device *icd = client->dev.platform_data; icd->ops = NULL; - i2c_set_clientdata(client, NULL); kfree(priv); return 0; } diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index e5bae4c9393b..fb44ff006628 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c @@ -920,7 +920,6 @@ static int mt9v022_probe(struct i2c_client *client, ret = mt9v022_video_probe(icd, client); if (ret) { icd->ops = NULL; - i2c_set_clientdata(client, NULL); kfree(mt9v022); } @@ -934,7 +933,6 @@ static int mt9v022_remove(struct i2c_client *client) icd->ops = NULL; mt9v022_video_remove(icd); - i2c_set_clientdata(client, NULL); client->driver = NULL; kfree(mt9v022); diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c index 7f8ece30c77b..c33acc94b747 100644 --- a/drivers/media/video/ov772x.c +++ b/drivers/media/video/ov772x.c @@ -1159,7 +1159,6 @@ static int ov772x_probe(struct i2c_client *client, ret = ov772x_video_probe(icd, client); if (ret) { icd->ops = NULL; - i2c_set_clientdata(client, NULL); kfree(priv); } @@ -1172,7 +1171,6 @@ static int ov772x_remove(struct i2c_client *client) struct soc_camera_device *icd = client->dev.platform_data; icd->ops = NULL; - i2c_set_clientdata(client, NULL); kfree(priv); return 0; } diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c index 36599a65f548..035e9ecb0c75 100644 --- a/drivers/media/video/ov9640.c +++ b/drivers/media/video/ov9640.c @@ -783,7 +783,6 @@ static int ov9640_probe(struct i2c_client *client, if (ret) { icd->ops = NULL; - i2c_set_clientdata(client, NULL); kfree(priv); } @@ -794,7 +793,6 @@ static int ov9640_remove(struct i2c_client *client) { struct ov9640_priv *priv = i2c_get_clientdata(client); - i2c_set_clientdata(client, NULL); kfree(priv); return 0; } diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c index bbd9c11e2c5a..2c3b58c99e18 100644 --- a/drivers/media/video/rj54n1cb0c.c +++ b/drivers/media/video/rj54n1cb0c.c @@ -1444,7 +1444,6 @@ static int rj54n1_probe(struct i2c_client *client, ret = rj54n1_video_probe(icd, client, rj54n1_priv); if (ret < 0) { icd->ops = NULL; - i2c_set_clientdata(client, NULL); kfree(rj54n1); return ret; } @@ -1461,7 +1460,6 @@ static int rj54n1_remove(struct i2c_client *client) icd->ops = NULL; if (icl->free_bus) icl->free_bus(icl); - i2c_set_clientdata(client, NULL); client->driver = NULL; kfree(rj54n1); diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c index b90e9da3167d..54681a535822 100644 --- a/drivers/media/video/tcm825x.c +++ b/drivers/media/video/tcm825x.c @@ -850,7 +850,6 @@ static int tcm825x_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct tcm825x_sensor *sensor = &tcm825x; - int rval; if (i2c_get_clientdata(client)) return -EBUSY; @@ -871,11 +870,7 @@ static int tcm825x_probe(struct i2c_client *client, sensor->pix.height = tcm825x_sizes[QVGA].height; sensor->pix.pixelformat = V4L2_PIX_FMT_RGB565; - rval = v4l2_int_device_register(sensor->v4l2_int_device); - if (rval) - i2c_set_clientdata(client, NULL); - - return rval; + return v4l2_int_device_register(sensor->v4l2_int_device); } static int tcm825x_remove(struct i2c_client *client) @@ -886,7 +881,6 @@ static int tcm825x_remove(struct i2c_client *client) return -ENODEV; /* our client isn't attached */ v4l2_int_device_unregister(sensor->v4l2_int_device); - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c index 76be733eabfd..6eb3395def07 100644 --- a/drivers/media/video/tw9910.c +++ b/drivers/media/video/tw9910.c @@ -977,7 +977,6 @@ static int tw9910_probe(struct i2c_client *client, ret = tw9910_video_probe(icd, client); if (ret) { icd->ops = NULL; - i2c_set_clientdata(client, NULL); kfree(priv); } @@ -990,7 +989,6 @@ static int tw9910_remove(struct i2c_client *client) struct soc_camera_device *icd = client->dev.platform_data; icd->ops = NULL; - i2c_set_clientdata(client, NULL); kfree(priv); return 0; } diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c index c933b64d1283..bc02e6b21608 100644 --- a/drivers/mfd/88pm860x-i2c.c +++ b/drivers/mfd/88pm860x-i2c.c @@ -200,8 +200,6 @@ static int __devexit pm860x_remove(struct i2c_client *client) pm860x_device_exit(chip); i2c_unregister_device(chip->companion); - i2c_set_clientdata(chip->client, NULL); - i2c_set_clientdata(client, NULL); kfree(chip); return 0; } diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index 53ebfee548fa..66379b413906 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c @@ -957,7 +957,6 @@ static int __init ab3100_probe(struct i2c_client *client, i2c_unregister_device(ab3100->testreg_client); exit_no_testreg_client: exit_no_detect: - i2c_set_clientdata(client, NULL); kfree(ab3100); return err; } @@ -979,7 +978,6 @@ static int __exit ab3100_remove(struct i2c_client *client) * their notifiers so deactivate IRQ */ free_irq(client->irq, ab3100); - i2c_set_clientdata(client, NULL); kfree(ab3100); return 0; } diff --git a/drivers/mfd/ab3550-core.c b/drivers/mfd/ab3550-core.c index 1060f8e1c40a..f54ab62e7bc6 100644 --- a/drivers/mfd/ab3550-core.c +++ b/drivers/mfd/ab3550-core.c @@ -1362,7 +1362,6 @@ static int __exit ab3550_remove(struct i2c_client *client) * their notifiers so deactivate IRQ */ free_irq(client->irq, ab); - i2c_set_clientdata(client, NULL); kfree(ab); return 0; } diff --git a/drivers/mfd/adp5520.c b/drivers/mfd/adp5520.c index 005532865654..3122139b4300 100644 --- a/drivers/mfd/adp5520.c +++ b/drivers/mfd/adp5520.c @@ -302,7 +302,6 @@ out_free_irq: free_irq(chip->irq, chip); out_free_chip: - i2c_set_clientdata(client, NULL); kfree(chip); return ret; @@ -317,7 +316,6 @@ static int __devexit adp5520_remove(struct i2c_client *client) adp5520_remove_subdevs(chip); adp5520_write(chip->dev, ADP5520_MODE_STATUS, 0); - i2c_set_clientdata(client, NULL); kfree(chip); return 0; } diff --git a/drivers/mfd/da903x.c b/drivers/mfd/da903x.c index 3ad915d0589c..c07aece900fb 100644 --- a/drivers/mfd/da903x.c +++ b/drivers/mfd/da903x.c @@ -534,7 +534,6 @@ static int __devinit da903x_probe(struct i2c_client *client, out_free_irq: free_irq(client->irq, chip); out_free_chip: - i2c_set_clientdata(client, NULL); kfree(chip); return ret; } @@ -544,7 +543,6 @@ static int __devexit da903x_remove(struct i2c_client *client) struct da903x_chip *chip = i2c_get_clientdata(client); da903x_remove_subdevs(chip); - i2c_set_clientdata(client, NULL); kfree(chip); return 0; } diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c index e73f3f5252a8..0219115e00c7 100644 --- a/drivers/mfd/max8925-i2c.c +++ b/drivers/mfd/max8925-i2c.c @@ -173,7 +173,6 @@ static int __devexit max8925_remove(struct i2c_client *client) max8925_device_exit(chip); i2c_unregister_device(chip->adc); i2c_unregister_device(chip->rtc); - i2c_set_clientdata(chip->i2c, NULL); kfree(chip); return 0; } diff --git a/drivers/mfd/menelaus.c b/drivers/mfd/menelaus.c index 721948be12c7..a3fb4bcb9889 100644 --- a/drivers/mfd/menelaus.c +++ b/drivers/mfd/menelaus.c @@ -1228,7 +1228,6 @@ fail2: free_irq(client->irq, menelaus); flush_scheduled_work(); fail1: - i2c_set_clientdata(client, NULL); kfree(menelaus); return err; } @@ -1238,7 +1237,6 @@ static int __exit menelaus_remove(struct i2c_client *client) struct menelaus_chip *menelaus = i2c_get_clientdata(client); free_irq(client->irq, menelaus); - i2c_set_clientdata(client, NULL); kfree(menelaus); the_menelaus = NULL; return 0; diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c index 704736e6e9b9..23e585527285 100644 --- a/drivers/mfd/pcf50633-core.c +++ b/drivers/mfd/pcf50633-core.c @@ -336,7 +336,6 @@ static int __devinit pcf50633_probe(struct i2c_client *client, return 0; err_free: - i2c_set_clientdata(client, NULL); kfree(pcf); return ret; @@ -357,7 +356,6 @@ static int __devexit pcf50633_remove(struct i2c_client *client) for (i = 0; i < PCF50633_NUM_REGULATORS; i++) platform_device_unregister(pcf->regulator_pdev[i]); - i2c_set_clientdata(client, NULL); kfree(pcf); return 0; diff --git a/drivers/mfd/tc35892.c b/drivers/mfd/tc35892.c index 715f095dd7a6..e619e2a55997 100644 --- a/drivers/mfd/tc35892.c +++ b/drivers/mfd/tc35892.c @@ -296,7 +296,6 @@ out_freeirq: out_removeirq: tc35892_irq_remove(tc35892); out_free: - i2c_set_clientdata(i2c, NULL); kfree(tc35892); return ret; } @@ -310,7 +309,6 @@ static int __devexit tc35892_remove(struct i2c_client *client) free_irq(tc35892->i2c->irq, tc35892); tc35892_irq_remove(tc35892); - i2c_set_clientdata(client, NULL); kfree(tc35892); return 0; diff --git a/drivers/mfd/tps65010.c b/drivers/mfd/tps65010.c index 9b22a77f70f5..d0016b67d125 100644 --- a/drivers/mfd/tps65010.c +++ b/drivers/mfd/tps65010.c @@ -530,7 +530,6 @@ static int __exit tps65010_remove(struct i2c_client *client) cancel_delayed_work(&tps->work); flush_scheduled_work(); debugfs_remove(tps->file); - i2c_set_clientdata(client, NULL); kfree(tps); the_tps = NULL; return 0; diff --git a/drivers/mfd/wm8350-i2c.c b/drivers/mfd/wm8350-i2c.c index 7795af4b1fe1..5fe5de166adb 100644 --- a/drivers/mfd/wm8350-i2c.c +++ b/drivers/mfd/wm8350-i2c.c @@ -80,7 +80,6 @@ static int wm8350_i2c_probe(struct i2c_client *i2c, return ret; err: - i2c_set_clientdata(i2c, NULL); kfree(wm8350); return ret; } @@ -90,7 +89,6 @@ static int wm8350_i2c_remove(struct i2c_client *i2c) struct wm8350 *wm8350 = i2c_get_clientdata(i2c); wm8350_device_exit(wm8350); - i2c_set_clientdata(i2c, NULL); kfree(wm8350); return 0; diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c index e08aafa663dc..1bfef4846b07 100644 --- a/drivers/mfd/wm8400-core.c +++ b/drivers/mfd/wm8400-core.c @@ -415,7 +415,6 @@ static int wm8400_i2c_probe(struct i2c_client *i2c, return 0; struct_err: - i2c_set_clientdata(i2c, NULL); kfree(wm8400); err: return ret; @@ -426,7 +425,6 @@ static int wm8400_i2c_remove(struct i2c_client *i2c) struct wm8400 *wm8400 = i2c_get_clientdata(i2c); wm8400_release(wm8400); - i2c_set_clientdata(i2c, NULL); kfree(wm8400); return 0; diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index f7ca3a42b490..559b0b3c16c3 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -643,7 +643,6 @@ static int __devexit at24_remove(struct i2c_client *client) kfree(at24->writebuf); kfree(at24); - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/mtd/maps/pismo.c b/drivers/mtd/maps/pismo.c index eb476b7f8d11..f4ce273e93fd 100644 --- a/drivers/mtd/maps/pismo.c +++ b/drivers/mtd/maps/pismo.c @@ -234,7 +234,6 @@ static int __devexit pismo_remove(struct i2c_client *client) /* FIXME: set_vpp needs saner arguments */ pismo_setvpp_remove_fix(pismo); - i2c_set_clientdata(client, NULL); kfree(pismo); return 0; @@ -286,7 +285,6 @@ static int __devinit pismo_probe(struct i2c_client *client, return 0; exit_free: - i2c_set_clientdata(client, NULL); kfree(pismo); return ret; } diff --git a/drivers/power/max17040_battery.c b/drivers/power/max17040_battery.c index f3e22c9fe20a..2f2f9a6f54fa 100644 --- a/drivers/power/max17040_battery.c +++ b/drivers/power/max17040_battery.c @@ -225,7 +225,6 @@ static int __devinit max17040_probe(struct i2c_client *client, ret = power_supply_register(&client->dev, &chip->battery); if (ret) { dev_err(&client->dev, "failed: power supply register\n"); - i2c_set_clientdata(client, NULL); kfree(chip); return ret; } @@ -245,7 +244,6 @@ static int __devexit max17040_remove(struct i2c_client *client) power_supply_unregister(&chip->battery); cancel_delayed_work(&chip->work); - i2c_set_clientdata(client, NULL); kfree(chip); return 0; } diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index 671a7d1f1f0e..8ae3732eb24b 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -519,8 +519,6 @@ static int __devexit lp3971_i2c_remove(struct i2c_client *i2c) struct lp3971 *lp3971 = i2c_get_clientdata(i2c); int i; - i2c_set_clientdata(i2c, NULL); - for (i = 0; i < lp3971->num_regulators; i++) regulator_unregister(lp3971->rdev[i]); diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c index b3c1afc16889..2b54d9d75f11 100644 --- a/drivers/regulator/max1586.c +++ b/drivers/regulator/max1586.c @@ -244,7 +244,6 @@ static int __devexit max1586_pmic_remove(struct i2c_client *client) for (i = 0; i <= MAX1586_V6; i++) if (rdev[i]) regulator_unregister(rdev[i]); - i2c_set_clientdata(client, NULL); kfree(rdev); return 0; diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c index bfc4c5ffdc96..4520ace3f7e7 100644 --- a/drivers/regulator/max8649.c +++ b/drivers/regulator/max8649.c @@ -357,7 +357,6 @@ static int __devinit max8649_regulator_probe(struct i2c_client *client, dev_info(info->dev, "Max8649 regulator device is detected.\n"); return 0; out: - i2c_set_clientdata(client, NULL); kfree(info); return ret; } @@ -369,7 +368,6 @@ static int __devexit max8649_regulator_remove(struct i2c_client *client) if (info) { if (info->regulator) regulator_unregister(info->regulator); - i2c_set_clientdata(client, NULL); kfree(info); } diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c index 3790b21879ff..d97220efae5a 100644 --- a/drivers/regulator/max8660.c +++ b/drivers/regulator/max8660.c @@ -471,7 +471,6 @@ static int __devexit max8660_remove(struct i2c_client *client) for (i = 0; i < MAX8660_V_END; i++) if (rdev[i]) regulator_unregister(rdev[i]); - i2c_set_clientdata(client, NULL); kfree(rdev); return 0; diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c index 8e2f2098b005..f50afc9f287a 100644 --- a/drivers/regulator/tps65023-regulator.c +++ b/drivers/regulator/tps65023-regulator.c @@ -538,9 +538,6 @@ static int __devexit tps_65023_remove(struct i2c_client *client) struct tps_pmic *tps = i2c_get_clientdata(client); int i; - /* clear the client data in i2c */ - i2c_set_clientdata(client, NULL); - for (i = 0; i < TPS65023_NUM_REGULATOR; i++) regulator_unregister(tps->rdev[i]); diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index 61945734ad00..1f0007fd4431 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -403,7 +403,6 @@ out_irq: free_irq(client->irq, client); out_free: - i2c_set_clientdata(client, NULL); kfree(ds1374); return ret; } @@ -422,7 +421,6 @@ static int __devexit ds1374_remove(struct i2c_client *client) } rtc_device_unregister(ds1374->rtc); - i2c_set_clientdata(client, NULL); kfree(ds1374); return 0; } diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index b65c82f792d9..789f62f9b47d 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -632,7 +632,6 @@ errout_reg: rtc_device_unregister(rx8025->rtc); errout_free: - i2c_set_clientdata(client, NULL); kfree(rx8025); errout: @@ -656,7 +655,6 @@ static int __devexit rx8025_remove(struct i2c_client *client) rx8025_sysfs_unregister(&client->dev); rtc_device_unregister(rx8025->rtc); - i2c_set_clientdata(client, NULL); kfree(rx8025); return 0; } diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c index def4d396d0b0..f789e002c9b0 100644 --- a/drivers/rtc/rtc-s35390a.c +++ b/drivers/rtc/rtc-s35390a.c @@ -275,7 +275,6 @@ exit_dummy: if (s35390a->client[i]) i2c_unregister_device(s35390a->client[i]); kfree(s35390a); - i2c_set_clientdata(client, NULL); exit: return err; @@ -292,7 +291,6 @@ static int s35390a_remove(struct i2c_client *client) rtc_device_unregister(s35390a->rtc); kfree(s35390a); - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/staging/dream/synaptics_i2c_rmi.c b/drivers/staging/dream/synaptics_i2c_rmi.c index 1f020dad6234..3320359408a9 100644 --- a/drivers/staging/dream/synaptics_i2c_rmi.c +++ b/drivers/staging/dream/synaptics_i2c_rmi.c @@ -519,7 +519,6 @@ err_input_register_device_failed: err_input_dev_alloc_failed: err_detect_failed: err_power_failed: - i2c_set_clientdata(client, NULL); kfree(ts); err_alloc_data_failed: err_check_functionality_failed: @@ -537,7 +536,6 @@ static int synaptics_ts_remove(struct i2c_client *client) else hrtimer_cancel(&ts->timer); input_unregister_device(ts->input_dev); - i2c_set_clientdata(client, NULL); kfree(ts); return 0; } diff --git a/drivers/staging/go7007/wis-saa7113.c b/drivers/staging/go7007/wis-saa7113.c index bd925457f8b7..72f5c1f56d19 100644 --- a/drivers/staging/go7007/wis-saa7113.c +++ b/drivers/staging/go7007/wis-saa7113.c @@ -289,7 +289,6 @@ static int wis_saa7113_probe(struct i2c_client *client, if (write_regs(client, initial_registers) < 0) { printk(KERN_ERR "wis-saa7113: error initializing SAA7113\n"); - i2c_set_clientdata(client, NULL); kfree(dec); return -ENODEV; } @@ -301,7 +300,6 @@ static int wis_saa7113_remove(struct i2c_client *client) { struct wis_saa7113 *dec = i2c_get_clientdata(client); - i2c_set_clientdata(client, NULL); kfree(dec); return 0; } diff --git a/drivers/staging/go7007/wis-saa7115.c b/drivers/staging/go7007/wis-saa7115.c index b2eb804c1954..cd950b61cf70 100644 --- a/drivers/staging/go7007/wis-saa7115.c +++ b/drivers/staging/go7007/wis-saa7115.c @@ -422,7 +422,6 @@ static int wis_saa7115_probe(struct i2c_client *client, if (write_regs(client, initial_registers) < 0) { printk(KERN_ERR "wis-saa7115: error initializing SAA7115\n"); - i2c_set_clientdata(client, NULL); kfree(dec); return -ENODEV; } @@ -434,7 +433,6 @@ static int wis_saa7115_remove(struct i2c_client *client) { struct wis_saa7115 *dec = i2c_get_clientdata(client); - i2c_set_clientdata(client, NULL); kfree(dec); return 0; } diff --git a/drivers/staging/go7007/wis-sony-tuner.c b/drivers/staging/go7007/wis-sony-tuner.c index b1013291190f..981c9b311b8b 100644 --- a/drivers/staging/go7007/wis-sony-tuner.c +++ b/drivers/staging/go7007/wis-sony-tuner.c @@ -684,7 +684,6 @@ static int wis_sony_tuner_remove(struct i2c_client *client) { struct wis_sony_tuner *t = i2c_get_clientdata(client); - i2c_set_clientdata(client, NULL); kfree(t); return 0; } diff --git a/drivers/staging/go7007/wis-tw2804.c b/drivers/staging/go7007/wis-tw2804.c index 315268d130dd..ee28a99dc388 100644 --- a/drivers/staging/go7007/wis-tw2804.c +++ b/drivers/staging/go7007/wis-tw2804.c @@ -323,7 +323,6 @@ static int wis_tw2804_remove(struct i2c_client *client) { struct wis_tw2804 *dec = i2c_get_clientdata(client); - i2c_set_clientdata(client, NULL); kfree(dec); return 0; } diff --git a/drivers/staging/go7007/wis-tw9903.c b/drivers/staging/go7007/wis-tw9903.c index 2afea09091b9..80d47269b1c0 100644 --- a/drivers/staging/go7007/wis-tw9903.c +++ b/drivers/staging/go7007/wis-tw9903.c @@ -294,7 +294,6 @@ static int wis_tw9903_probe(struct i2c_client *client, if (write_regs(client, initial_registers) < 0) { printk(KERN_ERR "wis-tw9903: error initializing TW9903\n"); - i2c_set_clientdata(client, NULL); kfree(dec); return -ENODEV; } @@ -306,7 +305,6 @@ static int wis_tw9903_remove(struct i2c_client *client) { struct wis_tw9903 *dec = i2c_get_clientdata(client); - i2c_set_clientdata(client, NULL); kfree(dec); return 0; } diff --git a/drivers/staging/iio/adc/max1363_core.c b/drivers/staging/iio/adc/max1363_core.c index 20e267448d1f..905f8560d31f 100644 --- a/drivers/staging/iio/adc/max1363_core.c +++ b/drivers/staging/iio/adc/max1363_core.c @@ -1011,7 +1011,6 @@ error_put_reg: if (!IS_ERR(st->reg)) regulator_put(st->reg); error_free_st: - i2c_set_clientdata(client, NULL); kfree(st); error_ret: @@ -1030,7 +1029,6 @@ static int max1363_remove(struct i2c_client *client) regulator_disable(st->reg); regulator_put(st->reg); } - i2c_set_clientdata(client, NULL); kfree(st); return 0; diff --git a/drivers/staging/iio/light/tsl2563.c b/drivers/staging/iio/light/tsl2563.c index 43aaacff4e74..e4b0a5ef1c1f 100644 --- a/drivers/staging/iio/light/tsl2563.c +++ b/drivers/staging/iio/light/tsl2563.c @@ -694,7 +694,6 @@ static int __devinit tsl2563_probe(struct i2c_client *client, fail2: iio_device_unregister(chip->indio_dev); fail1: - i2c_set_clientdata(client, NULL); kfree(chip); return err; } @@ -705,7 +704,6 @@ static int tsl2563_remove(struct i2c_client *client) iio_device_unregister(chip->indio_dev); - i2c_set_clientdata(client, NULL); kfree(chip); return 0; } diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c index 921ca37398f3..3ec24609151e 100644 --- a/drivers/video/backlight/adp8860_bl.c +++ b/drivers/video/backlight/adp8860_bl.c @@ -756,7 +756,6 @@ out: out1: backlight_device_unregister(bl); out2: - i2c_set_clientdata(client, NULL); kfree(data); return ret; @@ -776,7 +775,6 @@ static int __devexit adp8860_remove(struct i2c_client *client) &adp8860_bl_attr_group); backlight_device_unregister(data->bl); - i2c_set_clientdata(client, NULL); kfree(data); return 0; diff --git a/drivers/video/backlight/tosa_bl.c b/drivers/video/backlight/tosa_bl.c index e03e60bbfd85..2a04b382ec48 100644 --- a/drivers/video/backlight/tosa_bl.c +++ b/drivers/video/backlight/tosa_bl.c @@ -119,7 +119,6 @@ static int __devinit tosa_bl_probe(struct i2c_client *client, err_reg: data->bl = NULL; - i2c_set_clientdata(client, NULL); err_gpio_dir: gpio_free(TOSA_GPIO_BL_C20MA); err_gpio_bl: @@ -133,7 +132,6 @@ static int __devexit tosa_bl_remove(struct i2c_client *client) backlight_device_unregister(data->bl); data->bl = NULL; - i2c_set_clientdata(client, NULL); gpio_free(TOSA_GPIO_BL_C20MA); -- cgit v1.2.3 From a5b365a652206ca300256974ed9301a7d241a6ed Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 25 May 2010 14:17:54 +0200 Subject: virtio-blk: fix minimum number of S/G elements We need at least one S/G element to operate properly, as does the block layer which increments it to one anyway. We hit this due to a qemu bug which advertises a sg_elements of 0 under some circumstances. Signed-off-by: Christoph Hellwig Signed-off-by: Rusty Russell (tweaked logic) --- drivers/block/virtio_blk.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 83fa09a836ca..258bc2ae2885 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -298,7 +298,9 @@ static int __devinit virtblk_probe(struct virtio_device *vdev) err = virtio_config_val(vdev, VIRTIO_BLK_F_SEG_MAX, offsetof(struct virtio_blk_config, seg_max), &sg_elems); - if (err) + + /* We need at least one SG element, whatever they say. */ + if (err || !sg_elems) sg_elems = 1; /* We need an extra sg elements at head and tail. */ -- cgit v1.2.3 From 0047634d3daebca9e99a22eb89167bf77f35cdfa Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Thu, 27 May 2010 13:24:39 +0530 Subject: virtio: console: Fix crash when hot-unplugging a port and read is blocked When removing a port we don't check if a program was blocked for read. This leads to a crash when SIGTERM is sent to the program after hot-unplugging the port. Signed-off-by: Amit Shah Signed-off-by: Rusty Russell --- drivers/char/virtio_console.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 8c99bf1b5e9f..e3fb5296cf25 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1099,6 +1099,13 @@ static int remove_port(struct port *port) { struct port_buffer *buf; + if (port->guest_connected) { + port->guest_connected = false; + port->host_connected = false; + wake_up_interruptible(&port->waitqueue); + send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0); + } + spin_lock_irq(&port->portdev->ports_lock); list_del(&port->list); spin_unlock_irq(&port->portdev->ports_lock); @@ -1120,9 +1127,6 @@ static int remove_port(struct port *port) hvc_remove(port->cons.hvc); #endif } - if (port->guest_connected) - send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0); - sysfs_remove_group(&port->dev->kobj, &port_attribute_group); device_destroy(pdrvdata.class, port->dev->devt); cdev_del(&port->cdev); -- cgit v1.2.3 From 60e5e0b84045ce0f6ab07a02c7fcd6627b53d2d3 Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Thu, 27 May 2010 13:24:40 +0530 Subject: virtio: console: Fix crash when port is unplugged and blocked for write When a program that has a virtio port opened and blocked for a write operation, a port hot-unplug event will later led to a crash when SIGTERM was sent to the program. Fix that. Signed-off-by: Amit Shah Signed-off-by: Rusty Russell --- drivers/char/virtio_console.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index e3fb5296cf25..942a9826bd23 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -529,6 +529,10 @@ static bool will_write_block(struct port *port) { bool ret; + if (!port->guest_connected) { + /* Port got hot-unplugged. Let's exit. */ + return false; + } if (!port->host_connected) return true; -- cgit v1.2.3 From 3a4b4aaa546fa3d57b2ea7f41234f7d2e328da3f Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Thu, 3 Jun 2010 22:10:21 -0700 Subject: Input: wacom - add Cintiq 21UX2 and Intuos4 WL Signed-off-by: Ping Cheng Signed-off-by: Dmitry Torokhov --- drivers/input/tablet/wacom_sys.c | 1 - drivers/input/tablet/wacom_wac.c | 73 ++++++++++++++++++++++++++++++++-------- drivers/input/tablet/wacom_wac.h | 1 + 3 files changed, 60 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index 2dc0c07c0469..42ba3691d908 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c @@ -507,7 +507,6 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i goto fail3; } - input_dev->name = wacom_wac->name; input_dev->name = wacom_wac->name; input_dev->dev.parent = &intf->dev; input_dev->open = wacom_open; diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 847fd0135bcf..d564af58175c 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -300,7 +300,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) case 0x823: /* Intuos3 Grip Pen */ case 0x813: /* Intuos3 Classic Pen */ case 0x885: /* Intuos3 Marker Pen */ - case 0x802: /* Intuos4 Grip Pen Eraser */ + case 0x802: /* Intuos4 General Pen */ case 0x804: /* Intuos4 Marker Pen */ case 0x40802: /* Intuos4 Classic Pen */ case 0x022: @@ -335,7 +335,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) case 0x81b: /* Intuos3 Classic Pen Eraser */ case 0x91b: /* Intuos3 Airbrush Eraser */ case 0x80c: /* Intuos4 Marker Pen Eraser */ - case 0x80a: /* Intuos4 Grip Pen Eraser */ + case 0x80a: /* Intuos4 General Pen Eraser */ case 0x4080a: /* Intuos4 Classic Pen Eraser */ case 0x90a: /* Intuos4 Airbrush Eraser */ wacom->tool[idx] = BTN_TOOL_RUBBER; @@ -356,6 +356,11 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) return 1; } + /* older I4 styli don't work with new Cintiqs */ + if (!((wacom->id[idx] >> 20) & 0x01) && + (features->type == WACOM_21UX2)) + return 1; + /* Exit report */ if ((data[1] & 0xfe) == 0x80) { /* @@ -474,21 +479,43 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) input_report_abs(input, ABS_MISC, 0); } } else { - input_report_key(input, BTN_0, (data[5] & 0x01)); - input_report_key(input, BTN_1, (data[5] & 0x02)); - input_report_key(input, BTN_2, (data[5] & 0x04)); - input_report_key(input, BTN_3, (data[5] & 0x08)); - input_report_key(input, BTN_4, (data[6] & 0x01)); - input_report_key(input, BTN_5, (data[6] & 0x02)); - input_report_key(input, BTN_6, (data[6] & 0x04)); - input_report_key(input, BTN_7, (data[6] & 0x08)); - input_report_key(input, BTN_8, (data[5] & 0x10)); - input_report_key(input, BTN_9, (data[6] & 0x10)); + if (features->type == WACOM_21UX2) { + input_report_key(input, BTN_0, (data[5] & 0x01)); + input_report_key(input, BTN_1, (data[6] & 0x01)); + input_report_key(input, BTN_2, (data[6] & 0x02)); + input_report_key(input, BTN_3, (data[6] & 0x04)); + input_report_key(input, BTN_4, (data[6] & 0x08)); + input_report_key(input, BTN_5, (data[6] & 0x10)); + input_report_key(input, BTN_6, (data[6] & 0x20)); + input_report_key(input, BTN_7, (data[6] & 0x40)); + input_report_key(input, BTN_8, (data[6] & 0x80)); + input_report_key(input, BTN_9, (data[7] & 0x01)); + input_report_key(input, BTN_A, (data[8] & 0x01)); + input_report_key(input, BTN_B, (data[8] & 0x02)); + input_report_key(input, BTN_C, (data[8] & 0x04)); + input_report_key(input, BTN_X, (data[8] & 0x08)); + input_report_key(input, BTN_Y, (data[8] & 0x10)); + input_report_key(input, BTN_Z, (data[8] & 0x20)); + input_report_key(input, BTN_BASE, (data[8] & 0x40)); + input_report_key(input, BTN_BASE2, (data[8] & 0x80)); + } else { + input_report_key(input, BTN_0, (data[5] & 0x01)); + input_report_key(input, BTN_1, (data[5] & 0x02)); + input_report_key(input, BTN_2, (data[5] & 0x04)); + input_report_key(input, BTN_3, (data[5] & 0x08)); + input_report_key(input, BTN_4, (data[6] & 0x01)); + input_report_key(input, BTN_5, (data[6] & 0x02)); + input_report_key(input, BTN_6, (data[6] & 0x04)); + input_report_key(input, BTN_7, (data[6] & 0x08)); + input_report_key(input, BTN_8, (data[5] & 0x10)); + input_report_key(input, BTN_9, (data[6] & 0x10)); + } input_report_abs(input, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]); input_report_abs(input, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]); if ((data[5] & 0x1f) | (data[6] & 0x1f) | (data[1] & 0x1f) | - data[2] | (data[3] & 0x1f) | data[4]) { + data[2] | (data[3] & 0x1f) | data[4] | data[8] | + (data[7] & 0x01)) { input_report_key(input, wacom->tool[1], 1); input_report_abs(input, ABS_MISC, PAD_DEVICE_ID); } else { @@ -640,7 +667,7 @@ static void wacom_tpc_finger_in(struct wacom_wac *wacom, char *data, int idx) if (!idx) input_report_key(input, BTN_TOUCH, 1); input_event(input, EV_MSC, MSC_SERIAL, finger); - input_sync(wacom->input); + input_sync(input); wacom->last_finger = finger; } @@ -826,6 +853,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len) case INTUOS4L: case CINTIQ: case WACOM_BEE: + case WACOM_21UX2: sync = wacom_intuos_irq(wacom_wac); break; @@ -921,6 +949,17 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, __set_bit(BTN_STYLUS2, input_dev->keybit); break; + case WACOM_21UX2: + __set_bit(BTN_A, input_dev->keybit); + __set_bit(BTN_B, input_dev->keybit); + __set_bit(BTN_C, input_dev->keybit); + __set_bit(BTN_X, input_dev->keybit); + __set_bit(BTN_Y, input_dev->keybit); + __set_bit(BTN_Z, input_dev->keybit); + __set_bit(BTN_BASE, input_dev->keybit); + __set_bit(BTN_BASE2, input_dev->keybit); + /* fall through */ + case WACOM_BEE: __set_bit(BTN_8, input_dev->keybit); __set_bit(BTN_9, input_dev->keybit); @@ -1105,6 +1144,8 @@ static const struct wacom_features wacom_features_0xBA = { "Wacom Intuos4 8x13", WACOM_PKGLEN_INTUOS, 65024, 40640, 2047, 63, INTUOS4L }; static const struct wacom_features wacom_features_0xBB = { "Wacom Intuos4 12x19", WACOM_PKGLEN_INTUOS, 97536, 60960, 2047, 63, INTUOS4L }; +static const struct wacom_features wacom_features_0xBC = + { "Wacom Intuos4 WL", WACOM_PKGLEN_INTUOS, 40840, 25400, 2047, 63, INTUOS4 }; static const struct wacom_features wacom_features_0x3F = { "Wacom Cintiq 21UX", WACOM_PKGLEN_INTUOS, 87200, 65600, 1023, 63, CINTIQ }; static const struct wacom_features wacom_features_0xC5 = @@ -1113,6 +1154,8 @@ static const struct wacom_features wacom_features_0xC6 = { "Wacom Cintiq 12WX", WACOM_PKGLEN_INTUOS, 53020, 33440, 1023, 63, WACOM_BEE }; static const struct wacom_features wacom_features_0xC7 = { "Wacom DTU1931", WACOM_PKGLEN_GRAPHIRE, 37832, 30305, 511, 0, PL }; +static const struct wacom_features wacom_features_0xCC = + { "Wacom Cintiq 21UX2", WACOM_PKGLEN_INTUOS, 87200, 65600, 2047, 63, WACOM_21UX2 }; static const struct wacom_features wacom_features_0x90 = { "Wacom ISDv4 90", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC }; static const struct wacom_features wacom_features_0x93 = @@ -1185,10 +1228,12 @@ const struct usb_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0xB9) }, { USB_DEVICE_WACOM(0xBA) }, { USB_DEVICE_WACOM(0xBB) }, + { USB_DEVICE_WACOM(0xBC) }, { USB_DEVICE_WACOM(0x3F) }, { USB_DEVICE_WACOM(0xC5) }, { USB_DEVICE_WACOM(0xC6) }, { USB_DEVICE_WACOM(0xC7) }, + { USB_DEVICE_WACOM(0xCC) }, { USB_DEVICE_WACOM(0x90) }, { USB_DEVICE_WACOM(0x93) }, { USB_DEVICE_WACOM(0x9A) }, diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h index 063f1af3204f..854b92092dfc 100644 --- a/drivers/input/tablet/wacom_wac.h +++ b/drivers/input/tablet/wacom_wac.h @@ -50,6 +50,7 @@ enum { INTUOS4S, INTUOS4, INTUOS4L, + WACOM_21UX2, CINTIQ, WACOM_BEE, WACOM_MO, -- cgit v1.2.3 From 8bf2269fc08b883c728fce2171e9c6747a6a91b4 Mon Sep 17 00:00:00 2001 From: Christoph Egger Date: Thu, 3 Jun 2010 22:05:14 -0700 Subject: Input: i8042 - remove SPRUCE support CONFIG_SPRUCE was removed from kernel around 2.6.26; let's remove the last remaining piece. Signed-off-by: Christoph Egger Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042-ppcio.h | 75 --------------------------------------- 1 file changed, 75 deletions(-) (limited to 'drivers') diff --git a/drivers/input/serio/i8042-ppcio.h b/drivers/input/serio/i8042-ppcio.h index 2906e1b60c04..f708c75d16f1 100644 --- a/drivers/input/serio/i8042-ppcio.h +++ b/drivers/input/serio/i8042-ppcio.h @@ -52,81 +52,6 @@ static inline void i8042_platform_exit(void) { } -#elif defined(CONFIG_SPRUCE) - -#define I8042_KBD_IRQ 22 -#define I8042_AUX_IRQ 21 - -#define I8042_KBD_PHYS_DESC "spruceps2/serio0" -#define I8042_AUX_PHYS_DESC "spruceps2/serio1" -#define I8042_MUX_PHYS_DESC "spruceps2/serio%d" - -#define I8042_COMMAND_REG 0xff810000 -#define I8042_DATA_REG 0xff810001 - -static inline int i8042_read_data(void) -{ - unsigned long kbd_data; - - __raw_writel(0x00000088, 0xff500008); - eieio(); - - __raw_writel(0x03000000, 0xff50000c); - eieio(); - - asm volatile("lis 7,0xff88 \n\ - lswi 6,7,0x8 \n\ - mr %0,6" - : "=r" (kbd_data) :: "6", "7"); - - __raw_writel(0x00000000, 0xff50000c); - eieio(); - - return (unsigned char)(kbd_data >> 24); -} - -static inline int i8042_read_status(void) -{ - unsigned long kbd_status; - - __raw_writel(0x00000088, 0xff500008); - eieio(); - - __raw_writel(0x03000000, 0xff50000c); - eieio(); - - asm volatile("lis 7,0xff88 \n\ - ori 7,7,0x8 \n\ - lswi 6,7,0x8 \n\ - mr %0,6" - : "=r" (kbd_status) :: "6", "7"); - - __raw_writel(0x00000000, 0xff50000c); - eieio(); - - return (unsigned char)(kbd_status >> 24); -} - -static inline void i8042_write_data(int val) -{ - *((unsigned char *)0xff810000) = (char)val; -} - -static inline void i8042_write_command(int val) -{ - *((unsigned char *)0xff810001) = (char)val; -} - -static inline int i8042_platform_init(void) -{ - i8042_reset = 1; - return 0; -} - -static inline void i8042_platform_exit(void) -{ -} - #else #include "i8042-io.h" -- cgit v1.2.3 From 8aa4b14eb023fecaa48d55402e98bdf84b375c4a Mon Sep 17 00:00:00 2001 From: Chen Gong Date: Sun, 30 May 2010 11:37:08 +0800 Subject: ACPI: acpi_pad: Don't needlessly mark LAPIC unstable As suggested in Venki's suggestion in the commit 0dc698b, add LAPIC unstable detection in the acpi_pad drvier too. Signed-off-by: Chen Gong Signed-off-by: Len Brown --- drivers/acpi/acpi_pad.c | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index d269a8f3329c..446aced33aff 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -46,6 +46,8 @@ static unsigned long power_saving_mwait_eax; static unsigned char tsc_detected_unstable; static unsigned char tsc_marked_unstable; +static unsigned char lapic_detected_unstable; +static unsigned char lapic_marked_unstable; static void power_saving_mwait_init(void) { @@ -75,9 +77,6 @@ static void power_saving_mwait_init(void) power_saving_mwait_eax = (highest_cstate << MWAIT_SUBSTATE_SIZE) | (highest_subcstate - 1); - for_each_online_cpu(i) - clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &i); - #if defined(CONFIG_GENERIC_TIME) && defined(CONFIG_X86) switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: @@ -86,13 +85,15 @@ static void power_saving_mwait_init(void) * AMD Fam10h TSC will tick in all * C/P/S0/S1 states when this bit is set. */ - if (boot_cpu_has(X86_FEATURE_NONSTOP_TSC)) - return; - - /*FALL THROUGH*/ + if (!boot_cpu_has(X86_FEATURE_NONSTOP_TSC)) + tsc_detected_unstable = 1; + if (!boot_cpu_has(X86_FEATURE_ARAT)) + lapic_detected_unstable = 1; + break; default: - /* TSC could halt in idle */ + /* TSC & LAPIC could halt in idle */ tsc_detected_unstable = 1; + lapic_detected_unstable = 1; } #endif } @@ -180,10 +181,20 @@ static int power_saving_thread(void *data) mark_tsc_unstable("TSC halts in idle"); tsc_marked_unstable = 1; } + if (lapic_detected_unstable && !lapic_marked_unstable) { + int i; + /* LAPIC could halt in idle, so notify users */ + for_each_online_cpu(i) + clockevents_notify( + CLOCK_EVT_NOTIFY_BROADCAST_ON, + &i); + lapic_marked_unstable = 1; + } local_irq_disable(); cpu = smp_processor_id(); - clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, - &cpu); + if (lapic_marked_unstable) + clockevents_notify( + CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu); stop_critical_timings(); __monitor((void *)¤t_thread_info()->flags, 0, 0); @@ -192,8 +203,9 @@ static int power_saving_thread(void *data) __mwait(power_saving_mwait_eax, 1); start_critical_timings(); - clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, - &cpu); + if (lapic_marked_unstable) + clockevents_notify( + CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu); local_irq_enable(); if (jiffies > expire_time) { -- cgit v1.2.3 From 786d78318586cbdc8aec539fe5a4942490267fef Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Fri, 30 Apr 2010 16:50:22 +0300 Subject: UBI: simplify IO error codes We do not really need 2 separate error codes for indicating bad VID and bad EC headers (UBI_IO_BAD_EC_HDR, UBI_IO_BAD_VID_HDR), it is enough to have only one UBI_IO_BAD_HDR return code. This patch does not introduce any functional change, only some code simplification. Signed-off-by: Artem Bityutskiy Reviewed-by: Sebastian Andrzej Siewior Tested-by: Sebastian Andrzej Siewior --- drivers/mtd/ubi/eba.c | 4 ++-- drivers/mtd/ubi/io.c | 14 +++++++------- drivers/mtd/ubi/scan.c | 4 ++-- drivers/mtd/ubi/ubi.h | 7 ++----- 4 files changed, 13 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 9f87c99189a9..8e8226744320 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -418,7 +418,7 @@ retry: * may try to recover data. FIXME: but this is * not implemented. */ - if (err == UBI_IO_BAD_VID_HDR) { + if (err == UBI_IO_BAD_HDR) { ubi_warn("corrupted VID header at PEB " "%d, LEB %d:%d", pnum, vol_id, lnum); @@ -961,7 +961,7 @@ write_error: */ static int is_error_sane(int err) { - if (err == -EIO || err == -ENOMEM || err == UBI_IO_BAD_VID_HDR || + if (err == -EIO || err == -ENOMEM || err == UBI_IO_BAD_HDR || err == -ETIMEDOUT) return 0; return 1; diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index 4b979e34b159..02b19327dcc4 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -515,7 +515,7 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum) * In this case we probably anyway have garbage in this PEB. */ err1 = ubi_io_read_vid_hdr(ubi, pnum, &vid_hdr, 0); - if (err1 == UBI_IO_BAD_VID_HDR) + if (err1 == UBI_IO_BAD_HDR) /* * The VID header is corrupted, so we can safely erase this * PEB and not afraid that it will be treated as a valid PEB in @@ -709,7 +709,7 @@ bad: * o %UBI_IO_BITFLIPS if the CRC is correct, but bit-flips were detected * and corrected by the flash driver; this is harmless but may indicate that * this eraseblock may become bad soon (but may be not); - * o %UBI_IO_BAD_EC_HDR if the erase counter header is corrupted (a CRC error); + * o %UBI_IO_BAD_HDR if the erase counter header is corrupted (a CRC error); * o %UBI_IO_PEB_EMPTY if the physical eraseblock is empty; * o a negative error code in case of failure. */ @@ -774,7 +774,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, } else if (UBI_IO_DEBUG) dbg_msg("bad magic number at PEB %d: %08x instead of " "%08x", pnum, magic, UBI_EC_HDR_MAGIC); - return UBI_IO_BAD_EC_HDR; + return UBI_IO_BAD_HDR; } crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC); @@ -788,7 +788,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, } else if (UBI_IO_DEBUG) dbg_msg("bad EC header CRC at PEB %d, calculated " "%#08x, read %#08x", pnum, crc, hdr_crc); - return UBI_IO_BAD_EC_HDR; + return UBI_IO_BAD_HDR; } /* And of course validate what has just been read from the media */ @@ -977,7 +977,7 @@ bad: * o %UBI_IO_BITFLIPS if the CRC is correct, but bit-flips were detected * and corrected by the flash driver; this is harmless but may indicate that * this eraseblock may become bad soon; - * o %UBI_IO_BAD_VID_HDR if the volume identifier header is corrupted (a CRC + * o %UBI_IO_BAD_HDR if the volume identifier header is corrupted (a CRC * error detected); * o %UBI_IO_PEB_FREE if the physical eraseblock is free (i.e., there is no VID * header there); @@ -1045,7 +1045,7 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, } else if (UBI_IO_DEBUG) dbg_msg("bad magic number at PEB %d: %08x instead of " "%08x", pnum, magic, UBI_VID_HDR_MAGIC); - return UBI_IO_BAD_VID_HDR; + return UBI_IO_BAD_HDR; } crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC); @@ -1059,7 +1059,7 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, } else if (UBI_IO_DEBUG) dbg_msg("bad CRC at PEB %d, calculated %#08x, " "read %#08x", pnum, crc, hdr_crc); - return UBI_IO_BAD_VID_HDR; + return UBI_IO_BAD_HDR; } /* Validate the VID header that we have just read */ diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c index aed19f33b8f3..b878a7661f5a 100644 --- a/drivers/mtd/ubi/scan.c +++ b/drivers/mtd/ubi/scan.c @@ -745,7 +745,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, bitflips = 1; else if (err == UBI_IO_PEB_EMPTY) return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, &si->erase); - else if (err == UBI_IO_BAD_EC_HDR) { + else if (err == UBI_IO_BAD_HDR) { /* * We have to also look at the VID header, possibly it is not * corrupted. Set %bitflips flag in order to make this PEB be @@ -813,7 +813,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, return err; else if (err == UBI_IO_BITFLIPS) bitflips = 1; - else if (err == UBI_IO_BAD_VID_HDR || + else if (err == UBI_IO_BAD_HDR || (err == UBI_IO_PEB_FREE && ec_corr)) { /* VID header is corrupted */ err = add_to_list(si, pnum, ec, &si->corr); diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index a637f0283add..539b3f6c7a56 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -89,16 +89,13 @@ * %0xFF bytes * UBI_IO_PEB_FREE: the physical eraseblock is free, i.e. it contains only a * valid erase counter header, and the rest are %0xFF bytes - * UBI_IO_BAD_EC_HDR: the erase counter header is corrupted (bad magic or CRC) - * UBI_IO_BAD_VID_HDR: the volume identifier header is corrupted (bad magic or - * CRC) + * UBI_IO_BAD_HDR: the EC or VID header is corrupted (bad magic or CRC) * UBI_IO_BITFLIPS: bit-flips were detected and corrected */ enum { UBI_IO_PEB_EMPTY = 1, UBI_IO_PEB_FREE, - UBI_IO_BAD_EC_HDR, - UBI_IO_BAD_VID_HDR, + UBI_IO_BAD_HDR, UBI_IO_BITFLIPS }; -- cgit v1.2.3 From eb89580e1a8388d206bf143c6c39d001095106ba Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Mon, 3 May 2010 09:04:39 +0300 Subject: UBI: introduce a new IO return code This patch introduces the %UBI_IO_BAD_HDR_READ return code for the I/O level function. We will use this code in order to distinguish between "corrupted header possibly because this is non-ubi data" and "corrupted header possibly because of real data corruption and ECC error". So far this patch does not introduce any functional change, just a preparation. This patch is pased on a patch from Sebastian Andrzej Siewior Signed-off-by: Artem Bityutskiy Reviewed-by: Sebastian Andrzej Siewior Tested-by: Sebastian Andrzej Siewior --- drivers/mtd/ubi/eba.c | 5 +++-- drivers/mtd/ubi/io.c | 42 +++++++++++++++++++++++------------------- drivers/mtd/ubi/scan.c | 4 ++-- drivers/mtd/ubi/ubi.h | 3 +++ 4 files changed, 31 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 8e8226744320..b582671ca3a0 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -418,7 +418,8 @@ retry: * may try to recover data. FIXME: but this is * not implemented. */ - if (err == UBI_IO_BAD_HDR) { + if (err == UBI_IO_BAD_HDR_READ || + err == UBI_IO_BAD_HDR) { ubi_warn("corrupted VID header at PEB " "%d, LEB %d:%d", pnum, vol_id, lnum); @@ -962,7 +963,7 @@ write_error: static int is_error_sane(int err) { if (err == -EIO || err == -ENOMEM || err == UBI_IO_BAD_HDR || - err == -ETIMEDOUT) + err == UBI_IO_BAD_HDR_READ || err == -ETIMEDOUT) return 0; return 1; } diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index 02b19327dcc4..b812f8805367 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -515,7 +515,7 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum) * In this case we probably anyway have garbage in this PEB. */ err1 = ubi_io_read_vid_hdr(ubi, pnum, &vid_hdr, 0); - if (err1 == UBI_IO_BAD_HDR) + if (err1 == UBI_IO_BAD_HDR_READ || err1 == UBI_IO_BAD_HDR) /* * The VID header is corrupted, so we can safely erase this * PEB and not afraid that it will be treated as a valid PEB in @@ -736,23 +736,21 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, * header is still OK, we just report this as there was a * bit-flip. */ - read_err = err; + if (err == -EBADMSG) + read_err = UBI_IO_BAD_HDR_READ; } magic = be32_to_cpu(ec_hdr->magic); if (magic != UBI_EC_HDR_MAGIC) { + if (read_err) + return read_err; + /* * The magic field is wrong. Let's check if we have read all * 0xFF. If yes, this physical eraseblock is assumed to be * empty. - * - * But if there was a read error, we do not test it for all - * 0xFFs. Even if it does contain all 0xFFs, this error - * indicates that something is still wrong with this physical - * eraseblock and we anyway cannot treat it as empty. */ - if (read_err != -EBADMSG && - check_pattern(ec_hdr, 0xFF, UBI_EC_HDR_SIZE)) { + if (check_pattern(ec_hdr, 0xFF, UBI_EC_HDR_SIZE)) { /* The physical eraseblock is supposedly empty */ if (verbose) ubi_warn("no EC header found at PEB %d, " @@ -788,7 +786,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, } else if (UBI_IO_DEBUG) dbg_msg("bad EC header CRC at PEB %d, calculated " "%#08x, read %#08x", pnum, crc, hdr_crc); - return UBI_IO_BAD_HDR; + return read_err ?: UBI_IO_BAD_HDR; } /* And of course validate what has just been read from the media */ @@ -798,6 +796,10 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, return -EINVAL; } + /* + * If there was %-EBADMSG, but the header CRC is still OK, report about + * a bit-flip to force scrubbing on this PEB. + */ return read_err ? UBI_IO_BITFLIPS : 0; } @@ -1008,22 +1010,20 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, * CRC check-sum and we will identify this. If the VID header is * still OK, we just report this as there was a bit-flip. */ - read_err = err; + if (err == -EBADMSG) + read_err = UBI_IO_BAD_HDR_READ; } magic = be32_to_cpu(vid_hdr->magic); if (magic != UBI_VID_HDR_MAGIC) { + if (read_err) + return read_err; + /* * If we have read all 0xFF bytes, the VID header probably does * not exist and the physical eraseblock is assumed to be free. - * - * But if there was a read error, we do not test the data for - * 0xFFs. Even if it does contain all 0xFFs, this error - * indicates that something is still wrong with this physical - * eraseblock and it cannot be regarded as free. */ - if (read_err != -EBADMSG && - check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) { + if (check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) { /* The physical eraseblock is supposedly free */ if (verbose) ubi_warn("no VID header found at PEB %d, " @@ -1059,7 +1059,7 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, } else if (UBI_IO_DEBUG) dbg_msg("bad CRC at PEB %d, calculated %#08x, " "read %#08x", pnum, crc, hdr_crc); - return UBI_IO_BAD_HDR; + return read_err ?: UBI_IO_BAD_HDR; } /* Validate the VID header that we have just read */ @@ -1069,6 +1069,10 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, return -EINVAL; } + /* + * If there was a read error (%-EBADMSG), but the header CRC is still + * OK, report about a bit-flip to force scrubbing on this PEB. + */ return read_err ? UBI_IO_BITFLIPS : 0; } diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c index b878a7661f5a..c45900744107 100644 --- a/drivers/mtd/ubi/scan.c +++ b/drivers/mtd/ubi/scan.c @@ -745,7 +745,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, bitflips = 1; else if (err == UBI_IO_PEB_EMPTY) return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, &si->erase); - else if (err == UBI_IO_BAD_HDR) { + else if (err == UBI_IO_BAD_HDR_READ || err == UBI_IO_BAD_HDR) { /* * We have to also look at the VID header, possibly it is not * corrupted. Set %bitflips flag in order to make this PEB be @@ -813,7 +813,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, return err; else if (err == UBI_IO_BITFLIPS) bitflips = 1; - else if (err == UBI_IO_BAD_HDR || + else if (err == UBI_IO_BAD_HDR_READ || err == UBI_IO_BAD_HDR || (err == UBI_IO_PEB_FREE && ec_corr)) { /* VID header is corrupted */ err = add_to_list(si, pnum, ec, &si->corr); diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index 539b3f6c7a56..0359e0cce482 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -90,12 +90,15 @@ * UBI_IO_PEB_FREE: the physical eraseblock is free, i.e. it contains only a * valid erase counter header, and the rest are %0xFF bytes * UBI_IO_BAD_HDR: the EC or VID header is corrupted (bad magic or CRC) + * UBI_IO_BAD_HDR_READ: the same as %UBI_IO_BAD_HDR, but also there was a read + * error reported by the flash driver * UBI_IO_BITFLIPS: bit-flips were detected and corrected */ enum { UBI_IO_PEB_EMPTY = 1, UBI_IO_PEB_FREE, UBI_IO_BAD_HDR, + UBI_IO_BAD_HDR_READ, UBI_IO_BITFLIPS }; -- cgit v1.2.3 From 33789fb9d4470e27d18596c0966339e2ca8865a9 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Fri, 30 Apr 2010 12:31:26 +0300 Subject: UBI: introduce eraseblock counter variables This is just a preparation patch which introduces several 'struct ubi_scan_info' fields which count eraseblocks of different types. This will be used later on to decide whether it is safe to format the flash or not. No functional changes so far. Signed-off-by: Artem Bityutskiy Reviewed-by: Sebastian Andrzej Siewior Tested-by: Sebastian Andrzej Siewior --- drivers/mtd/ubi/scan.c | 27 +++++++++++++++++---------- drivers/mtd/ubi/scan.h | 19 ++++++++++++++----- 2 files changed, 31 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c index c45900744107..a20f278d0c6c 100644 --- a/drivers/mtd/ubi/scan.c +++ b/drivers/mtd/ubi/scan.c @@ -72,16 +72,19 @@ static int add_to_list(struct ubi_scan_info *si, int pnum, int ec, { struct ubi_scan_leb *seb; - if (list == &si->free) + if (list == &si->free) { dbg_bld("add to free: PEB %d, EC %d", pnum, ec); - else if (list == &si->erase) + si->free_peb_count += 1; + } else if (list == &si->erase) { dbg_bld("add to erase: PEB %d, EC %d", pnum, ec); - else if (list == &si->corr) { + si->erase_peb_count += 1; + } else if (list == &si->corr) { dbg_bld("add to corrupted: PEB %d, EC %d", pnum, ec); - si->corr_count += 1; - } else if (list == &si->alien) + si->corr_peb_count += 1; + } else if (list == &si->alien) { dbg_bld("add to alien: PEB %d, EC %d", pnum, ec); - else + si->alien_peb_count += 1; + } else BUG(); seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL); @@ -517,6 +520,7 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si, sv->leb_count += 1; rb_link_node(&seb->u.rb, parent, p); rb_insert_color(&seb->u.rb, &sv->root); + si->used_peb_count += 1; return 0; } @@ -751,7 +755,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, * corrupted. Set %bitflips flag in order to make this PEB be * moved and EC be re-created. */ - ec_corr = 1; + ec_corr = err; ec = UBI_SCAN_UNKNOWN_EC; bitflips = 1; } @@ -816,6 +820,9 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, else if (err == UBI_IO_BAD_HDR_READ || err == UBI_IO_BAD_HDR || (err == UBI_IO_PEB_FREE && ec_corr)) { /* VID header is corrupted */ + if (err == UBI_IO_BAD_HDR_READ || + ec_corr == UBI_IO_BAD_HDR_READ) + si->read_err_count += 1; err = add_to_list(si, pnum, ec, &si->corr); if (err) return err; @@ -855,7 +862,6 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, err = add_to_list(si, pnum, ec, &si->alien); if (err) return err; - si->alien_peb_count += 1; return 0; case UBI_COMPAT_REJECT: @@ -943,8 +949,9 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi) * unclean reboots. However, many of them may indicate some problems * with the flash HW or driver. Print a warning in this case. */ - if (si->corr_count >= 8 || si->corr_count >= ubi->peb_count / 4) { - ubi_warn("%d PEBs are corrupted", si->corr_count); + if (si->corr_peb_count >= 8 || + si->corr_peb_count >= ubi->peb_count / 4) { + ubi_warn("%d PEBs are corrupted", si->corr_peb_count); printk(KERN_WARNING "corrupted PEBs are:"); list_for_each_entry(seb, &si->corr, u.list) printk(KERN_CONT " %d", seb->pnum); diff --git a/drivers/mtd/ubi/scan.h b/drivers/mtd/ubi/scan.h index ff179ad7ca55..2576a8d1532b 100644 --- a/drivers/mtd/ubi/scan.h +++ b/drivers/mtd/ubi/scan.h @@ -91,10 +91,16 @@ struct ubi_scan_volume { * @erase: list of physical eraseblocks which have to be erased * @alien: list of physical eraseblocks which should not be used by UBI (e.g., * those belonging to "preserve"-compatible internal volumes) + * @used_peb_count: count of used PEBs + * @corr_peb_count: count of PEBs in the @corr list + * @read_err_count: count of PEBs read with error (%UBI_IO_BAD_HDR_READ was + * returned) + * @free_peb_count: count of PEBs in the @free list + * @erase_peb_count: count of PEBs in the @erase list + * @alien_peb_count: count of PEBs in the @alien list * @bad_peb_count: count of bad physical eraseblocks * @vols_found: number of volumes found during scanning * @highest_vol_id: highest volume ID - * @alien_peb_count: count of physical eraseblocks in the @alien list * @is_empty: flag indicating whether the MTD device is empty or not * @min_ec: lowest erase counter value * @max_ec: highest erase counter value @@ -102,7 +108,6 @@ struct ubi_scan_volume { * @mean_ec: mean erase counter value * @ec_sum: a temporary variable used when calculating @mean_ec * @ec_count: a temporary variable used when calculating @mean_ec - * @corr_count: count of corrupted PEBs * * This data structure contains the result of scanning and may be used by other * UBI sub-systems to build final UBI data structures, further error-recovery @@ -114,10 +119,15 @@ struct ubi_scan_info { struct list_head free; struct list_head erase; struct list_head alien; + int used_peb_count; + int corr_peb_count; + int read_err_count; + int free_peb_count; + int erase_peb_count; + int alien_peb_count; int bad_peb_count; int vols_found; int highest_vol_id; - int alien_peb_count; int is_empty; int min_ec; int max_ec; @@ -125,7 +135,6 @@ struct ubi_scan_info { int mean_ec; uint64_t ec_sum; int ec_count; - int corr_count; }; struct ubi_device; @@ -135,7 +144,7 @@ struct ubi_vid_hdr; * ubi_scan_move_to_list - move a PEB from the volume tree to a list. * * @sv: volume scanning information - * @seb: scanning eraseblock infprmation + * @seb: scanning eraseblock information * @list: the list to move to */ static inline void ubi_scan_move_to_list(struct ubi_scan_volume *sv, -- cgit v1.2.3 From 0798cea8c2e1afee59686c51d27d0e96b05e42d1 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Fri, 30 Apr 2010 13:02:33 +0300 Subject: UBI: improve corrupted flash handling This patch improves the way UBI handles corrupted flash, or flash containing garbage or non-UBI data, which is the same from UBI POW. Namely, we do the following: * if 5% or more PEBs are corrupted, refuse the flash * if less than 5% PEBs are corrupted, do not refuse the flash and format these PEBs * if less than 8 PEBs are corrupted, format them silently, otherwise print a warning message. Reported-by: Sebastian Andrzej Siewior Signed-off-by: Artem Bityutskiy Reviewed-by: Sebastian Andrzej Siewior Tested-by: Sebastian Andrzej Siewior --- drivers/mtd/ubi/scan.c | 101 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 82 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c index a20f278d0c6c..6b7c0c4baf07 100644 --- a/drivers/mtd/ubi/scan.c +++ b/drivers/mtd/ubi/scan.c @@ -760,8 +760,6 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, bitflips = 1; } - si->is_empty = 0; - if (!ec_corr) { int image_seq; @@ -891,6 +889,85 @@ adjust_mean_ec: return 0; } +/** + * check_what_we_have - check what PEB were found by scanning. + * @ubi: UBI device description object + * @si: scanning information + * + * This is a helper function which takes a look what PEBs were found by + * scanning, and decides whether the flash is empty and should be formatted and + * whether there are too many corrupted PEBs and we should not attach this + * MTD device. Returns zero if we should proceed with attaching the MTD device, + * and %-EINVAL if we should not. + */ +static int check_what_we_have(const struct ubi_device *ubi, + struct ubi_scan_info *si) +{ + struct ubi_scan_leb *seb; + int max_corr; + + max_corr = ubi->peb_count - si->bad_peb_count - si->alien_peb_count; + max_corr = max_corr / 20 ?: 8; + + /* + * Few corrupted PEBs are not a problem and may be just a result of + * unclean reboots. However, many of them may indicate some problems + * with the flash HW or driver. + */ + if (si->corr_peb_count >= 8) { + ubi_warn("%d PEBs are corrupted", si->corr_peb_count); + printk(KERN_WARNING "corrupted PEBs are:"); + list_for_each_entry(seb, &si->corr, u.list) + printk(KERN_CONT " %d", seb->pnum); + printk(KERN_CONT "\n"); + + /* + * If too many PEBs are corrupted, we refuse attaching, + * otherwise, only print a warning. + */ + if (si->corr_peb_count >= max_corr) { + ubi_err("too many corrupted PEBs, refusing this device"); + return -EINVAL; + } + } + + if (si->free_peb_count + si->used_peb_count + + si->alien_peb_count == 0) { + /* No UBI-formatted eraseblocks were found */ + if (si->corr_peb_count == si->read_err_count && + si->corr_peb_count < 8) { + /* No or just few corrupted PEBs, and all of them had a + * read error. We assume that those are bad PEBs, which + * were just not marked as bad so far. + * + * This piece of code basically tries to distinguish + * between the following 2 situations: + * + * 1. Flash is empty, but there are few bad PEBs, which + * are not marked as bad so far, and which were read + * with error. We want to go ahead and format this + * flash. While formating, the faulty PEBs will + * probably be marked as bad. + * + * 2. Flash probably contains non-UBI data and we do + * not want to format it and destroy possibly needed + * data (e.g., consider the case when the bootloader + * MTD partition was accidentally fed to UBI). + */ + si->is_empty = 1; + ubi_msg("empty MTD device detected"); + } else { + ubi_err("MTD device possibly contains non-UBI data, " + "refusing it"); + return -EINVAL; + } + } + + if (si->corr_peb_count >= 0) + ubi_msg("corrupted PEBs will be formatted"); + return 0; +} + /** * ubi_scan - scan an MTD device. * @ubi: UBI device description object @@ -915,7 +992,6 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi) INIT_LIST_HEAD(&si->erase); INIT_LIST_HEAD(&si->alien); si->volumes = RB_ROOT; - si->is_empty = 1; err = -ENOMEM; ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL); @@ -941,22 +1017,9 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi) if (si->ec_count) si->mean_ec = div_u64(si->ec_sum, si->ec_count); - if (si->is_empty) - ubi_msg("empty MTD device detected"); - - /* - * Few corrupted PEBs are not a problem and may be just a result of - * unclean reboots. However, many of them may indicate some problems - * with the flash HW or driver. Print a warning in this case. - */ - if (si->corr_peb_count >= 8 || - si->corr_peb_count >= ubi->peb_count / 4) { - ubi_warn("%d PEBs are corrupted", si->corr_peb_count); - printk(KERN_WARNING "corrupted PEBs are:"); - list_for_each_entry(seb, &si->corr, u.list) - printk(KERN_CONT " %d", seb->pnum); - printk(KERN_CONT "\n"); - } + err = check_what_we_have(ubi, si); + if (err) + goto out_vidh; /* * In case of unknown erase counter we use the mean erase counter -- cgit v1.2.3 From e5a2a04c264e693eafcc78fec5add34c9e15e471 Mon Sep 17 00:00:00 2001 From: Jindrich Makovicka Date: Thu, 3 Jun 2010 12:50:42 +0200 Subject: HID: check for HID_QUIRK_IGNORE during probing While the hardcoded ignore list is checked in hid_add_device(), the user supplied ignore flags are not. Thus, the IGNORE quirk (0x0004) cannot be used to stop usbhid from binding devices like iBuddy, which has been recently removed from the ignore list due to product ID conflict. This patch adds the user quirk check to hid_add_device(), and makes hid_add_device() return -ENODEV when HID_QUIRK_IGNORE bit is set. HID_QUIRK_NO_IGNORE still takes precedence over HID_QUIRK_IGNORE. With the patch, iBuddy works properly using libusb when the following option is added to modprobe.d: options usbhid quirks=0x1130:0x0002:0x0004 Signed-off-by: Jindrich Makovicka Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index aa0f7dcabcd7..66abeccdea78 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1760,7 +1760,8 @@ int hid_add_device(struct hid_device *hdev) /* we need to kill them here, otherwise they will stay allocated to * wait for coming driver */ - if (!(hdev->quirks & HID_QUIRK_NO_IGNORE) && hid_ignore(hdev)) + if (!(hdev->quirks & HID_QUIRK_NO_IGNORE) + && (hid_ignore(hdev) || (hdev->quirks & HID_QUIRK_IGNORE))) return -ENODEV; /* XXX hack, any other cleaner solution after the driver core -- cgit v1.2.3 From ef566d30a702cc9b49d24edc4ad45c62208a4f5d Mon Sep 17 00:00:00 2001 From: Chase Douglas Date: Wed, 2 Jun 2010 10:28:25 -0400 Subject: HID: magicmouse: scroll on entire surface, not just middle of mouse Previously, scroll events only occurred when the user moved a touch along the middle of the touch surface. This is unintuitive for a normal user who is not aware of this. The device has a uniform surface, so the distinction is artificial. This change removes the touch area check for a scroll event, which replicates the OS X behavior. Signed-off-by: Chase Douglas Acked-by: Michael Poole Signed-off-by: Jiri Kosina --- drivers/hid/hid-magicmouse.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index f10d56a15f21..cd706354496a 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -160,10 +160,9 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda msc->touches[id].size = misc & 63; /* If requested, emulate a scroll wheel by detecting small - * vertical touch motions along the middle of the mouse. + * vertical touch motions. */ - if (emulate_scroll_wheel && - middle_button_start < x && x < middle_button_stop) { + if (emulate_scroll_wheel) { static const int accel_profile[] = { 256, 228, 192, 160, 128, 96, 64, 32, }; -- cgit v1.2.3 From 9846f350ef4d4108c1154acfc125fe8d8630ef84 Mon Sep 17 00:00:00 2001 From: Chase Douglas Date: Wed, 2 Jun 2010 10:28:27 -0400 Subject: HID: magicmouse: disable and add module param for scroll acceleration Scroll acceleration is unique to the magicmouse driver, and is unintuitive to a user who is unaware of the functionality. Thus, disable it by default, but add a module parameter to enable it for power users who want it. Signed-off-by: Chase Douglas Acked-by: Michael Poole Signed-off-by: Jiri Kosina --- drivers/hid/hid-magicmouse.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index cd706354496a..4c4a79c760a2 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -30,6 +30,10 @@ static bool emulate_scroll_wheel = true; module_param(emulate_scroll_wheel, bool, 0644); MODULE_PARM_DESC(emulate_scroll_wheel, "Emulate a scroll wheel"); +static bool scroll_acceleration = false; +module_param(scroll_acceleration, bool, 0644); +MODULE_PARM_DESC(scroll_acceleration, "Accelerate sequential scroll events"); + static bool report_touches = true; module_param(report_touches, bool, 0644); MODULE_PARM_DESC(report_touches, "Emit touch records (otherwise, only use them for emulation)"); @@ -177,7 +181,9 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda switch (tdata[7] & TOUCH_STATE_MASK) { case TOUCH_STATE_START: msc->touches[id].scroll_y = y; - msc->scroll_accel = min_t(int, msc->scroll_accel + 1, + if (scroll_acceleration) + msc->scroll_accel = min_t(int, + msc->scroll_accel + 1, ARRAY_SIZE(accel_profile) - 1); break; case TOUCH_STATE_DRAG: -- cgit v1.2.3 From 157317ba3ec3e5a4d9683b8d24ba40b4f8f3296b Mon Sep 17 00:00:00 2001 From: Zhao Yakui Date: Wed, 2 Jun 2010 11:04:09 +0800 Subject: ACPI: Fix the incorrect calculation about C-state idle time The C-state idle time is not calculated correctly, which will return the wrong residency time in C-state. It will have the following effects: 1. The system can't choose the deeper C-state when it is idle next time. Of course the system power is increased. E.g. On one server machine about 40W idle power is increased. 2. The powertop shows that it will stay in C0 running state about 95% time although the system is idle at most time. 2.6.35-rc1 regression caused-by: 2da513f582a96c053aacc2c92873978d2ea7abff (ACPI: Minor cleanup eliminating redundant PMTIMER_TICKS to NS conversion) Signed-off-by: Zhao Yakui Reported-by: Yu Zhidong Tested-by: Yu Zhidong Acked-by: Venkatesh Pallipadi Signed-off-by: Len Brown --- drivers/acpi/processor_idle.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 2e8c27d48f2b..6b38a6b43ce8 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -1022,7 +1022,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, spin_unlock(&c3_lock); } kt2 = ktime_get_real(); - idle_time_ns = ktime_to_us(ktime_sub(kt2, kt1)); + idle_time_ns = ktime_to_ns(ktime_sub(kt2, kt1)); idle_time = idle_time_ns; do_div(idle_time, NSEC_PER_USEC); -- cgit v1.2.3 From bceefad59ab66d1b1a815a1738744ea013da966e Mon Sep 17 00:00:00 2001 From: Venkatesh Pallipadi Date: Wed, 2 Jun 2010 10:01:09 -0700 Subject: ACPI: Eliminate us to pm ticks conversion in common path acpi_enter_[simple|bm] routines does us to pm tick conversion on every idle wakeup and the value is only used in /proc/acpi display. We can store the time in us and convert it into pm ticks before printing instead and avoid the conversion in the common path. Signed-off-by: Venkatesh Pallipadi Signed-off-by: Len Brown --- drivers/acpi/processor_idle.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 6b38a6b43ce8..b1b385692f46 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -80,7 +80,7 @@ module_param(nocst, uint, 0000); static unsigned int latency_factor __read_mostly = 2; module_param(latency_factor, uint, 0644); -static s64 us_to_pm_timer_ticks(s64 t) +static u64 us_to_pm_timer_ticks(s64 t) { return div64_u64(t * PM_TIMER_FREQUENCY, 1000000); } @@ -731,10 +731,10 @@ static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset) seq_puts(seq, "demotion[--] "); - seq_printf(seq, "latency[%03d] usage[%08d] duration[%020llu]\n", + seq_printf(seq, "latency[%03d] usage[%08d] duration[%020Lu]\n", pr->power.states[i].latency, pr->power.states[i].usage, - (unsigned long long)pr->power.states[i].time); + us_to_pm_timer_ticks(pr->power.states[i].time)); } end: @@ -861,7 +861,6 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, ktime_t kt1, kt2; s64 idle_time_ns; s64 idle_time; - s64 sleep_ticks = 0; pr = __get_cpu_var(processors); @@ -906,8 +905,6 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, idle_time = idle_time_ns; do_div(idle_time, NSEC_PER_USEC); - sleep_ticks = us_to_pm_timer_ticks(idle_time); - /* Tell the scheduler how much we idled: */ sched_clock_idle_wakeup_event(idle_time_ns); @@ -918,7 +915,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, cx->usage++; lapic_timer_state_broadcast(pr, cx, 0); - cx->time += sleep_ticks; + cx->time += idle_time; return idle_time; } @@ -940,7 +937,6 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, ktime_t kt1, kt2; s64 idle_time_ns; s64 idle_time; - s64 sleep_ticks = 0; pr = __get_cpu_var(processors); @@ -1026,7 +1022,6 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, idle_time = idle_time_ns; do_div(idle_time, NSEC_PER_USEC); - sleep_ticks = us_to_pm_timer_ticks(idle_time); /* Tell the scheduler how much we idled: */ sched_clock_idle_wakeup_event(idle_time_ns); @@ -1037,7 +1032,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, cx->usage++; lapic_timer_state_broadcast(pr, cx, 0); - cx->time += sleep_ticks; + cx->time += idle_time; return idle_time; } -- cgit v1.2.3 From b41709f1263bb1ad37efc43fea0bb0b670c12e78 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 19 May 2010 22:13:17 +0200 Subject: USB: mos7840: fix null-pointer dereference Fix null-pointer dereference on error path. Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/mos7840.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index f8424d1bfc1b..585b7e663740 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -730,7 +730,6 @@ static void mos7840_bulk_in_callback(struct urb *urb) mos7840_port = urb->context; if (!mos7840_port) { dbg("%s", "NULL mos7840_port pointer"); - mos7840_port->read_urb_busy = false; return; } -- cgit v1.2.3 From 0c8a32dff4f9ebed3e067e52e12842d7d7e047a0 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Fri, 21 May 2010 04:37:42 -0400 Subject: USB: isp1362: fix inw warning on Blackfin systems The Blackfin code is incorrectly casting the argument to inw() to a pointer. Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/isp1362.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/isp1362.h b/drivers/usb/host/isp1362.h index 5151516ea1de..d995351f9bed 100644 --- a/drivers/usb/host/isp1362.h +++ b/drivers/usb/host/isp1362.h @@ -65,7 +65,7 @@ static inline void delayed_insw(unsigned int addr, void *buf, int len) unsigned short *bp = (unsigned short *)buf; while (len--) { DUMMY_DELAY_ACCESS; - *bp++ = inw((void *)addr); + *bp++ = inw(addr); } } -- cgit v1.2.3 From 2d62f3eea98354d61f90d6b115eecf9be5f4bdfe Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 24 May 2010 13:25:15 -0700 Subject: USB: xhci: Wait for controller to be ready after reset. After software resets an xHCI host controller, it must wait for the "Controller Not Ready" (CNR) bit in the status register to be cleared. Software is not supposed to ring any doorbells or write to any registers except the status register until this bit is cleared. Signed-off-by: Sarah Sharp Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 40e0a0c221b8..79ccfe5f8ad0 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -116,6 +116,7 @@ int xhci_reset(struct xhci_hcd *xhci) { u32 command; u32 state; + int ret; state = xhci_readl(xhci, &xhci->op_regs->status); if ((state & STS_HALT) == 0) { @@ -130,7 +131,17 @@ int xhci_reset(struct xhci_hcd *xhci) /* XXX: Why does EHCI set this here? Shouldn't other code do this? */ xhci_to_hcd(xhci)->state = HC_STATE_HALT; - return handshake(xhci, &xhci->op_regs->command, CMD_RESET, 0, 250 * 1000); + ret = handshake(xhci, &xhci->op_regs->command, + CMD_RESET, 0, 250 * 1000); + if (ret) + return ret; + + xhci_dbg(xhci, "Wait for controller to be ready for doorbell rings\n"); + /* + * xHCI cannot write to any doorbells or operational registers other + * than status until the "Controller Not Ready" flag is cleared. + */ + return handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000); } -- cgit v1.2.3 From ed07453fd356025cc25272629e982f5e4607632c Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 24 May 2010 13:25:21 -0700 Subject: USB: xhci: Wait for host to start running. When the run bit is set in the xHCI command register, it may take a few microseconds for the host to start running. We cannot ring any doorbells until the host is actually running, so wait until the status register says the host is running. Signed-off-by: Sarah Sharp Reported-by: Shinya Saito Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 79ccfe5f8ad0..8a49c6716b69 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -105,6 +105,33 @@ int xhci_halt(struct xhci_hcd *xhci) STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC); } +/* + * Set the run bit and wait for the host to be running. + */ +int xhci_start(struct xhci_hcd *xhci) +{ + u32 temp; + int ret; + + temp = xhci_readl(xhci, &xhci->op_regs->command); + temp |= (CMD_RUN); + xhci_dbg(xhci, "// Turn on HC, cmd = 0x%x.\n", + temp); + xhci_writel(xhci, temp, &xhci->op_regs->command); + + /* + * Wait for the HCHalted Status bit to be 0 to indicate the host is + * running. + */ + ret = handshake(xhci, &xhci->op_regs->status, + STS_HALT, 0, XHCI_MAX_HALT_USEC); + if (ret == -ETIMEDOUT) + xhci_err(xhci, "Host took too long to start, " + "waited %u microseconds.\n", + XHCI_MAX_HALT_USEC); + return ret; +} + /* * Reset a halted HC, and set the internal HC state to HC_STATE_HALT. * @@ -460,13 +487,11 @@ int xhci_run(struct usb_hcd *hcd) if (NUM_TEST_NOOPS > 0) doorbell = xhci_setup_one_noop(xhci); - temp = xhci_readl(xhci, &xhci->op_regs->command); - temp |= (CMD_RUN); - xhci_dbg(xhci, "// Turn on HC, cmd = 0x%x.\n", - temp); - xhci_writel(xhci, temp, &xhci->op_regs->command); - /* Flush PCI posted writes */ - temp = xhci_readl(xhci, &xhci->op_regs->command); + if (xhci_start(xhci)) { + xhci_halt(xhci); + return -ENODEV; + } + xhci_dbg(xhci, "// @%p = 0x%x\n", &xhci->op_regs->command, temp); if (doorbell) (*doorbell)(xhci); -- cgit v1.2.3 From 0238634d02dd10b678ebe9ea5d8803483277ee93 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 24 May 2010 13:25:28 -0700 Subject: USB: xhci: Print NEC firmware version. The NEC xHCI host controller firmware version can be found by putting a vendor-specific command on the command ring and extracting the BCD encoded-version out of the vendor-specific event TRB. The firmware version debug line in dmesg will look like: xhci_hcd 0000:05:00.0: NEC firmware version 30.21 (NEC merged with Renesas Technologies and became Renesas Electronics on April 1, 2010. I have their OK to merge this vendor-specific code.) Signed-off-by: Sarah Sharp Cc: Satoshi Otani Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-pci.c | 2 ++ drivers/usb/host/xhci-ring.c | 31 ++++++++++++++++++++++++++++++- drivers/usb/host/xhci.c | 5 +++++ drivers/usb/host/xhci.h | 12 ++++++++++++ 4 files changed, 49 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index edffd81fc253..11482b6b9381 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -78,6 +78,8 @@ static int xhci_pci_setup(struct usb_hcd *hcd) xhci_dbg(xhci, "QUIRK: Fresco Logic xHC needs configure" " endpoint cmd after reset endpoint\n"); } + if (pdev->vendor == PCI_VENDOR_ID_NEC) + xhci->quirks |= XHCI_NEC_HOST; /* Make sure the HC is halted. */ retval = xhci_halt(xhci); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 36c858e5b529..9012098add6b 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1071,6 +1071,15 @@ bandwidth_change: xhci_warn(xhci, "Reset device command completion " "for disabled slot %u\n", slot_id); break; + case TRB_TYPE(TRB_NEC_GET_FW): + if (!(xhci->quirks & XHCI_NEC_HOST)) { + xhci->error_bitmask |= 1 << 6; + break; + } + xhci_dbg(xhci, "NEC firmware version %2x.%02x\n", + NEC_FW_MAJOR(event->status), + NEC_FW_MINOR(event->status)); + break; default: /* Skip over unknown commands on the event ring */ xhci->error_bitmask |= 1 << 6; @@ -1079,6 +1088,17 @@ bandwidth_change: inc_deq(xhci, xhci->cmd_ring, false); } +static void handle_vendor_event(struct xhci_hcd *xhci, + union xhci_trb *event) +{ + u32 trb_type; + + trb_type = TRB_FIELD_TO_TYPE(event->generic.field[3]); + xhci_dbg(xhci, "Vendor specific event TRB type = %u\n", trb_type); + if (trb_type == TRB_NEC_CMD_COMP && (xhci->quirks & XHCI_NEC_HOST)) + handle_cmd_completion(xhci, &event->event_cmd); +} + static void handle_port_status(struct xhci_hcd *xhci, union xhci_trb *event) { @@ -1659,7 +1679,10 @@ void xhci_handle_event(struct xhci_hcd *xhci) update_ptrs = 0; break; default: - xhci->error_bitmask |= 1 << 3; + if ((event->event_cmd.flags & TRB_TYPE_BITMASK) >= TRB_TYPE(48)) + handle_vendor_event(xhci, event); + else + xhci->error_bitmask |= 1 << 3; } /* Any of the above functions may drop and re-acquire the lock, so check * to make sure a watchdog timer didn't mark the host as non-responsive. @@ -2378,6 +2401,12 @@ int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, false); } +int xhci_queue_vendor_command(struct xhci_hcd *xhci, + u32 field1, u32 field2, u32 field3, u32 field4) +{ + return queue_command(xhci, field1, field2, field3, field4, false); +} + /* Queue a reset device command TRB */ int xhci_queue_reset_device(struct xhci_hcd *xhci, u32 slot_id) { diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 8a49c6716b69..27345cd04da0 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -486,6 +486,9 @@ int xhci_run(struct usb_hcd *hcd) if (NUM_TEST_NOOPS > 0) doorbell = xhci_setup_one_noop(xhci); + if (xhci->quirks & XHCI_NEC_HOST) + xhci_queue_vendor_command(xhci, 0, 0, 0, + TRB_TYPE(TRB_NEC_GET_FW)); if (xhci_start(xhci)) { xhci_halt(xhci); @@ -495,6 +498,8 @@ int xhci_run(struct usb_hcd *hcd) xhci_dbg(xhci, "// @%p = 0x%x\n", &xhci->op_regs->command, temp); if (doorbell) (*doorbell)(xhci); + if (xhci->quirks & XHCI_NEC_HOST) + xhci_ring_cmd_db(xhci); xhci_dbg(xhci, "Finished xhci_run\n"); return 0; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index dada2fb59261..8b4b7d39f79c 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -925,6 +925,7 @@ union xhci_trb { /* TRB bit mask */ #define TRB_TYPE_BITMASK (0xfc00) #define TRB_TYPE(p) ((p) << 10) +#define TRB_FIELD_TO_TYPE(p) (((p) & TRB_TYPE_BITMASK) >> 10) /* TRB type IDs */ /* bulk, interrupt, isoc scatter/gather, and control data stage */ #define TRB_NORMAL 1 @@ -992,6 +993,14 @@ union xhci_trb { #define TRB_MFINDEX_WRAP 39 /* TRB IDs 40-47 reserved, 48-63 is vendor-defined */ +/* Nec vendor-specific command completion event. */ +#define TRB_NEC_CMD_COMP 48 +/* Get NEC firmware revision. */ +#define TRB_NEC_GET_FW 49 + +#define NEC_FW_MINOR(p) (((p) >> 0) & 0xff) +#define NEC_FW_MAJOR(p) (((p) >> 8) & 0xff) + /* * TRBS_PER_SEGMENT must be a multiple of 4, * since the command ring is 64-byte aligned. @@ -1172,6 +1181,7 @@ struct xhci_hcd { unsigned int quirks; #define XHCI_LINK_TRB_QUIRK (1 << 0) #define XHCI_RESET_EP_QUIRK (1 << 1) +#define XHCI_NEC_HOST (1 << 2) }; /* For testing purposes */ @@ -1379,6 +1389,8 @@ void xhci_set_hc_event_deq(struct xhci_hcd *xhci); int xhci_queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id); int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, u32 slot_id); +int xhci_queue_vendor_command(struct xhci_hcd *xhci, + u32 field1, u32 field2, u32 field3, u32 field4); int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id, unsigned int ep_index); int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, -- cgit v1.2.3 From 390b166138e95a47bdfde6582a1935f65e5c6547 Mon Sep 17 00:00:00 2001 From: Thomas Abraham Date: Mon, 24 May 2010 17:48:56 +0900 Subject: USB: s3c: Enable soft disconnect during initialization Enable soft disconnect bit the OTG core during initialization. Without this, the host sees that a gadget is connected and tries to enumerate. The soft disconnect should be enabled until the USB gadget driver is registered with this otg driver. Signed-off-by: Thomas Abraham Signed-off-by: Kukjin Kim Signed-off-by: Ben Dooks Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/s3c-hsotg.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 1f73b485732d..a6d725dd7335 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -2730,6 +2730,9 @@ static void s3c_hsotg_init(struct s3c_hsotg *hsotg) writel(0, hsotg->regs + S3C_DAINTMSK); + /* Be in disconnected state until gadget is registered */ + __orr32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon); + if (0) { /* post global nak until we're ready */ writel(S3C_DCTL_SGNPInNAK | S3C_DCTL_SGOUTNak, -- cgit v1.2.3 From 0287e43dda1a425da662f879dd27352021b0ca63 Mon Sep 17 00:00:00 2001 From: Maurus Cuelenaere Date: Tue, 25 May 2010 05:36:49 +0100 Subject: USB: s3c_hsotg: define USB_GADGET_DUALSPEED in Kconfig The s3c_hsotg driver sets usb_gadget->is_dualspeed to 1, yet it doesn't define USB_GADGET_DUALSPEED in Kconfig. This triggers a NULL pointer dereference in the composite driver (which is fixed in another patch). Signed-off-by: Maurus Cuelenaere Signed-off-by: Ben Dooks Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 649c0c5f7158..591ae9fde199 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -295,6 +295,7 @@ config USB_GADGET_S3C_HSOTG boolean "S3C HS/OtG USB Device controller" depends on S3C_DEV_USB_HSOTG select USB_GADGET_S3C_HSOTG_PIO + select USB_GADGET_DUALSPEED help The Samsung S3C64XX USB2.0 high-speed gadget controller integrated into the S3C64XX series SoC. -- cgit v1.2.3 From 0f002d200598918f5058dfcfda3da46f29019765 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 25 May 2010 05:36:50 +0100 Subject: USB: s3c-hsotg: Ensure TX FIFO addresses setup when initialising FIFOs Some versions of the S3C HS OtG block startup with overlapping TX FIFO information, so change the fifo_init code to ensure that known values are set into the FIFO registers at initialisation/reset time. This also ensures that the FIFO RAM pointers are in a known state before use. Signed-off-by: Ben Dooks Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/s3c-hsotg.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index a6d725dd7335..9abf96c5715d 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -297,6 +297,11 @@ static void s3c_hsotg_ctrl_epint(struct s3c_hsotg *hsotg, */ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg) { + unsigned int ep; + unsigned int addr; + unsigned int size; + u32 val; + /* the ryu 2.6.24 release ahs writel(0x1C0, hsotg->regs + S3C_GRXFSIZ); writel(S3C_GNPTXFSIZ_NPTxFStAddr(0x200) | @@ -310,6 +315,26 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg) writel(S3C_GNPTXFSIZ_NPTxFStAddr(2048) | S3C_GNPTXFSIZ_NPTxFDep(0x1C0), hsotg->regs + S3C_GNPTXFSIZ); + + /* arange all the rest of the TX FIFOs, as some versions of this + * block have overlapping default addresses. This also ensures + * that if the settings have been changed, then they are set to + * known values. */ + + /* start at the end of the GNPTXFSIZ, rounded up */ + addr = 2048 + 1024; + size = 768; + + /* currently we allocate TX FIFOs for all possible endpoints, + * and assume that they are all the same size. */ + + for (ep = 0; ep <= 15; ep++) { + val = addr; + val |= size << S3C_DPTXFSIZn_DPTxFSize_SHIFT; + addr += size; + + writel(val, hsotg->regs + S3C_DPTXFSIZn(ep)); + } } /** -- cgit v1.2.3 From 2e0e0777ec2ea1cb5461bded2c09573a9d778622 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 25 May 2010 05:36:51 +0100 Subject: USB: s3c-hsotg: SoftDisconnect minimum 3ms The shortest period SoftDisconnect can be asserted for is 3 milliseconds according to the V210 datasheet, so ensure that we add an msleep() to the registration code to enforce this. Signed-off-by: Ben Dooks Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/s3c-hsotg.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 9abf96c5715d..31d19e1f261d 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -2599,6 +2599,9 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) writel(S3C_DCTL_CGOUTNak | S3C_DCTL_CGNPInNAK, hsotg->regs + S3C_DCTL); + /* must be at-least 3ms to allow bus to see disconnect */ + msleep(3); + /* remove the soft-disconnect and let's go */ __bic32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon); -- cgit v1.2.3 From 1703a6d3c38944731ba23594843a704d828266f3 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 25 May 2010 05:36:52 +0100 Subject: USB: s3c-hsotg: Ensure FIFOs are fully flushed after layout According to the design guide, if the FIFO layout is changed, then the FIFOs must be flushed to ensure all FIFO pointers are correct. Signed-off-by: Ben Dooks Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/s3c-hsotg.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 31d19e1f261d..26193eceb323 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -300,6 +300,7 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg) unsigned int ep; unsigned int addr; unsigned int size; + int timeout; u32 val; /* the ryu 2.6.24 release ahs @@ -335,6 +336,31 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg) writel(val, hsotg->regs + S3C_DPTXFSIZn(ep)); } + + /* according to p428 of the design guide, we need to ensure that + * all fifos are flushed before continuing */ + + writel(S3C_GRSTCTL_TxFNum(0x10) | S3C_GRSTCTL_TxFFlsh | + S3C_GRSTCTL_RxFFlsh, hsotg->regs + S3C_GRSTCTL); + + /* wait until the fifos are both flushed */ + timeout = 100; + while (1) { + val = readl(hsotg->regs + S3C_GRSTCTL); + + if ((val & (S3C_GRSTCTL_TxFFlsh | S3C_GRSTCTL_RxFFlsh)) == 0) + break; + + if (--timeout == 0) { + dev_err(hsotg->dev, + "%s: timeout flushing fifos (GRSTCTL=%08x)\n", + __func__, val); + } + + udelay(1); + } + + dev_dbg(hsotg->dev, "FIFOs reset, timeout at %d\n", timeout); } /** -- cgit v1.2.3 From 6a1a82df91fa0eb1cc76069a9efe5714d087eccd Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Thu, 3 Jun 2010 13:55:02 +0200 Subject: USB: ftdi_sio: fix DTR/RTS line modes Call set_mctrl() and clear_mctrl() according to the flow control mode selected. This makes serial communication for FT232 connected devices work when CRTSCTS is not set. This fixes a regression introduced by 4175f3e31 ("tty_port: If we are opened non blocking we still need to raise the carrier"). This patch calls the low-level driver's dtr_rts() function which consequently sets TIOCM_DTR | TIOCM_RTS. A later call to set_termios() without CRTSCTS in cflags, however, does not reset these bits, and so data is not actually sent out on the serial wire. Signed-off-by: Daniel Mack Cc: Johan Hovold Cc: Alan Cox Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 050211afc07e..79dd1ae195e5 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -2005,6 +2005,8 @@ static void ftdi_set_termios(struct tty_struct *tty, "urb failed to set to rts/cts flow control\n"); } + /* raise DTR/RTS */ + set_mctrl(port, TIOCM_DTR | TIOCM_RTS); } else { /* * Xon/Xoff code @@ -2052,6 +2054,8 @@ static void ftdi_set_termios(struct tty_struct *tty, } } + /* lower DTR/RTS */ + clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); } return; } -- cgit v1.2.3 From c2572b78aa0447244a38e555ebb1b3b48a0088a5 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 31 May 2010 08:04:47 +0800 Subject: USB: cdc-acm: fix resource reclaim in error path of acm_probe This patch fixes resource reclaim in error path of acm_probe: 1. In the case of "out of memory (read urbs usb_alloc_urb)\n")", there is no need to call acm_read_buffers_free(acm) here. Fix it by goto alloc_fail6 instead of alloc_fail7. 2. In the case of "out of memory (write urbs usb_alloc_urb)", usb_alloc_urb may fail in any iteration of the for loop. Current implementation does not properly free allocated snd->urb. Fix it by goto alloc_fail8 instead of alloc_fail7. 3. In the case of device_create_file(&intf->dev,&dev_attr_iCountryCodeRelDate) fail, acm->country_codes is kfreed. As a result, device_remove_file for dev_attr_wCountryCodes will not be executed in acm_disconnect. Fix it by calling device_remove_file for dev_attr_wCountryCodes before goto skip_countries. Signed-off-by: Axel Lin Acked-by: Oliver Neukum Cc: stable Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 0c2f14ff9696..61d75507d5d0 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1201,7 +1201,7 @@ made_compressed_probe: if (rcv->urb == NULL) { dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)\n"); - goto alloc_fail7; + goto alloc_fail6; } rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; @@ -1225,7 +1225,7 @@ made_compressed_probe: if (snd->urb == NULL) { dev_dbg(&intf->dev, "out of memory (write urbs usb_alloc_urb)"); - goto alloc_fail7; + goto alloc_fail8; } if (usb_endpoint_xfer_int(epwrite)) @@ -1264,6 +1264,7 @@ made_compressed_probe: i = device_create_file(&intf->dev, &dev_attr_iCountryCodeRelDate); if (i < 0) { + device_remove_file(&intf->dev, &dev_attr_wCountryCodes); kfree(acm->country_codes); goto skip_countries; } @@ -1300,6 +1301,7 @@ alloc_fail8: usb_free_urb(acm->wb[i].urb); alloc_fail7: acm_read_buffers_free(acm); +alloc_fail6: for (i = 0; i < num_rx_buf; i++) usb_free_urb(acm->ru[i].urb); usb_free_urb(acm->ctrlurb); -- cgit v1.2.3 From 1f23b2d98c11fed43c552a5dbd00c793f81a8736 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Wed, 2 Jun 2010 13:53:17 -0600 Subject: usb: fix ehci_hcd build failure when both generic-OF and xilinx is selected This patch fixes the driver to allow both CONFIG_USB_EHCI_HCD_PPC_OF and CONFIG_USB_ECHI_HCD_XILINX to be selected. Signed-off-by: Grant Likely CC: John Linn CC: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-hcd.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index ef3e88f0b3c3..a3ef2a9d9dc2 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1135,7 +1135,7 @@ MODULE_LICENSE ("GPL"); #ifdef CONFIG_XPS_USB_HCD_XILINX #include "ehci-xilinx-of.c" -#define OF_PLATFORM_DRIVER ehci_hcd_xilinx_of_driver +#define XILINX_OF_PLATFORM_DRIVER ehci_hcd_xilinx_of_driver #endif #ifdef CONFIG_PLAT_ORION @@ -1159,7 +1159,8 @@ MODULE_LICENSE ("GPL"); #endif #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ - !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) + !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \ + !defined(XILINX_OF_PLATFORM_DRIVER) #error "missing bus glue for ehci-hcd" #endif @@ -1213,10 +1214,20 @@ static int __init ehci_hcd_init(void) if (retval < 0) goto clean3; #endif + +#ifdef XILINX_OF_PLATFORM_DRIVER + retval = of_register_platform_driver(&XILINX_OF_PLATFORM_DRIVER); + if (retval < 0) + goto clean4; +#endif return retval; +#ifdef XILINX_OF_PLATFORM_DRIVER + /* of_unregister_platform_driver(&XILINX_OF_PLATFORM_DRIVER); */ +clean4: +#endif #ifdef OF_PLATFORM_DRIVER - /* of_unregister_platform_driver(&OF_PLATFORM_DRIVER); */ + of_unregister_platform_driver(&OF_PLATFORM_DRIVER); clean3: #endif #ifdef PS3_SYSTEM_BUS_DRIVER @@ -1243,6 +1254,9 @@ module_init(ehci_hcd_init); static void __exit ehci_hcd_cleanup(void) { +#ifdef XILINX_OF_PLATFORM_DRIVER + of_unregister_platform_driver(&XILINX_OF_PLATFORM_DRIVER); +#endif #ifdef OF_PLATFORM_DRIVER of_unregister_platform_driver(&OF_PLATFORM_DRIVER); #endif -- cgit v1.2.3 From 109f34e71b9049a57f6cdf3f1da6bee2b722b259 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 27 May 2010 14:32:09 +0200 Subject: USB: serial: digi_acceleport: Eliminate a NULL pointer dereference If port is NULL, then the call to dev_err will dereference a value that is a small offset from NULL. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r exists@ expression E,E1; identifier f; statement S1,S2,S3; @@ if ((E == NULL && ...) || ...) { ... when != if (...) S1 else S2 when != E = E1 * E->f ... when any return ...; } else S3 // Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/digi_acceleport.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 3edda3ed822a..fd35f73b5721 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -1239,8 +1239,7 @@ static void digi_write_bulk_callback(struct urb *urb) /* port and serial sanity check */ if (port == NULL || (priv = usb_get_serial_port_data(port)) == NULL) { - dev_err(&port->dev, - "%s: port or port->private is NULL, status=%d\n", + pr_err("%s: port or port->private is NULL, status=%d\n", __func__, status); return; } -- cgit v1.2.3 From c043f1245654a726925529007210e9f786426448 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 4 Jun 2010 14:02:42 -0400 Subject: USB: unbind all interfaces before rebinding them MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch (as1387) fixes a bug introduced during the changeover to the runtime PM framework. When a driver doesn't support resume or reset-resume, and consequently its interfaces need to be unbound and rebound, we have to unbind all the interfaces before trying to rebind any of them. Otherwise the driver's probe method for one interface could try to claim a different interface and fail, because that other interface hasn't been unbound yet. This fixes Bugzilla #15788. The symptom is that some USB sound cards don't work after hibernation. Signed-off-by: Alan Stern Tested-by: François Valenduc Cc: stable [.34] Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index ded550eda5d9..de98a94d1853 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1328,6 +1328,7 @@ int usb_resume(struct device *dev, pm_message_t msg) /* For all other calls, take the device back to full power and * tell the PM core in case it was autosuspended previously. + * Unbind the interfaces that will need rebinding later. */ } else { status = usb_resume_both(udev, msg); @@ -1336,6 +1337,7 @@ int usb_resume(struct device *dev, pm_message_t msg) pm_runtime_set_active(dev); pm_runtime_enable(dev); udev->last_busy = jiffies; + do_unbind_rebind(udev, DO_REBIND); } } -- cgit v1.2.3 From 18c79d76ece432a48c985ea404800f8ee154ada2 Mon Sep 17 00:00:00 2001 From: Abhijeet Dharmapurikar Date: Thu, 20 May 2010 15:20:23 -0700 Subject: msm_serial: fix serial on trout Set the mnd counter based on uartclk. This fixes a problem on 7x30 where the uartclk is 19.2Mhz rather than the usual 4.8Mhz. Trout incorrectly reports uartclk to be running at 19.2Mhz It is actually running at 4.8Mhz. For trout force mnd counter values as if uartclk was fed by tcxo/4. Signed-off-by: Abhijeet Dharmapurikar [dwalker@codeaurora.org: inlined, moved into header, added comments.] Signed-off-by: Daniel Walker Signed-off-by: Greg Kroah-Hartman --- drivers/serial/msm_serial.c | 21 +++-------------- drivers/serial/msm_serial.h | 56 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/msm_serial.c b/drivers/serial/msm_serial.c index ecdc0facf7ee..f8c816e7725d 100644 --- a/drivers/serial/msm_serial.c +++ b/drivers/serial/msm_serial.c @@ -41,19 +41,6 @@ struct msm_port { unsigned int imr; }; -#define UART_TO_MSM(uart_port) ((struct msm_port *) uart_port) - -static inline void msm_write(struct uart_port *port, unsigned int val, - unsigned int off) -{ - __raw_writel(val, port->membase + off); -} - -static inline unsigned int msm_read(struct uart_port *port, unsigned int off) -{ - return __raw_readl(port->membase + off); -} - static void msm_stop_tx(struct uart_port *port) { struct msm_port *msm_port = UART_TO_MSM(port); @@ -320,11 +307,7 @@ static void msm_init_clock(struct uart_port *port) struct msm_port *msm_port = UART_TO_MSM(port); clk_enable(msm_port->clk); - - msm_write(port, 0xC0, UART_MREG); - msm_write(port, 0xB2, UART_NREG); - msm_write(port, 0x7D, UART_DREG); - msm_write(port, 0x1C, UART_MNDREG); + msm_serial_set_mnd_regs(port); } static int msm_startup(struct uart_port *port) @@ -706,6 +689,8 @@ static int __init msm_serial_probe(struct platform_device *pdev) if (unlikely(IS_ERR(msm_port->clk))) return PTR_ERR(msm_port->clk); port->uartclk = clk_get_rate(msm_port->clk); + printk(KERN_INFO "uartclk = %d\n", port->uartclk); + resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (unlikely(!resource)) diff --git a/drivers/serial/msm_serial.h b/drivers/serial/msm_serial.h index 689f1fa0e84e..f6ca9ca79e98 100644 --- a/drivers/serial/msm_serial.h +++ b/drivers/serial/msm_serial.h @@ -114,4 +114,60 @@ #define UART_MISR 0x0010 #define UART_ISR 0x0014 +#define UART_TO_MSM(uart_port) ((struct msm_port *) uart_port) + +static inline +void msm_write(struct uart_port *port, unsigned int val, unsigned int off) +{ + __raw_writel(val, port->membase + off); +} + +static inline +unsigned int msm_read(struct uart_port *port, unsigned int off) +{ + return __raw_readl(port->membase + off); +} + +/* + * Setup the MND registers to use the TCXO clock. + */ +static inline void msm_serial_set_mnd_regs_tcxo(struct uart_port *port) +{ + msm_write(port, 0x06, UART_MREG); + msm_write(port, 0xF1, UART_NREG); + msm_write(port, 0x0F, UART_DREG); + msm_write(port, 0x1A, UART_MNDREG); +} + +/* + * Setup the MND registers to use the TCXO clock divided by 4. + */ +static inline void msm_serial_set_mnd_regs_tcxoby4(struct uart_port *port) +{ + msm_write(port, 0x18, UART_MREG); + msm_write(port, 0xF6, UART_NREG); + msm_write(port, 0x0F, UART_DREG); + msm_write(port, 0x0A, UART_MNDREG); +} + +static inline +void msm_serial_set_mnd_regs_from_uartclk(struct uart_port *port) +{ + if (port->uartclk == 19200000) + msm_serial_set_mnd_regs_tcxo(port); + else + msm_serial_set_mnd_regs_tcxoby4(port); +} + +/* + * TROUT has a specific defect that makes it report it's uartclk + * as 19.2Mhz (TCXO) when it's actually 4.8Mhz (TCXO/4). This special + * cases TROUT to use the right clock. + */ +#ifdef CONFIG_MACH_TROUT +#define msm_serial_set_mnd_regs msm_serial_set_mnd_regs_tcxoby4 +#else +#define msm_serial_set_mnd_regs msm_serial_set_mnd_regs_from_uartclk +#endif + #endif /* __DRIVERS_SERIAL_MSM_SERIAL_H */ -- cgit v1.2.3 From 99ec88f345945208c650b54279dddc8dfd705571 Mon Sep 17 00:00:00 2001 From: Alexander Kurz Date: Thu, 20 May 2010 00:40:08 +0400 Subject: serial_cs: add and sort IDs for serial and modem cards Signed-off-by: Alexander Kurz Signed-off-by: Greg Kroah-Hartman --- drivers/serial/serial_cs.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index dadd686c9801..526307368f8b 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -715,6 +715,8 @@ static struct pcmcia_device_id serial_ids[] = { PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0057, 0x0021), PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0089, 0x110a), PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0104, 0x000a), + PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0d0a), + PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0e0a), PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0xea15), PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0109, 0x0501), PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0138, 0x110a), @@ -724,8 +726,6 @@ static struct pcmcia_device_id serial_ids[] = { PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x016c, 0x0081), PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x021b, 0x0101), PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x08a1, 0xc0ab), - PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0d0a), - PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0e0a), PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63), PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3336", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x0143b773, 0x46a52d63), PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "EM1144T", "PCMCIA MODEM", 0xf510db04, 0x856d66c8, 0xbd6c43ef), @@ -768,17 +768,26 @@ static struct pcmcia_device_id serial_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x0276), PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0039), PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0006), + PCMCIA_DEVICE_MANF_CARD(0x0105, 0x0101), /* TDK DF2814 */ + PCMCIA_DEVICE_MANF_CARD(0x0105, 0x100a), /* Xircom CM-56G */ + PCMCIA_DEVICE_MANF_CARD(0x0105, 0x3e0a), /* TDK DF5660 */ PCMCIA_DEVICE_MANF_CARD(0x0105, 0x410a), + PCMCIA_DEVICE_MANF_CARD(0x0107, 0x0002), /* USRobotics 14,400 */ PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d50), PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d51), PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d52), PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d53), PCMCIA_DEVICE_MANF_CARD(0x010b, 0xd180), + PCMCIA_DEVICE_MANF_CARD(0x0115, 0x3330), /* USRobotics/SUN 14,400 */ + PCMCIA_DEVICE_MANF_CARD(0x0124, 0x0100), /* Nokia DTP-2 ver II */ + PCMCIA_DEVICE_MANF_CARD(0x0134, 0x5600), /* LASAT COMMUNICATIONS A/S */ PCMCIA_DEVICE_MANF_CARD(0x0137, 0x000e), PCMCIA_DEVICE_MANF_CARD(0x0137, 0x001b), PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0025), PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0045), PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0052), + PCMCIA_DEVICE_MANF_CARD(0x016c, 0x0006), /* Psion 56K+Fax */ + PCMCIA_DEVICE_MANF_CARD(0x0200, 0x0001), /* MultiMobile */ PCMCIA_DEVICE_PROD_ID134("ADV", "TECH", "COMpad-32/85", 0x67459937, 0x916d02ba, 0x8fbe92ae), PCMCIA_DEVICE_PROD_ID124("GATEWAY2000", "CC3144", "PCMCIA MODEM", 0x506bccae, 0xcb3685f1, 0xbd6c43ef), PCMCIA_DEVICE_PROD_ID14("MEGAHERTZ", "PCMCIA MODEM", 0xf510db04, 0xbd6c43ef), @@ -792,16 +801,21 @@ static struct pcmcia_device_id serial_ids[] = { PCMCIA_DEVICE_PROD_ID12("COMPAQ", "PCMCIA 33600 FAX/DATA MODEM", 0xa3a3062c, 0x5a00ce95), PCMCIA_DEVICE_PROD_ID12("Computerboards, Inc.", "PCM-COM422", 0xd0b78f51, 0x7e2d49ed), PCMCIA_DEVICE_PROD_ID12("Dr. Neuhaus", "FURY CARD 14K4", 0x76942813, 0x8b96ce65), + PCMCIA_DEVICE_PROD_ID12("IBM", "ISDN/56K/GSM", 0xb569a6e5, 0xfee5297b), PCMCIA_DEVICE_PROD_ID12("Intelligent", "ANGIA FAX/MODEM", 0xb496e65e, 0xf31602a6), PCMCIA_DEVICE_PROD_ID12("Intel", "MODEM 2400+", 0x816cc815, 0x412729fb), + PCMCIA_DEVICE_PROD_ID12("Intertex", "IX34-PCMCIA", 0xf8a097e3, 0x97880447), PCMCIA_DEVICE_PROD_ID12("IOTech Inc ", "PCMCIA Dual RS-232 Serial Port Card", 0x3bd2d898, 0x92abc92f), PCMCIA_DEVICE_PROD_ID12("MACRONIX", "FAX/MODEM", 0x668388b3, 0x3f9bdf2f), PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT1432LT", 0x5f73be51, 0x0b3e2383), PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT2834LT", 0x5f73be51, 0x4cd7c09e), PCMCIA_DEVICE_PROD_ID12("OEM ", "C288MX ", 0xb572d360, 0xd2385b7a), + PCMCIA_DEVICE_PROD_ID12("Option International", "V34bis GSM/PSTN Data/Fax Modem", 0x9d7cd6f5, 0x5cb8bf41), PCMCIA_DEVICE_PROD_ID12("PCMCIA ", "C336MX ", 0x99bcafe9, 0xaa25bcab), PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "PCMCIA Dual RS-232 Serial Port Card", 0xc4420b35, 0x92abc92f), PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "Dual RS-232 Serial Port PC Card", 0xc4420b35, 0x031a380d), + PCMCIA_DEVICE_PROD_ID12("Telia", "SurfinBird 560P/A+", 0xe2cdd5e, 0xc9314b38), + PCMCIA_DEVICE_PROD_ID1("Smart Serial Port", 0x2d8ce292), PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "EN2218-LAN/MODEM", 0x281f1c5d, 0x570f348e, "cis/PCMLM28.cis"), PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "UE2218-LAN/MODEM", 0x281f1c5d, 0x6fdcacee, "cis/PCMLM28.cis"), PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet", 0xf5f025c2, 0x338e8155, "cis/PCMLM28.cis"), -- cgit v1.2.3 From ca3e442e8dbbe2551473f36f0e7797b1d3205f5a Mon Sep 17 00:00:00 2001 From: Graf Yang Date: Sun, 23 May 2010 04:40:13 -0400 Subject: serial: bfin_5xx: IRDA is not affected by anomaly 05000230 Anomaly 05000230 (over sampling of the UART STOP bit) applies only when the peripheral is operating in UART mode. So drop the anomaly handling when the UART is in IRDA mode. Signed-off-by: Graf Yang Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/serial/bfin_5xx.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index 96f7e7484fee..a78652b21e40 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -869,7 +869,12 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, } baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); - quot = uart_get_divisor(port, baud) - ANOMALY_05000230; + quot = uart_get_divisor(port, baud); + + /* If discipline is not IRDA, apply ANOMALY_05000230 */ + if (termios->c_line != N_IRDA) + quot -= ANOMALY_05000230; + spin_lock_irqsave(&uart->port.lock, flags); UART_SET_ANOMALY_THRESHOLD(uart, USEC_PER_SEC / baud * 15); -- cgit v1.2.3 From e59e2bd9e85604ad601ec7dd056baffcd6ad56a0 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Sun, 23 May 2010 04:40:14 -0400 Subject: serial: bfin_5xx: fix typo in IER check This most likely won't cause problems on systems as people don't typically enable GPIO RTS/CTS if they don't actually use it. Signed-off-by: Sonic Zhang Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/serial/bfin_5xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index a78652b21e40..511cbf687877 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -797,7 +797,7 @@ static void bfin_serial_shutdown(struct uart_port *port) gpio_free(uart->rts_pin); #endif #ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS - if (UART_GET_IER(uart) && EDSSI) + if (UART_GET_IER(uart) & EDSSI) free_irq(uart->status_irq, uart); #endif } -- cgit v1.2.3 From 328be395a396b1333b56e04571365dc614c96e46 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 25 May 2010 11:37:17 +0200 Subject: TTY/n_gsm: potential double lock In gsm_dlci_data_kick() we call gsm_dlci_data_sweep() with the "gsm->tx_lock" held so we can't lock it again inside gsm_dlci_data_sweep(). I removed that lock from and added one to gsmld_write_wakeup() instead. The sweep function is only called from those two places. Signed-off-by: Dan Carpenter Acked-by: Alan Cox Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/char/n_gsm.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/char/n_gsm.c b/drivers/char/n_gsm.c index c4161d5e053d..e4089c432f15 100644 --- a/drivers/char/n_gsm.c +++ b/drivers/char/n_gsm.c @@ -904,9 +904,7 @@ static void gsm_dlci_data_sweep(struct gsm_mux *gsm) int len; /* Priority ordering: We should do priority with RR of the groups */ int i = 1; - unsigned long flags; - spin_lock_irqsave(&gsm->tx_lock, flags); while (i < NUM_DLCI) { struct gsm_dlci *dlci; @@ -927,7 +925,6 @@ static void gsm_dlci_data_sweep(struct gsm_mux *gsm) if (len == 0) i++; } - spin_unlock_irqrestore(&gsm->tx_lock, flags); } /** @@ -2230,12 +2227,16 @@ static int gsmld_open(struct tty_struct *tty) static void gsmld_write_wakeup(struct tty_struct *tty) { struct gsm_mux *gsm = tty->disc_data; + unsigned long flags; /* Queue poll */ clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); gsm_data_kick(gsm); - if (gsm->tx_bytes < TX_THRESH_LO) + if (gsm->tx_bytes < TX_THRESH_LO) { + spin_lock_irqsave(&gsm->tx_lock, flags); gsm_dlci_data_sweep(gsm); + spin_unlock_irqrestore(&gsm->tx_lock, flags); + } } /** -- cgit v1.2.3 From d8d721f4c005f9a69bd1b5d5c6ba99b7e1d464de Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Tue, 25 May 2010 16:59:55 +0200 Subject: altera_uart: Don't take spinlock in already protected functions Don't take the port spinlock in uart functions where the serial core already takes care of locking/unlocking them. The code would actually lock up on architectures where spinlocks are implemented (not the case on nios2 where this driver is primarily used for now, thus this bug didn't trigger). Also protect calling altera_uart_rx_chars/altera_uart_tx_chars in the interrupt handler by the port spinlock. Thanks to Ian Abbott for pointing these issues out. Cc: Ian Abbott Cc: Thomas Chou Signed-off-by: Tobias Klauser Signed-off-by: Greg Kroah-Hartman --- drivers/serial/altera_uart.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/altera_uart.c b/drivers/serial/altera_uart.c index bcee156d2f2e..b1609cca0ec4 100644 --- a/drivers/serial/altera_uart.c +++ b/drivers/serial/altera_uart.c @@ -89,15 +89,12 @@ static unsigned int altera_uart_tx_empty(struct uart_port *port) static unsigned int altera_uart_get_mctrl(struct uart_port *port) { struct altera_uart *pp = container_of(port, struct altera_uart, port); - unsigned long flags; unsigned int sigs; - spin_lock_irqsave(&port->lock, flags); sigs = (readl(port->membase + ALTERA_UART_STATUS_REG) & ALTERA_UART_STATUS_CTS_MSK) ? TIOCM_CTS : 0; sigs |= (pp->sigs & TIOCM_RTS); - spin_unlock_irqrestore(&port->lock, flags); return sigs; } @@ -105,49 +102,37 @@ static unsigned int altera_uart_get_mctrl(struct uart_port *port) static void altera_uart_set_mctrl(struct uart_port *port, unsigned int sigs) { struct altera_uart *pp = container_of(port, struct altera_uart, port); - unsigned long flags; - spin_lock_irqsave(&port->lock, flags); pp->sigs = sigs; if (sigs & TIOCM_RTS) pp->imr |= ALTERA_UART_CONTROL_RTS_MSK; else pp->imr &= ~ALTERA_UART_CONTROL_RTS_MSK; writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); - spin_unlock_irqrestore(&port->lock, flags); } static void altera_uart_start_tx(struct uart_port *port) { struct altera_uart *pp = container_of(port, struct altera_uart, port); - unsigned long flags; - spin_lock_irqsave(&port->lock, flags); pp->imr |= ALTERA_UART_CONTROL_TRDY_MSK; writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); - spin_unlock_irqrestore(&port->lock, flags); } static void altera_uart_stop_tx(struct uart_port *port) { struct altera_uart *pp = container_of(port, struct altera_uart, port); - unsigned long flags; - spin_lock_irqsave(&port->lock, flags); pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK; writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); - spin_unlock_irqrestore(&port->lock, flags); } static void altera_uart_stop_rx(struct uart_port *port) { struct altera_uart *pp = container_of(port, struct altera_uart, port); - unsigned long flags; - spin_lock_irqsave(&port->lock, flags); pp->imr &= ~ALTERA_UART_CONTROL_RRDY_MSK; writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); - spin_unlock_irqrestore(&port->lock, flags); } static void altera_uart_break_ctl(struct uart_port *port, int break_state) @@ -272,10 +257,14 @@ static irqreturn_t altera_uart_interrupt(int irq, void *data) unsigned int isr; isr = readl(port->membase + ALTERA_UART_STATUS_REG) & pp->imr; + + spin_lock(&port->lock); if (isr & ALTERA_UART_STATUS_RRDY_MSK) altera_uart_rx_chars(pp); if (isr & ALTERA_UART_STATUS_TRDY_MSK) altera_uart_tx_chars(pp); + spin_unlock(&port->lock); + return IRQ_RETVAL(isr); } -- cgit v1.2.3 From fadf34f0f05ca5ea02ffcd89544cd372bbdb739b Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Tue, 25 May 2010 17:00:08 +0200 Subject: altera_uart: Simplify altera_uart_console_putc The check for the TRDY flag after writing the character is not needed. Also do a cpu_relax() inside the loop. Pass a struct uart_port to altera_uart_console_putc, so we do not need to get it (and dereference pointers) for every character. Cc: Thomas Chou Signed-off-by: Tobias Klauser Signed-off-by: Greg Kroah-Hartman --- drivers/serial/altera_uart.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/altera_uart.c b/drivers/serial/altera_uart.c index b1609cca0ec4..7d6afc9755d5 100644 --- a/drivers/serial/altera_uart.c +++ b/drivers/serial/altera_uart.c @@ -391,31 +391,24 @@ int __init early_altera_uart_setup(struct altera_uart_platform_uart *platp) return 0; } -static void altera_uart_console_putc(struct console *co, const char c) +static void altera_uart_console_putc(struct uart_port *port, const char c) { - struct uart_port *port = &(altera_uart_ports + co->index)->port; - int i; + while (!(readl(port->membase + ALTERA_UART_STATUS_REG) & + ALTERA_UART_STATUS_TRDY_MSK)) + cpu_relax(); - for (i = 0; i < 0x10000; i++) { - if (readl(port->membase + ALTERA_UART_STATUS_REG) & - ALTERA_UART_STATUS_TRDY_MSK) - break; - } writel(c, port->membase + ALTERA_UART_TXDATA_REG); - for (i = 0; i < 0x10000; i++) { - if (readl(port->membase + ALTERA_UART_STATUS_REG) & - ALTERA_UART_STATUS_TRDY_MSK) - break; - } } static void altera_uart_console_write(struct console *co, const char *s, unsigned int count) { + struct uart_port *port = &(altera_uart_ports + co->index)->port; + for (; count; count--, s++) { - altera_uart_console_putc(co, *s); + altera_uart_console_putc(port, *s); if (*s == '\n') - altera_uart_console_putc(co, '\r'); + altera_uart_console_putc(port, '\r'); } } -- cgit v1.2.3 From 962400e8fd29981a7b166e463dd143b6ac6a3e76 Mon Sep 17 00:00:00 2001 From: Frank Pan Date: Wed, 26 May 2010 15:37:43 +0800 Subject: tty: fix a little bug in scrup, vt.c The code uses vc->vc_cols instead of vc->vc_size_row by mistake, it will cause half of the region which is going to clear remain uncleared. The issue happens in background consoles, so it's hard to observe. Frank Pan Signed-off-by: Frank Pan Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/char/vt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 7cdb6ee569cd..1296c42ed5c6 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -304,7 +304,7 @@ static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr) d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t); s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr)); scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row); - scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char, + scr_memsetw(d + (b - t - nr) * vc->vc_size_row, vc->vc_video_erase_char, vc->vc_size_row * nr); } -- cgit v1.2.3 From c1bfffa94e0ca951ed450788991c9310adb8e823 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 31 May 2010 15:01:08 +0200 Subject: serial: altera_uart: Proper section for altera_uart_remove altera_uart_remove should be in .devexit.text Signed-off-by: Tobias Klauser Signed-off-by: Greg Kroah-Hartman --- drivers/serial/altera_uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/serial/altera_uart.c b/drivers/serial/altera_uart.c index 7d6afc9755d5..0f1189605d21 100644 --- a/drivers/serial/altera_uart.c +++ b/drivers/serial/altera_uart.c @@ -498,7 +498,7 @@ static int __devinit altera_uart_probe(struct platform_device *pdev) return 0; } -static int altera_uart_remove(struct platform_device *pdev) +static int __devexit altera_uart_remove(struct platform_device *pdev) { struct uart_port *port; int i; -- cgit v1.2.3 From 3fde85df5421eb01f563fef6f111ba73ab0d120e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 4 Jun 2010 12:20:46 +0200 Subject: vt_ioctl: return -EFAULT on copy_from_user errors copy_from_user() returns the number of bytes remaining but we want to return a negative error code here. Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/char/vt_ioctl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index 6aa10284104a..cb19dbc52136 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -1303,7 +1303,9 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, if (!perm) goto eperm; ret = copy_from_user(&ui, up, sizeof(struct unimapinit)); - if (!ret) + if (ret) + ret = -EFAULT; + else con_clear_unimap(vc, &ui); break; } -- cgit v1.2.3 From 66169ad17d9c67a33608830dd83dcef55c85a756 Mon Sep 17 00:00:00 2001 From: Yegor Yefremov Date: Fri, 4 Jun 2010 09:58:18 +0200 Subject: serial: add support for various Titan PCI cards serial: add support for various Titan PCI cards Models: 200I, 400I, 800I, 400EH, 800EH, 800EHB, 100E, 200E, 400E, 800E, 200EI, 200EISI Signed-off-by: Yegor Yefremov Signed-off-by: Greg Kroah-Hartman --- drivers/serial/8250_pci.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) (limited to 'drivers') diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c index 01c012da4e26..746a44621d91 100644 --- a/drivers/serial/8250_pci.c +++ b/drivers/serial/8250_pci.c @@ -982,6 +982,18 @@ static int skip_tx_en_setup(struct serial_private *priv, #define PCI_SUBDEVICE_ID_POCTAL422 0x0408 #define PCI_VENDOR_ID_ADVANTECH 0x13fe #define PCI_DEVICE_ID_ADVANTECH_PCI3620 0x3620 +#define PCI_DEVICE_ID_TITAN_200I 0x8028 +#define PCI_DEVICE_ID_TITAN_400I 0x8048 +#define PCI_DEVICE_ID_TITAN_800I 0x8088 +#define PCI_DEVICE_ID_TITAN_800EH 0xA007 +#define PCI_DEVICE_ID_TITAN_800EHB 0xA008 +#define PCI_DEVICE_ID_TITAN_400EH 0xA009 +#define PCI_DEVICE_ID_TITAN_100E 0xA010 +#define PCI_DEVICE_ID_TITAN_200E 0xA012 +#define PCI_DEVICE_ID_TITAN_400E 0xA013 +#define PCI_DEVICE_ID_TITAN_800E 0xA014 +#define PCI_DEVICE_ID_TITAN_200EI 0xA016 +#define PCI_DEVICE_ID_TITAN_200EISI 0xA017 /* Unknown vendors/cards - this should not be in linux/pci_ids.h */ #define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584 @@ -1541,6 +1553,10 @@ enum pci_board_num_t { pbn_b3_4_115200, pbn_b3_8_115200, + pbn_b4_bt_2_921600, + pbn_b4_bt_4_921600, + pbn_b4_bt_8_921600, + /* * Board-specific versions. */ @@ -1995,6 +2011,25 @@ static struct pciserial_board pci_boards[] __devinitdata = { .uart_offset = 8, }, + [pbn_b4_bt_2_921600] = { + .flags = FL_BASE4, + .num_ports = 2, + .base_baud = 921600, + .uart_offset = 8, + }, + [pbn_b4_bt_4_921600] = { + .flags = FL_BASE4, + .num_ports = 4, + .base_baud = 921600, + .uart_offset = 8, + }, + [pbn_b4_bt_8_921600] = { + .flags = FL_BASE4, + .num_ports = 8, + .base_baud = 921600, + .uart_offset = 8, + }, + /* * Entries following this are board-specific. */ @@ -3043,6 +3078,42 @@ static struct pci_device_id serial_pci_tbl[] = { { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800L, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_bt_8_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200I, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b4_bt_2_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400I, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b4_bt_4_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800I, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b4_bt_8_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400EH, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_4_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800EH, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_4_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800EHB, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_4_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100E, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200E, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_2_4000000 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400E, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_4_4000000 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800E, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_8_4000000 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EI, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_2_4000000 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EISI, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_2_4000000 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, -- cgit v1.2.3 From d7636e0b0769e0f4f437ff33168d723f86e7c080 Mon Sep 17 00:00:00 2001 From: "apatard@mandriva.com" Date: Wed, 19 May 2010 10:44:14 +0200 Subject: staging: Add framebuffer driver for XGI chipsets This driver handles XG20, XG21, XG40, XG42 chipsets from XGI. They're also known as Z7,Z9,Z11 chipsets. It's based on the SiS fb driver but has been heavily modified by XGI to support their newer chipsets. Signed-off-by: Arnaud Patard Signed-off-by: Greg Kroah-Hartman --- drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/xgifb/Kconfig | 11 + drivers/staging/xgifb/Makefile | 4 + drivers/staging/xgifb/TODO | 15 + drivers/staging/xgifb/XGI.h | 10 + drivers/staging/xgifb/XGI_accel.c | 596 ++ drivers/staging/xgifb/XGI_accel.h | 511 ++ drivers/staging/xgifb/XGI_main.h | 1023 ++++ drivers/staging/xgifb/XGI_main_26.c | 3773 ++++++++++++ drivers/staging/xgifb/XGIfb.h | 215 + drivers/staging/xgifb/osdef.h | 153 + drivers/staging/xgifb/vb_def.h | 1017 ++++ drivers/staging/xgifb/vb_ext.c | 1370 +++++ drivers/staging/xgifb/vb_ext.h | 32 + drivers/staging/xgifb/vb_init.c | 3444 +++++++++++ drivers/staging/xgifb/vb_init.h | 7 + drivers/staging/xgifb/vb_setmode.c | 10736 ++++++++++++++++++++++++++++++++++ drivers/staging/xgifb/vb_setmode.h | 40 + drivers/staging/xgifb/vb_struct.h | 534 ++ drivers/staging/xgifb/vb_table.h | 4406 ++++++++++++++ drivers/staging/xgifb/vb_util.c | 263 + drivers/staging/xgifb/vb_util.h | 15 + drivers/staging/xgifb/vgatypes.h | 325 + 24 files changed, 28503 insertions(+) create mode 100644 drivers/staging/xgifb/Kconfig create mode 100644 drivers/staging/xgifb/Makefile create mode 100644 drivers/staging/xgifb/TODO create mode 100644 drivers/staging/xgifb/XGI.h create mode 100644 drivers/staging/xgifb/XGI_accel.c create mode 100644 drivers/staging/xgifb/XGI_accel.h create mode 100644 drivers/staging/xgifb/XGI_main.h create mode 100644 drivers/staging/xgifb/XGI_main_26.c create mode 100644 drivers/staging/xgifb/XGIfb.h create mode 100644 drivers/staging/xgifb/osdef.h create mode 100644 drivers/staging/xgifb/vb_def.h create mode 100644 drivers/staging/xgifb/vb_ext.c create mode 100644 drivers/staging/xgifb/vb_ext.h create mode 100644 drivers/staging/xgifb/vb_init.c create mode 100644 drivers/staging/xgifb/vb_init.h create mode 100644 drivers/staging/xgifb/vb_setmode.c create mode 100644 drivers/staging/xgifb/vb_setmode.h create mode 100644 drivers/staging/xgifb/vb_struct.h create mode 100644 drivers/staging/xgifb/vb_table.h create mode 100644 drivers/staging/xgifb/vb_util.c create mode 100644 drivers/staging/xgifb/vb_util.h create mode 100644 drivers/staging/xgifb/vgatypes.h (limited to 'drivers') diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index b5c3b3013037..2a1a7c296429 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -141,5 +141,7 @@ source "drivers/staging/ti-st/Kconfig" source "drivers/staging/adis16255/Kconfig" +source "drivers/staging/xgifb/Kconfig" + endif # !STAGING_EXCLUDE_BUILD endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index e330dd5e843d..4a02c0df9ced 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -51,3 +51,4 @@ obj-$(CONFIG_CRYSTALHD) += crystalhd/ obj-$(CONFIG_CXT1E1) += cxt1e1/ obj-$(CONFIG_TI_ST) += ti-st/ obj-$(CONFIG_ADIS16255) += adis16255/ +obj-$(CONFIG_FB_XGI) += xgifb/ diff --git a/drivers/staging/xgifb/Kconfig b/drivers/staging/xgifb/Kconfig new file mode 100644 index 000000000000..bb0ca5974ea0 --- /dev/null +++ b/drivers/staging/xgifb/Kconfig @@ -0,0 +1,11 @@ +config FB_XGI + tristate "XGI display support" + depends on FB && PCI + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + help + This driver supports notebooks with XGI Z7,Z9,Z11 PCI chips. + Say Y if you have such a graphics card. + To compile this driver as a module, choose M here: the + module will be called xgifb.ko diff --git a/drivers/staging/xgifb/Makefile b/drivers/staging/xgifb/Makefile new file mode 100644 index 000000000000..2a317707de0f --- /dev/null +++ b/drivers/staging/xgifb/Makefile @@ -0,0 +1,4 @@ +obj-$(CONFIG_FB_XGI) += xgifb.o + +xgifb-objs := XGI_main_26.o XGI_accel.o vb_init.o vb_setmode.o vb_util.o vb_ext.o + diff --git a/drivers/staging/xgifb/TODO b/drivers/staging/xgifb/TODO new file mode 100644 index 000000000000..7d71019b84c2 --- /dev/null +++ b/drivers/staging/xgifb/TODO @@ -0,0 +1,15 @@ +This drivers still need a lot of work. I can list all cleanups to do but it's +going to be long. So, I'm writing "cleanups" and not the list. + +Arnaud + +TODO: +- clean ups +- fix build warnings when module +- sort out dup ids with SiS driver +- remove useless/wrong/unused #ifdef/code/... +- fix printk usages +- get rid of non-linux related stuff + +Please send patches to: +Arnaud Patard diff --git a/drivers/staging/xgifb/XGI.h b/drivers/staging/xgifb/XGI.h new file mode 100644 index 000000000000..87803dd032de --- /dev/null +++ b/drivers/staging/xgifb/XGI.h @@ -0,0 +1,10 @@ +#ifndef _XGI_H +#define _XGI_H + +#if 1 +#define TWDEBUG(x) +#else +#define TWDEBUG(x) printk(KERN_INFO x "\n"); +#endif + +#endif diff --git a/drivers/staging/xgifb/XGI_accel.c b/drivers/staging/xgifb/XGI_accel.c new file mode 100644 index 000000000000..86ec3421942f --- /dev/null +++ b/drivers/staging/xgifb/XGI_accel.c @@ -0,0 +1,596 @@ +/* + * XGI 300/630/730/540/315/550/650/740 frame buffer driver + * for Linux kernels 2.4.x and 2.5.x + * + * 2D acceleration part + * + * Based on the X driver's XGI300_accel.c which is + * Copyright Xavier Ducoin + * Copyright 2002 by Thomas Winischhofer, Vienna, Austria + * and XGI310_accel.c which is + * Copyright 2002 by Thomas Winischhofer, Vienna, Austria + * + * Author: Thomas Winischhofer + * (see http://www.winischhofer.net/ + * for more information and updates) + */ + +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +/* +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#include +#else +#include