From owner-svn-src-all@freebsd.org Tue Sep 3 14:08:15 2019 Return-Path: Delivered-To: svn-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id CE79FDD9C5; Tue, 3 Sep 2019 14:07:22 +0000 (UTC) (envelope-from yuripv@freebsd.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2610:1c1:1:6074::16:84]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "freefall.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 46N80V2SQTz4QXK; Tue, 3 Sep 2019 14:07:22 +0000 (UTC) (envelope-from yuripv@freebsd.org) Received: by freefall.freebsd.org (Postfix, from userid 1452) id EB3101B502; Tue, 3 Sep 2019 14:06:36 +0000 (UTC) X-Original-To: yuripv@localmail.freebsd.org Delivered-To: yuripv@localmail.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [96.47.72.80]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (Client CN "mx1.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by freefall.freebsd.org (Postfix) with ESMTPS id E5EBB10530; Mon, 22 Apr 2019 15:04:23 +0000 (UTC) (envelope-from owner-src-committers@freebsd.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2610:1c1:1:6074::16:84]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "freefall.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 330948EFDF; Mon, 22 Apr 2019 15:04:23 +0000 (UTC) (envelope-from owner-src-committers@freebsd.org) Received: by freefall.freebsd.org (Postfix, from userid 538) id 34FDE1047C; Mon, 22 Apr 2019 15:04:17 +0000 (UTC) Delivered-To: src-committers@localmail.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [96.47.72.80]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (Client CN "mx1.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by freefall.freebsd.org (Postfix) with ESMTPS id 48130103B0 for ; Mon, 22 Apr 2019 15:04:14 +0000 (UTC) (envelope-from ian@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 1C2E68EF09; Mon, 22 Apr 2019 15:04:14 +0000 (UTC) (envelope-from ian@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id EAE4EE9FD; Mon, 22 Apr 2019 15:04:13 +0000 (UTC) (envelope-from ian@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x3MF4D1o062942; Mon, 22 Apr 2019 15:04:13 GMT (envelope-from ian@FreeBSD.org) Received: (from ian@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x3MF4COV062860; Mon, 22 Apr 2019 15:04:12 GMT (envelope-from ian@FreeBSD.org) Message-Id: <201904221504.x3MF4COV062860@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: ian set sender to ian@FreeBSD.org using -f From: Ian Lepore To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r346557 - in stable/11: share/man/man4 sys/conf sys/dev/fdt sys/dev/flash sys/dev/spibus sys/modules sys/modules/fdt sys/modules/fdt/fdt_slicer sys/sys X-SVN-Group: stable-11 X-SVN-Commit-Author: ian X-SVN-Commit-Paths: in stable/11: share/man/man4 sys/conf sys/dev/fdt sys/dev/flash sys/dev/spibus sys/modules sys/modules/fdt sys/modules/fdt/fdt_slicer sys/sys X-SVN-Commit-Revision: 346557 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk X-Loop: FreeBSD.org Sender: owner-src-committers@freebsd.org X-Rspamd-Queue-Id: 330948EFDF X-Spamd-Bar: -- Authentication-Results: mx1.freebsd.org X-Spamd-Result: default: False [-2.97 / 15.00]; local_wl_from(0.00)[freebsd.org]; NEURAL_HAM_MEDIUM(-1.00)[-1.000,0]; NEURAL_HAM_SHORT(-0.98)[-0.975,0]; ASN(0.00)[asn:11403, ipnet:2610:1c1:1::/48, country:US]; NEURAL_HAM_LONG(-1.00)[-1.000,0] Status: O X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.29 List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Date: Tue, 03 Sep 2019 14:08:15 -0000 X-Original-Date: Mon, 22 Apr 2019 15:04:12 +0000 (UTC) X-List-Received-Date: Tue, 03 Sep 2019 14:08:15 -0000 Author: ian Date: Mon Apr 22 15:04:11 2019 New Revision: 346557 URL: https://svnweb.freebsd.org/changeset/base/346557 Log: MFC r335159, r344505-r344507, r344523, r344525-r344526, r344529, r344556, r344606-r344612, r344614-r344616, r344681, r344684-r344686, r344728, r344733-r344734, r344981 A large set of changes that collectively modernize the at45d and mx25l (DataFlash and SpiFlash) drivers, add FDT support, and add geom_flashmap support to them. r335159 by manu: mx25l: Add pnp info r344505: Add a functional detach() implementation to make module unloading possible. r344506: Add support for probing/attaching on FDT-based systems. r344507: Switch to using config_intrhook_oneshot(). That allows the error handling in the delayed attach to use early returns, which allows reducing the level of indentation. So all in all, what looks like a lot of changes is really no change in behavior, mostly just moving whitespace around. r344523: Include the jedec "extended device information string" in the criteria used to match a chip to our table of metadata describing the chips. At least one new DataFlash chip has a 3-byte jedec ID identical to its predecessors and differs only in the extended info, and it has different metadata requiring a unique entry in the table. This paves the way for supporting such chips. The metadata table now includes two new fields, extmask and extid. The two bytes of extended info obtained from the chip are ANDed with extmask then compared to extid, so it's possible to use only a subset of the extended info in the matching. We now always read 6 bytes of jedec ID info. Most chips don't return any extended info, and the values read back for those two bytes may be indeterminate, but such chips have extmask and extid values of 0x0000 in the table, so the extid effectively doesn't participate in the matching on those chips and it doesn't matter what they return in the extended info bytes. r344525: Add a metadata entry for the AT45DB641E chip. This chip has the same 3-byte jedec ID as its older cousin the AT45DB642D, but uses a different page size. The only way to distinguish between the two chips is that the 2D chip has 0 bytes of extended ID info and the new 1E has 1 byte of extended ID. The actual value of the extended ID byte is all zeroes. In other words, it's the presence of the extended info that identifies this chip. (Presumably a future upgrade might define non-zero values for the extended ID byte.) r344526: Resolve a name conflict when both SpiFlash and DataFlash devices are present. Both SpiFlash (mx25l) and DataFlash (at45d) drivers create a disk device with a name of /dev/flash/spiN where N is the driver's unit number. If both types of devices are present in the same system, this creates a fatal conflict that prevents attachment of whichever device attaches second (because mx25l0 and at45d0 both try to create a spi0). This gives each type of device a unique name (mx25lN or at45dN respectively) and also adds an alias of spiN for compatibility. When both device types appear in the same system, only the first to attach gets the spiN alias. When the second device attaches there is a non-fatal warning that the alias can't be created, but both devices are still accessible via their primary names (and there is no need for the spiN name to work for backwards compatibility on such a system, because it has never been possible to use the spiN names when both devices exist). r344529: Fix a paste-o that broke the build on all arches. r344556: Set maximum bus clock speed from hints when attaching hinted spibus(4) children. Some devices (such as spigen(4)) document that this works, but it appears that the code to implement it never got added. r344606: Add support for geom_flashmap by providing a getattr() for "SPI:device". r344607: Compile fdt_slicer and geom_flashmap when the at45d device is included. r344608: Update a comment to reflect reality; no functional changes. r344609: Make it possible to load fdt_slicer as a module (unloading works too fwiw). r344610: Add manpages for at45d(4) and mx25l(4). r344611: Add a module dependency on fdt_slicer. r344612: Add a module dependency on fdt_slicer. Also, move the PNP_INFO to its more usual location, down near the DRIVER_MODULE() stuff. r344614: Rename some functions and variables to have shorter names, which allows unwrapping multiple lines of code. Also, convert some short multiline comments into single-line comments. Change old-school FALSE to false. All in all, no functional changes, it's just more compact and readable. r344615: Child nodes with a compatible property are not slices, according to the devicetree/bindings/mtd/partitions.txt document, so just ignore them. r344616: Add support to fdt_slicer for the new style partition data documented in devicetree/bindings/mtd/partition.txt. In the old style, all the children of the device node which did not have a compatible property were the partitions. In the new style, there is a child node of the device which has a compatible string of "fixed-partitions", and its children are the individual partitions. Also, support the read-only property by setting the corresponding slice flag. r344681: Build fdt support modules on systems that use fdt data. kern.opts.mk sets make var OPT_FDT to a non-empty value if platform.h contains OPT_FDT. r344684: Undo accidental part of r344681. I think I must have accidentally mouse-click pasted while scrolling and didn't notice it. r344685: Add required header file to SRCS. r344686: Add another required header file. For some reason this seems to be required on aarch64, but I can build armv7 from clean without needing this in the list. (The file does get included, so the mystery is why armv7 works.) r344728: Bugfix: use a dummy buffer for the inactive side of a transfer. This is especially important for writes. SPI is inherently a bidirectional bus; you receive data (even if it's garbage) while writing. We should not receive that data into the same buffer we're writing to the device. When reading it doesn't matter what we send to the device, but using the dummy buffer for that as well is pleasingly symmetrical. r344733: Add some comments. Give #define'd names to some scattered numbers. Change some #define'd names to be more descriptive. When reporting a post-write compare failure, report the page number, not the byte address of the page. The latter is the only functional change, it makes the number match the words of the error message. r344734: Allow the sector size of the disk device to be configured using hints or FDT data. The sector size must be a multiple of the device's page size. If not configured, use the historical default of the device page size. Setting the disk sector size to 512 or 4096 allows a variety of standard filesystems to be used on the device. Of course you wouldn't want to be writing frequently to a SPI flash chip like it was a disk drive, but for data that gets written once (or rarely) and read often, using a standard filesystem is a nice convenient thing. r344981: Give the mx25l device sole ownership of the name /dev/flash/spi* instead of trying to use disk_add_alias() to make spi* an alias for mx25l*. It turns out disk_add_alias() works for partitions, but not slices, and that's hard to fix. This change is, in effect, a partial revert of r344526. The mips world relies on the existence of flashmap names formatted as /dev/flash/spi0s.name, whereas pretty much nothing relies on at45d devices using the /dev/spi* names (because until recently the at45d driver didn't even work reliably). So this change makes mx25l devices the sole owner of the /dev/flash/spi* namespace, which actually makes some sense because it is a SpiFlash(tm) device, so flash/spi isn't a horrible name. Added: stable/11/share/man/man4/at45d.4 - copied, changed from r344612, head/share/man/man4/at45d.4 stable/11/share/man/man4/mx25l.4 - copied unchanged from r344612, head/share/man/man4/mx25l.4 stable/11/sys/modules/fdt/ - copied from r344612, head/sys/modules/fdt/ Modified: stable/11/share/man/man4/Makefile stable/11/sys/conf/files stable/11/sys/dev/fdt/fdt_slicer.c stable/11/sys/dev/flash/at45d.c stable/11/sys/dev/flash/mx25l.c stable/11/sys/dev/spibus/spibus.c stable/11/sys/modules/Makefile stable/11/sys/modules/fdt/fdt_slicer/Makefile stable/11/sys/sys/slicer.h Directory Properties: stable/11/ (props changed) Modified: stable/11/share/man/man4/Makefile ============================================================================== --- stable/11/share/man/man4/Makefile Mon Apr 22 14:53:53 2019 (r346556) +++ stable/11/share/man/man4/Makefile Mon Apr 22 15:04:11 2019 (r346557) @@ -55,6 +55,7 @@ MAN= aac.4 \ ${_apic.4} \ arcmsr.4 \ ${_asmc.4} \ + at45d.4 \ ata.4 \ ath.4 \ ath_ahb.4 \ @@ -314,6 +315,7 @@ MAN= aac.4 \ mvs.4 \ mwl.4 \ mwlfw.4 \ + mx25l.4 \ mxge.4 \ my.4 \ nand.4 \ Copied and modified: stable/11/share/man/man4/at45d.4 (from r344612, head/share/man/man4/at45d.4) ============================================================================== --- head/share/man/man4/at45d.4 Tue Feb 26 22:52:41 2019 (r344612, copy source) +++ stable/11/share/man/man4/at45d.4 Mon Apr 22 15:04:11 2019 (r346557) @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd February 26, 2019 +.Dd March 2, 2019 .Dt AT45D 4 .Os .Sh NAME @@ -126,6 +126,10 @@ The following properties are optional for the .Nm device subnode: .Bl -tag -width indent +.It Va freebsd,sectorsize +The sector size of the disk created for this storage device. +It must be a multiple of the device's page size. +The default is the device page size. .It Va spi-cpha Empty property indicating the slave device requires shifted clock phase (CPHA) mode. @@ -156,6 +160,10 @@ The chip-select number to assert when performing I/O f Set the high bit (1 << 31) to invert the logic level of the chip select line. .It Va hint.at45d.%d.mode The SPI mode (0-3) to use when communicating with this device. +.It Va hint.at45d.%d.sectorsize +The sector size of the disk created for this storage device. +It must be a multiple of the device's page size. +The default is the device page size. .El .Sh FILES .Bl -tag -width /dev/flash/at45d? Copied: stable/11/share/man/man4/mx25l.4 (from r344612, head/share/man/man4/mx25l.4) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ stable/11/share/man/man4/mx25l.4 Mon Apr 22 15:04:11 2019 (r346557, copy of r344612, head/share/man/man4/mx25l.4) @@ -0,0 +1,209 @@ +.\" +.\" Copyright (c) 2019 Ian Lepore +.\" +.\" 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, 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. +.\" +.\" $FreeBSD$ +.\" +.Dd February 26, 2019 +.Dt MX25L 4 +.Os +.Sh NAME +.Nm mx25l +.Nd driver for SpiFlash(tm) compatible non-volatile storage devices +.Sh SYNOPSIS +To compile this driver into the kernel, +place the following line in your +kernel configuration file: +.Bd -ragged -offset indent +.Cd "device mx25l" +.Ed +.Pp +Alternatively, to load the driver as a +module at boot time, place the following line in +.Xr loader.conf 5 : +.Bd -literal -offset indent +mx25l_load="YES" +.Ed +.Sh DESCRIPTION +The +.Nm +driver provides support for the family of non-volatile storage +devices known collectively as SpiFlash(tm). +SpiFlash chips typically have part numbers beginning with EN25, +IS25, MX25, S25, SST25, or W25. +.Pp +The +.Nm +driver uses opcode 0x9f to read the manufacturer and device ID +data to determine whether the device is supported. +The device ID is looked up using a table of data within the driver +which describes the attributes of each supported device, +such as block size, sector size, and device capacity. +When a supported device is found, the +.Nm +driver creates a disk device and makes it accessible at +.Pa /dev/flash/mx25l? . +The new disk device is then tasted by the available +.Xr geom 4 +modules as with any disk device. +.Sh HARDWARE +The +.Nm +driver provides support for the following devices: +.Pp +.Bl -bullet -compact +.It +AT25DF641 +.It +EN25F32 +.It +EN25P32 +.It +EN25P64 +.It +EN25Q32 +.It +EN25Q64 +.It +GD25Q64 +.It +M25P32 +.It +M25P64 +.It +MX25L1606E +.It +MX25LL128 +.It +MX25LL256 +.It +MX25LL32 +.It +MX25LL64 +.It +S25FL032 +.It +S25FL064 +.It +S25FL128 +.It +S25FL256S +.It +SST25VF010A +.It +SST25VF032B +.It +W25Q128 +.It +W25Q256 +.It +W25Q32 +.It +W25Q64 +.It +W25Q64BV +.It +W25X32 +.It +W25X64 +.El +.Sh FDT CONFIGURATION +On an +.Xr fdt 4 +based system, the +.Nm +device is defined as a slave device subnode +of the SPI bus controller node. +All properties documented in the +.Va spibus.txt +bindings document can be used with the +.Nm +device. +The most commonly-used ones are documented below. +.Pp +The following properties are required in the +.Nm +device subnode: +.Bl -tag -width indent +.It Va compatible +Must be the string "jedec,spi-nor". +.It Va reg +Chip select address of device. +.It Va spi-max-frequency +The maximum bus frequency to use when communicating with this slave device. +Actual bus speed may be lower, depending on the capabilities of the SPI +bus controller hardware. +.El +.Pp +The following properties are optional for the +.Nm +device subnode: +.Bl -tag -width indent +.It Va spi-cpha +Empty property indicating the slave device requires shifted clock +phase (CPHA) mode. +.It Va spi-cpol +Empty property indicating the slave device requires inverse clock +polarity (CPOL) mode. +.It Va spi-cs-high +Empty property indicating the slave device requires chip select active high. +.El +.Sh HINTS CONFIGURATION +On a +.Xr device.hints 5 +based system, such as +.Li MIPS , +these values are configurable for +.Nm : +.Bl -tag -width indent +.It Va hint.mx25l.%d.at +The spibus the +.Nm +instance is attached to. +.It Va hint.mx25l.%d.clock +The maximum bus frequency to use when communicating with this device. +Actual bus speed may be lower, depending on the capabilities of the SPI +bus controller hardware. +.It Va hint.mx25l.%d.cs +The chip-select number to assert when performing I/O for this device. +Set the high bit (1 << 31) to invert the logic level of the chip select line. +.It Va hint.mx25l.%d.mode +The SPI mode (0-3) to use when communicating with this device. +.El +.Sh FILES +.Bl -tag -width /dev/flash/mx25l? +.It Pa /dev/flash/mx25l? +Provides read/write access to the storage device. +.It Pa /dev/flash/spi? +An alias for the +.Pa /dev/mx25l? +device, for backwards compatibility with older versions of the driver. +.El +.Sh SEE ALSO +.Xr fdt 4 , +.Xr geom 4 +.Sh HISTORY +The +.Nm +driver first appeared in +.Fx 8.0 . Modified: stable/11/sys/conf/files ============================================================================== --- stable/11/sys/conf/files Mon Apr 22 14:53:53 2019 (r346556) +++ stable/11/sys/conf/files Mon Apr 22 15:04:11 2019 (r346557) @@ -1724,7 +1724,7 @@ dev/fdt/fdt_clock_if.m optional fdt fdt_clock dev/fdt/fdt_common.c optional fdt dev/fdt/fdt_pinctrl.c optional fdt fdt_pinctrl dev/fdt/fdt_pinctrl_if.m optional fdt fdt_pinctrl -dev/fdt/fdt_slicer.c optional fdt cfi | fdt nand | fdt mx25l +dev/fdt/fdt_slicer.c optional fdt cfi | fdt nand | fdt mx25l | fdt at45d dev/fdt/fdt_static_dtb.S optional fdt fdt_dtb_static \ dependency "fdt_dtb_file" dev/fdt/simplebus.c optional fdt @@ -3456,7 +3456,7 @@ geom/geom_disk.c standard geom/geom_dump.c standard geom/geom_event.c standard geom/geom_fox.c optional geom_fox -geom/geom_flashmap.c optional fdt cfi | fdt nand | fdt mx25l | mmcsd +geom/geom_flashmap.c optional fdt cfi | fdt nand | fdt mx25l | mmcsd | fdt at45d geom/geom_io.c standard geom/geom_kern.c standard geom/geom_map.c optional geom_map Modified: stable/11/sys/dev/fdt/fdt_slicer.c ============================================================================== --- stable/11/sys/dev/fdt/fdt_slicer.c Mon Apr 22 14:53:53 2019 (r346556) +++ stable/11/sys/dev/fdt/fdt_slicer.c Mon Apr 22 15:04:11 2019 (r346557) @@ -30,6 +30,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -43,42 +44,34 @@ __FBSDID("$FreeBSD$"); #define debugf(fmt, args...) #endif -static int fdt_flash_fill_slices(device_t dev, const char *provider, +static int fill_slices(device_t dev, const char *provider, struct flash_slice *slices, int *slices_num); static void fdt_slicer_init(void); static int -fdt_flash_fill_slices(device_t dev, const char *provider __unused, - struct flash_slice *slices, int *slices_num) +fill_slices_from_node(phandle_t node, struct flash_slice *slices, int *count) { - char *slice_name; - phandle_t dt_node, dt_child; + char *label; + phandle_t child; u_long base, size; - int i; - ssize_t name_len; + int flags, i; + ssize_t nmlen; - /* - * We assume the caller provides buffer for FLASH_SLICES_MAX_NUM - * flash_slice structures. - */ - if (slices == NULL) { - *slices_num = 0; - return (ENOMEM); - } + i = 0; + for (child = OF_child(node); child != 0; child = OF_peer(child)) { + flags = FLASH_SLICES_FLAG_NONE; - dt_node = ofw_bus_get_node(dev); - for (dt_child = OF_child(dt_node), i = 0; dt_child != 0; - dt_child = OF_peer(dt_child)) { + /* Nodes with a compatible property are not slices. */ + if (OF_hasprop(child, "compatible")) + continue; if (i == FLASH_SLICES_MAX_NUM) { debugf("not enough buffer for slice i=%d\n", i); break; } - /* - * Retrieve start and size of the slice. - */ - if (fdt_regsize(dt_child, &base, &size) != 0) { + /* Retrieve start and size of the slice. */ + if (fdt_regsize(child, &base, &size) != 0) { debugf("error during processing reg property, i=%d\n", i); continue; @@ -89,50 +82,104 @@ fdt_flash_fill_slices(device_t dev, const char *provid continue; } - /* - * Retrieve label. - */ - name_len = OF_getprop_alloc(dt_child, "label", sizeof(char), - (void **)&slice_name); - if (name_len <= 0) { + /* Retrieve label. */ + nmlen = OF_getprop_alloc(child, "label", sizeof(char), + (void **)&label); + if (nmlen <= 0) { /* Use node name if no label defined */ - name_len = OF_getprop_alloc(dt_child, "name", - sizeof(char), (void **)&slice_name); - if (name_len <= 0) { + nmlen = OF_getprop_alloc(child, "name", sizeof(char), + (void **)&label); + if (nmlen <= 0) { debugf("slice i=%d with no name\n", i); - slice_name = NULL; + label = NULL; } } - /* - * Fill slice entry data. - */ + if (OF_hasprop(child, "read-only")) + flags |= FLASH_SLICES_FLAG_RO; + + /* Fill slice entry data. */ slices[i].base = base; slices[i].size = size; - slices[i].label = slice_name; + slices[i].label = label; + slices[i].flags = flags; i++; } - *slices_num = i; + *count = i; return (0); } +static int +fill_slices(device_t dev, const char *provider __unused, + struct flash_slice *slices, int *slices_num) +{ + phandle_t child, node; + + /* + * We assume the caller provides buffer for FLASH_SLICES_MAX_NUM + * flash_slice structures. + */ + if (slices == NULL) { + *slices_num = 0; + return (ENOMEM); + } + + node = ofw_bus_get_node(dev); + + /* + * If there is a child node whose compatible is "fixed-partitions" then + * we have new-style data where all partitions are the children of that + * node. Otherwise we have old-style data where all the children of the + * device node are the partitions. + */ + child = fdt_find_compatible(node, "fixed-partitions", false); + if (child == 0) + return fill_slices_from_node(node, slices, slices_num); + else + return fill_slices_from_node(child, slices, slices_num); +} + static void fdt_slicer_init(void) { - flash_register_slicer(fdt_flash_fill_slices, FLASH_SLICES_TYPE_NAND, - FALSE); - flash_register_slicer(fdt_flash_fill_slices, FLASH_SLICES_TYPE_CFI, - FALSE); - flash_register_slicer(fdt_flash_fill_slices, FLASH_SLICES_TYPE_SPI, - FALSE); + flash_register_slicer(fill_slices, FLASH_SLICES_TYPE_NAND, false); + flash_register_slicer(fill_slices, FLASH_SLICES_TYPE_CFI, false); + flash_register_slicer(fill_slices, FLASH_SLICES_TYPE_SPI, false); } +static void +fdt_slicer_cleanup(void) +{ + + flash_register_slicer(NULL, FLASH_SLICES_TYPE_NAND, true); + flash_register_slicer(NULL, FLASH_SLICES_TYPE_CFI, true); + flash_register_slicer(NULL, FLASH_SLICES_TYPE_SPI, true); +} + /* * Must be initialized after GEOM classes (SI_SUB_DRIVERS/SI_ORDER_FIRST), * i. e. after g_init() is called, due to the use of the GEOM topology_lock * in flash_register_slicer(). However, must be before SI_SUB_CONFIGURE. */ -SYSINIT(fdt_slicer_rootconf, SI_SUB_DRIVERS, SI_ORDER_SECOND, fdt_slicer_init, - NULL); +SYSINIT(fdt_slicer, SI_SUB_DRIVERS, SI_ORDER_SECOND, fdt_slicer_init, NULL); +SYSUNINIT(fdt_slicer, SI_SUB_DRIVERS, SI_ORDER_SECOND, fdt_slicer_cleanup, NULL); + +static int +mod_handler(module_t mod, int type, void *data) +{ + + /* + * Nothing to do here: the SYSINIT/SYSUNINIT defined above run + * automatically at module load/unload time. + */ + return (0); +} + +static moduledata_t fdt_slicer_mod = { + "fdt_slicer", mod_handler, NULL +}; + +DECLARE_MODULE(fdt_slicer, fdt_slicer_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND); +MODULE_VERSION(fdt_slicer, 1); Modified: stable/11/sys/dev/flash/at45d.c ============================================================================== --- stable/11/sys/dev/flash/at45d.c Mon Apr 22 14:53:53 2019 (r346556) +++ stable/11/sys/dev/flash/at45d.c Mon Apr 22 15:04:11 2019 (r346557) @@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -45,10 +46,36 @@ __FBSDID("$FreeBSD$"); #include #include "spibus_if.h" +#include "opt_platform.h" + +#ifdef FDT +#include +#include +#include + +static struct ofw_compat_data compat_data[] = { + { "atmel,at45", 1 }, + { "atmel,dataflash", 1 }, + { NULL, 0 }, +}; +#endif + +/* This is the information returned by the MANUFACTURER_ID command. */ +struct at45d_mfg_info { + uint32_t jedec_id; /* Mfg ID, DevId1, DevId2, ExtLen */ + uint16_t ext_id; /* ExtId1, ExtId2 */ +}; + +/* + * This is an entry in our table of metadata describing the chips. We match on + * both jedec id and extended id info returned by the MANUFACTURER_ID command. + */ struct at45d_flash_ident { const char *name; uint32_t jedec; + uint16_t extid; + uint16_t extmask; uint16_t pagecount; uint16_t pageoffset; uint16_t pagesize; @@ -61,13 +88,18 @@ struct at45d_softc struct mtx sc_mtx; struct disk *disk; struct proc *p; - struct intr_config_hook config_intrhook; device_t dev; + u_int taskstate; uint16_t pagecount; uint16_t pageoffset; uint16_t pagesize; + void *dummybuf; }; +#define TSTATE_STOPPED 0 +#define TSTATE_STOPPING 1 +#define TSTATE_RUNNING 2 + #define AT45D_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) #define AT45D_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) #define AT45D_LOCK_INIT(_sc) \ @@ -85,36 +117,51 @@ static device_probe_t at45d_probe; /* disk routines */ static int at45d_close(struct disk *dp); static int at45d_open(struct disk *dp); +static int at45d_getattr(struct bio *bp); static void at45d_strategy(struct bio *bp); static void at45d_task(void *arg); /* helper routines */ static void at45d_delayed_attach(void *xsc); -static int at45d_get_mfg_info(device_t dev, uint8_t *resp); +static int at45d_get_mfg_info(device_t dev, struct at45d_mfg_info *resp); static int at45d_get_status(device_t dev, uint8_t *status); static int at45d_wait_ready(device_t dev, uint8_t *status); -#define BUFFER_TRANSFER 0x53 -#define BUFFER_COMPARE 0x60 +#define PAGE_TO_BUFFER_TRANSFER 0x53 +#define PAGE_TO_BUFFER_COMPARE 0x60 #define PROGRAM_THROUGH_BUFFER 0x82 #define MANUFACTURER_ID 0x9f #define STATUS_REGISTER_READ 0xd7 #define CONTINUOUS_ARRAY_READ 0xe8 +#define STATUS_READY (1u << 7) +#define STATUS_CMPFAIL (1u << 6) +#define STATUS_PAGE2N (1u << 0) + /* + * Metadata for supported chips. + * + * The jedec id in this table includes the extended id length byte. A match is + * based on both jedec id and extended id matching. The chip's extended id (not + * present in most chips) is ANDed with ExtMask and the result is compared to + * ExtId. If a chip only returns 1 ext id byte it will be in the upper 8 bits + * of ExtId in this table. + * * A sectorsize2n != 0 is used to indicate that a device optionally supports * 2^N byte pages. If support for the latter is enabled, the sector offset * has to be reduced by one. */ static const struct at45d_flash_ident at45d_flash_devices[] = { - { "AT45DB011B", 0x1f2200, 512, 9, 264, 256 }, - { "AT45DB021B", 0x1f2300, 1024, 9, 264, 256 }, - { "AT45DB041x", 0x1f2400, 2028, 9, 264, 256 }, - { "AT45DB081B", 0x1f2500, 4096, 9, 264, 256 }, - { "AT45DB161x", 0x1f2600, 4096, 10, 528, 512 }, - { "AT45DB321x", 0x1f2700, 8192, 10, 528, 0 }, - { "AT45DB321x", 0x1f2701, 8192, 10, 528, 512 }, - { "AT45DB642x", 0x1f2800, 8192, 11, 1056, 1024 } + /* Part Name Jedec ID ExtId ExtMask PgCnt Offs PgSz PgSz2n */ + { "AT45DB011B", 0x1f220000, 0x0000, 0x0000, 512, 9, 264, 256 }, + { "AT45DB021B", 0x1f230000, 0x0000, 0x0000, 1024, 9, 264, 256 }, + { "AT45DB041x", 0x1f240000, 0x0000, 0x0000, 2028, 9, 264, 256 }, + { "AT45DB081B", 0x1f250000, 0x0000, 0x0000, 4096, 9, 264, 256 }, + { "AT45DB161x", 0x1f260000, 0x0000, 0x0000, 4096, 10, 528, 512 }, + { "AT45DB321x", 0x1f270000, 0x0000, 0x0000, 8192, 10, 528, 0 }, + { "AT45DB321x", 0x1f270100, 0x0000, 0x0000, 8192, 10, 528, 512 }, + { "AT45DB641E", 0x1f280001, 0x0000, 0xff00, 32768, 9, 264, 256 }, + { "AT45DB642x", 0x1f280000, 0x0000, 0x0000, 8192, 11, 1056, 1024 }, }; static int @@ -138,7 +185,7 @@ at45d_get_status(device_t dev, uint8_t *status) } static int -at45d_get_mfg_info(device_t dev, uint8_t *resp) +at45d_get_mfg_info(device_t dev, struct at45d_mfg_info *resp) { uint8_t rxBuf[8], txBuf[8]; struct spi_command cmd; @@ -151,11 +198,14 @@ at45d_get_mfg_info(device_t dev, uint8_t *resp) txBuf[0] = MANUFACTURER_ID; cmd.tx_cmd = &txBuf; cmd.rx_cmd = &rxBuf; - cmd.tx_cmd_sz = cmd.rx_cmd_sz = 5; + cmd.tx_cmd_sz = cmd.rx_cmd_sz = 7; err = SPIBUS_TRANSFER(device_get_parent(dev), dev, &cmd); if (err) return (err); - memcpy(resp, rxBuf + 1, 4); + + resp->jedec_id = be32dec(rxBuf + 1); + resp->ext_id = be16dec(rxBuf + 5); + return (0); } @@ -173,16 +223,29 @@ at45d_wait_ready(device_t dev, uint8_t *status) err = ETIMEDOUT; else err = at45d_get_status(dev, status); - } while (err == 0 && (*status & 0x80) == 0); + } while (err == 0 && !(*status & STATUS_READY)); return (err); } static int at45d_probe(device_t dev) { + int rv; +#ifdef FDT + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) + return (ENXIO); + + rv = BUS_PROBE_DEFAULT; +#else + rv = BUS_PROBE_NOWILDCARD; +#endif + device_set_desc(dev, "AT45D Flash Family"); - return (0); + return (rv); } static int @@ -194,81 +257,135 @@ at45d_attach(device_t dev) sc->dev = dev; AT45D_LOCK_INIT(sc); - /* We'll see what kind of flash we have later... */ - sc->config_intrhook.ich_func = at45d_delayed_attach; - sc->config_intrhook.ich_arg = sc; - if (config_intrhook_establish(&sc->config_intrhook) != 0) { - device_printf(dev, "config_intrhook_establish failed\n"); - return (ENOMEM); - } + config_intrhook_oneshot(at45d_delayed_attach, sc); return (0); } static int at45d_detach(device_t dev) { + struct at45d_softc *sc; + int err; - return (EBUSY) /* XXX */; + sc = device_get_softc(dev); + err = 0; + + AT45D_LOCK(sc); + if (sc->taskstate == TSTATE_RUNNING) { + sc->taskstate = TSTATE_STOPPING; + wakeup(sc); + while (err == 0 && sc->taskstate != TSTATE_STOPPED) { + err = msleep(sc, &sc->sc_mtx, 0, "at45dt", hz * 3); + if (err != 0) { + sc->taskstate = TSTATE_RUNNING; + device_printf(sc->dev, + "Failed to stop queue task\n"); + } + } + } + AT45D_UNLOCK(sc); + + if (err == 0 && sc->taskstate == TSTATE_STOPPED) { + if (sc->disk) { + disk_destroy(sc->disk); + bioq_flush(&sc->bio_queue, NULL, ENXIO); + free(sc->dummybuf, M_DEVBUF); + } + AT45D_LOCK_DESTROY(sc); + } + return (err); } static void at45d_delayed_attach(void *xsc) { struct at45d_softc *sc; + struct at45d_mfg_info mfginfo; const struct at45d_flash_ident *ident; u_int i; + int sectorsize; uint32_t jedec; uint16_t pagesize; - uint8_t buf[4], status; + uint8_t status; sc = xsc; ident = NULL; jedec = 0; - if (at45d_wait_ready(sc->dev, &status) != 0) + if (at45d_wait_ready(sc->dev, &status) != 0) { device_printf(sc->dev, "Error waiting for device-ready.\n"); - else if (at45d_get_mfg_info(sc->dev, buf) != 0) + return; + } + if (at45d_get_mfg_info(sc->dev, &mfginfo) != 0) { device_printf(sc->dev, "Failed to get ID.\n"); - else { - jedec = buf[0] << 16 | buf[1] << 8 | buf[2]; - for (i = 0; i < nitems(at45d_flash_devices); i++) { - if (at45d_flash_devices[i].jedec == jedec) { - ident = &at45d_flash_devices[i]; - break; - } + return; + } + for (i = 0; i < nitems(at45d_flash_devices); i++) { + ident = &at45d_flash_devices[i]; + if (mfginfo.jedec_id == ident->jedec && + (mfginfo.ext_id & ident->extmask) == ident->extid) { + break; } } - if (ident == NULL) + if (i == nitems(at45d_flash_devices)) { device_printf(sc->dev, "JEDEC 0x%x not in list.\n", jedec); - else { - sc->pagecount = ident->pagecount; - sc->pageoffset = ident->pageoffset; - if (ident->pagesize2n != 0 && (status & 0x01) != 0) { - sc->pageoffset -= 1; - pagesize = ident->pagesize2n; - } else - pagesize = ident->pagesize; - sc->pagesize = pagesize; + return; + } - sc->disk = disk_alloc(); - sc->disk->d_open = at45d_open; - sc->disk->d_close = at45d_close; - sc->disk->d_strategy = at45d_strategy; - sc->disk->d_name = "flash/spi"; - sc->disk->d_drv1 = sc; - sc->disk->d_maxsize = DFLTPHYS; - sc->disk->d_sectorsize = pagesize; - sc->disk->d_mediasize = pagesize * ident->pagecount; - sc->disk->d_unit = device_get_unit(sc->dev); - disk_create(sc->disk, DISK_VERSION); - bioq_init(&sc->bio_queue); - kproc_create(&at45d_task, sc, &sc->p, 0, 0, - "task: at45d flash"); - device_printf(sc->dev, "%s, %d bytes per page, %d pages\n", - ident->name, pagesize, ident->pagecount); + sc->pagecount = ident->pagecount; + sc->pageoffset = ident->pageoffset; + if (ident->pagesize2n != 0 && (status & STATUS_PAGE2N)) { + sc->pageoffset -= 1; + pagesize = ident->pagesize2n; + } else + pagesize = ident->pagesize; + sc->pagesize = pagesize; + + /* + * By default we set up a disk with a sector size that matches the + * device page size. If there is a device hint or fdt property + * requesting a different size, use that, as long as it is a multiple of + * the device page size). + */ + sectorsize = pagesize; +#ifdef FDT + { + pcell_t size; + if (OF_getencprop(ofw_bus_get_node(sc->dev), + "freebsd,sectorsize", &size, sizeof(size)) > 0) + sectorsize = size; } +#endif + resource_int_value(device_get_name(sc->dev), device_get_unit(sc->dev), + "sectorsize", §orsize); - config_intrhook_disestablish(&sc->config_intrhook); + if ((sectorsize % pagesize) != 0) { + device_printf(sc->dev, "Invalid sectorsize %d, " + "must be a multiple of %d\n", sectorsize, pagesize); + return; + } + + sc->dummybuf = malloc(pagesize, M_DEVBUF, M_WAITOK | M_ZERO); + + sc->disk = disk_alloc(); + sc->disk->d_open = at45d_open; + sc->disk->d_close = at45d_close; + sc->disk->d_strategy = at45d_strategy; + sc->disk->d_getattr = at45d_getattr; + sc->disk->d_name = "flash/at45d"; + sc->disk->d_drv1 = sc; + sc->disk->d_maxsize = DFLTPHYS; + sc->disk->d_sectorsize = sectorsize; + sc->disk->d_mediasize = pagesize * ident->pagecount; + sc->disk->d_unit = device_get_unit(sc->dev); + disk_create(sc->disk, DISK_VERSION); + bioq_init(&sc->bio_queue); + kproc_create(&at45d_task, sc, &sc->p, 0, 0, "task: at45d flash"); + sc->taskstate = TSTATE_RUNNING; + device_printf(sc->dev, + "%s, %d bytes per page, %d pages; %d KBytes; disk sector size %d\n", + ident->name, pagesize, ident->pagecount, + (pagesize * ident->pagecount) / 1024, sectorsize); } static int @@ -285,6 +402,26 @@ at45d_close(struct disk *dp) return (0); } +static int +at45d_getattr(struct bio *bp) +{ + struct at45d_softc *sc; + + /* + * This function exists to support geom_flashmap and fdt_slicer. + */ + + if (bp->bio_disk == NULL || bp->bio_disk->d_drv1 == NULL) + return (ENXIO); + if (strcmp(bp->bio_attribute, "SPI::device") != 0) + return (-1); + sc = bp->bio_disk->d_drv1; + if (bp->bio_length != sizeof(sc->dev)) + return (EFAULT); + bcopy(&sc->dev, bp->bio_data, sizeof(sc->dev)); + return (0); +} + static void at45d_strategy(struct bio *bp) { @@ -322,9 +459,15 @@ at45d_task(void *arg) for (;;) { AT45D_LOCK(sc); do { + if (sc->taskstate == TSTATE_STOPPING) { + sc->taskstate = TSTATE_STOPPED; + AT45D_UNLOCK(sc); + wakeup(sc); + kproc_exit(0); + } bp = bioq_takefirst(&sc->bio_queue); if (bp == NULL) - msleep(sc, &sc->sc_mtx, PRIBIO, "jobqueue", 0); + msleep(sc, &sc->sc_mtx, PRIBIO, "at45dq", 0); } while (bp == NULL); AT45D_UNLOCK(sc); @@ -338,11 +481,13 @@ at45d_task(void *arg) case BIO_READ: txBuf[0] = CONTINUOUS_ARRAY_READ; cmd.tx_cmd_sz = cmd.rx_cmd_sz = 8; - cmd.tx_data = cmd.rx_data = buf; + cmd.tx_data = sc->dummybuf; + cmd.rx_data = buf; break; case BIO_WRITE: cmd.tx_cmd_sz = cmd.rx_cmd_sz = 4; - cmd.tx_data = cmd.rx_data = buf; + cmd.tx_data = buf; + cmd.rx_data = sc->dummybuf; if (resid + offset > sc->pagesize) len = sc->pagesize - offset; break; @@ -361,14 +506,19 @@ at45d_task(void *arg) } addr = page << sc->pageoffset; if (bp->bio_cmd == BIO_WRITE) { + /* + * If writing less than a full page, transfer + * the existing page to the buffer, so that our + * PROGRAM_THROUGH_BUFFER below will preserve + * the parts of the page we're not writing. + */ if (len != sc->pagesize) { - txBuf[0] = BUFFER_TRANSFER; + txBuf[0] = PAGE_TO_BUFFER_TRANSFER; txBuf[1] = ((addr >> 16) & 0xff); txBuf[2] = ((addr >> 8) & 0xff); txBuf[3] = 0; cmd.tx_data_sz = cmd.rx_data_sz = 0; - err = SPIBUS_TRANSFER(pdev, dev, - &cmd); + err = SPIBUS_TRANSFER(pdev, dev, &cmd); if (err == 0) err = at45d_wait_ready(dev, &status); @@ -394,7 +544,7 @@ at45d_task(void *arg) } if (bp->bio_cmd == BIO_WRITE) { addr = page << sc->pageoffset; - txBuf[0] = BUFFER_COMPARE; + txBuf[0] = PAGE_TO_BUFFER_COMPARE; txBuf[1] = ((addr >> 16) & 0xff); txBuf[2] = ((addr >> 8) & 0xff); txBuf[3] = 0; @@ -402,9 +552,9 @@ at45d_task(void *arg) err = SPIBUS_TRANSFER(pdev, dev, &cmd); if (err == 0) err = at45d_wait_ready(dev, &status); - if (err != 0 || (status & 0x40) != 0) { + if (err != 0 || (status & STATUS_CMPFAIL)) { device_printf(dev, "comparing page " - "%d failed (status=0x%x)\n", addr, + "%d failed (status=0x%x)\n", page, status); berr = EIO; goto out; @@ -418,7 +568,10 @@ at45d_task(void *arg) len = sc->pagesize; else len = resid; - cmd.tx_data = cmd.rx_data = buf; + if (bp->bio_cmd == BIO_READ) + cmd.rx_data = buf; + else + cmd.tx_data = buf; } out: if (berr != 0) { @@ -449,3 +602,7 @@ static driver_t at45d_driver = { DRIVER_MODULE(at45d, spibus, at45d_driver, at45d_devclass, NULL, NULL); MODULE_DEPEND(at45d, spibus, 1, 1, 1); +#ifdef FDT +MODULE_DEPEND(at45d, fdt_slicer, 1, 1, 1); +#endif + Modified: stable/11/sys/dev/flash/mx25l.c ============================================================================== --- stable/11/sys/dev/flash/mx25l.c Mon Apr 22 14:53:53 2019 (r346556) +++ stable/11/sys/dev/flash/mx25l.c Mon Apr 22 15:04:11 2019 (r346557) @@ -681,3 +681,4 @@ static driver_t mx25l_driver = { DRIVER_MODULE(mx25l, spibus, mx25l_driver, mx25l_devclass, 0, 0); MODULE_DEPEND(mx25l, spibus, 1, 1, 1); +MODULE_DEPEND(mx25l, fdt_slicer, 1, 1, 1); Modified: stable/11/sys/dev/spibus/spibus.c ============================================================================== --- stable/11/sys/dev/spibus/spibus.c Mon Apr 22 14:53:53 2019 (r346556) +++ stable/11/sys/dev/spibus/spibus.c Mon Apr 22 15:04:11 2019 (r346557) @@ -216,6 +216,7 @@ spibus_hinted_child(device_t bus, const char *dname, i child = BUS_ADD_CHILD(bus, 0, dname, dunit); devi = SPIBUS_IVAR(child); devi->mode = SPIBUS_MODE_NONE; + resource_int_value(dname, dunit, "clock", &devi->clock); resource_int_value(dname, dunit, "cs", &devi->cs); resource_int_value(dname, dunit, "mode", &devi->mode); } Modified: stable/11/sys/modules/Makefile ============================================================================== --- stable/11/sys/modules/Makefile Mon Apr 22 14:53:53 2019 (r346556) +++ stable/11/sys/modules/Makefile Mon Apr 22 15:04:11 2019 (r346557) @@ -500,6 +500,10 @@ SUBDIR+= iscsi SUBDIR+= iscsi_initiator .endif +.if !empty(OPT_FDT) +SUBDIR+= fdt +.endif + .if ${MK_NAND} != "no" || defined(ALL_MODULES) _nandfs= nandfs *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***