diff options
Diffstat (limited to 'drivers/misc')
41 files changed, 1740 insertions, 1681 deletions
diff --git a/drivers/misc/ad525x_dpot-i2c.c b/drivers/misc/ad525x_dpot-i2c.c index 820826270b6..705b881e186 100644 --- a/drivers/misc/ad525x_dpot-i2c.c +++ b/drivers/misc/ad525x_dpot-i2c.c @@ -51,7 +51,7 @@ static const struct ad_dpot_bus_ops bops = { .write_r8d16 = write_r8d16, }; -static int __devinit ad_dpot_i2c_probe(struct i2c_client *client, +static int ad_dpot_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct ad_dpot_bus_data bdata = { @@ -68,7 +68,7 @@ static int __devinit ad_dpot_i2c_probe(struct i2c_client *client, return ad_dpot_probe(&client->dev, &bdata, id->driver_data, id->name); } -static int __devexit ad_dpot_i2c_remove(struct i2c_client *client) +static int ad_dpot_i2c_remove(struct i2c_client *client) { return ad_dpot_remove(&client->dev); } @@ -109,7 +109,7 @@ static struct i2c_driver ad_dpot_i2c_driver = { .owner = THIS_MODULE, }, .probe = ad_dpot_i2c_probe, - .remove = __devexit_p(ad_dpot_i2c_remove), + .remove = ad_dpot_i2c_remove, .id_table = ad_dpot_id, }; diff --git a/drivers/misc/ad525x_dpot-spi.c b/drivers/misc/ad525x_dpot-spi.c index f62317540d0..9da04ede04f 100644 --- a/drivers/misc/ad525x_dpot-spi.c +++ b/drivers/misc/ad525x_dpot-spi.c @@ -75,7 +75,7 @@ static const struct ad_dpot_bus_ops bops = { .write_r8d8 = write16, .write_r8d16 = write24, }; -static int __devinit ad_dpot_spi_probe(struct spi_device *spi) +static int ad_dpot_spi_probe(struct spi_device *spi) { struct ad_dpot_bus_data bdata = { .client = spi, @@ -87,7 +87,7 @@ static int __devinit ad_dpot_spi_probe(struct spi_device *spi) spi_get_device_id(spi)->name); } -static int __devexit ad_dpot_spi_remove(struct spi_device *spi) +static int ad_dpot_spi_remove(struct spi_device *spi) { return ad_dpot_remove(&spi->dev); } @@ -131,7 +131,7 @@ static struct spi_driver ad_dpot_spi_driver = { .owner = THIS_MODULE, }, .probe = ad_dpot_spi_probe, - .remove = __devexit_p(ad_dpot_spi_remove), + .remove = ad_dpot_spi_remove, .id_table = ad_dpot_spi_id, }; diff --git a/drivers/misc/ad525x_dpot.c b/drivers/misc/ad525x_dpot.c index 6938f1be664..8f99e8e3f0a 100644 --- a/drivers/misc/ad525x_dpot.c +++ b/drivers/misc/ad525x_dpot.c @@ -641,7 +641,7 @@ static const struct attribute_group ad525x_group_commands = { .attrs = ad525x_attributes_commands, }; -__devinit int ad_dpot_add_files(struct device *dev, +int ad_dpot_add_files(struct device *dev, unsigned features, unsigned rdac) { int err = sysfs_create_file(&dev->kobj, @@ -685,7 +685,7 @@ inline void ad_dpot_remove_files(struct device *dev, } } -int __devinit ad_dpot_probe(struct device *dev, +int ad_dpot_probe(struct device *dev, struct ad_dpot_bus_data *bdata, unsigned long devid, const char *name) { diff --git a/drivers/misc/apds9802als.c b/drivers/misc/apds9802als.c index 0314773f6db..d648b089302 100644 --- a/drivers/misc/apds9802als.c +++ b/drivers/misc/apds9802als.c @@ -68,7 +68,7 @@ static int als_wait_for_data_ready(struct device *dev) ret = i2c_smbus_read_byte_data(client, 0x86); } while (!(ret & 0x80) && retry--); - if (!retry) { + if (retry < 0) { dev_warn(dev, "timeout waiting for data ready\n"); return -ETIMEDOUT; } @@ -254,7 +254,7 @@ als_error1: return res; } -static int __devexit apds9802als_remove(struct i2c_client *client) +static int apds9802als_remove(struct i2c_client *client) { struct als_data *data = i2c_get_clientdata(client); @@ -326,7 +326,7 @@ static struct i2c_driver apds9802als_driver = { .pm = APDS9802ALS_PM_OPS, }, .probe = apds9802als_probe, - .remove = __devexit_p(apds9802als_remove), + .remove = apds9802als_remove, .suspend = apds9802als_suspend, .resume = apds9802als_resume, .id_table = apds9802als_id, diff --git a/drivers/misc/apds990x.c b/drivers/misc/apds990x.c index ee74244aa03..0e67f8263cd 100644 --- a/drivers/misc/apds990x.c +++ b/drivers/misc/apds990x.c @@ -1047,7 +1047,7 @@ static struct attribute_group apds990x_attribute_group[] = { {.attrs = sysfs_attrs_ctrl }, }; -static int __devinit apds990x_probe(struct i2c_client *client, +static int apds990x_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct apds990x_chip *chip; @@ -1181,7 +1181,7 @@ fail1: return err; } -static int __devexit apds990x_remove(struct i2c_client *client) +static int apds990x_remove(struct i2c_client *client) { struct apds990x_chip *chip = i2c_get_clientdata(client); @@ -1275,7 +1275,7 @@ static struct i2c_driver apds990x_driver = { .pm = &apds990x_pm_ops, }, .probe = apds990x_probe, - .remove = __devexit_p(apds990x_remove), + .remove = apds990x_remove, .id_table = apds990x_id, }; diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c index 5bb18778107..158da5a81a6 100644 --- a/drivers/misc/atmel-ssc.c +++ b/drivers/misc/atmel-ssc.c @@ -18,6 +18,8 @@ #include <linux/slab.h> #include <linux/module.h> +#include <linux/of.h> + /* Serialize access to ssc_list and user count */ static DEFINE_SPINLOCK(user_lock); static LIST_HEAD(ssc_list); @@ -29,7 +31,13 @@ struct ssc_device *ssc_request(unsigned int ssc_num) spin_lock(&user_lock); list_for_each_entry(ssc, &ssc_list, list) { - if (ssc->pdev->id == ssc_num) { + if (ssc->pdev->dev.of_node) { + if (of_alias_get_id(ssc->pdev->dev.of_node, "ssc") + == ssc_num) { + ssc_valid = 1; + break; + } + } else if (ssc->pdev->id == ssc_num) { ssc_valid = 1; break; } @@ -68,39 +76,93 @@ void ssc_free(struct ssc_device *ssc) } EXPORT_SYMBOL(ssc_free); -static int __init ssc_probe(struct platform_device *pdev) +static struct atmel_ssc_platform_data at91rm9200_config = { + .use_dma = 0, +}; + +static struct atmel_ssc_platform_data at91sam9g45_config = { + .use_dma = 1, +}; + +static const struct platform_device_id atmel_ssc_devtypes[] = { + { + .name = "at91rm9200_ssc", + .driver_data = (unsigned long) &at91rm9200_config, + }, { + .name = "at91sam9g45_ssc", + .driver_data = (unsigned long) &at91sam9g45_config, + }, { + /* sentinel */ + } +}; + +#ifdef CONFIG_OF +static const struct of_device_id atmel_ssc_dt_ids[] = { + { + .compatible = "atmel,at91rm9200-ssc", + .data = &at91rm9200_config, + }, { + .compatible = "atmel,at91sam9g45-ssc", + .data = &at91sam9g45_config, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, atmel_ssc_dt_ids); +#endif + +static inline const struct atmel_ssc_platform_data * __init + atmel_ssc_get_driver_data(struct platform_device *pdev) +{ + if (pdev->dev.of_node) { + const struct of_device_id *match; + match = of_match_node(atmel_ssc_dt_ids, pdev->dev.of_node); + if (match == NULL) + return NULL; + return match->data; + } + + return (struct atmel_ssc_platform_data *) + platform_get_device_id(pdev)->driver_data; +} + +static int ssc_probe(struct platform_device *pdev) { - int retval = 0; struct resource *regs; struct ssc_device *ssc; + const struct atmel_ssc_platform_data *plat_dat; - ssc = kzalloc(sizeof(struct ssc_device), GFP_KERNEL); + ssc = devm_kzalloc(&pdev->dev, sizeof(struct ssc_device), GFP_KERNEL); if (!ssc) { dev_dbg(&pdev->dev, "out of memory\n"); - retval = -ENOMEM; - goto out; + return -ENOMEM; } + ssc->pdev = pdev; + + plat_dat = atmel_ssc_get_driver_data(pdev); + if (!plat_dat) + return -ENODEV; + ssc->pdata = (struct atmel_ssc_platform_data *)plat_dat; + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!regs) { dev_dbg(&pdev->dev, "no mmio resource defined\n"); - retval = -ENXIO; - goto out_free; + return -ENXIO; } - ssc->clk = clk_get(&pdev->dev, "pclk"); - if (IS_ERR(ssc->clk)) { - dev_dbg(&pdev->dev, "no pclk clock defined\n"); - retval = -ENXIO; - goto out_free; - } - - ssc->pdev = pdev; - ssc->regs = ioremap(regs->start, resource_size(regs)); + ssc->regs = devm_request_and_ioremap(&pdev->dev, regs); if (!ssc->regs) { dev_dbg(&pdev->dev, "ioremap failed\n"); - retval = -EINVAL; - goto out_clk; + return -EINVAL; + } + + ssc->phybase = regs->start; + + ssc->clk = devm_clk_get(&pdev->dev, "pclk"); + if (IS_ERR(ssc->clk)) { + dev_dbg(&pdev->dev, "no pclk clock defined\n"); + return -ENXIO; } /* disable all interrupts */ @@ -112,8 +174,7 @@ static int __init ssc_probe(struct platform_device *pdev) ssc->irq = platform_get_irq(pdev, 0); if (!ssc->irq) { dev_dbg(&pdev->dev, "could not get irq\n"); - retval = -ENXIO; - goto out_unmap; + return -ENXIO; } spin_lock(&user_lock); @@ -125,51 +186,31 @@ static int __init ssc_probe(struct platform_device *pdev) dev_info(&pdev->dev, "Atmel SSC device at 0x%p (irq %d)\n", ssc->regs, ssc->irq); - goto out; - -out_unmap: - iounmap(ssc->regs); -out_clk: - clk_put(ssc->clk); -out_free: - kfree(ssc); -out: - return retval; + return 0; } -static int __devexit ssc_remove(struct platform_device *pdev) +static int ssc_remove(struct platform_device *pdev) { struct ssc_device *ssc = platform_get_drvdata(pdev); spin_lock(&user_lock); - iounmap(ssc->regs); - clk_put(ssc->clk); list_del(&ssc->list); - kfree(ssc); spin_unlock(&user_lock); return 0; } static struct platform_driver ssc_driver = { - .remove = __devexit_p(ssc_remove), .driver = { .name = "ssc", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(atmel_ssc_dt_ids), }, + .id_table = atmel_ssc_devtypes, + .probe = ssc_probe, + .remove = ssc_remove, }; - -static int __init ssc_init(void) -{ - return platform_driver_probe(&ssc_driver, ssc_probe); -} -module_init(ssc_init); - -static void __exit ssc_exit(void) -{ - platform_driver_unregister(&ssc_driver); -} -module_exit(ssc_exit); +module_platform_driver(ssc_driver); MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>"); MODULE_DESCRIPTION("SSC driver for Atmel AVR32 and AT91"); diff --git a/drivers/misc/bh1770glc.c b/drivers/misc/bh1770glc.c index 3d56ae7ef8d..2ed8fc3be7e 100644 --- a/drivers/misc/bh1770glc.c +++ b/drivers/misc/bh1770glc.c @@ -1162,7 +1162,7 @@ static struct attribute_group bh1770_attribute_group = { .attrs = sysfs_attrs }; -static int __devinit bh1770_probe(struct i2c_client *client, +static int bh1770_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct bh1770_chip *chip; @@ -1285,7 +1285,7 @@ fail1: return err; } -static int __devexit bh1770_remove(struct i2c_client *client) +static int bh1770_remove(struct i2c_client *client) { struct bh1770_chip *chip = i2c_get_clientdata(client); @@ -1395,7 +1395,7 @@ static struct i2c_driver bh1770_driver = { .pm = &bh1770_pm_ops, }, .probe = bh1770_probe, - .remove = __devexit_p(bh1770_remove), + .remove = bh1770_remove, .id_table = bh1770_id, }; diff --git a/drivers/misc/bh1780gli.c b/drivers/misc/bh1780gli.c index f1f9877f3fd..cf03d0abf33 100644 --- a/drivers/misc/bh1780gli.c +++ b/drivers/misc/bh1780gli.c @@ -144,7 +144,7 @@ static const struct attribute_group bh1780_attr_group = { .attrs = bh1780_attributes, }; -static int __devinit bh1780_probe(struct i2c_client *client, +static int bh1780_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret; @@ -185,7 +185,7 @@ err_op_failed: return ret; } -static int __devexit bh1780_remove(struct i2c_client *client) +static int bh1780_remove(struct i2c_client *client) { struct bh1780_data *ddata; @@ -248,7 +248,7 @@ static const struct i2c_device_id bh1780_id[] = { static struct i2c_driver bh1780_driver = { .probe = bh1780_probe, - .remove = __devexit_p(bh1780_remove), + .remove = bh1780_remove, .id_table = bh1780_id, .driver = { .name = "bh1780", diff --git a/drivers/misc/bmp085-i2c.c b/drivers/misc/bmp085-i2c.c index a4f33c995ea..3abfcecf842 100644 --- a/drivers/misc/bmp085-i2c.c +++ b/drivers/misc/bmp085-i2c.c @@ -36,7 +36,7 @@ static int bmp085_i2c_detect(struct i2c_client *client, return bmp085_detect(&client->dev); } -static int __devinit bmp085_i2c_probe(struct i2c_client *client, +static int bmp085_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { int err; @@ -71,7 +71,7 @@ static struct i2c_driver bmp085_i2c_driver = { }, .id_table = bmp085_id, .probe = bmp085_i2c_probe, - .remove = __devexit_p(bmp085_i2c_remove), + .remove = bmp085_i2c_remove, .detect = bmp085_i2c_detect, .address_list = normal_i2c diff --git a/drivers/misc/bmp085-spi.c b/drivers/misc/bmp085-spi.c index 5e982af9973..d6a52659cf2 100644 --- a/drivers/misc/bmp085-spi.c +++ b/drivers/misc/bmp085-spi.c @@ -22,7 +22,7 @@ #include <linux/err.h> #include "bmp085.h" -static int __devinit bmp085_spi_probe(struct spi_device *client) +static int bmp085_spi_probe(struct spi_device *client) { int err; struct regmap *regmap; @@ -70,7 +70,7 @@ static struct spi_driver bmp085_spi_driver = { }, .id_table = bmp085_id, .probe = bmp085_spi_probe, - .remove = __devexit_p(bmp085_spi_remove) + .remove = bmp085_spi_remove }; module_spi_driver(bmp085_spi_driver); diff --git a/drivers/misc/bmp085.c b/drivers/misc/bmp085.c index 62e418293b7..849e2fed4da 100644 --- a/drivers/misc/bmp085.c +++ b/drivers/misc/bmp085.c @@ -420,7 +420,7 @@ struct regmap_config bmp085_regmap_config = { }; EXPORT_SYMBOL_GPL(bmp085_regmap_config); -__devinit int bmp085_probe(struct device *dev, struct regmap *regmap) +int bmp085_probe(struct device *dev, struct regmap *regmap) { struct bmp085_data *data; int err = 0; diff --git a/drivers/misc/cb710/core.c b/drivers/misc/cb710/core.c index 9d5eed75466..2e50f811ff5 100644 --- a/drivers/misc/cb710/core.c +++ b/drivers/misc/cb710/core.c @@ -30,7 +30,7 @@ void cb710_pci_update_config_reg(struct pci_dev *pdev, EXPORT_SYMBOL_GPL(cb710_pci_update_config_reg); /* Some magic writes based on Windows driver init code */ -static int __devinit cb710_pci_configure(struct pci_dev *pdev) +static int cb710_pci_configure(struct pci_dev *pdev) { unsigned int devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0); struct pci_dev *pdev0; @@ -96,7 +96,7 @@ static void cb710_release_slot(struct device *dev) #endif } -static int __devinit cb710_register_slot(struct cb710_chip *chip, +static int cb710_register_slot(struct cb710_chip *chip, unsigned slot_mask, unsigned io_offset, const char *name) { int nr = chip->slots; @@ -201,7 +201,7 @@ static int cb710_resume(struct pci_dev *pdev) #endif /* CONFIG_PM */ -static int __devinit cb710_probe(struct pci_dev *pdev, +static int cb710_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct cb710_chip *chip; @@ -305,7 +305,7 @@ unreg_mmc: return err; } -static void __devexit cb710_remove_one(struct pci_dev *pdev) +static void cb710_remove_one(struct pci_dev *pdev) { struct cb710_chip *chip = pci_get_drvdata(pdev); unsigned long flags; @@ -332,7 +332,7 @@ static struct pci_driver cb710_driver = { .name = KBUILD_MODNAME, .id_table = cb710_pci_tbl, .probe = cb710_probe, - .remove = __devexit_p(cb710_remove_one), + .remove = cb710_remove_one, #ifdef CONFIG_PM .suspend = cb710_suspend, .resume = cb710_resume, diff --git a/drivers/misc/cs5535-mfgpt.c b/drivers/misc/cs5535-mfgpt.c index f505a40a8f4..9858f36dad8 100644 --- a/drivers/misc/cs5535-mfgpt.c +++ b/drivers/misc/cs5535-mfgpt.c @@ -246,7 +246,7 @@ EXPORT_SYMBOL_GPL(cs5535_mfgpt_write); * Jordan tells me that he and Mitch once played w/ it, but it's unclear * what the results of that were (and they experienced some instability). */ -static void __devinit reset_all_timers(void) +static void reset_all_timers(void) { uint32_t val, dummy; @@ -262,7 +262,7 @@ static void __devinit reset_all_timers(void) * In other cases (such as with VSAless OpenFirmware), the system firmware * leaves timers available for us to use. */ -static int __devinit scan_timers(struct cs5535_mfgpt_chip *mfgpt) +static int scan_timers(struct cs5535_mfgpt_chip *mfgpt) { struct cs5535_mfgpt_timer timer = { .chip = mfgpt }; unsigned long flags; @@ -289,7 +289,7 @@ static int __devinit scan_timers(struct cs5535_mfgpt_chip *mfgpt) return timers; } -static int __devinit cs5535_mfgpt_probe(struct platform_device *pdev) +static int cs5535_mfgpt_probe(struct platform_device *pdev) { struct resource *res; int err = -EIO, t; diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index ab1ad41786d..2baeec56edf 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -656,7 +656,7 @@ err_out: return err; } -static int __devexit at24_remove(struct i2c_client *client) +static int at24_remove(struct i2c_client *client) { struct at24_data *at24; int i; @@ -680,7 +680,7 @@ static struct i2c_driver at24_driver = { .owner = THIS_MODULE, }, .probe = at24_probe, - .remove = __devexit_p(at24_remove), + .remove = at24_remove, .id_table = at24_ids, }; diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c index 4ed93dd5411..b08cf8a0878 100644 --- a/drivers/misc/eeprom/at25.c +++ b/drivers/misc/eeprom/at25.c @@ -459,7 +459,7 @@ fail: return err; } -static int __devexit at25_remove(struct spi_device *spi) +static int at25_remove(struct spi_device *spi) { struct at25_data *at25; @@ -477,7 +477,7 @@ static struct spi_driver at25_driver = { .owner = THIS_MODULE, }, .probe = at25_probe, - .remove = __devexit_p(at25_remove), + .remove = at25_remove, }; module_spi_driver(at25_driver); diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c index ce3fe3633dd..a6b5d5e7348 100644 --- a/drivers/misc/eeprom/eeprom_93xx46.c +++ b/drivers/misc/eeprom/eeprom_93xx46.c @@ -309,7 +309,7 @@ static ssize_t eeprom_93xx46_store_erase(struct device *dev, } static DEVICE_ATTR(erase, S_IWUSR, NULL, eeprom_93xx46_store_erase); -static int __devinit eeprom_93xx46_probe(struct spi_device *spi) +static int eeprom_93xx46_probe(struct spi_device *spi) { struct eeprom_93xx46_platform_data *pd; struct eeprom_93xx46_dev *edev; @@ -370,7 +370,7 @@ fail: return err; } -static int __devexit eeprom_93xx46_remove(struct spi_device *spi) +static int eeprom_93xx46_remove(struct spi_device *spi) { struct eeprom_93xx46_dev *edev = dev_get_drvdata(&spi->dev); @@ -389,7 +389,7 @@ static struct spi_driver eeprom_93xx46_driver = { .owner = THIS_MODULE, }, .probe = eeprom_93xx46_probe, - .remove = __devexit_p(eeprom_93xx46_remove), + .remove = eeprom_93xx46_remove, }; module_spi_driver(eeprom_93xx46_driver); diff --git a/drivers/misc/fsa9480.c b/drivers/misc/fsa9480.c index ac96c3a4034..e8cbb1c59f4 100644 --- a/drivers/misc/fsa9480.c +++ b/drivers/misc/fsa9480.c @@ -407,7 +407,7 @@ static int fsa9480_irq_init(struct fsa9480_usbsw *usbsw) return 0; } -static int __devinit fsa9480_probe(struct i2c_client *client, +static int fsa9480_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); @@ -462,7 +462,7 @@ fail1: return ret; } -static int __devexit fsa9480_remove(struct i2c_client *client) +static int fsa9480_remove(struct i2c_client *client) { struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client); if (client->irq) @@ -533,7 +533,7 @@ static struct i2c_driver fsa9480_i2c_driver = { .name = "fsa9480", }, .probe = fsa9480_probe, - .remove = __devexit_p(fsa9480_remove), + .remove = fsa9480_remove, .resume = fsa9480_resume, .suspend = fsa9480_suspend, .id_table = fsa9480_id, diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c index 12ccdf94e4f..621c7a37339 100644 --- a/drivers/misc/hpilo.c +++ b/drivers/misc/hpilo.c @@ -30,7 +30,7 @@ static struct class *ilo_class; static unsigned int ilo_major; -static unsigned int max_ccb = MIN_CCB; +static unsigned int max_ccb = 16; static char ilo_hwdev[MAX_ILO_DEV]; static inline int get_entry_id(int entry) @@ -686,7 +686,7 @@ static void ilo_unmap_device(struct pci_dev *pdev, struct ilo_hwinfo *hw) pci_iounmap(pdev, hw->mmio_vaddr); } -static int __devinit ilo_map_device(struct pci_dev *pdev, struct ilo_hwinfo *hw) +static int ilo_map_device(struct pci_dev *pdev, struct ilo_hwinfo *hw) { int error = -ENOMEM; @@ -725,6 +725,9 @@ static void ilo_remove(struct pci_dev *pdev) int i, minor; struct ilo_hwinfo *ilo_hw = pci_get_drvdata(pdev); + if (!ilo_hw) + return; + clear_device(ilo_hw); minor = MINOR(ilo_hw->cdev.dev); @@ -748,12 +751,16 @@ static void ilo_remove(struct pci_dev *pdev) ilo_hwdev[(minor / max_ccb)] = 0; } -static int __devinit ilo_probe(struct pci_dev *pdev, +static int ilo_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - int devnum, minor, start, error; + int devnum, minor, start, error = 0; struct ilo_hwinfo *ilo_hw; + /* Ignore subsystem_device = 0x1979 (set by BIOS) */ + if (pdev->subsystem_device == 0x1979) + goto out; + if (max_ccb > MAX_CCB) max_ccb = MAX_CCB; else if (max_ccb < MIN_CCB) @@ -852,7 +859,7 @@ static struct pci_driver ilo_driver = { .name = ILO_NAME, .id_table = ilo_devices, .probe = ilo_probe, - .remove = __devexit_p(ilo_remove), + .remove = ilo_remove, }; static int __init ilo_init(void) @@ -892,14 +899,14 @@ static void __exit ilo_exit(void) class_destroy(ilo_class); } -MODULE_VERSION("1.3"); +MODULE_VERSION("1.4"); MODULE_ALIAS(ILO_NAME); MODULE_DESCRIPTION(ILO_NAME); MODULE_AUTHOR("David Altobelli <david.altobelli@hp.com>"); MODULE_LICENSE("GPL v2"); module_param(max_ccb, uint, 0444); -MODULE_PARM_DESC(max_ccb, "Maximum number of HP iLO channels to attach (8)"); +MODULE_PARM_DESC(max_ccb, "Maximum number of HP iLO channels to attach (16)"); module_init(ilo_init); module_exit(ilo_exit); diff --git a/drivers/misc/ibmasm/module.c b/drivers/misc/ibmasm/module.c index 168d8008f46..0346d87c5fe 100644 --- a/drivers/misc/ibmasm/module.c +++ b/drivers/misc/ibmasm/module.c @@ -62,7 +62,7 @@ module_param(ibmasm_debug, int , S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ibmasm_debug, " Set debug mode on or off"); -static int __devinit ibmasm_init_one(struct pci_dev *pdev, const struct pci_device_id *id) +static int ibmasm_init_one(struct pci_dev *pdev, const struct pci_device_id *id) { int result; struct service_processor *sp; @@ -163,7 +163,7 @@ error_resources: return result; } -static void __devexit ibmasm_remove_one(struct pci_dev *pdev) +static void ibmasm_remove_one(struct pci_dev *pdev) { struct service_processor *sp = (struct service_processor *)pci_get_drvdata(pdev); @@ -198,7 +198,7 @@ static struct pci_driver ibmasm_driver = { .name = DRIVER_NAME, .id_table = ibmasm_pci_table, .probe = ibmasm_init_one, - .remove = __devexit_p(ibmasm_remove_one), + .remove = ibmasm_remove_one, }; static void __exit ibmasm_exit (void) diff --git a/drivers/misc/ioc4.c b/drivers/misc/ioc4.c index 6a7710603a9..06f6ad29cef 100644 --- a/drivers/misc/ioc4.c +++ b/drivers/misc/ioc4.c @@ -139,7 +139,7 @@ ioc4_unregister_submodule(struct ioc4_submodule *is) * even though the following code utilizes external interrupt registers * to perform the speed calculation. */ -static void __devinit +static void ioc4_clock_calibrate(struct ioc4_driver_data *idd) { union ioc4_int_out int_out; @@ -231,7 +231,7 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd) * on the same PCI bus at slot number 3 to differentiate IO9 from IO10. * If neither is present, it's a PCI-RT. */ -static unsigned int __devinit +static unsigned int ioc4_variant(struct ioc4_driver_data *idd) { struct pci_dev *pdev = NULL; @@ -279,7 +279,7 @@ ioc4_load_modules(struct work_struct *work) static DECLARE_WORK(ioc4_load_modules_work, ioc4_load_modules); /* Adds a new instance of an IOC4 card */ -static int __devinit +static int ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) { struct ioc4_driver_data *idd; @@ -415,7 +415,7 @@ out: } /* Removes a particular instance of an IOC4 card. */ -static void __devexit +static void ioc4_remove(struct pci_dev *pdev) { struct ioc4_submodule *is; @@ -466,7 +466,7 @@ static struct pci_driver ioc4_driver = { .name = "IOC4", .id_table = ioc4_id_table, .probe = ioc4_probe, - .remove = __devexit_p(ioc4_remove), + .remove = ioc4_remove, }; MODULE_DEVICE_TABLE(pci, ioc4_id_table); diff --git a/drivers/misc/isl29003.c b/drivers/misc/isl29003.c index eb5de2e210d..29b306c6bdb 100644 --- a/drivers/misc/isl29003.c +++ b/drivers/misc/isl29003.c @@ -365,7 +365,7 @@ static int isl29003_init_client(struct i2c_client *client) * I2C layer */ -static int __devinit isl29003_probe(struct i2c_client *client, +static int isl29003_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); @@ -401,7 +401,7 @@ exit_kfree: return err; } -static int __devexit isl29003_remove(struct i2c_client *client) +static int isl29003_remove(struct i2c_client *client) { sysfs_remove_group(&client->dev.kobj, &isl29003_attr_group); isl29003_set_power_state(client, 0); @@ -451,7 +451,7 @@ static struct i2c_driver isl29003_driver = { .suspend = isl29003_suspend, .resume = isl29003_resume, .probe = isl29003_probe, - .remove = __devexit_p(isl29003_remove), + .remove = isl29003_remove, .id_table = isl29003_id, }; diff --git a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c index 60ec8689d6e..7c97550240f 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c +++ b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c @@ -114,7 +114,7 @@ static struct of_device_id lis3lv02d_i2c_dt_ids[] = { MODULE_DEVICE_TABLE(of, lis3lv02d_i2c_dt_ids); #endif -static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client, +static int lis3lv02d_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret = 0; @@ -191,7 +191,7 @@ fail: return ret; } -static int __devexit lis3lv02d_i2c_remove(struct i2c_client *client) +static int lis3lv02d_i2c_remove(struct i2c_client *client) { struct lis3lv02d *lis3 = i2c_get_clientdata(client); struct lis3lv02d_platform_data *pdata = client->dev.platform_data; @@ -280,7 +280,7 @@ static struct i2c_driver lis3lv02d_i2c_driver = { .of_match_table = of_match_ptr(lis3lv02d_i2c_dt_ids), }, .probe = lis3lv02d_i2c_probe, - .remove = __devexit_p(lis3lv02d_i2c_remove), + .remove = lis3lv02d_i2c_remove, .id_table = lis3lv02d_id, }; diff --git a/drivers/misc/lis3lv02d/lis3lv02d_spi.c b/drivers/misc/lis3lv02d/lis3lv02d_spi.c index ccb6475fa05..9aa2bd2a71a 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d_spi.c +++ b/drivers/misc/lis3lv02d/lis3lv02d_spi.c @@ -69,7 +69,7 @@ static struct of_device_id lis302dl_spi_dt_ids[] = { MODULE_DEVICE_TABLE(of, lis302dl_spi_dt_ids); #endif -static int __devinit lis302dl_spi_probe(struct spi_device *spi) +static int lis302dl_spi_probe(struct spi_device *spi) { int ret; @@ -100,7 +100,7 @@ static int __devinit lis302dl_spi_probe(struct spi_device *spi) return lis3lv02d_init_device(&lis3_dev); } -static int __devexit lis302dl_spi_remove(struct spi_device *spi) +static int lis302dl_spi_remove(struct spi_device *spi) { struct lis3lv02d *lis3 = spi_get_drvdata(spi); lis3lv02d_joystick_disable(lis3); @@ -144,7 +144,7 @@ static struct spi_driver lis302dl_spi_driver = { .of_match_table = of_match_ptr(lis302dl_spi_dt_ids), }, .probe = lis302dl_spi_probe, - .remove = __devexit_p(lis302dl_spi_remove), + .remove = lis302dl_spi_remove, }; module_spi_driver(lis302dl_spi_driver); diff --git a/drivers/misc/mei/Makefile b/drivers/misc/mei/Makefile index 57168db6c7e..0017842e166 100644 --- a/drivers/misc/mei/Makefile +++ b/drivers/misc/mei/Makefile @@ -8,4 +8,5 @@ mei-objs += interrupt.o mei-objs += interface.o mei-objs += iorw.o mei-objs += main.o +mei-objs += amthif.o mei-objs += wd.o diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c new file mode 100644 index 00000000000..18794aea606 --- /dev/null +++ b/drivers/misc/mei/amthif.c @@ -0,0 +1,722 @@ +/* + * + * Intel Management Engine Interface (Intel MEI) Linux driver + * Copyright (c) 2003-2012, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/errno.h> +#include <linux/types.h> +#include <linux/fcntl.h> +#include <linux/aio.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/ioctl.h> +#include <linux/cdev.h> +#include <linux/list.h> +#include <linux/delay.h> +#include <linux/sched.h> +#include <linux/uuid.h> +#include <linux/jiffies.h> +#include <linux/uaccess.h> + + +#include "mei_dev.h" +#include "hw.h" +#include <linux/mei.h> +#include "interface.h" + +const uuid_le mei_amthi_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, 0xac, + 0xa8, 0x46, 0xe0, 0xff, 0x65, + 0x81, 0x4c); + +/** + * mei_amthif_reset_params - initializes mei device iamthif + * + * @dev: the device structure + */ +void mei_amthif_reset_params(struct mei_device *dev) +{ + /* reset iamthif parameters. */ + dev->iamthif_current_cb = NULL; + dev->iamthif_msg_buf_size = 0; + dev->iamthif_msg_buf_index = 0; + dev->iamthif_canceled = false; + dev->iamthif_ioctl = false; + dev->iamthif_state = MEI_IAMTHIF_IDLE; + dev->iamthif_timer = 0; +} + +/** + * mei_amthif_host_init_ - mei initialization amthif client. + * + * @dev: the device structure + * + */ +void mei_amthif_host_init(struct mei_device *dev) +{ + int i; + unsigned char *msg_buf; + + mei_cl_init(&dev->iamthif_cl, dev); + dev->iamthif_cl.state = MEI_FILE_DISCONNECTED; + + /* find ME amthi client */ + i = mei_me_cl_link(dev, &dev->iamthif_cl, + &mei_amthi_guid, MEI_IAMTHIF_HOST_CLIENT_ID); + if (i < 0) { + dev_info(&dev->pdev->dev, "failed to find iamthif client.\n"); + return; + } + + /* Assign iamthif_mtu to the value received from ME */ + + dev->iamthif_mtu = dev->me_clients[i].props.max_msg_length; + dev_dbg(&dev->pdev->dev, "IAMTHIF_MTU = %d\n", + dev->me_clients[i].props.max_msg_length); + + kfree(dev->iamthif_msg_buf); + dev->iamthif_msg_buf = NULL; + + /* allocate storage for ME message buffer */ + msg_buf = kcalloc(dev->iamthif_mtu, + sizeof(unsigned char), GFP_KERNEL); + if (!msg_buf) { + dev_dbg(&dev->pdev->dev, "memory allocation for ME message buffer failed.\n"); + return; + } + + dev->iamthif_msg_buf = msg_buf; + + if (mei_connect(dev, &dev->iamthif_cl)) { + dev_dbg(&dev->pdev->dev, "Failed to connect to AMTHI client\n"); + dev->iamthif_cl.state = MEI_FILE_DISCONNECTED; + dev->iamthif_cl.host_client_id = 0; + } else { + dev->iamthif_cl.timer_count = MEI_CONNECT_TIMEOUT; + } +} + +/** + * mei_amthif_find_read_list_entry - finds a amthilist entry for current file + * + * @dev: the device structure + * @file: pointer to file object + * + * returns returned a list entry on success, NULL on failure. + */ +struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev, + struct file *file) +{ + struct mei_cl_cb *pos = NULL; + struct mei_cl_cb *next = NULL; + + list_for_each_entry_safe(pos, next, + &dev->amthif_rd_complete_list.list, list) { + if (pos->cl && pos->cl == &dev->iamthif_cl && + pos->file_object == file) + return pos; + } + return NULL; +} + + +/** + * mei_amthif_read - read data from AMTHIF client + * + * @dev: the device structure + * @if_num: minor number + * @file: pointer to file object + * @*ubuf: pointer to user data in user space + * @length: data length to read + * @offset: data read offset + * + * Locking: called under "dev->device_lock" lock + * + * returns + * returned data length on success, + * zero if no data to read, + * negative on failure. + */ +int mei_amthif_read(struct mei_device *dev, struct file *file, + char __user *ubuf, size_t length, loff_t *offset) +{ + int rets; + int wait_ret; + struct mei_cl_cb *cb = NULL; + struct mei_cl *cl = file->private_data; + unsigned long timeout; + int i; + + /* Only Posible if we are in timeout */ + if (!cl || cl != &dev->iamthif_cl) { + dev_dbg(&dev->pdev->dev, "bad file ext.\n"); + return -ETIMEDOUT; + } + + i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id); + + if (i < 0) { + dev_dbg(&dev->pdev->dev, "amthi client not found.\n"); + return -ENODEV; + } + dev_dbg(&dev->pdev->dev, "checking amthi data\n"); + cb = mei_amthif_find_read_list_entry(dev, file); + + /* Check for if we can block or not*/ + if (cb == NULL && file->f_flags & O_NONBLOCK) + return -EAGAIN; + + + dev_dbg(&dev->pdev->dev, "waiting for amthi data\n"); + while (cb == NULL) { + /* unlock the Mutex */ + mutex_unlock(&dev->device_lock); + + wait_ret = wait_event_interruptible(dev->iamthif_cl.wait, + (cb = mei_amthif_find_read_list_entry(dev, file))); + + if (wait_ret) + return -ERESTARTSYS; + + dev_dbg(&dev->pdev->dev, "woke up from sleep\n"); + + /* Locking again the Mutex */ + mutex_lock(&dev->device_lock); + } + + + dev_dbg(&dev->pdev->dev, "Got amthi data\n"); + dev->iamthif_timer = 0; + + if (cb) { + timeout = cb->read_time + + mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER); + dev_dbg(&dev->pdev->dev, "amthi timeout = %lud\n", + timeout); + + if (time_after(jiffies, timeout)) { + dev_dbg(&dev->pdev->dev, "amthi Time out\n"); + /* 15 sec for the message has expired */ + list_del(&cb->list); + rets = -ETIMEDOUT; + goto free; + } + } + /* if the whole message will fit remove it from the list */ + if (cb->buf_idx >= *offset && length >= (cb->buf_idx - *offset)) + list_del(&cb->list); + else if (cb->buf_idx > 0 && cb->buf_idx <= *offset) { + /* end of the message has been reached */ + list_del(&cb->list); + rets = 0; + goto free; + } + /* else means that not full buffer will be read and do not + * remove message from deletion list + */ + + dev_dbg(&dev->pdev->dev, "amthi cb->response_buffer size - %d\n", + cb->response_buffer.size); + dev_dbg(&dev->pdev->dev, "amthi cb->buf_idx - %lu\n", cb->buf_idx); + + /* length is being turncated to PAGE_SIZE, however, + * the buf_idx may point beyond */ + length = min_t(size_t, length, (cb->buf_idx - *offset)); + + if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) + rets = -EFAULT; + else { + rets = length; + if ((*offset + length) < cb->buf_idx) { + *offset += length; + goto out; + } + } +free: + dev_dbg(&dev->pdev->dev, "free amthi cb memory.\n"); + *offset = 0; + mei_io_cb_free(cb); +out: + return rets; +} + +/** + * mei_amthif_send_cmd - send amthif command to the ME + * + * @dev: the device structure + * @cb: mei call back struct + * + * returns 0 on success, <0 on failure. + * + */ +static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb) +{ + struct mei_msg_hdr mei_hdr; + int ret; + + if (!dev || !cb) + return -ENODEV; + + dev_dbg(&dev->pdev->dev, "write data to amthi client.\n"); + + dev->iamthif_state = MEI_IAMTHIF_WRITING; + dev->iamthif_current_cb = cb; + dev->iamthif_file_object = cb->file_object; + dev->iamthif_canceled = false; + dev->iamthif_ioctl = true; + dev->iamthif_msg_buf_size = cb->request_buffer.size; + memcpy(dev->iamthif_msg_buf, cb->request_buffer.data, + cb->request_buffer.size); + + ret = mei_flow_ctrl_creds(dev, &dev->iamthif_cl); + if (ret < 0) + return ret; + + if (ret && dev->mei_host_buffer_is_empty) { + ret = 0; + dev->mei_host_buffer_is_empty = false; + if (cb->request_buffer.size > mei_hbuf_max_data(dev)) { + mei_hdr.length = mei_hbuf_max_data(dev); + mei_hdr.msg_complete = 0; + } else { + mei_hdr.length = cb->request_buffer.size; + mei_hdr.msg_complete = 1; + } + + mei_hdr.host_addr = dev->iamthif_cl.host_client_id; + mei_hdr.me_addr = dev->iamthif_cl.me_client_id; + mei_hdr.reserved = 0; + dev->iamthif_msg_buf_index += mei_hdr.length; + if (mei_write_message(dev, &mei_hdr, + (unsigned char *)(dev->iamthif_msg_buf), + mei_hdr.length)) + return -ENODEV; + + if (mei_hdr.msg_complete) { + if (mei_flow_ctrl_reduce(dev, &dev->iamthif_cl)) + return -ENODEV; + dev->iamthif_flow_control_pending = true; + dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL; + dev_dbg(&dev->pdev->dev, "add amthi cb to write waiting list\n"); + dev->iamthif_current_cb = cb; + dev->iamthif_file_object = cb->file_object; + list_add_tail(&cb->list, &dev->write_waiting_list.list); + } else { + dev_dbg(&dev->pdev->dev, "message does not complete, so add amthi cb to write list.\n"); + list_add_tail(&cb->list, &dev->write_list.list); + } + } else { + if (!(dev->mei_host_buffer_is_empty)) + dev_dbg(&dev->pdev->dev, "host buffer is not empty"); + + dev_dbg(&dev->pdev->dev, "No flow control credentials, so add iamthif cb to write list.\n"); + list_add_tail(&cb->list, &dev->write_list.list); + } + return 0; +} + +/** + * mei_amthif_write - write amthif data to amthif client + * + * @dev: the device structure + * @cb: mei call back struct + * + * returns 0 on success, <0 on failure. + * + */ +int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *cb) +{ + int ret; + + if (!dev || !cb) + return -ENODEV; + + ret = mei_io_cb_alloc_resp_buf(cb, dev->iamthif_mtu); + if (ret) + return ret; + + cb->fop_type = MEI_FOP_IOCTL; + + if (!list_empty(&dev->amthif_cmd_list.list) || + dev->iamthif_state != MEI_IAMTHIF_IDLE) { + dev_dbg(&dev->pdev->dev, + "amthif state = %d\n", dev->iamthif_state); + dev_dbg(&dev->pdev->dev, "AMTHIF: add cb to the wait list\n"); + list_add_tail(&cb->list, &dev->amthif_cmd_list.list); + return 0; + } + return mei_amthif_send_cmd(dev, cb); +} +/** + * mei_amthif_run_next_cmd + * + * @dev: the device structure + * + * returns 0 on success, <0 on failure. + */ +void mei_amthif_run_next_cmd(struct mei_device *dev) +{ + struct mei_cl_cb *pos = NULL; + struct mei_cl_cb *next = NULL; + int status; + + if (!dev) + return; + + dev->iamthif_msg_buf_size = 0; + dev->iamthif_msg_buf_index = 0; + dev->iamthif_canceled = false; + dev->iamthif_ioctl = true; + dev->iamthif_state = MEI_IAMTHIF_IDLE; + dev->iamthif_timer = 0; + dev->iamthif_file_object = NULL; + + dev_dbg(&dev->pdev->dev, "complete amthi cmd_list cb.\n"); + + list_for_each_entry_safe(pos, next, &dev->amthif_cmd_list.list, list) { + list_del(&pos->list); + + if (pos->cl && pos->cl == &dev->iamthif_cl) { + status = mei_amthif_send_cmd(dev, pos); + if (status) { + dev_dbg(&dev->pdev->dev, + "amthi write failed status = %d\n", + status); + return; + } + break; + } + } +} + + +unsigned int mei_amthif_poll(struct mei_device *dev, + struct file *file, poll_table *wait) +{ + unsigned int mask = 0; + mutex_unlock(&dev->device_lock); + poll_wait(file, &dev->iamthif_cl.wait, wait); + mutex_lock(&dev->device_lock); + if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE && + dev->iamthif_file_object == file) { + mask |= (POLLIN | POLLRDNORM); + dev_dbg(&dev->pdev->dev, "run next amthi cb\n"); + mei_amthif_run_next_cmd(dev); + } + return mask; +} + + + +/** + * mei_amthif_irq_process_completed - processes completed iamthif operation. + * + * @dev: the device structure. + * @slots: free slots. + * @cb_pos: callback block. + * @cl: private data of the file object. + * @cmpl_list: complete list. + * + * returns 0, OK; otherwise, error. + */ +int mei_amthif_irq_write_complete(struct mei_device *dev, s32 *slots, + struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list) +{ + struct mei_msg_hdr *mei_hdr; + struct mei_cl *cl = cb->cl; + size_t len = dev->iamthif_msg_buf_size - dev->iamthif_msg_buf_index; + size_t msg_slots = mei_data2slots(len); + + mei_hdr = (struct mei_msg_hdr *)&dev->wr_msg_buf[0]; + mei_hdr->host_addr = cl->host_client_id; + mei_hdr->me_addr = cl->me_client_id; + mei_hdr->reserved = 0; + + if (*slots >= msg_slots) { + mei_hdr->length = len; + mei_hdr->msg_complete = 1; + /* Split the message only if we can write the whole host buffer */ + } else if (*slots == dev->hbuf_depth) { + msg_slots = *slots; + len = (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr); + mei_hdr->length = len; + mei_hdr->msg_complete = 0; + } else { + /* wait for next time the host buffer is empty */ + return 0; + } + + dev_dbg(&dev->pdev->dev, "msg: len = %d complete = %d\n", + mei_hdr->length, mei_hdr->msg_complete); + + *slots -= msg_slots; + if (mei_write_message(dev, mei_hdr, + dev->iamthif_msg_buf + dev->iamthif_msg_buf_index, + mei_hdr->length)) { + dev->iamthif_state = MEI_IAMTHIF_IDLE; + cl->status = -ENODEV; + list_del(&cb->list); + return -ENODEV; + } + + if (mei_flow_ctrl_reduce(dev, cl)) + return -ENODEV; + + dev->iamthif_msg_buf_index += mei_hdr->length; + cl->status = 0; + + if (mei_hdr->msg_complete) { + dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL; + dev->iamthif_flow_control_pending = true; + + /* save iamthif cb sent to amthi client */ + cb->buf_idx = dev->iamthif_msg_buf_index; + dev->iamthif_current_cb = cb; + + list_move_tail(&cb->list, &dev->write_waiting_list.list); + } + + + return 0; +} + +/** + * mei_amthif_irq_read_message - read routine after ISR to + * handle the read amthi message + * + * @complete_list: An instance of our list structure + * @dev: the device structure + * @mei_hdr: header of amthi message + * + * returns 0 on success, <0 on failure. + */ +int mei_amthif_irq_read_message(struct mei_cl_cb *complete_list, + struct mei_device *dev, struct mei_msg_hdr *mei_hdr) +{ + struct mei_cl_cb *cb; + unsigned char *buffer; + + BUG_ON(mei_hdr->me_addr != dev->iamthif_cl.me_client_id); + BUG_ON(dev->iamthif_state != MEI_IAMTHIF_READING); + + buffer = dev->iamthif_msg_buf + dev->iamthif_msg_buf_index; + BUG_ON(dev->iamthif_mtu < dev->iamthif_msg_buf_index + mei_hdr->length); + + mei_read_slots(dev, buffer, mei_hdr->length); + + dev->iamthif_msg_buf_index += mei_hdr->length; + + if (!mei_hdr->msg_complete) + return 0; + + dev_dbg(&dev->pdev->dev, + "amthi_message_buffer_index =%d\n", + mei_hdr->length); + + dev_dbg(&dev->pdev->dev, "completed amthi read.\n "); + if (!dev->iamthif_current_cb) + return -ENODEV; + + cb = dev->iamthif_current_cb; + dev->iamthif_current_cb = NULL; + + if (!cb->cl) + return -ENODEV; + + dev->iamthif_stall_timer = 0; + cb->buf_idx = dev->iamthif_msg_buf_index; + cb->read_time = jiffies; + if (dev->iamthif_ioctl && cb->cl == &dev->iamthif_cl) { + /* found the iamthif cb */ + dev_dbg(&dev->pdev->dev, "complete the amthi read cb.\n "); + dev_dbg(&dev->pdev->dev, "add the amthi read cb to complete.\n "); + list_add_tail(&cb->list, &complete_list->list); + } + return 0; +} + +/** + * mei_amthif_irq_read - prepares to read amthif data. + * + * @dev: the device structure. + * @slots: free slots. + * + * returns 0, OK; otherwise, error. + */ +int mei_amthif_irq_read(struct mei_device *dev, s32 *slots) +{ + + if (((*slots) * sizeof(u32)) < (sizeof(struct mei_msg_hdr) + + sizeof(struct hbm_flow_control))) { + return -EMSGSIZE; + } + *slots -= mei_data2slots(sizeof(struct hbm_flow_control)); + if (mei_send_flow_control(dev, &dev->iamthif_cl)) { + dev_dbg(&dev->pdev->dev, "iamthif flow control failed\n"); + return -EIO; + } + + dev_dbg(&dev->pdev->dev, "iamthif flow control success\n"); + dev->iamthif_state = MEI_IAMTHIF_READING; + dev->iamthif_flow_control_pending = false; + dev->iamthif_msg_buf_index = 0; + dev->iamthif_msg_buf_size = 0; + dev->iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER; + dev->mei_host_buffer_is_empty = mei_hbuf_is_empty(dev); + return 0; +} + +/** + * mei_amthif_complete - complete amthif callback. + * + * @dev: the device structure. + * @cb_pos: callback block. + */ +void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb) +{ + if (dev->iamthif_canceled != 1) { + dev->iamthif_state = MEI_IAMTHIF_READ_COMPLETE; + dev->iamthif_stall_timer = 0; + memcpy(cb->response_buffer.data, + dev->iamthif_msg_buf, + dev->iamthif_msg_buf_index); + list_add_tail(&cb->list, &dev->amthif_rd_complete_list.list); + dev_dbg(&dev->pdev->dev, "amthi read completed\n"); + dev->iamthif_timer = jiffies; + dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n", + dev->iamthif_timer); + } else { + mei_amthif_run_next_cmd(dev); + } + + dev_dbg(&dev->pdev->dev, "completing amthi call back.\n"); + wake_up_interruptible(&dev->iamthif_cl.wait); +} + +/** + * mei_clear_list - removes all callbacks associated with file + * from mei_cb_list + * + * @dev: device structure. + * @file: file structure + * @mei_cb_list: callbacks list + * + * mei_clear_list is called to clear resources associated with file + * when application calls close function or Ctrl-C was pressed + * + * returns true if callback removed from the list, false otherwise + */ +static bool mei_clear_list(struct mei_device *dev, + const struct file *file, struct list_head *mei_cb_list) +{ + struct mei_cl_cb *cb_pos = NULL; + struct mei_cl_cb *cb_next = NULL; + bool removed = false; + + /* list all list member */ + list_for_each_entry_safe(cb_pos, cb_next, mei_cb_list, list) { + /* check if list member associated with a file */ + if (file == cb_pos->file_object) { + /* remove member from the list */ + list_del(&cb_pos->list); + /* check if cb equal to current iamthif cb */ + if (dev->iamthif_current_cb == cb_pos) { + dev->iamthif_current_cb = NULL; + /* send flow control to iamthif client */ + mei_send_flow_control(dev, &dev->iamthif_cl); + } + /* free all allocated buffers */ + mei_io_cb_free(cb_pos); + cb_pos = NULL; + removed = true; + } + } + return removed; +} + +/** + * mei_clear_lists - removes all callbacks associated with file + * + * @dev: device structure + * @file: file structure + * + * mei_clear_lists is called to clear resources associated with file + * when application calls close function or Ctrl-C was pressed + * + * returns true if callback removed from the list, false otherwise + */ +static bool mei_clear_lists(struct mei_device *dev, struct file *file) +{ + bool removed = false; + + /* remove callbacks associated with a file */ + mei_clear_list(dev, file, &dev->amthif_cmd_list.list); + if (mei_clear_list(dev, file, &dev->amthif_rd_complete_list.list)) + removed = true; + + mei_clear_list(dev, file, &dev->ctrl_rd_list.list); + + if (mei_clear_list(dev, file, &dev->ctrl_wr_list.list)) + removed = true; + + if (mei_clear_list(dev, file, &dev->write_waiting_list.list)) + removed = true; + + if (mei_clear_list(dev, file, &dev->write_list.list)) + removed = true; + + /* check if iamthif_current_cb not NULL */ + if (dev->iamthif_current_cb && !removed) { + /* check file and iamthif current cb association */ + if (dev->iamthif_current_cb->file_object == file) { + /* remove cb */ + mei_io_cb_free(dev->iamthif_current_cb); + dev->iamthif_current_cb = NULL; + removed = true; + } + } + return removed; +} + +/** +* mei_amthif_release - the release function +* +* @inode: pointer to inode structure +* @file: pointer to file structure +* +* returns 0 on success, <0 on error +*/ +int mei_amthif_release(struct mei_device *dev, struct file *file) +{ + if (dev->open_handle_count > 0) + dev->open_handle_count--; + + if (dev->iamthif_file_object == file && + dev->iamthif_state != MEI_IAMTHIF_IDLE) { + + dev_dbg(&dev->pdev->dev, "amthi canceled iamthif state %d\n", + dev->iamthif_state); + dev->iamthif_canceled = true; + if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE) { + dev_dbg(&dev->pdev->dev, "run next amthi iamthif cb\n"); + mei_amthif_run_next_cmd(dev); + } + } + + if (mei_clear_lists(dev, file)) + dev->iamthif_state = MEI_IAMTHIF_IDLE; + + return 0; +} diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h index 9700532f02f..be8ca6b333c 100644 --- a/drivers/misc/mei/hw.h +++ b/drivers/misc/mei/hw.h @@ -20,16 +20,16 @@ #include <linux/uuid.h> /* - * Timeouts + * Timeouts in Seconds */ -#define MEI_INTEROP_TIMEOUT (HZ * 7) -#define MEI_CONNECT_TIMEOUT 3 /* at least 2 seconds */ +#define MEI_INTEROP_TIMEOUT 7 /* Timeout on ready message */ +#define MEI_CONNECT_TIMEOUT 3 /* HPS: at least 2 seconds */ -#define CONNECT_TIMEOUT 15 /* HPS definition */ -#define INIT_CLIENTS_TIMEOUT 15 /* HPS definition */ +#define MEI_CL_CONNECT_TIMEOUT 15 /* HPS: Client Connect Timeout */ +#define MEI_CLIENTS_INIT_TIMEOUT 15 /* HPS: Clients Enumeration Timeout */ -#define IAMTHIF_STALL_TIMER 12 /* seconds */ -#define IAMTHIF_READ_TIMER 10000 /* ms */ +#define MEI_IAMTHIF_STALL_TIMER 12 /* HPS */ +#define MEI_IAMTHIF_READ_TIMER 10 /* HPS */ /* * Internal Clients Number @@ -293,6 +293,14 @@ struct hbm_props_response { struct mei_client_properties client_properties; } __packed; +/** + * struct hbm_client_connect_request - connect/disconnect request + * + * @hbm_cmd - bus message command header + * @me_addr - address of the client in ME + * @host_addr - address of the client in the driver + * @reserved + */ struct hbm_client_connect_request { u8 hbm_cmd; u8 me_addr; @@ -300,6 +308,14 @@ struct hbm_client_connect_request { u8 reserved; } __packed; +/** + * struct hbm_client_connect_response - connect/disconnect response + * + * @hbm_cmd - bus message command header + * @me_addr - address of the client in ME + * @host_addr - address of the client in the driver + * @status - status of the request + */ struct hbm_client_connect_response { u8 hbm_cmd; u8 me_addr; @@ -307,12 +323,6 @@ struct hbm_client_connect_response { u8 status; } __packed; -struct hbm_client_disconnect_request { - u8 hbm_cmd; - u8 me_addr; - u8 host_addr; - u8 reserved[1]; -} __packed; #define MEI_FC_MESSAGE_RESERVED_LENGTH 5 diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 98f1430e3e1..a54cd5567ca 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -43,21 +43,6 @@ const char *mei_dev_state_str(int state) } -const uuid_le mei_amthi_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, 0xac, - 0xa8, 0x46, 0xe0, 0xff, 0x65, - 0x81, 0x4c); - -/** - * mei_io_list_init - Sets up a queue list. - * - * @list: An instance io list structure - * @dev: the device structure - */ -void mei_io_list_init(struct mei_io_list *list) -{ - /* initialize our queue list */ - INIT_LIST_HEAD(&list->mei_cb.cb_list); -} /** * mei_io_list_flush - removes list entry belonging to cl. @@ -65,17 +50,15 @@ void mei_io_list_init(struct mei_io_list *list) * @list: An instance of our list structure * @cl: private data of the file object */ -void mei_io_list_flush(struct mei_io_list *list, struct mei_cl *cl) +void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl) { struct mei_cl_cb *pos; struct mei_cl_cb *next; - list_for_each_entry_safe(pos, next, &list->mei_cb.cb_list, cb_list) { - if (pos->file_private) { - struct mei_cl *cl_tmp; - cl_tmp = (struct mei_cl *)pos->file_private; - if (mei_cl_cmp_id(cl, cl_tmp)) - list_del(&pos->cb_list); + list_for_each_entry_safe(pos, next, &list->list, list) { + if (pos->cl) { + if (mei_cl_cmp_id(cl, pos->cl)) + list_del(&pos->list); } } } @@ -96,31 +79,14 @@ int mei_cl_flush_queues(struct mei_cl *cl) mei_io_list_flush(&cl->dev->write_waiting_list, cl); mei_io_list_flush(&cl->dev->ctrl_wr_list, cl); mei_io_list_flush(&cl->dev->ctrl_rd_list, cl); - mei_io_list_flush(&cl->dev->amthi_cmd_list, cl); - mei_io_list_flush(&cl->dev->amthi_read_complete_list, cl); + mei_io_list_flush(&cl->dev->amthif_cmd_list, cl); + mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl); return 0; } /** - * mei_reset_iamthif_params - initializes mei device iamthif - * - * @dev: the device structure - */ -static void mei_reset_iamthif_params(struct mei_device *dev) -{ - /* reset iamthif parameters. */ - dev->iamthif_current_cb = NULL; - dev->iamthif_msg_buf_size = 0; - dev->iamthif_msg_buf_index = 0; - dev->iamthif_canceled = false; - dev->iamthif_ioctl = false; - dev->iamthif_state = MEI_IAMTHIF_IDLE; - dev->iamthif_timer = 0; -} - -/** * init_mei_device - allocates and initializes the mei device structure * * @pdev: The pci device structure @@ -144,16 +110,14 @@ struct mei_device *mei_device_init(struct pci_dev *pdev) init_waitqueue_head(&dev->wait_stop_wd); dev->dev_state = MEI_DEV_INITIALIZING; dev->iamthif_state = MEI_IAMTHIF_IDLE; - dev->wd_interface_reg = false; - mei_io_list_init(&dev->read_list); mei_io_list_init(&dev->write_list); mei_io_list_init(&dev->write_waiting_list); mei_io_list_init(&dev->ctrl_wr_list); mei_io_list_init(&dev->ctrl_rd_list); - mei_io_list_init(&dev->amthi_cmd_list); - mei_io_list_init(&dev->amthi_read_complete_list); + mei_io_list_init(&dev->amthif_cmd_list); + mei_io_list_init(&dev->amthif_rd_complete_list); dev->pdev = pdev; return dev; } @@ -196,7 +160,8 @@ int mei_hw_init(struct mei_device *dev) if (!dev->recvd_msg) { mutex_unlock(&dev->device_lock); err = wait_event_interruptible_timeout(dev->wait_recvd_msg, - dev->recvd_msg, MEI_INTEROP_TIMEOUT); + dev->recvd_msg, + mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT)); mutex_lock(&dev->device_lock); } @@ -317,15 +282,13 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) cl_pos->timer_count = 0; } /* remove entry if already in list */ - dev_dbg(&dev->pdev->dev, "list del iamthif and wd file list.\n"); - mei_remove_client_from_file_list(dev, - dev->wd_cl.host_client_id); + dev_dbg(&dev->pdev->dev, "remove iamthif and wd from the file list.\n"); + mei_me_cl_unlink(dev, &dev->wd_cl); - mei_remove_client_from_file_list(dev, - dev->iamthif_cl.host_client_id); + mei_me_cl_unlink(dev, &dev->iamthif_cl); - mei_reset_iamthif_params(dev); - dev->extra_write_index = 0; + mei_amthif_reset_params(dev); + memset(&dev->wr_ext_msg, 0, sizeof(dev->wr_ext_msg)); } dev->me_clients_num = 0; @@ -351,10 +314,9 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) } } /* remove all waiting requests */ - list_for_each_entry_safe(cb_pos, cb_next, - &dev->write_list.mei_cb.cb_list, cb_list) { - list_del(&cb_pos->cb_list); - mei_free_cb_private(cb_pos); + list_for_each_entry_safe(cb_pos, cb_next, &dev->write_list.list, list) { + list_del(&cb_pos->list); + mei_io_cb_free(cb_pos); } } @@ -370,31 +332,26 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) void mei_host_start_message(struct mei_device *dev) { struct mei_msg_hdr *mei_hdr; - struct hbm_host_version_request *host_start_req; + struct hbm_host_version_request *start_req; + const size_t len = sizeof(struct hbm_host_version_request); + + mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len); /* host start message */ - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = sizeof(struct hbm_host_version_request); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - - host_start_req = - (struct hbm_host_version_request *) &dev->wr_msg_buf[1]; - memset(host_start_req, 0, sizeof(struct hbm_host_version_request)); - host_start_req->hbm_cmd = HOST_START_REQ_CMD; - host_start_req->host_version.major_version = HBM_MAJOR_VERSION; - host_start_req->host_version.minor_version = HBM_MINOR_VERSION; + start_req = (struct hbm_host_version_request *)&dev->wr_msg_buf[1]; + memset(start_req, 0, len); + start_req->hbm_cmd = HOST_START_REQ_CMD; + start_req->host_version.major_version = HBM_MAJOR_VERSION; + start_req->host_version.minor_version = HBM_MINOR_VERSION; + dev->recvd_msg = false; - if (mei_write_message(dev, mei_hdr, (unsigned char *)host_start_req, - mei_hdr->length)) { + if (mei_write_message(dev, mei_hdr, (unsigned char *)start_req, len)) { dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n"); dev->dev_state = MEI_DEV_RESETING; mei_reset(dev, 1); } dev->init_clients_state = MEI_START_MESSAGE; - dev->init_clients_timer = INIT_CLIENTS_TIMEOUT; + dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; return ; } @@ -408,26 +365,22 @@ void mei_host_start_message(struct mei_device *dev) void mei_host_enum_clients_message(struct mei_device *dev) { struct mei_msg_hdr *mei_hdr; - struct hbm_host_enum_request *host_enum_req; - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; + struct hbm_host_enum_request *enum_req; + const size_t len = sizeof(struct hbm_host_enum_request); /* enumerate clients */ - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = sizeof(struct hbm_host_enum_request); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - - host_enum_req = (struct hbm_host_enum_request *) &dev->wr_msg_buf[1]; - memset(host_enum_req, 0, sizeof(struct hbm_host_enum_request)); - host_enum_req->hbm_cmd = HOST_ENUM_REQ_CMD; - if (mei_write_message(dev, mei_hdr, (unsigned char *)host_enum_req, - mei_hdr->length)) { + mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len); + + enum_req = (struct hbm_host_enum_request *) &dev->wr_msg_buf[1]; + memset(enum_req, 0, sizeof(struct hbm_host_enum_request)); + enum_req->hbm_cmd = HOST_ENUM_REQ_CMD; + + if (mei_write_message(dev, mei_hdr, (unsigned char *)enum_req, len)) { dev->dev_state = MEI_DEV_RESETING; dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n"); mei_reset(dev, 1); } dev->init_clients_state = MEI_ENUM_CLIENTS_MESSAGE; - dev->init_clients_timer = INIT_CLIENTS_TIMEOUT; + dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; return; } @@ -470,56 +423,87 @@ void mei_allocate_me_clients_storage(struct mei_device *dev) dev->me_clients = clients; return ; } -/** - * host_client_properties - reads properties for client - * - * @dev: the device structure - * - * returns: - * < 0 - Error. - * = 0 - no more clients. - * = 1 - still have clients to send properties request. - */ -int mei_host_client_properties(struct mei_device *dev) + +void mei_host_client_init(struct work_struct *work) { - struct mei_msg_hdr *mei_header; - struct hbm_props_request *host_cli_req; - int b; - u8 client_num = dev->me_client_presentation_num; - - b = dev->me_client_index; - b = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX, b); - if (b < MEI_CLIENTS_MAX) { - dev->me_clients[client_num].client_id = b; - dev->me_clients[client_num].mei_flow_ctrl_creds = 0; - mei_header = (struct mei_msg_hdr *)&dev->wr_msg_buf[0]; - mei_header->host_addr = 0; - mei_header->me_addr = 0; - mei_header->length = sizeof(struct hbm_props_request); - mei_header->msg_complete = 1; - mei_header->reserved = 0; - - host_cli_req = (struct hbm_props_request *)&dev->wr_msg_buf[1]; - - memset(host_cli_req, 0, sizeof(struct hbm_props_request)); - - host_cli_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD; - host_cli_req->address = b; - - if (mei_write_message(dev, mei_header, - (unsigned char *)host_cli_req, - mei_header->length)) { - dev->dev_state = MEI_DEV_RESETING; - dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n"); - mei_reset(dev, 1); - return -EIO; - } + struct mei_device *dev = container_of(work, + struct mei_device, init_work); + struct mei_client_properties *client_props; + int i; + + mutex_lock(&dev->device_lock); + + bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX); + dev->open_handle_count = 0; + + /* + * Reserving the first three client IDs + * 0: Reserved for MEI Bus Message communications + * 1: Reserved for Watchdog + * 2: Reserved for AMTHI + */ + bitmap_set(dev->host_clients_map, 0, 3); + + for (i = 0; i < dev->me_clients_num; i++) { + client_props = &dev->me_clients[i].props; + + if (!uuid_le_cmp(client_props->protocol_name, mei_amthi_guid)) + mei_amthif_host_init(dev); + else if (!uuid_le_cmp(client_props->protocol_name, mei_wd_guid)) + mei_wd_host_init(dev); + } + + dev->dev_state = MEI_DEV_ENABLED; - dev->init_clients_timer = INIT_CLIENTS_TIMEOUT; - dev->me_client_index = b; - return 1; + mutex_unlock(&dev->device_lock); +} + +int mei_host_client_enumerate(struct mei_device *dev) +{ + + struct mei_msg_hdr *mei_hdr; + struct hbm_props_request *prop_req; + const size_t len = sizeof(struct hbm_props_request); + unsigned long next_client_index; + u8 client_num; + + + client_num = dev->me_client_presentation_num; + + next_client_index = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX, + dev->me_client_index); + + /* We got all client properties */ + if (next_client_index == MEI_CLIENTS_MAX) { + schedule_work(&dev->init_work); + + return 0; } + dev->me_clients[client_num].client_id = next_client_index; + dev->me_clients[client_num].mei_flow_ctrl_creds = 0; + + mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len); + prop_req = (struct hbm_props_request *)&dev->wr_msg_buf[1]; + + memset(prop_req, 0, sizeof(struct hbm_props_request)); + + + prop_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD; + prop_req->address = next_client_index; + + if (mei_write_message(dev, mei_hdr, (unsigned char *) prop_req, + mei_hdr->length)) { + dev->dev_state = MEI_DEV_RESETING; + dev_err(&dev->pdev->dev, "Properties request command failed\n"); + mei_reset(dev, 1); + + return -EIO; + } + + dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; + dev->me_client_index = next_client_index; + return 0; } @@ -557,17 +541,20 @@ int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *cuuid) /** - * mei_me_cl_update_filext - searches for ME client guid - * sets client_id in mei_file_private if found + * mei_me_cl_link - create link between host and me clinet and add + * me_cl to the list + * * @dev: the device structure - * @cl: private file structure to set client_id in - * @cuuid: searched uuid of ME client - * @client_id: id of host client to be set in file private structure + * @cl: link between me and host client assocated with opened file descriptor + * @cuuid: uuid of ME client + * @client_id: id of the host client * - * returns ME client index + * returns ME client index if ME client + * -EINVAL on incorrect values + * -ENONET if client not found */ -int mei_me_cl_update_filext(struct mei_device *dev, struct mei_cl *cl, - const uuid_le *cuuid, u8 host_cl_id) +int mei_me_cl_link(struct mei_device *dev, struct mei_cl *cl, + const uuid_le *cuuid, u8 host_cl_id) { int i; @@ -587,54 +574,22 @@ int mei_me_cl_update_filext(struct mei_device *dev, struct mei_cl *cl, return -ENOENT; } - /** - * host_init_iamthif - mei initialization iamthif client. + * mei_me_cl_unlink - remove me_cl from the list * * @dev: the device structure - * + * @host_client_id: host client id to be removed */ -void mei_host_init_iamthif(struct mei_device *dev) +void mei_me_cl_unlink(struct mei_device *dev, struct mei_cl *cl) { - int i; - unsigned char *msg_buf; - - mei_cl_init(&dev->iamthif_cl, dev); - dev->iamthif_cl.state = MEI_FILE_DISCONNECTED; - - /* find ME amthi client */ - i = mei_me_cl_update_filext(dev, &dev->iamthif_cl, - &mei_amthi_guid, MEI_IAMTHIF_HOST_CLIENT_ID); - if (i < 0) { - dev_dbg(&dev->pdev->dev, "failed to find iamthif client.\n"); - return; - } - - /* Assign iamthif_mtu to the value received from ME */ - - dev->iamthif_mtu = dev->me_clients[i].props.max_msg_length; - dev_dbg(&dev->pdev->dev, "IAMTHIF_MTU = %d\n", - dev->me_clients[i].props.max_msg_length); - - kfree(dev->iamthif_msg_buf); - dev->iamthif_msg_buf = NULL; - - /* allocate storage for ME message buffer */ - msg_buf = kcalloc(dev->iamthif_mtu, - sizeof(unsigned char), GFP_KERNEL); - if (!msg_buf) { - dev_dbg(&dev->pdev->dev, "memory allocation for ME message buffer failed.\n"); - return; - } - - dev->iamthif_msg_buf = msg_buf; - - if (mei_connect(dev, &dev->iamthif_cl)) { - dev_dbg(&dev->pdev->dev, "Failed to connect to AMTHI client\n"); - dev->iamthif_cl.state = MEI_FILE_DISCONNECTED; - dev->iamthif_cl.host_client_id = 0; - } else { - dev->iamthif_cl.timer_count = CONNECT_TIMEOUT; + struct mei_cl *pos, *next; + list_for_each_entry_safe(pos, next, &dev->file_list, link) { + if (cl->host_client_id == pos->host_client_id) { + dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n", + pos->host_client_id, pos->me_client_id); + list_del_init(&pos->link); + break; + } } } @@ -671,9 +626,8 @@ struct mei_cl *mei_cl_allocate(struct mei_device *dev) */ int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) { - int rets, err; - long timeout = 15; /* 15 seconds */ struct mei_cl_cb *cb; + int rets, err; if (!dev || !cl) return -ENODEV; @@ -681,13 +635,11 @@ int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) if (cl->state != MEI_FILE_DISCONNECTING) return 0; - cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); + cb = mei_io_cb_init(cl, NULL); if (!cb) return -ENOMEM; - INIT_LIST_HEAD(&cb->cb_list); - cb->file_private = cl; - cb->major_file_operations = MEI_CLOSE; + cb->fop_type = MEI_FOP_CLOSE; if (dev->mei_host_buffer_is_empty) { dev->mei_host_buffer_is_empty = false; if (mei_disconnect(dev, cl)) { @@ -696,17 +648,17 @@ int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) goto free; } mdelay(10); /* Wait for hardware disconnection ready */ - list_add_tail(&cb->cb_list, &dev->ctrl_rd_list.mei_cb.cb_list); + list_add_tail(&cb->list, &dev->ctrl_rd_list.list); } else { dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n"); - list_add_tail(&cb->cb_list, - &dev->ctrl_wr_list.mei_cb.cb_list); + list_add_tail(&cb->list, &dev->ctrl_wr_list.list); + } mutex_unlock(&dev->device_lock); err = wait_event_timeout(dev->wait_recvd_msg, - (MEI_FILE_DISCONNECTED == cl->state), - timeout * HZ); + MEI_FILE_DISCONNECTED == cl->state, + mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT)); mutex_lock(&dev->device_lock); if (MEI_FILE_DISCONNECTED == cl->state) { @@ -728,29 +680,7 @@ int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) mei_io_list_flush(&dev->ctrl_rd_list, cl); mei_io_list_flush(&dev->ctrl_wr_list, cl); free: - mei_free_cb_private(cb); + mei_io_cb_free(cb); return rets; } -/** - * mei_remove_client_from_file_list - - * removes file private data from device file list - * - * @dev: the device structure - * @host_client_id: host client id to be removed - */ -void mei_remove_client_from_file_list(struct mei_device *dev, - u8 host_client_id) -{ - struct mei_cl *cl_pos = NULL; - struct mei_cl *cl_next = NULL; - list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) { - if (host_client_id == cl_pos->host_client_id) { - dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n", - cl_pos->host_client_id, - cl_pos->me_client_id); - list_del_init(&cl_pos->link); - break; - } - } -} diff --git a/drivers/misc/mei/interface.c b/drivers/misc/mei/interface.c index 509c3957ff4..8de85478596 100644 --- a/drivers/misc/mei/interface.c +++ b/drivers/misc/mei/interface.c @@ -292,28 +292,23 @@ int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl) int mei_send_flow_control(struct mei_device *dev, struct mei_cl *cl) { struct mei_msg_hdr *mei_hdr; - struct hbm_flow_control *mei_flow_control; - - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = sizeof(struct hbm_flow_control); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - - mei_flow_control = (struct hbm_flow_control *) &dev->wr_msg_buf[1]; - memset(mei_flow_control, 0, sizeof(*mei_flow_control)); - mei_flow_control->host_addr = cl->host_client_id; - mei_flow_control->me_addr = cl->me_client_id; - mei_flow_control->hbm_cmd = MEI_FLOW_CONTROL_CMD; - memset(mei_flow_control->reserved, 0, - sizeof(mei_flow_control->reserved)); + struct hbm_flow_control *flow_ctrl; + const size_t len = sizeof(struct hbm_flow_control); + + mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len); + + flow_ctrl = (struct hbm_flow_control *)&dev->wr_msg_buf[1]; + memset(flow_ctrl, 0, len); + flow_ctrl->hbm_cmd = MEI_FLOW_CONTROL_CMD; + flow_ctrl->host_addr = cl->host_client_id; + flow_ctrl->me_addr = cl->me_client_id; + /* FIXME: reserved !? */ + memset(flow_ctrl->reserved, 0, sizeof(flow_ctrl->reserved)); dev_dbg(&dev->pdev->dev, "sending flow control host client = %d, ME client = %d\n", cl->host_client_id, cl->me_client_id); return mei_write_message(dev, mei_hdr, - (unsigned char *) mei_flow_control, - sizeof(struct hbm_flow_control)); + (unsigned char *) flow_ctrl, len); } /** @@ -352,26 +347,19 @@ int mei_other_client_is_connecting(struct mei_device *dev, int mei_disconnect(struct mei_device *dev, struct mei_cl *cl) { struct mei_msg_hdr *mei_hdr; - struct hbm_client_disconnect_request *mei_cli_disconnect; - - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = sizeof(struct hbm_client_disconnect_request); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - - mei_cli_disconnect = - (struct hbm_client_disconnect_request *) &dev->wr_msg_buf[1]; - memset(mei_cli_disconnect, 0, sizeof(*mei_cli_disconnect)); - mei_cli_disconnect->host_addr = cl->host_client_id; - mei_cli_disconnect->me_addr = cl->me_client_id; - mei_cli_disconnect->hbm_cmd = CLIENT_DISCONNECT_REQ_CMD; - mei_cli_disconnect->reserved[0] = 0; + struct hbm_client_connect_request *req; + const size_t len = sizeof(struct hbm_client_connect_request); - return mei_write_message(dev, mei_hdr, - (unsigned char *) mei_cli_disconnect, - sizeof(struct hbm_client_disconnect_request)); + mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len); + + req = (struct hbm_client_connect_request *)&dev->wr_msg_buf[1]; + memset(req, 0, len); + req->hbm_cmd = CLIENT_DISCONNECT_REQ_CMD; + req->host_addr = cl->host_client_id; + req->me_addr = cl->me_client_id; + req->reserved = 0; + + return mei_write_message(dev, mei_hdr, (unsigned char *)req, len); } /** @@ -385,23 +373,16 @@ int mei_disconnect(struct mei_device *dev, struct mei_cl *cl) int mei_connect(struct mei_device *dev, struct mei_cl *cl) { struct mei_msg_hdr *mei_hdr; - struct hbm_client_connect_request *mei_cli_connect; - - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = sizeof(struct hbm_client_connect_request); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - - mei_cli_connect = - (struct hbm_client_connect_request *) &dev->wr_msg_buf[1]; - mei_cli_connect->host_addr = cl->host_client_id; - mei_cli_connect->me_addr = cl->me_client_id; - mei_cli_connect->hbm_cmd = CLIENT_CONNECT_REQ_CMD; - mei_cli_connect->reserved = 0; + struct hbm_client_connect_request *req; + const size_t len = sizeof(struct hbm_client_connect_request); - return mei_write_message(dev, mei_hdr, - (unsigned char *) mei_cli_connect, - sizeof(struct hbm_client_connect_request)); + mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len); + + req = (struct hbm_client_connect_request *) &dev->wr_msg_buf[1]; + req->hbm_cmd = CLIENT_CONNECT_REQ_CMD; + req->host_addr = cl->host_client_id; + req->me_addr = cl->me_client_id; + req->reserved = 0; + + return mei_write_message(dev, mei_hdr, (unsigned char *) req, len); } diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 3533edde04a..04fa2134615 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -57,14 +57,14 @@ irqreturn_t mei_interrupt_quick_handler(int irq, void *dev_id) */ static void _mei_cmpl(struct mei_cl *cl, struct mei_cl_cb *cb_pos) { - if (cb_pos->major_file_operations == MEI_WRITE) { - mei_free_cb_private(cb_pos); + if (cb_pos->fop_type == MEI_FOP_WRITE) { + mei_io_cb_free(cb_pos); cb_pos = NULL; cl->writing_state = MEI_WRITE_COMPLETE; if (waitqueue_active(&cl->tx_wait)) wake_up_interruptible(&cl->tx_wait); - } else if (cb_pos->major_file_operations == MEI_READ && + } else if (cb_pos->fop_type == MEI_FOP_READ && MEI_READING == cl->reading_state) { cl->reading_state = MEI_READ_COMPLETE; if (waitqueue_active(&cl->rx_wait)) @@ -74,94 +74,6 @@ static void _mei_cmpl(struct mei_cl *cl, struct mei_cl_cb *cb_pos) } /** - * _mei_cmpl_iamthif - processes completed iamthif operation. - * - * @dev: the device structure. - * @cb_pos: callback block. - */ -static void _mei_cmpl_iamthif(struct mei_device *dev, struct mei_cl_cb *cb_pos) -{ - if (dev->iamthif_canceled != 1) { - dev->iamthif_state = MEI_IAMTHIF_READ_COMPLETE; - dev->iamthif_stall_timer = 0; - memcpy(cb_pos->response_buffer.data, - dev->iamthif_msg_buf, - dev->iamthif_msg_buf_index); - list_add_tail(&cb_pos->cb_list, - &dev->amthi_read_complete_list.mei_cb.cb_list); - dev_dbg(&dev->pdev->dev, "amthi read completed.\n"); - dev->iamthif_timer = jiffies; - dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n", - dev->iamthif_timer); - } else { - mei_run_next_iamthif_cmd(dev); - } - - dev_dbg(&dev->pdev->dev, "completing amthi call back.\n"); - wake_up_interruptible(&dev->iamthif_cl.wait); -} - - -/** - * mei_irq_thread_read_amthi_message - bottom half read routine after ISR to - * handle the read amthi message data processing. - * - * @complete_list: An instance of our list structure - * @dev: the device structure - * @mei_hdr: header of amthi message - * - * returns 0 on success, <0 on failure. - */ -static int mei_irq_thread_read_amthi_message(struct mei_io_list *complete_list, - struct mei_device *dev, - struct mei_msg_hdr *mei_hdr) -{ - struct mei_cl *cl; - struct mei_cl_cb *cb; - unsigned char *buffer; - - BUG_ON(mei_hdr->me_addr != dev->iamthif_cl.me_client_id); - BUG_ON(dev->iamthif_state != MEI_IAMTHIF_READING); - - buffer = dev->iamthif_msg_buf + dev->iamthif_msg_buf_index; - BUG_ON(dev->iamthif_mtu < dev->iamthif_msg_buf_index + mei_hdr->length); - - mei_read_slots(dev, buffer, mei_hdr->length); - - dev->iamthif_msg_buf_index += mei_hdr->length; - - if (!mei_hdr->msg_complete) - return 0; - - dev_dbg(&dev->pdev->dev, - "amthi_message_buffer_index =%d\n", - mei_hdr->length); - - dev_dbg(&dev->pdev->dev, "completed amthi read.\n "); - if (!dev->iamthif_current_cb) - return -ENODEV; - - cb = dev->iamthif_current_cb; - dev->iamthif_current_cb = NULL; - - cl = (struct mei_cl *)cb->file_private; - if (!cl) - return -ENODEV; - - dev->iamthif_stall_timer = 0; - cb->information = dev->iamthif_msg_buf_index; - cb->read_time = jiffies; - if (dev->iamthif_ioctl && cl == &dev->iamthif_cl) { - /* found the iamthif cb */ - dev_dbg(&dev->pdev->dev, "complete the amthi read cb.\n "); - dev_dbg(&dev->pdev->dev, "add the amthi read cb to complete.\n "); - list_add_tail(&cb->cb_list, - &complete_list->mei_cb.cb_list); - } - return 0; -} - -/** * _mei_irq_thread_state_ok - checks if mei header matches file private data * * @cl: private data of the file object @@ -188,7 +100,7 @@ static int _mei_irq_thread_state_ok(struct mei_cl *cl, * * returns 0 on success, <0 on failure. */ -static int mei_irq_thread_read_client_message(struct mei_io_list *complete_list, +static int mei_irq_thread_read_client_message(struct mei_cl_cb *complete_list, struct mei_device *dev, struct mei_msg_hdr *mei_hdr) { @@ -197,36 +109,36 @@ static int mei_irq_thread_read_client_message(struct mei_io_list *complete_list, unsigned char *buffer = NULL; dev_dbg(&dev->pdev->dev, "start client msg\n"); - if (list_empty(&dev->read_list.mei_cb.cb_list)) + if (list_empty(&dev->read_list.list)) goto quit; - list_for_each_entry_safe(cb_pos, cb_next, - &dev->read_list.mei_cb.cb_list, cb_list) { - cl = (struct mei_cl *)cb_pos->file_private; + list_for_each_entry_safe(cb_pos, cb_next, &dev->read_list.list, list) { + cl = cb_pos->cl; if (cl && _mei_irq_thread_state_ok(cl, mei_hdr)) { cl->reading_state = MEI_READING; - buffer = cb_pos->response_buffer.data + cb_pos->information; + buffer = cb_pos->response_buffer.data + cb_pos->buf_idx; if (cb_pos->response_buffer.size < - mei_hdr->length + cb_pos->information) { + mei_hdr->length + cb_pos->buf_idx) { dev_dbg(&dev->pdev->dev, "message overflow.\n"); - list_del(&cb_pos->cb_list); + list_del(&cb_pos->list); return -ENOMEM; } if (buffer) mei_read_slots(dev, buffer, mei_hdr->length); - cb_pos->information += mei_hdr->length; + cb_pos->buf_idx += mei_hdr->length; if (mei_hdr->msg_complete) { cl->status = 0; - list_del(&cb_pos->cb_list); + list_del(&cb_pos->list); dev_dbg(&dev->pdev->dev, "completed read H cl = %d, ME cl = %d, length = %lu\n", cl->host_client_id, cl->me_client_id, - cb_pos->information); - list_add_tail(&cb_pos->cb_list, - &complete_list->mei_cb.cb_list); + cb_pos->buf_idx); + + list_add_tail(&cb_pos->list, + &complete_list->list); } break; @@ -246,37 +158,6 @@ quit: } /** - * _mei_irq_thread_iamthif_read - prepares to read iamthif data. - * - * @dev: the device structure. - * @slots: free slots. - * - * returns 0, OK; otherwise, error. - */ -static int _mei_irq_thread_iamthif_read(struct mei_device *dev, s32 *slots) -{ - - if (((*slots) * sizeof(u32)) < (sizeof(struct mei_msg_hdr) - + sizeof(struct hbm_flow_control))) { - return -EMSGSIZE; - } - *slots -= mei_data2slots(sizeof(struct hbm_flow_control)); - if (mei_send_flow_control(dev, &dev->iamthif_cl)) { - dev_dbg(&dev->pdev->dev, "iamthif flow control failed\n"); - return -EIO; - } - - dev_dbg(&dev->pdev->dev, "iamthif flow control success\n"); - dev->iamthif_state = MEI_IAMTHIF_READING; - dev->iamthif_flow_control_pending = false; - dev->iamthif_msg_buf_index = 0; - dev->iamthif_msg_buf_size = 0; - dev->iamthif_stall_timer = IAMTHIF_STALL_TIMER; - dev->mei_host_buffer_is_empty = mei_hbuf_is_empty(dev); - return 0; -} - -/** * _mei_irq_thread_close - processes close related operation. * * @dev: the device structure. @@ -290,26 +171,24 @@ static int _mei_irq_thread_iamthif_read(struct mei_device *dev, s32 *slots) static int _mei_irq_thread_close(struct mei_device *dev, s32 *slots, struct mei_cl_cb *cb_pos, struct mei_cl *cl, - struct mei_io_list *cmpl_list) + struct mei_cl_cb *cmpl_list) { if ((*slots * sizeof(u32)) < (sizeof(struct mei_msg_hdr) + - sizeof(struct hbm_client_disconnect_request))) + sizeof(struct hbm_client_connect_request))) return -EBADMSG; - *slots -= mei_data2slots(sizeof(struct hbm_client_disconnect_request)); + *slots -= mei_data2slots(sizeof(struct hbm_client_connect_request)); if (mei_disconnect(dev, cl)) { cl->status = 0; - cb_pos->information = 0; - list_move_tail(&cb_pos->cb_list, - &cmpl_list->mei_cb.cb_list); + cb_pos->buf_idx = 0; + list_move_tail(&cb_pos->list, &cmpl_list->list); return -EMSGSIZE; } else { cl->state = MEI_FILE_DISCONNECTING; cl->status = 0; - cb_pos->information = 0; - list_move_tail(&cb_pos->cb_list, - &dev->ctrl_rd_list.mei_cb.cb_list); + cb_pos->buf_idx = 0; + list_move_tail(&cb_pos->list, &dev->ctrl_rd_list.list); cl->timer_count = MEI_CONNECT_TIMEOUT; } @@ -356,7 +235,7 @@ static void mei_client_connect_response(struct mei_device *dev, { struct mei_cl *cl; - struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL; + struct mei_cl_cb *pos = NULL, *next = NULL; dev_dbg(&dev->pdev->dev, "connect_response:\n" @@ -373,8 +252,6 @@ static void mei_client_connect_response(struct mei_device *dev, dev_dbg(&dev->pdev->dev, "successfully connected to WD client.\n"); mei_watchdog_register(dev); - /* next step in the state maching */ - mei_host_init_iamthif(dev); return; } @@ -382,17 +259,16 @@ static void mei_client_connect_response(struct mei_device *dev, dev->iamthif_state = MEI_IAMTHIF_IDLE; return; } - list_for_each_entry_safe(cb_pos, cb_next, - &dev->ctrl_rd_list.mei_cb.cb_list, cb_list) { + list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) { - cl = (struct mei_cl *)cb_pos->file_private; + cl = pos->cl; if (!cl) { - list_del(&cb_pos->cb_list); + list_del(&pos->list); return; } - if (MEI_IOCTL == cb_pos->major_file_operations) { + if (pos->fop_type == MEI_FOP_IOCTL) { if (is_treat_specially_client(cl, rs)) { - list_del(&cb_pos->cb_list); + list_del(&pos->list); cl->status = 0; cl->timer_count = 0; break; @@ -411,7 +287,7 @@ static void mei_client_disconnect_response(struct mei_device *dev, struct hbm_client_connect_response *rs) { struct mei_cl *cl; - struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL; + struct mei_cl_cb *pos = NULL, *next = NULL; dev_dbg(&dev->pdev->dev, "disconnect_response:\n" @@ -422,12 +298,11 @@ static void mei_client_disconnect_response(struct mei_device *dev, rs->host_addr, rs->status); - list_for_each_entry_safe(cb_pos, cb_next, - &dev->ctrl_rd_list.mei_cb.cb_list, cb_list) { - cl = (struct mei_cl *)cb_pos->file_private; + list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) { + cl = pos->cl; if (!cl) { - list_del(&cb_pos->cb_list); + list_del(&pos->list); return; } @@ -435,7 +310,7 @@ static void mei_client_disconnect_response(struct mei_device *dev, if (cl->host_client_id == rs->host_addr && cl->me_client_id == rs->me_addr) { - list_del(&cb_pos->cb_list); + list_del(&pos->list); if (!rs->status) cl->state = MEI_FILE_DISCONNECTED; @@ -537,10 +412,10 @@ static void mei_client_flow_control_response(struct mei_device *dev, * returns !=0, same; 0,not. */ static int same_disconn_addr(struct mei_cl *cl, - struct hbm_client_disconnect_request *disconn) + struct hbm_client_connect_request *req) { - return (cl->host_client_id == disconn->host_addr && - cl->me_client_id == disconn->me_addr); + return (cl->host_client_id == req->host_addr && + cl->me_client_id == req->me_addr); } /** @@ -550,49 +425,38 @@ static int same_disconn_addr(struct mei_cl *cl, * @disconnect_req: disconnect request bus message. */ static void mei_client_disconnect_request(struct mei_device *dev, - struct hbm_client_disconnect_request *disconnect_req) + struct hbm_client_connect_request *disconnect_req) { - struct mei_msg_hdr *mei_hdr; struct hbm_client_connect_response *disconnect_res; - struct mei_cl *cl_pos = NULL; - struct mei_cl *cl_next = NULL; + struct mei_cl *pos, *next; + const size_t len = sizeof(struct hbm_client_connect_response); - list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) { - if (same_disconn_addr(cl_pos, disconnect_req)) { + list_for_each_entry_safe(pos, next, &dev->file_list, link) { + if (same_disconn_addr(pos, disconnect_req)) { dev_dbg(&dev->pdev->dev, "disconnect request host client %d ME client %d.\n", disconnect_req->host_addr, disconnect_req->me_addr); - cl_pos->state = MEI_FILE_DISCONNECTED; - cl_pos->timer_count = 0; - if (cl_pos == &dev->wd_cl) + pos->state = MEI_FILE_DISCONNECTED; + pos->timer_count = 0; + if (pos == &dev->wd_cl) dev->wd_pending = false; - else if (cl_pos == &dev->iamthif_cl) + else if (pos == &dev->iamthif_cl) dev->iamthif_timer = 0; /* prepare disconnect response */ - mei_hdr = - (struct mei_msg_hdr *) &dev->ext_msg_buf[0]; - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = - sizeof(struct hbm_client_connect_response); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - + (void)mei_hbm_hdr((u32 *)&dev->wr_ext_msg.hdr, len); disconnect_res = (struct hbm_client_connect_response *) - &dev->ext_msg_buf[1]; - disconnect_res->host_addr = cl_pos->host_client_id; - disconnect_res->me_addr = cl_pos->me_client_id; + &dev->wr_ext_msg.data; disconnect_res->hbm_cmd = CLIENT_DISCONNECT_RES_CMD; + disconnect_res->host_addr = pos->host_client_id; + disconnect_res->me_addr = pos->me_client_id; disconnect_res->status = 0; - dev->extra_write_index = 2; break; } } } - /** * mei_irq_thread_read_bus_message - bottom half read routine after ISR to * handle the read bus message cmd processing. @@ -604,16 +468,15 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, struct mei_msg_hdr *mei_hdr) { struct mei_bus_message *mei_msg; + struct mei_me_client *me_client; struct hbm_host_version_response *version_res; struct hbm_client_connect_response *connect_res; struct hbm_client_connect_response *disconnect_res; + struct hbm_client_connect_request *disconnect_req; struct hbm_flow_control *flow_control; struct hbm_props_response *props_res; struct hbm_host_enum_response *enum_res; - struct hbm_client_disconnect_request *disconnect_req; - struct hbm_host_stop_request *host_stop_req; - int res; - + struct hbm_host_stop_request *stop_req; /* read the message to our buffer */ BUG_ON(mei_hdr->length >= sizeof(dev->rd_msg_buf)); @@ -637,26 +500,20 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, return; } } else { + u32 *buf = dev->wr_msg_buf; + const size_t len = sizeof(struct hbm_host_stop_request); + dev->version = version_res->me_max_version; + /* send stop message */ - mei_hdr = (struct mei_msg_hdr *)&dev->wr_msg_buf[0]; - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = sizeof(struct hbm_host_stop_request); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - - host_stop_req = (struct hbm_host_stop_request *) - &dev->wr_msg_buf[1]; - - memset(host_stop_req, - 0, - sizeof(struct hbm_host_stop_request)); - host_stop_req->hbm_cmd = HOST_STOP_REQ_CMD; - host_stop_req->reason = DRIVER_STOP_REQUEST; + mei_hdr = mei_hbm_hdr(&buf[0], len); + stop_req = (struct hbm_host_stop_request *)&buf[1]; + memset(stop_req, 0, len); + stop_req->hbm_cmd = HOST_STOP_REQ_CMD; + stop_req->reason = DRIVER_STOP_REQUEST; + mei_write_message(dev, mei_hdr, - (unsigned char *) (host_stop_req), - mei_hdr->length); + (unsigned char *)stop_req, len); dev_dbg(&dev->pdev->dev, "version mismatch.\n"); return; } @@ -666,16 +523,14 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, break; case CLIENT_CONNECT_RES_CMD: - connect_res = - (struct hbm_client_connect_response *) mei_msg; + connect_res = (struct hbm_client_connect_response *) mei_msg; mei_client_connect_response(dev, connect_res); dev_dbg(&dev->pdev->dev, "client connect response message received.\n"); wake_up(&dev->wait_recvd_msg); break; case CLIENT_DISCONNECT_RES_CMD: - disconnect_res = - (struct hbm_client_connect_response *) mei_msg; + disconnect_res = (struct hbm_client_connect_response *) mei_msg; mei_client_disconnect_response(dev, disconnect_res); dev_dbg(&dev->pdev->dev, "client disconnect response message received.\n"); wake_up(&dev->wait_recvd_msg); @@ -689,64 +544,37 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, case HOST_CLIENT_PROPERTIES_RES_CMD: props_res = (struct hbm_props_response *)mei_msg; + me_client = &dev->me_clients[dev->me_client_presentation_num]; + if (props_res->status || !dev->me_clients) { dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message wrong status.\n"); mei_reset(dev, 1); return; } - if (dev->me_clients[dev->me_client_presentation_num] - .client_id == props_res->address) { - dev->me_clients[dev->me_client_presentation_num].props - = props_res->client_properties; + if (me_client->client_id != props_res->address) { + dev_err(&dev->pdev->dev, + "Host client properties reply mismatch\n"); + mei_reset(dev, 1); - if (dev->dev_state == MEI_DEV_INIT_CLIENTS && - dev->init_clients_state == - MEI_CLIENT_PROPERTIES_MESSAGE) { - dev->me_client_index++; - dev->me_client_presentation_num++; - - /** Send Client Properties request **/ - res = mei_host_client_properties(dev); - if (res < 0) { - dev_dbg(&dev->pdev->dev, "mei_host_client_properties() failed"); - return; - } else if (!res) { - /* - * No more clients to send to. - * Clear Map for indicating now ME clients - * with associated host client - */ - bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX); - dev->open_handle_count = 0; - - /* - * Reserving the first three client IDs - * Client Id 0 - Reserved for MEI Bus Message communications - * Client Id 1 - Reserved for Watchdog - * Client ID 2 - Reserved for AMTHI - */ - bitmap_set(dev->host_clients_map, 0, 3); - dev->dev_state = MEI_DEV_ENABLED; - - /* if wd initialization fails, initialization the AMTHI client, - * otherwise the AMTHI client will be initialized after the WD client connect response - * will be received - */ - if (mei_wd_host_init(dev)) - mei_host_init_iamthif(dev); - } + return; + } - } else { - dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message"); - mei_reset(dev, 1); - return; - } - } else { - dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message for wrong client ID\n"); + if (dev->dev_state != MEI_DEV_INIT_CLIENTS || + dev->init_clients_state != MEI_CLIENT_PROPERTIES_MESSAGE) { + dev_err(&dev->pdev->dev, + "Unexpected client properties reply\n"); mei_reset(dev, 1); + return; } + + me_client->props = props_res->client_properties; + dev->me_client_index++; + dev->me_client_presentation_num++; + + mei_host_client_enumerate(dev); + break; case HOST_ENUM_RES_CMD: @@ -760,7 +588,8 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, mei_allocate_me_clients_storage(dev); dev->init_clients_state = MEI_CLIENT_PROPERTIES_MESSAGE; - mei_host_client_properties(dev); + + mei_host_client_enumerate(dev); } else { dev_dbg(&dev->pdev->dev, "reset due to received host enumeration clients response bus message.\n"); mei_reset(dev, 1); @@ -776,29 +605,23 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, case CLIENT_DISCONNECT_REQ_CMD: /* search for client */ - disconnect_req = - (struct hbm_client_disconnect_request *) mei_msg; + disconnect_req = (struct hbm_client_connect_request *)mei_msg; mei_client_disconnect_request(dev, disconnect_req); break; case ME_STOP_REQ_CMD: - /* prepare stop request */ - mei_hdr = (struct mei_msg_hdr *) &dev->ext_msg_buf[0]; - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = sizeof(struct hbm_host_stop_request); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - host_stop_req = - (struct hbm_host_stop_request *) &dev->ext_msg_buf[1]; - memset(host_stop_req, 0, sizeof(struct hbm_host_stop_request)); - host_stop_req->hbm_cmd = HOST_STOP_REQ_CMD; - host_stop_req->reason = DRIVER_STOP_REQUEST; - host_stop_req->reserved[0] = 0; - host_stop_req->reserved[1] = 0; - dev->extra_write_index = 2; - break; + { + /* prepare stop request: sent in next interrupt event */ + + const size_t len = sizeof(struct hbm_host_stop_request); + mei_hdr = mei_hbm_hdr((u32 *)&dev->wr_ext_msg.hdr, len); + stop_req = (struct hbm_host_stop_request *)&dev->wr_ext_msg.data; + memset(stop_req, 0, len); + stop_req->hbm_cmd = HOST_STOP_REQ_CMD; + stop_req->reason = DRIVER_STOP_REQUEST; + break; + } default: BUG(); break; @@ -821,12 +644,12 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, static int _mei_irq_thread_read(struct mei_device *dev, s32 *slots, struct mei_cl_cb *cb_pos, struct mei_cl *cl, - struct mei_io_list *cmpl_list) + struct mei_cl_cb *cmpl_list) { if ((*slots * sizeof(u32)) < (sizeof(struct mei_msg_hdr) + sizeof(struct hbm_flow_control))) { /* return the cancel routine */ - list_del(&cb_pos->cb_list); + list_del(&cb_pos->list); return -EBADMSG; } @@ -834,11 +657,11 @@ static int _mei_irq_thread_read(struct mei_device *dev, s32 *slots, if (mei_send_flow_control(dev, cl)) { cl->status = -ENODEV; - cb_pos->information = 0; - list_move_tail(&cb_pos->cb_list, &cmpl_list->mei_cb.cb_list); + cb_pos->buf_idx = 0; + list_move_tail(&cb_pos->list, &cmpl_list->list); return -ENODEV; } - list_move_tail(&cb_pos->cb_list, &dev->read_list.mei_cb.cb_list); + list_move_tail(&cb_pos->list, &dev->read_list.list); return 0; } @@ -858,12 +681,12 @@ static int _mei_irq_thread_read(struct mei_device *dev, s32 *slots, static int _mei_irq_thread_ioctl(struct mei_device *dev, s32 *slots, struct mei_cl_cb *cb_pos, struct mei_cl *cl, - struct mei_io_list *cmpl_list) + struct mei_cl_cb *cmpl_list) { if ((*slots * sizeof(u32)) < (sizeof(struct mei_msg_hdr) + sizeof(struct hbm_client_connect_request))) { /* return the cancel routine */ - list_del(&cb_pos->cb_list); + list_del(&cb_pos->list); return -EBADMSG; } @@ -871,188 +694,73 @@ static int _mei_irq_thread_ioctl(struct mei_device *dev, s32 *slots, *slots -= mei_data2slots(sizeof(struct hbm_client_connect_request)); if (mei_connect(dev, cl)) { cl->status = -ENODEV; - cb_pos->information = 0; - list_del(&cb_pos->cb_list); + cb_pos->buf_idx = 0; + list_del(&cb_pos->list); return -ENODEV; } else { - list_move_tail(&cb_pos->cb_list, - &dev->ctrl_rd_list.mei_cb.cb_list); + list_move_tail(&cb_pos->list, &dev->ctrl_rd_list.list); cl->timer_count = MEI_CONNECT_TIMEOUT; } return 0; } /** - * _mei_irq_thread_cmpl - processes completed and no-iamthif operation. + * mei_irq_thread_write_complete - write messages to device. * * @dev: the device structure. * @slots: free slots. - * @cb_pos: callback block. - * @cl: private data of the file object. + * @cb: callback block. * @cmpl_list: complete list. * * returns 0, OK; otherwise, error. */ -static int _mei_irq_thread_cmpl(struct mei_device *dev, s32 *slots, - struct mei_cl_cb *cb_pos, - struct mei_cl *cl, - struct mei_io_list *cmpl_list) +static int mei_irq_thread_write_complete(struct mei_device *dev, s32 *slots, + struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list) { struct mei_msg_hdr *mei_hdr; + struct mei_cl *cl = cb->cl; + size_t len = cb->request_buffer.size - cb->buf_idx; + size_t msg_slots = mei_data2slots(len); + + mei_hdr = (struct mei_msg_hdr *)&dev->wr_msg_buf[0]; + mei_hdr->host_addr = cl->host_client_id; + mei_hdr->me_addr = cl->me_client_id; + mei_hdr->reserved = 0; - if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) + - (cb_pos->request_buffer.size - - cb_pos->information))) { - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = cl->host_client_id; - mei_hdr->me_addr = cl->me_client_id; - mei_hdr->length = cb_pos->request_buffer.size - - cb_pos->information; + if (*slots >= msg_slots) { + mei_hdr->length = len; mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - dev_dbg(&dev->pdev->dev, "cb_pos->request_buffer.size =%d" - "mei_hdr->msg_complete = %d\n", - cb_pos->request_buffer.size, - mei_hdr->msg_complete); - dev_dbg(&dev->pdev->dev, "cb_pos->information =%lu\n", - cb_pos->information); - dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n", - mei_hdr->length); - *slots -= mei_data2slots(mei_hdr->length); - if (mei_write_message(dev, mei_hdr, - (unsigned char *) - (cb_pos->request_buffer.data + - cb_pos->information), - mei_hdr->length)) { - cl->status = -ENODEV; - list_move_tail(&cb_pos->cb_list, - &cmpl_list->mei_cb.cb_list); - return -ENODEV; - } else { - if (mei_flow_ctrl_reduce(dev, cl)) - return -ENODEV; - cl->status = 0; - cb_pos->information += mei_hdr->length; - list_move_tail(&cb_pos->cb_list, - &dev->write_waiting_list.mei_cb.cb_list); - } + /* Split the message only if we can write the whole host buffer */ } else if (*slots == dev->hbuf_depth) { - /* buffer is still empty */ - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = cl->host_client_id; - mei_hdr->me_addr = cl->me_client_id; - mei_hdr->length = - (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr); + msg_slots = *slots; + len = (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr); + mei_hdr->length = len; mei_hdr->msg_complete = 0; - mei_hdr->reserved = 0; - *slots -= mei_data2slots(mei_hdr->length); - if (mei_write_message(dev, mei_hdr, - (unsigned char *) - (cb_pos->request_buffer.data + - cb_pos->information), - mei_hdr->length)) { - cl->status = -ENODEV; - list_move_tail(&cb_pos->cb_list, - &cmpl_list->mei_cb.cb_list); - return -ENODEV; - } else { - cb_pos->information += mei_hdr->length; - dev_dbg(&dev->pdev->dev, - "cb_pos->request_buffer.size =%d" - " mei_hdr->msg_complete = %d\n", - cb_pos->request_buffer.size, - mei_hdr->msg_complete); - dev_dbg(&dev->pdev->dev, "cb_pos->information =%lu\n", - cb_pos->information); - dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n", - mei_hdr->length); - } - return -EMSGSIZE; } else { - return -EBADMSG; + /* wait for next time the host buffer is empty */ + return 0; } - return 0; -} - -/** - * _mei_irq_thread_cmpl_iamthif - processes completed iamthif operation. - * - * @dev: the device structure. - * @slots: free slots. - * @cb_pos: callback block. - * @cl: private data of the file object. - * @cmpl_list: complete list. - * - * returns 0, OK; otherwise, error. - */ -static int _mei_irq_thread_cmpl_iamthif(struct mei_device *dev, s32 *slots, - struct mei_cl_cb *cb_pos, - struct mei_cl *cl, - struct mei_io_list *cmpl_list) -{ - struct mei_msg_hdr *mei_hdr; - - if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) + - dev->iamthif_msg_buf_size - - dev->iamthif_msg_buf_index)) { - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = cl->host_client_id; - mei_hdr->me_addr = cl->me_client_id; - mei_hdr->length = dev->iamthif_msg_buf_size - - dev->iamthif_msg_buf_index; - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - - *slots -= mei_data2slots(mei_hdr->length); - - if (mei_write_message(dev, mei_hdr, - (dev->iamthif_msg_buf + - dev->iamthif_msg_buf_index), - mei_hdr->length)) { - dev->iamthif_state = MEI_IAMTHIF_IDLE; - cl->status = -ENODEV; - list_del(&cb_pos->cb_list); - return -ENODEV; - } else { - if (mei_flow_ctrl_reduce(dev, cl)) - return -ENODEV; - dev->iamthif_msg_buf_index += mei_hdr->length; - cb_pos->information = dev->iamthif_msg_buf_index; - cl->status = 0; - dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL; - dev->iamthif_flow_control_pending = true; - /* save iamthif cb sent to amthi client */ - dev->iamthif_current_cb = cb_pos; - list_move_tail(&cb_pos->cb_list, - &dev->write_waiting_list.mei_cb.cb_list); + dev_dbg(&dev->pdev->dev, "buf: size = %d idx = %lu\n", + cb->request_buffer.size, cb->buf_idx); + dev_dbg(&dev->pdev->dev, "msg: len = %d complete = %d\n", + mei_hdr->length, mei_hdr->msg_complete); - } - } else if (*slots == dev->hbuf_depth) { - /* buffer is still empty */ - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = cl->host_client_id; - mei_hdr->me_addr = cl->me_client_id; - mei_hdr->length = - (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr); - mei_hdr->msg_complete = 0; - mei_hdr->reserved = 0; + *slots -= msg_slots; + if (mei_write_message(dev, mei_hdr, + cb->request_buffer.data + cb->buf_idx, len)) { + cl->status = -ENODEV; + list_move_tail(&cb->list, &cmpl_list->list); + return -ENODEV; + } - *slots -= mei_data2slots(mei_hdr->length); + if (mei_flow_ctrl_reduce(dev, cl)) + return -ENODEV; - if (mei_write_message(dev, mei_hdr, - (dev->iamthif_msg_buf + - dev->iamthif_msg_buf_index), - mei_hdr->length)) { - cl->status = -ENODEV; - list_del(&cb_pos->cb_list); - } else { - dev->iamthif_msg_buf_index += mei_hdr->length; - } - return -EMSGSIZE; - } else { - return -EBADMSG; - } + cl->status = 0; + cb->buf_idx += mei_hdr->length; + if (mei_hdr->msg_complete) + list_move_tail(&cb->list, &dev->write_waiting_list.list); return 0; } @@ -1067,7 +775,7 @@ static int _mei_irq_thread_cmpl_iamthif(struct mei_device *dev, s32 *slots, * * returns 0 on success, <0 on failure. */ -static int mei_irq_thread_read_handler(struct mei_io_list *cmpl_list, +static int mei_irq_thread_read_handler(struct mei_cl_cb *cmpl_list, struct mei_device *dev, s32 *slots) { @@ -1130,8 +838,8 @@ static int mei_irq_thread_read_handler(struct mei_io_list *cmpl_list, dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_iamthif_message.\n"); dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n", mei_hdr->length); - ret = mei_irq_thread_read_amthi_message(cmpl_list, - dev, mei_hdr); + + ret = mei_amthif_irq_read_message(cmpl_list, dev, mei_hdr); if (ret) goto end; @@ -1164,53 +872,51 @@ end: * mei_irq_thread_write_handler - bottom half write routine after * ISR to handle the write processing. * - * @cmpl_list: An instance of our list structure * @dev: the device structure - * @slots: slots to write. + * @cmpl_list: An instance of our list structure * * returns 0 on success, <0 on failure. */ -static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list, - struct mei_device *dev, - s32 *slots) +static int mei_irq_thread_write_handler(struct mei_device *dev, + struct mei_cl_cb *cmpl_list) { struct mei_cl *cl; struct mei_cl_cb *pos = NULL, *next = NULL; - struct mei_io_list *list; + struct mei_cl_cb *list; + s32 slots; int ret; if (!mei_hbuf_is_empty(dev)) { dev_dbg(&dev->pdev->dev, "host buffer is not empty.\n"); return 0; } - *slots = mei_hbuf_empty_slots(dev); - if (*slots <= 0) + slots = mei_hbuf_empty_slots(dev); + if (slots <= 0) return -EMSGSIZE; /* complete all waiting for write CB */ dev_dbg(&dev->pdev->dev, "complete all waiting for write cb.\n"); list = &dev->write_waiting_list; - list_for_each_entry_safe(pos, next, &list->mei_cb.cb_list, cb_list) { - cl = (struct mei_cl *)pos->file_private; + list_for_each_entry_safe(pos, next, &list->list, list) { + cl = pos->cl; if (cl == NULL) continue; cl->status = 0; - list_del(&pos->cb_list); + list_del(&pos->list); if (MEI_WRITING == cl->writing_state && - (pos->major_file_operations == MEI_WRITE) && - (cl != &dev->iamthif_cl)) { + pos->fop_type == MEI_FOP_WRITE && + cl != &dev->iamthif_cl) { dev_dbg(&dev->pdev->dev, "MEI WRITE COMPLETE\n"); cl->writing_state = MEI_WRITE_COMPLETE; - list_add_tail(&pos->cb_list, - &cmpl_list->mei_cb.cb_list); + list_add_tail(&pos->list, &cmpl_list->list); } if (cl == &dev->iamthif_cl) { dev_dbg(&dev->pdev->dev, "check iamthif flow control.\n"); if (dev->iamthif_flow_control_pending) { - ret = _mei_irq_thread_iamthif_read(dev, slots); + ret = mei_amthif_irq_read(dev, &slots); if (ret) return ret; } @@ -1222,15 +928,11 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list, wake_up_interruptible(&dev->wait_stop_wd); } - if (dev->extra_write_index) { - dev_dbg(&dev->pdev->dev, "extra_write_index =%d.\n", - dev->extra_write_index); - mei_write_message(dev, - (struct mei_msg_hdr *) &dev->ext_msg_buf[0], - (unsigned char *) &dev->ext_msg_buf[1], - (dev->extra_write_index - 1) * sizeof(u32)); - *slots -= dev->extra_write_index; - dev->extra_write_index = 0; + if (dev->wr_ext_msg.hdr.length) { + mei_write_message(dev, &dev->wr_ext_msg.hdr, + dev->wr_ext_msg.data, dev->wr_ext_msg.hdr.length); + slots -= mei_data2slots(dev->wr_ext_msg.hdr.length); + dev->wr_ext_msg.hdr.length = 0; } if (dev->dev_state == MEI_DEV_ENABLED) { if (dev->wd_pending && @@ -1243,41 +945,43 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list, dev->wd_pending = false; if (dev->wd_state == MEI_WD_RUNNING) - *slots -= mei_data2slots(MEI_WD_START_MSG_SIZE); + slots -= mei_data2slots(MEI_WD_START_MSG_SIZE); else - *slots -= mei_data2slots(MEI_WD_STOP_MSG_SIZE); + slots -= mei_data2slots(MEI_WD_STOP_MSG_SIZE); } } /* complete control write list CB */ dev_dbg(&dev->pdev->dev, "complete control write list cb.\n"); - list_for_each_entry_safe(pos, next, - &dev->ctrl_wr_list.mei_cb.cb_list, cb_list) { - cl = (struct mei_cl *) pos->file_private; + list_for_each_entry_safe(pos, next, &dev->ctrl_wr_list.list, list) { + cl = pos->cl; if (!cl) { - list_del(&pos->cb_list); + list_del(&pos->list); return -ENODEV; } - switch (pos->major_file_operations) { - case MEI_CLOSE: + switch (pos->fop_type) { + case MEI_FOP_CLOSE: /* send disconnect message */ - ret = _mei_irq_thread_close(dev, slots, pos, cl, cmpl_list); + ret = _mei_irq_thread_close(dev, &slots, pos, + cl, cmpl_list); if (ret) return ret; break; - case MEI_READ: + case MEI_FOP_READ: /* send flow control message */ - ret = _mei_irq_thread_read(dev, slots, pos, cl, cmpl_list); + ret = _mei_irq_thread_read(dev, &slots, pos, + cl, cmpl_list); if (ret) return ret; break; - case MEI_IOCTL: + case MEI_FOP_IOCTL: /* connect message */ if (mei_other_client_is_connecting(dev, cl)) continue; - ret = _mei_irq_thread_ioctl(dev, slots, pos, cl, cmpl_list); + ret = _mei_irq_thread_ioctl(dev, &slots, pos, + cl, cmpl_list); if (ret) return ret; @@ -1290,40 +994,26 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list, } /* complete write list CB */ dev_dbg(&dev->pdev->dev, "complete write list cb.\n"); - list_for_each_entry_safe(pos, next, - &dev->write_list.mei_cb.cb_list, cb_list) { - cl = (struct mei_cl *)pos->file_private; + list_for_each_entry_safe(pos, next, &dev->write_list.list, list) { + cl = pos->cl; if (cl == NULL) continue; - - if (cl != &dev->iamthif_cl) { - if (mei_flow_ctrl_creds(dev, cl) <= 0) { - dev_dbg(&dev->pdev->dev, - "No flow control credentials for client %d, not sending.\n", - cl->host_client_id); - continue; - } - ret = _mei_irq_thread_cmpl(dev, slots, pos, - cl, cmpl_list); - if (ret) - return ret; - - } else if (cl == &dev->iamthif_cl) { - /* IAMTHIF IOCTL */ - dev_dbg(&dev->pdev->dev, "complete amthi write cb.\n"); - if (mei_flow_ctrl_creds(dev, cl) <= 0) { - dev_dbg(&dev->pdev->dev, - "No flow control credentials for amthi client %d.\n", - cl->host_client_id); - continue; - } - ret = _mei_irq_thread_cmpl_iamthif(dev, slots, pos, - cl, cmpl_list); - if (ret) - return ret; - + if (mei_flow_ctrl_creds(dev, cl) <= 0) { + dev_dbg(&dev->pdev->dev, + "No flow control credentials for client %d, not sending.\n", + cl->host_client_id); + continue; } + if (cl == &dev->iamthif_cl) + ret = mei_amthif_irq_write_complete(dev, &slots, + pos, cmpl_list); + else + ret = mei_irq_thread_write_complete(dev, &slots, pos, + cmpl_list); + if (ret) + return ret; + } return 0; } @@ -1342,7 +1032,6 @@ void mei_timer(struct work_struct *work) unsigned long timeout; struct mei_cl *cl_pos = NULL; struct mei_cl *cl_next = NULL; - struct list_head *amthi_complete_list = NULL; struct mei_cl_cb *cb_pos = NULL; struct mei_cl_cb *cb_next = NULL; @@ -1385,19 +1074,18 @@ void mei_timer(struct work_struct *work) dev->iamthif_state = MEI_IAMTHIF_IDLE; dev->iamthif_timer = 0; - if (dev->iamthif_current_cb) - mei_free_cb_private(dev->iamthif_current_cb); + mei_io_cb_free(dev->iamthif_current_cb); + dev->iamthif_current_cb = NULL; dev->iamthif_file_object = NULL; - dev->iamthif_current_cb = NULL; - mei_run_next_iamthif_cmd(dev); + mei_amthif_run_next_cmd(dev); } } if (dev->iamthif_timer) { timeout = dev->iamthif_timer + - msecs_to_jiffies(IAMTHIF_READ_TIMER); + mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER); dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n", dev->iamthif_timer); @@ -1411,25 +1099,22 @@ void mei_timer(struct work_struct *work) dev_dbg(&dev->pdev->dev, "freeing AMTHI for other requests\n"); - amthi_complete_list = &dev->amthi_read_complete_list. - mei_cb.cb_list; - - list_for_each_entry_safe(cb_pos, cb_next, amthi_complete_list, cb_list) { + list_for_each_entry_safe(cb_pos, cb_next, + &dev->amthif_rd_complete_list.list, list) { cl_pos = cb_pos->file_object->private_data; /* Finding the AMTHI entry. */ if (cl_pos == &dev->iamthif_cl) - list_del(&cb_pos->cb_list); + list_del(&cb_pos->list); } - if (dev->iamthif_current_cb) - mei_free_cb_private(dev->iamthif_current_cb); + mei_io_cb_free(dev->iamthif_current_cb); + dev->iamthif_current_cb = NULL; dev->iamthif_file_object->private_data = NULL; dev->iamthif_file_object = NULL; - dev->iamthif_current_cb = NULL; dev->iamthif_timer = 0; - mei_run_next_iamthif_cmd(dev); + mei_amthif_run_next_cmd(dev); } } @@ -1451,7 +1136,7 @@ out: irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id) { struct mei_device *dev = (struct mei_device *) dev_id; - struct mei_io_list complete_list; + struct mei_cl_cb complete_list; struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL; struct mei_cl *cl; s32 slots; @@ -1504,17 +1189,17 @@ irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id) } /* check slots available for reading */ slots = mei_count_full_read_slots(dev); - dev_dbg(&dev->pdev->dev, "slots =%08x extra_write_index =%08x.\n", - slots, dev->extra_write_index); - while (slots > 0 && !dev->extra_write_index) { - dev_dbg(&dev->pdev->dev, "slots =%08x extra_write_index =%08x.\n", - slots, dev->extra_write_index); + while (slots > 0) { + /* we have urgent data to send so break the read */ + if (dev->wr_ext_msg.hdr.length) + break; + dev_dbg(&dev->pdev->dev, "slots =%08x\n", slots); dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_handler.\n"); rets = mei_irq_thread_read_handler(&complete_list, dev, &slots); if (rets) goto end; } - rets = mei_irq_thread_write_handler(&complete_list, dev, &slots); + rets = mei_irq_thread_write_handler(dev, &complete_list); end: dev_dbg(&dev->pdev->dev, "end of bottom half function.\n"); dev->host_hw_state = mei_hcsr_read(dev); @@ -1531,21 +1216,20 @@ end: wake_up_interruptible(&dev->wait_recvd_msg); bus_message_received = false; } - if (list_empty(&complete_list.mei_cb.cb_list)) + if (list_empty(&complete_list.list)) return IRQ_HANDLED; - list_for_each_entry_safe(cb_pos, cb_next, - &complete_list.mei_cb.cb_list, cb_list) { - cl = (struct mei_cl *)cb_pos->file_private; - list_del(&cb_pos->cb_list); + list_for_each_entry_safe(cb_pos, cb_next, &complete_list.list, list) { + cl = cb_pos->cl; + list_del(&cb_pos->list); if (cl) { if (cl != &dev->iamthif_cl) { dev_dbg(&dev->pdev->dev, "completing call back.\n"); _mei_cmpl(cl, cb_pos); cb_pos = NULL; } else if (cl == &dev->iamthif_cl) { - _mei_cmpl_iamthif(dev, cb_pos); + mei_amthif_complete(dev, cb_pos); } } } diff --git a/drivers/misc/mei/iorw.c b/drivers/misc/mei/iorw.c index fcba98eb892..eb93a1b53b9 100644 --- a/drivers/misc/mei/iorw.c +++ b/drivers/misc/mei/iorw.c @@ -39,6 +39,95 @@ #include "interface.h" /** + * mei_io_cb_free - free mei_cb_private related memory + * + * @cb: mei callback struct + */ +void mei_io_cb_free(struct mei_cl_cb *cb) +{ + if (cb == NULL) + return; + + kfree(cb->request_buffer.data); + kfree(cb->response_buffer.data); + kfree(cb); +} +/** + * mei_io_cb_init - allocate and initialize io callback + * + * @cl - mei client + * @file: pointer to file structure + * + * returns mei_cl_cb pointer or NULL; + */ +struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp) +{ + struct mei_cl_cb *cb; + + cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); + if (!cb) + return NULL; + + mei_io_list_init(cb); + + cb->file_object = fp; + cb->cl = cl; + cb->buf_idx = 0; + return cb; +} + + +/** + * mei_io_cb_alloc_req_buf - allocate request buffer + * + * @cb - io callback structure + * @size: size of the buffer + * + * returns 0 on success + * -EINVAL if cb is NULL + * -ENOMEM if allocation failed + */ +int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length) +{ + if (!cb) + return -EINVAL; + + if (length == 0) + return 0; + + cb->request_buffer.data = kmalloc(length, GFP_KERNEL); + if (!cb->request_buffer.data) + return -ENOMEM; + cb->request_buffer.size = length; + return 0; +} +/** + * mei_io_cb_alloc_req_buf - allocate respose buffer + * + * @cb - io callback structure + * @size: size of the buffer + * + * returns 0 on success + * -EINVAL if cb is NULL + * -ENOMEM if allocation failed + */ +int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length) +{ + if (!cb) + return -EINVAL; + + if (length == 0) + return 0; + + cb->response_buffer.data = kmalloc(length, GFP_KERNEL); + if (!cb->response_buffer.data) + return -ENOMEM; + cb->response_buffer.size = length; + return 0; +} + + +/** * mei_me_cl_by_id return index to me_clients for client_id * * @dev: the device structure @@ -82,9 +171,7 @@ int mei_ioctl_connect_client(struct file *file, struct mei_cl_cb *cb; struct mei_client *client; struct mei_cl *cl; - struct mei_cl *cl_pos = NULL; - struct mei_cl *cl_next = NULL; - long timeout = CONNECT_TIMEOUT; + long timeout = mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT); int i; int err; int rets; @@ -97,16 +184,14 @@ int mei_ioctl_connect_client(struct file *file, dev_dbg(&dev->pdev->dev, "mei_ioctl_connect_client() Entry\n"); - /* buffered ioctl cb */ - cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); + cb = mei_io_cb_init(cl, file); if (!cb) { rets = -ENOMEM; goto end; } - INIT_LIST_HEAD(&cb->cb_list); - cb->major_file_operations = MEI_IOCTL; + cb->fop_type = MEI_FOP_IOCTL; if (dev->dev_state != MEI_DEV_ENABLED) { rets = -ENODEV; @@ -142,21 +227,9 @@ int mei_ioctl_connect_client(struct file *file, goto end; } clear_bit(cl->host_client_id, dev->host_clients_map); - list_for_each_entry_safe(cl_pos, cl_next, - &dev->file_list, link) { - if (mei_cl_cmp_id(cl, cl_pos)) { - dev_dbg(&dev->pdev->dev, - "remove file private data node host" - " client = %d, ME client = %d.\n", - cl_pos->host_client_id, - cl_pos->me_client_id); - list_del(&cl_pos->link); - } + mei_me_cl_unlink(dev, cl); - } - dev_dbg(&dev->pdev->dev, "free file private data memory.\n"); kfree(cl); - cl = NULL; file->private_data = &dev->iamthif_cl; @@ -192,25 +265,19 @@ int mei_ioctl_connect_client(struct file *file, } else { dev_dbg(&dev->pdev->dev, "Sending connect message - succeeded\n"); cl->timer_count = MEI_CONNECT_TIMEOUT; - cb->file_private = cl; - list_add_tail(&cb->cb_list, - &dev->ctrl_rd_list.mei_cb. - cb_list); + list_add_tail(&cb->list, &dev->ctrl_rd_list.list); } } else { dev_dbg(&dev->pdev->dev, "Queuing the connect request due to device busy\n"); - cb->file_private = cl; dev_dbg(&dev->pdev->dev, "add connect cb to control write list.\n"); - list_add_tail(&cb->cb_list, - &dev->ctrl_wr_list.mei_cb.cb_list); + list_add_tail(&cb->list, &dev->ctrl_wr_list.list); } mutex_unlock(&dev->device_lock); err = wait_event_timeout(dev->wait_recvd_msg, (MEI_FILE_CONNECTED == cl->state || - MEI_FILE_DISCONNECTED == cl->state), - timeout * HZ); + MEI_FILE_DISCONNECTED == cl->state), timeout); mutex_lock(&dev->device_lock); if (MEI_FILE_CONNECTED == cl->state) { @@ -234,153 +301,7 @@ int mei_ioctl_connect_client(struct file *file, rets = 0; end: dev_dbg(&dev->pdev->dev, "free connect cb memory."); - kfree(cb); - return rets; -} - -/** - * find_amthi_read_list_entry - finds a amthilist entry for current file - * - * @dev: the device structure - * @file: pointer to file object - * - * returns returned a list entry on success, NULL on failure. - */ -struct mei_cl_cb *find_amthi_read_list_entry( - struct mei_device *dev, - struct file *file) -{ - struct mei_cl *cl_temp; - struct mei_cl_cb *pos = NULL; - struct mei_cl_cb *next = NULL; - - list_for_each_entry_safe(pos, next, - &dev->amthi_read_complete_list.mei_cb.cb_list, cb_list) { - cl_temp = (struct mei_cl *)pos->file_private; - if (cl_temp && cl_temp == &dev->iamthif_cl && - pos->file_object == file) - return pos; - } - return NULL; -} - -/** - * amthi_read - read data from AMTHI client - * - * @dev: the device structure - * @if_num: minor number - * @file: pointer to file object - * @*ubuf: pointer to user data in user space - * @length: data length to read - * @offset: data read offset - * - * Locking: called under "dev->device_lock" lock - * - * returns - * returned data length on success, - * zero if no data to read, - * negative on failure. - */ -int amthi_read(struct mei_device *dev, struct file *file, - char __user *ubuf, size_t length, loff_t *offset) -{ - int rets; - int wait_ret; - struct mei_cl_cb *cb = NULL; - struct mei_cl *cl = file->private_data; - unsigned long timeout; - int i; - - /* Only Posible if we are in timeout */ - if (!cl || cl != &dev->iamthif_cl) { - dev_dbg(&dev->pdev->dev, "bad file ext.\n"); - return -ETIMEDOUT; - } - - i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id); - - if (i < 0) { - dev_dbg(&dev->pdev->dev, "amthi client not found.\n"); - return -ENODEV; - } - dev_dbg(&dev->pdev->dev, "checking amthi data\n"); - cb = find_amthi_read_list_entry(dev, file); - - /* Check for if we can block or not*/ - if (cb == NULL && file->f_flags & O_NONBLOCK) - return -EAGAIN; - - - dev_dbg(&dev->pdev->dev, "waiting for amthi data\n"); - while (cb == NULL) { - /* unlock the Mutex */ - mutex_unlock(&dev->device_lock); - - wait_ret = wait_event_interruptible(dev->iamthif_cl.wait, - (cb = find_amthi_read_list_entry(dev, file))); - - if (wait_ret) - return -ERESTARTSYS; - - dev_dbg(&dev->pdev->dev, "woke up from sleep\n"); - - /* Locking again the Mutex */ - mutex_lock(&dev->device_lock); - } - - - dev_dbg(&dev->pdev->dev, "Got amthi data\n"); - dev->iamthif_timer = 0; - - if (cb) { - timeout = cb->read_time + msecs_to_jiffies(IAMTHIF_READ_TIMER); - dev_dbg(&dev->pdev->dev, "amthi timeout = %lud\n", - timeout); - - if (time_after(jiffies, timeout)) { - dev_dbg(&dev->pdev->dev, "amthi Time out\n"); - /* 15 sec for the message has expired */ - list_del(&cb->cb_list); - rets = -ETIMEDOUT; - goto free; - } - } - /* if the whole message will fit remove it from the list */ - if (cb->information >= *offset && length >= (cb->information - *offset)) - list_del(&cb->cb_list); - else if (cb->information > 0 && cb->information <= *offset) { - /* end of the message has been reached */ - list_del(&cb->cb_list); - rets = 0; - goto free; - } - /* else means that not full buffer will be read and do not - * remove message from deletion list - */ - - dev_dbg(&dev->pdev->dev, "amthi cb->response_buffer size - %d\n", - cb->response_buffer.size); - dev_dbg(&dev->pdev->dev, "amthi cb->information - %lu\n", - cb->information); - - /* length is being turncated to PAGE_SIZE, however, - * the information may be longer */ - length = min_t(size_t, length, (cb->information - *offset)); - - if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) - rets = -EFAULT; - else { - rets = length; - if ((*offset + length) < cb->information) { - *offset += length; - goto out; - } - } -free: - dev_dbg(&dev->pdev->dev, "free amthi cb memory.\n"); - *offset = 0; - mei_free_cb_private(cb); -out: + mei_io_cb_free(cb); return rets; } @@ -396,7 +317,7 @@ out: int mei_start_read(struct mei_device *dev, struct mei_cl *cl) { struct mei_cl_cb *cb; - int rets = 0; + int rets; int i; if (cl->state != MEI_FILE_CONNECTED) @@ -405,187 +326,41 @@ int mei_start_read(struct mei_device *dev, struct mei_cl *cl) if (dev->dev_state != MEI_DEV_ENABLED) return -ENODEV; - dev_dbg(&dev->pdev->dev, "check if read is pending.\n"); if (cl->read_pending || cl->read_cb) { dev_dbg(&dev->pdev->dev, "read is pending.\n"); return -EBUSY; } + i = mei_me_cl_by_id(dev, cl->me_client_id); + if (i < 0) { + dev_err(&dev->pdev->dev, "no such me client %d\n", + cl->me_client_id); + return -ENODEV; + } - cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); + cb = mei_io_cb_init(cl, NULL); if (!cb) return -ENOMEM; - dev_dbg(&dev->pdev->dev, "allocation call back successful. host client = %d, ME client = %d\n", - cl->host_client_id, cl->me_client_id); - i = mei_me_cl_by_id(dev, cl->me_client_id); - if (i < 0) { - rets = -ENODEV; - goto unlock; - } + rets = mei_io_cb_alloc_resp_buf(cb, + dev->me_clients[i].props.max_msg_length); + if (rets) + goto err; - cb->response_buffer.size = dev->me_clients[i].props.max_msg_length; - cb->response_buffer.data = - kmalloc(cb->response_buffer.size, GFP_KERNEL); - if (!cb->response_buffer.data) { - rets = -ENOMEM; - goto unlock; - } - dev_dbg(&dev->pdev->dev, "allocation call back data success.\n"); - cb->major_file_operations = MEI_READ; - /* make sure information is zero before we start */ - cb->information = 0; - cb->file_private = (void *) cl; + cb->fop_type = MEI_FOP_READ; cl->read_cb = cb; if (dev->mei_host_buffer_is_empty) { dev->mei_host_buffer_is_empty = false; if (mei_send_flow_control(dev, cl)) { rets = -ENODEV; - goto unlock; + goto err; } - list_add_tail(&cb->cb_list, &dev->read_list.mei_cb.cb_list); + list_add_tail(&cb->list, &dev->read_list.list); } else { - list_add_tail(&cb->cb_list, &dev->ctrl_wr_list.mei_cb.cb_list); + list_add_tail(&cb->list, &dev->ctrl_wr_list.list); } return rets; -unlock: - mei_free_cb_private(cb); +err: + mei_io_cb_free(cb); return rets; } -/** - * amthi_write - write iamthif data to amthi client - * - * @dev: the device structure - * @cb: mei call back struct - * - * returns 0 on success, <0 on failure. - */ -int amthi_write(struct mei_device *dev, struct mei_cl_cb *cb) -{ - struct mei_msg_hdr mei_hdr; - int ret; - - if (!dev || !cb) - return -ENODEV; - - dev_dbg(&dev->pdev->dev, "write data to amthi client.\n"); - - dev->iamthif_state = MEI_IAMTHIF_WRITING; - dev->iamthif_current_cb = cb; - dev->iamthif_file_object = cb->file_object; - dev->iamthif_canceled = false; - dev->iamthif_ioctl = true; - dev->iamthif_msg_buf_size = cb->request_buffer.size; - memcpy(dev->iamthif_msg_buf, cb->request_buffer.data, - cb->request_buffer.size); - - ret = mei_flow_ctrl_creds(dev, &dev->iamthif_cl); - if (ret < 0) - return ret; - - if (ret && dev->mei_host_buffer_is_empty) { - ret = 0; - dev->mei_host_buffer_is_empty = false; - if (cb->request_buffer.size > mei_hbuf_max_data(dev)) { - mei_hdr.length = mei_hbuf_max_data(dev); - mei_hdr.msg_complete = 0; - } else { - mei_hdr.length = cb->request_buffer.size; - mei_hdr.msg_complete = 1; - } - - mei_hdr.host_addr = dev->iamthif_cl.host_client_id; - mei_hdr.me_addr = dev->iamthif_cl.me_client_id; - mei_hdr.reserved = 0; - dev->iamthif_msg_buf_index += mei_hdr.length; - if (mei_write_message(dev, &mei_hdr, - (unsigned char *)(dev->iamthif_msg_buf), - mei_hdr.length)) - return -ENODEV; - - if (mei_hdr.msg_complete) { - if (mei_flow_ctrl_reduce(dev, &dev->iamthif_cl)) - return -ENODEV; - dev->iamthif_flow_control_pending = true; - dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL; - dev_dbg(&dev->pdev->dev, "add amthi cb to write waiting list\n"); - dev->iamthif_current_cb = cb; - dev->iamthif_file_object = cb->file_object; - list_add_tail(&cb->cb_list, - &dev->write_waiting_list.mei_cb.cb_list); - } else { - dev_dbg(&dev->pdev->dev, "message does not complete, " - "so add amthi cb to write list.\n"); - list_add_tail(&cb->cb_list, - &dev->write_list.mei_cb.cb_list); - } - } else { - if (!(dev->mei_host_buffer_is_empty)) - dev_dbg(&dev->pdev->dev, "host buffer is not empty"); - - dev_dbg(&dev->pdev->dev, "No flow control credentials, " - "so add iamthif cb to write list.\n"); - list_add_tail(&cb->cb_list, &dev->write_list.mei_cb.cb_list); - } - return 0; -} - -/** - * iamthif_ioctl_send_msg - send cmd data to amthi client - * - * @dev: the device structure - * - * returns 0 on success, <0 on failure. - */ -void mei_run_next_iamthif_cmd(struct mei_device *dev) -{ - struct mei_cl *cl_tmp; - struct mei_cl_cb *pos = NULL; - struct mei_cl_cb *next = NULL; - int status; - - if (!dev) - return; - - dev->iamthif_msg_buf_size = 0; - dev->iamthif_msg_buf_index = 0; - dev->iamthif_canceled = false; - dev->iamthif_ioctl = true; - dev->iamthif_state = MEI_IAMTHIF_IDLE; - dev->iamthif_timer = 0; - dev->iamthif_file_object = NULL; - - dev_dbg(&dev->pdev->dev, "complete amthi cmd_list cb.\n"); - - list_for_each_entry_safe(pos, next, - &dev->amthi_cmd_list.mei_cb.cb_list, cb_list) { - list_del(&pos->cb_list); - cl_tmp = (struct mei_cl *)pos->file_private; - - if (cl_tmp && cl_tmp == &dev->iamthif_cl) { - status = amthi_write(dev, pos); - if (status) { - dev_dbg(&dev->pdev->dev, - "amthi write failed status = %d\n", - status); - return; - } - break; - } - } -} - -/** - * mei_free_cb_private - free mei_cb_private related memory - * - * @cb: mei callback struct - */ -void mei_free_cb_private(struct mei_cl_cb *cb) -{ - if (cb == NULL) - return; - - kfree(cb->request_buffer.data); - kfree(cb->response_buffer.data); - kfree(cb); -} diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index e8b0858132c..43fb52ff98a 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -90,93 +90,6 @@ static DEFINE_MUTEX(mei_mutex); /** - * mei_clear_list - removes all callbacks associated with file - * from mei_cb_list - * - * @dev: device structure. - * @file: file structure - * @mei_cb_list: callbacks list - * - * mei_clear_list is called to clear resources associated with file - * when application calls close function or Ctrl-C was pressed - * - * returns true if callback removed from the list, false otherwise - */ -static bool mei_clear_list(struct mei_device *dev, - struct file *file, struct list_head *mei_cb_list) -{ - struct mei_cl_cb *cb_pos = NULL; - struct mei_cl_cb *cb_next = NULL; - struct file *file_temp; - bool removed = false; - - /* list all list member */ - list_for_each_entry_safe(cb_pos, cb_next, mei_cb_list, cb_list) { - file_temp = (struct file *)cb_pos->file_object; - /* check if list member associated with a file */ - if (file_temp == file) { - /* remove member from the list */ - list_del(&cb_pos->cb_list); - /* check if cb equal to current iamthif cb */ - if (dev->iamthif_current_cb == cb_pos) { - dev->iamthif_current_cb = NULL; - /* send flow control to iamthif client */ - mei_send_flow_control(dev, &dev->iamthif_cl); - } - /* free all allocated buffers */ - mei_free_cb_private(cb_pos); - cb_pos = NULL; - removed = true; - } - } - return removed; -} - -/** - * mei_clear_lists - removes all callbacks associated with file - * - * @dev: device structure - * @file: file structure - * - * mei_clear_lists is called to clear resources associated with file - * when application calls close function or Ctrl-C was pressed - * - * returns true if callback removed from the list, false otherwise - */ -static bool mei_clear_lists(struct mei_device *dev, struct file *file) -{ - bool removed = false; - - /* remove callbacks associated with a file */ - mei_clear_list(dev, file, &dev->amthi_cmd_list.mei_cb.cb_list); - if (mei_clear_list(dev, file, - &dev->amthi_read_complete_list.mei_cb.cb_list)) - removed = true; - - mei_clear_list(dev, file, &dev->ctrl_rd_list.mei_cb.cb_list); - - if (mei_clear_list(dev, file, &dev->ctrl_wr_list.mei_cb.cb_list)) - removed = true; - - if (mei_clear_list(dev, file, &dev->write_waiting_list.mei_cb.cb_list)) - removed = true; - - if (mei_clear_list(dev, file, &dev->write_list.mei_cb.cb_list)) - removed = true; - - /* check if iamthif_current_cb not NULL */ - if (dev->iamthif_current_cb && !removed) { - /* check file and iamthif current cb association */ - if (dev->iamthif_current_cb->file_object == file) { - /* remove cb */ - mei_free_cb_private(dev->iamthif_current_cb); - dev->iamthif_current_cb = NULL; - removed = true; - } - } - return removed; -} -/** * find_read_list_entry - find read list entry * * @dev: device structure @@ -192,14 +105,9 @@ static struct mei_cl_cb *find_read_list_entry( struct mei_cl_cb *next = NULL; dev_dbg(&dev->pdev->dev, "remove read_list CB\n"); - list_for_each_entry_safe(pos, next, - &dev->read_list.mei_cb.cb_list, cb_list) { - struct mei_cl *cl_temp; - cl_temp = (struct mei_cl *)pos->file_private; - - if (mei_cl_cmp_id(cl, cl_temp)) + list_for_each_entry_safe(pos, next, &dev->read_list.list, list) + if (mei_cl_cmp_id(cl, pos->cl)) return pos; - } return NULL; } @@ -297,67 +205,51 @@ static int mei_release(struct inode *inode, struct file *file) dev = cl->dev; mutex_lock(&dev->device_lock); - if (cl != &dev->iamthif_cl) { - if (cl->state == MEI_FILE_CONNECTED) { - cl->state = MEI_FILE_DISCONNECTING; - dev_dbg(&dev->pdev->dev, - "disconnecting client host client = %d, " - "ME client = %d\n", - cl->host_client_id, - cl->me_client_id); - rets = mei_disconnect_host_client(dev, cl); - } - mei_cl_flush_queues(cl); - dev_dbg(&dev->pdev->dev, "remove client host client = %d, ME client = %d\n", + if (cl == &dev->iamthif_cl) { + rets = mei_amthif_release(dev, file); + goto out; + } + if (cl->state == MEI_FILE_CONNECTED) { + cl->state = MEI_FILE_DISCONNECTING; + dev_dbg(&dev->pdev->dev, + "disconnecting client host client = %d, " + "ME client = %d\n", cl->host_client_id, cl->me_client_id); + rets = mei_disconnect_host_client(dev, cl); + } + mei_cl_flush_queues(cl); + dev_dbg(&dev->pdev->dev, "remove client host client = %d, ME client = %d\n", + cl->host_client_id, + cl->me_client_id); + + if (dev->open_handle_count > 0) { + clear_bit(cl->host_client_id, dev->host_clients_map); + dev->open_handle_count--; + } + mei_me_cl_unlink(dev, cl); - if (dev->open_handle_count > 0) { - clear_bit(cl->host_client_id, dev->host_clients_map); - dev->open_handle_count--; - } - mei_remove_client_from_file_list(dev, cl->host_client_id); - - /* free read cb */ - cb = NULL; - if (cl->read_cb) { - cb = find_read_list_entry(dev, cl); - /* Remove entry from read list */ - if (cb) - list_del(&cb->cb_list); - - cb = cl->read_cb; - cl->read_cb = NULL; - } - - file->private_data = NULL; - - if (cb) { - mei_free_cb_private(cb); - cb = NULL; - } + /* free read cb */ + cb = NULL; + if (cl->read_cb) { + cb = find_read_list_entry(dev, cl); + /* Remove entry from read list */ + if (cb) + list_del(&cb->list); - kfree(cl); - } else { - if (dev->open_handle_count > 0) - dev->open_handle_count--; - - if (dev->iamthif_file_object == file && - dev->iamthif_state != MEI_IAMTHIF_IDLE) { - - dev_dbg(&dev->pdev->dev, "amthi canceled iamthif state %d\n", - dev->iamthif_state); - dev->iamthif_canceled = true; - if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE) { - dev_dbg(&dev->pdev->dev, "run next amthi iamthif cb\n"); - mei_run_next_iamthif_cmd(dev); - } - } + cb = cl->read_cb; + cl->read_cb = NULL; + } - if (mei_clear_lists(dev, file)) - dev->iamthif_state = MEI_IAMTHIF_IDLE; + file->private_data = NULL; + if (cb) { + mei_io_cb_free(cb); + cb = NULL; } + + kfree(cl); +out: mutex_unlock(&dev->device_lock); return rets; } @@ -411,20 +303,19 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, } if (cl == &dev->iamthif_cl) { - rets = amthi_read(dev, file, ubuf, length, offset); + rets = mei_amthif_read(dev, file, ubuf, length, offset); goto out; } - if (cl->read_cb && cl->read_cb->information > *offset) { + if (cl->read_cb && cl->read_cb->buf_idx > *offset) { cb = cl->read_cb; goto copy_buffer; - } else if (cl->read_cb && cl->read_cb->information > 0 && - cl->read_cb->information <= *offset) { + } else if (cl->read_cb && cl->read_cb->buf_idx > 0 && + cl->read_cb->buf_idx <= *offset) { cb = cl->read_cb; rets = 0; goto free; - } else if ((!cl->read_cb || !cl->read_cb->information) && - *offset > 0) { + } else if ((!cl->read_cb || !cl->read_cb->buf_idx) && *offset > 0) { /*Offset needs to be cleaned for contiguous reads*/ *offset = 0; rets = 0; @@ -481,16 +372,15 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, copy_buffer: dev_dbg(&dev->pdev->dev, "cb->response_buffer size - %d\n", cb->response_buffer.size); - dev_dbg(&dev->pdev->dev, "cb->information - %lu\n", - cb->information); - if (length == 0 || ubuf == NULL || *offset > cb->information) { + dev_dbg(&dev->pdev->dev, "cb->buf_idx - %lu\n", cb->buf_idx); + if (length == 0 || ubuf == NULL || *offset > cb->buf_idx) { rets = -EMSGSIZE; goto free; } - /* length is being truncated to PAGE_SIZE, however, */ - /* information size may be longer */ - length = min_t(size_t, length, (cb->information - *offset)); + /* length is being truncated to PAGE_SIZE, + * however buf_idx may point beyond that */ + length = min_t(size_t, length, cb->buf_idx - *offset); if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) { rets = -EFAULT; @@ -499,15 +389,15 @@ copy_buffer: rets = length; *offset += length; - if ((unsigned long)*offset < cb->information) + if ((unsigned long)*offset < cb->buf_idx) goto out; free: cb_pos = find_read_list_entry(dev, cl); /* Remove entry from read list */ if (cb_pos) - list_del(&cb_pos->cb_list); - mei_free_cb_private(cb); + list_del(&cb_pos->list); + mei_io_cb_free(cb); cl->reading_state = MEI_IDLE; cl->read_cb = NULL; cl->read_pending = 0; @@ -516,7 +406,6 @@ out: mutex_unlock(&dev->device_lock); return rets; } - /** * mei_write - the write function. * @@ -546,23 +435,39 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, mutex_lock(&dev->device_lock); if (dev->dev_state != MEI_DEV_ENABLED) { - mutex_unlock(&dev->device_lock); - return -ENODEV; + rets = -ENODEV; + goto err; } + i = mei_me_cl_by_id(dev, cl->me_client_id); + if (i < 0) { + rets = -ENODEV; + goto err; + } + if (length > dev->me_clients[i].props.max_msg_length || length <= 0) { + rets = -EMSGSIZE; + goto err; + } + + if (cl->state != MEI_FILE_CONNECTED) { + rets = -ENODEV; + dev_err(&dev->pdev->dev, "host client = %d, is not connected to ME client = %d", + cl->host_client_id, cl->me_client_id); + goto err; + } if (cl == &dev->iamthif_cl) { - write_cb = find_amthi_read_list_entry(dev, file); + write_cb = mei_amthif_find_read_list_entry(dev, file); if (write_cb) { timeout = write_cb->read_time + - msecs_to_jiffies(IAMTHIF_READ_TIMER); + mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER); if (time_after(jiffies, timeout) || - cl->reading_state == MEI_READ_COMPLETE) { - *offset = 0; - list_del(&write_cb->cb_list); - mei_free_cb_private(write_cb); - write_cb = NULL; + cl->reading_state == MEI_READ_COMPLETE) { + *offset = 0; + list_del(&write_cb->list); + mei_io_cb_free(write_cb); + write_cb = NULL; } } } @@ -572,8 +477,8 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, *offset = 0; write_cb = find_read_list_entry(dev, cl); if (write_cb) { - list_del(&write_cb->cb_list); - mei_free_cb_private(write_cb); + list_del(&write_cb->list); + mei_io_cb_free(write_cb); write_cb = NULL; cl->reading_state = MEI_IDLE; cl->read_cb = NULL; @@ -583,24 +488,21 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, *offset = 0; - write_cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); + write_cb = mei_io_cb_init(cl, file); if (!write_cb) { - mutex_unlock(&dev->device_lock); - return -ENOMEM; + dev_err(&dev->pdev->dev, "write cb allocation failed\n"); + rets = -ENOMEM; + goto err; } + rets = mei_io_cb_alloc_req_buf(write_cb, length); + if (rets) + goto err; - write_cb->file_object = file; - write_cb->file_private = cl; - write_cb->request_buffer.data = kmalloc(length, GFP_KERNEL); - rets = -ENOMEM; - if (!write_cb->request_buffer.data) - goto unlock_dev; - - dev_dbg(&dev->pdev->dev, "length =%d\n", (int) length); + dev_dbg(&dev->pdev->dev, "cb request size = %zd\n", length); - rets = -EFAULT; - if (copy_from_user(write_cb->request_buffer.data, ubuf, length)) - goto unlock_dev; + rets = copy_from_user(write_cb->request_buffer.data, ubuf, length); + if (rets) + goto err; cl->sm_state = 0; if (length == 4 && @@ -612,139 +514,71 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, write_cb->request_buffer.data, 4) == 0))) cl->sm_state |= MEI_WD_STATE_INDEPENDENCE_MSG_SENT; - INIT_LIST_HEAD(&write_cb->cb_list); if (cl == &dev->iamthif_cl) { - write_cb->response_buffer.data = - kmalloc(dev->iamthif_mtu, GFP_KERNEL); - if (!write_cb->response_buffer.data) { - rets = -ENOMEM; - goto unlock_dev; - } - if (dev->dev_state != MEI_DEV_ENABLED) { - rets = -ENODEV; - goto unlock_dev; - } - i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id); - if (i < 0) { - rets = -ENODEV; - goto unlock_dev; - } - if (length > dev->me_clients[i].props.max_msg_length || - length <= 0) { - rets = -EMSGSIZE; - goto unlock_dev; - } + rets = mei_amthif_write(dev, write_cb); - write_cb->response_buffer.size = dev->iamthif_mtu; - write_cb->major_file_operations = MEI_IOCTL; - write_cb->information = 0; - write_cb->request_buffer.size = length; - if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) { - rets = -ENODEV; - goto unlock_dev; - } - - if (!list_empty(&dev->amthi_cmd_list.mei_cb.cb_list) || - dev->iamthif_state != MEI_IAMTHIF_IDLE) { - dev_dbg(&dev->pdev->dev, "amthi_state = %d\n", - (int) dev->iamthif_state); - dev_dbg(&dev->pdev->dev, "add amthi cb to amthi cmd waiting list\n"); - list_add_tail(&write_cb->cb_list, - &dev->amthi_cmd_list.mei_cb.cb_list); - rets = length; - } else { - dev_dbg(&dev->pdev->dev, "call amthi write\n"); - rets = amthi_write(dev, write_cb); - - if (rets) { - dev_dbg(&dev->pdev->dev, "amthi write failed with status = %d\n", - rets); - goto unlock_dev; - } - rets = length; + if (rets) { + dev_err(&dev->pdev->dev, + "amthi write failed with status = %d\n", rets); + goto err; } mutex_unlock(&dev->device_lock); - return rets; + return length; } - write_cb->major_file_operations = MEI_WRITE; - /* make sure information is zero before we start */ - - write_cb->information = 0; - write_cb->request_buffer.size = length; + write_cb->fop_type = MEI_FOP_WRITE; dev_dbg(&dev->pdev->dev, "host client = %d, ME client = %d\n", cl->host_client_id, cl->me_client_id); - if (cl->state != MEI_FILE_CONNECTED) { - rets = -ENODEV; - dev_dbg(&dev->pdev->dev, "host client = %d, is not connected to ME client = %d", - cl->host_client_id, - cl->me_client_id); - goto unlock_dev; - } - i = mei_me_cl_by_id(dev, cl->me_client_id); - if (i < 0) { - rets = -ENODEV; - goto unlock_dev; - } - if (length > dev->me_clients[i].props.max_msg_length || length <= 0) { - rets = -EINVAL; - goto unlock_dev; - } - write_cb->file_private = cl; - rets = mei_flow_ctrl_creds(dev, cl); if (rets < 0) - goto unlock_dev; + goto err; - if (rets && dev->mei_host_buffer_is_empty) { - rets = 0; - dev->mei_host_buffer_is_empty = false; - if (length > mei_hbuf_max_data(dev)) { - mei_hdr.length = mei_hbuf_max_data(dev); - mei_hdr.msg_complete = 0; - } else { - mei_hdr.length = length; - mei_hdr.msg_complete = 1; - } - mei_hdr.host_addr = cl->host_client_id; - mei_hdr.me_addr = cl->me_client_id; - mei_hdr.reserved = 0; - dev_dbg(&dev->pdev->dev, "call mei_write_message header=%08x.\n", - *((u32 *) &mei_hdr)); - if (mei_write_message(dev, &mei_hdr, - (unsigned char *) (write_cb->request_buffer.data), - mei_hdr.length)) { - rets = -ENODEV; - goto unlock_dev; - } + if (rets == 0 || dev->mei_host_buffer_is_empty == false) { + write_cb->buf_idx = 0; + mei_hdr.msg_complete = 0; cl->writing_state = MEI_WRITING; - write_cb->information = mei_hdr.length; - if (mei_hdr.msg_complete) { - if (mei_flow_ctrl_reduce(dev, cl)) { - rets = -ENODEV; - goto unlock_dev; - } - list_add_tail(&write_cb->cb_list, - &dev->write_waiting_list.mei_cb.cb_list); - } else { - list_add_tail(&write_cb->cb_list, - &dev->write_list.mei_cb.cb_list); - } + goto out; + } + dev->mei_host_buffer_is_empty = false; + if (length > mei_hbuf_max_data(dev)) { + mei_hdr.length = mei_hbuf_max_data(dev); + mei_hdr.msg_complete = 0; } else { + mei_hdr.length = length; + mei_hdr.msg_complete = 1; + } + mei_hdr.host_addr = cl->host_client_id; + mei_hdr.me_addr = cl->me_client_id; + mei_hdr.reserved = 0; + dev_dbg(&dev->pdev->dev, "call mei_write_message header=%08x.\n", + *((u32 *) &mei_hdr)); + if (mei_write_message(dev, &mei_hdr, + write_cb->request_buffer.data, mei_hdr.length)) { + rets = -ENODEV; + goto err; + } + cl->writing_state = MEI_WRITING; + write_cb->buf_idx = mei_hdr.length; - write_cb->information = 0; - cl->writing_state = MEI_WRITING; - list_add_tail(&write_cb->cb_list, - &dev->write_list.mei_cb.cb_list); +out: + if (mei_hdr.msg_complete) { + if (mei_flow_ctrl_reduce(dev, cl)) { + rets = -ENODEV; + goto err; + } + list_add_tail(&write_cb->list, &dev->write_waiting_list.list); + } else { + list_add_tail(&write_cb->list, &dev->write_list.list); } + mutex_unlock(&dev->device_lock); return length; -unlock_dev: +err: mutex_unlock(&dev->device_lock); - mei_free_cb_private(write_cb); + mei_io_cb_free(write_cb); return rets; } @@ -860,15 +694,7 @@ static unsigned int mei_poll(struct file *file, poll_table *wait) if (cl == &dev->iamthif_cl) { - mutex_unlock(&dev->device_lock); - poll_wait(file, &dev->iamthif_cl.wait, wait); - mutex_lock(&dev->device_lock); - if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE && - dev->iamthif_file_object == file) { - mask |= (POLLIN | POLLRDNORM); - dev_dbg(&dev->pdev->dev, "run next amthi cb\n"); - mei_run_next_iamthif_cmd(dev); - } + mask = mei_amthif_poll(dev, file, wait); goto out; } @@ -917,7 +743,7 @@ static struct miscdevice mei_misc_device = { * * returns true if ME Interface is valid, false otherwise */ -static bool __devinit mei_quirk_probe(struct pci_dev *pdev, +static bool mei_quirk_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { u32 reg; @@ -939,7 +765,7 @@ static bool __devinit mei_quirk_probe(struct pci_dev *pdev, * * returns 0 on success, <0 on failure. */ -static int __devinit mei_probe(struct pci_dev *pdev, +static int mei_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct mei_device *dev; @@ -1003,6 +829,8 @@ static int __devinit mei_probe(struct pci_dev *pdev, goto disable_msi; } INIT_DELAYED_WORK(&dev->timer_work, mei_timer); + INIT_WORK(&dev->init_work, mei_host_client_init); + if (mei_hw_init(dev)) { dev_err(&pdev->dev, "init hw failure.\n"); err = -ENODEV; @@ -1054,7 +882,7 @@ end: * mei_remove is called by the PCI subsystem to alert the driver * that it should release a PCI device. */ -static void __devexit mei_remove(struct pci_dev *pdev) +static void mei_remove(struct pci_dev *pdev) { struct mei_device *dev; @@ -1087,8 +915,8 @@ static void __devexit mei_remove(struct pci_dev *pdev) /* remove entry if already in list */ dev_dbg(&pdev->dev, "list del iamthif and wd file list.\n"); - mei_remove_client_from_file_list(dev, dev->wd_cl.host_client_id); - mei_remove_client_from_file_list(dev, dev->iamthif_cl.host_client_id); + mei_me_cl_unlink(dev, &dev->wd_cl); + mei_me_cl_unlink(dev, &dev->iamthif_cl); dev->iamthif_current_cb = NULL; dev->me_clients_num = 0; @@ -1195,8 +1023,8 @@ static struct pci_driver mei_driver = { .name = KBUILD_MODNAME, .id_table = mei_pci_tbl, .probe = mei_probe, - .remove = __devexit_p(mei_remove), - .shutdown = __devexit_p(mei_remove), + .remove = mei_remove, + .shutdown = mei_remove, .driver.pm = MEI_PM_OPS, }; diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index adb35fb9281..25da04549d0 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -19,6 +19,7 @@ #include <linux/types.h> #include <linux/watchdog.h> +#include <linux/poll.h> #include <linux/mei.h> #include "hw.h" @@ -125,13 +126,20 @@ enum mei_wd_states { MEI_WD_STOPPING, }; -/* MEI CB */ -enum mei_cb_major_types { - MEI_READ = 0, - MEI_WRITE, - MEI_IOCTL, - MEI_OPEN, - MEI_CLOSE +/** + * enum mei_cb_file_ops - file operation associated with the callback + * @MEI_FOP_READ - read + * @MEI_FOP_WRITE - write + * @MEI_FOP_IOCTL - ioctl + * @MEI_FOP_OPEN - open + * @MEI_FOP_CLOSE - close + */ +enum mei_cb_file_ops { + MEI_FOP_READ = 0, + MEI_FOP_WRITE, + MEI_FOP_IOCTL, + MEI_FOP_OPEN, + MEI_FOP_CLOSE }; /* @@ -143,13 +151,21 @@ struct mei_message_data { }; +struct mei_cl; + +/** + * struct mei_cl_cb - file operation callback structure + * + * @cl - file client who is running this operation + * @fop_type - file operation type + */ struct mei_cl_cb { - struct list_head cb_list; - enum mei_cb_major_types major_file_operations; - void *file_private; + struct list_head list; + struct mei_cl *cl; + enum mei_cb_file_ops fop_type; struct mei_message_data request_buffer; struct mei_message_data response_buffer; - unsigned long information; + unsigned long buf_idx; unsigned long read_time; struct file *file_object; }; @@ -175,29 +191,23 @@ struct mei_cl { struct mei_cl_cb *read_cb; }; -struct mei_io_list { - struct mei_cl_cb mei_cb; -}; - /** - * struct mei_deive - MEI private device struct + * struct mei_device - MEI private device struct * @hbuf_depth - depth of host(write) buffer + * @wr_ext_msg - buffer for hbm control responses (set in read cycle) */ struct mei_device { struct pci_dev *pdev; /* pointer to pci device struct */ /* * lists of queues */ - /* array of pointers to aio lists */ - struct mei_io_list read_list; /* driver read queue */ - struct mei_io_list write_list; /* driver write queue */ - struct mei_io_list write_waiting_list; /* write waiting queue */ - struct mei_io_list ctrl_wr_list; /* managed write IOCTL list */ - struct mei_io_list ctrl_rd_list; /* managed read IOCTL list */ - struct mei_io_list amthi_cmd_list; /* amthi list for cmd waiting */ - - /* driver managed amthi list for reading completed amthi cmd data */ - struct mei_io_list amthi_read_complete_list; + /* array of pointers to aio lists */ + struct mei_cl_cb read_list; /* driver read queue */ + struct mei_cl_cb write_list; /* driver write queue */ + struct mei_cl_cb write_waiting_list; /* write waiting queue */ + struct mei_cl_cb ctrl_wr_list; /* managed write IOCTL list */ + struct mei_cl_cb ctrl_rd_list; /* managed read IOCTL list */ + /* * list of files */ @@ -235,11 +245,13 @@ struct mei_device { u16 init_clients_timer; bool need_reset; - u32 extra_write_index; unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE]; /* control messages */ - u32 wr_msg_buf[128]; /* used for control messages */ - u32 ext_msg_buf[8]; /* for control responses */ u32 rd_msg_hdr; + u32 wr_msg_buf[128]; /* used for control messages */ + struct { + struct mei_msg_hdr hdr; + unsigned char data[4]; /* All HBM messages are 4 bytes */ + } wr_ext_msg; /* for control responses */ struct hbm_version version; @@ -253,12 +265,15 @@ struct mei_device { struct mei_cl wd_cl; enum mei_wd_states wd_state; - bool wd_interface_reg; bool wd_pending; u16 wd_timeout; unsigned char wd_data[MEI_WD_START_MSG_SIZE]; + /* amthif list for cmd waiting */ + struct mei_cl_cb amthif_cmd_list; + /* driver managed amthif list for reading completed amthif cmd data */ + struct mei_cl_cb amthif_rd_complete_list; struct file *iamthif_file_object; struct mei_cl iamthif_cl; struct mei_cl_cb *iamthif_current_cb; @@ -272,8 +287,15 @@ struct mei_device { bool iamthif_flow_control_pending; bool iamthif_ioctl; bool iamthif_canceled; + + struct work_struct init_work; }; +static inline unsigned long mei_secs_to_jiffies(unsigned long sec) +{ + return msecs_to_jiffies(sec * MSEC_PER_SEC); +} + /* * mei init function prototypes @@ -284,21 +306,34 @@ int mei_hw_init(struct mei_device *dev); int mei_task_initialize_clients(void *data); int mei_initialize_clients(struct mei_device *dev); int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl); -void mei_remove_client_from_file_list(struct mei_device *dev, u8 host_client_id); -void mei_host_init_iamthif(struct mei_device *dev); void mei_allocate_me_clients_storage(struct mei_device *dev); -int mei_me_cl_update_filext(struct mei_device *dev, struct mei_cl *cl, +int mei_me_cl_link(struct mei_device *dev, struct mei_cl *cl, const uuid_le *cguid, u8 host_client_id); +void mei_me_cl_unlink(struct mei_device *dev, struct mei_cl *cl); int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *cuuid); int mei_me_cl_by_id(struct mei_device *dev, u8 client_id); /* - * MEI IO List Functions + * MEI IO Functions + */ +struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp); +void mei_io_cb_free(struct mei_cl_cb *priv_cb); +int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length); +int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length); + + +/** + * mei_io_list_init - Sets up a queue list. + * + * @list: An instance cl callback structure */ -void mei_io_list_init(struct mei_io_list *list); -void mei_io_list_flush(struct mei_io_list *list, struct mei_cl *cl); +static inline void mei_io_list_init(struct mei_cl_cb *list) +{ + INIT_LIST_HEAD(&list->list); +} +void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl); /* * MEI ME Client Functions @@ -330,7 +365,8 @@ static inline bool mei_cl_cmp_id(const struct mei_cl *cl1, */ void mei_host_start_message(struct mei_device *dev); void mei_host_enum_clients_message(struct mei_device *dev); -int mei_host_client_properties(struct mei_device *dev); +int mei_host_client_enumerate(struct mei_device *dev); +void mei_host_client_init(struct work_struct *work); /* * MEI interrupt functions prototype @@ -347,18 +383,40 @@ int mei_ioctl_connect_client(struct file *file, int mei_start_read(struct mei_device *dev, struct mei_cl *cl); -int amthi_write(struct mei_device *dev, struct mei_cl_cb *priv_cb); -int amthi_read(struct mei_device *dev, struct file *file, - char __user *ubuf, size_t length, loff_t *offset); +/* + * AMTHIF - AMT Host Interface Functions + */ +void mei_amthif_reset_params(struct mei_device *dev); + +void mei_amthif_host_init(struct mei_device *dev); + +int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *priv_cb); -struct mei_cl_cb *find_amthi_read_list_entry(struct mei_device *dev, +int mei_amthif_read(struct mei_device *dev, struct file *file, + char __user *ubuf, size_t length, loff_t *offset); + +unsigned int mei_amthif_poll(struct mei_device *dev, + struct file *file, poll_table *wait); + +int mei_amthif_release(struct mei_device *dev, struct file *file); + +struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev, struct file *file); -void mei_run_next_iamthif_cmd(struct mei_device *dev); +void mei_amthif_run_next_cmd(struct mei_device *dev); + -void mei_free_cb_private(struct mei_cl_cb *priv_cb); +int mei_amthif_read_message(struct mei_cl_cb *complete_list, + struct mei_device *dev, struct mei_msg_hdr *mei_hdr); +int mei_amthif_irq_write_complete(struct mei_device *dev, s32 *slots, + struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list); + +void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb); +int mei_amthif_irq_read_message(struct mei_cl_cb *complete_list, + struct mei_device *dev, struct mei_msg_hdr *mei_hdr); +int mei_amthif_irq_read(struct mei_device *dev, s32 *slots); /* * Register Access Function @@ -437,4 +495,15 @@ void mei_csr_clear_his(struct mei_device *dev); void mei_enable_interrupts(struct mei_device *dev); void mei_disable_interrupts(struct mei_device *dev); +static inline struct mei_msg_hdr *mei_hbm_hdr(u32 *buf, size_t length) +{ + struct mei_msg_hdr *hdr = (struct mei_msg_hdr *)buf; + hdr->host_addr = 0; + hdr->me_addr = 0; + hdr->length = length; + hdr->msg_complete = 1; + hdr->reserved = 0; + return hdr; +} + #endif diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c index d96c537f046..636409f9667 100644 --- a/drivers/misc/mei/wd.c +++ b/drivers/misc/mei/wd.c @@ -62,6 +62,7 @@ static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout) */ int mei_wd_host_init(struct mei_device *dev) { + int id; mei_cl_init(&dev->wd_cl, dev); /* look for WD client and connect to it */ @@ -69,12 +70,11 @@ int mei_wd_host_init(struct mei_device *dev) dev->wd_timeout = MEI_WD_DEFAULT_TIMEOUT; dev->wd_state = MEI_WD_IDLE; - /* find ME WD client */ - mei_me_cl_update_filext(dev, &dev->wd_cl, + /* Connect WD ME client to the host client */ + id = mei_me_cl_link(dev, &dev->wd_cl, &mei_wd_guid, MEI_WD_HOST_CLIENT_ID); - dev_dbg(&dev->pdev->dev, "wd: check client\n"); - if (MEI_FILE_CONNECTING != dev->wd_cl.state) { + if (id < 0) { dev_info(&dev->pdev->dev, "wd: failed to find the client\n"); return -ENOENT; } @@ -85,7 +85,7 @@ int mei_wd_host_init(struct mei_device *dev) dev->wd_cl.host_client_id = 0; return -EIO; } - dev->wd_cl.timer_count = CONNECT_TIMEOUT; + dev->wd_cl.timer_count = MEI_CONNECT_TIMEOUT; return 0; } @@ -360,23 +360,20 @@ void mei_watchdog_register(struct mei_device *dev) if (watchdog_register_device(&amt_wd_dev)) { dev_err(&dev->pdev->dev, "wd: unable to register watchdog device.\n"); - dev->wd_interface_reg = false; return; } dev_dbg(&dev->pdev->dev, "wd: successfully register watchdog interface.\n"); - dev->wd_interface_reg = true; watchdog_set_drvdata(&amt_wd_dev, dev); } void mei_watchdog_unregister(struct mei_device *dev) { - if (!dev->wd_interface_reg) + if (test_bit(WDOG_UNREGISTERED, &amt_wd_dev.status)) return; watchdog_set_drvdata(&amt_wd_dev, NULL); watchdog_unregister_device(&amt_wd_dev); - dev->wd_interface_reg = false; } diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c index c9f20dae185..931e635aa49 100644 --- a/drivers/misc/pch_phub.c +++ b/drivers/misc/pch_phub.c @@ -666,7 +666,7 @@ static struct bin_attribute pch_bin_attr = { .write = pch_phub_bin_write, }; -static int __devinit pch_phub_probe(struct pci_dev *pdev, +static int pch_phub_probe(struct pci_dev *pdev, const struct pci_device_id *id) { int retval; @@ -819,7 +819,7 @@ err_pci_enable_dev: return ret; } -static void __devexit pch_phub_remove(struct pci_dev *pdev) +static void pch_phub_remove(struct pci_dev *pdev) { struct pch_phub_reg *chip = pci_get_drvdata(pdev); @@ -888,7 +888,7 @@ static struct pci_driver pch_phub_driver = { .name = "pch_phub", .id_table = pch_phub_pcidev_id, .probe = pch_phub_probe, - .remove = __devexit_p(pch_phub_remove), + .remove = pch_phub_remove, .suspend = pch_phub_suspend, .resume = pch_phub_resume }; diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c index 21b28fc6d91..68b7c773d2c 100644 --- a/drivers/misc/phantom.c +++ b/drivers/misc/phantom.c @@ -324,7 +324,7 @@ static irqreturn_t phantom_isr(int irq, void *data) * Init and deinit driver */ -static unsigned int __devinit phantom_get_free(void) +static unsigned int phantom_get_free(void) { unsigned int i; @@ -335,7 +335,7 @@ static unsigned int __devinit phantom_get_free(void) return i; } -static int __devinit phantom_probe(struct pci_dev *pdev, +static int phantom_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) { struct phantom_device *pht; @@ -435,7 +435,7 @@ err: return retval; } -static void __devexit phantom_remove(struct pci_dev *pdev) +static void phantom_remove(struct pci_dev *pdev) { struct phantom_device *pht = pci_get_drvdata(pdev); unsigned int minor = MINOR(pht->cdev.dev); @@ -487,7 +487,7 @@ static int phantom_resume(struct pci_dev *pdev) #define phantom_resume NULL #endif -static struct pci_device_id phantom_pci_tbl[] __devinitdata = { +static struct pci_device_id phantom_pci_tbl[] = { { .vendor = PCI_VENDOR_ID_PLX, .device = PCI_DEVICE_ID_PLX_9050, .subvendor = PCI_VENDOR_ID_PLX, .subdevice = PCI_DEVICE_ID_PLX_9050, .class = PCI_CLASS_BRIDGE_OTHER << 8, .class_mask = 0xffff00 }, @@ -499,7 +499,7 @@ static struct pci_driver phantom_pci_driver = { .name = "phantom", .id_table = phantom_pci_tbl, .probe = phantom_probe, - .remove = __devexit_p(phantom_remove), + .remove = phantom_remove, .suspend = phantom_suspend, .resume = phantom_resume }; diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c index 4999b34b7a6..f84ff0c0603 100644 --- a/drivers/misc/pti.c +++ b/drivers/misc/pti.c @@ -76,7 +76,7 @@ struct pti_dev { */ static DEFINE_MUTEX(alloclock); -static const struct pci_device_id pci_ids[] __devinitconst = { +static const struct pci_device_id pci_ids[] = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x82B)}, {0} }; @@ -796,7 +796,7 @@ static const struct tty_port_operations tty_port_ops = { * 0 for success * otherwise, error */ -static int __devinit pti_pci_probe(struct pci_dev *pdev, +static int pti_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { unsigned int a; @@ -879,14 +879,17 @@ err: * PCI bus. * @pdev: variable containing pci info of PTI. */ -static void __devexit pti_pci_remove(struct pci_dev *pdev) +static void pti_pci_remove(struct pci_dev *pdev) { struct pti_dev *drv_data = pci_get_drvdata(pdev); + unsigned int a; unregister_console(&pti_console); - tty_unregister_device(pti_tty_driver, 0); - tty_unregister_device(pti_tty_driver, 1); + for (a = 0; a < PTITTY_MINOR_NUM; a++) { + tty_unregister_device(pti_tty_driver, a); + tty_port_destroy(&drv_data->port[a]); + } iounmap(drv_data->pti_ioaddr); pci_set_drvdata(pdev, NULL); @@ -901,7 +904,7 @@ static struct pci_driver pti_pci_driver = { .name = PCINAME, .id_table = pci_ids, .probe = pti_pci_probe, - .remove = __devexit_p(pti_pci_remove), + .remove = pti_pci_remove, }; /** diff --git a/drivers/misc/spear13xx_pcie_gadget.c b/drivers/misc/spear13xx_pcie_gadget.c index 123ed98eec3..7deb25dc86a 100644 --- a/drivers/misc/spear13xx_pcie_gadget.c +++ b/drivers/misc/spear13xx_pcie_gadget.c @@ -711,7 +711,7 @@ static void spear13xx_pcie_device_init(struct spear_pcie_gadget_config *config) spear_dbi_write_reg(config, PCI_INTERRUPT_LINE, 1, 1); } -static int __devinit spear_pcie_gadget_probe(struct platform_device *pdev) +static int spear_pcie_gadget_probe(struct platform_device *pdev) { struct resource *res0, *res1; unsigned int status = 0; @@ -853,7 +853,7 @@ err_rel_res0: return status; } -static int __devexit spear_pcie_gadget_remove(struct platform_device *pdev) +static int spear_pcie_gadget_remove(struct platform_device *pdev) { struct resource *res0, *res1; static struct pcie_gadget_target *target; diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c index 46937b10726..b90a2241d79 100644 --- a/drivers/misc/ti-st/st_core.c +++ b/drivers/misc/ti-st/st_core.c @@ -511,7 +511,6 @@ long st_register(struct st_proto_s *new_proto) unsigned long flags = 0; st_kim_ref(&st_gdata, 0); - pr_info("%s(%d) ", __func__, new_proto->chnl_id); if (st_gdata == NULL || new_proto == NULL || new_proto->recv == NULL || new_proto->reg_complete_cb == NULL) { pr_err("gdata/new_proto/recv or reg_complete_cb not ready"); diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index 04a819944f6..9ff942a346e 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c @@ -705,9 +705,9 @@ static const struct file_operations list_debugfs_fops = { static struct dentry *kim_debugfs_dir; static int kim_probe(struct platform_device *pdev) { - long status; struct kim_data_s *kim_gdata; struct ti_st_plat_data *pdata = pdev->dev.platform_data; + int err; if ((pdev->id != -1) && (pdev->id < MAX_ST_DEVICES)) { /* multiple devices could exist */ @@ -724,10 +724,11 @@ static int kim_probe(struct platform_device *pdev) } dev_set_drvdata(&pdev->dev, kim_gdata); - status = st_core_init(&kim_gdata->core_data); - if (status != 0) { + err = st_core_init(&kim_gdata->core_data); + if (err != 0) { pr_err(" ST core init failed"); - return -EIO; + err = -EIO; + goto err_core_init; } /* refer to itself */ kim_gdata->core_data->kim_data = kim_gdata; @@ -738,10 +739,10 @@ static int kim_probe(struct platform_device *pdev) init_completion(&kim_gdata->kim_rcvd); init_completion(&kim_gdata->ldisc_installed); - status = sysfs_create_group(&pdev->dev.kobj, &uim_attr_grp); - if (status) { + err = sysfs_create_group(&pdev->dev.kobj, &uim_attr_grp); + if (err) { pr_err("failed to create sysfs entries"); - return status; + goto err_sysfs_group; } /* copying platform data */ @@ -753,8 +754,8 @@ static int kim_probe(struct platform_device *pdev) kim_debugfs_dir = debugfs_create_dir("ti-st", NULL); if (IS_ERR(kim_debugfs_dir)) { pr_err(" debugfs entries creation failed "); - kim_debugfs_dir = NULL; - return -EIO; + err = -EIO; + goto err_debugfs_dir; } debugfs_create_file("version", S_IRUGO, kim_debugfs_dir, @@ -763,6 +764,17 @@ static int kim_probe(struct platform_device *pdev) kim_gdata, &list_debugfs_fops); pr_info(" debugfs entries created "); return 0; + +err_debugfs_dir: + sysfs_remove_group(&pdev->dev.kobj, &uim_attr_grp); + +err_sysfs_group: + st_core_exit(kim_gdata->core_data); + +err_core_init: + kfree(kim_gdata); + + return err; } static int kim_remove(struct platform_device *pdev) diff --git a/drivers/misc/ti_dac7512.c b/drivers/misc/ti_dac7512.c index 5acbba120de..1d86407189e 100644 --- a/drivers/misc/ti_dac7512.c +++ b/drivers/misc/ti_dac7512.c @@ -54,7 +54,7 @@ static const struct attribute_group dac7512_attr_group = { .attrs = dac7512_attributes, }; -static int __devinit dac7512_probe(struct spi_device *spi) +static int dac7512_probe(struct spi_device *spi) { int ret; @@ -67,7 +67,7 @@ static int __devinit dac7512_probe(struct spi_device *spi) return sysfs_create_group(&spi->dev.kobj, &dac7512_attr_group); } -static int __devexit dac7512_remove(struct spi_device *spi) +static int dac7512_remove(struct spi_device *spi) { sysfs_remove_group(&spi->dev.kobj, &dac7512_attr_group); return 0; @@ -79,7 +79,7 @@ static struct spi_driver dac7512_driver = { .owner = THIS_MODULE, }, .probe = dac7512_probe, - .remove = __devexit_p(dac7512_remove), + .remove = dac7512_remove, }; module_spi_driver(dac7512_driver); diff --git a/drivers/misc/tsl2550.c b/drivers/misc/tsl2550.c index 0beb298a17d..1e7bc0eb081 100644 --- a/drivers/misc/tsl2550.c +++ b/drivers/misc/tsl2550.c @@ -347,7 +347,7 @@ static int tsl2550_init_client(struct i2c_client *client) */ static struct i2c_driver tsl2550_driver; -static int __devinit tsl2550_probe(struct i2c_client *client, +static int tsl2550_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); @@ -405,7 +405,7 @@ exit: return err; } -static int __devexit tsl2550_remove(struct i2c_client *client) +static int tsl2550_remove(struct i2c_client *client) { sysfs_remove_group(&client->dev.kobj, &tsl2550_attr_group); @@ -450,7 +450,7 @@ static struct i2c_driver tsl2550_driver = { .suspend = tsl2550_suspend, .resume = tsl2550_resume, .probe = tsl2550_probe, - .remove = __devexit_p(tsl2550_remove), + .remove = tsl2550_remove, .id_table = tsl2550_id, }; |