From patchwork Wed Feb 5 02:29:10 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rajat Jain X-Patchwork-Id: 3584111 X-Patchwork-Delegate: bhelgaas@google.com Return-Path: X-Original-To: patchwork-linux-pci@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 11BD49F2E9 for ; Wed, 5 Feb 2014 02:29:18 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 122EC201B6 for ; Wed, 5 Feb 2014 02:29:17 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id E595520181 for ; Wed, 5 Feb 2014 02:29:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753949AbaBEC3O (ORCPT ); Tue, 4 Feb 2014 21:29:14 -0500 Received: from mail-pd0-f182.google.com ([209.85.192.182]:54636 "EHLO mail-pd0-f182.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753796AbaBEC3N (ORCPT ); Tue, 4 Feb 2014 21:29:13 -0500 Received: by mail-pd0-f182.google.com with SMTP id v10so8969581pde.41 for ; Tue, 04 Feb 2014 18:29:12 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=message-id:date:from:user-agent:mime-version:to:cc:subject :content-type:content-transfer-encoding; bh=xfbN7ZSogrBcAyaXfp7A7YW8Fi20HkDbndBsl7jK2FQ=; b=EgcGL0i3lONWIVm0OAmRGMGoqS/H6ZXL4sjrEJTZSDcFFaGv/EDA8Vzdo0Sx4+7bnz 11kMfWUdHedz6UiNMaSN7D3kPJe3JoEGhMQVf+Euntla913hkqM1jEAR/Etm1xUWyGQi N0NsB1z8YUAK3hAGug5GIYg47r+7bbdsx4WyUWOTUfQ/2U1LrXqaJL0arjaBSrdSfHeC D90SuB1ul2mvpDGo9Rbp2iSTZ5oSwSoNy0gdS5FpmnL11YXJb+gguTrRz9MlbpY19azY eo9OfQZheIOdTBC3x0thmlUm56MiNN+LRevwteejPW5XUs/7oqLRwPDqPBOJXzew95k0 GiTA== X-Received: by 10.68.221.42 with SMTP id qb10mr47361428pbc.65.1391567352476; Tue, 04 Feb 2014 18:29:12 -0800 (PST) Received: from [192.168.211.137] ([66.129.239.13]) by mx.google.com with ESMTPSA id un5sm183792414pab.3.2014.02.04.18.29.10 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 04 Feb 2014 18:29:11 -0800 (PST) Message-ID: <52F1A1F6.2000800@gmail.com> Date: Tue, 04 Feb 2014 18:29:10 -0800 From: Rajat Jain User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130803 Thunderbird/17.0.8 MIME-Version: 1.0 To: Bjorn Helgaas , "Rafael J. Wysocki" , Kenji Kaneshige , Alex Williamson , Yijing Wang , linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, Yinghai Lu CC: Guenter Roeck , Rajat Jain , Rajat Jain Subject: [PATCH v4 2/8] pciehp: Use link change notifications for hot-plug and removal Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org X-Spam-Status: No, score=-7.4 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP A lot of systems do not have the fancy buttons and LEDs, and instead want to rely only on the Link state change events to drive the hotplug and removal state machinery. (http://www.spinics.net/lists/hotplug/msg05802.html) This patch adds support for that functionality. Here are the details about the patch itself: * Define and use interrupt events for linkup / linkdown. * Make the pcie_isr() also look at link events, and direct control to corresponding (new) link state change handler function. * Introduce the functions to handle link-up and link-down events and queue the add / removal work in the slot->wq to be processed by pciehp_power_thread() As a side note, this patch also fixes the bug https://bugzilla.kernel.org/show_bug.cgi?id=65521 Signed-off-by: Rajat Jain Signed-off-by: Rajat Jain Signed-off-by: Guenter Roeck --- drivers/pci/hotplug/pciehp.h | 3 ++ drivers/pci/hotplug/pciehp_ctrl.c | 88 +++++++++++++++++++++++++++++++++++++ drivers/pci/hotplug/pciehp_hpc.c | 6 ++- 3 files changed, 96 insertions(+), 1 deletion(-) diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index f952459..d8d0336 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -109,6 +109,8 @@ struct controller { #define INT_BUTTON_PRESS 7 #define INT_BUTTON_RELEASE 8 #define INT_BUTTON_CANCEL 9 +#define INT_LINK_UP 10 +#define INT_LINK_DOWN 11 #define STATIC_STATE 0 #define BLINKINGON_STATE 1 @@ -132,6 +134,7 @@ u8 pciehp_handle_attention_button(struct slot *p_slot); u8 pciehp_handle_switch_change(struct slot *p_slot); u8 pciehp_handle_presence_change(struct slot *p_slot); u8 pciehp_handle_power_fault(struct slot *p_slot); +void pciehp_handle_linkstate_change(struct slot *p_slot); int pciehp_configure_device(struct slot *p_slot); int pciehp_unconfigure_device(struct slot *p_slot); void pciehp_queue_pushbutton_work(struct work_struct *work); diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 5062848..5608284 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -150,6 +150,27 @@ u8 pciehp_handle_power_fault(struct slot *p_slot) return 1; } +void pciehp_handle_linkstate_change(struct slot *p_slot) +{ + u32 event_type; + struct controller *ctrl = p_slot->ctrl; + + /* Link Status Change */ + ctrl_dbg(ctrl, "Data Link Layer State change\n"); + + if (pciehp_check_link_active(ctrl)) { + ctrl_info(ctrl, "slot(%s): Link Up event\n", + slot_name(p_slot)); + event_type = INT_LINK_UP; + } else { + ctrl_info(ctrl, "slot(%s): Link Down event\n", + slot_name(p_slot)); + event_type = INT_LINK_DOWN; + } + + queue_interrupt_event(p_slot, event_type); +} + /* The following routines constitute the bulk of the hotplug controller logic */ @@ -415,6 +436,69 @@ static void handle_surprise_event(struct slot *p_slot) queue_work(p_slot->wq, &info->work); } +/* + * Note: This function must be called with slot->lock held + */ +static void handle_link_event(struct slot *p_slot, u32 event) +{ + struct controller *ctrl = p_slot->ctrl; + struct power_work_info *info; + + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n", + __func__); + return; + } + info->p_slot = p_slot; + INIT_WORK(&info->work, pciehp_power_thread); + + switch (p_slot->state) { + case BLINKINGON_STATE: + case BLINKINGOFF_STATE: + cancel_delayed_work(&p_slot->work); + /* Fall through */ + case STATIC_STATE: + p_slot->state = event == INT_LINK_UP ? + POWERON_STATE : POWEROFF_STATE; + queue_work(p_slot->wq, &info->work); + break; + case POWERON_STATE: + if (event == INT_LINK_UP) { + ctrl_info(ctrl, + "Link Up event ignored on slot(%s): already powering on\n", + slot_name(p_slot)); + kfree(info); + } else { + ctrl_info(ctrl, + "Link Down event queued on slot(%s): currently getting powered on\n", + slot_name(p_slot)); + p_slot->state = POWEROFF_STATE; + queue_work(p_slot->wq, &info->work); + } + break; + case POWEROFF_STATE: + if (event == INT_LINK_UP) { + ctrl_info(ctrl, + "Link Up event queued on slot(%s): currently getting powered off\n", + slot_name(p_slot)); + p_slot->state = POWERON_STATE; + queue_work(p_slot->wq, &info->work); + } else { + ctrl_info(ctrl, + "Link Down event ignored on slot(%s): already powering off\n", + slot_name(p_slot)); + kfree(info); + } + break; + default: + ctrl_err(ctrl, "Not a valid state on slot(%s)\n", + slot_name(p_slot)); + kfree(info); + break; + } +} + static void interrupt_event_handler(struct work_struct *work) { struct event_info *info = container_of(work, struct event_info, work); @@ -439,6 +523,10 @@ static void interrupt_event_handler(struct work_struct *work) ctrl_dbg(ctrl, "Surprise Removal\n"); handle_surprise_event(p_slot); break; + case INT_LINK_UP: + case INT_LINK_DOWN: + handle_link_event(p_slot, info->event_type); + break; default: break; } diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index aed6ab4..b413dce 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -540,7 +540,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) detected &= (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD | PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC | - PCI_EXP_SLTSTA_CC); + PCI_EXP_SLTSTA_CC | PCI_EXP_SLTSTA_DLLSC); detected &= ~intr_loc; intr_loc |= detected; if (!intr_loc) @@ -579,6 +579,10 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) ctrl->power_fault_detected = 1; pciehp_handle_power_fault(slot); } + + if (intr_loc & PCI_EXP_SLTSTA_DLLSC) + pciehp_handle_linkstate_change(slot); + return IRQ_HANDLED; }