Date: Wed, 17 Jan 2018 07:39:12 +0000 (UTC) From: Wojciech Macek <wma@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r328076 - head/sys/powerpc/powernv Message-ID: <201801170739.w0H7dCKw033550@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: wma Date: Wed Jan 17 07:39:11 2018 New Revision: 328076 URL: https://svnweb.freebsd.org/changeset/base/328076 Log: PowerNV: make PowerNV PCIe working on a real hardware Fixes: - map all devices to PE0 - use 1:1 TCE mapping - provide the same TCE mapping for all PEs (not only PE0) - add TCE reset and alignment (required by OPAL) Created by: Wojciech Macek <wma@semihalf.com> Obtained from: Semihalf Sponsored by: QCM Technologies Modified: head/sys/powerpc/powernv/opal.h head/sys/powerpc/powernv/opal_pci.c Modified: head/sys/powerpc/powernv/opal.h ============================================================================== --- head/sys/powerpc/powernv/opal.h Wed Jan 17 06:31:21 2018 (r328075) +++ head/sys/powerpc/powernv/opal.h Wed Jan 17 07:39:11 2018 (r328076) @@ -65,10 +65,13 @@ int opal_call(uint64_t token, ...); #define OPAL_GET_MSI_32 39 #define OPAL_GET_MSI_64 40 #define OPAL_PCI_MSI_EOI 63 +#define OPAL_PCI_GET_PHB_DIAG_DATA2 64 #define OPAL_START_CPU 41 +#define OPAL_PCI_MAP_PE_DMA_WINDOW 44 #define OPAL_PCI_MAP_PE_DMA_WINDOW_REAL 45 #define OPAL_RETURN_CPU 69 #define OPAL_REINIT_CPUS 70 +#define OPAL_PCI_TCE_KILL 126 /* For OPAL_PCI_SET_PE */ #define OPAL_UNMAP_PE 0 Modified: head/sys/powerpc/powernv/opal_pci.c ============================================================================== --- head/sys/powerpc/powernv/opal_pci.c Wed Jan 17 06:31:21 2018 (r328075) +++ head/sys/powerpc/powernv/opal_pci.c Wed Jan 17 07:39:11 2018 (r328076) @@ -1,5 +1,6 @@ /*- * Copyright (c) 2015-2016 Nathan Whitehorn + * Copyright (c) 2017-2018 Semihalf * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -58,6 +59,12 @@ __FBSDID("$FreeBSD$"); #include "iommu_if.h" #include "opal.h" +#define OPAL_PCI_TCE_MAX_ENTRIES (1024*1024UL) +#define OPAL_PCI_TCE_SEG_SIZE (16*1024*1024UL) +#define OPAL_PCI_TCE_R (1UL << 0) +#define OPAL_PCI_TCE_W (1UL << 1) +#define PHB3_TCE_KILL_INVAL_ALL (1UL << 63) + /* * Device interface. */ @@ -148,6 +155,8 @@ struct opalpci_softc { vmem_t *msi_vmem; int msi_base; /* Base XIVE number */ int base_msi_irq; /* Base IRQ assigned by FreeBSD to this PIC */ + uint64_t *tce; /* TCE table for 1:1 mapping */ + struct resource *r_reg; }; static devclass_t opalpci_devclass; @@ -177,12 +186,24 @@ opalpci_probe(device_t dev) return (BUS_PROBE_GENERIC); } +static void +pci_phb3_tce_invalidate_entire(struct opalpci_softc *sc) +{ + + mb(); + bus_write_8(sc->r_reg, 0x210, PHB3_TCE_KILL_INVAL_ALL); + mb(); +} + static int opalpci_attach(device_t dev) { struct opalpci_softc *sc; cell_t id[2], m64window[6], npe; int i, err; + uint64_t maxmem; + uint64_t entries; + int rid; sc = device_get_softc(dev); @@ -204,6 +225,15 @@ opalpci_attach(device_t dev) if (bootverbose) device_printf(dev, "OPAL ID %#lx\n", sc->phb_id); + rid = 0; + sc->r_reg = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &rid, RF_ACTIVE | RF_SHAREABLE); + if (sc->r_reg == NULL) { + device_printf(dev, "Failed to allocate PHB[%jd] registers\n", + (uintmax_t)sc->phb_id); + return (ENXIO); + } + /* * Reset PCI IODA table */ @@ -214,47 +244,12 @@ opalpci_attach(device_t dev) return (ENXIO); } while ((err = opal_call(OPAL_PCI_POLL, sc->phb_id)) > 0) - DELAY(1000*err); /* Returns expected delay in ms */ + DELAY(1000*(err + 1)); /* Returns expected delay in ms */ if (err < 0) { - device_printf(dev, "PHB IODA reset poll failed: %d\n", err); - return (ENXIO); + device_printf(dev, "WARNING: PHB IODA reset poll failed: %d\n", err); } /* - * Reset everything. Especially important if we have inherited the - * system from Linux by kexec() - */ -#ifdef NOTYET - if (bootverbose) - device_printf(dev, "Resetting PCI bus\n"); - err = opal_call(OPAL_PCI_RESET, sc->phb_id, OPAL_RESET_PHB_COMPLETE, 1); - if (err < 0) { - device_printf(dev, "PHB reset failed: %d\n", err); - return (ENXIO); - } - while ((err = opal_call(OPAL_PCI_POLL, sc->phb_id)) > 0) - DELAY(1000*err); /* Returns expected delay in ms */ - if (err < 0) { - device_printf(dev, "PHB reset poll failed: %d\n", err); - return (ENXIO); - } - DELAY(10000); - err = opal_call(OPAL_PCI_RESET, sc->phb_id, OPAL_RESET_PHB_COMPLETE, 0); - if (err < 0) { - device_printf(dev, "PHB reset completion failed: %d\n", err); - return (ENXIO); - } - while ((err = opal_call(OPAL_PCI_POLL, sc->phb_id)) > 0) - DELAY(1000*err); /* Returns expected delay in ms */ - if (err < 0) { - device_printf(dev, "PHB reset completion poll failed: %d\n", - err); - return (ENXIO); - } - DELAY(10000); -#endif - - /* * Map all devices on the bus to partitionable endpoint one until * such time as we start wanting to do things like bhyve. */ @@ -282,6 +277,8 @@ opalpci_attach(device_t dev) /* XXX: multiple M64 windows? */ if (OF_getencprop(ofw_bus_get_node(dev), "ibm,opal-m64-window", m64window, sizeof(m64window)) == sizeof(m64window)) { + opal_call(OPAL_PCI_PHB_MMIO_ENABLE, sc->phb_id, + OPAL_M64_WINDOW_TYPE, 0, 0); opal_call(OPAL_PCI_SET_PHB_MEM_WINDOW, sc->phb_id, OPAL_M64_WINDOW_TYPE, 0 /* index */, ((uint64_t)m64window[2] << 32) | m64window[3], 0, @@ -294,21 +291,54 @@ opalpci_attach(device_t dev) } /* - * Also disable the IOMMU for the time being for PE 1 (everything) + * Enable IOMMU for PE1 - map everything 1:1 using + * segments of OPAL_PCI_TCE_SEG_SIZE size */ + maxmem = roundup2(powerpc_ptob(Maxmem), OPAL_PCI_TCE_SEG_SIZE); + entries = maxmem / OPAL_PCI_TCE_SEG_SIZE; + if (entries > OPAL_PCI_TCE_MAX_ENTRIES) + panic("POWERNV supports only %jdGB of memory space\n", + (uintmax_t)((OPAL_PCI_TCE_MAX_ENTRIES * OPAL_PCI_TCE_SEG_SIZE) >> 30)); if (bootverbose) - device_printf(dev, "Mapping 0-%#lx for DMA\n", - roundup2(powerpc_ptob(Maxmem), 16*1024*1024)); - err = opal_call(OPAL_PCI_MAP_PE_DMA_WINDOW_REAL, sc->phb_id, - OPAL_PCI_DEFAULT_PE, OPAL_PCI_DEFAULT_PE << 1, - 0 /* start address */, roundup2(powerpc_ptob(Maxmem), - 16*1024*1024)/* all RAM */); - if (err != 0) { - device_printf(dev, "DMA mapping failed: %d\n", err); - return (ENXIO); + device_printf(dev, "Mapping 0-%#jx for DMA\n", (uintmax_t)maxmem); + sc->tce = contigmalloc(OPAL_PCI_TCE_MAX_ENTRIES * sizeof(uint64_t), + M_DEVBUF, M_NOWAIT | M_ZERO, 0, + BUS_SPACE_MAXADDR_32BIT, OPAL_PCI_TCE_SEG_SIZE, 0); + if (sc->tce == NULL) + panic("Failed to allocate TCE memory for PHB %jd\n", + (uintmax_t)sc->phb_id); + + for (i = 0; i < entries; i++) + sc->tce[i] = (i * OPAL_PCI_TCE_SEG_SIZE) | OPAL_PCI_TCE_R | OPAL_PCI_TCE_W; + + /* Map TCE for every PE. It seems necessary for Power8 */ + for (i = 0; i < npe; i++) { + err = opal_call(OPAL_PCI_MAP_PE_DMA_WINDOW, sc->phb_id, + i, (i << 1), + 1, pmap_kextract((uint64_t)&sc->tce[0]), + OPAL_PCI_TCE_MAX_ENTRIES * sizeof(uint64_t), OPAL_PCI_TCE_SEG_SIZE); + if (err != 0) { + device_printf(dev, "DMA IOMMU mapping failed: %d\n", err); + return (ENXIO); + } + + err = opal_call(OPAL_PCI_MAP_PE_DMA_WINDOW_REAL, sc->phb_id, + i, (i << 1) + 1, + (1UL << 59), maxmem); + if (err != 0) { + device_printf(dev, "DMA 64b bypass mapping failed: %d\n", err); + return (ENXIO); + } } /* + * Invalidate all previous TCE entries. + * + * TODO: add support for other PHBs than PHB3 + */ + pci_phb3_tce_invalidate_entire(sc); + + /* * Get MSI properties */ sc->msi_vmem = NULL; @@ -457,6 +487,7 @@ opalpci_write_config(device_t dev, u_int bus, u_int sl static int opalpci_route_interrupt(device_t bus, device_t dev, int pin) { + return (pin); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201801170739.w0H7dCKw033550>