From d47f3640fe2ac4da8a8e713a549e6eaf23ac2084 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 19 Apr 2006 15:42:28 -0700 Subject: [SUNGEM]: Marvell PHY suspend. In a short discussion with Benjamin Herrenschmidt he mentioned that Marvell PHYs are powered down the same way as the other ones we currently handle. Thus actually do that, hopefully saving some power during suspend. Signed-off-by: Johannes Berg Acked-by: Benjamin Herrenschmidt Signed-off-by: David S. Miller --- drivers/net/sungem_phy.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sungem_phy.c b/drivers/net/sungem_phy.c index cb0aba95d4e3..046371ee5bbe 100644 --- a/drivers/net/sungem_phy.c +++ b/drivers/net/sungem_phy.c @@ -275,7 +275,7 @@ static int bcm5411_init(struct mii_phy* phy) return 0; } -static int bcm5411_suspend(struct mii_phy* phy) +static int generic_suspend(struct mii_phy* phy) { phy_write(phy, MII_BMCR, BMCR_PDOWN); @@ -738,7 +738,7 @@ static struct mii_phy_def bcm5401_phy_def = { /* Broadcom BCM 5411 */ static struct mii_phy_ops bcm5411_phy_ops = { .init = bcm5411_init, - .suspend = bcm5411_suspend, + .suspend = generic_suspend, .setup_aneg = bcm54xx_setup_aneg, .setup_forced = bcm54xx_setup_forced, .poll_link = genmii_poll_link, @@ -757,7 +757,7 @@ static struct mii_phy_def bcm5411_phy_def = { /* Broadcom BCM 5421 */ static struct mii_phy_ops bcm5421_phy_ops = { .init = bcm5421_init, - .suspend = bcm5411_suspend, + .suspend = generic_suspend, .setup_aneg = bcm54xx_setup_aneg, .setup_forced = bcm54xx_setup_forced, .poll_link = genmii_poll_link, @@ -776,7 +776,7 @@ static struct mii_phy_def bcm5421_phy_def = { /* Broadcom BCM 5421 built-in K2 */ static struct mii_phy_ops bcm5421k2_phy_ops = { .init = bcm5421_init, - .suspend = bcm5411_suspend, + .suspend = generic_suspend, .setup_aneg = bcm54xx_setup_aneg, .setup_forced = bcm54xx_setup_forced, .poll_link = genmii_poll_link, @@ -795,7 +795,7 @@ static struct mii_phy_def bcm5421k2_phy_def = { /* Broadcom BCM 5462 built-in Vesta */ static struct mii_phy_ops bcm5462V_phy_ops = { .init = bcm5421_init, - .suspend = bcm5411_suspend, + .suspend = generic_suspend, .setup_aneg = bcm54xx_setup_aneg, .setup_forced = bcm54xx_setup_forced, .poll_link = genmii_poll_link, @@ -816,6 +816,7 @@ static struct mii_phy_def bcm5462V_phy_def = { * would be useful here) --BenH. */ static struct mii_phy_ops marvell_phy_ops = { + .suspend = generic_suspend, .setup_aneg = marvell_setup_aneg, .setup_forced = marvell_setup_forced, .poll_link = genmii_poll_link, -- cgit v1.2.3 From 4d6c58899c1cdac018f92cfa0383bb835a0c80ef Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 21 Apr 2006 15:04:22 +1000 Subject: [PATCH] powerpc: fix oops in alsa powermac driver This fixes an oops in 2.6.16.X when loading the snd_powermac module. The name of the requested module changed during the 2.6.16 development cycle from i2c-keylargo to i2c-powermac. Signed-off-by: Guido Guenther Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman Signed-off-by: Paul Mackerras --- drivers/macintosh/therm_adt746x.c | 4 ++-- sound/oss/dmasound/tas_common.c | 4 ++-- sound/ppc/daca.c | 2 +- sound/ppc/tumbler.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index 5ebfd1d138da..5282fec17075 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c @@ -627,8 +627,8 @@ thermostat_init(void) if(therm_type == ADT7460) device_create_file(&of_dev->dev, &dev_attr_sensor2_fan_speed); -#ifndef CONFIG_I2C_KEYWEST - request_module("i2c-keywest"); +#ifndef CONFIG_I2C_POWERMAC + request_module("i2c-powermac"); #endif return i2c_add_driver(&thermostat_driver); diff --git a/sound/oss/dmasound/tas_common.c b/sound/oss/dmasound/tas_common.c index 81315996c0f1..882ae98a41b1 100644 --- a/sound/oss/dmasound/tas_common.c +++ b/sound/oss/dmasound/tas_common.c @@ -195,8 +195,8 @@ tas_init(int driver_id, const char *driver_name) printk(KERN_INFO "tas driver [%s])\n", driver_name); -#ifndef CONFIG_I2C_KEYWEST - request_module("i2c-keywest"); +#ifndef CONFIG_I2C_POWERMAC + request_module("i2c-powermac"); #endif tas_node = find_devices("deq"); if (tas_node == NULL) diff --git a/sound/ppc/daca.c b/sound/ppc/daca.c index aa09ebd9ffb8..46eebf5610e3 100644 --- a/sound/ppc/daca.c +++ b/sound/ppc/daca.c @@ -255,7 +255,7 @@ int __init snd_pmac_daca_init(struct snd_pmac *chip) #ifdef CONFIG_KMOD if (current->fs->root) - request_module("i2c-keywest"); + request_module("i2c-powermac"); #endif /* CONFIG_KMOD */ mix = kmalloc(sizeof(*mix), GFP_KERNEL); diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index 1146dd882bb1..70e4ebc70260 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c @@ -1313,7 +1313,7 @@ int __init snd_pmac_tumbler_init(struct snd_pmac *chip) #ifdef CONFIG_KMOD if (current->fs->root) - request_module("i2c-keywest"); + request_module("i2c-powermac"); #endif /* CONFIG_KMOD */ mix = kmalloc(sizeof(*mix), GFP_KERNEL); -- cgit v1.2.3 From 67a5a59d3301949f51f2d617d689f005c6d21470 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Mon, 27 Mar 2006 19:52:14 +0000 Subject: [PARISC] Misc. janitorial work Fix a spelling mistake, add a KERN_INFO flag, and fix some whitespace uglies. Signed-off-by: Helge Deller Signed-off-by: Kyle McMartin --- arch/parisc/kernel/cache.c | 4 ++-- arch/parisc/mm/fault.c | 2 +- drivers/parisc/pdc_stable.c | 2 +- drivers/parisc/superio.c | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index 360b7391cb8c..c057ad7605ba 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1999 Helge Deller (07-13-1999) + * Copyright (C) 1999-2006 Helge Deller (07-13-1999) * Copyright (C) 1999 SuSE GmbH Nuernberg * Copyright (C) 2000 Philipp Rumpf (prumpf@tux.org) * @@ -358,5 +358,5 @@ void parisc_setup_cache_timing(void) if (!parisc_cache_flush_threshold) parisc_cache_flush_threshold = FLUSH_THRESHOLD; - printk("Setting cache flush threshold to %x (%d CPUs online)\n", parisc_cache_flush_threshold, num_online_cpus()); + printk(KERN_INFO "Setting cache flush threshold to %x (%d CPUs online)\n", parisc_cache_flush_threshold, num_online_cpus()); } diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c index 0ad945d4c0a4..64785e46f93b 100644 --- a/arch/parisc/mm/fault.c +++ b/arch/parisc/mm/fault.c @@ -186,7 +186,7 @@ good_area: break; case VM_FAULT_SIGBUS: /* - * We hit a hared mapping outside of the file, or some + * We hit a shared mapping outside of the file, or some * other thing happened to us that made us unable to * handle the page fault gracefully. */ diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c index 4e53be9c03ab..bbeabe3fc4c6 100644 --- a/drivers/parisc/pdc_stable.c +++ b/drivers/parisc/pdc_stable.c @@ -535,7 +535,7 @@ pdcs_auto_read(struct subsystem *entry, char *buf, int knob) { char *out = buf; struct pdcspath_entry *pathentry; - + if (!entry || !buf) return -EINVAL; diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c index 719b863bc20e..828eb45062de 100644 --- a/drivers/parisc/superio.c +++ b/drivers/parisc/superio.c @@ -155,7 +155,7 @@ superio_init(struct pci_dev *pcidev) struct pci_dev *pdev = sio->lio_pdev; u16 word; - if (sio->suckyio_irq_enabled) + if (sio->suckyio_irq_enabled) return; BUG_ON(!pdev); @@ -194,7 +194,7 @@ superio_init(struct pci_dev *pcidev) request_region (sio->acpi_base, 0x1f, "acpi"); /* Enable the legacy I/O function */ - pci_read_config_word (pdev, PCI_COMMAND, &word); + pci_read_config_word (pdev, PCI_COMMAND, &word); word |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_IO; pci_write_config_word (pdev, PCI_COMMAND, word); -- cgit v1.2.3 From b312c33e362696d873931d8f84a89b3e894077c8 Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Thu, 30 Mar 2006 07:13:21 +0000 Subject: [PARISC] Document that we tolerate "Relaxed Ordering" This means "DMA Read returns" can bypass "MMIO Writes". Violating the PCI specs in this case improves outbound DMA "flows" and is currently not required by any drivers. This is NOT a new behavior. Previous chipsets did this already and I believe ZX1 PDC was already setting this for hpux. I just want to further document the behavior. Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin --- drivers/parisc/sba_iommu.c | 45 ++++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index 42b32ff2fca6..278f325021ee 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -178,6 +178,11 @@ extern struct proc_dir_entry * proc_mckinley_root; #define ROPE6_CTL 0x230 #define ROPE7_CTL 0x238 +#define IOC_ROPE0_CFG 0x500 /* pluto only */ +#define IOC_ROPE_AO 0x10 /* Allow "Relaxed Ordering" */ + + + #define HF_ENABLE 0x40 @@ -1759,19 +1764,33 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa, sba_dev->num_ioc = num_ioc; for (i = 0; i < num_ioc; i++) { - /* - ** Make sure the box crashes if we get any errors on a rope. - */ - WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE0_CTL); - WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE1_CTL); - WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE2_CTL); - WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE3_CTL); - WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE4_CTL); - WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE5_CTL); - WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE6_CTL); - WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE7_CTL); - - /* flush out the writes */ + unsigned long ioc_hpa = sba_dev->ioc[i].ioc_hpa; + unsigned int j; + + for (j=0; j < sizeof(u64) * ROPES_PER_IOC; j+=sizeof(u64)) { + + /* + * Clear ROPE(N)_CONFIG AO bit. + * Disables "NT Ordering" (~= !"Relaxed Ordering") + * Overrides bit 1 in DMA Hint Sets. + * Improves netperf UDP_STREAM by ~10% for bcm5701. + */ + if (IS_PLUTO(sba_dev->iodc)) { + unsigned long rope_cfg, cfg_val; + + rope_cfg = ioc_hpa + IOC_ROPE0_CFG + j; + cfg_val = READ_REG(rope_cfg); + cfg_val &= ~IOC_ROPE_AO; + WRITE_REG(cfg_val, rope_cfg); + } + + /* + ** Make sure the box crashes on rope errors. + */ + WRITE_REG(HF_ENABLE, ioc_hpa + ROPE0_CTL + j); + } + + /* flush out the last writes */ READ_REG(sba_dev->ioc[i].ioc_hpa + ROPE7_CTL); DBG_INIT(" ioc[%d] ROPE_CFG 0x%Lx ROPE_DBG 0x%Lx\n", -- cgit v1.2.3 From d668da80d613def981c573354e1853e38bd0698d Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Mon, 3 Apr 2006 13:44:17 +0000 Subject: [PARISC] Fix up hil_kbd.c mismerge Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin --- drivers/input/keyboard/hil_kbd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c index 1dca3cf42a54..2e4abdc26367 100644 --- a/drivers/input/keyboard/hil_kbd.c +++ b/drivers/input/keyboard/hil_kbd.c @@ -350,11 +350,11 @@ static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv) return 0; bail2: serio_close(serio); + serio_set_drvdata(serio, NULL); bail1: input_free_device(kbd->dev); bail0: kfree(kbd); - serio_set_drvdata(serio, NULL); return -EIO; } -- cgit v1.2.3 From 6542729809baa3674b16a76a68346f449266c6dd Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 4 Apr 2006 10:17:52 +0200 Subject: [PATCH] pcmcia: add new ID to pcnet_cs This adds a new ID to pcnet_cs, as noted by Kuro Moji. Signed-off-by: Dominik Brodowski --- drivers/net/pcmcia/pcnet_cs.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 506e777c5f06..d090df413049 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -1639,6 +1639,7 @@ static struct pcmcia_device_id pcnet_ids[] = { PCMCIA_DEVICE_PROD_ID12("CONTEC", "C-NET(PC)C-10L", 0x21cab552, 0xf6f90722), PCMCIA_DEVICE_PROD_ID12("corega", "FEther PCC-TXF", 0x0a21501a, 0xa51564a2), PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega EtherII PCC-T", 0x5261440f, 0xfa9d85bd), + PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega EtherII PCC-TD", 0x5261440f, 0xc49bd73d), PCMCIA_DEVICE_PROD_ID12("Corega K.K.", "corega EtherII PCC-TD", 0xd4fdcbd8, 0xc49bd73d), PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega Ether PCC-T", 0x5261440f, 0x6705fcaa), PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FastEther PCC-TX", 0x5261440f, 0x485e85d9), -- cgit v1.2.3 From 6171b88b436ceb91d602ca570e63a0dcdd56648e Mon Sep 17 00:00:00 2001 From: Komuro Date: Sun, 2 Apr 2006 17:39:27 +0900 Subject: [PATCH] pcmcia: unload second device first Use list_add instead of list_add_tail for pcmcia_device_add so that second device of multi-function-card will be unloaded first. Signed-off-by: komurojun-mbn@nifty.com Signed-off-by: Dominik Brodowski --- drivers/pcmcia/ds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index ae10d1eed65e..7582362a38c3 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -628,7 +628,7 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f } /* Add to the list in pcmcia_bus_socket */ - list_add_tail(&p_dev->socket_device_list, &s->devices_list); + list_add(&p_dev->socket_device_list, &s->devices_list); spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); -- cgit v1.2.3 From 90ff87008df12da7f2486178d0dee13745c1de6b Mon Sep 17 00:00:00 2001 From: Komuro Date: Sun, 12 Mar 2006 11:32:07 +0900 Subject: [PATCH] pcmcia: fix comment for pcmcia_load_firmware The comment of "pcmcia_load_firmware" is wrong: the firmware(*.cis) files reside in /lib/firmware/ _not_ /lib/firmware/cis/ . Signed-off-by: komurojun-mbn@nifty.com Signed-off-by: Dominik Brodowski --- drivers/pcmcia/ds.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 7582362a38c3..7b7428c77d7a 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -236,11 +236,11 @@ static void pcmcia_check_driver(struct pcmcia_driver *p_drv) /** * pcmcia_load_firmware - load CIS from userspace if device-provided is broken * @dev - the pcmcia device which needs a CIS override - * @filename - requested filename in /lib/firmware/cis/ + * @filename - requested filename in /lib/firmware/ * * This uses the in-kernel firmware loading mechanism to use a "fake CIS" if * the one provided by the card is broken. The firmware files reside in - * /lib/firmware/cis/ in userspace. + * /lib/firmware/ in userspace. */ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename) { -- cgit v1.2.3 From a0aab14322a74ab5665704c6155bf48fbc38f445 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 4 Apr 2006 11:09:26 +0200 Subject: [PATCH] pcmcia: do not set dev_node to NULL too early If we set dev_node to NULL too early, some drivers which used this to determine whether unregister_netdev() needs to be called fail when removing a PCMCIA card. Signed-off-by: Dominik Brodowski --- drivers/pcmcia/ds.c | 2 ++ drivers/pcmcia/pcmcia_resource.c | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 7b7428c77d7a..0f98cab35186 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -476,6 +476,8 @@ static int pcmcia_device_remove(struct device * dev) if (p_drv->remove) p_drv->remove(p_dev); + p_dev->dev_node = NULL; + /* check for proper unloading */ if (p_dev->_irq || p_dev->_io || p_dev->_locked) printk(KERN_INFO "pcmcia: driver %s did not release config properly\n", diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index 45063b4e5b78..2539c0b23062 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -947,7 +947,5 @@ void pcmcia_disable_device(struct pcmcia_device *p_dev) { pcmcia_release_irq(p_dev, &p_dev->irq); if (&p_dev->win) pcmcia_release_window(p_dev->win); - - p_dev->dev_node = NULL; } EXPORT_SYMBOL(pcmcia_disable_device); -- cgit v1.2.3 From 80a55e923c76e022de298929e0c09bcca5c247d9 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 10 Apr 2006 23:24:57 -0700 Subject: [PATCH] pcmcia: remove unneeded forward declarations Also remove a couple of unneeded typecasts. Signed-off-by: Andrew Morton Signed-off-by: Dominik Brodowski --- drivers/pcmcia/ds.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 0f98cab35186..48d3b3d30c21 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -298,9 +298,6 @@ static inline int pcmcia_load_firmware(struct pcmcia_device *dev, char * filenam * * Registers a PCMCIA driver with the PCMCIA bus core. */ -static int pcmcia_device_probe(struct device *dev); -static int pcmcia_device_remove(struct device * dev); - int pcmcia_register_driver(struct pcmcia_driver *driver) { if (!driver) @@ -400,7 +397,7 @@ static int pcmcia_device_probe(struct device * dev) * call which will then check whether there are two * pseudo devices, and if not, add the second one. */ - did = (struct pcmcia_device_id *) p_dev->dev.driver_data; + did = p_dev->dev.driver_data; if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) && (p_dev->socket->device_count == 1) && (p_dev->device_no == 0)) pcmcia_add_pseudo_device(p_dev->socket); @@ -448,7 +445,6 @@ static void pcmcia_card_remove(struct pcmcia_socket *s, struct pcmcia_device *le return; } - static int pcmcia_device_remove(struct device * dev) { struct pcmcia_device *p_dev; @@ -463,7 +459,7 @@ static int pcmcia_device_remove(struct device * dev) * pseudo multi-function card, we need to unbind * all devices */ - did = (struct pcmcia_device_id *) p_dev->dev.driver_data; + did = p_dev->dev.driver_data; if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) && (p_dev->socket->device_count != 0) && (p_dev->device_no == 0)) -- cgit v1.2.3 From 2aff541c691b28cecb95ce710c367d16c0a84d8c Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Thu, 13 Apr 2006 19:06:49 +0200 Subject: [PATCH] pcmcia: fix oops in static mapping case As static maps do not have IO resources, this setting oopses. However, as we do not ever read this value, we can safely remove it. Signed-off-by: Dominik Brodowski --- drivers/pcmcia/pcmcia_resource.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index 2539c0b23062..cc3402c9b2c3 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -88,7 +88,6 @@ static int alloc_io_space(struct pcmcia_socket *s, u_int attr, ioaddr_t *base, } if ((s->features & SS_CAP_STATIC_MAP) && s->io_offset) { *base = s->io_offset | (*base & 0x0fff); - s->io[0].res->flags = (s->io[0].res->flags & ~IORESOURCE_BITS) | (attr & IORESOURCE_BITS); return 0; } /* Check for an already-allocated window that must conflict with -- cgit v1.2.3 From daaeb72bdf22873e6fa6497550c9e1d9a8825fea Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Thu, 6 Apr 2006 15:08:29 +0900 Subject: [PATCH] vrc4171: update config This patch updates "depends on" for PCMCIA_VRC4171. CONFIG_VRC4171 has been removed, so replace it with CPU_VR41XX && ISA. Signed-off-by: Yoichi Yuasa Signed-off-by: Dominik Brodowski --- drivers/pcmcia/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index cba6c9eef28e..61cb4b29f55c 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -250,7 +250,7 @@ config M32R_CFC_NUM config PCMCIA_VRC4171 tristate "NEC VRC4171 Card Controllers support" - depends on VRC4171 && PCMCIA + depends on CPU_VR41XX && ISA && PCMCIA config PCMCIA_VRC4173 tristate "NEC VRC4173 CARDU support" -- cgit v1.2.3 From 48b950ff241fca03a6969a5eb6a42a02722678d4 Mon Sep 17 00:00:00 2001 From: Daniel Ritz Date: Fri, 14 Apr 2006 17:42:13 +0200 Subject: [PATCH] pcmcia/pcmcia_resource.c: fix crash when using Cardbus cards Using the old ioctl interface together with cardbus card gives a NULL pointer dereference since cardbus devices don't have a struct pcmcia_device. also s->io[0].res can be NULL as well. Fix is to move the pcmcia code after the cardbus code and to check for a null pointer. Signed-off-by: Daniel Ritz Signed-off-by: Dominik Brodowski --- drivers/pcmcia/pcmcia_resource.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index cc3402c9b2c3..3131bb0a0095 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -208,7 +208,6 @@ int pccard_get_configuration_info(struct pcmcia_socket *s, if (!(s->state & SOCKET_PRESENT)) return CS_NO_CARD; - config->Function = p_dev->func; #ifdef CONFIG_CARDBUS if (s->state & SOCKET_CARDBUS) { @@ -222,14 +221,22 @@ int pccard_get_configuration_info(struct pcmcia_socket *s, config->AssignedIRQ = s->irq.AssignedIRQ; if (config->AssignedIRQ) config->Attributes |= CONF_ENABLE_IRQ; - config->BasePort1 = s->io[0].res->start; - config->NumPorts1 = s->io[0].res->end - config->BasePort1 + 1; + if (s->io[0].res) { + config->BasePort1 = s->io[0].res->start; + config->NumPorts1 = s->io[0].res->end - config->BasePort1 + 1; + } } return CS_SUCCESS; } #endif - c = (p_dev) ? p_dev->function_config : NULL; + if (p_dev) { + c = p_dev->function_config; + config->Function = p_dev->func; + } else { + c = NULL; + config->Function = 0; + } if ((c == NULL) || !(c->state & CONFIG_LOCKED)) { config->Attributes = 0; -- cgit v1.2.3 From 73a88814542d3f5b8973f3db9d7f380bd29957c4 Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Sat, 22 Apr 2006 02:35:30 -0700 Subject: [PATCH] isdn4linux: Siemens Gigaset base driver: fix disconnect handling Fix a possible Oops in the Siemens Gigaset base driver when the device is unplugged while an ISDN connection is still active, and makes sure that the isdn4linux link level (LL) is properly informed if a connection is broken by the USB cable being unplugged. - Avoid unsafe checks of URB status fields outside the URB completion handlers, keep track of in-use URBs myself instead. - If an isochronous transfer URB completes with status==0, also check the status of the frame descriptors. - Verify length of interrupt messages received from the device. - Align the length limit on transmitted AT commands with the device documentation. - In case of AT response receive overrun, keep newly arrived instead of old unread data. - Remove redundant check of device ID in the USB probe function. - Correct and improve some comments and formatting. Signed-off-by: Tilman Schmidt Acked-by: Hansjoerg Lipp Cc: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/isdn/gigaset/bas-gigaset.c | 597 ++++++++++++++++++++----------------- drivers/isdn/gigaset/common.c | 3 +- drivers/isdn/gigaset/ev-layer.c | 3 + drivers/isdn/gigaset/gigaset.h | 7 +- drivers/isdn/gigaset/i4l.c | 2 +- drivers/isdn/gigaset/isocdata.c | 10 +- 6 files changed, 342 insertions(+), 280 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index f86ed6af3aa2..eb41aba3ddef 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c @@ -5,8 +5,6 @@ * Tilman Schmidt , * Stefan Eilers. * - * Based on usb-gigaset.c. - * * ===================================================================== * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -46,19 +44,20 @@ MODULE_PARM_DESC(cidmode, "Call-ID mode"); #define GIGASET_DEVFSNAME "gig/bas/" #define GIGASET_DEVNAME "ttyGB" -#define IF_WRITEBUF 256 //FIXME +/* length limit according to Siemens 3070usb-protokoll.doc ch. 2.1 */ +#define IF_WRITEBUF 264 /* Values for the Gigaset 307x */ #define USB_GIGA_VENDOR_ID 0x0681 -#define USB_GIGA_PRODUCT_ID 0x0001 -#define USB_4175_PRODUCT_ID 0x0002 +#define USB_3070_PRODUCT_ID 0x0001 +#define USB_3075_PRODUCT_ID 0x0002 #define USB_SX303_PRODUCT_ID 0x0021 #define USB_SX353_PRODUCT_ID 0x0022 /* table of devices that work with this driver */ static struct usb_device_id gigaset_table [] = { - { USB_DEVICE(USB_GIGA_VENDOR_ID, USB_GIGA_PRODUCT_ID) }, - { USB_DEVICE(USB_GIGA_VENDOR_ID, USB_4175_PRODUCT_ID) }, + { USB_DEVICE(USB_GIGA_VENDOR_ID, USB_3070_PRODUCT_ID) }, + { USB_DEVICE(USB_GIGA_VENDOR_ID, USB_3075_PRODUCT_ID) }, { USB_DEVICE(USB_GIGA_VENDOR_ID, USB_SX303_PRODUCT_ID) }, { USB_DEVICE(USB_GIGA_VENDOR_ID, USB_SX353_PRODUCT_ID) }, { } /* Terminating entry */ @@ -77,6 +76,10 @@ static int gigaset_probe(struct usb_interface *interface, /* Function will be called if the device is unplugged */ static void gigaset_disconnect(struct usb_interface *interface); +static void read_ctrl_callback(struct urb *, struct pt_regs *); +static void stopurbs(struct bas_bc_state *); +static int atwrite_submit(struct cardstate *, unsigned char *, int); +static int start_cbsend(struct cardstate *); /*==============================================================================*/ @@ -111,12 +114,14 @@ struct bas_cardstate { }; /* status of direct USB connection to 307x base (bits in basstate) */ -#define BS_ATOPEN 0x001 -#define BS_B1OPEN 0x002 -#define BS_B2OPEN 0x004 -#define BS_ATREADY 0x008 -#define BS_INIT 0x010 -#define BS_ATTIMER 0x020 +#define BS_ATOPEN 0x001 /* AT channel open */ +#define BS_B1OPEN 0x002 /* B channel 1 open */ +#define BS_B2OPEN 0x004 /* B channel 2 open */ +#define BS_ATREADY 0x008 /* base ready for AT command */ +#define BS_INIT 0x010 /* base has signalled INIT_OK */ +#define BS_ATTIMER 0x020 /* waiting for HD_READY_SEND_ATDATA */ +#define BS_ATRDPEND 0x040 /* urb_cmd_in in use */ +#define BS_ATWRPEND 0x080 /* urb_cmd_out in use */ static struct gigaset_driver *driver = NULL; @@ -130,6 +135,47 @@ static struct usb_driver gigaset_usb_driver = { .id_table = gigaset_table, }; +/* get message text for usb_submit_urb return code + */ +static char *get_usb_rcmsg(int rc) +{ + static char unkmsg[28]; + + switch (rc) { + case 0: + return "success"; + case -ENOMEM: + return "out of memory"; + case -ENODEV: + return "device not present"; + case -ENOENT: + return "endpoint not present"; + case -ENXIO: + return "URB type not supported"; + case -EINVAL: + return "invalid argument"; + case -EAGAIN: + return "start frame too early or too much scheduled"; + case -EFBIG: + return "too many isochronous frames requested"; + case -EPIPE: + return "endpoint stalled"; + case -EMSGSIZE: + return "invalid packet size"; + case -ENOSPC: + return "would overcommit USB bandwidth"; + case -ESHUTDOWN: + return "device shut down"; + case -EPERM: + return "reject flag set"; + case -EHOSTUNREACH: + return "device suspended"; + default: + snprintf(unkmsg, sizeof(unkmsg), "unknown error %d", rc); + return unkmsg; + } +} + /* get message text for USB status code */ static char *get_usb_statmsg(int status) @@ -140,43 +186,37 @@ static char *get_usb_statmsg(int status) case 0: return "success"; case -ENOENT: - return "canceled"; - case -ECONNRESET: - return "canceled (async)"; + return "unlinked (sync)"; case -EINPROGRESS: return "pending"; case -EPROTO: - return "bit stuffing or unknown USB error"; + return "bit stuffing error, timeout, or unknown USB error"; case -EILSEQ: - return "Illegal byte sequence (CRC mismatch)"; - case -EPIPE: - return "babble detect or endpoint stalled"; - case -ENOSR: - return "buffer error"; + return "CRC mismatch, timeout, or unknown USB error"; case -ETIMEDOUT: return "timed out"; - case -ENODEV: - return "device not present"; + case -EPIPE: + return "endpoint stalled"; + case -ECOMM: + return "IN buffer overrun"; + case -ENOSR: + return "OUT buffer underrun"; + case -EOVERFLOW: + return "too much data"; case -EREMOTEIO: return "short packet detected"; + case -ENODEV: + return "device removed"; case -EXDEV: return "partial isochronous transfer"; case -EINVAL: return "invalid argument"; - case -ENXIO: - return "URB already queued"; - case -EAGAIN: - return "isochronous start frame too early or too much scheduled"; - case -EFBIG: - return "too many isochronous frames requested"; - case -EMSGSIZE: - return "endpoint message size zero"; + case -ECONNRESET: + return "unlinked (async)"; case -ESHUTDOWN: - return "endpoint shutdown"; - case -EBUSY: - return "another request pending"; + return "device shut down"; default: - snprintf(unkmsg, sizeof(unkmsg), "unknown error %d", status); + snprintf(unkmsg, sizeof(unkmsg), "unknown status %d", status); return unkmsg; } } @@ -277,18 +317,17 @@ static inline void error_hangup(struct bc_state *bcs) gig_dbg(DEBUG_ANY, "%s: scheduling HUP for channel %d", __func__, bcs->channel); - if (!gigaset_add_event(cs, &bcs->at_state, EV_HUP, NULL, 0, NULL)) { - //FIXME what should we do? - return; - } + if (!gigaset_add_event(cs, &bcs->at_state, EV_HUP, NULL, 0, NULL)) + dev_err(cs->dev, "event queue full\n"); gigaset_schedule_event(cs); } /* error_reset * reset Gigaset device because of an unrecoverable error - * This function may be called from any context and takes care of scheduling - * the necessary actions for execution outside of interrupt context. + * This function may be called from any context, and should take care of + * scheduling the necessary actions for execution outside of interrupt context. + * Right now, it just generates a kernel message calling for help. * argument: * controller state structure */ @@ -364,36 +403,38 @@ static void cmd_in_timeout(unsigned long data) { struct cardstate *cs = (struct cardstate *) data; struct bas_cardstate *ucs = cs->hw.bas; - unsigned long flags; - spin_lock_irqsave(&cs->lock, flags); - if (unlikely(!cs->connected)) { - gig_dbg(DEBUG_USBREQ, "%s: disconnected", __func__); - spin_unlock_irqrestore(&cs->lock, flags); - return; - } if (!ucs->rcvbuf_size) { gig_dbg(DEBUG_USBREQ, "%s: no receive in progress", __func__); - spin_unlock_irqrestore(&cs->lock, flags); return; } - spin_unlock_irqrestore(&cs->lock, flags); dev_err(cs->dev, "timeout reading AT response\n"); error_reset(cs); //FIXME retry? } +/* set/clear bits in base connection state, return previous state + */ +inline static int update_basstate(struct bas_cardstate *ucs, + int set, int clear) +{ + unsigned long flags; + int state; -static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs); + spin_lock_irqsave(&ucs->lock, flags); + state = atomic_read(&ucs->basstate); + atomic_set(&ucs->basstate, (state & ~clear) | set); + spin_unlock_irqrestore(&ucs->lock, flags); + return state; +} /* atread_submit - * submit an HD_READ_ATMESSAGE command URB + * submit an HD_READ_ATMESSAGE command URB and optionally start a timeout * parameters: * cs controller state structure * timeout timeout in 1/10 sec., 0: none * return value: * 0 on success - * -EINVAL if a NULL pointer is encountered somewhere * -EBUSY if another request is pending * any URB submission error code */ @@ -405,7 +446,7 @@ static int atread_submit(struct cardstate *cs, int timeout) gig_dbg(DEBUG_USBREQ, "-------> HD_READ_ATMESSAGE (%d)", ucs->rcvbuf_size); - if (ucs->urb_cmd_in->status == -EINPROGRESS) { + if (update_basstate(ucs, BS_ATRDPEND, 0) & BS_ATRDPEND) { dev_err(cs->dev, "could not submit HD_READ_ATMESSAGE: URB busy\n"); return -EBUSY; @@ -423,6 +464,7 @@ static int atread_submit(struct cardstate *cs, int timeout) read_ctrl_callback, cs->inbuf); if ((ret = usb_submit_urb(ucs->urb_cmd_in, SLAB_ATOMIC)) != 0) { + update_basstate(ucs, 0, BS_ATRDPEND); dev_err(cs->dev, "could not submit HD_READ_ATMESSAGE: %s\n", get_usb_statmsg(ret)); return ret; @@ -438,26 +480,6 @@ static int atread_submit(struct cardstate *cs, int timeout) return 0; } -static void stopurbs(struct bas_bc_state *); -static int start_cbsend(struct cardstate *); - -/* set/clear bits in base connection state - */ -inline static void update_basstate(struct bas_cardstate *ucs, - int set, int clear) -{ - unsigned long flags; - int state; - - spin_lock_irqsave(&ucs->lock, flags); - state = atomic_read(&ucs->basstate); - state &= ~clear; - state |= set; - atomic_set(&ucs->basstate, state); - spin_unlock_irqrestore(&ucs->lock, flags); -} - - /* read_int_callback * USB completion handler for interrupt pipe input * called by the USB subsystem in interrupt context @@ -471,20 +493,25 @@ static void read_int_callback(struct urb *urb, struct pt_regs *regs) struct bas_cardstate *ucs = cs->hw.bas; struct bc_state *bcs; unsigned long flags; - int status; + int rc; unsigned l; int channel; switch (urb->status) { case 0: /* success */ break; - case -ENOENT: /* canceled */ - case -ECONNRESET: /* canceled (async) */ + case -ENOENT: /* cancelled */ + case -ECONNRESET: /* cancelled (async) */ case -EINPROGRESS: /* pending */ /* ignore silently */ gig_dbg(DEBUG_USBREQ, "%s: %s", __func__, get_usb_statmsg(urb->status)); return; + case -ENODEV: /* device removed */ + case -ESHUTDOWN: /* device shut down */ + //FIXME use this as disconnect indicator? + gig_dbg(DEBUG_USBREQ, "%s: device disconnected", __func__); + return; default: /* severe trouble */ dev_warn(cs->dev, "interrupt read: %s\n", get_usb_statmsg(urb->status)); @@ -492,6 +519,13 @@ static void read_int_callback(struct urb *urb, struct pt_regs *regs) goto resubmit; } + /* drop incomplete packets even if the missing bytes wouldn't matter */ + if (unlikely(urb->actual_length < 3)) { + dev_warn(cs->dev, "incomplete interrupt packet (%d bytes)\n", + urb->actual_length); + goto resubmit; + } + l = (unsigned) ucs->int_in_buf[1] + (((unsigned) ucs->int_in_buf[2]) << 8); @@ -558,25 +592,28 @@ static void read_int_callback(struct urb *urb, struct pt_regs *regs) } spin_lock_irqsave(&cs->lock, flags); if (ucs->rcvbuf_size) { - spin_unlock_irqrestore(&cs->lock, flags); + /* throw away previous buffer - we have no queue */ dev_err(cs->dev, - "receive AT data overrun, %d bytes lost\n", l); - error_reset(cs); //FIXME reschedule - break; + "receive AT data overrun, %d bytes lost\n", + ucs->rcvbuf_size); + kfree(ucs->rcvbuf); + ucs->rcvbuf_size = 0; } if ((ucs->rcvbuf = kmalloc(l, GFP_ATOMIC)) == NULL) { spin_unlock_irqrestore(&cs->lock, flags); - dev_err(cs->dev, "out of memory, %d bytes lost\n", l); - error_reset(cs); //FIXME reschedule + dev_err(cs->dev, "out of memory receiving AT data\n"); + error_reset(cs); break; } ucs->rcvbuf_size = l; ucs->retry_cmd_in = 0; - if ((status = atread_submit(cs, BAS_TIMEOUT)) < 0) { + if ((rc = atread_submit(cs, BAS_TIMEOUT)) < 0) { kfree(ucs->rcvbuf); ucs->rcvbuf = NULL; ucs->rcvbuf_size = 0; - error_reset(cs); //FIXME reschedule + if (rc != -ENODEV) + //FIXME corrective action? + error_reset(cs); } spin_unlock_irqrestore(&cs->lock, flags); break; @@ -598,12 +635,10 @@ static void read_int_callback(struct urb *urb, struct pt_regs *regs) check_pending(ucs); resubmit: - spin_lock_irqsave(&cs->lock, flags); - status = cs->connected ? usb_submit_urb(urb, SLAB_ATOMIC) : -ENODEV; - spin_unlock_irqrestore(&cs->lock, flags); - if (unlikely(status)) { + rc = usb_submit_urb(urb, SLAB_ATOMIC); + if (unlikely(rc != 0 && rc != -ENODEV)) { dev_err(cs->dev, "could not resubmit interrupt URB: %s\n", - get_usb_statmsg(status)); + get_usb_rcmsg(rc)); error_reset(cs); } } @@ -622,18 +657,12 @@ static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs) struct bas_cardstate *ucs = cs->hw.bas; int have_data = 0; unsigned numbytes; - unsigned long flags; + int rc; - spin_lock_irqsave(&cs->lock, flags); - if (unlikely(!cs->connected)) { - warn("%s: disconnected", __func__); - spin_unlock_irqrestore(&cs->lock, flags); - return; - } + update_basstate(ucs, 0, BS_ATRDPEND); if (!ucs->rcvbuf_size) { dev_warn(cs->dev, "%s: no receive in progress\n", __func__); - spin_unlock_irqrestore(&cs->lock, flags); return; } @@ -666,9 +695,11 @@ static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs) } break; - case -ENOENT: /* canceled */ - case -ECONNRESET: /* canceled (async) */ + case -ENOENT: /* cancelled */ + case -ECONNRESET: /* cancelled (async) */ case -EINPROGRESS: /* pending */ + case -ENODEV: /* device removed */ + case -ESHUTDOWN: /* device shut down */ /* no action necessary */ gig_dbg(DEBUG_USBREQ, "%s: %s", __func__, get_usb_statmsg(urb->status)); @@ -681,11 +712,11 @@ static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs) if (ucs->retry_cmd_in++ < BAS_RETRY) { dev_notice(cs->dev, "control read: retry %d\n", ucs->retry_cmd_in); - if (atread_submit(cs, BAS_TIMEOUT) >= 0) { - /* resubmitted - bypass regular exit block */ - spin_unlock_irqrestore(&cs->lock, flags); + rc = atread_submit(cs, BAS_TIMEOUT); + if (rc >= 0 || rc == -ENODEV) + /* resubmitted or disconnected */ + /* - bypass regular exit block */ return; - } } else { dev_err(cs->dev, "control read: giving up after %d tries\n", @@ -697,7 +728,6 @@ static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs) kfree(ucs->rcvbuf); ucs->rcvbuf = NULL; ucs->rcvbuf_size = 0; - spin_unlock_irqrestore(&cs->lock, flags); if (have_data) { gig_dbg(DEBUG_INTR, "%s-->BH", __func__); gigaset_schedule_event(cs); @@ -719,8 +749,11 @@ static void read_iso_callback(struct urb *urb, struct pt_regs *regs) int i, rc; /* status codes not worth bothering the tasklet with */ - if (unlikely(urb->status == -ENOENT || urb->status == -ECONNRESET || - urb->status == -EINPROGRESS)) { + if (unlikely(urb->status == -ENOENT || + urb->status == -ECONNRESET || + urb->status == -EINPROGRESS || + urb->status == -ENODEV || + urb->status == -ESHUTDOWN)) { gig_dbg(DEBUG_ISO, "%s: %s", __func__, get_usb_statmsg(urb->status)); return; @@ -740,9 +773,9 @@ static void read_iso_callback(struct urb *urb, struct pt_regs *regs) for (i = 0; i < BAS_NUMFRAMES; i++) { ubc->isoinlost += urb->iso_frame_desc[i].actual_length; if (unlikely(urb->iso_frame_desc[i].status != 0 && - urb->iso_frame_desc[i].status != -EINPROGRESS)) { + urb->iso_frame_desc[i].status != + -EINPROGRESS)) ubc->loststatus = urb->iso_frame_desc[i].status; - } urb->iso_frame_desc[i].status = 0; urb->iso_frame_desc[i].actual_length = 0; } @@ -754,10 +787,10 @@ static void read_iso_callback(struct urb *urb, struct pt_regs *regs) gig_dbg(DEBUG_ISO, "%s: isoc read overrun/resubmit", __func__); rc = usb_submit_urb(urb, SLAB_ATOMIC); - if (unlikely(rc != 0)) { + if (unlikely(rc != 0 && rc != -ENODEV)) { dev_err(bcs->cs->dev, "could not resubmit isochronous read " - "URB: %s\n", get_usb_statmsg(rc)); + "URB: %s\n", get_usb_rcmsg(rc)); dump_urb(DEBUG_ISO, "isoc read", urb); error_hangup(bcs); } @@ -780,8 +813,11 @@ static void write_iso_callback(struct urb *urb, struct pt_regs *regs) unsigned long flags; /* status codes not worth bothering the tasklet with */ - if (unlikely(urb->status == -ENOENT || urb->status == -ECONNRESET || - urb->status == -EINPROGRESS)) { + if (unlikely(urb->status == -ENOENT || + urb->status == -ECONNRESET || + urb->status == -EINPROGRESS || + urb->status == -ENODEV || + urb->status == -ESHUTDOWN)) { gig_dbg(DEBUG_ISO, "%s: %s", __func__, get_usb_statmsg(urb->status)); return; @@ -822,7 +858,6 @@ static int starturbs(struct bc_state *bcs) for (k = 0; k < BAS_INURBS; k++) { urb = ubc->isoinurbs[k]; if (!urb) { - dev_err(bcs->cs->dev, "isoinurbs[%d]==NULL\n", k); rc = -EFAULT; goto error; } @@ -844,12 +879,8 @@ static int starturbs(struct bc_state *bcs) } dump_urb(DEBUG_ISO, "Initial isoc read", urb); - if ((rc = usb_submit_urb(urb, SLAB_ATOMIC)) != 0) { - dev_err(bcs->cs->dev, - "could not submit isochronous read URB %d: %s\n", - k, get_usb_statmsg(rc)); + if ((rc = usb_submit_urb(urb, SLAB_ATOMIC)) != 0) goto error; - } } /* initialize L2 transmission */ @@ -859,7 +890,6 @@ static int starturbs(struct bc_state *bcs) for (k = 0; k < BAS_OUTURBS; ++k) { urb = ubc->isoouturbs[k].urb; if (!urb) { - dev_err(bcs->cs->dev, "isoouturbs[%d].urb==NULL\n", k); rc = -EFAULT; goto error; } @@ -885,12 +915,8 @@ static int starturbs(struct bc_state *bcs) for (k = 0; k < 2; ++k) { dump_urb(DEBUG_ISO, "Initial isoc write", urb); rc = usb_submit_urb(ubc->isoouturbs[k].urb, SLAB_ATOMIC); - if (rc != 0) { - dev_err(bcs->cs->dev, - "could not submit isochronous write URB %d: %s\n", - k, get_usb_statmsg(rc)); + if (rc != 0) goto error; - } } dump_urb(DEBUG_ISO, "Initial isoc write (free)", urb); ubc->isooutfree = &ubc->isoouturbs[2]; @@ -916,15 +942,15 @@ static void stopurbs(struct bas_bc_state *ubc) for (k = 0; k < BAS_INURBS; ++k) { rc = usb_unlink_urb(ubc->isoinurbs[k]); gig_dbg(DEBUG_ISO, - "%s: isoc input URB %d unlinked, result = %d", - __func__, k, rc); + "%s: isoc input URB %d unlinked, result = %s", + __func__, k, get_usb_rcmsg(rc)); } for (k = 0; k < BAS_OUTURBS; ++k) { rc = usb_unlink_urb(ubc->isoouturbs[k].urb); gig_dbg(DEBUG_ISO, - "%s: isoc output URB %d unlinked, result = %d", - __func__, k, rc); + "%s: isoc output URB %d unlinked, result = %s", + __func__, k, get_usb_rcmsg(rc)); } } @@ -934,7 +960,7 @@ static void stopurbs(struct bas_bc_state *ubc) /* submit_iso_write_urb * fill and submit the next isochronous write URB * parameters: - * bcs B channel state structure + * ucx context structure containing URB * return value: * number of frames submitted in URB * 0 if URB not submitted because no data available (isooutbuf busy) @@ -946,7 +972,6 @@ static int submit_iso_write_urb(struct isow_urbctx_t *ucx) struct bas_bc_state *ubc = ucx->bcs->hw.bas; struct usb_iso_packet_descriptor *ifd; int corrbytes, nframe, rc; - unsigned long flags; /* urb->dev is clobbered by USB subsystem */ urb->dev = ucx->bcs->cs->hw.bas->udev; @@ -992,20 +1017,22 @@ static int submit_iso_write_urb(struct isow_urbctx_t *ucx) ifd->status = 0; ifd->actual_length = 0; } - if ((urb->number_of_packets = nframe) > 0) { - spin_lock_irqsave(&ucx->bcs->cs->lock, flags); - rc = ucx->bcs->cs->connected ? usb_submit_urb(urb, SLAB_ATOMIC) : -ENODEV; - spin_unlock_irqrestore(&ucx->bcs->cs->lock, flags); + if (unlikely(nframe == 0)) + return 0; /* no data to send */ + urb->number_of_packets = nframe; - if (rc) { + rc = usb_submit_urb(urb, SLAB_ATOMIC); + if (unlikely(rc)) { + if (rc == -ENODEV) + /* device removed - give up silently */ + gig_dbg(DEBUG_ISO, "%s: disconnected", __func__); + else dev_err(ucx->bcs->cs->dev, "could not submit isochronous write URB: %s\n", - get_usb_statmsg(rc)); - dump_urb(DEBUG_ISO, "isoc write", urb); - return rc; - } - ++ubc->numsub; + get_usb_rcmsg(rc)); + return rc; } + ++ubc->numsub; return nframe; } @@ -1028,6 +1055,7 @@ static void write_iso_tasklet(unsigned long data) int i; struct sk_buff *skb; int len; + int rc; /* loop while completed URBs arrive in time */ for (;;) { @@ -1057,7 +1085,8 @@ static void write_iso_tasklet(unsigned long data) ubc->isooutfree = NULL; spin_unlock_irqrestore(&ubc->isooutlock, flags); if (next) { - if (submit_iso_write_urb(next) <= 0) { + rc = submit_iso_write_urb(next); + if (unlikely(rc <= 0 && rc != -ENODEV)) { /* could not submit URB, put it back */ spin_lock_irqsave(&ubc->isooutlock, flags); if (ubc->isooutfree == NULL) { @@ -1077,17 +1106,18 @@ static void write_iso_tasklet(unsigned long data) /* process completed URB */ urb = done->urb; switch (urb->status) { + case -EXDEV: /* partial completion */ + gig_dbg(DEBUG_ISO, "%s: URB partially completed", + __func__); + /* fall through - what's the difference anyway? */ case 0: /* normal completion */ - break; - case -EXDEV: /* inspect individual frames */ - /* assumptions (for lack of documentation): - * - actual_length bytes of the frame in error are + /* inspect individual frames + * assumptions (for lack of documentation): + * - actual_length bytes of first frame in error are * successfully sent * - all following frames are not sent at all */ - gig_dbg(DEBUG_ISO, "%s: URB partially completed", - __func__); - offset = done->limit; /* just in case */ + offset = done->limit; /* default (no error) */ for (i = 0; i < BAS_NUMFRAMES; i++) { ifd = &urb->iso_frame_desc[i]; if (ifd->status || @@ -1122,7 +1152,7 @@ static void write_iso_tasklet(unsigned long data) } #endif break; - case -EPIPE: //FIXME is this the code for "underrun"? + case -EPIPE: /* stall - probably underrun */ dev_err(cs->dev, "isochronous write stalled\n"); error_hangup(bcs); break; @@ -1142,7 +1172,8 @@ static void write_iso_tasklet(unsigned long data) spin_unlock_irqrestore(&ubc->isooutlock, flags); if (next) { /* only one URB still active - resubmit one */ - if (submit_iso_write_urb(next) <= 0) { + rc = submit_iso_write_urb(next); + if (unlikely(rc <= 0 && rc != -ENODEV)) { /* couldn't submit */ error_hangup(bcs); } @@ -1222,10 +1253,9 @@ static void read_iso_tasklet(unsigned long data) break; case -ENOENT: case -ECONNRESET: - gig_dbg(DEBUG_ISO, "%s: URB canceled", __func__); - continue; /* -> skip */ - case -EINPROGRESS: /* huh? */ - gig_dbg(DEBUG_ISO, "%s: URB still pending", __func__); + case -EINPROGRESS: + gig_dbg(DEBUG_ISO, "%s: %s", + __func__, get_usb_statmsg(urb->status)); continue; /* -> skip */ case -EPIPE: dev_err(cs->dev, "isochronous read stalled\n"); @@ -1290,13 +1320,11 @@ static void read_iso_tasklet(unsigned long data) urb->dev = bcs->cs->hw.bas->udev; urb->transfer_flags = URB_ISO_ASAP; urb->number_of_packets = BAS_NUMFRAMES; - spin_lock_irqsave(&cs->lock, flags); - rc = cs->connected ? usb_submit_urb(urb, SLAB_ATOMIC) : -ENODEV; - spin_unlock_irqrestore(&cs->lock, flags); - if (rc) { + rc = usb_submit_urb(urb, SLAB_ATOMIC); + if (unlikely(rc != 0 && rc != -ENODEV)) { dev_err(cs->dev, "could not resubmit isochronous read URB: %s\n", - get_usb_statmsg(rc)); + get_usb_rcmsg(rc)); dump_urb(DEBUG_ISO, "resubmit iso read", urb); error_hangup(bcs); } @@ -1397,7 +1425,6 @@ static void write_ctrl_callback(struct urb *urb, struct pt_regs *regs) * timeout timeout in seconds (0: no timeout) * return value: * 0 on success - * -EINVAL if a NULL pointer is encountered somewhere * -EBUSY if another request is pending * any URB submission error code */ @@ -1418,12 +1445,6 @@ static int req_submit(struct bc_state *bcs, int req, int val, int timeout) req, ucs->pending); return -EBUSY; } - if (ucs->urb_ctrl->status == -EINPROGRESS) { - spin_unlock_irqrestore(&ucs->lock, flags); - dev_err(bcs->cs->dev, - "could not submit request 0x%02x: URB busy\n", req); - return -EBUSY; - } ucs->dr_ctrl.bRequestType = OUT_VENDOR_REQ; ucs->dr_ctrl.bRequest = req; @@ -1465,22 +1486,36 @@ static int req_submit(struct bc_state *bcs, int req, int val, int timeout) static int gigaset_init_bchannel(struct bc_state *bcs) { int req, ret; + unsigned long flags; + + spin_lock_irqsave(&bcs->cs->lock, flags); + if (unlikely(!bcs->cs->connected)) { + gig_dbg(DEBUG_USBREQ, "%s: not connected", __func__); + spin_unlock_irqrestore(&bcs->cs->lock, flags); + return -ENODEV; + } if ((ret = starturbs(bcs)) < 0) { dev_err(bcs->cs->dev, - "could not start isochronous I/O for channel %d\n", - bcs->channel + 1); - error_hangup(bcs); + "could not start isochronous I/O for channel B%d: %s\n", + bcs->channel + 1, + ret == -EFAULT ? "null URB" : get_usb_rcmsg(ret)); + if (ret != -ENODEV) + error_hangup(bcs); + spin_unlock_irqrestore(&bcs->cs->lock, flags); return ret; } req = bcs->channel ? HD_OPEN_B2CHANNEL : HD_OPEN_B1CHANNEL; if ((ret = req_submit(bcs, req, 0, BAS_TIMEOUT)) < 0) { - dev_err(bcs->cs->dev, "could not open channel %d: %s\n", - bcs->channel + 1, get_usb_statmsg(ret)); + dev_err(bcs->cs->dev, "could not open channel B%d\n", + bcs->channel + 1); stopurbs(bcs->hw.bas); - error_hangup(bcs); + if (ret != -ENODEV) + error_hangup(bcs); } + + spin_unlock_irqrestore(&bcs->cs->lock, flags); return ret; } @@ -1497,19 +1532,30 @@ static int gigaset_init_bchannel(struct bc_state *bcs) static int gigaset_close_bchannel(struct bc_state *bcs) { int req, ret; + unsigned long flags; + + spin_lock_irqsave(&bcs->cs->lock, flags); + if (unlikely(!bcs->cs->connected)) { + spin_unlock_irqrestore(&bcs->cs->lock, flags); + gig_dbg(DEBUG_USBREQ, "%s: not connected", __func__); + return -ENODEV; + } if (!(atomic_read(&bcs->cs->hw.bas->basstate) & (bcs->channel ? BS_B2OPEN : BS_B1OPEN))) { /* channel not running: just signal common.c */ + spin_unlock_irqrestore(&bcs->cs->lock, flags); gigaset_bchannel_down(bcs); return 0; } + /* channel running: tell device to close it */ req = bcs->channel ? HD_CLOSE_B2CHANNEL : HD_CLOSE_B1CHANNEL; if ((ret = req_submit(bcs, req, 0, BAS_TIMEOUT)) < 0) - dev_err(bcs->cs->dev, - "could not submit HD_CLOSE_BxCHANNEL request: %s\n", - get_usb_statmsg(ret)); + dev_err(bcs->cs->dev, "closing channel B%d failed\n", + bcs->channel + 1); + + spin_unlock_irqrestore(&bcs->cs->lock, flags); return ret; } @@ -1545,8 +1591,6 @@ static void complete_cb(struct cardstate *cs) kfree(cb); } -static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len); - /* write_command_callback * USB completion handler for AT command transmission * called by the USB subsystem in interrupt context @@ -1560,13 +1604,17 @@ static void write_command_callback(struct urb *urb, struct pt_regs *regs) struct bas_cardstate *ucs = cs->hw.bas; unsigned long flags; + update_basstate(ucs, 0, BS_ATWRPEND); + /* check status */ switch (urb->status) { case 0: /* normal completion */ break; - case -ENOENT: /* canceled */ - case -ECONNRESET: /* canceled (async) */ + case -ENOENT: /* cancelled */ + case -ECONNRESET: /* cancelled (async) */ case -EINPROGRESS: /* pending */ + case -ENODEV: /* device removed */ + case -ESHUTDOWN: /* device shut down */ /* ignore silently */ gig_dbg(DEBUG_USBREQ, "%s: %s", __func__, get_usb_statmsg(urb->status)); @@ -1627,19 +1675,17 @@ static void atrdy_timeout(unsigned long data) * len length of command to send * return value: * 0 on success - * -EFAULT if a NULL pointer is encountered somewhere * -EBUSY if another request is pending * any URB submission error code */ static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len) { struct bas_cardstate *ucs = cs->hw.bas; - unsigned long flags; - int ret; + int rc; gig_dbg(DEBUG_USBREQ, "-------> HD_WRITE_ATMESSAGE (%d)", len); - if (ucs->urb_cmd_out->status == -EINPROGRESS) { + if (update_basstate(ucs, BS_ATWRPEND, 0) & BS_ATWRPEND) { dev_err(cs->dev, "could not submit HD_WRITE_ATMESSAGE: URB busy\n"); return -EBUSY; @@ -1654,29 +1700,22 @@ static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len) usb_sndctrlpipe(ucs->udev, 0), (unsigned char*) &ucs->dr_cmd_out, buf, len, write_command_callback, cs); - - spin_lock_irqsave(&cs->lock, flags); - ret = cs->connected ? usb_submit_urb(ucs->urb_cmd_out, SLAB_ATOMIC) : -ENODEV; - spin_unlock_irqrestore(&cs->lock, flags); - - if (ret) { + rc = usb_submit_urb(ucs->urb_cmd_out, SLAB_ATOMIC); + if (unlikely(rc)) { + update_basstate(ucs, 0, BS_ATWRPEND); dev_err(cs->dev, "could not submit HD_WRITE_ATMESSAGE: %s\n", - get_usb_statmsg(ret)); - return ret; + get_usb_rcmsg(rc)); + return rc; } - /* submitted successfully */ - update_basstate(ucs, 0, BS_ATREADY); - - /* start timeout if necessary */ - if (!(atomic_read(&ucs->basstate) & BS_ATTIMER)) { + /* submitted successfully, start timeout if necessary */ + if (!(update_basstate(ucs, BS_ATTIMER, BS_ATREADY) & BS_ATTIMER)) { gig_dbg(DEBUG_OUTPUT, "setting ATREADY timeout of %d/10 secs", ATRDY_TIMEOUT); ucs->timer_atrdy.expires = jiffies + ATRDY_TIMEOUT * HZ / 10; ucs->timer_atrdy.data = (unsigned long) cs; ucs->timer_atrdy.function = atrdy_timeout; add_timer(&ucs->timer_atrdy); - update_basstate(ucs, BS_ATTIMER, 0); } return 0; } @@ -1702,7 +1741,6 @@ static int start_cbsend(struct cardstate *cs) gig_dbg(DEBUG_TRANSCMD|DEBUG_LOCKCMD, "AT channel not open"); rc = req_submit(cs->bcs, HD_OPEN_ATCHANNEL, 0, BAS_TIMEOUT); if (rc < 0) { - dev_err(cs->dev, "could not open AT channel\n"); /* flush command queue */ spin_lock_irqsave(&cs->cmdlock, flags); while (cs->cmdbuf != NULL) @@ -1786,8 +1824,14 @@ static int gigaset_write_cmd(struct cardstate *cs, cs->lastcmdbuf = cb; spin_unlock_irqrestore(&cs->cmdlock, flags); + spin_lock_irqsave(&cs->lock, flags); + if (unlikely(!cs->connected)) { + spin_unlock_irqrestore(&cs->lock, flags); + gig_dbg(DEBUG_USBREQ, "%s: not connected", __func__); + return -ENODEV; + } status = start_cbsend(cs); - + spin_unlock_irqrestore(&cs->lock, flags); return status < 0 ? status : len; } @@ -1849,12 +1893,32 @@ static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6]) */ static int gigaset_freebcshw(struct bc_state *bcs) { - if (!bcs->hw.bas) + struct bas_bc_state *ubc = bcs->hw.bas; + int i; + + if (!ubc) return 0; - if (bcs->hw.bas->isooutbuf) - kfree(bcs->hw.bas->isooutbuf); - kfree(bcs->hw.bas); + /* kill URBs and tasklets before freeing - better safe than sorry */ + atomic_set(&ubc->running, 0); + for (i = 0; i < BAS_OUTURBS; ++i) + if (ubc->isoouturbs[i].urb) { + gig_dbg(DEBUG_INIT, "%s: killing iso out URB %d", + __func__, i); + usb_kill_urb(ubc->isoouturbs[i].urb); + usb_free_urb(ubc->isoouturbs[i].urb); + } + for (i = 0; i < BAS_INURBS; ++i) + if (ubc->isoinurbs[i]) { + gig_dbg(DEBUG_INIT, "%s: killing iso in URB %d", + __func__, i); + usb_kill_urb(ubc->isoinurbs[i]); + usb_free_urb(ubc->isoinurbs[i]); + } + tasklet_kill(&ubc->sent_tasklet); + tasklet_kill(&ubc->rcvd_tasklet); + kfree(ubc->isooutbuf); + kfree(ubc); bcs->hw.bas = NULL; return 1; } @@ -1931,13 +1995,9 @@ static void gigaset_reinitbcshw(struct bc_state *bcs) static void gigaset_freecshw(struct cardstate *cs) { - struct bas_cardstate *ucs = cs->hw.bas; - - del_timer(&ucs->timer_ctrl); - del_timer(&ucs->timer_atrdy); - del_timer(&ucs->timer_cmd_in); - + /* timers, URBs and rcvbuf are disposed of in disconnect */ kfree(cs->hw.bas); + cs->hw.bas = NULL; } static int gigaset_initcshw(struct cardstate *cs) @@ -2041,23 +2101,13 @@ static int gigaset_probe(struct usb_interface *interface, struct bas_bc_state *ubc; struct usb_endpoint_descriptor *endpoint; int i, j; - int ret; + int rc; gig_dbg(DEBUG_ANY, "%s: Check if device matches .. (Vendor: 0x%x, Product: 0x%x)", __func__, le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct)); - /* See if the device offered us matches what we can accept */ - if ((le16_to_cpu(udev->descriptor.idVendor) != USB_GIGA_VENDOR_ID) || - (le16_to_cpu(udev->descriptor.idProduct) != USB_GIGA_PRODUCT_ID && - le16_to_cpu(udev->descriptor.idProduct) != USB_4175_PRODUCT_ID && - le16_to_cpu(udev->descriptor.idProduct) != USB_SX303_PRODUCT_ID && - le16_to_cpu(udev->descriptor.idProduct) != USB_SX353_PRODUCT_ID)) { - gig_dbg(DEBUG_ANY, "%s: unmatched ID - exiting", __func__); - return -ENODEV; - } - /* set required alternate setting */ hostif = interface->cur_altsetting; if (hostif->desc.bAlternateSetting != 3) { @@ -2105,45 +2155,22 @@ static int gigaset_probe(struct usb_interface *interface, * - three for the different uses of the default control pipe * - three for each isochronous pipe */ - ucs->urb_int_in = usb_alloc_urb(0, SLAB_KERNEL); - if (!ucs->urb_int_in) { - dev_err(cs->dev, "no free urbs available\n"); - goto error; - } - ucs->urb_cmd_in = usb_alloc_urb(0, SLAB_KERNEL); - if (!ucs->urb_cmd_in) { - dev_err(cs->dev, "no free urbs available\n"); - goto error; - } - ucs->urb_cmd_out = usb_alloc_urb(0, SLAB_KERNEL); - if (!ucs->urb_cmd_out) { - dev_err(cs->dev, "no free urbs available\n"); - goto error; - } - ucs->urb_ctrl = usb_alloc_urb(0, SLAB_KERNEL); - if (!ucs->urb_ctrl) { - dev_err(cs->dev, "no free urbs available\n"); - goto error; - } + if (!(ucs->urb_int_in = usb_alloc_urb(0, SLAB_KERNEL)) || + !(ucs->urb_cmd_in = usb_alloc_urb(0, SLAB_KERNEL)) || + !(ucs->urb_cmd_out = usb_alloc_urb(0, SLAB_KERNEL)) || + !(ucs->urb_ctrl = usb_alloc_urb(0, SLAB_KERNEL))) + goto allocerr; for (j = 0; j < 2; ++j) { ubc = cs->bcs[j].hw.bas; - for (i = 0; i < BAS_OUTURBS; ++i) { - ubc->isoouturbs[i].urb = - usb_alloc_urb(BAS_NUMFRAMES, SLAB_KERNEL); - if (!ubc->isoouturbs[i].urb) { - dev_err(cs->dev, "no free urbs available\n"); - goto error; - } - } - for (i = 0; i < BAS_INURBS; ++i) { - ubc->isoinurbs[i] = - usb_alloc_urb(BAS_NUMFRAMES, SLAB_KERNEL); - if (!ubc->isoinurbs[i]) { - dev_err(cs->dev, "no free urbs available\n"); - goto error; - } - } + for (i = 0; i < BAS_OUTURBS; ++i) + if (!(ubc->isoouturbs[i].urb = + usb_alloc_urb(BAS_NUMFRAMES, SLAB_KERNEL))) + goto allocerr; + for (i = 0; i < BAS_INURBS; ++i) + if (!(ubc->isoinurbs[i] = + usb_alloc_urb(BAS_NUMFRAMES, SLAB_KERNEL))) + goto allocerr; } ucs->rcvbuf = NULL; @@ -2156,15 +2183,14 @@ static int gigaset_probe(struct usb_interface *interface, (endpoint->bEndpointAddress) & 0x0f), ucs->int_in_buf, 3, read_int_callback, cs, endpoint->bInterval); - ret = usb_submit_urb(ucs->urb_int_in, SLAB_KERNEL); - if (ret) { + if ((rc = usb_submit_urb(ucs->urb_int_in, SLAB_KERNEL)) != 0) { dev_err(cs->dev, "could not submit interrupt URB: %s\n", - get_usb_statmsg(ret)); + get_usb_rcmsg(rc)); goto error; } /* tell the device that the driver is ready */ - if ((ret = req_submit(cs->bcs, HD_DEVICE_INIT_ACK, 0, 0)) != 0) + if ((rc = req_submit(cs->bcs, HD_DEVICE_INIT_ACK, 0, 0)) != 0) goto error; /* tell common part that the device is ready */ @@ -2179,6 +2205,8 @@ static int gigaset_probe(struct usb_interface *interface, return 0; +allocerr: + dev_err(cs->dev, "could not allocate URBs\n"); error: freeurbs(cs); usb_set_intfdata(interface, NULL); @@ -2193,19 +2221,34 @@ static void gigaset_disconnect(struct usb_interface *interface) { struct cardstate *cs; struct bas_cardstate *ucs; + int j; cs = usb_get_intfdata(interface); ucs = cs->hw.bas; dev_info(cs->dev, "disconnecting Gigaset base\n"); + + /* mark base as not ready, all channels disconnected */ + atomic_set(&ucs->basstate, 0); + + /* tell LL all channels are down */ + //FIXME shouldn't gigaset_stop() do this? + for (j = 0; j < 2; ++j) + gigaset_bchannel_down(cs->bcs + j); + + /* stop driver (common part) */ gigaset_stop(cs); + + /* stop timers and URBs, free ressources */ + del_timer_sync(&ucs->timer_ctrl); + del_timer_sync(&ucs->timer_atrdy); + del_timer_sync(&ucs->timer_cmd_in); freeurbs(cs); usb_set_intfdata(interface, NULL); kfree(ucs->rcvbuf); ucs->rcvbuf = NULL; ucs->rcvbuf_size = 0; - atomic_set(&ucs->basstate, 0); usb_put_dev(ucs->udev); ucs->interface = NULL; ucs->udev = NULL; @@ -2277,6 +2320,8 @@ error: if (cardstate) */ static void __exit bas_gigaset_exit(void) { + struct bas_cardstate *ucs = cardstate->hw.bas; + gigaset_blockdriver(driver); /* => probe will fail * => no gigaset_start any more */ @@ -2284,14 +2329,26 @@ static void __exit bas_gigaset_exit(void) gigaset_shutdown(cardstate); /* from now on, no isdn callback should be possible */ - if (atomic_read(&cardstate->hw.bas->basstate) & BS_ATOPEN) { - gig_dbg(DEBUG_ANY, "closing AT channel"); - if (req_submit(cardstate->bcs, - HD_CLOSE_ATCHANNEL, 0, BAS_TIMEOUT) >= 0) { - /* successfully submitted */ - //FIXME wait for completion? - } + /* close all still open channels */ + if (atomic_read(&ucs->basstate) & BS_B1OPEN) { + gig_dbg(DEBUG_INIT, "closing B1 channel"); + usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0), + HD_CLOSE_B1CHANNEL, OUT_VENDOR_REQ, 0, 0, + NULL, 0, BAS_TIMEOUT); + } + if (atomic_read(&ucs->basstate) & BS_B2OPEN) { + gig_dbg(DEBUG_INIT, "closing B2 channel"); + usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0), + HD_CLOSE_B2CHANNEL, OUT_VENDOR_REQ, 0, 0, + NULL, 0, BAS_TIMEOUT); + } + if (atomic_read(&ucs->basstate) & BS_ATOPEN) { + gig_dbg(DEBUG_INIT, "closing AT channel"); + usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0), + HD_CLOSE_ATCHANNEL, OUT_VENDOR_REQ, 0, 0, + NULL, 0, BAS_TIMEOUT); } + atomic_set(&ucs->basstate, 0); /* deregister this driver with the USB subsystem */ usb_deregister(&gigaset_usb_driver); diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index 749b3da1236e..e55767b2ccd3 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c @@ -781,8 +781,7 @@ error: if (cs) } EXPORT_SYMBOL_GPL(gigaset_initcs); -/* ReInitialize the b-channel structure */ -/* e.g. called on hangup, disconnect */ +/* ReInitialize the b-channel structure on hangup */ void gigaset_bcs_reinit(struct bc_state *bcs) { struct sk_buff *skb; diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c index 1ba3424a286b..18e05c09b71c 100644 --- a/drivers/isdn/gigaset/ev-layer.c +++ b/drivers/isdn/gigaset/ev-layer.c @@ -373,6 +373,9 @@ struct reply_t gigaset_tab_cid_m10x[] = /* for M10x */ {EV_TIMEOUT, 750,750, -1, 0, 0, {ACT_CONNTIMEOUT}}, + /* B channel closed (general case) */ + {EV_BC_CLOSED, -1, -1, -1, -1,-1, {ACT_NOTIFY_BC_DOWN}}, //FIXME + /* misc. */ {EV_PROTO_L2, -1, -1, -1, -1,-1, {ACT_PROTO_L2}}, //FIXME diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h index 9d21ba8757b0..22b9693f7c0a 100644 --- a/drivers/isdn/gigaset/gigaset.h +++ b/drivers/isdn/gigaset/gigaset.h @@ -75,7 +75,7 @@ extern int gigaset_debuglevel; /* "needs" cast to (enum debuglevel) */ * e.g. 'insmod usb_gigaset.o debug=0x2c' will set DEBUG_OPEN, DEBUG_CMD and * DEBUG_INTR. */ -enum debuglevel { /* up to 24 bits (atomic_t) */ +enum debuglevel { DEBUG_REG = 0x0002, /* serial port I/O register operations */ DEBUG_OPEN = 0x0004, /* open/close serial port */ DEBUG_INTR = 0x0008, /* interrupt processing */ @@ -141,7 +141,7 @@ enum debuglevel { /* up to 24 bits (atomic_t) */ printk(KERN_DEBUG KBUILD_MODNAME ": " format "\n", \ ## arg); \ } while (0) -#define DEBUG_DEFAULT (DEBUG_INIT | DEBUG_TRANSCMD | DEBUG_CMD | DEBUG_USBREQ) +#define DEBUG_DEFAULT (DEBUG_TRANSCMD | DEBUG_CMD | DEBUG_USBREQ) #else @@ -627,8 +627,7 @@ struct gigaset_ops { /* Called by gigaset_freecs() for freeing bcs->hw.xxx */ int (*freebcshw)(struct bc_state *bcs); - /* Called by gigaset_stop() or gigaset_bchannel_down() for resetting - bcs->hw.xxx */ + /* Called by gigaset_bchannel_down() for resetting bcs->hw.xxx */ void (*reinitbcshw)(struct bc_state *bcs); /* Called by gigaset_initcs() for setting up cs->hw.xxx */ diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c index 0815dbfb8291..1654fa413575 100644 --- a/drivers/isdn/gigaset/i4l.c +++ b/drivers/isdn/gigaset/i4l.c @@ -73,7 +73,7 @@ static int writebuf_from_LL(int driverID, int channel, int ack, len, skblen, (unsigned) skb->head[0], (unsigned) skb->head[1]); /* pass to device-specific module */ - return cs->ops->send_skb(bcs, skb); //FIXME cs->ops->send_skb() must handle !cs->connected correctly + return cs->ops->send_skb(bcs, skb); } void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb) diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c index 45f017ed6e8c..8667daaa1a82 100644 --- a/drivers/isdn/gigaset/isocdata.c +++ b/drivers/isdn/gigaset/isocdata.c @@ -992,14 +992,18 @@ int gigaset_isoc_send_skb(struct bc_state *bcs, struct sk_buff *skb) int len = skb->len; unsigned long flags; + spin_lock_irqsave(&bcs->cs->lock, flags); + if (!bcs->cs->connected) { + spin_unlock_irqrestore(&bcs->cs->lock, flags); + return -ENODEV; + } + skb_queue_tail(&bcs->squeue, skb); gig_dbg(DEBUG_ISO, "%s: skb queued, qlen=%d", __func__, skb_queue_len(&bcs->squeue)); /* tasklet submits URB if necessary */ - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->cs->connected) - tasklet_schedule(&bcs->hw.bas->sent_tasklet); + tasklet_schedule(&bcs->hw.bas->sent_tasklet); spin_unlock_irqrestore(&bcs->cs->lock, flags); return len; /* ok so far */ -- cgit v1.2.3 From 8c4335a87c9785d2102ab23f09393038e1663314 Mon Sep 17 00:00:00 2001 From: "akpm@osdl.org" Date: Sat, 22 Apr 2006 02:36:15 -0700 Subject: [PATCH] Altix snsc: duplicate kobject fix from: Greg Howard Fix Altix system controller (snsc) device names to include the slot number of the blade whose associated system controller is the target of the device interface. Including the slot number avoids a problem we're currently having where slots within the same enclosure are attempting to create multiple kobjects with identical names. Signed-off-by: Greg Howard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/snsc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c index b543821d8cb4..56c8243cdb73 100644 --- a/drivers/char/snsc.c +++ b/drivers/char/snsc.c @@ -390,7 +390,8 @@ scdrv_init(void) format_module_id(devnamep, geo_module(geoid), MODULE_FORMAT_BRIEF); devnamep = devname + strlen(devname); - sprintf(devnamep, "#%d", geo_slab(geoid)); + sprintf(devnamep, "^%d#%d", geo_slot(geoid), + geo_slab(geoid)); /* allocate sysctl device data */ scd = kzalloc(sizeof (struct sysctl_data_s), -- cgit v1.2.3 From 59e89f3a091d5cf93f4b176aedcfded61ece5252 Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sat, 22 Apr 2006 02:36:35 -0700 Subject: [PATCH] tpm: fix memory leak The eventname was kmalloc'd and not freed in the *_show functions. This bug was found by Coverity. Signed-off-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm_bios.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c index 537aa45d8c67..0549e2a35df8 100644 --- a/drivers/char/tpm/tpm_bios.c +++ b/drivers/char/tpm/tpm_bios.c @@ -306,6 +306,7 @@ static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v) /* 5th: delimiter */ seq_putc(m, '\0'); + kfree(eventname); return 0; } @@ -353,6 +354,7 @@ static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v) /* 4th: eventname <= max + \'0' delimiter */ seq_printf(m, " %s\n", eventname); + kfree(eventname); return 0; } -- cgit v1.2.3 From 7c69a47f1badf40dfa2febac71df98d32b1b56d7 Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sat, 22 Apr 2006 02:36:46 -0700 Subject: [PATCH] tpm: fix missing string A string corresponding to the tcpa_pc_event_id POST_CONTENTS was missing causing an overflow bug when access was attempted in the get_event_name function. This bug was found by Coverity. Signed-off-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm_bios.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c index 0549e2a35df8..5bcbaef53798 100644 --- a/drivers/char/tpm/tpm_bios.c +++ b/drivers/char/tpm/tpm_bios.c @@ -120,6 +120,7 @@ static const char* tcpa_pc_event_id_strings[] = { "S-CRTM Version", "S-CRTM Contents", "S-CRTM POST Contents", + "POST Contents", }; /* returns pointer to start of pos. entry of tcg log */ -- cgit v1.2.3 From 3c2f606a098b07f053904ec8b8f4d0e101c28b35 Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sat, 22 Apr 2006 02:36:56 -0700 Subject: [PATCH] tpm: spacing cleanups The following patch set contains numerous changes to the base tpm driver (tpm.c) to support the next generation of TPM chips. The changes include new sysfs files because of more relevant data being available, a function to access the timeout and duration values for the chip, and changes to make use of those duration values. Duration in the TPM specification is defined as the maximum amount of time the chip could take to return the results. Commands are in one of three categories short, medium and long. Also included are cleanups of how the commands for the sysfs files are composed to reduce a bunch of redundant arrays. This patch: Fix minor spacing issues. Signed-off-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 5a3870477ef1..379c5d465579 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -46,7 +46,7 @@ static void user_reader_timeout(unsigned long ptr) schedule_work(&chip->work); } -static void timeout_work(void * ptr) +static void timeout_work(void *ptr) { struct tpm_chip *chip = ptr; @@ -387,7 +387,7 @@ int tpm_release(struct inode *inode, struct file *file) EXPORT_SYMBOL_GPL(tpm_release); ssize_t tpm_write(struct file *file, const char __user *buf, - size_t size, loff_t * off) + size_t size, loff_t *off) { struct tpm_chip *chip = file->private_data; int in_size = size, out_size; @@ -419,11 +419,10 @@ ssize_t tpm_write(struct file *file, const char __user *buf, return in_size; } - EXPORT_SYMBOL_GPL(tpm_write); -ssize_t tpm_read(struct file * file, char __user *buf, - size_t size, loff_t * off) +ssize_t tpm_read(struct file *file, char __user *buf, + size_t size, loff_t *off) { struct tpm_chip *chip = file->private_data; int ret_size; -- cgit v1.2.3 From beed53a1aaeaae4eb93297c23f1598a726716adf Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sat, 22 Apr 2006 02:37:05 -0700 Subject: [PATCH] tpm: reorganize sysfs files Many of the sysfs files were calling the TPM_GetCapability command with array. Since for 1.2 more sysfs files of this type are coming I am generalizing the array so there can be one array and the unique parts can be filled in just before the command is called. Signed-off-by: Kylene Hall Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm.c | 145 +++++++++++++++++++++++++++++-------------------- 1 file changed, 86 insertions(+), 59 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 379c5d465579..187bcdaf7bf6 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -119,17 +119,57 @@ out: } #define TPM_DIGEST_SIZE 20 -#define CAP_PCR_RESULT_SIZE 18 -static const u8 cap_pcr[] = { +#define TPM_ERROR_SIZE 10 +#define TPM_RET_CODE_IDX 6 +#define TPM_GET_CAP_RET_SIZE_IDX 10 +#define TPM_GET_CAP_RET_UINT32_1_IDX 14 +#define TPM_GET_CAP_RET_UINT32_2_IDX 18 +#define TPM_GET_CAP_RET_UINT32_3_IDX 22 +#define TPM_GET_CAP_RET_UINT32_4_IDX 26 + +#define TPM_CAP_IDX 13 +#define TPM_CAP_SUBCAP_IDX 21 + +enum tpm_capabilities { + TPM_CAP_PROP = 5, +}; + +enum tpm_sub_capabilities { + TPM_CAP_PROP_PCR = 0x1, + TPM_CAP_PROP_MANUFACTURER = 0x3, +}; + +/* + * This is a semi generic GetCapability command for use + * with the capability type TPM_CAP_PROP or TPM_CAP_FLAG + * and their associated sub_capabilities. + */ + +static const u8 tpm_cap[] = { 0, 193, /* TPM_TAG_RQU_COMMAND */ 0, 0, 0, 22, /* length */ 0, 0, 0, 101, /* TPM_ORD_GetCapability */ - 0, 0, 0, 5, - 0, 0, 0, 4, - 0, 0, 1, 1 + 0, 0, 0, 0, /* TPM_CAP_ */ + 0, 0, 0, 4, /* TPM_CAP_SUB_ size */ + 0, 0, 1, 0 /* TPM_CAP_SUB_ */ }; -#define READ_PCR_RESULT_SIZE 30 +static ssize_t transmit_cmd(struct tpm_chip *chip, u8 *data, int len, + char *desc) +{ + int err; + + len = tpm_transmit(chip, data, len); + if (len < 0) + return len; + if (len == TPM_ERROR_SIZE) { + err = be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX))); + dev_dbg(chip->dev, "A TPM error (%d) occurred %s\n", err, desc); + return err; + } + return 0; +} + static const u8 pcrread[] = { 0, 193, /* TPM_TAG_RQU_COMMAND */ 0, 0, 0, 14, /* length */ @@ -140,8 +180,8 @@ static const u8 pcrread[] = { ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, char *buf) { - u8 data[READ_PCR_RESULT_SIZE]; - ssize_t len; + u8 data[30]; + ssize_t rc; int i, j, num_pcrs; __be32 index; char *str = buf; @@ -150,29 +190,24 @@ ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, if (chip == NULL) return -ENODEV; - memcpy(data, cap_pcr, sizeof(cap_pcr)); - if ((len = tpm_transmit(chip, data, sizeof(data))) - < CAP_PCR_RESULT_SIZE) { - dev_dbg(chip->dev, "A TPM error (%d) occurred " - "attempting to determine the number of PCRS\n", - be32_to_cpu(*((__be32 *) (data + 6)))); + memcpy(data, tpm_cap, sizeof(tpm_cap)); + data[TPM_CAP_IDX] = TPM_CAP_PROP; + data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_PCR; + + rc = transmit_cmd(chip, data, sizeof(data), + "attempting to determine the number of PCRS"); + if (rc) return 0; - } num_pcrs = be32_to_cpu(*((__be32 *) (data + 14))); - for (i = 0; i < num_pcrs; i++) { memcpy(data, pcrread, sizeof(pcrread)); index = cpu_to_be32(i); memcpy(data + 10, &index, 4); - if ((len = tpm_transmit(chip, data, sizeof(data))) - < READ_PCR_RESULT_SIZE){ - dev_dbg(chip->dev, "A TPM error (%d) occurred" - " attempting to read PCR %d of %d\n", - be32_to_cpu(*((__be32 *) (data + 6))), - i, num_pcrs); + rc = transmit_cmd(chip, data, sizeof(data), + "attempting to read a PCR"); + if (rc) goto out; - } str += sprintf(str, "PCR-%02d: ", i); for (j = 0; j < TPM_DIGEST_SIZE; j++) str += sprintf(str, "%02X ", *(data + 10 + j)); @@ -194,7 +229,7 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, char *buf) { u8 *data; - ssize_t len; + ssize_t err; int i, rc; char *str = buf; @@ -208,14 +243,10 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, memcpy(data, readpubek, sizeof(readpubek)); - if ((len = tpm_transmit(chip, data, READ_PUBEK_RESULT_SIZE)) < - READ_PUBEK_RESULT_SIZE) { - dev_dbg(chip->dev, "A TPM error (%d) occurred " - "attempting to read the PUBEK\n", - be32_to_cpu(*((__be32 *) (data + 6)))); - rc = 0; + err = transmit_cmd(chip, data, READ_PUBEK_RESULT_SIZE, + "attempting to read the PUBEK"); + if (err) goto out; - } /* ignore header 10 bytes @@ -245,63 +276,59 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, if ((i + 1) % 16 == 0) str += sprintf(str, "\n"); } - rc = str - buf; out: + rc = str - buf; kfree(data); return rc; } EXPORT_SYMBOL_GPL(tpm_show_pubek); -#define CAP_VER_RESULT_SIZE 18 +#define CAP_VERSION_1_1 6 +#define CAP_VERSION_IDX 13 static const u8 cap_version[] = { 0, 193, /* TPM_TAG_RQU_COMMAND */ 0, 0, 0, 18, /* length */ 0, 0, 0, 101, /* TPM_ORD_GetCapability */ - 0, 0, 0, 6, + 0, 0, 0, 0, 0, 0, 0, 0 }; -#define CAP_MANUFACTURER_RESULT_SIZE 18 -static const u8 cap_manufacturer[] = { - 0, 193, /* TPM_TAG_RQU_COMMAND */ - 0, 0, 0, 22, /* length */ - 0, 0, 0, 101, /* TPM_ORD_GetCapability */ - 0, 0, 0, 5, - 0, 0, 0, 4, - 0, 0, 1, 3 -}; - ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, char *buf) { - u8 data[sizeof(cap_manufacturer)]; - ssize_t len; + u8 data[30]; + ssize_t rc; char *str = buf; struct tpm_chip *chip = dev_get_drvdata(dev); if (chip == NULL) return -ENODEV; - memcpy(data, cap_manufacturer, sizeof(cap_manufacturer)); + memcpy(data, tpm_cap, sizeof(tpm_cap)); + data[TPM_CAP_IDX] = TPM_CAP_PROP; + data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER; - if ((len = tpm_transmit(chip, data, sizeof(data))) < - CAP_MANUFACTURER_RESULT_SIZE) - return len; + rc = transmit_cmd(chip, data, sizeof(data), + "attempting to determine the manufacturer"); + if (rc) + return 0; str += sprintf(str, "Manufacturer: 0x%x\n", - be32_to_cpu(*((__be32 *) (data + 14)))); + be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)))); memcpy(data, cap_version, sizeof(cap_version)); + data[CAP_VERSION_IDX] = CAP_VERSION_1_1; + rc = transmit_cmd(chip, data, sizeof(data), + "attempting to determine the 1.1 version"); + if (rc) + goto out; - if ((len = tpm_transmit(chip, data, sizeof(data))) < - CAP_VER_RESULT_SIZE) - return len; - - str += - sprintf(str, "TCG version: %d.%d\nFirmware version: %d.%d\n", - (int) data[14], (int) data[15], (int) data[16], - (int) data[17]); + str += sprintf(str, + "TCG version: %d.%d\nFirmware version: %d.%d\n", + (int) data[14], (int) data[15], (int) data[16], + (int) data[17]); +out: return str - buf; } EXPORT_SYMBOL_GPL(tpm_show_caps); -- cgit v1.2.3 From 90dda520c1962d55a0e1d2571deed0d75fd6d6f1 Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sat, 22 Apr 2006 02:37:15 -0700 Subject: [PATCH] tpm: chip struct update To assist with chip management and better support the possibility of having multiple TPMs in the system of the same kind, the struct tpm_vendor_specific member of the tpm_chip was changed from a pointer to an instance. This patch changes that declaration and fixes up all accesses to the structure member except in tpm_infineon which is coming in a patch from Marcel Selhorst. Signed-off-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm.c | 48 +++++++++++++++++++++----------------------- drivers/char/tpm/tpm.h | 2 +- drivers/char/tpm/tpm_atmel.c | 26 ++++++++++++------------ drivers/char/tpm/tpm_nsc.c | 32 ++++++++++++++--------------- 4 files changed, 53 insertions(+), 55 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 187bcdaf7bf6..50013eb8cf1e 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -78,7 +78,7 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, down(&chip->tpm_mutex); - if ((rc = chip->vendor->send(chip, (u8 *) buf, count)) < 0) { + if ((rc = chip->vendor.send(chip, (u8 *) buf, count)) < 0) { dev_err(chip->dev, "tpm_transmit: tpm_send: error %zd\n", rc); goto out; @@ -86,13 +86,12 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, stop = jiffies + 2 * 60 * HZ; do { - u8 status = chip->vendor->status(chip); - if ((status & chip->vendor->req_complete_mask) == - chip->vendor->req_complete_val) { + u8 status = chip->vendor.status(chip); + if ((status & chip->vendor.req_complete_mask) == + chip->vendor.req_complete_val) goto out_recv; - } - if ((status == chip->vendor->req_canceled)) { + if ((status == chip->vendor.req_canceled)) { dev_err(chip->dev, "Operation Canceled\n"); rc = -ECANCELED; goto out; @@ -102,14 +101,13 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, rmb(); } while (time_before(jiffies, stop)); - - chip->vendor->cancel(chip); + chip->vendor.cancel(chip); dev_err(chip->dev, "Operation Timed out\n"); rc = -ETIME; goto out; out_recv: - rc = chip->vendor->recv(chip, (u8 *) buf, bufsiz); + rc = chip->vendor.recv(chip, (u8 *) buf, bufsiz); if (rc < 0) dev_err(chip->dev, "tpm_transmit: tpm_recv: error %zd\n", rc); @@ -340,7 +338,7 @@ ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr, if (chip == NULL) return 0; - chip->vendor->cancel(chip); + chip->vendor.cancel(chip); return count; } EXPORT_SYMBOL_GPL(tpm_store_cancel); @@ -356,7 +354,7 @@ int tpm_open(struct inode *inode, struct file *file) spin_lock(&driver_lock); list_for_each_entry(pos, &tpm_chip_list, list) { - if (pos->vendor->miscdev.minor == minor) { + if (pos->vendor.miscdev.minor == minor) { chip = pos; break; } @@ -488,14 +486,14 @@ void tpm_remove_hardware(struct device *dev) spin_unlock(&driver_lock); dev_set_drvdata(dev, NULL); - misc_deregister(&chip->vendor->miscdev); - kfree(chip->vendor->miscdev.name); + misc_deregister(&chip->vendor.miscdev); + kfree(chip->vendor.miscdev.name); - sysfs_remove_group(&dev->kobj, chip->vendor->attr_group); + sysfs_remove_group(&dev->kobj, chip->vendor.attr_group); tpm_bios_log_teardown(chip->bios_dir); - dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES ] &= - ~(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES)); + dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES] &= + ~(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES)); kfree(chip); @@ -569,7 +567,7 @@ int tpm_register_hardware(struct device *dev, struct tpm_vendor_specific *entry) chip->user_read_timer.function = user_reader_timeout; chip->user_read_timer.data = (unsigned long) chip; - chip->vendor = entry; + memcpy(&chip->vendor, entry, sizeof(struct tpm_vendor_specific)); chip->dev_num = -1; @@ -588,22 +586,22 @@ dev_num_search_complete: kfree(chip); return -ENODEV; } else if (chip->dev_num == 0) - chip->vendor->miscdev.minor = TPM_MINOR; + chip->vendor.miscdev.minor = TPM_MINOR; else - chip->vendor->miscdev.minor = MISC_DYNAMIC_MINOR; + chip->vendor.miscdev.minor = MISC_DYNAMIC_MINOR; devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL); scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num); - chip->vendor->miscdev.name = devname; + chip->vendor.miscdev.name = devname; - chip->vendor->miscdev.dev = dev; + chip->vendor.miscdev.dev = dev; chip->dev = get_device(dev); - if (misc_register(&chip->vendor->miscdev)) { + if (misc_register(&chip->vendor.miscdev)) { dev_err(chip->dev, "unable to misc_register %s, minor %d\n", - chip->vendor->miscdev.name, - chip->vendor->miscdev.minor); + chip->vendor.miscdev.name, + chip->vendor.miscdev.minor); put_device(dev); kfree(chip); dev_mask[i] &= !(1 << j); @@ -618,7 +616,7 @@ dev_num_search_complete: spin_unlock(&driver_lock); - sysfs_create_group(&dev->kobj, chip->vendor->attr_group); + sysfs_create_group(&dev->kobj, chip->vendor.attr_group); chip->bios_dir = tpm_bios_log_setup(devname); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index dec0224b4478..a203963efaab 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -81,7 +81,7 @@ struct tpm_chip { struct work_struct work; struct semaphore tpm_mutex; /* tpm is processing */ - struct tpm_vendor_specific *vendor; + struct tpm_vendor_specific vendor; struct dentry **bios_dir; diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c index ff3654964fe3..26787976ef1a 100644 --- a/drivers/char/tpm/tpm_atmel.c +++ b/drivers/char/tpm/tpm_atmel.c @@ -47,12 +47,12 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count) return -EIO; for (i = 0; i < 6; i++) { - status = ioread8(chip->vendor->iobase + 1); + status = ioread8(chip->vendor.iobase + 1); if ((status & ATML_STATUS_DATA_AVAIL) == 0) { dev_err(chip->dev, "error reading header\n"); return -EIO; } - *buf++ = ioread8(chip->vendor->iobase); + *buf++ = ioread8(chip->vendor.iobase); } /* size of the data received */ @@ -63,7 +63,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count) dev_err(chip->dev, "Recv size(%d) less than available space\n", size); for (; i < size; i++) { /* clear the waiting data anyway */ - status = ioread8(chip->vendor->iobase + 1); + status = ioread8(chip->vendor.iobase + 1); if ((status & ATML_STATUS_DATA_AVAIL) == 0) { dev_err(chip->dev, "error reading data\n"); return -EIO; @@ -74,16 +74,16 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count) /* read all the data available */ for (; i < size; i++) { - status = ioread8(chip->vendor->iobase + 1); + status = ioread8(chip->vendor.iobase + 1); if ((status & ATML_STATUS_DATA_AVAIL) == 0) { dev_err(chip->dev, "error reading data\n"); return -EIO; } - *buf++ = ioread8(chip->vendor->iobase); + *buf++ = ioread8(chip->vendor.iobase); } /* make sure data available is gone */ - status = ioread8(chip->vendor->iobase + 1); + status = ioread8(chip->vendor.iobase + 1); if (status & ATML_STATUS_DATA_AVAIL) { dev_err(chip->dev, "data available is stuck\n"); @@ -100,7 +100,7 @@ static int tpm_atml_send(struct tpm_chip *chip, u8 *buf, size_t count) dev_dbg(chip->dev, "tpm_atml_send:\n"); for (i = 0; i < count; i++) { dev_dbg(chip->dev, "%d 0x%x(%d)\n", i, buf[i], buf[i]); - iowrite8(buf[i], chip->vendor->iobase); + iowrite8(buf[i], chip->vendor.iobase); } return count; @@ -108,12 +108,12 @@ static int tpm_atml_send(struct tpm_chip *chip, u8 *buf, size_t count) static void tpm_atml_cancel(struct tpm_chip *chip) { - iowrite8(ATML_STATUS_ABORT, chip->vendor->iobase + 1); + iowrite8(ATML_STATUS_ABORT, chip->vendor.iobase + 1); } static u8 tpm_atml_status(struct tpm_chip *chip) { - return ioread8(chip->vendor->iobase + 1); + return ioread8(chip->vendor.iobase + 1); } static struct file_operations atmel_ops = { @@ -159,10 +159,10 @@ static void atml_plat_remove(void) struct tpm_chip *chip = dev_get_drvdata(&pdev->dev); if (chip) { - if (chip->vendor->have_region) - atmel_release_region(chip->vendor->base, - chip->vendor->region_size); - atmel_put_base_addr(chip->vendor); + if (chip->vendor.have_region) + atmel_release_region(chip->vendor.base, + chip->vendor.region_size); + atmel_put_base_addr(chip->vendor.iobase); tpm_remove_hardware(chip->dev); platform_device_unregister(pdev); } diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c index 680a8e331887..3dbbe9686c76 100644 --- a/drivers/char/tpm/tpm_nsc.c +++ b/drivers/char/tpm/tpm_nsc.c @@ -71,7 +71,7 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, u8 val, u8 * data) unsigned long stop; /* status immediately available check */ - *data = inb(chip->vendor->base + NSC_STATUS); + *data = inb(chip->vendor.base + NSC_STATUS); if ((*data & mask) == val) return 0; @@ -79,7 +79,7 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, u8 val, u8 * data) stop = jiffies + 10 * HZ; do { msleep(TPM_TIMEOUT); - *data = inb(chip->vendor->base + 1); + *data = inb(chip->vendor.base + 1); if ((*data & mask) == val) return 0; } @@ -94,9 +94,9 @@ static int nsc_wait_for_ready(struct tpm_chip *chip) unsigned long stop; /* status immediately available check */ - status = inb(chip->vendor->base + NSC_STATUS); + status = inb(chip->vendor.base + NSC_STATUS); if (status & NSC_STATUS_OBF) - status = inb(chip->vendor->base + NSC_DATA); + status = inb(chip->vendor.base + NSC_DATA); if (status & NSC_STATUS_RDY) return 0; @@ -104,9 +104,9 @@ static int nsc_wait_for_ready(struct tpm_chip *chip) stop = jiffies + 100; do { msleep(TPM_TIMEOUT); - status = inb(chip->vendor->base + NSC_STATUS); + status = inb(chip->vendor.base + NSC_STATUS); if (status & NSC_STATUS_OBF) - status = inb(chip->vendor->base + NSC_DATA); + status = inb(chip->vendor.base + NSC_DATA); if (status & NSC_STATUS_RDY) return 0; } @@ -132,7 +132,7 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count) return -EIO; } if ((data = - inb(chip->vendor->base + NSC_DATA)) != NSC_COMMAND_NORMAL) { + inb(chip->vendor.base + NSC_DATA)) != NSC_COMMAND_NORMAL) { dev_err(chip->dev, "not in normal mode (0x%x)\n", data); return -EIO; @@ -148,7 +148,7 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count) } if (data & NSC_STATUS_F0) break; - *p = inb(chip->vendor->base + NSC_DATA); + *p = inb(chip->vendor.base + NSC_DATA); } if ((data & NSC_STATUS_F0) == 0 && @@ -156,7 +156,7 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count) dev_err(chip->dev, "F0 not set\n"); return -EIO; } - if ((data = inb(chip->vendor->base + NSC_DATA)) != NSC_COMMAND_EOC) { + if ((data = inb(chip->vendor.base + NSC_DATA)) != NSC_COMMAND_EOC) { dev_err(chip->dev, "expected end of command(0x%x)\n", data); return -EIO; @@ -182,7 +182,7 @@ static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count) * fix it. Not sure why this is needed, we followed the flow * chart in the manual to the letter. */ - outb(NSC_COMMAND_CANCEL, chip->vendor->base + NSC_COMMAND); + outb(NSC_COMMAND_CANCEL, chip->vendor.base + NSC_COMMAND); if (nsc_wait_for_ready(chip) != 0) return -EIO; @@ -192,7 +192,7 @@ static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count) return -EIO; } - outb(NSC_COMMAND_NORMAL, chip->vendor->base + NSC_COMMAND); + outb(NSC_COMMAND_NORMAL, chip->vendor.base + NSC_COMMAND); if (wait_for_stat(chip, NSC_STATUS_IBR, NSC_STATUS_IBR, &data) < 0) { dev_err(chip->dev, "IBR timeout\n"); return -EIO; @@ -204,26 +204,26 @@ static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count) "IBF timeout (while writing data)\n"); return -EIO; } - outb(buf[i], chip->vendor->base + NSC_DATA); + outb(buf[i], chip->vendor.base + NSC_DATA); } if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) { dev_err(chip->dev, "IBF timeout\n"); return -EIO; } - outb(NSC_COMMAND_EOC, chip->vendor->base + NSC_COMMAND); + outb(NSC_COMMAND_EOC, chip->vendor.base + NSC_COMMAND); return count; } static void tpm_nsc_cancel(struct tpm_chip *chip) { - outb(NSC_COMMAND_CANCEL, chip->vendor->base + NSC_COMMAND); + outb(NSC_COMMAND_CANCEL, chip->vendor.base + NSC_COMMAND); } static u8 tpm_nsc_status(struct tpm_chip *chip) { - return inb(chip->vendor->base + NSC_STATUS); + return inb(chip->vendor.base + NSC_STATUS); } static struct file_operations nsc_ops = { @@ -268,7 +268,7 @@ static void __devexit tpm_nsc_remove(struct device *dev) { struct tpm_chip *chip = dev_get_drvdata(dev); if ( chip ) { - release_region(chip->vendor->base, 2); + release_region(chip->vendor.base, 2); tpm_remove_hardware(chip->dev); } } -- cgit v1.2.3 From e0dd03caf20d040a0a86b6bd74028ec9bda545f5 Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sat, 22 Apr 2006 02:37:26 -0700 Subject: [PATCH] tpm: return chip from tpm_register_hardware Changes in the 1.2 TPM Specification make it necessary to update some fields of the chip structure in the initialization function after it is registered with tpm.c thus tpm_register_hardware was modified to return a pointer to the structure. This patch makes that change and the associated changes in tpm_atmel and tpm_nsc. The changes to tpm_infineon will be coming in a patch from Marcel Selhorst. Signed-off-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm.c | 11 ++++++----- drivers/char/tpm/tpm.h | 10 +++++----- drivers/char/tpm/tpm_atmel.c | 32 ++++++++++++++++++++++---------- drivers/char/tpm/tpm_atmel.h | 25 +++++++++++-------------- drivers/char/tpm/tpm_nsc.c | 17 +++++++++++------ 5 files changed, 55 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 50013eb8cf1e..5e58296f2832 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -544,7 +544,8 @@ EXPORT_SYMBOL_GPL(tpm_pm_resume); * upon errant exit from this function specific probe function should call * pci_disable_device */ -int tpm_register_hardware(struct device *dev, struct tpm_vendor_specific *entry) +struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vendor_specific + *entry) { #define DEVNAME_SIZE 7 @@ -555,7 +556,7 @@ int tpm_register_hardware(struct device *dev, struct tpm_vendor_specific *entry) /* Driver specific per-device data */ chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) - return -ENOMEM; + return NULL; init_MUTEX(&chip->buffer_mutex); init_MUTEX(&chip->tpm_mutex); @@ -584,7 +585,7 @@ dev_num_search_complete: if (chip->dev_num < 0) { dev_err(dev, "No available tpm device numbers\n"); kfree(chip); - return -ENODEV; + return NULL; } else if (chip->dev_num == 0) chip->vendor.miscdev.minor = TPM_MINOR; else @@ -605,7 +606,7 @@ dev_num_search_complete: put_device(dev); kfree(chip); dev_mask[i] &= !(1 << j); - return -ENODEV; + return NULL; } spin_lock(&driver_lock); @@ -620,7 +621,7 @@ dev_num_search_complete: chip->bios_dir = tpm_bios_log_setup(devname); - return 0; + return chip; } EXPORT_SYMBOL_GPL(tpm_register_hardware); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index a203963efaab..4f005345bf37 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -48,9 +48,9 @@ extern ssize_t tpm_store_cancel(struct device *, struct device_attribute *attr, struct tpm_chip; struct tpm_vendor_specific { - u8 req_complete_mask; - u8 req_complete_val; - u8 req_canceled; + const u8 req_complete_mask; + const u8 req_complete_val; + const u8 req_canceled; void __iomem *iobase; /* ioremapped address */ unsigned long base; /* TPM base address */ @@ -100,8 +100,8 @@ static inline void tpm_write_index(int base, int index, int value) outb(value & 0xFF, base+1); } -extern int tpm_register_hardware(struct device *, - struct tpm_vendor_specific *); +extern struct tpm_chip* tpm_register_hardware(struct device *, + const struct tpm_vendor_specific *); extern int tpm_open(struct inode *, struct file *); extern int tpm_release(struct inode *, struct file *); extern ssize_t tpm_write(struct file *, const char __user *, size_t, diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c index 26787976ef1a..58a258cec153 100644 --- a/drivers/char/tpm/tpm_atmel.c +++ b/drivers/char/tpm/tpm_atmel.c @@ -140,7 +140,7 @@ static struct attribute* atmel_attrs[] = { static struct attribute_group atmel_attr_grp = { .attrs = atmel_attrs }; -static struct tpm_vendor_specific tpm_atmel = { +static const struct tpm_vendor_specific tpm_atmel = { .recv = tpm_atml_recv, .send = tpm_atml_send, .cancel = tpm_atml_cancel, @@ -179,18 +179,22 @@ static struct device_driver atml_drv = { static int __init init_atmel(void) { int rc = 0; + void __iomem *iobase = NULL; + int have_region, region_size; + unsigned long base; + struct tpm_chip *chip; driver_register(&atml_drv); - if ((tpm_atmel.iobase = atmel_get_base_addr(&tpm_atmel)) == NULL) { + if ((iobase = atmel_get_base_addr(&base, ®ion_size)) == NULL) { rc = -ENODEV; goto err_unreg_drv; } - tpm_atmel.have_region = + have_region = (atmel_request_region - (tpm_atmel.base, tpm_atmel.region_size, - "tpm_atmel0") == NULL) ? 0 : 1; + (tpm_atmel.base, region_size, "tpm_atmel0") == NULL) ? 0 : 1; + if (IS_ERR (pdev = @@ -199,17 +203,25 @@ static int __init init_atmel(void) goto err_rel_reg; } - if ((rc = tpm_register_hardware(&pdev->dev, &tpm_atmel)) < 0) + if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_atmel))) { + rc = -ENODEV; goto err_unreg_dev; + } + + chip->vendor.iobase = iobase; + chip->vendor.base = base; + chip->vendor.have_region = have_region; + chip->vendor.region_size = region_size; + return 0; err_unreg_dev: platform_device_unregister(pdev); err_rel_reg: - atmel_put_base_addr(&tpm_atmel); - if (tpm_atmel.have_region) - atmel_release_region(tpm_atmel.base, - tpm_atmel.region_size); + atmel_put_base_addr(iobase); + if (have_region) + atmel_release_region(base, + region_size); err_unreg_drv: driver_unregister(&atml_drv); return rc; diff --git a/drivers/char/tpm/tpm_atmel.h b/drivers/char/tpm/tpm_atmel.h index d3478aaadd77..2e68eeb8a2cd 100644 --- a/drivers/char/tpm/tpm_atmel.h +++ b/drivers/char/tpm/tpm_atmel.h @@ -28,13 +28,12 @@ #define atmel_request_region request_mem_region #define atmel_release_region release_mem_region -static inline void atmel_put_base_addr(struct tpm_vendor_specific - *vendor) +static inline void atmel_put_base_addr(void __iomem *iobase) { - iounmap(vendor->iobase); + iounmap(iobase); } -static void __iomem * atmel_get_base_addr(struct tpm_vendor_specific *vendor) +static void __iomem * atmel_get_base_addr(unsigned long *base, int *region_size) { struct device_node *dn; unsigned long address, size; @@ -71,9 +70,9 @@ static void __iomem * atmel_get_base_addr(struct tpm_vendor_specific *vendor) else size = reg[naddrc]; - vendor->base = address; - vendor->region_size = size; - return ioremap(vendor->base, vendor->region_size); + *base = address; + *region_size = size; + return ioremap(*base, *region_size); } #else #define atmel_getb(chip, offset) inb(chip->vendor->base + offset) @@ -106,14 +105,12 @@ static int atmel_verify_tpm11(void) return 0; } -static inline void atmel_put_base_addr(struct tpm_vendor_specific - *vendor) +static inline void atmel_put_base_addr(void __iomem *iobase) { } /* Determine where to talk to device */ -static void __iomem * atmel_get_base_addr(struct tpm_vendor_specific - *vendor) +static void __iomem * atmel_get_base_addr(unsigned long *base, int *region_size) { int lo, hi; @@ -123,9 +120,9 @@ static void __iomem * atmel_get_base_addr(struct tpm_vendor_specific lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO); hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI); - vendor->base = (hi << 8) | lo; - vendor->region_size = 2; + *base = (hi << 8) | lo; + *region_size = 2; - return ioport_map(vendor->base, vendor->region_size); + return ioport_map(*base, *region_size); } #endif diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c index 3dbbe9686c76..4c8bc06c7d95 100644 --- a/drivers/char/tpm/tpm_nsc.c +++ b/drivers/char/tpm/tpm_nsc.c @@ -250,7 +250,7 @@ static struct attribute * nsc_attrs[] = { static struct attribute_group nsc_attr_grp = { .attrs = nsc_attrs }; -static struct tpm_vendor_specific tpm_nsc = { +static const struct tpm_vendor_specific tpm_nsc = { .recv = tpm_nsc_recv, .send = tpm_nsc_send, .cancel = tpm_nsc_cancel, @@ -286,7 +286,8 @@ static int __init init_nsc(void) int rc = 0; int lo, hi; int nscAddrBase = TPM_ADDR; - + struct tpm_chip *chip; + unsigned long base; /* verify that it is a National part (SID) */ if (tpm_read_index(TPM_ADDR, NSC_SID_INDEX) != 0xEF) { @@ -300,7 +301,7 @@ static int __init init_nsc(void) hi = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_HI); lo = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_LO); - tpm_nsc.base = (hi<<8) | lo; + base = (hi<<8) | lo; /* enable the DPM module */ tpm_write_index(nscAddrBase, NSC_LDC_INDEX, 0x01); @@ -320,13 +321,15 @@ static int __init init_nsc(void) if ((rc = platform_device_register(pdev)) < 0) goto err_free_dev; - if (request_region(tpm_nsc.base, 2, "tpm_nsc0") == NULL ) { + if (request_region(base, 2, "tpm_nsc0") == NULL ) { rc = -EBUSY; goto err_unreg_dev; } - if ((rc = tpm_register_hardware(&pdev->dev, &tpm_nsc)) < 0) + if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_nsc))) { + rc = -ENODEV; goto err_rel_reg; + } dev_dbg(&pdev->dev, "NSC TPM detected\n"); dev_dbg(&pdev->dev, @@ -361,10 +364,12 @@ static int __init init_nsc(void) "NSC TPM revision %d\n", tpm_read_index(nscAddrBase, 0x27) & 0x1F); + chip->vendor.base = base; + return 0; err_rel_reg: - release_region(tpm_nsc.base, 2); + release_region(base, 2); err_unreg_dev: platform_device_unregister(pdev); err_free_dev: -- cgit v1.2.3 From 9e18ee19179a7742999d0e2d4bfcba75b5562439 Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sat, 22 Apr 2006 02:37:38 -0700 Subject: [PATCH] tpm: command duration update With the TPM 1.2 Specification, each command is classified as short, medium or long and the chip tells you the maximum amount of time for a response to each class of command. This patch provides and array of the classifications and a function to determine how long the response should be waited for. Also, it uses that information in the command processing to determine how long to poll for. The function is exported so the 1.2 driver can use the functionality to determine how long to wait for a DataAvailable interrupt if interrupts are being used. Signed-off-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm.c | 312 ++++++++++++++++++++++++++++++++++++++++++++++++- drivers/char/tpm/tpm.h | 2 + 2 files changed, 311 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 5e58296f2832..e54bcb4e4e3e 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -35,10 +35,290 @@ enum tpm_const { TPM_NUM_MASK_ENTRIES = TPM_NUM_DEVICES / (8 * sizeof(int)) }; +enum tpm_duration { + TPM_SHORT = 0, + TPM_MEDIUM = 1, + TPM_LONG = 2, + TPM_UNDEFINED, +}; + +#define TPM_MAX_ORDINAL 243 +#define TPM_MAX_PROTECTED_ORDINAL 12 +#define TPM_PROTECTED_ORDINAL_MASK 0xFF + static LIST_HEAD(tpm_chip_list); static DEFINE_SPINLOCK(driver_lock); static int dev_mask[TPM_NUM_MASK_ENTRIES]; +/* + * Array with one entry per ordinal defining the maximum amount + * of time the chip could take to return the result. The ordinal + * designation of short, medium or long is defined in a table in + * TCG Specification TPM Main Part 2 TPM Structures Section 17. The + * values of the SHORT, MEDIUM, and LONG durations are retrieved + * from the chip during initialization with a call to tpm_get_timeouts. + */ +static const u8 tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL] = { + TPM_UNDEFINED, /* 0 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 5 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 10 */ + TPM_SHORT, +}; + +static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = { + TPM_UNDEFINED, /* 0 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 5 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 10 */ + TPM_SHORT, + TPM_MEDIUM, + TPM_LONG, + TPM_LONG, + TPM_MEDIUM, /* 15 */ + TPM_SHORT, + TPM_SHORT, + TPM_MEDIUM, + TPM_LONG, + TPM_SHORT, /* 20 */ + TPM_SHORT, + TPM_MEDIUM, + TPM_MEDIUM, + TPM_MEDIUM, + TPM_SHORT, /* 25 */ + TPM_SHORT, + TPM_MEDIUM, + TPM_SHORT, + TPM_SHORT, + TPM_MEDIUM, /* 30 */ + TPM_LONG, + TPM_MEDIUM, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, /* 35 */ + TPM_MEDIUM, + TPM_MEDIUM, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_MEDIUM, /* 40 */ + TPM_LONG, + TPM_MEDIUM, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, /* 45 */ + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_LONG, + TPM_MEDIUM, /* 50 */ + TPM_MEDIUM, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 55 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_MEDIUM, /* 60 */ + TPM_MEDIUM, + TPM_MEDIUM, + TPM_SHORT, + TPM_SHORT, + TPM_MEDIUM, /* 65 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 70 */ + TPM_SHORT, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 75 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_LONG, /* 80 */ + TPM_UNDEFINED, + TPM_MEDIUM, + TPM_LONG, + TPM_SHORT, + TPM_UNDEFINED, /* 85 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 90 */ + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_UNDEFINED, /* 95 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_MEDIUM, /* 100 */ + TPM_SHORT, + TPM_SHORT, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 105 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 110 */ + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, /* 115 */ + TPM_SHORT, + TPM_SHORT, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_LONG, /* 120 */ + TPM_LONG, + TPM_MEDIUM, + TPM_UNDEFINED, + TPM_SHORT, + TPM_SHORT, /* 125 */ + TPM_SHORT, + TPM_LONG, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, /* 130 */ + TPM_MEDIUM, + TPM_UNDEFINED, + TPM_SHORT, + TPM_MEDIUM, + TPM_UNDEFINED, /* 135 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 140 */ + TPM_SHORT, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 145 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 150 */ + TPM_MEDIUM, + TPM_MEDIUM, + TPM_SHORT, + TPM_SHORT, + TPM_UNDEFINED, /* 155 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 160 */ + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 165 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_LONG, /* 170 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 175 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_MEDIUM, /* 180 */ + TPM_SHORT, + TPM_MEDIUM, + TPM_MEDIUM, + TPM_MEDIUM, + TPM_MEDIUM, /* 185 */ + TPM_SHORT, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 190 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 195 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 200 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, + TPM_SHORT, /* 205 */ + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_MEDIUM, /* 210 */ + TPM_UNDEFINED, + TPM_MEDIUM, + TPM_MEDIUM, + TPM_MEDIUM, + TPM_UNDEFINED, /* 215 */ + TPM_MEDIUM, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, + TPM_SHORT, /* 220 */ + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_UNDEFINED, /* 225 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 230 */ + TPM_LONG, + TPM_MEDIUM, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 235 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 240 */ + TPM_UNDEFINED, + TPM_MEDIUM, +}; + static void user_reader_timeout(unsigned long ptr) { struct tpm_chip *chip = (struct tpm_chip *) ptr; @@ -56,6 +336,32 @@ static void timeout_work(void *ptr) up(&chip->buffer_mutex); } +/* + * Returns max number of jiffies to wait + */ +unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, + u32 ordinal) +{ + int duration_idx = TPM_UNDEFINED; + int duration = 0; + + if (ordinal < TPM_MAX_ORDINAL) + duration_idx = tpm_ordinal_duration[ordinal]; + else if ((ordinal & TPM_PROTECTED_ORDINAL_MASK) < + TPM_MAX_PROTECTED_ORDINAL) + duration_idx = + tpm_protected_ordinal_duration[ordinal & + TPM_PROTECTED_ORDINAL_MASK]; + + if (duration_idx != TPM_UNDEFINED) + duration = chip->vendor.duration[duration_idx] * HZ / 1000; + if (duration <= 0) + return 2 * 60 * HZ; + else + return duration; +} +EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration); + /* * Internal kernel interface to transmit TPM commands */ @@ -63,11 +369,11 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, size_t bufsiz) { ssize_t rc; - u32 count; + u32 count, ordinal; unsigned long stop; count = be32_to_cpu(*((__be32 *) (buf + 2))); - + ordinal = be32_to_cpu(*((__be32 *) (buf + 6))); if (count == 0) return -ENODATA; if (count > bufsiz) { @@ -84,7 +390,7 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, goto out; } - stop = jiffies + 2 * 60 * HZ; + stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal); do { u8 status = chip->vendor.status(chip); if ((status & chip->vendor.req_complete_mask) == diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 4f005345bf37..1d28485b8fb3 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -63,6 +63,7 @@ struct tpm_vendor_specific { u8 (*status) (struct tpm_chip *); struct miscdevice miscdev; struct attribute_group *attr_group; + u32 duration[3]; }; struct tpm_chip { @@ -100,6 +101,7 @@ static inline void tpm_write_index(int base, int index, int value) outb(value & 0xFF, base+1); } +extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32); extern struct tpm_chip* tpm_register_hardware(struct device *, const struct tpm_vendor_specific *); extern int tpm_open(struct inode *, struct file *); -- cgit v1.2.3 From 08e96e486dd1345ae0ad70247387d0d4fd346889 Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sat, 22 Apr 2006 02:37:50 -0700 Subject: [PATCH] tpm: new 1.2 sysfs files Many of the sysfs files were calling the TPM_GetCapability command with array. Since for 1.2 more sysfs files of this type are coming I am generalizing the array so there can be one array and the unique parts can be filled in just before the command is called. This updated version of the patch breaks the multi-value sysfs file into separate files pointed out by Greg. It also addresses the code redundancy and ugliness in the tpm_show_* functions pointed out on another patch by Dave Hansen. Signed-off-by: Kylene Hall Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm.c | 235 ++++++++++++++++++++++++++++++++++++++++++++++++- drivers/char/tpm/tpm.h | 14 +++ 2 files changed, 247 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index e54bcb4e4e3e..24c4423d4851 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -430,17 +430,27 @@ out: #define TPM_GET_CAP_RET_UINT32_2_IDX 18 #define TPM_GET_CAP_RET_UINT32_3_IDX 22 #define TPM_GET_CAP_RET_UINT32_4_IDX 26 +#define TPM_GET_CAP_PERM_DISABLE_IDX 16 +#define TPM_GET_CAP_PERM_INACTIVE_IDX 18 +#define TPM_GET_CAP_RET_BOOL_1_IDX 14 +#define TPM_GET_CAP_TEMP_INACTIVE_IDX 16 #define TPM_CAP_IDX 13 #define TPM_CAP_SUBCAP_IDX 21 enum tpm_capabilities { + TPM_CAP_FLAG = 4, TPM_CAP_PROP = 5, }; enum tpm_sub_capabilities { TPM_CAP_PROP_PCR = 0x1, TPM_CAP_PROP_MANUFACTURER = 0x3, + TPM_CAP_FLAG_PERM = 0x8, + TPM_CAP_FLAG_VOL = 0x9, + TPM_CAP_PROP_OWNER = 0x11, + TPM_CAP_PROP_TIS_TIMEOUT = 0x15, + TPM_CAP_PROP_TIS_DURATION = 0x20, }; /* @@ -474,6 +484,180 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, u8 *data, int len, return 0; } +void tpm_gen_interrupt(struct tpm_chip *chip) +{ + u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 30)]; + ssize_t rc; + + memcpy(data, tpm_cap, sizeof(tpm_cap)); + data[TPM_CAP_IDX] = TPM_CAP_PROP; + data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT; + + rc = transmit_cmd(chip, data, sizeof(data), + "attempting to determine the timeouts"); +} +EXPORT_SYMBOL_GPL(tpm_gen_interrupt); + +void tpm_get_timeouts(struct tpm_chip *chip) +{ + u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 30)]; + ssize_t rc; + u32 timeout; + + memcpy(data, tpm_cap, sizeof(tpm_cap)); + data[TPM_CAP_IDX] = TPM_CAP_PROP; + data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT; + + rc = transmit_cmd(chip, data, sizeof(data), + "attempting to determine the timeouts"); + if (rc) + goto duration; + + if (be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_SIZE_IDX))) + != 4 * sizeof(u32)) + goto duration; + + /* Don't overwrite default if value is 0 */ + timeout = + be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX))); + if (timeout) + chip->vendor.timeout_a = timeout; + timeout = + be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_2_IDX))); + if (timeout) + chip->vendor.timeout_b = timeout; + timeout = + be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_3_IDX))); + if (timeout) + chip->vendor.timeout_c = timeout; + timeout = + be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_4_IDX))); + if (timeout) + chip->vendor.timeout_d = timeout; + +duration: + memcpy(data, tpm_cap, sizeof(tpm_cap)); + data[TPM_CAP_IDX] = TPM_CAP_PROP; + data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_DURATION; + + rc = transmit_cmd(chip, data, sizeof(data), + "attempting to determine the durations"); + if (rc) + return; + + if (be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_SIZE_IDX))) + != 3 * sizeof(u32)) + return; + + chip->vendor.duration[TPM_SHORT] = + be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX))); + chip->vendor.duration[TPM_MEDIUM] = + be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_2_IDX))); + chip->vendor.duration[TPM_LONG] = + be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_3_IDX))); +} +EXPORT_SYMBOL_GPL(tpm_get_timeouts); + +void tpm_continue_selftest(struct tpm_chip *chip) +{ + u8 data[] = { + 0, 193, /* TPM_TAG_RQU_COMMAND */ + 0, 0, 0, 10, /* length */ + 0, 0, 0, 83, /* TPM_ORD_GetCapability */ + }; + + tpm_transmit(chip, data, sizeof(data)); +} +EXPORT_SYMBOL_GPL(tpm_continue_selftest); + +ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr, + char *buf) +{ + u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 35)]; + ssize_t rc; + + struct tpm_chip *chip = dev_get_drvdata(dev); + if (chip == NULL) + return -ENODEV; + + memcpy(data, tpm_cap, sizeof(tpm_cap)); + data[TPM_CAP_IDX] = TPM_CAP_FLAG; + data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM; + + rc = transmit_cmd(chip, data, sizeof(data), + "attemtping to determine the permanent state"); + if (rc) + return 0; + return sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_DISABLE_IDX]); +} +EXPORT_SYMBOL_GPL(tpm_show_enabled); + +ssize_t tpm_show_active(struct device * dev, struct device_attribute * attr, + char *buf) +{ + u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 35)]; + ssize_t rc; + + struct tpm_chip *chip = dev_get_drvdata(dev); + if (chip == NULL) + return -ENODEV; + + memcpy(data, tpm_cap, sizeof(tpm_cap)); + data[TPM_CAP_IDX] = TPM_CAP_FLAG; + data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM; + + rc = transmit_cmd(chip, data, sizeof(data), + "attemtping to determine the permanent state"); + if (rc) + return 0; + return sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_INACTIVE_IDX]); +} +EXPORT_SYMBOL_GPL(tpm_show_active); + +ssize_t tpm_show_owned(struct device * dev, struct device_attribute * attr, + char *buf) +{ + u8 data[sizeof(tpm_cap)]; + ssize_t rc; + + struct tpm_chip *chip = dev_get_drvdata(dev); + if (chip == NULL) + return -ENODEV; + + memcpy(data, tpm_cap, sizeof(tpm_cap)); + data[TPM_CAP_IDX] = TPM_CAP_PROP; + data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_OWNER; + + rc = transmit_cmd(chip, data, sizeof(data), + "attempting to determine the owner state"); + if (rc) + return 0; + return sprintf(buf, "%d\n", data[TPM_GET_CAP_RET_BOOL_1_IDX]); +} +EXPORT_SYMBOL_GPL(tpm_show_owned); + +ssize_t tpm_show_temp_deactivated(struct device * dev, + struct device_attribute * attr, char *buf) +{ + u8 data[sizeof(tpm_cap)]; + ssize_t rc; + + struct tpm_chip *chip = dev_get_drvdata(dev); + if (chip == NULL) + return -ENODEV; + + memcpy(data, tpm_cap, sizeof(tpm_cap)); + data[TPM_CAP_IDX] = TPM_CAP_FLAG; + data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_VOL; + + rc = transmit_cmd(chip, data, sizeof(data), + "attempting to determine the temporary state"); + if (rc) + return 0; + return sprintf(buf, "%d\n", data[TPM_GET_CAP_TEMP_INACTIVE_IDX]); +} +EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated); + static const u8 pcrread[] = { 0, 193, /* TPM_TAG_RQU_COMMAND */ 0, 0, 0, 14, /* length */ @@ -484,7 +668,7 @@ static const u8 pcrread[] = { ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, char *buf) { - u8 data[30]; + u8 data[max_t(int, max(ARRAY_SIZE(tpm_cap), ARRAY_SIZE(pcrread)), 30)]; ssize_t rc; int i, j, num_pcrs; __be32 index; @@ -588,6 +772,7 @@ out: EXPORT_SYMBOL_GPL(tpm_show_pubek); #define CAP_VERSION_1_1 6 +#define CAP_VERSION_1_2 0x1A #define CAP_VERSION_IDX 13 static const u8 cap_version[] = { 0, 193, /* TPM_TAG_RQU_COMMAND */ @@ -600,7 +785,7 @@ static const u8 cap_version[] = { ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, char *buf) { - u8 data[30]; + u8 data[max_t(int, max(ARRAY_SIZE(tpm_cap), ARRAY_SIZE(cap_version)), 30)]; ssize_t rc; char *str = buf; @@ -637,6 +822,52 @@ out: } EXPORT_SYMBOL_GPL(tpm_show_caps); +ssize_t tpm_show_caps_1_2(struct device * dev, + struct device_attribute * attr, char *buf) +{ + u8 data[max_t(int, max(ARRAY_SIZE(tpm_cap), ARRAY_SIZE(cap_version)), 30)]; + ssize_t len; + char *str = buf; + + struct tpm_chip *chip = dev_get_drvdata(dev); + if (chip == NULL) + return -ENODEV; + + memcpy(data, tpm_cap, sizeof(tpm_cap)); + data[TPM_CAP_IDX] = TPM_CAP_PROP; + data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER; + + if ((len = tpm_transmit(chip, data, sizeof(data))) <= + TPM_ERROR_SIZE) { + dev_dbg(chip->dev, "A TPM error (%d) occurred " + "attempting to determine the manufacturer\n", + be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX)))); + return 0; + } + + str += sprintf(str, "Manufacturer: 0x%x\n", + be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)))); + + memcpy(data, cap_version, sizeof(cap_version)); + data[CAP_VERSION_IDX] = CAP_VERSION_1_2; + + if ((len = tpm_transmit(chip, data, sizeof(data))) <= + TPM_ERROR_SIZE) { + dev_err(chip->dev, "A TPM error (%d) occurred " + "attempting to determine the 1.2 version\n", + be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX)))); + goto out; + } + str += sprintf(str, + "TCG version: %d.%d\nFirmware version: %d.%d\n", + (int) data[16], (int) data[17], (int) data[18], + (int) data[19]); + +out: + return str - buf; +} +EXPORT_SYMBOL_GPL(tpm_show_caps_1_2); + ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 1d28485b8fb3..75d105c4e65d 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -42,8 +42,18 @@ extern ssize_t tpm_show_pcrs(struct device *, struct device_attribute *attr, char *); extern ssize_t tpm_show_caps(struct device *, struct device_attribute *attr, char *); +extern ssize_t tpm_show_caps_1_2(struct device *, struct device_attribute *attr, + char *); extern ssize_t tpm_store_cancel(struct device *, struct device_attribute *attr, const char *, size_t); +extern ssize_t tpm_show_enabled(struct device *, struct device_attribute *attr, + char *); +extern ssize_t tpm_show_active(struct device *, struct device_attribute *attr, + char *); +extern ssize_t tpm_show_owned(struct device *, struct device_attribute *attr, + char *); +extern ssize_t tpm_show_temp_deactivated(struct device *, + struct device_attribute *attr, char *); struct tpm_chip; @@ -63,6 +73,7 @@ struct tpm_vendor_specific { u8 (*status) (struct tpm_chip *); struct miscdevice miscdev; struct attribute_group *attr_group; + u32 timeout_a, timeout_b, timeout_c, timeout_d; u32 duration[3]; }; @@ -101,6 +112,9 @@ static inline void tpm_write_index(int base, int index, int value) outb(value & 0xFF, base+1); } +extern void tpm_get_timeouts(struct tpm_chip *); +extern void tpm_gen_interrupt(struct tpm_chip *); +extern void tpm_continue_selftest(struct tpm_chip *); extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32); extern struct tpm_chip* tpm_register_hardware(struct device *, const struct tpm_vendor_specific *); -- cgit v1.2.3 From 27084efee0c3dc0eb15b5ed750aa9f1adb3983c3 Mon Sep 17 00:00:00 2001 From: Leendert van Doorn Date: Sat, 22 Apr 2006 02:38:03 -0700 Subject: [PATCH] tpm: driver for next generation TPM chips The driver for the next generation of TPM chips version 1.2 including support for interrupts. The Trusted Computing Group has written the TPM Interface Specification (TIS) which defines a common interface for all manufacturer's 1.2 TPM's thus the name tpm_tis. Signed-off-by: Leendert van Doorn Signed-off-by: Kylene Hall Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/Kconfig | 11 +- drivers/char/tpm/Makefile | 1 + drivers/char/tpm/tpm.c | 3 + drivers/char/tpm/tpm.h | 9 + drivers/char/tpm/tpm_tis.c | 647 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 670 insertions(+), 1 deletion(-) create mode 100644 drivers/char/tpm/tpm_tis.c (limited to 'drivers') diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index a6873bf89ffa..1efde3b27619 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -20,9 +20,18 @@ config TCG_TPM Note: For more TPM drivers enable CONFIG_PNP, CONFIG_ACPI and CONFIG_PNPACPI. +config TCG_TIS + tristate "TPM Interface Specification 1.2 Interface" + depends on TCG_TPM + ---help--- + If you have a TPM security chip that is compliant with the + TCG TIS 1.2 TPM specification say Yes and it will be accessible + from within Linux. To compile this driver as a module, choose + M here; the module will be called tpm_tis. + config TCG_NSC tristate "National Semiconductor TPM Interface" - depends on TCG_TPM + depends on TCG_TPM && PNPACPI ---help--- If you have a TPM security chip from National Semicondutor say Yes and it will be accessible from within Linux. To diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index ba4582d160fd..ea3a1e02a824 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_TCG_TPM) += tpm.o ifdef CONFIG_ACPI obj-$(CONFIG_TCG_TPM) += tpm_bios.o endif +obj-$(CONFIG_TCG_TIS) += tpm_tis.o obj-$(CONFIG_TCG_NSC) += tpm_nsc.o obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 24c4423d4851..150c86af7809 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -390,6 +390,9 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, goto out; } + if (chip->vendor.irq) + goto out_recv; + stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal); do { u8 status = chip->vendor.status(chip); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 75d105c4e65d..24541a556d02 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -64,6 +64,8 @@ struct tpm_vendor_specific { void __iomem *iobase; /* ioremapped address */ unsigned long base; /* TPM base address */ + int irq; + int region_size; int have_region; @@ -73,8 +75,13 @@ struct tpm_vendor_specific { u8 (*status) (struct tpm_chip *); struct miscdevice miscdev; struct attribute_group *attr_group; + struct list_head list; + int locality; u32 timeout_a, timeout_b, timeout_c, timeout_d; u32 duration[3]; + + wait_queue_head_t read_queue; + wait_queue_head_t int_queue; }; struct tpm_chip { @@ -100,6 +107,8 @@ struct tpm_chip { struct list_head list; }; +#define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor) + static inline int tpm_read_index(int base, int index) { outb(index, base); diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c new file mode 100644 index 000000000000..02759307f736 --- /dev/null +++ b/drivers/char/tpm/tpm_tis.c @@ -0,0 +1,647 @@ +/* + * Copyright (C) 2005, 2006 IBM Corporation + * + * Authors: + * Leendert van Doorn + * Kylene Hall + * + * Device driver for TCG/TCPA TPM (trusted platform module). + * Specifications at www.trustedcomputinggroup.org + * + * This device driver implements the TPM interface as defined in + * the TCG TPM Interface Spec version 1.2, revision 1.0. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + */ +#include +#include +#include +#include "tpm.h" + +#define TPM_HEADER_SIZE 10 + +enum tis_access { + TPM_ACCESS_VALID = 0x80, + TPM_ACCESS_ACTIVE_LOCALITY = 0x20, + TPM_ACCESS_REQUEST_PENDING = 0x04, + TPM_ACCESS_REQUEST_USE = 0x02, +}; + +enum tis_status { + TPM_STS_VALID = 0x80, + TPM_STS_COMMAND_READY = 0x40, + TPM_STS_GO = 0x20, + TPM_STS_DATA_AVAIL = 0x10, + TPM_STS_DATA_EXPECT = 0x08, +}; + +enum tis_int_flags { + TPM_GLOBAL_INT_ENABLE = 0x80000000, + TPM_INTF_BURST_COUNT_STATIC = 0x100, + TPM_INTF_CMD_READY_INT = 0x080, + TPM_INTF_INT_EDGE_FALLING = 0x040, + TPM_INTF_INT_EDGE_RISING = 0x020, + TPM_INTF_INT_LEVEL_LOW = 0x010, + TPM_INTF_INT_LEVEL_HIGH = 0x008, + TPM_INTF_LOCALITY_CHANGE_INT = 0x004, + TPM_INTF_STS_VALID_INT = 0x002, + TPM_INTF_DATA_AVAIL_INT = 0x001, +}; + +#define TPM_ACCESS(l) (0x0000 | ((l) << 12)) +#define TPM_INT_ENABLE(l) (0x0008 | ((l) << 12)) +#define TPM_INT_VECTOR(l) (0x000C | ((l) << 12)) +#define TPM_INT_STATUS(l) (0x0010 | ((l) << 12)) +#define TPM_INTF_CAPS(l) (0x0014 | ((l) << 12)) +#define TPM_STS(l) (0x0018 | ((l) << 12)) +#define TPM_DATA_FIFO(l) (0x0024 | ((l) << 12)) + +#define TPM_DID_VID(l) (0x0F00 | ((l) << 12)) +#define TPM_RID(l) (0x0F04 | ((l) << 12)) + +static LIST_HEAD(tis_chips); +static DEFINE_SPINLOCK(tis_lock); + +static int check_locality(struct tpm_chip *chip, int l) +{ + if ((ioread8(chip->vendor.iobase + TPM_ACCESS(l)) & + (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) == + (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) + return chip->vendor.locality = l; + + return -1; +} + +static void release_locality(struct tpm_chip *chip, int l, int force) +{ + if (force || (ioread8(chip->vendor.iobase + TPM_ACCESS(l)) & + (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) == + (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) + iowrite8(TPM_ACCESS_ACTIVE_LOCALITY, + chip->vendor.iobase + TPM_ACCESS(l)); +} + +static int request_locality(struct tpm_chip *chip, int l) +{ + unsigned long stop; + long rc; + + if (check_locality(chip, l) >= 0) + return l; + + iowrite8(TPM_ACCESS_REQUEST_USE, + chip->vendor.iobase + TPM_ACCESS(l)); + + if (chip->vendor.irq) { + rc = wait_event_interruptible_timeout(chip->vendor. + int_queue, + (check_locality + (chip, l) >= 0), + msecs_to_jiffies + (chip->vendor. + timeout_a)); + if (rc > 0) + return l; + + } else { + /* wait for burstcount */ + stop = jiffies + (HZ * chip->vendor.timeout_a / 1000); + do { + if (check_locality(chip, l) >= 0) + return l; + msleep(TPM_TIMEOUT); + } + while (time_before(jiffies, stop)); + } + return -1; +} + +static u8 tpm_tis_status(struct tpm_chip *chip) +{ + return ioread8(chip->vendor.iobase + + TPM_STS(chip->vendor.locality)); +} + +static void tpm_tis_ready(struct tpm_chip *chip) +{ + /* this causes the current command to be aborted */ + iowrite8(TPM_STS_COMMAND_READY, + chip->vendor.iobase + TPM_STS(chip->vendor.locality)); +} + +static int get_burstcount(struct tpm_chip *chip) +{ + unsigned long stop; + int burstcnt; + + /* wait for burstcount */ + /* which timeout value, spec has 2 answers (c & d) */ + stop = jiffies + (HZ * chip->vendor.timeout_d / 1000); + do { + burstcnt = ioread8(chip->vendor.iobase + + TPM_STS(chip->vendor.locality) + 1); + burstcnt += ioread8(chip->vendor.iobase + + TPM_STS(chip->vendor.locality) + + 2) << 8; + if (burstcnt) + return burstcnt; + msleep(TPM_TIMEOUT); + } while (time_before(jiffies, stop)); + return -EBUSY; +} + +static int wait_for_stat(struct tpm_chip *chip, u8 mask, u32 timeout, + wait_queue_head_t *queue) +{ + unsigned long stop; + long rc; + u8 status; + + /* check current status */ + status = tpm_tis_status(chip); + if ((status & mask) == mask) + return 0; + + if (chip->vendor.irq) { + rc = wait_event_interruptible_timeout(*queue, + ((tpm_tis_status + (chip) & mask) == + mask), + msecs_to_jiffies + (timeout)); + if (rc > 0) + return 0; + } else { + stop = jiffies + (HZ * timeout / 1000); + do { + msleep(TPM_TIMEOUT); + status = tpm_tis_status(chip); + if ((status & mask) == mask) + return 0; + } while (time_before(jiffies, stop)); + } + return -ETIME; +} + +static int recv_data(struct tpm_chip *chip, u8 * buf, size_t count) +{ + int size = 0, burstcnt; + while (size < count && + wait_for_stat(chip, + TPM_STS_DATA_AVAIL | TPM_STS_VALID, + chip->vendor.timeout_c, + &chip->vendor.read_queue) + == 0) { + burstcnt = get_burstcount(chip); + for (; burstcnt > 0 && size < count; burstcnt--) + buf[size++] = ioread8(chip->vendor.iobase + + TPM_DATA_FIFO(chip->vendor. + locality)); + } + return size; +} + +static int tpm_tis_recv(struct tpm_chip *chip, u8 * buf, size_t count) +{ + int size = 0; + int expected, status; + + if (count < TPM_HEADER_SIZE) { + size = -EIO; + goto out; + } + + /* read first 10 bytes, including tag, paramsize, and result */ + if ((size = + recv_data(chip, buf, TPM_HEADER_SIZE)) < TPM_HEADER_SIZE) { + dev_err(chip->dev, "Unable to read header\n"); + goto out; + } + + expected = be32_to_cpu(*(__be32 *) (buf + 2)); + if (expected > count) { + size = -EIO; + goto out; + } + + if ((size += + recv_data(chip, &buf[TPM_HEADER_SIZE], + expected - TPM_HEADER_SIZE)) < expected) { + dev_err(chip->dev, "Unable to read remainder of result\n"); + size = -ETIME; + goto out; + } + + wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, + &chip->vendor.int_queue); + status = tpm_tis_status(chip); + if (status & TPM_STS_DATA_AVAIL) { /* retry? */ + dev_err(chip->dev, "Error left over data\n"); + size = -EIO; + goto out; + } + +out: + tpm_tis_ready(chip); + release_locality(chip, chip->vendor.locality, 0); + return size; +} + +/* + * If interrupts are used (signaled by an irq set in the vendor structure) + * tpm.c can skip polling for the data to be available as the interrupt is + * waited for here + */ +static int tpm_tis_send(struct tpm_chip *chip, u8 * buf, size_t len) +{ + int rc, status, burstcnt; + size_t count = 0; + u32 ordinal; + + if (request_locality(chip, 0) < 0) + return -EBUSY; + + status = tpm_tis_status(chip); + if ((status & TPM_STS_COMMAND_READY) == 0) { + tpm_tis_ready(chip); + if (wait_for_stat + (chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b, + &chip->vendor.int_queue) < 0) { + rc = -ETIME; + goto out_err; + } + } + + while (count < len - 1) { + burstcnt = get_burstcount(chip); + for (; burstcnt > 0 && count < len - 1; burstcnt--) { + iowrite8(buf[count], chip->vendor.iobase + + TPM_DATA_FIFO(chip->vendor.locality)); + count++; + } + + wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, + &chip->vendor.int_queue); + status = tpm_tis_status(chip); + if ((status & TPM_STS_DATA_EXPECT) == 0) { + rc = -EIO; + goto out_err; + } + } + + /* write last byte */ + iowrite8(buf[count], + chip->vendor.iobase + + TPM_DATA_FIFO(chip->vendor.locality)); + wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, + &chip->vendor.int_queue); + status = tpm_tis_status(chip); + if ((status & TPM_STS_DATA_EXPECT) != 0) { + rc = -EIO; + goto out_err; + } + + /* go and do it */ + iowrite8(TPM_STS_GO, + chip->vendor.iobase + TPM_STS(chip->vendor.locality)); + + if (chip->vendor.irq) { + ordinal = be32_to_cpu(*((__be32 *) (buf + 6))); + if (wait_for_stat + (chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, + tpm_calc_ordinal_duration(chip, ordinal), + &chip->vendor.read_queue) < 0) { + rc = -ETIME; + goto out_err; + } + } + return len; +out_err: + tpm_tis_ready(chip); + release_locality(chip, chip->vendor.locality, 0); + return rc; +} + +static struct file_operations tis_ops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .open = tpm_open, + .read = tpm_read, + .write = tpm_write, + .release = tpm_release, +}; + +static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); +static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); +static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL); +static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); +static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); +static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, + NULL); +static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL); +static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); + +static struct attribute *tis_attrs[] = { + &dev_attr_pubek.attr, + &dev_attr_pcrs.attr, + &dev_attr_enabled.attr, + &dev_attr_active.attr, + &dev_attr_owned.attr, + &dev_attr_temp_deactivated.attr, + &dev_attr_caps.attr, + &dev_attr_cancel.attr, NULL, +}; + +static struct attribute_group tis_attr_grp = { + .attrs = tis_attrs +}; + +static struct tpm_vendor_specific tpm_tis = { + .status = tpm_tis_status, + .recv = tpm_tis_recv, + .send = tpm_tis_send, + .cancel = tpm_tis_ready, + .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, + .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, + .req_canceled = TPM_STS_COMMAND_READY, + .attr_group = &tis_attr_grp, + .miscdev = { + .fops = &tis_ops,}, +}; + +static irqreturn_t tis_int_probe(int irq, void *dev_id, struct pt_regs + *regs) +{ + struct tpm_chip *chip = (struct tpm_chip *) dev_id; + u32 interrupt; + + interrupt = ioread32(chip->vendor.iobase + + TPM_INT_STATUS(chip->vendor.locality)); + + if (interrupt == 0) + return IRQ_NONE; + + chip->vendor.irq = irq; + + /* Clear interrupts handled with TPM_EOI */ + iowrite32(interrupt, + chip->vendor.iobase + + TPM_INT_STATUS(chip->vendor.locality)); + return IRQ_HANDLED; +} + +static irqreturn_t tis_int_handler(int irq, void *dev_id, struct pt_regs + *regs) +{ + struct tpm_chip *chip = (struct tpm_chip *) dev_id; + u32 interrupt; + int i; + + interrupt = ioread32(chip->vendor.iobase + + TPM_INT_STATUS(chip->vendor.locality)); + + if (interrupt == 0) + return IRQ_NONE; + + if (interrupt & TPM_INTF_DATA_AVAIL_INT) + wake_up_interruptible(&chip->vendor.read_queue); + if (interrupt & TPM_INTF_LOCALITY_CHANGE_INT) + for (i = 0; i < 5; i++) + if (check_locality(chip, i) >= 0) + break; + if (interrupt & + (TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_STS_VALID_INT | + TPM_INTF_CMD_READY_INT)) + wake_up_interruptible(&chip->vendor.int_queue); + + /* Clear interrupts handled with TPM_EOI */ + iowrite32(interrupt, + chip->vendor.iobase + + TPM_INT_STATUS(chip->vendor.locality)); + return IRQ_HANDLED; +} + +static int __devinit tpm_tis_pnp_init(struct pnp_dev + *pnp_dev, const struct + pnp_device_id + *pnp_id) +{ + u32 vendor, intfcaps, intmask; + int rc, i; + unsigned long start, len; + struct tpm_chip *chip; + + start = pnp_mem_start(pnp_dev, 0); + len = pnp_mem_len(pnp_dev, 0); + + if (!(chip = tpm_register_hardware(&pnp_dev->dev, &tpm_tis))) + return -ENODEV; + + chip->vendor.iobase = ioremap(start, len); + if (!chip->vendor.iobase) { + rc = -EIO; + goto out_err; + } + + vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0)); + if ((vendor & 0xFFFF) == 0xFFFF) { + rc = -ENODEV; + goto out_err; + } + + /* Default timeouts */ + chip->vendor.timeout_a = 750; /* ms */ + chip->vendor.timeout_b = 2000; /* 2 sec */ + chip->vendor.timeout_c = 750; /* ms */ + chip->vendor.timeout_d = 750; /* ms */ + + dev_info(&pnp_dev->dev, + "1.2 TPM (device-id 0x%X, rev-id %d)\n", + vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0))); + + /* Figure out the capabilities */ + intfcaps = + ioread32(chip->vendor.iobase + + TPM_INTF_CAPS(chip->vendor.locality)); + dev_dbg(&pnp_dev->dev, "TPM interface capabilities (0x%x):\n", + intfcaps); + if (intfcaps & TPM_INTF_BURST_COUNT_STATIC) + dev_dbg(&pnp_dev->dev, "\tBurst Count Static\n"); + if (intfcaps & TPM_INTF_CMD_READY_INT) + dev_dbg(&pnp_dev->dev, "\tCommand Ready Int Support\n"); + if (intfcaps & TPM_INTF_INT_EDGE_FALLING) + dev_dbg(&pnp_dev->dev, "\tInterrupt Edge Falling\n"); + if (intfcaps & TPM_INTF_INT_EDGE_RISING) + dev_dbg(&pnp_dev->dev, "\tInterrupt Edge Rising\n"); + if (intfcaps & TPM_INTF_INT_LEVEL_LOW) + dev_dbg(&pnp_dev->dev, "\tInterrupt Level Low\n"); + if (intfcaps & TPM_INTF_INT_LEVEL_HIGH) + dev_dbg(&pnp_dev->dev, "\tInterrupt Level High\n"); + if (intfcaps & TPM_INTF_LOCALITY_CHANGE_INT) + dev_dbg(&pnp_dev->dev, "\tLocality Change Int Support\n"); + if (intfcaps & TPM_INTF_STS_VALID_INT) + dev_dbg(&pnp_dev->dev, "\tSts Valid Int Support\n"); + if (intfcaps & TPM_INTF_DATA_AVAIL_INT) + dev_dbg(&pnp_dev->dev, "\tData Avail Int Support\n"); + + if (request_locality(chip, 0) != 0) { + rc = -ENODEV; + goto out_err; + } + + /* INTERRUPT Setup */ + init_waitqueue_head(&chip->vendor.read_queue); + init_waitqueue_head(&chip->vendor.int_queue); + + intmask = + ioread32(chip->vendor.iobase + + TPM_INT_ENABLE(chip->vendor.locality)); + + intmask |= TPM_INTF_CMD_READY_INT + | TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_DATA_AVAIL_INT + | TPM_INTF_STS_VALID_INT; + + iowrite32(intmask, + chip->vendor.iobase + + TPM_INT_ENABLE(chip->vendor.locality)); + + chip->vendor.irq = + ioread8(chip->vendor.iobase + + TPM_INT_VECTOR(chip->vendor.locality)); + + for (i = 3; i < 16 && chip->vendor.irq == 0; i++) { + iowrite8(i, + chip->vendor.iobase + + TPM_INT_VECTOR(chip->vendor.locality)); + if (request_irq + (i, tis_int_probe, SA_SHIRQ, + chip->vendor.miscdev.name, chip) != 0) { + dev_info(chip->dev, + "Unable to request irq: %d for probe\n", + i); + continue; + } + + /* Clear all existing */ + iowrite32(ioread32 + (chip->vendor.iobase + + TPM_INT_STATUS(chip->vendor.locality)), + chip->vendor.iobase + + TPM_INT_STATUS(chip->vendor.locality)); + + /* Turn on */ + iowrite32(intmask | TPM_GLOBAL_INT_ENABLE, + chip->vendor.iobase + + TPM_INT_ENABLE(chip->vendor.locality)); + + /* Generate Interrupts */ + tpm_gen_interrupt(chip); + + /* Turn off */ + iowrite32(intmask, + chip->vendor.iobase + + TPM_INT_ENABLE(chip->vendor.locality)); + free_irq(i, chip); + } + if (chip->vendor.irq) { + iowrite8(chip->vendor.irq, + chip->vendor.iobase + + TPM_INT_VECTOR(chip->vendor.locality)); + if (request_irq + (chip->vendor.irq, tis_int_handler, SA_SHIRQ, + chip->vendor.miscdev.name, chip) != 0) { + dev_info(chip->dev, + "Unable to request irq: %d for use\n", i); + chip->vendor.irq = 0; + } else { + /* Clear all existing */ + iowrite32(ioread32 + (chip->vendor.iobase + + TPM_INT_STATUS(chip->vendor.locality)), + chip->vendor.iobase + + TPM_INT_STATUS(chip->vendor.locality)); + + /* Turn on */ + iowrite32(intmask | TPM_GLOBAL_INT_ENABLE, + chip->vendor.iobase + + TPM_INT_ENABLE(chip->vendor.locality)); + } + } + + INIT_LIST_HEAD(&chip->vendor.list); + spin_lock(&tis_lock); + list_add(&chip->vendor.list, &tis_chips); + spin_unlock(&tis_lock); + + tpm_get_timeouts(chip); + tpm_continue_selftest(chip); + + return 0; +out_err: + if (chip->vendor.iobase) + iounmap(chip->vendor.iobase); + tpm_remove_hardware(chip->dev); + return rc; +} + +static int tpm_tis_pnp_suspend(struct pnp_dev *dev, pm_message_t msg) +{ + return tpm_pm_suspend(&dev->dev, msg); +} + +static int tpm_tis_pnp_resume(struct pnp_dev *dev) +{ + return tpm_pm_resume(&dev->dev); +} + +static struct pnp_device_id tpm_pnp_tbl[] __devinitdata = { + {"PNP0C31", 0}, /* TPM */ + {"", 0} +}; + +static struct pnp_driver tis_pnp_driver = { + .name = "tpm_tis", + .id_table = tpm_pnp_tbl, + .probe = tpm_tis_pnp_init, + .suspend = tpm_tis_pnp_suspend, + .resume = tpm_tis_pnp_resume, +}; + +static int __init init_tis(void) +{ + return pnp_register_driver(&tis_pnp_driver); +} + +static void __exit cleanup_tis(void) +{ + struct tpm_vendor_specific *i, *j; + struct tpm_chip *chip; + spin_lock(&tis_lock); + list_for_each_entry_safe(i, j, &tis_chips, list) { + chip = to_tpm_chip(i); + iowrite32(~TPM_GLOBAL_INT_ENABLE & + ioread32(chip->vendor.iobase + + TPM_INT_ENABLE(chip->vendor. + locality)), + chip->vendor.iobase + + TPM_INT_ENABLE(chip->vendor.locality)); + release_locality(chip, chip->vendor.locality, 1); + if (chip->vendor.irq) + free_irq(chip->vendor.irq, chip); + iounmap(i->iobase); + list_del(&i->list); + tpm_remove_hardware(chip->dev); + } + spin_unlock(&tis_lock); + pnp_unregister_driver(&tis_pnp_driver); +} + +module_init(init_tis); +module_exit(cleanup_tis); +MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)"); +MODULE_DESCRIPTION("TPM Driver"); +MODULE_VERSION("2.0"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 36b20020e537036c4f9eb5b69140c88ead5da7dc Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sat, 22 Apr 2006 02:38:19 -0700 Subject: [PATCH] tpm: msecs_to_jiffies cleanups The timeout and duration values used in the tpm driver are not exposed to userspace. This patch converts the storage units to jiffies with msecs_to_jiffies. They were always being used in jiffies so this simplifies things removing the need for calculation all over the place. The change necessitated a type change in the tpm_chip struct to hold jiffies. Signed-off-by: Kylie Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm.c | 22 ++++++++++++++-------- drivers/char/tpm/tpm.h | 4 ++-- drivers/char/tpm/tpm_tis.c | 32 ++++++++++++++++---------------- 3 files changed, 32 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 150c86af7809..160dc080d580 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -354,7 +354,7 @@ unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, TPM_PROTECTED_ORDINAL_MASK]; if (duration_idx != TPM_UNDEFINED) - duration = chip->vendor.duration[duration_idx] * HZ / 1000; + duration = chip->vendor.duration[duration_idx]; if (duration <= 0) return 2 * 60 * HZ; else @@ -524,19 +524,19 @@ void tpm_get_timeouts(struct tpm_chip *chip) timeout = be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX))); if (timeout) - chip->vendor.timeout_a = timeout; + chip->vendor.timeout_a = msecs_to_jiffies(timeout); timeout = be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_2_IDX))); if (timeout) - chip->vendor.timeout_b = timeout; + chip->vendor.timeout_b = msecs_to_jiffies(timeout); timeout = be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_3_IDX))); if (timeout) - chip->vendor.timeout_c = timeout; + chip->vendor.timeout_c = msecs_to_jiffies(timeout); timeout = be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_4_IDX))); if (timeout) - chip->vendor.timeout_d = timeout; + chip->vendor.timeout_d = msecs_to_jiffies(timeout); duration: memcpy(data, tpm_cap, sizeof(tpm_cap)); @@ -553,11 +553,17 @@ duration: return; chip->vendor.duration[TPM_SHORT] = - be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX))); + msecs_to_jiffies(be32_to_cpu + (*((__be32 *) (data + + TPM_GET_CAP_RET_UINT32_1_IDX)))); chip->vendor.duration[TPM_MEDIUM] = - be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_2_IDX))); + msecs_to_jiffies(be32_to_cpu + (*((__be32 *) (data + + TPM_GET_CAP_RET_UINT32_2_IDX)))); chip->vendor.duration[TPM_LONG] = - be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_3_IDX))); + msecs_to_jiffies(be32_to_cpu + (*((__be32 *) (data + + TPM_GET_CAP_RET_UINT32_3_IDX)))); } EXPORT_SYMBOL_GPL(tpm_get_timeouts); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 24541a556d02..54a4c804e25f 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -77,8 +77,8 @@ struct tpm_vendor_specific { struct attribute_group *attr_group; struct list_head list; int locality; - u32 timeout_a, timeout_b, timeout_c, timeout_d; - u32 duration[3]; + unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* jiffies */ + unsigned long duration[3]; /* jiffies */ wait_queue_head_t read_queue; wait_queue_head_t int_queue; diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 02759307f736..1cb5a7f0755d 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -51,6 +51,11 @@ enum tis_int_flags { TPM_INTF_DATA_AVAIL_INT = 0x001, }; +enum tis_defaults { + TIS_SHORT_TIMEOUT = 750, /* ms */ + TIS_LONG_TIMEOUT = 2000, /* 2 sec */ +}; + #define TPM_ACCESS(l) (0x0000 | ((l) << 12)) #define TPM_INT_ENABLE(l) (0x0008 | ((l) << 12)) #define TPM_INT_VECTOR(l) (0x000C | ((l) << 12)) @@ -96,19 +101,16 @@ static int request_locality(struct tpm_chip *chip, int l) chip->vendor.iobase + TPM_ACCESS(l)); if (chip->vendor.irq) { - rc = wait_event_interruptible_timeout(chip->vendor. - int_queue, + rc = wait_event_interruptible_timeout(chip->vendor.int_queue, (check_locality (chip, l) >= 0), - msecs_to_jiffies - (chip->vendor. - timeout_a)); + chip->vendor.timeout_a); if (rc > 0) return l; } else { /* wait for burstcount */ - stop = jiffies + (HZ * chip->vendor.timeout_a / 1000); + stop = jiffies + chip->vendor.timeout_a; do { if (check_locality(chip, l) >= 0) return l; @@ -139,7 +141,7 @@ static int get_burstcount(struct tpm_chip *chip) /* wait for burstcount */ /* which timeout value, spec has 2 answers (c & d) */ - stop = jiffies + (HZ * chip->vendor.timeout_d / 1000); + stop = jiffies + chip->vendor.timeout_d; do { burstcnt = ioread8(chip->vendor.iobase + TPM_STS(chip->vendor.locality) + 1); @@ -153,7 +155,7 @@ static int get_burstcount(struct tpm_chip *chip) return -EBUSY; } -static int wait_for_stat(struct tpm_chip *chip, u8 mask, u32 timeout, +static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, wait_queue_head_t *queue) { unsigned long stop; @@ -169,13 +171,11 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, u32 timeout, rc = wait_event_interruptible_timeout(*queue, ((tpm_tis_status (chip) & mask) == - mask), - msecs_to_jiffies - (timeout)); + mask), timeout); if (rc > 0) return 0; } else { - stop = jiffies + (HZ * timeout / 1000); + stop = jiffies + timeout; do { msleep(TPM_TIMEOUT); status = tpm_tis_status(chip); @@ -453,10 +453,10 @@ static int __devinit tpm_tis_pnp_init(struct pnp_dev } /* Default timeouts */ - chip->vendor.timeout_a = 750; /* ms */ - chip->vendor.timeout_b = 2000; /* 2 sec */ - chip->vendor.timeout_c = 750; /* ms */ - chip->vendor.timeout_d = 750; /* ms */ + chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); + chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT); + chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT); + chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); dev_info(&pnp_dev->dev, "1.2 TPM (device-id 0x%X, rev-id %d)\n", -- cgit v1.2.3 From 10685a95301d02fde2b10f6047e405c69d2af82a Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sat, 22 Apr 2006 02:38:32 -0700 Subject: [PATCH] tpm: use clear_bit Use set_bit() and clear_bit() for dev_mask manipulation. Signed-off-by: Kylie Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm.c | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 160dc080d580..6889e7db3aff 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -32,7 +32,6 @@ enum tpm_const { TPM_MINOR = 224, /* officially assigned */ TPM_BUFSIZE = 2048, TPM_NUM_DEVICES = 256, - TPM_NUM_MASK_ENTRIES = TPM_NUM_DEVICES / (8 * sizeof(int)) }; enum tpm_duration { @@ -48,7 +47,7 @@ enum tpm_duration { static LIST_HEAD(tpm_chip_list); static DEFINE_SPINLOCK(driver_lock); -static int dev_mask[TPM_NUM_MASK_ENTRIES]; +static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES); /* * Array with one entry per ordinal defining the maximum amount @@ -1038,8 +1037,7 @@ void tpm_remove_hardware(struct device *dev) sysfs_remove_group(&dev->kobj, chip->vendor.attr_group); tpm_bios_log_teardown(chip->bios_dir); - dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES] &= - ~(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES)); + clear_bit(chip->dev_num, dev_mask); kfree(chip); @@ -1097,7 +1095,6 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend char *devname; struct tpm_chip *chip; - int i, j; /* Driver specific per-device data */ chip = kzalloc(sizeof(*chip), GFP_KERNEL); @@ -1116,19 +1113,9 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend memcpy(&chip->vendor, entry, sizeof(struct tpm_vendor_specific)); - chip->dev_num = -1; + chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES); - for (i = 0; i < TPM_NUM_MASK_ENTRIES; i++) - for (j = 0; j < 8 * sizeof(int); j++) - if ((dev_mask[i] & (1 << j)) == 0) { - chip->dev_num = - i * TPM_NUM_MASK_ENTRIES + j; - dev_mask[i] |= 1 << j; - goto dev_num_search_complete; - } - -dev_num_search_complete: - if (chip->dev_num < 0) { + if (chip->dev_num >= TPM_NUM_DEVICES) { dev_err(dev, "No available tpm device numbers\n"); kfree(chip); return NULL; @@ -1137,6 +1124,8 @@ dev_num_search_complete: else chip->vendor.miscdev.minor = MISC_DYNAMIC_MINOR; + set_bit(chip->dev_num, dev_mask); + devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL); scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num); chip->vendor.miscdev.name = devname; @@ -1150,8 +1139,8 @@ dev_num_search_complete: chip->vendor.miscdev.name, chip->vendor.miscdev.minor); put_device(dev); + clear_bit(chip->dev_num, dev_mask); kfree(chip); - dev_mask[i] &= !(1 << j); return NULL; } -- cgit v1.2.3 From e496f540540f0a0bffcc3f83785f9954dacf1b83 Mon Sep 17 00:00:00 2001 From: Marcel Selhorst Date: Sat, 22 Apr 2006 02:38:42 -0700 Subject: [PATCH] tpm: tpm_infineon updated to latest interface changes Apply the latest changes in the TPM interface to the Infineon TPM-driver. Signed-off-by: Marcel Selhorst Acked-by: Kylie Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm_infineon.c | 58 ++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c index 24095f6ee6da..90cae8f9fe21 100644 --- a/drivers/char/tpm/tpm_infineon.c +++ b/drivers/char/tpm/tpm_infineon.c @@ -104,7 +104,7 @@ static int empty_fifo(struct tpm_chip *chip, int clear_wrfifo) if (clear_wrfifo) { for (i = 0; i < 4096; i++) { - status = inb(chip->vendor->base + WRFIFO); + status = inb(chip->vendor.base + WRFIFO); if (status == 0xff) { if (check == 5) break; @@ -124,8 +124,8 @@ static int empty_fifo(struct tpm_chip *chip, int clear_wrfifo) */ i = 0; do { - status = inb(chip->vendor->base + RDFIFO); - status = inb(chip->vendor->base + STAT); + status = inb(chip->vendor.base + RDFIFO); + status = inb(chip->vendor.base + STAT); i++; if (i == TPM_MAX_TRIES) return -EIO; @@ -138,7 +138,7 @@ static int wait(struct tpm_chip *chip, int wait_for_bit) int status; int i; for (i = 0; i < TPM_MAX_TRIES; i++) { - status = inb(chip->vendor->base + STAT); + status = inb(chip->vendor.base + STAT); /* check the status-register if wait_for_bit is set */ if (status & 1 << wait_for_bit) break; @@ -157,7 +157,7 @@ static int wait(struct tpm_chip *chip, int wait_for_bit) static void wait_and_send(struct tpm_chip *chip, u8 sendbyte) { wait(chip, STAT_XFE); - outb(sendbyte, chip->vendor->base + WRFIFO); + outb(sendbyte, chip->vendor.base + WRFIFO); } /* Note: WTX means Waiting-Time-Extension. Whenever the TPM needs more @@ -204,7 +204,7 @@ recv_begin: ret = wait(chip, STAT_RDA); if (ret) return -EIO; - buf[i] = inb(chip->vendor->base + RDFIFO); + buf[i] = inb(chip->vendor.base + RDFIFO); } if (buf[0] != TPM_VL_VER) { @@ -219,7 +219,7 @@ recv_begin: for (i = 0; i < size; i++) { wait(chip, STAT_RDA); - buf[i] = inb(chip->vendor->base + RDFIFO); + buf[i] = inb(chip->vendor.base + RDFIFO); } if ((size == 0x6D00) && (buf[1] == 0x80)) { @@ -268,7 +268,7 @@ static int tpm_inf_send(struct tpm_chip *chip, u8 * buf, size_t count) u8 count_high, count_low, count_4, count_3, count_2, count_1; /* Disabling Reset, LP and IRQC */ - outb(RESET_LP_IRQC_DISABLE, chip->vendor->base + CMD); + outb(RESET_LP_IRQC_DISABLE, chip->vendor.base + CMD); ret = empty_fifo(chip, 1); if (ret) { @@ -319,7 +319,7 @@ static void tpm_inf_cancel(struct tpm_chip *chip) static u8 tpm_inf_status(struct tpm_chip *chip) { - return inb(chip->vendor->base + STAT); + return inb(chip->vendor.base + STAT); } static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); @@ -346,7 +346,7 @@ static struct file_operations inf_ops = { .release = tpm_release, }; -static struct tpm_vendor_specific tpm_inf = { +static const struct tpm_vendor_specific tpm_inf = { .recv = tpm_inf_recv, .send = tpm_inf_send, .cancel = tpm_inf_cancel, @@ -375,6 +375,7 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev, int version[2]; int productid[2]; char chipname[20]; + struct tpm_chip *chip; /* read IO-ports through PnP */ if (pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) && @@ -395,14 +396,13 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev, goto err_last; } /* publish my base address and request region */ - tpm_inf.base = TPM_INF_BASE; if (request_region - (tpm_inf.base, TPM_INF_PORT_LEN, "tpm_infineon0") == NULL) { + (TPM_INF_BASE, TPM_INF_PORT_LEN, "tpm_infineon0") == NULL) { rc = -EINVAL; goto err_last; } - if (request_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN, - "tpm_infineon0") == NULL) { + if (request_region + (TPM_INF_ADDR, TPM_INF_ADDR_LEN, "tpm_infineon0") == NULL) { rc = -EINVAL; goto err_last; } @@ -442,9 +442,9 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev, /* configure TPM with IO-ports */ outb(IOLIMH, TPM_INF_ADDR); - outb(((tpm_inf.base >> 8) & 0xff), TPM_INF_DATA); + outb(((TPM_INF_BASE >> 8) & 0xff), TPM_INF_DATA); outb(IOLIML, TPM_INF_ADDR); - outb((tpm_inf.base & 0xff), TPM_INF_DATA); + outb((TPM_INF_BASE & 0xff), TPM_INF_DATA); /* control if IO-ports are set correctly */ outb(IOLIMH, TPM_INF_ADDR); @@ -452,10 +452,10 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev, outb(IOLIML, TPM_INF_ADDR); iol = inb(TPM_INF_DATA); - if ((ioh << 8 | iol) != tpm_inf.base) { + if ((ioh << 8 | iol) != TPM_INF_BASE) { dev_err(&dev->dev, - "Could not set IO-ports to 0x%lx\n", - tpm_inf.base); + "Could not set IO-ports to 0x%x\n", + TPM_INF_BASE); rc = -EIO; goto err_release_region; } @@ -466,15 +466,15 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev, outb(DISABLE_REGISTER_PAIR, TPM_INF_ADDR); /* disable RESET, LP and IRQC */ - outb(RESET_LP_IRQC_DISABLE, tpm_inf.base + CMD); + outb(RESET_LP_IRQC_DISABLE, TPM_INF_BASE + CMD); /* Finally, we're done, print some infos */ dev_info(&dev->dev, "TPM found: " "config base 0x%x, " "io base 0x%x, " - "chip version %02x%02x, " - "vendor id %x%x (Infineon), " - "product id %02x%02x" + "chip version 0x%02x%02x, " + "vendor id 0x%x%x (Infineon), " + "product id 0x%02x%02x" "%s\n", TPM_INF_ADDR, TPM_INF_BASE, @@ -482,11 +482,10 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev, vendorid[0], vendorid[1], productid[0], productid[1], chipname); - rc = tpm_register_hardware(&dev->dev, &tpm_inf); - if (rc < 0) { - rc = -ENODEV; + if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf))) { goto err_release_region; } + chip->vendor.base = TPM_INF_BASE; return 0; } else { rc = -ENODEV; @@ -494,7 +493,7 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev, } err_release_region: - release_region(tpm_inf.base, TPM_INF_PORT_LEN); + release_region(TPM_INF_BASE, TPM_INF_PORT_LEN); release_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN); err_last: @@ -506,7 +505,8 @@ static __devexit void tpm_inf_pnp_remove(struct pnp_dev *dev) struct tpm_chip *chip = pnp_get_drvdata(dev); if (chip) { - release_region(chip->vendor->base, TPM_INF_PORT_LEN); + release_region(TPM_INF_BASE, TPM_INF_PORT_LEN); + release_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN); tpm_remove_hardware(chip->dev); } } @@ -538,5 +538,5 @@ module_exit(cleanup_inf); MODULE_AUTHOR("Marcel Selhorst "); MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2"); -MODULE_VERSION("1.7"); +MODULE_VERSION("1.8"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From b09d53009db21228adde29b468eb4583e66cbe7c Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sat, 22 Apr 2006 02:38:55 -0700 Subject: [PATCH] tpm: check mem start and len The memory start and length values obtained from the ACPI entry need to be checked and filled in with the default values from the specification if they don't exist. This patch fills in the default values and uses them appropriately. Signed-off-by: Kylie Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm_tis.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 1cb5a7f0755d..9c0727bf28b7 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -52,6 +52,8 @@ enum tis_int_flags { }; enum tis_defaults { + TIS_MEM_BASE = 0xFED4000, + TIS_MEM_LEN = 0x5000, TIS_SHORT_TIMEOUT = 750, /* ms */ TIS_LONG_TIMEOUT = 2000, /* 2 sec */ }; @@ -437,6 +439,11 @@ static int __devinit tpm_tis_pnp_init(struct pnp_dev start = pnp_mem_start(pnp_dev, 0); len = pnp_mem_len(pnp_dev, 0); + if (!start) + start = TIS_MEM_BASE; + if (!len) + len = TIS_MEM_LEN; + if (!(chip = tpm_register_hardware(&pnp_dev->dev, &tpm_tis))) return -ENODEV; -- cgit v1.2.3 From 8b006db604527c566dc1dd0aebae37714143aaef Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sat, 22 Apr 2006 02:39:07 -0700 Subject: [PATCH] tpm: update bios log code for 1.2 The acpi table which contains the BIOS log events was updated for 1.2. There are now client and server modes as defined in the specifications with slightly different formats. Additionally, the start field was even too small for the 1.1 version but had been working anyway. This patch updates the code to deal with any of the three types of headers probperly (1.1, 1.2 client and 1.2 server). Signed-off-by: Kylie Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm_bios.c | 49 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c index 5bcbaef53798..e45f0d3d12de 100644 --- a/drivers/char/tpm/tpm_bios.c +++ b/drivers/char/tpm/tpm_bios.c @@ -29,6 +29,11 @@ #define MAX_TEXT_EVENT 1000 /* Max event string length */ #define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */ +enum bios_platform_class { + BIOS_CLIENT = 0x00, + BIOS_SERVER = 0x01, +}; + struct tpm_bios_log { void *bios_event_log; void *bios_event_log_end; @@ -36,9 +41,18 @@ struct tpm_bios_log { struct acpi_tcpa { struct acpi_table_header hdr; - u16 reserved; - u32 log_max_len __attribute__ ((packed)); - u32 log_start_addr __attribute__ ((packed)); + u16 platform_class; + union { + struct client_hdr { + u32 log_max_len __attribute__ ((packed)); + u64 log_start_addr __attribute__ ((packed)); + } client; + struct server_hdr { + u16 reserved; + u64 log_max_len __attribute__ ((packed)); + u64 log_start_addr __attribute__ ((packed)); + } server; + }; }; struct tcpa_event { @@ -379,6 +393,7 @@ static int read_log(struct tpm_bios_log *log) struct acpi_tcpa *buff; acpi_status status; struct acpi_table_header *virt; + u64 len, start; if (log->bios_event_log != NULL) { printk(KERN_ERR @@ -399,27 +414,37 @@ static int read_log(struct tpm_bios_log *log) return -EIO; } - if (buff->log_max_len == 0) { + switch(buff->platform_class) { + case BIOS_SERVER: + len = buff->server.log_max_len; + start = buff->server.log_start_addr; + break; + case BIOS_CLIENT: + default: + len = buff->client.log_max_len; + start = buff->client.log_start_addr; + break; + } + if (!len) { printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", __func__); return -EIO; } /* malloc EventLog space */ - log->bios_event_log = kmalloc(buff->log_max_len, GFP_KERNEL); + log->bios_event_log = kmalloc(len, GFP_KERNEL); if (!log->bios_event_log) { - printk - ("%s: ERROR - Not enough Memory for BIOS measurements\n", - __func__); + printk("%s: ERROR - Not enough Memory for BIOS measurements\n", + __func__); return -ENOMEM; } - log->bios_event_log_end = log->bios_event_log + buff->log_max_len; + log->bios_event_log_end = log->bios_event_log + len; - acpi_os_map_memory(buff->log_start_addr, buff->log_max_len, (void *) &virt); + acpi_os_map_memory(start, len, (void *) &virt); - memcpy(log->bios_event_log, virt, buff->log_max_len); + memcpy(log->bios_event_log, virt, len); - acpi_os_unmap_memory(virt, buff->log_max_len); + acpi_os_unmap_memory(virt, len); return 0; } -- cgit v1.2.3 From 397c718299d848ff305ecd955838a9bd32f1f881 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 22 Apr 2006 02:39:18 -0700 Subject: [PATCH] tpm_infineon section fixup Use __devexit_p() for the exit/remove function to protect against discarding it. WARNING: drivers/char/tpm/tpm_infineon.o - Section mismatch: reference to .exit.text:tpm_inf_pnp_remove from .data between 'tpm_inf_pnp' (at offset 0x20) and 'tpm_inf' Signed-off-by: Randy Dunlap Cc: Kylene Jo Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm_infineon.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c index 90cae8f9fe21..adfff21beb21 100644 --- a/drivers/char/tpm/tpm_infineon.c +++ b/drivers/char/tpm/tpm_infineon.c @@ -15,6 +15,7 @@ * License. */ +#include #include #include "tpm.h" @@ -520,7 +521,7 @@ static struct pnp_driver tpm_inf_pnp = { }, .id_table = tpm_pnp_tbl, .probe = tpm_inf_pnp_probe, - .remove = tpm_inf_pnp_remove, + .remove = __devexit_p(tpm_inf_pnp_remove), }; static int __init init_inf(void) -- cgit v1.2.3 From cb5354253af2bc30ed449b8be4b3bddf3b3a2746 Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sat, 22 Apr 2006 02:39:31 -0700 Subject: [PATCH] tpm: spacing cleanups 2 Fixes minor spacing issues. Signed-off-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm_tis.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 9c0727bf28b7..398514745d3f 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -54,8 +54,8 @@ enum tis_int_flags { enum tis_defaults { TIS_MEM_BASE = 0xFED4000, TIS_MEM_LEN = 0x5000, - TIS_SHORT_TIMEOUT = 750, /* ms */ - TIS_LONG_TIMEOUT = 2000, /* 2 sec */ + TIS_SHORT_TIMEOUT = 750, /* ms */ + TIS_LONG_TIMEOUT = 2000, /* 2 sec */ }; #define TPM_ACCESS(l) (0x0000 | ((l) << 12)) @@ -188,7 +188,7 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, return -ETIME; } -static int recv_data(struct tpm_chip *chip, u8 * buf, size_t count) +static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) { int size = 0, burstcnt; while (size < count && @@ -206,7 +206,7 @@ static int recv_data(struct tpm_chip *chip, u8 * buf, size_t count) return size; } -static int tpm_tis_recv(struct tpm_chip *chip, u8 * buf, size_t count) +static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) { int size = 0; int expected, status; @@ -257,7 +257,7 @@ out: * tpm.c can skip polling for the data to be available as the interrupt is * waited for here */ -static int tpm_tis_send(struct tpm_chip *chip, u8 * buf, size_t len) +static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) { int rc, status, burstcnt; size_t count = 0; @@ -374,8 +374,7 @@ static struct tpm_vendor_specific tpm_tis = { .fops = &tis_ops,}, }; -static irqreturn_t tis_int_probe(int irq, void *dev_id, struct pt_regs - *regs) +static irqreturn_t tis_int_probe(int irq, void *dev_id, struct pt_regs *regs) { struct tpm_chip *chip = (struct tpm_chip *) dev_id; u32 interrupt; @@ -395,8 +394,7 @@ static irqreturn_t tis_int_probe(int irq, void *dev_id, struct pt_regs return IRQ_HANDLED; } -static irqreturn_t tis_int_handler(int irq, void *dev_id, struct pt_regs - *regs) +static irqreturn_t tis_int_handler(int irq, void *dev_id, struct pt_regs *regs) { struct tpm_chip *chip = (struct tpm_chip *) dev_id; u32 interrupt; @@ -426,10 +424,8 @@ static irqreturn_t tis_int_handler(int irq, void *dev_id, struct pt_regs return IRQ_HANDLED; } -static int __devinit tpm_tis_pnp_init(struct pnp_dev - *pnp_dev, const struct - pnp_device_id - *pnp_id) +static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev, + const struct pnp_device_id *pnp_id) { u32 vendor, intfcaps, intmask; int rc, i; -- cgit v1.2.3 From 5713556843aee24f484f445db6540f9fef976439 Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sat, 22 Apr 2006 02:39:44 -0700 Subject: [PATCH] tpm: add interrupt module parameter This patch adds a boolean module parameter that allows the user to turn interrupt support on and off. The default behavior is to attempt to use interrupts. Signed-off-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm_tis.c | 78 +++++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 398514745d3f..447f76388067 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -16,6 +16,9 @@ * published by the Free Software Foundation, version 2 of the * License. */ +#include +#include +#include #include #include #include @@ -424,6 +427,10 @@ static irqreturn_t tis_int_handler(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } +static int interrupts = 1; +module_param(interrupts, bool, 0444); +MODULE_PARM_DESC(interrupts, "Enable interrupts"); + static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev, const struct pnp_device_id *pnp_id) { @@ -510,44 +517,44 @@ static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev, iowrite32(intmask, chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor.locality)); + if (interrupts) { + chip->vendor.irq = + ioread8(chip->vendor.iobase + + TPM_INT_VECTOR(chip->vendor.locality)); + + for (i = 3; i < 16 && chip->vendor.irq == 0; i++) { + iowrite8(i, chip->vendor.iobase + + TPM_INT_VECTOR(chip->vendor.locality)); + if (request_irq + (i, tis_int_probe, SA_SHIRQ, + chip->vendor.miscdev.name, chip) != 0) { + dev_info(chip->dev, + "Unable to request irq: %d for probe\n", + i); + continue; + } - chip->vendor.irq = - ioread8(chip->vendor.iobase + - TPM_INT_VECTOR(chip->vendor.locality)); - - for (i = 3; i < 16 && chip->vendor.irq == 0; i++) { - iowrite8(i, - chip->vendor.iobase + - TPM_INT_VECTOR(chip->vendor.locality)); - if (request_irq - (i, tis_int_probe, SA_SHIRQ, - chip->vendor.miscdev.name, chip) != 0) { - dev_info(chip->dev, - "Unable to request irq: %d for probe\n", - i); - continue; - } - - /* Clear all existing */ - iowrite32(ioread32 - (chip->vendor.iobase + - TPM_INT_STATUS(chip->vendor.locality)), - chip->vendor.iobase + - TPM_INT_STATUS(chip->vendor.locality)); + /* Clear all existing */ + iowrite32(ioread32 + (chip->vendor.iobase + + TPM_INT_STATUS(chip->vendor.locality)), + chip->vendor.iobase + + TPM_INT_STATUS(chip->vendor.locality)); - /* Turn on */ - iowrite32(intmask | TPM_GLOBAL_INT_ENABLE, - chip->vendor.iobase + - TPM_INT_ENABLE(chip->vendor.locality)); + /* Turn on */ + iowrite32(intmask | TPM_GLOBAL_INT_ENABLE, + chip->vendor.iobase + + TPM_INT_ENABLE(chip->vendor.locality)); - /* Generate Interrupts */ - tpm_gen_interrupt(chip); + /* Generate Interrupts */ + tpm_gen_interrupt(chip); - /* Turn off */ - iowrite32(intmask, - chip->vendor.iobase + - TPM_INT_ENABLE(chip->vendor.locality)); - free_irq(i, chip); + /* Turn off */ + iowrite32(intmask, + chip->vendor.iobase + + TPM_INT_ENABLE(chip->vendor.locality)); + free_irq(i, chip); + } } if (chip->vendor.irq) { iowrite8(chip->vendor.irq, @@ -557,7 +564,8 @@ static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev, (chip->vendor.irq, tis_int_handler, SA_SHIRQ, chip->vendor.miscdev.name, chip) != 0) { dev_info(chip->dev, - "Unable to request irq: %d for use\n", i); + "Unable to request irq: %d for use\n", + chip->vendor.irq); chip->vendor.irq = 0; } else { /* Clear all existing */ -- cgit v1.2.3 From 93e1b7d42e1edb4ddde6257e9a02513fef26f715 Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sat, 22 Apr 2006 02:39:52 -0700 Subject: [PATCH] tpm: add HID module parameter I recently found that not all BIOS manufacturers are using the specified generic PNP id in their TPM ACPI table entry. I have added the vendor specific IDs that I know about and added a module parameter that a user can specify another HID to the probe list if their device isn't being found by the default list. Signed-off-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm_tis.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 447f76388067..b9cae9a238bb 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -610,7 +610,13 @@ static int tpm_tis_pnp_resume(struct pnp_dev *dev) static struct pnp_device_id tpm_pnp_tbl[] __devinitdata = { {"PNP0C31", 0}, /* TPM */ - {"", 0} + {"ATM1200", 0}, /* Atmel */ + {"IFX0102", 0}, /* Infineon */ + {"BCM0101", 0}, /* Broadcom */ + {"NSC1200", 0}, /* National */ + /* Add new here */ + {"", 0}, /* User Specified */ + {"", 0} /* Terminator */ }; static struct pnp_driver tis_pnp_driver = { @@ -621,6 +627,11 @@ static struct pnp_driver tis_pnp_driver = { .resume = tpm_tis_pnp_resume, }; +#define TIS_HID_USR_IDX sizeof(tpm_pnp_tbl)/sizeof(struct pnp_device_id) -2 +module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id, + sizeof(tpm_pnp_tbl[TIS_HID_USR_IDX].id), 0444); +MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe"); + static int __init init_tis(void) { return pnp_register_driver(&tis_pnp_driver); -- cgit v1.2.3 From caa98c41c0db9bfda5bc9a0e680f304283089268 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sun, 23 Apr 2006 18:14:00 +1000 Subject: drm: fixup r300 scratch on BE machines This fixes the r300 scratch stuff to work on PPC, from Ben Herrenschmidt on IRC. Signed-off-by: Dave Airlie --- drivers/char/drm/r300_cmdbuf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/drm/r300_cmdbuf.c b/drivers/char/drm/r300_cmdbuf.c index b108c7f913b2..26bdf2ca59d7 100644 --- a/drivers/char/drm/r300_cmdbuf.c +++ b/drivers/char/drm/r300_cmdbuf.c @@ -723,7 +723,7 @@ static int r300_scratch(drm_radeon_private_t *dev_priv, dev_priv->scratch_ages[header.scratch.reg]++; - ref_age_base = *(u32 **)cmdbuf->buf; + ref_age_base = (u32 *)(unsigned long)*((uint64_t *)cmdbuf->buf); cmdbuf->buf += sizeof(u64); cmdbuf->bufsz -= sizeof(u64); -- cgit v1.2.3 From 5d23fafb1bf8ef071738026c2e5071a92186d5f8 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sun, 23 Apr 2006 18:26:40 +1000 Subject: drm: possible cleanups This patch contains the following possible cleanups: - make the following needlessly global function static: - drm_bufs.c: drm_addbufs_fb() - remove the following unused EXPORT_SYMBOL's: - drm_agpsupport.c: drm_agp_bind_memory - drm_bufs.c: drm_rmmap_locked - drm_bufs.c: drm_rmmap - drm_stub.c: drm_get_dev Signed-off-by: Adrian Bunk Signed-off-by: Dave Airlie --- drivers/char/drm/drmP.h | 1 - drivers/char/drm/drm_agpsupport.c | 2 -- drivers/char/drm/drm_bufs.c | 5 +---- drivers/char/drm/drm_stub.c | 2 -- 4 files changed, 1 insertion(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index e1aadae00623..cb76e5ca9a23 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -889,7 +889,6 @@ extern int drm_lock_free(drm_device_t * dev, /* Buffer management support (drm_bufs.h) */ extern int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request); extern int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request); -extern int drm_addbufs_fb(drm_device_t *dev, drm_buf_desc_t *request); extern int drm_addmap(drm_device_t * dev, unsigned int offset, unsigned int size, drm_map_type_t type, drm_map_flags_t flags, drm_local_map_t ** map_ptr); diff --git a/drivers/char/drm/drm_agpsupport.c b/drivers/char/drm/drm_agpsupport.c index fabc930c67a2..40bfd9b01e39 100644 --- a/drivers/char/drm/drm_agpsupport.c +++ b/drivers/char/drm/drm_agpsupport.c @@ -503,8 +503,6 @@ int drm_agp_bind_memory(DRM_AGP_MEM * handle, off_t start) return agp_bind_memory(handle, start); } -EXPORT_SYMBOL(drm_agp_bind_memory); - /** Calls agp_unbind_memory() */ int drm_agp_unbind_memory(DRM_AGP_MEM * handle) { diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c index 8a9cf12e6183..006b06d29727 100644 --- a/drivers/char/drm/drm_bufs.c +++ b/drivers/char/drm/drm_bufs.c @@ -386,7 +386,6 @@ int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map) return 0; } -EXPORT_SYMBOL(drm_rmmap_locked); int drm_rmmap(drm_device_t *dev, drm_local_map_t *map) { @@ -398,7 +397,6 @@ int drm_rmmap(drm_device_t *dev, drm_local_map_t *map) return ret; } -EXPORT_SYMBOL(drm_rmmap); /* The rmmap ioctl appears to be unnecessary. All mappings are torn down on * the last close of the device, and this is necessary for cleanup when things @@ -1053,7 +1051,7 @@ static int drm_addbufs_sg(drm_device_t * dev, drm_buf_desc_t * request) return 0; } -int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request) +static int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request) { drm_device_dma_t *dma = dev->dma; drm_buf_entry_t *entry; @@ -1212,7 +1210,6 @@ int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request) atomic_dec(&dev->buf_alloc); return 0; } -EXPORT_SYMBOL(drm_addbufs_fb); /** diff --git a/drivers/char/drm/drm_stub.c b/drivers/char/drm/drm_stub.c index 68073e14fdec..9a842a36bb27 100644 --- a/drivers/char/drm/drm_stub.c +++ b/drivers/char/drm/drm_stub.c @@ -229,8 +229,6 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, return ret; } -EXPORT_SYMBOL(drm_get_dev); - /** * Put a device minor number. * -- cgit v1.2.3