From owner-svn-src-projects@FreeBSD.ORG Sun Dec 30 22:00:21 2012 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 6BB6397D; Sun, 30 Dec 2012 22:00:21 +0000 (UTC) (envelope-from gavin@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) by mx1.freebsd.org (Postfix) with ESMTP id 4FEBF8FC08; Sun, 30 Dec 2012 22:00:21 +0000 (UTC) Received: from svn.freebsd.org (svn.FreeBSD.org [8.8.178.70]) by svn.freebsd.org (8.14.5/8.14.5) with ESMTP id qBUM0Lew089175; Sun, 30 Dec 2012 22:00:21 GMT (envelope-from gavin@svn.freebsd.org) Received: (from gavin@localhost) by svn.freebsd.org (8.14.5/8.14.5/Submit) id qBUM0KWg089170; Sun, 30 Dec 2012 22:00:20 GMT (envelope-from gavin@svn.freebsd.org) Message-Id: <201212302200.qBUM0KWg089170@svn.freebsd.org> From: Gavin Atkinson Date: Sun, 30 Dec 2012 22:00:20 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r244873 - in projects/pciehp/sys: conf dev/pci X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 30 Dec 2012 22:00:21 -0000 Author: gavin Date: Sun Dec 30 22:00:19 2012 New Revision: 244873 URL: http://svnweb.freebsd.org/changeset/base/244873 Log: Commit proof-of-concept first cut at PCIe HotPlug support. This code is nowhere near ready for prime time. Almost every line of it is a hack, and almost all of it will need to be rewritten. Regardless, this is sufficient to reliably allow hot insertion and removal of an ASMedia ASM1042 xhci(4) USB 3.0 ExpressCard into a Toshiba Tecra M5 laptop. This is being committed in this very early state due to requests from other driver developers. Added: projects/pciehp/sys/dev/pci/pcie_hp.c Modified: projects/pciehp/sys/conf/files projects/pciehp/sys/dev/pci/pci.c projects/pciehp/sys/dev/pci/pci_private.h projects/pciehp/sys/dev/pci/pcivar.h Modified: projects/pciehp/sys/conf/files ============================================================================== --- projects/pciehp/sys/conf/files Sun Dec 30 21:47:11 2012 (r244872) +++ projects/pciehp/sys/conf/files Sun Dec 30 22:00:19 2012 (r244873) @@ -1810,6 +1810,7 @@ dev/pci/pci_pci.c optional pci dev/pci/pci_subr.c optional pci dev/pci/pci_user.c optional pci dev/pci/pcib_if.m standard +dev/pci/pcie_hp.c optional pci dev/pci/vga_pci.c optional pci dev/pcn/if_pcn.c optional pcn pci dev/pdq/if_fea.c optional fea eisa Modified: projects/pciehp/sys/dev/pci/pci.c ============================================================================== --- projects/pciehp/sys/dev/pci/pci.c Sun Dec 30 21:47:11 2012 (r244872) +++ projects/pciehp/sys/dev/pci/pci.c Sun Dec 30 22:00:19 2012 (r244873) @@ -3202,6 +3202,7 @@ pci_add_children(device_t dev, int domai int s, f, pcifunchigh; uint8_t hdrtype; + printf("pci_add_children\n"); KASSERT(dinfo_size >= sizeof(struct pci_devinfo), ("dinfo_size too small")); maxslots = PCIB_MAXSLOTS(pcib); @@ -3228,6 +3229,7 @@ pci_add_children(device_t dev, int domai void pci_add_child(device_t bus, struct pci_devinfo *dinfo) { + printf("pci_add_child\n"); dinfo->cfg.dev = device_add_child(bus, NULL, -1); device_set_ivars(dinfo->cfg.dev, dinfo); resource_list_init(&dinfo->resources); @@ -3279,6 +3281,9 @@ pci_attach_common(device_t dev) if (!tag_valid) #endif sc->sc_dma_tag = bus_get_dma_tag(dev); + + pci_hotplug_init(dev); + return (0); } Modified: projects/pciehp/sys/dev/pci/pci_private.h ============================================================================== --- projects/pciehp/sys/dev/pci/pci_private.h Sun Dec 30 21:47:11 2012 (r244872) +++ projects/pciehp/sys/dev/pci/pci_private.h Sun Dec 30 22:00:19 2012 (r244873) @@ -126,4 +126,6 @@ void pci_cfg_restore(device_t, struct p */ void pci_cfg_save(device_t, struct pci_devinfo *, int); +void pci_hotplug_init(device_t dev); + #endif /* _PCI_PRIVATE_H_ */ Added: projects/pciehp/sys/dev/pci/pcie_hp.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ projects/pciehp/sys/dev/pci/pcie_hp.c Sun Dec 30 22:00:19 2012 (r244873) @@ -0,0 +1,270 @@ +/*- + * Copyright (c) 2012, Gavin Atkinson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_bus.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#if defined(__i386__) || defined(__amd64__) || defined(__powerpc__) +#include +#endif + +#include +#include +#include +#include + +#include "pcib_if.h" +#include "pci_if.h" + + +static struct resource_spec hotplug_res_spec_msi[] = { + { SYS_RES_IRQ, 1, RF_ACTIVE }, + { -1, 0, 0 } +}; + + +static void +pci_slot_status_print(device_t pcib) +{ + struct pci_devinfo *dinfo; + int pos; + + dinfo = device_get_ivars(pcib); + pos = dinfo->cfg.pcie.pcie_location; + device_printf(pcib, "... LINK_STA=0x%b\n", + pci_read_config(pcib, pos + PCIER_LINK_STA, 2), + "\020" + "\001" + "\002" + "\003" + "\004" + "\005" + "\006" + "\007" + "\010" + "\011" + "\012" + "\013Undef" + "\014LinkTrain" + "\015SlotClkConfig" + "\016DLLLinkActive" + "\017LinkBWManStat" + "\020LinkAutonBwStat" + ); +// device_printf(pcib, "... SLOT_CAP=0x%x\n", +// pci_read_config(pcib, pos+PCIER_SLOT_CAP, 4)); + device_printf(pcib, "... SLOT_CTL=0x%b\n", + pci_read_config(pcib, pos + PCIER_SLOT_CTL, 2), + "\020" + "\001AttnButtPressEn" + "\002PowerFaultDetEn" + "\003MRLSensChgEn" + "\004PresDetChgEn" + "\005CmdCompIntEn" + "\006HotPlugIntEn" + "\007AttnIndCtl1" + "\010AttnIndCtl2" + "\011PwrIndCtl1" + "\012PwrIndCtl2" + "\013PwrCtrlrCtl" + "\014ElecMechIntCtl" + "\015DLLStatChEn" + "\016" + "\017" + "\020" + ); + device_printf(pcib, "... SLOT_STA=0x%b\n", + pci_read_config(pcib, pos + PCIER_SLOT_STA, 2), + "\020" + "\001AttnButtPress" + "\002PowerFaultDet" + "\003MRLSensChg" + "\004PresDetChg" + "\005CmdComplete" + "\006MRLSensState" + "\007PresDetState" + "\010ElecMechIntState" + "\011DLLState" + "\012" + "\013" + "\014" + "\015" + "\016" + "\017" + "\020" + ); +} + +static void +pci_hotplug_intr_task(void *arg, int npending) +{ + device_t dev = arg; + device_t pcib = device_get_parent(dev); + device_t *devlistp; + struct pci_devinfo *dinfo; + int busno, devcnt, domain, i, pos; + int linksta, slotsta; + + dinfo = device_get_ivars(pcib); + pos = dinfo->cfg.pcie.pcie_location; + +// mtx_lock(&dinfo->cfg.hp.hp_mtx); + + linksta = pci_read_config(pcib, pos + PCIER_LINK_STA, 2); + slotsta = pci_read_config(pcib, pos + PCIER_SLOT_STA, 2); + pci_slot_status_print(pcib); +/* XXXGA: HACK AHEAD */ + if (slotsta & PCIEM_SLOT_STA_DLLSC) { + if ((linksta & PCIEM_LINK_STA_DL_ACTIVE) && dinfo->cfg.hp.hp_cnt == 0) { + dinfo->cfg.hp.hp_cnt=1; + /* delay really for DLLSC */ + DELAY(100000); /* section 6.7.3.3 */ + printf("Hotplug: Attaching children\n"); + mtx_lock(&Giant); + domain = pcib_get_domain(dev); + busno = pcib_get_bus(dev); + pci_add_children(dev, domain, busno, + sizeof(struct pci_devinfo)); + (void)bus_generic_attach(dev); + mtx_unlock(&Giant); + } else if (((linksta & PCIEM_LINK_STA_DL_ACTIVE) == 0) && dinfo->cfg.hp.hp_cnt == 1) { + printf("Hotplug: Detaching children\n"); + mtx_lock(&Giant); + /* XXXGA error checking */ + (void)bus_generic_detach(dev); + device_get_children(dev, &devlistp, &devcnt); + for (i = 0; i < devcnt; i++) + device_delete_child(dev, devlistp[i]); + free(devlistp, M_TEMP); + mtx_unlock(&Giant); + dinfo->cfg.hp.hp_cnt=0; + } else + printf("Hotplug: Ignoring\n"); + } +// mtx_unlock(&dinfo->cfg.hp.hp_mtx); +} + +static int +pci_hotplug_intr(void *arg) +{ + device_t dev = arg; + device_t pcib = device_get_parent(dev); + struct pci_devinfo *dinfo; + + device_printf(dev, "Received interrupt!\n"); +// pci_slot_status_print(pcib); + dinfo = device_get_ivars(pcib); + taskqueue_enqueue_fast(taskqueue_fast, &dinfo->cfg.hp.hp_inttask); + + return (FILTER_HANDLED); +} + +void +pci_hotplug_init(device_t dev) +{ + device_t pcib = device_get_parent(dev); + struct pci_devinfo *dinfo; + int error, flags, irq, msic, pos; + + dinfo = device_get_ivars(pcib); + pos = dinfo->cfg.pcie.pcie_location; + device_printf(dev, "dinfo=%p, pos=0x%x\n", dinfo, pos); + if (pos != 0) { + device_printf(dev, "Hotplug?\n"); + flags = pci_read_config(pcib, pos + PCIER_FLAGS, 2); + device_printf(dev, "... FLAGS = 0x%x\n", flags); + if (flags & PCIEM_FLAGS_SLOT) { + mtx_init(&dinfo->cfg.hp.hp_mtx, + device_get_nameunit(dev), "pciehp", MTX_DEF); + device_printf(dev, "... is slot!\n"); +/* XXX GAV: Check for SLOT_CAP_HPC here */ + pci_slot_status_print(pcib); + irq = (flags & PCIEM_FLAGS_IRQ) >> 9; + device_printf(dev, "IRQ = %d\n", irq); + + device_printf(dev, "MSI count self %d parent %d\n", pci_msi_count(dev), pci_msi_count(pcib)); + device_printf(dev, "MSI-X count self %d parent %d\n", pci_msix_count(dev), pci_msix_count(pcib)); + + msic = pci_msi_count(pcib); + if (msic == 1) { + if (pci_alloc_msi(pcib, &msic) == 0) { + if (msic == 1) { + device_printf(dev, "Using %d MSI messages\n", + msic); + dinfo->cfg.pcie.pcie_irq_spec = hotplug_res_spec_msi; + } else { + device_printf(dev, "Error: %d MSI messages\n", + msic); + pci_release_msi(dev); + } + } + } +/* XXX GAV: Am currently ignoring "irq" */ + error = bus_alloc_resources(pcib, dinfo->cfg.pcie.pcie_irq_spec, dinfo->cfg.pcie.pcie_res_irq); + if (error) { + device_printf(dev, "couldn't allocate IRQ resources, %d\n", error); + } else { + error = bus_setup_intr(pcib, dinfo->cfg.pcie.pcie_res_irq[0], + INTR_TYPE_AV | INTR_MPSAFE, pci_hotplug_intr, NULL, dev, + &dinfo->cfg.pcie.pcie_intrhand[0]); + if (error) { + device_printf(dev, "couldn't set up IRQ resources, %d\n", error); + } + } + TASK_INIT(&dinfo->cfg.hp.hp_inttask, 0, pci_hotplug_intr_task, dev); + /* XXXGA 6.7.3.1 don't enable things the slot doesn't support */ + flags = pci_read_config(pcib, pos + PCIER_SLOT_CTL, 2); + flags |= PCIEM_SLOT_CTL_PDCE | PCIEM_SLOT_CTL_MRLSCE | PCIEM_SLOT_CTL_HPIE | PCIEM_SLOT_CTL_DLLSCE; + pci_write_config(pcib, pos + PCIER_SLOT_CTL, flags, 2); + device_printf(dev, "Enabled interrupts\n"); + pci_slot_status_print(pcib); + } + } +} + Modified: projects/pciehp/sys/dev/pci/pcivar.h ============================================================================== --- projects/pciehp/sys/dev/pci/pcivar.h Sun Dec 30 21:47:11 2012 (r244872) +++ projects/pciehp/sys/dev/pci/pcivar.h Sun Dec 30 22:00:19 2012 (r244873) @@ -30,7 +30,10 @@ #ifndef _PCIVAR_H_ #define _PCIVAR_H_ +#include +#include #include +#include /* some PCI bus constants */ #define PCI_MAXMAPS_0 6 /* max. no. of memory/port maps */ @@ -123,6 +126,8 @@ struct pcicfg_ht { uint64_t ht_msiaddr; /* MSI mapping base address */ }; +#define PCIE_MSI_MESSAGES 2 + /* Interesting values for PCI-express */ struct pcicfg_pcie { uint8_t pcie_location; /* Offset of PCI-e capability registers. */ @@ -135,6 +140,9 @@ struct pcicfg_pcie { uint16_t pcie_device_ctl2; /* Second device control register. */ uint16_t pcie_link_ctl2; /* Second link control register. */ uint16_t pcie_slot_ctl2; /* Second slot control register. */ + struct resource_spec *pcie_irq_spec; + struct resource *pcie_res_irq[PCIE_MSI_MESSAGES]; + void *pcie_intrhand[PCIE_MSI_MESSAGES]; }; struct pcicfg_pcix { @@ -142,6 +150,13 @@ struct pcicfg_pcix { uint8_t pcix_location; /* Offset of PCI-X capability registers. */ }; +/* Interesting values for PCIe Hotplug */ +struct pcicfg_hp { + struct mtx hp_mtx; + struct task hp_inttask; + int hp_cnt; +}; + /* config header information common to all header types */ typedef struct pcicfg { struct device *dev; /* device which owns this */ @@ -185,6 +200,7 @@ typedef struct pcicfg { struct pcicfg_ht ht; /* HyperTransport */ struct pcicfg_pcie pcie; /* PCI Express */ struct pcicfg_pcix pcix; /* PCI-X */ + struct pcicfg_hp hp; /* Hotplug */ } pcicfgregs; /* additional type 1 device config header information (PCI to PCI bridge) */