From 2984a7167717c4ea4d96ef9349e6e6a81600ea53 Mon Sep 17 00:00:00 2001 From: Allan Jude Date: Thu, 20 Jun 2019 15:44:43 +0000 Subject: [PATCH 001/165] top(1): Don't show the swap line when there are no swap devices Submitted by: antranigv@freebsd.am Reviewed by: bapt MFC after: 1 month Sponsored by: Klara Systems Differential Revision: https://reviews.freebsd.org/D18928 --- usr.bin/top/display.c | 6 ++++++ usr.bin/top/machine.c | 25 +++++++++++++++++-------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/usr.bin/top/display.c b/usr.bin/top/display.c index 539ddb4d536e..00534fd7f411 100644 --- a/usr.bin/top/display.c +++ b/usr.bin/top/display.c @@ -675,6 +675,9 @@ i_swap(int *stats) { swap_buffer = setup_buffer(swap_buffer, 0); + if (swap_names == NULL) + return; + fputs("\nSwap: ", stdout); lastline++; @@ -690,6 +693,9 @@ u_swap(int *stats) new = setup_buffer(new, 0); + if (swap_names == NULL) + return; + /* format the new line */ summary_format(new, stats, swap_names); line_update(swap_buffer, new, x_swap, y_swap); diff --git a/usr.bin/top/machine.c b/usr.bin/top/machine.c index 563efc624e24..dd2b7a110419 100644 --- a/usr.bin/top/machine.c +++ b/usr.bin/top/machine.c @@ -150,6 +150,7 @@ static const char *swapnames[] = { }; static int swap_stats[nitems(swapnames)]; +static int has_swap; /* these are for keeping track of the proc array */ @@ -248,12 +249,12 @@ update_layout(void) y_mem = 3; y_arc = 4; y_carc = 5; - y_swap = 4 + arc_enabled + carc_enabled; - y_idlecursor = 5 + arc_enabled + carc_enabled; - y_message = 5 + arc_enabled + carc_enabled; - y_header = 6 + arc_enabled + carc_enabled; - y_procs = 7 + arc_enabled + carc_enabled; - Header_lines = 7 + arc_enabled + carc_enabled; + y_swap = 3 + arc_enabled + carc_enabled + has_swap; + y_idlecursor = 4 + arc_enabled + carc_enabled + has_swap; + y_message = 4 + arc_enabled + carc_enabled + has_swap; + y_header = 5 + arc_enabled + carc_enabled + has_swap; + y_procs = 6 + arc_enabled + carc_enabled + has_swap; + Header_lines = 6 + arc_enabled + carc_enabled + has_swap; if (pcpu_stats) { y_mem += ncpus - 1; @@ -273,7 +274,7 @@ machine_init(struct statics *statics) { int i, j, empty, pagesize; uint64_t arc_size; - int carc_en; + int carc_en, nswapdev; size_t size; size = sizeof(smpmode); @@ -298,6 +299,11 @@ machine_init(struct statics *statics) if (kd == NULL) return (-1); + size = sizeof(nswapdev); + if (sysctlbyname("vm.nswapdev", &nswapdev, &size, NULL, + 0) == 0 && nswapdev != 0) + has_swap = 1; + GETSYSCTL("kern.ccpu", ccpu); /* this is used in calculating WCPU -- calculate it ahead of time */ @@ -332,7 +338,10 @@ machine_init(struct statics *statics) statics->carc_names = carcnames; else statics->carc_names = NULL; - statics->swap_names = swapnames; + if (has_swap) + statics->swap_names = swapnames; + else + statics->swap_names = NULL; statics->order_names = ordernames; /* Allocate state for per-CPU stats. */ From 67056e3d086bfd35e114bde3bf31fccbfc59031b Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Thu, 20 Jun 2019 16:36:20 +0000 Subject: [PATCH 002/165] VOP_REVOKE(9): update locking requirements per r143495 Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D20524 --- share/man/man9/VOP_REVOKE.9 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/share/man/man9/VOP_REVOKE.9 b/share/man/man9/VOP_REVOKE.9 index 3557ce1109e8..610fdb7142aa 100644 --- a/share/man/man9/VOP_REVOKE.9 +++ b/share/man/man9/VOP_REVOKE.9 @@ -34,7 +34,7 @@ .\" .\" $FreeBSD$ .\" -.Dd February 5, 2002 +.Dd June 20, 2019 .Dt VOP_REVOKE 9 .Os .Sh NAME @@ -61,7 +61,7 @@ to signify that all access will be revoked; any other value is invalid. .Sh LOCKS The .Fa vp -must be unlocked on entry, and will remain unlocked upon return. +must be exclusively locked on entry, and will remain locked upon return. .Sh SEE ALSO .Xr make_dev_alias 9 , .Xr vnode 9 From 0cf197862ddcdb30bdc94d3ea165cb108b3b382f Mon Sep 17 00:00:00 2001 From: Ed Maste Date: Thu, 20 Jun 2019 18:19:09 +0000 Subject: [PATCH 003/165] Clarify that vm_map_protect cannot upgrade max_protection It's implied by the man page's RETURN VALUES section, but be explicit in the description that vm_map_protect can not set new protection bits that are already in each entry's max_protection. Reviewed by: brooks MFC After: 1 week Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D20709 --- share/man/man9/vm_map_protect.9 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/share/man/man9/vm_map_protect.9 b/share/man/man9/vm_map_protect.9 index c4b5a738abe7..2c8b52f7e420 100644 --- a/share/man/man9/vm_map_protect.9 +++ b/share/man/man9/vm_map_protect.9 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd July 19, 2003 +.Dd June 20, 2019 .Dt VM_MAP_PROTECT 9 .Os .Sh NAME @@ -51,6 +51,11 @@ within the map .Fa map to .Fa new_prot . +The value specified by +.Fa new_prot +may not include any protection bits that are not set in +.Va max_protection +on every entry within the range. .Pp If .Fa set_max From 74a1b66cf41de99e2f6ee54f59926c8839a9e10b Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Thu, 20 Jun 2019 18:24:16 +0000 Subject: [PATCH 004/165] Extend mmap/mprotect API to specify the max page protections. A new macro PROT_MAX() alters a protection value so it can be OR'd with a regular protection value to specify the maximum permissions. If present, these flags specify the maximum permissions. While these flags are non-portable, they can be used in portable code with simple ifdefs to expand PROT_MAX() to 0. This change allows (e.g.) a region that must be writable during run-time linking or JIT code generation to be made permanently read+execute after writes are complete. This complements W^X protections allowing more precise control by the programmer. This change alters mprotect argument checking and returns an error when unhandled protection flags are set. This differs from POSIX (in that POSIX only specifies an error), but is the documented behavior on Linux and more closely matches historical mmap behavior. In addition to explicit setting of the maximum permissions, an experimental sysctl vm.imply_prot_max causes mmap to assume that the initial permissions requested should be the maximum when the sysctl is set to 1. PROT_NONE mappings are excluded from this for compatibility with rtld and other consumers that use such mappings to reserve address space before mapping contents into part of the reservation. A final version this is expected to provide per-binary and per-process opt-in/out options and this sysctl will go away in its current form. As such it is undocumented. Reviewed by: emaste, kib (prior version), markj Additional suggestions from: alc Obtained from: CheriBSD Sponsored by: DARPA, AFRL Differential Revision: https://reviews.freebsd.org/D18880 --- lib/libc/sys/mmap.2 | 23 ++++++++++++++++++++- lib/libc/sys/mprotect.2 | 27 ++++++++++++++++++++++++- sys/sys/mman.h | 8 ++++++++ sys/vm/vm_mmap.c | 45 +++++++++++++++++++++++++++++++++++------ 4 files changed, 95 insertions(+), 8 deletions(-) diff --git a/lib/libc/sys/mmap.2 b/lib/libc/sys/mmap.2 index 607a0a636352..1a2b0e511274 100644 --- a/lib/libc/sys/mmap.2 +++ b/lib/libc/sys/mmap.2 @@ -28,7 +28,7 @@ .\" @(#)mmap.2 8.4 (Berkeley) 5/11/95 .\" $FreeBSD$ .\" -.Dd June 22, 2017 +.Dd June 20, 2019 .Dt MMAP 2 .Os .Sh NAME @@ -113,6 +113,22 @@ Pages may be written. Pages may be executed. .El .Pp +In addition to these protection flags, +.Fx +provides the ability to set the maximum protection of a region allocated by +.Nm +and later altered by +.Xr mprotect 2 . +This is accomplished by +.Em or Ns 'ing +one or more +.Dv PROT_ +values wrapped in the +.Dv PROT_MAX() +macro into the +.Fa prot +argument. +.Pp The .Fa flags argument specifies the type of the mapped object, mapping options and @@ -416,6 +432,11 @@ An invalid value was passed in the .Fa prot argument. .It Bq Er EINVAL +The +.Fa prot +argument contains permissions which are not a subset of the specified +maximum permissions. +.It Bq Er EINVAL An undefined option was set in the .Fa flags argument. diff --git a/lib/libc/sys/mprotect.2 b/lib/libc/sys/mprotect.2 index 3be81c6582a3..b6e260ad42d6 100644 --- a/lib/libc/sys/mprotect.2 +++ b/lib/libc/sys/mprotect.2 @@ -28,7 +28,7 @@ .\" @(#)mprotect.2 8.1 (Berkeley) 6/9/93 .\" $FreeBSD$ .\" -.Dd August 3, 2016 +.Dd June 20, 2019 .Dt MPROTECT 2 .Os .Sh NAME @@ -65,6 +65,22 @@ The pages can be written. .It Dv PROT_EXEC The pages can be executed. .El +.Pp +In addition to these protection flags, +.Fx +provides the ability to set the maximum protection of a region +(which prevents +.Nm +from upgrading the permissions). +This is accomplished by +.Em or Ns 'ing +one or more +.Dv PROT_ +values wrapped in the +.Dv PROT_MAX() +macro into the +.Fa prot +argument. .Sh RETURN VALUES .Rv -std mprotect .Sh ERRORS @@ -78,6 +94,15 @@ The virtual address range specified by the and .Fa len arguments is not valid. +.It Bq Er EINVAL +The +.Fa prot +argument contains unhandled bits. +.It Bq Er EINVAL +The +.Fa prot +argument contains permissions which are not a subset of the specified +maximum permissions. .It Bq Er EACCES The calling process was not allowed to change the protection to the value specified by diff --git a/sys/sys/mman.h b/sys/sys/mman.h index b2fad0e47579..1b1b4bcc2cb9 100644 --- a/sys/sys/mman.h +++ b/sys/sys/mman.h @@ -55,6 +55,14 @@ #define PROT_READ 0x01 /* pages can be read */ #define PROT_WRITE 0x02 /* pages can be written */ #define PROT_EXEC 0x04 /* pages can be executed */ +#if __BSD_VISIBLE +#define _PROT_ALL (PROT_READ | PROT_WRITE | PROT_EXEC) +#define PROT_EXTRACT(prot) ((prot) & _PROT_ALL) + +#define _PROT_MAX_SHIFT 16 +#define PROT_MAX(prot) ((prot) << _PROT_MAX_SHIFT) +#define PROT_MAX_EXTRACT(prot) (((prot) >> _PROT_MAX_SHIFT) & _PROT_ALL) +#endif /* * Flags contain sharing type and options. diff --git a/sys/vm/vm_mmap.c b/sys/vm/vm_mmap.c index cd483527af71..24864889060c 100644 --- a/sys/vm/vm_mmap.c +++ b/sys/vm/vm_mmap.c @@ -103,6 +103,9 @@ SYSCTL_INT(_vm, OID_AUTO, old_mlock, CTLFLAG_RWTUN, &old_mlock, 0, static int mincore_mapped = 1; SYSCTL_INT(_vm, OID_AUTO, mincore_mapped, CTLFLAG_RWTUN, &mincore_mapped, 0, "mincore reports mappings, not residency"); +static int imply_prot_max = 0; +SYSCTL_INT(_vm, OID_AUTO, imply_prot_max, CTLFLAG_RWTUN, &imply_prot_max, 0, + "Imply maximum page permissions in mmap() when none are specified"); #ifdef MAP_32BIT #define MAP_32BIT_MAX_ADDR ((vm_offset_t)1 << 31) @@ -187,9 +190,25 @@ kern_mmap(struct thread *td, uintptr_t addr0, size_t len, int prot, int flags, vm_offset_t addr; vm_size_t pageoff, size; vm_prot_t cap_maxprot; - int align, error; + int align, error, max_prot; cap_rights_t rights; + if ((prot & ~(_PROT_ALL | PROT_MAX(_PROT_ALL))) != 0) + return (EINVAL); + max_prot = PROT_MAX_EXTRACT(prot); + prot = PROT_EXTRACT(prot); + if (max_prot != 0 && (max_prot & prot) != prot) + return (EINVAL); + /* + * Always honor PROT_MAX if set. If not, default to all + * permissions unless we're implying maximum permissions. + * + * XXX: should be tunable per process and ABI. + */ + if (max_prot == 0) + max_prot = (imply_prot_max && prot != PROT_NONE) ? + prot : _PROT_ALL; + vms = td->td_proc->p_vmspace; fp = NULL; AUDIT_ARG_FD(fd); @@ -335,7 +354,7 @@ kern_mmap(struct thread *td, uintptr_t addr0, size_t len, int prot, int flags, * This relies on VM_PROT_* matching PROT_*. */ error = vm_mmap_object(&vms->vm_map, &addr, size, prot, - VM_PROT_ALL, flags, NULL, pos, FALSE, td); + max_prot, flags, NULL, pos, FALSE, td); } else { /* * Mapping file, get fp for validation and don't let the @@ -363,7 +382,7 @@ kern_mmap(struct thread *td, uintptr_t addr0, size_t len, int prot, int flags, /* This relies on VM_PROT_* matching PROT_*. */ error = fo_mmap(fp, &vms->vm_map, &addr, size, prot, - cap_maxprot, flags, pos, td); + max_prot & cap_maxprot, flags, pos, td); } if (error == 0) @@ -594,9 +613,13 @@ kern_mprotect(struct thread *td, uintptr_t addr0, size_t size, int prot) { vm_offset_t addr; vm_size_t pageoff; + int vm_error, max_prot; addr = addr0; - prot = (prot & VM_PROT_ALL); + if ((prot & ~(_PROT_ALL | PROT_MAX(_PROT_ALL))) != 0) + return (EINVAL); + max_prot = PROT_MAX_EXTRACT(prot); + prot = PROT_EXTRACT(prot); pageoff = (addr & PAGE_MASK); addr -= pageoff; size += pageoff; @@ -610,8 +633,18 @@ kern_mprotect(struct thread *td, uintptr_t addr0, size_t size, int prot) if (addr + size < addr) return (EINVAL); - switch (vm_map_protect(&td->td_proc->p_vmspace->vm_map, addr, - addr + size, prot, FALSE)) { + vm_error = KERN_SUCCESS; + if (max_prot != 0) { + if ((max_prot & prot) != prot) + return (EINVAL); + vm_error = vm_map_protect(&td->td_proc->p_vmspace->vm_map, + addr, addr + size, max_prot, TRUE); + } + if (vm_error == KERN_SUCCESS) + vm_error = vm_map_protect(&td->td_proc->p_vmspace->vm_map, + addr, addr + size, prot, FALSE); + + switch (vm_error) { case KERN_SUCCESS: return (0); case KERN_PROTECTION_FAILURE: From cb537974736bb522d683d1c036f9d9e15ce7885e Mon Sep 17 00:00:00 2001 From: Ed Maste Date: Thu, 20 Jun 2019 18:30:19 +0000 Subject: [PATCH 005/165] Clarify vm_map_protect max_protection downgrade As reported in review D20709 by brooks calling vm_map_protect to set a new max_protection value downgrades existing mappings if necessary (as opposed to returning an error). Reported by: brooks MFC after: 1 week Sponsored by: The FreeBSD Foundation --- share/man/man9/vm_map_protect.9 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/share/man/man9/vm_map_protect.9 b/share/man/man9/vm_map_protect.9 index 2c8b52f7e420..3bd615c710ff 100644 --- a/share/man/man9/vm_map_protect.9 +++ b/share/man/man9/vm_map_protect.9 @@ -64,7 +64,12 @@ is TRUE, is treated as the new .Va max_protection setting for each underlying entry. -Otherwise, only the +Protection bits not included +.Fa new_prot +will be cleared from existing entries. +If +.Fa set_max +is FALSE only the .Va protection field is affected. .Pp From 17795d8234301642b0e9c05830534e2309111762 Mon Sep 17 00:00:00 2001 From: Navdeep Parhar Date: Thu, 20 Jun 2019 20:06:19 +0000 Subject: [PATCH 006/165] cxgbe/t4_tom: DDP_DEAD is a ddp flag and not a toepcb flag. The driver was in effect setting TPF_ABORT_SHUTDOWN on the toepcb instead of what was intended. MFC after: 1 week Sponsored by: Chelsio Communications --- sys/dev/cxgbe/tom/t4_ddp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/dev/cxgbe/tom/t4_ddp.c b/sys/dev/cxgbe/tom/t4_ddp.c index 47062e634bbf..f3f03e0faa2c 100644 --- a/sys/dev/cxgbe/tom/t4_ddp.c +++ b/sys/dev/cxgbe/tom/t4_ddp.c @@ -220,7 +220,7 @@ release_ddp_resources(struct toepcb *toep) int i; DDP_LOCK(toep); - toep->flags |= DDP_DEAD; + toep->ddp.flags |= DDP_DEAD; for (i = 0; i < nitems(toep->ddp.db); i++) { free_ddp_buffer(toep->td, &toep->ddp.db[i]); } From 35a9ffc350cd21c6e6fbaf64a90e6f789af2b9ba Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Thu, 20 Jun 2019 20:29:42 +0000 Subject: [PATCH 007/165] Optimize xpt_getattr(). Do not allocate temporary buffer for attributes we are going to return as-is, just make sure to NUL-terminate them. Do not zero temporary 64KB buffer for CDAI_TYPE_SCSI_DEVID, XPT tells us how much data it filled and there are also length fields inside the returned data also. MFC after: 2 weeks Sponsored by: iXsystems, Inc. --- sys/cam/cam_xpt.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c index 2217ecc6d2ff..95553316bca8 100644 --- a/sys/cam/cam_xpt.c +++ b/sys/cam/cam_xpt.c @@ -1253,6 +1253,7 @@ xpt_getattr(char *buf, size_t len, const char *attr, struct cam_path *path) cdai.ccb_h.func_code = XPT_DEV_ADVINFO; cdai.flags = CDAI_FLAG_NONE; cdai.bufsiz = len; + cdai.buf = buf; if (!strcmp(attr, "GEOM::ident")) cdai.buftype = CDAI_TYPE_SERIAL_NUM; @@ -1262,14 +1263,14 @@ xpt_getattr(char *buf, size_t len, const char *attr, struct cam_path *path) strcmp(attr, "GEOM::lunname") == 0) { cdai.buftype = CDAI_TYPE_SCSI_DEVID; cdai.bufsiz = CAM_SCSI_DEVID_MAXLEN; + cdai.buf = malloc(cdai.bufsiz, M_CAMXPT, M_NOWAIT); + if (cdai.buf == NULL) { + ret = ENOMEM; + goto out; + } } else goto out; - cdai.buf = malloc(cdai.bufsiz, M_CAMXPT, M_NOWAIT|M_ZERO); - if (cdai.buf == NULL) { - ret = ENOMEM; - goto out; - } xpt_action((union ccb *)&cdai); /* can only be synchronous */ if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0) cam_release_devq(cdai.ccb_h.path, 0, 0, 0, FALSE); @@ -1334,13 +1335,15 @@ xpt_getattr(char *buf, size_t len, const char *attr, struct cam_path *path) ret = EFAULT; } } else { - ret = 0; - if (strlcpy(buf, cdai.buf, len) >= len) + if (cdai.provsiz < len) { + cdai.buf[cdai.provsiz] = 0; + ret = 0; + } else ret = EFAULT; } out: - if (cdai.buf != NULL) + if ((char *)cdai.buf != buf) free(cdai.buf, M_CAMXPT); return ret; } From ee37749af6f8738f4c7edf54f80fe61dc71bf130 Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Thu, 20 Jun 2019 21:52:30 +0000 Subject: [PATCH 008/165] Add PROT_MAX to the HISTORY section. In the case of mmap(), add a HISTORY section. Mention that mmap() and mprotect()'s documentation predates an implementation. The implementation first saw wide use in 4.3-Reno, but there seems to be no easy way to express that in mdoc so stick with 4.4BSD. Reviewed by: emaste Requested by: cem Sponsored by: DARPA, AFRL Differential Revision: https://reviews.freebsd.org/D20713 --- lib/libc/sys/mmap.2 | 13 +++++++++++++ lib/libc/sys/mprotect.2 | 9 ++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/libc/sys/mmap.2 b/lib/libc/sys/mmap.2 index 1a2b0e511274..8a3c7c45f139 100644 --- a/lib/libc/sys/mmap.2 +++ b/lib/libc/sys/mmap.2 @@ -542,3 +542,16 @@ was specified and insufficient memory was available. .Xr munmap 2 , .Xr getpagesize 3 , .Xr getpagesizes 3 +.Sh HISTORY +The +.Nm +system call was first documented in +.Bx 4.2 +and implemented in +.Bx 4.4 . +.\" XXX: lots of missing history of FreeBSD additions. +.Pp +The +.Dv PROT_MAX +functionality was introduced in +.Fx 13 . diff --git a/lib/libc/sys/mprotect.2 b/lib/libc/sys/mprotect.2 index b6e260ad42d6..2c165f093861 100644 --- a/lib/libc/sys/mprotect.2 +++ b/lib/libc/sys/mprotect.2 @@ -118,5 +118,12 @@ argument. .Sh HISTORY The .Fn mprotect -system call first appeared in +system call was first documented in +.Bx 4.2 +and first appeared in .Bx 4.4 . +.Pp +The +.Dv PROT_MAX +functionality was introduced in +.Fx 13 . From 68035f638124f85d3423e99e6e2d559d3ebd38c5 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Thu, 20 Jun 2019 22:20:30 +0000 Subject: [PATCH 009/165] SPC-3 and up require some UAs to be returned as fixed. MFC after: 2 weeks --- sys/cam/ctl/ctl_error.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sys/cam/ctl/ctl_error.c b/sys/cam/ctl/ctl_error.c index 17e9e3a51d80..dae4deb9e5e7 100644 --- a/sys/cam/ctl/ctl_error.c +++ b/sys/cam/ctl/ctl_error.c @@ -80,6 +80,12 @@ ctl_set_sense_data_va(struct scsi_sense_data *sense_data, u_int *sense_len, * data. */ if (sense_format == SSD_TYPE_NONE) { + /* + * SPC-3 and up require some UAs to be returned as fixed. + */ + if (asc == 0x29 || (asc == 0x2A && ascq == 0x01)) + sense_format = SSD_TYPE_FIXED; + else /* * If the format isn't specified, we only return descriptor * sense if the LUN exists and descriptor sense is turned From 38b06f8ac4a85219287b2ca8f2a56de7d6bbba0c Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Thu, 20 Jun 2019 23:07:20 +0000 Subject: [PATCH 010/165] fcntl: fix overflow when setting F_READAHEAD VOP_READ and VOP_WRITE take the seqcount in blocks in a 16-bit field. However, fcntl allows you to set the seqcount in bytes to any nonnegative 31-bit value. The result can be a 16-bit overflow, which will be sign-extended in functions like ffs_read. Fix this by sanitizing the argument in kern_fcntl. As a matter of policy, limit to IO_SEQMAX rather than INT16_MAX. Also, fifos have overloaded the f_seqcount field for a completely different purpose ever since r238936. Formalize that by using a union type. Reviewed by: cem MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D20710 --- sys/fs/fifofs/fifo_vnops.c | 2 +- sys/kern/kern_descrip.c | 4 +++- sys/kern/sys_pipe.c | 2 +- sys/kern/vfs_vnops.c | 3 ++- sys/sys/file.h | 5 ++++- 5 files changed, 11 insertions(+), 5 deletions(-) diff --git a/sys/fs/fifofs/fifo_vnops.c b/sys/fs/fifofs/fifo_vnops.c index 96dd05a18323..b4fefbde79a6 100644 --- a/sys/fs/fifofs/fifo_vnops.c +++ b/sys/fs/fifofs/fifo_vnops.c @@ -174,7 +174,7 @@ fifo_open(ap) if (fip->fi_writers > 0) wakeup(&fip->fi_writers); } - fp->f_seqcount = fpipe->pipe_wgen - fip->fi_writers; + fp->f_pipegen = fpipe->pipe_wgen - fip->fi_writers; } if (ap->a_mode & FWRITE) { if ((ap->a_mode & O_NONBLOCK) && fip->fi_readers == 0) { diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 4d09eea37d56..4bc1a1546820 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -780,7 +780,9 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) } if (arg >= 0) { bsize = fp->f_vnode->v_mount->mnt_stat.f_iosize; - fp->f_seqcount = (arg + bsize - 1) / bsize; + arg = MIN(arg, INT_MAX - bsize + 1); + fp->f_seqcount = MIN(IO_SEQMAX, + (arg + bsize - 1) / bsize); atomic_set_int(&fp->f_flag, FRDAHEAD); } else { atomic_clear_int(&fp->f_flag, FRDAHEAD); diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c index eafb902601d7..3c04e8607a71 100644 --- a/sys/kern/sys_pipe.c +++ b/sys/kern/sys_pipe.c @@ -1414,7 +1414,7 @@ pipe_poll(struct file *fp, int events, struct ucred *active_cred, levents = events & (POLLIN | POLLINIGNEOF | POLLPRI | POLLRDNORM | POLLRDBAND); if (rpipe->pipe_state & PIPE_NAMED && fp->f_flag & FREAD && levents && - fp->f_seqcount == rpipe->pipe_wgen) + fp->f_pipegen == rpipe->pipe_wgen) events |= POLLINIGNEOF; if ((events & POLLINIGNEOF) == 0) { diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index 7871e536b56e..b31ec81bd1dd 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -499,7 +499,8 @@ sequential_heuristic(struct uio *uio, struct file *fp) * closely related to the best I/O size for real disks than * to any block size used by software. */ - fp->f_seqcount += howmany(uio->uio_resid, 16384); + fp->f_seqcount += MIN(IO_SEQMAX, + howmany(uio->uio_resid, 16384)); if (fp->f_seqcount > IO_SEQMAX) fp->f_seqcount = IO_SEQMAX; return (fp->f_seqcount << IO_SEQSHIFT); diff --git a/sys/sys/file.h b/sys/sys/file.h index 82af5e6b1bbe..942380c1647f 100644 --- a/sys/sys/file.h +++ b/sys/sys/file.h @@ -179,7 +179,10 @@ struct file { /* * DTYPE_VNODE specific fields. */ - int f_seqcount; /* (a) Count of sequential accesses. */ + union { + int16_t f_seqcount; /* (a) Count of sequential accesses. */ + int f_pipegen; + }; off_t f_nextoff; /* next expected read/write offset. */ union { struct cdev_privdata *fvn_cdevpriv; From a809abd44a24a54b92de608cbc8a3c853852fd4b Mon Sep 17 00:00:00 2001 From: Takanori Watanabe Date: Thu, 20 Jun 2019 23:52:33 +0000 Subject: [PATCH 011/165] Fix the case where no root hub object while host controller object exist in ACPI namespace. Also you can disable ACPI support for USB by setting debug.acpi.disabled="usb" PR: 238711 --- sys/dev/usb/usb_hub_acpi.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/sys/dev/usb/usb_hub_acpi.c b/sys/dev/usb/usb_hub_acpi.c index 5dd9f06ebaa4..b536a3d282e9 100644 --- a/sys/dev/usb/usb_hub_acpi.c +++ b/sys/dev/usb/usb_hub_acpi.c @@ -243,13 +243,14 @@ acpi_uhub_parse_pld(device_t dev, unsigned int port, ACPI_HANDLE ah) } ACPI_STATUS -acpi_uhub_find_rh(device_t dev, ACPI_HANDLE * ah){ +acpi_uhub_find_rh(device_t dev, ACPI_HANDLE * ah) +{ device_t grand; ACPI_HANDLE gah; + *ah = NULL; grand = device_get_parent(device_get_parent(dev)); if ((gah = acpi_get_handle(grand)) == NULL) { - *ah = NULL; return AE_ERROR; } return AcpiWalkNamespace(ACPI_TYPE_DEVICE, gah, 1, @@ -257,7 +258,8 @@ acpi_uhub_find_rh(device_t dev, ACPI_HANDLE * ah){ } ACPI_STATUS -acpi_usb_hub_port_probe_cb(ACPI_HANDLE ah, UINT32 lv, void *ctx, void **rv){ +acpi_usb_hub_port_probe_cb(ACPI_HANDLE ah, UINT32 lv, void *ctx, void **rv) +{ ACPI_DEVICE_INFO *devinfo; device_t dev = ctx; struct acpi_uhub_softc *sc = device_get_softc(dev); @@ -281,7 +283,8 @@ acpi_usb_hub_port_probe_cb(ACPI_HANDLE ah, UINT32 lv, void *ctx, void **rv){ } ACPI_STATUS -acpi_usb_hub_port_probe(device_t dev, ACPI_HANDLE ah){ +acpi_usb_hub_port_probe(device_t dev, ACPI_HANDLE ah) +{ return AcpiWalkNamespace(ACPI_TYPE_DEVICE, ah, 1, acpi_usb_hub_port_probe_cb, @@ -293,6 +296,9 @@ acpi_uhub_root_probe(device_t dev) ACPI_HANDLE ah; ACPI_STATUS status; + if(acpi_disabled("usb")) { + return ENXIO; + } status = acpi_uhub_find_rh(dev, &ah); if (ACPI_SUCCESS(status) && ah != NULL @@ -308,7 +314,7 @@ acpi_uhub_probe(device_t dev) { ACPI_HANDLE ah = acpi_get_handle(dev); - if (ah && (uhub_probe(dev) <= 0)) { + if (!acpi_disabled("usb") && ah && (uhub_probe(dev) <= 0)) { /*success prior than non - acpi hub*/ return (BUS_PROBE_DEFAULT + 1); } @@ -335,7 +341,6 @@ acpi_uhub_root_attach(device_t dev) sc->nports = uh->nports; sc->porthandle = malloc(sizeof(ACPI_HANDLE) * uh->nports, M_USBDEV, M_WAITOK | M_ZERO); - acpi_uhub_find_rh(dev, &devhandle); acpi_usb_hub_port_probe(dev, devhandle); return 0; From c363b16c639529cf82d353abaa17f19bad7f8aec Mon Sep 17 00:00:00 2001 From: Conrad Meyer Date: Fri, 21 Jun 2019 00:16:30 +0000 Subject: [PATCH 012/165] sys: Remove DEV_RANDOM device option Remove 'device random' from kernel configurations that reference it (most). Replace perhaps mistaken 'nodevice random' in two MIPS configs with 'options RANDOM_LOADABLE' instead. Document removal in UPDATING; update NOTES and random.4. Reviewed by: delphij, markm (previous version) Approved by: secteam(delphij) Differential Revision: https://reviews.freebsd.org/D19918 --- UPDATING | 6 ++++++ release/picobsd/bridge/PICOBSD | 1 - release/picobsd/qemu/PICOBSD | 1 - share/man/man4/random.4 | 1 - sys/amd64/conf/GENERIC | 1 - sys/amd64/conf/MINIMAL | 3 +-- sys/arm/conf/ALPINE | 1 - sys/arm/conf/ARMADA38X | 1 - sys/arm/conf/ARMADAXP | 1 - sys/arm/conf/DB-78XXX | 1 - sys/arm/conf/DB-88F5XXX | 1 - sys/arm/conf/DB-88F6XXX | 1 - sys/arm/conf/DOCKSTAR | 1 - sys/arm/conf/DREAMPLUG-1001 | 1 - sys/arm/conf/EFIKA_MX | 1 - sys/arm/conf/GENERIC | 1 - sys/arm/conf/IMX53 | 1 - sys/arm/conf/IMX6 | 1 - sys/arm/conf/RPI-B | 1 - sys/arm/conf/RT1310 | 1 - sys/arm/conf/SHEEVAPLUG | 1 - sys/arm/conf/SOCFPGA | 1 - sys/arm/conf/TEGRA124 | 1 - sys/arm/conf/TS7800 | 1 - sys/arm/conf/VERSATILEPB | 1 - sys/arm/conf/VYBRID | 1 - sys/arm/conf/ZEDBOARD | 1 - sys/arm64/conf/GENERIC | 1 - sys/conf/NOTES | 3 --- sys/conf/files | 16 +++++++-------- sys/conf/files.arm64 | 2 +- sys/conf/files.powerpc | 2 +- sys/conf/options | 1 - sys/i386/conf/GENERIC | 1 - sys/i386/conf/MINIMAL | 3 +-- sys/mips/conf/BCM | 1 - sys/mips/conf/DIR-825B1 | 1 - sys/mips/conf/ERL | 1 - sys/mips/conf/JZ4780 | 1 - sys/mips/conf/OCTEON1 | 1 - sys/mips/conf/PB92 | 1 - sys/mips/conf/PICOSTATION_M2HP | 3 --- sys/mips/conf/WZR-300HP | 2 +- sys/mips/conf/WZR-HPAG300H | 2 +- sys/mips/conf/X1000 | 1 - sys/mips/conf/std.AR5312 | 1 - sys/mips/conf/std.AR5315 | 1 - sys/mips/conf/std.AR_MIPS_BASE | 3 --- sys/mips/conf/std.BERI | 1 - sys/mips/conf/std.MALTA | 1 - sys/mips/conf/std.XLP | 1 - sys/mips/mediatek/std.mediatek | 3 --- sys/mips/mediatek/std.rt2880 | 3 --- sys/powerpc/conf/GENERIC | 1 - sys/powerpc/conf/GENERIC64 | 1 - sys/powerpc/conf/MPC85XX | 1 - sys/powerpc/conf/MPC85XXSPE | 1 - sys/powerpc/conf/QORIQ64 | 1 - sys/powerpc/conf/dpaa/DPAA | 1 - sys/riscv/conf/GENERIC | 1 - sys/sparc64/conf/GENERIC | 1 - sys/sys/random.h | 25 ----------------------- tools/tools/nanobsd/pcengines/ALIX_DSK | 1 - tools/tools/tinybsd/conf/bridge/TINYBSD | 1 - tools/tools/tinybsd/conf/default/TINYBSD | 1 - tools/tools/tinybsd/conf/firewall/TINYBSD | 1 - tools/tools/tinybsd/conf/minimal/TINYBSD | 1 - tools/tools/tinybsd/conf/vpn/TINYBSD | 1 - tools/tools/tinybsd/conf/wireless/TINYBSD | 1 - tools/tools/tinybsd/conf/wrap/TINYBSD | 1 - 70 files changed, 20 insertions(+), 112 deletions(-) diff --git a/UPDATING b/UPDATING index 7eb324078d53..86ffdc7379d5 100644 --- a/UPDATING +++ b/UPDATING @@ -31,6 +31,12 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 13.x IS SLOW: disable the most expensive debugging functionality run "ln -s 'abort:false,junk:false' /etc/malloc.conf".) +20190620: + The "device random" option has been removed. Entropy collection and + the /dev/random device are no longer an optional component. + Implementations of distilling algorithms can still be made loadable + with "options RANDOM_LOADABLE" (e.g., random_fortuna.ko). + 20190612: Clang, llvm, lld, lldb, compiler-rt, libc++, libunwind and openmp have been upgraded to 8.0.1. Please see the 20141231 entry below for diff --git a/release/picobsd/bridge/PICOBSD b/release/picobsd/bridge/PICOBSD index bc1185d61c64..c06091dcb888 100644 --- a/release/picobsd/bridge/PICOBSD +++ b/release/picobsd/bridge/PICOBSD @@ -50,7 +50,6 @@ device if_bridge # qemu, so we set HZ explicitly. options HZ=1000 -device random # used by ssh device pci # Floppy drives diff --git a/release/picobsd/qemu/PICOBSD b/release/picobsd/qemu/PICOBSD index 16b175385b0a..f3a9f9ccaf28 100644 --- a/release/picobsd/qemu/PICOBSD +++ b/release/picobsd/qemu/PICOBSD @@ -56,7 +56,6 @@ device if_bridge # qemu, so we set HZ explicitly. options HZ=1000 -device random # used by ssh device pci # Floppy drives diff --git a/share/man/man4/random.4 b/share/man/man4/random.4 index 0ccad03aeda4..3b3f9b2330e3 100644 --- a/share/man/man4/random.4 +++ b/share/man/man4/random.4 @@ -30,7 +30,6 @@ .Nm random .Nd the entropy device .Sh SYNOPSIS -.Cd "device random" .Cd "options RANDOM_LOADABLE" .Cd "options RANDOM_ENABLE_ETHER" .Cd "options RANDOM_ENABLE_UMA" diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC index 520f64734bb9..f04b60f3ca66 100644 --- a/sys/amd64/conf/GENERIC +++ b/sys/amd64/conf/GENERIC @@ -309,7 +309,6 @@ device wpi # Intel 3945ABG wireless NICs. # Pseudo devices. device crypto # core crypto support device loop # Network loopback -device random # Entropy device device padlock_rng # VIA Padlock RNG device rdrand_rng # Intel Bull Mountain RNG device ether # Ethernet support diff --git a/sys/amd64/conf/MINIMAL b/sys/amd64/conf/MINIMAL index 481a7ce96e44..211e00e7de46 100644 --- a/sys/amd64/conf/MINIMAL +++ b/sys/amd64/conf/MINIMAL @@ -10,7 +10,7 @@ # some features (ACL, GJOURNAL) that GENERIC includes. # o acpi as a module has been reported flakey and not well tested, so # is included in the kernel. -# o random is included due to uncertaty... +# o (non-loaded) random is included due to uncertainty... # o Many networking things are included # # For now, please run changes to these list past imp@freebsd.org @@ -131,7 +131,6 @@ device agp # support several AGP chipsets # Pseudo devices. device loop # Network loopback -device random # Entropy device device padlock_rng # VIA Padlock RNG device rdrand_rng # Intel Bull Mountain RNG device ether # Ethernet support diff --git a/sys/arm/conf/ALPINE b/sys/arm/conf/ALPINE index 6b35f120aefb..76689b5805c9 100644 --- a/sys/arm/conf/ALPINE +++ b/sys/arm/conf/ALPINE @@ -41,7 +41,6 @@ device al_udma # Universal DMA # Pseudo devices device loop -device random device pty device md device gpio diff --git a/sys/arm/conf/ARMADA38X b/sys/arm/conf/ARMADA38X index 29ea724172be..b82c18d79c52 100644 --- a/sys/arm/conf/ARMADA38X +++ b/sys/arm/conf/ARMADA38X @@ -25,7 +25,6 @@ options SMP options VM_KMEM_SIZE_MAX=0x9CCD000 # Pseudo devices -device random device pty device loop device md diff --git a/sys/arm/conf/ARMADAXP b/sys/arm/conf/ARMADAXP index 5e891e51fba7..7f73d69ece7a 100644 --- a/sys/arm/conf/ARMADAXP +++ b/sys/arm/conf/ARMADAXP @@ -46,7 +46,6 @@ options NO_FFS_SNAPSHOT options NO_SWAPPING # Pseudo devices -device random device pty device loop device md diff --git a/sys/arm/conf/DB-78XXX b/sys/arm/conf/DB-78XXX index aa474bcc43a1..b1379dfb544f 100644 --- a/sys/arm/conf/DB-78XXX +++ b/sys/arm/conf/DB-78XXX @@ -45,7 +45,6 @@ device pci # Pseudo devices device loop device md -device random # Serial ports device uart diff --git a/sys/arm/conf/DB-88F5XXX b/sys/arm/conf/DB-88F5XXX index 0199e8663336..a13a7002332d 100644 --- a/sys/arm/conf/DB-88F5XXX +++ b/sys/arm/conf/DB-88F5XXX @@ -44,7 +44,6 @@ device pci # Pseudo devices device md device loop -device random # Serial ports device uart diff --git a/sys/arm/conf/DB-88F6XXX b/sys/arm/conf/DB-88F6XXX index fa2810c97122..b0c36c0b1b42 100644 --- a/sys/arm/conf/DB-88F6XXX +++ b/sys/arm/conf/DB-88F6XXX @@ -46,7 +46,6 @@ device pci # Pseudo devices device loop device md -device random # Serial ports device uart diff --git a/sys/arm/conf/DOCKSTAR b/sys/arm/conf/DOCKSTAR index 5684d29ef87b..6f26d4290801 100644 --- a/sys/arm/conf/DOCKSTAR +++ b/sys/arm/conf/DOCKSTAR @@ -68,7 +68,6 @@ device gif # IPv6 and IPv4 tunneling device loop # Network loopback device md # Memory/malloc disk device pty # BSD-style compatibility pseudo ttys -device random # Entropy device device tuntap # Packet tunnel. device ether # Required for all ethernet devices device vlan # 802.1Q VLAN support diff --git a/sys/arm/conf/DREAMPLUG-1001 b/sys/arm/conf/DREAMPLUG-1001 index 5d6928470e5d..8a5ce4a6d8f2 100644 --- a/sys/arm/conf/DREAMPLUG-1001 +++ b/sys/arm/conf/DREAMPLUG-1001 @@ -71,7 +71,6 @@ device gif # IPv6 and IPv4 tunneling device loop # Network loopback device md # Memory/malloc disk device pty # BSD-style compatibility pseudo ttys -device random # Entropy device device tuntap # Packet tunnel. device ether # Required for all ethernet devices device vlan # 802.1Q VLAN support diff --git a/sys/arm/conf/EFIKA_MX b/sys/arm/conf/EFIKA_MX index 248060b6cf04..be5f5f35570d 100644 --- a/sys/arm/conf/EFIKA_MX +++ b/sys/arm/conf/EFIKA_MX @@ -57,7 +57,6 @@ device bpf # Berkeley packet filter # Pseudo devices. device loop # Network loopback -device random # Entropy device device ether # Ethernet support #device vlan # 802.1Q VLAN support #device tuntap # Packet tunnel. diff --git a/sys/arm/conf/GENERIC b/sys/arm/conf/GENERIC index d32baa63a667..8b998a15aa1e 100644 --- a/sys/arm/conf/GENERIC +++ b/sys/arm/conf/GENERIC @@ -121,7 +121,6 @@ device pl011 device pty device snp device md # Memory "disks" -device random # Entropy device device firmware # firmware assist module device pl310 # PL310 L2 cache controller device psci diff --git a/sys/arm/conf/IMX53 b/sys/arm/conf/IMX53 index 7b7d67bbca9c..be18afda6094 100644 --- a/sys/arm/conf/IMX53 +++ b/sys/arm/conf/IMX53 @@ -44,7 +44,6 @@ device bpf # Berkeley packet filter # Pseudo devices. device loop # Network loopback -device random # Entropy device device ether # Ethernet support #device vlan # 802.1Q VLAN support #device tuntap # Packet tunnel. diff --git a/sys/arm/conf/IMX6 b/sys/arm/conf/IMX6 index 3baf9f06f039..4dbebdfccd1f 100644 --- a/sys/arm/conf/IMX6 +++ b/sys/arm/conf/IMX6 @@ -49,7 +49,6 @@ device mpcore_timer # Pseudo devices. device loop # Network loopback -device random # Entropy device device vlan # 802.1Q VLAN support device tuntap # Packet tunnel. device md # Memory "disks" diff --git a/sys/arm/conf/RPI-B b/sys/arm/conf/RPI-B index e1f132105c20..e456d33742b8 100644 --- a/sys/arm/conf/RPI-B +++ b/sys/arm/conf/RPI-B @@ -65,7 +65,6 @@ device iicbus device bcm2835_bsc device md -device random # Entropy device # USB support device usb diff --git a/sys/arm/conf/RT1310 b/sys/arm/conf/RT1310 index 3ade997821be..08fde3516ac1 100644 --- a/sys/arm/conf/RT1310 +++ b/sys/arm/conf/RT1310 @@ -51,7 +51,6 @@ options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed device loop device md device pty -device random # Serial ports device uart diff --git a/sys/arm/conf/SHEEVAPLUG b/sys/arm/conf/SHEEVAPLUG index ff60f82bcf60..df44533dcd72 100644 --- a/sys/arm/conf/SHEEVAPLUG +++ b/sys/arm/conf/SHEEVAPLUG @@ -46,7 +46,6 @@ options BOOTP_WIRED_TO=mge0 # Pseudo devices device loop -device random # Serial ports device uart diff --git a/sys/arm/conf/SOCFPGA b/sys/arm/conf/SOCFPGA index b740ef1b84c9..cd78e17e08a4 100644 --- a/sys/arm/conf/SOCFPGA +++ b/sys/arm/conf/SOCFPGA @@ -58,7 +58,6 @@ device dwmmc # Pseudo devices device loop -device random device pty device md device gpio diff --git a/sys/arm/conf/TEGRA124 b/sys/arm/conf/TEGRA124 index a830519d909e..c44939b67301 100644 --- a/sys/arm/conf/TEGRA124 +++ b/sys/arm/conf/TEGRA124 @@ -43,7 +43,6 @@ device regulator # Pseudo devices. device loop # Network loopback -device random # Entropy device device vlan # 802.1Q VLAN support #device tuntap # Packet tunnel. device md # Memory "disks" diff --git a/sys/arm/conf/TS7800 b/sys/arm/conf/TS7800 index 17b237af46dd..15e9a77342d5 100644 --- a/sys/arm/conf/TS7800 +++ b/sys/arm/conf/TS7800 @@ -45,7 +45,6 @@ device pci # Pseudo devices device md device loop -device random # Serial ports device uart diff --git a/sys/arm/conf/VERSATILEPB b/sys/arm/conf/VERSATILEPB index 8c3e76cc2e87..3312f6d4f9e8 100644 --- a/sys/arm/conf/VERSATILEPB +++ b/sys/arm/conf/VERSATILEPB @@ -66,7 +66,6 @@ options SC_DFLT_FONT # compile font in makeoptions SC_DFLT_FONT=cp437 device md -device random # Entropy device options PLATFORM diff --git a/sys/arm/conf/VYBRID b/sys/arm/conf/VYBRID index 4ff18320df1a..a35a565711a2 100644 --- a/sys/arm/conf/VYBRID +++ b/sys/arm/conf/VYBRID @@ -59,7 +59,6 @@ device sdhci # generic sdhci # Pseudo devices device loop -device random device pty device md device gpio diff --git a/sys/arm/conf/ZEDBOARD b/sys/arm/conf/ZEDBOARD index 274d96642d6b..187d636c2e49 100644 --- a/sys/arm/conf/ZEDBOARD +++ b/sys/arm/conf/ZEDBOARD @@ -48,7 +48,6 @@ device pl310 # PL310 L2 cache controller device mpcore_timer device loop -device random device ether device cgem # Zynq-7000 gig ethernet device device mii diff --git a/sys/arm64/conf/GENERIC b/sys/arm64/conf/GENERIC index 8e3f04fe1db1..2adee9db99d4 100644 --- a/sys/arm64/conf/GENERIC +++ b/sys/arm64/conf/GENERIC @@ -293,7 +293,6 @@ device aw_cir # Pseudo devices. device crypto # core crypto support device loop # Network loopback -device random # Entropy device device ether # Ethernet support device vlan # 802.1Q VLAN support device tuntap # Packet tunnel. diff --git a/sys/conf/NOTES b/sys/conf/NOTES index 30ae142ba29b..34c1eab825b6 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -1170,9 +1170,6 @@ options NFS_DEBUG # Enable NFS Debugging # options EXT2FS -# Cryptographically secure random number generator; /dev/random -device random - # The system memory devices; /dev/mem, /dev/kmem device mem diff --git a/sys/conf/files b/sys/conf/files index dd67e0ec7a68..f84039696da6 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -686,14 +686,14 @@ crypto/des/des_ecb.c optional crypto | ipsec | ipsec_support | netsmb crypto/des/des_setkey.c optional crypto | ipsec | ipsec_support | netsmb crypto/rc4/rc4.c optional netgraph_mppc_encryption | kgssapi crypto/rijndael/rijndael-alg-fst.c optional crypto | ekcd | geom_bde | \ - ipsec | ipsec_support | random !random_loadable | wlan_ccmp -crypto/rijndael/rijndael-api-fst.c optional ekcd | geom_bde | random !random_loadable + ipsec | ipsec_support | !random_loadable | wlan_ccmp +crypto/rijndael/rijndael-api-fst.c optional ekcd | geom_bde | !random_loadable crypto/rijndael/rijndael-api.c optional crypto | ipsec | ipsec_support | \ wlan_ccmp crypto/sha1.c optional carp | crypto | ether | ipsec | \ ipsec_support | netgraph_mppc_encryption | sctp crypto/sha2/sha256c.c optional crypto | ekcd | geom_bde | ipsec | \ - ipsec_support | random !random_loadable | sctp | zfs + ipsec_support | !random_loadable | sctp | zfs crypto/sha2/sha512c.c optional crypto | geom_bde | ipsec | \ ipsec_support | zfs crypto/skein/skein.c optional crypto | zfs @@ -2766,11 +2766,11 @@ rt2860.fw optional rt2860fw | ralfw \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "rt2860.fw" -dev/random/random_infra.c optional random -dev/random/random_harvestq.c optional random -dev/random/randomdev.c optional random !random_loadable -dev/random/fortuna.c optional random !random_loadable -dev/random/hash.c optional random !random_loadable +dev/random/random_infra.c standard +dev/random/random_harvestq.c standard +dev/random/randomdev.c optional !random_loadable +dev/random/fortuna.c optional !random_loadable +dev/random/hash.c optional !random_loadable dev/rc/rc.c optional rc dev/rccgpio/rccgpio.c optional rccgpio gpio dev/re/if_re.c optional re diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64 index f8d9beba599d..b8c023425293 100644 --- a/sys/conf/files.arm64 +++ b/sys/conf/files.arm64 @@ -87,7 +87,7 @@ arm/broadcom/bcm2835/bcm2835_ft5406.c optional evdev bcm2835_ft5406 soc_brcm_bc arm/broadcom/bcm2835/bcm2835_gpio.c optional gpio soc_brcm_bcm2837 fdt arm/broadcom/bcm2835/bcm2835_intr.c optional soc_brcm_bcm2837 fdt arm/broadcom/bcm2835/bcm2835_mbox.c optional soc_brcm_bcm2837 fdt -arm/broadcom/bcm2835/bcm2835_rng.c optional random !random_loadable soc_brcm_bcm2837 fdt +arm/broadcom/bcm2835/bcm2835_rng.c optional !random_loadable soc_brcm_bcm2837 fdt arm/broadcom/bcm2835/bcm2835_sdhci.c optional sdhci soc_brcm_bcm2837 fdt arm/broadcom/bcm2835/bcm2835_sdhost.c optional sdhci soc_brcm_bcm2837 fdt arm/broadcom/bcm2835/bcm2835_spi.c optional bcm2835_spi soc_brcm_bcm2837 fdt diff --git a/sys/conf/files.powerpc b/sys/conf/files.powerpc index cbda69a0d7cf..ade545c59cd6 100644 --- a/sys/conf/files.powerpc +++ b/sys/conf/files.powerpc @@ -62,7 +62,7 @@ dev/ofw/ofw_standard.c optional aim powerpc dev/ofw/ofw_subr.c standard dev/powermac_nvram/powermac_nvram.c optional powermac_nvram powermac dev/quicc/quicc_bfe_fdt.c optional quicc mpc85xx -dev/random/darn.c optional powerpc64 random !random_loadable +dev/random/darn.c optional powerpc64 !random_loadable dev/scc/scc_bfe_macio.c optional scc powermac dev/sdhci/fsl_sdhci.c optional mpc85xx sdhci dev/sec/sec.c optional sec mpc85xx diff --git a/sys/conf/options b/sys/conf/options index df394936b9d4..6caae9a0708c 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -734,7 +734,6 @@ DEV_PCI opt_pci.h DEV_PF opt_pf.h DEV_PFLOG opt_pf.h DEV_PFSYNC opt_pf.h -DEV_RANDOM opt_global.h DEV_SPLASH opt_splash.h DEV_VLAN opt_vlan.h diff --git a/sys/i386/conf/GENERIC b/sys/i386/conf/GENERIC index dab73ee51da6..ddeabf5952c8 100644 --- a/sys/i386/conf/GENERIC +++ b/sys/i386/conf/GENERIC @@ -292,7 +292,6 @@ device wpi # Intel 3945ABG wireless NICs. # Pseudo devices. device crypto # core crypto support device loop # Network loopback -device random # Entropy device device padlock_rng # VIA Padlock RNG device rdrand_rng # Intel Bull Mountain RNG device ether # Ethernet support diff --git a/sys/i386/conf/MINIMAL b/sys/i386/conf/MINIMAL index 0b0bd23f40b4..0f1d268d013e 100644 --- a/sys/i386/conf/MINIMAL +++ b/sys/i386/conf/MINIMAL @@ -10,7 +10,7 @@ # some features (ACL, GJOURNAL) that GENERIC includes. # o acpi as a module has been reported flakey and not well tested, so # is included in the kernel. -# o random is included due to uncertaty... +# o (non-loaded) random is included due to uncertainty... # o Many networking things are included # # For now, please run changes to these list past imp@freebsd.org @@ -132,7 +132,6 @@ device agp # support several AGP chipsets # Pseudo devices. device loop # Network loopback -device random # Entropy device device padlock_rng # VIA Padlock RNG device rdrand_rng # Intel Bull Mountain RNG device ether # Ethernet support diff --git a/sys/mips/conf/BCM b/sys/mips/conf/BCM index 5c2753279a23..27d93766c354 100644 --- a/sys/mips/conf/BCM +++ b/sys/mips/conf/BCM @@ -82,7 +82,6 @@ device uart #Base device loop device ether -device random device md #Performance diff --git a/sys/mips/conf/DIR-825B1 b/sys/mips/conf/DIR-825B1 index 80a1d17c0ac0..8b43cf1b22ca 100644 --- a/sys/mips/conf/DIR-825B1 +++ b/sys/mips/conf/DIR-825B1 @@ -21,7 +21,6 @@ hints "DIR-825B1.hints" # Since the kernel image must fit inside 1024KiB, we have to build almost # everything as modules. -# nodevice random nodevice gpio nodevice gpioled nodevice gif diff --git a/sys/mips/conf/ERL b/sys/mips/conf/ERL index f12f6228bd95..a0e79450c871 100644 --- a/sys/mips/conf/ERL +++ b/sys/mips/conf/ERL @@ -149,7 +149,6 @@ device wlan_amrr # AMRR transmit rate control algorithm # Pseudo devices. device loop # Network loopback -device random # Entropy device device ether # Ethernet support device vlan # 802.1Q VLAN support device tuntap # Packet tunnel. diff --git a/sys/mips/conf/JZ4780 b/sys/mips/conf/JZ4780 index a3716cbe4873..459f908857a6 100644 --- a/sys/mips/conf/JZ4780 +++ b/sys/mips/conf/JZ4780 @@ -68,7 +68,6 @@ device miibus device bpf device md device uart -device random device fdt_pinctrl diff --git a/sys/mips/conf/OCTEON1 b/sys/mips/conf/OCTEON1 index 6c536f0d6ed4..256b66eff71f 100644 --- a/sys/mips/conf/OCTEON1 +++ b/sys/mips/conf/OCTEON1 @@ -184,7 +184,6 @@ device ral # Ralink Technology RT2500 wireless NICs. # Pseudo devices. device loop # Network loopback -device random # Entropy device device ether # Ethernet support device vlan # 802.1Q VLAN support device tuntap # Packet tunnel. diff --git a/sys/mips/conf/PB92 b/sys/mips/conf/PB92 index 4d3e890d0f96..64a0e6db120b 100644 --- a/sys/mips/conf/PB92 +++ b/sys/mips/conf/PB92 @@ -133,5 +133,4 @@ device loop device ether #device md #device bpf -device random #device if_bridge diff --git a/sys/mips/conf/PICOSTATION_M2HP b/sys/mips/conf/PICOSTATION_M2HP index e331f7764d2d..38e3d69c0509 100644 --- a/sys/mips/conf/PICOSTATION_M2HP +++ b/sys/mips/conf/PICOSTATION_M2HP @@ -68,6 +68,3 @@ device arswitch # Enable GPIO device gpio device gpioled - -# RNG -device random diff --git a/sys/mips/conf/WZR-300HP b/sys/mips/conf/WZR-300HP index 217e444f1b89..dd767888a1e9 100644 --- a/sys/mips/conf/WZR-300HP +++ b/sys/mips/conf/WZR-300HP @@ -49,4 +49,4 @@ device hwpmc # load these via modules, shrink kernel nodevice if_bridge nodevice bridgestp -nodevice random +options RANDOM_LOADABLE diff --git a/sys/mips/conf/WZR-HPAG300H b/sys/mips/conf/WZR-HPAG300H index b46f9de3eb8d..3337af682f2c 100644 --- a/sys/mips/conf/WZR-HPAG300H +++ b/sys/mips/conf/WZR-HPAG300H @@ -49,4 +49,4 @@ device hwpmc # load these via modules, shrink kernel nodevice if_bridge nodevice bridgestp -nodevice random +options RANDOM_LOADABLE diff --git a/sys/mips/conf/X1000 b/sys/mips/conf/X1000 index 907ea814de8f..8f10337218a5 100644 --- a/sys/mips/conf/X1000 +++ b/sys/mips/conf/X1000 @@ -63,7 +63,6 @@ device miibus device bpf device md device uart -device random device fdt_pinctrl diff --git a/sys/mips/conf/std.AR5312 b/sys/mips/conf/std.AR5312 index a3b055bfb743..56a45cb4c869 100644 --- a/sys/mips/conf/std.AR5312 +++ b/sys/mips/conf/std.AR5312 @@ -72,7 +72,6 @@ device loop device ether device md device bpf -device random options ARGE_DEBUG # Enable if_arge debugging for now diff --git a/sys/mips/conf/std.AR5315 b/sys/mips/conf/std.AR5315 index c9f85f6c0813..74a888c32f85 100644 --- a/sys/mips/conf/std.AR5315 +++ b/sys/mips/conf/std.AR5315 @@ -72,7 +72,6 @@ device loop device ether device md device bpf -device random options ARGE_DEBUG # Enable if_arge debugging for now diff --git a/sys/mips/conf/std.AR_MIPS_BASE b/sys/mips/conf/std.AR_MIPS_BASE index 37544a9b6660..ab0947a391ea 100644 --- a/sys/mips/conf/std.AR_MIPS_BASE +++ b/sys/mips/conf/std.AR_MIPS_BASE @@ -25,9 +25,6 @@ makeoptions MODULES_OVERRIDE+="gpio ar71xx if_gif if_vlan if_gre if_tuntap" makeoptions MODULES_OVERRIDE+="if_bridge bridgestp usb" makeoptions MODULES_OVERRIDE+="alq" -# Random - required during early boot! -device random - # net80211 options IEEE80211_DEBUG options IEEE80211_SUPPORT_MESH diff --git a/sys/mips/conf/std.BERI b/sys/mips/conf/std.BERI index 903af51875af..07f907b760df 100644 --- a/sys/mips/conf/std.BERI +++ b/sys/mips/conf/std.BERI @@ -61,5 +61,4 @@ device ether device geom_map device loop device md -device random device snp diff --git a/sys/mips/conf/std.MALTA b/sys/mips/conf/std.MALTA index 4c1965650fba..26940db1b92f 100644 --- a/sys/mips/conf/std.MALTA +++ b/sys/mips/conf/std.MALTA @@ -55,4 +55,3 @@ device miibus device bpf device md device uart -device random diff --git a/sys/mips/conf/std.XLP b/sys/mips/conf/std.XLP index 5330c19b3657..cbc13746fd06 100644 --- a/sys/mips/conf/std.XLP +++ b/sys/mips/conf/std.XLP @@ -66,7 +66,6 @@ makeoptions FDT_DTS_FILE=xlp-basic.dts # Pseudo device loop -device random device md device bpf diff --git a/sys/mips/mediatek/std.mediatek b/sys/mips/mediatek/std.mediatek index 7806da8f099a..d8c351aab36f 100644 --- a/sys/mips/mediatek/std.mediatek +++ b/sys/mips/mediatek/std.mediatek @@ -74,9 +74,6 @@ device fdt_pinctrl # UART support device uart -# random support -device random - # loop device support device loop diff --git a/sys/mips/mediatek/std.rt2880 b/sys/mips/mediatek/std.rt2880 index 8040585e9cb9..397a0bc322da 100644 --- a/sys/mips/mediatek/std.rt2880 +++ b/sys/mips/mediatek/std.rt2880 @@ -73,9 +73,6 @@ device fdt_pinctrl # UART support device uart -# random support -device random - # loop device support device loop diff --git a/sys/powerpc/conf/GENERIC b/sys/powerpc/conf/GENERIC index dc19d7a85598..78d83c9ba12d 100644 --- a/sys/powerpc/conf/GENERIC +++ b/sys/powerpc/conf/GENERIC @@ -162,7 +162,6 @@ device fxp # Intel EtherExpress PRO/100B (82557, 82558) # Pseudo devices. device crypto # core crypto support device loop # Network loopback -device random # Entropy device device ether # Ethernet support device vlan # 802.1Q VLAN support device tuntap # Packet tunnel. diff --git a/sys/powerpc/conf/GENERIC64 b/sys/powerpc/conf/GENERIC64 index dc3d54e371c9..409062047b24 100644 --- a/sys/powerpc/conf/GENERIC64 +++ b/sys/powerpc/conf/GENERIC64 @@ -183,7 +183,6 @@ device rl # RealTek 8129/8139 # Pseudo devices. device crypto # core crypto support device loop # Network loopback -device random # Entropy device device ether # Ethernet support device vlan # 802.1Q VLAN support device tuntap # Packet tunnel. diff --git a/sys/powerpc/conf/MPC85XX b/sys/powerpc/conf/MPC85XX index 3eeba5f54ec4..7962bdc22db0 100644 --- a/sys/powerpc/conf/MPC85XX +++ b/sys/powerpc/conf/MPC85XX @@ -93,7 +93,6 @@ device mmcsd device pass device pci device quicc -device random #device rl device scbus device scc diff --git a/sys/powerpc/conf/MPC85XXSPE b/sys/powerpc/conf/MPC85XXSPE index 1d649c1b36b9..2cea302361a3 100644 --- a/sys/powerpc/conf/MPC85XXSPE +++ b/sys/powerpc/conf/MPC85XXSPE @@ -94,7 +94,6 @@ device mmcsd device pass device pci device quicc -device random #device rl device scbus device scc diff --git a/sys/powerpc/conf/QORIQ64 b/sys/powerpc/conf/QORIQ64 index eecc0eb8e06b..1661829a6d25 100644 --- a/sys/powerpc/conf/QORIQ64 +++ b/sys/powerpc/conf/QORIQ64 @@ -99,7 +99,6 @@ device mmc device mmcsd device pass device pci -device random #device rl device scbus device scc diff --git a/sys/powerpc/conf/dpaa/DPAA b/sys/powerpc/conf/dpaa/DPAA index 2cbc908ec120..4aa24c188acc 100644 --- a/sys/powerpc/conf/dpaa/DPAA +++ b/sys/powerpc/conf/dpaa/DPAA @@ -96,7 +96,6 @@ device pci # Pseudo devices device ether # Ethernet support device loop # Network loopback -device random # Entropy device device bpf # Berkeley packet filter device md # Memory "disks" diff --git a/sys/riscv/conf/GENERIC b/sys/riscv/conf/GENERIC index 559e9166daa9..5b647977879f 100644 --- a/sys/riscv/conf/GENERIC +++ b/sys/riscv/conf/GENERIC @@ -137,7 +137,6 @@ options ZSTDIO # zstd-compressed kernel and user dumps # Pseudo devices. device crypto # core crypto support device loop # Network loopback -device random # Entropy device device ether # Ethernet support device vlan # 802.1Q VLAN support device tuntap # Packet tunnel. diff --git a/sys/sparc64/conf/GENERIC b/sys/sparc64/conf/GENERIC index 285adadf332c..75fe3f842577 100644 --- a/sys/sparc64/conf/GENERIC +++ b/sys/sparc64/conf/GENERIC @@ -224,7 +224,6 @@ device ath_rate_sample # SampleRate tx rate control for ath # Pseudo devices. device crypto # core crypto support device loop # Network loopback -device random # Entropy device device ether # Ethernet support device vlan # 802.1Q VLAN support device tuntap # Packet tunnel. diff --git a/sys/sys/random.h b/sys/sys/random.h index aa8c5f02c32e..8bcbe470cfc1 100644 --- a/sys/sys/random.h +++ b/sys/sys/random.h @@ -37,26 +37,9 @@ struct uio; -#if defined(DEV_RANDOM) void read_random(void *, u_int); int read_random_uio(struct uio *, bool); bool is_random_seeded(void); -#else -static __inline int -read_random_uio(void *a __unused, u_int b __unused) -{ - return (0); -} -static __inline void -read_random(void *a __unused, u_int b __unused) -{ -} -static __inline bool -is_random_seeded(void) -{ - return (false); -} -#endif /* * Note: if you add or remove members of random_entropy_source, remember to @@ -101,7 +84,6 @@ _Static_assert(ENTROPYSOURCE <= 32, #define RANDOM_LEGACY_BOOT_ENTROPY_MODULE "/boot/entropy" #define RANDOM_CACHED_BOOT_ENTROPY_MODULE "boot_entropy_cache" -#if defined(DEV_RANDOM) extern u_int hc_source_mask; void random_harvest_queue_(const void *, u_int, enum random_entropy_source); void random_harvest_fast_(const void *, u_int); @@ -133,13 +115,6 @@ random_harvest_direct(const void *entropy, u_int size, enum random_entropy_sourc void random_harvest_register_source(enum random_entropy_source); void random_harvest_deregister_source(enum random_entropy_source); -#else -#define random_harvest_queue(a, b, c) do {} while (0) -#define random_harvest_fast(a, b, c) do {} while (0) -#define random_harvest_direct(a, b, c) do {} while (0) -#define random_harvest_register_source(a) do {} while (0) -#define random_harvest_deregister_source(a) do {} while (0) -#endif #if defined(RANDOM_ENABLE_UMA) #define random_harvest_fast_uma(a, b, c) random_harvest_fast(a, b, c) diff --git a/tools/tools/nanobsd/pcengines/ALIX_DSK b/tools/tools/nanobsd/pcengines/ALIX_DSK index 96ae724d736b..e11f7de4f2f4 100644 --- a/tools/tools/nanobsd/pcengines/ALIX_DSK +++ b/tools/tools/nanobsd/pcengines/ALIX_DSK @@ -65,7 +65,6 @@ device ath_hal device ath_rate_sample device wi device loop -device random device ether device tun device pty diff --git a/tools/tools/tinybsd/conf/bridge/TINYBSD b/tools/tools/tinybsd/conf/bridge/TINYBSD index 0788aea40e44..5d99ad95700d 100644 --- a/tools/tools/tinybsd/conf/bridge/TINYBSD +++ b/tools/tools/tinybsd/conf/bridge/TINYBSD @@ -130,7 +130,6 @@ device wi # WaveLAN/Intersil/Symbol 802.11 wireless NICs. # Pseudo devices. device loop # Network loopback -device random # Entropy device device ether # Ethernet support device pty # Pseudo-ttys (telnet etc) device md # Memory "disks" diff --git a/tools/tools/tinybsd/conf/default/TINYBSD b/tools/tools/tinybsd/conf/default/TINYBSD index 6052764b3f81..841a19e8ee49 100644 --- a/tools/tools/tinybsd/conf/default/TINYBSD +++ b/tools/tools/tinybsd/conf/default/TINYBSD @@ -140,7 +140,6 @@ device wi # WaveLAN/Intersil/Symbol 802.11 wireless NICs. # Pseudo devices. device loop # Network loopback -device random # Entropy device device ether # Ethernet support device ppp # Kernel PPP device tun # Packet tunnel. diff --git a/tools/tools/tinybsd/conf/firewall/TINYBSD b/tools/tools/tinybsd/conf/firewall/TINYBSD index f410c139e371..994280346bbd 100644 --- a/tools/tools/tinybsd/conf/firewall/TINYBSD +++ b/tools/tools/tinybsd/conf/firewall/TINYBSD @@ -129,7 +129,6 @@ device wlan # 802.11 support # Pseudo devices. device loop # Network loopback -device random # Entropy device device ether # Ethernet support device pty # Pseudo-ttys (telnet etc) device md # Memory "disks" diff --git a/tools/tools/tinybsd/conf/minimal/TINYBSD b/tools/tools/tinybsd/conf/minimal/TINYBSD index 2cd1f9af9ae6..74e3c0506bcf 100644 --- a/tools/tools/tinybsd/conf/minimal/TINYBSD +++ b/tools/tools/tinybsd/conf/minimal/TINYBSD @@ -65,7 +65,6 @@ device pmtimer # Pseudo devices. device loop # Network loopback -device random # Entropy device device ether # Ethernet support device pty # Pseudo-ttys (telnet etc) device md # Memory "disks" diff --git a/tools/tools/tinybsd/conf/vpn/TINYBSD b/tools/tools/tinybsd/conf/vpn/TINYBSD index 956c13b00413..4fd064ef8fc7 100644 --- a/tools/tools/tinybsd/conf/vpn/TINYBSD +++ b/tools/tools/tinybsd/conf/vpn/TINYBSD @@ -130,7 +130,6 @@ device xe # Xircom pccard Ethernet # Pseudo devices. device loop # Network loopback -device random # Entropy device device ether # Ethernet support device ppp # Kernel PPP device tun # Packet tunnel. diff --git a/tools/tools/tinybsd/conf/wireless/TINYBSD b/tools/tools/tinybsd/conf/wireless/TINYBSD index aa7ddceb7895..afcd47ca4462 100644 --- a/tools/tools/tinybsd/conf/wireless/TINYBSD +++ b/tools/tools/tinybsd/conf/wireless/TINYBSD @@ -136,7 +136,6 @@ device wi # WaveLAN/Intersil/Symbol 802.11 wireless NICs. # Pseudo devices. device loop # Network loopback -device random # Entropy device device ether # Ethernet support device pty # Pseudo-ttys (telnet etc) device md # Memory "disks" diff --git a/tools/tools/tinybsd/conf/wrap/TINYBSD b/tools/tools/tinybsd/conf/wrap/TINYBSD index c3ce7954b278..2ef7c6742cbd 100644 --- a/tools/tools/tinybsd/conf/wrap/TINYBSD +++ b/tools/tools/tinybsd/conf/wrap/TINYBSD @@ -102,7 +102,6 @@ device ath_rate_sample # Pseudo devices. device loop # Network loopback -device random # Entropy device device ether # Ethernet support device ppp # Kernel PPP device tun # Packet tunnel. From 58b5b90d6a01a16a4b549354cc79a54bdd5cbd26 Mon Sep 17 00:00:00 2001 From: Conrad Meyer Date: Fri, 21 Jun 2019 00:33:45 +0000 Subject: [PATCH 013/165] Fixup UPDATING text for r349253 Requested by: delphij --- UPDATING | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/UPDATING b/UPDATING index 86ffdc7379d5..479a9a6eb729 100644 --- a/UPDATING +++ b/UPDATING @@ -32,8 +32,8 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 13.x IS SLOW: "ln -s 'abort:false,junk:false' /etc/malloc.conf".) 20190620: - The "device random" option has been removed. Entropy collection and - the /dev/random device are no longer an optional component. + Entropy collection and the /dev/random device are no longer optional + components. The "device random" option has been removed. Implementations of distilling algorithms can still be made loadable with "options RANDOM_LOADABLE" (e.g., random_fortuna.ko). From cd07b6eddcbec6492582646974f3b7d4a92a949f Mon Sep 17 00:00:00 2001 From: Conrad Meyer Date: Fri, 21 Jun 2019 02:37:54 +0000 Subject: [PATCH 014/165] rc.d/motd: Update motd more robustly Use appropriate fsyncs to persist the rewritten /etc/motd file, when a rewrite is performed. Reported by: Jonathan Walton Reviewed by: allanjude, vangyzen Sponsored by: Dell EMC Isilon Differential Revision: https://reviews.freebsd.org/D20701 --- libexec/rc/rc.d/motd | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/libexec/rc/rc.d/motd b/libexec/rc/rc.d/motd index acb376723e80..2c06187c1d2a 100755 --- a/libexec/rc/rc.d/motd +++ b/libexec/rc/rc.d/motd @@ -37,11 +37,15 @@ motd_start() uname -v | sed -e 's,^\([^#]*\) #\(.* [1-2][0-9][0-9][0-9]\).*/\([^\]*\) $,\1 (\3) #\2,' > ${T} awk '{if (NR == 1) {if ($1 == "FreeBSD") {next} else {print "\n"$0}} else {print}}' < /etc/motd >> ${T} - cmp -s $T /etc/motd || { - cp $T /etc/motd + if ! cmp -s $T /etc/motd; then + mv -f $T /etc/.motd.tmp + fsync /etc/.motd.tmp + mv -f /etc/.motd.tmp /etc/motd chmod ${PERMS} /etc/motd - } - rm -f $T + fsync /etc + else + rm -f $T + fi check_startmsgs && echo '.' } From a3cea1de1a2eeed04c96b64d8ccd86ae234635bf Mon Sep 17 00:00:00 2001 From: Kevin Lo Date: Fri, 21 Jun 2019 02:49:36 +0000 Subject: [PATCH 015/165] Correct function names. --- share/man/man9/iflibdi.9 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/share/man/man9/iflibdi.9 b/share/man/man9/iflibdi.9 index 84340d502080..c37832ede6af 100644 --- a/share/man/man9/iflibdi.9 +++ b/share/man/man9/iflibdi.9 @@ -1,5 +1,5 @@ .\" $FreeBSD$ -.Dd May 24, 2017 +.Dd May 21, 2019 .Dt IFLIBDI 9 .Os .Sh NAME @@ -194,10 +194,10 @@ Allocate and initialize the \fIif_ctx_t\fP structure. Setup and initialize the MSI or MSI/X interrupt queues if necessary. Allocate memory for queues and qset structure setup. -.It Fn iflib_device_irq_alloc +.It Fn iflib_irq_alloc Allocate an interrupt resource for a given rid value with an associated filter and handler function. -.It Fn iflib_device_irq_alloc_generic +.It Fn iflib_irq_alloc_generic Performs the same function as iflib_device_irq_alloc along with the additional functionality of adding a taskgroup. The data fields and callback function are determined by the type of interrupt, From 804b78634d543667a37ac459e692fe42c9dd30e8 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Fri, 21 Jun 2019 03:49:36 +0000 Subject: [PATCH 016/165] Mount and unmount devfs around calls to add packages. pkg now uses /dev/null for some of its operations. NanoBSD's packaging stuff didn't mount that for the chroot it ran in, so any config that added packages would see the error: pkg: Cannot open /dev/null:No such file or directory when trying to actually add those packages. It's easy enough for nanobsd to mount /dev and it won't hurt anything that was already working and may help things that weren't (like this). I moved the mount/unmount pair to be in the right push/pop order from the submitted patch. PR: 238727 Submitted by: mike tancsa Tested by: Karl Denninger --- tools/tools/nanobsd/defaults.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/tools/nanobsd/defaults.sh b/tools/tools/nanobsd/defaults.sh index 0002373be658..86acab65f67d 100755 --- a/tools/tools/nanobsd/defaults.sh +++ b/tools/tools/nanobsd/defaults.sh @@ -778,8 +778,9 @@ cust_pkgng ( ) ( # Mount packages into chroot mkdir -p ${NANO_WORLDDIR}/_.p mount -t nullfs -o noatime -o ro ${NANO_PACKAGE_DIR} ${NANO_WORLDDIR}/_.p + mount -t devfs devfs ${NANO_WORLDDIR}/dev - trap "umount ${NANO_WORLDDIR}/_.p ; rm -rf ${NANO_WORLDDIR}/_.p" 1 2 15 EXIT + trap "umount ${NANO_WORLDDIR}/dev; umount ${NANO_WORLDDIR}/_.p ; rm -rf ${NANO_WORLDDIR}/_.p" 1 2 15 EXIT # Install pkg-* package CR "${PKGCMD} add /_.p/${_NANO_PKG_PACKAGE}" @@ -804,6 +805,7 @@ cust_pkgng ( ) ( CR0 "${PKGCMD} info" trap - 1 2 15 EXIT + umount ${NANO_WORLDDIR}/dev umount ${NANO_WORLDDIR}/_.p rm -rf ${NANO_WORLDDIR}/_.p ) From 65a184e091bb8df4886227d659a08d1516388784 Mon Sep 17 00:00:00 2001 From: Shteryana Shopova Date: Fri, 21 Jun 2019 07:29:02 +0000 Subject: [PATCH 017/165] Unbreak snmp_pf(3) after the changes introduced in r338209 PR: 237011 Event: Vienna Hackathon 2019 MFC after: 2 weeks --- usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c | 2 +- usr.sbin/bsnmpd/modules/snmp_pf/pf_tree.def | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c b/usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c index 7d4398264322..d20f7bccfe26 100644 --- a/usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c +++ b/usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c @@ -907,7 +907,7 @@ pf_tbladdr(struct snmp_context __unused *ctx, struct snmp_value __unused *val, } int -pf_altq(struct snmp_context __unused *ctx, struct snmp_value *val, +pf_altq_num(struct snmp_context __unused *ctx, struct snmp_value *val, u_int sub, u_int __unused vindex, enum snmp_op op) { asn_subid_t which = val->var.subs[sub - 1]; diff --git a/usr.sbin/bsnmpd/modules/snmp_pf/pf_tree.def b/usr.sbin/bsnmpd/modules/snmp_pf/pf_tree.def index 1dfa14ce4c2a..b545c1e79fae 100644 --- a/usr.sbin/bsnmpd/modules/snmp_pf/pf_tree.def +++ b/usr.sbin/bsnmpd/modules/snmp_pf/pf_tree.def @@ -174,7 +174,7 @@ ) ) (10 pfAltq - (1 pfAltqQueueNumber INTEGER32 pf_altq GET) + (1 pfAltqQueueNumber INTEGER32 pf_altq_num GET) (2 pfAltqQueueTable (1 pfAltqQueueEntry : INTEGER32 pf_altqq (1 pfAltqQueueIndex INTEGER32) From 9a8070808e9c3ccf866ec81a25c9cfb9a71ca2d3 Mon Sep 17 00:00:00 2001 From: Shteryana Shopova Date: Fri, 21 Jun 2019 07:45:58 +0000 Subject: [PATCH 018/165] No need for each bsnmpd(1) module to open connection to syslog bsnmpd(1) main does that early on init and the connection is available to all loaded modules Event: Vienna Hackathon 2019 PR: 233431 , 221487 MFC after: 2 weeks --- usr.sbin/bsnmpd/modules/snmp_lm75/snmp_lm75.c | 1 - 1 file changed, 1 deletion(-) diff --git a/usr.sbin/bsnmpd/modules/snmp_lm75/snmp_lm75.c b/usr.sbin/bsnmpd/modules/snmp_lm75/snmp_lm75.c index 1822f7801e80..a55050b851d3 100644 --- a/usr.sbin/bsnmpd/modules/snmp_lm75/snmp_lm75.c +++ b/usr.sbin/bsnmpd/modules/snmp_lm75/snmp_lm75.c @@ -100,7 +100,6 @@ lm75_init(struct lmodule *mod, int argc __unused, char *argv[] __unused) module = mod; lm75_sensors = 0; - openlog("snmp_lm75", LOG_NDELAY | LOG_PID, LOG_DAEMON); return(0); } From 05fc9d78d783848f63ccf1d1dc54775aab284bc6 Mon Sep 17 00:00:00 2001 From: Kristof Provost Date: Fri, 21 Jun 2019 07:58:08 +0000 Subject: [PATCH 019/165] ip_output: pass PFIL_FWD in the slow path If we take the slow path for forwarding we should still tell our firewalls (hooked through pfil(9)) that we're forwarding. Pass the ip_output() flags to ip_output_pfil() so it can set the PFIL_FWD flag when we're forwarding. MFC after: 1 week Sponsored by: Axiado --- sys/netinet/ip_output.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index 99b8c3662be5..2a7eb7f56286 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -109,20 +109,24 @@ extern int in_mcast_loop; extern struct protosw inetsw[]; static inline int -ip_output_pfil(struct mbuf **mp, struct ifnet *ifp, struct inpcb *inp, - struct sockaddr_in *dst, int *fibnum, int *error) +ip_output_pfil(struct mbuf **mp, struct ifnet *ifp, int flags, + struct inpcb *inp, struct sockaddr_in *dst, int *fibnum, int *error) { struct m_tag *fwd_tag = NULL; struct mbuf *m; struct in_addr odst; struct ip *ip; + int pflags = PFIL_OUT; + + if (flags & IP_FORWARDING) + pflags |= PFIL_FWD; m = *mp; ip = mtod(m, struct ip *); /* Run through list of hooks for output packets. */ odst.s_addr = ip->ip_dst.s_addr; - switch (pfil_run_hooks(V_inet_pfil_head, mp, ifp, PFIL_OUT, inp)) { + switch (pfil_run_hooks(V_inet_pfil_head, mp, ifp, pflags, inp)) { case PFIL_DROPPED: *error = EPERM; /* FALLTHROUGH */ @@ -653,7 +657,8 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags, /* Jump over all PFIL processing if hooks are not active. */ if (PFIL_HOOKED_OUT(V_inet_pfil_head)) { - switch (ip_output_pfil(&m, ifp, inp, dst, &fibnum, &error)) { + switch (ip_output_pfil(&m, ifp, flags, inp, dst, &fibnum, + &error)) { case 1: /* Finished */ goto done; From 978f2d17285bf3a0017510c61eb71a2dcae38dbe Mon Sep 17 00:00:00 2001 From: "Andrey V. Elsukov" Date: Fri, 21 Jun 2019 10:54:51 +0000 Subject: [PATCH 020/165] Add "tcpmss" opcode to match the TCP MSS value. With this opcode it is possible to match TCP packets with specified MSS option, whose value corresponds to configured in opcode value. It is allowed to specify single value, range of values, or array of specific values or ranges. E.g. # ipfw add deny log tcp from any to any tcpmss 0-500 Reviewed by: melifaro,bcr Obtained from: Yandex LLC MFC after: 1 week Sponsored by: Yandex LLC --- sbin/ipfw/ipfw.8 | 8 +++++- sbin/ipfw/ipfw2.c | 20 +++++++++++---- sbin/ipfw/ipfw2.h | 1 + sys/netinet/ip_fw.h | 1 + sys/netpfil/ipfw/ip_fw2.c | 42 ++++++++++++++++++++++++++++---- sys/netpfil/ipfw/ip_fw_sockopt.c | 5 +++- 6 files changed, 65 insertions(+), 12 deletions(-) diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8 index fcba4a4b03f2..bcc8017a571b 100644 --- a/sbin/ipfw/ipfw.8 +++ b/sbin/ipfw/ipfw.8 @@ -1,7 +1,7 @@ .\" .\" $FreeBSD$ .\" -.Dd May 24, 2019 +.Dd June 21, 2019 .Dt IPFW 8 .Os .Sh NAME @@ -1989,6 +1989,12 @@ a non-zero offset. See the .Cm frag option for details on matching fragmented packets. +.It Cm tcpmss Ar tcpmss-list +Matches TCP packets whose MSS (maximum segment size) value is set to +.Ar tcpmss-list , +which is either a single value or a list of values or ranges +specified in the same way as +.Ar ports . .It Cm tcpseq Ar seq TCP packets only. Match if the TCP header sequence number field is set to diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c index 3e73fa3b8736..4fd977edb91f 100644 --- a/sbin/ipfw/ipfw2.c +++ b/sbin/ipfw/ipfw2.c @@ -338,6 +338,7 @@ static struct _s_x rule_options[] = { { "tcpdatalen", TOK_TCPDATALEN }, { "tcpflags", TOK_TCPFLAGS }, { "tcpflgs", TOK_TCPFLAGS }, + { "tcpmss", TOK_TCPMSS }, { "tcpoptions", TOK_TCPOPTS }, { "tcpopts", TOK_TCPOPTS }, { "tcpseq", TOK_TCPSEQ }, @@ -881,6 +882,7 @@ static struct _s_x _port_name[] = { {"ipttl", O_IPTTL}, {"mac-type", O_MAC_TYPE}, {"tcpdatalen", O_TCPDATALEN}, + {"tcpmss", O_TCPMSS}, {"tcpwin", O_TCPWIN}, {"tagged", O_TAGGED}, {NULL, 0} @@ -1588,6 +1590,7 @@ print_instruction(struct buf_pr *bp, const struct format_opts *fo, case O_IPTTL: case O_IPLEN: case O_TCPDATALEN: + case O_TCPMSS: case O_TCPWIN: if (F_LEN(cmd) == 1) { switch (cmd->opcode) { @@ -1603,6 +1606,9 @@ print_instruction(struct buf_pr *bp, const struct format_opts *fo, case O_TCPDATALEN: s = "tcpdatalen"; break; + case O_TCPMSS: + s = "tcpmss"; + break; case O_TCPWIN: s = "tcpwin"; break; @@ -4709,14 +4715,18 @@ compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate) av++; break; + case TOK_TCPMSS: case TOK_TCPWIN: - NEED1("tcpwin requires length"); + NEED1("tcpmss/tcpwin requires size"); if (strpbrk(*av, "-,")) { - if (!add_ports(cmd, *av, 0, O_TCPWIN, cblen)) - errx(EX_DATAERR, "invalid tcpwin len %s", *av); + if (add_ports(cmd, *av, 0, + i == TOK_TCPWIN ? O_TCPWIN : O_TCPMSS, + cblen) == NULL) + errx(EX_DATAERR, "invalid %s size %s", + s, *av); } else - fill_cmd(cmd, O_TCPWIN, 0, - strtoul(*av, NULL, 0)); + fill_cmd(cmd, i == TOK_TCPWIN ? O_TCPWIN : + O_TCPMSS, 0, strtoul(*av, NULL, 0)); av++; break; diff --git a/sbin/ipfw/ipfw2.h b/sbin/ipfw/ipfw2.h index e6c209d65bab..215416eecc8a 100644 --- a/sbin/ipfw/ipfw2.h +++ b/sbin/ipfw/ipfw2.h @@ -151,6 +151,7 @@ enum tokens { TOK_TCPOPTS, TOK_TCPSEQ, TOK_TCPACK, + TOK_TCPMSS, TOK_TCPWIN, TOK_ICMPTYPES, TOK_MAC, diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h index de0cc29db1d2..7a01c82ba58b 100644 --- a/sys/netinet/ip_fw.h +++ b/sys/netinet/ip_fw.h @@ -293,6 +293,7 @@ enum ipfw_opcodes { /* arguments (4 byte each) */ O_EXTERNAL_DATA, /* variable length data */ O_SKIP_ACTION, /* none */ + O_TCPMSS, /* arg1=MSS value */ O_LAST_OPCODE /* not an opcode! */ }; diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c index a4a3830132eb..6796ad81611d 100644 --- a/sys/netpfil/ipfw/ip_fw2.c +++ b/sys/netpfil/ipfw/ip_fw2.c @@ -331,10 +331,10 @@ ipopts_match(struct ip *ip, ipfw_insn *cmd) } static int -tcpopts_match(struct tcphdr *tcp, ipfw_insn *cmd) +tcpopts_parse(struct tcphdr *tcp, uint16_t *mss) { - int optlen, bits = 0; u_char *cp = (u_char *)(tcp + 1); + int optlen, bits = 0; int x = (tcp->th_off << 2) - sizeof(struct tcphdr); for (; x > 0; x -= optlen, cp += optlen) { @@ -350,12 +350,13 @@ tcpopts_match(struct tcphdr *tcp, ipfw_insn *cmd) } switch (opt) { - default: break; case TCPOPT_MAXSEG: bits |= IP_FW_TCPOPT_MSS; + if (mss != NULL) + *mss = be16dec(cp + 2); break; case TCPOPT_WINDOW: @@ -370,10 +371,16 @@ tcpopts_match(struct tcphdr *tcp, ipfw_insn *cmd) case TCPOPT_TIMESTAMP: bits |= IP_FW_TCPOPT_TS; break; - } } - return (flags_match(cmd, bits)); + return (bits); +} + +static int +tcpopts_match(struct tcphdr *tcp, ipfw_insn *cmd) +{ + + return (flags_match(cmd, tcpopts_parse(tcp, NULL))); } static int @@ -2316,6 +2323,31 @@ do { \ TCP(ulp)->th_ack); break; + case O_TCPMSS: + if (proto == IPPROTO_TCP && + (args->f_id._flags & TH_SYN) != 0 && + ulp != NULL) { + uint16_t mss, *p; + int i; + + PULLUP_LEN(hlen, ulp, + (TCP(ulp)->th_off << 2)); + if ((tcpopts_parse(TCP(ulp), &mss) & + IP_FW_TCPOPT_MSS) == 0) + break; + if (cmdlen == 1) { + match = (cmd->arg1 == mss); + break; + } + /* Otherwise we have ranges. */ + p = ((ipfw_insn_u16 *)cmd)->ports; + i = cmdlen - 1; + for (; !match && i > 0; i--, p += 2) + match = (mss >= p[0] && + mss <= p[1]); + } + break; + case O_TCPWIN: if (proto == IPPROTO_TCP && offset == 0) { uint16_t x; diff --git a/sys/netpfil/ipfw/ip_fw_sockopt.c b/sys/netpfil/ipfw/ip_fw_sockopt.c index a83e75447633..297b01ca7d3d 100644 --- a/sys/netpfil/ipfw/ip_fw_sockopt.c +++ b/sys/netpfil/ipfw/ip_fw_sockopt.c @@ -1176,7 +1176,9 @@ move_objects(struct ip_fw_chain *ch, ipfw_range_tlv *rt) } } return (c); -}/* +} + +/* * Changes set of given rule rannge @rt * with each other. * @@ -1907,6 +1909,7 @@ check_ipfw_rule_body(ipfw_insn *cmd, int cmd_len, struct rule_check_info *ci) case O_IPTTL: case O_IPLEN: case O_TCPDATALEN: + case O_TCPMSS: case O_TCPWIN: case O_TAGGED: if (cmdlen < 1 || cmdlen > 31) From b72236b4075f96fdaf20c3ffcf7393463644aeeb Mon Sep 17 00:00:00 2001 From: Ed Maste Date: Fri, 21 Jun 2019 13:42:40 +0000 Subject: [PATCH 021/165] nandsim: correct test to avoid out-of-bounds access Previously nandsim_chip_status returned EINVAL iff both of user-provided chip->ctrl_num and chip->num were out of bounds. If only one failed the bounds check arbitrary memory would be read and returned. The NAND framework is not built by default, nandsim is not intended for production use (it is a simulator), and the nandsim device has root-only permissions. admbugs: 827 Reported by: Daniel Hodson of elttam MFC after: 3 days Security: kernel information leak or DoS Sponsored by: The FreeBSD Foundation --- sys/dev/nand/nandsim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/dev/nand/nandsim.c b/sys/dev/nand/nandsim.c index 4639a15700a2..50e4f8bb2e33 100644 --- a/sys/dev/nand/nandsim.c +++ b/sys/dev/nand/nandsim.c @@ -295,7 +295,7 @@ nandsim_chip_status(struct sim_chip *chip) nand_debug(NDBG_SIM,"status for chip num:%d at ctrl:%d", chip->num, chip->ctrl_num); - if (chip->ctrl_num >= MAX_SIM_DEV && + if (chip->ctrl_num >= MAX_SIM_DEV || chip->num >= MAX_CTRL_CS) return (EINVAL); From 3103a7eef7b062131a381b22de3f5e01b61c4367 Mon Sep 17 00:00:00 2001 From: Ian Lepore Date: Fri, 21 Jun 2019 14:01:02 +0000 Subject: [PATCH 022/165] Some mundane tweaks and cleanups to help de-clutter the diffs of some upcoming functional changes. Add an ofw_compat_data table for probing compat strings, and use it to add PNP data. Remove some stray semicolons at the end of macro definitions, and add a PWM_LOCK_ASSERT macro to round out the usual suite. Move the device_t and driver_methods structs to the end of the file. Tweak comments. --- sys/arm/ti/am335x/am335x_ehrpwm.c | 45 ++++++++++++++++++------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/sys/arm/ti/am335x/am335x_ehrpwm.c b/sys/arm/ti/am335x/am335x_ehrpwm.c index 53cb3bb78249..298dd601ef0a 100644 --- a/sys/arm/ti/am335x/am335x_ehrpwm.c +++ b/sys/arm/ti/am335x/am335x_ehrpwm.c @@ -53,13 +53,14 @@ __FBSDID("$FreeBSD$"); #define PWM_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) #define PWM_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) +#define PWM_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED) #define PWM_LOCK_INIT(_sc) mtx_init(&(_sc)->sc_mtx, \ device_get_nameunit(_sc->sc_dev), "am335x_ehrpwm softc", MTX_DEF) #define PWM_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx) -#define EPWM_READ2(_sc, reg) bus_read_2((_sc)->sc_mem_res, reg); +#define EPWM_READ2(_sc, reg) bus_read_2((_sc)->sc_mem_res, reg) #define EPWM_WRITE2(_sc, reg, value) \ - bus_write_2((_sc)->sc_mem_res, reg, value); + bus_write_2((_sc)->sc_mem_res, reg, value) #define EPWM_TBCTL 0x00 #define TBCTL_FREERUN (2 << 14) @@ -140,7 +141,8 @@ struct am335x_ehrpwm_softc { struct mtx sc_mtx; struct resource *sc_mem_res; int sc_mem_rid; - /* sysctl for configuration */ + + /* Things used for configuration via sysctl [deprecated]. */ int sc_pwm_clkdiv; int sc_pwm_freq; struct sysctl_oid *sc_clkdiv_oid; @@ -153,21 +155,12 @@ struct am335x_ehrpwm_softc { uint32_t sc_pwm_dutyB; }; -static device_method_t am335x_ehrpwm_methods[] = { - DEVMETHOD(device_probe, am335x_ehrpwm_probe), - DEVMETHOD(device_attach, am335x_ehrpwm_attach), - DEVMETHOD(device_detach, am335x_ehrpwm_detach), - - DEVMETHOD_END +static struct ofw_compat_data compat_data[] = { + {"ti,am33xx-ehrpwm", true}, + {NULL, false}, }; +SIMPLEBUS_PNP_INFO(compat_data); -static driver_t am335x_ehrpwm_driver = { - "am335x_ehrpwm", - am335x_ehrpwm_methods, - sizeof(struct am335x_ehrpwm_softc), -}; - -static devclass_t am335x_ehrpwm_devclass; static void am335x_ehrpwm_freq(struct am335x_ehrpwm_softc *sc) @@ -337,7 +330,7 @@ am335x_ehrpwm_probe(device_t dev) if (!ofw_bus_status_okay(dev)) return (ENXIO); - if (!ofw_bus_is_compatible(dev, "ti,am33xx-ehrpwm")) + if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) return (ENXIO); device_set_desc(dev, "AM335x EHRPWM"); @@ -365,7 +358,7 @@ am335x_ehrpwm_attach(device_t dev) goto fail; } - /* Init backlight interface */ + /* Init sysctl interface */ ctx = device_get_sysctl_ctx(sc->sc_dev); tree = device_get_sysctl_tree(sc->sc_dev); @@ -442,6 +435,22 @@ am335x_ehrpwm_detach(device_t dev) return (0); } +static device_method_t am335x_ehrpwm_methods[] = { + DEVMETHOD(device_probe, am335x_ehrpwm_probe), + DEVMETHOD(device_attach, am335x_ehrpwm_attach), + DEVMETHOD(device_detach, am335x_ehrpwm_detach), + + DEVMETHOD_END +}; + +static driver_t am335x_ehrpwm_driver = { + "pwm", + am335x_ehrpwm_methods, + sizeof(struct am335x_ehrpwm_softc), +}; + +static devclass_t am335x_ehrpwm_devclass; + DRIVER_MODULE(am335x_ehrpwm, am335x_pwmss, am335x_ehrpwm_driver, am335x_ehrpwm_devclass, 0, 0); MODULE_VERSION(am335x_ehrpwm, 1); MODULE_DEPEND(am335x_ehrpwm, am335x_pwmss, 1, 1, 1); From ef558a107824372e4bb70ef57cff4406a8f7fedd Mon Sep 17 00:00:00 2001 From: Ian Lepore Date: Fri, 21 Jun 2019 14:24:33 +0000 Subject: [PATCH 023/165] Add support for the PWM(9) API. This allows configuring the pwm output using pwm(9), but also maintains the historical sysctl config interface for compatiblity with existing apps. The two config systems are not compatible with each other; if you use both interfaces to change configurations you're likely to end up with incorrect output or none at all. --- sys/arm/ti/am335x/am335x_ehrpwm.c | 265 +++++++++++++++++++++++++++++- 1 file changed, 264 insertions(+), 1 deletion(-) diff --git a/sys/arm/ti/am335x/am335x_ehrpwm.c b/sys/arm/ti/am335x/am335x_ehrpwm.c index 298dd601ef0a..cbb947038ba9 100644 --- a/sys/arm/ti/am335x/am335x_ehrpwm.c +++ b/sys/arm/ti/am335x/am335x_ehrpwm.c @@ -45,12 +45,33 @@ __FBSDID("$FreeBSD$"); #include #include +#include "pwmbus_if.h" + #include "am335x_pwm.h" +/******************************************************************************* + * Enhanced resolution PWM driver. Many of the advanced featues of the hardware + * are not supported by this driver. What is implemented here is simple + * variable-duty-cycle PWM output. + * + * Note that this driver was historically configured using a set of sysctl + * variables/procs, and later gained support for the PWM(9) API. The sysctl + * code is still present to support existing apps, but that interface is + * considered deprecated. + * + * An important caveat is that the original sysctl interface and the new PWM API + * cannot both be used at once. If both interfaces are used to change + * configuration, it's quite likely you won't get the expected results. Also, + * reading the sysctl values after configuring via PWM will not return the right + * results. + ******************************************************************************/ + /* In ticks */ #define DEFAULT_PWM_PERIOD 1000 #define PWM_CLOCK 100000000UL +#define NS_PER_SEC 1000000000 + #define PWM_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) #define PWM_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) #define PWM_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED) @@ -120,6 +141,11 @@ __FBSDID("$FreeBSD$"); #define AQCTL_ZRO_TOGGLE (3 << 0) #define EPWM_AQSFRC 0x1a #define EPWM_AQCSFRC 0x1c +#define AQCSFRC_OFF 0 +#define AQCSFRC_LO 1 +#define AQCSFRC_HI 2 +#define AQCSFRC_MASK 3 +#define AQCSFRC(chan, hilo) ((hilo) << (2 * chan)) /* Trip-Zone module */ #define EPWM_TZCTL 0x28 @@ -136,8 +162,16 @@ static device_detach_t am335x_ehrpwm_detach; static int am335x_ehrpwm_clkdiv[8] = { 1, 2, 4, 8, 16, 32, 64, 128 }; +struct ehrpwm_channel { + u_int duty; /* on duration, in ns */ + bool enabled; /* channel enabled? */ + bool inverted; /* signal inverted? */ +}; +#define NUM_CHANNELS 2 + struct am335x_ehrpwm_softc { device_t sc_dev; + device_t sc_busdev; struct mtx sc_mtx; struct resource *sc_mem_res; int sc_mem_rid; @@ -153,6 +187,12 @@ struct am335x_ehrpwm_softc { uint32_t sc_pwm_period; uint32_t sc_pwm_dutyA; uint32_t sc_pwm_dutyB; + + /* Things used for configuration via pwm(9) api. */ + u_int sc_clkfreq; /* frequency in Hz */ + u_int sc_clktick; /* duration in ns */ + u_int sc_period; /* duration in ns */ + struct ehrpwm_channel sc_channels[NUM_CHANNELS]; }; static struct ofw_compat_data compat_data[] = { @@ -161,6 +201,116 @@ static struct ofw_compat_data compat_data[] = { }; SIMPLEBUS_PNP_INFO(compat_data); +static void +am335x_ehrpwm_cfg_duty(struct am335x_ehrpwm_softc *sc, u_int chan, u_int duty) +{ + u_int tbcmp; + + if (duty == 0) + tbcmp = 0; + else + tbcmp = max(1, duty / sc->sc_clktick); + + sc->sc_channels[chan].duty = tbcmp * sc->sc_clktick; + + PWM_LOCK_ASSERT(sc); + EPWM_WRITE2(sc, (chan == 0) ? EPWM_CMPA : EPWM_CMPB, tbcmp); +} + +static void +am335x_ehrpwm_cfg_enable(struct am335x_ehrpwm_softc *sc, u_int chan, bool enable) +{ + uint16_t regval; + + sc->sc_channels[chan].enabled = enable; + + /* + * Turn off any existing software-force of the channel, then force + * it in the right direction (high or low) if it's not being enabled. + */ + PWM_LOCK_ASSERT(sc); + regval = EPWM_READ2(sc, EPWM_AQCSFRC); + regval &= ~AQCSFRC(chan, AQCSFRC_MASK); + if (!sc->sc_channels[chan].enabled) { + if (sc->sc_channels[chan].inverted) + regval |= AQCSFRC(chan, AQCSFRC_HI); + else + regval |= AQCSFRC(chan, AQCSFRC_LO); + } + EPWM_WRITE2(sc, EPWM_AQCSFRC, regval); +} + +static bool +am335x_ehrpwm_cfg_period(struct am335x_ehrpwm_softc *sc, u_int period) +{ + uint16_t regval; + u_int clkdiv, hspclkdiv, pwmclk, pwmtick, tbprd; + + /* Can't do a period shorter than 2 clock ticks. */ + if (period < 2 * NS_PER_SEC / PWM_CLOCK) { + sc->sc_clkfreq = 0; + sc->sc_clktick = 0; + sc->sc_period = 0; + return (false); + } + + /* + * Figure out how much we have to divide down the base 100MHz clock so + * that we can express the requested period as a 16-bit tick count. + */ + tbprd = 0; + for (clkdiv = 0; clkdiv < 8; ++clkdiv) { + const u_int cd = 1 << clkdiv; + for (hspclkdiv = 0; hspclkdiv < 8; ++hspclkdiv) { + const u_int cdhs = max(1, hspclkdiv * 2); + pwmclk = PWM_CLOCK / (cd * cdhs); + pwmtick = NS_PER_SEC / pwmclk; + if (period / pwmtick < 65536) { + tbprd = period / pwmtick; + break; + } + } + if (tbprd != 0) + break; + } + + /* Handle requested period too long for available clock divisors. */ + if (tbprd == 0) + return (false); + + /* + * If anything has changed from the current settings, reprogram the + * clock divisors and period register. + */ + if (sc->sc_clkfreq != pwmclk || sc->sc_clktick != pwmtick || + sc->sc_period != tbprd * pwmtick) { + + sc->sc_clkfreq = pwmclk; + sc->sc_clktick = pwmtick; + sc->sc_period = tbprd * pwmtick; + + PWM_LOCK_ASSERT(sc); + regval = EPWM_READ2(sc, EPWM_TBCTL); + regval &= ~(TBCTL_CLKDIV_MASK | TBCTL_HSPCLKDIV_MASK); + regval |= TBCTL_CLKDIV(clkdiv) | TBCTL_HSPCLKDIV(hspclkdiv); + EPWM_WRITE2(sc, EPWM_TBCTL, regval); + EPWM_WRITE2(sc, EPWM_TBPRD, tbprd - 1); +#if 0 + device_printf(sc->sc_dev, "clkdiv %u hspclkdiv %u tbprd %u " + "clkfreq %u Hz clktick %u ns period got %u requested %u\n", + clkdiv, hspclkdiv, tbprd - 1, + sc->sc_clkfreq, sc->sc_clktick, sc->sc_period, period); +#endif + /* + * If the period changed, that invalidates the current CMP + * registers (duty values), just zero them out. + */ + am335x_ehrpwm_cfg_duty(sc, 0, 0); + am335x_ehrpwm_cfg_duty(sc, 1, 0); + } + + return (true); +} static void am335x_ehrpwm_freq(struct am335x_ehrpwm_softc *sc) @@ -323,6 +473,82 @@ am335x_ehrpwm_sysctl_period(SYSCTL_HANDLER_ARGS) return (error); } +static int +am335x_ehrpwm_channel_count(device_t dev, u_int *nchannel) +{ + + *nchannel = NUM_CHANNELS; + + return (0); +} + +static int +am335x_ehrpwm_channel_config(device_t dev, u_int channel, u_int period, u_int duty) +{ + struct am335x_ehrpwm_softc *sc; + bool status; + + if (channel >= NUM_CHANNELS) + return (EINVAL); + + sc = device_get_softc(dev); + + PWM_LOCK(sc); + status = am335x_ehrpwm_cfg_period(sc, period); + if (status) + am335x_ehrpwm_cfg_duty(sc, channel, duty); + PWM_UNLOCK(sc); + + return (status ? 0 : EINVAL); +} + +static int +am335x_ehrpwm_channel_get_config(device_t dev, u_int channel, + u_int *period, u_int *duty) +{ + struct am335x_ehrpwm_softc *sc; + + if (channel >= NUM_CHANNELS) + return (EINVAL); + + sc = device_get_softc(dev); + *period = sc->sc_period; + *duty = sc->sc_channels[channel].duty; + return (0); +} + +static int +am335x_ehrpwm_channel_enable(device_t dev, u_int channel, bool enable) +{ + struct am335x_ehrpwm_softc *sc; + + if (channel >= NUM_CHANNELS) + return (EINVAL); + + sc = device_get_softc(dev); + + PWM_LOCK(sc); + am335x_ehrpwm_cfg_enable(sc, channel, enable); + PWM_UNLOCK(sc); + + return (0); +} + +static int +am335x_ehrpwm_channel_is_enabled(device_t dev, u_int channel, bool *enabled) +{ + struct am335x_ehrpwm_softc *sc; + + if (channel >= NUM_CHANNELS) + return (EINVAL); + + sc = device_get_softc(dev); + + *enabled = sc->sc_channels[channel].enabled; + + return (0); +} + static int am335x_ehrpwm_probe(device_t dev) { @@ -407,7 +633,13 @@ am335x_ehrpwm_attach(device_t dev) EPWM_WRITE2(sc, EPWM_TZCTL, 0xf); reg = EPWM_READ2(sc, EPWM_TZFLG); - return (0); + if ((sc->sc_busdev = device_add_child(dev, "pwmbus", -1)) == NULL) { + device_printf(dev, "Cannot add child pwmbus\n"); + // This driver can still do things even without the bus child. + } + + bus_generic_probe(dev); + return (bus_generic_attach(dev)); fail: PWM_LOCK_DESTROY(sc); if (sc->sc_mem_res) @@ -421,13 +653,22 @@ static int am335x_ehrpwm_detach(device_t dev) { struct am335x_ehrpwm_softc *sc; + int error; sc = device_get_softc(dev); + if ((error = bus_generic_detach(sc->sc_dev)) != 0) + return (error); + PWM_LOCK(sc); + + if (sc->sc_busdev != NULL) + device_delete_child(dev, sc->sc_busdev); + if (sc->sc_mem_res) bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mem_rid, sc->sc_mem_res); + PWM_UNLOCK(sc); PWM_LOCK_DESTROY(sc); @@ -435,11 +676,32 @@ am335x_ehrpwm_detach(device_t dev) return (0); } +static phandle_t +am335x_ehrpwm_get_node(device_t bus, device_t dev) +{ + + /* + * Share our controller node with our pwmbus child; it instantiates + * devices by walking the children contained within our node. + */ + return ofw_bus_get_node(bus); +} + static device_method_t am335x_ehrpwm_methods[] = { DEVMETHOD(device_probe, am335x_ehrpwm_probe), DEVMETHOD(device_attach, am335x_ehrpwm_attach), DEVMETHOD(device_detach, am335x_ehrpwm_detach), + /* ofw_bus_if */ + DEVMETHOD(ofw_bus_get_node, am335x_ehrpwm_get_node), + + /* pwm interface */ + DEVMETHOD(pwmbus_channel_count, am335x_ehrpwm_channel_count), + DEVMETHOD(pwmbus_channel_config, am335x_ehrpwm_channel_config), + DEVMETHOD(pwmbus_channel_get_config, am335x_ehrpwm_channel_get_config), + DEVMETHOD(pwmbus_channel_enable, am335x_ehrpwm_channel_enable), + DEVMETHOD(pwmbus_channel_is_enabled, am335x_ehrpwm_channel_is_enabled), + DEVMETHOD_END }; @@ -454,3 +716,4 @@ static devclass_t am335x_ehrpwm_devclass; DRIVER_MODULE(am335x_ehrpwm, am335x_pwmss, am335x_ehrpwm_driver, am335x_ehrpwm_devclass, 0, 0); MODULE_VERSION(am335x_ehrpwm, 1); MODULE_DEPEND(am335x_ehrpwm, am335x_pwmss, 1, 1, 1); +MODULE_DEPEND(am335x_ehrpwm, pwmbus, 1, 1, 1); From 7202a380991a7dfaeff259c6d6fb4a005205e41d Mon Sep 17 00:00:00 2001 From: Ian Lepore Date: Fri, 21 Jun 2019 14:46:43 +0000 Subject: [PATCH 024/165] Catch up with recent changes in pwmbus(9). The pwm(9) and pwmbus(9) interfaces were unified into pwmbus(9), and the PWMBUS_CHANNEL_MAX method was renamed PWMBUS_CHANNEL_COUNT. The pwmbus_attach_bus() function just went away completely. Also, fix a few typos such as s/is/if/. --- share/man/man9/Makefile | 2 +- share/man/man9/pwm.9 | 93 ----------------------------------------- share/man/man9/pwmbus.9 | 31 ++++++-------- 3 files changed, 14 insertions(+), 112 deletions(-) delete mode 100644 share/man/man9/pwm.9 diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile index 682eb2a39502..a4fb56b891b9 100644 --- a/share/man/man9/Makefile +++ b/share/man/man9/Makefile @@ -270,7 +270,6 @@ MAN= accept_filter.9 \ proc_rwmem.9 \ pseudofs.9 \ psignal.9 \ - pwm.9 \ pwmbus.9 \ random.9 \ random_harvest.9 \ @@ -1670,6 +1669,7 @@ MLINKS+=proc_rwmem.9 proc_readmem.9 \ MLINKS+=psignal.9 gsignal.9 \ psignal.9 pgsignal.9 \ psignal.9 tdsignal.9 +MLINKS+=pwmbus.9 pwm.9 MLINKS+=random.9 arc4rand.9 \ random.9 arc4random.9 \ random.9 is_random_seeded.9 \ diff --git a/share/man/man9/pwm.9 b/share/man/man9/pwm.9 deleted file mode 100644 index f7564a4eeca3..000000000000 --- a/share/man/man9/pwm.9 +++ /dev/null @@ -1,93 +0,0 @@ -.\" Copyright (c) 2018 Emmanuel Vadot -.\" -.\" 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 DEVELOPERS ``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 DEVELOPERS 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 January 12, 2019 -.Dt PWM 9 -.Os -.Sh NAME -.Nm pwm , -.Nm PWM_GET_BUS , -.Nm PWM_CHANNEL_CONFIG , -.Nm PWM_CHANNEL_GET_CONFIG , -.Nm PWM_CHANNEL_SET_FLAGS , -.Nm PWM_CHANNEL_GET_FLAGS , -.Nm PWM_CHANNEL_ENABLE , -.Nm PWM_CHANNEL_IS_ENABLED , -.Nm PWM_CHANNEL_MAX -.Nd PWM methods -.Sh SYNOPSIS -.Cd "device pwm" -.In "pwm_if.h" -.Ft device_t -.Fn PWM_GET_BUS "device_t dev" -.Ft int -.Fn PWM_CHANNEL_CONFIG "device_t dev" "int channel" "uint64_t period" "uint64_t duty" -.Ft int -.Fn PWM_CHANNEL_GET_CONFIG "device_t dev" "int channel" "uint64_t *period" "uint64_t *duty" -.Ft int -.Fn PWM_CHANNEL_SET_FLAGS "device_t dev" "int channel" "uint32_t flags" -.Ft int -.Fn PWM_CHANNEL_GET_FLAGS "device_t dev" "int channel" "uint32_t *flags" -.Ft int -.Fn PWM_CHANNEL_ENABLE "device_t dev" "int channel" "bool enable" -.Ft int -.Fn PWM_CHANNEL_IS_ENABLED "device_t dev" "int channel" "bool *enabled" -.Ft int -.Fn PWM_CHANNEL_MAX "device_t dev" "int channel" "int *nchannel" -.Sh DESCRIPTION -The PWM (Pulse-Width Modulation) interface allows the device driver to register to a global -bus so other devices in the kernel can use them in a generic way. -.Sh INTERFACE -.Bl -tag -width indent -.It Fn PWM_GET_BUS "device_t dev" -Return the bus device. -.It Fn PWM_CHANNEL_CONFIG "device_t dev" "int channel" "uint64_t period" "uint64_t duty" -Configure the period and duty (in nanoseconds) in the PWM controller for the specified channel. -Returns 0 on success or -.Er EINVAL -if the values are not supported by the controller or -.Er EBUSY -is the PWM controller is in use and does not support changing the value on the fly. -.It Fn PWM_CHANNEL_GET_CONFIG "device_t dev" "int channel" "uint64_t *period" "uint64_t *duty" -Get the current configuration of the period and duty for the specified channel. -.It Fn PWM_CHANNEL_SET_FLAGS "device_t dev" "int channel" "uint32_t flags" -Set the flags of the channel (like inverted polarity). -.It Fn PWM_CHANNEL_GET_FLAGS "device_t dev" "int channel" "uint32_t *flags" -Get the current flags for the channel. -.It Fn PWM_CHANNEL_ENABLE "device_t dev" "int channel" "bool enable" -Enable the PWM channel. -.It Fn PWM_CHANNEL_ISENABLED "device_t dev" "int channel" "bool *enable" -Test if the PWM channel is enabled. -.It Fn PWM_CHANNEL_MAX "device_t dev" "int channel" "int *nchannel" -Get the maximum number of channels supported by the controller. -.El -.Sh HISTORY -The -.Nm pwm -interface first appeared in -.Fx 13.0 . -The -.Nm pwm -interface and manual page was written by -.An Emmanuel Vadot Aq Mt manu@FreeBSD.org . diff --git a/share/man/man9/pwmbus.9 b/share/man/man9/pwmbus.9 index ba987eaf77a5..74397afb1042 100644 --- a/share/man/man9/pwmbus.9 +++ b/share/man/man9/pwmbus.9 @@ -22,12 +22,11 @@ .\" .\" $FreeBSD$ .\" -.Dd November 12, 2018 +.Dd June 21, 2019 .Dt PWMBUS 9 .Os .Sh NAME .Nm pwmbus , -.Nm pwmbus_attach_bus , .Nm PWMBUS_GET_BUS , .Nm PWMBUS_CHANNEL_CONFIG , .Nm PWMBUS_CHANNEL_GET_CONFIG , @@ -40,8 +39,6 @@ .Sh SYNOPSIS .Cd "device pwm" .In "pwmbus_if.h" -.Ft device_t -.Fn pwmbus_attach_bus "device_t dev" .Ft int .Fn PWMBUS_CHANNEL_CONFIG "device_t bus" "int channel" "uint64_t period" "uint64_t duty" .Ft int @@ -55,37 +52,35 @@ .Ft int .Fn PWMBUS_CHANNEL_IS_ENABLED "device_t bus" "int channel" "bool *enabled" .Ft int -.Fn PWMBUS_CHANNEL_MAX "device_t bus" "int channel" "int *nchannel" +.Fn PWMBUS_CHANNEL_COUNT "device_t bus" "int channel" "int *nchannel" .Sh DESCRIPTION The PWMBUS (Pulse-Width Modulation) interface allows the device driver to register to a global -bus so other devices in the kernel can use them in a generic way +bus so other devices in the kernel can use them in a generic way. .Sh INTERFACE .Bl -tag -width indent -.It Fn pwmbus_attach_bus "device_t dev" -Attach the -.Nm pwmbus -to the device driver .It Fn PWMBUS_CHANNEL_CONFIG "device_t bus" "int channel" "uint64_t period" "uint64_t duty" Configure the period and duty (in nanoseconds) in the PWM controller on the bus for the specified channel. Returns 0 on success or .Er EINVAL -is the values are not supported by the controller or +if the values are not supported by the controller or .Er EBUSY -is the PWMBUS controller is in use and doesn't support changing the value on the fly. +if the PWMBUS controller is in use and doesn't support changing the value on the fly. .It Fn PWMBUS_CHANNEL_GET_CONFIG "device_t bus" "int channel" "uint64_t *period" "uint64_t *duty" Get the current configuration of the period and duty for the specified channel. .It Fn PWMBUS_CHANNEL_SET_FLAGS "device_t bus" "int channel" "uint32_t flags" -Set the flags of the channel (like inverted polarity), if the driver or controller -doesn't support this a default method is used. +Set the flags of the channel (such as inverted polarity), if the driver or controller +doesn't support this a do-nothing default method is used. .It Fn PWMBUS_CHANNEL_GET_FLAGS "device_t bus" "int channel" "uint32_t *flags" -Get the current flags for the channel, if the driver or controller -doesn't support this, a default method is used. +Get the current flags for the channel. +If the driver or controller +doesn't support this, a default method returns a flags value of zero. .It Fn PWMBUS_CHANNEL_ENABLE "device_t bus" "int channel" "bool enable" Enable the PWM channel. .It Fn PWMBUS_CHANNEL_ISENABLED "device_t bus" "int channel" "bool *enable" Test if the PWM channel is enabled. -.It PWMBUS_CHANNEL_MAX "device_t bus" "int channel" "int *nchannel" -Get the maximum number of channel supported by the controller. +.It PWMBUS_CHANNEL_COUNT "device_t bus" "int channel" "int *nchannel" +Get the number of channels supported by the controller. +Channel numbers count up from zero. .El .Sh HISTORY The From 1d90bbbb24e689f92b20aa576596e590e0cafb49 Mon Sep 17 00:00:00 2001 From: Ian Lepore Date: Fri, 21 Jun 2019 15:12:17 +0000 Subject: [PATCH 025/165] Do some general cleanup and light wordsmithing. Sort methods alphabetically. Wrap long lines. Start sentences on a new line. Remove contractions (not because it's a good idea, just to silence igor). Add some explanation of the units for the period and duty arguments and the convention for channel numbers. --- share/man/man9/pwmbus.9 | 72 ++++++++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 26 deletions(-) diff --git a/share/man/man9/pwmbus.9 b/share/man/man9/pwmbus.9 index 74397afb1042..5b0915c10812 100644 --- a/share/man/man9/pwmbus.9 +++ b/share/man/man9/pwmbus.9 @@ -27,14 +27,14 @@ .Os .Sh NAME .Nm pwmbus , -.Nm PWMBUS_GET_BUS , .Nm PWMBUS_CHANNEL_CONFIG , -.Nm PWMBUS_CHANNEL_GET_CONFIG , -.Nm PWMBUS_CHANNEL_SET_FLAGS , -.Nm PWMBUS_CHANNEL_GET_FLAGS , +.Nm PWMBUS_CHANNEL_COUNT , .Nm PWMBUS_CHANNEL_ENABLE , +.Nm PWMBUS_CHANNEL_GET_CONFIG , +.Nm PWMBUS_CHANNEL_GET_FLAGS , .Nm PWMBUS_CHANNEL_IS_ENABLED , -.Nm PWMBUS_CHANNEL_MAX +.Nm PWMBUS_CHANNEL_SET_FLAGS , +.Nm PWMBUS_GET_BUS .Nd PWMBUS methods .Sh SYNOPSIS .Cd "device pwm" @@ -42,45 +42,65 @@ .Ft int .Fn PWMBUS_CHANNEL_CONFIG "device_t bus" "int channel" "uint64_t period" "uint64_t duty" .Ft int -.Fn PWMBUS_CHANNEL_GET_CONFIG "device_t bus" "int channel" "uint64_t *period" "uint64_t *duty" -.Ft int -.Fn PWMBUS_CHANNEL_SET_FLAGS "device_t bus" "int channel" "uint32_t flags" -.Ft int -.Fn PWMBUS_CHANNEL_GET_FLAGS "device_t bus" "int channel" "uint32_t *flags" +.Fn PWMBUS_CHANNEL_COUNT "device_t bus" "int channel" "int *nchannel" .Ft int .Fn PWMBUS_CHANNEL_ENABLE "device_t bus" "int channel" "bool enable" .Ft int +.Fn PWMBUS_CHANNEL_GET_CONFIG "device_t bus" "int channel" "uint64_t *period" "uint64_t *duty" +.Ft int +.Fn PWMBUS_CHANNEL_GET_FLAGS "device_t bus" "int channel" "uint32_t *flags" +.Ft int .Fn PWMBUS_CHANNEL_IS_ENABLED "device_t bus" "int channel" "bool *enabled" .Ft int -.Fn PWMBUS_CHANNEL_COUNT "device_t bus" "int channel" "int *nchannel" +.Fn PWMBUS_CHANNEL_SET_FLAGS "device_t bus" "int channel" "uint32_t flags" .Sh DESCRIPTION -The PWMBUS (Pulse-Width Modulation) interface allows the device driver to register to a global -bus so other devices in the kernel can use them in a generic way. +The PWMBUS (Pulse-Width Modulation) interface allows a device driver to +register to a global bus so other devices in the kernel can use them in a +generic way. +.Pp +For all +.Nm +methods, the +.Va period +argument is the duration in nanoseconds of one complete on-off cycle, and the +.Va duty +argument is the duration in nanoseconds of the on portion of that cycle. +.Pp +Some PWM hardware is organized as a single controller with multiple channels. +Channel numbers count up from zero. +When multiple channels are present, they sometimes share a common clock or +other resources. +In such cases, changing the period or duty cycle of any one channel may affect +other channels within the hardware which share the same resources. +Consult the documentation for the underlying PWM hardware device driver for +details on channels that share resources. .Sh INTERFACE .Bl -tag -width indent .It Fn PWMBUS_CHANNEL_CONFIG "device_t bus" "int channel" "uint64_t period" "uint64_t duty" -Configure the period and duty (in nanoseconds) in the PWM controller on the bus for the specified channel. +Configure the period and duty (in nanoseconds) in the PWM controller on the bus +for the specified channel. Returns 0 on success or .Er EINVAL if the values are not supported by the controller or .Er EBUSY -if the PWMBUS controller is in use and doesn't support changing the value on the fly. +if the PWMBUS controller is in use and does not support changing the value on +the fly. +.It Fn PWMBUS_CHANNEL_COUNT "device_t bus" "int *nchannel" +Get the number of channels supported by the controller. +.It Fn PWMBUS_CHANNEL_ENABLE "device_t bus" "int channel" "bool enable" +Enable the PWM channel. .It Fn PWMBUS_CHANNEL_GET_CONFIG "device_t bus" "int channel" "uint64_t *period" "uint64_t *duty" Get the current configuration of the period and duty for the specified channel. -.It Fn PWMBUS_CHANNEL_SET_FLAGS "device_t bus" "int channel" "uint32_t flags" -Set the flags of the channel (such as inverted polarity), if the driver or controller -doesn't support this a do-nothing default method is used. .It Fn PWMBUS_CHANNEL_GET_FLAGS "device_t bus" "int channel" "uint32_t *flags" Get the current flags for the channel. If the driver or controller -doesn't support this, a default method returns a flags value of zero. -.It Fn PWMBUS_CHANNEL_ENABLE "device_t bus" "int channel" "bool enable" -Enable the PWM channel. -.It Fn PWMBUS_CHANNEL_ISENABLED "device_t bus" "int channel" "bool *enable" -Test if the PWM channel is enabled. -.It PWMBUS_CHANNEL_COUNT "device_t bus" "int channel" "int *nchannel" -Get the number of channels supported by the controller. -Channel numbers count up from zero. +does not support this, a default method returns a flags value of zero. +.It Fn PWMBUS_CHANNEL_IS_ENABLED "device_t bus" "int channel" "bool *enable" +Test whether the PWM channel is enabled. +.It Fn PWMBUS_CHANNEL_SET_FLAGS "device_t bus" "int channel" "uint32_t flags" +Set the flags of the channel (such as inverted polarity). +If the driver or controller does not support this a do-nothing default method +is used. .El .Sh HISTORY The From 83b319101ff242dd9b21946a66bcf6b54d408cf3 Mon Sep 17 00:00:00 2001 From: Ian Lepore Date: Fri, 21 Jun 2019 15:44:58 +0000 Subject: [PATCH 026/165] Add pwm to the armv7 GENERIC kernel, it's now used by TI and Allwinner. --- sys/arm/conf/GENERIC | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sys/arm/conf/GENERIC b/sys/arm/conf/GENERIC index 8b998a15aa1e..34be5898c7eb 100644 --- a/sys/arm/conf/GENERIC +++ b/sys/arm/conf/GENERIC @@ -174,6 +174,9 @@ device ti_spi # ADC support device ti_adc +# PWM +device pwm + # Watchdog support # If we don't enable the watchdog driver, the BealeBone could potentially # reboot automatically because the boot loader might have enabled the From 62260f68b48b6bc3b6398c5c35b10696def93dba Mon Sep 17 00:00:00 2001 From: Johannes Lundberg Date: Fri, 21 Jun 2019 16:43:16 +0000 Subject: [PATCH 027/165] LinuxKPI: Add atomic_long_sub macro. Reviewed by: imp (mentor), hps Approved by: imp (mentor), hps MFC after: 1 week Differential Revision: D20718 --- sys/compat/linuxkpi/common/include/asm/atomic-long.h | 1 + 1 file changed, 1 insertion(+) diff --git a/sys/compat/linuxkpi/common/include/asm/atomic-long.h b/sys/compat/linuxkpi/common/include/asm/atomic-long.h index d7f839f2541f..108d7f4f7b3a 100644 --- a/sys/compat/linuxkpi/common/include/asm/atomic-long.h +++ b/sys/compat/linuxkpi/common/include/asm/atomic-long.h @@ -42,6 +42,7 @@ typedef struct { } atomic_long_t; #define atomic_long_add(i, v) atomic_long_add_return((i), (v)) +#define atomic_long_sub(i, v) atomic_long_add_return(-(i), (v)) #define atomic_long_inc_return(v) atomic_long_add_return(1, (v)) #define atomic_long_inc_not_zero(v) atomic_long_add_unless((v), 1, 0) From 6425fed7e6de354910b09cdacef42a677dd65c1b Mon Sep 17 00:00:00 2001 From: Johannes Lundberg Date: Fri, 21 Jun 2019 18:48:07 +0000 Subject: [PATCH 028/165] LinuxKPI: Additions to rcu list. - Add rcu list functions. - Make rcu hlist's foreach macro use rcu calls instead of the non-rcu macro. - Bump FreeBSD version so we have a checkpoint for the vboxvideo drm driver. Reviewed by: hps Approved by: imp (mentor), hps MFC after: 1 week Differential Revision: D20719 --- .../linuxkpi/common/include/linux/rculist.h | 27 +++++++++++++++++-- sys/sys/param.h | 2 +- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/sys/compat/linuxkpi/common/include/linux/rculist.h b/sys/compat/linuxkpi/common/include/linux/rculist.h index e4823de7a3bf..0a4ad499c380 100644 --- a/sys/compat/linuxkpi/common/include/linux/rculist.h +++ b/sys/compat/linuxkpi/common/include/linux/rculist.h @@ -33,6 +33,25 @@ #include #include +#define list_entry_rcu(ptr, type, member) \ + container_of(READ_ONCE(ptr), type, member) + +#define list_next_rcu(head) (*((struct list_head **)(&(head)->next))) + +#define list_for_each_entry_rcu(pos, head, member) \ + for (pos = list_entry_rcu((head)->next, typeof(*(pos)), member); \ + &(pos)->member != (head); \ + pos = list_entry_rcu((pos)->member.next, typeof(*(pos)), member)) + +static inline void +list_add_rcu(struct list_head *new, struct list_head *prev) +{ + new->next = prev->next; + new->prev = prev; + rcu_assign_pointer(list_next_rcu(prev), new); + prev->prev = new; +} + #define hlist_first_rcu(head) (*((struct hlist_node **)(&(head)->first))) #define hlist_next_rcu(node) (*((struct hlist_node **)(&(node)->next))) #define hlist_pprev_rcu(node) (*((struct hlist_node **)((node)->pprev))) @@ -47,8 +66,12 @@ hlist_add_behind_rcu(struct hlist_node *n, struct hlist_node *prev) n->next->pprev = &n->next; } -#define hlist_for_each_entry_rcu(pos, head, member) \ - hlist_for_each_entry(pos, head, member) +#define hlist_for_each_entry_rcu(pos, head, member) \ + for (pos = hlist_entry_safe (rcu_dereference_raw(hlist_first_rcu(head)),\ + typeof(*(pos)), member); \ + (pos); \ + pos = hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu( \ + &(pos)->member)), typeof(*(pos)), member)) static inline void hlist_del_rcu(struct hlist_node *n) diff --git a/sys/sys/param.h b/sys/sys/param.h index 2534537558c5..8cc1907dc2dd 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -60,7 +60,7 @@ * in the range 5 to 9. */ #undef __FreeBSD_version -#define __FreeBSD_version 1300032 /* Master, propagated to newvers */ +#define __FreeBSD_version 1300033 /* Master, propagated to newvers */ /* * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD, From db2114b4b885d490c84416af27ec50add8a354fd Mon Sep 17 00:00:00 2001 From: Eric van Gyzen Date: Fri, 21 Jun 2019 18:57:33 +0000 Subject: [PATCH 029/165] bhyve: Fix vtscsi maximum segment config The seg_max value reported to the guest should be two less than the host's maximum, in order to leave room for the request and the response. This is analogous to r347033 for virtio_block. We hit the "too many segments to enqueue" assertion on OneFS because we increase MAXPHYS to 256 KB. Reviewed by: bryanv Discussed with: cem jhb rgrimes MFC after: 1 week Sponsored by: Dell EMC Isilon Differential Revision: https://reviews.freebsd.org/D20529 --- usr.sbin/bhyve/pci_virtio_scsi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/usr.sbin/bhyve/pci_virtio_scsi.c b/usr.sbin/bhyve/pci_virtio_scsi.c index 283dd83b6e08..9d9fa822e01d 100644 --- a/usr.sbin/bhyve/pci_virtio_scsi.c +++ b/usr.sbin/bhyve/pci_virtio_scsi.c @@ -309,7 +309,8 @@ pci_vtscsi_reset(void *vsc) /* initialize config structure */ sc->vss_config = (struct pci_vtscsi_config){ .num_queues = VTSCSI_REQUESTQ, - .seg_max = VTSCSI_MAXSEG, + /* Leave room for the request and the response. */ + .seg_max = VTSCSI_MAXSEG - 2, .max_sectors = 2, .cmd_per_lun = 1, .event_info_size = sizeof(struct pci_vtscsi_event), From 1bb957296b3677de64b46de7832136b6bb5a2654 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Fri, 21 Jun 2019 21:50:14 +0000 Subject: [PATCH 030/165] Reduce namespace pollution from r349233 Define __daddr_t in _types.h and use it in filio.h Reported by: ian, bde Reviewed by: ian, imp, cem MFC after: 2 weeks MFC-With: 349233 Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D20715 --- sys/sys/_types.h | 1 + sys/sys/filio.h | 12 ++++++------ sys/sys/types.h | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/sys/sys/_types.h b/sys/sys/_types.h index 22a37c53389a..020ba025ea98 100644 --- a/sys/sys/_types.h +++ b/sys/sys/_types.h @@ -68,6 +68,7 @@ typedef unsigned int __useconds_t; /* microseconds (unsigned) */ typedef int __cpuwhich_t; /* which parameter for cpuset. */ typedef int __cpulevel_t; /* level parameter for cpuset. */ typedef int __cpusetid_t; /* cpuset identifier. */ +typedef __int64_t __daddr_t; /* bwrite(3), FIOBMAP2, etc */ /* * Unusual type definitions. diff --git a/sys/sys/filio.h b/sys/sys/filio.h index e85db9cff4d1..c5cf3d4432e9 100644 --- a/sys/sys/filio.h +++ b/sys/sys/filio.h @@ -40,7 +40,7 @@ #ifndef _SYS_FILIO_H_ #define _SYS_FILIO_H_ -#include +#include #include /* Generic file-descriptor ioctl's. */ @@ -64,12 +64,12 @@ struct fiodgname_arg { #define FIOSEEKDATA _IOWR('f', 97, off_t) /* SEEK_DATA */ #define FIOSEEKHOLE _IOWR('f', 98, off_t) /* SEEK_HOLE */ struct fiobmap2_arg { - int64_t bn; - int runp; - int runb; + __daddr_t bn; + int runp; + int runb; }; -/* Get the file's bmap info for the logical block bn */ -#define FIOBMAP2 _IOWR('f', 99, struct fiobmap2_arg) +/* Get the file's bmap info for the logical block bn. */ +#define FIOBMAP2 _IOWR('f', 99, struct fiobmap2_arg) #ifdef _KERNEL #ifdef COMPAT_FREEBSD32 diff --git a/sys/sys/types.h b/sys/sys/types.h index 39d8d63262e8..c3ece22e58b8 100644 --- a/sys/sys/types.h +++ b/sys/sys/types.h @@ -101,7 +101,7 @@ typedef __clockid_t clockid_t; #endif typedef __critical_t critical_t; /* Critical section value */ -typedef __int64_t daddr_t; /* disk address */ +typedef __daddr_t daddr_t; /* disk address */ #ifndef _DEV_T_DECLARED typedef __dev_t dev_t; /* device number or struct cdev */ From 7318fcb51df11b4b0020513a6945b0897d01c103 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Fri, 21 Jun 2019 23:29:16 +0000 Subject: [PATCH 031/165] Fix individual_element_index when some type has 0 elements. When some type has 0 elements, saved_individual_element_index was set to -1 on second type bump, since individual_element_index was not restored after the first. To me it looks easier just to increment saved_individual_element_index separately than think when to save it. MFC after: 2 weeks --- sys/cam/scsi/scsi_enc_ses.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/sys/cam/scsi/scsi_enc_ses.c b/sys/cam/scsi/scsi_enc_ses.c index 5e9d2dc94d2d..f34fe3de6aaf 100644 --- a/sys/cam/scsi/scsi_enc_ses.c +++ b/sys/cam/scsi/scsi_enc_ses.c @@ -444,6 +444,7 @@ ses_iter_next(struct ses_iterator *iter) iter->type_element_index = ITERATOR_INDEX_END; iter->global_element_index = ITERATOR_INDEX_END; iter->individual_element_index = ITERATOR_INDEX_END; + iter->saved_individual_element_index = ITERATOR_INDEX_END; return (NULL); } @@ -468,17 +469,12 @@ ses_iter_next(struct ses_iterator *iter) */ iter->type_index++; iter->type_element_index = 0; - iter->saved_individual_element_index - = iter->individual_element_index; iter->individual_element_index = ITERATOR_INDEX_INVALID; } if (iter->type_element_index > 0) { - if (iter->type_element_index == 1) { - iter->individual_element_index - = iter->saved_individual_element_index; - } - iter->individual_element_index++; + iter->individual_element_index = + ++iter->saved_individual_element_index; } return (&iter->cache->elm_map[iter->global_element_index]); From 0feb46b0c60c47c9b818142f49d028dfdf8e0545 Mon Sep 17 00:00:00 2001 From: Scott Long Date: Fri, 21 Jun 2019 23:40:26 +0000 Subject: [PATCH 032/165] Refactor xpt_getattr() to make it more readable. No outwardly visible functional changes, though code flow was modified a bit internally to lessen the need for goto jumps and chained if conditionals. --- sys/cam/cam_xpt.c | 84 +++++++++++++++++++++++++++-------------------- 1 file changed, 49 insertions(+), 35 deletions(-) diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c index 95553316bca8..4736c7212a2c 100644 --- a/sys/cam/cam_xpt.c +++ b/sys/cam/cam_xpt.c @@ -1244,6 +1244,7 @@ xpt_getattr(char *buf, size_t len, const char *attr, struct cam_path *path) { int ret = -1, l, o; struct ccb_dev_advinfo cdai; + struct scsi_vpd_device_id *did; struct scsi_vpd_id_descriptor *idd; xpt_path_assert(path, MA_OWNED); @@ -1276,31 +1277,36 @@ xpt_getattr(char *buf, size_t len, const char *attr, struct cam_path *path) cam_release_devq(cdai.ccb_h.path, 0, 0, 0, FALSE); if (cdai.provsiz == 0) goto out; - if (cdai.buftype == CDAI_TYPE_SCSI_DEVID) { + switch(cdai.buftype) { + case CDAI_TYPE_SCSI_DEVID: + did = (struct scsi_vpd_device_id *)cdai.buf; if (strcmp(attr, "GEOM::lunid") == 0) { - idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, - cdai.provsiz, scsi_devid_is_lun_naa); + idd = scsi_get_devid(did, cdai.provsiz, + scsi_devid_is_lun_naa); if (idd == NULL) - idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, - cdai.provsiz, scsi_devid_is_lun_eui64); + idd = scsi_get_devid(did, cdai.provsiz, + scsi_devid_is_lun_eui64); if (idd == NULL) - idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, - cdai.provsiz, scsi_devid_is_lun_uuid); + idd = scsi_get_devid(did, cdai.provsiz, + scsi_devid_is_lun_uuid); if (idd == NULL) - idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, - cdai.provsiz, scsi_devid_is_lun_md5); + idd = scsi_get_devid(did, cdai.provsiz, + scsi_devid_is_lun_md5); } else idd = NULL; + if (idd == NULL) - idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, - cdai.provsiz, scsi_devid_is_lun_t10); + idd = scsi_get_devid(did, cdai.provsiz, + scsi_devid_is_lun_t10); if (idd == NULL) - idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, - cdai.provsiz, scsi_devid_is_lun_name); + idd = scsi_get_devid(did, cdai.provsiz, + scsi_devid_is_lun_name); if (idd == NULL) - goto out; + break; + ret = 0; - if ((idd->proto_codeset & SVPD_ID_CODESET_MASK) == SVPD_ID_CODESET_ASCII) { + if ((idd->proto_codeset & SVPD_ID_CODESET_MASK) == + SVPD_ID_CODESET_ASCII) { if (idd->length < len) { for (l = 0; l < idd->length; l++) buf[l] = idd->identifier[l] ? @@ -1308,38 +1314,46 @@ xpt_getattr(char *buf, size_t len, const char *attr, struct cam_path *path) buf[l] = 0; } else ret = EFAULT; - } else if ((idd->proto_codeset & SVPD_ID_CODESET_MASK) == SVPD_ID_CODESET_UTF8) { + break; + } + if ((idd->proto_codeset & SVPD_ID_CODESET_MASK) == + SVPD_ID_CODESET_UTF8) { l = strnlen(idd->identifier, idd->length); if (l < len) { bcopy(idd->identifier, buf, l); buf[l] = 0; } else ret = EFAULT; - } else if ((idd->id_type & SVPD_ID_TYPE_MASK) == SVPD_ID_TYPE_UUID - && idd->identifier[0] == 0x10) { - if ((idd->length - 2) * 2 + 4 < len) { - for (l = 2, o = 0; l < idd->length; l++) { - if (l == 6 || l == 8 || l == 10 || l == 12) - o += sprintf(buf + o, "-"); - o += sprintf(buf + o, "%02x", - idd->identifier[l]); - } - } else - ret = EFAULT; - } else { - if (idd->length * 2 < len) { - for (l = 0; l < idd->length; l++) - sprintf(buf + l * 2, "%02x", - idd->identifier[l]); - } else - ret = EFAULT; + break; } - } else { + if ((idd->id_type & SVPD_ID_TYPE_MASK) == + SVPD_ID_TYPE_UUID && idd->identifier[0] == 0x10) { + if ((idd->length - 2) * 2 + 4 >= len) { + ret = EFAULT; + break; + } + for (l = 2, o = 0; l < idd->length; l++) { + if (l == 6 || l == 8 || l == 10 || l == 12) + o += sprintf(buf + o, "-"); + o += sprintf(buf + o, "%02x", + idd->identifier[l]); + } + break; + } + if (idd->length * 2 < len) { + for (l = 0; l < idd->length; l++) + sprintf(buf + l * 2, "%02x", + idd->identifier[l]); + } else + ret = EFAULT; + break; + default: if (cdai.provsiz < len) { cdai.buf[cdai.provsiz] = 0; ret = 0; } else ret = EFAULT; + break; } out: From 6805c9b74d80b043f733f07e744298ae565967cd Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Sat, 22 Jun 2019 01:06:41 +0000 Subject: [PATCH 033/165] Make ELEMENT INDEX validation more strict. SES specifications tell: "The Additional Element Status descriptors shall be in the same order as the status elements in the Enclosure Status diagnostic page". It allows us to question ELEMENT INDEX that is lower then values we already processed. There are many SAS2 enclosures with this kind of problem. While there, add more specific error messages for cases when ELEMENT INDEX is obviously wrong. Also skip elements with INVALID bit set. MFC after: 2 weeks --- sys/cam/scsi/scsi_enc_ses.c | 64 +++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 16 deletions(-) diff --git a/sys/cam/scsi/scsi_enc_ses.c b/sys/cam/scsi/scsi_enc_ses.c index f34fe3de6aaf..b3c3466fe056 100644 --- a/sys/cam/scsi/scsi_enc_ses.c +++ b/sys/cam/scsi/scsi_enc_ses.c @@ -1681,7 +1681,6 @@ ses_process_elm_addlstatus(enc_softc_t *enc, struct enc_fsm_state *state, struct ses_iterator iter, titer; int eip; int err; - int ignore_index = 0; int length; int offset; enc_cache_t *enc_cache; @@ -1752,7 +1751,7 @@ ses_process_elm_addlstatus(enc_softc_t *enc, struct enc_fsm_state *state, elm_hdr = (struct ses_elm_addlstatus_base_hdr *)&buf[offset]; eip = ses_elm_addlstatus_eip(elm_hdr); - if (eip && !ignore_index) { + if (eip) { struct ses_elm_addlstatus_eip_hdr *eip_hdr; int expected_index, index; ses_elem_index_type_t index_type; @@ -1765,17 +1764,44 @@ ses_process_elm_addlstatus(enc_softc_t *enc, struct enc_fsm_state *state, index_type = SES_ELEM_INDEX_INDIVIDUAL; expected_index = iter.individual_element_index; } + if (eip_hdr->element_index < expected_index) { + ENC_VLOG(enc, "%s: provided %selement index " + "%d is lower then expected %d\n", + __func__, (eip_hdr->byte2 & + SES_ADDL_EIP_EIIOE) ? "global " : "", + eip_hdr->element_index, expected_index); + goto badindex; + } titer = iter; telement = ses_iter_seek_to(&titer, eip_hdr->element_index, index_type); - if (telement != NULL && - (ses_typehasaddlstatus(enc, titer.type_index) != - TYPE_ADDLSTATUS_NONE || - titer.type_index > ELMTYP_SAS_CONN)) { + if (telement == NULL) { + ENC_VLOG(enc, "%s: provided %selement index " + "%d does not exist\n", __func__, + (eip_hdr->byte2 & SES_ADDL_EIP_EIIOE) ? + "global " : "", eip_hdr->element_index); + goto badindex; + } + if (ses_typehasaddlstatus(enc, titer.type_index) == + TYPE_ADDLSTATUS_NONE) { + ENC_VLOG(enc, "%s: provided %selement index " + "%d can't have additional status\n", + __func__, + (eip_hdr->byte2 & SES_ADDL_EIP_EIIOE) ? + "global " : "", eip_hdr->element_index); +badindex: + /* + * If we expected mandatory element, we may + * guess it was just a wrong index and we may + * use the status. If element was optional, + * then we have no idea where status belongs. + */ + if (status_type == TYPE_ADDLSTATUS_OPTIONAL) + break; + } else { iter = titer; element = telement; - } else - ignore_index = 1; + } if (eip_hdr->byte2 & SES_ADDL_EIP_EIIOE) index = iter.global_element_index; @@ -1797,35 +1823,41 @@ ses_process_elm_addlstatus(enc_softc_t *enc, struct enc_fsm_state *state, "type element index=%d, offset=0x%x, " "byte0=0x%x, length=0x%x\n", __func__, iter.global_element_index, iter.type_index, - iter.type_element_index, offset, elmpriv->addl.hdr->byte0, - elmpriv->addl.hdr->length); + iter.type_element_index, offset, elm_hdr->byte0, + elm_hdr->length); /* Skip to after the length field */ offset += sizeof(struct ses_elm_addlstatus_base_hdr); /* Make sure the descriptor is within bounds */ - if ((offset + elmpriv->addl.hdr->length) > length) { + if ((offset + elm_hdr->length) > length) { ENC_VLOG(enc, "Element %d Beyond End " "of Additional Element Status Descriptors\n", iter.global_element_index); break; } + /* Skip elements marked as invalid. */ + if (ses_elm_addlstatus_invalid(elm_hdr)) { + offset += elm_hdr->length; + continue; + } + /* Advance to the protocol data, skipping eip bytes if needed */ offset += (eip * SES_EIP_HDR_EXTRA_LEN); - proto_info_len = elmpriv->addl.hdr->length + proto_info_len = elm_hdr->length - (eip * SES_EIP_HDR_EXTRA_LEN); /* Errors in this block are ignored as they are non-fatal */ - switch(ses_elm_addlstatus_proto(elmpriv->addl.hdr)) { + switch(ses_elm_addlstatus_proto(elm_hdr)) { case SPSP_PROTO_FC: - if (elmpriv->addl.hdr->length == 0) + if (elm_hdr->length == 0) break; ses_get_elm_addlstatus_fc(enc, enc_cache, &buf[offset], proto_info_len); break; case SPSP_PROTO_SAS: - if (elmpriv->addl.hdr->length <= 2) + if (elm_hdr->length <= 2) break; ses_get_elm_addlstatus_sas(enc, enc_cache, &buf[offset], @@ -1836,7 +1868,7 @@ ses_process_elm_addlstatus(enc_softc_t *enc, struct enc_fsm_state *state, default: ENC_VLOG(enc, "Element %d: Unknown Additional Element " "Protocol 0x%x\n", iter.global_element_index, - ses_elm_addlstatus_proto(elmpriv->addl.hdr)); + ses_elm_addlstatus_proto(elm_hdr)); break; } From df8406543fab98a6706bb41f3093863b93d92b91 Mon Sep 17 00:00:00 2001 From: Eric van Gyzen Date: Sat, 22 Jun 2019 01:20:45 +0000 Subject: [PATCH 034/165] VirtIO SCSI: validate seg_max on attach Until r349278, bhyve presented a seg_max to the guest that was too large. Detect this case and clamp it to the virtqueue size. Otherwise, we would fail the "too many segments to enqueue" assertion in virtqueue_enqueue(). I hit this by running a guest with a MAXPHYS of 256 KB. Reviewed by: bryanv cem MFC after: 1 week Sponsored by: Dell EMC Isilon Differential Revision: https://reviews.freebsd.org/D20703 --- sys/dev/virtio/scsi/virtio_scsi.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/sys/dev/virtio/scsi/virtio_scsi.c b/sys/dev/virtio/scsi/virtio_scsi.c index ec98178d5697..6f2dfbcac5a4 100644 --- a/sys/dev/virtio/scsi/virtio_scsi.c +++ b/sys/dev/virtio/scsi/virtio_scsi.c @@ -81,6 +81,7 @@ static void vtscsi_read_config(struct vtscsi_softc *, struct virtio_scsi_config *); static int vtscsi_maximum_segments(struct vtscsi_softc *, int); static int vtscsi_alloc_virtqueues(struct vtscsi_softc *); +static void vtscsi_check_sizes(struct vtscsi_softc *); static void vtscsi_write_device_config(struct vtscsi_softc *); static int vtscsi_reinit(struct vtscsi_softc *); @@ -311,6 +312,8 @@ vtscsi_attach(device_t dev) goto fail; } + vtscsi_check_sizes(sc); + error = vtscsi_init_event_vq(sc); if (error) { device_printf(dev, "cannot populate the eventvq\n"); @@ -477,6 +480,26 @@ vtscsi_alloc_virtqueues(struct vtscsi_softc *sc) return (virtio_alloc_virtqueues(dev, 0, nvqs, vq_info)); } +static void +vtscsi_check_sizes(struct vtscsi_softc *sc) +{ + int rqsize; + + if ((sc->vtscsi_flags & VTSCSI_FLAG_INDIRECT) == 0) { + /* + * Ensure the assertions in virtqueue_enqueue(), + * even if the hypervisor reports a bad seg_max. + */ + rqsize = virtqueue_size(sc->vtscsi_request_vq); + if (sc->vtscsi_max_nsegs > rqsize) { + device_printf(sc->vtscsi_dev, + "clamping seg_max (%d %d)\n", sc->vtscsi_max_nsegs, + rqsize); + sc->vtscsi_max_nsegs = rqsize; + } + } +} + static void vtscsi_write_device_config(struct vtscsi_softc *sc) { From a616b25342fe1ceaa2bb7c68d9791f6586656fed Mon Sep 17 00:00:00 2001 From: Doug Moore Date: Sat, 22 Jun 2019 03:16:01 +0000 Subject: [PATCH 035/165] Modify swapon(8) to invoke BIO_DELETE to trim swap devices, either if '-E' appears on the swapon command line, or if "trimonce" appears as an fstab option. Discussed at: BSDCAN Tested by: markj Reviewed by: markj Approved by: markj (mentor) Differential Revision:https://reviews.freebsd.org/D20599 --- sbin/swapon/swapon.8 | 9 +++++-- sbin/swapon/swapon.c | 59 ++++++++++++++++++++++++++++++++++++++---- share/man/man5/fstab.5 | 6 +++++ 3 files changed, 67 insertions(+), 7 deletions(-) diff --git a/sbin/swapon/swapon.8 b/sbin/swapon/swapon.8 index 058f681ce5ce..f69dd484a93b 100644 --- a/sbin/swapon/swapon.8 +++ b/sbin/swapon/swapon.8 @@ -28,7 +28,7 @@ .\" @(#)swapon.8 8.1 (Berkeley) 6/5/93 .\" $FreeBSD$ .\" -.Dd October 21, 2016 +.Dd June 21, 2019 .Dt SWAPON 8 .Os .Sh NAME @@ -38,7 +38,7 @@ .Nm swapon .Oo Fl F Ar fstab .Oc -.Fl aLq | Ar +.Fl aLq | E Ar .Nm swapoff .Oo Fl F Ar fstab .Oc @@ -86,6 +86,11 @@ If the option is used, informational messages will not be written to standard output when a swap device is added. +The +.Fl E +option causes each of following devices to receive a +.Dv BIO_DELETE +command to mark all blocks as unused. .Pp The .Nm swapoff diff --git a/sbin/swapon/swapon.c b/sbin/swapon/swapon.c index 83201535b4ab..c8904ade5a8f 100644 --- a/sbin/swapon/swapon.c +++ b/sbin/swapon/swapon.c @@ -43,6 +43,7 @@ static char sccsid[] = "@(#)swapon.c 8.1 (Berkeley) 6/5/93"; #include __FBSDID("$FreeBSD$"); +#include #include #include #include @@ -77,7 +78,7 @@ static int run_cmd(int *, const char *, ...) __printflike(2, 3); static enum { SWAPON, SWAPOFF, SWAPCTL } orig_prog, which_prog = SWAPCTL; -static int qflag; +static int Eflag, qflag; int main(int argc, char **argv) @@ -100,7 +101,7 @@ main(int argc, char **argv) doall = 0; etc_fstab = NULL; - while ((ch = getopt(argc, argv, "AadghklLmqsUF:")) != -1) { + while ((ch = getopt(argc, argv, "AadEghklLmqsUF:")) != -1) { switch(ch) { case 'A': if (which_prog == SWAPCTL) { @@ -121,6 +122,12 @@ main(int argc, char **argv) else usage(); break; + case 'E': + if (which_prog == SWAPON) + Eflag = 2; + else + usage(); + break; case 'g': hflag = 'G'; break; @@ -182,8 +189,10 @@ main(int argc, char **argv) strstr(fsp->fs_mntops, "late") == NULL && late != 0) continue; + Eflag |= (strstr(fsp->fs_mntops, "trimonce") != NULL); swfile = swap_on_off(fsp->fs_spec, 1, fsp->fs_mntops); + Eflag &= ~1; if (swfile == NULL) { ret = 1; continue; @@ -378,12 +387,22 @@ swap_on_geli_args(const char *mntops) return (NULL); } } else if (strcmp(token, "notrim") == 0) { + if (Eflag) { + warn("Options \"notrim\" and " + "\"trimonce\" conflict"); + free(ops); + return (NULL); + } Tflag = " -T "; } else if (strcmp(token, "late") == 0) { /* ignore known option */ } else if (strcmp(token, "noauto") == 0) { /* ignore known option */ - } else if (strcmp(token, "sw") != 0) { + } else if (strcmp(token, "sw") == 0) { + /* ignore known option */ + } else if (strcmp(token, "trimonce") == 0) { + /* ignore known option */ + } else { warnx("Invalid option: %s", token); free(ops); return (NULL); @@ -721,14 +740,42 @@ run_cmd(int *ofd, const char *cmdline, ...) return (WEXITSTATUS(status)); } +static void +swap_trim(const char *name) +{ + struct stat sb; + off_t ioarg[2], sz; + int fd; + + fd = open(name, O_WRONLY); + if (fd < 0) + errx(1, "Cannot open %s", name); + if (fstat(fd, &sb) < 0) + errx(1, "Cannot stat %s", name); + if (S_ISREG(sb.st_mode)) + sz = sb.st_size; + else if (S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode)) { + if (ioctl(fd, DIOCGMEDIASIZE, &sz) != 0) + err(1, "ioctl(DIOCGMEDIASIZE)"); + } else + errx(1, "%s has an invalid file type", name); + ioarg[0] = 0; + ioarg[1] = sz; + if (ioctl(fd, DIOCGDELETE, ioarg) != 0) + warn("ioctl(DIOCGDELETE)"); + close(fd); +} + static const char * swap_on_off_sfile(const char *name, int doingall) { int error; - if (which_prog == SWAPON) + if (which_prog == SWAPON) { + if (Eflag) + swap_trim(name); error = swapon(name); - else /* SWAPOFF */ + } else /* SWAPOFF */ error = swapoff(name); if (error == -1) { @@ -759,6 +806,8 @@ usage(void) fprintf(stderr, "usage: %s ", getprogname()); switch(orig_prog) { case SWAPON: + fprintf(stderr, "[-F fstab] -aLq | [-E] file ...\n"); + break; case SWAPOFF: fprintf(stderr, "[-F fstab] -aLq | file ...\n"); break; diff --git a/share/man/man5/fstab.5 b/share/man/man5/fstab.5 index 062ab601851f..f4e9ce2b653e 100644 --- a/share/man/man5/fstab.5 +++ b/share/man/man5/fstab.5 @@ -216,6 +216,12 @@ then the special file is made available as a piece of swap space by the .Xr swapon 8 command at the end of the system reboot procedure. +For swap devices, the keyword +.Dq trimonce +triggers the delivery of a +.Dv BIO_DELETE +command to the device to mark +all blocks as unused. For vnode-backed swap spaces, .Dq file is supported in the From b8038d7827edfaf0d89d13ce5f4718ed0c7db423 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Sat, 22 Jun 2019 03:50:43 +0000 Subject: [PATCH 036/165] Remove ancient SCSI-2/3 mentioning. MFC after: 2 weeks --- sys/cam/scsi/scsi_enc.c | 20 +++++--------------- sys/cam/scsi/scsi_enc_internal.h | 2 -- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/sys/cam/scsi/scsi_enc.c b/sys/cam/scsi/scsi_enc.c index 363f27db5f78..97339206beee 100644 --- a/sys/cam/scsi/scsi_enc.c +++ b/sys/cam/scsi/scsi_enc.c @@ -684,14 +684,8 @@ enc_type(struct ccb_getdev *cgd) buflen = min(sizeof(cgd->inq_data), SID_ADDITIONAL_LENGTH(&cgd->inq_data)); - if ((iqd[0] & 0x1f) == T_ENCLOSURE) { - if ((iqd[2] & 0x7) > 2) { - return (ENC_SES); - } else { - return (ENC_SES_SCSI2); - } - return (ENC_NONE); - } + if ((iqd[0] & 0x1f) == T_ENCLOSURE) + return (ENC_SES); #ifdef SES_ENABLE_PASSTHROUGH if ((iqd[6] & 0x40) && (iqd[2] & 0x7) >= 2) { @@ -928,7 +922,6 @@ enc_ctor(struct cam_periph *periph, void *arg) switch (enc->enc_type) { case ENC_SES: - case ENC_SES_SCSI2: case ENC_SES_PASSTHROUGH: case ENC_SEMB_SES: err = ses_softc_init(enc); @@ -1017,17 +1010,14 @@ enc_ctor(struct cam_periph *periph, void *arg) case ENC_NONE: tname = "No ENC device"; break; - case ENC_SES_SCSI2: - tname = "SCSI-2 ENC Device"; - break; case ENC_SES: - tname = "SCSI-3 ENC Device"; + tname = "SES Device"; break; case ENC_SES_PASSTHROUGH: - tname = "ENC Passthrough Device"; + tname = "SES Passthrough Device"; break; case ENC_SAFT: - tname = "SAF-TE Compliant Device"; + tname = "SAF-TE Device"; break; case ENC_SEMB_SES: tname = "SEMB SES Device"; diff --git a/sys/cam/scsi/scsi_enc_internal.h b/sys/cam/scsi/scsi_enc_internal.h index 0d4bdffda4f9..04948ad7361e 100644 --- a/sys/cam/scsi/scsi_enc_internal.h +++ b/sys/cam/scsi/scsi_enc_internal.h @@ -55,10 +55,8 @@ typedef struct enc_element { typedef enum { ENC_NONE, - ENC_SES_SCSI2, ENC_SES, ENC_SES_PASSTHROUGH, - ENC_SEN, ENC_SAFT, ENC_SEMB_SES, ENC_SEMB_SAFT From a6d2a24c3efa1c3e749fb32e3be14cdd0c809290 Mon Sep 17 00:00:00 2001 From: Ryan Libby Date: Sat, 22 Jun 2019 05:35:23 +0000 Subject: [PATCH 037/165] ddb show proc typo --- sys/ddb/db_ps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/ddb/db_ps.c b/sys/ddb/db_ps.c index 72bf0edd9161..82e50e0ca85d 100644 --- a/sys/ddb/db_ps.c +++ b/sys/ddb/db_ps.c @@ -481,7 +481,7 @@ DB_SHOW_COMMAND(proc, db_show_proc) dump_args(p); db_printf("\n"); } - db_printf(" repear: %p reapsubtree: %d\n", + db_printf(" reaper: %p reapsubtree: %d\n", p->p_reaper, p->p_reapsubtree); db_printf(" sigparent: %d\n", p->p_sigparent); db_printf(" vmspace: %p\n", p->p_vmspace); From 6ab631e856301442f8c1b1049f1676e8c5d87a34 Mon Sep 17 00:00:00 2001 From: Devin Teske Date: Sat, 22 Jun 2019 15:39:34 +0000 Subject: [PATCH 038/165] `libjail/jail.c' includes both and Latter is undesired when including according to style(9) Submitted by: Faraz Vahedi Reviewed by: cem Differential Revision: https://reviews.freebsd.org/D20637 --- lib/libjail/jail.c | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/libjail/jail.c b/lib/libjail/jail.c index ad05f5273f2c..6a35cdc6dde5 100644 --- a/lib/libjail/jail.c +++ b/lib/libjail/jail.c @@ -30,7 +30,6 @@ __FBSDID("$FreeBSD$"); #include -#include #include #include #include From 36c5a4cb3f8e9395447f6e7e9dd30d681e3d0a02 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sat, 22 Jun 2019 16:26:38 +0000 Subject: [PATCH 039/165] Introduce pmap_remove_l3_range() and use it in two places: (1) pmap_remove(), where it eliminates redundant TLB invalidations by pmap_remove() and pmap_remove_l3(), and (2) pmap_enter_l2(), where it may optimize the TLB invalidations by batching them. Reviewed by: markj MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D12725 --- sys/arm64/arm64/pmap.c | 116 +++++++++++++++++++++++++++++------------ 1 file changed, 83 insertions(+), 33 deletions(-) diff --git a/sys/arm64/arm64/pmap.c b/sys/arm64/arm64/pmap.c index df34873025dd..8afee14fbdd1 100644 --- a/sys/arm64/arm64/pmap.c +++ b/sys/arm64/arm64/pmap.c @@ -2509,6 +2509,82 @@ pmap_remove_l3(pmap_t pmap, pt_entry_t *l3, vm_offset_t va, return (pmap_unuse_pt(pmap, va, l2e, free)); } +/* + * Remove the specified range of addresses from the L3 page table that is + * identified by the given L2 entry. + */ +static void +pmap_remove_l3_range(pmap_t pmap, pd_entry_t l2e, vm_offset_t sva, + vm_offset_t eva, struct spglist *free, struct rwlock **lockp) +{ + struct md_page *pvh; + struct rwlock *new_lock; + pt_entry_t *l3, old_l3; + vm_offset_t va; + vm_page_t m; + + PMAP_LOCK_ASSERT(pmap, MA_OWNED); + KASSERT(rounddown2(sva, L2_SIZE) + L2_SIZE == roundup2(eva, L2_SIZE), + ("pmap_remove_l3_range: range crosses an L3 page table boundary")); + va = eva; + for (l3 = pmap_l2_to_l3(&l2e, sva); sva != eva; l3++, sva += L3_SIZE) { + if (!pmap_l3_valid(pmap_load(l3))) { + if (va != eva) { + pmap_invalidate_range(pmap, va, sva); + va = eva; + } + continue; + } + old_l3 = pmap_load_clear(l3); + if ((old_l3 & ATTR_SW_WIRED) != 0) + pmap->pm_stats.wired_count--; + pmap_resident_count_dec(pmap, 1); + if ((old_l3 & ATTR_SW_MANAGED) != 0) { + m = PHYS_TO_VM_PAGE(old_l3 & ~ATTR_MASK); + if (pmap_page_dirty(old_l3)) + vm_page_dirty(m); + if ((old_l3 & ATTR_AF) != 0) + vm_page_aflag_set(m, PGA_REFERENCED); + new_lock = PHYS_TO_PV_LIST_LOCK(VM_PAGE_TO_PHYS(m)); + if (new_lock != *lockp) { + if (*lockp != NULL) { + /* + * Pending TLB invalidations must be + * performed before the PV list lock is + * released. Otherwise, a concurrent + * pmap_remove_all() on a physical page + * could return while a stale TLB entry + * still provides access to that page. + */ + if (va != eva) { + pmap_invalidate_range(pmap, va, + sva); + va = eva; + } + rw_wunlock(*lockp); + } + *lockp = new_lock; + rw_wlock(*lockp); + } + pmap_pvh_free(&m->md, pmap, sva); + if (TAILQ_EMPTY(&m->md.pv_list) && + (m->flags & PG_FICTITIOUS) == 0) { + pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); + if (TAILQ_EMPTY(&pvh->pv_list)) + vm_page_aflag_clear(m, PGA_WRITEABLE); + } + } + if (va == eva) + va = sva; + if (pmap_unuse_pt(pmap, sva, l2e, free)) { + sva += L3_SIZE; + break; + } + } + if (va != eva) + pmap_invalidate_range(pmap, va, sva); +} + /* * Remove the given range of addresses from the specified map. * @@ -2519,9 +2595,9 @@ void pmap_remove(pmap_t pmap, vm_offset_t sva, vm_offset_t eva) { struct rwlock *lock; - vm_offset_t va, va_next; + vm_offset_t va_next; pd_entry_t *l0, *l1, *l2; - pt_entry_t l3_paddr, *l3; + pt_entry_t l3_paddr; struct spglist free; /* @@ -2594,28 +2670,8 @@ pmap_remove(pmap_t pmap, vm_offset_t sva, vm_offset_t eva) if (va_next > eva) va_next = eva; - va = va_next; - for (l3 = pmap_l2_to_l3(l2, sva); sva != va_next; l3++, - sva += L3_SIZE) { - if (l3 == NULL) - panic("l3 == NULL"); - if (pmap_load(l3) == 0) { - if (va != va_next) { - pmap_invalidate_range(pmap, va, sva); - va = va_next; - } - continue; - } - if (va == va_next) - va = sva; - if (pmap_remove_l3(pmap, l3, sva, l3_paddr, &free, - &lock)) { - sva += L3_SIZE; - break; - } - } - if (va != va_next) - pmap_invalidate_range(pmap, va, sva); + pmap_remove_l3_range(pmap, l3_paddr, sva, va_next, &free, + &lock); } if (lock != NULL) rw_wunlock(lock); @@ -3419,8 +3475,7 @@ pmap_enter_l2(pmap_t pmap, vm_offset_t va, pd_entry_t new_l2, u_int flags, vm_page_t m, struct rwlock **lockp) { struct spglist free; - pd_entry_t *l2, *l3, old_l2; - vm_offset_t sva; + pd_entry_t *l2, old_l2; vm_page_t l2pg, mt; PMAP_LOCK_ASSERT(pmap, MA_OWNED); @@ -3449,13 +3504,8 @@ pmap_enter_l2(pmap_t pmap, vm_offset_t va, pd_entry_t new_l2, u_int flags, (void)pmap_remove_l2(pmap, l2, va, pmap_load(pmap_l1(pmap, va)), &free, lockp); else - for (sva = va; sva < va + L2_SIZE; sva += PAGE_SIZE) { - l3 = pmap_l2_to_l3(l2, sva); - if (pmap_l3_valid(pmap_load(l3)) && - pmap_remove_l3(pmap, l3, sva, old_l2, &free, - lockp) != 0) - break; - } + pmap_remove_l3_range(pmap, old_l2, va, va + L2_SIZE, + &free, lockp); vm_page_free_pages_toq(&free, true); if (va >= VM_MAXUSER_ADDRESS) { /* From 05b626019a9e55653ad5e161f0d3a3da28442f67 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Sat, 22 Jun 2019 16:54:23 +0000 Subject: [PATCH 040/165] Add list of valid CPUTYPE flags for arm/arm64 to make.conf example Summary: Adds a list of valid CPUTYPE flags for arm and arm64 architectures List taken from share/mk/bsd.cpu.mk Submitted by: Daniel Engberg Reviewed By: imp Differential Revision: https://reviews.freebsd.org/D20315 --- share/examples/etc/make.conf | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/share/examples/etc/make.conf b/share/examples/etc/make.conf index 8a9fa90ac12a..f9463c334631 100644 --- a/share/examples/etc/make.conf +++ b/share/examples/etc/make.conf @@ -49,6 +49,12 @@ # icelake-client, cannonlake, knm, skylake-avx512, knl, # goldmont, skylake, broadwell, haswell, ivybridge, # sandybridge, westmere, nehalem, silvermont, bonnell +# ARM architecture: armv5, armv5te, armv6, armv6t2, arm1176jzf-s, armv7, +# armv7-a, armv7ve, generic-armv7-a, cortex-a5, +# cortex-a7, cortex-a8, cortex-a9, cortex-a12, +# cortex-a15, cortex-a17 +# ARM64 architechture: cortex-a53, cortex-a57, cortex-a72, +# exynos-m1 # # (?= allows to buildworld for a different CPUTYPE.) # From 6d4d657360451aa495a82edd7cc28af69ea35168 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Sat, 22 Jun 2019 19:09:10 +0000 Subject: [PATCH 041/165] Decouple enc/ses verbosity from bootverbose. I don't want to be regularly notified that my enclosure violates standards until there is some real problem I want to debug. MFC after: 2 weeks --- sys/cam/scsi/scsi_enc.c | 8 ++++++++ sys/cam/scsi/scsi_enc_internal.h | 7 ++++++- sys/cam/scsi/scsi_enc_safte.c | 1 - 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/sys/cam/scsi/scsi_enc.c b/sys/cam/scsi/scsi_enc.c index 97339206beee..e6688af2a786 100644 --- a/sys/cam/scsi/scsi_enc.c +++ b/sys/cam/scsi/scsi_enc.c @@ -81,6 +81,14 @@ static enctyp enc_type(struct ccb_getdev *); SYSCTL_NODE(_kern_cam, OID_AUTO, enc, CTLFLAG_RD, 0, "CAM Enclosure Services driver"); +#if defined(DEBUG) || defined(ENC_DEBUG) +int enc_verbose = 1; +#else +int enc_verbose = 0; +#endif +SYSCTL_INT(_kern_cam_enc, OID_AUTO, verbose, CTLFLAG_RWTUN, + &enc_verbose, 0, "Enable verbose logging"); + static struct periph_driver encdriver = { enc_init, "ses", TAILQ_HEAD_INITIALIZER(encdriver.units), /* generation */ 0 diff --git a/sys/cam/scsi/scsi_enc_internal.h b/sys/cam/scsi/scsi_enc_internal.h index 04948ad7361e..29fd880ec3ae 100644 --- a/sys/cam/scsi/scsi_enc_internal.h +++ b/sys/cam/scsi/scsi_enc_internal.h @@ -36,6 +36,8 @@ #ifndef __SCSI_ENC_INTERNAL_H__ #define __SCSI_ENC_INTERNAL_H__ +#include + typedef struct enc_element { uint32_t enctype : 8, /* enclosure type */ @@ -204,6 +206,9 @@ enc_softc_init_t ses_softc_init; /* SAF-TE interface */ enc_softc_init_t safte_softc_init; +SYSCTL_DECL(_kern_cam_enc); +extern int enc_verbose; + /* Helper macros */ MALLOC_DECLARE(M_SCSIENC); #define ENC_CFLAGS CAM_RETRY_SELTO @@ -216,7 +221,7 @@ MALLOC_DECLARE(M_SCSIENC); #else #define ENC_DLOG if (0) enc_log #endif -#define ENC_VLOG if (bootverbose) enc_log +#define ENC_VLOG if (enc_verbose) enc_log #define ENC_MALLOC(amt) malloc(amt, M_SCSIENC, M_NOWAIT) #define ENC_MALLOCZ(amt) malloc(amt, M_SCSIENC, M_ZERO|M_NOWAIT) /* Cast away const avoiding GCC warnings. */ diff --git a/sys/cam/scsi/scsi_enc_safte.c b/sys/cam/scsi/scsi_enc_safte.c index 8afcc323991a..8d6e3fe5eeb4 100644 --- a/sys/cam/scsi/scsi_enc_safte.c +++ b/sys/cam/scsi/scsi_enc_safte.c @@ -227,7 +227,6 @@ static char *safte_2little = "Too Little Data Returned (%d) at line %d\n"; } int emulate_array_devices = 1; -SYSCTL_DECL(_kern_cam_enc); SYSCTL_INT(_kern_cam_enc, OID_AUTO, emulate_array_devices, CTLFLAG_RWTUN, &emulate_array_devices, 0, "Emulate Array Devices for SAF-TE"); From 9035b2257f5f619b8047e4bb86f3c92fbfff8656 Mon Sep 17 00:00:00 2001 From: Doug Moore Date: Sat, 22 Jun 2019 19:27:09 +0000 Subject: [PATCH 042/165] You can't use block special nodes for swap, so don't let that happen. Fix a style violation with regard to header file arrangement. Improved by: alc Approved by: markj, kib (mentor) Differential Revision: https://reviews.freebsd.org/D20723 --- sbin/swapon/swapon.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sbin/swapon/swapon.c b/sbin/swapon/swapon.c index c8904ade5a8f..e6c8b7eb215d 100644 --- a/sbin/swapon/swapon.c +++ b/sbin/swapon/swapon.c @@ -43,9 +43,8 @@ static char sccsid[] = "@(#)swapon.c 8.1 (Berkeley) 6/5/93"; #include __FBSDID("$FreeBSD$"); -#include #include -#include +#include #include #include #include @@ -754,7 +753,7 @@ swap_trim(const char *name) errx(1, "Cannot stat %s", name); if (S_ISREG(sb.st_mode)) sz = sb.st_size; - else if (S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode)) { + else if (S_ISCHR(sb.st_mode)) { if (ioctl(fd, DIOCGMEDIASIZE, &sz) != 0) err(1, "ioctl(DIOCGMEDIASIZE)"); } else From 07fb2bcc245c52923889747f7262073f04383392 Mon Sep 17 00:00:00 2001 From: Sevan Janiyan Date: Sat, 22 Jun 2019 22:34:59 +0000 Subject: [PATCH 043/165] Remove question mark from the link between NetBSD & Darwin. As linked to in bug 26137 as a source https://web.archive.org/web/20001012121507/http://www.opensource.apple.com/projects/darwin/faq.html mentions: "We already synchronize our code periodically with NetBSD for most of our user commands" --- share/misc/bsd-family-tree | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/misc/bsd-family-tree b/share/misc/bsd-family-tree index 81741ca34446..c80f4ee544cf 100644 --- a/share/misc/bsd-family-tree +++ b/share/misc/bsd-family-tree @@ -135,7 +135,7 @@ FreeBSD 4.0 | | | | | NetBSD 1.4.2 | | | FreeBSD 3.5.1 | | | | | | | | | | | | | | | *---FreeBSD 4.1 | | | | | | | - | | | | (?) | | | | + | | | | | | | | | | FreeBSD 4.1.1 | | / | | | | | | | | / | | | | | FreeBSD 4.2 Darwin/ | NetBSD 1.4.3 | | From 31d2b1cf99062a653040112f2a43a5aa6f70d8b0 Mon Sep 17 00:00:00 2001 From: Sevan Janiyan Date: Sat, 22 Jun 2019 22:43:40 +0000 Subject: [PATCH 044/165] Add DragonFly BSD 5.6.1 --- share/misc/bsd-family-tree | 3 +++ 1 file changed, 3 insertions(+) diff --git a/share/misc/bsd-family-tree b/share/misc/bsd-family-tree index c80f4ee544cf..6f386cbc0b08 100644 --- a/share/misc/bsd-family-tree +++ b/share/misc/bsd-family-tree @@ -399,6 +399,8 @@ FreeBSD 5.2 | | | | | | | NetBSD | | | | | 8.1 | DragonFly 5.6 | | | | | + | | | | DragonFly 5.6.1 + | | | | | FreeBSD 13 -current | NetBSD -current OpenBSD -current DragonFly -current | | | | | v v v v v @@ -783,6 +785,7 @@ DragonFly 5.4.1 2018-12-24 [DFB] OpenBSD 6.5 2019-05-01 [OBD] NetBSD 8.1 2019-06-04 [NBD] DragonFly 5.6 2019-06-17 [DFB] +DragonFly 5.6.1 2019-06-19 [DFB] Bibliography ------------------------ From dfdc07bc4307d27650a15bc40786bf89cc6c0279 Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Sun, 23 Jun 2019 10:45:50 +0000 Subject: [PATCH 045/165] Remove redundand 'else' and 'return'. Sponsored by: The FreeBSD Foundation MFC after: 1 week --- lib/libc/gen/libc_dlopen.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/libc/gen/libc_dlopen.c b/lib/libc/gen/libc_dlopen.c index fe28d56f8cb0..5c386b649456 100644 --- a/lib/libc/gen/libc_dlopen.c +++ b/lib/libc/gen/libc_dlopen.c @@ -48,8 +48,8 @@ libc_dlopen(const char *path, int mode) if (__libc_restricted_mode) { _rtld_error("Service unavailable -- libc in restricted mode"); return (NULL); - } else - return (dlopen(path, mode)); + } + return (dlopen(path, mode)); } void @@ -57,6 +57,5 @@ __FreeBSD_libc_enter_restricted_mode(void) { __libc_restricted_mode = 1; - return; } From 0cab2a4a534edb02c9bf21f549fd14bead7efeb7 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Sun, 23 Jun 2019 10:47:07 +0000 Subject: [PATCH 046/165] Fix two WARNS=6 warnings in opendir.c and telldir.c This is in preparation for compiling these files as part of rtld (which is built with WARNS=6). See https://reviews.freebsd.org/D20663 for more details. --- lib/libc/gen/opendir.c | 4 ++-- lib/libc/gen/telldir.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/libc/gen/opendir.c b/lib/libc/gen/opendir.c index f264dd956a4c..98354e028dc4 100644 --- a/lib/libc/gen/opendir.c +++ b/lib/libc/gen/opendir.c @@ -99,8 +99,8 @@ static int opendir_compar(const void *p1, const void *p2) { - return (strcmp((*(const struct dirent **)p1)->d_name, - (*(const struct dirent **)p2)->d_name)); + return (strcmp((*(const struct dirent * const *)p1)->d_name, + (*(const struct dirent * const *)p2)->d_name)); } /* diff --git a/lib/libc/gen/telldir.c b/lib/libc/gen/telldir.c index 12309cf93266..d801345fc24c 100644 --- a/lib/libc/gen/telldir.c +++ b/lib/libc/gen/telldir.c @@ -63,8 +63,8 @@ telldir(DIR *dirp) * 2) Otherwise, see if it's already been recorded in the linked list * 3) Otherwise, malloc a new one */ - if (dirp->dd_seek < (1ul << DD_SEEK_BITS) && - dirp->dd_loc < (1ul << DD_LOC_BITS)) { + if (dirp->dd_seek < (off_t)(1l << DD_SEEK_BITS) && + dirp->dd_loc < (1l << DD_LOC_BITS)) { ddloc.s.is_packed = 1; ddloc.s.loc = dirp->dd_loc; ddloc.s.seek = dirp->dd_seek; From 2d8c3eeb122361d6eef5773cabc71484cac6af13 Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Sun, 23 Jun 2019 10:50:26 +0000 Subject: [PATCH 047/165] Add libc stub for pthread_getthreadid_np(3). Requested by: jbeich PR: 238650 Sponsored by: The FreeBSD Foundation MFC after: 1 week --- lib/libc/gen/Symbol.map | 1 + lib/libc/gen/_pthread_stubs.c | 2 ++ lib/libc/include/libc_private.h | 1 + lib/libthr/thread/thr_init.c | 1 + 4 files changed, 5 insertions(+) diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map index 9c6b969ea8d3..703cfe796a38 100644 --- a/lib/libc/gen/Symbol.map +++ b/lib/libc/gen/Symbol.map @@ -338,6 +338,7 @@ FBSD_1.2 { getutxid; getutxline; getutxuser; + pthread_getthreadid_np; pututxline; sem_close; sem_destroy; diff --git a/lib/libc/gen/_pthread_stubs.c b/lib/libc/gen/_pthread_stubs.c index 89325a39b48a..870cbf2152ee 100644 --- a/lib/libc/gen/_pthread_stubs.c +++ b/lib/libc/gen/_pthread_stubs.c @@ -130,6 +130,7 @@ pthread_func_entry_t __thr_jtable[PJT_MAX] = { {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_MUTEX_CONSISTENT */ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_MUTEXATTR_GETROBUST */ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_MUTEXATTR_SETROBUST */ + {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_GETTHREADID_NP */ }; /* @@ -248,6 +249,7 @@ STUB_FUNC1(pthread_rwlock_trywrlock, PJT_RWLOCK_TRYWRLOCK, int, void *) STUB_FUNC1(pthread_rwlock_unlock, PJT_RWLOCK_UNLOCK, int, void *) STUB_FUNC1(pthread_rwlock_wrlock, PJT_RWLOCK_WRLOCK, int, void *) STUB_FUNC(pthread_self, PJT_SELF, pthread_t) +STUB_FUNC(pthread_getthreadid_np, PJT_GETTHREADID_NP, int) STUB_FUNC2(pthread_setspecific, PJT_SETSPECIFIC, int, pthread_key_t, void *) STUB_FUNC3(pthread_sigmask, PJT_SIGMASK, int, int, void *, void *) STUB_FUNC3(pthread_atfork, PJT_ATFORK, int, void *, void *, void*) diff --git a/lib/libc/include/libc_private.h b/lib/libc/include/libc_private.h index 116764b399b9..529ae6b17c41 100644 --- a/lib/libc/include/libc_private.h +++ b/lib/libc/include/libc_private.h @@ -176,6 +176,7 @@ typedef enum { PJT_MUTEX_CONSISTENT, PJT_MUTEXATTR_GETROBUST, PJT_MUTEXATTR_SETROBUST, + PJT_GETTHREADID_NP, PJT_MAX } pjt_index_t; diff --git a/lib/libthr/thread/thr_init.c b/lib/libthr/thread/thr_init.c index 1568529e8c51..7b043a38b1f2 100644 --- a/lib/libthr/thread/thr_init.c +++ b/lib/libthr/thread/thr_init.c @@ -272,6 +272,7 @@ static pthread_func_t jmp_table[][2] = { {DUAL_ENTRY(_pthread_mutex_consistent)},/* PJT_MUTEX_CONSISTENT */ {DUAL_ENTRY(_pthread_mutexattr_getrobust)},/* PJT_MUTEXATTR_GETROBUST */ {DUAL_ENTRY(_pthread_mutexattr_setrobust)},/* PJT_MUTEXATTR_SETROBUST */ + {DUAL_ENTRY(_pthread_getthreadid_np)}, /* PJT_GETTHREADID_NP */ }; static int init_once = 0; From 5cafc162078264b6078d3f317fb5d877b6115449 Mon Sep 17 00:00:00 2001 From: Ian Lepore Date: Sun, 23 Jun 2019 17:20:39 +0000 Subject: [PATCH 048/165] Remove some unused header files from the ad7418 driver. --- sys/dev/iicbus/ad7418.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/sys/dev/iicbus/ad7418.c b/sys/dev/iicbus/ad7418.c index 457b3626c8ef..034597768790 100644 --- a/sys/dev/iicbus/ad7418.c +++ b/sys/dev/iicbus/ad7418.c @@ -35,18 +35,9 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include -#include #include #include -#include -#include -#include -#include -#include -#include - #include #include "iicbus_if.h" From 48fedd09608e29f6129c0bfe0e63d1e04e805c8d Mon Sep 17 00:00:00 2001 From: Ian Lepore Date: Sun, 23 Jun 2019 17:23:56 +0000 Subject: [PATCH 049/165] Add the rtc8583 driver to conf/files. Also, move sy8106a from file.allwinner to conf/files... it's not allwinner-specific, some day other platforms could use the same regulator chip. --- sys/arm/allwinner/files.allwinner | 1 - sys/conf/files | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/sys/arm/allwinner/files.allwinner b/sys/arm/allwinner/files.allwinner index 73367b391c3a..dd801c016d49 100644 --- a/sys/arm/allwinner/files.allwinner +++ b/sys/arm/allwinner/files.allwinner @@ -28,7 +28,6 @@ dev/usb/controller/generic_ohci.c optional ohci dev/usb/controller/generic_usb_if.m optional ohci arm/allwinner/aw_sid.c optional aw_sid arm/allwinner/aw_thermal.c optional aw_thermal -dev/iicbus/sy8106a.c optional sy8106a arm/allwinner/aw_cir.c optional aw_cir evdev arm/allwinner/aw_reset.c standard diff --git a/sys/conf/files b/sys/conf/files index f84039696da6..0edeec48c37f 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1792,7 +1792,9 @@ dev/iicbus/isl12xx.c optional isl12xx dev/iicbus/lm75.c optional lm75 dev/iicbus/nxprtc.c optional nxprtc | pcf8563 dev/iicbus/ofw_iicbus.c optional fdt iicbus +dev/iicbus/rtc8583.c optional rtc8583 dev/iicbus/s35390a.c optional s35390a +dev/iicbus/sy8106a.c optional sy8106a dev/iir/iir.c optional iir dev/iir/iir_ctrl.c optional iir dev/iir/iir_pci.c optional iir pci From 9026f4b86db9a53e2e1792304a65758056e206c1 Mon Sep 17 00:00:00 2001 From: Ian Lepore Date: Sun, 23 Jun 2019 17:38:30 +0000 Subject: [PATCH 050/165] The sy8106a and syr827 drviers require FDT and the ext_resources subsystem. --- sys/conf/files | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/conf/files b/sys/conf/files index 0edeec48c37f..6f085e7fe7f6 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1775,7 +1775,7 @@ dev/iicbus/ds13rtc.c optional ds13rtc | ds133x | ds1374 dev/iicbus/ds1672.c optional ds1672 dev/iicbus/ds3231.c optional ds3231 dev/iicbus/rtc8583.c optional rtc8583 -dev/iicbus/syr827.c optional ext_resources syr827 +dev/iicbus/syr827.c optional syr827 ext_resources fdt dev/iicbus/icee.c optional icee dev/iicbus/if_ic.c optional ic dev/iicbus/iic.c optional iic @@ -1794,7 +1794,7 @@ dev/iicbus/nxprtc.c optional nxprtc | pcf8563 dev/iicbus/ofw_iicbus.c optional fdt iicbus dev/iicbus/rtc8583.c optional rtc8583 dev/iicbus/s35390a.c optional s35390a -dev/iicbus/sy8106a.c optional sy8106a +dev/iicbus/sy8106a.c optional sy8106a ext_resources fdt dev/iir/iir.c optional iir dev/iir/iir_ctrl.c optional iir dev/iir/iir_pci.c optional iir pci From ac6a9e474f19a6ba15b90b04c9f5f7732d06205d Mon Sep 17 00:00:00 2001 From: Ian Lepore Date: Sun, 23 Jun 2019 17:39:13 +0000 Subject: [PATCH 051/165] Add some i2c slave-device drivers that were missing from NOTES. --- sys/conf/NOTES | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sys/conf/NOTES b/sys/conf/NOTES index 34c1eab825b6..ce7ce9a28ee3 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -2421,14 +2421,19 @@ device iicoc # OpenCores I2C controller support # I2C peripheral devices # +device ad7418 # Analog Devices temp and voltage sensor device ds1307 # Dallas DS1307 RTC and compatible device ds13rtc # All Dallas/Maxim ds13xx chips device ds1672 # Dallas DS1672 RTC device ds3231 # Dallas DS3231 RTC + temperature device icee # AT24Cxxx and compatible EEPROMs +device isl12xx # Intersil ISL12xx RTC device lm75 # LM75 compatible temperature sensor device nxprtc # NXP RTCs: PCA/PFC212x PCA/PCF85xx +device rtc8583 # Epson RTC-8583 device s35390a # Seiko Instruments S-35390A RTC +device sy8106a # Silergy Corp. SY8106A buck regulator +device syr827 # Silergy Corp. DC/DC regulator # Parallel-Port Bus # From 7a29e0bf968602fc2fad59089875a31daa81fd40 Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Sun, 23 Jun 2019 18:35:11 +0000 Subject: [PATCH 052/165] coredump: avoid writing to core files not owned by the real user. Reported by: blake frantz PR: 68905 admbugs: 358 Sponsored by: The FreeBSD Foundation MFC after: 1 week --- sys/kern/kern_sig.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 8dbcb87698bc..f40aad4b3869 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -3597,10 +3597,11 @@ coredump(struct thread *td) /* * Don't dump to non-regular files or files with links. - * Do not dump into system files. + * Do not dump into system files. Real user must own the corefile. */ if (vp->v_type != VREG || VOP_GETATTR(vp, &vattr, cred) != 0 || - vattr.va_nlink != 1 || (vp->v_vflag & VV_SYSTEM) != 0) { + vattr.va_nlink != 1 || (vp->v_vflag & VV_SYSTEM) != 0 || + vattr.va_uid != cred->cr_ruid) { VOP_UNLOCK(vp, 0); error = EFAULT; goto out; From 53f5ac1310ef91ddb6ad09e60172ede57c6b02ef Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Sun, 23 Jun 2019 19:05:01 +0000 Subject: [PATCH 053/165] Improve AHCI Enclosure Management and SES interoperation. Since SES specs do not define mechanism to map enclosure slots to SATA disks, AHCI EM code I written many years ago appeared quite useless, that always bugged me. I was thinking whether it was a good idea, but if LSI HBAs do that, why I shouldn't? This change introduces simple non-standard mechanism for the mapping into both AHCI EM and SES code, that makes AHCI EM on capable controllers (most of Intel's) a first-class SES citizen, allowing it to report disk physical path to GEOM, show devices inserted into each enclosure slot in `sesutil map` and `getencstat`, control locate and fault LEDs for specific devices with `sesutil locate adaX on` and `sesutil fault adaX on`, etc. I've successfully tested this on Supermicro X10DRH-i motherboard connected with sideband cable of its S-SATA Mini-SAS connector to SAS815TQ backplane. It can indicate with LEDs Locate, Fault and Rebuild/Remap SES statuses for each disk identical to real SES of Supermicro SAS2 backplanes. MFC after: 2 weeks --- sys/cam/scsi/scsi_all.c | 4 +- sys/cam/scsi/scsi_enc.c | 21 ++- sys/cam/scsi/scsi_enc.h | 36 ++++- sys/cam/scsi/scsi_enc_internal.h | 16 +-- sys/cam/scsi/scsi_enc_safte.c | 26 ++-- sys/cam/scsi/scsi_enc_ses.c | 222 ++++++++++++++++++++++--------- sys/cam/scsi/scsi_ses.h | 31 ++++- sys/dev/ahci/ahci.c | 48 +++++++ sys/dev/ahci/ahci.h | 8 ++ sys/dev/ahci/ahciem.c | 125 ++++++++++++----- 10 files changed, 400 insertions(+), 137 deletions(-) diff --git a/sys/cam/scsi/scsi_all.c b/sys/cam/scsi/scsi_all.c index 1d92c4d8e915..5ab37e3f6416 100644 --- a/sys/cam/scsi/scsi_all.c +++ b/sys/cam/scsi/scsi_all.c @@ -5574,6 +5574,7 @@ scsi_devid_is_naa_ieee_reg(uint8_t *bufp) { struct scsi_vpd_id_descriptor *descr; struct scsi_vpd_id_naa_basic *naa; + int n; descr = (struct scsi_vpd_id_descriptor *)bufp; naa = (struct scsi_vpd_id_naa_basic *)descr->identifier; @@ -5581,7 +5582,8 @@ scsi_devid_is_naa_ieee_reg(uint8_t *bufp) return 0; if (descr->length < sizeof(struct scsi_vpd_id_naa_ieee_reg)) return 0; - if ((naa->naa >> SVPD_ID_NAA_NAA_SHIFT) != SVPD_ID_NAA_IEEE_REG) + n = naa->naa >> SVPD_ID_NAA_NAA_SHIFT; + if (n != SVPD_ID_NAA_LOCAL_REG && n != SVPD_ID_NAA_IEEE_REG) return 0; return 1; } diff --git a/sys/cam/scsi/scsi_enc.c b/sys/cam/scsi/scsi_enc.c index e6688af2a786..ec190232fff9 100644 --- a/sys/cam/scsi/scsi_enc.c +++ b/sys/cam/scsi/scsi_enc.c @@ -89,6 +89,9 @@ int enc_verbose = 0; SYSCTL_INT(_kern_cam_enc, OID_AUTO, verbose, CTLFLAG_RWTUN, &enc_verbose, 0, "Enable verbose logging"); +const char *elm_type_names[] = ELM_TYPE_NAMES; +CTASSERT(nitems(elm_type_names) - 1 == ELMTYP_LAST); + static struct periph_driver encdriver = { enc_init, "ses", TAILQ_HEAD_INITIALIZER(encdriver.units), /* generation */ 0 @@ -240,11 +243,17 @@ enc_async(void *callback_arg, uint32_t code, struct cam_path *path, void *arg) struct enc_softc *softc; softc = (struct enc_softc *)periph->softc; - if (xpt_path_path_id(periph->path) != path_id - || softc == NULL - || (softc->enc_flags & ENC_FLAG_INITIALIZED) - == 0 - || softc->enc_vec.device_found == NULL) + + /* Check this SEP is ready. */ + if (softc == NULL || (softc->enc_flags & + ENC_FLAG_INITIALIZED) == 0 || + softc->enc_vec.device_found == NULL) + continue; + + /* Check this SEP may manage this device. */ + if (xpt_path_path_id(periph->path) != path_id && + (softc->enc_type != ENC_SEMB_SES || + cgd->protocol != PROTO_ATA)) continue; softc->enc_vec.device_found(softc); @@ -440,7 +449,7 @@ enc_ioctl(struct cdev *dev, u_long cmd, caddr_t arg_addr, int flag, encioc_element_t kelm; kelm.elm_idx = i; kelm.elm_subenc_id = cache->elm_map[i].subenclosure; - kelm.elm_type = cache->elm_map[i].enctype; + kelm.elm_type = cache->elm_map[i].elm_type; error = copyout(&kelm, &uelm[i], sizeof(kelm)); if (error) break; diff --git a/sys/cam/scsi/scsi_enc.h b/sys/cam/scsi/scsi_enc.h index fc7e3bd3f1c6..f9abe099e337 100644 --- a/sys/cam/scsi/scsi_enc.h +++ b/sys/cam/scsi/scsi_enc.h @@ -120,10 +120,42 @@ typedef enum { ELMTYP_SCSI_INI = 0x15, ELMTYP_SUBENC = 0x16, ELMTYP_ARRAY_DEV = 0x17, - ELMTYP_SAS_EXP = 0x18, /* SAS expander */ - ELMTYP_SAS_CONN = 0x19 /* SAS connector */ + ELMTYP_SAS_EXP = 0x18, /* SAS Expander */ + ELMTYP_SAS_CONN = 0x19, /* SAS Connector */ + ELMTYP_LAST = ELMTYP_SAS_CONN } elm_type_t; +#define ELM_TYPE_NAMES { \ + "Unspecified", \ + "Device Slot", \ + "Power Supply", \ + "Cooling", \ + "Temperature Sensors", \ + "Door", \ + "Audible alarm", \ + "Enclosure Services Controller Electronics", \ + "SCC Controller Electronics", \ + "Nonvolatile Cache", \ + "Invalid Operation Reason", \ + "Uninterruptible Power Supply", \ + "Display", \ + "Key Pad Entry", \ + "Enclosure", \ + "SCSI Port/Transceiver", \ + "Language", \ + "Communication Port", \ + "Voltage Sensor", \ + "Current Sensor", \ + "SCSI Target Port", \ + "SCSI Initiator Port", \ + "Simple Subenclosure", \ + "Array Device Slot", \ + "SAS Expander", \ + "SAS Connector" \ +} + +extern const char *elm_type_names[]; + typedef struct encioc_element { /* Element Index */ unsigned int elm_idx; diff --git a/sys/cam/scsi/scsi_enc_internal.h b/sys/cam/scsi/scsi_enc_internal.h index 29fd880ec3ae..293da3ee7386 100644 --- a/sys/cam/scsi/scsi_enc_internal.h +++ b/sys/cam/scsi/scsi_enc_internal.h @@ -39,16 +39,12 @@ #include typedef struct enc_element { - uint32_t - enctype : 8, /* enclosure type */ - subenclosure : 8, /* subenclosure id */ - svalid : 1, /* enclosure information valid */ - overall_status_elem: 1,/* - * This object represents generic - * status about all objects of this - * type. - */ - priv : 14; /* private data, per object */ + uint8_t elm_idx; /* index of element */ + uint8_t elm_type; /* element type */ + uint8_t subenclosure; /* subenclosure id */ + uint8_t type_elm_idx; /* index of element within type */ + uint8_t svalid; /* enclosure information valid */ + uint16_t priv; /* private data, per object */ uint8_t encstat[4]; /* state && stats */ uint8_t *physical_path; /* Device physical path data. */ u_int physical_path_len; /* Length of device path data. */ diff --git a/sys/cam/scsi/scsi_enc_safte.c b/sys/cam/scsi/scsi_enc_safte.c index 8d6e3fe5eeb4..94219cde7a89 100644 --- a/sys/cam/scsi/scsi_enc_safte.c +++ b/sys/cam/scsi/scsi_enc_safte.c @@ -301,21 +301,21 @@ safte_process_config(enc_softc_t *enc, struct enc_fsm_state *state, * in later fetches of status. */ for (i = 0; i < cfg->Nfans; i++) - enc->enc_cache.elm_map[r++].enctype = ELMTYP_FAN; + enc->enc_cache.elm_map[r++].elm_type = ELMTYP_FAN; cfg->pwroff = (uint8_t) r; for (i = 0; i < cfg->Npwr; i++) - enc->enc_cache.elm_map[r++].enctype = ELMTYP_POWER; + enc->enc_cache.elm_map[r++].elm_type = ELMTYP_POWER; for (i = 0; i < cfg->DoorLock; i++) - enc->enc_cache.elm_map[r++].enctype = ELMTYP_DOORLOCK; + enc->enc_cache.elm_map[r++].elm_type = ELMTYP_DOORLOCK; if (cfg->Nspkrs > 0) - enc->enc_cache.elm_map[r++].enctype = ELMTYP_ALARM; + enc->enc_cache.elm_map[r++].elm_type = ELMTYP_ALARM; for (i = 0; i < cfg->Ntherm; i++) - enc->enc_cache.elm_map[r++].enctype = ELMTYP_THERM; + enc->enc_cache.elm_map[r++].elm_type = ELMTYP_THERM; for (i = 0; i <= cfg->Ntstats; i++) - enc->enc_cache.elm_map[r++].enctype = ELMTYP_THERM; + enc->enc_cache.elm_map[r++].elm_type = ELMTYP_THERM; cfg->slotoff = (uint8_t) r; for (i = 0; i < cfg->Nslots; i++) - enc->enc_cache.elm_map[r++].enctype = + enc->enc_cache.elm_map[r++].elm_type = emulate_array_devices ? ELMTYP_ARRAY_DEV : ELMTYP_DEVICE; @@ -505,7 +505,7 @@ safte_process_status(enc_softc_t *enc, struct enc_fsm_state *state, */ for (i = 0; i < cfg->Nslots; i++) { SAFT_BAIL(r, xfer_len); - if (cache->elm_map[cfg->slotoff + i].enctype == ELMTYP_DEVICE) + if (cache->elm_map[cfg->slotoff + i].elm_type == ELMTYP_DEVICE) cache->elm_map[cfg->slotoff + i].encstat[1] = buf[r]; r++; } @@ -678,7 +678,7 @@ safte_process_slotstatus(enc_softc_t *enc, struct enc_fsm_state *state, oid = cfg->slotoff; for (r = i = 0; i < cfg->Nslots; i++, r += 4) { SAFT_BAIL(r+3, xfer_len); - if (cache->elm_map[oid].enctype == ELMTYP_ARRAY_DEV) + if (cache->elm_map[oid].elm_type == ELMTYP_ARRAY_DEV) cache->elm_map[oid].encstat[1] = 0; cache->elm_map[oid].encstat[2] &= SESCTL_RQSID; cache->elm_map[oid].encstat[3] = 0; @@ -705,7 +705,7 @@ safte_process_slotstatus(enc_softc_t *enc, struct enc_fsm_state *state, cache->elm_map[oid].encstat[3] |= SESCTL_RQSFLT; if (buf[r+0] & 0x40) cache->elm_map[oid].encstat[0] |= SESCTL_PRDFAIL; - if (cache->elm_map[oid].enctype == ELMTYP_ARRAY_DEV) { + if (cache->elm_map[oid].elm_type == ELMTYP_ARRAY_DEV) { if (buf[r+0] & 0x01) cache->elm_map[oid].encstat[1] |= 0x80; if (buf[r+0] & 0x04) @@ -771,7 +771,7 @@ safte_fill_control_request(enc_softc_t *enc, struct enc_fsm_state *state, } else { ep = &enc->enc_cache.elm_map[idx]; - switch (ep->enctype) { + switch (ep->elm_type) { case ELMTYP_DEVICE: case ELMTYP_ARRAY_DEV: switch (cfg->current_request_stage) { @@ -781,7 +781,7 @@ safte_fill_control_request(enc_softc_t *enc, struct enc_fsm_state *state, ep->priv |= 0x40; if (req->elm_stat[3] & SESCTL_RQSFLT) ep->priv |= 0x02; - if (ep->enctype == ELMTYP_ARRAY_DEV) { + if (ep->elm_type == ELMTYP_ARRAY_DEV) { if (req->elm_stat[1] & 0x01) ep->priv |= 0x200; if (req->elm_stat[1] & 0x02) @@ -970,7 +970,7 @@ safte_process_control_request(enc_softc_t *enc, struct enc_fsm_state *state, if (idx == SES_SETSTATUS_ENC_IDX) type = -1; else - type = enc->enc_cache.elm_map[idx].enctype; + type = enc->enc_cache.elm_map[idx].elm_type; if (type == ELMTYP_DEVICE || type == ELMTYP_ARRAY_DEV) enc_update_request(enc, SAFTE_UPDATE_READSLOTSTATUS); else diff --git a/sys/cam/scsi/scsi_enc_ses.c b/sys/cam/scsi/scsi_enc_ses.c index b3c3466fe056..e5a18d5d9a45 100644 --- a/sys/cam/scsi/scsi_enc_ses.c +++ b/sys/cam/scsi/scsi_enc_ses.c @@ -102,6 +102,7 @@ typedef struct ses_addl_status { union { union ses_fcobj_hdr *fc; union ses_elm_sas_hdr *sas; + struct ses_elm_ata_hdr *ata; } proto_hdr; union ses_addl_data proto_data; /* array sizes stored in header */ } ses_add_status_t; @@ -825,14 +826,6 @@ ses_devids_iter(enc_softc_t *enc, enc_element_t *elm, elmpriv = elm->elm_private; addl = &(elmpriv->addl); - /* - * Don't assume this object has additional status information, or - * that it is a SAS device, or that it is a device slot device. - */ - if (addl->hdr == NULL || addl->proto_hdr.sas == NULL - || addl->proto_data.sasdev_phys == NULL) - return; - devid_record_size = SVPD_DEVICE_ID_DESC_HDR_LEN + sizeof(struct scsi_vpd_id_naa_ieee_reg); for (i = 0; i < addl->proto_hdr.sas->base_hdr.num_phys; i++) { @@ -950,11 +943,40 @@ static void ses_paths_iter(enc_softc_t *enc, enc_element_t *elm, ses_path_callback_t *callback, void *callback_arg) { - ses_path_iter_args_t args; + ses_element_t *elmpriv; + struct ses_addl_status *addl; - args.callback = callback; - args.callback_arg = callback_arg; - ses_devids_iter(enc, elm, ses_path_iter_devid_callback, &args); + elmpriv = elm->elm_private; + addl = &(elmpriv->addl); + + if (addl->hdr == NULL) + return; + + if (addl->proto_hdr.sas != NULL && + addl->proto_data.sasdev_phys != NULL) { + ses_path_iter_args_t args; + + args.callback = callback; + args.callback_arg = callback_arg; + ses_devids_iter(enc, elm, ses_path_iter_devid_callback, &args); + } else if (addl->proto_hdr.ata != NULL) { + struct cam_path *path; + struct ccb_getdev cgd; + + if (xpt_create_path(&path, /*periph*/NULL, + scsi_4btoul(addl->proto_hdr.ata->bus), + scsi_4btoul(addl->proto_hdr.ata->target), 0) + != CAM_REQ_CMP) + return; + + xpt_setup_ccb(&cgd.ccb_h, path, CAM_PRIORITY_NORMAL); + cgd.ccb_h.func_code = XPT_GDEV_TYPE; + xpt_action((union ccb *)&cgd); + if (cgd.ccb_h.status == CAM_REQ_CMP) + callback(enc, elm, path, callback_arg); + + xpt_free_path(path); + } } /** @@ -1059,6 +1081,10 @@ ses_set_physpath(enc_softc_t *enc, enc_element_t *elm, ret = EIO; devid = NULL; + elmpriv = elm->elm_private; + if (elmpriv->addl.hdr == NULL) + goto out; + /* * Assemble the components of the physical path starting with * the device ID of the enclosure itself. @@ -1091,7 +1117,6 @@ ses_set_physpath(enc_softc_t *enc, enc_element_t *elm, scsi_8btou64(idd->identifier), iter->type_index, iter->type_element_index); /* Append the element descriptor if one exists */ - elmpriv = elm->elm_private; if (elmpriv->descr != NULL && elmpriv->descr_len > 0) { sbuf_cat(&sb, "/elmdesc@"); for (i = 0, c = elmpriv->descr; i < elmpriv->descr_len; @@ -1457,9 +1482,10 @@ ses_process_config(enc_softc_t *enc, struct enc_fsm_state *state, iter.global_element_index, iter.type_index, nelm, iter.type_element_index); thdr = ses_cache->ses_types[iter.type_index].hdr; + element->elm_idx = iter.global_element_index; + element->elm_type = thdr->etype_elm_type; element->subenclosure = thdr->etype_subenc; - element->enctype = thdr->etype_elm_type; - element->overall_status_elem = iter.type_element_index == 0; + element->type_elm_idx = iter.type_element_index; element->elm_private = malloc(sizeof(ses_element_t), M_SCSIENC, M_WAITOK|M_ZERO); ENC_DLOG(enc, "%s: creating elmpriv %d(%d,%d) subenc %d " @@ -1663,6 +1689,8 @@ static int ses_get_elm_addlstatus_fc(enc_softc_t *, enc_cache_t *, uint8_t *, int); static int ses_get_elm_addlstatus_sas(enc_softc_t *, enc_cache_t *, uint8_t *, int, int, int, int); +static int ses_get_elm_addlstatus_ata(enc_softc_t *, enc_cache_t *, uint8_t *, + int, int, int, int); /** * \brief Parse the additional status element data for each object. @@ -1818,7 +1846,6 @@ ses_process_elm_addlstatus(enc_softc_t *enc, struct enc_fsm_state *state, } } elmpriv = element->elm_private; - elmpriv->addl.hdr = elm_hdr; ENC_DLOG(enc, "%s: global element index=%d, type index=%d " "type element index=%d, offset=0x%x, " "byte0=0x%x, length=0x%x\n", __func__, @@ -1842,6 +1869,7 @@ ses_process_elm_addlstatus(enc_softc_t *enc, struct enc_fsm_state *state, offset += elm_hdr->length; continue; } + elmpriv->addl.hdr = elm_hdr; /* Advance to the protocol data, skipping eip bytes if needed */ offset += (eip * SES_EIP_HDR_EXTRA_LEN); @@ -1865,6 +1893,13 @@ ses_process_elm_addlstatus(enc_softc_t *enc, struct enc_fsm_state *state, eip, iter.type_index, iter.global_element_index); break; + case SPSP_PROTO_ATA: + ses_get_elm_addlstatus_ata(enc, enc_cache, + &buf[offset], + proto_info_len, + eip, iter.type_index, + iter.global_element_index); + break; default: ENC_VLOG(enc, "Element %d: Unknown Additional Element " "Protocol 0x%x\n", iter.global_element_index, @@ -2193,18 +2228,16 @@ ses_get_elm_addlstatus_fc(enc_softc_t *enc, enc_cache_t *enc_cache, } #define SES_PRINT_PORTS(p, type) do { \ - sbuf_printf(sbp, " %s(", type); \ - if (((p) & SES_SASOBJ_DEV_PHY_PROTOMASK) == 0) \ - sbuf_printf(sbp, " None"); \ - else { \ + if (((p) & SES_SASOBJ_DEV_PHY_PROTOMASK) != 0) { \ + sbuf_printf(sbp, " %s (", type); \ if ((p) & SES_SASOBJ_DEV_PHY_SMP) \ sbuf_printf(sbp, " SMP"); \ if ((p) & SES_SASOBJ_DEV_PHY_STP) \ sbuf_printf(sbp, " STP"); \ if ((p) & SES_SASOBJ_DEV_PHY_SSP) \ sbuf_printf(sbp, " SSP"); \ + sbuf_printf(sbp, " )"); \ } \ - sbuf_printf(sbp, " )"); \ } while(0) /** @@ -2214,11 +2247,10 @@ ses_get_elm_addlstatus_fc(enc_softc_t *enc, enc_cache_t *enc_cache, * \param sesname SES device name associated with the object. * \param sbp Sbuf to print to. * \param obj The object to print the data for. - * \param periph_name Peripheral string associated with the object. */ static void ses_print_addl_data_sas_type0(char *sesname, struct sbuf *sbp, - enc_element_t *obj, char *periph_name) + enc_element_t *obj) { int i; ses_element_t *elmpriv; @@ -2227,16 +2259,12 @@ ses_print_addl_data_sas_type0(char *sesname, struct sbuf *sbp, elmpriv = obj->elm_private; addl = &(elmpriv->addl); - if (addl->proto_hdr.sas == NULL) - return; - sbuf_printf(sbp, "%s: %s: SAS Device Slot Element:", - sesname, periph_name); - sbuf_printf(sbp, " %d Phys", addl->proto_hdr.sas->base_hdr.num_phys); + sbuf_printf(sbp, ", SAS Slot: %d%s phys", + addl->proto_hdr.sas->base_hdr.num_phys, + ses_elm_sas_type0_not_all_phys(addl->proto_hdr.sas) ? "+" : ""); if (ses_elm_addlstatus_eip(addl->hdr)) - sbuf_printf(sbp, " at Slot %d", + sbuf_printf(sbp, " at slot %d", addl->proto_hdr.sas->type0_eip.dev_slot_num); - if (ses_elm_sas_type0_not_all_phys(addl->proto_hdr.sas)) - sbuf_printf(sbp, ", Not All Phys"); sbuf_printf(sbp, "\n"); if (addl->proto_data.sasdev_phys == NULL) return; @@ -2247,9 +2275,8 @@ ses_print_addl_data_sas_type0(char *sesname, struct sbuf *sbp, /* Spec says all other fields are specific values */ sbuf_printf(sbp, " SATA device\n"); else { - sbuf_printf(sbp, " SAS device type %d id %d\n", + sbuf_printf(sbp, " SAS device type %d phy %d", ses_elm_sas_dev_phy_dev_type(phy), phy->phy_id); - sbuf_printf(sbp, "%s: phy %d: protocols:", sesname, i); SES_PRINT_PORTS(phy->initiator_ports, "Initiator"); SES_PRINT_PORTS(phy->target_ports, "Target"); sbuf_printf(sbp, "\n"); @@ -2262,33 +2289,17 @@ ses_print_addl_data_sas_type0(char *sesname, struct sbuf *sbp, } #undef SES_PRINT_PORTS -/** - * \brief Report whether a given enclosure object is an expander. - * - * \param enc SES softc associated with object. - * \param obj Enclosure object to report for. - * - * \return 1 if true, 0 otherwise. - */ -static int -ses_obj_is_expander(enc_softc_t *enc, enc_element_t *obj) -{ - return (obj->enctype == ELMTYP_SAS_EXP); -} - /** * \brief Print the additional element status data for this object, for SAS * type 1 objects. See SES2 r20 Sections 6.1.13.3.3 and 6.1.13.3.4. * - * \param enc SES enclosure, needed for type identification. * \param sesname SES device name associated with the object. * \param sbp Sbuf to print to. * \param obj The object to print the data for. - * \param periph_name Peripheral string associated with the object. */ static void -ses_print_addl_data_sas_type1(enc_softc_t *enc, char *sesname, - struct sbuf *sbp, enc_element_t *obj, char *periph_name) +ses_print_addl_data_sas_type1(char *sesname, struct sbuf *sbp, + enc_element_t *obj) { int i, num_phys; ses_element_t *elmpriv; @@ -2298,12 +2309,10 @@ ses_print_addl_data_sas_type1(enc_softc_t *enc, char *sesname, elmpriv = obj->elm_private; addl = &(elmpriv->addl); - if (addl->proto_hdr.sas == NULL) - return; - sbuf_printf(sbp, "%s: %s: SAS ", sesname, periph_name); - if (ses_obj_is_expander(enc, obj)) { + sbuf_printf(sbp, ", SAS "); + if (obj->elm_type == ELMTYP_SAS_EXP) { num_phys = addl->proto_hdr.sas->base_hdr.num_phys; - sbuf_printf(sbp, "Expander: %d Phys", num_phys); + sbuf_printf(sbp, "Expander: %d phys", num_phys); if (addl->proto_data.sasexp_phys == NULL) return; for (i = 0;i < num_phys;i++) { @@ -2314,7 +2323,7 @@ ses_print_addl_data_sas_type1(enc_softc_t *enc, char *sesname, } } else { num_phys = addl->proto_hdr.sas->base_hdr.num_phys; - sbuf_printf(sbp, "Port: %d Phys", num_phys); + sbuf_printf(sbp, "Port: %d phys", num_phys); if (addl->proto_data.sasport_phys == NULL) return; for (i = 0;i < num_phys;i++) { @@ -2329,6 +2338,24 @@ ses_print_addl_data_sas_type1(enc_softc_t *enc, char *sesname, } } +/** + * \brief Print the additional element status data for this object, for + * ATA objects. + * + * \param sbp Sbuf to print to. + * \param obj The object to print the data for. + */ +static void +ses_print_addl_data_ata(struct sbuf *sbp, enc_element_t *obj) +{ + ses_element_t *elmpriv = obj->elm_private; + struct ses_addl_status *addl = &elmpriv->addl; + struct ses_elm_ata_hdr *ata = addl->proto_hdr.ata; + + sbuf_printf(sbp, ", SATA Slot: scbus%d target %d\n", + scsi_4btoul(ata->bus), scsi_4btoul(ata->target)); +} + /** * \brief Print the additional element status data for this object. * @@ -2360,27 +2387,45 @@ ses_print_addl_data(enc_softc_t *enc, enc_element_t *obj) sbuf_printf(&sesname, "%s%d", enc->periph->periph_name, enc->periph->unit_number); sbuf_finish(&sesname); + sbuf_printf(&out, "%s: %s in ", sbuf_data(&sesname), sbuf_data(&name)); if (elmpriv->descr != NULL) - sbuf_printf(&out, "%s: %s: Element descriptor: '%s'\n", - sbuf_data(&sesname), sbuf_data(&name), elmpriv->descr); + sbuf_printf(&out, "'%s'", elmpriv->descr); + else { + if (obj->elm_type <= ELMTYP_LAST) + sbuf_cat(&out, elm_type_names[obj->elm_type]); + else + sbuf_printf(&out, "", obj->elm_type); + sbuf_printf(&out, " %d", obj->type_elm_idx); + if (obj->subenclosure != 0) + sbuf_printf(&out, " of subenc %d", obj->subenclosure); + } switch(ses_elm_addlstatus_proto(addl->hdr)) { + case SPSP_PROTO_FC: + goto noaddl; /* stubbed for now */ case SPSP_PROTO_SAS: + if (addl->proto_hdr.sas == NULL) + goto noaddl; switch(ses_elm_sas_descr_type(addl->proto_hdr.sas)) { case SES_SASOBJ_TYPE_SLOT: ses_print_addl_data_sas_type0(sbuf_data(&sesname), - &out, obj, sbuf_data(&name)); + &out, obj); break; case SES_SASOBJ_TYPE_OTHER: - ses_print_addl_data_sas_type1(enc, sbuf_data(&sesname), - &out, obj, sbuf_data(&name)); + ses_print_addl_data_sas_type1(sbuf_data(&sesname), + &out, obj); break; default: - break; + goto noaddl; } break; - case SPSP_PROTO_FC: /* stubbed for now */ + case SPSP_PROTO_ATA: + if (addl->proto_hdr.ata == NULL) + goto noaddl; + ses_print_addl_data_ata(&out, obj); break; default: +noaddl: + sbuf_cat(&out, "\n"); break; } sbuf_finish(&out); @@ -2485,7 +2530,7 @@ ses_get_elm_addlstatus_sas_type1(enc_softc_t *enc, enc_cache_t *enc_cache, goto out; /* Process expanders differently from other type1 cases */ - if (ses_obj_is_expander(enc, obj)) { + if (obj->elm_type == ELMTYP_SAS_EXP) { offset += sizeof(struct ses_elm_sas_type1_expander_hdr); physz = addl->proto_hdr.sas->base_hdr.num_phys * sizeof(struct ses_elm_sas_expander_phy); @@ -2593,6 +2638,53 @@ ses_get_elm_addlstatus_sas(enc_softc_t *enc, enc_cache_t *enc_cache, return (err); } +/** + * \brief Update the softc with the additional element status data for this + * object, for ATA objects. + * + * \param enc SES softc to be updated. + * \param buf The additional element status response buffer. + * \param bufsiz Size of the response buffer. + * \param eip The EIP bit value. + * \param tidx Type index for this object. + * \param nobj Number of objects attached to the SES softc. + * + * \return 0 on success, errno otherwise. + */ +static int +ses_get_elm_addlstatus_ata(enc_softc_t *enc, enc_cache_t *enc_cache, + uint8_t *buf, int bufsiz, int eip, int tidx, + int nobj) +{ + int err; + ses_cache_t *ses_cache; + + if (bufsiz < sizeof(struct ses_elm_ata_hdr)) { + err = EIO; + goto out; + } + + ses_cache = enc_cache->private; + switch(ses_cache->ses_types[tidx].hdr->etype_elm_type) { + case ELMTYP_DEVICE: + case ELMTYP_ARRAY_DEV: + break; + default: + ENC_VLOG(enc, "Element %d has Additional Status, " + "invalid for SES element type 0x%x\n", nobj, + ses_cache->ses_types[tidx].hdr->etype_elm_type); + err = ENODEV; + goto out; + } + + ((ses_element_t *)enc_cache->elm_map[nobj].elm_private) + ->addl.proto_hdr.ata = (struct ses_elm_ata_hdr *)buf; + err = 0; + +out: + return (err); +} + static void ses_softc_invalidate(enc_softc_t *enc) { diff --git a/sys/cam/scsi/scsi_ses.h b/sys/cam/scsi/scsi_ses.h index 779b3a97a00d..b9c69cbcfe30 100644 --- a/sys/cam/scsi/scsi_ses.h +++ b/sys/cam/scsi/scsi_ses.h @@ -2181,15 +2181,27 @@ struct ses_status_page_hdr { #define SESCTL_DISABLE 0x20 #define SESCTL_RSTSWAP 0x10 - -/* Control bits, Device Elements, byte 2 */ -#define SESCTL_DRVLCK 0x40 /* "DO NOT REMOVE" */ +/* Control bits, Array Device Slot Elements, byte 1 */ +#define SESCTL_RQSOK 0x80 /* RQST OK */ +#define SESCTL_RQSRSV 0x40 /* RQST RSVD DEVICE */ +#define SESCTL_RQSSPR 0x20 /* RQST HOT SPARE */ +#define SESCTL_RQSCCH 0x10 /* RQST CONS CHECK */ +#define SESCTL_RQSCRA 0x08 /* RQST IN CRIT ARRAY */ +#define SESCTL_RQSFAA 0x04 /* RQST IN FAILED ARRAY */ +#define SESCTL_RQSRR 0x02 /* RQST REBUI/REMAP */ +#define SESCTL_RQSRRA 0x01 /* RQST R/R ABORT */ +/* Control bits, [Array] Device Slot Elements, byte 2 */ +#define SESCTL_RQSACT 0x80 /* RQST ACTIVE */ +#define SESCTL_DRVLCK 0x40 /* DO NOT REMOVE */ +#define SESCTL_RQSMSN 0x10 /* RQST MISSING */ #define SESCTL_RQSINS 0x08 /* RQST INSERT */ #define SESCTL_RQSRMV 0x04 /* RQST REMOVE */ #define SESCTL_RQSID 0x02 /* RQST IDENT */ -/* Control bits, Device Elements, byte 3 */ +/* Control bits, [Array] Device Slot Elements, byte 3 */ #define SESCTL_RQSFLT 0x20 /* RQST FAULT */ #define SESCTL_DEVOFF 0x10 /* DEVICE OFF */ +#define SESCTL_ENBYPA 0x08 /* ENABLE BYP A */ +#define SESCTL_ENBYPB 0x04 /* ENABLE BYP B */ /* Control bits, Generic, byte 3 */ #define SESCTL_RQSTFAIL 0x40 @@ -2399,6 +2411,17 @@ union ses_elm_sas_hdr { int ses_elm_sas_type0_not_all_phys(union ses_elm_sas_hdr *); int ses_elm_sas_descr_type(union ses_elm_sas_hdr *); +/* + * This structure for SPSP_PROTO_ATA is not defined by SES specs, + * but purely my own design to make AHCI EM interoperate with SES. + * Since no other software I know can talk to SEMB, and we do not + * expose this this outside, it should be safe to do what we want. + */ +struct ses_elm_ata_hdr { + uint8_t bus[4]; + uint8_t target[4]; +}; + struct ses_elm_addlstatus_base_hdr { uint8_t byte0; /* diff --git a/sys/dev/ahci/ahci.c b/sys/dev/ahci/ahci.c index 4a17fb535498..435661107e95 100644 --- a/sys/dev/ahci/ahci.c +++ b/sys/dev/ahci/ahci.c @@ -186,6 +186,7 @@ ahci_attach(device_t dev) ctlr->ccc = 0; resource_int_value(device_get_name(dev), device_get_unit(dev), "ccc", &ctlr->ccc); + mtx_init(&ctlr->ch_mtx, "AHCI channels lock", NULL, MTX_DEF); /* Setup our own memory management for channels. */ ctlr->sc_iomem.rm_start = rman_get_start(ctlr->r_mem); @@ -379,6 +380,7 @@ ahci_detach(device_t dev) /* Free memory. */ rman_fini(&ctlr->sc_iomem); ahci_free_mem(dev); + mtx_destroy(&ctlr->ch_mtx); return (0); } @@ -666,6 +668,50 @@ ahci_get_dma_tag(device_t dev, device_t child) return (ctlr->dma_tag); } +void +ahci_attached(device_t dev, struct ahci_channel *ch) +{ + struct ahci_controller *ctlr = device_get_softc(dev); + + mtx_lock(&ctlr->ch_mtx); + ctlr->ch[ch->unit] = ch; + mtx_unlock(&ctlr->ch_mtx); +} + +void +ahci_detached(device_t dev, struct ahci_channel *ch) +{ + struct ahci_controller *ctlr = device_get_softc(dev); + + mtx_lock(&ctlr->ch_mtx); + mtx_lock(&ch->mtx); + ctlr->ch[ch->unit] = NULL; + mtx_unlock(&ch->mtx); + mtx_unlock(&ctlr->ch_mtx); +} + +struct ahci_channel * +ahci_getch(device_t dev, int n) +{ + struct ahci_controller *ctlr = device_get_softc(dev); + struct ahci_channel *ch; + + KASSERT(n >= 0 && n < AHCI_MAX_PORTS, ("Bad channel number %d", n)); + mtx_lock(&ctlr->ch_mtx); + ch = ctlr->ch[n]; + if (ch != NULL) + mtx_lock(&ch->mtx); + mtx_unlock(&ctlr->ch_mtx); + return (ch); +} + +void +ahci_putch(struct ahci_channel *ch) +{ + + mtx_unlock(&ch->mtx); +} + static int ahci_ch_probe(device_t dev) { @@ -824,6 +870,7 @@ ahci_ch_attach(device_t dev) ahci_ch_pm, ch); } mtx_unlock(&ch->mtx); + ahci_attached(device_get_parent(dev), ch); ctx = device_get_sysctl_ctx(dev); tree = device_get_sysctl_tree(dev); SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "disable_phy", @@ -849,6 +896,7 @@ ahci_ch_detach(device_t dev) { struct ahci_channel *ch = device_get_softc(dev); + ahci_detached(device_get_parent(dev), ch); mtx_lock(&ch->mtx); xpt_async(AC_LOST_DEVICE, ch->path, NULL); /* Forget about reset. */ diff --git a/sys/dev/ahci/ahci.h b/sys/dev/ahci/ahci.h index fc53d346f17f..27b3970dadfc 100644 --- a/sys/dev/ahci/ahci.h +++ b/sys/dev/ahci/ahci.h @@ -524,6 +524,8 @@ struct ahci_controller { } interrupt[AHCI_MAX_PORTS]; void (*ch_start)(struct ahci_channel *); int dma_coherent; /* DMA is cache-coherent */ + struct mtx ch_mtx; /* Lock for attached channels */ + struct ahci_channel *ch[AHCI_MAX_PORTS]; /* Attached channels */ }; enum ahci_err_type { @@ -654,5 +656,11 @@ int ahci_ctlr_reset(device_t dev); int ahci_ctlr_setup(device_t dev); void ahci_free_mem(device_t dev); +/* Functions to allow AHCI EM to access other channels. */ +void ahci_attached(device_t dev, struct ahci_channel *ch); +void ahci_detached(device_t dev, struct ahci_channel *ch); +struct ahci_channel * ahci_getch(device_t dev, int n); +void ahci_putch(struct ahci_channel *ch); + extern devclass_t ahci_devclass; diff --git a/sys/dev/ahci/ahciem.c b/sys/dev/ahci/ahciem.c index 9bb4d9717763..a6f22fac5639 100644 --- a/sys/dev/ahci/ahciem.c +++ b/sys/dev/ahci/ahciem.c @@ -294,14 +294,14 @@ ahci_em_setleds(device_t dev, int c) enc = device_get_softc(dev); val = 0; - if (enc->status[c][2] & 0x80) /* Activity */ + if (enc->status[c][2] & SESCTL_RQSACT) /* Activity */ val |= (1 << 0); - if (enc->status[c][2] & SESCTL_RQSID) /* Identification */ + if (enc->status[c][1] & SESCTL_RQSRR) /* Rebuild */ + val |= (1 << 6) | (1 << 3); + else if (enc->status[c][2] & SESCTL_RQSID) /* Identification */ val |= (1 << 3); else if (enc->status[c][3] & SESCTL_RQSFLT) /* Fault */ val |= (1 << 6); - else if (enc->status[c][1] & 0x02) /* Rebuild */ - val |= (1 << 6) | (1 << 3); timeout = 10000; while (ATA_INL(enc->r_memc, 0) & (AHCI_EM_TM | AHCI_EM_RST) && @@ -366,9 +366,12 @@ static void ahci_em_emulate_ses_on_led(device_t dev, union ccb *ccb) { struct ahci_enclosure *enc; + struct ahci_channel *ch; struct ses_status_page *page; struct ses_status_array_dev_slot *ads, *ads0; struct ses_elm_desc_hdr *elmd; + struct ses_elm_addlstatus_eip_hdr *elma; + struct ses_elm_ata_hdr *elmb; uint8_t *buf; int i; @@ -391,7 +394,7 @@ ahci_em_emulate_ses_on_led(device_t dev, union ccb *ccb) strncpy(&buf[3], device_get_nameunit(dev), 7); strncpy(&buf[10], "AHCI ", SID_VENDOR_SIZE); strncpy(&buf[18], "SGPIO Enclosure ", SID_PRODUCT_SIZE); - strncpy(&buf[34], "1.00", SID_REVISION_SIZE); + strncpy(&buf[34], "2.00", SID_REVISION_SIZE); strncpy(&buf[39], "0001", 4); strncpy(&buf[43], "S-E-S ", 6); strncpy(&buf[49], "2.00", 4); @@ -403,14 +406,15 @@ ahci_em_emulate_ses_on_led(device_t dev, union ccb *ccb) page = (struct ses_status_page *)buf; if (ccb->ataio.cmd.lba_low == 0x02 && ccb->ataio.cmd.features == 0x00 && - ccb->ataio.cmd.sector_count >= 2) { + ccb->ataio.cmd.sector_count >= 3) { bzero(buf, ccb->ataio.dxfer_len); page->hdr.page_code = 0; - scsi_ulto2b(4, page->hdr.length); - buf[4] = 0; - buf[5] = 1; - buf[6] = 2; - buf[7] = 7; + scsi_ulto2b(5, page->hdr.length); + buf[4] = 0x00; + buf[5] = 0x01; + buf[6] = 0x02; + buf[7] = 0x07; + buf[8] = 0x0a; ccb->ccb_h.status = CAM_REQ_CMP; goto out; } @@ -418,26 +422,30 @@ ahci_em_emulate_ses_on_led(device_t dev, union ccb *ccb) /* SEMB RECEIVE DIAGNOSTIC RESULT (1) */ if (ccb->ataio.cmd.lba_low == 0x02 && ccb->ataio.cmd.features == 0x01 && - ccb->ataio.cmd.sector_count >= 13) { + ccb->ataio.cmd.sector_count >= 16) { struct ses_enc_desc *ed; struct ses_elm_type_desc *td; bzero(buf, ccb->ataio.dxfer_len); page->hdr.page_code = 0x01; - scsi_ulto2b(4 + 4 + 36 + 4, page->hdr.length); + scsi_ulto2b(4 + sizeof(*ed) + sizeof(*td) + 11, + page->hdr.length); ed = (struct ses_enc_desc *)&buf[8]; ed->byte0 = 0x11; ed->subenc_id = 0; ed->num_types = 1; ed->length = 36; + ed->logical_id[0] = 0x30; /* NAA Locally Assigned. */ + strncpy(&ed->logical_id[1], device_get_nameunit(dev), 7); strncpy(ed->vendor_id, "AHCI ", SID_VENDOR_SIZE); strncpy(ed->product_id, "SGPIO Enclosure ", SID_PRODUCT_SIZE); - strncpy(ed->product_rev, " ", SID_REVISION_SIZE); + strncpy(ed->product_rev, "2.00", SID_REVISION_SIZE); td = (struct ses_elm_type_desc *)ses_enc_desc_next(ed); td->etype_elm_type = 0x17; td->etype_maxelt = enc->channels; td->etype_subenc = 0; - td->etype_txt_len = 0; + td->etype_txt_len = 11; + snprintf((char *)(td + 1), 12, "Drive Slots"); ccb->ccb_h.status = CAM_REQ_CMP; goto out; } @@ -453,10 +461,22 @@ ahci_em_emulate_ses_on_led(device_t dev, union ccb *ccb) for (i = 0; i < enc->channels; i++) { ads = &page->elements[i + 1].array_dev_slot; memcpy(ads, enc->status[i], 4); - ads->common.bytes[0] |= - (enc->ichannels & (1 << i)) ? - SES_OBJSTAT_UNKNOWN : - SES_OBJSTAT_NOTINSTALLED; + ch = ahci_getch(device_get_parent(dev), i); + if (ch == NULL) { + ads->common.bytes[0] |= SES_OBJSTAT_UNKNOWN; + continue; + } + if (ch->pm_present) + ads->common.bytes[0] |= SES_OBJSTAT_UNKNOWN; + else if (ch->devices) + ads->common.bytes[0] |= SES_OBJSTAT_OK; + else if (ch->disablephy) + ads->common.bytes[0] |= SES_OBJSTAT_NOTAVAIL; + else + ads->common.bytes[0] |= SES_OBJSTAT_NOTINSTALLED; + if (ch->disablephy) + ads->common.bytes[3] |= SESCTL_DEVOFF; + ahci_putch(ch); } ccb->ccb_h.status = CAM_REQ_CMP; goto out; @@ -471,21 +491,21 @@ ahci_em_emulate_ses_on_led(device_t dev, union ccb *ccb) ads = &page->elements[i + 1].array_dev_slot; if (ads->common.bytes[0] & SESCTL_CSEL) { enc->status[i][0] = 0; - enc->status[i][1] = - ads->bytes[0] & 0x02; - enc->status[i][2] = - ads->bytes[1] & (0x80 | SESCTL_RQSID); - enc->status[i][3] = - ads->bytes[2] & SESCTL_RQSFLT; + enc->status[i][1] = ads->bytes[0] & + SESCTL_RQSRR; + enc->status[i][2] = ads->bytes[1] & + (SESCTL_RQSACT | SESCTL_RQSID); + enc->status[i][3] = ads->bytes[2] & + SESCTL_RQSFLT; ahci_em_setleds(dev, i); } else if (ads0->common.bytes[0] & SESCTL_CSEL) { enc->status[i][0] = 0; - enc->status[i][1] = - ads0->bytes[0] & 0x02; - enc->status[i][2] = - ads0->bytes[1] & (0x80 | SESCTL_RQSID); - enc->status[i][3] = - ads0->bytes[2] & SESCTL_RQSFLT; + enc->status[i][1] = ads0->bytes[0] & + SESCTL_RQSRR; + enc->status[i][2] = ads0->bytes[1] & + (SESCTL_RQSACT | SESCTL_RQSID); + enc->status[i][3] = ads0->bytes[2] & + SESCTL_RQSFLT; ahci_em_setleds(dev, i); } } @@ -496,15 +516,48 @@ ahci_em_emulate_ses_on_led(device_t dev, union ccb *ccb) /* SEMB RECEIVE DIAGNOSTIC RESULT (7) */ if (ccb->ataio.cmd.lba_low == 0x02 && ccb->ataio.cmd.features == 0x07 && - ccb->ataio.cmd.sector_count >= (3 + 3 * enc->channels)) { + ccb->ataio.cmd.sector_count >= (6 + 3 * enc->channels)) { bzero(buf, ccb->ataio.dxfer_len); page->hdr.page_code = 0x07; - scsi_ulto2b(4 + 4 + 12 * enc->channels, + scsi_ulto2b(4 + 15 + 11 * enc->channels, page->hdr.length); + elmd = (struct ses_elm_desc_hdr *)&buf[8]; + scsi_ulto2b(11, elmd->length); + snprintf((char *)(elmd + 1), 12, "Drive Slots"); + for (i = 0; i < enc->channels; i++) { + elmd = (struct ses_elm_desc_hdr *)&buf[8 + 15 + 11 * i]; + scsi_ulto2b(7, elmd->length); + snprintf((char *)(elmd + 1), 8, "Slot %02d", i); + } + ccb->ccb_h.status = CAM_REQ_CMP; + goto out; + } + + /* SEMB RECEIVE DIAGNOSTIC RESULT (a) */ + if (ccb->ataio.cmd.lba_low == 0x02 && + ccb->ataio.cmd.features == 0x0a && + ccb->ataio.cmd.sector_count >= (2 + 3 * enc->channels)) { + bzero(buf, ccb->ataio.dxfer_len); + page->hdr.page_code = 0x0a; + scsi_ulto2b(4 + (sizeof(*elma) + sizeof(*elmb)) * enc->channels, page->hdr.length); for (i = 0; i < enc->channels; i++) { - elmd = (struct ses_elm_desc_hdr *)&buf[8 + 4 + 12 * i]; - scsi_ulto2b(8, elmd->length); - snprintf((char *)(elmd + 1), 9, "SLOT %03d", i); + elma = (struct ses_elm_addlstatus_eip_hdr *)&buf[ + 8 + (sizeof(*elma) + sizeof(*elmb)) * i]; + elma->base.byte0 = 0x10 | SPSP_PROTO_ATA; + elma->base.length = 2 + sizeof(*elmb); + elma->byte2 = 0x01; + elma->element_index = 1 + i; + ch = ahci_getch(device_get_parent(dev), i); + if (ch == NULL) { + elma->base.byte0 |= 0x80; + continue; + } + if (ch->devices == 0 || ch->pm_present) + elma->base.byte0 |= 0x80; + elmb = (struct ses_elm_ata_hdr *)(elma + 1); + scsi_ulto4b(cam_sim_path(ch->sim), elmb->bus); + scsi_ulto4b(0, elmb->target); + ahci_putch(ch); } ccb->ccb_h.status = CAM_REQ_CMP; goto out; From 01e92e29779c6373d3353d81c3a139f4671669e2 Mon Sep 17 00:00:00 2001 From: Li-Wen Hsu Date: Sun, 23 Jun 2019 19:37:12 +0000 Subject: [PATCH 054/165] Skip sys.netinet.socket_afinet.socket_afinet_bind_zero temporarily because it doesn't work when mac_portacl(4) loaded PR: 238781 Sponsored by: The FreeBSD Foundation --- tests/sys/netinet/socket_afinet.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/sys/netinet/socket_afinet.c b/tests/sys/netinet/socket_afinet.c index d45f70165519..47744d69b587 100644 --- a/tests/sys/netinet/socket_afinet.c +++ b/tests/sys/netinet/socket_afinet.c @@ -51,6 +51,8 @@ ATF_TC_BODY(socket_afinet_bind_zero, tc) int sd, rc; struct sockaddr_in sin; + atf_tc_skip("doesn't work when mac_portacl(4) loaded (bug238781)"); + sd = socket(PF_INET, SOCK_DGRAM, 0); ATF_CHECK(sd >= 0); From 22c7bcb842258be4d12355c3e2e97c0deb88d735 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sun, 23 Jun 2019 21:06:56 +0000 Subject: [PATCH 055/165] pmap_enter_quick_locked() never replaces a valid mapping, so it need not perform a TLB invalidation. A barrier suffices. (See r343876.) Add a comment to pmap_enter_quick_locked() in order to highlight the fact that it does not replace valid mappings. Correct a typo in one of pmap_enter()'s comments. MFC after: 1 week --- sys/arm64/arm64/pmap.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sys/arm64/arm64/pmap.c b/sys/arm64/arm64/pmap.c index 8afee14fbdd1..ff0c0611743e 100644 --- a/sys/arm64/arm64/pmap.c +++ b/sys/arm64/arm64/pmap.c @@ -3408,7 +3408,7 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot, __func__, pmap, va, new_l3); } } else { - /* New mappig */ + /* New mapping */ pmap_load_store(l3, new_l3); dsb(ishst); } @@ -3706,6 +3706,9 @@ pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, l3 = pmap_l2_to_l3(pde, va); } + /* + * Abort if a mapping already exists. + */ if (pmap_load(l3) != 0) { if (mpte != NULL) { mpte->wire_count--; @@ -3755,7 +3758,7 @@ pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, cpu_icache_sync_range(PHYS_TO_DMAP(pa), PAGE_SIZE); pmap_load_store(l3, l3_val); - pmap_invalidate_page(pmap, va); + dsb(ishst); return (mpte); } From 89f2ab0608a73a1e2da00f61c0da334b2049baed Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Sun, 23 Jun 2019 21:15:31 +0000 Subject: [PATCH 056/165] Switch to check for effective user id in r349320, and disable dumping into existing files for sugid processes. Despite using real user id pronounces the intent, it actually breaks suid coredumps, while not making any difference for non-sugid processes. The reason for the breakage is that non-existent core file is created with the effective uid (unless weird hacks like SUIDDIR are configured). Then, if user enabled kern.sugid_coredump, core dumping should not overwrite core files owned by effective uid, but we cannot pretend to use real uid for dumping. PR: 68905 admbugs: 358 Sponsored by: The FreeBSD Foundation MFC after: 1 week --- sys/kern/kern_sig.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index f40aad4b3869..a3a05cef1038 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -3398,10 +3398,16 @@ corefile_open_last(struct thread *td, char *name, int indexpos, } if (oldvp != NULL) { - if (nextvp == NULL) - nextvp = oldvp; - else + if (nextvp == NULL) { + if ((td->td_proc->p_flag & P_SUGID) != 0) { + error = EFAULT; + vnode_close_locked(td, oldvp); + } else { + nextvp = oldvp; + } + } else { vnode_close_locked(td, oldvp); + } } if (error != 0) { if (nextvp != NULL) @@ -3521,6 +3527,8 @@ corefile_open(const char *comm, uid_t uid, pid_t pid, struct thread *td, oflags = VN_OPEN_NOAUDIT | VN_OPEN_NAMECACHE | (capmode_coredump ? VN_OPEN_NOCAPCHECK : 0); flags = O_CREAT | FWRITE | O_NOFOLLOW; + if ((td->td_proc->p_flag & P_SUGID) != 0) + flags |= O_EXCL; NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, name, td); error = vn_open_cred(&nd, &flags, cmode, oflags, td->td_ucred, @@ -3597,11 +3605,11 @@ coredump(struct thread *td) /* * Don't dump to non-regular files or files with links. - * Do not dump into system files. Real user must own the corefile. + * Do not dump into system files. Effective user must own the corefile. */ if (vp->v_type != VREG || VOP_GETATTR(vp, &vattr, cred) != 0 || vattr.va_nlink != 1 || (vp->v_vflag & VV_SYSTEM) != 0 || - vattr.va_uid != cred->cr_ruid) { + vattr.va_uid != cred->cr_uid) { VOP_UNLOCK(vp, 0); error = EFAULT; goto out; From 7a3a48426eb0c3ca74d575afc7ae164622cfe758 Mon Sep 17 00:00:00 2001 From: Ian Lepore Date: Sun, 23 Jun 2019 21:17:41 +0000 Subject: [PATCH 057/165] Allow compiling ukbdmap.h on arm, since it appears to work fine. --- sys/conf/files.arm | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sys/conf/files.arm b/sys/conf/files.arm index 6134b20e1177..8d890144b277 100644 --- a/sys/conf/files.arm +++ b/sys/conf/files.arm @@ -166,6 +166,12 @@ cloudabi32_vdso_blob.o optional compat_cloudabi32 \ clean "cloudabi32_vdso_blob.o" # +# +ukbdmap.h optional ukbd_dflt_keymap \ + compile-with "kbdcontrol -P ${S:S/sys$/share/}/vt/keymaps -P ${S:S/sys$/share/}/syscons/keymaps -L ${UKBD_DFLT_KEYMAP} | sed -e 's/^static keymap_t.* = /static keymap_t key_map = /' -e 's/^static accentmap_t.* = /static accentmap_t accent_map = /' > ukbdmap.h" \ + no-obj no-implicit-rule before-depend \ + clean "ukbdmap.h" + # Annapurna support arm/annapurna/alpine/alpine_ccu.c optional al_ccu fdt arm/annapurna/alpine/alpine_nb_service.c optional al_nb_service fdt From d8ddb98a5ed0069fa2c9e577a31ff1c1d0306a74 Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Sun, 23 Jun 2019 21:21:11 +0000 Subject: [PATCH 058/165] amd64 pmap: block on turnstile for lock-less DI. Port the code to block on turnstile instead of yielding, to lock-less delayed invalidation. The yield might cause tight loop due to priority inversion. Since it is impossible to avoid race between block and wake-up, arm 1-tick callout to wakeup when thread blocks itself. Reported and tested by: mjg Reviewed by: alc, markj Sponsored by: The FreeBSD Foundation MFC after: 2 months Differential revision: https://reviews.freebsd.org/D20636 --- sys/amd64/amd64/pmap.c | 131 ++++++++++++++++++++++++++++++++--------- 1 file changed, 104 insertions(+), 27 deletions(-) diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c index d7a35b5c9cfc..3b3f4b4200ff 100644 --- a/sys/amd64/amd64/pmap.c +++ b/sys/amd64/amd64/pmap.c @@ -484,6 +484,9 @@ static struct pmap_invl_gen pmap_invl_gen_head = { .next = NULL, }; static u_long pmap_invl_gen = 1; +static int pmap_invl_waiters; +static struct callout pmap_invl_callout; +static bool pmap_invl_callout_inited; #define PMAP_ASSERT_NOT_IN_DI() \ KASSERT(pmap_not_in_di(), ("DI already started")) @@ -538,6 +541,34 @@ pmap_thread_init_invl_gen_l(struct thread *td) invl_gen->gen = 0; } +static void +pmap_delayed_invl_wait_block(u_long *m_gen, u_long *invl_gen) +{ + struct turnstile *ts; + + ts = turnstile_trywait(&invl_gen_ts); + if (*m_gen > atomic_load_long(invl_gen)) + turnstile_wait(ts, NULL, TS_SHARED_QUEUE); + else + turnstile_cancel(ts); +} + +static void +pmap_delayed_invl_finish_unblock(u_long new_gen) +{ + struct turnstile *ts; + + turnstile_chain_lock(&invl_gen_ts); + ts = turnstile_lookup(&invl_gen_ts); + if (new_gen != 0) + pmap_invl_gen = new_gen; + if (ts != NULL) { + turnstile_broadcast(ts, TS_SHARED_QUEUE); + turnstile_unpend(ts); + } + turnstile_chain_unlock(&invl_gen_ts); +} + /* * Start a new Delayed Invalidation (DI) block of code, executed by * the current thread. Within a DI block, the current thread may @@ -582,24 +613,15 @@ static void pmap_delayed_invl_finish_l(void) { struct pmap_invl_gen *invl_gen, *next; - struct turnstile *ts; invl_gen = &curthread->td_md.md_invl_gen; KASSERT(invl_gen->gen != 0, ("missed invl_start")); mtx_lock(&invl_gen_mtx); next = LIST_NEXT(invl_gen, link); - if (next == NULL) { - turnstile_chain_lock(&invl_gen_ts); - ts = turnstile_lookup(&invl_gen_ts); - pmap_invl_gen = invl_gen->gen; - if (ts != NULL) { - turnstile_broadcast(ts, TS_SHARED_QUEUE); - turnstile_unpend(ts); - } - turnstile_chain_unlock(&invl_gen_ts); - } else { + if (next == NULL) + pmap_delayed_invl_finish_unblock(invl_gen->gen); + else next->gen = invl_gen->gen; - } LIST_REMOVE(invl_gen, link); mtx_unlock(&invl_gen_mtx); invl_gen->gen = 0; @@ -856,6 +878,8 @@ pmap_delayed_invl_finish_u(void) goto again; } critical_exit(); + if (atomic_load_int(&pmap_invl_waiters) > 0) + pmap_delayed_invl_finish_unblock(0); if (invl_gen->saved_pri != 0) { thread_lock(td); sched_prio(td, invl_gen->saved_pri); @@ -888,6 +912,9 @@ DB_SHOW_COMMAND(di_queue, pmap_di_queue) static long invl_wait; SYSCTL_LONG(_vm_pmap, OID_AUTO, invl_wait, CTLFLAG_RD, &invl_wait, 0, "Number of times DI invalidation blocked pmap_remove_all/write"); +static long invl_wait_slow; +SYSCTL_LONG(_vm_pmap, OID_AUTO, invl_wait_slow, CTLFLAG_RD, &invl_wait_slow, 0, + "Number of slow invalidation waits for lockless DI"); #endif static u_long * @@ -897,6 +924,27 @@ pmap_delayed_invl_genp(vm_page_t m) return (&pv_invl_gen[pa_index(VM_PAGE_TO_PHYS(m)) % NPV_LIST_LOCKS]); } +static void +pmap_delayed_invl_callout_func(void *arg __unused) +{ + + if (atomic_load_int(&pmap_invl_waiters) == 0) + return; + pmap_delayed_invl_finish_unblock(0); +} + +static void +pmap_delayed_invl_callout_init(void *arg __unused) +{ + + if (pmap_di_locked()) + return; + callout_init(&pmap_invl_callout, 1); + pmap_invl_callout_inited = true; +} +SYSINIT(pmap_di_callout, SI_SUB_CPU + 1, SI_ORDER_ANY, + pmap_delayed_invl_callout_init, NULL); + /* * Ensure that all currently executing DI blocks, that need to flush * TLB for the given page m, actually flushed the TLB at the time the @@ -914,7 +962,6 @@ pmap_delayed_invl_genp(vm_page_t m) static void pmap_delayed_invl_wait_l(vm_page_t m) { - struct turnstile *ts; u_long *m_gen; #ifdef PV_STATS bool accounted = false; @@ -928,11 +975,7 @@ pmap_delayed_invl_wait_l(vm_page_t m) accounted = true; } #endif - ts = turnstile_trywait(&invl_gen_ts); - if (*m_gen > pmap_invl_gen) - turnstile_wait(ts, NULL, TS_SHARED_QUEUE); - else - turnstile_cancel(ts); + pmap_delayed_invl_wait_block(m_gen, &pmap_invl_gen); } } @@ -940,19 +983,53 @@ static void pmap_delayed_invl_wait_u(vm_page_t m) { u_long *m_gen; -#ifdef PV_STATS - bool accounted = false; -#endif + struct lock_delay_arg lda; + bool fast; + fast = true; m_gen = pmap_delayed_invl_genp(m); + lock_delay_arg_init(&lda, &di_delay); while (*m_gen > atomic_load_long(&pmap_invl_gen_head.gen)) { -#ifdef PV_STATS - if (!accounted) { - atomic_add_long(&invl_wait, 1); - accounted = true; + if (fast || !pmap_invl_callout_inited) { + PV_STAT(atomic_add_long(&invl_wait, 1)); + lock_delay(&lda); + fast = false; + } else { + /* + * The page's invalidation generation number + * is still below the current thread's number. + * Prepare to block so that we do not waste + * CPU cycles or worse, suffer livelock. + * + * Since it is impossible to block without + * racing with pmap_delayed_invl_finish_u(), + * prepare for the race by incrementing + * pmap_invl_waiters and arming a 1-tick + * callout which will unblock us if we lose + * the race. + */ + atomic_add_int(&pmap_invl_waiters, 1); + + /* + * Re-check the current thread's invalidation + * generation after incrementing + * pmap_invl_waiters, so that there is no race + * with pmap_delayed_invl_finish_u() setting + * the page generation and checking + * pmap_invl_waiters. The only race allowed + * is for a missed unblock, which is handled + * by the callout. + */ + if (*m_gen > + atomic_load_long(&pmap_invl_gen_head.gen)) { + callout_reset(&pmap_invl_callout, 1, + pmap_delayed_invl_callout_func, NULL); + PV_STAT(atomic_add_long(&invl_wait_slow, 1)); + pmap_delayed_invl_wait_block(m_gen, + &pmap_invl_gen_head.gen); + } + atomic_add_int(&pmap_invl_waiters, -1); } -#endif - kern_yield(PRI_USER); } } From 5364951d98435634f74f99cc071d678ac541ebe1 Mon Sep 17 00:00:00 2001 From: Ian Lepore Date: Mon, 24 Jun 2019 01:42:09 +0000 Subject: [PATCH 059/165] Build an armv7 LINT kernel in addition to armv5 LINT. You might think this had been done years ago. I did. All this time we've only compiled a LINT kernel for TARGET_ARCH=arm. Now separate LINT-V5 and LINT-V7 configs are generated and built. There are two new files in arm/conf, NOTES.armv5 and NOTES.armv7, containing some of what used to be in the arm NOTES file. That file now contains only the bits that are common to v5 and v7. The makeLINT.mk file now creates the LINT-V5 and LINT-V7 files by concatening sys/conf/NOTES, arm/conf/NOTES, and arm/conf/NOTES.armv{5,7} in that order. --- sys/arm/conf/NOTES | 61 +++++++------------------------------- sys/arm/conf/NOTES.armv5 | 38 ++++++++++++++++++++++++ sys/arm/conf/NOTES.armv7 | 64 ++++++++++++++++++++++++++++++++++++++++ sys/conf/makeLINT.mk | 5 ++++ 4 files changed, 117 insertions(+), 51 deletions(-) create mode 100644 sys/arm/conf/NOTES.armv5 create mode 100644 sys/arm/conf/NOTES.armv7 diff --git a/sys/arm/conf/NOTES b/sys/arm/conf/NOTES index 559146b58014..518cf4050ad9 100644 --- a/sys/arm/conf/NOTES +++ b/sys/arm/conf/NOTES @@ -1,44 +1,22 @@ # $FreeBSD$ -machine arm - -cpu CPU_ARM9E - -files "../mv/files.mv" -files "../mv/discovery/files.db78xxx" -files "../mv/kirkwood/files.kirkwood" -files "../mv/orion/files.db88f5xxx" -files "../mv/orion/files.ts7800" - -makeoptions CONF_CFLAGS+="-march=armv5te" -makeoptions LDFLAGS="-zmuldefs" -makeoptions KERNPHYSADDR=0x00000000 - options FDT -options SOC_MV_DISCOVERY -options SOC_MV_KIRKWOOD -options SOC_MV_ORION - -options ARM_MANY_BOARD -device nand - -# IIC -device twsi - -nooptions SMP -nooptions MAXCPU +# Undo options from sys/conf/NOTES that we do not want... nooptions COMPAT_FREEBSD4 nooptions COMPAT_FREEBSD5 nooptions COMPAT_FREEBSD6 nooptions COMPAT_FREEBSD7 nooptions COMPAT_FREEBSD9 -nooption PPC_PROBE_CHIPSET +nooptions PPC_PROBE_CHIPSET +nooptions MAXCPU # value is set in machine/param.h + +# Devices in sys/conf/NOTES for which no such hardware exists on arm, +# or the drivers don't compile... nodevice fdc nodevice sym -nodevice ukbd nodevice sc nodevice blank_saver @@ -58,28 +36,9 @@ nodevice cxgbe nodevice cxgbev nodevice snd_cmi -# -# Enable the kernel DTrace hooks which are required to load the DTrace -# kernel modules. -# -options KDTRACE_HOOKS - -# DTrace core -# NOTE: introduces CDDL-licensed components into the kernel -#device dtrace - -# DTrace modules -#device dtrace_profile -#device dtrace_sdt -#device dtrace_fbt -#device dtrace_systrace -#device dtrace_prototype -#device dtnfscl -#device dtmalloc - -# Alternatively include all the DTrace modules -#device dtraceall - -# These aren't known to work on arm and/or don't compile nodevice mpr nodevice mps + +# Add devices which are specific to various arm platforms... + +device twsi # i2c controller on Marvel and Allwinner diff --git a/sys/arm/conf/NOTES.armv5 b/sys/arm/conf/NOTES.armv5 new file mode 100644 index 000000000000..c67b37ed0052 --- /dev/null +++ b/sys/arm/conf/NOTES.armv5 @@ -0,0 +1,38 @@ +# armv5-specific changes for doing a LINT build. +# +# The contents of sys/conf/NOTES, sys/arm/conf/NOTES, and this file are +# concatenated (in that order) to create the LINT-V5 kernel config file. +# +# $FreeBSD$ + +#NO_UNIVERSE + +machine arm arm +cpu CPU_ARM9E + +files "../mv/files.mv" +files "../mv/discovery/files.db78xxx" +files "../mv/kirkwood/files.kirkwood" +files "../mv/orion/files.db88f5xxx" +files "../mv/orion/files.ts7800" + +makeoptions CONF_CFLAGS+="-march=armv5te" +makeoptions LDFLAGS="-zmuldefs" +makeoptions KERNPHYSADDR=0x00000000 + +# Undo options from sys/conf/NOTES that we do not want... + +nooptions SMP # All armv5 are single-core + +# Add options for armv5 that are not in sys/conf/NOTES... + +options ARM_MANY_BOARD + +options SOC_MV_DISCOVERY +options SOC_MV_KIRKWOOD +options SOC_MV_ORION + +# Add devices which are specific to various arm platforms... + +device nand + diff --git a/sys/arm/conf/NOTES.armv7 b/sys/arm/conf/NOTES.armv7 new file mode 100644 index 000000000000..e8a19034b001 --- /dev/null +++ b/sys/arm/conf/NOTES.armv7 @@ -0,0 +1,64 @@ +# armv7-specific changes for doing a LINT build. +# +# The contents of sys/conf/NOTES, sys/arm/conf/NOTES, and this file are +# concatenated (in that order) to create the LINT-V7 kernel config file. +# +# $FreeBSD$ + + +#NO_UNIVERSE + +machine arm armv7 +cpu CPU_CORTEXA +cpu CPU_MV_PJ4B +makeoptions CONF_CFLAGS+="-march=armv7a" + +# Add options for armv7 that are not in sys/conf/NOTES... + +options ARM_L2_PIPT # Only L2 PIPT is supported +options FREEBSD_BOOT_LOADER # Process metadata passed from loader(8) +options INTRNG # Include INTRNG framework +options LINUX_BOOT_ABI # Process metadata passed from U-Boot +options PLATFORM # Include platform_if support +options SMP # Most v7 SoCs are multicore +options VFP # Enable floating point hardware support + +# NOTE: dtrace introduces CDDL-licensed components into the kernel +device dtrace # dtrace core +device dtraceall # include all dtrace modules +options KDTRACE_HOOKS + +# Add misc devices which are specific to various arm platforms... + +device generic_timer # ARM Generic Timer +device gic # Interrupt controller +device gpio # gpio interface and bus +device mpcore_timer # ARM MPCore Timer +device pl310 # PL310 L2 cache controller +device pmu # PMU support (for CCNT). + +# Add EXT_RESOURCES pseudo devices... + +options EXT_RESOURCES +device clk +device phy +device hwreset +device nvmem +device regulator +device syscon + +# Build SOC-specific modules... + +makeoptions MODULES_EXTRA+="allwinner" +makeoptions MODULES_EXTRA+="arm_ti" +makeoptions MODULES_EXTRA+="imx" + +# Build dtb files... + +makeoptions MODULES_EXTRA+="dtb/allwinner" +makeoptions MODULES_EXTRA+="dtb/am335x" +makeoptions MODULES_EXTRA+="dtb/imx6" +makeoptions MODULES_EXTRA+="dtb/nvidia" +makeoptions MODULES_EXTRA+="dtb/omap4" +makeoptions MODULES_EXTRA+="dtb/rpi" +makeoptions MODULES_EXTRA+="dtb/zynq" diff --git a/sys/conf/makeLINT.mk b/sys/conf/makeLINT.mk index 52dddf5a97d7..d3a414c14ff6 100644 --- a/sys/conf/makeLINT.mk +++ b/sys/conf/makeLINT.mk @@ -47,6 +47,11 @@ LINT: ${NOTES} ${MAKELINT_SED} echo "nodevice txp" >> ${.TARGET}-NOIP echo "nodevice netmap" >> ${.TARGET}-NOIP .endif +.if ${TARGET} == "arm" + cat ${.TARGET} ${.CURDIR}/NOTES.armv5 > ${.TARGET}-V5 + cat ${.TARGET} ${.CURDIR}/NOTES.armv7 > ${.TARGET}-V7 + rm ${.TARGET} +.endif .if ${TARGET} == "mips" echo "machine ${TARGET} ${TARGET_ARCH}" >> ${.TARGET} .endif From 2973d38a49547d101d9a2a157123c4768707ddaa Mon Sep 17 00:00:00 2001 From: Ian Lepore Date: Mon, 24 Jun 2019 02:27:17 +0000 Subject: [PATCH 060/165] The gpiopps(4) driver currently has probe and attach code only for FDT based systems, so conditionalize it accordingly in conf/files. --- sys/conf/files | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/conf/files b/sys/conf/files index 6f085e7fe7f6..96211a9fc623 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1751,7 +1751,7 @@ dev/gpio/gpiospi.c optional gpiospi dev/gpio/gpioths.c optional gpioths dev/gpio/gpio_if.m optional gpio dev/gpio/gpiobus_if.m optional gpio -dev/gpio/gpiopps.c optional gpiopps +dev/gpio/gpiopps.c optional gpiopps fdt dev/gpio/ofw_gpiobus.c optional fdt gpio dev/hifn/hifn7751.c optional hifn dev/hme/if_hme.c optional hme From 6e36309d83dd3353854e8ebbdabaeaa69e5ab6ac Mon Sep 17 00:00:00 2001 From: Ian Lepore Date: Mon, 24 Jun 2019 02:30:05 +0000 Subject: [PATCH 061/165] Add gpio(4) and related drivers to NOTES. --- sys/conf/NOTES | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sys/conf/NOTES b/sys/conf/NOTES index ce7ce9a28ee3..65154ab178cf 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -2481,6 +2481,18 @@ device pps device lpbb device pcfclock +# General Purpose I/O pins +device gpio # gpio interfaces and bus support +device gpiobacklight # sysctl control of gpio-based backlight +device gpioiic # i2c via gpio bitbang +device gpiokeys # kbd(4) glue for gpio-based key input +device gpioled # led(4) gpio glue +device gpiopower # event handler for gpio-based powerdown +device gpiopps # Pulse per second input from gpio pin +device gpioregulator # extres/regulator glue for gpio pin +device gpiospi # SPI via gpio bitbang +device gpioths # 1-wire temp/humidity sensor on gpio pin + # # Etherswitch framework and drivers # From 0bab2b6e6fb960673de231be51df14117605b0f1 Mon Sep 17 00:00:00 2001 From: Ian Lepore Date: Mon, 24 Jun 2019 02:39:56 +0000 Subject: [PATCH 062/165] Add pwm devices to NOTES. --- sys/conf/NOTES | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sys/conf/NOTES b/sys/conf/NOTES index 65154ab178cf..dfa5ff68d802 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -2493,6 +2493,10 @@ device gpioregulator # extres/regulator glue for gpio pin device gpiospi # SPI via gpio bitbang device gpioths # 1-wire temp/humidity sensor on gpio pin +# Pulse width modulation +device pwmbus # pwm interface and bus support +device pwmc # userland control access to pwm outputs + # # Etherswitch framework and drivers # From 51a7230a180fec81b637e2808cc2f5964108d9c2 Mon Sep 17 00:00:00 2001 From: Cy Schubert Date: Mon, 24 Jun 2019 02:58:02 +0000 Subject: [PATCH 063/165] Clean out duplicate definitions of TCP macros also found in netinet/tcp.h. MFC after: 1 week --- sys/contrib/ipfilter/netinet/ip_compat.h | 31 ------------------------ 1 file changed, 31 deletions(-) diff --git a/sys/contrib/ipfilter/netinet/ip_compat.h b/sys/contrib/ipfilter/netinet/ip_compat.h index 777495b39aed..363992ddb284 100644 --- a/sys/contrib/ipfilter/netinet/ip_compat.h +++ b/sys/contrib/ipfilter/netinet/ip_compat.h @@ -829,37 +829,6 @@ typedef struct tcpiphdr tcpiphdr_t; #undef IPOPT_AH #define IPOPT_AH 256+IPPROTO_AH -#ifndef TCPOPT_EOL -# define TCPOPT_EOL 0 -#endif -#ifndef TCPOPT_NOP -# define TCPOPT_NOP 1 -#endif -#ifndef TCPOPT_MAXSEG -# define TCPOPT_MAXSEG 2 -#endif -#ifndef TCPOLEN_MAXSEG -# define TCPOLEN_MAXSEG 4 -#endif -#ifndef TCPOPT_WINDOW -# define TCPOPT_WINDOW 3 -#endif -#ifndef TCPOLEN_WINDOW -# define TCPOLEN_WINDOW 3 -#endif -#ifndef TCPOPT_SACK_PERMITTED -# define TCPOPT_SACK_PERMITTED 4 -#endif -#ifndef TCPOLEN_SACK_PERMITTED -# define TCPOLEN_SACK_PERMITTED 2 -#endif -#ifndef TCPOPT_SACK -# define TCPOPT_SACK 5 -#endif -#ifndef TCPOPT_TIMESTAMP -# define TCPOPT_TIMESTAMP 8 -#endif - #ifndef ICMP_MINLEN # define ICMP_MINLEN 8 #endif From 2771ab3322fec0c64fcc3cc88084106a5a746b22 Mon Sep 17 00:00:00 2001 From: Ed Maste Date: Mon, 24 Jun 2019 17:25:14 +0000 Subject: [PATCH 064/165] vtfontcvt: improve .bdf validation Previously if we had a FONTBOUNDINGBOX or DWIDTH entry that had missing or invalid values and and failed sscanf, we would proceeded with partially initialized bounding box / device width variables. Reported by: afl (FONTBOUNDINGBOX) MFC with: r349100 Sponsored by: The FreeBSD Foundation --- usr.bin/vtfontcvt/vtfontcvt.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/usr.bin/vtfontcvt/vtfontcvt.c b/usr.bin/vtfontcvt/vtfontcvt.c index 70ec7cf31812..e34308d5d365 100644 --- a/usr.bin/vtfontcvt/vtfontcvt.c +++ b/usr.bin/vtfontcvt/vtfontcvt.c @@ -335,9 +335,11 @@ parse_bdf(FILE *fp, unsigned int map_idx) break; } } - } else if (strncmp(ln, "FONTBOUNDINGBOX ", 16) == 0 && - sscanf(ln + 16, "%d %d %d %d", &fbbw, &fbbh, &fbbox, - &fbboy) == 4) { + } else if (strncmp(ln, "FONTBOUNDINGBOX ", 16) == 0) { + if (sscanf(ln + 16, "%d %d %d %d", &fbbw, &fbbh, &fbbox, + &fbboy) != 4) + errx(1, "invalid FONTBOUNDINGBOX at line %u", + linenum); set_width(fbbw); set_height(fbbh); break; @@ -353,8 +355,9 @@ parse_bdf(FILE *fp, unsigned int map_idx) linenum++; ln[length - 1] = '\0'; - if (strncmp(ln, "DWIDTH ", 7) == 0 && - sscanf(ln + 7, "%d %d", &dwidth, &dwy) == 2) { + if (strncmp(ln, "DWIDTH ", 7) == 0) { + if (sscanf(ln + 7, "%d %d", &dwidth, &dwy) != 2) + errx(1, "invalid DWIDTH at line %u", linenum); if (dwy != 0 || (dwidth != fbbw && dwidth * 2 != fbbw)) errx(1, "bitmap with unsupported DWIDTH %d %d at line %u", dwidth, dwy, linenum); From 673c1c294479f113f6864445c36a0f2048e2737f Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Mon, 24 Jun 2019 19:19:37 +0000 Subject: [PATCH 065/165] Remove a lingering use of splbio(). The buffer must be locked by the caller. No functional change intended. Reviewed by: kib MFC after: 1 week Sponsored by: The FreeBSD Foundation --- sys/fs/smbfs/smbfs_io.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sys/fs/smbfs/smbfs_io.c b/sys/fs/smbfs/smbfs_io.c index 4edba5c761e7..fa6a14024213 100644 --- a/sys/fs/smbfs/smbfs_io.c +++ b/sys/fs/smbfs/smbfs_io.c @@ -375,9 +375,6 @@ smbfs_doio(struct vnode *vp, struct buf *bp, struct ucred *cr, struct thread *td */ if (error == EINTR || (!error && (bp->b_flags & B_NEEDCOMMIT))) { - int s; - - s = splbio(); bp->b_flags &= ~(B_INVAL|B_NOCACHE); if ((bp->b_flags & B_ASYNC) == 0) bp->b_flags |= B_EINTR; @@ -387,7 +384,6 @@ smbfs_doio(struct vnode *vp, struct buf *bp, struct ucred *cr, struct thread *td } if ((bp->b_flags & B_ASYNC) == 0) bp->b_flags |= B_EINTR; - splx(s); } else { if (error) { bp->b_ioflags |= BIO_ERROR; From 7e3c7420615fa2ab5604677993b953a43d663902 Mon Sep 17 00:00:00 2001 From: Scott Long Date: Mon, 24 Jun 2019 19:31:32 +0000 Subject: [PATCH 066/165] Add the PCI HDAudio device model from the 2016 GSoC. Detailed information can be found at https://wiki.freebsd.org/SummerOfCode2016/HDAudioEmulationForBhyve This commit has evolved from the original work to include Capsicum integration. As part of that, it only opens the host audio devices once and leaves them open, instead of opening and closing them on each guest access. Thanks to Peter Grehan and Marcelo Araujo for their help in bringing the work forward and providing some of the final techncial push. Submitted by: Alex Teaca Differential Revision: D7840, D12419 --- usr.sbin/bhyve/Makefile | 3 + usr.sbin/bhyve/audio.c | 282 ++++++++ usr.sbin/bhyve/audio.h | 86 +++ usr.sbin/bhyve/hda_codec.c | 950 +++++++++++++++++++++++++ usr.sbin/bhyve/hda_reg.h | 1367 ++++++++++++++++++++++++++++++++++++ usr.sbin/bhyve/hdac_reg.h | 269 +++++++ usr.sbin/bhyve/pci_hda.c | 1330 +++++++++++++++++++++++++++++++++++ usr.sbin/bhyve/pci_hda.h | 90 +++ 8 files changed, 4377 insertions(+) create mode 100644 usr.sbin/bhyve/audio.c create mode 100644 usr.sbin/bhyve/audio.h create mode 100644 usr.sbin/bhyve/hda_codec.c create mode 100644 usr.sbin/bhyve/hda_reg.h create mode 100644 usr.sbin/bhyve/hdac_reg.h create mode 100644 usr.sbin/bhyve/pci_hda.c create mode 100644 usr.sbin/bhyve/pci_hda.h diff --git a/usr.sbin/bhyve/Makefile b/usr.sbin/bhyve/Makefile index 85fdf11928b1..e203a57c18a3 100644 --- a/usr.sbin/bhyve/Makefile +++ b/usr.sbin/bhyve/Makefile @@ -16,6 +16,7 @@ BHYVE_SYSDIR?=${SRCTOP} SRCS= \ atkbdc.c \ acpi.c \ + audio.c \ bhyvegc.c \ bhyverun.c \ block_if.c \ @@ -27,6 +28,7 @@ SRCS= \ dbgport.c \ fwctl.c \ gdb.c \ + hda_codec.c \ inout.c \ ioapic.c \ mem.c \ @@ -36,6 +38,7 @@ SRCS= \ pci_ahci.c \ pci_e82545.c \ pci_emul.c \ + pci_hda.c \ pci_fbuf.c \ pci_hostbridge.c \ pci_irq.c \ diff --git a/usr.sbin/bhyve/audio.c b/usr.sbin/bhyve/audio.c new file mode 100644 index 000000000000..6a288cbded63 --- /dev/null +++ b/usr.sbin/bhyve/audio.c @@ -0,0 +1,282 @@ +/*- + * Copyright (c) 2016 Alex Teaca + * 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, 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 OR CONTRIBUTORS 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$"); + +#ifndef WITHOUT_CAPSICUM +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "audio.h" +#include "pci_hda.h" + +/* + * Audio Player internal data structures + */ + +struct audio { + int fd; + uint8_t dir; + uint8_t inited; + char dev_name[64]; +}; + +/* + * Audio Player module function definitions + */ + +/* + * audio_init - initialize an instance of audio player + * @dev_name - the backend sound device used to play / capture + * @dir - dir = 1 for write mode, dir = 0 for read mode + */ +struct audio * +audio_init(const char *dev_name, uint8_t dir) +{ + struct audio *aud = NULL; +#ifndef WITHOUT_CAPSICUM + cap_rights_t rights; + cap_ioctl_t cmds[] = { + SNDCTL_DSP_RESET, SNDCTL_DSP_SETFMT, SNDCTL_DSP_CHANNELS, + SNDCTL_DSP_SPEED, +#ifdef DEBUG_HDA + SNDCTL_DSP_GETOSPACE, SNDCTL_DSP_GETISPACE, +#endif + }; +#endif + + assert(dev_name); + + aud = calloc(1, sizeof(*aud)); + if (!aud) + return NULL; + + if (strlen(dev_name) < sizeof(aud->dev_name)) + memcpy(aud->dev_name, dev_name, strlen(dev_name) + 1); + else { + DPRINTF("dev_name too big\n"); + free(aud); + return NULL; + } + + aud->dir = dir; + + aud->fd = open(aud->dev_name, aud->dir ? O_WRONLY : O_RDONLY, 0); + if (aud->fd == -1) { + DPRINTF("Failed to open dev: %s, errno: %d\n", + aud->dev_name, errno); + return (NULL); + } + +#ifndef WITHOUT_CAPSICUM + cap_rights_init(&rights, CAP_IOCTL, CAP_READ, CAP_WRITE); + if (caph_rights_limit(aud->fd, &rights) == -1) + errx(EX_OSERR, "Unable to apply rights for sandbox"); + if (caph_ioctls_limit(aud->fd, cmds, nitems(cmds)) == -1) + errx(EX_OSERR, "Unable to limit ioctl rights for sandbox"); +#endif + + return aud; +} + +/* + * audio_set_params - reset the sound device and set the audio params + * @aud - the audio player to be configured + * @params - the audio parameters to be set + */ +int +audio_set_params(struct audio *aud, struct audio_params *params) +{ + int audio_fd; + int format, channels, rate; + int err; +#if DEBUG_HDA == 1 + audio_buf_info info; +#endif + + assert(aud); + assert(params); + + if ((audio_fd = aud->fd) < 0) { + DPRINTF("Incorrect audio device descriptor for %s\n", + aud->dev_name); + return (-1); + } + + /* Reset the device if it was previously opened */ + if (aud->inited) { + err = ioctl(audio_fd, SNDCTL_DSP_RESET, NULL); + if (err == -1) { + DPRINTF("Failed to reset fd: %d, errno: %d\n", + aud->fd, errno); + return (-1); + } + } else + aud->inited = 1; + + /* Set the Format (Bits per Sample) */ + format = params->format; + err = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format); + if (err == -1) { + DPRINTF("Fail to set fmt: 0x%x errno: %d\n", + params->format, errno); + return -1; + } + + /* The device does not support the requested audio format */ + if (format != params->format) { + DPRINTF("Mismatch format: 0x%x params->format: 0x%x\n", + format, params->format); + return -1; + } + + /* Set the Number of Channels */ + channels = params->channels; + err = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &channels); + if (err == -1) { + DPRINTF("Fail to set channels: %d errno: %d\n", + params->channels, errno); + return -1; + } + + /* The device does not support the requested no. of channels */ + if (channels != params->channels) { + DPRINTF("Mismatch channels: %d params->channels: %d\n", + channels, params->channels); + return -1; + } + + /* Set the Sample Rate / Speed */ + rate = params->rate; + err = ioctl(audio_fd, SNDCTL_DSP_SPEED, &rate); + if (err == -1) { + DPRINTF("Fail to set speed: %d errno: %d\n", + params->rate, errno); + return -1; + } + + /* The device does not support the requested rate / speed */ + if (rate != params->rate) { + DPRINTF("Mismatch rate: %d params->rate: %d\n", + rate, params->rate); + return -1; + } + +#if DEBUG_HDA == 1 + err = ioctl(audio_fd, aud->dir ? SNDCTL_DSP_GETOSPACE : + SNDCTL_DSP_GETISPACE, &info); + if (err == -1) { + DPRINTF("Fail to get audio buf info errno: %d\n", errno); + return -1; + } + DPRINTF("fragstotal: 0x%x fragsize: 0x%x\n", + info.fragstotal, info.fragsize); +#endif + return 0; +} + +/* + * audio_playback - plays samples to the sound device using blocking operations + * @aud - the audio player used to play the samples + * @buf - the buffer containing the samples + * @count - the number of bytes in buffer + */ +int +audio_playback(struct audio *aud, const void *buf, size_t count) +{ + int audio_fd = -1; + ssize_t len = 0, total = 0; + + assert(aud); + assert(aud->dir); + assert(buf); + + audio_fd = aud->fd; + assert(audio_fd != -1); + + total = 0; + while (total < count) { + len = write(audio_fd, buf + total, count - total); + if (len == -1) { + DPRINTF("Fail to write to fd: %d, errno: %d\n", + audio_fd, errno); + return -1; + } + + total += len; + } + + return 0; +} + +/* + * audio_record - records samples from the sound device using + * blocking operations. + * @aud - the audio player used to capture the samples + * @buf - the buffer to receive the samples + * @count - the number of bytes to capture in buffer + * Returns -1 on error and 0 on success + */ +int +audio_record(struct audio *aud, void *buf, size_t count) +{ + int audio_fd = -1; + ssize_t len = 0, total = 0; + + assert(aud); + assert(!aud->dir); + assert(buf); + + audio_fd = aud->fd; + assert(audio_fd != -1); + + total = 0; + while (total < count) { + len = read(audio_fd, buf + total, count - total); + if (len == -1) { + DPRINTF("Fail to write to fd: %d, errno: %d\n", + audio_fd, errno); + return -1; + } + + total += len; + } + + return 0; +} diff --git a/usr.sbin/bhyve/audio.h b/usr.sbin/bhyve/audio.h new file mode 100644 index 000000000000..01ef17071b14 --- /dev/null +++ b/usr.sbin/bhyve/audio.h @@ -0,0 +1,86 @@ +/*- + * Copyright (c) 2016 Alex Teaca + * 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, 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 OR CONTRIBUTORS 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$ + */ + +#ifndef _AUDIO_EMUL_H_ +#define _AUDIO_EMUL_H_ + +#include +#include + +/* + * Audio Player data structures + */ + +struct audio; + +struct audio_params { + int channels; + int format; + int rate; +}; + +/* + * Audio Player API + */ + +/* + * audio_init - initialize an instance of audio player + * @dev_name - the backend sound device used to play / capture + * @dir - dir = 1 for write mode, dir = 0 for read mode + * Returns NULL on error and the address of the audio player instance + */ +struct audio *audio_init(const char *dev_name, uint8_t dir); + +/* + * audio_set_params - reset the sound device and set the audio params + * @aud - the audio player to be configured + * @params - the audio parameters to be set + * Returns -1 on error and 0 on success + */ +int audio_set_params(struct audio *aud, struct audio_params *params); + +/* + * audio_playback - plays samples to the sound device using blocking operations + * @aud - the audio player used to play the samples + * @buf - the buffer containing the samples + * @count - the number of bytes in buffer + * Returns -1 on error and 0 on success + */ +int audio_playback(struct audio *aud, const void *buf, size_t count); + +/* + * audio_record - records samples from the sound device using blocking + * operations. + * @aud - the audio player used to capture the samples + * @buf - the buffer to receive the samples + * @count - the number of bytes to capture in buffer + * Returns -1 on error and 0 on success + */ +int audio_record(struct audio *aud, void *buf, size_t count); + +#endif /* _AUDIO_EMUL_H_ */ diff --git a/usr.sbin/bhyve/hda_codec.c b/usr.sbin/bhyve/hda_codec.c new file mode 100644 index 000000000000..ab53eb036e9f --- /dev/null +++ b/usr.sbin/bhyve/hda_codec.c @@ -0,0 +1,950 @@ +/*- + * Copyright (c) 2016 Alex Teaca + * 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, 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 OR CONTRIBUTORS 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 +#include +#include + +#include "pci_hda.h" +#include "audio.h" + +/* + * HDA Codec defines + */ +#define INTEL_VENDORID 0x8086 + +#define HDA_CODEC_SUBSYSTEM_ID ((INTEL_VENDORID << 16) | 0x01) +#define HDA_CODEC_ROOT_NID 0x00 +#define HDA_CODEC_FG_NID 0x01 +#define HDA_CODEC_AUDIO_OUTPUT_NID 0x02 +#define HDA_CODEC_PIN_OUTPUT_NID 0x03 +#define HDA_CODEC_AUDIO_INPUT_NID 0x04 +#define HDA_CODEC_PIN_INPUT_NID 0x05 + +#define HDA_CODEC_STREAMS_COUNT 0x02 +#define HDA_CODEC_STREAM_OUTPUT 0x00 +#define HDA_CODEC_STREAM_INPUT 0x01 + +#define HDA_CODEC_PARAMS_COUNT 0x14 +#define HDA_CODEC_CONN_LIST_COUNT 0x01 +#define HDA_CODEC_RESPONSE_EX_UNSOL 0x10 +#define HDA_CODEC_RESPONSE_EX_SOL 0x00 +#define HDA_CODEC_AMP_NUMSTEPS 0x4a + +#define HDA_CODEC_SUPP_STREAM_FORMATS_PCM \ + (1 << HDA_PARAM_SUPP_STREAM_FORMATS_PCM_SHIFT) + +#define HDA_CODEC_FMT_BASE_MASK (0x01 << 14) + +#define HDA_CODEC_FMT_MULT_MASK (0x07 << 11) +#define HDA_CODEC_FMT_MULT_2 (0x01 << 11) +#define HDA_CODEC_FMT_MULT_3 (0x02 << 11) +#define HDA_CODEC_FMT_MULT_4 (0x03 << 11) + +#define HDA_CODEC_FMT_DIV_MASK 0x07 +#define HDA_CODEC_FMT_DIV_SHIFT 8 + +#define HDA_CODEC_FMT_BITS_MASK (0x07 << 4) +#define HDA_CODEC_FMT_BITS_8 (0x00 << 4) +#define HDA_CODEC_FMT_BITS_16 (0x01 << 4) +#define HDA_CODEC_FMT_BITS_24 (0x03 << 4) +#define HDA_CODEC_FMT_BITS_32 (0x04 << 4) + +#define HDA_CODEC_FMT_CHAN_MASK (0x0f << 0) + +#define HDA_CODEC_AUDIO_WCAP_OUTPUT \ + (0x00 << HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT) +#define HDA_CODEC_AUDIO_WCAP_INPUT \ + (0x01 << HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT) +#define HDA_CODEC_AUDIO_WCAP_PIN \ + (0x04 << HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT) +#define HDA_CODEC_AUDIO_WCAP_CONN_LIST \ + (1 << HDA_PARAM_AUDIO_WIDGET_CAP_CONN_LIST_SHIFT) +#define HDA_CODEC_AUDIO_WCAP_FORMAT_OVR \ + (1 << HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR_SHIFT) +#define HDA_CODEC_AUDIO_WCAP_AMP_OVR \ + (1 << HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR_SHIFT) +#define HDA_CODEC_AUDIO_WCAP_OUT_AMP \ + (1 << HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP_SHIFT) +#define HDA_CODEC_AUDIO_WCAP_IN_AMP \ + (1 << HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP_SHIFT) +#define HDA_CODEC_AUDIO_WCAP_STEREO \ + (1 << HDA_PARAM_AUDIO_WIDGET_CAP_STEREO_SHIFT) + +#define HDA_CODEC_PIN_CAP_OUTPUT \ + (1 << HDA_PARAM_PIN_CAP_OUTPUT_CAP_SHIFT) +#define HDA_CODEC_PIN_CAP_INPUT \ + (1 << HDA_PARAM_PIN_CAP_INPUT_CAP_SHIFT) +#define HDA_CODEC_PIN_CAP_PRESENCE_DETECT \ + (1 << HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP_SHIFT) + +#define HDA_CODEC_OUTPUT_AMP_CAP_MUTE_CAP \ + (1 << HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP_SHIFT) +#define HDA_CODEC_OUTPUT_AMP_CAP_STEPSIZE \ + (0x03 << HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_SHIFT) +#define HDA_CODEC_OUTPUT_AMP_CAP_NUMSTEPS \ + (HDA_CODEC_AMP_NUMSTEPS << HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_SHIFT) +#define HDA_CODEC_OUTPUT_AMP_CAP_OFFSET \ + (HDA_CODEC_AMP_NUMSTEPS << HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_SHIFT) + +#define HDA_CODEC_SET_AMP_GAIN_MUTE_MUTE 0x80 +#define HDA_CODEC_SET_AMP_GAIN_MUTE_GAIN_MASK 0x7f + +#define HDA_CODEC_PIN_SENSE_PRESENCE_PLUGGED (1 << 31) +#define HDA_CODEC_PIN_WIDGET_CTRL_OUT_ENABLE \ + (1 << HDA_CMD_GET_PIN_WIDGET_CTRL_OUT_ENABLE_SHIFT) +#define HDA_CODEC_PIN_WIDGET_CTRL_IN_ENABLE \ + (1 << HDA_CMD_GET_PIN_WIDGET_CTRL_IN_ENABLE_SHIFT) + +#define HDA_CONFIG_DEFAULTCONF_COLOR_BLACK \ + (0x01 << HDA_CONFIG_DEFAULTCONF_COLOR_SHIFT) +#define HDA_CONFIG_DEFAULTCONF_COLOR_RED \ + (0x05 << HDA_CONFIG_DEFAULTCONF_COLOR_SHIFT) + +#define HDA_CODEC_BUF_SIZE HDA_FIFO_SIZE + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + + +/* + * HDA Audio Context data structures + */ + +typedef void (*transfer_func_t)(void *arg); +typedef int (*setup_func_t)(void *arg); + +struct hda_audio_ctxt { + char name[64]; + uint8_t run; + uint8_t started; + void *priv; + pthread_t tid; + pthread_mutex_t mtx; + pthread_cond_t cond; + setup_func_t do_setup; + transfer_func_t do_transfer; +}; + +/* + * HDA Audio Context module function declarations + */ + +static void *hda_audio_ctxt_thr(void *arg); +static int hda_audio_ctxt_init(struct hda_audio_ctxt *actx, const char *tname, + transfer_func_t do_transfer, setup_func_t do_setup, void *priv); +static int hda_audio_ctxt_start(struct hda_audio_ctxt *actx); +static int hda_audio_ctxt_stop(struct hda_audio_ctxt *actx); + +/* + * HDA Codec data structures + */ + +struct hda_codec_softc; + +typedef uint32_t (*verb_func_t)(struct hda_codec_softc *sc, uint16_t verb, + uint16_t payload); + +struct hda_codec_stream { + uint8_t buf[HDA_CODEC_BUF_SIZE]; + uint8_t channel; + uint16_t fmt; + uint8_t stream; + + uint8_t left_gain; + uint8_t right_gain; + uint8_t left_mute; + uint8_t right_mute; + + struct audio *aud; + struct hda_audio_ctxt actx; +}; + +struct hda_codec_softc { + uint32_t no_nodes; + uint32_t subsystem_id; + const uint32_t (*get_parameters)[HDA_CODEC_PARAMS_COUNT]; + const uint8_t (*conn_list)[HDA_CODEC_CONN_LIST_COUNT]; + const uint32_t *conf_default; + const uint8_t *pin_ctrl_default; + const verb_func_t *verb_handlers; + + struct hda_codec_inst *hci; + struct hda_codec_stream streams[HDA_CODEC_STREAMS_COUNT]; +}; + +/* + * HDA Codec module function declarations + */ +static int hda_codec_init(struct hda_codec_inst *hci, const char *play, + const char *rec, const char *opts); +static int hda_codec_reset(struct hda_codec_inst *hci); +static int hda_codec_command(struct hda_codec_inst *hci, uint32_t cmd_data); +static int hda_codec_notify(struct hda_codec_inst *hci, uint8_t run, + uint8_t stream, uint8_t dir); + +static int hda_codec_parse_format(uint16_t fmt, struct audio_params *params); + +static uint32_t hda_codec_audio_output_nid(struct hda_codec_softc *sc, + uint16_t verb, uint16_t payload); +static void hda_codec_audio_output_do_transfer(void *arg); +static int hda_codec_audio_output_do_setup(void *arg); +static uint32_t hda_codec_audio_input_nid(struct hda_codec_softc *sc, + uint16_t verb, uint16_t payload); +static void hda_codec_audio_input_do_transfer(void *arg); +static int hda_codec_audio_input_do_setup(void *arg); + +static uint32_t hda_codec_audio_inout_nid(struct hda_codec_stream *st, + uint16_t verb, uint16_t payload); + +/* + * HDA Codec global data + */ + +#define HDA_CODEC_ROOT_DESC \ + [HDA_CODEC_ROOT_NID] = { \ + [HDA_PARAM_VENDOR_ID] = INTEL_VENDORID, \ + [HDA_PARAM_REVISION_ID] = 0xffff, \ + /* 1 Subnode, StartNid = 1 */ \ + [HDA_PARAM_SUB_NODE_COUNT] = 0x00010001, \ + }, \ + +#define HDA_CODEC_FG_COMMON_DESC \ + [HDA_PARAM_FCT_GRP_TYPE] = HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO,\ + /* B8 - B32, 8.0 - 192.0kHz */ \ + [HDA_PARAM_SUPP_PCM_SIZE_RATE] = (0x1f << 16) | 0x7ff, \ + [HDA_PARAM_SUPP_STREAM_FORMATS] = HDA_CODEC_SUPP_STREAM_FORMATS_PCM,\ + [HDA_PARAM_INPUT_AMP_CAP] = 0x00, /* None */ \ + [HDA_PARAM_OUTPUT_AMP_CAP] = 0x00, /* None */ \ + [HDA_PARAM_GPIO_COUNT] = 0x00, \ + +#define HDA_CODEC_FG_OUTPUT_DESC \ + [HDA_CODEC_FG_NID] = { \ + /* 2 Subnodes, StartNid = 2 */ \ + [HDA_PARAM_SUB_NODE_COUNT] = 0x00020002, \ + HDA_CODEC_FG_COMMON_DESC \ + }, \ + +#define HDA_CODEC_FG_INPUT_DESC \ + [HDA_CODEC_FG_NID] = { \ + /* 2 Subnodes, StartNid = 4 */ \ + [HDA_PARAM_SUB_NODE_COUNT] = 0x00040002, \ + HDA_CODEC_FG_COMMON_DESC \ + }, \ + +#define HDA_CODEC_FG_DUPLEX_DESC \ + [HDA_CODEC_FG_NID] = { \ + /* 4 Subnodes, StartNid = 2 */ \ + [HDA_PARAM_SUB_NODE_COUNT] = 0x00020004, \ + HDA_CODEC_FG_COMMON_DESC \ + }, \ + +#define HDA_CODEC_OUTPUT_DESC \ + [HDA_CODEC_AUDIO_OUTPUT_NID] = { \ + [HDA_PARAM_AUDIO_WIDGET_CAP] = \ + HDA_CODEC_AUDIO_WCAP_OUTPUT | \ + HDA_CODEC_AUDIO_WCAP_FORMAT_OVR | \ + HDA_CODEC_AUDIO_WCAP_AMP_OVR | \ + HDA_CODEC_AUDIO_WCAP_OUT_AMP | \ + HDA_CODEC_AUDIO_WCAP_STEREO, \ + /* B16, 16.0 - 192.0kHz */ \ + [HDA_PARAM_SUPP_PCM_SIZE_RATE] = (0x02 << 16) | 0x7fc, \ + [HDA_PARAM_SUPP_STREAM_FORMATS] = \ + HDA_CODEC_SUPP_STREAM_FORMATS_PCM, \ + [HDA_PARAM_INPUT_AMP_CAP] = 0x00, /* None */ \ + [HDA_PARAM_CONN_LIST_LENGTH] = 0x00, \ + [HDA_PARAM_OUTPUT_AMP_CAP] = \ + HDA_CODEC_OUTPUT_AMP_CAP_MUTE_CAP | \ + HDA_CODEC_OUTPUT_AMP_CAP_STEPSIZE | \ + HDA_CODEC_OUTPUT_AMP_CAP_NUMSTEPS | \ + HDA_CODEC_OUTPUT_AMP_CAP_OFFSET, \ + }, \ + [HDA_CODEC_PIN_OUTPUT_NID] = { \ + [HDA_PARAM_AUDIO_WIDGET_CAP] = \ + HDA_CODEC_AUDIO_WCAP_PIN | \ + HDA_CODEC_AUDIO_WCAP_CONN_LIST | \ + HDA_CODEC_AUDIO_WCAP_STEREO, \ + [HDA_PARAM_PIN_CAP] = HDA_CODEC_PIN_CAP_OUTPUT | \ + HDA_CODEC_PIN_CAP_PRESENCE_DETECT,\ + [HDA_PARAM_INPUT_AMP_CAP] = 0x00, /* None */ \ + [HDA_PARAM_CONN_LIST_LENGTH] = 0x01, \ + [HDA_PARAM_OUTPUT_AMP_CAP] = 0x00, /* None */ \ + }, \ + +#define HDA_CODEC_INPUT_DESC \ + [HDA_CODEC_AUDIO_INPUT_NID] = { \ + [HDA_PARAM_AUDIO_WIDGET_CAP] = \ + HDA_CODEC_AUDIO_WCAP_INPUT | \ + HDA_CODEC_AUDIO_WCAP_CONN_LIST | \ + HDA_CODEC_AUDIO_WCAP_FORMAT_OVR | \ + HDA_CODEC_AUDIO_WCAP_AMP_OVR | \ + HDA_CODEC_AUDIO_WCAP_IN_AMP | \ + HDA_CODEC_AUDIO_WCAP_STEREO, \ + /* B16, 16.0 - 192.0kHz */ \ + [HDA_PARAM_SUPP_PCM_SIZE_RATE] = (0x02 << 16) | 0x7fc, \ + [HDA_PARAM_SUPP_STREAM_FORMATS] = \ + HDA_CODEC_SUPP_STREAM_FORMATS_PCM, \ + [HDA_PARAM_OUTPUT_AMP_CAP] = 0x00, /* None */ \ + [HDA_PARAM_CONN_LIST_LENGTH] = 0x01, \ + [HDA_PARAM_INPUT_AMP_CAP] = \ + HDA_CODEC_OUTPUT_AMP_CAP_MUTE_CAP | \ + HDA_CODEC_OUTPUT_AMP_CAP_STEPSIZE | \ + HDA_CODEC_OUTPUT_AMP_CAP_NUMSTEPS | \ + HDA_CODEC_OUTPUT_AMP_CAP_OFFSET, \ + }, \ + [HDA_CODEC_PIN_INPUT_NID] = { \ + [HDA_PARAM_AUDIO_WIDGET_CAP] = \ + HDA_CODEC_AUDIO_WCAP_PIN | \ + HDA_CODEC_AUDIO_WCAP_STEREO, \ + [HDA_PARAM_PIN_CAP] = HDA_CODEC_PIN_CAP_INPUT | \ + HDA_CODEC_PIN_CAP_PRESENCE_DETECT, \ + [HDA_PARAM_INPUT_AMP_CAP] = 0x00, /* None */ \ + [HDA_PARAM_OUTPUT_AMP_CAP] = 0x00, /* None */ \ + }, \ + +static const uint32_t +hda_codec_output_parameters[][HDA_CODEC_PARAMS_COUNT] = { + HDA_CODEC_ROOT_DESC + HDA_CODEC_FG_OUTPUT_DESC + HDA_CODEC_OUTPUT_DESC +}; + +static const uint32_t +hda_codec_input_parameters[][HDA_CODEC_PARAMS_COUNT] = { + HDA_CODEC_ROOT_DESC + HDA_CODEC_FG_INPUT_DESC + HDA_CODEC_INPUT_DESC +}; + +static const uint32_t +hda_codec_duplex_parameters[][HDA_CODEC_PARAMS_COUNT] = { + HDA_CODEC_ROOT_DESC + HDA_CODEC_FG_DUPLEX_DESC + HDA_CODEC_OUTPUT_DESC + HDA_CODEC_INPUT_DESC +}; + +#define HDA_CODEC_NODES_COUNT (ARRAY_SIZE(hda_codec_duplex_parameters)) + +static const uint8_t +hda_codec_conn_list[HDA_CODEC_NODES_COUNT][HDA_CODEC_CONN_LIST_COUNT] = { + [HDA_CODEC_PIN_OUTPUT_NID] = {HDA_CODEC_AUDIO_OUTPUT_NID}, + [HDA_CODEC_AUDIO_INPUT_NID] = {HDA_CODEC_PIN_INPUT_NID}, +}; + +static const uint32_t +hda_codec_conf_default[HDA_CODEC_NODES_COUNT] = { + [HDA_CODEC_PIN_OUTPUT_NID] = \ + HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK | + HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT | + HDA_CONFIG_DEFAULTCONF_COLOR_BLACK | + (0x01 << HDA_CONFIG_DEFAULTCONF_ASSOCIATION_SHIFT), + [HDA_CODEC_PIN_INPUT_NID] = HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK | + HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN | + HDA_CONFIG_DEFAULTCONF_COLOR_RED | + (0x02 << HDA_CONFIG_DEFAULTCONF_ASSOCIATION_SHIFT), +}; + +static const uint8_t +hda_codec_pin_ctrl_default[HDA_CODEC_NODES_COUNT] = { + [HDA_CODEC_PIN_OUTPUT_NID] = HDA_CODEC_PIN_WIDGET_CTRL_OUT_ENABLE, + [HDA_CODEC_PIN_INPUT_NID] = HDA_CODEC_PIN_WIDGET_CTRL_IN_ENABLE, +}; + +static const +verb_func_t hda_codec_verb_handlers[HDA_CODEC_NODES_COUNT] = { + [HDA_CODEC_AUDIO_OUTPUT_NID] = hda_codec_audio_output_nid, + [HDA_CODEC_AUDIO_INPUT_NID] = hda_codec_audio_input_nid, +}; + +/* + * HDA Codec module function definitions + */ + +static int +hda_codec_init(struct hda_codec_inst *hci, const char *play, + const char *rec, const char *opts) +{ + struct hda_codec_softc *sc = NULL; + struct hda_codec_stream *st = NULL; + int err; + + if (!(play || rec)) + return (-1); + + DPRINTF("cad: 0x%x opts: %s\n", hci->cad, opts); + + sc = calloc(1, sizeof(*sc)); + if (!sc) + return (-1); + + if (play && rec) + sc->get_parameters = hda_codec_duplex_parameters; + else { + if (play) + sc->get_parameters = hda_codec_output_parameters; + else + sc->get_parameters = hda_codec_input_parameters; + } + sc->subsystem_id = HDA_CODEC_SUBSYSTEM_ID; + sc->no_nodes = HDA_CODEC_NODES_COUNT; + sc->conn_list = hda_codec_conn_list; + sc->conf_default = hda_codec_conf_default; + sc->pin_ctrl_default = hda_codec_pin_ctrl_default; + sc->verb_handlers = hda_codec_verb_handlers; + DPRINTF("HDA Codec nodes: %d\n", sc->no_nodes); + + /* + * Initialize the Audio Output stream + */ + if (play) { + st = &sc->streams[HDA_CODEC_STREAM_OUTPUT]; + + err = hda_audio_ctxt_init(&st->actx, "hda-audio-output", + hda_codec_audio_output_do_transfer, + hda_codec_audio_output_do_setup, sc); + assert(!err); + + st->aud = audio_init(play, 1); + if (!st->aud) { + DPRINTF("Fail to init the output audio player\n"); + return (-1); + } + } + + /* + * Initialize the Audio Input stream + */ + if (rec) { + st = &sc->streams[HDA_CODEC_STREAM_INPUT]; + + err = hda_audio_ctxt_init(&st->actx, "hda-audio-input", + hda_codec_audio_input_do_transfer, + hda_codec_audio_input_do_setup, sc); + assert(!err); + + st->aud = audio_init(rec, 0); + if (!st->aud) { + DPRINTF("Fail to init the input audio player\n"); + return (-1); + } + } + + sc->hci = hci; + hci->priv = sc; + + return (0); +} + +static int +hda_codec_reset(struct hda_codec_inst *hci) +{ + struct hda_ops *hops = NULL; + struct hda_codec_softc *sc = NULL; + struct hda_codec_stream *st = NULL; + int i; + + assert(hci); + + hops = hci->hops; + assert(hops); + + sc = (struct hda_codec_softc *)hci->priv; + assert(sc); + + for (i = 0; i < HDA_CODEC_STREAMS_COUNT; i++) { + st = &sc->streams[i]; + st->left_gain = HDA_CODEC_AMP_NUMSTEPS; + st->right_gain = HDA_CODEC_AMP_NUMSTEPS; + st->left_mute = HDA_CODEC_SET_AMP_GAIN_MUTE_MUTE; + st->right_mute = HDA_CODEC_SET_AMP_GAIN_MUTE_MUTE; + } + + DPRINTF("cad: 0x%x\n", hci->cad); + + if (!hops->signal) { + DPRINTF("The controller ops does not implement \ + the signal function\n"); + return (-1); + } + + return (hops->signal(hci)); +} + +static int +hda_codec_command(struct hda_codec_inst *hci, uint32_t cmd_data) +{ + struct hda_codec_softc *sc = NULL; + struct hda_ops *hops = NULL; + uint8_t cad = 0, nid = 0; + uint16_t verb = 0, payload = 0; + uint32_t res = 0; + + /* 4 bits */ + cad = (cmd_data >> HDA_CMD_CAD_SHIFT) & 0x0f; + /* 8 bits */ + nid = (cmd_data >> HDA_CMD_NID_SHIFT) & 0xff; + + if ((cmd_data & 0x70000) == 0x70000) { + /* 12 bits */ + verb = (cmd_data >> HDA_CMD_VERB_12BIT_SHIFT) & 0x0fff; + /* 8 bits */ + payload = cmd_data & 0xff; + } else { + /* 4 bits */ + verb = (cmd_data >> HDA_CMD_VERB_4BIT_SHIFT) & 0x0f; + /* 16 bits */ + payload = cmd_data & 0xffff; + } + + assert(cad == hci->cad); + assert(hci); + + hops = hci->hops; + assert(hops); + + sc = (struct hda_codec_softc *)hci->priv; + assert(sc); + + assert(nid < sc->no_nodes); + + if (!hops->response) { + DPRINTF("The controller ops does not implement \ + the response function\n"); + return (-1); + } + + switch (verb) { + case HDA_CMD_VERB_GET_PARAMETER: + res = sc->get_parameters[nid][payload]; + break; + case HDA_CMD_VERB_GET_CONN_LIST_ENTRY: + res = sc->conn_list[nid][0]; + break; + case HDA_CMD_VERB_GET_PIN_WIDGET_CTRL: + res = sc->pin_ctrl_default[nid]; + break; + case HDA_CMD_VERB_GET_PIN_SENSE: + res = HDA_CODEC_PIN_SENSE_PRESENCE_PLUGGED; + break; + case HDA_CMD_VERB_GET_CONFIGURATION_DEFAULT: + res = sc->conf_default[nid]; + break; + case HDA_CMD_VERB_GET_SUBSYSTEM_ID: + res = sc->subsystem_id; + break; + default: + assert(sc->verb_handlers); + if (sc->verb_handlers[nid]) + res = sc->verb_handlers[nid](sc, verb, payload); + else + DPRINTF("Unknown VERB: 0x%x\n", verb); + break; + } + + DPRINTF("cad: 0x%x nid: 0x%x verb: 0x%x payload: 0x%x response: 0x%x\n", + cad, nid, verb, payload, res); + + return (hops->response(hci, res, HDA_CODEC_RESPONSE_EX_SOL)); +} + +static int +hda_codec_notify(struct hda_codec_inst *hci, uint8_t run, + uint8_t stream, uint8_t dir) +{ + struct hda_codec_softc *sc = NULL; + struct hda_codec_stream *st = NULL; + struct hda_audio_ctxt *actx = NULL; + int i; + int err; + + assert(hci); + assert(stream); + + sc = (struct hda_codec_softc *)hci->priv; + assert(sc); + + i = dir ? HDA_CODEC_STREAM_OUTPUT : HDA_CODEC_STREAM_INPUT; + st = &sc->streams[i]; + + DPRINTF("run: %d, stream: 0x%x, st->stream: 0x%x dir: %d\n", + run, stream, st->stream, dir); + + if (stream != st->stream) { + DPRINTF("Stream not found\n"); + return (0); + } + + actx = &st->actx; + + if (run) + err = hda_audio_ctxt_start(actx); + else + err = hda_audio_ctxt_stop(actx); + + return (err); +} + +static int +hda_codec_parse_format(uint16_t fmt, struct audio_params *params) +{ + uint8_t div = 0; + + assert(params); + + /* Compute the Sample Rate */ + params->rate = (fmt & HDA_CODEC_FMT_BASE_MASK) ? 44100 : 48000; + + switch (fmt & HDA_CODEC_FMT_MULT_MASK) { + case HDA_CODEC_FMT_MULT_2: + params->rate *= 2; + break; + case HDA_CODEC_FMT_MULT_3: + params->rate *= 3; + break; + case HDA_CODEC_FMT_MULT_4: + params->rate *= 4; + break; + } + + div = (fmt >> HDA_CODEC_FMT_DIV_SHIFT) & HDA_CODEC_FMT_DIV_MASK; + params->rate /= (div + 1); + + /* Compute the Bits per Sample */ + switch (fmt & HDA_CODEC_FMT_BITS_MASK) { + case HDA_CODEC_FMT_BITS_8: + params->format = AFMT_U8; + break; + case HDA_CODEC_FMT_BITS_16: + params->format = AFMT_S16_LE; + break; + case HDA_CODEC_FMT_BITS_24: + params->format = AFMT_S24_LE; + break; + case HDA_CODEC_FMT_BITS_32: + params->format = AFMT_S32_LE; + break; + default: + DPRINTF("Unknown format bits: 0x%x\n", + fmt & HDA_CODEC_FMT_BITS_MASK); + return (-1); + } + + /* Compute the Number of Channels */ + params->channels = (fmt & HDA_CODEC_FMT_CHAN_MASK) + 1; + + return (0); +} + +static uint32_t +hda_codec_audio_output_nid(struct hda_codec_softc *sc, uint16_t verb, + uint16_t payload) +{ + struct hda_codec_stream *st = &sc->streams[HDA_CODEC_STREAM_OUTPUT]; + int res; + + res = hda_codec_audio_inout_nid(st, verb, payload); + + return (res); +} + +static void +hda_codec_audio_output_do_transfer(void *arg) +{ + struct hda_codec_softc *sc = (struct hda_codec_softc *)arg; + struct hda_codec_inst *hci = NULL; + struct hda_ops *hops = NULL; + struct hda_codec_stream *st = NULL; + struct audio *aud = NULL; + int err; + + hci = sc->hci; + assert(hci); + + hops = hci->hops; + assert(hops); + + st = &sc->streams[HDA_CODEC_STREAM_OUTPUT]; + aud = st->aud; + + err = hops->transfer(hci, st->stream, 1, st->buf, sizeof(st->buf)); + if (err) + return; + + err = audio_playback(aud, st->buf, sizeof(st->buf)); + assert(!err); +} + +static int +hda_codec_audio_output_do_setup(void *arg) +{ + struct hda_codec_softc *sc = (struct hda_codec_softc *)arg; + struct hda_codec_stream *st = NULL; + struct audio *aud = NULL; + struct audio_params params; + int err; + + st = &sc->streams[HDA_CODEC_STREAM_OUTPUT]; + aud = st->aud; + + err = hda_codec_parse_format(st->fmt, ¶ms); + if (err) + return (-1); + + DPRINTF("rate: %d, channels: %d, format: 0x%x\n", + params.rate, params.channels, params.format); + + return (audio_set_params(aud, ¶ms)); +} + +static uint32_t +hda_codec_audio_input_nid(struct hda_codec_softc *sc, uint16_t verb, + uint16_t payload) +{ + struct hda_codec_stream *st = &sc->streams[HDA_CODEC_STREAM_INPUT]; + int res; + + res = hda_codec_audio_inout_nid(st, verb, payload); + + return (res); +} + +static void +hda_codec_audio_input_do_transfer(void *arg) +{ + struct hda_codec_softc *sc = (struct hda_codec_softc *)arg; + struct hda_codec_inst *hci = NULL; + struct hda_ops *hops = NULL; + struct hda_codec_stream *st = NULL; + struct audio *aud = NULL; + int err; + + hci = sc->hci; + assert(hci); + + hops = hci->hops; + assert(hops); + + st = &sc->streams[HDA_CODEC_STREAM_INPUT]; + aud = st->aud; + + err = audio_record(aud, st->buf, sizeof(st->buf)); + assert(!err); + + hops->transfer(hci, st->stream, 0, st->buf, sizeof(st->buf)); +} + +static int +hda_codec_audio_input_do_setup(void *arg) +{ + struct hda_codec_softc *sc = (struct hda_codec_softc *)arg; + struct hda_codec_stream *st = NULL; + struct audio *aud = NULL; + struct audio_params params; + int err; + + st = &sc->streams[HDA_CODEC_STREAM_INPUT]; + aud = st->aud; + + err = hda_codec_parse_format(st->fmt, ¶ms); + if (err) + return (-1); + + DPRINTF("rate: %d, channels: %d, format: 0x%x\n", + params.rate, params.channels, params.format); + + return (audio_set_params(aud, ¶ms)); +} + +static uint32_t +hda_codec_audio_inout_nid(struct hda_codec_stream *st, uint16_t verb, + uint16_t payload) +{ + uint32_t res = 0; + uint8_t mute = 0; + uint8_t gain = 0; + + DPRINTF("%s verb: 0x%x, payload, 0x%x\n", st->actx.name, verb, payload); + + switch (verb) { + case HDA_CMD_VERB_GET_CONV_FMT: + res = st->fmt; + break; + case HDA_CMD_VERB_SET_CONV_FMT: + st->fmt = payload; + break; + case HDA_CMD_VERB_GET_AMP_GAIN_MUTE: + if (payload & HDA_CMD_GET_AMP_GAIN_MUTE_LEFT) { + res = st->left_gain | st->left_mute; + DPRINTF("GET_AMP_GAIN_MUTE_LEFT: 0x%x\n", res); + } else { + res = st->right_gain | st->right_mute; + DPRINTF("GET_AMP_GAIN_MUTE_RIGHT: 0x%x\n", res); + } + break; + case HDA_CMD_VERB_SET_AMP_GAIN_MUTE: + mute = payload & HDA_CODEC_SET_AMP_GAIN_MUTE_MUTE; + gain = payload & HDA_CODEC_SET_AMP_GAIN_MUTE_GAIN_MASK; + + if (payload & HDA_CMD_SET_AMP_GAIN_MUTE_LEFT) { + st->left_mute = mute; + st->left_gain = gain; + DPRINTF("SET_AMP_GAIN_MUTE_LEFT: \ + mute: 0x%x gain: 0x%x\n", mute, gain); + } + + if (payload & HDA_CMD_SET_AMP_GAIN_MUTE_RIGHT) { + st->right_mute = mute; + st->right_gain = gain; + DPRINTF("SET_AMP_GAIN_MUTE_RIGHT: \ + mute: 0x%x gain: 0x%x\n", mute, gain); + } + break; + case HDA_CMD_VERB_GET_CONV_STREAM_CHAN: + res = (st->stream << 4) | st->channel; + break; + case HDA_CMD_VERB_SET_CONV_STREAM_CHAN: + st->channel = payload & 0x0f; + st->stream = (payload >> 4) & 0x0f; + DPRINTF("st->channel: 0x%x st->stream: 0x%x\n", + st->channel, st->stream); + if (!st->stream) + hda_audio_ctxt_stop(&st->actx); + break; + default: + DPRINTF("Unknown VERB: 0x%x\n", verb); + break; + } + + return (res); +} + +struct hda_codec_class hda_codec = { + .name = "hda_codec", + .init = hda_codec_init, + .reset = hda_codec_reset, + .command = hda_codec_command, + .notify = hda_codec_notify, +}; + +HDA_EMUL_SET(hda_codec); + + +/* + * HDA Audio Context module function definitions + */ + +static void * +hda_audio_ctxt_thr(void *arg) +{ + struct hda_audio_ctxt *actx = arg; + + DPRINTF("Start Thread: %s\n", actx->name); + + pthread_mutex_lock(&actx->mtx); + while (1) { + while (!actx->run) + pthread_cond_wait(&actx->cond, &actx->mtx); + + actx->do_transfer(actx->priv); + } + pthread_mutex_unlock(&actx->mtx); + + pthread_exit(NULL); + return (NULL); +} + +static int +hda_audio_ctxt_init(struct hda_audio_ctxt *actx, const char *tname, + transfer_func_t do_transfer, setup_func_t do_setup, void *priv) +{ + int err; + + assert(actx); + assert(tname); + assert(do_transfer); + assert(do_setup); + assert(priv); + + memset(actx, 0, sizeof(*actx)); + + actx->run = 0; + actx->do_transfer = do_transfer; + actx->do_setup = do_setup; + actx->priv = priv; + if (strlen(tname) < sizeof(actx->name)) + memcpy(actx->name, tname, strlen(tname) + 1); + else + strcpy(actx->name, "unknown"); + + err = pthread_mutex_init(&actx->mtx, NULL); + assert(!err); + + err = pthread_cond_init(&actx->cond, NULL); + assert(!err); + + err = pthread_create(&actx->tid, NULL, hda_audio_ctxt_thr, actx); + assert(!err); + + pthread_set_name_np(actx->tid, tname); + + actx->started = 1; + + return (0); +} + +static int +hda_audio_ctxt_start(struct hda_audio_ctxt *actx) +{ + int err = 0; + + assert(actx); + assert(actx->started); + + /* The stream is supposed to be stopped */ + if (actx->run) + return (-1); + + pthread_mutex_lock(&actx->mtx); + err = (* actx->do_setup)(actx->priv); + if (!err) { + actx->run = 1; + pthread_cond_signal(&actx->cond); + } + pthread_mutex_unlock(&actx->mtx); + + return (err); +} + +static int +hda_audio_ctxt_stop(struct hda_audio_ctxt *actx) +{ + actx->run = 0; + return (0); +} diff --git a/usr.sbin/bhyve/hda_reg.h b/usr.sbin/bhyve/hda_reg.h new file mode 100644 index 000000000000..dd7098524537 --- /dev/null +++ b/usr.sbin/bhyve/hda_reg.h @@ -0,0 +1,1367 @@ +/*- + * Copyright (c) 2006 Stephane E. Potvin + * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$ + */ + +#ifndef _HDA_REG_H_ +#define _HDA_REG_H_ + +/**************************************************************************** + * HDA Device Verbs + ****************************************************************************/ + +/* HDA Command */ +#define HDA_CMD_VERB_MASK 0x000fffff +#define HDA_CMD_VERB_SHIFT 0 +#define HDA_CMD_NID_MASK 0x0ff00000 +#define HDA_CMD_NID_SHIFT 20 +#define HDA_CMD_CAD_MASK 0xf0000000 +#define HDA_CMD_CAD_SHIFT 28 + +#define HDA_CMD_VERB_4BIT_SHIFT 16 +#define HDA_CMD_VERB_12BIT_SHIFT 8 + +#define HDA_CMD_VERB_4BIT(verb, payload) \ + (((verb) << HDA_CMD_VERB_4BIT_SHIFT) | (payload)) +#define HDA_CMD_4BIT(cad, nid, verb, payload) \ + (((cad) << HDA_CMD_CAD_SHIFT) | \ + ((nid) << HDA_CMD_NID_SHIFT) | \ + (HDA_CMD_VERB_4BIT((verb), (payload)))) + +#define HDA_CMD_VERB_12BIT(verb, payload) \ + (((verb) << HDA_CMD_VERB_12BIT_SHIFT) | (payload)) +#define HDA_CMD_12BIT(cad, nid, verb, payload) \ + (((cad) << HDA_CMD_CAD_SHIFT) | \ + ((nid) << HDA_CMD_NID_SHIFT) | \ + (HDA_CMD_VERB_12BIT((verb), (payload)))) + +/* Get Parameter */ +#define HDA_CMD_VERB_GET_PARAMETER 0xf00 + +#define HDA_CMD_GET_PARAMETER(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_PARAMETER, (payload))) + +/* Connection Select Control */ +#define HDA_CMD_VERB_GET_CONN_SELECT_CONTROL 0xf01 +#define HDA_CMD_VERB_SET_CONN_SELECT_CONTROL 0x701 + +#define HDA_CMD_GET_CONN_SELECT_CONTROL(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_CONN_SELECT_CONTROL, 0x0)) +#define HDA_CMD_SET_CONNECTION_SELECT_CONTROL(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_CONN_SELECT_CONTROL, (payload))) + +/* Connection List Entry */ +#define HDA_CMD_VERB_GET_CONN_LIST_ENTRY 0xf02 + +#define HDA_CMD_GET_CONN_LIST_ENTRY(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_CONN_LIST_ENTRY, (payload))) + +#define HDA_CMD_GET_CONN_LIST_ENTRY_SIZE_SHORT 1 +#define HDA_CMD_GET_CONN_LIST_ENTRY_SIZE_LONG 2 + +/* Processing State */ +#define HDA_CMD_VERB_GET_PROCESSING_STATE 0xf03 +#define HDA_CMD_VERB_SET_PROCESSING_STATE 0x703 + +#define HDA_CMD_GET_PROCESSING_STATE(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_PROCESSING_STATE, 0x0)) +#define HDA_CMD_SET_PROCESSING_STATE(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_PROCESSING_STATE, (payload))) + +#define HDA_CMD_GET_PROCESSING_STATE_STATE_OFF 0x00 +#define HDA_CMD_GET_PROCESSING_STATE_STATE_ON 0x01 +#define HDA_CMD_GET_PROCESSING_STATE_STATE_BENIGN 0x02 + +/* Coefficient Index */ +#define HDA_CMD_VERB_GET_COEFF_INDEX 0xd +#define HDA_CMD_VERB_SET_COEFF_INDEX 0x5 + +#define HDA_CMD_GET_COEFF_INDEX(cad, nid) \ + (HDA_CMD_4BIT((cad), (nid), \ + HDA_CMD_VERB_GET_COEFF_INDEX, 0x0)) +#define HDA_CMD_SET_COEFF_INDEX(cad, nid, payload) \ + (HDA_CMD_4BIT((cad), (nid), \ + HDA_CMD_VERB_SET_COEFF_INDEX, (payload))) + +/* Processing Coefficient */ +#define HDA_CMD_VERB_GET_PROCESSING_COEFF 0xc +#define HDA_CMD_VERB_SET_PROCESSING_COEFF 0x4 + +#define HDA_CMD_GET_PROCESSING_COEFF(cad, nid) \ + (HDA_CMD_4BIT((cad), (nid), \ + HDA_CMD_VERB_GET_PROCESSING_COEFF, 0x0)) +#define HDA_CMD_SET_PROCESSING_COEFF(cad, nid, payload) \ + (HDA_CMD_4BIT((cad), (nid), \ + HDA_CMD_VERB_SET_PROCESSING_COEFF, (payload))) + +/* Amplifier Gain/Mute */ +#define HDA_CMD_VERB_GET_AMP_GAIN_MUTE 0xb +#define HDA_CMD_VERB_SET_AMP_GAIN_MUTE 0x3 + +#define HDA_CMD_GET_AMP_GAIN_MUTE(cad, nid, payload) \ + (HDA_CMD_4BIT((cad), (nid), \ + HDA_CMD_VERB_GET_AMP_GAIN_MUTE, (payload))) +#define HDA_CMD_SET_AMP_GAIN_MUTE(cad, nid, payload) \ + (HDA_CMD_4BIT((cad), (nid), \ + HDA_CMD_VERB_SET_AMP_GAIN_MUTE, (payload))) + +#define HDA_CMD_GET_AMP_GAIN_MUTE_INPUT 0x0000 +#define HDA_CMD_GET_AMP_GAIN_MUTE_OUTPUT 0x8000 +#define HDA_CMD_GET_AMP_GAIN_MUTE_RIGHT 0x0000 +#define HDA_CMD_GET_AMP_GAIN_MUTE_LEFT 0x2000 + +#define HDA_CMD_GET_AMP_GAIN_MUTE_MUTE_MASK 0x00000008 +#define HDA_CMD_GET_AMP_GAIN_MUTE_MUTE_SHIFT 7 +#define HDA_CMD_GET_AMP_GAIN_MUTE_GAIN_MASK 0x00000007 +#define HDA_CMD_GET_AMP_GAIN_MUTE_GAIN_SHIFT 0 + +#define HDA_CMD_GET_AMP_GAIN_MUTE_MUTE(rsp) \ + (((rsp) & HDA_CMD_GET_AMP_GAIN_MUTE_MUTE_MASK) >> \ + HDA_CMD_GET_AMP_GAIN_MUTE_MUTE_SHIFT) +#define HDA_CMD_GET_AMP_GAIN_MUTE_GAIN(rsp) \ + (((rsp) & HDA_CMD_GET_AMP_GAIN_MUTE_GAIN_MASK) >> \ + HDA_CMD_GET_AMP_GAIN_MUTE_GAIN_SHIFT) + +#define HDA_CMD_SET_AMP_GAIN_MUTE_OUTPUT 0x8000 +#define HDA_CMD_SET_AMP_GAIN_MUTE_INPUT 0x4000 +#define HDA_CMD_SET_AMP_GAIN_MUTE_LEFT 0x2000 +#define HDA_CMD_SET_AMP_GAIN_MUTE_RIGHT 0x1000 +#define HDA_CMD_SET_AMP_GAIN_MUTE_INDEX_MASK 0x0f00 +#define HDA_CMD_SET_AMP_GAIN_MUTE_INDEX_SHIFT 8 +#define HDA_CMD_SET_AMP_GAIN_MUTE_MUTE 0x0080 +#define HDA_CMD_SET_AMP_GAIN_MUTE_GAIN_MASK 0x0007 +#define HDA_CMD_SET_AMP_GAIN_MUTE_GAIN_SHIFT 0 + +#define HDA_CMD_SET_AMP_GAIN_MUTE_INDEX(index) \ + (((index) << HDA_CMD_SET_AMP_GAIN_MUTE_INDEX_SHIFT) & \ + HDA_CMD_SET_AMP_GAIN_MUTE_INDEX_MASK) +#define HDA_CMD_SET_AMP_GAIN_MUTE_GAIN(index) \ + (((index) << HDA_CMD_SET_AMP_GAIN_MUTE_GAIN_SHIFT) & \ + HDA_CMD_SET_AMP_GAIN_MUTE_GAIN_MASK) + +/* Converter format */ +#define HDA_CMD_VERB_GET_CONV_FMT 0xa +#define HDA_CMD_VERB_SET_CONV_FMT 0x2 + +#define HDA_CMD_GET_CONV_FMT(cad, nid) \ + (HDA_CMD_4BIT((cad), (nid), \ + HDA_CMD_VERB_GET_CONV_FMT, 0x0)) +#define HDA_CMD_SET_CONV_FMT(cad, nid, payload) \ + (HDA_CMD_4BIT((cad), (nid), \ + HDA_CMD_VERB_SET_CONV_FMT, (payload))) + +/* Digital Converter Control */ +#define HDA_CMD_VERB_GET_DIGITAL_CONV_FMT1 0xf0d +#define HDA_CMD_VERB_GET_DIGITAL_CONV_FMT2 0xf0e +#define HDA_CMD_VERB_SET_DIGITAL_CONV_FMT1 0x70d +#define HDA_CMD_VERB_SET_DIGITAL_CONV_FMT2 0x70e + +#define HDA_CMD_GET_DIGITAL_CONV_FMT(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_DIGITAL_CONV_FMT1, 0x0)) +#define HDA_CMD_SET_DIGITAL_CONV_FMT1(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_DIGITAL_CONV_FMT1, (payload))) +#define HDA_CMD_SET_DIGITAL_CONV_FMT2(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_DIGITAL_CONV_FMT2, (payload))) + +#define HDA_CMD_GET_DIGITAL_CONV_FMT_CC_MASK 0x7f00 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_CC_SHIFT 8 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_L_MASK 0x0080 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_L_SHIFT 7 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_PRO_MASK 0x0040 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_PRO_SHIFT 6 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_NAUDIO_MASK 0x0020 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_NAUDIO_SHIFT 5 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_COPY_MASK 0x0010 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_COPY_SHIFT 4 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_PRE_MASK 0x0008 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_PRE_SHIFT 3 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_VCFG_MASK 0x0004 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_VCFG_SHIFT 2 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_V_MASK 0x0002 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_V_SHIFT 1 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_DIGEN_MASK 0x0001 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_DIGEN_SHIFT 0 + +#define HDA_CMD_GET_DIGITAL_CONV_FMT_CC(rsp) \ + (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_CC_MASK) >> \ + HDA_CMD_GET_DIGITAL_CONV_FMT_CC_SHIFT) +#define HDA_CMD_GET_DIGITAL_CONV_FMT_L(rsp) \ + (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_L_MASK) >> \ + HDA_CMD_GET_DIGITAL_CONV_FMT_L_SHIFT) +#define HDA_CMD_GET_DIGITAL_CONV_FMT_PRO(rsp) \ + (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_PRO_MASK) >> \ + HDA_CMD_GET_DIGITAL_CONV_FMT_PRO_SHIFT) +#define HDA_CMD_GET_DIGITAL_CONV_FMT_NAUDIO(rsp) \ + (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_NAUDIO_MASK) >> \ + HDA_CMD_GET_DIGITAL_CONV_FMT_NAUDIO_SHIFT) +#define HDA_CMD_GET_DIGITAL_CONV_FMT_COPY(rsp) \ + (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_COPY_MASK) >> \ + HDA_CMD_GET_DIGITAL_CONV_FMT_COPY_SHIFT) +#define HDA_CMD_GET_DIGITAL_CONV_FMT_PRE(rsp) \ + (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_PRE_MASK) >> \ + HDA_CMD_GET_DIGITAL_CONV_FMT_PRE_SHIFT) +#define HDA_CMD_GET_DIGITAL_CONV_FMT_VCFG(rsp) \ + (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_VCFG_MASK) >> \ + HDA_CMD_GET_DIGITAL_CONV_FMT_VCFG_SHIFT) +#define HDA_CMD_GET_DIGITAL_CONV_FMT_V(rsp) \ + (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_V_MASK) >> \ + HDA_CMD_GET_DIGITAL_CONV_FMT_V_SHIFT) +#define HDA_CMD_GET_DIGITAL_CONV_FMT_DIGEN(rsp) \ + (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_DIGEN_MASK) >> \ + HDA_CMD_GET_DIGITAL_CONV_FMT_DIGEN_SHIFT) + +#define HDA_CMD_SET_DIGITAL_CONV_FMT1_L 0x80 +#define HDA_CMD_SET_DIGITAL_CONV_FMT1_PRO 0x40 +#define HDA_CMD_SET_DIGITAL_CONV_FMT1_NAUDIO 0x20 +#define HDA_CMD_SET_DIGITAL_CONV_FMT1_COPY 0x10 +#define HDA_CMD_SET_DIGITAL_CONV_FMT1_PRE 0x08 +#define HDA_CMD_SET_DIGITAL_CONV_FMT1_VCFG 0x04 +#define HDA_CMD_SET_DIGITAL_CONV_FMT1_V 0x02 +#define HDA_CMD_SET_DIGITAL_CONV_FMT1_DIGEN 0x01 + +/* Power State */ +#define HDA_CMD_VERB_GET_POWER_STATE 0xf05 +#define HDA_CMD_VERB_SET_POWER_STATE 0x705 + +#define HDA_CMD_GET_POWER_STATE(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_POWER_STATE, 0x0)) +#define HDA_CMD_SET_POWER_STATE(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_POWER_STATE, (payload))) + +#define HDA_CMD_POWER_STATE_D0 0x00 +#define HDA_CMD_POWER_STATE_D1 0x01 +#define HDA_CMD_POWER_STATE_D2 0x02 +#define HDA_CMD_POWER_STATE_D3 0x03 + +#define HDA_CMD_POWER_STATE_ACT_MASK 0x000000f0 +#define HDA_CMD_POWER_STATE_ACT_SHIFT 4 +#define HDA_CMD_POWER_STATE_SET_MASK 0x0000000f +#define HDA_CMD_POWER_STATE_SET_SHIFT 0 + +#define HDA_CMD_GET_POWER_STATE_ACT(rsp) \ + (((rsp) & HDA_CMD_POWER_STATE_ACT_MASK) >> \ + HDA_CMD_POWER_STATE_ACT_SHIFT) +#define HDA_CMD_GET_POWER_STATE_SET(rsp) \ + (((rsp) & HDA_CMD_POWER_STATE_SET_MASK) >> \ + HDA_CMD_POWER_STATE_SET_SHIFT) + +#define HDA_CMD_SET_POWER_STATE_ACT(ps) \ + (((ps) << HDA_CMD_POWER_STATE_ACT_SHIFT) & \ + HDA_CMD_POWER_STATE_ACT_MASK) +#define HDA_CMD_SET_POWER_STATE_SET(ps) \ + (((ps) << HDA_CMD_POWER_STATE_SET_SHIFT) & \ + HDA_CMD_POWER_STATE_ACT_MASK) + +/* Converter Stream, Channel */ +#define HDA_CMD_VERB_GET_CONV_STREAM_CHAN 0xf06 +#define HDA_CMD_VERB_SET_CONV_STREAM_CHAN 0x706 + +#define HDA_CMD_GET_CONV_STREAM_CHAN(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_CONV_STREAM_CHAN, 0x0)) +#define HDA_CMD_SET_CONV_STREAM_CHAN(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_CONV_STREAM_CHAN, (payload))) + +#define HDA_CMD_CONV_STREAM_CHAN_STREAM_MASK 0x000000f0 +#define HDA_CMD_CONV_STREAM_CHAN_STREAM_SHIFT 4 +#define HDA_CMD_CONV_STREAM_CHAN_CHAN_MASK 0x0000000f +#define HDA_CMD_CONV_STREAM_CHAN_CHAN_SHIFT 0 + +#define HDA_CMD_GET_CONV_STREAM_CHAN_STREAM(rsp) \ + (((rsp) & HDA_CMD_CONV_STREAM_CHAN_STREAM_MASK) >> \ + HDA_CMD_CONV_STREAM_CHAN_STREAM_SHIFT) +#define HDA_CMD_GET_CONV_STREAM_CHAN_CHAN(rsp) \ + (((rsp) & HDA_CMD_CONV_STREAM_CHAN_CHAN_MASK) >> \ + HDA_CMD_CONV_STREAM_CHAN_CHAN_SHIFT) + +#define HDA_CMD_SET_CONV_STREAM_CHAN_STREAM(param) \ + (((param) << HDA_CMD_CONV_STREAM_CHAN_STREAM_SHIFT) & \ + HDA_CMD_CONV_STREAM_CHAN_STREAM_MASK) +#define HDA_CMD_SET_CONV_STREAM_CHAN_CHAN(param) \ + (((param) << HDA_CMD_CONV_STREAM_CHAN_CHAN_SHIFT) & \ + HDA_CMD_CONV_STREAM_CHAN_CHAN_MASK) + +/* Input Converter SDI Select */ +#define HDA_CMD_VERB_GET_INPUT_CONVERTER_SDI_SELECT 0xf04 +#define HDA_CMD_VERB_SET_INPUT_CONVERTER_SDI_SELECT 0x704 + +#define HDA_CMD_GET_INPUT_CONVERTER_SDI_SELECT(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_INPUT_CONVERTER_SDI_SELECT, 0x0)) +#define HDA_CMD_SET_INPUT_CONVERTER_SDI_SELECT(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_INPUT_CONVERTER_SDI_SELECT, (payload))) + +/* Pin Widget Control */ +#define HDA_CMD_VERB_GET_PIN_WIDGET_CTRL 0xf07 +#define HDA_CMD_VERB_SET_PIN_WIDGET_CTRL 0x707 + +#define HDA_CMD_GET_PIN_WIDGET_CTRL(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_PIN_WIDGET_CTRL, 0x0)) +#define HDA_CMD_SET_PIN_WIDGET_CTRL(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_PIN_WIDGET_CTRL, (payload))) + +#define HDA_CMD_GET_PIN_WIDGET_CTRL_HPHN_ENABLE_MASK 0x00000080 +#define HDA_CMD_GET_PIN_WIDGET_CTRL_HPHN_ENABLE_SHIFT 7 +#define HDA_CMD_GET_PIN_WIDGET_CTRL_OUT_ENABLE_MASK 0x00000040 +#define HDA_CMD_GET_PIN_WIDGET_CTRL_OUT_ENABLE_SHIFT 6 +#define HDA_CMD_GET_PIN_WIDGET_CTRL_IN_ENABLE_MASK 0x00000020 +#define HDA_CMD_GET_PIN_WIDGET_CTRL_IN_ENABLE_SHIFT 5 +#define HDA_CMD_GET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK 0x00000007 +#define HDA_CMD_GET_PIN_WIDGET_CTRL_VREF_ENABLE_SHIFT 0 + +#define HDA_CMD_GET_PIN_WIDGET_CTRL_HPHN_ENABLE(rsp) \ + (((rsp) & HDA_CMD_GET_PIN_WIDGET_CTRL_HPHN_ENABLE_MASK) >> \ + HDA_CMD_GET_PIN_WIDGET_CTRL_HPHN_ENABLE_SHIFT) +#define HDA_CMD_GET_PIN_WIDGET_CTRL_OUT_ENABLE(rsp) \ + (((rsp) & HDA_CMD_GET_PIN_WIDGET_CTRL_OUT_ENABLE_MASK) >> \ + HDA_GET_CMD_PIN_WIDGET_CTRL_OUT_ENABLE_SHIFT) +#define HDA_CMD_GET_PIN_WIDGET_CTRL_IN_ENABLE(rsp) \ + (((rsp) & HDA_CMD_GET_PIN_WIDGET_CTRL_IN_ENABLE_MASK) >> \ + HDA_CMD_GET_PIN_WIDGET_CTRL_IN_ENABLE_SHIFT) +#define HDA_CMD_GET_PIN_WIDGET_CTRL_VREF_ENABLE(rsp) \ + (((rsp) & HDA_CMD_GET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK) >> \ + HDA_CMD_GET_PIN_WIDGET_CTRL_VREF_ENABLE_SHIFT) + +#define HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE 0x80 +#define HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE 0x40 +#define HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE 0x20 +#define HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK 0x07 +#define HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_SHIFT 0 + +#define HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(param) \ + (((param) << HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_SHIFT) & \ + HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK) + +#define HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_HIZ 0 +#define HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_50 1 +#define HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_GROUND 2 +#define HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_80 4 +#define HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_100 5 + +/* Unsolicited Response */ +#define HDA_CMD_VERB_GET_UNSOLICITED_RESPONSE 0xf08 +#define HDA_CMD_VERB_SET_UNSOLICITED_RESPONSE 0x708 + +#define HDA_CMD_GET_UNSOLICITED_RESPONSE(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_UNSOLICITED_RESPONSE, 0x0)) +#define HDA_CMD_SET_UNSOLICITED_RESPONSE(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_UNSOLICITED_RESPONSE, (payload))) + +#define HDA_CMD_GET_UNSOLICITED_RESPONSE_ENABLE_MASK 0x00000080 +#define HDA_CMD_GET_UNSOLICITED_RESPONSE_ENABLE_SHIFT 7 +#define HDA_CMD_GET_UNSOLICITED_RESPONSE_TAG_MASK 0x0000001f +#define HDA_CMD_GET_UNSOLICITED_RESPONSE_TAG_SHIFT 0 + +#define HDA_CMD_GET_UNSOLICITED_RESPONSE_ENABLE(rsp) \ + (((rsp) & HDA_CMD_GET_UNSOLICITED_RESPONSE_ENABLE_MASK) >> \ + HDA_CMD_GET_UNSOLICITED_RESPONSE_ENABLE_SHIFT) +#define HDA_CMD_GET_UNSOLICITED_RESPONSE_TAG(rsp) \ + (((rsp) & HDA_CMD_GET_UNSOLICITED_RESPONSE_TAG_MASK) >> \ + HDA_CMD_GET_UNSOLICITED_RESPONSE_TAG_SHIFT) + +#define HDA_CMD_SET_UNSOLICITED_RESPONSE_ENABLE 0x80 +#define HDA_CMD_SET_UNSOLICITED_RESPONSE_TAG_MASK 0x3f +#define HDA_CMD_SET_UNSOLICITED_RESPONSE_TAG_SHIFT 0 + +#define HDA_CMD_SET_UNSOLICITED_RESPONSE_TAG(param) \ + (((param) << HDA_CMD_SET_UNSOLICITED_RESPONSE_TAG_SHIFT) & \ + HDA_CMD_SET_UNSOLICITED_RESPONSE_TAG_MASK) + +/* Pin Sense */ +#define HDA_CMD_VERB_GET_PIN_SENSE 0xf09 +#define HDA_CMD_VERB_SET_PIN_SENSE 0x709 + +#define HDA_CMD_GET_PIN_SENSE(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_PIN_SENSE, 0x0)) +#define HDA_CMD_SET_PIN_SENSE(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_PIN_SENSE, (payload))) + +#define HDA_CMD_GET_PIN_SENSE_PRESENCE_DETECT 0x80000000 +#define HDA_CMD_GET_PIN_SENSE_ELD_VALID 0x40000000 +#define HDA_CMD_GET_PIN_SENSE_IMP_SENSE_MASK 0x7fffffff +#define HDA_CMD_GET_PIN_SENSE_IMP_SENSE_SHIFT 0 + +#define HDA_CMD_GET_PIN_SENSE_IMP_SENSE(rsp) \ + (((rsp) & HDA_CMD_GET_PIN_SENSE_IMP_SENSE_MASK) >> \ + HDA_CMD_GET_PIN_SENSE_IMP_SENSE_SHIFT) + +#define HDA_CMD_GET_PIN_SENSE_IMP_SENSE_INVALID 0x7fffffff + +#define HDA_CMD_SET_PIN_SENSE_LEFT_CHANNEL 0x00 +#define HDA_CMD_SET_PIN_SENSE_RIGHT_CHANNEL 0x01 + +/* EAPD/BTL Enable */ +#define HDA_CMD_VERB_GET_EAPD_BTL_ENABLE 0xf0c +#define HDA_CMD_VERB_SET_EAPD_BTL_ENABLE 0x70c + +#define HDA_CMD_GET_EAPD_BTL_ENABLE(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_EAPD_BTL_ENABLE, 0x0)) +#define HDA_CMD_SET_EAPD_BTL_ENABLE(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_EAPD_BTL_ENABLE, (payload))) + +#define HDA_CMD_GET_EAPD_BTL_ENABLE_LR_SWAP_MASK 0x00000004 +#define HDA_CMD_GET_EAPD_BTL_ENABLE_LR_SWAP_SHIFT 2 +#define HDA_CMD_GET_EAPD_BTL_ENABLE_EAPD_MASK 0x00000002 +#define HDA_CMD_GET_EAPD_BTL_ENABLE_EAPD_SHIFT 1 +#define HDA_CMD_GET_EAPD_BTL_ENABLE_BTL_MASK 0x00000001 +#define HDA_CMD_GET_EAPD_BTL_ENABLE_BTL_SHIFT 0 + +#define HDA_CMD_GET_EAPD_BTL_ENABLE_LR_SWAP(rsp) \ + (((rsp) & HDA_CMD_GET_EAPD_BTL_ENABLE_LR_SWAP_MASK) >> \ + HDA_CMD_GET_EAPD_BTL_ENABLE_LR_SWAP_SHIFT) +#define HDA_CMD_GET_EAPD_BTL_ENABLE_EAPD(rsp) \ + (((rsp) & HDA_CMD_GET_EAPD_BTL_ENABLE_EAPD_MASK) >> \ + HDA_CMD_GET_EAPD_BTL_ENABLE_EAPD_SHIFT) +#define HDA_CMD_GET_EAPD_BTL_ENABLE_BTL(rsp) \ + (((rsp) & HDA_CMD_GET_EAPD_BTL_ENABLE_BTL_MASK) >> \ + HDA_CMD_GET_EAPD_BTL_ENABLE_BTL_SHIFT) + +#define HDA_CMD_SET_EAPD_BTL_ENABLE_LR_SWAP 0x04 +#define HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD 0x02 +#define HDA_CMD_SET_EAPD_BTL_ENABLE_BTL 0x01 + +/* GPI Data */ +#define HDA_CMD_VERB_GET_GPI_DATA 0xf10 +#define HDA_CMD_VERB_SET_GPI_DATA 0x710 + +#define HDA_CMD_GET_GPI_DATA(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPI_DATA, 0x0)) +#define HDA_CMD_SET_GPI_DATA(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPI_DATA, (payload))) + +/* GPI Wake Enable Mask */ +#define HDA_CMD_VERB_GET_GPI_WAKE_ENABLE_MASK 0xf11 +#define HDA_CMD_VERB_SET_GPI_WAKE_ENABLE_MASK 0x711 + +#define HDA_CMD_GET_GPI_WAKE_ENABLE_MASK(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPI_WAKE_ENABLE_MASK, 0x0)) +#define HDA_CMD_SET_GPI_WAKE_ENABLE_MASK(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPI_WAKE_ENABLE_MASK, (payload))) + +/* GPI Unsolicited Enable Mask */ +#define HDA_CMD_VERB_GET_GPI_UNSOLICITED_ENABLE_MASK 0xf12 +#define HDA_CMD_VERB_SET_GPI_UNSOLICITED_ENABLE_MASK 0x712 + +#define HDA_CMD_GET_GPI_UNSOLICITED_ENABLE_MASK(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPI_UNSOLICITED_ENABLE_MASK, 0x0)) +#define HDA_CMD_SET_GPI_UNSOLICITED_ENABLE_MASK(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPI_UNSOLICITED_ENABLE_MASK, (payload))) + +/* GPI Sticky Mask */ +#define HDA_CMD_VERB_GET_GPI_STICKY_MASK 0xf13 +#define HDA_CMD_VERB_SET_GPI_STICKY_MASK 0x713 + +#define HDA_CMD_GET_GPI_STICKY_MASK(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPI_STICKY_MASK, 0x0)) +#define HDA_CMD_SET_GPI_STICKY_MASK(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPI_STICKY_MASK, (payload))) + +/* GPO Data */ +#define HDA_CMD_VERB_GET_GPO_DATA 0xf14 +#define HDA_CMD_VERB_SET_GPO_DATA 0x714 + +#define HDA_CMD_GET_GPO_DATA(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPO_DATA, 0x0)) +#define HDA_CMD_SET_GPO_DATA(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPO_DATA, (payload))) + +/* GPIO Data */ +#define HDA_CMD_VERB_GET_GPIO_DATA 0xf15 +#define HDA_CMD_VERB_SET_GPIO_DATA 0x715 + +#define HDA_CMD_GET_GPIO_DATA(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPIO_DATA, 0x0)) +#define HDA_CMD_SET_GPIO_DATA(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPIO_DATA, (payload))) + +/* GPIO Enable Mask */ +#define HDA_CMD_VERB_GET_GPIO_ENABLE_MASK 0xf16 +#define HDA_CMD_VERB_SET_GPIO_ENABLE_MASK 0x716 + +#define HDA_CMD_GET_GPIO_ENABLE_MASK(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPIO_ENABLE_MASK, 0x0)) +#define HDA_CMD_SET_GPIO_ENABLE_MASK(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPIO_ENABLE_MASK, (payload))) + +/* GPIO Direction */ +#define HDA_CMD_VERB_GET_GPIO_DIRECTION 0xf17 +#define HDA_CMD_VERB_SET_GPIO_DIRECTION 0x717 + +#define HDA_CMD_GET_GPIO_DIRECTION(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPIO_DIRECTION, 0x0)) +#define HDA_CMD_SET_GPIO_DIRECTION(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPIO_DIRECTION, (payload))) + +/* GPIO Wake Enable Mask */ +#define HDA_CMD_VERB_GET_GPIO_WAKE_ENABLE_MASK 0xf18 +#define HDA_CMD_VERB_SET_GPIO_WAKE_ENABLE_MASK 0x718 + +#define HDA_CMD_GET_GPIO_WAKE_ENABLE_MASK(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPIO_WAKE_ENABLE_MASK, 0x0)) +#define HDA_CMD_SET_GPIO_WAKE_ENABLE_MASK(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPIO_WAKE_ENABLE_MASK, (payload))) + +/* GPIO Unsolicited Enable Mask */ +#define HDA_CMD_VERB_GET_GPIO_UNSOLICITED_ENABLE_MASK 0xf19 +#define HDA_CMD_VERB_SET_GPIO_UNSOLICITED_ENABLE_MASK 0x719 + +#define HDA_CMD_GET_GPIO_UNSOLICITED_ENABLE_MASK(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPIO_UNSOLICITED_ENABLE_MASK, 0x0)) +#define HDA_CMD_SET_GPIO_UNSOLICITED_ENABLE_MASK(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPIO_UNSOLICITED_ENABLE_MASK, (payload))) + +/* GPIO_STICKY_MASK */ +#define HDA_CMD_VERB_GET_GPIO_STICKY_MASK 0xf1a +#define HDA_CMD_VERB_SET_GPIO_STICKY_MASK 0x71a + +#define HDA_CMD_GET_GPIO_STICKY_MASK(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPIO_STICKY_MASK, 0x0)) +#define HDA_CMD_SET_GPIO_STICKY_MASK(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPIO_STICKY_MASK, (payload))) + +/* Beep Generation */ +#define HDA_CMD_VERB_GET_BEEP_GENERATION 0xf0a +#define HDA_CMD_VERB_SET_BEEP_GENERATION 0x70a + +#define HDA_CMD_GET_BEEP_GENERATION(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_BEEP_GENERATION, 0x0)) +#define HDA_CMD_SET_BEEP_GENERATION(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_BEEP_GENERATION, (payload))) + +/* Volume Knob */ +#define HDA_CMD_VERB_GET_VOLUME_KNOB 0xf0f +#define HDA_CMD_VERB_SET_VOLUME_KNOB 0x70f + +#define HDA_CMD_GET_VOLUME_KNOB(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_VOLUME_KNOB, 0x0)) +#define HDA_CMD_SET_VOLUME_KNOB(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_VOLUME_KNOB, (payload))) + +/* Subsystem ID */ +#define HDA_CMD_VERB_GET_SUBSYSTEM_ID 0xf20 +#define HDA_CMD_VERB_SET_SUSBYSTEM_ID1 0x720 +#define HDA_CMD_VERB_SET_SUBSYSTEM_ID2 0x721 +#define HDA_CMD_VERB_SET_SUBSYSTEM_ID3 0x722 +#define HDA_CMD_VERB_SET_SUBSYSTEM_ID4 0x723 + +#define HDA_CMD_GET_SUBSYSTEM_ID(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_SUBSYSTEM_ID, 0x0)) +#define HDA_CMD_SET_SUBSYSTEM_ID1(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_SUSBYSTEM_ID1, (payload))) +#define HDA_CMD_SET_SUBSYSTEM_ID2(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_SUSBYSTEM_ID2, (payload))) +#define HDA_CMD_SET_SUBSYSTEM_ID3(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_SUSBYSTEM_ID3, (payload))) +#define HDA_CMD_SET_SUBSYSTEM_ID4(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_SUSBYSTEM_ID4, (payload))) + +/* Configuration Default */ +#define HDA_CMD_VERB_GET_CONFIGURATION_DEFAULT 0xf1c +#define HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT1 0x71c +#define HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT2 0x71d +#define HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT3 0x71e +#define HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT4 0x71f + +#define HDA_CMD_GET_CONFIGURATION_DEFAULT(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_CONFIGURATION_DEFAULT, 0x0)) +#define HDA_CMD_SET_CONFIGURATION_DEFAULT1(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT1, (payload))) +#define HDA_CMD_SET_CONFIGURATION_DEFAULT2(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT2, (payload))) +#define HDA_CMD_SET_CONFIGURATION_DEFAULT3(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT3, (payload))) +#define HDA_CMD_SET_CONFIGURATION_DEFAULT4(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT4, (payload))) + +/* Stripe Control */ +#define HDA_CMD_VERB_GET_STRIPE_CONTROL 0xf24 +#define HDA_CMD_VERB_SET_STRIPE_CONTROL 0x724 + +#define HDA_CMD_GET_STRIPE_CONTROL(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_STRIPE_CONTROL, 0x0)) +#define HDA_CMD_SET_STRIPE_CONTROL(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_STRIPE_CONTROL, (payload))) + +/* Channel Count Control */ +#define HDA_CMD_VERB_GET_CONV_CHAN_COUNT 0xf2d +#define HDA_CMD_VERB_SET_CONV_CHAN_COUNT 0x72d + +#define HDA_CMD_GET_CONV_CHAN_COUNT(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_CONV_CHAN_COUNT, 0x0)) +#define HDA_CMD_SET_CONV_CHAN_COUNT(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_CONV_CHAN_COUNT, (payload))) + +#define HDA_CMD_VERB_GET_HDMI_DIP_SIZE 0xf2e + +#define HDA_CMD_GET_HDMI_DIP_SIZE(cad, nid, arg) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_HDMI_DIP_SIZE, (arg))) + +#define HDA_CMD_VERB_GET_HDMI_ELDD 0xf2f + +#define HDA_CMD_GET_HDMI_ELDD(cad, nid, off) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_HDMI_ELDD, (off))) + +#define HDA_CMD_VERB_GET_HDMI_DIP_INDEX 0xf30 +#define HDA_CMD_VERB_SET_HDMI_DIP_INDEX 0x730 + +#define HDA_CMD_GET_HDMI_DIP_INDEX(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_HDMI_DIP_INDEX, 0x0)) +#define HDA_CMD_SET_HDMI_DIP_INDEX(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_HDMI_DIP_INDEX, (payload))) + +#define HDA_CMD_VERB_GET_HDMI_DIP_DATA 0xf31 +#define HDA_CMD_VERB_SET_HDMI_DIP_DATA 0x731 + +#define HDA_CMD_GET_HDMI_DIP_DATA(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_HDMI_DIP_DATA, 0x0)) +#define HDA_CMD_SET_HDMI_DIP_DATA(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_HDMI_DIP_DATA, (payload))) + +#define HDA_CMD_VERB_GET_HDMI_DIP_XMIT 0xf32 +#define HDA_CMD_VERB_SET_HDMI_DIP_XMIT 0x732 + +#define HDA_CMD_GET_HDMI_DIP_XMIT(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_HDMI_DIP_XMIT, 0x0)) +#define HDA_CMD_SET_HDMI_DIP_XMIT(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_HDMI_DIP_XMIT, (payload))) + +#define HDA_CMD_VERB_GET_HDMI_CP_CTRL 0xf33 +#define HDA_CMD_VERB_SET_HDMI_CP_CTRL 0x733 + +#define HDA_CMD_VERB_GET_HDMI_CHAN_SLOT 0xf34 +#define HDA_CMD_VERB_SET_HDMI_CHAN_SLOT 0x734 + +#define HDA_CMD_GET_HDMI_CHAN_SLOT(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_HDMI_CHAN_SLOT, 0x0)) +#define HDA_CMD_SET_HDMI_CHAN_SLOT(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_HDMI_CHAN_SLOT, (payload))) + +#define HDA_HDMI_CODING_TYPE_REF_STREAM_HEADER 0 +#define HDA_HDMI_CODING_TYPE_LPCM 1 +#define HDA_HDMI_CODING_TYPE_AC3 2 +#define HDA_HDMI_CODING_TYPE_MPEG1 3 +#define HDA_HDMI_CODING_TYPE_MP3 4 +#define HDA_HDMI_CODING_TYPE_MPEG2 5 +#define HDA_HDMI_CODING_TYPE_AACLC 6 +#define HDA_HDMI_CODING_TYPE_DTS 7 +#define HDA_HDMI_CODING_TYPE_ATRAC 8 +#define HDA_HDMI_CODING_TYPE_SACD 9 +#define HDA_HDMI_CODING_TYPE_EAC3 10 +#define HDA_HDMI_CODING_TYPE_DTS_HD 11 +#define HDA_HDMI_CODING_TYPE_MLP 12 +#define HDA_HDMI_CODING_TYPE_DST 13 +#define HDA_HDMI_CODING_TYPE_WMAPRO 14 +#define HDA_HDMI_CODING_TYPE_REF_CTX 15 + +/* Function Reset */ +#define HDA_CMD_VERB_FUNCTION_RESET 0x7ff + +#define HDA_CMD_FUNCTION_RESET(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_FUNCTION_RESET, 0x0)) + + +/**************************************************************************** + * HDA Device Parameters + ****************************************************************************/ + +/* Vendor ID */ +#define HDA_PARAM_VENDOR_ID 0x00 + +#define HDA_PARAM_VENDOR_ID_VENDOR_ID_MASK 0xffff0000 +#define HDA_PARAM_VENDOR_ID_VENDOR_ID_SHIFT 16 +#define HDA_PARAM_VENDOR_ID_DEVICE_ID_MASK 0x0000ffff +#define HDA_PARAM_VENDOR_ID_DEVICE_ID_SHIFT 0 + +#define HDA_PARAM_VENDOR_ID_VENDOR_ID(param) \ + (((param) & HDA_PARAM_VENDOR_ID_VENDOR_ID_MASK) >> \ + HDA_PARAM_VENDOR_ID_VENDOR_ID_SHIFT) +#define HDA_PARAM_VENDOR_ID_DEVICE_ID(param) \ + (((param) & HDA_PARAM_VENDOR_ID_DEVICE_ID_MASK) >> \ + HDA_PARAM_VENDOR_ID_DEVICE_ID_SHIFT) + +/* Revision ID */ +#define HDA_PARAM_REVISION_ID 0x02 + +#define HDA_PARAM_REVISION_ID_MAJREV_MASK 0x00f00000 +#define HDA_PARAM_REVISION_ID_MAJREV_SHIFT 20 +#define HDA_PARAM_REVISION_ID_MINREV_MASK 0x000f0000 +#define HDA_PARAM_REVISION_ID_MINREV_SHIFT 16 +#define HDA_PARAM_REVISION_ID_REVISION_ID_MASK 0x0000ff00 +#define HDA_PARAM_REVISION_ID_REVISION_ID_SHIFT 8 +#define HDA_PARAM_REVISION_ID_STEPPING_ID_MASK 0x000000ff +#define HDA_PARAM_REVISION_ID_STEPPING_ID_SHIFT 0 + +#define HDA_PARAM_REVISION_ID_MAJREV(param) \ + (((param) & HDA_PARAM_REVISION_ID_MAJREV_MASK) >> \ + HDA_PARAM_REVISION_ID_MAJREV_SHIFT) +#define HDA_PARAM_REVISION_ID_MINREV(param) \ + (((param) & HDA_PARAM_REVISION_ID_MINREV_MASK) >> \ + HDA_PARAM_REVISION_ID_MINREV_SHIFT) +#define HDA_PARAM_REVISION_ID_REVISION_ID(param) \ + (((param) & HDA_PARAM_REVISION_ID_REVISION_ID_MASK) >> \ + HDA_PARAM_REVISION_ID_REVISION_ID_SHIFT) +#define HDA_PARAM_REVISION_ID_STEPPING_ID(param) \ + (((param) & HDA_PARAM_REVISION_ID_STEPPING_ID_MASK) >> \ + HDA_PARAM_REVISION_ID_STEPPING_ID_SHIFT) + +/* Subordinate Node Cound */ +#define HDA_PARAM_SUB_NODE_COUNT 0x04 + +#define HDA_PARAM_SUB_NODE_COUNT_START_MASK 0x00ff0000 +#define HDA_PARAM_SUB_NODE_COUNT_START_SHIFT 16 +#define HDA_PARAM_SUB_NODE_COUNT_TOTAL_MASK 0x000000ff +#define HDA_PARAM_SUB_NODE_COUNT_TOTAL_SHIFT 0 + +#define HDA_PARAM_SUB_NODE_COUNT_START(param) \ + (((param) & HDA_PARAM_SUB_NODE_COUNT_START_MASK) >> \ + HDA_PARAM_SUB_NODE_COUNT_START_SHIFT) +#define HDA_PARAM_SUB_NODE_COUNT_TOTAL(param) \ + (((param) & HDA_PARAM_SUB_NODE_COUNT_TOTAL_MASK) >> \ + HDA_PARAM_SUB_NODE_COUNT_TOTAL_SHIFT) + +/* Function Group Type */ +#define HDA_PARAM_FCT_GRP_TYPE 0x05 + +#define HDA_PARAM_FCT_GRP_TYPE_UNSOL_MASK 0x00000100 +#define HDA_PARAM_FCT_GRP_TYPE_UNSOL_SHIFT 8 +#define HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_MASK 0x000000ff +#define HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_SHIFT 0 + +#define HDA_PARAM_FCT_GRP_TYPE_UNSOL(param) \ + (((param) & HDA_PARAM_FCT_GRP_TYPE_UNSOL_MASK) >> \ + HDA_PARAM_FCT_GROUP_TYPE_UNSOL_SHIFT) +#define HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE(param) \ + (((param) & HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_MASK) >> \ + HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_SHIFT) + +#define HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO 0x01 +#define HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_MODEM 0x02 + +/* Audio Function Group Capabilities */ +#define HDA_PARAM_AUDIO_FCT_GRP_CAP 0x08 + +#define HDA_PARAM_AUDIO_FCT_GRP_CAP_BEEP_GEN_MASK 0x00010000 +#define HDA_PARAM_AUDIO_FCT_GRP_CAP_BEEP_GEN_SHIFT 16 +#define HDA_PARAM_AUDIO_FCT_GRP_CAP_INPUT_DELAY_MASK 0x00000f00 +#define HDA_PARAM_AUDIO_FCT_GRP_CAP_INPUT_DELAY_SHIFT 8 +#define HDA_PARAM_AUDIO_FCT_GRP_CAP_OUTPUT_DELAY_MASK 0x0000000f +#define HDA_PARAM_AUDIO_FCT_GRP_CAP_OUTPUT_DELAY_SHIFT 0 + +#define HDA_PARAM_AUDIO_FCT_GRP_CAP_BEEP_GEN(param) \ + (((param) & HDA_PARAM_AUDIO_FCT_GRP_CAP_BEEP_GEN_MASK) >> \ + HDA_PARAM_AUDIO_FCT_GRP_CAP_BEEP_GEN_SHIFT) +#define HDA_PARAM_AUDIO_FCT_GRP_CAP_INPUT_DELAY(param) \ + (((param) & HDA_PARAM_AUDIO_FCT_GRP_CAP_INPUT_DELAY_MASK) >> \ + HDA_PARAM_AUDIO_FCT_GRP_CAP_INPUT_DELAY_SHIFT) +#define HDA_PARAM_AUDIO_FCT_GRP_CAP_OUTPUT_DELAY(param) \ + (((param) & HDA_PARAM_AUDIO_FCT_GRP_CAP_OUTPUT_DELAY_MASK) >> \ + HDA_PARAM_AUDIO_FCT_GRP_CAP_OUTPUT_DELAY_SHIFT) + +/* Audio Widget Capabilities */ +#define HDA_PARAM_AUDIO_WIDGET_CAP 0x09 + +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_MASK 0x00f00000 +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT 20 +#define HDA_PARAM_AUDIO_WIDGET_CAP_DELAY_MASK 0x000f0000 +#define HDA_PARAM_AUDIO_WIDGET_CAP_DELAY_SHIFT 16 +#define HDA_PARAM_AUDIO_WIDGET_CAP_CC_EXT_MASK 0x0000e000 +#define HDA_PARAM_AUDIO_WIDGET_CAP_CC_EXT_SHIFT 13 +#define HDA_PARAM_AUDIO_WIDGET_CAP_CP_MASK 0x00001000 +#define HDA_PARAM_AUDIO_WIDGET_CAP_CP_SHIFT 12 +#define HDA_PARAM_AUDIO_WIDGET_CAP_LR_SWAP_MASK 0x00000800 +#define HDA_PARAM_AUDIO_WIDGET_CAP_LR_SWAP_SHIFT 11 +#define HDA_PARAM_AUDIO_WIDGET_CAP_POWER_CTRL_MASK 0x00000400 +#define HDA_PARAM_AUDIO_WIDGET_CAP_POWER_CTRL_SHIFT 10 +#define HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL_MASK 0x00000200 +#define HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL_SHIFT 9 +#define HDA_PARAM_AUDIO_WIDGET_CAP_CONN_LIST_MASK 0x00000100 +#define HDA_PARAM_AUDIO_WIDGET_CAP_CONN_LIST_SHIFT 8 +#define HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP_MASK 0x00000080 +#define HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP_SHIFT 7 +#define HDA_PARAM_AUDIO_WIDGET_CAP_PROC_WIDGET_MASK 0x00000040 +#define HDA_PARAM_AUDIO_WIDGET_CAP_PROC_WIDGET_SHIFT 6 +#define HDA_PARAM_AUDIO_WIDGET_CAP_STRIPE_MASK 0x00000020 +#define HDA_PARAM_AUDIO_WIDGET_CAP_STRIPE_SHIFT 5 +#define HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR_MASK 0x00000010 +#define HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR_SHIFT 4 +#define HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR_MASK 0x00000008 +#define HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR_SHIFT 3 +#define HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP_MASK 0x00000004 +#define HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP_SHIFT 2 +#define HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP_MASK 0x00000002 +#define HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP_SHIFT 1 +#define HDA_PARAM_AUDIO_WIDGET_CAP_STEREO_MASK 0x00000001 +#define HDA_PARAM_AUDIO_WIDGET_CAP_STEREO_SHIFT 0 + +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_DELAY(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_DELAY_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_DELAY_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_CC(param) \ + ((((param) & HDA_PARAM_AUDIO_WIDGET_CAP_CC_EXT_MASK) >> \ + (HDA_PARAM_AUDIO_WIDGET_CAP_CC_EXT_SHIFT - 1)) | \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_STEREO_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_STEREO_SHIFT)) +#define HDA_PARAM_AUDIO_WIDGET_CAP_CP(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_CP_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_CP_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_LR_SWAP(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_LR_SWAP_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_LR_SWAP_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_POWER_CTRL(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_POWER_CTRL_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_POWER_CTRL_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_CONN_LIST(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_CONN_LIST_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_CONN_LIST_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_PROC_WIDGET(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_PROC_WIDGET_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_PROC_WIDGET_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_STRIPE(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_STRIPE_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_STRIPE_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_STEREO(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_STEREO_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_STEREO_SHIFT) + +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT 0x0 +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT 0x1 +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER 0x2 +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR 0x3 +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX 0x4 +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_POWER_WIDGET 0x5 +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_VOLUME_WIDGET 0x6 +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET 0x7 +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_VENDOR_WIDGET 0xf + +/* Supported PCM Size, Rates */ + +#define HDA_PARAM_SUPP_PCM_SIZE_RATE 0x0a + +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT_MASK 0x00100000 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT_SHIFT 20 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT_MASK 0x00080000 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT_SHIFT 19 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT_MASK 0x00040000 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT_SHIFT 18 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT_MASK 0x00020000 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT_SHIFT 17 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT_MASK 0x00010000 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT_SHIFT 16 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ_MASK 0x00000001 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ_SHIFT 0 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ_MASK 0x00000002 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ_SHIFT 1 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ_MASK 0x00000004 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ_SHIFT 2 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ_MASK 0x00000008 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ_SHIFT 3 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ_MASK 0x00000010 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ_SHIFT 4 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ_MASK 0x00000020 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ_SHIFT 5 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_48KHZ_MASK 0x00000040 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_48KHZ_SHIFT 6 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ_MASK 0x00000080 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ_SHIFT 7 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ_MASK 0x00000100 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ_SHIFT 8 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ_MASK 0x00000200 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ_SHIFT 9 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ_MASK 0x00000400 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ_SHIFT 10 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_384KHZ_MASK 0x00000800 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_384KHZ_SHIFT 11 + +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_48KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_48KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_48KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_384KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_384KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_384KHZ_SHIFT) + +/* Supported Stream Formats */ +#define HDA_PARAM_SUPP_STREAM_FORMATS 0x0b + +#define HDA_PARAM_SUPP_STREAM_FORMATS_AC3_MASK 0x00000004 +#define HDA_PARAM_SUPP_STREAM_FORMATS_AC3_SHIFT 2 +#define HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32_MASK 0x00000002 +#define HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32_SHIFT 1 +#define HDA_PARAM_SUPP_STREAM_FORMATS_PCM_MASK 0x00000001 +#define HDA_PARAM_SUPP_STREAM_FORMATS_PCM_SHIFT 0 + +#define HDA_PARAM_SUPP_STREAM_FORMATS_AC3(param) \ + (((param) & HDA_PARAM_SUPP_STREAM_FORMATS_AC3_MASK) >> \ + HDA_PARAM_SUPP_STREAM_FORMATS_AC3_SHIFT) +#define HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32(param) \ + (((param) & HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32_MASK) >> \ + HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32_SHIFT) +#define HDA_PARAM_SUPP_STREAM_FORMATS_PCM(param) \ + (((param) & HDA_PARAM_SUPP_STREAM_FORMATS_PCM_MASK) >> \ + HDA_PARAM_SUPP_STREAM_FORMATS_PCM_SHIFT) + +/* Pin Capabilities */ +#define HDA_PARAM_PIN_CAP 0x0c + +#define HDA_PARAM_PIN_CAP_HBR_MASK 0x08000000 +#define HDA_PARAM_PIN_CAP_HBR_SHIFT 27 +#define HDA_PARAM_PIN_CAP_DP_MASK 0x01000000 +#define HDA_PARAM_PIN_CAP_DP_SHIFT 24 +#define HDA_PARAM_PIN_CAP_EAPD_CAP_MASK 0x00010000 +#define HDA_PARAM_PIN_CAP_EAPD_CAP_SHIFT 16 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_MASK 0x0000ff00 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_SHIFT 8 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_100_MASK 0x00002000 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_100_SHIFT 13 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_80_MASK 0x00001000 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_80_SHIFT 12 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_GROUND_MASK 0x00000400 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_GROUND_SHIFT 10 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_50_MASK 0x00000200 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_50_SHIFT 9 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_HIZ_MASK 0x00000100 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_HIZ_SHIFT 8 +#define HDA_PARAM_PIN_CAP_HDMI_MASK 0x00000080 +#define HDA_PARAM_PIN_CAP_HDMI_SHIFT 7 +#define HDA_PARAM_PIN_CAP_BALANCED_IO_PINS_MASK 0x00000040 +#define HDA_PARAM_PIN_CAP_BALANCED_IO_PINS_SHIFT 6 +#define HDA_PARAM_PIN_CAP_INPUT_CAP_MASK 0x00000020 +#define HDA_PARAM_PIN_CAP_INPUT_CAP_SHIFT 5 +#define HDA_PARAM_PIN_CAP_OUTPUT_CAP_MASK 0x00000010 +#define HDA_PARAM_PIN_CAP_OUTPUT_CAP_SHIFT 4 +#define HDA_PARAM_PIN_CAP_HEADPHONE_CAP_MASK 0x00000008 +#define HDA_PARAM_PIN_CAP_HEADPHONE_CAP_SHIFT 3 +#define HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP_MASK 0x00000004 +#define HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP_SHIFT 2 +#define HDA_PARAM_PIN_CAP_TRIGGER_REQD_MASK 0x00000002 +#define HDA_PARAM_PIN_CAP_TRIGGER_REQD_SHIFT 1 +#define HDA_PARAM_PIN_CAP_IMP_SENSE_CAP_MASK 0x00000001 +#define HDA_PARAM_PIN_CAP_IMP_SENSE_CAP_SHIFT 0 + +#define HDA_PARAM_PIN_CAP_HBR(param) \ + (((param) & HDA_PARAM_PIN_CAP_HBR_MASK) >> \ + HDA_PARAM_PIN_CAP_HBR_SHIFT) +#define HDA_PARAM_PIN_CAP_DP(param) \ + (((param) & HDA_PARAM_PIN_CAP_DP_MASK) >> \ + HDA_PARAM_PIN_CAP_DP_SHIFT) +#define HDA_PARAM_PIN_CAP_EAPD_CAP(param) \ + (((param) & HDA_PARAM_PIN_CAP_EAPD_CAP_MASK) >> \ + HDA_PARAM_PIN_CAP_EAPD_CAP_SHIFT) +#define HDA_PARAM_PIN_CAP_VREF_CTRL(param) \ + (((param) & HDA_PARAM_PIN_CAP_VREF_CTRL_MASK) >> \ + HDA_PARAM_PIN_CAP_VREF_CTRL_SHIFT) +#define HDA_PARAM_PIN_CAP_VREF_CTRL_100(param) \ + (((param) & HDA_PARAM_PIN_CAP_VREF_CTRL_100_MASK) >> \ + HDA_PARAM_PIN_CAP_VREF_CTRL_100_SHIFT) +#define HDA_PARAM_PIN_CAP_VREF_CTRL_80(param) \ + (((param) & HDA_PARAM_PIN_CAP_VREF_CTRL_80_MASK) >> \ + HDA_PARAM_PIN_CAP_VREF_CTRL_80_SHIFT) +#define HDA_PARAM_PIN_CAP_VREF_CTRL_GROUND(param) \ + (((param) & HDA_PARAM_PIN_CAP_VREF_CTRL_GROUND_MASK) >> \ + HDA_PARAM_PIN_CAP_VREF_CTRL_GROUND_SHIFT) +#define HDA_PARAM_PIN_CAP_VREF_CTRL_50(param) \ + (((param) & HDA_PARAM_PIN_CAP_VREF_CTRL_50_MASK) >> \ + HDA_PARAM_PIN_CAP_VREF_CTRL_50_SHIFT) +#define HDA_PARAM_PIN_CAP_VREF_CTRL_HIZ(param) \ + (((param) & HDA_PARAM_PIN_CAP_VREF_CTRL_HIZ_MASK) >> \ + HDA_PARAM_PIN_CAP_VREF_CTRL_HIZ_SHIFT) +#define HDA_PARAM_PIN_CAP_HDMI(param) \ + (((param) & HDA_PARAM_PIN_CAP_HDMI_MASK) >> \ + HDA_PARAM_PIN_CAP_HDMI_SHIFT) +#define HDA_PARAM_PIN_CAP_BALANCED_IO_PINS(param) \ + (((param) & HDA_PARAM_PIN_CAP_BALANCED_IO_PINS_MASK) >> \ + HDA_PARAM_PIN_CAP_BALANCED_IO_PINS_SHIFT) +#define HDA_PARAM_PIN_CAP_INPUT_CAP(param) \ + (((param) & HDA_PARAM_PIN_CAP_INPUT_CAP_MASK) >> \ + HDA_PARAM_PIN_CAP_INPUT_CAP_SHIFT) +#define HDA_PARAM_PIN_CAP_OUTPUT_CAP(param) \ + (((param) & HDA_PARAM_PIN_CAP_OUTPUT_CAP_MASK) >> \ + HDA_PARAM_PIN_CAP_OUTPUT_CAP_SHIFT) +#define HDA_PARAM_PIN_CAP_HEADPHONE_CAP(param) \ + (((param) & HDA_PARAM_PIN_CAP_HEADPHONE_CAP_MASK) >> \ + HDA_PARAM_PIN_CAP_HEADPHONE_CAP_SHIFT) +#define HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(param) \ + (((param) & HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP_MASK) >> \ + HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP_SHIFT) +#define HDA_PARAM_PIN_CAP_TRIGGER_REQD(param) \ + (((param) & HDA_PARAM_PIN_CAP_TRIGGER_REQD_MASK) >> \ + HDA_PARAM_PIN_CAP_TRIGGER_REQD_SHIFT) +#define HDA_PARAM_PIN_CAP_IMP_SENSE_CAP(param) \ + (((param) & HDA_PARAM_PIN_CAP_IMP_SENSE_CAP_MASK) >> \ + HDA_PARAM_PIN_CAP_IMP_SENSE_CAP_SHIFT) + +/* Input Amplifier Capabilities */ +#define HDA_PARAM_INPUT_AMP_CAP 0x0d + +#define HDA_PARAM_INPUT_AMP_CAP_MUTE_CAP_MASK 0x80000000 +#define HDA_PARAM_INPUT_AMP_CAP_MUTE_CAP_SHIFT 31 +#define HDA_PARAM_INPUT_AMP_CAP_STEPSIZE_MASK 0x007f0000 +#define HDA_PARAM_INPUT_AMP_CAP_STEPSIZE_SHIFT 16 +#define HDA_PARAM_INPUT_AMP_CAP_NUMSTEPS_MASK 0x00007f00 +#define HDA_PARAM_INPUT_AMP_CAP_NUMSTEPS_SHIFT 8 +#define HDA_PARAM_INPUT_AMP_CAP_OFFSET_MASK 0x0000007f +#define HDA_PARAM_INPUT_AMP_CAP_OFFSET_SHIFT 0 + +#define HDA_PARAM_INPUT_AMP_CAP_MUTE_CAP(param) \ + (((param) & HDA_PARAM_INPUT_AMP_CAP_MUTE_CAP_MASK) >> \ + HDA_PARAM_INPUT_AMP_CAP_MUTE_CAP_SHIFT) +#define HDA_PARAM_INPUT_AMP_CAP_STEPSIZE(param) \ + (((param) & HDA_PARAM_INPUT_AMP_CAP_STEPSIZE_MASK) >> \ + HDA_PARAM_INPUT_AMP_CAP_STEPSIZE_SHIFT) +#define HDA_PARAM_INPUT_AMP_CAP_NUMSTEPS(param) \ + (((param) & HDA_PARAM_INPUT_AMP_CAP_NUMSTEPS_MASK) >> \ + HDA_PARAM_INPUT_AMP_CAP_NUMSTEPS_SHIFT) +#define HDA_PARAM_INPUT_AMP_CAP_OFFSET(param) \ + (((param) & HDA_PARAM_INPUT_AMP_CAP_OFFSET_MASK) >> \ + HDA_PARAM_INPUT_AMP_CAP_OFFSET_SHIFT) + +/* Output Amplifier Capabilities */ +#define HDA_PARAM_OUTPUT_AMP_CAP 0x12 + +#define HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP_MASK 0x80000000 +#define HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP_SHIFT 31 +#define HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_MASK 0x007f0000 +#define HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_SHIFT 16 +#define HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_MASK 0x00007f00 +#define HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_SHIFT 8 +#define HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_MASK 0x0000007f +#define HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_SHIFT 0 + +#define HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP(param) \ + (((param) & HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP_MASK) >> \ + HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP_SHIFT) +#define HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE(param) \ + (((param) & HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_MASK) >> \ + HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_SHIFT) +#define HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS(param) \ + (((param) & HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_MASK) >> \ + HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_SHIFT) +#define HDA_PARAM_OUTPUT_AMP_CAP_OFFSET(param) \ + (((param) & HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_MASK) >> \ + HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_SHIFT) + +/* Connection List Length */ +#define HDA_PARAM_CONN_LIST_LENGTH 0x0e + +#define HDA_PARAM_CONN_LIST_LENGTH_LONG_FORM_MASK 0x00000080 +#define HDA_PARAM_CONN_LIST_LENGTH_LONG_FORM_SHIFT 7 +#define HDA_PARAM_CONN_LIST_LENGTH_LIST_LENGTH_MASK 0x0000007f +#define HDA_PARAM_CONN_LIST_LENGTH_LIST_LENGTH_SHIFT 0 + +#define HDA_PARAM_CONN_LIST_LENGTH_LONG_FORM(param) \ + (((param) & HDA_PARAM_CONN_LIST_LENGTH_LONG_FORM_MASK) >> \ + HDA_PARAM_CONN_LIST_LENGTH_LONG_FORM_SHIFT) +#define HDA_PARAM_CONN_LIST_LENGTH_LIST_LENGTH(param) \ + (((param) & HDA_PARAM_CONN_LIST_LENGTH_LIST_LENGTH_MASK) >> \ + HDA_PARAM_CONN_LIST_LENGTH_LIST_LENGTH_SHIFT) + +/* Supported Power States */ +#define HDA_PARAM_SUPP_POWER_STATES 0x0f + +#define HDA_PARAM_SUPP_POWER_STATES_D3_MASK 0x00000008 +#define HDA_PARAM_SUPP_POWER_STATES_D3_SHIFT 3 +#define HDA_PARAM_SUPP_POWER_STATES_D2_MASK 0x00000004 +#define HDA_PARAM_SUPP_POWER_STATES_D2_SHIFT 2 +#define HDA_PARAM_SUPP_POWER_STATES_D1_MASK 0x00000002 +#define HDA_PARAM_SUPP_POWER_STATES_D1_SHIFT 1 +#define HDA_PARAM_SUPP_POWER_STATES_D0_MASK 0x00000001 +#define HDA_PARAM_SUPP_POWER_STATES_D0_SHIFT 0 + +#define HDA_PARAM_SUPP_POWER_STATES_D3(param) \ + (((param) & HDA_PARAM_SUPP_POWER_STATES_D3_MASK) >> \ + HDA_PARAM_SUPP_POWER_STATES_D3_SHIFT) +#define HDA_PARAM_SUPP_POWER_STATES_D2(param) \ + (((param) & HDA_PARAM_SUPP_POWER_STATES_D2_MASK) >> \ + HDA_PARAM_SUPP_POWER_STATES_D2_SHIFT) +#define HDA_PARAM_SUPP_POWER_STATES_D1(param) \ + (((param) & HDA_PARAM_SUPP_POWER_STATES_D1_MASK) >> \ + HDA_PARAM_SUPP_POWER_STATES_D1_SHIFT) +#define HDA_PARAM_SUPP_POWER_STATES_D0(param) \ + (((param) & HDA_PARAM_SUPP_POWER_STATES_D0_MASK) >> \ + HDA_PARAM_SUPP_POWER_STATES_D0_SHIFT) + +/* Processing Capabilities */ +#define HDA_PARAM_PROCESSING_CAP 0x10 + +#define HDA_PARAM_PROCESSING_CAP_NUMCOEFF_MASK 0x0000ff00 +#define HDA_PARAM_PROCESSING_CAP_NUMCOEFF_SHIFT 8 +#define HDA_PARAM_PROCESSING_CAP_BENIGN_MASK 0x00000001 +#define HDA_PARAM_PROCESSING_CAP_BENIGN_SHIFT 0 + +#define HDA_PARAM_PROCESSING_CAP_NUMCOEFF(param) \ + (((param) & HDA_PARAM_PROCESSING_CAP_NUMCOEFF_MASK) >> \ + HDA_PARAM_PROCESSING_CAP_NUMCOEFF_SHIFT) +#define HDA_PARAM_PROCESSING_CAP_BENIGN(param) \ + (((param) & HDA_PARAM_PROCESSING_CAP_BENIGN_MASK) >> \ + HDA_PARAM_PROCESSING_CAP_BENIGN_SHIFT) + +/* GPIO Count */ +#define HDA_PARAM_GPIO_COUNT 0x11 + +#define HDA_PARAM_GPIO_COUNT_GPI_WAKE_MASK 0x80000000 +#define HDA_PARAM_GPIO_COUNT_GPI_WAKE_SHIFT 31 +#define HDA_PARAM_GPIO_COUNT_GPI_UNSOL_MASK 0x40000000 +#define HDA_PARAM_GPIO_COUNT_GPI_UNSOL_SHIFT 30 +#define HDA_PARAM_GPIO_COUNT_NUM_GPI_MASK 0x00ff0000 +#define HDA_PARAM_GPIO_COUNT_NUM_GPI_SHIFT 16 +#define HDA_PARAM_GPIO_COUNT_NUM_GPO_MASK 0x0000ff00 +#define HDA_PARAM_GPIO_COUNT_NUM_GPO_SHIFT 8 +#define HDA_PARAM_GPIO_COUNT_NUM_GPIO_MASK 0x000000ff +#define HDA_PARAM_GPIO_COUNT_NUM_GPIO_SHIFT 0 + +#define HDA_PARAM_GPIO_COUNT_GPI_WAKE(param) \ + (((param) & HDA_PARAM_GPIO_COUNT_GPI_WAKE_MASK) >> \ + HDA_PARAM_GPIO_COUNT_GPI_WAKE_SHIFT) +#define HDA_PARAM_GPIO_COUNT_GPI_UNSOL(param) \ + (((param) & HDA_PARAM_GPIO_COUNT_GPI_UNSOL_MASK) >> \ + HDA_PARAM_GPIO_COUNT_GPI_UNSOL_SHIFT) +#define HDA_PARAM_GPIO_COUNT_NUM_GPI(param) \ + (((param) & HDA_PARAM_GPIO_COUNT_NUM_GPI_MASK) >> \ + HDA_PARAM_GPIO_COUNT_NUM_GPI_SHIFT) +#define HDA_PARAM_GPIO_COUNT_NUM_GPO(param) \ + (((param) & HDA_PARAM_GPIO_COUNT_NUM_GPO_MASK) >> \ + HDA_PARAM_GPIO_COUNT_NUM_GPO_SHIFT) +#define HDA_PARAM_GPIO_COUNT_NUM_GPIO(param) \ + (((param) & HDA_PARAM_GPIO_COUNT_NUM_GPIO_MASK) >> \ + HDA_PARAM_GPIO_COUNT_NUM_GPIO_SHIFT) + +/* Volume Knob Capabilities */ +#define HDA_PARAM_VOLUME_KNOB_CAP 0x13 + +#define HDA_PARAM_VOLUME_KNOB_CAP_DELTA_MASK 0x00000080 +#define HDA_PARAM_VOLUME_KNOB_CAP_DELTA_SHIFT 7 +#define HDA_PARAM_VOLUME_KNOB_CAP_NUM_STEPS_MASK 0x0000007f +#define HDA_PARAM_VOLUME_KNOB_CAP_NUM_STEPS_SHIFT 0 + +#define HDA_PARAM_VOLUME_KNOB_CAP_DELTA(param) \ + (((param) & HDA_PARAM_VOLUME_KNOB_CAP_DELTA_MASK) >> \ + HDA_PARAM_VOLUME_KNOB_CAP_DELTA_SHIFT) +#define HDA_PARAM_VOLUME_KNOB_CAP_NUM_STEPS(param) \ + (((param) & HDA_PARAM_VOLUME_KNOB_CAP_NUM_STEPS_MASK) >> \ + HDA_PARAM_VOLUME_KNOB_CAP_NUM_STEPS_SHIFT) + + +#define HDA_CONFIG_DEFAULTCONF_SEQUENCE_MASK 0x0000000f +#define HDA_CONFIG_DEFAULTCONF_SEQUENCE_SHIFT 0 +#define HDA_CONFIG_DEFAULTCONF_ASSOCIATION_MASK 0x000000f0 +#define HDA_CONFIG_DEFAULTCONF_ASSOCIATION_SHIFT 4 +#define HDA_CONFIG_DEFAULTCONF_MISC_MASK 0x00000f00 +#define HDA_CONFIG_DEFAULTCONF_MISC_SHIFT 8 +#define HDA_CONFIG_DEFAULTCONF_COLOR_MASK 0x0000f000 +#define HDA_CONFIG_DEFAULTCONF_COLOR_SHIFT 12 +#define HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_MASK 0x000f0000 +#define HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_SHIFT 16 +#define HDA_CONFIG_DEFAULTCONF_DEVICE_MASK 0x00f00000 +#define HDA_CONFIG_DEFAULTCONF_DEVICE_SHIFT 20 +#define HDA_CONFIG_DEFAULTCONF_LOCATION_MASK 0x3f000000 +#define HDA_CONFIG_DEFAULTCONF_LOCATION_SHIFT 24 +#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK 0xc0000000 +#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_SHIFT 30 + +#define HDA_CONFIG_DEFAULTCONF_SEQUENCE(conf) \ + (((conf) & HDA_CONFIG_DEFAULTCONF_SEQUENCE_MASK) >> \ + HDA_CONFIG_DEFAULTCONF_SEQUENCE_SHIFT) +#define HDA_CONFIG_DEFAULTCONF_ASSOCIATION(conf) \ + (((conf) & HDA_CONFIG_DEFAULTCONF_ASSOCIATION_MASK) >> \ + HDA_CONFIG_DEFAULTCONF_ASSOCIATION_SHIFT) +#define HDA_CONFIG_DEFAULTCONF_MISC(conf) \ + (((conf) & HDA_CONFIG_DEFAULTCONF_MISC_MASK) >> \ + HDA_CONFIG_DEFAULTCONF_MISC_SHIFT) +#define HDA_CONFIG_DEFAULTCONF_COLOR(conf) \ + (((conf) & HDA_CONFIG_DEFAULTCONF_COLOR_MASK) >> \ + HDA_CONFIG_DEFAULTCONF_COLOR_SHIFT) +#define HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE(conf) \ + (((conf) & HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_MASK) >> \ + HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_SHIFT) +#define HDA_CONFIG_DEFAULTCONF_DEVICE(conf) \ + (((conf) & HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) >> \ + HDA_CONFIG_DEFAULTCONF_DEVICE_SHIFT) +#define HDA_CONFIG_DEFAULTCONF_LOCATION(conf) \ + (((conf) & HDA_CONFIG_DEFAULTCONF_LOCATION_MASK) >> \ + HDA_CONFIG_DEFAULTCONF_LOCATION_SHIFT) +#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY(conf) \ + (((conf) & HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) >> \ + HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_SHIFT) + +#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK (0<<30) +#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE (1<<30) +#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED (2<<30) +#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_BOTH (3<<30) + +#define HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT (0<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_SPEAKER (1<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT (2<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_CD (3<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_OUT (4<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_OUT (5<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_MODEM_LINE (6<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_MODEM_HANDSET (7<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN (8<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_AUX (9<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN (10<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_TELEPHONY (11<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_IN (12<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_IN (13<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_OTHER (15<<20) + +#endif /* _HDA_REG_H_ */ diff --git a/usr.sbin/bhyve/hdac_reg.h b/usr.sbin/bhyve/hdac_reg.h new file mode 100644 index 000000000000..2bef0d0edc35 --- /dev/null +++ b/usr.sbin/bhyve/hdac_reg.h @@ -0,0 +1,269 @@ +/*- + * Copyright (c) 2006 Stephane E. Potvin + * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$ + */ + +#ifndef _HDAC_REG_H_ +#define _HDAC_REG_H_ + +/**************************************************************************** + * HDA Controller Register Set + ****************************************************************************/ +#define HDAC_GCAP 0x00 /* 2 - Global Capabilities*/ +#define HDAC_VMIN 0x02 /* 1 - Minor Version */ +#define HDAC_VMAJ 0x03 /* 1 - Major Version */ +#define HDAC_OUTPAY 0x04 /* 2 - Output Payload Capability */ +#define HDAC_INPAY 0x06 /* 2 - Input Payload Capability */ +#define HDAC_GCTL 0x08 /* 4 - Global Control */ +#define HDAC_WAKEEN 0x0c /* 2 - Wake Enable */ +#define HDAC_STATESTS 0x0e /* 2 - State Change Status */ +#define HDAC_GSTS 0x10 /* 2 - Global Status */ +#define HDAC_OUTSTRMPAY 0x18 /* 2 - Output Stream Payload Capability */ +#define HDAC_INSTRMPAY 0x1a /* 2 - Input Stream Payload Capability */ +#define HDAC_INTCTL 0x20 /* 4 - Interrupt Control */ +#define HDAC_INTSTS 0x24 /* 4 - Interrupt Status */ +#define HDAC_WALCLK 0x30 /* 4 - Wall Clock Counter */ +#define HDAC_SSYNC 0x38 /* 4 - Stream Synchronization */ +#define HDAC_CORBLBASE 0x40 /* 4 - CORB Lower Base Address */ +#define HDAC_CORBUBASE 0x44 /* 4 - CORB Upper Base Address */ +#define HDAC_CORBWP 0x48 /* 2 - CORB Write Pointer */ +#define HDAC_CORBRP 0x4a /* 2 - CORB Read Pointer */ +#define HDAC_CORBCTL 0x4c /* 1 - CORB Control */ +#define HDAC_CORBSTS 0x4d /* 1 - CORB Status */ +#define HDAC_CORBSIZE 0x4e /* 1 - CORB Size */ +#define HDAC_RIRBLBASE 0x50 /* 4 - RIRB Lower Base Address */ +#define HDAC_RIRBUBASE 0x54 /* 4 - RIRB Upper Base Address */ +#define HDAC_RIRBWP 0x58 /* 2 - RIRB Write Pointer */ +#define HDAC_RINTCNT 0x5a /* 2 - Response Interrupt Count */ +#define HDAC_RIRBCTL 0x5c /* 1 - RIRB Control */ +#define HDAC_RIRBSTS 0x5d /* 1 - RIRB Status */ +#define HDAC_RIRBSIZE 0x5e /* 1 - RIRB Size */ +#define HDAC_ICOI 0x60 /* 4 - Immediate Command Output Interface */ +#define HDAC_ICII 0x64 /* 4 - Immediate Command Input Interface */ +#define HDAC_ICIS 0x68 /* 2 - Immediate Command Status */ +#define HDAC_DPIBLBASE 0x70 /* 4 - DMA Position Buffer Lower Base */ +#define HDAC_DPIBUBASE 0x74 /* 4 - DMA Position Buffer Upper Base */ +#define HDAC_SDCTL0 0x80 /* 3 - Stream Descriptor Control */ +#define HDAC_SDCTL1 0x81 /* 3 - Stream Descriptor Control */ +#define HDAC_SDCTL2 0x82 /* 3 - Stream Descriptor Control */ +#define HDAC_SDSTS 0x83 /* 1 - Stream Descriptor Status */ +#define HDAC_SDLPIB 0x84 /* 4 - Link Position in Buffer */ +#define HDAC_SDCBL 0x88 /* 4 - Cyclic Buffer Length */ +#define HDAC_SDLVI 0x8C /* 2 - Last Valid Index */ +#define HDAC_SDFIFOS 0x90 /* 2 - FIFOS */ +#define HDAC_SDFMT 0x92 /* 2 - fmt */ +#define HDAC_SDBDPL 0x98 /* 4 - Buffer Descriptor Pointer Lower Base */ +#define HDAC_SDBDPU 0x9C /* 4 - Buffer Descriptor Pointer Upper Base */ + +#define _HDAC_ISDOFFSET(n, iss, oss) (0x80 + ((n) * 0x20)) +#define _HDAC_ISDCTL(n, iss, oss) (0x00 + _HDAC_ISDOFFSET(n, iss, oss)) +#define _HDAC_ISDSTS(n, iss, oss) (0x03 + _HDAC_ISDOFFSET(n, iss, oss)) +#define _HDAC_ISDPICB(n, iss, oss) (0x04 + _HDAC_ISDOFFSET(n, iss, oss)) +#define _HDAC_ISDCBL(n, iss, oss) (0x08 + _HDAC_ISDOFFSET(n, iss, oss)) +#define _HDAC_ISDLVI(n, iss, oss) (0x0c + _HDAC_ISDOFFSET(n, iss, oss)) +#define _HDAC_ISDFIFOD(n, iss, oss) (0x10 + _HDAC_ISDOFFSET(n, iss, oss)) +#define _HDAC_ISDFMT(n, iss, oss) (0x12 + _HDAC_ISDOFFSET(n, iss, oss)) +#define _HDAC_ISDBDPL(n, iss, oss) (0x18 + _HDAC_ISDOFFSET(n, iss, oss)) +#define _HDAC_ISDBDPU(n, iss, oss) (0x1c + _HDAC_ISDOFFSET(n, iss, oss)) + +#define _HDAC_OSDOFFSET(n, iss, oss) (0x80 + ((iss) * 0x20) + ((n) * 0x20)) +#define _HDAC_OSDCTL(n, iss, oss) (0x00 + _HDAC_OSDOFFSET(n, iss, oss)) +#define _HDAC_OSDSTS(n, iss, oss) (0x03 + _HDAC_OSDOFFSET(n, iss, oss)) +#define _HDAC_OSDPICB(n, iss, oss) (0x04 + _HDAC_OSDOFFSET(n, iss, oss)) +#define _HDAC_OSDCBL(n, iss, oss) (0x08 + _HDAC_OSDOFFSET(n, iss, oss)) +#define _HDAC_OSDLVI(n, iss, oss) (0x0c + _HDAC_OSDOFFSET(n, iss, oss)) +#define _HDAC_OSDFIFOD(n, iss, oss) (0x10 + _HDAC_OSDOFFSET(n, iss, oss)) +#define _HDAC_OSDFMT(n, iss, oss) (0x12 + _HDAC_OSDOFFSET(n, iss, oss)) +#define _HDAC_OSDBDPL(n, iss, oss) (0x18 + _HDAC_OSDOFFSET(n, iss, oss)) +#define _HDAC_OSDBDPU(n, iss, oss) (0x1c + _HDAC_OSDOFFSET(n, iss, oss)) + +#define _HDAC_BSDOFFSET(n, iss, oss) \ + (0x80 + ((iss) * 0x20) + ((oss) * 0x20) + ((n) * 0x20)) +#define _HDAC_BSDCTL(n, iss, oss) (0x00 + _HDAC_BSDOFFSET(n, iss, oss)) +#define _HDAC_BSDSTS(n, iss, oss) (0x03 + _HDAC_BSDOFFSET(n, iss, oss)) +#define _HDAC_BSDPICB(n, iss, oss) (0x04 + _HDAC_BSDOFFSET(n, iss, oss)) +#define _HDAC_BSDCBL(n, iss, oss) (0x08 + _HDAC_BSDOFFSET(n, iss, oss)) +#define _HDAC_BSDLVI(n, iss, oss) (0x0c + _HDAC_BSDOFFSET(n, iss, oss)) +#define _HDAC_BSDFIFOD(n, iss, oss) (0x10 + _HDAC_BSDOFFSET(n, iss, oss)) +#define _HDAC_BSDFMT(n, iss, oss) (0x12 + _HDAC_BSDOFFSET(n, iss, oss)) +#define _HDAC_BSDBDPL(n, iss, oss) (0x18 + _HDAC_BSDOFFSET(n, iss, oss)) +#define _HDAC_BSDBDBU(n, iss, oss) (0x1c + _HDAC_BSDOFFSET(n, iss, oss)) + +/**************************************************************************** + * HDA Controller Register Fields + ****************************************************************************/ + +/* GCAP - Global Capabilities */ +#define HDAC_GCAP_64OK 0x0001 +#define HDAC_GCAP_NSDO_MASK 0x0006 +#define HDAC_GCAP_NSDO_SHIFT 1 +#define HDAC_GCAP_BSS_MASK 0x00f8 +#define HDAC_GCAP_BSS_SHIFT 3 +#define HDAC_GCAP_ISS_MASK 0x0f00 +#define HDAC_GCAP_ISS_SHIFT 8 +#define HDAC_GCAP_OSS_MASK 0xf000 +#define HDAC_GCAP_OSS_SHIFT 12 + +#define HDAC_GCAP_NSDO_1SDO 0x00 +#define HDAC_GCAP_NSDO_2SDO 0x02 +#define HDAC_GCAP_NSDO_4SDO 0x04 + +#define HDAC_GCAP_BSS(gcap) \ + (((gcap) & HDAC_GCAP_BSS_MASK) >> HDAC_GCAP_BSS_SHIFT) +#define HDAC_GCAP_ISS(gcap) \ + (((gcap) & HDAC_GCAP_ISS_MASK) >> HDAC_GCAP_ISS_SHIFT) +#define HDAC_GCAP_OSS(gcap) \ + (((gcap) & HDAC_GCAP_OSS_MASK) >> HDAC_GCAP_OSS_SHIFT) +#define HDAC_GCAP_NSDO(gcap) \ + (((gcap) & HDAC_GCAP_NSDO_MASK) >> HDAC_GCAP_NSDO_SHIFT) + +/* GCTL - Global Control */ +#define HDAC_GCTL_CRST 0x00000001 +#define HDAC_GCTL_FCNTRL 0x00000002 +#define HDAC_GCTL_UNSOL 0x00000100 + +/* WAKEEN - Wake Enable */ +#define HDAC_WAKEEN_SDIWEN_MASK 0x7fff +#define HDAC_WAKEEN_SDIWEN_SHIFT 0 + +/* STATESTS - State Change Status */ +#define HDAC_STATESTS_SDIWAKE_MASK 0x7fff +#define HDAC_STATESTS_SDIWAKE_SHIFT 0 + +#define HDAC_STATESTS_SDIWAKE(statests, n) \ + (((((statests) & HDAC_STATESTS_SDIWAKE_MASK) >> \ + HDAC_STATESTS_SDIWAKE_SHIFT) >> (n)) & 0x0001) + +/* GSTS - Global Status */ +#define HDAC_GSTS_FSTS 0x0002 + +/* INTCTL - Interrut Control */ +#define HDAC_INTCTL_SIE_MASK 0x3fffffff +#define HDAC_INTCTL_SIE_SHIFT 0 +#define HDAC_INTCTL_CIE 0x40000000 +#define HDAC_INTCTL_GIE 0x80000000 + +/* INTSTS - Interrupt Status */ +#define HDAC_INTSTS_SIS_MASK 0x3fffffff +#define HDAC_INTSTS_SIS_SHIFT 0 +#define HDAC_INTSTS_CIS 0x40000000 +#define HDAC_INTSTS_GIS 0x80000000 + +/* SSYNC - Stream Synchronization */ +#define HDAC_SSYNC_SSYNC_MASK 0x3fffffff +#define HDAC_SSYNC_SSYNC_SHIFT 0 + +/* CORBWP - CORB Write Pointer */ +#define HDAC_CORBWP_CORBWP_MASK 0x00ff +#define HDAC_CORBWP_CORBWP_SHIFT 0 + +/* CORBRP - CORB Read Pointer */ +#define HDAC_CORBRP_CORBRP_MASK 0x00ff +#define HDAC_CORBRP_CORBRP_SHIFT 0 +#define HDAC_CORBRP_CORBRPRST 0x8000 + +/* CORBCTL - CORB Control */ +#define HDAC_CORBCTL_CMEIE 0x01 +#define HDAC_CORBCTL_CORBRUN 0x02 + +/* CORBSTS - CORB Status */ +#define HDAC_CORBSTS_CMEI 0x01 + +/* CORBSIZE - CORB Size */ +#define HDAC_CORBSIZE_CORBSIZE_MASK 0x03 +#define HDAC_CORBSIZE_CORBSIZE_SHIFT 0 +#define HDAC_CORBSIZE_CORBSZCAP_MASK 0xf0 +#define HDAC_CORBSIZE_CORBSZCAP_SHIFT 4 + +#define HDAC_CORBSIZE_CORBSIZE_2 0x00 +#define HDAC_CORBSIZE_CORBSIZE_16 0x01 +#define HDAC_CORBSIZE_CORBSIZE_256 0x02 + +#define HDAC_CORBSIZE_CORBSZCAP_2 0x10 +#define HDAC_CORBSIZE_CORBSZCAP_16 0x20 +#define HDAC_CORBSIZE_CORBSZCAP_256 0x40 + +#define HDAC_CORBSIZE_CORBSIZE(corbsize) \ + (((corbsize) & HDAC_CORBSIZE_CORBSIZE_MASK) >> HDAC_CORBSIZE_CORBSIZE_SHIFT) + +/* RIRBWP - RIRB Write Pointer */ +#define HDAC_RIRBWP_RIRBWP_MASK 0x00ff +#define HDAC_RIRBWP_RIRBWP_SHIFT 0 +#define HDAC_RIRBWP_RIRBWPRST 0x8000 + +/* RINTCTN - Response Interrupt Count */ +#define HDAC_RINTCNT_MASK 0x00ff +#define HDAC_RINTCNT_SHIFT 0 + +/* RIRBCTL - RIRB Control */ +#define HDAC_RIRBCTL_RINTCTL 0x01 +#define HDAC_RIRBCTL_RIRBDMAEN 0x02 +#define HDAC_RIRBCTL_RIRBOIC 0x04 + +/* RIRBSTS - RIRB Status */ +#define HDAC_RIRBSTS_RINTFL 0x01 +#define HDAC_RIRBSTS_RIRBOIS 0x04 + +/* RIRBSIZE - RIRB Size */ +#define HDAC_RIRBSIZE_RIRBSIZE_MASK 0x03 +#define HDAC_RIRBSIZE_RIRBSIZE_SHIFT 0 +#define HDAC_RIRBSIZE_RIRBSZCAP_MASK 0xf0 +#define HDAC_RIRBSIZE_RIRBSZCAP_SHIFT 4 + +#define HDAC_RIRBSIZE_RIRBSIZE_2 0x00 +#define HDAC_RIRBSIZE_RIRBSIZE_16 0x01 +#define HDAC_RIRBSIZE_RIRBSIZE_256 0x02 + +#define HDAC_RIRBSIZE_RIRBSZCAP_2 0x10 +#define HDAC_RIRBSIZE_RIRBSZCAP_16 0x20 +#define HDAC_RIRBSIZE_RIRBSZCAP_256 0x40 + +#define HDAC_RIRBSIZE_RIRBSIZE(rirbsize) \ + (((rirbsize) & HDAC_RIRBSIZE_RIRBSIZE_MASK) >> HDAC_RIRBSIZE_RIRBSIZE_SHIFT) + +/* DPLBASE - DMA Position Lower Base Address */ +#define HDAC_DPLBASE_DPLBASE_MASK 0xffffff80 +#define HDAC_DPLBASE_DPLBASE_SHIFT 7 +#define HDAC_DPLBASE_DPLBASE_DMAPBE 0x00000001 + +/* SDCTL - Stream Descriptor Control */ +#define HDAC_SDCTL_SRST 0x000001 +#define HDAC_SDCTL_RUN 0x000002 +#define HDAC_SDCTL_IOCE 0x000004 +#define HDAC_SDCTL_FEIE 0x000008 +#define HDAC_SDCTL_DEIE 0x000010 +#define HDAC_SDCTL2_STRIPE_MASK 0x03 +#define HDAC_SDCTL2_STRIPE_SHIFT 0 +#define HDAC_SDCTL2_TP 0x04 +#define HDAC_SDCTL2_DIR 0x08 +#define HDAC_SDCTL2_STRM_MASK 0xf0 +#define HDAC_SDCTL2_STRM_SHIFT 4 + +#define HDAC_SDSTS_DESE (1 << 4) +#define HDAC_SDSTS_FIFOE (1 << 3) +#define HDAC_SDSTS_BCIS (1 << 2) + +#endif /* _HDAC_REG_H_ */ diff --git a/usr.sbin/bhyve/pci_hda.c b/usr.sbin/bhyve/pci_hda.c new file mode 100644 index 000000000000..99f8aec31c6e --- /dev/null +++ b/usr.sbin/bhyve/pci_hda.c @@ -0,0 +1,1330 @@ +/*- + * Copyright (c) 2016 Alex Teaca + * 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, 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 OR CONTRIBUTORS 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 + +#include "pci_hda.h" +#include "bhyverun.h" +#include "pci_emul.h" +#include "hdac_reg.h" + +/* + * HDA defines + */ +#define PCIR_HDCTL 0x40 +#define INTEL_VENDORID 0x8086 +#define HDA_INTEL_82801G 0x27d8 + +#define HDA_IOSS_NO 0x08 +#define HDA_OSS_NO 0x04 +#define HDA_ISS_NO 0x04 +#define HDA_CODEC_MAX 0x0f +#define HDA_LAST_OFFSET \ + (0x2084 + ((HDA_ISS_NO) * 0x20) + ((HDA_OSS_NO) * 0x20)) +#define HDA_SET_REG_TABLE_SZ \ + (0x80 + ((HDA_ISS_NO) * 0x20) + ((HDA_OSS_NO) * 0x20)) +#define HDA_CORB_ENTRY_LEN 0x04 +#define HDA_RIRB_ENTRY_LEN 0x08 +#define HDA_BDL_ENTRY_LEN 0x10 +#define HDA_DMA_PIB_ENTRY_LEN 0x08 +#define HDA_STREAM_TAGS_CNT 0x10 +#define HDA_STREAM_REGS_BASE 0x80 +#define HDA_STREAM_REGS_LEN 0x20 + +#define HDA_DMA_ACCESS_LEN (sizeof(uint32_t)) +#define HDA_BDL_MAX_LEN 0x0100 + +#define HDAC_SDSTS_FIFORDY (1 << 5) + +#define HDA_RIRBSTS_IRQ_MASK (HDAC_RIRBSTS_RINTFL | HDAC_RIRBSTS_RIRBOIS) +#define HDA_STATESTS_IRQ_MASK ((1 << HDA_CODEC_MAX) - 1) +#define HDA_SDSTS_IRQ_MASK \ + (HDAC_SDSTS_DESE | HDAC_SDSTS_FIFOE | HDAC_SDSTS_BCIS) + +/* + * HDA data structures + */ + +struct hda_softc; + +typedef void (*hda_set_reg_handler)(struct hda_softc *sc, uint32_t offset, + uint32_t old); + +struct hda_bdle { + uint32_t addrh; + uint32_t addrl; + uint32_t ioc; + uint32_t len; +} __packed; + +struct hda_bdle_desc { + void *addr; + uint8_t ioc; + uint32_t len; +}; + +struct hda_codec_cmd_ctl { + char *name; + void *dma_vaddr; + uint8_t run; + uint16_t rp; + uint16_t size; + uint16_t wp; +}; + +struct hda_stream_desc { + uint8_t dir; + uint8_t run; + uint8_t stream; + + /* bp is the no. of bytes transferred in the current bdle */ + uint32_t bp; + /* be is the no. of bdles transferred in the bdl */ + uint32_t be; + + uint32_t bdl_cnt; + struct hda_bdle_desc bdl[HDA_BDL_MAX_LEN]; +}; + +struct hda_softc { + struct pci_devinst *pci_dev; + uint32_t regs[HDA_LAST_OFFSET]; + + uint8_t lintr; + uint8_t rirb_cnt; + uint64_t wall_clock_start; + + struct hda_codec_cmd_ctl corb; + struct hda_codec_cmd_ctl rirb; + + uint8_t codecs_no; + struct hda_codec_inst *codecs[HDA_CODEC_MAX]; + + /* Base Address of the DMA Position Buffer */ + void *dma_pib_vaddr; + + struct hda_stream_desc streams[HDA_IOSS_NO]; + /* 2 tables for output and input */ + uint8_t stream_map[2][HDA_STREAM_TAGS_CNT]; +}; + +/* + * HDA module function declarations + */ +static inline void hda_set_reg_by_offset(struct hda_softc *sc, uint32_t offset, + uint32_t value); +static inline uint32_t hda_get_reg_by_offset(struct hda_softc *sc, + uint32_t offset); +static inline void hda_set_field_by_offset(struct hda_softc *sc, + uint32_t offset, uint32_t mask, uint32_t value); + +static uint8_t hda_parse_config(const char *opts, const char *key, char *val); +static struct hda_softc *hda_init(const char *opts); +static void hda_update_intr(struct hda_softc *sc); +static void hda_response_interrupt(struct hda_softc *sc); +static int hda_codec_constructor(struct hda_softc *sc, + struct hda_codec_class *codec, const char *play, const char *rec, + const char *opts); +static struct hda_codec_class *hda_find_codec_class(const char *name); + +static int hda_send_command(struct hda_softc *sc, uint32_t verb); +static int hda_notify_codecs(struct hda_softc *sc, uint8_t run, + uint8_t stream, uint8_t dir); +static void hda_reset(struct hda_softc *sc); +static void hda_reset_regs(struct hda_softc *sc); +static void hda_stream_reset(struct hda_softc *sc, uint8_t stream_ind); +static int hda_stream_start(struct hda_softc *sc, uint8_t stream_ind); +static int hda_stream_stop(struct hda_softc *sc, uint8_t stream_ind); +static uint32_t hda_read(struct hda_softc *sc, uint32_t offset); +static int hda_write(struct hda_softc *sc, uint32_t offset, uint8_t size, + uint32_t value); + +static inline void hda_print_cmd_ctl_data(struct hda_codec_cmd_ctl *p); +static int hda_corb_start(struct hda_softc *sc); +static int hda_corb_run(struct hda_softc *sc); +static int hda_rirb_start(struct hda_softc *sc); + +static void *hda_dma_get_vaddr(struct hda_softc *sc, uint64_t dma_paddr, + size_t len); +static void hda_dma_st_dword(void *dma_vaddr, uint32_t data); +static uint32_t hda_dma_ld_dword(void *dma_vaddr); + +static inline uint8_t hda_get_stream_by_offsets(uint32_t offset, + uint8_t reg_offset); +static inline uint32_t hda_get_offset_stream(uint8_t stream_ind); + +static void hda_set_gctl(struct hda_softc *sc, uint32_t offset, uint32_t old); +static void hda_set_statests(struct hda_softc *sc, uint32_t offset, + uint32_t old); +static void hda_set_corbwp(struct hda_softc *sc, uint32_t offset, uint32_t old); +static void hda_set_corbctl(struct hda_softc *sc, uint32_t offset, + uint32_t old); +static void hda_set_rirbctl(struct hda_softc *sc, uint32_t offset, + uint32_t old); +static void hda_set_rirbsts(struct hda_softc *sc, uint32_t offset, + uint32_t old); +static void hda_set_dpiblbase(struct hda_softc *sc, uint32_t offset, + uint32_t old); +static void hda_set_sdctl(struct hda_softc *sc, uint32_t offset, uint32_t old); +static void hda_set_sdctl2(struct hda_softc *sc, uint32_t offset, uint32_t old); +static void hda_set_sdsts(struct hda_softc *sc, uint32_t offset, uint32_t old); + +static int hda_signal_state_change(struct hda_codec_inst *hci); +static int hda_response(struct hda_codec_inst *hci, uint32_t response, + uint8_t unsol); +static int hda_transfer(struct hda_codec_inst *hci, uint8_t stream, + uint8_t dir, void *buf, size_t count); + +static void hda_set_pib(struct hda_softc *sc, uint8_t stream_ind, uint32_t pib); +static uint64_t hda_get_clock_ns(void); + +/* + * PCI HDA function declarations + */ +static int pci_hda_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts); +static void pci_hda_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, + int baridx, uint64_t offset, int size, uint64_t value); +static uint64_t pci_hda_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, + int baridx, uint64_t offset, int size); +/* + * HDA global data + */ + +static const hda_set_reg_handler hda_set_reg_table[] = { + [HDAC_GCTL] = hda_set_gctl, + [HDAC_STATESTS] = hda_set_statests, + [HDAC_CORBWP] = hda_set_corbwp, + [HDAC_CORBCTL] = hda_set_corbctl, + [HDAC_RIRBCTL] = hda_set_rirbctl, + [HDAC_RIRBSTS] = hda_set_rirbsts, + [HDAC_DPIBLBASE] = hda_set_dpiblbase, + +#define HDAC_ISTREAM(n, iss, oss) \ + [_HDAC_ISDCTL(n, iss, oss)] = hda_set_sdctl, \ + [_HDAC_ISDCTL(n, iss, oss) + 2] = hda_set_sdctl2, \ + [_HDAC_ISDSTS(n, iss, oss)] = hda_set_sdsts, \ + +#define HDAC_OSTREAM(n, iss, oss) \ + [_HDAC_OSDCTL(n, iss, oss)] = hda_set_sdctl, \ + [_HDAC_OSDCTL(n, iss, oss) + 2] = hda_set_sdctl2, \ + [_HDAC_OSDSTS(n, iss, oss)] = hda_set_sdsts, \ + + HDAC_ISTREAM(0, HDA_ISS_NO, HDA_OSS_NO) + HDAC_ISTREAM(1, HDA_ISS_NO, HDA_OSS_NO) + HDAC_ISTREAM(2, HDA_ISS_NO, HDA_OSS_NO) + HDAC_ISTREAM(3, HDA_ISS_NO, HDA_OSS_NO) + + HDAC_OSTREAM(0, HDA_ISS_NO, HDA_OSS_NO) + HDAC_OSTREAM(1, HDA_ISS_NO, HDA_OSS_NO) + HDAC_OSTREAM(2, HDA_ISS_NO, HDA_OSS_NO) + HDAC_OSTREAM(3, HDA_ISS_NO, HDA_OSS_NO) + + [HDA_SET_REG_TABLE_SZ] = NULL, +}; + +static const uint16_t hda_corb_sizes[] = { + [HDAC_CORBSIZE_CORBSIZE_2] = 2, + [HDAC_CORBSIZE_CORBSIZE_16] = 16, + [HDAC_CORBSIZE_CORBSIZE_256] = 256, + [HDAC_CORBSIZE_CORBSIZE_MASK] = 0, +}; + +static const uint16_t hda_rirb_sizes[] = { + [HDAC_RIRBSIZE_RIRBSIZE_2] = 2, + [HDAC_RIRBSIZE_RIRBSIZE_16] = 16, + [HDAC_RIRBSIZE_RIRBSIZE_256] = 256, + [HDAC_RIRBSIZE_RIRBSIZE_MASK] = 0, +}; + +static struct hda_ops hops = { + .signal = hda_signal_state_change, + .response = hda_response, + .transfer = hda_transfer, +}; + +struct pci_devemu pci_de_hda = { + .pe_emu = "hda", + .pe_init = pci_hda_init, + .pe_barwrite = pci_hda_write, + .pe_barread = pci_hda_read +}; + +PCI_EMUL_SET(pci_de_hda); + +SET_DECLARE(hda_codec_class_set, struct hda_codec_class); + +#if DEBUG_HDA == 1 +FILE *dbg; +#endif + +/* + * HDA module function definitions + */ + +static inline void +hda_set_reg_by_offset(struct hda_softc *sc, uint32_t offset, uint32_t value) +{ + assert(offset < HDA_LAST_OFFSET); + sc->regs[offset] = value; +} + +static inline uint32_t +hda_get_reg_by_offset(struct hda_softc *sc, uint32_t offset) +{ + assert(offset < HDA_LAST_OFFSET); + return sc->regs[offset]; +} + +static inline void +hda_set_field_by_offset(struct hda_softc *sc, uint32_t offset, + uint32_t mask, uint32_t value) +{ + uint32_t reg_value = 0; + + reg_value = hda_get_reg_by_offset(sc, offset); + + reg_value &= ~mask; + reg_value |= (value & mask); + + hda_set_reg_by_offset(sc, offset, reg_value); +} + +static uint8_t +hda_parse_config(const char *opts, const char *key, char *val) +{ + char buf[64]; + char *s = buf; + char *tmp = NULL; + int len; + int i; + + if (!opts) + return (0); + + len = strlen(opts); + + if (len >= 64) { + DPRINTF("Opts too big\n"); + return (0); + } + + DPRINTF("opts: %s\n", opts); + + strcpy(buf, opts); + + for (i = 0; i < len; i++) + if (buf[i] == ',') { + buf[i] = 0; + tmp = buf + i + 1; + break; + } + + if (!memcmp(s, key, strlen(key))) { + strncpy(val, s + strlen(key), 64); + return (1); + } + + if (!tmp) + return (0); + + s = tmp; + if (!memcmp(s, key, strlen(key))) { + strncpy(val, s + strlen(key), 64); + return (1); + } + + return (0); +} + +static struct hda_softc * +hda_init(const char *opts) +{ + struct hda_softc *sc = NULL; + struct hda_codec_class *codec = NULL; + char play[64]; + char rec[64]; + int err, p, r; + +#if DEBUG_HDA == 1 + dbg = fopen("/tmp/bhyve_hda.log", "w+"); +#endif + + DPRINTF("opts: %s\n", opts); + + sc = calloc(1, sizeof(*sc)); + if (!sc) + return (NULL); + + hda_reset_regs(sc); + + /* + * TODO search all the codecs declared in opts + * For now we play with one single codec + */ + codec = hda_find_codec_class("hda_codec"); + if (codec) { + p = hda_parse_config(opts, "play=", play); + r = hda_parse_config(opts, "rec=", rec); + DPRINTF("play: %s rec: %s\n", play, rec); + if (p | r) { + err = hda_codec_constructor(sc, codec, p ? \ + play : NULL, r ? rec : NULL, NULL); + assert(!err); + } + } + + return (sc); +} + +static void +hda_update_intr(struct hda_softc *sc) +{ + struct pci_devinst *pi = sc->pci_dev; + uint32_t intctl = hda_get_reg_by_offset(sc, HDAC_INTCTL); + uint32_t intsts = 0; + uint32_t sdsts = 0; + uint32_t rirbsts = 0; + uint32_t wakeen = 0; + uint32_t statests = 0; + uint32_t off = 0; + int i; + + /* update the CIS bits */ + rirbsts = hda_get_reg_by_offset(sc, HDAC_RIRBSTS); + if (rirbsts & (HDAC_RIRBSTS_RINTFL | HDAC_RIRBSTS_RIRBOIS)) + intsts |= HDAC_INTSTS_CIS; + + wakeen = hda_get_reg_by_offset(sc, HDAC_WAKEEN); + statests = hda_get_reg_by_offset(sc, HDAC_STATESTS); + if (statests & wakeen) + intsts |= HDAC_INTSTS_CIS; + + /* update the SIS bits */ + for (i = 0; i < HDA_IOSS_NO; i++) { + off = hda_get_offset_stream(i); + sdsts = hda_get_reg_by_offset(sc, off + HDAC_SDSTS); + if (sdsts & HDAC_SDSTS_BCIS) + intsts |= (1 << i); + } + + /* update the GIS bit */ + if (intsts) + intsts |= HDAC_INTSTS_GIS; + + hda_set_reg_by_offset(sc, HDAC_INTSTS, intsts); + + if ((intctl & HDAC_INTCTL_GIE) && ((intsts & \ + ~HDAC_INTSTS_GIS) & intctl)) { + if (!sc->lintr) { + pci_lintr_assert(pi); + sc->lintr = 1; + } + } else { + if (sc->lintr) { + pci_lintr_deassert(pi); + sc->lintr = 0; + } + } +} + +static void +hda_response_interrupt(struct hda_softc *sc) +{ + uint8_t rirbctl = hda_get_reg_by_offset(sc, HDAC_RIRBCTL); + + if ((rirbctl & HDAC_RIRBCTL_RINTCTL) && sc->rirb_cnt) { + sc->rirb_cnt = 0; + hda_set_field_by_offset(sc, HDAC_RIRBSTS, HDAC_RIRBSTS_RINTFL, + HDAC_RIRBSTS_RINTFL); + hda_update_intr(sc); + } +} + +static int +hda_codec_constructor(struct hda_softc *sc, struct hda_codec_class *codec, + const char *play, const char *rec, const char *opts) +{ + struct hda_codec_inst *hci = NULL; + + if (sc->codecs_no >= HDA_CODEC_MAX) + return (-1); + + hci = calloc(1, sizeof(struct hda_codec_inst)); + if (!hci) + return (-1); + + hci->hda = sc; + hci->hops = &hops; + hci->cad = sc->codecs_no; + hci->codec = codec; + + sc->codecs[sc->codecs_no++] = hci; + + if (!codec->init) { + DPRINTF("This codec does not implement the init function\n"); + return (-1); + } + + return (codec->init(hci, play, rec, opts)); +} + +static struct hda_codec_class * +hda_find_codec_class(const char *name) +{ + struct hda_codec_class **pdpp = NULL, *pdp = NULL; + + SET_FOREACH(pdpp, hda_codec_class_set) { + pdp = *pdpp; + if (!strcmp(pdp->name, name)) { + return (pdp); + } + } + + return (NULL); +} + +static int +hda_send_command(struct hda_softc *sc, uint32_t verb) +{ + struct hda_codec_inst *hci = NULL; + struct hda_codec_class *codec = NULL; + uint8_t cad = (verb >> HDA_CMD_CAD_SHIFT) & 0x0f; + + hci = sc->codecs[cad]; + if (!hci) + return (-1); + + DPRINTF("cad: 0x%x verb: 0x%x\n", cad, verb); + + codec = hci->codec; + assert(codec); + + if (!codec->command) { + DPRINTF("This codec does not implement the command function\n"); + return (-1); + } + + return (codec->command(hci, verb)); +} + +static int +hda_notify_codecs(struct hda_softc *sc, uint8_t run, uint8_t stream, + uint8_t dir) +{ + struct hda_codec_inst *hci = NULL; + struct hda_codec_class *codec = NULL; + int err; + int i; + + /* Notify each codec */ + for (i = 0; i < sc->codecs_no; i++) { + hci = sc->codecs[i]; + assert(hci); + + codec = hci->codec; + assert(codec); + + if (codec->notify) { + err = codec->notify(hci, run, stream, dir); + if (!err) + break; + } + } + + return (i == sc->codecs_no ? (-1) : 0); +} + +static void +hda_reset(struct hda_softc *sc) +{ + int i; + struct hda_codec_inst *hci = NULL; + struct hda_codec_class *codec = NULL; + + hda_reset_regs(sc); + + /* Reset each codec */ + for (i = 0; i < sc->codecs_no; i++) { + hci = sc->codecs[i]; + assert(hci); + + codec = hci->codec; + assert(codec); + + if (codec->reset) + codec->reset(hci); + } + + sc->wall_clock_start = hda_get_clock_ns(); +} + +static void +hda_reset_regs(struct hda_softc *sc) +{ + uint32_t off = 0; + uint8_t i; + + DPRINTF("Reset the HDA controller registers ...\n"); + + memset(sc->regs, 0, sizeof(sc->regs)); + + hda_set_reg_by_offset(sc, HDAC_GCAP, + HDAC_GCAP_64OK | + (HDA_ISS_NO << HDAC_GCAP_ISS_SHIFT) | + (HDA_OSS_NO << HDAC_GCAP_OSS_SHIFT)); + hda_set_reg_by_offset(sc, HDAC_VMAJ, 0x01); + hda_set_reg_by_offset(sc, HDAC_OUTPAY, 0x3c); + hda_set_reg_by_offset(sc, HDAC_INPAY, 0x1d); + hda_set_reg_by_offset(sc, HDAC_CORBSIZE, + HDAC_CORBSIZE_CORBSZCAP_256 | HDAC_CORBSIZE_CORBSIZE_256); + hda_set_reg_by_offset(sc, HDAC_RIRBSIZE, + HDAC_RIRBSIZE_RIRBSZCAP_256 | HDAC_RIRBSIZE_RIRBSIZE_256); + + for (i = 0; i < HDA_IOSS_NO; i++) { + off = hda_get_offset_stream(i); + hda_set_reg_by_offset(sc, off + HDAC_SDFIFOS, HDA_FIFO_SIZE); + } +} + +static void +hda_stream_reset(struct hda_softc *sc, uint8_t stream_ind) +{ + struct hda_stream_desc *st = &sc->streams[stream_ind]; + uint32_t off = hda_get_offset_stream(stream_ind); + + DPRINTF("Reset the HDA stream: 0x%x\n", stream_ind); + + /* Reset the Stream Descriptor registers */ + memset(sc->regs + HDA_STREAM_REGS_BASE + off, 0, HDA_STREAM_REGS_LEN); + + /* Reset the Stream Descriptor */ + memset(st, 0, sizeof(*st)); + + hda_set_field_by_offset(sc, off + HDAC_SDSTS, + HDAC_SDSTS_FIFORDY, HDAC_SDSTS_FIFORDY); + hda_set_field_by_offset(sc, off + HDAC_SDCTL0, + HDAC_SDCTL_SRST, HDAC_SDCTL_SRST); +} + +static int +hda_stream_start(struct hda_softc *sc, uint8_t stream_ind) +{ + struct hda_stream_desc *st = &sc->streams[stream_ind]; + struct hda_bdle_desc *bdle_desc = NULL; + struct hda_bdle *bdle = NULL; + uint32_t lvi = 0; + uint32_t bdl_cnt = 0; + uint64_t bdpl = 0; + uint64_t bdpu = 0; + uint64_t bdl_paddr = 0; + void *bdl_vaddr = NULL; + uint32_t bdle_sz = 0; + uint64_t bdle_addrl = 0; + uint64_t bdle_addrh = 0; + uint64_t bdle_paddr = 0; + void *bdle_vaddr = NULL; + uint32_t off = hda_get_offset_stream(stream_ind); + uint32_t sdctl = 0; + uint8_t strm = 0; + uint8_t dir = 0; + int i; + + assert(!st->run); + + lvi = hda_get_reg_by_offset(sc, off + HDAC_SDLVI); + bdpl = hda_get_reg_by_offset(sc, off + HDAC_SDBDPL); + bdpu = hda_get_reg_by_offset(sc, off + HDAC_SDBDPU); + + bdl_cnt = lvi + 1; + assert(bdl_cnt <= HDA_BDL_MAX_LEN); + + bdl_paddr = bdpl | (bdpu << 32); + bdl_vaddr = hda_dma_get_vaddr(sc, bdl_paddr, + HDA_BDL_ENTRY_LEN * bdl_cnt); + if (!bdl_vaddr) { + DPRINTF("Fail to get the guest virtual address\n"); + return (-1); + } + + DPRINTF("stream: 0x%x bdl_cnt: 0x%x bdl_paddr: 0x%lx\n", + stream_ind, bdl_cnt, bdl_paddr); + + st->bdl_cnt = bdl_cnt; + + bdle = (struct hda_bdle *)bdl_vaddr; + for (i = 0; i < bdl_cnt; i++, bdle++) { + bdle_sz = bdle->len; + assert(!(bdle_sz % HDA_DMA_ACCESS_LEN)); + + bdle_addrl = bdle->addrl; + bdle_addrh = bdle->addrh; + + bdle_paddr = bdle_addrl | (bdle_addrh << 32); + bdle_vaddr = hda_dma_get_vaddr(sc, bdle_paddr, bdle_sz); + if (!bdle_vaddr) { + DPRINTF("Fail to get the guest virtual address\n"); + return (-1); + } + + bdle_desc = &st->bdl[i]; + bdle_desc->addr = bdle_vaddr; + bdle_desc->len = bdle_sz; + bdle_desc->ioc = bdle->ioc; + + DPRINTF("bdle: 0x%x bdle_sz: 0x%x\n", i, bdle_sz); + } + + sdctl = hda_get_reg_by_offset(sc, off + HDAC_SDCTL0); + strm = (sdctl >> 20) & 0x0f; + dir = stream_ind >= HDA_ISS_NO; + + DPRINTF("strm: 0x%x, dir: 0x%x\n", strm, dir); + + sc->stream_map[dir][strm] = stream_ind; + st->stream = strm; + st->dir = dir; + st->bp = 0; + st->be = 0; + + hda_set_pib(sc, stream_ind, 0); + + st->run = 1; + + hda_notify_codecs(sc, 1, strm, dir); + + return (0); +} + +static int +hda_stream_stop(struct hda_softc *sc, uint8_t stream_ind) +{ + struct hda_stream_desc *st = &sc->streams[stream_ind]; + uint8_t strm = st->stream; + uint8_t dir = st->dir; + + DPRINTF("stream: 0x%x, strm: 0x%x, dir: 0x%x\n", stream_ind, strm, dir); + + st->run = 0; + + hda_notify_codecs(sc, 0, strm, dir); + + return (0); +} + +static uint32_t +hda_read(struct hda_softc *sc, uint32_t offset) +{ + if (offset == HDAC_WALCLK) + return (24 * (hda_get_clock_ns() - \ + sc->wall_clock_start) / 1000); + + return (hda_get_reg_by_offset(sc, offset)); +} + +static int +hda_write(struct hda_softc *sc, uint32_t offset, uint8_t size, uint32_t value) +{ + uint32_t old = hda_get_reg_by_offset(sc, offset); + uint32_t masks[] = {0x00000000, 0x000000ff, 0x0000ffff, + 0x00ffffff, 0xffffffff}; + hda_set_reg_handler set_reg_handler = hda_set_reg_table[offset]; + + hda_set_field_by_offset(sc, offset, masks[size], value); + + if (set_reg_handler) + set_reg_handler(sc, offset, old); + + return (0); +} + +static inline void +hda_print_cmd_ctl_data(struct hda_codec_cmd_ctl *p) +{ +#if DEBUG_HDA == 1 + char *name = p->name; +#endif + DPRINTF("%s size: %d\n", name, p->size); + DPRINTF("%s dma_vaddr: %p\n", name, p->dma_vaddr); + DPRINTF("%s wp: 0x%x\n", name, p->wp); + DPRINTF("%s rp: 0x%x\n", name, p->rp); +} + +static int +hda_corb_start(struct hda_softc *sc) +{ + struct hda_codec_cmd_ctl *corb = &sc->corb; + uint8_t corbsize = 0; + uint64_t corblbase = 0; + uint64_t corbubase = 0; + uint64_t corbpaddr = 0; + + corb->name = "CORB"; + + corbsize = hda_get_reg_by_offset(sc, HDAC_CORBSIZE) & \ + HDAC_CORBSIZE_CORBSIZE_MASK; + corb->size = hda_corb_sizes[corbsize]; + + if (!corb->size) { + DPRINTF("Invalid corb size\n"); + return (-1); + } + + corblbase = hda_get_reg_by_offset(sc, HDAC_CORBLBASE); + corbubase = hda_get_reg_by_offset(sc, HDAC_CORBUBASE); + + corbpaddr = corblbase | (corbubase << 32); + DPRINTF("CORB dma_paddr: %p\n", (void *)corbpaddr); + + corb->dma_vaddr = hda_dma_get_vaddr(sc, corbpaddr, + HDA_CORB_ENTRY_LEN * corb->size); + if (!corb->dma_vaddr) { + DPRINTF("Fail to get the guest virtual address\n"); + return (-1); + } + + corb->wp = hda_get_reg_by_offset(sc, HDAC_CORBWP); + corb->rp = hda_get_reg_by_offset(sc, HDAC_CORBRP); + + corb->run = 1; + + hda_print_cmd_ctl_data(corb); + + return (0); +} + +static int +hda_corb_run(struct hda_softc *sc) +{ + struct hda_codec_cmd_ctl *corb = &sc->corb; + uint32_t verb = 0; + int err; + + corb->wp = hda_get_reg_by_offset(sc, HDAC_CORBWP); + + while (corb->rp != corb->wp && corb->run) { + corb->rp++; + corb->rp %= corb->size; + + verb = hda_dma_ld_dword(corb->dma_vaddr + \ + HDA_CORB_ENTRY_LEN * corb->rp); + + err = hda_send_command(sc, verb); + assert(!err); + } + + hda_set_reg_by_offset(sc, HDAC_CORBRP, corb->rp); + + if (corb->run) + hda_response_interrupt(sc); + + return (0); +} + +static int +hda_rirb_start(struct hda_softc *sc) +{ + struct hda_codec_cmd_ctl *rirb = &sc->rirb; + uint8_t rirbsize = 0; + uint64_t rirblbase = 0; + uint64_t rirbubase = 0; + uint64_t rirbpaddr = 0; + + rirb->name = "RIRB"; + + rirbsize = hda_get_reg_by_offset(sc, HDAC_RIRBSIZE) & \ + HDAC_RIRBSIZE_RIRBSIZE_MASK; + rirb->size = hda_rirb_sizes[rirbsize]; + + if (!rirb->size) { + DPRINTF("Invalid rirb size\n"); + return (-1); + } + + rirblbase = hda_get_reg_by_offset(sc, HDAC_RIRBLBASE); + rirbubase = hda_get_reg_by_offset(sc, HDAC_RIRBUBASE); + + rirbpaddr = rirblbase | (rirbubase << 32); + DPRINTF("RIRB dma_paddr: %p\n", (void *)rirbpaddr); + + rirb->dma_vaddr = hda_dma_get_vaddr(sc, rirbpaddr, + HDA_RIRB_ENTRY_LEN * rirb->size); + if (!rirb->dma_vaddr) { + DPRINTF("Fail to get the guest virtual address\n"); + return (-1); + } + + rirb->wp = hda_get_reg_by_offset(sc, HDAC_RIRBWP); + rirb->rp = 0x0000; + + rirb->run = 1; + + hda_print_cmd_ctl_data(rirb); + + return (0); +} + +static void * +hda_dma_get_vaddr(struct hda_softc *sc, uint64_t dma_paddr, size_t len) +{ + struct pci_devinst *pi = sc->pci_dev; + + assert(pi); + + return (paddr_guest2host(pi->pi_vmctx, (uintptr_t)dma_paddr, len)); +} + +static void +hda_dma_st_dword(void *dma_vaddr, uint32_t data) +{ + *(uint32_t*)dma_vaddr = data; +} + +static uint32_t +hda_dma_ld_dword(void *dma_vaddr) +{ + return (*(uint32_t*)dma_vaddr); +} + +static inline uint8_t +hda_get_stream_by_offsets(uint32_t offset, uint8_t reg_offset) +{ + uint8_t stream_ind = (offset - reg_offset) >> 5; + + assert(stream_ind < HDA_IOSS_NO); + + return (stream_ind); +} + +static inline uint32_t +hda_get_offset_stream(uint8_t stream_ind) +{ + return (stream_ind << 5); +} + +static void +hda_set_gctl(struct hda_softc *sc, uint32_t offset, uint32_t old) +{ + uint32_t value = hda_get_reg_by_offset(sc, offset); + + if (!(value & HDAC_GCTL_CRST)) { + hda_reset(sc); + } +} + +static void +hda_set_statests(struct hda_softc *sc, uint32_t offset, uint32_t old) +{ + uint32_t value = hda_get_reg_by_offset(sc, offset); + + hda_set_reg_by_offset(sc, offset, old); + + /* clear the corresponding bits written by the software (guest) */ + hda_set_field_by_offset(sc, offset, value & HDA_STATESTS_IRQ_MASK, 0); + + hda_update_intr(sc); +} + +static void +hda_set_corbwp(struct hda_softc *sc, uint32_t offset, uint32_t old) +{ + hda_corb_run(sc); +} + +static void +hda_set_corbctl(struct hda_softc *sc, uint32_t offset, uint32_t old) +{ + uint32_t value = hda_get_reg_by_offset(sc, offset); + int err; + struct hda_codec_cmd_ctl *corb = NULL; + + if (value & HDAC_CORBCTL_CORBRUN) { + if (!(old & HDAC_CORBCTL_CORBRUN)) { + err = hda_corb_start(sc); + assert(!err); + } + } else { + corb = &sc->corb; + memset(corb, 0, sizeof(*corb)); + } + + hda_corb_run(sc); +} + +static void +hda_set_rirbctl(struct hda_softc *sc, uint32_t offset, uint32_t old) +{ + uint32_t value = hda_get_reg_by_offset(sc, offset); + int err; + struct hda_codec_cmd_ctl *rirb = NULL; + + if (value & HDAC_RIRBCTL_RIRBDMAEN) { + err = hda_rirb_start(sc); + assert(!err); + } else { + rirb = &sc->rirb; + memset(rirb, 0, sizeof(*rirb)); + } +} + +static void +hda_set_rirbsts(struct hda_softc *sc, uint32_t offset, uint32_t old) +{ + uint32_t value = hda_get_reg_by_offset(sc, offset); + + hda_set_reg_by_offset(sc, offset, old); + + /* clear the corresponding bits written by the software (guest) */ + hda_set_field_by_offset(sc, offset, value & HDA_RIRBSTS_IRQ_MASK, 0); + + hda_update_intr(sc); +} + +static void +hda_set_dpiblbase(struct hda_softc *sc, uint32_t offset, uint32_t old) +{ + uint32_t value = hda_get_reg_by_offset(sc, offset); + uint64_t dpiblbase = 0; + uint64_t dpibubase = 0; + uint64_t dpibpaddr = 0; + + if ((value & HDAC_DPLBASE_DPLBASE_DMAPBE) != (old & \ + HDAC_DPLBASE_DPLBASE_DMAPBE)) { + if (value & HDAC_DPLBASE_DPLBASE_DMAPBE) { + dpiblbase = value & HDAC_DPLBASE_DPLBASE_MASK; + dpibubase = hda_get_reg_by_offset(sc, HDAC_DPIBUBASE); + + dpibpaddr = dpiblbase | (dpibubase << 32); + DPRINTF("DMA Position In Buffer dma_paddr: %p\n", + (void *)dpibpaddr); + + sc->dma_pib_vaddr = hda_dma_get_vaddr(sc, dpibpaddr, + HDA_DMA_PIB_ENTRY_LEN * HDA_IOSS_NO); + if (!sc->dma_pib_vaddr) { + DPRINTF("Fail to get the guest \ + virtual address\n"); + assert(0); + } + } else { + DPRINTF("DMA Position In Buffer Reset\n"); + sc->dma_pib_vaddr = NULL; + } + } +} + +static void +hda_set_sdctl(struct hda_softc *sc, uint32_t offset, uint32_t old) +{ + uint8_t stream_ind = hda_get_stream_by_offsets(offset, HDAC_SDCTL0); + uint32_t value = hda_get_reg_by_offset(sc, offset); + int err; + + DPRINTF("stream_ind: 0x%x old: 0x%x value: 0x%x\n", + stream_ind, old, value); + + if (value & HDAC_SDCTL_SRST) { + hda_stream_reset(sc, stream_ind); + } + + if ((value & HDAC_SDCTL_RUN) != (old & HDAC_SDCTL_RUN)) { + if (value & HDAC_SDCTL_RUN) { + err = hda_stream_start(sc, stream_ind); + assert(!err); + } else { + err = hda_stream_stop(sc, stream_ind); + assert(!err); + } + } +} + +static void +hda_set_sdctl2(struct hda_softc *sc, uint32_t offset, uint32_t old) +{ + uint32_t value = hda_get_reg_by_offset(sc, offset); + + hda_set_field_by_offset(sc, offset - 2, 0x00ff0000, value << 16); +} + +static void +hda_set_sdsts(struct hda_softc *sc, uint32_t offset, uint32_t old) +{ + uint32_t value = hda_get_reg_by_offset(sc, offset); + + hda_set_reg_by_offset(sc, offset, old); + + /* clear the corresponding bits written by the software (guest) */ + hda_set_field_by_offset(sc, offset, value & HDA_SDSTS_IRQ_MASK, 0); + + hda_update_intr(sc); +} + +static int +hda_signal_state_change(struct hda_codec_inst *hci) +{ + struct hda_softc *sc = NULL; + uint32_t sdiwake = 0; + + assert(hci); + assert(hci->hda); + + DPRINTF("cad: 0x%x\n", hci->cad); + + sc = hci->hda; + sdiwake = 1 << hci->cad; + + hda_set_field_by_offset(sc, HDAC_STATESTS, sdiwake, sdiwake); + hda_update_intr(sc); + + return (0); +} + +static int +hda_response(struct hda_codec_inst *hci, uint32_t response, uint8_t unsol) +{ + struct hda_softc *sc = NULL; + struct hda_codec_cmd_ctl *rirb = NULL; + uint32_t response_ex = 0; + uint8_t rintcnt = 0; + + assert(hci); + assert(hci->cad <= HDA_CODEC_MAX); + + response_ex = hci->cad | unsol; + + sc = hci->hda; + assert(sc); + + rirb = &sc->rirb; + + if (rirb->run) { + rirb->wp++; + rirb->wp %= rirb->size; + + hda_dma_st_dword(rirb->dma_vaddr + HDA_RIRB_ENTRY_LEN * \ + rirb->wp, response); + hda_dma_st_dword(rirb->dma_vaddr + HDA_RIRB_ENTRY_LEN * \ + rirb->wp + 0x04, response_ex); + + hda_set_reg_by_offset(sc, HDAC_RIRBWP, rirb->wp); + + sc->rirb_cnt++; + } + + rintcnt = hda_get_reg_by_offset(sc, HDAC_RINTCNT); + if (sc->rirb_cnt == rintcnt) + hda_response_interrupt(sc); + + return (0); +} + +static int +hda_transfer(struct hda_codec_inst *hci, uint8_t stream, uint8_t dir, + void *buf, size_t count) +{ + struct hda_softc *sc = NULL; + struct hda_stream_desc *st = NULL; + struct hda_bdle_desc *bdl = NULL; + struct hda_bdle_desc *bdle_desc = NULL; + uint8_t stream_ind = 0; + uint32_t lpib = 0; + uint32_t off = 0; + size_t left = 0; + uint8_t irq = 0; + + assert(hci); + assert(hci->hda); + assert(buf); + assert(!(count % HDA_DMA_ACCESS_LEN)); + + if (!stream) { + DPRINTF("Invalid stream\n"); + return (-1); + } + + sc = hci->hda; + + assert(stream < HDA_STREAM_TAGS_CNT); + stream_ind = sc->stream_map[dir][stream]; + + if (!dir) + assert(stream_ind < HDA_ISS_NO); + else + assert(stream_ind >= HDA_ISS_NO && stream_ind < HDA_IOSS_NO); + + st = &sc->streams[stream_ind]; + if (!st->run) { + DPRINTF("Stream 0x%x stopped\n", stream); + return (-1); + } + + assert(st->stream == stream); + + off = hda_get_offset_stream(stream_ind); + + lpib = hda_get_reg_by_offset(sc, off + HDAC_SDLPIB); + + bdl = st->bdl; + + assert(st->be < st->bdl_cnt); + assert(st->bp < bdl[st->be].len); + + left = count; + while (left) { + bdle_desc = &bdl[st->be]; + + if (dir) + *(uint32_t *)buf = \ + hda_dma_ld_dword(bdle_desc->addr + st->bp); + else + hda_dma_st_dword(bdle_desc->addr + st->bp, + *(uint32_t *)buf); + + buf += HDA_DMA_ACCESS_LEN; + st->bp += HDA_DMA_ACCESS_LEN; + lpib += HDA_DMA_ACCESS_LEN; + left -= HDA_DMA_ACCESS_LEN; + + if (st->bp == bdle_desc->len) { + st->bp = 0; + if (bdle_desc->ioc) + irq = 1; + st->be++; + if (st->be == st->bdl_cnt) { + st->be = 0; + lpib = 0; + } + bdle_desc = &bdl[st->be]; + } + } + + hda_set_pib(sc, stream_ind, lpib); + + if (irq) { + hda_set_field_by_offset(sc, off + HDAC_SDSTS, + HDAC_SDSTS_BCIS, HDAC_SDSTS_BCIS); + hda_update_intr(sc); + } + + return (0); +} + +static void +hda_set_pib(struct hda_softc *sc, uint8_t stream_ind, uint32_t pib) +{ + uint32_t off = hda_get_offset_stream(stream_ind); + + hda_set_reg_by_offset(sc, off + HDAC_SDLPIB, pib); + /* LPIB Alias */ + hda_set_reg_by_offset(sc, 0x2000 + off + HDAC_SDLPIB, pib); + if (sc->dma_pib_vaddr) + *(uint32_t *)(sc->dma_pib_vaddr + stream_ind * \ + HDA_DMA_PIB_ENTRY_LEN) = pib; +} + +static uint64_t hda_get_clock_ns(void) +{ + struct timespec ts; + int err; + + err = clock_gettime(CLOCK_MONOTONIC, &ts); + assert(!err); + + return (ts.tv_sec * 1000000000LL + ts.tv_nsec); +} + +/* + * PCI HDA function definitions + */ +static int +pci_hda_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) +{ + struct hda_softc *sc = NULL; + + assert(ctx != NULL); + assert(pi != NULL); + + pci_set_cfgdata16(pi, PCIR_VENDOR, INTEL_VENDORID); + pci_set_cfgdata16(pi, PCIR_DEVICE, HDA_INTEL_82801G); + + pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_MULTIMEDIA_HDA); + pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_MULTIMEDIA); + + /* select the Intel HDA mode */ + pci_set_cfgdata8(pi, PCIR_HDCTL, 0x01); + + /* allocate one BAR register for the Memory address offsets */ + pci_emul_alloc_bar(pi, 0, PCIBAR_MEM32, HDA_LAST_OFFSET); + + /* allocate an IRQ pin for our slot */ + pci_lintr_request(pi); + + sc = hda_init(opts); + if (!sc) + return (-1); + + sc->pci_dev = pi; + pi->pi_arg = sc; + + return (0); +} + +static void +pci_hda_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, + int baridx, uint64_t offset, int size, uint64_t value) +{ + struct hda_softc *sc = pi->pi_arg; + int err; + + assert(sc); + assert(baridx == 0); + assert(size <= 4); + + DPRINTF("offset: 0x%lx value: 0x%lx\n", offset, value); + + err = hda_write(sc, offset, size, value); + assert(!err); +} + +static uint64_t +pci_hda_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, + int baridx, uint64_t offset, int size) +{ + struct hda_softc *sc = pi->pi_arg; + uint64_t value = 0; + + assert(sc); + assert(baridx == 0); + assert(size <= 4); + + value = hda_read(sc, offset); + + DPRINTF("offset: 0x%lx value: 0x%lx\n", offset, value); + + return (value); +} diff --git a/usr.sbin/bhyve/pci_hda.h b/usr.sbin/bhyve/pci_hda.h new file mode 100644 index 000000000000..038a1da8dee6 --- /dev/null +++ b/usr.sbin/bhyve/pci_hda.h @@ -0,0 +1,90 @@ +/*- + * Copyright (c) 2016 Alex Teaca + * 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, 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 OR CONTRIBUTORS 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$ + */ + +#ifndef _HDA_EMUL_H_ +#define _HDA_EMUL_H_ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "hda_reg.h" + +/* + * HDA Debug Log + */ +#define DEBUG_HDA 1 +#if DEBUG_HDA == 1 +extern FILE *dbg; +#define DPRINTF(fmt, arg...) \ +do {fprintf(dbg, "%s-%d: " fmt, __func__, __LINE__, ##arg); \ +fflush(dbg); } while (0) +#else +#define DPRINTF(fmt, arg...) +#endif + +#define HDA_FIFO_SIZE 0x100 + +struct hda_softc; +struct hda_codec_class; + +struct hda_codec_inst { + uint8_t cad; + struct hda_codec_class *codec; + struct hda_softc *hda; + struct hda_ops *hops; + void *priv; +}; + +struct hda_codec_class { + char *name; + int (*init)(struct hda_codec_inst *hci, const char *play, + const char *rec, const char *opts); + int (*reset)(struct hda_codec_inst *hci); + int (*command)(struct hda_codec_inst *hci, uint32_t cmd_data); + int (*notify)(struct hda_codec_inst *hci, uint8_t run, uint8_t stream, + uint8_t dir); +}; + +struct hda_ops { + int (*signal)(struct hda_codec_inst *hci); + int (*response)(struct hda_codec_inst *hci, uint32_t response, + uint8_t unsol); + int (*transfer)(struct hda_codec_inst *hci, uint8_t stream, + uint8_t dir, void *buf, size_t count); +}; + +#define HDA_EMUL_SET(x) DATA_SET(hda_codec_class_set, x); + +#endif /* _HDA_EMUL_H_ */ From 0a944371e8492a339377ac04dbcf06ed14019f56 Mon Sep 17 00:00:00 2001 From: Scott Long Date: Mon, 24 Jun 2019 19:42:32 +0000 Subject: [PATCH 067/165] Add a section about the HD Audio module support --- usr.sbin/bhyve/bhyve.8 | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/usr.sbin/bhyve/bhyve.8 b/usr.sbin/bhyve/bhyve.8 index 2f2236e8ce38..3ab9e4e67dde 100644 --- a/usr.sbin/bhyve/bhyve.8 +++ b/usr.sbin/bhyve/bhyve.8 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd December 11, 2018 +.Dd June 24, 2019 .Dt BHYVE 8 .Os .Sh NAME @@ -248,6 +248,8 @@ Raw framebuffer device attached to VNC server. eXtensible Host Controller Interface (xHCI) USB controller. .It Li nvme NVM Express (NVMe) controller. +.It Li hda +High Definition Audio Controller. .El .It Op Ar conf This optional parameter describes the backend for device emulations. @@ -475,6 +477,16 @@ Sector size (defaults to blockif sector size). .It Li ser Serial number with maximum 20 characters. .El +.Pp +HD Audio devices: +.Bl -tag -width 10n +.It Li play +Playback device, typically +.Ar /dev/dsp0 . +.It Li rec +Recording device, typically +.Ar /dev/dsp0 . +.El .El .It Fl S Wire guest memory. From 161d2a1796dc232c253a4b4f2792509942b11b01 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Mon, 24 Jun 2019 20:18:49 +0000 Subject: [PATCH 068/165] Go ahead and completely fix the ata_params before calling the veto function. This breaks nothing that uses it in the tree since ata_params is ignored in storvsc_ada_probe_veto which is the only in-tree consumer. --- sys/cam/ata/ata_xpt.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/sys/cam/ata/ata_xpt.c b/sys/cam/ata/ata_xpt.c index 94dc435b099b..acef293f1b46 100644 --- a/sys/cam/ata/ata_xpt.c +++ b/sys/cam/ata/ata_xpt.c @@ -896,22 +896,14 @@ device_fail: if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0) int16_t *ptr; int veto = 0; + /* + * Convert to host byte order, and fix the strings. + */ ident_buf = &softc->ident_data; for (ptr = (int16_t *)ident_buf; ptr < (int16_t *)ident_buf + sizeof(struct ata_params)/2; ptr++) { *ptr = le16toh(*ptr); } - - /* - * Allow others to veto this ATA disk attachment. This - * is mainly used by VMs, whose disk controllers may - * share the disks with the simulated ATA controllers. - */ - EVENTHANDLER_INVOKE(ada_probe_veto, path, ident_buf, &veto); - if (veto) { - goto device_fail; - } - if (strncmp(ident_buf->model, "FX", 2) && strncmp(ident_buf->model, "NEC", 3) && strncmp(ident_buf->model, "Pioneer", 7) && @@ -926,6 +918,17 @@ device_fail: if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0) ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision)); ata_btrim(ident_buf->serial, sizeof(ident_buf->serial)); ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial)); + + /* + * Allow others to veto this ATA disk attachment. This + * is mainly used by VMs, whose disk controllers may + * share the disks with the simulated ATA controllers. + */ + EVENTHANDLER_INVOKE(ada_probe_veto, path, ident_buf, &veto); + if (veto) { + goto device_fail; + } + /* Device may need spin-up before IDENTIFY become valid. */ if ((ident_buf->specconf == 0x37c8 || ident_buf->specconf == 0x738c) && From 2afaed2d0f4aea7309156870e9d115edbbec3dfe Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Mon, 24 Jun 2019 20:18:58 +0000 Subject: [PATCH 069/165] Create ata_param_fixup Create a common fixup routine to do the canonical fixup of the ata_param fixup. Call it from both the ATA and the ATA over SCSI paths. --- sys/cam/ata/ata_all.c | 25 +++++++++++++++++++++++++ sys/cam/ata/ata_all.h | 1 + sys/cam/ata/ata_xpt.c | 20 +------------------- sys/cam/scsi/scsi_da.c | 5 ++--- 4 files changed, 29 insertions(+), 22 deletions(-) diff --git a/sys/cam/ata/ata_all.c b/sys/cam/ata/ata_all.c index 76d65ae5e405..9a4cdbed071b 100644 --- a/sys/cam/ata/ata_all.c +++ b/sys/cam/ata/ata_all.c @@ -1238,3 +1238,28 @@ ata_zac_mgmt_in(struct ccb_ataio *ataio, uint32_t retries, ataio->aux = auxiliary; } } + +void +ata_param_fixup(struct ata_params *ident_buf) +{ + int16_t *ptr; + + for (ptr = (int16_t *)ident_buf; + ptr < (int16_t *)ident_buf + sizeof(struct ata_params)/2; ptr++) { + *ptr = le16toh(*ptr); + } + if (strncmp(ident_buf->model, "FX", 2) && + strncmp(ident_buf->model, "NEC", 3) && + strncmp(ident_buf->model, "Pioneer", 7) && + strncmp(ident_buf->model, "SHARP", 5)) { + ata_bswap(ident_buf->model, sizeof(ident_buf->model)); + ata_bswap(ident_buf->revision, sizeof(ident_buf->revision)); + ata_bswap(ident_buf->serial, sizeof(ident_buf->serial)); + } + ata_btrim(ident_buf->model, sizeof(ident_buf->model)); + ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model)); + ata_btrim(ident_buf->revision, sizeof(ident_buf->revision)); + ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision)); + ata_btrim(ident_buf->serial, sizeof(ident_buf->serial)); + ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial)); +} diff --git a/sys/cam/ata/ata_all.h b/sys/cam/ata/ata_all.h index 087d6820f980..ca635253511c 100644 --- a/sys/cam/ata/ata_all.h +++ b/sys/cam/ata/ata_all.h @@ -135,6 +135,7 @@ void ata_read_log(struct ccb_ataio *ataio, uint32_t retries, uint16_t block_count, uint32_t protocol, uint8_t *data_ptr, uint32_t dxfer_len, uint32_t timeout); +void ata_param_fixup(struct ata_params *ident_buf); void ata_bswap(int8_t *buf, int len); void ata_btrim(int8_t *buf, int len); void ata_bpack(int8_t *src, int8_t *dst, int len); diff --git a/sys/cam/ata/ata_xpt.c b/sys/cam/ata/ata_xpt.c index acef293f1b46..017db8854b08 100644 --- a/sys/cam/ata/ata_xpt.c +++ b/sys/cam/ata/ata_xpt.c @@ -893,31 +893,13 @@ device_fail: if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0) case PROBE_IDENTIFY: { struct ccb_pathinq cpi; - int16_t *ptr; int veto = 0; /* * Convert to host byte order, and fix the strings. */ ident_buf = &softc->ident_data; - for (ptr = (int16_t *)ident_buf; - ptr < (int16_t *)ident_buf + sizeof(struct ata_params)/2; ptr++) { - *ptr = le16toh(*ptr); - } - if (strncmp(ident_buf->model, "FX", 2) && - strncmp(ident_buf->model, "NEC", 3) && - strncmp(ident_buf->model, "Pioneer", 7) && - strncmp(ident_buf->model, "SHARP", 5)) { - ata_bswap(ident_buf->model, sizeof(ident_buf->model)); - ata_bswap(ident_buf->revision, sizeof(ident_buf->revision)); - ata_bswap(ident_buf->serial, sizeof(ident_buf->serial)); - } - ata_btrim(ident_buf->model, sizeof(ident_buf->model)); - ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model)); - ata_btrim(ident_buf->revision, sizeof(ident_buf->revision)); - ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision)); - ata_btrim(ident_buf->serial, sizeof(ident_buf->serial)); - ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial)); + ata_param_fixup(ident_buf); /* * Allow others to veto this ATA disk attachment. This diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c index a89c40e19a7b..d2e66307cce6 100644 --- a/sys/cam/scsi/scsi_da.c +++ b/sys/cam/scsi/scsi_da.c @@ -5192,7 +5192,7 @@ dadone_probeata(struct cam_periph *periph, union ccb *done_ccb) struct da_softc *softc; u_int32_t priority; int continue_probe; - int error, i; + int error; int16_t *ptr; CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("dadone_probeata\n")); @@ -5210,8 +5210,7 @@ dadone_probeata(struct cam_periph *periph, union ccb *done_ccb) if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { uint16_t old_rate; - for (i = 0; i < sizeof(*ata_params) / 2; i++) - ptr[i] = le16toh(ptr[i]); + ata_param_fixup(ata_params); if (ata_params->support_dsm & ATA_SUPPORT_DSM_TRIM && (softc->quirks & DA_Q_NO_UNMAP) == 0) { dadeleteflag(softc, DA_DELETE_ATA_TRIM, 1); From 6506ca91d21f5e7f303cb50dd85c6691cade048f Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Mon, 24 Jun 2019 20:19:03 +0000 Subject: [PATCH 070/165] Use ata_param_fixup instead of a custom copy here --- sbin/camcontrol/camcontrol.c | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/sbin/camcontrol/camcontrol.c b/sbin/camcontrol/camcontrol.c index 0784fab75a0e..99d59e59d86c 100644 --- a/sbin/camcontrol/camcontrol.c +++ b/sbin/camcontrol/camcontrol.c @@ -2326,9 +2326,11 @@ ata_do_identify(struct cam_device *device, int retry_count, int timeout, } } + ident_buf = (struct ata_params *)ptr; + ata_param_fixup(ident_buf); + error = 1; for (i = 0; i < sizeof(struct ata_params) / 2; i++) { - ptr[i] = le16toh(ptr[i]); if (ptr[i] != 0) error = 0; } @@ -2346,26 +2348,6 @@ ata_do_identify(struct cam_device *device, int retry_count, int timeout, return (error); } - ident_buf = (struct ata_params *)ptr; - if (strncmp(ident_buf->model, "FX", 2) && - strncmp(ident_buf->model, "NEC", 3) && - strncmp(ident_buf->model, "Pioneer", 7) && - strncmp(ident_buf->model, "SHARP", 5)) { - ata_bswap(ident_buf->model, sizeof(ident_buf->model)); - ata_bswap(ident_buf->revision, sizeof(ident_buf->revision)); - ata_bswap(ident_buf->serial, sizeof(ident_buf->serial)); - ata_bswap(ident_buf->media_serial, sizeof(ident_buf->media_serial)); - } - ata_btrim(ident_buf->model, sizeof(ident_buf->model)); - ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model)); - ata_btrim(ident_buf->revision, sizeof(ident_buf->revision)); - ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision)); - ata_btrim(ident_buf->serial, sizeof(ident_buf->serial)); - ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial)); - ata_btrim(ident_buf->media_serial, sizeof(ident_buf->media_serial)); - ata_bpack(ident_buf->media_serial, ident_buf->media_serial, - sizeof(ident_buf->media_serial)); - *ident_bufp = ident_buf; return (0); From 97ad52ca4ce2eb52379af2f19a589fd18eb4dd51 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Mon, 24 Jun 2019 20:23:19 +0000 Subject: [PATCH 071/165] Use the cam_ed copy of ata_params rather than malloc and freeing memory for it. This reaches into internal bits of xpt a little, and I'll clean that up later. --- sys/cam/scsi/scsi_da.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c index d2e66307cce6..f2f60d35b2e2 100644 --- a/sys/cam/scsi/scsi_da.c +++ b/sys/cam/scsi/scsi_da.c @@ -64,6 +64,9 @@ __FBSDID("$FreeBSD$"); #include #include #include +#ifdef _KERNEL +#include +#endif /* _KERNEL */ #include #include @@ -3613,15 +3616,7 @@ dastart(struct cam_periph *periph, union ccb *start_ccb) break; } - ata_params = (struct ata_params*) - malloc(sizeof(*ata_params), M_SCSIDA,M_NOWAIT|M_ZERO); - - if (ata_params == NULL) { - xpt_print(periph->path, "Couldn't malloc ata_params " - "data\n"); - /* da_free_periph??? */ - break; - } + ata_params = &periph->path->device->ident_data; scsi_ata_identify(&start_ccb->csio, /*retries*/da_retry_count, @@ -5294,7 +5289,6 @@ dadone_probeata(struct cam_periph *periph, union ccb *done_ccb) } } - free(ata_params, M_SCSIDA); if ((softc->zone_mode == DA_ZONE_HOST_AWARE) || (softc->zone_mode == DA_ZONE_HOST_MANAGED)) { /* From ec9abc1843219b354494b58fa322fe6f6d3439e9 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Mon, 24 Jun 2019 20:34:53 +0000 Subject: [PATCH 072/165] Move to using a common kernel path between the boot / laoder bits and the kernel. --- stand/common/paths.h | 5 ++++- stand/efi/loader/main.c | 5 +++-- sys/kern/kern_mib.c | 2 +- sys/sys/boot.h | 2 ++ 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/stand/common/paths.h b/stand/common/paths.h index 9ed45e646a3e..b32313770129 100644 --- a/stand/common/paths.h +++ b/stand/common/paths.h @@ -29,11 +29,14 @@ #ifndef _PATHS_H_ #define _PATHS_H_ +#include /* To get kernel path */ + #define PATH_DOTCONFIG "/boot.config" #define PATH_CONFIG "/boot/config" #define PATH_LOADER "/boot/loader" #define PATH_LOADER_EFI "/boot/loader.efi" #define PATH_LOADER_ZFS "/boot/zfsloader" -#define PATH_KERNEL "/boot/kernel/kernel" +#define PATH_LOADER_CONF "/boot/loader.conf" +#define PATH_DEFAULTS_LOADER_CONF "/boot/defaults/loader.conf" #endif /* _PATHS_H_ */ diff --git a/stand/efi/loader/main.c b/stand/efi/loader/main.c index 8b3ba741178c..60d8c1442518 100644 --- a/stand/efi/loader/main.c +++ b/stand/efi/loader/main.c @@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -237,8 +238,8 @@ sanity_check_currdev(void) { struct stat st; - return (stat("/boot/defaults/loader.conf", &st) == 0 || - stat("/boot/kernel/kernel", &st) == 0); + return (stat(PATH_DEFAULTS_LOADER_CONF, &st) == 0 || + stat(PATH_KERNEL, &st) == 0); } #ifdef EFI_ZFS_BOOT diff --git a/sys/kern/kern_mib.c b/sys/kern/kern_mib.c index a92f6488c39f..d515f9f5b3a3 100644 --- a/sys/kern/kern_mib.c +++ b/sys/kern/kern_mib.c @@ -136,7 +136,7 @@ SYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD|CTLFLAG_CAPRD, SYSCTL_NULL_INT_PTR, 0, "Whether saved set-group/user ID is available"); #endif -char kernelname[MAXPATHLEN] = "/boot/kernel/kernel"; /* XXX bloat */ +char kernelname[MAXPATHLEN] = PATH_KERNEL; /* XXX bloat */ SYSCTL_STRING(_kern, KERN_BOOTFILE, bootfile, CTLFLAG_RW | CTLFLAG_MPSAFE, kernelname, sizeof kernelname, "Name of kernel file booted"); diff --git a/sys/sys/boot.h b/sys/sys/boot.h index 68b9e1e0daf3..7874d9663736 100644 --- a/sys/sys/boot.h +++ b/sys/sys/boot.h @@ -32,6 +32,8 @@ #ifndef _SYS_BOOT_H_ #define _SYS_BOOT_H_ +#define PATH_KERNEL "/boot/kernel/kernel" + int boot_env_to_howto(void); void boot_howto_to_env(int howto); int boot_parse_arg(char *v); From af9727f61802e394cdc5f3e6930e9b1900933ac3 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Mon, 24 Jun 2019 20:52:21 +0000 Subject: [PATCH 073/165] Add missing include of sys/boot.h This change was dropped out in a rebase and I didn't catch that before I committed. --- sys/kern/kern_mib.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sys/kern/kern_mib.c b/sys/kern/kern_mib.c index d515f9f5b3a3..54cdff148247 100644 --- a/sys/kern/kern_mib.c +++ b/sys/kern/kern_mib.c @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$"); #include "opt_config.h" #include +#include #include #include #include From 893caf588ab4520c9d12fe49cd5e92e5d54ecf2e Mon Sep 17 00:00:00 2001 From: "Jayachandran C." Date: Mon, 24 Jun 2019 21:00:28 +0000 Subject: [PATCH 074/165] arm64 gic: Drop unused GICV3_IVAR_REDIST_VADDR Now that GICV3_IVAR_REDIST is available, GICV3_IVAR_REDIST_VADDR is unused and can be removed. Drop the define and add a comment. Reviewed by: andrew Differential Revision: https://reviews.freebsd.org/D20454 --- sys/arm64/arm64/gic_v3.c | 4 ---- sys/arm64/arm64/gic_v3_var.h | 3 +-- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/sys/arm64/arm64/gic_v3.c b/sys/arm64/arm64/gic_v3.c index af08ee992bb6..a83ef576e30e 100644 --- a/sys/arm64/arm64/gic_v3.c +++ b/sys/arm64/arm64/gic_v3.c @@ -390,10 +390,6 @@ gic_v3_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) case GICV3_IVAR_NIRQS: *result = (NIRQ - sc->gic_nirqs) / sc->gic_nchildren; return (0); - case GICV3_IVAR_REDIST_VADDR: - *result = (uintptr_t)rman_get_virtual( - &sc->gic_redists.pcpu[PCPU_GET(cpuid)]->res); - return (0); case GICV3_IVAR_REDIST: *result = (uintptr_t)sc->gic_redists.pcpu[PCPU_GET(cpuid)]; return (0); diff --git a/sys/arm64/arm64/gic_v3_var.h b/sys/arm64/arm64/gic_v3_var.h index 27dec4d72190..1257484a5e57 100644 --- a/sys/arm64/arm64/gic_v3_var.h +++ b/sys/arm64/arm64/gic_v3_var.h @@ -94,11 +94,10 @@ MALLOC_DECLARE(M_GIC_V3); /* ivars */ #define GICV3_IVAR_NIRQS 1000 -#define GICV3_IVAR_REDIST_VADDR 1001 +/* 1001 was GICV3_IVAR_REDIST_VADDR */ #define GICV3_IVAR_REDIST 1002 __BUS_ACCESSOR(gicv3, nirqs, GICV3, NIRQS, u_int); -__BUS_ACCESSOR(gicv3, redist_vaddr, GICV3, REDIST_VADDR, void *); __BUS_ACCESSOR(gicv3, redist, GICV3, REDIST, void *); /* Device methods */ From 73701bbe9d8ff75309d5386e82808272a8bd98be Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Mon, 24 Jun 2019 21:05:14 +0000 Subject: [PATCH 075/165] kbdcontrol -h prints two error messages. We loop through getopt(3) twice. Once for -P args and once for the rest. Catch '?' and print usage when that happens. --- usr.sbin/kbdcontrol/kbdcontrol.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/usr.sbin/kbdcontrol/kbdcontrol.c b/usr.sbin/kbdcontrol/kbdcontrol.c index 3144e44d72b3..f4651acea840 100644 --- a/usr.sbin/kbdcontrol/kbdcontrol.c +++ b/usr.sbin/kbdcontrol/kbdcontrol.c @@ -1220,9 +1220,12 @@ main(int argc, char **argv) int opt; /* Collect any -P arguments, regardless of where they appear. */ - while ((opt = getopt(argc, argv, optstring)) != -1) + while ((opt = getopt(argc, argv, optstring)) != -1) { if (opt == 'P') add_keymap_path(optarg); + if (opt == '?') + usage(); + } optind = optreset = 1; while ((opt = getopt(argc, argv, optstring)) != -1) From c66524f07da76c8188e3d86f56adee334881e593 Mon Sep 17 00:00:00 2001 From: "Jayachandran C." Date: Mon, 24 Jun 2019 21:13:45 +0000 Subject: [PATCH 076/165] arm64 gicv3_its: enable all ITS blocks for a CPU We now support multiple ITS blocks raising interrupts to a CPU. Add all available CPUs to the ITS when no NUMA information is available. This reverts the check added in r340602, at that tim we did not suppport multiple ITS blocks for a CPU. Differential Revision: https://reviews.freebsd.org/D20417 --- sys/arm64/arm64/gicv3_its.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sys/arm64/arm64/gicv3_its.c b/sys/arm64/arm64/gicv3_its.c index f347a36c12cc..2701a7e8df0a 100644 --- a/sys/arm64/arm64/gicv3_its.c +++ b/sys/arm64/arm64/gicv3_its.c @@ -747,9 +747,7 @@ gicv3_its_attach(device_t dev) if (domain < MAXMEMDOM) CPU_COPY(&cpuset_domain[domain], &sc->sc_cpus); } else { - /* XXX : cannot handle more than one ITS per cpu */ - if (device_get_unit(dev) == 0) - CPU_COPY(&all_cpus, &sc->sc_cpus); + CPU_COPY(&all_cpus, &sc->sc_cpus); } /* Allocate the command circular buffer */ From b0f79e328e18f454a54011ab1bb09e4910e73840 Mon Sep 17 00:00:00 2001 From: "Jayachandran C." Date: Mon, 24 Jun 2019 21:24:55 +0000 Subject: [PATCH 077/165] arm64 acpi_iort: add some error handling Print warnings for some bad kernel configurations (like NUMA disabled with multiple domains). Check and report some firmware errors (like incorrect proximity domain entries). Differential Revision: https://reviews.freebsd.org/D20416 --- sys/arm64/acpica/acpi_iort.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/sys/arm64/acpica/acpi_iort.c b/sys/arm64/acpica/acpi_iort.c index edd87474c9c9..10a501254bc6 100644 --- a/sys/arm64/acpica/acpi_iort.c +++ b/sys/arm64/acpica/acpi_iort.c @@ -370,19 +370,44 @@ srat_resolve_its_pxm(ACPI_SUBTABLE_HEADER *entry, void *arg) ACPI_SRAT_GIC_ITS_AFFINITY *gicits; struct iort_node *its_node; struct iort_its_entry *its_entry; - int i, matches; + int *map_counts; + int i, matches, dom; if (entry->Type != ACPI_SRAT_TYPE_GIC_ITS_AFFINITY) return; matches = 0; + map_counts = arg; gicits = (ACPI_SRAT_GIC_ITS_AFFINITY *)entry; + dom = acpi_map_pxm_to_vm_domainid(gicits->ProximityDomain); + + /* + * Catch firmware and config errors. map_counts keeps a + * count of ProximityDomain values mapping to a domain ID + */ +#if MAXMEMDOM > 1 + if (dom == -1) + printf("Firmware Error: Proximity Domain %d could not be" + " mapped for GIC ITS ID %d!\n", + gicits->ProximityDomain, gicits->ItsId); +#endif + /* use dom + 1 as index to handle the case where dom == -1 */ + i = ++map_counts[dom + 1]; + if (i > 1) { +#ifdef NUMA + if (dom != -1) + printf("ERROR: Multiple Proximity Domains map to the" + " same NUMA domain %d!\n", dom); +#else + printf("WARNING: multiple Proximity Domains in SRAT but NUMA" + " NOT enabled!\n"); +#endif + } TAILQ_FOREACH(its_node, &its_groups, next) { its_entry = its_node->entries.its; for (i = 0; i < its_node->nentries; i++, its_entry++) { if (its_entry->its_id == gicits->ItsId) { - its_entry->pxm = acpi_map_pxm_to_vm_domainid( - gicits->ProximityDomain); + its_entry->pxm = dom; matches++; } } @@ -401,6 +426,7 @@ iort_post_process_its(void) ACPI_TABLE_MADT *madt; ACPI_TABLE_SRAT *srat; vm_paddr_t madt_pa, srat_pa; + int map_counts[MAXMEMDOM + 1] = { 0 }; /* Check ITS block in MADT */ madt_pa = acpi_find_table(ACPI_SIG_MADT); @@ -417,7 +443,7 @@ iort_post_process_its(void) srat = acpi_map_table(srat_pa, ACPI_SIG_SRAT); KASSERT(srat != NULL, ("can't map SRAT!")); acpi_walk_subtables(srat + 1, (char *)srat + srat->Header.Length, - srat_resolve_its_pxm, NULL); + srat_resolve_its_pxm, map_counts); acpi_unmap_table(srat); } return (0); From da4961c796795b7337cd905b84be8dcf200d408c Mon Sep 17 00:00:00 2001 From: Rebecca Cran Date: Mon, 24 Jun 2019 23:18:42 +0000 Subject: [PATCH 078/165] loader: add HTTP support using UEFI Add support for an HTTP "network filesystem" using the UEFI's HTTP stack. This also supports HTTPS, but TianoCore EDK2 implementations currently crash while fetching loader files. Only IPv4 is supported at the moment. IPv6 support is planned for a follow-up changeset. Note that we include some headers from the TianoCore EDK II project in stand/efi/include/Protocol verbatim, including links to the license instead of including the full text because that's their preferred way of communicating it, despite not being normal FreeBSD project practice. Submitted by: scottph Reviewed by: imp, bcran Differential Revision: https://reviews.freebsd.org/D20643 --- stand/efi/include/Protocol/Http.h | 523 +++++++++++++ stand/efi/include/Protocol/Ip4Config2.h | 324 +++++++++ stand/efi/include/Protocol/ServiceBinding.h | 95 +++ stand/efi/include/efidevp.h | 22 + stand/efi/include/efilib.h | 1 + stand/efi/libefi/Makefile | 1 + stand/efi/libefi/efihttp.c | 766 ++++++++++++++++++++ stand/efi/loader/conf.c | 2 + stand/libsa/stand.h | 1 + 9 files changed, 1735 insertions(+) create mode 100644 stand/efi/include/Protocol/Http.h create mode 100644 stand/efi/include/Protocol/Ip4Config2.h create mode 100644 stand/efi/include/Protocol/ServiceBinding.h create mode 100644 stand/efi/libefi/efihttp.c diff --git a/stand/efi/include/Protocol/Http.h b/stand/efi/include/Protocol/Http.h new file mode 100644 index 000000000000..54f49ab5e35c --- /dev/null +++ b/stand/efi/include/Protocol/Http.h @@ -0,0 +1,523 @@ +/* $FreeBSD$ */ +/** @file + This file defines the EFI HTTP Protocol interface. It is split into + the following two main sections: + HTTP Service Binding Protocol (HTTPSB) + HTTP Protocol (HTTP) + + Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.
+ (C) Copyright 2015-2017 Hewlett Packard Enterprise Development LP
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + @par Revision Reference: + This Protocol is introduced in UEFI Specification 2.5 + +**/ + +#ifndef __EFI_HTTP_PROTOCOL_H__ +#define __EFI_HTTP_PROTOCOL_H__ + +#define EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID \ + { \ + 0xbdc8e6af, 0xd9bc, 0x4379, {0xa7, 0x2a, 0xe0, 0xc4, 0xe7, 0x5d, 0xae, 0x1c } \ + } + +#define EFI_HTTP_PROTOCOL_GUID \ + { \ + 0x7a59b29b, 0x910b, 0x4171, {0x82, 0x42, 0xa8, 0x5a, 0x0d, 0xf2, 0x5b, 0x5b } \ + } + +typedef struct _EFI_HTTP_PROTOCOL EFI_HTTP_PROTOCOL; + +/// +/// EFI_HTTP_VERSION +/// +typedef enum { + HttpVersion10, + HttpVersion11, + HttpVersionUnsupported +} EFI_HTTP_VERSION; + +/// +/// EFI_HTTP_METHOD +/// +typedef enum { + HttpMethodGet, + HttpMethodPost, + HttpMethodPatch, + HttpMethodOptions, + HttpMethodConnect, + HttpMethodHead, + HttpMethodPut, + HttpMethodDelete, + HttpMethodTrace, + HttpMethodMax +} EFI_HTTP_METHOD; + +/// +/// EFI_HTTP_STATUS_CODE +/// +typedef enum { + HTTP_STATUS_UNSUPPORTED_STATUS = 0, + HTTP_STATUS_100_CONTINUE, + HTTP_STATUS_101_SWITCHING_PROTOCOLS, + HTTP_STATUS_200_OK, + HTTP_STATUS_201_CREATED, + HTTP_STATUS_202_ACCEPTED, + HTTP_STATUS_203_NON_AUTHORITATIVE_INFORMATION, + HTTP_STATUS_204_NO_CONTENT, + HTTP_STATUS_205_RESET_CONTENT, + HTTP_STATUS_206_PARTIAL_CONTENT, + HTTP_STATUS_300_MULTIPLE_CHOICES, + HTTP_STATUS_301_MOVED_PERMANENTLY, + HTTP_STATUS_302_FOUND, + HTTP_STATUS_303_SEE_OTHER, + HTTP_STATUS_304_NOT_MODIFIED, + HTTP_STATUS_305_USE_PROXY, + HTTP_STATUS_307_TEMPORARY_REDIRECT, + HTTP_STATUS_400_BAD_REQUEST, + HTTP_STATUS_401_UNAUTHORIZED, + HTTP_STATUS_402_PAYMENT_REQUIRED, + HTTP_STATUS_403_FORBIDDEN, + HTTP_STATUS_404_NOT_FOUND, + HTTP_STATUS_405_METHOD_NOT_ALLOWED, + HTTP_STATUS_406_NOT_ACCEPTABLE, + HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED, + HTTP_STATUS_408_REQUEST_TIME_OUT, + HTTP_STATUS_409_CONFLICT, + HTTP_STATUS_410_GONE, + HTTP_STATUS_411_LENGTH_REQUIRED, + HTTP_STATUS_412_PRECONDITION_FAILED, + HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE, + HTTP_STATUS_414_REQUEST_URI_TOO_LARGE, + HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE, + HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED, + HTTP_STATUS_417_EXPECTATION_FAILED, + HTTP_STATUS_500_INTERNAL_SERVER_ERROR, + HTTP_STATUS_501_NOT_IMPLEMENTED, + HTTP_STATUS_502_BAD_GATEWAY, + HTTP_STATUS_503_SERVICE_UNAVAILABLE, + HTTP_STATUS_504_GATEWAY_TIME_OUT, + HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED, + HTTP_STATUS_308_PERMANENT_REDIRECT +} EFI_HTTP_STATUS_CODE; + +/// +/// EFI_HTTPv4_ACCESS_POINT +/// +typedef struct { + /// + /// Set to TRUE to instruct the EFI HTTP instance to use the default address + /// information in every TCP connection made by this instance. In addition, when set + /// to TRUE, LocalAddress and LocalSubnet are ignored. + /// + BOOLEAN UseDefaultAddress; + /// + /// If UseDefaultAddress is set to FALSE, this defines the local IP address to be + /// used in every TCP connection opened by this instance. + /// + EFI_IPv4_ADDRESS LocalAddress; + /// + /// If UseDefaultAddress is set to FALSE, this defines the local subnet to be used + /// in every TCP connection opened by this instance. + /// + EFI_IPv4_ADDRESS LocalSubnet; + /// + /// This defines the local port to be used in + /// every TCP connection opened by this instance. + /// + UINT16 LocalPort; +} EFI_HTTPv4_ACCESS_POINT; + +/// +/// EFI_HTTPv6_ACCESS_POINT +/// +typedef struct { + /// + /// Local IP address to be used in every TCP connection opened by this instance. + /// + EFI_IPv6_ADDRESS LocalAddress; + /// + /// Local port to be used in every TCP connection opened by this instance. + /// + UINT16 LocalPort; +} EFI_HTTPv6_ACCESS_POINT; + +/// +/// EFI_HTTP_CONFIG_DATA_ACCESS_POINT +/// + + +typedef struct { + /// + /// HTTP version that this instance will support. + /// + EFI_HTTP_VERSION HttpVersion; + /// + /// Time out (in milliseconds) when blocking for requests. + /// + UINT32 TimeOutMillisec; + /// + /// Defines behavior of EFI DNS and TCP protocols consumed by this instance. If + /// FALSE, this instance will use EFI_DNS4_PROTOCOL and EFI_TCP4_PROTOCOL. If TRUE, + /// this instance will use EFI_DNS6_PROTOCOL and EFI_TCP6_PROTOCOL. + /// + BOOLEAN LocalAddressIsIPv6; + + union { + /// + /// When LocalAddressIsIPv6 is FALSE, this points to the local address, subnet, and + /// port used by the underlying TCP protocol. + /// + EFI_HTTPv4_ACCESS_POINT *IPv4Node; + /// + /// When LocalAddressIsIPv6 is TRUE, this points to the local IPv6 address and port + /// used by the underlying TCP protocol. + /// + EFI_HTTPv6_ACCESS_POINT *IPv6Node; + } AccessPoint; +} EFI_HTTP_CONFIG_DATA; + +/// +/// EFI_HTTP_REQUEST_DATA +/// +typedef struct { + /// + /// The HTTP method (e.g. GET, POST) for this HTTP Request. + /// + EFI_HTTP_METHOD Method; + /// + /// The URI of a remote host. From the information in this field, the HTTP instance + /// will be able to determine whether to use HTTP or HTTPS and will also be able to + /// determine the port number to use. If no port number is specified, port 80 (HTTP) + /// is assumed. See RFC 3986 for more details on URI syntax. + /// + CHAR16 *Url; +} EFI_HTTP_REQUEST_DATA; + +/// +/// EFI_HTTP_RESPONSE_DATA +/// +typedef struct { + /// + /// Response status code returned by the remote host. + /// + EFI_HTTP_STATUS_CODE StatusCode; +} EFI_HTTP_RESPONSE_DATA; + +/// +/// EFI_HTTP_HEADER +/// +typedef struct { + /// + /// Null terminated string which describes a field name. See RFC 2616 Section 14 for + /// detailed information about field names. + /// + CHAR8 *FieldName; + /// + /// Null terminated string which describes the corresponding field value. See RFC 2616 + /// Section 14 for detailed information about field values. + /// + CHAR8 *FieldValue; +} EFI_HTTP_HEADER; + +/// +/// EFI_HTTP_MESSAGE +/// +typedef struct { + /// + /// HTTP message data. + /// + union { + /// + /// When the token is used to send a HTTP request, Request is a pointer to storage that + /// contains such data as URL and HTTP method. + /// + EFI_HTTP_REQUEST_DATA *Request; + /// + /// When used to await a response, Response points to storage containing HTTP response + /// status code. + /// + EFI_HTTP_RESPONSE_DATA *Response; + } Data; + /// + /// Number of HTTP header structures in Headers list. On request, this count is + /// provided by the caller. On response, this count is provided by the HTTP driver. + /// + UINTN HeaderCount; + /// + /// Array containing list of HTTP headers. On request, this array is populated by the + /// caller. On response, this array is allocated and populated by the HTTP driver. It + /// is the responsibility of the caller to free this memory on both request and + /// response. + /// + EFI_HTTP_HEADER *Headers; + /// + /// Length in bytes of the HTTP body. This can be zero depending on the HttpMethod type. + /// + UINTN BodyLength; + /// + /// Body associated with the HTTP request or response. This can be NULL depending on + /// the HttpMethod type. + /// + VOID *Body; +} EFI_HTTP_MESSAGE; + + +/// +/// EFI_HTTP_TOKEN +/// +typedef struct { + /// + /// This Event will be signaled after the Status field is updated by the EFI HTTP + /// Protocol driver. The type of Event must be EFI_NOTIFY_SIGNAL. The Task Priority + /// Level (TPL) of Event must be lower than or equal to TPL_CALLBACK. + /// + EFI_EVENT Event; + /// + /// Status will be set to one of the following value if the HTTP request is + /// successfully sent or if an unexpected error occurs: + /// EFI_SUCCESS: The HTTP request was successfully sent to the remote host. + /// EFI_HTTP_ERROR: The response message was successfully received but contains a + /// HTTP error. The response status code is returned in token. + /// EFI_ABORTED: The HTTP request was cancelled by the caller and removed from + /// the transmit queue. + /// EFI_TIMEOUT: The HTTP request timed out before reaching the remote host. + /// EFI_DEVICE_ERROR: An unexpected system or network error occurred. + /// + EFI_STATUS Status; + /// + /// Pointer to storage containing HTTP message data. + /// + EFI_HTTP_MESSAGE *Message; +} EFI_HTTP_TOKEN; + +/** + Returns the operational parameters for the current HTTP child instance. + + The GetModeData() function is used to read the current mode data (operational + parameters) for this HTTP protocol instance. + + @param[in] This Pointer to EFI_HTTP_PROTOCOL instance. + @param[out] HttpConfigData Point to buffer for operational parameters of this + HTTP instance. It is the responsibility of the caller + to allocate the memory for HttpConfigData and + HttpConfigData->AccessPoint.IPv6Node/IPv4Node. In fact, + it is recommended to allocate sufficient memory to record + IPv6Node since it is big enough for all possibilities. + + @retval EFI_SUCCESS Operation succeeded. + @retval EFI_INVALID_PARAMETER This is NULL. + HttpConfigData is NULL. + HttpConfigData->AccessPoint.IPv4Node or + HttpConfigData->AccessPoint.IPv6Node is NULL. + @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been started. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_HTTP_GET_MODE_DATA)( + IN EFI_HTTP_PROTOCOL *This, + OUT EFI_HTTP_CONFIG_DATA *HttpConfigData + ); + +/** + Initialize or brutally reset the operational parameters for this EFI HTTP instance. + + The Configure() function does the following: + When HttpConfigData is not NULL Initialize this EFI HTTP instance by configuring + timeout, local address, port, etc. + When HttpConfigData is NULL, reset this EFI HTTP instance by closing all active + connections with remote hosts, canceling all asynchronous tokens, and flush request + and response buffers without informing the appropriate hosts. + + No other EFI HTTP function can be executed by this instance until the Configure() + function is executed and returns successfully. + + @param[in] This Pointer to EFI_HTTP_PROTOCOL instance. + @param[in] HttpConfigData Pointer to the configure data to configure the instance. + + @retval EFI_SUCCESS Operation succeeded. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. + HttpConfigData->LocalAddressIsIPv6 is FALSE and + HttpConfigData->AccessPoint.IPv4Node is NULL. + HttpConfigData->LocalAddressIsIPv6 is TRUE and + HttpConfigData->AccessPoint.IPv6Node is NULL. + @retval EFI_ALREADY_STARTED Reinitialize this HTTP instance without calling + Configure() with NULL to reset it. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_OUT_OF_RESOURCES Could not allocate enough system resources when + executing Configure(). + @retval EFI_UNSUPPORTED One or more options in ConfigData are not supported + in the implementation. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_HTTP_CONFIGURE)( + IN EFI_HTTP_PROTOCOL *This, + IN EFI_HTTP_CONFIG_DATA *HttpConfigData OPTIONAL + ); + +/** + The Request() function queues an HTTP request to this HTTP instance, + similar to Transmit() function in the EFI TCP driver. When the HTTP request is sent + successfully, or if there is an error, Status in token will be updated and Event will + be signaled. + + @param[in] This Pointer to EFI_HTTP_PROTOCOL instance. + @param[in] Token Pointer to storage containing HTTP request token. + + @retval EFI_SUCCESS Outgoing data was processed. + @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been started. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_TIMEOUT Data was dropped out of the transmit or receive queue. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. + Token is NULL. + Token->Message is NULL. + Token->Message->Body is not NULL, + Token->Message->BodyLength is non-zero, and + Token->Message->Data is NULL, but a previous call to + Request()has not been completed successfully. + @retval EFI_OUT_OF_RESOURCES Could not allocate enough system resources. + @retval EFI_UNSUPPORTED The HTTP method is not supported in current implementation. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_HTTP_REQUEST) ( + IN EFI_HTTP_PROTOCOL *This, + IN EFI_HTTP_TOKEN *Token + ); + +/** + Abort an asynchronous HTTP request or response token. + + The Cancel() function aborts a pending HTTP request or response transaction. If + Token is not NULL and the token is in transmit or receive queues when it is being + cancelled, its Token->Status will be set to EFI_ABORTED and then Token->Event will + be signaled. If the token is not in one of the queues, which usually means that the + asynchronous operation has completed, EFI_NOT_FOUND is returned. If Token is NULL, + all asynchronous tokens issued by Request() or Response() will be aborted. + + @param[in] This Pointer to EFI_HTTP_PROTOCOL instance. + @param[in] Token Point to storage containing HTTP request or response + token. + + @retval EFI_SUCCESS Request and Response queues are successfully flushed. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_STARTED This instance hasn't been configured. + @retval EFI_NOT_FOUND The asynchronous request or response token is not + found. + @retval EFI_UNSUPPORTED The implementation does not support this function. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_HTTP_CANCEL)( + IN EFI_HTTP_PROTOCOL *This, + IN EFI_HTTP_TOKEN *Token + ); + +/** + The Response() function queues an HTTP response to this HTTP instance, similar to + Receive() function in the EFI TCP driver. When the HTTP Response is received successfully, + or if there is an error, Status in token will be updated and Event will be signaled. + + The HTTP driver will queue a receive token to the underlying TCP instance. When data + is received in the underlying TCP instance, the data will be parsed and Token will + be populated with the response data. If the data received from the remote host + contains an incomplete or invalid HTTP header, the HTTP driver will continue waiting + (asynchronously) for more data to be sent from the remote host before signaling + Event in Token. + + It is the responsibility of the caller to allocate a buffer for Body and specify the + size in BodyLength. If the remote host provides a response that contains a content + body, up to BodyLength bytes will be copied from the receive buffer into Body and + BodyLength will be updated with the amount of bytes received and copied to Body. This + allows the client to download a large file in chunks instead of into one contiguous + block of memory. Similar to HTTP request, if Body is not NULL and BodyLength is + non-zero and all other fields are NULL or 0, the HTTP driver will queue a receive + token to underlying TCP instance. If data arrives in the receive buffer, up to + BodyLength bytes of data will be copied to Body. The HTTP driver will then update + BodyLength with the amount of bytes received and copied to Body. + + If the HTTP driver does not have an open underlying TCP connection with the host + specified in the response URL, Request() will return EFI_ACCESS_DENIED. This is + consistent with RFC 2616 recommendation that HTTP clients should attempt to maintain + an open TCP connection between client and host. + + @param[in] This Pointer to EFI_HTTP_PROTOCOL instance. + @param[in] Token Pointer to storage containing HTTP response token. + + @retval EFI_SUCCESS Allocation succeeded. + @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been + initialized. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. + Token is NULL. + Token->Message->Headers is NULL. + Token->Message is NULL. + Token->Message->Body is not NULL, + Token->Message->BodyLength is non-zero, and + Token->Message->Data is NULL, but a previous call to + Response() has not been completed successfully. + @retval EFI_OUT_OF_RESOURCES Could not allocate enough system resources. + @retval EFI_ACCESS_DENIED An open TCP connection is not present with the host + specified by response URL. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_HTTP_RESPONSE) ( + IN EFI_HTTP_PROTOCOL *This, + IN EFI_HTTP_TOKEN *Token + ); + +/** + The Poll() function can be used by network drivers and applications to increase the + rate that data packets are moved between the communication devices and the transmit + and receive queues. + + In some systems, the periodic timer event in the managed network driver may not poll + the underlying communications device fast enough to transmit and/or receive all data + packets without missing incoming packets or dropping outgoing packets. Drivers and + applications that are experiencing packet loss should try calling the Poll() function + more often. + + @param[in] This Pointer to EFI_HTTP_PROTOCOL instance. + + @retval EFI_SUCCESS Incoming or outgoing data was processed.. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_READY No incoming or outgoing data is processed. + @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been started. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_HTTP_POLL) ( + IN EFI_HTTP_PROTOCOL *This + ); + +/// +/// The EFI HTTP protocol is designed to be used by EFI drivers and applications to +/// create and transmit HTTP Requests, as well as handle HTTP responses that are +/// returned by a remote host. This EFI protocol uses and relies on an underlying EFI +/// TCP protocol. +/// +struct _EFI_HTTP_PROTOCOL { + EFI_HTTP_GET_MODE_DATA GetModeData; + EFI_HTTP_CONFIGURE Configure; + EFI_HTTP_REQUEST Request; + EFI_HTTP_CANCEL Cancel; + EFI_HTTP_RESPONSE Response; + EFI_HTTP_POLL Poll; +}; + +extern EFI_GUID gEfiHttpServiceBindingProtocolGuid; +extern EFI_GUID gEfiHttpProtocolGuid; + +#endif diff --git a/stand/efi/include/Protocol/Ip4Config2.h b/stand/efi/include/Protocol/Ip4Config2.h new file mode 100644 index 000000000000..47241d7ad7d4 --- /dev/null +++ b/stand/efi/include/Protocol/Ip4Config2.h @@ -0,0 +1,324 @@ +/* $FreeBSD$ */ +/** @file + This file provides a definition of the EFI IPv4 Configuration II + Protocol. + +Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +@par Revision Reference: +This Protocol is introduced in UEFI Specification 2.5 + +**/ +#ifndef __EFI_IP4CONFIG2_PROTOCOL_H__ +#define __EFI_IP4CONFIG2_PROTOCOL_H__ + +/* #include */ + +#define EFI_IP4_CONFIG2_PROTOCOL_GUID \ + { \ + 0x5b446ed1, 0xe30b, 0x4faa, {0x87, 0x1a, 0x36, 0x54, 0xec, 0xa3, 0x60, 0x80 } \ + } + +typedef struct _EFI_IP4_CONFIG2_PROTOCOL EFI_IP4_CONFIG2_PROTOCOL; + + +/// +/// EFI_IP4_CONFIG2_DATA_TYPE +/// +typedef enum { + /// + /// The interface information of the communication device this EFI + /// IPv4 Configuration II Protocol instance manages. This type of + /// data is read only. The corresponding Data is of type + /// EFI_IP4_CONFIG2_INTERFACE_INFO. + /// + Ip4Config2DataTypeInterfaceInfo, + /// + /// The general configuration policy for the EFI IPv4 network stack + /// running on the communication device this EFI IPv4 + /// Configuration II Protocol instance manages. The policy will + /// affect other configuration settings. The corresponding Data is of + /// type EFI_IP4_CONFIG2_POLICY. + /// + Ip4Config2DataTypePolicy, + /// + /// The station addresses set manually for the EFI IPv4 network + /// stack. It is only configurable when the policy is + /// Ip4Config2PolicyStatic. The corresponding Data is of + /// type EFI_IP4_CONFIG2_MANUAL_ADDRESS. When DataSize + /// is 0 and Data is NULL, the existing configuration is cleared + /// from the EFI IPv4 Configuration II Protocol instance. + /// + Ip4Config2DataTypeManualAddress, + /// + /// The gateway addresses set manually for the EFI IPv4 network + /// stack running on the communication device this EFI IPv4 + /// Configuration II Protocol manages. It is not configurable when + /// the policy is Ip4Config2PolicyDhcp. The gateway + /// addresses must be unicast IPv4 addresses. The corresponding + /// Data is a pointer to an array of EFI_IPv4_ADDRESS instances. + /// When DataSize is 0 and Data is NULL, the existing configuration + /// is cleared from the EFI IPv4 Configuration II Protocol instance. + /// + Ip4Config2DataTypeGateway, + /// + /// The DNS server list for the EFI IPv4 network stack running on + /// the communication device this EFI IPv4 Configuration II + /// Protocol manages. It is not configurable when the policy is + /// Ip4Config2PolicyDhcp. The DNS server addresses must be + /// unicast IPv4 addresses. The corresponding Data is a pointer to + /// an array of EFI_IPv4_ADDRESS instances. When DataSize + /// is 0 and Data is NULL, the existing configuration is cleared + /// from the EFI IPv4 Configuration II Protocol instance. + /// + Ip4Config2DataTypeDnsServer, + Ip4Config2DataTypeMaximum +} EFI_IP4_CONFIG2_DATA_TYPE; + +/// +/// EFI_IP4_CONFIG2_INTERFACE_INFO related definitions +/// +#define EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE 32 + +/// +/// EFI_IP4_CONFIG2_INTERFACE_INFO +/// +typedef struct { + /// + /// The name of the interface. It is a NULL-terminated Unicode string. + /// + CHAR16 Name[EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE]; + /// + /// The interface type of the network interface. See RFC 1700, + /// section "Number Hardware Type". + /// + UINT8 IfType; + /// + /// The size, in bytes, of the network interface's hardware address. + /// + UINT32 HwAddressSize; + /// + /// The hardware address for the network interface. + /// + EFI_MAC_ADDRESS HwAddress; + /// + /// The station IPv4 address of this EFI IPv4 network stack. + /// + EFI_IPv4_ADDRESS StationAddress; + /// + /// The subnet address mask that is associated with the station address. + /// + EFI_IPv4_ADDRESS SubnetMask; + /// + /// Size of the following RouteTable, in bytes. May be zero. + /// + UINT32 RouteTableSize; + /// + /// The route table of the IPv4 network stack runs on this interface. + /// Set to NULL if RouteTableSize is zero. Type EFI_IP4_ROUTE_TABLE is defined in + /// EFI_IP4_PROTOCOL.GetModeData(). + /// + EFI_IP4_ROUTE_TABLE *RouteTable OPTIONAL; +} EFI_IP4_CONFIG2_INTERFACE_INFO; + +/// +/// EFI_IP4_CONFIG2_POLICY +/// +typedef enum { + /// + /// Under this policy, the Ip4Config2DataTypeManualAddress, + /// Ip4Config2DataTypeGateway and Ip4Config2DataTypeDnsServer configuration + /// data are required to be set manually. The EFI IPv4 Protocol will get all + /// required configuration such as IPv4 address, subnet mask and + /// gateway settings from the EFI IPv4 Configuration II protocol. + /// + Ip4Config2PolicyStatic, + /// + /// Under this policy, the Ip4Config2DataTypeManualAddress, + /// Ip4Config2DataTypeGateway and Ip4Config2DataTypeDnsServer configuration data are + /// not allowed to set via SetData(). All of these configurations are retrieved from DHCP + /// server or other auto-configuration mechanism. + /// + Ip4Config2PolicyDhcp, + Ip4Config2PolicyMax +} EFI_IP4_CONFIG2_POLICY; + +/// +/// EFI_IP4_CONFIG2_MANUAL_ADDRESS +/// +typedef struct { + /// + /// The IPv4 unicast address. + /// + EFI_IPv4_ADDRESS Address; + /// + /// The subnet mask. + /// + EFI_IPv4_ADDRESS SubnetMask; +} EFI_IP4_CONFIG2_MANUAL_ADDRESS; + +/** + Set the configuration for the EFI IPv4 network stack running on the communication device this EFI + IPv4 Configuration II Protocol instance manages. + + This function is used to set the configuration data of type DataType for the EFI IPv4 network stack + running on the communication device this EFI IPv4 Configuration II Protocol instance manages. + The successfully configured data is valid after system reset or power-off. + The DataSize is used to calculate the count of structure instances in the Data for some + DataType that multiple structure instances are allowed. + This function is always non-blocking. When setting some typeof configuration data, an + asynchronous process is invoked to check the correctness of the data, such as doing address conflict + detection on the manually set local IPv4 address. EFI_NOT_READY is returned immediately to + indicate that such an asynchronous process is invoked and the process is not finished yet. The caller + willing to get the result of the asynchronous process is required to call RegisterDataNotify() + to register an event on the specified configuration data. Once the event is signaled, the caller can call + GetData()to get back the configuration data in order to know the result. For other types of + configuration data that do not require an asynchronous configuration process, the result of the + operation is immediately returned. + + @param[in] This Pointer to the EFI_IP4_CONFIG2_PROTOCOL instance. + @param[in] DataType The type of data to set. + @param[in] DataSize Size of the buffer pointed to by Data in bytes. + @param[in] Data The data buffer to set. The type ofthe data buffer is associated + with the DataType. + + @retval EFI_SUCCESS The specified configuration data for the EFI IPv4 network stack is set + successfully. + @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: + This is NULL. + One or more fields in Data and DataSize do not match the + requirement of the data type indicated by DataType. + @retval EFI_WRITE_PROTECTED The specified configuration data is read-only or the specified configuration + data can not be set under the current policy. + @retval EFI_ACCESS_DENIED Another set operation on the specified configuration data is already in process. + @retval EFI_NOT_READY An asynchronous process is invoked to set the specified configuration data and + the process is not finished yet. + @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type indicated by DataType. + @retval EFI_UNSUPPORTED This DataType is not supported. + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. + @retval EFI_DEVICE_ERROR An unexpected system error or network error occurred. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_CONFIG2_SET_DATA) ( + IN EFI_IP4_CONFIG2_PROTOCOL *This, + IN EFI_IP4_CONFIG2_DATA_TYPE DataType, + IN UINTN DataSize, + IN VOID *Data + ); + +/** + Get the configuration data for the EFI IPv4 network stack running on the communication device this + EFI IPv4 Configuration II Protocol instance manages. + + This function returns the configuration data of type DataType for the EFI IPv4 network stack + running on the communication device this EFI IPv4 Configuration II Protocol instance manages. + The caller is responsible for allocating the buffer usedto return the specified configuration data and + the required size will be returned to the caller if the size of the buffer is too small. + EFI_NOT_READY is returned if the specified configuration data is not ready due to an already in + progress asynchronous configuration process. The caller can call RegisterDataNotify() to + register an event on the specified configuration data. Once the asynchronous configuration process is + finished, the event will be signaled and a subsequent GetData() call will return the specified + configuration data. + + @param[in] This Pointer to the EFI_IP4_CONFIG2_PROTOCOL instance. + @param[in] DataType The type of data to get. + @param[out] DataSize On input, in bytes, the size of Data. On output, in bytes, the size + of buffer required to store the specified configuration data. + @param[in] Data The data buffer in which the configuration data is returned. The + type of the data buffer is associated with the DataType. Ignored + if DataSize is 0. + + @retval EFI_SUCCESS The specified configuration data is got successfully. + @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE: + This is NULL. + DataSize is NULL. + Data is NULL if *DataSizeis not zero. + @retval EFI_BUFFER_TOO_SMALL The size of Data is too small for the specified configuration data + and the required size is returned in DataSize. + @retval EFI_NOT_READY The specified configuration data is not ready due to an already in + progress asynchronous configuration process. + @retval EFI_NOT_FOUND The specified configuration data is not found. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_CONFIG2_GET_DATA) ( + IN EFI_IP4_CONFIG2_PROTOCOL *This, + IN EFI_IP4_CONFIG2_DATA_TYPE DataType, + IN OUT UINTN *DataSize, + IN VOID *Data OPTIONAL + ); + +/** + Register an event that is to be signaled whenever a configuration process on the specified + configuration data is done. + + This function registers an event that is to be signaled whenever a configuration process on the + specified configuration data is done. An event can be registered for different DataType + simultaneously and the caller is responsible for determining which type of configuration data causes + the signaling of the event in such case. + + @param[in] This Pointer to the EFI_IP4_CONFIG2_PROTOCOL instance. + @param[in] DataType The type of data to unregister the event for. + @param[in] Event The event to register. + + @retval EFI_SUCCESS The notification event for the specified configuration data is + registered. + @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL. + @retval EFI_UNSUPPORTED The configuration data type specified by DataType is not supported. + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. + @retval EFI_ACCESS_DENIED The Event is already registered for the DataType. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_CONFIG2_REGISTER_NOTIFY) ( + IN EFI_IP4_CONFIG2_PROTOCOL *This, + IN EFI_IP4_CONFIG2_DATA_TYPE DataType, + IN EFI_EVENT Event + ); + +/** + Remove a previously registered event for the specified configuration data. + + This function removes a previously registeredevent for the specified configuration data. + + @param[in] This Pointer to the EFI_IP4_CONFIG2_PROTOCOL instance. + @param[in] DataType The type of data to remove the previously registered event for. + @param[in] Event The event to unregister. + + @retval EFI_SUCCESS The event registered for the specified configuration data is removed. + @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL. + @retval EFI_NOT_FOUND The Eventhas not been registered for the specified DataType. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_CONFIG2_UNREGISTER_NOTIFY) ( + IN EFI_IP4_CONFIG2_PROTOCOL *This, + IN EFI_IP4_CONFIG2_DATA_TYPE DataType, + IN EFI_EVENT Event + ); + +/// +/// The EFI_IP4_CONFIG2_PROTOCOL is designed to be the central repository for the common +/// configurations and the administrator configurable settings for the EFI IPv4 network stack. +/// An EFI IPv4 Configuration II Protocol instance will be installed on each communication device that +/// the EFI IPv4 network stack runs on. +/// +struct _EFI_IP4_CONFIG2_PROTOCOL { + EFI_IP4_CONFIG2_SET_DATA SetData; + EFI_IP4_CONFIG2_GET_DATA GetData; + EFI_IP4_CONFIG2_REGISTER_NOTIFY RegisterDataNotify; + EFI_IP4_CONFIG2_UNREGISTER_NOTIFY UnregisterDataNotify; +}; + +extern EFI_GUID gEfiIp4Config2ProtocolGuid; + +#endif + diff --git a/stand/efi/include/Protocol/ServiceBinding.h b/stand/efi/include/Protocol/ServiceBinding.h new file mode 100644 index 000000000000..39602b086e5b --- /dev/null +++ b/stand/efi/include/Protocol/ServiceBinding.h @@ -0,0 +1,95 @@ +/* $FreeBSD$ */ +/** @file + UEFI Service Binding Protocol is defined in UEFI specification. + + The file defines the generic Service Binding Protocol functions. + It provides services that are required to create and destroy child + handles that support a given set of protocols. + + Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __EFI_SERVICE_BINDING_H__ +#define __EFI_SERVICE_BINDING_H__ + +/// +/// Forward reference for pure ANSI compatibility +/// +typedef struct _EFI_SERVICE_BINDING_PROTOCOL EFI_SERVICE_BINDING_PROTOCOL; + +/** + Creates a child handle and installs a protocol. + + The CreateChild() function installs a protocol on ChildHandle. + If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle. + If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle. + + @param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance. + @param ChildHandle Pointer to the handle of the child to create. If it is NULL, + then a new handle is created. If it is a pointer to an existing UEFI handle, + then the protocol is added to the existing UEFI handle. + + @retval EFI_SUCCES The protocol was added to ChildHandle. + @retval EFI_INVALID_PARAMETER ChildHandle is NULL. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to create + the child + @retval other The child handle was not created + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SERVICE_BINDING_CREATE_CHILD)( + IN EFI_SERVICE_BINDING_PROTOCOL *This, + IN OUT EFI_HANDLE *ChildHandle + ); + +/** + Destroys a child handle with a protocol installed on it. + + The DestroyChild() function does the opposite of CreateChild(). It removes a protocol + that was installed by CreateChild() from ChildHandle. If the removed protocol is the + last protocol on ChildHandle, then ChildHandle is destroyed. + + @param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance. + @param ChildHandle Handle of the child to destroy + + @retval EFI_SUCCES The protocol was removed from ChildHandle. + @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed. + @retval EFI_INVALID_PARAMETER Child handle is NULL. + @retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle + because its services are being used. + @retval other The child handle was not destroyed + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SERVICE_BINDING_DESTROY_CHILD)( + IN EFI_SERVICE_BINDING_PROTOCOL *This, + IN EFI_HANDLE ChildHandle + ); + +/// +/// The EFI_SERVICE_BINDING_PROTOCOL provides member functions to create and destroy +/// child handles. A driver is responsible for adding protocols to the child handle +/// in CreateChild() and removing protocols in DestroyChild(). It is also required +/// that the CreateChild() function opens the parent protocol BY_CHILD_CONTROLLER +/// to establish the parent-child relationship, and closes the protocol in DestroyChild(). +/// The pseudo code for CreateChild() and DestroyChild() is provided to specify the +/// required behavior, not to specify the required implementation. Each consumer of +/// a software protocol is responsible for calling CreateChild() when it requires the +/// protocol and calling DestroyChild() when it is finished with that protocol. +/// +struct _EFI_SERVICE_BINDING_PROTOCOL { + EFI_SERVICE_BINDING_CREATE_CHILD CreateChild; + EFI_SERVICE_BINDING_DESTROY_CHILD DestroyChild; +}; + +#endif diff --git a/stand/efi/include/efidevp.h b/stand/efi/include/efidevp.h index 6f320260952e..70e506efa50b 100644 --- a/stand/efi/include/efidevp.h +++ b/stand/efi/include/efidevp.h @@ -232,6 +232,8 @@ typedef struct _IPv4_DEVICE_PATH { UINT16 RemotePort; UINT16 Protocol; BOOLEAN StaticIpAddress; + EFI_IPv4_ADDRESS GatewayIpAddress; + EFI_IPv4_ADDRESS SubnetMask; } IPv4_DEVICE_PATH; #define MSG_IPv6_DP 0x0d @@ -294,6 +296,26 @@ typedef struct _SATA_DEVICE_PATH { UINT16 Lun; } SATA_DEVICE_PATH; + +/* DNS Device Path SubType */ +#define MSG_DNS_DP 0x1F +typedef struct { + EFI_DEVICE_PATH Header; + /* Indicates the DNS server address is IPv4 or IPv6 address. */ + UINT8 IsIPv6; + /* Instance of the DNS server address. */ + /* XXX: actually EFI_IP_ADDRESS */ + EFI_IPv4_ADDRESS DnsServerIp[]; +} DNS_DEVICE_PATH; + +/* Uniform Resource Identifiers (URI) Device Path SubType */ +#define MSG_URI_DP 0x18 +typedef struct { + EFI_DEVICE_PATH Header; + /* Instance of the URI pursuant to RFC 3986. */ + CHAR8 Uri[]; +} URI_DEVICE_PATH; + #define MEDIA_DEVICE_PATH 0x04 #define MEDIA_HARDDRIVE_DP 0x01 diff --git a/stand/efi/include/efilib.h b/stand/efi/include/efilib.h index 91fa294965a3..6ca41d848384 100644 --- a/stand/efi/include/efilib.h +++ b/stand/efi/include/efilib.h @@ -42,6 +42,7 @@ extern EFI_RUNTIME_SERVICES *RS; extern struct devsw efipart_fddev; extern struct devsw efipart_cddev; extern struct devsw efipart_hddev; +extern struct devsw efihttp_dev; extern struct devsw efinet_dev; extern struct netif_driver efinetif; diff --git a/stand/efi/libefi/Makefile b/stand/efi/libefi/Makefile index 9b0330815900..7ca1a1f92fd7 100644 --- a/stand/efi/libefi/Makefile +++ b/stand/efi/libefi/Makefile @@ -12,6 +12,7 @@ SRCS= delay.c \ efi_driver_utils.c \ efichar.c \ efienv.c \ + efihttp.c \ efinet.c \ efipart.c \ efizfs.c \ diff --git a/stand/efi/libefi/efihttp.c b/stand/efi/libefi/efihttp.c new file mode 100644 index 000000000000..5a0c3d2fec8f --- /dev/null +++ b/stand/efi/libefi/efihttp.c @@ -0,0 +1,766 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2019 Intel Corporation + * + * 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 AUTHORS AND CONTRIBUTORS ``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 AUTHORS OR CONTRIBUTORS 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$ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +/* Poll timeout in milliseconds */ +static const int EFIHTTP_POLL_TIMEOUT = 300000; + +static EFI_GUID http_guid = EFI_HTTP_PROTOCOL_GUID; +static EFI_GUID httpsb_guid = EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID; +static EFI_GUID ip4config2_guid = EFI_IP4_CONFIG2_PROTOCOL_GUID; + +static int efihttp_dev_init(void); +static int efihttp_dev_strategy(void *devdata, int rw, daddr_t blk, size_t size, + char *buf, size_t *rsize); +static int efihttp_dev_open(struct open_file *f, ...); +static int efihttp_dev_close(struct open_file *f); + +static int efihttp_fs_open(const char *path, struct open_file *f); +static int efihttp_fs_close(struct open_file *f); +static int efihttp_fs_read(struct open_file *f, void *buf, size_t size, + size_t *resid); +static int efihttp_fs_write(struct open_file *f, const void *buf, size_t size, + size_t *resid); +static off_t efihttp_fs_seek(struct open_file *f, off_t offset, int where); +static int efihttp_fs_stat(struct open_file *f, struct stat *sb); +static int efihttp_fs_readdir(struct open_file *f, struct dirent *d); + +struct open_efihttp { + EFI_HTTP_PROTOCOL *http; + EFI_HANDLE http_handle; + EFI_HANDLE dev_handle; + char *uri_base; +}; + +struct file_efihttp { + ssize_t size; + off_t offset; + char *path; + bool is_dir; +}; + +struct devsw efihttp_dev = { + .dv_name = "http", + .dv_type = DEVT_NET, + .dv_init = efihttp_dev_init, + .dv_strategy = efihttp_dev_strategy, + .dv_open = efihttp_dev_open, + .dv_close = efihttp_dev_close, + .dv_ioctl = noioctl, + .dv_print = NULL, + .dv_cleanup = NULL, +}; + +struct fs_ops efihttp_fsops = { + .fs_name = "efihttp", + .fo_open = efihttp_fs_open, + .fo_close = efihttp_fs_close, + .fo_read = efihttp_fs_read, + .fo_write = efihttp_fs_write, + .fo_seek = efihttp_fs_seek, + .fo_stat = efihttp_fs_stat, + .fo_readdir = efihttp_fs_readdir, +}; + +static void EFIAPI +notify(EFI_EVENT event, void *context) +{ + bool *b; + + b = (bool *)context; + *b = true; +} + +static int +setup_ipv4_config2(EFI_HANDLE handle, MAC_ADDR_DEVICE_PATH *mac, + IPv4_DEVICE_PATH *ipv4, DNS_DEVICE_PATH *dns) +{ + EFI_IP4_CONFIG2_PROTOCOL *ip4config2; + EFI_STATUS status; + + status = BS->OpenProtocol(handle, &ip4config2_guid, + (void **)&ip4config2, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + if (ipv4) { + setenv("boot.netif.hwaddr", + ether_sprintf((u_char *)mac->MacAddress.Addr), 1); + setenv("boot.netif.ip", + inet_ntoa(*(struct in_addr *)ipv4->LocalIpAddress.Addr), 1); + setenv("boot.netif.netmask", + intoa(*(n_long *)ipv4->SubnetMask.Addr), 1); + setenv("boot.netif.gateway", + inet_ntoa(*(struct in_addr *)ipv4->GatewayIpAddress.Addr), + 1); + status = ip4config2->SetData(ip4config2, + Ip4Config2DataTypePolicy, sizeof(EFI_IP4_CONFIG2_POLICY), + &(EFI_IP4_CONFIG2_POLICY) { Ip4Config2PolicyStatic }); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + + status = ip4config2->SetData(ip4config2, + Ip4Config2DataTypeManualAddress, + sizeof(EFI_IP4_CONFIG2_MANUAL_ADDRESS), + &(EFI_IP4_CONFIG2_MANUAL_ADDRESS) { + .Address = ipv4->LocalIpAddress, + .SubnetMask = ipv4->SubnetMask }); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + + if (ipv4->GatewayIpAddress.Addr[0] != 0) { + status = ip4config2->SetData(ip4config2, + Ip4Config2DataTypeGateway, sizeof(EFI_IPv4_ADDRESS), + &ipv4->GatewayIpAddress); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + } + + if (dns) { + status = ip4config2->SetData(ip4config2, + Ip4Config2DataTypeDnsServer, + sizeof(EFI_IPv4_ADDRESS), &dns->DnsServerIp); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + } + } else { + status = ip4config2->SetData(ip4config2, + Ip4Config2DataTypePolicy, sizeof(EFI_IP4_CONFIG2_POLICY), + &(EFI_IP4_CONFIG2_POLICY) { Ip4Config2PolicyDhcp }); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + } + + return (0); +} + +static int +efihttp_dev_init(void) +{ + EFI_DEVICE_PATH *imgpath, *devpath; + URI_DEVICE_PATH *uri; + EFI_HANDLE handle; + EFI_STATUS status; + int err; + bool found_http; + + imgpath = efi_lookup_image_devpath(IH); + if (imgpath == NULL) + return (ENXIO); + devpath = imgpath; + found_http = false; + for (; !IsDevicePathEnd(devpath); + devpath = NextDevicePathNode(devpath)) { + if (DevicePathType(devpath) != MESSAGING_DEVICE_PATH || + DevicePathSubType(devpath) != MSG_URI_DP) + continue; + uri = (URI_DEVICE_PATH *)devpath; + if (strncmp("http", uri->Uri, 4) == 0) + found_http = true; + } + if (!found_http) + return (ENXIO); + + status = BS->LocateDevicePath(&httpsb_guid, &imgpath, &handle); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + + err = efi_register_handles(&efihttp_dev, &handle, NULL, 1); + return (err); +} + +static int +efihttp_dev_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf, + size_t *rsize) +{ + return (EIO); +} + +static int +efihttp_dev_open(struct open_file *f, ...) +{ + EFI_HTTP_CONFIG_DATA config; + EFI_HTTPv4_ACCESS_POINT config_access; + DNS_DEVICE_PATH *dns; + EFI_DEVICE_PATH *devpath, *imgpath; + EFI_SERVICE_BINDING_PROTOCOL *sb; + IPv4_DEVICE_PATH *ipv4; + MAC_ADDR_DEVICE_PATH *mac; + URI_DEVICE_PATH *uri; + struct devdesc *dev; + struct open_efihttp *oh; + char *c; + EFI_HANDLE handle; + EFI_STATUS status; + int err, len; + + imgpath = efi_lookup_image_devpath(IH); + if (imgpath == NULL) + return (ENXIO); + devpath = imgpath; + status = BS->LocateDevicePath(&httpsb_guid, &devpath, &handle); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + ipv4 = NULL; + dns = NULL; + uri = NULL; + for (; !IsDevicePathEnd(imgpath); + imgpath = NextDevicePathNode(imgpath)) { + if (DevicePathType(imgpath) != MESSAGING_DEVICE_PATH) + continue; + switch (DevicePathSubType(imgpath)) { + case MSG_MAC_ADDR_DP: + mac = (MAC_ADDR_DEVICE_PATH *)imgpath; + break; + case MSG_IPv4_DP: + ipv4 = (IPv4_DEVICE_PATH *)imgpath; + break; + case MSG_DNS_DP: + dns = (DNS_DEVICE_PATH *)imgpath; + break; + case MSG_URI_DP: + uri = (URI_DEVICE_PATH *)imgpath; + break; + default: + break; + } + } + + if (uri == NULL) + return (ENXIO); + + err = setup_ipv4_config2(handle, mac, ipv4, dns); + if (err) + return (err); + + oh = calloc(1, sizeof(struct open_efihttp)); + if (!oh) + return (ENOMEM); + oh->dev_handle = handle; + dev = (struct devdesc *)f->f_devdata; + dev->d_opendata = oh; + + status = BS->OpenProtocol(handle, &httpsb_guid, (void **)&sb, IH, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(status)) { + err = efi_status_to_errno(status); + goto end; + } + + status = sb->CreateChild(sb, &oh->http_handle); + if (EFI_ERROR(status)) { + err = efi_status_to_errno(status); + goto end; + } + + status = BS->OpenProtocol(oh->http_handle, &http_guid, + (void **)&oh->http, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(status)) { + sb->DestroyChild(sb, oh->http_handle); + err = efi_status_to_errno(status); + goto end; + } + + config.HttpVersion = HttpVersion11; + config.TimeOutMillisec = 0; + config.LocalAddressIsIPv6 = FALSE; + config.AccessPoint.IPv4Node = &config_access; + config_access.UseDefaultAddress = TRUE; + config_access.LocalPort = 0; + status = oh->http->Configure(oh->http, &config); + if (EFI_ERROR(status)) { + sb->DestroyChild(sb, oh->http_handle); + err = efi_status_to_errno(status); + goto end; + } + + /* + * Here we make attempt to construct a "base" URI by stripping + * the last two path components from the loaded URI under the + * assumption that it is something like: + * + * http://127.0.0.1/foo/boot/loader.efi + * + * hoping to arriving at: + * + * http://127.0.0.1/foo/ + */ + len = DevicePathNodeLength(&uri->Header) - sizeof(URI_DEVICE_PATH); + oh->uri_base = malloc(len + 1); + if (oh->uri_base == NULL) { + err = ENOMEM; + goto end; + } + strncpy(oh->uri_base, uri->Uri, len); + oh->uri_base[len] = '\0'; + c = strrchr(oh->uri_base, '/'); + if (c != NULL) + *c = '\0'; + c = strrchr(oh->uri_base, '/'); + if (c != NULL && *(c + 1) != '\0') + *(c + 1) = '\0'; + + err = 0; +end: + if (err != 0) { + free(dev->d_opendata); + dev->d_opendata = NULL; + } + return (err); +} + +static int +efihttp_dev_close(struct open_file *f) +{ + EFI_SERVICE_BINDING_PROTOCOL *sb; + struct devdesc *dev; + struct open_efihttp *oh; + EFI_STATUS status; + + dev = (struct devdesc *)f->f_devdata; + oh = (struct open_efihttp *)dev->d_opendata; + status = BS->OpenProtocol(oh->dev_handle, &httpsb_guid, (void **)&sb, + IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + sb->DestroyChild(sb, oh->http_handle); + free(oh->uri_base); + free(oh); + dev->d_opendata = NULL; + return (0); +} + +static int +_efihttp_fs_open(const char *path, struct open_file *f) +{ + EFI_HTTP_CONFIG_DATA config; + EFI_HTTPv4_ACCESS_POINT config_access; + EFI_HTTP_TOKEN token; + EFI_HTTP_MESSAGE message; + EFI_HTTP_REQUEST_DATA request; + EFI_HTTP_RESPONSE_DATA response; + EFI_HTTP_HEADER headers[3]; + char *host, *hostp; + char *c; + struct devdesc *dev; + struct open_efihttp *oh; + struct file_efihttp *fh; + EFI_STATUS status; + int i; + int polltime; + bool done; + + dev = (struct devdesc *)f->f_devdata; + oh = (struct open_efihttp *)dev->d_opendata; + fh = calloc(1, sizeof(struct file_efihttp)); + if (fh == NULL) + return (ENOMEM); + f->f_fsdata = fh; + fh->path = strdup(path); + + /* + * Reset the HTTP state. + * + * EDK II's persistent HTTP connection handling is graceless, + * assuming that all connections are persistent regardless of + * any Connection: header or HTTP version reported by the + * server, and failing to send requests when a more sane + * implementation would seem to be just reestablishing the + * closed connection. + * + * In the hopes of having some robustness, we indicate to the + * server that we will close the connection by using a + * Connection: close header. And then here we manually + * unconfigure and reconfigure the http instance to force the + * connection closed. + */ + memset(&config, 0, sizeof(config)); + memset(&config_access, 0, sizeof(config_access)); + config.AccessPoint.IPv4Node = &config_access; + status = oh->http->GetModeData(oh->http, &config); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + status = oh->http->Configure(oh->http, NULL); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + status = oh->http->Configure(oh->http, &config); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + + /* Send the read request */ + done = false; + status = BS->CreateEvent(EVT_NOTIFY_SIGNAL, TPL_CALLBACK, notify, + &done, &token.Event); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + + /* extract the host portion of the URL */ + host = strdup(oh->uri_base); + if (host == NULL) + return (ENOMEM); + hostp = host; + /* Remove the protocol scheme */ + c = strchr(host, '/'); + if (c != NULL && *(c + 1) == '/') + hostp = (c + 2); + + /* Remove any path information */ + c = strchr(hostp, '/'); + if (c != NULL) + *c = '\0'; + + token.Status = EFI_NOT_READY; + token.Message = &message; + message.Data.Request = &request; + message.HeaderCount = 3; + message.Headers = headers; + message.BodyLength = 0; + message.Body = NULL; + request.Method = HttpMethodGet; + request.Url = calloc(strlen(oh->uri_base) + strlen(path) + 1, 2); + headers[0].FieldName = "Host"; + headers[0].FieldValue = hostp; + headers[1].FieldName = "Connection"; + headers[1].FieldValue = "close"; + headers[2].FieldName = "Accept"; + headers[2].FieldValue = "*/*"; + cpy8to16(oh->uri_base, request.Url, strlen(oh->uri_base)); + cpy8to16(path, request.Url + strlen(oh->uri_base), strlen(path)); + status = oh->http->Request(oh->http, &token); + free(request.Url); + free(host); + if (EFI_ERROR(status)) { + BS->CloseEvent(token.Event); + return (efi_status_to_errno(status)); + } + + polltime = 0; + while (!done && polltime < EFIHTTP_POLL_TIMEOUT) { + status = oh->http->Poll(oh->http); + if (EFI_ERROR(status)) + break; + + if (!done) { + delay(100 * 1000); + polltime += 100; + } + } + BS->CloseEvent(token.Event); + if (EFI_ERROR(token.Status)) + return (efi_status_to_errno(token.Status)); + + /* Wait for the read response */ + done = false; + status = BS->CreateEvent(EVT_NOTIFY_SIGNAL, TPL_CALLBACK, notify, + &done, &token.Event); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + token.Status = EFI_NOT_READY; + token.Message = &message; + message.Data.Response = &response; + message.HeaderCount = 0; + message.Headers = NULL; + message.BodyLength = 0; + message.Body = NULL; + response.StatusCode = HTTP_STATUS_UNSUPPORTED_STATUS; + status = oh->http->Response(oh->http, &token); + if (EFI_ERROR(status)) { + BS->CloseEvent(token.Event); + return (efi_status_to_errno(status)); + } + + polltime = 0; + while (!done && polltime < EFIHTTP_POLL_TIMEOUT) { + status = oh->http->Poll(oh->http); + if (EFI_ERROR(status)) + break; + + if (!done) { + delay(100 * 1000); + polltime += 100; + } + } + BS->CloseEvent(token.Event); + if (EFI_ERROR(token.Status)) { + BS->FreePool(message.Headers); + return (efi_status_to_errno(token.Status)); + } + if (response.StatusCode != HTTP_STATUS_200_OK) { + BS->FreePool(message.Headers); + return (EIO); + } + fh->size = 0; + fh->is_dir = false; + for (i = 0; i < message.HeaderCount; i++) { + if (strcasecmp(message.Headers[i].FieldName, + "Content-Length") == 0) + fh->size = strtoul(message.Headers[i].FieldValue, NULL, + 10); + else if (strcasecmp(message.Headers[i].FieldName, + "Content-type") == 0) { + if (strncmp(message.Headers[i].FieldValue, "text/html", + 9) == 0) + fh->is_dir = true; + } + } + + return (0); +} + +static int +efihttp_fs_open(const char *path, struct open_file *f) +{ + char *path_slash; + int err; + + /* + * If any path fails to open, try with a trailing slash in + * case it's a directory. + */ + err = _efihttp_fs_open(path, f); + if (err != 0) { + path_slash = malloc(strlen(path) + 2); + if (path_slash == NULL) + return (ENOMEM); + strcpy(path_slash, path); + strcat(path_slash, "/"); + err = _efihttp_fs_open(path_slash, f); + free(path_slash); + } + return (err); +} + +static int +efihttp_fs_close(struct open_file *f) +{ + return (0); +} + +static int +_efihttp_fs_read(struct open_file *f, void *buf, size_t size, size_t *resid) +{ + EFI_HTTP_TOKEN token; + EFI_HTTP_MESSAGE message; + EFI_STATUS status; + struct devdesc *dev; + struct open_efihttp *oh; + struct file_efihttp *fh; + bool done; + int polltime; + + fh = (struct file_efihttp *)f->f_fsdata; + + if (fh->size > 0 && fh->offset >= fh->size) { + if (resid != NULL) + *resid = size; + + return 0; + } + + dev = (struct devdesc *)f->f_devdata; + oh = (struct open_efihttp *)dev->d_opendata; + done = false; + status = BS->CreateEvent(EVT_NOTIFY_SIGNAL, TPL_CALLBACK, notify, + &done, &token.Event); + if (EFI_ERROR(status)) { + return (efi_status_to_errno(status)); + } + token.Status = EFI_NOT_READY; + token.Message = &message; + message.Data.Request = NULL; + message.HeaderCount = 0; + message.Headers = NULL; + message.BodyLength = size; + message.Body = buf; + status = oh->http->Response(oh->http, &token); + if (status == EFI_CONNECTION_FIN) { + if (resid) + *resid = size; + return (0); + } else if (EFI_ERROR(status)) { + BS->CloseEvent(token.Event); + return (efi_status_to_errno(status)); + } + polltime = 0; + while (!done && polltime < EFIHTTP_POLL_TIMEOUT) { + status = oh->http->Poll(oh->http); + if (EFI_ERROR(status)) + break; + + if (!done) { + delay(100 * 1000); + polltime += 100; + } + } + BS->CloseEvent(token.Event); + if (token.Status == EFI_CONNECTION_FIN) { + if (resid) + *resid = size; + return (0); + } else if (EFI_ERROR(token.Status)) + return (efi_status_to_errno(token.Status)); + if (resid) + *resid = size - message.BodyLength; + fh->offset += message.BodyLength; + return (0); +} + +static int +efihttp_fs_read(struct open_file *f, void *buf, size_t size, size_t *resid) +{ + size_t res; + int err; + + while (size > 0) { + err = _efihttp_fs_read(f, buf, size, &res); + if (err != 0 || res == size) + goto end; + buf += (size - res); + size = res; + } +end: + if (resid) + *resid = size; + return (err); +} + +static int +efihttp_fs_write(struct open_file *f, const void *buf, size_t size, size_t *resid) +{ + return (EIO); +} + +static off_t +efihttp_fs_seek(struct open_file *f, off_t offset, int where) +{ + struct file_efihttp *fh; + char *path; + void *buf; + size_t res, res2; + int err; + + fh = (struct file_efihttp *)f->f_fsdata; + if (where == SEEK_SET && fh->offset == offset) + return (0); + if (where == SEEK_SET && fh->offset < offset) { + buf = malloc(1500); + res = offset - fh->offset; + while (res > 0) { + err = _efihttp_fs_read(f, buf, min(1500, res), &res2); + if (err != 0) { + free(buf); + return (err); + } + res -= min(1500, res) - res2; + } + free(buf); + return (0); + } else if (where == SEEK_SET) { + path = fh->path; + fh->path = NULL; + efihttp_fs_close(f); + err = efihttp_fs_open(path, f); + free(path); + if (err != 0) + return (err); + return efihttp_fs_seek(f, offset, where); + } + return (EIO); +} + +static int +efihttp_fs_stat(struct open_file *f, struct stat *sb) +{ + struct file_efihttp *fh; + + fh = (struct file_efihttp *)f->f_fsdata; + memset(sb, 0, sizeof(*sb)); + sb->st_nlink = 1; + sb->st_mode = 0777 | (fh->is_dir ? S_IFDIR : S_IFREG); + sb->st_size = fh->size; + return (0); +} + +static int +efihttp_fs_readdir(struct open_file *f, struct dirent *d) +{ + static char *dirbuf = NULL, *db2, *cursor; + static int dirbuf_len = 0; + char *end; + struct file_efihttp *fh; + + fh = (struct file_efihttp *)f->f_fsdata; + if (dirbuf_len < fh->size) { + db2 = realloc(dirbuf, fh->size); + if (db2 == NULL) { + free(dirbuf); + return (ENOMEM); + } else + dirbuf = db2; + + dirbuf_len = fh->size; + } + + if (fh->offset != fh->size) { + efihttp_fs_seek(f, 0, SEEK_SET); + efihttp_fs_read(f, dirbuf, dirbuf_len, NULL); + cursor = dirbuf; + } + + cursor = strstr(cursor, "d_type = DT_DIR; + } else + d->d_type = DT_REG; + memcpy(d->d_name, cursor, end - cursor); + d->d_name[end - cursor] = '\0'; + + return (0); +} diff --git a/stand/efi/loader/conf.c b/stand/efi/loader/conf.c index 2e4d35f88a6c..d08ded39b4f2 100644 --- a/stand/efi/loader/conf.c +++ b/stand/efi/loader/conf.c @@ -39,6 +39,7 @@ struct devsw *devsw[] = { &efipart_fddev, &efipart_cddev, &efipart_hddev, + &efihttp_dev, /* ordering with efinet_dev matters */ &efinet_dev, &vdisk_dev, #ifdef EFI_ZFS_BOOT @@ -54,6 +55,7 @@ struct fs_ops *file_system[] = { &dosfs_fsops, &ufs_fsops, &cd9660_fsops, + &efihttp_fsops, &tftp_fsops, &nfs_fsops, &gzipfs_fsops, diff --git a/stand/libsa/stand.h b/stand/libsa/stand.h index 5e44e31ff2d9..d7584ee01fe7 100644 --- a/stand/libsa/stand.h +++ b/stand/libsa/stand.h @@ -126,6 +126,7 @@ extern struct fs_ops dosfs_fsops; extern struct fs_ops ext2fs_fsops; extern struct fs_ops splitfs_fsops; extern struct fs_ops pkgfs_fsops; +extern struct fs_ops efihttp_fsops; /* where values for lseek(2) */ #define SEEK_SET 0 /* set file offset to offset */ From f62da49b2f17f279ddba946bf4bc7ba7247273a5 Mon Sep 17 00:00:00 2001 From: Justin Hibbits Date: Tue, 25 Jun 2019 00:40:44 +0000 Subject: [PATCH 079/165] powerpc: Transition to Secure-PLT, like most other OSs Summary: PowerPC has two PLT models: BSS-PLT and Secure-PLT. BSS-PLT uses runtime code generation to generate the PLT stubs. Secure-PLT was introduced with GCC 4.1 and Binutils 2.17 (base has GCC 4.2.1 and Binutils 2.17), and is a more secure PLT format, using a read-only linkage table, with the dynamic linker populating a non-executable index table. This is the libc, rtld, and kernel support only. The toolchain and build parts will be updated separately. Reviewed By: nwhitehorn, bdragon, pfg Differential Revision: https://reviews.freebsd.org/D20598 MFC after: 1 month --- contrib/gcc/config/rs6000/tramp.asm | 3 +- lib/libc/powerpc/SYS.h | 7 ++- lib/libc/powerpc/gen/_ctx_start.S | 9 +++- lib/libc/powerpc/sys/cerror.S | 23 +++++++--- libexec/rtld-elf/powerpc/reloc.c | 27 +++++++++++- libexec/rtld-elf/powerpc/rtld_start.S | 63 ++++++++++++++++----------- libexec/rtld-elf/rtld.c | 6 +++ libexec/rtld-elf/rtld.h | 4 ++ sys/powerpc/powerpc/machdep.c | 13 ++++++ 9 files changed, 116 insertions(+), 39 deletions(-) diff --git a/contrib/gcc/config/rs6000/tramp.asm b/contrib/gcc/config/rs6000/tramp.asm index 013cac363b68..fe05401e039c 100644 --- a/contrib/gcc/config/rs6000/tramp.asm +++ b/contrib/gcc/config/rs6000/tramp.asm @@ -38,6 +38,7 @@ .file "tramp.asm" .section ".text" #include "ppc-asm.h" + #include "auto-host.h" #ifndef __powerpc64__ .type trampoline_initial,@object @@ -105,7 +106,7 @@ FUNC_START(__trampoline_setup) blr .Labort: -#if defined SHARED && defined HAVE_AS_REL16 +#if (defined(__PIC__) || defined(__pic__)) && defined HAVE_AS_REL16 bcl 20,31,1f 1: mflr r30 addis r30,r30,_GLOBAL_OFFSET_TABLE_-1b@ha diff --git a/lib/libc/powerpc/SYS.h b/lib/libc/powerpc/SYS.h index 63a5ec47c4b4..e9b6d3226c97 100644 --- a/lib/libc/powerpc/SYS.h +++ b/lib/libc/powerpc/SYS.h @@ -44,7 +44,7 @@ #define SYSCALL(name) \ .text; \ .align 2; \ -2: b PIC_PLT(CNAME(HIDENAME(cerror))); \ +2: b CNAME(HIDENAME(cerror)); \ ENTRY(__sys_##name); \ WEAK_REFERENCE(__sys_##name, name); \ WEAK_REFERENCE(__sys_##name, _##name); \ @@ -58,15 +58,14 @@ ENTRY(__sys_##name); \ WEAK_REFERENCE(__sys_##name, _##name); \ _SYSCALL(name); \ bnslr; \ - b PIC_PLT(CNAME(HIDENAME(cerror))) + b CNAME(HIDENAME(cerror)) #define RSYSCALL(name) \ .text; \ .align 2; \ -2: b PIC_PLT(CNAME(HIDENAME(cerror))); \ ENTRY(__sys_##name); \ WEAK_REFERENCE(__sys_##name, name); \ WEAK_REFERENCE(__sys_##name, _##name); \ _SYSCALL(name); \ bnslr; \ - b PIC_PLT(CNAME(HIDENAME(cerror))) + b CNAME(HIDENAME(cerror)) diff --git a/lib/libc/powerpc/gen/_ctx_start.S b/lib/libc/powerpc/gen/_ctx_start.S index 4b9fc1d53ae0..70b4a9d91c8c 100644 --- a/lib/libc/powerpc/gen/_ctx_start.S +++ b/lib/libc/powerpc/gen/_ctx_start.S @@ -35,11 +35,18 @@ mtlr %r14 blrl /* branch to start function */ mr %r3,%r15 /* pass pointer to ucontext as argument */ - bl PIC_PLT(CNAME(_ctx_done)) /* branch to ctxt completion func */ + bl CNAME(_ctx_done) /* branch to ctxt completion func */ + /* * we should never return from the * above branch. */ + /* Don't bother saving off %r30, we're already in a bad state. */ + bcl 20,31,1f +1: mflr %r30 + mr %r3,%r30 # save for _DYNAMIC + addis %r30,%r30,_GLOBAL_OFFSET_TABLE_-1b@ha + addi %r30,%r30,_GLOBAL_OFFSET_TABLE_-1b@l bl PIC_PLT(CNAME(abort)) /* abort */ END(_cts_start) diff --git a/lib/libc/powerpc/sys/cerror.S b/lib/libc/powerpc/sys/cerror.S index 7667cb8361d3..c2bc994b9c33 100644 --- a/lib/libc/powerpc/sys/cerror.S +++ b/lib/libc/powerpc/sys/cerror.S @@ -40,16 +40,27 @@ __FBSDID("$FreeBSD$"); */ HIDENAME(cerror): mflr %r0 - stwu %r1,-16(%r1) /* allocate new stack frame */ - stw %r0,20(%r1) /* and save lr, r31 */ - stw %r31,8(%r1) + stwu %r1,-20(%r1) /* allocate new stack frame */ + stw %r0,24(%r1) /* and save lr, r31 */ + stw %r31,12(%r1) +#ifdef __PIC__ + stw %r30,8(%r1) + bcl 20,31,1f +1: + mflr %r30 + addis %r30,%r30,_GLOBAL_OFFSET_TABLE_-1b@ha + addi %r30,%r30,_GLOBAL_OFFSET_TABLE_-1b@l +#endif mr %r31,%r3 /* stash errval in callee-saved register */ bl PIC_PLT(CNAME(__error)) stw %r31,0(%r3) /* store errval into &errno */ - lwz %r0,20(%r1) - lwz %r31,8(%r1) + lwz %r0,24(%r1) + lwz %r31,12(%r1) +#ifdef __PIC__ + lwz %r30,8(%r1) +#endif mtlr %r0 - la %r1,16(%r1) + la %r1,20(%r1) li %r3,-1 li %r4,-1 blr /* return to callers caller */ diff --git a/libexec/rtld-elf/powerpc/reloc.c b/libexec/rtld-elf/powerpc/reloc.c index 382417ca3490..c923c7326079 100644 --- a/libexec/rtld-elf/powerpc/reloc.c +++ b/libexec/rtld-elf/powerpc/reloc.c @@ -57,6 +57,8 @@ #define JMPTAB_BASE(N) (18 + N*2 + ((N > PLT_EXTENDED_BEGIN) ? \ (N - PLT_EXTENDED_BEGIN)*2 : 0)) +void _rtld_bind_secureplt_start(void); + /* * Process the R_PPC_COPY relocations */ @@ -361,6 +363,11 @@ reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela) if (reloff < 0) return (-1); + if (obj->gotptr != NULL) { + *where += (Elf_Addr)obj->relocbase; + return (0); + } + pltlongresolve = obj->pltgot + 5; pltresolve = pltlongresolve + 5; @@ -425,7 +432,7 @@ reloc_plt(Obj_Entry *obj, int flags __unused, RtldLockState *lockstate __unused) * Sync the icache for the byte range represented by the * trampoline routines and call slots. */ - if (obj->pltgot != NULL) + if (obj->pltgot != NULL && obj->gotptr == NULL) __syncicache(obj->pltgot, JMPTAB_BASE(N)*4); return (0); @@ -501,6 +508,14 @@ reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, */ offset = target - (Elf_Addr)wherep; + if (obj->gotptr != NULL) { + assert(wherep >= (Elf_Word *)obj->pltgot); + assert(wherep < + (Elf_Word *)obj->pltgot + obj->pltrelasize); + *wherep = target; + goto out; + } + if (abs((int)offset) < 32*1024*1024) { /* inside 32MB? */ /* b value # branch directly */ *wherep = 0x48000000 | (offset & 0x03fffffc); @@ -579,6 +594,16 @@ init_pltgot(Obj_Entry *obj) return; } + /* Handle Secure-PLT first, if applicable. */ + if (obj->gotptr != NULL) { + obj->gotptr[1] = (Elf_Addr)_rtld_bind_secureplt_start; + obj->gotptr[2] = (Elf_Addr)obj; + dbg("obj %s secure-plt gotptr=%p start=%p obj=%p", + obj->path, obj->gotptr, + (void *)obj->gotptr[1], (void *)obj->gotptr[2]); + return; + } + /* * From the SVR4 PPC ABI: * diff --git a/libexec/rtld-elf/powerpc/rtld_start.S b/libexec/rtld-elf/powerpc/rtld_start.S index 28ec19bad110..5a2cd7bd2652 100644 --- a/libexec/rtld-elf/powerpc/rtld_start.S +++ b/libexec/rtld-elf/powerpc/rtld_start.S @@ -52,35 +52,22 @@ _ENTRY(.rtld_start) * - use link-time constants to determine offset to the * _DYNAMIC section and the GOT. Add these to the PC to * convert to absolute addresses. - * - sync icache to allow execution of the SVR4 ABI-specified - * blrl instruction preceding the GOT - * - Use this instruction to determine the GOT absolute address * - read GOT[0], which is the SVR4 ABI-specified link-time * value of _DYNAMIC. Subtract this value from the absolute * value to determine the load address * - call reloc_non_plt_self() to fix up ld-elf.so's relocations */ - bl 1f - .long _DYNAMIC-. - .long _GLOBAL_OFFSET_TABLE_-. /* branch lr + 4 */ -1: - mflr %r3 /* PC value at .long */ - lwz %r4,4(%r3) - add %r4,%r4,%r3 /* &_GLOBAL_OFFSET_TABLE-4, blrl insn. */ - dcbst %r0,%r4 /* sync i-cache with d-cache */ - sync - icbi %r0,%r4 - isync - - lwz %r4,0(%r3) /* offset to _DYNAMIC */ - add %r3,%r4,%r3 /* r3 = &_DYNAMIC, absolute value */ - - bl _GLOBAL_OFFSET_TABLE_@local-4 - mflr %r4 /* &_GLOBAL_OFFSET_TABLE_, absolute value */ - lwz %r4,0(%r4) /* linker &_DYNAMIC, from got[0] */ - subf %r4,%r4,%r3 /* subtract to calculate relocbase */ - - bl reloc_non_plt_self@plt /* reloc_non_plt_self(&_DYNAMIC,base) */ + bcl 20,31,1f +1: mflr %r30 + mr %r3,%r30 # save for _DYNAMIC + addis %r30,%r30,_GLOBAL_OFFSET_TABLE_-1b@ha + addi %r30,%r30,_GLOBAL_OFFSET_TABLE_-1b@l + addis %r3,%r3,_DYNAMIC-1b@ha # get _DYNAMIC actual address + addi %r3,%r3,_DYNAMIC-1b@l + lwz %r28,0(%r30) # get base-relative &_DYNAMIC + sub %r28,%r3,%r28 # r28 = relocbase + mr %r4,%r28 # r4 = relocbase + bl reloc_non_plt_self /* reloc_non_plt_self(&_DYNAMIC,base) */ /* * The _rtld() function likes to see a stack layout containing @@ -95,7 +82,7 @@ _ENTRY(.rtld_start) addi %r4,%r1,8 /* &exit_proc on stack */ addi %r5,%r1,12 /* &obj_main on stack */ - bl _rtld@plt /* &_start = _rtld(sp, &exit_proc, &obj_main)*/ + bl _rtld /* &_start = _rtld(sp, &exit_proc, &obj_main)*/ mtlr %r3 /* @@ -114,6 +101,29 @@ _ENTRY(.rtld_start) li %r0,1 /* _exit() */ sc +/* + * _rtld_bind_secureplt_start() + * + * Call into the MI binder (Secure-PLT stub). + * secure-plt expects %r11 to be the offset to the rela entry. + * bss-plt expects %r11 to be index of the rela entry. + * So for bss-plt, we multiply the index by 12 to get the offset. + */ +_ENTRY(_rtld_bind_secureplt_start) + stwu %r1,-160(%r1) # stack space for 29 regs + r0/lr/cr + stw %r0,20(%r1) # save r0 + + /* + * Instead of division which is costly we will use multiplicative + * inverse. a / n = ((a * inv(n)) >> 32) + * where inv(n) = (0x100000000 + n - 1) / n + */ + mr %r0,%r11 + lis %r11,0x15555556@h # load multiplicative inverse of 12 + ori %r11,%r11,0x15555556@l + mulhwu %r11,%r11,%r0 # get high half of multiplication + b 1f + /* * _rtld_bind_start() * @@ -129,6 +139,7 @@ _ENTRY(.rtld_start) _ENTRY(_rtld_bind_start) stwu %r1,-160(%r1) # stack space for 29 regs + r0/lr/cr stw %r0,20(%r1) # save r0 +1: mflr %r0 stw %r0,16(%r1) # save lr mfcr %r0 @@ -137,7 +148,7 @@ _ENTRY(_rtld_bind_start) mr %r3,%r12 # obj mulli %r4,%r11,12 # rela index * sizeof(Elf_Rela) - bl _rtld_bind@PLT # target addr = _rtld_bind(obj, reloff) + bl _rtld_bind # target addr = _rtld_bind(obj, reloff) mtctr %r3 # move absolute target addr into ctr lmw %r3,24(%r1) # restore r3-r31 diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index 7cdd5c58c5dc..ece58e138235 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -1286,10 +1286,16 @@ digest_dynamic1(Obj_Entry *obj, int early, const Elf_Dyn **dyn_rpath, #endif +#ifdef __powerpc__ #ifdef __powerpc64__ case DT_PPC64_GLINK: obj->glink = (Elf_Addr)(obj->relocbase + dynp->d_un.d_ptr); break; +#else + case DT_PPC_GOT: + obj->gotptr = (Elf_Addr *)(obj->relocbase + dynp->d_un.d_ptr); + break; +#endif #endif case DT_FLAGS_1: diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h index d7ef9d56b8d0..fc9f10255811 100644 --- a/libexec/rtld-elf/rtld.h +++ b/libexec/rtld-elf/rtld.h @@ -190,8 +190,12 @@ typedef struct Struct_Obj_Entry { Elf_Word gotsym; /* First dynamic symbol in GOT */ Elf_Addr *mips_pltgot; /* Second PLT GOT */ #endif +#ifdef __powerpc__ #ifdef __powerpc64__ Elf_Addr glink; /* GLINK PLT call stub section */ +#else + Elf_Addr *gotptr; /* GOT pointer (secure-plt only) */ +#endif #endif const Elf_Verneed *verneed; /* Required versions. */ diff --git a/sys/powerpc/powerpc/machdep.c b/sys/powerpc/powerpc/machdep.c index 6fb874e31d9c..0bd6a11197ab 100644 --- a/sys/powerpc/powerpc/machdep.c +++ b/sys/powerpc/powerpc/machdep.c @@ -595,3 +595,16 @@ bzero(void *buf, size_t len) len--; } } + +/* __stack_chk_fail_local() is called in secure-plt (32-bit). */ +#if !defined(__powerpc64__) +extern void __stack_chk_fail(void); +void __stack_chk_fail_local(void); + +void +__stack_chk_fail_local(void) +{ + + __stack_chk_fail(); +} +#endif From e861dab451869582008237a8c11e97348d2440ce Mon Sep 17 00:00:00 2001 From: Justin Hibbits Date: Tue, 25 Jun 2019 02:35:22 +0000 Subject: [PATCH 080/165] powerpc: Transition to Secure-PLT, like most other OSs (Toolchain part) Summary: Toolchain follow-up to r349350. LLVM patches will be submitted upstream for 9.0 as well. The bsd.cpu.mk change is required because GNU ld assumes BSS-PLT if it cannot determine for certain that it needs Secure-PLT, and some binaries do not compile in such a way to make it know to use Secure-PLT. Reviewed By: nwhitehorn, bdragon, pfg Differential Revision: https://reviews.freebsd.org/D20598 --- contrib/llvm/lib/Target/PowerPC/PPCSubtarget.cpp | 3 ++- contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/PPC.cpp | 3 ++- gnu/usr.bin/cc/cc_tools/Makefile.hdrs | 3 +++ share/mk/bsd.cpu.mk | 4 ++++ 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/llvm/lib/Target/PowerPC/PPCSubtarget.cpp b/contrib/llvm/lib/Target/PowerPC/PPCSubtarget.cpp index 1fdf74549dec..57244ddff552 100644 --- a/contrib/llvm/lib/Target/PowerPC/PPCSubtarget.cpp +++ b/contrib/llvm/lib/Target/PowerPC/PPCSubtarget.cpp @@ -138,7 +138,8 @@ void PPCSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) { if (isDarwin()) HasLazyResolverStubs = true; - if (TargetTriple.isOSNetBSD() || TargetTriple.isOSOpenBSD()) + if ((TargetTriple.isOSFreeBSD() && TargetTriple.getOSMajorVersion() >= 13) + || TargetTriple.isOSNetBSD() || TargetTriple.isOSOpenBSD()) SecurePlt = true; if (HasSPE && IsPPC64) diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/PPC.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/PPC.cpp index 791f1206cf25..a85ff8d30a2e 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/PPC.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/PPC.cpp @@ -116,7 +116,8 @@ ppc::ReadGOTPtrMode ppc::getPPCReadGOTPtrMode(const Driver &D, const llvm::Tripl const ArgList &Args) { if (Args.getLastArg(options::OPT_msecure_plt)) return ppc::ReadGOTPtrMode::SecurePlt; - if (Triple.isOSOpenBSD()) + if ((Triple.isOSFreeBSD() && Triple.getOSMajorVersion() >= 13) || + Triple.isOSOpenBSD()) return ppc::ReadGOTPtrMode::SecurePlt; else return ppc::ReadGOTPtrMode::Bss; diff --git a/gnu/usr.bin/cc/cc_tools/Makefile.hdrs b/gnu/usr.bin/cc/cc_tools/Makefile.hdrs index f2576f7fdf0a..dc5bcb7a2d94 100644 --- a/gnu/usr.bin/cc/cc_tools/Makefile.hdrs +++ b/gnu/usr.bin/cc/cc_tools/Makefile.hdrs @@ -21,6 +21,9 @@ TARGET_INC+= ${GCC_CPU}/${GCC_CPU}.h TARGET_INC+= ${GCC_CPU}/unix.h TARGET_INC+= ${GCC_CPU}/att.h .endif +.if ${TARGET_CPUARCH} == "powerpc" +TARGET_INC+= ${GCC_CPU}/secureplt.h +.endif TARGET_INC+= dbxelf.h TARGET_INC+= elfos-undef.h TARGET_INC+= elfos.h diff --git a/share/mk/bsd.cpu.mk b/share/mk/bsd.cpu.mk index acf1f5922593..c16ab5a85bf6 100644 --- a/share/mk/bsd.cpu.mk +++ b/share/mk/bsd.cpu.mk @@ -369,6 +369,10 @@ CFLAGS += -mfloat-abi=softfp .endif .endif +.if ${MACHINE_ARCH} == "powerpc" || ${MACHINE_ARCH} == "powerpcspe" +LDFLAGS+= -Wl,--secure-plt +.endif + .if ${MACHINE_ARCH} == "powerpcspe" CFLAGS += -mcpu=8548 -Wa,-me500 -mspe=yes -mabi=spe -mfloat-gprs=double .endif From f5a95d9a07941650493461c255408f5727d0638b Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Tue, 25 Jun 2019 04:50:09 +0000 Subject: [PATCH 081/165] Remove NAND and NANDFS support NANDFS has been broken for years. Remove it. The NAND drivers that remain are for ancient parts that are no longer relevant. They are polled, have terrible performance and just for ancient arm hardware. NAND parts have evolved significantly from this early work and little to none of it would be relevant should someone need to update to support raw nand. This code has been off by default for years and has violated the vnode protocol leading to panics since it was committed. Numerous posts to arch@ and other locations have found no actual users for this software. Relnotes: Yes No Objection From: arch@ Differential Revision: https://reviews.freebsd.org/D20745 --- etc/mtree/BSD.include.dist | 4 - include/Makefile | 20 +- lib/Makefile | 1 - lib/libnandfs/Makefile | 10 - lib/libnandfs/Makefile.depend | 17 - lib/libnandfs/libnandfs.h | 67 - lib/libnandfs/nandfs.c | 249 -- sbin/Makefile | 2 - sbin/camcontrol/camcontrol.c | 24 +- sbin/nandfs/Makefile | 10 - sbin/nandfs/Makefile.depend | 18 - sbin/nandfs/lssnap.c | 114 - sbin/nandfs/mksnap.c | 82 - sbin/nandfs/nandfs.8 | 79 - sbin/nandfs/nandfs.c | 76 - sbin/nandfs/nandfs.h | 42 - sbin/nandfs/rmsnap.c | 89 - sbin/newfs_nandfs/Makefile | 9 - sbin/newfs_nandfs/Makefile.depend | 20 - sbin/newfs_nandfs/newfs_nandfs.8 | 74 - sbin/newfs_nandfs/newfs_nandfs.c | 1183 --------- share/man/man4/Makefile | 2 - share/man/man4/nand.4 | 145 -- share/man/man4/nandsim.4 | 93 - share/man/man5/Makefile | 4 - share/man/man5/nandfs.5 | 132 - share/mk/bsd.libnames.mk | 1 - share/mk/src.libnames.mk | 1 - share/mk/src.opts.mk | 1 - stand/arm/uboot/conf.c | 3 - stand/arm/uboot/version | 1 + stand/common/part.c | 8 - stand/common/part.h | 1 - stand/i386/loader/conf.c | 3 - stand/libsa/Makefile | 3 - stand/libsa/nandfs.c | 1061 -------- stand/libsa/stand.h | 1 - stand/loader.mk | 3 - stand/mips/uboot/conf.c | 3 - stand/mips/uboot/version | 1 + sys/arm/conf/DB-78XXX | 3 - sys/arm/conf/DB-88F6XXX | 3 - sys/arm/conf/DREAMPLUG-1001 | 8 - sys/arm/conf/NOTES.armv5 | 5 - sys/arm/conf/SHEEVAPLUG | 3 - sys/arm/conf/VYBRID | 3 - sys/arm/freescale/vybrid/vf_nfc.c | 528 ---- sys/arm/mv/files.arm7 | 1 - sys/arm/mv/files.mv | 1 - sys/cam/ata/ata_all.c | 25 - sys/cam/ata/ata_all.h | 1 - sys/cam/ata/ata_xpt.c | 23 +- sys/cam/scsi/scsi_da.c | 19 +- sys/conf/files | 33 +- sys/conf/files.powerpc | 2 - sys/conf/kern.opts.mk | 1 - sys/dev/nand/nand.c | 826 ------- sys/dev/nand/nand.h | 415 ---- sys/dev/nand/nand_bbt.c | 275 --- sys/dev/nand/nand_cdev.c | 454 ---- sys/dev/nand/nand_dev.h | 92 - sys/dev/nand/nand_ecc_pos.h | 58 - sys/dev/nand/nand_generic.c | 1366 ----------- sys/dev/nand/nand_geom.c | 467 ---- sys/dev/nand/nand_id.c | 70 - sys/dev/nand/nand_if.m | 168 -- sys/dev/nand/nandbus.c | 542 ---- sys/dev/nand/nandbus.h | 51 - sys/dev/nand/nandbus_if.m | 100 - sys/dev/nand/nandsim.c | 670 ----- sys/dev/nand/nandsim.h | 177 -- sys/dev/nand/nandsim_chip.c | 898 ------- sys/dev/nand/nandsim_chip.h | 161 -- sys/dev/nand/nandsim_ctrl.c | 398 --- sys/dev/nand/nandsim_log.c | 188 -- sys/dev/nand/nandsim_log.h | 54 - sys/dev/nand/nandsim_swap.c | 383 --- sys/dev/nand/nandsim_swap.h | 66 - sys/dev/nand/nfc_fsl.c | 717 ------ sys/dev/nand/nfc_fsl.h | 99 - sys/dev/nand/nfc_if.m | 165 -- sys/dev/nand/nfc_mv.c | 238 -- sys/dev/nand/nfc_rb.c | 321 --- sys/fs/nandfs/bmap.c | 625 ----- sys/fs/nandfs/bmap.h | 42 - sys/fs/nandfs/nandfs.h | 312 --- sys/fs/nandfs/nandfs_alloc.c | 366 --- sys/fs/nandfs/nandfs_bmap.c | 232 -- sys/fs/nandfs/nandfs_buffer.c | 85 - sys/fs/nandfs/nandfs_cleaner.c | 622 ----- sys/fs/nandfs/nandfs_cpfile.c | 778 ------ sys/fs/nandfs/nandfs_dat.c | 346 --- sys/fs/nandfs/nandfs_dir.c | 316 --- sys/fs/nandfs/nandfs_fs.h | 567 ----- sys/fs/nandfs/nandfs_ifile.c | 215 -- sys/fs/nandfs/nandfs_mount.h | 52 - sys/fs/nandfs/nandfs_segment.c | 1314 ---------- sys/fs/nandfs/nandfs_subr.c | 1091 --------- sys/fs/nandfs/nandfs_subr.h | 240 -- sys/fs/nandfs/nandfs_sufile.c | 571 ----- sys/fs/nandfs/nandfs_vfsops.c | 1601 ------------ sys/fs/nandfs/nandfs_vnops.c | 2454 ------------------- sys/fs/smbfs/smbfs_io.c | 4 + sys/geom/geom_flashmap.c | 24 - sys/modules/Makefile | 7 - sys/modules/nand/Makefile | 10 - sys/modules/nandfs/Makefile | 12 - sys/modules/nandsim/Makefile | 9 - sys/sys/param.h | 2 +- targets/pseudo/userland/Makefile.depend | 9 - targets/pseudo/userland/lib/Makefile.depend | 4 - usr.bin/vtfontcvt/vtfontcvt.c | 13 +- usr.sbin/Makefile | 2 - usr.sbin/bhyve/Makefile | 3 - usr.sbin/bhyve/audio.c | 282 --- usr.sbin/bhyve/audio.h | 86 - usr.sbin/bhyve/bhyve.8 | 14 +- usr.sbin/bhyve/hda_codec.c | 950 ------- usr.sbin/bhyve/hda_reg.h | 1367 ----------- usr.sbin/bhyve/hdac_reg.h | 269 -- usr.sbin/bhyve/pci_hda.c | 1330 ---------- usr.sbin/bhyve/pci_hda.h | 90 - usr.sbin/nandsim/Makefile | 8 - usr.sbin/nandsim/Makefile.depend | 17 - usr.sbin/nandsim/nandsim.8 | 229 -- usr.sbin/nandsim/nandsim.c | 1399 ----------- usr.sbin/nandsim/nandsim_cfgparse.c | 961 -------- usr.sbin/nandsim/nandsim_cfgparse.h | 88 - usr.sbin/nandsim/nandsim_rcfile.c | 442 ---- usr.sbin/nandsim/nandsim_rcfile.h | 72 - usr.sbin/nandsim/sample.conf | 174 -- usr.sbin/nandtool/Makefile | 10 - usr.sbin/nandtool/Makefile.depend | 20 - usr.sbin/nandtool/nand_erase.c | 116 - usr.sbin/nandtool/nand_info.c | 88 - usr.sbin/nandtool/nand_read.c | 141 -- usr.sbin/nandtool/nand_readoob.c | 113 - usr.sbin/nandtool/nand_write.c | 145 -- usr.sbin/nandtool/nand_writeoob.c | 115 - usr.sbin/nandtool/nandtool.8 | 184 -- usr.sbin/nandtool/nandtool.c | 285 --- usr.sbin/nandtool/nandtool.h | 59 - usr.sbin/nandtool/usage.h | 114 - 143 files changed, 71 insertions(+), 34760 deletions(-) delete mode 100644 lib/libnandfs/Makefile delete mode 100644 lib/libnandfs/Makefile.depend delete mode 100644 lib/libnandfs/libnandfs.h delete mode 100644 lib/libnandfs/nandfs.c delete mode 100644 sbin/nandfs/Makefile delete mode 100644 sbin/nandfs/Makefile.depend delete mode 100644 sbin/nandfs/lssnap.c delete mode 100644 sbin/nandfs/mksnap.c delete mode 100644 sbin/nandfs/nandfs.8 delete mode 100644 sbin/nandfs/nandfs.c delete mode 100644 sbin/nandfs/nandfs.h delete mode 100644 sbin/nandfs/rmsnap.c delete mode 100644 sbin/newfs_nandfs/Makefile delete mode 100644 sbin/newfs_nandfs/Makefile.depend delete mode 100644 sbin/newfs_nandfs/newfs_nandfs.8 delete mode 100644 sbin/newfs_nandfs/newfs_nandfs.c delete mode 100644 share/man/man4/nand.4 delete mode 100644 share/man/man4/nandsim.4 delete mode 100644 share/man/man5/nandfs.5 delete mode 100644 stand/libsa/nandfs.c delete mode 100644 sys/arm/freescale/vybrid/vf_nfc.c delete mode 100644 sys/dev/nand/nand.c delete mode 100644 sys/dev/nand/nand.h delete mode 100644 sys/dev/nand/nand_bbt.c delete mode 100644 sys/dev/nand/nand_cdev.c delete mode 100644 sys/dev/nand/nand_dev.h delete mode 100644 sys/dev/nand/nand_ecc_pos.h delete mode 100644 sys/dev/nand/nand_generic.c delete mode 100644 sys/dev/nand/nand_geom.c delete mode 100644 sys/dev/nand/nand_id.c delete mode 100644 sys/dev/nand/nand_if.m delete mode 100644 sys/dev/nand/nandbus.c delete mode 100644 sys/dev/nand/nandbus.h delete mode 100644 sys/dev/nand/nandbus_if.m delete mode 100644 sys/dev/nand/nandsim.c delete mode 100644 sys/dev/nand/nandsim.h delete mode 100644 sys/dev/nand/nandsim_chip.c delete mode 100644 sys/dev/nand/nandsim_chip.h delete mode 100644 sys/dev/nand/nandsim_ctrl.c delete mode 100644 sys/dev/nand/nandsim_log.c delete mode 100644 sys/dev/nand/nandsim_log.h delete mode 100644 sys/dev/nand/nandsim_swap.c delete mode 100644 sys/dev/nand/nandsim_swap.h delete mode 100644 sys/dev/nand/nfc_fsl.c delete mode 100644 sys/dev/nand/nfc_fsl.h delete mode 100644 sys/dev/nand/nfc_if.m delete mode 100644 sys/dev/nand/nfc_mv.c delete mode 100644 sys/dev/nand/nfc_rb.c delete mode 100644 sys/fs/nandfs/bmap.c delete mode 100644 sys/fs/nandfs/bmap.h delete mode 100644 sys/fs/nandfs/nandfs.h delete mode 100644 sys/fs/nandfs/nandfs_alloc.c delete mode 100644 sys/fs/nandfs/nandfs_bmap.c delete mode 100644 sys/fs/nandfs/nandfs_buffer.c delete mode 100644 sys/fs/nandfs/nandfs_cleaner.c delete mode 100644 sys/fs/nandfs/nandfs_cpfile.c delete mode 100644 sys/fs/nandfs/nandfs_dat.c delete mode 100644 sys/fs/nandfs/nandfs_dir.c delete mode 100644 sys/fs/nandfs/nandfs_fs.h delete mode 100644 sys/fs/nandfs/nandfs_ifile.c delete mode 100644 sys/fs/nandfs/nandfs_mount.h delete mode 100644 sys/fs/nandfs/nandfs_segment.c delete mode 100644 sys/fs/nandfs/nandfs_subr.c delete mode 100644 sys/fs/nandfs/nandfs_subr.h delete mode 100644 sys/fs/nandfs/nandfs_sufile.c delete mode 100644 sys/fs/nandfs/nandfs_vfsops.c delete mode 100644 sys/fs/nandfs/nandfs_vnops.c delete mode 100644 sys/modules/nand/Makefile delete mode 100644 sys/modules/nandfs/Makefile delete mode 100644 sys/modules/nandsim/Makefile delete mode 100644 usr.sbin/bhyve/audio.c delete mode 100644 usr.sbin/bhyve/audio.h delete mode 100644 usr.sbin/bhyve/hda_codec.c delete mode 100644 usr.sbin/bhyve/hda_reg.h delete mode 100644 usr.sbin/bhyve/hdac_reg.h delete mode 100644 usr.sbin/bhyve/pci_hda.c delete mode 100644 usr.sbin/bhyve/pci_hda.h delete mode 100644 usr.sbin/nandsim/Makefile delete mode 100644 usr.sbin/nandsim/Makefile.depend delete mode 100644 usr.sbin/nandsim/nandsim.8 delete mode 100644 usr.sbin/nandsim/nandsim.c delete mode 100644 usr.sbin/nandsim/nandsim_cfgparse.c delete mode 100644 usr.sbin/nandsim/nandsim_cfgparse.h delete mode 100644 usr.sbin/nandsim/nandsim_rcfile.c delete mode 100644 usr.sbin/nandsim/nandsim_rcfile.h delete mode 100644 usr.sbin/nandsim/sample.conf delete mode 100644 usr.sbin/nandtool/Makefile delete mode 100644 usr.sbin/nandtool/Makefile.depend delete mode 100644 usr.sbin/nandtool/nand_erase.c delete mode 100644 usr.sbin/nandtool/nand_info.c delete mode 100644 usr.sbin/nandtool/nand_read.c delete mode 100644 usr.sbin/nandtool/nand_readoob.c delete mode 100644 usr.sbin/nandtool/nand_write.c delete mode 100644 usr.sbin/nandtool/nand_writeoob.c delete mode 100644 usr.sbin/nandtool/nandtool.8 delete mode 100644 usr.sbin/nandtool/nandtool.c delete mode 100644 usr.sbin/nandtool/nandtool.h delete mode 100644 usr.sbin/nandtool/usage.h diff --git a/etc/mtree/BSD.include.dist b/etc/mtree/BSD.include.dist index b0e305558f1a..b774449a17bf 100644 --- a/etc/mtree/BSD.include.dist +++ b/etc/mtree/BSD.include.dist @@ -138,8 +138,6 @@ mpilib .. .. - nand - .. nvme .. ofw @@ -184,8 +182,6 @@ .. msdosfs .. - nandfs - .. nfs .. nullfs diff --git a/include/Makefile b/include/Makefile index bd0ddc10b492..8893eba97ea9 100644 --- a/include/Makefile +++ b/include/Makefile @@ -48,7 +48,7 @@ LSUBDIRS= cam/ata cam/mmc cam/nvme cam/scsi \ dev/ic dev/iicbus dev/io dev/mfi dev/mmc dev/nvme \ dev/ofw dev/pbio dev/pci ${_dev_powermac_nvram} dev/ppbus dev/pwm \ dev/smbus dev/speaker dev/tcp_log dev/veriexec dev/vkbd dev/wi \ - fs/devfs fs/fdescfs fs/msdosfs fs/nandfs fs/nfs fs/nullfs \ + fs/devfs fs/fdescfs fs/msdosfs fs/nfs fs/nullfs \ fs/procfs fs/smbfs fs/udf fs/unionfs \ geom/cache geom/concat geom/eli geom/gate geom/journal geom/label \ geom/mirror geom/mountver geom/multipath geom/nop \ @@ -158,7 +158,7 @@ copies: .PHONY .META done; \ fi .endfor -.for i in ${LDIRS} ${LSUBDIRS:Ndev/agp:Ndev/acpica:Ndev/bktr:Ndev/evdev:Ndev/hyperv:Ndev/nand:Ndev/pci:Ndev/veriexec} ${LSUBSUBDIRS} +.for i in ${LDIRS} ${LSUBDIRS:Ndev/agp:Ndev/acpica:Ndev/bktr:Ndev/evdev:Ndev/hyperv:Ndev/pci:Ndev/veriexec} ${LSUBSUBDIRS} cd ${SRCTOP}/sys; \ ${INSTALL} -C ${TAG_ARGS} -o ${BINOWN} -g ${BINGRP} -m 444 $i/*.h \ ${SDESTDIR}${INCLUDEDIR}/$i @@ -174,13 +174,6 @@ copies: .PHONY .META cd ${SRCTOP}/sys/dev/bktr; \ ${INSTALL} -C ${TAG_ARGS} -o ${BINOWN} -g ${BINGRP} -m 444 ioctl_*.h \ ${SDESTDIR}${INCLUDEDIR}/dev/bktr -.if ${MK_NAND} != "no" - cd ${SRCTOP}/sys/dev/nand; \ - ${INSTALL} -C ${TAG_ARGS} -o ${BINOWN} -g ${BINGRP} -m 444 nandsim.h \ - ${SDESTDIR}${INCLUDEDIR}/dev/nand; \ - ${INSTALL} -C ${TAG_ARGS} -o ${BINOWN} -g ${BINGRP} -m 444 nand_dev.h \ - ${SDESTDIR}${INCLUDEDIR}/dev/nand -.endif cd ${SRCTOP}/sys/dev/evdev; \ ${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 input.h \ ${SDESTDIR}${INCLUDEDIR}/dev/evdev; \ @@ -268,7 +261,7 @@ symlinks: .PHONY .META ${INSTALL_SYMLINK} ${TAG_ARGS} ../../../sys/$i/$$h ${SDESTDIR}${INCLUDEDIR}/$i; \ done .endfor -.for i in ${LSUBDIRS:Ndev/agp:Ndev/acpica:Ndev/bktr:Ndev/evdev:Ndev/hyperv:Ndev/nand:Ndev/pci:Ndev/veriexec} +.for i in ${LSUBDIRS:Ndev/agp:Ndev/acpica:Ndev/bktr:Ndev/evdev:Ndev/hyperv:Ndev/pci:Ndev/veriexec} cd ${SRCTOP}/sys/$i; \ for h in *.h; do \ ${INSTALL_SYMLINK} ${TAG_ARGS} ../../../../sys/$i/$$h ${SDESTDIR}${INCLUDEDIR}/$i; \ @@ -289,13 +282,6 @@ symlinks: .PHONY .META ${INSTALL_SYMLINK} ${TAG_ARGS} ../../../../sys/dev/bktr/$$h \ ${SDESTDIR}${INCLUDEDIR}/dev/bktr; \ done -.if ${MK_NAND} != "no" - cd ${SRCTOP}/sys/dev/nand; \ - for h in nandsim.h nand_dev.h; do \ - ${INSTALL_SYMLINK} ${TAG_ARGS} ../../../../sys/dev/nand/$$h \ - ${SDESTDIR}${INCLUDEDIR}/dev/nand; \ - done -.endif cd ${SRCTOP}/sys/dev/evdev; \ for h in input.h input-event-codes.h uinput.h; do \ ln -fs ../../../../sys/dev/evdev/$$h \ diff --git a/lib/Makefile b/lib/Makefile index f5e89b0712c4..33f31f7f7ed6 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -174,7 +174,6 @@ SUBDIR.${MK_GOOGLETEST}+= googletest SUBDIR.${MK_LIBTHR}+= libthr SUBDIR.${MK_LLVM_LIBUNWIND}+= libgcc_eh SUBDIR.${MK_LLVM_LIBUNWIND}+= libgcc_s -SUBDIR.${MK_NAND}+= libnandfs SUBDIR.${MK_NETGRAPH}+= libnetgraph SUBDIR.${MK_NIS}+= libypclnt diff --git a/lib/libnandfs/Makefile b/lib/libnandfs/Makefile deleted file mode 100644 index e900c3c6eab4..000000000000 --- a/lib/libnandfs/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# $FreeBSD$ - -PACKAGE=lib${LIB} -LIB= nandfs -SRCS+= nandfs.c -INCS= libnandfs.h - -CFLAGS += -I${.CURDIR} - -.include diff --git a/lib/libnandfs/Makefile.depend b/lib/libnandfs/Makefile.depend deleted file mode 100644 index 6cfaab1c3644..000000000000 --- a/lib/libnandfs/Makefile.depend +++ /dev/null @@ -1,17 +0,0 @@ -# $FreeBSD$ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - gnu/lib/csu \ - include \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - lib/libcompiler_rt \ - - -.include - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif diff --git a/lib/libnandfs/libnandfs.h b/lib/libnandfs/libnandfs.h deleted file mode 100644 index 53cd04946d0e..000000000000 --- a/lib/libnandfs/libnandfs.h +++ /dev/null @@ -1,67 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$ - */ - -#ifndef _LIBNANDFS_NANDFS_H -#define _LIBNANDFS_NANDFS_H - -struct nandfs { - struct nandfs_fsdata n_fsdata; - struct nandfs_super_block n_sb; - char n_ioc[MNAMELEN]; - char n_dev[MNAMELEN]; - int n_iocfd; - int n_devfd; - int n_flags; - char n_errmsg[120]; -}; - -int nandfs_iserror(struct nandfs *); -const char *nandfs_errmsg(struct nandfs *); - -void nandfs_init(struct nandfs *, const char *); -void nandfs_destroy(struct nandfs *); - -const char *nandfs_dev(struct nandfs *); - -int nandfs_open(struct nandfs *); -void nandfs_close(struct nandfs *); - -int nandfs_get_cpstat(struct nandfs *, struct nandfs_cpstat *); - -ssize_t nandfs_get_cp(struct nandfs *, uint64_t, - struct nandfs_cpinfo *, size_t); - -ssize_t nandfs_get_snap(struct nandfs *, uint64_t, - struct nandfs_cpinfo *, size_t); - -int nandfs_make_snap(struct nandfs *, uint64_t *); -int nandfs_delete_snap(struct nandfs *, uint64_t); - -#endif /* _LIBNANDFS_NANDFS_H */ diff --git a/lib/libnandfs/nandfs.c b/lib/libnandfs/nandfs.c deleted file mode 100644 index f1dd771ae8fd..000000000000 --- a/lib/libnandfs/nandfs.c +++ /dev/null @@ -1,249 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define NANDFS_IS_VALID 0x1 -#define NANDFS_IS_OPENED 0x2 -#define NANDFS_IS_OPENED_DEV 0x4 -#define NANDFS_IS_ERROR 0x8 - -#define DEBUG -#undef DEBUG -#ifdef DEBUG -#define NANDFS_DEBUG(fmt, args...) do { \ - printf("libnandfs:" fmt "\n", ##args); } while (0) -#else -#define NANDFS_DEBUG(fmt, args...) -#endif - -#define NANDFS_ASSERT_VALID(fs) assert((fs)->n_flags & NANDFS_IS_VALID) -#define NANDFS_ASSERT_VALID_DEV(fs) \ - assert(((fs)->n_flags & (NANDFS_IS_VALID | NANDFS_IS_OPENED_DEV)) == \ - (NANDFS_IS_VALID | NANDFS_IS_OPENED_DEV)) - -int -nandfs_iserror(struct nandfs *fs) -{ - - NANDFS_ASSERT_VALID(fs); - - return (fs->n_flags & NANDFS_IS_ERROR); -} - -const char * -nandfs_errmsg(struct nandfs *fs) -{ - - NANDFS_ASSERT_VALID(fs); - - assert(nandfs_iserror(fs)); - assert(fs->n_errmsg); - return (fs->n_errmsg); -} - -static void -nandfs_seterr(struct nandfs *fs, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vsnprintf(fs->n_errmsg, sizeof(fs->n_errmsg), fmt, ap); - va_end(ap); - fs->n_flags |= NANDFS_IS_ERROR; -} - -const char * -nandfs_dev(struct nandfs *fs) -{ - - NANDFS_ASSERT_VALID(fs); - return (fs->n_dev); -} - -void -nandfs_init(struct nandfs *fs, const char *dir) -{ - - snprintf(fs->n_ioc, sizeof(fs->n_ioc), "%s/%s", dir, "."); - fs->n_iocfd = -1; - fs->n_flags = NANDFS_IS_VALID; -} - -void -nandfs_destroy(struct nandfs *fs) -{ - - assert(fs->n_iocfd == -1); - fs->n_flags &= - ~(NANDFS_IS_ERROR | NANDFS_IS_VALID); - assert(fs->n_flags == 0); -} - -int -nandfs_open(struct nandfs *fs) -{ - struct nandfs_fsinfo fsinfo; - - fs->n_flags |= NANDFS_IS_OPENED; - - fs->n_iocfd = open(fs->n_ioc, O_RDONLY, S_IRUSR | S_IWUSR | S_IRGRP | - S_IWGRP | S_IROTH | S_IWOTH); - if (fs->n_iocfd == -1) { - nandfs_seterr(fs, "couldn't open %s: %s", fs->n_ioc, - strerror(errno)); - return (-1); - } - - if (ioctl(fs->n_iocfd, NANDFS_IOCTL_GET_FSINFO, &fsinfo) == -1) { - nandfs_seterr(fs, "couldn't fetch fsinfo: %s", - strerror(errno)); - return (-1); - } - - memcpy(&fs->n_fsdata, &fsinfo.fs_fsdata, sizeof(fs->n_fsdata)); - memcpy(&fs->n_sb, &fsinfo.fs_super, sizeof(fs->n_sb)); - snprintf(fs->n_dev, sizeof(fs->n_dev), "%s", fsinfo.fs_dev); - - return (0); -} - -void -nandfs_close(struct nandfs *fs) -{ - - NANDFS_ASSERT_VALID(fs); - assert(fs->n_flags & NANDFS_IS_OPENED); - - close(fs->n_iocfd); - fs->n_iocfd = -1; - fs->n_flags &= ~NANDFS_IS_OPENED; -} - -int -nandfs_get_cpstat(struct nandfs *fs, struct nandfs_cpstat *cpstat) -{ - - NANDFS_ASSERT_VALID(fs); - - if (ioctl(fs->n_iocfd, NANDFS_IOCTL_GET_CPSTAT, cpstat) == -1) { - nandfs_seterr(fs, "ioctl NANDFS_IOCTL_GET_CPSTAT: %s", - strerror(errno)); - return (-1); - } - - return (0); -} - -static ssize_t -nandfs_get_cpinfo(struct nandfs *fs, uint64_t cno, int mode, - struct nandfs_cpinfo *cpinfo, size_t nci) -{ - struct nandfs_argv args; - - NANDFS_ASSERT_VALID(fs); - - args.nv_base = (u_long)cpinfo; - args.nv_nmembs = nci; - args.nv_index = cno; - args.nv_flags = mode; - - if (ioctl(fs->n_iocfd, NANDFS_IOCTL_GET_CPINFO, &args) == -1) { - nandfs_seterr(fs, "ioctl NANDFS_IOCTL_GET_CPINFO: %s", - strerror(errno)); - return (-1); - } - - return (args.nv_nmembs); -} - -ssize_t -nandfs_get_cp(struct nandfs *fs, uint64_t cno, struct nandfs_cpinfo *cpinfo, - size_t nci) -{ - - return (nandfs_get_cpinfo(fs, cno, NANDFS_CHECKPOINT, cpinfo, nci)); -} - -ssize_t -nandfs_get_snap(struct nandfs *fs, uint64_t cno, struct nandfs_cpinfo *cpinfo, - size_t nci) -{ - - return (nandfs_get_cpinfo(fs, cno, NANDFS_SNAPSHOT, cpinfo, nci)); -} - -int -nandfs_make_snap(struct nandfs *fs, uint64_t *cno) -{ - - NANDFS_ASSERT_VALID(fs); - - if (ioctl(fs->n_iocfd, NANDFS_IOCTL_MAKE_SNAP, cno) == -1) { - nandfs_seterr(fs, "ioctl NANDFS_IOCTL_MAKE_SNAP: %s", - strerror(errno)); - return (-1); - } - - return (0); -} - -int -nandfs_delete_snap(struct nandfs *fs, uint64_t cno) -{ - - NANDFS_ASSERT_VALID(fs); - - if (ioctl(fs->n_iocfd, NANDFS_IOCTL_DELETE_SNAP, &cno) == -1) { - nandfs_seterr(fs, "ioctl NANDFS_IOCTL_DELETE_SNAP: %s", - strerror(errno)); - return (-1); - } - - return (0); -} diff --git a/sbin/Makefile b/sbin/Makefile index 78c581e357a1..72da4c5bb058 100644 --- a/sbin/Makefile +++ b/sbin/Makefile @@ -79,8 +79,6 @@ SUBDIR.${MK_IPFILTER}+= ipf SUBDIR.${MK_IPFW}+= ipfw SUBDIR.${MK_IPFW}+= natd SUBDIR.${MK_ISCSI}+= iscontrol -SUBDIR.${MK_NAND}+= nandfs -SUBDIR.${MK_NAND}+= newfs_nandfs SUBDIR.${MK_NVME}+= nvmecontrol SUBDIR.${MK_OPENSSL}+= decryptcore SUBDIR.${MK_PF}+= pfctl diff --git a/sbin/camcontrol/camcontrol.c b/sbin/camcontrol/camcontrol.c index 99d59e59d86c..0784fab75a0e 100644 --- a/sbin/camcontrol/camcontrol.c +++ b/sbin/camcontrol/camcontrol.c @@ -2326,11 +2326,9 @@ ata_do_identify(struct cam_device *device, int retry_count, int timeout, } } - ident_buf = (struct ata_params *)ptr; - ata_param_fixup(ident_buf); - error = 1; for (i = 0; i < sizeof(struct ata_params) / 2; i++) { + ptr[i] = le16toh(ptr[i]); if (ptr[i] != 0) error = 0; } @@ -2348,6 +2346,26 @@ ata_do_identify(struct cam_device *device, int retry_count, int timeout, return (error); } + ident_buf = (struct ata_params *)ptr; + if (strncmp(ident_buf->model, "FX", 2) && + strncmp(ident_buf->model, "NEC", 3) && + strncmp(ident_buf->model, "Pioneer", 7) && + strncmp(ident_buf->model, "SHARP", 5)) { + ata_bswap(ident_buf->model, sizeof(ident_buf->model)); + ata_bswap(ident_buf->revision, sizeof(ident_buf->revision)); + ata_bswap(ident_buf->serial, sizeof(ident_buf->serial)); + ata_bswap(ident_buf->media_serial, sizeof(ident_buf->media_serial)); + } + ata_btrim(ident_buf->model, sizeof(ident_buf->model)); + ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model)); + ata_btrim(ident_buf->revision, sizeof(ident_buf->revision)); + ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision)); + ata_btrim(ident_buf->serial, sizeof(ident_buf->serial)); + ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial)); + ata_btrim(ident_buf->media_serial, sizeof(ident_buf->media_serial)); + ata_bpack(ident_buf->media_serial, ident_buf->media_serial, + sizeof(ident_buf->media_serial)); + *ident_bufp = ident_buf; return (0); diff --git a/sbin/nandfs/Makefile b/sbin/nandfs/Makefile deleted file mode 100644 index 40af5775c510..000000000000 --- a/sbin/nandfs/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# $FreeBSD$ - -PACKAGE=nandfs -PROG= nandfs -SRCS= nandfs.c lssnap.c mksnap.c rmsnap.c -MAN= nandfs.8 - -LIBADD= nandfs - -.include diff --git a/sbin/nandfs/Makefile.depend b/sbin/nandfs/Makefile.depend deleted file mode 100644 index 1269878d50ef..000000000000 --- a/sbin/nandfs/Makefile.depend +++ /dev/null @@ -1,18 +0,0 @@ -# $FreeBSD$ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - gnu/lib/csu \ - include \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - lib/libcompiler_rt \ - lib/libnandfs \ - - -.include - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif diff --git a/sbin/nandfs/lssnap.c b/sbin/nandfs/lssnap.c deleted file mode 100644 index cb240fb1da84..000000000000 --- a/sbin/nandfs/lssnap.c +++ /dev/null @@ -1,114 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2012 The FreeBSD Foundation - * All rights reserved. - * - * This software was developed by Semihalf under sponsorship - * from the FreeBSD Foundation. - * - * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 - -#include -#include -#include -#include - -#include -#include - -#include "nandfs.h" - -#define NCPINFO 512 - -static void -lssnap_usage(void) -{ - - fprintf(stderr, "usage:\n"); - fprintf(stderr, "\tlssnap node\n"); -} - -static void -print_cpinfo(struct nandfs_cpinfo *cpinfo) -{ - struct tm tm; - time_t t; - char timebuf[128]; - - t = (time_t)cpinfo->nci_create; - localtime_r(&t, &tm); - strftime(timebuf, sizeof(timebuf), "%F %T", &tm); - - printf("%20llu %s\n", (unsigned long long)cpinfo->nci_cno, timebuf); -} - -int -nandfs_lssnap(int argc, char **argv) -{ - struct nandfs_cpinfo *cpinfos; - struct nandfs fs; - uint64_t next; - int error, nsnap, i; - - if (argc != 1) { - lssnap_usage(); - return (EX_USAGE); - } - - cpinfos = malloc(sizeof(*cpinfos) * NCPINFO); - if (cpinfos == NULL) { - fprintf(stderr, "cannot allocate memory\n"); - return (-1); - } - - nandfs_init(&fs, argv[0]); - error = nandfs_open(&fs); - if (error == -1) { - fprintf(stderr, "nandfs_open: %s\n", nandfs_errmsg(&fs)); - goto out; - } - - for (next = 1; next != 0; next = cpinfos[nsnap - 1].nci_next) { - nsnap = nandfs_get_snap(&fs, next, cpinfos, NCPINFO); - if (nsnap < 1) - break; - - for (i = 0; i < nsnap; i++) - print_cpinfo(&cpinfos[i]); - } - - if (nsnap == -1) - fprintf(stderr, "nandfs_get_snap: %s\n", nandfs_errmsg(&fs)); - -out: - nandfs_close(&fs); - nandfs_destroy(&fs); - free(cpinfos); - return (error); -} diff --git a/sbin/nandfs/mksnap.c b/sbin/nandfs/mksnap.c deleted file mode 100644 index f75eda3834a9..000000000000 --- a/sbin/nandfs/mksnap.c +++ /dev/null @@ -1,82 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2012 The FreeBSD Foundation - * All rights reserved. - * - * This software was developed by Semihalf under sponsorship - * from the FreeBSD Foundation. - * - * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 - -#include -#include - -#include -#include - -#include "nandfs.h" - -static void -mksnap_usage(void) -{ - - fprintf(stderr, "usage:\n"); - fprintf(stderr, "\tmksnap node\n"); -} - -int -nandfs_mksnap(int argc, char **argv) -{ - struct nandfs fs; - uint64_t cpno; - int error; - - if (argc != 1) { - mksnap_usage(); - return (EX_USAGE); - } - - nandfs_init(&fs, argv[0]); - error = nandfs_open(&fs); - if (error == -1) { - fprintf(stderr, "nandfs_open: %s\n", nandfs_errmsg(&fs)); - goto out; - } - - error = nandfs_make_snap(&fs, &cpno); - if (error == -1) - fprintf(stderr, "nandfs_make_snap: %s\n", nandfs_errmsg(&fs)); - else - printf("%jd\n", cpno); - -out: - nandfs_close(&fs); - nandfs_destroy(&fs); - return (error); -} diff --git a/sbin/nandfs/nandfs.8 b/sbin/nandfs/nandfs.8 deleted file mode 100644 index 9995905d3c68..000000000000 --- a/sbin/nandfs/nandfs.8 +++ /dev/null @@ -1,79 +0,0 @@ -.\" -.\" Copyright (c) 2012 The FreeBSD Foundation -.\" All rights reserved. -.\" -.\" This software was developed by Semihalf under sponsorship -.\" from the FreeBSD Foundation. -.\" -.\" 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 September 10, 2016 -.Dt NANDFS 8 -.Os -.Sh NAME -.Nm nandfs -.Nd manage mounted NAND FS -.Sh SYNOPSIS -.Nm -.Cm lssnap -.Ar node -.Nm -.Cm mksnap -.Ar node -.Nm -.Cm rmsnap -.Ar snapshot node -.Sh DESCRIPTION -The -.Nm -utility allows the management of snapshots on a mounted NAND FS. -.Sh EXAMPLES -Create a snapshot of filesystem mounted on -.Em /nand . -.Bd -literal -offset 2n -.Li # Ic nandfs mksnap /nand -1 -.Ed -.Pp -List snapshots of filesystem mounted on -.Em /nand . -.Bd -literal -offset 2n -.Li # Ic nandfs lssnap /nand -1 2012-02-28 18:49:45 ss 138 2 -.Ed -.Pp -Remove snapshot 1 of filesystem mounted on -.Em /nand . -.Bd -literal -offset 2n -.Li # Ic nandfs rmsnap 1 /nand -.Ed -.Sh HISTORY -The -.Nm -utility appeared in -.Fx 10.0 . -.Sh AUTHORS -This utility and manual page were written by -.An Mateusz Guzik . diff --git a/sbin/nandfs/nandfs.c b/sbin/nandfs/nandfs.c deleted file mode 100644 index b319b58bc5c1..000000000000 --- a/sbin/nandfs/nandfs.c +++ /dev/null @@ -1,76 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2012 The FreeBSD Foundation - * All rights reserved. - * - * This software was developed by Semihalf under sponsorship - * from the FreeBSD Foundation. - * - * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 -#include -#include -#include -#include - -#include "nandfs.h" - -static void -usage(void) -{ - - fprintf(stderr, "usage: nandfs [lssnap | mksnap | rmsnap ] " - "node\n"); - exit(1); -} - -int -main(int argc, char **argv) -{ - int error = 0; - char *cmd; - - if (argc < 2) - usage(); - - cmd = argv[1]; - argc -= 2; - argv += 2; - - if (strcmp(cmd, "lssnap") == 0) - error = nandfs_lssnap(argc, argv); - else if (strcmp(cmd, "mksnap") == 0) - error = nandfs_mksnap(argc, argv); - else if (strcmp(cmd, "rmsnap") == 0) - error = nandfs_rmsnap(argc, argv); - else - usage(); - - return (error); -} diff --git a/sbin/nandfs/nandfs.h b/sbin/nandfs/nandfs.h deleted file mode 100644 index 993d9338e904..000000000000 --- a/sbin/nandfs/nandfs.h +++ /dev/null @@ -1,42 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2012 The FreeBSD Foundation - * All rights reserved. - * - * This software was developed by Semihalf under sponsorship - * from the FreeBSD Foundation. - * - * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$ - */ - -#ifndef NANDFS_H -#define NANDFS_H - -int nandfs_lssnap(int, char **); -int nandfs_mksnap(int, char **); -int nandfs_rmsnap(int, char **); - -#endif /* !NANDFS_H */ diff --git a/sbin/nandfs/rmsnap.c b/sbin/nandfs/rmsnap.c deleted file mode 100644 index c07439d694ef..000000000000 --- a/sbin/nandfs/rmsnap.c +++ /dev/null @@ -1,89 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2012 The FreeBSD Foundation - * All rights reserved. - * - * This software was developed by Semihalf under sponsorship - * from the FreeBSD Foundation. - * - * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 - -#include -#include -#include -#include - -#include -#include - -#include "nandfs.h" - -static void -rmsnap_usage(void) -{ - - fprintf(stderr, "usage:\n"); - fprintf(stderr, "\trmsnap snap node\n"); -} - -int -nandfs_rmsnap(int argc, char **argv) -{ - struct nandfs fs; - uint64_t cpno; - int error; - - if (argc != 2) { - rmsnap_usage(); - return (EX_USAGE); - } - - cpno = strtoll(argv[0], (char **)NULL, 10); - if (cpno == 0) { - fprintf(stderr, "%s must be a number greater than 0\n", - argv[0]); - return (EX_USAGE); - } - - nandfs_init(&fs, argv[1]); - error = nandfs_open(&fs); - if (error == -1) { - fprintf(stderr, "nandfs_open: %s\n", nandfs_errmsg(&fs)); - goto out; - } - - error = nandfs_delete_snap(&fs, cpno); - if (error == -1) - fprintf(stderr, "nandfs_delete_snap: %s\n", nandfs_errmsg(&fs)); - -out: - nandfs_close(&fs); - nandfs_destroy(&fs); - return (error); -} diff --git a/sbin/newfs_nandfs/Makefile b/sbin/newfs_nandfs/Makefile deleted file mode 100644 index 9b1b3009c400..000000000000 --- a/sbin/newfs_nandfs/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# $FreeBSD$ - -PACKAGE=nandfs -PROG= newfs_nandfs -MAN= newfs_nandfs.8 - -LIBADD= geom - -.include diff --git a/sbin/newfs_nandfs/Makefile.depend b/sbin/newfs_nandfs/Makefile.depend deleted file mode 100644 index 0220673c9076..000000000000 --- a/sbin/newfs_nandfs/Makefile.depend +++ /dev/null @@ -1,20 +0,0 @@ -# $FreeBSD$ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - gnu/lib/csu \ - include \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - lib/libcompiler_rt \ - lib/libexpat \ - lib/libgeom \ - lib/libsbuf \ - - -.include - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif diff --git a/sbin/newfs_nandfs/newfs_nandfs.8 b/sbin/newfs_nandfs/newfs_nandfs.8 deleted file mode 100644 index fe3216394109..000000000000 --- a/sbin/newfs_nandfs/newfs_nandfs.8 +++ /dev/null @@ -1,74 +0,0 @@ -.\" -.\" Copyright (c) 2010 Semihalf -.\" 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, 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 AND CONTRIBUTORS ``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 AUTHOR OR CONTRIBUTORS 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 October 1, 2013 -.Dt NEWFS_NANDFS 8 -.Os -.Sh NAME -.Nm newfs_nandfs -.Nd construct a new NAND FS file system -.Sh SYNOPSIS -.Nm -.Op Fl b Ar blocsize -.Op Fl B Ar blocks-per-segment -.Op Fl L Ar label -.Op Fl m Ar reserved-segment-percent -.Ar device -.Sh DESCRIPTION -The -.Nm -utility creates a NAND FS file system on device. -.Pp -The options are as follow: -.Bl -tag -width indent -.It Fl b Ar blocksize -Size of block (1024 if not specified). -.It Fl B Ar blocks_per_segment -Number of blocks per segment (2048 if not specified). -.It Fl L Ar label -Volume label (up to 16 characters). -.It Fl m Ar reserved_block_percent -Percentage of reserved blocks (5 if not specified). -.El -.Sh EXIT STATUS -Exit status is 0 on success and 1 on error. -.Sh EXAMPLES -Create a file system, using default parameters, on -.Pa /dev/ada0s1 : -.Bd -literal -offset indent -newfs_nandfs /dev/ada0s1 -.Ed -.Sh SEE ALSO -.Xr gpart 8 , -.Xr newfs 8 -.Sh HISTORY -The -.Nm -utility first appeared in -.Fx 10.0 . -.Sh AUTHORS -.An Grzegorz Bernacki diff --git a/sbin/newfs_nandfs/newfs_nandfs.c b/sbin/newfs_nandfs/newfs_nandfs.c deleted file mode 100644 index e432cc6e6420..000000000000 --- a/sbin/newfs_nandfs/newfs_nandfs.c +++ /dev/null @@ -1,1183 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define DEBUG -#undef DEBUG -#ifdef DEBUG -#define debug(fmt, args...) do { \ - printf("nandfs:" fmt "\n", ##args); } while (0) -#else -#define debug(fmt, args...) -#endif - -#define NANDFS_FIRST_BLOCK nandfs_first_block() -#define NANDFS_FIRST_CNO 1 -#define NANDFS_BLOCK_BAD 1 -#define NANDFS_BLOCK_GOOD 0 - -struct file_info { - uint64_t ino; - const char *name; - uint32_t mode; - uint64_t size; - uint8_t nblocks; - uint32_t *blocks; - struct nandfs_inode *inode; -}; - -static struct file_info user_files[] = { - { NANDFS_ROOT_INO, NULL, S_IFDIR | 0755, 0, 1, NULL, NULL }, -}; - -static struct file_info ifile = - { NANDFS_IFILE_INO, NULL, 0, 0, -1, NULL, NULL }; -static struct file_info sufile = - { NANDFS_SUFILE_INO, NULL, 0, 0, -1, NULL, NULL }; -static struct file_info cpfile = - { NANDFS_CPFILE_INO, NULL, 0, 0, -1, NULL, NULL }; -static struct file_info datfile = - { NANDFS_DAT_INO, NULL, 0, 0, -1, NULL, NULL }; - -struct nandfs_block { - LIST_ENTRY(nandfs_block) block_link; - uint32_t number; - uint64_t offset; - void *data; -}; - -static LIST_HEAD(, nandfs_block) block_head = - LIST_HEAD_INITIALIZER(&block_head); - -/* Storage geometry */ -static off_t mediasize; -static ssize_t sectorsize; -static uint64_t nsegments; -static uint64_t erasesize; -static uint64_t segsize; - -static struct nandfs_fsdata fsdata; -static struct nandfs_super_block super_block; - -static int is_nand; - -/* Nandfs parameters */ -static size_t blocksize = NANDFS_DEF_BLOCKSIZE; -static long blocks_per_segment; -static long rsv_segment_percent = 5; -static time_t nandfs_time; -static uint32_t bad_segments_count = 0; -static uint32_t *bad_segments = NULL; -static uint8_t fsdata_blocks_state[NANDFS_NFSAREAS]; - -static u_char *volumelabel = NULL; - -static struct nandfs_super_root *sr; - -static uint32_t nuserfiles; -static uint32_t seg_nblocks; -static uint32_t seg_endblock; - -#define SIZE_TO_BLOCK(size) howmany(size, blocksize) - -static uint32_t -nandfs_first_block(void) -{ - uint32_t i, first_free, start_bad_segments = 0; - - for (i = 0; i < bad_segments_count; i++) { - if (i == bad_segments[i]) - start_bad_segments++; - else - break; - } - - first_free = SIZE_TO_BLOCK(NANDFS_DATA_OFFSET_BYTES(erasesize) + - (start_bad_segments * segsize)); - - if (first_free < (uint32_t)blocks_per_segment) - return (blocks_per_segment); - else - return (first_free); -} - -static void -usage(void) -{ - - fprintf(stderr, - "usage: newfs_nandfs [ -options ] device\n" - "where the options are:\n" - "\t-b block-size\n" - "\t-B blocks-per-segment\n" - "\t-L volume label\n" - "\t-m reserved-segments-percentage\n"); - exit(1); -} - -static int -nandfs_log2(unsigned n) -{ - unsigned count; - - /* - * N.B. this function will return 0 if supplied 0. - */ - for (count = 0; n/2; count++) - n /= 2; - return count; -} - -/* from NetBSD's src/sys/net/if_ethersubr.c */ -static uint32_t -crc32_le(uint32_t crc, const uint8_t *buf, size_t len) -{ - static const uint32_t crctab[] = { - 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, - 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, - 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, - 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c - }; - size_t i; - - crc = crc ^ ~0U; - - for (i = 0; i < len; i++) { - crc ^= buf[i]; - crc = (crc >> 4) ^ crctab[crc & 0xf]; - crc = (crc >> 4) ^ crctab[crc & 0xf]; - } - - return (crc ^ ~0U); -} - -static void * -get_block(uint32_t block_nr, uint64_t offset) -{ - struct nandfs_block *block, *new_block; - - LIST_FOREACH(block, &block_head, block_link) { - if (block->number == block_nr) - return block->data; - } - - debug("allocating block %x\n", block_nr); - - new_block = malloc(sizeof(*block)); - if (!new_block) - err(1, "cannot allocate block"); - - new_block->number = block_nr; - new_block->offset = offset; - new_block->data = malloc(blocksize); - if (!new_block->data) - err(1, "cannot allocate block data"); - - memset(new_block->data, 0, blocksize); - - LIST_INSERT_HEAD(&block_head, new_block, block_link); - - return (new_block->data); -} - -static int -nandfs_seg_usage_blk_offset(uint64_t seg, uint64_t *blk, uint64_t *offset) -{ - uint64_t off; - uint16_t seg_size; - - seg_size = sizeof(struct nandfs_segment_usage); - - off = roundup(sizeof(struct nandfs_sufile_header), seg_size); - off += (seg * seg_size); - - *blk = off / blocksize; - *offset = (off % blocksize) / seg_size; - return (0); -} - -static uint32_t -segment_size(void) -{ - u_int size; - - size = sizeof(struct nandfs_segment_summary ); - size += seg_nblocks * sizeof(struct nandfs_binfo_v); - - if (size > blocksize) - err(1, "segsum info bigger that blocksize"); - - return (size); -} - - -static void -prepare_blockgrouped_file(uint32_t block) -{ - struct nandfs_block_group_desc *desc; - uint32_t i, entries; - - desc = (struct nandfs_block_group_desc *)get_block(block, 0); - entries = blocksize / sizeof(struct nandfs_block_group_desc); - for (i = 0; i < entries; i++) - desc[i].bg_nfrees = blocksize * 8; -} - -static void -alloc_blockgrouped_file(uint32_t block, uint32_t entry) -{ - struct nandfs_block_group_desc *desc; - uint32_t desc_nr; - uint32_t *bitmap; - - desc = (struct nandfs_block_group_desc *)get_block(block, 0); - bitmap = (uint32_t *)get_block(block + 1, 1); - - bitmap += (entry >> 5); - if (*bitmap & (1 << (entry % 32))) { - printf("nandfs: blockgrouped entry %d already allocated\n", - entry); - } - *bitmap |= (1 << (entry % 32)); - - desc_nr = entry / (blocksize * 8); - desc[desc_nr].bg_nfrees--; -} - - -static uint64_t -count_su_blocks(void) -{ - uint64_t maxblk, blk, offset, i; - - maxblk = blk = 0; - - for (i = 0; i < bad_segments_count; i++) { - nandfs_seg_usage_blk_offset(bad_segments[i], &blk, &offset); - debug("bad segment at block:%jx off: %jx", blk, offset); - if (blk > maxblk) - maxblk = blk; - } - - debug("bad segment needs %#jx", blk); - if (blk >= NANDFS_NDADDR) { - printf("nandfs: file too big (%jd > %d)\n", blk, NANDFS_NDADDR); - exit(2); - } - - sufile.size = (blk + 1) * blocksize; - return (blk + 1); -} - -static void -count_seg_blocks(void) -{ - uint32_t i; - - for (i = 0; i < nuserfiles; i++) - if (user_files[i].nblocks) { - seg_nblocks += user_files[i].nblocks; - user_files[i].blocks = malloc(user_files[i].nblocks * sizeof(uint32_t)); - } - - ifile.nblocks = 2 + - SIZE_TO_BLOCK(sizeof(struct nandfs_inode) * (NANDFS_USER_INO + 1)); - ifile.blocks = malloc(ifile.nblocks * sizeof(uint32_t)); - seg_nblocks += ifile.nblocks; - - cpfile.nblocks = - SIZE_TO_BLOCK((NANDFS_CPFILE_FIRST_CHECKPOINT_OFFSET + 1) * - sizeof(struct nandfs_checkpoint)); - cpfile.blocks = malloc(cpfile.nblocks * sizeof(uint32_t)); - seg_nblocks += cpfile.nblocks; - - if (!bad_segments) { - sufile.nblocks = - SIZE_TO_BLOCK((NANDFS_SUFILE_FIRST_SEGMENT_USAGE_OFFSET + 1) * - sizeof(struct nandfs_segment_usage)); - } else { - debug("bad blocks found: extra space for sufile"); - sufile.nblocks = count_su_blocks(); - } - - sufile.blocks = malloc(sufile.nblocks * sizeof(uint32_t)); - seg_nblocks += sufile.nblocks; - - datfile.nblocks = 2 + - SIZE_TO_BLOCK((seg_nblocks) * sizeof(struct nandfs_dat_entry)); - datfile.blocks = malloc(datfile.nblocks * sizeof(uint32_t)); - seg_nblocks += datfile.nblocks; -} - -static void -assign_file_blocks(uint64_t start_block) -{ - uint32_t i, j; - - for (i = 0; i < nuserfiles; i++) - for (j = 0; j < user_files[i].nblocks; j++) { - debug("user file %d at block %d at %#jx", - i, j, (uintmax_t)start_block); - user_files[i].blocks[j] = start_block++; - } - - for (j = 0; j < ifile.nblocks; j++) { - debug("ifile block %d at %#jx", j, (uintmax_t)start_block); - ifile.blocks[j] = start_block++; - } - - for (j = 0; j < cpfile.nblocks; j++) { - debug("cpfile block %d at %#jx", j, (uintmax_t)start_block); - cpfile.blocks[j] = start_block++; - } - - for (j = 0; j < sufile.nblocks; j++) { - debug("sufile block %d at %#jx", j, (uintmax_t)start_block); - sufile.blocks[j] = start_block++; - } - - for (j = 0; j < datfile.nblocks; j++) { - debug("datfile block %d at %#jx", j, (uintmax_t)start_block); - datfile.blocks[j] = start_block++; - } - - /* add one for superroot */ - debug("sr at block %#jx", (uintmax_t)start_block); - sr = (struct nandfs_super_root *)get_block(start_block++, 0); - seg_endblock = start_block; -} - -static void -save_datfile(void) -{ - - prepare_blockgrouped_file(datfile.blocks[0]); -} - -static uint64_t -update_datfile(uint64_t block) -{ - struct nandfs_dat_entry *dat; - static uint64_t vblock = 0; - uint64_t allocated, i, off; - - if (vblock == 0) { - alloc_blockgrouped_file(datfile.blocks[0], vblock); - vblock++; - } - allocated = vblock; - i = vblock / (blocksize / sizeof(*dat)); - off = vblock % (blocksize / sizeof(*dat)); - vblock++; - - dat = (struct nandfs_dat_entry *)get_block(datfile.blocks[2 + i], 2 + i); - - alloc_blockgrouped_file(datfile.blocks[0], allocated); - dat[off].de_blocknr = block; - dat[off].de_start = NANDFS_FIRST_CNO; - dat[off].de_end = UINTMAX_MAX; - - return (allocated); -} - -static union nandfs_binfo * -update_block_info(union nandfs_binfo *binfo, struct file_info *file) -{ - nandfs_daddr_t vblock; - uint32_t i; - - for (i = 0; i < file->nblocks; i++) { - debug("%s: blk %x", __func__, i); - if (file->ino != NANDFS_DAT_INO) { - vblock = update_datfile(file->blocks[i]); - binfo->bi_v.bi_vblocknr = vblock; - binfo->bi_v.bi_blkoff = i; - binfo->bi_v.bi_ino = file->ino; - file->inode->i_db[i] = vblock; - } else { - binfo->bi_dat.bi_blkoff = i; - binfo->bi_dat.bi_ino = file->ino; - file->inode->i_db[i] = datfile.blocks[i]; - } - binfo++; - } - - return (binfo); -} - -static void -save_segsum(struct nandfs_segment_summary *ss) -{ - union nandfs_binfo *binfo; - struct nandfs_block *block; - uint32_t sum_bytes, i; - uint8_t crc_data, crc_skip; - - sum_bytes = segment_size(); - ss->ss_magic = NANDFS_SEGSUM_MAGIC; - ss->ss_bytes = sizeof(struct nandfs_segment_summary); - ss->ss_flags = NANDFS_SS_LOGBGN | NANDFS_SS_LOGEND | NANDFS_SS_SR; - ss->ss_seq = 1; - ss->ss_create = nandfs_time; - - ss->ss_next = nandfs_first_block() + blocks_per_segment; - /* nblocks = segment blocks + segsum block + superroot */ - ss->ss_nblocks = seg_nblocks + 2; - ss->ss_nbinfos = seg_nblocks; - ss->ss_sumbytes = sum_bytes; - - crc_skip = sizeof(ss->ss_datasum) + sizeof(ss->ss_sumsum); - ss->ss_sumsum = crc32_le(0, (uint8_t *)ss + crc_skip, - sum_bytes - crc_skip); - crc_data = 0; - - binfo = (union nandfs_binfo *)(ss + 1); - for (i = 0; i < nuserfiles; i++) { - if (user_files[i].nblocks) - binfo = update_block_info(binfo, &user_files[i]); - } - - binfo = update_block_info(binfo, &ifile); - binfo = update_block_info(binfo, &cpfile); - binfo = update_block_info(binfo, &sufile); - update_block_info(binfo, &datfile); - - /* save superroot crc */ - crc_skip = sizeof(sr->sr_sum); - sr->sr_sum = crc32_le(0, (uint8_t *)sr + crc_skip, - NANDFS_SR_BYTES - crc_skip); - - /* segment checksup */ - crc_skip = sizeof(ss->ss_datasum); - LIST_FOREACH(block, &block_head, block_link) { - if (block->number < NANDFS_FIRST_BLOCK) - continue; - if (block->number == NANDFS_FIRST_BLOCK) - crc_data = crc32_le(0, - (uint8_t *)block->data + crc_skip, - blocksize - crc_skip); - else - crc_data = crc32_le(crc_data, (uint8_t *)block->data, - blocksize); - } - ss->ss_datasum = crc_data; -} - -static void -create_fsdata(void) -{ - struct uuid tmp; - - memset(&fsdata, 0, sizeof(struct nandfs_fsdata)); - - fsdata.f_magic = NANDFS_FSDATA_MAGIC; - fsdata.f_nsegments = nsegments; - fsdata.f_erasesize = erasesize; - fsdata.f_first_data_block = NANDFS_FIRST_BLOCK; - fsdata.f_blocks_per_segment = blocks_per_segment; - fsdata.f_r_segments_percentage = rsv_segment_percent; - fsdata.f_rev_level = NANDFS_CURRENT_REV; - fsdata.f_sbbytes = NANDFS_SB_BYTES; - fsdata.f_bytes = NANDFS_FSDATA_CRC_BYTES; - fsdata.f_ctime = nandfs_time; - fsdata.f_log_block_size = nandfs_log2(blocksize) - 10; - fsdata.f_errors = 1; - fsdata.f_inode_size = sizeof(struct nandfs_inode); - fsdata.f_dat_entry_size = sizeof(struct nandfs_dat_entry); - fsdata.f_checkpoint_size = sizeof(struct nandfs_checkpoint); - fsdata.f_segment_usage_size = sizeof(struct nandfs_segment_usage); - - uuidgen(&tmp, 1); - fsdata.f_uuid = tmp; - - if (volumelabel) - memcpy(fsdata.f_volume_name, volumelabel, 16); - - fsdata.f_sum = crc32_le(0, (const uint8_t *)&fsdata, - NANDFS_FSDATA_CRC_BYTES); -} - -static void -save_fsdata(void *data) -{ - - memcpy(data, &fsdata, sizeof(fsdata)); -} - -static void -create_super_block(void) -{ - - memset(&super_block, 0, sizeof(struct nandfs_super_block)); - - super_block.s_magic = NANDFS_SUPER_MAGIC; - super_block.s_last_cno = NANDFS_FIRST_CNO; - super_block.s_last_pseg = NANDFS_FIRST_BLOCK; - super_block.s_last_seq = 1; - super_block.s_free_blocks_count = - (nsegments - bad_segments_count) * blocks_per_segment; - super_block.s_mtime = 0; - super_block.s_wtime = nandfs_time; - super_block.s_state = NANDFS_VALID_FS; - - super_block.s_sum = crc32_le(0, (const uint8_t *)&super_block, - NANDFS_SB_BYTES); -} - -static void -save_super_block(void *data) -{ - - memcpy(data, &super_block, sizeof(super_block)); -} - -static void -save_super_root(void) -{ - - sr->sr_bytes = NANDFS_SR_BYTES; - sr->sr_flags = 0; - sr->sr_nongc_ctime = nandfs_time; - datfile.inode = &sr->sr_dat; - cpfile.inode = &sr->sr_cpfile; - sufile.inode = &sr->sr_sufile; -} - -static struct nandfs_dir_entry * -add_de(void *block, struct nandfs_dir_entry *de, uint64_t ino, - const char *name, uint8_t type) -{ - uint16_t reclen; - - /* modify last de */ - de->rec_len = NANDFS_DIR_REC_LEN(de->name_len); - de = (void *)((uint8_t *)de + de->rec_len); - - reclen = blocksize - ((uintptr_t)de - (uintptr_t)block); - if (reclen < NANDFS_DIR_REC_LEN(strlen(name))) { - printf("nandfs: too many dir entries for one block\n"); - return (NULL); - } - - de->inode = ino; - de->rec_len = reclen; - de->name_len = strlen(name); - de->file_type = type; - memset(de->name, 0, - (strlen(name) + NANDFS_DIR_PAD - 1) & ~NANDFS_DIR_ROUND); - memcpy(de->name, name, strlen(name)); - - return (de); -} - -static struct nandfs_dir_entry * -make_dir(void *block, uint64_t ino, uint64_t parent_ino) -{ - struct nandfs_dir_entry *de = (struct nandfs_dir_entry *)block; - - /* create '..' entry */ - de->inode = parent_ino; - de->rec_len = NANDFS_DIR_REC_LEN(2); - de->name_len = 2; - de->file_type = DT_DIR; - memset(de->name, 0, NANDFS_DIR_NAME_LEN(2)); - memcpy(de->name, "..", 2); - - /* create '.' entry */ - de = (void *)((uint8_t *)block + NANDFS_DIR_REC_LEN(2)); - de->inode = ino; - de->rec_len = blocksize - NANDFS_DIR_REC_LEN(2); - de->name_len = 1; - de->file_type = DT_DIR; - memset(de->name, 0, NANDFS_DIR_NAME_LEN(1)); - memcpy(de->name, ".", 1); - - return (de); -} - -static void -save_root_dir(void) -{ - struct file_info *root = &user_files[0]; - struct nandfs_dir_entry *de; - uint32_t i; - void *block; - - block = get_block(root->blocks[0], 0); - - de = make_dir(block, root->ino, root->ino); - for (i = 1; i < nuserfiles; i++) - de = add_de(block, de, user_files[i].ino, user_files[i].name, - IFTODT(user_files[i].mode)); - - root->size = ((uintptr_t)de - (uintptr_t)block) + - NANDFS_DIR_REC_LEN(de->name_len); -} - -static void -save_sufile(void) -{ - struct nandfs_sufile_header *header; - struct nandfs_segment_usage *su; - uint64_t blk, i, off; - void *block; - int start; - - /* - * At the beginning just zero-out everything - */ - for (i = 0; i < sufile.nblocks; i++) - get_block(sufile.blocks[i], 0); - - start = 0; - - block = get_block(sufile.blocks[start], 0); - header = (struct nandfs_sufile_header *)block; - header->sh_ncleansegs = nsegments - bad_segments_count - 1; - header->sh_ndirtysegs = 1; - header->sh_last_alloc = 1; - - su = (struct nandfs_segment_usage *)header; - off = NANDFS_SUFILE_FIRST_SEGMENT_USAGE_OFFSET; - /* Allocate data segment */ - su[off].su_lastmod = nandfs_time; - /* nblocks = segment blocks + segsum block + superroot */ - su[off].su_nblocks = seg_nblocks + 2; - su[off].su_flags = NANDFS_SEGMENT_USAGE_DIRTY; - off++; - /* Allocate next segment */ - su[off].su_lastmod = nandfs_time; - su[off].su_nblocks = 0; - su[off].su_flags = NANDFS_SEGMENT_USAGE_DIRTY; - for (i = 0; i < bad_segments_count; i++) { - nandfs_seg_usage_blk_offset(bad_segments[i], &blk, &off); - debug("storing bad_segments[%jd]=%x at %jx off %jx\n", i, - bad_segments[i], blk, off); - block = get_block(sufile.blocks[blk], - off * sizeof(struct nandfs_segment_usage *)); - su = (struct nandfs_segment_usage *)block; - su[off].su_lastmod = nandfs_time; - su[off].su_nblocks = 0; - su[off].su_flags = NANDFS_SEGMENT_USAGE_ERROR; - } -} - -static void -save_cpfile(void) -{ - struct nandfs_cpfile_header *header; - struct nandfs_checkpoint *cp, *initial_cp; - int i, entries = blocksize / sizeof(struct nandfs_checkpoint); - uint64_t cno; - - header = (struct nandfs_cpfile_header *)get_block(cpfile.blocks[0], 0); - header->ch_ncheckpoints = 1; - header->ch_nsnapshots = 0; - - cp = (struct nandfs_checkpoint *)header; - - /* fill first checkpoint data*/ - initial_cp = &cp[NANDFS_CPFILE_FIRST_CHECKPOINT_OFFSET]; - initial_cp->cp_flags = 0; - initial_cp->cp_checkpoints_count = 0; - initial_cp->cp_cno = NANDFS_FIRST_CNO; - initial_cp->cp_create = nandfs_time; - initial_cp->cp_nblk_inc = seg_endblock - 1; - initial_cp->cp_blocks_count = seg_nblocks; - memset(&initial_cp->cp_snapshot_list, 0, - sizeof(struct nandfs_snapshot_list)); - - ifile.inode = &initial_cp->cp_ifile_inode; - - /* mark rest of cp as invalid */ - cno = NANDFS_FIRST_CNO + 1; - i = NANDFS_CPFILE_FIRST_CHECKPOINT_OFFSET + 1; - for (; i < entries; i++) { - cp[i].cp_cno = cno++; - cp[i].cp_flags = NANDFS_CHECKPOINT_INVALID; - } -} - -static void -init_inode(struct nandfs_inode *inode, struct file_info *file) -{ - - inode->i_blocks = file->nblocks; - inode->i_ctime = nandfs_time; - inode->i_mtime = nandfs_time; - inode->i_mode = file->mode & 0xffff; - inode->i_links_count = 1; - - if (file->size > 0) - inode->i_size = file->size; - else - inode->i_size = 0; - - if (file->ino == NANDFS_USER_INO) - inode->i_flags = SF_NOUNLINK|UF_NOUNLINK; - else - inode->i_flags = 0; -} - -static void -save_ifile(void) -{ - struct nandfs_inode *inode; - struct file_info *file; - uint64_t ino, blk, off; - uint32_t i; - - prepare_blockgrouped_file(ifile.blocks[0]); - for (i = 0; i <= NANDFS_USER_INO; i++) - alloc_blockgrouped_file(ifile.blocks[0], i); - - for (i = 0; i < nuserfiles; i++) { - file = &user_files[i]; - ino = file->ino; - blk = ino / (blocksize / sizeof(*inode)); - off = ino % (blocksize / sizeof(*inode)); - inode = - (struct nandfs_inode *)get_block(ifile.blocks[2 + blk], 2 + blk); - file->inode = &inode[off]; - init_inode(file->inode, file); - } - - init_inode(ifile.inode, &ifile); - init_inode(cpfile.inode, &cpfile); - init_inode(sufile.inode, &sufile); - init_inode(datfile.inode, &datfile); -} - -static int -create_fs(void) -{ - uint64_t start_block; - uint32_t segsum_size; - char *data; - int i; - - nuserfiles = nitems(user_files); - - /* Count and assign blocks */ - count_seg_blocks(); - segsum_size = segment_size(); - start_block = NANDFS_FIRST_BLOCK + SIZE_TO_BLOCK(segsum_size); - assign_file_blocks(start_block); - - /* Create super root structure */ - save_super_root(); - - /* Create root directory */ - save_root_dir(); - - /* Fill in file contents */ - save_sufile(); - save_cpfile(); - save_ifile(); - save_datfile(); - - /* Save fsdata and superblocks */ - create_fsdata(); - create_super_block(); - - for (i = 0; i < NANDFS_NFSAREAS; i++) { - if (fsdata_blocks_state[i] != NANDFS_BLOCK_GOOD) - continue; - - data = get_block((i * erasesize)/blocksize, 0); - save_fsdata(data); - - data = get_block((i * erasesize + NANDFS_SBLOCK_OFFSET_BYTES) / - blocksize, 0); - if (blocksize > NANDFS_SBLOCK_OFFSET_BYTES) - data += NANDFS_SBLOCK_OFFSET_BYTES; - save_super_block(data); - memset(data + sizeof(struct nandfs_super_block), 0xff, - (blocksize - sizeof(struct nandfs_super_block) - - NANDFS_SBLOCK_OFFSET_BYTES)); - } - - /* Save segment summary and CRCs */ - save_segsum(get_block(NANDFS_FIRST_BLOCK, 0)); - - return (0); -} - -static void -write_fs(int fda) -{ - struct nandfs_block *block; - char *data; - u_int ret; - - /* Overwrite next block with ff if not nand device */ - if (!is_nand) { - data = get_block(seg_endblock, 0); - memset(data, 0xff, blocksize); - } - - LIST_FOREACH(block, &block_head, block_link) { - lseek(fda, block->number * blocksize, SEEK_SET); - ret = write(fda, block->data, blocksize); - if (ret != blocksize) - err(1, "cannot write filesystem data"); - } -} - -static void -check_parameters(void) -{ - int i; - - /* check blocksize */ - if ((blocksize < NANDFS_MIN_BLOCKSIZE) || (blocksize > MAXBSIZE) || - ((blocksize - 1) & blocksize)) { - errx(1, "Bad blocksize (%zu). Must be in range [%u-%u] " - "and a power of two.", blocksize, NANDFS_MIN_BLOCKSIZE, - MAXBSIZE); - } - - /* check blocks per segments */ - if ((blocks_per_segment < NANDFS_SEG_MIN_BLOCKS) || - ((blocksize - 1) & blocksize)) - errx(1, "Bad blocks per segment (%lu). Must be greater than " - "%u and a power of two.", blocks_per_segment, - NANDFS_SEG_MIN_BLOCKS); - - /* check reserved segment percentage */ - if ((rsv_segment_percent < 1) || (rsv_segment_percent > 99)) - errx(1, "Bad reserved segment percentage. " - "Must in range 1..99."); - - /* check volume label */ - i = 0; - if (volumelabel) { - while (isalnum(volumelabel[++i])) - ; - - if (volumelabel[i] != '\0') { - errx(1, "bad volume label. " - "Valid characters are alphanumerics."); - } - - if (strlen(volumelabel) >= 16) - errx(1, "Bad volume label. Length is longer than %d.", - 16); - } - - nandfs_time = time(NULL); -} - -static void -print_parameters(void) -{ - - printf("filesystem parameters:\n"); - printf("blocksize: %#zx sectorsize: %#zx\n", blocksize, sectorsize); - printf("erasesize: %#jx mediasize: %#jx\n", erasesize, mediasize); - printf("segment size: %#jx blocks per segment: %#x\n", segsize, - (uint32_t)blocks_per_segment); -} - -/* - * Exit with error if file system is mounted. - */ -static void -check_mounted(const char *fname, mode_t mode) -{ - struct statfs *mp; - const char *s1, *s2; - size_t len; - int n, r; - - if (!(n = getmntinfo(&mp, MNT_NOWAIT))) - err(1, "getmntinfo"); - - len = strlen(_PATH_DEV); - s1 = fname; - if (!strncmp(s1, _PATH_DEV, len)) - s1 += len; - - r = S_ISCHR(mode) && s1 != fname && *s1 == 'r'; - - for (; n--; mp++) { - s2 = mp->f_mntfromname; - - if (!strncmp(s2, _PATH_DEV, len)) - s2 += len; - if ((r && s2 != mp->f_mntfromname && !strcmp(s1 + 1, s2)) || - !strcmp(s1, s2)) - errx(1, "%s is mounted on %s", fname, mp->f_mntonname); - } -} - -static void -calculate_geometry(int fd) -{ - struct chip_param_io chip_params; - char ident[DISK_IDENT_SIZE]; - char medianame[MAXPATHLEN]; - - /* Check storage type */ - g_get_ident(fd, ident, DISK_IDENT_SIZE); - g_get_name(ident, medianame, MAXPATHLEN); - debug("device name: %s", medianame); - - is_nand = (strstr(medianame, "gnand") != NULL); - debug("is_nand = %d", is_nand); - - sectorsize = g_sectorsize(fd); - debug("sectorsize: %#zx", sectorsize); - - /* Get storage size */ - mediasize = g_mediasize(fd); - debug("mediasize: %#jx", mediasize); - - /* Get storage erase unit size */ - if (!is_nand) - erasesize = NANDFS_DEF_ERASESIZE; - else if (ioctl(fd, NAND_IO_GET_CHIP_PARAM, &chip_params) != -1) - erasesize = chip_params.page_size * chip_params.pages_per_block; - else - errx(1, "Cannot ioctl(NAND_IO_GET_CHIP_PARAM)"); - - debug("erasesize: %#jx", (uintmax_t)erasesize); - - if (blocks_per_segment == 0) { - if (erasesize >= NANDFS_MIN_SEGSIZE) - blocks_per_segment = erasesize / blocksize; - else - blocks_per_segment = NANDFS_MIN_SEGSIZE / blocksize; - } - - /* Calculate number of segments */ - segsize = blocksize * blocks_per_segment; - nsegments = ((mediasize - NANDFS_NFSAREAS * erasesize) / segsize) - 2; - debug("segsize: %#jx", segsize); - debug("nsegments: %#jx", nsegments); -} - -static void -erase_device(int fd) -{ - int rest, failed; - uint64_t i, nblocks; - off_t offset; - - failed = 0; - for (i = 0; i < NANDFS_NFSAREAS; i++) { - debug("Deleting %jx\n", i * erasesize); - if (g_delete(fd, i * erasesize, erasesize)) { - printf("cannot delete %jx\n", i * erasesize); - fsdata_blocks_state[i] = NANDFS_BLOCK_BAD; - failed++; - } else - fsdata_blocks_state[i] = NANDFS_BLOCK_GOOD; - } - - if (failed == NANDFS_NFSAREAS) { - printf("%d first blocks not usable. Unable to create " - "filesystem.\n", failed); - exit(1); - } - - for (i = 0; i < nsegments; i++) { - offset = NANDFS_NFSAREAS * erasesize + i * segsize; - if (g_delete(fd, offset, segsize)) { - printf("cannot delete segment %jx (offset %jd)\n", - i, offset); - bad_segments_count++; - bad_segments = realloc(bad_segments, - bad_segments_count * sizeof(uint32_t)); - bad_segments[bad_segments_count - 1] = i; - } - } - - if (bad_segments_count == nsegments) { - printf("no valid segments\n"); - exit(1); - } - - /* Delete remaining blocks at the end of device */ - rest = mediasize % segsize; - nblocks = rest / erasesize; - for (i = 0; i < nblocks; i++) { - offset = (segsize * nsegments) + (i * erasesize); - if (g_delete(fd, offset, erasesize)) { - printf("cannot delete space after last segment " - "- probably a bad block\n"); - } - } -} - -static void -erase_initial(int fd) -{ - char buf[512]; - u_int i; - - memset(buf, 0xff, sizeof(buf)); - - lseek(fd, 0, SEEK_SET); - for (i = 0; i < NANDFS_NFSAREAS * erasesize; i += sizeof(buf)) - write(fd, buf, sizeof(buf)); -} - -static void -create_nandfs(int fd) -{ - - create_fs(); - - write_fs(fd); -} - -static void -print_summary(void) -{ - - printf("filesystem was created successfully\n"); - printf("total segments: %#jx valid segments: %#jx\n", nsegments, - nsegments - bad_segments_count); - printf("total space: %ju MB free: %ju MB\n", - (nsegments * - blocks_per_segment * blocksize) / (1024 * 1024), - ((nsegments - bad_segments_count) * - blocks_per_segment * blocksize) / (1024 * 1024)); -} - -int -main(int argc, char *argv[]) -{ - struct stat sb; - char buf[MAXPATHLEN]; - const char opts[] = "b:B:L:m:"; - const char *fname; - int ch, fd; - - while ((ch = getopt(argc, argv, opts)) != -1) { - switch (ch) { - case 'b': - blocksize = strtol(optarg, (char **)NULL, 10); - if (blocksize == 0) - usage(); - break; - case 'B': - blocks_per_segment = strtol(optarg, (char **)NULL, 10); - if (blocks_per_segment == 0) - usage(); - break; - case 'L': - volumelabel = optarg; - break; - case 'm': - rsv_segment_percent = strtol(optarg, (char **)NULL, 10); - if (rsv_segment_percent == 0) - usage(); - break; - default: - usage(); - } - } - - argc -= optind; - argv += optind; - if (argc < 1 || argc > 2) - usage(); - - /* construct proper device path */ - fname = *argv++; - if (!strchr(fname, '/')) { - snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname); - if (!(fname = strdup(buf))) - err(1, NULL); - } - - fd = g_open(fname, 1); - if (fd == -1) - err(1, "Cannot open %s", fname); - - if (fstat(fd, &sb) == -1) - err(1, "Cannot stat %s", fname); - if (!S_ISCHR(sb.st_mode)) - warnx("%s is not a character device", fname); - - check_mounted(fname, sb.st_mode); - - calculate_geometry(fd); - - check_parameters(); - - print_parameters(); - - if (is_nand) - erase_device(fd); - else - erase_initial(fd); - - create_nandfs(fd); - - print_summary(); - - g_close(fd); - - return (0); -} - - diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index a810d9153349..13c3069b8172 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -303,8 +303,6 @@ MAN= aac.4 \ mx25l.4 \ mxge.4 \ my.4 \ - nand.4 \ - nandsim.4 \ ${_ndis.4} \ net80211.4 \ netdump.4 \ diff --git a/share/man/man4/nand.4 b/share/man/man4/nand.4 deleted file mode 100644 index 5c868a1151e6..000000000000 --- a/share/man/man4/nand.4 +++ /dev/null @@ -1,145 +0,0 @@ -.\" -.\" Copyright (c) 2012 The FreeBSD Foundation -.\" All rights reserved. -.\" -.\" This documentation was written by Semihalf under sponsorship from -.\" the FreeBSD Foundation. -.\" -.\" 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 March 8, 2012 -.Dt NAND 4 -.Os -.Sh NAME -.Nm nand -.Nd NAND Flash framework -.Sh SYNOPSIS -.Cd "device nand" -.Sh DESCRIPTION -The -.Fx -.Nm -framework consists of a set of interfaces that aim to provide an extensible, -object oriented environment for NAND controllers and NAND Flash memory chips -from various hardware vendors, and to allow for uniform and flexible -management of the NAND devices. -It comprises of the following major components: -.Bl -bullet -.It -NAND Flash controller (NFC) interface. -.Pp -Defines methods which allow to send commands as well as send/receive data -between the controller and a NAND chip. -Back-end drivers for specific NAND -controllers plug into this interface and implement low-level routines for a -given NAND controller. -.Pp -This layer implements basic functionality of a NAND Flash controller. -It allows to send command and address to chip, drive CS (chip select line), -as well as read/write to the selected NAND chip. -This layer is independent of -NAND chip devices actually connected to the controller. -.It -NAND chip interface. -.Pp -Provides basic operations like read page, program page, erase block. -Currently three generic classes of drivers are available, which provide -support for the following chips: -.Bl -bullet -.It -large page -.It -small page -.It -ONFI-compliant -.El -.Pp -This layer implements basic operations to be performed on a NAND chip, like -read, program, erase, get status etc. -Since these operations use specific -commands (depending on the vendor), each chip has potentially its own -implementation of the commands set. -.Pp -The framework is extensible so it is also possible to create a custom command -set for a non standard chip support. -.It -NANDbus. -.Pp -This layer is responsible for enumerating NAND chips in the system and -establishing the hierarchy between chips and their supervising controllers. -.Pp -Its main purpose is detecting type of NAND chips connected to a given chip -select (CS line). -It also allows manages locking access to the NAND -controller. -NANDbus passes requests from an active chip to the chip controller. -.It -NAND character / GEOM device. -.Pp -For each NAND chip found in a system a character and GEOM devices are created -which allows to read / write directly to a device, as well as perform other -specific operations (like via ioctl). -.Pp -There are two GEOM devices created for each NAND chip: -.Bl -bullet -.It -raw device -.It -normal device -.El -.Pp -Raw device allows to bypass ECC checking when reading/writing to it, while -normal device always uses ECC algorithm to validate the read data. -.Pp -NAND character devices will be created for each NAND chip detected while -probing the NAND controller. -.El -.Sh SEE ALSO -.Xr libnandfs 3 , -.Xr gnand 4 , -.Xr nandsim 4 , -.Xr nandfs 5 , -.Xr makefs 8 , -.Xr mount_nandfs 8 , -.Xr nandfs 8 , -.Xr nandsim 8 , -.Xr nandtool 8 , -.Xr newfs_nandfs 8 , -.Xr umount_nandfs 8 -.Sh STANDARDS -Open NAND Flash Interface Working Group -.Pq Vt ONFI . -.Sh HISTORY -The -.Nm -framework support first appeared in -.Fx 10.0 . -.Sh AUTHORS -.An -nosplit -The -.Nm -framework was designed and developed by -.An Grzegorz Bernacki . -This manual page was written by -.An Rafal Jaworowski . diff --git a/share/man/man4/nandsim.4 b/share/man/man4/nandsim.4 deleted file mode 100644 index bf8d624eeb8a..000000000000 --- a/share/man/man4/nandsim.4 +++ /dev/null @@ -1,93 +0,0 @@ -.\" -.\" Copyright (c) 2012 The FreeBSD Foundation -.\" All rights reserved. -.\" -.\" This documentation was written by Semihalf under sponsorship from -.\" the FreeBSD Foundation. -.\" -.\" 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 March 8, 2012 -.Dt NANDSIM 4 -.Os -.Sh NAME -.Nm nandsim -.Nd NAND Flash simulator driver -.Sh SYNOPSIS -.Cd "device nand" -.Cd "device nandsim" -.Cd "options ALQ" -.Sh DESCRIPTION -The -.Nm -is part of the -.Fx -NAND framework -.Xr nand 4 -and can be characterized with the following highlights: -.Bl -bullet -.It -plugs into the -.Xr nand 4 -framework APIs as if it were a hardware controller (hanging on the nexus bus) -with real NAND chips connected to it -.It -physically part of the kernel code (either statically linked into the kernel -image or built as a module) -.It -controlled with a user space program -.Xr nandsim 8 -.El -.Pp -From the user perspective, the -.Nm -allows for imitating ONFI-compliant NAND Flash devices as if they were -attached to the system via a virtual controller. -.Pp -Some -.Nm -features rely on the ability to log contents to a file, which is achieved -through the -.Xr alq 9 -facility. -.Sh SEE ALSO -.Xr nand 4 , -.Xr nandsim.conf 5 , -.Xr nandsim 8 -.Sh STANDARDS -Open NAND Flash Interface Working Group -.Pq Vt ONFI . -.Sh HISTORY -The -.Nm -support first appeared in -.Fx 10.0 . -.Sh AUTHORS -.An -nosplit -The -.Nm -kernel driver was developed by -.An Grzegorz Bernacki . -This manual page was written by -.An Rafal Jaworowski . diff --git a/share/man/man5/Makefile b/share/man/man5/Makefile index b5ec870f75ff..119869128acb 100644 --- a/share/man/man5/Makefile +++ b/share/man/man5/Makefile @@ -101,10 +101,6 @@ MAN+= freebsd-update.conf.5 MAN+= hesiod.conf.5 .endif -.if ${MK_NAND} != "no" -MAN+= nandfs.5 -.endif - .if ${MK_PF} != "no" MAN+= pf.conf.5 \ pf.os.5 diff --git a/share/man/man5/nandfs.5 b/share/man/man5/nandfs.5 deleted file mode 100644 index 7e895993674d..000000000000 --- a/share/man/man5/nandfs.5 +++ /dev/null @@ -1,132 +0,0 @@ -.\" -.\" Copyright (c) 2010 Semihalf -.\" 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 Nov 11, 2010 -.Dt NANDFS 5 -.Os -.Sh NAME -.Nm nandfs -.Nd NAND Flash file system -.Sh SYNOPSIS -To compile support for the -.Nm , -place the following in your kernel configuration file: -.Bd -ragged -offset indent -.Cd "options NANDFS" -.Ed -.Pp -Even though the NAND FS can be used with any storage media, it has been -optimized and designed towards NAND Flash devices, so typically the following -driver is used: -.Bd -ragged -offset indent -.Cd "device nand" -.Ed -.Sh DESCRIPTION -The -.Nm -driver enables -.Fx -with support for NAND-oriented file system. -.Pp -It is a log-structured style file system with the following major features and -characteristics: -.Bl -bullet -.It -Hard links, symbolic links support -.It -Block journaling -.It -Copy-On-Write -.It -Snapshots (continuous, taken automatically, simultaneously mountable) -.It -Quick crash recovery at mount time -.It -64-bit data structures; supports many files, large files and volumes -.It -POSIX file permissions -.It -Checksum / ECC -.El -.Sh EXAMPLES -The most common usage is mounting the file system: -.Pp -.Dl "mount -t nandfs /dev/ /mnt" -.Pp -or: -.Dl "mount_nandfs /dev/ /mnt" -.Pp -where -.Ar gnandN -is the GEOM device representing a Flash partition (slice) containing the -.Nm -structure, and -.Pa /mnt -is a mount point. -.Pp -It is possible to define an entry in -.Pa /etc/fstab -for the -.Nm : -.Bd -literal -/dev/gnand0 /flash nandfs rw 0 0 -.Ed -.Pp -This will mount a -.Nm -partition at the specified mount point during system boot. -.Sh SEE ALSO -.Xr gnand 4 , -.Xr nand 4 , -.Xr mount_nandfs 8 , -.Xr nandfs 8 , -.Xr nandsim 8 , -.Xr nandtool 8 , -.Xr umount_nandfs 8 -.Sh HISTORY -The NAND FS concepts are based on NILFS principles and initial implementation -was derived from early read-only NILFS NetBSD code. -Since then the NAND FS -code diverged significantly and is by no means compatible with NILFS. -.Pp -The NAND Flash file system first appeared in -.Fx 10.0 . -.Sh AUTHORS -.An -nosplit -The NAND FS was written by -.An Grzegorz Bernacki -with the help of -.An Mateusz Guzik , -based on the NetBSD code created by -.An Reinoud Zandijk . -Additional help and support by -.An Lukasz Plachno , -.An Jan Sieka -and -.An Lukasz Wojcik . -This manual page was written by -.An Rafal Jaworowski . diff --git a/share/mk/bsd.libnames.mk b/share/mk/bsd.libnames.mk index b2675fce7cf3..1bea2ff10786 100644 --- a/share/mk/bsd.libnames.mk +++ b/share/mk/bsd.libnames.mk @@ -104,7 +104,6 @@ LIBMLX4?= ${LIBDESTDIR}${LIBDIR_BASE}/libmlx4.a LIBMLX5?= ${LIBDESTDIR}${LIBDIR_BASE}/libmlx5.a LIBMP?= ${LIBDESTDIR}${LIBDIR_BASE}/libmp.a LIBMT?= ${LIBDESTDIR}${LIBDIR_BASE}/libmt.a -LIBNANDFS?= ${LIBDESTDIR}${LIBDIR_BASE}/libnandfs.a LIBNCURSES?= ${LIBDESTDIR}${LIBDIR_BASE}/libncurses.a LIBNCURSESW?= ${LIBDESTDIR}${LIBDIR_BASE}/libncursesw.a LIBNETGRAPH?= ${LIBDESTDIR}${LIBDIR_BASE}/libnetgraph.a diff --git a/share/mk/src.libnames.mk b/share/mk/src.libnames.mk index d08a8653de3a..fcb03aaaedcd 100644 --- a/share/mk/src.libnames.mk +++ b/share/mk/src.libnames.mk @@ -135,7 +135,6 @@ _LIBRARIES= \ memstat \ mp \ mt \ - nandfs \ ncurses \ ncursesw \ netgraph \ diff --git a/share/mk/src.opts.mk b/share/mk/src.opts.mk index 96e3c94a948f..03d089b8246b 100644 --- a/share/mk/src.opts.mk +++ b/share/mk/src.opts.mk @@ -206,7 +206,6 @@ __DEFAULT_NO_OPTIONS = \ LOADER_FORCE_LE \ LOADER_VERBOSE \ LOADER_VERIEXEC_PASS_MANIFEST \ - NAND \ OFED_EXTRA \ OPENLDAP \ RPCBIND_WARMSTART_SUPPORT \ diff --git a/stand/arm/uboot/conf.c b/stand/arm/uboot/conf.c index 777a7b20340c..077541220f92 100644 --- a/stand/arm/uboot/conf.c +++ b/stand/arm/uboot/conf.c @@ -59,9 +59,6 @@ struct fs_ops *file_system[] = { #if defined(LOADER_EXT2FS_SUPPORT) &ext2fs_fsops, #endif -#if defined(LOADER_NANDFS_SUPPORT) - &nandfs_fsops, -#endif #if defined(LOADER_NFS_SUPPORT) &nfs_fsops, #endif diff --git a/stand/arm/uboot/version b/stand/arm/uboot/version index 486c4125cc0d..ec46b388b281 100644 --- a/stand/arm/uboot/version +++ b/stand/arm/uboot/version @@ -3,6 +3,7 @@ $FreeBSD$ NOTE ANY CHANGES YOU MAKE TO THE BOOTBLOCKS HERE. The format of this file is important. Make sure the current version number is on line 6. +1.3: Remove NAND FS support. 1.2: Extended with NAND FS support. 1.1: Flattened Device Tree blob support. 1.0: Added storage support. Booting from HDD, USB, etc. is now possible. diff --git a/stand/common/part.c b/stand/common/part.c index ec9697c6a10b..8eb4c065b473 100644 --- a/stand/common/part.c +++ b/stand/common/part.c @@ -57,7 +57,6 @@ static const uuid_t gpt_uuid_freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS; static const uuid_t gpt_uuid_efi = GPT_ENT_TYPE_EFI; static const uuid_t gpt_uuid_freebsd = GPT_ENT_TYPE_FREEBSD; static const uuid_t gpt_uuid_freebsd_boot = GPT_ENT_TYPE_FREEBSD_BOOT; -static const uuid_t gpt_uuid_freebsd_nandfs = GPT_ENT_TYPE_FREEBSD_NANDFS; static const uuid_t gpt_uuid_freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP; static const uuid_t gpt_uuid_freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS; static const uuid_t gpt_uuid_freebsd_vinum = GPT_ENT_TYPE_FREEBSD_VINUM; @@ -91,7 +90,6 @@ static struct parttypes { { PART_EFI, "EFI" }, { PART_FREEBSD, "FreeBSD" }, { PART_FREEBSD_BOOT, "FreeBSD boot" }, - { PART_FREEBSD_NANDFS, "FreeBSD nandfs" }, { PART_FREEBSD_UFS, "FreeBSD UFS" }, { PART_FREEBSD_ZFS, "FreeBSD ZFS" }, { PART_FREEBSD_SWAP, "FreeBSD swap" }, @@ -141,8 +139,6 @@ gpt_parttype(uuid_t type) return (PART_FREEBSD_SWAP); else if (uuid_equal(&type, &gpt_uuid_freebsd_vinum, NULL)) return (PART_FREEBSD_VINUM); - else if (uuid_equal(&type, &gpt_uuid_freebsd_nandfs, NULL)) - return (PART_FREEBSD_NANDFS); else if (uuid_equal(&type, &gpt_uuid_freebsd, NULL)) return (PART_FREEBSD); return (PART_UNKNOWN); @@ -445,8 +441,6 @@ bsd_parttype(uint8_t type) { switch (type) { - case FS_NANDFS: - return (PART_FREEBSD_NANDFS); case FS_SWAP: return (PART_FREEBSD_SWAP); case FS_BSDFFS: @@ -527,8 +521,6 @@ vtoc8_parttype(uint16_t type) { switch (type) { - case VTOC_TAG_FREEBSD_NANDFS: - return (PART_FREEBSD_NANDFS); case VTOC_TAG_FREEBSD_SWAP: return (PART_FREEBSD_SWAP); case VTOC_TAG_FREEBSD_UFS: diff --git a/stand/common/part.h b/stand/common/part.h index 3eac476b6d66..490db6746c38 100644 --- a/stand/common/part.h +++ b/stand/common/part.h @@ -45,7 +45,6 @@ enum partition_type { PART_EFI, PART_FREEBSD, PART_FREEBSD_BOOT, - PART_FREEBSD_NANDFS, PART_FREEBSD_UFS, PART_FREEBSD_ZFS, PART_FREEBSD_SWAP, diff --git a/stand/i386/loader/conf.c b/stand/i386/loader/conf.c index 02f1160cd1a4..c70a53d4191a 100644 --- a/stand/i386/loader/conf.c +++ b/stand/i386/loader/conf.c @@ -84,9 +84,6 @@ struct fs_ops *file_system[] = { #if defined(LOADER_CD9660_SUPPORT) &cd9660_fsops, #endif -#if defined(LOADER_NANDFS_SUPPORT) - &nandfs_fsops, -#endif #ifdef LOADER_NFS_SUPPORT &nfs_fsops, #endif diff --git a/stand/libsa/Makefile b/stand/libsa/Makefile index b09b23c79d93..72a9775298d0 100644 --- a/stand/libsa/Makefile +++ b/stand/libsa/Makefile @@ -145,9 +145,6 @@ SRCS+= ufs.c nfs.c cd9660.c tftp.c gzipfs.c bzipfs.c SRCS+= dosfs.c ext2fs.c SRCS+= splitfs.c SRCS+= pkgfs.c -.if ${MK_NAND} != "no" -SRCS+= nandfs.c -.endif # kernel ufs support .PATH: ${SRCTOP}/sys/ufs/ffs diff --git a/stand/libsa/nandfs.c b/stand/libsa/nandfs.c deleted file mode 100644 index b3e72243e995..000000000000 --- a/stand/libsa/nandfs.c +++ /dev/null @@ -1,1061 +0,0 @@ -/*- - * Copyright (c) 2010-2012 Semihalf. - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 -#include -#include -#include -#include -#include "stand.h" -#include "string.h" -#include "zlib.h" - -#define DEBUG -#undef DEBUG -#ifdef DEBUG -#define NANDFS_DEBUG(fmt, args...) do { \ - printf("NANDFS_DEBUG:" fmt "\n", ##args); } while (0) -#else -#define NANDFS_DEBUG(fmt, args...) -#endif - -struct nandfs_mdt { - uint32_t entries_per_block; - uint32_t entries_per_group; - uint32_t blocks_per_group; - uint32_t groups_per_desc_block; /* desc is super group */ - uint32_t blocks_per_desc_block; /* desc is super group */ -}; - -struct bmap_buf { - LIST_ENTRY(bmap_buf) list; - nandfs_daddr_t blknr; - uint64_t *map; -}; - -struct nandfs_node { - struct nandfs_inode *inode; - LIST_HEAD(, bmap_buf) bmap_bufs; -}; -struct nandfs { - int nf_blocksize; - int nf_sectorsize; - int nf_cpno; - - struct open_file *nf_file; - struct nandfs_node *nf_opened_node; - u_int nf_offset; - uint8_t *nf_buf; - int64_t nf_buf_blknr; - - struct nandfs_fsdata *nf_fsdata; - struct nandfs_super_block *nf_sb; - struct nandfs_segment_summary nf_segsum; - struct nandfs_checkpoint nf_checkpoint; - struct nandfs_super_root nf_sroot; - struct nandfs_node nf_ifile; - struct nandfs_node nf_datfile; - struct nandfs_node nf_cpfile; - struct nandfs_mdt nf_datfile_mdt; - struct nandfs_mdt nf_ifile_mdt; - - int nf_nindir[NANDFS_NIADDR]; -}; - -static int nandfs_open(const char *, struct open_file *); -static int nandfs_close(struct open_file *); -static int nandfs_read(struct open_file *, void *, size_t, size_t *); -static off_t nandfs_seek(struct open_file *, off_t, int); -static int nandfs_stat(struct open_file *, struct stat *); -static int nandfs_readdir(struct open_file *, struct dirent *); - -static int nandfs_buf_read(struct nandfs *, void **, size_t *); -static struct nandfs_node *nandfs_lookup_path(struct nandfs *, const char *); -static int nandfs_read_inode(struct nandfs *, struct nandfs_node *, - nandfs_lbn_t, u_int, void *, int); -static int nandfs_read_blk(struct nandfs *, nandfs_daddr_t, void *, int); -static int nandfs_bmap_lookup(struct nandfs *, struct nandfs_node *, - nandfs_lbn_t, nandfs_daddr_t *, int); -static int nandfs_get_checkpoint(struct nandfs *, uint64_t, - struct nandfs_checkpoint *); -static nandfs_daddr_t nandfs_vtop(struct nandfs *, nandfs_daddr_t); -static void nandfs_calc_mdt_consts(int, struct nandfs_mdt *, int); -static void nandfs_mdt_trans(struct nandfs_mdt *, uint64_t, - nandfs_daddr_t *, uint32_t *); -static int ioread(struct open_file *, off_t, void *, u_int); -static int nandfs_probe_sectorsize(struct open_file *); - -struct fs_ops nandfs_fsops = { - "nandfs", - nandfs_open, - nandfs_close, - nandfs_read, - null_write, - nandfs_seek, - nandfs_stat, - nandfs_readdir -}; - -#define NINDIR(fs) ((fs)->nf_blocksize / sizeof(nandfs_daddr_t)) - -/* from NetBSD's src/sys/net/if_ethersubr.c */ -static uint32_t -nandfs_crc32(uint32_t crc, const uint8_t *buf, size_t len) -{ - static const uint32_t crctab[] = { - 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, - 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, - 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, - 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c - }; - size_t i; - - crc = crc ^ ~0U; - for (i = 0; i < len; i++) { - crc ^= buf[i]; - crc = (crc >> 4) ^ crctab[crc & 0xf]; - crc = (crc >> 4) ^ crctab[crc & 0xf]; - } - return (crc ^ ~0U); -} - -static int -nandfs_check_fsdata_crc(struct nandfs_fsdata *fsdata) -{ - uint32_t fsdata_crc, comp_crc; - - if (fsdata->f_magic != NANDFS_FSDATA_MAGIC) - return (0); - - /* Preserve crc */ - fsdata_crc = fsdata->f_sum; - - /* Calculate */ - fsdata->f_sum = (0); - comp_crc = nandfs_crc32(0, (uint8_t *)fsdata, fsdata->f_bytes); - - /* Restore */ - fsdata->f_sum = fsdata_crc; - - /* Check CRC */ - return (fsdata_crc == comp_crc); -} - -static int -nandfs_check_superblock_crc(struct nandfs_fsdata *fsdata, - struct nandfs_super_block *super) -{ - uint32_t super_crc, comp_crc; - - /* Check super block magic */ - if (super->s_magic != NANDFS_SUPER_MAGIC) - return (0); - - /* Preserve CRC */ - super_crc = super->s_sum; - - /* Calculate */ - super->s_sum = (0); - comp_crc = nandfs_crc32(0, (uint8_t *)super, fsdata->f_sbbytes); - - /* Restore */ - super->s_sum = super_crc; - - /* Check CRC */ - return (super_crc == comp_crc); -} - -static int -nandfs_find_super_block(struct nandfs *fs, struct open_file *f) -{ - struct nandfs_super_block *sb; - int i, j, n, s; - int sectors_to_read, error; - - sb = malloc(fs->nf_sectorsize); - if (sb == NULL) - return (ENOMEM); - - memset(fs->nf_sb, 0, sizeof(*fs->nf_sb)); - - sectors_to_read = (NANDFS_NFSAREAS * fs->nf_fsdata->f_erasesize) / - fs->nf_sectorsize; - for (i = 0; i < sectors_to_read; i++) { - NANDFS_DEBUG("reading i %d offset %d\n", i, - i * fs->nf_sectorsize); - error = ioread(f, i * fs->nf_sectorsize, (char *)sb, - fs->nf_sectorsize); - if (error) { - NANDFS_DEBUG("error %d\n", error); - continue; - } - n = fs->nf_sectorsize / sizeof(struct nandfs_super_block); - s = 0; - if ((i * fs->nf_sectorsize) % fs->nf_fsdata->f_erasesize == 0) { - if (fs->nf_sectorsize == sizeof(struct nandfs_fsdata)) - continue; - else { - s += (sizeof(struct nandfs_fsdata) / - sizeof(struct nandfs_super_block)); - } - } - - for (j = s; j < n; j++) { - if (!nandfs_check_superblock_crc(fs->nf_fsdata, &sb[j])) - continue; - NANDFS_DEBUG("magic %x wtime %jd, lastcp 0x%jx\n", - sb[j].s_magic, sb[j].s_wtime, sb[j].s_last_cno); - if (sb[j].s_last_cno > fs->nf_sb->s_last_cno) - memcpy(fs->nf_sb, &sb[j], sizeof(*fs->nf_sb)); - } - } - - free(sb); - - return (fs->nf_sb->s_magic != 0 ? 0 : EINVAL); -} - -static int -nandfs_find_fsdata(struct nandfs *fs, struct open_file *f) -{ - int offset, error, i; - - NANDFS_DEBUG("starting\n"); - - offset = 0; - for (i = 0; i < 64 * NANDFS_NFSAREAS; i++) { - error = ioread(f, offset, (char *)fs->nf_fsdata, - sizeof(struct nandfs_fsdata)); - if (error) - return (error); - if (fs->nf_fsdata->f_magic == NANDFS_FSDATA_MAGIC) { - NANDFS_DEBUG("found at %x, volume %s\n", offset, - fs->nf_fsdata->f_volume_name); - if (nandfs_check_fsdata_crc(fs->nf_fsdata)) - break; - } - offset += fs->nf_sectorsize; - } - - return (error); -} - -static int -nandfs_read_structures(struct nandfs *fs, struct open_file *f) -{ - int error; - - error = nandfs_find_fsdata(fs, f); - if (error) - return (error); - - error = nandfs_find_super_block(fs, f); - - if (error == 0) - NANDFS_DEBUG("selected sb with w_time %jd last_pseg %jx\n", - fs->nf_sb->s_wtime, fs->nf_sb->s_last_pseg); - - return (error); -} - -static int -nandfs_mount(struct nandfs *fs, struct open_file *f) -{ - int err = 0, level; - uint64_t last_pseg; - - fs->nf_fsdata = malloc(sizeof(struct nandfs_fsdata)); - fs->nf_sb = malloc(sizeof(struct nandfs_super_block)); - - err = nandfs_read_structures(fs, f); - if (err) { - free(fs->nf_fsdata); - free(fs->nf_sb); - return (err); - } - - fs->nf_blocksize = 1 << (fs->nf_fsdata->f_log_block_size + 10); - - NANDFS_DEBUG("using superblock with wtime %jd\n", fs->nf_sb->s_wtime); - - fs->nf_cpno = fs->nf_sb->s_last_cno; - last_pseg = fs->nf_sb->s_last_pseg; - - /* - * Calculate indirect block levels. - */ - nandfs_daddr_t mult; - - mult = 1; - for (level = 0; level < NANDFS_NIADDR; level++) { - mult *= NINDIR(fs); - fs->nf_nindir[level] = mult; - } - - nandfs_calc_mdt_consts(fs->nf_blocksize, &fs->nf_datfile_mdt, - fs->nf_fsdata->f_dat_entry_size); - - nandfs_calc_mdt_consts(fs->nf_blocksize, &fs->nf_ifile_mdt, - fs->nf_fsdata->f_inode_size); - - err = ioread(f, last_pseg * fs->nf_blocksize, &fs->nf_segsum, - sizeof(struct nandfs_segment_summary)); - if (err) { - free(fs->nf_sb); - free(fs->nf_fsdata); - return (err); - } - - err = ioread(f, (last_pseg + fs->nf_segsum.ss_nblocks - 1) * - fs->nf_blocksize, &fs->nf_sroot, sizeof(struct nandfs_super_root)); - if (err) { - free(fs->nf_sb); - free(fs->nf_fsdata); - return (err); - } - - fs->nf_datfile.inode = &fs->nf_sroot.sr_dat; - LIST_INIT(&fs->nf_datfile.bmap_bufs); - fs->nf_cpfile.inode = &fs->nf_sroot.sr_cpfile; - LIST_INIT(&fs->nf_cpfile.bmap_bufs); - - err = nandfs_get_checkpoint(fs, fs->nf_cpno, &fs->nf_checkpoint); - if (err) { - free(fs->nf_sb); - free(fs->nf_fsdata); - return (err); - } - - NANDFS_DEBUG("checkpoint cp_cno=%lld\n", fs->nf_checkpoint.cp_cno); - NANDFS_DEBUG("checkpoint cp_inodes_count=%lld\n", - fs->nf_checkpoint.cp_inodes_count); - NANDFS_DEBUG("checkpoint cp_ifile_inode.i_blocks=%lld\n", - fs->nf_checkpoint.cp_ifile_inode.i_blocks); - - fs->nf_ifile.inode = &fs->nf_checkpoint.cp_ifile_inode; - LIST_INIT(&fs->nf_ifile.bmap_bufs); - return (0); -} - -#define NINDIR(fs) ((fs)->nf_blocksize / sizeof(nandfs_daddr_t)) - -static int -nandfs_open(const char *path, struct open_file *f) -{ - struct nandfs *fs; - struct nandfs_node *node; - int err, bsize, level; - - NANDFS_DEBUG("nandfs_open('%s', %p)\n", path, f); - - fs = malloc(sizeof(struct nandfs)); - f->f_fsdata = fs; - fs->nf_file = f; - - bsize = nandfs_probe_sectorsize(f); - if (bsize < 0) { - printf("Cannot probe medium sector size\n"); - return (EINVAL); - } - - fs->nf_sectorsize = bsize; - - /* - * Calculate indirect block levels. - */ - nandfs_daddr_t mult; - - mult = 1; - for (level = 0; level < NANDFS_NIADDR; level++) { - mult *= NINDIR(fs); - fs->nf_nindir[level] = mult; - } - - NANDFS_DEBUG("fs %p nf_sectorsize=%x\n", fs, fs->nf_sectorsize); - - err = nandfs_mount(fs, f); - if (err) { - NANDFS_DEBUG("Cannot mount nandfs: %s\n", strerror(err)); - return (err); - } - - node = nandfs_lookup_path(fs, path); - if (node == NULL) - return (EINVAL); - - fs->nf_offset = 0; - fs->nf_buf = NULL; - fs->nf_buf_blknr = -1; - fs->nf_opened_node = node; - LIST_INIT(&fs->nf_opened_node->bmap_bufs); - return (0); -} - -static void -nandfs_free_node(struct nandfs_node *node) -{ - struct bmap_buf *bmap, *tmp; - - free(node->inode); - LIST_FOREACH_SAFE(bmap, &node->bmap_bufs, list, tmp) { - LIST_REMOVE(bmap, list); - free(bmap->map); - free(bmap); - } - free(node); -} - -static int -nandfs_close(struct open_file *f) -{ - struct nandfs *fs = f->f_fsdata; - - NANDFS_DEBUG("nandfs_close(%p)\n", f); - - if (fs->nf_buf != NULL) - free(fs->nf_buf); - - nandfs_free_node(fs->nf_opened_node); - free(fs->nf_sb); - free(fs); - return (0); -} - -static int -nandfs_read(struct open_file *f, void *addr, size_t size, size_t *resid) -{ - struct nandfs *fs = (struct nandfs *)f->f_fsdata; - size_t csize, buf_size; - void *buf; - int error = 0; - - NANDFS_DEBUG("nandfs_read(file=%p, addr=%p, size=%d)\n", f, addr, size); - - while (size != 0) { - if (fs->nf_offset >= fs->nf_opened_node->inode->i_size) - break; - - error = nandfs_buf_read(fs, &buf, &buf_size); - if (error) - break; - - csize = size; - if (csize > buf_size) - csize = buf_size; - - bcopy(buf, addr, csize); - - fs->nf_offset += csize; - addr = (char *)addr + csize; - size -= csize; - } - - if (resid) - *resid = size; - return (error); -} - -static off_t -nandfs_seek(struct open_file *f, off_t offset, int where) -{ - struct nandfs *fs = f->f_fsdata; - off_t off; - u_int size; - - NANDFS_DEBUG("nandfs_seek(file=%p, offset=%lld, where=%d)\n", f, - offset, where); - - size = fs->nf_opened_node->inode->i_size; - - switch (where) { - case SEEK_SET: - off = 0; - break; - case SEEK_CUR: - off = fs->nf_offset; - break; - case SEEK_END: - off = size; - break; - default: - errno = EINVAL; - return (-1); - } - - off += offset; - if (off < 0 || off > size) { - errno = EINVAL; - return(-1); - } - - fs->nf_offset = (u_int)off; - - return (off); -} - -static int -nandfs_stat(struct open_file *f, struct stat *sb) -{ - struct nandfs *fs = f->f_fsdata; - - NANDFS_DEBUG("nandfs_stat(file=%p, stat=%p)\n", f, sb); - - sb->st_size = fs->nf_opened_node->inode->i_size; - sb->st_mode = fs->nf_opened_node->inode->i_mode; - sb->st_uid = fs->nf_opened_node->inode->i_uid; - sb->st_gid = fs->nf_opened_node->inode->i_gid; - return (0); -} - -static int -nandfs_readdir(struct open_file *f, struct dirent *d) -{ - struct nandfs *fs = f->f_fsdata; - struct nandfs_dir_entry *dirent; - void *buf; - size_t buf_size; - - NANDFS_DEBUG("nandfs_readdir(file=%p, dirent=%p)\n", f, d); - - if (fs->nf_offset >= fs->nf_opened_node->inode->i_size) { - NANDFS_DEBUG("nandfs_readdir(file=%p, dirent=%p) ENOENT\n", - f, d); - return (ENOENT); - } - - if (nandfs_buf_read(fs, &buf, &buf_size)) { - NANDFS_DEBUG("nandfs_readdir(file=%p, dirent=%p)" - "buf_read failed\n", f, d); - return (EIO); - } - - NANDFS_DEBUG("nandfs_readdir(file=%p, dirent=%p) moving forward\n", - f, d); - - dirent = (struct nandfs_dir_entry *)buf; - fs->nf_offset += dirent->rec_len; - strncpy(d->d_name, dirent->name, dirent->name_len); - d->d_name[dirent->name_len] = '\0'; - d->d_type = dirent->file_type; - return (0); -} - -static int -nandfs_buf_read(struct nandfs *fs, void **buf_p, size_t *size_p) -{ - nandfs_daddr_t blknr, blkoff; - - blknr = fs->nf_offset / fs->nf_blocksize; - blkoff = fs->nf_offset % fs->nf_blocksize; - - if (blknr != fs->nf_buf_blknr) { - if (fs->nf_buf == NULL) - fs->nf_buf = malloc(fs->nf_blocksize); - - if (nandfs_read_inode(fs, fs->nf_opened_node, blknr, 1, - fs->nf_buf, 0)) - return (EIO); - - fs->nf_buf_blknr = blknr; - } - - *buf_p = fs->nf_buf + blkoff; - *size_p = fs->nf_blocksize - blkoff; - - NANDFS_DEBUG("nandfs_buf_read buf_p=%p size_p=%d\n", *buf_p, *size_p); - - if (*size_p > fs->nf_opened_node->inode->i_size - fs->nf_offset) - *size_p = fs->nf_opened_node->inode->i_size - fs->nf_offset; - - return (0); -} - -static struct nandfs_node * -nandfs_lookup_node(struct nandfs *fs, uint64_t ino) -{ - uint64_t blocknr; - int entrynr; - struct nandfs_inode *buffer; - struct nandfs_node *node; - struct nandfs_inode *inode; - - NANDFS_DEBUG("nandfs_lookup_node ino=%lld\n", ino); - - if (ino == 0) { - printf("nandfs_lookup_node: invalid inode requested\n"); - return (NULL); - } - - buffer = malloc(fs->nf_blocksize); - inode = malloc(sizeof(struct nandfs_inode)); - node = malloc(sizeof(struct nandfs_node)); - - nandfs_mdt_trans(&fs->nf_ifile_mdt, ino, &blocknr, &entrynr); - - if (nandfs_read_inode(fs, &fs->nf_ifile, blocknr, 1, buffer, 0)) - return (NULL); - - memcpy(inode, &buffer[entrynr], sizeof(struct nandfs_inode)); - node->inode = inode; - free(buffer); - return (node); -} - -static struct nandfs_node * -nandfs_lookup_path(struct nandfs *fs, const char *path) -{ - struct nandfs_node *node; - struct nandfs_dir_entry *dirent; - char *namebuf; - uint64_t i, done, pinode, inode; - int nlinks = 0, counter, len, link_len, nameidx; - uint8_t *buffer, *orig; - char *strp, *lpath; - - buffer = malloc(fs->nf_blocksize); - orig = buffer; - - namebuf = malloc(2 * MAXPATHLEN + 2); - strncpy(namebuf, path, MAXPATHLEN); - namebuf[MAXPATHLEN] = '\0'; - done = nameidx = 0; - lpath = namebuf; - - /* Get the root inode */ - node = nandfs_lookup_node(fs, NANDFS_ROOT_INO); - inode = NANDFS_ROOT_INO; - - while ((strp = strsep(&lpath, "/")) != NULL) { - if (*strp == '\0') - continue; - if ((node->inode->i_mode & IFMT) != IFDIR) { - nandfs_free_node(node); - node = NULL; - goto out; - } - - len = strlen(strp); - NANDFS_DEBUG("%s: looking for %s\n", __func__, strp); - for (i = 0; i < node->inode->i_blocks; i++) { - if (nandfs_read_inode(fs, node, i, 1, orig, 0)) { - node = NULL; - goto out; - } - - buffer = orig; - done = counter = 0; - while (1) { - dirent = - (struct nandfs_dir_entry *)(void *)buffer; - NANDFS_DEBUG("%s: dirent.name = %s\n", - __func__, dirent->name); - NANDFS_DEBUG("%s: dirent.rec_len = %d\n", - __func__, dirent->rec_len); - NANDFS_DEBUG("%s: dirent.inode = %lld\n", - __func__, dirent->inode); - if (len == dirent->name_len && - (strncmp(strp, dirent->name, len) == 0) && - dirent->inode != 0) { - nandfs_free_node(node); - node = nandfs_lookup_node(fs, - dirent->inode); - pinode = inode; - inode = dirent->inode; - done = 1; - break; - } - - counter += dirent->rec_len; - buffer += dirent->rec_len; - - if (counter == fs->nf_blocksize) - break; - } - - if (done) - break; - } - - if (!done) { - node = NULL; - goto out; - } - - NANDFS_DEBUG("%s: %.*s has mode %o\n", __func__, - dirent->name_len, dirent->name, node->inode->i_mode); - - if ((node->inode->i_mode & IFMT) == IFLNK) { - NANDFS_DEBUG("%s: %.*s is symlink\n", - __func__, dirent->name_len, dirent->name); - link_len = node->inode->i_size; - - if (++nlinks > MAXSYMLINKS) { - nandfs_free_node(node); - node = NULL; - goto out; - } - - if (nandfs_read_inode(fs, node, 0, 1, orig, 0)) { - nandfs_free_node(node); - node = NULL; - goto out; - } - - NANDFS_DEBUG("%s: symlink is %.*s\n", - __func__, link_len, (char *)orig); - - nameidx = (nameidx == 0) ? MAXPATHLEN + 1 : 0; - bcopy((char *)orig, namebuf + nameidx, - (unsigned)link_len); - if (lpath != NULL) { - namebuf[nameidx + link_len++] = '/'; - strncpy(namebuf + nameidx + link_len, lpath, - MAXPATHLEN - link_len); - namebuf[nameidx + MAXPATHLEN] = '\0'; - } else - namebuf[nameidx + link_len] = '\0'; - - NANDFS_DEBUG("%s: strp=%s, lpath=%s, namebuf0=%s, " - "namebuf1=%s, idx=%d\n", __func__, strp, lpath, - namebuf + 0, namebuf + MAXPATHLEN + 1, nameidx); - - lpath = namebuf + nameidx; - - nandfs_free_node(node); - - /* - * If absolute pathname, restart at root. Otherwise - * continue with out parent inode. - */ - inode = (orig[0] == '/') ? NANDFS_ROOT_INO : pinode; - node = nandfs_lookup_node(fs, inode); - } - } - -out: - free(namebuf); - free(orig); - return (node); -} - -static int -nandfs_read_inode(struct nandfs *fs, struct nandfs_node *node, - nandfs_daddr_t blknr, u_int nblks, void *buf, int raw) -{ - uint64_t *pblks; - uint64_t *vblks; - u_int i; - int error; - - pblks = malloc(nblks * sizeof(uint64_t)); - vblks = malloc(nblks * sizeof(uint64_t)); - - NANDFS_DEBUG("nandfs_read_inode fs=%p node=%p blknr=%lld nblks=%d\n", - fs, node, blknr, nblks); - for (i = 0; i < nblks; i++) { - error = nandfs_bmap_lookup(fs, node, blknr + i, &vblks[i], raw); - if (error) { - free(pblks); - free(vblks); - return (error); - } - if (raw == 0) - pblks[i] = nandfs_vtop(fs, vblks[i]); - else - pblks[i] = vblks[i]; - } - - for (i = 0; i < nblks; i++) { - if (ioread(fs->nf_file, pblks[i] * fs->nf_blocksize, buf, - fs->nf_blocksize)) { - free(pblks); - free(vblks); - return (EIO); - } - - buf = (void *)((uintptr_t)buf + fs->nf_blocksize); - } - - free(pblks); - free(vblks); - return (0); -} - -static int -nandfs_read_blk(struct nandfs *fs, nandfs_daddr_t blknr, void *buf, int phys) -{ - uint64_t pblknr; - - pblknr = (phys ? blknr : nandfs_vtop(fs, blknr)); - - return (ioread(fs->nf_file, pblknr * fs->nf_blocksize, buf, - fs->nf_blocksize)); -} - -static int -nandfs_get_checkpoint(struct nandfs *fs, uint64_t cpno, - struct nandfs_checkpoint *cp) -{ - uint64_t blocknr; - int blockoff, cp_per_block, dlen; - uint8_t *buf; - - NANDFS_DEBUG("nandfs_get_checkpoint(fs=%p cpno=%lld)\n", fs, cpno); - - buf = malloc(fs->nf_blocksize); - - cpno += NANDFS_CPFILE_FIRST_CHECKPOINT_OFFSET - 1; - dlen = fs->nf_fsdata->f_checkpoint_size; - cp_per_block = fs->nf_blocksize / dlen; - blocknr = cpno / cp_per_block; - blockoff = (cpno % cp_per_block) * dlen; - - if (nandfs_read_inode(fs, &fs->nf_cpfile, blocknr, 1, buf, 0)) { - free(buf); - return (EINVAL); - } - - memcpy(cp, buf + blockoff, sizeof(struct nandfs_checkpoint)); - free(buf); - - return (0); -} - -static uint64_t * -nandfs_get_map(struct nandfs *fs, struct nandfs_node *node, nandfs_daddr_t blknr, - int phys) -{ - struct bmap_buf *bmap; - uint64_t *map; - - LIST_FOREACH(bmap, &node->bmap_bufs, list) { - if (bmap->blknr == blknr) - return (bmap->map); - } - - map = malloc(fs->nf_blocksize); - if (nandfs_read_blk(fs, blknr, map, phys)) { - free(map); - return (NULL); - } - - bmap = malloc(sizeof(struct bmap_buf)); - bmap->blknr = blknr; - bmap->map = map; - - LIST_INSERT_HEAD(&node->bmap_bufs, bmap, list); - - NANDFS_DEBUG("%s:(node=%p, map=%p)\n", __func__, node, map); - return (map); -} - -static int -nandfs_bmap_lookup(struct nandfs *fs, struct nandfs_node *node, - nandfs_lbn_t lblknr, nandfs_daddr_t *vblknr, int phys) -{ - struct nandfs_inode *ino; - nandfs_daddr_t ind_block_num; - uint64_t *map; - int idx; - int level; - - ino = node->inode; - - if (lblknr < NANDFS_NDADDR) { - *vblknr = ino->i_db[lblknr]; - return (0); - } - - lblknr -= NANDFS_NDADDR; - - /* - * nindir[0] = NINDIR - * nindir[1] = NINDIR**2 - * nindir[2] = NINDIR**3 - * etc - */ - for (level = 0; level < NANDFS_NIADDR; level++) { - NANDFS_DEBUG("lblknr=%jx fs->nf_nindir[%d]=%d\n", lblknr, level, fs->nf_nindir[level]); - if (lblknr < fs->nf_nindir[level]) - break; - lblknr -= fs->nf_nindir[level]; - } - - if (level == NANDFS_NIADDR) { - /* Block number too high */ - NANDFS_DEBUG("lblknr %jx too high\n", lblknr); - return (EFBIG); - } - - ind_block_num = ino->i_ib[level]; - - for (; level >= 0; level--) { - if (ind_block_num == 0) { - *vblknr = 0; /* missing */ - return (0); - } - - twiddle(1); - NANDFS_DEBUG("calling get_map with %jx\n", ind_block_num); - map = nandfs_get_map(fs, node, ind_block_num, phys); - if (map == NULL) - return (EIO); - - if (level > 0) { - idx = lblknr / fs->nf_nindir[level - 1]; - lblknr %= fs->nf_nindir[level - 1]; - } else - idx = lblknr; - - ind_block_num = ((nandfs_daddr_t *)map)[idx]; - } - - *vblknr = ind_block_num; - - return (0); -} - -static nandfs_daddr_t -nandfs_vtop(struct nandfs *fs, nandfs_daddr_t vblocknr) -{ - nandfs_lbn_t blocknr; - nandfs_daddr_t pblocknr; - int entrynr; - struct nandfs_dat_entry *dat; - - dat = malloc(fs->nf_blocksize); - nandfs_mdt_trans(&fs->nf_datfile_mdt, vblocknr, &blocknr, &entrynr); - - if (nandfs_read_inode(fs, &fs->nf_datfile, blocknr, 1, dat, 1)) { - free(dat); - return (0); - } - - NANDFS_DEBUG("nandfs_vtop entrynr=%d vblocknr=%lld pblocknr=%lld\n", - entrynr, vblocknr, dat[entrynr].de_blocknr); - - pblocknr = dat[entrynr].de_blocknr; - free(dat); - return (pblocknr); -} - -static void -nandfs_calc_mdt_consts(int blocksize, struct nandfs_mdt *mdt, int entry_size) -{ - - mdt->entries_per_group = blocksize * 8; /* bits in sector */ - mdt->entries_per_block = blocksize / entry_size; - mdt->blocks_per_group = - (mdt->entries_per_group -1) / mdt->entries_per_block + 1 + 1; - mdt->groups_per_desc_block = - blocksize / sizeof(struct nandfs_block_group_desc); - mdt->blocks_per_desc_block = - mdt->groups_per_desc_block * mdt->blocks_per_group + 1; -} - -static void -nandfs_mdt_trans(struct nandfs_mdt *mdt, uint64_t index, - nandfs_daddr_t *blocknr, uint32_t *entry_in_block) -{ - nandfs_daddr_t blknr; - uint64_t group, group_offset, blocknr_in_group; - uint64_t desc_block, desc_offset; - - /* Calculate our offset in the file */ - group = index / mdt->entries_per_group; - group_offset = index % mdt->entries_per_group; - desc_block = group / mdt->groups_per_desc_block; - desc_offset = group % mdt->groups_per_desc_block; - blocknr_in_group = group_offset / mdt->entries_per_block; - - /* To descgroup offset */ - blknr = 1 + desc_block * mdt->blocks_per_desc_block; - - /* To group offset */ - blknr += desc_offset * mdt->blocks_per_group; - - /* To actual file block */ - blknr += 1 + blocknr_in_group; - - *blocknr = blknr; - *entry_in_block = group_offset % mdt->entries_per_block; -} - -static int -ioread(struct open_file *f, off_t pos, void *buf, u_int length) -{ - void *buffer; - int err; - int bsize = ((struct nandfs *)f->f_fsdata)->nf_sectorsize; - u_int off, nsec; - - off = pos % bsize; - pos /= bsize; - nsec = howmany(length, bsize); - - NANDFS_DEBUG("pos=%lld length=%d off=%d nsec=%d\n", pos, length, - off, nsec); - - buffer = malloc(nsec * bsize); - - err = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, pos, - nsec * bsize, buffer, NULL); - - memcpy(buf, (void *)((uintptr_t)buffer + off), length); - free(buffer); - - return (err); -} - -static int -nandfs_probe_sectorsize(struct open_file *f) -{ - void *buffer; - int i, err; - - buffer = malloc(16 * 1024); - - NANDFS_DEBUG("probing for sector size: "); - - for (i = 512; i < (16 * 1024); i <<= 1) { - NANDFS_DEBUG("%d ", i); - err = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 0, i, - buffer, NULL); - - if (err == 0) { - NANDFS_DEBUG("found"); - free(buffer); - return (i); - } - } - - free(buffer); - NANDFS_DEBUG("not found\n"); - return (-1); -} diff --git a/stand/libsa/stand.h b/stand/libsa/stand.h index d7584ee01fe7..3d0cb4ff0c50 100644 --- a/stand/libsa/stand.h +++ b/stand/libsa/stand.h @@ -119,7 +119,6 @@ extern struct fs_ops ufs_fsops; extern struct fs_ops tftp_fsops; extern struct fs_ops nfs_fsops; extern struct fs_ops cd9660_fsops; -extern struct fs_ops nandfs_fsops; extern struct fs_ops gzipfs_fsops; extern struct fs_ops bzipfs_fsops; extern struct fs_ops dosfs_fsops; diff --git a/stand/loader.mk b/stand/loader.mk index bd24f33bc6b1..a7fbd6c12dd9 100644 --- a/stand/loader.mk +++ b/stand/loader.mk @@ -99,9 +99,6 @@ CFLAGS+= -DLOADER_EXT2FS_SUPPORT .if ${LOADER_MSDOS_SUPPORT:Uno} == "yes" CFLAGS+= -DLOADER_MSDOS_SUPPORT .endif -.if ${LOADER_NANDFS_SUPPORT:U${MK_NAND}} == "yes" -CFLAGS+= -DLOADER_NANDFS_SUPPORT -.endif .if ${LOADER_UFS_SUPPORT:Uyes} == "yes" CFLAGS+= -DLOADER_UFS_SUPPORT .endif diff --git a/stand/mips/uboot/conf.c b/stand/mips/uboot/conf.c index f711a8cec5f2..922f7680b616 100644 --- a/stand/mips/uboot/conf.c +++ b/stand/mips/uboot/conf.c @@ -62,9 +62,6 @@ struct fs_ops *file_system[] = { #if defined(LOADER_EXT2FS_SUPPORT) &ext2fs_fsops, #endif -#if defined(LOADER_NANDFS_SUPPORT) - &nandfs_fsops, -#endif #if defined(LOADER_NFS_SUPPORT) &nfs_fsops, #endif diff --git a/stand/mips/uboot/version b/stand/mips/uboot/version index 486c4125cc0d..ec46b388b281 100644 --- a/stand/mips/uboot/version +++ b/stand/mips/uboot/version @@ -3,6 +3,7 @@ $FreeBSD$ NOTE ANY CHANGES YOU MAKE TO THE BOOTBLOCKS HERE. The format of this file is important. Make sure the current version number is on line 6. +1.3: Remove NAND FS support. 1.2: Extended with NAND FS support. 1.1: Flattened Device Tree blob support. 1.0: Added storage support. Booting from HDD, USB, etc. is now possible. diff --git a/sys/arm/conf/DB-78XXX b/sys/arm/conf/DB-78XXX index b1379dfb544f..2007405751cc 100644 --- a/sys/arm/conf/DB-78XXX +++ b/sys/arm/conf/DB-78XXX @@ -74,9 +74,6 @@ device ds133x # SATA device mvs -# NAND -device nand - # GPIO device gpio diff --git a/sys/arm/conf/DB-88F6XXX b/sys/arm/conf/DB-88F6XXX index b0c36c0b1b42..64465baf4c77 100644 --- a/sys/arm/conf/DB-88F6XXX +++ b/sys/arm/conf/DB-88F6XXX @@ -78,9 +78,6 @@ device twsi # SATA device mvs -# NAND -device nand - # GPIO device gpio diff --git a/sys/arm/conf/DREAMPLUG-1001 b/sys/arm/conf/DREAMPLUG-1001 index 8a5ce4a6d8f2..18b2dee86fac 100644 --- a/sys/arm/conf/DREAMPLUG-1001 +++ b/sys/arm/conf/DREAMPLUG-1001 @@ -157,14 +157,6 @@ options ALTQ_PRIQ # Priority Queueing options ALTQ_NOPCC # Required if the TSC is unusable #options ALTQ_DEBUG -# To use this configuration with the (rare) model 1001N (nand flash), -# create a kernel config file that looks like this: -# -# include DREAMPLUG-1001 -# nomakeoptions FDT_DTS_FILE -# makeoptions FDT_DTS_FILE=dreamplug-1001N.dts -# device nand - # Flattened Device Tree options FDT # Configure using FDT/DTB data options FDT_DTB_STATIC diff --git a/sys/arm/conf/NOTES.armv5 b/sys/arm/conf/NOTES.armv5 index c67b37ed0052..1e8825980448 100644 --- a/sys/arm/conf/NOTES.armv5 +++ b/sys/arm/conf/NOTES.armv5 @@ -31,8 +31,3 @@ options ARM_MANY_BOARD options SOC_MV_DISCOVERY options SOC_MV_KIRKWOOD options SOC_MV_ORION - -# Add devices which are specific to various arm platforms... - -device nand - diff --git a/sys/arm/conf/SHEEVAPLUG b/sys/arm/conf/SHEEVAPLUG index df44533dcd72..b24a6d80a873 100644 --- a/sys/arm/conf/SHEEVAPLUG +++ b/sys/arm/conf/SHEEVAPLUG @@ -72,9 +72,6 @@ device scbus device pass device da -# NAND -device nand - # GPIO device gpio diff --git a/sys/arm/conf/VYBRID b/sys/arm/conf/VYBRID index a35a565711a2..318a7d0e3c68 100644 --- a/sys/arm/conf/VYBRID +++ b/sys/arm/conf/VYBRID @@ -37,7 +37,6 @@ options PLATFORM # Platform based SoC #options BOOTP_WIRED_TO=ffec0 #options ROOTDEVNAME=\"nfs:10.5.0.1:/tftpboot/cosmic\" -#options ROOTDEVNAME=\"nandfs:/dev/gnand0s.root\" options ROOTDEVNAME=\"ufs:/dev/da0\" options MUTEX_NOINLINE @@ -80,8 +79,6 @@ device pass #device atadisk #device mvs -device nand - # Serial ports device uart diff --git a/sys/arm/freescale/vybrid/vf_nfc.c b/sys/arm/freescale/vybrid/vf_nfc.c deleted file mode 100644 index cdefa2564864..000000000000 --- a/sys/arm/freescale/vybrid/vf_nfc.c +++ /dev/null @@ -1,528 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2013 Ruslan Bukin - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. - */ - -/* - * Vybrid Family NAND Flash Controller (NFC) - * Chapter 31, Vybrid Reference Manual, Rev. 5, 07/2013 - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include "nfc_if.h" - -#include - -enum addr_type { - ADDR_NONE, - ADDR_ID, - ADDR_ROW, - ADDR_ROWCOL -}; - -struct fsl_nfc_fcm { - uint32_t addr_bits; - enum addr_type addr_type; - uint32_t col_addr_bits; - uint32_t row_addr_bits; - u_int read_ptr; - u_int addr_ptr; - u_int command; - u_int code; -}; - -struct vf_nand_softc { - struct nand_softc nand_dev; - bus_space_handle_t bsh; - bus_space_tag_t bst; - struct resource *res[2]; - struct fsl_nfc_fcm fcm; -}; - -static struct resource_spec nfc_spec[] = { - { SYS_RES_MEMORY, 0, RF_ACTIVE }, - { SYS_RES_IRQ, 0, RF_ACTIVE }, - { -1, 0 } -}; - -static int vf_nand_attach(device_t); -static int vf_nand_probe(device_t); -static int vf_nand_send_command(device_t, uint8_t); -static int vf_nand_send_address(device_t, uint8_t); -static int vf_nand_start_command(device_t); -static uint8_t vf_nand_read_byte(device_t); -static void vf_nand_read_buf(device_t, void *, uint32_t); -static void vf_nand_write_buf(device_t, void *, uint32_t); -static int vf_nand_select_cs(device_t, uint8_t); -static int vf_nand_read_rnb(device_t); - -#define CMD_READ_PAGE 0x7EE0 -#define CMD_PROG_PAGE 0x7FC0 -#define CMD_PROG_PAGE_DMA 0xFFC8 -#define CMD_ERASE 0x4EC0 -#define CMD_READ_ID 0x4804 -#define CMD_READ_STATUS 0x4068 -#define CMD_RESET 0x4040 -#define CMD_RANDOM_IN 0x7140 -#define CMD_RANDOM_OUT 0x70E0 - -#define CMD_BYTE2_PROG_PAGE 0x10 -#define CMD_BYTE2_PAGE_READ 0x30 -#define CMD_BYTE2_ERASE 0xD0 - -#define NFC_CMD1 0x3F00 /* Flash command 1 */ -#define NFC_CMD2 0x3F04 /* Flash command 2 */ -#define NFC_CAR 0x3F08 /* Column address */ -#define NFC_RAR 0x3F0C /* Row address */ -#define NFC_RPT 0x3F10 /* Flash command repeat */ -#define NFC_RAI 0x3F14 /* Row address increment */ -#define NFC_SR1 0x3F18 /* Flash status 1 */ -#define NFC_SR2 0x3F1C /* Flash status 2 */ -#define NFC_DMA_CH1 0x3F20 /* DMA channel 1 address */ -#define NFC_DMACFG 0x3F24 /* DMA configuration */ -#define NFC_SWAP 0x3F28 /* Cach swap */ -#define NFC_SECSZ 0x3F2C /* Sector size */ -#define NFC_CFG 0x3F30 /* Flash configuration */ -#define NFC_DMA_CH2 0x3F34 /* DMA channel 2 address */ -#define NFC_ISR 0x3F38 /* Interrupt status */ - -#define ECCMODE_SHIFT 17 -#define AIAD_SHIFT 5 -#define AIBN_SHIFT 4 -#define PAGECOUNT_SHIFT 0 -#define BITWIDTH_SHIFT 7 -#define BITWIDTH8 0 -#define BITWIDTH16 1 -#define PAGECOUNT_MASK 0xf - -#define CMD2_BYTE1_SHIFT 24 -#define CMD2_CODE_SHIFT 8 -#define CMD2_BUFNO_SHIFT 1 -#define CMD2_START_SHIFT 0 - -static device_method_t vf_nand_methods[] = { - DEVMETHOD(device_probe, vf_nand_probe), - DEVMETHOD(device_attach, vf_nand_attach), - DEVMETHOD(nfc_start_command, vf_nand_start_command), - DEVMETHOD(nfc_send_command, vf_nand_send_command), - DEVMETHOD(nfc_send_address, vf_nand_send_address), - DEVMETHOD(nfc_read_byte, vf_nand_read_byte), - DEVMETHOD(nfc_read_buf, vf_nand_read_buf), - DEVMETHOD(nfc_write_buf, vf_nand_write_buf), - DEVMETHOD(nfc_select_cs, vf_nand_select_cs), - DEVMETHOD(nfc_read_rnb, vf_nand_read_rnb), - { 0, 0 }, -}; - -static driver_t vf_nand_driver = { - "nand", - vf_nand_methods, - sizeof(struct vf_nand_softc), -}; - -static devclass_t vf_nand_devclass; -DRIVER_MODULE(vf_nand, simplebus, vf_nand_driver, vf_nand_devclass, 0, 0); - -static int -vf_nand_probe(device_t dev) -{ - - if (!ofw_bus_status_okay(dev)) - return (ENXIO); - - if (!ofw_bus_is_compatible(dev, "fsl,mvf600-nand")) - return (ENXIO); - - device_set_desc(dev, "Vybrid Family NAND controller"); - return (BUS_PROBE_DEFAULT); -} - -static int -vf_nand_attach(device_t dev) -{ - struct vf_nand_softc *sc; - int err; - int reg; - - sc = device_get_softc(dev); - if (bus_alloc_resources(dev, nfc_spec, sc->res)) { - device_printf(dev, "could not allocate resources!\n"); - return (ENXIO); - } - - sc->bst = rman_get_bustag(sc->res[0]); - sc->bsh = rman_get_bushandle(sc->res[0]); - - /* Size in bytes of one elementary transfer unit */ - WRITE4(sc, NFC_SECSZ, 2048); - - /* Flash mode width */ - reg = READ4(sc, NFC_CFG); - reg |= (BITWIDTH16 << BITWIDTH_SHIFT); - - /* No correction, ECC bypass */ - reg &= ~(0x7 << ECCMODE_SHIFT); - - /* Disable Auto-incrementing of flash row address */ - reg &= ~(0x1 << AIAD_SHIFT); - - /* Disable Auto-incrementing of buffer numbers */ - reg &= ~(0x1 << AIBN_SHIFT); - - /* - * Number of virtual pages (in one physical flash page) - * to be programmed or read, etc. - */ - reg &= ~(PAGECOUNT_MASK); - reg |= (1 << PAGECOUNT_SHIFT); - WRITE4(sc, NFC_CFG, reg); - - nand_init(&sc->nand_dev, dev, NAND_ECC_NONE, 0, 0, NULL, NULL); - err = nandbus_create(dev); - return (err); -} - -static int -vf_nand_start_command(device_t dev) -{ - struct vf_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - int reg; - - sc = device_get_softc(dev); - fcm = &sc->fcm; - - nand_debug(NDBG_DRV,"vf_nand: start command %x", fcm->command); - - /* CMD2 */ - reg = READ4(sc, NFC_CMD2); - reg &= ~(0xff << CMD2_BYTE1_SHIFT); - reg |= (fcm->command << CMD2_BYTE1_SHIFT); - WRITE4(sc, NFC_CMD2, reg); - - /* CMD1 */ - if ((fcm->command == NAND_CMD_READ) || - (fcm->command == NAND_CMD_PROG) || - (fcm->command == NAND_CMD_ERASE)) { - reg = READ4(sc, NFC_CMD1); - reg &= ~(0xff << 24); - - if (fcm->command == NAND_CMD_READ) - reg |= (CMD_BYTE2_PAGE_READ << 24); - else if (fcm->command == NAND_CMD_PROG) - reg |= (CMD_BYTE2_PROG_PAGE << 24); - else if (fcm->command == NAND_CMD_ERASE) - reg |= (CMD_BYTE2_ERASE << 24); - - WRITE4(sc, NFC_CMD1, reg); - } - - /* We work with 1st buffer */ - reg = READ4(sc, NFC_CMD2); - reg &= ~(0xf << CMD2_BUFNO_SHIFT); - reg |= (0 << CMD2_BUFNO_SHIFT); - WRITE4(sc, NFC_CMD2, reg); - - /* Cmd CODE */ - reg = READ4(sc, NFC_CMD2); - reg &= ~(0xffff << CMD2_CODE_SHIFT); - reg |= (fcm->code << CMD2_CODE_SHIFT); - WRITE4(sc, NFC_CMD2, reg); - - /* Col */ - if (fcm->addr_type == ADDR_ROWCOL) { - reg = READ4(sc, NFC_CAR); - reg &= ~(0xffff); - reg |= fcm->col_addr_bits; - nand_debug(NDBG_DRV,"setting CAR to 0x%08x\n", reg); - WRITE4(sc, NFC_CAR, reg); - } - - /* Row */ - reg = READ4(sc, NFC_RAR); - reg &= ~(0xffffff); - if (fcm->addr_type == ADDR_ID) - reg |= fcm->addr_bits; - else - reg |= fcm->row_addr_bits; - WRITE4(sc, NFC_RAR, reg); - - /* Start */ - reg = READ4(sc, NFC_CMD2); - reg |= (1 << CMD2_START_SHIFT); - WRITE4(sc, NFC_CMD2, reg); - - /* Wait command completion */ - while (READ4(sc, NFC_CMD2) & (1 << CMD2_START_SHIFT)) - ; - - return (0); -} - -static int -vf_nand_send_command(device_t dev, uint8_t command) -{ - struct vf_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - - nand_debug(NDBG_DRV,"vf_nand: send command %x", command); - - sc = device_get_softc(dev); - fcm = &sc->fcm; - - if ((command == NAND_CMD_READ_END) || - (command == NAND_CMD_PROG_END) || - (command == NAND_CMD_ERASE_END)) { - return (0); - } - - fcm->command = command; - - fcm->code = 0; - fcm->read_ptr = 0; - fcm->addr_type = 0; - fcm->addr_bits = 0; - - fcm->addr_ptr = 0; - fcm->col_addr_bits = 0; - fcm->row_addr_bits = 0; - - switch (command) { - case NAND_CMD_READ: - fcm->code = CMD_READ_PAGE; - fcm->addr_type = ADDR_ROWCOL; - break; - case NAND_CMD_PROG: - fcm->code = CMD_PROG_PAGE; - fcm->addr_type = ADDR_ROWCOL; - break; - case NAND_CMD_PROG_END: - break; - case NAND_CMD_ERASE_END: - break; - case NAND_CMD_RESET: - fcm->code = CMD_RESET; - break; - case NAND_CMD_READ_ID: - fcm->code = CMD_READ_ID; - fcm->addr_type = ADDR_ID; - break; - case NAND_CMD_READ_PARAMETER: - fcm->code = CMD_READ_PAGE; - fcm->addr_type = ADDR_ID; - break; - case NAND_CMD_STATUS: - fcm->code = CMD_READ_STATUS; - break; - case NAND_CMD_ERASE: - fcm->code = CMD_ERASE; - fcm->addr_type = ADDR_ROW; - break; - default: - nand_debug(NDBG_DRV, "unknown command %d\n", command); - return (1); - } - - return (0); -} - -static int -vf_nand_send_address(device_t dev, uint8_t addr) -{ - struct vf_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - - nand_debug(NDBG_DRV,"vf_nand: send address %x", addr); - sc = device_get_softc(dev); - fcm = &sc->fcm; - - nand_debug(NDBG_DRV, "setting addr #%d to 0x%02x\n", fcm->addr_ptr, addr); - - if (fcm->addr_type == ADDR_ID) { - fcm->addr_bits = addr; - } else if (fcm->addr_type == ADDR_ROWCOL) { - - if (fcm->addr_ptr < 2) - fcm->col_addr_bits |= (addr << (fcm->addr_ptr * 8)); - else - fcm->row_addr_bits |= (addr << ((fcm->addr_ptr - 2) * 8)); - - } else if (fcm->addr_type == ADDR_ROW) - fcm->row_addr_bits |= (addr << (fcm->addr_ptr * 8)); - - fcm->addr_ptr += 1; - - return (0); -} - -static uint8_t -vf_nand_read_byte(device_t dev) -{ - struct vf_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - uint8_t data; - int sr1, sr2; - int b; - - sc = device_get_softc(dev); - fcm = &sc->fcm; - - sr1 = READ4(sc, NFC_SR1); - sr2 = READ4(sc, NFC_SR2); - - data = 0; - if (fcm->addr_type == ADDR_ID) { - b = 32 - ((fcm->read_ptr + 1) * 8); - data = (sr1 >> b) & 0xff; - fcm->read_ptr++; - } else if (fcm->command == NAND_CMD_STATUS) { - data = sr2 & 0xff; - } - - nand_debug(NDBG_DRV,"vf_nand: read %x", data); - return (data); -} - -static void -vf_nand_read_buf(device_t dev, void* buf, uint32_t len) -{ - struct vf_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - uint16_t *tmp; - uint8_t *b; - int i; - - b = (uint8_t*)buf; - sc = device_get_softc(dev); - fcm = &sc->fcm; - - nand_debug(NDBG_DRV, "vf_nand: read_buf len %d", len); - - if (fcm->command == NAND_CMD_READ_PARAMETER) { - tmp = malloc(len, M_DEVBUF, M_NOWAIT); - bus_read_region_2(sc->res[0], 0x0, tmp, len); - - for (i = 0; i < len; i += 2) { - b[i] = tmp[i+1]; - b[i+1] = tmp[i]; - } - - free(tmp, M_DEVBUF); - -#ifdef NAND_DEBUG - for (i = 0; i < len; i++) { - if (!(i % 16)) - printf("%s", i == 0 ? "vf_nand:\n" : "\n"); - printf(" %x", b[i]); - if (i == len - 1) - printf("\n"); - } -#endif - - } else { - - for (i = 0; i < len; i++) { - b[i] = READ1(sc, i); - -#ifdef NAND_DEBUG - if (!(i % 16)) - printf("%s", i == 0 ? "vf_nand:\n" : "\n"); - printf(" %x", b[i]); - if (i == len - 1) - printf("\n"); -#endif - } - - } -} - -static void -vf_nand_write_buf(device_t dev, void* buf, uint32_t len) -{ - struct vf_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - uint8_t *b; - int i; - - b = (uint8_t*)buf; - sc = device_get_softc(dev); - fcm = &sc->fcm; - - nand_debug(NDBG_DRV,"vf_nand: write_buf len %d", len); - - for (i = 0; i < len; i++) { - WRITE1(sc, i, b[i]); - -#ifdef NAND_DEBUG - if (!(i % 16)) - printf("%s", i == 0 ? "vf_nand:\n" : "\n"); - printf(" %x", b[i]); - if (i == len - 1) - printf("\n"); -#endif - - } -} - -static int -vf_nand_select_cs(device_t dev, uint8_t cs) -{ - - if (cs > 0) - return (ENODEV); - - return (0); -} - -static int -vf_nand_read_rnb(device_t dev) -{ - - /* no-op */ - return (0); /* ready */ -} diff --git a/sys/arm/mv/files.arm7 b/sys/arm/mv/files.arm7 index d27357480cae..a6138042bc80 100644 --- a/sys/arm/mv/files.arm7 +++ b/sys/arm/mv/files.arm7 @@ -29,7 +29,6 @@ dev/iicbus/twsi/mv_twsi.c optional twsi dev/mge/if_mge.c optional mge dev/neta/if_mvneta_fdt.c optional neta fdt dev/neta/if_mvneta.c optional neta mdio mii -dev/nand/nfc_mv.c optional nand dev/mvs/mvs_soc.c optional mvs dev/uart/uart_dev_ns8250.c optional uart dev/uart/uart_dev_snps.c optional uart diff --git a/sys/arm/mv/files.mv b/sys/arm/mv/files.mv index ee027f059441..1dc45105450c 100644 --- a/sys/arm/mv/files.mv +++ b/sys/arm/mv/files.mv @@ -26,7 +26,6 @@ dev/iicbus/twsi/mv_twsi.c optional twsi dev/mge/if_mge.c optional mge dev/neta/if_mvneta_fdt.c optional neta fdt dev/neta/if_mvneta.c optional neta mdio mii -dev/nand/nfc_mv.c optional nand dev/mvs/mvs_soc.c optional mvs dev/uart/uart_dev_ns8250.c optional uart dev/uart/uart_dev_snps.c optional uart diff --git a/sys/cam/ata/ata_all.c b/sys/cam/ata/ata_all.c index 9a4cdbed071b..76d65ae5e405 100644 --- a/sys/cam/ata/ata_all.c +++ b/sys/cam/ata/ata_all.c @@ -1238,28 +1238,3 @@ ata_zac_mgmt_in(struct ccb_ataio *ataio, uint32_t retries, ataio->aux = auxiliary; } } - -void -ata_param_fixup(struct ata_params *ident_buf) -{ - int16_t *ptr; - - for (ptr = (int16_t *)ident_buf; - ptr < (int16_t *)ident_buf + sizeof(struct ata_params)/2; ptr++) { - *ptr = le16toh(*ptr); - } - if (strncmp(ident_buf->model, "FX", 2) && - strncmp(ident_buf->model, "NEC", 3) && - strncmp(ident_buf->model, "Pioneer", 7) && - strncmp(ident_buf->model, "SHARP", 5)) { - ata_bswap(ident_buf->model, sizeof(ident_buf->model)); - ata_bswap(ident_buf->revision, sizeof(ident_buf->revision)); - ata_bswap(ident_buf->serial, sizeof(ident_buf->serial)); - } - ata_btrim(ident_buf->model, sizeof(ident_buf->model)); - ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model)); - ata_btrim(ident_buf->revision, sizeof(ident_buf->revision)); - ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision)); - ata_btrim(ident_buf->serial, sizeof(ident_buf->serial)); - ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial)); -} diff --git a/sys/cam/ata/ata_all.h b/sys/cam/ata/ata_all.h index ca635253511c..087d6820f980 100644 --- a/sys/cam/ata/ata_all.h +++ b/sys/cam/ata/ata_all.h @@ -135,7 +135,6 @@ void ata_read_log(struct ccb_ataio *ataio, uint32_t retries, uint16_t block_count, uint32_t protocol, uint8_t *data_ptr, uint32_t dxfer_len, uint32_t timeout); -void ata_param_fixup(struct ata_params *ident_buf); void ata_bswap(int8_t *buf, int len); void ata_btrim(int8_t *buf, int len); void ata_bpack(int8_t *src, int8_t *dst, int len); diff --git a/sys/cam/ata/ata_xpt.c b/sys/cam/ata/ata_xpt.c index 017db8854b08..94dc435b099b 100644 --- a/sys/cam/ata/ata_xpt.c +++ b/sys/cam/ata/ata_xpt.c @@ -893,13 +893,14 @@ device_fail: if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0) case PROBE_IDENTIFY: { struct ccb_pathinq cpi; + int16_t *ptr; int veto = 0; - /* - * Convert to host byte order, and fix the strings. - */ ident_buf = &softc->ident_data; - ata_param_fixup(ident_buf); + for (ptr = (int16_t *)ident_buf; + ptr < (int16_t *)ident_buf + sizeof(struct ata_params)/2; ptr++) { + *ptr = le16toh(*ptr); + } /* * Allow others to veto this ATA disk attachment. This @@ -911,6 +912,20 @@ device_fail: if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0) goto device_fail; } + if (strncmp(ident_buf->model, "FX", 2) && + strncmp(ident_buf->model, "NEC", 3) && + strncmp(ident_buf->model, "Pioneer", 7) && + strncmp(ident_buf->model, "SHARP", 5)) { + ata_bswap(ident_buf->model, sizeof(ident_buf->model)); + ata_bswap(ident_buf->revision, sizeof(ident_buf->revision)); + ata_bswap(ident_buf->serial, sizeof(ident_buf->serial)); + } + ata_btrim(ident_buf->model, sizeof(ident_buf->model)); + ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model)); + ata_btrim(ident_buf->revision, sizeof(ident_buf->revision)); + ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision)); + ata_btrim(ident_buf->serial, sizeof(ident_buf->serial)); + ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial)); /* Device may need spin-up before IDENTIFY become valid. */ if ((ident_buf->specconf == 0x37c8 || ident_buf->specconf == 0x738c) && diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c index f2f60d35b2e2..a89c40e19a7b 100644 --- a/sys/cam/scsi/scsi_da.c +++ b/sys/cam/scsi/scsi_da.c @@ -64,9 +64,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#ifdef _KERNEL -#include -#endif /* _KERNEL */ #include #include @@ -3616,7 +3613,15 @@ dastart(struct cam_periph *periph, union ccb *start_ccb) break; } - ata_params = &periph->path->device->ident_data; + ata_params = (struct ata_params*) + malloc(sizeof(*ata_params), M_SCSIDA,M_NOWAIT|M_ZERO); + + if (ata_params == NULL) { + xpt_print(periph->path, "Couldn't malloc ata_params " + "data\n"); + /* da_free_periph??? */ + break; + } scsi_ata_identify(&start_ccb->csio, /*retries*/da_retry_count, @@ -5187,7 +5192,7 @@ dadone_probeata(struct cam_periph *periph, union ccb *done_ccb) struct da_softc *softc; u_int32_t priority; int continue_probe; - int error; + int error, i; int16_t *ptr; CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("dadone_probeata\n")); @@ -5205,7 +5210,8 @@ dadone_probeata(struct cam_periph *periph, union ccb *done_ccb) if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { uint16_t old_rate; - ata_param_fixup(ata_params); + for (i = 0; i < sizeof(*ata_params) / 2; i++) + ptr[i] = le16toh(ptr[i]); if (ata_params->support_dsm & ATA_SUPPORT_DSM_TRIM && (softc->quirks & DA_Q_NO_UNMAP) == 0) { dadeleteflag(softc, DA_DELETE_ATA_TRIM, 1); @@ -5289,6 +5295,7 @@ dadone_probeata(struct cam_periph *periph, union ccb *done_ccb) } } + free(ata_params, M_SCSIDA); if ((softc->zone_mode == DA_ZONE_HOST_AWARE) || (softc->zone_mode == DA_ZONE_HOST_MANAGED)) { /* diff --git a/sys/conf/files b/sys/conf/files index 96211a9fc623..c62a9e285e47 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1708,7 +1708,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 | fdt n25q | fdt at45d +dev/fdt/fdt_slicer.c optional fdt cfi | fdt mx25l | fdt n25q | fdt at45d dev/fdt/fdt_static_dtb.S optional fdt fdt_dtb_static \ dependency "${FDT_DTS_FILE:T:R}.dtb" dev/fdt/simplebus.c optional fdt @@ -2457,21 +2457,6 @@ dev/mxge/mxge_ethp_z8e.c optional mxge pci dev/mxge/mxge_rss_eth_z8e.c optional mxge pci dev/mxge/mxge_rss_ethp_z8e.c optional mxge pci dev/my/if_my.c optional my -dev/nand/nand.c optional nand -dev/nand/nand_bbt.c optional nand -dev/nand/nand_cdev.c optional nand -dev/nand/nand_generic.c optional nand -dev/nand/nand_geom.c optional nand -dev/nand/nand_id.c optional nand -dev/nand/nandbus.c optional nand -dev/nand/nandbus_if.m optional nand -dev/nand/nand_if.m optional nand -dev/nand/nandsim.c optional nandsim nand -dev/nand/nandsim_chip.c optional nandsim nand -dev/nand/nandsim_ctrl.c optional nandsim nand -dev/nand/nandsim_log.c optional nandsim nand -dev/nand/nandsim_swap.c optional nandsim nand -dev/nand/nfc_if.m optional nand dev/netmap/if_ptnet.c optional netmap inet dev/netmap/netmap.c optional netmap dev/netmap/netmap_bdg.c optional netmap @@ -3499,20 +3484,6 @@ fs/msdosfs/msdosfs_iconv.c optional msdosfs_iconv fs/msdosfs/msdosfs_lookup.c optional msdosfs fs/msdosfs/msdosfs_vfsops.c optional msdosfs fs/msdosfs/msdosfs_vnops.c optional msdosfs -fs/nandfs/bmap.c optional nandfs -fs/nandfs/nandfs_alloc.c optional nandfs -fs/nandfs/nandfs_bmap.c optional nandfs -fs/nandfs/nandfs_buffer.c optional nandfs -fs/nandfs/nandfs_cleaner.c optional nandfs -fs/nandfs/nandfs_cpfile.c optional nandfs -fs/nandfs/nandfs_dat.c optional nandfs -fs/nandfs/nandfs_dir.c optional nandfs -fs/nandfs/nandfs_ifile.c optional nandfs -fs/nandfs/nandfs_segment.c optional nandfs -fs/nandfs/nandfs_subr.c optional nandfs -fs/nandfs/nandfs_sufile.c optional nandfs -fs/nandfs/nandfs_vfsops.c optional nandfs -fs/nandfs/nandfs_vnops.c optional nandfs fs/nfs/nfs_commonkrpc.c optional nfscl | nfsd fs/nfs/nfs_commonsubs.c optional nfscl | nfsd fs/nfs/nfs_commonport.c optional nfscl | nfsd @@ -3600,7 +3571,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 | fdt n25q | fdt at45d +geom/geom_flashmap.c optional fdt cfi | fdt mx25l | mmcsd | fdt n25q | fdt at45d geom/geom_io.c standard geom/geom_kern.c standard geom/geom_map.c optional geom_map diff --git a/sys/conf/files.powerpc b/sys/conf/files.powerpc index ade545c59cd6..5383595b1411 100644 --- a/sys/conf/files.powerpc +++ b/sys/conf/files.powerpc @@ -43,8 +43,6 @@ dev/iicbus/max6690.c optional max6690 powermac dev/iicbus/ofw_iicbus.c optional iicbus aim dev/ipmi/ipmi.c optional ipmi dev/ipmi/ipmi_opal.c optional powernv ipmi -dev/nand/nfc_fsl.c optional nand mpc85xx -dev/nand/nfc_rb.c optional nand mpc85xx # Most ofw stuff below is brought in by conf/files for options FDT, but # we always want it, even on non-FDT platforms. dev/fdt/simplebus.c standard diff --git a/sys/conf/kern.opts.mk b/sys/conf/kern.opts.mk index 33aa0bcba989..58f125efbd06 100644 --- a/sys/conf/kern.opts.mk +++ b/sys/conf/kern.opts.mk @@ -52,7 +52,6 @@ __DEFAULT_YES_OPTIONS = \ __DEFAULT_NO_OPTIONS = \ EXTRA_TCP_STACKS \ KERNEL_RETPOLINE \ - NAND \ OFED \ RATELIMIT diff --git a/sys/dev/nand/nand.c b/sys/dev/nand/nand.c deleted file mode 100644 index 6997ef7f8a0d..000000000000 --- a/sys/dev/nand/nand.c +++ /dev/null @@ -1,826 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include "nfc_if.h" -#include "nand_if.h" -#include "nandbus_if.h" -#include - -#define NAND_RESET_DELAY 1000 /* tRST */ -#define NAND_ERASE_DELAY 3000 /* tBERS */ -#define NAND_PROG_DELAY 700 /* tPROG */ -#define NAND_READ_DELAY 50 /* tR */ - -#define BIT0(x) ((x) & 0x1) -#define BIT1(x) (BIT0(x >> 1)) -#define BIT2(x) (BIT0(x >> 2)) -#define BIT3(x) (BIT0(x >> 3)) -#define BIT4(x) (BIT0(x >> 4)) -#define BIT5(x) (BIT0(x >> 5)) -#define BIT6(x) (BIT0(x >> 6)) -#define BIT7(x) (BIT0(x >> 7)) - -#define SOFTECC_SIZE 256 -#define SOFTECC_BYTES 3 - -int nand_debug_flag = 0; -SYSCTL_INT(_debug, OID_AUTO, nand_debug, CTLFLAG_RWTUN, &nand_debug_flag, 0, - "NAND subsystem debug flag"); - -MALLOC_DEFINE(M_NAND, "NAND", "NAND dynamic data"); - -static void calculate_ecc(const uint8_t *, uint8_t *); -static int correct_ecc(uint8_t *, uint8_t *, uint8_t *); - -void -nand_debug(int level, const char *fmt, ...) -{ - va_list ap; - - if (!(nand_debug_flag & level)) - return; - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); - printf("\n"); -} - -void -nand_init(struct nand_softc *nand, device_t dev, int ecc_mode, - int ecc_bytes, int ecc_size, uint16_t *eccposition, char *cdev_name) -{ - - nand->ecc.eccmode = ecc_mode; - nand->chip_cdev_name = cdev_name; - - if (ecc_mode == NAND_ECC_SOFT) { - nand->ecc.eccbytes = SOFTECC_BYTES; - nand->ecc.eccsize = SOFTECC_SIZE; - } else if (ecc_mode != NAND_ECC_NONE) { - nand->ecc.eccbytes = ecc_bytes; - nand->ecc.eccsize = ecc_size; - if (eccposition) - nand->ecc.eccpositions = eccposition; - } -} - -void -nand_onfi_set_params(struct nand_chip *chip, struct onfi_chip_params *params) -{ - struct chip_geom *cg; - - cg = &chip->chip_geom; - - init_chip_geom(cg, params->luns, params->blocks_per_lun, - params->pages_per_block, params->bytes_per_page, - params->spare_bytes_per_page); - chip->t_bers = params->t_bers; - chip->t_prog = params->t_prog; - chip->t_r = params->t_r; - chip->t_ccs = params->t_ccs; - - if (params->features & ONFI_FEAT_16BIT) - chip->flags |= NAND_16_BIT; -} - -void -nand_set_params(struct nand_chip *chip, struct nand_params *params) -{ - struct chip_geom *cg; - uint32_t blocks_per_chip; - - cg = &chip->chip_geom; - blocks_per_chip = (params->chip_size << 20) / - (params->page_size * params->pages_per_block); - - init_chip_geom(cg, 1, blocks_per_chip, - params->pages_per_block, params->page_size, - params->oob_size); - - chip->t_bers = NAND_ERASE_DELAY; - chip->t_prog = NAND_PROG_DELAY; - chip->t_r = NAND_READ_DELAY; - chip->t_ccs = 0; - - if (params->flags & NAND_16_BIT) - chip->flags |= NAND_16_BIT; -} - -int -nand_init_stat(struct nand_chip *chip) -{ - struct block_stat *blk_stat; - struct page_stat *pg_stat; - struct chip_geom *cg; - uint32_t blks, pgs; - - cg = &chip->chip_geom; - blks = cg->blks_per_lun * cg->luns; - blk_stat = malloc(sizeof(struct block_stat) * blks, M_NAND, - M_WAITOK | M_ZERO); - if (!blk_stat) - return (ENOMEM); - - pgs = blks * cg->pgs_per_blk; - pg_stat = malloc(sizeof(struct page_stat) * pgs, M_NAND, - M_WAITOK | M_ZERO); - if (!pg_stat) { - free(blk_stat, M_NAND); - return (ENOMEM); - } - - chip->blk_stat = blk_stat; - chip->pg_stat = pg_stat; - - return (0); -} - -void -nand_destroy_stat(struct nand_chip *chip) -{ - - free(chip->pg_stat, M_NAND); - free(chip->blk_stat, M_NAND); -} - -int -init_chip_geom(struct chip_geom *cg, uint32_t luns, uint32_t blks_per_lun, - uint32_t pgs_per_blk, uint32_t pg_size, uint32_t oob_size) -{ - int shift; - - if (!cg) - return (-1); - - cg->luns = luns; - cg->blks_per_lun = blks_per_lun; - cg->blks_per_chip = blks_per_lun * luns; - cg->pgs_per_blk = pgs_per_blk; - - cg->page_size = pg_size; - cg->oob_size = oob_size; - cg->block_size = cg->page_size * cg->pgs_per_blk; - cg->chip_size = cg->block_size * cg->blks_per_chip; - - shift = fls(cg->pgs_per_blk - 1); - cg->pg_mask = (1 << shift) - 1; - cg->blk_shift = shift; - - if (cg->blks_per_lun > 0) { - shift = fls(cg->blks_per_lun - 1); - cg->blk_mask = ((1 << shift) - 1) << cg->blk_shift; - } else { - shift = 0; - cg->blk_mask = 0; - } - - cg->lun_shift = shift + cg->blk_shift; - shift = fls(cg->luns - 1); - cg->lun_mask = ((1 << shift) - 1) << cg->lun_shift; - - nand_debug(NDBG_NAND, "Masks: lun 0x%x blk 0x%x page 0x%x\n" - "Shifts: lun %d blk %d", - cg->lun_mask, cg->blk_mask, cg->pg_mask, - cg->lun_shift, cg->blk_shift); - - return (0); -} - -int -nand_row_to_blkpg(struct chip_geom *cg, uint32_t row, uint32_t *lun, - uint32_t *blk, uint32_t *pg) -{ - - if (!cg || !lun || !blk || !pg) - return (-1); - - if (row & ~(cg->lun_mask | cg->blk_mask | cg->pg_mask)) { - nand_debug(NDBG_NAND,"Address out of bounds\n"); - return (-1); - } - - *lun = (row & cg->lun_mask) >> cg->lun_shift; - *blk = (row & cg->blk_mask) >> cg->blk_shift; - *pg = (row & cg->pg_mask); - - nand_debug(NDBG_NAND,"address %x-%x-%x\n", *lun, *blk, *pg); - - return (0); -} - -int page_to_row(struct chip_geom *cg, uint32_t page, uint32_t *row) -{ - uint32_t lun, block, pg_in_blk; - - if (!cg || !row) - return (-1); - - block = page / cg->pgs_per_blk; - pg_in_blk = page % cg->pgs_per_blk; - - lun = block / cg->blks_per_lun; - block = block % cg->blks_per_lun; - - *row = (lun << cg->lun_shift) & cg->lun_mask; - *row |= ((block << cg->blk_shift) & cg->blk_mask); - *row |= (pg_in_blk & cg->pg_mask); - - return (0); -} - -int -nand_check_page_boundary(struct nand_chip *chip, uint32_t page) -{ - struct chip_geom* cg; - - cg = &chip->chip_geom; - if (page >= (cg->pgs_per_blk * cg->blks_per_lun * cg->luns)) { - nand_debug(NDBG_GEN,"%s: page number too big %#x\n", - __func__, page); - return (1); - } - - return (0); -} - -void -nand_get_chip_param(struct nand_chip *chip, struct chip_param_io *param) -{ - struct chip_geom *cg; - - cg = &chip->chip_geom; - param->page_size = cg->page_size; - param->oob_size = cg->oob_size; - - param->blocks = cg->blks_per_lun * cg->luns; - param->pages_per_block = cg->pgs_per_blk; -} - -static uint16_t * -default_software_ecc_positions(struct nand_chip *chip) -{ - /* If positions have been set already, use them. */ - if (chip->nand->ecc.eccpositions) - return (chip->nand->ecc.eccpositions); - - /* - * XXX Note that the following logic isn't really sufficient, especially - * in the ONFI case where the number of ECC bytes can be dictated by - * values in the parameters page, and that could lead to needing more - * byte positions than exist within the tables of software-ecc defaults. - */ - if (chip->chip_geom.oob_size >= 128) - return (default_software_ecc_positions_128); - if (chip->chip_geom.oob_size >= 64) - return (default_software_ecc_positions_64); - else if (chip->chip_geom.oob_size >= 16) - return (default_software_ecc_positions_16); - - return (NULL); -} - -static void -calculate_ecc(const uint8_t *buf, uint8_t *ecc) -{ - uint8_t p8, byte; - int i; - - memset(ecc, 0, 3); - - for (i = 0; i < 256; i++) { - byte = buf[i]; - ecc[0] ^= (BIT0(byte) ^ BIT2(byte) ^ BIT4(byte) ^ - BIT6(byte)) << 2; - ecc[0] ^= (BIT1(byte) ^ BIT3(byte) ^ BIT5(byte) ^ - BIT7(byte)) << 3; - ecc[0] ^= (BIT0(byte) ^ BIT1(byte) ^ BIT4(byte) ^ - BIT5(byte)) << 4; - ecc[0] ^= (BIT2(byte) ^ BIT3(byte) ^ BIT6(byte) ^ - BIT7(byte)) << 5; - ecc[0] ^= (BIT0(byte) ^ BIT1(byte) ^ BIT2(byte) ^ - BIT3(byte)) << 6; - ecc[0] ^= (BIT4(byte) ^ BIT5(byte) ^ BIT6(byte) ^ - BIT7(byte)) << 7; - - p8 = BIT0(byte) ^ BIT1(byte) ^ BIT2(byte) ^ - BIT3(byte) ^ BIT4(byte) ^ BIT5(byte) ^ BIT6(byte) ^ - BIT7(byte); - - if (p8) { - ecc[2] ^= (0x1 << BIT0(i)); - ecc[2] ^= (0x4 << BIT1(i)); - ecc[2] ^= (0x10 << BIT2(i)); - ecc[2] ^= (0x40 << BIT3(i)); - - ecc[1] ^= (0x1 << BIT4(i)); - ecc[1] ^= (0x4 << BIT5(i)); - ecc[1] ^= (0x10 << BIT6(i)); - ecc[1] ^= (0x40 << BIT7(i)); - } - } - ecc[0] = ~ecc[0]; - ecc[1] = ~ecc[1]; - ecc[2] = ~ecc[2]; - ecc[0] |= 3; -} - -static int -correct_ecc(uint8_t *buf, uint8_t *calc_ecc, uint8_t *read_ecc) -{ - uint8_t ecc0, ecc1, ecc2, onesnum, bit, byte; - uint16_t addr = 0; - - ecc0 = calc_ecc[0] ^ read_ecc[0]; - ecc1 = calc_ecc[1] ^ read_ecc[1]; - ecc2 = calc_ecc[2] ^ read_ecc[2]; - - if (!ecc0 && !ecc1 && !ecc2) - return (ECC_OK); - - addr = BIT3(ecc0) | (BIT5(ecc0) << 1) | (BIT7(ecc0) << 2); - addr |= (BIT1(ecc2) << 3) | (BIT3(ecc2) << 4) | - (BIT5(ecc2) << 5) | (BIT7(ecc2) << 6); - addr |= (BIT1(ecc1) << 7) | (BIT3(ecc1) << 8) | - (BIT5(ecc1) << 9) | (BIT7(ecc1) << 10); - - onesnum = 0; - while (ecc0 || ecc1 || ecc2) { - if (ecc0 & 1) - onesnum++; - if (ecc1 & 1) - onesnum++; - if (ecc2 & 1) - onesnum++; - - ecc0 >>= 1; - ecc1 >>= 1; - ecc2 >>= 1; - } - - if (onesnum == 11) { - /* Correctable error */ - bit = addr & 7; - byte = addr >> 3; - buf[byte] ^= (1 << bit); - return (ECC_CORRECTABLE); - } else if (onesnum == 1) { - /* ECC error */ - return (ECC_ERROR_ECC); - } else { - /* Uncorrectable error */ - return (ECC_UNCORRECTABLE); - } - - return (0); -} - -int -nand_softecc_get(device_t dev, uint8_t *buf, int pagesize, uint8_t *ecc) -{ - int steps = pagesize / SOFTECC_SIZE; - int i = 0, j = 0; - - for (; i < (steps * SOFTECC_BYTES); - i += SOFTECC_BYTES, j += SOFTECC_SIZE) { - calculate_ecc(&buf[j], &ecc[i]); - } - - return (0); -} - -int -nand_softecc_correct(device_t dev, uint8_t *buf, int pagesize, - uint8_t *readecc, uint8_t *calcecc) -{ - int steps = pagesize / SOFTECC_SIZE; - int i = 0, j = 0, ret = 0; - - for (i = 0; i < (steps * SOFTECC_BYTES); - i += SOFTECC_BYTES, j += SOFTECC_SIZE) { - ret += correct_ecc(&buf[j], &calcecc[i], &readecc[i]); - if (ret < 0) - return (ret); - } - - return (ret); -} - -static int -offset_to_page(struct chip_geom *cg, uint32_t offset) -{ - - return (offset / cg->page_size); -} - -int -nand_read_pages(struct nand_chip *chip, uint32_t offset, void *buf, - uint32_t len) -{ - struct chip_geom *cg; - struct nand_ecc_data *eccd; - struct page_stat *pg_stat; - device_t nandbus; - void *oob = NULL; - uint8_t *ptr; - uint16_t *eccpos = NULL; - uint32_t page, num, steps = 0; - int i, retval = 0, needwrite; - - nand_debug(NDBG_NAND,"%p read page %x[%x]", chip, offset, len); - cg = &chip->chip_geom; - eccd = &chip->nand->ecc; - page = offset_to_page(cg, offset); - num = len / cg->page_size; - - if (eccd->eccmode != NAND_ECC_NONE) { - steps = cg->page_size / eccd->eccsize; - eccpos = default_software_ecc_positions(chip); - oob = malloc(cg->oob_size, M_NAND, M_WAITOK); - } - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - ptr = (uint8_t *)buf; - while (num--) { - pg_stat = &(chip->pg_stat[page]); - - if (NAND_READ_PAGE(chip->dev, page, ptr, cg->page_size, 0)) { - retval = ENXIO; - break; - } - - if (eccd->eccmode != NAND_ECC_NONE) { - if (NAND_GET_ECC(chip->dev, ptr, eccd->ecccalculated, - &needwrite)) { - retval = ENXIO; - break; - } - nand_debug(NDBG_ECC,"%s: ECC calculated:", - __func__); - if (nand_debug_flag & NDBG_ECC) - for (i = 0; i < (eccd->eccbytes * steps); i++) - printf("%x ", eccd->ecccalculated[i]); - - nand_debug(NDBG_ECC,"\n"); - - if (NAND_READ_OOB(chip->dev, page, oob, cg->oob_size, - 0)) { - retval = ENXIO; - break; - } - for (i = 0; i < (eccd->eccbytes * steps); i++) - eccd->eccread[i] = ((uint8_t *)oob)[eccpos[i]]; - - nand_debug(NDBG_ECC,"%s: ECC read:", __func__); - if (nand_debug_flag & NDBG_ECC) - for (i = 0; i < (eccd->eccbytes * steps); i++) - printf("%x ", eccd->eccread[i]); - nand_debug(NDBG_ECC,"\n"); - - retval = NAND_CORRECT_ECC(chip->dev, ptr, eccd->eccread, - eccd->ecccalculated); - - nand_debug(NDBG_ECC, "NAND_CORRECT_ECC() returned %d", - retval); - - if (retval == 0) - pg_stat->ecc_stat.ecc_succeded++; - else if (retval > 0) { - pg_stat->ecc_stat.ecc_corrected += retval; - retval = ECC_CORRECTABLE; - } else { - pg_stat->ecc_stat.ecc_failed++; - break; - } - } - - pg_stat->page_read++; - page++; - ptr += cg->page_size; - } - - NANDBUS_UNLOCK(nandbus); - - if (oob) - free(oob, M_NAND); - - return (retval); -} - -int -nand_read_pages_raw(struct nand_chip *chip, uint32_t offset, void *buf, - uint32_t len) -{ - struct chip_geom *cg; - device_t nandbus; - uint8_t *ptr; - uint32_t page, num, end, begin = 0, begin_off; - int retval = 0; - - cg = &chip->chip_geom; - page = offset_to_page(cg, offset); - begin_off = offset - page * cg->page_size; - if (begin_off) { - begin = cg->page_size - begin_off; - len -= begin; - } - num = len / cg->page_size; - end = len % cg->page_size; - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - ptr = (uint8_t *)buf; - if (begin_off) { - if (NAND_READ_PAGE(chip->dev, page, ptr, begin, begin_off)) { - NANDBUS_UNLOCK(nandbus); - return (ENXIO); - } - - page++; - ptr += begin; - } - - while (num--) { - if (NAND_READ_PAGE(chip->dev, page, ptr, cg->page_size, 0)) { - NANDBUS_UNLOCK(nandbus); - return (ENXIO); - } - - page++; - ptr += cg->page_size; - } - - if (end) - if (NAND_READ_PAGE(chip->dev, page, ptr, end, 0)) { - NANDBUS_UNLOCK(nandbus); - return (ENXIO); - } - - NANDBUS_UNLOCK(nandbus); - - return (retval); -} - - -int -nand_prog_pages(struct nand_chip *chip, uint32_t offset, uint8_t *buf, - uint32_t len) -{ - struct chip_geom *cg; - struct page_stat *pg_stat; - struct nand_ecc_data *eccd; - device_t nandbus; - uint32_t page, num; - uint8_t *oob = NULL; - uint16_t *eccpos = NULL; - int steps = 0, i, needwrite, err = 0; - - nand_debug(NDBG_NAND,"%p prog page %x[%x]", chip, offset, len); - - eccd = &chip->nand->ecc; - cg = &chip->chip_geom; - page = offset_to_page(cg, offset); - num = len / cg->page_size; - - if (eccd->eccmode != NAND_ECC_NONE) { - steps = cg->page_size / eccd->eccsize; - oob = malloc(cg->oob_size, M_NAND, M_WAITOK); - eccpos = default_software_ecc_positions(chip); - } - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - while (num--) { - if (NAND_PROGRAM_PAGE(chip->dev, page, buf, cg->page_size, 0)) { - err = ENXIO; - break; - } - - if (eccd->eccmode != NAND_ECC_NONE) { - if (NAND_GET_ECC(chip->dev, buf, &eccd->ecccalculated, - &needwrite)) { - err = ENXIO; - break; - } - nand_debug(NDBG_ECC,"ECC calculated:"); - if (nand_debug_flag & NDBG_ECC) - for (i = 0; i < (eccd->eccbytes * steps); i++) - printf("%x ", eccd->ecccalculated[i]); - - nand_debug(NDBG_ECC,"\n"); - - if (needwrite) { - if (NAND_READ_OOB(chip->dev, page, oob, cg->oob_size, - 0)) { - err = ENXIO; - break; - } - - for (i = 0; i < (eccd->eccbytes * steps); i++) - oob[eccpos[i]] = eccd->ecccalculated[i]; - - if (NAND_PROGRAM_OOB(chip->dev, page, oob, - cg->oob_size, 0)) { - err = ENXIO; - break; - } - } - } - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_written++; - - page++; - buf += cg->page_size; - } - - NANDBUS_UNLOCK(nandbus); - - if (oob) - free(oob, M_NAND); - - return (err); -} - -int -nand_prog_pages_raw(struct nand_chip *chip, uint32_t offset, void *buf, - uint32_t len) -{ - struct chip_geom *cg; - device_t nandbus; - uint8_t *ptr; - uint32_t page, num, end, begin = 0, begin_off; - int retval = 0; - - cg = &chip->chip_geom; - page = offset_to_page(cg, offset); - begin_off = offset - page * cg->page_size; - if (begin_off) { - begin = cg->page_size - begin_off; - len -= begin; - } - num = len / cg->page_size; - end = len % cg->page_size; - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - ptr = (uint8_t *)buf; - if (begin_off) { - if (NAND_PROGRAM_PAGE(chip->dev, page, ptr, begin, begin_off)) { - NANDBUS_UNLOCK(nandbus); - return (ENXIO); - } - - page++; - ptr += begin; - } - - while (num--) { - if (NAND_PROGRAM_PAGE(chip->dev, page, ptr, cg->page_size, 0)) { - NANDBUS_UNLOCK(nandbus); - return (ENXIO); - } - - page++; - ptr += cg->page_size; - } - - if (end) - retval = NAND_PROGRAM_PAGE(chip->dev, page, ptr, end, 0); - - NANDBUS_UNLOCK(nandbus); - - return (retval); -} - -int -nand_read_oob(struct nand_chip *chip, uint32_t page, void *buf, - uint32_t len) -{ - device_t nandbus; - int retval = 0; - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - retval = NAND_READ_OOB(chip->dev, page, buf, len, 0); - - NANDBUS_UNLOCK(nandbus); - - return (retval); -} - - -int -nand_prog_oob(struct nand_chip *chip, uint32_t page, void *buf, - uint32_t len) -{ - device_t nandbus; - int retval = 0; - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - retval = NAND_PROGRAM_OOB(chip->dev, page, buf, len, 0); - - NANDBUS_UNLOCK(nandbus); - - return (retval); -} - -int -nand_erase_blocks(struct nand_chip *chip, off_t offset, size_t len) -{ - device_t nandbus; - struct chip_geom *cg; - uint32_t block, num_blocks; - int err = 0; - - cg = &chip->chip_geom; - if ((offset % cg->block_size) || (len % cg->block_size)) - return (EINVAL); - - block = offset / cg->block_size; - num_blocks = len / cg->block_size; - nand_debug(NDBG_NAND,"%p erase blocks %d[%d]", chip, block, num_blocks); - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - while (num_blocks--) { - if (!nand_check_bad_block(chip, block)) { - if (NAND_ERASE_BLOCK(chip->dev, block)) { - nand_debug(NDBG_NAND,"%p erase blocks %d error", - chip, block); - nand_mark_bad_block(chip, block); - err = ENXIO; - } - } else - err = ENXIO; - - block++; - } - - NANDBUS_UNLOCK(nandbus); - - if (err) - nand_update_bbt(chip); - - return (err); -} - -MODULE_VERSION(nand, 1); diff --git a/sys/dev/nand/nand.h b/sys/dev/nand/nand.h deleted file mode 100644 index 06902601b8d0..000000000000 --- a/sys/dev/nand/nand.h +++ /dev/null @@ -1,415 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$ - */ - -#ifndef _DEV_NAND_H_ -#define _DEV_NAND_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -MALLOC_DECLARE(M_NAND); - -/* Read commands */ -#define NAND_CMD_READ 0x00 -#define NAND_CMD_CHNG_READ_COL 0x05 -#define NAND_CMD_READ_END 0x30 -#define NAND_CMD_READ_CACHE 0x31 -#define NAND_CMD_READ_CPBK 0x35 -#define NAND_CMD_READ_CACHE_END 0x3F -#define NAND_CMD_CHNG_READ_COL_END 0xE0 - -/* Erase commands */ -#define NAND_CMD_ERASE 0x60 -#define NAND_CMD_ERASE_END 0xD0 -#define NAND_CMD_ERASE_INTLV 0xD1 - -/* Program commands */ -#define NAND_CMD_PROG 0x80 -#define NAND_CMD_CHNG_WRITE_COL 0x85 -#define NAND_CMD_PROG_END 0x10 -#define NAND_CMD_PROG_INTLV 0x11 -#define NAND_CMD_PROG_CACHE 0x15 - -/* Misc commands */ -#define NAND_CMD_STATUS 0x70 -#define NAND_CMD_STATUS_ENH 0x78 -#define NAND_CMD_READ_ID 0x90 -#define NAND_CMD_READ_PARAMETER 0xec -#define NAND_CMD_READ_UNIQUE_ID 0xed -#define NAND_CMD_GET_FEATURE 0xee -#define NAND_CMD_SET_FEATURE 0xef - -/* Reset commands */ -#define NAND_CMD_SYNCH_RESET 0xfc -#define NAND_CMD_RESET 0xff - -/* Small page flash commands */ -#define NAND_CMD_SMALLA 0x00 -#define NAND_CMD_SMALLB 0x01 -#define NAND_CMD_SMALLOOB 0x50 - -#define NAND_STATUS_FAIL 0x1 -#define NAND_STATUS_FAILC 0x2 -#define NAND_STATUS_ARDY 0x20 -#define NAND_STATUS_RDY 0x40 -#define NAND_STATUS_WP 0x80 - -#define NAND_LP_OOB_COLUMN_START 0x800 -#define NAND_LP_OOBSZ 0x40 -#define NAND_SP_OOB_COLUMN_START 0x200 -#define NAND_SP_OOBSZ 0x10 - -#define PAGE_PARAM_LENGTH 0x100 -#define PAGE_PARAMETER_DEF 0x0 -#define PAGE_PARAMETER_RED_1 0x100 -#define PAGE_PARAMETER_RED_2 0x200 - -#define ONFI_SIG_ADDR 0x20 - -#define NAND_MAX_CHIPS 0x4 -#define NAND_MAX_OOBSZ 512 -#define NAND_MAX_PAGESZ 16384 - -#define NAND_SMALL_PAGE_SIZE 0x200 - -#define NAND_16_BIT 0x00000001 - -#define NAND_ECC_NONE 0x0 -#define NAND_ECC_SOFT 0x1 -#define NAND_ECC_FULLHW 0x2 -#define NAND_ECC_PARTHW 0x4 -#define NAND_ECC_MODE_MASK 0x7 - -#define ECC_OK 0 -#define ECC_CORRECTABLE 1 -#define ECC_ERROR_ECC (-1) -#define ECC_UNCORRECTABLE (-2) - -#define NAND_MAN_SAMSUNG 0xec -#define NAND_MAN_HYNIX 0xad -#define NAND_MAN_STMICRO 0x20 -#define NAND_MAN_MICRON 0x2c - -struct nand_id { - uint8_t man_id; - uint8_t dev_id; -}; - -struct nand_params { - struct nand_id id; - char *name; - uint32_t chip_size; - uint32_t page_size; - uint32_t oob_size; - uint32_t pages_per_block; - uint32_t flags; -}; - -/* nand debug levels */ -#define NDBG_NAND 0x01 -#define NDBG_CDEV 0x02 -#define NDBG_GEN 0x04 -#define NDBG_GEOM 0x08 -#define NDBG_BUS 0x10 -#define NDBG_SIM 0x20 -#define NDBG_CTRL 0x40 -#define NDBG_DRV 0x80 -#define NDBG_ECC 0x100 - -/* nand_debug_function */ -void nand_debug(int level, const char *fmt, ...); -extern int nand_debug_flag; - -/* ONFI features bit*/ -#define ONFI_FEAT_16BIT 0x01 -#define ONFI_FEAT_MULT_LUN 0x02 -#define ONFI_FEAT_INTLV_OPS 0x04 -#define ONFI_FEAT_CPBK_RESTRICT 0x08 -#define ONFI_FEAT_SRC_SYNCH 0x10 - -/* ONFI optional commands bits */ -#define ONFI_OPTCOM_PROG_CACHE 0x01 -#define ONFI_OPTCOM_READ_CACHE 0x02 -#define ONFI_OPTCOM_GETSET_FEAT 0x04 -#define ONFI_OPTCOM_STATUS_ENH 0x08 -#define ONFI_OPTCOM_COPYBACK 0x10 -#define ONFI_OPTCOM_UNIQUE_ID 0x20 - - -/* Layout of parameter page is defined in ONFI */ -struct onfi_params { - char signature[4]; - uint16_t rev; - uint16_t features; - uint16_t optional_commands; - uint8_t primary_advanced_command; - uint8_t res1; - uint16_t extended_parameter_page_length; - uint8_t parameter_page_count; - uint8_t res2[17]; - char manufacturer_name[12]; - char device_model[20]; - uint8_t manufacturer_id; - uint8_t manufacture_date_yy; - uint8_t manufacture_date_ww; - uint8_t res3[13]; - uint32_t bytes_per_page; - uint16_t spare_bytes_per_page; - uint32_t bytes_per_partial_page; - uint16_t spare_bytes_per_partial_page; - uint32_t pages_per_block; - uint32_t blocks_per_lun; - uint8_t luns; - uint8_t address_cycles; - uint8_t bits_per_cell; - uint16_t max_bad_block_per_lun; - uint16_t block_endurance; - uint8_t guaranteed_valid_blocks; - uint16_t valid_block_endurance; - uint8_t programs_per_page; - uint8_t partial_prog_attr; - uint8_t bits_of_ecc; - uint8_t interleaved_addr_bits; - uint8_t interleaved_oper_attr; - uint8_t eznand_support; - uint8_t res4[12]; - uint8_t pin_capacitance; - uint16_t asynch_timing_mode_support; - uint16_t asynch_prog_cache_timing_mode_support; - uint16_t t_prog; /* us, max page program time */ - uint16_t t_bers; /* us, max block erase time */ - uint16_t t_r; /* us, max page read time */ - uint16_t t_ccs; /* ns, min change column setup time */ - uint16_t source_synch_timing_mode_support; - uint8_t source_synch_feat; - uint16_t clk_input_capacitance; - uint16_t io_capacitance; - uint16_t input_capacitance; - uint8_t input_capacitance_max; - uint8_t driver_strength_support; - uint16_t t_r_interleaved; - uint16_t t_adl; - uint16_t t_r_eznand; - uint8_t nv_ddr2_features; - uint8_t nv_ddr2_warmup_cycles; - uint8_t res5[4]; - uint16_t vendor_rev; - uint8_t vendor_spec[88]; - uint16_t crc; -}__attribute__((packed)); -CTASSERT(sizeof(struct onfi_params) == 256); - -struct onfi_chip_params { - uint32_t blocks_per_lun; - uint32_t pages_per_block; - uint32_t bytes_per_page; - uint32_t spare_bytes_per_page; - uint16_t t_bers; - uint16_t t_prog; - uint16_t t_r; - uint16_t t_ccs; - uint16_t features; - uint8_t address_cycles; - uint8_t luns; -}; - -struct nand_ecc_data { - int eccsize; /* Number of data bytes per ECC step */ - int eccmode; - int eccbytes; /* Number of ECC bytes per step */ - - uint16_t *eccpositions; /* Positions of ecc bytes */ - uint8_t ecccalculated[NAND_MAX_OOBSZ]; - uint8_t eccread[NAND_MAX_OOBSZ]; -}; - -struct ecc_stat { - uint32_t ecc_succeded; - uint32_t ecc_corrected; - uint32_t ecc_failed; -}; - -struct page_stat { - struct ecc_stat ecc_stat; - uint32_t page_read; - uint32_t page_raw_read; - uint32_t page_written; - uint32_t page_raw_written; -}; - -struct block_stat { - uint32_t block_erased; -}; - -struct chip_geom { - uint32_t chip_size; - uint32_t block_size; - uint32_t page_size; - uint32_t oob_size; - - uint32_t luns; - uint32_t blks_per_lun; - uint32_t blks_per_chip; - uint32_t pgs_per_blk; - - uint32_t pg_mask; - uint32_t blk_mask; - uint32_t lun_mask; - uint8_t blk_shift; - uint8_t lun_shift; -}; - -struct nand_chip { - device_t dev; - struct nand_id id; - struct chip_geom chip_geom; - - uint16_t t_prog; /* us, max page program time */ - uint16_t t_bers; /* us, max block erase time */ - uint16_t t_r; /* us, max page read time */ - uint16_t t_ccs; /* ns, min change column setup time */ - uint8_t num; - uint8_t flags; - - struct page_stat *pg_stat; - struct block_stat *blk_stat; - struct nand_softc *nand; - struct nand_bbt *bbt; - struct nand_ops *ops; - struct cdev *cdev; - - struct disk *ndisk; - struct disk *rdisk; - struct bio_queue_head bioq; /* bio queue */ - struct mtx qlock; /* bioq lock */ - struct taskqueue *tq; /* private task queue for i/o request */ - struct task iotask; /* i/o processing */ - -}; - -struct nand_softc { - uint8_t flags; - - char *chip_cdev_name; - struct nand_ecc_data ecc; -}; - -/* NAND ops */ -int nand_erase_blocks(struct nand_chip *chip, off_t offset, size_t len); -int nand_prog_pages(struct nand_chip *chip, uint32_t offset, uint8_t *buf, - uint32_t len); -int nand_read_pages(struct nand_chip *chip, uint32_t offset, void *buf, - uint32_t len); -int nand_read_pages_raw(struct nand_chip *chip, uint32_t offset, void *buf, - uint32_t len); -int nand_prog_pages_raw(struct nand_chip *chip, uint32_t offset, void *buf, - uint32_t len); -int nand_read_oob(struct nand_chip *chip, uint32_t page, void *buf, - uint32_t len); -int nand_prog_oob(struct nand_chip *chip, uint32_t page, void *buf, - uint32_t len); - -int nand_select_cs(device_t dev, uint8_t cs); - -int nand_read_parameter(struct nand_softc *nand, struct onfi_params *param); -int nand_synch_reset(struct nand_softc *nand); -int nand_chng_read_col(device_t dev, uint32_t col, void *buf, size_t len); -int nand_chng_write_col(device_t dev, uint32_t col, void *buf, size_t len); -int nand_get_feature(device_t dev, uint8_t feat, void* buf); -int nand_set_feature(device_t dev, uint8_t feat, void* buf); - - -int nand_erase_block_intlv(device_t dev, uint32_t block); -int nand_copyback_read(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len); -int nand_copyback_prog(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len); -int nand_copyback_prog_intlv(device_t dev, uint32_t page); -int nand_prog_cache(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len, uint8_t end); -int nand_prog_intlv(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len); -int nand_read_cache(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len, uint8_t end); - -int nand_write_ecc(struct nand_softc *nand, uint32_t page, uint8_t *data); -int nand_read_ecc(struct nand_softc *nand, uint32_t page, uint8_t *data); - -int nand_softecc_get(device_t dev, uint8_t *buf, int pagesize, uint8_t *ecc); -int nand_softecc_correct(device_t dev, uint8_t *buf, int pagesize, - uint8_t *readecc, uint8_t *calcecc); - -/* Chip initialization */ -void nand_init(struct nand_softc *nand, device_t dev, int ecc_mode, - int ecc_bytes, int ecc_size, uint16_t* eccposition, char* cdev_name); -void nand_detach(struct nand_softc *nand); -struct nand_params *nand_get_params(struct nand_id *id); - -void nand_onfi_set_params(struct nand_chip *chip, struct onfi_chip_params *params); -void nand_set_params(struct nand_chip *chip, struct nand_params *params); -int nand_init_stat(struct nand_chip *chip); -void nand_destroy_stat(struct nand_chip *chip); - -/* BBT */ -int nand_init_bbt(struct nand_chip *chip); -void nand_destroy_bbt(struct nand_chip *chip); -int nand_update_bbt(struct nand_chip *chip); -int nand_mark_bad_block(struct nand_chip* chip, uint32_t block_num); -int nand_check_bad_block(struct nand_chip* chip, uint32_t block_num); - -/* cdev creation/removal */ -int nand_make_dev(struct nand_chip* chip); -void nand_destroy_dev(struct nand_chip *chip); - -int create_geom_disk(struct nand_chip* chip); -int create_geom_raw_disk(struct nand_chip *chip); -void destroy_geom_disk(struct nand_chip *chip); -void destroy_geom_raw_disk(struct nand_chip *chip); - -int init_chip_geom(struct chip_geom* cg, uint32_t luns, uint32_t blks_per_lun, - uint32_t pgs_per_blk, uint32_t pg_size, uint32_t oob_size); -int nand_row_to_blkpg(struct chip_geom *cg, uint32_t row, uint32_t *lun, - uint32_t *blk, uint32_t *pg); -int page_to_row(struct chip_geom *cg, uint32_t page, uint32_t *row); -int nand_check_page_boundary(struct nand_chip *chip, uint32_t page); -void nand_get_chip_param(struct nand_chip *chip, struct chip_param_io *param); - -#endif /* _DEV_NAND_H_ */ diff --git a/sys/dev/nand/nand_bbt.c b/sys/dev/nand/nand_bbt.c deleted file mode 100644 index d99ed67523a2..000000000000 --- a/sys/dev/nand/nand_bbt.c +++ /dev/null @@ -1,275 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2009-2012 Semihalf - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$ - */ - -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include "nand_if.h" - -#define BBT_PRIMARY_PATTERN 0x01020304 -#define BBT_SECONDARY_PATTERN 0x05060708 - -enum bbt_place { - BBT_NONE, - BBT_PRIMARY, - BBT_SECONDARY -}; - -struct nand_bbt { - struct nand_chip *chip; - uint32_t primary_map; - uint32_t secondary_map; - enum bbt_place active; - struct bbt_header *hdr; - uint32_t tab_len; - uint32_t *table; -}; - -struct bbt_header { - uint32_t pattern; - int32_t seq_nr; -}; - -static int nand_bbt_save(struct nand_bbt *); -static int nand_bbt_load_hdr(struct nand_bbt *, struct bbt_header *, int8_t); -static int nand_bbt_load_table(struct nand_bbt *); -static int nand_bbt_prescan(struct nand_bbt *); - -int -nand_init_bbt(struct nand_chip *chip) -{ - struct chip_geom *cg; - struct nand_bbt *bbt; - int err; - - cg = &chip->chip_geom; - - bbt = malloc(sizeof(struct nand_bbt), M_NAND, M_ZERO | M_WAITOK); - if (!bbt) { - device_printf(chip->dev, - "Cannot allocate memory for bad block struct"); - return (ENOMEM); - } - - bbt->chip = chip; - bbt->active = BBT_NONE; - bbt->primary_map = cg->chip_size - cg->block_size; - bbt->secondary_map = cg->chip_size - 2 * cg->block_size; - bbt->tab_len = cg->blks_per_chip * sizeof(uint32_t); - bbt->hdr = malloc(sizeof(struct bbt_header) + bbt->tab_len, M_NAND, - M_WAITOK); - if (!bbt->hdr) { - device_printf(chip->dev, "Cannot allocate %d bytes for BB " - "Table", bbt->tab_len); - free(bbt, M_NAND); - return (ENOMEM); - } - bbt->hdr->seq_nr = 0; - bbt->table = (uint32_t *)((uint8_t *)bbt->hdr + - sizeof(struct bbt_header)); - - err = nand_bbt_load_table(bbt); - if (err) { - free(bbt->table, M_NAND); - free(bbt, M_NAND); - return (err); - } - - chip->bbt = bbt; - if (bbt->active == BBT_NONE) { - bbt->active = BBT_PRIMARY; - memset(bbt->table, 0xff, bbt->tab_len); - nand_bbt_prescan(bbt); - nand_bbt_save(bbt); - } else - device_printf(chip->dev, "Found BBT table for chip\n"); - - return (0); -} - -void -nand_destroy_bbt(struct nand_chip *chip) -{ - - if (chip->bbt) { - nand_bbt_save(chip->bbt); - - free(chip->bbt->hdr, M_NAND); - free(chip->bbt, M_NAND); - chip->bbt = NULL; - } -} - -int -nand_update_bbt(struct nand_chip *chip) -{ - - nand_bbt_save(chip->bbt); - - return (0); -} - -static int -nand_bbt_save(struct nand_bbt *bbt) -{ - enum bbt_place next; - uint32_t addr; - int32_t err; - - if (bbt->active == BBT_PRIMARY) { - addr = bbt->secondary_map; - bbt->hdr->pattern = BBT_SECONDARY_PATTERN; - next = BBT_SECONDARY; - } else { - addr = bbt->primary_map; - bbt->hdr->pattern = BBT_PRIMARY_PATTERN; - next = BBT_PRIMARY; - } - - err = nand_erase_blocks(bbt->chip, addr, - bbt->chip->chip_geom.block_size); - if (err) - return (err); - - bbt->hdr->seq_nr++; - - err = nand_prog_pages_raw(bbt->chip, addr, bbt->hdr, - bbt->tab_len + sizeof(struct bbt_header)); - if (err) - return (err); - - bbt->active = next; - return (0); -} - -static int -nand_bbt_load_hdr(struct nand_bbt *bbt, struct bbt_header *hdr, int8_t primary) -{ - uint32_t addr; - - if (primary) - addr = bbt->primary_map; - else - addr = bbt->secondary_map; - - return (nand_read_pages_raw(bbt->chip, addr, hdr, - sizeof(struct bbt_header))); -} - -static int -nand_bbt_load_table(struct nand_bbt *bbt) -{ - struct bbt_header hdr1, hdr2; - uint32_t address = 0; - int err = 0; - - bzero(&hdr1, sizeof(hdr1)); - bzero(&hdr2, sizeof(hdr2)); - - nand_bbt_load_hdr(bbt, &hdr1, 1); - if (hdr1.pattern == BBT_PRIMARY_PATTERN) { - bbt->active = BBT_PRIMARY; - address = bbt->primary_map; - } else - bzero(&hdr1, sizeof(hdr1)); - - - nand_bbt_load_hdr(bbt, &hdr2, 0); - if ((hdr2.pattern == BBT_SECONDARY_PATTERN) && - (hdr2.seq_nr > hdr1.seq_nr)) { - bbt->active = BBT_SECONDARY; - address = bbt->secondary_map; - } else - bzero(&hdr2, sizeof(hdr2)); - - if (bbt->active != BBT_NONE) - err = nand_read_pages_raw(bbt->chip, address, bbt->hdr, - bbt->tab_len + sizeof(struct bbt_header)); - - return (err); -} - -static int -nand_bbt_prescan(struct nand_bbt *bbt) -{ - int32_t i; - uint8_t bad; - bool printed_hash = 0; - - device_printf(bbt->chip->dev, "No BBT found. Prescan chip...\n"); - for (i = 0; i < bbt->chip->chip_geom.blks_per_chip; i++) { - if (NAND_IS_BLK_BAD(bbt->chip->dev, i, &bad)) - return (ENXIO); - - if (bad) { - device_printf(bbt->chip->dev, "Bad block(%d)\n", i); - bbt->table[i] = 0x0FFFFFFF; - } - if (!(i % 100)) { - printf("#"); - printed_hash = 1; - } - } - - if (printed_hash) - printf("\n"); - - return (0); -} - -int -nand_check_bad_block(struct nand_chip *chip, uint32_t block_number) -{ - - if (!chip || !chip->bbt) - return (0); - - if ((chip->bbt->table[block_number] & 0xF0000000) == 0) - return (1); - - return (0); -} - -int -nand_mark_bad_block(struct nand_chip *chip, uint32_t block_number) -{ - - chip->bbt->table[block_number] = 0x0FFFFFFF; - - return (0); -} diff --git a/sys/dev/nand/nand_cdev.c b/sys/dev/nand/nand_cdev.c deleted file mode 100644 index 53c62dbc2913..000000000000 --- a/sys/dev/nand/nand_cdev.c +++ /dev/null @@ -1,454 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include "nand_if.h" -#include "nandbus_if.h" - -static int nand_page_stat(struct nand_chip *, struct page_stat_io *); -static int nand_block_stat(struct nand_chip *, struct block_stat_io *); - -static d_ioctl_t nand_ioctl; -static d_open_t nand_open; -static d_strategy_t nand_strategy; - -static struct cdevsw nand_cdevsw = { - .d_version = D_VERSION, - .d_name = "nand", - .d_open = nand_open, - .d_read = physread, - .d_write = physwrite, - .d_ioctl = nand_ioctl, - .d_strategy = nand_strategy, -}; - -static int -offset_to_page(struct chip_geom *cg, uint32_t offset) -{ - - return (offset / cg->page_size); -} - -static int -offset_to_page_off(struct chip_geom *cg, uint32_t offset) -{ - - return (offset % cg->page_size); -} - -int -nand_make_dev(struct nand_chip *chip) -{ - struct nandbus_ivar *ivar; - device_t parent, nandbus; - int parent_unit, unit; - char *name; - - ivar = device_get_ivars(chip->dev); - nandbus = device_get_parent(chip->dev); - - if (ivar->chip_cdev_name) { - name = ivar->chip_cdev_name; - - /* - * If we got distinct name for chip device we can enumarete it - * based on contoller number. - */ - parent = device_get_parent(nandbus); - } else { - name = "nand"; - parent = nandbus; - } - - parent_unit = device_get_unit(parent); - unit = parent_unit * 4 + chip->num; - chip->cdev = make_dev(&nand_cdevsw, unit, UID_ROOT, GID_WHEEL, - 0666, "%s%d.%d", name, parent_unit, chip->num); - - if (chip->cdev == NULL) - return (ENXIO); - - if (bootverbose) - device_printf(chip->dev, "Created cdev %s%d.%d for chip " - "[0x%0x, 0x%0x]\n", name, parent_unit, chip->num, - ivar->man_id, ivar->dev_id); - - chip->cdev->si_drv1 = chip; - - return (0); -} - -void -nand_destroy_dev(struct nand_chip *chip) -{ - - if (chip->cdev) - destroy_dev(chip->cdev); -} - -static int -nand_open(struct cdev *dev, int oflags, int devtype, struct thread *td) -{ - - return (0); -} - -static int -nand_read(struct nand_chip *chip, uint32_t offset, void *buf, uint32_t len) -{ - struct chip_geom *cg; - device_t nandbus; - int start_page, count, off, err = 0; - uint8_t *ptr, *tmp; - - nand_debug(NDBG_CDEV, "Read from chip%d [%p] at %d\n", chip->num, - chip, offset); - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - cg = &chip->chip_geom; - start_page = offset_to_page(cg, offset); - off = offset_to_page_off(cg, offset); - count = (len > cg->page_size - off) ? cg->page_size - off : len; - - ptr = (uint8_t *)buf; - while (len > 0) { - if (len < cg->page_size) { - tmp = malloc(cg->page_size, M_NAND, M_WAITOK); - if (!tmp) { - err = ENOMEM; - break; - } - err = NAND_READ_PAGE(chip->dev, start_page, - tmp, cg->page_size, 0); - if (err) { - free(tmp, M_NAND); - break; - } - bcopy(tmp + off, ptr, count); - free(tmp, M_NAND); - } else { - err = NAND_READ_PAGE(chip->dev, start_page, - ptr, cg->page_size, 0); - if (err) - break; - } - - len -= count; - start_page++; - ptr += count; - count = (len > cg->page_size) ? cg->page_size : len; - off = 0; - } - - NANDBUS_UNLOCK(nandbus); - return (err); -} - -static int -nand_write(struct nand_chip *chip, uint32_t offset, void* buf, uint32_t len) -{ - struct chip_geom *cg; - device_t nandbus; - int off, start_page, err = 0; - uint8_t *ptr; - - nand_debug(NDBG_CDEV, "Write to chip %d [%p] at %d\n", chip->num, - chip, offset); - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - cg = &chip->chip_geom; - start_page = offset_to_page(cg, offset); - off = offset_to_page_off(cg, offset); - - if (off != 0 || (len % cg->page_size) != 0) { - printf("Not aligned write start [0x%08x] size [0x%08x]\n", - off, len); - NANDBUS_UNLOCK(nandbus); - return (EINVAL); - } - - ptr = (uint8_t *)buf; - while (len > 0) { - err = NAND_PROGRAM_PAGE(chip->dev, start_page, ptr, - cg->page_size, 0); - if (err) - break; - - len -= cg->page_size; - start_page++; - ptr += cg->page_size; - } - - NANDBUS_UNLOCK(nandbus); - return (err); -} - -static void -nand_strategy(struct bio *bp) -{ - struct nand_chip *chip; - struct cdev *dev; - int err = 0; - - dev = bp->bio_dev; - chip = dev->si_drv1; - - nand_debug(NDBG_CDEV, "Strategy %s on chip %d [%p]\n", - bp->bio_cmd == BIO_READ ? "READ" : "WRITE", - chip->num, chip); - - if (bp->bio_cmd == BIO_READ) { - err = nand_read(chip, - bp->bio_offset & 0xffffffff, - bp->bio_data, bp->bio_bcount); - } else { - err = nand_write(chip, - bp->bio_offset & 0xffffffff, - bp->bio_data, bp->bio_bcount); - } - - if (err == 0) - bp->bio_resid = 0; - else { - bp->bio_error = EIO; - bp->bio_flags |= BIO_ERROR; - bp->bio_resid = bp->bio_bcount; - } - - biodone(bp); -} - -static int -nand_oob_access(struct nand_chip *chip, uint32_t page, uint32_t offset, - uint32_t len, uint8_t *data, uint8_t write) -{ - struct chip_geom *cg; - uint8_t *buf = NULL; - int ret = 0; - - cg = &chip->chip_geom; - - buf = malloc(cg->oob_size, M_NAND, M_WAITOK); - if (!buf) - return (ENOMEM); - - memset(buf, 0xff, cg->oob_size); - - if (!write) { - ret = nand_read_oob(chip, page, buf, cg->oob_size); - copyout(buf, data, len); - } else { - copyin(data, buf, len); - ret = nand_prog_oob(chip, page, buf, cg->oob_size); - } - - free(buf, M_NAND); - - return (ret); -} - -static int -nand_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, - struct thread *td) -{ - struct nand_chip *chip; - struct chip_geom *cg; - struct nand_oob_rw *oob_rw = NULL; - struct nand_raw_rw *raw_rw = NULL; - device_t nandbus; - size_t bufsize = 0, len = 0; - size_t raw_size; - off_t off; - uint8_t *buf = NULL; - int ret = 0; - uint8_t status; - - chip = (struct nand_chip *)dev->si_drv1; - cg = &chip->chip_geom; - nandbus = device_get_parent(chip->dev); - - if ((cmd == NAND_IO_RAW_READ) || (cmd == NAND_IO_RAW_PROG)) { - raw_rw = (struct nand_raw_rw *)data; - raw_size = cg->pgs_per_blk * (cg->page_size + cg->oob_size); - - /* Check if len is not bigger than chip size */ - if (raw_rw->len > raw_size) - return (EFBIG); - - /* - * Do not ask for too much memory, in case of large transfers - * read/write in 16-pages chunks - */ - bufsize = 16 * (cg->page_size + cg->oob_size); - if (raw_rw->len < bufsize) - bufsize = raw_rw->len; - - buf = malloc(bufsize, M_NAND, M_WAITOK); - len = raw_rw->len; - off = 0; - } - switch(cmd) { - case NAND_IO_ERASE: - ret = nand_erase_blocks(chip, ((off_t *)data)[0], - ((off_t *)data)[1]); - break; - - case NAND_IO_OOB_READ: - oob_rw = (struct nand_oob_rw *)data; - ret = nand_oob_access(chip, oob_rw->page, 0, - oob_rw->len, oob_rw->data, 0); - break; - - case NAND_IO_OOB_PROG: - oob_rw = (struct nand_oob_rw *)data; - ret = nand_oob_access(chip, oob_rw->page, 0, - oob_rw->len, oob_rw->data, 1); - break; - - case NAND_IO_GET_STATUS: - NANDBUS_LOCK(nandbus); - ret = NANDBUS_GET_STATUS(nandbus, &status); - if (ret == 0) - *(uint8_t *)data = status; - NANDBUS_UNLOCK(nandbus); - break; - - case NAND_IO_RAW_PROG: - while (len > 0) { - if (len < bufsize) - bufsize = len; - ret = copyin(raw_rw->data + off, buf, bufsize); - if (ret) - break; - ret = nand_prog_pages_raw(chip, raw_rw->off + off, buf, - bufsize); - if (ret) - break; - len -= bufsize; - off += bufsize; - } - break; - - case NAND_IO_RAW_READ: - while (len > 0) { - if (len < bufsize) - bufsize = len; - - ret = nand_read_pages_raw(chip, raw_rw->off + off, buf, - bufsize); - if (ret) - break; - - ret = copyout(buf, raw_rw->data + off, bufsize); - if (ret) - break; - len -= bufsize; - off += bufsize; - } - break; - - case NAND_IO_PAGE_STAT: - ret = nand_page_stat(chip, (struct page_stat_io *)data); - break; - - case NAND_IO_BLOCK_STAT: - ret = nand_block_stat(chip, (struct block_stat_io *)data); - break; - - case NAND_IO_GET_CHIP_PARAM: - nand_get_chip_param(chip, (struct chip_param_io *)data); - break; - - default: - printf("Unknown nand_ioctl request \n"); - ret = EIO; - } - - if (buf) - free(buf, M_NAND); - - return (ret); -} - -static int -nand_page_stat(struct nand_chip *chip, struct page_stat_io *page_stat) -{ - struct chip_geom *cg; - struct page_stat *stat; - int num_pages; - - cg = &chip->chip_geom; - num_pages = cg->pgs_per_blk * cg->blks_per_lun * cg->luns; - if (page_stat->page_num >= num_pages) - return (EINVAL); - - stat = &chip->pg_stat[page_stat->page_num]; - page_stat->page_read = stat->page_read; - page_stat->page_written = stat->page_written; - page_stat->page_raw_read = stat->page_raw_read; - page_stat->page_raw_written = stat->page_raw_written; - page_stat->ecc_succeded = stat->ecc_stat.ecc_succeded; - page_stat->ecc_corrected = stat->ecc_stat.ecc_corrected; - page_stat->ecc_failed = stat->ecc_stat.ecc_failed; - - return (0); -} - -static int -nand_block_stat(struct nand_chip *chip, struct block_stat_io *block_stat) -{ - struct chip_geom *cg; - uint32_t block_num = block_stat->block_num; - - cg = &chip->chip_geom; - if (block_num >= cg->blks_per_lun * cg->luns) - return (EINVAL); - - block_stat->block_erased = chip->blk_stat[block_num].block_erased; - - return (0); -} diff --git a/sys/dev/nand/nand_dev.h b/sys/dev/nand/nand_dev.h deleted file mode 100644 index bd00c4d4b3b4..000000000000 --- a/sys/dev/nand/nand_dev.h +++ /dev/null @@ -1,92 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$ - */ - -#ifndef _DEV_NAND_CDEV_H_ -#define _DEV_NAND_CDEV_H_ - -#include -#include - -struct nand_raw_rw { - off_t off; - off_t len; - uint8_t *data; -}; - -struct nand_oob_rw { - uint32_t page; - off_t len; - uint8_t *data; -}; - -#define NAND_IOCTL_GROUP 'N' -#define NAND_IO_ERASE _IOWR(NAND_IOCTL_GROUP, 0x0, off_t[2]) - -#define NAND_IO_OOB_READ _IOWR(NAND_IOCTL_GROUP, 0x1, struct nand_oob_rw) - -#define NAND_IO_OOB_PROG _IOWR(NAND_IOCTL_GROUP, 0x2, struct nand_oob_rw) - -#define NAND_IO_RAW_READ _IOWR(NAND_IOCTL_GROUP, 0x3, struct nand_raw_rw) - -#define NAND_IO_RAW_PROG _IOWR(NAND_IOCTL_GROUP, 0x4, struct nand_raw_rw) - -#define NAND_IO_GET_STATUS _IOWR(NAND_IOCTL_GROUP, 0x5, uint8_t) - -struct page_stat_io { - uint32_t page_num; - uint32_t page_read; - uint32_t page_written; - uint32_t page_raw_read; - uint32_t page_raw_written; - uint32_t ecc_succeded; - uint32_t ecc_corrected; - uint32_t ecc_failed; -}; -#define NAND_IO_PAGE_STAT _IOWR(NAND_IOCTL_GROUP, 0x6, \ - struct page_stat_io) - -struct block_stat_io { - uint32_t block_num; - uint32_t block_erased; -}; -#define NAND_IO_BLOCK_STAT _IOWR(NAND_IOCTL_GROUP, 0x7, \ - struct block_stat_io) - -struct chip_param_io { - uint32_t page_size; - uint32_t oob_size; - - uint32_t blocks; - uint32_t pages_per_block; -}; -#define NAND_IO_GET_CHIP_PARAM _IOWR(NAND_IOCTL_GROUP, 0x8, \ - struct chip_param_io) - -#endif /* _DEV_NAND_CDEV_H_ */ diff --git a/sys/dev/nand/nand_ecc_pos.h b/sys/dev/nand/nand_ecc_pos.h deleted file mode 100644 index 835f45e6c083..000000000000 --- a/sys/dev/nand/nand_ecc_pos.h +++ /dev/null @@ -1,58 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$ - */ - -#ifndef _DEV_NAND_ECC_POS_H_ -#define _DEV_NAND_ECC_POS_H_ - -static uint16_t default_software_ecc_positions_16[] = {2, 0, 1, 7, 4, 6}; - -static uint16_t default_software_ecc_positions_64[] = { - - 42, 40, 41, 45, 43, 44, 48, 46, - 47, 51, 49, 50, 54, 52, 53, 57, - 55, 56, 60, 58, 59, 63, 61, 62 -}; - -static uint16_t default_software_ecc_positions_128[] = { - 8, 9, 10, 11, 12, 13, - 18, 19, 20, 21, 22, 23, - 28, 29, 30, 31, 32, 33, - 38, 39, 40, 41, 42, 43, - 48, 49, 50, 51, 52, 53, - 58, 59, 60, 61, 62, 63, - 68, 69, 70, 71, 72, 73, - 78, 79, 80, 81, 82, 83, - 88, 89, 90, 91, 92, 93, - 98, 99, 100, 101, 102, 103, - 108, 109, 110, 111, 112, 113, - 118, 119, 120, 121, 122, 123, -}; -#endif /* _DEV_NAND_ECC_POS_H_ */ - diff --git a/sys/dev/nand/nand_generic.c b/sys/dev/nand/nand_generic.c deleted file mode 100644 index cc6ef9bd57b0..000000000000 --- a/sys/dev/nand/nand_generic.c +++ /dev/null @@ -1,1366 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. - */ - -/* Generic NAND driver */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "nfc_if.h" -#include "nand_if.h" -#include "nandbus_if.h" - - -static int onfi_nand_probe(device_t dev); -static int large_nand_probe(device_t dev); -static int small_nand_probe(device_t dev); -static int generic_nand_attach(device_t dev); -static int generic_nand_detach(device_t dev); - -static int generic_erase_block(device_t, uint32_t); -static int generic_erase_block_intlv(device_t, uint32_t); -static int generic_read_page (device_t, uint32_t, void *, uint32_t, uint32_t); -static int generic_read_oob(device_t, uint32_t, void *, uint32_t, uint32_t); -static int generic_program_page(device_t, uint32_t, void *, uint32_t, uint32_t); -static int generic_program_page_intlv(device_t, uint32_t, void *, uint32_t, - uint32_t); -static int generic_program_oob(device_t, uint32_t, void *, uint32_t, uint32_t); -static int generic_is_blk_bad(device_t, uint32_t, uint8_t *); -static int generic_get_ecc(device_t, void *, void *, int *); -static int generic_correct_ecc(device_t, void *, void *, void *); - -static int small_read_page(device_t, uint32_t, void *, uint32_t, uint32_t); -static int small_read_oob(device_t, uint32_t, void *, uint32_t, uint32_t); -static int small_program_page(device_t, uint32_t, void *, uint32_t, uint32_t); -static int small_program_oob(device_t, uint32_t, void *, uint32_t, uint32_t); - -static int onfi_is_blk_bad(device_t, uint32_t, uint8_t *); -static int onfi_read_parameter(struct nand_chip *, struct onfi_chip_params *); - -static int nand_send_address(device_t, int32_t, int32_t, int8_t); - -static device_method_t onand_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, onfi_nand_probe), - DEVMETHOD(device_attach, generic_nand_attach), - DEVMETHOD(device_detach, generic_nand_detach), - - DEVMETHOD(nand_read_page, generic_read_page), - DEVMETHOD(nand_program_page, generic_program_page), - DEVMETHOD(nand_program_page_intlv, generic_program_page_intlv), - DEVMETHOD(nand_read_oob, generic_read_oob), - DEVMETHOD(nand_program_oob, generic_program_oob), - DEVMETHOD(nand_erase_block, generic_erase_block), - DEVMETHOD(nand_erase_block_intlv, generic_erase_block_intlv), - - DEVMETHOD(nand_is_blk_bad, onfi_is_blk_bad), - DEVMETHOD(nand_get_ecc, generic_get_ecc), - DEVMETHOD(nand_correct_ecc, generic_correct_ecc), - { 0, 0 } -}; - -static device_method_t lnand_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, large_nand_probe), - DEVMETHOD(device_attach, generic_nand_attach), - DEVMETHOD(device_detach, generic_nand_detach), - - DEVMETHOD(nand_read_page, generic_read_page), - DEVMETHOD(nand_program_page, generic_program_page), - DEVMETHOD(nand_read_oob, generic_read_oob), - DEVMETHOD(nand_program_oob, generic_program_oob), - DEVMETHOD(nand_erase_block, generic_erase_block), - - DEVMETHOD(nand_is_blk_bad, generic_is_blk_bad), - DEVMETHOD(nand_get_ecc, generic_get_ecc), - DEVMETHOD(nand_correct_ecc, generic_correct_ecc), - { 0, 0 } -}; - -static device_method_t snand_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, small_nand_probe), - DEVMETHOD(device_attach, generic_nand_attach), - DEVMETHOD(device_detach, generic_nand_detach), - - DEVMETHOD(nand_read_page, small_read_page), - DEVMETHOD(nand_program_page, small_program_page), - DEVMETHOD(nand_read_oob, small_read_oob), - DEVMETHOD(nand_program_oob, small_program_oob), - DEVMETHOD(nand_erase_block, generic_erase_block), - - DEVMETHOD(nand_is_blk_bad, generic_is_blk_bad), - DEVMETHOD(nand_get_ecc, generic_get_ecc), - DEVMETHOD(nand_correct_ecc, generic_correct_ecc), - { 0, 0 } -}; - -devclass_t onand_devclass; -devclass_t lnand_devclass; -devclass_t snand_devclass; - -driver_t onand_driver = { - "onand", - onand_methods, - sizeof(struct nand_chip) -}; - -driver_t lnand_driver = { - "lnand", - lnand_methods, - sizeof(struct nand_chip) -}; - -driver_t snand_driver = { - "snand", - snand_methods, - sizeof(struct nand_chip) -}; - -DRIVER_MODULE(onand, nandbus, onand_driver, onand_devclass, 0, 0); -DRIVER_MODULE(lnand, nandbus, lnand_driver, lnand_devclass, 0, 0); -DRIVER_MODULE(snand, nandbus, snand_driver, snand_devclass, 0, 0); - -static int -onfi_nand_probe(device_t dev) -{ - struct nandbus_ivar *ivar; - - ivar = device_get_ivars(dev); - if (ivar && ivar->is_onfi) { - device_set_desc(dev, "ONFI compliant NAND"); - return (BUS_PROBE_DEFAULT); - } - - return (ENODEV); -} - -static int -large_nand_probe(device_t dev) -{ - struct nandbus_ivar *ivar; - - ivar = device_get_ivars(dev); - if (ivar && !ivar->is_onfi && ivar->params->page_size >= 512) { - device_set_desc(dev, ivar->params->name); - return (BUS_PROBE_DEFAULT); - } - - return (ENODEV); -} - -static int -small_nand_probe(device_t dev) -{ - struct nandbus_ivar *ivar; - - ivar = device_get_ivars(dev); - if (ivar && !ivar->is_onfi && ivar->params->page_size == 512) { - device_set_desc(dev, ivar->params->name); - return (BUS_PROBE_DEFAULT); - } - - return (ENODEV); -} - -static int -generic_nand_attach(device_t dev) -{ - struct nand_chip *chip; - struct nandbus_ivar *ivar; - struct onfi_chip_params *onfi_chip_params; - device_t nandbus, nfc; - int err; - - chip = device_get_softc(dev); - chip->dev = dev; - - ivar = device_get_ivars(dev); - chip->id.man_id = ivar->man_id; - chip->id.dev_id = ivar->dev_id; - chip->num = ivar->cs; - - /* TODO remove when HW ECC supported */ - nandbus = device_get_parent(dev); - nfc = device_get_parent(nandbus); - - chip->nand = device_get_softc(nfc); - - if (ivar->is_onfi) { - onfi_chip_params = malloc(sizeof(struct onfi_chip_params), - M_NAND, M_WAITOK | M_ZERO); - - if (onfi_read_parameter(chip, onfi_chip_params)) { - nand_debug(NDBG_GEN,"Could not read parameter page!\n"); - free(onfi_chip_params, M_NAND); - return (ENXIO); - } - - nand_onfi_set_params(chip, onfi_chip_params); - /* Set proper column and row cycles */ - ivar->cols = (onfi_chip_params->address_cycles >> 4) & 0xf; - ivar->rows = onfi_chip_params->address_cycles & 0xf; - free(onfi_chip_params, M_NAND); - - } else { - nand_set_params(chip, ivar->params); - } - - err = nand_init_stat(chip); - if (err) { - generic_nand_detach(dev); - return (err); - } - - err = nand_init_bbt(chip); - if (err) { - generic_nand_detach(dev); - return (err); - } - - err = nand_make_dev(chip); - if (err) { - generic_nand_detach(dev); - return (err); - } - - err = create_geom_disk(chip); - if (err) { - generic_nand_detach(dev); - return (err); - } - - return (0); -} - -static int -generic_nand_detach(device_t dev) -{ - struct nand_chip *chip; - - chip = device_get_softc(dev); - - nand_destroy_bbt(chip); - destroy_geom_disk(chip); - nand_destroy_dev(chip); - nand_destroy_stat(chip); - - return (0); -} - -static int -can_write(device_t nandbus) -{ - uint8_t status; - - if (NANDBUS_WAIT_READY(nandbus, &status)) - return (0); - - if (!(status & NAND_STATUS_WP)) { - nand_debug(NDBG_GEN,"Chip is write-protected"); - return (0); - } - - return (1); -} - -static int -check_fail(device_t nandbus) -{ - uint8_t status; - - NANDBUS_WAIT_READY(nandbus, &status); - if (status & NAND_STATUS_FAIL) { - nand_debug(NDBG_GEN,"Status failed %x", status); - return (ENXIO); - } - - return (0); -} - -static uint16_t -onfi_crc(const void *buf, size_t buflen) -{ - int i, j; - uint16_t crc; - const uint8_t *bufptr; - - bufptr = buf; - crc = 0x4f4e; - for (j = 0; j < buflen; j++) { - crc ^= *bufptr++ << 8; - for (i = 0; i < 8; i++) - if (crc & 0x8000) - crc = (crc << 1) ^ 0x8005; - else - crc <<= 1; - } - return crc; -} - -static int -onfi_read_parameter(struct nand_chip *chip, struct onfi_chip_params *chip_params) -{ - device_t nandbus; - struct onfi_params params; - int found, sigcount, trycopy; - - nand_debug(NDBG_GEN,"read parameter"); - - nandbus = device_get_parent(chip->dev); - - NANDBUS_SELECT_CS(nandbus, chip->num); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_READ_PARAMETER)) - return (ENXIO); - - if (nand_send_address(chip->dev, -1, -1, PAGE_PARAMETER_DEF)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - /* - * XXX Bogus DELAY, we really need a nandbus_wait_ready() here, but it's - * not accessible from here (static to nandbus). - */ - DELAY(1000); - - /* - * The ONFI spec mandates a minimum of three copies of the parameter - * data, so loop up to 3 times trying to find good data. Each copy is - * validated by a signature of "ONFI" and a crc. There is a very strange - * rule that the signature is valid if any 2 of the 4 bytes are correct. - */ - for (found= 0, trycopy = 0; !found && trycopy < 3; trycopy++) { - NANDBUS_READ_BUFFER(nandbus, ¶ms, sizeof(struct onfi_params)); - sigcount = params.signature[0] == 'O'; - sigcount += params.signature[1] == 'N'; - sigcount += params.signature[2] == 'F'; - sigcount += params.signature[3] == 'I'; - if (sigcount < 2) - continue; - if (onfi_crc(¶ms, 254) != params.crc) - continue; - found = 1; - } - if (!found) - return (ENXIO); - - chip_params->luns = params.luns; - chip_params->blocks_per_lun = le32dec(¶ms.blocks_per_lun); - chip_params->pages_per_block = le32dec(¶ms.pages_per_block); - chip_params->bytes_per_page = le32dec(¶ms.bytes_per_page); - chip_params->spare_bytes_per_page = le16dec(¶ms.spare_bytes_per_page); - chip_params->t_bers = le16dec(¶ms.t_bers); - chip_params->t_prog = le16dec(¶ms.t_prog); - chip_params->t_r = le16dec(¶ms.t_r); - chip_params->t_ccs = le16dec(¶ms.t_ccs); - chip_params->features = le16dec(¶ms.features); - chip_params->address_cycles = params.address_cycles; - - return (0); -} - -static int -send_read_page(device_t nand, uint8_t start_command, uint8_t end_command, - uint32_t row, uint32_t column) -{ - device_t nandbus = device_get_parent(nand); - - if (NANDBUS_SEND_COMMAND(nandbus, start_command)) - return (ENXIO); - - if (nand_send_address(nand, row, column, -1)) - return (ENXIO); - - if (NANDBUS_SEND_COMMAND(nandbus, end_command)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - return (0); -} - -static int -generic_read_page(device_t nand, uint32_t page, void *buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p raw read page %x[%x] at %x", nand, page, len, offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (send_read_page(nand, NAND_CMD_READ, NAND_CMD_READ_END, row, - offset)) - return (ENXIO); - - DELAY(chip->t_r); - - NANDBUS_READ_BUFFER(nandbus, buf, len); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_read++; - - return (0); -} - -static int -generic_read_oob(device_t nand, uint32_t page, void* buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p raw read oob %x[%x] at %x", nand, page, len, offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) { - nand_debug(NDBG_GEN,"page boundary check failed: %08x\n", page); - return (ENXIO); - } - - page_to_row(&chip->chip_geom, page, &row); - - offset += chip->chip_geom.page_size; - - if (send_read_page(nand, NAND_CMD_READ, NAND_CMD_READ_END, row, - offset)) - return (ENXIO); - - DELAY(chip->t_r); - - NANDBUS_READ_BUFFER(nandbus, buf, len); - - if (check_fail(nandbus)) - return (ENXIO); - - return (0); -} - -static int -send_start_program_page(device_t nand, uint32_t row, uint32_t column) -{ - device_t nandbus = device_get_parent(nand); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_PROG)) - return (ENXIO); - - if (nand_send_address(nand, row, column, -1)) - return (ENXIO); - - return (0); -} - -static int -send_end_program_page(device_t nandbus, uint8_t end_command) -{ - - if (NANDBUS_SEND_COMMAND(nandbus, end_command)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - return (0); -} - -static int -generic_program_page(device_t nand, uint32_t page, void *buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p raw prog page %x[%x] at %x", nand, page, len, - offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (!can_write(nandbus)) - return (ENXIO); - - if (send_start_program_page(nand, row, offset)) - return (ENXIO); - - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (send_end_program_page(nandbus, NAND_CMD_PROG_END)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_written++; - - return (0); -} - -static int -generic_program_page_intlv(device_t nand, uint32_t page, void *buf, - uint32_t len, uint32_t offset) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p raw prog page %x[%x] at %x", nand, page, len, offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (!can_write(nandbus)) - return (ENXIO); - - if (send_start_program_page(nand, row, offset)) - return (ENXIO); - - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (send_end_program_page(nandbus, NAND_CMD_PROG_INTLV)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_written++; - - return (0); -} - -static int -generic_program_oob(device_t nand, uint32_t page, void* buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p raw prog oob %x[%x] at %x", nand, page, len, - offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - offset += chip->chip_geom.page_size; - - if (!can_write(nandbus)) - return (ENXIO); - - if (send_start_program_page(nand, row, offset)) - return (ENXIO); - - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (send_end_program_page(nandbus, NAND_CMD_PROG_END)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - return (0); -} - -static int -send_erase_block(device_t nand, uint32_t row, uint8_t second_command) -{ - device_t nandbus = device_get_parent(nand); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_ERASE)) - return (ENXIO); - - if (nand_send_address(nand, row, -1, -1)) - return (ENXIO); - - if (NANDBUS_SEND_COMMAND(nandbus, second_command)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - return (0); -} - -static int -generic_erase_block(device_t nand, uint32_t block) -{ - struct block_stat *blk_stat; - struct nand_chip *chip; - device_t nandbus; - int row; - - nand_debug(NDBG_GEN,"%p erase block %x", nand, block); - nandbus = device_get_parent(nand); - chip = device_get_softc(nand); - - if (block >= (chip->chip_geom.blks_per_lun * chip->chip_geom.luns)) - return (ENXIO); - - row = (block << chip->chip_geom.blk_shift) & - chip->chip_geom.blk_mask; - - nand_debug(NDBG_GEN,"%p erase block row %x", nand, row); - - if (!can_write(nandbus)) - return (ENXIO); - - send_erase_block(nand, row, NAND_CMD_ERASE_END); - - DELAY(chip->t_bers); - - if (check_fail(nandbus)) - return (ENXIO); - - blk_stat = &(chip->blk_stat[block]); - blk_stat->block_erased++; - - return (0); -} - -static int -generic_erase_block_intlv(device_t nand, uint32_t block) -{ - struct block_stat *blk_stat; - struct nand_chip *chip; - device_t nandbus; - int row; - - nand_debug(NDBG_GEN,"%p erase block %x", nand, block); - nandbus = device_get_parent(nand); - chip = device_get_softc(nand); - - if (block >= (chip->chip_geom.blks_per_lun * chip->chip_geom.luns)) - return (ENXIO); - - row = (block << chip->chip_geom.blk_shift) & - chip->chip_geom.blk_mask; - - if (!can_write(nandbus)) - return (ENXIO); - - send_erase_block(nand, row, NAND_CMD_ERASE_INTLV); - - DELAY(chip->t_bers); - - if (check_fail(nandbus)) - return (ENXIO); - - blk_stat = &(chip->blk_stat[block]); - blk_stat->block_erased++; - - return (0); - -} - -static int -onfi_is_blk_bad(device_t device, uint32_t block_number, uint8_t *bad) -{ - struct nand_chip *chip; - int page_number, i, j, err; - uint8_t *oob; - - chip = device_get_softc(device); - - oob = malloc(chip->chip_geom.oob_size, M_NAND, M_WAITOK); - - page_number = block_number * chip->chip_geom.pgs_per_blk; - *bad = 0; - /* Check OOB of first and last page */ - for (i = 0; i < 2; i++, page_number+= chip->chip_geom.pgs_per_blk - 1) { - err = generic_read_oob(device, page_number, oob, - chip->chip_geom.oob_size, 0); - if (err) { - device_printf(device, "%s: cannot allocate oob\n", - __func__); - free(oob, M_NAND); - return (ENOMEM); - } - - for (j = 0; j < chip->chip_geom.oob_size; j++) { - if (!oob[j]) { - *bad = 1; - free(oob, M_NAND); - return (0); - } - } - } - - free(oob, M_NAND); - - return (0); -} - -static int -send_small_read_page(device_t nand, uint8_t start_command, - uint32_t row, uint32_t column) -{ - device_t nandbus = device_get_parent(nand); - - if (NANDBUS_SEND_COMMAND(nandbus, start_command)) - return (ENXIO); - - if (nand_send_address(nand, row, column, -1)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - return (0); -} - - -static int -small_read_page(device_t nand, uint32_t page, void *buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p small read page %x[%x] at %x", nand, page, len, offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (offset < 256) { - if (send_small_read_page(nand, NAND_CMD_SMALLA, row, offset)) - return (ENXIO); - } else { - offset -= 256; - if (send_small_read_page(nandbus, NAND_CMD_SMALLB, row, offset)) - return (ENXIO); - } - - DELAY(chip->t_r); - - NANDBUS_READ_BUFFER(nandbus, buf, len); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_read++; - - return (0); -} - -static int -small_read_oob(device_t nand, uint32_t page, void *buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p small read oob %x[%x] at %x", nand, page, len, offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (send_small_read_page(nand, NAND_CMD_SMALLOOB, row, 0)) - return (ENXIO); - - DELAY(chip->t_r); - - NANDBUS_READ_BUFFER(nandbus, buf, len); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_read++; - - return (0); -} - -static int -small_program_page(device_t nand, uint32_t page, void* buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p small prog page %x[%x] at %x", nand, page, len, offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (!can_write(nandbus)) - return (ENXIO); - - if (offset < 256) { - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_SMALLA)) - return (ENXIO); - } else { - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_SMALLB)) - return (ENXIO); - } - - if (send_start_program_page(nand, row, offset)) - return (ENXIO); - - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (send_end_program_page(nandbus, NAND_CMD_PROG_END)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - return (0); -} - -static int -small_program_oob(device_t nand, uint32_t page, void* buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p small prog oob %x[%x] at %x", nand, page, len, offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (!can_write(nandbus)) - return (ENXIO); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_SMALLOOB)) - return (ENXIO); - - if (send_start_program_page(nand, row, offset)) - return (ENXIO); - - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (send_end_program_page(nandbus, NAND_CMD_PROG_END)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - return (0); -} - -int -nand_send_address(device_t nand, int32_t row, int32_t col, int8_t id) -{ - struct nandbus_ivar *ivar; - device_t nandbus; - uint8_t addr; - int err = 0; - int i; - - nandbus = device_get_parent(nand); - ivar = device_get_ivars(nand); - - if (id != -1) { - nand_debug(NDBG_GEN,"send_address: send id %02x", id); - err = NANDBUS_SEND_ADDRESS(nandbus, id); - } - - if (!err && col != -1) { - for (i = 0; i < ivar->cols; i++, col >>= 8) { - addr = (uint8_t)(col & 0xff); - nand_debug(NDBG_GEN,"send_address: send address column " - "%02x", addr); - err = NANDBUS_SEND_ADDRESS(nandbus, addr); - if (err) - break; - } - } - - if (!err && row != -1) { - for (i = 0; i < ivar->rows; i++, row >>= 8) { - addr = (uint8_t)(row & 0xff); - nand_debug(NDBG_GEN,"send_address: send address row " - "%02x", addr); - err = NANDBUS_SEND_ADDRESS(nandbus, addr); - if (err) - break; - } - } - - return (err); -} - -static int -generic_is_blk_bad(device_t dev, uint32_t block, uint8_t *bad) -{ - struct nand_chip *chip; - int page_number, err, i; - uint8_t *oob; - - chip = device_get_softc(dev); - - oob = malloc(chip->chip_geom.oob_size, M_NAND, M_WAITOK); - - page_number = block * chip->chip_geom.pgs_per_blk; - *bad = 0; - - /* Check OOB of first and second page */ - for (i = 0; i < 2; i++) { - err = NAND_READ_OOB(dev, page_number + i, oob, - chip->chip_geom.oob_size, 0); - if (err) { - device_printf(dev, "%s: cannot allocate OOB\n", - __func__); - free(oob, M_NAND); - return (ENOMEM); - } - - if (!oob[0]) { - *bad = 1; - free(oob, M_NAND); - return (0); - } - } - - free(oob, M_NAND); - - return (0); -} - -static int -generic_get_ecc(device_t dev, void *buf, void *ecc, int *needwrite) -{ - struct nand_chip *chip = device_get_softc(dev); - struct chip_geom *cg = &chip->chip_geom; - - return (NANDBUS_GET_ECC(device_get_parent(dev), buf, cg->page_size, - ecc, needwrite)); -} - -static int -generic_correct_ecc(device_t dev, void *buf, void *readecc, void *calcecc) -{ - struct nand_chip *chip = device_get_softc(dev); - struct chip_geom *cg = &chip->chip_geom; - - return (NANDBUS_CORRECT_ECC(device_get_parent(dev), buf, - cg->page_size, readecc, calcecc)); -} - - -#if 0 -int -nand_chng_read_col(device_t nand, uint32_t col, void *buf, size_t len) -{ - struct nand_chip *chip; - device_t nandbus; - - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_CHNG_READ_COL)) - return (ENXIO); - - if (NANDBUS_SEND_ADDRESS(nandbus, -1, col, -1)) - return (ENXIO); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_CHNG_READ_COL_END)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - if (buf != NULL && len > 0) - NANDBUS_READ_BUFFER(nandbus, buf, len); - - return (0); -} - -int -nand_chng_write_col(device_t dev, uint32_t col, void *buf, - size_t len) -{ - struct nand_chip *chip; - device_t nandbus; - - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_CHNG_WRITE_COL)) - return (ENXIO); - - if (NANDBUS_SEND_ADDRESS(nandbus, -1, col, -1)) - return (ENXIO); - - if (buf != NULL && len > 0) - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_CHNG_READ_COL_END)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - return (0); -} - -int -nand_copyback_read(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN," raw read page %x[%x] at %x", page, col, len); - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (send_read_page(nand, NAND_CMD_READ, NAND_CMD_READ_CPBK, row, 0)) - return (ENXIO); - - DELAY(chip->t_r); - if (check_fail(nandbus)) - return (ENXIO); - - if (buf != NULL && len > 0) - NANDBUS_READ_BUFFER(nandbus, buf, len); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_read++; - - return (0); -} - -int -nand_copyback_prog(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"copyback prog page %x[%x]", page, len); - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (!can_write(nandbus)) - return (ENXIO); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_CHNG_WRITE_COL)) - return (ENXIO); - - if (NANDBUS_SEND_ADDRESS(nandbus, row, col, -1)) - return (ENXIO); - - if (buf != NULL && len > 0) - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (send_end_program_page(nandbus, NAND_CMD_PROG_END)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_written++; - - return (0); -} - -int -nand_copyback_prog_intlv(device_t dev, uint32_t page) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"cache prog page %x", page); - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (!can_write(nandbus)) - return (ENXIO); - - if (send_start_program_page(nand, row, 0)) - return (ENXIO); - - if (send_end_program_page(nandbus, NAND_CMD_PROG_INTLV)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_written++; - - return (0); -} - -int -nand_prog_cache(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len, uint8_t end) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - uint8_t command; - - nand_debug(NDBG_GEN,"cache prog page %x[%x]", page, len); - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (!can_write(nandbus)) - return (ENXIO); - - if (send_start_program_page(dev, row, 0)) - return (ENXIO); - - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (end) - command = NAND_CMD_PROG_END; - else - command = NAND_CMD_PROG_CACHE; - - if (send_end_program_page(nandbus, command)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_written++; - - return (0); -} - -int -nand_read_cache(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len, uint8_t end) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - uint8_t command; - - nand_debug(NDBG_GEN,"cache read page %x[%x] ", page, len); - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (page != -1) { - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_READ)) - return (ENXIO); - - if (NANDBUS_SEND_ADDRESS(nandbus, row, col, -1)) - return (ENXIO); - } - - if (end) - command = NAND_CMD_READ_CACHE_END; - else - command = NAND_CMD_READ_CACHE; - - if (NANDBUS_SEND_COMMAND(nandbus, command)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - DELAY(chip->t_r); - if (check_fail(nandbus)) - return (ENXIO); - - if (buf != NULL && len > 0) - NANDBUS_READ_BUFFER(nandbus, buf, len); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_read++; - - return (0); -} - -int -nand_get_feature(device_t dev, uint8_t feat, void *buf) -{ - struct nand_chip *chip; - device_t nandbus; - - nand_debug(NDBG_GEN,"nand get feature"); - - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_GET_FEATURE)) - return (ENXIO); - - if (NANDBUS_SEND_ADDRESS(nandbus, -1, -1, feat)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - DELAY(chip->t_r); - NANDBUS_READ_BUFFER(nandbus, buf, 4); - - return (0); -} - -int -nand_set_feature(device_t dev, uint8_t feat, void *buf) -{ - struct nand_chip *chip; - device_t nandbus; - - nand_debug(NDBG_GEN,"nand set feature"); - - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_SET_FEATURE)) - return (ENXIO); - - if (NANDBUS_SEND_ADDRESS(nandbus, -1, -1, feat)) - return (ENXIO); - - NANDBUS_WRITE_BUFFER(nandbus, buf, 4); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - return (0); -} -#endif diff --git a/sys/dev/nand/nand_geom.c b/sys/dev/nand/nand_geom.c deleted file mode 100644 index b814ffc4e0a9..000000000000 --- a/sys/dev/nand/nand_geom.c +++ /dev/null @@ -1,467 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include "nand_if.h" -#include "nandbus_if.h" - -#define BIO_NAND_STD ((void *)1) -#define BIO_NAND_RAW ((void *)2) - -static disk_ioctl_t nand_ioctl; -static disk_getattr_t nand_getattr; -static disk_strategy_t nand_strategy; -static disk_strategy_t nand_strategy_raw; - -static int -nand_read(struct nand_chip *chip, uint32_t offset, void *buf, uint32_t len) -{ - - nand_debug(NDBG_GEOM, "Read from chip %d [%p] at %d", chip->num, chip, - offset); - - return (nand_read_pages(chip, offset, buf, len)); -} - -static int -nand_write(struct nand_chip *chip, uint32_t offset, void* buf, uint32_t len) -{ - - nand_debug(NDBG_GEOM, "Write to chip %d [%p] at %d", chip->num, chip, - offset); - - return (nand_prog_pages(chip, offset, buf, len)); -} - -static int -nand_read_raw(struct nand_chip *chip, uint32_t offset, void *buf, uint32_t len) -{ - nand_debug(NDBG_GEOM, "Raw read from chip %d [%p] at %d", chip->num, - chip, offset); - - return (nand_read_pages_raw(chip, offset, buf, len)); -} - -static int -nand_write_raw(struct nand_chip *chip, uint32_t offset, void *buf, uint32_t len) -{ - - nand_debug(NDBG_GEOM, "Raw write to chip %d [%p] at %d", chip->num, - chip, offset); - - return (nand_prog_pages_raw(chip, offset, buf, len)); -} - -static void -nand_strategy(struct bio *bp) -{ - struct nand_chip *chip; - - chip = (struct nand_chip *)bp->bio_disk->d_drv1; - - bp->bio_driver1 = BIO_NAND_STD; - - nand_debug(NDBG_GEOM, "Strategy %s on chip %d [%p]", - bp->bio_cmd == BIO_READ ? "READ" : - (bp->bio_cmd == BIO_WRITE ? "WRITE" : - (bp->bio_cmd == BIO_DELETE ? "DELETE" : "UNKNOWN")), - chip->num, chip); - - mtx_lock(&chip->qlock); - bioq_insert_tail(&chip->bioq, bp); - mtx_unlock(&chip->qlock); - taskqueue_enqueue(chip->tq, &chip->iotask); -} - -static void -nand_strategy_raw(struct bio *bp) -{ - struct nand_chip *chip; - - chip = (struct nand_chip *)bp->bio_disk->d_drv1; - - /* Inform taskqueue that it's a raw access */ - bp->bio_driver1 = BIO_NAND_RAW; - - nand_debug(NDBG_GEOM, "Strategy %s on chip %d [%p]", - bp->bio_cmd == BIO_READ ? "READ" : - (bp->bio_cmd == BIO_WRITE ? "WRITE" : - (bp->bio_cmd == BIO_DELETE ? "DELETE" : "UNKNOWN")), - chip->num, chip); - - mtx_lock(&chip->qlock); - bioq_insert_tail(&chip->bioq, bp); - mtx_unlock(&chip->qlock); - taskqueue_enqueue(chip->tq, &chip->iotask); -} - -static int -nand_oob_access(struct nand_chip *chip, uint32_t page, uint32_t offset, - uint32_t len, uint8_t *data, uint8_t write) -{ - struct chip_geom *cg; - int ret = 0; - - cg = &chip->chip_geom; - - if (!write) - ret = nand_read_oob(chip, page, data, cg->oob_size); - else - ret = nand_prog_oob(chip, page, data, cg->oob_size); - - return (ret); -} - -static int -nand_getattr(struct bio *bp) -{ - struct nand_chip *chip; - struct chip_geom *cg; - device_t dev; - int val; - - if (bp->bio_disk == NULL || bp->bio_disk->d_drv1 == NULL) - return (ENXIO); - - chip = (struct nand_chip *)bp->bio_disk->d_drv1; - cg = &(chip->chip_geom); - - dev = device_get_parent(chip->dev); - dev = device_get_parent(dev); - - if (strcmp(bp->bio_attribute, "NAND::device") == 0) { - if (bp->bio_length != sizeof(dev)) - return (EFAULT); - bcopy(&dev, bp->bio_data, sizeof(dev)); - } else { - if (strcmp(bp->bio_attribute, "NAND::oobsize") == 0) - val = cg->oob_size; - else if (strcmp(bp->bio_attribute, "NAND::pagesize") == 0) - val = cg->page_size; - else if (strcmp(bp->bio_attribute, "NAND::blocksize") == 0) - val = cg->block_size; - else - return (-1); - if (bp->bio_length != sizeof(val)) - return (EFAULT); - bcopy(&val, bp->bio_data, sizeof(val)); - } - bp->bio_completed = bp->bio_length; - return (0); -} - -static int -nand_ioctl(struct disk *ndisk, u_long cmd, void *data, int fflag, - struct thread *td) -{ - struct nand_chip *chip; - struct chip_geom *cg; - struct nand_oob_rw *oob_rw = NULL; - struct nand_raw_rw *raw_rw = NULL; - device_t nandbus; - size_t bufsize = 0, len = 0; - size_t raw_size; - off_t off; - uint8_t *buf = NULL; - int ret = 0; - uint8_t status; - - chip = (struct nand_chip *)ndisk->d_drv1; - cg = &chip->chip_geom; - nandbus = device_get_parent(chip->dev); - - if ((cmd == NAND_IO_RAW_READ) || (cmd == NAND_IO_RAW_PROG)) { - raw_rw = (struct nand_raw_rw *)data; - raw_size = cg->pgs_per_blk * (cg->page_size + cg->oob_size); - - /* Check if len is not bigger than chip size */ - if (raw_rw->len > raw_size) - return (EFBIG); - - /* - * Do not ask for too much memory, in case of large transfers - * read/write in 16-pages chunks - */ - bufsize = 16 * (cg->page_size + cg->oob_size); - if (raw_rw->len < bufsize) - bufsize = raw_rw->len; - - buf = malloc(bufsize, M_NAND, M_WAITOK); - len = raw_rw->len; - off = 0; - } - - switch (cmd) { - case NAND_IO_ERASE: - ret = nand_erase_blocks(chip, ((off_t *)data)[0], - ((off_t *)data)[1]); - break; - - case NAND_IO_OOB_READ: - oob_rw = (struct nand_oob_rw *)data; - ret = nand_oob_access(chip, oob_rw->page, 0, - oob_rw->len, oob_rw->data, 0); - break; - - case NAND_IO_OOB_PROG: - oob_rw = (struct nand_oob_rw *)data; - ret = nand_oob_access(chip, oob_rw->page, 0, - oob_rw->len, oob_rw->data, 1); - break; - - case NAND_IO_GET_STATUS: - NANDBUS_LOCK(nandbus); - ret = NANDBUS_GET_STATUS(nandbus, &status); - if (ret == 0) - *(uint8_t *)data = status; - NANDBUS_UNLOCK(nandbus); - break; - - case NAND_IO_RAW_PROG: - while (len > 0) { - if (len < bufsize) - bufsize = len; - - ret = copyin(raw_rw->data + off, buf, bufsize); - if (ret) - break; - ret = nand_prog_pages_raw(chip, raw_rw->off + off, buf, - bufsize); - if (ret) - break; - len -= bufsize; - off += bufsize; - } - break; - - case NAND_IO_RAW_READ: - while (len > 0) { - if (len < bufsize) - bufsize = len; - - ret = nand_read_pages_raw(chip, raw_rw->off + off, buf, - bufsize); - if (ret) - break; - - ret = copyout(buf, raw_rw->data + off, bufsize); - if (ret) - break; - len -= bufsize; - off += bufsize; - } - break; - - case NAND_IO_GET_CHIP_PARAM: - nand_get_chip_param(chip, (struct chip_param_io *)data); - break; - - default: - printf("Unknown nand_ioctl request \n"); - ret = EIO; - } - - if (buf) - free(buf, M_NAND); - - return (ret); -} - -static void -nand_io_proc(void *arg, int pending) -{ - struct nand_chip *chip = arg; - struct bio *bp; - int err = 0; - - for (;;) { - mtx_lock(&chip->qlock); - bp = bioq_takefirst(&chip->bioq); - mtx_unlock(&chip->qlock); - if (bp == NULL) - break; - - if (bp->bio_driver1 == BIO_NAND_STD) { - if (bp->bio_cmd == BIO_READ) { - err = nand_read(chip, - bp->bio_offset & 0xffffffff, - bp->bio_data, bp->bio_bcount); - } else if (bp->bio_cmd == BIO_WRITE) { - err = nand_write(chip, - bp->bio_offset & 0xffffffff, - bp->bio_data, bp->bio_bcount); - } - } else if (bp->bio_driver1 == BIO_NAND_RAW) { - if (bp->bio_cmd == BIO_READ) { - err = nand_read_raw(chip, - bp->bio_offset & 0xffffffff, - bp->bio_data, bp->bio_bcount); - } else if (bp->bio_cmd == BIO_WRITE) { - err = nand_write_raw(chip, - bp->bio_offset & 0xffffffff, - bp->bio_data, bp->bio_bcount); - } - } else - panic("Unknown access type in bio->bio_driver1\n"); - - if (bp->bio_cmd == BIO_DELETE) { - nand_debug(NDBG_GEOM, "Delete on chip%d offset %lld " - "length %ld\n", chip->num, bp->bio_offset, - bp->bio_bcount); - err = nand_erase_blocks(chip, - bp->bio_offset & 0xffffffff, - bp->bio_bcount); - } - - if (err == 0 || err == ECC_CORRECTABLE) - bp->bio_resid = 0; - else { - nand_debug(NDBG_GEOM,"nand_[read|write|erase_blocks] " - "error: %d\n", err); - - bp->bio_error = EIO; - bp->bio_flags |= BIO_ERROR; - bp->bio_resid = bp->bio_bcount; - } - biodone(bp); - } -} - -int -create_geom_disk(struct nand_chip *chip) -{ - struct disk *ndisk, *rdisk; - - /* Create the disk device */ - ndisk = disk_alloc(); - ndisk->d_strategy = nand_strategy; - ndisk->d_ioctl = nand_ioctl; - ndisk->d_getattr = nand_getattr; - ndisk->d_name = "gnand"; - ndisk->d_drv1 = chip; - ndisk->d_maxsize = chip->chip_geom.block_size; - ndisk->d_sectorsize = chip->chip_geom.page_size; - ndisk->d_mediasize = chip->chip_geom.chip_size; - ndisk->d_unit = chip->num + - 10 * device_get_unit(device_get_parent(chip->dev)); - - /* - * When using BBT, make two last blocks of device unavailable - * to user (because those are used to store BBT table). - */ - if (chip->bbt != NULL) - ndisk->d_mediasize -= (2 * chip->chip_geom.block_size); - - ndisk->d_flags = DISKFLAG_CANDELETE; - - snprintf(ndisk->d_ident, sizeof(ndisk->d_ident), - "nand: Man:0x%02x Dev:0x%02x", chip->id.man_id, chip->id.dev_id); - ndisk->d_rotation_rate = DISK_RR_NON_ROTATING; - - disk_create(ndisk, DISK_VERSION); - - /* Create the RAW disk device */ - rdisk = disk_alloc(); - rdisk->d_strategy = nand_strategy_raw; - rdisk->d_ioctl = nand_ioctl; - rdisk->d_getattr = nand_getattr; - rdisk->d_name = "gnand.raw"; - rdisk->d_drv1 = chip; - rdisk->d_maxsize = chip->chip_geom.block_size; - rdisk->d_sectorsize = chip->chip_geom.page_size; - rdisk->d_mediasize = chip->chip_geom.chip_size; - rdisk->d_unit = chip->num + - 10 * device_get_unit(device_get_parent(chip->dev)); - - rdisk->d_flags = DISKFLAG_CANDELETE; - - snprintf(rdisk->d_ident, sizeof(rdisk->d_ident), - "nand_raw: Man:0x%02x Dev:0x%02x", chip->id.man_id, - chip->id.dev_id); - rdisk->d_rotation_rate = DISK_RR_NON_ROTATING; - - disk_create(rdisk, DISK_VERSION); - - chip->ndisk = ndisk; - chip->rdisk = rdisk; - - mtx_init(&chip->qlock, "NAND I/O lock", NULL, MTX_DEF); - bioq_init(&chip->bioq); - - TASK_INIT(&chip->iotask, 0, nand_io_proc, chip); - chip->tq = taskqueue_create("nand_taskq", M_WAITOK, - taskqueue_thread_enqueue, &chip->tq); - taskqueue_start_threads(&chip->tq, 1, PI_DISK, "nand taskq"); - - if (bootverbose) - device_printf(chip->dev, "Created gnand%d for chip [0x%0x, " - "0x%0x]\n", ndisk->d_unit, chip->id.man_id, - chip->id.dev_id); - - return (0); -} - -void -destroy_geom_disk(struct nand_chip *chip) -{ - struct bio *bp; - - taskqueue_free(chip->tq); - disk_destroy(chip->ndisk); - disk_destroy(chip->rdisk); - - mtx_lock(&chip->qlock); - for (;;) { - bp = bioq_takefirst(&chip->bioq); - if (bp == NULL) - break; - bp->bio_error = EIO; - bp->bio_flags |= BIO_ERROR; - bp->bio_resid = bp->bio_bcount; - - biodone(bp); - } - mtx_unlock(&chip->qlock); - - mtx_destroy(&chip->qlock); -} diff --git a/sys/dev/nand/nand_id.c b/sys/dev/nand/nand_id.c deleted file mode 100644 index 7259c951bfc9..000000000000 --- a/sys/dev/nand/nand_id.c +++ /dev/null @@ -1,70 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 -#include - -#include - -struct nand_params nand_ids[] = { - { { NAND_MAN_SAMSUNG, 0x75 }, "Samsung K9F5608U0B NAND 32MiB 8-bit", - 0x20, 0x200, 0x10, 0x20, 0 }, - { { NAND_MAN_SAMSUNG, 0xf1 }, "Samsung K9F1G08U0A NAND 128MiB 3,3V 8-bit", - 0x80, 0x800, 0x40, 0x40, 0 }, - { { NAND_MAN_SAMSUNG, 0xda }, "Samsung K9F2G08U0A NAND 256MiB 3,3V 8-bit", - 0x100, 0x800, 0x40, 0x40, 0 }, - { { NAND_MAN_SAMSUNG, 0xdc }, "Samsung NAND 512MiB 3,3V 8-bit", - 0x200, 0x800, 0x40, 0x40, 0 }, - { { NAND_MAN_SAMSUNG, 0xd3 }, "Samsung NAND 1GiB 3,3V 8-bit", - 0x400, 0x800, 0x40, 0x40, 0 }, - { { NAND_MAN_HYNIX, 0x76 }, "Hynix NAND 64MiB 3,3V 8-bit", - 0x40, 0x200, 0x10, 0x20, 0 }, - { { NAND_MAN_HYNIX, 0xdc }, "Hynix NAND 512MiB 3,3V 8-bit", - 0x200, 0x800, 0x40, 0x40, 0 }, - { { NAND_MAN_HYNIX, 0x79 }, "Hynix NAND 128MB 3,3V 8-bit", - 0x80, 0x200, 0x10, 0x20, 0 }, - { { NAND_MAN_STMICRO, 0xf1 }, "STMicro 128MB 3,3V 8-bit", - 0x80, 2048, 64, 0x40, 0 }, - { { NAND_MAN_MICRON, 0xcc }, "Micron NAND 512MiB 3,3V 16-bit", - 0x200, 2048, 64, 0x40, 0 }, -}; - -struct nand_params *nand_get_params(struct nand_id *id) -{ - int i; - - for (i = 0; i < nitems(nand_ids); i++) - if (nand_ids[i].id.man_id == id->man_id && - nand_ids[i].id.dev_id == id->dev_id) - return (&nand_ids[i]); - - return (NULL); -} diff --git a/sys/dev/nand/nand_if.m b/sys/dev/nand/nand_if.m deleted file mode 100644 index 49c8879b6890..000000000000 --- a/sys/dev/nand/nand_if.m +++ /dev/null @@ -1,168 +0,0 @@ -#- -# Copyright (C) 2009-2012 Semihalf -# 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$ - -# NAND chip interface description -# - -#include -#include - -INTERFACE nand; - -CODE { - static int nand_method_not_supported(device_t dev) - { - return (ENOENT); - } -}; - -# Read NAND page -# -# Return values: -# 0: Success -# -METHOD int read_page { - device_t dev; - uint32_t page; - void* buf; - uint32_t len; - uint32_t offset; -}; - -# Program NAND page -# -# Return values: -# 0: Success -# -METHOD int program_page { - device_t dev; - uint32_t page; - void* buf; - uint32_t len; - uint32_t offset; -}; - -# Program NAND page interleaved -# -# Return values: -# 0: Success -# -METHOD int program_page_intlv { - device_t dev; - uint32_t page; - void* buf; - uint32_t len; - uint32_t offset; -} DEFAULT nand_method_not_supported; - -# Read NAND oob -# -# Return values: -# 0: Success -# -METHOD int read_oob { - device_t dev; - uint32_t page; - void* buf; - uint32_t len; - uint32_t offset; -}; - -# Program NAND oob -# -# Return values: -# 0: Success -# -METHOD int program_oob { - device_t dev; - uint32_t page; - void* buf; - uint32_t len; - uint32_t offset; -}; - -# Erase NAND block -# -# Return values: -# 0: Success -# -METHOD int erase_block { - device_t dev; - uint32_t block; -}; - -# Erase NAND block interleaved -# -# Return values: -# 0: Success -# -METHOD int erase_block_intlv { - device_t dev; - uint32_t block; -} DEFAULT nand_method_not_supported; - -# NAND get status -# -# Return values: -# 0: Success -# -METHOD int get_status { - device_t dev; - uint8_t *status; -}; - -# NAND check if block is bad -# -# Return values: -# 0: Success -# -METHOD int is_blk_bad { - device_t dev; - uint32_t block_number; - uint8_t *bad; -}; - -# NAND get ECC -# -# -METHOD int get_ecc { - device_t dev; - void *buf; - void *ecc; - int *needwrite; -}; - -# NAND correct ECC -# -# -METHOD int correct_ecc { - device_t dev; - void *buf; - void *readecc; - void *calcecc; -}; - diff --git a/sys/dev/nand/nandbus.c b/sys/dev/nand/nandbus.c deleted file mode 100644 index 003c1797af64..000000000000 --- a/sys/dev/nand/nandbus.c +++ /dev/null @@ -1,542 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "nand_if.h" -#include "nandbus_if.h" -#include "nfc_if.h" - -#define NAND_NCS 4 - -static int nandbus_probe(device_t dev); -static int nandbus_attach(device_t dev); -static int nandbus_detach(device_t dev); - -static int nandbus_child_location_str(device_t, device_t, char *, size_t); -static int nandbus_child_pnpinfo_str(device_t, device_t, char *, size_t); - -static int nandbus_get_status(device_t, uint8_t *); -static void nandbus_read_buffer(device_t, void *, uint32_t); -static int nandbus_select_cs(device_t, uint8_t); -static int nandbus_send_command(device_t, uint8_t); -static int nandbus_send_address(device_t, uint8_t); -static int nandbus_start_command(device_t); -static int nandbus_wait_ready(device_t, uint8_t *); -static void nandbus_write_buffer(device_t, void *, uint32_t); -static int nandbus_get_ecc(device_t, void *, uint32_t, void *, int *); -static int nandbus_correct_ecc(device_t, void *, int, void *, void *); -static void nandbus_lock(device_t); -static void nandbus_unlock(device_t); - -static int nand_readid(device_t, uint8_t *, uint8_t *); -static int nand_probe_onfi(device_t, uint8_t *); -static int nand_reset(device_t); - -struct nandbus_softc { - device_t dev; - struct cv nandbus_cv; - struct mtx nandbus_mtx; - uint8_t busy; -}; - -static device_method_t nandbus_methods[] = { - /* device interface */ - DEVMETHOD(device_probe, nandbus_probe), - DEVMETHOD(device_attach, nandbus_attach), - DEVMETHOD(device_detach, nandbus_detach), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - - /* bus interface */ - DEVMETHOD(bus_print_child, bus_generic_print_child), - DEVMETHOD(bus_driver_added, bus_generic_driver_added), - DEVMETHOD(bus_child_pnpinfo_str, nandbus_child_pnpinfo_str), - DEVMETHOD(bus_child_location_str, nandbus_child_location_str), - - /* nandbus interface */ - DEVMETHOD(nandbus_get_status, nandbus_get_status), - DEVMETHOD(nandbus_read_buffer, nandbus_read_buffer), - DEVMETHOD(nandbus_select_cs, nandbus_select_cs), - DEVMETHOD(nandbus_send_command, nandbus_send_command), - DEVMETHOD(nandbus_send_address, nandbus_send_address), - DEVMETHOD(nandbus_start_command,nandbus_start_command), - DEVMETHOD(nandbus_wait_ready, nandbus_wait_ready), - DEVMETHOD(nandbus_write_buffer, nandbus_write_buffer), - DEVMETHOD(nandbus_get_ecc, nandbus_get_ecc), - DEVMETHOD(nandbus_correct_ecc, nandbus_correct_ecc), - DEVMETHOD(nandbus_lock, nandbus_lock), - DEVMETHOD(nandbus_unlock, nandbus_unlock), - { 0, 0 } -}; - -devclass_t nandbus_devclass; - -driver_t nandbus_driver = { - "nandbus", - nandbus_methods, - sizeof(struct nandbus_softc) -}; - -DRIVER_MODULE(nandbus, nand, nandbus_driver, nandbus_devclass, 0, 0); - -int -nandbus_create(device_t nfc) -{ - device_t child; - - child = device_add_child(nfc, "nandbus", -1); - if (!child) - return (ENODEV); - - bus_generic_attach(nfc); - - return(0); -} - -void -nandbus_destroy(device_t nfc) -{ - device_t *children; - int nchildren, i; - - mtx_lock(&Giant); - /* Detach & delete all children */ - if (!device_get_children(nfc, &children, &nchildren)) { - for (i = 0; i < nchildren; i++) - device_delete_child(nfc, children[i]); - - free(children, M_TEMP); - } - mtx_unlock(&Giant); -} - -static int -nandbus_probe(device_t dev) -{ - - device_set_desc(dev, "NAND bus"); - - return (0); -} - -static int -nandbus_attach(device_t dev) -{ - device_t child, nfc; - struct nand_id chip_id; - struct nandbus_softc *sc; - struct nandbus_ivar *ivar; - struct nand_softc *nfc_sc; - struct nand_params *chip_params; - uint8_t cs, onfi; - - sc = device_get_softc(dev); - sc->dev = dev; - - nfc = device_get_parent(dev); - nfc_sc = device_get_softc(nfc); - - mtx_init(&sc->nandbus_mtx, "nandbus lock", NULL, MTX_DEF); - cv_init(&sc->nandbus_cv, "nandbus cv"); - - /* Check each possible CS for existing nand devices */ - for (cs = 0; cs < NAND_NCS; cs++) { - nand_debug(NDBG_BUS,"probe chip select %x", cs); - - /* Select & reset chip */ - if (nandbus_select_cs(dev, cs)) - break; - - if (nand_reset(dev)) - continue; - - /* Read manufacturer and device id */ - if (nand_readid(dev, &chip_id.man_id, &chip_id.dev_id)) - continue; - - if (chip_id.man_id == 0xff) - continue; - - /* - * First try to get info from the table. If that fails, see if - * the chip can provide ONFI info. We check the table first to - * allow table entries to override info from chips that are - * known to provide bad ONFI data. - */ - onfi = 0; - chip_params = nand_get_params(&chip_id); - if (chip_params == NULL) { - nand_probe_onfi(dev, &onfi); - } - - /* - * At this point it appears there is a chip at this chipselect, - * so if we can't work with it, whine about it. - */ - if (chip_params == NULL && onfi == 0) { - if (bootverbose || (nand_debug_flag & NDBG_BUS)) - printf("Chip params not found, chipsel: %d " - "(manuf: 0x%0x, chipid: 0x%0x, onfi: %d)\n", - cs, chip_id.man_id, chip_id.dev_id, onfi); - continue; - } - - ivar = malloc(sizeof(struct nandbus_ivar), - M_NAND, M_WAITOK); - - if (onfi == 1) { - ivar->cs = cs; - ivar->cols = 0; - ivar->rows = 0; - ivar->params = NULL; - ivar->man_id = chip_id.man_id; - ivar->dev_id = chip_id.dev_id; - ivar->is_onfi = onfi; - ivar->chip_cdev_name = nfc_sc->chip_cdev_name; - - child = device_add_child(dev, NULL, -1); - device_set_ivars(child, ivar); - continue; - } - - ivar->cs = cs; - ivar->cols = 1; - ivar->rows = 2; - ivar->params = chip_params; - ivar->man_id = chip_id.man_id; - ivar->dev_id = chip_id.dev_id; - ivar->is_onfi = onfi; - ivar->chip_cdev_name = nfc_sc->chip_cdev_name; - - /* - * Check what type of device we have. - * devices bigger than 32MiB have on more row (3) - */ - if (chip_params->chip_size > 32) - ivar->rows++; - /* Large page devices have one more col (2) */ - if (chip_params->chip_size >= 128 && - chip_params->page_size > 512) - ivar->cols++; - - child = device_add_child(dev, NULL, -1); - device_set_ivars(child, ivar); - } - - bus_generic_attach(dev); - return (0); -} - -static int -nandbus_detach(device_t dev) -{ - struct nandbus_softc *sc; - - sc = device_get_softc(dev); - - bus_generic_detach(dev); - - mtx_destroy(&sc->nandbus_mtx); - cv_destroy(&sc->nandbus_cv); - - return (0); -} - -static int -nandbus_child_location_str(device_t bus, device_t child, char *buf, - size_t buflen) -{ - struct nandbus_ivar *ivar = device_get_ivars(child); - - snprintf(buf, buflen, "at cs#%d", ivar->cs); - return (0); -} - -static int -nandbus_child_pnpinfo_str(device_t bus, device_t child, char *buf, - size_t buflen) -{ - // XXX man id, model id ???? - *buf = '\0'; - return (0); -} - -static int -nand_readid(device_t bus, uint8_t *man_id, uint8_t *dev_id) -{ - device_t nfc; - - if (!bus || !man_id || !dev_id) - return (EINVAL); - - nand_debug(NDBG_BUS,"read id"); - - nfc = device_get_parent(bus); - - if (NFC_SEND_COMMAND(nfc, NAND_CMD_READ_ID)) { - nand_debug(NDBG_BUS,"Error : could not send READ ID command"); - return (ENXIO); - } - - if (NFC_SEND_ADDRESS(nfc, 0)) { - nand_debug(NDBG_BUS,"Error : could not sent address to chip"); - return (ENXIO); - } - - if (NFC_START_COMMAND(nfc) != 0) { - nand_debug(NDBG_BUS,"Error : could not start command"); - return (ENXIO); - } - - DELAY(25); - - *man_id = NFC_READ_BYTE(nfc); - *dev_id = NFC_READ_BYTE(nfc); - - nand_debug(NDBG_BUS,"manufacturer id: %x chip id: %x", *man_id, - *dev_id); - - return (0); -} - -static int -nand_probe_onfi(device_t bus, uint8_t *onfi_compliant) -{ - device_t nfc; - char onfi_id[] = {'O', 'N', 'F', 'I', '\0'}; - int i; - - nand_debug(NDBG_BUS,"probing ONFI"); - - nfc = device_get_parent(bus); - - if (NFC_SEND_COMMAND(nfc, NAND_CMD_READ_ID)) { - nand_debug(NDBG_BUS,"Error : could not sent READ ID command"); - return (ENXIO); - } - - if (NFC_SEND_ADDRESS(nfc, ONFI_SIG_ADDR)) { - nand_debug(NDBG_BUS,"Error : could not sent address to chip"); - return (ENXIO); - } - - if (NFC_START_COMMAND(nfc) != 0) { - nand_debug(NDBG_BUS,"Error : could not start command"); - return (ENXIO); - } - for (i = 0; onfi_id[i] != '\0'; i++) - if (NFC_READ_BYTE(nfc) != onfi_id[i]) { - nand_debug(NDBG_BUS,"ONFI non-compliant"); - *onfi_compliant = 0; - return (0); - } - - nand_debug(NDBG_BUS,"ONFI compliant"); - *onfi_compliant = 1; - - return (0); -} - -static int -nand_reset(device_t bus) -{ - device_t nfc; - nand_debug(NDBG_BUS,"resetting..."); - - nfc = device_get_parent(bus); - - if (NFC_SEND_COMMAND(nfc, NAND_CMD_RESET) != 0) { - nand_debug(NDBG_BUS,"Error : could not sent RESET command"); - return (ENXIO); - } - - if (NFC_START_COMMAND(nfc) != 0) { - nand_debug(NDBG_BUS,"Error : could not start RESET command"); - return (ENXIO); - } - - DELAY(1000); - - return (0); -} - -void -nandbus_lock(device_t dev) -{ - struct nandbus_softc *sc; - - sc = device_get_softc(dev); - - mtx_lock(&sc->nandbus_mtx); - if (sc->busy) - cv_wait(&sc->nandbus_cv, &sc->nandbus_mtx); - sc->busy = 1; - mtx_unlock(&sc->nandbus_mtx); -} - -void -nandbus_unlock(device_t dev) -{ - struct nandbus_softc *sc; - - sc = device_get_softc(dev); - - mtx_lock(&sc->nandbus_mtx); - sc->busy = 0; - cv_signal(&sc->nandbus_cv); - mtx_unlock(&sc->nandbus_mtx); -} - -int -nandbus_select_cs(device_t dev, uint8_t cs) -{ - - return (NFC_SELECT_CS(device_get_parent(dev), cs)); -} - -int -nandbus_send_command(device_t dev, uint8_t command) -{ - int err; - - if ((err = NFC_SEND_COMMAND(device_get_parent(dev), command))) - nand_debug(NDBG_BUS,"Err: Could not send command %x, err %x", - command, err); - - return (err); -} - -int -nandbus_send_address(device_t dev, uint8_t address) -{ - int err; - - if ((err = NFC_SEND_ADDRESS(device_get_parent(dev), address))) - nand_debug(NDBG_BUS,"Err: Could not send address %x, err %x", - address, err); - - return (err); -} - -int -nandbus_start_command(device_t dev) -{ - int err; - - if ((err = NFC_START_COMMAND(device_get_parent(dev)))) - nand_debug(NDBG_BUS,"Err: Could not start command, err %x", - err); - - return (err); -} - -void -nandbus_read_buffer(device_t dev, void *buf, uint32_t len) -{ - - NFC_READ_BUF(device_get_parent(dev), buf, len); -} - -void -nandbus_write_buffer(device_t dev, void *buf, uint32_t len) -{ - - NFC_WRITE_BUF(device_get_parent(dev), buf, len); -} - -int -nandbus_get_status(device_t dev, uint8_t *status) -{ - int err; - - if ((err = NANDBUS_SEND_COMMAND(dev, NAND_CMD_STATUS))) - return (err); - if ((err = NANDBUS_START_COMMAND(dev))) - return (err); - - *status = NFC_READ_BYTE(device_get_parent(dev)); - - return (0); -} - -int -nandbus_wait_ready(device_t dev, uint8_t *status) -{ - struct timeval tv, tv2; - - tv2.tv_sec = 0; - tv2.tv_usec = 50 * 5000; /* 250ms */ - - getmicrotime(&tv); - timevaladd(&tv, &tv2); - - do { - if (NANDBUS_GET_STATUS(dev, status)) - return (ENXIO); - - if (*status & NAND_STATUS_RDY) - return (0); - - getmicrotime(&tv2); - } while (timevalcmp(&tv2, &tv, <=)); - - return (EBUSY); -} - -int -nandbus_get_ecc(device_t dev, void *buf, uint32_t pagesize, void *ecc, - int *needwrite) -{ - - return (NFC_GET_ECC(device_get_parent(dev), buf, pagesize, ecc, needwrite)); -} - -int -nandbus_correct_ecc(device_t dev, void *buf, int pagesize, void *readecc, - void *calcecc) -{ - - return (NFC_CORRECT_ECC(device_get_parent(dev), buf, pagesize, - readecc, calcecc)); -} - diff --git a/sys/dev/nand/nandbus.h b/sys/dev/nand/nandbus.h deleted file mode 100644 index 6dd4cbf26daa..000000000000 --- a/sys/dev/nand/nandbus.h +++ /dev/null @@ -1,51 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$ - */ - -#ifndef _NANDBUS_H_ -#define _NANDBUS_H_ - -struct nandbus_ivar { - uint8_t cs; - uint8_t cols; - uint8_t rows; - uint8_t man_id; - uint8_t dev_id; - uint8_t is_onfi; - char *chip_cdev_name; - struct nand_params *params; -}; - -extern devclass_t nandbus_devclass; -extern driver_t nandbus_driver; - -int nandbus_create(device_t nfc); -void nandbus_destroy(device_t nfc); - -#endif /* _NANDBUS_H_ */ diff --git a/sys/dev/nand/nandbus_if.m b/sys/dev/nand/nandbus_if.m deleted file mode 100644 index e914e18de661..000000000000 --- a/sys/dev/nand/nandbus_if.m +++ /dev/null @@ -1,100 +0,0 @@ -#- -# Copyright (C) 2009-2012 Semihalf -# 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$ - -# NAND bus interface description -# - -#include -#include - -INTERFACE nandbus; - -METHOD int get_status { - device_t dev; - uint8_t * status; -}; - -METHOD void read_buffer { - device_t dev; - void * buf; - uint32_t len; -}; - -METHOD int select_cs { - device_t dev; - uint8_t cs; -}; - -METHOD int send_command { - device_t dev; - uint8_t command; -}; - -METHOD int send_address { - device_t dev; - uint8_t address; -}; - -METHOD int start_command { - device_t dev; -}; - -METHOD int wait_ready { - device_t dev; - uint8_t * status; -} - -METHOD void write_buffer { - device_t dev; - void * buf; - uint32_t len; -}; - -METHOD int get_ecc { - device_t dev; - void * buf; - uint32_t pagesize; - void * ecc; - int * needwrite; -}; - -METHOD int correct_ecc { - device_t dev; - void * buf; - int pagesize; - void * readecc; - void * calcecc; -}; - -METHOD void lock { - device_t dev; -}; - -METHOD void unlock { - device_t dev; -}; - diff --git a/sys/dev/nand/nandsim.c b/sys/dev/nand/nandsim.c deleted file mode 100644 index 50e4f8bb2e33..000000000000 --- a/sys/dev/nand/nandsim.c +++ /dev/null @@ -1,670 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. - */ - -/* Simulated NAND controller driver */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -struct sim_param sim; -struct sim_ctrl_conf ctrls[MAX_SIM_DEV]; - -static struct cdev *nandsim_dev; -static d_ioctl_t nandsim_ioctl; - -static void nandsim_init_sim_param(struct sim_param *); -static int nandsim_create_ctrl(struct sim_ctrl *); -static int nandsim_destroy_ctrl(int); -static int nandsim_ctrl_status(struct sim_ctrl *); -static int nandsim_create_chip(struct sim_chip *); -static int nandsim_destroy_chip(struct sim_ctrl_chip *); -static int nandsim_chip_status(struct sim_chip *); -static int nandsim_start_ctrl(int); -static int nandsim_stop_ctrl(int); -static int nandsim_inject_error(struct sim_error *); -static int nandsim_get_block_state(struct sim_block_state *); -static int nandsim_set_block_state(struct sim_block_state *); -static int nandsim_modify(struct sim_mod *); -static int nandsim_dump(struct sim_dump *); -static int nandsim_restore(struct sim_dump *); -static int nandsim_freeze(struct sim_ctrl_chip *); -static void nandsim_print_log(struct sim_log *); -static struct nandsim_chip *get_nandsim_chip(uint8_t, uint8_t); - -static struct cdevsw nandsim_cdevsw = { - .d_version = D_VERSION, - .d_flags = D_NEEDGIANT, - .d_ioctl = nandsim_ioctl, - .d_name = "nandsim", -}; - -int -nandsim_ioctl(struct cdev *dev, u_long cmd, caddr_t data, - int flags, struct thread *td) -{ - int ret = 0; - - switch (cmd) { - case NANDSIM_SIM_PARAM: - nandsim_init_sim_param((struct sim_param *)data); - break; - case NANDSIM_CREATE_CTRL: - ret = nandsim_create_ctrl((struct sim_ctrl *)data); - break; - case NANDSIM_DESTROY_CTRL: - ret = nandsim_destroy_ctrl(*(int *)data); - break; - case NANDSIM_STATUS_CTRL: - ret = nandsim_ctrl_status((struct sim_ctrl *)data); - break; - case NANDSIM_CREATE_CHIP: - ret = nandsim_create_chip((struct sim_chip *)data); - break; - case NANDSIM_DESTROY_CHIP: - ret = nandsim_destroy_chip((struct sim_ctrl_chip *)data); - break; - case NANDSIM_STATUS_CHIP: - ret = nandsim_chip_status((struct sim_chip *)data); - break; - case NANDSIM_MODIFY: - ret = nandsim_modify((struct sim_mod *)data); - break; - case NANDSIM_START_CTRL: - ret = nandsim_start_ctrl(*(int *)data); - break; - case NANDSIM_STOP_CTRL: - ret = nandsim_stop_ctrl(*(int *)data); - break; - case NANDSIM_INJECT_ERROR: - ret = nandsim_inject_error((struct sim_error *)data); - break; - case NANDSIM_SET_BLOCK_STATE: - ret = nandsim_set_block_state((struct sim_block_state *)data); - break; - case NANDSIM_GET_BLOCK_STATE: - ret = nandsim_get_block_state((struct sim_block_state *)data); - break; - case NANDSIM_PRINT_LOG: - nandsim_print_log((struct sim_log *)data); - break; - case NANDSIM_DUMP: - ret = nandsim_dump((struct sim_dump *)data); - break; - case NANDSIM_RESTORE: - ret = nandsim_restore((struct sim_dump *)data); - break; - case NANDSIM_FREEZE: - ret = nandsim_freeze((struct sim_ctrl_chip *)data); - break; - default: - ret = EINVAL; - break; - } - - return (ret); -} - -static void -nandsim_init_sim_param(struct sim_param *param) -{ - - if (!param) - return; - - nand_debug(NDBG_SIM,"log level:%d output %d", param->log_level, - param->log_output); - nandsim_log_level = param->log_level; - nandsim_log_output = param->log_output; -} - -static int -nandsim_create_ctrl(struct sim_ctrl *ctrl) -{ - struct sim_ctrl_conf *sim_ctrl; - - nand_debug(NDBG_SIM,"create controller num:%d cs:%d",ctrl->num, - ctrl->num_cs); - - if (ctrl->num >= MAX_SIM_DEV) { - return (EINVAL); - } - - sim_ctrl = &ctrls[ctrl->num]; - if(sim_ctrl->created) - return (EEXIST); - - sim_ctrl->num = ctrl->num; - sim_ctrl->num_cs = ctrl->num_cs; - sim_ctrl->ecc = ctrl->ecc; - memcpy(sim_ctrl->ecc_layout, ctrl->ecc_layout, - MAX_ECC_BYTES * sizeof(ctrl->ecc_layout[0])); - strlcpy(sim_ctrl->filename, ctrl->filename, - FILENAME_SIZE); - sim_ctrl->created = 1; - - return (0); -} - -static int -nandsim_destroy_ctrl(int ctrl_num) -{ - - nand_debug(NDBG_SIM,"destroy controller num:%d", ctrl_num); - - if (ctrl_num >= MAX_SIM_DEV) { - return (EINVAL); - } - - if (!ctrls[ctrl_num].created) { - return (ENODEV); - } - - if (ctrls[ctrl_num].running) { - return (EBUSY); - } - - memset(&ctrls[ctrl_num], 0, sizeof(ctrls[ctrl_num])); - - return (0); -} - -static int -nandsim_ctrl_status(struct sim_ctrl *ctrl) -{ - - nand_debug(NDBG_SIM,"status controller num:%d cs:%d",ctrl->num, - ctrl->num_cs); - - if (ctrl->num >= MAX_SIM_DEV) { - return (EINVAL); - } - - ctrl->num_cs = ctrls[ctrl->num].num_cs; - ctrl->ecc = ctrls[ctrl->num].ecc; - memcpy(ctrl->ecc_layout, ctrls[ctrl->num].ecc_layout, - MAX_ECC_BYTES * sizeof(ctrl->ecc_layout[0])); - strlcpy(ctrl->filename, ctrls[ctrl->num].filename, - FILENAME_SIZE); - ctrl->running = ctrls[ctrl->num].running; - ctrl->created = ctrls[ctrl->num].created; - - return (0); -} - -static int -nandsim_create_chip(struct sim_chip *chip) -{ - struct sim_chip *sim_chip; - - nand_debug(NDBG_SIM,"create chip num:%d at ctrl:%d", chip->num, - chip->ctrl_num); - - if (chip->ctrl_num >= MAX_SIM_DEV || - chip->num >= MAX_CTRL_CS) { - return (EINVAL); - } - - if (ctrls[chip->ctrl_num].chips[chip->num]) { - return (EEXIST); - } - - sim_chip = malloc(sizeof(*sim_chip), M_NANDSIM, - M_WAITOK); - if (sim_chip == NULL) { - return (ENOMEM); - } - - memcpy(sim_chip, chip, sizeof(*sim_chip)); - ctrls[chip->ctrl_num].chips[chip->num] = sim_chip; - sim_chip->created = 1; - - return (0); -} - -static int -nandsim_destroy_chip(struct sim_ctrl_chip *chip) -{ - struct sim_ctrl_conf *ctrl_conf; - - nand_debug(NDBG_SIM,"destroy chip num:%d at ctrl:%d", chip->chip_num, - chip->ctrl_num); - - if (chip->ctrl_num >= MAX_SIM_DEV || - chip->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - ctrl_conf = &ctrls[chip->ctrl_num]; - - if (!ctrl_conf->created || !ctrl_conf->chips[chip->chip_num]) - return (ENODEV); - - if (ctrl_conf->running) - return (EBUSY); - - free(ctrl_conf->chips[chip->chip_num], M_NANDSIM); - ctrl_conf->chips[chip->chip_num] = NULL; - - return (0); -} - -static int -nandsim_chip_status(struct sim_chip *chip) -{ - struct sim_ctrl_conf *ctrl_conf; - - nand_debug(NDBG_SIM,"status for chip num:%d at ctrl:%d", chip->num, - chip->ctrl_num); - - if (chip->ctrl_num >= MAX_SIM_DEV || - chip->num >= MAX_CTRL_CS) - return (EINVAL); - - ctrl_conf = &ctrls[chip->ctrl_num]; - if (!ctrl_conf->chips[chip->num]) - chip->created = 0; - else - memcpy(chip, ctrl_conf->chips[chip->num], sizeof(*chip)); - - return (0); -} - -static int -nandsim_start_ctrl(int num) -{ - device_t nexus, ndev; - devclass_t nexus_devclass; - int ret = 0; - - nand_debug(NDBG_SIM,"start ctlr num:%d", num); - - if (num >= MAX_SIM_DEV) - return (EINVAL); - - if (!ctrls[num].created) - return (ENODEV); - - if (ctrls[num].running) - return (EBUSY); - - /* We will add our device as a child of the nexus0 device */ - if (!(nexus_devclass = devclass_find("nexus")) || - !(nexus = devclass_get_device(nexus_devclass, 0))) - return (EFAULT); - - /* - * Create a newbus device representing this frontend instance - * - * XXX powerpc nexus doesn't implement bus_add_child, so child - * must be added by device_add_child(). - */ -#if defined(__powerpc__) - ndev = device_add_child(nexus, "nandsim", num); -#else - ndev = BUS_ADD_CHILD(nexus, 0, "nandsim", num); -#endif - if (!ndev) - return (EFAULT); - - mtx_lock(&Giant); - ret = device_probe_and_attach(ndev); - mtx_unlock(&Giant); - - if (ret == 0) { - ctrls[num].sim_ctrl_dev = ndev; - ctrls[num].running = 1; - } - - return (ret); -} - -static int -nandsim_stop_ctrl(int num) -{ - device_t nexus; - devclass_t nexus_devclass; - int ret = 0; - - nand_debug(NDBG_SIM,"stop controller num:%d", num); - - if (num >= MAX_SIM_DEV) { - return (EINVAL); - } - - if (!ctrls[num].created || !ctrls[num].running) { - return (ENODEV); - } - - /* We will add our device as a child of the nexus0 device */ - if (!(nexus_devclass = devclass_find("nexus")) || - !(nexus = devclass_get_device(nexus_devclass, 0))) { - return (ENODEV); - } - - mtx_lock(&Giant); - if (ctrls[num].sim_ctrl_dev) { - ret = device_delete_child(nexus, ctrls[num].sim_ctrl_dev); - ctrls[num].sim_ctrl_dev = NULL; - } - mtx_unlock(&Giant); - - ctrls[num].running = 0; - - return (ret); -} - -static struct nandsim_chip * -get_nandsim_chip(uint8_t ctrl_num, uint8_t chip_num) -{ - struct nandsim_softc *sc; - - if (!ctrls[ctrl_num].sim_ctrl_dev) - return (NULL); - - sc = device_get_softc(ctrls[ctrl_num].sim_ctrl_dev); - return (sc->chips[chip_num]); -} - -static void -nandsim_print_log(struct sim_log *sim_log) -{ - struct nandsim_softc *sc; - int len1, len2; - - if (!ctrls[sim_log->ctrl_num].sim_ctrl_dev) - return; - - sc = device_get_softc(ctrls[sim_log->ctrl_num].sim_ctrl_dev); - if (sc->log_buff) { - len1 = strlen(&sc->log_buff[sc->log_idx + 1]); - if (len1 >= sim_log->len) - len1 = sim_log->len; - copyout(&sc->log_buff[sc->log_idx + 1], sim_log->log, len1); - len2 = strlen(sc->log_buff); - if (len2 >= (sim_log->len - len1)) - len2 = (sim_log->len - len1); - copyout(sc->log_buff, &sim_log->log[len1], len2); - sim_log->len = len1 + len2; - } -} - -static int -nandsim_inject_error(struct sim_error *error) -{ - struct nandsim_chip *chip; - struct block_space *bs; - struct onfi_params *param; - int page, page_size, block, offset; - - nand_debug(NDBG_SIM,"inject error for chip %d at ctrl %d\n", - error->chip_num, error->ctrl_num); - - if (error->ctrl_num >= MAX_SIM_DEV || - error->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - if (!ctrls[error->ctrl_num].created || !ctrls[error->ctrl_num].running) - return (ENODEV); - - chip = get_nandsim_chip(error->ctrl_num, error->chip_num); - param = &chip->params; - page_size = param->bytes_per_page + param->spare_bytes_per_page; - block = error->page_num / param->pages_per_block; - page = error->page_num % param->pages_per_block; - - bs = get_bs(chip->swap, block, 1); - if (!bs) - return (EINVAL); - - offset = (page * page_size) + error->column; - memset(&bs->blk_ptr[offset], error->pattern, error->len); - - return (0); -} - -static int -nandsim_set_block_state(struct sim_block_state *bs) -{ - struct onfi_params *params; - struct nandsim_chip *chip; - int blocks; - - nand_debug(NDBG_SIM,"set block state for %d:%d block %d\n", - bs->chip_num, bs->ctrl_num, bs->block_num); - - if (bs->ctrl_num >= MAX_SIM_DEV || - bs->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - chip = get_nandsim_chip(bs->ctrl_num, bs->chip_num); - params = &chip->params; - blocks = params->luns * params->blocks_per_lun; - - if (bs->block_num > blocks) - return (EINVAL); - - chip->blk_state[bs->block_num].is_bad = bs->state; - - if (bs->wearout >= 0) - chip->blk_state[bs->block_num].wear_lev = bs->wearout; - - return (0); -} - -static int -nandsim_get_block_state(struct sim_block_state *bs) -{ - struct onfi_params *params; - struct nandsim_chip *chip; - int blocks; - - if (bs->ctrl_num >= MAX_SIM_DEV || - bs->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - nand_debug(NDBG_SIM,"get block state for %d:%d block %d\n", - bs->chip_num, bs->ctrl_num, bs->block_num); - - chip = get_nandsim_chip(bs->ctrl_num, bs->chip_num); - params = &chip->params; - blocks = params->luns * params->blocks_per_lun; - - if (bs->block_num > blocks) - return (EINVAL); - - bs->state = chip->blk_state[bs->block_num].is_bad; - bs->wearout = chip->blk_state[bs->block_num].wear_lev; - - return (0); -} - -static int -nandsim_dump(struct sim_dump *dump) -{ - struct nandsim_chip *chip; - struct block_space *bs; - int blk_size; - - nand_debug(NDBG_SIM,"dump chip %d %d\n", dump->ctrl_num, dump->chip_num); - - if (dump->ctrl_num >= MAX_SIM_DEV || - dump->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - chip = get_nandsim_chip(dump->ctrl_num, dump->chip_num); - blk_size = chip->cg.block_size + - (chip->cg.oob_size * chip->cg.pgs_per_blk); - - bs = get_bs(chip->swap, dump->block_num, 0); - if (!bs) - return (EINVAL); - - if (dump->len > blk_size) - dump->len = blk_size; - - copyout(bs->blk_ptr, dump->data, dump->len); - - return (0); -} - -static int -nandsim_restore(struct sim_dump *dump) -{ - struct nandsim_chip *chip; - struct block_space *bs; - int blk_size; - - nand_debug(NDBG_SIM,"restore chip %d %d\n", dump->ctrl_num, - dump->chip_num); - - if (dump->ctrl_num >= MAX_SIM_DEV || - dump->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - chip = get_nandsim_chip(dump->ctrl_num, dump->chip_num); - blk_size = chip->cg.block_size + - (chip->cg.oob_size * chip->cg.pgs_per_blk); - - bs = get_bs(chip->swap, dump->block_num, 1); - if (!bs) - return (EINVAL); - - if (dump->len > blk_size) - dump->len = blk_size; - - - copyin(dump->data, bs->blk_ptr, dump->len); - - return (0); -} - -static int -nandsim_freeze(struct sim_ctrl_chip *ctrl_chip) -{ - struct nandsim_chip *chip; - - if (ctrl_chip->ctrl_num >= MAX_SIM_DEV || - ctrl_chip->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - chip = get_nandsim_chip(ctrl_chip->ctrl_num, ctrl_chip->chip_num); - nandsim_chip_freeze(chip); - - return (0); -} - -static int -nandsim_modify(struct sim_mod *mod) -{ - struct sim_chip *sim_conf = NULL; - struct nandsim_chip *sim_chip = NULL; - - nand_debug(NDBG_SIM,"modify ctlr %d chip %d", mod->ctrl_num, - mod->chip_num); - - if (mod->field != SIM_MOD_LOG_LEVEL) { - if (mod->ctrl_num >= MAX_SIM_DEV || - mod->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - sim_conf = ctrls[mod->ctrl_num].chips[mod->chip_num]; - sim_chip = get_nandsim_chip(mod->ctrl_num, mod->chip_num); - } - - switch (mod->field) { - case SIM_MOD_LOG_LEVEL: - nandsim_log_level = mod->new_value; - break; - case SIM_MOD_ERASE_TIME: - sim_conf->erase_time = sim_chip->erase_delay = mod->new_value; - break; - case SIM_MOD_PROG_TIME: - sim_conf->prog_time = sim_chip->prog_delay = mod->new_value; - break; - case SIM_MOD_READ_TIME: - sim_conf->read_time = sim_chip->read_delay = mod->new_value; - break; - case SIM_MOD_ERROR_RATIO: - sim_conf->error_ratio = mod->new_value; - sim_chip->error_ratio = mod->new_value; - break; - default: - break; - } - - return (0); -} -static int -nandsim_modevent(module_t mod __unused, int type, void *data __unused) -{ - struct sim_ctrl_chip chip_ctrl; - int i, j; - - switch (type) { - case MOD_LOAD: - nandsim_dev = make_dev(&nandsim_cdevsw, 0, - UID_ROOT, GID_WHEEL, 0600, "nandsim.ioctl"); - break; - case MOD_UNLOAD: - for (i = 0; i < MAX_SIM_DEV; i++) { - nandsim_stop_ctrl(i); - chip_ctrl.ctrl_num = i; - for (j = 0; j < MAX_CTRL_CS; j++) { - chip_ctrl.chip_num = j; - nandsim_destroy_chip(&chip_ctrl); - } - nandsim_destroy_ctrl(i); - } - destroy_dev(nandsim_dev); - break; - case MOD_SHUTDOWN: - break; - default: - return (EOPNOTSUPP); - } - return (0); -} - -DEV_MODULE(nandsim, nandsim_modevent, NULL); -MODULE_VERSION(nandsim, 1); -MODULE_DEPEND(nandsim, nand, 1, 1, 1); -MODULE_DEPEND(nandsim, alq, 1, 1, 1); diff --git a/sys/dev/nand/nandsim.h b/sys/dev/nand/nandsim.h deleted file mode 100644 index d4b225113bfd..000000000000 --- a/sys/dev/nand/nandsim.h +++ /dev/null @@ -1,177 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$ - */ - -#ifndef _NANDSIM_H_ -#define _NANDSIM_H_ - -#include -#include - -#define MAX_SIM_DEV 4 -#define MAX_CTRL_CS 4 -#define MAX_ECC_BYTES 512 -#define MAX_BAD_BLOCKS 512 -#define DEV_MODEL_STR_SIZE 21 -#define MAN_STR_SIZE 13 -#define FILENAME_SIZE 20 - -#define MAX_CHIPS (MAX_SIM_DEV*MAX_CTRL_CS) - -#define NANDSIM_OUTPUT_NONE 0x0 -#define NANDSIM_OUTPUT_CONSOLE 0x1 -#define NANDSIM_OUTPUT_RAM 0x2 -#define NANDSIM_OUTPUT_FILE 0x3 - -struct sim_ctrl_chip { - uint8_t ctrl_num; - uint8_t chip_num; -}; - -#define NANDSIM_BASE 'A' - -struct sim_param { - uint8_t log_level; - uint8_t log_output; -}; - -#define NANDSIM_SIM_PARAM _IOW(NANDSIM_BASE, 1, struct sim_param) - -struct sim_ctrl { - uint8_t running; - uint8_t created; - uint8_t num; - uint8_t num_cs; - uint8_t ecc; - char filename[FILENAME_SIZE]; - uint16_t ecc_layout[MAX_ECC_BYTES]; -}; -#define NANDSIM_CREATE_CTRL _IOW(NANDSIM_BASE, 2, struct sim_ctrl) -#define NANDSIM_DESTROY_CTRL _IOW(NANDSIM_BASE, 3, int) - -struct sim_chip { - uint8_t num; - uint8_t ctrl_num; - uint8_t created; - uint8_t device_id; - uint8_t manufact_id; - char device_model[DEV_MODEL_STR_SIZE]; - char manufacturer[MAN_STR_SIZE]; - uint8_t col_addr_cycles; - uint8_t row_addr_cycles; - uint8_t features; - uint8_t width; - uint32_t page_size; - uint32_t oob_size; - uint32_t pgs_per_blk; - uint32_t blks_per_lun; - uint32_t luns; - - uint32_t prog_time; - uint32_t erase_time; - uint32_t read_time; - uint32_t ccs_time; - - uint32_t error_ratio; - uint32_t wear_level; - uint32_t bad_block_map[MAX_BAD_BLOCKS]; - uint8_t is_wp; -}; - -#define NANDSIM_CREATE_CHIP _IOW(NANDSIM_BASE, 3, struct sim_chip) - -struct sim_chip_destroy { - uint8_t ctrl_num; - uint8_t chip_num; -}; -#define NANDSIM_DESTROY_CHIP _IOW(NANDSIM_BASE, 4, struct sim_chip_destroy) - -#define NANDSIM_START_CTRL _IOW(NANDSIM_BASE, 5, int) -#define NANDSIM_STOP_CTRL _IOW(NANDSIM_BASE, 6, int) -#define NANDSIM_RESTART_CTRL _IOW(NANDSIM_BASE, 7, int) - -#define NANDSIM_STATUS_CTRL _IOWR(NANDSIM_BASE, 8, struct sim_ctrl) -#define NANDSIM_STATUS_CHIP _IOWR(NANDSIM_BASE, 9, struct sim_chip) - -struct sim_mod { - uint8_t chip_num; - uint8_t ctrl_num; - uint32_t field; - uint32_t new_value; -}; -#define SIM_MOD_LOG_LEVEL 0 -#define SIM_MOD_ERASE_TIME 1 -#define SIM_MOD_PROG_TIME 2 -#define SIM_MOD_READ_TIME 3 -#define SIM_MOD_CCS_TIME 4 -#define SIM_MOD_ERROR_RATIO 5 - -#define NANDSIM_MODIFY _IOW(NANDSIM_BASE, 10, struct sim_mod) -#define NANDSIM_FREEZE _IOW(NANDSIM_BASE, 11, struct sim_ctrl_chip) - -struct sim_error { - uint8_t ctrl_num; - uint8_t chip_num; - uint32_t page_num; - uint32_t column; - uint32_t len; - uint32_t pattern; -}; -#define NANDSIM_INJECT_ERROR _IOW(NANDSIM_BASE, 20, struct sim_error) - -#define NANDSIM_GOOD_BLOCK 0 -#define NANDSIM_BAD_BLOCK 1 -struct sim_block_state { - uint8_t ctrl_num; - uint8_t chip_num; - uint32_t block_num; - int wearout; - uint8_t state; -}; -#define NANDSIM_SET_BLOCK_STATE _IOW(NANDSIM_BASE, 21, struct sim_block_state) -#define NANDSIM_GET_BLOCK_STATE _IOWR(NANDSIM_BASE, 22, struct sim_block_state) - -struct sim_log { - uint8_t ctrl_num; - char* log; - size_t len; -}; -#define NANDSIM_PRINT_LOG _IOWR(NANDSIM_BASE, 23, struct sim_log) - -struct sim_dump { - uint8_t ctrl_num; - uint8_t chip_num; - uint32_t block_num; - uint32_t len; - void* data; -}; -#define NANDSIM_DUMP _IOWR(NANDSIM_BASE, 24, struct sim_dump) -#define NANDSIM_RESTORE _IOWR(NANDSIM_BASE, 25, struct sim_dump) - -#endif /* _NANDSIM_H_ */ diff --git a/sys/dev/nand/nandsim_chip.c b/sys/dev/nand/nandsim_chip.c deleted file mode 100644 index b7ab83b9d208..000000000000 --- a/sys/dev/nand/nandsim_chip.c +++ /dev/null @@ -1,898 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -MALLOC_DEFINE(M_NANDSIM, "NANDsim", "NANDsim dynamic data"); - -#define NANDSIM_CHIP_LOCK(chip) mtx_lock(&(chip)->ns_lock) -#define NANDSIM_CHIP_UNLOCK(chip) mtx_unlock(&(chip)->ns_lock) - -static nandsim_evh_t erase_evh; -static nandsim_evh_t idle_evh; -static nandsim_evh_t poweron_evh; -static nandsim_evh_t reset_evh; -static nandsim_evh_t read_evh; -static nandsim_evh_t readid_evh; -static nandsim_evh_t readparam_evh; -static nandsim_evh_t write_evh; - -static void nandsim_loop(void *); -static void nandsim_undefined(struct nandsim_chip *, uint8_t); -static void nandsim_bad_address(struct nandsim_chip *, uint8_t *); -static void nandsim_ignore_address(struct nandsim_chip *, uint8_t); -static void nandsim_sm_error(struct nandsim_chip *); -static void nandsim_start_handler(struct nandsim_chip *, nandsim_evh_t); - -static void nandsim_callout_eh(void *); -static int nandsim_delay(struct nandsim_chip *, int); - -static int nandsim_bbm_init(struct nandsim_chip *, uint32_t, uint32_t *); -static int nandsim_blk_state_init(struct nandsim_chip *, uint32_t, uint32_t); -static void nandsim_blk_state_destroy(struct nandsim_chip *); -static int nandchip_is_block_valid(struct nandsim_chip *, int); - -static void nandchip_set_status(struct nandsim_chip *, uint8_t); -static void nandchip_clear_status(struct nandsim_chip *, uint8_t); - -struct proc *nandsim_proc; - -struct nandsim_chip * -nandsim_chip_init(struct nandsim_softc* sc, uint8_t chip_num, - struct sim_chip *sim_chip) -{ - struct nandsim_chip *chip; - struct onfi_params *chip_param; - char swapfile[20]; - uint32_t size; - int error; - - chip = malloc(sizeof(*chip), M_NANDSIM, M_WAITOK | M_ZERO); - - mtx_init(&chip->ns_lock, "nandsim lock", NULL, MTX_DEF); - callout_init(&chip->ns_callout, 1); - STAILQ_INIT(&chip->nandsim_events); - - chip->chip_num = chip_num; - chip->ctrl_num = sim_chip->ctrl_num; - chip->sc = sc; - - if (!sim_chip->is_wp) - nandchip_set_status(chip, NAND_STATUS_WP); - - chip_param = &chip->params; - - chip->id.dev_id = sim_chip->device_id; - chip->id.man_id = sim_chip->manufact_id; - - chip->error_ratio = sim_chip->error_ratio; - chip->wear_level = sim_chip->wear_level; - chip->prog_delay = sim_chip->prog_time; - chip->erase_delay = sim_chip->erase_time; - chip->read_delay = sim_chip->read_time; - - chip_param->t_prog = sim_chip->prog_time; - chip_param->t_bers = sim_chip->erase_time; - chip_param->t_r = sim_chip->read_time; - bcopy("onfi", &chip_param->signature, 4); - - chip_param->manufacturer_id = sim_chip->manufact_id; - strncpy(chip_param->manufacturer_name, sim_chip->manufacturer, 12); - chip_param->manufacturer_name[11] = 0; - strncpy(chip_param->device_model, sim_chip->device_model, 20); - chip_param->device_model[19] = 0; - - chip_param->bytes_per_page = sim_chip->page_size; - chip_param->spare_bytes_per_page = sim_chip->oob_size; - chip_param->pages_per_block = sim_chip->pgs_per_blk; - chip_param->blocks_per_lun = sim_chip->blks_per_lun; - chip_param->luns = sim_chip->luns; - - init_chip_geom(&chip->cg, chip_param->luns, chip_param->blocks_per_lun, - chip_param->pages_per_block, chip_param->bytes_per_page, - chip_param->spare_bytes_per_page); - - chip_param->address_cycles = sim_chip->row_addr_cycles | - (sim_chip->col_addr_cycles << 4); - chip_param->features = sim_chip->features; - if (sim_chip->width == 16) - chip_param->features |= ONFI_FEAT_16BIT; - - size = chip_param->blocks_per_lun * chip_param->luns; - - error = nandsim_blk_state_init(chip, size, sim_chip->wear_level); - if (error) { - mtx_destroy(&chip->ns_lock); - free(chip, M_NANDSIM); - return (NULL); - } - - error = nandsim_bbm_init(chip, size, sim_chip->bad_block_map); - if (error) { - mtx_destroy(&chip->ns_lock); - nandsim_blk_state_destroy(chip); - free(chip, M_NANDSIM); - return (NULL); - } - - nandsim_start_handler(chip, poweron_evh); - - nand_debug(NDBG_SIM,"Create thread for chip%d [%8p]", chip->chip_num, - chip); - /* Create chip thread */ - error = kproc_kthread_add(nandsim_loop, chip, &nandsim_proc, - &chip->nandsim_td, RFSTOPPED | RFHIGHPID, - 0, "nandsim", "chip"); - if (error) { - mtx_destroy(&chip->ns_lock); - nandsim_blk_state_destroy(chip); - free(chip, M_NANDSIM); - return (NULL); - } - - thread_lock(chip->nandsim_td); - sched_class(chip->nandsim_td, PRI_REALTIME); - sched_add(chip->nandsim_td, SRQ_BORING); - thread_unlock(chip->nandsim_td); - - size = (chip_param->bytes_per_page + - chip_param->spare_bytes_per_page) * - chip_param->pages_per_block; - - sprintf(swapfile, "chip%d%d.swp", chip->ctrl_num, chip->chip_num); - chip->swap = nandsim_swap_init(swapfile, chip_param->blocks_per_lun * - chip_param->luns, size); - if (!chip->swap) - nandsim_chip_destroy(chip); - - /* Wait for new thread to enter main loop */ - tsleep(chip->nandsim_td, PWAIT, "ns_chip", 1 * hz); - - return (chip); -} - -static int -nandsim_blk_state_init(struct nandsim_chip *chip, uint32_t size, - uint32_t wear_lev) -{ - int i; - - if (!chip || size == 0) - return (-1); - - chip->blk_state = malloc(size * sizeof(struct nandsim_block_state), - M_NANDSIM, M_WAITOK | M_ZERO); - - for (i = 0; i < size; i++) { - if (wear_lev) - chip->blk_state[i].wear_lev = wear_lev; - else - chip->blk_state[i].wear_lev = -1; - } - - return (0); -} - -static void -nandsim_blk_state_destroy(struct nandsim_chip *chip) -{ - - if (chip && chip->blk_state) - free(chip->blk_state, M_NANDSIM); -} - -static int -nandsim_bbm_init(struct nandsim_chip *chip, uint32_t size, - uint32_t *sim_bbm) -{ - uint32_t index; - int i; - - if ((chip == NULL) || (size == 0)) - return (-1); - - if (chip->blk_state == NULL) - return (-1); - - if (sim_bbm == NULL) - return (0); - - for (i = 0; i < MAX_BAD_BLOCKS; i++) { - index = sim_bbm[i]; - - if (index == 0xffffffff) - break; - else if (index > size) - return (-1); - else - chip->blk_state[index].is_bad = 1; - } - - return (0); -} - -void -nandsim_chip_destroy(struct nandsim_chip *chip) -{ - struct nandsim_ev *ev; - - ev = create_event(chip, NANDSIM_EV_EXIT, 0); - if (ev) - send_event(ev); -} - -void -nandsim_chip_freeze(struct nandsim_chip *chip) -{ - - chip->flags |= NANDSIM_CHIP_FROZEN; -} - -static void -nandsim_loop(void *arg) -{ - struct nandsim_chip *chip = (struct nandsim_chip *)arg; - struct nandsim_ev *ev; - - nand_debug(NDBG_SIM,"Start main loop for chip%d [%8p]", chip->chip_num, - chip); - for(;;) { - NANDSIM_CHIP_LOCK(chip); - if (!(chip->flags & NANDSIM_CHIP_ACTIVE)) { - chip->flags |= NANDSIM_CHIP_ACTIVE; - wakeup(chip->nandsim_td); - } - - if (STAILQ_EMPTY(&chip->nandsim_events)) { - nand_debug(NDBG_SIM,"Chip%d [%8p] going sleep", - chip->chip_num, chip); - msleep(chip, &chip->ns_lock, PRIBIO, "nandev", 0); - } - - ev = STAILQ_FIRST(&chip->nandsim_events); - STAILQ_REMOVE_HEAD(&chip->nandsim_events, links); - NANDSIM_CHIP_UNLOCK(chip); - if (ev->type == NANDSIM_EV_EXIT) { - NANDSIM_CHIP_LOCK(chip); - destroy_event(ev); - wakeup(ev); - while (!STAILQ_EMPTY(&chip->nandsim_events)) { - ev = STAILQ_FIRST(&chip->nandsim_events); - STAILQ_REMOVE_HEAD(&chip->nandsim_events, - links); - destroy_event(ev); - wakeup(ev); - } - NANDSIM_CHIP_UNLOCK(chip); - nandsim_log(chip, NANDSIM_LOG_SM, "destroyed\n"); - mtx_destroy(&chip->ns_lock); - nandsim_blk_state_destroy(chip); - nandsim_swap_destroy(chip->swap); - free(chip, M_NANDSIM); - nandsim_proc = NULL; - - kthread_exit(); - } - - if (!(chip->flags & NANDSIM_CHIP_FROZEN)) { - nand_debug(NDBG_SIM,"Chip [%x] get event [%x]", - chip->chip_num, ev->type); - chip->ev_handler(chip, ev->type, ev->data); - } - - wakeup(ev); - destroy_event(ev); - } - -} - -struct nandsim_ev * -create_event(struct nandsim_chip *chip, uint8_t type, uint8_t data_size) -{ - struct nandsim_ev *ev; - - ev = malloc(sizeof(*ev), M_NANDSIM, M_NOWAIT | M_ZERO); - if (!ev) { - nand_debug(NDBG_SIM,"Cannot create event"); - return (NULL); - } - - if (data_size > 0) - ev->data = malloc(sizeof(*ev), M_NANDSIM, M_NOWAIT | M_ZERO); - ev->type = type; - ev->chip = chip; - - return (ev); -} - -void -destroy_event(struct nandsim_ev *ev) -{ - - if (ev->data) - free(ev->data, M_NANDSIM); - free(ev, M_NANDSIM); -} - -int -send_event(struct nandsim_ev *ev) -{ - struct nandsim_chip *chip = ev->chip; - - if (!(chip->flags & NANDSIM_CHIP_FROZEN)) { - nand_debug(NDBG_SIM,"Chip%d [%p] send event %x", - chip->chip_num, chip, ev->type); - - NANDSIM_CHIP_LOCK(chip); - STAILQ_INSERT_TAIL(&chip->nandsim_events, ev, links); - NANDSIM_CHIP_UNLOCK(chip); - - wakeup(chip); - if ((ev->type != NANDSIM_EV_TIMEOUT) && chip->nandsim_td && - (curthread != chip->nandsim_td)) - tsleep(ev, PWAIT, "ns_ev", 5 * hz); - } - - return (0); -} - -static void -nandsim_callout_eh(void *arg) -{ - struct nandsim_ev *ev = (struct nandsim_ev *)arg; - - send_event(ev); -} - -static int -nandsim_delay(struct nandsim_chip *chip, int timeout) -{ - struct nandsim_ev *ev; - struct timeval delay; - int tm; - - nand_debug(NDBG_SIM,"Chip[%d] Set delay: %d", chip->chip_num, timeout); - - ev = create_event(chip, NANDSIM_EV_TIMEOUT, 0); - if (!ev) - return (-1); - - chip->sm_state = NANDSIM_STATE_TIMEOUT; - tm = (timeout/10000) * (hz / 100); - if (callout_reset(&chip->ns_callout, tm, nandsim_callout_eh, ev)) - return (-1); - - delay.tv_sec = chip->read_delay / 1000000; - delay.tv_usec = chip->read_delay % 1000000; - timevaladd(&chip->delay_tv, &delay); - - return (0); -} - -static void -nandsim_start_handler(struct nandsim_chip *chip, nandsim_evh_t evh) -{ - struct nandsim_ev *ev; - - chip->ev_handler = evh; - - nand_debug(NDBG_SIM,"Start handler %p for chip%d [%p]", evh, - chip->chip_num, chip); - ev = create_event(chip, NANDSIM_EV_START, 0); - if (!ev) - nandsim_sm_error(chip); - - send_event(ev); -} - -static void -nandchip_set_data(struct nandsim_chip *chip, uint8_t *data, uint32_t len, - uint32_t idx) -{ - - nand_debug(NDBG_SIM,"Chip [%x] data %p [%x] at %x", chip->chip_num, - data, len, idx); - chip->data.data_ptr = data; - chip->data.size = len; - chip->data.index = idx; -} - -static int -nandchip_chip_space(struct nandsim_chip *chip, int32_t row, int32_t column, - size_t size, uint8_t writing) -{ - struct block_space *blk_space; - uint32_t lun, block, page, offset, block_size; - int err; - - block_size = chip->cg.block_size + - (chip->cg.oob_size * chip->cg.pgs_per_blk); - - err = nand_row_to_blkpg(&chip->cg, row, &lun, &block, &page); - if (err) { - nand_debug(NDBG_SIM,"cannot get address\n"); - return (-1); - } - - if (!nandchip_is_block_valid(chip, block)) { - nandchip_set_data(chip, NULL, 0, 0); - return (-1); - } - - blk_space = get_bs(chip->swap, block, writing); - if (!blk_space) { - nandchip_set_data(chip, NULL, 0, 0); - return (-1); - } - - if (size > block_size) - size = block_size; - - if (size == block_size) { - offset = 0; - column = 0; - } else - offset = page * (chip->cg.page_size + chip->cg.oob_size); - - nandchip_set_data(chip, &blk_space->blk_ptr[offset], size, column); - - return (0); -} - -static int -nandchip_get_addr_byte(struct nandsim_chip *chip, void *data, uint32_t *value) -{ - int ncycles = 0; - uint8_t byte; - uint8_t *buffer; - - buffer = (uint8_t *)value; - byte = *((uint8_t *)data); - - KASSERT((chip->sm_state == NANDSIM_STATE_WAIT_ADDR_ROW || - chip->sm_state == NANDSIM_STATE_WAIT_ADDR_COL), - ("unexpected state")); - - if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_ROW) { - ncycles = chip->params.address_cycles & 0xf; - buffer[chip->sm_addr_cycle++] = byte; - } else if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_COL) { - ncycles = (chip->params.address_cycles >> 4) & 0xf; - buffer[chip->sm_addr_cycle++] = byte; - } - - nand_debug(NDBG_SIM, "Chip [%x] read addr byte: %02x (%d of %d)\n", - chip->chip_num, byte, chip->sm_addr_cycle, ncycles); - - if (chip->sm_addr_cycle == ncycles) { - chip->sm_addr_cycle = 0; - return (0); - } - - return (1); -} - -static int -nandchip_is_block_valid(struct nandsim_chip *chip, int block_num) -{ - - if (!chip || !chip->blk_state) - return (0); - - if (chip->blk_state[block_num].wear_lev == 0 || - chip->blk_state[block_num].is_bad) - return (0); - - return (1); -} - -static void -nandchip_set_status(struct nandsim_chip *chip, uint8_t flags) -{ - - chip->chip_status |= flags; -} - -static void -nandchip_clear_status(struct nandsim_chip *chip, uint8_t flags) -{ - - chip->chip_status &= ~flags; -} - -uint8_t -nandchip_get_status(struct nandsim_chip *chip) -{ - return (chip->chip_status); -} - -void -nandsim_chip_timeout(struct nandsim_chip *chip) -{ - struct timeval tv; - - getmicrotime(&tv); - - if (chip->sm_state == NANDSIM_STATE_TIMEOUT && - timevalcmp(&tv, &chip->delay_tv, >=)) { - nandchip_set_status(chip, NAND_STATUS_RDY); - } -} -void -poweron_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - uint8_t cmd; - - if (type == NANDSIM_EV_START) - chip->sm_state = NANDSIM_STATE_IDLE; - else if (type == NANDSIM_EV_CMD) { - cmd = *(uint8_t *)data; - switch(cmd) { - case NAND_CMD_RESET: - nandsim_log(chip, NANDSIM_LOG_SM, "in RESET state\n"); - nandsim_start_handler(chip, reset_evh); - break; - default: - nandsim_undefined(chip, type); - break; - } - } else - nandsim_undefined(chip, type); -} - -void -idle_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - uint8_t cmd; - - if (type == NANDSIM_EV_START) { - nandsim_log(chip, NANDSIM_LOG_SM, "in IDLE state\n"); - chip->sm_state = NANDSIM_STATE_WAIT_CMD; - } else if (type == NANDSIM_EV_CMD) { - nandchip_clear_status(chip, NAND_STATUS_FAIL); - getmicrotime(&chip->delay_tv); - cmd = *(uint8_t *)data; - switch(cmd) { - case NAND_CMD_READ_ID: - nandsim_start_handler(chip, readid_evh); - break; - case NAND_CMD_READ_PARAMETER: - nandsim_start_handler(chip, readparam_evh); - break; - case NAND_CMD_READ: - nandsim_start_handler(chip, read_evh); - break; - case NAND_CMD_PROG: - nandsim_start_handler(chip, write_evh); - break; - case NAND_CMD_ERASE: - nandsim_start_handler(chip, erase_evh); - break; - default: - nandsim_undefined(chip, type); - break; - } - } else - nandsim_undefined(chip, type); -} - -void -readid_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - struct onfi_params *params; - uint8_t addr; - - params = &chip->params; - - if (type == NANDSIM_EV_START) { - nandsim_log(chip, NANDSIM_LOG_SM, "in READID state\n"); - chip->sm_state = NANDSIM_STATE_WAIT_ADDR_BYTE; - } else if (type == NANDSIM_EV_ADDR) { - - addr = *((uint8_t *)data); - - if (addr == 0x0) - nandchip_set_data(chip, (uint8_t *)&chip->id, 2, 0); - else if (addr == ONFI_SIG_ADDR) - nandchip_set_data(chip, (uint8_t *)¶ms->signature, - 4, 0); - else - nandsim_bad_address(chip, &addr); - - nandsim_start_handler(chip, idle_evh); - } else - nandsim_undefined(chip, type); -} - -void -readparam_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - struct onfi_params *params; - uint8_t addr; - - params = &chip->params; - - if (type == NANDSIM_EV_START) { - nandsim_log(chip, NANDSIM_LOG_SM, "in READPARAM state\n"); - chip->sm_state = NANDSIM_STATE_WAIT_ADDR_BYTE; - } else if (type == NANDSIM_EV_ADDR) { - addr = *((uint8_t *)data); - - if (addr == 0) { - nandchip_set_data(chip, (uint8_t *)params, - sizeof(*params), 0); - } else - nandsim_bad_address(chip, &addr); - - nandsim_start_handler(chip, idle_evh); - } else - nandsim_undefined(chip, type); -} - -void -read_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - static uint32_t column = 0, row = 0; - uint32_t size; - uint8_t cmd; - - size = chip->cg.page_size + chip->cg.oob_size; - - switch (type) { - case NANDSIM_EV_START: - nandsim_log(chip, NANDSIM_LOG_SM, "in READ state\n"); - chip->sm_state = NANDSIM_STATE_WAIT_ADDR_COL; - break; - case NANDSIM_EV_ADDR: - if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_COL) { - if (nandchip_get_addr_byte(chip, data, &column)) - break; - - chip->sm_state = NANDSIM_STATE_WAIT_ADDR_ROW; - } else if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_ROW) { - if (nandchip_get_addr_byte(chip, data, &row)) - break; - - chip->sm_state = NANDSIM_STATE_WAIT_CMD; - } else - nandsim_ignore_address(chip, *((uint8_t *)data)); - break; - case NANDSIM_EV_CMD: - cmd = *(uint8_t *)data; - if (chip->sm_state == NANDSIM_STATE_WAIT_CMD && - cmd == NAND_CMD_READ_END) { - if (chip->read_delay != 0 && - nandsim_delay(chip, chip->read_delay) == 0) - nandchip_clear_status(chip, NAND_STATUS_RDY); - else { - nandchip_chip_space(chip, row, column, size, 0); - nandchip_set_status(chip, NAND_STATUS_RDY); - nandsim_start_handler(chip, idle_evh); - } - } else - nandsim_undefined(chip, type); - break; - case NANDSIM_EV_TIMEOUT: - if (chip->sm_state == NANDSIM_STATE_TIMEOUT) { - nandchip_chip_space(chip, row, column, size, 0); - nandchip_set_status(chip, NAND_STATUS_RDY); - nandsim_start_handler(chip, idle_evh); - } else - nandsim_undefined(chip, type); - break; - } -} -void -write_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - static uint32_t column, row; - uint32_t size; - uint8_t cmd; - int err; - - size = chip->cg.page_size + chip->cg.oob_size; - - switch(type) { - case NANDSIM_EV_START: - nandsim_log(chip, NANDSIM_LOG_SM, "in WRITE state\n"); - chip->sm_state = NANDSIM_STATE_WAIT_ADDR_COL; - break; - case NANDSIM_EV_ADDR: - if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_COL) { - if (nandchip_get_addr_byte(chip, data, &column)) - break; - - chip->sm_state = NANDSIM_STATE_WAIT_ADDR_ROW; - } else if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_ROW) { - if (nandchip_get_addr_byte(chip, data, &row)) - break; - - err = nandchip_chip_space(chip, row, column, size, 1); - if (err == -1) - nandchip_set_status(chip, NAND_STATUS_FAIL); - - chip->sm_state = NANDSIM_STATE_WAIT_CMD; - } else - nandsim_ignore_address(chip, *((uint8_t *)data)); - break; - case NANDSIM_EV_CMD: - cmd = *(uint8_t *)data; - if (chip->sm_state == NANDSIM_STATE_WAIT_CMD && - cmd == NAND_CMD_PROG_END) { - if (chip->prog_delay != 0 && - nandsim_delay(chip, chip->prog_delay) == 0) - nandchip_clear_status(chip, NAND_STATUS_RDY); - else { - nandchip_set_status(chip, NAND_STATUS_RDY); - nandsim_start_handler(chip, idle_evh); - } - } else - nandsim_undefined(chip, type); - break; - case NANDSIM_EV_TIMEOUT: - if (chip->sm_state == NANDSIM_STATE_TIMEOUT) { - nandsim_start_handler(chip, idle_evh); - nandchip_set_status(chip, NAND_STATUS_RDY); - } else - nandsim_undefined(chip, type); - break; - } -} - -void -erase_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - static uint32_t row, block_size; - uint32_t lun, block, page; - int err; - uint8_t cmd; - - block_size = chip->cg.block_size + - (chip->cg.oob_size * chip->cg.pgs_per_blk); - - switch (type) { - case NANDSIM_EV_START: - nandsim_log(chip, NANDSIM_LOG_SM, "in ERASE state\n"); - chip->sm_state = NANDSIM_STATE_WAIT_ADDR_ROW; - break; - case NANDSIM_EV_CMD: - cmd = *(uint8_t *)data; - if (chip->sm_state == NANDSIM_STATE_WAIT_CMD && - cmd == NAND_CMD_ERASE_END) { - if (chip->data.data_ptr != NULL && - chip->data.size == block_size) - memset(chip->data.data_ptr, 0xff, block_size); - else - nand_debug(NDBG_SIM,"Bad block erase data\n"); - - err = nand_row_to_blkpg(&chip->cg, row, &lun, - &block, &page); - if (!err) { - if (chip->blk_state[block].wear_lev > 0) - chip->blk_state[block].wear_lev--; - } - - if (chip->erase_delay != 0 && - nandsim_delay(chip, chip->erase_delay) == 0) - nandchip_clear_status(chip, NAND_STATUS_RDY); - else { - nandchip_set_status(chip, NAND_STATUS_RDY); - nandsim_start_handler(chip, idle_evh); - } - } else - nandsim_undefined(chip, type); - break; - case NANDSIM_EV_ADDR: - if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_ROW) { - if (nandchip_get_addr_byte(chip, data, &row)) - break; - - err = nandchip_chip_space(chip, row, 0, block_size, 1); - if (err == -1) { - nandchip_set_status(chip, NAND_STATUS_FAIL); - } - chip->sm_state = NANDSIM_STATE_WAIT_CMD; - } else - nandsim_ignore_address(chip, *((uint8_t *)data)); - break; - case NANDSIM_EV_TIMEOUT: - if (chip->sm_state == NANDSIM_STATE_TIMEOUT) { - nandchip_set_status(chip, NAND_STATUS_RDY); - nandsim_start_handler(chip, idle_evh); - } else - nandsim_undefined(chip, type); - break; - } -} - -void -reset_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - - if (type == NANDSIM_EV_START) { - nandsim_log(chip, NANDSIM_LOG_SM, "in RESET state\n"); - chip->sm_state = NANDSIM_STATE_TIMEOUT; - nandchip_set_data(chip, NULL, 0, 0); - DELAY(500); - nandsim_start_handler(chip, idle_evh); - } else - nandsim_undefined(chip, type); -} - -static void -nandsim_undefined(struct nandsim_chip *chip, uint8_t type) -{ - - nandsim_log(chip, NANDSIM_LOG_ERR, - "ERR: Chip received ev %x in state %x\n", - type, chip->sm_state); - nandsim_start_handler(chip, idle_evh); -} - -static void -nandsim_bad_address(struct nandsim_chip *chip, uint8_t *addr) -{ - - nandsim_log(chip, NANDSIM_LOG_ERR, - "ERR: Chip received out of range address" - "%02x%02x - %02x%02x%02x\n", addr[0], addr[1], addr[2], - addr[3], addr[4]); -} - -static void -nandsim_ignore_address(struct nandsim_chip *chip, uint8_t byte) -{ - nandsim_log(chip, NANDSIM_LOG_SM, "ignored address byte: %d\n", byte); -} - -static void -nandsim_sm_error(struct nandsim_chip *chip) -{ - - nandsim_log(chip, NANDSIM_LOG_ERR, "ERR: State machine error." - "Restart required.\n"); -} diff --git a/sys/dev/nand/nandsim_chip.h b/sys/dev/nand/nandsim_chip.h deleted file mode 100644 index 86ced5ea2bf2..000000000000 --- a/sys/dev/nand/nandsim_chip.h +++ /dev/null @@ -1,161 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$ - */ - -#ifndef _NANDSIM_CHIP_H -#define _NANDSIM_CHIP_H - -#include -#include -#include -#include -#include - -MALLOC_DECLARE(M_NANDSIM); - -#define MAX_CS_NUM 4 -struct nandsim_chip; - -typedef void nandsim_evh_t(struct nandsim_chip *chip, uint32_t ev, void *data); - -enum addr_type { - ADDR_NONE, - ADDR_ID, - ADDR_ROW, - ADDR_ROWCOL -}; - -struct nandsim_softc { - struct nand_softc nand_dev; - device_t dev; - - struct nandsim_chip *chips[MAX_CS_NUM]; - struct nandsim_chip *active_chip; - - uint8_t address_cycle; - enum addr_type address_type; - int log_idx; - char *log_buff; - struct alq *alq; -}; - -struct nandsim_ev { - STAILQ_ENTRY(nandsim_ev) links; - struct nandsim_chip *chip; - uint8_t type; - void *data; -}; - -struct nandsim_data { - uint8_t *data_ptr; - uint32_t index; - uint32_t size; -}; - -struct nandsim_block_state { - int32_t wear_lev; - uint8_t is_bad; -}; - -#define NANDSIM_CHIP_ACTIVE 0x1 -#define NANDSIM_CHIP_FROZEN 0x2 -#define NANDSIM_CHIP_GET_STATUS 0x4 - -struct nandsim_chip { - struct nandsim_softc *sc; - struct thread *nandsim_td; - - STAILQ_HEAD(, nandsim_ev) nandsim_events; - nandsim_evh_t *ev_handler; - struct mtx ns_lock; - struct callout ns_callout; - - struct chip_geom cg; - struct nand_id id; - struct onfi_params params; - struct nandsim_data data; - struct nandsim_block_state *blk_state; - - struct chip_swap *swap; - - uint32_t error_ratio; - uint32_t wear_level; - uint32_t sm_state; - uint32_t sm_addr_cycle; - - uint32_t erase_delay; - uint32_t prog_delay; - uint32_t read_delay; - struct timeval delay_tv; - - uint8_t flags; - uint8_t chip_status; - uint8_t ctrl_num; - uint8_t chip_num; -}; - -struct sim_ctrl_conf { - uint8_t num; - uint8_t num_cs; - uint8_t ecc; - uint8_t running; - uint8_t created; - device_t sim_ctrl_dev; - struct sim_chip *chips[MAX_CTRL_CS]; - uint16_t ecc_layout[MAX_ECC_BYTES]; - char filename[FILENAME_SIZE]; -}; - -#define NANDSIM_STATE_IDLE 0x0 -#define NANDSIM_STATE_WAIT_ADDR_BYTE 0x1 -#define NANDSIM_STATE_WAIT_CMD 0x2 -#define NANDSIM_STATE_TIMEOUT 0x3 -#define NANDSIM_STATE_WAIT_ADDR_ROW 0x4 -#define NANDSIM_STATE_WAIT_ADDR_COL 0x5 - -#define NANDSIM_EV_START 0x1 -#define NANDSIM_EV_CMD 0x2 -#define NANDSIM_EV_ADDR 0x3 -#define NANDSIM_EV_TIMEOUT 0x4 -#define NANDSIM_EV_EXIT 0xff - -struct nandsim_chip *nandsim_chip_init(struct nandsim_softc *, - uint8_t, struct sim_chip *); -void nandsim_chip_destroy(struct nandsim_chip *); -void nandsim_chip_freeze(struct nandsim_chip *); -void nandsim_chip_timeout(struct nandsim_chip *); -int nandsim_chip_check_bad_block(struct nandsim_chip *, int); - -uint8_t nandchip_get_status(struct nandsim_chip *); - -void destroy_event(struct nandsim_ev *); -int send_event(struct nandsim_ev *); -struct nandsim_ev *create_event(struct nandsim_chip *, uint8_t, uint8_t); - -#endif /* _NANDSIM_CHIP_H */ diff --git a/sys/dev/nand/nandsim_ctrl.c b/sys/dev/nand/nandsim_ctrl.c deleted file mode 100644 index bc203902fe7e..000000000000 --- a/sys/dev/nand/nandsim_ctrl.c +++ /dev/null @@ -1,398 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. - */ - -/* Simulated NAND controller driver */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include "nfc_if.h" - -#define ADDRESS_SIZE 5 - -extern struct sim_ctrl_conf ctrls[MAX_SIM_DEV]; - -static void byte_corrupt(struct nandsim_chip *, uint8_t *); - -static int nandsim_attach(device_t); -static int nandsim_detach(device_t); -static int nandsim_probe(device_t); - -static uint8_t nandsim_read_byte(device_t); -static uint16_t nandsim_read_word(device_t); -static int nandsim_select_cs(device_t, uint8_t); -static void nandsim_write_byte(device_t, uint8_t); -static void nandsim_write_word(device_t, uint16_t); -static void nandsim_read_buf(device_t, void *, uint32_t); -static void nandsim_write_buf(device_t, void *, uint32_t); -static int nandsim_send_command(device_t, uint8_t); -static int nandsim_send_address(device_t, uint8_t); - -static device_method_t nandsim_methods[] = { - DEVMETHOD(device_probe, nandsim_probe), - DEVMETHOD(device_attach, nandsim_attach), - DEVMETHOD(device_detach, nandsim_detach), - - DEVMETHOD(nfc_select_cs, nandsim_select_cs), - DEVMETHOD(nfc_send_command, nandsim_send_command), - DEVMETHOD(nfc_send_address, nandsim_send_address), - DEVMETHOD(nfc_read_byte, nandsim_read_byte), - DEVMETHOD(nfc_read_word, nandsim_read_word), - DEVMETHOD(nfc_write_byte, nandsim_write_byte), - DEVMETHOD(nfc_read_buf, nandsim_read_buf), - DEVMETHOD(nfc_write_buf, nandsim_write_buf), - - { 0, 0 }, -}; - -static driver_t nandsim_driver = { - "nandsim", - nandsim_methods, - sizeof(struct nandsim_softc), -}; - -static devclass_t nandsim_devclass; -DRIVER_MODULE(nandsim, nexus, nandsim_driver, nandsim_devclass, 0, 0); -DRIVER_MODULE(nandbus, nandsim, nandbus_driver, nandbus_devclass, 0, 0); - -static int -nandsim_probe(device_t dev) -{ - - device_set_desc(dev, "NAND controller simulator"); - return (BUS_PROBE_DEFAULT); -} - -static int -nandsim_attach(device_t dev) -{ - struct nandsim_softc *sc; - struct sim_ctrl_conf *params; - struct sim_chip *chip; - uint16_t *eccpos; - int i, err; - - sc = device_get_softc(dev); - params = &ctrls[device_get_unit(dev)]; - - if (strlen(params->filename) == 0) - snprintf(params->filename, FILENAME_SIZE, "ctrl%d.log", - params->num); - - nandsim_log_init(sc, params->filename); - for (i = 0; i < params->num_cs; i++) { - chip = params->chips[i]; - if (chip && chip->device_id != 0) { - sc->chips[i] = nandsim_chip_init(sc, i, chip); - if (chip->features & ONFI_FEAT_16BIT) - sc->nand_dev.flags |= NAND_16_BIT; - } - } - - if (params->ecc_layout[0] != 0xffff) - eccpos = params->ecc_layout; - else - eccpos = NULL; - - nand_init(&sc->nand_dev, dev, params->ecc, 0, 0, eccpos, "nandsim"); - - err = nandbus_create(dev); - - return (err); -} - -static int -nandsim_detach(device_t dev) -{ - struct nandsim_softc *sc; - struct sim_ctrl_conf *params; - int i; - - sc = device_get_softc(dev); - params = &ctrls[device_get_unit(dev)]; - - for (i = 0; i < params->num_cs; i++) - if (sc->chips[i] != NULL) - nandsim_chip_destroy(sc->chips[i]); - - nandsim_log_close(sc); - - return (0); -} - -static int -nandsim_select_cs(device_t dev, uint8_t cs) -{ - struct nandsim_softc *sc; - - sc = device_get_softc(dev); - - if (cs >= MAX_CS_NUM) - return (EINVAL); - - sc->active_chip = sc->chips[cs]; - - if (sc->active_chip) - nandsim_log(sc->active_chip, NANDSIM_LOG_EV, - "Select cs %d\n", cs); - - return (0); -} - -static int -nandsim_send_command(device_t dev, uint8_t command) -{ - struct nandsim_softc *sc; - struct nandsim_chip *chip; - struct nandsim_ev *ev; - - sc = device_get_softc(dev); - chip = sc->active_chip; - - if (chip == NULL) - return (0); - - nandsim_log(chip, NANDSIM_LOG_EV, "Send command %x\n", command); - - switch (command) { - case NAND_CMD_READ_ID: - case NAND_CMD_READ_PARAMETER: - sc->address_type = ADDR_ID; - break; - case NAND_CMD_ERASE: - sc->address_type = ADDR_ROW; - break; - case NAND_CMD_READ: - case NAND_CMD_PROG: - sc->address_type = ADDR_ROWCOL; - break; - default: - sc->address_type = ADDR_NONE; - break; - } - - if (command == NAND_CMD_STATUS) - chip->flags |= NANDSIM_CHIP_GET_STATUS; - else { - ev = create_event(chip, NANDSIM_EV_CMD, 1); - *(uint8_t *)ev->data = command; - send_event(ev); - } - - return (0); -} - -static int -nandsim_send_address(device_t dev, uint8_t addr) -{ - struct nandsim_ev *ev; - struct nandsim_softc *sc; - struct nandsim_chip *chip; - - sc = device_get_softc(dev); - chip = sc->active_chip; - - if (chip == NULL) - return (0); - - KASSERT((sc->address_type != ADDR_NONE), ("unexpected address")); - nandsim_log(chip, NANDSIM_LOG_EV, "Send addr %x\n", addr); - - ev = create_event(chip, NANDSIM_EV_ADDR, 1); - - *((uint8_t *)(ev->data)) = addr; - - send_event(ev); - return (0); -} - -static uint8_t -nandsim_read_byte(device_t dev) -{ - struct nandsim_softc *sc; - struct nandsim_chip *chip; - uint8_t ret = 0xff; - - sc = device_get_softc(dev); - chip = sc->active_chip; - - if (chip && !(chip->flags & NANDSIM_CHIP_FROZEN)) { - if (chip->flags & NANDSIM_CHIP_GET_STATUS) { - nandsim_chip_timeout(chip); - ret = nandchip_get_status(chip); - chip->flags &= ~NANDSIM_CHIP_GET_STATUS; - } else if (chip->data.index < chip->data.size) { - ret = chip->data.data_ptr[chip->data.index++]; - byte_corrupt(chip, &ret); - } - nandsim_log(chip, NANDSIM_LOG_DATA, "read %02x\n", ret); - } - - return (ret); -} - -static uint16_t -nandsim_read_word(device_t dev) -{ - struct nandsim_softc *sc; - struct nandsim_chip *chip; - uint16_t *data_ptr; - uint16_t ret = 0xffff; - uint8_t *byte_ret = (uint8_t *)&ret; - - sc = device_get_softc(dev); - chip = sc->active_chip; - - if (chip && !(chip->flags & NANDSIM_CHIP_FROZEN)) { - if (chip->data.index < chip->data.size - 1) { - data_ptr = - (uint16_t *)&(chip->data.data_ptr[chip->data.index]); - ret = *data_ptr; - chip->data.index += 2; - byte_corrupt(chip, byte_ret); - byte_corrupt(chip, byte_ret + 1); - } - nandsim_log(chip, NANDSIM_LOG_DATA, "read %04x\n", ret); - } - - return (ret); -} - -static void -nandsim_write_byte(device_t dev, uint8_t byte) -{ - struct nandsim_softc *sc; - struct nandsim_chip *chip; - - sc = device_get_softc(dev); - chip = sc->active_chip; - - if (chip && !(chip->flags & NANDSIM_CHIP_FROZEN) && - (chip->data.index < chip->data.size)) { - byte_corrupt(chip, &byte); - chip->data.data_ptr[chip->data.index] &= byte; - chip->data.index++; - nandsim_log(chip, NANDSIM_LOG_DATA, "write %02x\n", byte); - } -} - -static void -nandsim_write_word(device_t dev, uint16_t word) -{ - struct nandsim_softc *sc; - struct nandsim_chip *chip; - uint16_t *data_ptr; - uint8_t *byte_ptr = (uint8_t *)&word; - - sc = device_get_softc(dev); - chip = sc->active_chip; - - if (chip && !(chip->flags & NANDSIM_CHIP_FROZEN)) { - if ((chip->data.index + 1) < chip->data.size) { - byte_corrupt(chip, byte_ptr); - byte_corrupt(chip, byte_ptr + 1); - data_ptr = - (uint16_t *)&(chip->data.data_ptr[chip->data.index]); - *data_ptr &= word; - chip->data.index += 2; - } - - nandsim_log(chip, NANDSIM_LOG_DATA, "write %04x\n", word); - } -} - -static void -nandsim_read_buf(device_t dev, void *buf, uint32_t len) -{ - struct nandsim_softc *sc; - uint16_t *buf16 = (uint16_t *)buf; - uint8_t *buf8 = (uint8_t *)buf; - int i; - - sc = device_get_softc(dev); - - if (sc->nand_dev.flags & NAND_16_BIT) { - for (i = 0; i < len / 2; i++) - buf16[i] = nandsim_read_word(dev); - } else { - for (i = 0; i < len; i++) - buf8[i] = nandsim_read_byte(dev); - } -} - -static void -nandsim_write_buf(device_t dev, void *buf, uint32_t len) -{ - struct nandsim_softc *sc; - uint16_t *buf16 = (uint16_t *)buf; - uint8_t *buf8 = (uint8_t *)buf; - int i; - - sc = device_get_softc(dev); - - if (sc->nand_dev.flags & NAND_16_BIT) { - for (i = 0; i < len / 2; i++) - nandsim_write_word(dev, buf16[i]); - } else { - for (i = 0; i < len; i++) - nandsim_write_byte(dev, buf8[i]); - } -} - -static void -byte_corrupt(struct nandsim_chip *chip, uint8_t *byte) -{ - uint32_t rand; - uint8_t bit; - - rand = random(); - if ((rand % 1000000) < chip->error_ratio) { - bit = rand % 8; - if (*byte & (1 << bit)) - *byte &= ~(1 << bit); - else - *byte |= (1 << bit); - } -} diff --git a/sys/dev/nand/nandsim_log.c b/sys/dev/nand/nandsim_log.c deleted file mode 100644 index 0bd316ace4e2..000000000000 --- a/sys/dev/nand/nandsim_log.c +++ /dev/null @@ -1,188 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -int nandsim_log_level; -int nandsim_log_output; -int log_size = NANDSIM_RAM_LOG_SIZE; - -static int nandsim_entry_size = NANDSIM_ENTRY_SIZE; -static int nandsim_entry_count = NANDSIM_ENTRY_COUNT; -static int str_index = 0; -static char string[NANDSIM_ENTRY_SIZE + 1] = {0}; - -int -nandsim_log_init(struct nandsim_softc *sc, char *filename) -{ - int error = 0; - - if (nandsim_log_output == NANDSIM_OUTPUT_FILE) { - error = alq_open(&sc->alq, filename, - curthread->td_ucred, 0644, - nandsim_entry_size, nandsim_entry_count); - } else if (nandsim_log_output == NANDSIM_OUTPUT_RAM) { - sc->log_buff = malloc(log_size, M_NANDSIM, M_WAITOK | M_ZERO); - if (!sc->log_buff) - error = ENOMEM; - } - - return (error); -} - -void -nandsim_log_close(struct nandsim_softc *sc) -{ - - if (nandsim_log_output == NANDSIM_OUTPUT_FILE) { - memset(&string[str_index], 0, NANDSIM_ENTRY_SIZE - str_index); - alq_write(sc->alq, (void *) string, ALQ_NOWAIT); - str_index = 0; - string[0] = '\0'; - alq_close(sc->alq); - } else if (nandsim_log_output == NANDSIM_OUTPUT_RAM) { - free(sc->log_buff, M_NANDSIM); - sc->log_buff = NULL; - } -} - -void -nandsim_log(struct nandsim_chip *chip, int level, const char *fmt, ...) -{ - char hdr[TIME_STR_SIZE]; - char tmp[NANDSIM_ENTRY_SIZE]; - struct nandsim_softc *sc; - struct timeval currtime; - va_list ap; - int hdr_len, len, rest; - - if (nandsim_log_output == NANDSIM_OUTPUT_NONE) - return; - - if (chip == NULL) - return; - - sc = chip->sc; - if (!sc->alq && nandsim_log_output == NANDSIM_OUTPUT_FILE) - return; - - if (level <= nandsim_log_level) { - microtime(&currtime); - hdr_len = sprintf(hdr, "%08jd.%08li [chip:%d, ctrl:%d]: ", - (intmax_t)currtime.tv_sec, currtime.tv_usec, - chip->chip_num, chip->ctrl_num); - - switch(nandsim_log_output) { - case NANDSIM_OUTPUT_CONSOLE: - printf("%s", hdr); - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); - break; - case NANDSIM_OUTPUT_RAM: - va_start(ap, fmt); - len = vsnprintf(tmp, NANDSIM_ENTRY_SIZE - 1, fmt, ap); - tmp[NANDSIM_ENTRY_SIZE - 1] = 0; - va_end(ap); - - rest = log_size - sc->log_idx - 1; - if (rest >= hdr_len) { - bcopy(hdr, &sc->log_buff[sc->log_idx], - hdr_len); - sc->log_idx += hdr_len; - sc->log_buff[sc->log_idx] = 0; - } else { - bcopy(hdr, &sc->log_buff[sc->log_idx], rest); - bcopy(&hdr[rest], sc->log_buff, - hdr_len - rest); - sc->log_idx = hdr_len - rest; - sc->log_buff[sc->log_idx] = 0; - } - - rest = log_size - sc->log_idx - 1; - if (rest >= len) { - bcopy(tmp, &sc->log_buff[sc->log_idx], len); - sc->log_idx += len; - sc->log_buff[sc->log_idx] = 0; - } else { - bcopy(tmp, &sc->log_buff[sc->log_idx], rest); - bcopy(&tmp[rest], sc->log_buff, len - rest); - sc->log_idx = len - rest; - sc->log_buff[sc->log_idx] = 0; - } - - break; - - case NANDSIM_OUTPUT_FILE: - va_start(ap, fmt); - len = vsnprintf(tmp, NANDSIM_ENTRY_SIZE - 1, fmt, ap); - tmp[NANDSIM_ENTRY_SIZE - 1] = 0; - va_end(ap); - - rest = NANDSIM_ENTRY_SIZE - str_index; - if (rest >= hdr_len) { - strcat(string, hdr); - str_index += hdr_len; - } else { - strlcat(string, hdr, NANDSIM_ENTRY_SIZE + 1); - alq_write(sc->alq, (void *) string, - ALQ_NOWAIT); - strcpy(string, &hdr[rest]); - str_index = hdr_len - rest; - } - rest = NANDSIM_ENTRY_SIZE - str_index; - if (rest >= len) { - strcat(string, tmp); - str_index += len; - } else { - strlcat(string, tmp, NANDSIM_ENTRY_SIZE + 1); - alq_write(sc->alq, (void *) string, - ALQ_NOWAIT); - strcpy(string, &tmp[rest]); - str_index = len - rest; - } - break; - default: - break; - } - } -} diff --git a/sys/dev/nand/nandsim_log.h b/sys/dev/nand/nandsim_log.h deleted file mode 100644 index 5e5a055a4053..000000000000 --- a/sys/dev/nand/nandsim_log.h +++ /dev/null @@ -1,54 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$ - */ - -#ifndef _NANDSIM_LOG_H -#define _NANDSIM_LOG_H - -#include - -#define NANDSIM_ENTRY_SIZE 128 -#define NANDSIM_ENTRY_COUNT 1024 -#define NANDSIM_RAM_LOG_SIZE 16384 -#define TIME_STR_SIZE 40 - -#define NANDSIM_LOG_ERR 1 -#define NANDSIM_LOG_SM 5 -#define NANDSIM_LOG_EV 10 -#define NANDSIM_LOG_DATA 15 - -extern int nandsim_log_level; -extern int nandsim_log_output; - -int nandsim_log_init(struct nandsim_softc *, char *); -void nandsim_log_close(struct nandsim_softc *); -void nandsim_log(struct nandsim_chip *, int, const char *, ...); - -#endif /* _NANDSIM_LOG_H */ - diff --git a/sys/dev/nand/nandsim_swap.c b/sys/dev/nand/nandsim_swap.c deleted file mode 100644 index 78e14e9557bd..000000000000 --- a/sys/dev/nand/nandsim_swap.c +++ /dev/null @@ -1,383 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -static int init_block_state(struct chip_swap *); -static void destroy_block_state(struct chip_swap *); - -static int create_buffers(struct chip_swap *); -static void destroy_buffers(struct chip_swap *); - -static int swap_file_open(struct chip_swap *, const char *); -static void swap_file_close(struct chip_swap *); -static int swap_file_write(struct chip_swap *, struct block_state *); -static int swap_file_read(struct chip_swap *, struct block_state *); - -#define CHIP_SWAP_CMODE 0600 -#define CHIP_SWAP_BLOCKSPACES 2 - -static int -init_block_state(struct chip_swap *swap) -{ - struct block_state *blk_state; - int i; - - if (swap == NULL) - return (-1); - - blk_state = malloc(swap->nof_blks * sizeof(struct block_state), - M_NANDSIM, M_WAITOK | M_ZERO); - - for (i = 0; i < swap->nof_blks; i++) - blk_state[i].offset = 0xffffffff; - - swap->blk_state = blk_state; - - return (0); -} - -static void -destroy_block_state(struct chip_swap *swap) -{ - - if (swap == NULL) - return; - - if (swap->blk_state != NULL) - free(swap->blk_state, M_NANDSIM); -} - -static int -create_buffers(struct chip_swap *swap) -{ - struct block_space *block_space; - void *block; - int i; - - for (i = 0; i < CHIP_SWAP_BLOCKSPACES; i++) { - block_space = malloc(sizeof(*block_space), M_NANDSIM, M_WAITOK); - block = malloc(swap->blk_size, M_NANDSIM, M_WAITOK); - block_space->blk_ptr = block; - SLIST_INSERT_HEAD(&swap->free_bs, block_space, free_link); - nand_debug(NDBG_SIM,"created blk_space %p[%p]\n", block_space, - block); - } - - if (i == 0) - return (-1); - - return (0); -} - -static void -destroy_buffers(struct chip_swap *swap) -{ - struct block_space *blk_space; - - if (swap == NULL) - return; - - blk_space = SLIST_FIRST(&swap->free_bs); - while (blk_space) { - SLIST_REMOVE_HEAD(&swap->free_bs, free_link); - nand_debug(NDBG_SIM,"destroyed blk_space %p[%p]\n", - blk_space, blk_space->blk_ptr); - free(blk_space->blk_ptr, M_NANDSIM); - free(blk_space, M_NANDSIM); - blk_space = SLIST_FIRST(&swap->free_bs); - } - - blk_space = STAILQ_FIRST(&swap->used_bs); - while (blk_space) { - STAILQ_REMOVE_HEAD(&swap->used_bs, used_link); - nand_debug(NDBG_SIM,"destroyed blk_space %p[%p]\n", - blk_space, blk_space->blk_ptr); - free(blk_space->blk_ptr, M_NANDSIM); - free(blk_space, M_NANDSIM); - blk_space = STAILQ_FIRST(&swap->used_bs); - } -} - -static int -swap_file_open(struct chip_swap *swap, const char *swap_file) -{ - struct nameidata nd; - int flags, error; - - NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, swap_file, - curthread); - - flags = FWRITE | FREAD | O_NOFOLLOW | O_CREAT | O_TRUNC; - - error = vn_open(&nd, &flags, CHIP_SWAP_CMODE, NULL); - if (error) { - nand_debug(NDBG_SIM,"Cannot create swap file %s", swap_file); - NDFREE(&nd, NDF_ONLY_PNBUF); - return (error); - } - - swap->swap_cred = crhold(curthread->td_ucred); - NDFREE(&nd, NDF_ONLY_PNBUF); - - /* We just unlock so we hold a reference */ - VOP_UNLOCK(nd.ni_vp, 0); - - swap->swap_vp = nd.ni_vp; - - return (0); -} - -static void -swap_file_close(struct chip_swap *swap) -{ - - if (swap == NULL) - return; - - if (swap->swap_vp == NULL) - return; - - vn_close(swap->swap_vp, FWRITE, swap->swap_cred, curthread); - crfree(swap->swap_cred); -} - -static int -swap_file_write(struct chip_swap *swap, struct block_state *blk_state) -{ - struct block_space *blk_space; - struct thread *td; - struct mount *mp; - struct vnode *vp; - struct uio auio; - struct iovec aiov; - - if (swap == NULL || blk_state == NULL) - return (-1); - - blk_space = blk_state->blk_sp; - if (blk_state->offset == -1) { - blk_state->offset = swap->swap_offset; - swap->swap_offset += swap->blk_size; - } - - nand_debug(NDBG_SIM,"saving %p[%p] at %x\n", - blk_space, blk_space->blk_ptr, blk_state->offset); - - bzero(&aiov, sizeof(aiov)); - bzero(&auio, sizeof(auio)); - - aiov.iov_base = blk_space->blk_ptr; - aiov.iov_len = swap->blk_size; - td = curthread; - vp = swap->swap_vp; - - auio.uio_iov = &aiov; - auio.uio_offset = blk_state->offset; - auio.uio_segflg = UIO_SYSSPACE; - auio.uio_rw = UIO_WRITE; - auio.uio_iovcnt = 1; - auio.uio_resid = swap->blk_size; - auio.uio_td = td; - - vn_start_write(vp, &mp, V_WAIT); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); - VOP_WRITE(vp, &auio, IO_UNIT, swap->swap_cred); - VOP_UNLOCK(vp, 0); - vn_finished_write(mp); - - return (0); -} - -static int -swap_file_read(struct chip_swap *swap, struct block_state *blk_state) -{ - struct block_space *blk_space; - struct thread *td; - struct vnode *vp; - struct uio auio; - struct iovec aiov; - - if (swap == NULL || blk_state == NULL) - return (-1); - - blk_space = blk_state->blk_sp; - - nand_debug(NDBG_SIM,"restore %p[%p] at %x\n", - blk_space, blk_space->blk_ptr, blk_state->offset); - - bzero(&aiov, sizeof(aiov)); - bzero(&auio, sizeof(auio)); - - aiov.iov_base = blk_space->blk_ptr; - aiov.iov_len = swap->blk_size; - td = curthread; - vp = swap->swap_vp; - - auio.uio_iov = &aiov; - auio.uio_offset = blk_state->offset; - auio.uio_segflg = UIO_SYSSPACE; - auio.uio_rw = UIO_READ; - auio.uio_iovcnt = 1; - auio.uio_resid = swap->blk_size; - auio.uio_td = td; - - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); - VOP_READ(vp, &auio, 0, swap->swap_cred); - VOP_UNLOCK(vp, 0); - - return (0); -} - -struct chip_swap * -nandsim_swap_init(const char *swap_file, uint32_t nof_blks, uint32_t blk_size) -{ - struct chip_swap *swap; - int err = 0; - - if ((swap_file == NULL) || (nof_blks == 0) || (blk_size == 0)) - return (NULL); - - swap = malloc(sizeof(*swap), M_NANDSIM, M_WAITOK | M_ZERO); - - SLIST_INIT(&swap->free_bs); - STAILQ_INIT(&swap->used_bs); - swap->blk_size = blk_size; - swap->nof_blks = nof_blks; - - err = init_block_state(swap); - if (err) { - nandsim_swap_destroy(swap); - return (NULL); - } - - err = create_buffers(swap); - if (err) { - nandsim_swap_destroy(swap); - return (NULL); - } - - err = swap_file_open(swap, swap_file); - if (err) { - nandsim_swap_destroy(swap); - return (NULL); - } - - return (swap); -} - -void -nandsim_swap_destroy(struct chip_swap *swap) -{ - - if (swap == NULL) - return; - - destroy_block_state(swap); - destroy_buffers(swap); - swap_file_close(swap); - free(swap, M_NANDSIM); -} - -struct block_space * -get_bs(struct chip_swap *swap, uint32_t block, uint8_t writing) -{ - struct block_state *blk_state, *old_blk_state = NULL; - struct block_space *blk_space; - - if (swap == NULL || (block >= swap->nof_blks)) - return (NULL); - - blk_state = &swap->blk_state[block]; - nand_debug(NDBG_SIM,"blk_state %x\n", blk_state->status); - - if (blk_state->status & BLOCK_ALLOCATED) { - blk_space = blk_state->blk_sp; - } else { - blk_space = SLIST_FIRST(&swap->free_bs); - if (blk_space) { - SLIST_REMOVE_HEAD(&swap->free_bs, free_link); - STAILQ_INSERT_TAIL(&swap->used_bs, blk_space, - used_link); - } else { - blk_space = STAILQ_FIRST(&swap->used_bs); - old_blk_state = blk_space->blk_state; - STAILQ_REMOVE_HEAD(&swap->used_bs, used_link); - STAILQ_INSERT_TAIL(&swap->used_bs, blk_space, - used_link); - if (old_blk_state->status & BLOCK_DIRTY) { - swap_file_write(swap, old_blk_state); - old_blk_state->status &= ~BLOCK_DIRTY; - old_blk_state->status |= BLOCK_SWAPPED; - } - } - } - - if (blk_space == NULL) - return (NULL); - - if (old_blk_state != NULL) { - old_blk_state->status &= ~BLOCK_ALLOCATED; - old_blk_state->blk_sp = NULL; - } - - blk_state->blk_sp = blk_space; - blk_space->blk_state = blk_state; - - if (!(blk_state->status & BLOCK_ALLOCATED)) { - if (blk_state->status & BLOCK_SWAPPED) - swap_file_read(swap, blk_state); - else - memset(blk_space->blk_ptr, 0xff, swap->blk_size); - blk_state->status |= BLOCK_ALLOCATED; - } - - if (writing) - blk_state->status |= BLOCK_DIRTY; - - nand_debug(NDBG_SIM,"get_bs returned %p[%p] state %x\n", blk_space, - blk_space->blk_ptr, blk_state->status); - - return (blk_space); -} diff --git a/sys/dev/nand/nandsim_swap.h b/sys/dev/nand/nandsim_swap.h deleted file mode 100644 index c9eb0be63a9c..000000000000 --- a/sys/dev/nand/nandsim_swap.h +++ /dev/null @@ -1,66 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$ - */ - -#ifndef _NANDSIM_SWAP_CHIP_H_ -#define _NANDSIM_SWAP_CHIP_H_ - -struct block_space { - SLIST_ENTRY(block_space) free_link; - STAILQ_ENTRY(block_space) used_link; - struct block_state *blk_state; - uint8_t *blk_ptr; -}; - -#define BLOCK_ALLOCATED 0x1 -#define BLOCK_SWAPPED 0x2 -#define BLOCK_DIRTY 0x4 - -struct block_state { - struct block_space *blk_sp; - uint32_t offset; - uint8_t status; -}; - -struct chip_swap { - struct block_state *blk_state; - SLIST_HEAD(,block_space) free_bs; - STAILQ_HEAD(,block_space) used_bs; - struct ucred *swap_cred; - struct vnode *swap_vp; - uint32_t swap_offset; - uint32_t blk_size; - uint32_t nof_blks; -}; - -struct chip_swap *nandsim_swap_init(const char *, uint32_t, uint32_t); -void nandsim_swap_destroy(struct chip_swap *); -struct block_space *get_bs(struct chip_swap *, uint32_t, uint8_t); - -#endif /* _NANDSIM_SWAP_CHIP_H_ */ diff --git a/sys/dev/nand/nfc_fsl.c b/sys/dev/nand/nfc_fsl.c deleted file mode 100644 index 992cfeb784fe..000000000000 --- a/sys/dev/nand/nfc_fsl.c +++ /dev/null @@ -1,717 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2012 Juniper Networks, Inc. - * Copyright (C) 2009-2012 Semihalf - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. - */ -/* - * TODO : - * - * -- test support for small pages - * -- support for reading ONFI parameters - * -- support for cached and interleaving commands - * -- proper setting of AL bits in FMR - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include - -#include -#include - -#include "nfc_fsl.h" - -#include "nfc_if.h" - -#define LBC_READ(regname) lbc_read_reg(dev, (LBC85XX_ ## regname)) -#define LBC_WRITE(regname, val) lbc_write_reg(dev, (LBC85XX_ ## regname), val) - -enum addr_type { - ADDR_NONE, - ADDR_ID, - ADDR_ROW, - ADDR_ROWCOL -}; - -struct fsl_nfc_fcm { - /* Read-only after initialization */ - uint32_t reg_fmr; - - /* To be preserved across "start_command" */ - u_int buf_ofs; - u_int read_ptr; - u_int status:1; - - /* Command state -- cleared by "start_command" */ - uint32_t fcm_startzero; - uint32_t reg_fcr; - uint32_t reg_fir; - uint32_t reg_mdr; - uint32_t reg_fbcr; - uint32_t reg_fbar; - uint32_t reg_fpar; - u_int cmdnr; - u_int opnr; - u_int pg_ofs; - enum addr_type addr_type; - u_int addr_bytes; - u_int row_addr; - u_int column_addr; - u_int data_fir:8; - uint32_t fcm_endzero; -}; - -struct fsl_nand_softc { - struct nand_softc nand_dev; - device_t dev; - struct resource *res; - int rid; /* Resourceid */ - struct lbc_devinfo *dinfo; - struct fsl_nfc_fcm fcm; - uint8_t col_cycles; - uint8_t row_cycles; - uint16_t pgsz; /* Page size */ -}; - -static int fsl_nand_attach(device_t dev); -static int fsl_nand_probe(device_t dev); -static int fsl_nand_detach(device_t dev); - -static int fsl_nfc_select_cs(device_t dev, uint8_t cs); -static int fsl_nfc_read_rnb(device_t dev); -static int fsl_nfc_send_command(device_t dev, uint8_t command); -static int fsl_nfc_send_address(device_t dev, uint8_t address); -static uint8_t fsl_nfc_read_byte(device_t dev); -static int fsl_nfc_start_command(device_t dev); -static void fsl_nfc_read_buf(device_t dev, void *buf, uint32_t len); -static void fsl_nfc_write_buf(device_t dev, void *buf, uint32_t len); - -static device_method_t fsl_nand_methods[] = { - DEVMETHOD(device_probe, fsl_nand_probe), - DEVMETHOD(device_attach, fsl_nand_attach), - DEVMETHOD(device_detach, fsl_nand_detach), - - DEVMETHOD(nfc_select_cs, fsl_nfc_select_cs), - DEVMETHOD(nfc_read_rnb, fsl_nfc_read_rnb), - DEVMETHOD(nfc_start_command, fsl_nfc_start_command), - DEVMETHOD(nfc_send_command, fsl_nfc_send_command), - DEVMETHOD(nfc_send_address, fsl_nfc_send_address), - DEVMETHOD(nfc_read_byte, fsl_nfc_read_byte), - DEVMETHOD(nfc_read_buf, fsl_nfc_read_buf), - DEVMETHOD(nfc_write_buf, fsl_nfc_write_buf), - { 0, 0 }, -}; - -static driver_t fsl_nand_driver = { - "nand", - fsl_nand_methods, - sizeof(struct fsl_nand_softc), -}; - -static devclass_t fsl_nand_devclass; - -DRIVER_MODULE(fsl_nand, lbc, fsl_nand_driver, fsl_nand_devclass, - 0, 0); - -static int fsl_nand_build_address(device_t dev, uint32_t page, uint32_t column); -static int fsl_nand_chip_preprobe(device_t dev, struct nand_id *id); - -#ifdef NAND_DEBUG_TIMING -static device_t fcm_devs[8]; -#endif - -#define CMD_SHIFT(cmd_num) (24 - ((cmd_num) * 8)) -#define OP_SHIFT(op_num) (28 - ((op_num) * 4)) - -#define FSL_LARGE_PAGE_SIZE (2112) -#define FSL_SMALL_PAGE_SIZE (528) - -static void -fsl_nand_init_regs(struct fsl_nand_softc *sc) -{ - uint32_t or_v, br_v; - device_t dev; - - dev = sc->dev; - - sc->fcm.reg_fmr = (15 << FMR_CWTO_SHIFT); - - /* - * Setup 4 row cycles and hope that chip ignores superfluous address - * bytes. - */ - sc->fcm.reg_fmr |= (2 << FMR_AL_SHIFT); - - /* Reprogram BR(x) */ - br_v = lbc_read_reg(dev, LBC85XX_BR(sc->dinfo->di_bank)); - br_v &= 0xffff8000; - br_v |= 1 << 11; /* 8-bit port size */ - br_v |= 0 << 9; /* No ECC checking and generation */ - br_v |= 1 << 5; /* FCM machine */ - br_v |= 1; /* Valid */ - lbc_write_reg(dev, LBC85XX_BR(sc->dinfo->di_bank), br_v); - - /* Reprogram OR(x) */ - or_v = lbc_read_reg(dev, LBC85XX_OR(sc->dinfo->di_bank)); - or_v &= 0xfffffc00; - or_v |= 0x03AE; /* Default POR timing */ - lbc_write_reg(dev, LBC85XX_OR(sc->dinfo->di_bank), or_v); - - if (or_v & OR_FCM_PAGESIZE) { - sc->pgsz = FSL_LARGE_PAGE_SIZE; - sc->col_cycles = 2; - nand_debug(NDBG_DRV, "%s: large page NAND device at #%d", - device_get_nameunit(dev), sc->dinfo->di_bank); - } else { - sc->pgsz = FSL_SMALL_PAGE_SIZE; - sc->col_cycles = 1; - nand_debug(NDBG_DRV, "%s: small page NAND device at #%d", - device_get_nameunit(dev), sc->dinfo->di_bank); - } -} - -static int -fsl_nand_probe(device_t dev) -{ - - if (!ofw_bus_is_compatible(dev, "fsl,elbc-fcm-nand")) - return (ENXIO); - - device_set_desc(dev, "Freescale localbus FCM Controller"); - return (BUS_PROBE_DEFAULT); -} - -static int -fsl_nand_attach(device_t dev) -{ - struct fsl_nand_softc *sc; - struct nand_id id; - struct nand_params *param; - uint32_t num_pages; - - sc = device_get_softc(dev); - sc->dev = dev; - sc->dinfo = device_get_ivars(dev); - - sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid, - RF_ACTIVE); - if (sc->res == NULL) { - device_printf(dev, "could not allocate resources!\n"); - return (ENXIO); - } - - bzero(&sc->fcm, sizeof(sc->fcm)); - - /* Init register and check if HW ECC turned on */ - fsl_nand_init_regs(sc); - - /* Chip is probed, so determine number of row address cycles */ - fsl_nand_chip_preprobe(dev, &id); - param = nand_get_params(&id); - if (param != NULL) { - num_pages = (param->chip_size << 20) / param->page_size; - while(num_pages) { - sc->row_cycles++; - num_pages >>= 8; - } - - sc->fcm.reg_fmr &= ~(FMR_AL); - sc->fcm.reg_fmr |= (sc->row_cycles - 2) << FMR_AL_SHIFT; - } - - nand_init(&sc->nand_dev, dev, NAND_ECC_SOFT, 0, 0, NULL, NULL); - -#ifdef NAND_DEBUG_TIMING - fcm_devs[sc->dinfo->di_bank] = dev; -#endif - - return (nandbus_create(dev)); -} - -static int -fsl_nand_detach(device_t dev) -{ - struct fsl_nand_softc *sc; - - sc = device_get_softc(dev); - - if (sc->res != NULL) - bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res); - - return (0); -} - -static int -fsl_nfc_select_cs(device_t dev, uint8_t cs) -{ - - // device_printf(dev, "%s(cs=%u)\n", __func__, cs); - return ((cs > 0) ? EINVAL : 0); -} - -static int -fsl_nfc_read_rnb(device_t dev) -{ - - // device_printf(dev, "%s()\n", __func__); - return (0); -} - -static int -fsl_nfc_send_command(device_t dev, uint8_t command) -{ - struct fsl_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - uint8_t fir_op; - - // device_printf(dev, "%s(command=%u)\n", __func__, command); - - sc = device_get_softc(dev); - fcm = &sc->fcm; - - if (command == NAND_CMD_PROG_END) { - fcm->reg_fir |= (FIR_OP_WB << OP_SHIFT(fcm->opnr)); - fcm->opnr++; - } - fcm->reg_fcr |= command << CMD_SHIFT(fcm->cmdnr); - fir_op = (fcm->cmdnr == 0) ? FIR_OP_CW0 : FIR_OP_CM(fcm->cmdnr); - fcm->cmdnr++; - - fcm->reg_fir |= (fir_op << OP_SHIFT(fcm->opnr)); - fcm->opnr++; - - switch (command) { - case NAND_CMD_READ_ID: - fcm->data_fir = FIR_OP_RBW; - fcm->addr_type = ADDR_ID; - break; - case NAND_CMD_SMALLOOB: - fcm->pg_ofs += 256; - /*FALLTHROUGH*/ - case NAND_CMD_SMALLB: - fcm->pg_ofs += 256; - /*FALLTHROUGH*/ - case NAND_CMD_READ: /* NAND_CMD_SMALLA */ - fcm->data_fir = FIR_OP_RBW; - fcm->addr_type = ADDR_ROWCOL; - break; - case NAND_CMD_STATUS: - fcm->data_fir = FIR_OP_RS; - fcm->status = 1; - break; - case NAND_CMD_ERASE: - fcm->addr_type = ADDR_ROW; - break; - case NAND_CMD_PROG: - fcm->addr_type = ADDR_ROWCOL; - break; - } - return (0); -} - -static int -fsl_nfc_send_address(device_t dev, uint8_t addr) -{ - struct fsl_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - uint32_t addr_bits; - - // device_printf(dev, "%s(address=%u)\n", __func__, addr); - - sc = device_get_softc(dev); - fcm = &sc->fcm; - - KASSERT(fcm->addr_type != ADDR_NONE, - ("controller doesn't expect address cycle")); - - addr_bits = addr; - - if (fcm->addr_type == ADDR_ID) { - fcm->reg_fir |= (FIR_OP_UA << OP_SHIFT(fcm->opnr)); - fcm->opnr++; - - fcm->reg_fbcr = 5; - fcm->reg_fbar = 0; - fcm->reg_fpar = 0; - fcm->reg_mdr = addr_bits; - fcm->buf_ofs = 0; - fcm->read_ptr = 0; - return (0); - } - - if (fcm->addr_type == ADDR_ROW) { - addr_bits <<= fcm->addr_bytes * 8; - fcm->row_addr |= addr_bits; - fcm->addr_bytes++; - if (fcm->addr_bytes < sc->row_cycles) - return (0); - } else { - if (fcm->addr_bytes < sc->col_cycles) { - addr_bits <<= fcm->addr_bytes * 8; - fcm->column_addr |= addr_bits; - } else { - addr_bits <<= (fcm->addr_bytes - sc->col_cycles) * 8; - fcm->row_addr |= addr_bits; - } - fcm->addr_bytes++; - if (fcm->addr_bytes < (sc->row_cycles + sc->col_cycles)) - return (0); - } - - return (fsl_nand_build_address(dev, fcm->row_addr, fcm->column_addr)); -} - -static int -fsl_nand_build_address(device_t dev, uint32_t row, uint32_t column) -{ - struct fsl_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - uint32_t byte_count = 0; - uint32_t block_address = 0; - uint32_t page_address = 0; - - sc = device_get_softc(dev); - fcm = &sc->fcm; - - fcm->read_ptr = 0; - fcm->buf_ofs = 0; - - if (fcm->addr_type == ADDR_ROWCOL) { - fcm->reg_fir |= (FIR_OP_CA << OP_SHIFT(fcm->opnr)); - fcm->opnr++; - - column += fcm->pg_ofs; - fcm->pg_ofs = 0; - - page_address |= column; - - if (column != 0) { - byte_count = sc->pgsz - column; - fcm->read_ptr = column; - } - } - - fcm->reg_fir |= (FIR_OP_PA << OP_SHIFT(fcm->opnr)); - fcm->opnr++; - - if (sc->pgsz == FSL_LARGE_PAGE_SIZE) { - block_address = row >> 6; - page_address |= ((row << FPAR_LP_PI_SHIFT) & FPAR_LP_PI); - fcm->buf_ofs = (row & 1) * 4096; - } else { - block_address = row >> 5; - page_address |= ((row << FPAR_SP_PI_SHIFT) & FPAR_SP_PI); - fcm->buf_ofs = (row & 7) * 1024; - } - - fcm->reg_fbcr = byte_count; - fcm->reg_fbar = block_address; - fcm->reg_fpar = page_address; - return (0); -} - -static int -fsl_nfc_start_command(device_t dev) -{ - struct fsl_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - uint32_t fmr, ltesr_v; - int error, timeout; - - // device_printf(dev, "%s()\n", __func__); - - sc = device_get_softc(dev); - fcm = &sc->fcm; - - fmr = fcm->reg_fmr | FMR_OP; - - if (fcm->data_fir) - fcm->reg_fir |= (fcm->data_fir << OP_SHIFT(fcm->opnr)); - - LBC_WRITE(FIR, fcm->reg_fir); - LBC_WRITE(FCR, fcm->reg_fcr); - - LBC_WRITE(FMR, fmr); - - LBC_WRITE(FBCR, fcm->reg_fbcr); - LBC_WRITE(FBAR, fcm->reg_fbar); - LBC_WRITE(FPAR, fcm->reg_fpar); - - if (fcm->addr_type == ADDR_ID) - LBC_WRITE(MDR, fcm->reg_mdr); - - nand_debug(NDBG_DRV, "BEFORE:\nFMR=%#x, FIR=%#x, FCR=%#x", fmr, - fcm->reg_fir, fcm->reg_fcr); - nand_debug(NDBG_DRV, "MDR=%#x, FBAR=%#x, FPAR=%#x, FBCR=%#x", - LBC_READ(MDR), fcm->reg_fbar, fcm->reg_fpar, fcm->reg_fbcr); - - LBC_WRITE(LSOR, sc->dinfo->di_bank); - - timeout = (cold) ? FSL_FCM_WAIT_TIMEOUT : ~0; - error = 0; - ltesr_v = LBC_READ(LTESR); - while (!error && (ltesr_v & LTESR_CC) == 0) { - if (cold) { - DELAY(1000); - timeout--; - if (timeout < 0) - error = EWOULDBLOCK; - } else - error = tsleep(device_get_parent(sc->dev), PRIBIO, - "nfcfsl", hz); - ltesr_v = LBC_READ(LTESR); - } - if (error) - nand_debug(NDBG_DRV, "Command complete wait timeout\n"); - - nand_debug(NDBG_DRV, "AFTER:\nLTESR=%#x, LTEDR=%#x, LTEIR=%#x," - " LTEATR=%#x, LTEAR=%#x, LTECCR=%#x", ltesr_v, - LBC_READ(LTEDR), LBC_READ(LTEIR), LBC_READ(LTEATR), - LBC_READ(LTEAR), LBC_READ(LTECCR)); - - bzero(&fcm->fcm_startzero, - __rangeof(struct fsl_nfc_fcm, fcm_startzero, fcm_endzero)); - - if (fcm->status) - sc->fcm.reg_mdr = LBC_READ(MDR); - - /* Even if timeout occurred, we should perform steps below */ - LBC_WRITE(LTESR, ltesr_v); - LBC_WRITE(LTEATR, 0); - - return (error); -} - -static uint8_t -fsl_nfc_read_byte(device_t dev) -{ - struct fsl_nand_softc *sc = device_get_softc(dev); - uint32_t offset; - - // device_printf(dev, "%s()\n", __func__); - - /* - * LBC controller allows us to read status into a MDR instead of FCM - * buffer. If last operation requested before read_byte() was STATUS, - * then return MDR instead of reading a single byte from a buffer. - */ - if (sc->fcm.status) { - sc->fcm.status = 0; - return (sc->fcm.reg_mdr); - } - - KASSERT(sc->fcm.read_ptr < sc->pgsz, - ("Attempt to read beyond buffer %x %x", sc->fcm.read_ptr, - sc->pgsz)); - - offset = sc->fcm.buf_ofs + sc->fcm.read_ptr; - sc->fcm.read_ptr++; - return (bus_read_1(sc->res, offset)); -} - -static void -fsl_nfc_read_buf(device_t dev, void *buf, uint32_t len) -{ - struct fsl_nand_softc *sc = device_get_softc(dev); - uint32_t offset; - int bytesleft = 0; - - // device_printf(dev, "%s(buf=%p, len=%u)\n", __func__, buf, len); - - nand_debug(NDBG_DRV, "REQUEST OF 0x%0x B (BIB=0x%0x, NTR=0x%0x)", - len, sc->pgsz, sc->fcm.read_ptr); - - bytesleft = MIN((unsigned int)len, sc->pgsz - sc->fcm.read_ptr); - - offset = sc->fcm.buf_ofs + sc->fcm.read_ptr; - bus_read_region_1(sc->res, offset, buf, bytesleft); - sc->fcm.read_ptr += bytesleft; -} - -static void -fsl_nfc_write_buf(device_t dev, void *buf, uint32_t len) -{ - struct fsl_nand_softc *sc = device_get_softc(dev); - uint32_t offset; - int bytesleft = 0; - - // device_printf(dev, "%s(buf=%p, len=%u)\n", __func__, buf, len); - - KASSERT(len <= sc->pgsz - sc->fcm.read_ptr, - ("Attempt to write beyond buffer")); - - bytesleft = MIN((unsigned int)len, sc->pgsz - sc->fcm.read_ptr); - - nand_debug(NDBG_DRV, "REQUEST TO WRITE 0x%0x (BIB=0x%0x, NTR=0x%0x)", - bytesleft, sc->pgsz, sc->fcm.read_ptr); - - offset = sc->fcm.buf_ofs + sc->fcm.read_ptr; - bus_write_region_1(sc->res, offset, buf, bytesleft); - sc->fcm.read_ptr += bytesleft; -} - -static int -fsl_nand_chip_preprobe(device_t dev, struct nand_id *id) -{ - - if (fsl_nfc_send_command(dev, NAND_CMD_RESET) != 0) - return (ENXIO); - - if (fsl_nfc_start_command(dev) != 0) - return (ENXIO); - - DELAY(1000); - - if (fsl_nfc_send_command(dev, NAND_CMD_READ_ID)) - return (ENXIO); - - if (fsl_nfc_send_address(dev, 0)) - return (ENXIO); - - if (fsl_nfc_start_command(dev) != 0) - return (ENXIO); - - DELAY(25); - - id->man_id = fsl_nfc_read_byte(dev); - id->dev_id = fsl_nfc_read_byte(dev); - - nand_debug(NDBG_DRV, "manufacturer id: %x chip id: %x", - id->man_id, id->dev_id); - - return (0); -} - -#ifdef NAND_DEBUG_TIMING - -static SYSCTL_NODE(_debug, OID_AUTO, fcm, CTLFLAG_RD, 0, "FCM timing"); - -static u_int csct = 1; /* 22: Chip select to command time (trlx). */ -SYSCTL_UINT(_debug_fcm, OID_AUTO, csct, CTLFLAG_RW, &csct, 1, - "Chip select to command time: determines how far in advance -LCSn is " - "asserted prior to any bus activity during a NAND Flash access handled " - "by the FCM. This helps meet chip-select setup times for slow memories."); - -static u_int cst = 1; /* 23: Command setup time (trlx). */ -SYSCTL_UINT(_debug_fcm, OID_AUTO, cst, CTLFLAG_RW, &cst, 1, - "Command setup time: determines the delay of -LFWE assertion relative to " - "the command, address, or data change when the external memory access " - "is handled by the FCM."); - -static u_int cht = 1; /* 24: Command hold time (trlx). */ -SYSCTL_UINT(_debug_fcm, OID_AUTO, cht, CTLFLAG_RW, &cht, 1, - "Command hold time: determines the -LFWE negation prior to the command, " - "address, or data change when the external memory access is handled by " - "the FCM."); - -static u_int scy = 2; /* 25-27: Cycle length in bus clocks */ -SYSCTL_UINT(_debug_fcm, OID_AUTO, scy, CTLFLAG_RW, &scy, 2, - "Cycle length in bus clocks: see RM"); - -static u_int rst = 1; /* 28: Read setup time (trlx). */ -SYSCTL_UINT(_debug_fcm, OID_AUTO, rst, CTLFLAG_RW, &rst, 1, - "Read setup time: determines the delay of -LFRE assertion relative to " - "sampling of read data when the external memory access is handled by " - "the FCM."); - -static u_int trlx = 1; /* 29: Timing relaxed. */ -SYSCTL_UINT(_debug_fcm, OID_AUTO, trlx, CTLFLAG_RW, &trlx, 1, - "Timing relaxed: modifies the settings of timing parameters for slow " - "memories. See RM"); - -static u_int ehtr = 1; /* 30: Extended hold time on read accesses. */ -SYSCTL_UINT(_debug_fcm, OID_AUTO, ehtr, CTLFLAG_RW, &ehtr, 1, - "Extended hold time on read accesses: indicates with TRLX how many " - "cycles are inserted between a read access from the current bank and " - "the next access."); - -static u_int -fsl_nand_get_timing(void) -{ - u_int timing; - - timing = ((csct & 1) << 9) | ((cst & 1) << 8) | ((cht & 1) << 7) | - ((scy & 7) << 4) | ((rst & 1) << 3) | ((trlx & 1) << 2) | - ((ehtr & 1) << 1); - - printf("nfc_fsl: timing = %u\n", timing); - return (timing); -} - -static int -fsl_sysctl_program(SYSCTL_HANDLER_ARGS) -{ - struct fsl_nand_softc *sc; - int error, i; - device_t dev; - uint32_t or_v; - - error = sysctl_wire_old_buffer(req, sizeof(int)); - if (error == 0) { - i = 0; - error = sysctl_handle_int(oidp, &i, 0, req); - } - if (error != 0 || req->newptr == NULL) - return (error); - - for (i = 0; i < 8; i++) { - dev = fcm_devs[i]; - if (dev == NULL) - continue; - sc = device_get_softc(dev); - - /* Reprogram OR(x) */ - or_v = lbc_read_reg(dev, LBC85XX_OR(sc->dinfo->di_bank)); - or_v &= 0xfffffc00; - or_v |= fsl_nand_get_timing(); - lbc_write_reg(dev, LBC85XX_OR(sc->dinfo->di_bank), or_v); - } - return (0); -} - -SYSCTL_PROC(_debug_fcm, OID_AUTO, program, CTLTYPE_INT | CTLFLAG_RW, NULL, 0, - fsl_sysctl_program, "I", "write to program FCM with current values"); - -#endif /* NAND_DEBUG_TIMING */ diff --git a/sys/dev/nand/nfc_fsl.h b/sys/dev/nand/nfc_fsl.h deleted file mode 100644 index 5410da558171..000000000000 --- a/sys/dev/nand/nfc_fsl.h +++ /dev/null @@ -1,99 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2012 Juniper Networks, Inc. - * Copyright (C) 2009-2012 Semihalf - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$ - */ - -#ifndef _NAND_NFC_FSL_H_ -#define _NAND_NFC_FSL_H_ - -/* LBC BR/OR Registers layout definitions */ -#define BR_V 0x00000001 -#define BR_V_SHIFT 0 -#define BR_MSEL 0x000000E0 -#define BR_MSEL_SHIFT 5 -#define BR_DECC_CHECK_MODE 0x00000600 -#define BR_DECC_CHECK_GEN 0x00000400 - -#define OR_FCM_PAGESIZE 0x00000400 - -/* Options definitions */ -#define NAND_OPT_ECC_MODE_HW 1 -#define NAND_OPT_ECC_MODE_SOFT (1 << 1) - -/* FMR - Flash Mode Register */ -#define FMR_CWTO 0xF000 -#define FMR_CWTO_SHIFT 12 -#define FMR_BOOT 0x0800 -#define FMR_ECCM 0x0100 -#define FMR_AL 0x0030 -#define FMR_AL_SHIFT 4 -#define FMR_OP 0x0003 -#define FMR_OP_SHIFT 0 - -#define FIR_OP_NOP 0x0 /* No operation and end of sequence */ -#define FIR_OP_CA 0x1 /* Issue current column address */ -#define FIR_OP_PA 0x2 /* Issue current block+page address */ -#define FIR_OP_UA 0x3 /* Issue user defined address */ -#define FIR_OP_CM(x) (4 + (x)) /* Issue command from FCR[CMD(x)] */ -#define FIR_OP_WB 0x8 /* Write FBCR bytes from FCM buffer */ -#define FIR_OP_WS 0x9 /* Write 1 or 2 bytes from MDR[AS] */ -#define FIR_OP_RB 0xA /* Read FBCR bytes to FCM buffer */ -#define FIR_OP_RS 0xB /* Read 1 or 2 bytes to MDR[AS] */ -#define FIR_OP_CW0 0xC /* Wait then issue FCR[CMD0] */ -#define FIR_OP_CW1 0xD /* Wait then issue FCR[CMD1] */ -#define FIR_OP_RBW 0xE /* Wait then read FBCR bytes */ -#define FIR_OP_RSW 0xF /* Wait then read 1 or 2 bytes */ - -/* LTESR - Transfer Error Status Register */ -#define LTESR_BM 0x80000000 -#define LTESR_FCT 0x40000000 -#define LTESR_PAR 0x20000000 -#define LTESR_WP 0x04000000 -#define LTESR_ATMW 0x00800000 -#define LTESR_ATMR 0x00400000 -#define LTESR_CS 0x00080000 -#define LTESR_CC 0x00000001 - -#define LTESR_NAND_MASK (LTESR_FCT | LTESR_CC | LTESR_CS) - -/* FPAR - Flash Page Address Register */ -#define FPAR_SP_PI 0x00007C00 -#define FPAR_SP_PI_SHIFT 10 -#define FPAR_SP_MS 0x00000200 -#define FPAR_SP_CI 0x000001FF -#define FPAR_SP_CI_SHIFT 0 -#define FPAR_LP_PI 0x0003F000 -#define FPAR_LP_PI_SHIFT 12 -#define FPAR_LP_MS 0x00000800 -#define FPAR_LP_CI 0x000007FF -#define FPAR_LP_CI_SHIFT 0 - -#define FSL_FCM_WAIT_TIMEOUT 10 - -#endif /* _NAND_NFC_FSL_H_ */ diff --git a/sys/dev/nand/nfc_if.m b/sys/dev/nand/nfc_if.m deleted file mode 100644 index a4e1099220ac..000000000000 --- a/sys/dev/nand/nfc_if.m +++ /dev/null @@ -1,165 +0,0 @@ -#- -# Copyright (C) 2009-2012 Semihalf -# 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$ - -# NAND controller interface description -# - -#include -#include - -INTERFACE nfc; - -CODE { - static int nfc_default_method(device_t dev) - { - return (0); - } - - static int nfc_softecc_get(device_t dev, void *buf, int pagesize, - void *ecc, int *needwrite) - { - *needwrite = 1; - return (nand_softecc_get(dev, buf, pagesize, ecc)); - } - - static int nfc_softecc_correct(device_t dev, void *buf, int pagesize, - void *readecc, void *calcecc) - { - return (nand_softecc_correct(dev, buf, pagesize, readecc, - calcecc)); - } -}; - -# Send command to a NAND chip -# -# Return values: -# 0: Success -# -METHOD int send_command { - device_t dev; - uint8_t command; -}; - -# Send address to a NAND chip -# -# Return values: -# 0: Success -# -METHOD int send_address { - device_t dev; - uint8_t address; -}; - -# Read byte -# -# Return values: -# byte read -# -METHOD uint8_t read_byte { - device_t dev; -}; - -# Write byte -# -METHOD void write_byte { - device_t dev; - uint8_t byte; -}; - -# Read word -# -# Return values: -# word read -# -METHOD uint16_t read_word { - device_t dev; -}; - -# Write word -# -METHOD void write_word { - device_t dev; - uint16_t word; -}; - -# Read buf -# -METHOD void read_buf { - device_t dev; - void *buf; - uint32_t len; -}; - -# Write buf -# -METHOD void write_buf { - device_t dev; - void *buf; - uint32_t len; -}; - -# Select CS -# -METHOD int select_cs { - device_t dev; - uint8_t cs; -}; - -# Read ready/busy signal -# -METHOD int read_rnb { - device_t dev; -}; - -# Start command -# -# Return values: -# 0: Success -# -METHOD int start_command { - device_t dev; -} DEFAULT nfc_default_method; - -# Generate ECC or get it from H/W -# -METHOD int get_ecc { - device_t dev; - void *buf; - int pagesize; - void *ecc; - int *needwrite; -} DEFAULT nfc_softecc_get; - -# Correct ECC -# -METHOD int correct_ecc { - device_t dev; - void *buf; - int pagesize; - void *readecc; - void *calcecc; -} DEFAULT nfc_softecc_correct; diff --git a/sys/dev/nand/nfc_mv.c b/sys/dev/nand/nfc_mv.c deleted file mode 100644 index 0d78d34d9912..000000000000 --- a/sys/dev/nand/nfc_mv.c +++ /dev/null @@ -1,238 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. - */ - -/* Integrated NAND controller driver */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include "nfc_if.h" - -#define MV_NAND_DATA (0x00) -#define MV_NAND_COMMAND (0x01) -#define MV_NAND_ADDRESS (0x02) - -struct mv_nand_softc { - struct nand_softc nand_dev; - bus_space_handle_t sc_handle; - bus_space_tag_t sc_tag; - struct resource *res; - int rid; -}; - -static int mv_nand_attach(device_t); -static int mv_nand_probe(device_t); -static int mv_nand_send_command(device_t, uint8_t); -static int mv_nand_send_address(device_t, uint8_t); -static uint8_t mv_nand_read_byte(device_t); -static void mv_nand_read_buf(device_t, void *, uint32_t); -static void mv_nand_write_buf(device_t, void *, uint32_t); -static int mv_nand_select_cs(device_t, uint8_t); -static int mv_nand_read_rnb(device_t); - -static device_method_t mv_nand_methods[] = { - DEVMETHOD(device_probe, mv_nand_probe), - DEVMETHOD(device_attach, mv_nand_attach), - - DEVMETHOD(nfc_send_command, mv_nand_send_command), - DEVMETHOD(nfc_send_address, mv_nand_send_address), - DEVMETHOD(nfc_read_byte, mv_nand_read_byte), - DEVMETHOD(nfc_read_buf, mv_nand_read_buf), - DEVMETHOD(nfc_write_buf, mv_nand_write_buf), - DEVMETHOD(nfc_select_cs, mv_nand_select_cs), - DEVMETHOD(nfc_read_rnb, mv_nand_read_rnb), - - { 0, 0 }, -}; - -static driver_t mv_nand_driver = { - "nand", - mv_nand_methods, - sizeof(struct mv_nand_softc), -}; - -static devclass_t mv_nand_devclass; -DRIVER_MODULE(mv_nand, localbus, mv_nand_driver, mv_nand_devclass, 0, 0); - -static int -mv_nand_probe(device_t dev) -{ - - if (!ofw_bus_is_compatible(dev, "mrvl,nfc")) - return (ENXIO); - - device_set_desc(dev, "Marvell NAND controller"); - return (BUS_PROBE_DEFAULT); -} - -static int -mv_nand_attach(device_t dev) -{ - struct mv_nand_softc *sc; - int err; - - sc = device_get_softc(dev); - sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid, - RF_ACTIVE); - if (sc->res == NULL) { - device_printf(dev, "could not allocate resources!\n"); - return (ENXIO); - } - - sc->sc_tag = rman_get_bustag(sc->res); - sc->sc_handle = rman_get_bushandle(sc->res); - - nand_init(&sc->nand_dev, dev, NAND_ECC_SOFT, 0, 0, NULL, NULL); - - err = nandbus_create(dev); - - return (err); -} - -static int -mv_nand_send_command(device_t dev, uint8_t command) -{ - struct mv_nand_softc *sc; - - nand_debug(NDBG_DRV,"mv_nand: send command %x", command); - - sc = device_get_softc(dev); - bus_space_write_1(sc->sc_tag, sc->sc_handle, MV_NAND_COMMAND, command); - return (0); -} - -static int -mv_nand_send_address(device_t dev, uint8_t addr) -{ - struct mv_nand_softc *sc; - - nand_debug(NDBG_DRV,"mv_nand: send address %x", addr); - - sc = device_get_softc(dev); - bus_space_write_1(sc->sc_tag, sc->sc_handle, MV_NAND_ADDRESS, addr); - return (0); -} - -static uint8_t -mv_nand_read_byte(device_t dev) -{ - struct mv_nand_softc *sc; - uint8_t data; - - sc = device_get_softc(dev); - data = bus_space_read_1(sc->sc_tag, sc->sc_handle, MV_NAND_DATA); - - nand_debug(NDBG_DRV,"mv_nand: read %x", data); - - return (data); -} - -static void -mv_nand_read_buf(device_t dev, void* buf, uint32_t len) -{ - struct mv_nand_softc *sc; - int i; - uint8_t *b = (uint8_t*)buf; - - sc = device_get_softc(dev); - - for (i = 0; i < len; i++) { - b[i] = bus_space_read_1(sc->sc_tag, sc->sc_handle, - MV_NAND_DATA); -#ifdef NAND_DEBUG - if (!(i % 16)) - printf("%s", i == 0 ? "mv_nand:\n" : "\n"); - printf(" %x", b[i]); - if (i == len - 1) - printf("\n"); -#endif - } -} - -static void -mv_nand_write_buf(device_t dev, void* buf, uint32_t len) -{ - struct mv_nand_softc *sc; - int i; - uint8_t *b = (uint8_t*)buf; - - sc = device_get_softc(dev); - - for (i = 0; i < len; i++) { -#ifdef NAND_DEBUG - if (!(i % 16)) - printf("%s", i == 0 ? "mv_nand:\n" : "\n"); - printf(" %x", b[i]); - if (i == len - 1) - printf("\n"); -#endif - bus_space_write_1(sc->sc_tag, sc->sc_handle, MV_NAND_DATA, - b[i]); - } -} - -static int -mv_nand_select_cs(device_t dev, uint8_t cs) -{ - - if (cs > 0) - return (ENODEV); - - return (0); -} - -static int -mv_nand_read_rnb(device_t dev) -{ - - /* no-op */ - return (0); /* ready */ -} diff --git a/sys/dev/nand/nfc_rb.c b/sys/dev/nand/nfc_rb.c deleted file mode 100644 index 1102b3abb9c4..000000000000 --- a/sys/dev/nand/nfc_rb.c +++ /dev/null @@ -1,321 +0,0 @@ -/*- - * Copyright (C) 2015 Justin Hibbits - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. - */ - -/* RouterBoard 600/800 NAND controller driver. */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include -#include - -#include -#include - -#include - -#include "nfc_if.h" -#include "gpio_if.h" - -#define RB_NAND_DATA (0x00) - -struct rb_nand_softc { - struct nand_softc nand_dev; - struct resource *sc_mem; - int rid; - device_t sc_gpio; - uint32_t sc_rdy_pin; - uint32_t sc_nce_pin; - uint32_t sc_cle_pin; - uint32_t sc_ale_pin; -}; - -static int rb_nand_attach(device_t); -static int rb_nand_probe(device_t); -static int rb_nand_send_command(device_t, uint8_t); -static int rb_nand_send_address(device_t, uint8_t); -static uint8_t rb_nand_read_byte(device_t); -static void rb_nand_read_buf(device_t, void *, uint32_t); -static void rb_nand_write_buf(device_t, void *, uint32_t); -static int rb_nand_select_cs(device_t, uint8_t); -static int rb_nand_read_rnb(device_t); - -static device_method_t rb_nand_methods[] = { - DEVMETHOD(device_probe, rb_nand_probe), - DEVMETHOD(device_attach, rb_nand_attach), - - DEVMETHOD(nfc_send_command, rb_nand_send_command), - DEVMETHOD(nfc_send_address, rb_nand_send_address), - DEVMETHOD(nfc_read_byte, rb_nand_read_byte), - DEVMETHOD(nfc_read_buf, rb_nand_read_buf), - DEVMETHOD(nfc_write_buf, rb_nand_write_buf), - DEVMETHOD(nfc_select_cs, rb_nand_select_cs), - DEVMETHOD(nfc_read_rnb, rb_nand_read_rnb), - - { 0, 0 }, -}; - -static driver_t rb_nand_driver = { - "nand", - rb_nand_methods, - sizeof(struct rb_nand_softc), -}; - -static devclass_t rb_nand_devclass; -DRIVER_MODULE(rb_nand, ofwbus, rb_nand_driver, rb_nand_devclass, 0, 0); - -#if 0 -static const struct nand_ecc_data rb_ecc = { - .eccsize = 6, - .eccmode = NAND_ECC_SOFT, - .eccbytes = 6, - .eccpositions = { 8, 9, 10, 13, 14, 15 }, -}; -#endif - -/* Slicer operates on the NAND controller, so we have to find the chip. */ -static int -rb_nand_slicer(device_t dev, const char *provider __unused, - struct flash_slice *slices, int *nslices) -{ - struct nand_chip *chip; - device_t *children; - int n; - - if (device_get_children(dev, &children, &n) != 0) { - panic("Slicer called on controller with no child!"); - } - dev = children[0]; - free(children, M_TEMP); - - if (device_get_children(dev, &children, &n) != 0) { - panic("Slicer called on controller with nandbus but no child!"); - } - dev = children[0]; - free(children, M_TEMP); - - chip = device_get_softc(dev); - *nslices = 2; - slices[0].base = 0; - slices[0].size = 4 * 1024 * 1024; - slices[0].label = "boot"; - - slices[1].base = 4 * 1024 * 1024; - slices[1].size = chip->ndisk->d_mediasize - slices[0].size; - slices[1].label = "rootfs"; - - return (0); -} - -static int -rb_nand_probe(device_t dev) -{ - const char *device_type; - - device_type = ofw_bus_get_type(dev); - - if (!device_type || strcmp(device_type, "rb,nand")) - return (ENXIO); - - device_set_desc(dev, "RouterBoard 333/600/800 NAND controller"); - return (BUS_PROBE_DEFAULT); -} - -static int -rb_nand_attach(device_t dev) -{ - struct rb_nand_softc *sc; - phandle_t node; - uint32_t ale[2],cle[2],nce[2],rdy[2]; - u_long size,start; - int err; - - sc = device_get_softc(dev); - node = ofw_bus_get_node(dev); - - if (OF_getprop(node, "ale", ale, sizeof(ale)) <= 0) { - return (ENXIO); - } - if (OF_getprop(node, "cle", cle, sizeof(cle)) <= 0) { - return (ENXIO); - } - if (OF_getprop(node, "nce", nce, sizeof(nce)) <= 0) { - return (ENXIO); - } - if (OF_getprop(node, "rdy", rdy, sizeof(rdy)) <= 0) { - return (ENXIO); - } - - if (ale[0] != cle[0] || ale[0] != nce[0] || ale[0] != rdy[0]) { - device_printf(dev, "GPIO handles for signals must match.\n"); - return (ENXIO); - } - sc->sc_ale_pin = ale[1]; - sc->sc_cle_pin = cle[1]; - sc->sc_nce_pin = nce[1]; - sc->sc_rdy_pin = rdy[1]; - - sc->sc_gpio = OF_device_from_xref(ale[0]); - if (sc->sc_gpio == NULL) { - device_printf(dev, "No GPIO resource found!\n"); - return (ENXIO); - } - - sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid, - RF_ACTIVE); - if (sc->sc_mem == NULL) { - device_printf(dev, "could not allocate resources!\n"); - return (ENXIO); - } - - start = rman_get_start(sc->sc_mem); - size = rman_get_size(sc->sc_mem); - if (law_enable(OCP85XX_TGTIF_LBC, start, size) != 0) { - bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->sc_mem); - device_printf(dev, "could not allocate local address window.\n"); - return (ENXIO); - } - - flash_register_slicer(rb_nand_slicer, FLASH_SLICES_TYPE_NAND, TRUE); - - nand_init(&sc->nand_dev, dev, NAND_ECC_SOFT, 0, 0, NULL, NULL); - - err = nandbus_create(dev); - - return (err); -} - -static int -rb_nand_send_command(device_t dev, uint8_t command) -{ - struct rb_nand_softc *sc; - - nand_debug(NDBG_DRV,"rb_nand: send command %x", command); - - sc = device_get_softc(dev); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_cle_pin, 1); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_ale_pin, 0); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_nce_pin, 0); - bus_write_1(sc->sc_mem, RB_NAND_DATA, command); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_cle_pin, 0); - return (0); -} - -static int -rb_nand_send_address(device_t dev, uint8_t addr) -{ - struct rb_nand_softc *sc; - - nand_debug(NDBG_DRV,"rb_nand: send address %x", addr); - - sc = device_get_softc(dev); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_cle_pin, 0); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_ale_pin, 1); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_nce_pin, 0); - bus_write_1(sc->sc_mem, RB_NAND_DATA, addr); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_ale_pin, 0); - return (0); -} - -static uint8_t -rb_nand_read_byte(device_t dev) -{ - struct rb_nand_softc *sc; - uint8_t data; - - sc = device_get_softc(dev); - data = bus_read_1(sc->sc_mem, RB_NAND_DATA); - - nand_debug(NDBG_DRV,"rb_nand: read %x", data); - - return (data); -} - -static void -rb_nand_read_buf(device_t dev, void* buf, uint32_t len) -{ - struct rb_nand_softc *sc; - - sc = device_get_softc(dev); - - bus_read_region_1(sc->sc_mem, RB_NAND_DATA, buf, len); -} - -static void -rb_nand_write_buf(device_t dev, void* buf, uint32_t len) -{ - struct rb_nand_softc *sc; - int i; - uint8_t *b = (uint8_t*)buf; - - sc = device_get_softc(dev); - - for (i = 0; i < len; i++) { -#ifdef NAND_DEBUG - if (!(i % 16)) - printf("%s", i == 0 ? "rb_nand:\n" : "\n"); - printf(" %x", b[i]); - if (i == len - 1) - printf("\n"); -#endif - bus_write_1(sc->sc_mem, RB_NAND_DATA, b[i]); - } -} - -static int -rb_nand_select_cs(device_t dev, uint8_t cs) -{ - - if (cs > 0) - return (ENODEV); - - return (0); -} - -static int -rb_nand_read_rnb(device_t dev) -{ - struct rb_nand_softc *sc; - uint32_t rdy_bit; - - sc = device_get_softc(dev); - GPIO_PIN_GET(sc->sc_gpio, sc->sc_rdy_pin, &rdy_bit); - - return (rdy_bit); /* ready */ -} diff --git a/sys/fs/nandfs/bmap.c b/sys/fs/nandfs/bmap.c deleted file mode 100644 index 5721cf0157bc..000000000000 --- a/sys/fs/nandfs/bmap.c +++ /dev/null @@ -1,625 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2012 Semihalf - * 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, 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include "nandfs_mount.h" -#include "nandfs.h" -#include "nandfs_subr.h" -#include "bmap.h" - -static int bmap_getlbns(struct nandfs_node *, nandfs_lbn_t, - struct nandfs_indir *, int *); - -int -bmap_lookup(struct nandfs_node *node, nandfs_lbn_t lblk, nandfs_daddr_t *vblk) -{ - struct nandfs_inode *ip; - struct nandfs_indir a[NANDFS_NIADDR + 1], *ap; - nandfs_daddr_t daddr; - struct buf *bp; - int error; - int num, *nump; - - DPRINTF(BMAP, ("%s: node %p lblk %jx enter\n", __func__, node, lblk)); - ip = &node->nn_inode; - - ap = a; - nump = # - - error = bmap_getlbns(node, lblk, ap, nump); - if (error) - return (error); - - if (num == 0) { - *vblk = ip->i_db[lblk]; - return (0); - } - - DPRINTF(BMAP, ("%s: node %p lblk=%jx trying ip->i_ib[%x]\n", __func__, - node, lblk, ap->in_off)); - daddr = ip->i_ib[ap->in_off]; - for (bp = NULL, ++ap; --num; ap++) { - if (daddr == 0) { - DPRINTF(BMAP, ("%s: node %p lblk=%jx returning with " - "vblk 0\n", __func__, node, lblk)); - *vblk = 0; - return (0); - } - if (ap->in_lbn == lblk) { - DPRINTF(BMAP, ("%s: node %p lblk=%jx ap->in_lbn=%jx " - "returning address of indirect block (%jx)\n", - __func__, node, lblk, ap->in_lbn, daddr)); - *vblk = daddr; - return (0); - } - - DPRINTF(BMAP, ("%s: node %p lblk=%jx reading block " - "ap->in_lbn=%jx\n", __func__, node, lblk, ap->in_lbn)); - - error = nandfs_bread_meta(node, ap->in_lbn, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - - daddr = ((nandfs_daddr_t *)bp->b_data)[ap->in_off]; - brelse(bp); - } - - DPRINTF(BMAP, ("%s: node %p lblk=%jx returning with %jx\n", __func__, - node, lblk, daddr)); - *vblk = daddr; - - return (0); -} - -int -bmap_dirty_meta(struct nandfs_node *node, nandfs_lbn_t lblk, int force) -{ - struct nandfs_indir a[NANDFS_NIADDR+1], *ap; -#ifdef DEBUG - nandfs_daddr_t daddr; -#endif - struct buf *bp; - int error; - int num, *nump; - - DPRINTF(BMAP, ("%s: node %p lblk=%jx\n", __func__, node, lblk)); - - ap = a; - nump = # - - error = bmap_getlbns(node, lblk, ap, nump); - if (error) - return (error); - - /* - * Direct block, nothing to do - */ - if (num == 0) - return (0); - - DPRINTF(BMAP, ("%s: node %p reading blocks\n", __func__, node)); - - for (bp = NULL, ++ap; --num; ap++) { - error = nandfs_bread_meta(node, ap->in_lbn, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - -#ifdef DEBUG - daddr = ((nandfs_daddr_t *)bp->b_data)[ap->in_off]; - MPASS(daddr != 0 || node->nn_ino == 3); -#endif - - error = nandfs_dirty_buf_meta(bp, force); - if (error) - return (error); - } - - return (0); -} - -int -bmap_insert_block(struct nandfs_node *node, nandfs_lbn_t lblk, - nandfs_daddr_t vblk) -{ - struct nandfs_inode *ip; - struct nandfs_indir a[NANDFS_NIADDR+1], *ap; - struct buf *bp; - nandfs_daddr_t daddr; - int error; - int num, *nump, i; - - DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx\n", __func__, node, lblk, - vblk)); - - ip = &node->nn_inode; - - ap = a; - nump = # - - error = bmap_getlbns(node, lblk, ap, nump); - if (error) - return (error); - - DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx got num=%d\n", __func__, - node, lblk, vblk, num)); - - if (num == 0) { - DPRINTF(BMAP, ("%s: node %p lblk=%jx direct block\n", __func__, - node, lblk)); - ip->i_db[lblk] = vblk; - return (0); - } - - DPRINTF(BMAP, ("%s: node %p lblk=%jx indirect block level %d\n", - __func__, node, lblk, ap->in_off)); - - if (num == 1) { - DPRINTF(BMAP, ("%s: node %p lblk=%jx indirect block: inserting " - "%jx as vblk for indirect block %d\n", __func__, node, - lblk, vblk, ap->in_off)); - ip->i_ib[ap->in_off] = vblk; - return (0); - } - - bp = NULL; - daddr = ip->i_ib[a[0].in_off]; - for (i = 1; i < num; i++) { - if (bp) - brelse(bp); - if (daddr == 0) { - DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx create " - "block %jx %d\n", __func__, node, lblk, vblk, - a[i].in_lbn, a[i].in_off)); - error = nandfs_bcreate_meta(node, a[i].in_lbn, NOCRED, - 0, &bp); - if (error) - return (error); - } else { - DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx read " - "block %jx %d\n", __func__, node, daddr, vblk, - a[i].in_lbn, a[i].in_off)); - error = nandfs_bread_meta(node, a[i].in_lbn, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - } - daddr = ((nandfs_daddr_t *)bp->b_data)[a[i].in_off]; - } - i--; - - DPRINTF(BMAP, - ("%s: bmap node %p lblk=%jx vblk=%jx inserting vblk level %d at " - "offset %d at %jx\n", __func__, node, lblk, vblk, i, a[i].in_off, - daddr)); - - if (!bp) { - nandfs_error("%s: cannot find indirect block\n", __func__); - return (-1); - } - ((nandfs_daddr_t *)bp->b_data)[a[i].in_off] = vblk; - - error = nandfs_dirty_buf_meta(bp, 0); - if (error) { - nandfs_warning("%s: dirty failed buf: %p\n", __func__, bp); - return (error); - } - DPRINTF(BMAP, ("%s: exiting node %p lblk=%jx vblk=%jx\n", __func__, - node, lblk, vblk)); - - return (error); -} - -CTASSERT(NANDFS_NIADDR <= 3); -#define SINGLE 0 /* index of single indirect block */ -#define DOUBLE 1 /* index of double indirect block */ -#define TRIPLE 2 /* index of triple indirect block */ - -static __inline nandfs_lbn_t -lbn_offset(struct nandfs_device *fsdev, int level) -{ - nandfs_lbn_t res; - - for (res = 1; level > 0; level--) - res *= MNINDIR(fsdev); - return (res); -} - -static nandfs_lbn_t -blocks_inside(struct nandfs_device *fsdev, int level, struct nandfs_indir *nip) -{ - nandfs_lbn_t blocks; - - for (blocks = 1; level >= SINGLE; level--, nip++) { - MPASS(nip->in_off >= 0 && nip->in_off < MNINDIR(fsdev)); - blocks += nip->in_off * lbn_offset(fsdev, level); - } - - return (blocks); -} - -static int -bmap_truncate_indirect(struct nandfs_node *node, int level, nandfs_lbn_t *left, - int *cleaned, struct nandfs_indir *ap, struct nandfs_indir *fp, - nandfs_daddr_t *copy) -{ - struct buf *bp; - nandfs_lbn_t i, lbn, nlbn, factor, tosub; - struct nandfs_device *fsdev; - int error, lcleaned, modified; - - DPRINTF(BMAP, ("%s: node %p level %d left %jx\n", __func__, - node, level, *left)); - - fsdev = node->nn_nandfsdev; - - MPASS(ap->in_off >= 0 && ap->in_off < MNINDIR(fsdev)); - - factor = lbn_offset(fsdev, level); - lbn = ap->in_lbn; - - error = nandfs_bread_meta(node, lbn, NOCRED, 0, &bp); - if (error) { - if (bp != NULL) - brelse(bp); - return (error); - } - - bcopy(bp->b_data, copy, fsdev->nd_blocksize); - bqrelse(bp); - - modified = 0; - - i = ap->in_off; - - if (ap != fp) - ap++; - for (nlbn = lbn + 1 - i * factor; i >= 0 && *left > 0; i--, - nlbn += factor) { - lcleaned = 0; - - DPRINTF(BMAP, - ("%s: node %p i=%jx nlbn=%jx left=%jx ap=%p vblk %jx\n", - __func__, node, i, nlbn, *left, ap, copy[i])); - - if (copy[i] == 0) { - tosub = blocks_inside(fsdev, level - 1, ap); - if (tosub > *left) - tosub = 0; - - *left -= tosub; - } else { - if (level > SINGLE) { - if (ap == fp) - ap->in_lbn = nlbn; - - error = bmap_truncate_indirect(node, level - 1, - left, &lcleaned, ap, fp, - copy + MNINDIR(fsdev)); - if (error) - return (error); - } else { - error = nandfs_bdestroy(node, copy[i]); - if (error) - return (error); - lcleaned = 1; - *left -= 1; - } - } - - if (lcleaned) { - if (level > SINGLE) { - error = nandfs_vblock_end(fsdev, copy[i]); - if (error) - return (error); - } - copy[i] = 0; - modified++; - } - - ap = fp; - } - - if (i == -1) - *cleaned = 1; - - error = nandfs_bread_meta(node, lbn, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - if (modified) - bcopy(copy, bp->b_data, fsdev->nd_blocksize); - - /* Force success even if we can't dirty the buffer metadata when freeing space */ - nandfs_dirty_buf_meta(bp, 1); - - return (0); -} - -int -bmap_truncate_mapping(struct nandfs_node *node, nandfs_lbn_t lastblk, - nandfs_lbn_t todo) -{ - struct nandfs_inode *ip; - struct nandfs_indir a[NANDFS_NIADDR + 1], f[NANDFS_NIADDR], *ap; - nandfs_daddr_t indir_lbn[NANDFS_NIADDR]; - nandfs_daddr_t *copy; - int error, level; - nandfs_lbn_t left, tosub; - struct nandfs_device *fsdev; - int cleaned, i; - int num, *nump; - - DPRINTF(BMAP, ("%s: node %p lastblk %jx truncating by %jx\n", __func__, - node, lastblk, todo)); - - ip = &node->nn_inode; - fsdev = node->nn_nandfsdev; - - ap = a; - nump = # - - error = bmap_getlbns(node, lastblk, ap, nump); - if (error) - return (error); - - indir_lbn[SINGLE] = -NANDFS_NDADDR; - indir_lbn[DOUBLE] = indir_lbn[SINGLE] - MNINDIR(fsdev) - 1; - indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - MNINDIR(fsdev) - * MNINDIR(fsdev) - 1; - - for (i = 0; i < NANDFS_NIADDR; i++) { - f[i].in_off = MNINDIR(fsdev) - 1; - f[i].in_lbn = 0xdeadbeef; - } - - left = todo; - -#ifdef DEBUG - a[num].in_off = -1; -#endif - - ap++; - num -= 2; - - if (num < 0) - goto direct; - - copy = malloc(MNINDIR(fsdev) * sizeof(nandfs_daddr_t) * (num + 1), - M_NANDFSTEMP, M_WAITOK); - - for (level = num; level >= SINGLE && left > 0; level--) { - cleaned = 0; - - if (ip->i_ib[level] == 0) { - tosub = blocks_inside(fsdev, level, ap); - if (tosub > left) - left = 0; - else - left -= tosub; - } else { - if (ap == f) - ap->in_lbn = indir_lbn[level]; - error = bmap_truncate_indirect(node, level, &left, - &cleaned, ap, f, copy); - if (error) { - free(copy, M_NANDFSTEMP); - nandfs_error("%s: error %d when truncate " - "at level %d\n", __func__, error, level); - return (error); - } - } - - if (cleaned) { - nandfs_vblock_end(fsdev, ip->i_ib[level]); - ip->i_ib[level] = 0; - } - - ap = f; - } - - free(copy, M_NANDFSTEMP); - -direct: - if (num < 0) - i = lastblk; - else - i = NANDFS_NDADDR - 1; - - for (; i >= 0 && left > 0; i--) { - if (ip->i_db[i] != 0) { - error = nandfs_bdestroy(node, ip->i_db[i]); - if (error) { - nandfs_error("%s: cannot destroy " - "block %jx, error %d\n", __func__, - (uintmax_t)ip->i_db[i], error); - return (error); - } - ip->i_db[i] = 0; - } - - left--; - } - - KASSERT(left == 0, - ("truncated wrong number of blocks (%jd should be 0)", left)); - - return (error); -} - -nandfs_lbn_t -get_maxfilesize(struct nandfs_device *fsdev) -{ - struct nandfs_indir f[NANDFS_NIADDR]; - nandfs_lbn_t max; - int i; - - max = NANDFS_NDADDR; - - for (i = 0; i < NANDFS_NIADDR; i++) { - f[i].in_off = MNINDIR(fsdev) - 1; - max += blocks_inside(fsdev, i, f); - } - - max *= fsdev->nd_blocksize; - - return (max); -} - -/* - * This is ufs_getlbns with minor modifications. - */ -/* - * Create an array of logical block number/offset pairs which represent the - * path of indirect blocks required to access a data block. The first "pair" - * contains the logical block number of the appropriate single, double or - * triple indirect block and the offset into the inode indirect block array. - * Note, the logical block number of the inode single/double/triple indirect - * block appears twice in the array, once with the offset into the i_ib and - * once with the offset into the page itself. - */ -static int -bmap_getlbns(struct nandfs_node *node, nandfs_lbn_t bn, struct nandfs_indir *ap, int *nump) -{ - nandfs_daddr_t blockcnt; - nandfs_lbn_t metalbn, realbn; - struct nandfs_device *fsdev; - int i, numlevels, off; - - fsdev = node->nn_nandfsdev; - - DPRINTF(BMAP, ("%s: node %p bn=%jx mnindir=%zd enter\n", __func__, - node, bn, MNINDIR(fsdev))); - - if (nump) - *nump = 0; - numlevels = 0; - realbn = bn; - - if (bn < 0) - bn = -bn; - - /* The first NANDFS_NDADDR blocks are direct blocks. */ - if (bn < NANDFS_NDADDR) - return (0); - - /* - * Determine the number of levels of indirection. After this loop - * is done, blockcnt indicates the number of data blocks possible - * at the previous level of indirection, and NANDFS_NIADDR - i is the - * number of levels of indirection needed to locate the requested block. - */ - for (blockcnt = 1, i = NANDFS_NIADDR, bn -= NANDFS_NDADDR;; i--, bn -= blockcnt) { - DPRINTF(BMAP, ("%s: blockcnt=%jd i=%d bn=%jd\n", __func__, - blockcnt, i, bn)); - if (i == 0) - return (EFBIG); - blockcnt *= MNINDIR(fsdev); - if (bn < blockcnt) - break; - } - - /* Calculate the address of the first meta-block. */ - if (realbn >= 0) - metalbn = -(realbn - bn + NANDFS_NIADDR - i); - else - metalbn = -(-realbn - bn + NANDFS_NIADDR - i); - - /* - * At each iteration, off is the offset into the bap array which is - * an array of disk addresses at the current level of indirection. - * The logical block number and the offset in that block are stored - * into the argument array. - */ - ap->in_lbn = metalbn; - ap->in_off = off = NANDFS_NIADDR - i; - - DPRINTF(BMAP, ("%s: initial: ap->in_lbn=%jx ap->in_off=%d\n", __func__, - metalbn, off)); - - ap++; - for (++numlevels; i <= NANDFS_NIADDR; i++) { - /* If searching for a meta-data block, quit when found. */ - if (metalbn == realbn) - break; - - blockcnt /= MNINDIR(fsdev); - off = (bn / blockcnt) % MNINDIR(fsdev); - - ++numlevels; - ap->in_lbn = metalbn; - ap->in_off = off; - - DPRINTF(BMAP, ("%s: in_lbn=%jx in_off=%d\n", __func__, - ap->in_lbn, ap->in_off)); - ++ap; - - metalbn -= -1 + off * blockcnt; - } - if (nump) - *nump = numlevels; - - DPRINTF(BMAP, ("%s: numlevels=%d\n", __func__, numlevels)); - - return (0); -} diff --git a/sys/fs/nandfs/bmap.h b/sys/fs/nandfs/bmap.h deleted file mode 100644 index a4784f7a88f9..000000000000 --- a/sys/fs/nandfs/bmap.h +++ /dev/null @@ -1,42 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2012 Semihalf - * 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, 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$ - */ - -#ifndef _BMAP_H -#define _BMAP_H - -#include "nandfs_fs.h" - -int bmap_lookup(struct nandfs_node *, nandfs_lbn_t, nandfs_daddr_t *); -int bmap_insert_block(struct nandfs_node *, nandfs_lbn_t, nandfs_daddr_t); -int bmap_truncate_mapping(struct nandfs_node *, nandfs_lbn_t, nandfs_lbn_t); -int bmap_dirty_meta(struct nandfs_node *, nandfs_lbn_t, int); - -nandfs_lbn_t get_maxfilesize(struct nandfs_device *); - -#endif /* _BMAP_H */ diff --git a/sys/fs/nandfs/nandfs.h b/sys/fs/nandfs/nandfs.h deleted file mode 100644 index 9a9b28a1bc0b..000000000000 --- a/sys/fs/nandfs/nandfs.h +++ /dev/null @@ -1,312 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf - * Copyright (c) 2008, 2009 Reinoud Zandijk - * 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, 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. - * - * From: NetBSD: nilfs.h,v 1.1 2009/07/18 16:31:42 reinoud - * - * $FreeBSD$ - */ - -#ifndef _FS_NANDFS_NANDFS_H_ -#define _FS_NANDFS_NANDFS_H_ - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include "nandfs_fs.h" - -MALLOC_DECLARE(M_NANDFSTEMP); - -/* Debug categories */ -#define NANDFS_DEBUG_VOLUMES 0x000001 -#define NANDFS_DEBUG_BLOCK 0x000004 -#define NANDFS_DEBUG_LOCKING 0x000008 -#define NANDFS_DEBUG_NODE 0x000010 -#define NANDFS_DEBUG_LOOKUP 0x000020 -#define NANDFS_DEBUG_READDIR 0x000040 -#define NANDFS_DEBUG_TRANSLATE 0x000080 -#define NANDFS_DEBUG_STRATEGY 0x000100 -#define NANDFS_DEBUG_READ 0x000200 -#define NANDFS_DEBUG_WRITE 0x000400 -#define NANDFS_DEBUG_IFILE 0x000800 -#define NANDFS_DEBUG_ATTR 0x001000 -#define NANDFS_DEBUG_EXTATTR 0x002000 -#define NANDFS_DEBUG_ALLOC 0x004000 -#define NANDFS_DEBUG_CPFILE 0x008000 -#define NANDFS_DEBUG_DIRHASH 0x010000 -#define NANDFS_DEBUG_NOTIMPL 0x020000 -#define NANDFS_DEBUG_SHEDULE 0x040000 -#define NANDFS_DEBUG_SEG 0x080000 -#define NANDFS_DEBUG_SYNC 0x100000 -#define NANDFS_DEBUG_PARANOIA 0x200000 -#define NANDFS_DEBUG_VNCALL 0x400000 -#define NANDFS_DEBUG_BUF 0x1000000 -#define NANDFS_DEBUG_BMAP 0x2000000 -#define NANDFS_DEBUG_DAT 0x4000000 -#define NANDFS_DEBUG_GENERIC 0x8000000 -#define NANDFS_DEBUG_CLEAN 0x10000000 - -extern int nandfs_verbose; - -#define DPRINTF(name, arg) { \ - if (nandfs_verbose & NANDFS_DEBUG_##name) {\ - printf arg;\ - };\ - } -#define DPRINTFIF(name, cond, arg) { \ - if (nandfs_verbose & NANDFS_DEBUG_##name) { \ - if (cond) printf arg;\ - };\ - } - -#define VFSTONANDFS(mp) ((struct nandfsmount *)((mp)->mnt_data)) -#define VTON(vp) ((struct nandfs_node *)(vp)->v_data) -#define NTOV(xp) ((xp)->nn_vnode) - -int nandfs_init(struct vfsconf *); -int nandfs_uninit(struct vfsconf *); - -extern struct vop_vector nandfs_vnodeops; -extern struct vop_vector nandfs_system_vnodeops; - -struct nandfs_node; - -/* Structure and derivatives */ -struct nandfs_mdt { - uint32_t entries_per_block; - uint32_t entries_per_group; - uint32_t blocks_per_group; - uint32_t groups_per_desc_block; /* desc is super group */ - uint32_t blocks_per_desc_block; /* desc is super group */ -}; - -struct nandfs_segment { - LIST_ENTRY(nandfs_segment) seg_link; - - struct nandfs_device *fsdev; - - TAILQ_HEAD(, buf) segsum; - TAILQ_HEAD(, buf) data; - - uint64_t seg_num; - uint64_t seg_next; - uint64_t start_block; - uint32_t num_blocks; - - uint32_t nblocks; - uint32_t nbinfos; - uint32_t segsum_blocks; - uint32_t segsum_bytes; - uint32_t bytes_left; - char *current_off; -}; - -struct nandfs_seginfo { - LIST_HEAD( ,nandfs_segment) seg_list; - struct nandfs_segment *curseg; - struct nandfs_device *fsdev; - uint32_t blocks; - uint8_t reiterate; -}; - -#define NANDFS_FSSTOR_FAILED 1 -struct nandfs_fsarea { - int offset; - int flags; - int last_used; -}; - -extern int nandfs_cleaner_enable; -extern int nandfs_cleaner_interval; -extern int nandfs_cleaner_segments; - -struct nandfs_device { - struct vnode *nd_devvp; - struct g_consumer *nd_gconsumer; - - struct thread *nd_syncer; - struct thread *nd_cleaner; - int nd_syncer_exit; - int nd_cleaner_exit; - - struct nandfs_fsarea nd_fsarea[NANDFS_NFSAREAS]; - int nd_last_fsarea; - - STAILQ_HEAD(nandfs_mnts, nandfsmount) nd_mounts; - SLIST_ENTRY(nandfs_device) nd_next_device; - - /* FS structures */ - struct nandfs_fsdata nd_fsdata; - struct nandfs_super_block nd_super; - struct nandfs_segment_summary nd_last_segsum; - struct nandfs_super_root nd_super_root; - struct nandfs_node *nd_dat_node; - struct nandfs_node *nd_cp_node; - struct nandfs_node *nd_su_node; - struct nandfs_node *nd_gc_node; - - struct nandfs_mdt nd_dat_mdt; - struct nandfs_mdt nd_ifile_mdt; - - struct timespec nd_ts; - - /* Synchronization */ - struct mtx nd_mutex; - struct mtx nd_sync_mtx; - struct cv nd_sync_cv; - struct mtx nd_clean_mtx; - struct cv nd_clean_cv; - struct lock nd_seg_const; - - struct nandfs_seginfo *nd_seginfo; - - /* FS geometry */ - uint64_t nd_devsize; - uint64_t nd_maxfilesize; - uint32_t nd_blocksize; - uint32_t nd_erasesize; - - uint32_t nd_devblocksize; - - uint32_t nd_segs_reserved; - - /* Segment usage */ - uint64_t nd_clean_segs; - uint64_t *nd_free_base; - uint64_t nd_free_count; - uint64_t nd_dirty_bufs; - - /* Running values */ - uint64_t nd_seg_sequence; - uint64_t nd_seg_num; - uint64_t nd_next_seg_num; - uint64_t nd_last_pseg; - uint64_t nd_last_cno; - uint64_t nd_last_ino; - uint64_t nd_fakevblk; - - int nd_mount_state; - int nd_refcnt; - int nd_syncing; - int nd_cleaning; -}; - -extern SLIST_HEAD(_nandfs_devices, nandfs_device) nandfs_devices; - -#define NANDFS_FORCE_SYNCER 0x1 -#define NANDFS_UMOUNT 0x2 - -#define SYNCER_UMOUNT 0x0 -#define SYNCER_VFS_SYNC 0x1 -#define SYNCER_BDFLUSH 0x2 -#define SYNCER_FFORCE 0x3 -#define SYNCER_FSYNC 0x4 -#define SYNCER_ROUPD 0x5 - -static __inline int -nandfs_writelockflags(struct nandfs_device *fsdev, int flags) -{ - int error = 0; - - if (lockstatus(&fsdev->nd_seg_const) != LK_EXCLUSIVE) - error = lockmgr(&fsdev->nd_seg_const, flags | LK_SHARED, NULL); - - return (error); -} - -static __inline void -nandfs_writeunlock(struct nandfs_device *fsdev) -{ - - if (lockstatus(&fsdev->nd_seg_const) != LK_EXCLUSIVE) - lockmgr(&(fsdev)->nd_seg_const, LK_RELEASE, NULL); -} - -#define NANDFS_WRITELOCKFLAGS(fsdev, flags) nandfs_writelockflags(fsdev, flags) - -#define NANDFS_WRITELOCK(fsdev) NANDFS_WRITELOCKFLAGS(fsdev, 0) - -#define NANDFS_WRITEUNLOCK(fsdev) nandfs_writeunlock(fsdev) - -#define NANDFS_WRITEASSERT(fsdev) lockmgr_assert(&(fsdev)->nd_seg_const, KA_LOCKED) - -/* Specific mountpoint; head or a checkpoint/snapshot */ -struct nandfsmount { - STAILQ_ENTRY(nandfsmount) nm_next_mount; - - struct mount *nm_vfs_mountp; - struct nandfs_device *nm_nandfsdev; - struct nandfs_args nm_mount_args; - struct nandfs_node *nm_ifile_node; - - uint8_t nm_flags; - int8_t nm_ronly; -}; - -struct nandfs_node { - struct vnode *nn_vnode; - struct nandfsmount *nn_nmp; - struct nandfs_device *nn_nandfsdev; - struct lockf *nn_lockf; - - uint64_t nn_ino; - struct nandfs_inode nn_inode; - - uint64_t nn_diroff; - uint32_t nn_flags; -}; - -#define IN_ACCESS 0x0001 /* Inode access time update request */ -#define IN_CHANGE 0x0002 /* Inode change time update request */ -#define IN_UPDATE 0x0004 /* Inode was written to; update mtime*/ -#define IN_MODIFIED 0x0008 /* node has been modified */ -#define IN_RENAME 0x0010 /* node is being renamed. */ - -/* File permissions. */ -#define IEXEC 0000100 /* Executable. */ -#define IWRITE 0000200 /* Writeable. */ -#define IREAD 0000400 /* Readable. */ -#define ISVTX 0001000 /* Sticky bit. */ -#define ISGID 0002000 /* Set-gid. */ -#define ISUID 0004000 /* Set-uid. */ - -#define PRINT_NODE_FLAGS \ - "\10\1IN_ACCESS\2IN_CHANGE\3IN_UPDATE\4IN_MODIFIED\5IN_RENAME" - -#define NANDFS_GATHER(x) ((x)->b_flags |= B_FS_FLAG1) -#define NANDFS_UNGATHER(x) ((x)->b_flags &= ~B_FS_FLAG1) -#define NANDFS_ISGATHERED(x) ((x)->b_flags & B_FS_FLAG1) - -#endif /* !_FS_NANDFS_NANDFS_H_ */ diff --git a/sys/fs/nandfs/nandfs_alloc.c b/sys/fs/nandfs/nandfs_alloc.c deleted file mode 100644 index afff174d130d..000000000000 --- a/sys/fs/nandfs/nandfs_alloc.c +++ /dev/null @@ -1,366 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -static void -nandfs_get_desc_block_nr(struct nandfs_mdt *mdt, uint64_t desc, - uint64_t *desc_block) -{ - - *desc_block = desc * mdt->blocks_per_desc_block; -} - -static void -nandfs_get_group_block_nr(struct nandfs_mdt *mdt, uint64_t group, - uint64_t *group_block) -{ - uint64_t desc, group_off; - - desc = group / mdt->groups_per_desc_block; - group_off = group % mdt->groups_per_desc_block; - *group_block = desc * mdt->blocks_per_desc_block + - 1 + group_off * mdt->blocks_per_group; -} - -static void -init_desc_block(struct nandfs_mdt *mdt, uint8_t *block_data) -{ - struct nandfs_block_group_desc *desc; - uint32_t i; - - desc = (struct nandfs_block_group_desc *) block_data; - for (i = 0; i < mdt->groups_per_desc_block; i++) - desc[i].bg_nfrees = mdt->entries_per_group; -} - -int -nandfs_find_free_entry(struct nandfs_mdt *mdt, struct nandfs_node *node, - struct nandfs_alloc_request *req) -{ - nandfs_daddr_t desc, group, maxgroup, maxdesc, pos = 0; - nandfs_daddr_t start_group, start_desc; - nandfs_daddr_t desc_block, group_block; - nandfs_daddr_t file_blocks; - struct nandfs_block_group_desc *descriptors; - struct buf *bp, *bp2; - uint32_t *mask, i, mcount, msize; - int error; - - file_blocks = node->nn_inode.i_blocks; - maxgroup = 0x100000000ull / mdt->entries_per_group; - maxdesc = maxgroup / mdt->groups_per_desc_block; - start_group = req->entrynum / mdt->entries_per_group; - start_desc = start_group / mdt->groups_per_desc_block; - - bp = bp2 = NULL; -restart: - for (desc = start_desc; desc < maxdesc; desc++) { - nandfs_get_desc_block_nr(mdt, desc, &desc_block); - - if (bp) - brelse(bp); - if (desc_block < file_blocks) { - error = nandfs_bread(node, desc_block, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - } else { - error = nandfs_bcreate(node, desc_block, NOCRED, 0, - &bp); - if (error) - return (error); - file_blocks++; - init_desc_block(mdt, bp->b_data); - } - - descriptors = (struct nandfs_block_group_desc *) bp->b_data; - for (group = start_group; group < mdt->groups_per_desc_block; - group++) { - if (descriptors[group].bg_nfrees > 0) { - nandfs_get_group_block_nr(mdt, group, - &group_block); - - if (bp2) - brelse(bp2); - if (group_block < file_blocks) { - error = nandfs_bread(node, group_block, - NOCRED, 0, &bp2); - if (error) { - brelse(bp); - return (error); - } - } else { - error = nandfs_bcreate(node, - group_block, NOCRED, 0, &bp2); - if (error) - return (error); - file_blocks++; - } - mask = (uint32_t *)bp2->b_data; - msize = (sizeof(uint32_t) * __CHAR_BIT); - mcount = mdt->entries_per_group / msize; - for (i = 0; i < mcount; i++) { - if (mask[i] == UINT32_MAX) - continue; - - pos = ffs(~mask[i]) - 1; - pos += (msize * i); - pos += (group * mdt->entries_per_group); - pos += desc * group * - mdt->groups_per_desc_block * - mdt->entries_per_group; - goto found; - } - } - } - start_group = 0; - } - - if (start_desc != 0) { - maxdesc = start_desc; - start_desc = 0; - req->entrynum = 0; - goto restart; - } - - return (ENOENT); - -found: - req->entrynum = pos; - req->bp_desc = bp; - req->bp_bitmap = bp2; - DPRINTF(ALLOC, ("%s: desc: %p bitmap: %p entry: %#jx\n", - __func__, req->bp_desc, req->bp_bitmap, (uintmax_t)pos)); - - return (0); -} - -int -nandfs_find_entry(struct nandfs_mdt* mdt, struct nandfs_node *nnode, - struct nandfs_alloc_request *req) -{ - uint64_t dblock, bblock, eblock; - uint32_t offset; - int error; - - nandfs_mdt_trans_blk(mdt, req->entrynum, &dblock, &bblock, &eblock, - &offset); - - error = nandfs_bread(nnode, dblock, NOCRED, 0, &req->bp_desc); - if (error) { - brelse(req->bp_desc); - return (error); - } - - error = nandfs_bread(nnode, bblock, NOCRED, 0, &req->bp_bitmap); - if (error) { - brelse(req->bp_desc); - brelse(req->bp_bitmap); - return (error); - } - - error = nandfs_bread(nnode, eblock, NOCRED, 0, &req->bp_entry); - if (error) { - brelse(req->bp_desc); - brelse(req->bp_bitmap); - brelse(req->bp_entry); - return (error); - } - - DPRINTF(ALLOC, - ("%s: desc_buf: %p bitmap_buf %p entry_buf %p offset %x\n", - __func__, req->bp_desc, req->bp_bitmap, req->bp_entry, offset)); - - return (0); -} - -static __inline void -nandfs_calc_idx_entry(struct nandfs_mdt* mdt, uint32_t entrynum, - uint64_t *group, uint64_t *bitmap_idx, uint64_t *bitmap_off) -{ - - /* Find group_desc index */ - entrynum = entrynum % - (mdt->entries_per_group * mdt->groups_per_desc_block); - *group = entrynum / mdt->entries_per_group; - /* Find bitmap index and bit offset */ - entrynum = entrynum % mdt->entries_per_group; - *bitmap_idx = entrynum / (sizeof(uint32_t) * __CHAR_BIT); - *bitmap_off = entrynum % (sizeof(uint32_t) * __CHAR_BIT); -} - -int -nandfs_free_entry(struct nandfs_mdt* mdt, struct nandfs_alloc_request *req) -{ - struct nandfs_block_group_desc *descriptors; - uint64_t bitmap_idx, bitmap_off; - uint64_t group; - uint32_t *mask, maskrw; - - nandfs_calc_idx_entry(mdt, req->entrynum, &group, &bitmap_idx, - &bitmap_off); - - DPRINTF(ALLOC, ("nandfs_free_entry: req->entrynum=%jx bitmap_idx=%jx" - " bitmap_off=%jx group=%jx\n", (uintmax_t)req->entrynum, - (uintmax_t)bitmap_idx, (uintmax_t)bitmap_off, (uintmax_t)group)); - - /* Update counter of free entries for group */ - descriptors = (struct nandfs_block_group_desc *) req->bp_desc->b_data; - descriptors[group].bg_nfrees++; - - /* Set bit to indicate that entry is taken */ - mask = (uint32_t *)req->bp_bitmap->b_data; - maskrw = mask[bitmap_idx]; - KASSERT(maskrw & (1 << bitmap_off), ("freeing unallocated vblock")); - maskrw &= ~(1 << bitmap_off); - mask[bitmap_idx] = maskrw; - - /* Make descriptor, bitmap and entry buffer dirty */ - if (nandfs_dirty_buf(req->bp_desc, 0) == 0) { - nandfs_dirty_buf(req->bp_bitmap, 1); - nandfs_dirty_buf(req->bp_entry, 1); - } else { - brelse(req->bp_bitmap); - brelse(req->bp_entry); - return (-1); - } - - return (0); -} - -int -nandfs_alloc_entry(struct nandfs_mdt* mdt, struct nandfs_alloc_request *req) -{ - struct nandfs_block_group_desc *descriptors; - uint64_t bitmap_idx, bitmap_off; - uint64_t group; - uint32_t *mask, maskrw; - - nandfs_calc_idx_entry(mdt, req->entrynum, &group, &bitmap_idx, - &bitmap_off); - - DPRINTF(ALLOC, ("nandfs_alloc_entry: req->entrynum=%jx bitmap_idx=%jx" - " bitmap_off=%jx group=%jx\n", (uintmax_t)req->entrynum, - (uintmax_t)bitmap_idx, (uintmax_t)bitmap_off, (uintmax_t)group)); - - /* Update counter of free entries for group */ - descriptors = (struct nandfs_block_group_desc *) req->bp_desc->b_data; - descriptors[group].bg_nfrees--; - - /* Clear bit to indicate that entry is free */ - mask = (uint32_t *)req->bp_bitmap->b_data; - maskrw = mask[bitmap_idx]; - maskrw |= 1 << bitmap_off; - mask[bitmap_idx] = maskrw; - - /* Make descriptor, bitmap and entry buffer dirty */ - if (nandfs_dirty_buf(req->bp_desc, 0) == 0) { - nandfs_dirty_buf(req->bp_bitmap, 1); - nandfs_dirty_buf(req->bp_entry, 1); - } else { - brelse(req->bp_bitmap); - brelse(req->bp_entry); - return (-1); - } - - return (0); -} - -void -nandfs_abort_entry(struct nandfs_alloc_request *req) -{ - - brelse(req->bp_desc); - brelse(req->bp_bitmap); - brelse(req->bp_entry); -} - -int -nandfs_get_entry_block(struct nandfs_mdt *mdt, struct nandfs_node *node, - struct nandfs_alloc_request *req, uint32_t *entry, int create) -{ - struct buf *bp; - nandfs_lbn_t blocknr; - int error; - - /* Find buffer number for given entry */ - nandfs_mdt_trans(mdt, req->entrynum, &blocknr, entry); - DPRINTF(ALLOC, ("%s: ino %#jx entrynum:%#jx block:%#jx entry:%x\n", - __func__, (uintmax_t)node->nn_ino, (uintmax_t)req->entrynum, - (uintmax_t)blocknr, *entry)); - - /* Read entry block or create if 'create' parameter is not zero */ - bp = NULL; - - if (blocknr < node->nn_inode.i_blocks) - error = nandfs_bread(node, blocknr, NOCRED, 0, &bp); - else if (create) - error = nandfs_bcreate(node, blocknr, NOCRED, 0, &bp); - else - error = E2BIG; - - if (error) { - DPRINTF(ALLOC, ("%s: ino %#jx block %#jx entry %x error %d\n", - __func__, (uintmax_t)node->nn_ino, (uintmax_t)blocknr, - *entry, error)); - if (bp) - brelse(bp); - return (error); - } - - MPASS(nandfs_vblk_get(bp) != 0 || node->nn_ino == NANDFS_DAT_INO); - - req->bp_entry = bp; - return (0); -} diff --git a/sys/fs/nandfs/nandfs_bmap.c b/sys/fs/nandfs/nandfs_bmap.c deleted file mode 100644 index 6a1c2b0775d5..000000000000 --- a/sys/fs/nandfs/nandfs_bmap.c +++ /dev/null @@ -1,232 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf - * Copyright (c) 2008, 2009 Reinoud Zandijk - * 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, 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. - * - * From: NetBSD: nilfs_subr.c,v 1.4 2009/07/29 17:06:57 reinoud - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include "nandfs_mount.h" -#include "nandfs.h" -#include "nandfs_subr.h" -#include "bmap.h" - -nandfs_lbn_t -nandfs_get_maxfilesize(struct nandfs_device *fsdev) -{ - - return (get_maxfilesize(fsdev)); -} - -int -nandfs_bmap_lookup(struct nandfs_node *node, nandfs_lbn_t lblk, - nandfs_daddr_t *vblk) -{ - int error = 0; - - if (node->nn_ino == NANDFS_GC_INO && lblk >= 0) - *vblk = lblk; - else - error = bmap_lookup(node, lblk, vblk); - - DPRINTF(TRANSLATE, ("%s: error %d ino %#jx lblocknr %#jx -> %#jx\n", - __func__, error, (uintmax_t)node->nn_ino, (uintmax_t)lblk, - (uintmax_t)*vblk)); - - if (error) - nandfs_error("%s: returned %d", __func__, error); - - return (error); -} - -int -nandfs_bmap_insert_block(struct nandfs_node *node, nandfs_lbn_t lblk, - struct buf *bp) -{ - struct nandfs_device *fsdev; - nandfs_daddr_t vblk; - int error; - - fsdev = node->nn_nandfsdev; - - vblk = 0; - if (node->nn_ino != NANDFS_DAT_INO) { - error = nandfs_vblock_alloc(fsdev, &vblk); - if (error) - return (error); - } - - nandfs_buf_set(bp, NANDFS_VBLK_ASSIGNED); - nandfs_vblk_set(bp, vblk); - - error = bmap_insert_block(node, lblk, vblk); - if (error) { - nandfs_vblock_free(fsdev, vblk); - return (error); - } - - return (0); -} - -int -nandfs_bmap_dirty_blocks(struct nandfs_node *node, struct buf *bp, int force) -{ - int error; - - error = bmap_dirty_meta(node, bp->b_lblkno, force); - if (error) - nandfs_error("%s: cannot dirty buffer %p\n", - __func__, bp); - - return (error); -} - -static int -nandfs_bmap_update_mapping(struct nandfs_node *node, nandfs_lbn_t lblk, - nandfs_daddr_t blknr) -{ - int error; - - DPRINTF(BMAP, - ("%s: node: %p ino: %#jx lblk: %#jx vblk: %#jx\n", - __func__, node, (uintmax_t)node->nn_ino, (uintmax_t)lblk, - (uintmax_t)blknr)); - - error = bmap_insert_block(node, lblk, blknr); - - return (error); -} - -int -nandfs_bmap_update_block(struct nandfs_node *node, struct buf *bp, - nandfs_lbn_t blknr) -{ - nandfs_lbn_t lblk; - int error; - - lblk = bp->b_lblkno; - nandfs_vblk_set(bp, blknr); - - DPRINTF(BMAP, ("%s: node: %p ino: %#jx bp: %p lblk: %#jx blk: %#jx\n", - __func__, node, (uintmax_t)node->nn_ino, bp, - (uintmax_t)lblk, (uintmax_t)blknr)); - - error = nandfs_bmap_update_mapping(node, lblk, blknr); - if (error) { - nandfs_error("%s: cannot update lblk:%jx to blk:%jx for " - "node:%p, error:%d\n", __func__, (uintmax_t)lblk, - (uintmax_t)blknr, node, error); - return (error); - } - - return (error); -} - -int -nandfs_bmap_update_dat(struct nandfs_node *node, nandfs_daddr_t oldblk, - struct buf *bp) -{ - struct nandfs_device *fsdev; - nandfs_daddr_t vblk = 0; - int error; - - if (node->nn_ino == NANDFS_DAT_INO) - return (0); - - if (nandfs_buf_check(bp, NANDFS_VBLK_ASSIGNED)) { - nandfs_buf_clear(bp, NANDFS_VBLK_ASSIGNED); - return (0); - } - - fsdev = node->nn_nandfsdev; - - /* First alloc new virtual block.... */ - error = nandfs_vblock_alloc(fsdev, &vblk); - if (error) - return (error); - - error = nandfs_bmap_update_block(node, bp, vblk); - if (error) - return (error); - - /* Then we can end up with old one */ - nandfs_vblock_end(fsdev, oldblk); - - DPRINTF(BMAP, - ("%s: ino %#jx block %#jx: update vblk %#jx to %#jx\n", - __func__, (uintmax_t)node->nn_ino, (uintmax_t)bp->b_lblkno, - (uintmax_t)oldblk, (uintmax_t)vblk)); - return (error); -} - -int -nandfs_bmap_truncate_mapping(struct nandfs_node *node, nandfs_lbn_t oblk, - nandfs_lbn_t nblk) -{ - nandfs_lbn_t todo; - int error; - - todo = oblk - nblk; - - DPRINTF(BMAP, ("%s: node %p oblk %jx nblk %jx truncate by %jx\n", - __func__, node, oblk, nblk, todo)); - - error = bmap_truncate_mapping(node, oblk, todo); - if (error) - return (error); - - return (error); -} diff --git a/sys/fs/nandfs/nandfs_buffer.c b/sys/fs/nandfs/nandfs_buffer.c deleted file mode 100644 index 57089718554f..000000000000 --- a/sys/fs/nandfs/nandfs_buffer.c +++ /dev/null @@ -1,85 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -struct buf * -nandfs_geteblk(int size, int flags) -{ - struct buf *bp; - - /* - * XXX - * Right now we can call geteblk with GB_NOWAIT_BD flag, which means - * it can return NULL. But we cannot afford to get NULL, hence this panic. - */ - bp = geteblk(size, flags); - if (bp == NULL) - panic("geteblk returned NULL"); - - return (bp); -} - -void -nandfs_dirty_bufs_increment(struct nandfs_device *fsdev) -{ - - mtx_lock(&fsdev->nd_mutex); - KASSERT(fsdev->nd_dirty_bufs >= 0, ("negative nd_dirty_bufs")); - fsdev->nd_dirty_bufs++; - mtx_unlock(&fsdev->nd_mutex); -} - -void -nandfs_dirty_bufs_decrement(struct nandfs_device *fsdev) -{ - - mtx_lock(&fsdev->nd_mutex); - KASSERT(fsdev->nd_dirty_bufs > 0, - ("decrementing not-positive nd_dirty_bufs")); - fsdev->nd_dirty_bufs--; - mtx_unlock(&fsdev->nd_mutex); -} diff --git a/sys/fs/nandfs/nandfs_cleaner.c b/sys/fs/nandfs/nandfs_cleaner.c deleted file mode 100644 index 3241c8701bfc..000000000000 --- a/sys/fs/nandfs/nandfs_cleaner.c +++ /dev/null @@ -1,622 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define NANDFS_CLEANER_KILL 1 - -static void nandfs_cleaner(struct nandfs_device *); -static int nandfs_cleaner_clean_segments(struct nandfs_device *, - struct nandfs_vinfo *, uint32_t, struct nandfs_period *, uint32_t, - struct nandfs_bdesc *, uint32_t, uint64_t *, uint32_t); - -static int -nandfs_process_bdesc(struct nandfs_device *nffsdev, struct nandfs_bdesc *bd, - uint64_t nmembs); - -static void -nandfs_wakeup_wait_cleaner(struct nandfs_device *fsdev, int reason) -{ - - mtx_lock(&fsdev->nd_clean_mtx); - if (reason == NANDFS_CLEANER_KILL) - fsdev->nd_cleaner_exit = 1; - if (fsdev->nd_cleaning == 0) { - fsdev->nd_cleaning = 1; - wakeup(&fsdev->nd_cleaning); - } - cv_wait(&fsdev->nd_clean_cv, &fsdev->nd_clean_mtx); - mtx_unlock(&fsdev->nd_clean_mtx); -} - -int -nandfs_start_cleaner(struct nandfs_device *fsdev) -{ - int error; - - MPASS(fsdev->nd_cleaner == NULL); - - fsdev->nd_cleaner_exit = 0; - - error = kthread_add((void(*)(void *))nandfs_cleaner, fsdev, NULL, - &fsdev->nd_cleaner, 0, 0, "nandfs_cleaner"); - if (error) - printf("nandfs: could not start cleaner: %d\n", error); - - return (error); -} - -int -nandfs_stop_cleaner(struct nandfs_device *fsdev) -{ - - MPASS(fsdev->nd_cleaner != NULL); - nandfs_wakeup_wait_cleaner(fsdev, NANDFS_CLEANER_KILL); - fsdev->nd_cleaner = NULL; - - DPRINTF(CLEAN, ("cleaner stopped\n")); - return (0); -} - -static int -nandfs_cleaner_finished(struct nandfs_device *fsdev) -{ - int exit; - - mtx_lock(&fsdev->nd_clean_mtx); - fsdev->nd_cleaning = 0; - if (!fsdev->nd_cleaner_exit) { - DPRINTF(CLEAN, ("%s: sleep\n", __func__)); - msleep(&fsdev->nd_cleaning, &fsdev->nd_clean_mtx, PRIBIO, "-", - hz * nandfs_cleaner_interval); - } - exit = fsdev->nd_cleaner_exit; - cv_broadcast(&fsdev->nd_clean_cv); - mtx_unlock(&fsdev->nd_clean_mtx); - if (exit) { - DPRINTF(CLEAN, ("%s: no longer active\n", __func__)); - return (1); - } - - return (0); -} - -static void -print_suinfo(struct nandfs_suinfo *suinfo, int nsegs) -{ - int i; - - for (i = 0; i < nsegs; i++) { - DPRINTF(CLEAN, ("%jx %jd %c%c%c %10u\n", - suinfo[i].nsi_num, suinfo[i].nsi_lastmod, - (suinfo[i].nsi_flags & - (NANDFS_SEGMENT_USAGE_ACTIVE) ? 'a' : '-'), - (suinfo[i].nsi_flags & - (NANDFS_SEGMENT_USAGE_DIRTY) ? 'd' : '-'), - (suinfo[i].nsi_flags & - (NANDFS_SEGMENT_USAGE_ERROR) ? 'e' : '-'), - suinfo[i].nsi_blocks)); - } -} - -static int -nandfs_cleaner_vblock_is_alive(struct nandfs_device *fsdev, - struct nandfs_vinfo *vinfo, struct nandfs_cpinfo *cp, uint32_t ncps) -{ - int64_t idx, min, max; - - if (vinfo->nvi_end >= fsdev->nd_last_cno) - return (1); - - if (ncps == 0) - return (0); - - if (vinfo->nvi_end < cp[0].nci_cno || - vinfo->nvi_start > cp[ncps - 1].nci_cno) - return (0); - - idx = min = 0; - max = ncps - 1; - while (min <= max) { - idx = (min + max) / 2; - if (vinfo->nvi_start == cp[idx].nci_cno) - return (1); - if (vinfo->nvi_start < cp[idx].nci_cno) - max = idx - 1; - else - min = idx + 1; - } - - return (vinfo->nvi_end >= cp[idx].nci_cno); -} - -static void -nandfs_cleaner_vinfo_mark_alive(struct nandfs_device *fsdev, - struct nandfs_vinfo *vinfo, uint32_t nmembs, struct nandfs_cpinfo *cp, - uint32_t ncps) -{ - uint32_t i; - - for (i = 0; i < nmembs; i++) - vinfo[i].nvi_alive = - nandfs_cleaner_vblock_is_alive(fsdev, &vinfo[i], cp, ncps); -} - -static int -nandfs_cleaner_bdesc_is_alive(struct nandfs_device *fsdev, - struct nandfs_bdesc *bdesc) -{ - int alive; - - alive = bdesc->bd_oblocknr == bdesc->bd_blocknr; - if (!alive) - MPASS(abs(bdesc->bd_oblocknr - bdesc->bd_blocknr) > 2); - - return (alive); -} - -static void -nandfs_cleaner_bdesc_mark_alive(struct nandfs_device *fsdev, - struct nandfs_bdesc *bdesc, uint32_t nmembs) -{ - uint32_t i; - - for (i = 0; i < nmembs; i++) - bdesc[i].bd_alive = nandfs_cleaner_bdesc_is_alive(fsdev, - &bdesc[i]); -} - -static void -nandfs_cleaner_iterate_psegment(struct nandfs_device *fsdev, - struct nandfs_segment_summary *segsum, union nandfs_binfo *binfo, - nandfs_daddr_t blk, struct nandfs_vinfo **vipp, struct nandfs_bdesc **bdpp) -{ - int i; - - DPRINTF(CLEAN, ("%s nbinfos %x\n", __func__, segsum->ss_nbinfos)); - for (i = 0; i < segsum->ss_nbinfos; i++) { - if (binfo[i].bi_v.bi_ino == NANDFS_DAT_INO) { - (*bdpp)->bd_oblocknr = blk + segsum->ss_nblocks - - segsum->ss_nbinfos + i; - /* - * XXX Hack - */ - if (segsum->ss_flags & NANDFS_SS_SR) - (*bdpp)->bd_oblocknr--; - (*bdpp)->bd_level = binfo[i].bi_dat.bi_level; - (*bdpp)->bd_offset = binfo[i].bi_dat.bi_blkoff; - (*bdpp)++; - } else { - (*vipp)->nvi_ino = binfo[i].bi_v.bi_ino; - (*vipp)->nvi_vblocknr = binfo[i].bi_v.bi_vblocknr; - (*vipp)++; - } - } -} - -static int -nandfs_cleaner_iterate_segment(struct nandfs_device *fsdev, uint64_t segno, - struct nandfs_vinfo **vipp, struct nandfs_bdesc **bdpp, int *select) -{ - struct nandfs_segment_summary *segsum; - union nandfs_binfo *binfo; - struct buf *bp; - uint32_t nblocks; - nandfs_daddr_t curr, start, end; - int error = 0; - - nandfs_get_segment_range(fsdev, segno, &start, &end); - - DPRINTF(CLEAN, ("%s: segno %jx start %jx end %jx\n", __func__, segno, - start, end)); - - *select = 0; - - for (curr = start; curr < end; curr += nblocks) { - error = nandfs_dev_bread(fsdev, curr, NOCRED, 0, &bp); - if (error) { - brelse(bp); - nandfs_error("%s: couldn't load segment summary of %jx: %d\n", - __func__, segno, error); - return (error); - } - - segsum = (struct nandfs_segment_summary *)bp->b_data; - binfo = (union nandfs_binfo *)(bp->b_data + segsum->ss_bytes); - - if (!nandfs_segsum_valid(segsum)) { - brelse(bp); - nandfs_error("nandfs: invalid summary of segment %jx\n", segno); - return (error); - } - - DPRINTF(CLEAN, ("%s: %jx magic %x bytes %x nblocks %x nbinfos " - "%x\n", __func__, segno, segsum->ss_magic, segsum->ss_bytes, - segsum->ss_nblocks, segsum->ss_nbinfos)); - - nandfs_cleaner_iterate_psegment(fsdev, segsum, binfo, curr, - vipp, bdpp); - nblocks = segsum->ss_nblocks; - brelse(bp); - } - - if (error == 0) - *select = 1; - - return (error); -} - -static int -nandfs_cleaner_choose_segment(struct nandfs_device *fsdev, uint64_t **segpp, - uint64_t nsegs, uint64_t *rseg) -{ - struct nandfs_suinfo *suinfo; - uint64_t i, ssegs; - int error; - - suinfo = malloc(sizeof(*suinfo) * nsegs, M_NANDFSTEMP, - M_ZERO | M_WAITOK); - - if (*rseg >= fsdev->nd_fsdata.f_nsegments) - *rseg = 0; - -retry: - error = nandfs_get_segment_info_filter(fsdev, suinfo, nsegs, *rseg, - &ssegs, NANDFS_SEGMENT_USAGE_DIRTY, - NANDFS_SEGMENT_USAGE_ACTIVE | NANDFS_SEGMENT_USAGE_ERROR | - NANDFS_SEGMENT_USAGE_GC); - if (error) { - nandfs_error("%s:%d", __FILE__, __LINE__); - goto out; - } - if (ssegs == 0 && *rseg != 0) { - *rseg = 0; - goto retry; - } - if (ssegs > 0) { - print_suinfo(suinfo, ssegs); - - for (i = 0; i < ssegs; i++) { - (**segpp) = suinfo[i].nsi_num; - (*segpp)++; - } - *rseg = suinfo[i - 1].nsi_num + 1; - } - -out: - free(suinfo, M_NANDFSTEMP); - return (error); -} - -static int -nandfs_cleaner_body(struct nandfs_device *fsdev, uint64_t *rseg) -{ - struct nandfs_vinfo *vinfo, *vip, *vipi; - struct nandfs_bdesc *bdesc, *bdp, *bdpi; - struct nandfs_cpstat cpstat; - struct nandfs_cpinfo *cpinfo = NULL; - uint64_t *segnums, *segp; - int select, selected; - int error = 0; - int nsegs; - int i; - - nsegs = nandfs_cleaner_segments; - - vip = vinfo = malloc(sizeof(*vinfo) * - fsdev->nd_fsdata.f_blocks_per_segment * nsegs, M_NANDFSTEMP, - M_ZERO | M_WAITOK); - bdp = bdesc = malloc(sizeof(*bdesc) * - fsdev->nd_fsdata.f_blocks_per_segment * nsegs, M_NANDFSTEMP, - M_ZERO | M_WAITOK); - segp = segnums = malloc(sizeof(*segnums) * nsegs, M_NANDFSTEMP, - M_WAITOK); - - error = nandfs_cleaner_choose_segment(fsdev, &segp, nsegs, rseg); - if (error) { - nandfs_error("%s:%d", __FILE__, __LINE__); - goto out; - } - - if (segnums == segp) - goto out; - - selected = 0; - for (i = 0; i < segp - segnums; i++) { - error = nandfs_cleaner_iterate_segment(fsdev, segnums[i], &vip, - &bdp, &select); - if (error) { - /* - * XXX deselect (see below)? - */ - goto out; - } - if (!select) - segnums[i] = NANDFS_NOSEGMENT; - else { - error = nandfs_markgc_segment(fsdev, segnums[i]); - if (error) { - nandfs_error("%s:%d\n", __FILE__, __LINE__); - goto out; - } - selected++; - } - } - - if (selected == 0) { - MPASS(vinfo == vip); - MPASS(bdesc == bdp); - goto out; - } - - error = nandfs_get_cpstat(fsdev->nd_cp_node, &cpstat); - if (error) { - nandfs_error("%s:%d\n", __FILE__, __LINE__); - goto out; - } - - if (cpstat.ncp_nss != 0) { - cpinfo = malloc(sizeof(struct nandfs_cpinfo) * cpstat.ncp_nss, - M_NANDFSTEMP, M_WAITOK); - error = nandfs_get_cpinfo(fsdev->nd_cp_node, 1, NANDFS_SNAPSHOT, - cpinfo, cpstat.ncp_nss, NULL); - if (error) { - nandfs_error("%s:%d\n", __FILE__, __LINE__); - goto out_locked; - } - } - - NANDFS_WRITELOCK(fsdev); - DPRINTF(CLEAN, ("%s: got lock\n", __func__)); - - error = nandfs_get_dat_vinfo(fsdev, vinfo, vip - vinfo); - if (error) { - nandfs_error("%s:%d\n", __FILE__, __LINE__); - goto out_locked; - } - - nandfs_cleaner_vinfo_mark_alive(fsdev, vinfo, vip - vinfo, cpinfo, - cpstat.ncp_nss); - - error = nandfs_get_dat_bdescs(fsdev, bdesc, bdp - bdesc); - if (error) { - nandfs_error("%s:%d\n", __FILE__, __LINE__); - goto out_locked; - } - - nandfs_cleaner_bdesc_mark_alive(fsdev, bdesc, bdp - bdesc); - - DPRINTF(CLEAN, ("got:\n")); - for (vipi = vinfo; vipi < vip; vipi++) { - DPRINTF(CLEAN, ("v ino %jx vblocknr %jx start %jx end %jx " - "alive %d\n", vipi->nvi_ino, vipi->nvi_vblocknr, - vipi->nvi_start, vipi->nvi_end, vipi->nvi_alive)); - } - for (bdpi = bdesc; bdpi < bdp; bdpi++) { - DPRINTF(CLEAN, ("b oblocknr %jx blocknr %jx offset %jx " - "alive %d\n", bdpi->bd_oblocknr, bdpi->bd_blocknr, - bdpi->bd_offset, bdpi->bd_alive)); - } - DPRINTF(CLEAN, ("end list\n")); - - error = nandfs_cleaner_clean_segments(fsdev, vinfo, vip - vinfo, NULL, - 0, bdesc, bdp - bdesc, segnums, segp - segnums); - if (error) - nandfs_error("%s:%d\n", __FILE__, __LINE__); - -out_locked: - NANDFS_WRITEUNLOCK(fsdev); -out: - free(cpinfo, M_NANDFSTEMP); - free(segnums, M_NANDFSTEMP); - free(bdesc, M_NANDFSTEMP); - free(vinfo, M_NANDFSTEMP); - - return (error); -} - -static void -nandfs_cleaner(struct nandfs_device *fsdev) -{ - uint64_t checked_seg = 0; - int error; - - while (!nandfs_cleaner_finished(fsdev)) { - if (!nandfs_cleaner_enable || rebooting) - continue; - - DPRINTF(CLEAN, ("%s: run started\n", __func__)); - - fsdev->nd_cleaning = 1; - - error = nandfs_cleaner_body(fsdev, &checked_seg); - - DPRINTF(CLEAN, ("%s: run finished error %d\n", __func__, - error)); - } - - DPRINTF(CLEAN, ("%s: exiting\n", __func__)); - kthread_exit(); -} - -static int -nandfs_cleaner_clean_segments(struct nandfs_device *nffsdev, - struct nandfs_vinfo *vinfo, uint32_t nvinfo, - struct nandfs_period *pd, uint32_t npd, - struct nandfs_bdesc *bdesc, uint32_t nbdesc, - uint64_t *segments, uint32_t nsegs) -{ - struct nandfs_node *gc; - struct buf *bp; - uint32_t i; - int error = 0; - - gc = nffsdev->nd_gc_node; - - DPRINTF(CLEAN, ("%s: enter\n", __func__)); - - VOP_LOCK(NTOV(gc), LK_EXCLUSIVE); - for (i = 0; i < nvinfo; i++) { - if (!vinfo[i].nvi_alive) - continue; - DPRINTF(CLEAN, ("%s: read vblknr:%#jx blk:%#jx\n", - __func__, (uintmax_t)vinfo[i].nvi_vblocknr, - (uintmax_t)vinfo[i].nvi_blocknr)); - error = nandfs_bread(nffsdev->nd_gc_node, vinfo[i].nvi_blocknr, - NULL, 0, &bp); - if (error) { - nandfs_error("%s:%d", __FILE__, __LINE__); - VOP_UNLOCK(NTOV(gc), 0); - goto out; - } - nandfs_vblk_set(bp, vinfo[i].nvi_vblocknr); - nandfs_buf_set(bp, NANDFS_VBLK_ASSIGNED); - nandfs_dirty_buf(bp, 1); - } - VOP_UNLOCK(NTOV(gc), 0); - - /* Delete checkpoints */ - for (i = 0; i < npd; i++) { - DPRINTF(CLEAN, ("delete checkpoint: %jx\n", - (uintmax_t)pd[i].p_start)); - error = nandfs_delete_cp(nffsdev->nd_cp_node, pd[i].p_start, - pd[i].p_end); - if (error) { - nandfs_error("%s:%d", __FILE__, __LINE__); - goto out; - } - } - - /* Update vblocks */ - for (i = 0; i < nvinfo; i++) { - if (vinfo[i].nvi_alive) - continue; - DPRINTF(CLEAN, ("freeing vblknr: %jx\n", vinfo[i].nvi_vblocknr)); - error = nandfs_vblock_free(nffsdev, vinfo[i].nvi_vblocknr); - if (error) { - nandfs_error("%s:%d", __FILE__, __LINE__); - goto out; - } - } - - error = nandfs_process_bdesc(nffsdev, bdesc, nbdesc); - if (error) { - nandfs_error("%s:%d", __FILE__, __LINE__); - goto out; - } - - /* Add segments to clean */ - if (nffsdev->nd_free_count) { - nffsdev->nd_free_base = realloc(nffsdev->nd_free_base, - (nffsdev->nd_free_count + nsegs) * sizeof(uint64_t), - M_NANDFSTEMP, M_WAITOK | M_ZERO); - memcpy(&nffsdev->nd_free_base[nffsdev->nd_free_count], segments, - nsegs * sizeof(uint64_t)); - nffsdev->nd_free_count += nsegs; - } else { - nffsdev->nd_free_base = malloc(nsegs * sizeof(uint64_t), - M_NANDFSTEMP, M_WAITOK|M_ZERO); - memcpy(nffsdev->nd_free_base, segments, - nsegs * sizeof(uint64_t)); - nffsdev->nd_free_count = nsegs; - } - -out: - - DPRINTF(CLEAN, ("%s: exit error %d\n", __func__, error)); - - return (error); -} - -static int -nandfs_process_bdesc(struct nandfs_device *nffsdev, struct nandfs_bdesc *bd, - uint64_t nmembs) -{ - struct nandfs_node *dat_node; - struct buf *bp; - uint64_t i; - int error; - - dat_node = nffsdev->nd_dat_node; - - VOP_LOCK(NTOV(dat_node), LK_EXCLUSIVE); - - for (i = 0; i < nmembs; i++) { - if (!bd[i].bd_alive) - continue; - DPRINTF(CLEAN, ("%s: idx %jx offset %jx\n", - __func__, i, bd[i].bd_offset)); - if (bd[i].bd_level) { - error = nandfs_bread_meta(dat_node, bd[i].bd_offset, - NULL, 0, &bp); - if (error) { - nandfs_error("%s: cannot read dat node " - "level:%d\n", __func__, bd[i].bd_level); - brelse(bp); - VOP_UNLOCK(NTOV(dat_node), 0); - return (error); - } - nandfs_dirty_buf_meta(bp, 1); - nandfs_bmap_dirty_blocks(VTON(bp->b_vp), bp, 1); - } else { - error = nandfs_bread(dat_node, bd[i].bd_offset, NULL, - 0, &bp); - if (error) { - nandfs_error("%s: cannot read dat node\n", - __func__); - brelse(bp); - VOP_UNLOCK(NTOV(dat_node), 0); - return (error); - } - nandfs_dirty_buf(bp, 1); - } - DPRINTF(CLEAN, ("%s: bp: %p\n", __func__, bp)); - } - - VOP_UNLOCK(NTOV(dat_node), 0); - - return (0); -} diff --git a/sys/fs/nandfs/nandfs_cpfile.c b/sys/fs/nandfs/nandfs_cpfile.c deleted file mode 100644 index 8c9a695879e4..000000000000 --- a/sys/fs/nandfs/nandfs_cpfile.c +++ /dev/null @@ -1,778 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "nandfs_mount.h" -#include "nandfs.h" -#include "nandfs_subr.h" - - -static int -nandfs_checkpoint_size(struct nandfs_device *fsdev) -{ - - return (fsdev->nd_fsdata.f_checkpoint_size); -} - -static int -nandfs_checkpoint_blk_offset(struct nandfs_device *fsdev, uint64_t cn, - uint64_t *blk, uint64_t *offset) -{ - uint64_t off; - uint16_t cp_size, cp_per_blk; - - KASSERT((cn), ("checkpoing cannot be zero")); - - cp_size = fsdev->nd_fsdata.f_checkpoint_size; - cp_per_blk = fsdev->nd_blocksize / cp_size; - off = roundup(sizeof(struct nandfs_cpfile_header), cp_size) / cp_size; - off += (cn - 1); - - *blk = off / cp_per_blk; - *offset = (off % cp_per_blk) * cp_size; - - return (0); -} - -static int -nandfs_checkpoint_blk_remaining(struct nandfs_device *fsdev, uint64_t cn, - uint64_t blk, uint64_t offset) -{ - uint16_t cp_size, cp_remaining; - - cp_size = fsdev->nd_fsdata.f_checkpoint_size; - cp_remaining = (fsdev->nd_blocksize - offset) / cp_size; - - return (cp_remaining); -} - -int -nandfs_get_checkpoint(struct nandfs_device *fsdev, struct nandfs_node *cp_node, - uint64_t cn) -{ - struct buf *bp; - uint64_t blk, offset; - int error; - - if (cn != fsdev->nd_last_cno && cn != (fsdev->nd_last_cno + 1)) { - return (-1); - } - - error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (-1); - } - - error = nandfs_dirty_buf(bp, 0); - if (error) - return (-1); - - - nandfs_checkpoint_blk_offset(fsdev, cn, &blk, &offset); - - if (blk != 0) { - if (blk < cp_node->nn_inode.i_blocks) - error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp); - else - error = nandfs_bcreate(cp_node, blk, NOCRED, 0, &bp); - if (error) { - if (bp) - brelse(bp); - return (-1); - } - - nandfs_dirty_buf(bp, 1); - } - - DPRINTF(CPFILE, ("%s: cn:%#jx entry block:%#jx offset:%#jx\n", - __func__, (uintmax_t)cn, (uintmax_t)blk, (uintmax_t)offset)); - - return (0); -} - -int -nandfs_set_checkpoint(struct nandfs_device *fsdev, struct nandfs_node *cp_node, - uint64_t cn, struct nandfs_inode *ifile_inode, uint64_t nblocks) -{ - struct nandfs_cpfile_header *cnh; - struct nandfs_checkpoint *cnp; - struct buf *bp; - uint64_t blk, offset; - int error; - - if (cn != fsdev->nd_last_cno && cn != (fsdev->nd_last_cno + 1)) { - nandfs_error("%s: trying to set invalid chekpoint %jx - %jx\n", - __func__, cn, fsdev->nd_last_cno); - return (-1); - } - - error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return error; - } - - cnh = (struct nandfs_cpfile_header *) bp->b_data; - cnh->ch_ncheckpoints++; - - nandfs_checkpoint_blk_offset(fsdev, cn, &blk, &offset); - - if(blk != 0) { - brelse(bp); - error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return error; - } - } - - cnp = (struct nandfs_checkpoint *)((uint8_t *)bp->b_data + offset); - cnp->cp_flags = 0; - cnp->cp_checkpoints_count = 1; - memset(&cnp->cp_snapshot_list, 0, sizeof(struct nandfs_snapshot_list)); - cnp->cp_cno = cn; - cnp->cp_create = fsdev->nd_ts.tv_sec; - cnp->cp_nblk_inc = nblocks; - cnp->cp_blocks_count = 0; - memcpy (&cnp->cp_ifile_inode, ifile_inode, sizeof(cnp->cp_ifile_inode)); - - DPRINTF(CPFILE, ("%s: cn:%#jx ctime:%#jx nblk:%#jx\n", - __func__, (uintmax_t)cn, (uintmax_t)cnp->cp_create, - (uintmax_t)nblocks)); - - brelse(bp); - return (0); -} - -static int -nandfs_cp_mounted(struct nandfs_device *nandfsdev, uint64_t cno) -{ - struct nandfsmount *nmp; - int mounted = 0; - - mtx_lock(&nandfsdev->nd_mutex); - /* No double-mounting of the same checkpoint */ - STAILQ_FOREACH(nmp, &nandfsdev->nd_mounts, nm_next_mount) { - if (nmp->nm_mount_args.cpno == cno) { - mounted = 1; - break; - } - } - mtx_unlock(&nandfsdev->nd_mutex); - - return (mounted); -} - -static int -nandfs_cp_set_snapshot(struct nandfs_node *cp_node, uint64_t cno) -{ - struct nandfs_device *fsdev; - struct nandfs_cpfile_header *cnh; - struct nandfs_checkpoint *cnp; - struct nandfs_snapshot_list *list; - struct buf *bp; - uint64_t blk, prev_blk, offset; - uint64_t curr, prev; - int error; - - fsdev = cp_node->nn_nandfsdev; - - /* Get snapshot data */ - nandfs_checkpoint_blk_offset(fsdev, cno, &blk, &offset); - error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - if (cnp->cp_flags & NANDFS_CHECKPOINT_INVALID) { - brelse(bp); - return (ENOENT); - } - if ((cnp->cp_flags & NANDFS_CHECKPOINT_SNAPSHOT)) { - brelse(bp); - return (EINVAL); - } - - brelse(bp); - /* Get list from header */ - error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - - cnh = (struct nandfs_cpfile_header *) bp->b_data; - list = &cnh->ch_snapshot_list; - prev = list->ssl_prev; - brelse(bp); - prev_blk = ~(0); - curr = 0; - while (prev > cno) { - curr = prev; - nandfs_checkpoint_blk_offset(fsdev, prev, &prev_blk, &offset); - error = nandfs_bread(cp_node, prev_blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - list = &cnp->cp_snapshot_list; - prev = list->ssl_prev; - brelse(bp); - } - - if (curr == 0) { - nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - cnh = (struct nandfs_cpfile_header *) bp->b_data; - list = &cnh->ch_snapshot_list; - } else { - nandfs_checkpoint_blk_offset(fsdev, curr, &blk, &offset); - error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - list = &cnp->cp_snapshot_list; - } - - list->ssl_prev = cno; - error = nandfs_dirty_buf(bp, 0); - if (error) - return (error); - - - /* Update snapshot for cno */ - nandfs_checkpoint_blk_offset(fsdev, cno, &blk, &offset); - error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - list = &cnp->cp_snapshot_list; - list->ssl_prev = prev; - list->ssl_next = curr; - cnp->cp_flags |= NANDFS_CHECKPOINT_SNAPSHOT; - nandfs_dirty_buf(bp, 1); - - if (prev == 0) { - nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - cnh = (struct nandfs_cpfile_header *) bp->b_data; - list = &cnh->ch_snapshot_list; - } else { - /* Update snapshot list for prev */ - nandfs_checkpoint_blk_offset(fsdev, prev, &blk, &offset); - error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - list = &cnp->cp_snapshot_list; - } - list->ssl_next = cno; - nandfs_dirty_buf(bp, 1); - - /* Update header */ - error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnh = (struct nandfs_cpfile_header *) bp->b_data; - cnh->ch_nsnapshots++; - nandfs_dirty_buf(bp, 1); - - return (0); -} - -static int -nandfs_cp_clr_snapshot(struct nandfs_node *cp_node, uint64_t cno) -{ - struct nandfs_device *fsdev; - struct nandfs_cpfile_header *cnh; - struct nandfs_checkpoint *cnp; - struct nandfs_snapshot_list *list; - struct buf *bp; - uint64_t blk, offset, snapshot_cnt; - uint64_t next, prev; - int error; - - fsdev = cp_node->nn_nandfsdev; - - /* Get snapshot data */ - nandfs_checkpoint_blk_offset(fsdev, cno, &blk, &offset); - error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - if (cnp->cp_flags & NANDFS_CHECKPOINT_INVALID) { - brelse(bp); - return (ENOENT); - } - if (!(cnp->cp_flags & NANDFS_CHECKPOINT_SNAPSHOT)) { - brelse(bp); - return (EINVAL); - } - - list = &cnp->cp_snapshot_list; - next = list->ssl_next; - prev = list->ssl_prev; - brelse(bp); - - /* Get previous snapshot */ - if (prev != 0) { - nandfs_checkpoint_blk_offset(fsdev, prev, &blk, &offset); - error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - list = &cnp->cp_snapshot_list; - } else { - nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - cnh = (struct nandfs_cpfile_header *) bp->b_data; - list = &cnh->ch_snapshot_list; - } - - list->ssl_next = next; - error = nandfs_dirty_buf(bp, 0); - if (error) - return (error); - - /* Get next snapshot */ - if (next != 0) { - nandfs_checkpoint_blk_offset(fsdev, next, &blk, &offset); - error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - list = &cnp->cp_snapshot_list; - } else { - nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - cnh = (struct nandfs_cpfile_header *) bp->b_data; - list = &cnh->ch_snapshot_list; - } - list->ssl_prev = prev; - nandfs_dirty_buf(bp, 1); - - /* Update snapshot list for cno */ - nandfs_checkpoint_blk_offset(fsdev, cno, &blk, &offset); - error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - list = &cnp->cp_snapshot_list; - list->ssl_prev = 0; - list->ssl_next = 0; - cnp->cp_flags &= !NANDFS_CHECKPOINT_SNAPSHOT; - nandfs_dirty_buf(bp, 1); - - /* Update header */ - error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnh = (struct nandfs_cpfile_header *) bp->b_data; - snapshot_cnt = cnh->ch_nsnapshots; - snapshot_cnt--; - cnh->ch_nsnapshots = snapshot_cnt; - nandfs_dirty_buf(bp, 1); - - return (0); -} - -int -nandfs_chng_cpmode(struct nandfs_node *node, struct nandfs_cpmode *ncpm) -{ - struct nandfs_device *fsdev; - uint64_t cno = ncpm->ncpm_cno; - int mode = ncpm->ncpm_mode; - int ret; - - fsdev = node->nn_nandfsdev; - VOP_LOCK(NTOV(node), LK_EXCLUSIVE); - switch (mode) { - case NANDFS_CHECKPOINT: - if (nandfs_cp_mounted(fsdev, cno)) { - ret = EBUSY; - } else - ret = nandfs_cp_clr_snapshot(node, cno); - break; - case NANDFS_SNAPSHOT: - ret = nandfs_cp_set_snapshot(node, cno); - break; - default: - ret = EINVAL; - break; - } - VOP_UNLOCK(NTOV(node), 0); - - return (ret); -} - -static void -nandfs_cpinfo_fill(struct nandfs_checkpoint *cnp, struct nandfs_cpinfo *nci) -{ - - nci->nci_flags = cnp->cp_flags; - nci->nci_pad = 0; - nci->nci_cno = cnp->cp_cno; - nci->nci_create = cnp->cp_create; - nci->nci_nblk_inc = cnp->cp_nblk_inc; - nci->nci_blocks_count = cnp->cp_blocks_count; - nci->nci_next = cnp->cp_snapshot_list.ssl_next; - DPRINTF(CPFILE, ("%s: cn:%#jx ctime:%#jx\n", - __func__, (uintmax_t)cnp->cp_cno, - (uintmax_t)cnp->cp_create)); -} - -static int -nandfs_get_cpinfo_cp(struct nandfs_node *node, uint64_t cno, - struct nandfs_cpinfo *nci, uint32_t mnmembs, uint32_t *nmembs) -{ - struct nandfs_device *fsdev; - struct buf *bp; - uint64_t blk, offset, last_cno, i; - uint16_t remaining; - int error; -#ifdef INVARIANTS - uint64_t testblk, testoffset; -#endif - - if (cno == 0) { - return (ENOENT); - } - - if (mnmembs < 1) { - return (EINVAL); - } - - fsdev = node->nn_nandfsdev; - last_cno = fsdev->nd_last_cno; - DPRINTF(CPFILE, ("%s: cno:%#jx mnmembs: %#jx last:%#jx\n", __func__, - (uintmax_t)cno, (uintmax_t)mnmembs, - (uintmax_t)fsdev->nd_last_cno)); - - /* - * do { - * get block - * read checkpoints until we hit last checkpoint, end of block or - * requested number - * } while (last read checkpoint <= last checkpoint on fs && - * read checkpoints < request number); - */ - *nmembs = i = 0; - do { - nandfs_checkpoint_blk_offset(fsdev, cno, &blk, &offset); - remaining = nandfs_checkpoint_blk_remaining(fsdev, cno, - blk, offset); - error = nandfs_bread(node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - - while (cno <= last_cno && i < mnmembs && remaining) { -#ifdef INVARIANTS - nandfs_checkpoint_blk_offset(fsdev, cno, &testblk, - &testoffset); - KASSERT(testblk == blk, ("testblk != blk")); - KASSERT(testoffset == offset, ("testoffset != offset")); -#endif - DPRINTF(CPFILE, ("%s: cno %#jx\n", __func__, - (uintmax_t)cno)); - - nandfs_cpinfo_fill((struct nandfs_checkpoint *) - (bp->b_data + offset), nci); - offset += nandfs_checkpoint_size(fsdev); - i++; - nci++; - cno++; - (*nmembs)++; - remaining--; - } - brelse(bp); - } while (cno <= last_cno && i < mnmembs); - - return (0); -} - -static int -nandfs_get_cpinfo_sp(struct nandfs_node *node, uint64_t cno, - struct nandfs_cpinfo *nci, uint32_t mnmembs, uint32_t *nmembs) -{ - struct nandfs_checkpoint *cnp; - struct nandfs_cpfile_header *cnh; - struct nandfs_device *fsdev; - struct buf *bp = NULL; - uint64_t curr = 0; - uint64_t blk, offset, curr_cno; - uint32_t flag; - int i, error; - - if (cno == 0 || cno == ~(0)) - return (ENOENT); - - fsdev = node->nn_nandfsdev; - curr_cno = cno; - - if (nmembs) - *nmembs = 0; - if (curr_cno == 1) { - /* Get list from header */ - error = nandfs_bread(node, 0, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - cnh = (struct nandfs_cpfile_header *) bp->b_data; - curr_cno = cnh->ch_snapshot_list.ssl_next; - brelse(bp); - bp = NULL; - - /* No snapshots */ - if (curr_cno == 0) - return (0); - } - - for (i = 0; i < mnmembs; i++, nci++) { - nandfs_checkpoint_blk_offset(fsdev, curr_cno, &blk, &offset); - if (i == 0 || curr != blk) { - if (bp) - brelse(bp); - error = nandfs_bread(node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (ENOENT); - } - curr = blk; - } - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - flag = cnp->cp_flags; - if (!(flag & NANDFS_CHECKPOINT_SNAPSHOT) || - (flag & NANDFS_CHECKPOINT_INVALID)) - break; - - nci->nci_flags = flag; - nci->nci_pad = 0; - nci->nci_cno = cnp->cp_cno; - nci->nci_create = cnp->cp_create; - nci->nci_nblk_inc = cnp->cp_nblk_inc; - nci->nci_blocks_count = cnp->cp_blocks_count; - nci->nci_next = cnp->cp_snapshot_list.ssl_next; - if (nmembs) - (*nmembs)++; - - curr_cno = nci->nci_next; - if (!curr_cno) - break; - } - - brelse(bp); - - return (0); -} - -int -nandfs_get_cpinfo(struct nandfs_node *node, uint64_t cno, uint16_t flags, - struct nandfs_cpinfo *nci, uint32_t nmembs, uint32_t *nnmembs) -{ - int error; - - VOP_LOCK(NTOV(node), LK_EXCLUSIVE); - switch (flags) { - case NANDFS_CHECKPOINT: - error = nandfs_get_cpinfo_cp(node, cno, nci, nmembs, nnmembs); - break; - case NANDFS_SNAPSHOT: - error = nandfs_get_cpinfo_sp(node, cno, nci, nmembs, nnmembs); - break; - default: - error = EINVAL; - break; - } - VOP_UNLOCK(NTOV(node), 0); - - return (error); -} - -int -nandfs_get_cpinfo_ioctl(struct nandfs_node *node, struct nandfs_argv *nargv) -{ - struct nandfs_cpinfo *nci; - uint64_t cno = nargv->nv_index; - void *buf = (void *)((uintptr_t)nargv->nv_base); - uint16_t flags = nargv->nv_flags; - uint32_t nmembs = 0; - int error; - - if (nargv->nv_nmembs > NANDFS_CPINFO_MAX) - return (EINVAL); - - nci = malloc(sizeof(struct nandfs_cpinfo) * nargv->nv_nmembs, - M_NANDFSTEMP, M_WAITOK | M_ZERO); - - error = nandfs_get_cpinfo(node, cno, flags, nci, nargv->nv_nmembs, &nmembs); - - if (error == 0) { - nargv->nv_nmembs = nmembs; - error = copyout(nci, buf, - sizeof(struct nandfs_cpinfo) * nmembs); - } - - free(nci, M_NANDFSTEMP); - return (error); -} - -int -nandfs_delete_cp(struct nandfs_node *node, uint64_t start, uint64_t end) -{ - struct nandfs_checkpoint *cnp; - struct nandfs_device *fsdev; - struct buf *bp; - uint64_t cno = start, blk, offset; - int error; - - DPRINTF(CPFILE, ("%s: delete cno %jx-%jx\n", __func__, start, end)); - VOP_LOCK(NTOV(node), LK_EXCLUSIVE); - fsdev = node->nn_nandfsdev; - for (cno = start; cno <= end; cno++) { - if (!cno) - continue; - - nandfs_checkpoint_blk_offset(fsdev, cno, &blk, &offset); - error = nandfs_bread(node, blk, NOCRED, 0, &bp); - if (error) { - VOP_UNLOCK(NTOV(node), 0); - brelse(bp); - return (error); - } - - cnp = (struct nandfs_checkpoint *)(bp->b_data + offset); - if (cnp->cp_flags & NANDFS_CHECKPOINT_SNAPSHOT) { - brelse(bp); - VOP_UNLOCK(NTOV(node), 0); - return (0); - } - - cnp->cp_flags |= NANDFS_CHECKPOINT_INVALID; - - error = nandfs_dirty_buf(bp, 0); - if (error) - return (error); - } - VOP_UNLOCK(NTOV(node), 0); - - return (0); -} - -int -nandfs_make_snap(struct nandfs_device *fsdev, uint64_t *cno) -{ - struct nandfs_cpmode cpm; - int error; - - *cno = cpm.ncpm_cno = fsdev->nd_last_cno; - cpm.ncpm_mode = NANDFS_SNAPSHOT; - error = nandfs_chng_cpmode(fsdev->nd_cp_node, &cpm); - return (error); -} - -int -nandfs_delete_snap(struct nandfs_device *fsdev, uint64_t cno) -{ - struct nandfs_cpmode cpm; - int error; - - cpm.ncpm_cno = cno; - cpm.ncpm_mode = NANDFS_CHECKPOINT; - error = nandfs_chng_cpmode(fsdev->nd_cp_node, &cpm); - return (error); -} - -int nandfs_get_cpstat(struct nandfs_node *cp_node, struct nandfs_cpstat *ncp) -{ - struct nandfs_device *fsdev; - struct nandfs_cpfile_header *cnh; - struct buf *bp; - int error; - - VOP_LOCK(NTOV(cp_node), LK_EXCLUSIVE); - fsdev = cp_node->nn_nandfsdev; - - /* Get header */ - error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - if (error) { - brelse(bp); - VOP_UNLOCK(NTOV(cp_node), 0); - return (error); - } - cnh = (struct nandfs_cpfile_header *) bp->b_data; - ncp->ncp_cno = fsdev->nd_last_cno; - ncp->ncp_ncps = cnh->ch_ncheckpoints; - ncp->ncp_nss = cnh->ch_nsnapshots; - DPRINTF(CPFILE, ("%s: cno:%#jx ncps:%#jx nss:%#jx\n", - __func__, ncp->ncp_cno, ncp->ncp_ncps, ncp->ncp_nss)); - brelse(bp); - VOP_UNLOCK(NTOV(cp_node), 0); - - return (0); -} diff --git a/sys/fs/nandfs/nandfs_dat.c b/sys/fs/nandfs/nandfs_dat.c deleted file mode 100644 index e81a117589f8..000000000000 --- a/sys/fs/nandfs/nandfs_dat.c +++ /dev/null @@ -1,346 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -int -nandfs_vblock_alloc(struct nandfs_device *nandfsdev, nandfs_daddr_t *vblock) -{ - struct nandfs_node *dat; - struct nandfs_mdt *mdt; - struct nandfs_alloc_request req; - struct nandfs_dat_entry *dat_entry; - uint64_t start; - uint32_t entry; - int locked, error; - - dat = nandfsdev->nd_dat_node; - mdt = &nandfsdev->nd_dat_mdt; - start = nandfsdev->nd_last_cno + 1; - - locked = NANDFS_VOP_ISLOCKED(NTOV(dat)); - if (!locked) - VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); - req.entrynum = 0; - - /* Alloc vblock number */ - error = nandfs_find_free_entry(mdt, dat, &req); - if (error) { - nandfs_error("%s: cannot find free vblk entry\n", - __func__); - if (!locked) - VOP_UNLOCK(NTOV(dat), 0); - return (error); - } - - /* Read/create buffer */ - error = nandfs_get_entry_block(mdt, dat, &req, &entry, 1); - if (error) { - nandfs_error("%s: cannot get free vblk entry\n", - __func__); - nandfs_abort_entry(&req); - if (!locked) - VOP_UNLOCK(NTOV(dat), 0); - return (error); - } - - /* Fill out vblock data */ - dat_entry = (struct nandfs_dat_entry *) req.bp_entry->b_data; - dat_entry[entry].de_start = start; - dat_entry[entry].de_end = UINTMAX_MAX; - dat_entry[entry].de_blocknr = 0; - - /* Commit allocation */ - error = nandfs_alloc_entry(mdt, &req); - if (error) { - nandfs_error("%s: cannot get free vblk entry\n", - __func__); - if (!locked) - VOP_UNLOCK(NTOV(dat), 0); - return (error); - } - - /* Return allocated vblock */ - *vblock = req.entrynum; - DPRINTF(DAT, ("%s: allocated vblock %#jx\n", - __func__, (uintmax_t)*vblock)); - - if (!locked) - VOP_UNLOCK(NTOV(dat), 0); - return (error); -} - -int -nandfs_vblock_assign(struct nandfs_device *nandfsdev, nandfs_daddr_t vblock, - nandfs_lbn_t block) -{ - struct nandfs_node *dat; - struct nandfs_mdt *mdt; - struct nandfs_alloc_request req; - struct nandfs_dat_entry *dat_entry; - uint32_t entry; - int locked, error; - - dat = nandfsdev->nd_dat_node; - mdt = &nandfsdev->nd_dat_mdt; - - locked = NANDFS_VOP_ISLOCKED(NTOV(dat)); - if (!locked) - VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); - req.entrynum = vblock; - - error = nandfs_get_entry_block(mdt, dat, &req, &entry, 0); - if (!error) { - dat_entry = (struct nandfs_dat_entry *) req.bp_entry->b_data; - dat_entry[entry].de_blocknr = block; - - DPRINTF(DAT, ("%s: assing vblock %jx->%jx\n", - __func__, (uintmax_t)vblock, (uintmax_t)block)); - - /* - * It is mostly called from syncer() so - * we want to force making buf dirty - */ - error = nandfs_dirty_buf(req.bp_entry, 1); - } - - if (!locked) - VOP_UNLOCK(NTOV(dat), 0); - - return (error); -} - -int -nandfs_vblock_end(struct nandfs_device *nandfsdev, nandfs_daddr_t vblock) -{ - struct nandfs_node *dat; - struct nandfs_mdt *mdt; - struct nandfs_alloc_request req; - struct nandfs_dat_entry *dat_entry; - uint64_t end; - uint32_t entry; - int locked, error; - - dat = nandfsdev->nd_dat_node; - mdt = &nandfsdev->nd_dat_mdt; - end = nandfsdev->nd_last_cno; - - locked = NANDFS_VOP_ISLOCKED(NTOV(dat)); - if (!locked) - VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); - req.entrynum = vblock; - - error = nandfs_get_entry_block(mdt, dat, &req, &entry, 0); - if (!error) { - dat_entry = (struct nandfs_dat_entry *) req.bp_entry->b_data; - dat_entry[entry].de_end = end; - DPRINTF(DAT, ("%s: end vblock %#jx at checkpoint %#jx\n", - __func__, (uintmax_t)vblock, (uintmax_t)end)); - - /* - * It is mostly called from syncer() so - * we want to force making buf dirty - */ - error = nandfs_dirty_buf(req.bp_entry, 1); - } - - if (!locked) - VOP_UNLOCK(NTOV(dat), 0); - - return (error); -} - -int -nandfs_vblock_free(struct nandfs_device *nandfsdev, nandfs_daddr_t vblock) -{ - struct nandfs_node *dat; - struct nandfs_mdt *mdt; - struct nandfs_alloc_request req; - int error; - - dat = nandfsdev->nd_dat_node; - mdt = &nandfsdev->nd_dat_mdt; - - VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); - req.entrynum = vblock; - - error = nandfs_find_entry(mdt, dat, &req); - if (!error) { - DPRINTF(DAT, ("%s: vblk %#jx\n", __func__, (uintmax_t)vblock)); - nandfs_free_entry(mdt, &req); - } - - VOP_UNLOCK(NTOV(dat), 0); - return (error); -} - -int -nandfs_get_dat_vinfo_ioctl(struct nandfs_device *nandfsdev, struct nandfs_argv *nargv) -{ - struct nandfs_vinfo *vinfo; - size_t size; - int error; - - if (nargv->nv_nmembs > NANDFS_VINFO_MAX) - return (EINVAL); - - size = sizeof(struct nandfs_vinfo) * nargv->nv_nmembs; - vinfo = malloc(size, M_NANDFSTEMP, M_WAITOK|M_ZERO); - - error = copyin((void *)(uintptr_t)nargv->nv_base, vinfo, size); - if (error) { - free(vinfo, M_NANDFSTEMP); - return (error); - } - - error = nandfs_get_dat_vinfo(nandfsdev, vinfo, nargv->nv_nmembs); - if (error == 0) - error = copyout(vinfo, (void *)(uintptr_t)nargv->nv_base, size); - free(vinfo, M_NANDFSTEMP); - return (error); -} - -int -nandfs_get_dat_vinfo(struct nandfs_device *nandfsdev, struct nandfs_vinfo *vinfo, - uint32_t nmembs) -{ - struct nandfs_node *dat; - struct nandfs_mdt *mdt; - struct nandfs_alloc_request req; - struct nandfs_dat_entry *dat_entry; - uint32_t i, idx; - int error = 0; - - dat = nandfsdev->nd_dat_node; - mdt = &nandfsdev->nd_dat_mdt; - - DPRINTF(DAT, ("%s: nmembs %#x\n", __func__, nmembs)); - - VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); - - for (i = 0; i < nmembs; i++) { - req.entrynum = vinfo[i].nvi_vblocknr; - - error = nandfs_get_entry_block(mdt, dat,&req, &idx, 0); - if (error) - break; - - dat_entry = ((struct nandfs_dat_entry *) req.bp_entry->b_data); - vinfo[i].nvi_start = dat_entry[idx].de_start; - vinfo[i].nvi_end = dat_entry[idx].de_end; - vinfo[i].nvi_blocknr = dat_entry[idx].de_blocknr; - - DPRINTF(DAT, ("%s: vinfo: %jx[%jx-%jx]->%jx\n", - __func__, vinfo[i].nvi_vblocknr, vinfo[i].nvi_start, - vinfo[i].nvi_end, vinfo[i].nvi_blocknr)); - - brelse(req.bp_entry); - } - - VOP_UNLOCK(NTOV(dat), 0); - return (error); -} - -int -nandfs_get_dat_bdescs_ioctl(struct nandfs_device *nffsdev, - struct nandfs_argv *nargv) -{ - struct nandfs_bdesc *bd; - size_t size; - int error; - - size = nargv->nv_nmembs * sizeof(struct nandfs_bdesc); - bd = malloc(size, M_NANDFSTEMP, M_WAITOK); - error = copyin((void *)(uintptr_t)nargv->nv_base, bd, size); - if (error) { - free(bd, M_NANDFSTEMP); - return (error); - } - - error = nandfs_get_dat_bdescs(nffsdev, bd, nargv->nv_nmembs); - - if (error == 0) - error = copyout(bd, (void *)(uintptr_t)nargv->nv_base, size); - - free(bd, M_NANDFSTEMP); - return (error); -} - -int -nandfs_get_dat_bdescs(struct nandfs_device *nffsdev, struct nandfs_bdesc *bd, - uint32_t nmembs) -{ - struct nandfs_node *dat_node; - uint64_t map; - uint32_t i; - int error = 0; - - dat_node = nffsdev->nd_dat_node; - - VOP_LOCK(NTOV(dat_node), LK_EXCLUSIVE); - - for (i = 0; i < nmembs; i++) { - DPRINTF(CLEAN, - ("%s: bd ino:%#jx oblk:%#jx blocknr:%#jx off:%#jx\n", - __func__, (uintmax_t)bd[i].bd_ino, - (uintmax_t)bd[i].bd_oblocknr, (uintmax_t)bd[i].bd_blocknr, - (uintmax_t)bd[i].bd_offset)); - - error = nandfs_bmap_lookup(dat_node, bd[i].bd_offset, &map); - if (error) - break; - bd[i].bd_blocknr = map; - } - - VOP_UNLOCK(NTOV(dat_node), 0); - return (error); -} diff --git a/sys/fs/nandfs/nandfs_dir.c b/sys/fs/nandfs/nandfs_dir.c deleted file mode 100644 index 404edecfaa08..000000000000 --- a/sys/fs/nandfs/nandfs_dir.c +++ /dev/null @@ -1,316 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf - * Copyright (c) 2008, 2009 Reinoud Zandijk - * 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, 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. - * - * From: NetBSD: nilfs_subr.c,v 1.4 2009/07/29 17:06:57 reinoud - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "nandfs_mount.h" -#include "nandfs.h" -#include "nandfs_subr.h" - -int -nandfs_add_dirent(struct vnode *dvp, uint64_t ino, char *nameptr, long namelen, - uint8_t type) -{ - struct nandfs_node *dir_node = VTON(dvp); - struct nandfs_dir_entry *dirent, *pdirent; - uint32_t blocksize = dir_node->nn_nandfsdev->nd_blocksize; - uint64_t filesize = dir_node->nn_inode.i_size; - uint64_t inode_blks = dir_node->nn_inode.i_blocks; - uint32_t off, rest; - uint8_t *pos; - struct buf *bp; - int error; - - pdirent = NULL; - bp = NULL; - if (inode_blks) { - error = nandfs_bread(dir_node, inode_blks - 1, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - - pos = bp->b_data; - off = 0; - while (off < blocksize) { - pdirent = (struct nandfs_dir_entry *) (pos + off); - if (!pdirent->rec_len) { - pdirent = NULL; - break; - } - off += pdirent->rec_len; - } - - if (pdirent) - rest = pdirent->rec_len - - NANDFS_DIR_REC_LEN(pdirent->name_len); - else - rest = blocksize; - - if (rest < NANDFS_DIR_REC_LEN(namelen)) { - /* Do not update pdirent as new block is created */ - pdirent = NULL; - brelse(bp); - /* Set to NULL to create new */ - bp = NULL; - filesize += rest; - } - } - - /* If no bp found create new */ - if (!bp) { - error = nandfs_bcreate(dir_node, inode_blks, NOCRED, 0, &bp); - if (error) - return (error); - off = 0; - pos = bp->b_data; - } - - /* Modify pdirent if exists */ - if (pdirent) { - DPRINTF(LOOKUP, ("modify pdirent %p\n", pdirent)); - /* modify last de */ - off -= pdirent->rec_len; - pdirent->rec_len = - NANDFS_DIR_REC_LEN(pdirent->name_len); - off += pdirent->rec_len; - } - - /* Create new dirent */ - dirent = (struct nandfs_dir_entry *) (pos + off); - dirent->rec_len = blocksize - off; - dirent->inode = ino; - dirent->name_len = namelen; - memset(dirent->name, 0, NANDFS_DIR_NAME_LEN(namelen)); - memcpy(dirent->name, nameptr, namelen); - dirent->file_type = type; - - filesize += NANDFS_DIR_REC_LEN(dirent->name_len); - - DPRINTF(LOOKUP, ("create dir_entry '%.*s' at %p with size %x " - "new filesize: %jx\n", - (int)namelen, dirent->name, dirent, dirent->rec_len, - (uintmax_t)filesize)); - - error = nandfs_dirty_buf(bp, 0); - if (error) - return (error); - - dir_node->nn_inode.i_size = filesize; - dir_node->nn_flags |= IN_CHANGE | IN_UPDATE; - vnode_pager_setsize(dvp, filesize); - - return (0); -} - -int -nandfs_remove_dirent(struct vnode *dvp, struct nandfs_node *node, - struct componentname *cnp) -{ - struct nandfs_node *dir_node; - struct nandfs_dir_entry *dirent, *pdirent; - struct buf *bp; - uint64_t filesize, blocknr, ino, offset; - uint32_t blocksize, limit, off; - uint16_t newsize; - uint8_t *pos; - int error, found; - - dir_node = VTON(dvp); - filesize = dir_node->nn_inode.i_size; - if (!filesize) - return (0); - - if (node) { - offset = node->nn_diroff; - ino = node->nn_ino; - } else { - offset = dir_node->nn_diroff; - ino = NANDFS_WHT_INO; - } - - dirent = pdirent = NULL; - blocksize = dir_node->nn_nandfsdev->nd_blocksize; - blocknr = offset / blocksize; - - DPRINTF(LOOKUP, ("rm direntry dvp %p node %p ino %#jx at off %#jx\n", - dvp, node, (uintmax_t)ino, (uintmax_t)offset)); - - error = nandfs_bread(dir_node, blocknr, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - - pos = bp->b_data; - off = 0; - found = 0; - limit = offset % blocksize; - pdirent = (struct nandfs_dir_entry *) bp->b_data; - while (off <= limit) { - dirent = (struct nandfs_dir_entry *) (pos + off); - - if ((off == limit) && - (dirent->inode == ino)) { - found = 1; - break; - } - if (dirent->inode != 0) - pdirent = dirent; - off += dirent->rec_len; - } - - if (!found) { - nandfs_error("cannot find entry to remove"); - brelse(bp); - return (error); - } - DPRINTF(LOOKUP, - ("rm dirent ino %#jx at %#x with size %#x\n", - (uintmax_t)dirent->inode, off, dirent->rec_len)); - - newsize = (uintptr_t)dirent - (uintptr_t)pdirent; - newsize += dirent->rec_len; - pdirent->rec_len = newsize; - dirent->inode = 0; - error = nandfs_dirty_buf(bp, 0); - if (error) - return (error); - - dir_node->nn_flags |= IN_CHANGE | IN_UPDATE; - /* If last one modify filesize */ - if ((offset + NANDFS_DIR_REC_LEN(dirent->name_len)) == filesize) { - filesize = blocknr * blocksize + - ((uintptr_t)pdirent - (uintptr_t)pos) + - NANDFS_DIR_REC_LEN(pdirent->name_len); - dir_node->nn_inode.i_size = filesize; - } - - return (0); -} - -int -nandfs_update_parent_dir(struct vnode *dvp, uint64_t newparent) -{ - struct nandfs_dir_entry *dirent; - struct nandfs_node *dir_node; - struct buf *bp; - int error; - - dir_node = VTON(dvp); - error = nandfs_bread(dir_node, 0, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - dirent = (struct nandfs_dir_entry *)bp->b_data; - dirent->inode = newparent; - error = nandfs_dirty_buf(bp, 0); - if (error) - return (error); - - return (0); -} - -int -nandfs_update_dirent(struct vnode *dvp, struct nandfs_node *fnode, - struct nandfs_node *tnode) -{ - struct nandfs_node *dir_node; - struct nandfs_dir_entry *dirent; - struct buf *bp; - uint64_t file_size, blocknr; - uint32_t blocksize, off; - uint8_t *pos; - int error; - - dir_node = VTON(dvp); - file_size = dir_node->nn_inode.i_size; - if (!file_size) - return (0); - - DPRINTF(LOOKUP, - ("chg direntry dvp %p ino %#jx to in %#jx at off %#jx\n", - dvp, (uintmax_t)tnode->nn_ino, (uintmax_t)fnode->nn_ino, - (uintmax_t)tnode->nn_diroff)); - - blocksize = dir_node->nn_nandfsdev->nd_blocksize; - blocknr = tnode->nn_diroff / blocksize; - off = tnode->nn_diroff % blocksize; - error = nandfs_bread(dir_node, blocknr, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - - pos = bp->b_data; - dirent = (struct nandfs_dir_entry *) (pos + off); - KASSERT((dirent->inode == tnode->nn_ino), - ("direntry mismatch")); - - dirent->inode = fnode->nn_ino; - error = nandfs_dirty_buf(bp, 0); - if (error) - return (error); - - return (0); -} - -int -nandfs_init_dir(struct vnode *dvp, uint64_t ino, uint64_t parent_ino) -{ - - if (nandfs_add_dirent(dvp, parent_ino, "..", 2, DT_DIR) || - nandfs_add_dirent(dvp, ino, ".", 1, DT_DIR)) { - nandfs_error("%s: cannot initialize dir ino:%jd(pino:%jd)\n", - __func__, ino, parent_ino); - return (-1); - } - return (0); -} diff --git a/sys/fs/nandfs/nandfs_fs.h b/sys/fs/nandfs/nandfs_fs.h deleted file mode 100644 index 9cb440ebcb90..000000000000 --- a/sys/fs/nandfs/nandfs_fs.h +++ /dev/null @@ -1,567 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf - * Copyright (c) 2008, 2009 Reinoud Zandijk - * 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, 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. - * - * Original definitions written by Koji Sato - * and Ryusuke Konishi - * From: NetBSD: nandfs_fs.h,v 1.1 2009/07/18 16:31:42 reinoud - * - * $FreeBSD$ - */ - -#ifndef _NANDFS_FS_H -#define _NANDFS_FS_H - -#include - -#define MNINDIR(fsdev) ((fsdev)->nd_blocksize / sizeof(nandfs_daddr_t)) - -/* - * Inode structure. There are a few dedicated inode numbers that are - * defined here first. - */ -#define NANDFS_WHT_INO 1 /* Whiteout ino */ -#define NANDFS_ROOT_INO 2 /* Root file inode */ -#define NANDFS_DAT_INO 3 /* DAT file */ -#define NANDFS_CPFILE_INO 4 /* checkpoint file */ -#define NANDFS_SUFILE_INO 5 /* segment usage file */ -#define NANDFS_IFILE_INO 6 /* ifile */ -#define NANDFS_GC_INO 7 /* Cleanerd node */ -#define NANDFS_ATIME_INO 8 /* Atime file (reserved) */ -#define NANDFS_XATTR_INO 9 /* Xattribute file (reserved) */ -#define NANDFS_SKETCH_INO 10 /* Sketch file (obsolete) */ -#define NANDFS_USER_INO 11 /* First user's file inode number */ - -#define NANDFS_SYS_NODE(ino) \ - (((ino) >= NANDFS_DAT_INO) && ((ino) <= NANDFS_GC_INO)) - -#define NANDFS_NDADDR 12 /* Direct addresses in inode. */ -#define NANDFS_NIADDR 3 /* Indirect addresses in inode. */ - -typedef int64_t nandfs_daddr_t; -typedef int64_t nandfs_lbn_t; - -struct nandfs_inode { - uint64_t i_blocks; /* 0: size in device blocks */ - uint64_t i_size; /* 8: size in bytes */ - uint64_t i_ctime; /* 16: creation time in seconds */ - uint64_t i_mtime; /* 24: modification time in seconds part*/ - uint32_t i_ctime_nsec; /* 32: creation time nanoseconds part */ - uint32_t i_mtime_nsec; /* 36: modification time in nanoseconds */ - uint32_t i_uid; /* 40: user id */ - uint32_t i_gid; /* 44: group id */ - uint16_t i_mode; /* 48: file mode */ - uint16_t i_links_count; /* 50: number of references to the inode*/ - uint32_t i_flags; /* 52: NANDFS_*_FL flags */ - nandfs_daddr_t i_special; /* 56: special */ - nandfs_daddr_t i_db[NANDFS_NDADDR]; /* 64: Direct disk blocks. */ - nandfs_daddr_t i_ib[NANDFS_NIADDR]; /* 160: Indirect disk blocks. */ - uint64_t i_xattr; /* 184: reserved for extended attributes*/ - uint32_t i_generation; /* 192: file generation for NFS */ - uint32_t i_pad[15]; /* 196: make it 64 bits aligned */ -}; - -#ifdef _KERNEL -CTASSERT(sizeof(struct nandfs_inode) == 256); -#endif - -/* - * Each checkpoint/snapshot has a super root. - * - * The super root holds the inodes of the three system files: `dat', `cp' and - * 'su' files. All other FS state is defined by those. - * - * It is CRC checksum'ed and time stamped. - */ - -struct nandfs_super_root { - uint32_t sr_sum; /* check-sum */ - uint16_t sr_bytes; /* byte count of this structure */ - uint16_t sr_flags; /* reserved for flags */ - uint64_t sr_nongc_ctime; /* timestamp, not for cleaner(?) */ - struct nandfs_inode sr_dat; /* DAT, virt->phys translation inode */ - struct nandfs_inode sr_cpfile; /* CP, checkpoints inode */ - struct nandfs_inode sr_sufile; /* SU, segment usage inode */ -}; - -#define NANDFS_SR_MDT_OFFSET(inode_size, i) \ - ((uint32_t)&((struct nandfs_super_root *)0)->sr_dat + \ - (inode_size) * (i)) - -#define NANDFS_SR_DAT_OFFSET(inode_size) NANDFS_SR_MDT_OFFSET(inode_size, 0) -#define NANDFS_SR_CPFILE_OFFSET(inode_size) NANDFS_SR_MDT_OFFSET(inode_size, 1) -#define NANDFS_SR_SUFILE_OFFSET(inode_size) NANDFS_SR_MDT_OFFSET(inode_size, 2) -#define NANDFS_SR_BYTES (sizeof(struct nandfs_super_root)) - -/* - * The superblock describes the basic structure and mount history. It also - * records some sizes of structures found on the disc for sanity checks. - * - * The superblock is stored at two places: NANDFS_SB_OFFSET_BYTES and - * NANDFS_SB2_OFFSET_BYTES. - */ - -/* File system states stored on media in superblock's sbp->s_state */ -#define NANDFS_VALID_FS 0x0001 /* cleanly unmounted and all is ok */ -#define NANDFS_ERROR_FS 0x0002 /* there were errors detected, fsck */ -#define NANDFS_RESIZE_FS 0x0004 /* resize required, XXX unknown flag*/ -#define NANDFS_MOUNT_STATE_BITS "\20\1VALID_FS\2ERROR_FS\3RESIZE_FS" - -/* - * Brief description of control structures: - * - * NANDFS_NFSAREAS first blocks contain fsdata and some amount of super blocks. - * Simple round-robin policy is used in order to choose which block will - * contain new super block. - * - * Simple case with 2 blocks: - * 1: fsdata sblock1 [sblock3 [sblock5 ..]] - * 2: fsdata sblock2 [sblock4 [sblock6 ..]] - */ -struct nandfs_fsdata { - uint16_t f_magic; - uint16_t f_bytes; - - uint32_t f_sum; /* checksum of fsdata */ - uint32_t f_rev_level; /* major disk format revision */ - - uint64_t f_ctime; /* creation time (execution time - of newfs) */ - /* Block size represented as: blocksize = 1 << (f_log_block_size + 10) */ - uint32_t f_log_block_size; - - uint16_t f_inode_size; /* size of an inode */ - uint16_t f_dat_entry_size; /* size of a dat entry */ - uint16_t f_checkpoint_size; /* size of a checkpoint */ - uint16_t f_segment_usage_size; /* size of a segment usage */ - - uint16_t f_sbbytes; /* byte count of CRC calculation - for super blocks. s_reserved - is excluded! */ - - uint16_t f_errors; /* behaviour on detecting errors */ - - uint32_t f_erasesize; - uint64_t f_nsegments; /* number of segm. in filesystem */ - nandfs_daddr_t f_first_data_block; /* 1st seg disk block number */ - uint32_t f_blocks_per_segment; /* number of blocks per segment */ - uint32_t f_r_segments_percentage; /* reserved segments percentage */ - - struct uuid f_uuid; /* 128-bit uuid for volume */ - char f_volume_name[16]; /* volume name */ - uint32_t f_pad[104]; -} __packed; - -#ifdef _KERNEL -CTASSERT(sizeof(struct nandfs_fsdata) == 512); -#endif - -struct nandfs_super_block { - uint16_t s_magic; /* magic value for identification */ - - uint32_t s_sum; /* check sum of super block */ - - uint64_t s_last_cno; /* last checkpoint number */ - uint64_t s_last_pseg; /* addr part. segm. written last */ - uint64_t s_last_seq; /* seq.number of seg written last */ - uint64_t s_free_blocks_count; /* free blocks count */ - - uint64_t s_mtime; /* mount time */ - uint64_t s_wtime; /* write time */ - uint16_t s_state; /* file system state */ - - char s_last_mounted[64]; /* directory where last mounted */ - - uint32_t s_c_interval; /* commit interval of segment */ - uint32_t s_c_block_max; /* threshold of data amount for - the segment construction */ - uint32_t s_reserved[32]; /* padding to end of the block */ -} __packed; - -#ifdef _KERNEL -CTASSERT(sizeof(struct nandfs_super_block) == 256); -#endif - -#define NANDFS_FSDATA_MAGIC 0xf8da -#define NANDFS_SUPER_MAGIC 0x8008 - -#define NANDFS_NFSAREAS 4 -#define NANDFS_DATA_OFFSET_BYTES(esize) (NANDFS_NFSAREAS * (esize)) - -#define NANDFS_SBLOCK_OFFSET_BYTES (sizeof(struct nandfs_fsdata)) - -#define NANDFS_DEF_BLOCKSIZE 4096 -#define NANDFS_MIN_BLOCKSIZE 512 - -#define NANDFS_DEF_ERASESIZE (2 << 16) - -#define NANDFS_MIN_SEGSIZE NANDFS_DEF_ERASESIZE - -#define NANDFS_CURRENT_REV 9 /* current major revision */ - -#define NANDFS_FSDATA_CRC_BYTES offsetof(struct nandfs_fsdata, f_pad) -/* Bytes count of super_block for CRC-calculation */ -#define NANDFS_SB_BYTES offsetof(struct nandfs_super_block, s_reserved) - -/* Maximal count of links to a file */ -#define NANDFS_LINK_MAX 32000 - -/* - * Structure of a directory entry. - * - * Note that they can't span blocks; the rec_len fills out. - */ - -#define NANDFS_NAME_LEN 255 -struct nandfs_dir_entry { - uint64_t inode; /* inode number */ - uint16_t rec_len; /* directory entry length */ - uint8_t name_len; /* name length */ - uint8_t file_type; - char name[NANDFS_NAME_LEN]; /* file name */ - char pad; -}; - -/* - * NANDFS_DIR_PAD defines the directory entries boundaries - * - * NOTE: It must be a multiple of 8 - */ -#define NANDFS_DIR_PAD 8 -#define NANDFS_DIR_ROUND (NANDFS_DIR_PAD - 1) -#define NANDFS_DIR_NAME_OFFSET (offsetof(struct nandfs_dir_entry, name)) -#define NANDFS_DIR_REC_LEN(name_len) \ - (((name_len) + NANDFS_DIR_NAME_OFFSET + NANDFS_DIR_ROUND) \ - & ~NANDFS_DIR_ROUND) -#define NANDFS_DIR_NAME_LEN(name_len) \ - (NANDFS_DIR_REC_LEN(name_len) - NANDFS_DIR_NAME_OFFSET) - -/* - * NiLFS/NANDFS devides the disc into fixed length segments. Each segment is - * filled with one or more partial segments of variable lengths. - * - * Each partial segment has a segment summary header followed by updates of - * files and optionally a super root. - */ - -/* - * Virtual to physical block translation information. For data blocks it maps - * logical block number bi_blkoff to virtual block nr bi_vblocknr. For non - * datablocks it is the virtual block number assigned to an indirect block - * and has no bi_blkoff. The physical block number is the next - * available data block in the partial segment after all the binfo's. - */ -struct nandfs_binfo_v { - uint64_t bi_ino; /* file's inode */ - uint64_t bi_vblocknr; /* assigned virtual block number */ - uint64_t bi_blkoff; /* for file's logical block number */ -}; - -/* - * DAT allocation. For data blocks just the logical block number that maps on - * the next available data block in the partial segment after the binfo's. - */ -struct nandfs_binfo_dat { - uint64_t bi_ino; - uint64_t bi_blkoff; /* DAT file's logical block number */ - uint8_t bi_level; /* whether this is meta block */ - uint8_t bi_pad[7]; -}; - -#ifdef _KERNEL -CTASSERT(sizeof(struct nandfs_binfo_v) == sizeof(struct nandfs_binfo_dat)); -#endif - -/* Convenience union for both types of binfo's */ -union nandfs_binfo { - struct nandfs_binfo_v bi_v; - struct nandfs_binfo_dat bi_dat; -}; - -/* Indirect buffers path */ -struct nandfs_indir { - nandfs_daddr_t in_lbn; - int in_off; -}; - -/* The (partial) segment summary */ -struct nandfs_segment_summary { - uint32_t ss_datasum; /* CRC of complete data block */ - uint32_t ss_sumsum; /* CRC of segment summary only */ - uint32_t ss_magic; /* magic to identify segment summary */ - uint16_t ss_bytes; /* size of segment summary structure */ - uint16_t ss_flags; /* NANDFS_SS_* flags */ - uint64_t ss_seq; /* sequence number of this segm. sum */ - uint64_t ss_create; /* creation timestamp in seconds */ - uint64_t ss_next; /* blocknumber of next segment */ - uint32_t ss_nblocks; /* number of blocks used by summary */ - uint32_t ss_nbinfos; /* number of binfo structures */ - uint32_t ss_sumbytes; /* total size of segment summary */ - uint32_t ss_pad; - /* stream of binfo structures */ -}; - -#define NANDFS_SEGSUM_MAGIC 0x8e680011 /* segment summary magic number */ - -/* Segment summary flags */ -#define NANDFS_SS_LOGBGN 0x0001 /* begins a logical segment */ -#define NANDFS_SS_LOGEND 0x0002 /* ends a logical segment */ -#define NANDFS_SS_SR 0x0004 /* has super root */ -#define NANDFS_SS_SYNDT 0x0008 /* includes data only updates */ -#define NANDFS_SS_GC 0x0010 /* segment written for cleaner operation */ -#define NANDFS_SS_FLAG_BITS "\20\1LOGBGN\2LOGEND\3SR\4SYNDT\5GC" - -/* Segment summary constrains */ -#define NANDFS_SEG_MIN_BLOCKS 16 /* minimum number of blocks in a - full segment */ -#define NANDFS_PSEG_MIN_BLOCKS 2 /* minimum number of blocks in a - partial segment */ -#define NANDFS_MIN_NRSVSEGS 8 /* minimum number of reserved - segments */ - -/* - * Structure of DAT/inode file. - * - * A DAT file is divided into groups. The maximum number of groups is the - * number of block group descriptors that fit into one block; this descriptor - * only gives the number of free entries in the associated group. - * - * Each group has a block sized bitmap indicating if an entry is taken or - * empty. Each bit stands for a DAT entry. - * - * The inode file has exactly the same format only the entries are inode - * entries. - */ - -struct nandfs_block_group_desc { - uint32_t bg_nfrees; /* num. free entries in block group */ -}; - -/* DAT entry in a super root's DAT file */ -struct nandfs_dat_entry { - uint64_t de_blocknr; /* block number */ - uint64_t de_start; /* valid from checkpoint */ - uint64_t de_end; /* valid till checkpoint */ - uint64_t de_rsv; /* reserved for future use */ -}; - -/* - * Structure of CP file. - * - * A snapshot is just a checkpoint only it's protected against removal by the - * cleaner. The snapshots are kept on a double linked list of checkpoints. - */ -struct nandfs_snapshot_list { - uint64_t ssl_next; /* checkpoint nr. forward */ - uint64_t ssl_prev; /* checkpoint nr. back */ -}; - -/* Checkpoint entry structure */ -struct nandfs_checkpoint { - uint32_t cp_flags; /* NANDFS_CHECKPOINT_* flags */ - uint32_t cp_checkpoints_count; /* ZERO, not used anymore? */ - struct nandfs_snapshot_list cp_snapshot_list; /* list of snapshots */ - uint64_t cp_cno; /* checkpoint number */ - uint64_t cp_create; /* creation timestamp */ - uint64_t cp_nblk_inc; /* number of blocks incremented */ - uint64_t cp_blocks_count; /* reserved (might be deleted) */ - struct nandfs_inode cp_ifile_inode; /* inode file inode */ -}; - -/* Checkpoint flags */ -#define NANDFS_CHECKPOINT_SNAPSHOT 1 -#define NANDFS_CHECKPOINT_INVALID 2 -#define NANDFS_CHECKPOINT_SKETCH 4 -#define NANDFS_CHECKPOINT_MINOR 8 -#define NANDFS_CHECKPOINT_BITS "\20\1SNAPSHOT\2INVALID\3SKETCH\4MINOR" - -/* Header of the checkpoint file */ -struct nandfs_cpfile_header { - uint64_t ch_ncheckpoints; /* number of checkpoints */ - uint64_t ch_nsnapshots; /* number of snapshots */ - struct nandfs_snapshot_list ch_snapshot_list; /* snapshot list */ -}; - -#define NANDFS_CPFILE_FIRST_CHECKPOINT_OFFSET \ - ((sizeof(struct nandfs_cpfile_header) + \ - sizeof(struct nandfs_checkpoint) - 1) / \ - sizeof(struct nandfs_checkpoint)) - - -#define NANDFS_NOSEGMENT 0xffffffff - -/* - * Structure of SU file. - * - * The segment usage file sums up how each of the segments are used. They are - * indexed by their segment number. - */ - -/* Segment usage entry */ -struct nandfs_segment_usage { - uint64_t su_lastmod; /* last modified timestamp */ - uint32_t su_nblocks; /* number of blocks in segment */ - uint32_t su_flags; /* NANDFS_SEGMENT_USAGE_* flags */ -}; - -/* Segment usage flag */ -#define NANDFS_SEGMENT_USAGE_ACTIVE 1 -#define NANDFS_SEGMENT_USAGE_DIRTY 2 -#define NANDFS_SEGMENT_USAGE_ERROR 4 -#define NANDFS_SEGMENT_USAGE_GC 8 -#define NANDFS_SEGMENT_USAGE_BITS "\20\1ACTIVE\2DIRTY\3ERROR" - -/* Header of the segment usage file */ -struct nandfs_sufile_header { - uint64_t sh_ncleansegs; /* number of segments marked clean */ - uint64_t sh_ndirtysegs; /* number of segments marked dirty */ - uint64_t sh_last_alloc; /* last allocated segment number */ -}; - -#define NANDFS_SUFILE_FIRST_SEGMENT_USAGE_OFFSET \ - ((sizeof(struct nandfs_sufile_header) + \ - sizeof(struct nandfs_segment_usage) - 1) / \ - sizeof(struct nandfs_segment_usage)) - -struct nandfs_seg_stat { - uint64_t nss_nsegs; - uint64_t nss_ncleansegs; - uint64_t nss_ndirtysegs; - uint64_t nss_ctime; - uint64_t nss_nongc_ctime; - uint64_t nss_prot_seq; -}; - -enum { - NANDFS_CHECKPOINT, - NANDFS_SNAPSHOT -}; - -#define NANDFS_CPINFO_MAX 512 - -struct nandfs_cpinfo { - uint32_t nci_flags; - uint32_t nci_pad; - uint64_t nci_cno; - uint64_t nci_create; - uint64_t nci_nblk_inc; - uint64_t nci_blocks_count; - uint64_t nci_next; -}; - -#define NANDFS_SEGMENTS_MAX 512 - -struct nandfs_suinfo { - uint64_t nsi_num; - uint64_t nsi_lastmod; - uint32_t nsi_blocks; - uint32_t nsi_flags; -}; - -#define NANDFS_VINFO_MAX 512 - -struct nandfs_vinfo { - uint64_t nvi_ino; - uint64_t nvi_vblocknr; - uint64_t nvi_start; - uint64_t nvi_end; - uint64_t nvi_blocknr; - int nvi_alive; -}; - -struct nandfs_cpmode { - uint64_t ncpm_cno; - uint32_t ncpm_mode; - uint32_t ncpm_pad; -}; - -struct nandfs_argv { - uint64_t nv_base; - uint32_t nv_nmembs; - uint16_t nv_size; - uint16_t nv_flags; - uint64_t nv_index; -}; - -struct nandfs_cpstat { - uint64_t ncp_cno; - uint64_t ncp_ncps; - uint64_t ncp_nss; -}; - -struct nandfs_period { - uint64_t p_start; - uint64_t p_end; -}; - -struct nandfs_vdesc { - uint64_t vd_ino; - uint64_t vd_cno; - uint64_t vd_vblocknr; - struct nandfs_period vd_period; - uint64_t vd_blocknr; - uint64_t vd_offset; - uint32_t vd_flags; - uint32_t vd_pad; -}; - -struct nandfs_bdesc { - uint64_t bd_ino; - uint64_t bd_oblocknr; - uint64_t bd_blocknr; - uint64_t bd_offset; - uint32_t bd_level; - uint32_t bd_alive; -}; - -#ifndef _KERNEL -#ifndef MNAMELEN -#define MNAMELEN 1024 -#endif -#endif - -struct nandfs_fsinfo { - struct nandfs_fsdata fs_fsdata; - struct nandfs_super_block fs_super; - char fs_dev[MNAMELEN]; -}; - -#define NANDFS_MAX_MOUNTS 65535 - -#define NANDFS_IOCTL_GET_SUSTAT _IOR('N', 100, struct nandfs_seg_stat) -#define NANDFS_IOCTL_CHANGE_CPMODE _IOWR('N', 101, struct nandfs_cpmode) -#define NANDFS_IOCTL_GET_CPINFO _IOWR('N', 102, struct nandfs_argv) -#define NANDFS_IOCTL_DELETE_CP _IOWR('N', 103, uint64_t[2]) -#define NANDFS_IOCTL_GET_CPSTAT _IOR('N', 104, struct nandfs_cpstat) -#define NANDFS_IOCTL_GET_SUINFO _IOWR('N', 105, struct nandfs_argv) -#define NANDFS_IOCTL_GET_VINFO _IOWR('N', 106, struct nandfs_argv) -#define NANDFS_IOCTL_GET_BDESCS _IOWR('N', 107, struct nandfs_argv) -#define NANDFS_IOCTL_GET_FSINFO _IOR('N', 108, struct nandfs_fsinfo) -#define NANDFS_IOCTL_MAKE_SNAP _IOWR('N', 109, uint64_t) -#define NANDFS_IOCTL_DELETE_SNAP _IOWR('N', 110, uint64_t) -#define NANDFS_IOCTL_SYNC _IOWR('N', 111, uint64_t) - -#endif /* _NANDFS_FS_H */ diff --git a/sys/fs/nandfs/nandfs_ifile.c b/sys/fs/nandfs/nandfs_ifile.c deleted file mode 100644 index 2c10bbac1ffe..000000000000 --- a/sys/fs/nandfs/nandfs_ifile.c +++ /dev/null @@ -1,215 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -int -nandfs_node_create(struct nandfsmount *nmp, struct nandfs_node **node, - uint16_t mode) -{ - struct nandfs_alloc_request req; - struct nandfs_device *nandfsdev; - struct nandfs_mdt *mdt; - struct nandfs_node *ifile; - struct nandfs_inode *inode; - struct vnode *vp; - uint32_t entry; - int error = 0; - - nandfsdev = nmp->nm_nandfsdev; - mdt = &nandfsdev->nd_ifile_mdt; - ifile = nmp->nm_ifile_node; - vp = NTOV(ifile); - - VOP_LOCK(vp, LK_EXCLUSIVE); - /* Allocate new inode in ifile */ - req.entrynum = nandfsdev->nd_last_ino + 1; - error = nandfs_find_free_entry(mdt, ifile, &req); - if (error) { - VOP_UNLOCK(vp, 0); - return (error); - } - - error = nandfs_get_entry_block(mdt, ifile, &req, &entry, 1); - if (error) { - VOP_UNLOCK(vp, 0); - return (error); - } - - /* Inode initialization */ - inode = ((struct nandfs_inode *) req.bp_entry->b_data) + entry; - nandfs_inode_init(inode, mode); - - error = nandfs_alloc_entry(mdt, &req); - if (error) { - VOP_UNLOCK(vp, 0); - return (error); - } - - VOP_UNLOCK(vp, 0); - - nandfsdev->nd_last_ino = req.entrynum; - error = nandfs_get_node(nmp, req.entrynum, node); - DPRINTF(IFILE, ("%s: node: %p ino: %#jx\n", - __func__, node, (uintmax_t)((*node)->nn_ino))); - - return (error); -} - -int -nandfs_node_destroy(struct nandfs_node *node) -{ - struct nandfs_alloc_request req; - struct nandfsmount *nmp; - struct nandfs_mdt *mdt; - struct nandfs_node *ifile; - struct vnode *vp; - int error = 0; - - nmp = node->nn_nmp; - req.entrynum = node->nn_ino; - mdt = &nmp->nm_nandfsdev->nd_ifile_mdt; - ifile = nmp->nm_ifile_node; - vp = NTOV(ifile); - - DPRINTF(IFILE, ("%s: destroy node: %p ino: %#jx\n", - __func__, node, (uintmax_t)node->nn_ino)); - VOP_LOCK(vp, LK_EXCLUSIVE); - - error = nandfs_find_entry(mdt, ifile, &req); - if (error) { - nandfs_error("%s: finding entry error:%d node %p(%jx)", - __func__, error, node, node->nn_ino); - VOP_UNLOCK(vp, 0); - return (error); - } - - nandfs_inode_destroy(&node->nn_inode); - - error = nandfs_free_entry(mdt, &req); - if (error) { - nandfs_error("%s: freing entry error:%d node %p(%jx)", - __func__, error, node, node->nn_ino); - VOP_UNLOCK(vp, 0); - return (error); - } - - VOP_UNLOCK(vp, 0); - DPRINTF(IFILE, ("%s: freed node %p ino %#jx\n", - __func__, node, (uintmax_t)node->nn_ino)); - return (error); -} - -int -nandfs_node_update(struct nandfs_node *node) -{ - struct nandfs_alloc_request req; - struct nandfsmount *nmp; - struct nandfs_mdt *mdt; - struct nandfs_node *ifile; - struct nandfs_inode *inode; - uint32_t index; - int error = 0; - - nmp = node->nn_nmp; - ifile = nmp->nm_ifile_node; - ASSERT_VOP_LOCKED(NTOV(ifile), __func__); - - req.entrynum = node->nn_ino; - mdt = &nmp->nm_nandfsdev->nd_ifile_mdt; - - DPRINTF(IFILE, ("%s: node:%p ino:%#jx\n", - __func__, &node->nn_inode, (uintmax_t)node->nn_ino)); - - error = nandfs_get_entry_block(mdt, ifile, &req, &index, 0); - if (error) { - printf("nandfs_get_entry_block returned with ERROR=%d\n", - error); - return (error); - } - - inode = ((struct nandfs_inode *) req.bp_entry->b_data) + index; - memcpy(inode, &node->nn_inode, sizeof(*inode)); - error = nandfs_dirty_buf(req.bp_entry, 0); - - return (error); -} - -int -nandfs_get_node_entry(struct nandfsmount *nmp, struct nandfs_inode **inode, - uint64_t ino, struct buf **bp) -{ - struct nandfs_alloc_request req; - struct nandfs_mdt *mdt; - struct nandfs_node *ifile; - struct vnode *vp; - uint32_t index; - int error = 0; - - req.entrynum = ino; - mdt = &nmp->nm_nandfsdev->nd_ifile_mdt; - ifile = nmp->nm_ifile_node; - vp = NTOV(ifile); - - VOP_LOCK(vp, LK_EXCLUSIVE); - error = nandfs_get_entry_block(mdt, ifile, &req, &index, 0); - if (error) { - VOP_UNLOCK(vp, 0); - return (error); - } - - *inode = ((struct nandfs_inode *) req.bp_entry->b_data) + index; - *bp = req.bp_entry; - VOP_UNLOCK(vp, 0); - return (0); -} - diff --git a/sys/fs/nandfs/nandfs_mount.h b/sys/fs/nandfs/nandfs_mount.h deleted file mode 100644 index cc6e30eb0bbd..000000000000 --- a/sys/fs/nandfs/nandfs_mount.h +++ /dev/null @@ -1,52 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-4-Clause - * - * Copyright (c) 2008, 2009 Reinoud Zandijk - * 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, 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed for the - * NetBSD Project. See http://www.NetBSD.org/ for - * information about NetBSD. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * 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. - * - * From: NetBSD: nilfs_mount.h,v 1.1 2009/07/18 16:31:42 reinoud - * - * $FreeBSD$ - */ - -#ifndef _FS_NANDFS_NANDFS_MOUNT_H_ -#define _FS_NANDFS_NANDFS_MOUNT_H_ - -/* - * Arguments to mount NANDFS filingsystem. - */ - -struct nandfs_args { - char *fspec; /* mount specifier */ - int64_t cpno; /* checkpoint number */ -}; - -#endif /* !_FS_NANDFS_NANDFS_MOUNT_H_ */ - diff --git a/sys/fs/nandfs/nandfs_segment.c b/sys/fs/nandfs/nandfs_segment.c deleted file mode 100644 index 36efc89af409..000000000000 --- a/sys/fs/nandfs/nandfs_segment.c +++ /dev/null @@ -1,1314 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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_ddb.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -static int -nandfs_new_segment(struct nandfs_device *fsdev) -{ - int error = 0; - uint64_t new; - - error = nandfs_alloc_segment(fsdev, &new); - if (!error) { - fsdev->nd_seg_num = fsdev->nd_next_seg_num; - fsdev->nd_next_seg_num = new; - } - DPRINTF(SYNC, ("%s: new segment %jx next %jx error %d\n", - __func__, (uintmax_t)fsdev->nd_seg_num, (uintmax_t)new, error)); - if (error) - nandfs_error("%s: cannot create segment error %d\n", - __func__, error); - - return (error); -} - -static int -create_segment(struct nandfs_seginfo *seginfo) -{ - struct nandfs_segment *seg; - struct nandfs_device *fsdev; - struct nandfs_segment *prev; - struct buf *bp; - uint64_t start_block, curr; - uint32_t blks_per_seg, nblocks; - int error; - - fsdev = seginfo->fsdev; - prev = seginfo->curseg; - blks_per_seg = fsdev->nd_fsdata.f_blocks_per_segment; - nblocks = fsdev->nd_last_segsum.ss_nblocks; - - if (!prev) { - vfs_timestamp(&fsdev->nd_ts); - /* Touch current segment */ - error = nandfs_touch_segment(fsdev, fsdev->nd_seg_num); - if (error) { - nandfs_error("%s: cannot preallocate segment %jx\n", - __func__, fsdev->nd_seg_num); - return (error); - } - error = nandfs_touch_segment(fsdev, 0); - if (error) { - nandfs_error("%s: cannot dirty block with segment 0\n", - __func__); - return (error); - } - start_block = fsdev->nd_last_pseg + (uint64_t)nblocks; - /* - * XXX Hack - */ - if (blks_per_seg - (start_block % blks_per_seg) - 1 == 0) - start_block++; - curr = nandfs_get_segnum_of_block(fsdev, start_block); - /* Allocate new segment if last one is full */ - if (fsdev->nd_seg_num != curr) { - error = nandfs_new_segment(fsdev); - if (error) { - nandfs_error("%s: cannot create new segment\n", - __func__); - return (error); - } - /* - * XXX Hack - */ - nandfs_get_segment_range(fsdev, fsdev->nd_seg_num, &start_block, NULL); - } - } else { - nandfs_get_segment_range(fsdev, fsdev->nd_next_seg_num, - &start_block, NULL); - - /* Touch current segment and allocate and touch new one */ - error = nandfs_new_segment(fsdev); - if (error) { - nandfs_error("%s: cannot create next segment\n", - __func__); - return (error); - } - - /* Reiterate in case new buf is dirty */ - seginfo->reiterate = 1; - } - - /* Allocate and initialize nandfs_segment structure */ - seg = malloc(sizeof(*seg), M_DEVBUF, M_WAITOK|M_ZERO); - TAILQ_INIT(&seg->segsum); - TAILQ_INIT(&seg->data); - seg->fsdev = fsdev; - seg->start_block = start_block; - seg->num_blocks = blks_per_seg - (start_block % blks_per_seg) - 1; - seg->seg_num = fsdev->nd_seg_num; - seg->seg_next = fsdev->nd_next_seg_num; - seg->segsum_blocks = 1; - seg->bytes_left = fsdev->nd_blocksize - - sizeof(struct nandfs_segment_summary); - seg->segsum_bytes = sizeof(struct nandfs_segment_summary); - - /* Allocate buffer for segment summary */ - bp = getblk(fsdev->nd_devvp, nandfs_block_to_dblock(fsdev, - seg->start_block), fsdev->nd_blocksize, 0, 0, 0); - bzero(bp->b_data, seginfo->fsdev->nd_blocksize); - bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj; - bp->b_flags |= B_MANAGED; - - /* Add buffer to segment */ - TAILQ_INSERT_TAIL(&seg->segsum, bp, b_cluster.cluster_entry); - seg->current_off = bp->b_data + sizeof(struct nandfs_segment_summary); - - DPRINTF(SYNC, ("%s: seg %p : initial settings: start %#jx size :%#x\n", - __func__, seg, (uintmax_t)seg->start_block, seg->num_blocks)); - DPRINTF(SYNC, ("%s: seg->seg_num %#jx cno %#jx next %#jx\n", __func__, - (uintmax_t)seg->seg_num, (uintmax_t)(fsdev->nd_last_cno + 1), - (uintmax_t)seg->seg_next)); - - if (!prev) - LIST_INSERT_HEAD(&seginfo->seg_list, seg, seg_link); - else - LIST_INSERT_AFTER(prev, seg, seg_link); - - seginfo->curseg = seg; - - return (0); -} - -static int -delete_segment(struct nandfs_seginfo *seginfo) -{ - struct nandfs_segment *seg, *tseg; - struct buf *bp, *tbp; - - LIST_FOREACH_SAFE(seg, &seginfo->seg_list, seg_link, tseg) { - TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, - tbp) { - TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry); - bp->b_flags &= ~B_MANAGED; - brelse(bp); - } - - LIST_REMOVE(seg, seg_link); - free(seg, M_DEVBUF); - } - - return (0); -} - -static int -create_seginfo(struct nandfs_device *fsdev, struct nandfs_seginfo **seginfo) -{ - struct nandfs_seginfo *info; - - info = malloc(sizeof(*info), M_DEVBUF, M_WAITOK); - - LIST_INIT(&info->seg_list); - info->fsdev = fsdev; - info->curseg = NULL; - info->blocks = 0; - *seginfo = info; - fsdev->nd_seginfo = info; - return (0); -} - -static int -delete_seginfo(struct nandfs_seginfo *seginfo) -{ - struct nandfs_device *nffsdev; - - nffsdev = seginfo->fsdev; - delete_segment(seginfo); - nffsdev->nd_seginfo = NULL; - free(seginfo, M_DEVBUF); - - return (0); -} - -static int -nandfs_create_superroot_block(struct nandfs_seginfo *seginfo, - struct buf **newbp) -{ - struct buf *bp; - int error; - - bp = nandfs_geteblk(seginfo->fsdev->nd_blocksize, GB_NOWAIT_BD); - - bzero(bp->b_data, seginfo->fsdev->nd_blocksize); - bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj; - bp->b_flags |= B_MANAGED; - - if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) { - error = create_segment(seginfo); - if (error) { - brelse(bp); - nandfs_error("%s: no segment for superroot\n", - __func__); - return (error); - } - } - - TAILQ_INSERT_TAIL(&seginfo->curseg->data, bp, b_cluster.cluster_entry); - - seginfo->curseg->nblocks++; - seginfo->curseg->num_blocks--; - seginfo->blocks++; - - *newbp = bp; - return (0); -} - -static int -nandfs_add_superroot(struct nandfs_seginfo *seginfo) -{ - struct nandfs_device *fsdev; - struct nandfs_super_root *sr; - struct buf *bp = NULL; - uint64_t crc_skip; - uint32_t crc_calc; - int error; - - fsdev = seginfo->fsdev; - - error = nandfs_create_superroot_block(seginfo, &bp); - if (error) { - nandfs_error("%s: cannot add superroot\n", __func__); - return (error); - } - - sr = (struct nandfs_super_root *)bp->b_data; - /* Save superroot CRC */ - sr->sr_bytes = NANDFS_SR_BYTES; - sr->sr_flags = 0; - sr->sr_nongc_ctime = 0; - - memcpy(&sr->sr_dat, &fsdev->nd_dat_node->nn_inode, - sizeof(struct nandfs_inode)); - memcpy(&sr->sr_cpfile, &fsdev->nd_cp_node->nn_inode, - sizeof(struct nandfs_inode)); - memcpy(&sr->sr_sufile, &fsdev->nd_su_node->nn_inode, - sizeof(struct nandfs_inode)); - - crc_skip = sizeof(sr->sr_sum); - crc_calc = crc32((uint8_t *)sr + crc_skip, NANDFS_SR_BYTES - crc_skip); - - sr->sr_sum = crc_calc; - - bp->b_flags |= B_MANAGED; - bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj; - - bp->b_flags &= ~B_INVAL; - nandfs_dirty_bufs_increment(fsdev); - DPRINTF(SYNC, ("%s: bp:%p\n", __func__, bp)); - - return (0); -} - -static int -nandfs_add_segsum_block(struct nandfs_seginfo *seginfo, struct buf **newbp) -{ - struct nandfs_device *fsdev; - nandfs_daddr_t blk; - struct buf *bp; - int error; - - if (!(seginfo->curseg) || seginfo->curseg->num_blocks <= 1) { - error = create_segment(seginfo); - if (error) { - nandfs_error("%s: error:%d when creating segment\n", - __func__, error); - return (error); - } - *newbp = TAILQ_FIRST(&seginfo->curseg->segsum); - return (0); - } - - fsdev = seginfo->fsdev; - blk = nandfs_block_to_dblock(fsdev, seginfo->curseg->start_block + - seginfo->curseg->segsum_blocks); - - bp = getblk(fsdev->nd_devvp, blk, fsdev->nd_blocksize, 0, 0, 0); - - bzero(bp->b_data, seginfo->fsdev->nd_blocksize); - bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj; - bp->b_flags |= B_MANAGED; - - TAILQ_INSERT_TAIL(&seginfo->curseg->segsum, bp, - b_cluster.cluster_entry); - seginfo->curseg->num_blocks--; - - seginfo->curseg->segsum_blocks++; - seginfo->curseg->bytes_left = seginfo->fsdev->nd_blocksize; - seginfo->curseg->current_off = bp->b_data; - seginfo->blocks++; - - *newbp = bp; - - DPRINTF(SYNC, ("%s: bp %p\n", __func__, bp)); - - return (0); -} - -static int -nandfs_add_blocks(struct nandfs_seginfo *seginfo, struct nandfs_node *node, - struct buf *bp) -{ - union nandfs_binfo *binfo; - struct buf *seg_bp; - int error; - - if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) { - error = create_segment(seginfo); - if (error) { - nandfs_error("%s: error:%d when creating segment\n", - __func__, error); - return (error); - } - } - - if (seginfo->curseg->bytes_left < sizeof(union nandfs_binfo)) { - error = nandfs_add_segsum_block(seginfo, &seg_bp); - if (error) { - nandfs_error("%s: error:%d when adding segsum\n", - __func__, error); - return (error); - } - } - binfo = (union nandfs_binfo *)seginfo->curseg->current_off; - - if (node->nn_ino != NANDFS_DAT_INO) { - binfo->bi_v.bi_blkoff = bp->b_lblkno; - binfo->bi_v.bi_ino = node->nn_ino; - } else { - binfo->bi_dat.bi_blkoff = bp->b_lblkno; - binfo->bi_dat.bi_ino = node->nn_ino; - if (NANDFS_IS_INDIRECT(bp)) - binfo->bi_dat.bi_level = 1; - else - binfo->bi_dat.bi_level = 0; - } - binfo++; - - seginfo->curseg->bytes_left -= sizeof(union nandfs_binfo); - seginfo->curseg->segsum_bytes += sizeof(union nandfs_binfo); - seginfo->curseg->current_off = (char *)binfo; - - TAILQ_INSERT_TAIL(&seginfo->curseg->data, bp, b_cluster.cluster_entry); - - seginfo->curseg->nbinfos++; - seginfo->curseg->nblocks++; - seginfo->curseg->num_blocks--; - seginfo->blocks++; - - DPRINTF(SYNC, ("%s: bp (%p) number %x (left %x)\n", - __func__, bp, seginfo->curseg->nblocks, - seginfo->curseg->num_blocks)); - return (0); -} - -static int -nandfs_iterate_dirty_buf(struct vnode *vp, struct nandfs_seginfo *seginfo, - uint8_t hold) -{ - struct buf *bp, *tbd; - struct bufobj *bo; - struct nandfs_node *node; - int error; - - node = VTON(vp); - bo = &vp->v_bufobj; - - ASSERT_VOP_ELOCKED(vp, __func__); - - /* Iterate dirty data bufs */ - TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, tbd) { - DPRINTF(SYNC, ("%s: vp (%p): bp (%p) with lblkno %jx ino %jx " - "add buf\n", __func__, vp, bp, bp->b_lblkno, node->nn_ino)); - - if (!(NANDFS_ISGATHERED(bp))) { - error = nandfs_bmap_update_dat(node, - nandfs_vblk_get(bp), bp); - if (error) - return (error); - NANDFS_GATHER(bp); - nandfs_add_blocks(seginfo, node, bp); - } - } - - return (0); -} - -static int -nandfs_iterate_system_vnode(struct nandfs_node *node, - struct nandfs_seginfo *seginfo) -{ - struct vnode *vp; - int nblocks; - uint8_t hold = 0; - - if (node->nn_ino != NANDFS_IFILE_INO) - hold = 1; - - vp = NTOV(node); - - nblocks = vp->v_bufobj.bo_dirty.bv_cnt; - DPRINTF(SYNC, ("%s: vp (%p): nblocks %x ino %jx\n", - __func__, vp, nblocks, node->nn_ino)); - - if (nblocks) - nandfs_iterate_dirty_buf(vp, seginfo, hold); - - return (0); -} - -static int -nandfs_iterate_dirty_vnodes(struct mount *mp, struct nandfs_seginfo *seginfo) -{ - struct nandfs_node *nandfs_node; - struct vnode *vp, *mvp; - struct thread *td; - struct bufobj *bo; - int error, update; - - td = curthread; - - MNT_VNODE_FOREACH_ACTIVE(vp, mp, mvp) { - update = 0; - - if (mp->mnt_syncer == vp || VOP_ISLOCKED(vp)) { - VI_UNLOCK(vp); - continue; - } - if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK | LK_NOWAIT, td) != 0) - continue; - - nandfs_node = VTON(vp); - if (nandfs_node->nn_flags & IN_MODIFIED) { - nandfs_node->nn_flags &= ~(IN_MODIFIED); - update = 1; - } - - bo = &vp->v_bufobj; - BO_LOCK(bo); - if (vp->v_bufobj.bo_dirty.bv_cnt) { - error = nandfs_iterate_dirty_buf(vp, seginfo, 0); - if (error) { - nandfs_error("%s: cannot iterate vnode:%p " - "err:%d\n", __func__, vp, error); - vput(vp); - BO_UNLOCK(bo); - return (error); - } - update = 1; - } else - vput(vp); - BO_UNLOCK(bo); - - if (update) - nandfs_node_update(nandfs_node); - } - - return (0); -} - -static int -nandfs_update_phys_block(struct nandfs_device *fsdev, struct buf *bp, - uint64_t phys_blknr, union nandfs_binfo *binfo) -{ - struct nandfs_node *node, *dat; - struct vnode *vp; - uint64_t new_blknr; - int error; - - vp = bp->b_vp; - node = VTON(vp); - new_blknr = nandfs_vblk_get(bp); - dat = fsdev->nd_dat_node; - - DPRINTF(BMAP, ("%s: ino %#jx lblk %#jx: vblk %#jx -> %#jx\n", - __func__, (uintmax_t)node->nn_ino, (uintmax_t)bp->b_lblkno, - (uintmax_t)new_blknr, (uintmax_t)phys_blknr)); - - if (node->nn_ino != NANDFS_DAT_INO) { - KASSERT((new_blknr != 0), ("vblk for bp %p is 0", bp)); - - nandfs_vblock_assign(fsdev, new_blknr, phys_blknr); - binfo->bi_v.bi_vblocknr = new_blknr; - binfo->bi_v.bi_blkoff = bp->b_lblkno; - binfo->bi_v.bi_ino = node->nn_ino; - } else { - VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); - error = nandfs_bmap_update_block(node, bp, phys_blknr); - if (error) { - nandfs_error("%s: error updating block:%jx for bp:%p\n", - __func__, (uintmax_t)phys_blknr, bp); - VOP_UNLOCK(NTOV(dat), 0); - return (error); - } - VOP_UNLOCK(NTOV(dat), 0); - binfo->bi_dat.bi_blkoff = bp->b_lblkno; - binfo->bi_dat.bi_ino = node->nn_ino; - if (NANDFS_IS_INDIRECT(bp)) - binfo->bi_dat.bi_level = 1; - else - binfo->bi_dat.bi_level = 0; - } - - return (0); -} - -#define NBINFO(off) ((off) + sizeof(union nandfs_binfo)) -static int -nandfs_segment_assign_pblk(struct nandfs_segment *nfsseg) -{ - struct nandfs_device *fsdev; - union nandfs_binfo *binfo; - struct buf *bp, *seg_bp; - uint64_t blocknr; - uint32_t curr_off, blocksize; - int error; - - fsdev = nfsseg->fsdev; - blocksize = fsdev->nd_blocksize; - - blocknr = nfsseg->start_block + nfsseg->segsum_blocks; - seg_bp = TAILQ_FIRST(&nfsseg->segsum); - DPRINTF(SYNC, ("%s: seg:%p segsum bp:%p data:%p\n", - __func__, nfsseg, seg_bp, seg_bp->b_data)); - - binfo = (union nandfs_binfo *)(seg_bp->b_data + - sizeof(struct nandfs_segment_summary)); - curr_off = sizeof(struct nandfs_segment_summary); - - TAILQ_FOREACH(bp, &nfsseg->data, b_cluster.cluster_entry) { - KASSERT((bp->b_vp), ("bp %p has not vp", bp)); - - DPRINTF(BMAP, ("\n\n%s: assign buf %p for ino %#jx next %p\n", - __func__, bp, (uintmax_t)VTON(bp->b_vp)->nn_ino, - TAILQ_NEXT(bp, b_cluster.cluster_entry))); - - if (NBINFO(curr_off) > blocksize) { - seg_bp = TAILQ_NEXT(seg_bp, b_cluster.cluster_entry); - binfo = (union nandfs_binfo *)seg_bp->b_data; - curr_off = 0; - DPRINTF(SYNC, ("%s: next segsum %p data %p\n", - __func__, seg_bp, seg_bp->b_data)); - } - - error = nandfs_update_phys_block(fsdev, bp, blocknr, binfo); - if (error) { - nandfs_error("%s: err:%d when updatinng phys block:%jx" - " for bp:%p and binfo:%p\n", __func__, error, - (uintmax_t)blocknr, bp, binfo); - return (error); - } - binfo++; - curr_off = NBINFO(curr_off); - - blocknr++; - } - - return (0); -} - -static int -nandfs_seginfo_assign_pblk(struct nandfs_seginfo *seginfo) -{ - struct nandfs_segment *nfsseg; - int error = 0; - - LIST_FOREACH(nfsseg, &seginfo->seg_list, seg_link) { - error = nandfs_segment_assign_pblk(nfsseg); - if (error) - break; - } - - return (error); -} - -static struct nandfs_segment_summary * -nandfs_fill_segsum(struct nandfs_segment *seg, int has_sr) -{ - struct nandfs_segment_summary *ss; - struct nandfs_device *fsdev; - struct buf *bp; - uint32_t rest, segsum_size, blocksize, crc_calc; - uint16_t flags; - uint8_t *crc_area, crc_skip; - - DPRINTF(SYNC, ("%s: seg %#jx nblocks %#x sumbytes %#x\n", - __func__, (uintmax_t) seg->seg_num, - seg->nblocks + seg->segsum_blocks, - seg->segsum_bytes)); - - fsdev = seg->fsdev; - - flags = NANDFS_SS_LOGBGN | NANDFS_SS_LOGEND; - if (has_sr) - flags |= NANDFS_SS_SR; - - bp = TAILQ_FIRST(&seg->segsum); - ss = (struct nandfs_segment_summary *) bp->b_data; - ss->ss_magic = NANDFS_SEGSUM_MAGIC; - ss->ss_bytes = sizeof(struct nandfs_segment_summary); - ss->ss_flags = flags; - ss->ss_seq = ++(fsdev->nd_seg_sequence); - ss->ss_create = fsdev->nd_ts.tv_sec; - nandfs_get_segment_range(fsdev, seg->seg_next, &ss->ss_next, NULL); - ss->ss_nblocks = seg->nblocks + seg->segsum_blocks; - ss->ss_nbinfos = seg->nbinfos; - ss->ss_sumbytes = seg->segsum_bytes; - - crc_skip = sizeof(ss->ss_datasum) + sizeof(ss->ss_sumsum); - blocksize = seg->fsdev->nd_blocksize; - - segsum_size = seg->segsum_bytes - crc_skip; - rest = min(seg->segsum_bytes, blocksize) - crc_skip; - crc_area = (uint8_t *)ss + crc_skip; - crc_calc = ~0U; - while (segsum_size > 0) { - crc_calc = crc32_raw(crc_area, rest, crc_calc); - segsum_size -= rest; - if (!segsum_size) - break; - bp = TAILQ_NEXT(bp, b_cluster.cluster_entry); - crc_area = (uint8_t *)bp->b_data; - rest = segsum_size <= blocksize ? segsum_size : blocksize; - } - ss->ss_sumsum = crc_calc ^ ~0U; - - return (ss); - -} - -static int -nandfs_save_buf(struct buf *bp, uint64_t blocknr, struct nandfs_device *fsdev) -{ - struct bufobj *bo; - int error; - - bo = &fsdev->nd_devvp->v_bufobj; - - bp->b_blkno = nandfs_block_to_dblock(fsdev, blocknr); - bp->b_iooffset = dbtob(bp->b_blkno); - - KASSERT(bp->b_bufobj != NULL, ("no bufobj for %p", bp)); - if (bp->b_bufobj != bo) { - BO_LOCK(bp->b_bufobj); - BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, - BO_LOCKPTR(bp->b_bufobj)); - KASSERT(BUF_ISLOCKED(bp), ("Problem with locking buffer")); - } - - DPRINTF(SYNC, ("%s: buf: %p offset %#jx blk %#jx size %#x\n", - __func__, bp, (uintmax_t)bp->b_offset, (uintmax_t)blocknr, - fsdev->nd_blocksize)); - - NANDFS_UNGATHER(bp); - nandfs_buf_clear(bp, 0xffffffff); - bp->b_flags &= ~(B_ASYNC|B_INVAL|B_MANAGED); - error = bwrite(bp); - if (error) { - nandfs_error("%s: error:%d when writing buffer:%p\n", - __func__, error, bp); - return (error); - } - return (error); -} - -static void -nandfs_clean_buf(struct nandfs_device *fsdev, struct buf *bp) -{ - - DPRINTF(SYNC, ("%s: buf: %p\n", __func__, bp)); - - NANDFS_UNGATHER(bp); - nandfs_buf_clear(bp, 0xffffffff); - bp->b_flags &= ~(B_ASYNC|B_INVAL|B_MANAGED); - nandfs_undirty_buf_fsdev(fsdev, bp); -} - -static void -nandfs_clean_segblocks(struct nandfs_segment *seg, uint8_t unlock) -{ - struct nandfs_device *fsdev = seg->fsdev; - struct nandfs_segment *next_seg; - struct buf *bp, *tbp, *next_bp; - struct vnode *vp, *next_vp; - - VOP_LOCK(fsdev->nd_devvp, LK_EXCLUSIVE); - TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, tbp) { - TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry); - nandfs_clean_buf(fsdev, bp); - } - - TAILQ_FOREACH_SAFE(bp, &seg->data, b_cluster.cluster_entry, tbp) { - TAILQ_REMOVE(&seg->data, bp, b_cluster.cluster_entry); - - /* - * If bp is not super-root and vnode is not currently - * locked lock it. - */ - vp = bp->b_vp; - next_vp = NULL; - next_bp = TAILQ_NEXT(bp, b_cluster.cluster_entry); - if (!next_bp) { - next_seg = LIST_NEXT(seg, seg_link); - if (next_seg) - next_bp = TAILQ_FIRST(&next_seg->data); - } - - if (next_bp) - next_vp = next_bp->b_vp; - - nandfs_clean_buf(fsdev, bp); - - if (unlock && vp != NULL && next_vp != vp && - !NANDFS_SYS_NODE(VTON(vp)->nn_ino)) - vput(vp); - - nandfs_dirty_bufs_decrement(fsdev); - } - - VOP_UNLOCK(fsdev->nd_devvp, 0); -} - -static int -nandfs_save_segblocks(struct nandfs_segment *seg, uint8_t unlock) -{ - struct nandfs_device *fsdev = seg->fsdev; - struct nandfs_segment *next_seg; - struct buf *bp, *tbp, *next_bp; - struct vnode *vp, *next_vp; - uint64_t blocknr; - uint32_t i = 0; - int error = 0; - - VOP_LOCK(fsdev->nd_devvp, LK_EXCLUSIVE); - TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, tbp) { - TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry); - blocknr = seg->start_block + i; - error = nandfs_save_buf(bp, blocknr, fsdev); - if (error) { - nandfs_error("%s: error saving buf: %p blocknr:%jx\n", - __func__, bp, (uintmax_t)blocknr); - goto out; - } - i++; - } - - i = 0; - TAILQ_FOREACH_SAFE(bp, &seg->data, b_cluster.cluster_entry, tbp) { - TAILQ_REMOVE(&seg->data, bp, b_cluster.cluster_entry); - - blocknr = seg->start_block + seg->segsum_blocks + i; - /* - * If bp is not super-root and vnode is not currently - * locked lock it. - */ - vp = bp->b_vp; - next_vp = NULL; - next_bp = TAILQ_NEXT(bp, b_cluster.cluster_entry); - if (!next_bp) { - next_seg = LIST_NEXT(seg, seg_link); - if (next_seg) - next_bp = TAILQ_FIRST(&next_seg->data); - } - - if (next_bp) - next_vp = next_bp->b_vp; - - error = nandfs_save_buf(bp, blocknr, fsdev); - if (error) { - nandfs_error("%s: error saving buf: %p blknr: %jx\n", - __func__, bp, (uintmax_t)blocknr); - if (unlock && vp != NULL && next_vp != vp && - !NANDFS_SYS_NODE(VTON(vp)->nn_ino)) - vput(vp); - goto out; - } - - if (unlock && vp != NULL && next_vp != vp && - !NANDFS_SYS_NODE(VTON(vp)->nn_ino)) - vput(vp); - - i++; - nandfs_dirty_bufs_decrement(fsdev); - } -out: - if (error) { - nandfs_clean_segblocks(seg, unlock); - VOP_UNLOCK(fsdev->nd_devvp, 0); - return (error); - } - - VOP_UNLOCK(fsdev->nd_devvp, 0); - return (error); -} - - -static void -clean_seginfo(struct nandfs_seginfo *seginfo, uint8_t unlock) -{ - struct nandfs_segment *seg; - - DPRINTF(SYNC, ("%s: seginfo %p\n", __func__, seginfo)); - - LIST_FOREACH(seg, &seginfo->seg_list, seg_link) { - nandfs_clean_segblocks(seg, unlock); - } -} - -static int -save_seginfo(struct nandfs_seginfo *seginfo, uint8_t unlock) -{ - struct nandfs_segment *seg; - struct nandfs_device *fsdev; - struct nandfs_segment_summary *ss; - int error = 0; - - fsdev = seginfo->fsdev; - - DPRINTF(SYNC, ("%s: seginfo %p\n", __func__, seginfo)); - - LIST_FOREACH(seg, &seginfo->seg_list, seg_link) { - if (LIST_NEXT(seg, seg_link)) { - nandfs_fill_segsum(seg, 0); - error = nandfs_save_segblocks(seg, unlock); - if (error) { - nandfs_error("%s: error:%d saving seg:%p\n", - __func__, error, seg); - goto out; - } - } else { - ss = nandfs_fill_segsum(seg, 1); - fsdev->nd_last_segsum = *ss; - error = nandfs_save_segblocks(seg, unlock); - if (error) { - nandfs_error("%s: error:%d saving seg:%p\n", - __func__, error, seg); - goto out; - } - fsdev->nd_last_cno++; - fsdev->nd_last_pseg = seg->start_block; - } - } -out: - if (error) - clean_seginfo(seginfo, unlock); - return (error); -} - -static void -nandfs_invalidate_bufs(struct nandfs_device *fsdev, uint64_t segno) -{ - uint64_t start, end; - struct buf *bp, *tbd; - struct bufobj *bo; - - nandfs_get_segment_range(fsdev, segno, &start, &end); - - bo = &NTOV(fsdev->nd_gc_node)->v_bufobj; - - BO_LOCK(bo); -restart_locked_gc: - TAILQ_FOREACH_SAFE(bp, &bo->bo_clean.bv_hd, b_bobufs, tbd) { - if (!(bp->b_lblkno >= start && bp->b_lblkno <= end)) - continue; - - if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL)) - goto restart_locked_gc; - - bremfree(bp); - bp->b_flags |= (B_INVAL | B_RELBUF); - bp->b_flags &= ~(B_ASYNC | B_MANAGED); - BO_UNLOCK(bo); - brelse(bp); - BO_LOCK(bo); - } - BO_UNLOCK(bo); -} - -/* Process segments marks to free by cleaner */ -static void -nandfs_process_segments(struct nandfs_device *fsdev) -{ - uint64_t saved_segment; - int i; - - if (fsdev->nd_free_base) { - saved_segment = nandfs_get_segnum_of_block(fsdev, - fsdev->nd_super.s_last_pseg); - for (i = 0; i < fsdev->nd_free_count; i++) { - if (fsdev->nd_free_base[i] == NANDFS_NOSEGMENT) - continue; - /* Update superblock if clearing segment point by it */ - if (fsdev->nd_free_base[i] == saved_segment) { - nandfs_write_superblock(fsdev); - saved_segment = nandfs_get_segnum_of_block( - fsdev, fsdev->nd_super.s_last_pseg); - } - nandfs_invalidate_bufs(fsdev, fsdev->nd_free_base[i]); - nandfs_clear_segment(fsdev, fsdev->nd_free_base[i]); - } - - free(fsdev->nd_free_base, M_NANDFSTEMP); - fsdev->nd_free_base = NULL; - fsdev->nd_free_count = 0; - } -} - -/* Collect and write dirty buffers */ -int -nandfs_sync_file(struct vnode *vp) -{ - struct nandfs_device *fsdev; - struct nandfs_node *nandfs_node; - struct nandfsmount *nmp; - struct nandfs_node *dat, *su, *ifile, *cp; - struct nandfs_seginfo *seginfo = NULL; - struct nandfs_segment *seg; - int update, error; - int cno_changed; - - ASSERT_VOP_LOCKED(vp, __func__); - DPRINTF(SYNC, ("%s: START\n", __func__)); - - error = 0; - nmp = VFSTONANDFS(vp->v_mount); - fsdev = nmp->nm_nandfsdev; - - dat = fsdev->nd_dat_node; - su = fsdev->nd_su_node; - cp = fsdev->nd_cp_node; - ifile = nmp->nm_ifile_node; - - NANDFS_WRITEASSERT(fsdev); - if (lockmgr(&fsdev->nd_seg_const, LK_UPGRADE, NULL) != 0) { - DPRINTF(SYNC, ("%s: lost shared lock\n", __func__)); - if (lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL) != 0) - panic("couldn't lock exclusive"); - } - DPRINTF(SYNC, ("%s: got lock\n", __func__)); - - VOP_LOCK(NTOV(su), LK_EXCLUSIVE); - create_seginfo(fsdev, &seginfo); - - update = 0; - - nandfs_node = VTON(vp); - if (nandfs_node->nn_flags & IN_MODIFIED) { - nandfs_node->nn_flags &= ~(IN_MODIFIED); - update = 1; - } - - if (vp->v_bufobj.bo_dirty.bv_cnt) { - error = nandfs_iterate_dirty_buf(vp, seginfo, 0); - if (error) { - clean_seginfo(seginfo, 0); - delete_seginfo(seginfo); - VOP_UNLOCK(NTOV(su), 0); - lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); - nandfs_error("%s: err:%d iterating dirty bufs vp:%p", - __func__, error, vp); - return (error); - } - update = 1; - } - - if (update) { - VOP_LOCK(NTOV(ifile), LK_EXCLUSIVE); - error = nandfs_node_update(nandfs_node); - if (error) { - clean_seginfo(seginfo, 0); - delete_seginfo(seginfo); - VOP_UNLOCK(NTOV(ifile), 0); - VOP_UNLOCK(NTOV(su), 0); - lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); - nandfs_error("%s: err:%d updating vp:%p", - __func__, error, vp); - return (error); - } - VOP_UNLOCK(NTOV(ifile), 0); - } - - cno_changed = 0; - if (seginfo->blocks) { - VOP_LOCK(NTOV(cp), LK_EXCLUSIVE); - cno_changed = 1; - /* Create new checkpoint */ - error = nandfs_get_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1); - if (error) { - clean_seginfo(seginfo, 0); - delete_seginfo(seginfo); - VOP_UNLOCK(NTOV(cp), 0); - VOP_UNLOCK(NTOV(su), 0); - lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); - nandfs_error("%s: err:%d getting cp:%jx", - __func__, error, fsdev->nd_last_cno + 1); - return (error); - } - - /* Reiterate all blocks and assign physical block number */ - nandfs_seginfo_assign_pblk(seginfo); - - /* Fill checkpoint data */ - error = nandfs_set_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1, - &ifile->nn_inode, seginfo->blocks); - if (error) { - clean_seginfo(seginfo, 0); - delete_seginfo(seginfo); - VOP_UNLOCK(NTOV(cp), 0); - VOP_UNLOCK(NTOV(su), 0); - lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); - nandfs_error("%s: err:%d setting cp:%jx", - __func__, error, fsdev->nd_last_cno + 1); - return (error); - } - - VOP_UNLOCK(NTOV(cp), 0); - LIST_FOREACH(seg, &seginfo->seg_list, seg_link) - nandfs_update_segment(fsdev, seg->seg_num, - seg->nblocks + seg->segsum_blocks); - - VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); - error = save_seginfo(seginfo, 0); - if (error) { - clean_seginfo(seginfo, 0); - delete_seginfo(seginfo); - VOP_UNLOCK(NTOV(dat), 0); - VOP_UNLOCK(NTOV(su), 0); - lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); - nandfs_error("%s: err:%d updating seg", - __func__, error); - return (error); - } - VOP_UNLOCK(NTOV(dat), 0); - } - - VOP_UNLOCK(NTOV(su), 0); - - delete_seginfo(seginfo); - lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); - - if (cno_changed && !error) { - if (nandfs_cps_between_sblocks != 0 && - fsdev->nd_last_cno % nandfs_cps_between_sblocks == 0) - nandfs_write_superblock(fsdev); - } - - ASSERT_VOP_LOCKED(vp, __func__); - DPRINTF(SYNC, ("%s: END error %d\n", __func__, error)); - return (error); -} - -int -nandfs_segment_constructor(struct nandfsmount *nmp, int flags) -{ - struct nandfs_device *fsdev; - struct nandfs_seginfo *seginfo = NULL; - struct nandfs_segment *seg; - struct nandfs_node *dat, *su, *ifile, *cp, *gc; - int cno_changed, error; - - DPRINTF(SYNC, ("%s: START\n", __func__)); - fsdev = nmp->nm_nandfsdev; - - lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL); - DPRINTF(SYNC, ("%s: git lock\n", __func__)); -again: - create_seginfo(fsdev, &seginfo); - - dat = fsdev->nd_dat_node; - su = fsdev->nd_su_node; - cp = fsdev->nd_cp_node; - gc = fsdev->nd_gc_node; - ifile = nmp->nm_ifile_node; - - VOP_LOCK(NTOV(su), LK_EXCLUSIVE); - VOP_LOCK(NTOV(ifile), LK_EXCLUSIVE); - VOP_LOCK(NTOV(gc), LK_EXCLUSIVE); - VOP_LOCK(NTOV(cp), LK_EXCLUSIVE); - - nandfs_iterate_system_vnode(gc, seginfo); - nandfs_iterate_dirty_vnodes(nmp->nm_vfs_mountp, seginfo); - nandfs_iterate_system_vnode(ifile, seginfo); - nandfs_iterate_system_vnode(su, seginfo); - - cno_changed = 0; - if (seginfo->blocks || flags) { - cno_changed = 1; - /* Create new checkpoint */ - error = nandfs_get_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1); - if (error) { - clean_seginfo(seginfo, 0); - delete_seginfo(seginfo); - goto error_locks; - } - - /* Collect blocks from system files */ - nandfs_iterate_system_vnode(cp, seginfo); - nandfs_iterate_system_vnode(su, seginfo); - VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); - nandfs_iterate_system_vnode(dat, seginfo); - VOP_UNLOCK(NTOV(dat), 0); -reiterate: - seginfo->reiterate = 0; - nandfs_iterate_system_vnode(su, seginfo); - VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); - nandfs_iterate_system_vnode(dat, seginfo); - VOP_UNLOCK(NTOV(dat), 0); - if (seginfo->reiterate) - goto reiterate; - if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) { - error = create_segment(seginfo); - if (error) { - clean_seginfo(seginfo, 0); - delete_seginfo(seginfo); - goto error_locks; - } - goto reiterate; - } - - /* Reiterate all blocks and assign physical block number */ - nandfs_seginfo_assign_pblk(seginfo); - - /* Fill superroot */ - error = nandfs_add_superroot(seginfo); - if (error) { - clean_seginfo(seginfo, 0); - delete_seginfo(seginfo); - goto error_locks; - } - KASSERT(!(seginfo->reiterate), ("reiteration after superroot")); - - /* Fill checkpoint data */ - nandfs_set_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1, - &ifile->nn_inode, seginfo->blocks); - - LIST_FOREACH(seg, &seginfo->seg_list, seg_link) - nandfs_update_segment(fsdev, seg->seg_num, - seg->nblocks + seg->segsum_blocks); - - VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); - error = save_seginfo(seginfo, 1); - if (error) { - clean_seginfo(seginfo, 1); - delete_seginfo(seginfo); - goto error_dat; - } - VOP_UNLOCK(NTOV(dat), 0); - } - - VOP_UNLOCK(NTOV(cp), 0); - VOP_UNLOCK(NTOV(gc), 0); - VOP_UNLOCK(NTOV(ifile), 0); - - nandfs_process_segments(fsdev); - - VOP_UNLOCK(NTOV(su), 0); - - delete_seginfo(seginfo); - - /* - * XXX: a hack, will go away soon - */ - if ((NTOV(dat)->v_bufobj.bo_dirty.bv_cnt != 0 || - NTOV(cp)->v_bufobj.bo_dirty.bv_cnt != 0 || - NTOV(gc)->v_bufobj.bo_dirty.bv_cnt != 0 || - NTOV(ifile)->v_bufobj.bo_dirty.bv_cnt != 0 || - NTOV(su)->v_bufobj.bo_dirty.bv_cnt != 0) && - (flags & NANDFS_UMOUNT)) { - DPRINTF(SYNC, ("%s: RERUN\n", __func__)); - goto again; - } - - MPASS(fsdev->nd_free_base == NULL); - - lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL); - - if (cno_changed) { - if ((nandfs_cps_between_sblocks != 0 && - fsdev->nd_last_cno % nandfs_cps_between_sblocks == 0) || - flags & NANDFS_UMOUNT) - nandfs_write_superblock(fsdev); - } - - DPRINTF(SYNC, ("%s: END\n", __func__)); - return (0); -error_dat: - VOP_UNLOCK(NTOV(dat), 0); -error_locks: - VOP_UNLOCK(NTOV(cp), 0); - VOP_UNLOCK(NTOV(gc), 0); - VOP_UNLOCK(NTOV(ifile), 0); - VOP_UNLOCK(NTOV(su), 0); - lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL); - - return (error); -} - -#ifdef DDB -/* - * Show details about the given NANDFS mount point. - */ -DB_SHOW_COMMAND(nandfs, db_show_nandfs) -{ - struct mount *mp; - struct nandfs_device *nffsdev; - struct nandfs_segment *seg; - struct nandfsmount *nmp; - struct buf *bp; - struct vnode *vp; - - if (!have_addr) { - db_printf("\nUsage: show nandfs \n"); - return; - } - - mp = (struct mount *)addr; - db_printf("%p %s on %s (%s)\n", mp, mp->mnt_stat.f_mntfromname, - mp->mnt_stat.f_mntonname, mp->mnt_stat.f_fstypename); - - - nmp = (struct nandfsmount *)(mp->mnt_data); - nffsdev = nmp->nm_nandfsdev; - db_printf("dev vnode:%p\n", nffsdev->nd_devvp); - db_printf("blocksize:%jx last cno:%jx last pseg:%jx seg num:%jx\n", - (uintmax_t)nffsdev->nd_blocksize, (uintmax_t)nffsdev->nd_last_cno, - (uintmax_t)nffsdev->nd_last_pseg, (uintmax_t)nffsdev->nd_seg_num); - db_printf("system nodes: dat:%p cp:%p su:%p ifile:%p gc:%p\n", - nffsdev->nd_dat_node, nffsdev->nd_cp_node, nffsdev->nd_su_node, - nmp->nm_ifile_node, nffsdev->nd_gc_node); - - if (nffsdev->nd_seginfo != NULL) { - LIST_FOREACH(seg, &nffsdev->nd_seginfo->seg_list, seg_link) { - db_printf("seg: %p\n", seg); - TAILQ_FOREACH(bp, &seg->segsum, - b_cluster.cluster_entry) - db_printf("segbp %p\n", bp); - TAILQ_FOREACH(bp, &seg->data, - b_cluster.cluster_entry) { - vp = bp->b_vp; - db_printf("bp:%p bp->b_vp:%p ino:%jx\n", bp, vp, - (uintmax_t)(vp ? VTON(vp)->nn_ino : 0)); - } - } - } -} -#endif diff --git a/sys/fs/nandfs/nandfs_subr.c b/sys/fs/nandfs/nandfs_subr.c deleted file mode 100644 index 0a3f65a50543..000000000000 --- a/sys/fs/nandfs/nandfs_subr.c +++ /dev/null @@ -1,1091 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf - * Copyright (c) 2008, 2009 Reinoud Zandijk - * 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, 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. - * - * From: NetBSD: nilfs_subr.c,v 1.4 2009/07/29 17:06:57 reinoud - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include -#include "nandfs_mount.h" -#include "nandfs.h" -#include "nandfs_subr.h" - -MALLOC_DEFINE(M_NANDFSMNT, "nandfs_mount", "NANDFS mount"); -MALLOC_DEFINE(M_NANDFSTEMP, "nandfs_tmt", "NANDFS tmp"); - -uma_zone_t nandfs_node_zone; - -void nandfs_bdflush(struct bufobj *bo, struct buf *bp); -int nandfs_bufsync(struct bufobj *bo, int waitfor); - -struct buf_ops buf_ops_nandfs = { - .bop_name = "buf_ops_nandfs", - .bop_write = bufwrite, - .bop_strategy = bufstrategy, - .bop_sync = nandfs_bufsync, - .bop_bdflush = nandfs_bdflush, -}; - -int -nandfs_bufsync(struct bufobj *bo, int waitfor) -{ - struct vnode *vp; - int error = 0; - - vp = bo2vnode(bo); - - ASSERT_VOP_LOCKED(vp, __func__); - error = nandfs_sync_file(vp); - if (error) - nandfs_warning("%s: cannot flush buffers err:%d\n", - __func__, error); - - return (error); -} - -void -nandfs_bdflush(bo, bp) - struct bufobj *bo; - struct buf *bp; -{ - struct vnode *vp; - int error; - - if (bo->bo_dirty.bv_cnt <= ((dirtybufthresh * 8) / 10)) - return; - - vp = bp->b_vp; - if (NANDFS_SYS_NODE(VTON(vp)->nn_ino)) - return; - - if (NANDFS_IS_INDIRECT(bp)) - return; - - error = nandfs_sync_file(vp); - if (error) - nandfs_warning("%s: cannot flush buffers err:%d\n", - __func__, error); -} - -int -nandfs_init(struct vfsconf *vfsp) -{ - - nandfs_node_zone = uma_zcreate("nandfs node zone", - sizeof(struct nandfs_node), NULL, NULL, NULL, NULL, 0, 0); - - return (0); -} - -int -nandfs_uninit(struct vfsconf *vfsp) -{ - - uma_zdestroy(nandfs_node_zone); - return (0); -} - -/* Basic calculators */ -uint64_t -nandfs_get_segnum_of_block(struct nandfs_device *nandfsdev, - nandfs_daddr_t blocknr) -{ - uint64_t segnum, blks_per_seg; - - MPASS(blocknr >= nandfsdev->nd_fsdata.f_first_data_block); - - blks_per_seg = nandfsdev->nd_fsdata.f_blocks_per_segment; - - segnum = blocknr / blks_per_seg; - segnum -= nandfsdev->nd_fsdata.f_first_data_block / blks_per_seg; - - DPRINTF(SYNC, ("%s: returning blocknr %jx -> segnum %jx\n", __func__, - blocknr, segnum)); - - return (segnum); -} - -void -nandfs_get_segment_range(struct nandfs_device *nandfsdev, uint64_t segnum, - uint64_t *seg_start, uint64_t *seg_end) -{ - uint64_t blks_per_seg; - - blks_per_seg = nandfsdev->nd_fsdata.f_blocks_per_segment; - *seg_start = nandfsdev->nd_fsdata.f_first_data_block + - blks_per_seg * segnum; - if (seg_end != NULL) - *seg_end = *seg_start + blks_per_seg -1; -} - -void nandfs_calc_mdt_consts(struct nandfs_device *nandfsdev, - struct nandfs_mdt *mdt, int entry_size) -{ - uint32_t blocksize = nandfsdev->nd_blocksize; - - mdt->entries_per_group = blocksize * 8; - mdt->entries_per_block = blocksize / entry_size; - - mdt->blocks_per_group = - (mdt->entries_per_group -1) / mdt->entries_per_block + 1 + 1; - mdt->groups_per_desc_block = - blocksize / sizeof(struct nandfs_block_group_desc); - mdt->blocks_per_desc_block = - mdt->groups_per_desc_block * mdt->blocks_per_group + 1; -} - -int -nandfs_dev_bread(struct nandfs_device *nandfsdev, nandfs_lbn_t blocknr, - struct ucred *cred, int flags, struct buf **bpp) -{ - int blk2dev = nandfsdev->nd_blocksize / DEV_BSIZE; - int error; - - DPRINTF(BLOCK, ("%s: read from block %jx vp %p\n", __func__, - blocknr * blk2dev, nandfsdev->nd_devvp)); - error = bread(nandfsdev->nd_devvp, blocknr * blk2dev, - nandfsdev->nd_blocksize, NOCRED, bpp); - if (error) - nandfs_error("%s: cannot read from device - blk:%jx\n", - __func__, blocknr); - return (error); -} - -/* Read on a node */ -int -nandfs_bread(struct nandfs_node *node, nandfs_lbn_t blocknr, - struct ucred *cred, int flags, struct buf **bpp) -{ - nandfs_daddr_t vblk; - int error; - - DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node), - blocknr)); - - error = bread(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize, - cred, bpp); - - KASSERT(error == 0, ("%s: vp:%p lbn:%#jx err:%d\n", __func__, - NTOV(node), blocknr, error)); - - if (!nandfs_vblk_get(*bpp) && - ((*bpp)->b_flags & B_CACHE) && node->nn_ino != NANDFS_DAT_INO) { - nandfs_bmap_lookup(node, blocknr, &vblk); - nandfs_vblk_set(*bpp, vblk); - } - return (error); -} - -int -nandfs_bread_meta(struct nandfs_node *node, nandfs_lbn_t blocknr, - struct ucred *cred, int flags, struct buf **bpp) -{ - nandfs_daddr_t vblk; - int error; - - DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node), - blocknr)); - - error = bread(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize, - cred, bpp); - - KASSERT(error == 0, ("%s: vp:%p lbn:%#jx err:%d\n", __func__, - NTOV(node), blocknr, error)); - - if (!nandfs_vblk_get(*bpp) && - ((*bpp)->b_flags & B_CACHE) && node->nn_ino != NANDFS_DAT_INO) { - nandfs_bmap_lookup(node, blocknr, &vblk); - nandfs_vblk_set(*bpp, vblk); - } - - return (error); -} - -int -nandfs_bdestroy(struct nandfs_node *node, nandfs_daddr_t vblk) -{ - int error; - - if (!NANDFS_SYS_NODE(node->nn_ino)) - NANDFS_WRITEASSERT(node->nn_nandfsdev); - - error = nandfs_vblock_end(node->nn_nandfsdev, vblk); - if (error) { - nandfs_error("%s: ending vblk: %jx failed\n", - __func__, (uintmax_t)vblk); - return (error); - } - node->nn_inode.i_blocks--; - - return (0); -} - -int -nandfs_bcreate(struct nandfs_node *node, nandfs_lbn_t blocknr, - struct ucred *cred, int flags, struct buf **bpp) -{ - int error; - - ASSERT_VOP_LOCKED(NTOV(node), __func__); - if (!NANDFS_SYS_NODE(node->nn_ino)) - NANDFS_WRITEASSERT(node->nn_nandfsdev); - - DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node), - blocknr)); - - *bpp = getblk(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize, - 0, 0, 0); - - KASSERT((*bpp), ("%s: vp:%p lbn:%#jx\n", __func__, - NTOV(node), blocknr)); - - if (*bpp) { - vfs_bio_clrbuf(*bpp); - (*bpp)->b_blkno = ~(0); /* To avoid VOP_BMAP in bdwrite */ - error = nandfs_bmap_insert_block(node, blocknr, *bpp); - if (error) { - nandfs_warning("%s: failed bmap insert node:%p" - " blk:%jx\n", __func__, node, blocknr); - brelse(*bpp); - return (error); - } - node->nn_inode.i_blocks++; - - return (0); - } - - return (-1); -} - -int -nandfs_bcreate_meta(struct nandfs_node *node, nandfs_lbn_t blocknr, - struct ucred *cred, int flags, struct buf **bpp) -{ - struct nandfs_device *fsdev; - nandfs_daddr_t vblk; - int error; - - ASSERT_VOP_LOCKED(NTOV(node), __func__); - NANDFS_WRITEASSERT(node->nn_nandfsdev); - - DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node), - blocknr)); - - fsdev = node->nn_nandfsdev; - - *bpp = getblk(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize, - 0, 0, 0); - - KASSERT((*bpp), ("%s: vp:%p lbn:%#jx\n", __func__, - NTOV(node), blocknr)); - - memset((*bpp)->b_data, 0, fsdev->nd_blocksize); - - vfs_bio_clrbuf(*bpp); - (*bpp)->b_blkno = ~(0); /* To avoid VOP_BMAP in bdwrite */ - - nandfs_buf_set(*bpp, NANDFS_VBLK_ASSIGNED); - - if (node->nn_ino != NANDFS_DAT_INO) { - error = nandfs_vblock_alloc(fsdev, &vblk); - if (error) { - nandfs_buf_clear(*bpp, NANDFS_VBLK_ASSIGNED); - brelse(*bpp); - return (error); - } - } else - vblk = fsdev->nd_fakevblk++; - - nandfs_vblk_set(*bpp, vblk); - - nandfs_bmap_insert_block(node, blocknr, *bpp); - return (0); -} - -/* Translate index to a file block number and an entry */ -void -nandfs_mdt_trans(struct nandfs_mdt *mdt, uint64_t index, - nandfs_lbn_t *blocknr, uint32_t *entry_in_block) -{ - uint64_t blknr; - uint64_t group, group_offset, blocknr_in_group; - uint64_t desc_block, desc_offset; - - /* Calculate our offset in the file */ - group = index / mdt->entries_per_group; - group_offset = index % mdt->entries_per_group; - desc_block = group / mdt->groups_per_desc_block; - desc_offset = group % mdt->groups_per_desc_block; - blocknr_in_group = group_offset / mdt->entries_per_block; - - /* To descgroup offset */ - blknr = 1 + desc_block * mdt->blocks_per_desc_block; - - /* To group offset */ - blknr += desc_offset * mdt->blocks_per_group; - - /* To actual file block */ - blknr += 1 + blocknr_in_group; - - *blocknr = blknr; - *entry_in_block = group_offset % mdt->entries_per_block; -} - -void -nandfs_mdt_trans_blk(struct nandfs_mdt *mdt, uint64_t index, - uint64_t *desc, uint64_t *bitmap, nandfs_lbn_t *blocknr, - uint32_t *entry_in_block) -{ - uint64_t blknr; - uint64_t group, group_offset, blocknr_in_group; - uint64_t desc_block, desc_offset; - - /* Calculate our offset in the file */ - group = index / mdt->entries_per_group; - group_offset = index % mdt->entries_per_group; - desc_block = group / mdt->groups_per_desc_block; - desc_offset = group % mdt->groups_per_desc_block; - blocknr_in_group = group_offset / mdt->entries_per_block; - - /* To descgroup offset */ - *desc = desc_block * mdt->blocks_per_desc_block; - blknr = 1 + desc_block * mdt->blocks_per_desc_block; - - /* To group offset */ - blknr += desc_offset * mdt->blocks_per_group; - *bitmap = blknr; - - /* To actual file block */ - blknr += 1 + blocknr_in_group; - - *blocknr = blknr; - *entry_in_block = group_offset % mdt->entries_per_block; - - DPRINTF(ALLOC, - ("%s: desc_buf: %jx bitmap_buf: %jx entry_buf: %jx entry: %x\n", - __func__, (uintmax_t)*desc, (uintmax_t)*bitmap, - (uintmax_t)*blocknr, *entry_in_block)); -} - -int -nandfs_vtop(struct nandfs_node *node, nandfs_daddr_t vblocknr, - nandfs_daddr_t *pblocknr) -{ - struct nandfs_node *dat_node; - struct nandfs_dat_entry *entry; - struct buf *bp; - nandfs_lbn_t ldatblknr; - uint32_t entry_in_block; - int locked, error; - - if (node->nn_ino == NANDFS_DAT_INO || node->nn_ino == NANDFS_GC_INO) { - *pblocknr = vblocknr; - return (0); - } - - /* only translate valid vblocknrs */ - if (vblocknr == 0) - return (0); - - dat_node = node->nn_nandfsdev->nd_dat_node; - nandfs_mdt_trans(&node->nn_nandfsdev->nd_dat_mdt, vblocknr, &ldatblknr, - &entry_in_block); - - locked = NANDFS_VOP_ISLOCKED(NTOV(dat_node)); - if (!locked) - VOP_LOCK(NTOV(dat_node), LK_SHARED); - error = nandfs_bread(dat_node, ldatblknr, NOCRED, 0, &bp); - if (error) { - DPRINTF(TRANSLATE, ("vtop: can't read in DAT block %#jx!\n", - (uintmax_t)ldatblknr)); - brelse(bp); - VOP_UNLOCK(NTOV(dat_node), 0); - return (error); - } - - /* Get our translation */ - entry = ((struct nandfs_dat_entry *) bp->b_data) + entry_in_block; - DPRINTF(TRANSLATE, ("\tentry %p data %p entry_in_block %x\n", - entry, bp->b_data, entry_in_block)) - DPRINTF(TRANSLATE, ("\tvblk %#jx -> %#jx for cp [%#jx-%#jx]\n", - (uintmax_t)vblocknr, (uintmax_t)entry->de_blocknr, - (uintmax_t)entry->de_start, (uintmax_t)entry->de_end)); - - *pblocknr = entry->de_blocknr; - brelse(bp); - if (!locked) - VOP_UNLOCK(NTOV(dat_node), 0); - - MPASS(*pblocknr >= node->nn_nandfsdev->nd_fsdata.f_first_data_block || - *pblocknr == 0); - - return (0); -} - -int -nandfs_segsum_valid(struct nandfs_segment_summary *segsum) -{ - - return (segsum->ss_magic == NANDFS_SEGSUM_MAGIC); -} - -int -nandfs_load_segsum(struct nandfs_device *fsdev, nandfs_daddr_t blocknr, - struct nandfs_segment_summary *segsum) -{ - struct buf *bp; - int error; - - DPRINTF(VOLUMES, ("nandfs: try segsum at block %jx\n", - (uintmax_t)blocknr)); - - error = nandfs_dev_bread(fsdev, blocknr, NOCRED, 0, &bp); - if (error) - return (error); - - memcpy(segsum, bp->b_data, sizeof(struct nandfs_segment_summary)); - brelse(bp); - - if (!nandfs_segsum_valid(segsum)) { - DPRINTF(VOLUMES, ("%s: bad magic pseg:%jx\n", __func__, - blocknr)); - return (EINVAL); - } - - return (error); -} - -static int -nandfs_load_super_root(struct nandfs_device *nandfsdev, - struct nandfs_segment_summary *segsum, uint64_t pseg) -{ - struct nandfs_super_root super_root; - struct buf *bp; - uint64_t blocknr; - uint32_t super_root_crc, comp_crc; - int off, error; - - /* Check if there is a superroot */ - if ((segsum->ss_flags & NANDFS_SS_SR) == 0) { - DPRINTF(VOLUMES, ("%s: no super root in pseg:%jx\n", __func__, - pseg)); - return (ENOENT); - } - - /* Get our super root, located at the end of the pseg */ - blocknr = pseg + segsum->ss_nblocks - 1; - DPRINTF(VOLUMES, ("%s: try at %#jx\n", __func__, (uintmax_t)blocknr)); - - error = nandfs_dev_bread(nandfsdev, blocknr, NOCRED, 0, &bp); - if (error) - return (error); - - memcpy(&super_root, bp->b_data, sizeof(struct nandfs_super_root)); - brelse(bp); - - /* Check super root CRC */ - super_root_crc = super_root.sr_sum; - off = sizeof(super_root.sr_sum); - comp_crc = crc32((uint8_t *)&super_root + off, - NANDFS_SR_BYTES - off); - - if (super_root_crc != comp_crc) { - DPRINTF(VOLUMES, ("%s: invalid crc:%#x [expect:%#x]\n", - __func__, super_root_crc, comp_crc)); - return (EINVAL); - } - - nandfsdev->nd_super_root = super_root; - DPRINTF(VOLUMES, ("%s: got valid superroot\n", __func__)); - - return (0); -} - -/* - * Search for the last super root recorded. - */ -int -nandfs_search_super_root(struct nandfs_device *nandfsdev) -{ - struct nandfs_super_block *super; - struct nandfs_segment_summary segsum; - uint64_t seg_start, seg_end, cno, seq, create, pseg; - uint64_t segnum; - int error, found; - - error = found = 0; - - /* Search for last super root */ - pseg = nandfsdev->nd_super.s_last_pseg; - segnum = nandfs_get_segnum_of_block(nandfsdev, pseg); - - cno = nandfsdev->nd_super.s_last_cno; - create = seq = 0; - DPRINTF(VOLUMES, ("%s: start in pseg %#jx\n", __func__, - (uintmax_t)pseg)); - - for (;;) { - error = nandfs_load_segsum(nandfsdev, pseg, &segsum); - if (error) - break; - - if (segsum.ss_seq < seq || segsum.ss_create < create) - break; - - /* Try to load super root */ - if (segsum.ss_flags & NANDFS_SS_SR) { - error = nandfs_load_super_root(nandfsdev, &segsum, pseg); - if (error) - break; /* confused */ - found = 1; - - super = &nandfsdev->nd_super; - nandfsdev->nd_last_segsum = segsum; - super->s_last_pseg = pseg; - super->s_last_cno = cno++; - super->s_last_seq = segsum.ss_seq; - super->s_state = NANDFS_VALID_FS; - seq = segsum.ss_seq; - create = segsum.ss_create; - } else { - seq = segsum.ss_seq; - create = segsum.ss_create; - } - - /* Calculate next partial segment location */ - pseg += segsum.ss_nblocks; - DPRINTF(VOLUMES, ("%s: next partial seg is %jx\n", __func__, - (uintmax_t)pseg)); - - /* Did we reach the end of the segment? if so, go to the next */ - nandfs_get_segment_range(nandfsdev, segnum, &seg_start, - &seg_end); - if (pseg >= seg_end) { - pseg = segsum.ss_next; - DPRINTF(VOLUMES, - (" partial seg oor next is %jx[%jx - %jx]\n", - (uintmax_t)pseg, (uintmax_t)seg_start, - (uintmax_t)seg_end)); - } - segnum = nandfs_get_segnum_of_block(nandfsdev, pseg); - } - - if (error && !found) - return (error); - - return (0); -} - -int -nandfs_get_node_raw(struct nandfs_device *nandfsdev, struct nandfsmount *nmp, - uint64_t ino, struct nandfs_inode *inode, struct nandfs_node **nodep) -{ - struct nandfs_node *node; - struct vnode *nvp; - struct mount *mp; - int error; - - *nodep = NULL; - - /* Associate with mountpoint if present */ - if (nmp) { - mp = nmp->nm_vfs_mountp; - error = getnewvnode("nandfs", mp, &nandfs_vnodeops, &nvp); - if (error) - return (error); - } else { - mp = NULL; - error = getnewvnode("snandfs", mp, &nandfs_system_vnodeops, - &nvp); - if (error) - return (error); - } - - if (mp) - NANDFS_WRITELOCK(nandfsdev); - - DPRINTF(IFILE, ("%s: ino: %#jx -> vp: %p\n", - __func__, (uintmax_t)ino, nvp)); - /* Lock node */ - lockmgr(nvp->v_vnlock, LK_EXCLUSIVE, NULL); - - if (mp) { - error = insmntque(nvp, mp); - if (error != 0) { - *nodep = NULL; - return (error); - } - } - - node = uma_zalloc(nandfs_node_zone, M_WAITOK | M_ZERO); - - /* Crosslink */ - node->nn_vnode = nvp; - nvp->v_bufobj.bo_ops = &buf_ops_nandfs; - node->nn_nmp = nmp; - node->nn_nandfsdev = nandfsdev; - nvp->v_data = node; - - /* Initiase NANDFS node */ - node->nn_ino = ino; - if (inode != NULL) - node->nn_inode = *inode; - - nandfs_vinit(nvp, ino); - - /* Return node */ - *nodep = node; - DPRINTF(IFILE, ("%s: ino:%#jx vp:%p node:%p\n", - __func__, (uintmax_t)ino, nvp, *nodep)); - - return (0); -} - -int -nandfs_get_node(struct nandfsmount *nmp, uint64_t ino, - struct nandfs_node **nodep) -{ - struct nandfs_device *nandfsdev; - struct nandfs_inode inode, *entry; - struct vnode *nvp, *vpp; - struct thread *td; - struct buf *bp; - uint64_t ivblocknr; - uint32_t entry_in_block; - int error; - - /* Look up node in hash table */ - td = curthread; - *nodep = NULL; - - if ((ino < NANDFS_ATIME_INO) && (ino != NANDFS_ROOT_INO)) { - printf("nandfs_get_node: system ino %"PRIu64" not in mount " - "point!\n", ino); - return (ENOENT); - } - - error = vfs_hash_get(nmp->nm_vfs_mountp, ino, LK_EXCLUSIVE, td, &nvp, - NULL, NULL); - if (error) - return (error); - - if (nvp != NULL) { - *nodep = (struct nandfs_node *)nvp->v_data; - return (0); - } - - /* Look up inode structure in mountpoints ifile */ - nandfsdev = nmp->nm_nandfsdev; - nandfs_mdt_trans(&nandfsdev->nd_ifile_mdt, ino, &ivblocknr, - &entry_in_block); - - VOP_LOCK(NTOV(nmp->nm_ifile_node), LK_SHARED); - error = nandfs_bread(nmp->nm_ifile_node, ivblocknr, NOCRED, 0, &bp); - if (error) { - brelse(bp); - VOP_UNLOCK(NTOV(nmp->nm_ifile_node), 0); - return (ENOENT); - } - - /* Get inode entry */ - entry = (struct nandfs_inode *) bp->b_data + entry_in_block; - memcpy(&inode, entry, sizeof(struct nandfs_inode)); - brelse(bp); - VOP_UNLOCK(NTOV(nmp->nm_ifile_node), 0); - - /* Get node */ - error = nandfs_get_node_raw(nmp->nm_nandfsdev, nmp, ino, &inode, nodep); - if (error) { - *nodep = NULL; - return (error); - } - - nvp = (*nodep)->nn_vnode; - error = vfs_hash_insert(nvp, ino, 0, td, &vpp, NULL, NULL); - if (error) { - *nodep = NULL; - return (error); - } - - return (error); -} - -void -nandfs_dispose_node(struct nandfs_node **nodep) -{ - struct nandfs_node *node; - struct vnode *vp; - - /* Protect against rogue values */ - node = *nodep; - if (!node) { - return; - } - DPRINTF(NODE, ("nandfs_dispose_node: %p\n", *nodep)); - - vp = NTOV(node); - vp->v_data = NULL; - - /* Free our associated memory */ - uma_zfree(nandfs_node_zone, node); - - *nodep = NULL; -} - -int -nandfs_lookup_name_in_dir(struct vnode *dvp, const char *name, int namelen, - uint64_t *ino, int *found, uint64_t *off) -{ - struct nandfs_node *dir_node = VTON(dvp); - struct nandfs_dir_entry *ndirent; - struct buf *bp; - uint64_t file_size, diroffset, blkoff; - uint64_t blocknr; - uint32_t blocksize = dir_node->nn_nandfsdev->nd_blocksize; - uint8_t *pos, name_len; - int error; - - *found = 0; - - DPRINTF(VNCALL, ("%s: %s file\n", __func__, name)); - if (dvp->v_type != VDIR) { - return (ENOTDIR); - } - - /* Get directory filesize */ - file_size = dir_node->nn_inode.i_size; - - /* Walk the directory */ - diroffset = 0; - blocknr = 0; - blkoff = 0; - error = nandfs_bread(dir_node, blocknr, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (EIO); - } - - while (diroffset < file_size) { - if (blkoff >= blocksize) { - blkoff = 0; blocknr++; - brelse(bp); - error = nandfs_bread(dir_node, blocknr, NOCRED, 0, - &bp); - if (error) { - brelse(bp); - return (EIO); - } - } - - /* Read in one dirent */ - pos = (uint8_t *) bp->b_data + blkoff; - ndirent = (struct nandfs_dir_entry *) pos; - name_len = ndirent->name_len; - - if ((name_len == namelen) && - (strncmp(name, ndirent->name, name_len) == 0) && - (ndirent->inode != 0)) { - *ino = ndirent->inode; - *off = diroffset; - DPRINTF(LOOKUP, ("found `%.*s` with ino %"PRIx64"\n", - name_len, ndirent->name, *ino)); - *found = 1; - break; - } - - /* Advance */ - diroffset += ndirent->rec_len; - blkoff += ndirent->rec_len; - } - brelse(bp); - - return (error); -} - -int -nandfs_get_fsinfo(struct nandfsmount *nmp, struct nandfs_fsinfo *fsinfo) -{ - struct nandfs_device *fsdev; - - fsdev = nmp->nm_nandfsdev; - - memcpy(&fsinfo->fs_fsdata, &fsdev->nd_fsdata, sizeof(fsdev->nd_fsdata)); - memcpy(&fsinfo->fs_super, &fsdev->nd_super, sizeof(fsdev->nd_super)); - snprintf(fsinfo->fs_dev, sizeof(fsinfo->fs_dev), - "%s", nmp->nm_vfs_mountp->mnt_stat.f_mntfromname); - - return (0); -} - -void -nandfs_inode_init(struct nandfs_inode *inode, uint16_t mode) -{ - struct timespec ts; - - vfs_timestamp(&ts); - - inode->i_blocks = 0; - inode->i_size = 0; - inode->i_ctime = ts.tv_sec; - inode->i_ctime_nsec = ts.tv_nsec; - inode->i_mtime = ts.tv_sec; - inode->i_mtime_nsec = ts.tv_nsec; - inode->i_mode = mode; - inode->i_links_count = 1; - if (S_ISDIR(mode)) - inode->i_links_count = 2; - inode->i_flags = 0; - - inode->i_special = 0; - memset(inode->i_db, 0, sizeof(inode->i_db)); - memset(inode->i_ib, 0, sizeof(inode->i_ib)); -} - -void -nandfs_inode_destroy(struct nandfs_inode *inode) -{ - - MPASS(inode->i_blocks == 0); - bzero(inode, sizeof(*inode)); -} - -int -nandfs_fs_full(struct nandfs_device *nffsdev) -{ - uint64_t space, bps; - - bps = nffsdev->nd_fsdata.f_blocks_per_segment; - space = (nffsdev->nd_clean_segs - 1) * bps; - - DPRINTF(BUF, ("%s: bufs:%jx space:%jx\n", __func__, - (uintmax_t)nffsdev->nd_dirty_bufs, (uintmax_t)space)); - - if (nffsdev->nd_dirty_bufs + (nffsdev->nd_segs_reserved * bps) >= space) - return (1); - - return (0); -} - -static int -_nandfs_dirty_buf(struct buf *bp, int dirty_meta, int force) -{ - struct nandfs_device *nffsdev; - struct nandfs_node *node; - uint64_t ino, bps; - - if (NANDFS_ISGATHERED(bp)) { - bqrelse(bp); - return (0); - } - if ((bp->b_flags & (B_MANAGED | B_DELWRI)) == (B_MANAGED | B_DELWRI)) { - bqrelse(bp); - return (0); - } - - node = VTON(bp->b_vp); - nffsdev = node->nn_nandfsdev; - DPRINTF(BUF, ("%s: buf:%p\n", __func__, bp)); - ino = node->nn_ino; - - if (nandfs_fs_full(nffsdev) && !NANDFS_SYS_NODE(ino) && !force) { - brelse(bp); - return (ENOSPC); - } - - bp->b_flags |= B_MANAGED; - bdwrite(bp); - - nandfs_dirty_bufs_increment(nffsdev); - - KASSERT((bp->b_vp), ("vp missing for bp")); - KASSERT((nandfs_vblk_get(bp) || ino == NANDFS_DAT_INO), - ("bp vblk is 0")); - - /* - * To maintain consistency of FS we need to force making - * meta buffers dirty, even if free space is low. - */ - if (dirty_meta && ino != NANDFS_GC_INO) - nandfs_bmap_dirty_blocks(VTON(bp->b_vp), bp, 1); - - bps = nffsdev->nd_fsdata.f_blocks_per_segment; - - if (nffsdev->nd_dirty_bufs >= (bps * nandfs_max_dirty_segs)) { - mtx_lock(&nffsdev->nd_sync_mtx); - if (nffsdev->nd_syncing == 0) { - DPRINTF(SYNC, ("%s: wakeup gc\n", __func__)); - nffsdev->nd_syncing = 1; - wakeup(&nffsdev->nd_syncing); - } - mtx_unlock(&nffsdev->nd_sync_mtx); - } - - return (0); -} - -int -nandfs_dirty_buf(struct buf *bp, int force) -{ - - return (_nandfs_dirty_buf(bp, 1, force)); -} - -int -nandfs_dirty_buf_meta(struct buf *bp, int force) -{ - - return (_nandfs_dirty_buf(bp, 0, force)); -} - -void -nandfs_undirty_buf_fsdev(struct nandfs_device *nffsdev, struct buf *bp) -{ - - BUF_ASSERT_HELD(bp); - - if (bp->b_flags & B_DELWRI) { - bp->b_flags &= ~(B_DELWRI|B_MANAGED); - nandfs_dirty_bufs_decrement(nffsdev); - } - /* - * Since it is now being written, we can clear its deferred write flag. - */ - bp->b_flags &= ~B_DEFERRED; - - brelse(bp); -} - -void -nandfs_undirty_buf(struct buf *bp) -{ - struct nandfs_node *node; - - node = VTON(bp->b_vp); - - nandfs_undirty_buf_fsdev(node->nn_nandfsdev, bp); -} - -void -nandfs_vblk_set(struct buf *bp, nandfs_daddr_t blocknr) -{ - - nandfs_daddr_t *vblk = (nandfs_daddr_t *)(&bp->b_fsprivate1); - *vblk = blocknr; -} - -nandfs_daddr_t -nandfs_vblk_get(struct buf *bp) -{ - - nandfs_daddr_t *vblk = (nandfs_daddr_t *)(&bp->b_fsprivate1); - return (*vblk); -} - -void -nandfs_buf_set(struct buf *bp, uint32_t bits) -{ - uintptr_t flags; - - flags = (uintptr_t)bp->b_fsprivate3; - flags |= (uintptr_t)bits; - bp->b_fsprivate3 = (void *)flags; -} - -void -nandfs_buf_clear(struct buf *bp, uint32_t bits) -{ - uintptr_t flags; - - flags = (uintptr_t)bp->b_fsprivate3; - flags &= ~(uintptr_t)bits; - bp->b_fsprivate3 = (void *)flags; -} - -int -nandfs_buf_check(struct buf *bp, uint32_t bits) -{ - uintptr_t flags; - - flags = (uintptr_t)bp->b_fsprivate3; - if (flags & bits) - return (1); - return (0); -} - -int -nandfs_erase(struct nandfs_device *fsdev, off_t offset, size_t size) -{ - DPRINTF(BLOCK, ("%s: performing erase at offset %jx size %zx\n", - __func__, offset, size)); - - MPASS(size % fsdev->nd_erasesize == 0); - - return (g_delete_data(fsdev->nd_gconsumer, offset, size)); -} - -int -nandfs_vop_islocked(struct vnode *vp) -{ - int islocked; - - islocked = VOP_ISLOCKED(vp); - return (islocked == LK_EXCLUSIVE || islocked == LK_SHARED); -} - -nandfs_daddr_t -nandfs_block_to_dblock(struct nandfs_device *fsdev, nandfs_lbn_t block) -{ - - return (btodb(block * fsdev->nd_blocksize)); -} diff --git a/sys/fs/nandfs/nandfs_subr.h b/sys/fs/nandfs/nandfs_subr.h deleted file mode 100644 index 36c2c9dc2ff2..000000000000 --- a/sys/fs/nandfs/nandfs_subr.h +++ /dev/null @@ -1,240 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf - * Copyright (c) 2008, 2009 Reinoud Zandijk - * 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, 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. - * - * From: NetBSD: nilfs_subr.h,v 1.1 2009/07/18 16:31:42 reinoud - * - * $FreeBSD$ - */ - -#ifndef _FS_NANDFS_NANDFS_SUBR_H_ -#define _FS_NANDFS_NANDFS_SUBR_H_ - -struct nandfs_mdt; - -struct nandfs_alloc_request -{ - uint64_t entrynum; - struct buf *bp_desc; - struct buf *bp_bitmap; - struct buf *bp_entry; -}; - -/* Segment creation */ -void nandfs_wakeup_wait_sync(struct nandfs_device *, int); -int nandfs_segment_constructor(struct nandfsmount *, int); -int nandfs_sync_file(struct vnode *); - -/* Basic calculators */ -uint64_t nandfs_get_segnum_of_block(struct nandfs_device *, nandfs_daddr_t); -void nandfs_get_segment_range(struct nandfs_device *, uint64_t, uint64_t *, - uint64_t *); -void nandfs_calc_mdt_consts(struct nandfs_device *, struct nandfs_mdt *, int); - -/* Log reading / volume helpers */ -int nandfs_search_super_root(struct nandfs_device *); - -/* Reading */ -int nandfs_dev_bread(struct nandfs_device *, nandfs_daddr_t, struct ucred *, - int, struct buf **); -int nandfs_bread(struct nandfs_node *, nandfs_lbn_t, struct ucred *, int, - struct buf **); -int nandfs_bread_meta(struct nandfs_node *, nandfs_lbn_t, struct ucred *, int, - struct buf **); -int nandfs_bdestroy(struct nandfs_node *, nandfs_daddr_t); -int nandfs_bcreate(struct nandfs_node *, nandfs_lbn_t, struct ucred *, int, - struct buf **); -int nandfs_bcreate_meta(struct nandfs_node *, nandfs_lbn_t, struct ucred *, - int, struct buf **); -int nandfs_bread_create(struct nandfs_node *, nandfs_lbn_t, struct ucred *, - int, struct buf **); - -/* vtop operations */ -int nandfs_vtop(struct nandfs_node *, nandfs_daddr_t, nandfs_daddr_t *); - -/* Node action implementators */ -int nandfs_vinit(struct vnode *, uint64_t); -int nandfs_get_node(struct nandfsmount *, uint64_t, struct nandfs_node **); -int nandfs_get_node_raw(struct nandfs_device *, struct nandfsmount *, uint64_t, - struct nandfs_inode *, struct nandfs_node **); -void nandfs_dispose_node(struct nandfs_node **); - -void nandfs_itimes(struct vnode *); -int nandfs_lookup_name_in_dir(struct vnode *, const char *, int, uint64_t *, - int *, uint64_t *); -int nandfs_create_node(struct vnode *, struct vnode **, struct vattr *, - struct componentname *); -void nandfs_delete_node(struct nandfs_node *); - -int nandfs_chsize(struct vnode *, u_quad_t, struct ucred *); -int nandfs_dir_detach(struct nandfsmount *, struct nandfs_node *, - struct nandfs_node *, struct componentname *); -int nandfs_dir_attach(struct nandfsmount *, struct nandfs_node *, - struct nandfs_node *, struct vattr *, struct componentname *); - -int nandfs_dirty_buf(struct buf *, int); -int nandfs_dirty_buf_meta(struct buf *, int); -int nandfs_fs_full(struct nandfs_device *); -void nandfs_undirty_buf_fsdev(struct nandfs_device *, struct buf *); -void nandfs_undirty_buf(struct buf *); - -void nandfs_clear_buf(struct buf *); -void nandfs_buf_set(struct buf *, uint32_t); -void nandfs_buf_clear(struct buf *, uint32_t); -int nandfs_buf_check(struct buf *, uint32_t); - -int nandfs_find_free_entry(struct nandfs_mdt *, struct nandfs_node *, - struct nandfs_alloc_request *); -int nandfs_find_entry(struct nandfs_mdt *, struct nandfs_node *, - struct nandfs_alloc_request *); -int nandfs_alloc_entry(struct nandfs_mdt *, struct nandfs_alloc_request *); -void nandfs_abort_entry(struct nandfs_alloc_request *); -int nandfs_free_entry(struct nandfs_mdt *, struct nandfs_alloc_request *); -int nandfs_get_entry_block(struct nandfs_mdt *, struct nandfs_node *, - struct nandfs_alloc_request *, uint32_t *, int); - -/* Inode management. */ -int nandfs_node_create(struct nandfsmount *, struct nandfs_node **, uint16_t); -int nandfs_node_destroy(struct nandfs_node *); -int nandfs_node_update(struct nandfs_node *); -int nandfs_get_node_entry(struct nandfsmount *, struct nandfs_inode **, - uint64_t, struct buf **); -void nandfs_mdt_trans_blk(struct nandfs_mdt *, uint64_t, uint64_t *, - uint64_t *, nandfs_lbn_t *, uint32_t *); - -/* vblock management */ -void nandfs_mdt_trans(struct nandfs_mdt *, uint64_t, nandfs_lbn_t *, uint32_t *); -int nandfs_vblock_alloc(struct nandfs_device *, nandfs_daddr_t *); -int nandfs_vblock_end(struct nandfs_device *, nandfs_daddr_t); -int nandfs_vblock_assign(struct nandfs_device *, nandfs_daddr_t, - nandfs_lbn_t); -int nandfs_vblock_free(struct nandfs_device *, nandfs_daddr_t); - -/* Checkpoint management */ -int nandfs_get_checkpoint(struct nandfs_device *, struct nandfs_node *, - uint64_t); -int nandfs_set_checkpoint(struct nandfs_device *, struct nandfs_node *, - uint64_t, struct nandfs_inode *, uint64_t); - -/* Segment management */ -int nandfs_alloc_segment(struct nandfs_device *, uint64_t *); -int nandfs_update_segment(struct nandfs_device *, uint64_t, uint32_t); -int nandfs_free_segment(struct nandfs_device *, uint64_t); -int nandfs_clear_segment(struct nandfs_device *, uint64_t); -int nandfs_touch_segment(struct nandfs_device *, uint64_t); -int nandfs_markgc_segment(struct nandfs_device *, uint64_t); - -int nandfs_bmap_insert_block(struct nandfs_node *, nandfs_lbn_t, struct buf *); -int nandfs_bmap_update_block(struct nandfs_node *, struct buf *, nandfs_lbn_t); -int nandfs_bmap_update_dat(struct nandfs_node *, nandfs_daddr_t, struct buf *); -int nandfs_bmap_dirty_blocks(struct nandfs_node *, struct buf *, int); -int nandfs_bmap_truncate_mapping(struct nandfs_node *, nandfs_lbn_t, - nandfs_lbn_t); -int nandfs_bmap_lookup(struct nandfs_node *, nandfs_lbn_t, nandfs_daddr_t *); - -/* dirent */ -int nandfs_add_dirent(struct vnode *, uint64_t, char *, long, uint8_t); -int nandfs_remove_dirent(struct vnode *, struct nandfs_node *, - struct componentname *); -int nandfs_update_dirent(struct vnode *, struct nandfs_node *, - struct nandfs_node *); -int nandfs_init_dir(struct vnode *, uint64_t, uint64_t); -int nandfs_update_parent_dir(struct vnode *, uint64_t); - -void nandfs_vblk_set(struct buf *, nandfs_daddr_t); -nandfs_daddr_t nandfs_vblk_get(struct buf *); - -void nandfs_inode_init(struct nandfs_inode *, uint16_t); -void nandfs_inode_destroy(struct nandfs_inode *); - -/* ioctl */ -int nandfs_get_seg_stat(struct nandfs_device *, struct nandfs_seg_stat *); -int nandfs_chng_cpmode(struct nandfs_node *, struct nandfs_cpmode *); -int nandfs_get_cpinfo_ioctl(struct nandfs_node *, struct nandfs_argv *); -int nandfs_delete_cp(struct nandfs_node *, uint64_t start, uint64_t); -int nandfs_make_snap(struct nandfs_device *, uint64_t *); -int nandfs_delete_snap(struct nandfs_device *, uint64_t); -int nandfs_get_cpstat(struct nandfs_node *, struct nandfs_cpstat *); -int nandfs_get_segment_info_ioctl(struct nandfs_device *, struct nandfs_argv *); -int nandfs_get_dat_vinfo_ioctl(struct nandfs_device *, struct nandfs_argv *); -int nandfs_get_dat_bdescs_ioctl(struct nandfs_device *, struct nandfs_argv *); -int nandfs_get_fsinfo(struct nandfsmount *, struct nandfs_fsinfo *); - -int nandfs_get_cpinfo(struct nandfs_node *, uint64_t, uint16_t, - struct nandfs_cpinfo *, uint32_t, uint32_t *); - -nandfs_lbn_t nandfs_get_maxfilesize(struct nandfs_device *); - -int nandfs_write_superblock(struct nandfs_device *); - -extern int nandfs_sync_interval; -extern int nandfs_max_dirty_segs; -extern int nandfs_cps_between_sblocks; - -struct buf *nandfs_geteblk(int, int); - -void nandfs_dirty_bufs_increment(struct nandfs_device *); -void nandfs_dirty_bufs_decrement(struct nandfs_device *); - -int nandfs_start_cleaner(struct nandfs_device *); -int nandfs_stop_cleaner(struct nandfs_device *); - -int nandfs_segsum_valid(struct nandfs_segment_summary *); -int nandfs_load_segsum(struct nandfs_device *, nandfs_daddr_t, - struct nandfs_segment_summary *); -int nandfs_get_segment_info(struct nandfs_device *, struct nandfs_suinfo *, - uint32_t, uint64_t); -int nandfs_get_segment_info_filter(struct nandfs_device *, - struct nandfs_suinfo *, uint32_t, uint64_t, uint64_t *, uint32_t, uint32_t); -int nandfs_get_dat_vinfo(struct nandfs_device *, struct nandfs_vinfo *, - uint32_t); -int nandfs_get_dat_bdescs(struct nandfs_device *, struct nandfs_bdesc *, - uint32_t); - -#define NANDFS_VBLK_ASSIGNED 1 - -#define NANDFS_IS_INDIRECT(bp) ((bp)->b_lblkno < 0) - -int nandfs_erase(struct nandfs_device *, off_t, size_t); - -#define NANDFS_VOP_ISLOCKED(vp) nandfs_vop_islocked((vp)) -int nandfs_vop_islocked(struct vnode *vp); - -nandfs_daddr_t nandfs_block_to_dblock(struct nandfs_device *, nandfs_lbn_t); - -#define DEBUG_MODE -#if defined(DEBUG_MODE) -#define nandfs_error panic -#define nandfs_warning printf -#elif defined(TEST_MODE) -#define nandfs_error printf -#define nandfs_warning printf -#else -#define nandfs_error(...) -#define nandfs_warning(...) -#endif - -#endif /* !_FS_NANDFS_NANDFS_SUBR_H_ */ diff --git a/sys/fs/nandfs/nandfs_sufile.c b/sys/fs/nandfs/nandfs_sufile.c deleted file mode 100644 index 5276008de096..000000000000 --- a/sys/fs/nandfs/nandfs_sufile.c +++ /dev/null @@ -1,571 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#define SU_USAGE_OFF(bp, offset) \ - ((struct nandfs_segment_usage *)((bp)->b_data + offset)) - -static int -nandfs_seg_usage_blk_offset(struct nandfs_device *fsdev, uint64_t seg, - uint64_t *blk, uint64_t *offset) -{ - uint64_t off; - uint16_t seg_size; - - seg_size = fsdev->nd_fsdata.f_segment_usage_size; - - off = roundup(sizeof(struct nandfs_sufile_header), seg_size); - off += (seg * seg_size); - - *blk = off / fsdev->nd_blocksize; - *offset = off % fsdev->nd_blocksize; - return (0); -} - -/* Alloc new segment */ -int -nandfs_alloc_segment(struct nandfs_device *fsdev, uint64_t *seg) -{ - struct nandfs_node *su_node; - struct nandfs_sufile_header *su_header; - struct nandfs_segment_usage *su_usage; - struct buf *bp_header, *bp; - uint64_t blk, vblk, offset, i, rest, nsegments; - uint16_t seg_size; - int error, found; - - seg_size = fsdev->nd_fsdata.f_segment_usage_size; - nsegments = fsdev->nd_fsdata.f_nsegments; - - su_node = fsdev->nd_su_node; - ASSERT_VOP_LOCKED(NTOV(su_node), __func__); - - /* Read header buffer */ - error = nandfs_bread(su_node, 0, NOCRED, 0, &bp_header); - if (error) { - brelse(bp_header); - return (error); - } - - su_header = (struct nandfs_sufile_header *)bp_header->b_data; - - /* Get last allocated segment */ - i = su_header->sh_last_alloc + 1; - - found = 0; - bp = NULL; - while (!found) { - nandfs_seg_usage_blk_offset(fsdev, i, &blk, &offset); - if(blk != 0) { - error = nandfs_bmap_lookup(su_node, blk, &vblk); - if (error) { - nandfs_error("%s: cannot find vblk for blk " - "blk:%jx\n", __func__, blk); - return (error); - } - if (vblk) - error = nandfs_bread(su_node, blk, NOCRED, 0, - &bp); - else - error = nandfs_bcreate(su_node, blk, NOCRED, 0, - &bp); - if (error) { - nandfs_error("%s: cannot create/read " - "vblk:%jx\n", __func__, vblk); - if (bp) - brelse(bp); - return (error); - } - - su_usage = SU_USAGE_OFF(bp, offset); - } else { - su_usage = SU_USAGE_OFF(bp_header, offset); - bp = bp_header; - } - - rest = (fsdev->nd_blocksize - offset) / seg_size; - /* Go through all su usage in block */ - while (rest) { - /* When last check start from beginning */ - if (i == nsegments) - break; - - if (!su_usage->su_flags) { - su_usage->su_flags = 1; - found = 1; - break; - } - su_usage++; - i++; - - /* If all checked return error */ - if (i == su_header->sh_last_alloc) { - DPRINTF(SEG, ("%s: cannot allocate segment \n", - __func__)); - brelse(bp_header); - if (blk != 0) - brelse(bp); - return (1); - } - rest--; - } - if (!found) { - /* Otherwise read another block */ - if (blk != 0) - brelse(bp); - if (i == nsegments) { - blk = 0; - i = 0; - } else - blk++; - offset = 0; - } - } - - if (found) { - *seg = i; - su_header->sh_last_alloc = i; - su_header->sh_ncleansegs--; - su_header->sh_ndirtysegs++; - - fsdev->nd_super.s_free_blocks_count = su_header->sh_ncleansegs * - fsdev->nd_fsdata.f_blocks_per_segment; - fsdev->nd_clean_segs--; - - /* - * It is mostly called from syncer() so we want to force - * making buf dirty. - */ - error = nandfs_dirty_buf(bp_header, 1); - if (error) { - if (bp && bp != bp_header) - brelse(bp); - return (error); - } - if (bp && bp != bp_header) - nandfs_dirty_buf(bp, 1); - - DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)i)); - - return (0); - } - - DPRINTF(SEG, ("%s: failed\n", __func__)); - - return (1); -} - -/* - * Make buffer dirty, it will be updated soon but first it need to be - * gathered by syncer. - */ -int -nandfs_touch_segment(struct nandfs_device *fsdev, uint64_t seg) -{ - struct nandfs_node *su_node; - struct buf *bp; - uint64_t blk, offset; - int error; - - su_node = fsdev->nd_su_node; - ASSERT_VOP_LOCKED(NTOV(su_node), __func__); - - nandfs_seg_usage_blk_offset(fsdev, seg, &blk, &offset); - - error = nandfs_bread(su_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - nandfs_error("%s: cannot preallocate new segment\n", __func__); - return (error); - } else - nandfs_dirty_buf(bp, 1); - - DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)seg)); - return (error); -} - -/* Update block count of segment */ -int -nandfs_update_segment(struct nandfs_device *fsdev, uint64_t seg, uint32_t nblks) -{ - struct nandfs_node *su_node; - struct nandfs_segment_usage *su_usage; - struct buf *bp; - uint64_t blk, offset; - int error; - - su_node = fsdev->nd_su_node; - ASSERT_VOP_LOCKED(NTOV(su_node), __func__); - - nandfs_seg_usage_blk_offset(fsdev, seg, &blk, &offset); - - error = nandfs_bread(su_node, blk, NOCRED, 0, &bp); - if (error) { - nandfs_error("%s: read block:%jx to update\n", - __func__, blk); - brelse(bp); - return (error); - } - - su_usage = SU_USAGE_OFF(bp, offset); - su_usage->su_lastmod = fsdev->nd_ts.tv_sec; - su_usage->su_flags = NANDFS_SEGMENT_USAGE_DIRTY; - su_usage->su_nblocks += nblks; - - DPRINTF(SEG, ("%s: seg:%#jx inc:%#x cur:%#x\n", __func__, - (uintmax_t)seg, nblks, su_usage->su_nblocks)); - - nandfs_dirty_buf(bp, 1); - - return (0); -} - -/* Make segment free */ -int -nandfs_free_segment(struct nandfs_device *fsdev, uint64_t seg) -{ - struct nandfs_node *su_node; - struct nandfs_sufile_header *su_header; - struct nandfs_segment_usage *su_usage; - struct buf *bp_header, *bp; - uint64_t blk, offset; - int error; - - su_node = fsdev->nd_su_node; - ASSERT_VOP_LOCKED(NTOV(su_node), __func__); - - /* Read su header */ - error = nandfs_bread(su_node, 0, NOCRED, 0, &bp_header); - if (error) { - brelse(bp_header); - return (error); - } - - su_header = (struct nandfs_sufile_header *)bp_header->b_data; - nandfs_seg_usage_blk_offset(fsdev, seg, &blk, &offset); - - /* Read su usage block if other than su header block */ - if (blk != 0) { - error = nandfs_bread(su_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - brelse(bp_header); - return (error); - } - } else - bp = bp_header; - - /* Reset su usage data */ - su_usage = SU_USAGE_OFF(bp, offset); - su_usage->su_lastmod = fsdev->nd_ts.tv_sec; - su_usage->su_nblocks = 0; - su_usage->su_flags = 0; - - /* Update clean/dirty counter in header */ - su_header->sh_ncleansegs++; - su_header->sh_ndirtysegs--; - - /* - * Make buffers dirty, called by cleaner - * so force dirty even if no much space left - * on device - */ - nandfs_dirty_buf(bp_header, 1); - if (bp != bp_header) - nandfs_dirty_buf(bp, 1); - - /* Update free block count */ - fsdev->nd_super.s_free_blocks_count = su_header->sh_ncleansegs * - fsdev->nd_fsdata.f_blocks_per_segment; - fsdev->nd_clean_segs++; - - DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)seg)); - - return (0); -} - -static int -nandfs_bad_segment(struct nandfs_device *fsdev, uint64_t seg) -{ - struct nandfs_node *su_node; - struct nandfs_segment_usage *su_usage; - struct buf *bp; - uint64_t blk, offset; - int error; - - su_node = fsdev->nd_su_node; - ASSERT_VOP_LOCKED(NTOV(su_node), __func__); - - nandfs_seg_usage_blk_offset(fsdev, seg, &blk, &offset); - - error = nandfs_bread(su_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (error); - } - - su_usage = SU_USAGE_OFF(bp, offset); - su_usage->su_lastmod = fsdev->nd_ts.tv_sec; - su_usage->su_flags = NANDFS_SEGMENT_USAGE_ERROR; - - DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)seg)); - - nandfs_dirty_buf(bp, 1); - - return (0); -} - -int -nandfs_markgc_segment(struct nandfs_device *fsdev, uint64_t seg) -{ - struct nandfs_node *su_node; - struct nandfs_segment_usage *su_usage; - struct buf *bp; - uint64_t blk, offset; - int error; - - su_node = fsdev->nd_su_node; - - VOP_LOCK(NTOV(su_node), LK_EXCLUSIVE); - - nandfs_seg_usage_blk_offset(fsdev, seg, &blk, &offset); - - error = nandfs_bread(su_node, blk, NOCRED, 0, &bp); - if (error) { - brelse(bp); - VOP_UNLOCK(NTOV(su_node), 0); - return (error); - } - - su_usage = SU_USAGE_OFF(bp, offset); - MPASS((su_usage->su_flags & NANDFS_SEGMENT_USAGE_GC) == 0); - su_usage->su_flags |= NANDFS_SEGMENT_USAGE_GC; - - brelse(bp); - VOP_UNLOCK(NTOV(su_node), 0); - - DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)seg)); - - return (0); -} - -int -nandfs_clear_segment(struct nandfs_device *fsdev, uint64_t seg) -{ - uint64_t offset, segsize; - uint32_t bps, bsize; - int error = 0; - - bps = fsdev->nd_fsdata.f_blocks_per_segment; - bsize = fsdev->nd_blocksize; - segsize = bsize * bps; - nandfs_get_segment_range(fsdev, seg, &offset, NULL); - offset *= bsize; - - DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)seg)); - - /* Erase it and mark it bad when fail */ - if (nandfs_erase(fsdev, offset, segsize)) - error = nandfs_bad_segment(fsdev, seg); - - if (error) - return (error); - - /* Mark it free */ - error = nandfs_free_segment(fsdev, seg); - - return (error); -} - -int -nandfs_get_seg_stat(struct nandfs_device *nandfsdev, - struct nandfs_seg_stat *nss) -{ - struct nandfs_sufile_header *suhdr; - struct nandfs_node *su_node; - struct buf *bp; - int err; - - su_node = nandfsdev->nd_su_node; - - NANDFS_WRITELOCK(nandfsdev); - VOP_LOCK(NTOV(su_node), LK_SHARED); - err = nandfs_bread(nandfsdev->nd_su_node, 0, NOCRED, 0, &bp); - if (err) { - brelse(bp); - VOP_UNLOCK(NTOV(su_node), 0); - NANDFS_WRITEUNLOCK(nandfsdev); - return (-1); - } - - suhdr = (struct nandfs_sufile_header *)bp->b_data; - nss->nss_nsegs = nandfsdev->nd_fsdata.f_nsegments; - nss->nss_ncleansegs = suhdr->sh_ncleansegs; - nss->nss_ndirtysegs = suhdr->sh_ndirtysegs; - nss->nss_ctime = 0; - nss->nss_nongc_ctime = nandfsdev->nd_ts.tv_sec; - nss->nss_prot_seq = nandfsdev->nd_seg_sequence; - - brelse(bp); - VOP_UNLOCK(NTOV(su_node), 0); - - NANDFS_WRITEUNLOCK(nandfsdev); - - return (0); -} - -int -nandfs_get_segment_info_ioctl(struct nandfs_device *fsdev, - struct nandfs_argv *nargv) -{ - struct nandfs_suinfo *nsi; - int error; - - if (nargv->nv_nmembs > NANDFS_SEGMENTS_MAX) - return (EINVAL); - - nsi = malloc(sizeof(struct nandfs_suinfo) * nargv->nv_nmembs, - M_NANDFSTEMP, M_WAITOK | M_ZERO); - - error = nandfs_get_segment_info(fsdev, nsi, nargv->nv_nmembs, - nargv->nv_index); - - if (error == 0) - error = copyout(nsi, (void *)(uintptr_t)nargv->nv_base, - sizeof(struct nandfs_suinfo) * nargv->nv_nmembs); - - free(nsi, M_NANDFSTEMP); - return (error); -} - -int -nandfs_get_segment_info(struct nandfs_device *fsdev, struct nandfs_suinfo *nsi, - uint32_t nmembs, uint64_t segment) -{ - - return (nandfs_get_segment_info_filter(fsdev, nsi, nmembs, segment, - NULL, 0, 0)); -} - -int -nandfs_get_segment_info_filter(struct nandfs_device *fsdev, - struct nandfs_suinfo *nsi, uint32_t nmembs, uint64_t segment, - uint64_t *nsegs, uint32_t filter, uint32_t nfilter) -{ - struct nandfs_segment_usage *su; - struct nandfs_node *su_node; - struct buf *bp; - uint64_t curr, blocknr, blockoff, i; - uint32_t flags; - int err = 0; - - curr = ~(0); - - lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL); - su_node = fsdev->nd_su_node; - - VOP_LOCK(NTOV(su_node), LK_SHARED); - - bp = NULL; - if (nsegs != NULL) - *nsegs = 0; - for (i = 0; i < nmembs; segment++) { - if (segment == fsdev->nd_fsdata.f_nsegments) - break; - - nandfs_seg_usage_blk_offset(fsdev, segment, &blocknr, - &blockoff); - - if (i == 0 || curr != blocknr) { - if (bp != NULL) - brelse(bp); - err = nandfs_bread(su_node, blocknr, NOCRED, - 0, &bp); - if (err) { - goto out; - } - curr = blocknr; - } - - su = SU_USAGE_OFF(bp, blockoff); - flags = su->su_flags; - if (segment == fsdev->nd_seg_num || - segment == fsdev->nd_next_seg_num) - flags |= NANDFS_SEGMENT_USAGE_ACTIVE; - - if (nfilter != 0 && (flags & nfilter) != 0) - continue; - if (filter != 0 && (flags & filter) == 0) - continue; - - nsi->nsi_num = segment; - nsi->nsi_lastmod = su->su_lastmod; - nsi->nsi_blocks = su->su_nblocks; - nsi->nsi_flags = flags; - nsi++; - i++; - if (nsegs != NULL) - (*nsegs)++; - } - -out: - if (bp != NULL) - brelse(bp); - VOP_UNLOCK(NTOV(su_node), 0); - lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL); - - return (err); -} diff --git a/sys/fs/nandfs/nandfs_vfsops.c b/sys/fs/nandfs/nandfs_vfsops.c deleted file mode 100644 index f703044728ef..000000000000 --- a/sys/fs/nandfs/nandfs_vfsops.c +++ /dev/null @@ -1,1601 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf - * Copyright (c) 2008, 2009 Reinoud Zandijk - * 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, 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. - * - * From: NetBSD: nilfs_vfsops.c,v 1.1 2009/07/18 16:31:42 reinoud Exp - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include - -static MALLOC_DEFINE(M_NANDFSMNT, "nandfs_mount", "NANDFS mount structure"); - -#define NANDFS_SET_SYSTEMFILE(vp) { \ - (vp)->v_vflag |= VV_SYSTEM; \ - vref(vp); \ - vput(vp); } - -#define NANDFS_UNSET_SYSTEMFILE(vp) { \ - VOP_LOCK(vp, LK_EXCLUSIVE); \ - MPASS(vp->v_bufobj.bo_dirty.bv_cnt == 0); \ - (vp)->v_vflag &= ~VV_SYSTEM; \ - vgone(vp); \ - vput(vp); } - -/* Globals */ -struct _nandfs_devices nandfs_devices; - -/* Parameters */ -int nandfs_verbose = 0; - -static void -nandfs_tunable_init(void *arg) -{ - - TUNABLE_INT_FETCH("vfs.nandfs.verbose", &nandfs_verbose); -} -SYSINIT(nandfs_tunables, SI_SUB_VFS, SI_ORDER_ANY, nandfs_tunable_init, NULL); - -static SYSCTL_NODE(_vfs, OID_AUTO, nandfs, CTLFLAG_RD, 0, "NAND filesystem"); -static SYSCTL_NODE(_vfs_nandfs, OID_AUTO, mount, CTLFLAG_RD, 0, - "NANDFS mountpoints"); -SYSCTL_INT(_vfs_nandfs, OID_AUTO, verbose, CTLFLAG_RW, &nandfs_verbose, 0, ""); - -#define NANDFS_CONSTR_INTERVAL 5 -int nandfs_sync_interval = NANDFS_CONSTR_INTERVAL; /* sync every 5 seconds */ -SYSCTL_UINT(_vfs_nandfs, OID_AUTO, sync_interval, CTLFLAG_RW, - &nandfs_sync_interval, 0, ""); - -#define NANDFS_MAX_DIRTY_SEGS 5 -int nandfs_max_dirty_segs = NANDFS_MAX_DIRTY_SEGS; /* sync when 5 dirty seg */ -SYSCTL_UINT(_vfs_nandfs, OID_AUTO, max_dirty_segs, CTLFLAG_RW, - &nandfs_max_dirty_segs, 0, ""); - -#define NANDFS_CPS_BETWEEN_SBLOCKS 5 -int nandfs_cps_between_sblocks = NANDFS_CPS_BETWEEN_SBLOCKS; /* write superblock every 5 checkpoints */ -SYSCTL_UINT(_vfs_nandfs, OID_AUTO, cps_between_sblocks, CTLFLAG_RW, - &nandfs_cps_between_sblocks, 0, ""); - -#define NANDFS_CLEANER_ENABLE 1 -int nandfs_cleaner_enable = NANDFS_CLEANER_ENABLE; -SYSCTL_UINT(_vfs_nandfs, OID_AUTO, cleaner_enable, CTLFLAG_RW, - &nandfs_cleaner_enable, 0, ""); - -#define NANDFS_CLEANER_INTERVAL 5 -int nandfs_cleaner_interval = NANDFS_CLEANER_INTERVAL; -SYSCTL_UINT(_vfs_nandfs, OID_AUTO, cleaner_interval, CTLFLAG_RW, - &nandfs_cleaner_interval, 0, ""); - -#define NANDFS_CLEANER_SEGMENTS 5 -int nandfs_cleaner_segments = NANDFS_CLEANER_SEGMENTS; -SYSCTL_UINT(_vfs_nandfs, OID_AUTO, cleaner_segments, CTLFLAG_RW, - &nandfs_cleaner_segments, 0, ""); - -static int nandfs_mountfs(struct vnode *devvp, struct mount *mp); -static vfs_mount_t nandfs_mount; -static vfs_root_t nandfs_root; -static vfs_statfs_t nandfs_statfs; -static vfs_unmount_t nandfs_unmount; -static vfs_vget_t nandfs_vget; -static vfs_sync_t nandfs_sync; -static const char *nandfs_opts[] = { - "snap", "from", "noatime", NULL -}; - -/* System nodes */ -static int -nandfs_create_system_nodes(struct nandfs_device *nandfsdev) -{ - int error; - - error = nandfs_get_node_raw(nandfsdev, NULL, NANDFS_DAT_INO, - &nandfsdev->nd_super_root.sr_dat, &nandfsdev->nd_dat_node); - if (error) - goto errorout; - - error = nandfs_get_node_raw(nandfsdev, NULL, NANDFS_CPFILE_INO, - &nandfsdev->nd_super_root.sr_cpfile, &nandfsdev->nd_cp_node); - if (error) - goto errorout; - - error = nandfs_get_node_raw(nandfsdev, NULL, NANDFS_SUFILE_INO, - &nandfsdev->nd_super_root.sr_sufile, &nandfsdev->nd_su_node); - if (error) - goto errorout; - - error = nandfs_get_node_raw(nandfsdev, NULL, NANDFS_GC_INO, - NULL, &nandfsdev->nd_gc_node); - if (error) - goto errorout; - - NANDFS_SET_SYSTEMFILE(NTOV(nandfsdev->nd_dat_node)); - NANDFS_SET_SYSTEMFILE(NTOV(nandfsdev->nd_cp_node)); - NANDFS_SET_SYSTEMFILE(NTOV(nandfsdev->nd_su_node)); - NANDFS_SET_SYSTEMFILE(NTOV(nandfsdev->nd_gc_node)); - - DPRINTF(VOLUMES, ("System vnodes: dat: %p cp: %p su: %p\n", - NTOV(nandfsdev->nd_dat_node), NTOV(nandfsdev->nd_cp_node), - NTOV(nandfsdev->nd_su_node))); - return (0); - -errorout: - nandfs_dispose_node(&nandfsdev->nd_gc_node); - nandfs_dispose_node(&nandfsdev->nd_dat_node); - nandfs_dispose_node(&nandfsdev->nd_cp_node); - nandfs_dispose_node(&nandfsdev->nd_su_node); - - return (error); -} - -static void -nandfs_release_system_nodes(struct nandfs_device *nandfsdev) -{ - - if (!nandfsdev) - return; - if (nandfsdev->nd_refcnt > 0) - return; - - if (nandfsdev->nd_gc_node) - NANDFS_UNSET_SYSTEMFILE(NTOV(nandfsdev->nd_gc_node)); - if (nandfsdev->nd_dat_node) - NANDFS_UNSET_SYSTEMFILE(NTOV(nandfsdev->nd_dat_node)); - if (nandfsdev->nd_cp_node) - NANDFS_UNSET_SYSTEMFILE(NTOV(nandfsdev->nd_cp_node)); - if (nandfsdev->nd_su_node) - NANDFS_UNSET_SYSTEMFILE(NTOV(nandfsdev->nd_su_node)); -} - -static int -nandfs_check_fsdata_crc(struct nandfs_fsdata *fsdata) -{ - uint32_t fsdata_crc, comp_crc; - - if (fsdata->f_magic != NANDFS_FSDATA_MAGIC) - return (0); - - /* Preserve CRC */ - fsdata_crc = fsdata->f_sum; - - /* Calculate */ - fsdata->f_sum = (0); - comp_crc = crc32((uint8_t *)fsdata, fsdata->f_bytes); - - /* Restore */ - fsdata->f_sum = fsdata_crc; - - /* Check CRC */ - return (fsdata_crc == comp_crc); -} - -static int -nandfs_check_superblock_crc(struct nandfs_fsdata *fsdata, - struct nandfs_super_block *super) -{ - uint32_t super_crc, comp_crc; - - /* Check super block magic */ - if (super->s_magic != NANDFS_SUPER_MAGIC) - return (0); - - /* Preserve CRC */ - super_crc = super->s_sum; - - /* Calculate */ - super->s_sum = (0); - comp_crc = crc32((uint8_t *)super, fsdata->f_sbbytes); - - /* Restore */ - super->s_sum = super_crc; - - /* Check CRC */ - return (super_crc == comp_crc); -} - -static void -nandfs_calc_superblock_crc(struct nandfs_fsdata *fsdata, - struct nandfs_super_block *super) -{ - uint32_t comp_crc; - - /* Calculate */ - super->s_sum = 0; - comp_crc = crc32((uint8_t *)super, fsdata->f_sbbytes); - - /* Restore */ - super->s_sum = comp_crc; -} - -static int -nandfs_is_empty(u_char *area, int size) -{ - int i; - - for (i = 0; i < size; i++) - if (area[i] != 0xff) - return (0); - - return (1); -} - -static __inline int -nandfs_sblocks_in_esize(struct nandfs_device *fsdev) -{ - - return ((fsdev->nd_erasesize - NANDFS_SBLOCK_OFFSET_BYTES) / - sizeof(struct nandfs_super_block)); -} - -static __inline int -nandfs_max_sblocks(struct nandfs_device *fsdev) -{ - - return (NANDFS_NFSAREAS * nandfs_sblocks_in_esize(fsdev)); -} - -static __inline int -nandfs_sblocks_in_block(struct nandfs_device *fsdev) -{ - - return (fsdev->nd_devblocksize / sizeof(struct nandfs_super_block)); -} - -#if 0 -static __inline int -nandfs_sblocks_in_first_block(struct nandfs_device *fsdev) -{ - int n; - - n = nandfs_sblocks_in_block(fsdev) - - NANDFS_SBLOCK_OFFSET_BYTES / sizeof(struct nandfs_super_block); - if (n < 0) - n = 0; - - return (n); -} -#endif - -static int -nandfs_write_superblock_at(struct nandfs_device *fsdev, - struct nandfs_fsarea *fstp) -{ - struct nandfs_super_block *super, *supert; - struct buf *bp; - int sb_per_sector, sbs_in_fsd, read_block; - int index, pos, error; - off_t offset; - - DPRINTF(SYNC, ("%s: last_used %d nandfs_sblocks_in_esize %d\n", - __func__, fstp->last_used, nandfs_sblocks_in_esize(fsdev))); - if (fstp->last_used == nandfs_sblocks_in_esize(fsdev) - 1) - index = 0; - else - index = fstp->last_used + 1; - - super = &fsdev->nd_super; - supert = NULL; - - sb_per_sector = nandfs_sblocks_in_block(fsdev); - sbs_in_fsd = sizeof(struct nandfs_fsdata) / - sizeof(struct nandfs_super_block); - index += sbs_in_fsd; - offset = fstp->offset; - - DPRINTF(SYNC, ("%s: offset %#jx s_last_pseg %#jx s_last_cno %#jx " - "s_last_seq %#jx wtime %jd index %d\n", __func__, offset, - super->s_last_pseg, super->s_last_cno, super->s_last_seq, - super->s_wtime, index)); - - read_block = btodb(offset + rounddown(index, sb_per_sector) * - sizeof(struct nandfs_super_block)); - - DPRINTF(SYNC, ("%s: read_block %#x\n", __func__, read_block)); - - if (index == sbs_in_fsd) { - error = nandfs_erase(fsdev, offset, fsdev->nd_erasesize); - if (error) - return (error); - - error = bread(fsdev->nd_devvp, btodb(offset), - fsdev->nd_devblocksize, NOCRED, &bp); - if (error) { - printf("NANDFS: couldn't read initial data: %d\n", - error); - brelse(bp); - return (error); - } - memcpy(bp->b_data, &fsdev->nd_fsdata, sizeof(fsdev->nd_fsdata)); - /* - * 0xff-out the rest. This bp could be cached, so potentially - * b_data contains stale super blocks. - * - * We don't mind cached bp since most of the time we just add - * super blocks to already 0xff-out b_data and don't need to - * perform actual read. - */ - if (fsdev->nd_devblocksize > sizeof(fsdev->nd_fsdata)) - memset(bp->b_data + sizeof(fsdev->nd_fsdata), 0xff, - fsdev->nd_devblocksize - sizeof(fsdev->nd_fsdata)); - error = bwrite(bp); - if (error) { - printf("NANDFS: cannot rewrite initial data at %jx\n", - offset); - return (error); - } - } - - error = bread(fsdev->nd_devvp, read_block, fsdev->nd_devblocksize, - NOCRED, &bp); - if (error) { - brelse(bp); - return (error); - } - - supert = (struct nandfs_super_block *)(bp->b_data); - pos = index % sb_per_sector; - - DPRINTF(SYNC, ("%s: storing at %d\n", __func__, pos)); - memcpy(&supert[pos], super, sizeof(struct nandfs_super_block)); - - /* - * See comment above in code that performs erase. - */ - if (pos == 0) - memset(&supert[1], 0xff, - (sb_per_sector - 1) * sizeof(struct nandfs_super_block)); - - error = bwrite(bp); - if (error) { - printf("NANDFS: cannot update superblock at %jx\n", offset); - return (error); - } - - DPRINTF(SYNC, ("%s: fstp->last_used %d -> %d\n", __func__, - fstp->last_used, index - sbs_in_fsd)); - fstp->last_used = index - sbs_in_fsd; - - return (0); -} - -int -nandfs_write_superblock(struct nandfs_device *fsdev) -{ - struct nandfs_super_block *super; - struct timespec ts; - int error; - int i, j; - - vfs_timestamp(&ts); - - super = &fsdev->nd_super; - - super->s_last_pseg = fsdev->nd_last_pseg; - super->s_last_cno = fsdev->nd_last_cno; - super->s_last_seq = fsdev->nd_seg_sequence; - super->s_wtime = ts.tv_sec; - - nandfs_calc_superblock_crc(&fsdev->nd_fsdata, super); - - error = 0; - for (i = 0, j = fsdev->nd_last_fsarea; i < NANDFS_NFSAREAS; - i++, j = (j + 1 % NANDFS_NFSAREAS)) { - if (fsdev->nd_fsarea[j].flags & NANDFS_FSSTOR_FAILED) { - DPRINTF(SYNC, ("%s: skipping %d\n", __func__, j)); - continue; - } - error = nandfs_write_superblock_at(fsdev, &fsdev->nd_fsarea[j]); - if (error) { - printf("NANDFS: writing superblock at offset %d failed:" - "%d\n", j * fsdev->nd_erasesize, error); - fsdev->nd_fsarea[j].flags |= NANDFS_FSSTOR_FAILED; - } else - break; - } - - if (i == NANDFS_NFSAREAS) { - printf("NANDFS: superblock was not written\n"); - /* - * TODO: switch to read-only? - */ - return (error); - } else - fsdev->nd_last_fsarea = (j + 1) % NANDFS_NFSAREAS; - - return (0); -} - -static int -nandfs_select_fsdata(struct nandfs_device *fsdev, - struct nandfs_fsdata *fsdatat, struct nandfs_fsdata **fsdata, int nfsds) -{ - int i; - - *fsdata = NULL; - for (i = 0; i < nfsds; i++) { - DPRINTF(VOLUMES, ("%s: i %d f_magic %x f_crc %x\n", __func__, - i, fsdatat[i].f_magic, fsdatat[i].f_sum)); - if (!nandfs_check_fsdata_crc(&fsdatat[i])) - continue; - *fsdata = &fsdatat[i]; - break; - } - - return (*fsdata != NULL ? 0 : EINVAL); -} - -static int -nandfs_select_sb(struct nandfs_device *fsdev, - struct nandfs_super_block *supert, struct nandfs_super_block **super, - int nsbs) -{ - int i; - - *super = NULL; - for (i = 0; i < nsbs; i++) { - if (!nandfs_check_superblock_crc(&fsdev->nd_fsdata, &supert[i])) - continue; - DPRINTF(SYNC, ("%s: i %d s_last_cno %jx s_magic %x " - "s_wtime %jd\n", __func__, i, supert[i].s_last_cno, - supert[i].s_magic, supert[i].s_wtime)); - if (*super == NULL || supert[i].s_last_cno > - (*super)->s_last_cno) - *super = &supert[i]; - } - - return (*super != NULL ? 0 : EINVAL); -} - -static int -nandfs_read_structures_at(struct nandfs_device *fsdev, - struct nandfs_fsarea *fstp, struct nandfs_fsdata *fsdata, - struct nandfs_super_block *super) -{ - struct nandfs_super_block *tsuper, *tsuperd; - struct buf *bp; - int error, read_size; - int i; - int offset; - - offset = fstp->offset; - - if (fsdev->nd_erasesize > MAXBSIZE) - read_size = MAXBSIZE; - else - read_size = fsdev->nd_erasesize; - - error = bread(fsdev->nd_devvp, btodb(offset), read_size, NOCRED, &bp); - if (error) { - printf("couldn't read: %d\n", error); - brelse(bp); - fstp->flags |= NANDFS_FSSTOR_FAILED; - return (error); - } - - tsuper = super; - - memcpy(fsdata, bp->b_data, sizeof(struct nandfs_fsdata)); - memcpy(tsuper, (bp->b_data + sizeof(struct nandfs_fsdata)), - read_size - sizeof(struct nandfs_fsdata)); - brelse(bp); - - tsuper += (read_size - sizeof(struct nandfs_fsdata)) / - sizeof(struct nandfs_super_block); - - for (i = 1; i < fsdev->nd_erasesize / read_size; i++) { - error = bread(fsdev->nd_devvp, btodb(offset + i * read_size), - read_size, NOCRED, &bp); - if (error) { - printf("couldn't read: %d\n", error); - brelse(bp); - fstp->flags |= NANDFS_FSSTOR_FAILED; - return (error); - } - memcpy(tsuper, bp->b_data, read_size); - tsuper += read_size / sizeof(struct nandfs_super_block); - brelse(bp); - } - - tsuper -= 1; - fstp->last_used = nandfs_sblocks_in_esize(fsdev) - 1; - for (tsuperd = super - 1; (tsuper != tsuperd); tsuper -= 1) { - if (nandfs_is_empty((u_char *)tsuper, sizeof(*tsuper))) - fstp->last_used--; - else - break; - } - - DPRINTF(VOLUMES, ("%s: last_used %d\n", __func__, fstp->last_used)); - - return (0); -} - -static int -nandfs_read_structures(struct nandfs_device *fsdev) -{ - struct nandfs_fsdata *fsdata, *fsdatat; - struct nandfs_super_block *sblocks, *ssblock; - u_int nsbs, nfsds, i; - int error = 0; - int nrsbs; - - nfsds = NANDFS_NFSAREAS; - nsbs = nandfs_max_sblocks(fsdev); - - fsdatat = malloc(sizeof(struct nandfs_fsdata) * nfsds, M_NANDFSTEMP, - M_WAITOK | M_ZERO); - sblocks = malloc(sizeof(struct nandfs_super_block) * nsbs, M_NANDFSTEMP, - M_WAITOK | M_ZERO); - - nrsbs = 0; - for (i = 0; i < NANDFS_NFSAREAS; i++) { - fsdev->nd_fsarea[i].offset = i * fsdev->nd_erasesize; - error = nandfs_read_structures_at(fsdev, &fsdev->nd_fsarea[i], - &fsdatat[i], sblocks + nrsbs); - if (error) - continue; - nrsbs += (fsdev->nd_fsarea[i].last_used + 1); - if (fsdev->nd_fsarea[fsdev->nd_last_fsarea].last_used > - fsdev->nd_fsarea[i].last_used) - fsdev->nd_last_fsarea = i; - } - - if (nrsbs == 0) { - printf("nandfs: no valid superblocks found\n"); - error = EINVAL; - goto out; - } - - error = nandfs_select_fsdata(fsdev, fsdatat, &fsdata, nfsds); - if (error) - goto out; - memcpy(&fsdev->nd_fsdata, fsdata, sizeof(struct nandfs_fsdata)); - - error = nandfs_select_sb(fsdev, sblocks, &ssblock, nsbs); - if (error) - goto out; - - memcpy(&fsdev->nd_super, ssblock, sizeof(struct nandfs_super_block)); -out: - free(fsdatat, M_NANDFSTEMP); - free(sblocks, M_NANDFSTEMP); - - if (error == 0) - DPRINTF(VOLUMES, ("%s: selected sb with w_time %jd " - "last_pseg %#jx\n", __func__, fsdev->nd_super.s_wtime, - fsdev->nd_super.s_last_pseg)); - - return (error); -} - -static void -nandfs_unmount_base(struct nandfs_device *nandfsdev) -{ - int error; - - if (!nandfsdev) - return; - - /* Remove all our information */ - error = vinvalbuf(nandfsdev->nd_devvp, V_SAVE, 0, 0); - if (error) { - /* - * Flushing buffers failed when fs was umounting, can't do - * much now, just printf error and continue with umount. - */ - nandfs_error("%s(): error:%d when umounting FS\n", - __func__, error); - } - - /* Release the device's system nodes */ - nandfs_release_system_nodes(nandfsdev); -} - -static void -nandfs_get_ncleanseg(struct nandfs_device *nandfsdev) -{ - struct nandfs_seg_stat nss; - - nandfs_get_seg_stat(nandfsdev, &nss); - nandfsdev->nd_clean_segs = nss.nss_ncleansegs; - DPRINTF(VOLUMES, ("nandfs_mount: clean segs: %jx\n", - (uintmax_t)nandfsdev->nd_clean_segs)); -} - - -static int -nandfs_mount_base(struct nandfs_device *nandfsdev, struct mount *mp, - struct nandfs_args *args) -{ - uint32_t log_blocksize; - int error; - - /* Flush out any old buffers remaining from a previous use. */ - if ((error = vinvalbuf(nandfsdev->nd_devvp, V_SAVE, 0, 0))) - return (error); - - error = nandfs_read_structures(nandfsdev); - if (error) { - printf("nandfs: could not get valid filesystem structures\n"); - return (error); - } - - if (nandfsdev->nd_fsdata.f_rev_level != NANDFS_CURRENT_REV) { - printf("nandfs: unsupported file system revision: %d " - "(supported is %d).\n", nandfsdev->nd_fsdata.f_rev_level, - NANDFS_CURRENT_REV); - return (EINVAL); - } - - if (nandfsdev->nd_fsdata.f_erasesize != nandfsdev->nd_erasesize) { - printf("nandfs: erasesize mismatch (device %#x, fs %#x)\n", - nandfsdev->nd_erasesize, nandfsdev->nd_fsdata.f_erasesize); - return (EINVAL); - } - - /* Get our blocksize */ - log_blocksize = nandfsdev->nd_fsdata.f_log_block_size; - nandfsdev->nd_blocksize = (uint64_t) 1 << (log_blocksize + 10); - DPRINTF(VOLUMES, ("%s: blocksize:%x\n", __func__, - nandfsdev->nd_blocksize)); - - DPRINTF(VOLUMES, ("%s: accepted super block with cp %#jx\n", __func__, - (uintmax_t)nandfsdev->nd_super.s_last_cno)); - - /* Calculate dat structure parameters */ - nandfs_calc_mdt_consts(nandfsdev, &nandfsdev->nd_dat_mdt, - nandfsdev->nd_fsdata.f_dat_entry_size); - nandfs_calc_mdt_consts(nandfsdev, &nandfsdev->nd_ifile_mdt, - nandfsdev->nd_fsdata.f_inode_size); - - /* Search for the super root and roll forward when needed */ - if (nandfs_search_super_root(nandfsdev)) { - printf("Cannot find valid SuperRoot\n"); - return (EINVAL); - } - - nandfsdev->nd_mount_state = nandfsdev->nd_super.s_state; - if (nandfsdev->nd_mount_state != NANDFS_VALID_FS) { - printf("FS is seriously damaged, needs repairing\n"); - printf("aborting mount\n"); - return (EINVAL); - } - - /* - * FS should be ok now. The superblock and the last segsum could be - * updated from the repair so extract running values again. - */ - nandfsdev->nd_last_pseg = nandfsdev->nd_super.s_last_pseg; - nandfsdev->nd_seg_sequence = nandfsdev->nd_super.s_last_seq; - nandfsdev->nd_seg_num = nandfs_get_segnum_of_block(nandfsdev, - nandfsdev->nd_last_pseg); - nandfsdev->nd_next_seg_num = nandfs_get_segnum_of_block(nandfsdev, - nandfsdev->nd_last_segsum.ss_next); - nandfsdev->nd_ts.tv_sec = nandfsdev->nd_last_segsum.ss_create; - nandfsdev->nd_last_cno = nandfsdev->nd_super.s_last_cno; - nandfsdev->nd_fakevblk = 1; - /* - * FIXME: bogus calculation. Should use actual number of usable segments - * instead of total amount. - */ - nandfsdev->nd_segs_reserved = - nandfsdev->nd_fsdata.f_nsegments * - nandfsdev->nd_fsdata.f_r_segments_percentage / 100; - nandfsdev->nd_last_ino = NANDFS_USER_INO; - DPRINTF(VOLUMES, ("%s: last_pseg %#jx last_cno %#jx last_seq %#jx\n" - "fsdev: last_seg: seq %#jx num %#jx, next_seg_num %#jx " - "segs_reserved %#jx\n", - __func__, (uintmax_t)nandfsdev->nd_last_pseg, - (uintmax_t)nandfsdev->nd_last_cno, - (uintmax_t)nandfsdev->nd_seg_sequence, - (uintmax_t)nandfsdev->nd_seg_sequence, - (uintmax_t)nandfsdev->nd_seg_num, - (uintmax_t)nandfsdev->nd_next_seg_num, - (uintmax_t)nandfsdev->nd_segs_reserved)); - - DPRINTF(VOLUMES, ("nandfs_mount: accepted super root\n")); - - /* Create system vnodes for DAT, CP and SEGSUM */ - error = nandfs_create_system_nodes(nandfsdev); - if (error) - nandfs_unmount_base(nandfsdev); - - nandfs_get_ncleanseg(nandfsdev); - - return (error); -} - -static void -nandfs_unmount_device(struct nandfs_device *nandfsdev) -{ - - /* Is there anything? */ - if (nandfsdev == NULL) - return; - - /* Remove the device only if we're the last reference */ - nandfsdev->nd_refcnt--; - if (nandfsdev->nd_refcnt >= 1) - return; - - MPASS(nandfsdev->nd_syncer == NULL); - MPASS(nandfsdev->nd_cleaner == NULL); - MPASS(nandfsdev->nd_free_base == NULL); - - /* Unmount our base */ - nandfs_unmount_base(nandfsdev); - - /* Remove from our device list */ - SLIST_REMOVE(&nandfs_devices, nandfsdev, nandfs_device, nd_next_device); - - DROP_GIANT(); - g_topology_lock(); - g_vfs_close(nandfsdev->nd_gconsumer); - g_topology_unlock(); - PICKUP_GIANT(); - - DPRINTF(VOLUMES, ("closing device\n")); - - /* Clear our mount reference and release device node */ - vrele(nandfsdev->nd_devvp); - - dev_rel(nandfsdev->nd_devvp->v_rdev); - - /* Free our device info */ - cv_destroy(&nandfsdev->nd_sync_cv); - mtx_destroy(&nandfsdev->nd_sync_mtx); - cv_destroy(&nandfsdev->nd_clean_cv); - mtx_destroy(&nandfsdev->nd_clean_mtx); - mtx_destroy(&nandfsdev->nd_mutex); - lockdestroy(&nandfsdev->nd_seg_const); - free(nandfsdev, M_NANDFSMNT); -} - -static int -nandfs_check_mounts(struct nandfs_device *nandfsdev, struct mount *mp, - struct nandfs_args *args) -{ - struct nandfsmount *nmp; - uint64_t last_cno; - - /* no double-mounting of the same checkpoint */ - STAILQ_FOREACH(nmp, &nandfsdev->nd_mounts, nm_next_mount) { - if (nmp->nm_mount_args.cpno == args->cpno) - return (EBUSY); - } - - /* Allow readonly mounts without questioning here */ - if (mp->mnt_flag & MNT_RDONLY) - return (0); - - /* Read/write mount */ - STAILQ_FOREACH(nmp, &nandfsdev->nd_mounts, nm_next_mount) { - /* Only one RW mount on this device! */ - if ((nmp->nm_vfs_mountp->mnt_flag & MNT_RDONLY)==0) - return (EROFS); - /* RDONLY on last mountpoint is device busy */ - last_cno = nmp->nm_nandfsdev->nd_super.s_last_cno; - if (nmp->nm_mount_args.cpno == last_cno) - return (EBUSY); - } - - /* OK for now */ - return (0); -} - -static int -nandfs_mount_device(struct vnode *devvp, struct mount *mp, - struct nandfs_args *args, struct nandfs_device **nandfsdev_p) -{ - struct nandfs_device *nandfsdev; - struct g_provider *pp; - struct g_consumer *cp; - struct cdev *dev; - uint32_t erasesize; - int error, size; - int ronly; - - DPRINTF(VOLUMES, ("Mounting NANDFS device\n")); - - ronly = (mp->mnt_flag & MNT_RDONLY) != 0; - - /* Look up device in our nandfs_mountpoints */ - *nandfsdev_p = NULL; - SLIST_FOREACH(nandfsdev, &nandfs_devices, nd_next_device) - if (nandfsdev->nd_devvp == devvp) - break; - - if (nandfsdev) { - DPRINTF(VOLUMES, ("device already mounted\n")); - error = nandfs_check_mounts(nandfsdev, mp, args); - if (error) - return error; - nandfsdev->nd_refcnt++; - *nandfsdev_p = nandfsdev; - - if (!ronly) { - DROP_GIANT(); - g_topology_lock(); - error = g_access(nandfsdev->nd_gconsumer, 0, 1, 0); - g_topology_unlock(); - PICKUP_GIANT(); - } - return (error); - } - - vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); - dev = devvp->v_rdev; - dev_ref(dev); - DROP_GIANT(); - g_topology_lock(); - error = g_vfs_open(devvp, &cp, "nandfs", ronly ? 0 : 1); - pp = g_dev_getprovider(dev); - g_topology_unlock(); - PICKUP_GIANT(); - VOP_UNLOCK(devvp, 0); - if (error) { - dev_rel(dev); - return (error); - } - - nandfsdev = malloc(sizeof(struct nandfs_device), M_NANDFSMNT, M_WAITOK | M_ZERO); - - /* Initialise */ - nandfsdev->nd_refcnt = 1; - nandfsdev->nd_devvp = devvp; - nandfsdev->nd_syncing = 0; - nandfsdev->nd_cleaning = 0; - nandfsdev->nd_gconsumer = cp; - cv_init(&nandfsdev->nd_sync_cv, "nandfssync"); - mtx_init(&nandfsdev->nd_sync_mtx, "nffssyncmtx", NULL, MTX_DEF); - cv_init(&nandfsdev->nd_clean_cv, "nandfsclean"); - mtx_init(&nandfsdev->nd_clean_mtx, "nffscleanmtx", NULL, MTX_DEF); - mtx_init(&nandfsdev->nd_mutex, "nandfsdev lock", NULL, MTX_DEF); - lockinit(&nandfsdev->nd_seg_const, PVFS, "nffssegcon", VLKTIMEOUT, - LK_CANRECURSE); - STAILQ_INIT(&nandfsdev->nd_mounts); - - nandfsdev->nd_devsize = pp->mediasize; - nandfsdev->nd_devblocksize = pp->sectorsize; - - size = sizeof(erasesize); - error = g_io_getattr("NAND::blocksize", nandfsdev->nd_gconsumer, &size, - &erasesize); - if (error) { - DPRINTF(VOLUMES, ("couldn't get erasesize: %d\n", error)); - - if (error == ENOIOCTL || error == EOPNOTSUPP) { - /* - * We conclude that this is not NAND storage - */ - erasesize = NANDFS_DEF_ERASESIZE; - } else { - DROP_GIANT(); - g_topology_lock(); - g_vfs_close(nandfsdev->nd_gconsumer); - g_topology_unlock(); - PICKUP_GIANT(); - dev_rel(dev); - free(nandfsdev, M_NANDFSMNT); - return (error); - } - } - nandfsdev->nd_erasesize = erasesize; - - DPRINTF(VOLUMES, ("%s: erasesize %x\n", __func__, - nandfsdev->nd_erasesize)); - - /* Register nandfs_device in list */ - SLIST_INSERT_HEAD(&nandfs_devices, nandfsdev, nd_next_device); - - error = nandfs_mount_base(nandfsdev, mp, args); - if (error) { - /* Remove all our information */ - nandfs_unmount_device(nandfsdev); - return (EINVAL); - } - - nandfsdev->nd_maxfilesize = nandfs_get_maxfilesize(nandfsdev); - - *nandfsdev_p = nandfsdev; - DPRINTF(VOLUMES, ("NANDFS device mounted ok\n")); - - return (0); -} - -static int -nandfs_mount_checkpoint(struct nandfsmount *nmp) -{ - struct nandfs_cpfile_header *cphdr; - struct nandfs_checkpoint *cp; - struct nandfs_inode ifile_inode; - struct nandfs_node *cp_node; - struct buf *bp; - uint64_t ncp, nsn, cpno, fcpno, blocknr, last_cno; - uint32_t off, dlen; - int cp_per_block, error; - - cpno = nmp->nm_mount_args.cpno; - if (cpno == 0) - cpno = nmp->nm_nandfsdev->nd_super.s_last_cno; - - DPRINTF(VOLUMES, ("%s: trying to mount checkpoint number %"PRIu64"\n", - __func__, cpno)); - - cp_node = nmp->nm_nandfsdev->nd_cp_node; - - VOP_LOCK(NTOV(cp_node), LK_SHARED); - /* Get cpfile header from 1st block of cp file */ - error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp); - if (error) { - brelse(bp); - VOP_UNLOCK(NTOV(cp_node), 0); - return (error); - } - - cphdr = (struct nandfs_cpfile_header *) bp->b_data; - ncp = cphdr->ch_ncheckpoints; - nsn = cphdr->ch_nsnapshots; - - brelse(bp); - - DPRINTF(VOLUMES, ("mount_nandfs: checkpoint header read in\n")); - DPRINTF(VOLUMES, ("\tNumber of checkpoints %"PRIu64"\n", ncp)); - DPRINTF(VOLUMES, ("\tNumber of snapshots %"PRIu64"\n", nsn)); - - /* Read in our specified checkpoint */ - dlen = nmp->nm_nandfsdev->nd_fsdata.f_checkpoint_size; - cp_per_block = nmp->nm_nandfsdev->nd_blocksize / dlen; - - fcpno = cpno + NANDFS_CPFILE_FIRST_CHECKPOINT_OFFSET - 1; - blocknr = fcpno / cp_per_block; - off = (fcpno % cp_per_block) * dlen; - error = nandfs_bread(cp_node, blocknr, NOCRED, 0, &bp); - if (error) { - brelse(bp); - VOP_UNLOCK(NTOV(cp_node), 0); - printf("mount_nandfs: couldn't read cp block %"PRIu64"\n", - fcpno); - return (EINVAL); - } - - /* Needs to be a valid checkpoint */ - cp = (struct nandfs_checkpoint *) ((uint8_t *) bp->b_data + off); - if (cp->cp_flags & NANDFS_CHECKPOINT_INVALID) { - printf("mount_nandfs: checkpoint marked invalid\n"); - brelse(bp); - VOP_UNLOCK(NTOV(cp_node), 0); - return (EINVAL); - } - - /* Is this really the checkpoint we want? */ - if (cp->cp_cno != cpno) { - printf("mount_nandfs: checkpoint file corrupt? " - "expected cpno %"PRIu64", found cpno %"PRIu64"\n", - cpno, cp->cp_cno); - brelse(bp); - VOP_UNLOCK(NTOV(cp_node), 0); - return (EINVAL); - } - - /* Check if it's a snapshot ! */ - last_cno = nmp->nm_nandfsdev->nd_super.s_last_cno; - if (cpno != last_cno) { - /* Only allow snapshots if not mounting on the last cp */ - if ((cp->cp_flags & NANDFS_CHECKPOINT_SNAPSHOT) == 0) { - printf( "mount_nandfs: checkpoint %"PRIu64" is not a " - "snapshot\n", cpno); - brelse(bp); - VOP_UNLOCK(NTOV(cp_node), 0); - return (EINVAL); - } - } - - ifile_inode = cp->cp_ifile_inode; - brelse(bp); - - /* Get ifile inode */ - error = nandfs_get_node_raw(nmp->nm_nandfsdev, NULL, NANDFS_IFILE_INO, - &ifile_inode, &nmp->nm_ifile_node); - if (error) { - printf("mount_nandfs: can't read ifile node\n"); - VOP_UNLOCK(NTOV(cp_node), 0); - return (EINVAL); - } - - NANDFS_SET_SYSTEMFILE(NTOV(nmp->nm_ifile_node)); - VOP_UNLOCK(NTOV(cp_node), 0); - /* Get root node? */ - - return (0); -} - -static void -free_nandfs_mountinfo(struct mount *mp) -{ - struct nandfsmount *nmp = VFSTONANDFS(mp); - - if (nmp == NULL) - return; - - free(nmp, M_NANDFSMNT); -} - -void -nandfs_wakeup_wait_sync(struct nandfs_device *nffsdev, int reason) -{ - char *reasons[] = { - "umount", - "vfssync", - "bdflush", - "fforce", - "fsync", - "ro_upd" - }; - - DPRINTF(SYNC, ("%s: %s\n", __func__, reasons[reason])); - mtx_lock(&nffsdev->nd_sync_mtx); - if (nffsdev->nd_syncing) - cv_wait(&nffsdev->nd_sync_cv, &nffsdev->nd_sync_mtx); - if (reason == SYNCER_UMOUNT) - nffsdev->nd_syncer_exit = 1; - nffsdev->nd_syncing = 1; - wakeup(&nffsdev->nd_syncing); - cv_wait(&nffsdev->nd_sync_cv, &nffsdev->nd_sync_mtx); - - mtx_unlock(&nffsdev->nd_sync_mtx); -} - -static void -nandfs_gc_finished(struct nandfs_device *nffsdev, int exit) -{ - int error; - - mtx_lock(&nffsdev->nd_sync_mtx); - nffsdev->nd_syncing = 0; - DPRINTF(SYNC, ("%s: cleaner finish\n", __func__)); - cv_broadcast(&nffsdev->nd_sync_cv); - mtx_unlock(&nffsdev->nd_sync_mtx); - if (!exit) { - error = tsleep(&nffsdev->nd_syncing, PRIBIO, "-", - hz * nandfs_sync_interval); - DPRINTF(SYNC, ("%s: cleaner waked up: %d\n", - __func__, error)); - } -} - -static void -nandfs_syncer(struct nandfsmount *nmp) -{ - struct nandfs_device *nffsdev; - struct mount *mp; - int flags, error; - - mp = nmp->nm_vfs_mountp; - nffsdev = nmp->nm_nandfsdev; - tsleep(&nffsdev->nd_syncing, PRIBIO, "-", hz * nandfs_sync_interval); - - while (!nffsdev->nd_syncer_exit) { - DPRINTF(SYNC, ("%s: syncer run\n", __func__)); - nffsdev->nd_syncing = 1; - - flags = (nmp->nm_flags & (NANDFS_FORCE_SYNCER | NANDFS_UMOUNT)); - - error = nandfs_segment_constructor(nmp, flags); - if (error) - nandfs_error("%s: error:%d when creating segments\n", - __func__, error); - - nmp->nm_flags &= ~flags; - - nandfs_gc_finished(nffsdev, 0); - } - - MPASS(nffsdev->nd_cleaner == NULL); - error = nandfs_segment_constructor(nmp, - NANDFS_FORCE_SYNCER | NANDFS_UMOUNT); - if (error) - nandfs_error("%s: error:%d when creating segments\n", - __func__, error); - nandfs_gc_finished(nffsdev, 1); - nffsdev->nd_syncer = NULL; - MPASS(nffsdev->nd_free_base == NULL); - - DPRINTF(SYNC, ("%s: exiting\n", __func__)); - kthread_exit(); -} - -static int -start_syncer(struct nandfsmount *nmp) -{ - int error; - - MPASS(nmp->nm_nandfsdev->nd_syncer == NULL); - - DPRINTF(SYNC, ("%s: start syncer\n", __func__)); - - nmp->nm_nandfsdev->nd_syncer_exit = 0; - - error = kthread_add((void(*)(void *))nandfs_syncer, nmp, NULL, - &nmp->nm_nandfsdev->nd_syncer, 0, 0, "nandfs_syncer"); - - if (error) - printf("nandfs: could not start syncer: %d\n", error); - - return (error); -} - -static int -stop_syncer(struct nandfsmount *nmp) -{ - - MPASS(nmp->nm_nandfsdev->nd_syncer != NULL); - - nandfs_wakeup_wait_sync(nmp->nm_nandfsdev, SYNCER_UMOUNT); - - DPRINTF(SYNC, ("%s: stop syncer\n", __func__)); - return (0); -} - -/* - * Mount null layer - */ -static int -nandfs_mount(struct mount *mp) -{ - struct nandfsmount *nmp; - struct vnode *devvp; - struct nameidata nd; - struct vfsoptlist *opts; - struct thread *td; - char *from; - int error = 0, flags; - - DPRINTF(VOLUMES, ("%s: mp = %p\n", __func__, (void *)mp)); - - td = curthread; - opts = mp->mnt_optnew; - - if (vfs_filteropt(opts, nandfs_opts)) - return (EINVAL); - - /* - * Update is a no-op - */ - if (mp->mnt_flag & MNT_UPDATE) { - nmp = VFSTONANDFS(mp); - if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0)) { - return (error); - } - if (!(nmp->nm_ronly) && vfs_flagopt(opts, "ro", NULL, 0)) { - vn_start_write(NULL, &mp, V_WAIT); - error = VFS_SYNC(mp, MNT_WAIT); - if (error) - return (error); - vn_finished_write(mp); - - flags = WRITECLOSE; - if (mp->mnt_flag & MNT_FORCE) - flags |= FORCECLOSE; - - nandfs_wakeup_wait_sync(nmp->nm_nandfsdev, - SYNCER_ROUPD); - error = vflush(mp, 0, flags, td); - if (error) - return (error); - - nandfs_stop_cleaner(nmp->nm_nandfsdev); - stop_syncer(nmp); - DROP_GIANT(); - g_topology_lock(); - g_access(nmp->nm_nandfsdev->nd_gconsumer, 0, -1, 0); - g_topology_unlock(); - PICKUP_GIANT(); - MNT_ILOCK(mp); - mp->mnt_flag |= MNT_RDONLY; - MNT_IUNLOCK(mp); - nmp->nm_ronly = 1; - - } else if ((nmp->nm_ronly) && - !vfs_flagopt(opts, "ro", NULL, 0)) { - /* - * Don't allow read-write snapshots. - */ - if (nmp->nm_mount_args.cpno != 0) - return (EROFS); - /* - * If upgrade to read-write by non-root, then verify - * that user has necessary permissions on the device. - */ - devvp = nmp->nm_nandfsdev->nd_devvp; - vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); - error = VOP_ACCESS(devvp, VREAD | VWRITE, - td->td_ucred, td); - if (error) { - error = priv_check(td, PRIV_VFS_MOUNT_PERM); - if (error) { - VOP_UNLOCK(devvp, 0); - return (error); - } - } - - VOP_UNLOCK(devvp, 0); - DROP_GIANT(); - g_topology_lock(); - error = g_access(nmp->nm_nandfsdev->nd_gconsumer, 0, 1, - 0); - g_topology_unlock(); - PICKUP_GIANT(); - if (error) - return (error); - - MNT_ILOCK(mp); - mp->mnt_flag &= ~MNT_RDONLY; - MNT_IUNLOCK(mp); - error = start_syncer(nmp); - if (error == 0) - error = nandfs_start_cleaner(nmp->nm_nandfsdev); - if (error) { - DROP_GIANT(); - g_topology_lock(); - g_access(nmp->nm_nandfsdev->nd_gconsumer, 0, -1, - 0); - g_topology_unlock(); - PICKUP_GIANT(); - return (error); - } - - nmp->nm_ronly = 0; - } - return (0); - } - - from = vfs_getopts(opts, "from", &error); - if (error) - return (error); - - /* - * Find device node - */ - NDINIT(&nd, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, from, curthread); - error = namei(&nd); - if (error) - return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - - devvp = nd.ni_vp; - - if (!vn_isdisk(devvp, &error)) { - vput(devvp); - return (error); - } - - /* Check the access rights on the mount device */ - error = VOP_ACCESS(devvp, VREAD, curthread->td_ucred, curthread); - if (error) - error = priv_check(curthread, PRIV_VFS_MOUNT_PERM); - if (error) { - vput(devvp); - return (error); - } - - vfs_getnewfsid(mp); - - error = nandfs_mountfs(devvp, mp); - if (error) - return (error); - vfs_mountedfrom(mp, from); - - return (0); -} - -static int -nandfs_mountfs(struct vnode *devvp, struct mount *mp) -{ - struct nandfsmount *nmp = NULL; - struct nandfs_args *args = NULL; - struct nandfs_device *nandfsdev; - char *from; - int error, ronly; - char *cpno; - - ronly = (mp->mnt_flag & MNT_RDONLY) != 0; - - if (devvp->v_rdev->si_iosize_max != 0) - mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max; - VOP_UNLOCK(devvp, 0); - - if (mp->mnt_iosize_max > MAXPHYS) - mp->mnt_iosize_max = MAXPHYS; - - from = vfs_getopts(mp->mnt_optnew, "from", &error); - if (error) - goto error; - - error = vfs_getopt(mp->mnt_optnew, "snap", (void **)&cpno, NULL); - if (error == ENOENT) - cpno = NULL; - else if (error) - goto error; - - args = (struct nandfs_args *)malloc(sizeof(struct nandfs_args), - M_NANDFSMNT, M_WAITOK | M_ZERO); - - if (cpno != NULL) - args->cpno = strtoul(cpno, (char **)NULL, 10); - else - args->cpno = 0; - args->fspec = from; - - if (args->cpno != 0 && !ronly) { - error = EROFS; - goto error; - } - - printf("WARNING: NANDFS is considered to be a highly experimental " - "feature in FreeBSD.\n"); - - error = nandfs_mount_device(devvp, mp, args, &nandfsdev); - if (error) - goto error; - - nmp = (struct nandfsmount *) malloc(sizeof(struct nandfsmount), - M_NANDFSMNT, M_WAITOK | M_ZERO); - - mp->mnt_data = nmp; - nmp->nm_vfs_mountp = mp; - nmp->nm_ronly = ronly; - MNT_ILOCK(mp); - mp->mnt_flag |= MNT_LOCAL; - mp->mnt_kern_flag |= MNTK_USES_BCACHE; - MNT_IUNLOCK(mp); - nmp->nm_nandfsdev = nandfsdev; - /* Add our mountpoint */ - STAILQ_INSERT_TAIL(&nandfsdev->nd_mounts, nmp, nm_next_mount); - - if (args->cpno > nandfsdev->nd_last_cno) { - printf("WARNING: supplied checkpoint number (%jd) is greater " - "than last known checkpoint on filesystem (%jd). Mounting" - " checkpoint %jd\n", (uintmax_t)args->cpno, - (uintmax_t)nandfsdev->nd_last_cno, - (uintmax_t)nandfsdev->nd_last_cno); - args->cpno = nandfsdev->nd_last_cno; - } - - /* Setting up other parameters */ - nmp->nm_mount_args = *args; - free(args, M_NANDFSMNT); - error = nandfs_mount_checkpoint(nmp); - if (error) { - nandfs_unmount(mp, MNT_FORCE); - goto unmounted; - } - - if (!ronly) { - error = start_syncer(nmp); - if (error == 0) - error = nandfs_start_cleaner(nmp->nm_nandfsdev); - if (error) - nandfs_unmount(mp, MNT_FORCE); - } - - return (0); - -error: - if (args != NULL) - free(args, M_NANDFSMNT); - - if (nmp != NULL) { - free(nmp, M_NANDFSMNT); - mp->mnt_data = NULL; - } -unmounted: - return (error); -} - -static int -nandfs_unmount(struct mount *mp, int mntflags) -{ - struct nandfs_device *nandfsdev; - struct nandfsmount *nmp; - int error; - int flags = 0; - - DPRINTF(VOLUMES, ("%s: mp = %p\n", __func__, (void *)mp)); - - if (mntflags & MNT_FORCE) - flags |= FORCECLOSE; - - nmp = mp->mnt_data; - nandfsdev = nmp->nm_nandfsdev; - - error = vflush(mp, 0, flags | SKIPSYSTEM, curthread); - if (error) - return (error); - - if (!(nmp->nm_ronly)) { - nandfs_stop_cleaner(nandfsdev); - stop_syncer(nmp); - } - - if (nmp->nm_ifile_node) - NANDFS_UNSET_SYSTEMFILE(NTOV(nmp->nm_ifile_node)); - - /* Remove our mount point */ - STAILQ_REMOVE(&nandfsdev->nd_mounts, nmp, nandfsmount, nm_next_mount); - - /* Unmount the device itself when we're the last one */ - nandfs_unmount_device(nandfsdev); - - free_nandfs_mountinfo(mp); - - /* - * Finally, throw away the null_mount structure - */ - mp->mnt_data = 0; - MNT_ILOCK(mp); - mp->mnt_flag &= ~MNT_LOCAL; - MNT_IUNLOCK(mp); - - return (0); -} - -static int -nandfs_statfs(struct mount *mp, struct statfs *sbp) -{ - struct nandfsmount *nmp; - struct nandfs_device *nandfsdev; - struct nandfs_fsdata *fsdata; - struct nandfs_super_block *sb; - struct nandfs_block_group_desc *groups; - struct nandfs_node *ifile; - struct nandfs_mdt *mdt; - struct buf *bp; - int i, error; - uint32_t entries_per_group; - uint64_t files = 0; - - nmp = mp->mnt_data; - nandfsdev = nmp->nm_nandfsdev; - fsdata = &nandfsdev->nd_fsdata; - sb = &nandfsdev->nd_super; - ifile = nmp->nm_ifile_node; - mdt = &nandfsdev->nd_ifile_mdt; - entries_per_group = mdt->entries_per_group; - - VOP_LOCK(NTOV(ifile), LK_SHARED); - error = nandfs_bread(ifile, 0, NOCRED, 0, &bp); - if (error) { - brelse(bp); - VOP_UNLOCK(NTOV(ifile), 0); - return (error); - } - - groups = (struct nandfs_block_group_desc *)bp->b_data; - - for (i = 0; i < mdt->groups_per_desc_block; i++) - files += (entries_per_group - groups[i].bg_nfrees); - - brelse(bp); - VOP_UNLOCK(NTOV(ifile), 0); - - sbp->f_bsize = nandfsdev->nd_blocksize; - sbp->f_iosize = sbp->f_bsize; - sbp->f_blocks = fsdata->f_blocks_per_segment * fsdata->f_nsegments; - sbp->f_bfree = sb->s_free_blocks_count; - sbp->f_bavail = sbp->f_bfree; - sbp->f_files = files; - sbp->f_ffree = 0; - return (0); -} - -static int -nandfs_root(struct mount *mp, int flags, struct vnode **vpp) -{ - struct nandfsmount *nmp = VFSTONANDFS(mp); - struct nandfs_node *node; - int error; - - error = nandfs_get_node(nmp, NANDFS_ROOT_INO, &node); - if (error) - return (error); - - KASSERT(NTOV(node)->v_vflag & VV_ROOT, - ("root_vp->v_vflag & VV_ROOT")); - - *vpp = NTOV(node); - - return (error); -} - -static int -nandfs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) -{ - struct nandfsmount *nmp = VFSTONANDFS(mp); - struct nandfs_node *node; - int error; - - error = nandfs_get_node(nmp, ino, &node); - if (node) - *vpp = NTOV(node); - - return (error); -} - -static int -nandfs_sync(struct mount *mp, int waitfor) -{ - struct nandfsmount *nmp = VFSTONANDFS(mp); - - DPRINTF(SYNC, ("%s: mp %p waitfor %d\n", __func__, mp, waitfor)); - - /* - * XXX: A hack to be removed soon - */ - if (waitfor == MNT_LAZY) - return (0); - if (waitfor == MNT_SUSPEND) - return (0); - nandfs_wakeup_wait_sync(nmp->nm_nandfsdev, SYNCER_VFS_SYNC); - return (0); -} - -static struct vfsops nandfs_vfsops = { - .vfs_init = nandfs_init, - .vfs_mount = nandfs_mount, - .vfs_root = nandfs_root, - .vfs_statfs = nandfs_statfs, - .vfs_uninit = nandfs_uninit, - .vfs_unmount = nandfs_unmount, - .vfs_vget = nandfs_vget, - .vfs_sync = nandfs_sync, -}; - -VFS_SET(nandfs_vfsops, nandfs, VFCF_LOOPBACK); diff --git a/sys/fs/nandfs/nandfs_vnops.c b/sys/fs/nandfs/nandfs_vnops.c deleted file mode 100644 index 5027d6adbbc1..000000000000 --- a/sys/fs/nandfs/nandfs_vnops.c +++ /dev/null @@ -1,2454 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf - * Copyright (c) 2008, 2009 Reinoud Zandijk - * 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, 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. - * - * From: NetBSD: nilfs_vnops.c,v 1.2 2009/08/26 03:40:48 elad - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include - -extern uma_zone_t nandfs_node_zone; -static void nandfs_read_filebuf(struct nandfs_node *, struct buf *); -static void nandfs_itimes_locked(struct vnode *); -static int nandfs_truncate(struct vnode *, uint64_t); - -static vop_pathconf_t nandfs_pathconf; - -#define UPDATE_CLOSE 0 -#define UPDATE_WAIT 0 - -static int -nandfs_inactive(struct vop_inactive_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *node = VTON(vp); - int error = 0; - - DPRINTF(VNCALL, ("%s: vp:%p node:%p\n", __func__, vp, node)); - - if (node == NULL) { - DPRINTF(NODE, ("%s: inactive NULL node\n", __func__)); - return (0); - } - - if (node->nn_inode.i_mode != 0 && !(node->nn_inode.i_links_count)) { - nandfs_truncate(vp, 0); - error = nandfs_node_destroy(node); - if (error) - nandfs_error("%s: destroy node: %p\n", __func__, node); - node->nn_flags = 0; - vrecycle(vp); - } - - return (error); -} - -static int -nandfs_reclaim(struct vop_reclaim_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *nandfs_node = VTON(vp); - struct nandfs_device *fsdev = nandfs_node->nn_nandfsdev; - uint64_t ino = nandfs_node->nn_ino; - - DPRINTF(VNCALL, ("%s: vp:%p node:%p\n", __func__, vp, nandfs_node)); - - /* Invalidate all entries to a particular vnode. */ - cache_purge(vp); - - /* Destroy the vm object and flush associated pages. */ - vnode_destroy_vobject(vp); - - /* Remove from vfs hash if not system vnode */ - if (!NANDFS_SYS_NODE(nandfs_node->nn_ino)) - vfs_hash_remove(vp); - - /* Dispose all node knowledge */ - nandfs_dispose_node(&nandfs_node); - - if (!NANDFS_SYS_NODE(ino)) - NANDFS_WRITEUNLOCK(fsdev); - - return (0); -} - -static int -nandfs_read(struct vop_read_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *node = VTON(vp); - struct nandfs_device *nandfsdev = node->nn_nandfsdev; - struct uio *uio = ap->a_uio; - struct buf *bp; - uint64_t size; - uint32_t blocksize; - off_t bytesinfile; - ssize_t toread, off; - daddr_t lbn; - ssize_t resid; - int error = 0; - - if (uio->uio_resid == 0) - return (0); - - size = node->nn_inode.i_size; - if (uio->uio_offset >= size) - return (0); - - blocksize = nandfsdev->nd_blocksize; - bytesinfile = size - uio->uio_offset; - - resid = omin(uio->uio_resid, bytesinfile); - - while (resid) { - lbn = uio->uio_offset / blocksize; - off = uio->uio_offset & (blocksize - 1); - - toread = omin(resid, blocksize - off); - - DPRINTF(READ, ("nandfs_read bn: 0x%jx toread: 0x%zx (0x%x)\n", - (uintmax_t)lbn, toread, blocksize)); - - error = nandfs_bread(node, lbn, NOCRED, 0, &bp); - if (error) { - brelse(bp); - break; - } - - error = uiomove(bp->b_data + off, toread, uio); - if (error) { - brelse(bp); - break; - } - - brelse(bp); - resid -= toread; - } - - return (error); -} - -static int -nandfs_write(struct vop_write_args *ap) -{ - struct nandfs_device *fsdev; - struct nandfs_node *node; - struct vnode *vp; - struct uio *uio; - struct buf *bp; - uint64_t file_size, vblk; - uint32_t blocksize; - ssize_t towrite, off; - daddr_t lbn; - ssize_t resid; - int error, ioflag, modified; - - vp = ap->a_vp; - uio = ap->a_uio; - ioflag = ap->a_ioflag; - node = VTON(vp); - fsdev = node->nn_nandfsdev; - - if (nandfs_fs_full(fsdev)) - return (ENOSPC); - - DPRINTF(WRITE, ("nandfs_write called %#zx at %#jx\n", - uio->uio_resid, (uintmax_t)uio->uio_offset)); - - if (uio->uio_offset < 0) - return (EINVAL); - if (uio->uio_resid == 0) - return (0); - - blocksize = fsdev->nd_blocksize; - file_size = node->nn_inode.i_size; - - switch (vp->v_type) { - case VREG: - if (ioflag & IO_APPEND) - uio->uio_offset = file_size; - break; - case VDIR: - return (EISDIR); - case VLNK: - break; - default: - panic("%s: bad file type vp: %p", __func__, vp); - } - - /* If explicitly asked to append, uio_offset can be wrong? */ - if (ioflag & IO_APPEND) - uio->uio_offset = file_size; - - resid = uio->uio_resid; - modified = error = 0; - - while (uio->uio_resid) { - lbn = uio->uio_offset / blocksize; - off = uio->uio_offset & (blocksize - 1); - - towrite = omin(uio->uio_resid, blocksize - off); - - DPRINTF(WRITE, ("%s: lbn: 0x%jd toread: 0x%zx (0x%x)\n", - __func__, (uintmax_t)lbn, towrite, blocksize)); - - error = nandfs_bmap_lookup(node, lbn, &vblk); - if (error) - break; - - DPRINTF(WRITE, ("%s: lbn: 0x%jd toread: 0x%zx (0x%x) " - "vblk=%jx\n", __func__, (uintmax_t)lbn, towrite, blocksize, - vblk)); - - if (vblk != 0) - error = nandfs_bread(node, lbn, NOCRED, 0, &bp); - else - error = nandfs_bcreate(node, lbn, NOCRED, 0, &bp); - - DPRINTF(WRITE, ("%s: vp %p bread bp %p lbn %#jx\n", __func__, - vp, bp, (uintmax_t)lbn)); - if (error) { - if (bp) - brelse(bp); - break; - } - - error = uiomove((char *)bp->b_data + off, (int)towrite, uio); - if (error) - break; - - error = nandfs_dirty_buf(bp, 0); - if (error) - break; - - modified++; - } - - /* XXX proper handling when only part of file was properly written */ - if (modified) { - if (resid > uio->uio_resid && ap->a_cred && - ap->a_cred->cr_uid != 0) - node->nn_inode.i_mode &= ~(ISUID | ISGID); - - if (file_size < uio->uio_offset + uio->uio_resid) { - node->nn_inode.i_size = uio->uio_offset + - uio->uio_resid; - node->nn_flags |= IN_CHANGE | IN_UPDATE; - vnode_pager_setsize(vp, uio->uio_offset + - uio->uio_resid); - nandfs_itimes(vp); - } - } - - DPRINTF(WRITE, ("%s: return:%d\n", __func__, error)); - - return (error); -} - -static int -nandfs_lookup(struct vop_cachedlookup_args *ap) -{ - struct vnode *dvp, **vpp; - struct componentname *cnp; - struct ucred *cred; - struct thread *td; - struct nandfs_node *dir_node, *node; - struct nandfsmount *nmp; - uint64_t ino, off; - const char *name; - int namelen, nameiop, islastcn, mounted_ro; - int error, found; - - DPRINTF(VNCALL, ("%s\n", __func__)); - - dvp = ap->a_dvp; - vpp = ap->a_vpp; - *vpp = NULL; - - cnp = ap->a_cnp; - cred = cnp->cn_cred; - td = cnp->cn_thread; - - dir_node = VTON(dvp); - nmp = dir_node->nn_nmp; - - /* Simplify/clarification flags */ - nameiop = cnp->cn_nameiop; - islastcn = cnp->cn_flags & ISLASTCN; - mounted_ro = dvp->v_mount->mnt_flag & MNT_RDONLY; - - /* - * If requesting a modify on the last path element on a read-only - * filingsystem, reject lookup; - */ - if (islastcn && mounted_ro && (nameiop == DELETE || nameiop == RENAME)) - return (EROFS); - - if (dir_node->nn_inode.i_links_count == 0) - return (ENOENT); - - /* - * Obviously, the file is not (anymore) in the namecache, we have to - * search for it. There are three basic cases: '.', '..' and others. - * - * Following the guidelines of VOP_LOOKUP manpage and tmpfs. - */ - error = 0; - if ((cnp->cn_namelen == 1) && (cnp->cn_nameptr[0] == '.')) { - DPRINTF(LOOKUP, ("\tlookup '.'\n")); - /* Special case 1 '.' */ - VREF(dvp); - *vpp = dvp; - /* Done */ - } else if (cnp->cn_flags & ISDOTDOT) { - /* Special case 2 '..' */ - DPRINTF(LOOKUP, ("\tlookup '..'\n")); - - /* Get our node */ - name = ".."; - namelen = 2; - error = nandfs_lookup_name_in_dir(dvp, name, namelen, &ino, - &found, &off); - if (error) - goto out; - if (!found) - error = ENOENT; - - /* First unlock parent */ - VOP_UNLOCK(dvp, 0); - - if (error == 0) { - DPRINTF(LOOKUP, ("\tfound '..'\n")); - /* Try to create/reuse the node */ - error = nandfs_get_node(nmp, ino, &node); - - if (!error) { - DPRINTF(LOOKUP, - ("\tnode retrieved/created OK\n")); - *vpp = NTOV(node); - } - } - - /* Try to relock parent */ - vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); - } else { - DPRINTF(LOOKUP, ("\tlookup file\n")); - /* All other files */ - /* Look up filename in the directory returning its inode */ - name = cnp->cn_nameptr; - namelen = cnp->cn_namelen; - error = nandfs_lookup_name_in_dir(dvp, name, namelen, - &ino, &found, &off); - if (error) - goto out; - if (!found) { - DPRINTF(LOOKUP, ("\tNOT found\n")); - /* - * UGH, didn't find name. If we're creating or - * renaming on the last name this is OK and we ought - * to return EJUSTRETURN if its allowed to be created. - */ - error = ENOENT; - if ((nameiop == CREATE || nameiop == RENAME) && - islastcn) { - error = VOP_ACCESS(dvp, VWRITE, cred, td); - if (!error) { - /* keep the component name */ - cnp->cn_flags |= SAVENAME; - error = EJUSTRETURN; - } - } - /* Done */ - } else { - if (ino == NANDFS_WHT_INO) - cnp->cn_flags |= ISWHITEOUT; - - if ((cnp->cn_flags & ISWHITEOUT) && - (nameiop == LOOKUP)) - return (ENOENT); - - if ((nameiop == DELETE) && islastcn) { - if ((cnp->cn_flags & ISWHITEOUT) && - (cnp->cn_flags & DOWHITEOUT)) { - cnp->cn_flags |= SAVENAME; - dir_node->nn_diroff = off; - return (EJUSTRETURN); - } - - error = VOP_ACCESS(dvp, VWRITE, cred, - cnp->cn_thread); - if (error) - return (error); - - /* Try to create/reuse the node */ - error = nandfs_get_node(nmp, ino, &node); - if (!error) { - *vpp = NTOV(node); - node->nn_diroff = off; - } - - if ((dir_node->nn_inode.i_mode & ISVTX) && - cred->cr_uid != 0 && - cred->cr_uid != dir_node->nn_inode.i_uid && - node->nn_inode.i_uid != cred->cr_uid) { - vput(*vpp); - *vpp = NULL; - return (EPERM); - } - } else if ((nameiop == RENAME) && islastcn) { - error = VOP_ACCESS(dvp, VWRITE, cred, - cnp->cn_thread); - if (error) - return (error); - - /* Try to create/reuse the node */ - error = nandfs_get_node(nmp, ino, &node); - if (!error) { - *vpp = NTOV(node); - node->nn_diroff = off; - } - } else { - /* Try to create/reuse the node */ - error = nandfs_get_node(nmp, ino, &node); - if (!error) { - *vpp = NTOV(node); - node->nn_diroff = off; - } - } - } - } - -out: - /* - * Store result in the cache if requested. If we are creating a file, - * the file might not be found and thus putting it into the namecache - * might be seen as negative caching. - */ - if ((cnp->cn_flags & MAKEENTRY) != 0) - cache_enter(dvp, *vpp, cnp); - - return (error); - -} - -static int -nandfs_getattr(struct vop_getattr_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct vattr *vap = ap->a_vap; - struct nandfs_node *node = VTON(vp); - struct nandfs_inode *inode = &node->nn_inode; - - DPRINTF(VNCALL, ("%s: vp: %p\n", __func__, vp)); - nandfs_itimes(vp); - - /* Basic info */ - VATTR_NULL(vap); - vap->va_atime.tv_sec = inode->i_mtime; - vap->va_atime.tv_nsec = inode->i_mtime_nsec; - vap->va_mtime.tv_sec = inode->i_mtime; - vap->va_mtime.tv_nsec = inode->i_mtime_nsec; - vap->va_ctime.tv_sec = inode->i_ctime; - vap->va_ctime.tv_nsec = inode->i_ctime_nsec; - vap->va_type = IFTOVT(inode->i_mode); - vap->va_mode = inode->i_mode & ~S_IFMT; - vap->va_nlink = inode->i_links_count; - vap->va_uid = inode->i_uid; - vap->va_gid = inode->i_gid; - vap->va_rdev = inode->i_special; - vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; - vap->va_fileid = node->nn_ino; - vap->va_size = inode->i_size; - vap->va_blocksize = node->nn_nandfsdev->nd_blocksize; - vap->va_gen = 0; - vap->va_flags = inode->i_flags; - vap->va_bytes = inode->i_blocks * vap->va_blocksize; - vap->va_filerev = 0; - vap->va_vaflags = 0; - - return (0); -} - -static int -nandfs_vtruncbuf(struct vnode *vp, uint64_t nblks) -{ - struct nandfs_device *nffsdev; - struct bufobj *bo; - struct buf *bp, *nbp; - - bo = &vp->v_bufobj; - nffsdev = VTON(vp)->nn_nandfsdev; - - ASSERT_VOP_LOCKED(vp, "nandfs_truncate"); -restart: - BO_LOCK(bo); -restart_locked: - TAILQ_FOREACH_SAFE(bp, &bo->bo_clean.bv_hd, b_bobufs, nbp) { - if (bp->b_lblkno < nblks) - continue; - if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL)) - goto restart_locked; - - bremfree(bp); - bp->b_flags |= (B_INVAL | B_RELBUF); - bp->b_flags &= ~(B_ASYNC | B_MANAGED); - BO_UNLOCK(bo); - brelse(bp); - BO_LOCK(bo); - } - - TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) { - if (bp->b_lblkno < nblks) - continue; - if (BUF_LOCK(bp, - LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK, - BO_LOCKPTR(bo)) == ENOLCK) - goto restart; - bp->b_flags |= (B_INVAL | B_RELBUF); - bp->b_flags &= ~(B_ASYNC | B_MANAGED); - brelse(bp); - nandfs_dirty_bufs_decrement(nffsdev); - BO_LOCK(bo); - } - - BO_UNLOCK(bo); - - return (0); -} - -static int -nandfs_truncate(struct vnode *vp, uint64_t newsize) -{ - struct nandfs_device *nffsdev; - struct nandfs_node *node; - struct nandfs_inode *inode; - struct buf *bp = NULL; - uint64_t oblks, nblks, vblk, size, rest; - int error; - - node = VTON(vp); - nffsdev = node->nn_nandfsdev; - inode = &node->nn_inode; - - /* Calculate end of file */ - size = inode->i_size; - - if (newsize == size) { - node->nn_flags |= IN_CHANGE | IN_UPDATE; - nandfs_itimes(vp); - return (0); - } - - if (newsize > size) { - inode->i_size = newsize; - vnode_pager_setsize(vp, newsize); - node->nn_flags |= IN_CHANGE | IN_UPDATE; - nandfs_itimes(vp); - return (0); - } - - nblks = howmany(newsize, nffsdev->nd_blocksize); - oblks = howmany(size, nffsdev->nd_blocksize); - rest = newsize % nffsdev->nd_blocksize; - - if (rest) { - error = nandfs_bmap_lookup(node, nblks - 1, &vblk); - if (error) - return (error); - - if (vblk != 0) - error = nandfs_bread(node, nblks - 1, NOCRED, 0, &bp); - else - error = nandfs_bcreate(node, nblks - 1, NOCRED, 0, &bp); - - if (error) { - if (bp) - brelse(bp); - return (error); - } - - bzero((char *)bp->b_data + rest, - (u_int)(nffsdev->nd_blocksize - rest)); - error = nandfs_dirty_buf(bp, 0); - if (error) - return (error); - } - - DPRINTF(VNCALL, ("%s: vp %p oblks %jx nblks %jx\n", __func__, vp, oblks, - nblks)); - - error = nandfs_bmap_truncate_mapping(node, oblks - 1, nblks - 1); - if (error) { - if (bp) - nandfs_undirty_buf(bp); - return (error); - } - - error = nandfs_vtruncbuf(vp, nblks); - if (error) { - if (bp) - nandfs_undirty_buf(bp); - return (error); - } - - inode->i_size = newsize; - vnode_pager_setsize(vp, newsize); - node->nn_flags |= IN_CHANGE | IN_UPDATE; - nandfs_itimes(vp); - - return (error); -} - -static void -nandfs_itimes_locked(struct vnode *vp) -{ - struct nandfs_node *node; - struct nandfs_inode *inode; - struct timespec ts; - - ASSERT_VI_LOCKED(vp, __func__); - - node = VTON(vp); - inode = &node->nn_inode; - - if ((node->nn_flags & (IN_ACCESS | IN_CHANGE | IN_UPDATE)) == 0) - return; - - if (((vp->v_mount->mnt_kern_flag & - (MNTK_SUSPENDED | MNTK_SUSPEND)) == 0) || - (node->nn_flags & (IN_CHANGE | IN_UPDATE))) - node->nn_flags |= IN_MODIFIED; - - vfs_timestamp(&ts); - if (node->nn_flags & IN_UPDATE) { - inode->i_mtime = ts.tv_sec; - inode->i_mtime_nsec = ts.tv_nsec; - } - if (node->nn_flags & IN_CHANGE) { - inode->i_ctime = ts.tv_sec; - inode->i_ctime_nsec = ts.tv_nsec; - } - - node->nn_flags &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE); -} - -void -nandfs_itimes(struct vnode *vp) -{ - - VI_LOCK(vp); - nandfs_itimes_locked(vp); - VI_UNLOCK(vp); -} - -static int -nandfs_chmod(struct vnode *vp, int mode, struct ucred *cred, struct thread *td) -{ - struct nandfs_node *node = VTON(vp); - struct nandfs_inode *inode = &node->nn_inode; - uint16_t nmode; - int error = 0; - - DPRINTF(VNCALL, ("%s: vp %p, mode %x, cred %p, td %p\n", __func__, vp, - mode, cred, td)); - /* - * To modify the permissions on a file, must possess VADMIN - * for that file. - */ - if ((error = VOP_ACCESS(vp, VADMIN, cred, td))) - return (error); - - /* - * Privileged processes may set the sticky bit on non-directories, - * as well as set the setgid bit on a file with a group that the - * process is not a member of. Both of these are allowed in - * jail(8). - */ - if (vp->v_type != VDIR && (mode & S_ISTXT)) { - if (priv_check_cred(cred, PRIV_VFS_STICKYFILE)) - return (EFTYPE); - } - if (!groupmember(inode->i_gid, cred) && (mode & ISGID)) { - error = priv_check_cred(cred, PRIV_VFS_SETGID); - if (error) - return (error); - } - - /* - * Deny setting setuid if we are not the file owner. - */ - if ((mode & ISUID) && inode->i_uid != cred->cr_uid) { - error = priv_check_cred(cred, PRIV_VFS_ADMIN); - if (error) - return (error); - } - - nmode = inode->i_mode; - nmode &= ~ALLPERMS; - nmode |= (mode & ALLPERMS); - inode->i_mode = nmode; - node->nn_flags |= IN_CHANGE; - - DPRINTF(VNCALL, ("%s: to mode %x\n", __func__, nmode)); - - return (error); -} - -static int -nandfs_chown(struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred, - struct thread *td) -{ - struct nandfs_node *node = VTON(vp); - struct nandfs_inode *inode = &node->nn_inode; - uid_t ouid; - gid_t ogid; - int error = 0; - - if (uid == (uid_t)VNOVAL) - uid = inode->i_uid; - if (gid == (gid_t)VNOVAL) - gid = inode->i_gid; - /* - * To modify the ownership of a file, must possess VADMIN for that - * file. - */ - if ((error = VOP_ACCESSX(vp, VWRITE_OWNER, cred, td))) - return (error); - /* - * To change the owner of a file, or change the group of a file to a - * group of which we are not a member, the caller must have - * privilege. - */ - if (((uid != inode->i_uid && uid != cred->cr_uid) || - (gid != inode->i_gid && !groupmember(gid, cred))) && - (error = priv_check_cred(cred, PRIV_VFS_CHOWN))) - return (error); - ogid = inode->i_gid; - ouid = inode->i_uid; - - inode->i_gid = gid; - inode->i_uid = uid; - - node->nn_flags |= IN_CHANGE; - if ((inode->i_mode & (ISUID | ISGID)) && - (ouid != uid || ogid != gid)) { - if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID)) - inode->i_mode &= ~(ISUID | ISGID); - } - DPRINTF(VNCALL, ("%s: vp %p, cred %p, td %p - ret OK\n", __func__, vp, - cred, td)); - return (0); -} - -static int -nandfs_setattr(struct vop_setattr_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *node = VTON(vp); - struct nandfs_inode *inode = &node->nn_inode; - struct vattr *vap = ap->a_vap; - struct ucred *cred = ap->a_cred; - struct thread *td = curthread; - uint32_t flags; - int error = 0; - - if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || - (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || - (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || - (vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { - DPRINTF(VNCALL, ("%s: unsettable attribute\n", __func__)); - return (EINVAL); - } - - if (vap->va_flags != VNOVAL) { - DPRINTF(VNCALL, ("%s: vp:%p td:%p flags:%lx\n", __func__, vp, - td, vap->va_flags)); - - if (vp->v_mount->mnt_flag & MNT_RDONLY) - return (EROFS); - /* - * Callers may only modify the file flags on objects they - * have VADMIN rights for. - */ - if ((error = VOP_ACCESS(vp, VADMIN, cred, td))) - return (error); - /* - * Unprivileged processes are not permitted to unset system - * flags, or modify flags if any system flags are set. - * Privileged non-jail processes may not modify system flags - * if securelevel > 0 and any existing system flags are set. - * Privileged jail processes behave like privileged non-jail - * processes if the PR_ALLOW_CHFLAGS permission bit is set; - * otherwise, they behave like unprivileged processes. - */ - - flags = inode->i_flags; - if (!priv_check_cred(cred, PRIV_VFS_SYSFLAGS)) { - if (flags & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND)) { - error = securelevel_gt(cred, 0); - if (error) - return (error); - } - /* Snapshot flag cannot be set or cleared */ - if (((vap->va_flags & SF_SNAPSHOT) != 0 && - (flags & SF_SNAPSHOT) == 0) || - ((vap->va_flags & SF_SNAPSHOT) == 0 && - (flags & SF_SNAPSHOT) != 0)) - return (EPERM); - - inode->i_flags = vap->va_flags; - } else { - if (flags & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND) || - (vap->va_flags & UF_SETTABLE) != vap->va_flags) - return (EPERM); - - flags &= SF_SETTABLE; - flags |= (vap->va_flags & UF_SETTABLE); - inode->i_flags = flags; - } - node->nn_flags |= IN_CHANGE; - if (vap->va_flags & (IMMUTABLE | APPEND)) - return (0); - } - if (inode->i_flags & (IMMUTABLE | APPEND)) - return (EPERM); - - if (vap->va_size != (u_quad_t)VNOVAL) { - DPRINTF(VNCALL, ("%s: vp:%p td:%p size:%jx\n", __func__, vp, td, - (uintmax_t)vap->va_size)); - - switch (vp->v_type) { - case VDIR: - return (EISDIR); - case VLNK: - case VREG: - if (vp->v_mount->mnt_flag & MNT_RDONLY) - return (EROFS); - if ((inode->i_flags & SF_SNAPSHOT) != 0) - return (EPERM); - break; - default: - return (0); - } - - if (vap->va_size > node->nn_nandfsdev->nd_maxfilesize) - return (EFBIG); - - KASSERT((vp->v_type == VREG), ("Set size %d", vp->v_type)); - nandfs_truncate(vp, vap->va_size); - node->nn_flags |= IN_CHANGE; - - return (0); - } - - if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) { - if (vp->v_mount->mnt_flag & MNT_RDONLY) - return (EROFS); - DPRINTF(VNCALL, ("%s: vp:%p td:%p uid/gid %x/%x\n", __func__, - vp, td, vap->va_uid, vap->va_gid)); - error = nandfs_chown(vp, vap->va_uid, vap->va_gid, cred, td); - if (error) - return (error); - } - - if (vap->va_mode != (mode_t)VNOVAL) { - if (vp->v_mount->mnt_flag & MNT_RDONLY) - return (EROFS); - DPRINTF(VNCALL, ("%s: vp:%p td:%p mode %x\n", __func__, vp, td, - vap->va_mode)); - - error = nandfs_chmod(vp, (int)vap->va_mode, cred, td); - if (error) - return (error); - } - if (vap->va_atime.tv_sec != VNOVAL || - vap->va_mtime.tv_sec != VNOVAL || - vap->va_birthtime.tv_sec != VNOVAL) { - DPRINTF(VNCALL, ("%s: vp:%p td:%p time a/m/b %jx/%jx/%jx\n", - __func__, vp, td, (uintmax_t)vap->va_atime.tv_sec, - (uintmax_t)vap->va_mtime.tv_sec, - (uintmax_t)vap->va_birthtime.tv_sec)); - - if (vap->va_atime.tv_sec != VNOVAL) - node->nn_flags |= IN_ACCESS; - if (vap->va_mtime.tv_sec != VNOVAL) - node->nn_flags |= IN_CHANGE | IN_UPDATE; - if (vap->va_birthtime.tv_sec != VNOVAL) - node->nn_flags |= IN_MODIFIED; - nandfs_itimes(vp); - return (0); - } - - return (0); -} - -static int -nandfs_open(struct vop_open_args *ap) -{ - struct nandfs_node *node = VTON(ap->a_vp); - uint64_t filesize; - - DPRINTF(VNCALL, ("nandfs_open called ap->a_mode %x\n", ap->a_mode)); - - if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) - return (EOPNOTSUPP); - - if ((node->nn_inode.i_flags & APPEND) && - (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE) - return (EPERM); - - filesize = node->nn_inode.i_size; - vnode_create_vobject(ap->a_vp, filesize, ap->a_td); - - return (0); -} - -static int -nandfs_close(struct vop_close_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *node = VTON(vp); - - DPRINTF(VNCALL, ("%s: vp %p node %p\n", __func__, vp, node)); - - mtx_lock(&vp->v_interlock); - if (vp->v_usecount > 1) - nandfs_itimes_locked(vp); - mtx_unlock(&vp->v_interlock); - - return (0); -} - -static int -nandfs_check_possible(struct vnode *vp, struct vattr *vap, mode_t mode) -{ - - /* Check if we are allowed to write */ - switch (vap->va_type) { - case VDIR: - case VLNK: - case VREG: - /* - * Normal nodes: check if we're on a read-only mounted - * filingsystem and bomb out if we're trying to write. - */ - if ((mode & VMODIFY_PERMS) && (vp->v_mount->mnt_flag & MNT_RDONLY)) - return (EROFS); - break; - case VBLK: - case VCHR: - case VSOCK: - case VFIFO: - /* - * Special nodes: even on read-only mounted filingsystems - * these are allowed to be written to if permissions allow. - */ - break; - default: - /* No idea what this is */ - return (EINVAL); - } - - /* No one may write immutable files */ - if ((mode & VWRITE) && (VTON(vp)->nn_inode.i_flags & IMMUTABLE)) - return (EPERM); - - return (0); -} - -static int -nandfs_check_permitted(struct vnode *vp, struct vattr *vap, mode_t mode, - struct ucred *cred) -{ - - return (vaccess(vp->v_type, vap->va_mode, vap->va_uid, vap->va_gid, mode, - cred, NULL)); -} - -static int -nandfs_advlock(struct vop_advlock_args *ap) -{ - struct nandfs_node *nvp; - quad_t size; - - nvp = VTON(ap->a_vp); - size = nvp->nn_inode.i_size; - return (lf_advlock(ap, &(nvp->nn_lockf), size)); -} - -static int -nandfs_access(struct vop_access_args *ap) -{ - struct vnode *vp = ap->a_vp; - accmode_t accmode = ap->a_accmode; - struct ucred *cred = ap->a_cred; - struct vattr vap; - int error; - - DPRINTF(VNCALL, ("%s: vp:%p mode: %x\n", __func__, vp, accmode)); - - error = VOP_GETATTR(vp, &vap, NULL); - if (error) - return (error); - - error = nandfs_check_possible(vp, &vap, accmode); - if (error) - return (error); - - error = nandfs_check_permitted(vp, &vap, accmode, cred); - - return (error); -} - -static int -nandfs_print(struct vop_print_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *nvp = VTON(vp); - - printf("\tvp=%p, nandfs_node=%p\n", vp, nvp); - printf("nandfs inode %#jx\n", (uintmax_t)nvp->nn_ino); - printf("flags = 0x%b\n", (u_int)nvp->nn_flags, PRINT_NODE_FLAGS); - - return (0); -} - -static void -nandfs_read_filebuf(struct nandfs_node *node, struct buf *bp) -{ - struct nandfs_device *nandfsdev = node->nn_nandfsdev; - struct buf *nbp; - nandfs_daddr_t vblk, pblk; - nandfs_lbn_t from; - uint32_t blocksize; - int error = 0; - int blk2dev = nandfsdev->nd_blocksize / DEV_BSIZE; - - /* - * Translate all the block sectors into a series of buffers to read - * asynchronously from the nandfs device. Note that this lookup may - * induce readin's too. - */ - - blocksize = nandfsdev->nd_blocksize; - if (bp->b_bcount / blocksize != 1) - panic("invalid b_count in bp %p\n", bp); - - from = bp->b_blkno; - - DPRINTF(READ, ("\tread in from inode %#jx blkno %#jx" - " count %#lx\n", (uintmax_t)node->nn_ino, from, - bp->b_bcount)); - - /* Get virtual block numbers for the vnode's buffer span */ - error = nandfs_bmap_lookup(node, from, &vblk); - if (error) { - bp->b_error = EINVAL; - bp->b_ioflags |= BIO_ERROR; - bufdone(bp); - return; - } - - /* Translate virtual block numbers to physical block numbers */ - error = nandfs_vtop(node, vblk, &pblk); - if (error) { - bp->b_error = EINVAL; - bp->b_ioflags |= BIO_ERROR; - bufdone(bp); - return; - } - - /* Issue translated blocks */ - bp->b_resid = bp->b_bcount; - - /* Note virtual block 0 marks not mapped */ - if (vblk == 0) { - vfs_bio_clrbuf(bp); - bufdone(bp); - return; - } - - nbp = bp; - nbp->b_blkno = pblk * blk2dev; - bp->b_iooffset = dbtob(nbp->b_blkno); - MPASS(bp->b_iooffset >= 0); - BO_STRATEGY(&nandfsdev->nd_devvp->v_bufobj, nbp); - nandfs_vblk_set(bp, vblk); - DPRINTF(READ, ("read_filebuf : ino %#jx blk %#jx -> " - "%#jx -> %#jx [bp %p]\n", (uintmax_t)node->nn_ino, - (uintmax_t)(from), (uintmax_t)vblk, - (uintmax_t)pblk, nbp)); -} - -static void -nandfs_write_filebuf(struct nandfs_node *node, struct buf *bp) -{ - struct nandfs_device *nandfsdev = node->nn_nandfsdev; - - bp->b_iooffset = dbtob(bp->b_blkno); - MPASS(bp->b_iooffset >= 0); - BO_STRATEGY(&nandfsdev->nd_devvp->v_bufobj, bp); -} - -static int -nandfs_strategy(struct vop_strategy_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct buf *bp = ap->a_bp; - struct nandfs_node *node = VTON(vp); - - - /* check if we ought to be here */ - KASSERT((vp->v_type != VBLK && vp->v_type != VCHR), - ("nandfs_strategy on type %d", vp->v_type)); - - /* Translate if needed and pass on */ - if (bp->b_iocmd == BIO_READ) { - nandfs_read_filebuf(node, bp); - return (0); - } - - /* Send to segment collector */ - nandfs_write_filebuf(node, bp); - return (0); -} - -static int -nandfs_readdir(struct vop_readdir_args *ap) -{ - struct uio *uio = ap->a_uio; - struct vnode *vp = ap->a_vp; - struct nandfs_node *node = VTON(vp); - struct nandfs_dir_entry *ndirent; - struct dirent dirent; - struct buf *bp; - uint64_t file_size, diroffset, transoffset, blkoff; - uint64_t blocknr; - uint32_t blocksize = node->nn_nandfsdev->nd_blocksize; - uint8_t *pos, name_len; - int error; - - DPRINTF(READDIR, ("nandfs_readdir called\n")); - - if (vp->v_type != VDIR) - return (ENOTDIR); - - file_size = node->nn_inode.i_size; - DPRINTF(READDIR, ("nandfs_readdir filesize %jd resid %zd\n", - (uintmax_t)file_size, uio->uio_resid )); - - /* We are called just as long as we keep on pushing data in */ - error = 0; - if ((uio->uio_offset < file_size) && - (uio->uio_resid >= sizeof(struct dirent))) { - diroffset = uio->uio_offset; - transoffset = diroffset; - - blocknr = diroffset / blocksize; - blkoff = diroffset % blocksize; - error = nandfs_bread(node, blocknr, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (EIO); - } - while (diroffset < file_size) { - DPRINTF(READDIR, ("readdir : offset = %"PRIu64"\n", - diroffset)); - if (blkoff >= blocksize) { - blkoff = 0; blocknr++; - brelse(bp); - error = nandfs_bread(node, blocknr, NOCRED, 0, - &bp); - if (error) { - brelse(bp); - return (EIO); - } - } - - /* Read in one dirent */ - pos = (uint8_t *)bp->b_data + blkoff; - ndirent = (struct nandfs_dir_entry *)pos; - - name_len = ndirent->name_len; - memset(&dirent, 0, sizeof(dirent)); - dirent.d_fileno = ndirent->inode; - if (dirent.d_fileno) { - dirent.d_type = ndirent->file_type; - dirent.d_namlen = name_len; - strncpy(dirent.d_name, ndirent->name, name_len); - dirent.d_reclen = GENERIC_DIRSIZ(&dirent); - /* NOTE: d_off is the offset of the *next* entry. */ - dirent.d_off = diroffset + ndirent->rec_len; - dirent_terminate(&dirent); - DPRINTF(READDIR, ("copying `%*.*s`\n", name_len, - name_len, dirent.d_name)); - } - - /* - * If there isn't enough space in the uio to return a - * whole dirent, break off read - */ - if (uio->uio_resid < GENERIC_DIRSIZ(&dirent)) - break; - - /* Transfer */ - if (dirent.d_fileno) - uiomove(&dirent, dirent.d_reclen, uio); - - /* Advance */ - diroffset += ndirent->rec_len; - blkoff += ndirent->rec_len; - - /* Remember the last entry we transferred */ - transoffset = diroffset; - } - brelse(bp); - - /* Pass on last transferred offset */ - uio->uio_offset = transoffset; - } - - if (ap->a_eofflag) - *ap->a_eofflag = (uio->uio_offset >= file_size); - - return (error); -} - -static int -nandfs_dirempty(struct vnode *dvp, uint64_t parentino, struct ucred *cred) -{ - struct nandfs_node *dnode = VTON(dvp); - struct nandfs_dir_entry *dirent; - uint64_t file_size = dnode->nn_inode.i_size; - uint64_t blockcount = dnode->nn_inode.i_blocks; - uint64_t blocknr; - uint32_t blocksize = dnode->nn_nandfsdev->nd_blocksize; - uint32_t limit; - uint32_t off; - uint8_t *pos; - struct buf *bp; - int error; - - DPRINTF(LOOKUP, ("%s: dvp %p parentino %#jx cred %p\n", __func__, dvp, - (uintmax_t)parentino, cred)); - - KASSERT((file_size != 0), ("nandfs_dirempty for NULL dir %p", dvp)); - - blocknr = 0; - while (blocknr < blockcount) { - error = nandfs_bread(dnode, blocknr, NOCRED, 0, &bp); - if (error) { - brelse(bp); - return (0); - } - - pos = (uint8_t *)bp->b_data; - off = 0; - - if (blocknr == (blockcount - 1)) - limit = file_size % blocksize; - else - limit = blocksize; - - while (off < limit) { - dirent = (struct nandfs_dir_entry *)(pos + off); - off += dirent->rec_len; - - if (dirent->inode == 0) - continue; - - switch (dirent->name_len) { - case 0: - break; - case 1: - if (dirent->name[0] != '.') - goto notempty; - - KASSERT(dirent->inode == dnode->nn_ino, - (".'s inode does not match dir")); - break; - case 2: - if (dirent->name[0] != '.' && - dirent->name[1] != '.') - goto notempty; - - KASSERT(dirent->inode == parentino, - ("..'s inode does not match parent")); - break; - default: - goto notempty; - } - } - - brelse(bp); - blocknr++; - } - - return (1); -notempty: - brelse(bp); - return (0); -} - -static int -nandfs_link(struct vop_link_args *ap) -{ - struct vnode *tdvp = ap->a_tdvp; - struct vnode *vp = ap->a_vp; - struct componentname *cnp = ap->a_cnp; - struct nandfs_node *node = VTON(vp); - struct nandfs_inode *inode = &node->nn_inode; - int error; - - if (inode->i_links_count >= NANDFS_LINK_MAX) - return (EMLINK); - - if (inode->i_flags & (IMMUTABLE | APPEND)) - return (EPERM); - - /* Update link count */ - inode->i_links_count++; - - /* Add dir entry */ - error = nandfs_add_dirent(tdvp, node->nn_ino, cnp->cn_nameptr, - cnp->cn_namelen, IFTODT(inode->i_mode)); - if (error) { - inode->i_links_count--; - } - - node->nn_flags |= IN_CHANGE; - nandfs_itimes(vp); - DPRINTF(VNCALL, ("%s: tdvp %p vp %p cnp %p\n", - __func__, tdvp, vp, cnp)); - - return (0); -} - -static int -nandfs_create(struct vop_create_args *ap) -{ - struct vnode *dvp = ap->a_dvp; - struct vnode **vpp = ap->a_vpp; - struct componentname *cnp = ap->a_cnp; - uint16_t mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode); - struct nandfs_node *dir_node = VTON(dvp); - struct nandfsmount *nmp = dir_node->nn_nmp; - struct nandfs_node *node; - int error; - - DPRINTF(VNCALL, ("%s: dvp %p\n", __func__, dvp)); - - if (nandfs_fs_full(dir_node->nn_nandfsdev)) - return (ENOSPC); - - /* Create new vnode/inode */ - error = nandfs_node_create(nmp, &node, mode); - if (error) - return (error); - node->nn_inode.i_gid = dir_node->nn_inode.i_gid; - node->nn_inode.i_uid = cnp->cn_cred->cr_uid; - - /* Add new dir entry */ - error = nandfs_add_dirent(dvp, node->nn_ino, cnp->cn_nameptr, - cnp->cn_namelen, IFTODT(mode)); - if (error) { - if (nandfs_node_destroy(node)) { - nandfs_error("%s: error destroying node %p\n", - __func__, node); - } - return (error); - } - *vpp = NTOV(node); - if ((cnp->cn_flags & MAKEENTRY) != 0) - cache_enter(dvp, *vpp, cnp); - - DPRINTF(VNCALL, ("created file vp %p nandnode %p ino %jx\n", *vpp, node, - (uintmax_t)node->nn_ino)); - return (0); -} - -static int -nandfs_remove(struct vop_remove_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct vnode *dvp = ap->a_dvp; - struct nandfs_node *node = VTON(vp); - struct nandfs_node *dnode = VTON(dvp); - struct componentname *cnp = ap->a_cnp; - - DPRINTF(VNCALL, ("%s: dvp %p vp %p nandnode %p ino %#jx link %d\n", - __func__, dvp, vp, node, (uintmax_t)node->nn_ino, - node->nn_inode.i_links_count)); - - if (vp->v_type == VDIR) - return (EISDIR); - - /* Files marked as immutable or append-only cannot be deleted. */ - if ((node->nn_inode.i_flags & (IMMUTABLE | APPEND | NOUNLINK)) || - (dnode->nn_inode.i_flags & APPEND)) - return (EPERM); - - nandfs_remove_dirent(dvp, node, cnp); - node->nn_inode.i_links_count--; - node->nn_flags |= IN_CHANGE; - - return (0); -} - -/* - * Check if source directory is in the path of the target directory. - * Target is supplied locked, source is unlocked. - * The target is always vput before returning. - */ -static int -nandfs_checkpath(struct nandfs_node *src, struct nandfs_node *dest, - struct ucred *cred) -{ - struct vnode *vp; - int error, rootino; - struct nandfs_dir_entry dirent; - - vp = NTOV(dest); - if (src->nn_ino == dest->nn_ino) { - error = EEXIST; - goto out; - } - rootino = NANDFS_ROOT_INO; - error = 0; - if (dest->nn_ino == rootino) - goto out; - - for (;;) { - if (vp->v_type != VDIR) { - error = ENOTDIR; - break; - } - - error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirent, - NANDFS_DIR_REC_LEN(2), (off_t)0, UIO_SYSSPACE, - IO_NODELOCKED | IO_NOMACCHECK, cred, NOCRED, - NULL, NULL); - if (error != 0) - break; - if (dirent.name_len != 2 || - dirent.name[0] != '.' || - dirent.name[1] != '.') { - error = ENOTDIR; - break; - } - if (dirent.inode == src->nn_ino) { - error = EINVAL; - break; - } - if (dirent.inode == rootino) - break; - vput(vp); - if ((error = VFS_VGET(vp->v_mount, dirent.inode, - LK_EXCLUSIVE, &vp)) != 0) { - vp = NULL; - break; - } - } - -out: - if (error == ENOTDIR) - printf("checkpath: .. not a directory\n"); - if (vp != NULL) - vput(vp); - return (error); -} - -static int -nandfs_rename(struct vop_rename_args *ap) -{ - struct vnode *tvp = ap->a_tvp; - struct vnode *tdvp = ap->a_tdvp; - struct vnode *fvp = ap->a_fvp; - struct vnode *fdvp = ap->a_fdvp; - struct componentname *tcnp = ap->a_tcnp; - struct componentname *fcnp = ap->a_fcnp; - int doingdirectory = 0, oldparent = 0, newparent = 0; - int error = 0; - - struct nandfs_node *fdnode, *fnode, *fnode1; - struct nandfs_node *tdnode = VTON(tdvp); - struct nandfs_node *tnode; - - uint32_t tdflags, fflags, fdflags; - uint16_t mode; - - DPRINTF(VNCALL, ("%s: fdvp:%p fvp:%p tdvp:%p tdp:%p\n", __func__, fdvp, - fvp, tdvp, tvp)); - - /* - * Check for cross-device rename. - */ - if ((fvp->v_mount != tdvp->v_mount) || - (tvp && (fvp->v_mount != tvp->v_mount))) { - error = EXDEV; -abortit: - if (tdvp == tvp) - vrele(tdvp); - else - vput(tdvp); - if (tvp) - vput(tvp); - vrele(fdvp); - vrele(fvp); - return (error); - } - - tdflags = tdnode->nn_inode.i_flags; - if (tvp && - ((VTON(tvp)->nn_inode.i_flags & (NOUNLINK | IMMUTABLE | APPEND)) || - (tdflags & APPEND))) { - error = EPERM; - goto abortit; - } - - /* - * Renaming a file to itself has no effect. The upper layers should - * not call us in that case. Temporarily just warn if they do. - */ - if (fvp == tvp) { - printf("nandfs_rename: fvp == tvp (can't happen)\n"); - error = 0; - goto abortit; - } - - if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0) - goto abortit; - - fdnode = VTON(fdvp); - fnode = VTON(fvp); - - if (fnode->nn_inode.i_links_count >= NANDFS_LINK_MAX) { - VOP_UNLOCK(fvp, 0); - error = EMLINK; - goto abortit; - } - - fflags = fnode->nn_inode.i_flags; - fdflags = fdnode->nn_inode.i_flags; - - if ((fflags & (NOUNLINK | IMMUTABLE | APPEND)) || - (fdflags & APPEND)) { - VOP_UNLOCK(fvp, 0); - error = EPERM; - goto abortit; - } - - mode = fnode->nn_inode.i_mode; - if ((mode & S_IFMT) == S_IFDIR) { - /* - * Avoid ".", "..", and aliases of "." for obvious reasons. - */ - - if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') || - (fdvp == fvp) || - ((fcnp->cn_flags | tcnp->cn_flags) & ISDOTDOT) || - (fnode->nn_flags & IN_RENAME)) { - VOP_UNLOCK(fvp, 0); - error = EINVAL; - goto abortit; - } - fnode->nn_flags |= IN_RENAME; - doingdirectory = 1; - DPRINTF(VNCALL, ("%s: doingdirectory dvp %p\n", __func__, - tdvp)); - oldparent = fdnode->nn_ino; - } - - vrele(fdvp); - - tnode = NULL; - if (tvp) - tnode = VTON(tvp); - - /* - * Bump link count on fvp while we are moving stuff around. If we - * crash before completing the work, the link count may be wrong - * but correctable. - */ - fnode->nn_inode.i_links_count++; - - /* Check for in path moving XXX */ - error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_thread); - VOP_UNLOCK(fvp, 0); - if (oldparent != tdnode->nn_ino) - newparent = tdnode->nn_ino; - if (doingdirectory && newparent) { - if (error) /* write access check above */ - goto bad; - if (tnode != NULL) - vput(tvp); - - error = nandfs_checkpath(fnode, tdnode, tcnp->cn_cred); - if (error) - goto out; - - VREF(tdvp); - error = relookup(tdvp, &tvp, tcnp); - if (error) - goto out; - vrele(tdvp); - tdnode = VTON(tdvp); - tnode = NULL; - if (tvp) - tnode = VTON(tvp); - } - - /* - * If the target doesn't exist, link the target to the source and - * unlink the source. Otherwise, rewrite the target directory to - * reference the source and remove the original entry. - */ - - if (tvp == NULL) { - /* - * Account for ".." in new directory. - */ - if (doingdirectory && fdvp != tdvp) - tdnode->nn_inode.i_links_count++; - - DPRINTF(VNCALL, ("%s: new entry in dvp:%p\n", __func__, tdvp)); - /* - * Add name in new directory. - */ - error = nandfs_add_dirent(tdvp, fnode->nn_ino, tcnp->cn_nameptr, - tcnp->cn_namelen, IFTODT(fnode->nn_inode.i_mode)); - if (error) { - if (doingdirectory && fdvp != tdvp) - tdnode->nn_inode.i_links_count--; - goto bad; - } - - vput(tdvp); - } else { - /* - * If the parent directory is "sticky", then the user must - * own the parent directory, or the destination of the rename, - * otherwise the destination may not be changed (except by - * root). This implements append-only directories. - */ - if ((tdnode->nn_inode.i_mode & S_ISTXT) && - tcnp->cn_cred->cr_uid != 0 && - tcnp->cn_cred->cr_uid != tdnode->nn_inode.i_uid && - tnode->nn_inode.i_uid != tcnp->cn_cred->cr_uid) { - error = EPERM; - goto bad; - } - /* - * Target must be empty if a directory and have no links - * to it. Also, ensure source and target are compatible - * (both directories, or both not directories). - */ - mode = tnode->nn_inode.i_mode; - if ((mode & S_IFMT) == S_IFDIR) { - if (!nandfs_dirempty(tvp, tdnode->nn_ino, - tcnp->cn_cred)) { - error = ENOTEMPTY; - goto bad; - } - if (!doingdirectory) { - error = ENOTDIR; - goto bad; - } - /* - * Update name cache since directory is going away. - */ - cache_purge(tdvp); - } else if (doingdirectory) { - error = EISDIR; - goto bad; - } - - DPRINTF(VNCALL, ("%s: update entry dvp:%p\n", __func__, tdvp)); - /* - * Change name tcnp in tdvp to point at fvp. - */ - error = nandfs_update_dirent(tdvp, fnode, tnode); - if (error) - goto bad; - - if (doingdirectory && !newparent) - tdnode->nn_inode.i_links_count--; - - vput(tdvp); - - tnode->nn_inode.i_links_count--; - vput(tvp); - tnode = NULL; - } - - /* - * Unlink the source. - */ - fcnp->cn_flags &= ~MODMASK; - fcnp->cn_flags |= LOCKPARENT | LOCKLEAF; - VREF(fdvp); - error = relookup(fdvp, &fvp, fcnp); - if (error == 0) - vrele(fdvp); - if (fvp != NULL) { - fnode1 = VTON(fvp); - fdnode = VTON(fdvp); - } else { - /* - * From name has disappeared. - */ - if (doingdirectory) - panic("nandfs_rename: lost dir entry"); - vrele(ap->a_fvp); - return (0); - } - - DPRINTF(VNCALL, ("%s: unlink source fnode:%p\n", __func__, fnode)); - - /* - * Ensure that the directory entry still exists and has not - * changed while the new name has been entered. If the source is - * a file then the entry may have been unlinked or renamed. In - * either case there is no further work to be done. If the source - * is a directory then it cannot have been rmdir'ed; its link - * count of three would cause a rmdir to fail with ENOTEMPTY. - * The IN_RENAME flag ensures that it cannot be moved by another - * rename. - */ - if (fnode != fnode1) { - if (doingdirectory) - panic("nandfs: lost dir entry"); - } else { - /* - * If the source is a directory with a - * new parent, the link count of the old - * parent directory must be decremented - * and ".." set to point to the new parent. - */ - if (doingdirectory && newparent) { - DPRINTF(VNCALL, ("%s: new parent %#jx -> %#jx\n", - __func__, (uintmax_t) oldparent, - (uintmax_t) newparent)); - error = nandfs_update_parent_dir(fvp, newparent); - if (!error) { - fdnode->nn_inode.i_links_count--; - fdnode->nn_flags |= IN_CHANGE; - } - } - error = nandfs_remove_dirent(fdvp, fnode, fcnp); - if (!error) { - fnode->nn_inode.i_links_count--; - fnode->nn_flags |= IN_CHANGE; - } - fnode->nn_flags &= ~IN_RENAME; - } - if (fdnode) - vput(fdvp); - if (fnode) - vput(fvp); - vrele(ap->a_fvp); - return (error); - -bad: - DPRINTF(VNCALL, ("%s: error:%d\n", __func__, error)); - if (tnode) - vput(NTOV(tnode)); - vput(NTOV(tdnode)); -out: - if (doingdirectory) - fnode->nn_flags &= ~IN_RENAME; - if (vn_lock(fvp, LK_EXCLUSIVE) == 0) { - fnode->nn_inode.i_links_count--; - fnode->nn_flags |= IN_CHANGE; - fnode->nn_flags &= ~IN_RENAME; - vput(fvp); - } else - vrele(fvp); - return (error); -} - -static int -nandfs_mkdir(struct vop_mkdir_args *ap) -{ - struct vnode *dvp = ap->a_dvp; - struct vnode **vpp = ap->a_vpp; - struct componentname *cnp = ap->a_cnp; - struct nandfs_node *dir_node = VTON(dvp); - struct nandfs_inode *dir_inode = &dir_node->nn_inode; - struct nandfs_node *node; - struct nandfsmount *nmp = dir_node->nn_nmp; - uint16_t mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode); - int error; - - DPRINTF(VNCALL, ("%s: dvp %p\n", __func__, dvp)); - - if (nandfs_fs_full(dir_node->nn_nandfsdev)) - return (ENOSPC); - - if (dir_inode->i_links_count >= NANDFS_LINK_MAX) - return (EMLINK); - - error = nandfs_node_create(nmp, &node, mode); - if (error) - return (error); - - node->nn_inode.i_gid = dir_node->nn_inode.i_gid; - node->nn_inode.i_uid = cnp->cn_cred->cr_uid; - - *vpp = NTOV(node); - - error = nandfs_add_dirent(dvp, node->nn_ino, cnp->cn_nameptr, - cnp->cn_namelen, IFTODT(mode)); - if (error) { - vput(*vpp); - return (error); - } - - dir_node->nn_inode.i_links_count++; - dir_node->nn_flags |= IN_CHANGE; - - error = nandfs_init_dir(NTOV(node), node->nn_ino, dir_node->nn_ino); - if (error) { - vput(NTOV(node)); - return (error); - } - - DPRINTF(VNCALL, ("created dir vp %p nandnode %p ino %jx\n", *vpp, node, - (uintmax_t)node->nn_ino)); - return (0); -} - -static int -nandfs_mknod(struct vop_mknod_args *ap) -{ - struct vnode *dvp = ap->a_dvp; - struct vnode **vpp = ap->a_vpp; - struct vattr *vap = ap->a_vap; - uint16_t mode = MAKEIMODE(vap->va_type, vap->va_mode); - struct componentname *cnp = ap->a_cnp; - struct nandfs_node *dir_node = VTON(dvp); - struct nandfsmount *nmp = dir_node->nn_nmp; - struct nandfs_node *node; - int error; - - if (nandfs_fs_full(dir_node->nn_nandfsdev)) - return (ENOSPC); - - error = nandfs_node_create(nmp, &node, mode); - if (error) - return (error); - node->nn_inode.i_gid = dir_node->nn_inode.i_gid; - node->nn_inode.i_uid = cnp->cn_cred->cr_uid; - if (vap->va_rdev != VNOVAL) - node->nn_inode.i_special = vap->va_rdev; - - *vpp = NTOV(node); - - if (nandfs_add_dirent(dvp, node->nn_ino, cnp->cn_nameptr, - cnp->cn_namelen, IFTODT(mode))) { - vput(*vpp); - return (ENOTDIR); - } - - node->nn_flags |= IN_ACCESS | IN_CHANGE | IN_UPDATE; - - return (0); -} - -static int -nandfs_symlink(struct vop_symlink_args *ap) -{ - struct vnode **vpp = ap->a_vpp; - struct vnode *dvp = ap->a_dvp; - uint16_t mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode); - struct componentname *cnp = ap->a_cnp; - struct nandfs_node *dir_node = VTON(dvp); - struct nandfsmount *nmp = dir_node->nn_nmp; - struct nandfs_node *node; - int len, error; - - if (nandfs_fs_full(dir_node->nn_nandfsdev)) - return (ENOSPC); - - error = nandfs_node_create(nmp, &node, S_IFLNK | mode); - if (error) - return (error); - node->nn_inode.i_gid = dir_node->nn_inode.i_gid; - node->nn_inode.i_uid = cnp->cn_cred->cr_uid; - - *vpp = NTOV(node); - - if (nandfs_add_dirent(dvp, node->nn_ino, cnp->cn_nameptr, - cnp->cn_namelen, IFTODT(mode))) { - vput(*vpp); - return (ENOTDIR); - } - - - len = strlen(ap->a_target); - error = vn_rdwr(UIO_WRITE, *vpp, __DECONST(void *, ap->a_target), - len, (off_t)0, UIO_SYSSPACE, IO_NODELOCKED | IO_NOMACCHECK, - cnp->cn_cred, NOCRED, NULL, NULL); - if (error) - vput(*vpp); - - return (error); -} - -static int -nandfs_readlink(struct vop_readlink_args *ap) -{ - struct vnode *vp = ap->a_vp; - - return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred)); -} - -static int -nandfs_rmdir(struct vop_rmdir_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct vnode *dvp = ap->a_dvp; - struct componentname *cnp = ap->a_cnp; - struct nandfs_node *node, *dnode; - uint32_t dflag, flag; - int error = 0; - - node = VTON(vp); - dnode = VTON(dvp); - - /* Files marked as immutable or append-only cannot be deleted. */ - if ((node->nn_inode.i_flags & (IMMUTABLE | APPEND | NOUNLINK)) || - (dnode->nn_inode.i_flags & APPEND)) - return (EPERM); - - DPRINTF(VNCALL, ("%s: dvp %p vp %p nandnode %p ino %#jx\n", __func__, - dvp, vp, node, (uintmax_t)node->nn_ino)); - - if (node->nn_inode.i_links_count < 2) - return (EINVAL); - - if (!nandfs_dirempty(vp, dnode->nn_ino, cnp->cn_cred)) - return (ENOTEMPTY); - - /* Files marked as immutable or append-only cannot be deleted. */ - dflag = dnode->nn_inode.i_flags; - flag = node->nn_inode.i_flags; - if ((dflag & APPEND) || - (flag & (NOUNLINK | IMMUTABLE | APPEND))) { - return (EPERM); - } - - if (vp->v_mountedhere != 0) - return (EINVAL); - - nandfs_remove_dirent(dvp, node, cnp); - dnode->nn_inode.i_links_count -= 1; - dnode->nn_flags |= IN_CHANGE; - - cache_purge(dvp); - - error = nandfs_truncate(vp, (uint64_t)0); - if (error) - return (error); - - node->nn_inode.i_links_count -= 2; - node->nn_flags |= IN_CHANGE; - - cache_purge(vp); - - return (error); -} - -static int -nandfs_fsync(struct vop_fsync_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *node = VTON(vp); - int locked; - - DPRINTF(VNCALL, ("%s: vp %p nandnode %p ino %#jx\n", __func__, vp, - node, (uintmax_t)node->nn_ino)); - - /* - * Start syncing vnode only if inode was modified or - * there are some dirty buffers - */ - if (VTON(vp)->nn_flags & IN_MODIFIED || - vp->v_bufobj.bo_dirty.bv_cnt) { - locked = VOP_ISLOCKED(vp); - VOP_UNLOCK(vp, 0); - nandfs_wakeup_wait_sync(node->nn_nandfsdev, SYNCER_FSYNC); - VOP_LOCK(vp, locked | LK_RETRY); - } - - return (0); -} - -static int -nandfs_bmap(struct vop_bmap_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *nnode = VTON(vp); - struct nandfs_device *nandfsdev = nnode->nn_nandfsdev; - nandfs_daddr_t l2vmap, v2pmap; - int error; - int blk2dev = nandfsdev->nd_blocksize / DEV_BSIZE; - - DPRINTF(VNCALL, ("%s: vp %p nandnode %p ino %#jx\n", __func__, vp, - nnode, (uintmax_t)nnode->nn_ino)); - - if (ap->a_bop != NULL) - *ap->a_bop = &nandfsdev->nd_devvp->v_bufobj; - if (ap->a_bnp == NULL) - return (0); - if (ap->a_runp != NULL) - *ap->a_runp = 0; - if (ap->a_runb != NULL) - *ap->a_runb = 0; - - /* - * Translate all the block sectors into a series of buffers to read - * asynchronously from the nandfs device. Note that this lookup may - * induce readin's too. - */ - - /* Get virtual block numbers for the vnode's buffer span */ - error = nandfs_bmap_lookup(nnode, ap->a_bn, &l2vmap); - if (error) - return (-1); - - /* Translate virtual block numbers to physical block numbers */ - error = nandfs_vtop(nnode, l2vmap, &v2pmap); - if (error) - return (-1); - - /* Note virtual block 0 marks not mapped */ - if (l2vmap == 0) - *ap->a_bnp = -1; - else - *ap->a_bnp = v2pmap * blk2dev; /* in DEV_BSIZE */ - - DPRINTF(VNCALL, ("%s: vp %p nandnode %p ino %#jx lblk %jx -> blk %jx\n", - __func__, vp, nnode, (uintmax_t)nnode->nn_ino, (uintmax_t)ap->a_bn, - (uintmax_t)*ap->a_bnp )); - - return (0); -} - -static void -nandfs_force_syncer(struct nandfsmount *nmp) -{ - - nmp->nm_flags |= NANDFS_FORCE_SYNCER; - nandfs_wakeup_wait_sync(nmp->nm_nandfsdev, SYNCER_FFORCE); -} - -static int -nandfs_ioctl(struct vop_ioctl_args *ap) -{ - struct vnode *vp = ap->a_vp; - u_long command = ap->a_command; - caddr_t data = ap->a_data; - struct nandfs_node *node = VTON(vp); - struct nandfs_device *nandfsdev = node->nn_nandfsdev; - struct nandfsmount *nmp = node->nn_nmp; - uint64_t *tab, *cno; - struct nandfs_seg_stat *nss; - struct nandfs_cpmode *ncpm; - struct nandfs_argv *nargv; - struct nandfs_cpstat *ncp; - int error; - - DPRINTF(VNCALL, ("%s: %x\n", __func__, (uint32_t)command)); - - error = priv_check(ap->a_td, PRIV_VFS_MOUNT); - if (error) - return (error); - - if (nmp->nm_ronly) { - switch (command) { - case NANDFS_IOCTL_GET_FSINFO: - case NANDFS_IOCTL_GET_SUSTAT: - case NANDFS_IOCTL_GET_CPINFO: - case NANDFS_IOCTL_GET_CPSTAT: - case NANDFS_IOCTL_GET_SUINFO: - case NANDFS_IOCTL_GET_VINFO: - case NANDFS_IOCTL_GET_BDESCS: - break; - default: - return (EROFS); - } - } - - switch (command) { - case NANDFS_IOCTL_GET_FSINFO: - error = nandfs_get_fsinfo(nmp, (struct nandfs_fsinfo *)data); - break; - case NANDFS_IOCTL_GET_SUSTAT: - nss = (struct nandfs_seg_stat *)data; - error = nandfs_get_seg_stat(nandfsdev, nss); - break; - case NANDFS_IOCTL_CHANGE_CPMODE: - ncpm = (struct nandfs_cpmode *)data; - error = nandfs_chng_cpmode(nandfsdev->nd_cp_node, ncpm); - nandfs_force_syncer(nmp); - break; - case NANDFS_IOCTL_GET_CPINFO: - nargv = (struct nandfs_argv *)data; - error = nandfs_get_cpinfo_ioctl(nandfsdev->nd_cp_node, nargv); - break; - case NANDFS_IOCTL_DELETE_CP: - tab = (uint64_t *)data; - error = nandfs_delete_cp(nandfsdev->nd_cp_node, tab[0], tab[1]); - nandfs_force_syncer(nmp); - break; - case NANDFS_IOCTL_GET_CPSTAT: - ncp = (struct nandfs_cpstat *)data; - error = nandfs_get_cpstat(nandfsdev->nd_cp_node, ncp); - break; - case NANDFS_IOCTL_GET_SUINFO: - nargv = (struct nandfs_argv *)data; - error = nandfs_get_segment_info_ioctl(nandfsdev, nargv); - break; - case NANDFS_IOCTL_GET_VINFO: - nargv = (struct nandfs_argv *)data; - error = nandfs_get_dat_vinfo_ioctl(nandfsdev, nargv); - break; - case NANDFS_IOCTL_GET_BDESCS: - nargv = (struct nandfs_argv *)data; - error = nandfs_get_dat_bdescs_ioctl(nandfsdev, nargv); - break; - case NANDFS_IOCTL_SYNC: - cno = (uint64_t *)data; - nandfs_force_syncer(nmp); - *cno = nandfsdev->nd_last_cno; - error = 0; - break; - case NANDFS_IOCTL_MAKE_SNAP: - cno = (uint64_t *)data; - error = nandfs_make_snap(nandfsdev, cno); - nandfs_force_syncer(nmp); - break; - case NANDFS_IOCTL_DELETE_SNAP: - cno = (uint64_t *)data; - error = nandfs_delete_snap(nandfsdev, *cno); - nandfs_force_syncer(nmp); - break; - default: - error = ENOTTY; - break; - } - - return (error); -} - -/* - * Whiteout vnode call - */ -static int -nandfs_whiteout(struct vop_whiteout_args *ap) -{ - struct vnode *dvp = ap->a_dvp; - struct componentname *cnp = ap->a_cnp; - int error = 0; - - switch (ap->a_flags) { - case LOOKUP: - return (0); - case CREATE: - /* Create a new directory whiteout */ -#ifdef INVARIANTS - if ((cnp->cn_flags & SAVENAME) == 0) - panic("nandfs_whiteout: missing name"); -#endif - error = nandfs_add_dirent(dvp, NANDFS_WHT_INO, cnp->cn_nameptr, - cnp->cn_namelen, DT_WHT); - break; - - case DELETE: - /* Remove an existing directory whiteout */ - cnp->cn_flags &= ~DOWHITEOUT; - error = nandfs_remove_dirent(dvp, NULL, cnp); - break; - default: - panic("nandf_whiteout: unknown op: %d", ap->a_flags); - } - - return (error); -} - -static int -nandfs_pathconf(struct vop_pathconf_args *ap) -{ - int error; - - error = 0; - switch (ap->a_name) { - case _PC_LINK_MAX: - *ap->a_retval = NANDFS_LINK_MAX; - break; - case _PC_NAME_MAX: - *ap->a_retval = NANDFS_NAME_LEN; - break; - case _PC_PIPE_BUF: - if (ap->a_vp->v_type == VDIR || ap->a_vp->v_type == VFIFO) - *ap->a_retval = PIPE_BUF; - else - error = EINVAL; - break; - case _PC_CHOWN_RESTRICTED: - *ap->a_retval = 1; - break; - case _PC_NO_TRUNC: - *ap->a_retval = 1; - break; - case _PC_ALLOC_SIZE_MIN: - *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_bsize; - break; - case _PC_FILESIZEBITS: - *ap->a_retval = 64; - break; - case _PC_REC_INCR_XFER_SIZE: - *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize; - break; - case _PC_REC_MAX_XFER_SIZE: - *ap->a_retval = -1; /* means ``unlimited'' */ - break; - case _PC_REC_MIN_XFER_SIZE: - *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize; - break; - default: - error = vop_stdpathconf(ap); - break; - } - return (error); -} - -static int -nandfs_vnlock1(struct vop_lock1_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *node = VTON(vp); - int error, vi_locked; - - /* - * XXX can vnode go away while we are sleeping? - */ - vi_locked = mtx_owned(&vp->v_interlock); - if (vi_locked) - VI_UNLOCK(vp); - error = NANDFS_WRITELOCKFLAGS(node->nn_nandfsdev, - ap->a_flags & LK_NOWAIT); - if (vi_locked && !error) - VI_LOCK(vp); - if (error) - return (error); - - error = vop_stdlock(ap); - if (error) { - NANDFS_WRITEUNLOCK(node->nn_nandfsdev); - return (error); - } - - return (0); -} - -static int -nandfs_vnunlock(struct vop_unlock_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *node = VTON(vp); - int error; - - error = vop_stdunlock(ap); - if (error) - return (error); - - NANDFS_WRITEUNLOCK(node->nn_nandfsdev); - - return (0); -} - -/* - * Global vfs data structures - */ -struct vop_vector nandfs_vnodeops = { - .vop_default = &default_vnodeops, - .vop_access = nandfs_access, - .vop_advlock = nandfs_advlock, - .vop_bmap = nandfs_bmap, - .vop_close = nandfs_close, - .vop_create = nandfs_create, - .vop_fsync = nandfs_fsync, - .vop_getattr = nandfs_getattr, - .vop_inactive = nandfs_inactive, - .vop_cachedlookup = nandfs_lookup, - .vop_ioctl = nandfs_ioctl, - .vop_link = nandfs_link, - .vop_lookup = vfs_cache_lookup, - .vop_mkdir = nandfs_mkdir, - .vop_mknod = nandfs_mknod, - .vop_open = nandfs_open, - .vop_pathconf = nandfs_pathconf, - .vop_print = nandfs_print, - .vop_read = nandfs_read, - .vop_readdir = nandfs_readdir, - .vop_readlink = nandfs_readlink, - .vop_reclaim = nandfs_reclaim, - .vop_remove = nandfs_remove, - .vop_rename = nandfs_rename, - .vop_rmdir = nandfs_rmdir, - .vop_whiteout = nandfs_whiteout, - .vop_write = nandfs_write, - .vop_setattr = nandfs_setattr, - .vop_strategy = nandfs_strategy, - .vop_symlink = nandfs_symlink, - .vop_lock1 = nandfs_vnlock1, - .vop_unlock = nandfs_vnunlock, -}; - -struct vop_vector nandfs_system_vnodeops = { - .vop_default = &default_vnodeops, - .vop_close = nandfs_close, - .vop_inactive = nandfs_inactive, - .vop_reclaim = nandfs_reclaim, - .vop_strategy = nandfs_strategy, - .vop_fsync = nandfs_fsync, - .vop_bmap = nandfs_bmap, - .vop_access = VOP_PANIC, - .vop_advlock = VOP_PANIC, - .vop_create = VOP_PANIC, - .vop_getattr = VOP_PANIC, - .vop_cachedlookup = VOP_PANIC, - .vop_ioctl = VOP_PANIC, - .vop_link = VOP_PANIC, - .vop_lookup = VOP_PANIC, - .vop_mkdir = VOP_PANIC, - .vop_mknod = VOP_PANIC, - .vop_open = VOP_PANIC, - .vop_pathconf = VOP_PANIC, - .vop_print = VOP_PANIC, - .vop_read = VOP_PANIC, - .vop_readdir = VOP_PANIC, - .vop_readlink = VOP_PANIC, - .vop_remove = VOP_PANIC, - .vop_rename = VOP_PANIC, - .vop_rmdir = VOP_PANIC, - .vop_whiteout = VOP_PANIC, - .vop_write = VOP_PANIC, - .vop_setattr = VOP_PANIC, - .vop_symlink = VOP_PANIC, -}; - -static int -nandfsfifo_close(struct vop_close_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct nandfs_node *node = VTON(vp); - - DPRINTF(VNCALL, ("%s: vp %p node %p\n", __func__, vp, node)); - - mtx_lock(&vp->v_interlock); - if (vp->v_usecount > 1) - nandfs_itimes_locked(vp); - mtx_unlock(&vp->v_interlock); - - return (fifo_specops.vop_close(ap)); -} - -struct vop_vector nandfs_fifoops = { - .vop_default = &fifo_specops, - .vop_fsync = VOP_PANIC, - .vop_access = nandfs_access, - .vop_close = nandfsfifo_close, - .vop_getattr = nandfs_getattr, - .vop_inactive = nandfs_inactive, - .vop_pathconf = nandfs_pathconf, - .vop_print = nandfs_print, - .vop_read = VOP_PANIC, - .vop_reclaim = nandfs_reclaim, - .vop_setattr = nandfs_setattr, - .vop_write = VOP_PANIC, - .vop_lock1 = nandfs_vnlock1, - .vop_unlock = nandfs_vnunlock, -}; - -int -nandfs_vinit(struct vnode *vp, uint64_t ino) -{ - struct nandfs_node *node; - - ASSERT_VOP_LOCKED(vp, __func__); - - node = VTON(vp); - - /* Check if we're fetching the root */ - if (ino == NANDFS_ROOT_INO) - vp->v_vflag |= VV_ROOT; - - if (ino != NANDFS_GC_INO) - vp->v_type = IFTOVT(node->nn_inode.i_mode); - else - vp->v_type = VREG; - - if (vp->v_type == VFIFO) - vp->v_op = &nandfs_fifoops; - - return (0); -} diff --git a/sys/fs/smbfs/smbfs_io.c b/sys/fs/smbfs/smbfs_io.c index fa6a14024213..4edba5c761e7 100644 --- a/sys/fs/smbfs/smbfs_io.c +++ b/sys/fs/smbfs/smbfs_io.c @@ -375,6 +375,9 @@ smbfs_doio(struct vnode *vp, struct buf *bp, struct ucred *cr, struct thread *td */ if (error == EINTR || (!error && (bp->b_flags & B_NEEDCOMMIT))) { + int s; + + s = splbio(); bp->b_flags &= ~(B_INVAL|B_NOCACHE); if ((bp->b_flags & B_ASYNC) == 0) bp->b_flags |= B_EINTR; @@ -384,6 +387,7 @@ smbfs_doio(struct vnode *vp, struct buf *bp, struct ucred *cr, struct thread *td } if ((bp->b_flags & B_ASYNC) == 0) bp->b_flags |= B_EINTR; + splx(s); } else { if (error) { bp->b_ioflags |= BIO_ERROR; diff --git a/sys/geom/geom_flashmap.c b/sys/geom/geom_flashmap.c index ac7344a34bb6..71007a4f7936 100644 --- a/sys/geom/geom_flashmap.c +++ b/sys/geom/geom_flashmap.c @@ -43,8 +43,6 @@ __FBSDID("$FreeBSD$"); #include #include -#include - struct g_flashmap_slice { off_t sl_start; off_t sl_end; @@ -65,7 +63,6 @@ static struct { { "MMC::device", NULL } }; -static g_ioctl_t g_flashmap_ioctl; static g_taste_t g_flashmap_taste; static int g_flashmap_load(device_t dev, struct g_provider *pp, @@ -127,26 +124,6 @@ g_flashmap_modify(struct g_flashmap *gfp, struct g_geom *gp, return (0); } -static int -g_flashmap_ioctl(struct g_provider *pp, u_long cmd, void *data, int fflag, - struct thread *td) -{ - struct g_consumer *cp; - struct g_geom *gp; - - if (cmd != NAND_IO_GET_CHIP_PARAM) - return (ENOIOCTL); - - cp = LIST_FIRST(&pp->geom->consumer); - if (cp == NULL) - return (ENOIOCTL); - gp = cp->provider->geom; - if (gp->ioctl == NULL) - return (ENOIOCTL); - - return (gp->ioctl(cp->provider, cmd, data, fflag, td)); -} - static struct g_geom * g_flashmap_taste(struct g_class *mp, struct g_provider *pp, int flags) { @@ -245,7 +222,6 @@ static struct g_class g_flashmap_class = { .name = FLASHMAP_CLASS_NAME, .version = G_VERSION, .taste = g_flashmap_taste, - .ioctl = g_flashmap_ioctl, }; DECLARE_GEOM_CLASS(g_flashmap_class, g_flashmap); diff --git a/sys/modules/Makefile b/sys/modules/Makefile index a9a5c5ed98ef..876a13f19ea9 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -255,8 +255,6 @@ SUBDIR= \ ${_mwlfw} \ mxge \ my \ - ${_nandfs} \ - ${_nandsim} \ ${_nctgpio} \ ${_ndis} \ ${_netgraph} \ @@ -489,11 +487,6 @@ _mlx5ib= mlx5ib .endif .endif -.if ${MK_NAND} != "no" || defined(ALL_MODULES) -_nandfs= nandfs -_nandsim= nandsim -.endif - .if ${MK_NETGRAPH} != "no" || defined(ALL_MODULES) _netgraph= netgraph .endif diff --git a/sys/modules/nand/Makefile b/sys/modules/nand/Makefile deleted file mode 100644 index c9d9962e897f..000000000000 --- a/sys/modules/nand/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# $FreeBSD$ - -.PATH: ${SRCTOP}/sys/dev/nand - -KMOD = nand -SRCS= nand.c nand_bbt.c nand_cdev.c nand_generic.c nand_geom.c \ - nand_id.c nandbus.c nandbus_if.c nand_if.c nfc_if.c \ - nand_if.h device_if.h bus_if.h nfc_if.h nandbus_if.h - -.include diff --git a/sys/modules/nandfs/Makefile b/sys/modules/nandfs/Makefile deleted file mode 100644 index f13858c57c7b..000000000000 --- a/sys/modules/nandfs/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# $FreeBSD$ - -.PATH: ${SRCTOP}/sys/fs/nandfs - -KMOD= nandfs -SRCS= vnode_if.h opt_ddb.h \ - bmap.c nandfs_bmap.c nandfs_dir.c nandfs_subr.c nandfs_vfsops.c \ - nandfs_vnops.c nandfs_alloc.c nandfs_cpfile.c nandfs_dat.c \ - nandfs_ifile.c nandfs_segment.c nandfs_sufile.c nandfs_buffer.c \ - nandfs_cleaner.c - -.include diff --git a/sys/modules/nandsim/Makefile b/sys/modules/nandsim/Makefile deleted file mode 100644 index 4f0aeca9eb4b..000000000000 --- a/sys/modules/nandsim/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# $FreeBSD$ - -.PATH: ${SRCTOP}/sys/dev/nand - -KMOD= nandsim -SRCS= nandsim.c nandsim_chip.c nandsim_swap.c nandsim_ctrl.c nandsim_log.c\ - bus_if.h device_if.h vnode_if.h nfc_if.h nand_if.h - -.include diff --git a/sys/sys/param.h b/sys/sys/param.h index 8cc1907dc2dd..9a68762388f2 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -60,7 +60,7 @@ * in the range 5 to 9. */ #undef __FreeBSD_version -#define __FreeBSD_version 1300033 /* Master, propagated to newvers */ +#define __FreeBSD_version 1300034 /* Master, propagated to newvers */ /* * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD, diff --git a/targets/pseudo/userland/Makefile.depend b/targets/pseudo/userland/Makefile.depend index 934d7be54ed7..469d34993b46 100644 --- a/targets/pseudo/userland/Makefile.depend +++ b/targets/pseudo/userland/Makefile.depend @@ -772,15 +772,6 @@ DIRDEPS+= \ DIRDEPS+= usr.sbin/efidp .endif -.if ${MK_NAND} != "no" -DIRDEPS+= \ - sbin/nandfs \ - sbin/newfs_nandfs \ - usr.sbin/nandsim \ - usr.sbin/nandtool \ - -.endif - DIRDEPS.amd64= \ sbin/bsdlabel \ sbin/fdisk \ diff --git a/targets/pseudo/userland/lib/Makefile.depend b/targets/pseudo/userland/lib/Makefile.depend index 2139d18204ca..6e2e549278a7 100644 --- a/targets/pseudo/userland/lib/Makefile.depend +++ b/targets/pseudo/userland/lib/Makefile.depend @@ -215,10 +215,6 @@ DIRDEPS+= \ DIRDEPS+= stand/libsa32 .endif -.if ${MK_NAND} != "no" -DIRDEPS+= lib/libnandfs -.endif - .if ${MK_CASPER} != "no" DIRDEPS+= \ lib/libcasper/libcasper \ diff --git a/usr.bin/vtfontcvt/vtfontcvt.c b/usr.bin/vtfontcvt/vtfontcvt.c index e34308d5d365..70ec7cf31812 100644 --- a/usr.bin/vtfontcvt/vtfontcvt.c +++ b/usr.bin/vtfontcvt/vtfontcvt.c @@ -335,11 +335,9 @@ parse_bdf(FILE *fp, unsigned int map_idx) break; } } - } else if (strncmp(ln, "FONTBOUNDINGBOX ", 16) == 0) { - if (sscanf(ln + 16, "%d %d %d %d", &fbbw, &fbbh, &fbbox, - &fbboy) != 4) - errx(1, "invalid FONTBOUNDINGBOX at line %u", - linenum); + } else if (strncmp(ln, "FONTBOUNDINGBOX ", 16) == 0 && + sscanf(ln + 16, "%d %d %d %d", &fbbw, &fbbh, &fbbox, + &fbboy) == 4) { set_width(fbbw); set_height(fbbh); break; @@ -355,9 +353,8 @@ parse_bdf(FILE *fp, unsigned int map_idx) linenum++; ln[length - 1] = '\0'; - if (strncmp(ln, "DWIDTH ", 7) == 0) { - if (sscanf(ln + 7, "%d %d", &dwidth, &dwy) != 2) - errx(1, "invalid DWIDTH at line %u", linenum); + if (strncmp(ln, "DWIDTH ", 7) == 0 && + sscanf(ln + 7, "%d %d", &dwidth, &dwy) == 2) { if (dwy != 0 || (dwidth != fbbw && dwidth * 2 != fbbw)) errx(1, "bitmap with unsupported DWIDTH %d %d at line %u", dwidth, dwy, linenum); diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index d52364bac84e..508573b23bc1 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -166,8 +166,6 @@ SUBDIR.${MK_NS_CACHING}+= nscd SUBDIR.${MK_LPR}+= lpr SUBDIR.${MK_MAN_UTILS}+= manctl SUBDIR.${MK_MLX5TOOL}+= mlx5tool -SUBDIR.${MK_NAND}+= nandsim -SUBDIR.${MK_NAND}+= nandtool SUBDIR.${MK_NETGRAPH}+= flowctl SUBDIR.${MK_NETGRAPH}+= ngctl SUBDIR.${MK_NETGRAPH}+= nghook diff --git a/usr.sbin/bhyve/Makefile b/usr.sbin/bhyve/Makefile index e203a57c18a3..85fdf11928b1 100644 --- a/usr.sbin/bhyve/Makefile +++ b/usr.sbin/bhyve/Makefile @@ -16,7 +16,6 @@ BHYVE_SYSDIR?=${SRCTOP} SRCS= \ atkbdc.c \ acpi.c \ - audio.c \ bhyvegc.c \ bhyverun.c \ block_if.c \ @@ -28,7 +27,6 @@ SRCS= \ dbgport.c \ fwctl.c \ gdb.c \ - hda_codec.c \ inout.c \ ioapic.c \ mem.c \ @@ -38,7 +36,6 @@ SRCS= \ pci_ahci.c \ pci_e82545.c \ pci_emul.c \ - pci_hda.c \ pci_fbuf.c \ pci_hostbridge.c \ pci_irq.c \ diff --git a/usr.sbin/bhyve/audio.c b/usr.sbin/bhyve/audio.c deleted file mode 100644 index 6a288cbded63..000000000000 --- a/usr.sbin/bhyve/audio.c +++ /dev/null @@ -1,282 +0,0 @@ -/*- - * Copyright (c) 2016 Alex Teaca - * 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, 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 OR CONTRIBUTORS 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$"); - -#ifndef WITHOUT_CAPSICUM -#include -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "audio.h" -#include "pci_hda.h" - -/* - * Audio Player internal data structures - */ - -struct audio { - int fd; - uint8_t dir; - uint8_t inited; - char dev_name[64]; -}; - -/* - * Audio Player module function definitions - */ - -/* - * audio_init - initialize an instance of audio player - * @dev_name - the backend sound device used to play / capture - * @dir - dir = 1 for write mode, dir = 0 for read mode - */ -struct audio * -audio_init(const char *dev_name, uint8_t dir) -{ - struct audio *aud = NULL; -#ifndef WITHOUT_CAPSICUM - cap_rights_t rights; - cap_ioctl_t cmds[] = { - SNDCTL_DSP_RESET, SNDCTL_DSP_SETFMT, SNDCTL_DSP_CHANNELS, - SNDCTL_DSP_SPEED, -#ifdef DEBUG_HDA - SNDCTL_DSP_GETOSPACE, SNDCTL_DSP_GETISPACE, -#endif - }; -#endif - - assert(dev_name); - - aud = calloc(1, sizeof(*aud)); - if (!aud) - return NULL; - - if (strlen(dev_name) < sizeof(aud->dev_name)) - memcpy(aud->dev_name, dev_name, strlen(dev_name) + 1); - else { - DPRINTF("dev_name too big\n"); - free(aud); - return NULL; - } - - aud->dir = dir; - - aud->fd = open(aud->dev_name, aud->dir ? O_WRONLY : O_RDONLY, 0); - if (aud->fd == -1) { - DPRINTF("Failed to open dev: %s, errno: %d\n", - aud->dev_name, errno); - return (NULL); - } - -#ifndef WITHOUT_CAPSICUM - cap_rights_init(&rights, CAP_IOCTL, CAP_READ, CAP_WRITE); - if (caph_rights_limit(aud->fd, &rights) == -1) - errx(EX_OSERR, "Unable to apply rights for sandbox"); - if (caph_ioctls_limit(aud->fd, cmds, nitems(cmds)) == -1) - errx(EX_OSERR, "Unable to limit ioctl rights for sandbox"); -#endif - - return aud; -} - -/* - * audio_set_params - reset the sound device and set the audio params - * @aud - the audio player to be configured - * @params - the audio parameters to be set - */ -int -audio_set_params(struct audio *aud, struct audio_params *params) -{ - int audio_fd; - int format, channels, rate; - int err; -#if DEBUG_HDA == 1 - audio_buf_info info; -#endif - - assert(aud); - assert(params); - - if ((audio_fd = aud->fd) < 0) { - DPRINTF("Incorrect audio device descriptor for %s\n", - aud->dev_name); - return (-1); - } - - /* Reset the device if it was previously opened */ - if (aud->inited) { - err = ioctl(audio_fd, SNDCTL_DSP_RESET, NULL); - if (err == -1) { - DPRINTF("Failed to reset fd: %d, errno: %d\n", - aud->fd, errno); - return (-1); - } - } else - aud->inited = 1; - - /* Set the Format (Bits per Sample) */ - format = params->format; - err = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format); - if (err == -1) { - DPRINTF("Fail to set fmt: 0x%x errno: %d\n", - params->format, errno); - return -1; - } - - /* The device does not support the requested audio format */ - if (format != params->format) { - DPRINTF("Mismatch format: 0x%x params->format: 0x%x\n", - format, params->format); - return -1; - } - - /* Set the Number of Channels */ - channels = params->channels; - err = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &channels); - if (err == -1) { - DPRINTF("Fail to set channels: %d errno: %d\n", - params->channels, errno); - return -1; - } - - /* The device does not support the requested no. of channels */ - if (channels != params->channels) { - DPRINTF("Mismatch channels: %d params->channels: %d\n", - channels, params->channels); - return -1; - } - - /* Set the Sample Rate / Speed */ - rate = params->rate; - err = ioctl(audio_fd, SNDCTL_DSP_SPEED, &rate); - if (err == -1) { - DPRINTF("Fail to set speed: %d errno: %d\n", - params->rate, errno); - return -1; - } - - /* The device does not support the requested rate / speed */ - if (rate != params->rate) { - DPRINTF("Mismatch rate: %d params->rate: %d\n", - rate, params->rate); - return -1; - } - -#if DEBUG_HDA == 1 - err = ioctl(audio_fd, aud->dir ? SNDCTL_DSP_GETOSPACE : - SNDCTL_DSP_GETISPACE, &info); - if (err == -1) { - DPRINTF("Fail to get audio buf info errno: %d\n", errno); - return -1; - } - DPRINTF("fragstotal: 0x%x fragsize: 0x%x\n", - info.fragstotal, info.fragsize); -#endif - return 0; -} - -/* - * audio_playback - plays samples to the sound device using blocking operations - * @aud - the audio player used to play the samples - * @buf - the buffer containing the samples - * @count - the number of bytes in buffer - */ -int -audio_playback(struct audio *aud, const void *buf, size_t count) -{ - int audio_fd = -1; - ssize_t len = 0, total = 0; - - assert(aud); - assert(aud->dir); - assert(buf); - - audio_fd = aud->fd; - assert(audio_fd != -1); - - total = 0; - while (total < count) { - len = write(audio_fd, buf + total, count - total); - if (len == -1) { - DPRINTF("Fail to write to fd: %d, errno: %d\n", - audio_fd, errno); - return -1; - } - - total += len; - } - - return 0; -} - -/* - * audio_record - records samples from the sound device using - * blocking operations. - * @aud - the audio player used to capture the samples - * @buf - the buffer to receive the samples - * @count - the number of bytes to capture in buffer - * Returns -1 on error and 0 on success - */ -int -audio_record(struct audio *aud, void *buf, size_t count) -{ - int audio_fd = -1; - ssize_t len = 0, total = 0; - - assert(aud); - assert(!aud->dir); - assert(buf); - - audio_fd = aud->fd; - assert(audio_fd != -1); - - total = 0; - while (total < count) { - len = read(audio_fd, buf + total, count - total); - if (len == -1) { - DPRINTF("Fail to write to fd: %d, errno: %d\n", - audio_fd, errno); - return -1; - } - - total += len; - } - - return 0; -} diff --git a/usr.sbin/bhyve/audio.h b/usr.sbin/bhyve/audio.h deleted file mode 100644 index 01ef17071b14..000000000000 --- a/usr.sbin/bhyve/audio.h +++ /dev/null @@ -1,86 +0,0 @@ -/*- - * Copyright (c) 2016 Alex Teaca - * 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, 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 OR CONTRIBUTORS 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$ - */ - -#ifndef _AUDIO_EMUL_H_ -#define _AUDIO_EMUL_H_ - -#include -#include - -/* - * Audio Player data structures - */ - -struct audio; - -struct audio_params { - int channels; - int format; - int rate; -}; - -/* - * Audio Player API - */ - -/* - * audio_init - initialize an instance of audio player - * @dev_name - the backend sound device used to play / capture - * @dir - dir = 1 for write mode, dir = 0 for read mode - * Returns NULL on error and the address of the audio player instance - */ -struct audio *audio_init(const char *dev_name, uint8_t dir); - -/* - * audio_set_params - reset the sound device and set the audio params - * @aud - the audio player to be configured - * @params - the audio parameters to be set - * Returns -1 on error and 0 on success - */ -int audio_set_params(struct audio *aud, struct audio_params *params); - -/* - * audio_playback - plays samples to the sound device using blocking operations - * @aud - the audio player used to play the samples - * @buf - the buffer containing the samples - * @count - the number of bytes in buffer - * Returns -1 on error and 0 on success - */ -int audio_playback(struct audio *aud, const void *buf, size_t count); - -/* - * audio_record - records samples from the sound device using blocking - * operations. - * @aud - the audio player used to capture the samples - * @buf - the buffer to receive the samples - * @count - the number of bytes to capture in buffer - * Returns -1 on error and 0 on success - */ -int audio_record(struct audio *aud, void *buf, size_t count); - -#endif /* _AUDIO_EMUL_H_ */ diff --git a/usr.sbin/bhyve/bhyve.8 b/usr.sbin/bhyve/bhyve.8 index 3ab9e4e67dde..2f2236e8ce38 100644 --- a/usr.sbin/bhyve/bhyve.8 +++ b/usr.sbin/bhyve/bhyve.8 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd June 24, 2019 +.Dd December 11, 2018 .Dt BHYVE 8 .Os .Sh NAME @@ -248,8 +248,6 @@ Raw framebuffer device attached to VNC server. eXtensible Host Controller Interface (xHCI) USB controller. .It Li nvme NVM Express (NVMe) controller. -.It Li hda -High Definition Audio Controller. .El .It Op Ar conf This optional parameter describes the backend for device emulations. @@ -477,16 +475,6 @@ Sector size (defaults to blockif sector size). .It Li ser Serial number with maximum 20 characters. .El -.Pp -HD Audio devices: -.Bl -tag -width 10n -.It Li play -Playback device, typically -.Ar /dev/dsp0 . -.It Li rec -Recording device, typically -.Ar /dev/dsp0 . -.El .El .It Fl S Wire guest memory. diff --git a/usr.sbin/bhyve/hda_codec.c b/usr.sbin/bhyve/hda_codec.c deleted file mode 100644 index ab53eb036e9f..000000000000 --- a/usr.sbin/bhyve/hda_codec.c +++ /dev/null @@ -1,950 +0,0 @@ -/*- - * Copyright (c) 2016 Alex Teaca - * 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, 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 OR CONTRIBUTORS 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 -#include -#include - -#include "pci_hda.h" -#include "audio.h" - -/* - * HDA Codec defines - */ -#define INTEL_VENDORID 0x8086 - -#define HDA_CODEC_SUBSYSTEM_ID ((INTEL_VENDORID << 16) | 0x01) -#define HDA_CODEC_ROOT_NID 0x00 -#define HDA_CODEC_FG_NID 0x01 -#define HDA_CODEC_AUDIO_OUTPUT_NID 0x02 -#define HDA_CODEC_PIN_OUTPUT_NID 0x03 -#define HDA_CODEC_AUDIO_INPUT_NID 0x04 -#define HDA_CODEC_PIN_INPUT_NID 0x05 - -#define HDA_CODEC_STREAMS_COUNT 0x02 -#define HDA_CODEC_STREAM_OUTPUT 0x00 -#define HDA_CODEC_STREAM_INPUT 0x01 - -#define HDA_CODEC_PARAMS_COUNT 0x14 -#define HDA_CODEC_CONN_LIST_COUNT 0x01 -#define HDA_CODEC_RESPONSE_EX_UNSOL 0x10 -#define HDA_CODEC_RESPONSE_EX_SOL 0x00 -#define HDA_CODEC_AMP_NUMSTEPS 0x4a - -#define HDA_CODEC_SUPP_STREAM_FORMATS_PCM \ - (1 << HDA_PARAM_SUPP_STREAM_FORMATS_PCM_SHIFT) - -#define HDA_CODEC_FMT_BASE_MASK (0x01 << 14) - -#define HDA_CODEC_FMT_MULT_MASK (0x07 << 11) -#define HDA_CODEC_FMT_MULT_2 (0x01 << 11) -#define HDA_CODEC_FMT_MULT_3 (0x02 << 11) -#define HDA_CODEC_FMT_MULT_4 (0x03 << 11) - -#define HDA_CODEC_FMT_DIV_MASK 0x07 -#define HDA_CODEC_FMT_DIV_SHIFT 8 - -#define HDA_CODEC_FMT_BITS_MASK (0x07 << 4) -#define HDA_CODEC_FMT_BITS_8 (0x00 << 4) -#define HDA_CODEC_FMT_BITS_16 (0x01 << 4) -#define HDA_CODEC_FMT_BITS_24 (0x03 << 4) -#define HDA_CODEC_FMT_BITS_32 (0x04 << 4) - -#define HDA_CODEC_FMT_CHAN_MASK (0x0f << 0) - -#define HDA_CODEC_AUDIO_WCAP_OUTPUT \ - (0x00 << HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT) -#define HDA_CODEC_AUDIO_WCAP_INPUT \ - (0x01 << HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT) -#define HDA_CODEC_AUDIO_WCAP_PIN \ - (0x04 << HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT) -#define HDA_CODEC_AUDIO_WCAP_CONN_LIST \ - (1 << HDA_PARAM_AUDIO_WIDGET_CAP_CONN_LIST_SHIFT) -#define HDA_CODEC_AUDIO_WCAP_FORMAT_OVR \ - (1 << HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR_SHIFT) -#define HDA_CODEC_AUDIO_WCAP_AMP_OVR \ - (1 << HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR_SHIFT) -#define HDA_CODEC_AUDIO_WCAP_OUT_AMP \ - (1 << HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP_SHIFT) -#define HDA_CODEC_AUDIO_WCAP_IN_AMP \ - (1 << HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP_SHIFT) -#define HDA_CODEC_AUDIO_WCAP_STEREO \ - (1 << HDA_PARAM_AUDIO_WIDGET_CAP_STEREO_SHIFT) - -#define HDA_CODEC_PIN_CAP_OUTPUT \ - (1 << HDA_PARAM_PIN_CAP_OUTPUT_CAP_SHIFT) -#define HDA_CODEC_PIN_CAP_INPUT \ - (1 << HDA_PARAM_PIN_CAP_INPUT_CAP_SHIFT) -#define HDA_CODEC_PIN_CAP_PRESENCE_DETECT \ - (1 << HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP_SHIFT) - -#define HDA_CODEC_OUTPUT_AMP_CAP_MUTE_CAP \ - (1 << HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP_SHIFT) -#define HDA_CODEC_OUTPUT_AMP_CAP_STEPSIZE \ - (0x03 << HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_SHIFT) -#define HDA_CODEC_OUTPUT_AMP_CAP_NUMSTEPS \ - (HDA_CODEC_AMP_NUMSTEPS << HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_SHIFT) -#define HDA_CODEC_OUTPUT_AMP_CAP_OFFSET \ - (HDA_CODEC_AMP_NUMSTEPS << HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_SHIFT) - -#define HDA_CODEC_SET_AMP_GAIN_MUTE_MUTE 0x80 -#define HDA_CODEC_SET_AMP_GAIN_MUTE_GAIN_MASK 0x7f - -#define HDA_CODEC_PIN_SENSE_PRESENCE_PLUGGED (1 << 31) -#define HDA_CODEC_PIN_WIDGET_CTRL_OUT_ENABLE \ - (1 << HDA_CMD_GET_PIN_WIDGET_CTRL_OUT_ENABLE_SHIFT) -#define HDA_CODEC_PIN_WIDGET_CTRL_IN_ENABLE \ - (1 << HDA_CMD_GET_PIN_WIDGET_CTRL_IN_ENABLE_SHIFT) - -#define HDA_CONFIG_DEFAULTCONF_COLOR_BLACK \ - (0x01 << HDA_CONFIG_DEFAULTCONF_COLOR_SHIFT) -#define HDA_CONFIG_DEFAULTCONF_COLOR_RED \ - (0x05 << HDA_CONFIG_DEFAULTCONF_COLOR_SHIFT) - -#define HDA_CODEC_BUF_SIZE HDA_FIFO_SIZE - -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) - - -/* - * HDA Audio Context data structures - */ - -typedef void (*transfer_func_t)(void *arg); -typedef int (*setup_func_t)(void *arg); - -struct hda_audio_ctxt { - char name[64]; - uint8_t run; - uint8_t started; - void *priv; - pthread_t tid; - pthread_mutex_t mtx; - pthread_cond_t cond; - setup_func_t do_setup; - transfer_func_t do_transfer; -}; - -/* - * HDA Audio Context module function declarations - */ - -static void *hda_audio_ctxt_thr(void *arg); -static int hda_audio_ctxt_init(struct hda_audio_ctxt *actx, const char *tname, - transfer_func_t do_transfer, setup_func_t do_setup, void *priv); -static int hda_audio_ctxt_start(struct hda_audio_ctxt *actx); -static int hda_audio_ctxt_stop(struct hda_audio_ctxt *actx); - -/* - * HDA Codec data structures - */ - -struct hda_codec_softc; - -typedef uint32_t (*verb_func_t)(struct hda_codec_softc *sc, uint16_t verb, - uint16_t payload); - -struct hda_codec_stream { - uint8_t buf[HDA_CODEC_BUF_SIZE]; - uint8_t channel; - uint16_t fmt; - uint8_t stream; - - uint8_t left_gain; - uint8_t right_gain; - uint8_t left_mute; - uint8_t right_mute; - - struct audio *aud; - struct hda_audio_ctxt actx; -}; - -struct hda_codec_softc { - uint32_t no_nodes; - uint32_t subsystem_id; - const uint32_t (*get_parameters)[HDA_CODEC_PARAMS_COUNT]; - const uint8_t (*conn_list)[HDA_CODEC_CONN_LIST_COUNT]; - const uint32_t *conf_default; - const uint8_t *pin_ctrl_default; - const verb_func_t *verb_handlers; - - struct hda_codec_inst *hci; - struct hda_codec_stream streams[HDA_CODEC_STREAMS_COUNT]; -}; - -/* - * HDA Codec module function declarations - */ -static int hda_codec_init(struct hda_codec_inst *hci, const char *play, - const char *rec, const char *opts); -static int hda_codec_reset(struct hda_codec_inst *hci); -static int hda_codec_command(struct hda_codec_inst *hci, uint32_t cmd_data); -static int hda_codec_notify(struct hda_codec_inst *hci, uint8_t run, - uint8_t stream, uint8_t dir); - -static int hda_codec_parse_format(uint16_t fmt, struct audio_params *params); - -static uint32_t hda_codec_audio_output_nid(struct hda_codec_softc *sc, - uint16_t verb, uint16_t payload); -static void hda_codec_audio_output_do_transfer(void *arg); -static int hda_codec_audio_output_do_setup(void *arg); -static uint32_t hda_codec_audio_input_nid(struct hda_codec_softc *sc, - uint16_t verb, uint16_t payload); -static void hda_codec_audio_input_do_transfer(void *arg); -static int hda_codec_audio_input_do_setup(void *arg); - -static uint32_t hda_codec_audio_inout_nid(struct hda_codec_stream *st, - uint16_t verb, uint16_t payload); - -/* - * HDA Codec global data - */ - -#define HDA_CODEC_ROOT_DESC \ - [HDA_CODEC_ROOT_NID] = { \ - [HDA_PARAM_VENDOR_ID] = INTEL_VENDORID, \ - [HDA_PARAM_REVISION_ID] = 0xffff, \ - /* 1 Subnode, StartNid = 1 */ \ - [HDA_PARAM_SUB_NODE_COUNT] = 0x00010001, \ - }, \ - -#define HDA_CODEC_FG_COMMON_DESC \ - [HDA_PARAM_FCT_GRP_TYPE] = HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO,\ - /* B8 - B32, 8.0 - 192.0kHz */ \ - [HDA_PARAM_SUPP_PCM_SIZE_RATE] = (0x1f << 16) | 0x7ff, \ - [HDA_PARAM_SUPP_STREAM_FORMATS] = HDA_CODEC_SUPP_STREAM_FORMATS_PCM,\ - [HDA_PARAM_INPUT_AMP_CAP] = 0x00, /* None */ \ - [HDA_PARAM_OUTPUT_AMP_CAP] = 0x00, /* None */ \ - [HDA_PARAM_GPIO_COUNT] = 0x00, \ - -#define HDA_CODEC_FG_OUTPUT_DESC \ - [HDA_CODEC_FG_NID] = { \ - /* 2 Subnodes, StartNid = 2 */ \ - [HDA_PARAM_SUB_NODE_COUNT] = 0x00020002, \ - HDA_CODEC_FG_COMMON_DESC \ - }, \ - -#define HDA_CODEC_FG_INPUT_DESC \ - [HDA_CODEC_FG_NID] = { \ - /* 2 Subnodes, StartNid = 4 */ \ - [HDA_PARAM_SUB_NODE_COUNT] = 0x00040002, \ - HDA_CODEC_FG_COMMON_DESC \ - }, \ - -#define HDA_CODEC_FG_DUPLEX_DESC \ - [HDA_CODEC_FG_NID] = { \ - /* 4 Subnodes, StartNid = 2 */ \ - [HDA_PARAM_SUB_NODE_COUNT] = 0x00020004, \ - HDA_CODEC_FG_COMMON_DESC \ - }, \ - -#define HDA_CODEC_OUTPUT_DESC \ - [HDA_CODEC_AUDIO_OUTPUT_NID] = { \ - [HDA_PARAM_AUDIO_WIDGET_CAP] = \ - HDA_CODEC_AUDIO_WCAP_OUTPUT | \ - HDA_CODEC_AUDIO_WCAP_FORMAT_OVR | \ - HDA_CODEC_AUDIO_WCAP_AMP_OVR | \ - HDA_CODEC_AUDIO_WCAP_OUT_AMP | \ - HDA_CODEC_AUDIO_WCAP_STEREO, \ - /* B16, 16.0 - 192.0kHz */ \ - [HDA_PARAM_SUPP_PCM_SIZE_RATE] = (0x02 << 16) | 0x7fc, \ - [HDA_PARAM_SUPP_STREAM_FORMATS] = \ - HDA_CODEC_SUPP_STREAM_FORMATS_PCM, \ - [HDA_PARAM_INPUT_AMP_CAP] = 0x00, /* None */ \ - [HDA_PARAM_CONN_LIST_LENGTH] = 0x00, \ - [HDA_PARAM_OUTPUT_AMP_CAP] = \ - HDA_CODEC_OUTPUT_AMP_CAP_MUTE_CAP | \ - HDA_CODEC_OUTPUT_AMP_CAP_STEPSIZE | \ - HDA_CODEC_OUTPUT_AMP_CAP_NUMSTEPS | \ - HDA_CODEC_OUTPUT_AMP_CAP_OFFSET, \ - }, \ - [HDA_CODEC_PIN_OUTPUT_NID] = { \ - [HDA_PARAM_AUDIO_WIDGET_CAP] = \ - HDA_CODEC_AUDIO_WCAP_PIN | \ - HDA_CODEC_AUDIO_WCAP_CONN_LIST | \ - HDA_CODEC_AUDIO_WCAP_STEREO, \ - [HDA_PARAM_PIN_CAP] = HDA_CODEC_PIN_CAP_OUTPUT | \ - HDA_CODEC_PIN_CAP_PRESENCE_DETECT,\ - [HDA_PARAM_INPUT_AMP_CAP] = 0x00, /* None */ \ - [HDA_PARAM_CONN_LIST_LENGTH] = 0x01, \ - [HDA_PARAM_OUTPUT_AMP_CAP] = 0x00, /* None */ \ - }, \ - -#define HDA_CODEC_INPUT_DESC \ - [HDA_CODEC_AUDIO_INPUT_NID] = { \ - [HDA_PARAM_AUDIO_WIDGET_CAP] = \ - HDA_CODEC_AUDIO_WCAP_INPUT | \ - HDA_CODEC_AUDIO_WCAP_CONN_LIST | \ - HDA_CODEC_AUDIO_WCAP_FORMAT_OVR | \ - HDA_CODEC_AUDIO_WCAP_AMP_OVR | \ - HDA_CODEC_AUDIO_WCAP_IN_AMP | \ - HDA_CODEC_AUDIO_WCAP_STEREO, \ - /* B16, 16.0 - 192.0kHz */ \ - [HDA_PARAM_SUPP_PCM_SIZE_RATE] = (0x02 << 16) | 0x7fc, \ - [HDA_PARAM_SUPP_STREAM_FORMATS] = \ - HDA_CODEC_SUPP_STREAM_FORMATS_PCM, \ - [HDA_PARAM_OUTPUT_AMP_CAP] = 0x00, /* None */ \ - [HDA_PARAM_CONN_LIST_LENGTH] = 0x01, \ - [HDA_PARAM_INPUT_AMP_CAP] = \ - HDA_CODEC_OUTPUT_AMP_CAP_MUTE_CAP | \ - HDA_CODEC_OUTPUT_AMP_CAP_STEPSIZE | \ - HDA_CODEC_OUTPUT_AMP_CAP_NUMSTEPS | \ - HDA_CODEC_OUTPUT_AMP_CAP_OFFSET, \ - }, \ - [HDA_CODEC_PIN_INPUT_NID] = { \ - [HDA_PARAM_AUDIO_WIDGET_CAP] = \ - HDA_CODEC_AUDIO_WCAP_PIN | \ - HDA_CODEC_AUDIO_WCAP_STEREO, \ - [HDA_PARAM_PIN_CAP] = HDA_CODEC_PIN_CAP_INPUT | \ - HDA_CODEC_PIN_CAP_PRESENCE_DETECT, \ - [HDA_PARAM_INPUT_AMP_CAP] = 0x00, /* None */ \ - [HDA_PARAM_OUTPUT_AMP_CAP] = 0x00, /* None */ \ - }, \ - -static const uint32_t -hda_codec_output_parameters[][HDA_CODEC_PARAMS_COUNT] = { - HDA_CODEC_ROOT_DESC - HDA_CODEC_FG_OUTPUT_DESC - HDA_CODEC_OUTPUT_DESC -}; - -static const uint32_t -hda_codec_input_parameters[][HDA_CODEC_PARAMS_COUNT] = { - HDA_CODEC_ROOT_DESC - HDA_CODEC_FG_INPUT_DESC - HDA_CODEC_INPUT_DESC -}; - -static const uint32_t -hda_codec_duplex_parameters[][HDA_CODEC_PARAMS_COUNT] = { - HDA_CODEC_ROOT_DESC - HDA_CODEC_FG_DUPLEX_DESC - HDA_CODEC_OUTPUT_DESC - HDA_CODEC_INPUT_DESC -}; - -#define HDA_CODEC_NODES_COUNT (ARRAY_SIZE(hda_codec_duplex_parameters)) - -static const uint8_t -hda_codec_conn_list[HDA_CODEC_NODES_COUNT][HDA_CODEC_CONN_LIST_COUNT] = { - [HDA_CODEC_PIN_OUTPUT_NID] = {HDA_CODEC_AUDIO_OUTPUT_NID}, - [HDA_CODEC_AUDIO_INPUT_NID] = {HDA_CODEC_PIN_INPUT_NID}, -}; - -static const uint32_t -hda_codec_conf_default[HDA_CODEC_NODES_COUNT] = { - [HDA_CODEC_PIN_OUTPUT_NID] = \ - HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK | - HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT | - HDA_CONFIG_DEFAULTCONF_COLOR_BLACK | - (0x01 << HDA_CONFIG_DEFAULTCONF_ASSOCIATION_SHIFT), - [HDA_CODEC_PIN_INPUT_NID] = HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK | - HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN | - HDA_CONFIG_DEFAULTCONF_COLOR_RED | - (0x02 << HDA_CONFIG_DEFAULTCONF_ASSOCIATION_SHIFT), -}; - -static const uint8_t -hda_codec_pin_ctrl_default[HDA_CODEC_NODES_COUNT] = { - [HDA_CODEC_PIN_OUTPUT_NID] = HDA_CODEC_PIN_WIDGET_CTRL_OUT_ENABLE, - [HDA_CODEC_PIN_INPUT_NID] = HDA_CODEC_PIN_WIDGET_CTRL_IN_ENABLE, -}; - -static const -verb_func_t hda_codec_verb_handlers[HDA_CODEC_NODES_COUNT] = { - [HDA_CODEC_AUDIO_OUTPUT_NID] = hda_codec_audio_output_nid, - [HDA_CODEC_AUDIO_INPUT_NID] = hda_codec_audio_input_nid, -}; - -/* - * HDA Codec module function definitions - */ - -static int -hda_codec_init(struct hda_codec_inst *hci, const char *play, - const char *rec, const char *opts) -{ - struct hda_codec_softc *sc = NULL; - struct hda_codec_stream *st = NULL; - int err; - - if (!(play || rec)) - return (-1); - - DPRINTF("cad: 0x%x opts: %s\n", hci->cad, opts); - - sc = calloc(1, sizeof(*sc)); - if (!sc) - return (-1); - - if (play && rec) - sc->get_parameters = hda_codec_duplex_parameters; - else { - if (play) - sc->get_parameters = hda_codec_output_parameters; - else - sc->get_parameters = hda_codec_input_parameters; - } - sc->subsystem_id = HDA_CODEC_SUBSYSTEM_ID; - sc->no_nodes = HDA_CODEC_NODES_COUNT; - sc->conn_list = hda_codec_conn_list; - sc->conf_default = hda_codec_conf_default; - sc->pin_ctrl_default = hda_codec_pin_ctrl_default; - sc->verb_handlers = hda_codec_verb_handlers; - DPRINTF("HDA Codec nodes: %d\n", sc->no_nodes); - - /* - * Initialize the Audio Output stream - */ - if (play) { - st = &sc->streams[HDA_CODEC_STREAM_OUTPUT]; - - err = hda_audio_ctxt_init(&st->actx, "hda-audio-output", - hda_codec_audio_output_do_transfer, - hda_codec_audio_output_do_setup, sc); - assert(!err); - - st->aud = audio_init(play, 1); - if (!st->aud) { - DPRINTF("Fail to init the output audio player\n"); - return (-1); - } - } - - /* - * Initialize the Audio Input stream - */ - if (rec) { - st = &sc->streams[HDA_CODEC_STREAM_INPUT]; - - err = hda_audio_ctxt_init(&st->actx, "hda-audio-input", - hda_codec_audio_input_do_transfer, - hda_codec_audio_input_do_setup, sc); - assert(!err); - - st->aud = audio_init(rec, 0); - if (!st->aud) { - DPRINTF("Fail to init the input audio player\n"); - return (-1); - } - } - - sc->hci = hci; - hci->priv = sc; - - return (0); -} - -static int -hda_codec_reset(struct hda_codec_inst *hci) -{ - struct hda_ops *hops = NULL; - struct hda_codec_softc *sc = NULL; - struct hda_codec_stream *st = NULL; - int i; - - assert(hci); - - hops = hci->hops; - assert(hops); - - sc = (struct hda_codec_softc *)hci->priv; - assert(sc); - - for (i = 0; i < HDA_CODEC_STREAMS_COUNT; i++) { - st = &sc->streams[i]; - st->left_gain = HDA_CODEC_AMP_NUMSTEPS; - st->right_gain = HDA_CODEC_AMP_NUMSTEPS; - st->left_mute = HDA_CODEC_SET_AMP_GAIN_MUTE_MUTE; - st->right_mute = HDA_CODEC_SET_AMP_GAIN_MUTE_MUTE; - } - - DPRINTF("cad: 0x%x\n", hci->cad); - - if (!hops->signal) { - DPRINTF("The controller ops does not implement \ - the signal function\n"); - return (-1); - } - - return (hops->signal(hci)); -} - -static int -hda_codec_command(struct hda_codec_inst *hci, uint32_t cmd_data) -{ - struct hda_codec_softc *sc = NULL; - struct hda_ops *hops = NULL; - uint8_t cad = 0, nid = 0; - uint16_t verb = 0, payload = 0; - uint32_t res = 0; - - /* 4 bits */ - cad = (cmd_data >> HDA_CMD_CAD_SHIFT) & 0x0f; - /* 8 bits */ - nid = (cmd_data >> HDA_CMD_NID_SHIFT) & 0xff; - - if ((cmd_data & 0x70000) == 0x70000) { - /* 12 bits */ - verb = (cmd_data >> HDA_CMD_VERB_12BIT_SHIFT) & 0x0fff; - /* 8 bits */ - payload = cmd_data & 0xff; - } else { - /* 4 bits */ - verb = (cmd_data >> HDA_CMD_VERB_4BIT_SHIFT) & 0x0f; - /* 16 bits */ - payload = cmd_data & 0xffff; - } - - assert(cad == hci->cad); - assert(hci); - - hops = hci->hops; - assert(hops); - - sc = (struct hda_codec_softc *)hci->priv; - assert(sc); - - assert(nid < sc->no_nodes); - - if (!hops->response) { - DPRINTF("The controller ops does not implement \ - the response function\n"); - return (-1); - } - - switch (verb) { - case HDA_CMD_VERB_GET_PARAMETER: - res = sc->get_parameters[nid][payload]; - break; - case HDA_CMD_VERB_GET_CONN_LIST_ENTRY: - res = sc->conn_list[nid][0]; - break; - case HDA_CMD_VERB_GET_PIN_WIDGET_CTRL: - res = sc->pin_ctrl_default[nid]; - break; - case HDA_CMD_VERB_GET_PIN_SENSE: - res = HDA_CODEC_PIN_SENSE_PRESENCE_PLUGGED; - break; - case HDA_CMD_VERB_GET_CONFIGURATION_DEFAULT: - res = sc->conf_default[nid]; - break; - case HDA_CMD_VERB_GET_SUBSYSTEM_ID: - res = sc->subsystem_id; - break; - default: - assert(sc->verb_handlers); - if (sc->verb_handlers[nid]) - res = sc->verb_handlers[nid](sc, verb, payload); - else - DPRINTF("Unknown VERB: 0x%x\n", verb); - break; - } - - DPRINTF("cad: 0x%x nid: 0x%x verb: 0x%x payload: 0x%x response: 0x%x\n", - cad, nid, verb, payload, res); - - return (hops->response(hci, res, HDA_CODEC_RESPONSE_EX_SOL)); -} - -static int -hda_codec_notify(struct hda_codec_inst *hci, uint8_t run, - uint8_t stream, uint8_t dir) -{ - struct hda_codec_softc *sc = NULL; - struct hda_codec_stream *st = NULL; - struct hda_audio_ctxt *actx = NULL; - int i; - int err; - - assert(hci); - assert(stream); - - sc = (struct hda_codec_softc *)hci->priv; - assert(sc); - - i = dir ? HDA_CODEC_STREAM_OUTPUT : HDA_CODEC_STREAM_INPUT; - st = &sc->streams[i]; - - DPRINTF("run: %d, stream: 0x%x, st->stream: 0x%x dir: %d\n", - run, stream, st->stream, dir); - - if (stream != st->stream) { - DPRINTF("Stream not found\n"); - return (0); - } - - actx = &st->actx; - - if (run) - err = hda_audio_ctxt_start(actx); - else - err = hda_audio_ctxt_stop(actx); - - return (err); -} - -static int -hda_codec_parse_format(uint16_t fmt, struct audio_params *params) -{ - uint8_t div = 0; - - assert(params); - - /* Compute the Sample Rate */ - params->rate = (fmt & HDA_CODEC_FMT_BASE_MASK) ? 44100 : 48000; - - switch (fmt & HDA_CODEC_FMT_MULT_MASK) { - case HDA_CODEC_FMT_MULT_2: - params->rate *= 2; - break; - case HDA_CODEC_FMT_MULT_3: - params->rate *= 3; - break; - case HDA_CODEC_FMT_MULT_4: - params->rate *= 4; - break; - } - - div = (fmt >> HDA_CODEC_FMT_DIV_SHIFT) & HDA_CODEC_FMT_DIV_MASK; - params->rate /= (div + 1); - - /* Compute the Bits per Sample */ - switch (fmt & HDA_CODEC_FMT_BITS_MASK) { - case HDA_CODEC_FMT_BITS_8: - params->format = AFMT_U8; - break; - case HDA_CODEC_FMT_BITS_16: - params->format = AFMT_S16_LE; - break; - case HDA_CODEC_FMT_BITS_24: - params->format = AFMT_S24_LE; - break; - case HDA_CODEC_FMT_BITS_32: - params->format = AFMT_S32_LE; - break; - default: - DPRINTF("Unknown format bits: 0x%x\n", - fmt & HDA_CODEC_FMT_BITS_MASK); - return (-1); - } - - /* Compute the Number of Channels */ - params->channels = (fmt & HDA_CODEC_FMT_CHAN_MASK) + 1; - - return (0); -} - -static uint32_t -hda_codec_audio_output_nid(struct hda_codec_softc *sc, uint16_t verb, - uint16_t payload) -{ - struct hda_codec_stream *st = &sc->streams[HDA_CODEC_STREAM_OUTPUT]; - int res; - - res = hda_codec_audio_inout_nid(st, verb, payload); - - return (res); -} - -static void -hda_codec_audio_output_do_transfer(void *arg) -{ - struct hda_codec_softc *sc = (struct hda_codec_softc *)arg; - struct hda_codec_inst *hci = NULL; - struct hda_ops *hops = NULL; - struct hda_codec_stream *st = NULL; - struct audio *aud = NULL; - int err; - - hci = sc->hci; - assert(hci); - - hops = hci->hops; - assert(hops); - - st = &sc->streams[HDA_CODEC_STREAM_OUTPUT]; - aud = st->aud; - - err = hops->transfer(hci, st->stream, 1, st->buf, sizeof(st->buf)); - if (err) - return; - - err = audio_playback(aud, st->buf, sizeof(st->buf)); - assert(!err); -} - -static int -hda_codec_audio_output_do_setup(void *arg) -{ - struct hda_codec_softc *sc = (struct hda_codec_softc *)arg; - struct hda_codec_stream *st = NULL; - struct audio *aud = NULL; - struct audio_params params; - int err; - - st = &sc->streams[HDA_CODEC_STREAM_OUTPUT]; - aud = st->aud; - - err = hda_codec_parse_format(st->fmt, ¶ms); - if (err) - return (-1); - - DPRINTF("rate: %d, channels: %d, format: 0x%x\n", - params.rate, params.channels, params.format); - - return (audio_set_params(aud, ¶ms)); -} - -static uint32_t -hda_codec_audio_input_nid(struct hda_codec_softc *sc, uint16_t verb, - uint16_t payload) -{ - struct hda_codec_stream *st = &sc->streams[HDA_CODEC_STREAM_INPUT]; - int res; - - res = hda_codec_audio_inout_nid(st, verb, payload); - - return (res); -} - -static void -hda_codec_audio_input_do_transfer(void *arg) -{ - struct hda_codec_softc *sc = (struct hda_codec_softc *)arg; - struct hda_codec_inst *hci = NULL; - struct hda_ops *hops = NULL; - struct hda_codec_stream *st = NULL; - struct audio *aud = NULL; - int err; - - hci = sc->hci; - assert(hci); - - hops = hci->hops; - assert(hops); - - st = &sc->streams[HDA_CODEC_STREAM_INPUT]; - aud = st->aud; - - err = audio_record(aud, st->buf, sizeof(st->buf)); - assert(!err); - - hops->transfer(hci, st->stream, 0, st->buf, sizeof(st->buf)); -} - -static int -hda_codec_audio_input_do_setup(void *arg) -{ - struct hda_codec_softc *sc = (struct hda_codec_softc *)arg; - struct hda_codec_stream *st = NULL; - struct audio *aud = NULL; - struct audio_params params; - int err; - - st = &sc->streams[HDA_CODEC_STREAM_INPUT]; - aud = st->aud; - - err = hda_codec_parse_format(st->fmt, ¶ms); - if (err) - return (-1); - - DPRINTF("rate: %d, channels: %d, format: 0x%x\n", - params.rate, params.channels, params.format); - - return (audio_set_params(aud, ¶ms)); -} - -static uint32_t -hda_codec_audio_inout_nid(struct hda_codec_stream *st, uint16_t verb, - uint16_t payload) -{ - uint32_t res = 0; - uint8_t mute = 0; - uint8_t gain = 0; - - DPRINTF("%s verb: 0x%x, payload, 0x%x\n", st->actx.name, verb, payload); - - switch (verb) { - case HDA_CMD_VERB_GET_CONV_FMT: - res = st->fmt; - break; - case HDA_CMD_VERB_SET_CONV_FMT: - st->fmt = payload; - break; - case HDA_CMD_VERB_GET_AMP_GAIN_MUTE: - if (payload & HDA_CMD_GET_AMP_GAIN_MUTE_LEFT) { - res = st->left_gain | st->left_mute; - DPRINTF("GET_AMP_GAIN_MUTE_LEFT: 0x%x\n", res); - } else { - res = st->right_gain | st->right_mute; - DPRINTF("GET_AMP_GAIN_MUTE_RIGHT: 0x%x\n", res); - } - break; - case HDA_CMD_VERB_SET_AMP_GAIN_MUTE: - mute = payload & HDA_CODEC_SET_AMP_GAIN_MUTE_MUTE; - gain = payload & HDA_CODEC_SET_AMP_GAIN_MUTE_GAIN_MASK; - - if (payload & HDA_CMD_SET_AMP_GAIN_MUTE_LEFT) { - st->left_mute = mute; - st->left_gain = gain; - DPRINTF("SET_AMP_GAIN_MUTE_LEFT: \ - mute: 0x%x gain: 0x%x\n", mute, gain); - } - - if (payload & HDA_CMD_SET_AMP_GAIN_MUTE_RIGHT) { - st->right_mute = mute; - st->right_gain = gain; - DPRINTF("SET_AMP_GAIN_MUTE_RIGHT: \ - mute: 0x%x gain: 0x%x\n", mute, gain); - } - break; - case HDA_CMD_VERB_GET_CONV_STREAM_CHAN: - res = (st->stream << 4) | st->channel; - break; - case HDA_CMD_VERB_SET_CONV_STREAM_CHAN: - st->channel = payload & 0x0f; - st->stream = (payload >> 4) & 0x0f; - DPRINTF("st->channel: 0x%x st->stream: 0x%x\n", - st->channel, st->stream); - if (!st->stream) - hda_audio_ctxt_stop(&st->actx); - break; - default: - DPRINTF("Unknown VERB: 0x%x\n", verb); - break; - } - - return (res); -} - -struct hda_codec_class hda_codec = { - .name = "hda_codec", - .init = hda_codec_init, - .reset = hda_codec_reset, - .command = hda_codec_command, - .notify = hda_codec_notify, -}; - -HDA_EMUL_SET(hda_codec); - - -/* - * HDA Audio Context module function definitions - */ - -static void * -hda_audio_ctxt_thr(void *arg) -{ - struct hda_audio_ctxt *actx = arg; - - DPRINTF("Start Thread: %s\n", actx->name); - - pthread_mutex_lock(&actx->mtx); - while (1) { - while (!actx->run) - pthread_cond_wait(&actx->cond, &actx->mtx); - - actx->do_transfer(actx->priv); - } - pthread_mutex_unlock(&actx->mtx); - - pthread_exit(NULL); - return (NULL); -} - -static int -hda_audio_ctxt_init(struct hda_audio_ctxt *actx, const char *tname, - transfer_func_t do_transfer, setup_func_t do_setup, void *priv) -{ - int err; - - assert(actx); - assert(tname); - assert(do_transfer); - assert(do_setup); - assert(priv); - - memset(actx, 0, sizeof(*actx)); - - actx->run = 0; - actx->do_transfer = do_transfer; - actx->do_setup = do_setup; - actx->priv = priv; - if (strlen(tname) < sizeof(actx->name)) - memcpy(actx->name, tname, strlen(tname) + 1); - else - strcpy(actx->name, "unknown"); - - err = pthread_mutex_init(&actx->mtx, NULL); - assert(!err); - - err = pthread_cond_init(&actx->cond, NULL); - assert(!err); - - err = pthread_create(&actx->tid, NULL, hda_audio_ctxt_thr, actx); - assert(!err); - - pthread_set_name_np(actx->tid, tname); - - actx->started = 1; - - return (0); -} - -static int -hda_audio_ctxt_start(struct hda_audio_ctxt *actx) -{ - int err = 0; - - assert(actx); - assert(actx->started); - - /* The stream is supposed to be stopped */ - if (actx->run) - return (-1); - - pthread_mutex_lock(&actx->mtx); - err = (* actx->do_setup)(actx->priv); - if (!err) { - actx->run = 1; - pthread_cond_signal(&actx->cond); - } - pthread_mutex_unlock(&actx->mtx); - - return (err); -} - -static int -hda_audio_ctxt_stop(struct hda_audio_ctxt *actx) -{ - actx->run = 0; - return (0); -} diff --git a/usr.sbin/bhyve/hda_reg.h b/usr.sbin/bhyve/hda_reg.h deleted file mode 100644 index dd7098524537..000000000000 --- a/usr.sbin/bhyve/hda_reg.h +++ /dev/null @@ -1,1367 +0,0 @@ -/*- - * Copyright (c) 2006 Stephane E. Potvin - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$ - */ - -#ifndef _HDA_REG_H_ -#define _HDA_REG_H_ - -/**************************************************************************** - * HDA Device Verbs - ****************************************************************************/ - -/* HDA Command */ -#define HDA_CMD_VERB_MASK 0x000fffff -#define HDA_CMD_VERB_SHIFT 0 -#define HDA_CMD_NID_MASK 0x0ff00000 -#define HDA_CMD_NID_SHIFT 20 -#define HDA_CMD_CAD_MASK 0xf0000000 -#define HDA_CMD_CAD_SHIFT 28 - -#define HDA_CMD_VERB_4BIT_SHIFT 16 -#define HDA_CMD_VERB_12BIT_SHIFT 8 - -#define HDA_CMD_VERB_4BIT(verb, payload) \ - (((verb) << HDA_CMD_VERB_4BIT_SHIFT) | (payload)) -#define HDA_CMD_4BIT(cad, nid, verb, payload) \ - (((cad) << HDA_CMD_CAD_SHIFT) | \ - ((nid) << HDA_CMD_NID_SHIFT) | \ - (HDA_CMD_VERB_4BIT((verb), (payload)))) - -#define HDA_CMD_VERB_12BIT(verb, payload) \ - (((verb) << HDA_CMD_VERB_12BIT_SHIFT) | (payload)) -#define HDA_CMD_12BIT(cad, nid, verb, payload) \ - (((cad) << HDA_CMD_CAD_SHIFT) | \ - ((nid) << HDA_CMD_NID_SHIFT) | \ - (HDA_CMD_VERB_12BIT((verb), (payload)))) - -/* Get Parameter */ -#define HDA_CMD_VERB_GET_PARAMETER 0xf00 - -#define HDA_CMD_GET_PARAMETER(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_PARAMETER, (payload))) - -/* Connection Select Control */ -#define HDA_CMD_VERB_GET_CONN_SELECT_CONTROL 0xf01 -#define HDA_CMD_VERB_SET_CONN_SELECT_CONTROL 0x701 - -#define HDA_CMD_GET_CONN_SELECT_CONTROL(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_CONN_SELECT_CONTROL, 0x0)) -#define HDA_CMD_SET_CONNECTION_SELECT_CONTROL(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_CONN_SELECT_CONTROL, (payload))) - -/* Connection List Entry */ -#define HDA_CMD_VERB_GET_CONN_LIST_ENTRY 0xf02 - -#define HDA_CMD_GET_CONN_LIST_ENTRY(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_CONN_LIST_ENTRY, (payload))) - -#define HDA_CMD_GET_CONN_LIST_ENTRY_SIZE_SHORT 1 -#define HDA_CMD_GET_CONN_LIST_ENTRY_SIZE_LONG 2 - -/* Processing State */ -#define HDA_CMD_VERB_GET_PROCESSING_STATE 0xf03 -#define HDA_CMD_VERB_SET_PROCESSING_STATE 0x703 - -#define HDA_CMD_GET_PROCESSING_STATE(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_PROCESSING_STATE, 0x0)) -#define HDA_CMD_SET_PROCESSING_STATE(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_PROCESSING_STATE, (payload))) - -#define HDA_CMD_GET_PROCESSING_STATE_STATE_OFF 0x00 -#define HDA_CMD_GET_PROCESSING_STATE_STATE_ON 0x01 -#define HDA_CMD_GET_PROCESSING_STATE_STATE_BENIGN 0x02 - -/* Coefficient Index */ -#define HDA_CMD_VERB_GET_COEFF_INDEX 0xd -#define HDA_CMD_VERB_SET_COEFF_INDEX 0x5 - -#define HDA_CMD_GET_COEFF_INDEX(cad, nid) \ - (HDA_CMD_4BIT((cad), (nid), \ - HDA_CMD_VERB_GET_COEFF_INDEX, 0x0)) -#define HDA_CMD_SET_COEFF_INDEX(cad, nid, payload) \ - (HDA_CMD_4BIT((cad), (nid), \ - HDA_CMD_VERB_SET_COEFF_INDEX, (payload))) - -/* Processing Coefficient */ -#define HDA_CMD_VERB_GET_PROCESSING_COEFF 0xc -#define HDA_CMD_VERB_SET_PROCESSING_COEFF 0x4 - -#define HDA_CMD_GET_PROCESSING_COEFF(cad, nid) \ - (HDA_CMD_4BIT((cad), (nid), \ - HDA_CMD_VERB_GET_PROCESSING_COEFF, 0x0)) -#define HDA_CMD_SET_PROCESSING_COEFF(cad, nid, payload) \ - (HDA_CMD_4BIT((cad), (nid), \ - HDA_CMD_VERB_SET_PROCESSING_COEFF, (payload))) - -/* Amplifier Gain/Mute */ -#define HDA_CMD_VERB_GET_AMP_GAIN_MUTE 0xb -#define HDA_CMD_VERB_SET_AMP_GAIN_MUTE 0x3 - -#define HDA_CMD_GET_AMP_GAIN_MUTE(cad, nid, payload) \ - (HDA_CMD_4BIT((cad), (nid), \ - HDA_CMD_VERB_GET_AMP_GAIN_MUTE, (payload))) -#define HDA_CMD_SET_AMP_GAIN_MUTE(cad, nid, payload) \ - (HDA_CMD_4BIT((cad), (nid), \ - HDA_CMD_VERB_SET_AMP_GAIN_MUTE, (payload))) - -#define HDA_CMD_GET_AMP_GAIN_MUTE_INPUT 0x0000 -#define HDA_CMD_GET_AMP_GAIN_MUTE_OUTPUT 0x8000 -#define HDA_CMD_GET_AMP_GAIN_MUTE_RIGHT 0x0000 -#define HDA_CMD_GET_AMP_GAIN_MUTE_LEFT 0x2000 - -#define HDA_CMD_GET_AMP_GAIN_MUTE_MUTE_MASK 0x00000008 -#define HDA_CMD_GET_AMP_GAIN_MUTE_MUTE_SHIFT 7 -#define HDA_CMD_GET_AMP_GAIN_MUTE_GAIN_MASK 0x00000007 -#define HDA_CMD_GET_AMP_GAIN_MUTE_GAIN_SHIFT 0 - -#define HDA_CMD_GET_AMP_GAIN_MUTE_MUTE(rsp) \ - (((rsp) & HDA_CMD_GET_AMP_GAIN_MUTE_MUTE_MASK) >> \ - HDA_CMD_GET_AMP_GAIN_MUTE_MUTE_SHIFT) -#define HDA_CMD_GET_AMP_GAIN_MUTE_GAIN(rsp) \ - (((rsp) & HDA_CMD_GET_AMP_GAIN_MUTE_GAIN_MASK) >> \ - HDA_CMD_GET_AMP_GAIN_MUTE_GAIN_SHIFT) - -#define HDA_CMD_SET_AMP_GAIN_MUTE_OUTPUT 0x8000 -#define HDA_CMD_SET_AMP_GAIN_MUTE_INPUT 0x4000 -#define HDA_CMD_SET_AMP_GAIN_MUTE_LEFT 0x2000 -#define HDA_CMD_SET_AMP_GAIN_MUTE_RIGHT 0x1000 -#define HDA_CMD_SET_AMP_GAIN_MUTE_INDEX_MASK 0x0f00 -#define HDA_CMD_SET_AMP_GAIN_MUTE_INDEX_SHIFT 8 -#define HDA_CMD_SET_AMP_GAIN_MUTE_MUTE 0x0080 -#define HDA_CMD_SET_AMP_GAIN_MUTE_GAIN_MASK 0x0007 -#define HDA_CMD_SET_AMP_GAIN_MUTE_GAIN_SHIFT 0 - -#define HDA_CMD_SET_AMP_GAIN_MUTE_INDEX(index) \ - (((index) << HDA_CMD_SET_AMP_GAIN_MUTE_INDEX_SHIFT) & \ - HDA_CMD_SET_AMP_GAIN_MUTE_INDEX_MASK) -#define HDA_CMD_SET_AMP_GAIN_MUTE_GAIN(index) \ - (((index) << HDA_CMD_SET_AMP_GAIN_MUTE_GAIN_SHIFT) & \ - HDA_CMD_SET_AMP_GAIN_MUTE_GAIN_MASK) - -/* Converter format */ -#define HDA_CMD_VERB_GET_CONV_FMT 0xa -#define HDA_CMD_VERB_SET_CONV_FMT 0x2 - -#define HDA_CMD_GET_CONV_FMT(cad, nid) \ - (HDA_CMD_4BIT((cad), (nid), \ - HDA_CMD_VERB_GET_CONV_FMT, 0x0)) -#define HDA_CMD_SET_CONV_FMT(cad, nid, payload) \ - (HDA_CMD_4BIT((cad), (nid), \ - HDA_CMD_VERB_SET_CONV_FMT, (payload))) - -/* Digital Converter Control */ -#define HDA_CMD_VERB_GET_DIGITAL_CONV_FMT1 0xf0d -#define HDA_CMD_VERB_GET_DIGITAL_CONV_FMT2 0xf0e -#define HDA_CMD_VERB_SET_DIGITAL_CONV_FMT1 0x70d -#define HDA_CMD_VERB_SET_DIGITAL_CONV_FMT2 0x70e - -#define HDA_CMD_GET_DIGITAL_CONV_FMT(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_DIGITAL_CONV_FMT1, 0x0)) -#define HDA_CMD_SET_DIGITAL_CONV_FMT1(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_DIGITAL_CONV_FMT1, (payload))) -#define HDA_CMD_SET_DIGITAL_CONV_FMT2(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_DIGITAL_CONV_FMT2, (payload))) - -#define HDA_CMD_GET_DIGITAL_CONV_FMT_CC_MASK 0x7f00 -#define HDA_CMD_GET_DIGITAL_CONV_FMT_CC_SHIFT 8 -#define HDA_CMD_GET_DIGITAL_CONV_FMT_L_MASK 0x0080 -#define HDA_CMD_GET_DIGITAL_CONV_FMT_L_SHIFT 7 -#define HDA_CMD_GET_DIGITAL_CONV_FMT_PRO_MASK 0x0040 -#define HDA_CMD_GET_DIGITAL_CONV_FMT_PRO_SHIFT 6 -#define HDA_CMD_GET_DIGITAL_CONV_FMT_NAUDIO_MASK 0x0020 -#define HDA_CMD_GET_DIGITAL_CONV_FMT_NAUDIO_SHIFT 5 -#define HDA_CMD_GET_DIGITAL_CONV_FMT_COPY_MASK 0x0010 -#define HDA_CMD_GET_DIGITAL_CONV_FMT_COPY_SHIFT 4 -#define HDA_CMD_GET_DIGITAL_CONV_FMT_PRE_MASK 0x0008 -#define HDA_CMD_GET_DIGITAL_CONV_FMT_PRE_SHIFT 3 -#define HDA_CMD_GET_DIGITAL_CONV_FMT_VCFG_MASK 0x0004 -#define HDA_CMD_GET_DIGITAL_CONV_FMT_VCFG_SHIFT 2 -#define HDA_CMD_GET_DIGITAL_CONV_FMT_V_MASK 0x0002 -#define HDA_CMD_GET_DIGITAL_CONV_FMT_V_SHIFT 1 -#define HDA_CMD_GET_DIGITAL_CONV_FMT_DIGEN_MASK 0x0001 -#define HDA_CMD_GET_DIGITAL_CONV_FMT_DIGEN_SHIFT 0 - -#define HDA_CMD_GET_DIGITAL_CONV_FMT_CC(rsp) \ - (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_CC_MASK) >> \ - HDA_CMD_GET_DIGITAL_CONV_FMT_CC_SHIFT) -#define HDA_CMD_GET_DIGITAL_CONV_FMT_L(rsp) \ - (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_L_MASK) >> \ - HDA_CMD_GET_DIGITAL_CONV_FMT_L_SHIFT) -#define HDA_CMD_GET_DIGITAL_CONV_FMT_PRO(rsp) \ - (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_PRO_MASK) >> \ - HDA_CMD_GET_DIGITAL_CONV_FMT_PRO_SHIFT) -#define HDA_CMD_GET_DIGITAL_CONV_FMT_NAUDIO(rsp) \ - (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_NAUDIO_MASK) >> \ - HDA_CMD_GET_DIGITAL_CONV_FMT_NAUDIO_SHIFT) -#define HDA_CMD_GET_DIGITAL_CONV_FMT_COPY(rsp) \ - (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_COPY_MASK) >> \ - HDA_CMD_GET_DIGITAL_CONV_FMT_COPY_SHIFT) -#define HDA_CMD_GET_DIGITAL_CONV_FMT_PRE(rsp) \ - (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_PRE_MASK) >> \ - HDA_CMD_GET_DIGITAL_CONV_FMT_PRE_SHIFT) -#define HDA_CMD_GET_DIGITAL_CONV_FMT_VCFG(rsp) \ - (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_VCFG_MASK) >> \ - HDA_CMD_GET_DIGITAL_CONV_FMT_VCFG_SHIFT) -#define HDA_CMD_GET_DIGITAL_CONV_FMT_V(rsp) \ - (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_V_MASK) >> \ - HDA_CMD_GET_DIGITAL_CONV_FMT_V_SHIFT) -#define HDA_CMD_GET_DIGITAL_CONV_FMT_DIGEN(rsp) \ - (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_DIGEN_MASK) >> \ - HDA_CMD_GET_DIGITAL_CONV_FMT_DIGEN_SHIFT) - -#define HDA_CMD_SET_DIGITAL_CONV_FMT1_L 0x80 -#define HDA_CMD_SET_DIGITAL_CONV_FMT1_PRO 0x40 -#define HDA_CMD_SET_DIGITAL_CONV_FMT1_NAUDIO 0x20 -#define HDA_CMD_SET_DIGITAL_CONV_FMT1_COPY 0x10 -#define HDA_CMD_SET_DIGITAL_CONV_FMT1_PRE 0x08 -#define HDA_CMD_SET_DIGITAL_CONV_FMT1_VCFG 0x04 -#define HDA_CMD_SET_DIGITAL_CONV_FMT1_V 0x02 -#define HDA_CMD_SET_DIGITAL_CONV_FMT1_DIGEN 0x01 - -/* Power State */ -#define HDA_CMD_VERB_GET_POWER_STATE 0xf05 -#define HDA_CMD_VERB_SET_POWER_STATE 0x705 - -#define HDA_CMD_GET_POWER_STATE(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_POWER_STATE, 0x0)) -#define HDA_CMD_SET_POWER_STATE(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_POWER_STATE, (payload))) - -#define HDA_CMD_POWER_STATE_D0 0x00 -#define HDA_CMD_POWER_STATE_D1 0x01 -#define HDA_CMD_POWER_STATE_D2 0x02 -#define HDA_CMD_POWER_STATE_D3 0x03 - -#define HDA_CMD_POWER_STATE_ACT_MASK 0x000000f0 -#define HDA_CMD_POWER_STATE_ACT_SHIFT 4 -#define HDA_CMD_POWER_STATE_SET_MASK 0x0000000f -#define HDA_CMD_POWER_STATE_SET_SHIFT 0 - -#define HDA_CMD_GET_POWER_STATE_ACT(rsp) \ - (((rsp) & HDA_CMD_POWER_STATE_ACT_MASK) >> \ - HDA_CMD_POWER_STATE_ACT_SHIFT) -#define HDA_CMD_GET_POWER_STATE_SET(rsp) \ - (((rsp) & HDA_CMD_POWER_STATE_SET_MASK) >> \ - HDA_CMD_POWER_STATE_SET_SHIFT) - -#define HDA_CMD_SET_POWER_STATE_ACT(ps) \ - (((ps) << HDA_CMD_POWER_STATE_ACT_SHIFT) & \ - HDA_CMD_POWER_STATE_ACT_MASK) -#define HDA_CMD_SET_POWER_STATE_SET(ps) \ - (((ps) << HDA_CMD_POWER_STATE_SET_SHIFT) & \ - HDA_CMD_POWER_STATE_ACT_MASK) - -/* Converter Stream, Channel */ -#define HDA_CMD_VERB_GET_CONV_STREAM_CHAN 0xf06 -#define HDA_CMD_VERB_SET_CONV_STREAM_CHAN 0x706 - -#define HDA_CMD_GET_CONV_STREAM_CHAN(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_CONV_STREAM_CHAN, 0x0)) -#define HDA_CMD_SET_CONV_STREAM_CHAN(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_CONV_STREAM_CHAN, (payload))) - -#define HDA_CMD_CONV_STREAM_CHAN_STREAM_MASK 0x000000f0 -#define HDA_CMD_CONV_STREAM_CHAN_STREAM_SHIFT 4 -#define HDA_CMD_CONV_STREAM_CHAN_CHAN_MASK 0x0000000f -#define HDA_CMD_CONV_STREAM_CHAN_CHAN_SHIFT 0 - -#define HDA_CMD_GET_CONV_STREAM_CHAN_STREAM(rsp) \ - (((rsp) & HDA_CMD_CONV_STREAM_CHAN_STREAM_MASK) >> \ - HDA_CMD_CONV_STREAM_CHAN_STREAM_SHIFT) -#define HDA_CMD_GET_CONV_STREAM_CHAN_CHAN(rsp) \ - (((rsp) & HDA_CMD_CONV_STREAM_CHAN_CHAN_MASK) >> \ - HDA_CMD_CONV_STREAM_CHAN_CHAN_SHIFT) - -#define HDA_CMD_SET_CONV_STREAM_CHAN_STREAM(param) \ - (((param) << HDA_CMD_CONV_STREAM_CHAN_STREAM_SHIFT) & \ - HDA_CMD_CONV_STREAM_CHAN_STREAM_MASK) -#define HDA_CMD_SET_CONV_STREAM_CHAN_CHAN(param) \ - (((param) << HDA_CMD_CONV_STREAM_CHAN_CHAN_SHIFT) & \ - HDA_CMD_CONV_STREAM_CHAN_CHAN_MASK) - -/* Input Converter SDI Select */ -#define HDA_CMD_VERB_GET_INPUT_CONVERTER_SDI_SELECT 0xf04 -#define HDA_CMD_VERB_SET_INPUT_CONVERTER_SDI_SELECT 0x704 - -#define HDA_CMD_GET_INPUT_CONVERTER_SDI_SELECT(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_INPUT_CONVERTER_SDI_SELECT, 0x0)) -#define HDA_CMD_SET_INPUT_CONVERTER_SDI_SELECT(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_INPUT_CONVERTER_SDI_SELECT, (payload))) - -/* Pin Widget Control */ -#define HDA_CMD_VERB_GET_PIN_WIDGET_CTRL 0xf07 -#define HDA_CMD_VERB_SET_PIN_WIDGET_CTRL 0x707 - -#define HDA_CMD_GET_PIN_WIDGET_CTRL(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_PIN_WIDGET_CTRL, 0x0)) -#define HDA_CMD_SET_PIN_WIDGET_CTRL(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_PIN_WIDGET_CTRL, (payload))) - -#define HDA_CMD_GET_PIN_WIDGET_CTRL_HPHN_ENABLE_MASK 0x00000080 -#define HDA_CMD_GET_PIN_WIDGET_CTRL_HPHN_ENABLE_SHIFT 7 -#define HDA_CMD_GET_PIN_WIDGET_CTRL_OUT_ENABLE_MASK 0x00000040 -#define HDA_CMD_GET_PIN_WIDGET_CTRL_OUT_ENABLE_SHIFT 6 -#define HDA_CMD_GET_PIN_WIDGET_CTRL_IN_ENABLE_MASK 0x00000020 -#define HDA_CMD_GET_PIN_WIDGET_CTRL_IN_ENABLE_SHIFT 5 -#define HDA_CMD_GET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK 0x00000007 -#define HDA_CMD_GET_PIN_WIDGET_CTRL_VREF_ENABLE_SHIFT 0 - -#define HDA_CMD_GET_PIN_WIDGET_CTRL_HPHN_ENABLE(rsp) \ - (((rsp) & HDA_CMD_GET_PIN_WIDGET_CTRL_HPHN_ENABLE_MASK) >> \ - HDA_CMD_GET_PIN_WIDGET_CTRL_HPHN_ENABLE_SHIFT) -#define HDA_CMD_GET_PIN_WIDGET_CTRL_OUT_ENABLE(rsp) \ - (((rsp) & HDA_CMD_GET_PIN_WIDGET_CTRL_OUT_ENABLE_MASK) >> \ - HDA_GET_CMD_PIN_WIDGET_CTRL_OUT_ENABLE_SHIFT) -#define HDA_CMD_GET_PIN_WIDGET_CTRL_IN_ENABLE(rsp) \ - (((rsp) & HDA_CMD_GET_PIN_WIDGET_CTRL_IN_ENABLE_MASK) >> \ - HDA_CMD_GET_PIN_WIDGET_CTRL_IN_ENABLE_SHIFT) -#define HDA_CMD_GET_PIN_WIDGET_CTRL_VREF_ENABLE(rsp) \ - (((rsp) & HDA_CMD_GET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK) >> \ - HDA_CMD_GET_PIN_WIDGET_CTRL_VREF_ENABLE_SHIFT) - -#define HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE 0x80 -#define HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE 0x40 -#define HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE 0x20 -#define HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK 0x07 -#define HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_SHIFT 0 - -#define HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(param) \ - (((param) << HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_SHIFT) & \ - HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK) - -#define HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_HIZ 0 -#define HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_50 1 -#define HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_GROUND 2 -#define HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_80 4 -#define HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_100 5 - -/* Unsolicited Response */ -#define HDA_CMD_VERB_GET_UNSOLICITED_RESPONSE 0xf08 -#define HDA_CMD_VERB_SET_UNSOLICITED_RESPONSE 0x708 - -#define HDA_CMD_GET_UNSOLICITED_RESPONSE(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_UNSOLICITED_RESPONSE, 0x0)) -#define HDA_CMD_SET_UNSOLICITED_RESPONSE(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_UNSOLICITED_RESPONSE, (payload))) - -#define HDA_CMD_GET_UNSOLICITED_RESPONSE_ENABLE_MASK 0x00000080 -#define HDA_CMD_GET_UNSOLICITED_RESPONSE_ENABLE_SHIFT 7 -#define HDA_CMD_GET_UNSOLICITED_RESPONSE_TAG_MASK 0x0000001f -#define HDA_CMD_GET_UNSOLICITED_RESPONSE_TAG_SHIFT 0 - -#define HDA_CMD_GET_UNSOLICITED_RESPONSE_ENABLE(rsp) \ - (((rsp) & HDA_CMD_GET_UNSOLICITED_RESPONSE_ENABLE_MASK) >> \ - HDA_CMD_GET_UNSOLICITED_RESPONSE_ENABLE_SHIFT) -#define HDA_CMD_GET_UNSOLICITED_RESPONSE_TAG(rsp) \ - (((rsp) & HDA_CMD_GET_UNSOLICITED_RESPONSE_TAG_MASK) >> \ - HDA_CMD_GET_UNSOLICITED_RESPONSE_TAG_SHIFT) - -#define HDA_CMD_SET_UNSOLICITED_RESPONSE_ENABLE 0x80 -#define HDA_CMD_SET_UNSOLICITED_RESPONSE_TAG_MASK 0x3f -#define HDA_CMD_SET_UNSOLICITED_RESPONSE_TAG_SHIFT 0 - -#define HDA_CMD_SET_UNSOLICITED_RESPONSE_TAG(param) \ - (((param) << HDA_CMD_SET_UNSOLICITED_RESPONSE_TAG_SHIFT) & \ - HDA_CMD_SET_UNSOLICITED_RESPONSE_TAG_MASK) - -/* Pin Sense */ -#define HDA_CMD_VERB_GET_PIN_SENSE 0xf09 -#define HDA_CMD_VERB_SET_PIN_SENSE 0x709 - -#define HDA_CMD_GET_PIN_SENSE(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_PIN_SENSE, 0x0)) -#define HDA_CMD_SET_PIN_SENSE(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_PIN_SENSE, (payload))) - -#define HDA_CMD_GET_PIN_SENSE_PRESENCE_DETECT 0x80000000 -#define HDA_CMD_GET_PIN_SENSE_ELD_VALID 0x40000000 -#define HDA_CMD_GET_PIN_SENSE_IMP_SENSE_MASK 0x7fffffff -#define HDA_CMD_GET_PIN_SENSE_IMP_SENSE_SHIFT 0 - -#define HDA_CMD_GET_PIN_SENSE_IMP_SENSE(rsp) \ - (((rsp) & HDA_CMD_GET_PIN_SENSE_IMP_SENSE_MASK) >> \ - HDA_CMD_GET_PIN_SENSE_IMP_SENSE_SHIFT) - -#define HDA_CMD_GET_PIN_SENSE_IMP_SENSE_INVALID 0x7fffffff - -#define HDA_CMD_SET_PIN_SENSE_LEFT_CHANNEL 0x00 -#define HDA_CMD_SET_PIN_SENSE_RIGHT_CHANNEL 0x01 - -/* EAPD/BTL Enable */ -#define HDA_CMD_VERB_GET_EAPD_BTL_ENABLE 0xf0c -#define HDA_CMD_VERB_SET_EAPD_BTL_ENABLE 0x70c - -#define HDA_CMD_GET_EAPD_BTL_ENABLE(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_EAPD_BTL_ENABLE, 0x0)) -#define HDA_CMD_SET_EAPD_BTL_ENABLE(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_EAPD_BTL_ENABLE, (payload))) - -#define HDA_CMD_GET_EAPD_BTL_ENABLE_LR_SWAP_MASK 0x00000004 -#define HDA_CMD_GET_EAPD_BTL_ENABLE_LR_SWAP_SHIFT 2 -#define HDA_CMD_GET_EAPD_BTL_ENABLE_EAPD_MASK 0x00000002 -#define HDA_CMD_GET_EAPD_BTL_ENABLE_EAPD_SHIFT 1 -#define HDA_CMD_GET_EAPD_BTL_ENABLE_BTL_MASK 0x00000001 -#define HDA_CMD_GET_EAPD_BTL_ENABLE_BTL_SHIFT 0 - -#define HDA_CMD_GET_EAPD_BTL_ENABLE_LR_SWAP(rsp) \ - (((rsp) & HDA_CMD_GET_EAPD_BTL_ENABLE_LR_SWAP_MASK) >> \ - HDA_CMD_GET_EAPD_BTL_ENABLE_LR_SWAP_SHIFT) -#define HDA_CMD_GET_EAPD_BTL_ENABLE_EAPD(rsp) \ - (((rsp) & HDA_CMD_GET_EAPD_BTL_ENABLE_EAPD_MASK) >> \ - HDA_CMD_GET_EAPD_BTL_ENABLE_EAPD_SHIFT) -#define HDA_CMD_GET_EAPD_BTL_ENABLE_BTL(rsp) \ - (((rsp) & HDA_CMD_GET_EAPD_BTL_ENABLE_BTL_MASK) >> \ - HDA_CMD_GET_EAPD_BTL_ENABLE_BTL_SHIFT) - -#define HDA_CMD_SET_EAPD_BTL_ENABLE_LR_SWAP 0x04 -#define HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD 0x02 -#define HDA_CMD_SET_EAPD_BTL_ENABLE_BTL 0x01 - -/* GPI Data */ -#define HDA_CMD_VERB_GET_GPI_DATA 0xf10 -#define HDA_CMD_VERB_SET_GPI_DATA 0x710 - -#define HDA_CMD_GET_GPI_DATA(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_GPI_DATA, 0x0)) -#define HDA_CMD_SET_GPI_DATA(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_GPI_DATA, (payload))) - -/* GPI Wake Enable Mask */ -#define HDA_CMD_VERB_GET_GPI_WAKE_ENABLE_MASK 0xf11 -#define HDA_CMD_VERB_SET_GPI_WAKE_ENABLE_MASK 0x711 - -#define HDA_CMD_GET_GPI_WAKE_ENABLE_MASK(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_GPI_WAKE_ENABLE_MASK, 0x0)) -#define HDA_CMD_SET_GPI_WAKE_ENABLE_MASK(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_GPI_WAKE_ENABLE_MASK, (payload))) - -/* GPI Unsolicited Enable Mask */ -#define HDA_CMD_VERB_GET_GPI_UNSOLICITED_ENABLE_MASK 0xf12 -#define HDA_CMD_VERB_SET_GPI_UNSOLICITED_ENABLE_MASK 0x712 - -#define HDA_CMD_GET_GPI_UNSOLICITED_ENABLE_MASK(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_GPI_UNSOLICITED_ENABLE_MASK, 0x0)) -#define HDA_CMD_SET_GPI_UNSOLICITED_ENABLE_MASK(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_GPI_UNSOLICITED_ENABLE_MASK, (payload))) - -/* GPI Sticky Mask */ -#define HDA_CMD_VERB_GET_GPI_STICKY_MASK 0xf13 -#define HDA_CMD_VERB_SET_GPI_STICKY_MASK 0x713 - -#define HDA_CMD_GET_GPI_STICKY_MASK(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_GPI_STICKY_MASK, 0x0)) -#define HDA_CMD_SET_GPI_STICKY_MASK(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_GPI_STICKY_MASK, (payload))) - -/* GPO Data */ -#define HDA_CMD_VERB_GET_GPO_DATA 0xf14 -#define HDA_CMD_VERB_SET_GPO_DATA 0x714 - -#define HDA_CMD_GET_GPO_DATA(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_GPO_DATA, 0x0)) -#define HDA_CMD_SET_GPO_DATA(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_GPO_DATA, (payload))) - -/* GPIO Data */ -#define HDA_CMD_VERB_GET_GPIO_DATA 0xf15 -#define HDA_CMD_VERB_SET_GPIO_DATA 0x715 - -#define HDA_CMD_GET_GPIO_DATA(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_GPIO_DATA, 0x0)) -#define HDA_CMD_SET_GPIO_DATA(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_GPIO_DATA, (payload))) - -/* GPIO Enable Mask */ -#define HDA_CMD_VERB_GET_GPIO_ENABLE_MASK 0xf16 -#define HDA_CMD_VERB_SET_GPIO_ENABLE_MASK 0x716 - -#define HDA_CMD_GET_GPIO_ENABLE_MASK(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_GPIO_ENABLE_MASK, 0x0)) -#define HDA_CMD_SET_GPIO_ENABLE_MASK(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_GPIO_ENABLE_MASK, (payload))) - -/* GPIO Direction */ -#define HDA_CMD_VERB_GET_GPIO_DIRECTION 0xf17 -#define HDA_CMD_VERB_SET_GPIO_DIRECTION 0x717 - -#define HDA_CMD_GET_GPIO_DIRECTION(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_GPIO_DIRECTION, 0x0)) -#define HDA_CMD_SET_GPIO_DIRECTION(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_GPIO_DIRECTION, (payload))) - -/* GPIO Wake Enable Mask */ -#define HDA_CMD_VERB_GET_GPIO_WAKE_ENABLE_MASK 0xf18 -#define HDA_CMD_VERB_SET_GPIO_WAKE_ENABLE_MASK 0x718 - -#define HDA_CMD_GET_GPIO_WAKE_ENABLE_MASK(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_GPIO_WAKE_ENABLE_MASK, 0x0)) -#define HDA_CMD_SET_GPIO_WAKE_ENABLE_MASK(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_GPIO_WAKE_ENABLE_MASK, (payload))) - -/* GPIO Unsolicited Enable Mask */ -#define HDA_CMD_VERB_GET_GPIO_UNSOLICITED_ENABLE_MASK 0xf19 -#define HDA_CMD_VERB_SET_GPIO_UNSOLICITED_ENABLE_MASK 0x719 - -#define HDA_CMD_GET_GPIO_UNSOLICITED_ENABLE_MASK(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_GPIO_UNSOLICITED_ENABLE_MASK, 0x0)) -#define HDA_CMD_SET_GPIO_UNSOLICITED_ENABLE_MASK(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_GPIO_UNSOLICITED_ENABLE_MASK, (payload))) - -/* GPIO_STICKY_MASK */ -#define HDA_CMD_VERB_GET_GPIO_STICKY_MASK 0xf1a -#define HDA_CMD_VERB_SET_GPIO_STICKY_MASK 0x71a - -#define HDA_CMD_GET_GPIO_STICKY_MASK(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_GPIO_STICKY_MASK, 0x0)) -#define HDA_CMD_SET_GPIO_STICKY_MASK(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_GPIO_STICKY_MASK, (payload))) - -/* Beep Generation */ -#define HDA_CMD_VERB_GET_BEEP_GENERATION 0xf0a -#define HDA_CMD_VERB_SET_BEEP_GENERATION 0x70a - -#define HDA_CMD_GET_BEEP_GENERATION(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_BEEP_GENERATION, 0x0)) -#define HDA_CMD_SET_BEEP_GENERATION(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_BEEP_GENERATION, (payload))) - -/* Volume Knob */ -#define HDA_CMD_VERB_GET_VOLUME_KNOB 0xf0f -#define HDA_CMD_VERB_SET_VOLUME_KNOB 0x70f - -#define HDA_CMD_GET_VOLUME_KNOB(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_VOLUME_KNOB, 0x0)) -#define HDA_CMD_SET_VOLUME_KNOB(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_VOLUME_KNOB, (payload))) - -/* Subsystem ID */ -#define HDA_CMD_VERB_GET_SUBSYSTEM_ID 0xf20 -#define HDA_CMD_VERB_SET_SUSBYSTEM_ID1 0x720 -#define HDA_CMD_VERB_SET_SUBSYSTEM_ID2 0x721 -#define HDA_CMD_VERB_SET_SUBSYSTEM_ID3 0x722 -#define HDA_CMD_VERB_SET_SUBSYSTEM_ID4 0x723 - -#define HDA_CMD_GET_SUBSYSTEM_ID(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_SUBSYSTEM_ID, 0x0)) -#define HDA_CMD_SET_SUBSYSTEM_ID1(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_SUSBYSTEM_ID1, (payload))) -#define HDA_CMD_SET_SUBSYSTEM_ID2(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_SUSBYSTEM_ID2, (payload))) -#define HDA_CMD_SET_SUBSYSTEM_ID3(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_SUSBYSTEM_ID3, (payload))) -#define HDA_CMD_SET_SUBSYSTEM_ID4(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_SUSBYSTEM_ID4, (payload))) - -/* Configuration Default */ -#define HDA_CMD_VERB_GET_CONFIGURATION_DEFAULT 0xf1c -#define HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT1 0x71c -#define HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT2 0x71d -#define HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT3 0x71e -#define HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT4 0x71f - -#define HDA_CMD_GET_CONFIGURATION_DEFAULT(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_CONFIGURATION_DEFAULT, 0x0)) -#define HDA_CMD_SET_CONFIGURATION_DEFAULT1(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT1, (payload))) -#define HDA_CMD_SET_CONFIGURATION_DEFAULT2(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT2, (payload))) -#define HDA_CMD_SET_CONFIGURATION_DEFAULT3(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT3, (payload))) -#define HDA_CMD_SET_CONFIGURATION_DEFAULT4(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT4, (payload))) - -/* Stripe Control */ -#define HDA_CMD_VERB_GET_STRIPE_CONTROL 0xf24 -#define HDA_CMD_VERB_SET_STRIPE_CONTROL 0x724 - -#define HDA_CMD_GET_STRIPE_CONTROL(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_STRIPE_CONTROL, 0x0)) -#define HDA_CMD_SET_STRIPE_CONTROL(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_STRIPE_CONTROL, (payload))) - -/* Channel Count Control */ -#define HDA_CMD_VERB_GET_CONV_CHAN_COUNT 0xf2d -#define HDA_CMD_VERB_SET_CONV_CHAN_COUNT 0x72d - -#define HDA_CMD_GET_CONV_CHAN_COUNT(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_CONV_CHAN_COUNT, 0x0)) -#define HDA_CMD_SET_CONV_CHAN_COUNT(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_CONV_CHAN_COUNT, (payload))) - -#define HDA_CMD_VERB_GET_HDMI_DIP_SIZE 0xf2e - -#define HDA_CMD_GET_HDMI_DIP_SIZE(cad, nid, arg) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_HDMI_DIP_SIZE, (arg))) - -#define HDA_CMD_VERB_GET_HDMI_ELDD 0xf2f - -#define HDA_CMD_GET_HDMI_ELDD(cad, nid, off) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_HDMI_ELDD, (off))) - -#define HDA_CMD_VERB_GET_HDMI_DIP_INDEX 0xf30 -#define HDA_CMD_VERB_SET_HDMI_DIP_INDEX 0x730 - -#define HDA_CMD_GET_HDMI_DIP_INDEX(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_HDMI_DIP_INDEX, 0x0)) -#define HDA_CMD_SET_HDMI_DIP_INDEX(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_HDMI_DIP_INDEX, (payload))) - -#define HDA_CMD_VERB_GET_HDMI_DIP_DATA 0xf31 -#define HDA_CMD_VERB_SET_HDMI_DIP_DATA 0x731 - -#define HDA_CMD_GET_HDMI_DIP_DATA(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_HDMI_DIP_DATA, 0x0)) -#define HDA_CMD_SET_HDMI_DIP_DATA(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_HDMI_DIP_DATA, (payload))) - -#define HDA_CMD_VERB_GET_HDMI_DIP_XMIT 0xf32 -#define HDA_CMD_VERB_SET_HDMI_DIP_XMIT 0x732 - -#define HDA_CMD_GET_HDMI_DIP_XMIT(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_HDMI_DIP_XMIT, 0x0)) -#define HDA_CMD_SET_HDMI_DIP_XMIT(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_HDMI_DIP_XMIT, (payload))) - -#define HDA_CMD_VERB_GET_HDMI_CP_CTRL 0xf33 -#define HDA_CMD_VERB_SET_HDMI_CP_CTRL 0x733 - -#define HDA_CMD_VERB_GET_HDMI_CHAN_SLOT 0xf34 -#define HDA_CMD_VERB_SET_HDMI_CHAN_SLOT 0x734 - -#define HDA_CMD_GET_HDMI_CHAN_SLOT(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_GET_HDMI_CHAN_SLOT, 0x0)) -#define HDA_CMD_SET_HDMI_CHAN_SLOT(cad, nid, payload) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_SET_HDMI_CHAN_SLOT, (payload))) - -#define HDA_HDMI_CODING_TYPE_REF_STREAM_HEADER 0 -#define HDA_HDMI_CODING_TYPE_LPCM 1 -#define HDA_HDMI_CODING_TYPE_AC3 2 -#define HDA_HDMI_CODING_TYPE_MPEG1 3 -#define HDA_HDMI_CODING_TYPE_MP3 4 -#define HDA_HDMI_CODING_TYPE_MPEG2 5 -#define HDA_HDMI_CODING_TYPE_AACLC 6 -#define HDA_HDMI_CODING_TYPE_DTS 7 -#define HDA_HDMI_CODING_TYPE_ATRAC 8 -#define HDA_HDMI_CODING_TYPE_SACD 9 -#define HDA_HDMI_CODING_TYPE_EAC3 10 -#define HDA_HDMI_CODING_TYPE_DTS_HD 11 -#define HDA_HDMI_CODING_TYPE_MLP 12 -#define HDA_HDMI_CODING_TYPE_DST 13 -#define HDA_HDMI_CODING_TYPE_WMAPRO 14 -#define HDA_HDMI_CODING_TYPE_REF_CTX 15 - -/* Function Reset */ -#define HDA_CMD_VERB_FUNCTION_RESET 0x7ff - -#define HDA_CMD_FUNCTION_RESET(cad, nid) \ - (HDA_CMD_12BIT((cad), (nid), \ - HDA_CMD_VERB_FUNCTION_RESET, 0x0)) - - -/**************************************************************************** - * HDA Device Parameters - ****************************************************************************/ - -/* Vendor ID */ -#define HDA_PARAM_VENDOR_ID 0x00 - -#define HDA_PARAM_VENDOR_ID_VENDOR_ID_MASK 0xffff0000 -#define HDA_PARAM_VENDOR_ID_VENDOR_ID_SHIFT 16 -#define HDA_PARAM_VENDOR_ID_DEVICE_ID_MASK 0x0000ffff -#define HDA_PARAM_VENDOR_ID_DEVICE_ID_SHIFT 0 - -#define HDA_PARAM_VENDOR_ID_VENDOR_ID(param) \ - (((param) & HDA_PARAM_VENDOR_ID_VENDOR_ID_MASK) >> \ - HDA_PARAM_VENDOR_ID_VENDOR_ID_SHIFT) -#define HDA_PARAM_VENDOR_ID_DEVICE_ID(param) \ - (((param) & HDA_PARAM_VENDOR_ID_DEVICE_ID_MASK) >> \ - HDA_PARAM_VENDOR_ID_DEVICE_ID_SHIFT) - -/* Revision ID */ -#define HDA_PARAM_REVISION_ID 0x02 - -#define HDA_PARAM_REVISION_ID_MAJREV_MASK 0x00f00000 -#define HDA_PARAM_REVISION_ID_MAJREV_SHIFT 20 -#define HDA_PARAM_REVISION_ID_MINREV_MASK 0x000f0000 -#define HDA_PARAM_REVISION_ID_MINREV_SHIFT 16 -#define HDA_PARAM_REVISION_ID_REVISION_ID_MASK 0x0000ff00 -#define HDA_PARAM_REVISION_ID_REVISION_ID_SHIFT 8 -#define HDA_PARAM_REVISION_ID_STEPPING_ID_MASK 0x000000ff -#define HDA_PARAM_REVISION_ID_STEPPING_ID_SHIFT 0 - -#define HDA_PARAM_REVISION_ID_MAJREV(param) \ - (((param) & HDA_PARAM_REVISION_ID_MAJREV_MASK) >> \ - HDA_PARAM_REVISION_ID_MAJREV_SHIFT) -#define HDA_PARAM_REVISION_ID_MINREV(param) \ - (((param) & HDA_PARAM_REVISION_ID_MINREV_MASK) >> \ - HDA_PARAM_REVISION_ID_MINREV_SHIFT) -#define HDA_PARAM_REVISION_ID_REVISION_ID(param) \ - (((param) & HDA_PARAM_REVISION_ID_REVISION_ID_MASK) >> \ - HDA_PARAM_REVISION_ID_REVISION_ID_SHIFT) -#define HDA_PARAM_REVISION_ID_STEPPING_ID(param) \ - (((param) & HDA_PARAM_REVISION_ID_STEPPING_ID_MASK) >> \ - HDA_PARAM_REVISION_ID_STEPPING_ID_SHIFT) - -/* Subordinate Node Cound */ -#define HDA_PARAM_SUB_NODE_COUNT 0x04 - -#define HDA_PARAM_SUB_NODE_COUNT_START_MASK 0x00ff0000 -#define HDA_PARAM_SUB_NODE_COUNT_START_SHIFT 16 -#define HDA_PARAM_SUB_NODE_COUNT_TOTAL_MASK 0x000000ff -#define HDA_PARAM_SUB_NODE_COUNT_TOTAL_SHIFT 0 - -#define HDA_PARAM_SUB_NODE_COUNT_START(param) \ - (((param) & HDA_PARAM_SUB_NODE_COUNT_START_MASK) >> \ - HDA_PARAM_SUB_NODE_COUNT_START_SHIFT) -#define HDA_PARAM_SUB_NODE_COUNT_TOTAL(param) \ - (((param) & HDA_PARAM_SUB_NODE_COUNT_TOTAL_MASK) >> \ - HDA_PARAM_SUB_NODE_COUNT_TOTAL_SHIFT) - -/* Function Group Type */ -#define HDA_PARAM_FCT_GRP_TYPE 0x05 - -#define HDA_PARAM_FCT_GRP_TYPE_UNSOL_MASK 0x00000100 -#define HDA_PARAM_FCT_GRP_TYPE_UNSOL_SHIFT 8 -#define HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_MASK 0x000000ff -#define HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_SHIFT 0 - -#define HDA_PARAM_FCT_GRP_TYPE_UNSOL(param) \ - (((param) & HDA_PARAM_FCT_GRP_TYPE_UNSOL_MASK) >> \ - HDA_PARAM_FCT_GROUP_TYPE_UNSOL_SHIFT) -#define HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE(param) \ - (((param) & HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_MASK) >> \ - HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_SHIFT) - -#define HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO 0x01 -#define HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_MODEM 0x02 - -/* Audio Function Group Capabilities */ -#define HDA_PARAM_AUDIO_FCT_GRP_CAP 0x08 - -#define HDA_PARAM_AUDIO_FCT_GRP_CAP_BEEP_GEN_MASK 0x00010000 -#define HDA_PARAM_AUDIO_FCT_GRP_CAP_BEEP_GEN_SHIFT 16 -#define HDA_PARAM_AUDIO_FCT_GRP_CAP_INPUT_DELAY_MASK 0x00000f00 -#define HDA_PARAM_AUDIO_FCT_GRP_CAP_INPUT_DELAY_SHIFT 8 -#define HDA_PARAM_AUDIO_FCT_GRP_CAP_OUTPUT_DELAY_MASK 0x0000000f -#define HDA_PARAM_AUDIO_FCT_GRP_CAP_OUTPUT_DELAY_SHIFT 0 - -#define HDA_PARAM_AUDIO_FCT_GRP_CAP_BEEP_GEN(param) \ - (((param) & HDA_PARAM_AUDIO_FCT_GRP_CAP_BEEP_GEN_MASK) >> \ - HDA_PARAM_AUDIO_FCT_GRP_CAP_BEEP_GEN_SHIFT) -#define HDA_PARAM_AUDIO_FCT_GRP_CAP_INPUT_DELAY(param) \ - (((param) & HDA_PARAM_AUDIO_FCT_GRP_CAP_INPUT_DELAY_MASK) >> \ - HDA_PARAM_AUDIO_FCT_GRP_CAP_INPUT_DELAY_SHIFT) -#define HDA_PARAM_AUDIO_FCT_GRP_CAP_OUTPUT_DELAY(param) \ - (((param) & HDA_PARAM_AUDIO_FCT_GRP_CAP_OUTPUT_DELAY_MASK) >> \ - HDA_PARAM_AUDIO_FCT_GRP_CAP_OUTPUT_DELAY_SHIFT) - -/* Audio Widget Capabilities */ -#define HDA_PARAM_AUDIO_WIDGET_CAP 0x09 - -#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_MASK 0x00f00000 -#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT 20 -#define HDA_PARAM_AUDIO_WIDGET_CAP_DELAY_MASK 0x000f0000 -#define HDA_PARAM_AUDIO_WIDGET_CAP_DELAY_SHIFT 16 -#define HDA_PARAM_AUDIO_WIDGET_CAP_CC_EXT_MASK 0x0000e000 -#define HDA_PARAM_AUDIO_WIDGET_CAP_CC_EXT_SHIFT 13 -#define HDA_PARAM_AUDIO_WIDGET_CAP_CP_MASK 0x00001000 -#define HDA_PARAM_AUDIO_WIDGET_CAP_CP_SHIFT 12 -#define HDA_PARAM_AUDIO_WIDGET_CAP_LR_SWAP_MASK 0x00000800 -#define HDA_PARAM_AUDIO_WIDGET_CAP_LR_SWAP_SHIFT 11 -#define HDA_PARAM_AUDIO_WIDGET_CAP_POWER_CTRL_MASK 0x00000400 -#define HDA_PARAM_AUDIO_WIDGET_CAP_POWER_CTRL_SHIFT 10 -#define HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL_MASK 0x00000200 -#define HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL_SHIFT 9 -#define HDA_PARAM_AUDIO_WIDGET_CAP_CONN_LIST_MASK 0x00000100 -#define HDA_PARAM_AUDIO_WIDGET_CAP_CONN_LIST_SHIFT 8 -#define HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP_MASK 0x00000080 -#define HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP_SHIFT 7 -#define HDA_PARAM_AUDIO_WIDGET_CAP_PROC_WIDGET_MASK 0x00000040 -#define HDA_PARAM_AUDIO_WIDGET_CAP_PROC_WIDGET_SHIFT 6 -#define HDA_PARAM_AUDIO_WIDGET_CAP_STRIPE_MASK 0x00000020 -#define HDA_PARAM_AUDIO_WIDGET_CAP_STRIPE_SHIFT 5 -#define HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR_MASK 0x00000010 -#define HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR_SHIFT 4 -#define HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR_MASK 0x00000008 -#define HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR_SHIFT 3 -#define HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP_MASK 0x00000004 -#define HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP_SHIFT 2 -#define HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP_MASK 0x00000002 -#define HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP_SHIFT 1 -#define HDA_PARAM_AUDIO_WIDGET_CAP_STEREO_MASK 0x00000001 -#define HDA_PARAM_AUDIO_WIDGET_CAP_STEREO_SHIFT 0 - -#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE(param) \ - (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_MASK) >> \ - HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT) -#define HDA_PARAM_AUDIO_WIDGET_CAP_DELAY(param) \ - (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_DELAY_MASK) >> \ - HDA_PARAM_AUDIO_WIDGET_CAP_DELAY_SHIFT) -#define HDA_PARAM_AUDIO_WIDGET_CAP_CC(param) \ - ((((param) & HDA_PARAM_AUDIO_WIDGET_CAP_CC_EXT_MASK) >> \ - (HDA_PARAM_AUDIO_WIDGET_CAP_CC_EXT_SHIFT - 1)) | \ - (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_STEREO_MASK) >> \ - HDA_PARAM_AUDIO_WIDGET_CAP_STEREO_SHIFT)) -#define HDA_PARAM_AUDIO_WIDGET_CAP_CP(param) \ - (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_CP_MASK) >> \ - HDA_PARAM_AUDIO_WIDGET_CAP_CP_SHIFT) -#define HDA_PARAM_AUDIO_WIDGET_CAP_LR_SWAP(param) \ - (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_LR_SWAP_MASK) >> \ - HDA_PARAM_AUDIO_WIDGET_CAP_LR_SWAP_SHIFT) -#define HDA_PARAM_AUDIO_WIDGET_CAP_POWER_CTRL(param) \ - (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_POWER_CTRL_MASK) >> \ - HDA_PARAM_AUDIO_WIDGET_CAP_POWER_CTRL_SHIFT) -#define HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(param) \ - (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL_MASK) >> \ - HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL_SHIFT) -#define HDA_PARAM_AUDIO_WIDGET_CAP_CONN_LIST(param) \ - (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_CONN_LIST_MASK) >> \ - HDA_PARAM_AUDIO_WIDGET_CAP_CONN_LIST_SHIFT) -#define HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(param) \ - (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP_MASK) >> \ - HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP_SHIFT) -#define HDA_PARAM_AUDIO_WIDGET_CAP_PROC_WIDGET(param) \ - (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_PROC_WIDGET_MASK) >> \ - HDA_PARAM_AUDIO_WIDGET_CAP_PROC_WIDGET_SHIFT) -#define HDA_PARAM_AUDIO_WIDGET_CAP_STRIPE(param) \ - (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_STRIPE_MASK) >> \ - HDA_PARAM_AUDIO_WIDGET_CAP_STRIPE_SHIFT) -#define HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR(param) \ - (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR_MASK) >> \ - HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR_SHIFT) -#define HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR(param) \ - (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR_MASK) >> \ - HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR_SHIFT) -#define HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP(param) \ - (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP_MASK) >> \ - HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP_SHIFT) -#define HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP(param) \ - (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP_MASK) >> \ - HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP_SHIFT) -#define HDA_PARAM_AUDIO_WIDGET_CAP_STEREO(param) \ - (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_STEREO_MASK) >> \ - HDA_PARAM_AUDIO_WIDGET_CAP_STEREO_SHIFT) - -#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT 0x0 -#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT 0x1 -#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER 0x2 -#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR 0x3 -#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX 0x4 -#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_POWER_WIDGET 0x5 -#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_VOLUME_WIDGET 0x6 -#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET 0x7 -#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_VENDOR_WIDGET 0xf - -/* Supported PCM Size, Rates */ - -#define HDA_PARAM_SUPP_PCM_SIZE_RATE 0x0a - -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT_MASK 0x00100000 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT_SHIFT 20 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT_MASK 0x00080000 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT_SHIFT 19 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT_MASK 0x00040000 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT_SHIFT 18 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT_MASK 0x00020000 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT_SHIFT 17 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT_MASK 0x00010000 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT_SHIFT 16 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ_MASK 0x00000001 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ_SHIFT 0 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ_MASK 0x00000002 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ_SHIFT 1 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ_MASK 0x00000004 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ_SHIFT 2 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ_MASK 0x00000008 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ_SHIFT 3 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ_MASK 0x00000010 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ_SHIFT 4 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ_MASK 0x00000020 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ_SHIFT 5 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_48KHZ_MASK 0x00000040 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_48KHZ_SHIFT 6 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ_MASK 0x00000080 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ_SHIFT 7 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ_MASK 0x00000100 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ_SHIFT 8 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ_MASK 0x00000200 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ_SHIFT 9 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ_MASK 0x00000400 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ_SHIFT 10 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_384KHZ_MASK 0x00000800 -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_384KHZ_SHIFT 11 - -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT(param) \ - (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT_MASK) >> \ - HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT_SHIFT) -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT(param) \ - (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT_MASK) >> \ - HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT_SHIFT) -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT(param) \ - (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT_MASK) >> \ - HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT_SHIFT) -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT(param) \ - (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT_MASK) >> \ - HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT_SHIFT) -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT(param) \ - (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT_MASK) >> \ - HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT_SHIFT) -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ(param) \ - (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ_MASK) >> \ - HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ_SHIFT) -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ(param) \ - (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ_MASK) >> \ - HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ_SHIFT) -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ(param) \ - (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ_MASK) >> \ - HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ_SHIFT) -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ(param) \ - (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ_MASK) >> \ - HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ_SHIFT) -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ(param) \ - (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ_MASK) >> \ - HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ_SHIFT) -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ(param) \ - (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ_MASK) >> \ - HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ_SHIFT) -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_48KHZ(param) \ - (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_48KHZ_MASK) >> \ - HDA_PARAM_SUPP_PCM_SIZE_RATE_48KHZ_SHIFT) -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ(param) \ - (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ_MASK) >> \ - HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ_SHIFT) -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ(param) \ - (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ_MASK) >> \ - HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ_SHIFT) -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ(param) \ - (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ_MASK) >> \ - HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ_SHIFT) -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ(param) \ - (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ_MASK) >> \ - HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ_SHIFT) -#define HDA_PARAM_SUPP_PCM_SIZE_RATE_384KHZ(param) \ - (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_384KHZ_MASK) >> \ - HDA_PARAM_SUPP_PCM_SIZE_RATE_384KHZ_SHIFT) - -/* Supported Stream Formats */ -#define HDA_PARAM_SUPP_STREAM_FORMATS 0x0b - -#define HDA_PARAM_SUPP_STREAM_FORMATS_AC3_MASK 0x00000004 -#define HDA_PARAM_SUPP_STREAM_FORMATS_AC3_SHIFT 2 -#define HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32_MASK 0x00000002 -#define HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32_SHIFT 1 -#define HDA_PARAM_SUPP_STREAM_FORMATS_PCM_MASK 0x00000001 -#define HDA_PARAM_SUPP_STREAM_FORMATS_PCM_SHIFT 0 - -#define HDA_PARAM_SUPP_STREAM_FORMATS_AC3(param) \ - (((param) & HDA_PARAM_SUPP_STREAM_FORMATS_AC3_MASK) >> \ - HDA_PARAM_SUPP_STREAM_FORMATS_AC3_SHIFT) -#define HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32(param) \ - (((param) & HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32_MASK) >> \ - HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32_SHIFT) -#define HDA_PARAM_SUPP_STREAM_FORMATS_PCM(param) \ - (((param) & HDA_PARAM_SUPP_STREAM_FORMATS_PCM_MASK) >> \ - HDA_PARAM_SUPP_STREAM_FORMATS_PCM_SHIFT) - -/* Pin Capabilities */ -#define HDA_PARAM_PIN_CAP 0x0c - -#define HDA_PARAM_PIN_CAP_HBR_MASK 0x08000000 -#define HDA_PARAM_PIN_CAP_HBR_SHIFT 27 -#define HDA_PARAM_PIN_CAP_DP_MASK 0x01000000 -#define HDA_PARAM_PIN_CAP_DP_SHIFT 24 -#define HDA_PARAM_PIN_CAP_EAPD_CAP_MASK 0x00010000 -#define HDA_PARAM_PIN_CAP_EAPD_CAP_SHIFT 16 -#define HDA_PARAM_PIN_CAP_VREF_CTRL_MASK 0x0000ff00 -#define HDA_PARAM_PIN_CAP_VREF_CTRL_SHIFT 8 -#define HDA_PARAM_PIN_CAP_VREF_CTRL_100_MASK 0x00002000 -#define HDA_PARAM_PIN_CAP_VREF_CTRL_100_SHIFT 13 -#define HDA_PARAM_PIN_CAP_VREF_CTRL_80_MASK 0x00001000 -#define HDA_PARAM_PIN_CAP_VREF_CTRL_80_SHIFT 12 -#define HDA_PARAM_PIN_CAP_VREF_CTRL_GROUND_MASK 0x00000400 -#define HDA_PARAM_PIN_CAP_VREF_CTRL_GROUND_SHIFT 10 -#define HDA_PARAM_PIN_CAP_VREF_CTRL_50_MASK 0x00000200 -#define HDA_PARAM_PIN_CAP_VREF_CTRL_50_SHIFT 9 -#define HDA_PARAM_PIN_CAP_VREF_CTRL_HIZ_MASK 0x00000100 -#define HDA_PARAM_PIN_CAP_VREF_CTRL_HIZ_SHIFT 8 -#define HDA_PARAM_PIN_CAP_HDMI_MASK 0x00000080 -#define HDA_PARAM_PIN_CAP_HDMI_SHIFT 7 -#define HDA_PARAM_PIN_CAP_BALANCED_IO_PINS_MASK 0x00000040 -#define HDA_PARAM_PIN_CAP_BALANCED_IO_PINS_SHIFT 6 -#define HDA_PARAM_PIN_CAP_INPUT_CAP_MASK 0x00000020 -#define HDA_PARAM_PIN_CAP_INPUT_CAP_SHIFT 5 -#define HDA_PARAM_PIN_CAP_OUTPUT_CAP_MASK 0x00000010 -#define HDA_PARAM_PIN_CAP_OUTPUT_CAP_SHIFT 4 -#define HDA_PARAM_PIN_CAP_HEADPHONE_CAP_MASK 0x00000008 -#define HDA_PARAM_PIN_CAP_HEADPHONE_CAP_SHIFT 3 -#define HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP_MASK 0x00000004 -#define HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP_SHIFT 2 -#define HDA_PARAM_PIN_CAP_TRIGGER_REQD_MASK 0x00000002 -#define HDA_PARAM_PIN_CAP_TRIGGER_REQD_SHIFT 1 -#define HDA_PARAM_PIN_CAP_IMP_SENSE_CAP_MASK 0x00000001 -#define HDA_PARAM_PIN_CAP_IMP_SENSE_CAP_SHIFT 0 - -#define HDA_PARAM_PIN_CAP_HBR(param) \ - (((param) & HDA_PARAM_PIN_CAP_HBR_MASK) >> \ - HDA_PARAM_PIN_CAP_HBR_SHIFT) -#define HDA_PARAM_PIN_CAP_DP(param) \ - (((param) & HDA_PARAM_PIN_CAP_DP_MASK) >> \ - HDA_PARAM_PIN_CAP_DP_SHIFT) -#define HDA_PARAM_PIN_CAP_EAPD_CAP(param) \ - (((param) & HDA_PARAM_PIN_CAP_EAPD_CAP_MASK) >> \ - HDA_PARAM_PIN_CAP_EAPD_CAP_SHIFT) -#define HDA_PARAM_PIN_CAP_VREF_CTRL(param) \ - (((param) & HDA_PARAM_PIN_CAP_VREF_CTRL_MASK) >> \ - HDA_PARAM_PIN_CAP_VREF_CTRL_SHIFT) -#define HDA_PARAM_PIN_CAP_VREF_CTRL_100(param) \ - (((param) & HDA_PARAM_PIN_CAP_VREF_CTRL_100_MASK) >> \ - HDA_PARAM_PIN_CAP_VREF_CTRL_100_SHIFT) -#define HDA_PARAM_PIN_CAP_VREF_CTRL_80(param) \ - (((param) & HDA_PARAM_PIN_CAP_VREF_CTRL_80_MASK) >> \ - HDA_PARAM_PIN_CAP_VREF_CTRL_80_SHIFT) -#define HDA_PARAM_PIN_CAP_VREF_CTRL_GROUND(param) \ - (((param) & HDA_PARAM_PIN_CAP_VREF_CTRL_GROUND_MASK) >> \ - HDA_PARAM_PIN_CAP_VREF_CTRL_GROUND_SHIFT) -#define HDA_PARAM_PIN_CAP_VREF_CTRL_50(param) \ - (((param) & HDA_PARAM_PIN_CAP_VREF_CTRL_50_MASK) >> \ - HDA_PARAM_PIN_CAP_VREF_CTRL_50_SHIFT) -#define HDA_PARAM_PIN_CAP_VREF_CTRL_HIZ(param) \ - (((param) & HDA_PARAM_PIN_CAP_VREF_CTRL_HIZ_MASK) >> \ - HDA_PARAM_PIN_CAP_VREF_CTRL_HIZ_SHIFT) -#define HDA_PARAM_PIN_CAP_HDMI(param) \ - (((param) & HDA_PARAM_PIN_CAP_HDMI_MASK) >> \ - HDA_PARAM_PIN_CAP_HDMI_SHIFT) -#define HDA_PARAM_PIN_CAP_BALANCED_IO_PINS(param) \ - (((param) & HDA_PARAM_PIN_CAP_BALANCED_IO_PINS_MASK) >> \ - HDA_PARAM_PIN_CAP_BALANCED_IO_PINS_SHIFT) -#define HDA_PARAM_PIN_CAP_INPUT_CAP(param) \ - (((param) & HDA_PARAM_PIN_CAP_INPUT_CAP_MASK) >> \ - HDA_PARAM_PIN_CAP_INPUT_CAP_SHIFT) -#define HDA_PARAM_PIN_CAP_OUTPUT_CAP(param) \ - (((param) & HDA_PARAM_PIN_CAP_OUTPUT_CAP_MASK) >> \ - HDA_PARAM_PIN_CAP_OUTPUT_CAP_SHIFT) -#define HDA_PARAM_PIN_CAP_HEADPHONE_CAP(param) \ - (((param) & HDA_PARAM_PIN_CAP_HEADPHONE_CAP_MASK) >> \ - HDA_PARAM_PIN_CAP_HEADPHONE_CAP_SHIFT) -#define HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(param) \ - (((param) & HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP_MASK) >> \ - HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP_SHIFT) -#define HDA_PARAM_PIN_CAP_TRIGGER_REQD(param) \ - (((param) & HDA_PARAM_PIN_CAP_TRIGGER_REQD_MASK) >> \ - HDA_PARAM_PIN_CAP_TRIGGER_REQD_SHIFT) -#define HDA_PARAM_PIN_CAP_IMP_SENSE_CAP(param) \ - (((param) & HDA_PARAM_PIN_CAP_IMP_SENSE_CAP_MASK) >> \ - HDA_PARAM_PIN_CAP_IMP_SENSE_CAP_SHIFT) - -/* Input Amplifier Capabilities */ -#define HDA_PARAM_INPUT_AMP_CAP 0x0d - -#define HDA_PARAM_INPUT_AMP_CAP_MUTE_CAP_MASK 0x80000000 -#define HDA_PARAM_INPUT_AMP_CAP_MUTE_CAP_SHIFT 31 -#define HDA_PARAM_INPUT_AMP_CAP_STEPSIZE_MASK 0x007f0000 -#define HDA_PARAM_INPUT_AMP_CAP_STEPSIZE_SHIFT 16 -#define HDA_PARAM_INPUT_AMP_CAP_NUMSTEPS_MASK 0x00007f00 -#define HDA_PARAM_INPUT_AMP_CAP_NUMSTEPS_SHIFT 8 -#define HDA_PARAM_INPUT_AMP_CAP_OFFSET_MASK 0x0000007f -#define HDA_PARAM_INPUT_AMP_CAP_OFFSET_SHIFT 0 - -#define HDA_PARAM_INPUT_AMP_CAP_MUTE_CAP(param) \ - (((param) & HDA_PARAM_INPUT_AMP_CAP_MUTE_CAP_MASK) >> \ - HDA_PARAM_INPUT_AMP_CAP_MUTE_CAP_SHIFT) -#define HDA_PARAM_INPUT_AMP_CAP_STEPSIZE(param) \ - (((param) & HDA_PARAM_INPUT_AMP_CAP_STEPSIZE_MASK) >> \ - HDA_PARAM_INPUT_AMP_CAP_STEPSIZE_SHIFT) -#define HDA_PARAM_INPUT_AMP_CAP_NUMSTEPS(param) \ - (((param) & HDA_PARAM_INPUT_AMP_CAP_NUMSTEPS_MASK) >> \ - HDA_PARAM_INPUT_AMP_CAP_NUMSTEPS_SHIFT) -#define HDA_PARAM_INPUT_AMP_CAP_OFFSET(param) \ - (((param) & HDA_PARAM_INPUT_AMP_CAP_OFFSET_MASK) >> \ - HDA_PARAM_INPUT_AMP_CAP_OFFSET_SHIFT) - -/* Output Amplifier Capabilities */ -#define HDA_PARAM_OUTPUT_AMP_CAP 0x12 - -#define HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP_MASK 0x80000000 -#define HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP_SHIFT 31 -#define HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_MASK 0x007f0000 -#define HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_SHIFT 16 -#define HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_MASK 0x00007f00 -#define HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_SHIFT 8 -#define HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_MASK 0x0000007f -#define HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_SHIFT 0 - -#define HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP(param) \ - (((param) & HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP_MASK) >> \ - HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP_SHIFT) -#define HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE(param) \ - (((param) & HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_MASK) >> \ - HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_SHIFT) -#define HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS(param) \ - (((param) & HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_MASK) >> \ - HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_SHIFT) -#define HDA_PARAM_OUTPUT_AMP_CAP_OFFSET(param) \ - (((param) & HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_MASK) >> \ - HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_SHIFT) - -/* Connection List Length */ -#define HDA_PARAM_CONN_LIST_LENGTH 0x0e - -#define HDA_PARAM_CONN_LIST_LENGTH_LONG_FORM_MASK 0x00000080 -#define HDA_PARAM_CONN_LIST_LENGTH_LONG_FORM_SHIFT 7 -#define HDA_PARAM_CONN_LIST_LENGTH_LIST_LENGTH_MASK 0x0000007f -#define HDA_PARAM_CONN_LIST_LENGTH_LIST_LENGTH_SHIFT 0 - -#define HDA_PARAM_CONN_LIST_LENGTH_LONG_FORM(param) \ - (((param) & HDA_PARAM_CONN_LIST_LENGTH_LONG_FORM_MASK) >> \ - HDA_PARAM_CONN_LIST_LENGTH_LONG_FORM_SHIFT) -#define HDA_PARAM_CONN_LIST_LENGTH_LIST_LENGTH(param) \ - (((param) & HDA_PARAM_CONN_LIST_LENGTH_LIST_LENGTH_MASK) >> \ - HDA_PARAM_CONN_LIST_LENGTH_LIST_LENGTH_SHIFT) - -/* Supported Power States */ -#define HDA_PARAM_SUPP_POWER_STATES 0x0f - -#define HDA_PARAM_SUPP_POWER_STATES_D3_MASK 0x00000008 -#define HDA_PARAM_SUPP_POWER_STATES_D3_SHIFT 3 -#define HDA_PARAM_SUPP_POWER_STATES_D2_MASK 0x00000004 -#define HDA_PARAM_SUPP_POWER_STATES_D2_SHIFT 2 -#define HDA_PARAM_SUPP_POWER_STATES_D1_MASK 0x00000002 -#define HDA_PARAM_SUPP_POWER_STATES_D1_SHIFT 1 -#define HDA_PARAM_SUPP_POWER_STATES_D0_MASK 0x00000001 -#define HDA_PARAM_SUPP_POWER_STATES_D0_SHIFT 0 - -#define HDA_PARAM_SUPP_POWER_STATES_D3(param) \ - (((param) & HDA_PARAM_SUPP_POWER_STATES_D3_MASK) >> \ - HDA_PARAM_SUPP_POWER_STATES_D3_SHIFT) -#define HDA_PARAM_SUPP_POWER_STATES_D2(param) \ - (((param) & HDA_PARAM_SUPP_POWER_STATES_D2_MASK) >> \ - HDA_PARAM_SUPP_POWER_STATES_D2_SHIFT) -#define HDA_PARAM_SUPP_POWER_STATES_D1(param) \ - (((param) & HDA_PARAM_SUPP_POWER_STATES_D1_MASK) >> \ - HDA_PARAM_SUPP_POWER_STATES_D1_SHIFT) -#define HDA_PARAM_SUPP_POWER_STATES_D0(param) \ - (((param) & HDA_PARAM_SUPP_POWER_STATES_D0_MASK) >> \ - HDA_PARAM_SUPP_POWER_STATES_D0_SHIFT) - -/* Processing Capabilities */ -#define HDA_PARAM_PROCESSING_CAP 0x10 - -#define HDA_PARAM_PROCESSING_CAP_NUMCOEFF_MASK 0x0000ff00 -#define HDA_PARAM_PROCESSING_CAP_NUMCOEFF_SHIFT 8 -#define HDA_PARAM_PROCESSING_CAP_BENIGN_MASK 0x00000001 -#define HDA_PARAM_PROCESSING_CAP_BENIGN_SHIFT 0 - -#define HDA_PARAM_PROCESSING_CAP_NUMCOEFF(param) \ - (((param) & HDA_PARAM_PROCESSING_CAP_NUMCOEFF_MASK) >> \ - HDA_PARAM_PROCESSING_CAP_NUMCOEFF_SHIFT) -#define HDA_PARAM_PROCESSING_CAP_BENIGN(param) \ - (((param) & HDA_PARAM_PROCESSING_CAP_BENIGN_MASK) >> \ - HDA_PARAM_PROCESSING_CAP_BENIGN_SHIFT) - -/* GPIO Count */ -#define HDA_PARAM_GPIO_COUNT 0x11 - -#define HDA_PARAM_GPIO_COUNT_GPI_WAKE_MASK 0x80000000 -#define HDA_PARAM_GPIO_COUNT_GPI_WAKE_SHIFT 31 -#define HDA_PARAM_GPIO_COUNT_GPI_UNSOL_MASK 0x40000000 -#define HDA_PARAM_GPIO_COUNT_GPI_UNSOL_SHIFT 30 -#define HDA_PARAM_GPIO_COUNT_NUM_GPI_MASK 0x00ff0000 -#define HDA_PARAM_GPIO_COUNT_NUM_GPI_SHIFT 16 -#define HDA_PARAM_GPIO_COUNT_NUM_GPO_MASK 0x0000ff00 -#define HDA_PARAM_GPIO_COUNT_NUM_GPO_SHIFT 8 -#define HDA_PARAM_GPIO_COUNT_NUM_GPIO_MASK 0x000000ff -#define HDA_PARAM_GPIO_COUNT_NUM_GPIO_SHIFT 0 - -#define HDA_PARAM_GPIO_COUNT_GPI_WAKE(param) \ - (((param) & HDA_PARAM_GPIO_COUNT_GPI_WAKE_MASK) >> \ - HDA_PARAM_GPIO_COUNT_GPI_WAKE_SHIFT) -#define HDA_PARAM_GPIO_COUNT_GPI_UNSOL(param) \ - (((param) & HDA_PARAM_GPIO_COUNT_GPI_UNSOL_MASK) >> \ - HDA_PARAM_GPIO_COUNT_GPI_UNSOL_SHIFT) -#define HDA_PARAM_GPIO_COUNT_NUM_GPI(param) \ - (((param) & HDA_PARAM_GPIO_COUNT_NUM_GPI_MASK) >> \ - HDA_PARAM_GPIO_COUNT_NUM_GPI_SHIFT) -#define HDA_PARAM_GPIO_COUNT_NUM_GPO(param) \ - (((param) & HDA_PARAM_GPIO_COUNT_NUM_GPO_MASK) >> \ - HDA_PARAM_GPIO_COUNT_NUM_GPO_SHIFT) -#define HDA_PARAM_GPIO_COUNT_NUM_GPIO(param) \ - (((param) & HDA_PARAM_GPIO_COUNT_NUM_GPIO_MASK) >> \ - HDA_PARAM_GPIO_COUNT_NUM_GPIO_SHIFT) - -/* Volume Knob Capabilities */ -#define HDA_PARAM_VOLUME_KNOB_CAP 0x13 - -#define HDA_PARAM_VOLUME_KNOB_CAP_DELTA_MASK 0x00000080 -#define HDA_PARAM_VOLUME_KNOB_CAP_DELTA_SHIFT 7 -#define HDA_PARAM_VOLUME_KNOB_CAP_NUM_STEPS_MASK 0x0000007f -#define HDA_PARAM_VOLUME_KNOB_CAP_NUM_STEPS_SHIFT 0 - -#define HDA_PARAM_VOLUME_KNOB_CAP_DELTA(param) \ - (((param) & HDA_PARAM_VOLUME_KNOB_CAP_DELTA_MASK) >> \ - HDA_PARAM_VOLUME_KNOB_CAP_DELTA_SHIFT) -#define HDA_PARAM_VOLUME_KNOB_CAP_NUM_STEPS(param) \ - (((param) & HDA_PARAM_VOLUME_KNOB_CAP_NUM_STEPS_MASK) >> \ - HDA_PARAM_VOLUME_KNOB_CAP_NUM_STEPS_SHIFT) - - -#define HDA_CONFIG_DEFAULTCONF_SEQUENCE_MASK 0x0000000f -#define HDA_CONFIG_DEFAULTCONF_SEQUENCE_SHIFT 0 -#define HDA_CONFIG_DEFAULTCONF_ASSOCIATION_MASK 0x000000f0 -#define HDA_CONFIG_DEFAULTCONF_ASSOCIATION_SHIFT 4 -#define HDA_CONFIG_DEFAULTCONF_MISC_MASK 0x00000f00 -#define HDA_CONFIG_DEFAULTCONF_MISC_SHIFT 8 -#define HDA_CONFIG_DEFAULTCONF_COLOR_MASK 0x0000f000 -#define HDA_CONFIG_DEFAULTCONF_COLOR_SHIFT 12 -#define HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_MASK 0x000f0000 -#define HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_SHIFT 16 -#define HDA_CONFIG_DEFAULTCONF_DEVICE_MASK 0x00f00000 -#define HDA_CONFIG_DEFAULTCONF_DEVICE_SHIFT 20 -#define HDA_CONFIG_DEFAULTCONF_LOCATION_MASK 0x3f000000 -#define HDA_CONFIG_DEFAULTCONF_LOCATION_SHIFT 24 -#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK 0xc0000000 -#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_SHIFT 30 - -#define HDA_CONFIG_DEFAULTCONF_SEQUENCE(conf) \ - (((conf) & HDA_CONFIG_DEFAULTCONF_SEQUENCE_MASK) >> \ - HDA_CONFIG_DEFAULTCONF_SEQUENCE_SHIFT) -#define HDA_CONFIG_DEFAULTCONF_ASSOCIATION(conf) \ - (((conf) & HDA_CONFIG_DEFAULTCONF_ASSOCIATION_MASK) >> \ - HDA_CONFIG_DEFAULTCONF_ASSOCIATION_SHIFT) -#define HDA_CONFIG_DEFAULTCONF_MISC(conf) \ - (((conf) & HDA_CONFIG_DEFAULTCONF_MISC_MASK) >> \ - HDA_CONFIG_DEFAULTCONF_MISC_SHIFT) -#define HDA_CONFIG_DEFAULTCONF_COLOR(conf) \ - (((conf) & HDA_CONFIG_DEFAULTCONF_COLOR_MASK) >> \ - HDA_CONFIG_DEFAULTCONF_COLOR_SHIFT) -#define HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE(conf) \ - (((conf) & HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_MASK) >> \ - HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_SHIFT) -#define HDA_CONFIG_DEFAULTCONF_DEVICE(conf) \ - (((conf) & HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) >> \ - HDA_CONFIG_DEFAULTCONF_DEVICE_SHIFT) -#define HDA_CONFIG_DEFAULTCONF_LOCATION(conf) \ - (((conf) & HDA_CONFIG_DEFAULTCONF_LOCATION_MASK) >> \ - HDA_CONFIG_DEFAULTCONF_LOCATION_SHIFT) -#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY(conf) \ - (((conf) & HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) >> \ - HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_SHIFT) - -#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK (0<<30) -#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE (1<<30) -#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED (2<<30) -#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_BOTH (3<<30) - -#define HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT (0<<20) -#define HDA_CONFIG_DEFAULTCONF_DEVICE_SPEAKER (1<<20) -#define HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT (2<<20) -#define HDA_CONFIG_DEFAULTCONF_DEVICE_CD (3<<20) -#define HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_OUT (4<<20) -#define HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_OUT (5<<20) -#define HDA_CONFIG_DEFAULTCONF_DEVICE_MODEM_LINE (6<<20) -#define HDA_CONFIG_DEFAULTCONF_DEVICE_MODEM_HANDSET (7<<20) -#define HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN (8<<20) -#define HDA_CONFIG_DEFAULTCONF_DEVICE_AUX (9<<20) -#define HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN (10<<20) -#define HDA_CONFIG_DEFAULTCONF_DEVICE_TELEPHONY (11<<20) -#define HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_IN (12<<20) -#define HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_IN (13<<20) -#define HDA_CONFIG_DEFAULTCONF_DEVICE_OTHER (15<<20) - -#endif /* _HDA_REG_H_ */ diff --git a/usr.sbin/bhyve/hdac_reg.h b/usr.sbin/bhyve/hdac_reg.h deleted file mode 100644 index 2bef0d0edc35..000000000000 --- a/usr.sbin/bhyve/hdac_reg.h +++ /dev/null @@ -1,269 +0,0 @@ -/*- - * Copyright (c) 2006 Stephane E. Potvin - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$ - */ - -#ifndef _HDAC_REG_H_ -#define _HDAC_REG_H_ - -/**************************************************************************** - * HDA Controller Register Set - ****************************************************************************/ -#define HDAC_GCAP 0x00 /* 2 - Global Capabilities*/ -#define HDAC_VMIN 0x02 /* 1 - Minor Version */ -#define HDAC_VMAJ 0x03 /* 1 - Major Version */ -#define HDAC_OUTPAY 0x04 /* 2 - Output Payload Capability */ -#define HDAC_INPAY 0x06 /* 2 - Input Payload Capability */ -#define HDAC_GCTL 0x08 /* 4 - Global Control */ -#define HDAC_WAKEEN 0x0c /* 2 - Wake Enable */ -#define HDAC_STATESTS 0x0e /* 2 - State Change Status */ -#define HDAC_GSTS 0x10 /* 2 - Global Status */ -#define HDAC_OUTSTRMPAY 0x18 /* 2 - Output Stream Payload Capability */ -#define HDAC_INSTRMPAY 0x1a /* 2 - Input Stream Payload Capability */ -#define HDAC_INTCTL 0x20 /* 4 - Interrupt Control */ -#define HDAC_INTSTS 0x24 /* 4 - Interrupt Status */ -#define HDAC_WALCLK 0x30 /* 4 - Wall Clock Counter */ -#define HDAC_SSYNC 0x38 /* 4 - Stream Synchronization */ -#define HDAC_CORBLBASE 0x40 /* 4 - CORB Lower Base Address */ -#define HDAC_CORBUBASE 0x44 /* 4 - CORB Upper Base Address */ -#define HDAC_CORBWP 0x48 /* 2 - CORB Write Pointer */ -#define HDAC_CORBRP 0x4a /* 2 - CORB Read Pointer */ -#define HDAC_CORBCTL 0x4c /* 1 - CORB Control */ -#define HDAC_CORBSTS 0x4d /* 1 - CORB Status */ -#define HDAC_CORBSIZE 0x4e /* 1 - CORB Size */ -#define HDAC_RIRBLBASE 0x50 /* 4 - RIRB Lower Base Address */ -#define HDAC_RIRBUBASE 0x54 /* 4 - RIRB Upper Base Address */ -#define HDAC_RIRBWP 0x58 /* 2 - RIRB Write Pointer */ -#define HDAC_RINTCNT 0x5a /* 2 - Response Interrupt Count */ -#define HDAC_RIRBCTL 0x5c /* 1 - RIRB Control */ -#define HDAC_RIRBSTS 0x5d /* 1 - RIRB Status */ -#define HDAC_RIRBSIZE 0x5e /* 1 - RIRB Size */ -#define HDAC_ICOI 0x60 /* 4 - Immediate Command Output Interface */ -#define HDAC_ICII 0x64 /* 4 - Immediate Command Input Interface */ -#define HDAC_ICIS 0x68 /* 2 - Immediate Command Status */ -#define HDAC_DPIBLBASE 0x70 /* 4 - DMA Position Buffer Lower Base */ -#define HDAC_DPIBUBASE 0x74 /* 4 - DMA Position Buffer Upper Base */ -#define HDAC_SDCTL0 0x80 /* 3 - Stream Descriptor Control */ -#define HDAC_SDCTL1 0x81 /* 3 - Stream Descriptor Control */ -#define HDAC_SDCTL2 0x82 /* 3 - Stream Descriptor Control */ -#define HDAC_SDSTS 0x83 /* 1 - Stream Descriptor Status */ -#define HDAC_SDLPIB 0x84 /* 4 - Link Position in Buffer */ -#define HDAC_SDCBL 0x88 /* 4 - Cyclic Buffer Length */ -#define HDAC_SDLVI 0x8C /* 2 - Last Valid Index */ -#define HDAC_SDFIFOS 0x90 /* 2 - FIFOS */ -#define HDAC_SDFMT 0x92 /* 2 - fmt */ -#define HDAC_SDBDPL 0x98 /* 4 - Buffer Descriptor Pointer Lower Base */ -#define HDAC_SDBDPU 0x9C /* 4 - Buffer Descriptor Pointer Upper Base */ - -#define _HDAC_ISDOFFSET(n, iss, oss) (0x80 + ((n) * 0x20)) -#define _HDAC_ISDCTL(n, iss, oss) (0x00 + _HDAC_ISDOFFSET(n, iss, oss)) -#define _HDAC_ISDSTS(n, iss, oss) (0x03 + _HDAC_ISDOFFSET(n, iss, oss)) -#define _HDAC_ISDPICB(n, iss, oss) (0x04 + _HDAC_ISDOFFSET(n, iss, oss)) -#define _HDAC_ISDCBL(n, iss, oss) (0x08 + _HDAC_ISDOFFSET(n, iss, oss)) -#define _HDAC_ISDLVI(n, iss, oss) (0x0c + _HDAC_ISDOFFSET(n, iss, oss)) -#define _HDAC_ISDFIFOD(n, iss, oss) (0x10 + _HDAC_ISDOFFSET(n, iss, oss)) -#define _HDAC_ISDFMT(n, iss, oss) (0x12 + _HDAC_ISDOFFSET(n, iss, oss)) -#define _HDAC_ISDBDPL(n, iss, oss) (0x18 + _HDAC_ISDOFFSET(n, iss, oss)) -#define _HDAC_ISDBDPU(n, iss, oss) (0x1c + _HDAC_ISDOFFSET(n, iss, oss)) - -#define _HDAC_OSDOFFSET(n, iss, oss) (0x80 + ((iss) * 0x20) + ((n) * 0x20)) -#define _HDAC_OSDCTL(n, iss, oss) (0x00 + _HDAC_OSDOFFSET(n, iss, oss)) -#define _HDAC_OSDSTS(n, iss, oss) (0x03 + _HDAC_OSDOFFSET(n, iss, oss)) -#define _HDAC_OSDPICB(n, iss, oss) (0x04 + _HDAC_OSDOFFSET(n, iss, oss)) -#define _HDAC_OSDCBL(n, iss, oss) (0x08 + _HDAC_OSDOFFSET(n, iss, oss)) -#define _HDAC_OSDLVI(n, iss, oss) (0x0c + _HDAC_OSDOFFSET(n, iss, oss)) -#define _HDAC_OSDFIFOD(n, iss, oss) (0x10 + _HDAC_OSDOFFSET(n, iss, oss)) -#define _HDAC_OSDFMT(n, iss, oss) (0x12 + _HDAC_OSDOFFSET(n, iss, oss)) -#define _HDAC_OSDBDPL(n, iss, oss) (0x18 + _HDAC_OSDOFFSET(n, iss, oss)) -#define _HDAC_OSDBDPU(n, iss, oss) (0x1c + _HDAC_OSDOFFSET(n, iss, oss)) - -#define _HDAC_BSDOFFSET(n, iss, oss) \ - (0x80 + ((iss) * 0x20) + ((oss) * 0x20) + ((n) * 0x20)) -#define _HDAC_BSDCTL(n, iss, oss) (0x00 + _HDAC_BSDOFFSET(n, iss, oss)) -#define _HDAC_BSDSTS(n, iss, oss) (0x03 + _HDAC_BSDOFFSET(n, iss, oss)) -#define _HDAC_BSDPICB(n, iss, oss) (0x04 + _HDAC_BSDOFFSET(n, iss, oss)) -#define _HDAC_BSDCBL(n, iss, oss) (0x08 + _HDAC_BSDOFFSET(n, iss, oss)) -#define _HDAC_BSDLVI(n, iss, oss) (0x0c + _HDAC_BSDOFFSET(n, iss, oss)) -#define _HDAC_BSDFIFOD(n, iss, oss) (0x10 + _HDAC_BSDOFFSET(n, iss, oss)) -#define _HDAC_BSDFMT(n, iss, oss) (0x12 + _HDAC_BSDOFFSET(n, iss, oss)) -#define _HDAC_BSDBDPL(n, iss, oss) (0x18 + _HDAC_BSDOFFSET(n, iss, oss)) -#define _HDAC_BSDBDBU(n, iss, oss) (0x1c + _HDAC_BSDOFFSET(n, iss, oss)) - -/**************************************************************************** - * HDA Controller Register Fields - ****************************************************************************/ - -/* GCAP - Global Capabilities */ -#define HDAC_GCAP_64OK 0x0001 -#define HDAC_GCAP_NSDO_MASK 0x0006 -#define HDAC_GCAP_NSDO_SHIFT 1 -#define HDAC_GCAP_BSS_MASK 0x00f8 -#define HDAC_GCAP_BSS_SHIFT 3 -#define HDAC_GCAP_ISS_MASK 0x0f00 -#define HDAC_GCAP_ISS_SHIFT 8 -#define HDAC_GCAP_OSS_MASK 0xf000 -#define HDAC_GCAP_OSS_SHIFT 12 - -#define HDAC_GCAP_NSDO_1SDO 0x00 -#define HDAC_GCAP_NSDO_2SDO 0x02 -#define HDAC_GCAP_NSDO_4SDO 0x04 - -#define HDAC_GCAP_BSS(gcap) \ - (((gcap) & HDAC_GCAP_BSS_MASK) >> HDAC_GCAP_BSS_SHIFT) -#define HDAC_GCAP_ISS(gcap) \ - (((gcap) & HDAC_GCAP_ISS_MASK) >> HDAC_GCAP_ISS_SHIFT) -#define HDAC_GCAP_OSS(gcap) \ - (((gcap) & HDAC_GCAP_OSS_MASK) >> HDAC_GCAP_OSS_SHIFT) -#define HDAC_GCAP_NSDO(gcap) \ - (((gcap) & HDAC_GCAP_NSDO_MASK) >> HDAC_GCAP_NSDO_SHIFT) - -/* GCTL - Global Control */ -#define HDAC_GCTL_CRST 0x00000001 -#define HDAC_GCTL_FCNTRL 0x00000002 -#define HDAC_GCTL_UNSOL 0x00000100 - -/* WAKEEN - Wake Enable */ -#define HDAC_WAKEEN_SDIWEN_MASK 0x7fff -#define HDAC_WAKEEN_SDIWEN_SHIFT 0 - -/* STATESTS - State Change Status */ -#define HDAC_STATESTS_SDIWAKE_MASK 0x7fff -#define HDAC_STATESTS_SDIWAKE_SHIFT 0 - -#define HDAC_STATESTS_SDIWAKE(statests, n) \ - (((((statests) & HDAC_STATESTS_SDIWAKE_MASK) >> \ - HDAC_STATESTS_SDIWAKE_SHIFT) >> (n)) & 0x0001) - -/* GSTS - Global Status */ -#define HDAC_GSTS_FSTS 0x0002 - -/* INTCTL - Interrut Control */ -#define HDAC_INTCTL_SIE_MASK 0x3fffffff -#define HDAC_INTCTL_SIE_SHIFT 0 -#define HDAC_INTCTL_CIE 0x40000000 -#define HDAC_INTCTL_GIE 0x80000000 - -/* INTSTS - Interrupt Status */ -#define HDAC_INTSTS_SIS_MASK 0x3fffffff -#define HDAC_INTSTS_SIS_SHIFT 0 -#define HDAC_INTSTS_CIS 0x40000000 -#define HDAC_INTSTS_GIS 0x80000000 - -/* SSYNC - Stream Synchronization */ -#define HDAC_SSYNC_SSYNC_MASK 0x3fffffff -#define HDAC_SSYNC_SSYNC_SHIFT 0 - -/* CORBWP - CORB Write Pointer */ -#define HDAC_CORBWP_CORBWP_MASK 0x00ff -#define HDAC_CORBWP_CORBWP_SHIFT 0 - -/* CORBRP - CORB Read Pointer */ -#define HDAC_CORBRP_CORBRP_MASK 0x00ff -#define HDAC_CORBRP_CORBRP_SHIFT 0 -#define HDAC_CORBRP_CORBRPRST 0x8000 - -/* CORBCTL - CORB Control */ -#define HDAC_CORBCTL_CMEIE 0x01 -#define HDAC_CORBCTL_CORBRUN 0x02 - -/* CORBSTS - CORB Status */ -#define HDAC_CORBSTS_CMEI 0x01 - -/* CORBSIZE - CORB Size */ -#define HDAC_CORBSIZE_CORBSIZE_MASK 0x03 -#define HDAC_CORBSIZE_CORBSIZE_SHIFT 0 -#define HDAC_CORBSIZE_CORBSZCAP_MASK 0xf0 -#define HDAC_CORBSIZE_CORBSZCAP_SHIFT 4 - -#define HDAC_CORBSIZE_CORBSIZE_2 0x00 -#define HDAC_CORBSIZE_CORBSIZE_16 0x01 -#define HDAC_CORBSIZE_CORBSIZE_256 0x02 - -#define HDAC_CORBSIZE_CORBSZCAP_2 0x10 -#define HDAC_CORBSIZE_CORBSZCAP_16 0x20 -#define HDAC_CORBSIZE_CORBSZCAP_256 0x40 - -#define HDAC_CORBSIZE_CORBSIZE(corbsize) \ - (((corbsize) & HDAC_CORBSIZE_CORBSIZE_MASK) >> HDAC_CORBSIZE_CORBSIZE_SHIFT) - -/* RIRBWP - RIRB Write Pointer */ -#define HDAC_RIRBWP_RIRBWP_MASK 0x00ff -#define HDAC_RIRBWP_RIRBWP_SHIFT 0 -#define HDAC_RIRBWP_RIRBWPRST 0x8000 - -/* RINTCTN - Response Interrupt Count */ -#define HDAC_RINTCNT_MASK 0x00ff -#define HDAC_RINTCNT_SHIFT 0 - -/* RIRBCTL - RIRB Control */ -#define HDAC_RIRBCTL_RINTCTL 0x01 -#define HDAC_RIRBCTL_RIRBDMAEN 0x02 -#define HDAC_RIRBCTL_RIRBOIC 0x04 - -/* RIRBSTS - RIRB Status */ -#define HDAC_RIRBSTS_RINTFL 0x01 -#define HDAC_RIRBSTS_RIRBOIS 0x04 - -/* RIRBSIZE - RIRB Size */ -#define HDAC_RIRBSIZE_RIRBSIZE_MASK 0x03 -#define HDAC_RIRBSIZE_RIRBSIZE_SHIFT 0 -#define HDAC_RIRBSIZE_RIRBSZCAP_MASK 0xf0 -#define HDAC_RIRBSIZE_RIRBSZCAP_SHIFT 4 - -#define HDAC_RIRBSIZE_RIRBSIZE_2 0x00 -#define HDAC_RIRBSIZE_RIRBSIZE_16 0x01 -#define HDAC_RIRBSIZE_RIRBSIZE_256 0x02 - -#define HDAC_RIRBSIZE_RIRBSZCAP_2 0x10 -#define HDAC_RIRBSIZE_RIRBSZCAP_16 0x20 -#define HDAC_RIRBSIZE_RIRBSZCAP_256 0x40 - -#define HDAC_RIRBSIZE_RIRBSIZE(rirbsize) \ - (((rirbsize) & HDAC_RIRBSIZE_RIRBSIZE_MASK) >> HDAC_RIRBSIZE_RIRBSIZE_SHIFT) - -/* DPLBASE - DMA Position Lower Base Address */ -#define HDAC_DPLBASE_DPLBASE_MASK 0xffffff80 -#define HDAC_DPLBASE_DPLBASE_SHIFT 7 -#define HDAC_DPLBASE_DPLBASE_DMAPBE 0x00000001 - -/* SDCTL - Stream Descriptor Control */ -#define HDAC_SDCTL_SRST 0x000001 -#define HDAC_SDCTL_RUN 0x000002 -#define HDAC_SDCTL_IOCE 0x000004 -#define HDAC_SDCTL_FEIE 0x000008 -#define HDAC_SDCTL_DEIE 0x000010 -#define HDAC_SDCTL2_STRIPE_MASK 0x03 -#define HDAC_SDCTL2_STRIPE_SHIFT 0 -#define HDAC_SDCTL2_TP 0x04 -#define HDAC_SDCTL2_DIR 0x08 -#define HDAC_SDCTL2_STRM_MASK 0xf0 -#define HDAC_SDCTL2_STRM_SHIFT 4 - -#define HDAC_SDSTS_DESE (1 << 4) -#define HDAC_SDSTS_FIFOE (1 << 3) -#define HDAC_SDSTS_BCIS (1 << 2) - -#endif /* _HDAC_REG_H_ */ diff --git a/usr.sbin/bhyve/pci_hda.c b/usr.sbin/bhyve/pci_hda.c deleted file mode 100644 index 99f8aec31c6e..000000000000 --- a/usr.sbin/bhyve/pci_hda.c +++ /dev/null @@ -1,1330 +0,0 @@ -/*- - * Copyright (c) 2016 Alex Teaca - * 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, 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 OR CONTRIBUTORS 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 - -#include "pci_hda.h" -#include "bhyverun.h" -#include "pci_emul.h" -#include "hdac_reg.h" - -/* - * HDA defines - */ -#define PCIR_HDCTL 0x40 -#define INTEL_VENDORID 0x8086 -#define HDA_INTEL_82801G 0x27d8 - -#define HDA_IOSS_NO 0x08 -#define HDA_OSS_NO 0x04 -#define HDA_ISS_NO 0x04 -#define HDA_CODEC_MAX 0x0f -#define HDA_LAST_OFFSET \ - (0x2084 + ((HDA_ISS_NO) * 0x20) + ((HDA_OSS_NO) * 0x20)) -#define HDA_SET_REG_TABLE_SZ \ - (0x80 + ((HDA_ISS_NO) * 0x20) + ((HDA_OSS_NO) * 0x20)) -#define HDA_CORB_ENTRY_LEN 0x04 -#define HDA_RIRB_ENTRY_LEN 0x08 -#define HDA_BDL_ENTRY_LEN 0x10 -#define HDA_DMA_PIB_ENTRY_LEN 0x08 -#define HDA_STREAM_TAGS_CNT 0x10 -#define HDA_STREAM_REGS_BASE 0x80 -#define HDA_STREAM_REGS_LEN 0x20 - -#define HDA_DMA_ACCESS_LEN (sizeof(uint32_t)) -#define HDA_BDL_MAX_LEN 0x0100 - -#define HDAC_SDSTS_FIFORDY (1 << 5) - -#define HDA_RIRBSTS_IRQ_MASK (HDAC_RIRBSTS_RINTFL | HDAC_RIRBSTS_RIRBOIS) -#define HDA_STATESTS_IRQ_MASK ((1 << HDA_CODEC_MAX) - 1) -#define HDA_SDSTS_IRQ_MASK \ - (HDAC_SDSTS_DESE | HDAC_SDSTS_FIFOE | HDAC_SDSTS_BCIS) - -/* - * HDA data structures - */ - -struct hda_softc; - -typedef void (*hda_set_reg_handler)(struct hda_softc *sc, uint32_t offset, - uint32_t old); - -struct hda_bdle { - uint32_t addrh; - uint32_t addrl; - uint32_t ioc; - uint32_t len; -} __packed; - -struct hda_bdle_desc { - void *addr; - uint8_t ioc; - uint32_t len; -}; - -struct hda_codec_cmd_ctl { - char *name; - void *dma_vaddr; - uint8_t run; - uint16_t rp; - uint16_t size; - uint16_t wp; -}; - -struct hda_stream_desc { - uint8_t dir; - uint8_t run; - uint8_t stream; - - /* bp is the no. of bytes transferred in the current bdle */ - uint32_t bp; - /* be is the no. of bdles transferred in the bdl */ - uint32_t be; - - uint32_t bdl_cnt; - struct hda_bdle_desc bdl[HDA_BDL_MAX_LEN]; -}; - -struct hda_softc { - struct pci_devinst *pci_dev; - uint32_t regs[HDA_LAST_OFFSET]; - - uint8_t lintr; - uint8_t rirb_cnt; - uint64_t wall_clock_start; - - struct hda_codec_cmd_ctl corb; - struct hda_codec_cmd_ctl rirb; - - uint8_t codecs_no; - struct hda_codec_inst *codecs[HDA_CODEC_MAX]; - - /* Base Address of the DMA Position Buffer */ - void *dma_pib_vaddr; - - struct hda_stream_desc streams[HDA_IOSS_NO]; - /* 2 tables for output and input */ - uint8_t stream_map[2][HDA_STREAM_TAGS_CNT]; -}; - -/* - * HDA module function declarations - */ -static inline void hda_set_reg_by_offset(struct hda_softc *sc, uint32_t offset, - uint32_t value); -static inline uint32_t hda_get_reg_by_offset(struct hda_softc *sc, - uint32_t offset); -static inline void hda_set_field_by_offset(struct hda_softc *sc, - uint32_t offset, uint32_t mask, uint32_t value); - -static uint8_t hda_parse_config(const char *opts, const char *key, char *val); -static struct hda_softc *hda_init(const char *opts); -static void hda_update_intr(struct hda_softc *sc); -static void hda_response_interrupt(struct hda_softc *sc); -static int hda_codec_constructor(struct hda_softc *sc, - struct hda_codec_class *codec, const char *play, const char *rec, - const char *opts); -static struct hda_codec_class *hda_find_codec_class(const char *name); - -static int hda_send_command(struct hda_softc *sc, uint32_t verb); -static int hda_notify_codecs(struct hda_softc *sc, uint8_t run, - uint8_t stream, uint8_t dir); -static void hda_reset(struct hda_softc *sc); -static void hda_reset_regs(struct hda_softc *sc); -static void hda_stream_reset(struct hda_softc *sc, uint8_t stream_ind); -static int hda_stream_start(struct hda_softc *sc, uint8_t stream_ind); -static int hda_stream_stop(struct hda_softc *sc, uint8_t stream_ind); -static uint32_t hda_read(struct hda_softc *sc, uint32_t offset); -static int hda_write(struct hda_softc *sc, uint32_t offset, uint8_t size, - uint32_t value); - -static inline void hda_print_cmd_ctl_data(struct hda_codec_cmd_ctl *p); -static int hda_corb_start(struct hda_softc *sc); -static int hda_corb_run(struct hda_softc *sc); -static int hda_rirb_start(struct hda_softc *sc); - -static void *hda_dma_get_vaddr(struct hda_softc *sc, uint64_t dma_paddr, - size_t len); -static void hda_dma_st_dword(void *dma_vaddr, uint32_t data); -static uint32_t hda_dma_ld_dword(void *dma_vaddr); - -static inline uint8_t hda_get_stream_by_offsets(uint32_t offset, - uint8_t reg_offset); -static inline uint32_t hda_get_offset_stream(uint8_t stream_ind); - -static void hda_set_gctl(struct hda_softc *sc, uint32_t offset, uint32_t old); -static void hda_set_statests(struct hda_softc *sc, uint32_t offset, - uint32_t old); -static void hda_set_corbwp(struct hda_softc *sc, uint32_t offset, uint32_t old); -static void hda_set_corbctl(struct hda_softc *sc, uint32_t offset, - uint32_t old); -static void hda_set_rirbctl(struct hda_softc *sc, uint32_t offset, - uint32_t old); -static void hda_set_rirbsts(struct hda_softc *sc, uint32_t offset, - uint32_t old); -static void hda_set_dpiblbase(struct hda_softc *sc, uint32_t offset, - uint32_t old); -static void hda_set_sdctl(struct hda_softc *sc, uint32_t offset, uint32_t old); -static void hda_set_sdctl2(struct hda_softc *sc, uint32_t offset, uint32_t old); -static void hda_set_sdsts(struct hda_softc *sc, uint32_t offset, uint32_t old); - -static int hda_signal_state_change(struct hda_codec_inst *hci); -static int hda_response(struct hda_codec_inst *hci, uint32_t response, - uint8_t unsol); -static int hda_transfer(struct hda_codec_inst *hci, uint8_t stream, - uint8_t dir, void *buf, size_t count); - -static void hda_set_pib(struct hda_softc *sc, uint8_t stream_ind, uint32_t pib); -static uint64_t hda_get_clock_ns(void); - -/* - * PCI HDA function declarations - */ -static int pci_hda_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts); -static void pci_hda_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, - int baridx, uint64_t offset, int size, uint64_t value); -static uint64_t pci_hda_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, - int baridx, uint64_t offset, int size); -/* - * HDA global data - */ - -static const hda_set_reg_handler hda_set_reg_table[] = { - [HDAC_GCTL] = hda_set_gctl, - [HDAC_STATESTS] = hda_set_statests, - [HDAC_CORBWP] = hda_set_corbwp, - [HDAC_CORBCTL] = hda_set_corbctl, - [HDAC_RIRBCTL] = hda_set_rirbctl, - [HDAC_RIRBSTS] = hda_set_rirbsts, - [HDAC_DPIBLBASE] = hda_set_dpiblbase, - -#define HDAC_ISTREAM(n, iss, oss) \ - [_HDAC_ISDCTL(n, iss, oss)] = hda_set_sdctl, \ - [_HDAC_ISDCTL(n, iss, oss) + 2] = hda_set_sdctl2, \ - [_HDAC_ISDSTS(n, iss, oss)] = hda_set_sdsts, \ - -#define HDAC_OSTREAM(n, iss, oss) \ - [_HDAC_OSDCTL(n, iss, oss)] = hda_set_sdctl, \ - [_HDAC_OSDCTL(n, iss, oss) + 2] = hda_set_sdctl2, \ - [_HDAC_OSDSTS(n, iss, oss)] = hda_set_sdsts, \ - - HDAC_ISTREAM(0, HDA_ISS_NO, HDA_OSS_NO) - HDAC_ISTREAM(1, HDA_ISS_NO, HDA_OSS_NO) - HDAC_ISTREAM(2, HDA_ISS_NO, HDA_OSS_NO) - HDAC_ISTREAM(3, HDA_ISS_NO, HDA_OSS_NO) - - HDAC_OSTREAM(0, HDA_ISS_NO, HDA_OSS_NO) - HDAC_OSTREAM(1, HDA_ISS_NO, HDA_OSS_NO) - HDAC_OSTREAM(2, HDA_ISS_NO, HDA_OSS_NO) - HDAC_OSTREAM(3, HDA_ISS_NO, HDA_OSS_NO) - - [HDA_SET_REG_TABLE_SZ] = NULL, -}; - -static const uint16_t hda_corb_sizes[] = { - [HDAC_CORBSIZE_CORBSIZE_2] = 2, - [HDAC_CORBSIZE_CORBSIZE_16] = 16, - [HDAC_CORBSIZE_CORBSIZE_256] = 256, - [HDAC_CORBSIZE_CORBSIZE_MASK] = 0, -}; - -static const uint16_t hda_rirb_sizes[] = { - [HDAC_RIRBSIZE_RIRBSIZE_2] = 2, - [HDAC_RIRBSIZE_RIRBSIZE_16] = 16, - [HDAC_RIRBSIZE_RIRBSIZE_256] = 256, - [HDAC_RIRBSIZE_RIRBSIZE_MASK] = 0, -}; - -static struct hda_ops hops = { - .signal = hda_signal_state_change, - .response = hda_response, - .transfer = hda_transfer, -}; - -struct pci_devemu pci_de_hda = { - .pe_emu = "hda", - .pe_init = pci_hda_init, - .pe_barwrite = pci_hda_write, - .pe_barread = pci_hda_read -}; - -PCI_EMUL_SET(pci_de_hda); - -SET_DECLARE(hda_codec_class_set, struct hda_codec_class); - -#if DEBUG_HDA == 1 -FILE *dbg; -#endif - -/* - * HDA module function definitions - */ - -static inline void -hda_set_reg_by_offset(struct hda_softc *sc, uint32_t offset, uint32_t value) -{ - assert(offset < HDA_LAST_OFFSET); - sc->regs[offset] = value; -} - -static inline uint32_t -hda_get_reg_by_offset(struct hda_softc *sc, uint32_t offset) -{ - assert(offset < HDA_LAST_OFFSET); - return sc->regs[offset]; -} - -static inline void -hda_set_field_by_offset(struct hda_softc *sc, uint32_t offset, - uint32_t mask, uint32_t value) -{ - uint32_t reg_value = 0; - - reg_value = hda_get_reg_by_offset(sc, offset); - - reg_value &= ~mask; - reg_value |= (value & mask); - - hda_set_reg_by_offset(sc, offset, reg_value); -} - -static uint8_t -hda_parse_config(const char *opts, const char *key, char *val) -{ - char buf[64]; - char *s = buf; - char *tmp = NULL; - int len; - int i; - - if (!opts) - return (0); - - len = strlen(opts); - - if (len >= 64) { - DPRINTF("Opts too big\n"); - return (0); - } - - DPRINTF("opts: %s\n", opts); - - strcpy(buf, opts); - - for (i = 0; i < len; i++) - if (buf[i] == ',') { - buf[i] = 0; - tmp = buf + i + 1; - break; - } - - if (!memcmp(s, key, strlen(key))) { - strncpy(val, s + strlen(key), 64); - return (1); - } - - if (!tmp) - return (0); - - s = tmp; - if (!memcmp(s, key, strlen(key))) { - strncpy(val, s + strlen(key), 64); - return (1); - } - - return (0); -} - -static struct hda_softc * -hda_init(const char *opts) -{ - struct hda_softc *sc = NULL; - struct hda_codec_class *codec = NULL; - char play[64]; - char rec[64]; - int err, p, r; - -#if DEBUG_HDA == 1 - dbg = fopen("/tmp/bhyve_hda.log", "w+"); -#endif - - DPRINTF("opts: %s\n", opts); - - sc = calloc(1, sizeof(*sc)); - if (!sc) - return (NULL); - - hda_reset_regs(sc); - - /* - * TODO search all the codecs declared in opts - * For now we play with one single codec - */ - codec = hda_find_codec_class("hda_codec"); - if (codec) { - p = hda_parse_config(opts, "play=", play); - r = hda_parse_config(opts, "rec=", rec); - DPRINTF("play: %s rec: %s\n", play, rec); - if (p | r) { - err = hda_codec_constructor(sc, codec, p ? \ - play : NULL, r ? rec : NULL, NULL); - assert(!err); - } - } - - return (sc); -} - -static void -hda_update_intr(struct hda_softc *sc) -{ - struct pci_devinst *pi = sc->pci_dev; - uint32_t intctl = hda_get_reg_by_offset(sc, HDAC_INTCTL); - uint32_t intsts = 0; - uint32_t sdsts = 0; - uint32_t rirbsts = 0; - uint32_t wakeen = 0; - uint32_t statests = 0; - uint32_t off = 0; - int i; - - /* update the CIS bits */ - rirbsts = hda_get_reg_by_offset(sc, HDAC_RIRBSTS); - if (rirbsts & (HDAC_RIRBSTS_RINTFL | HDAC_RIRBSTS_RIRBOIS)) - intsts |= HDAC_INTSTS_CIS; - - wakeen = hda_get_reg_by_offset(sc, HDAC_WAKEEN); - statests = hda_get_reg_by_offset(sc, HDAC_STATESTS); - if (statests & wakeen) - intsts |= HDAC_INTSTS_CIS; - - /* update the SIS bits */ - for (i = 0; i < HDA_IOSS_NO; i++) { - off = hda_get_offset_stream(i); - sdsts = hda_get_reg_by_offset(sc, off + HDAC_SDSTS); - if (sdsts & HDAC_SDSTS_BCIS) - intsts |= (1 << i); - } - - /* update the GIS bit */ - if (intsts) - intsts |= HDAC_INTSTS_GIS; - - hda_set_reg_by_offset(sc, HDAC_INTSTS, intsts); - - if ((intctl & HDAC_INTCTL_GIE) && ((intsts & \ - ~HDAC_INTSTS_GIS) & intctl)) { - if (!sc->lintr) { - pci_lintr_assert(pi); - sc->lintr = 1; - } - } else { - if (sc->lintr) { - pci_lintr_deassert(pi); - sc->lintr = 0; - } - } -} - -static void -hda_response_interrupt(struct hda_softc *sc) -{ - uint8_t rirbctl = hda_get_reg_by_offset(sc, HDAC_RIRBCTL); - - if ((rirbctl & HDAC_RIRBCTL_RINTCTL) && sc->rirb_cnt) { - sc->rirb_cnt = 0; - hda_set_field_by_offset(sc, HDAC_RIRBSTS, HDAC_RIRBSTS_RINTFL, - HDAC_RIRBSTS_RINTFL); - hda_update_intr(sc); - } -} - -static int -hda_codec_constructor(struct hda_softc *sc, struct hda_codec_class *codec, - const char *play, const char *rec, const char *opts) -{ - struct hda_codec_inst *hci = NULL; - - if (sc->codecs_no >= HDA_CODEC_MAX) - return (-1); - - hci = calloc(1, sizeof(struct hda_codec_inst)); - if (!hci) - return (-1); - - hci->hda = sc; - hci->hops = &hops; - hci->cad = sc->codecs_no; - hci->codec = codec; - - sc->codecs[sc->codecs_no++] = hci; - - if (!codec->init) { - DPRINTF("This codec does not implement the init function\n"); - return (-1); - } - - return (codec->init(hci, play, rec, opts)); -} - -static struct hda_codec_class * -hda_find_codec_class(const char *name) -{ - struct hda_codec_class **pdpp = NULL, *pdp = NULL; - - SET_FOREACH(pdpp, hda_codec_class_set) { - pdp = *pdpp; - if (!strcmp(pdp->name, name)) { - return (pdp); - } - } - - return (NULL); -} - -static int -hda_send_command(struct hda_softc *sc, uint32_t verb) -{ - struct hda_codec_inst *hci = NULL; - struct hda_codec_class *codec = NULL; - uint8_t cad = (verb >> HDA_CMD_CAD_SHIFT) & 0x0f; - - hci = sc->codecs[cad]; - if (!hci) - return (-1); - - DPRINTF("cad: 0x%x verb: 0x%x\n", cad, verb); - - codec = hci->codec; - assert(codec); - - if (!codec->command) { - DPRINTF("This codec does not implement the command function\n"); - return (-1); - } - - return (codec->command(hci, verb)); -} - -static int -hda_notify_codecs(struct hda_softc *sc, uint8_t run, uint8_t stream, - uint8_t dir) -{ - struct hda_codec_inst *hci = NULL; - struct hda_codec_class *codec = NULL; - int err; - int i; - - /* Notify each codec */ - for (i = 0; i < sc->codecs_no; i++) { - hci = sc->codecs[i]; - assert(hci); - - codec = hci->codec; - assert(codec); - - if (codec->notify) { - err = codec->notify(hci, run, stream, dir); - if (!err) - break; - } - } - - return (i == sc->codecs_no ? (-1) : 0); -} - -static void -hda_reset(struct hda_softc *sc) -{ - int i; - struct hda_codec_inst *hci = NULL; - struct hda_codec_class *codec = NULL; - - hda_reset_regs(sc); - - /* Reset each codec */ - for (i = 0; i < sc->codecs_no; i++) { - hci = sc->codecs[i]; - assert(hci); - - codec = hci->codec; - assert(codec); - - if (codec->reset) - codec->reset(hci); - } - - sc->wall_clock_start = hda_get_clock_ns(); -} - -static void -hda_reset_regs(struct hda_softc *sc) -{ - uint32_t off = 0; - uint8_t i; - - DPRINTF("Reset the HDA controller registers ...\n"); - - memset(sc->regs, 0, sizeof(sc->regs)); - - hda_set_reg_by_offset(sc, HDAC_GCAP, - HDAC_GCAP_64OK | - (HDA_ISS_NO << HDAC_GCAP_ISS_SHIFT) | - (HDA_OSS_NO << HDAC_GCAP_OSS_SHIFT)); - hda_set_reg_by_offset(sc, HDAC_VMAJ, 0x01); - hda_set_reg_by_offset(sc, HDAC_OUTPAY, 0x3c); - hda_set_reg_by_offset(sc, HDAC_INPAY, 0x1d); - hda_set_reg_by_offset(sc, HDAC_CORBSIZE, - HDAC_CORBSIZE_CORBSZCAP_256 | HDAC_CORBSIZE_CORBSIZE_256); - hda_set_reg_by_offset(sc, HDAC_RIRBSIZE, - HDAC_RIRBSIZE_RIRBSZCAP_256 | HDAC_RIRBSIZE_RIRBSIZE_256); - - for (i = 0; i < HDA_IOSS_NO; i++) { - off = hda_get_offset_stream(i); - hda_set_reg_by_offset(sc, off + HDAC_SDFIFOS, HDA_FIFO_SIZE); - } -} - -static void -hda_stream_reset(struct hda_softc *sc, uint8_t stream_ind) -{ - struct hda_stream_desc *st = &sc->streams[stream_ind]; - uint32_t off = hda_get_offset_stream(stream_ind); - - DPRINTF("Reset the HDA stream: 0x%x\n", stream_ind); - - /* Reset the Stream Descriptor registers */ - memset(sc->regs + HDA_STREAM_REGS_BASE + off, 0, HDA_STREAM_REGS_LEN); - - /* Reset the Stream Descriptor */ - memset(st, 0, sizeof(*st)); - - hda_set_field_by_offset(sc, off + HDAC_SDSTS, - HDAC_SDSTS_FIFORDY, HDAC_SDSTS_FIFORDY); - hda_set_field_by_offset(sc, off + HDAC_SDCTL0, - HDAC_SDCTL_SRST, HDAC_SDCTL_SRST); -} - -static int -hda_stream_start(struct hda_softc *sc, uint8_t stream_ind) -{ - struct hda_stream_desc *st = &sc->streams[stream_ind]; - struct hda_bdle_desc *bdle_desc = NULL; - struct hda_bdle *bdle = NULL; - uint32_t lvi = 0; - uint32_t bdl_cnt = 0; - uint64_t bdpl = 0; - uint64_t bdpu = 0; - uint64_t bdl_paddr = 0; - void *bdl_vaddr = NULL; - uint32_t bdle_sz = 0; - uint64_t bdle_addrl = 0; - uint64_t bdle_addrh = 0; - uint64_t bdle_paddr = 0; - void *bdle_vaddr = NULL; - uint32_t off = hda_get_offset_stream(stream_ind); - uint32_t sdctl = 0; - uint8_t strm = 0; - uint8_t dir = 0; - int i; - - assert(!st->run); - - lvi = hda_get_reg_by_offset(sc, off + HDAC_SDLVI); - bdpl = hda_get_reg_by_offset(sc, off + HDAC_SDBDPL); - bdpu = hda_get_reg_by_offset(sc, off + HDAC_SDBDPU); - - bdl_cnt = lvi + 1; - assert(bdl_cnt <= HDA_BDL_MAX_LEN); - - bdl_paddr = bdpl | (bdpu << 32); - bdl_vaddr = hda_dma_get_vaddr(sc, bdl_paddr, - HDA_BDL_ENTRY_LEN * bdl_cnt); - if (!bdl_vaddr) { - DPRINTF("Fail to get the guest virtual address\n"); - return (-1); - } - - DPRINTF("stream: 0x%x bdl_cnt: 0x%x bdl_paddr: 0x%lx\n", - stream_ind, bdl_cnt, bdl_paddr); - - st->bdl_cnt = bdl_cnt; - - bdle = (struct hda_bdle *)bdl_vaddr; - for (i = 0; i < bdl_cnt; i++, bdle++) { - bdle_sz = bdle->len; - assert(!(bdle_sz % HDA_DMA_ACCESS_LEN)); - - bdle_addrl = bdle->addrl; - bdle_addrh = bdle->addrh; - - bdle_paddr = bdle_addrl | (bdle_addrh << 32); - bdle_vaddr = hda_dma_get_vaddr(sc, bdle_paddr, bdle_sz); - if (!bdle_vaddr) { - DPRINTF("Fail to get the guest virtual address\n"); - return (-1); - } - - bdle_desc = &st->bdl[i]; - bdle_desc->addr = bdle_vaddr; - bdle_desc->len = bdle_sz; - bdle_desc->ioc = bdle->ioc; - - DPRINTF("bdle: 0x%x bdle_sz: 0x%x\n", i, bdle_sz); - } - - sdctl = hda_get_reg_by_offset(sc, off + HDAC_SDCTL0); - strm = (sdctl >> 20) & 0x0f; - dir = stream_ind >= HDA_ISS_NO; - - DPRINTF("strm: 0x%x, dir: 0x%x\n", strm, dir); - - sc->stream_map[dir][strm] = stream_ind; - st->stream = strm; - st->dir = dir; - st->bp = 0; - st->be = 0; - - hda_set_pib(sc, stream_ind, 0); - - st->run = 1; - - hda_notify_codecs(sc, 1, strm, dir); - - return (0); -} - -static int -hda_stream_stop(struct hda_softc *sc, uint8_t stream_ind) -{ - struct hda_stream_desc *st = &sc->streams[stream_ind]; - uint8_t strm = st->stream; - uint8_t dir = st->dir; - - DPRINTF("stream: 0x%x, strm: 0x%x, dir: 0x%x\n", stream_ind, strm, dir); - - st->run = 0; - - hda_notify_codecs(sc, 0, strm, dir); - - return (0); -} - -static uint32_t -hda_read(struct hda_softc *sc, uint32_t offset) -{ - if (offset == HDAC_WALCLK) - return (24 * (hda_get_clock_ns() - \ - sc->wall_clock_start) / 1000); - - return (hda_get_reg_by_offset(sc, offset)); -} - -static int -hda_write(struct hda_softc *sc, uint32_t offset, uint8_t size, uint32_t value) -{ - uint32_t old = hda_get_reg_by_offset(sc, offset); - uint32_t masks[] = {0x00000000, 0x000000ff, 0x0000ffff, - 0x00ffffff, 0xffffffff}; - hda_set_reg_handler set_reg_handler = hda_set_reg_table[offset]; - - hda_set_field_by_offset(sc, offset, masks[size], value); - - if (set_reg_handler) - set_reg_handler(sc, offset, old); - - return (0); -} - -static inline void -hda_print_cmd_ctl_data(struct hda_codec_cmd_ctl *p) -{ -#if DEBUG_HDA == 1 - char *name = p->name; -#endif - DPRINTF("%s size: %d\n", name, p->size); - DPRINTF("%s dma_vaddr: %p\n", name, p->dma_vaddr); - DPRINTF("%s wp: 0x%x\n", name, p->wp); - DPRINTF("%s rp: 0x%x\n", name, p->rp); -} - -static int -hda_corb_start(struct hda_softc *sc) -{ - struct hda_codec_cmd_ctl *corb = &sc->corb; - uint8_t corbsize = 0; - uint64_t corblbase = 0; - uint64_t corbubase = 0; - uint64_t corbpaddr = 0; - - corb->name = "CORB"; - - corbsize = hda_get_reg_by_offset(sc, HDAC_CORBSIZE) & \ - HDAC_CORBSIZE_CORBSIZE_MASK; - corb->size = hda_corb_sizes[corbsize]; - - if (!corb->size) { - DPRINTF("Invalid corb size\n"); - return (-1); - } - - corblbase = hda_get_reg_by_offset(sc, HDAC_CORBLBASE); - corbubase = hda_get_reg_by_offset(sc, HDAC_CORBUBASE); - - corbpaddr = corblbase | (corbubase << 32); - DPRINTF("CORB dma_paddr: %p\n", (void *)corbpaddr); - - corb->dma_vaddr = hda_dma_get_vaddr(sc, corbpaddr, - HDA_CORB_ENTRY_LEN * corb->size); - if (!corb->dma_vaddr) { - DPRINTF("Fail to get the guest virtual address\n"); - return (-1); - } - - corb->wp = hda_get_reg_by_offset(sc, HDAC_CORBWP); - corb->rp = hda_get_reg_by_offset(sc, HDAC_CORBRP); - - corb->run = 1; - - hda_print_cmd_ctl_data(corb); - - return (0); -} - -static int -hda_corb_run(struct hda_softc *sc) -{ - struct hda_codec_cmd_ctl *corb = &sc->corb; - uint32_t verb = 0; - int err; - - corb->wp = hda_get_reg_by_offset(sc, HDAC_CORBWP); - - while (corb->rp != corb->wp && corb->run) { - corb->rp++; - corb->rp %= corb->size; - - verb = hda_dma_ld_dword(corb->dma_vaddr + \ - HDA_CORB_ENTRY_LEN * corb->rp); - - err = hda_send_command(sc, verb); - assert(!err); - } - - hda_set_reg_by_offset(sc, HDAC_CORBRP, corb->rp); - - if (corb->run) - hda_response_interrupt(sc); - - return (0); -} - -static int -hda_rirb_start(struct hda_softc *sc) -{ - struct hda_codec_cmd_ctl *rirb = &sc->rirb; - uint8_t rirbsize = 0; - uint64_t rirblbase = 0; - uint64_t rirbubase = 0; - uint64_t rirbpaddr = 0; - - rirb->name = "RIRB"; - - rirbsize = hda_get_reg_by_offset(sc, HDAC_RIRBSIZE) & \ - HDAC_RIRBSIZE_RIRBSIZE_MASK; - rirb->size = hda_rirb_sizes[rirbsize]; - - if (!rirb->size) { - DPRINTF("Invalid rirb size\n"); - return (-1); - } - - rirblbase = hda_get_reg_by_offset(sc, HDAC_RIRBLBASE); - rirbubase = hda_get_reg_by_offset(sc, HDAC_RIRBUBASE); - - rirbpaddr = rirblbase | (rirbubase << 32); - DPRINTF("RIRB dma_paddr: %p\n", (void *)rirbpaddr); - - rirb->dma_vaddr = hda_dma_get_vaddr(sc, rirbpaddr, - HDA_RIRB_ENTRY_LEN * rirb->size); - if (!rirb->dma_vaddr) { - DPRINTF("Fail to get the guest virtual address\n"); - return (-1); - } - - rirb->wp = hda_get_reg_by_offset(sc, HDAC_RIRBWP); - rirb->rp = 0x0000; - - rirb->run = 1; - - hda_print_cmd_ctl_data(rirb); - - return (0); -} - -static void * -hda_dma_get_vaddr(struct hda_softc *sc, uint64_t dma_paddr, size_t len) -{ - struct pci_devinst *pi = sc->pci_dev; - - assert(pi); - - return (paddr_guest2host(pi->pi_vmctx, (uintptr_t)dma_paddr, len)); -} - -static void -hda_dma_st_dword(void *dma_vaddr, uint32_t data) -{ - *(uint32_t*)dma_vaddr = data; -} - -static uint32_t -hda_dma_ld_dword(void *dma_vaddr) -{ - return (*(uint32_t*)dma_vaddr); -} - -static inline uint8_t -hda_get_stream_by_offsets(uint32_t offset, uint8_t reg_offset) -{ - uint8_t stream_ind = (offset - reg_offset) >> 5; - - assert(stream_ind < HDA_IOSS_NO); - - return (stream_ind); -} - -static inline uint32_t -hda_get_offset_stream(uint8_t stream_ind) -{ - return (stream_ind << 5); -} - -static void -hda_set_gctl(struct hda_softc *sc, uint32_t offset, uint32_t old) -{ - uint32_t value = hda_get_reg_by_offset(sc, offset); - - if (!(value & HDAC_GCTL_CRST)) { - hda_reset(sc); - } -} - -static void -hda_set_statests(struct hda_softc *sc, uint32_t offset, uint32_t old) -{ - uint32_t value = hda_get_reg_by_offset(sc, offset); - - hda_set_reg_by_offset(sc, offset, old); - - /* clear the corresponding bits written by the software (guest) */ - hda_set_field_by_offset(sc, offset, value & HDA_STATESTS_IRQ_MASK, 0); - - hda_update_intr(sc); -} - -static void -hda_set_corbwp(struct hda_softc *sc, uint32_t offset, uint32_t old) -{ - hda_corb_run(sc); -} - -static void -hda_set_corbctl(struct hda_softc *sc, uint32_t offset, uint32_t old) -{ - uint32_t value = hda_get_reg_by_offset(sc, offset); - int err; - struct hda_codec_cmd_ctl *corb = NULL; - - if (value & HDAC_CORBCTL_CORBRUN) { - if (!(old & HDAC_CORBCTL_CORBRUN)) { - err = hda_corb_start(sc); - assert(!err); - } - } else { - corb = &sc->corb; - memset(corb, 0, sizeof(*corb)); - } - - hda_corb_run(sc); -} - -static void -hda_set_rirbctl(struct hda_softc *sc, uint32_t offset, uint32_t old) -{ - uint32_t value = hda_get_reg_by_offset(sc, offset); - int err; - struct hda_codec_cmd_ctl *rirb = NULL; - - if (value & HDAC_RIRBCTL_RIRBDMAEN) { - err = hda_rirb_start(sc); - assert(!err); - } else { - rirb = &sc->rirb; - memset(rirb, 0, sizeof(*rirb)); - } -} - -static void -hda_set_rirbsts(struct hda_softc *sc, uint32_t offset, uint32_t old) -{ - uint32_t value = hda_get_reg_by_offset(sc, offset); - - hda_set_reg_by_offset(sc, offset, old); - - /* clear the corresponding bits written by the software (guest) */ - hda_set_field_by_offset(sc, offset, value & HDA_RIRBSTS_IRQ_MASK, 0); - - hda_update_intr(sc); -} - -static void -hda_set_dpiblbase(struct hda_softc *sc, uint32_t offset, uint32_t old) -{ - uint32_t value = hda_get_reg_by_offset(sc, offset); - uint64_t dpiblbase = 0; - uint64_t dpibubase = 0; - uint64_t dpibpaddr = 0; - - if ((value & HDAC_DPLBASE_DPLBASE_DMAPBE) != (old & \ - HDAC_DPLBASE_DPLBASE_DMAPBE)) { - if (value & HDAC_DPLBASE_DPLBASE_DMAPBE) { - dpiblbase = value & HDAC_DPLBASE_DPLBASE_MASK; - dpibubase = hda_get_reg_by_offset(sc, HDAC_DPIBUBASE); - - dpibpaddr = dpiblbase | (dpibubase << 32); - DPRINTF("DMA Position In Buffer dma_paddr: %p\n", - (void *)dpibpaddr); - - sc->dma_pib_vaddr = hda_dma_get_vaddr(sc, dpibpaddr, - HDA_DMA_PIB_ENTRY_LEN * HDA_IOSS_NO); - if (!sc->dma_pib_vaddr) { - DPRINTF("Fail to get the guest \ - virtual address\n"); - assert(0); - } - } else { - DPRINTF("DMA Position In Buffer Reset\n"); - sc->dma_pib_vaddr = NULL; - } - } -} - -static void -hda_set_sdctl(struct hda_softc *sc, uint32_t offset, uint32_t old) -{ - uint8_t stream_ind = hda_get_stream_by_offsets(offset, HDAC_SDCTL0); - uint32_t value = hda_get_reg_by_offset(sc, offset); - int err; - - DPRINTF("stream_ind: 0x%x old: 0x%x value: 0x%x\n", - stream_ind, old, value); - - if (value & HDAC_SDCTL_SRST) { - hda_stream_reset(sc, stream_ind); - } - - if ((value & HDAC_SDCTL_RUN) != (old & HDAC_SDCTL_RUN)) { - if (value & HDAC_SDCTL_RUN) { - err = hda_stream_start(sc, stream_ind); - assert(!err); - } else { - err = hda_stream_stop(sc, stream_ind); - assert(!err); - } - } -} - -static void -hda_set_sdctl2(struct hda_softc *sc, uint32_t offset, uint32_t old) -{ - uint32_t value = hda_get_reg_by_offset(sc, offset); - - hda_set_field_by_offset(sc, offset - 2, 0x00ff0000, value << 16); -} - -static void -hda_set_sdsts(struct hda_softc *sc, uint32_t offset, uint32_t old) -{ - uint32_t value = hda_get_reg_by_offset(sc, offset); - - hda_set_reg_by_offset(sc, offset, old); - - /* clear the corresponding bits written by the software (guest) */ - hda_set_field_by_offset(sc, offset, value & HDA_SDSTS_IRQ_MASK, 0); - - hda_update_intr(sc); -} - -static int -hda_signal_state_change(struct hda_codec_inst *hci) -{ - struct hda_softc *sc = NULL; - uint32_t sdiwake = 0; - - assert(hci); - assert(hci->hda); - - DPRINTF("cad: 0x%x\n", hci->cad); - - sc = hci->hda; - sdiwake = 1 << hci->cad; - - hda_set_field_by_offset(sc, HDAC_STATESTS, sdiwake, sdiwake); - hda_update_intr(sc); - - return (0); -} - -static int -hda_response(struct hda_codec_inst *hci, uint32_t response, uint8_t unsol) -{ - struct hda_softc *sc = NULL; - struct hda_codec_cmd_ctl *rirb = NULL; - uint32_t response_ex = 0; - uint8_t rintcnt = 0; - - assert(hci); - assert(hci->cad <= HDA_CODEC_MAX); - - response_ex = hci->cad | unsol; - - sc = hci->hda; - assert(sc); - - rirb = &sc->rirb; - - if (rirb->run) { - rirb->wp++; - rirb->wp %= rirb->size; - - hda_dma_st_dword(rirb->dma_vaddr + HDA_RIRB_ENTRY_LEN * \ - rirb->wp, response); - hda_dma_st_dword(rirb->dma_vaddr + HDA_RIRB_ENTRY_LEN * \ - rirb->wp + 0x04, response_ex); - - hda_set_reg_by_offset(sc, HDAC_RIRBWP, rirb->wp); - - sc->rirb_cnt++; - } - - rintcnt = hda_get_reg_by_offset(sc, HDAC_RINTCNT); - if (sc->rirb_cnt == rintcnt) - hda_response_interrupt(sc); - - return (0); -} - -static int -hda_transfer(struct hda_codec_inst *hci, uint8_t stream, uint8_t dir, - void *buf, size_t count) -{ - struct hda_softc *sc = NULL; - struct hda_stream_desc *st = NULL; - struct hda_bdle_desc *bdl = NULL; - struct hda_bdle_desc *bdle_desc = NULL; - uint8_t stream_ind = 0; - uint32_t lpib = 0; - uint32_t off = 0; - size_t left = 0; - uint8_t irq = 0; - - assert(hci); - assert(hci->hda); - assert(buf); - assert(!(count % HDA_DMA_ACCESS_LEN)); - - if (!stream) { - DPRINTF("Invalid stream\n"); - return (-1); - } - - sc = hci->hda; - - assert(stream < HDA_STREAM_TAGS_CNT); - stream_ind = sc->stream_map[dir][stream]; - - if (!dir) - assert(stream_ind < HDA_ISS_NO); - else - assert(stream_ind >= HDA_ISS_NO && stream_ind < HDA_IOSS_NO); - - st = &sc->streams[stream_ind]; - if (!st->run) { - DPRINTF("Stream 0x%x stopped\n", stream); - return (-1); - } - - assert(st->stream == stream); - - off = hda_get_offset_stream(stream_ind); - - lpib = hda_get_reg_by_offset(sc, off + HDAC_SDLPIB); - - bdl = st->bdl; - - assert(st->be < st->bdl_cnt); - assert(st->bp < bdl[st->be].len); - - left = count; - while (left) { - bdle_desc = &bdl[st->be]; - - if (dir) - *(uint32_t *)buf = \ - hda_dma_ld_dword(bdle_desc->addr + st->bp); - else - hda_dma_st_dword(bdle_desc->addr + st->bp, - *(uint32_t *)buf); - - buf += HDA_DMA_ACCESS_LEN; - st->bp += HDA_DMA_ACCESS_LEN; - lpib += HDA_DMA_ACCESS_LEN; - left -= HDA_DMA_ACCESS_LEN; - - if (st->bp == bdle_desc->len) { - st->bp = 0; - if (bdle_desc->ioc) - irq = 1; - st->be++; - if (st->be == st->bdl_cnt) { - st->be = 0; - lpib = 0; - } - bdle_desc = &bdl[st->be]; - } - } - - hda_set_pib(sc, stream_ind, lpib); - - if (irq) { - hda_set_field_by_offset(sc, off + HDAC_SDSTS, - HDAC_SDSTS_BCIS, HDAC_SDSTS_BCIS); - hda_update_intr(sc); - } - - return (0); -} - -static void -hda_set_pib(struct hda_softc *sc, uint8_t stream_ind, uint32_t pib) -{ - uint32_t off = hda_get_offset_stream(stream_ind); - - hda_set_reg_by_offset(sc, off + HDAC_SDLPIB, pib); - /* LPIB Alias */ - hda_set_reg_by_offset(sc, 0x2000 + off + HDAC_SDLPIB, pib); - if (sc->dma_pib_vaddr) - *(uint32_t *)(sc->dma_pib_vaddr + stream_ind * \ - HDA_DMA_PIB_ENTRY_LEN) = pib; -} - -static uint64_t hda_get_clock_ns(void) -{ - struct timespec ts; - int err; - - err = clock_gettime(CLOCK_MONOTONIC, &ts); - assert(!err); - - return (ts.tv_sec * 1000000000LL + ts.tv_nsec); -} - -/* - * PCI HDA function definitions - */ -static int -pci_hda_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) -{ - struct hda_softc *sc = NULL; - - assert(ctx != NULL); - assert(pi != NULL); - - pci_set_cfgdata16(pi, PCIR_VENDOR, INTEL_VENDORID); - pci_set_cfgdata16(pi, PCIR_DEVICE, HDA_INTEL_82801G); - - pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_MULTIMEDIA_HDA); - pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_MULTIMEDIA); - - /* select the Intel HDA mode */ - pci_set_cfgdata8(pi, PCIR_HDCTL, 0x01); - - /* allocate one BAR register for the Memory address offsets */ - pci_emul_alloc_bar(pi, 0, PCIBAR_MEM32, HDA_LAST_OFFSET); - - /* allocate an IRQ pin for our slot */ - pci_lintr_request(pi); - - sc = hda_init(opts); - if (!sc) - return (-1); - - sc->pci_dev = pi; - pi->pi_arg = sc; - - return (0); -} - -static void -pci_hda_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, - int baridx, uint64_t offset, int size, uint64_t value) -{ - struct hda_softc *sc = pi->pi_arg; - int err; - - assert(sc); - assert(baridx == 0); - assert(size <= 4); - - DPRINTF("offset: 0x%lx value: 0x%lx\n", offset, value); - - err = hda_write(sc, offset, size, value); - assert(!err); -} - -static uint64_t -pci_hda_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, - int baridx, uint64_t offset, int size) -{ - struct hda_softc *sc = pi->pi_arg; - uint64_t value = 0; - - assert(sc); - assert(baridx == 0); - assert(size <= 4); - - value = hda_read(sc, offset); - - DPRINTF("offset: 0x%lx value: 0x%lx\n", offset, value); - - return (value); -} diff --git a/usr.sbin/bhyve/pci_hda.h b/usr.sbin/bhyve/pci_hda.h deleted file mode 100644 index 038a1da8dee6..000000000000 --- a/usr.sbin/bhyve/pci_hda.h +++ /dev/null @@ -1,90 +0,0 @@ -/*- - * Copyright (c) 2016 Alex Teaca - * 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, 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 OR CONTRIBUTORS 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$ - */ - -#ifndef _HDA_EMUL_H_ -#define _HDA_EMUL_H_ - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "hda_reg.h" - -/* - * HDA Debug Log - */ -#define DEBUG_HDA 1 -#if DEBUG_HDA == 1 -extern FILE *dbg; -#define DPRINTF(fmt, arg...) \ -do {fprintf(dbg, "%s-%d: " fmt, __func__, __LINE__, ##arg); \ -fflush(dbg); } while (0) -#else -#define DPRINTF(fmt, arg...) -#endif - -#define HDA_FIFO_SIZE 0x100 - -struct hda_softc; -struct hda_codec_class; - -struct hda_codec_inst { - uint8_t cad; - struct hda_codec_class *codec; - struct hda_softc *hda; - struct hda_ops *hops; - void *priv; -}; - -struct hda_codec_class { - char *name; - int (*init)(struct hda_codec_inst *hci, const char *play, - const char *rec, const char *opts); - int (*reset)(struct hda_codec_inst *hci); - int (*command)(struct hda_codec_inst *hci, uint32_t cmd_data); - int (*notify)(struct hda_codec_inst *hci, uint8_t run, uint8_t stream, - uint8_t dir); -}; - -struct hda_ops { - int (*signal)(struct hda_codec_inst *hci); - int (*response)(struct hda_codec_inst *hci, uint32_t response, - uint8_t unsol); - int (*transfer)(struct hda_codec_inst *hci, uint8_t stream, - uint8_t dir, void *buf, size_t count); -}; - -#define HDA_EMUL_SET(x) DATA_SET(hda_codec_class_set, x); - -#endif /* _HDA_EMUL_H_ */ diff --git a/usr.sbin/nandsim/Makefile b/usr.sbin/nandsim/Makefile deleted file mode 100644 index 9269ab5de34f..000000000000 --- a/usr.sbin/nandsim/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# $FreeBSD$ - -PROG= nandsim -SRCS= nandsim.c nandsim_rcfile.c nandsim_cfgparse.c -BINDIR= /usr/sbin -MAN= nandsim.8 - -.include diff --git a/usr.sbin/nandsim/Makefile.depend b/usr.sbin/nandsim/Makefile.depend deleted file mode 100644 index 6cfaab1c3644..000000000000 --- a/usr.sbin/nandsim/Makefile.depend +++ /dev/null @@ -1,17 +0,0 @@ -# $FreeBSD$ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - gnu/lib/csu \ - include \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - lib/libcompiler_rt \ - - -.include - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif diff --git a/usr.sbin/nandsim/nandsim.8 b/usr.sbin/nandsim/nandsim.8 deleted file mode 100644 index 0951cc7a1aac..000000000000 --- a/usr.sbin/nandsim/nandsim.8 +++ /dev/null @@ -1,229 +0,0 @@ -.\" Copyright (c) 2010 Semihalf -.\" 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 August 10, 2010 -.Dt NANDSIM 8 -.Os -.Sh NAME -.Nm nandsim -.Nd NAND simulator control program -.Sh SYNOPSIS -.Nm -.Ic status -.Aq ctrl_no | Fl -all | Fl a -.Op Fl v -.Nm -.Ic conf -.Aq filename -.Nm -.Ic start -.Aq ctrl_no -.Nm -.Ic mod -.Aq ctrl_no:cs_no | Fl l Aq loglevel -.Op Fl p Aq prog_time -.Op Fl e Aq erase_time -.Op Fl r Aq read_time -.Op Fl E Aq error_ratio -.Op Fl h -.Nm -.Ic stop -.Aq ctrl_no -.Nm -.Ic error -.Aq ctrl_no:cs_no -.Aq page_num -.Aq column -.Aq length -.Aq pattern -.Nm -.Ic bb -.Aq ctrl_no:cs_no -.Op blk_num,blk_num2,... -.Op Fl U -.Op Fl L -.Nm -.Ic freeze -.Op ctrl_no -.Nm -.Ic log -.Aq ctrl_no | Fl -all | Fl a -.Nm -.Ic stats -.Aq ctrl_no:cs_no -.Aq page_num -.Nm -.Ic dump -.Aq ctrl_no:cs_no -.Aq filename -.Nm -.Ic restore -.Aq ctrl_no:chip_no -.Aq filename -.Nm -.Ic destroy -.Aq ctrl_no[:cs_no] | Fl -all | Fl a -.Nm -.Ic help -.Op Fl v -.Sh COMMAND DESCRIPTION -Controllers and chips are arranged into a simple hierarchy. -There can be up to 4 controllers configured, each with 4 chip select (CS) lines. -A given chip is connected to one of the chip selects. -.Pp -Controllers are specified as -.Aq ctrl_no ; -chip selects are specified as -.Aq cs_no . -.Bl -tag -width periphlist -.It Ic status -Gets controller(s) status. If -.Fl a -or -.Fl -all -flag is specified - command will print status of every controller -currently available. -Optional flag -.Fl v -causes printing complete information about the controller, and all -chips attached to it. -.It Ic conf -Reads simulator configuration from a specified file (this includes -the simulation "layout" i.e. controllers-chips assignments). -Configuration changes for an already started simulation require a -full stop-start cycle in order to take effect i.e.: -.Bl -column -.It nandsim stop ... -.It nandsim destroy ... -.Pp -.It << edit config file >> -.Pp -.It nandsim conf ... -.It nandsim start ... -.El -.It Ic mod -Alters simulator parameters on-the-fly. -If controller number and CS pair is not specified, the general -simulator parameters (not specific to a controller or a chip) will be modified. -Changing chip's parameters requires specifying both controller number and CS -to which the given chip is connected. -Parameters which can be altered: -.Pp -General simulator related: -.Bl -tag -width flag -.It Fl l Aq log_level -change logging level to -.Aq log_level -.El -.Pp -Chip related: -.Bl -tag -width flag -.It Fl p Aq prog_time -change prog time for specified chip to -.Aq prog_time -.It Fl e Aq erase_time -change erase time for specified chip to -.Aq erase_time -.It Fl r Aq read_time -change read time for specified chip to -.Aq read_time -.It Fl E Aq error_ratio -change error ratio for specified chip to -.Aq error_ratio . -Error ratio is a number of errors per million read/write bytes. -.El -.Pp -Additionally, flag -.Fl h -will list parameters which can be altered. -.El -.Bl -tag -width periphlist -.It Ic bb -Marks/unmarks a specified block as bad. -To mark/unmark the bad condition an a block, the following parameters -have to be supplied: controller number, CS number, and at least one -block number. -It is possible to specify multiple blocks, by separating blocks numbers -with a comma. -The following options can be used for the 'bb' command: -.Bl -tag -width flag -.It Fl U -unmark the bad previously marked block as bad. -.It Fl L -list all blocks marked as bad on a given chip. -.El -.It Ic log -Prints activity log of the specified controller to stdout; if -controller number is not specified, logs for all available -controllers are printed. -.It Ic stats -Print statistics of the selected controller, chip and page. -Statistics includes read count, write count, raw read count, raw -write count, ECC stats (succeeded corrections, failed correction). -.It Ic dump -Dumps a snaphot of a single chip (including data and bad blocks -information, wearout level) into the file. -.It Ic restore -Restores chip state from a dump-file snapshot (produced previously -with the 'dump' command). -.It Ic start -Starts a controller i.e. the simulation. -.It Ic stop -Stops an already started controller; if the controller number is not -supplied, attempts to stop all currently working controllers. -.It Ic destroy -Removes existing active chip/controller and its configuration from -memory and releases the resources. -Specifying flag -.Fl a -or -.Fl -all -causes removal of every chip and controller. -Controller must be stopped in order to be destroyed. -.It Ic error -Directly overwrites a certain number of bytes in the specified page -at a given offset with a supplied pattern (which mimics the -corruption of flash contents). -.It Ic help -Prints synopsis, -.Fl v -gives more verbose output. -.It Ic freeze -Stops simulation of given controller (simulates power-loss). -All commands issues to any chip on this controller are ignored. -.El -.Sh SEE ALSO -.Xr nand 4 , -.Xr nandsim 4 , -.Xr nandsim.conf 5 -.Sh HISTORY -The -.Nm -utility first appeared in -.Fx 10.0 . -.Sh AUTHORS -This utility was written by -.An Lukasz Wojcik . diff --git a/usr.sbin/nandsim/nandsim.c b/usr.sbin/nandsim/nandsim.c deleted file mode 100644 index 10eadcbc940d..000000000000 --- a/usr.sbin/nandsim/nandsim.c +++ /dev/null @@ -1,1399 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * 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, 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 AND CONTRIBUTORS ``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 AUTHOR OR CONTRIBUTORS 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. - */ - -/* - * Control application for the NAND simulator. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "nandsim_cfgparse.h" - -#define SIMDEVICE "/dev/nandsim.ioctl" - -#define error(fmt, args...) do { \ - printf("ERROR: " fmt "\n", ##args); } while (0) - -#define warn(fmt, args...) do { \ - printf("WARNING: " fmt "\n", ##args); } while (0) - -#define DEBUG -#undef DEBUG - -#ifdef DEBUG -#define debug(fmt, args...) do { \ - printf("NANDSIM_CONF:" fmt "\n", ##args); } while (0) -#else -#define debug(fmt, args...) do {} while(0) -#endif - -#define NANDSIM_RAM_LOG_SIZE 16384 - -#define MSG_NOTRUNNING "Controller#%d is not running.Please start" \ - " it first." -#define MSG_RUNNING "Controller#%d is already running!" -#define MSG_CTRLCHIPNEEDED "You have to specify ctrl_no:cs_no pair!" -#define MSG_STATUSACQCTRLCHIP "Could not acquire status for ctrl#%d chip#%d" -#define MSG_STATUSACQCTRL "Could not acquire status for ctrl#%d" -#define MSG_NOCHIP "There is no such chip configured (chip#%d "\ - "at ctrl#%d)!" - -#define MSG_NOCTRL "Controller#%d is not configured!" -#define MSG_NOTCONFIGDCTRLCHIP "Chip connected to ctrl#%d at cs#%d " \ - "is not configured." - -typedef int (commandfunc_t)(int , char **); - -static struct nandsim_command *getcommand(char *); -static int parse_devstring(char *, int *, int *); -static void printchip(struct sim_chip *, uint8_t); -static void printctrl(struct sim_ctrl *); -static int opendev(int *); -static commandfunc_t cmdstatus; -static commandfunc_t cmdconf; -static commandfunc_t cmdstart; -static commandfunc_t cmdstop; -static commandfunc_t cmdmod; -static commandfunc_t cmderror; -static commandfunc_t cmdbb; -static commandfunc_t cmdfreeze; -static commandfunc_t cmdlog; -static commandfunc_t cmdstats; -static commandfunc_t cmddump; -static commandfunc_t cmdrestore; -static commandfunc_t cmddestroy; -static commandfunc_t cmdhelp; -static int checkusage(int, int, char **); -static int is_chip_created(int, int, int *); -static int is_ctrl_created(int, int *); -static int is_ctrl_running(int, int *); -static int assert_chip_connected(int , int); -static int printstats(int, int, uint32_t, int); - -struct nandsim_command { - const char *cmd_name; /* Command name */ - commandfunc_t *commandfunc; /* Ptr to command function */ - uint8_t req_argc; /* Mandatory arguments count */ - const char *usagestring; /* Usage string */ -}; - -static struct nandsim_command commands[] = { - {"status", cmdstatus, 1, - "status [-v]\n" }, - {"conf", cmdconf, 1, - "conf \n" }, - {"start", cmdstart, 1, - "start \n" }, - {"mod", cmdmod, 2, - "mod [-l ] | [-p ]\n" - "\t[-e ] [-r ]\n" - "\t[-E ] | [-h]\n" }, - {"stop", cmdstop, 1, - "stop \n" }, - {"error", cmderror, 5, - "error \n" }, - {"bb", cmdbb, 2, - "bb [blk_num1,blk_num2,..] [-U] [-L]\n" }, - {"freeze", cmdfreeze, 1, - "freeze [ctrl_no]\n" }, - {"log", cmdlog, 1, - "log \n" }, - {"stats", cmdstats, 2, - "stats \n" }, - {"dump", cmddump, 2, - "dump \n" }, - {"restore", cmdrestore, 2, - "restore \n" }, - {"destroy", cmddestroy, 1, - "destroy \n" }, - {"help", cmdhelp, 0, - "help [-v]" }, - {NULL, NULL, 0, NULL}, -}; - - -/* Parse command name, and start appropriate function */ -static struct nandsim_command* -getcommand(char *arg) -{ - struct nandsim_command *opts; - - for (opts = commands; (opts != NULL) && - (opts->cmd_name != NULL); opts++) { - if (strcmp(opts->cmd_name, arg) == 0) - return (opts); - } - return (NULL); -} - -/* - * Parse given string in format :, if possible -- set - * ctrl and/or cs, and return 0 (success) or 1 (in case of error). - * - * ctrl == 0xff && chip == 0xff : '--all' flag specified - * ctrl != 0xff && chip != 0xff : both ctrl & chip were specified - * ctrl != 0xff && chip == 0xff : only ctrl was specified - */ -static int -parse_devstring(char *str, int *ctrl, int *cs) -{ - char *tmpstr; - unsigned int num = 0; - - /* Ignore white spaces at the beginning */ - while (isspace(*str) && (*str != '\0')) - str++; - - *ctrl = 0xff; - *cs = 0xff; - if (strcmp(str, "--all") == 0 || - strcmp(str, "-a") == 0) { - /* If --all or -a is specified, ctl==chip==0xff */ - debug("CTRL=%d CHIP=%d\n", *ctrl, *cs); - return (0); - } - /* Separate token and try to convert it to int */ - tmpstr = (char *)strtok(str, ":"); - if ((tmpstr != NULL) && (*tmpstr != '\0')) { - if (convert_arguint(tmpstr, &num) != 0) - return (1); - - if (num > MAX_SIM_DEV - 1) { - error("Invalid ctrl_no supplied: %s. Valid ctrl_no " - "value must lie between 0 and 3!", tmpstr); - return (1); - } - - *ctrl = num; - tmpstr = (char *)strtok(NULL, ":"); - - if ((tmpstr != NULL) && (*tmpstr != '\0')) { - if (convert_arguint(tmpstr, &num) != 0) - return (1); - - /* Check if chip_no is valid */ - if (num > MAX_CTRL_CS - 1) { - error("Invalid chip_no supplied: %s. Valid " - "chip_no value must lie between 0 and 3!", - tmpstr); - return (1); - } - *cs = num; - } - } else - /* Empty devstring supplied */ - return (1); - - debug("CTRL=%d CHIP=%d\n", *ctrl, *cs); - return (0); -} - -static int -opendev(int *fd) -{ - - *fd = open(SIMDEVICE, O_RDWR); - if (*fd == -1) { - error("Could not open simulator device file (%s)!", - SIMDEVICE); - return (EX_OSFILE); - } - return (EX_OK); -} - -static int -opencdev(int *cdevd, int ctrl, int chip) -{ - char fname[255]; - - sprintf(fname, "/dev/nandsim%d.%d", ctrl, chip); - *cdevd = open(fname, O_RDWR); - if (*cdevd == -1) - return (EX_NOINPUT); - - return (EX_OK); -} - -/* - * Check if given arguments count match requirements. If no, or - * --help (-h) flag is specified -- return 1 (print usage) - */ -static int -checkusage(int gargc, int argsreqd, char **gargv) -{ - - if (gargc < argsreqd + 2 || (gargc >= (argsreqd + 2) && - (strcmp(gargv[1], "--help") == 0 || - strcmp(gargv[1], "-h") == 0))) - return (1); - - return (0); -} - -static int -cmdstatus(int gargc, char **gargv) -{ - int chip = 0, ctl = 0, err = 0, fd, idx, idx2, start, stop; - uint8_t verbose = 0; - struct sim_ctrl ctrlconf; - struct sim_chip chipconf; - - err = parse_devstring(gargv[2], &ctl, &chip); - if (err) { - return (EX_USAGE); - } else if (ctl == 0xff) { - /* Every controller */ - start = 0; - stop = MAX_SIM_DEV-1; - } else { - /* Specified controller only */ - start = ctl; - stop = ctl; - } - - if (opendev(&fd) != EX_OK) - return (EX_OSFILE); - - for (idx = 0; idx < gargc; idx ++) - if (strcmp(gargv[idx], "-v") == 0 || - strcmp(gargv[idx], "--verbose") == 0) - verbose = 1; - - for (idx = start; idx <= stop; idx++) { - ctrlconf.num = idx; - err = ioctl(fd, NANDSIM_STATUS_CTRL, &ctrlconf); - if (err) { - err = EX_SOFTWARE; - error(MSG_STATUSACQCTRL, idx); - continue; - } - - printctrl(&ctrlconf); - - for (idx2 = 0; idx2 < MAX_CTRL_CS; idx2++) { - chipconf.num = idx2; - chipconf.ctrl_num = idx; - - err = ioctl(fd, NANDSIM_STATUS_CHIP, &chipconf); - if (err) { - err = EX_SOFTWARE; - error(MSG_STATUSACQCTRL, idx); - continue; - } - - printchip(&chipconf, verbose); - } - } - close(fd); - return (err); -} - -static int -cmdconf(int gargc __unused, char **gargv) -{ - int err; - - err = parse_config(gargv[2], SIMDEVICE); - if (err) - return (EX_DATAERR); - - return (EX_OK); -} - -static int -cmdstart(int gargc __unused, char **gargv) -{ - int chip = 0, ctl = 0, err = 0, fd, running, state; - - err = parse_devstring(gargv[2], &ctl, &chip); - if (err) - return (EX_USAGE); - - err = is_ctrl_created(ctl, &state); - if (err) { - return (EX_SOFTWARE); - } else if (state == 0) { - error(MSG_NOCTRL, ctl); - return (EX_SOFTWARE); - } - - err = is_ctrl_running(ctl, &running); - if (err) - return (EX_SOFTWARE); - - if (running) { - warn(MSG_RUNNING, ctl); - } else { - if (opendev(&fd) != EX_OK) - return (EX_OSFILE); - - err = ioctl(fd, NANDSIM_START_CTRL, &ctl); - close(fd); - if (err) { - error("Cannot start controller#%d", ctl); - err = EX_SOFTWARE; - } - } - return (err); -} - -static int -cmdstop(int gargc __unused, char **gargv) -{ - int chip = 0, ctl = 0, err = 0, fd, running; - - err = parse_devstring(gargv[2], &ctl, &chip); - if (err) - return (EX_USAGE); - - err = is_ctrl_running(ctl, &running); - if (err) - return (EX_SOFTWARE); - - if (!running) { - error(MSG_NOTRUNNING, ctl); - } else { - if (opendev(&fd) != EX_OK) - return (EX_OSFILE); - - err = ioctl(fd, NANDSIM_STOP_CTRL, &ctl); - close(fd); - if (err) { - error("Cannot stop controller#%d", ctl); - err = EX_SOFTWARE; - } - } - - return (err); -} - -static int -cmdmod(int gargc __unused, char **gargv) -{ - int chip, ctl, err = 0, fd = -1, i; - struct sim_mod mods; - - if (gargc >= 4) { - if (strcmp(gargv[2], "--loglevel") == 0 || strcmp(gargv[2], - "-l") == 0) { - /* Set loglevel (ctrl:chip pair independent) */ - mods.field = SIM_MOD_LOG_LEVEL; - - if (convert_arguint(gargv[3], &mods.new_value) != 0) - return (EX_SOFTWARE); - - if (opendev(&fd) != EX_OK) - return (EX_OSFILE); - - err = ioctl(fd, NANDSIM_MODIFY, &mods); - if (err) { - error("simulator parameter %s could not be " - "modified !", gargv[3]); - close(fd); - return (EX_SOFTWARE); - } - - debug("request : loglevel = %d\n", mods.new_value); - close(fd); - return (EX_OK); - } - } - - err = parse_devstring(gargv[2], &ctl, &chip); - if (err) - return (EX_USAGE); - - else if (chip == 0xff) { - error(MSG_CTRLCHIPNEEDED); - return (EX_USAGE); - } - - if (!assert_chip_connected(ctl, chip)) - return (EX_SOFTWARE); - - if (opendev(&fd) != EX_OK) - return (EX_OSFILE); - - /* Find out which flags were passed */ - for (i = 3; i < gargc; i++) { - - if (convert_arguint(gargv[i + 1], &mods.new_value) != 0) - continue; - - if (strcmp(gargv[i], "--prog-time") == 0 || - strcmp(gargv[i], "-p") == 0) { - - mods.field = SIM_MOD_PROG_TIME; - debug("request : progtime = %d\n", mods.new_value); - - } else if (strcmp(gargv[i], "--erase-time") == 0 || - strcmp(gargv[i], "-e") == 0) { - - mods.field = SIM_MOD_ERASE_TIME; - debug("request : eraseime = %d\n", mods.new_value); - - } else if (strcmp(gargv[i], "--read-time") == 0 || - strcmp(gargv[i], "-r") == 0) { - - mods.field = SIM_MOD_READ_TIME; - debug("request : read_time = %d\n", mods.new_value); - - } else if (strcmp(gargv[i], "--error-ratio") == 0 || - strcmp(gargv[i], "-E") == 0) { - - mods.field = SIM_MOD_ERROR_RATIO; - debug("request : error_ratio = %d\n", mods.new_value); - - } else { - /* Flag not recognized, or nothing specified. */ - error("Unrecognized flag:%s\n", gargv[i]); - if (fd >= 0) - close(fd); - return (EX_USAGE); - } - - mods.chip_num = chip; - mods.ctrl_num = ctl; - - /* Call appropriate ioctl */ - err = ioctl(fd, NANDSIM_MODIFY, &mods); - if (err) { - error("simulator parameter %s could not be modified! ", - gargv[i]); - continue; - } - i++; - } - close(fd); - return (EX_OK); -} - -static int -cmderror(int gargc __unused, char **gargv) -{ - uint32_t page, column, len, pattern; - int chip = 0, ctl = 0, err = 0, fd; - struct sim_error sim_err; - - err = parse_devstring(gargv[2], &ctl, &chip); - if (err) - return (EX_USAGE); - - if (chip == 0xff) { - error(MSG_CTRLCHIPNEEDED); - return (EX_USAGE); - } - - if (convert_arguint(gargv[3], &page) || - convert_arguint(gargv[4], &column) || - convert_arguint(gargv[5], &len) || - convert_arguint(gargv[6], &pattern)) - return (EX_SOFTWARE); - - if (!assert_chip_connected(ctl, chip)) - return (EX_SOFTWARE); - - sim_err.page_num = page; - sim_err.column = column; - sim_err.len = len; - sim_err.pattern = pattern; - sim_err.ctrl_num = ctl; - sim_err.chip_num = chip; - - if (opendev(&fd) != EX_OK) - return (EX_OSFILE); - - err = ioctl(fd, NANDSIM_INJECT_ERROR, &sim_err); - - close(fd); - if (err) { - error("Could not inject error !"); - return (EX_SOFTWARE); - } - return (EX_OK); -} - -static int -cmdbb(int gargc, char **gargv) -{ - struct sim_block_state bs; - struct chip_param_io cparams; - uint32_t blkidx; - int c, cdevd, chip = 0, ctl = 0, err = 0, fd, idx; - uint8_t flagL = 0, flagU = 0; - int *badblocks = NULL; - - /* Check for --list/-L or --unmark/-U flags */ - for (idx = 3; idx < gargc; idx++) { - if (strcmp(gargv[idx], "--list") == 0 || - strcmp(gargv[idx], "-L") == 0) - flagL = idx; - if (strcmp(gargv[idx], "--unmark") == 0 || - strcmp(gargv[idx], "-U") == 0) - flagU = idx; - } - - if (flagL == 2 || flagU == 2 || flagU == 3) - return (EX_USAGE); - - err = parse_devstring(gargv[2], &ctl, &chip); - if (err) { - return (EX_USAGE); - } - if (chip == 0xff || ctl == 0xff) { - error(MSG_CTRLCHIPNEEDED); - return (EX_USAGE); - } - - bs.ctrl_num = ctl; - bs.chip_num = chip; - - if (!assert_chip_connected(ctl, chip)) - return (EX_SOFTWARE); - - if (opencdev(&cdevd, ctl, chip) != EX_OK) - return (EX_OSFILE); - - err = ioctl(cdevd, NAND_IO_GET_CHIP_PARAM, &cparams); - if (err) - return (EX_SOFTWARE); - - close(cdevd); - - bs.ctrl_num = ctl; - bs.chip_num = chip; - - if (opendev(&fd) != EX_OK) - return (EX_OSFILE); - - if (flagL != 3) { - /* - * Flag -L was specified either after blocklist or was not - * specified at all. - */ - c = parse_intarray(gargv[3], &badblocks); - - for (idx = 0; idx < c; idx++) { - bs.block_num = badblocks[idx]; - /* Do not change wearout */ - bs.wearout = -1; - bs.state = (flagU == 0) ? NANDSIM_BAD_BLOCK : - NANDSIM_GOOD_BLOCK; - - err = ioctl(fd, NANDSIM_SET_BLOCK_STATE, &bs); - if (err) { - error("Could not set bad block(%d) for " - "controller (%d)!", - badblocks[idx], ctl); - err = EX_SOFTWARE; - break; - } - } - } - if (flagL != 0) { - /* If flag -L was specified (anywhere) */ - for (blkidx = 0; blkidx < cparams.blocks; blkidx++) { - bs.block_num = blkidx; - /* Do not change the wearout */ - bs.wearout = -1; - err = ioctl(fd, NANDSIM_GET_BLOCK_STATE, &bs); - if (err) { - error("Could not acquire block state"); - err = EX_SOFTWARE; - continue; - } - printf("Block#%d: wear count: %d %s\n", blkidx, - bs.wearout, - (bs.state == NANDSIM_BAD_BLOCK) ? "BAD":"GOOD"); - } - } - close(fd); - return (err); -} - -static int -cmdfreeze(int gargc __unused, char **gargv) -{ - int chip = 0, ctl = 0, err = 0, fd, i, start = 0, state, stop = 0; - struct sim_ctrl_chip ctrlchip; - - err = parse_devstring(gargv[2], &ctl, &chip); - if (err) - return (EX_USAGE); - - if (ctl == 0xff) { - error("You have to specify at least controller number"); - return (EX_USAGE); - } - - if (ctl != 0xff && chip == 0xff) { - start = 0; - stop = MAX_CTRL_CS - 1; - } else { - start = chip; - stop = chip; - } - - ctrlchip.ctrl_num = ctl; - - err = is_ctrl_running(ctl, &state); - if (err) - return (EX_SOFTWARE); - if (state == 0) { - error(MSG_NOTRUNNING, ctl); - return (EX_SOFTWARE); - } - - if (opendev(&fd) != EX_OK) - return (EX_OSFILE); - - for (i = start; i <= stop; i++) { - err = is_chip_created(ctl, i, &state); - if (err) - return (EX_SOFTWARE); - else if (state == 0) { - continue; - } - - ctrlchip.chip_num = i; - err = ioctl(fd, NANDSIM_FREEZE, &ctrlchip); - if (err) { - error("Could not freeze ctrl#%d chip#%d", ctl, i); - close(fd); - return (EX_SOFTWARE); - } - } - close(fd); - return (EX_OK); -} - -static int -cmdlog(int gargc __unused, char **gargv) -{ - struct sim_log log; - int chip = 0, ctl = 0, err = 0, fd, idx, start = 0, stop = 0; - char *logbuf; - - err = parse_devstring(gargv[2], &ctl, &chip); - if (err) - return (EX_USAGE); - - logbuf = (char *)malloc(sizeof(char) * NANDSIM_RAM_LOG_SIZE); - if (logbuf == NULL) { - error("Not enough memory to create log buffer"); - return (EX_SOFTWARE); - } - - memset(logbuf, 0, NANDSIM_RAM_LOG_SIZE); - log.log = logbuf; - log.len = NANDSIM_RAM_LOG_SIZE; - - if (ctl == 0xff) { - start = 0; - stop = MAX_SIM_DEV-1; - } else { - start = ctl; - stop = ctl; - } - - if (opendev(&fd) != EX_OK) { - free(logbuf); - return (EX_OSFILE); - } - - /* Print logs for selected controller(s) */ - for (idx = start; idx <= stop; idx++) { - log.ctrl_num = idx; - - err = ioctl(fd, NANDSIM_PRINT_LOG, &log); - if (err) { - error("Could not get log for controller %d!", idx); - continue; - } - - printf("Logs for controller#%d:\n%s\n", idx, logbuf); - } - - free(logbuf); - close(fd); - return (EX_OK); -} - -static int -cmdstats(int gargc __unused, char **gargv) -{ - int cdevd, chip = 0, ctl = 0, err = 0; - uint32_t pageno = 0; - - err = parse_devstring(gargv[2], &ctl, &chip); - - if (err) - return (EX_USAGE); - - if (chip == 0xff) { - error(MSG_CTRLCHIPNEEDED); - return (EX_USAGE); - } - - if (convert_arguint(gargv[3], &pageno) != 0) - return (EX_USAGE); - - if (!assert_chip_connected(ctl, chip)) - return (EX_SOFTWARE); - - if (opencdev(&cdevd, ctl, chip) != EX_OK) - return (EX_OSFILE); - - err = printstats(ctl, chip, pageno, cdevd); - if (err) { - close(cdevd); - return (EX_SOFTWARE); - } - close(cdevd); - return (EX_OK); -} - -static int -cmddump(int gargc __unused, char **gargv) -{ - struct sim_dump dump; - struct sim_block_state bs; - struct chip_param_io cparams; - int chip = 0, ctl = 0, err = EX_OK, fd, dumpfd; - uint32_t blkidx, bwritten = 0, totalwritten = 0; - void *buf; - - err = parse_devstring(gargv[2], &ctl, &chip); - if (err) - return (EX_USAGE); - - if (chip == 0xff || ctl == 0xff) { - error(MSG_CTRLCHIPNEEDED); - return (EX_USAGE); - } - - if (!assert_chip_connected(ctl, chip)) - return (EX_SOFTWARE); - - if (opencdev(&fd, ctl, chip) != EX_OK) - return (EX_OSFILE); - - err = ioctl(fd, NAND_IO_GET_CHIP_PARAM, &cparams); - if (err) { - error("Cannot get parameters for chip %d:%d", ctl, chip); - close(fd); - return (EX_SOFTWARE); - } - close(fd); - - dump.ctrl_num = ctl; - dump.chip_num = chip; - - dump.len = cparams.pages_per_block * (cparams.page_size + - cparams.oob_size); - - buf = malloc(dump.len); - if (buf == NULL) { - error("Could not allocate memory!"); - return (EX_SOFTWARE); - } - dump.data = buf; - - errno = 0; - dumpfd = open(gargv[3], O_WRONLY | O_CREAT, 0666); - if (dumpfd == -1) { - error("Cannot create dump file."); - free(buf); - return (EX_SOFTWARE); - } - - if (opendev(&fd)) { - close(dumpfd); - free(buf); - return (EX_SOFTWARE); - } - - bs.ctrl_num = ctl; - bs.chip_num = chip; - - /* First uint32_t in file shall contain block count */ - if (write(dumpfd, &cparams, sizeof(cparams)) < (int)sizeof(cparams)) { - error("Error writing to dumpfile!"); - close(fd); - close(dumpfd); - free(buf); - return (EX_SOFTWARE); - } - - /* - * First loop acquires blocks states and writes them to - * the dump file. - */ - for (blkidx = 0; blkidx < cparams.blocks; blkidx++) { - bs.block_num = blkidx; - err = ioctl(fd, NANDSIM_GET_BLOCK_STATE, &bs); - if (err) { - error("Could not get bad block(%d) for " - "controller (%d)!", blkidx, ctl); - close(fd); - close(dumpfd); - free(buf); - return (EX_SOFTWARE); - } - - bwritten = write(dumpfd, &bs, sizeof(bs)); - if (bwritten != sizeof(bs)) { - error("Error writing to dumpfile"); - close(fd); - close(dumpfd); - free(buf); - return (EX_SOFTWARE); - } - } - - /* Second loop dumps the data */ - for (blkidx = 0; blkidx < cparams.blocks; blkidx++) { - debug("Block#%d...", blkidx); - dump.block_num = blkidx; - - err = ioctl(fd, NANDSIM_DUMP, &dump); - if (err) { - error("Could not dump ctrl#%d chip#%d " - "block#%d", ctl, chip, blkidx); - err = EX_SOFTWARE; - break; - } - - bwritten = write(dumpfd, dump.data, dump.len); - if (bwritten != dump.len) { - error("Error writing to dumpfile"); - err = EX_SOFTWARE; - break; - } - debug("OK!\n"); - totalwritten += bwritten; - } - printf("%d out of %d B written.\n", totalwritten, dump.len * blkidx); - - close(fd); - close(dumpfd); - free(buf); - return (err); -} - -static int -cmdrestore(int gargc __unused, char **gargv) -{ - struct sim_dump dump; - struct sim_block_state bs; - struct stat filestat; - int chip = 0, ctl = 0, err = 0, fd, dumpfd = -1; - uint32_t blkidx, blksz, fsize = 0, expfilesz; - void *buf; - struct chip_param_io cparams, dumpcparams; - - err = parse_devstring(gargv[2], &ctl, &chip); - if (err) - return (EX_USAGE); - else if (ctl == 0xff) { - error(MSG_CTRLCHIPNEEDED); - return (EX_USAGE); - } - - if (!assert_chip_connected(ctl, chip)) - return (EX_SOFTWARE); - - /* Get chip geometry */ - if (opencdev(&fd, ctl, chip) != EX_OK) - return (EX_OSFILE); - - err = ioctl(fd, NAND_IO_GET_CHIP_PARAM, &cparams); - if (err) { - error("Cannot get parameters for chip %d:%d", ctl, chip); - close(fd); - return (err); - } - close(fd); - - /* Obtain dump file size */ - errno = 0; - if (stat(gargv[3], &filestat) != 0) { - error("Could not acquire file size! : %s", - strerror(errno)); - return (EX_IOERR); - } - - fsize = filestat.st_size; - blksz = cparams.pages_per_block * (cparams.page_size + - cparams.oob_size); - - /* Expected dump file size for chip */ - expfilesz = cparams.blocks * (blksz + sizeof(bs)) + sizeof(cparams); - - if (fsize != expfilesz) { - error("File size does not match chip geometry (file size: %d" - ", dump size: %d)", fsize, expfilesz); - return (EX_SOFTWARE); - } - - dumpfd = open(gargv[3], O_RDONLY); - if (dumpfd == -1) { - error("Could not open dump file!"); - return (EX_IOERR); - } - - /* Read chip params saved in dumpfile */ - read(dumpfd, &dumpcparams, sizeof(dumpcparams)); - - /* XXX */ - if (bcmp(&dumpcparams, &cparams, sizeof(cparams)) != 0) { - error("Supplied dump is created for a chip with different " - "chip configuration!"); - close(dumpfd); - return (EX_SOFTWARE); - } - - if (opendev(&fd) != EX_OK) { - close(dumpfd); - return (EX_OSFILE); - } - - buf = malloc(blksz); - if (buf == NULL) { - error("Could not allocate memory for block buffer"); - close(dumpfd); - close(fd); - return (EX_SOFTWARE); - } - - dump.ctrl_num = ctl; - dump.chip_num = chip; - dump.data = buf; - /* Restore block states and wearouts */ - for (blkidx = 0; blkidx < cparams.blocks; blkidx++) { - dump.block_num = blkidx; - if (read(dumpfd, &bs, sizeof(bs)) != sizeof(bs)) { - error("Error reading dumpfile"); - close(dumpfd); - close(fd); - free(buf); - return (EX_SOFTWARE); - } - bs.ctrl_num = ctl; - bs.chip_num = chip; - debug("BLKIDX=%d BLOCKS=%d CTRL=%d CHIP=%d STATE=%d\n" - "WEAROUT=%d BS.CTRL_NUM=%d BS.CHIP_NUM=%d\n", - blkidx, cparams.blocks, dump.ctrl_num, dump.chip_num, - bs.state, bs.wearout, bs.ctrl_num, bs.chip_num); - - err = ioctl(fd, NANDSIM_SET_BLOCK_STATE, &bs); - if (err) { - error("Could not set bad block(%d) for " - "controller: %d, chip: %d!", blkidx, ctl, chip); - close(dumpfd); - close(fd); - free(buf); - return (EX_SOFTWARE); - } - } - /* Restore data */ - for (blkidx = 0; blkidx < cparams.blocks; blkidx++) { - errno = 0; - dump.len = read(dumpfd, buf, blksz); - if (errno) { - error("Failed to read block#%d from dumpfile.", blkidx); - err = EX_SOFTWARE; - break; - } - dump.block_num = blkidx; - err = ioctl(fd, NANDSIM_RESTORE, &dump); - if (err) { - error("Could not restore block#%d of ctrl#%d chip#%d" - ": %s", blkidx, ctl, chip, strerror(errno)); - err = EX_SOFTWARE; - break; - } - } - - free(buf); - close(dumpfd); - close(fd); - return (err); - -} - -static int -cmddestroy(int gargc __unused, char **gargv) -{ - int chip = 0, ctl = 0, err = 0, fd, idx, idx2, state; - int chipstart, chipstop, ctrlstart, ctrlstop; - struct sim_chip_destroy chip_destroy; - - err = parse_devstring(gargv[2], &ctl, &chip); - - if (err) - return (EX_USAGE); - - if (ctl == 0xff) { - /* Every chip at every controller */ - ctrlstart = chipstart = 0; - ctrlstop = MAX_SIM_DEV - 1; - chipstop = MAX_CTRL_CS - 1; - } else { - ctrlstart = ctrlstop = ctl; - if (chip == 0xff) { - /* Every chip at selected controller */ - chipstart = 0; - chipstop = MAX_CTRL_CS - 1; - } else - /* Selected chip at selected controller */ - chipstart = chipstop = chip; - } - debug("CTRLSTART=%d CTRLSTOP=%d CHIPSTART=%d CHIPSTOP=%d\n", - ctrlstart, ctrlstop, chipstart, chipstop); - for (idx = ctrlstart; idx <= ctrlstop; idx++) { - err = is_ctrl_created(idx, &state); - if (err) { - error("Could not acquire ctrl#%d state. Cannot " - "destroy controller.", idx); - return (EX_SOFTWARE); - } - if (state == 0) { - continue; - } - err = is_ctrl_running(idx, &state); - if (err) { - error(MSG_STATUSACQCTRL, idx); - return (EX_SOFTWARE); - } - if (state != 0) { - error(MSG_RUNNING, ctl); - return (EX_SOFTWARE); - } - if (opendev(&fd) != EX_OK) - return (EX_OSFILE); - - for (idx2 = chipstart; idx2 <= chipstop; idx2++) { - err = is_chip_created(idx, idx2, &state); - if (err) { - error(MSG_STATUSACQCTRLCHIP, idx2, idx); - continue; - } - if (state == 0) - /* There is no such chip running */ - continue; - chip_destroy.ctrl_num = idx; - chip_destroy.chip_num = idx2; - ioctl(fd, NANDSIM_DESTROY_CHIP, - &chip_destroy); - } - /* If chip isn't explicitly specified -- destroy ctrl */ - if (chip == 0xff) { - err = ioctl(fd, NANDSIM_DESTROY_CTRL, &idx); - if (err) { - error("Could not destroy ctrl#%d", idx); - continue; - } - } - close(fd); - } - return (err); -} - -int -main(int argc, char **argv) -{ - struct nandsim_command *cmdopts; - int retcode = 0; - - if (argc < 2) { - cmdhelp(argc, argv); - retcode = EX_USAGE; - } else { - cmdopts = getcommand(argv[1]); - if (cmdopts != NULL && cmdopts->commandfunc != NULL) { - if (checkusage(argc, cmdopts->req_argc, argv) == 1) { - /* Print command specific usage */ - printf("nandsim %s", cmdopts->usagestring); - return (EX_USAGE); - } - retcode = cmdopts->commandfunc(argc, argv); - - if (retcode == EX_USAGE) { - /* Print command-specific usage */ - printf("nandsim %s", cmdopts->usagestring); - } else if (retcode == EX_OSFILE) { - error("Could not open device file"); - } - - } else { - error("Unknown command!"); - retcode = EX_USAGE; - } - } - return (retcode); -} - -static int -cmdhelp(int gargc __unused, char **gargv __unused) -{ - struct nandsim_command *opts; - - printf("usage: nandsim [command params] [params]\n\n"); - - for (opts = commands; (opts != NULL) && - (opts->cmd_name != NULL); opts++) - printf("nandsim %s", opts->usagestring); - - printf("\n"); - return (EX_OK); -} - -static void -printchip(struct sim_chip *chip, uint8_t verbose) -{ - - if (chip->created == 0) - return; - if (verbose > 0) { - printf("\n[Chip info]\n"); - printf("num= %d\nctrl_num=%d\ndevice_id=%02x" - "\tmanufacturer_id=%02x\ndevice_model=%s\nmanufacturer=" - "%s\ncol_addr_cycles=%d\nrow_addr_cycles=%d" - "\npage_size=%d\noob_size=%d\npages_per_block=%d\n" - "blocks_per_lun=%d\nluns=%d\n\nprog_time=%d\n" - "erase_time=%d\nread_time=%d\n" - "error_ratio=%d\nwear_level=%d\nwrite_protect=%c\n" - "chip_width=%db\n", chip->num, chip->ctrl_num, - chip->device_id, chip->manufact_id,chip->device_model, - chip->manufacturer, chip->col_addr_cycles, - chip->row_addr_cycles, chip->page_size, - chip->oob_size, chip->pgs_per_blk, chip->blks_per_lun, - chip->luns,chip->prog_time, chip->erase_time, - chip->read_time, chip->error_ratio, chip->wear_level, - (chip->is_wp == 0) ? 'N':'Y', chip->width); - } else { - printf("[Chip info]\n"); - printf("\tnum=%d\n\tdevice_model=%s\n\tmanufacturer=%s\n" - "\tpage_size=%d\n\twrite_protect=%s\n", - chip->num, chip->device_model, chip->manufacturer, - chip->page_size, (chip->is_wp == 0) ? "NO":"YES"); - } -} - -static void -printctrl(struct sim_ctrl *ctrl) -{ - int i; - - if (ctrl->created == 0) { - printf(MSG_NOCTRL "\n", ctrl->num); - return; - } - printf("\n[Controller info]\n"); - printf("\trunning: %s\n", ctrl->running ? "yes" : "no"); - printf("\tnum cs: %d\n", ctrl->num_cs); - printf("\tecc: %d\n", ctrl->ecc); - printf("\tlog_filename: %s\n", ctrl->filename); - printf("\tecc_layout:"); - for (i = 0; i < MAX_ECC_BYTES; i++) { - if (ctrl->ecc_layout[i] == 0xffff) - break; - else - printf("%c%d", i%16 ? ' ' : '\n', - ctrl->ecc_layout[i]); - } - printf("\n"); -} - -static int -is_ctrl_running(int ctrl_no, int *running) -{ - struct sim_ctrl ctrl; - int err, fd; - - ctrl.num = ctrl_no; - if (opendev(&fd) != EX_OK) - return (EX_OSFILE); - - err = ioctl(fd, NANDSIM_STATUS_CTRL, &ctrl); - if (err) { - error(MSG_STATUSACQCTRL, ctrl_no); - close(fd); - return (err); - } - *running = ctrl.running; - close(fd); - return (0); -} - -static int -is_ctrl_created(int ctrl_no, int *created) -{ - struct sim_ctrl ctrl; - int err, fd; - - ctrl.num = ctrl_no; - - if (opendev(&fd) != EX_OK) - return (EX_OSFILE); - - err = ioctl(fd, NANDSIM_STATUS_CTRL, &ctrl); - if (err) { - error("Could not acquire conf for ctrl#%d", ctrl_no); - close(fd); - return (err); - } - *created = ctrl.created; - close(fd); - return (0); -} - -static int -is_chip_created(int ctrl_no, int chip_no, int *created) -{ - struct sim_chip chip; - int err, fd; - - chip.ctrl_num = ctrl_no; - chip.num = chip_no; - - if (opendev(&fd) != EX_OK) - return (EX_OSFILE); - - err = ioctl(fd, NANDSIM_STATUS_CHIP, &chip); - if (err) { - error("Could not acquire conf for chip#%d", chip_no); - close(fd); - return (err); - } - *created = chip.created; - close(fd); - return (0); -} - -static int -assert_chip_connected(int ctrl_no, int chip_no) -{ - int created, running; - - if (is_ctrl_created(ctrl_no, &created)) - return (0); - - if (!created) { - error(MSG_NOCTRL, ctrl_no); - return (0); - } - - if (is_chip_created(ctrl_no, chip_no, &created)) - return (0); - - if (!created) { - error(MSG_NOTCONFIGDCTRLCHIP, ctrl_no, chip_no); - return (0); - } - - if (is_ctrl_running(ctrl_no, &running)) - return (0); - - if (!running) { - error(MSG_NOTRUNNING, ctrl_no); - return (0); - } - - return (1); -} - -static int -printstats(int ctrlno, int chipno, uint32_t pageno, int cdevd) -{ - struct page_stat_io pstats; - struct block_stat_io bstats; - struct chip_param_io cparams; - uint32_t blkidx; - int err; - - /* Gather information about chip */ - err = ioctl(cdevd, NAND_IO_GET_CHIP_PARAM, &cparams); - - if (err) { - error("Could not acquire chip info for chip attached to cs#" - "%d, ctrl#%d", chipno, ctrlno); - return (EX_SOFTWARE); - } - - blkidx = (pageno / cparams.pages_per_block); - bstats.block_num = blkidx; - - err = ioctl(cdevd, NAND_IO_BLOCK_STAT, &bstats); - if (err) { - error("Could not acquire block#%d statistics!", blkidx); - return (ENXIO); - } - - printf("Block #%d erased: %d\n", blkidx, bstats.block_erased); - pstats.page_num = pageno; - - err = ioctl(cdevd, NAND_IO_PAGE_STAT, &pstats); - if (err) { - error("Could not acquire page statistics!"); - return (ENXIO); - } - - debug("BLOCKIDX = %d PAGENO (REL. TO BLK) = %d\n", blkidx, - pstats.page_num); - - printf("Page#%d : reads:%d writes:%d \n\traw reads:%d raw writes:%d " - "\n\tecc_succeeded:%d ecc_corrected:%d ecc_failed:%d\n", - pstats.page_num, pstats.page_read, pstats.page_written, - pstats.page_raw_read, pstats.page_raw_written, - pstats.ecc_succeded, pstats.ecc_corrected, pstats.ecc_failed); - return (0); -} diff --git a/usr.sbin/nandsim/nandsim_cfgparse.c b/usr.sbin/nandsim/nandsim_cfgparse.c deleted file mode 100644 index 4a310fb58a0f..000000000000 --- a/usr.sbin/nandsim/nandsim_cfgparse.c +++ /dev/null @@ -1,961 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * 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, 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 AND CONTRIBUTORS ``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 AUTHOR OR CONTRIBUTORS 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 -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "nandsim_cfgparse.h" - -#define warn(fmt, args...) do { \ - printf("WARNING: " fmt "\n", ##args); } while (0) - -#define error(fmt, args...) do { \ - printf("ERROR: " fmt "\n", ##args); } while (0) - -#define MSG_MANDATORYKEYMISSING "mandatory key \"%s\" value belonging to " \ - "section \"%s\" is missing!\n" - -#define DEBUG -#undef DEBUG - -#ifdef DEBUG -#define debug(fmt, args...) do { \ - printf("NANDSIM_CONF:" fmt "\n", ##args); } while (0) -#else -#define debug(fmt, args...) do {} while(0) -#endif - -#define STRBUFSIZ 2000 - -/* Macros extracts type and type size */ -#define TYPE(x) ((x) & 0xf8) -#define SIZE(x) (((x) & 0x07)) - -/* Erase/Prog/Read time max and min values */ -#define DELAYTIME_MIN 10000 -#define DELAYTIME_MAX 10000000 - -/* Structure holding configuration for controller. */ -static struct sim_ctrl ctrl_conf; -/* Structure holding configuration for chip. */ -static struct sim_chip chip_conf; - -static struct nandsim_key nandsim_ctrl_keys[] = { - {"num_cs", 1, VALUE_UINT | SIZE_8, (void *)&ctrl_conf.num_cs, 0}, - {"ctrl_num", 1, VALUE_UINT | SIZE_8, (void *)&ctrl_conf.num, 0}, - - {"ecc_layout", 1, VALUE_UINTARRAY | SIZE_16, - (void *)&ctrl_conf.ecc_layout, MAX_ECC_BYTES}, - - {"filename", 0, VALUE_STRING, - (void *)&ctrl_conf.filename, FILENAME_SIZE}, - - {"ecc", 0, VALUE_BOOL, (void *)&ctrl_conf.ecc, 0}, - {NULL, 0, 0, NULL, 0}, -}; - -static struct nandsim_key nandsim_chip_keys[] = { - {"chip_cs", 1, VALUE_UINT | SIZE_8, (void *)&chip_conf.num, 0}, - {"chip_ctrl", 1, VALUE_UINT | SIZE_8, (void *)&chip_conf.ctrl_num, - 0}, - {"device_id", 1, VALUE_UINT | SIZE_8, (void *)&chip_conf.device_id, - 0}, - {"manufacturer_id", 1, VALUE_UINT | SIZE_8, - (void *)&chip_conf.manufact_id, 0}, - {"model", 0, VALUE_STRING, (void *)&chip_conf.device_model, - DEV_MODEL_STR_SIZE}, - {"manufacturer", 0, VALUE_STRING, (void *)&chip_conf.manufacturer, - MAN_STR_SIZE}, - {"page_size", 1, VALUE_UINT | SIZE_32, (void *)&chip_conf.page_size, - 0}, - {"oob_size", 1, VALUE_UINT | SIZE_32, (void *)&chip_conf.oob_size, - 0}, - {"pages_per_block", 1, VALUE_UINT | SIZE_32, - (void *)&chip_conf.pgs_per_blk, 0}, - {"blocks_per_lun", 1, VALUE_UINT | SIZE_32, - (void *)&chip_conf.blks_per_lun, 0}, - {"luns", 1, VALUE_UINT | SIZE_32, (void *)&chip_conf.luns, 0}, - {"column_addr_cycle", 1,VALUE_UINT | SIZE_8, - (void *)&chip_conf.col_addr_cycles, 0}, - {"row_addr_cycle", 1, VALUE_UINT | SIZE_8, - (void *)&chip_conf.row_addr_cycles, 0}, - {"program_time", 0, VALUE_UINT | SIZE_32, - (void *)&chip_conf.prog_time, 0}, - {"erase_time", 0, VALUE_UINT | SIZE_32, - (void *)&chip_conf.erase_time, 0}, - {"read_time", 0, VALUE_UINT | SIZE_32, - (void *)&chip_conf.read_time, 0}, - {"width", 1, VALUE_UINT | SIZE_8, (void *)&chip_conf.width, 0}, - {"wear_out", 1, VALUE_UINT | SIZE_32, (void *)&chip_conf.wear_level, - 0}, - {"bad_block_map", 0, VALUE_UINTARRAY | SIZE_32, - (void *)&chip_conf.bad_block_map, MAX_BAD_BLOCKS}, - {NULL, 0, 0, NULL, 0}, -}; - -static struct nandsim_section sections[] = { - {"ctrl", (struct nandsim_key *)&nandsim_ctrl_keys}, - {"chip", (struct nandsim_key *)&nandsim_chip_keys}, - {NULL, NULL}, -}; - -static uint8_t logoutputtoint(char *, int *); -static uint8_t validate_chips(struct sim_chip *, int, struct sim_ctrl *, int); -static uint8_t validate_ctrls(struct sim_ctrl *, int); -static int configure_sim(const char *, struct rcfile *); -static int create_ctrls(struct rcfile *, struct sim_ctrl **, int *); -static int create_chips(struct rcfile *, struct sim_chip **, int *); -static void destroy_ctrls(struct sim_ctrl *); -static void destroy_chips(struct sim_chip *); -static int validate_section_config(struct rcfile *, const char *, int); - -int -convert_argint(char *arg, int *value) -{ - - if (arg == NULL || value == NULL) - return (EINVAL); - - errno = 0; - *value = (int)strtol(arg, NULL, 0); - if (*value == 0 && errno != 0) { - error("Cannot convert to number argument \'%s\'", arg); - return (EINVAL); - } - return (0); -} - -int -convert_arguint(char *arg, unsigned int *value) -{ - - if (arg == NULL || value == NULL) - return (EINVAL); - - errno = 0; - *value = (unsigned int)strtol(arg, NULL, 0); - if (*value == 0 && errno != 0) { - error("Cannot convert to number argument \'%s\'", arg); - return (EINVAL); - } - return (0); -} - -/* Parse given ',' separated list of bytes into buffer. */ -int -parse_intarray(char *array, int **buffer) -{ - char *tmp, *tmpstr, *origstr; - unsigned int currbufp = 0, i; - unsigned int count = 0, from = 0, to = 0; - - /* Remove square braces */ - if (array[0] == '[') - array ++; - if (array[strlen(array)-1] == ']') - array[strlen(array)-1] = ','; - - from = strlen(array); - origstr = (char *)malloc(sizeof(char) * from); - strcpy(origstr, array); - - tmpstr = (char *)strtok(array, ","); - /* First loop checks for how big int array we need to allocate */ - while (tmpstr != NULL) { - errno = 0; - if ((tmp = strchr(tmpstr, '-')) != NULL) { - *tmp = ' '; - if (convert_arguint(tmpstr, &from) || - convert_arguint(tmp, &to)) { - free(origstr); - return (EINVAL); - } - - count += to - from + 1; - } else { - if (convert_arguint(tmpstr, &from)) { - free(origstr); - return (EINVAL); - } - count++; - } - tmpstr = (char *)strtok(NULL, ","); - } - - if (count == 0) - goto out; - - /* Allocate buffer of ints */ - tmpstr = (char *)strtok(origstr, ","); - *buffer = malloc(count * sizeof(int)); - - /* Second loop is just inserting converted values into int array */ - while (tmpstr != NULL) { - errno = 0; - if ((tmp = strchr(tmpstr, '-')) != NULL) { - *tmp = ' '; - from = strtol(tmpstr, NULL, 0); - to = strtol(tmp, NULL, 0); - tmpstr = strtok(NULL, ","); - for (i = from; i <= to; i ++) - (*buffer)[currbufp++] = i; - continue; - } - errno = 0; - from = (int)strtol(tmpstr, NULL, 0); - (*buffer)[currbufp++] = from; - tmpstr = (char *)strtok(NULL, ","); - } -out: - free(origstr); - return (count); -} - -/* Convert logoutput strings literals into appropriate ints. */ -static uint8_t -logoutputtoint(char *logoutput, int *output) -{ - int out; - - if (strcmp(logoutput, "file") == 0) - out = NANDSIM_OUTPUT_FILE; - - else if (strcmp(logoutput, "console") == 0) - out = NANDSIM_OUTPUT_CONSOLE; - - else if (strcmp(logoutput, "ram") == 0) - out = NANDSIM_OUTPUT_RAM; - - else if (strcmp(logoutput, "none") == 0) - out = NANDSIM_OUTPUT_NONE; - else - out = -1; - - *output = out; - - if (out == -1) - return (EINVAL); - else - return (0); -} - -static int -configure_sim(const char *devfname, struct rcfile *f) -{ - struct sim_param sim_conf; - char buf[255]; - int err, tmpv, fd; - - err = rc_getint(f, "sim", 0, "log_level", &tmpv); - - if (tmpv < 0 || tmpv > 255 || err) { - error("Bad log level specified (%d)\n", tmpv); - return (ENOTSUP); - } else - sim_conf.log_level = tmpv; - - rc_getstring(f, "sim", 0, "log_output", 255, (char *)&buf); - - tmpv = -1; - err = logoutputtoint((char *)&buf, &tmpv); - if (err) { - error("Log output specified in config file does not seem to " - "be valid (%s)!", (char *)&buf); - return (ENOTSUP); - } - - sim_conf.log_output = tmpv; - - fd = open(devfname, O_RDWR); - if (fd == -1) { - error("could not open simulator device file (%s)!", - devfname); - return (EX_OSFILE); - } - - err = ioctl(fd, NANDSIM_SIM_PARAM, &sim_conf); - if (err) { - error("simulator parameters could not be modified: %s", - strerror(errno)); - close(fd); - return (ENXIO); - } - - close(fd); - return (EX_OK); -} - -static int -create_ctrls(struct rcfile *f, struct sim_ctrl **ctrls, int *cnt) -{ - int count, i; - struct sim_ctrl *ctrlsptr; - - count = rc_getsectionscount(f, "ctrl"); - if (count > MAX_SIM_DEV) { - error("Too many CTRL sections specified(%d)", count); - return (ENOTSUP); - } else if (count == 0) { - error("No ctrl sections specified"); - return (ENOENT); - } - - ctrlsptr = (struct sim_ctrl *)malloc(sizeof(struct sim_ctrl) * count); - if (ctrlsptr == NULL) { - error("Could not allocate memory for ctrl configuration"); - return (ENOMEM); - } - - for (i = 0; i < count; i++) { - bzero((void *)&ctrl_conf, sizeof(ctrl_conf)); - - /* - * ECC layout have to end up with 0xffff, so - * we're filling buffer with 0xff. If ecc_layout is - * defined in config file, values will be overridden. - */ - memset((void *)&ctrl_conf.ecc_layout, 0xff, - sizeof(ctrl_conf.ecc_layout)); - - if (validate_section_config(f, "ctrl", i) != 0) { - free(ctrlsptr); - return (EINVAL); - } - - if (parse_section(f, "ctrl", i) != 0) { - free(ctrlsptr); - return (EINVAL); - } - - memcpy(&ctrlsptr[i], &ctrl_conf, sizeof(ctrl_conf)); - /* Try to create ctrl with config parsed */ - debug("NUM=%d\nNUM_CS=%d\nECC=%d\nFILENAME=%s\nECC_LAYOUT[0]" - "=%d\nECC_LAYOUT[1]=%d\n\n", - ctrlsptr[i].num, ctrlsptr[i].num_cs, ctrlsptr[i].ecc, - ctrlsptr[i].filename, ctrlsptr[i].ecc_layout[0], - ctrlsptr[i].ecc_layout[1]); - } - *cnt = count; - *ctrls = ctrlsptr; - return (0); -} - -static void -destroy_ctrls(struct sim_ctrl *ctrls) -{ - - free(ctrls); -} - -static int -create_chips(struct rcfile *f, struct sim_chip **chips, int *cnt) -{ - struct sim_chip *chipsptr; - int count, i; - - count = rc_getsectionscount(f, "chip"); - if (count > (MAX_CTRL_CS * MAX_SIM_DEV)) { - error("Too many chip sections specified(%d)", count); - return (ENOTSUP); - } else if (count == 0) { - error("No chip sections specified"); - return (ENOENT); - } - - chipsptr = (struct sim_chip *)malloc(sizeof(struct sim_chip) * count); - if (chipsptr == NULL) { - error("Could not allocate memory for chip configuration"); - return (ENOMEM); - } - - for (i = 0; i < count; i++) { - bzero((void *)&chip_conf, sizeof(chip_conf)); - - /* - * Bad block map have to end up with 0xffff, so - * we're filling array with 0xff. If bad block map is - * defined in config file, values will be overridden. - */ - memset((void *)&chip_conf.bad_block_map, 0xff, - sizeof(chip_conf.bad_block_map)); - - if (validate_section_config(f, "chip", i) != 0) { - free(chipsptr); - return (EINVAL); - } - - if (parse_section(f, "chip", i) != 0) { - free(chipsptr); - return (EINVAL); - } - - memcpy(&chipsptr[i], &chip_conf, sizeof(chip_conf)); - - /* Try to create chip with config parsed */ - debug("CHIP:\nNUM=%d\nCTRL_NUM=%d\nDEVID=%d\nMANID=%d\n" - "PAGE_SZ=%d\nOOBSZ=%d\nREAD_T=%d\nDEVMODEL=%s\n" - "MAN=%s\nCOLADDRCYCLES=%d\nROWADDRCYCLES=%d\nCHWIDTH=%d\n" - "PGS/BLK=%d\nBLK/LUN=%d\nLUNS=%d\nERR_RATIO=%d\n" - "WEARLEVEL=%d\nISWP=%d\n\n\n\n", - chipsptr[i].num, chipsptr[i].ctrl_num, - chipsptr[i].device_id, chipsptr[i].manufact_id, - chipsptr[i].page_size, chipsptr[i].oob_size, - chipsptr[i].read_time, chipsptr[i].device_model, - chipsptr[i].manufacturer, chipsptr[i].col_addr_cycles, - chipsptr[i].row_addr_cycles, chipsptr[i].width, - chipsptr[i].pgs_per_blk, chipsptr[i].blks_per_lun, - chipsptr[i].luns, chipsptr[i].error_ratio, - chipsptr[i].wear_level, chipsptr[i].is_wp); - } - *cnt = count; - *chips = chipsptr; - return (0); -} - -static void -destroy_chips(struct sim_chip *chips) -{ - - free(chips); -} - -int -parse_config(char *cfgfname, const char *devfname) -{ - int err = 0, fd; - unsigned int chipsectionscnt, ctrlsectionscnt, i; - struct rcfile *f; - struct sim_chip *chips; - struct sim_ctrl *ctrls; - - err = rc_open(cfgfname, "r", &f); - if (err) { - error("could not open configuration file (%s)", cfgfname); - return (EX_NOINPUT); - } - - /* First, try to configure simulator itself. */ - if (configure_sim(devfname, f) != EX_OK) { - rc_close(f); - return (EINVAL); - } - - debug("SIM CONFIGURED!\n"); - /* Then create controllers' configs */ - if (create_ctrls(f, &ctrls, &ctrlsectionscnt) != 0) { - rc_close(f); - return (ENXIO); - } - debug("CTRLS CONFIG READ!\n"); - - /* Then create chips' configs */ - if (create_chips(f, &chips, &chipsectionscnt) != 0) { - destroy_ctrls(ctrls); - rc_close(f); - return (ENXIO); - } - debug("CHIPS CONFIG READ!\n"); - - if (validate_ctrls(ctrls, ctrlsectionscnt) != 0) { - destroy_ctrls(ctrls); - destroy_chips(chips); - rc_close(f); - return (EX_SOFTWARE); - } - if (validate_chips(chips, chipsectionscnt, ctrls, - ctrlsectionscnt) != 0) { - destroy_ctrls(ctrls); - destroy_chips(chips); - rc_close(f); - return (EX_SOFTWARE); - } - - /* Open device */ - fd = open(devfname, O_RDWR); - if (fd == -1) { - error("could not open simulator device file (%s)!", - devfname); - rc_close(f); - destroy_chips(chips); - destroy_ctrls(ctrls); - return (EX_OSFILE); - } - - debug("SIM CONFIG STARTED!\n"); - - /* At this stage, both ctrls' and chips' configs should be valid */ - for (i = 0; i < ctrlsectionscnt; i++) { - err = ioctl(fd, NANDSIM_CREATE_CTRL, &ctrls[i]); - if (err) { - if (err == EEXIST) - error("Controller#%d already created\n", - ctrls[i].num); - else if (err == EINVAL) - error("Incorrect controller number (%d)\n", - ctrls[i].num); - else - error("Could not created controller#%d\n", - ctrls[i].num); - /* Errors during controller creation stops parsing */ - close(fd); - rc_close(f); - destroy_ctrls(ctrls); - destroy_chips(chips); - return (ENXIO); - } - debug("CTRL#%d CONFIG STARTED!\n", i); - } - - for (i = 0; i < chipsectionscnt; i++) { - err = ioctl(fd, NANDSIM_CREATE_CHIP, &chips[i]); - if (err) { - if (err == EEXIST) - error("Chip#%d for controller#%d already " - "created\n", chips[i].num, - chips[i].ctrl_num); - else if (err == EINVAL) - error("Incorrect chip number (%d:%d)\n", - chips[i].num, chips[i].ctrl_num); - else - error("Could not create chip (%d:%d)\n", - chips[i].num, chips[i].ctrl_num); - error("Could not start chip#%d\n", i); - destroy_chips(chips); - destroy_ctrls(ctrls); - close(fd); - rc_close(f); - return (ENXIO); - } - } - debug("CHIPS CONFIG STARTED!\n"); - - close(fd); - rc_close(f); - destroy_chips(chips); - destroy_ctrls(ctrls); - return (0); -} - -/* - * Function tries to get appropriate value for given key, convert it to - * array of ints (of given size), and perform all the necessary checks and - * conversions. - */ -static int -get_argument_intarray(const char *sect_name, int sectno, - struct nandsim_key *key, struct rcfile *f) -{ - char strbuf[STRBUFSIZ]; - int *intbuf; - int getres; - uint32_t cnt, i = 0; - - getres = rc_getstring(f, sect_name, sectno, key->keyname, STRBUFSIZ, - (char *)&strbuf); - - if (getres != 0) { - if (key->mandatory != 0) { - error(MSG_MANDATORYKEYMISSING, key->keyname, - sect_name); - return (EINVAL); - } else - /* Non-mandatory key, not present -- skip */ - return (0); - } - cnt = parse_intarray((char *)&strbuf, &intbuf); - cnt = (cnt <= key->maxlength) ? cnt : key->maxlength; - - for (i = 0; i < cnt; i++) { - if (SIZE(key->valuetype) == SIZE_8) - *((uint8_t *)(key->field) + i) = - (uint8_t)intbuf[i]; - else if (SIZE(key->valuetype) == SIZE_16) - *((uint16_t *)(key->field) + i) = - (uint16_t)intbuf[i]; - else - *((uint32_t *)(key->field) + i) = - (uint32_t)intbuf[i]; - } - free(intbuf); - return (0); -} - -/* - * Function tries to get appropriate value for given key, convert it to - * int of certain length. - */ -static int -get_argument_int(const char *sect_name, int sectno, struct nandsim_key *key, - struct rcfile *f) -{ - int getres; - uint32_t val; - - getres = rc_getint(f, sect_name, sectno, key->keyname, &val); - if (getres != 0) { - - if (key->mandatory != 0) { - error(MSG_MANDATORYKEYMISSING, key->keyname, - sect_name); - - return (EINVAL); - } else - /* Non-mandatory key, not present -- skip */ - return (0); - } - if (SIZE(key->valuetype) == SIZE_8) - *(uint8_t *)(key->field) = (uint8_t)val; - else if (SIZE(key->valuetype) == SIZE_16) - *(uint16_t *)(key->field) = (uint16_t)val; - else - *(uint32_t *)(key->field) = (uint32_t)val; - return (0); -} - -/* Function tries to get string value for given key */ -static int -get_argument_string(const char *sect_name, int sectno, - struct nandsim_key *key, struct rcfile *f) -{ - char strbuf[STRBUFSIZ]; - int getres; - - getres = rc_getstring(f, sect_name, sectno, key->keyname, STRBUFSIZ, - strbuf); - - if (getres != 0) { - if (key->mandatory != 0) { - error(MSG_MANDATORYKEYMISSING, key->keyname, - sect_name); - return (1); - } else - /* Non-mandatory key, not present -- skip */ - return (0); - } - strncpy(key->field, (char *)&strbuf, (size_t)(key->maxlength - 1)); - return (0); -} - -/* Function tries to get on/off value for given key */ -static int -get_argument_bool(const char *sect_name, int sectno, struct nandsim_key *key, - struct rcfile *f) -{ - int getres, val; - - getres = rc_getbool(f, sect_name, sectno, key->keyname, &val); - if (getres != 0) { - if (key->mandatory != 0) { - error(MSG_MANDATORYKEYMISSING, key->keyname, - sect_name); - return (1); - } else - /* Non-mandatory key, not present -- skip */ - return (0); - } - *(uint8_t *)key->field = (uint8_t)val; - return (0); -} - -int -parse_section(struct rcfile *f, const char *sect_name, int sectno) -{ - struct nandsim_key *key; - struct nandsim_section *sect = (struct nandsim_section *)§ions; - int getres = 0; - - while (1) { - if (sect == NULL) - return (EINVAL); - - if (strcmp(sect->name, sect_name) == 0) - break; - else - sect++; - } - key = sect->keys; - do { - debug("->Section: %s, Key: %s, type: %d, size: %d", - sect_name, key->keyname, TYPE(key->valuetype), - SIZE(key->valuetype)/2); - - switch (TYPE(key->valuetype)) { - case VALUE_UINT: - /* Single int value */ - getres = get_argument_int(sect_name, sectno, key, f); - - if (getres != 0) - return (getres); - - break; - case VALUE_UINTARRAY: - /* Array of ints */ - getres = get_argument_intarray(sect_name, - sectno, key, f); - - if (getres != 0) - return (getres); - - break; - case VALUE_STRING: - /* Array of chars */ - getres = get_argument_string(sect_name, sectno, key, - f); - - if (getres != 0) - return (getres); - - break; - case VALUE_BOOL: - /* Boolean value (true/false/on/off/yes/no) */ - getres = get_argument_bool(sect_name, sectno, key, - f); - - if (getres != 0) - return (getres); - - break; - } - } while ((++key)->keyname != NULL); - - return (0); -} - -static uint8_t -validate_chips(struct sim_chip *chips, int chipcnt, - struct sim_ctrl *ctrls, int ctrlcnt) -{ - int cchipcnt, i, width, j, id, max; - - cchipcnt = chipcnt; - for (chipcnt -= 1; chipcnt >= 0; chipcnt--) { - if (chips[chipcnt].num >= MAX_CTRL_CS) { - error("chip no. too high (%d)!!\n", - chips[chipcnt].num); - return (EINVAL); - } - - if (chips[chipcnt].ctrl_num >= MAX_SIM_DEV) { - error("controller no. too high (%d)!!\n", - chips[chipcnt].ctrl_num); - return (EINVAL); - } - - if (chips[chipcnt].width != 8 && - chips[chipcnt].width != 16) { - error("invalid width:%d for chip#%d", - chips[chipcnt].width, chips[chipcnt].num); - return (EINVAL); - } - - /* Check if page size is > 512 and if its power of 2 */ - if (chips[chipcnt].page_size < 512 || - (chips[chipcnt].page_size & - (chips[chipcnt].page_size - 1)) != 0) { - error("invalid page size:%d for chip#%d at ctrl#%d!!" - "\n", chips[chipcnt].page_size, - chips[chipcnt].num, - chips[chipcnt].ctrl_num); - return (EINVAL); - } - - /* Check if controller no. ctrl_num is configured */ - for (i = 0, id = -1; i < ctrlcnt && id == -1; i++) - if (ctrls[i].num == chips[chipcnt].ctrl_num) - id = i; - - if (i == ctrlcnt && id == -1) { - error("Missing configuration for controller %d" - " (at least one chip is connected to it)", - chips[chipcnt].ctrl_num); - return (EINVAL); - } else { - /* - * Controller is configured -> check oob_size - * validity - */ - i = 0; - max = ctrls[id].ecc_layout[0]; - while (i < MAX_ECC_BYTES && - ctrls[id].ecc_layout[i] != 0xffff) { - - if (ctrls[id].ecc_layout[i] > max) - max = ctrls[id].ecc_layout[i]; - i++; - } - - if (chips[chipcnt].oob_size < (unsigned)i) { - error("OOB size for chip#%d at ctrl#%d is " - "smaller than ecc layout length!", - chips[chipcnt].num, - chips[chipcnt].ctrl_num); - exit(EINVAL); - } - - if (chips[chipcnt].oob_size < (unsigned)max) { - error("OOB size for chip#%d at ctrl#%d is " - "smaller than maximal ecc position in " - "defined layout!", chips[chipcnt].num, - chips[chipcnt].ctrl_num); - exit(EINVAL); - } - - - } - - if ((chips[chipcnt].erase_time < DELAYTIME_MIN || - chips[chipcnt].erase_time > DELAYTIME_MAX) && - chips[chipcnt].erase_time != 0) { - error("Invalid erase time value for chip#%d at " - "ctrl#%d", - chips[chipcnt].num, - chips[chipcnt].ctrl_num); - return (EINVAL); - } - - if ((chips[chipcnt].prog_time < DELAYTIME_MIN || - chips[chipcnt].prog_time > DELAYTIME_MAX) && - chips[chipcnt].prog_time != 0) { - error("Invalid prog time value for chip#%d at " - "ctr#%d!", - chips[chipcnt].num, - chips[chipcnt].ctrl_num); - return (EINVAL); - } - - if ((chips[chipcnt].read_time < DELAYTIME_MIN || - chips[chipcnt].read_time > DELAYTIME_MAX) && - chips[chipcnt].read_time != 0) { - error("Invalid read time value for chip#%d at " - "ctrl#%d!", - chips[chipcnt].num, - chips[chipcnt].ctrl_num); - return (EINVAL); - } - } - /* Check if chips attached to the same controller, have same width */ - for (i = 0; i < ctrlcnt; i++) { - width = -1; - for (j = 0; j < cchipcnt; j++) { - if (chips[j].ctrl_num == i) { - if (width == -1) { - width = chips[j].width; - } else { - if (width != chips[j].width) { - error("Chips attached to " - "ctrl#%d have different " - "widths!\n", i); - return (EINVAL); - } - } - } - } - } - - return (0); -} - -static uint8_t -validate_ctrls(struct sim_ctrl *ctrl, int ctrlcnt) -{ - for (ctrlcnt -= 1; ctrlcnt >= 0; ctrlcnt--) { - if (ctrl[ctrlcnt].num > MAX_SIM_DEV) { - error("Controller no. too high (%d)!!\n", - ctrl[ctrlcnt].num); - return (EINVAL); - } - if (ctrl[ctrlcnt].num_cs > MAX_CTRL_CS) { - error("Too many CS (%d)!!\n", ctrl[ctrlcnt].num_cs); - return (EINVAL); - } - if (ctrl[ctrlcnt].ecc != 0 && ctrl[ctrlcnt].ecc != 1) { - error("ECC is set to neither 0 nor 1 !\n"); - return (EINVAL); - } - } - - return (0); -} - -static int validate_section_config(struct rcfile *f, const char *sect_name, - int sectno) -{ - struct nandsim_key *key; - struct nandsim_section *sect; - char **keys_tbl; - int i, match; - - for (match = 0, sect = (struct nandsim_section *)§ions; - sect != NULL; sect++) { - if (strcmp(sect->name, sect_name) == 0) { - match = 1; - break; - } - } - - if (match == 0) - return (EINVAL); - - keys_tbl = rc_getkeys(f, sect_name, sectno); - if (keys_tbl == NULL) - return (ENOMEM); - - for (i = 0; keys_tbl[i] != NULL; i++) { - key = sect->keys; - match = 0; - do { - if (strcmp(keys_tbl[i], key->keyname) == 0) { - match = 1; - break; - } - } while ((++key)->keyname != NULL); - - if (match == 0) { - error("Invalid key in config file: %s\n", keys_tbl[i]); - free(keys_tbl); - return (EINVAL); - } - } - - free(keys_tbl); - return (0); -} diff --git a/usr.sbin/nandsim/nandsim_cfgparse.h b/usr.sbin/nandsim/nandsim_cfgparse.h deleted file mode 100644 index 12365666ad93..000000000000 --- a/usr.sbin/nandsim/nandsim_cfgparse.h +++ /dev/null @@ -1,88 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * 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, 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 AND CONTRIBUTORS ``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 AUTHOR OR CONTRIBUTORS 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$ - */ - -#ifndef _NANDSIM_CONFPARSER_H_ -#define _NANDSIM_CONFPARSER_H_ - -#define VALUE_UINT 0x08 -#define VALUE_INT 0x10 -#define VALUE_UINTARRAY 0x18 -#define VALUE_INTARRAY 0x20 -#define VALUE_STRING 0x28 -#define VALUE_CHAR 0x40 -#define VALUE_BOOL 0x48 - -#define SIZE_8 0x01 -#define SIZE_16 0x02 -#define SIZE_32 0x04 - -#include "nandsim_rcfile.h" - -/* - * keyname = name of a key, - * mandatory = is key mandatory in section belonging to, 0=false 1=true - * valuetype = what kind of value is assigned to that key, e.g. - * VALUE_UINT | SIZE_8 -- unsigned uint size 8 bits; - * VALUE_UINTARRAY | SIZE_8 -- array of uints 8-bit long; - * VALUE_BOOL -- 'on', 'off','true','false','yes' or 'no' - * literals; - * VALUE_STRING -- strings - * field = ptr to the field that should hold value for parsed value - * maxlength = contains maximum length of an array (used only with either - * VALUE_STRING or VALUE_(U)INTARRAY value types. - */ -struct nandsim_key { - const char *keyname; - uint8_t mandatory; - uint8_t valuetype; - void *field; - uint32_t maxlength; -}; -struct nandsim_section { - const char *name; - struct nandsim_key *keys; -}; - -struct nandsim_config { - struct sim_param **simparams; - struct sim_chip **simchips; - struct sim_ctrl **simctrls; - int chipcnt; - int ctrlcnt; -}; - -int parse_intarray(char *, int **); -int parse_config(char *, const char *); -int parse_section(struct rcfile *, const char *, int); -int compare_configs(struct nandsim_config *, struct nandsim_config *); -int convert_argint(char *, int *); -int convert_arguint(char *, unsigned int *); - -#endif /* _NANDSIM_CONFPARSER_H_ */ diff --git a/usr.sbin/nandsim/nandsim_rcfile.c b/usr.sbin/nandsim/nandsim_rcfile.c deleted file mode 100644 index 8e9cca17f37b..000000000000 --- a/usr.sbin/nandsim/nandsim_rcfile.c +++ /dev/null @@ -1,442 +0,0 @@ -/* - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 1999, Boris Popov - * 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, 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. - * 3. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. - * - * from: FreeBSD: src/lib/libncp/ncpl_rcfile.c,v 1.5 2007/01/09 23:27:39 imp Exp - */ - -#include -__FBSDID("$FreeBSD$"); -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "nandsim_rcfile.h" - -SLIST_HEAD(rcfile_head, rcfile); -static struct rcfile_head pf_head = {NULL}; -static struct rcsection *rc_findsect(struct rcfile *rcp, - const char *sectname, int sect_id); -static struct rcsection *rc_addsect(struct rcfile *rcp, - const char *sectname); -static int rc_sect_free(struct rcsection *rsp); -static struct rckey *rc_sect_findkey(struct rcsection *rsp, - const char *keyname); -static struct rckey *rc_sect_addkey(struct rcsection *rsp, const char *name, - char *value); -static void rc_key_free(struct rckey *p); -static void rc_parse(struct rcfile *rcp); - -static struct rcfile* rc_find(const char *filename); - -/* - * open rcfile and load its content, if already open - return previous handle - */ -int -rc_open(const char *filename, const char *mode,struct rcfile **rcfile) -{ - struct rcfile *rcp; - FILE *f; - rcp = rc_find(filename); - if (rcp) { - *rcfile = rcp; - return (0); - } - f = fopen (filename, mode); - if (f == NULL) - return errno; - rcp = malloc(sizeof(struct rcfile)); - if (rcp == NULL) { - fclose(f); - return ENOMEM; - } - bzero(rcp, sizeof(struct rcfile)); - rcp->rf_name = strdup(filename); - rcp->rf_f = f; - SLIST_INSERT_HEAD(&pf_head, rcp, rf_next); - rc_parse(rcp); - *rcfile = rcp; - return (0); -} - -int -rc_close(struct rcfile *rcp) -{ - struct rcsection *p,*n; - - fclose(rcp->rf_f); - for (p = SLIST_FIRST(&rcp->rf_sect); p; ) { - n = p; - p = SLIST_NEXT(p,rs_next); - rc_sect_free(n); - } - free(rcp->rf_name); - SLIST_REMOVE(&pf_head, rcp, rcfile, rf_next); - free(rcp); - return (0); -} - -static struct rcfile* -rc_find(const char *filename) -{ - struct rcfile *p; - - SLIST_FOREACH(p, &pf_head, rf_next) - if (strcmp (filename, p->rf_name) == 0) - return (p); - return (0); -} - -/* Find section with given name and id */ -static struct rcsection * -rc_findsect(struct rcfile *rcp, const char *sectname, int sect_id) -{ - struct rcsection *p; - - SLIST_FOREACH(p, &rcp->rf_sect, rs_next) - if (strcmp(p->rs_name, sectname) == 0 && p->rs_id == sect_id) - return (p); - return (NULL); -} - -static struct rcsection * -rc_addsect(struct rcfile *rcp, const char *sectname) -{ - struct rcsection *p; - int id = 0; - p = rc_findsect(rcp, sectname, 0); - if (p) { - /* - * If section with that name already exists -- add one more, - * same named, but with different id (higher by one) - */ - while (p != NULL) { - id = p->rs_id + 1; - p = rc_findsect(rcp, sectname, id); - } - } - p = malloc(sizeof(*p)); - if (!p) - return (NULL); - p->rs_name = strdup(sectname); - p->rs_id = id; - SLIST_INIT(&p->rs_keys); - SLIST_INSERT_HEAD(&rcp->rf_sect, p, rs_next); - return (p); -} - -static int -rc_sect_free(struct rcsection *rsp) -{ - struct rckey *p,*n; - - for (p = SLIST_FIRST(&rsp->rs_keys); p; ) { - n = p; - p = SLIST_NEXT(p,rk_next); - rc_key_free(n); - } - free(rsp->rs_name); - free(rsp); - return (0); -} - -static struct rckey * -rc_sect_findkey(struct rcsection *rsp, const char *keyname) -{ - struct rckey *p; - - SLIST_FOREACH(p, &rsp->rs_keys, rk_next) - if (strcmp(p->rk_name, keyname)==0) - return (p); - return (NULL); -} - -static struct rckey * -rc_sect_addkey(struct rcsection *rsp, const char *name, char *value) -{ - struct rckey *p; - p = rc_sect_findkey(rsp, name); - if (p) { - free(p->rk_value); - } else { - p = malloc(sizeof(*p)); - if (!p) - return (NULL); - SLIST_INSERT_HEAD(&rsp->rs_keys, p, rk_next); - p->rk_name = strdup(name); - } - p->rk_value = value ? strdup(value) : strdup(""); - return (p); -} - -static void -rc_key_free(struct rckey *p) -{ - free(p->rk_value); - free(p->rk_name); - free(p); -} - -enum { stNewLine, stHeader, stSkipToEOL, stGetKey, stGetValue}; - -static void -rc_parse(struct rcfile *rcp) -{ - FILE *f = rcp->rf_f; - int state = stNewLine, c; - struct rcsection *rsp = NULL; - struct rckey *rkp = NULL; - char buf[2048]; - char *next = buf, *last = &buf[sizeof(buf)-1]; - - while ((c = getc (f)) != EOF) { - if (c == '\r') - continue; - if (state == stNewLine) { - next = buf; - if (isspace(c)) - continue; /* skip leading junk */ - if (c == '[') { - state = stHeader; - rsp = NULL; - continue; - } - if (c == '#' || c == ';') { - state = stSkipToEOL; - } else { /* something meaningful */ - state = stGetKey; - } - } - if (state == stSkipToEOL || next == last) {/* ignore long lines */ - if (c == '\n') { - state = stNewLine; - next = buf; - } - continue; - } - if (state == stHeader) { - if (c == ']') { - *next = 0; - next = buf; - rsp = rc_addsect(rcp, buf); - state = stSkipToEOL; - } else - *next++ = c; - continue; - } - if (state == stGetKey) { - if (c == ' ' || c == '\t')/* side effect: 'key name='*/ - continue; /* become 'keyname=' */ - if (c == '\n') { /* silently ignore ... */ - state = stNewLine; - continue; - } - if (c != '=') { - *next++ = c; - continue; - } - *next = 0; - if (rsp == NULL) { - fprintf(stderr, "Key '%s' defined before " - "section\n", buf); - state = stSkipToEOL; - continue; - } - rkp = rc_sect_addkey(rsp, buf, NULL); - next = buf; - state = stGetValue; - continue; - } - /* only stGetValue left */ - if (state != stGetValue) { - fprintf(stderr, "Well, I can't parse file " - "'%s'\n",rcp->rf_name); - state = stSkipToEOL; - } - if (c != '\n') { - *next++ = c; - continue; - } - *next = 0; - rkp->rk_value = strdup(buf); - state = stNewLine; - rkp = NULL; - } /* while */ - if (c == EOF && state == stGetValue) { - *next = 0; - rkp->rk_value = strdup(buf); - } -} - -int -rc_getstringptr(struct rcfile *rcp, const char *section, int sect_id, - const char *key, char **dest) -{ - struct rcsection *rsp; - struct rckey *rkp; - - *dest = NULL; - rsp = rc_findsect(rcp, section, sect_id); - if (!rsp) - return (ENOENT); - rkp = rc_sect_findkey(rsp,key); - if (!rkp) - return (ENOENT); - *dest = rkp->rk_value; - return (0); -} - -int -rc_getstring(struct rcfile *rcp, const char *section, int sect_id, - const char *key, unsigned int maxlen, char *dest) -{ - char *value; - int error; - - error = rc_getstringptr(rcp, section, sect_id, key, &value); - if (error) - return (error); - if (strlen(value) >= maxlen) { - fprintf(stderr, "line too long for key '%s' in section '%s'," - "max = %d\n",key, section, maxlen); - return (EINVAL); - } - strcpy(dest,value); - return (0); -} - -int -rc_getint(struct rcfile *rcp, const char *section, int sect_id, - const char *key, int *value) -{ - struct rcsection *rsp; - struct rckey *rkp; - - rsp = rc_findsect(rcp, section, sect_id); - if (!rsp) - return (ENOENT); - rkp = rc_sect_findkey(rsp,key); - if (!rkp) - return (ENOENT); - errno = 0; - *value = strtol(rkp->rk_value,NULL,0); - if (errno) { - fprintf(stderr, "invalid int value '%s' for key '%s' in " - "section '%s'\n",rkp->rk_value,key,section); - return (errno); - } - return (0); -} - -/* - * 1,yes,true - * 0,no,false - */ -int -rc_getbool(struct rcfile *rcp, const char *section, int sect_id, - const char *key, int *value) -{ - struct rcsection *rsp; - struct rckey *rkp; - char *p; - - rsp = rc_findsect(rcp, section, sect_id); - if (!rsp) - return (ENOENT); - rkp = rc_sect_findkey(rsp,key); - if (!rkp) - return (ENOENT); - p = rkp->rk_value; - while (*p && isspace(*p)) p++; - if (*p == '0' || strcasecmp(p,"no") == 0 || - strcasecmp(p, "false") == 0 || - strcasecmp(p, "off") == 0) { - *value = 0; - return (0); - } - if (*p == '1' || strcasecmp(p,"yes") == 0 || - strcasecmp(p, "true") == 0 || - strcasecmp(p, "on") == 0) { - *value = 1; - return (0); - } - fprintf(stderr, "invalid boolean value '%s' for key '%s' in section " - "'%s' \n",p, key, section); - return (EINVAL); -} - -/* Count how many sections with given name exists in configuration. */ -int rc_getsectionscount(struct rcfile *f, const char *sectname) -{ - struct rcsection *p; - int count = 0; - - p = rc_findsect(f, sectname, 0); - if (p) { - while (p != NULL) { - count = p->rs_id + 1; - p = rc_findsect(f, sectname, count); - } - return (count); - } else - return (0); -} - -char ** -rc_getkeys(struct rcfile *rcp, const char *sectname, int sect_id) -{ - struct rcsection *rsp; - struct rckey *p; - char **names_tbl; - int i = 0, count = 0; - - rsp = rc_findsect(rcp, sectname, sect_id); - if (rsp == NULL) - return (NULL); - - SLIST_FOREACH(p, &rsp->rs_keys, rk_next) - count++; - - names_tbl = malloc(sizeof(char *) * (count + 1)); - if (names_tbl == NULL) - return (NULL); - - SLIST_FOREACH(p, &rsp->rs_keys, rk_next) - names_tbl[i++] = p->rk_name; - - names_tbl[i] = NULL; - return (names_tbl); -} - diff --git a/usr.sbin/nandsim/nandsim_rcfile.h b/usr.sbin/nandsim/nandsim_rcfile.h deleted file mode 100644 index d92ae870f0fc..000000000000 --- a/usr.sbin/nandsim/nandsim_rcfile.h +++ /dev/null @@ -1,72 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 1999, Boris Popov - * 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, 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. - * 3. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$ - * - * from: FreeBSD: src/lib/libncp/ncpl_rcfile.c,v 1.5 2007/01/09 23:27:39 imp Exp - */ - -#ifndef _SIMRC_H_ -#define _SIMRC_H_ - -#include - -struct rckey { - SLIST_ENTRY(rckey) rk_next; - char *rk_name; /* key name */ - char *rk_value; /* key value */ -}; - -struct rcsection { - SLIST_ENTRY(rcsection) rs_next; - SLIST_HEAD(rckey_head,rckey) rs_keys; /* key list */ - char *rs_name; /* section name */ - int rs_id; /* allow few same named */ -}; - -struct rcfile { - SLIST_ENTRY(rcfile) rf_next; - SLIST_HEAD(rcsec_head, rcsection) rf_sect; /* sections list */ - char *rf_name; /* file name */ - FILE *rf_f; /* file desc */ -}; - -int rc_open(const char *, const char *,struct rcfile **); -int rc_close(struct rcfile *); -int rc_getstringptr(struct rcfile *, const char *, int, const char *, - char **); -int rc_getstring(struct rcfile *, const char *, int, const char *, - unsigned int, char *); -int rc_getint(struct rcfile *, const char *, int, const char *, int *); -int rc_getbool(struct rcfile *, const char *, int, const char *, int *); -int rc_getsectionscount(struct rcfile *, const char *); -char **rc_getkeys(struct rcfile *, const char *, int); - -#endif /* _SIMRC_H_ */ diff --git a/usr.sbin/nandsim/sample.conf b/usr.sbin/nandsim/sample.conf deleted file mode 100644 index bc534e109fe5..000000000000 --- a/usr.sbin/nandsim/sample.conf +++ /dev/null @@ -1,174 +0,0 @@ -#- -# Copyright (C) 2009-2012 Semihalf -# 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$ - -# -# Sample NANDsim configuration file. -# - -############################################################################# -# -# [sim] General (common) simulator configuration section. -# -[sim] -# log_level=0..255 -log_level=11 - -# log_output=[none, console, ram, file] -# -# When log_output=file is specified, each [ctrl] section must have a -# corresponding 'log_filename' field provided, which specifies log file name -# to be used. -log_output=none - -############################################################################# -# -# [ctrl] Controller configuration section. -# -# There can be a number of controllers defined for simulation, each has a -# dedicated [ctrl] section. With a given controller there are associated -# subordinate NAND chips, which are tied to chip select lines. -# -[ctrl] -# The number of this controller. -# ctrl_num=0..3 -ctrl_num=0 - -# The number of chip selects available at this controller. -# num_cs=1..4 -num_cs=1 - -# ECC enable flag. -# ecc=[on|off] -ecc=on - -# ECC layout. This is the list of byte offsets within OOB area, which comprise -# the ECC contents set. -# -# ecc_layout=[byte1, byte2-byte3, ..byten] -ecc_layout=[0-53] - -# Absolute path to the log file for this controller. -#log_filename=/var/log/nandsim-ctl0.log - - -############################################################################# -# -# [chip] Chip configuration section. -# -# There can be a number of individual NAND chip devices defined for -# simulation, and each has a dedicated [chip] section. -# -# A particular chip needs to be associated with its parent NAND controller by -# specifying the following fields: controller number (chip_ctrl) and the chip -# select line it is connected to (chip_cs). The chip can be connected to only -# a single (and unique) controller:cs pair. -# -[chip] -# The number of parent controller. This has to fit one of the controller -# instance number (ctrl_num from [ctrl] section). -# chip_ctrl=0..3 -chip_ctrl=0 - -# Chip select line. -# chip_cs=0..3 -chip_cs=0 - -# ONFI device identifier. -# device_id=0x00..0xff -device_id=0xd3 - -# ONFI manufacturer identifier. -# manufacturer_id=0x00..0xff -manufacturer_id=0xec - -# Textual description of the chip. -# model="model_name" -model="k9xxg08uxM:1GiB 3,3V 8-bit" - -# Textual name of the chip manufacturer. -# manufacturer="manufacturer name" -manufacturer="SAMSUNG" - -# page_size=[must be power of 2 and >= 512] (in bytes) -page_size=2048 -# oob_size=[>0] -oob_size=64 -# pages_per_block=n*32 -pages_per_block=64 -# blocks_per_lun=[>0] -blocks_per_lun=4096 -# luns=1..N -luns=1 -# column_addr_cycle=[1,2] -column_addr_cycle=2 -# row_addr_cycle=[1,2,3] -row_addr_cycle=3 - -# program_time= (in us) -program_time=0 -# erase_time= (in us) -erase_time=0 -# read_time= (in us) -read_time=0 -# ccs_time= (in us) -#ccs_time=200 - -# Simulate write-protect on the chip. -# write_protect=[yes|no] -#write_protect=no - -# Blocks wear-out threshold. Each block has a counter of program-erase cycles; -# when this counter reaches 'wear_out' value a given block is treated as a bad -# block (access will report error). -# -# Setting wear_out to 0 means that blocks will never wear out. -# -# wear_out=0..100000 -wear_out=50000 - -# Errors per million read/write bytes. This simulates an accidental read/write -# block error, which can happen in real devices with certain probability. Note -# this isn't a bad block condition i.e. the block at which the read/write -# operation is simulated to fail here remains usable, only the operation has -# not succeeded (this is where ECC comes into play and is supposed to correct -# such problems). -# -# error_ratio=0..1000000 -#error_ratio=50 - -# Chip data bus width. All chips connected to the same controller must have -# the same bus width. -# -# width=[8|16] -width=8 - -# Bad block map. NANDsim emulates bad block behavior upon accessing a block -# with number from the specified list. -# -# bad_block_map=[bad_block1, bad_block2-bad_block3, ..bad_blockn] -bad_block_map=[100-200] - diff --git a/usr.sbin/nandtool/Makefile b/usr.sbin/nandtool/Makefile deleted file mode 100644 index c01c2fdedbbf..000000000000 --- a/usr.sbin/nandtool/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# $FreeBSD$ - -PROG= nandtool -SRCS= nandtool.c nand_read.c nand_write.c nand_erase.c nand_info.c -SRCS+= nand_readoob.c nand_writeoob.c -BINDIR= /usr/sbin -LIBADD= geom -MAN= nandtool.8 - -.include diff --git a/usr.sbin/nandtool/Makefile.depend b/usr.sbin/nandtool/Makefile.depend deleted file mode 100644 index 0220673c9076..000000000000 --- a/usr.sbin/nandtool/Makefile.depend +++ /dev/null @@ -1,20 +0,0 @@ -# $FreeBSD$ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - gnu/lib/csu \ - include \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - lib/libcompiler_rt \ - lib/libexpat \ - lib/libgeom \ - lib/libsbuf \ - - -.include - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif diff --git a/usr.sbin/nandtool/nand_erase.c b/usr.sbin/nandtool/nand_erase.c deleted file mode 100644 index e9742d15ddf9..000000000000 --- a/usr.sbin/nandtool/nand_erase.c +++ /dev/null @@ -1,116 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 -#include -#include -#include -#include -#include -#include -#include "nandtool.h" - -int nand_erase(struct cmd_param *params) -{ - struct chip_param_io chip_params; - char *dev; - int fd = -1, ret = 0; - off_t pos, count; - off_t start, nblocks, i; - int block_size, mult; - - if (!(dev = param_get_string(params, "dev"))) { - fprintf(stderr, "Please supply valid 'dev' parameter.\n"); - return (1); - } - - if (param_has_value(params, "count")) - count = param_get_intx(params, "count"); - else - count = 1; - - if ((fd = g_open(dev, 1)) < 0) { - perrorf("Cannot open %s", dev); - return (1); - } - - if (ioctl(fd, NAND_IO_GET_CHIP_PARAM, &chip_params) == -1) { - perrorf("Cannot ioctl(NAND_IO_GET_CHIP_PARAM)"); - ret = 1; - goto out; - } - - block_size = chip_params.page_size * chip_params.pages_per_block; - - if (param_has_value(params, "page")) { - pos = chip_params.page_size * param_get_intx(params, "page"); - mult = chip_params.page_size; - } else if (param_has_value(params, "block")) { - pos = block_size * param_get_intx(params, "block"); - mult = block_size; - } else if (param_has_value(params, "pos")) { - pos = param_get_intx(params, "pos"); - mult = 1; - } else { - /* Erase whole chip */ - if (ioctl(fd, DIOCGMEDIASIZE, &count) == -1) { - ret = 1; - goto out; - } - - pos = 0; - mult = 1; - } - - if (pos % block_size) { - fprintf(stderr, "Position must be block-size aligned!\n"); - ret = 1; - goto out; - } - - count *= mult; - start = pos / block_size; - nblocks = count / block_size; - - for (i = 0; i < nblocks; i++) { - if (g_delete(fd, (start + i) * block_size, block_size) == -1) { - perrorf("Cannot erase block %d - probably a bad block", - start + i); - ret = 1; - } - } - -out: - g_close(fd); - - return (ret); -} - diff --git a/usr.sbin/nandtool/nand_info.c b/usr.sbin/nandtool/nand_info.c deleted file mode 100644 index 79f84abd1136..000000000000 --- a/usr.sbin/nandtool/nand_info.c +++ /dev/null @@ -1,88 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 -#include -#include -#include -#include -#include -#include -#include "nandtool.h" - -int nand_info(struct cmd_param *params) -{ - struct chip_param_io chip_params; - int fd = -1, ret = 0; - int block_size; - off_t chip_size, media_size; - const char *dev; - - if ((dev = param_get_string(params, "dev")) == NULL) { - fprintf(stderr, "Please supply 'dev' parameter, eg. " - "'dev=/dev/gnand0'\n"); - return (1); - } - - if ((fd = g_open(dev, 1)) == -1) { - perrorf("Cannot open %s", dev); - return (1); - } - - if (ioctl(fd, NAND_IO_GET_CHIP_PARAM, &chip_params) == -1) { - perrorf("Cannot ioctl(NAND_IO_GET_CHIP_PARAM)"); - ret = 1; - goto out; - } - - if (ioctl(fd, DIOCGMEDIASIZE, &media_size) == -1) { - perrorf("Cannot ioctl(DIOCGMEDIASIZE)"); - ret = 1; - goto out; - } - - block_size = chip_params.page_size * chip_params.pages_per_block; - chip_size = block_size * chip_params.blocks; - - printf("Device:\t\t\t%s\n", dev); - printf("Page size:\t\t%d bytes\n", chip_params.page_size); - printf("Block size:\t\t%d bytes (%d KB)\n", block_size, - block_size / 1024); - printf("OOB size per page:\t%d bytes\n", chip_params.oob_size); - printf("Chip size:\t\t%jd MB\n", (uintmax_t)(chip_size / 1024 / 1024)); - printf("Slice size:\t\t%jd MB\n", - (uintmax_t)(media_size / 1024 / 1024)); - -out: - g_close(fd); - - return (ret); -} diff --git a/usr.sbin/nandtool/nand_read.c b/usr.sbin/nandtool/nand_read.c deleted file mode 100644 index 395b0c3fa7f5..000000000000 --- a/usr.sbin/nandtool/nand_read.c +++ /dev/null @@ -1,141 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 -#include -#include -#include -#include -#include -#include -#include "nandtool.h" - -int nand_read(struct cmd_param *params) -{ - struct chip_param_io chip_params; - int fd = -1, out_fd = -1, done = 0, ret = 0; - char *dev, *out; - int pos, count, mult, block_size; - uint8_t *buf = NULL; - - if (!(dev = param_get_string(params, "dev"))) { - fprintf(stderr, "You must specify 'dev' parameter\n"); - return (1); - } - - if ((out = param_get_string(params, "out"))) { - out_fd = open(out, O_WRONLY|O_CREAT, 0666); - if (out_fd == -1) { - perrorf("Cannot open %s for writing", out); - return (1); - } - } - - if ((fd = g_open(dev, 1)) == -1) { - perrorf("Cannot open %s", dev); - ret = 1; - goto out; - } - - if (ioctl(fd, NAND_IO_GET_CHIP_PARAM, &chip_params) == -1) { - perrorf("Cannot ioctl(NAND_IO_GET_CHIP_PARAM)"); - ret = 1; - goto out; - } - - block_size = chip_params.page_size * chip_params.pages_per_block; - - if (param_has_value(params, "page")) { - pos = chip_params.page_size * param_get_int(params, "page"); - mult = chip_params.page_size; - } else if (param_has_value(params, "block")) { - pos = block_size * param_get_int(params, "block"); - mult = block_size; - } else if (param_has_value(params, "pos")) { - pos = param_get_int(params, "pos"); - mult = 1; - if (pos % chip_params.page_size) { - fprintf(stderr, "Position must be page-size aligned!\n"); - ret = 1; - goto out; - } - } else { - fprintf(stderr, "You must specify one of: 'block', 'page'," - "'pos' arguments\n"); - ret = 1; - goto out; - } - - if (!(param_has_value(params, "count"))) - count = mult; - else - count = param_get_int(params, "count") * mult; - - if (!(buf = malloc(chip_params.page_size))) { - perrorf("Cannot allocate buffer [size %x]", - chip_params.page_size); - ret = 1; - goto out; - } - - lseek(fd, pos, SEEK_SET); - - while (done < count) { - if ((ret = read(fd, buf, chip_params.page_size)) != - (int32_t)chip_params.page_size) { - perrorf("read error (read %d bytes)", ret); - goto out; - } - - if (out_fd != -1) { - done += ret; - if ((ret = write(out_fd, buf, chip_params.page_size)) != - (int32_t)chip_params.page_size) { - perrorf("write error (written %d bytes)", ret); - ret = 1; - goto out; - } - } else { - hexdumpoffset(buf, chip_params.page_size, done); - done += ret; - } - } - -out: - g_close(fd); - if (out_fd != -1) - close(out_fd); - if (buf) - free(buf); - - return (ret); -} - diff --git a/usr.sbin/nandtool/nand_readoob.c b/usr.sbin/nandtool/nand_readoob.c deleted file mode 100644 index 6c5bb372c3e0..000000000000 --- a/usr.sbin/nandtool/nand_readoob.c +++ /dev/null @@ -1,113 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 -#include -#include -#include -#include -#include -#include -#include -#include "nandtool.h" - -int nand_read_oob(struct cmd_param *params) -{ - struct chip_param_io chip_params; - struct nand_oob_rw req; - char *dev, *out; - int fd = -1, fd_out = -1, ret = 0; - int page; - uint8_t *buf = NULL; - - if ((page = param_get_int(params, "page")) < 0) { - fprintf(stderr, "You must supply valid 'page' argument.\n"); - return (1); - } - - if (!(dev = param_get_string(params, "dev"))) { - fprintf(stderr, "You must supply 'dev' argument.\n"); - return (1); - } - - if ((out = param_get_string(params, "out"))) { - if ((fd_out = open(out, O_WRONLY | O_CREAT, 0666)) == -1) { - perrorf("Cannot open %s", out); - ret = 1; - goto out; - } - } - - if ((fd = g_open(dev, 1)) == -1) { - perrorf("Cannot open %s", dev); - ret = 1; - goto out; - } - - if (ioctl(fd, NAND_IO_GET_CHIP_PARAM, &chip_params) == -1) { - perrorf("Cannot ioctl(NAND_IO_GET_CHIP_PARAM)"); - ret = 1; - goto out; - } - - buf = malloc(chip_params.oob_size); - if (buf == NULL) { - perrorf("Cannot allocate %d bytes\n", chip_params.oob_size); - ret = 1; - goto out; - } - - req.page = page; - req.len = chip_params.oob_size; - req.data = buf; - - if (ioctl(fd, NAND_IO_OOB_READ, &req) == -1) { - perrorf("Cannot read OOB from %s", dev); - ret = 1; - goto out; - } - - if (fd_out != -1) - write(fd_out, buf, chip_params.oob_size); - else - hexdump(buf, chip_params.oob_size); - -out: - close(fd_out); - - if (fd != -1) - g_close(fd); - if (buf) - free(buf); - - return (ret); -} - diff --git a/usr.sbin/nandtool/nand_write.c b/usr.sbin/nandtool/nand_write.c deleted file mode 100644 index 481f1a453538..000000000000 --- a/usr.sbin/nandtool/nand_write.c +++ /dev/null @@ -1,145 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 -#include -#include -#include -#include -#include -#include -#include "nandtool.h" - -int nand_write(struct cmd_param *params) -{ - struct chip_param_io chip_params; - char *dev, *file; - int in_fd = -1, ret = 0, done = 0; - int fd, block_size, mult, pos, count; - uint8_t *buf = NULL; - - if (!(dev = param_get_string(params, "dev"))) { - fprintf(stderr, "Please supply 'dev' argument.\n"); - return (1); - } - - if (!(file = param_get_string(params, "in"))) { - fprintf(stderr, "Please supply 'in' argument.\n"); - return (1); - } - - if ((fd = g_open(dev, 1)) == -1) { - perrorf("Cannot open %s", dev); - return (1); - } - - if ((in_fd = open(file, O_RDONLY)) == -1) { - perrorf("Cannot open file %s", file); - ret = 1; - goto out; - } - - if (ioctl(fd, NAND_IO_GET_CHIP_PARAM, &chip_params) == -1) { - perrorf("Cannot ioctl(NAND_IO_GET_CHIP_PARAM)"); - ret = 1; - goto out; - } - - block_size = chip_params.page_size * chip_params.pages_per_block; - - if (param_has_value(params, "page")) { - pos = chip_params.page_size * param_get_int(params, "page"); - mult = chip_params.page_size; - } else if (param_has_value(params, "block")) { - pos = block_size * param_get_int(params, "block"); - mult = block_size; - } else if (param_has_value(params, "pos")) { - pos = param_get_int(params, "pos"); - mult = 1; - if (pos % chip_params.page_size) { - fprintf(stderr, "Position must be page-size " - "aligned!\n"); - ret = 1; - goto out; - } - } else { - fprintf(stderr, "You must specify one of: 'block', 'page'," - "'pos' arguments\n"); - ret = 1; - goto out; - } - - if (!(param_has_value(params, "count"))) - count = mult; - else - count = param_get_int(params, "count") * mult; - - if (!(buf = malloc(chip_params.page_size))) { - perrorf("Cannot allocate buffer [size %x]", - chip_params.page_size); - ret = 1; - goto out; - } - - lseek(fd, pos, SEEK_SET); - - while (done < count) { - if ((ret = read(in_fd, buf, chip_params.page_size)) != - (int32_t)chip_params.page_size) { - if (ret > 0) { - /* End of file ahead, truncate here */ - break; - } else { - perrorf("Cannot read from %s", file); - ret = 1; - goto out; - } - } - - if ((ret = write(fd, buf, chip_params.page_size)) != - (int32_t)chip_params.page_size) { - ret = 1; - goto out; - } - - done += ret; - } - -out: - g_close(fd); - if (in_fd != -1) - close(in_fd); - if (buf) - free(buf); - - return (ret); -} - diff --git a/usr.sbin/nandtool/nand_writeoob.c b/usr.sbin/nandtool/nand_writeoob.c deleted file mode 100644 index f1143b8a382a..000000000000 --- a/usr.sbin/nandtool/nand_writeoob.c +++ /dev/null @@ -1,115 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 -#include -#include -#include -#include -#include -#include -#include "nandtool.h" - -int nand_write_oob(struct cmd_param *params) -{ - struct chip_param_io chip_params; - struct nand_oob_rw req; - char *dev, *in; - int fd = -1, fd_in = -1, ret = 0; - uint8_t *buf = NULL; - int page; - - if (!(dev = param_get_string(params, "dev"))) { - fprintf(stderr, "Please supply valid 'dev' parameter.\n"); - return (1); - } - - if (!(in = param_get_string(params, "in"))) { - fprintf(stderr, "Please supply valid 'in' parameter.\n"); - return (1); - } - - if ((page = param_get_int(params, "page")) < 0) { - fprintf(stderr, "Please supply valid 'page' parameter.\n"); - return (1); - } - - if ((fd = g_open(dev, 1)) == -1) { - perrorf("Cannot open %s", dev); - return (1); - } - - if ((fd_in = open(in, O_RDONLY)) == -1) { - perrorf("Cannot open %s", in); - ret = 1; - goto out; - } - - if (ioctl(fd, NAND_IO_GET_CHIP_PARAM, &chip_params) == -1) { - perrorf("Cannot ioctl(NAND_IO_GET_CHIP_PARAM)"); - ret = 1; - goto out; - } - - buf = malloc(chip_params.oob_size); - if (buf == NULL) { - perrorf("Cannot allocate %d bytes\n", chip_params.oob_size); - ret = 1; - goto out; - } - - if (read(fd_in, buf, chip_params.oob_size) == -1) { - perrorf("Cannot read from %s", in); - ret = 1; - goto out; - } - - req.page = page; - req.len = chip_params.oob_size; - req.data = buf; - - if (ioctl(fd, NAND_IO_OOB_PROG, &req) == -1) { - perrorf("Cannot write OOB to %s", dev); - ret = 1; - goto out; - } - -out: - g_close(fd); - if (fd_in != -1) - close(fd_in); - if (buf) - free(buf); - - return (ret); -} - - diff --git a/usr.sbin/nandtool/nandtool.8 b/usr.sbin/nandtool/nandtool.8 deleted file mode 100644 index 8f8f1deffddf..000000000000 --- a/usr.sbin/nandtool/nandtool.8 +++ /dev/null @@ -1,184 +0,0 @@ -.\" Copyright (c) 2010 Semihalf -.\" 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 April 10, 2012 -.Dt NANDTOOL 8 -.Os -.Sh NAME -.Nm nandtool -.Nd NAND devices swiss army knife -.Sh SYNOPSIS -.Nm -.Ar command -.Op Ar operands ... -.Sh DESCRIPTION -The -.Nm -utility can be used to perform various operations on -.Xr gnand 4 -devices (read, write, erase, -read and write OOB area and to get info about NAND flash chip). -.Pp -The following commands are available: -.Bl -tag -width ".Cm of Ns = Ns Ar file" -.It Cm read Ns -Read pages from NAND device. -.It Cm write Ns -Write pages to NAND device. -.It Cm erase Ns -Erase blocks. -Requires offset aligned to block granularity. -.It Cm info Ns -Get information about NAND chip (page size, block size, OOB area size, chip size -and media size) -.It Cm readoob Ns -Read OOB area from specified page. -.It Cm writeoob Ns -Write OOB area bound to specified page. -.It Cm help Ns -Get usage info. -.El -.Sh COMMAND read -The following operands are available for -.Nm -.Cm read -command: -.Bl -tag -width ".Cm of Ns = Ns Ar file" -.It Cm dev Ns = Ns Ar -Path to a -.Xr gnand 4 -device node, required for all operations. -.It Cm out Ns = Ns Ar -Output file path. If not specified, page contents -will be dumped to stdout in format similar to -.Xr hexdump 1 -.It Cm page Ns = Ns Ar -Offset on device, expressed as page number. -.It Cm block Ns = Ns Ar -Offset on device, expressed as block number. -.It Cm pos Ns = Ns Ar -Offset on device, expressed in bytes (however, must be aligned -to page granularity). -.It Cm count Ns = Ns Ar -Count of objects (pages, blocks, bytes). -.El -.Sh COMMAND readoob -The following operands are available for -.Nm -.Cm readoob -command: -.Bl -tag -width ".Cm of Ns = Ns Ar file" -.It Cm dev Ns = Ns Ar -Path to NAND device node. -.It Cm page Ns = Ns Ar -Offset on device, expressed as page number. -.It Cm out Ns = Ns Ar -Output file path, optional. -.El -.Sh COMMAND write -The following operands are available for -.Nm -.Cm write -command: -.Bl -tag -width ".Cm of Ns = Ns Ar file" -.It Cm dev Ns = Ns Ar -Path to NAND device node. -.It Cm page Ns = Ns Ar -Offset on device, expressed as page number. -.It Cm block Ns = Ns Ar -Offset on device, expressed as block number. -.It Cm pos Ns = Ns Ar -Offset on device, expressed in bytes (however, must be aligned -to page granularity). -.It Cm in Ns = Ns Ar -Input file path. -.El -.Sh COMMAND writeoob -The following operands are available for -.Nm -.Cm writeoob -command: -.Bl -tag -width ".Cm of Ns = Ns Ar file" -.It Cm dev Ns = Ns Ar -Path to NAND device node. -.It Cm page Ns = Ns Ar -Offset on device, expressed as page number. -.It Cm in Ns = Ns Ar -Input file path. -.El -.Sh COMMAND erase -The following operands are available for -.Nm -.Cm erase -command: -.Bl -tag -width ".Cm of Ns = Ns Ar file" -.It Cm dev Ns = Ns Ar -Path to NAND device node. -.It Cm page Ns = Ns Ar -Offset on device, expressed as page number. -.It Cm block Ns = Ns Ar -Offset on device, expressed as block number. -.It Cm pos Ns = Ns Ar -Offset on device, epressed in bytes (however, must be aligned -to block granularity). -.It Cm count Ns = Ns Ar -Count of objects (pages, blocks, bytes). -.El -.Pp -WARNING: The only required parameter for the \fBerase\fP command is -.Ar dev . -When no other arguments are provided the whole device is erased! -.Sh COMMAND info -There is only one operand available for -.Nm -.Cm info -command: -.Bl -tag -width ".Cm of Ns = Ns Ar file" -.It Cm dev Ns = Ns Ar -Path to NAND device node. -.El -.Sh COMMAND help -There is only one operand available for -.Nm -.Cm help -command: -.Bl -tag -width ".Cm of Ns = Ns Ar file" -.It Cm topic Ns = Ns Ar -Help topic. -.El -.Sh EXIT STATUS -.Ex -std -If the supplied argument -.Ar dev -points to a device node other than gnand or gnand.raw both -.Nm -.Cm readoob -and -.Nm -.Cm writeoob -return error. -.Sh SEE ALSO -.Xr gnand 4 diff --git a/usr.sbin/nandtool/nandtool.c b/usr.sbin/nandtool/nandtool.c deleted file mode 100644 index e87ed7342e6d..000000000000 --- a/usr.sbin/nandtool/nandtool.c +++ /dev/null @@ -1,285 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 -#include -#include -#include -#include -#include -#include -#include -#include "nandtool.h" -#include "usage.h" - -int usage(struct cmd_param *); - -static const struct { - const char *name; - const char *usage; - int (*handler)(struct cmd_param *); -} commands[] = { - { "help", nand_help_usage, usage }, - { "read", nand_read_usage, nand_read }, - { "write", nand_write_usage, nand_write }, - { "erase", nand_erase_usage, nand_erase }, - { "readoob", nand_read_oob_usage, nand_read_oob }, - { "writeoob", nand_write_oob_usage, nand_write_oob }, - { "info", nand_info_usage, nand_info }, - { NULL, NULL, NULL }, -}; - -static char * -_param_get_stringx(struct cmd_param *params, const char *name, int doexit) -{ - int i; - - for (i = 0; params[i].name[0] != '\0'; i++) { - if (!strcmp(params[i].name, name)) - return params[i].value; - } - - if (doexit) { - perrorf("Missing parameter %s", name); - exit(1); - } - return (NULL); -} - -char * -param_get_string(struct cmd_param *params, const char *name) -{ - - return (_param_get_stringx(params, name, 0)); -} - -static int -_param_get_intx(struct cmd_param *params, const char *name, int doexit) -{ - int ret; - char *str = _param_get_stringx(params, name, doexit); - - if (!str) - return (-1); - - errno = 0; - ret = (int)strtol(str, (char **)NULL, 10); - if (errno) { - if (doexit) { - perrorf("Invalid value for parameter %s", name); - exit(1); - } - return (-1); - } - - return (ret); -} - -int -param_get_intx(struct cmd_param *params, const char *name) -{ - - return (_param_get_intx(params, name, 1)); -} - -int -param_get_int(struct cmd_param *params, const char *name) -{ - - return (_param_get_intx(params, name, 0)); -} - -int -param_get_boolean(struct cmd_param *params, const char *name) -{ - char *str = param_get_string(params, name); - - if (!str) - return (0); - - if (!strcmp(str, "true") || !strcmp(str, "yes")) - return (1); - - return (0); -} - -int -param_has_value(struct cmd_param *params, const char *name) -{ - int i; - - for (i = 0; params[i].name[0] != '\0'; i++) { - if (!strcmp(params[i].name, name)) - return (1); - } - - return (0); -} - -int -param_get_count(struct cmd_param *params) -{ - int i; - - for (i = 0; params[i].name[0] != '\0'; i++); - - return (i); -} - -void -hexdumpoffset(uint8_t *buf, int length, int off) -{ - int i, j; - for (i = 0; i < length; i += 16) { - printf("%08x: ", off + i); - - for (j = 0; j < 16; j++) - printf("%02x ", buf[i+j]); - - printf("| "); - - for (j = 0; j < 16; j++) { - printf("%c", isalnum(buf[i+j]) - ? buf[i+j] - : '.'); - } - - printf("\n"); - } -} - -void -hexdump(uint8_t *buf, int length) -{ - - hexdumpoffset(buf, length, 0); -} - -void * -xmalloc(size_t len) -{ - void *ret = malloc(len); - - if (!ret) { - fprintf(stderr, "Cannot allocate buffer of %zd bytes. " - "Exiting.\n", len); - exit(EX_OSERR); - } - - return (ret); -} - -void -perrorf(const char *format, ...) -{ - va_list args; - - va_start(args, format); - vfprintf(stderr, format, args); - va_end(args); - fprintf(stderr, ": %s\n", strerror(errno)); -} - -int -usage(struct cmd_param *params) -{ - int i; - - if (!params || !param_get_count(params)) { - fprintf(stderr, "Usage: nandtool [arguments...]\n"); - fprintf(stderr, "Arguments are in form 'name=value'.\n\n"); - fprintf(stderr, "Available commands:\n"); - - for (i = 0; commands[i].name != NULL; i++) - fprintf(stderr, "\t%s\n", commands[i].name); - - fprintf(stderr, "\n"); - fprintf(stderr, "For information about particular command, " - "type:\n"); - fprintf(stderr, "'nandtool help topic='\n"); - } else if (param_has_value(params, "topic")) { - for (i = 0; commands[i].name != NULL; i++) { - if (!strcmp(param_get_string(params, "topic"), - commands[i].name)) { - fprintf(stderr, commands[i].usage, "nandtool"); - return (0); - } - } - - fprintf(stderr, "No such command\n"); - return (EX_SOFTWARE); - } else { - fprintf(stderr, "Wrong arguments given. Try: 'nandtool help'\n"); - } - - return (EX_USAGE); -} - -int -main(int argc, const char *argv[]) -{ - struct cmd_param *params; - int i, ret, idx; - - if (argc < 2) { - usage(NULL); - return (0); - } - - params = malloc(sizeof(struct cmd_param) * (argc - 1)); - - for (i = 2, idx = 0; i < argc; i++, idx++) { - if (sscanf(argv[i], "%63[^=]=%63s", params[idx].name, - params[idx].value) < 2) { - fprintf(stderr, "Syntax error in argument %d. " - "Argument should be in form 'name=value'.\n", i); - free(params); - return (-1); - } - } - - params[idx].name[0] = '\0'; - params[idx].value[0] = '\0'; - - for (i = 0; commands[i].name != NULL; i++) { - if (!strcmp(commands[i].name, argv[1])) { - ret = commands[i].handler(params); - free(params); - return (ret); - } - } - - free(params); - fprintf(stderr, "Unknown command. Try '%s help'\n", argv[0]); - - return (-1); -} - diff --git a/usr.sbin/nandtool/nandtool.h b/usr.sbin/nandtool/nandtool.h deleted file mode 100644 index c0dd1c095444..000000000000 --- a/usr.sbin/nandtool/nandtool.h +++ /dev/null @@ -1,59 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$ - */ - -#ifndef __UTILS_H -#define __UTILS_H - -struct cmd_param -{ - char name[64]; - char value[64]; -}; - -char *param_get_string(struct cmd_param *, const char *); -int param_get_int(struct cmd_param *, const char *); -int param_get_intx(struct cmd_param *, const char *); -int param_get_boolean(struct cmd_param *, const char *); -int param_has_value(struct cmd_param *, const char *); -int param_get_count(struct cmd_param *); -void perrorf(const char *, ...); -void hexdumpoffset(uint8_t *, int, int); -void hexdump(uint8_t *, int); -void *xmalloc(size_t); - -/* Command handlers */ -int nand_read(struct cmd_param *); -int nand_write(struct cmd_param *); -int nand_read_oob(struct cmd_param *); -int nand_write_oob(struct cmd_param *); -int nand_erase(struct cmd_param *); -int nand_info(struct cmd_param *); - -#endif /* __UTILS_H */ diff --git a/usr.sbin/nandtool/usage.h b/usr.sbin/nandtool/usage.h deleted file mode 100644 index 0dbb70a2c99d..000000000000 --- a/usr.sbin/nandtool/usage.h +++ /dev/null @@ -1,114 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010-2012 Semihalf. - * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$ - */ - -#ifndef __USAGE_H -#define __USAGE_H - -static const char nand_help_usage[] = - "Usage: %s help topic=\n" - "\n" - "Arguments:\n" - "\tcmd\t- [help|read|write|erase|readoob|writeoob|info]\n" - "\n"; - -static const char nand_read_usage[] = - "Usage: %s read dev= (block|page|pos)=n [count=n]\n" - "\n" - "Arguments:\n" - "\tdev\t- path to gnand device node\n" - "\tblock\t- starting block or\n" - "\tpage\t- starting page or\n" - "\tpos\t- starting position (in bytes, must be page-aligned)\n" - "\tout\t- output file (hexdump to stdout if not supplied)\n" - "\n" - "Note that you can only specify only one of: 'block', 'page', 'pos'\n" - "parameters at once. 'count' parameter is meaningful in terms of used\n" - "unit (page, block or byte).\n"; - -static const char nand_write_usage[] = - "Usage: %s write dev= in= (block|page|pos)=n [count=n]\n" - "\n" - "Arguments:\n" - "\tdev\t- path to gnand device node\n" - "\tin\t- path to input file which be writed to gnand\n" - "\tblock\t- starting block or\n" - "\tpage\t- starting page or\n" - "\tpos\t- starting position (in bytes, must be page-aligned)\n" - "\tcount\t- byte/page/block count\n" - "\n" - ""; - -static const char nand_erase_usage[] = - "Usage: %s erase dev= (block|page|pos)=n [count=n]\n" - "\n" - "Arguments:\n" - "\tdev\t- path to gnand device node\n" - "\tblock\t- starting block or\n" - "\tpage\t- starting page or\n" - "\tpos\t- starting position (in bytes, muse be block-aligned)\n" - "\tcount\t- byte/page/block count\n" - "\n" - "NOTE: position and count for erase operation MUST be block-aligned\n"; - -static const char nand_read_oob_usage[] = - "Usage: %s readoob dev= page=n [out=file] [count=n]\n" - "\n" - "Arguments:\n" - "\tdev\t- path to gnand device node\n" - "\tpage\t- page (page) number\n" - "\tout\t- outut file (hexdump to stdout if not supplied)\n" - "\tcount\t- page count (default is 1)\n" - "\n" - "If you supply count parameter with value other than 1, data will be\n" - "read from subsequent page's OOB areas\n"; - -static const char nand_write_oob_usage[] = - "Usage: %s writeoob dev= in= page=n [count=n]\n" - "\n" - "\tdev\t- path to gnand device node\n" - "\tin\t- path to file containing data which will be written\n" - "\tpage\t- page (page) number\n" - "\n" - "If you supply count parameter with value other than 1, data will be\n" - "written to subsequent page's OOB areas\n"; - -static const char nand_info_usage[] = - "Usage: %s info dev=\n" - "\n" - "Arguments:\n" - "\tdev\t- path to gnand device node\n"; - -static const char nand_stats_usage[] = - "Usage: %s stats dev= (page|block)=\n" - "\n" - "Arguments:\n" - "\tdev\t- path to gnand device node\n"; - -#endif /* __USAGE_H */ From 912a01b36dfff365606ede479f4db2c29e0db601 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Tue, 25 Jun 2019 06:13:56 +0000 Subject: [PATCH 082/165] Replay r349333 by emaste accidentally reverted by r349352 vtfontcvt: improve .bdf validation Previously if we had a FONTBOUNDINGBOX or DWIDTH entry that had missing or invalid values and and failed sscanf, we would proceeded with partially initialized bounding box / device width variables. Reported by: afl (FONTBOUNDINGBOX) MFC with: r349100 Sponsored by: The FreeBSD Foundation --- usr.bin/vtfontcvt/vtfontcvt.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/usr.bin/vtfontcvt/vtfontcvt.c b/usr.bin/vtfontcvt/vtfontcvt.c index 70ec7cf31812..e34308d5d365 100644 --- a/usr.bin/vtfontcvt/vtfontcvt.c +++ b/usr.bin/vtfontcvt/vtfontcvt.c @@ -335,9 +335,11 @@ parse_bdf(FILE *fp, unsigned int map_idx) break; } } - } else if (strncmp(ln, "FONTBOUNDINGBOX ", 16) == 0 && - sscanf(ln + 16, "%d %d %d %d", &fbbw, &fbbh, &fbbox, - &fbboy) == 4) { + } else if (strncmp(ln, "FONTBOUNDINGBOX ", 16) == 0) { + if (sscanf(ln + 16, "%d %d %d %d", &fbbw, &fbbh, &fbbox, + &fbboy) != 4) + errx(1, "invalid FONTBOUNDINGBOX at line %u", + linenum); set_width(fbbw); set_height(fbbh); break; @@ -353,8 +355,9 @@ parse_bdf(FILE *fp, unsigned int map_idx) linenum++; ln[length - 1] = '\0'; - if (strncmp(ln, "DWIDTH ", 7) == 0 && - sscanf(ln + 7, "%d %d", &dwidth, &dwy) == 2) { + if (strncmp(ln, "DWIDTH ", 7) == 0) { + if (sscanf(ln + 7, "%d %d", &dwidth, &dwy) != 2) + errx(1, "invalid DWIDTH at line %u", linenum); if (dwy != 0 || (dwidth != fbbw && dwidth * 2 != fbbw)) errx(1, "bitmap with unsupported DWIDTH %d %d at line %u", dwidth, dwy, linenum); From e5500f1efa890973547b917fdb9308947daca2c8 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Tue, 25 Jun 2019 06:14:00 +0000 Subject: [PATCH 083/165] Replay r349334 by markj accidentally reverted by r349352 Remove a lingering use of splbio(). The buffer must be locked by the caller. No functional change intended. Reviewed by: kib MFC after: 1 week Sponsored by: The FreeBSD Foundation --- sys/fs/smbfs/smbfs_io.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sys/fs/smbfs/smbfs_io.c b/sys/fs/smbfs/smbfs_io.c index 4edba5c761e7..fa6a14024213 100644 --- a/sys/fs/smbfs/smbfs_io.c +++ b/sys/fs/smbfs/smbfs_io.c @@ -375,9 +375,6 @@ smbfs_doio(struct vnode *vp, struct buf *bp, struct ucred *cr, struct thread *td */ if (error == EINTR || (!error && (bp->b_flags & B_NEEDCOMMIT))) { - int s; - - s = splbio(); bp->b_flags &= ~(B_INVAL|B_NOCACHE); if ((bp->b_flags & B_ASYNC) == 0) bp->b_flags |= B_EINTR; @@ -387,7 +384,6 @@ smbfs_doio(struct vnode *vp, struct buf *bp, struct ucred *cr, struct thread *td } if ((bp->b_flags & B_ASYNC) == 0) bp->b_flags |= B_EINTR; - splx(s); } else { if (error) { bp->b_ioflags |= BIO_ERROR; From 6b021cc2dd48de5d238763469a7f6e03b83d4414 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Tue, 25 Jun 2019 06:14:05 +0000 Subject: [PATCH 084/165] Replay r349335 by scottl accidentally reverted by r349352 Add the PCI HDAudio device model from the 2016 GSoC. Detailed information can be found at https://wiki.freebsd.org/SummerOfCode2016/HDAudioEmulationForBhyve This commit has evolved from the original work to include Capsicum integration. As part of that, it only opens the host audio devices once and leaves them open, instead of opening and closing them on each guest access. Thanks to Peter Grehan and Marcelo Araujo for their help in bringing the work forward and providing some of the final techncial push. Submitted by: Alex Teaca Differential Revision: D7840, D12419 --- usr.sbin/bhyve/Makefile | 3 + usr.sbin/bhyve/audio.c | 282 ++++++++ usr.sbin/bhyve/audio.h | 86 +++ usr.sbin/bhyve/hda_codec.c | 950 +++++++++++++++++++++++++ usr.sbin/bhyve/hda_reg.h | 1367 ++++++++++++++++++++++++++++++++++++ usr.sbin/bhyve/hdac_reg.h | 269 +++++++ usr.sbin/bhyve/pci_hda.c | 1330 +++++++++++++++++++++++++++++++++++ usr.sbin/bhyve/pci_hda.h | 90 +++ 8 files changed, 4377 insertions(+) create mode 100644 usr.sbin/bhyve/audio.c create mode 100644 usr.sbin/bhyve/audio.h create mode 100644 usr.sbin/bhyve/hda_codec.c create mode 100644 usr.sbin/bhyve/hda_reg.h create mode 100644 usr.sbin/bhyve/hdac_reg.h create mode 100644 usr.sbin/bhyve/pci_hda.c create mode 100644 usr.sbin/bhyve/pci_hda.h diff --git a/usr.sbin/bhyve/Makefile b/usr.sbin/bhyve/Makefile index 85fdf11928b1..e203a57c18a3 100644 --- a/usr.sbin/bhyve/Makefile +++ b/usr.sbin/bhyve/Makefile @@ -16,6 +16,7 @@ BHYVE_SYSDIR?=${SRCTOP} SRCS= \ atkbdc.c \ acpi.c \ + audio.c \ bhyvegc.c \ bhyverun.c \ block_if.c \ @@ -27,6 +28,7 @@ SRCS= \ dbgport.c \ fwctl.c \ gdb.c \ + hda_codec.c \ inout.c \ ioapic.c \ mem.c \ @@ -36,6 +38,7 @@ SRCS= \ pci_ahci.c \ pci_e82545.c \ pci_emul.c \ + pci_hda.c \ pci_fbuf.c \ pci_hostbridge.c \ pci_irq.c \ diff --git a/usr.sbin/bhyve/audio.c b/usr.sbin/bhyve/audio.c new file mode 100644 index 000000000000..6a288cbded63 --- /dev/null +++ b/usr.sbin/bhyve/audio.c @@ -0,0 +1,282 @@ +/*- + * Copyright (c) 2016 Alex Teaca + * 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, 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 OR CONTRIBUTORS 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$"); + +#ifndef WITHOUT_CAPSICUM +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "audio.h" +#include "pci_hda.h" + +/* + * Audio Player internal data structures + */ + +struct audio { + int fd; + uint8_t dir; + uint8_t inited; + char dev_name[64]; +}; + +/* + * Audio Player module function definitions + */ + +/* + * audio_init - initialize an instance of audio player + * @dev_name - the backend sound device used to play / capture + * @dir - dir = 1 for write mode, dir = 0 for read mode + */ +struct audio * +audio_init(const char *dev_name, uint8_t dir) +{ + struct audio *aud = NULL; +#ifndef WITHOUT_CAPSICUM + cap_rights_t rights; + cap_ioctl_t cmds[] = { + SNDCTL_DSP_RESET, SNDCTL_DSP_SETFMT, SNDCTL_DSP_CHANNELS, + SNDCTL_DSP_SPEED, +#ifdef DEBUG_HDA + SNDCTL_DSP_GETOSPACE, SNDCTL_DSP_GETISPACE, +#endif + }; +#endif + + assert(dev_name); + + aud = calloc(1, sizeof(*aud)); + if (!aud) + return NULL; + + if (strlen(dev_name) < sizeof(aud->dev_name)) + memcpy(aud->dev_name, dev_name, strlen(dev_name) + 1); + else { + DPRINTF("dev_name too big\n"); + free(aud); + return NULL; + } + + aud->dir = dir; + + aud->fd = open(aud->dev_name, aud->dir ? O_WRONLY : O_RDONLY, 0); + if (aud->fd == -1) { + DPRINTF("Failed to open dev: %s, errno: %d\n", + aud->dev_name, errno); + return (NULL); + } + +#ifndef WITHOUT_CAPSICUM + cap_rights_init(&rights, CAP_IOCTL, CAP_READ, CAP_WRITE); + if (caph_rights_limit(aud->fd, &rights) == -1) + errx(EX_OSERR, "Unable to apply rights for sandbox"); + if (caph_ioctls_limit(aud->fd, cmds, nitems(cmds)) == -1) + errx(EX_OSERR, "Unable to limit ioctl rights for sandbox"); +#endif + + return aud; +} + +/* + * audio_set_params - reset the sound device and set the audio params + * @aud - the audio player to be configured + * @params - the audio parameters to be set + */ +int +audio_set_params(struct audio *aud, struct audio_params *params) +{ + int audio_fd; + int format, channels, rate; + int err; +#if DEBUG_HDA == 1 + audio_buf_info info; +#endif + + assert(aud); + assert(params); + + if ((audio_fd = aud->fd) < 0) { + DPRINTF("Incorrect audio device descriptor for %s\n", + aud->dev_name); + return (-1); + } + + /* Reset the device if it was previously opened */ + if (aud->inited) { + err = ioctl(audio_fd, SNDCTL_DSP_RESET, NULL); + if (err == -1) { + DPRINTF("Failed to reset fd: %d, errno: %d\n", + aud->fd, errno); + return (-1); + } + } else + aud->inited = 1; + + /* Set the Format (Bits per Sample) */ + format = params->format; + err = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format); + if (err == -1) { + DPRINTF("Fail to set fmt: 0x%x errno: %d\n", + params->format, errno); + return -1; + } + + /* The device does not support the requested audio format */ + if (format != params->format) { + DPRINTF("Mismatch format: 0x%x params->format: 0x%x\n", + format, params->format); + return -1; + } + + /* Set the Number of Channels */ + channels = params->channels; + err = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &channels); + if (err == -1) { + DPRINTF("Fail to set channels: %d errno: %d\n", + params->channels, errno); + return -1; + } + + /* The device does not support the requested no. of channels */ + if (channels != params->channels) { + DPRINTF("Mismatch channels: %d params->channels: %d\n", + channels, params->channels); + return -1; + } + + /* Set the Sample Rate / Speed */ + rate = params->rate; + err = ioctl(audio_fd, SNDCTL_DSP_SPEED, &rate); + if (err == -1) { + DPRINTF("Fail to set speed: %d errno: %d\n", + params->rate, errno); + return -1; + } + + /* The device does not support the requested rate / speed */ + if (rate != params->rate) { + DPRINTF("Mismatch rate: %d params->rate: %d\n", + rate, params->rate); + return -1; + } + +#if DEBUG_HDA == 1 + err = ioctl(audio_fd, aud->dir ? SNDCTL_DSP_GETOSPACE : + SNDCTL_DSP_GETISPACE, &info); + if (err == -1) { + DPRINTF("Fail to get audio buf info errno: %d\n", errno); + return -1; + } + DPRINTF("fragstotal: 0x%x fragsize: 0x%x\n", + info.fragstotal, info.fragsize); +#endif + return 0; +} + +/* + * audio_playback - plays samples to the sound device using blocking operations + * @aud - the audio player used to play the samples + * @buf - the buffer containing the samples + * @count - the number of bytes in buffer + */ +int +audio_playback(struct audio *aud, const void *buf, size_t count) +{ + int audio_fd = -1; + ssize_t len = 0, total = 0; + + assert(aud); + assert(aud->dir); + assert(buf); + + audio_fd = aud->fd; + assert(audio_fd != -1); + + total = 0; + while (total < count) { + len = write(audio_fd, buf + total, count - total); + if (len == -1) { + DPRINTF("Fail to write to fd: %d, errno: %d\n", + audio_fd, errno); + return -1; + } + + total += len; + } + + return 0; +} + +/* + * audio_record - records samples from the sound device using + * blocking operations. + * @aud - the audio player used to capture the samples + * @buf - the buffer to receive the samples + * @count - the number of bytes to capture in buffer + * Returns -1 on error and 0 on success + */ +int +audio_record(struct audio *aud, void *buf, size_t count) +{ + int audio_fd = -1; + ssize_t len = 0, total = 0; + + assert(aud); + assert(!aud->dir); + assert(buf); + + audio_fd = aud->fd; + assert(audio_fd != -1); + + total = 0; + while (total < count) { + len = read(audio_fd, buf + total, count - total); + if (len == -1) { + DPRINTF("Fail to write to fd: %d, errno: %d\n", + audio_fd, errno); + return -1; + } + + total += len; + } + + return 0; +} diff --git a/usr.sbin/bhyve/audio.h b/usr.sbin/bhyve/audio.h new file mode 100644 index 000000000000..01ef17071b14 --- /dev/null +++ b/usr.sbin/bhyve/audio.h @@ -0,0 +1,86 @@ +/*- + * Copyright (c) 2016 Alex Teaca + * 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, 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 OR CONTRIBUTORS 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$ + */ + +#ifndef _AUDIO_EMUL_H_ +#define _AUDIO_EMUL_H_ + +#include +#include + +/* + * Audio Player data structures + */ + +struct audio; + +struct audio_params { + int channels; + int format; + int rate; +}; + +/* + * Audio Player API + */ + +/* + * audio_init - initialize an instance of audio player + * @dev_name - the backend sound device used to play / capture + * @dir - dir = 1 for write mode, dir = 0 for read mode + * Returns NULL on error and the address of the audio player instance + */ +struct audio *audio_init(const char *dev_name, uint8_t dir); + +/* + * audio_set_params - reset the sound device and set the audio params + * @aud - the audio player to be configured + * @params - the audio parameters to be set + * Returns -1 on error and 0 on success + */ +int audio_set_params(struct audio *aud, struct audio_params *params); + +/* + * audio_playback - plays samples to the sound device using blocking operations + * @aud - the audio player used to play the samples + * @buf - the buffer containing the samples + * @count - the number of bytes in buffer + * Returns -1 on error and 0 on success + */ +int audio_playback(struct audio *aud, const void *buf, size_t count); + +/* + * audio_record - records samples from the sound device using blocking + * operations. + * @aud - the audio player used to capture the samples + * @buf - the buffer to receive the samples + * @count - the number of bytes to capture in buffer + * Returns -1 on error and 0 on success + */ +int audio_record(struct audio *aud, void *buf, size_t count); + +#endif /* _AUDIO_EMUL_H_ */ diff --git a/usr.sbin/bhyve/hda_codec.c b/usr.sbin/bhyve/hda_codec.c new file mode 100644 index 000000000000..ab53eb036e9f --- /dev/null +++ b/usr.sbin/bhyve/hda_codec.c @@ -0,0 +1,950 @@ +/*- + * Copyright (c) 2016 Alex Teaca + * 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, 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 OR CONTRIBUTORS 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 +#include +#include + +#include "pci_hda.h" +#include "audio.h" + +/* + * HDA Codec defines + */ +#define INTEL_VENDORID 0x8086 + +#define HDA_CODEC_SUBSYSTEM_ID ((INTEL_VENDORID << 16) | 0x01) +#define HDA_CODEC_ROOT_NID 0x00 +#define HDA_CODEC_FG_NID 0x01 +#define HDA_CODEC_AUDIO_OUTPUT_NID 0x02 +#define HDA_CODEC_PIN_OUTPUT_NID 0x03 +#define HDA_CODEC_AUDIO_INPUT_NID 0x04 +#define HDA_CODEC_PIN_INPUT_NID 0x05 + +#define HDA_CODEC_STREAMS_COUNT 0x02 +#define HDA_CODEC_STREAM_OUTPUT 0x00 +#define HDA_CODEC_STREAM_INPUT 0x01 + +#define HDA_CODEC_PARAMS_COUNT 0x14 +#define HDA_CODEC_CONN_LIST_COUNT 0x01 +#define HDA_CODEC_RESPONSE_EX_UNSOL 0x10 +#define HDA_CODEC_RESPONSE_EX_SOL 0x00 +#define HDA_CODEC_AMP_NUMSTEPS 0x4a + +#define HDA_CODEC_SUPP_STREAM_FORMATS_PCM \ + (1 << HDA_PARAM_SUPP_STREAM_FORMATS_PCM_SHIFT) + +#define HDA_CODEC_FMT_BASE_MASK (0x01 << 14) + +#define HDA_CODEC_FMT_MULT_MASK (0x07 << 11) +#define HDA_CODEC_FMT_MULT_2 (0x01 << 11) +#define HDA_CODEC_FMT_MULT_3 (0x02 << 11) +#define HDA_CODEC_FMT_MULT_4 (0x03 << 11) + +#define HDA_CODEC_FMT_DIV_MASK 0x07 +#define HDA_CODEC_FMT_DIV_SHIFT 8 + +#define HDA_CODEC_FMT_BITS_MASK (0x07 << 4) +#define HDA_CODEC_FMT_BITS_8 (0x00 << 4) +#define HDA_CODEC_FMT_BITS_16 (0x01 << 4) +#define HDA_CODEC_FMT_BITS_24 (0x03 << 4) +#define HDA_CODEC_FMT_BITS_32 (0x04 << 4) + +#define HDA_CODEC_FMT_CHAN_MASK (0x0f << 0) + +#define HDA_CODEC_AUDIO_WCAP_OUTPUT \ + (0x00 << HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT) +#define HDA_CODEC_AUDIO_WCAP_INPUT \ + (0x01 << HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT) +#define HDA_CODEC_AUDIO_WCAP_PIN \ + (0x04 << HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT) +#define HDA_CODEC_AUDIO_WCAP_CONN_LIST \ + (1 << HDA_PARAM_AUDIO_WIDGET_CAP_CONN_LIST_SHIFT) +#define HDA_CODEC_AUDIO_WCAP_FORMAT_OVR \ + (1 << HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR_SHIFT) +#define HDA_CODEC_AUDIO_WCAP_AMP_OVR \ + (1 << HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR_SHIFT) +#define HDA_CODEC_AUDIO_WCAP_OUT_AMP \ + (1 << HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP_SHIFT) +#define HDA_CODEC_AUDIO_WCAP_IN_AMP \ + (1 << HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP_SHIFT) +#define HDA_CODEC_AUDIO_WCAP_STEREO \ + (1 << HDA_PARAM_AUDIO_WIDGET_CAP_STEREO_SHIFT) + +#define HDA_CODEC_PIN_CAP_OUTPUT \ + (1 << HDA_PARAM_PIN_CAP_OUTPUT_CAP_SHIFT) +#define HDA_CODEC_PIN_CAP_INPUT \ + (1 << HDA_PARAM_PIN_CAP_INPUT_CAP_SHIFT) +#define HDA_CODEC_PIN_CAP_PRESENCE_DETECT \ + (1 << HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP_SHIFT) + +#define HDA_CODEC_OUTPUT_AMP_CAP_MUTE_CAP \ + (1 << HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP_SHIFT) +#define HDA_CODEC_OUTPUT_AMP_CAP_STEPSIZE \ + (0x03 << HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_SHIFT) +#define HDA_CODEC_OUTPUT_AMP_CAP_NUMSTEPS \ + (HDA_CODEC_AMP_NUMSTEPS << HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_SHIFT) +#define HDA_CODEC_OUTPUT_AMP_CAP_OFFSET \ + (HDA_CODEC_AMP_NUMSTEPS << HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_SHIFT) + +#define HDA_CODEC_SET_AMP_GAIN_MUTE_MUTE 0x80 +#define HDA_CODEC_SET_AMP_GAIN_MUTE_GAIN_MASK 0x7f + +#define HDA_CODEC_PIN_SENSE_PRESENCE_PLUGGED (1 << 31) +#define HDA_CODEC_PIN_WIDGET_CTRL_OUT_ENABLE \ + (1 << HDA_CMD_GET_PIN_WIDGET_CTRL_OUT_ENABLE_SHIFT) +#define HDA_CODEC_PIN_WIDGET_CTRL_IN_ENABLE \ + (1 << HDA_CMD_GET_PIN_WIDGET_CTRL_IN_ENABLE_SHIFT) + +#define HDA_CONFIG_DEFAULTCONF_COLOR_BLACK \ + (0x01 << HDA_CONFIG_DEFAULTCONF_COLOR_SHIFT) +#define HDA_CONFIG_DEFAULTCONF_COLOR_RED \ + (0x05 << HDA_CONFIG_DEFAULTCONF_COLOR_SHIFT) + +#define HDA_CODEC_BUF_SIZE HDA_FIFO_SIZE + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + + +/* + * HDA Audio Context data structures + */ + +typedef void (*transfer_func_t)(void *arg); +typedef int (*setup_func_t)(void *arg); + +struct hda_audio_ctxt { + char name[64]; + uint8_t run; + uint8_t started; + void *priv; + pthread_t tid; + pthread_mutex_t mtx; + pthread_cond_t cond; + setup_func_t do_setup; + transfer_func_t do_transfer; +}; + +/* + * HDA Audio Context module function declarations + */ + +static void *hda_audio_ctxt_thr(void *arg); +static int hda_audio_ctxt_init(struct hda_audio_ctxt *actx, const char *tname, + transfer_func_t do_transfer, setup_func_t do_setup, void *priv); +static int hda_audio_ctxt_start(struct hda_audio_ctxt *actx); +static int hda_audio_ctxt_stop(struct hda_audio_ctxt *actx); + +/* + * HDA Codec data structures + */ + +struct hda_codec_softc; + +typedef uint32_t (*verb_func_t)(struct hda_codec_softc *sc, uint16_t verb, + uint16_t payload); + +struct hda_codec_stream { + uint8_t buf[HDA_CODEC_BUF_SIZE]; + uint8_t channel; + uint16_t fmt; + uint8_t stream; + + uint8_t left_gain; + uint8_t right_gain; + uint8_t left_mute; + uint8_t right_mute; + + struct audio *aud; + struct hda_audio_ctxt actx; +}; + +struct hda_codec_softc { + uint32_t no_nodes; + uint32_t subsystem_id; + const uint32_t (*get_parameters)[HDA_CODEC_PARAMS_COUNT]; + const uint8_t (*conn_list)[HDA_CODEC_CONN_LIST_COUNT]; + const uint32_t *conf_default; + const uint8_t *pin_ctrl_default; + const verb_func_t *verb_handlers; + + struct hda_codec_inst *hci; + struct hda_codec_stream streams[HDA_CODEC_STREAMS_COUNT]; +}; + +/* + * HDA Codec module function declarations + */ +static int hda_codec_init(struct hda_codec_inst *hci, const char *play, + const char *rec, const char *opts); +static int hda_codec_reset(struct hda_codec_inst *hci); +static int hda_codec_command(struct hda_codec_inst *hci, uint32_t cmd_data); +static int hda_codec_notify(struct hda_codec_inst *hci, uint8_t run, + uint8_t stream, uint8_t dir); + +static int hda_codec_parse_format(uint16_t fmt, struct audio_params *params); + +static uint32_t hda_codec_audio_output_nid(struct hda_codec_softc *sc, + uint16_t verb, uint16_t payload); +static void hda_codec_audio_output_do_transfer(void *arg); +static int hda_codec_audio_output_do_setup(void *arg); +static uint32_t hda_codec_audio_input_nid(struct hda_codec_softc *sc, + uint16_t verb, uint16_t payload); +static void hda_codec_audio_input_do_transfer(void *arg); +static int hda_codec_audio_input_do_setup(void *arg); + +static uint32_t hda_codec_audio_inout_nid(struct hda_codec_stream *st, + uint16_t verb, uint16_t payload); + +/* + * HDA Codec global data + */ + +#define HDA_CODEC_ROOT_DESC \ + [HDA_CODEC_ROOT_NID] = { \ + [HDA_PARAM_VENDOR_ID] = INTEL_VENDORID, \ + [HDA_PARAM_REVISION_ID] = 0xffff, \ + /* 1 Subnode, StartNid = 1 */ \ + [HDA_PARAM_SUB_NODE_COUNT] = 0x00010001, \ + }, \ + +#define HDA_CODEC_FG_COMMON_DESC \ + [HDA_PARAM_FCT_GRP_TYPE] = HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO,\ + /* B8 - B32, 8.0 - 192.0kHz */ \ + [HDA_PARAM_SUPP_PCM_SIZE_RATE] = (0x1f << 16) | 0x7ff, \ + [HDA_PARAM_SUPP_STREAM_FORMATS] = HDA_CODEC_SUPP_STREAM_FORMATS_PCM,\ + [HDA_PARAM_INPUT_AMP_CAP] = 0x00, /* None */ \ + [HDA_PARAM_OUTPUT_AMP_CAP] = 0x00, /* None */ \ + [HDA_PARAM_GPIO_COUNT] = 0x00, \ + +#define HDA_CODEC_FG_OUTPUT_DESC \ + [HDA_CODEC_FG_NID] = { \ + /* 2 Subnodes, StartNid = 2 */ \ + [HDA_PARAM_SUB_NODE_COUNT] = 0x00020002, \ + HDA_CODEC_FG_COMMON_DESC \ + }, \ + +#define HDA_CODEC_FG_INPUT_DESC \ + [HDA_CODEC_FG_NID] = { \ + /* 2 Subnodes, StartNid = 4 */ \ + [HDA_PARAM_SUB_NODE_COUNT] = 0x00040002, \ + HDA_CODEC_FG_COMMON_DESC \ + }, \ + +#define HDA_CODEC_FG_DUPLEX_DESC \ + [HDA_CODEC_FG_NID] = { \ + /* 4 Subnodes, StartNid = 2 */ \ + [HDA_PARAM_SUB_NODE_COUNT] = 0x00020004, \ + HDA_CODEC_FG_COMMON_DESC \ + }, \ + +#define HDA_CODEC_OUTPUT_DESC \ + [HDA_CODEC_AUDIO_OUTPUT_NID] = { \ + [HDA_PARAM_AUDIO_WIDGET_CAP] = \ + HDA_CODEC_AUDIO_WCAP_OUTPUT | \ + HDA_CODEC_AUDIO_WCAP_FORMAT_OVR | \ + HDA_CODEC_AUDIO_WCAP_AMP_OVR | \ + HDA_CODEC_AUDIO_WCAP_OUT_AMP | \ + HDA_CODEC_AUDIO_WCAP_STEREO, \ + /* B16, 16.0 - 192.0kHz */ \ + [HDA_PARAM_SUPP_PCM_SIZE_RATE] = (0x02 << 16) | 0x7fc, \ + [HDA_PARAM_SUPP_STREAM_FORMATS] = \ + HDA_CODEC_SUPP_STREAM_FORMATS_PCM, \ + [HDA_PARAM_INPUT_AMP_CAP] = 0x00, /* None */ \ + [HDA_PARAM_CONN_LIST_LENGTH] = 0x00, \ + [HDA_PARAM_OUTPUT_AMP_CAP] = \ + HDA_CODEC_OUTPUT_AMP_CAP_MUTE_CAP | \ + HDA_CODEC_OUTPUT_AMP_CAP_STEPSIZE | \ + HDA_CODEC_OUTPUT_AMP_CAP_NUMSTEPS | \ + HDA_CODEC_OUTPUT_AMP_CAP_OFFSET, \ + }, \ + [HDA_CODEC_PIN_OUTPUT_NID] = { \ + [HDA_PARAM_AUDIO_WIDGET_CAP] = \ + HDA_CODEC_AUDIO_WCAP_PIN | \ + HDA_CODEC_AUDIO_WCAP_CONN_LIST | \ + HDA_CODEC_AUDIO_WCAP_STEREO, \ + [HDA_PARAM_PIN_CAP] = HDA_CODEC_PIN_CAP_OUTPUT | \ + HDA_CODEC_PIN_CAP_PRESENCE_DETECT,\ + [HDA_PARAM_INPUT_AMP_CAP] = 0x00, /* None */ \ + [HDA_PARAM_CONN_LIST_LENGTH] = 0x01, \ + [HDA_PARAM_OUTPUT_AMP_CAP] = 0x00, /* None */ \ + }, \ + +#define HDA_CODEC_INPUT_DESC \ + [HDA_CODEC_AUDIO_INPUT_NID] = { \ + [HDA_PARAM_AUDIO_WIDGET_CAP] = \ + HDA_CODEC_AUDIO_WCAP_INPUT | \ + HDA_CODEC_AUDIO_WCAP_CONN_LIST | \ + HDA_CODEC_AUDIO_WCAP_FORMAT_OVR | \ + HDA_CODEC_AUDIO_WCAP_AMP_OVR | \ + HDA_CODEC_AUDIO_WCAP_IN_AMP | \ + HDA_CODEC_AUDIO_WCAP_STEREO, \ + /* B16, 16.0 - 192.0kHz */ \ + [HDA_PARAM_SUPP_PCM_SIZE_RATE] = (0x02 << 16) | 0x7fc, \ + [HDA_PARAM_SUPP_STREAM_FORMATS] = \ + HDA_CODEC_SUPP_STREAM_FORMATS_PCM, \ + [HDA_PARAM_OUTPUT_AMP_CAP] = 0x00, /* None */ \ + [HDA_PARAM_CONN_LIST_LENGTH] = 0x01, \ + [HDA_PARAM_INPUT_AMP_CAP] = \ + HDA_CODEC_OUTPUT_AMP_CAP_MUTE_CAP | \ + HDA_CODEC_OUTPUT_AMP_CAP_STEPSIZE | \ + HDA_CODEC_OUTPUT_AMP_CAP_NUMSTEPS | \ + HDA_CODEC_OUTPUT_AMP_CAP_OFFSET, \ + }, \ + [HDA_CODEC_PIN_INPUT_NID] = { \ + [HDA_PARAM_AUDIO_WIDGET_CAP] = \ + HDA_CODEC_AUDIO_WCAP_PIN | \ + HDA_CODEC_AUDIO_WCAP_STEREO, \ + [HDA_PARAM_PIN_CAP] = HDA_CODEC_PIN_CAP_INPUT | \ + HDA_CODEC_PIN_CAP_PRESENCE_DETECT, \ + [HDA_PARAM_INPUT_AMP_CAP] = 0x00, /* None */ \ + [HDA_PARAM_OUTPUT_AMP_CAP] = 0x00, /* None */ \ + }, \ + +static const uint32_t +hda_codec_output_parameters[][HDA_CODEC_PARAMS_COUNT] = { + HDA_CODEC_ROOT_DESC + HDA_CODEC_FG_OUTPUT_DESC + HDA_CODEC_OUTPUT_DESC +}; + +static const uint32_t +hda_codec_input_parameters[][HDA_CODEC_PARAMS_COUNT] = { + HDA_CODEC_ROOT_DESC + HDA_CODEC_FG_INPUT_DESC + HDA_CODEC_INPUT_DESC +}; + +static const uint32_t +hda_codec_duplex_parameters[][HDA_CODEC_PARAMS_COUNT] = { + HDA_CODEC_ROOT_DESC + HDA_CODEC_FG_DUPLEX_DESC + HDA_CODEC_OUTPUT_DESC + HDA_CODEC_INPUT_DESC +}; + +#define HDA_CODEC_NODES_COUNT (ARRAY_SIZE(hda_codec_duplex_parameters)) + +static const uint8_t +hda_codec_conn_list[HDA_CODEC_NODES_COUNT][HDA_CODEC_CONN_LIST_COUNT] = { + [HDA_CODEC_PIN_OUTPUT_NID] = {HDA_CODEC_AUDIO_OUTPUT_NID}, + [HDA_CODEC_AUDIO_INPUT_NID] = {HDA_CODEC_PIN_INPUT_NID}, +}; + +static const uint32_t +hda_codec_conf_default[HDA_CODEC_NODES_COUNT] = { + [HDA_CODEC_PIN_OUTPUT_NID] = \ + HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK | + HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT | + HDA_CONFIG_DEFAULTCONF_COLOR_BLACK | + (0x01 << HDA_CONFIG_DEFAULTCONF_ASSOCIATION_SHIFT), + [HDA_CODEC_PIN_INPUT_NID] = HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK | + HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN | + HDA_CONFIG_DEFAULTCONF_COLOR_RED | + (0x02 << HDA_CONFIG_DEFAULTCONF_ASSOCIATION_SHIFT), +}; + +static const uint8_t +hda_codec_pin_ctrl_default[HDA_CODEC_NODES_COUNT] = { + [HDA_CODEC_PIN_OUTPUT_NID] = HDA_CODEC_PIN_WIDGET_CTRL_OUT_ENABLE, + [HDA_CODEC_PIN_INPUT_NID] = HDA_CODEC_PIN_WIDGET_CTRL_IN_ENABLE, +}; + +static const +verb_func_t hda_codec_verb_handlers[HDA_CODEC_NODES_COUNT] = { + [HDA_CODEC_AUDIO_OUTPUT_NID] = hda_codec_audio_output_nid, + [HDA_CODEC_AUDIO_INPUT_NID] = hda_codec_audio_input_nid, +}; + +/* + * HDA Codec module function definitions + */ + +static int +hda_codec_init(struct hda_codec_inst *hci, const char *play, + const char *rec, const char *opts) +{ + struct hda_codec_softc *sc = NULL; + struct hda_codec_stream *st = NULL; + int err; + + if (!(play || rec)) + return (-1); + + DPRINTF("cad: 0x%x opts: %s\n", hci->cad, opts); + + sc = calloc(1, sizeof(*sc)); + if (!sc) + return (-1); + + if (play && rec) + sc->get_parameters = hda_codec_duplex_parameters; + else { + if (play) + sc->get_parameters = hda_codec_output_parameters; + else + sc->get_parameters = hda_codec_input_parameters; + } + sc->subsystem_id = HDA_CODEC_SUBSYSTEM_ID; + sc->no_nodes = HDA_CODEC_NODES_COUNT; + sc->conn_list = hda_codec_conn_list; + sc->conf_default = hda_codec_conf_default; + sc->pin_ctrl_default = hda_codec_pin_ctrl_default; + sc->verb_handlers = hda_codec_verb_handlers; + DPRINTF("HDA Codec nodes: %d\n", sc->no_nodes); + + /* + * Initialize the Audio Output stream + */ + if (play) { + st = &sc->streams[HDA_CODEC_STREAM_OUTPUT]; + + err = hda_audio_ctxt_init(&st->actx, "hda-audio-output", + hda_codec_audio_output_do_transfer, + hda_codec_audio_output_do_setup, sc); + assert(!err); + + st->aud = audio_init(play, 1); + if (!st->aud) { + DPRINTF("Fail to init the output audio player\n"); + return (-1); + } + } + + /* + * Initialize the Audio Input stream + */ + if (rec) { + st = &sc->streams[HDA_CODEC_STREAM_INPUT]; + + err = hda_audio_ctxt_init(&st->actx, "hda-audio-input", + hda_codec_audio_input_do_transfer, + hda_codec_audio_input_do_setup, sc); + assert(!err); + + st->aud = audio_init(rec, 0); + if (!st->aud) { + DPRINTF("Fail to init the input audio player\n"); + return (-1); + } + } + + sc->hci = hci; + hci->priv = sc; + + return (0); +} + +static int +hda_codec_reset(struct hda_codec_inst *hci) +{ + struct hda_ops *hops = NULL; + struct hda_codec_softc *sc = NULL; + struct hda_codec_stream *st = NULL; + int i; + + assert(hci); + + hops = hci->hops; + assert(hops); + + sc = (struct hda_codec_softc *)hci->priv; + assert(sc); + + for (i = 0; i < HDA_CODEC_STREAMS_COUNT; i++) { + st = &sc->streams[i]; + st->left_gain = HDA_CODEC_AMP_NUMSTEPS; + st->right_gain = HDA_CODEC_AMP_NUMSTEPS; + st->left_mute = HDA_CODEC_SET_AMP_GAIN_MUTE_MUTE; + st->right_mute = HDA_CODEC_SET_AMP_GAIN_MUTE_MUTE; + } + + DPRINTF("cad: 0x%x\n", hci->cad); + + if (!hops->signal) { + DPRINTF("The controller ops does not implement \ + the signal function\n"); + return (-1); + } + + return (hops->signal(hci)); +} + +static int +hda_codec_command(struct hda_codec_inst *hci, uint32_t cmd_data) +{ + struct hda_codec_softc *sc = NULL; + struct hda_ops *hops = NULL; + uint8_t cad = 0, nid = 0; + uint16_t verb = 0, payload = 0; + uint32_t res = 0; + + /* 4 bits */ + cad = (cmd_data >> HDA_CMD_CAD_SHIFT) & 0x0f; + /* 8 bits */ + nid = (cmd_data >> HDA_CMD_NID_SHIFT) & 0xff; + + if ((cmd_data & 0x70000) == 0x70000) { + /* 12 bits */ + verb = (cmd_data >> HDA_CMD_VERB_12BIT_SHIFT) & 0x0fff; + /* 8 bits */ + payload = cmd_data & 0xff; + } else { + /* 4 bits */ + verb = (cmd_data >> HDA_CMD_VERB_4BIT_SHIFT) & 0x0f; + /* 16 bits */ + payload = cmd_data & 0xffff; + } + + assert(cad == hci->cad); + assert(hci); + + hops = hci->hops; + assert(hops); + + sc = (struct hda_codec_softc *)hci->priv; + assert(sc); + + assert(nid < sc->no_nodes); + + if (!hops->response) { + DPRINTF("The controller ops does not implement \ + the response function\n"); + return (-1); + } + + switch (verb) { + case HDA_CMD_VERB_GET_PARAMETER: + res = sc->get_parameters[nid][payload]; + break; + case HDA_CMD_VERB_GET_CONN_LIST_ENTRY: + res = sc->conn_list[nid][0]; + break; + case HDA_CMD_VERB_GET_PIN_WIDGET_CTRL: + res = sc->pin_ctrl_default[nid]; + break; + case HDA_CMD_VERB_GET_PIN_SENSE: + res = HDA_CODEC_PIN_SENSE_PRESENCE_PLUGGED; + break; + case HDA_CMD_VERB_GET_CONFIGURATION_DEFAULT: + res = sc->conf_default[nid]; + break; + case HDA_CMD_VERB_GET_SUBSYSTEM_ID: + res = sc->subsystem_id; + break; + default: + assert(sc->verb_handlers); + if (sc->verb_handlers[nid]) + res = sc->verb_handlers[nid](sc, verb, payload); + else + DPRINTF("Unknown VERB: 0x%x\n", verb); + break; + } + + DPRINTF("cad: 0x%x nid: 0x%x verb: 0x%x payload: 0x%x response: 0x%x\n", + cad, nid, verb, payload, res); + + return (hops->response(hci, res, HDA_CODEC_RESPONSE_EX_SOL)); +} + +static int +hda_codec_notify(struct hda_codec_inst *hci, uint8_t run, + uint8_t stream, uint8_t dir) +{ + struct hda_codec_softc *sc = NULL; + struct hda_codec_stream *st = NULL; + struct hda_audio_ctxt *actx = NULL; + int i; + int err; + + assert(hci); + assert(stream); + + sc = (struct hda_codec_softc *)hci->priv; + assert(sc); + + i = dir ? HDA_CODEC_STREAM_OUTPUT : HDA_CODEC_STREAM_INPUT; + st = &sc->streams[i]; + + DPRINTF("run: %d, stream: 0x%x, st->stream: 0x%x dir: %d\n", + run, stream, st->stream, dir); + + if (stream != st->stream) { + DPRINTF("Stream not found\n"); + return (0); + } + + actx = &st->actx; + + if (run) + err = hda_audio_ctxt_start(actx); + else + err = hda_audio_ctxt_stop(actx); + + return (err); +} + +static int +hda_codec_parse_format(uint16_t fmt, struct audio_params *params) +{ + uint8_t div = 0; + + assert(params); + + /* Compute the Sample Rate */ + params->rate = (fmt & HDA_CODEC_FMT_BASE_MASK) ? 44100 : 48000; + + switch (fmt & HDA_CODEC_FMT_MULT_MASK) { + case HDA_CODEC_FMT_MULT_2: + params->rate *= 2; + break; + case HDA_CODEC_FMT_MULT_3: + params->rate *= 3; + break; + case HDA_CODEC_FMT_MULT_4: + params->rate *= 4; + break; + } + + div = (fmt >> HDA_CODEC_FMT_DIV_SHIFT) & HDA_CODEC_FMT_DIV_MASK; + params->rate /= (div + 1); + + /* Compute the Bits per Sample */ + switch (fmt & HDA_CODEC_FMT_BITS_MASK) { + case HDA_CODEC_FMT_BITS_8: + params->format = AFMT_U8; + break; + case HDA_CODEC_FMT_BITS_16: + params->format = AFMT_S16_LE; + break; + case HDA_CODEC_FMT_BITS_24: + params->format = AFMT_S24_LE; + break; + case HDA_CODEC_FMT_BITS_32: + params->format = AFMT_S32_LE; + break; + default: + DPRINTF("Unknown format bits: 0x%x\n", + fmt & HDA_CODEC_FMT_BITS_MASK); + return (-1); + } + + /* Compute the Number of Channels */ + params->channels = (fmt & HDA_CODEC_FMT_CHAN_MASK) + 1; + + return (0); +} + +static uint32_t +hda_codec_audio_output_nid(struct hda_codec_softc *sc, uint16_t verb, + uint16_t payload) +{ + struct hda_codec_stream *st = &sc->streams[HDA_CODEC_STREAM_OUTPUT]; + int res; + + res = hda_codec_audio_inout_nid(st, verb, payload); + + return (res); +} + +static void +hda_codec_audio_output_do_transfer(void *arg) +{ + struct hda_codec_softc *sc = (struct hda_codec_softc *)arg; + struct hda_codec_inst *hci = NULL; + struct hda_ops *hops = NULL; + struct hda_codec_stream *st = NULL; + struct audio *aud = NULL; + int err; + + hci = sc->hci; + assert(hci); + + hops = hci->hops; + assert(hops); + + st = &sc->streams[HDA_CODEC_STREAM_OUTPUT]; + aud = st->aud; + + err = hops->transfer(hci, st->stream, 1, st->buf, sizeof(st->buf)); + if (err) + return; + + err = audio_playback(aud, st->buf, sizeof(st->buf)); + assert(!err); +} + +static int +hda_codec_audio_output_do_setup(void *arg) +{ + struct hda_codec_softc *sc = (struct hda_codec_softc *)arg; + struct hda_codec_stream *st = NULL; + struct audio *aud = NULL; + struct audio_params params; + int err; + + st = &sc->streams[HDA_CODEC_STREAM_OUTPUT]; + aud = st->aud; + + err = hda_codec_parse_format(st->fmt, ¶ms); + if (err) + return (-1); + + DPRINTF("rate: %d, channels: %d, format: 0x%x\n", + params.rate, params.channels, params.format); + + return (audio_set_params(aud, ¶ms)); +} + +static uint32_t +hda_codec_audio_input_nid(struct hda_codec_softc *sc, uint16_t verb, + uint16_t payload) +{ + struct hda_codec_stream *st = &sc->streams[HDA_CODEC_STREAM_INPUT]; + int res; + + res = hda_codec_audio_inout_nid(st, verb, payload); + + return (res); +} + +static void +hda_codec_audio_input_do_transfer(void *arg) +{ + struct hda_codec_softc *sc = (struct hda_codec_softc *)arg; + struct hda_codec_inst *hci = NULL; + struct hda_ops *hops = NULL; + struct hda_codec_stream *st = NULL; + struct audio *aud = NULL; + int err; + + hci = sc->hci; + assert(hci); + + hops = hci->hops; + assert(hops); + + st = &sc->streams[HDA_CODEC_STREAM_INPUT]; + aud = st->aud; + + err = audio_record(aud, st->buf, sizeof(st->buf)); + assert(!err); + + hops->transfer(hci, st->stream, 0, st->buf, sizeof(st->buf)); +} + +static int +hda_codec_audio_input_do_setup(void *arg) +{ + struct hda_codec_softc *sc = (struct hda_codec_softc *)arg; + struct hda_codec_stream *st = NULL; + struct audio *aud = NULL; + struct audio_params params; + int err; + + st = &sc->streams[HDA_CODEC_STREAM_INPUT]; + aud = st->aud; + + err = hda_codec_parse_format(st->fmt, ¶ms); + if (err) + return (-1); + + DPRINTF("rate: %d, channels: %d, format: 0x%x\n", + params.rate, params.channels, params.format); + + return (audio_set_params(aud, ¶ms)); +} + +static uint32_t +hda_codec_audio_inout_nid(struct hda_codec_stream *st, uint16_t verb, + uint16_t payload) +{ + uint32_t res = 0; + uint8_t mute = 0; + uint8_t gain = 0; + + DPRINTF("%s verb: 0x%x, payload, 0x%x\n", st->actx.name, verb, payload); + + switch (verb) { + case HDA_CMD_VERB_GET_CONV_FMT: + res = st->fmt; + break; + case HDA_CMD_VERB_SET_CONV_FMT: + st->fmt = payload; + break; + case HDA_CMD_VERB_GET_AMP_GAIN_MUTE: + if (payload & HDA_CMD_GET_AMP_GAIN_MUTE_LEFT) { + res = st->left_gain | st->left_mute; + DPRINTF("GET_AMP_GAIN_MUTE_LEFT: 0x%x\n", res); + } else { + res = st->right_gain | st->right_mute; + DPRINTF("GET_AMP_GAIN_MUTE_RIGHT: 0x%x\n", res); + } + break; + case HDA_CMD_VERB_SET_AMP_GAIN_MUTE: + mute = payload & HDA_CODEC_SET_AMP_GAIN_MUTE_MUTE; + gain = payload & HDA_CODEC_SET_AMP_GAIN_MUTE_GAIN_MASK; + + if (payload & HDA_CMD_SET_AMP_GAIN_MUTE_LEFT) { + st->left_mute = mute; + st->left_gain = gain; + DPRINTF("SET_AMP_GAIN_MUTE_LEFT: \ + mute: 0x%x gain: 0x%x\n", mute, gain); + } + + if (payload & HDA_CMD_SET_AMP_GAIN_MUTE_RIGHT) { + st->right_mute = mute; + st->right_gain = gain; + DPRINTF("SET_AMP_GAIN_MUTE_RIGHT: \ + mute: 0x%x gain: 0x%x\n", mute, gain); + } + break; + case HDA_CMD_VERB_GET_CONV_STREAM_CHAN: + res = (st->stream << 4) | st->channel; + break; + case HDA_CMD_VERB_SET_CONV_STREAM_CHAN: + st->channel = payload & 0x0f; + st->stream = (payload >> 4) & 0x0f; + DPRINTF("st->channel: 0x%x st->stream: 0x%x\n", + st->channel, st->stream); + if (!st->stream) + hda_audio_ctxt_stop(&st->actx); + break; + default: + DPRINTF("Unknown VERB: 0x%x\n", verb); + break; + } + + return (res); +} + +struct hda_codec_class hda_codec = { + .name = "hda_codec", + .init = hda_codec_init, + .reset = hda_codec_reset, + .command = hda_codec_command, + .notify = hda_codec_notify, +}; + +HDA_EMUL_SET(hda_codec); + + +/* + * HDA Audio Context module function definitions + */ + +static void * +hda_audio_ctxt_thr(void *arg) +{ + struct hda_audio_ctxt *actx = arg; + + DPRINTF("Start Thread: %s\n", actx->name); + + pthread_mutex_lock(&actx->mtx); + while (1) { + while (!actx->run) + pthread_cond_wait(&actx->cond, &actx->mtx); + + actx->do_transfer(actx->priv); + } + pthread_mutex_unlock(&actx->mtx); + + pthread_exit(NULL); + return (NULL); +} + +static int +hda_audio_ctxt_init(struct hda_audio_ctxt *actx, const char *tname, + transfer_func_t do_transfer, setup_func_t do_setup, void *priv) +{ + int err; + + assert(actx); + assert(tname); + assert(do_transfer); + assert(do_setup); + assert(priv); + + memset(actx, 0, sizeof(*actx)); + + actx->run = 0; + actx->do_transfer = do_transfer; + actx->do_setup = do_setup; + actx->priv = priv; + if (strlen(tname) < sizeof(actx->name)) + memcpy(actx->name, tname, strlen(tname) + 1); + else + strcpy(actx->name, "unknown"); + + err = pthread_mutex_init(&actx->mtx, NULL); + assert(!err); + + err = pthread_cond_init(&actx->cond, NULL); + assert(!err); + + err = pthread_create(&actx->tid, NULL, hda_audio_ctxt_thr, actx); + assert(!err); + + pthread_set_name_np(actx->tid, tname); + + actx->started = 1; + + return (0); +} + +static int +hda_audio_ctxt_start(struct hda_audio_ctxt *actx) +{ + int err = 0; + + assert(actx); + assert(actx->started); + + /* The stream is supposed to be stopped */ + if (actx->run) + return (-1); + + pthread_mutex_lock(&actx->mtx); + err = (* actx->do_setup)(actx->priv); + if (!err) { + actx->run = 1; + pthread_cond_signal(&actx->cond); + } + pthread_mutex_unlock(&actx->mtx); + + return (err); +} + +static int +hda_audio_ctxt_stop(struct hda_audio_ctxt *actx) +{ + actx->run = 0; + return (0); +} diff --git a/usr.sbin/bhyve/hda_reg.h b/usr.sbin/bhyve/hda_reg.h new file mode 100644 index 000000000000..dd7098524537 --- /dev/null +++ b/usr.sbin/bhyve/hda_reg.h @@ -0,0 +1,1367 @@ +/*- + * Copyright (c) 2006 Stephane E. Potvin + * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$ + */ + +#ifndef _HDA_REG_H_ +#define _HDA_REG_H_ + +/**************************************************************************** + * HDA Device Verbs + ****************************************************************************/ + +/* HDA Command */ +#define HDA_CMD_VERB_MASK 0x000fffff +#define HDA_CMD_VERB_SHIFT 0 +#define HDA_CMD_NID_MASK 0x0ff00000 +#define HDA_CMD_NID_SHIFT 20 +#define HDA_CMD_CAD_MASK 0xf0000000 +#define HDA_CMD_CAD_SHIFT 28 + +#define HDA_CMD_VERB_4BIT_SHIFT 16 +#define HDA_CMD_VERB_12BIT_SHIFT 8 + +#define HDA_CMD_VERB_4BIT(verb, payload) \ + (((verb) << HDA_CMD_VERB_4BIT_SHIFT) | (payload)) +#define HDA_CMD_4BIT(cad, nid, verb, payload) \ + (((cad) << HDA_CMD_CAD_SHIFT) | \ + ((nid) << HDA_CMD_NID_SHIFT) | \ + (HDA_CMD_VERB_4BIT((verb), (payload)))) + +#define HDA_CMD_VERB_12BIT(verb, payload) \ + (((verb) << HDA_CMD_VERB_12BIT_SHIFT) | (payload)) +#define HDA_CMD_12BIT(cad, nid, verb, payload) \ + (((cad) << HDA_CMD_CAD_SHIFT) | \ + ((nid) << HDA_CMD_NID_SHIFT) | \ + (HDA_CMD_VERB_12BIT((verb), (payload)))) + +/* Get Parameter */ +#define HDA_CMD_VERB_GET_PARAMETER 0xf00 + +#define HDA_CMD_GET_PARAMETER(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_PARAMETER, (payload))) + +/* Connection Select Control */ +#define HDA_CMD_VERB_GET_CONN_SELECT_CONTROL 0xf01 +#define HDA_CMD_VERB_SET_CONN_SELECT_CONTROL 0x701 + +#define HDA_CMD_GET_CONN_SELECT_CONTROL(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_CONN_SELECT_CONTROL, 0x0)) +#define HDA_CMD_SET_CONNECTION_SELECT_CONTROL(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_CONN_SELECT_CONTROL, (payload))) + +/* Connection List Entry */ +#define HDA_CMD_VERB_GET_CONN_LIST_ENTRY 0xf02 + +#define HDA_CMD_GET_CONN_LIST_ENTRY(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_CONN_LIST_ENTRY, (payload))) + +#define HDA_CMD_GET_CONN_LIST_ENTRY_SIZE_SHORT 1 +#define HDA_CMD_GET_CONN_LIST_ENTRY_SIZE_LONG 2 + +/* Processing State */ +#define HDA_CMD_VERB_GET_PROCESSING_STATE 0xf03 +#define HDA_CMD_VERB_SET_PROCESSING_STATE 0x703 + +#define HDA_CMD_GET_PROCESSING_STATE(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_PROCESSING_STATE, 0x0)) +#define HDA_CMD_SET_PROCESSING_STATE(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_PROCESSING_STATE, (payload))) + +#define HDA_CMD_GET_PROCESSING_STATE_STATE_OFF 0x00 +#define HDA_CMD_GET_PROCESSING_STATE_STATE_ON 0x01 +#define HDA_CMD_GET_PROCESSING_STATE_STATE_BENIGN 0x02 + +/* Coefficient Index */ +#define HDA_CMD_VERB_GET_COEFF_INDEX 0xd +#define HDA_CMD_VERB_SET_COEFF_INDEX 0x5 + +#define HDA_CMD_GET_COEFF_INDEX(cad, nid) \ + (HDA_CMD_4BIT((cad), (nid), \ + HDA_CMD_VERB_GET_COEFF_INDEX, 0x0)) +#define HDA_CMD_SET_COEFF_INDEX(cad, nid, payload) \ + (HDA_CMD_4BIT((cad), (nid), \ + HDA_CMD_VERB_SET_COEFF_INDEX, (payload))) + +/* Processing Coefficient */ +#define HDA_CMD_VERB_GET_PROCESSING_COEFF 0xc +#define HDA_CMD_VERB_SET_PROCESSING_COEFF 0x4 + +#define HDA_CMD_GET_PROCESSING_COEFF(cad, nid) \ + (HDA_CMD_4BIT((cad), (nid), \ + HDA_CMD_VERB_GET_PROCESSING_COEFF, 0x0)) +#define HDA_CMD_SET_PROCESSING_COEFF(cad, nid, payload) \ + (HDA_CMD_4BIT((cad), (nid), \ + HDA_CMD_VERB_SET_PROCESSING_COEFF, (payload))) + +/* Amplifier Gain/Mute */ +#define HDA_CMD_VERB_GET_AMP_GAIN_MUTE 0xb +#define HDA_CMD_VERB_SET_AMP_GAIN_MUTE 0x3 + +#define HDA_CMD_GET_AMP_GAIN_MUTE(cad, nid, payload) \ + (HDA_CMD_4BIT((cad), (nid), \ + HDA_CMD_VERB_GET_AMP_GAIN_MUTE, (payload))) +#define HDA_CMD_SET_AMP_GAIN_MUTE(cad, nid, payload) \ + (HDA_CMD_4BIT((cad), (nid), \ + HDA_CMD_VERB_SET_AMP_GAIN_MUTE, (payload))) + +#define HDA_CMD_GET_AMP_GAIN_MUTE_INPUT 0x0000 +#define HDA_CMD_GET_AMP_GAIN_MUTE_OUTPUT 0x8000 +#define HDA_CMD_GET_AMP_GAIN_MUTE_RIGHT 0x0000 +#define HDA_CMD_GET_AMP_GAIN_MUTE_LEFT 0x2000 + +#define HDA_CMD_GET_AMP_GAIN_MUTE_MUTE_MASK 0x00000008 +#define HDA_CMD_GET_AMP_GAIN_MUTE_MUTE_SHIFT 7 +#define HDA_CMD_GET_AMP_GAIN_MUTE_GAIN_MASK 0x00000007 +#define HDA_CMD_GET_AMP_GAIN_MUTE_GAIN_SHIFT 0 + +#define HDA_CMD_GET_AMP_GAIN_MUTE_MUTE(rsp) \ + (((rsp) & HDA_CMD_GET_AMP_GAIN_MUTE_MUTE_MASK) >> \ + HDA_CMD_GET_AMP_GAIN_MUTE_MUTE_SHIFT) +#define HDA_CMD_GET_AMP_GAIN_MUTE_GAIN(rsp) \ + (((rsp) & HDA_CMD_GET_AMP_GAIN_MUTE_GAIN_MASK) >> \ + HDA_CMD_GET_AMP_GAIN_MUTE_GAIN_SHIFT) + +#define HDA_CMD_SET_AMP_GAIN_MUTE_OUTPUT 0x8000 +#define HDA_CMD_SET_AMP_GAIN_MUTE_INPUT 0x4000 +#define HDA_CMD_SET_AMP_GAIN_MUTE_LEFT 0x2000 +#define HDA_CMD_SET_AMP_GAIN_MUTE_RIGHT 0x1000 +#define HDA_CMD_SET_AMP_GAIN_MUTE_INDEX_MASK 0x0f00 +#define HDA_CMD_SET_AMP_GAIN_MUTE_INDEX_SHIFT 8 +#define HDA_CMD_SET_AMP_GAIN_MUTE_MUTE 0x0080 +#define HDA_CMD_SET_AMP_GAIN_MUTE_GAIN_MASK 0x0007 +#define HDA_CMD_SET_AMP_GAIN_MUTE_GAIN_SHIFT 0 + +#define HDA_CMD_SET_AMP_GAIN_MUTE_INDEX(index) \ + (((index) << HDA_CMD_SET_AMP_GAIN_MUTE_INDEX_SHIFT) & \ + HDA_CMD_SET_AMP_GAIN_MUTE_INDEX_MASK) +#define HDA_CMD_SET_AMP_GAIN_MUTE_GAIN(index) \ + (((index) << HDA_CMD_SET_AMP_GAIN_MUTE_GAIN_SHIFT) & \ + HDA_CMD_SET_AMP_GAIN_MUTE_GAIN_MASK) + +/* Converter format */ +#define HDA_CMD_VERB_GET_CONV_FMT 0xa +#define HDA_CMD_VERB_SET_CONV_FMT 0x2 + +#define HDA_CMD_GET_CONV_FMT(cad, nid) \ + (HDA_CMD_4BIT((cad), (nid), \ + HDA_CMD_VERB_GET_CONV_FMT, 0x0)) +#define HDA_CMD_SET_CONV_FMT(cad, nid, payload) \ + (HDA_CMD_4BIT((cad), (nid), \ + HDA_CMD_VERB_SET_CONV_FMT, (payload))) + +/* Digital Converter Control */ +#define HDA_CMD_VERB_GET_DIGITAL_CONV_FMT1 0xf0d +#define HDA_CMD_VERB_GET_DIGITAL_CONV_FMT2 0xf0e +#define HDA_CMD_VERB_SET_DIGITAL_CONV_FMT1 0x70d +#define HDA_CMD_VERB_SET_DIGITAL_CONV_FMT2 0x70e + +#define HDA_CMD_GET_DIGITAL_CONV_FMT(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_DIGITAL_CONV_FMT1, 0x0)) +#define HDA_CMD_SET_DIGITAL_CONV_FMT1(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_DIGITAL_CONV_FMT1, (payload))) +#define HDA_CMD_SET_DIGITAL_CONV_FMT2(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_DIGITAL_CONV_FMT2, (payload))) + +#define HDA_CMD_GET_DIGITAL_CONV_FMT_CC_MASK 0x7f00 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_CC_SHIFT 8 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_L_MASK 0x0080 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_L_SHIFT 7 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_PRO_MASK 0x0040 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_PRO_SHIFT 6 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_NAUDIO_MASK 0x0020 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_NAUDIO_SHIFT 5 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_COPY_MASK 0x0010 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_COPY_SHIFT 4 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_PRE_MASK 0x0008 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_PRE_SHIFT 3 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_VCFG_MASK 0x0004 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_VCFG_SHIFT 2 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_V_MASK 0x0002 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_V_SHIFT 1 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_DIGEN_MASK 0x0001 +#define HDA_CMD_GET_DIGITAL_CONV_FMT_DIGEN_SHIFT 0 + +#define HDA_CMD_GET_DIGITAL_CONV_FMT_CC(rsp) \ + (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_CC_MASK) >> \ + HDA_CMD_GET_DIGITAL_CONV_FMT_CC_SHIFT) +#define HDA_CMD_GET_DIGITAL_CONV_FMT_L(rsp) \ + (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_L_MASK) >> \ + HDA_CMD_GET_DIGITAL_CONV_FMT_L_SHIFT) +#define HDA_CMD_GET_DIGITAL_CONV_FMT_PRO(rsp) \ + (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_PRO_MASK) >> \ + HDA_CMD_GET_DIGITAL_CONV_FMT_PRO_SHIFT) +#define HDA_CMD_GET_DIGITAL_CONV_FMT_NAUDIO(rsp) \ + (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_NAUDIO_MASK) >> \ + HDA_CMD_GET_DIGITAL_CONV_FMT_NAUDIO_SHIFT) +#define HDA_CMD_GET_DIGITAL_CONV_FMT_COPY(rsp) \ + (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_COPY_MASK) >> \ + HDA_CMD_GET_DIGITAL_CONV_FMT_COPY_SHIFT) +#define HDA_CMD_GET_DIGITAL_CONV_FMT_PRE(rsp) \ + (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_PRE_MASK) >> \ + HDA_CMD_GET_DIGITAL_CONV_FMT_PRE_SHIFT) +#define HDA_CMD_GET_DIGITAL_CONV_FMT_VCFG(rsp) \ + (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_VCFG_MASK) >> \ + HDA_CMD_GET_DIGITAL_CONV_FMT_VCFG_SHIFT) +#define HDA_CMD_GET_DIGITAL_CONV_FMT_V(rsp) \ + (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_V_MASK) >> \ + HDA_CMD_GET_DIGITAL_CONV_FMT_V_SHIFT) +#define HDA_CMD_GET_DIGITAL_CONV_FMT_DIGEN(rsp) \ + (((rsp) & HDA_CMD_GET_DIGITAL_CONV_FMT_DIGEN_MASK) >> \ + HDA_CMD_GET_DIGITAL_CONV_FMT_DIGEN_SHIFT) + +#define HDA_CMD_SET_DIGITAL_CONV_FMT1_L 0x80 +#define HDA_CMD_SET_DIGITAL_CONV_FMT1_PRO 0x40 +#define HDA_CMD_SET_DIGITAL_CONV_FMT1_NAUDIO 0x20 +#define HDA_CMD_SET_DIGITAL_CONV_FMT1_COPY 0x10 +#define HDA_CMD_SET_DIGITAL_CONV_FMT1_PRE 0x08 +#define HDA_CMD_SET_DIGITAL_CONV_FMT1_VCFG 0x04 +#define HDA_CMD_SET_DIGITAL_CONV_FMT1_V 0x02 +#define HDA_CMD_SET_DIGITAL_CONV_FMT1_DIGEN 0x01 + +/* Power State */ +#define HDA_CMD_VERB_GET_POWER_STATE 0xf05 +#define HDA_CMD_VERB_SET_POWER_STATE 0x705 + +#define HDA_CMD_GET_POWER_STATE(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_POWER_STATE, 0x0)) +#define HDA_CMD_SET_POWER_STATE(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_POWER_STATE, (payload))) + +#define HDA_CMD_POWER_STATE_D0 0x00 +#define HDA_CMD_POWER_STATE_D1 0x01 +#define HDA_CMD_POWER_STATE_D2 0x02 +#define HDA_CMD_POWER_STATE_D3 0x03 + +#define HDA_CMD_POWER_STATE_ACT_MASK 0x000000f0 +#define HDA_CMD_POWER_STATE_ACT_SHIFT 4 +#define HDA_CMD_POWER_STATE_SET_MASK 0x0000000f +#define HDA_CMD_POWER_STATE_SET_SHIFT 0 + +#define HDA_CMD_GET_POWER_STATE_ACT(rsp) \ + (((rsp) & HDA_CMD_POWER_STATE_ACT_MASK) >> \ + HDA_CMD_POWER_STATE_ACT_SHIFT) +#define HDA_CMD_GET_POWER_STATE_SET(rsp) \ + (((rsp) & HDA_CMD_POWER_STATE_SET_MASK) >> \ + HDA_CMD_POWER_STATE_SET_SHIFT) + +#define HDA_CMD_SET_POWER_STATE_ACT(ps) \ + (((ps) << HDA_CMD_POWER_STATE_ACT_SHIFT) & \ + HDA_CMD_POWER_STATE_ACT_MASK) +#define HDA_CMD_SET_POWER_STATE_SET(ps) \ + (((ps) << HDA_CMD_POWER_STATE_SET_SHIFT) & \ + HDA_CMD_POWER_STATE_ACT_MASK) + +/* Converter Stream, Channel */ +#define HDA_CMD_VERB_GET_CONV_STREAM_CHAN 0xf06 +#define HDA_CMD_VERB_SET_CONV_STREAM_CHAN 0x706 + +#define HDA_CMD_GET_CONV_STREAM_CHAN(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_CONV_STREAM_CHAN, 0x0)) +#define HDA_CMD_SET_CONV_STREAM_CHAN(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_CONV_STREAM_CHAN, (payload))) + +#define HDA_CMD_CONV_STREAM_CHAN_STREAM_MASK 0x000000f0 +#define HDA_CMD_CONV_STREAM_CHAN_STREAM_SHIFT 4 +#define HDA_CMD_CONV_STREAM_CHAN_CHAN_MASK 0x0000000f +#define HDA_CMD_CONV_STREAM_CHAN_CHAN_SHIFT 0 + +#define HDA_CMD_GET_CONV_STREAM_CHAN_STREAM(rsp) \ + (((rsp) & HDA_CMD_CONV_STREAM_CHAN_STREAM_MASK) >> \ + HDA_CMD_CONV_STREAM_CHAN_STREAM_SHIFT) +#define HDA_CMD_GET_CONV_STREAM_CHAN_CHAN(rsp) \ + (((rsp) & HDA_CMD_CONV_STREAM_CHAN_CHAN_MASK) >> \ + HDA_CMD_CONV_STREAM_CHAN_CHAN_SHIFT) + +#define HDA_CMD_SET_CONV_STREAM_CHAN_STREAM(param) \ + (((param) << HDA_CMD_CONV_STREAM_CHAN_STREAM_SHIFT) & \ + HDA_CMD_CONV_STREAM_CHAN_STREAM_MASK) +#define HDA_CMD_SET_CONV_STREAM_CHAN_CHAN(param) \ + (((param) << HDA_CMD_CONV_STREAM_CHAN_CHAN_SHIFT) & \ + HDA_CMD_CONV_STREAM_CHAN_CHAN_MASK) + +/* Input Converter SDI Select */ +#define HDA_CMD_VERB_GET_INPUT_CONVERTER_SDI_SELECT 0xf04 +#define HDA_CMD_VERB_SET_INPUT_CONVERTER_SDI_SELECT 0x704 + +#define HDA_CMD_GET_INPUT_CONVERTER_SDI_SELECT(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_INPUT_CONVERTER_SDI_SELECT, 0x0)) +#define HDA_CMD_SET_INPUT_CONVERTER_SDI_SELECT(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_INPUT_CONVERTER_SDI_SELECT, (payload))) + +/* Pin Widget Control */ +#define HDA_CMD_VERB_GET_PIN_WIDGET_CTRL 0xf07 +#define HDA_CMD_VERB_SET_PIN_WIDGET_CTRL 0x707 + +#define HDA_CMD_GET_PIN_WIDGET_CTRL(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_PIN_WIDGET_CTRL, 0x0)) +#define HDA_CMD_SET_PIN_WIDGET_CTRL(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_PIN_WIDGET_CTRL, (payload))) + +#define HDA_CMD_GET_PIN_WIDGET_CTRL_HPHN_ENABLE_MASK 0x00000080 +#define HDA_CMD_GET_PIN_WIDGET_CTRL_HPHN_ENABLE_SHIFT 7 +#define HDA_CMD_GET_PIN_WIDGET_CTRL_OUT_ENABLE_MASK 0x00000040 +#define HDA_CMD_GET_PIN_WIDGET_CTRL_OUT_ENABLE_SHIFT 6 +#define HDA_CMD_GET_PIN_WIDGET_CTRL_IN_ENABLE_MASK 0x00000020 +#define HDA_CMD_GET_PIN_WIDGET_CTRL_IN_ENABLE_SHIFT 5 +#define HDA_CMD_GET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK 0x00000007 +#define HDA_CMD_GET_PIN_WIDGET_CTRL_VREF_ENABLE_SHIFT 0 + +#define HDA_CMD_GET_PIN_WIDGET_CTRL_HPHN_ENABLE(rsp) \ + (((rsp) & HDA_CMD_GET_PIN_WIDGET_CTRL_HPHN_ENABLE_MASK) >> \ + HDA_CMD_GET_PIN_WIDGET_CTRL_HPHN_ENABLE_SHIFT) +#define HDA_CMD_GET_PIN_WIDGET_CTRL_OUT_ENABLE(rsp) \ + (((rsp) & HDA_CMD_GET_PIN_WIDGET_CTRL_OUT_ENABLE_MASK) >> \ + HDA_GET_CMD_PIN_WIDGET_CTRL_OUT_ENABLE_SHIFT) +#define HDA_CMD_GET_PIN_WIDGET_CTRL_IN_ENABLE(rsp) \ + (((rsp) & HDA_CMD_GET_PIN_WIDGET_CTRL_IN_ENABLE_MASK) >> \ + HDA_CMD_GET_PIN_WIDGET_CTRL_IN_ENABLE_SHIFT) +#define HDA_CMD_GET_PIN_WIDGET_CTRL_VREF_ENABLE(rsp) \ + (((rsp) & HDA_CMD_GET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK) >> \ + HDA_CMD_GET_PIN_WIDGET_CTRL_VREF_ENABLE_SHIFT) + +#define HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE 0x80 +#define HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE 0x40 +#define HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE 0x20 +#define HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK 0x07 +#define HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_SHIFT 0 + +#define HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(param) \ + (((param) << HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_SHIFT) & \ + HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK) + +#define HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_HIZ 0 +#define HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_50 1 +#define HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_GROUND 2 +#define HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_80 4 +#define HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_100 5 + +/* Unsolicited Response */ +#define HDA_CMD_VERB_GET_UNSOLICITED_RESPONSE 0xf08 +#define HDA_CMD_VERB_SET_UNSOLICITED_RESPONSE 0x708 + +#define HDA_CMD_GET_UNSOLICITED_RESPONSE(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_UNSOLICITED_RESPONSE, 0x0)) +#define HDA_CMD_SET_UNSOLICITED_RESPONSE(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_UNSOLICITED_RESPONSE, (payload))) + +#define HDA_CMD_GET_UNSOLICITED_RESPONSE_ENABLE_MASK 0x00000080 +#define HDA_CMD_GET_UNSOLICITED_RESPONSE_ENABLE_SHIFT 7 +#define HDA_CMD_GET_UNSOLICITED_RESPONSE_TAG_MASK 0x0000001f +#define HDA_CMD_GET_UNSOLICITED_RESPONSE_TAG_SHIFT 0 + +#define HDA_CMD_GET_UNSOLICITED_RESPONSE_ENABLE(rsp) \ + (((rsp) & HDA_CMD_GET_UNSOLICITED_RESPONSE_ENABLE_MASK) >> \ + HDA_CMD_GET_UNSOLICITED_RESPONSE_ENABLE_SHIFT) +#define HDA_CMD_GET_UNSOLICITED_RESPONSE_TAG(rsp) \ + (((rsp) & HDA_CMD_GET_UNSOLICITED_RESPONSE_TAG_MASK) >> \ + HDA_CMD_GET_UNSOLICITED_RESPONSE_TAG_SHIFT) + +#define HDA_CMD_SET_UNSOLICITED_RESPONSE_ENABLE 0x80 +#define HDA_CMD_SET_UNSOLICITED_RESPONSE_TAG_MASK 0x3f +#define HDA_CMD_SET_UNSOLICITED_RESPONSE_TAG_SHIFT 0 + +#define HDA_CMD_SET_UNSOLICITED_RESPONSE_TAG(param) \ + (((param) << HDA_CMD_SET_UNSOLICITED_RESPONSE_TAG_SHIFT) & \ + HDA_CMD_SET_UNSOLICITED_RESPONSE_TAG_MASK) + +/* Pin Sense */ +#define HDA_CMD_VERB_GET_PIN_SENSE 0xf09 +#define HDA_CMD_VERB_SET_PIN_SENSE 0x709 + +#define HDA_CMD_GET_PIN_SENSE(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_PIN_SENSE, 0x0)) +#define HDA_CMD_SET_PIN_SENSE(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_PIN_SENSE, (payload))) + +#define HDA_CMD_GET_PIN_SENSE_PRESENCE_DETECT 0x80000000 +#define HDA_CMD_GET_PIN_SENSE_ELD_VALID 0x40000000 +#define HDA_CMD_GET_PIN_SENSE_IMP_SENSE_MASK 0x7fffffff +#define HDA_CMD_GET_PIN_SENSE_IMP_SENSE_SHIFT 0 + +#define HDA_CMD_GET_PIN_SENSE_IMP_SENSE(rsp) \ + (((rsp) & HDA_CMD_GET_PIN_SENSE_IMP_SENSE_MASK) >> \ + HDA_CMD_GET_PIN_SENSE_IMP_SENSE_SHIFT) + +#define HDA_CMD_GET_PIN_SENSE_IMP_SENSE_INVALID 0x7fffffff + +#define HDA_CMD_SET_PIN_SENSE_LEFT_CHANNEL 0x00 +#define HDA_CMD_SET_PIN_SENSE_RIGHT_CHANNEL 0x01 + +/* EAPD/BTL Enable */ +#define HDA_CMD_VERB_GET_EAPD_BTL_ENABLE 0xf0c +#define HDA_CMD_VERB_SET_EAPD_BTL_ENABLE 0x70c + +#define HDA_CMD_GET_EAPD_BTL_ENABLE(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_EAPD_BTL_ENABLE, 0x0)) +#define HDA_CMD_SET_EAPD_BTL_ENABLE(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_EAPD_BTL_ENABLE, (payload))) + +#define HDA_CMD_GET_EAPD_BTL_ENABLE_LR_SWAP_MASK 0x00000004 +#define HDA_CMD_GET_EAPD_BTL_ENABLE_LR_SWAP_SHIFT 2 +#define HDA_CMD_GET_EAPD_BTL_ENABLE_EAPD_MASK 0x00000002 +#define HDA_CMD_GET_EAPD_BTL_ENABLE_EAPD_SHIFT 1 +#define HDA_CMD_GET_EAPD_BTL_ENABLE_BTL_MASK 0x00000001 +#define HDA_CMD_GET_EAPD_BTL_ENABLE_BTL_SHIFT 0 + +#define HDA_CMD_GET_EAPD_BTL_ENABLE_LR_SWAP(rsp) \ + (((rsp) & HDA_CMD_GET_EAPD_BTL_ENABLE_LR_SWAP_MASK) >> \ + HDA_CMD_GET_EAPD_BTL_ENABLE_LR_SWAP_SHIFT) +#define HDA_CMD_GET_EAPD_BTL_ENABLE_EAPD(rsp) \ + (((rsp) & HDA_CMD_GET_EAPD_BTL_ENABLE_EAPD_MASK) >> \ + HDA_CMD_GET_EAPD_BTL_ENABLE_EAPD_SHIFT) +#define HDA_CMD_GET_EAPD_BTL_ENABLE_BTL(rsp) \ + (((rsp) & HDA_CMD_GET_EAPD_BTL_ENABLE_BTL_MASK) >> \ + HDA_CMD_GET_EAPD_BTL_ENABLE_BTL_SHIFT) + +#define HDA_CMD_SET_EAPD_BTL_ENABLE_LR_SWAP 0x04 +#define HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD 0x02 +#define HDA_CMD_SET_EAPD_BTL_ENABLE_BTL 0x01 + +/* GPI Data */ +#define HDA_CMD_VERB_GET_GPI_DATA 0xf10 +#define HDA_CMD_VERB_SET_GPI_DATA 0x710 + +#define HDA_CMD_GET_GPI_DATA(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPI_DATA, 0x0)) +#define HDA_CMD_SET_GPI_DATA(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPI_DATA, (payload))) + +/* GPI Wake Enable Mask */ +#define HDA_CMD_VERB_GET_GPI_WAKE_ENABLE_MASK 0xf11 +#define HDA_CMD_VERB_SET_GPI_WAKE_ENABLE_MASK 0x711 + +#define HDA_CMD_GET_GPI_WAKE_ENABLE_MASK(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPI_WAKE_ENABLE_MASK, 0x0)) +#define HDA_CMD_SET_GPI_WAKE_ENABLE_MASK(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPI_WAKE_ENABLE_MASK, (payload))) + +/* GPI Unsolicited Enable Mask */ +#define HDA_CMD_VERB_GET_GPI_UNSOLICITED_ENABLE_MASK 0xf12 +#define HDA_CMD_VERB_SET_GPI_UNSOLICITED_ENABLE_MASK 0x712 + +#define HDA_CMD_GET_GPI_UNSOLICITED_ENABLE_MASK(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPI_UNSOLICITED_ENABLE_MASK, 0x0)) +#define HDA_CMD_SET_GPI_UNSOLICITED_ENABLE_MASK(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPI_UNSOLICITED_ENABLE_MASK, (payload))) + +/* GPI Sticky Mask */ +#define HDA_CMD_VERB_GET_GPI_STICKY_MASK 0xf13 +#define HDA_CMD_VERB_SET_GPI_STICKY_MASK 0x713 + +#define HDA_CMD_GET_GPI_STICKY_MASK(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPI_STICKY_MASK, 0x0)) +#define HDA_CMD_SET_GPI_STICKY_MASK(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPI_STICKY_MASK, (payload))) + +/* GPO Data */ +#define HDA_CMD_VERB_GET_GPO_DATA 0xf14 +#define HDA_CMD_VERB_SET_GPO_DATA 0x714 + +#define HDA_CMD_GET_GPO_DATA(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPO_DATA, 0x0)) +#define HDA_CMD_SET_GPO_DATA(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPO_DATA, (payload))) + +/* GPIO Data */ +#define HDA_CMD_VERB_GET_GPIO_DATA 0xf15 +#define HDA_CMD_VERB_SET_GPIO_DATA 0x715 + +#define HDA_CMD_GET_GPIO_DATA(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPIO_DATA, 0x0)) +#define HDA_CMD_SET_GPIO_DATA(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPIO_DATA, (payload))) + +/* GPIO Enable Mask */ +#define HDA_CMD_VERB_GET_GPIO_ENABLE_MASK 0xf16 +#define HDA_CMD_VERB_SET_GPIO_ENABLE_MASK 0x716 + +#define HDA_CMD_GET_GPIO_ENABLE_MASK(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPIO_ENABLE_MASK, 0x0)) +#define HDA_CMD_SET_GPIO_ENABLE_MASK(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPIO_ENABLE_MASK, (payload))) + +/* GPIO Direction */ +#define HDA_CMD_VERB_GET_GPIO_DIRECTION 0xf17 +#define HDA_CMD_VERB_SET_GPIO_DIRECTION 0x717 + +#define HDA_CMD_GET_GPIO_DIRECTION(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPIO_DIRECTION, 0x0)) +#define HDA_CMD_SET_GPIO_DIRECTION(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPIO_DIRECTION, (payload))) + +/* GPIO Wake Enable Mask */ +#define HDA_CMD_VERB_GET_GPIO_WAKE_ENABLE_MASK 0xf18 +#define HDA_CMD_VERB_SET_GPIO_WAKE_ENABLE_MASK 0x718 + +#define HDA_CMD_GET_GPIO_WAKE_ENABLE_MASK(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPIO_WAKE_ENABLE_MASK, 0x0)) +#define HDA_CMD_SET_GPIO_WAKE_ENABLE_MASK(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPIO_WAKE_ENABLE_MASK, (payload))) + +/* GPIO Unsolicited Enable Mask */ +#define HDA_CMD_VERB_GET_GPIO_UNSOLICITED_ENABLE_MASK 0xf19 +#define HDA_CMD_VERB_SET_GPIO_UNSOLICITED_ENABLE_MASK 0x719 + +#define HDA_CMD_GET_GPIO_UNSOLICITED_ENABLE_MASK(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPIO_UNSOLICITED_ENABLE_MASK, 0x0)) +#define HDA_CMD_SET_GPIO_UNSOLICITED_ENABLE_MASK(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPIO_UNSOLICITED_ENABLE_MASK, (payload))) + +/* GPIO_STICKY_MASK */ +#define HDA_CMD_VERB_GET_GPIO_STICKY_MASK 0xf1a +#define HDA_CMD_VERB_SET_GPIO_STICKY_MASK 0x71a + +#define HDA_CMD_GET_GPIO_STICKY_MASK(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_GPIO_STICKY_MASK, 0x0)) +#define HDA_CMD_SET_GPIO_STICKY_MASK(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_GPIO_STICKY_MASK, (payload))) + +/* Beep Generation */ +#define HDA_CMD_VERB_GET_BEEP_GENERATION 0xf0a +#define HDA_CMD_VERB_SET_BEEP_GENERATION 0x70a + +#define HDA_CMD_GET_BEEP_GENERATION(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_BEEP_GENERATION, 0x0)) +#define HDA_CMD_SET_BEEP_GENERATION(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_BEEP_GENERATION, (payload))) + +/* Volume Knob */ +#define HDA_CMD_VERB_GET_VOLUME_KNOB 0xf0f +#define HDA_CMD_VERB_SET_VOLUME_KNOB 0x70f + +#define HDA_CMD_GET_VOLUME_KNOB(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_VOLUME_KNOB, 0x0)) +#define HDA_CMD_SET_VOLUME_KNOB(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_VOLUME_KNOB, (payload))) + +/* Subsystem ID */ +#define HDA_CMD_VERB_GET_SUBSYSTEM_ID 0xf20 +#define HDA_CMD_VERB_SET_SUSBYSTEM_ID1 0x720 +#define HDA_CMD_VERB_SET_SUBSYSTEM_ID2 0x721 +#define HDA_CMD_VERB_SET_SUBSYSTEM_ID3 0x722 +#define HDA_CMD_VERB_SET_SUBSYSTEM_ID4 0x723 + +#define HDA_CMD_GET_SUBSYSTEM_ID(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_SUBSYSTEM_ID, 0x0)) +#define HDA_CMD_SET_SUBSYSTEM_ID1(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_SUSBYSTEM_ID1, (payload))) +#define HDA_CMD_SET_SUBSYSTEM_ID2(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_SUSBYSTEM_ID2, (payload))) +#define HDA_CMD_SET_SUBSYSTEM_ID3(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_SUSBYSTEM_ID3, (payload))) +#define HDA_CMD_SET_SUBSYSTEM_ID4(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_SUSBYSTEM_ID4, (payload))) + +/* Configuration Default */ +#define HDA_CMD_VERB_GET_CONFIGURATION_DEFAULT 0xf1c +#define HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT1 0x71c +#define HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT2 0x71d +#define HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT3 0x71e +#define HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT4 0x71f + +#define HDA_CMD_GET_CONFIGURATION_DEFAULT(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_CONFIGURATION_DEFAULT, 0x0)) +#define HDA_CMD_SET_CONFIGURATION_DEFAULT1(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT1, (payload))) +#define HDA_CMD_SET_CONFIGURATION_DEFAULT2(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT2, (payload))) +#define HDA_CMD_SET_CONFIGURATION_DEFAULT3(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT3, (payload))) +#define HDA_CMD_SET_CONFIGURATION_DEFAULT4(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_CONFIGURATION_DEFAULT4, (payload))) + +/* Stripe Control */ +#define HDA_CMD_VERB_GET_STRIPE_CONTROL 0xf24 +#define HDA_CMD_VERB_SET_STRIPE_CONTROL 0x724 + +#define HDA_CMD_GET_STRIPE_CONTROL(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_STRIPE_CONTROL, 0x0)) +#define HDA_CMD_SET_STRIPE_CONTROL(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_STRIPE_CONTROL, (payload))) + +/* Channel Count Control */ +#define HDA_CMD_VERB_GET_CONV_CHAN_COUNT 0xf2d +#define HDA_CMD_VERB_SET_CONV_CHAN_COUNT 0x72d + +#define HDA_CMD_GET_CONV_CHAN_COUNT(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_CONV_CHAN_COUNT, 0x0)) +#define HDA_CMD_SET_CONV_CHAN_COUNT(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_CONV_CHAN_COUNT, (payload))) + +#define HDA_CMD_VERB_GET_HDMI_DIP_SIZE 0xf2e + +#define HDA_CMD_GET_HDMI_DIP_SIZE(cad, nid, arg) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_HDMI_DIP_SIZE, (arg))) + +#define HDA_CMD_VERB_GET_HDMI_ELDD 0xf2f + +#define HDA_CMD_GET_HDMI_ELDD(cad, nid, off) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_HDMI_ELDD, (off))) + +#define HDA_CMD_VERB_GET_HDMI_DIP_INDEX 0xf30 +#define HDA_CMD_VERB_SET_HDMI_DIP_INDEX 0x730 + +#define HDA_CMD_GET_HDMI_DIP_INDEX(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_HDMI_DIP_INDEX, 0x0)) +#define HDA_CMD_SET_HDMI_DIP_INDEX(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_HDMI_DIP_INDEX, (payload))) + +#define HDA_CMD_VERB_GET_HDMI_DIP_DATA 0xf31 +#define HDA_CMD_VERB_SET_HDMI_DIP_DATA 0x731 + +#define HDA_CMD_GET_HDMI_DIP_DATA(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_HDMI_DIP_DATA, 0x0)) +#define HDA_CMD_SET_HDMI_DIP_DATA(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_HDMI_DIP_DATA, (payload))) + +#define HDA_CMD_VERB_GET_HDMI_DIP_XMIT 0xf32 +#define HDA_CMD_VERB_SET_HDMI_DIP_XMIT 0x732 + +#define HDA_CMD_GET_HDMI_DIP_XMIT(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_HDMI_DIP_XMIT, 0x0)) +#define HDA_CMD_SET_HDMI_DIP_XMIT(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_HDMI_DIP_XMIT, (payload))) + +#define HDA_CMD_VERB_GET_HDMI_CP_CTRL 0xf33 +#define HDA_CMD_VERB_SET_HDMI_CP_CTRL 0x733 + +#define HDA_CMD_VERB_GET_HDMI_CHAN_SLOT 0xf34 +#define HDA_CMD_VERB_SET_HDMI_CHAN_SLOT 0x734 + +#define HDA_CMD_GET_HDMI_CHAN_SLOT(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_GET_HDMI_CHAN_SLOT, 0x0)) +#define HDA_CMD_SET_HDMI_CHAN_SLOT(cad, nid, payload) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_SET_HDMI_CHAN_SLOT, (payload))) + +#define HDA_HDMI_CODING_TYPE_REF_STREAM_HEADER 0 +#define HDA_HDMI_CODING_TYPE_LPCM 1 +#define HDA_HDMI_CODING_TYPE_AC3 2 +#define HDA_HDMI_CODING_TYPE_MPEG1 3 +#define HDA_HDMI_CODING_TYPE_MP3 4 +#define HDA_HDMI_CODING_TYPE_MPEG2 5 +#define HDA_HDMI_CODING_TYPE_AACLC 6 +#define HDA_HDMI_CODING_TYPE_DTS 7 +#define HDA_HDMI_CODING_TYPE_ATRAC 8 +#define HDA_HDMI_CODING_TYPE_SACD 9 +#define HDA_HDMI_CODING_TYPE_EAC3 10 +#define HDA_HDMI_CODING_TYPE_DTS_HD 11 +#define HDA_HDMI_CODING_TYPE_MLP 12 +#define HDA_HDMI_CODING_TYPE_DST 13 +#define HDA_HDMI_CODING_TYPE_WMAPRO 14 +#define HDA_HDMI_CODING_TYPE_REF_CTX 15 + +/* Function Reset */ +#define HDA_CMD_VERB_FUNCTION_RESET 0x7ff + +#define HDA_CMD_FUNCTION_RESET(cad, nid) \ + (HDA_CMD_12BIT((cad), (nid), \ + HDA_CMD_VERB_FUNCTION_RESET, 0x0)) + + +/**************************************************************************** + * HDA Device Parameters + ****************************************************************************/ + +/* Vendor ID */ +#define HDA_PARAM_VENDOR_ID 0x00 + +#define HDA_PARAM_VENDOR_ID_VENDOR_ID_MASK 0xffff0000 +#define HDA_PARAM_VENDOR_ID_VENDOR_ID_SHIFT 16 +#define HDA_PARAM_VENDOR_ID_DEVICE_ID_MASK 0x0000ffff +#define HDA_PARAM_VENDOR_ID_DEVICE_ID_SHIFT 0 + +#define HDA_PARAM_VENDOR_ID_VENDOR_ID(param) \ + (((param) & HDA_PARAM_VENDOR_ID_VENDOR_ID_MASK) >> \ + HDA_PARAM_VENDOR_ID_VENDOR_ID_SHIFT) +#define HDA_PARAM_VENDOR_ID_DEVICE_ID(param) \ + (((param) & HDA_PARAM_VENDOR_ID_DEVICE_ID_MASK) >> \ + HDA_PARAM_VENDOR_ID_DEVICE_ID_SHIFT) + +/* Revision ID */ +#define HDA_PARAM_REVISION_ID 0x02 + +#define HDA_PARAM_REVISION_ID_MAJREV_MASK 0x00f00000 +#define HDA_PARAM_REVISION_ID_MAJREV_SHIFT 20 +#define HDA_PARAM_REVISION_ID_MINREV_MASK 0x000f0000 +#define HDA_PARAM_REVISION_ID_MINREV_SHIFT 16 +#define HDA_PARAM_REVISION_ID_REVISION_ID_MASK 0x0000ff00 +#define HDA_PARAM_REVISION_ID_REVISION_ID_SHIFT 8 +#define HDA_PARAM_REVISION_ID_STEPPING_ID_MASK 0x000000ff +#define HDA_PARAM_REVISION_ID_STEPPING_ID_SHIFT 0 + +#define HDA_PARAM_REVISION_ID_MAJREV(param) \ + (((param) & HDA_PARAM_REVISION_ID_MAJREV_MASK) >> \ + HDA_PARAM_REVISION_ID_MAJREV_SHIFT) +#define HDA_PARAM_REVISION_ID_MINREV(param) \ + (((param) & HDA_PARAM_REVISION_ID_MINREV_MASK) >> \ + HDA_PARAM_REVISION_ID_MINREV_SHIFT) +#define HDA_PARAM_REVISION_ID_REVISION_ID(param) \ + (((param) & HDA_PARAM_REVISION_ID_REVISION_ID_MASK) >> \ + HDA_PARAM_REVISION_ID_REVISION_ID_SHIFT) +#define HDA_PARAM_REVISION_ID_STEPPING_ID(param) \ + (((param) & HDA_PARAM_REVISION_ID_STEPPING_ID_MASK) >> \ + HDA_PARAM_REVISION_ID_STEPPING_ID_SHIFT) + +/* Subordinate Node Cound */ +#define HDA_PARAM_SUB_NODE_COUNT 0x04 + +#define HDA_PARAM_SUB_NODE_COUNT_START_MASK 0x00ff0000 +#define HDA_PARAM_SUB_NODE_COUNT_START_SHIFT 16 +#define HDA_PARAM_SUB_NODE_COUNT_TOTAL_MASK 0x000000ff +#define HDA_PARAM_SUB_NODE_COUNT_TOTAL_SHIFT 0 + +#define HDA_PARAM_SUB_NODE_COUNT_START(param) \ + (((param) & HDA_PARAM_SUB_NODE_COUNT_START_MASK) >> \ + HDA_PARAM_SUB_NODE_COUNT_START_SHIFT) +#define HDA_PARAM_SUB_NODE_COUNT_TOTAL(param) \ + (((param) & HDA_PARAM_SUB_NODE_COUNT_TOTAL_MASK) >> \ + HDA_PARAM_SUB_NODE_COUNT_TOTAL_SHIFT) + +/* Function Group Type */ +#define HDA_PARAM_FCT_GRP_TYPE 0x05 + +#define HDA_PARAM_FCT_GRP_TYPE_UNSOL_MASK 0x00000100 +#define HDA_PARAM_FCT_GRP_TYPE_UNSOL_SHIFT 8 +#define HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_MASK 0x000000ff +#define HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_SHIFT 0 + +#define HDA_PARAM_FCT_GRP_TYPE_UNSOL(param) \ + (((param) & HDA_PARAM_FCT_GRP_TYPE_UNSOL_MASK) >> \ + HDA_PARAM_FCT_GROUP_TYPE_UNSOL_SHIFT) +#define HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE(param) \ + (((param) & HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_MASK) >> \ + HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_SHIFT) + +#define HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO 0x01 +#define HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_MODEM 0x02 + +/* Audio Function Group Capabilities */ +#define HDA_PARAM_AUDIO_FCT_GRP_CAP 0x08 + +#define HDA_PARAM_AUDIO_FCT_GRP_CAP_BEEP_GEN_MASK 0x00010000 +#define HDA_PARAM_AUDIO_FCT_GRP_CAP_BEEP_GEN_SHIFT 16 +#define HDA_PARAM_AUDIO_FCT_GRP_CAP_INPUT_DELAY_MASK 0x00000f00 +#define HDA_PARAM_AUDIO_FCT_GRP_CAP_INPUT_DELAY_SHIFT 8 +#define HDA_PARAM_AUDIO_FCT_GRP_CAP_OUTPUT_DELAY_MASK 0x0000000f +#define HDA_PARAM_AUDIO_FCT_GRP_CAP_OUTPUT_DELAY_SHIFT 0 + +#define HDA_PARAM_AUDIO_FCT_GRP_CAP_BEEP_GEN(param) \ + (((param) & HDA_PARAM_AUDIO_FCT_GRP_CAP_BEEP_GEN_MASK) >> \ + HDA_PARAM_AUDIO_FCT_GRP_CAP_BEEP_GEN_SHIFT) +#define HDA_PARAM_AUDIO_FCT_GRP_CAP_INPUT_DELAY(param) \ + (((param) & HDA_PARAM_AUDIO_FCT_GRP_CAP_INPUT_DELAY_MASK) >> \ + HDA_PARAM_AUDIO_FCT_GRP_CAP_INPUT_DELAY_SHIFT) +#define HDA_PARAM_AUDIO_FCT_GRP_CAP_OUTPUT_DELAY(param) \ + (((param) & HDA_PARAM_AUDIO_FCT_GRP_CAP_OUTPUT_DELAY_MASK) >> \ + HDA_PARAM_AUDIO_FCT_GRP_CAP_OUTPUT_DELAY_SHIFT) + +/* Audio Widget Capabilities */ +#define HDA_PARAM_AUDIO_WIDGET_CAP 0x09 + +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_MASK 0x00f00000 +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT 20 +#define HDA_PARAM_AUDIO_WIDGET_CAP_DELAY_MASK 0x000f0000 +#define HDA_PARAM_AUDIO_WIDGET_CAP_DELAY_SHIFT 16 +#define HDA_PARAM_AUDIO_WIDGET_CAP_CC_EXT_MASK 0x0000e000 +#define HDA_PARAM_AUDIO_WIDGET_CAP_CC_EXT_SHIFT 13 +#define HDA_PARAM_AUDIO_WIDGET_CAP_CP_MASK 0x00001000 +#define HDA_PARAM_AUDIO_WIDGET_CAP_CP_SHIFT 12 +#define HDA_PARAM_AUDIO_WIDGET_CAP_LR_SWAP_MASK 0x00000800 +#define HDA_PARAM_AUDIO_WIDGET_CAP_LR_SWAP_SHIFT 11 +#define HDA_PARAM_AUDIO_WIDGET_CAP_POWER_CTRL_MASK 0x00000400 +#define HDA_PARAM_AUDIO_WIDGET_CAP_POWER_CTRL_SHIFT 10 +#define HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL_MASK 0x00000200 +#define HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL_SHIFT 9 +#define HDA_PARAM_AUDIO_WIDGET_CAP_CONN_LIST_MASK 0x00000100 +#define HDA_PARAM_AUDIO_WIDGET_CAP_CONN_LIST_SHIFT 8 +#define HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP_MASK 0x00000080 +#define HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP_SHIFT 7 +#define HDA_PARAM_AUDIO_WIDGET_CAP_PROC_WIDGET_MASK 0x00000040 +#define HDA_PARAM_AUDIO_WIDGET_CAP_PROC_WIDGET_SHIFT 6 +#define HDA_PARAM_AUDIO_WIDGET_CAP_STRIPE_MASK 0x00000020 +#define HDA_PARAM_AUDIO_WIDGET_CAP_STRIPE_SHIFT 5 +#define HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR_MASK 0x00000010 +#define HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR_SHIFT 4 +#define HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR_MASK 0x00000008 +#define HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR_SHIFT 3 +#define HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP_MASK 0x00000004 +#define HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP_SHIFT 2 +#define HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP_MASK 0x00000002 +#define HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP_SHIFT 1 +#define HDA_PARAM_AUDIO_WIDGET_CAP_STEREO_MASK 0x00000001 +#define HDA_PARAM_AUDIO_WIDGET_CAP_STEREO_SHIFT 0 + +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_DELAY(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_DELAY_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_DELAY_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_CC(param) \ + ((((param) & HDA_PARAM_AUDIO_WIDGET_CAP_CC_EXT_MASK) >> \ + (HDA_PARAM_AUDIO_WIDGET_CAP_CC_EXT_SHIFT - 1)) | \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_STEREO_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_STEREO_SHIFT)) +#define HDA_PARAM_AUDIO_WIDGET_CAP_CP(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_CP_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_CP_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_LR_SWAP(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_LR_SWAP_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_LR_SWAP_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_POWER_CTRL(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_POWER_CTRL_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_POWER_CTRL_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_CONN_LIST(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_CONN_LIST_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_CONN_LIST_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_PROC_WIDGET(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_PROC_WIDGET_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_PROC_WIDGET_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_STRIPE(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_STRIPE_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_STRIPE_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP_SHIFT) +#define HDA_PARAM_AUDIO_WIDGET_CAP_STEREO(param) \ + (((param) & HDA_PARAM_AUDIO_WIDGET_CAP_STEREO_MASK) >> \ + HDA_PARAM_AUDIO_WIDGET_CAP_STEREO_SHIFT) + +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT 0x0 +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT 0x1 +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER 0x2 +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR 0x3 +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX 0x4 +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_POWER_WIDGET 0x5 +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_VOLUME_WIDGET 0x6 +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET 0x7 +#define HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_VENDOR_WIDGET 0xf + +/* Supported PCM Size, Rates */ + +#define HDA_PARAM_SUPP_PCM_SIZE_RATE 0x0a + +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT_MASK 0x00100000 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT_SHIFT 20 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT_MASK 0x00080000 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT_SHIFT 19 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT_MASK 0x00040000 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT_SHIFT 18 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT_MASK 0x00020000 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT_SHIFT 17 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT_MASK 0x00010000 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT_SHIFT 16 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ_MASK 0x00000001 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ_SHIFT 0 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ_MASK 0x00000002 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ_SHIFT 1 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ_MASK 0x00000004 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ_SHIFT 2 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ_MASK 0x00000008 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ_SHIFT 3 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ_MASK 0x00000010 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ_SHIFT 4 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ_MASK 0x00000020 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ_SHIFT 5 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_48KHZ_MASK 0x00000040 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_48KHZ_SHIFT 6 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ_MASK 0x00000080 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ_SHIFT 7 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ_MASK 0x00000100 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ_SHIFT 8 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ_MASK 0x00000200 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ_SHIFT 9 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ_MASK 0x00000400 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ_SHIFT 10 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_384KHZ_MASK 0x00000800 +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_384KHZ_SHIFT 11 + +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_48KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_48KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_48KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ_SHIFT) +#define HDA_PARAM_SUPP_PCM_SIZE_RATE_384KHZ(param) \ + (((param) & HDA_PARAM_SUPP_PCM_SIZE_RATE_384KHZ_MASK) >> \ + HDA_PARAM_SUPP_PCM_SIZE_RATE_384KHZ_SHIFT) + +/* Supported Stream Formats */ +#define HDA_PARAM_SUPP_STREAM_FORMATS 0x0b + +#define HDA_PARAM_SUPP_STREAM_FORMATS_AC3_MASK 0x00000004 +#define HDA_PARAM_SUPP_STREAM_FORMATS_AC3_SHIFT 2 +#define HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32_MASK 0x00000002 +#define HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32_SHIFT 1 +#define HDA_PARAM_SUPP_STREAM_FORMATS_PCM_MASK 0x00000001 +#define HDA_PARAM_SUPP_STREAM_FORMATS_PCM_SHIFT 0 + +#define HDA_PARAM_SUPP_STREAM_FORMATS_AC3(param) \ + (((param) & HDA_PARAM_SUPP_STREAM_FORMATS_AC3_MASK) >> \ + HDA_PARAM_SUPP_STREAM_FORMATS_AC3_SHIFT) +#define HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32(param) \ + (((param) & HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32_MASK) >> \ + HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32_SHIFT) +#define HDA_PARAM_SUPP_STREAM_FORMATS_PCM(param) \ + (((param) & HDA_PARAM_SUPP_STREAM_FORMATS_PCM_MASK) >> \ + HDA_PARAM_SUPP_STREAM_FORMATS_PCM_SHIFT) + +/* Pin Capabilities */ +#define HDA_PARAM_PIN_CAP 0x0c + +#define HDA_PARAM_PIN_CAP_HBR_MASK 0x08000000 +#define HDA_PARAM_PIN_CAP_HBR_SHIFT 27 +#define HDA_PARAM_PIN_CAP_DP_MASK 0x01000000 +#define HDA_PARAM_PIN_CAP_DP_SHIFT 24 +#define HDA_PARAM_PIN_CAP_EAPD_CAP_MASK 0x00010000 +#define HDA_PARAM_PIN_CAP_EAPD_CAP_SHIFT 16 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_MASK 0x0000ff00 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_SHIFT 8 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_100_MASK 0x00002000 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_100_SHIFT 13 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_80_MASK 0x00001000 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_80_SHIFT 12 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_GROUND_MASK 0x00000400 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_GROUND_SHIFT 10 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_50_MASK 0x00000200 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_50_SHIFT 9 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_HIZ_MASK 0x00000100 +#define HDA_PARAM_PIN_CAP_VREF_CTRL_HIZ_SHIFT 8 +#define HDA_PARAM_PIN_CAP_HDMI_MASK 0x00000080 +#define HDA_PARAM_PIN_CAP_HDMI_SHIFT 7 +#define HDA_PARAM_PIN_CAP_BALANCED_IO_PINS_MASK 0x00000040 +#define HDA_PARAM_PIN_CAP_BALANCED_IO_PINS_SHIFT 6 +#define HDA_PARAM_PIN_CAP_INPUT_CAP_MASK 0x00000020 +#define HDA_PARAM_PIN_CAP_INPUT_CAP_SHIFT 5 +#define HDA_PARAM_PIN_CAP_OUTPUT_CAP_MASK 0x00000010 +#define HDA_PARAM_PIN_CAP_OUTPUT_CAP_SHIFT 4 +#define HDA_PARAM_PIN_CAP_HEADPHONE_CAP_MASK 0x00000008 +#define HDA_PARAM_PIN_CAP_HEADPHONE_CAP_SHIFT 3 +#define HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP_MASK 0x00000004 +#define HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP_SHIFT 2 +#define HDA_PARAM_PIN_CAP_TRIGGER_REQD_MASK 0x00000002 +#define HDA_PARAM_PIN_CAP_TRIGGER_REQD_SHIFT 1 +#define HDA_PARAM_PIN_CAP_IMP_SENSE_CAP_MASK 0x00000001 +#define HDA_PARAM_PIN_CAP_IMP_SENSE_CAP_SHIFT 0 + +#define HDA_PARAM_PIN_CAP_HBR(param) \ + (((param) & HDA_PARAM_PIN_CAP_HBR_MASK) >> \ + HDA_PARAM_PIN_CAP_HBR_SHIFT) +#define HDA_PARAM_PIN_CAP_DP(param) \ + (((param) & HDA_PARAM_PIN_CAP_DP_MASK) >> \ + HDA_PARAM_PIN_CAP_DP_SHIFT) +#define HDA_PARAM_PIN_CAP_EAPD_CAP(param) \ + (((param) & HDA_PARAM_PIN_CAP_EAPD_CAP_MASK) >> \ + HDA_PARAM_PIN_CAP_EAPD_CAP_SHIFT) +#define HDA_PARAM_PIN_CAP_VREF_CTRL(param) \ + (((param) & HDA_PARAM_PIN_CAP_VREF_CTRL_MASK) >> \ + HDA_PARAM_PIN_CAP_VREF_CTRL_SHIFT) +#define HDA_PARAM_PIN_CAP_VREF_CTRL_100(param) \ + (((param) & HDA_PARAM_PIN_CAP_VREF_CTRL_100_MASK) >> \ + HDA_PARAM_PIN_CAP_VREF_CTRL_100_SHIFT) +#define HDA_PARAM_PIN_CAP_VREF_CTRL_80(param) \ + (((param) & HDA_PARAM_PIN_CAP_VREF_CTRL_80_MASK) >> \ + HDA_PARAM_PIN_CAP_VREF_CTRL_80_SHIFT) +#define HDA_PARAM_PIN_CAP_VREF_CTRL_GROUND(param) \ + (((param) & HDA_PARAM_PIN_CAP_VREF_CTRL_GROUND_MASK) >> \ + HDA_PARAM_PIN_CAP_VREF_CTRL_GROUND_SHIFT) +#define HDA_PARAM_PIN_CAP_VREF_CTRL_50(param) \ + (((param) & HDA_PARAM_PIN_CAP_VREF_CTRL_50_MASK) >> \ + HDA_PARAM_PIN_CAP_VREF_CTRL_50_SHIFT) +#define HDA_PARAM_PIN_CAP_VREF_CTRL_HIZ(param) \ + (((param) & HDA_PARAM_PIN_CAP_VREF_CTRL_HIZ_MASK) >> \ + HDA_PARAM_PIN_CAP_VREF_CTRL_HIZ_SHIFT) +#define HDA_PARAM_PIN_CAP_HDMI(param) \ + (((param) & HDA_PARAM_PIN_CAP_HDMI_MASK) >> \ + HDA_PARAM_PIN_CAP_HDMI_SHIFT) +#define HDA_PARAM_PIN_CAP_BALANCED_IO_PINS(param) \ + (((param) & HDA_PARAM_PIN_CAP_BALANCED_IO_PINS_MASK) >> \ + HDA_PARAM_PIN_CAP_BALANCED_IO_PINS_SHIFT) +#define HDA_PARAM_PIN_CAP_INPUT_CAP(param) \ + (((param) & HDA_PARAM_PIN_CAP_INPUT_CAP_MASK) >> \ + HDA_PARAM_PIN_CAP_INPUT_CAP_SHIFT) +#define HDA_PARAM_PIN_CAP_OUTPUT_CAP(param) \ + (((param) & HDA_PARAM_PIN_CAP_OUTPUT_CAP_MASK) >> \ + HDA_PARAM_PIN_CAP_OUTPUT_CAP_SHIFT) +#define HDA_PARAM_PIN_CAP_HEADPHONE_CAP(param) \ + (((param) & HDA_PARAM_PIN_CAP_HEADPHONE_CAP_MASK) >> \ + HDA_PARAM_PIN_CAP_HEADPHONE_CAP_SHIFT) +#define HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(param) \ + (((param) & HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP_MASK) >> \ + HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP_SHIFT) +#define HDA_PARAM_PIN_CAP_TRIGGER_REQD(param) \ + (((param) & HDA_PARAM_PIN_CAP_TRIGGER_REQD_MASK) >> \ + HDA_PARAM_PIN_CAP_TRIGGER_REQD_SHIFT) +#define HDA_PARAM_PIN_CAP_IMP_SENSE_CAP(param) \ + (((param) & HDA_PARAM_PIN_CAP_IMP_SENSE_CAP_MASK) >> \ + HDA_PARAM_PIN_CAP_IMP_SENSE_CAP_SHIFT) + +/* Input Amplifier Capabilities */ +#define HDA_PARAM_INPUT_AMP_CAP 0x0d + +#define HDA_PARAM_INPUT_AMP_CAP_MUTE_CAP_MASK 0x80000000 +#define HDA_PARAM_INPUT_AMP_CAP_MUTE_CAP_SHIFT 31 +#define HDA_PARAM_INPUT_AMP_CAP_STEPSIZE_MASK 0x007f0000 +#define HDA_PARAM_INPUT_AMP_CAP_STEPSIZE_SHIFT 16 +#define HDA_PARAM_INPUT_AMP_CAP_NUMSTEPS_MASK 0x00007f00 +#define HDA_PARAM_INPUT_AMP_CAP_NUMSTEPS_SHIFT 8 +#define HDA_PARAM_INPUT_AMP_CAP_OFFSET_MASK 0x0000007f +#define HDA_PARAM_INPUT_AMP_CAP_OFFSET_SHIFT 0 + +#define HDA_PARAM_INPUT_AMP_CAP_MUTE_CAP(param) \ + (((param) & HDA_PARAM_INPUT_AMP_CAP_MUTE_CAP_MASK) >> \ + HDA_PARAM_INPUT_AMP_CAP_MUTE_CAP_SHIFT) +#define HDA_PARAM_INPUT_AMP_CAP_STEPSIZE(param) \ + (((param) & HDA_PARAM_INPUT_AMP_CAP_STEPSIZE_MASK) >> \ + HDA_PARAM_INPUT_AMP_CAP_STEPSIZE_SHIFT) +#define HDA_PARAM_INPUT_AMP_CAP_NUMSTEPS(param) \ + (((param) & HDA_PARAM_INPUT_AMP_CAP_NUMSTEPS_MASK) >> \ + HDA_PARAM_INPUT_AMP_CAP_NUMSTEPS_SHIFT) +#define HDA_PARAM_INPUT_AMP_CAP_OFFSET(param) \ + (((param) & HDA_PARAM_INPUT_AMP_CAP_OFFSET_MASK) >> \ + HDA_PARAM_INPUT_AMP_CAP_OFFSET_SHIFT) + +/* Output Amplifier Capabilities */ +#define HDA_PARAM_OUTPUT_AMP_CAP 0x12 + +#define HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP_MASK 0x80000000 +#define HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP_SHIFT 31 +#define HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_MASK 0x007f0000 +#define HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_SHIFT 16 +#define HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_MASK 0x00007f00 +#define HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_SHIFT 8 +#define HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_MASK 0x0000007f +#define HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_SHIFT 0 + +#define HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP(param) \ + (((param) & HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP_MASK) >> \ + HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP_SHIFT) +#define HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE(param) \ + (((param) & HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_MASK) >> \ + HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_SHIFT) +#define HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS(param) \ + (((param) & HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_MASK) >> \ + HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_SHIFT) +#define HDA_PARAM_OUTPUT_AMP_CAP_OFFSET(param) \ + (((param) & HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_MASK) >> \ + HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_SHIFT) + +/* Connection List Length */ +#define HDA_PARAM_CONN_LIST_LENGTH 0x0e + +#define HDA_PARAM_CONN_LIST_LENGTH_LONG_FORM_MASK 0x00000080 +#define HDA_PARAM_CONN_LIST_LENGTH_LONG_FORM_SHIFT 7 +#define HDA_PARAM_CONN_LIST_LENGTH_LIST_LENGTH_MASK 0x0000007f +#define HDA_PARAM_CONN_LIST_LENGTH_LIST_LENGTH_SHIFT 0 + +#define HDA_PARAM_CONN_LIST_LENGTH_LONG_FORM(param) \ + (((param) & HDA_PARAM_CONN_LIST_LENGTH_LONG_FORM_MASK) >> \ + HDA_PARAM_CONN_LIST_LENGTH_LONG_FORM_SHIFT) +#define HDA_PARAM_CONN_LIST_LENGTH_LIST_LENGTH(param) \ + (((param) & HDA_PARAM_CONN_LIST_LENGTH_LIST_LENGTH_MASK) >> \ + HDA_PARAM_CONN_LIST_LENGTH_LIST_LENGTH_SHIFT) + +/* Supported Power States */ +#define HDA_PARAM_SUPP_POWER_STATES 0x0f + +#define HDA_PARAM_SUPP_POWER_STATES_D3_MASK 0x00000008 +#define HDA_PARAM_SUPP_POWER_STATES_D3_SHIFT 3 +#define HDA_PARAM_SUPP_POWER_STATES_D2_MASK 0x00000004 +#define HDA_PARAM_SUPP_POWER_STATES_D2_SHIFT 2 +#define HDA_PARAM_SUPP_POWER_STATES_D1_MASK 0x00000002 +#define HDA_PARAM_SUPP_POWER_STATES_D1_SHIFT 1 +#define HDA_PARAM_SUPP_POWER_STATES_D0_MASK 0x00000001 +#define HDA_PARAM_SUPP_POWER_STATES_D0_SHIFT 0 + +#define HDA_PARAM_SUPP_POWER_STATES_D3(param) \ + (((param) & HDA_PARAM_SUPP_POWER_STATES_D3_MASK) >> \ + HDA_PARAM_SUPP_POWER_STATES_D3_SHIFT) +#define HDA_PARAM_SUPP_POWER_STATES_D2(param) \ + (((param) & HDA_PARAM_SUPP_POWER_STATES_D2_MASK) >> \ + HDA_PARAM_SUPP_POWER_STATES_D2_SHIFT) +#define HDA_PARAM_SUPP_POWER_STATES_D1(param) \ + (((param) & HDA_PARAM_SUPP_POWER_STATES_D1_MASK) >> \ + HDA_PARAM_SUPP_POWER_STATES_D1_SHIFT) +#define HDA_PARAM_SUPP_POWER_STATES_D0(param) \ + (((param) & HDA_PARAM_SUPP_POWER_STATES_D0_MASK) >> \ + HDA_PARAM_SUPP_POWER_STATES_D0_SHIFT) + +/* Processing Capabilities */ +#define HDA_PARAM_PROCESSING_CAP 0x10 + +#define HDA_PARAM_PROCESSING_CAP_NUMCOEFF_MASK 0x0000ff00 +#define HDA_PARAM_PROCESSING_CAP_NUMCOEFF_SHIFT 8 +#define HDA_PARAM_PROCESSING_CAP_BENIGN_MASK 0x00000001 +#define HDA_PARAM_PROCESSING_CAP_BENIGN_SHIFT 0 + +#define HDA_PARAM_PROCESSING_CAP_NUMCOEFF(param) \ + (((param) & HDA_PARAM_PROCESSING_CAP_NUMCOEFF_MASK) >> \ + HDA_PARAM_PROCESSING_CAP_NUMCOEFF_SHIFT) +#define HDA_PARAM_PROCESSING_CAP_BENIGN(param) \ + (((param) & HDA_PARAM_PROCESSING_CAP_BENIGN_MASK) >> \ + HDA_PARAM_PROCESSING_CAP_BENIGN_SHIFT) + +/* GPIO Count */ +#define HDA_PARAM_GPIO_COUNT 0x11 + +#define HDA_PARAM_GPIO_COUNT_GPI_WAKE_MASK 0x80000000 +#define HDA_PARAM_GPIO_COUNT_GPI_WAKE_SHIFT 31 +#define HDA_PARAM_GPIO_COUNT_GPI_UNSOL_MASK 0x40000000 +#define HDA_PARAM_GPIO_COUNT_GPI_UNSOL_SHIFT 30 +#define HDA_PARAM_GPIO_COUNT_NUM_GPI_MASK 0x00ff0000 +#define HDA_PARAM_GPIO_COUNT_NUM_GPI_SHIFT 16 +#define HDA_PARAM_GPIO_COUNT_NUM_GPO_MASK 0x0000ff00 +#define HDA_PARAM_GPIO_COUNT_NUM_GPO_SHIFT 8 +#define HDA_PARAM_GPIO_COUNT_NUM_GPIO_MASK 0x000000ff +#define HDA_PARAM_GPIO_COUNT_NUM_GPIO_SHIFT 0 + +#define HDA_PARAM_GPIO_COUNT_GPI_WAKE(param) \ + (((param) & HDA_PARAM_GPIO_COUNT_GPI_WAKE_MASK) >> \ + HDA_PARAM_GPIO_COUNT_GPI_WAKE_SHIFT) +#define HDA_PARAM_GPIO_COUNT_GPI_UNSOL(param) \ + (((param) & HDA_PARAM_GPIO_COUNT_GPI_UNSOL_MASK) >> \ + HDA_PARAM_GPIO_COUNT_GPI_UNSOL_SHIFT) +#define HDA_PARAM_GPIO_COUNT_NUM_GPI(param) \ + (((param) & HDA_PARAM_GPIO_COUNT_NUM_GPI_MASK) >> \ + HDA_PARAM_GPIO_COUNT_NUM_GPI_SHIFT) +#define HDA_PARAM_GPIO_COUNT_NUM_GPO(param) \ + (((param) & HDA_PARAM_GPIO_COUNT_NUM_GPO_MASK) >> \ + HDA_PARAM_GPIO_COUNT_NUM_GPO_SHIFT) +#define HDA_PARAM_GPIO_COUNT_NUM_GPIO(param) \ + (((param) & HDA_PARAM_GPIO_COUNT_NUM_GPIO_MASK) >> \ + HDA_PARAM_GPIO_COUNT_NUM_GPIO_SHIFT) + +/* Volume Knob Capabilities */ +#define HDA_PARAM_VOLUME_KNOB_CAP 0x13 + +#define HDA_PARAM_VOLUME_KNOB_CAP_DELTA_MASK 0x00000080 +#define HDA_PARAM_VOLUME_KNOB_CAP_DELTA_SHIFT 7 +#define HDA_PARAM_VOLUME_KNOB_CAP_NUM_STEPS_MASK 0x0000007f +#define HDA_PARAM_VOLUME_KNOB_CAP_NUM_STEPS_SHIFT 0 + +#define HDA_PARAM_VOLUME_KNOB_CAP_DELTA(param) \ + (((param) & HDA_PARAM_VOLUME_KNOB_CAP_DELTA_MASK) >> \ + HDA_PARAM_VOLUME_KNOB_CAP_DELTA_SHIFT) +#define HDA_PARAM_VOLUME_KNOB_CAP_NUM_STEPS(param) \ + (((param) & HDA_PARAM_VOLUME_KNOB_CAP_NUM_STEPS_MASK) >> \ + HDA_PARAM_VOLUME_KNOB_CAP_NUM_STEPS_SHIFT) + + +#define HDA_CONFIG_DEFAULTCONF_SEQUENCE_MASK 0x0000000f +#define HDA_CONFIG_DEFAULTCONF_SEQUENCE_SHIFT 0 +#define HDA_CONFIG_DEFAULTCONF_ASSOCIATION_MASK 0x000000f0 +#define HDA_CONFIG_DEFAULTCONF_ASSOCIATION_SHIFT 4 +#define HDA_CONFIG_DEFAULTCONF_MISC_MASK 0x00000f00 +#define HDA_CONFIG_DEFAULTCONF_MISC_SHIFT 8 +#define HDA_CONFIG_DEFAULTCONF_COLOR_MASK 0x0000f000 +#define HDA_CONFIG_DEFAULTCONF_COLOR_SHIFT 12 +#define HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_MASK 0x000f0000 +#define HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_SHIFT 16 +#define HDA_CONFIG_DEFAULTCONF_DEVICE_MASK 0x00f00000 +#define HDA_CONFIG_DEFAULTCONF_DEVICE_SHIFT 20 +#define HDA_CONFIG_DEFAULTCONF_LOCATION_MASK 0x3f000000 +#define HDA_CONFIG_DEFAULTCONF_LOCATION_SHIFT 24 +#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK 0xc0000000 +#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_SHIFT 30 + +#define HDA_CONFIG_DEFAULTCONF_SEQUENCE(conf) \ + (((conf) & HDA_CONFIG_DEFAULTCONF_SEQUENCE_MASK) >> \ + HDA_CONFIG_DEFAULTCONF_SEQUENCE_SHIFT) +#define HDA_CONFIG_DEFAULTCONF_ASSOCIATION(conf) \ + (((conf) & HDA_CONFIG_DEFAULTCONF_ASSOCIATION_MASK) >> \ + HDA_CONFIG_DEFAULTCONF_ASSOCIATION_SHIFT) +#define HDA_CONFIG_DEFAULTCONF_MISC(conf) \ + (((conf) & HDA_CONFIG_DEFAULTCONF_MISC_MASK) >> \ + HDA_CONFIG_DEFAULTCONF_MISC_SHIFT) +#define HDA_CONFIG_DEFAULTCONF_COLOR(conf) \ + (((conf) & HDA_CONFIG_DEFAULTCONF_COLOR_MASK) >> \ + HDA_CONFIG_DEFAULTCONF_COLOR_SHIFT) +#define HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE(conf) \ + (((conf) & HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_MASK) >> \ + HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_SHIFT) +#define HDA_CONFIG_DEFAULTCONF_DEVICE(conf) \ + (((conf) & HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) >> \ + HDA_CONFIG_DEFAULTCONF_DEVICE_SHIFT) +#define HDA_CONFIG_DEFAULTCONF_LOCATION(conf) \ + (((conf) & HDA_CONFIG_DEFAULTCONF_LOCATION_MASK) >> \ + HDA_CONFIG_DEFAULTCONF_LOCATION_SHIFT) +#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY(conf) \ + (((conf) & HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) >> \ + HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_SHIFT) + +#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK (0<<30) +#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE (1<<30) +#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED (2<<30) +#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_BOTH (3<<30) + +#define HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT (0<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_SPEAKER (1<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT (2<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_CD (3<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_OUT (4<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_OUT (5<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_MODEM_LINE (6<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_MODEM_HANDSET (7<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN (8<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_AUX (9<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN (10<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_TELEPHONY (11<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_IN (12<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_IN (13<<20) +#define HDA_CONFIG_DEFAULTCONF_DEVICE_OTHER (15<<20) + +#endif /* _HDA_REG_H_ */ diff --git a/usr.sbin/bhyve/hdac_reg.h b/usr.sbin/bhyve/hdac_reg.h new file mode 100644 index 000000000000..2bef0d0edc35 --- /dev/null +++ b/usr.sbin/bhyve/hdac_reg.h @@ -0,0 +1,269 @@ +/*- + * Copyright (c) 2006 Stephane E. Potvin + * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$ + */ + +#ifndef _HDAC_REG_H_ +#define _HDAC_REG_H_ + +/**************************************************************************** + * HDA Controller Register Set + ****************************************************************************/ +#define HDAC_GCAP 0x00 /* 2 - Global Capabilities*/ +#define HDAC_VMIN 0x02 /* 1 - Minor Version */ +#define HDAC_VMAJ 0x03 /* 1 - Major Version */ +#define HDAC_OUTPAY 0x04 /* 2 - Output Payload Capability */ +#define HDAC_INPAY 0x06 /* 2 - Input Payload Capability */ +#define HDAC_GCTL 0x08 /* 4 - Global Control */ +#define HDAC_WAKEEN 0x0c /* 2 - Wake Enable */ +#define HDAC_STATESTS 0x0e /* 2 - State Change Status */ +#define HDAC_GSTS 0x10 /* 2 - Global Status */ +#define HDAC_OUTSTRMPAY 0x18 /* 2 - Output Stream Payload Capability */ +#define HDAC_INSTRMPAY 0x1a /* 2 - Input Stream Payload Capability */ +#define HDAC_INTCTL 0x20 /* 4 - Interrupt Control */ +#define HDAC_INTSTS 0x24 /* 4 - Interrupt Status */ +#define HDAC_WALCLK 0x30 /* 4 - Wall Clock Counter */ +#define HDAC_SSYNC 0x38 /* 4 - Stream Synchronization */ +#define HDAC_CORBLBASE 0x40 /* 4 - CORB Lower Base Address */ +#define HDAC_CORBUBASE 0x44 /* 4 - CORB Upper Base Address */ +#define HDAC_CORBWP 0x48 /* 2 - CORB Write Pointer */ +#define HDAC_CORBRP 0x4a /* 2 - CORB Read Pointer */ +#define HDAC_CORBCTL 0x4c /* 1 - CORB Control */ +#define HDAC_CORBSTS 0x4d /* 1 - CORB Status */ +#define HDAC_CORBSIZE 0x4e /* 1 - CORB Size */ +#define HDAC_RIRBLBASE 0x50 /* 4 - RIRB Lower Base Address */ +#define HDAC_RIRBUBASE 0x54 /* 4 - RIRB Upper Base Address */ +#define HDAC_RIRBWP 0x58 /* 2 - RIRB Write Pointer */ +#define HDAC_RINTCNT 0x5a /* 2 - Response Interrupt Count */ +#define HDAC_RIRBCTL 0x5c /* 1 - RIRB Control */ +#define HDAC_RIRBSTS 0x5d /* 1 - RIRB Status */ +#define HDAC_RIRBSIZE 0x5e /* 1 - RIRB Size */ +#define HDAC_ICOI 0x60 /* 4 - Immediate Command Output Interface */ +#define HDAC_ICII 0x64 /* 4 - Immediate Command Input Interface */ +#define HDAC_ICIS 0x68 /* 2 - Immediate Command Status */ +#define HDAC_DPIBLBASE 0x70 /* 4 - DMA Position Buffer Lower Base */ +#define HDAC_DPIBUBASE 0x74 /* 4 - DMA Position Buffer Upper Base */ +#define HDAC_SDCTL0 0x80 /* 3 - Stream Descriptor Control */ +#define HDAC_SDCTL1 0x81 /* 3 - Stream Descriptor Control */ +#define HDAC_SDCTL2 0x82 /* 3 - Stream Descriptor Control */ +#define HDAC_SDSTS 0x83 /* 1 - Stream Descriptor Status */ +#define HDAC_SDLPIB 0x84 /* 4 - Link Position in Buffer */ +#define HDAC_SDCBL 0x88 /* 4 - Cyclic Buffer Length */ +#define HDAC_SDLVI 0x8C /* 2 - Last Valid Index */ +#define HDAC_SDFIFOS 0x90 /* 2 - FIFOS */ +#define HDAC_SDFMT 0x92 /* 2 - fmt */ +#define HDAC_SDBDPL 0x98 /* 4 - Buffer Descriptor Pointer Lower Base */ +#define HDAC_SDBDPU 0x9C /* 4 - Buffer Descriptor Pointer Upper Base */ + +#define _HDAC_ISDOFFSET(n, iss, oss) (0x80 + ((n) * 0x20)) +#define _HDAC_ISDCTL(n, iss, oss) (0x00 + _HDAC_ISDOFFSET(n, iss, oss)) +#define _HDAC_ISDSTS(n, iss, oss) (0x03 + _HDAC_ISDOFFSET(n, iss, oss)) +#define _HDAC_ISDPICB(n, iss, oss) (0x04 + _HDAC_ISDOFFSET(n, iss, oss)) +#define _HDAC_ISDCBL(n, iss, oss) (0x08 + _HDAC_ISDOFFSET(n, iss, oss)) +#define _HDAC_ISDLVI(n, iss, oss) (0x0c + _HDAC_ISDOFFSET(n, iss, oss)) +#define _HDAC_ISDFIFOD(n, iss, oss) (0x10 + _HDAC_ISDOFFSET(n, iss, oss)) +#define _HDAC_ISDFMT(n, iss, oss) (0x12 + _HDAC_ISDOFFSET(n, iss, oss)) +#define _HDAC_ISDBDPL(n, iss, oss) (0x18 + _HDAC_ISDOFFSET(n, iss, oss)) +#define _HDAC_ISDBDPU(n, iss, oss) (0x1c + _HDAC_ISDOFFSET(n, iss, oss)) + +#define _HDAC_OSDOFFSET(n, iss, oss) (0x80 + ((iss) * 0x20) + ((n) * 0x20)) +#define _HDAC_OSDCTL(n, iss, oss) (0x00 + _HDAC_OSDOFFSET(n, iss, oss)) +#define _HDAC_OSDSTS(n, iss, oss) (0x03 + _HDAC_OSDOFFSET(n, iss, oss)) +#define _HDAC_OSDPICB(n, iss, oss) (0x04 + _HDAC_OSDOFFSET(n, iss, oss)) +#define _HDAC_OSDCBL(n, iss, oss) (0x08 + _HDAC_OSDOFFSET(n, iss, oss)) +#define _HDAC_OSDLVI(n, iss, oss) (0x0c + _HDAC_OSDOFFSET(n, iss, oss)) +#define _HDAC_OSDFIFOD(n, iss, oss) (0x10 + _HDAC_OSDOFFSET(n, iss, oss)) +#define _HDAC_OSDFMT(n, iss, oss) (0x12 + _HDAC_OSDOFFSET(n, iss, oss)) +#define _HDAC_OSDBDPL(n, iss, oss) (0x18 + _HDAC_OSDOFFSET(n, iss, oss)) +#define _HDAC_OSDBDPU(n, iss, oss) (0x1c + _HDAC_OSDOFFSET(n, iss, oss)) + +#define _HDAC_BSDOFFSET(n, iss, oss) \ + (0x80 + ((iss) * 0x20) + ((oss) * 0x20) + ((n) * 0x20)) +#define _HDAC_BSDCTL(n, iss, oss) (0x00 + _HDAC_BSDOFFSET(n, iss, oss)) +#define _HDAC_BSDSTS(n, iss, oss) (0x03 + _HDAC_BSDOFFSET(n, iss, oss)) +#define _HDAC_BSDPICB(n, iss, oss) (0x04 + _HDAC_BSDOFFSET(n, iss, oss)) +#define _HDAC_BSDCBL(n, iss, oss) (0x08 + _HDAC_BSDOFFSET(n, iss, oss)) +#define _HDAC_BSDLVI(n, iss, oss) (0x0c + _HDAC_BSDOFFSET(n, iss, oss)) +#define _HDAC_BSDFIFOD(n, iss, oss) (0x10 + _HDAC_BSDOFFSET(n, iss, oss)) +#define _HDAC_BSDFMT(n, iss, oss) (0x12 + _HDAC_BSDOFFSET(n, iss, oss)) +#define _HDAC_BSDBDPL(n, iss, oss) (0x18 + _HDAC_BSDOFFSET(n, iss, oss)) +#define _HDAC_BSDBDBU(n, iss, oss) (0x1c + _HDAC_BSDOFFSET(n, iss, oss)) + +/**************************************************************************** + * HDA Controller Register Fields + ****************************************************************************/ + +/* GCAP - Global Capabilities */ +#define HDAC_GCAP_64OK 0x0001 +#define HDAC_GCAP_NSDO_MASK 0x0006 +#define HDAC_GCAP_NSDO_SHIFT 1 +#define HDAC_GCAP_BSS_MASK 0x00f8 +#define HDAC_GCAP_BSS_SHIFT 3 +#define HDAC_GCAP_ISS_MASK 0x0f00 +#define HDAC_GCAP_ISS_SHIFT 8 +#define HDAC_GCAP_OSS_MASK 0xf000 +#define HDAC_GCAP_OSS_SHIFT 12 + +#define HDAC_GCAP_NSDO_1SDO 0x00 +#define HDAC_GCAP_NSDO_2SDO 0x02 +#define HDAC_GCAP_NSDO_4SDO 0x04 + +#define HDAC_GCAP_BSS(gcap) \ + (((gcap) & HDAC_GCAP_BSS_MASK) >> HDAC_GCAP_BSS_SHIFT) +#define HDAC_GCAP_ISS(gcap) \ + (((gcap) & HDAC_GCAP_ISS_MASK) >> HDAC_GCAP_ISS_SHIFT) +#define HDAC_GCAP_OSS(gcap) \ + (((gcap) & HDAC_GCAP_OSS_MASK) >> HDAC_GCAP_OSS_SHIFT) +#define HDAC_GCAP_NSDO(gcap) \ + (((gcap) & HDAC_GCAP_NSDO_MASK) >> HDAC_GCAP_NSDO_SHIFT) + +/* GCTL - Global Control */ +#define HDAC_GCTL_CRST 0x00000001 +#define HDAC_GCTL_FCNTRL 0x00000002 +#define HDAC_GCTL_UNSOL 0x00000100 + +/* WAKEEN - Wake Enable */ +#define HDAC_WAKEEN_SDIWEN_MASK 0x7fff +#define HDAC_WAKEEN_SDIWEN_SHIFT 0 + +/* STATESTS - State Change Status */ +#define HDAC_STATESTS_SDIWAKE_MASK 0x7fff +#define HDAC_STATESTS_SDIWAKE_SHIFT 0 + +#define HDAC_STATESTS_SDIWAKE(statests, n) \ + (((((statests) & HDAC_STATESTS_SDIWAKE_MASK) >> \ + HDAC_STATESTS_SDIWAKE_SHIFT) >> (n)) & 0x0001) + +/* GSTS - Global Status */ +#define HDAC_GSTS_FSTS 0x0002 + +/* INTCTL - Interrut Control */ +#define HDAC_INTCTL_SIE_MASK 0x3fffffff +#define HDAC_INTCTL_SIE_SHIFT 0 +#define HDAC_INTCTL_CIE 0x40000000 +#define HDAC_INTCTL_GIE 0x80000000 + +/* INTSTS - Interrupt Status */ +#define HDAC_INTSTS_SIS_MASK 0x3fffffff +#define HDAC_INTSTS_SIS_SHIFT 0 +#define HDAC_INTSTS_CIS 0x40000000 +#define HDAC_INTSTS_GIS 0x80000000 + +/* SSYNC - Stream Synchronization */ +#define HDAC_SSYNC_SSYNC_MASK 0x3fffffff +#define HDAC_SSYNC_SSYNC_SHIFT 0 + +/* CORBWP - CORB Write Pointer */ +#define HDAC_CORBWP_CORBWP_MASK 0x00ff +#define HDAC_CORBWP_CORBWP_SHIFT 0 + +/* CORBRP - CORB Read Pointer */ +#define HDAC_CORBRP_CORBRP_MASK 0x00ff +#define HDAC_CORBRP_CORBRP_SHIFT 0 +#define HDAC_CORBRP_CORBRPRST 0x8000 + +/* CORBCTL - CORB Control */ +#define HDAC_CORBCTL_CMEIE 0x01 +#define HDAC_CORBCTL_CORBRUN 0x02 + +/* CORBSTS - CORB Status */ +#define HDAC_CORBSTS_CMEI 0x01 + +/* CORBSIZE - CORB Size */ +#define HDAC_CORBSIZE_CORBSIZE_MASK 0x03 +#define HDAC_CORBSIZE_CORBSIZE_SHIFT 0 +#define HDAC_CORBSIZE_CORBSZCAP_MASK 0xf0 +#define HDAC_CORBSIZE_CORBSZCAP_SHIFT 4 + +#define HDAC_CORBSIZE_CORBSIZE_2 0x00 +#define HDAC_CORBSIZE_CORBSIZE_16 0x01 +#define HDAC_CORBSIZE_CORBSIZE_256 0x02 + +#define HDAC_CORBSIZE_CORBSZCAP_2 0x10 +#define HDAC_CORBSIZE_CORBSZCAP_16 0x20 +#define HDAC_CORBSIZE_CORBSZCAP_256 0x40 + +#define HDAC_CORBSIZE_CORBSIZE(corbsize) \ + (((corbsize) & HDAC_CORBSIZE_CORBSIZE_MASK) >> HDAC_CORBSIZE_CORBSIZE_SHIFT) + +/* RIRBWP - RIRB Write Pointer */ +#define HDAC_RIRBWP_RIRBWP_MASK 0x00ff +#define HDAC_RIRBWP_RIRBWP_SHIFT 0 +#define HDAC_RIRBWP_RIRBWPRST 0x8000 + +/* RINTCTN - Response Interrupt Count */ +#define HDAC_RINTCNT_MASK 0x00ff +#define HDAC_RINTCNT_SHIFT 0 + +/* RIRBCTL - RIRB Control */ +#define HDAC_RIRBCTL_RINTCTL 0x01 +#define HDAC_RIRBCTL_RIRBDMAEN 0x02 +#define HDAC_RIRBCTL_RIRBOIC 0x04 + +/* RIRBSTS - RIRB Status */ +#define HDAC_RIRBSTS_RINTFL 0x01 +#define HDAC_RIRBSTS_RIRBOIS 0x04 + +/* RIRBSIZE - RIRB Size */ +#define HDAC_RIRBSIZE_RIRBSIZE_MASK 0x03 +#define HDAC_RIRBSIZE_RIRBSIZE_SHIFT 0 +#define HDAC_RIRBSIZE_RIRBSZCAP_MASK 0xf0 +#define HDAC_RIRBSIZE_RIRBSZCAP_SHIFT 4 + +#define HDAC_RIRBSIZE_RIRBSIZE_2 0x00 +#define HDAC_RIRBSIZE_RIRBSIZE_16 0x01 +#define HDAC_RIRBSIZE_RIRBSIZE_256 0x02 + +#define HDAC_RIRBSIZE_RIRBSZCAP_2 0x10 +#define HDAC_RIRBSIZE_RIRBSZCAP_16 0x20 +#define HDAC_RIRBSIZE_RIRBSZCAP_256 0x40 + +#define HDAC_RIRBSIZE_RIRBSIZE(rirbsize) \ + (((rirbsize) & HDAC_RIRBSIZE_RIRBSIZE_MASK) >> HDAC_RIRBSIZE_RIRBSIZE_SHIFT) + +/* DPLBASE - DMA Position Lower Base Address */ +#define HDAC_DPLBASE_DPLBASE_MASK 0xffffff80 +#define HDAC_DPLBASE_DPLBASE_SHIFT 7 +#define HDAC_DPLBASE_DPLBASE_DMAPBE 0x00000001 + +/* SDCTL - Stream Descriptor Control */ +#define HDAC_SDCTL_SRST 0x000001 +#define HDAC_SDCTL_RUN 0x000002 +#define HDAC_SDCTL_IOCE 0x000004 +#define HDAC_SDCTL_FEIE 0x000008 +#define HDAC_SDCTL_DEIE 0x000010 +#define HDAC_SDCTL2_STRIPE_MASK 0x03 +#define HDAC_SDCTL2_STRIPE_SHIFT 0 +#define HDAC_SDCTL2_TP 0x04 +#define HDAC_SDCTL2_DIR 0x08 +#define HDAC_SDCTL2_STRM_MASK 0xf0 +#define HDAC_SDCTL2_STRM_SHIFT 4 + +#define HDAC_SDSTS_DESE (1 << 4) +#define HDAC_SDSTS_FIFOE (1 << 3) +#define HDAC_SDSTS_BCIS (1 << 2) + +#endif /* _HDAC_REG_H_ */ diff --git a/usr.sbin/bhyve/pci_hda.c b/usr.sbin/bhyve/pci_hda.c new file mode 100644 index 000000000000..99f8aec31c6e --- /dev/null +++ b/usr.sbin/bhyve/pci_hda.c @@ -0,0 +1,1330 @@ +/*- + * Copyright (c) 2016 Alex Teaca + * 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, 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 OR CONTRIBUTORS 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 + +#include "pci_hda.h" +#include "bhyverun.h" +#include "pci_emul.h" +#include "hdac_reg.h" + +/* + * HDA defines + */ +#define PCIR_HDCTL 0x40 +#define INTEL_VENDORID 0x8086 +#define HDA_INTEL_82801G 0x27d8 + +#define HDA_IOSS_NO 0x08 +#define HDA_OSS_NO 0x04 +#define HDA_ISS_NO 0x04 +#define HDA_CODEC_MAX 0x0f +#define HDA_LAST_OFFSET \ + (0x2084 + ((HDA_ISS_NO) * 0x20) + ((HDA_OSS_NO) * 0x20)) +#define HDA_SET_REG_TABLE_SZ \ + (0x80 + ((HDA_ISS_NO) * 0x20) + ((HDA_OSS_NO) * 0x20)) +#define HDA_CORB_ENTRY_LEN 0x04 +#define HDA_RIRB_ENTRY_LEN 0x08 +#define HDA_BDL_ENTRY_LEN 0x10 +#define HDA_DMA_PIB_ENTRY_LEN 0x08 +#define HDA_STREAM_TAGS_CNT 0x10 +#define HDA_STREAM_REGS_BASE 0x80 +#define HDA_STREAM_REGS_LEN 0x20 + +#define HDA_DMA_ACCESS_LEN (sizeof(uint32_t)) +#define HDA_BDL_MAX_LEN 0x0100 + +#define HDAC_SDSTS_FIFORDY (1 << 5) + +#define HDA_RIRBSTS_IRQ_MASK (HDAC_RIRBSTS_RINTFL | HDAC_RIRBSTS_RIRBOIS) +#define HDA_STATESTS_IRQ_MASK ((1 << HDA_CODEC_MAX) - 1) +#define HDA_SDSTS_IRQ_MASK \ + (HDAC_SDSTS_DESE | HDAC_SDSTS_FIFOE | HDAC_SDSTS_BCIS) + +/* + * HDA data structures + */ + +struct hda_softc; + +typedef void (*hda_set_reg_handler)(struct hda_softc *sc, uint32_t offset, + uint32_t old); + +struct hda_bdle { + uint32_t addrh; + uint32_t addrl; + uint32_t ioc; + uint32_t len; +} __packed; + +struct hda_bdle_desc { + void *addr; + uint8_t ioc; + uint32_t len; +}; + +struct hda_codec_cmd_ctl { + char *name; + void *dma_vaddr; + uint8_t run; + uint16_t rp; + uint16_t size; + uint16_t wp; +}; + +struct hda_stream_desc { + uint8_t dir; + uint8_t run; + uint8_t stream; + + /* bp is the no. of bytes transferred in the current bdle */ + uint32_t bp; + /* be is the no. of bdles transferred in the bdl */ + uint32_t be; + + uint32_t bdl_cnt; + struct hda_bdle_desc bdl[HDA_BDL_MAX_LEN]; +}; + +struct hda_softc { + struct pci_devinst *pci_dev; + uint32_t regs[HDA_LAST_OFFSET]; + + uint8_t lintr; + uint8_t rirb_cnt; + uint64_t wall_clock_start; + + struct hda_codec_cmd_ctl corb; + struct hda_codec_cmd_ctl rirb; + + uint8_t codecs_no; + struct hda_codec_inst *codecs[HDA_CODEC_MAX]; + + /* Base Address of the DMA Position Buffer */ + void *dma_pib_vaddr; + + struct hda_stream_desc streams[HDA_IOSS_NO]; + /* 2 tables for output and input */ + uint8_t stream_map[2][HDA_STREAM_TAGS_CNT]; +}; + +/* + * HDA module function declarations + */ +static inline void hda_set_reg_by_offset(struct hda_softc *sc, uint32_t offset, + uint32_t value); +static inline uint32_t hda_get_reg_by_offset(struct hda_softc *sc, + uint32_t offset); +static inline void hda_set_field_by_offset(struct hda_softc *sc, + uint32_t offset, uint32_t mask, uint32_t value); + +static uint8_t hda_parse_config(const char *opts, const char *key, char *val); +static struct hda_softc *hda_init(const char *opts); +static void hda_update_intr(struct hda_softc *sc); +static void hda_response_interrupt(struct hda_softc *sc); +static int hda_codec_constructor(struct hda_softc *sc, + struct hda_codec_class *codec, const char *play, const char *rec, + const char *opts); +static struct hda_codec_class *hda_find_codec_class(const char *name); + +static int hda_send_command(struct hda_softc *sc, uint32_t verb); +static int hda_notify_codecs(struct hda_softc *sc, uint8_t run, + uint8_t stream, uint8_t dir); +static void hda_reset(struct hda_softc *sc); +static void hda_reset_regs(struct hda_softc *sc); +static void hda_stream_reset(struct hda_softc *sc, uint8_t stream_ind); +static int hda_stream_start(struct hda_softc *sc, uint8_t stream_ind); +static int hda_stream_stop(struct hda_softc *sc, uint8_t stream_ind); +static uint32_t hda_read(struct hda_softc *sc, uint32_t offset); +static int hda_write(struct hda_softc *sc, uint32_t offset, uint8_t size, + uint32_t value); + +static inline void hda_print_cmd_ctl_data(struct hda_codec_cmd_ctl *p); +static int hda_corb_start(struct hda_softc *sc); +static int hda_corb_run(struct hda_softc *sc); +static int hda_rirb_start(struct hda_softc *sc); + +static void *hda_dma_get_vaddr(struct hda_softc *sc, uint64_t dma_paddr, + size_t len); +static void hda_dma_st_dword(void *dma_vaddr, uint32_t data); +static uint32_t hda_dma_ld_dword(void *dma_vaddr); + +static inline uint8_t hda_get_stream_by_offsets(uint32_t offset, + uint8_t reg_offset); +static inline uint32_t hda_get_offset_stream(uint8_t stream_ind); + +static void hda_set_gctl(struct hda_softc *sc, uint32_t offset, uint32_t old); +static void hda_set_statests(struct hda_softc *sc, uint32_t offset, + uint32_t old); +static void hda_set_corbwp(struct hda_softc *sc, uint32_t offset, uint32_t old); +static void hda_set_corbctl(struct hda_softc *sc, uint32_t offset, + uint32_t old); +static void hda_set_rirbctl(struct hda_softc *sc, uint32_t offset, + uint32_t old); +static void hda_set_rirbsts(struct hda_softc *sc, uint32_t offset, + uint32_t old); +static void hda_set_dpiblbase(struct hda_softc *sc, uint32_t offset, + uint32_t old); +static void hda_set_sdctl(struct hda_softc *sc, uint32_t offset, uint32_t old); +static void hda_set_sdctl2(struct hda_softc *sc, uint32_t offset, uint32_t old); +static void hda_set_sdsts(struct hda_softc *sc, uint32_t offset, uint32_t old); + +static int hda_signal_state_change(struct hda_codec_inst *hci); +static int hda_response(struct hda_codec_inst *hci, uint32_t response, + uint8_t unsol); +static int hda_transfer(struct hda_codec_inst *hci, uint8_t stream, + uint8_t dir, void *buf, size_t count); + +static void hda_set_pib(struct hda_softc *sc, uint8_t stream_ind, uint32_t pib); +static uint64_t hda_get_clock_ns(void); + +/* + * PCI HDA function declarations + */ +static int pci_hda_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts); +static void pci_hda_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, + int baridx, uint64_t offset, int size, uint64_t value); +static uint64_t pci_hda_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, + int baridx, uint64_t offset, int size); +/* + * HDA global data + */ + +static const hda_set_reg_handler hda_set_reg_table[] = { + [HDAC_GCTL] = hda_set_gctl, + [HDAC_STATESTS] = hda_set_statests, + [HDAC_CORBWP] = hda_set_corbwp, + [HDAC_CORBCTL] = hda_set_corbctl, + [HDAC_RIRBCTL] = hda_set_rirbctl, + [HDAC_RIRBSTS] = hda_set_rirbsts, + [HDAC_DPIBLBASE] = hda_set_dpiblbase, + +#define HDAC_ISTREAM(n, iss, oss) \ + [_HDAC_ISDCTL(n, iss, oss)] = hda_set_sdctl, \ + [_HDAC_ISDCTL(n, iss, oss) + 2] = hda_set_sdctl2, \ + [_HDAC_ISDSTS(n, iss, oss)] = hda_set_sdsts, \ + +#define HDAC_OSTREAM(n, iss, oss) \ + [_HDAC_OSDCTL(n, iss, oss)] = hda_set_sdctl, \ + [_HDAC_OSDCTL(n, iss, oss) + 2] = hda_set_sdctl2, \ + [_HDAC_OSDSTS(n, iss, oss)] = hda_set_sdsts, \ + + HDAC_ISTREAM(0, HDA_ISS_NO, HDA_OSS_NO) + HDAC_ISTREAM(1, HDA_ISS_NO, HDA_OSS_NO) + HDAC_ISTREAM(2, HDA_ISS_NO, HDA_OSS_NO) + HDAC_ISTREAM(3, HDA_ISS_NO, HDA_OSS_NO) + + HDAC_OSTREAM(0, HDA_ISS_NO, HDA_OSS_NO) + HDAC_OSTREAM(1, HDA_ISS_NO, HDA_OSS_NO) + HDAC_OSTREAM(2, HDA_ISS_NO, HDA_OSS_NO) + HDAC_OSTREAM(3, HDA_ISS_NO, HDA_OSS_NO) + + [HDA_SET_REG_TABLE_SZ] = NULL, +}; + +static const uint16_t hda_corb_sizes[] = { + [HDAC_CORBSIZE_CORBSIZE_2] = 2, + [HDAC_CORBSIZE_CORBSIZE_16] = 16, + [HDAC_CORBSIZE_CORBSIZE_256] = 256, + [HDAC_CORBSIZE_CORBSIZE_MASK] = 0, +}; + +static const uint16_t hda_rirb_sizes[] = { + [HDAC_RIRBSIZE_RIRBSIZE_2] = 2, + [HDAC_RIRBSIZE_RIRBSIZE_16] = 16, + [HDAC_RIRBSIZE_RIRBSIZE_256] = 256, + [HDAC_RIRBSIZE_RIRBSIZE_MASK] = 0, +}; + +static struct hda_ops hops = { + .signal = hda_signal_state_change, + .response = hda_response, + .transfer = hda_transfer, +}; + +struct pci_devemu pci_de_hda = { + .pe_emu = "hda", + .pe_init = pci_hda_init, + .pe_barwrite = pci_hda_write, + .pe_barread = pci_hda_read +}; + +PCI_EMUL_SET(pci_de_hda); + +SET_DECLARE(hda_codec_class_set, struct hda_codec_class); + +#if DEBUG_HDA == 1 +FILE *dbg; +#endif + +/* + * HDA module function definitions + */ + +static inline void +hda_set_reg_by_offset(struct hda_softc *sc, uint32_t offset, uint32_t value) +{ + assert(offset < HDA_LAST_OFFSET); + sc->regs[offset] = value; +} + +static inline uint32_t +hda_get_reg_by_offset(struct hda_softc *sc, uint32_t offset) +{ + assert(offset < HDA_LAST_OFFSET); + return sc->regs[offset]; +} + +static inline void +hda_set_field_by_offset(struct hda_softc *sc, uint32_t offset, + uint32_t mask, uint32_t value) +{ + uint32_t reg_value = 0; + + reg_value = hda_get_reg_by_offset(sc, offset); + + reg_value &= ~mask; + reg_value |= (value & mask); + + hda_set_reg_by_offset(sc, offset, reg_value); +} + +static uint8_t +hda_parse_config(const char *opts, const char *key, char *val) +{ + char buf[64]; + char *s = buf; + char *tmp = NULL; + int len; + int i; + + if (!opts) + return (0); + + len = strlen(opts); + + if (len >= 64) { + DPRINTF("Opts too big\n"); + return (0); + } + + DPRINTF("opts: %s\n", opts); + + strcpy(buf, opts); + + for (i = 0; i < len; i++) + if (buf[i] == ',') { + buf[i] = 0; + tmp = buf + i + 1; + break; + } + + if (!memcmp(s, key, strlen(key))) { + strncpy(val, s + strlen(key), 64); + return (1); + } + + if (!tmp) + return (0); + + s = tmp; + if (!memcmp(s, key, strlen(key))) { + strncpy(val, s + strlen(key), 64); + return (1); + } + + return (0); +} + +static struct hda_softc * +hda_init(const char *opts) +{ + struct hda_softc *sc = NULL; + struct hda_codec_class *codec = NULL; + char play[64]; + char rec[64]; + int err, p, r; + +#if DEBUG_HDA == 1 + dbg = fopen("/tmp/bhyve_hda.log", "w+"); +#endif + + DPRINTF("opts: %s\n", opts); + + sc = calloc(1, sizeof(*sc)); + if (!sc) + return (NULL); + + hda_reset_regs(sc); + + /* + * TODO search all the codecs declared in opts + * For now we play with one single codec + */ + codec = hda_find_codec_class("hda_codec"); + if (codec) { + p = hda_parse_config(opts, "play=", play); + r = hda_parse_config(opts, "rec=", rec); + DPRINTF("play: %s rec: %s\n", play, rec); + if (p | r) { + err = hda_codec_constructor(sc, codec, p ? \ + play : NULL, r ? rec : NULL, NULL); + assert(!err); + } + } + + return (sc); +} + +static void +hda_update_intr(struct hda_softc *sc) +{ + struct pci_devinst *pi = sc->pci_dev; + uint32_t intctl = hda_get_reg_by_offset(sc, HDAC_INTCTL); + uint32_t intsts = 0; + uint32_t sdsts = 0; + uint32_t rirbsts = 0; + uint32_t wakeen = 0; + uint32_t statests = 0; + uint32_t off = 0; + int i; + + /* update the CIS bits */ + rirbsts = hda_get_reg_by_offset(sc, HDAC_RIRBSTS); + if (rirbsts & (HDAC_RIRBSTS_RINTFL | HDAC_RIRBSTS_RIRBOIS)) + intsts |= HDAC_INTSTS_CIS; + + wakeen = hda_get_reg_by_offset(sc, HDAC_WAKEEN); + statests = hda_get_reg_by_offset(sc, HDAC_STATESTS); + if (statests & wakeen) + intsts |= HDAC_INTSTS_CIS; + + /* update the SIS bits */ + for (i = 0; i < HDA_IOSS_NO; i++) { + off = hda_get_offset_stream(i); + sdsts = hda_get_reg_by_offset(sc, off + HDAC_SDSTS); + if (sdsts & HDAC_SDSTS_BCIS) + intsts |= (1 << i); + } + + /* update the GIS bit */ + if (intsts) + intsts |= HDAC_INTSTS_GIS; + + hda_set_reg_by_offset(sc, HDAC_INTSTS, intsts); + + if ((intctl & HDAC_INTCTL_GIE) && ((intsts & \ + ~HDAC_INTSTS_GIS) & intctl)) { + if (!sc->lintr) { + pci_lintr_assert(pi); + sc->lintr = 1; + } + } else { + if (sc->lintr) { + pci_lintr_deassert(pi); + sc->lintr = 0; + } + } +} + +static void +hda_response_interrupt(struct hda_softc *sc) +{ + uint8_t rirbctl = hda_get_reg_by_offset(sc, HDAC_RIRBCTL); + + if ((rirbctl & HDAC_RIRBCTL_RINTCTL) && sc->rirb_cnt) { + sc->rirb_cnt = 0; + hda_set_field_by_offset(sc, HDAC_RIRBSTS, HDAC_RIRBSTS_RINTFL, + HDAC_RIRBSTS_RINTFL); + hda_update_intr(sc); + } +} + +static int +hda_codec_constructor(struct hda_softc *sc, struct hda_codec_class *codec, + const char *play, const char *rec, const char *opts) +{ + struct hda_codec_inst *hci = NULL; + + if (sc->codecs_no >= HDA_CODEC_MAX) + return (-1); + + hci = calloc(1, sizeof(struct hda_codec_inst)); + if (!hci) + return (-1); + + hci->hda = sc; + hci->hops = &hops; + hci->cad = sc->codecs_no; + hci->codec = codec; + + sc->codecs[sc->codecs_no++] = hci; + + if (!codec->init) { + DPRINTF("This codec does not implement the init function\n"); + return (-1); + } + + return (codec->init(hci, play, rec, opts)); +} + +static struct hda_codec_class * +hda_find_codec_class(const char *name) +{ + struct hda_codec_class **pdpp = NULL, *pdp = NULL; + + SET_FOREACH(pdpp, hda_codec_class_set) { + pdp = *pdpp; + if (!strcmp(pdp->name, name)) { + return (pdp); + } + } + + return (NULL); +} + +static int +hda_send_command(struct hda_softc *sc, uint32_t verb) +{ + struct hda_codec_inst *hci = NULL; + struct hda_codec_class *codec = NULL; + uint8_t cad = (verb >> HDA_CMD_CAD_SHIFT) & 0x0f; + + hci = sc->codecs[cad]; + if (!hci) + return (-1); + + DPRINTF("cad: 0x%x verb: 0x%x\n", cad, verb); + + codec = hci->codec; + assert(codec); + + if (!codec->command) { + DPRINTF("This codec does not implement the command function\n"); + return (-1); + } + + return (codec->command(hci, verb)); +} + +static int +hda_notify_codecs(struct hda_softc *sc, uint8_t run, uint8_t stream, + uint8_t dir) +{ + struct hda_codec_inst *hci = NULL; + struct hda_codec_class *codec = NULL; + int err; + int i; + + /* Notify each codec */ + for (i = 0; i < sc->codecs_no; i++) { + hci = sc->codecs[i]; + assert(hci); + + codec = hci->codec; + assert(codec); + + if (codec->notify) { + err = codec->notify(hci, run, stream, dir); + if (!err) + break; + } + } + + return (i == sc->codecs_no ? (-1) : 0); +} + +static void +hda_reset(struct hda_softc *sc) +{ + int i; + struct hda_codec_inst *hci = NULL; + struct hda_codec_class *codec = NULL; + + hda_reset_regs(sc); + + /* Reset each codec */ + for (i = 0; i < sc->codecs_no; i++) { + hci = sc->codecs[i]; + assert(hci); + + codec = hci->codec; + assert(codec); + + if (codec->reset) + codec->reset(hci); + } + + sc->wall_clock_start = hda_get_clock_ns(); +} + +static void +hda_reset_regs(struct hda_softc *sc) +{ + uint32_t off = 0; + uint8_t i; + + DPRINTF("Reset the HDA controller registers ...\n"); + + memset(sc->regs, 0, sizeof(sc->regs)); + + hda_set_reg_by_offset(sc, HDAC_GCAP, + HDAC_GCAP_64OK | + (HDA_ISS_NO << HDAC_GCAP_ISS_SHIFT) | + (HDA_OSS_NO << HDAC_GCAP_OSS_SHIFT)); + hda_set_reg_by_offset(sc, HDAC_VMAJ, 0x01); + hda_set_reg_by_offset(sc, HDAC_OUTPAY, 0x3c); + hda_set_reg_by_offset(sc, HDAC_INPAY, 0x1d); + hda_set_reg_by_offset(sc, HDAC_CORBSIZE, + HDAC_CORBSIZE_CORBSZCAP_256 | HDAC_CORBSIZE_CORBSIZE_256); + hda_set_reg_by_offset(sc, HDAC_RIRBSIZE, + HDAC_RIRBSIZE_RIRBSZCAP_256 | HDAC_RIRBSIZE_RIRBSIZE_256); + + for (i = 0; i < HDA_IOSS_NO; i++) { + off = hda_get_offset_stream(i); + hda_set_reg_by_offset(sc, off + HDAC_SDFIFOS, HDA_FIFO_SIZE); + } +} + +static void +hda_stream_reset(struct hda_softc *sc, uint8_t stream_ind) +{ + struct hda_stream_desc *st = &sc->streams[stream_ind]; + uint32_t off = hda_get_offset_stream(stream_ind); + + DPRINTF("Reset the HDA stream: 0x%x\n", stream_ind); + + /* Reset the Stream Descriptor registers */ + memset(sc->regs + HDA_STREAM_REGS_BASE + off, 0, HDA_STREAM_REGS_LEN); + + /* Reset the Stream Descriptor */ + memset(st, 0, sizeof(*st)); + + hda_set_field_by_offset(sc, off + HDAC_SDSTS, + HDAC_SDSTS_FIFORDY, HDAC_SDSTS_FIFORDY); + hda_set_field_by_offset(sc, off + HDAC_SDCTL0, + HDAC_SDCTL_SRST, HDAC_SDCTL_SRST); +} + +static int +hda_stream_start(struct hda_softc *sc, uint8_t stream_ind) +{ + struct hda_stream_desc *st = &sc->streams[stream_ind]; + struct hda_bdle_desc *bdle_desc = NULL; + struct hda_bdle *bdle = NULL; + uint32_t lvi = 0; + uint32_t bdl_cnt = 0; + uint64_t bdpl = 0; + uint64_t bdpu = 0; + uint64_t bdl_paddr = 0; + void *bdl_vaddr = NULL; + uint32_t bdle_sz = 0; + uint64_t bdle_addrl = 0; + uint64_t bdle_addrh = 0; + uint64_t bdle_paddr = 0; + void *bdle_vaddr = NULL; + uint32_t off = hda_get_offset_stream(stream_ind); + uint32_t sdctl = 0; + uint8_t strm = 0; + uint8_t dir = 0; + int i; + + assert(!st->run); + + lvi = hda_get_reg_by_offset(sc, off + HDAC_SDLVI); + bdpl = hda_get_reg_by_offset(sc, off + HDAC_SDBDPL); + bdpu = hda_get_reg_by_offset(sc, off + HDAC_SDBDPU); + + bdl_cnt = lvi + 1; + assert(bdl_cnt <= HDA_BDL_MAX_LEN); + + bdl_paddr = bdpl | (bdpu << 32); + bdl_vaddr = hda_dma_get_vaddr(sc, bdl_paddr, + HDA_BDL_ENTRY_LEN * bdl_cnt); + if (!bdl_vaddr) { + DPRINTF("Fail to get the guest virtual address\n"); + return (-1); + } + + DPRINTF("stream: 0x%x bdl_cnt: 0x%x bdl_paddr: 0x%lx\n", + stream_ind, bdl_cnt, bdl_paddr); + + st->bdl_cnt = bdl_cnt; + + bdle = (struct hda_bdle *)bdl_vaddr; + for (i = 0; i < bdl_cnt; i++, bdle++) { + bdle_sz = bdle->len; + assert(!(bdle_sz % HDA_DMA_ACCESS_LEN)); + + bdle_addrl = bdle->addrl; + bdle_addrh = bdle->addrh; + + bdle_paddr = bdle_addrl | (bdle_addrh << 32); + bdle_vaddr = hda_dma_get_vaddr(sc, bdle_paddr, bdle_sz); + if (!bdle_vaddr) { + DPRINTF("Fail to get the guest virtual address\n"); + return (-1); + } + + bdle_desc = &st->bdl[i]; + bdle_desc->addr = bdle_vaddr; + bdle_desc->len = bdle_sz; + bdle_desc->ioc = bdle->ioc; + + DPRINTF("bdle: 0x%x bdle_sz: 0x%x\n", i, bdle_sz); + } + + sdctl = hda_get_reg_by_offset(sc, off + HDAC_SDCTL0); + strm = (sdctl >> 20) & 0x0f; + dir = stream_ind >= HDA_ISS_NO; + + DPRINTF("strm: 0x%x, dir: 0x%x\n", strm, dir); + + sc->stream_map[dir][strm] = stream_ind; + st->stream = strm; + st->dir = dir; + st->bp = 0; + st->be = 0; + + hda_set_pib(sc, stream_ind, 0); + + st->run = 1; + + hda_notify_codecs(sc, 1, strm, dir); + + return (0); +} + +static int +hda_stream_stop(struct hda_softc *sc, uint8_t stream_ind) +{ + struct hda_stream_desc *st = &sc->streams[stream_ind]; + uint8_t strm = st->stream; + uint8_t dir = st->dir; + + DPRINTF("stream: 0x%x, strm: 0x%x, dir: 0x%x\n", stream_ind, strm, dir); + + st->run = 0; + + hda_notify_codecs(sc, 0, strm, dir); + + return (0); +} + +static uint32_t +hda_read(struct hda_softc *sc, uint32_t offset) +{ + if (offset == HDAC_WALCLK) + return (24 * (hda_get_clock_ns() - \ + sc->wall_clock_start) / 1000); + + return (hda_get_reg_by_offset(sc, offset)); +} + +static int +hda_write(struct hda_softc *sc, uint32_t offset, uint8_t size, uint32_t value) +{ + uint32_t old = hda_get_reg_by_offset(sc, offset); + uint32_t masks[] = {0x00000000, 0x000000ff, 0x0000ffff, + 0x00ffffff, 0xffffffff}; + hda_set_reg_handler set_reg_handler = hda_set_reg_table[offset]; + + hda_set_field_by_offset(sc, offset, masks[size], value); + + if (set_reg_handler) + set_reg_handler(sc, offset, old); + + return (0); +} + +static inline void +hda_print_cmd_ctl_data(struct hda_codec_cmd_ctl *p) +{ +#if DEBUG_HDA == 1 + char *name = p->name; +#endif + DPRINTF("%s size: %d\n", name, p->size); + DPRINTF("%s dma_vaddr: %p\n", name, p->dma_vaddr); + DPRINTF("%s wp: 0x%x\n", name, p->wp); + DPRINTF("%s rp: 0x%x\n", name, p->rp); +} + +static int +hda_corb_start(struct hda_softc *sc) +{ + struct hda_codec_cmd_ctl *corb = &sc->corb; + uint8_t corbsize = 0; + uint64_t corblbase = 0; + uint64_t corbubase = 0; + uint64_t corbpaddr = 0; + + corb->name = "CORB"; + + corbsize = hda_get_reg_by_offset(sc, HDAC_CORBSIZE) & \ + HDAC_CORBSIZE_CORBSIZE_MASK; + corb->size = hda_corb_sizes[corbsize]; + + if (!corb->size) { + DPRINTF("Invalid corb size\n"); + return (-1); + } + + corblbase = hda_get_reg_by_offset(sc, HDAC_CORBLBASE); + corbubase = hda_get_reg_by_offset(sc, HDAC_CORBUBASE); + + corbpaddr = corblbase | (corbubase << 32); + DPRINTF("CORB dma_paddr: %p\n", (void *)corbpaddr); + + corb->dma_vaddr = hda_dma_get_vaddr(sc, corbpaddr, + HDA_CORB_ENTRY_LEN * corb->size); + if (!corb->dma_vaddr) { + DPRINTF("Fail to get the guest virtual address\n"); + return (-1); + } + + corb->wp = hda_get_reg_by_offset(sc, HDAC_CORBWP); + corb->rp = hda_get_reg_by_offset(sc, HDAC_CORBRP); + + corb->run = 1; + + hda_print_cmd_ctl_data(corb); + + return (0); +} + +static int +hda_corb_run(struct hda_softc *sc) +{ + struct hda_codec_cmd_ctl *corb = &sc->corb; + uint32_t verb = 0; + int err; + + corb->wp = hda_get_reg_by_offset(sc, HDAC_CORBWP); + + while (corb->rp != corb->wp && corb->run) { + corb->rp++; + corb->rp %= corb->size; + + verb = hda_dma_ld_dword(corb->dma_vaddr + \ + HDA_CORB_ENTRY_LEN * corb->rp); + + err = hda_send_command(sc, verb); + assert(!err); + } + + hda_set_reg_by_offset(sc, HDAC_CORBRP, corb->rp); + + if (corb->run) + hda_response_interrupt(sc); + + return (0); +} + +static int +hda_rirb_start(struct hda_softc *sc) +{ + struct hda_codec_cmd_ctl *rirb = &sc->rirb; + uint8_t rirbsize = 0; + uint64_t rirblbase = 0; + uint64_t rirbubase = 0; + uint64_t rirbpaddr = 0; + + rirb->name = "RIRB"; + + rirbsize = hda_get_reg_by_offset(sc, HDAC_RIRBSIZE) & \ + HDAC_RIRBSIZE_RIRBSIZE_MASK; + rirb->size = hda_rirb_sizes[rirbsize]; + + if (!rirb->size) { + DPRINTF("Invalid rirb size\n"); + return (-1); + } + + rirblbase = hda_get_reg_by_offset(sc, HDAC_RIRBLBASE); + rirbubase = hda_get_reg_by_offset(sc, HDAC_RIRBUBASE); + + rirbpaddr = rirblbase | (rirbubase << 32); + DPRINTF("RIRB dma_paddr: %p\n", (void *)rirbpaddr); + + rirb->dma_vaddr = hda_dma_get_vaddr(sc, rirbpaddr, + HDA_RIRB_ENTRY_LEN * rirb->size); + if (!rirb->dma_vaddr) { + DPRINTF("Fail to get the guest virtual address\n"); + return (-1); + } + + rirb->wp = hda_get_reg_by_offset(sc, HDAC_RIRBWP); + rirb->rp = 0x0000; + + rirb->run = 1; + + hda_print_cmd_ctl_data(rirb); + + return (0); +} + +static void * +hda_dma_get_vaddr(struct hda_softc *sc, uint64_t dma_paddr, size_t len) +{ + struct pci_devinst *pi = sc->pci_dev; + + assert(pi); + + return (paddr_guest2host(pi->pi_vmctx, (uintptr_t)dma_paddr, len)); +} + +static void +hda_dma_st_dword(void *dma_vaddr, uint32_t data) +{ + *(uint32_t*)dma_vaddr = data; +} + +static uint32_t +hda_dma_ld_dword(void *dma_vaddr) +{ + return (*(uint32_t*)dma_vaddr); +} + +static inline uint8_t +hda_get_stream_by_offsets(uint32_t offset, uint8_t reg_offset) +{ + uint8_t stream_ind = (offset - reg_offset) >> 5; + + assert(stream_ind < HDA_IOSS_NO); + + return (stream_ind); +} + +static inline uint32_t +hda_get_offset_stream(uint8_t stream_ind) +{ + return (stream_ind << 5); +} + +static void +hda_set_gctl(struct hda_softc *sc, uint32_t offset, uint32_t old) +{ + uint32_t value = hda_get_reg_by_offset(sc, offset); + + if (!(value & HDAC_GCTL_CRST)) { + hda_reset(sc); + } +} + +static void +hda_set_statests(struct hda_softc *sc, uint32_t offset, uint32_t old) +{ + uint32_t value = hda_get_reg_by_offset(sc, offset); + + hda_set_reg_by_offset(sc, offset, old); + + /* clear the corresponding bits written by the software (guest) */ + hda_set_field_by_offset(sc, offset, value & HDA_STATESTS_IRQ_MASK, 0); + + hda_update_intr(sc); +} + +static void +hda_set_corbwp(struct hda_softc *sc, uint32_t offset, uint32_t old) +{ + hda_corb_run(sc); +} + +static void +hda_set_corbctl(struct hda_softc *sc, uint32_t offset, uint32_t old) +{ + uint32_t value = hda_get_reg_by_offset(sc, offset); + int err; + struct hda_codec_cmd_ctl *corb = NULL; + + if (value & HDAC_CORBCTL_CORBRUN) { + if (!(old & HDAC_CORBCTL_CORBRUN)) { + err = hda_corb_start(sc); + assert(!err); + } + } else { + corb = &sc->corb; + memset(corb, 0, sizeof(*corb)); + } + + hda_corb_run(sc); +} + +static void +hda_set_rirbctl(struct hda_softc *sc, uint32_t offset, uint32_t old) +{ + uint32_t value = hda_get_reg_by_offset(sc, offset); + int err; + struct hda_codec_cmd_ctl *rirb = NULL; + + if (value & HDAC_RIRBCTL_RIRBDMAEN) { + err = hda_rirb_start(sc); + assert(!err); + } else { + rirb = &sc->rirb; + memset(rirb, 0, sizeof(*rirb)); + } +} + +static void +hda_set_rirbsts(struct hda_softc *sc, uint32_t offset, uint32_t old) +{ + uint32_t value = hda_get_reg_by_offset(sc, offset); + + hda_set_reg_by_offset(sc, offset, old); + + /* clear the corresponding bits written by the software (guest) */ + hda_set_field_by_offset(sc, offset, value & HDA_RIRBSTS_IRQ_MASK, 0); + + hda_update_intr(sc); +} + +static void +hda_set_dpiblbase(struct hda_softc *sc, uint32_t offset, uint32_t old) +{ + uint32_t value = hda_get_reg_by_offset(sc, offset); + uint64_t dpiblbase = 0; + uint64_t dpibubase = 0; + uint64_t dpibpaddr = 0; + + if ((value & HDAC_DPLBASE_DPLBASE_DMAPBE) != (old & \ + HDAC_DPLBASE_DPLBASE_DMAPBE)) { + if (value & HDAC_DPLBASE_DPLBASE_DMAPBE) { + dpiblbase = value & HDAC_DPLBASE_DPLBASE_MASK; + dpibubase = hda_get_reg_by_offset(sc, HDAC_DPIBUBASE); + + dpibpaddr = dpiblbase | (dpibubase << 32); + DPRINTF("DMA Position In Buffer dma_paddr: %p\n", + (void *)dpibpaddr); + + sc->dma_pib_vaddr = hda_dma_get_vaddr(sc, dpibpaddr, + HDA_DMA_PIB_ENTRY_LEN * HDA_IOSS_NO); + if (!sc->dma_pib_vaddr) { + DPRINTF("Fail to get the guest \ + virtual address\n"); + assert(0); + } + } else { + DPRINTF("DMA Position In Buffer Reset\n"); + sc->dma_pib_vaddr = NULL; + } + } +} + +static void +hda_set_sdctl(struct hda_softc *sc, uint32_t offset, uint32_t old) +{ + uint8_t stream_ind = hda_get_stream_by_offsets(offset, HDAC_SDCTL0); + uint32_t value = hda_get_reg_by_offset(sc, offset); + int err; + + DPRINTF("stream_ind: 0x%x old: 0x%x value: 0x%x\n", + stream_ind, old, value); + + if (value & HDAC_SDCTL_SRST) { + hda_stream_reset(sc, stream_ind); + } + + if ((value & HDAC_SDCTL_RUN) != (old & HDAC_SDCTL_RUN)) { + if (value & HDAC_SDCTL_RUN) { + err = hda_stream_start(sc, stream_ind); + assert(!err); + } else { + err = hda_stream_stop(sc, stream_ind); + assert(!err); + } + } +} + +static void +hda_set_sdctl2(struct hda_softc *sc, uint32_t offset, uint32_t old) +{ + uint32_t value = hda_get_reg_by_offset(sc, offset); + + hda_set_field_by_offset(sc, offset - 2, 0x00ff0000, value << 16); +} + +static void +hda_set_sdsts(struct hda_softc *sc, uint32_t offset, uint32_t old) +{ + uint32_t value = hda_get_reg_by_offset(sc, offset); + + hda_set_reg_by_offset(sc, offset, old); + + /* clear the corresponding bits written by the software (guest) */ + hda_set_field_by_offset(sc, offset, value & HDA_SDSTS_IRQ_MASK, 0); + + hda_update_intr(sc); +} + +static int +hda_signal_state_change(struct hda_codec_inst *hci) +{ + struct hda_softc *sc = NULL; + uint32_t sdiwake = 0; + + assert(hci); + assert(hci->hda); + + DPRINTF("cad: 0x%x\n", hci->cad); + + sc = hci->hda; + sdiwake = 1 << hci->cad; + + hda_set_field_by_offset(sc, HDAC_STATESTS, sdiwake, sdiwake); + hda_update_intr(sc); + + return (0); +} + +static int +hda_response(struct hda_codec_inst *hci, uint32_t response, uint8_t unsol) +{ + struct hda_softc *sc = NULL; + struct hda_codec_cmd_ctl *rirb = NULL; + uint32_t response_ex = 0; + uint8_t rintcnt = 0; + + assert(hci); + assert(hci->cad <= HDA_CODEC_MAX); + + response_ex = hci->cad | unsol; + + sc = hci->hda; + assert(sc); + + rirb = &sc->rirb; + + if (rirb->run) { + rirb->wp++; + rirb->wp %= rirb->size; + + hda_dma_st_dword(rirb->dma_vaddr + HDA_RIRB_ENTRY_LEN * \ + rirb->wp, response); + hda_dma_st_dword(rirb->dma_vaddr + HDA_RIRB_ENTRY_LEN * \ + rirb->wp + 0x04, response_ex); + + hda_set_reg_by_offset(sc, HDAC_RIRBWP, rirb->wp); + + sc->rirb_cnt++; + } + + rintcnt = hda_get_reg_by_offset(sc, HDAC_RINTCNT); + if (sc->rirb_cnt == rintcnt) + hda_response_interrupt(sc); + + return (0); +} + +static int +hda_transfer(struct hda_codec_inst *hci, uint8_t stream, uint8_t dir, + void *buf, size_t count) +{ + struct hda_softc *sc = NULL; + struct hda_stream_desc *st = NULL; + struct hda_bdle_desc *bdl = NULL; + struct hda_bdle_desc *bdle_desc = NULL; + uint8_t stream_ind = 0; + uint32_t lpib = 0; + uint32_t off = 0; + size_t left = 0; + uint8_t irq = 0; + + assert(hci); + assert(hci->hda); + assert(buf); + assert(!(count % HDA_DMA_ACCESS_LEN)); + + if (!stream) { + DPRINTF("Invalid stream\n"); + return (-1); + } + + sc = hci->hda; + + assert(stream < HDA_STREAM_TAGS_CNT); + stream_ind = sc->stream_map[dir][stream]; + + if (!dir) + assert(stream_ind < HDA_ISS_NO); + else + assert(stream_ind >= HDA_ISS_NO && stream_ind < HDA_IOSS_NO); + + st = &sc->streams[stream_ind]; + if (!st->run) { + DPRINTF("Stream 0x%x stopped\n", stream); + return (-1); + } + + assert(st->stream == stream); + + off = hda_get_offset_stream(stream_ind); + + lpib = hda_get_reg_by_offset(sc, off + HDAC_SDLPIB); + + bdl = st->bdl; + + assert(st->be < st->bdl_cnt); + assert(st->bp < bdl[st->be].len); + + left = count; + while (left) { + bdle_desc = &bdl[st->be]; + + if (dir) + *(uint32_t *)buf = \ + hda_dma_ld_dword(bdle_desc->addr + st->bp); + else + hda_dma_st_dword(bdle_desc->addr + st->bp, + *(uint32_t *)buf); + + buf += HDA_DMA_ACCESS_LEN; + st->bp += HDA_DMA_ACCESS_LEN; + lpib += HDA_DMA_ACCESS_LEN; + left -= HDA_DMA_ACCESS_LEN; + + if (st->bp == bdle_desc->len) { + st->bp = 0; + if (bdle_desc->ioc) + irq = 1; + st->be++; + if (st->be == st->bdl_cnt) { + st->be = 0; + lpib = 0; + } + bdle_desc = &bdl[st->be]; + } + } + + hda_set_pib(sc, stream_ind, lpib); + + if (irq) { + hda_set_field_by_offset(sc, off + HDAC_SDSTS, + HDAC_SDSTS_BCIS, HDAC_SDSTS_BCIS); + hda_update_intr(sc); + } + + return (0); +} + +static void +hda_set_pib(struct hda_softc *sc, uint8_t stream_ind, uint32_t pib) +{ + uint32_t off = hda_get_offset_stream(stream_ind); + + hda_set_reg_by_offset(sc, off + HDAC_SDLPIB, pib); + /* LPIB Alias */ + hda_set_reg_by_offset(sc, 0x2000 + off + HDAC_SDLPIB, pib); + if (sc->dma_pib_vaddr) + *(uint32_t *)(sc->dma_pib_vaddr + stream_ind * \ + HDA_DMA_PIB_ENTRY_LEN) = pib; +} + +static uint64_t hda_get_clock_ns(void) +{ + struct timespec ts; + int err; + + err = clock_gettime(CLOCK_MONOTONIC, &ts); + assert(!err); + + return (ts.tv_sec * 1000000000LL + ts.tv_nsec); +} + +/* + * PCI HDA function definitions + */ +static int +pci_hda_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) +{ + struct hda_softc *sc = NULL; + + assert(ctx != NULL); + assert(pi != NULL); + + pci_set_cfgdata16(pi, PCIR_VENDOR, INTEL_VENDORID); + pci_set_cfgdata16(pi, PCIR_DEVICE, HDA_INTEL_82801G); + + pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_MULTIMEDIA_HDA); + pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_MULTIMEDIA); + + /* select the Intel HDA mode */ + pci_set_cfgdata8(pi, PCIR_HDCTL, 0x01); + + /* allocate one BAR register for the Memory address offsets */ + pci_emul_alloc_bar(pi, 0, PCIBAR_MEM32, HDA_LAST_OFFSET); + + /* allocate an IRQ pin for our slot */ + pci_lintr_request(pi); + + sc = hda_init(opts); + if (!sc) + return (-1); + + sc->pci_dev = pi; + pi->pi_arg = sc; + + return (0); +} + +static void +pci_hda_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, + int baridx, uint64_t offset, int size, uint64_t value) +{ + struct hda_softc *sc = pi->pi_arg; + int err; + + assert(sc); + assert(baridx == 0); + assert(size <= 4); + + DPRINTF("offset: 0x%lx value: 0x%lx\n", offset, value); + + err = hda_write(sc, offset, size, value); + assert(!err); +} + +static uint64_t +pci_hda_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, + int baridx, uint64_t offset, int size) +{ + struct hda_softc *sc = pi->pi_arg; + uint64_t value = 0; + + assert(sc); + assert(baridx == 0); + assert(size <= 4); + + value = hda_read(sc, offset); + + DPRINTF("offset: 0x%lx value: 0x%lx\n", offset, value); + + return (value); +} diff --git a/usr.sbin/bhyve/pci_hda.h b/usr.sbin/bhyve/pci_hda.h new file mode 100644 index 000000000000..038a1da8dee6 --- /dev/null +++ b/usr.sbin/bhyve/pci_hda.h @@ -0,0 +1,90 @@ +/*- + * Copyright (c) 2016 Alex Teaca + * 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, 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 OR CONTRIBUTORS 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$ + */ + +#ifndef _HDA_EMUL_H_ +#define _HDA_EMUL_H_ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "hda_reg.h" + +/* + * HDA Debug Log + */ +#define DEBUG_HDA 1 +#if DEBUG_HDA == 1 +extern FILE *dbg; +#define DPRINTF(fmt, arg...) \ +do {fprintf(dbg, "%s-%d: " fmt, __func__, __LINE__, ##arg); \ +fflush(dbg); } while (0) +#else +#define DPRINTF(fmt, arg...) +#endif + +#define HDA_FIFO_SIZE 0x100 + +struct hda_softc; +struct hda_codec_class; + +struct hda_codec_inst { + uint8_t cad; + struct hda_codec_class *codec; + struct hda_softc *hda; + struct hda_ops *hops; + void *priv; +}; + +struct hda_codec_class { + char *name; + int (*init)(struct hda_codec_inst *hci, const char *play, + const char *rec, const char *opts); + int (*reset)(struct hda_codec_inst *hci); + int (*command)(struct hda_codec_inst *hci, uint32_t cmd_data); + int (*notify)(struct hda_codec_inst *hci, uint8_t run, uint8_t stream, + uint8_t dir); +}; + +struct hda_ops { + int (*signal)(struct hda_codec_inst *hci); + int (*response)(struct hda_codec_inst *hci, uint32_t response, + uint8_t unsol); + int (*transfer)(struct hda_codec_inst *hci, uint8_t stream, + uint8_t dir, void *buf, size_t count); +}; + +#define HDA_EMUL_SET(x) DATA_SET(hda_codec_class_set, x); + +#endif /* _HDA_EMUL_H_ */ From 36f9f044cdb13444553fbb4783ab671491d62cbb Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Tue, 25 Jun 2019 06:14:11 +0000 Subject: [PATCH 085/165] Replay r349336 by scottl accidentally reverted by r349352 Add a section about the HD Audio module support --- usr.sbin/bhyve/bhyve.8 | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/usr.sbin/bhyve/bhyve.8 b/usr.sbin/bhyve/bhyve.8 index 2f2236e8ce38..3ab9e4e67dde 100644 --- a/usr.sbin/bhyve/bhyve.8 +++ b/usr.sbin/bhyve/bhyve.8 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd December 11, 2018 +.Dd June 24, 2019 .Dt BHYVE 8 .Os .Sh NAME @@ -248,6 +248,8 @@ Raw framebuffer device attached to VNC server. eXtensible Host Controller Interface (xHCI) USB controller. .It Li nvme NVM Express (NVMe) controller. +.It Li hda +High Definition Audio Controller. .El .It Op Ar conf This optional parameter describes the backend for device emulations. @@ -475,6 +477,16 @@ Sector size (defaults to blockif sector size). .It Li ser Serial number with maximum 20 characters. .El +.Pp +HD Audio devices: +.Bl -tag -width 10n +.It Li play +Playback device, typically +.Ar /dev/dsp0 . +.It Li rec +Recording device, typically +.Ar /dev/dsp0 . +.El .El .It Fl S Wire guest memory. From 76769dc1080f1f7279bf57fb9132b030c0927a89 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Tue, 25 Jun 2019 06:14:16 +0000 Subject: [PATCH 086/165] Replay r349339 by imp accidentally reverted by r349352 Go ahead and completely fix the ata_params before calling the veto function. This breaks nothing that uses it in the tree since ata_params is ignored in storvsc_ada_probe_veto which is the only in-tree consumer. --- sys/cam/ata/ata_xpt.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/sys/cam/ata/ata_xpt.c b/sys/cam/ata/ata_xpt.c index 94dc435b099b..acef293f1b46 100644 --- a/sys/cam/ata/ata_xpt.c +++ b/sys/cam/ata/ata_xpt.c @@ -896,22 +896,14 @@ device_fail: if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0) int16_t *ptr; int veto = 0; + /* + * Convert to host byte order, and fix the strings. + */ ident_buf = &softc->ident_data; for (ptr = (int16_t *)ident_buf; ptr < (int16_t *)ident_buf + sizeof(struct ata_params)/2; ptr++) { *ptr = le16toh(*ptr); } - - /* - * Allow others to veto this ATA disk attachment. This - * is mainly used by VMs, whose disk controllers may - * share the disks with the simulated ATA controllers. - */ - EVENTHANDLER_INVOKE(ada_probe_veto, path, ident_buf, &veto); - if (veto) { - goto device_fail; - } - if (strncmp(ident_buf->model, "FX", 2) && strncmp(ident_buf->model, "NEC", 3) && strncmp(ident_buf->model, "Pioneer", 7) && @@ -926,6 +918,17 @@ device_fail: if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0) ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision)); ata_btrim(ident_buf->serial, sizeof(ident_buf->serial)); ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial)); + + /* + * Allow others to veto this ATA disk attachment. This + * is mainly used by VMs, whose disk controllers may + * share the disks with the simulated ATA controllers. + */ + EVENTHANDLER_INVOKE(ada_probe_veto, path, ident_buf, &veto); + if (veto) { + goto device_fail; + } + /* Device may need spin-up before IDENTIFY become valid. */ if ((ident_buf->specconf == 0x37c8 || ident_buf->specconf == 0x738c) && From 296218d4cf417c2e88324c265e604fabe9e96366 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Tue, 25 Jun 2019 06:14:21 +0000 Subject: [PATCH 087/165] Replay r349340 by imp accidentally reverted by r349352 Create ata_param_fixup Create a common fixup routine to do the canonical fixup of the ata_param fixup. Call it from both the ATA and the ATA over SCSI paths. --- sys/cam/ata/ata_all.c | 25 +++++++++++++++++++++++++ sys/cam/ata/ata_all.h | 1 + sys/cam/ata/ata_xpt.c | 20 +------------------- sys/cam/scsi/scsi_da.c | 5 ++--- 4 files changed, 29 insertions(+), 22 deletions(-) diff --git a/sys/cam/ata/ata_all.c b/sys/cam/ata/ata_all.c index 76d65ae5e405..9a4cdbed071b 100644 --- a/sys/cam/ata/ata_all.c +++ b/sys/cam/ata/ata_all.c @@ -1238,3 +1238,28 @@ ata_zac_mgmt_in(struct ccb_ataio *ataio, uint32_t retries, ataio->aux = auxiliary; } } + +void +ata_param_fixup(struct ata_params *ident_buf) +{ + int16_t *ptr; + + for (ptr = (int16_t *)ident_buf; + ptr < (int16_t *)ident_buf + sizeof(struct ata_params)/2; ptr++) { + *ptr = le16toh(*ptr); + } + if (strncmp(ident_buf->model, "FX", 2) && + strncmp(ident_buf->model, "NEC", 3) && + strncmp(ident_buf->model, "Pioneer", 7) && + strncmp(ident_buf->model, "SHARP", 5)) { + ata_bswap(ident_buf->model, sizeof(ident_buf->model)); + ata_bswap(ident_buf->revision, sizeof(ident_buf->revision)); + ata_bswap(ident_buf->serial, sizeof(ident_buf->serial)); + } + ata_btrim(ident_buf->model, sizeof(ident_buf->model)); + ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model)); + ata_btrim(ident_buf->revision, sizeof(ident_buf->revision)); + ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision)); + ata_btrim(ident_buf->serial, sizeof(ident_buf->serial)); + ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial)); +} diff --git a/sys/cam/ata/ata_all.h b/sys/cam/ata/ata_all.h index 087d6820f980..ca635253511c 100644 --- a/sys/cam/ata/ata_all.h +++ b/sys/cam/ata/ata_all.h @@ -135,6 +135,7 @@ void ata_read_log(struct ccb_ataio *ataio, uint32_t retries, uint16_t block_count, uint32_t protocol, uint8_t *data_ptr, uint32_t dxfer_len, uint32_t timeout); +void ata_param_fixup(struct ata_params *ident_buf); void ata_bswap(int8_t *buf, int len); void ata_btrim(int8_t *buf, int len); void ata_bpack(int8_t *src, int8_t *dst, int len); diff --git a/sys/cam/ata/ata_xpt.c b/sys/cam/ata/ata_xpt.c index acef293f1b46..017db8854b08 100644 --- a/sys/cam/ata/ata_xpt.c +++ b/sys/cam/ata/ata_xpt.c @@ -893,31 +893,13 @@ device_fail: if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0) case PROBE_IDENTIFY: { struct ccb_pathinq cpi; - int16_t *ptr; int veto = 0; /* * Convert to host byte order, and fix the strings. */ ident_buf = &softc->ident_data; - for (ptr = (int16_t *)ident_buf; - ptr < (int16_t *)ident_buf + sizeof(struct ata_params)/2; ptr++) { - *ptr = le16toh(*ptr); - } - if (strncmp(ident_buf->model, "FX", 2) && - strncmp(ident_buf->model, "NEC", 3) && - strncmp(ident_buf->model, "Pioneer", 7) && - strncmp(ident_buf->model, "SHARP", 5)) { - ata_bswap(ident_buf->model, sizeof(ident_buf->model)); - ata_bswap(ident_buf->revision, sizeof(ident_buf->revision)); - ata_bswap(ident_buf->serial, sizeof(ident_buf->serial)); - } - ata_btrim(ident_buf->model, sizeof(ident_buf->model)); - ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model)); - ata_btrim(ident_buf->revision, sizeof(ident_buf->revision)); - ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision)); - ata_btrim(ident_buf->serial, sizeof(ident_buf->serial)); - ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial)); + ata_param_fixup(ident_buf); /* * Allow others to veto this ATA disk attachment. This diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c index a89c40e19a7b..d2e66307cce6 100644 --- a/sys/cam/scsi/scsi_da.c +++ b/sys/cam/scsi/scsi_da.c @@ -5192,7 +5192,7 @@ dadone_probeata(struct cam_periph *periph, union ccb *done_ccb) struct da_softc *softc; u_int32_t priority; int continue_probe; - int error, i; + int error; int16_t *ptr; CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("dadone_probeata\n")); @@ -5210,8 +5210,7 @@ dadone_probeata(struct cam_periph *periph, union ccb *done_ccb) if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { uint16_t old_rate; - for (i = 0; i < sizeof(*ata_params) / 2; i++) - ptr[i] = le16toh(ptr[i]); + ata_param_fixup(ata_params); if (ata_params->support_dsm & ATA_SUPPORT_DSM_TRIM && (softc->quirks & DA_Q_NO_UNMAP) == 0) { dadeleteflag(softc, DA_DELETE_ATA_TRIM, 1); From 91211c46acc3bbcd1e15ceb0b60c312397cde4ad Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Tue, 25 Jun 2019 06:14:26 +0000 Subject: [PATCH 088/165] Replay r349341 by imp accidentally reverted by r349352 Use ata_param_fixup instead of a custom copy here --- sbin/camcontrol/camcontrol.c | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/sbin/camcontrol/camcontrol.c b/sbin/camcontrol/camcontrol.c index 0784fab75a0e..99d59e59d86c 100644 --- a/sbin/camcontrol/camcontrol.c +++ b/sbin/camcontrol/camcontrol.c @@ -2326,9 +2326,11 @@ ata_do_identify(struct cam_device *device, int retry_count, int timeout, } } + ident_buf = (struct ata_params *)ptr; + ata_param_fixup(ident_buf); + error = 1; for (i = 0; i < sizeof(struct ata_params) / 2; i++) { - ptr[i] = le16toh(ptr[i]); if (ptr[i] != 0) error = 0; } @@ -2346,26 +2348,6 @@ ata_do_identify(struct cam_device *device, int retry_count, int timeout, return (error); } - ident_buf = (struct ata_params *)ptr; - if (strncmp(ident_buf->model, "FX", 2) && - strncmp(ident_buf->model, "NEC", 3) && - strncmp(ident_buf->model, "Pioneer", 7) && - strncmp(ident_buf->model, "SHARP", 5)) { - ata_bswap(ident_buf->model, sizeof(ident_buf->model)); - ata_bswap(ident_buf->revision, sizeof(ident_buf->revision)); - ata_bswap(ident_buf->serial, sizeof(ident_buf->serial)); - ata_bswap(ident_buf->media_serial, sizeof(ident_buf->media_serial)); - } - ata_btrim(ident_buf->model, sizeof(ident_buf->model)); - ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model)); - ata_btrim(ident_buf->revision, sizeof(ident_buf->revision)); - ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision)); - ata_btrim(ident_buf->serial, sizeof(ident_buf->serial)); - ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial)); - ata_btrim(ident_buf->media_serial, sizeof(ident_buf->media_serial)); - ata_bpack(ident_buf->media_serial, ident_buf->media_serial, - sizeof(ident_buf->media_serial)); - *ident_bufp = ident_buf; return (0); From a9154c1c835b4e71369d97fc4228d1e687ba0e61 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Tue, 25 Jun 2019 06:14:31 +0000 Subject: [PATCH 089/165] Replay r349342 by imp accidentally reverted by r349352 Use the cam_ed copy of ata_params rather than malloc and freeing memory for it. This reaches into internal bits of xpt a little, and I'll clean that up later. --- sys/cam/scsi/scsi_da.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c index d2e66307cce6..f2f60d35b2e2 100644 --- a/sys/cam/scsi/scsi_da.c +++ b/sys/cam/scsi/scsi_da.c @@ -64,6 +64,9 @@ __FBSDID("$FreeBSD$"); #include #include #include +#ifdef _KERNEL +#include +#endif /* _KERNEL */ #include #include @@ -3613,15 +3616,7 @@ dastart(struct cam_periph *periph, union ccb *start_ccb) break; } - ata_params = (struct ata_params*) - malloc(sizeof(*ata_params), M_SCSIDA,M_NOWAIT|M_ZERO); - - if (ata_params == NULL) { - xpt_print(periph->path, "Couldn't malloc ata_params " - "data\n"); - /* da_free_periph??? */ - break; - } + ata_params = &periph->path->device->ident_data; scsi_ata_identify(&start_ccb->csio, /*retries*/da_retry_count, @@ -5294,7 +5289,6 @@ dadone_probeata(struct cam_periph *periph, union ccb *done_ccb) } } - free(ata_params, M_SCSIDA); if ((softc->zone_mode == DA_ZONE_HOST_AWARE) || (softc->zone_mode == DA_ZONE_HOST_MANAGED)) { /* From 3e21da8ad116826194b19606561ea73f6ab1f1d3 Mon Sep 17 00:00:00 2001 From: Marcelo Araujo Date: Tue, 25 Jun 2019 06:24:56 +0000 Subject: [PATCH 090/165] Add SPDX tags to bhyve(8) HD Audio device. Reviewed by: bcran Differential Revision: https://reviews.freebsd.org/D20750 --- usr.sbin/bhyve/audio.c | 2 ++ usr.sbin/bhyve/audio.h | 2 ++ usr.sbin/bhyve/hda_codec.c | 2 ++ usr.sbin/bhyve/hda_reg.h | 2 ++ usr.sbin/bhyve/hdac_reg.h | 2 ++ usr.sbin/bhyve/pci_hda.c | 2 ++ usr.sbin/bhyve/pci_hda.h | 2 ++ 7 files changed, 14 insertions(+) diff --git a/usr.sbin/bhyve/audio.c b/usr.sbin/bhyve/audio.c index 6a288cbded63..dda575813332 100644 --- a/usr.sbin/bhyve/audio.c +++ b/usr.sbin/bhyve/audio.c @@ -1,4 +1,6 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2016 Alex Teaca * All rights reserved. * diff --git a/usr.sbin/bhyve/audio.h b/usr.sbin/bhyve/audio.h index 01ef17071b14..2b559a43e5df 100644 --- a/usr.sbin/bhyve/audio.h +++ b/usr.sbin/bhyve/audio.h @@ -1,4 +1,6 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2016 Alex Teaca * All rights reserved. * diff --git a/usr.sbin/bhyve/hda_codec.c b/usr.sbin/bhyve/hda_codec.c index ab53eb036e9f..82f5fb1eed92 100644 --- a/usr.sbin/bhyve/hda_codec.c +++ b/usr.sbin/bhyve/hda_codec.c @@ -1,4 +1,6 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2016 Alex Teaca * All rights reserved. * diff --git a/usr.sbin/bhyve/hda_reg.h b/usr.sbin/bhyve/hda_reg.h index dd7098524537..b3034bf9f417 100644 --- a/usr.sbin/bhyve/hda_reg.h +++ b/usr.sbin/bhyve/hda_reg.h @@ -1,4 +1,6 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2006 Stephane E. Potvin * All rights reserved. * diff --git a/usr.sbin/bhyve/hdac_reg.h b/usr.sbin/bhyve/hdac_reg.h index 2bef0d0edc35..35272e5135cb 100644 --- a/usr.sbin/bhyve/hdac_reg.h +++ b/usr.sbin/bhyve/hdac_reg.h @@ -1,4 +1,6 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2006 Stephane E. Potvin * All rights reserved. * diff --git a/usr.sbin/bhyve/pci_hda.c b/usr.sbin/bhyve/pci_hda.c index 99f8aec31c6e..acd6977cea02 100644 --- a/usr.sbin/bhyve/pci_hda.c +++ b/usr.sbin/bhyve/pci_hda.c @@ -1,4 +1,6 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2016 Alex Teaca * All rights reserved. * diff --git a/usr.sbin/bhyve/pci_hda.h b/usr.sbin/bhyve/pci_hda.h index 038a1da8dee6..8ed050cc8f40 100644 --- a/usr.sbin/bhyve/pci_hda.h +++ b/usr.sbin/bhyve/pci_hda.h @@ -1,4 +1,6 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2016 Alex Teaca * All rights reserved. * From c964c987938037c4b6cd4b52704f2a7449951d20 Mon Sep 17 00:00:00 2001 From: Cy Schubert Date: Tue, 25 Jun 2019 07:04:47 +0000 Subject: [PATCH 091/165] The definition of icmptypes in ip_compt.h is dead code as it already use the icmptypes in ip_icmp.h. MFC after: 1 week --- sys/contrib/ipfilter/netinet/ip_compat.h | 156 +---------------------- 1 file changed, 3 insertions(+), 153 deletions(-) diff --git a/sys/contrib/ipfilter/netinet/ip_compat.h b/sys/contrib/ipfilter/netinet/ip_compat.h index 363992ddb284..75f4d7c116ce 100644 --- a/sys/contrib/ipfilter/netinet/ip_compat.h +++ b/sys/contrib/ipfilter/netinet/ip_compat.h @@ -829,159 +829,9 @@ typedef struct tcpiphdr tcpiphdr_t; #undef IPOPT_AH #define IPOPT_AH 256+IPPROTO_AH -#ifndef ICMP_MINLEN -# define ICMP_MINLEN 8 -#endif -#ifndef ICMP_ECHOREPLY -# define ICMP_ECHOREPLY 0 -#endif -#ifndef ICMP_UNREACH -# define ICMP_UNREACH 3 -#endif -#ifndef ICMP_UNREACH_NET -# define ICMP_UNREACH_NET 0 -#endif -#ifndef ICMP_UNREACH_HOST -# define ICMP_UNREACH_HOST 1 -#endif -#ifndef ICMP_UNREACH_PROTOCOL -# define ICMP_UNREACH_PROTOCOL 2 -#endif -#ifndef ICMP_UNREACH_PORT -# define ICMP_UNREACH_PORT 3 -#endif -#ifndef ICMP_UNREACH_NEEDFRAG -# define ICMP_UNREACH_NEEDFRAG 4 -#endif -#ifndef ICMP_UNREACH_SRCFAIL -# define ICMP_UNREACH_SRCFAIL 5 -#endif -#ifndef ICMP_UNREACH_NET_UNKNOWN -# define ICMP_UNREACH_NET_UNKNOWN 6 -#endif -#ifndef ICMP_UNREACH_HOST_UNKNOWN -# define ICMP_UNREACH_HOST_UNKNOWN 7 -#endif -#ifndef ICMP_UNREACH_ISOLATED -# define ICMP_UNREACH_ISOLATED 8 -#endif -#ifndef ICMP_UNREACH_NET_PROHIB -# define ICMP_UNREACH_NET_PROHIB 9 -#endif -#ifndef ICMP_UNREACH_HOST_PROHIB -# define ICMP_UNREACH_HOST_PROHIB 10 -#endif -#ifndef ICMP_UNREACH_TOSNET -# define ICMP_UNREACH_TOSNET 11 -#endif -#ifndef ICMP_UNREACH_TOSHOST -# define ICMP_UNREACH_TOSHOST 12 -#endif -#ifndef ICMP_UNREACH_ADMIN_PROHIBIT -# define ICMP_UNREACH_ADMIN_PROHIBIT 13 -#endif -#ifndef ICMP_UNREACH_FILTER -# define ICMP_UNREACH_FILTER 13 -#endif -#ifndef ICMP_UNREACH_HOST_PRECEDENCE -# define ICMP_UNREACH_HOST_PRECEDENCE 14 -#endif -#ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF -# define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 -#endif -#ifndef ICMP_SOURCEQUENCH -# define ICMP_SOURCEQUENCH 4 -#endif -#ifndef ICMP_REDIRECT_NET -# define ICMP_REDIRECT_NET 0 -#endif -#ifndef ICMP_REDIRECT_HOST -# define ICMP_REDIRECT_HOST 1 -#endif -#ifndef ICMP_REDIRECT_TOSNET -# define ICMP_REDIRECT_TOSNET 2 -#endif -#ifndef ICMP_REDIRECT_TOSHOST -# define ICMP_REDIRECT_TOSHOST 3 -#endif -#ifndef ICMP_ALTHOSTADDR -# define ICMP_ALTHOSTADDR 6 -#endif -#ifndef ICMP_TIMXCEED -# define ICMP_TIMXCEED 11 -#endif -#ifndef ICMP_TIMXCEED_INTRANS -# define ICMP_TIMXCEED_INTRANS 0 -#endif -#ifndef ICMP_TIMXCEED_REASS -# define ICMP_TIMXCEED_REASS 1 -#endif -#ifndef ICMP_PARAMPROB -# define ICMP_PARAMPROB 12 -#endif -#ifndef ICMP_PARAMPROB_ERRATPTR -# define ICMP_PARAMPROB_ERRATPTR 0 -#endif -#ifndef ICMP_PARAMPROB_OPTABSENT -# define ICMP_PARAMPROB_OPTABSENT 1 -#endif -#ifndef ICMP_PARAMPROB_LENGTH -# define ICMP_PARAMPROB_LENGTH 2 -#endif -#ifndef ICMP_TSTAMP -# define ICMP_TSTAMP 13 -#endif -#ifndef ICMP_TSTAMPREPLY -# define ICMP_TSTAMPREPLY 14 -#endif -#ifndef ICMP_IREQ -# define ICMP_IREQ 15 -#endif -#ifndef ICMP_IREQREPLY -# define ICMP_IREQREPLY 16 -#endif -#ifndef ICMP_MASKREQ -# define ICMP_MASKREQ 17 -#endif -#ifndef ICMP_MASKREPLY -# define ICMP_MASKREPLY 18 -#endif -#ifndef ICMP_TRACEROUTE -# define ICMP_TRACEROUTE 30 -#endif -#ifndef ICMP_DATACONVERR -# define ICMP_DATACONVERR 31 -#endif -#ifndef ICMP_MOBILE_REDIRECT -# define ICMP_MOBILE_REDIRECT 32 -#endif -#ifndef ICMP_IPV6_WHEREAREYOU -# define ICMP_IPV6_WHEREAREYOU 33 -#endif -#ifndef ICMP_IPV6_IAMHERE -# define ICMP_IPV6_IAMHERE 34 -#endif -#ifndef ICMP_MOBILE_REGREQUEST -# define ICMP_MOBILE_REGREQUEST 35 -#endif -#ifndef ICMP_MOBILE_REGREPLY -# define ICMP_MOBILE_REGREPLY 36 -#endif -#ifndef ICMP_SKIP -# define ICMP_SKIP 39 -#endif -#ifndef ICMP_PHOTURIS -# define ICMP_PHOTURIS 40 -#endif -#ifndef ICMP_PHOTURIS_UNKNOWN_INDEX -# define ICMP_PHOTURIS_UNKNOWN_INDEX 1 -#endif -#ifndef ICMP_PHOTURIS_AUTH_FAILED -# define ICMP_PHOTURIS_AUTH_FAILED 2 -#endif -#ifndef ICMP_PHOTURIS_DECRYPT_FAILED -# define ICMP_PHOTURIS_DECRYPT_FAILED 3 -#endif +# define ICMP_UNREACH_ADMIN_PROHIBIT ICMP_UNREACH_FILTER_PROHIB +# define ICMP_UNREACH_FILTER ICMP_UNREACH_FILTER_PROHIB + #ifndef IPVERSION # define IPVERSION 4 #endif From 18cd8bb80011a5f1053007d1a641d510d0f3a5bd Mon Sep 17 00:00:00 2001 From: Doug Moore Date: Tue, 25 Jun 2019 07:44:37 +0000 Subject: [PATCH 092/165] vm_map_protect may return an INVALID_ARGUMENT or PROTECTION_FAILURE error response after clipping the first map entry in the region to be reserved. This creates a pair of matching entries that should have been "simplified" back into one, or never created. This change defers the clipping of that entry until those two vm_map_protect failure cases have been ruled out. Reviewed by: alc Approved by: markj (mentor) Differential Revision: https://reviews.freebsd.org/D20711 --- sys/vm/vm_map.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c index 912031702070..38afe6308cc8 100644 --- a/sys/vm/vm_map.c +++ b/sys/vm/vm_map.c @@ -2472,11 +2472,8 @@ vm_map_protect(vm_map_t map, vm_offset_t start, vm_offset_t end, VM_MAP_RANGE_CHECK(map, start, end); - if (vm_map_lookup_entry(map, start, &entry)) { - vm_map_clip_start(map, entry, start); - } else { + if (!vm_map_lookup_entry(map, start, &entry)) entry = entry->next; - } /* * Make a first pass to check for protection violations. @@ -2515,6 +2512,7 @@ vm_map_protect(vm_map_t map, vm_offset_t start, vm_offset_t end, * now will do cow due to allowed write (e.g. debugger sets * breakpoint on text segment) */ + vm_map_clip_start(map, entry, start); for (current = entry; current->start < end; current = current->next) { vm_map_clip_end(map, current, end); From 55507128b93b01c76f7446bdd5e7f38bed4d4652 Mon Sep 17 00:00:00 2001 From: "Andrey V. Elsukov" Date: Tue, 25 Jun 2019 09:08:24 +0000 Subject: [PATCH 093/165] Restore ipfw(8)'s compact output support broken after r331668. Also modify it a bit. Now -c option omits only 'from any to any' part and works for different protocols (not just for ip). Reported by: Dmitry Selivanov MFC after: 1 week --- sbin/ipfw/ipfw2.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c index 4fd977edb91f..c2d89fcbf72f 100644 --- a/sbin/ipfw/ipfw2.c +++ b/sbin/ipfw/ipfw2.c @@ -2223,6 +2223,8 @@ show_static_rule(struct cmdline_opts *co, struct format_opts *fo, } print_proto(bp, fo, &state); + if (co->do_compact != 0 && (rule->flags & IPFW_RULE_NOOPT)) + goto justopts; /* Print source */ bprintf(bp, " from"); @@ -4395,6 +4397,8 @@ compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate) } OR_BLOCK(get_proto); + first_cmd = cmd; /* update pointer to use in compact form */ + /* * "from", mandatory */ @@ -4466,6 +4470,8 @@ compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate) cmd = next_cmd(cmd, &cblen); } } + if (first_cmd == cmd) + rule->flags |= IPFW_RULE_NOOPT; read_options: prev = NULL; From 7d4b2d52448bbf32924838d1f00e9bd0e350855d Mon Sep 17 00:00:00 2001 From: "Andrey V. Elsukov" Date: Tue, 25 Jun 2019 09:11:22 +0000 Subject: [PATCH 094/165] Mark default rule with IPFW_RULE_NOOPT flag, so it can be showed in compact form. MFC after: 1 week --- sys/netpfil/ipfw/ip_fw2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c index 6796ad81611d..f8bd4dea1d61 100644 --- a/sys/netpfil/ipfw/ip_fw2.c +++ b/sys/netpfil/ipfw/ip_fw2.c @@ -3364,6 +3364,7 @@ vnet_ipfw_init(const void *unused) /* fill and insert the default rule */ rule = ipfw_alloc_rule(chain, sizeof(struct ip_fw)); + rule->flags |= IPFW_RULE_NOOPT; rule->cmd_len = 1; rule->cmd[0].len = 1; rule->cmd[0].opcode = default_to_accept ? O_ACCEPT : O_DENY; From 019c8c9330b6659624793c5ba066daffabdb02d4 Mon Sep 17 00:00:00 2001 From: "Andrey V. Elsukov" Date: Tue, 25 Jun 2019 11:40:37 +0000 Subject: [PATCH 095/165] Follow the RFC 3128 and drop short TCP fragments with offset = 1. Reported by: emaste MFC after: 1 week --- sys/netpfil/ipfw/ip_fw2.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c index f8bd4dea1d61..535be037b6cc 100644 --- a/sys/netpfil/ipfw/ip_fw2.c +++ b/sys/netpfil/ipfw/ip_fw2.c @@ -1719,6 +1719,11 @@ do { \ default: break; } + } else { + if (offset == 1 && proto == IPPROTO_TCP) { + /* RFC 3128 */ + goto pullup_failed; + } } UPDATE_POINTERS(); From c7ffaed92e1f8dac4307f7935c8120c98811ae45 Mon Sep 17 00:00:00 2001 From: Hans Petter Selasky Date: Tue, 25 Jun 2019 11:42:53 +0000 Subject: [PATCH 096/165] Fix for deadlock situation in cuse(3) The final server unref should be done by the server thread to prevent deadlock in the client cdevpriv destructor, which cannot destroy itself. MFC after: 1 week Sponsored by: Mellanox Technologies --- sys/fs/cuse/cuse.c | 43 +++++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/sys/fs/cuse/cuse.c b/sys/fs/cuse/cuse.c index 578bf3eda74f..2fc38dda3da6 100644 --- a/sys/fs/cuse/cuse.c +++ b/sys/fs/cuse/cuse.c @@ -699,12 +699,38 @@ cuse_server_unref(struct cuse_server *pcs) free(pcs, M_CUSE); } +static int +cuse_server_do_close(struct cuse_server *pcs) +{ + int retval; + + cuse_lock(); + cuse_server_is_closing(pcs); + /* final client wakeup, if any */ + cuse_server_wakeup_all_client_locked(pcs); + + knlist_clear(&pcs->selinfo.si_note, 1); + + retval = pcs->refs; + cuse_unlock(); + + return (retval); +} + static void cuse_server_free(void *arg) { struct cuse_server *pcs = arg; - /* drop refcount */ + /* + * The final server unref should be done by the server thread + * to prevent deadlock in the client cdevpriv destructor, + * which cannot destroy itself. + */ + while (cuse_server_do_close(pcs) != 1) + pause("W", hz); + + /* drop final refcount */ cuse_server_unref(pcs); } @@ -746,21 +772,10 @@ static int cuse_server_close(struct cdev *dev, int fflag, int devtype, struct thread *td) { struct cuse_server *pcs; - int error; - error = cuse_server_get(&pcs); - if (error != 0) - goto done; + if (cuse_server_get(&pcs) == 0) + cuse_server_do_close(pcs); - cuse_lock(); - cuse_server_is_closing(pcs); - /* final client wakeup, if any */ - cuse_server_wakeup_all_client_locked(pcs); - - knlist_clear(&pcs->selinfo.si_note, 1); - cuse_unlock(); - -done: return (0); } From 43a9329e1b94de73833eb3f216d516d7724a2c71 Mon Sep 17 00:00:00 2001 From: Hans Petter Selasky Date: Tue, 25 Jun 2019 11:46:01 +0000 Subject: [PATCH 097/165] Free all allocated unit IDs in cuse(3) after the client character devices have been destroyed to avoid creating character devices with identical name. MFC after: 1 week Sponsored by: Mellanox Technologies --- sys/fs/cuse/cuse.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/fs/cuse/cuse.c b/sys/fs/cuse/cuse.c index 2fc38dda3da6..765fe308af7b 100644 --- a/sys/fs/cuse/cuse.c +++ b/sys/fs/cuse/cuse.c @@ -671,8 +671,6 @@ cuse_server_unref(struct cuse_server *pcs) TAILQ_REMOVE(&cuse_server_head, pcs, entry); - cuse_free_unit_by_id_locked(pcs, -1); - while ((pcsd = TAILQ_FIRST(&pcs->hdev)) != NULL) { TAILQ_REMOVE(&pcs->hdev, pcsd, entry); cuse_unlock(); @@ -680,6 +678,8 @@ cuse_server_unref(struct cuse_server *pcs) cuse_lock(); } + cuse_free_unit_by_id_locked(pcs, -1); + while ((mem = TAILQ_FIRST(&pcs->hmem)) != NULL) { TAILQ_REMOVE(&pcs->hmem, mem, entry); cuse_unlock(); From 59854ecf556f455aeaecfd540474afc8c277defe Mon Sep 17 00:00:00 2001 From: Hans Petter Selasky Date: Tue, 25 Jun 2019 11:54:41 +0000 Subject: [PATCH 098/165] Convert all IPv4 and IPv6 multicast memberships into using a STAILQ instead of a linear array. The multicast memberships for the inpcb structure are protected by a non-sleepable lock, INP_WLOCK(), which needs to be dropped when calling the underlying possibly sleeping if_ioctl() method. When using a linear array to keep track of multicast memberships, the computed memory location of the multicast filter may suddenly change, due to concurrent insertion or removal of elements in the linear array. This in turn leads to various invalid memory access issues and kernel panics. To avoid this problem, put all multicast memberships on a STAILQ based list. Then the memory location of the IPv4 and IPv6 multicast filters become fixed during their lifetime and use after free and memory leak issues are easier to track, for example by: vmstat -m | grep multi All list manipulation has been factored into inline functions including some macros, to easily allow for a future hash-list implementation, if needed. This patch has been tested by pho@ . Differential Revision: https://reviews.freebsd.org/D20080 Reviewed by: markj @ MFC after: 1 week Sponsored by: Mellanox Technologies --- sys/net/if_vxlan.c | 2 +- sys/netinet/in.h | 6 +- sys/netinet/in_mcast.c | 439 +++++++++++++---------------------- sys/netinet/in_pcb.c | 32 +-- sys/netinet/in_var.h | 52 +++++ sys/netinet/ip_carp.c | 98 ++++---- sys/netinet/ip_mroute.c | 5 +- sys/netinet/ip_var.h | 10 +- sys/netinet6/in6.h | 5 +- sys/netinet6/in6_ifattach.c | 2 + sys/netinet6/in6_mcast.c | 449 ++++++++++++++---------------------- sys/netinet6/in6_pcb.c | 25 +- sys/netinet6/in6_var.h | 52 +++++ sys/netinet6/ip6_var.h | 11 +- sys/netpfil/pf/if_pfsync.c | 45 ++-- 15 files changed, 565 insertions(+), 668 deletions(-) diff --git a/sys/net/if_vxlan.c b/sys/net/if_vxlan.c index 81065bcec431..5e35baae2dbc 100644 --- a/sys/net/if_vxlan.c +++ b/sys/net/if_vxlan.c @@ -1134,7 +1134,7 @@ vxlan_socket_mc_join_group(struct vxlan_socket *vso, * If we really need to, we can of course look in the INP's * membership list: * sotoinpcb(vso->vxlso_sock)->inp_moptions-> - * imo_membership[]->inm_ifp + * imo_head[]->imf_inm->inm_ifp * similarly to imo_match_group(). */ source->in4.sin_addr = local->in4.sin_addr; diff --git a/sys/netinet/in.h b/sys/netinet/in.h index 148d51eff36a..cfa168f99be6 100644 --- a/sys/netinet/in.h +++ b/sys/netinet/in.h @@ -505,13 +505,9 @@ __END_DECLS #define IP_DEFAULT_MULTICAST_LOOP 1 /* normally hear sends if a member */ /* - * The imo_membership vector for each socket is now dynamically allocated at - * run-time, bounded by USHRT_MAX, and is reallocated when needed, sized - * according to a power-of-two increment. + * Limit for IPv4 multicast memberships */ -#define IP_MIN_MEMBERSHIPS 31 #define IP_MAX_MEMBERSHIPS 4095 -#define IP_MAX_SOURCE_FILTER 1024 /* XXX to be unused */ /* * Default resource limits for IPv4 multicast source filtering. diff --git a/sys/netinet/in_mcast.c b/sys/netinet/in_mcast.c index 2980c1a463ca..ac5c6a03ab54 100644 --- a/sys/netinet/in_mcast.c +++ b/sys/netinet/in_mcast.c @@ -94,7 +94,9 @@ static MALLOC_DEFINE(M_IPMSOURCE, "ip_msource", /* * Locking: - * - Lock order is: Giant, INP_WLOCK, IN_MULTI_LIST_LOCK, IGMP_LOCK, IF_ADDR_LOCK. + * + * - Lock order is: Giant, IN_MULTI_LOCK, INP_WLOCK, + * IN_MULTI_LIST_LOCK, IGMP_LOCK, IF_ADDR_LOCK. * - The IF_ADDR_LOCK is implicitly taken by inm_lookup() earlier, however * it can be taken by code in net/if.c also. * - ip_moptions and in_mfilter are covered by the INP_WLOCK. @@ -144,12 +146,11 @@ static int imf_prune(struct in_mfilter *, const struct sockaddr_in *); static void imf_purge(struct in_mfilter *); static void imf_rollback(struct in_mfilter *); static void imf_reap(struct in_mfilter *); -static int imo_grow(struct ip_moptions *); -static size_t imo_match_group(const struct ip_moptions *, +static struct in_mfilter * + imo_match_group(const struct ip_moptions *, const struct ifnet *, const struct sockaddr *); static struct in_msource * - imo_match_source(const struct ip_moptions *, const size_t, - const struct sockaddr *); + imo_match_source(struct in_mfilter *, const struct sockaddr *); static void ims_merge(struct ip_msource *ims, const struct in_msource *lims, const int rollback); static int in_getmulti(struct ifnet *, const struct in_addr *, @@ -333,6 +334,26 @@ imf_init(struct in_mfilter *imf, const int st0, const int st1) imf->imf_st[1] = st1; } +struct in_mfilter * +ip_mfilter_alloc(const int mflags, const int st0, const int st1) +{ + struct in_mfilter *imf; + + imf = malloc(sizeof(*imf), M_INMFILTER, mflags); + if (imf != NULL) + imf_init(imf, st0, st1); + + return (imf); +} + +void +ip_mfilter_free(struct in_mfilter *imf) +{ + + imf_purge(imf); + free(imf, M_INMFILTER); +} + /* * Function for looking up an in_multi record for an IPv4 multicast address * on a given interface. ifp must be valid. If no record found, return NULL. @@ -378,90 +399,31 @@ inm_lookup(struct ifnet *ifp, const struct in_addr ina) return (inm); } -/* - * Resize the ip_moptions vector to the next power-of-two minus 1. - * May be called with locks held; do not sleep. - */ -static int -imo_grow(struct ip_moptions *imo) -{ - struct in_multi **nmships; - struct in_multi **omships; - struct in_mfilter *nmfilters; - struct in_mfilter *omfilters; - size_t idx; - size_t newmax; - size_t oldmax; - - nmships = NULL; - nmfilters = NULL; - omships = imo->imo_membership; - omfilters = imo->imo_mfilters; - oldmax = imo->imo_max_memberships; - newmax = ((oldmax + 1) * 2) - 1; - - if (newmax <= IP_MAX_MEMBERSHIPS) { - nmships = (struct in_multi **)realloc(omships, - sizeof(struct in_multi *) * newmax, M_IPMOPTS, M_NOWAIT); - nmfilters = (struct in_mfilter *)realloc(omfilters, - sizeof(struct in_mfilter) * newmax, M_INMFILTER, M_NOWAIT); - if (nmships != NULL && nmfilters != NULL) { - /* Initialize newly allocated source filter heads. */ - for (idx = oldmax; idx < newmax; idx++) { - imf_init(&nmfilters[idx], MCAST_UNDEFINED, - MCAST_EXCLUDE); - } - imo->imo_max_memberships = newmax; - imo->imo_membership = nmships; - imo->imo_mfilters = nmfilters; - } - } - - if (nmships == NULL || nmfilters == NULL) { - if (nmships != NULL) - free(nmships, M_IPMOPTS); - if (nmfilters != NULL) - free(nmfilters, M_INMFILTER); - return (ETOOMANYREFS); - } - - return (0); -} - /* * Find an IPv4 multicast group entry for this ip_moptions instance * which matches the specified group, and optionally an interface. * Return its index into the array, or -1 if not found. */ -static size_t +static struct in_mfilter * imo_match_group(const struct ip_moptions *imo, const struct ifnet *ifp, const struct sockaddr *group) { const struct sockaddr_in *gsin; - struct in_multi **pinm; - int idx; - int nmships; + struct in_mfilter *imf; + struct in_multi *inm; gsin = (const struct sockaddr_in *)group; - /* The imo_membership array may be lazy allocated. */ - if (imo->imo_membership == NULL || imo->imo_num_memberships == 0) - return (-1); - - nmships = imo->imo_num_memberships; - pinm = &imo->imo_membership[0]; - for (idx = 0; idx < nmships; idx++, pinm++) { - if (*pinm == NULL) + IP_MFILTER_FOREACH(imf, &imo->imo_head) { + inm = imf->imf_inm; + if (inm == NULL) continue; - if ((ifp == NULL || ((*pinm)->inm_ifp == ifp)) && - in_hosteq((*pinm)->inm_addr, gsin->sin_addr)) { + if ((ifp == NULL || (inm->inm_ifp == ifp)) && + in_hosteq(inm->inm_addr, gsin->sin_addr)) { break; } } - if (idx >= nmships) - idx = -1; - - return (idx); + return (imf); } /* @@ -472,22 +434,13 @@ imo_match_group(const struct ip_moptions *imo, const struct ifnet *ifp, * it exists, which may not be the desired behaviour. */ static struct in_msource * -imo_match_source(const struct ip_moptions *imo, const size_t gidx, - const struct sockaddr *src) +imo_match_source(struct in_mfilter *imf, const struct sockaddr *src) { struct ip_msource find; - struct in_mfilter *imf; struct ip_msource *ims; const sockunion_t *psa; KASSERT(src->sa_family == AF_INET, ("%s: !AF_INET", __func__)); - KASSERT(gidx != -1 && gidx < imo->imo_num_memberships, - ("%s: invalid index %d\n", __func__, (int)gidx)); - - /* The imo_mfilters array may be lazy allocated. */ - if (imo->imo_mfilters == NULL) - return (NULL); - imf = &imo->imo_mfilters[gidx]; /* Source trees are keyed in host byte order. */ psa = (const sockunion_t *)src; @@ -507,14 +460,14 @@ int imo_multi_filter(const struct ip_moptions *imo, const struct ifnet *ifp, const struct sockaddr *group, const struct sockaddr *src) { - size_t gidx; + struct in_mfilter *imf; struct in_msource *ims; int mode; KASSERT(ifp != NULL, ("%s: null ifp", __func__)); - gidx = imo_match_group(imo, ifp, group); - if (gidx == -1) + imf = imo_match_group(imo, ifp, group); + if (imf == NULL) return (MCAST_NOTGMEMBER); /* @@ -526,8 +479,8 @@ imo_multi_filter(const struct ip_moptions *imo, const struct ifnet *ifp, * NOTE: We are comparing group state here at IGMP t1 (now) * with socket-layer t0 (since last downcall). */ - mode = imo->imo_mfilters[gidx].imf_st[1]; - ims = imo_match_source(imo, gidx, src); + mode = imf->imf_st[1]; + ims = imo_match_source(imf, src); if ((ims == NULL && mode == MCAST_INCLUDE) || (ims != NULL && ims->imsl_st[0] != mode)) @@ -1452,7 +1405,6 @@ inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) struct ip_moptions *imo; struct in_msource *ims; struct in_multi *inm; - size_t idx; uint16_t fmode; int error, doblock; @@ -1531,20 +1483,18 @@ inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr))) return (EINVAL); + IN_MULTI_LOCK(); + /* * Check if we are actually a member of this group. */ imo = inp_findmoptions(inp); - idx = imo_match_group(imo, ifp, &gsa->sa); - if (idx == -1 || imo->imo_mfilters == NULL) { + imf = imo_match_group(imo, ifp, &gsa->sa); + if (imf == NULL) { error = EADDRNOTAVAIL; goto out_inp_locked; } - - KASSERT(imo->imo_mfilters != NULL, - ("%s: imo_mfilters not allocated", __func__)); - imf = &imo->imo_mfilters[idx]; - inm = imo->imo_membership[idx]; + inm = imf->imf_inm; /* * Attempting to use the delta-based API on an @@ -1562,7 +1512,7 @@ inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) * Asked to unblock, but nothing to unblock. * If adding a new block entry, allocate it. */ - ims = imo_match_source(imo, idx, &ssa->sa); + ims = imo_match_source(imf, &ssa->sa); if ((ims != NULL && doblock) || (ims == NULL && !doblock)) { CTR3(KTR_IGMPV3, "%s: source 0x%08x %spresent", __func__, ntohl(ssa->sin.sin_addr.s_addr), doblock ? "" : "not "); @@ -1593,14 +1543,13 @@ inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) /* * Begin state merge transaction at IGMP layer. */ - IN_MULTI_LOCK(); CTR1(KTR_IGMPV3, "%s: merge inm state", __func__); IN_MULTI_LIST_LOCK(); error = inm_merge(inm, imf); if (error) { CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__); IN_MULTI_LIST_UNLOCK(); - goto out_in_multi_locked; + goto out_imf_rollback; } CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__); @@ -1609,9 +1558,6 @@ inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) if (error) CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__); -out_in_multi_locked: - - IN_MULTI_UNLOCK(); out_imf_rollback: if (error) imf_rollback(imf); @@ -1622,6 +1568,7 @@ inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) out_inp_locked: INP_WUNLOCK(inp); + IN_MULTI_UNLOCK(); return (error); } @@ -1636,9 +1583,6 @@ static struct ip_moptions * inp_findmoptions(struct inpcb *inp) { struct ip_moptions *imo; - struct in_multi **immp; - struct in_mfilter *imfp; - size_t idx; INP_WLOCK(inp); if (inp->inp_moptions != NULL) @@ -1647,29 +1591,16 @@ inp_findmoptions(struct inpcb *inp) INP_WUNLOCK(inp); imo = malloc(sizeof(*imo), M_IPMOPTS, M_WAITOK); - immp = malloc(sizeof(*immp) * IP_MIN_MEMBERSHIPS, M_IPMOPTS, - M_WAITOK | M_ZERO); - imfp = malloc(sizeof(struct in_mfilter) * IP_MIN_MEMBERSHIPS, - M_INMFILTER, M_WAITOK); imo->imo_multicast_ifp = NULL; imo->imo_multicast_addr.s_addr = INADDR_ANY; imo->imo_multicast_vif = -1; imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL; imo->imo_multicast_loop = in_mcast_loop; - imo->imo_num_memberships = 0; - imo->imo_max_memberships = IP_MIN_MEMBERSHIPS; - imo->imo_membership = immp; - - /* Initialize per-group source filters. */ - for (idx = 0; idx < IP_MIN_MEMBERSHIPS; idx++) - imf_init(&imfp[idx], MCAST_UNDEFINED, MCAST_EXCLUDE); - imo->imo_mfilters = imfp; + STAILQ_INIT(&imo->imo_head); INP_WLOCK(inp); if (inp->inp_moptions != NULL) { - free(imfp, M_INMFILTER); - free(immp, M_IPMOPTS); free(imo, M_IPMOPTS); return (inp->inp_moptions); } @@ -1680,32 +1611,25 @@ inp_findmoptions(struct inpcb *inp) static void inp_gcmoptions(struct ip_moptions *imo) { - struct in_mfilter *imf; + struct in_mfilter *imf; struct in_multi *inm; struct ifnet *ifp; - size_t idx, nmships; - nmships = imo->imo_num_memberships; - for (idx = 0; idx < nmships; ++idx) { - imf = imo->imo_mfilters ? &imo->imo_mfilters[idx] : NULL; - if (imf) - imf_leave(imf); - inm = imo->imo_membership[idx]; - ifp = inm->inm_ifp; - if (ifp != NULL) { - CURVNET_SET(ifp->if_vnet); - (void)in_leavegroup(inm, imf); - CURVNET_RESTORE(); - } else { - (void)in_leavegroup(inm, imf); + while ((imf = ip_mfilter_first(&imo->imo_head)) != NULL) { + ip_mfilter_remove(&imo->imo_head, imf); + + imf_leave(imf); + if ((inm = imf->imf_inm) != NULL) { + if ((ifp = inm->inm_ifp) != NULL) { + CURVNET_SET(ifp->if_vnet); + (void)in_leavegroup(inm, imf); + CURVNET_RESTORE(); + } else { + (void)in_leavegroup(inm, imf); + } } - if (imf) - imf_purge(imf); + ip_mfilter_free(imf); } - - if (imo->imo_mfilters) - free(imo->imo_mfilters, M_INMFILTER); - free(imo->imo_membership, M_IPMOPTS); free(imo, M_IPMOPTS); } @@ -1741,7 +1665,7 @@ inp_get_source_filters(struct inpcb *inp, struct sockopt *sopt) struct sockaddr_storage *ptss; struct sockaddr_storage *tss; int error; - size_t idx, nsrcs, ncsrcs; + size_t nsrcs, ncsrcs; INP_WLOCK_ASSERT(inp); @@ -1768,12 +1692,11 @@ inp_get_source_filters(struct inpcb *inp, struct sockopt *sopt) * Lookup group on the socket. */ gsa = (sockunion_t *)&msfr.msfr_group; - idx = imo_match_group(imo, ifp, &gsa->sa); - if (idx == -1 || imo->imo_mfilters == NULL) { + imf = imo_match_group(imo, ifp, &gsa->sa); + if (imf == NULL) { INP_WUNLOCK(inp); return (EADDRNOTAVAIL); } - imf = &imo->imo_mfilters[idx]; /* * Ignore memberships which are in limbo. @@ -2033,14 +1956,11 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) struct ip_moptions *imo; struct in_multi *inm; struct in_msource *lims; - size_t idx; int error, is_new; ifp = NULL; - imf = NULL; lims = NULL; error = 0; - is_new = 0; memset(&gsr, 0, sizeof(struct group_source_req)); gsa = (sockunion_t *)&gsr.gsr_group; @@ -2148,13 +2068,25 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) return (EADDRNOTAVAIL); + IN_MULTI_LOCK(); + + /* + * Find the membership in the membership list. + */ imo = inp_findmoptions(inp); - idx = imo_match_group(imo, ifp, &gsa->sa); - if (idx == -1) { + imf = imo_match_group(imo, ifp, &gsa->sa); + if (imf == NULL) { is_new = 1; + inm = NULL; + + if (ip_mfilter_count(&imo->imo_head) >= IP_MAX_MEMBERSHIPS) { + error = ENOMEM; + goto out_inp_locked; + } } else { - inm = imo->imo_membership[idx]; - imf = &imo->imo_mfilters[idx]; + is_new = 0; + inm = imf->imf_inm; + if (ssa->ss.ss_family != AF_UNSPEC) { /* * MCAST_JOIN_SOURCE_GROUP on an exclusive membership @@ -2181,7 +2113,7 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) * full-state SSM API with the delta-based API, * which is discouraged in the relevant RFCs. */ - lims = imo_match_source(imo, idx, &ssa->sa); + lims = imo_match_source(imf, &ssa->sa); if (lims != NULL /*&& lims->imsl_st[1] == MCAST_INCLUDE*/) { error = EADDRNOTAVAIL; @@ -2214,27 +2146,6 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) */ INP_WLOCK_ASSERT(inp); - if (is_new) { - if (imo->imo_num_memberships == imo->imo_max_memberships) { - error = imo_grow(imo); - if (error) - goto out_inp_locked; - } - /* - * Allocate the new slot upfront so we can deal with - * grafting the new source filter in same code path - * as for join-source on existing membership. - */ - idx = imo->imo_num_memberships; - imo->imo_membership[idx] = NULL; - imo->imo_num_memberships++; - KASSERT(imo->imo_mfilters != NULL, - ("%s: imf_mfilters vector was not allocated", __func__)); - imf = &imo->imo_mfilters[idx]; - KASSERT(RB_EMPTY(&imf->imf_sources), - ("%s: imf_sources not empty", __func__)); - } - /* * Graft new source into filter list for this inpcb's * membership of the group. The in_multi may not have @@ -2250,7 +2161,11 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) /* Membership starts in IN mode */ if (is_new) { CTR1(KTR_IGMPV3, "%s: new join w/source", __func__); - imf_init(imf, MCAST_UNDEFINED, MCAST_INCLUDE); + imf = ip_mfilter_alloc(M_NOWAIT, MCAST_UNDEFINED, MCAST_INCLUDE); + if (imf == NULL) { + error = ENOMEM; + goto out_inp_locked; + } } else { CTR2(KTR_IGMPV3, "%s: %s source", __func__, "allow"); } @@ -2259,34 +2174,41 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) CTR1(KTR_IGMPV3, "%s: merge imf state failed", __func__); error = ENOMEM; - goto out_imo_free; + goto out_inp_locked; } } else { /* No address specified; Membership starts in EX mode */ if (is_new) { CTR1(KTR_IGMPV3, "%s: new join w/o source", __func__); - imf_init(imf, MCAST_UNDEFINED, MCAST_EXCLUDE); + imf = ip_mfilter_alloc(M_NOWAIT, MCAST_UNDEFINED, MCAST_EXCLUDE); + if (imf == NULL) { + error = ENOMEM; + goto out_inp_locked; + } } } /* * Begin state merge transaction at IGMP layer. */ - in_pcbref(inp); - INP_WUNLOCK(inp); - IN_MULTI_LOCK(); - if (is_new) { + in_pcbref(inp); + INP_WUNLOCK(inp); + error = in_joingroup_locked(ifp, &gsa->sin.sin_addr, imf, - &inm); + &imf->imf_inm); + + INP_WLOCK(inp); + if (in_pcbrele_wlocked(inp)) { + error = ENXIO; + goto out_inp_unlocked; + } if (error) { CTR1(KTR_IGMPV3, "%s: in_joingroup_locked failed", __func__); - IN_MULTI_LIST_UNLOCK(); - goto out_imo_free; + goto out_inp_locked; } - inm_acquire(inm); - imo->imo_membership[idx] = inm; + inm_acquire(imf->imf_inm); } else { CTR1(KTR_IGMPV3, "%s: merge inm state", __func__); IN_MULTI_LIST_LOCK(); @@ -2295,7 +2217,9 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__); IN_MULTI_LIST_UNLOCK(); - goto out_in_multi_locked; + imf_rollback(imf); + imf_reap(imf); + goto out_inp_locked; } CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__); error = igmp_change_state(inm); @@ -2303,40 +2227,30 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) if (error) { CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__); - goto out_in_multi_locked; - } - } - -out_in_multi_locked: - - IN_MULTI_UNLOCK(); - INP_WLOCK(inp); - if (in_pcbrele_wlocked(inp)) - return (ENXIO); - if (error) { - imf_rollback(imf); - if (is_new) - imf_purge(imf); - else + imf_rollback(imf); imf_reap(imf); - } else { - imf_commit(imf); - } - -out_imo_free: - if (error && is_new) { - inm = imo->imo_membership[idx]; - if (inm != NULL) { - IN_MULTI_LIST_LOCK(); - inm_release_deferred(inm); - IN_MULTI_LIST_UNLOCK(); + goto out_inp_locked; } - imo->imo_membership[idx] = NULL; - --imo->imo_num_memberships; } + if (is_new) + ip_mfilter_insert(&imo->imo_head, imf); + + imf_commit(imf); + imf = NULL; out_inp_locked: INP_WUNLOCK(inp); +out_inp_unlocked: + IN_MULTI_UNLOCK(); + + if (is_new && imf) { + if (imf->imf_inm != NULL) { + IN_MULTI_LIST_LOCK(); + inm_release_deferred(imf->imf_inm); + IN_MULTI_LIST_UNLOCK(); + } + ip_mfilter_free(imf); + } return (error); } @@ -2355,12 +2269,12 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) struct ip_moptions *imo; struct in_msource *ims; struct in_multi *inm; - size_t idx; - int error, is_final; + int error; + bool is_final; ifp = NULL; error = 0; - is_final = 1; + is_final = true; memset(&gsr, 0, sizeof(struct group_source_req)); gsa = (sockunion_t *)&gsr.gsr_group; @@ -2460,20 +2374,21 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr))) return (EINVAL); + IN_MULTI_LOCK(); + /* - * Find the membership in the membership array. + * Find the membership in the membership list. */ imo = inp_findmoptions(inp); - idx = imo_match_group(imo, ifp, &gsa->sa); - if (idx == -1) { + imf = imo_match_group(imo, ifp, &gsa->sa); + if (imf == NULL) { error = EADDRNOTAVAIL; goto out_inp_locked; } - inm = imo->imo_membership[idx]; - imf = &imo->imo_mfilters[idx]; + inm = imf->imf_inm; if (ssa->ss.ss_family != AF_UNSPEC) - is_final = 0; + is_final = false; /* * Begin state merge transaction at socket layer. @@ -2485,13 +2400,14 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) * MCAST_LEAVE_SOURCE_GROUP is only valid for inclusive memberships. */ if (is_final) { + ip_mfilter_remove(&imo->imo_head, imf); imf_leave(imf); } else { if (imf->imf_st[0] == MCAST_EXCLUDE) { error = EADDRNOTAVAIL; goto out_inp_locked; } - ims = imo_match_source(imo, idx, &ssa->sa); + ims = imo_match_source(imf, &ssa->sa); if (ims == NULL) { CTR3(KTR_IGMPV3, "%s: source 0x%08x %spresent", __func__, ntohl(ssa->sin.sin_addr.s_addr), "not "); @@ -2510,17 +2426,7 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) /* * Begin state merge transaction at IGMP layer. */ - in_pcbref(inp); - INP_WUNLOCK(inp); - IN_MULTI_LOCK(); - - if (is_final) { - /* - * Give up the multicast address record to which - * the membership points. - */ - (void)in_leavegroup_locked(inm, imf); - } else { + if (!is_final) { CTR1(KTR_IGMPV3, "%s: merge inm state", __func__); IN_MULTI_LIST_LOCK(); error = inm_merge(inm, imf); @@ -2528,7 +2434,9 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__); IN_MULTI_LIST_UNLOCK(); - goto out_in_multi_locked; + imf_rollback(imf); + imf_reap(imf); + goto out_inp_locked; } CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__); @@ -2537,38 +2445,27 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) if (error) { CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__); + imf_rollback(imf); + imf_reap(imf); + goto out_inp_locked; } } - -out_in_multi_locked: - - IN_MULTI_UNLOCK(); - INP_WLOCK(inp); - if (in_pcbrele_wlocked(inp)) - return (ENXIO); - - if (error) - imf_rollback(imf); - else - imf_commit(imf); - + imf_commit(imf); imf_reap(imf); - if (is_final) { - /* Remove the gap in the membership and filter array. */ - KASSERT(RB_EMPTY(&imf->imf_sources), - ("%s: imf_sources not empty", __func__)); - for (++idx; idx < imo->imo_num_memberships; ++idx) { - imo->imo_membership[idx - 1] = imo->imo_membership[idx]; - imo->imo_mfilters[idx - 1] = imo->imo_mfilters[idx]; - } - imf_init(&imo->imo_mfilters[idx - 1], MCAST_UNDEFINED, - MCAST_EXCLUDE); - imo->imo_num_memberships--; - } - out_inp_locked: INP_WUNLOCK(inp); + + if (is_final && imf) { + /* + * Give up the multicast address record to which + * the membership points. + */ + (void) in_leavegroup_locked(imf->imf_inm, imf); + ip_mfilter_free(imf); + } + + IN_MULTI_UNLOCK(); return (error); } @@ -2658,7 +2555,6 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) struct in_mfilter *imf; struct ip_moptions *imo; struct in_multi *inm; - size_t idx; int error; error = sooptcopyin(sopt, &msfr, sizeof(struct __msfilterreq), @@ -2690,18 +2586,19 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) if (ifp == NULL) return (EADDRNOTAVAIL); + IN_MULTI_LOCK(); + /* * Take the INP write lock. * Check if this socket is a member of this group. */ imo = inp_findmoptions(inp); - idx = imo_match_group(imo, ifp, &gsa->sa); - if (idx == -1 || imo->imo_mfilters == NULL) { + imf = imo_match_group(imo, ifp, &gsa->sa); + if (imf == NULL) { error = EADDRNOTAVAIL; goto out_inp_locked; } - inm = imo->imo_membership[idx]; - imf = &imo->imo_mfilters[idx]; + inm = imf->imf_inm; /* * Begin state merge transaction at socket layer. @@ -2778,7 +2675,6 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) goto out_imf_rollback; INP_WLOCK_ASSERT(inp); - IN_MULTI_LOCK(); /* * Begin state merge transaction at IGMP layer. @@ -2789,7 +2685,7 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) if (error) { CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__); IN_MULTI_LIST_UNLOCK(); - goto out_in_multi_locked; + goto out_imf_rollback; } CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__); @@ -2798,10 +2694,6 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) if (error) CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__); -out_in_multi_locked: - - IN_MULTI_UNLOCK(); - out_imf_rollback: if (error) imf_rollback(imf); @@ -2812,6 +2704,7 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) out_inp_locked: INP_WUNLOCK(inp); + IN_MULTI_UNLOCK(); return (error); } diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 17fa34895595..b68475afa655 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -86,6 +86,9 @@ __FBSDID("$FreeBSD$"); #if defined(INET) || defined(INET6) #include #include +#ifdef INET +#include +#endif #include #include #ifdef TCPHPTS @@ -93,16 +96,13 @@ __FBSDID("$FreeBSD$"); #endif #include #include -#endif -#ifdef INET -#include -#endif #ifdef INET6 #include #include #include #include #endif /* INET6 */ +#endif #include @@ -1779,8 +1779,9 @@ void in_pcbpurgeif0(struct inpcbinfo *pcbinfo, struct ifnet *ifp) { struct inpcb *inp; + struct in_multi *inm; + struct in_mfilter *imf; struct ip_moptions *imo; - int i, gap; INP_INFO_WLOCK(pcbinfo); CK_LIST_FOREACH(inp, pcbinfo->ipi_listhead, inp_list) { @@ -1801,17 +1802,18 @@ in_pcbpurgeif0(struct inpcbinfo *pcbinfo, struct ifnet *ifp) * * XXX This can all be deferred to an epoch_call */ - for (i = 0, gap = 0; i < imo->imo_num_memberships; - i++) { - if (imo->imo_membership[i]->inm_ifp == ifp) { - IN_MULTI_LOCK_ASSERT(); - in_leavegroup_locked(imo->imo_membership[i], NULL); - gap++; - } else if (gap != 0) - imo->imo_membership[i - gap] = - imo->imo_membership[i]; +restart: + IP_MFILTER_FOREACH(imf, &imo->imo_head) { + if ((inm = imf->imf_inm) == NULL) + continue; + if (inm->inm_ifp != ifp) + continue; + ip_mfilter_remove(&imo->imo_head, imf); + IN_MULTI_LOCK_ASSERT(); + in_leavegroup_locked(inm, NULL); + ip_mfilter_free(imf); + goto restart; } - imo->imo_num_memberships -= gap; } INP_WUNLOCK(inp); } diff --git a/sys/netinet/in_var.h b/sys/netinet/in_var.h index 5b7a464bd3e8..50112481f236 100644 --- a/sys/netinet/in_var.h +++ b/sys/netinet/in_var.h @@ -232,8 +232,60 @@ struct in_mfilter { struct ip_msource_tree imf_sources; /* source list for (S,G) */ u_long imf_nsrc; /* # of source entries */ uint8_t imf_st[2]; /* state before/at commit */ + struct in_multi *imf_inm; /* associated multicast address */ + STAILQ_ENTRY(in_mfilter) imf_entry; /* list entry */ }; +/* + * Helper types and functions for IPv4 multicast filters. + */ +STAILQ_HEAD(ip_mfilter_head, in_mfilter); + +struct in_mfilter *ip_mfilter_alloc(int mflags, int st0, int st1); +void ip_mfilter_free(struct in_mfilter *); + +static inline void +ip_mfilter_init(struct ip_mfilter_head *head) +{ + + STAILQ_INIT(head); +} + +static inline struct in_mfilter * +ip_mfilter_first(const struct ip_mfilter_head *head) +{ + + return (STAILQ_FIRST(head)); +} + +static inline void +ip_mfilter_insert(struct ip_mfilter_head *head, struct in_mfilter *imf) +{ + + STAILQ_INSERT_TAIL(head, imf, imf_entry); +} + +static inline void +ip_mfilter_remove(struct ip_mfilter_head *head, struct in_mfilter *imf) +{ + + STAILQ_REMOVE(head, imf, in_mfilter, imf_entry); +} + +#define IP_MFILTER_FOREACH(imf, head) \ + STAILQ_FOREACH(imf, head, imf_entry) + +static inline size_t +ip_mfilter_count(struct ip_mfilter_head *head) +{ + struct in_mfilter *imf; + size_t num = 0; + + STAILQ_FOREACH(imf, head, imf_entry) + num++; + return (num); +} + /* * IPv4 group descriptor. * diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c index 9c24fb9fdd67..819a0f9c75e6 100644 --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -1371,25 +1371,24 @@ carp_multicast_setup(struct carp_if *cif, sa_family_t sa) case AF_INET: { struct ip_moptions *imo = &cif->cif_imo; + struct in_mfilter *imf; struct in_addr addr; - if (imo->imo_membership) + if (ip_mfilter_first(&imo->imo_head) != NULL) return (0); - imo->imo_membership = (struct in_multi **)malloc( - (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_CARP, - M_WAITOK); - imo->imo_mfilters = NULL; - imo->imo_max_memberships = IP_MIN_MEMBERSHIPS; + imf = ip_mfilter_alloc(M_WAITOK, 0, 0); + ip_mfilter_init(&imo->imo_head); imo->imo_multicast_vif = -1; addr.s_addr = htonl(INADDR_CARP_GROUP); if ((error = in_joingroup(ifp, &addr, NULL, - &imo->imo_membership[0])) != 0) { - free(imo->imo_membership, M_CARP); + &imf->imf_inm)) != 0) { + ip_mfilter_free(imf); break; } - imo->imo_num_memberships++; + + ip_mfilter_insert(&imo->imo_head, imf); imo->imo_multicast_ifp = ifp; imo->imo_multicast_ttl = CARP_DFLTTL; imo->imo_multicast_loop = 0; @@ -1400,17 +1399,16 @@ carp_multicast_setup(struct carp_if *cif, sa_family_t sa) case AF_INET6: { struct ip6_moptions *im6o = &cif->cif_im6o; + struct in6_mfilter *im6f[2]; struct in6_addr in6; - struct in6_multi *in6m; - if (im6o->im6o_membership) + if (ip6_mfilter_first(&im6o->im6o_head)) return (0); - im6o->im6o_membership = (struct in6_multi **)malloc( - (sizeof(struct in6_multi *) * IPV6_MIN_MEMBERSHIPS), M_CARP, - M_ZERO | M_WAITOK); - im6o->im6o_mfilters = NULL; - im6o->im6o_max_memberships = IPV6_MIN_MEMBERSHIPS; + im6f[0] = ip6_mfilter_alloc(M_WAITOK, 0, 0); + im6f[1] = ip6_mfilter_alloc(M_WAITOK, 0, 0); + + ip6_mfilter_init(&im6o->im6o_head); im6o->im6o_multicast_hlim = CARP_DFLTTL; im6o->im6o_multicast_ifp = ifp; @@ -1419,17 +1417,15 @@ carp_multicast_setup(struct carp_if *cif, sa_family_t sa) in6.s6_addr16[0] = htons(0xff02); in6.s6_addr8[15] = 0x12; if ((error = in6_setscope(&in6, ifp, NULL)) != 0) { - free(im6o->im6o_membership, M_CARP); + ip6_mfilter_free(im6f[0]); + ip6_mfilter_free(im6f[1]); break; } - in6m = NULL; - if ((error = in6_joingroup(ifp, &in6, NULL, &in6m, 0)) != 0) { - free(im6o->im6o_membership, M_CARP); + if ((error = in6_joingroup(ifp, &in6, NULL, &im6f[0]->im6f_in6m, 0)) != 0) { + ip6_mfilter_free(im6f[0]); + ip6_mfilter_free(im6f[1]); break; } - in6m_acquire(in6m); - im6o->im6o_membership[0] = in6m; - im6o->im6o_num_memberships++; /* Join solicited multicast address. */ bzero(&in6, sizeof(in6)); @@ -1438,20 +1434,21 @@ carp_multicast_setup(struct carp_if *cif, sa_family_t sa) in6.s6_addr32[2] = htonl(1); in6.s6_addr32[3] = 0; in6.s6_addr8[12] = 0xff; + if ((error = in6_setscope(&in6, ifp, NULL)) != 0) { - in6_leavegroup(im6o->im6o_membership[0], NULL); - free(im6o->im6o_membership, M_CARP); + ip6_mfilter_free(im6f[0]); + ip6_mfilter_free(im6f[1]); break; } - in6m = NULL; - if ((error = in6_joingroup(ifp, &in6, NULL, &in6m, 0)) != 0) { - in6_leavegroup(im6o->im6o_membership[0], NULL); - free(im6o->im6o_membership, M_CARP); + + if ((error = in6_joingroup(ifp, &in6, NULL, &im6f[1]->im6f_in6m, 0)) != 0) { + in6_leavegroup(im6f[0]->im6f_in6m, NULL); + ip6_mfilter_free(im6f[0]); + ip6_mfilter_free(im6f[1]); break; } - in6m_acquire(in6m); - im6o->im6o_membership[1] = in6m; - im6o->im6o_num_memberships++; + ip6_mfilter_insert(&im6o->im6o_head, im6f[0]); + ip6_mfilter_insert(&im6o->im6o_head, im6f[1]); break; } #endif @@ -1466,35 +1463,38 @@ carp_multicast_setup(struct carp_if *cif, sa_family_t sa) static void carp_multicast_cleanup(struct carp_if *cif, sa_family_t sa) { - +#ifdef INET + struct ip_moptions *imo = &cif->cif_imo; + struct in_mfilter *imf; +#endif +#ifdef INET6 + struct ip6_moptions *im6o = &cif->cif_im6o; + struct in6_mfilter *im6f; +#endif sx_assert(&carp_sx, SA_XLOCKED); switch (sa) { #ifdef INET case AF_INET: - if (cif->cif_naddrs == 0) { - struct ip_moptions *imo = &cif->cif_imo; - - in_leavegroup(imo->imo_membership[0], NULL); - KASSERT(imo->imo_mfilters == NULL, - ("%s: imo_mfilters != NULL", __func__)); - free(imo->imo_membership, M_CARP); - imo->imo_membership = NULL; + if (cif->cif_naddrs != 0) + break; + while ((imf = ip_mfilter_first(&imo->imo_head)) != NULL) { + ip_mfilter_remove(&imo->imo_head, imf); + in_leavegroup(imf->imf_inm, NULL); + ip_mfilter_free(imf); } break; #endif #ifdef INET6 case AF_INET6: - if (cif->cif_naddrs6 == 0) { - struct ip6_moptions *im6o = &cif->cif_im6o; + if (cif->cif_naddrs6 != 0) + break; - in6_leavegroup(im6o->im6o_membership[0], NULL); - in6_leavegroup(im6o->im6o_membership[1], NULL); - KASSERT(im6o->im6o_mfilters == NULL, - ("%s: im6o_mfilters != NULL", __func__)); - free(im6o->im6o_membership, M_CARP); - im6o->im6o_membership = NULL; + while ((im6f = ip6_mfilter_first(&im6o->im6o_head)) != NULL) { + ip6_mfilter_remove(&im6o->im6o_head, im6f); + in6_leavegroup(im6f->im6f_in6m, NULL); + ip6_mfilter_free(im6f); } break; #endif diff --git a/sys/netinet/ip_mroute.c b/sys/netinet/ip_mroute.c index 0439d353575d..14ebb6ef1007 100644 --- a/sys/netinet/ip_mroute.c +++ b/sys/netinet/ip_mroute.c @@ -1680,7 +1680,6 @@ static void send_packet(struct vif *vifp, struct mbuf *m) { struct ip_moptions imo; - struct in_multi *imm[2]; int error __unused; VIF_LOCK_ASSERT(); @@ -1689,9 +1688,7 @@ send_packet(struct vif *vifp, struct mbuf *m) imo.imo_multicast_ttl = mtod(m, struct ip *)->ip_ttl - 1; imo.imo_multicast_loop = 1; imo.imo_multicast_vif = -1; - imo.imo_num_memberships = 0; - imo.imo_max_memberships = 2; - imo.imo_membership = &imm[0]; + STAILQ_INIT(&imo.imo_head); /* * Re-entrancy should not be a problem here, because diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h index 38602efb3f4e..7580a7b45212 100644 --- a/sys/netinet/ip_var.h +++ b/sys/netinet/ip_var.h @@ -82,6 +82,7 @@ struct ipoption { char ipopt_list[MAX_IPOPTLEN]; /* options proper */ }; +#if defined(_NETINET_IN_VAR_H_) && defined(_KERNEL) /* * Structure attached to inpcb.ip_moptions and * passed to ip_output when IP multicast options are in use. @@ -93,12 +94,11 @@ struct ip_moptions { u_long imo_multicast_vif; /* vif num outgoing multicasts */ u_char imo_multicast_ttl; /* TTL for outgoing multicasts */ u_char imo_multicast_loop; /* 1 => hear sends if a member */ - u_short imo_num_memberships; /* no. memberships this socket */ - u_short imo_max_memberships; /* max memberships this socket */ - struct in_multi **imo_membership; /* group memberships */ - struct in_mfilter *imo_mfilters; /* source filters */ - struct epoch_context imo_epoch_ctx; + struct ip_mfilter_head imo_head; /* group membership list */ }; +#else +struct ip_moptions; +#endif struct ipstat { uint64_t ips_total; /* total packets received */ diff --git a/sys/netinet6/in6.h b/sys/netinet6/in6.h index 37d6ad40289e..56ab11460af2 100644 --- a/sys/netinet6/in6.h +++ b/sys/netinet6/in6.h @@ -523,11 +523,8 @@ struct route_in6 { #define IPV6_DEFAULT_MULTICAST_LOOP 1 /* normally hear sends if a member */ /* - * The im6o_membership vector for each socket is now dynamically allocated at - * run-time, bounded by USHRT_MAX, and is reallocated when needed, sized - * according to a power-of-two increment. + * Limit for IPv6 multicast memberships */ -#define IPV6_MIN_MEMBERSHIPS 31 #define IPV6_MAX_MEMBERSHIPS 4095 /* diff --git a/sys/netinet6/in6_ifattach.c b/sys/netinet6/in6_ifattach.c index a1a707449bf2..7ce680f2f91a 100644 --- a/sys/netinet6/in6_ifattach.c +++ b/sys/netinet6/in6_ifattach.c @@ -774,9 +774,11 @@ _in6_ifdetach(struct ifnet *ifp, int purgeulp) in6_purgeaddr(ifa); } if (purgeulp) { + IN6_MULTI_LOCK(); in6_pcbpurgeif0(&V_udbinfo, ifp); in6_pcbpurgeif0(&V_ulitecbinfo, ifp); in6_pcbpurgeif0(&V_ripcbinfo, ifp); + IN6_MULTI_UNLOCK(); } /* leave from all multicast groups joined */ in6_purgemaddrs(ifp); diff --git a/sys/netinet6/in6_mcast.c b/sys/netinet6/in6_mcast.c index 5557a7c76564..f68b0a84d17d 100644 --- a/sys/netinet6/in6_mcast.c +++ b/sys/netinet6/in6_mcast.c @@ -102,7 +102,8 @@ RB_GENERATE(ip6_msource_tree, ip6_msource, im6s_link, ip6_msource_cmp); /* * Locking: - * - Lock order is: Giant, INP_WLOCK, IN6_MULTI_LOCK, MLD_LOCK, IF_ADDR_LOCK. + * - Lock order is: Giant, IN6_MULTI_LOCK, INP_WLOCK, + * IN6_MULTI_LIST_LOCK, MLD_LOCK, IF_ADDR_LOCK. * - The IF_ADDR_LOCK is implicitly taken by in6m_lookup() earlier, however * it can be taken by code in net/if.c also. * - ip6_moptions and in6_mfilter are covered by the INP_WLOCK. @@ -134,12 +135,11 @@ static int im6f_prune(struct in6_mfilter *, const struct sockaddr_in6 *); static void im6f_purge(struct in6_mfilter *); static void im6f_rollback(struct in6_mfilter *); static void im6f_reap(struct in6_mfilter *); -static int im6o_grow(struct ip6_moptions *); -static size_t im6o_match_group(const struct ip6_moptions *, +static struct in6_mfilter * + im6o_match_group(const struct ip6_moptions *, const struct ifnet *, const struct sockaddr *); static struct in6_msource * - im6o_match_source(const struct ip6_moptions *, const size_t, - const struct sockaddr *); + im6o_match_source(struct in6_mfilter *, const struct sockaddr *); static void im6s_merge(struct ip6_msource *ims, const struct in6_msource *lims, const int rollback); static int in6_getmulti(struct ifnet *, const struct in6_addr *, @@ -228,55 +228,25 @@ im6f_init(struct in6_mfilter *imf, const int st0, const int st1) imf->im6f_st[1] = st1; } -/* - * Resize the ip6_moptions vector to the next power-of-two minus 1. - * May be called with locks held; do not sleep. - */ -static int -im6o_grow(struct ip6_moptions *imo) +struct in6_mfilter * +ip6_mfilter_alloc(const int mflags, const int st0, const int st1) { - struct in6_multi **nmships; - struct in6_multi **omships; - struct in6_mfilter *nmfilters; - struct in6_mfilter *omfilters; - size_t idx; - size_t newmax; - size_t oldmax; + struct in6_mfilter *imf; - nmships = NULL; - nmfilters = NULL; - omships = imo->im6o_membership; - omfilters = imo->im6o_mfilters; - oldmax = imo->im6o_max_memberships; - newmax = ((oldmax + 1) * 2) - 1; + imf = malloc(sizeof(*imf), M_IN6MFILTER, mflags); - if (newmax <= IPV6_MAX_MEMBERSHIPS) { - nmships = (struct in6_multi **)realloc(omships, - sizeof(struct in6_multi *) * newmax, M_IP6MOPTS, M_NOWAIT); - nmfilters = (struct in6_mfilter *)realloc(omfilters, - sizeof(struct in6_mfilter) * newmax, M_IN6MFILTER, - M_NOWAIT); - if (nmships != NULL && nmfilters != NULL) { - /* Initialize newly allocated source filter heads. */ - for (idx = oldmax; idx < newmax; idx++) { - im6f_init(&nmfilters[idx], MCAST_UNDEFINED, - MCAST_EXCLUDE); - } - imo->im6o_max_memberships = newmax; - imo->im6o_membership = nmships; - imo->im6o_mfilters = nmfilters; - } - } + if (imf != NULL) + im6f_init(imf, st0, st1); - if (nmships == NULL || nmfilters == NULL) { - if (nmships != NULL) - free(nmships, M_IP6MOPTS); - if (nmfilters != NULL) - free(nmfilters, M_IN6MFILTER); - return (ETOOMANYREFS); - } + return (imf); +} - return (0); +void +ip6_mfilter_free(struct in6_mfilter *imf) +{ + + im6f_purge(imf); + free(imf, M_IN6MFILTER); } /* @@ -284,36 +254,27 @@ im6o_grow(struct ip6_moptions *imo) * which matches the specified group, and optionally an interface. * Return its index into the array, or -1 if not found. */ -static size_t +static struct in6_mfilter * im6o_match_group(const struct ip6_moptions *imo, const struct ifnet *ifp, const struct sockaddr *group) { const struct sockaddr_in6 *gsin6; - struct in6_multi **pinm; - int idx; - int nmships; + struct in6_mfilter *imf; + struct in6_multi *inm; - gsin6 = (const struct sockaddr_in6 *)group; + gsin6 = (const struct sockaddr_in6 *)group; - /* The im6o_membership array may be lazy allocated. */ - if (imo->im6o_membership == NULL || imo->im6o_num_memberships == 0) - return (-1); - - nmships = imo->im6o_num_memberships; - pinm = &imo->im6o_membership[0]; - for (idx = 0; idx < nmships; idx++, pinm++) { - if (*pinm == NULL) + IP6_MFILTER_FOREACH(imf, &imo->im6o_head) { + inm = imf->im6f_in6m; + if (inm == NULL) continue; - if ((ifp == NULL || ((*pinm)->in6m_ifp == ifp)) && - IN6_ARE_ADDR_EQUAL(&(*pinm)->in6m_addr, + if ((ifp == NULL || (inm->in6m_ifp == ifp)) && + IN6_ARE_ADDR_EQUAL(&inm->in6m_addr, &gsin6->sin6_addr)) { break; } } - if (idx >= nmships) - idx = -1; - - return (idx); + return (imf); } /* @@ -328,22 +289,13 @@ im6o_match_group(const struct ip6_moptions *imo, const struct ifnet *ifp, * it exists, which may not be the desired behaviour. */ static struct in6_msource * -im6o_match_source(const struct ip6_moptions *imo, const size_t gidx, - const struct sockaddr *src) +im6o_match_source(struct in6_mfilter *imf, const struct sockaddr *src) { struct ip6_msource find; - struct in6_mfilter *imf; struct ip6_msource *ims; const sockunion_t *psa; KASSERT(src->sa_family == AF_INET6, ("%s: !AF_INET6", __func__)); - KASSERT(gidx != -1 && gidx < imo->im6o_num_memberships, - ("%s: invalid index %d\n", __func__, (int)gidx)); - - /* The im6o_mfilters array may be lazy allocated. */ - if (imo->im6o_mfilters == NULL) - return (NULL); - imf = &imo->im6o_mfilters[gidx]; psa = (const sockunion_t *)src; find.im6s_addr = psa->sin6.sin6_addr; @@ -363,14 +315,14 @@ int im6o_mc_filter(const struct ip6_moptions *imo, const struct ifnet *ifp, const struct sockaddr *group, const struct sockaddr *src) { - size_t gidx; + struct in6_mfilter *imf; struct in6_msource *ims; int mode; KASSERT(ifp != NULL, ("%s: null ifp", __func__)); - gidx = im6o_match_group(imo, ifp, group); - if (gidx == -1) + imf = im6o_match_group(imo, ifp, group); + if (imf == NULL) return (MCAST_NOTGMEMBER); /* @@ -382,8 +334,8 @@ im6o_mc_filter(const struct ip6_moptions *imo, const struct ifnet *ifp, * NOTE: We are comparing group state here at MLD t1 (now) * with socket-layer t0 (since last downcall). */ - mode = imo->im6o_mfilters[gidx].im6f_st[1]; - ims = im6o_match_source(imo, gidx, src); + mode = imf->im6f_st[1]; + ims = im6o_match_source(imf, src); if ((ims == NULL && mode == MCAST_INCLUDE) || (ims != NULL && ims->im6sl_st[0] != mode)) @@ -1447,7 +1399,6 @@ in6p_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) struct ip6_moptions *imo; struct in6_msource *ims; struct in6_multi *inm; - size_t idx; uint16_t fmode; int error, doblock; #ifdef KTR @@ -1504,16 +1455,12 @@ in6p_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) * Check if we are actually a member of this group. */ imo = in6p_findmoptions(inp); - idx = im6o_match_group(imo, ifp, &gsa->sa); - if (idx == -1 || imo->im6o_mfilters == NULL) { + imf = im6o_match_group(imo, ifp, &gsa->sa); + if (imf == NULL) { error = EADDRNOTAVAIL; goto out_in6p_locked; } - - KASSERT(imo->im6o_mfilters != NULL, - ("%s: im6o_mfilters not allocated", __func__)); - imf = &imo->im6o_mfilters[idx]; - inm = imo->im6o_membership[idx]; + inm = imf->im6f_in6m; /* * Attempting to use the delta-based API on an @@ -1531,7 +1478,7 @@ in6p_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) * Asked to unblock, but nothing to unblock. * If adding a new block entry, allocate it. */ - ims = im6o_match_source(imo, idx, &ssa->sa); + ims = im6o_match_source(imf, &ssa->sa); if ((ims != NULL && doblock) || (ims == NULL && !doblock)) { CTR3(KTR_MLD, "%s: source %s %spresent", __func__, ip6_sprintf(ip6tbuf, &ssa->sin6.sin6_addr), @@ -1601,9 +1548,6 @@ static struct ip6_moptions * in6p_findmoptions(struct inpcb *inp) { struct ip6_moptions *imo; - struct in6_multi **immp; - struct in6_mfilter *imfp; - size_t idx; INP_WLOCK(inp); if (inp->in6p_moptions != NULL) @@ -1612,27 +1556,14 @@ in6p_findmoptions(struct inpcb *inp) INP_WUNLOCK(inp); imo = malloc(sizeof(*imo), M_IP6MOPTS, M_WAITOK); - immp = malloc(sizeof(*immp) * IPV6_MIN_MEMBERSHIPS, M_IP6MOPTS, - M_WAITOK | M_ZERO); - imfp = malloc(sizeof(struct in6_mfilter) * IPV6_MIN_MEMBERSHIPS, - M_IN6MFILTER, M_WAITOK); imo->im6o_multicast_ifp = NULL; imo->im6o_multicast_hlim = V_ip6_defmcasthlim; imo->im6o_multicast_loop = in6_mcast_loop; - imo->im6o_num_memberships = 0; - imo->im6o_max_memberships = IPV6_MIN_MEMBERSHIPS; - imo->im6o_membership = immp; - - /* Initialize per-group source filters. */ - for (idx = 0; idx < IPV6_MIN_MEMBERSHIPS; idx++) - im6f_init(&imfp[idx], MCAST_UNDEFINED, MCAST_EXCLUDE); - imo->im6o_mfilters = imfp; + STAILQ_INIT(&imo->im6o_head); INP_WLOCK(inp); if (inp->in6p_moptions != NULL) { - free(imfp, M_IN6MFILTER); - free(immp, M_IP6MOPTS); free(imo, M_IP6MOPTS); return (inp->in6p_moptions); } @@ -1652,33 +1583,26 @@ in6p_findmoptions(struct inpcb *inp) static void inp_gcmoptions(struct ip6_moptions *imo) { - struct in6_mfilter *imf; + struct in6_mfilter *imf; struct in6_multi *inm; struct ifnet *ifp; - size_t idx, nmships; - nmships = imo->im6o_num_memberships; - for (idx = 0; idx < nmships; ++idx) { - imf = imo->im6o_mfilters ? &imo->im6o_mfilters[idx] : NULL; - if (imf) - im6f_leave(imf); - inm = imo->im6o_membership[idx]; - ifp = inm->in6m_ifp; - if (ifp != NULL) { - CURVNET_SET(ifp->if_vnet); - (void)in6_leavegroup(inm, imf); - CURVNET_RESTORE(); - } else { - (void)in6_leavegroup(inm, imf); - } - if (imf) - im6f_purge(imf); - } + while ((imf = ip6_mfilter_first(&imo->im6o_head)) != NULL) { + ip6_mfilter_remove(&imo->im6o_head, imf); - if (imo->im6o_mfilters) - free(imo->im6o_mfilters, M_IN6MFILTER); - free(imo->im6o_membership, M_IP6MOPTS); - free(imo, M_IP6MOPTS); + im6f_leave(imf); + if ((inm = imf->im6f_in6m) != NULL) { + if ((ifp = inm->in6m_ifp) != NULL) { + CURVNET_SET(ifp->if_vnet); + (void)in6_leavegroup(inm, imf); + CURVNET_RESTORE(); + } else { + (void)in6_leavegroup(inm, imf); + } + } + ip6_mfilter_free(imf); + } + free(imo, M_IP6MOPTS); } void @@ -1707,7 +1631,7 @@ in6p_get_source_filters(struct inpcb *inp, struct sockopt *sopt) struct sockaddr_storage *ptss; struct sockaddr_storage *tss; int error; - size_t idx, nsrcs, ncsrcs; + size_t nsrcs, ncsrcs; INP_WLOCK_ASSERT(inp); @@ -1741,12 +1665,11 @@ in6p_get_source_filters(struct inpcb *inp, struct sockopt *sopt) /* * Lookup group on the socket. */ - idx = im6o_match_group(imo, ifp, &gsa->sa); - if (idx == -1 || imo->im6o_mfilters == NULL) { + imf = im6o_match_group(imo, ifp, &gsa->sa); + if (imf == NULL) { INP_WUNLOCK(inp); return (EADDRNOTAVAIL); } - imf = &imo->im6o_mfilters[idx]; /* * Ignore memberships which are in limbo. @@ -1943,15 +1866,12 @@ in6p_join_group(struct inpcb *inp, struct sockopt *sopt) struct ip6_moptions *imo; struct in6_multi *inm; struct in6_msource *lims; - size_t idx; int error, is_new; SLIST_INIT(&inmh); ifp = NULL; - imf = NULL; lims = NULL; error = 0; - is_new = 0; memset(&gsr, 0, sizeof(struct group_source_req)); gsa = (sockunion_t *)&gsr.gsr_group; @@ -2052,13 +1972,25 @@ in6p_join_group(struct inpcb *inp, struct sockopt *sopt) */ (void)in6_setscope(&gsa->sin6.sin6_addr, ifp, NULL); + IN6_MULTI_LOCK(); + + /* + * Find the membership in the membership list. + */ imo = in6p_findmoptions(inp); - idx = im6o_match_group(imo, ifp, &gsa->sa); - if (idx == -1) { + imf = im6o_match_group(imo, ifp, &gsa->sa); + if (imf == NULL) { is_new = 1; + inm = NULL; + + if (ip6_mfilter_count(&imo->im6o_head) >= IPV6_MAX_MEMBERSHIPS) { + error = ENOMEM; + goto out_in6p_locked; + } } else { - inm = imo->im6o_membership[idx]; - imf = &imo->im6o_mfilters[idx]; + is_new = 0; + inm = imf->im6f_in6m; + if (ssa->ss.ss_family != AF_UNSPEC) { /* * MCAST_JOIN_SOURCE_GROUP on an exclusive membership @@ -2085,7 +2017,7 @@ in6p_join_group(struct inpcb *inp, struct sockopt *sopt) * full-state SSM API with the delta-based API, * which is discouraged in the relevant RFCs. */ - lims = im6o_match_source(imo, idx, &ssa->sa); + lims = im6o_match_source(imf, &ssa->sa); if (lims != NULL /*&& lims->im6sl_st[1] == MCAST_INCLUDE*/) { error = EADDRNOTAVAIL; @@ -2113,27 +2045,6 @@ in6p_join_group(struct inpcb *inp, struct sockopt *sopt) */ INP_WLOCK_ASSERT(inp); - if (is_new) { - if (imo->im6o_num_memberships == imo->im6o_max_memberships) { - error = im6o_grow(imo); - if (error) - goto out_in6p_locked; - } - /* - * Allocate the new slot upfront so we can deal with - * grafting the new source filter in same code path - * as for join-source on existing membership. - */ - idx = imo->im6o_num_memberships; - imo->im6o_membership[idx] = NULL; - imo->im6o_num_memberships++; - KASSERT(imo->im6o_mfilters != NULL, - ("%s: im6f_mfilters vector was not allocated", __func__)); - imf = &imo->im6o_mfilters[idx]; - KASSERT(RB_EMPTY(&imf->im6f_sources), - ("%s: im6f_sources not empty", __func__)); - } - /* * Graft new source into filter list for this inpcb's * membership of the group. The in6_multi may not have @@ -2149,7 +2060,11 @@ in6p_join_group(struct inpcb *inp, struct sockopt *sopt) /* Membership starts in IN mode */ if (is_new) { CTR1(KTR_MLD, "%s: new join w/source", __func__); - im6f_init(imf, MCAST_UNDEFINED, MCAST_INCLUDE); + imf = ip6_mfilter_alloc(M_NOWAIT, MCAST_UNDEFINED, MCAST_INCLUDE); + if (imf == NULL) { + error = ENOMEM; + goto out_in6p_locked; + } } else { CTR2(KTR_MLD, "%s: %s source", __func__, "allow"); } @@ -2158,81 +2073,88 @@ in6p_join_group(struct inpcb *inp, struct sockopt *sopt) CTR1(KTR_MLD, "%s: merge imf state failed", __func__); error = ENOMEM; - goto out_im6o_free; + goto out_in6p_locked; } } else { /* No address specified; Membership starts in EX mode */ if (is_new) { CTR1(KTR_MLD, "%s: new join w/o source", __func__); - im6f_init(imf, MCAST_UNDEFINED, MCAST_EXCLUDE); + imf = ip6_mfilter_alloc(M_NOWAIT, MCAST_UNDEFINED, MCAST_EXCLUDE); + if (imf == NULL) { + error = ENOMEM; + goto out_in6p_locked; + } } } /* * Begin state merge transaction at MLD layer. */ - in_pcbref(inp); - INP_WUNLOCK(inp); - IN6_MULTI_LOCK(); - if (is_new) { + in_pcbref(inp); + INP_WUNLOCK(inp); + error = in6_joingroup_locked(ifp, &gsa->sin6.sin6_addr, imf, - &inm, 0); + &imf->im6f_in6m, 0); + + INP_WLOCK(inp); + if (in_pcbrele_wlocked(inp)) { + error = ENXIO; + goto out_in6p_unlocked; + } if (error) { - IN6_MULTI_UNLOCK(); - goto out_im6o_free; + goto out_in6p_locked; } /* * NOTE: Refcount from in6_joingroup_locked() * is protecting membership. */ - imo->im6o_membership[idx] = inm; } else { CTR1(KTR_MLD, "%s: merge inm state", __func__); IN6_MULTI_LIST_LOCK(); error = in6m_merge(inm, imf); - if (error) + if (error) { CTR1(KTR_MLD, "%s: failed to merge inm state", __func__); - else { - CTR1(KTR_MLD, "%s: doing mld downcall", __func__); - error = mld_change_state(inm, 0); - if (error) - CTR1(KTR_MLD, "%s: failed mld downcall", - __func__); - } - IN6_MULTI_LIST_UNLOCK(); - } - - IN6_MULTI_UNLOCK(); - INP_WLOCK(inp); - if (in_pcbrele_wlocked(inp)) - return (ENXIO); - if (error) { - im6f_rollback(imf); - if (is_new) - im6f_purge(imf); - else - im6f_reap(imf); - } else { - im6f_commit(imf); - } - -out_im6o_free: - if (error && is_new) { - inm = imo->im6o_membership[idx]; - if (inm != NULL) { - IN6_MULTI_LIST_LOCK(); - in6m_rele_locked(&inmh, inm); IN6_MULTI_LIST_UNLOCK(); + im6f_rollback(imf); + im6f_reap(imf); + goto out_in6p_locked; + } + CTR1(KTR_MLD, "%s: doing mld downcall", __func__); + error = mld_change_state(inm, 0); + IN6_MULTI_LIST_UNLOCK(); + + if (error) { + CTR1(KTR_MLD, "%s: failed mld downcall", + __func__); + im6f_rollback(imf); + im6f_reap(imf); + goto out_in6p_locked; } - imo->im6o_membership[idx] = NULL; - --imo->im6o_num_memberships; } + if (is_new) + ip6_mfilter_insert(&imo->im6o_head, imf); + + im6f_commit(imf); + imf = NULL; + out_in6p_locked: INP_WUNLOCK(inp); - in6m_release_list_deferred(&inmh); +out_in6p_unlocked: + IN6_MULTI_UNLOCK(); + + if (is_new && imf) { + if (imf->im6f_in6m != NULL) { + struct in6_multi_head inmh; + + SLIST_INIT(&inmh); + SLIST_INSERT_HEAD(&inmh, imf->im6f_in6m, in6m_defer); + in6m_release_list_deferred(&inmh); + } + ip6_mfilter_free(imf); + } return (error); } @@ -2251,8 +2173,8 @@ in6p_leave_group(struct inpcb *inp, struct sockopt *sopt) struct in6_msource *ims; struct in6_multi *inm; uint32_t ifindex; - size_t idx; - int error, is_final; + int error; + bool is_final; #ifdef KTR char ip6tbuf[INET6_ADDRSTRLEN]; #endif @@ -2260,7 +2182,7 @@ in6p_leave_group(struct inpcb *inp, struct sockopt *sopt) ifp = NULL; ifindex = 0; error = 0; - is_final = 1; + is_final = true; memset(&gsr, 0, sizeof(struct group_source_req)); gsa = (sockunion_t *)&gsr.gsr_group; @@ -2378,20 +2300,21 @@ in6p_leave_group(struct inpcb *inp, struct sockopt *sopt) CTR2(KTR_MLD, "%s: ifp = %p", __func__, ifp); KASSERT(ifp != NULL, ("%s: ifp did not resolve", __func__)); + IN6_MULTI_LOCK(); + /* - * Find the membership in the membership array. + * Find the membership in the membership list. */ imo = in6p_findmoptions(inp); - idx = im6o_match_group(imo, ifp, &gsa->sa); - if (idx == -1) { + imf = im6o_match_group(imo, ifp, &gsa->sa); + if (imf == NULL) { error = EADDRNOTAVAIL; goto out_in6p_locked; } - inm = imo->im6o_membership[idx]; - imf = &imo->im6o_mfilters[idx]; + inm = imf->im6f_in6m; if (ssa->ss.ss_family != AF_UNSPEC) - is_final = 0; + is_final = false; /* * Begin state merge transaction at socket layer. @@ -2403,13 +2326,14 @@ in6p_leave_group(struct inpcb *inp, struct sockopt *sopt) * MCAST_LEAVE_SOURCE_GROUP is only valid for inclusive memberships. */ if (is_final) { + ip6_mfilter_remove(&imo->im6o_head, imf); im6f_leave(imf); } else { if (imf->im6f_st[0] == MCAST_EXCLUDE) { error = EADDRNOTAVAIL; goto out_in6p_locked; } - ims = im6o_match_source(imo, idx, &ssa->sa); + ims = im6o_match_source(imf, &ssa->sa); if (ims == NULL) { CTR3(KTR_MLD, "%s: source %p %spresent", __func__, ip6_sprintf(ip6tbuf, &ssa->sin6.sin6_addr), @@ -2429,60 +2353,47 @@ in6p_leave_group(struct inpcb *inp, struct sockopt *sopt) /* * Begin state merge transaction at MLD layer. */ - in_pcbref(inp); - INP_WUNLOCK(inp); - IN6_MULTI_LOCK(); + if (!is_final) { + CTR1(KTR_MLD, "%s: merge inm state", __func__); + IN6_MULTI_LIST_LOCK(); + error = in6m_merge(inm, imf); + if (error) { + CTR1(KTR_MLD, "%s: failed to merge inm state", + __func__); + IN6_MULTI_LIST_UNLOCK(); + im6f_rollback(imf); + im6f_reap(imf); + goto out_in6p_locked; + } - if (is_final) { + CTR1(KTR_MLD, "%s: doing mld downcall", __func__); + error = mld_change_state(inm, 0); + IN6_MULTI_LIST_UNLOCK(); + if (error) { + CTR1(KTR_MLD, "%s: failed mld downcall", + __func__); + im6f_rollback(imf); + im6f_reap(imf); + goto out_in6p_locked; + } + } + + im6f_commit(imf); + im6f_reap(imf); + +out_in6p_locked: + INP_WUNLOCK(inp); + + if (is_final && imf) { /* * Give up the multicast address record to which * the membership points. */ (void)in6_leavegroup_locked(inm, imf); - } else { - CTR1(KTR_MLD, "%s: merge inm state", __func__); - IN6_MULTI_LIST_LOCK(); - error = in6m_merge(inm, imf); - if (error) - CTR1(KTR_MLD, "%s: failed to merge inm state", - __func__); - else { - CTR1(KTR_MLD, "%s: doing mld downcall", __func__); - error = mld_change_state(inm, 0); - if (error) - CTR1(KTR_MLD, "%s: failed mld downcall", - __func__); - } - IN6_MULTI_LIST_UNLOCK(); + ip6_mfilter_free(imf); } IN6_MULTI_UNLOCK(); - INP_WLOCK(inp); - if (in_pcbrele_wlocked(inp)) - return (ENXIO); - - if (error) - im6f_rollback(imf); - else - im6f_commit(imf); - - im6f_reap(imf); - - if (is_final) { - /* Remove the gap in the membership array. */ - KASSERT(RB_EMPTY(&imf->im6f_sources), - ("%s: im6f_sources not empty", __func__)); - for (++idx; idx < imo->im6o_num_memberships; ++idx) { - imo->im6o_membership[idx - 1] = imo->im6o_membership[idx]; - imo->im6o_mfilters[idx - 1] = imo->im6o_mfilters[idx]; - } - im6f_init(&imo->im6o_mfilters[idx - 1], MCAST_UNDEFINED, - MCAST_EXCLUDE); - imo->im6o_num_memberships--; - } - -out_in6p_locked: - INP_WUNLOCK(inp); return (error); } @@ -2540,7 +2451,6 @@ in6p_set_source_filters(struct inpcb *inp, struct sockopt *sopt) struct in6_mfilter *imf; struct ip6_moptions *imo; struct in6_multi *inm; - size_t idx; int error; error = sooptcopyin(sopt, &msfr, sizeof(struct __msfilterreq), @@ -2577,13 +2487,12 @@ in6p_set_source_filters(struct inpcb *inp, struct sockopt *sopt) * Check if this socket is a member of this group. */ imo = in6p_findmoptions(inp); - idx = im6o_match_group(imo, ifp, &gsa->sa); - if (idx == -1 || imo->im6o_mfilters == NULL) { + imf = im6o_match_group(imo, ifp, &gsa->sa); + if (imf == NULL) { error = EADDRNOTAVAIL; goto out_in6p_locked; } - inm = imo->im6o_membership[idx]; - imf = &imo->im6o_mfilters[idx]; + inm = imf->im6f_in6m; /* * Begin state merge transaction at socket layer. diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index c27464b1e3e7..abad883dc623 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -802,8 +802,9 @@ void in6_pcbpurgeif0(struct inpcbinfo *pcbinfo, struct ifnet *ifp) { struct inpcb *in6p; + struct in6_multi *inm; + struct in6_mfilter *imf; struct ip6_moptions *im6o; - int i, gap; INP_INFO_WLOCK(pcbinfo); CK_LIST_FOREACH(in6p, pcbinfo->ipi_listhead, inp_list) { @@ -824,18 +825,18 @@ in6_pcbpurgeif0(struct inpcbinfo *pcbinfo, struct ifnet *ifp) * Drop multicast group membership if we joined * through the interface being detached. */ - gap = 0; - for (i = 0; i < im6o->im6o_num_memberships; i++) { - if (im6o->im6o_membership[i]->in6m_ifp == - ifp) { - in6_leavegroup(im6o->im6o_membership[i], NULL); - gap++; - } else if (gap != 0) { - im6o->im6o_membership[i - gap] = - im6o->im6o_membership[i]; - } +restart: + IP6_MFILTER_FOREACH(imf, &im6o->im6o_head) { + if ((inm = imf->im6f_in6m) == NULL) + continue; + if (inm->in6m_ifp != ifp) + continue; + ip6_mfilter_remove(&im6o->im6o_head, imf); + IN6_MULTI_LOCK_ASSERT(); + in6_leavegroup_locked(inm, NULL); + ip6_mfilter_free(imf); + goto restart; } - im6o->im6o_num_memberships -= gap; } INP_WUNLOCK(in6p); } diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h index 3e965c2d4b32..3e535310b29e 100644 --- a/sys/netinet6/in6_var.h +++ b/sys/netinet6/in6_var.h @@ -602,8 +602,60 @@ struct in6_mfilter { struct ip6_msource_tree im6f_sources; /* source list for (S,G) */ u_long im6f_nsrc; /* # of source entries */ uint8_t im6f_st[2]; /* state before/at commit */ + struct in6_multi *im6f_in6m; /* associated multicast address */ + STAILQ_ENTRY(in6_mfilter) im6f_entry; /* list entry */ }; +/* + * Helper types and functions for IPv4 multicast filters. + */ +STAILQ_HEAD(ip6_mfilter_head, in6_mfilter); + +struct in6_mfilter *ip6_mfilter_alloc(int mflags, int st0, int st1); +void ip6_mfilter_free(struct in6_mfilter *); + +static inline void +ip6_mfilter_init(struct ip6_mfilter_head *head) +{ + + STAILQ_INIT(head); +} + +static inline struct in6_mfilter * +ip6_mfilter_first(const struct ip6_mfilter_head *head) +{ + + return (STAILQ_FIRST(head)); +} + +static inline void +ip6_mfilter_insert(struct ip6_mfilter_head *head, struct in6_mfilter *imf) +{ + + STAILQ_INSERT_TAIL(head, imf, im6f_entry); +} + +static inline void +ip6_mfilter_remove(struct ip6_mfilter_head *head, struct in6_mfilter *imf) +{ + + STAILQ_REMOVE(head, imf, in6_mfilter, im6f_entry); +} + +#define IP6_MFILTER_FOREACH(imf, head) \ + STAILQ_FOREACH(imf, head, im6f_entry) + +static inline size_t +ip6_mfilter_count(struct ip6_mfilter_head *head) +{ + struct in6_mfilter *imf; + size_t num = 0; + + STAILQ_FOREACH(imf, head, im6f_entry) + num++; + return (num); +} + /* * Legacy KAME IPv6 multicast membership descriptor. */ diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h index 40f502abcd08..45ee4425fb74 100644 --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -110,6 +110,7 @@ struct ip6_direct_ctx { uint32_t ip6dc_off; /* offset to next header */ }; +#if defined(_NETINET6_IN6_VAR_H_) && defined(_KERNEL) /* * Structure attached to inpcb.in6p_moptions and * passed to ip6_output when IPv6 multicast options are in use. @@ -119,13 +120,11 @@ struct ip6_moptions { struct ifnet *im6o_multicast_ifp; /* ifp for outgoing multicasts */ u_char im6o_multicast_hlim; /* hoplimit for outgoing multicasts */ u_char im6o_multicast_loop; /* 1 >= hear sends if a member */ - u_short im6o_num_memberships; /* no. memberships this socket */ - u_short im6o_max_memberships; /* max memberships this socket */ - struct in6_multi **im6o_membership; /* group memberships */ - struct in6_mfilter *im6o_mfilters; /* source filters */ - struct epoch_context imo6_epoch_ctx; + struct ip6_mfilter_head im6o_head; /* group membership list */ }; - +#else +struct ip6_moptions; +#endif /* * Control options for outgoing packets */ diff --git a/sys/netpfil/pf/if_pfsync.c b/sys/netpfil/pf/if_pfsync.c index 45b1e090f95c..0566593b7616 100644 --- a/sys/netpfil/pf/if_pfsync.c +++ b/sys/netpfil/pf/if_pfsync.c @@ -264,7 +264,7 @@ static void pfsync_push(struct pfsync_bucket *); static void pfsync_push_all(struct pfsync_softc *); static void pfsyncintr(void *); static int pfsync_multicast_setup(struct pfsync_softc *, struct ifnet *, - void *); + struct in_mfilter *imf); static void pfsync_multicast_cleanup(struct pfsync_softc *); static void pfsync_pointers_init(void); static void pfsync_pointers_uninit(void); @@ -430,8 +430,7 @@ pfsync_clone_destroy(struct ifnet *ifp) pfsync_drop(sc); if_free(ifp); - if (sc->sc_imo.imo_membership) - pfsync_multicast_cleanup(sc); + pfsync_multicast_cleanup(sc); mtx_destroy(&sc->sc_mtx); mtx_destroy(&sc->sc_bulk_mtx); @@ -1373,10 +1372,9 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) case SIOCSETPFSYNC: { - struct ip_moptions *imo = &sc->sc_imo; + struct in_mfilter *imf = NULL; struct ifnet *sifp; struct ip *ip; - void *mship = NULL; if ((error = priv_check(curthread, PRIV_NETINET_PF)) != 0) return (error); @@ -1396,8 +1394,7 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) pfsyncr.pfsyncr_syncpeer.s_addr == 0 || pfsyncr.pfsyncr_syncpeer.s_addr == htonl(INADDR_PFSYNC_GROUP))) - mship = malloc((sizeof(struct in_multi *) * - IP_MIN_MEMBERSHIPS), M_PFSYNC, M_WAITOK | M_ZERO); + imf = ip_mfilter_alloc(M_WAITOK, 0, 0); PFSYNC_LOCK(sc); if (pfsyncr.pfsyncr_syncpeer.s_addr == 0) @@ -1419,8 +1416,7 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) if (sc->sc_sync_if) if_rele(sc->sc_sync_if); sc->sc_sync_if = NULL; - if (imo->imo_membership) - pfsync_multicast_cleanup(sc); + pfsync_multicast_cleanup(sc); PFSYNC_UNLOCK(sc); break; } @@ -1436,14 +1432,13 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) PFSYNC_BUCKET_UNLOCK(&sc->sc_buckets[c]); } - if (imo->imo_membership) - pfsync_multicast_cleanup(sc); + pfsync_multicast_cleanup(sc); if (sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) { - error = pfsync_multicast_setup(sc, sifp, mship); + error = pfsync_multicast_setup(sc, sifp, imf); if (error) { if_rele(sifp); - free(mship, M_PFSYNC); + ip_mfilter_free(imf); PFSYNC_UNLOCK(sc); return (error); } @@ -2353,7 +2348,8 @@ pfsyncintr(void *arg) } static int -pfsync_multicast_setup(struct pfsync_softc *sc, struct ifnet *ifp, void *mship) +pfsync_multicast_setup(struct pfsync_softc *sc, struct ifnet *ifp, + struct in_mfilter *imf) { struct ip_moptions *imo = &sc->sc_imo; int error; @@ -2361,16 +2357,14 @@ pfsync_multicast_setup(struct pfsync_softc *sc, struct ifnet *ifp, void *mship) if (!(ifp->if_flags & IFF_MULTICAST)) return (EADDRNOTAVAIL); - imo->imo_membership = (struct in_multi **)mship; - imo->imo_max_memberships = IP_MIN_MEMBERSHIPS; imo->imo_multicast_vif = -1; if ((error = in_joingroup(ifp, &sc->sc_sync_peer, NULL, - &imo->imo_membership[0])) != 0) { - imo->imo_membership = NULL; + &imf->imf_inm)) != 0) return (error); - } - imo->imo_num_memberships++; + + ip_mfilter_init(&imo->imo_head); + ip_mfilter_insert(&imo->imo_head, imf); imo->imo_multicast_ifp = ifp; imo->imo_multicast_ttl = PFSYNC_DFLTTL; imo->imo_multicast_loop = 0; @@ -2382,10 +2376,13 @@ static void pfsync_multicast_cleanup(struct pfsync_softc *sc) { struct ip_moptions *imo = &sc->sc_imo; + struct in_mfilter *imf; - in_leavegroup(imo->imo_membership[0], NULL); - free(imo->imo_membership, M_PFSYNC); - imo->imo_membership = NULL; + while ((imf = ip_mfilter_first(&imo->imo_head)) != NULL) { + ip_mfilter_remove(&imo->imo_head, imf); + in_leavegroup(imf->imf_inm, NULL); + ip_mfilter_free(imf); + } imo->imo_multicast_ifp = NULL; } @@ -2404,7 +2401,7 @@ pfsync_detach_ifnet(struct ifnet *ifp) * is going away. We do need to ensure we don't try to do * cleanup later. */ - sc->sc_imo.imo_membership = NULL; + ip_mfilter_init(&sc->sc_imo.imo_head); sc->sc_imo.imo_multicast_ifp = NULL; sc->sc_sync_if = NULL; } From 9efd65a9d280969c46be0b25e2d6a6ceca161ce0 Mon Sep 17 00:00:00 2001 From: Hans Petter Selasky Date: Tue, 25 Jun 2019 13:15:29 +0000 Subject: [PATCH 099/165] Fix parsing of corrupt data in usbdump(8). Check that the transfer type array lookup is within bounds to avoid segfault. PR: 238801 MFC after: 3 days Sponsored by: Mellanox Technologies --- usr.sbin/usbdump/usbdump.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/usr.sbin/usbdump/usbdump.c b/usr.sbin/usbdump/usbdump.c index ef4476f55d8c..a38d08a252af 100644 --- a/usr.sbin/usbdump/usbdump.c +++ b/usr.sbin/usbdump/usbdump.c @@ -149,7 +149,9 @@ static const char *errstr_table[USB_ERR_MAX] = { [USB_ERR_NOT_LOCKED] = "NOT_LOCKED", }; -static const char *xfertype_table[4] = { +#define USB_XFERTYPE_MAX 4 + +static const char *xfertype_table[USB_XFERTYPE_MAX] = { [UE_CONTROL] = "CTRL", [UE_ISOCHRONOUS] = "ISOC", [UE_BULK] = "BULK", @@ -320,6 +322,15 @@ usb_speedstr(uint8_t speed) return (speed_table[speed]); } +static const char * +usb_xferstr(uint8_t type) +{ + if (type >= USB_XFERTYPE_MAX || xfertype_table[type] == NULL) + return ("UNKN"); + else + return (xfertype_table[type]); +} + static void print_flags(uint32_t flags) { @@ -496,7 +507,7 @@ print_apacket(const struct header_32 *hdr, const uint8_t *ptr, int ptr_len) (int)len, buf, tv.tv_usec, (int)up->up_busunit, (int)up->up_address, (up->up_type == USBPF_XFERTAP_SUBMIT) ? "SUBM" : "DONE", - xfertype_table[up->up_xfertype], + usb_xferstr(up->up_xfertype), (unsigned int)up->up_endpoint, usb_speedstr(up->up_speed), (int)up->up_frames, From 8d048f68d4e0c1df38c6cb734b4de9dc491e3f2c Mon Sep 17 00:00:00 2001 From: Marko Zec Date: Tue, 25 Jun 2019 14:50:03 +0000 Subject: [PATCH 100/165] Croatian calendar: update / fix names, dates, group national public holidays, sort by date. MFC after: 3 days --- .../hr_HR.ISO8859-2/calendar.praznici | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/usr.bin/calendar/calendars/hr_HR.ISO8859-2/calendar.praznici b/usr.bin/calendar/calendars/hr_HR.ISO8859-2/calendar.praznici index 60ae5e30bd2f..491ec6a4f3f3 100644 --- a/usr.bin/calendar/calendars/hr_HR.ISO8859-2/calendar.praznici +++ b/usr.bin/calendar/calendars/hr_HR.ISO8859-2/calendar.praznici @@ -10,31 +10,31 @@ LANG=hr_HR.ISO8859-2 /* dr¾avni praznici */ -01/01 Nova godina -05/01 Praznik rada -05/30 Tjelovo -06/22 Dan antifa¹istièke borbe -06/25 Dan dr¾avnosti -08/05 Dan domovinske zahvalnosti -10/08 Dan neovisnosti - -/* katolièki blagdani */ -01/06 Sveta tri kralja -Easter-2 Veliki petak +01/01 Nova godina +01/06 Bogojavljenje ili Sveta tri kralja Easter Uskrs Easter+1 Uskrsni ponedjeljak -Easter+49 Duhovi -Easter+50 Duhovni ponedjeljak -Easter+39 Uza¹a¹æe +05/01 Praznik rada +Easter+60 Tijelovo +06/22 Dan antifa¹istièke borbe +06/25 Dan dr¾avnosti +08/05 Dan pobjede i domovinske zahvalnosti i Dan hrvatskih branitelja 08/15 Velika Gospa +10/08 Dan neovisnosti 11/01 Svi sveti 12/25 Bo¾iæ -12/26 Stjepandan +12/26 Sveti Stjepan + +/* katolièki blagdani */ +Easter-2 Veliki petak +Easter+39 Uza¹a¹æe +Easter+49 Duhovi +Easter+50 Duhovni ponedjeljak /* godi¹nja doba */ 03/21* Poèetak proljeæa 06/21* Poèetak ljeta -09/21* Poèetak jesena +09/23* Poèetak jeseni 12/21* Poèetak zime /* ljetno vrijeme */ From 343a7eabf30393a4ee7b51469ddc804b9ac132a4 Mon Sep 17 00:00:00 2001 From: Glen Barber Date: Tue, 25 Jun 2019 14:56:13 +0000 Subject: [PATCH 101/165] Include files containing metadata specific to the branch in the directory where the individual distribution sets exist. The new metadata files include the build date, svn branch, and revision of the build. Requested by: Mellanox Technologies (via kib) MFC after: 3 days Sponsored by: Rubicon Communications, LLC (Netgate) --- release/Makefile.mirrors | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/release/Makefile.mirrors b/release/Makefile.mirrors index 44589d698c3c..6857ff0eafb1 100644 --- a/release/Makefile.mirrors +++ b/release/Makefile.mirrors @@ -19,6 +19,7 @@ FTPDIR?= ${RELEASEDIR}/ftp-stage .if exists(${RELEASEDIR}) STAGE_TARGETS?= iso-images-stage .endif +SRCBRANCH!= ${SVN_CMD} info --show-item relative-url ${WORLDDIR} .if (defined(EMBEDDED_TARGET) && !empty(EMBEDDED_TARGET)) || (defined(EMBEDDEDBUILD) && !empty(EMBEDDEDBUILD)) . if ${TARGET:Marm*} != "" || ${EMBEDDED_TARGET:Marm*} != "" @@ -185,6 +186,9 @@ iso-images-stage: .if exists(${RELEASEDIR}/ftp) mkdir -p ${FTP_DIR} cp -p ${RELEASEDIR}/ftp/*.txz ${RELEASEDIR}/ftp/MANIFEST ${FTP_DIR} + echo ${BUILDDATE} > ${FTP_DIR}/BUILDDATE + echo ${SRCBRANCH} > ${FTP_DIR}/SRCBRANCH + echo r${SVNREVISION} > ${FTP_DIR}/REVISION cd ${TLD}/${TARGET} && \ ln -s ${TARGET_ARCH}/${REVISION}-${BRANCH} \ ${REVISION}-${BRANCH} From 0e2464ea18bd17f21eea3336d3462fd912e4218c Mon Sep 17 00:00:00 2001 From: Ryan Libby Date: Tue, 25 Jun 2019 15:43:52 +0000 Subject: [PATCH 102/165] netipsec key_register: check for M_NOWAIT alloc failure Reviewed by: ae, cem Sponsored by: Dell EMC Isilon Differential Revision: https://reviews.freebsd.org/D20742 --- sys/netipsec/key.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/netipsec/key.c b/sys/netipsec/key.c index d54427410b92..82a84a412538 100644 --- a/sys/netipsec/key.c +++ b/sys/netipsec/key.c @@ -7164,7 +7164,7 @@ key_register(struct socket *so, struct mbuf *m, const struct sadb_msghdr *mhp) return key_senderror(so, m, ENOBUFS); MGETHDR(n, M_NOWAIT, MT_DATA); - if (len > MHLEN) { + if (n != NULL && len > MHLEN) { if (!(MCLGET(n, M_NOWAIT))) { m_freem(n); n = NULL; From 7a3e3a2859242f9c855b21248d0aebd3b7cbe782 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Tue, 25 Jun 2019 16:39:25 +0000 Subject: [PATCH 103/165] Remove a couple of harmless stray references to nandfs. Submitted by: tsoome@ --- sys/arm/conf/DB-78XXX | 1 - sys/arm/conf/DB-88F6XXX | 1 - sys/arm/conf/SHEEVAPLUG | 1 - sys/arm/conf/VYBRID | 1 - sys/conf/options | 1 - sys/kern/Make.tags.inc | 2 -- 6 files changed, 7 deletions(-) diff --git a/sys/arm/conf/DB-78XXX b/sys/arm/conf/DB-78XXX index 2007405751cc..44df77cf45f1 100644 --- a/sys/arm/conf/DB-78XXX +++ b/sys/arm/conf/DB-78XXX @@ -20,7 +20,6 @@ options GEOM_PART_BSD # BSD partition scheme options GEOM_PART_MBR # MBR partition scheme options TMPFS # Efficient memory filesystem options FFS # Berkeley Fast Filesystem -options NANDFS # NAND Filesystem options NFSCL # Network Filesystem Client options NFSLOCKD # Network Lock Manager options NFS_ROOT # NFS usable as /, requires NFSCL diff --git a/sys/arm/conf/DB-88F6XXX b/sys/arm/conf/DB-88F6XXX index 64465baf4c77..66a385ddbe40 100644 --- a/sys/arm/conf/DB-88F6XXX +++ b/sys/arm/conf/DB-88F6XXX @@ -17,7 +17,6 @@ options INET # InterNETworking options INET6 # IPv6 communications protocols options TCP_HHOOK # hhook(9) framework for TCP options FFS # Berkeley Fast Filesystem -options NANDFS # NAND Filesystem options NFSCL # Network Filesystem Client options NFSLOCKD # Network Lock Manager options NFS_ROOT # NFS usable as /, requires NFSCL diff --git a/sys/arm/conf/SHEEVAPLUG b/sys/arm/conf/SHEEVAPLUG index b24a6d80a873..d7d161956ce4 100644 --- a/sys/arm/conf/SHEEVAPLUG +++ b/sys/arm/conf/SHEEVAPLUG @@ -19,7 +19,6 @@ options INET # InterNETworking options INET6 # IPv6 communications protocols options TCP_HHOOK # hhook(9) framework for TCP options FFS # Berkeley Fast Filesystem -options NANDFS # NAND Filesystem options NFSCL # Network Filesystem Client options NFSLOCKD # Network Lock Manager options NFS_ROOT # NFS usable as /, requires NFSCL diff --git a/sys/arm/conf/VYBRID b/sys/arm/conf/VYBRID index 318a7d0e3c68..b114c6e3e923 100644 --- a/sys/arm/conf/VYBRID +++ b/sys/arm/conf/VYBRID @@ -26,7 +26,6 @@ makeoptions WERROR="-Werror" options SCHED_4BSD # 4BSD scheduler options PLATFORM # Platform based SoC -#options NANDFS # NAND Filesystem #options SMP # Enable multiple cores # NFS root from boopt/dhcp diff --git a/sys/conf/options b/sys/conf/options index 6caae9a0708c..ca0b94dfadbe 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -256,7 +256,6 @@ FDESCFS opt_dontuse.h FFS opt_dontuse.h FUSEFS opt_dontuse.h MSDOSFS opt_dontuse.h -NANDFS opt_dontuse.h NULLFS opt_dontuse.h PROCFS opt_dontuse.h PSEUDOFS opt_dontuse.h diff --git a/sys/kern/Make.tags.inc b/sys/kern/Make.tags.inc index 50aed68dbf40..cdefa98a32f6 100644 --- a/sys/kern/Make.tags.inc +++ b/sys/kern/Make.tags.inc @@ -28,7 +28,6 @@ COMM= ${SYS}/sys/vnode.h \ ${SYS}/fs/fifofs/*.[ch] \ ${SYS}/fs/fuse/*.[ch] \ ${SYS}/fs/msdosfs/*.[ch] \ - ${SYS}/fs/nandfs/*.[ch] \ ${SYS}/fs/nfs/*.[ch] \ ${SYS}/fs/nfsclient/*.[ch] \ ${SYS}/fs/nfsserver/*.[ch] \ @@ -82,7 +81,6 @@ COMMDIR2= ${SYS}/dev/alc \ ${SYS}/fs/fifofs \ ${SYS}/fs/fuse \ ${SYS}/fs/msdosfs \ - ${SYS}/fs/nandfs \ ${SYS}/fs/nfs \ ${SYS}/fs/nfsclient \ ${SYS}/fs/nfsserver \ From 4ae6e084f088f6a0b50cf2a78eb48dc44ea086c2 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Tue, 25 Jun 2019 17:00:53 +0000 Subject: [PATCH 104/165] Fix strsep_quote() on strings without quotes. For strings without quotes and escapes dstptr and srcptr are equal, so zeroing *dstptr before checking *srcptr is not a good idea. In practice it means that in -maproot=65534:65533 everything after the colon is lost. The problem was there since r293305, but before r346976 it was covered by improper strsep_quote() usage. PR: 238725 MFC after: 3 days Sponsored by: iXsystems, Inc. --- usr.sbin/mountd/mountd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr.sbin/mountd/mountd.c b/usr.sbin/mountd/mountd.c index 7d1685914742..79d6ac7f5693 100644 --- a/usr.sbin/mountd/mountd.c +++ b/usr.sbin/mountd/mountd.c @@ -385,8 +385,8 @@ strsep_quote(char **stringp, const char *delim) *dstptr++ = *srcptr++; } - *dstptr = 0; /* Terminate the string */ *stringp = (*srcptr == '\0') ? NULL : srcptr + 1; + *dstptr = 0; /* Terminate the string */ return (retval); } From e2edff41672437d201f7df6994ced3ed002d7bad Mon Sep 17 00:00:00 2001 From: Leandro Lupori Date: Tue, 25 Jun 2019 17:15:44 +0000 Subject: [PATCH 105/165] [PowerPC64] Don't mark module data as static Fixes panic when loading ipfw.ko and if_epair.ko built with modern compiler. Similar to arm64 and riscv, when using a modern compiler (!gcc4.2), code generated tries to access data in the wrong location, causing kernel panic (data storage interrupt trap) when loading if_epair and ipfw. Issue was reproduced with kernel/module compiled using gcc8 and clang8. It affects both ELFv1 and ELFv2 ABI environments. PR: 232387 Submitted by: alfredo.junior_eldorado.org.br Reported by: Mark Millard Reviewed by: jhibbits Differential Revision: https://reviews.freebsd.org/D20461 --- sys/net/vnet.h | 3 ++- sys/sys/pcpu.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/sys/net/vnet.h b/sys/net/vnet.h index b4168750e026..a8c9887ed506 100644 --- a/sys/net/vnet.h +++ b/sys/net/vnet.h @@ -273,7 +273,8 @@ extern struct sx vnet_sxlock; /* struct _hack is to stop this from being used with static data */ #define VNET_DEFINE(t, n) \ struct _hack; t VNET_NAME(n) __section(VNET_SETNAME) __used -#if defined(KLD_MODULE) && (defined(__aarch64__) || defined(__riscv)) +#if defined(KLD_MODULE) && (defined(__aarch64__) || defined(__riscv) \ + || defined(__powerpc64__)) /* * As with DPCPU_DEFINE_STATIC we are unable to mark this data as static * in modules on some architectures. diff --git a/sys/sys/pcpu.h b/sys/sys/pcpu.h index 38785cd26c94..3672d6070deb 100644 --- a/sys/sys/pcpu.h +++ b/sys/sys/pcpu.h @@ -85,7 +85,8 @@ extern uintptr_t dpcpu_off[]; /* struct _hack is to stop this from being used with the static keyword. */ #define DPCPU_DEFINE(t, n) \ struct _hack; t DPCPU_NAME(n) __section(DPCPU_SETNAME) __used -#if defined(KLD_MODULE) && (defined(__aarch64__) || defined(__riscv)) +#if defined(KLD_MODULE) && (defined(__aarch64__) || defined(__riscv) \ + || defined(__powerpc64__)) /* * On some architectures the compiler will use PC-relative load to * find the address of DPCPU data with the static keyword. We then From e70bb5c1a153cdd8b5e33652d67d2499e8c6da4e Mon Sep 17 00:00:00 2001 From: Doug Moore Date: Tue, 25 Jun 2019 17:27:37 +0000 Subject: [PATCH 106/165] Document the KERN_PROTECTION_FAILURE return value from vm_map_protect(). Reviewed by: alc (earlier version) Approved by: kib, markj (mentors) Differential Revision: https://reviews.freebsd.org/D20751 --- share/man/man9/vm_map_protect.9 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/share/man/man9/vm_map_protect.9 b/share/man/man9/vm_map_protect.9 index 3bd615c710ff..5e58074ebda7 100644 --- a/share/man/man9/vm_map_protect.9 +++ b/share/man/man9/vm_map_protect.9 @@ -96,6 +96,11 @@ would exceed for an entry within the range, .Dv KERN_PROTECTION_FAILURE is returned. +If a copy-on-write mapping is transitioned from read-only to +read-write, and too little swap space is available for backing the +copied pages, +.Dv KERN_RESOURCE_SHORTAGE +is returned. .Sh SEE ALSO .Xr vm_map 9 .Sh AUTHORS From b335f799acbcbaba861946f2b3b2e88bdc94d86b Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Tue, 25 Jun 2019 18:13:39 +0000 Subject: [PATCH 107/165] libbe(3): mount: the BE dataset is mounted at / Other parts of libbe(3) were fairly strict on the mountpoint property of the BE dataset, and be_mount was not much better. It was improved in r347027 to allow mountpoint=none for depth==0, but this bit was still sensitive to mountpoint != / and mountpoint != none. Given that other parts of libbe(3) no longer restrict the mountpoint property here, and the rest of the base system is generally OK and will assume that a BE is mounted at /, let's do the same. Reported by: ler MFC after: 3 days --- lib/libbe/be_access.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/libbe/be_access.c b/lib/libbe/be_access.c index d3e415bdbd42..eaa53473445d 100644 --- a/lib/libbe/be_access.c +++ b/lib/libbe/be_access.c @@ -96,7 +96,7 @@ be_mount_iter(zfs_handle_t *zfs_hdl, void *data) NULL, NULL, 0, 1)) return (1); - if (strcmp("none", zfs_mnt) == 0) { + if (strcmp("none", zfs_mnt) == 0 || info->depth == 0) { /* * mountpoint=none; we'll mount it at info->mountpoint assuming * we're at the root. If we're not at the root, we're likely From 419110374a63bdf1b3b7ad0acb3f7206d0d67796 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Tue, 25 Jun 2019 18:35:23 +0000 Subject: [PATCH 108/165] Avoid extra taskq_dispatch() calls by DMU. DMU sync code calls taskq_dispatch() for each sublist of os_dirty_dnodes and os_synced_dnodes. Since the number of sublists by default is equal to number of CPUs, it will dispatch equal, potentially large, number of tasks, waking up many CPUs to handle them, even if only one or few of sublists actually have any work to do. This change adds check for empty sublists to avoid this. --- .../uts/common/fs/zfs/dmu_objset.c | 19 +++++++++++----- .../opensolaris/uts/common/fs/zfs/multilist.c | 22 +++++++++++++++++++ .../uts/common/fs/zfs/sys/multilist.h | 2 ++ 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c index 2e36e0e5eec1..71d9cd7b6f17 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c @@ -1334,6 +1334,8 @@ dmu_objset_sync(objset_t *os, zio_t *pio, dmu_tx_t *tx) zio_t *zio; list_t *list; dbuf_dirty_record_t *dr; + int num_sublists; + multilist_t *ml; blkptr_t *blkptr_copy = kmem_alloc(sizeof (*os->os_rootbp), KM_SLEEP); *blkptr_copy = *os->os_rootbp; @@ -1402,10 +1404,13 @@ dmu_objset_sync(objset_t *os, zio_t *pio, dmu_tx_t *tx) } } - for (int i = 0; - i < multilist_get_num_sublists(os->os_dirty_dnodes[txgoff]); i++) { + ml = os->os_dirty_dnodes[txgoff]; + num_sublists = multilist_get_num_sublists(ml); + for (int i = 0; i < num_sublists; i++) { + if (multilist_sublist_is_empty_idx(ml, i)) + continue; sync_dnodes_arg_t *sda = kmem_alloc(sizeof (*sda), KM_SLEEP); - sda->sda_list = os->os_dirty_dnodes[txgoff]; + sda->sda_list = ml; sda->sda_sublist_idx = i; sda->sda_tx = tx; (void) taskq_dispatch(dmu_objset_pool(os)->dp_sync_taskq, @@ -1619,6 +1624,8 @@ userquota_updates_task(void *arg) void dmu_objset_do_userquota_updates(objset_t *os, dmu_tx_t *tx) { + int num_sublists; + if (!dmu_objset_userused_enabled(os)) return; @@ -1632,8 +1639,10 @@ dmu_objset_do_userquota_updates(objset_t *os, dmu_tx_t *tx) DMU_OT_USERGROUP_USED, DMU_OT_NONE, 0, tx)); } - for (int i = 0; - i < multilist_get_num_sublists(os->os_synced_dnodes); i++) { + num_sublists = multilist_get_num_sublists(os->os_synced_dnodes); + for (int i = 0; i < num_sublists; i++) { + if (multilist_sublist_is_empty_idx(os->os_synced_dnodes, i)) + continue; userquota_updates_arg_t *uua = kmem_alloc(sizeof (*uua), KM_SLEEP); uua->uua_os = os; diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/multilist.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/multilist.c index b61d1358c8a8..f517454d3d6d 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/multilist.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/multilist.c @@ -360,6 +360,28 @@ multilist_sublist_remove(multilist_sublist_t *mls, void *obj) list_remove(&mls->mls_list, obj); } +int +multilist_sublist_is_empty(multilist_sublist_t *mls) +{ + ASSERT(MUTEX_HELD(&mls->mls_lock)); + return (list_is_empty(&mls->mls_list)); +} + +int +multilist_sublist_is_empty_idx(multilist_t *ml, unsigned int sublist_idx) +{ + multilist_sublist_t *mls; + int empty; + + ASSERT3U(sublist_idx, <, ml->ml_num_sublists); + mls = &ml->ml_sublists[sublist_idx]; + ASSERT(!MUTEX_HELD(&mls->mls_lock)); + mutex_enter(&mls->mls_lock); + empty = list_is_empty(&mls->mls_list); + mutex_exit(&mls->mls_lock); + return (empty); +} + void * multilist_sublist_head(multilist_sublist_t *mls) { diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/multilist.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/multilist.h index 7f386fb7c3be..a3b44e60eb97 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/multilist.h +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/multilist.h @@ -89,6 +89,8 @@ void multilist_sublist_insert_head(multilist_sublist_t *, void *); void multilist_sublist_insert_tail(multilist_sublist_t *, void *); void multilist_sublist_move_forward(multilist_sublist_t *mls, void *obj); void multilist_sublist_remove(multilist_sublist_t *, void *); +int multilist_sublist_is_empty(multilist_sublist_t *); +int multilist_sublist_is_empty_idx(multilist_t *, unsigned int); void *multilist_sublist_head(multilist_sublist_t *); void *multilist_sublist_tail(multilist_sublist_t *); From 3afb4dc28a5fb124127c1c1fc470fcba6213a24e Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Tue, 25 Jun 2019 18:47:40 +0000 Subject: [PATCH 109/165] libbe(3): restructure be_mount, skip canmount check for BE dataset Further cleanup after r349380; loader and kernel will both ignore canmount on the root dataset as well, so we should not be so strict about it when mounting it. be_mount is restructured to make it more clear that depth==0 is special, and to not try fetching these properties that we won't care about. MFC after: 3 days --- lib/libbe/be_access.c | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/lib/libbe/be_access.c b/lib/libbe/be_access.c index eaa53473445d..9c267bd2f9a6 100644 --- a/lib/libbe/be_access.c +++ b/lib/libbe/be_access.c @@ -89,25 +89,31 @@ be_mount_iter(zfs_handle_t *zfs_hdl, void *data) return (0); } - if (zfs_prop_get_int(zfs_hdl, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_OFF) - return (0); - - if (zfs_prop_get(zfs_hdl, ZFS_PROP_MOUNTPOINT, zfs_mnt, BE_MAXPATHLEN, - NULL, NULL, 0, 1)) - return (1); - - if (strcmp("none", zfs_mnt) == 0 || info->depth == 0) { - /* - * mountpoint=none; we'll mount it at info->mountpoint assuming - * we're at the root. If we're not at the root, we're likely - * at some intermediate dataset (e.g. zroot/var) that will have - * children that may need to be mounted. - */ - if (info->depth > 0) - goto skipmount; - + /* + * canmount and mountpoint are both ignored for the BE dataset, because + * the rest of the system (kernel and loader) will effectively do the + * same. + */ + if (info->depth == 0) { snprintf(tmp, BE_MAXPATHLEN, "%s", info->mountpoint); } else { + if (zfs_prop_get_int(zfs_hdl, ZFS_PROP_CANMOUNT) == + ZFS_CANMOUNT_OFF) + return (0); + + if (zfs_prop_get(zfs_hdl, ZFS_PROP_MOUNTPOINT, zfs_mnt, + BE_MAXPATHLEN, NULL, NULL, 0, 1)) + return (1); + + /* + * We've encountered mountpoint=none at some intermediate + * dataset (e.g. zroot/var) that will have children that may + * need to be mounted. Skip mounting it, but iterate through + * the children. + */ + if (strcmp("none", zfs_mnt) == 0) + goto skipmount; + mountpoint = be_mountpoint_augmented(info->lbh, zfs_mnt); snprintf(tmp, BE_MAXPATHLEN, "%s%s", info->mountpoint, mountpoint); From 9349d37845789b1f0aec2dd46659037309a709ad Mon Sep 17 00:00:00 2001 From: Ed Maste Date: Tue, 25 Jun 2019 19:06:43 +0000 Subject: [PATCH 110/165] bhyve: avoid theoretical stack buffer overflow from integer overflow Use the proper size_t type to match strlen's return type. This is not exploitable in practice as this parses command line arguments, which are limited to well below 2^31 bytes. This is a minimal change to address the reported issue; hda_parse_config and the rest of this file will benefit from further review. Reported by: Fakhri Zulkifli Reviewed by: jhb, markj MFC after: 3 days Sponsored by: The FreeBSD Foundation --- usr.sbin/bhyve/pci_hda.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/usr.sbin/bhyve/pci_hda.c b/usr.sbin/bhyve/pci_hda.c index acd6977cea02..ace88274ac91 100644 --- a/usr.sbin/bhyve/pci_hda.c +++ b/usr.sbin/bhyve/pci_hda.c @@ -324,15 +324,14 @@ hda_parse_config(const char *opts, const char *key, char *val) char buf[64]; char *s = buf; char *tmp = NULL; - int len; + size_t len; int i; if (!opts) return (0); len = strlen(opts); - - if (len >= 64) { + if (len >= sizeof(buf)) { DPRINTF("Opts too big\n"); return (0); } From 4f53d57e8c851899c03bdc7e884619b84a7b2065 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Tue, 25 Jun 2019 19:44:22 +0000 Subject: [PATCH 111/165] fcntl: style changes to r349248 Reported by: bde MFC after: 2 weeks MFC-With: 349248 Sponsored by: The FreeBSD Foundation --- sys/kern/vfs_vnops.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index b31ec81bd1dd..aba141c26249 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -499,10 +499,8 @@ sequential_heuristic(struct uio *uio, struct file *fp) * closely related to the best I/O size for real disks than * to any block size used by software. */ - fp->f_seqcount += MIN(IO_SEQMAX, + fp->f_seqcount += lmin(IO_SEQMAX, howmany(uio->uio_resid, 16384)); - if (fp->f_seqcount > IO_SEQMAX) - fp->f_seqcount = IO_SEQMAX; return (fp->f_seqcount << IO_SEQSHIFT); } From eb2b51ffda85293ed70711111fe3db366ae68b5d Mon Sep 17 00:00:00 2001 From: Julian Elischer Date: Tue, 25 Jun 2019 19:55:42 +0000 Subject: [PATCH 112/165] Fix annoying whitespace issue. NO real change --- sys/sys/pmckern.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/sys/pmckern.h b/sys/sys/pmckern.h index e892d658a1ca..5b337f8d76df 100644 --- a/sys/sys/pmckern.h +++ b/sys/sys/pmckern.h @@ -226,7 +226,7 @@ do { \ */ #define PMC_CALL_HOOK_UNLOCKED(t, cmd, arg) \ do { \ - if (pmc_hook != NULL) \ + if (pmc_hook != NULL) \ (pmc_hook)((t), (cmd), (arg)); \ } while (0) From 52499d1739956d2eea31741f3f1537794dbd1a03 Mon Sep 17 00:00:00 2001 From: Doug Moore Date: Tue, 25 Jun 2019 20:25:16 +0000 Subject: [PATCH 113/165] Eliminate some uses of the prev and next fields of vm_map_entry_t. Since the only caller to vm_map_splay is vm_map_lookup_entry, move the implementation of vm_map_splay into vm_map_lookup_helper, called by vm_map_lookup_entry. vm_map_lookup_entry returns the greatest entry less than or equal to a given address, but in many cases the caller wants the least entry greater than or equal to the address and uses the next pointer to get to it. Provide an alternative interface to lookup, vm_map_lookup_entry_ge, to provide the latter behavior, and let callers use one or the other rather than having them use the next pointer after a lookup miss to get what they really want. In vm_map_growstack, the caller wants an entry that includes a given address, and either the preceding or next entry depending on the value of eflags in the first entry. Incorporate that behavior into vm_map_lookup_helper, the function that implements all of these lookups. Eliminate some temporary variables used with vm_map_lookup_entry, but inessential. Reviewed by: markj (earlier version) Approved by: kib (mentor) Differential Revision: https://reviews.freebsd.org/D20664 --- sys/vm/vm_map.c | 328 ++++++++++++++++++++++-------------------------- sys/vm/vm_map.h | 2 +- 2 files changed, 153 insertions(+), 177 deletions(-) diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c index 38afe6308cc8..4cf152a85170 100644 --- a/sys/vm/vm_map.c +++ b/sys/vm/vm_map.c @@ -983,6 +983,17 @@ vm_map_entry_max_free_right(vm_map_entry_t root, vm_map_entry_t right_ancestor) root->right->max_free : right_ancestor->start - root->end); } +/* + * vm_map_splay_split, vm_map_splay_merge: + * + * The Sleator and Tarjan top-down splay algorithm with the following + * variation. Max_free must be computed bottom-up, so on the downward + * pass (vm_map_splay_split), maintain the left and right spines in + * reverse order, and ensure that the max_free values for those nodes + * store the values of their descendents not on the search path. Later, + * make a second pass up each side (vm_map_splay_merge) to fix the + * pointers and compute max_free. The time bound is O(log n) amortized. + */ #define SPLAY_LEFT_STEP(root, y, rlist, test) do { \ vm_size_t max_free; \ \ @@ -1165,56 +1176,6 @@ vm_map_splay_merge(vm_map_t map, vm_map_entry_t root, map->root = root; } -/* - * vm_map_splay: - * - * The Sleator and Tarjan top-down splay algorithm with the - * following variation. Max_free must be computed bottom-up, so - * on the downward pass, maintain the left and right spines in - * reverse order. Then, make a second pass up each side to fix - * the pointers and compute max_free. The time bound is O(log n) - * amortized. - * - * The new root is the vm_map_entry containing "addr", or else an - * adjacent entry (lower if possible) if addr is not in the tree. - * - * The map must be locked, and leaves it so. - * - * Returns: the new root. - */ -static vm_map_entry_t -vm_map_splay(vm_map_t map, vm_offset_t addr) -{ - vm_map_entry_t llist, rlist, root; - - root = vm_map_splay_split(map, addr, 0, &llist, &rlist); - if (root != NULL) { - /* do nothing */ - } else if (llist != &map->header) { - /* - * Recover the greatest node in the left - * subtree and make it the root. - */ - root = llist; - llist = root->right; - root->right = NULL; - } else if (rlist != &map->header) { - /* - * Recover the least node in the right - * subtree and make it the root. - */ - root = rlist; - rlist = root->left; - root->left = NULL; - } else { - /* There is no root. */ - return (NULL); - } - vm_map_splay_merge(map, root, llist, rlist); - VM_MAP_ASSERT_CONSISTENT(map); - return (root); -} - /* * vm_map_entry_{un,}link: * @@ -1331,79 +1292,131 @@ vm_map_entry_resize(vm_map_t map, vm_map_entry_t entry, vm_size_t grow_amount) } /* - * vm_map_lookup_entry: [ internal use only ] + * vm_map_lookup_helper: [ internal use only ] * - * Finds the map entry containing (or - * immediately preceding) the specified address - * in the given map; the entry is returned - * in the "entry" parameter. The boolean - * result indicates whether the address is - * actually contained in the map. + * Finds the map entry containing (or adjacent to) the specified address + * in the given map; the entry is returned in the "entry" parameter. The + * boolean result indicates whether the address is actually contained in + * the map. If the address is not contained in the map, parameter lesseq + * determines whether the entry provided is before or after the address. + * If the address is contained in the map, parameter nbr, if not NULL, is + * where the next or previous entry is saved, depending on the value of + * eflags in the found entry. */ -boolean_t -vm_map_lookup_entry( - vm_map_t map, - vm_offset_t address, - vm_map_entry_t *entry) /* OUT */ +static bool +vm_map_lookup_helper(vm_map_t map, vm_offset_t addr, bool lesseq, + vm_map_entry_t *entry, vm_map_entry_t *nbr) /* OUT */ { - vm_map_entry_t cur, lbound; - boolean_t locked; + vm_map_entry_t llist, rlist, root; + bool locked, found; /* * If the map is empty, then the map entry immediately preceding - * "address" is the map's header. + * "addr" is the map's header. */ - cur = map->root; - if (cur == NULL) { + root = map->root; + if (root == NULL) { *entry = &map->header; - return (FALSE); - } - if (address >= cur->start && cur->end > address) { - *entry = cur; - return (TRUE); + return (false); } if ((locked = vm_map_locked(map)) || sx_try_upgrade(&map->lock)) { + /* * Splay requires a write lock on the map. However, it only * restructures the binary search tree; it does not otherwise * change the map. Thus, the map's timestamp need not change * on a temporary upgrade. */ - cur = vm_map_splay(map, address); + root = vm_map_splay_split(map, addr, 0, &llist, &rlist); + found = root != NULL; + *entry = root; + if (root != NULL) { + if (nbr == NULL) + ; /* Ignore. */ + else if ((root->eflags & MAP_ENTRY_STACK_GAP_DN) != 0) { + vm_map_splay_findnext(root, &rlist); + *nbr = rlist; + } else { + vm_map_splay_findprev(root, &llist); + *nbr = llist; + } + } else if (llist != &map->header) { + /* + * Recover the greatest node in the left + * subtree and make it the root. + */ + *entry = lesseq ? llist : rlist; + root = llist; + llist = root->right; + root->right = NULL; + } else { + /* + * Recover the least node in the right + * subtree and make it the root. + */ + *entry = lesseq ? llist : rlist; + root = rlist; + rlist = root->left; + root->left = NULL; + } + vm_map_splay_merge(map, root, llist, rlist); + VM_MAP_ASSERT_CONSISTENT(map); if (!locked) sx_downgrade(&map->lock); - - /* - * If "address" is contained within a map entry, the new root - * is that map entry. Otherwise, the new root is a map entry - * immediately before or after "address". - */ - if (address < cur->start) { - *entry = &map->header; - return (FALSE); - } - *entry = cur; - return (address < cur->end); + return (found); } /* * Since the map is only locked for read access, perform a - * standard binary search tree lookup for "address". + * standard binary search tree lookup for "addr". */ - lbound = &map->header; + llist = rlist = &map->header; do { - if (address < cur->start) { - cur = cur->left; - } else if (cur->end <= address) { - lbound = cur; - cur = cur->right; + if (addr < root->start) { + rlist = root; + root = root->left; + } else if (root->end <= addr) { + llist = root; + root = root->right; } else { - *entry = cur; - return (TRUE); + *entry = root; + if (nbr == NULL); + else if ((root->eflags & MAP_ENTRY_STACK_GAP_DN) != 0) { + /* Make nbr the successor to root. */ + if (root->right != NULL) { + rlist = root->right; + while (rlist->left != NULL) + rlist = rlist->left; + } + *nbr = rlist; + } else { + /* Make nbr the predecessor to root. */ + if (root->left != NULL) { + llist = root->left; + while (llist->right != NULL) + llist = llist->right; + } + *nbr = llist; + } + return (true); } - } while (cur != NULL); - *entry = lbound; - return (FALSE); + } while (root != NULL); + *entry = lesseq ? llist : rlist; + return (false); +} + +bool +vm_map_lookup_entry(vm_map_t map, vm_offset_t addr, + vm_map_entry_t *entry) /* OUT */ +{ + return (vm_map_lookup_helper(map, addr, true, entry, NULL)); +} + +static bool +vm_map_lookup_entry_ge(vm_map_t map, vm_offset_t addr, + vm_map_entry_t *entry) /* OUT */ +{ + return (vm_map_lookup_helper(map, addr, false, entry, NULL)); } /* @@ -1422,7 +1435,7 @@ int vm_map_insert(vm_map_t map, vm_object_t object, vm_ooffset_t offset, vm_offset_t start, vm_offset_t end, vm_prot_t prot, vm_prot_t max, int cow) { - vm_map_entry_t new_entry, prev_entry, temp_entry; + vm_map_entry_t new_entry, prev_entry; struct ucred *cred; vm_eflags_t protoeflags; vm_inherit_t inheritance; @@ -1447,11 +1460,9 @@ vm_map_insert(vm_map_t map, vm_object_t object, vm_ooffset_t offset, * Find the entry prior to the proposed starting address; if it's part * of an existing entry, this range is bogus. */ - if (vm_map_lookup_entry(map, start, &temp_entry)) + if (vm_map_lookup_entry(map, start, &prev_entry)) return (KERN_NO_SPACE); - prev_entry = temp_entry; - /* * Assert that the next entry doesn't overlap the end point. */ @@ -2314,10 +2325,8 @@ vm_map_submap( VM_MAP_RANGE_CHECK(map, start, end); - if (vm_map_lookup_entry(map, start, &entry)) { + if (vm_map_lookup_entry_ge(map, start, &entry)) vm_map_clip_start(map, entry, start); - } else - entry = entry->next; vm_map_clip_end(map, entry, end); @@ -2472,8 +2481,7 @@ vm_map_protect(vm_map_t map, vm_offset_t start, vm_offset_t end, VM_MAP_RANGE_CHECK(map, start, end); - if (!vm_map_lookup_entry(map, start, &entry)) - entry = entry->next; + vm_map_lookup_entry_ge(map, start, &entry); /* * Make a first pass to check for protection violations. @@ -2663,11 +2671,9 @@ vm_map_madvise( */ VM_MAP_RANGE_CHECK(map, start, end); - if (vm_map_lookup_entry(map, start, &entry)) { + if (vm_map_lookup_entry_ge(map, start, &entry)) { if (modify_map) vm_map_clip_start(map, entry, start); - } else { - entry = entry->next; } if (modify_map) { @@ -2799,7 +2805,6 @@ vm_map_inherit(vm_map_t map, vm_offset_t start, vm_offset_t end, vm_inherit_t new_inheritance) { vm_map_entry_t entry; - vm_map_entry_t temp_entry; switch (new_inheritance) { case VM_INHERIT_NONE: @@ -2814,11 +2819,8 @@ vm_map_inherit(vm_map_t map, vm_offset_t start, vm_offset_t end, return (KERN_SUCCESS); vm_map_lock(map); VM_MAP_RANGE_CHECK(map, start, end); - if (vm_map_lookup_entry(map, start, &temp_entry)) { - entry = temp_entry; + if (vm_map_lookup_entry_ge(map, start, &entry)) vm_map_clip_start(map, entry, start); - } else - entry = temp_entry->next; while (entry->start < end) { vm_map_clip_end(map, entry, end); if ((entry->eflags & MAP_ENTRY_GUARD) == 0 || @@ -2851,10 +2853,8 @@ vm_map_unwire(vm_map_t map, vm_offset_t start, vm_offset_t end, user_unwire = (flags & VM_MAP_WIRE_USER) ? TRUE : FALSE; vm_map_lock(map); VM_MAP_RANGE_CHECK(map, start, end); - if (!vm_map_lookup_entry(map, start, &first_entry)) { - if (flags & VM_MAP_WIRE_HOLESOK) - first_entry = first_entry->next; - else { + if (!vm_map_lookup_entry_ge(map, start, &first_entry)) { + if ((flags & VM_MAP_WIRE_HOLESOK) == 0) { vm_map_unlock(map); return (KERN_INVALID_ADDRESS); } @@ -2882,11 +2882,9 @@ vm_map_unwire(vm_map_t map, vm_offset_t start, vm_offset_t end, * Specifically, the entry may have been * clipped, merged, or deleted. */ - if (!vm_map_lookup_entry(map, saved_start, + if (!vm_map_lookup_entry_ge(map, saved_start, &tmp_entry)) { - if (flags & VM_MAP_WIRE_HOLESOK) - tmp_entry = tmp_entry->next; - else { + if ((flags & VM_MAP_WIRE_HOLESOK) == 0) { if (saved_start == start) { /* * First_entry has been deleted. @@ -2944,11 +2942,9 @@ vm_map_unwire(vm_map_t map, vm_offset_t start, vm_offset_t end, done: need_wakeup = FALSE; if (first_entry == NULL) { - result = vm_map_lookup_entry(map, start, &first_entry); - if (!result && (flags & VM_MAP_WIRE_HOLESOK)) - first_entry = first_entry->next; - else - KASSERT(result, ("vm_map_unwire: lookup failed")); + result = vm_map_lookup_entry_ge(map, start, &first_entry); + KASSERT(result || (flags & VM_MAP_WIRE_HOLESOK) != 0, + ("vm_map_unwire: lookup failed")); } for (entry = first_entry; entry->start < end; entry = entry->next) { /* @@ -3090,10 +3086,8 @@ vm_map_wire_locked(vm_map_t map, vm_offset_t start, vm_offset_t end, int flags) prot |= VM_PROT_WRITE; user_wire = (flags & VM_MAP_WIRE_USER) ? TRUE : FALSE; VM_MAP_RANGE_CHECK(map, start, end); - if (!vm_map_lookup_entry(map, start, &first_entry)) { - if (flags & VM_MAP_WIRE_HOLESOK) - first_entry = first_entry->next; - else + if (!vm_map_lookup_entry_ge(map, start, &first_entry)) { + if ((flags & VM_MAP_WIRE_HOLESOK) == 0) return (KERN_INVALID_ADDRESS); } last_timestamp = map->timestamp; @@ -3119,11 +3113,9 @@ vm_map_wire_locked(vm_map_t map, vm_offset_t start, vm_offset_t end, int flags) * Specifically, the entry may have been * clipped, merged, or deleted. */ - if (!vm_map_lookup_entry(map, saved_start, + if (!vm_map_lookup_entry_ge(map, saved_start, &tmp_entry)) { - if (flags & VM_MAP_WIRE_HOLESOK) - tmp_entry = tmp_entry->next; - else { + if ((flags & VM_MAP_WIRE_HOLESOK) == 0) { if (saved_start == start) { /* * first_entry has been deleted. @@ -3256,11 +3248,9 @@ vm_map_wire_locked(vm_map_t map, vm_offset_t start, vm_offset_t end, int flags) done: need_wakeup = FALSE; if (first_entry == NULL) { - result = vm_map_lookup_entry(map, start, &first_entry); - if (!result && (flags & VM_MAP_WIRE_HOLESOK)) - first_entry = first_entry->next; - else - KASSERT(result, ("vm_map_wire: lookup failed")); + result = vm_map_lookup_entry_ge(map, start, &first_entry); + KASSERT(result || (flags & VM_MAP_WIRE_HOLESOK) != 0, + ("vm_map_wire: lookup failed")); } for (entry = first_entry; entry->start < end; entry = entry->next) { /* @@ -3361,7 +3351,8 @@ vm_map_sync( if (!vm_map_lookup_entry(map, start, &entry)) { vm_map_unlock_read(map); return (KERN_INVALID_ADDRESS); - } else if (start == end) { + } + if (start == end) { start = entry->start; end = entry->end; } @@ -3416,9 +3407,10 @@ vm_map_sync( start += size; vm_object_deallocate(object); vm_map_lock_read(map); - if (last_timestamp == map->timestamp || - !vm_map_lookup_entry(map, start, ¤t)) + if (last_timestamp == map->timestamp) current = current->next; + else + vm_map_lookup_entry_ge(map, start, ¤t); } vm_map_unlock_read(map); @@ -3551,7 +3543,6 @@ int vm_map_delete(vm_map_t map, vm_offset_t start, vm_offset_t end) { vm_map_entry_t entry; - vm_map_entry_t first_entry; VM_MAP_ASSERT_LOCKED(map); if (start == end) @@ -3560,12 +3551,8 @@ vm_map_delete(vm_map_t map, vm_offset_t start, vm_offset_t end) /* * Find the start of the region, and clip it */ - if (!vm_map_lookup_entry(map, start, &first_entry)) - entry = first_entry->next; - else { - entry = first_entry; + if (vm_map_lookup_entry_ge(map, start, &entry)) vm_map_clip_start(map, entry, start); - } /* * Step through all entries in this region @@ -3583,29 +3570,22 @@ vm_map_delete(vm_map_t map, vm_offset_t start, vm_offset_t end) vm_map_entry_system_wired_count(entry) != 0)) { unsigned int last_timestamp; vm_offset_t saved_start; - vm_map_entry_t tmp_entry; saved_start = entry->start; entry->eflags |= MAP_ENTRY_NEEDS_WAKEUP; last_timestamp = map->timestamp; (void) vm_map_unlock_and_wait(map, 0); vm_map_lock(map); - if (last_timestamp + 1 != map->timestamp) { - /* - * Look again for the entry because the map was - * modified while it was unlocked. - * Specifically, the entry may have been - * clipped, merged, or deleted. - */ - if (!vm_map_lookup_entry(map, saved_start, - &tmp_entry)) - entry = tmp_entry->next; - else { - entry = tmp_entry; - vm_map_clip_start(map, entry, - saved_start); - } - } + if (last_timestamp + 1 == map->timestamp) + continue; + + /* + * Look again for the entry because the map was + * modified while it was unlocked. Specifically, the + * entry may have been clipped, merged, or deleted. + */ + if (vm_map_lookup_entry_ge(map, saved_start, &entry)) + vm_map_clip_start(map, entry, saved_start); continue; } vm_map_clip_end(map, entry, end); @@ -3680,11 +3660,9 @@ vm_map_check_protection(vm_map_t map, vm_offset_t start, vm_offset_t end, vm_prot_t protection) { vm_map_entry_t entry; - vm_map_entry_t tmp_entry; - if (!vm_map_lookup_entry(map, start, &tmp_entry)) + if (!vm_map_lookup_entry(map, start, &entry)) return (FALSE); - entry = tmp_entry; while (start < end) { /* @@ -4120,7 +4098,7 @@ static int vm_map_stack_locked(vm_map_t map, vm_offset_t addrbos, vm_size_t max_ssize, vm_size_t growsize, vm_prot_t prot, vm_prot_t max, int cow) { - vm_map_entry_t new_entry, prev_entry; + vm_map_entry_t new_entry; vm_offset_t bot, gap_bot, gap_top, top; vm_size_t init_ssize, sgp; int orient, rv; @@ -4148,13 +4126,13 @@ vm_map_stack_locked(vm_map_t map, vm_offset_t addrbos, vm_size_t max_ssize, init_ssize = max_ssize - sgp; /* If addr is already mapped, no go */ - if (vm_map_lookup_entry(map, addrbos, &prev_entry)) + if (vm_map_lookup_entry_ge(map, addrbos, &new_entry)) return (KERN_NO_SPACE); /* * If we can't accommodate max_ssize in the current mapping, no go. */ - if (prev_entry->next->start < addrbos + max_ssize) + if (new_entry->start < addrbos + max_ssize) return (KERN_NO_SPACE); /* @@ -4181,7 +4159,6 @@ vm_map_stack_locked(vm_map_t map, vm_offset_t addrbos, vm_size_t max_ssize, rv = vm_map_insert(map, NULL, 0, bot, top, prot, max, cow); if (rv != KERN_SUCCESS) return (rv); - new_entry = prev_entry->next; KASSERT(new_entry->end == top || new_entry->start == bot, ("Bad entry start/end for new stack entry")); KASSERT((orient & MAP_STACK_GROWS_DOWN) == 0 || @@ -4240,19 +4217,18 @@ vm_map_growstack(vm_map_t map, vm_offset_t addr, vm_map_entry_t gap_entry) vmemlim = lim_cur(curthread, RLIMIT_VMEM); retry: /* If addr is not in a hole for a stack grow area, no need to grow. */ - if (gap_entry == NULL && !vm_map_lookup_entry(map, addr, &gap_entry)) + if (gap_entry == NULL && + !vm_map_lookup_helper(map, addr, true, &gap_entry, &stack_entry)) return (KERN_FAILURE); if ((gap_entry->eflags & MAP_ENTRY_GUARD) == 0) return (KERN_SUCCESS); if ((gap_entry->eflags & MAP_ENTRY_STACK_GAP_DN) != 0) { - stack_entry = gap_entry->next; if ((stack_entry->eflags & MAP_ENTRY_GROWS_DOWN) == 0 || stack_entry->start != gap_entry->end) return (KERN_FAILURE); grow_amount = round_page(stack_entry->start - addr); grow_down = true; } else if ((gap_entry->eflags & MAP_ENTRY_STACK_GAP_UP) != 0) { - stack_entry = gap_entry->prev; if ((stack_entry->eflags & MAP_ENTRY_GROWS_UP) == 0 || stack_entry->end != gap_entry->start) return (KERN_FAILURE); diff --git a/sys/vm/vm_map.h b/sys/vm/vm_map.h index 3b870baac759..570ea701c1e6 100644 --- a/sys/vm/vm_map.h +++ b/sys/vm/vm_map.h @@ -415,7 +415,7 @@ int vm_map_lookup (vm_map_t *, vm_offset_t, vm_prot_t, vm_map_entry_t *, vm_obje int vm_map_lookup_locked(vm_map_t *, vm_offset_t, vm_prot_t, vm_map_entry_t *, vm_object_t *, vm_pindex_t *, vm_prot_t *, boolean_t *); void vm_map_lookup_done (vm_map_t, vm_map_entry_t); -boolean_t vm_map_lookup_entry (vm_map_t, vm_offset_t, vm_map_entry_t *); +bool vm_map_lookup_entry(vm_map_t, vm_offset_t, vm_map_entry_t *); int vm_map_protect (vm_map_t, vm_offset_t, vm_offset_t, vm_prot_t, boolean_t); int vm_map_remove (vm_map_t, vm_offset_t, vm_offset_t); void vm_map_simplify_entry(vm_map_t map, vm_map_entry_t entry); From 519346ce8c66a496d011a680426571e7c5957dc0 Mon Sep 17 00:00:00 2001 From: Rebecca Cran Date: Tue, 25 Jun 2019 21:26:57 +0000 Subject: [PATCH 114/165] Disconnect EFI HTTP support The EFI HTTP code has been causing boot failures for people, so disable it while a fix is being worked on. --- stand/efi/loader/conf.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/stand/efi/loader/conf.c b/stand/efi/loader/conf.c index d08ded39b4f2..2e4d35f88a6c 100644 --- a/stand/efi/loader/conf.c +++ b/stand/efi/loader/conf.c @@ -39,7 +39,6 @@ struct devsw *devsw[] = { &efipart_fddev, &efipart_cddev, &efipart_hddev, - &efihttp_dev, /* ordering with efinet_dev matters */ &efinet_dev, &vdisk_dev, #ifdef EFI_ZFS_BOOT @@ -55,7 +54,6 @@ struct fs_ops *file_system[] = { &dosfs_fsops, &ufs_fsops, &cd9660_fsops, - &efihttp_fsops, &tftp_fsops, &nfs_fsops, &gzipfs_fsops, From 7f39a7e4923647e7ef51d89d39a02ca3d7c7ba7b Mon Sep 17 00:00:00 2001 From: Cy Schubert Date: Wed, 26 Jun 2019 00:53:43 +0000 Subject: [PATCH 115/165] Prompted by r349366, ipfilter is also does not conform to RFC 3128 by dropping TCP fragments with offset = 1. In addition to dropping these fragments, add a DTrace probe to allow for more detailed monitoring and diagnosis if required. MFC after: 1 week --- sys/contrib/ipfilter/netinet/fil.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sys/contrib/ipfilter/netinet/fil.c b/sys/contrib/ipfilter/netinet/fil.c index a0d008dbd2d7..bbfb2287337b 100644 --- a/sys/contrib/ipfilter/netinet/fil.c +++ b/sys/contrib/ipfilter/netinet/fil.c @@ -1723,6 +1723,10 @@ ipf_pr_ipv4hdr(fin) * calculate the byte offset that it represents. */ off &= IP_MF|IP_OFFMASK; + if (off == 1 && p == IPPROTO_TCP) { + fin->fin_flx |= FI_SHORT; /* RFC 3128 */ + DT1(ipf_fi_tcp_frag_off_1, fr_info_t *, fin); + } if (off != 0) { int morefrag = off & IP_MF; From 2637412cbc784548c6369c2de612359645907f47 Mon Sep 17 00:00:00 2001 From: Cy Schubert Date: Wed, 26 Jun 2019 00:53:46 +0000 Subject: [PATCH 116/165] Remove a tautological compare for offset != 0. MFC after: 1 week --- sys/contrib/ipfilter/netinet/fil.c | 34 ++++++++++++++---------------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/sys/contrib/ipfilter/netinet/fil.c b/sys/contrib/ipfilter/netinet/fil.c index bbfb2287337b..de2dd8866b23 100644 --- a/sys/contrib/ipfilter/netinet/fil.c +++ b/sys/contrib/ipfilter/netinet/fil.c @@ -1732,24 +1732,22 @@ ipf_pr_ipv4hdr(fin) fi->fi_flx |= FI_FRAG; off &= IP_OFFMASK; - if (off != 0) { - fin->fin_flx |= FI_FRAGBODY; - off <<= 3; - if ((off + fin->fin_dlen > 65535) || - (fin->fin_dlen == 0) || - ((morefrag != 0) && ((fin->fin_dlen & 7) != 0))) { - /* - * The length of the packet, starting at its - * offset cannot exceed 65535 (0xffff) as the - * length of an IP packet is only 16 bits. - * - * Any fragment that isn't the last fragment - * must have a length greater than 0 and it - * must be an even multiple of 8. - */ - fi->fi_flx |= FI_BAD; - DT1(ipf_fi_bad_fragbody_gt_65535, fr_info_t *, fin); - } + fin->fin_flx |= FI_FRAGBODY; + off <<= 3; + if ((off + fin->fin_dlen > 65535) || + (fin->fin_dlen == 0) || + ((morefrag != 0) && ((fin->fin_dlen & 7) != 0))) { + /* + * The length of the packet, starting at its + * offset cannot exceed 65535 (0xffff) as the + * length of an IP packet is only 16 bits. + * + * Any fragment that isn't the last fragment + * must have a length greater than 0 and it + * must be an even multiple of 8. + */ + fi->fi_flx |= FI_BAD; + DT1(ipf_fi_bad_fragbody_gt_65535, fr_info_t *, fin); } } fin->fin_off = off; From 65f07d9976c0e36765bea5ecb54a17baebf0d671 Mon Sep 17 00:00:00 2001 From: Cy Schubert Date: Wed, 26 Jun 2019 00:53:49 +0000 Subject: [PATCH 117/165] While working on PR/238796 I discovered an unused variable in frdest, the next hop structure. It is likely this contributes to PR/238796 though other factors remain to be investigated. PR: 238796 MFC after: 1 week --- sys/contrib/ipfilter/netinet/fil.c | 4 ---- sys/contrib/ipfilter/netinet/ip_fil.h | 1 - 2 files changed, 5 deletions(-) diff --git a/sys/contrib/ipfilter/netinet/fil.c b/sys/contrib/ipfilter/netinet/fil.c index de2dd8866b23..1d142165c341 100644 --- a/sys/contrib/ipfilter/netinet/fil.c +++ b/sys/contrib/ipfilter/netinet/fil.c @@ -7474,10 +7474,6 @@ ipf_resolvedest(softc, base, fdp, v) } fdp->fd_ptr = ifp; - if ((ifp != NULL) && (ifp != (void *)-1)) { - fdp->fd_local = ipf_deliverlocal(softc, v, ifp, &fdp->fd_ip6); - } - return errval; } diff --git a/sys/contrib/ipfilter/netinet/ip_fil.h b/sys/contrib/ipfilter/netinet/ip_fil.h index f3185c6458d7..032cf0dea853 100644 --- a/sys/contrib/ipfilter/netinet/ip_fil.h +++ b/sys/contrib/ipfilter/netinet/ip_fil.h @@ -560,7 +560,6 @@ typedef struct frdest { addrfamily_t fd_addr; fr_dtypes_t fd_type; int fd_name; - int fd_local; } frdest_t; #define fd_ip6 fd_addr.adf_addr From 088c26aee87fb3b994fea2758af66677331a4c3f Mon Sep 17 00:00:00 2001 From: Justin Hibbits Date: Wed, 26 Jun 2019 01:14:39 +0000 Subject: [PATCH 118/165] powerpc/booke: Handle misaligned floating point loads/stores as on AIM Misaligned floating point loads and stores are already handled for AIM, but use the DSISR to obtain the necessary data. Book-E does not have the DSISR, so these fixups are not performed, leading to a SIGBUS on misaligned FP loads or stores. Obtain the necessary data on the Book-E side, similar to how is done for SPE. MFC after: 1 week --- sys/powerpc/include/trap.h | 2 +- sys/powerpc/powerpc/trap.c | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/sys/powerpc/include/trap.h b/sys/powerpc/include/trap.h index 5017a7535d29..56b789c248ef 100644 --- a/sys/powerpc/include/trap.h +++ b/sys/powerpc/include/trap.h @@ -130,7 +130,7 @@ /* Macros to extract register information */ #define EXC_ALI_RST(dsisr) ((dsisr >> 5) & 0x1f) /* source or target */ #define EXC_ALI_RA(dsisr) (dsisr & 0x1f) -#define EXC_ALI_SPE_REG(instr) ((instr >> 21) & 0x1f) +#define EXC_ALI_INST_RST(instr) ((instr >> 21) & 0x1f) /* * SRR1 bits for program exception traps. These identify what caused diff --git a/sys/powerpc/powerpc/trap.c b/sys/powerpc/powerpc/trap.c index 0200c7bbd142..3cc04fbc75ad 100644 --- a/sys/powerpc/powerpc/trap.c +++ b/sys/powerpc/powerpc/trap.c @@ -788,7 +788,7 @@ static int fix_unaligned(struct thread *td, struct trapframe *frame) { struct thread *fputhread; -#ifdef __SPE__ +#ifdef BOOKE uint32_t inst; #endif int indicator, reg; @@ -799,7 +799,7 @@ fix_unaligned(struct thread *td, struct trapframe *frame) if (indicator & ESR_SPE) { if (copyin((void *)frame->srr0, &inst, sizeof(inst)) != 0) return (-1); - reg = EXC_ALI_SPE_REG(inst); + reg = EXC_ALI_INST_RST(inst); fpr = (double *)td->td_pcb->pcb_vec.vr[reg]; fputhread = PCPU_GET(vecthread); @@ -828,13 +828,23 @@ fix_unaligned(struct thread *td, struct trapframe *frame) } return (0); } +#else +#ifdef BOOKE + indicator = (frame->cpu.booke.esr & ESR_ST) ? EXC_ALI_STFD : EXC_ALI_LFD; #else indicator = EXC_ALI_OPCODE_INDICATOR(frame->cpu.aim.dsisr); +#endif switch (indicator) { case EXC_ALI_LFD: case EXC_ALI_STFD: +#ifdef BOOKE + if (copyin((void *)frame->srr0, &inst, sizeof(inst)) != 0) + return (-1); + reg = EXC_ALI_INST_RST(inst); +#else reg = EXC_ALI_RST(frame->cpu.aim.dsisr); +#endif fpr = &td->td_pcb->pcb_fpu.fpr[reg].fpr; fputhread = PCPU_GET(fputhread); From 1ee03da25edcb64b79a2fe7337930596c43c9015 Mon Sep 17 00:00:00 2001 From: Rebecca Cran Date: Wed, 26 Jun 2019 03:06:57 +0000 Subject: [PATCH 119/165] Re-enable loader efi http boot and fix dv_open bug if dv_init failed The code in efihttp.c was assuming that dv_open wouldn't be called if dv_init failed. But the dv_init return value is currently ignored. Add a new variable, `efihttp_init_done` and only proceed in dv_open if it's true. This fixes the loader on systems without efi http support. --- stand/efi/libefi/efihttp.c | 10 ++++++++++ stand/efi/loader/conf.c | 2 ++ 2 files changed, 12 insertions(+) diff --git a/stand/efi/libefi/efihttp.c b/stand/efi/libefi/efihttp.c index 5a0c3d2fec8f..abe2e28821ea 100644 --- a/stand/efi/libefi/efihttp.c +++ b/stand/efi/libefi/efihttp.c @@ -52,6 +52,8 @@ static EFI_GUID http_guid = EFI_HTTP_PROTOCOL_GUID; static EFI_GUID httpsb_guid = EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID; static EFI_GUID ip4config2_guid = EFI_IP4_CONFIG2_PROTOCOL_GUID; +static bool efihttp_init_done = false; + static int efihttp_dev_init(void); static int efihttp_dev_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf, size_t *rsize); @@ -208,6 +210,9 @@ efihttp_dev_init(void) return (efi_status_to_errno(status)); err = efi_register_handles(&efihttp_dev, &handle, NULL, 1); + if (!err) + efihttp_init_done = true; + return (err); } @@ -236,6 +241,9 @@ efihttp_dev_open(struct open_file *f, ...) EFI_STATUS status; int err, len; + if (!efihttp_init_done) + return (ENXIO); + imgpath = efi_lookup_image_devpath(IH); if (imgpath == NULL) return (ENXIO); @@ -555,6 +563,8 @@ efihttp_fs_open(const char *path, struct open_file *f) char *path_slash; int err; + if (!efihttp_init_done) + return (ENXIO); /* * If any path fails to open, try with a trailing slash in * case it's a directory. diff --git a/stand/efi/loader/conf.c b/stand/efi/loader/conf.c index 2e4d35f88a6c..d08ded39b4f2 100644 --- a/stand/efi/loader/conf.c +++ b/stand/efi/loader/conf.c @@ -39,6 +39,7 @@ struct devsw *devsw[] = { &efipart_fddev, &efipart_cddev, &efipart_hddev, + &efihttp_dev, /* ordering with efinet_dev matters */ &efinet_dev, &vdisk_dev, #ifdef EFI_ZFS_BOOT @@ -54,6 +55,7 @@ struct fs_ops *file_system[] = { &dosfs_fsops, &ufs_fsops, &cd9660_fsops, + &efihttp_fsops, &tftp_fsops, &nfs_fsops, &gzipfs_fsops, From d1d3f7e1d153df2cfa6c881b766d7212747aa547 Mon Sep 17 00:00:00 2001 From: Doug Moore Date: Wed, 26 Jun 2019 03:12:57 +0000 Subject: [PATCH 120/165] Revert r349393, which leads to an assertion failure on bootup, in vm_map_stack_locked. Reported by: ler@lerctr.org Approved by: kib, markj (mentors, implicit) --- sys/vm/vm_map.c | 328 ++++++++++++++++++++++++++---------------------- sys/vm/vm_map.h | 2 +- 2 files changed, 177 insertions(+), 153 deletions(-) diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c index 4cf152a85170..38afe6308cc8 100644 --- a/sys/vm/vm_map.c +++ b/sys/vm/vm_map.c @@ -983,17 +983,6 @@ vm_map_entry_max_free_right(vm_map_entry_t root, vm_map_entry_t right_ancestor) root->right->max_free : right_ancestor->start - root->end); } -/* - * vm_map_splay_split, vm_map_splay_merge: - * - * The Sleator and Tarjan top-down splay algorithm with the following - * variation. Max_free must be computed bottom-up, so on the downward - * pass (vm_map_splay_split), maintain the left and right spines in - * reverse order, and ensure that the max_free values for those nodes - * store the values of their descendents not on the search path. Later, - * make a second pass up each side (vm_map_splay_merge) to fix the - * pointers and compute max_free. The time bound is O(log n) amortized. - */ #define SPLAY_LEFT_STEP(root, y, rlist, test) do { \ vm_size_t max_free; \ \ @@ -1176,6 +1165,56 @@ vm_map_splay_merge(vm_map_t map, vm_map_entry_t root, map->root = root; } +/* + * vm_map_splay: + * + * The Sleator and Tarjan top-down splay algorithm with the + * following variation. Max_free must be computed bottom-up, so + * on the downward pass, maintain the left and right spines in + * reverse order. Then, make a second pass up each side to fix + * the pointers and compute max_free. The time bound is O(log n) + * amortized. + * + * The new root is the vm_map_entry containing "addr", or else an + * adjacent entry (lower if possible) if addr is not in the tree. + * + * The map must be locked, and leaves it so. + * + * Returns: the new root. + */ +static vm_map_entry_t +vm_map_splay(vm_map_t map, vm_offset_t addr) +{ + vm_map_entry_t llist, rlist, root; + + root = vm_map_splay_split(map, addr, 0, &llist, &rlist); + if (root != NULL) { + /* do nothing */ + } else if (llist != &map->header) { + /* + * Recover the greatest node in the left + * subtree and make it the root. + */ + root = llist; + llist = root->right; + root->right = NULL; + } else if (rlist != &map->header) { + /* + * Recover the least node in the right + * subtree and make it the root. + */ + root = rlist; + rlist = root->left; + root->left = NULL; + } else { + /* There is no root. */ + return (NULL); + } + vm_map_splay_merge(map, root, llist, rlist); + VM_MAP_ASSERT_CONSISTENT(map); + return (root); +} + /* * vm_map_entry_{un,}link: * @@ -1292,131 +1331,79 @@ vm_map_entry_resize(vm_map_t map, vm_map_entry_t entry, vm_size_t grow_amount) } /* - * vm_map_lookup_helper: [ internal use only ] + * vm_map_lookup_entry: [ internal use only ] * - * Finds the map entry containing (or adjacent to) the specified address - * in the given map; the entry is returned in the "entry" parameter. The - * boolean result indicates whether the address is actually contained in - * the map. If the address is not contained in the map, parameter lesseq - * determines whether the entry provided is before or after the address. - * If the address is contained in the map, parameter nbr, if not NULL, is - * where the next or previous entry is saved, depending on the value of - * eflags in the found entry. + * Finds the map entry containing (or + * immediately preceding) the specified address + * in the given map; the entry is returned + * in the "entry" parameter. The boolean + * result indicates whether the address is + * actually contained in the map. */ -static bool -vm_map_lookup_helper(vm_map_t map, vm_offset_t addr, bool lesseq, - vm_map_entry_t *entry, vm_map_entry_t *nbr) /* OUT */ +boolean_t +vm_map_lookup_entry( + vm_map_t map, + vm_offset_t address, + vm_map_entry_t *entry) /* OUT */ { - vm_map_entry_t llist, rlist, root; - bool locked, found; + vm_map_entry_t cur, lbound; + boolean_t locked; /* * If the map is empty, then the map entry immediately preceding - * "addr" is the map's header. + * "address" is the map's header. */ - root = map->root; - if (root == NULL) { + cur = map->root; + if (cur == NULL) { *entry = &map->header; - return (false); + return (FALSE); + } + if (address >= cur->start && cur->end > address) { + *entry = cur; + return (TRUE); } if ((locked = vm_map_locked(map)) || sx_try_upgrade(&map->lock)) { - /* * Splay requires a write lock on the map. However, it only * restructures the binary search tree; it does not otherwise * change the map. Thus, the map's timestamp need not change * on a temporary upgrade. */ - root = vm_map_splay_split(map, addr, 0, &llist, &rlist); - found = root != NULL; - *entry = root; - if (root != NULL) { - if (nbr == NULL) - ; /* Ignore. */ - else if ((root->eflags & MAP_ENTRY_STACK_GAP_DN) != 0) { - vm_map_splay_findnext(root, &rlist); - *nbr = rlist; - } else { - vm_map_splay_findprev(root, &llist); - *nbr = llist; - } - } else if (llist != &map->header) { - /* - * Recover the greatest node in the left - * subtree and make it the root. - */ - *entry = lesseq ? llist : rlist; - root = llist; - llist = root->right; - root->right = NULL; - } else { - /* - * Recover the least node in the right - * subtree and make it the root. - */ - *entry = lesseq ? llist : rlist; - root = rlist; - rlist = root->left; - root->left = NULL; - } - vm_map_splay_merge(map, root, llist, rlist); - VM_MAP_ASSERT_CONSISTENT(map); + cur = vm_map_splay(map, address); if (!locked) sx_downgrade(&map->lock); - return (found); + + /* + * If "address" is contained within a map entry, the new root + * is that map entry. Otherwise, the new root is a map entry + * immediately before or after "address". + */ + if (address < cur->start) { + *entry = &map->header; + return (FALSE); + } + *entry = cur; + return (address < cur->end); } /* * Since the map is only locked for read access, perform a - * standard binary search tree lookup for "addr". + * standard binary search tree lookup for "address". */ - llist = rlist = &map->header; + lbound = &map->header; do { - if (addr < root->start) { - rlist = root; - root = root->left; - } else if (root->end <= addr) { - llist = root; - root = root->right; + if (address < cur->start) { + cur = cur->left; + } else if (cur->end <= address) { + lbound = cur; + cur = cur->right; } else { - *entry = root; - if (nbr == NULL); - else if ((root->eflags & MAP_ENTRY_STACK_GAP_DN) != 0) { - /* Make nbr the successor to root. */ - if (root->right != NULL) { - rlist = root->right; - while (rlist->left != NULL) - rlist = rlist->left; - } - *nbr = rlist; - } else { - /* Make nbr the predecessor to root. */ - if (root->left != NULL) { - llist = root->left; - while (llist->right != NULL) - llist = llist->right; - } - *nbr = llist; - } - return (true); + *entry = cur; + return (TRUE); } - } while (root != NULL); - *entry = lesseq ? llist : rlist; - return (false); -} - -bool -vm_map_lookup_entry(vm_map_t map, vm_offset_t addr, - vm_map_entry_t *entry) /* OUT */ -{ - return (vm_map_lookup_helper(map, addr, true, entry, NULL)); -} - -static bool -vm_map_lookup_entry_ge(vm_map_t map, vm_offset_t addr, - vm_map_entry_t *entry) /* OUT */ -{ - return (vm_map_lookup_helper(map, addr, false, entry, NULL)); + } while (cur != NULL); + *entry = lbound; + return (FALSE); } /* @@ -1435,7 +1422,7 @@ int vm_map_insert(vm_map_t map, vm_object_t object, vm_ooffset_t offset, vm_offset_t start, vm_offset_t end, vm_prot_t prot, vm_prot_t max, int cow) { - vm_map_entry_t new_entry, prev_entry; + vm_map_entry_t new_entry, prev_entry, temp_entry; struct ucred *cred; vm_eflags_t protoeflags; vm_inherit_t inheritance; @@ -1460,9 +1447,11 @@ vm_map_insert(vm_map_t map, vm_object_t object, vm_ooffset_t offset, * Find the entry prior to the proposed starting address; if it's part * of an existing entry, this range is bogus. */ - if (vm_map_lookup_entry(map, start, &prev_entry)) + if (vm_map_lookup_entry(map, start, &temp_entry)) return (KERN_NO_SPACE); + prev_entry = temp_entry; + /* * Assert that the next entry doesn't overlap the end point. */ @@ -2325,8 +2314,10 @@ vm_map_submap( VM_MAP_RANGE_CHECK(map, start, end); - if (vm_map_lookup_entry_ge(map, start, &entry)) + if (vm_map_lookup_entry(map, start, &entry)) { vm_map_clip_start(map, entry, start); + } else + entry = entry->next; vm_map_clip_end(map, entry, end); @@ -2481,7 +2472,8 @@ vm_map_protect(vm_map_t map, vm_offset_t start, vm_offset_t end, VM_MAP_RANGE_CHECK(map, start, end); - vm_map_lookup_entry_ge(map, start, &entry); + if (!vm_map_lookup_entry(map, start, &entry)) + entry = entry->next; /* * Make a first pass to check for protection violations. @@ -2671,9 +2663,11 @@ vm_map_madvise( */ VM_MAP_RANGE_CHECK(map, start, end); - if (vm_map_lookup_entry_ge(map, start, &entry)) { + if (vm_map_lookup_entry(map, start, &entry)) { if (modify_map) vm_map_clip_start(map, entry, start); + } else { + entry = entry->next; } if (modify_map) { @@ -2805,6 +2799,7 @@ vm_map_inherit(vm_map_t map, vm_offset_t start, vm_offset_t end, vm_inherit_t new_inheritance) { vm_map_entry_t entry; + vm_map_entry_t temp_entry; switch (new_inheritance) { case VM_INHERIT_NONE: @@ -2819,8 +2814,11 @@ vm_map_inherit(vm_map_t map, vm_offset_t start, vm_offset_t end, return (KERN_SUCCESS); vm_map_lock(map); VM_MAP_RANGE_CHECK(map, start, end); - if (vm_map_lookup_entry_ge(map, start, &entry)) + if (vm_map_lookup_entry(map, start, &temp_entry)) { + entry = temp_entry; vm_map_clip_start(map, entry, start); + } else + entry = temp_entry->next; while (entry->start < end) { vm_map_clip_end(map, entry, end); if ((entry->eflags & MAP_ENTRY_GUARD) == 0 || @@ -2853,8 +2851,10 @@ vm_map_unwire(vm_map_t map, vm_offset_t start, vm_offset_t end, user_unwire = (flags & VM_MAP_WIRE_USER) ? TRUE : FALSE; vm_map_lock(map); VM_MAP_RANGE_CHECK(map, start, end); - if (!vm_map_lookup_entry_ge(map, start, &first_entry)) { - if ((flags & VM_MAP_WIRE_HOLESOK) == 0) { + if (!vm_map_lookup_entry(map, start, &first_entry)) { + if (flags & VM_MAP_WIRE_HOLESOK) + first_entry = first_entry->next; + else { vm_map_unlock(map); return (KERN_INVALID_ADDRESS); } @@ -2882,9 +2882,11 @@ vm_map_unwire(vm_map_t map, vm_offset_t start, vm_offset_t end, * Specifically, the entry may have been * clipped, merged, or deleted. */ - if (!vm_map_lookup_entry_ge(map, saved_start, + if (!vm_map_lookup_entry(map, saved_start, &tmp_entry)) { - if ((flags & VM_MAP_WIRE_HOLESOK) == 0) { + if (flags & VM_MAP_WIRE_HOLESOK) + tmp_entry = tmp_entry->next; + else { if (saved_start == start) { /* * First_entry has been deleted. @@ -2942,9 +2944,11 @@ vm_map_unwire(vm_map_t map, vm_offset_t start, vm_offset_t end, done: need_wakeup = FALSE; if (first_entry == NULL) { - result = vm_map_lookup_entry_ge(map, start, &first_entry); - KASSERT(result || (flags & VM_MAP_WIRE_HOLESOK) != 0, - ("vm_map_unwire: lookup failed")); + result = vm_map_lookup_entry(map, start, &first_entry); + if (!result && (flags & VM_MAP_WIRE_HOLESOK)) + first_entry = first_entry->next; + else + KASSERT(result, ("vm_map_unwire: lookup failed")); } for (entry = first_entry; entry->start < end; entry = entry->next) { /* @@ -3086,8 +3090,10 @@ vm_map_wire_locked(vm_map_t map, vm_offset_t start, vm_offset_t end, int flags) prot |= VM_PROT_WRITE; user_wire = (flags & VM_MAP_WIRE_USER) ? TRUE : FALSE; VM_MAP_RANGE_CHECK(map, start, end); - if (!vm_map_lookup_entry_ge(map, start, &first_entry)) { - if ((flags & VM_MAP_WIRE_HOLESOK) == 0) + if (!vm_map_lookup_entry(map, start, &first_entry)) { + if (flags & VM_MAP_WIRE_HOLESOK) + first_entry = first_entry->next; + else return (KERN_INVALID_ADDRESS); } last_timestamp = map->timestamp; @@ -3113,9 +3119,11 @@ vm_map_wire_locked(vm_map_t map, vm_offset_t start, vm_offset_t end, int flags) * Specifically, the entry may have been * clipped, merged, or deleted. */ - if (!vm_map_lookup_entry_ge(map, saved_start, + if (!vm_map_lookup_entry(map, saved_start, &tmp_entry)) { - if ((flags & VM_MAP_WIRE_HOLESOK) == 0) { + if (flags & VM_MAP_WIRE_HOLESOK) + tmp_entry = tmp_entry->next; + else { if (saved_start == start) { /* * first_entry has been deleted. @@ -3248,9 +3256,11 @@ vm_map_wire_locked(vm_map_t map, vm_offset_t start, vm_offset_t end, int flags) done: need_wakeup = FALSE; if (first_entry == NULL) { - result = vm_map_lookup_entry_ge(map, start, &first_entry); - KASSERT(result || (flags & VM_MAP_WIRE_HOLESOK) != 0, - ("vm_map_wire: lookup failed")); + result = vm_map_lookup_entry(map, start, &first_entry); + if (!result && (flags & VM_MAP_WIRE_HOLESOK)) + first_entry = first_entry->next; + else + KASSERT(result, ("vm_map_wire: lookup failed")); } for (entry = first_entry; entry->start < end; entry = entry->next) { /* @@ -3351,8 +3361,7 @@ vm_map_sync( if (!vm_map_lookup_entry(map, start, &entry)) { vm_map_unlock_read(map); return (KERN_INVALID_ADDRESS); - } - if (start == end) { + } else if (start == end) { start = entry->start; end = entry->end; } @@ -3407,10 +3416,9 @@ vm_map_sync( start += size; vm_object_deallocate(object); vm_map_lock_read(map); - if (last_timestamp == map->timestamp) + if (last_timestamp == map->timestamp || + !vm_map_lookup_entry(map, start, ¤t)) current = current->next; - else - vm_map_lookup_entry_ge(map, start, ¤t); } vm_map_unlock_read(map); @@ -3543,6 +3551,7 @@ int vm_map_delete(vm_map_t map, vm_offset_t start, vm_offset_t end) { vm_map_entry_t entry; + vm_map_entry_t first_entry; VM_MAP_ASSERT_LOCKED(map); if (start == end) @@ -3551,8 +3560,12 @@ vm_map_delete(vm_map_t map, vm_offset_t start, vm_offset_t end) /* * Find the start of the region, and clip it */ - if (vm_map_lookup_entry_ge(map, start, &entry)) + if (!vm_map_lookup_entry(map, start, &first_entry)) + entry = first_entry->next; + else { + entry = first_entry; vm_map_clip_start(map, entry, start); + } /* * Step through all entries in this region @@ -3570,22 +3583,29 @@ vm_map_delete(vm_map_t map, vm_offset_t start, vm_offset_t end) vm_map_entry_system_wired_count(entry) != 0)) { unsigned int last_timestamp; vm_offset_t saved_start; + vm_map_entry_t tmp_entry; saved_start = entry->start; entry->eflags |= MAP_ENTRY_NEEDS_WAKEUP; last_timestamp = map->timestamp; (void) vm_map_unlock_and_wait(map, 0); vm_map_lock(map); - if (last_timestamp + 1 == map->timestamp) - continue; - - /* - * Look again for the entry because the map was - * modified while it was unlocked. Specifically, the - * entry may have been clipped, merged, or deleted. - */ - if (vm_map_lookup_entry_ge(map, saved_start, &entry)) - vm_map_clip_start(map, entry, saved_start); + if (last_timestamp + 1 != map->timestamp) { + /* + * Look again for the entry because the map was + * modified while it was unlocked. + * Specifically, the entry may have been + * clipped, merged, or deleted. + */ + if (!vm_map_lookup_entry(map, saved_start, + &tmp_entry)) + entry = tmp_entry->next; + else { + entry = tmp_entry; + vm_map_clip_start(map, entry, + saved_start); + } + } continue; } vm_map_clip_end(map, entry, end); @@ -3660,9 +3680,11 @@ vm_map_check_protection(vm_map_t map, vm_offset_t start, vm_offset_t end, vm_prot_t protection) { vm_map_entry_t entry; + vm_map_entry_t tmp_entry; - if (!vm_map_lookup_entry(map, start, &entry)) + if (!vm_map_lookup_entry(map, start, &tmp_entry)) return (FALSE); + entry = tmp_entry; while (start < end) { /* @@ -4098,7 +4120,7 @@ static int vm_map_stack_locked(vm_map_t map, vm_offset_t addrbos, vm_size_t max_ssize, vm_size_t growsize, vm_prot_t prot, vm_prot_t max, int cow) { - vm_map_entry_t new_entry; + vm_map_entry_t new_entry, prev_entry; vm_offset_t bot, gap_bot, gap_top, top; vm_size_t init_ssize, sgp; int orient, rv; @@ -4126,13 +4148,13 @@ vm_map_stack_locked(vm_map_t map, vm_offset_t addrbos, vm_size_t max_ssize, init_ssize = max_ssize - sgp; /* If addr is already mapped, no go */ - if (vm_map_lookup_entry_ge(map, addrbos, &new_entry)) + if (vm_map_lookup_entry(map, addrbos, &prev_entry)) return (KERN_NO_SPACE); /* * If we can't accommodate max_ssize in the current mapping, no go. */ - if (new_entry->start < addrbos + max_ssize) + if (prev_entry->next->start < addrbos + max_ssize) return (KERN_NO_SPACE); /* @@ -4159,6 +4181,7 @@ vm_map_stack_locked(vm_map_t map, vm_offset_t addrbos, vm_size_t max_ssize, rv = vm_map_insert(map, NULL, 0, bot, top, prot, max, cow); if (rv != KERN_SUCCESS) return (rv); + new_entry = prev_entry->next; KASSERT(new_entry->end == top || new_entry->start == bot, ("Bad entry start/end for new stack entry")); KASSERT((orient & MAP_STACK_GROWS_DOWN) == 0 || @@ -4217,18 +4240,19 @@ vm_map_growstack(vm_map_t map, vm_offset_t addr, vm_map_entry_t gap_entry) vmemlim = lim_cur(curthread, RLIMIT_VMEM); retry: /* If addr is not in a hole for a stack grow area, no need to grow. */ - if (gap_entry == NULL && - !vm_map_lookup_helper(map, addr, true, &gap_entry, &stack_entry)) + if (gap_entry == NULL && !vm_map_lookup_entry(map, addr, &gap_entry)) return (KERN_FAILURE); if ((gap_entry->eflags & MAP_ENTRY_GUARD) == 0) return (KERN_SUCCESS); if ((gap_entry->eflags & MAP_ENTRY_STACK_GAP_DN) != 0) { + stack_entry = gap_entry->next; if ((stack_entry->eflags & MAP_ENTRY_GROWS_DOWN) == 0 || stack_entry->start != gap_entry->end) return (KERN_FAILURE); grow_amount = round_page(stack_entry->start - addr); grow_down = true; } else if ((gap_entry->eflags & MAP_ENTRY_STACK_GAP_UP) != 0) { + stack_entry = gap_entry->prev; if ((stack_entry->eflags & MAP_ENTRY_GROWS_UP) == 0 || stack_entry->end != gap_entry->start) return (KERN_FAILURE); diff --git a/sys/vm/vm_map.h b/sys/vm/vm_map.h index 570ea701c1e6..3b870baac759 100644 --- a/sys/vm/vm_map.h +++ b/sys/vm/vm_map.h @@ -415,7 +415,7 @@ int vm_map_lookup (vm_map_t *, vm_offset_t, vm_prot_t, vm_map_entry_t *, vm_obje int vm_map_lookup_locked(vm_map_t *, vm_offset_t, vm_prot_t, vm_map_entry_t *, vm_object_t *, vm_pindex_t *, vm_prot_t *, boolean_t *); void vm_map_lookup_done (vm_map_t, vm_map_entry_t); -bool vm_map_lookup_entry(vm_map_t, vm_offset_t, vm_map_entry_t *); +boolean_t vm_map_lookup_entry (vm_map_t, vm_offset_t, vm_map_entry_t *); int vm_map_protect (vm_map_t, vm_offset_t, vm_offset_t, vm_prot_t, boolean_t); int vm_map_remove (vm_map_t, vm_offset_t, vm_offset_t); void vm_map_simplify_entry(vm_map_t map, vm_map_entry_t entry); From 8352171a5883e36cd969e780c5b8f0c7be00c671 Mon Sep 17 00:00:00 2001 From: Andriy Gapon Date: Wed, 26 Jun 2019 06:40:30 +0000 Subject: [PATCH 121/165] owc.4: document how to set up the 1-wire bus on a device.hints system MFC after: 1 week --- share/man/man4/owc.4 | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/share/man/man4/owc.4 b/share/man/man4/owc.4 index 43d6cb776ae4..93039015baf0 100644 --- a/share/man/man4/owc.4 +++ b/share/man/man4/owc.4 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd July 20, 2015 +.Dd June 26, 2019 .Dt OWC 4 .Os .Sh NAME @@ -69,6 +69,23 @@ For more details about the .Va gpios property, please consult .Pa /usr/src/sys/dts/bindings-gpio.txt . +.Pp +On a +.Xr device.hints 5 +based system these values are required for the +.Nm : +.Bl -tag -width ".Va hint.owc.%d.atXXX" +.It Va hint.owc.%d.at +The +.Nm gpiobus +you are attaching to. +.It Va hint.owc.%d.pins +This is a bitmask that defines a pin on the +.Nm gpiobus +that is to be used for the 1-Wire bus. +For instance, to configure pin 10, use the bitmask of 0x400. +Please note that this mask should have only one bit set +(any other bits - i.e., pins - will be ignored). .Sh SEE ALSO .Xr gpiobus 4 , .Xr ow 4 , From 50b4788ba1fca0a0ce84e2bd13aa24e766f80f69 Mon Sep 17 00:00:00 2001 From: Andriy Gapon Date: Wed, 26 Jun 2019 07:08:51 +0000 Subject: [PATCH 122/165] fix up r349406, add missing .El MFC after: 1 week --- share/man/man4/owc.4 | 1 + 1 file changed, 1 insertion(+) diff --git a/share/man/man4/owc.4 b/share/man/man4/owc.4 index 93039015baf0..06c4e909ac96 100644 --- a/share/man/man4/owc.4 +++ b/share/man/man4/owc.4 @@ -86,6 +86,7 @@ that is to be used for the 1-Wire bus. For instance, to configure pin 10, use the bitmask of 0x400. Please note that this mask should have only one bit set (any other bits - i.e., pins - will be ignored). +.El .Sh SEE ALSO .Xr gpiobus 4 , .Xr ow 4 , From 59c94acee91870f20e4522f95432442529e5708a Mon Sep 17 00:00:00 2001 From: Andriy Gapon Date: Wed, 26 Jun 2019 07:38:31 +0000 Subject: [PATCH 123/165] gpio.4: document device hints common to all devices on gpiobus "at" keyword is documented in device.hints(5) for all buses, but it does hurt to add another reference to it. "pins" keyword is specific to gpiobus. At least these two hints should be configured for any gpiobus device on a hints based system. MFC after: 10 days --- share/man/man4/gpio.4 | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/share/man/man4/gpio.4 b/share/man/man4/gpio.4 index 0e2c8cdb1423..b1eb1ef8a5bc 100644 --- a/share/man/man4/gpio.4 +++ b/share/man/man4/gpio.4 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd November 5, 2013 +.Dd June 26, 2019 .Dt GPIO 4 .Os .Sh NAME @@ -103,12 +103,36 @@ passed to the kernel, being either statically compiled in, or by a variety of ways where the boot loader (or Open Firmware enabled system) passes the DTS blob to the kernel at boot. .Pp +On a +.Xr device.hints 5 +based system these hints can be used to configure drivers for devices +attached to +.Nm +pins: +.Bl -tag -width ".Va hint.driver.unit.pins" +.It Va hint.driver.unit.at +The +.Nm gpiobus +where the device is attached. +For example, +.Qq gpiobus0 . +.Ar driver +and +.Ar unit +are the driver name and the unit number for the device driver. +.It Va hint.driver.unit.pins +This is a bitmask of the pins on the +.Nm gpiobus +that are connected to the device. +The pins will be allocated to the specified driver instance. +.El +.Pp The following .Xr device.hints 5 are only provided by the .Cd ar71xx_gpio driver: -.Bl -tag -width ".Va hint.gpioiic.%d.atXXX" +.Bl -tag -width ".Va hint.gpio.function_clear" .It Va hint.gpio.%d.pinmask This is a bitmask of pins on the GPIO board that we would like to expose for use to the host operating system. @@ -133,6 +157,7 @@ of some device in a system. .Xr gpioiic 4 , .Xr gpioled 4 , .Xr iicbus 4 , +.Xr device.hints 5 , .Xr gpioctl 8 .Sh HISTORY The From a41b0ec1439e4395216539d4ed03eff6760e1e1b Mon Sep 17 00:00:00 2001 From: Hans Petter Selasky Date: Wed, 26 Jun 2019 11:28:08 +0000 Subject: [PATCH 124/165] Fix support for LIBUSB_HOTPLUG_ENUMERATE in libusb. Currently all devices are enumerated regardless of of the LIBUSB_HOTPLUG_ENUMERATE flag. Make sure when the flag is not specified no arrival events are generated for currently enumerated devices. MFC after: 3 days Sponsored by: Mellanox Technologies --- lib/libusb/libusb10.h | 4 +++- lib/libusb/libusb10_hotplug.c | 33 ++++++++++++++++++++++----------- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/lib/libusb/libusb10.h b/lib/libusb/libusb10.h index c3deb562c6d4..5caa56666c32 100644 --- a/lib/libusb/libusb10.h +++ b/lib/libusb/libusb10.h @@ -89,6 +89,8 @@ struct libusb_hotplug_callback_handle_struct { void *user_data; }; +TAILQ_HEAD(libusb_device_head, libusb_device); + struct libusb_context { int debug; int debug_fixed; @@ -106,7 +108,7 @@ struct libusb_context { TAILQ_HEAD(, libusb_super_pollfd) pollfds; TAILQ_HEAD(, libusb_super_transfer) tr_done; TAILQ_HEAD(, libusb_hotplug_callback_handle_struct) hotplug_cbh; - TAILQ_HEAD(, libusb_device) hotplug_devs; + struct libusb_device_head hotplug_devs; struct libusb_super_pollfd ctx_poll; diff --git a/lib/libusb/libusb10_hotplug.c b/lib/libusb/libusb10_hotplug.c index 162cf2bbb5af..5ece97c19170 100644 --- a/lib/libusb/libusb10_hotplug.c +++ b/lib/libusb/libusb10_hotplug.c @@ -85,20 +85,35 @@ libusb_hotplug_filter(libusb_context *ctx, libusb_hotplug_callback_handle pcbh, return (pcbh->fn(ctx, dev, event, pcbh->user_data)); } +static int +libusb_hotplug_enumerate(libusb_context *ctx, struct libusb_device_head *phead) +{ + libusb_device **ppdev; + ssize_t count; + ssize_t x; + + count = libusb_get_device_list(ctx, &ppdev); + if (count < 0) + return (-1); + + for (x = 0; x != count; x++) + TAILQ_INSERT_TAIL(phead, ppdev[x], hotplug_entry); + + libusb_free_device_list(ppdev, 0); + return (0); +} + static void * libusb_hotplug_scan(void *arg) { - TAILQ_HEAD(, libusb_device) hotplug_devs; + struct libusb_device_head hotplug_devs; libusb_hotplug_callback_handle acbh; libusb_hotplug_callback_handle bcbh; libusb_context *ctx = arg; - libusb_device **ppdev; libusb_device *temp; libusb_device *adev; libusb_device *bdev; unsigned do_loop = 1; - ssize_t count; - ssize_t x; while (do_loop) { usleep(4000000); @@ -108,14 +123,8 @@ libusb_hotplug_scan(void *arg) TAILQ_INIT(&hotplug_devs); if (ctx->hotplug_handler != NO_THREAD) { - count = libusb_get_device_list(ctx, &ppdev); - if (count < 0) + if (libusb_hotplug_enumerate(ctx, &hotplug_devs) < 0) continue; - for (x = 0; x != count; x++) { - TAILQ_INSERT_TAIL(&hotplug_devs, ppdev[x], - hotplug_entry); - } - libusb_free_device_list(ppdev, 0); } else { do_loop = 0; } @@ -202,6 +211,8 @@ int libusb_hotplug_register_callback(libusb_context *ctx, handle->fn = cb_fn; handle->user_data = user_data; + libusb_hotplug_enumerate(ctx, &ctx->hotplug_devs); + if (flags & LIBUSB_HOTPLUG_ENUMERATE) { TAILQ_FOREACH(adev, &ctx->hotplug_devs, hotplug_entry) { if (libusb_hotplug_filter(ctx, handle, adev, From a5b24a2b65b945f8688ae677e816b1a2c632a39a Mon Sep 17 00:00:00 2001 From: Hans Petter Selasky Date: Wed, 26 Jun 2019 12:04:54 +0000 Subject: [PATCH 125/165] Only call libusb_hotplug_enumerate() once from libusb_hotplug_register_callback(). Else when registering multiple filters the same USB device may appear twice in the list. MFC after: 3 days Sponsored by: Mellanox Technologies --- lib/libusb/libusb10_hotplug.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/libusb/libusb10_hotplug.c b/lib/libusb/libusb10_hotplug.c index 5ece97c19170..96e3bf9a12ca 100644 --- a/lib/libusb/libusb10_hotplug.c +++ b/lib/libusb/libusb10_hotplug.c @@ -1,6 +1,6 @@ /* $FreeBSD$ */ /*- - * Copyright (c) 2016 Hans Petter Selasky. All rights reserved. + * Copyright (c) 2016-2019 Hans Petter Selasky. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -200,6 +200,8 @@ int libusb_hotplug_register_callback(libusb_context *ctx, HOTPLUG_LOCK(ctx); if (ctx->hotplug_handler == NO_THREAD) { + libusb_hotplug_enumerate(ctx, &ctx->hotplug_devs); + if (pthread_create(&ctx->hotplug_handler, NULL, &libusb_hotplug_scan, ctx) != 0) ctx->hotplug_handler = NO_THREAD; @@ -211,8 +213,6 @@ int libusb_hotplug_register_callback(libusb_context *ctx, handle->fn = cb_fn; handle->user_data = user_data; - libusb_hotplug_enumerate(ctx, &ctx->hotplug_devs); - if (flags & LIBUSB_HOTPLUG_ENUMERATE) { TAILQ_FOREACH(adev, &ctx->hotplug_devs, hotplug_entry) { if (libusb_hotplug_filter(ctx, handle, adev, From c2c5d1e7874dd2928bc5e85912e59541741f74a3 Mon Sep 17 00:00:00 2001 From: Marius Strobl Date: Wed, 26 Jun 2019 15:28:21 +0000 Subject: [PATCH 126/165] o In iflib_txq_drain(): - Remove desc_used, which is only ever written to. - Remove a dead store to reclaimed. - Don't recycle avail. - Sort variables according to style(9). These changes will make a subsequent commit easier to read. o In iflib_tx_credits_update(), don't bother checking whether the ift_txd_credits_update method pointer is NULL; _iflib_pre_assert() asserts upfront that this method has been assigned and functions like iflib_{fast_intr_rxtx,netmap_timer_adjust,txq_can_drain}() and _task_fn_tx() were already unconditionally relying on the method being callable. --- sys/net/iflib.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/sys/net/iflib.c b/sys/net/iflib.c index d932e9373be0..e33c2bec61e2 100644 --- a/sys/net/iflib.c +++ b/sys/net/iflib.c @@ -3580,10 +3580,10 @@ iflib_txq_drain(struct ifmp_ring *r, uint32_t cidx, uint32_t pidx) iflib_txq_t txq = r->cookie; if_ctx_t ctx = txq->ift_ctx; if_t ifp = ctx->ifc_ifp; - struct mbuf **mp, *m; - int i, count, consumed, pkt_sent, bytes_sent, mcast_sent, avail; - int reclaimed, err, in_use_prev, desc_used; - bool do_prefetch, ring, rang; + struct mbuf *m, **mp; + int avail, bytes_sent, consumed, count, err, i, in_use_prev; + int mcast_sent, pkt_sent, reclaimed, txq_avail; + bool do_prefetch, rang, ring; if (__predict_false(!(if_getdrvflags(ifp) & IFF_DRV_RUNNING) || !LINK_ACTIVE(ctx))) { @@ -3621,16 +3621,15 @@ iflib_txq_drain(struct ifmp_ring *r, uint32_t cidx, uint32_t pidx) avail, ctx->ifc_flags, TXQ_AVAIL(txq)); #endif do_prefetch = (ctx->ifc_flags & IFC_PREFETCH); - avail = TXQ_AVAIL(txq); + txq_avail = TXQ_AVAIL(txq); err = 0; - for (desc_used = i = 0; i < count && avail > MAX_TX_DESC(ctx) + 2; i++) { + for (i = 0; i < count && txq_avail > MAX_TX_DESC(ctx) + 2; i++) { int rem = do_prefetch ? count - i : 0; mp = _ring_peek_one(r, cidx, i, rem); MPASS(mp != NULL && *mp != NULL); if (__predict_false(*mp == (struct mbuf *)txq)) { consumed++; - reclaimed++; continue; } in_use_prev = txq->ift_in_use; @@ -3649,10 +3648,9 @@ iflib_txq_drain(struct ifmp_ring *r, uint32_t cidx, uint32_t pidx) DBG_COUNTER_INC(tx_sent); bytes_sent += m->m_pkthdr.len; mcast_sent += !!(m->m_flags & M_MCAST); - avail = TXQ_AVAIL(txq); + txq_avail = TXQ_AVAIL(txq); txq->ift_db_pending += (txq->ift_in_use - in_use_prev); - desc_used += (txq->ift_in_use - in_use_prev); ETHER_BPF_MTAP(ifp, m); if (__predict_false(!(ifp->if_drv_flags & IFF_DRV_RUNNING))) break; @@ -6155,9 +6153,6 @@ iflib_tx_credits_update(if_ctx_t ctx, iflib_txq_t txq) int credits_pre = txq->ift_cidx_processed; #endif - if (ctx->isc_txd_credits_update == NULL) - return (0); - bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_ifdi->idi_map, BUS_DMASYNC_POSTREAD); if ((credits = ctx->isc_txd_credits_update(ctx->ifc_softc, txq->ift_id, true)) == 0) From df5e39248342eb6579361b756fb07d2ee08e6955 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Wed, 26 Jun 2019 15:43:20 +0000 Subject: [PATCH 127/165] Fix -Wsign-compare warnings in realpath.c This is needed in order to build realpath.c as part of rtld. --- lib/libc/stdlib/realpath.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/libc/stdlib/realpath.c b/lib/libc/stdlib/realpath.c index 9b0ba94473cb..99dc388c4db6 100644 --- a/lib/libc/stdlib/realpath.c +++ b/lib/libc/stdlib/realpath.c @@ -91,7 +91,7 @@ realpath1(const char *path, char *resolved) */ p = strchr(left, '/'); - next_token_len = p != NULL ? p - left : left_len; + next_token_len = p != NULL ? (size_t)(p - left) : left_len; memcpy(next_token, left, next_token_len); next_token[next_token_len] = '\0'; @@ -146,7 +146,7 @@ realpath1(const char *path, char *resolved) return (NULL); } slen = readlink(resolved, symlink, sizeof(symlink)); - if (slen <= 0 || slen >= sizeof(symlink)) { + if (slen <= 0 || slen >= (ssize_t)sizeof(symlink)) { if (slen < 0) ; /* keep errno from readlink(2) call */ else if (slen == 0) @@ -173,7 +173,7 @@ realpath1(const char *path, char *resolved) */ if (p != NULL) { if (symlink[slen - 1] != '/') { - if (slen + 1 >= sizeof(symlink)) { + if (slen + 1 >= (ssize_t)sizeof(symlink)) { errno = ENAMETOOLONG; return (NULL); } From e69dc8626a52ba77fbee80ced3b39edd2526d833 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Wed, 26 Jun 2019 15:43:26 +0000 Subject: [PATCH 128/165] Use rtld_putstr() instead of write() for the rtld msg() macro This removes an unnecessary libc dependency from rtld. See https://reviews.freebsd.org/D20663 for more details. --- libexec/rtld-elf/debug.h | 4 ++-- libexec/rtld-elf/rtld_printf.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libexec/rtld-elf/debug.h b/libexec/rtld-elf/debug.h index 1ad0323b42f9..4dcefbabdb45 100644 --- a/libexec/rtld-elf/debug.h +++ b/libexec/rtld-elf/debug.h @@ -37,7 +37,7 @@ #include #include -#include +#include "rtld_printf.h" void debug_printf(const char *, ...) __printflike(1, 2); extern int debug; @@ -57,7 +57,7 @@ extern int debug; #define assert(cond) ((cond) ? (void) 0 : \ (msg(_MYNAME ": assert failed: " __FILE__ ":" \ __XSTRING(__LINE__) "\n"), abort())) -#define msg(s) write(STDOUT_FILENO, s, strlen(s)) +#define msg(s) rtld_putstr(s) #define trace() msg(_MYNAME ": " __XSTRING(__LINE__) "\n") diff --git a/libexec/rtld-elf/rtld_printf.h b/libexec/rtld-elf/rtld_printf.h index 5cfcc6d062f1..3d3a0480ecce 100644 --- a/libexec/rtld-elf/rtld_printf.h +++ b/libexec/rtld-elf/rtld_printf.h @@ -31,6 +31,7 @@ #define RTLD_PRINTF_H 1 #include +#include #include int rtld_snprintf(char *buf, size_t bufsize, const char *fmt, ...) From c0c317d20314c1194007ab20e084ccda74bf71e5 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Wed, 26 Jun 2019 16:23:24 +0000 Subject: [PATCH 129/165] Fix qlxgbe(4) static build. MFC after: 2 weeks --- sys/conf/files.amd64 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64 index 1d399122c50c..81cd730a5c34 100644 --- a/sys/conf/files.amd64 +++ b/sys/conf/files.amd64 @@ -389,6 +389,9 @@ dev/qlxgbe/ql_isr.c optional qlxgbe pci dev/qlxgbe/ql_misc.c optional qlxgbe pci dev/qlxgbe/ql_os.c optional qlxgbe pci dev/qlxgbe/ql_reset.c optional qlxgbe pci +dev/qlxgbe/ql_fw.c optional qlxgbe pci +dev/qlxgbe/ql_boot.c optional qlxgbe pci +dev/qlxgbe/ql_minidump.c optional qlxgbe pci dev/qlnx/qlnxe/ecore_cxt.c optional qlnxe pci \ compile-with "${LINUXKPI_C}" dev/qlnx/qlnxe/ecore_dbg_fw_funcs.c optional qlnxe pci \ From 6137883ff33799642e0a72237076b036082106d3 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Wed, 26 Jun 2019 16:28:42 +0000 Subject: [PATCH 130/165] Remove references to splbio in ffs_softdep.c. Assert that the per-mountpoint softdep mutex is held in modified functions that do not already have this assertion. No functional change intended. Reviewed by: kib, mckusick (previous version) MFC after: 1 week Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D20741 --- sys/ufs/ffs/ffs_softdep.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c index 3a4a20b8565c..8d43e5528e18 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -2110,7 +2110,6 @@ pagedep_find(pagedephd, ino, lbn, pagedeppp) * Look up a pagedep. Return 1 if found, 0 otherwise. * If not found, allocate if DEPALLOC flag is passed. * Found or allocated entry is returned in pagedeppp. - * This routine must be called with splbio interrupts blocked. */ static int pagedep_lookup(mp, bp, ino, lbn, flags, pagedeppp) @@ -2202,7 +2201,6 @@ inodedep_find(inodedephd, inum, inodedeppp) * Look up an inodedep. Return 1 if found, 0 if not found. * If not found, allocate if DEPALLOC flag is passed. * Found or allocated entry is returned in inodedeppp. - * This routine must be called with splbio interrupts blocked. */ static int inodedep_lookup(mp, inum, flags, inodedeppp) @@ -5478,7 +5476,6 @@ jnewblk_merge(new, old, wkhd) /* * Replace an old allocdirect dependency with a newer one. - * This routine must be called with splbio interrupts blocked. */ static void allocdirect_merge(adphead, newadp, oldadp) @@ -7534,7 +7531,6 @@ free_newblk(newblk) /* * Free a newdirblk. Clear the NEWBLOCK flag on its associated pagedep. - * This routine must be called with splbio interrupts blocked. */ static void free_newdirblk(newdirblk) @@ -7665,7 +7661,6 @@ softdep_freefile(pvp, ino, mode) /* * Check to see if an inode has never been written to disk. If * so free the inodedep and return success, otherwise return failure. - * This routine must be called with splbio interrupts blocked. * * If we still have a bitmap dependency, then the inode has never * been written to disk. Drop the dependency as it is no longer @@ -8897,8 +8892,7 @@ cancel_diradd(dap, dirrem, jremref, dotremref, dotdotremref) } /* - * Free a diradd dependency structure. This routine must be called - * with splbio interrupts blocked. + * Free a diradd dependency structure. */ static void free_diradd(dap, wkhd) @@ -11195,9 +11189,7 @@ softdep_disk_write_complete(bp) } /* - * Called from within softdep_disk_write_complete above. Note that - * this routine is always called from interrupt level with further - * splbio interrupts blocked. + * Called from within softdep_disk_write_complete above. */ static void handle_allocdirect_partdone(adp, wkhd) @@ -11209,6 +11201,7 @@ handle_allocdirect_partdone(adp, wkhd) struct inodedep *inodedep; long bsize; + LOCK_OWNED(VFSTOUFS(adp->ad_block.nb_list.wk_mp)); if ((adp->ad_state & ALLCOMPLETE) != ALLCOMPLETE) return; /* @@ -11818,7 +11811,6 @@ handle_written_indirdep(indirdep, bp, bpp, flags) /* * Process a diradd entry after its dependent inode has been written. - * This routine must be called with splbio interrupts blocked. */ static void diradd_inode_written(dap, inodedep) @@ -11826,6 +11818,7 @@ diradd_inode_written(dap, inodedep) struct inodedep *inodedep; { + LOCK_OWNED(VFSTOUFS(dap->da_list.wk_mp)); dap->da_state |= COMPLETE; complete_diradd(dap); WORKLIST_INSERT(&inodedep->id_pendinghd, &dap->da_list); @@ -12386,8 +12379,7 @@ softdep_update_inodeblock(ip, bp, waitfor) /* * Merge the a new inode dependency list (such as id_newinoupdt) into an - * old inode dependency list (such as id_inoupdt). This routine must be - * called with splbio interrupts blocked. + * old inode dependency list (such as id_inoupdt). */ static void merge_inode_lists(newlisthead, oldlisthead) @@ -12397,6 +12389,8 @@ merge_inode_lists(newlisthead, oldlisthead) struct allocdirect *listadp, *newadp; newadp = TAILQ_FIRST(newlisthead); + if (newadp != NULL) + LOCK_OWNED(VFSTOUFS(newadp->ad_block.nb_list.wk_mp)); for (listadp = TAILQ_FIRST(oldlisthead); listadp && newadp;) { if (listadp->ad_offset < newadp->ad_offset) { listadp = TAILQ_NEXT(listadp, ad_next); @@ -12891,7 +12885,6 @@ softdep_sync_buf(struct vnode *vp, struct buf *bp, int waitfor) /* * Flush the dependencies associated with an inodedep. - * Called with splbio blocked. */ static int flush_inodedep_deps(vp, mp, ino) @@ -12956,7 +12949,6 @@ flush_inodedep_deps(vp, mp, ino) /* * Flush an inode dependency list. - * Called with splbio blocked. */ static int flush_deplist(listhead, waitfor, errorp) @@ -13098,7 +13090,6 @@ flush_newblk_dep(vp, mp, lbn) /* * Eliminate a pagedep dependency by flushing out all its diradd dependencies. - * Called with splbio blocked. */ static int flush_pagedep_deps(pvp, mp, diraddhdp) From 70b0aff9a1bec4453531408665655a6f679a4440 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Wed, 26 Jun 2019 16:30:14 +0000 Subject: [PATCH 131/165] libelftc: Micro-optimize string table insertion. The string's length is already known, so use memcpy() instead of strcpy() to add it to the string table image. Reviewed by: emaste MFC after: 1 week Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D20760 --- contrib/elftoolchain/libelftc/elftc_string_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/elftoolchain/libelftc/elftc_string_table.c b/contrib/elftoolchain/libelftc/elftc_string_table.c index c0da15eed794..c738fc64501e 100644 --- a/contrib/elftoolchain/libelftc/elftc_string_table.c +++ b/contrib/elftoolchain/libelftc/elftc_string_table.c @@ -119,7 +119,7 @@ elftc_string_table_add_to_pool(Elftc_String_Table *st, const char *string) st->st_string_pool_size = newsize; } - strcpy(st->st_string_pool + stlen, string); + memcpy(st->st_string_pool + stlen, string, len); ELFTC_STRING_TABLE_UPDATE_LENGTH(st, stlen + len); return (stlen); From b90eaf941f00efcbd64e28d8058a619dad3b81e4 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Wed, 26 Jun 2019 16:31:50 +0000 Subject: [PATCH 132/165] libelftc: Consistently use size_t for string table offsets and sizes. Reviewed by: emaste MFC after: 1 week Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D20702 --- .../libelftc/elftc_string_table.c | 35 ++++++++++--------- .../libelftc/elftc_string_table_create.3 | 6 ++-- contrib/elftoolchain/libelftc/libelftc.h | 4 +-- 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/contrib/elftoolchain/libelftc/elftc_string_table.c b/contrib/elftoolchain/libelftc/elftc_string_table.c index c738fc64501e..37fcc36d407b 100644 --- a/contrib/elftoolchain/libelftc/elftc_string_table.c +++ b/contrib/elftoolchain/libelftc/elftc_string_table.c @@ -44,7 +44,7 @@ ELFTC_VCSID("$Id: elftc_string_table.c 2869 2013-01-06 13:29:18Z jkoshy $"); #define ELFTC_STRING_TABLE_POOL_SIZE_INCREMENT (4*1024) struct _Elftc_String_Table_Entry { - int ste_idx; + ssize_t ste_idx; SLIST_ENTRY(_Elftc_String_Table_Entry) ste_next; }; @@ -64,9 +64,9 @@ struct _Elftc_String_Table_Entry { } while (0) struct _Elftc_String_Table { - unsigned int st_len; /* length and flags */ + size_t st_len; /* length and flags */ int st_nbuckets; - int st_string_pool_size; + size_t st_string_pool_size; char *st_string_pool; SLIST_HEAD(_Elftc_String_Table_Bucket, _Elftc_String_Table_Entry) st_buckets[]; @@ -86,7 +86,7 @@ elftc_string_table_find_hash_entry(Elftc_String_Table *st, const char *string, *rhashindex = hashindex; SLIST_FOREACH(ste, &st->st_buckets[hashindex], ste_next) { - s = st->st_string_pool + abs(ste->ste_idx); + s = st->st_string_pool + labs(ste->ste_idx); assert(s > st->st_string_pool && s < st->st_string_pool + st->st_string_pool_size); @@ -102,7 +102,7 @@ static int elftc_string_table_add_to_pool(Elftc_String_Table *st, const char *string) { char *newpool; - int len, newsize, stlen; + size_t len, newsize, stlen; len = strlen(string) + 1; /* length, including the trailing NUL */ stlen = ELFTC_STRING_TABLE_LENGTH(st); @@ -126,10 +126,10 @@ elftc_string_table_add_to_pool(Elftc_String_Table *st, const char *string) } Elftc_String_Table * -elftc_string_table_create(int sizehint) +elftc_string_table_create(size_t sizehint) { - int n, nbuckets, tablesize; struct _Elftc_String_Table *st; + int n, nbuckets, tablesize; if (sizehint < ELFTC_STRING_TABLE_DEFAULT_SIZE) sizehint = ELFTC_STRING_TABLE_DEFAULT_SIZE; @@ -173,13 +173,13 @@ elftc_string_table_destroy(Elftc_String_Table *st) } Elftc_String_Table * -elftc_string_table_from_section(Elf_Scn *scn, int sizehint) +elftc_string_table_from_section(Elf_Scn *scn, size_t sizehint) { - int len; Elf_Data *d; GElf_Shdr sh; const char *s, *end; Elftc_String_Table *st; + size_t len; /* Verify the type of the section passed in. */ if (gelf_getshdr(scn, &sh) == NULL || @@ -235,7 +235,8 @@ elftc_string_table_image(Elftc_String_Table *st, size_t *size) char *r, *s, *end; struct _Elftc_String_Table_Entry *ste; struct _Elftc_String_Table_Bucket *head; - int copied, hashindex, offset, length, newsize; + size_t copied, offset, length, newsize; + int hashindex; /* * For the common case of a string table has not seen @@ -303,8 +304,9 @@ elftc_string_table_image(Elftc_String_Table *st, size_t *size) size_t elftc_string_table_insert(Elftc_String_Table *st, const char *string) { - int hashindex, idx; struct _Elftc_String_Table_Entry *ste; + ssize_t idx; + int hashindex; hashindex = 0; @@ -326,7 +328,7 @@ elftc_string_table_insert(Elftc_String_Table *st, const char *string) idx = ste->ste_idx; if (idx < 0) /* Undelete. */ - ste->ste_idx = idx = (- idx); + ste->ste_idx = idx = -idx; return (idx); } @@ -334,8 +336,9 @@ elftc_string_table_insert(Elftc_String_Table *st, const char *string) size_t elftc_string_table_lookup(Elftc_String_Table *st, const char *string) { - int hashindex, idx; struct _Elftc_String_Table_Entry *ste; + ssize_t idx; + int hashindex; ste = elftc_string_table_find_hash_entry(st, string, &hashindex); @@ -350,17 +353,17 @@ elftc_string_table_lookup(Elftc_String_Table *st, const char *string) int elftc_string_table_remove(Elftc_String_Table *st, const char *string) { - int idx; struct _Elftc_String_Table_Entry *ste; + ssize_t idx; ste = elftc_string_table_find_hash_entry(st, string, NULL); if (ste == NULL || (idx = ste->ste_idx) < 0) return (ELFTC_FAILURE); - assert(idx > 0 && idx < (int) ELFTC_STRING_TABLE_LENGTH(st)); + assert(idx > 0 && (size_t)idx < ELFTC_STRING_TABLE_LENGTH(st)); - ste->ste_idx = (- idx); + ste->ste_idx = -idx; ELFTC_STRING_TABLE_SET_COMPACTION_FLAG(st); diff --git a/contrib/elftoolchain/libelftc/elftc_string_table_create.3 b/contrib/elftoolchain/libelftc/elftc_string_table_create.3 index 36c7290d9f46..813999a47180 100644 --- a/contrib/elftoolchain/libelftc/elftc_string_table_create.3 +++ b/contrib/elftoolchain/libelftc/elftc_string_table_create.3 @@ -24,7 +24,7 @@ .\" .\" $Id: elftc_string_table_create.3 3645 2018-10-15 20:17:14Z jkoshy $ .\" -.Dd January 5, 2013 +.Dd June 19, 2019 .Dt ELFTC_STRING_TABLE_CREATE 3 .Os .Sh NAME @@ -40,11 +40,11 @@ .Sh SYNOPSIS .In libelftc.h .Ft "Elftc_String_Table *" -.Fn elftc_string_table_create "int sizehint" +.Fn elftc_string_table_create "size_t sizehint" .Ft int .Fn elftc_string_table_destroy "Elftc_String_Table *table" .Ft "Elftc_String_Table *" -.Fn elftc_string_table_from_section "Elf_Scn *scn" "int sizehint" +.Fn elftc_string_table_from_section "Elf_Scn *scn" "size_t sizehint" .Ft "const char *" .Fo elftc_string_table_image .Fa "Elftc_String_Table *table" diff --git a/contrib/elftoolchain/libelftc/libelftc.h b/contrib/elftoolchain/libelftc/libelftc.h index a235097e6910..a404dfe34e9c 100644 --- a/contrib/elftoolchain/libelftc/libelftc.h +++ b/contrib/elftoolchain/libelftc/libelftc.h @@ -77,10 +77,10 @@ int elftc_demangle(const char *_mangledname, char *_buffer, size_t _bufsize, unsigned int _flags); const char *elftc_reloc_type_str(unsigned int mach, unsigned int type); int elftc_set_timestamps(const char *_filename, struct stat *_sb); -Elftc_String_Table *elftc_string_table_create(int _hint); +Elftc_String_Table *elftc_string_table_create(size_t _sizehint); void elftc_string_table_destroy(Elftc_String_Table *_table); Elftc_String_Table *elftc_string_table_from_section(Elf_Scn *_scn, - int _hint); + size_t _sizehint); const char *elftc_string_table_image(Elftc_String_Table *_table, size_t *_sz); size_t elftc_string_table_insert(Elftc_String_Table *_table, From 9810827a3a97a1f0d2f663701e9bf064b8c00e8c Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Wed, 26 Jun 2019 16:32:41 +0000 Subject: [PATCH 133/165] libelftc: Fix the documented prototype for elftc_string_table_destroy(). MFC after: 1 week Sponsored by: The FreeBSD Foundation --- contrib/elftoolchain/libelftc/elftc_string_table_create.3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/elftoolchain/libelftc/elftc_string_table_create.3 b/contrib/elftoolchain/libelftc/elftc_string_table_create.3 index 813999a47180..c3cf864af29c 100644 --- a/contrib/elftoolchain/libelftc/elftc_string_table_create.3 +++ b/contrib/elftoolchain/libelftc/elftc_string_table_create.3 @@ -41,7 +41,7 @@ .In libelftc.h .Ft "Elftc_String_Table *" .Fn elftc_string_table_create "size_t sizehint" -.Ft int +.Ft void .Fn elftc_string_table_destroy "Elftc_String_Table *table" .Ft "Elftc_String_Table *" .Fn elftc_string_table_from_section "Elf_Scn *scn" "size_t sizehint" From c8b057f4a76947a67916e659428583334d54c1a0 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Wed, 26 Jun 2019 16:35:37 +0000 Subject: [PATCH 134/165] elfcopy: Provide a size hint when creating the section string table. Use the input file's .shstrtab size as the hint if it exists. This gives a small performance improvement when processing files with many sections. Reviewed by: emaste MFC after: 1 week Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D20544 --- contrib/elftoolchain/elfcopy/sections.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/contrib/elftoolchain/elfcopy/sections.c b/contrib/elftoolchain/elfcopy/sections.c index 93dbf4422863..2bd094d2bfbe 100644 --- a/contrib/elftoolchain/elfcopy/sections.c +++ b/contrib/elftoolchain/elfcopy/sections.c @@ -1398,7 +1398,23 @@ update_shdr(struct elfcopy *ecp, int update_link) void init_shstrtab(struct elfcopy *ecp) { + Elf_Scn *shstrtab; + GElf_Shdr shdr; struct section *s; + size_t indx, sizehint; + + if (elf_getshstrndx(ecp->ein, &indx) != 0) { + shstrtab = elf_getscn(ecp->ein, indx); + if (shstrtab == NULL) + errx(EXIT_FAILURE, "elf_getscn failed: %s", + elf_errmsg(-1)); + if (gelf_getshdr(shstrtab, &shdr) != &shdr) + errx(EXIT_FAILURE, "gelf_getshdr failed: %s", + elf_errmsg(-1)); + sizehint = shdr.sh_size; + } else { + sizehint = 0; + } if ((ecp->shstrtab = calloc(1, sizeof(*ecp->shstrtab))) == NULL) err(EXIT_FAILURE, "calloc failed"); @@ -1410,7 +1426,7 @@ init_shstrtab(struct elfcopy *ecp) s->loadable = 0; s->type = SHT_STRTAB; s->vma = 0; - s->strtab = elftc_string_table_create(0); + s->strtab = elftc_string_table_create(sizehint); add_to_shstrtab(ecp, ""); add_to_shstrtab(ecp, ".symtab"); From ab69795fcd38f94bda3e409ee08dc66a126e833a Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Wed, 26 Jun 2019 16:38:30 +0000 Subject: [PATCH 135/165] libdwarf: Use the cached strtab pointer when reading string attributes. Previously we would perform a linear search of the DWARF section list for ".debug_str". However, libdwarf always caches a pointer to the strtab image in its debug descriptor. Using it gives a modest performance improvement when iterating over the attributes of each DIE. Reviewed by: emaste MFC after: 1 week Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D20759 --- contrib/elftoolchain/libdwarf/libdwarf_attr.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/contrib/elftoolchain/libdwarf/libdwarf_attr.c b/contrib/elftoolchain/libdwarf/libdwarf_attr.c index dfbbc484c352..ea05374d051c 100644 --- a/contrib/elftoolchain/libdwarf/libdwarf_attr.c +++ b/contrib/elftoolchain/libdwarf/libdwarf_attr.c @@ -100,7 +100,6 @@ _dwarf_attr_init(Dwarf_Debug dbg, Dwarf_Section *ds, uint64_t *offsetp, uint64_t form, int indirect, Dwarf_Error *error) { struct _Dwarf_Attribute atref; - Dwarf_Section *str; int ret; ret = DW_DLE_NONE; @@ -183,9 +182,7 @@ _dwarf_attr_init(Dwarf_Debug dbg, Dwarf_Section *ds, uint64_t *offsetp, break; case DW_FORM_strp: atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, dwarf_size); - str = _dwarf_find_section(dbg, ".debug_str"); - assert(str != NULL); - atref.u[1].s = (char *) str->ds_data + atref.u[0].u64; + atref.u[1].s = _dwarf_strtab_get_table(dbg) + atref.u[0].u64; break; case DW_FORM_ref_sig8: atref.u[0].u64 = 8; From b726d74fced41e32cd1128265a3a0915dc58ea94 Mon Sep 17 00:00:00 2001 From: Olivier Houchard Date: Wed, 26 Jun 2019 16:56:56 +0000 Subject: [PATCH 136/165] Fix debugging of 32bits arm binaries on arm64. In set_regs32()/fill_regs32(), we have to get/set SP and LR from/to tf_x[13] and tf_x[14]. set_regs() and fill_regs() may be called for a 32bits process, if the process is ptrace'd from a 64bits debugger. So, in set_regs() and fill_regs(), get or set PC and SPSR from where the debugger expects it, from tf_x[15] and tf_x[16]. --- sys/arm64/arm64/machdep.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/sys/arm64/arm64/machdep.c b/sys/arm64/arm64/machdep.c index b8ecfc08e676..4356add12aa0 100644 --- a/sys/arm64/arm64/machdep.c +++ b/sys/arm64/arm64/machdep.c @@ -194,6 +194,16 @@ fill_regs(struct thread *td, struct reg *regs) memcpy(regs->x, frame->tf_x, sizeof(regs->x)); +#ifdef COMPAT_FREEBSD32 + /* + * We may be called here for a 32bits process, if we're using a + * 64bits debugger. If so, put PC and SPSR where it expects it. + */ + if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) { + regs->x[15] = frame->tf_elr; + regs->x[16] = frame->tf_spsr; + } +#endif return (0); } @@ -211,6 +221,17 @@ set_regs(struct thread *td, struct reg *regs) memcpy(frame->tf_x, regs->x, sizeof(frame->tf_x)); +#ifdef COMPAT_FREEBSD32 + if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) { + /* + * We may be called for a 32bits process if we're using + * a 64bits debugger. If so, get PC and SPSR from where + * it put it. + */ + frame->tf_elr = regs->x[15]; + frame->tf_spsr = regs->x[16] & PSR_FLAGS; + } +#endif return (0); } @@ -283,8 +304,9 @@ fill_regs32(struct thread *td, struct reg32 *regs) tf = td->td_frame; for (i = 0; i < 13; i++) regs->r[i] = tf->tf_x[i]; - regs->r_sp = tf->tf_sp; - regs->r_lr = tf->tf_lr; + /* For arm32, SP is r13 and LR is r14 */ + regs->r_sp = tf->tf_x[13]; + regs->r_lr = tf->tf_x[14]; regs->r_pc = tf->tf_elr; regs->r_cpsr = tf->tf_spsr; @@ -300,8 +322,9 @@ set_regs32(struct thread *td, struct reg32 *regs) tf = td->td_frame; for (i = 0; i < 13; i++) tf->tf_x[i] = regs->r[i]; - tf->tf_sp = regs->r_sp; - tf->tf_lr = regs->r_lr; + /* For arm 32, SP is r13 an LR is r14 */ + tf->tf_x[13] = regs->r_sp; + tf->tf_x[14] = regs->r_lr; tf->tf_elr = regs->r_pc; tf->tf_spsr = regs->r_cpsr; From 7256d0fcfd20d10fd80136b6144ace6ca9c83372 Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Wed, 26 Jun 2019 17:16:26 +0000 Subject: [PATCH 137/165] amd64 pmap: Fix pkru handling in pmap_remove(). When pmap_pkru_on_remove() is called, the sva argument value was advanced. Clear PKRU earlier when sva still specifies the start of the region. Noted and reviewed by: alc Sponsored by: The FreeBSD Foundation MFC after: 3 days --- sys/amd64/amd64/pmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c index 3b3f4b4200ff..a0a2eb0baa6b 100644 --- a/sys/amd64/amd64/pmap.c +++ b/sys/amd64/amd64/pmap.c @@ -4998,6 +4998,7 @@ pmap_remove(pmap_t pmap, vm_offset_t sva, vm_offset_t eva) pmap_delayed_invl_start(); PMAP_LOCK(pmap); + pmap_pkru_on_remove(pmap, sva, eva); /* * special handling of removing one page. a very @@ -5091,7 +5092,6 @@ pmap_remove(pmap_t pmap, vm_offset_t sva, vm_offset_t eva) out: if (anyvalid) pmap_invalidate_all(pmap); - pmap_pkru_on_remove(pmap, sva, eva); PMAP_UNLOCK(pmap); pmap_delayed_invl_finish(); vm_page_free_pages_toq(&free, true); From 926c3367c8dd9bf69c81699618ce2a71c6fa7bc3 Mon Sep 17 00:00:00 2001 From: Andriy Gapon Date: Wed, 26 Jun 2019 17:17:33 +0000 Subject: [PATCH 138/165] owc_gpiobus: clean / fix up the driver module things "fdt" is removed from the driver module name as the driver does not require FDT and can work very well on hints based systems. A module dependency is added for gpiobus. Without that owc cannot resolve symbols in gpiobus if both are loaded as kernel modules. Finally, a driver module module version is added. Reviewed by: imp MFC after: 11 days --- sys/dev/ow/owc_gpiobus.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sys/dev/ow/owc_gpiobus.c b/sys/dev/ow/owc_gpiobus.c index f03d01432b03..ef501f14d481 100644 --- a/sys/dev/ow/owc_gpiobus.c +++ b/sys/dev/ow/owc_gpiobus.c @@ -416,5 +416,7 @@ static driver_t owc_gpiobus_driver = { sizeof(struct owc_gpiobus_softc), }; -DRIVER_MODULE(owc_gpiobus_fdt, gpiobus, owc_gpiobus_driver, owc_gpiobus_devclass, 0, 0); -MODULE_DEPEND(owc_gpiobus_fdt, ow, 1, 1, 1); +DRIVER_MODULE(owc_gpiobus, gpiobus, owc_gpiobus_driver, owc_gpiobus_devclass, 0, 0); +MODULE_DEPEND(owc_gpiobust, ow, 1, 1, 1); +MODULE_DEPEND(owc_gpiobus, gpiobus, 1, 1, 1); +MODULE_VERSION(owc_gpiobus, 1); From 0fd977b3fa32d54b61554416363faae8a7bfaa2b Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Wed, 26 Jun 2019 17:37:51 +0000 Subject: [PATCH 139/165] Add a return value to vm_page_remove(). Use it to indicate whether the page may be safely freed following its removal from the object. Also change vm_page_remove() to assume that the page's object pointer is non-NULL, and have callers perform this check instead. This is a step towards an implementation of an atomic reference counter for each physical page structure. Reviewed by: alc, dougm, kib MFC after: 1 week Sponsored by: Netflix Differential Revision: https://reviews.freebsd.org/D20758 --- sys/amd64/sgx/sgx.c | 2 +- sys/dev/drm2/ttm/ttm_bo_vm.c | 2 +- sys/vm/device_pager.c | 2 +- sys/vm/vm_fault.c | 2 +- sys/vm/vm_object.c | 8 ++------ sys/vm/vm_page.c | 15 +++++++++------ sys/vm/vm_page.h | 2 +- 7 files changed, 16 insertions(+), 17 deletions(-) diff --git a/sys/amd64/sgx/sgx.c b/sys/amd64/sgx/sgx.c index d47d4a3596a5..3d45b60de3ef 100644 --- a/sys/amd64/sgx/sgx.c +++ b/sys/amd64/sgx/sgx.c @@ -358,7 +358,7 @@ sgx_page_remove(struct sgx_softc *sc, vm_page_t p) uint64_t offs; vm_page_lock(p); - vm_page_remove(p); + (void)vm_page_remove(p); vm_page_unlock(p); dprintf("%s: p->pidx %ld\n", __func__, p->pindex); diff --git a/sys/dev/drm2/ttm/ttm_bo_vm.c b/sys/dev/drm2/ttm/ttm_bo_vm.c index 6f7184857ce6..43d027fc5cd9 100644 --- a/sys/dev/drm2/ttm/ttm_bo_vm.c +++ b/sys/dev/drm2/ttm/ttm_bo_vm.c @@ -115,7 +115,7 @@ ttm_bo_vm_fault(vm_object_t vm_obj, vm_ooffset_t offset, vm_object_pip_add(vm_obj, 1); if (*mres != NULL) { vm_page_lock(*mres); - vm_page_remove(*mres); + (void)vm_page_remove(*mres); vm_page_unlock(*mres); } retry: diff --git a/sys/vm/device_pager.c b/sys/vm/device_pager.c index c27d60869def..7dce4778f951 100644 --- a/sys/vm/device_pager.c +++ b/sys/vm/device_pager.c @@ -236,7 +236,7 @@ cdev_pager_free_page(vm_object_t object, vm_page_t m) KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("unmanaged %p", m)); pmap_remove_all(m); vm_page_lock(m); - vm_page_remove(m); + (void)vm_page_remove(m); vm_page_unlock(m); } else if (object->type == OBJT_DEVICE) dev_pager_free_page(object, m); diff --git a/sys/vm/vm_fault.c b/sys/vm/vm_fault.c index 4268db264d52..ae0103595ae7 100644 --- a/sys/vm/vm_fault.c +++ b/sys/vm/vm_fault.c @@ -1144,7 +1144,7 @@ RetryFault:; fs.object == fs.first_object->backing_object) { vm_page_lock(fs.m); vm_page_dequeue(fs.m); - vm_page_remove(fs.m); + (void)vm_page_remove(fs.m); vm_page_unlock(fs.m); vm_page_lock(fs.first_m); vm_page_replace_checked(fs.m, fs.first_object, diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c index 9fd90f04b6d9..7c3575e646cf 100644 --- a/sys/vm/vm_object.c +++ b/sys/vm/vm_object.c @@ -1595,10 +1595,8 @@ vm_object_collapse_scan(vm_object_t object, int op) vm_page_lock(p); KASSERT(!pmap_page_is_mapped(p), ("freeing mapped page %p", p)); - if (!vm_page_wired(p)) + if (vm_page_remove(p)) vm_page_free(p); - else - vm_page_remove(p); vm_page_unlock(p); continue; } @@ -1639,10 +1637,8 @@ vm_object_collapse_scan(vm_object_t object, int op) vm_page_lock(p); KASSERT(!pmap_page_is_mapped(p), ("freeing mapped page %p", p)); - if (!vm_page_wired(p)) + if (vm_page_remove(p)) vm_page_free(p); - else - vm_page_remove(p); vm_page_unlock(p); continue; } diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c index a90961ce57b5..e43817b812a0 100644 --- a/sys/vm/vm_page.c +++ b/sys/vm/vm_page.c @@ -1458,20 +1458,21 @@ vm_page_insert_radixdone(vm_page_t m, vm_object_t object, vm_page_t mpred) * vm_page_remove: * * Removes the specified page from its containing object, but does not - * invalidate any backing storage. + * invalidate any backing storage. Return true if the page may be safely + * freed and false otherwise. * * The object must be locked. The page must be locked if it is managed. */ -void +bool vm_page_remove(vm_page_t m) { vm_object_t object; vm_page_t mrem; + object = m->object; + if ((m->oflags & VPO_UNMANAGED) == 0) vm_page_assert_locked(m); - if ((object = m->object) == NULL) - return; VM_OBJECT_ASSERT_WLOCKED(object); if (vm_page_xbusied(m)) vm_page_xunbusy_maybelocked(m); @@ -1495,6 +1496,7 @@ vm_page_remove(vm_page_t m) vdrop(object->handle); m->object = NULL; + return (!vm_page_wired(m)); } /* @@ -1665,7 +1667,7 @@ vm_page_rename(vm_page_t m, vm_object_t new_object, vm_pindex_t new_pindex) */ m->pindex = opidx; vm_page_lock(m); - vm_page_remove(m); + (void)vm_page_remove(m); /* Return back to the new pindex to complete vm_page_insert(). */ m->pindex = new_pindex; @@ -3436,7 +3438,8 @@ vm_page_free_prep(vm_page_t m) if (vm_page_sbusied(m)) panic("vm_page_free_prep: freeing busy page %p", m); - vm_page_remove(m); + if (m->object != NULL) + (void)vm_page_remove(m); /* * If fictitious remove object association and diff --git a/sys/vm/vm_page.h b/sys/vm/vm_page.h index d1938d2a1bd8..57f9f6e9081c 100644 --- a/sys/vm/vm_page.h +++ b/sys/vm/vm_page.h @@ -561,7 +561,7 @@ bool vm_page_reclaim_contig(int req, u_long npages, vm_paddr_t low, bool vm_page_reclaim_contig_domain(int domain, int req, u_long npages, vm_paddr_t low, vm_paddr_t high, u_long alignment, vm_paddr_t boundary); void vm_page_reference(vm_page_t m); -void vm_page_remove (vm_page_t); +bool vm_page_remove(vm_page_t); int vm_page_rename (vm_page_t, vm_object_t, vm_pindex_t); vm_page_t vm_page_replace(vm_page_t mnew, vm_object_t object, vm_pindex_t pindex); From b66ed8ee28ec18a5f74cd1ab85e23497899f97f4 Mon Sep 17 00:00:00 2001 From: Andriy Gapon Date: Wed, 26 Jun 2019 17:38:38 +0000 Subject: [PATCH 140/165] fix up r349428, fix a typo made during "fdt" removal Reported by: ian MFC after: 11 days --- sys/dev/ow/owc_gpiobus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/dev/ow/owc_gpiobus.c b/sys/dev/ow/owc_gpiobus.c index ef501f14d481..24a18789bea8 100644 --- a/sys/dev/ow/owc_gpiobus.c +++ b/sys/dev/ow/owc_gpiobus.c @@ -417,6 +417,6 @@ static driver_t owc_gpiobus_driver = { }; DRIVER_MODULE(owc_gpiobus, gpiobus, owc_gpiobus_driver, owc_gpiobus_devclass, 0, 0); -MODULE_DEPEND(owc_gpiobust, ow, 1, 1, 1); +MODULE_DEPEND(owc_gpiobus, ow, 1, 1, 1); MODULE_DEPEND(owc_gpiobus, gpiobus, 1, 1, 1); MODULE_VERSION(owc_gpiobus, 1); From a3ae40c7a4681adb45ea73b26c3fdad1e4286b54 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Wed, 26 Jun 2019 20:11:52 +0000 Subject: [PATCH 141/165] Avoid a divide-by-zero when bad checksum counters overflow. A mixture of IP or UDP packets with valid and invalid checksum could cause {ip,udp}_packets_bad_checksum to wrap around to 0, resulting in a division by zero. This is packet.c rev. 1.27 from OpenBSD. admbugs: 552 Obtained from: OpenBSD MFC after: 3 days --- sbin/dhclient/packet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sbin/dhclient/packet.c b/sbin/dhclient/packet.c index 2328d577386d..21726aaaeb84 100644 --- a/sbin/dhclient/packet.c +++ b/sbin/dhclient/packet.c @@ -183,7 +183,7 @@ decode_udp_ip_header(unsigned char *buf, int bufix, struct sockaddr_in *from, ip_packets_seen++; if (wrapsum(checksum(buf + bufix, ip_len, 0)) != 0) { ip_packets_bad_checksum++; - if (ip_packets_seen > 4 && + if (ip_packets_seen > 4 && ip_packets_bad_checksum != 0 && (ip_packets_seen / ip_packets_bad_checksum) < 2) { note("%d bad IP checksums seen in %d packets", ip_packets_bad_checksum, ip_packets_seen); @@ -235,7 +235,7 @@ decode_udp_ip_header(unsigned char *buf, int bufix, struct sockaddr_in *from, udp_packets_seen++; if (usum && usum != sum) { udp_packets_bad_checksum++; - if (udp_packets_seen > 4 && + if (udp_packets_seen > 4 && udp_packets_bad_checksum != 0 && (udp_packets_seen / udp_packets_bad_checksum) < 2) { note("%d bad udp checksums in %d packets", udp_packets_bad_checksum, udp_packets_seen); From 5baf985da7a0cf19e9f03cd1b35265a38c68762d Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Wed, 26 Jun 2019 20:19:48 +0000 Subject: [PATCH 142/165] Free DHCP options with length zero. Otherwise they are leaked, allowing an attacker to trigger memory exhaustion. This is options.c rev. 1.70 from OpenBSD. admbugs: 552 Obtained from: OpenBSD MFC after: 3 days --- sbin/dhclient/options.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sbin/dhclient/options.c b/sbin/dhclient/options.c index 3b05e3ff1889..dc4cceab8418 100644 --- a/sbin/dhclient/options.c +++ b/sbin/dhclient/options.c @@ -896,6 +896,5 @@ do_packet(struct interface_info *interface, struct dhcp_packet *packet, /* Free the data associated with the options. */ for (i = 0; i < 256; i++) - if (tp.options[i].len && tp.options[i].data) - free(tp.options[i].data); + free(tp.options[i].data); } From e4da41f932a5415ec01d08e97ff2cde948afa073 Mon Sep 17 00:00:00 2001 From: "Rodney W. Grimes" Date: Wed, 26 Jun 2019 21:19:43 +0000 Subject: [PATCH 143/165] Emulate the "TEST r/m{16,32,64}, imm{16,32,32}" instructions (opcode F7H). This adds emulation for: test r/m16, imm16 test r/m32, imm32 test r/m64, imm32 sign-extended to 64 OpenBSD guests compiled with clang 8.0.0 use TEST directly against a Local APIC register instead of separate read via MOV followed by a TEST against the register. PR: 238794 Submitted by: jhb Reported by: Jason Tubnor jason@tubnor.net Tested by: Jason Tubnor jason@tubnor.net Reviewed by: markj, Patrick Mooney patrick.mooney@joyent.com MFC after: 3 days Differential Revision: https://reviews.freebsd.org/D20755 --- sys/amd64/vmm/vmm_instruction_emul.c | 95 ++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/sys/amd64/vmm/vmm_instruction_emul.c b/sys/amd64/vmm/vmm_instruction_emul.c index 230da1881ef0..f3afa23d8281 100644 --- a/sys/amd64/vmm/vmm_instruction_emul.c +++ b/sys/amd64/vmm/vmm_instruction_emul.c @@ -78,6 +78,7 @@ enum { VIE_OP_TYPE_BITTEST, VIE_OP_TYPE_TWOB_GRP15, VIE_OP_TYPE_ADD, + VIE_OP_TYPE_TEST, VIE_OP_TYPE_LAST }; @@ -221,6 +222,12 @@ static const struct vie_op one_byte_opcodes[256] = { .op_byte = 0x8F, .op_type = VIE_OP_TYPE_POP, }, + [0xF7] = { + /* XXX Group 3 extended opcode - not just TEST */ + .op_byte = 0xF7, + .op_type = VIE_OP_TYPE_TEST, + .op_flags = VIE_OP_F_IMM, + }, [0xFF] = { /* XXX Group 5 extended opcode - not just PUSH */ .op_byte = 0xFF, @@ -450,6 +457,41 @@ getaddflags(int opsize, uint64_t x, uint64_t y) return (getaddflags64(x, y)); } +/* + * Return the status flags that would result from doing (x & y). + */ +#define GETANDFLAGS(sz) \ +static u_long \ +getandflags##sz(uint##sz##_t x, uint##sz##_t y) \ +{ \ + u_long rflags; \ + \ + __asm __volatile("and %2,%1; pushfq; popq %0" : \ + "=r" (rflags), "+r" (x) : "m" (y)); \ + return (rflags); \ +} struct __hack + +GETANDFLAGS(8); +GETANDFLAGS(16); +GETANDFLAGS(32); +GETANDFLAGS(64); + +static u_long +getandflags(int opsize, uint64_t x, uint64_t y) +{ + KASSERT(opsize == 1 || opsize == 2 || opsize == 4 || opsize == 8, + ("getandflags: invalid operand size %d", opsize)); + + if (opsize == 1) + return (getandflags8(x, y)); + else if (opsize == 2) + return (getandflags16(x, y)); + else if (opsize == 4) + return (getandflags32(x, y)); + else + return (getandflags64(x, y)); +} + static int emulate_mov(void *vm, int vcpuid, uint64_t gpa, struct vie *vie, mem_region_read_t memread, mem_region_write_t memwrite, void *arg) @@ -1218,6 +1260,55 @@ emulate_cmp(void *vm, int vcpuid, uint64_t gpa, struct vie *vie, return (error); } +static int +emulate_test(void *vm, int vcpuid, uint64_t gpa, struct vie *vie, + mem_region_read_t memread, mem_region_write_t memwrite, void *arg) +{ + int error, size; + uint64_t op1, rflags, rflags2; + + size = vie->opsize; + error = EINVAL; + + switch (vie->op.op_byte) { + case 0xF7: + /* + * F7 /0 test r/m16, imm16 + * F7 /0 test r/m32, imm32 + * REX.W + F7 /0 test r/m64, imm32 sign-extended to 64 + * + * Test mem (ModRM:r/m) with immediate and set status + * flags according to the results. The comparison is + * performed by anding the immediate from the first + * operand and then setting the status flags. + */ + if ((vie->reg & 7) != 0) + return (EINVAL); + + error = memread(vm, vcpuid, gpa, &op1, size, arg); + if (error) + return (error); + + rflags2 = getandflags(size, op1, vie->immediate); + break; + default: + return (EINVAL); + } + error = vie_read_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, &rflags); + if (error) + return (error); + + /* + * OF and CF are cleared; the SF, ZF and PF flags are set according + * to the result; AF is undefined. + */ + rflags &= ~RFLAGS_STATUS_BITS; + rflags |= rflags2 & (PSL_PF | PSL_Z | PSL_N); + + error = vie_update_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, rflags, 8); + return (error); +} + static int emulate_add(void *vm, int vcpuid, uint64_t gpa, struct vie *vie, mem_region_read_t memread, mem_region_write_t memwrite, void *arg) @@ -1643,6 +1734,10 @@ vmm_emulate_instruction(void *vm, int vcpuid, uint64_t gpa, struct vie *vie, error = emulate_add(vm, vcpuid, gpa, vie, memread, memwrite, memarg); break; + case VIE_OP_TYPE_TEST: + error = emulate_test(vm, vcpuid, gpa, vie, + memread, memwrite, memarg); + break; default: error = EINVAL; break; From 1d3423d9142734691351e32d7ce4bc65d3c6e903 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 26 Jun 2019 21:43:41 +0000 Subject: [PATCH 144/165] Revert one of the changes from r349323. Specifically, undo the change that replaced a pmap_invalidate_page() with a dsb(ishst) in pmap_enter_quick_locked(). Even though this change is in principle correct, I am seeing occasional, spurious bus errors that are only reproducible without this pmap_invalidate_page(). (None of adding an isb, "upgrading" the dsb to wait on loads as well as stores, or disabling superpage mappings eliminates the bus errors.) Add an XXX comment explaining why the pmap_invalidate_page() is being performed. Discussed with: andrew, markj --- sys/arm64/arm64/pmap.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sys/arm64/arm64/pmap.c b/sys/arm64/arm64/pmap.c index ff0c0611743e..bf74bb55f038 100644 --- a/sys/arm64/arm64/pmap.c +++ b/sys/arm64/arm64/pmap.c @@ -3758,7 +3758,15 @@ pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, cpu_icache_sync_range(PHYS_TO_DMAP(pa), PAGE_SIZE); pmap_load_store(l3, l3_val); - dsb(ishst); + + /* + * XXX In principle, because this L3 entry was invalid, we should not + * need to perform a TLB invalidation here. However, in practice, + * when simply performing a "dsb ishst" here, processes are being + * terminated due to bus errors and segmentation violations. + */ + pmap_invalidate_page(pmap, va); + return (mpte); } From 84322e3ee3b5ce7ad02a5939ac9dcc31c2b04190 Mon Sep 17 00:00:00 2001 From: Olivier Houchard Date: Wed, 26 Jun 2019 22:06:40 +0000 Subject: [PATCH 145/165] In get_fpcontext32() and set_fpcontext32(), we can't just use memcpy() to copy the VFP registers. arvm7 VFP uses 32 64bits fp registers (but those could be used in pairs to make 16 128bits registers), while aarch64 uses 32 128bits fp registers, so we have to copy the value of each register. --- sys/arm64/arm64/freebsd32_machdep.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sys/arm64/arm64/freebsd32_machdep.c b/sys/arm64/arm64/freebsd32_machdep.c index aeac4605f2f5..2e25fe062b19 100644 --- a/sys/arm64/arm64/freebsd32_machdep.c +++ b/sys/arm64/arm64/freebsd32_machdep.c @@ -122,6 +122,7 @@ static void get_fpcontext32(struct thread *td, mcontext32_vfp_t *mcp) { struct pcb *curpcb; + int i; critical_enter(); curpcb = curthread->td_pcb; @@ -137,8 +138,8 @@ get_fpcontext32(struct thread *td, mcontext32_vfp_t *mcp) ("Called get_fpcontext while the kernel is using the VFP")); KASSERT((curpcb->pcb_fpflags & ~PCB_FP_USERMASK) == 0, ("Non-userspace FPU flags set in get_fpcontext")); - memcpy(mcp->mcv_reg, curpcb->pcb_fpustate.vfp_regs, - sizeof(mcp->mcv_reg)); + for (i = 0; i < 32; i++) + mcp->mcv_reg[i] = (uint64_t)curpcb->pcb_fpustate.vfp_regs[i]; mcp->mcv_fpscr = VFP_FPSCR_FROM_SRCR(curpcb->pcb_fpustate.vfp_fpcr, curpcb->pcb_fpustate.vfp_fpsr); } @@ -149,13 +150,14 @@ static void set_fpcontext32(struct thread *td, mcontext32_vfp_t *mcp) { struct pcb *pcb; + int i; critical_enter(); pcb = td->td_pcb; if (td == curthread) vfp_discard(td); - memcpy(pcb->pcb_fpustate.vfp_regs, mcp->mcv_reg, - sizeof(pcb->pcb_fpustate.vfp_regs)); + for (i = 0; i < 32; i++) + pcb->pcb_fpustate.vfp_regs[i] = mcp->mcv_reg[i]; pcb->pcb_fpustate.vfp_fpsr = VFP_FPSR_FROM_FPSCR(mcp->mcv_fpscr); pcb->pcb_fpustate.vfp_fpcr = VFP_FPSR_FROM_FPSCR(mcp->mcv_fpscr); critical_exit(); From f9510887eeb5ad2eab96b48c41631886f8f33ad6 Mon Sep 17 00:00:00 2001 From: "Simon J. Gerraty" Date: Wed, 26 Jun 2019 23:33:32 +0000 Subject: [PATCH 146/165] libsecureboot: allow OpenPGP support to be dormant Since we can now add OpenPGP trust anchors at runtime, ensure the latent support is available. Ensure we do not add duplicate keys to trust store. Also allow reporting names of trust anchors added/revoked We only do this for loader and only after initializing trust store. Thus only changes to initial trust store will be logged. Reviewed by: stevek MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D20700 --- lib/libsecureboot/h/libsecureboot.h | 5 + lib/libsecureboot/libsecureboot-priv.h | 2 + lib/libsecureboot/local.trust.mk | 9 ++ lib/libsecureboot/openpgp/opgp_key.c | 49 ++++++++- lib/libsecureboot/readfile.c | 39 ++++--- lib/libsecureboot/verify_file.c | 29 +++++- lib/libsecureboot/vets.c | 138 +++++++++++++++++++++++-- 7 files changed, 240 insertions(+), 31 deletions(-) diff --git a/lib/libsecureboot/h/libsecureboot.h b/lib/libsecureboot/h/libsecureboot.h index 81984fde5f3e..d7d72e880744 100644 --- a/lib/libsecureboot/h/libsecureboot.h +++ b/lib/libsecureboot/h/libsecureboot.h @@ -42,6 +42,7 @@ #include +unsigned char * read_fd(int, size_t); #ifndef NEED_BRSSL_H unsigned char * read_file(const char *, size_t *); #endif @@ -51,8 +52,12 @@ extern int DebugVe; #define DEBUG_PRINTF(n, x) if (DebugVe >= n) printf x int ve_trust_init(void); +size_t ve_trust_anchors_add_buf(unsigned char *, size_t); +size_t ve_trust_anchors_revoke(unsigned char *, size_t); int ve_trust_add(const char *); void ve_debug_set(int); +void ve_anchor_verbose_set(int); +int ve_anchor_verbose_get(void); void ve_utc_set(time_t utc); char *ve_error_get(void); int ve_error_set(const char *, ...) __printflike(1,2); diff --git a/lib/libsecureboot/libsecureboot-priv.h b/lib/libsecureboot/libsecureboot-priv.h index c6a90d2c7404..bdf0c5c0c9bb 100644 --- a/lib/libsecureboot/libsecureboot-priv.h +++ b/lib/libsecureboot/libsecureboot-priv.h @@ -56,6 +56,8 @@ int is_verified(struct stat *stp); void add_verify_status(struct stat *stp, int status); int openpgp_trust_init(void); +int openpgp_trust_add_buf(unsigned char *, size_t); +int openpgp_trust_revoke(const char *); int openpgp_self_tests(void); int efi_secure_boot_enabled(void); diff --git a/lib/libsecureboot/local.trust.mk b/lib/libsecureboot/local.trust.mk index 4ba4c862e929..b28e5ee2d1ef 100644 --- a/lib/libsecureboot/local.trust.mk +++ b/lib/libsecureboot/local.trust.mk @@ -33,6 +33,10 @@ VE_SIGNATURE_EXT_LIST+= \ sig .endif +# add OpenPGP support - possibly dormant +VE_SIGNATURE_LIST+= OPENPGP +VE_SIGNATURE_EXT_LIST+= asc + SIGNER ?= ${SB_TOOLS_PATH:U/volume/buildtools/bin}/sign.py .if exists(${SIGNER}) @@ -42,7 +46,12 @@ SIGN_ECDSA= ${PYTHON} ${SIGNER} -u ${SIGN_HOST}:${ECDSA_PORT} -h sha256 RSA2_PORT:= ${163%y:L:gmtime} SIGN_RSA2= ${PYTHON} ${SIGNER} -u ${SIGN_HOST}:${RSA2_PORT} -h sha256 +# deal with quirk of our .esig format +XCFLAGS.vets+= -DVE_ECDSA_HASH_AGAIN + .if !empty(OPENPGP_SIGN_URL) +XCFLAGS.opgp_key+= -DHAVE_TA_ASC_H + VE_SIGNATURE_LIST+= OPENPGP VE_SIGNATURE_EXT_LIST+= asc diff --git a/lib/libsecureboot/openpgp/opgp_key.c b/lib/libsecureboot/openpgp/opgp_key.c index dc0d8fa2934d..c108cd2fa328 100644 --- a/lib/libsecureboot/openpgp/opgp_key.c +++ b/lib/libsecureboot/openpgp/opgp_key.c @@ -209,12 +209,53 @@ openpgp_trust_add(OpenPGP_key *key) LIST_INIT(&trust_list); } - if (key) { - DEBUG_PRINTF(2, ("openpgp_trust_add(%s)\n", key->id)); + if (key && openpgp_trust_get(key->id) == NULL) { + if (ve_anchor_verbose_get()) + printf("openpgp_trust_add(%s)\n", key->id); LIST_INSERT_HEAD(&trust_list, key, entries); } } +/** + * @brief add trust anchor from buf + */ +int +openpgp_trust_add_buf(unsigned char *buf, size_t nbytes) +{ + OpenPGP_key *key; + + if ((key = load_key_buf(buf, nbytes))) { + openpgp_trust_add(key); + } + return (key != NULL); +} + + +/** + * @brief if keyID is in our list clobber it + * + * @return true if keyID removed + */ +int +openpgp_trust_revoke(const char *keyID) +{ + OpenPGP_key *key, *tkey; + + openpgp_trust_add(NULL); /* initialize if needed */ + + LIST_FOREACH(key, &trust_list, entries) { + if (strcmp(key->id, keyID) == 0) { + tkey = key; + LIST_REMOVE(tkey, entries); + printf("openpgp_trust_revoke(%s)\n", key->id); + memset(key, 0, sizeof(OpenPGP_key)); + free(key); + return (1); + } + } + return (0); +} + /** * @brief if keyID is in our list return the key * @@ -251,7 +292,9 @@ load_key_file(const char *kfile) return (key); } +#ifdef HAVE_TA_ASC_H #include +#endif #ifndef _STANDALONE /* we can lookup keyID in filesystem */ @@ -330,8 +373,8 @@ openpgp_trust_init(void) } } } - } #endif + } return (once); } diff --git a/lib/libsecureboot/readfile.c b/lib/libsecureboot/readfile.c index f632922143ce..ff9f9f6f6d60 100644 --- a/lib/libsecureboot/readfile.c +++ b/lib/libsecureboot/readfile.c @@ -28,21 +28,13 @@ __FBSDID("$FreeBSD$"); #include unsigned char * -read_file(const char *path, size_t *len) +read_fd(int fd, size_t len) { - int fd, m, n, x; - struct stat st; + int m, n, x; unsigned char *buf; - if (len) - *len = 0; - if ((fd = open(path, O_RDONLY)) < 0) - return (NULL); - fstat(fd, &st); - if (len) - *len = st.st_size; - buf = malloc(st.st_size + 1); - for (x = 0, m = st.st_size; m > 0; ) { + buf = malloc(len + 1); + for (x = 0, m = len; m > 0; ) { n = read(fd, &buf[x], m); if (n < 0) break; @@ -51,11 +43,30 @@ read_file(const char *path, size_t *len) x += n; } } - close(fd); if (m == 0) { - buf[st.st_size] = '\0'; + buf[len] = '\0'; return (buf); } free(buf); return (NULL); } + +unsigned char * +read_file(const char *path, size_t *len) +{ + struct stat st; + unsigned char *ucp; + int fd; + + if (len) + *len = 0; + if ((fd = open(path, O_RDONLY)) < 0) + return (NULL); + fstat(fd, &st); + ucp = read_fd(fd, st.st_size); + close(fd); + if (len != NULL && ucp != NULL) + *len = st.st_size; + return (ucp); +} + diff --git a/lib/libsecureboot/verify_file.c b/lib/libsecureboot/verify_file.c index e8b00451133f..bb092dda2ed2 100644 --- a/lib/libsecureboot/verify_file.c +++ b/lib/libsecureboot/verify_file.c @@ -246,7 +246,9 @@ severity_guess(const char *filename) } static void -verify_tweak(char *tweak, int *accept_no_fp, int *verbose, int *verifying) +verify_tweak(int fd, off_t off, struct stat *stp, + char *tweak, int *accept_no_fp, + int *verbose, int *verifying) { if (strcmp(tweak, "off") == 0) { *verifying = 0; @@ -268,6 +270,25 @@ verify_tweak(char *tweak, int *accept_no_fp, int *verbose, int *verifying) *verbose = 1; } else if (strcmp(tweak, "quiet") == 0) { *verbose = 0; + } else if (strncmp(tweak, "trust", 5) == 0) { + /* content is trust anchor to add or revoke */ + unsigned char *ucp; + size_t num; + + if (off > 0) + lseek(fd, 0, SEEK_SET); + ucp = read_fd(fd, stp->st_size); + if (ucp == NULL) + return; + if (strstr(tweak, "revoke")) { + num = ve_trust_anchors_revoke(ucp, stp->st_size); + DEBUG_PRINTF(3, ("revoked %d trust anchors\n", + (int) num)); + } else { + num = ve_trust_anchors_add_buf(ucp, stp->st_size); + DEBUG_PRINTF(3, ("added %d trust anchors\n", + (int) num)); + } } } @@ -317,8 +338,10 @@ verify_file(int fd, const char *filename, off_t off, int severity) rc = verifying ? VE_NOT_CHECKED : VE_NOT_VERIFYING; ve_status_set(0, rc); ve_status_state = VE_STATUS_NONE; - if (verifying) + if (verifying) { ve_self_tests(); + ve_anchor_verbose_set(1); + } } if (!verifying) return (0); @@ -367,7 +390,7 @@ verify_file(int fd, const char *filename, off_t off, int severity) cp++; if (strncmp(cp, "loader.ve.", 10) == 0) { cp += 10; - verify_tweak(cp, + verify_tweak(fd, off, &st, cp, &accept_no_fp, &verbose, &verifying); } diff --git a/lib/libsecureboot/vets.c b/lib/libsecureboot/vets.c index 73e3db7722d5..87fb190577eb 100644 --- a/lib/libsecureboot/vets.c +++ b/lib/libsecureboot/vets.c @@ -55,6 +55,20 @@ static anchor_list trust_anchors = VEC_INIT; static anchor_list forbidden_anchors = VEC_INIT; static digest_list forbidden_digests = VEC_INIT; +static int anchor_verbose = 0; + +void +ve_anchor_verbose_set(int n) +{ + anchor_verbose = n; +} + +int +ve_anchor_verbose_get(void) +{ + return (anchor_verbose); +} + void ve_debug_set(int n) { @@ -116,6 +130,47 @@ free_cert_contents(br_x509_certificate *xc) xfree(xc->data); } +/* + * a bit of a dance to get commonName from a certificate + */ +static char * +x509_cn_get(br_x509_certificate *xc, char *buf, size_t len) +{ + br_x509_minimal_context mc; + br_name_element cn; + unsigned char cn_oid[4]; + int err; + + if (buf == NULL) + return (buf); + /* + * We want the commonName field + * the OID we want is 2,5,4,3 - but DER encoded + */ + cn_oid[0] = 3; + cn_oid[1] = 0x55; + cn_oid[2] = 4; + cn_oid[3] = 3; + cn.oid = cn_oid; + cn.buf = buf; + cn.len = len; + cn.buf[0] = '\0'; + + br_x509_minimal_init(&mc, &br_sha256_vtable, NULL, 0); + br_x509_minimal_set_name_elements(&mc, &cn, 1); + /* the below actually does the work - updates cn.status */ + mc.vtable->start_chain(&mc.vtable, NULL); + mc.vtable->start_cert(&mc.vtable, xc->data_len); + mc.vtable->append(&mc.vtable, xc->data, xc->data_len); + mc.vtable->end_cert(&mc.vtable); + /* we don' actually care about cert status - just its name */ + err = mc.vtable->end_chain(&mc.vtable); + + if (!cn.status) + buf = NULL; + return (buf); +} + /* ASN parsing related defines */ #define ASN1_PRIMITIVE_TAG 0x1F #define ASN1_INF_LENGTH 0x80 @@ -184,7 +239,8 @@ ve_forbidden_digest_add(hash_data *digest, size_t num) } static size_t -ve_anchors_add(br_x509_certificate *xcs, size_t num, anchor_list *anchors) +ve_anchors_add(br_x509_certificate *xcs, size_t num, anchor_list *anchors, + char *anchors_name) { br_x509_trust_anchor ta; size_t u; @@ -194,6 +250,15 @@ ve_anchors_add(br_x509_certificate *xcs, size_t num, anchor_list *anchors) break; } VEC_ADD(*anchors, ta); + if (anchor_verbose && anchors_name) { + char buf[64]; + char *cp; + + cp = x509_cn_get(&xcs[u], buf, sizeof(buf)); + if (cp) { + printf("x509_anchor(%s) %s\n", cp, anchors_name); + } + } } return (u); } @@ -205,13 +270,68 @@ ve_anchors_add(br_x509_certificate *xcs, size_t num, anchor_list *anchors) size_t ve_trust_anchors_add(br_x509_certificate *xcs, size_t num) { - return (ve_anchors_add(xcs, num, &trust_anchors)); + return (ve_anchors_add(xcs, num, &trust_anchors, "trusted")); } size_t ve_forbidden_anchors_add(br_x509_certificate *xcs, size_t num) { - return (ve_anchors_add(xcs, num, &forbidden_anchors)); + return (ve_anchors_add(xcs, num, &forbidden_anchors, "forbidden")); +} + + +/** + * @brief add trust anchors in buf + * + * Assume buf contains x509 certificates, but if not and + * we support OpenPGP try adding as that. + * + * @return number of anchors added + */ +size_t +ve_trust_anchors_add_buf(unsigned char *buf, size_t len) +{ + br_x509_certificate *xcs; + size_t num; + + num = 0; + xcs = parse_certificates(buf, len, &num); + if (xcs != NULL) { + num = ve_trust_anchors_add(xcs, num); +#ifdef VE_OPENPGP_SUPPORT + } else { + num = openpgp_trust_add_buf(buf, len); +#endif + } + return (num); +} + +/** + * @brief revoke trust anchors in buf + * + * Assume buf contains x509 certificates, but if not and + * we support OpenPGP try revoking keyId + * + * @return number of anchors revoked + */ +size_t +ve_trust_anchors_revoke(unsigned char *buf, size_t len) +{ + br_x509_certificate *xcs; + size_t num; + + num = 0; + xcs = parse_certificates(buf, len, &num); + if (xcs != NULL) { + num = ve_forbidden_anchors_add(xcs, num); +#ifdef VE_OPENPGP_SUPPORT + } else { + if (buf[len - 1] == '\n') + buf[len - 1] = '\0'; + num = openpgp_trust_revoke((char *)buf); +#endif + } + return (num); } /** @@ -221,11 +341,7 @@ ve_forbidden_anchors_add(br_x509_certificate *xcs, size_t num) int ve_trust_init(void) { -#ifdef TRUST_ANCHOR_STR - br_x509_certificate *xcs; -#endif static int once = -1; - size_t num; if (once >= 0) return (once); @@ -240,10 +356,8 @@ ve_trust_init(void) #endif #ifdef TRUST_ANCHOR_STR - xcs = parse_certificates(__DECONST(unsigned char *, TRUST_ANCHOR_STR), - sizeof(TRUST_ANCHOR_STR), &num); - if (xcs != NULL) - num = ve_trust_anchors_add(xcs, num); + ve_trust_anchors_add_buf(__DECONST(unsigned char *, TRUST_ANCHOR_STR), + sizeof(TRUST_ANCHOR_STR)); #endif once = (int) VEC_LEN(trust_anchors); #ifdef VE_OPENPGP_SUPPORT @@ -552,6 +666,7 @@ verify_ec(br_x509_pkey *pk, const char *file, const char *sigfile) br_sha256_init(&ctx); br_sha256_update(&ctx, fcp, flen); br_sha256_out(&ctx, rhbuf); +#ifdef VE_ECDSA_HASH_AGAIN hex = hexdigest(hexbuf, sizeof(hexbuf), rhbuf, br_sha256_SIZE); /* now hash that */ if (hex) { @@ -559,6 +674,7 @@ verify_ec(br_x509_pkey *pk, const char *file, const char *sigfile) br_sha256_update(&ctx, hex, strlen(hex)); br_sha256_out(&ctx, rhbuf); } +#endif ec = br_ec_get_default(); vrfy = br_ecdsa_vrfy_asn1_get_default(); if (!vrfy(ec, rhbuf, br_sha256_SIZE, &pk->key.ec, po->data, From 797a7db05aa3b40fead5f6c438a5d21dba704b18 Mon Sep 17 00:00:00 2001 From: Cy Schubert Date: Thu, 27 Jun 2019 02:42:56 +0000 Subject: [PATCH 147/165] Fix a typo. PR/238816 initially addressed updates to usage() however it has now become a shopping list of fixes to ipmon man pages and usage(). PR: 238816 MFC after: 3 days --- contrib/ipfilter/man/ipmon.8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/ipfilter/man/ipmon.8 b/contrib/ipfilter/man/ipmon.8 index 126f4a7b15ee..aa20e5b3a49d 100644 --- a/contrib/ipfilter/man/ipmon.8 +++ b/contrib/ipfilter/man/ipmon.8 @@ -27,7 +27,7 @@ ipmon \- monitors /dev/ipl for logged packets .LP \fBipmon\fP opens \fB/dev/ipl\fP for reading and awaits data to be saved from the packet filter. The binary data read from the device is reprinted in -human readable for, however, IP#'s are not mapped back to hostnames, nor are +human readable form, however, IP#'s are not mapped back to hostnames, nor are ports mapped back to service names. The output goes to standard output by default or a filename, if given on the command line. Should the \fB\-s\fP option be used, output is instead sent to \fBsyslogd(8)\fP. Messages sent From 74bc7fc0b44b7e5a8734b9fda5732a181cfaeb37 Mon Sep 17 00:00:00 2001 From: Cy Schubert Date: Thu, 27 Jun 2019 02:43:26 +0000 Subject: [PATCH 148/165] Add the ipmon.5 man page. PR/238816 initially addressed updates to usage() however the PR has morphed into a shopping list of updates to usage() and man pages. PR: 238816 (I added to the list during discussion) MFC after: 1 week --- sbin/ipf/ipmon/Makefile | 2 +- tools/build/mk/OptionalObsoleteFiles.inc | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/sbin/ipf/ipmon/Makefile b/sbin/ipf/ipmon/Makefile index 5d76a05ae44a..12155cfe3106 100644 --- a/sbin/ipf/ipmon/Makefile +++ b/sbin/ipf/ipmon/Makefile @@ -3,7 +3,7 @@ PACKAGE= ipf PROG= ipmon SRCS= ${GENHDRS} ipmon.c ipmon_y.c ipmon_l.c -MAN= ipmon.8 +MAN= ipmon.5 ipmon.8 CFLAGS+= -DLOGFAC=LOG_LOCAL0 -I. diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc index 58592329e11d..eb2411a2830e 100644 --- a/tools/build/mk/OptionalObsoleteFiles.inc +++ b/tools/build/mk/OptionalObsoleteFiles.inc @@ -3350,6 +3350,7 @@ OLD_FILES+=usr/share/man/man5/ipf.5.gz OLD_FILES+=usr/share/man/man5/ipf.conf.5.gz OLD_FILES+=usr/share/man/man5/ipf6.conf.5.gz OLD_FILES+=usr/share/man/man5/ipfilter.5.gz +OLD_FILES+=usr/share/man/man8/ipmon.5.gz OLD_FILES+=usr/share/man/man5/ipnat.5.gz OLD_FILES+=usr/share/man/man5/ipnat.conf.5.gz OLD_FILES+=usr/share/man/man5/ippool.5.gz From accc4633dbb13a0200a0cb11e8a6368c0ed4f166 Mon Sep 17 00:00:00 2001 From: Cy Schubert Date: Thu, 27 Jun 2019 02:43:30 +0000 Subject: [PATCH 149/165] Update usage() to refect the current state of ipmon. PR: 238816 MFC after: 1 week --- contrib/ipfilter/tools/ipmon.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/contrib/ipfilter/tools/ipmon.c b/contrib/ipfilter/tools/ipmon.c index 4e4d9cc28f9e..d08895a85c34 100644 --- a/contrib/ipfilter/tools/ipmon.c +++ b/contrib/ipfilter/tools/ipmon.c @@ -1438,8 +1438,11 @@ static void print_ipflog(conf, buf, blen) static void usage(prog) char *prog; { - fprintf(stderr, "%s: [-NFhstvxX] [-f ]\n", prog); - exit(1); + fprintf(stderr, "Usage: %s [ -abDFhnpstvxX ] [ -B ] [ -C ]\n" + "\t[ -f ] [ -L ] [ -N ]\n" + "\t[ -o [NSI] ] [ -O [NSI] ] [ -P ] [ -S ]\n" + "\t[ ]\n", prog); + exit(-1); } From 358e680a6751e34206821ef37abe1930b7699c95 Mon Sep 17 00:00:00 2001 From: Cy Schubert Date: Thu, 27 Jun 2019 03:50:13 +0000 Subject: [PATCH 150/165] Return a return code scripts might expect. I missed this while reviewing and rewriting a patch in PR/238816. PR: 238816 Reported by: rgrimes@ Pointy hat to: cy@ MFC after: 1 week X-MFC with: r349450 --- contrib/ipfilter/tools/ipmon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/ipfilter/tools/ipmon.c b/contrib/ipfilter/tools/ipmon.c index d08895a85c34..d7ad1a228378 100644 --- a/contrib/ipfilter/tools/ipmon.c +++ b/contrib/ipfilter/tools/ipmon.c @@ -1442,7 +1442,7 @@ static void usage(prog) "\t[ -f ] [ -L ] [ -N ]\n" "\t[ -o [NSI] ] [ -O [NSI] ] [ -P ] [ -S ]\n" "\t[ ]\n", prog); - exit(-1); + exit(1); } From 015cb6cde4f977ce62d0130ae617c802b6600257 Mon Sep 17 00:00:00 2001 From: Cy Schubert Date: Thu, 27 Jun 2019 12:37:44 +0000 Subject: [PATCH 151/165] Create a link to the ipmon.conf.5 man page as documented in ipmon.5. Add its corresponding optional removal entry. PR: 238816 MFC after: 1 week --- sbin/ipf/ipmon/Makefile | 1 + tools/build/mk/OptionalObsoleteFiles.inc | 1 + 2 files changed, 2 insertions(+) diff --git a/sbin/ipf/ipmon/Makefile b/sbin/ipf/ipmon/Makefile index 12155cfe3106..8227811db2ad 100644 --- a/sbin/ipf/ipmon/Makefile +++ b/sbin/ipf/ipmon/Makefile @@ -4,6 +4,7 @@ PACKAGE= ipf PROG= ipmon SRCS= ${GENHDRS} ipmon.c ipmon_y.c ipmon_l.c MAN= ipmon.5 ipmon.8 +MLINKS= ipmon.5 ipmon.conf.5 CFLAGS+= -DLOGFAC=LOG_LOCAL0 -I. diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc index eb2411a2830e..c8a2235b5bc0 100644 --- a/tools/build/mk/OptionalObsoleteFiles.inc +++ b/tools/build/mk/OptionalObsoleteFiles.inc @@ -3351,6 +3351,7 @@ OLD_FILES+=usr/share/man/man5/ipf.conf.5.gz OLD_FILES+=usr/share/man/man5/ipf6.conf.5.gz OLD_FILES+=usr/share/man/man5/ipfilter.5.gz OLD_FILES+=usr/share/man/man8/ipmon.5.gz +OLD_FILES+=usr/share/man/man5/ipmon.conf.5.gz OLD_FILES+=usr/share/man/man5/ipnat.5.gz OLD_FILES+=usr/share/man/man5/ipnat.conf.5.gz OLD_FILES+=usr/share/man/man5/ippool.5.gz From 338412e5a61376f75ae5386383f7893c8ebeab03 Mon Sep 17 00:00:00 2001 From: Ed Maste Date: Thu, 27 Jun 2019 13:31:55 +0000 Subject: [PATCH 152/165] picobsd: also exclude .git where we exclude .svn today Sponsored by: The FreeBSD Foundation --- release/picobsd/build/picobsd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release/picobsd/build/picobsd b/release/picobsd/build/picobsd index 807f9acd7242..2d057ed81c5c 100755 --- a/release/picobsd/build/picobsd +++ b/release/picobsd/build/picobsd @@ -437,7 +437,7 @@ populate_floppy_fs() { # OK ${MY_TREE}/floppy.tree.${SITE} ; do if [ -d ${FLOPPY_TREE} ] ; then (cd ${FLOPPY_TREE} ; tar -cf - \ - --exclude .svn ${excl} . ) | \ + --exclude .git --exclude .svn ${excl} . ) | \ (cd ${dst} ; tar x${o_tarv}f - ) log "Copied from ${FLOPPY_TREE}" fi @@ -698,7 +698,7 @@ populate_mfs_tree() { for MFS_TREE in ${PICO_TREE}/mfs_tree ${MY_TREE}/mfs_tree ; do if [ -d ${MFS_TREE} ] ; then log "Copy ${MFS_TREE} ..." - (cd ${MFS_TREE} ; tar -cf - --exclude .svn . ) | \ + (cd ${MFS_TREE} ; tar -cf - --exclude .git --exclude .svn . ) | \ (cd ${dst} ; tar x${o_tarv}f - ) fi done From d05fa0d94959e354c6f028826bc540787791d6af Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Thu, 27 Jun 2019 14:03:32 +0000 Subject: [PATCH 153/165] bectl(8): create non-recursive boot environments bectl advertises that it has the ability to create recursive and non-recursive boot environments. This patch implements that functionality using the be_create_depth API provided by libbe. With this patch, bectl now works as bectl(8) describes in regards to creating recursive/non-recursive boot environments. Submitted by: Rob Fairbanks (with minor changes) MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D20240 --- sbin/bectl/bectl.c | 37 +++++++++++++++++----------------- sbin/bectl/tests/bectl_test.sh | 24 ++++++++++++++++++++++ 2 files changed, 43 insertions(+), 18 deletions(-) diff --git a/sbin/bectl/bectl.c b/sbin/bectl/bectl.c index 366fa048a893..5119759deb97 100644 --- a/sbin/bectl/bectl.c +++ b/sbin/bectl/bectl.c @@ -184,7 +184,8 @@ bectl_cmd_activate(int argc, char *argv[]) static int bectl_cmd_create(int argc, char *argv[]) { - char *atpos, *bootenv, *snapname, *source; + char snapshot[BE_MAXPATHLEN]; + char *atpos, *bootenv, *snapname; int err, opt; bool recursive; @@ -214,6 +215,8 @@ bectl_cmd_create(int argc, char *argv[]) } bootenv = *argv; + + err = BE_ERR_SUCCESS; if ((atpos = strchr(bootenv, '@')) != NULL) { /* * This is the "create a snapshot variant". No new boot @@ -221,24 +224,22 @@ bectl_cmd_create(int argc, char *argv[]) */ *atpos++ = '\0'; err = be_snapshot(be, bootenv, atpos, recursive, NULL); - } else if (snapname != NULL) { - if (strchr(snapname, '@') != NULL) - err = be_create_from_existing_snap(be, bootenv, - snapname); - else - err = be_create_from_existing(be, bootenv, snapname); } else { - if ((snapname = strchr(bootenv, '@')) != NULL) { - *(snapname++) = '\0'; - if ((err = be_snapshot(be, be_active_path(be), - snapname, true, NULL)) != BE_ERR_SUCCESS) - fprintf(stderr, "failed to create snapshot\n"); - asprintf(&source, "%s@%s", be_active_path(be), snapname); - err = be_create_from_existing_snap(be, bootenv, - source); - return (err); - } else - err = be_create(be, bootenv); + if (snapname == NULL) + /* Create from currently booted BE */ + err = be_snapshot(be, be_active_path(be), NULL, + recursive, snapshot); + else if (strchr(snapname, '@') != NULL) + /* Create from given snapshot */ + strlcpy(snapshot, snapname, sizeof(snapshot)); + else + /* Create from given BE */ + err = be_snapshot(be, snapname, NULL, recursive, + snapshot); + + if (err == BE_ERR_SUCCESS) + err = be_create_depth(be, bootenv, snapshot, + recursive == true ? -1 : 0); } switch (err) { diff --git a/sbin/bectl/tests/bectl_test.sh b/sbin/bectl/tests/bectl_test.sh index 6d268c00b178..e551e501b790 100755 --- a/sbin/bectl/tests/bectl_test.sh +++ b/sbin/bectl/tests/bectl_test.sh @@ -99,11 +99,35 @@ bectl_create_body() mount=${cwd}/mnt bectl_create_setup ${zpool} ${disk} ${mount} + + # Create a child dataset that will be used to test creation + # of recursive and non-recursive boot environments. + atf_check zfs create -o mountpoint=/usr -o canmount=noauto \ + ${zpool}/ROOT/default/usr + # Test standard creation, creation of a snapshot, and creation from a # snapshot. atf_check bectl -r ${zpool}/ROOT create -e default default2 atf_check bectl -r ${zpool}/ROOT create default2@test_snap atf_check bectl -r ${zpool}/ROOT create -e default2@test_snap default3 + + # Test standard creation, creation of a snapshot, and creation from a + # snapshot for recursive boot environments. + atf_check bectl -r ${zpool}/ROOT create -r -e default recursive + atf_check bectl -r ${zpool}/ROOT create -r recursive@test_snap + atf_check bectl -r ${zpool}/ROOT create -r -e recursive@test_snap recursive-snap + + # Test that non-recursive boot environments have no child datasets. + atf_check -e not-empty -s not-exit:0 \ + zfs list "${zpool}/ROOT/default2/usr" + atf_check -e not-empty -s not-exit:0 \ + zfs list "${zpool}/ROOT/default3/usr" + + # Test that recursive boot environments have child datasets. + atf_check -o not-empty \ + zfs list "${zpool}/ROOT/recursive/usr" + atf_check -o not-empty \ + zfs list "${zpool}/ROOT/recursive-snap/usr" } bectl_create_cleanup() { From d55fcc487ef1439858894ed039f92de4c54ed86c Mon Sep 17 00:00:00 2001 From: Andriy Gapon Date: Thu, 27 Jun 2019 15:07:06 +0000 Subject: [PATCH 154/165] upgrade the warning printf-s in bus accessors to KASSERT-s After this change sys/bus.h includes sys/systm.h. Discussed with: cem, imp MFC after: 2 weeks --- sys/sys/bus.h | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/sys/sys/bus.h b/sys/sys/bus.h index 9fb4a6d4c38e..915d6bc886db 100644 --- a/sys/sys/bus.h +++ b/sys/sys/bus.h @@ -35,6 +35,7 @@ #include #include #include +#include /** * @defgroup NEWBUS newbus - a generic framework for managing devices @@ -813,12 +814,9 @@ static __inline type varp ## _get_ ## var(device_t dev) \ int e; \ e = BUS_READ_IVAR(device_get_parent(dev), dev, \ ivarp ## _IVAR_ ## ivar, &v); \ - if (e != 0) { \ - device_printf(dev, "failed to read ivar " \ - __XSTRING(ivarp ## _IVAR_ ## ivar) " on bus %s, " \ - "error = %d\n", \ - device_get_nameunit(device_get_parent(dev)), e); \ - } \ + KASSERT(e == 0, ("%s failed for %s on bus %s, error = %d", \ + __func__, device_get_nameunit(dev), \ + device_get_nameunit(device_get_parent(dev)), e)); \ return ((type) v); \ } \ \ @@ -828,12 +826,9 @@ static __inline void varp ## _set_ ## var(device_t dev, type t) \ int e; \ e = BUS_WRITE_IVAR(device_get_parent(dev), dev, \ ivarp ## _IVAR_ ## ivar, v); \ - if (e != 0) { \ - device_printf(dev, "failed to write ivar " \ - __XSTRING(ivarp ## _IVAR_ ## ivar) " on bus %s, " \ - "error = %d\n", \ - device_get_nameunit(device_get_parent(dev)), e); \ - } \ + KASSERT(e == 0, ("%s failed for %s on bus %s, error = %d", \ + __func__, device_get_nameunit(dev), \ + device_get_nameunit(device_get_parent(dev)), e)); \ } /** From 061b38cdccdb63311b9917fedd92cd4190010c67 Mon Sep 17 00:00:00 2001 From: Andriy Gapon Date: Thu, 27 Jun 2019 15:46:06 +0000 Subject: [PATCH 155/165] gpiobus: provide a new hint, pin_list "pin_list" allows to specify child pins as a list of pin numbers. Existing hint "pins" serves the same purpose but with a 32-bit wide bit mask. One problem with that is that a controller can have more than 32 pins. One example is amdgpio. Also, a list of numbers is a little bit more human friendly than a matching bit mask. As a side note, it seems that in FDT pins are typically specified by their numbers as well. This commit also adds accessors for instance variables (IVARs) that define the child pins. My primary goal is to allow a child to be configured programmatically rather than via hints (assuming that FDT is not supported on a platform). Also, while a child should not care about specific pin numbers that are allocated to it, it could be interested in how many were actually assigned to it. While there, I removed "flags" instance variable. It was unused. Reviewed by: mizhka MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D20459 --- share/man/man4/gpio.4 | 18 +++- sys/dev/gpio/gpiobus.c | 185 ++++++++++++++++++++++++++++++++------ sys/dev/gpio/gpiobusvar.h | 14 ++- 3 files changed, 189 insertions(+), 28 deletions(-) diff --git a/share/man/man4/gpio.4 b/share/man/man4/gpio.4 index b1eb1ef8a5bc..da95c39f8e98 100644 --- a/share/man/man4/gpio.4 +++ b/share/man/man4/gpio.4 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd June 26, 2019 +.Dd June 27, 2019 .Dt GPIO 4 .Os .Sh NAME @@ -109,7 +109,7 @@ based system these hints can be used to configure drivers for devices attached to .Nm pins: -.Bl -tag -width ".Va hint.driver.unit.pins" +.Bl -tag -width ".Va hint.driver.unit.pin_list" .It Va hint.driver.unit.at The .Nm gpiobus @@ -125,6 +125,20 @@ This is a bitmask of the pins on the .Nm gpiobus that are connected to the device. The pins will be allocated to the specified driver instance. +Only pins with numbers from 0 to 31 can be specified using this hint. +.It Va hint.driver.unit.pin_list +This is a list of pin numbers of pins on the +.Nm gpiobus +that are connected to the device. +The pins will be allocated to the specified driver instance. +This is a more user friendly alternative to the +.Ar pins +hint. +Additionally, this hint allows specifying pin numbers greater than 31. +The numbers can be decimal or hexadecimal with 0x prefix. +Any non-digit character can be used as a separator. +For example, it can be a comma, a slash or a space. +The separator can be followed by any number of space characters. .El .Pp The following diff --git a/sys/dev/gpio/gpiobus.c b/sys/dev/gpio/gpiobus.c index 133b72185d7f..64fadb382a02 100644 --- a/sys/dev/gpio/gpiobus.c +++ b/sys/dev/gpio/gpiobus.c @@ -255,13 +255,6 @@ gpiobus_alloc_ivars(struct gpiobus_ivar *devi) M_NOWAIT | M_ZERO); if (devi->pins == NULL) return (ENOMEM); - devi->flags = malloc(sizeof(uint32_t) * devi->npins, M_DEVBUF, - M_NOWAIT | M_ZERO); - if (devi->flags == NULL) { - free(devi->pins, M_DEVBUF); - return (ENOMEM); - } - return (0); } @@ -269,14 +262,11 @@ void gpiobus_free_ivars(struct gpiobus_ivar *devi) { - if (devi->flags) { - free(devi->flags, M_DEVBUF); - devi->flags = NULL; - } if (devi->pins) { free(devi->pins, M_DEVBUF); devi->pins = NULL; } + devi->npins = 0; } int @@ -325,6 +315,34 @@ gpiobus_release_pin(device_t bus, uint32_t pin) return (0); } +static int +gpiobus_acquire_child_pins(device_t dev, device_t child) +{ + struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); + int i; + + for (i = 0; i < devi->npins; i++) { + /* Reserve the GPIO pin. */ + if (gpiobus_acquire_pin(dev, devi->pins[i]) != 0) { + device_printf(child, "cannot acquire pin %d\n", + devi->pins[i]); + while (--i >= 0) { + (void)gpiobus_release_pin(dev, + devi->pins[i]); + } + gpiobus_free_ivars(devi); + return (EBUSY); + } + } + for (i = 0; i < devi->npins; i++) { + /* Use the child name as pin name. */ + GPIOBUS_PIN_SETNAME(dev, devi->pins[i], + device_get_nameunit(child)); + + } + return (0); +} + static int gpiobus_parse_pins(struct gpiobus_softc *sc, device_t child, int mask) { @@ -349,17 +367,66 @@ gpiobus_parse_pins(struct gpiobus_softc *sc, device_t child, int mask) for (i = 0; i < 32; i++) { if ((mask & (1 << i)) == 0) continue; - /* Reserve the GPIO pin. */ - if (gpiobus_acquire_pin(sc->sc_busdev, i) != 0) { - gpiobus_free_ivars(devi); - return (EINVAL); - } devi->pins[npins++] = i; - /* Use the child name as pin name. */ - GPIOBUS_PIN_SETNAME(sc->sc_busdev, i, - device_get_nameunit(child)); } + if (gpiobus_acquire_child_pins(sc->sc_busdev, child) != 0) + return (EINVAL); + return (0); +} + +static int +gpiobus_parse_pin_list(struct gpiobus_softc *sc, device_t child, + const char *pins) +{ + struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); + const char *p; + char *endp; + unsigned long pin; + int i, npins; + + npins = 0; + p = pins; + for (;;) { + pin = strtoul(p, &endp, 0); + if (endp == p) + break; + npins++; + if (*endp == '\0') + break; + p = endp + 1; + } + + if (*endp != '\0') { + device_printf(child, "garbage in the pin list: %s\n", endp); + return (EINVAL); + } + if (npins == 0) { + device_printf(child, "empty pin list\n"); + return (EINVAL); + } + + devi->npins = npins; + if (gpiobus_alloc_ivars(devi) != 0) { + device_printf(child, "cannot allocate device ivars\n"); + return (EINVAL); + } + + i = 0; + p = pins; + for (;;) { + pin = strtoul(p, &endp, 0); + + devi->pins[i] = pin; + + if (*endp == '\0') + break; + i++; + p = endp + 1; + } + + if (gpiobus_acquire_child_pins(sc->sc_busdev, child) != 0) + return (EINVAL); return (0); } @@ -539,15 +606,26 @@ gpiobus_hinted_child(device_t bus, const char *dname, int dunit) struct gpiobus_softc *sc = GPIOBUS_SOFTC(bus); struct gpiobus_ivar *devi; device_t child; - int irq, pins; + const char *pins; + int irq, pinmask; child = BUS_ADD_CHILD(bus, 0, dname, dunit); devi = GPIOBUS_IVAR(child); - resource_int_value(dname, dunit, "pins", &pins); - if (gpiobus_parse_pins(sc, child, pins)) { - resource_list_free(&devi->rl); - free(devi, M_DEVBUF); - device_delete_child(bus, child); + if (resource_int_value(dname, dunit, "pins", &pinmask) == 0) { + if (gpiobus_parse_pins(sc, child, pinmask)) { + resource_list_free(&devi->rl); + free(devi, M_DEVBUF); + device_delete_child(bus, child); + return; + } + } + else if (resource_string_value(dname, dunit, "pin_list", &pins) == 0) { + if (gpiobus_parse_pin_list(sc, child, pins)) { + resource_list_free(&devi->rl); + free(devi, M_DEVBUF); + device_delete_child(bus, child); + return; + } } if (resource_int_value(dname, dunit, "irq", &irq) == 0) { if (bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1) != 0) @@ -574,6 +652,61 @@ gpiobus_set_resource(device_t dev, device_t child, int type, int rid, return (0); } +static int +gpiobus_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) +{ + struct gpiobus_ivar *devi; + + devi = GPIOBUS_IVAR(child); + switch (which) { + case GPIOBUS_IVAR_NPINS: + *result = devi->npins; + break; + case GPIOBUS_IVAR_PINS: + /* Children do not ever need to directly examine this. */ + return (ENOTSUP); + default: + return (ENOENT); + } + + return (0); +} + +static int +gpiobus_write_ivar(device_t dev, device_t child, int which, uintptr_t value) +{ + struct gpiobus_ivar *devi; + const uint32_t *ptr; + int i; + + devi = GPIOBUS_IVAR(child); + switch (which) { + case GPIOBUS_IVAR_NPINS: + /* GPIO ivars are set once. */ + if (devi->npins != 0) { + return (EBUSY); + } + devi->npins = value; + if (gpiobus_alloc_ivars(devi) != 0) { + device_printf(child, "cannot allocate device ivars\n"); + devi->npins = 0; + return (ENOMEM); + } + break; + case GPIOBUS_IVAR_PINS: + ptr = (const uint32_t *)value; + for (i = 0; i < devi->npins; i++) + devi->pins[i] = ptr[i]; + if (gpiobus_acquire_child_pins(dev, child) != 0) + return (EBUSY); + break; + default: + return (ENOENT); + } + + return (0); +} + static struct resource * gpiobus_alloc_resource(device_t bus, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) @@ -833,6 +966,8 @@ static device_method_t gpiobus_methods[] = { DEVMETHOD(bus_child_pnpinfo_str, gpiobus_child_pnpinfo_str), DEVMETHOD(bus_child_location_str, gpiobus_child_location_str), DEVMETHOD(bus_hinted_child, gpiobus_hinted_child), + DEVMETHOD(bus_read_ivar, gpiobus_read_ivar), + DEVMETHOD(bus_write_ivar, gpiobus_write_ivar), /* GPIO protocol */ DEVMETHOD(gpiobus_acquire_bus, gpiobus_acquire_bus), diff --git a/sys/dev/gpio/gpiobusvar.h b/sys/dev/gpio/gpiobusvar.h index 5aa363a23daf..08f0ccf904d0 100644 --- a/sys/dev/gpio/gpiobusvar.h +++ b/sys/dev/gpio/gpiobusvar.h @@ -107,10 +107,22 @@ struct gpiobus_ivar { struct resource_list rl; /* isr resource list */ uint32_t npins; /* pins total */ - uint32_t *flags; /* pins flags */ uint32_t *pins; /* pins map */ }; +enum gpiobus_ivars { + GPIOBUS_IVAR_NPINS = 10500, + GPIOBUS_IVAR_PINS, +}; + +#define GPIOBUS_ACCESSOR(var, ivar, type) \ + __BUS_ACCESSOR(gpiobus, var, GPIOBUS, ivar, type) + +GPIOBUS_ACCESSOR(npins, NPINS, uint32_t) +GPIOBUS_ACCESSOR(pins, PINS, const uint32_t *) + +#undef GPIOBUS_ACCESSOR + #ifdef FDT struct ofw_gpiobus_devinfo { struct gpiobus_ivar opd_dinfo; From f45e9414cfa62630c05dbe185b9fe099195a88aa Mon Sep 17 00:00:00 2001 From: Andriy Gapon Date: Thu, 27 Jun 2019 15:51:50 +0000 Subject: [PATCH 156/165] revert r349460, printf -> KASSERT in bus.h, until I can fix it I tested only kernel builds naively assuming that sys/bus.h cannot affect userland builds. Pointyhat to: me --- sys/sys/bus.h | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/sys/sys/bus.h b/sys/sys/bus.h index 915d6bc886db..9fb4a6d4c38e 100644 --- a/sys/sys/bus.h +++ b/sys/sys/bus.h @@ -35,7 +35,6 @@ #include #include #include -#include /** * @defgroup NEWBUS newbus - a generic framework for managing devices @@ -814,9 +813,12 @@ static __inline type varp ## _get_ ## var(device_t dev) \ int e; \ e = BUS_READ_IVAR(device_get_parent(dev), dev, \ ivarp ## _IVAR_ ## ivar, &v); \ - KASSERT(e == 0, ("%s failed for %s on bus %s, error = %d", \ - __func__, device_get_nameunit(dev), \ - device_get_nameunit(device_get_parent(dev)), e)); \ + if (e != 0) { \ + device_printf(dev, "failed to read ivar " \ + __XSTRING(ivarp ## _IVAR_ ## ivar) " on bus %s, " \ + "error = %d\n", \ + device_get_nameunit(device_get_parent(dev)), e); \ + } \ return ((type) v); \ } \ \ @@ -826,9 +828,12 @@ static __inline void varp ## _set_ ## var(device_t dev, type t) \ int e; \ e = BUS_WRITE_IVAR(device_get_parent(dev), dev, \ ivarp ## _IVAR_ ## ivar, v); \ - KASSERT(e == 0, ("%s failed for %s on bus %s, error = %d", \ - __func__, device_get_nameunit(dev), \ - device_get_nameunit(device_get_parent(dev)), e)); \ + if (e != 0) { \ + device_printf(dev, "failed to write ivar " \ + __XSTRING(ivarp ## _IVAR_ ## ivar) " on bus %s, " \ + "error = %d\n", \ + device_get_nameunit(device_get_parent(dev)), e); \ + } \ } /** From 2593e9dcb29566f159f4087832a6d9b7627290b7 Mon Sep 17 00:00:00 2001 From: Ruslan Bukin Date: Thu, 27 Jun 2019 18:08:18 +0000 Subject: [PATCH 157/165] Add support for extended descriptor format to Altera mSGDMA driver. The format to use depends on hardware configuration (synthesis-time), so make it compile-time kernel option. Extended format allows DMA engine to operate with 64-bit memory addresses. Sponsored by: DARPA, AFRL --- sys/conf/options | 6 ++++ sys/dev/altera/msgdma/msgdma.c | 13 ++++--- sys/dev/altera/msgdma/msgdma.h | 64 +++++++++++++++++++++++++++++++--- sys/mips/conf/BERI_DE4_BASE | 1 + 4 files changed, 75 insertions(+), 9 deletions(-) diff --git a/sys/conf/options b/sys/conf/options index ca0b94dfadbe..c4c3bb7eed67 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -861,6 +861,12 @@ AH_INTERRUPT_DEBUGGING opt_ah.h # XXX do not use this for AR9130 AH_AR5416_INTERRUPT_MITIGATION opt_ah.h +# options for the Altera mSGDMA driver (altera_msgdma) +ALTERA_MSGDMA_DESC_STD opt_altera_msgdma.h +ALTERA_MSGDMA_DESC_EXT opt_altera_msgdma.h +ALTERA_MSGDMA_DESC_PF_STD opt_altera_msgdma.h +ALTERA_MSGDMA_DESC_PF_EXT opt_altera_msgdma.h + # options for the Broadcom BCM43xx driver (bwi) BWI_DEBUG opt_bwi.h BWI_DEBUG_VERBOSE opt_bwi.h diff --git a/sys/dev/altera/msgdma/msgdma.c b/sys/dev/altera/msgdma/msgdma.c index c60c7ccfe352..9acb313f91f5 100644 --- a/sys/dev/altera/msgdma/msgdma.c +++ b/sys/dev/altera/msgdma/msgdma.c @@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$"); #include #include "xdma_if.h" +#include "opt_altera_msgdma.h" #include @@ -470,8 +471,8 @@ msgdma_channel_submit_sg(device_t dev, struct xdma_channel *xchan, struct msgdma_channel *chan; struct msgdma_desc *desc; struct msgdma_softc *sc; - uint32_t src_addr_lo; - uint32_t dst_addr_lo; + bus_addr_t src_addr_lo; + bus_addr_t dst_addr_lo; uint32_t len; uint32_t tmp; int i; @@ -481,14 +482,18 @@ msgdma_channel_submit_sg(device_t dev, struct xdma_channel *xchan, chan = (struct msgdma_channel *)xchan->chan; for (i = 0; i < sg_n; i++) { - src_addr_lo = (uint32_t)sg[i].src_addr; - dst_addr_lo = (uint32_t)sg[i].dst_addr; + src_addr_lo = sg[i].src_addr; + dst_addr_lo = sg[i].dst_addr; len = (uint32_t)sg[i].len; dprintf("%s: src %x dst %x len %d\n", __func__, src_addr_lo, dst_addr_lo, len); desc = chan->descs[chan->idx_head]; +#if defined(ALTERA_MSGDMA_DESC_EXT) || defined(ALTERA_MSGDMA_DESC_PF_EXT) + desc->read_hi = htole32(src_addr_lo >> 32); + desc->write_hi = htole32(dst_addr_lo >> 32); +#endif desc->read_lo = htole32(src_addr_lo); desc->write_lo = htole32(dst_addr_lo); desc->length = htole32(len); diff --git a/sys/dev/altera/msgdma/msgdma.h b/sys/dev/altera/msgdma/msgdma.h index e10a233902a2..498fb93d86bf 100644 --- a/sys/dev/altera/msgdma/msgdma.h +++ b/sys/dev/altera/msgdma/msgdma.h @@ -30,6 +30,8 @@ * $FreeBSD$ */ +#include "opt_altera_msgdma.h" + /* Altera mSGDMA registers. */ #define DMA_STATUS 0x00 #define STATUS_RESETTING (1 << 6) @@ -75,15 +77,36 @@ #define WRITE4_DESC(_sc, _reg, _val) \ bus_space_write_4(_sc->bst_d, _sc->bsh_d, _reg, htole32(_val)) -/* Prefetcher-disabled descriptor format. */ -struct msgdma_desc_nonpf { - uint32_t src_addr; - uint32_t dst_addr; +#if defined(ALTERA_MSGDMA_DESC_STD) + +/* Standard descriptor format with prefetcher disabled. */ +struct msgdma_desc { + uint32_t read_lo; + uint32_t write_lo; uint32_t length; uint32_t control; }; -/* Prefetcher-enabled descriptor format. */ +#elif defined(ALTERA_MSGDMA_DESC_EXT) + +/* Extended descriptor format with prefetcher disabled. */ +struct msgdma_desc { + uint32_t read_lo; + uint32_t write_lo; + uint32_t length; + uint8_t write_burst; + uint8_t read_burst; + uint16_t seq_num; + uint16_t write_stride; + uint16_t read_stride; + uint32_t read_hi; + uint32_t write_hi; + uint32_t control; +}; + +#elif defined(ALTERA_MSGDMA_DESC_PF_STD) + +/* Standard descriptor format with prefetcher enabled. */ struct msgdma_desc { uint32_t read_lo; uint32_t write_lo; @@ -94,3 +117,34 @@ struct msgdma_desc { uint32_t reserved; uint32_t control; }; + +#elif defined(ALTERA_MSGDMA_DESC_PF_EXT) + +/* Extended descriptor format with prefetcher enabled. */ +struct msgdma_desc { + uint32_t read_lo; + uint32_t write_lo; + uint32_t length; + uint32_t next; + uint32_t transferred; + uint32_t status; + uint32_t reserved; + uint8_t write_burst; + uint8_t read_burst; + uint16_t seq_num; + uint16_t write_stride; + uint16_t read_stride; + uint32_t read_hi; + uint32_t write_hi; + uint32_t next_hi; + uint32_t reserved1; + uint32_t reserved2; + uint32_t reserved3; + uint32_t control; +}; + +#else + +#error "mSGDMA descriptor format (kernel option) is not set." + +#endif diff --git a/sys/mips/conf/BERI_DE4_BASE b/sys/mips/conf/BERI_DE4_BASE index 0985d60e60d1..7719009ccf5a 100644 --- a/sys/mips/conf/BERI_DE4_BASE +++ b/sys/mips/conf/BERI_DE4_BASE @@ -44,6 +44,7 @@ options DEVICE_POLLING # # DMA support # +options ALTERA_MSGDMA_DESC_PF_STD device xdma device altera_softdma device altera_msgdma From 7f63b888c79b2c8cd4f86b3628f1d6f57f8439b9 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Thu, 27 Jun 2019 19:36:30 +0000 Subject: [PATCH 158/165] Hold an explicit reference on the socket for the aiotx task. Previously, the aiotx task relied on the aio jobs in the queue to hold a reference on the socket. However, when the last job is completed, there is nothing left to hold a reference to the socket buffer lock used to check if the queue is empty. In addition, if the last job on the queue is cancelled, the task can run with no queued jobs holding a reference to the socket buffer lock the task uses to notice the queue is empty. Fix these races by holding an explicit reference on the socket when the task is queued and dropping that reference when the task completes. Reviewed by: np MFC after: 1 week Sponsored by: Chelsio Communications Differential Revision: https://reviews.freebsd.org/D20539 --- sys/dev/cxgbe/tom/t4_cpl_io.c | 25 ++++++++++++++----------- sys/dev/cxgbe/tom/t4_tom.h | 2 +- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/sys/dev/cxgbe/tom/t4_cpl_io.c b/sys/dev/cxgbe/tom/t4_cpl_io.c index 27ef745c764c..fd4f376d8676 100644 --- a/sys/dev/cxgbe/tom/t4_cpl_io.c +++ b/sys/dev/cxgbe/tom/t4_cpl_io.c @@ -74,7 +74,7 @@ __FBSDID("$FreeBSD$"); #include "tom/t4_tom.h" static void t4_aiotx_cancel(struct kaiocb *job); -static void t4_aiotx_queue_toep(struct toepcb *toep); +static void t4_aiotx_queue_toep(struct socket *so, struct toepcb *toep); static size_t aiotx_mbuf_pgoff(struct mbuf *m) @@ -785,7 +785,7 @@ t4_push_frames(struct adapter *sc, struct toepcb *toep, int drop) if (sowwakeup) { if (!TAILQ_EMPTY( &toep->aiotx_jobq)) - t4_aiotx_queue_toep( + t4_aiotx_queue_toep(so, toep); sowwakeup_locked(so); } else @@ -829,7 +829,7 @@ t4_push_frames(struct adapter *sc, struct toepcb *toep, int drop) } if (sowwakeup) { if (!TAILQ_EMPTY(&toep->aiotx_jobq)) - t4_aiotx_queue_toep(toep); + t4_aiotx_queue_toep(so, toep); sowwakeup_locked(so); } else SOCKBUF_UNLOCK(sb); @@ -1821,7 +1821,7 @@ do_fw4_ack(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) tls_ofld->sb_off -= plen; } if (!TAILQ_EMPTY(&toep->aiotx_jobq)) - t4_aiotx_queue_toep(toep); + t4_aiotx_queue_toep(so, toep); sowwakeup_locked(so); /* unlocks so_snd */ } SOCKBUF_UNLOCK_ASSERT(sb); @@ -2195,10 +2195,10 @@ static void t4_aiotx_task(void *context, int pending) { struct toepcb *toep = context; - struct inpcb *inp = toep->inp; - struct socket *so = inp->inp_socket; + struct socket *so; struct kaiocb *job; + so = toep->aiotx_so; CURVNET_SET(toep->vnet); SOCKBUF_LOCK(&so->so_snd); while (!TAILQ_EMPTY(&toep->aiotx_jobq) && sowriteable(so)) { @@ -2209,15 +2209,17 @@ t4_aiotx_task(void *context, int pending) t4_aiotx_process_job(toep, so, job); } - toep->aiotx_task_active = false; + toep->aiotx_so = NULL; SOCKBUF_UNLOCK(&so->so_snd); CURVNET_RESTORE(); free_toepcb(toep); + SOCK_LOCK(so); + sorele(so); } static void -t4_aiotx_queue_toep(struct toepcb *toep) +t4_aiotx_queue_toep(struct socket *so, struct toepcb *toep) { SOCKBUF_LOCK_ASSERT(&toep->inp->inp_socket->so_snd); @@ -2225,9 +2227,10 @@ t4_aiotx_queue_toep(struct toepcb *toep) CTR3(KTR_CXGBE, "%s: queueing aiotx task for tid %d, active = %s", __func__, toep->tid, toep->aiotx_task_active ? "true" : "false"); #endif - if (toep->aiotx_task_active) + if (toep->aiotx_so != NULL) return; - toep->aiotx_task_active = true; + soref(so); + toep->aiotx_so = so; hold_toepcb(toep); soaio_enqueue(&toep->aiotx_task); } @@ -2284,7 +2287,7 @@ t4_aio_queue_aiotx(struct socket *so, struct kaiocb *job) panic("new job was cancelled"); TAILQ_INSERT_TAIL(&toep->aiotx_jobq, job, list); if (sowriteable(so)) - t4_aiotx_queue_toep(toep); + t4_aiotx_queue_toep(so, toep); SOCKBUF_UNLOCK(&so->so_snd); return (0); } diff --git a/sys/dev/cxgbe/tom/t4_tom.h b/sys/dev/cxgbe/tom/t4_tom.h index db9e50cd39e1..d4ff4490abad 100644 --- a/sys/dev/cxgbe/tom/t4_tom.h +++ b/sys/dev/cxgbe/tom/t4_tom.h @@ -194,7 +194,7 @@ struct toepcb { TAILQ_HEAD(, kaiocb) aiotx_jobq; struct task aiotx_task; - bool aiotx_task_active; + struct socket *aiotx_so; /* Tx software descriptor */ uint8_t txsd_total; From fb9a985516b495b6713cda4951a58a721d99df71 Mon Sep 17 00:00:00 2001 From: Ed Maste Date: Thu, 27 Jun 2019 20:34:50 +0000 Subject: [PATCH 159/165] Expose the kernel's build-ID through `uname -b` After r348611 the kernel's build-ID is available via sysctl. Add a -b flag to uname to report it. Submitted by: Ali Mashtizadeh Reviewed by: markj, imp Relnotes: Yes Event: Waterloo Hackathon 2019 Differential Revision: https://reviews.freebsd.org/D20511 --- usr.bin/uname/uname.1 | 10 ++++++++-- usr.bin/uname/uname.c | 19 +++++++++++++++---- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/usr.bin/uname/uname.1 b/usr.bin/uname/uname.1 index 2a5a03f5162f..a3ccc893c1a9 100644 --- a/usr.bin/uname/uname.1 +++ b/usr.bin/uname/uname.1 @@ -28,7 +28,7 @@ .\" @(#)uname.1 8.3 (Berkeley) 4/8/94 .\" $FreeBSD$ .\" -.Dd May 31, 2017 +.Dd June 27, 2019 .Dt UNAME 1 .Os .Sh NAME @@ -36,7 +36,7 @@ .Nd display information about the system .Sh SYNOPSIS .Nm -.Op Fl aiKmnoprsUv +.Op Fl abiKmnoprsUv .Sh DESCRIPTION The .Nm @@ -53,6 +53,8 @@ Behave as though the options and .Fl v were specified. +.It Fl b +Write the kernel's linker-generated build-id to standard output. .It Fl i Write the kernel ident to standard output. .It Fl K @@ -152,3 +154,7 @@ and .Fl U extension flags appeared in .Fx 10.0 . +The +.Fl b +extension flag appeared in +.Fx 13.0 . diff --git a/usr.bin/uname/uname.c b/usr.bin/uname/uname.c index c3bf57303b3c..e97b9c3cb744 100644 --- a/usr.bin/uname/uname.c +++ b/usr.bin/uname/uname.c @@ -67,9 +67,10 @@ static const char sccsid[] = "@(#)uname.c 8.2 (Berkeley) 5/4/95"; #define IFLAG 0x40 #define UFLAG 0x80 #define KFLAG 0x100 +#define BFLAG 0x200 typedef void (*get_t)(void); -static get_t get_ident, get_platform, get_hostname, get_arch, +static get_t get_buildid, get_ident, get_platform, get_hostname, get_arch, get_release, get_sysname, get_kernvers, get_uservers, get_version; static void native_ident(void); @@ -81,11 +82,13 @@ static void native_sysname(void); static void native_version(void); static void native_kernvers(void); static void native_uservers(void); +static void native_buildid(void); static void print_uname(u_int); static void setup_get(void); static void usage(void); -static char *ident, *platform, *hostname, *arch, *release, *sysname, *version, *kernvers, *uservers; +static char *buildid, *ident, *platform, *hostname, *arch, *release, *sysname, + *version, *kernvers, *uservers; static int space; int @@ -97,11 +100,14 @@ main(int argc, char *argv[]) setup_get(); flags = 0; - while ((ch = getopt(argc, argv, "aiKmnoprsUv")) != -1) + while ((ch = getopt(argc, argv, "abiKmnoprsUv")) != -1) switch(ch) { case 'a': flags |= (MFLAG | NFLAG | RFLAG | SFLAG | VFLAG); break; + case 'b': + flags |= BFLAG; + break; case 'i': flags |= IFLAG; break; @@ -169,6 +175,7 @@ setup_get(void) CHECK_ENV("i", ident); CHECK_ENV("K", kernvers); CHECK_ENV("U", uservers); + CHECK_ENV("b", buildid); } #define PRINT_FLAG(flags,flag,var) \ @@ -194,6 +201,7 @@ print_uname(u_int flags) PRINT_FLAG(flags, IFLAG, ident); PRINT_FLAG(flags, KFLAG, kernvers); PRINT_FLAG(flags, UFLAG, uservers); + PRINT_FLAG(flags, BFLAG, buildid); printf("\n"); } @@ -261,6 +269,9 @@ NATIVE_SYSCTL2_GET(arch, CTL_HW, HW_MACHINE_ARCH) { NATIVE_SYSCTLNAME_GET(ident, "kern.ident") { } NATIVE_SET; +NATIVE_SYSCTLNAME_GET(buildid, "kern.build_id") { +} NATIVE_SET; + static void native_uservers(void) { @@ -282,6 +293,6 @@ native_kernvers(void) static void usage(void) { - fprintf(stderr, "usage: uname [-aiKmnoprsUv]\n"); + fprintf(stderr, "usage: uname [-abiKmnoprsUv]\n"); exit(1); } From 7aa24c60064c6c5db48b9114515e368aee05ef14 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Thu, 27 Jun 2019 21:45:40 +0000 Subject: [PATCH 160/165] Use __FBSDID() and sort #includes. No functional change. --- usr.sbin/bhyve/net_utils.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/usr.sbin/bhyve/net_utils.c b/usr.sbin/bhyve/net_utils.c index dc29124e84bd..32b15fc7f54b 100644 --- a/usr.sbin/bhyve/net_utils.c +++ b/usr.sbin/bhyve/net_utils.c @@ -21,17 +21,21 @@ * 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$ */ -#include "net_utils.h" -#include "bhyverun.h" -#include +#include +__FBSDID("$FreeBSD$"); + +#include #include -#include -#include + #include +#include +#include +#include + +#include "bhyverun.h" +#include "net_utils.h" int net_parsemac(char *mac_str, uint8_t *mac_addr) From 94e8f7c65f1580210bb4e95738fe72c3ddc7eb1e Mon Sep 17 00:00:00 2001 From: Rebecca Cran Date: Thu, 27 Jun 2019 22:06:41 +0000 Subject: [PATCH 161/165] Increase EFI_STAGING_SIZE to 100MB on x64 To avoid failures when the large 18MB nvidia.ko module is being loaded, increase EFI_STAGING_SIZE from 64MB to 100MB on x64 systems. Leave the other platforms at 64MB. --- stand/efi/loader/copy.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/stand/efi/loader/copy.c b/stand/efi/loader/copy.c index a19b048c9beb..e134c22c091e 100644 --- a/stand/efi/loader/copy.c +++ b/stand/efi/loader/copy.c @@ -176,8 +176,12 @@ efi_verify_staging_size(unsigned long *nr_pages) #endif /* __i386__ || __amd64__ */ #ifndef EFI_STAGING_SIZE +#if defined(__amd64__) +#define EFI_STAGING_SIZE 100 +#else #define EFI_STAGING_SIZE 64 #endif +#endif EFI_PHYSICAL_ADDRESS staging, staging_end; int stage_offset_set = 0; From 404e646960d5d6c9eb83b0f4a93a14bd5a414ef3 Mon Sep 17 00:00:00 2001 From: Li-Wen Hsu Date: Thu, 27 Jun 2019 22:18:21 +0000 Subject: [PATCH 162/165] Follow r349460 to complete removing "flags" in struct gpiobus_ivar MFC with: r349460 Sponsored by: The FreeBSD Foundation --- sys/dev/gpio/ofw_gpiobus.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sys/dev/gpio/ofw_gpiobus.c b/sys/dev/gpio/ofw_gpiobus.c index 698701c8769d..3c48c62feed3 100644 --- a/sys/dev/gpio/ofw_gpiobus.c +++ b/sys/dev/gpio/ofw_gpiobus.c @@ -321,10 +321,8 @@ ofw_gpiobus_setup_devinfo(device_t bus, device_t child, phandle_t node) ofw_gpiobus_destroy_devinfo(bus, dinfo); return (NULL); } - for (i = 0; i < devi->npins; i++) { - devi->flags[i] = pins[i].flags; + for (i = 0; i < devi->npins; i++) devi->pins[i] = pins[i].pin; - } free(pins, M_DEVBUF); /* Parse the interrupt resources. */ if (ofw_bus_intr_to_rl(bus, node, &dinfo->opd_dinfo.rl, NULL) != 0) { From 6b69072acc25efddad12be41761b773dcd6f468b Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Thu, 27 Jun 2019 22:34:05 +0000 Subject: [PATCH 163/165] Reject attempts to register a TCP stack being unloaded. Reviewed by: gallatin MFC after: 2 weeks Sponsored by: Netflix Differential Revision: https://reviews.freebsd.org/D20617 --- sys/netinet/tcp_subr.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 4ac87cb0d470..8f767305f97d 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -798,8 +798,12 @@ register_tcp_functions_as_names(struct tcp_function_block *blk, int wait, } } + if (blk->tfb_flags & TCP_FUNC_BEING_REMOVED) { + *num_names = 0; + return (EINVAL); + } + refcount_init(&blk->tfb_refcnt, 0); - blk->tfb_flags = 0; blk->tfb_id = atomic_fetchadd_int(&next_tcp_stack_id, 1); for (i = 0; i < *num_names; i++) { n = malloc(sizeof(struct tcp_function), M_TCPFUNCTIONS, wait); From 1db2626a9b449db8ededf7ad5687f504c3ffc64e Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Thu, 27 Jun 2019 22:50:11 +0000 Subject: [PATCH 164/165] Fix comment in sofree() to reference sbdestroy(). r160875 added sbdestroy() as a wrapper around sbrelease_internal to be called from sofree(), yet the comment added in the same revision to sofree() still mentions sbrelease_internal(). Sponsored by: Netflix Differential Revision: https://reviews.freebsd.org/D20488 --- sys/kern/uipc_socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c index e38f8c06bbb3..05be168e8a84 100644 --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -1044,7 +1044,7 @@ sofree(struct socket *so) * * We used to do a lot of socket buffer and socket locking here, as * well as invoke sorflush() and perform wakeups. The direct call to - * dom_dispose() and sbrelease_internal() are an inlining of what was + * dom_dispose() and sbdestroy() are an inlining of what was * necessary from sorflush(). * * Notice that the socket buffer and kqueue state are torn down From e3680954376d380b897066a542ba7cf0b7ba9124 Mon Sep 17 00:00:00 2001 From: Rick Macklem Date: Thu, 27 Jun 2019 23:10:40 +0000 Subject: [PATCH 165/165] Add non-blocking trylock variants for the rangelock functions. A future patch that will add a Linux compatible copy_file_range(2) syscall needs to be able to lock the byte ranges of two files concurrently. To do this without a risk of deadlock, a non-blocking variant of vn_rangelock_rlock() called vn_rangelock_tryrlock() was needed. This patch adds this, along with vn_rangelock_trywlock(), in order to do this. The patch also adds a couple of comments, that I hope clarify how the algorithm used in kern_rangelock.c works. Reviewed by: kib, asomers (previous version) Differential Revision: https://reviews.freebsd.org/D20645 --- sys/kern/kern_rangelock.c | 71 +++++++++++++++++++++++++++++++++------ sys/sys/rangelock.h | 4 +++ sys/sys/vnode.h | 4 +++ 3 files changed, 69 insertions(+), 10 deletions(-) diff --git a/sys/kern/kern_rangelock.c b/sys/kern/kern_rangelock.c index 35bd6e864d37..b434ac4b4c1c 100644 --- a/sys/kern/kern_rangelock.c +++ b/sys/kern/kern_rangelock.c @@ -141,15 +141,33 @@ rangelock_calc_block(struct rangelock *lock) static void rangelock_unlock_locked(struct rangelock *lock, struct rl_q_entry *entry, - struct mtx *ilk) + struct mtx *ilk, bool do_calc_block) { MPASS(lock != NULL && entry != NULL && ilk != NULL); mtx_assert(ilk, MA_OWNED); - KASSERT(entry != lock->rl_currdep, ("stuck currdep")); + + if (!do_calc_block) { + /* + * This is the case where rangelock_enqueue() has been called + * with trylock == true and just inserted this entry in the + * queue. + * If rl_currdep is this entry, rl_currdep needs to + * be set to the next entry in the rl_waiters list. + * However, since this entry is the last entry in the + * list, the next entry is NULL. + */ + if (lock->rl_currdep == entry) { + KASSERT(TAILQ_NEXT(lock->rl_currdep, rl_q_link) == NULL, + ("rangelock_enqueue: next entry not NULL")); + lock->rl_currdep = NULL; + } + } else + KASSERT(entry != lock->rl_currdep, ("stuck currdep")); TAILQ_REMOVE(&lock->rl_waiters, entry, rl_q_link); - rangelock_calc_block(lock); + if (do_calc_block) + rangelock_calc_block(lock); mtx_unlock(ilk); if (curthread->td_rlqe == NULL) curthread->td_rlqe = entry; @@ -164,7 +182,7 @@ rangelock_unlock(struct rangelock *lock, void *cookie, struct mtx *ilk) MPASS(lock != NULL && cookie != NULL && ilk != NULL); mtx_lock(ilk); - rangelock_unlock_locked(lock, cookie, ilk); + rangelock_unlock_locked(lock, cookie, ilk, true); } /* @@ -185,7 +203,7 @@ rangelock_unlock_range(struct rangelock *lock, void *cookie, off_t start, mtx_lock(ilk); if (entry->rl_q_end == end) { - rangelock_unlock_locked(lock, cookie, ilk); + rangelock_unlock_locked(lock, cookie, ilk, true); return (NULL); } entry->rl_q_end = end; @@ -196,11 +214,11 @@ rangelock_unlock_range(struct rangelock *lock, void *cookie, off_t start, /* * Add the lock request to the queue of the pending requests for - * rangelock. Sleep until the request can be granted. + * rangelock. Sleep until the request can be granted unless trylock == true. */ static void * rangelock_enqueue(struct rangelock *lock, off_t start, off_t end, int mode, - struct mtx *ilk) + struct mtx *ilk, bool trylock) { struct rl_q_entry *entry; struct thread *td; @@ -226,11 +244,28 @@ rangelock_enqueue(struct rangelock *lock, off_t start, off_t end, int mode, */ TAILQ_INSERT_TAIL(&lock->rl_waiters, entry, rl_q_link); + /* + * If rl_currdep == NULL, there is no entry waiting for a conflicting + * range to be resolved, so set rl_currdep to this entry. If there is + * no conflicting entry for this entry, rl_currdep will be set back to + * NULL by rangelock_calc_block(). + */ if (lock->rl_currdep == NULL) lock->rl_currdep = entry; rangelock_calc_block(lock); - while (!(entry->rl_q_flags & RL_LOCK_GRANTED)) + while (!(entry->rl_q_flags & RL_LOCK_GRANTED)) { + if (trylock) { + /* + * For this case, the range is not actually locked + * yet, but removal from the list requires the same + * steps, except for not doing a rangelock_calc_block() + * call, since rangelock_calc_block() was called above. + */ + rangelock_unlock_locked(lock, entry, ilk, false); + return (NULL); + } msleep(entry, ilk, 0, "range", 0); + } mtx_unlock(ilk); return (entry); } @@ -239,12 +274,28 @@ void * rangelock_rlock(struct rangelock *lock, off_t start, off_t end, struct mtx *ilk) { - return (rangelock_enqueue(lock, start, end, RL_LOCK_READ, ilk)); + return (rangelock_enqueue(lock, start, end, RL_LOCK_READ, ilk, false)); +} + +void * +rangelock_tryrlock(struct rangelock *lock, off_t start, off_t end, + struct mtx *ilk) +{ + + return (rangelock_enqueue(lock, start, end, RL_LOCK_READ, ilk, true)); } void * rangelock_wlock(struct rangelock *lock, off_t start, off_t end, struct mtx *ilk) { - return (rangelock_enqueue(lock, start, end, RL_LOCK_WRITE, ilk)); + return (rangelock_enqueue(lock, start, end, RL_LOCK_WRITE, ilk, false)); +} + +void * +rangelock_trywlock(struct rangelock *lock, off_t start, off_t end, + struct mtx *ilk) +{ + + return (rangelock_enqueue(lock, start, end, RL_LOCK_WRITE, ilk, true)); } diff --git a/sys/sys/rangelock.h b/sys/sys/rangelock.h index 732bd9406d48..9a8a107aed8f 100644 --- a/sys/sys/rangelock.h +++ b/sys/sys/rangelock.h @@ -75,8 +75,12 @@ void *rangelock_unlock_range(struct rangelock *lock, void *cookie, off_t start, off_t end, struct mtx *ilk); void *rangelock_rlock(struct rangelock *lock, off_t start, off_t end, struct mtx *ilk); +void *rangelock_tryrlock(struct rangelock *lock, off_t start, off_t end, + struct mtx *ilk); void *rangelock_wlock(struct rangelock *lock, off_t start, off_t end, struct mtx *ilk); +void *rangelock_trywlock(struct rangelock *lock, off_t start, off_t end, + struct mtx *ilk); void rlqentry_free(struct rl_q_entry *rlqe); #endif /* _KERNEL */ diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index 0ed2ffc96fb7..cfde146f6765 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -720,8 +720,12 @@ int vn_io_fault_pgmove(vm_page_t ma[], vm_offset_t offset, int xfersize, VI_MTX(vp)) #define vn_rangelock_rlock(vp, start, end) \ rangelock_rlock(&(vp)->v_rl, (start), (end), VI_MTX(vp)) +#define vn_rangelock_tryrlock(vp, start, end) \ + rangelock_tryrlock(&(vp)->v_rl, (start), (end), VI_MTX(vp)) #define vn_rangelock_wlock(vp, start, end) \ rangelock_wlock(&(vp)->v_rl, (start), (end), VI_MTX(vp)) +#define vn_rangelock_trywlock(vp, start, end) \ + rangelock_trywlock(&(vp)->v_rl, (start), (end), VI_MTX(vp)) int vfs_cache_lookup(struct vop_lookup_args *ap); void vfs_timestamp(struct timespec *);