From patchwork Tue Oct 26 09:14:11 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Zhao, Yakui" X-Patchwork-Id: 281742 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id o9Q9JJJ0019129 for ; Tue, 26 Oct 2010 09:19:20 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755913Ab0JZJTT (ORCPT ); Tue, 26 Oct 2010 05:19:19 -0400 Received: from mga11.intel.com ([192.55.52.93]:24764 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755024Ab0JZJTT (ORCPT ); Tue, 26 Oct 2010 05:19:19 -0400 Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga102.fm.intel.com with ESMTP; 26 Oct 2010 02:19:18 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.58,240,1286175600"; d="scan'208";a="620367765" Received: from yakui_zhao.sh.intel.com (HELO localhost.localdomain) ([10.239.36.9]) by fmsmga002.fm.intel.com with ESMTP; 26 Oct 2010 02:19:18 -0700 From: yakui.zhao@intel.com To: openipmi-developer@lists.sourceforge.net, linux-acpi@vger.kernel.org Cc: minyard@acm.org, lenb@kernel.org, Zhao Yakui Subject: [RFC PATCH 1/4] IPMI: Add one interface to get more info of low-level IPMI device Date: Tue, 26 Oct 2010 17:14:11 +0800 Message-Id: <1288084454-560-2-git-send-email-yakui.zhao@intel.com> X-Mailer: git-send-email 1.5.4.5 In-Reply-To: <1288084454-560-1-git-send-email-yakui.zhao@intel.com> References: <1288084454-560-1-git-send-email-yakui.zhao@intel.com> Sender: linux-acpi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Tue, 26 Oct 2010 09:19:20 +0000 (UTC) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 4f3f8c9..e323edb 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -970,6 +970,52 @@ out_kfree: } EXPORT_SYMBOL(ipmi_create_user); +int ipmi_get_smi_info(int if_num, struct ipmi_smi_info *data) +{ + int rv = 0; + ipmi_smi_t intf; + struct ipmi_smi_handlers *handlers; + + mutex_lock(&ipmi_interfaces_mutex); + list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { + if (intf->intf_num == if_num) + goto found; + } + /* Not found, return an error */ + rv = -EINVAL; + mutex_unlock(&ipmi_interfaces_mutex); + return rv; + +found: + handlers = intf->handlers; + rv = handlers->get_smi_info(intf->send_info, data); + mutex_unlock(&ipmi_interfaces_mutex); + + return rv; +} +EXPORT_SYMBOL(ipmi_get_smi_info); + +void ipmi_put_smi_info(int if_num) +{ + ipmi_smi_t intf; + struct ipmi_smi_handlers *handlers; + + mutex_lock(&ipmi_interfaces_mutex); + list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { + if (intf->intf_num == if_num) + goto found; + } + /* Not found, return */ + mutex_unlock(&ipmi_interfaces_mutex); + return; + +found: + handlers = intf->handlers; + handlers->put_smi_info(intf->send_info); + mutex_unlock(&ipmi_interfaces_mutex); +} +EXPORT_SYMBOL(ipmi_put_smi_info); + static void free_user(struct kref *ref) { ipmi_user_t user = container_of(ref, struct ipmi_user, refcount); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 7bd7c45..d313018 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -57,6 +57,7 @@ #include #include #include +#include #include #include #include "ipmi_si_sm.h" @@ -107,10 +108,6 @@ enum si_type { }; static char *si_to_str[] = { "kcs", "smic", "bt" }; -enum ipmi_addr_src { - SI_INVALID = 0, SI_HOTMOD, SI_HARDCODED, SI_SPMI, SI_ACPI, SI_SMBIOS, - SI_PCI, SI_DEVICETREE, SI_DEFAULT -}; static char *ipmi_addr_src_to_str[] = { NULL, "hotmod", "hardcoded", "SPMI", "ACPI", "SMBIOS", "PCI", "device-tree", "default" }; @@ -291,6 +288,12 @@ struct smi_info { struct task_struct *thread; struct list_head link; + /* + * Count the refcount of smi_data->dev related with the function + * of ipmi_get_smi_info/ipmi_put_smi_info. + */ + atomic_t smi_info_ref; + struct ipmi_smi_info smi_data; }; #define smi_inc_stat(smi, stat) \ @@ -1186,6 +1189,27 @@ static int smi_start_processing(void *send_info, return 0; } +static int get_smi_info(void *send_info, struct ipmi_smi_info *data) +{ + struct smi_info *new_smi = send_info; + struct ipmi_smi_info *smi_data = &new_smi->smi_data; + + get_device(new_smi->dev); + memcpy(data, smi_data, sizeof(*smi_data)); + smi_data->addr_src = new_smi->addr_source; + atomic_inc(&new_smi->smi_info_ref); + + return 0; +} + +static void put_smi_info(void *send_info) +{ + struct smi_info *new_smi = send_info; + + put_device(new_smi->dev); + atomic_dec(&new_smi->smi_info_ref); +} + static void set_maintenance_mode(void *send_info, int enable) { struct smi_info *smi_info = send_info; @@ -1197,6 +1221,8 @@ static void set_maintenance_mode(void *send_info, int enable) static struct ipmi_smi_handlers handlers = { .owner = THIS_MODULE, .start_processing = smi_start_processing, + .get_smi_info = get_smi_info, + .put_smi_info = put_smi_info, .sender = sender, .request_events = request_events, .set_maintenance_mode = set_maintenance_mode, @@ -2143,6 +2169,8 @@ static int __devinit ipmi_pnp_probe(struct pnp_dev *dev, return -ENOMEM; info->addr_source = SI_ACPI; + info->smi_data.addr_info.acpi_info.acpi_handle = + acpi_dev->handle; printk(KERN_INFO PFX "probing via ACPI\n"); handle = acpi_dev->handle; @@ -3092,6 +3120,7 @@ static int try_smi_init(struct smi_info *new_smi) { int rv = 0; int i; + struct ipmi_smi_info *smi_data; printk(KERN_INFO PFX "Trying %s-specified %s state" " machine at %s address 0x%lx, slave address 0x%x," @@ -3255,6 +3284,9 @@ static int try_smi_init(struct smi_info *new_smi) dev_info(new_smi->dev, "IPMI %s interface initialized\n", si_to_str[new_smi->si_type]); + smi_data = &new_smi->smi_data; + smi_data->dev = new_smi->dev; + atomic_set(&new_smi->smi_info_ref, 0); return 0; @@ -3501,7 +3533,14 @@ static void cleanup_one_si(struct smi_info *to_clean) printk(KERN_ERR PFX "Unable to unregister device: errno=%d\n", rv); } - + /* maybe the caller doesn't release the refcount of dev, which is + * increased by calling the function of ipmi_get_smi_info. So try + * to help it. + */ + while (atomic_read(&to_clean->smi_info_ref)) { + put_device(to_clean->dev); + atomic_dec(&to_clean->smi_info_ref); + } if (to_clean->handlers) to_clean->handlers->cleanup(to_clean->si_sm); diff --git a/include/linux/ipmi.h b/include/linux/ipmi.h index 65aae34..9a0c72e 100644 --- a/include/linux/ipmi.h +++ b/include/linux/ipmi.h @@ -454,6 +454,35 @@ unsigned int ipmi_addr_length(int addr_type); /* Validate that the given IPMI address is valid. */ int ipmi_validate_addr(struct ipmi_addr *addr, int len); +enum ipmi_addr_src { + SI_INVALID = 0, SI_HOTMOD, SI_HARDCODED, SI_SPMI, SI_ACPI, SI_SMBIOS, + SI_PCI, SI_DEVICETREE, SI_DEFAULT +}; +struct ipmi_smi_info { + enum ipmi_addr_src addr_src; + struct device *dev; + /* + * The addr_info can provide more detailed info of one IPMI device. + * Now only SI_ACPI info is provided. And it depends on the SI_ACPI + * address type. If the info is required for other address type, please + * add it. + */ + union { + /* the acpi_info element is defined for the SI_ACPI + * address type + */ + struct { + void *acpi_handle; + } acpi_info; + } addr_info; +}; + +/* This is to get the private info of ipmi_smi_t */ +extern int ipmi_get_smi_info(int if_num, struct ipmi_smi_info *data); +/* This is to decrease refcount of dev added in the function of + * ipmi_get_smi_info + */ +extern void ipmi_put_smi_info(int if_num); #endif /* __KERNEL__ */ diff --git a/include/linux/ipmi_smi.h b/include/linux/ipmi_smi.h index 4b48318..b99942d 100644 --- a/include/linux/ipmi_smi.h +++ b/include/linux/ipmi_smi.h @@ -86,6 +86,14 @@ struct ipmi_smi_handlers { int (*start_processing)(void *send_info, ipmi_smi_t new_intf); + /* + * Get the detailed private info of the low level interface and store + * it into the structure of ipmi_smi_data. For example: the + * ACPI device handle will be returned for the pnp_acpi IPMI device. + */ + int (*get_smi_info)(void *send_info, struct ipmi_smi_info *data); + + void (*put_smi_info)(void *send_info); /* Called to enqueue an SMI message to be sent. This operation is not allowed to fail. If an error occurs, it should report back the error in a received message. It may