Taku Izumi wrote:
This patch adds an uevent framework to pci_hotplug. Signed-off-by: Taku Izumi <izumi.taku@xxxxxxxxxxxxxx> --- drivers/pci/hotplug/Makefile | 2 drivers/pci/hotplug/pci_hotplug_core.c | 9 + drivers/pci/hotplug/pci_hotplug_uevent.c | 169 +++++++++++++++++++++++++++++++ drivers/pci/hotplug/pci_hotplug_uevent.h | 43 +++++++ 4 files changed, 223 insertions(+) Index: linux-next.29rc6/drivers/pci/hotplug/Makefile =================================================================== --- linux-next.29rc6.orig/drivers/pci/hotplug/Makefile +++ linux-next.29rc6/drivers/pci/hotplug/Makefile @@ -24,6 +24,8 @@ obj-$(CONFIG_HOTPLUG_PCI_FAKE) += fakep pci_hotplug-objs := pci_hotplug_core.o +pci_hotplug-objs += pci_hotplug_uevent.o + ifdef CONFIG_HOTPLUG_PCI_CPCI pci_hotplug-objs += cpci_hotplug_core.o \ cpci_hotplug_pci.o Index: linux-next.29rc6/drivers/pci/hotplug/pci_hotplug_core.c =================================================================== --- linux-next.29rc6.orig/drivers/pci/hotplug/pci_hotplug_core.c +++ linux-next.29rc6/drivers/pci/hotplug/pci_hotplug_core.c @@ -42,6 +42,7 @@ #include <linux/pci_hotplug.h> #include <asm/uaccess.h> #include "../pci.h" +#include "pci_hotplug_uevent.h" #define MY_NAME "pci_hotplug" @@ -658,6 +659,12 @@ static int __init pci_hotplug_init (void { int result; + result = pcihp_uevent_init(); + if (result) { + err("pcihp_uevent_init with error %d\n", result); + goto err_pcihp_uevent; + } + result = cpci_hotplug_init(debug); if (result) { err ("cpci_hotplug_init with error %d\n", result); @@ -666,6 +673,7 @@ static int __init pci_hotplug_init (void info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); +err_pcihp_uevent: err_cpci: return result; } @@ -673,6 +681,7 @@ err_cpci: static void __exit pci_hotplug_exit (void) { cpci_hotplug_exit(); + pcihp_uevent_exit(); } module_init(pci_hotplug_init); Index: linux-next.29rc6/drivers/pci/hotplug/pci_hotplug_uevent.c =================================================================== --- /dev/null +++ linux-next.29rc6/drivers/pci/hotplug/pci_hotplug_uevent.c @@ -0,0 +1,169 @@ +/* + * PCI Hotplug Uevent Support (pci_hotplug_uevent) + * + * Copyright (C) 2009 Taku Izumi + * Copyright (C) 2009 FUJITSU LIMITED + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ +#include <linux/slab.h> +#include <linux/kobject.h> +#include <linux/pci.h> +#include <linux/pci_hotplug.h> + +#include "pci_hotplug_uevent.h" + +#define MY_NAME "pci_hotplug_uevent" +#define err(format, arg...) \ + printk(KERN_ERR "%s: " format, MY_NAME , ## arg) +#define info(format, arg...) \ + printk(KERN_INFO "%s: " format, MY_NAME , ## arg) +#define warn(format, arg...) \ + printk(KERN_WARNING "%s: " format, MY_NAME , ## arg) + +static const struct { + enum pcihp_uevent_type type; + enum kobject_action action; + char *name;
I think we don't need the "type" field. And I also think we don't need "action" field because we will always use KOBJ_CHANGE. So we don't need this struct.
+} _pcihp_uevent_type_names[] = { + {PHP_UEVT_PRESENCE_ON, KOBJ_CHANGE, "Card Present"}, + {PHP_UEVT_PRESENCE_OFF, KOBJ_CHANGE, "Card Not Present"}, + {PHP_UEVT_SWITCH_CLOSE, KOBJ_CHANGE, "Latch Close"}, + {PHP_UEVT_SWITCH_OPEN, KOBJ_CHANGE, "Latch Open"}, + {PHP_UEVT_POWER_FAULT, KOBJ_CHANGE, "Power Fault"}, + {PHP_UEVT_POWER_FAULT_CLEAR, KOBJ_CHANGE, "Power Fault Cleared"}, + {PHP_UEVT_BUTTON_PRESS, KOBJ_CHANGE, "Attention Button Pressed"}, +}; + +static struct kmem_cache *_pcihp_uevent_cache; +
I don't think we need to create new kmem cache.
+struct pcihp_uevent { + struct hotplug_slot *slot; + enum kobject_action action; + struct kobj_uevent_env ku_env; +};
I think we don't need the "slot" field. And I also think we don't need "action" field because we will always use KOBJ_CHANGE. So we don't need struct pcihp_uevent.
+ +static void pcihp_uevent_free(struct pcihp_uevent *event) +{ + kmem_cache_free(_pcihp_uevent_cache, event); +} + +static struct pcihp_uevent *pcihp_uevent_create(struct hotplug_slot *slot, + enum kobject_action action, + const char *event_name) +{ + struct pcihp_uevent *event; + + event = kmem_cache_zalloc(_pcihp_uevent_cache, GFP_ATOMIC);
How about adding struct pcihp_uevent (I think we only need struct kobj_uevent_env though) into struct hotplug_slot? This will remove memory allocation in each event. Though we need to serialize pcihp_uevent_create() on each slot.
+ if (!event) { + err("%s: kmem_cache_zalloc() failed", __func__); + goto err_nomem; + } + + event->slot = slot; + event->action = action; + + if (add_uevent_var(&event->ku_env, + "PCIHP_SLOT_NAME=%s", + hotplug_slot_name(slot))) { + err("%s: add_uevent_var() for PCIHP_SLOT_NAME failed", + __func__); + goto err_add; + } + + if (add_uevent_var(&event->ku_env, + "PCIHP_SLOT_ADDRESS=%04x:%02x:%02x", + pci_domain_nr(slot->pci_slot->bus), + slot->pci_slot->bus->number, + slot->pci_slot->number)) { + err("%s: add_uevent_var() for PCIHP_SLOT_ADDRESS failed", + __func__); + goto err_add; + }
I don't think we need PCIHP_SLOT_ADDRESS because we can get it from sys/bus/pci/slots/<slot name>/address file.
+ + if (add_uevent_var(&event->ku_env, + "PCIHP_DRV_NAME=%s", + slot->ops->owner->name)) { + err("%s: add_uevent_var() for PCIHP_DRV_NAME failed", + __func__); + goto err_add; + } +
How about adding new file under sys/bus/pci/<slot name> directory to indicate which php driver manages the slot, instead of adding PCIHP_DRV_NAME environment variable. I had some experiences that it was difficult to know the slot was manged by what php driver in debugging. So the new file will be useful for debugging too.
+ if (add_uevent_var(&event->ku_env, + "PCIHP_EVENT_TYPE=%s", + event_name)) { + err("%s: add_uevent_var() for PCIHP_EVENT_TYPE failed\n", + __func__); + goto err_add; + } + + return event; + +err_add: + pcihp_uevent_free(event); +err_nomem: + return ERR_PTR(-ENOMEM); +} + +static void pcihp_uevent_send(struct pcihp_uevent *event, struct kobject *kobj) +{ + int ret; + + ret = kobject_uevent_env(kobj, event->action, event->ku_env.envp); + if (ret) + err("%s: kobject_uevent_env failed", __func__); +} + +void pcihp_slot_uevent(enum pcihp_uevent_type event_type, + struct hotplug_slot *slot) +{ + struct pcihp_uevent *event; + + if (event_type >= ARRAY_SIZE(_pcihp_uevent_type_names)) { + err("%s: Invalid event_type %d", __func__, event_type); + goto out; + } + + event = pcihp_uevent_create(slot, + _pcihp_uevent_type_names[event_type].action, + _pcihp_uevent_type_names[event_type].name); + if (IS_ERR(event)) + goto out; + + pcihp_uevent_send(event, &slot->pci_slot->kobj); + + pcihp_uevent_free(event); +out: + return; +} +EXPORT_SYMBOL_GPL(pcihp_slot_uevent); + + +int pcihp_uevent_init(void) +{ + _pcihp_uevent_cache = KMEM_CACHE(pcihp_uevent, 0); + if (!_pcihp_uevent_cache) + return -ENOMEM; + + return 0; +} + +void pcihp_uevent_exit(void) +{ + kmem_cache_destroy(_pcihp_uevent_cache); +} Index: linux-next.29rc6/drivers/pci/hotplug/pci_hotplug_uevent.h =================================================================== --- /dev/null +++ linux-next.29rc6/drivers/pci/hotplug/pci_hotplug_uevent.h @@ -0,0 +1,43 @@ +/* + * PCI Hotplug Uevent Support + * + * Copyright (C) 2009 Taku Izumi + * Copyright (C) 2009 FUJITSU LIMITED + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef PCI_HOTPLUG_UEVENT_H +#define PCI_HOTPLUG_UEVENT_H + +enum pcihp_uevent_type { + PHP_UEVT_PRESENCE_ON, + PHP_UEVT_PRESENCE_OFF, + PHP_UEVT_SWITCH_CLOSE, + PHP_UEVT_SWITCH_OPEN, + PHP_UEVT_POWER_FAULT, + PHP_UEVT_POWER_FAULT_CLEAR, + PHP_UEVT_BUTTON_PRESS, +};
Attention button is used to request several kinds on hotplug operations. - Initiate hot-add operation - Cancel hot-add operation - Initiate hot-removal operation - Cancel hot-removal operation I think PHP_UEVT_BUTTON_PRESS should be divided for each because userland has no way to identify it. In addition, ACPI doesn't define attention button, but ACPI Device/Bus check event and Eject request event can be mapped to "Initiate hot-add operation" and "Initiate hot-removal operation" respectively in acpiphp. Thanks, Kenji Kaneshige
+ +extern int pcihp_uevent_init(void); +extern void pcihp_uevent_exit(void); +extern void pcihp_slot_uevent(enum pcihp_uevent_type event_type, + struct hotplug_slot *slot); + +#endif /* PCI_HOTPLUG_UEVENT_H */ -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html
-- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html