MFhead @ r305013

This commit is contained in:
Enji Cooper 2016-08-29 18:53:36 +00:00
commit 2f52412dee
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/projects/netbsd-tests-update-12/; revision=305014
179 changed files with 13642 additions and 3898 deletions

View File

@ -59,7 +59,7 @@ translator psinfo_t < struct proc *T > {
pr_gid = T->p_ucred->cr_rgid;
pr_egid = T->p_ucred->cr_groups[0];
pr_addr = 0;
pr_psargs = (T->p_args->ar_args == 0) ? "" :
pr_psargs = (T->p_args == 0) ? "" :
memstr(T->p_args->ar_args, ' ', T->p_args->ar_length);
pr_arglen = T->p_args->ar_length;
pr_jailid = T->p_ucred->cr_prison->pr_id;

View File

@ -108,6 +108,12 @@ class Vdev
* \brief No-op copy constructor for nonexistent vdevs.
*/
Vdev();
/**
* \brief No-op virtual destructor, since this class has virtual
* functions.
*/
virtual ~Vdev();
bool DoesNotExist() const;
/**
@ -145,6 +151,10 @@ class Vdev
extern Vdev NonexistentVdev;
//- Vdev Inline Public Methods ------------------------------------------------
inline Vdev::~Vdev()
{
}
inline DevdCtl::Guid
Vdev::PoolGUID() const
{

View File

@ -12,7 +12,11 @@
#define __OPTS_H__
#ifndef SOLARIS
#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
# if defined(sun) && (defined(__svr4__) || defined(__SVR4))
# define SOLARIS 1
# else
# define SOLARIS 0
# endif
#endif
#define OPT_REMOVE 0x000001
#define OPT_DEBUG 0x000002

View File

@ -1128,8 +1128,15 @@ header_common(struct archive_read *a, struct tar *tar,
if (tar->entry_bytes_remaining < 0) {
tar->entry_bytes_remaining = 0;
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Tar entry has negative size?");
err = ARCHIVE_WARN;
"Tar entry has negative size");
return (ARCHIVE_FATAL);
}
if (tar->entry_bytes_remaining == INT64_MAX) {
/* Note: tar_atol returns INT64_MAX on overflow */
tar->entry_bytes_remaining = 0;
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Tar entry size overflow");
return (ARCHIVE_FATAL);
}
tar->realsize = tar->entry_bytes_remaining;
archive_entry_set_size(entry, tar->entry_bytes_remaining);

View File

@ -418,18 +418,30 @@ zip_time(const char *p)
* id1+size1+data1 + id2+size2+data2 ...
* triplets. id and size are 2 bytes each.
*/
static void
process_extra(const char *p, size_t extra_length, struct zip_entry* zip_entry)
static int
process_extra(struct archive_read *a, const char *p, size_t extra_length, struct zip_entry* zip_entry)
{
unsigned offset = 0;
while (offset < extra_length - 4) {
if (extra_length == 0) {
return ARCHIVE_OK;
}
if (extra_length < 4) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Too-small extra data: Need at least 4 bytes, but only found %d bytes", (int)extra_length);
return ARCHIVE_FAILED;
}
while (offset <= extra_length - 4) {
unsigned short headerid = archive_le16dec(p + offset);
unsigned short datasize = archive_le16dec(p + offset + 2);
offset += 4;
if (offset + datasize > extra_length) {
break;
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Extra data overflow: Need %d bytes but only found %d bytes",
(int)datasize, (int)(extra_length - offset));
return ARCHIVE_FAILED;
}
#ifdef DEBUG
fprintf(stderr, "Header id 0x%04x, length %d\n",
@ -715,13 +727,13 @@ process_extra(const char *p, size_t extra_length, struct zip_entry* zip_entry)
}
offset += datasize;
}
#ifdef DEBUG
if (offset != extra_length)
{
fprintf(stderr,
"Extra data field contents do not match reported size!\n");
if (offset != extra_length) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Malformed extra data: Consumed %d bytes of %d bytes",
(int)offset, (int)extra_length);
return ARCHIVE_FAILED;
}
#endif
return ARCHIVE_OK;
}
/*
@ -840,7 +852,9 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
return (ARCHIVE_FATAL);
}
process_extra(h, extra_length, zip_entry);
if (ARCHIVE_OK != process_extra(a, h, extra_length, zip_entry)) {
return ARCHIVE_FATAL;
}
__archive_read_consume(a, extra_length);
/* Work around a bug in Info-Zip: When reading from a pipe, it
@ -1293,7 +1307,7 @@ zip_read_data_deflate(struct archive_read *a, const void **buff,
&& bytes_avail > zip->entry_bytes_remaining) {
bytes_avail = (ssize_t)zip->entry_bytes_remaining;
}
if (bytes_avail <= 0) {
if (bytes_avail < 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated ZIP file body");
return (ARCHIVE_FATAL);
@ -2691,7 +2705,9 @@ slurp_central_directory(struct archive_read *a, struct zip *zip)
"Truncated ZIP file header");
return ARCHIVE_FATAL;
}
process_extra(p + filename_length, extra_length, zip_entry);
if (ARCHIVE_OK != process_extra(a, p + filename_length, extra_length, zip_entry)) {
return ARCHIVE_FATAL;
}
/*
* Mac resource fork files are stored under the

View File

@ -138,6 +138,7 @@ set_acl(struct archive *a, int fd, const char *name,
acl_permset_t acl_permset;
#ifdef ACL_TYPE_NFS4
acl_flagset_t acl_flagset;
int r;
#endif
int ret;
int ae_type, ae_permset, ae_tag, ae_id;
@ -145,7 +146,7 @@ set_acl(struct archive *a, int fd, const char *name,
gid_t ae_gid;
const char *ae_name;
int entries;
int i, r;
int i;
ret = ARCHIVE_OK;
entries = archive_acl_reset(abstract_acl, ae_requested_type);

View File

@ -2401,8 +2401,18 @@ check_symlinks(struct archive_write_disk *a)
r = lstat(a->name, &st);
if (r != 0) {
/* We've hit a dir that doesn't exist; stop now. */
if (errno == ENOENT)
if (errno == ENOENT) {
break;
} else {
/* Note: This effectively disables deep directory
* support when security checks are enabled.
* Otherwise, very long pathnames that trigger
* an error here could evade the sandbox.
* TODO: We could do better, but it would probably
* require merging the symlink checks with the
* deep-directory editing. */
return (ARCHIVE_FAILED);
}
} else if (S_ISLNK(st.st_mode)) {
if (c == '\0') {
/*

View File

@ -182,7 +182,7 @@ safe_fprintf(FILE *f, const char *fmt, ...)
}
/* If our output buffer is full, dump it and keep going. */
if (i > (sizeof(outbuff) - 20)) {
if (i > (sizeof(outbuff) - 128)) {
outbuff[i] = '\0';
fprintf(f, "%s", outbuff);
i = 0;

View File

@ -94,7 +94,7 @@ struct speed {
int sp; /* the actual speed */
};
#define DATA(number) { B##number, number }
#define DATA(number) { (NCURSES_OSPEED)B##number, number }
static struct speed const speeds[] =
{

View File

@ -32,6 +32,9 @@ basic_head()
}
basic_body()
{
# Begin FreeBSD
atf_tc_expect_fail "dirname //usr//bin doesn't return //usr like it used to; bug # 212193"
# End FreeBSD
atf_check -o inline:"/\n" dirname /
atf_check -o inline:"/\n" dirname //
atf_check -o inline:"/usr\n" dirname /usr/bin/

View File

@ -392,11 +392,9 @@ int c4iw_post_send(struct ibv_qp *ibqp, struct ibv_send_wr *wr,
t4_sq_produce(&qhp->wq, len16);
idx += DIV_ROUND_UP(len16*16, T4_EQ_ENTRY_SIZE);
}
if (t4_wq_db_enabled(&qhp->wq)) {
t4_ring_sq_db(&qhp->wq, idx, dev_is_t5(qhp->rhp),
len16, wqe);
} else
ring_kernel_db(qhp, qhp->wq.sq.qid, idx);
t4_ring_sq_db(&qhp->wq, idx, dev_is_t5(qhp->rhp),
len16, wqe);
qhp->wq.sq.queue[qhp->wq.sq.size].status.host_wq_pidx = \
(qhp->wq.sq.wq_pidx);
pthread_spin_unlock(&qhp->lock);
@ -458,11 +456,9 @@ int c4iw_post_receive(struct ibv_qp *ibqp, struct ibv_recv_wr *wr,
wr = wr->next;
num_wrs--;
}
if (t4_wq_db_enabled(&qhp->wq))
t4_ring_rq_db(&qhp->wq, idx, dev_is_t5(qhp->rhp),
len16, wqe);
else
ring_kernel_db(qhp, qhp->wq.rq.qid, idx);
t4_ring_rq_db(&qhp->wq, idx, dev_is_t5(qhp->rhp),
len16, wqe);
qhp->wq.rq.queue[qhp->wq.rq.size].status.host_wq_pidx = \
(qhp->wq.rq.wq_pidx);
pthread_spin_unlock(&qhp->lock);

View File

@ -39,4 +39,23 @@ char *basename_r(const char *, char *);
char *dirname(char *);
__END_DECLS
/*
* In FreeBSD 12, the prototype of dirname() was modified to comply to
* POSIX. This function may now modify its input. Unfortunately, our
* copy of xinstall(8) shipped with previous versions of FreeBSD is
* built using the host headers and libc during the bootstrapping phase
* and depends on the old behavior.
*
* Apply a workaround where we explicitly link against dirname@FBSD_1.0
* in case this function is called on constant strings, instead of
* making the build fail.
*/
#if defined(__generic) && !defined(__cplusplus)
__BEGIN_DECLS
char *__old_dirname(const char *);
__END_DECLS
__sym_compat(dirname, __old_dirname, FBSD_1.0);
#define dirname(x) __generic(x, const char *, __old_dirname, dirname)(x)
#endif
#endif /* !_LIBGEN_H_ */

View File

@ -211,8 +211,6 @@ TESTS_SRCS= \
test_write_disk_perms.c \
test_write_disk_secure.c \
test_write_disk_secure744.c \
test_write_disk_secure745.c \
test_write_disk_secure746.c \
test_write_disk_sparse.c \
test_write_disk_symlink.c \
test_write_disk_times.c \

View File

@ -4,7 +4,7 @@
SRCS+= amd64_get_fsbase.c amd64_get_gsbase.c amd64_set_fsbase.c \
amd64_set_gsbase.c
MDASM= vfork.S brk.S cerror.S exect.S getcontext.S ptrace.S \
MDASM= vfork.S brk.S cerror.S exect.S getcontext.S \
sbrk.S setlogin.S sigreturn.S
# Don't generate default code for these syscalls:

View File

@ -1,55 +0,0 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* William Jolitz.
*
* 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.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*/
#if defined(SYSLIBC_SCCS) && !defined(lint)
.asciz "@(#)ptrace.s 5.1 (Berkeley) 4/23/90"
#endif /* SYSLIBC_SCCS and not lint */
#include <machine/asm.h>
__FBSDID("$FreeBSD$");
#include "SYS.h"
ENTRY(ptrace)
xorl %eax,%eax
#ifdef PIC
movq PIC_GOT(CNAME(errno)),%r8
movl %eax,(%r8)
#else
movl %eax,CNAME(errno)(%rip)
#endif
mov $SYS_ptrace,%eax
KERNCALL
jb HIDENAME(cerror)
ret
END(ptrace)
.section .note.GNU-stack,"",%progbits

View File

@ -2,7 +2,7 @@
SRCS+= __vdso_gettc.c
MDASM= Ovfork.S brk.S cerror.S ptrace.S sbrk.S shmat.S sigreturn.S syscall.S
MDASM= Ovfork.S brk.S cerror.S sbrk.S shmat.S sigreturn.S syscall.S
# Don't generate default code for these syscalls:
NOASM= break.o exit.o getlogin.o sstk.o vfork.o yield.o

View File

@ -1,51 +0,0 @@
/* $NetBSD: ptrace.S,v 1.7 2003/08/07 16:42:04 agc Exp $ */
/*-
* Copyright (c) 1990 The Regents of the University of California.
* 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 University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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: @(#)ptrace.s 5.1 (Berkeley) 4/23/90
*/
#include <machine/asm.h>
__FBSDID("$FreeBSD$");
#include "SYS.h"
ENTRY(ptrace)
stmfd sp!, {r0-r3, lr}
sub sp, sp, #4 /* align stack */
bl PIC_SYM(_C_LABEL(__error), PLT)
add sp, sp, #4 /* unalign stack */
mov r1, #0x00000000
str r1, [r0]
ldmfd sp!, {r0-r3, lr}
SYSTRAP(ptrace)
bcs PIC_SYM(CERROR, PLT)
RET
END(ptrace)
.section .note.GNU-stack,"",%progbits

View File

@ -31,7 +31,7 @@ __FBSDID("$FreeBSD$");
#include <string.h>
char *
dirname(char *path)
(dirname)(char *path)
{
const char *in, *prev, *begin, *end;
char *out;

View File

@ -7,7 +7,7 @@ SRCS+= i386_clr_watch.c i386_set_watch.c i386_vm86.c
SRCS+= i386_get_fsbase.c i386_get_gsbase.c i386_get_ioperm.c i386_get_ldt.c \
i386_set_fsbase.c i386_set_gsbase.c i386_set_ioperm.c i386_set_ldt.c
MDASM= Ovfork.S brk.S cerror.S exect.S getcontext.S ptrace.S \
MDASM= Ovfork.S brk.S cerror.S exect.S getcontext.S \
sbrk.S setlogin.S sigreturn.S syscall.S
# Don't generate default code for these syscalls:

View File

@ -1,57 +0,0 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* William Jolitz.
*
* 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.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*/
#if defined(SYSLIBC_SCCS) && !defined(lint)
.asciz "@(#)ptrace.s 5.1 (Berkeley) 4/23/90"
#endif /* SYSLIBC_SCCS and not lint */
#include <machine/asm.h>
__FBSDID("$FreeBSD$");
#include "SYS.h"
ENTRY(ptrace)
xorl %eax,%eax
#ifdef PIC
PIC_PROLOGUE
movl PIC_GOT(CNAME(errno)),%edx
movl %eax,(%edx)
PIC_EPILOGUE
#else
movl %eax,CNAME(errno)
#endif
mov $SYS_ptrace,%eax
KERNCALL
jb HIDENAME(cerror)
ret
END(ptrace)
.section .note.GNU-stack,"",%progbits

View File

@ -335,6 +335,7 @@ int __sys_openat(int, const char *, int, ...);
int __sys_pselect(int, struct fd_set *, struct fd_set *,
struct fd_set *, const struct timespec *,
const __sigset_t *);
int __sys_ptrace(int, __pid_t, char *, int);
int __sys_poll(struct pollfd *, unsigned, int);
int __sys_ppoll(struct pollfd *, unsigned, const struct timespec *,
const __sigset_t *);

View File

@ -3,7 +3,7 @@
SRCS+= trivial-vdso_tc.c
MDASM= Ovfork.S brk.S cerror.S exect.S \
ptrace.S sbrk.S syscall.S
sbrk.S syscall.S
# Don't generate default code for these syscalls:
NOASM= break.o exit.o getlogin.o sstk.o vfork.o yield.o

View File

@ -1,71 +0,0 @@
/* $NetBSD: ptrace.S,v 1.9 2003/08/07 16:42:17 agc Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Ralph Campbell.
*
* 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 University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 <machine/asm.h>
__FBSDID("$FreeBSD$");
#include "SYS.h"
#if defined(LIBC_SCCS) && !defined(lint)
ASMSTR("from: @(#)ptrace.s 8.1 (Berkeley) 6/4/93")
ASMSTR("$NetBSD: ptrace.S,v 1.9 2003/08/07 16:42:17 agc Exp $")
#endif /* LIBC_SCCS and not lint */
NESTED_NOPROFILE(ptrace, CALLFRAME_SIZ, ra)
.mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
SETUP_GP
PTR_SUBU sp, sp, CALLFRAME_SIZ
SETUP_GP64(CALLFRAME_GP, ptrace)
SAVE_GP(CALLFRAME_GP)
PTR_S ra, CALLFRAME_RA(sp)
PTR_LA t9, _C_LABEL(__error) # locate address of errno
jalr t9
PTR_L ra, CALLFRAME_RA(sp)
INT_S zero, 0(v0) # update errno value
li v0, SYS_ptrace
syscall
# Load __cerror's address using our gp, then restore it.
PTR_LA t9, __cerror
RESTORE_GP64
PTR_ADDU sp, sp, CALLFRAME_SIZ
bne a3, zero, 1f
j ra
1: j t9
END(ptrace)

View File

@ -224,6 +224,7 @@ struct ai_order {
struct policyqueue *aio_dstpolicy;
struct addrinfo *aio_ai;
int aio_matchlen;
int aio_initial_sequence;
};
static const ns_src default_dns_files[] = {
@ -708,6 +709,7 @@ reorder(struct addrinfo *sentinel)
aio[i].aio_dstpolicy = match_addrselectpolicy(ai->ai_addr,
&policyhead);
set_source(&aio[i], &policyhead);
aio[i].aio_initial_sequence = i;
}
/* perform sorting. */
@ -1066,6 +1068,23 @@ comp_dst(const void *arg1, const void *arg2)
}
/* Rule 10: Otherwise, leave the order unchanged. */
/*
* Note that qsort is unstable; so, we can't return zero and
* expect the order to be unchanged.
* That also means we can't depend on the current position of
* dst2 being after dst1. We must enforce the initial order
* with an explicit compare on the original position.
* The qsort specification requires that "When the same objects
* (consisting of width bytes, irrespective of their current
* positions in the array) are passed more than once to the
* comparison function, the results shall be consistent with one
* another."
* In other words, If A < B, then we must also return B > A.
*/
if (dst2->aio_initial_sequence < dst1->aio_initial_sequence)
return(1);
return(-1);
}

View File

@ -1,6 +1,6 @@
# $FreeBSD$
MDASM+= brk.S cerror.S exect.S ptrace.S sbrk.S setlogin.S
MDASM+= brk.S cerror.S exect.S sbrk.S setlogin.S
# Don't generate default code for these syscalls:
NOASM= break.o exit.o getlogin.o sstk.o yield.o

View File

@ -1,61 +0,0 @@
/*-
* Copyright (c) 2002 Peter Grehan.
* 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.
*/
/* $NetBSD: ptrace.S,v 1.3 2000/02/23 20:16:57 kleink Exp $ */
#include <machine/asm.h>
__FBSDID("$FreeBSD$");
#include "SYS.h"
ENTRY(ptrace)
mflr %r0
stwu %r1,-32(%r1)
stw %r0,36(%r1)
stw %r3,8(%r1)
stw %r4,12(%r1)
stw %r5,16(%r1)
stw %r6,20(%r1)
bl PIC_PLT(CNAME(__error))
li %r7,0
stw %r7,0(%r3)
lwz %r3,8(%r1)
lwz %r4,12(%r1)
lwz %r5,16(%r1)
lwz %r0,36(%r1)
lwz %r6,20(%r1)
mtlr %r0
la %r1,32(%r1)
li %r0,SYS_ptrace
sc
bso 1f
blr
1:
b PIC_PLT(HIDENAME(cerror))
END(ptrace)
.section .note.GNU-stack,"",%progbits

View File

@ -1,6 +1,6 @@
# $FreeBSD$
MDASM+= brk.S cerror.S exect.S ptrace.S sbrk.S setlogin.S
MDASM+= brk.S cerror.S exect.S sbrk.S setlogin.S
# Don't generate default code for these syscalls:
NOASM= break.o exit.o getlogin.o sstk.o yield.o

View File

@ -12,7 +12,7 @@ SRCS+= __sparc_sigtramp_setup.c \
CFLAGS+= -I${LIBC_SRCTOP}/sparc64/fpu
MDASM+= brk.S cerror.S exect.S ptrace.S sbrk.S setlogin.S sigaction1.S
MDASM+= brk.S cerror.S exect.S sbrk.S setlogin.S sigaction1.S
# Don't generate default code for these syscalls:
NOASM= break.o exit.o getlogin.o sstk.o yield.o

View File

@ -1,57 +0,0 @@
/*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* 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.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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: Header: ptrace.s,v 1.2 91/12/20 01:59:00 leres Exp
* from: NetBSD: ptrace.S,v 1.4 2000/07/24 00:11:10 mycroft Exp
*/
#if defined(SYSLIBC_SCCS) && !defined(lint)
.asciz "@(#)ptrace.s 8.1 (Berkeley) 6/4/93"
#if 0
RCSID("$NetBSD: ptrace.S,v 1.4 2000/07/24 00:11:10 mycroft Exp $")
#endif
#endif /* SYSLIBC_SCCS and not lint */
#include <machine/asm.h>
__FBSDID("$FreeBSD$");
#include "SYS.h"
_SYSENTRY(ptrace)
save %sp, -CCFSZ, %sp
call CNAME(__error)
nop
stw %g0, [%o0]
restore
_SYSCALL(ptrace)
retl
nop
_SYSEND(ptrace)

View File

@ -139,8 +139,11 @@ fgetln(FILE *fp, size_t *lenp)
(void)memcpy((void *)(fp->_lb._base + off), (void *)fp->_p,
len - off);
off = len;
if (__srefill(fp))
break; /* EOF or error: return partial line */
if (__srefill(fp)) {
if (__sfeof(fp))
break;
goto error;
}
if ((p = memchr((void *)fp->_p, '\n', (size_t)fp->_r)) == NULL)
continue;

View File

@ -53,7 +53,6 @@ fgetwln_l(FILE * __restrict fp, size_t *lenp, locale_t locale)
ORIENT(fp, 1);
len = 0;
/* WEOF or error: return partial line, see fgetln(3). */
while ((wc = __fgetwc(fp, locale)) != WEOF) {
#define GROW 512
if (len * sizeof(wchar_t) >= fp->_lb._size &&
@ -65,7 +64,7 @@ fgetwln_l(FILE * __restrict fp, size_t *lenp, locale_t locale)
if (wc == L'\n')
break;
}
if (len == 0)
if (len == 0 || (wc == WEOF && !__sfeof(fp)))
goto error;
FUNLOCKFILE(fp);

View File

@ -48,6 +48,7 @@ INTERPOSED = \
poll \
ppoll \
pselect \
ptrace \
read \
readv \
recvfrom \

View File

@ -2,7 +2,7 @@
.\" $NetBSD: ptrace.2,v 1.2 1995/02/27 12:35:37 cgd Exp $
.\"
.\" This file is in the public domain.
.Dd July 28, 2016
.Dd August 28, 2016
.Dt PTRACE 2
.Os
.Sh NAME
@ -906,7 +906,13 @@ to return
\-1
as a non-error value; to disambiguate,
.Va errno
can be set to 0 before the call and checked afterwards.
is set to 0 in the libc wrapper for the
.Fn ptrace
system call and
.Fn ptrace
callers can reliably check
.Va errno
for non-zero value afterwards.
.Sh ERRORS
The
.Fn ptrace

49
lib/libc/sys/ptrace.c Normal file
View File

@ -0,0 +1,49 @@
/*
* Copyright (c) 2016 The FreeBSD Foundation.
* All rights reserved.
*
* Portions of this software were developed by Konstantin Belousov
* 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(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), 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 COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/ptrace.h>
#include <errno.h>
#include "libc_private.h"
__weak_reference(_ptrace, ptrace);
int
_ptrace(int request, pid_t pid, caddr_t addr, int data)
{
errno = 0;
return (__sys_ptrace(request, pid, addr, data));
}

View File

@ -11,7 +11,8 @@ SHLIB_MAJOR= 0
.PATH: ${.CURDIR}/../../sys/contrib/libnv ${.CURDIR}/../../sys/sys
CFLAGS+=-I${.CURDIR}/../../sys -I${.CURDIR}
SRCS= dnvlist.c
SRCS= cnvlist.c
SRCS+= dnvlist.c
SRCS+= msgio.c
SRCS+= nvlist.c
SRCS+= nvpair.c

View File

@ -1,6 +1,7 @@
# $FreeBSD$
ATF_TESTS_CXX= \
cnv_tests \
dnv_tests \
nv_array_tests \
nv_tests \

1508
lib/libnv/tests/cnv_tests.cc Normal file

File diff suppressed because it is too large Load Diff

View File

@ -439,7 +439,7 @@ dos_readdir(struct open_file *fd, struct dirent *d)
u_char fn[261];
DOS_DIR dd;
size_t res;
u_int chk, i, x, xdn;
u_int chk, x, xdn;
int err;
x = chk = 0;
@ -598,7 +598,7 @@ lookup(DOS_FS *fs, u_int clus, const char *name, DOS_DE **dep)
u_char lfn[261];
u_char sfn[13];
u_int nsec, lsec, xdn, chk, sec, ent, x;
int err, ok, i;
int err, ok;
if (!clus)
for (ent = 0; ent < 2; ent++)
@ -774,11 +774,11 @@ fatget(DOS_FS *fs, u_int *c)
int err = 0;
if (fat.unit != dd->d_unit) {
/* fat cache was changed to another device, dont use it */
/* fat cache was changed to another device, don't use it */
err = ioread(fs, secbyt(fs->lsnfat) + fatoff(fs->fatsz, *c), buf,
fs->fatsz != 32 ? 2 : 4);
if (err)
return err;
return (err);
} else {
offset = fatoff(fs->fatsz, *c);
nbyte = fs->fatsz != 32 ? 2 : 4;

View File

@ -645,7 +645,7 @@ _mips_get_tls(void)
".set\tmips64r2\n\t"
"rdhwr\t%0, $29\n\t"
".set\tpop"
: "=v" (_rv));
: "=r" (_rv));
/*
* XXXSS See 'git show c6be4f4d2d1b71c04de5d3bbb6933ce2dbcdb317'
*
@ -670,7 +670,7 @@ _mips_get_tls(void)
".set\tmips32r2\n\t"
"rdhwr\t%0, $29\n\t"
".set\tpop"
: "=v" (_rv));
: "=r" (_rv));
/*
* XXXSS See 'git show c6be4f4d2d1b71c04de5d3bbb6933ce2dbcdb317'
*

File diff suppressed because it is too large Load Diff

View File

@ -132,7 +132,11 @@ lzf_decompress (const void *const in_data, unsigned int in_len,
* Unconditionally aligning does not cost very much, so do it if unsure
*/
#ifndef STRICT_ALIGN
# define STRICT_ALIGN !(defined(__i386) || defined (__amd64))
# if !(defined(__i386) || defined (__amd64))
# define STRICT_ALIGN 1
# else
# define STRICT_ALIGN 0
# endif
#endif
/*

View File

@ -57,6 +57,7 @@ MAN= accept_filter.9 \
byteorder.9 \
casuword.9 \
cd.9 \
cnv.9 \
condvar.9 \
config_intrhook.9 \
contigmalloc.9 \
@ -617,6 +618,41 @@ MLINKS+=byteorder.9 be16dec.9 \
byteorder.9 le64dec.9 \
byteorder.9 le64enc.9 \
byteorder.9 le64toh.9
MLINKS+=cnv.9 cnvlist.9 \
cnv.9 cnvlist_free_binary.9 \
cnv.9 cnvlist_free_bool.9 \
cnv.9 cnvlist_free_bool_array.9 \
cnv.9 cnvlist_free_descriptor.9 \
cnv.9 cnvlist_free_descriptor_array.9 \
cnv.9 cnvlist_free_null.9 \
cnv.9 cnvlist_free_number.9 \
cnv.9 cnvlist_free_number_array.9 \
cnv.9 cnvlist_free_nvlist.9 \
cnv.9 cnvlist_free_nvlist_array.9 \
cnv.9 cnvlist_free_string.9 \
cnv.9 cnvlist_free_string_array.9 \
cnv.9 cnvlist_get_binary.9 \
cnv.9 cnvlist_get_bool.9 \
cnv.9 cnvlist_get_bool_array.9 \
cnv.9 cnvlist_get_descriptor.9 \
cnv.9 cnvlist_get_descriptor_array.9 \
cnv.9 cnvlist_get_number.9 \
cnv.9 cnvlist_get_number_array.9 \
cnv.9 cnvlist_get_nvlist.9 \
cnv.9 cnvlist_get_nvlist_array.9 \
cnv.9 cnvlist_get_string.9 \
cnv.9 cnvlist_get_string_array.9 \
cnv.9 cnvlist_take_binary.9 \
cnv.9 cnvlist_take_bool.9 \
cnv.9 cnvlist_take_bool_array.9 \
cnv.9 cnvlist_take_descriptor.9 \
cnv.9 cnvlist_take_descriptor_array.9 \
cnv.9 cnvlist_take_number.9 \
cnv.9 cnvlist_take_number_array.9 \
cnv.9 cnvlist_take_nvlist.9 \
cnv.9 cnvlist_take_nvlist_array.9 \
cnv.9 cnvlist_take_string.9 \
cnv.9 cnvlist_take_string_array.9
MLINKS+=condvar.9 cv_broadcast.9 \
condvar.9 cv_broadcastpri.9 \
condvar.9 cv_destroy.9 \

199
share/man/man9/cnv.9 Normal file
View File

@ -0,0 +1,199 @@
.\"
.\" Copyright (c) 2016 Adam Starak <starak.adam@gmail.com>
.\" 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 27, 2016
.Dt CNV 9
.Os
.Sh NAME
.Nm cnvlist_get,
.Nm cnvlist_take,
.Nm cnvlist_free,
.Nd "API for managing name/value pairs by cookie."
.Sh LIBRARY
.Lb libnv
.Sh SYNOPSIS
.In sys/cnv.h
.Ft bool
.Fn cnvlist_get_bool "void *cookiep"
.Ft uint64_t
.Fn cnvlist_get_number "void *cookiep"
.Ft "const char *"
.Fn cnvlist_get_string "void *cookiep"
.Ft "const nvlist_t *"
.Fn cnvlist_get_nvlist "void *cookiep"
.Ft "const void *"
.Fn cnvlist_get_binary "void *cookiep" "size_t *sizep"
.Ft "const bool *"
.Fn cnvlist_get_bool_array "void *cookiep" "size_t *nitemsp"
.Ft "const uint64_t *"
.Fn cnvlist_get_number_array "void *cookiep" "size_t *nitemsp"
.Ft "const char * const *"
.Fn cnvlist_get_string_array "void *cookiep" "size_t *nitemsp"
.Ft "const nvlist_t * const *"
.Fn cnvlist_get_nvlist_array "void *cookiep" "size_t *nitemsp"
.Ft int
.Fn cnvlist_get_descriptor "void *cookiep"
.Ft "const int *"
.Fn cnvlist_get_descriptor_array "void *cookiep" "size_t *nitemsp"
.\"
.Ft bool
.Fn cnvlist_take_bool "void *cookiep"
.Ft uint64_t
.Fn cnvlist_take_number "void *cookiep"
.Ft "const char *"
.Fn cnvlist_take_string "void *cookiep"
.Ft "const nvlist_t *"
.Fn cnvlist_take_nvlist "void *cookiep"
.Ft "const void *"
.Fn cnvlist_take_binary "void *cookiep" "size_t *sizep"
.Ft "const bool *"
.Fn cnvlist_take_bool_array "void *cookiep" "size_t *nitemsp"
.Ft "const uint64_t *"
.Fn cnvlist_take_number_array "void *cookiep" "size_t *nitemsp"
.Ft "const char * const *"
.Fn cnvlist_take_string_array "void *cookiep" "size_t *nitemsp"
.Ft "const nvlist_t * const *"
.Fn cnvlist_take_nvlist_array "void *cookiep" "size_t *nitemsp"
.Ft int
.Fn cnvlist_take_descriptor "void *cookiep"
.Ft "const int *'
.Fn cnvlist_take_descriptor_array "void *cookiep" "size_t *nitemsp"
.\"
.Ft void
.Fn cnvlist_free_null "nvlist_t *nvl" "void *cookiep"
.Ft void
.Fn cnvlist_free_bool "nvlist_t *nvl" "void *cookiep"
.Ft void
.Fn cnvlist_free_number "nvlist_t *nvl" "void *cookiep"
.Ft void
.Fn cnvlist_free_string "nvlist_t *nvl" "void *cookiep"
.Ft void
.Fn cnvlist_free_nvlist "nvlist_t *nvl" "void *cookiep"
.Ft void
.Fn cnvlist_free_descriptor "nvlist_t *nvl" "void *cookiep"
.Ft void
.Fn cnvlist_free_binary "nvlist_t *nvl" "void *cookiep"
.Ft void
.Fn cnvlist_free_bool_array "nvlist_t *nvl" "void *cookiep"
.Ft void
.Fn cnvlist_free_number_array "nvlist_t *nvl" "void *cookiep"
.Ft void
.Fn cnvlist_free_string_array "nvlist_t *nvl" "void *cookiep"
.Ft void
.Fn cnvlist_free_nvlist_array "nvlist_t *nvl" "void *cookiep"
.Ft void
.Fn cnvlist_free_descriptor_array "nvlist_t *nvl" "void *cookiep"
.Sh DESCRIPTION
The
.Nm libnv
library permits easy management of name/value pairs and can send and receive
them over sockets.
For more information, also see
.Xr nv 9 .
.Pp
The concept of cookies is explained in
.Fn nvlist_next ,
.Fn nvlist_get_parent ,
and
.Fn nvlist_get_pararr
from
.Xr nv 9 .
.Pp
The
.Nm cnvlist_get
family of functions obtains the value associated with the given cookie.
Returned strings, nvlists, descriptors, binaries, or arrays must not be modified
by the user, since they still belong to the nvlist.
The nvlist must not be in an error state.
.Pp
The
.Nm cnvlist_take
family of functions returns the value associated with the given cookie and
removes the element from the nvlist.
When the value is a string, binary, or array value, the caller is responsible
for freeing the returned memory with
.Fn free 3 .
When the value is an nvlist, the caller is responsible for destroying the
returned nvlist with
.Fn nvlist_destroy .
When the value is a descriptor, the caller is responsible for closing the
returned descriptor with the
.Fn close 2 .
.Pp
The
.Nm cnvlist_free
family of functions removes an element of the supplied cookie and frees all
resources.
If an element of the given cookie has the wrong type or does not exist, the
program
is aborted.
.Sh EXAMPLE
The following example demonstrates how to deal with cnvlist API.
.Bd -literal
int type;
void *cookie, *scookie, *bcookie;
nvlist_t *nvl;
char *name;
nvl = nvlist_create(0);
nvlist_add_bool(nvl, "test", 1 == 2);
nvlist_add_string(nvl, "test2", "cnvlist");
cookie = NULL;
while (nvlist_next(nvl, &type, &cookie) != NULL) {
switch (type) {
case NV_TYPE_BOOL:
printf("test: %d\\n", cnvlist_get_bool(cookie));
bcookie = cookie;
break;
case NV_TYPE_STRING:
printf("test2: %s\\n", cnvlist_get_string(cookie));
scookie = cookie;
break;
}
}
name = cnvlist_take_string(nvl, scookie);
cnvlist_free_bool(nvl, bcookie);
printf("test2: %s\\n", name);
free(name);
printf("nvlist_empty = %d\\n", nvlist_empty(nvl));
nvlist_destroy(nvl);
return (0);
.Ed
.Sh SEE ALSO
.Xr nv 9 ,
.Xr close 2 ,
.Xr free 3
.Sh AUTHORS
.An -nosplit
The
.Nm cnv
API was created during the Google Summer Of Code 2016 by

View File

@ -297,6 +297,8 @@ cleandepend:
rm -rf ${CLEANDEPENDDIRS}
.endif
.endif
.ORDER: cleandepend all
.ORDER: cleandepend depend
.if !target(checkdpadd) && (defined(DPADD) || defined(LDADD))
_LDADD_FROM_DPADD= ${DPADD:R:T:C;^lib(.*)$;-l\1;g}

View File

@ -156,6 +156,7 @@ clean:
-rm -rf ${CLEANDIRS}
.endif
.endif
.ORDER: clean all
cleandir: cleanobj

View File

@ -128,6 +128,11 @@ CWARNFLAGS+= -Wno-error=address \
-Wno-error=unused-value
.endif
# GCC 5.3.0
.if ${COMPILER_TYPE} == "gcc" && ${COMPILER_VERSION} >= 50300
CWARNFLAGS+= -Wno-error=strict-overflow
.endif
# GCC 6.1.0
.if ${COMPILER_TYPE} == "gcc" && ${COMPILER_VERSION} >= 60100
CWARNFLAGS+= -Wno-error=misleading-indentation \

View File

@ -23,6 +23,7 @@ _src_env_conf_included_: .NOTMAIN
.if make(*install*) && ${.MAKE.LEVEL} == 0
META_MODE= normal
MK_META_MODE= no
.export MK_META_MODE
.endif
# If we were found via .../share/mk we need to replace that

View File

@ -5153,8 +5153,7 @@ pmap_copy(pmap_t dst_pmap, pmap_t src_pmap, vm_offset_t dst_addr, vm_size_t len,
}
/*
* pmap_zero_page zeros the specified hardware page by mapping
* the page into KVM and using bzero to clear its contents.
* Zero the specified hardware page.
*/
void
pmap_zero_page(vm_page_t m)
@ -5165,10 +5164,8 @@ pmap_zero_page(vm_page_t m)
}
/*
* pmap_zero_page_area zeros the specified hardware page by mapping
* the page into KVM and using bzero to clear its contents.
*
* off and size may not cover an area beyond a single hardware page.
* Zero an an area within a single hardware page. off and size must not
* cover an area beyond a single hardware page.
*/
void
pmap_zero_page_area(vm_page_t m, int off, int size)
@ -5182,24 +5179,20 @@ pmap_zero_page_area(vm_page_t m, int off, int size)
}
/*
* pmap_zero_page_idle zeros the specified hardware page by mapping
* the page into KVM and using bzero to clear its contents. This
* is intended to be called from the vm_pagezero process only and
* outside of Giant.
* Zero the specified hardware page in a way that minimizes cache thrashing.
* This is intended to be called from the vm_pagezero process only and
* outside of Giant.
*/
void
pmap_zero_page_idle(vm_page_t m)
{
vm_offset_t va = PHYS_TO_DMAP(VM_PAGE_TO_PHYS(m));
pagezero((void *)va);
sse2_pagezero((void *)va);
}
/*
* pmap_copy_page copies the specified (machine independent)
* page by mapping the page into virtual memory and using
* bcopy to copy the page, one machine dependent page at a
* time.
* Copy 1 specified hardware page to another.
*/
void
pmap_copy_page(vm_page_t msrc, vm_page_t mdst)

View File

@ -72,6 +72,30 @@ ENTRY(pagezero)
ret
END(pagezero)
/* Address: %rdi */
ENTRY(sse2_pagezero)
PUSH_FRAME_POINTER
movq $-PAGE_SIZE,%rdx
subq %rdx,%rdi
xorl %eax,%eax
jmp 1f
/*
* The loop takes 29 bytes. Ensure that it doesn't cross a 32-byte
* cache line.
*/
.p2align 5,0x90
1:
movnti %rax,(%rdi,%rdx)
movnti %rax,8(%rdi,%rdx)
movnti %rax,16(%rdi,%rdx)
movnti %rax,24(%rdi,%rdx)
addq $32,%rdx
jne 1b
sfence
POP_FRAME_POINTER
ret
END(sse2_pagezero)
ENTRY(bcmp)
PUSH_FRAME_POINTER
movq %rdx,%rcx

View File

@ -57,6 +57,7 @@ void gsbase_load_fault(void) __asm(__STRING(gsbase_load_fault));
void fpstate_drop(struct thread *td);
void pagezero(void *addr);
void setidt(int idx, alias_for_inthand_t *func, int typ, int dpl, int ist);
void sse2_pagezero(void *addr);
struct savefpu *get_pcb_user_save_td(struct thread *td);
struct savefpu *get_pcb_user_save_pcb(struct pcb *pcb);

View File

@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include <machine/cpu.h>
#include <machine/md_var.h>
#include "vmm_util.h"
@ -51,6 +52,10 @@ static int iommu_avail;
SYSCTL_INT(_hw_vmm_iommu, OID_AUTO, initialized, CTLFLAG_RD, &iommu_avail,
0, "bhyve iommu initialized?");
static int iommu_enable = 1;
SYSCTL_INT(_hw_vmm_iommu, OID_AUTO, enable, CTLFLAG_RDTUN, &iommu_enable, 0,
"Enable use of I/O MMU (required for PCI passthrough).");
static struct iommu_ops *ops;
static void *host_domain;
@ -148,7 +153,7 @@ IOMMU_DISABLE(void)
(*ops->disable)();
}
void
static void
iommu_init(void)
{
int error, bus, slot, func;
@ -156,6 +161,9 @@ iommu_init(void)
const char *name;
device_t dev;
if (!iommu_enable)
return;
if (vmm_is_intel())
ops = &iommu_ops_intel;
else if (vmm_is_amd())
@ -174,8 +182,13 @@ iommu_init(void)
*/
maxaddr = vmm_mem_maxaddr();
host_domain = IOMMU_CREATE_DOMAIN(maxaddr);
if (host_domain == NULL)
panic("iommu_init: unable to create a host domain");
if (host_domain == NULL) {
printf("iommu_init: unable to create a host domain");
IOMMU_CLEANUP();
ops = NULL;
iommu_avail = 0;
return;
}
/*
* Create 1:1 mappings from '0' to 'maxaddr' for devices assigned to
@ -216,7 +229,16 @@ iommu_cleanup(void)
void *
iommu_create_domain(vm_paddr_t maxaddr)
{
static volatile int iommu_initted;
if (iommu_initted < 2) {
if (atomic_cmpset_int(&iommu_initted, 0, 1)) {
iommu_init();
atomic_store_rel_int(&iommu_initted, 2);
} else
while (iommu_initted == 1)
cpu_spinwait();
}
return (IOMMU_CREATE_DOMAIN(maxaddr));
}

View File

@ -61,7 +61,6 @@ struct iommu_ops {
extern struct iommu_ops iommu_ops_intel;
extern struct iommu_ops iommu_ops_amd;
void iommu_init(void);
void iommu_cleanup(void);
void *iommu_host_domain(void);
void *iommu_create_domain(vm_paddr_t maxaddr);

View File

@ -224,11 +224,6 @@ SYSCTL_INT(_hw_vmm, OID_AUTO, trace_guest_exceptions, CTLFLAG_RDTUN,
&trace_guest_exceptions, 0,
"Trap into hypervisor on all guest exceptions and reflect them back");
static int vmm_force_iommu = 0;
TUNABLE_INT("hw.vmm.force_iommu", &vmm_force_iommu);
SYSCTL_INT(_hw_vmm, OID_AUTO, force_iommu, CTLFLAG_RDTUN, &vmm_force_iommu, 0,
"Force use of I/O MMU even if no passthrough devices were found.");
static void vm_free_memmap(struct vm *vm, int ident);
static bool sysmem_mapping(struct vm *vm, struct mem_map *mm);
static void vcpu_notify_event_locked(struct vcpu *vcpu, bool lapic_intr);
@ -358,8 +353,6 @@ vmm_handler(module_t mod, int what, void *arg)
switch (what) {
case MOD_LOAD:
vmmdev_init();
if (vmm_force_iommu || ppt_avail_devices() > 0)
iommu_init();
error = vmm_init();
if (error == 0)
vmm_initialized = 1;
@ -396,9 +389,6 @@ static moduledata_t vmm_kmod = {
/*
* vmm initialization has the following dependencies:
*
* - iommu initialization must happen after the pci passthru driver has had
* a chance to attach to any passthru devices (after SI_SUB_CONFIGURE).
*
* - VT-x initialization requires smp_rendezvous() and therefore must happen
* after SMP is fully functional (after SI_SUB_SMP).
*/
@ -893,6 +883,8 @@ vm_assign_pptdev(struct vm *vm, int bus, int slot, int func)
("vm_assign_pptdev: iommu must be NULL"));
maxaddr = sysmem_maxaddr(vm);
vm->iommu = iommu_create_domain(maxaddr);
if (vm->iommu == NULL)
return (ENXIO);
vm_iommu_map(vm);
}

View File

@ -1089,7 +1089,9 @@ DB_SHOW_COMMAND(vtop, db_show_vtop)
if (have_addr) {
phys = arm64_address_translate_s1e1r(addr);
db_printf("Physical address reg: 0x%016lx\n", phys);
db_printf("Physical address reg (read): 0x%016lx\n", phys);
phys = arm64_address_translate_s1e1w(addr);
db_printf("Physical address reg (write): 0x%016lx\n", phys);
} else
db_printf("show vtop <virt_addr>\n");
}

View File

@ -497,7 +497,7 @@ bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t offset, size_t size,
char *buf, size_t *rsize)
{
struct disk_devdesc *dev = (struct disk_devdesc *)devdata;
int blks;
int blks, remaining;
#ifdef BD_SUPPORT_FRAGS /* XXX: sector size */
char fragbuf[BIOSDISK_SECSIZE];
size_t fragsize;
@ -513,14 +513,15 @@ bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t offset, size_t size,
if (rsize)
*rsize = 0;
if (dblk >= BD(dev).bd_sectors) {
DEBUG("IO past disk end %llu", (unsigned long long)dblk);
return (EIO);
}
if (dblk + blks > BD(dev).bd_sectors) {
/* perform partial read */
blks = BD(dev).bd_sectors - dblk;
/*
* Perform partial read to prevent read-ahead crossing
* the end of disk - or any 32 bit aliases of the end.
* Signed arithmetic is used to handle wrap-around cases
* like we do for TCP sequence numbers.
*/
remaining = (int)(BD(dev).bd_sectors - dblk); /* truncate */
if (remaining > 0 && remaining < blks) {
blks = remaining;
size = blks * BD(dev).bd_sectorsize;
DEBUG("short read %d", blks);
}

View File

@ -88,6 +88,7 @@ ata_op_string(struct ata_cmd *cmd)
}
return "DSM";
case 0x08: return ("DEVICE_RESET");
case 0x0b: return ("REQUEST_SENSE_DATA_EXT");
case 0x20: return ("READ");
case 0x24: return ("READ48");
case 0x25: return ("READ_DMA48");
@ -120,6 +121,12 @@ ata_op_string(struct ata_cmd *cmd)
case 0x47: return ("READ_LOG_DMA_EXT");
case 0x4a: return ("ZAC_MANAGEMENT_IN");
case 0x51: return ("CONFIGURE_STREAM");
case 0x57: return ("WRITE_LOG_DMA_EXT");
case 0x5b: return ("TRUSTED_NON_DATA");
case 0x5c: return ("TRUSTED_RECEIVE");
case 0x5d: return ("TRUSTED_RECEIVE_DMA");
case 0x5e: return ("TRUSTED_SEND");
case 0x5f: return ("TRUSTED_SEND_DMA");
case 0x60: return ("READ_FPDMA_QUEUED");
case 0x61: return ("WRITE_FPDMA_QUEUED");
case 0x63:
@ -160,9 +167,12 @@ ata_op_string(struct ata_cmd *cmd)
}
return ("SEP_ATTN");
case 0x70: return ("SEEK");
case 0x77: return ("SET_DATE_TIME_EXT");
case 0x78: return ("ACCESSIBLE_MAX_ADDRESS_CONFIGURATION");
case 0x87: return ("CFA_TRANSLATE_SECTOR");
case 0x90: return ("EXECUTE_DEVICE_DIAGNOSTIC");
case 0x92: return ("DOWNLOAD_MICROCODE");
case 0x93: return ("DOWNLOAD_MICROCODE_DMA");
case 0x9a: return ("ZAC_MANAGEMENT_OUT");
case 0xa0: return ("PACKET");
case 0xa1: return ("ATAPI_IDENTIFY");
@ -180,6 +190,7 @@ ata_op_string(struct ata_cmd *cmd)
}
return ("SMART");
case 0xb1: return ("DEVICE CONFIGURATION");
case 0xb4: return ("SANITIZE_DEVICE");
case 0xc0: return ("CFA_ERASE");
case 0xc4: return ("READ_MUL");
case 0xc5: return ("WRITE_MUL");

View File

@ -526,6 +526,7 @@ contrib/libfdt/fdt_rw.c optional fdt
contrib/libfdt/fdt_strerror.c optional fdt
contrib/libfdt/fdt_sw.c optional fdt
contrib/libfdt/fdt_wip.c optional fdt
contrib/libnv/cnvlist.c standard
contrib/libnv/dnvlist.c standard
contrib/libnv/nvlist.c standard
contrib/libnv/nvpair.c standard
@ -1157,19 +1158,26 @@ dev/bhnd/bcma/bcma_bhndb.c optional bcma bhnd bhndb
dev/bhnd/bcma/bcma_erom.c optional bcma bhnd
dev/bhnd/bcma/bcma_nexus.c optional bcma_nexus bcma bhnd
dev/bhnd/bcma/bcma_subr.c optional bcma bhnd
dev/bhnd/cores/chipc/bhnd_chipc_if.m optional bhnd
dev/bhnd/cores/chipc/bhnd_sprom_chipc.c optional bhnd
dev/bhnd/cores/chipc/bhnd_pmu_chipc.c optional bhnd
dev/bhnd/cores/chipc/chipc.c optional bhnd
dev/bhnd/cores/chipc/chipc_cfi.c optional bhnd cfi
dev/bhnd/cores/chipc/chipc_slicer.c optional bhnd cfi | bhnd spibus
dev/bhnd/cores/chipc/chipc_spi.c optional bhnd spibus
dev/bhnd/cores/chipc/chipc_subr.c optional bhnd
dev/bhnd/cores/chipc/bhnd_chipc_if.m optional bhnd
dev/bhnd/cores/chipc/bhnd_sprom_chipc.c optional bhnd
dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.c optional bhnd
dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_subr.c optional bhnd
dev/bhnd/cores/pci/bhnd_pci.c optional bhnd pci
dev/bhnd/cores/pci/bhnd_pci_hostb.c optional bhndb bhnd pci
dev/bhnd/cores/pci/bhnd_pcib.c optional bhnd_pcib bhnd pci
dev/bhnd/cores/pcie2/bhnd_pcie2.c optional bhnd pci
dev/bhnd/cores/pcie2/bhnd_pcie2_hostb.c optional bhndb bhnd pci
dev/bhnd/cores/pcie2/bhnd_pcie2b.c optional bhnd_pcie2b bhnd pci
dev/bhnd/cores/pmu/bhnd_pmu.c optional bhnd
dev/bhnd/cores/pmu/bhnd_pmu_core.c optional bhnd
dev/bhnd/cores/pmu/bhnd_pmu_if.m optional bhnd
dev/bhnd/cores/pmu/bhnd_pmu_subr.c optional bhnd
dev/bhnd/nvram/bhnd_nvram.c optional bhnd
dev/bhnd/nvram/bhnd_nvram_common.c optional bhnd
dev/bhnd/nvram/bhnd_nvram_cfe.c optional bhnd siba_nexus cfe | \

View File

@ -1882,6 +1882,12 @@
#define AR_PHY_PLL_BB_DPLL3 AR_PHY_65NM(overlay_0x16180.Osprey.ch0_bb_dpll3)
#define AR_PHY_PLL_BB_DPLL4 AR_PHY_65NM(overlay_0x16180.Osprey.ch0_bb_dpll4)
/*
* Wasp/Hornet PHY USB PLL control
*/
#define AR_PHY_USB_CTRL1 0x16c84
#define AR_PHY_USB_CTRL2 0x16c88
/*
* PMU Register Map
*/

View File

@ -32,7 +32,13 @@
# define __KERNEL__
#endif
#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
#ifndef SOLARIS
# if defined(sun) && (defined(__svr4__) || defined(__SVR4))
# define SOLARIS 1
# else
# define SOLARIS 0
# endif
#endif
#if defined(__SVR4) || defined(__svr4__) || defined(__sgi)

View File

@ -29,7 +29,11 @@
#endif
#ifndef SOLARIS
# define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
# if defined(sun) && (defined(__svr4__) || defined(__SVR4))
# define SOLARIS 1
# else
# define SOLARIS 0
# endif
#endif
#ifndef __P

View File

@ -19,7 +19,11 @@
# include <osreldate.h>
#endif
#ifndef SOLARIS
# define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
# if defined(sun) && (defined(__svr4__) || defined(__SVR4))
# define SOLARIS 1
# else
# define SOLARIS 0
# endif
#endif
#include <sys/errno.h>
#include <sys/types.h>

View File

@ -13,8 +13,12 @@
#ifndef __IP_NAT_H__
#define __IP_NAT_H__
#ifndef SOLARIS
#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
#ifndef SOLARIS
# if defined(sun) && (defined(__svr4__) || defined(__SVR4))
# define SOLARIS 1
# else
# define SOLARIS 0
# endif
#endif
#if defined(__STDC__) || defined(__GNUC__) || defined(_AIX51)

View File

@ -12,8 +12,12 @@
#ifndef __IP_PROXY_H__
#define __IP_PROXY_H__
#ifndef SOLARIS
#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
#ifndef SOLARIS
# if defined(sun) && (defined(__svr4__) || defined(__SVR4))
# define SOLARIS 1
# else
# define SOLARIS 0
# endif
#endif
#if defined(__STDC__) || defined(__GNUC__) || defined(_AIX51)

197
sys/contrib/libnv/cnvlist.c Normal file
View File

@ -0,0 +1,197 @@
/*-
* Copyright (c) 2016 Adam Starak <starak.adam@gmail.com>
* 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 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#ifdef _KERNEL
#include <sys/types.h>
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <machine/stdarg.h>
#else
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#endif
#include <sys/cnv.h>
#include <sys/nv.h>
#include "nv_impl.h"
#include "nvlist_impl.h"
#include "nvpair_impl.h"
#define CNVLIST_GET(ftype, type, NVTYPE) \
ftype \
cnvlist_get_##type(void *cookiep) \
{ \
\
if (nvpair_type(cookiep) != NV_TYPE_##NVTYPE) { \
nvlist_report_missing(NV_TYPE_##NVTYPE, \
nvpair_name(cookiep)); \
} \
return (nvpair_get_##type(cookiep)); \
}
CNVLIST_GET(bool, bool, BOOL)
CNVLIST_GET(uint64_t, number, NUMBER)
CNVLIST_GET(const char *, string, STRING)
CNVLIST_GET(const nvlist_t *, nvlist, NVLIST)
#ifndef _KERNEL
CNVLIST_GET(int, descriptor, DESCRIPTOR)
#endif
#undef CNVLIST_GET
#define CNVLIST_GET_ARRAY(ftype, type, NVTYPE) \
ftype \
cnvlist_get_##type(void *cookiep, size_t *nitemsp) \
{ \
\
if (nvpair_type(cookiep) != NV_TYPE_##NVTYPE) { \
nvlist_report_missing(NV_TYPE_##NVTYPE, \
nvpair_name(cookiep)); \
} \
return (nvpair_get_##type(cookiep, nitemsp)); \
}
CNVLIST_GET_ARRAY(const bool *, bool_array, BOOL_ARRAY)
CNVLIST_GET_ARRAY(const uint64_t *, number_array, NUMBER_ARRAY)
CNVLIST_GET_ARRAY(const char * const *, string_array, STRING_ARRAY)
CNVLIST_GET_ARRAY(const nvlist_t * const *, nvlist_array, NVLIST_ARRAY)
#ifndef _KERNEL
CNVLIST_GET_ARRAY(const int *, descriptor_array, DESCRIPTOR_ARRAY)
#endif
#undef CNVLIST_GET_ARRAY
const void *
cnvlist_get_binary(void *cookiep, size_t *sizep)
{
if (nvpair_type(cookiep) != NV_TYPE_BINARY)
nvlist_report_missing(NV_TYPE_BINARY, nvpair_name(cookiep));
return (nvpair_get_binary(cookiep, sizep));
}
#define CNVLIST_TAKE(ftype, type, NVTYPE) \
ftype \
cnvlist_take_##type(nvlist_t *nvl, void *cookiep) \
{ \
ftype value; \
\
if (nvpair_type(cookiep) != NV_TYPE_##NVTYPE) { \
nvlist_report_missing(NV_TYPE_##NVTYPE, \
nvpair_name(cookiep)); \
} \
value = (ftype)(intptr_t)nvpair_get_##type(cookiep); \
nvlist_remove_nvpair(nvl, cookiep); \
nvpair_free_structure(cookiep); \
return (value); \
}
CNVLIST_TAKE(bool, bool, BOOL)
CNVLIST_TAKE(uint64_t, number, NUMBER)
CNVLIST_TAKE(char *, string, STRING)
CNVLIST_TAKE(nvlist_t *, nvlist, NVLIST)
#ifndef _KERNEL
CNVLIST_TAKE(int, descriptor, DESCRIPTOR)
#endif
#undef CNVLIST_TAKE
#define CNVLIST_TAKE_ARRAY(ftype, type, NVTYPE) \
ftype \
cnvlist_take_##type(nvlist_t *nvl, void *cookiep, size_t *nitemsp) \
{ \
ftype value; \
\
if (nvpair_type(cookiep) != NV_TYPE_##NVTYPE) { \
nvlist_report_missing(NV_TYPE_##NVTYPE, \
nvpair_name(cookiep)); \
} \
value = (ftype)(intptr_t)nvpair_get_##type(cookiep, nitemsp); \
nvlist_remove_nvpair(nvl, cookiep); \
nvpair_free_structure(cookiep); \
return (value); \
}
CNVLIST_TAKE_ARRAY(bool *, bool_array, BOOL_ARRAY)
CNVLIST_TAKE_ARRAY(uint64_t *, number_array, NUMBER_ARRAY)
CNVLIST_TAKE_ARRAY(char **, string_array, STRING_ARRAY)
CNVLIST_TAKE_ARRAY(nvlist_t **, nvlist_array, NVLIST_ARRAY)
#ifndef _KERNEL
CNVLIST_TAKE_ARRAY(int *, descriptor_array, DESCRIPTOR_ARRAY);
#endif
#undef CNVLIST_TAKE_ARRAY
void *
cnvlist_take_binary(nvlist_t *nvl, void *cookiep, size_t *sizep)
{
void *value;
if (nvpair_type(cookiep) != NV_TYPE_BINARY)
nvlist_report_missing(NV_TYPE_BINARY, nvpair_name(cookiep));
value = (void *)(intptr_t)nvpair_get_binary(cookiep, sizep);
nvlist_remove_nvpair(nvl, cookiep);
nvpair_free_structure(cookiep);
return (value);
}
#define CNVLIST_FREE(type) \
void \
cnvlist_free_##type(nvlist_t *nvl, void *cookiep) \
{ \
\
nvlist_free_nvpair(nvl, cookiep); \
}
CNVLIST_FREE(bool)
CNVLIST_FREE(number)
CNVLIST_FREE(string)
CNVLIST_FREE(nvlist)
CNVLIST_FREE(binary);
CNVLIST_FREE(bool_array)
CNVLIST_FREE(number_array)
CNVLIST_FREE(string_array)
CNVLIST_FREE(nvlist_array)
#ifndef _KERNEL
CNVLIST_FREE(descriptor)
CNVLIST_FREE(descriptor_array)
#endif
#undef CNVLIST_FREE

View File

@ -314,7 +314,7 @@ nvlist_set_flags(nvlist_t *nvl, int flags)
nvl->nvl_flags = flags;
}
static void
void
nvlist_report_missing(int type, const char *name)
{

View File

@ -39,6 +39,7 @@
#include <stdint.h>
#endif
void nvlist_report_missing(int type, const char *name);
nvpair_t *nvlist_get_nvpair_parent(const nvlist_t *nvl);
const unsigned char *nvlist_unpack_header(nvlist_t *nvl,
const unsigned char *ptr, size_t nfds, bool *isbep, size_t *leftp);

View File

@ -72,6 +72,7 @@ static db_cmdfcn_t db_halt;
static db_cmdfcn_t db_kill;
static db_cmdfcn_t db_reset;
static db_cmdfcn_t db_stack_trace;
static db_cmdfcn_t db_stack_trace_active;
static db_cmdfcn_t db_stack_trace_all;
static db_cmdfcn_t db_watchdog;
@ -79,6 +80,12 @@ static db_cmdfcn_t db_watchdog;
* 'show' commands
*/
static struct command db_show_active_cmds[] = {
{ "trace", db_stack_trace_active, 0, NULL },
};
struct command_table db_show_active_table =
LIST_HEAD_INITIALIZER(db_show_active_table);
static struct command db_show_all_cmds[] = {
{ "trace", db_stack_trace_all, 0, NULL },
};
@ -86,6 +93,7 @@ struct command_table db_show_all_table =
LIST_HEAD_INITIALIZER(db_show_all_table);
static struct command db_show_cmds[] = {
{ "active", 0, 0, &db_show_active_table },
{ "all", 0, 0, &db_show_all_table },
{ "registers", db_show_regs, 0, NULL },
{ "breaks", db_listbreak_cmd, 0, NULL },
@ -120,6 +128,8 @@ static struct command db_cmds[] = {
{ "match", db_trace_until_matching_cmd,0, NULL },
{ "trace", db_stack_trace, CS_OWN, NULL },
{ "t", db_stack_trace, CS_OWN, NULL },
/* XXX alias for active trace */
{ "acttrace", db_stack_trace_active, 0, NULL },
/* XXX alias for all trace */
{ "alltrace", db_stack_trace_all, 0, NULL },
{ "where", db_stack_trace, CS_OWN, NULL },
@ -195,6 +205,9 @@ db_command_init(void)
db_command_register(&db_cmd_table, &db_cmds[i]);
for (i = 0; i < N(db_show_cmds); i++)
db_command_register(&db_show_table, &db_show_cmds[i]);
for (i = 0; i < N(db_show_active_cmds); i++)
db_command_register(&db_show_active_table,
&db_show_active_cmds[i]);
for (i = 0; i < N(db_show_all_cmds); i++)
db_command_register(&db_show_all_table, &db_show_all_cmds[i]);
#undef N
@ -799,8 +812,7 @@ db_stack_trace(db_expr_t tid, bool hastid, db_expr_t count, char *modif)
}
static void
db_stack_trace_all(db_expr_t dummy, bool dummy2, db_expr_t dummy3,
char *dummy4)
_db_stack_trace_all(bool active_only)
{
struct proc *p;
struct thread *td;
@ -811,8 +823,18 @@ db_stack_trace_all(db_expr_t dummy, bool dummy2, db_expr_t dummy3,
prev_jb = kdb_jmpbuf(jb);
if (setjmp(jb) == 0) {
FOREACH_THREAD_IN_PROC(p, td) {
db_printf("\nTracing command %s pid %d tid %ld td %p\n",
p->p_comm, p->p_pid, (long)td->td_tid, td);
if (td->td_state == TDS_RUNNING)
db_printf("\nTracing command %s pid %d"
" tid %ld td %p (CPU %d)\n",
p->p_comm, p->p_pid,
(long)td->td_tid, td,
td->td_oncpu);
else if (active_only)
continue;
else
db_printf("\nTracing command %s pid %d"
" tid %ld td %p\n", p->p_comm,
p->p_pid, (long)td->td_tid, td);
db_trace_thread(td, -1);
if (db_pager_quit) {
kdb_jmpbuf(prev_jb);
@ -824,6 +846,22 @@ db_stack_trace_all(db_expr_t dummy, bool dummy2, db_expr_t dummy3,
}
}
static void
db_stack_trace_active(db_expr_t dummy, bool dummy2, db_expr_t dummy3,
char *dummy4)
{
_db_stack_trace_all(true);
}
static void
db_stack_trace_all(db_expr_t dummy, bool dummy2, db_expr_t dummy3,
char *dummy4)
{
_db_stack_trace_all(false);
}
/*
* Take the parsed expression value from the command line that was parsed
* as a hexadecimal value and convert it as if the expression was parsed

View File

@ -57,7 +57,8 @@ db_term(db_expr_t *valuep)
if (!db_value_of_name(db_tok_string, valuep) &&
!db_value_of_name_pcpu(db_tok_string, valuep) &&
!db_value_of_name_vnet(db_tok_string, valuep)) {
db_error("Symbol not found\n");
db_printf("Symbol '%s' not found\n", db_tok_string);
db_error(NULL);
/*NOTREACHED*/
}
return (true);
@ -89,12 +90,14 @@ db_term(db_expr_t *valuep)
}
if (t == tLPAREN) {
if (!db_expression(valuep)) {
db_error("Syntax error\n");
db_printf("Expression syntax error after '%c'\n", '(');
db_error(NULL);
/*NOTREACHED*/
}
t = db_read_token();
if (t != tRPAREN) {
db_error("Syntax error\n");
db_printf("Expression syntax error -- expected '%c'\n", ')');
db_error(NULL);
/*NOTREACHED*/
}
return (true);
@ -164,7 +167,9 @@ db_mult_expr(db_expr_t *valuep)
while (t == tSTAR || t == tSLASH || t == tPCT || t == tHASH ||
t == tBIT_AND ) {
if (!db_term(&rhs)) {
db_printf("Expression syntax error after '%c'\n", '!');
db_printf("Expression syntax error after '%c'\n",
t == tSTAR ? '*' : t == tSLASH ? '/' : t == tPCT ? '%' :
t == tHASH ? '#' : '&');
db_error(NULL);
/*NOTREACHED*/
}
@ -177,7 +182,7 @@ db_mult_expr(db_expr_t *valuep)
break;
default:
if (rhs == 0) {
db_error("Divide by 0\n");
db_error("Division by 0\n");
/*NOTREACHED*/
}
if (t == tSLASH)
@ -199,7 +204,6 @@ db_add_expr(db_expr_t *valuep)
{
db_expr_t lhs, rhs;
int t;
char c;
if (!db_mult_expr(&lhs))
return (false);
@ -207,8 +211,8 @@ db_add_expr(db_expr_t *valuep)
t = db_read_token();
while (t == tPLUS || t == tMINUS || t == tBIT_OR) {
if (!db_mult_expr(&rhs)) {
c = db_tok_string[0];
db_printf("Expression syntax error after '%c'\n", c);
db_printf("Expression syntax error after '%c'\n",
t == tPLUS ? '+' : t == tMINUS ? '-' : '|');
db_error(NULL);
/*NOTREACHED*/
}
@ -243,11 +247,14 @@ db_shift_expr(db_expr_t *valuep)
t = db_read_token();
while (t == tSHIFT_L || t == tSHIFT_R) {
if (!db_add_expr(&rhs)) {
db_error("Syntax error\n");
db_printf("Expression syntax error after '%s'\n",
t == tSHIFT_L ? "<<" : ">>");
db_error(NULL);
/*NOTREACHED*/
}
if (rhs < 0) {
db_error("Negative shift amount\n");
db_printf("Negative shift amount %jd\n", (intmax_t)rhs);
db_error(NULL);
/*NOTREACHED*/
}
if (t == tSHIFT_L)
@ -269,7 +276,6 @@ db_logical_relation_expr(
{
db_expr_t lhs, rhs;
int t;
char op[3];
if (!db_shift_expr(&lhs))
return (false);
@ -277,11 +283,11 @@ db_logical_relation_expr(
t = db_read_token();
while (t == tLOG_EQ || t == tLOG_NOT_EQ || t == tGREATER ||
t == tGREATER_EQ || t == tLESS || t == tLESS_EQ) {
op[0] = db_tok_string[0];
op[1] = db_tok_string[1];
op[2] = 0;
if (!db_shift_expr(&rhs)) {
db_printf("Expression syntax error after \"%s\"\n", op);
db_printf("Expression syntax error after '%s'\n",
t == tLOG_EQ ? "==" : t == tLOG_NOT_EQ ? "!=" :
t == tGREATER ? ">" : t == tGREATER_EQ ? ">=" :
t == tLESS ? "<" : "<=");
db_error(NULL);
/*NOTREACHED*/
}

View File

@ -259,6 +259,78 @@ bcma_suspend_core(device_t dev, device_t child)
return (ENXIO);
}
static uint32_t
bcma_read_config(device_t dev, device_t child, bus_size_t offset, u_int width)
{
struct bcma_devinfo *dinfo;
struct bhnd_resource *r;
/* Must be a directly attached child core */
if (device_get_parent(child) != dev)
return (UINT32_MAX);
/* Fetch the agent registers */
dinfo = device_get_ivars(child);
if ((r = dinfo->res_agent) == NULL)
return (UINT32_MAX);
/* Verify bounds */
if (offset > rman_get_size(r->res))
return (UINT32_MAX);
if (rman_get_size(r->res) - offset < width)
return (UINT32_MAX);
switch (width) {
case 1:
return (bhnd_bus_read_1(r, offset));
case 2:
return (bhnd_bus_read_2(r, offset));
case 4:
return (bhnd_bus_read_4(r, offset));
default:
return (UINT32_MAX);
}
}
static void
bcma_write_config(device_t dev, device_t child, bus_size_t offset, uint32_t val,
u_int width)
{
struct bcma_devinfo *dinfo;
struct bhnd_resource *r;
/* Must be a directly attached child core */
if (device_get_parent(child) != dev)
return;
/* Fetch the agent registers */
dinfo = device_get_ivars(child);
if ((r = dinfo->res_agent) == NULL)
return;
/* Verify bounds */
if (offset > rman_get_size(r->res))
return;
if (rman_get_size(r->res) - offset < width)
return;
switch (width) {
case 1:
bhnd_bus_write_1(r, offset, val);
break;
case 2:
bhnd_bus_write_2(r, offset, val);
break;
case 4:
bhnd_bus_write_4(r, offset, val);
break;
default:
break;
}
}
static u_int
bcma_get_port_count(device_t dev, device_t child, bhnd_port_type type)
{
@ -420,6 +492,42 @@ bcma_free_bhnd_dinfo(device_t dev, struct bhnd_devinfo *dinfo)
bcma_free_dinfo(dev, (struct bcma_devinfo *)dinfo);
}
static int
bcma_get_core_table(device_t dev, device_t child, struct bhnd_core_info **cores,
u_int *num_cores)
{
struct bcma_softc *sc;
struct bcma_erom erom;
const struct bhnd_chipid *cid;
struct resource *r;
int error;
int rid;
sc = device_get_softc(dev);
/* Map the EROM table. */
cid = BHND_BUS_GET_CHIPID(dev, dev);
rid = 0;
r = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, cid->enum_addr,
cid->enum_addr + BCMA_EROM_TABLE_SIZE, BCMA_EROM_TABLE_SIZE,
RF_ACTIVE);
if (r == NULL) {
device_printf(dev, "failed to allocate EROM resource\n");
return (ENXIO);
}
/* Enumerate all declared cores */
if ((error = bcma_erom_open(&erom, r, BCMA_EROM_TABLE_START)))
goto cleanup;
error = bcma_erom_get_core_info(&erom, cores, num_cores);
cleanup:
bus_release_resource(dev, SYS_RES_MEMORY, rid, r);
return (error);
}
/**
* Scan a device enumeration ROM table, adding all valid discovered cores to
* the bus.
@ -473,6 +581,9 @@ bcma_add_children(device_t bus, struct resource *erom_res, bus_size_t erom_offse
* unpopulated, the device shouldn't be used. */
if (bhnd_is_hw_disabled(child))
device_disable(child);
/* Issue bus callback for fully initialized child. */
BHND_BUS_CHILD_ADDED(bus, child);
}
/* Hit EOF parsing cores? */
@ -502,8 +613,11 @@ static device_method_t bcma_methods[] = {
DEVMETHOD(bhnd_bus_find_hostb_device, bcma_find_hostb_device),
DEVMETHOD(bhnd_bus_alloc_devinfo, bcma_alloc_bhnd_dinfo),
DEVMETHOD(bhnd_bus_free_devinfo, bcma_free_bhnd_dinfo),
DEVMETHOD(bhnd_bus_get_core_table, bcma_get_core_table),
DEVMETHOD(bhnd_bus_reset_core, bcma_reset_core),
DEVMETHOD(bhnd_bus_suspend_core, bcma_suspend_core),
DEVMETHOD(bhnd_bus_read_config, bcma_read_config),
DEVMETHOD(bhnd_bus_write_config, bcma_write_config),
DEVMETHOD(bhnd_bus_get_port_count, bcma_get_port_count),
DEVMETHOD(bhnd_bus_get_region_count, bcma_get_region_count),
DEVMETHOD(bhnd_bus_get_port_rid, bcma_get_port_rid),

View File

@ -51,15 +51,22 @@ __FBSDID("$FreeBSD$");
static int
bcma_bhndb_probe(device_t dev)
{
const struct bhnd_chipid *cid;
const struct bhnd_chipid *cid;
int error;
/* Defer to default probe implementation */
if ((error = bcma_probe(dev)) > 0)
return (error);
/* Check bus type */
cid = BHNDB_GET_CHIPID(device_get_parent(dev), dev);
if (cid->chip_type != BHND_CHIPTYPE_BCMA)
return (ENXIO);
/* Delegate to default probe implementation */
return (bcma_probe(dev));
/* Set device description */
bhnd_set_default_bus_desc(dev, cid);
return (error);
}
static int

View File

@ -109,6 +109,19 @@
#define BCMA_DMP_OOBDINWIDTH 0x364
#define BCMA_DMP_OOBDOUTWIDTH 0x368
/* The exact interpretation of these bits is unverified; these
* are our best guesses as to their use */
#define BCMA_DMP_OOBSEL_MASK 0xFF /**< OOBSEL config mask */
#define BCMA_DMP_OOBSEL_0_MASK BCMA_DMP_OOBSEL_MASK
#define BCMA_DMP_OOBSEL_1_MASK BCMA_DMP_OOBSEL_MASK
#define BCMA_DMP_OOBSEL_2_MASK BCMA_DMP_OOBSEL_MASK
#define BCMA_DMP_OOBSEL_3_MASK BCMA_DMP_OOBSEL_MASK
#define BCMA_DMP_OOBSEL_0_SHIFT 0 /**< first OOBSEL config */
#define BCMA_DMP_OOBSEL_1_SHIFT 8 /**< second OOBSEL config */
#define BCMA_DMP_OOBSEL_2_SHIFT 16 /**< third OOBSEL config */
#define BCMA_DMP_OOBSEL_3_SHIFT 24 /**< fouth OOBSEL config */
#define BCMA_DMP_OOBSEL_EN (1 << 7) /**< enable bit */
// This was inherited from Broadcom's aidmp.h header
// Is it required for any of our use-cases?
#if 0 /* defined(IL_BIGENDIAN) && defined(BCMHND74K) */

View File

@ -65,10 +65,18 @@ static int erom_skip_mport(struct bcma_erom *erom);
static int erom_skip_sport_region(struct bcma_erom *erom);
static int erom_seek_next(struct bcma_erom *erom, uint8_t etype);
static int erom_region_to_port_type(struct bcma_erom *erom,
uint8_t region_type, bhnd_port_type *port_type);
#define EROM_LOG(erom, fmt, ...) \
device_printf(erom->dev, "erom[0x%llx]: " fmt, \
(unsigned long long) (erom->offset), ##__VA_ARGS__);
#define EROM_LOG(erom, fmt, ...) do { \
if (erom->dev != NULL) { \
device_printf(erom->dev, "erom[0x%llx]: " fmt, \
(unsigned long long) (erom->offset), ##__VA_ARGS__);\
} else { \
printf("erom[0x%llx]: " fmt, \
(unsigned long long) (erom->offset), ##__VA_ARGS__);\
} \
} while(0)
/**
* Open an EROM table for reading.
@ -82,11 +90,37 @@ static int erom_seek_next(struct bcma_erom *erom, uint8_t etype);
* @retval non-zero if the erom table could not be opened.
*/
int
bcma_erom_open(struct bcma_erom *erom, struct resource *r, bus_size_t offset)
bcma_erom_open(struct bcma_erom *erom, struct resource *r,
bus_size_t offset)
{
return (bhnd_erom_bus_space_open(erom, rman_get_device(r),
rman_get_bustag(r), rman_get_bushandle(r), offset));
return (0);
}
/**
* Open an EROM table for reading using the provided bus space tag and
* handle.
*
* @param[out] erom On success, will be populated with a valid EROM
* read state.
* @param dev The owning device, or NULL if none.
* @param bst EROM table bus space tag.
* @param bsh EROM table bus space handle.
* @param offset Offset of the EROM core from @p resource.
*
* @retval 0 success
* @retval non-zero if the erom table could not be opened.
*/
int
bhnd_erom_bus_space_open(struct bcma_erom *erom, device_t dev,
bus_space_tag_t bst, bus_space_handle_t bsh, bus_size_t offset)
{
/* Initialize the EROM reader */
erom->dev = rman_get_device(r);
erom->r = r;
erom->dev = dev;
erom->bst = bst;
erom->bsh = bsh;
erom->start = offset + BCMA_EROM_TABLE_START;
erom->offset = 0;
@ -145,7 +179,8 @@ bcma_erom_peek32(struct bcma_erom *erom, uint32_t *entry)
return (EINVAL);
}
*entry = bus_read_4(erom->r, erom->start + erom->offset);
*entry = bus_space_read_4(erom->bst, erom->bsh,
erom->start + erom->offset);
return (0);
}
@ -299,6 +334,20 @@ bcma_erom_reset(struct bcma_erom *erom)
erom->offset = 0;
}
/**
* Seek to the next core entry.
*
* @param erom EROM read state.
* @retval 0 success
* @retval ENOENT The end of the EROM table was reached.
* @retval non-zero Reading or parsing failed.
*/
int
bcma_erom_seek_next_core(struct bcma_erom *erom)
{
return (erom_seek_next(erom, BCMA_EROM_ENTRY_TYPE_CORE));
}
/**
* Seek to the requested core entry.
*
@ -386,6 +435,153 @@ bcma_erom_parse_core(struct bcma_erom *erom, struct bcma_erom_core *core)
return (0);
}
/**
* Seek to a region record associated with @p core_index.
*
* @param erom EROM read state.
* @param core_index The index of the core record to be searched.
* @param port_type The port type to search for.
* @param port_num The port number to search for.
* @param region_num The region number to search for.
* @retval 0 success
* @retval ENOENT The requested region was not found.
* @retval non-zero Reading or parsing failed.
*/
int
bcma_erom_seek_core_sport_region(struct bcma_erom *erom, u_int core_index,
bhnd_port_type port_type, u_int port_num, u_int region_num)
{
struct bcma_erom_core core;
uint32_t entry;
uint8_t region_port, region_type;
bool found;
int error;
if ((error = bcma_erom_seek_core_index(erom, core_index)))
return (error);
if ((error = bcma_erom_parse_core(erom, &core)))
return (error);
/* Skip master ports */
for (u_long i = 0; i < core.num_mport; i++) {
if ((error = erom_skip_mport(erom)))
return (error);
}
/* Seek to the region block for the given port type */
found = false;
while (1) {
bhnd_port_type p_type;
uint8_t r_type;
if ((error = bcma_erom_peek32(erom, &entry)))
return (error);
if (!BCMA_EROM_ENTRY_IS(entry, REGION))
return (ENOENT);
/* Expected region type? */
r_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE);
if ((error = erom_region_to_port_type(erom, r_type, &p_type)))
return (error);
if (p_type == port_type) {
found = true;
break;
}
/* Skip to next entry */
if ((error = erom_skip_sport_region(erom)))
return (error);
}
if (!found)
return (ENOENT);
/* Found the appropriate port type block; now find the region records
* for the given port number */
found = false;
for (u_int i = 0; i <= port_num; i++) {
bhnd_port_type p_type;
if ((error = bcma_erom_peek32(erom, &entry)))
return (error);
if (!BCMA_EROM_ENTRY_IS(entry, REGION))
return (ENOENT);
/* Fetch the type/port of the first region entry */
region_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE);
region_port = BCMA_EROM_GET_ATTR(entry, REGION_PORT);
/* Have we found the region entries for the desired port? */
if (i == port_num) {
error = erom_region_to_port_type(erom, region_type,
&p_type);
if (error)
return (error);
if (p_type == port_type)
found = true;
break;
}
/* Otherwise, seek to next block of region records */
while (1) {
uint8_t next_type, next_port;
if ((error = erom_skip_sport_region(erom)))
return (error);
if ((error = bcma_erom_peek32(erom, &entry)))
return (error);
if (!BCMA_EROM_ENTRY_IS(entry, REGION))
return (ENOENT);
next_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE);
next_port = BCMA_EROM_GET_ATTR(entry, REGION_PORT);
if (next_type != region_type ||
next_port != region_port)
break;
}
}
if (!found)
return (ENOENT);
/* Finally, search for the requested region number */
for (u_int i = 0; i <= region_num; i++) {
uint8_t next_port, next_type;
if ((error = bcma_erom_peek32(erom, &entry)))
return (error);
if (!BCMA_EROM_ENTRY_IS(entry, REGION))
return (ENOENT);
/* Check for the end of the region block */
next_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE);
next_port = BCMA_EROM_GET_ATTR(entry, REGION_PORT);
if (next_type != region_type ||
next_port != region_port)
break;
if (i == region_num)
return (0);
if ((error = erom_skip_sport_region(erom)))
return (error);
}
/* Not found */
return (ENOENT);
}
/**
* Read the next master port descriptor from the EROM table.
*
@ -491,6 +687,25 @@ bcma_erom_parse_sport_region(struct bcma_erom *erom,
return (0);
}
/**
* Convert a bcma_erom_core record to its bhnd_core_info representation.
*
* @param core EROM core record to convert.
* @param core_idx The core index of @p core.
* @param core_unit The core unit of @p core.
* @param[out] info The populated bhnd_core_info representation.
*/
void
bcma_erom_to_core_info(const struct bcma_erom_core *core, u_int core_idx,
int core_unit, struct bhnd_core_info *info)
{
info->vendor = core->vendor;
info->device = core->device;
info->hwrev = core->rev;
info->core_idx = core_idx;
info->unit = core_unit;
}
/**
* Parse all cores descriptors from @p erom and return the array
* in @p cores and the count in @p num_cores. The current EROM read position
@ -545,7 +760,8 @@ bcma_erom_get_core_info(struct bcma_erom *erom,
/* Parse all core descriptors */
bcma_erom_reset(erom);
for (u_int i = 0; i < count; i++) {
struct bcma_erom_core core;
struct bcma_erom_core core;
int unit;
/* Parse the core */
error = erom_seek_next(erom, BCMA_EROM_ENTRY_TYPE_CORE);
@ -555,20 +771,17 @@ bcma_erom_get_core_info(struct bcma_erom *erom,
error = bcma_erom_parse_core(erom, &core);
if (error)
goto cleanup;
/* Convert to a bhnd info record */
buffer[i].vendor = core.vendor;
buffer[i].device = core.device;
buffer[i].hwrev = core.rev;
buffer[i].core_idx = i;
buffer[i].unit = 0;
/* Determine the unit number */
unit = 0;
for (u_int j = 0; j < i; j++) {
if (buffer[i].vendor == buffer[j].vendor &&
buffer[i].device == buffer[j].device)
buffer[i].unit++;
unit++;
}
/* Convert to a bhnd info record */
bcma_erom_to_core_info(&core, i, unit, &buffer[i]);
}
cleanup:
@ -585,6 +798,33 @@ bcma_erom_get_core_info(struct bcma_erom *erom,
return (error);
}
/**
* Map an EROM region type to its corresponding port type.
*
* @param region_type Region type value.
* @param[out] port_type On success, the corresponding port type.
*/
static int
erom_region_to_port_type(struct bcma_erom *erom, uint8_t region_type,
bhnd_port_type *port_type)
{
switch (region_type) {
case BCMA_EROM_REGION_TYPE_DEVICE:
*port_type = BHND_PORT_DEVICE;
return (0);
case BCMA_EROM_REGION_TYPE_BRIDGE:
*port_type = BHND_PORT_BRIDGE;
return (0);
case BCMA_EROM_REGION_TYPE_MWRAP:
case BCMA_EROM_REGION_TYPE_SWRAP:
*port_type = BHND_PORT_AGENT;
return (0);
default:
EROM_LOG(erom, "unsupported region type %hhx\n",
region_type);
return (EINVAL);
}
}
/**
* Register all MMIO region descriptors for the given slave port.
@ -608,24 +848,10 @@ erom_corecfg_fill_port_regions(struct bcma_erom *erom,
bhnd_port_type port_type;
error = 0;
/* Determine the port type for this region type. */
switch (region_type) {
case BCMA_EROM_REGION_TYPE_DEVICE:
port_type = BHND_PORT_DEVICE;
break;
case BCMA_EROM_REGION_TYPE_BRIDGE:
port_type = BHND_PORT_BRIDGE;
break;
case BCMA_EROM_REGION_TYPE_MWRAP:
case BCMA_EROM_REGION_TYPE_SWRAP:
port_type = BHND_PORT_AGENT;
break;
default:
EROM_LOG(erom, "unsupported region type %hhx\n",
region_type);
return (EINVAL);
}
if ((error = erom_region_to_port_type(erom, region_type, &port_type)))
return (error);
/* Fetch the list to be populated */
sports = bcma_corecfg_get_port_list(corecfg, port_type);

View File

@ -40,10 +40,11 @@
* EROM read context.
*/
struct bcma_erom {
device_t dev; /**< EROM parent device */
struct resource *r; /**< EROM table resource. */
bus_size_t start; /**< EROM table offset */
bus_size_t offset; /**< current read offset */
device_t dev; /**< EROM parent device */
bus_space_tag_t bst; /**< EROM table bus space */
bus_space_handle_t bsh; /**< EROM table bus handle */
bus_size_t start; /**< EROM table offset */
bus_size_t offset; /**< current read offset */
};
/** EROM core descriptor. */
@ -78,22 +79,34 @@ struct bcma_erom_sport_region {
int bcma_erom_open(struct bcma_erom *erom, struct resource *r,
bus_size_t offset);
int bhnd_erom_bus_space_open(struct bcma_erom *erom, device_t owner,
bus_space_tag_t bst, bus_space_handle_t bsh,
bus_size_t offset);
int bcma_erom_peek32(struct bcma_erom *erom, uint32_t *entry);
bus_size_t bcma_erom_tell(struct bcma_erom *erom);
void bcma_erom_seek(struct bcma_erom *erom, bus_size_t offset);
void bcma_erom_reset(struct bcma_erom *erom);
int bcma_erom_seek_next_core(struct bcma_erom *erom);
int bcma_erom_seek_core_index(struct bcma_erom *erom,
u_int core_index);
int bcma_erom_parse_core(struct bcma_erom *erom,
struct bcma_erom_core *core);
int bcma_erom_seek_core_sport_region(struct bcma_erom *erom,
u_int core_index, bhnd_port_type port_type, u_int port_num,
u_int region_num);
int bcma_erom_parse_mport(struct bcma_erom *erom,
struct bcma_erom_mport *mport);
int bcma_erom_parse_sport_region(struct bcma_erom *erom,
struct bcma_erom_sport_region *region);
void bcma_erom_to_core_info(const struct bcma_erom_core *core,
u_int core_idx, int core_unit, struct bhnd_core_info *info);
int bcma_erom_get_core_info(struct bcma_erom *erom,
struct bhnd_core_info **cores,
u_int *num_cores);

View File

@ -82,6 +82,9 @@ bcma_nexus_probe(device_t dev)
return (error);
}
/* Set device description */
bhnd_set_default_bus_desc(dev, &sc->bcma_cid);
return (0);
}

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -60,6 +60,9 @@ __FBSDID("$FreeBSD$");
#include <dev/bhnd/cores/chipc/chipcvar.h>
#include <dev/bhnd/cores/pmu/bhnd_pmu.h>
#include <dev/bhnd/cores/pmu/bhnd_pmureg.h>
#include "bhnd_chipc_if.h"
#include "bhnd_nvram_if.h"
@ -342,7 +345,7 @@ bhnd_finish_attach(struct bhnd_softc *sc)
{
struct chipc_caps *ccaps;
GIANT_REQUIRED; /* newbus */
GIANT_REQUIRED; /* for newbus */
KASSERT(bus_current_pass >= BHND_FINISH_ATTACH_PASS,
("bhnd_finish_attach() called in pass %d", bus_current_pass));
@ -367,10 +370,11 @@ bhnd_finish_attach(struct bhnd_softc *sc)
}
/* Look for a PMU */
if (ccaps->pmu) {
if (ccaps->pmu || ccaps->pwr_ctrl) {
if ((sc->pmu_dev = bhnd_find_pmu(sc)) == NULL) {
device_printf(sc->dev,
"warning: PMU device not found\n");
"attach failed: supported PMU not found\n");
return (ENXIO);
}
}
@ -478,8 +482,6 @@ bhnd_find_platform_dev(struct bhnd_softc *sc, const char *classname)
static device_t
bhnd_find_pmu(struct bhnd_softc *sc)
{
struct chipc_caps *ccaps;
/* Make sure we're holding Giant for newbus */
GIANT_REQUIRED;
@ -494,11 +496,6 @@ bhnd_find_pmu(struct bhnd_softc *sc)
return (sc->pmu_dev);
}
if ((ccaps = bhnd_find_chipc_caps(sc)) == NULL)
return (NULL);
if (!ccaps->pmu)
return (NULL);
return (bhnd_find_platform_dev(sc, "bhnd_pmu"));
}
@ -625,6 +622,244 @@ bhnd_generic_get_probe_order(device_t dev, device_t child)
}
}
/**
* Default bhnd(4) bus driver implementation of BHND_BUS_ALLOC_PMU().
*/
int
bhnd_generic_alloc_pmu(device_t dev, device_t child)
{
struct bhnd_softc *sc;
struct bhnd_resource *br;
struct chipc_caps *ccaps;
struct bhnd_devinfo *dinfo;
struct bhnd_core_pmu_info *pm;
struct resource_list *rl;
struct resource_list_entry *rle;
device_t pmu_dev;
bhnd_addr_t r_addr;
bhnd_size_t r_size;
bus_size_t pmu_regs;
int error;
GIANT_REQUIRED; /* for newbus */
sc = device_get_softc(dev);
dinfo = device_get_ivars(child);
pmu_regs = BHND_CLK_CTL_ST;
if ((ccaps = bhnd_find_chipc_caps(sc)) == NULL) {
device_printf(sc->dev, "alloc_pmu failed: chipc "
"capabilities unavailable\n");
return (ENXIO);
}
if ((pmu_dev = bhnd_find_pmu(sc)) == NULL) {
device_printf(sc->dev,
"pmu unavailable; cannot allocate request state\n");
return (ENXIO);
}
/* already allocated? */
if (dinfo->pmu_info != NULL) {
panic("duplicate PMU allocation for %s",
device_get_nameunit(child));
}
/* Determine address+size of the core's PMU register block */
error = bhnd_get_region_addr(child, BHND_PORT_DEVICE, 0, 0, &r_addr,
&r_size);
if (error) {
device_printf(sc->dev, "error fetching register block info for "
"%s: %d\n", device_get_nameunit(child), error);
return (error);
}
if (r_size < (pmu_regs + sizeof(uint32_t))) {
device_printf(sc->dev, "pmu offset %#jx would overrun %s "
"register block\n", (uintmax_t)pmu_regs,
device_get_nameunit(child));
return (ENODEV);
}
/* Locate actual resource containing the core's register block */
if ((rl = BUS_GET_RESOURCE_LIST(dev, child)) == NULL) {
device_printf(dev, "NULL resource list returned for %s\n",
device_get_nameunit(child));
return (ENXIO);
}
if ((rle = resource_list_find(rl, SYS_RES_MEMORY, 0)) == NULL) {
device_printf(dev, "cannot locate core register resource "
"for %s\n", device_get_nameunit(child));
return (ENXIO);
}
if (rle->res == NULL) {
device_printf(dev, "core register resource unallocated for "
"%s\n", device_get_nameunit(child));
return (ENXIO);
}
if (r_addr+pmu_regs < rman_get_start(rle->res) ||
r_addr+pmu_regs >= rman_get_end(rle->res))
{
device_printf(dev, "core register resource does not map PMU "
"registers at %#jx\n for %s\n", r_addr+pmu_regs,
device_get_nameunit(child));
return (ENXIO);
}
/* Adjust PMU register offset relative to the actual start address
* of the core's register block allocation.
*
* XXX: The saved offset will be invalid if bus_adjust_resource is
* used to modify the resource's start address.
*/
if (rman_get_start(rle->res) > r_addr)
pmu_regs -= rman_get_start(rle->res) - r_addr;
else
pmu_regs -= r_addr - rman_get_start(rle->res);
/* Allocate and initialize PMU info */
br = malloc(sizeof(struct bhnd_resource), M_BHND, M_NOWAIT);
if (br == NULL)
return (ENOMEM);
br->res = rle->res;
br->direct = ((rman_get_flags(rle->res) & RF_ACTIVE) != 0);
pm = malloc(sizeof(*dinfo->pmu_info), M_BHND, M_NOWAIT);
if (pm == NULL) {
free(br, M_BHND);
return (ENOMEM);
}
pm->pm_dev = child;
pm->pm_pmu = pmu_dev;
pm->pm_res = br;
pm->pm_regs = pmu_regs;
dinfo->pmu_info = pm;
return (0);
}
/**
* Default bhnd(4) bus driver implementation of BHND_BUS_RELEASE_PMU().
*/
int
bhnd_generic_release_pmu(device_t dev, device_t child)
{
struct bhnd_softc *sc;
struct bhnd_devinfo *dinfo;
device_t pmu;
int error;
GIANT_REQUIRED; /* for newbus */
sc = device_get_softc(dev);
dinfo = device_get_ivars(child);
if ((pmu = bhnd_find_pmu(sc)) == NULL) {
device_printf(sc->dev,
"pmu unavailable; cannot release request state\n");
return (ENXIO);
}
/* dispatch release request */
if (dinfo->pmu_info == NULL)
panic("pmu over-release for %s", device_get_nameunit(child));
if ((error = BHND_PMU_CORE_RELEASE(pmu, dinfo->pmu_info)))
return (error);
/* free PMU info */
free(dinfo->pmu_info->pm_res, M_BHND);
free(dinfo->pmu_info, M_BHND);
dinfo->pmu_info = NULL;
return (0);
}
/**
* Default bhnd(4) bus driver implementation of BHND_BUS_REQUEST_CLOCK().
*/
int
bhnd_generic_request_clock(device_t dev, device_t child, bhnd_clock clock)
{
struct bhnd_softc *sc;
struct bhnd_devinfo *dinfo;
struct bhnd_core_pmu_info *pm;
sc = device_get_softc(dev);
dinfo = device_get_ivars(child);
if ((pm = dinfo->pmu_info) == NULL)
panic("no active PMU request state");
/* dispatch request to PMU */
return (BHND_PMU_CORE_REQ_CLOCK(pm->pm_pmu, pm, clock));
}
/**
* Default bhnd(4) bus driver implementation of BHND_BUS_ENABLE_CLOCKS().
*/
int
bhnd_generic_enable_clocks(device_t dev, device_t child, uint32_t clocks)
{
struct bhnd_softc *sc;
struct bhnd_devinfo *dinfo;
struct bhnd_core_pmu_info *pm;
sc = device_get_softc(dev);
dinfo = device_get_ivars(child);
if ((pm = dinfo->pmu_info) == NULL)
panic("no active PMU request state");
/* dispatch request to PMU */
return (BHND_PMU_CORE_EN_CLOCKS(pm->pm_pmu, pm, clocks));
}
/**
* Default bhnd(4) bus driver implementation of BHND_BUS_REQUEST_EXT_RSRC().
*/
int
bhnd_generic_request_ext_rsrc(device_t dev, device_t child, u_int rsrc)
{
struct bhnd_softc *sc;
struct bhnd_devinfo *dinfo;
struct bhnd_core_pmu_info *pm;
sc = device_get_softc(dev);
dinfo = device_get_ivars(child);
if ((pm = dinfo->pmu_info) == NULL)
panic("no active PMU request state");
/* dispatch request to PMU */
return (BHND_PMU_CORE_REQ_EXT_RSRC(pm->pm_pmu, pm, rsrc));
}
/**
* Default bhnd(4) bus driver implementation of BHND_BUS_RELEASE_EXT_RSRC().
*/
int
bhnd_generic_release_ext_rsrc(device_t dev, device_t child, u_int rsrc)
{
struct bhnd_softc *sc;
struct bhnd_devinfo *dinfo;
struct bhnd_core_pmu_info *pm;
sc = device_get_softc(dev);
dinfo = device_get_ivars(child);
if ((pm = dinfo->pmu_info) == NULL)
panic("no active PMU request state");
/* dispatch request to PMU */
return (BHND_PMU_CORE_RELEASE_EXT_RSRC(pm->pm_pmu, pm, rsrc));
}
/**
* Default bhnd(4) bus driver implementation of BHND_BUS_IS_REGION_VALID().
*
@ -815,12 +1050,20 @@ bhnd_generic_add_child(device_t dev, u_int order, const char *name, int unit)
device_set_ivars(child, dinfo);
/* Inform concrete bus driver. */
BHND_BUS_CHILD_ADDED(dev, child);
return (child);
}
/**
* Default bhnd(4) bus driver implementation of BHND_BUS_CHILD_ADDED().
*
* This implementation manages internal bhnd(4) state, and must be called
* by subclassing drivers.
*/
void
bhnd_generic_child_added(device_t dev, device_t child)
{
}
/**
* Default bhnd(4) bus driver implementation of BUS_CHILD_DELETED().
*
@ -836,8 +1079,17 @@ bhnd_generic_child_deleted(device_t dev, device_t child)
sc = device_get_softc(dev);
/* Free device info */
if ((dinfo = device_get_ivars(child)) != NULL)
if ((dinfo = device_get_ivars(child)) != NULL) {
if (dinfo->pmu_info != NULL) {
/* Releasing PMU requests automatically would be nice,
* but we can't reference per-core PMU register
* resource after driver detach */
panic("%s leaked device pmu state\n",
device_get_nameunit(child));
}
BHND_BUS_FREE_DEVINFO(dev, dinfo);
}
/* Clean up platform device references */
if (sc->chipc_dev == child) {
@ -998,9 +1250,20 @@ static device_method_t bhnd_methods[] = {
/* BHND interface */
DEVMETHOD(bhnd_bus_get_chipid, bhnd_bus_generic_get_chipid),
DEVMETHOD(bhnd_bus_get_probe_order, bhnd_generic_get_probe_order),
DEVMETHOD(bhnd_bus_is_region_valid, bhnd_generic_is_region_valid),
DEVMETHOD(bhnd_bus_is_hw_disabled, bhnd_bus_generic_is_hw_disabled),
DEVMETHOD(bhnd_bus_read_board_info, bhnd_bus_generic_read_board_info),
DEVMETHOD(bhnd_bus_get_probe_order, bhnd_generic_get_probe_order),
DEVMETHOD(bhnd_bus_alloc_pmu, bhnd_generic_alloc_pmu),
DEVMETHOD(bhnd_bus_release_pmu, bhnd_generic_release_pmu),
DEVMETHOD(bhnd_bus_request_clock, bhnd_generic_request_clock),
DEVMETHOD(bhnd_bus_enable_clocks, bhnd_generic_enable_clocks),
DEVMETHOD(bhnd_bus_request_ext_rsrc, bhnd_generic_request_ext_rsrc),
DEVMETHOD(bhnd_bus_release_ext_rsrc, bhnd_generic_release_ext_rsrc),
DEVMETHOD(bhnd_bus_child_added, bhnd_generic_child_added),
DEVMETHOD(bhnd_bus_is_region_valid, bhnd_generic_is_region_valid),
DEVMETHOD(bhnd_bus_get_nvram_var, bhnd_generic_get_nvram_var),
/* BHND interface (bus I/O) */

View File

@ -49,6 +49,9 @@ extern devclass_t bhnd_devclass;
extern devclass_t bhnd_hostb_devclass;
extern devclass_t bhnd_nvram_devclass;
#define BHND_CHIPID_MAX_NAMELEN 32 /**< maximum buffer required for a
bhnd_format_chip_id() */
/**
* bhnd child instance variables
*/
@ -254,6 +257,8 @@ bhnd_devclass_t bhnd_find_core_class(uint16_t vendor,
const char *bhnd_core_name(const struct bhnd_core_info *ci);
bhnd_devclass_t bhnd_core_class(const struct bhnd_core_info *ci);
int bhnd_format_chip_id(char *buffer, size_t size,
uint16_t chip_id);
device_t bhnd_match_child(device_t dev,
const struct bhnd_core_match *desc);
@ -312,6 +317,10 @@ void bhnd_release_resources(device_t dev,
struct bhnd_chipid bhnd_parse_chipid(uint32_t idreg,
bhnd_addr_t enum_addr);
int bhnd_chipid_fixed_ncores(
const struct bhnd_chipid *cid,
uint16_t chipc_hwrev, uint8_t *ncores);
int bhnd_read_chipid(device_t dev,
struct resource_spec *rs,
bus_size_t chipc_offset,
@ -321,6 +330,9 @@ void bhnd_set_custom_core_desc(device_t dev,
const char *name);
void bhnd_set_default_core_desc(device_t dev);
void bhnd_set_default_bus_desc(device_t dev,
const struct bhnd_chipid *chip_id);
int bhnd_nvram_getvar_str(device_t dev,
const char *name, char *buf, size_t len,
size_t *rlen);
@ -416,6 +428,93 @@ bhnd_get_chipid(device_t dev) {
return (BHND_BUS_GET_CHIPID(device_get_parent(dev), dev));
};
/**
* Get a list of all cores discoverable on the bhnd bus.
*
* Enumerates all cores discoverable on @p dev, returning the list in
* @p cores and the count in @p num_cores.
*
* The memory allocated for the list should be freed using
* `free(*cores, M_BHND)`. @p cores and @p num_cores are not changed
* when an error is returned.
*
* @param dev A bhnd bus child device.
* @param[out] cores The table of core descriptors.
* @param[out] num_cores The number of core descriptors in @p cores.
*
* @retval 0 success
* @retval non-zero if an error occurs enumerating @p dev, a regular UNIX
* error code should be returned.
*/
static inline int
bhnd_get_core_table(device_t dev, struct bhnd_core_info **cores,
u_int *num_cores)
{
return (BHND_BUS_GET_CORE_TABLE(device_get_parent(dev), dev, cores,
num_cores));
}
/**
* If supported by the chipset, return the clock source for the given clock.
*
* This function is only supported on early PWRCTL-equipped chipsets
* that expose clock management via their host bridge interface. Currently,
* this includes PCI (not PCIe) devices, with ChipCommon core revisions 0-9.
*
* @param dev A bhnd bus child device.
* @param clock The clock for which a clock source will be returned.
*
* @retval bhnd_clksrc The clock source for @p clock.
* @retval BHND_CLKSRC_UNKNOWN If @p clock is unsupported, or its
* clock source is not known to the bus.
*/
static inline bhnd_clksrc
bhnd_pwrctl_get_clksrc(device_t dev, bhnd_clock clock)
{
return (BHND_BUS_PWRCTL_GET_CLKSRC(device_get_parent(dev), dev, clock));
}
/**
* If supported by the chipset, gate @p clock
*
* This function is only supported on early PWRCTL-equipped chipsets
* that expose clock management via their host bridge interface. Currently,
* this includes PCI (not PCIe) devices, with ChipCommon core revisions 0-9.
*
* @param dev A bhnd bus child device.
* @param clock The clock to be disabled.
*
* @retval 0 success
* @retval ENODEV If bus-level clock source management is not supported.
* @retval ENXIO If bus-level management of @p clock is not supported.
*/
static inline int
bhnd_pwrctl_gate_clock(device_t dev, bhnd_clock clock)
{
return (BHND_BUS_PWRCTL_GATE_CLOCK(device_get_parent(dev), dev, clock));
}
/**
* If supported by the chipset, ungate @p clock
*
* This function is only supported on early PWRCTL-equipped chipsets
* that expose clock management via their host bridge interface. Currently,
* this includes PCI (not PCIe) devices, with ChipCommon core revisions 0-9.
*
* @param dev A bhnd bus child device.
* @param clock The clock to be enabled.
*
* @retval 0 success
* @retval ENODEV If bus-level clock source management is not supported.
* @retval ENXIO If bus-level management of @p clock is not supported.
*/
static inline int
bhnd_pwrctl_ungate_clock(device_t dev, bhnd_clock clock)
{
return (BHND_BUS_PWRCTL_UNGATE_CLOCK(device_get_parent(dev), dev,
clock));
}
/**
* Return the BHND attachment type of the parent bhnd bus.
*
@ -453,6 +552,171 @@ bhnd_read_board_info(device_t dev, struct bhnd_board_info *info)
return (BHND_BUS_READ_BOARD_INFO(device_get_parent(dev), dev, info));
}
/**
* Allocate and enable per-core PMU request handling for @p child.
*
* The region containing the core's PMU register block (if any) must be
* allocated via bus_alloc_resource(9) (or bhnd_alloc_resource) before
* calling bhnd_alloc_pmu(), and must not be released until after
* calling bhnd_release_pmu().
*
* @param dev The parent of @p child.
* @param child The requesting bhnd device.
*
* @retval 0 success
* @retval non-zero If allocating PMU request state otherwise fails, a
* regular unix error code will be returned.
*/
static inline int
bhnd_alloc_pmu(device_t dev)
{
return (BHND_BUS_ALLOC_PMU(device_get_parent(dev), dev));
}
/**
* Release any per-core PMU resources allocated for @p child. Any outstanding
* PMU requests are are discarded.
*
* @param dev The parent of @p child.
* @param child The requesting bhnd device.
*
* @retval 0 success
* @retval non-zero If releasing PMU request state otherwise fails, a
* regular unix error code will be returned, and
* the core state will be left unmodified.
*/
static inline int
bhnd_release_pmu(device_t dev)
{
return (BHND_BUS_RELEASE_PMU(device_get_parent(dev), dev));
}
/**
* Request that @p clock (or faster) be routed to @p dev.
*
* A driver must ask the bhnd bus to allocate clock request state
* via bhnd_alloc_pmu() before it can request clock resources.
*
* Request multiplexing is managed by the bus.
*
* @param dev The bhnd(4) device to which @p clock should be routed.
* @param clock The requested clock source.
*
* @retval 0 success
* @retval ENODEV If an unsupported clock was requested.
* @retval ENXIO If the PMU has not been initialized or is otherwise unvailable.
*/
static inline int
bhnd_request_clock(device_t dev, bhnd_clock clock)
{
return (BHND_BUS_REQUEST_CLOCK(device_get_parent(dev), dev, clock));
}
/**
* Request that @p clocks be powered on behalf of @p dev.
*
* This will power any clock sources (e.g. XTAL, PLL, etc) required for
* @p clocks and wait until they are ready, discarding any previous
* requests by @p dev.
*
* Request multiplexing is managed by the bus.
*
* A driver must ask the bhnd bus to allocate clock request state
* via bhnd_alloc_pmu() before it can request clock resources.
*
* @param dev The requesting bhnd(4) device.
* @param clocks The clock(s) to be enabled.
*
* @retval 0 success
* @retval ENODEV If an unsupported clock was requested.
* @retval ENXIO If the PMU has not been initialized or is otherwise unvailable.
*/
static inline int
bhnd_enable_clocks(device_t dev, uint32_t clocks)
{
return (BHND_BUS_ENABLE_CLOCKS(device_get_parent(dev), dev, clocks));
}
/**
* Power up an external PMU-managed resource assigned to @p dev.
*
* A driver must ask the bhnd bus to allocate PMU request state
* via bhnd_alloc_pmu() before it can request PMU resources.
*
* @param dev The requesting bhnd(4) device.
* @param rsrc The core-specific external resource identifier.
*
* @retval 0 success
* @retval ENODEV If the PMU does not support @p rsrc.
* @retval ENXIO If the PMU has not been initialized or is otherwise unvailable.
*/
static inline int
bhnd_request_ext_rsrc(device_t dev, u_int rsrc)
{
return (BHND_BUS_REQUEST_EXT_RSRC(device_get_parent(dev), dev, rsrc));
}
/**
* Power down an external PMU-managed resource assigned to @p dev.
*
* A driver must ask the bhnd bus to allocate PMU request state
* via bhnd_alloc_pmu() before it can request PMU resources.
*
* @param dev The requesting bhnd(4) device.
* @param rsrc The core-specific external resource identifier.
*
* @retval 0 success
* @retval ENODEV If the PMU does not support @p rsrc.
* @retval ENXIO If the PMU has not been initialized or is otherwise unvailable.
*/
static inline int
bhnd_release_ext_rsrc(device_t dev, u_int rsrc)
{
return (BHND_BUS_RELEASE_EXT_RSRC(device_get_parent(dev), dev, rsrc));
}
/**
* Read @p width bytes at @p offset from the bus-specific agent/config
* space of @p dev.
*
* @param dev The bhnd device for which @p offset should be read.
* @param offset The offset to be read.
* @param width The size of the access. Must be 1, 2 or 4 bytes.
*
* The exact behavior of this method is bus-specific. In the case of
* bcma(4), this method provides access to the first agent port of @p child.
*
* @note Device drivers should only use this API for functionality
* that is not available via another bhnd(4) function.
*/
static inline uint32_t
bhnd_read_config(device_t dev, bus_size_t offset, u_int width)
{
return (BHND_BUS_READ_CONFIG(device_get_parent(dev), dev, offset,
width));
}
/**
* Read @p width bytes at @p offset from the bus-specific agent/config
* space of @p dev.
*
* @param dev The bhnd device for which @p offset should be read.
* @param offset The offset to be written.
* @param width The size of the access. Must be 1, 2 or 4 bytes.
*
* The exact behavior of this method is bus-specific. In the case of
* bcma(4), this method provides access to the first agent port of @p child.
*
* @note Device drivers should only use this API for functionality
* that is not available via another bhnd(4) function.
*/
static inline void
bhnd_write_config(device_t dev, bus_size_t offset, uint32_t val, u_int width)
{
BHND_BUS_WRITE_CONFIG(device_get_parent(dev), dev, offset, val, width);
}
/**
* Read an NVRAM variable, coerced to the requested @p type.
*

View File

@ -56,11 +56,39 @@ CODE {
panic("bhnd_bus_get_chipid unimplemented");
}
static int
bhnd_bus_null_get_core_table(device_t dev, device_t child,
struct bhnd_core_info **cores, u_int *num_cores)
{
panic("bhnd_bus_get_core_table unimplemented");
}
static bhnd_attach_type
bhnd_bus_null_get_attach_type(device_t dev, device_t child)
{
panic("bhnd_bus_get_attach_type unimplemented");
}
static bhnd_clksrc
bhnd_bus_null_pwrctl_get_clksrc(device_t dev, device_t child,
bhnd_clock clock)
{
return (BHND_CLKSRC_UNKNOWN);
}
static int
bhnd_bus_null_pwrctl_gate_clock(device_t dev, device_t child,
bhnd_clock clock)
{
return (ENODEV);
}
static int
bhnd_bus_null_pwrctl_ungate_clock(device_t dev, device_t child,
bhnd_clock clock)
{
return (ENODEV);
}
static int
bhnd_bus_null_read_board_info(device_t dev, device_t child,
@ -74,6 +102,60 @@ CODE {
{
}
static int
bhnd_bus_null_alloc_pmu(device_t dev, device_t child)
{
panic("bhnd_bus_alloc_pmu unimplemented");
}
static int
bhnd_bus_null_release_pmu(device_t dev, device_t child)
{
panic("bhnd_bus_release_pmu unimplemented");
}
static int
bhnd_bus_null_request_clock(device_t dev, device_t child,
bhnd_clock clock)
{
panic("bhnd_bus_request_clock unimplemented");
}
static int
bhnd_bus_null_enable_clocks(device_t dev, device_t child,
uint32_t clocks)
{
panic("bhnd_bus_enable_clocks unimplemented");
}
static int
bhnd_bus_null_request_ext_rsrc(device_t dev, device_t child,
u_int rsrc)
{
panic("bhnd_bus_request_ext_rsrc unimplemented");
}
static int
bhnd_bus_null_release_ext_rsrc(device_t dev, device_t child,
u_int rsrc)
{
panic("bhnd_bus_release_ext_rsrc unimplemented");
}
static uint32_t
bhnd_bus_null_read_config(device_t dev, device_t child,
bus_size_t offset, u_int width)
{
panic("bhnd_bus_null_read_config unimplemented");
}
static void
bhnd_bus_null_write_config(device_t dev, device_t child,
bus_size_t offset, uint32_t val, u_int width)
{
panic("bhnd_bus_null_write_config unimplemented");
}
static device_t
bhnd_bus_null_find_hostb_device(device_t dev)
{
@ -195,6 +277,32 @@ METHOD const struct bhnd_chipid * get_chipid {
device_t child;
} DEFAULT bhnd_bus_null_get_chipid;
/**
* Get a list of all cores discoverable on @p dev.
*
* Enumerates all cores discoverable on @p dev, returning the list in
* @p cores and the count in @p num_cores.
*
* The memory allocated for the list should be freed using
* `free(*cores, M_BHND)`. @p cores and @p num_cores are not changed
* when an error is returned.
*
* @param dev The bhnd bus device.
* @param child The requesting bhnd bus child.
* @param[out] cores The table of core descriptors.
* @param[out] num_cores The number of core descriptors in @p cores.
*
* @retval 0 success
* @retval non-zero if an error occurs enumerating @p dev, a regular UNIX
* error code should be returned.
*/
METHOD int get_core_table {
device_t dev;
device_t child;
struct bhnd_core_info **cores;
u_int *num_cores;
} DEFAULT bhnd_bus_null_get_core_table;
/**
* Return the BHND attachment type of the parent bus.
*
@ -261,9 +369,8 @@ METHOD void free_devinfo {
/**
* Notify a bhnd bus that a child was added.
*
* Called at the end of BUS_ADD_CHILD() to allow the concrete bhnd(4)
* driver instance to initialize any additional driver-specific state for the
* child.
* This method must be called by concrete bhnd(4) driver impementations
* after @p child's bus state is fully initialized.
*
* @param dev The bhnd bus whose child is being added.
* @param child The child added to @p dev.
@ -303,6 +410,231 @@ METHOD int suspend_core {
device_t child;
}
/**
* If supported by the chipset, return the clock source for the given clock.
*
* This function is only supported on early PWRCTL-equipped chipsets
* that expose clock management via their host bridge interface. Currently,
* this includes PCI (not PCIe) devices, with ChipCommon core revisions 0-9.
*
* @param dev The parent of @p child.
* @param child The bhnd device requesting a clock source.
* @param clock The clock for which a clock source will be returned.
*
* @retval bhnd_clksrc The clock source for @p clock.
* @retval BHND_CLKSRC_UNKNOWN If @p clock is unsupported, or its
* clock source is not known to the bus.
*/
METHOD bhnd_clksrc pwrctl_get_clksrc {
device_t dev;
device_t child;
bhnd_clock clock;
} DEFAULT bhnd_bus_null_pwrctl_get_clksrc;
/**
* If supported by the chipset, gate the clock source for @p clock
*
* This function is only supported on early PWRCTL-equipped chipsets
* that expose clock management via their host bridge interface. Currently,
* this includes PCI (not PCIe) devices, with ChipCommon core revisions 0-9.
*
* @param dev The parent of @p child.
* @param child The bhnd device requesting clock gating.
* @param clock The clock to be disabled.
*
* @retval 0 success
* @retval ENODEV If bus-level clock source management is not supported.
* @retval ENXIO If bus-level management of @p clock is not supported.
*/
METHOD int pwrctl_gate_clock {
device_t dev;
device_t child;
bhnd_clock clock;
} DEFAULT bhnd_bus_null_pwrctl_gate_clock;
/**
* If supported by the chipset, ungate the clock source for @p clock
*
* This function is only supported on early PWRCTL-equipped chipsets
* that expose clock management via their host bridge interface. Currently,
* this includes PCI (not PCIe) devices, with ChipCommon core revisions 0-9.
*
* @param dev The parent of @p child.
* @param child The bhnd device requesting clock gating.
* @param clock The clock to be enabled.
*
* @retval 0 success
* @retval ENODEV If bus-level clock source management is not supported.
* @retval ENXIO If bus-level management of @p clock is not supported.
*/
METHOD int pwrctl_ungate_clock {
device_t dev;
device_t child;
bhnd_clock clock;
} DEFAULT bhnd_bus_null_pwrctl_ungate_clock;
/**
* Allocate and enable per-core PMU request handling for @p child.
*
* The region containing the core's PMU register block (if any) must be
* allocated via bus_alloc_resource(9) (or bhnd_alloc_resource) before
* calling BHND_BUS_ALLOC_PMU(), and must not be released until after
* calling BHND_BUS_RELEASE_PMU().
*
* @param dev The parent of @p child.
* @param child The requesting bhnd device.
*/
METHOD int alloc_pmu {
device_t dev;
device_t child;
} DEFAULT bhnd_bus_null_alloc_pmu;
/**
* Release per-core PMU resources allocated for @p child. Any
* outstanding PMU requests are discarded.
*
* @param dev The parent of @p child.
* @param child The requesting bhnd device.
*/
METHOD int release_pmu {
device_t dev;
device_t child;
} DEFAULT bhnd_bus_null_release_pmu;
/**
* Request that @p clock (or faster) be routed to @p child.
*
* A driver must ask the bhnd bus to allocate PMU request state
* via BHND_BUS_ALLOC_PMU() before it can request clock resources.
*
* Request multiplexing is managed by the bus.
*
* @param dev The parent of @p child.
* @param child The bhnd device requesting @p clock.
* @param clock The requested clock source.
*
* @retval 0 success
* @retval ENODEV If an unsupported clock was requested.
* @retval ENXIO If the PMU has not been initialized or is otherwise unvailable.
*/
METHOD int request_clock {
device_t dev;
device_t child;
bhnd_clock clock;
} DEFAULT bhnd_bus_null_request_clock;
/**
* Request that @p clocks be powered on behalf of @p child.
*
* This will power on clock sources (e.g. XTAL, PLL, etc) required for
* @p clocks and wait until they are ready, discarding any previous
* requests by @p child.
*
* Request multiplexing is managed by the bus.
*
* A driver must ask the bhnd bus to allocate PMU request state
* via BHND_BUS_ALLOC_PMU() before it can request clock resources.
*
* @param dev The parent of @p child.
* @param child The bhnd device requesting @p clock.
* @param clock The requested clock source.
*
* @retval 0 success
* @retval ENODEV If an unsupported clock was requested.
* @retval ENXIO If the PMU has not been initialized or is otherwise unvailable.
*/
METHOD int enable_clocks {
device_t dev;
device_t child;
uint32_t clocks;
} DEFAULT bhnd_bus_null_enable_clocks;
/**
* Power up an external PMU-managed resource assigned to @p child.
*
* A driver must ask the bhnd bus to allocate PMU request state
* via BHND_BUS_ALLOC_PMU() before it can request PMU resources.
*
* @param dev The parent of @p child.
* @param child The bhnd device requesting @p rsrc.
* @param rsrc The core-specific external resource identifier.
*
* @retval 0 success
* @retval ENODEV If the PMU does not support @p rsrc.
* @retval ENXIO If the PMU has not been initialized or is otherwise unvailable.
*/
METHOD int request_ext_rsrc {
device_t dev;
device_t child;
u_int rsrc;
} DEFAULT bhnd_bus_null_request_ext_rsrc;
/**
* Power down an external PMU-managed resource assigned to @p child.
*
* A driver must ask the bhnd bus to allocate PMU request state
* via BHND_BUS_ALLOC_PMU() before it can request PMU resources.
*
* @param dev The parent of @p child.
* @param child The bhnd device requesting @p rsrc.
* @param rsrc The core-specific external resource number.
*
* @retval 0 success
* @retval ENODEV If the PMU does not support @p rsrc.
* @retval ENXIO If the PMU has not been initialized or is otherwise unvailable.
*/
METHOD int release_ext_rsrc {
device_t dev;
device_t child;
u_int rsrc;
} DEFAULT bhnd_bus_null_release_ext_rsrc;
/**
* Read @p width bytes at @p offset from the bus-specific agent/config
* space of @p child.
*
* @param dev The parent of @p child.
* @param child The bhnd device for which @p offset should be read.
* @param offset The offset to be read.
* @param width The size of the access. Must be 1, 2 or 4 bytes.
*
* The exact behavior of this method is bus-specific. On a bcma(4) bus, this
* method provides access to the first agent port of @p child; on a siba(4) bus,
* this method provides access to the core's CFG0 register block.
*
* @note Device drivers should only use this API for functionality
* that is not available via another bhnd(4) function.
*/
METHOD uint32_t read_config {
device_t dev;
device_t child;
bus_size_t offset;
u_int width;
} DEFAULT bhnd_bus_null_read_config;
/**
* Read @p width bytes at @p offset from the bus-specific agent/config
* space of @p child.
*
* @param dev The parent of @p child.
* @param child The bhnd device for which @p offset should be read.
* @param offset The offset to be written.
* @param width The size of the access. Must be 1, 2 or 4 bytes.
*
* The exact behavior of this method is bus-specific. In the case of
* bcma(4), this method provides access to the first agent port of @p child.
*
* @note Device drivers should only use this API for functionality
* that is not available via another bhnd(4) function.
*/
METHOD void write_config {
device_t dev;
device_t child;
bus_size_t offset;
uint32_t val;
u_int width;
} DEFAULT bhnd_bus_null_write_config;
/**
* Allocate a bhnd resource.
*

View File

@ -46,40 +46,4 @@
#define BHND_RESET_SF 0x0804
/*
* A register that is common to all cores to
* communicate w/PMU regarding clock control.
*
* TODO: Determine when this register first appeared.
*/
#define BHND_CLK_CTL_ST 0x1e0 /**< clock control and status */
/*
* BHND_CLK_CTL_ST register
*
* Clock Mode Name Description
* High Throughput (HT) Full bandwidth, low latency. Generally supplied
* from PLL.
* Active Low Power (ALP) Register access, low speed DMA.
* Idle Low Power (ILP) No interconnect activity, or if long latency
* is permitted.
*/
#define BHND_CCS_FORCEALP 0x00000001 /**< force ALP request */
#define BHND_CCS_FORCEHT 0x00000002 /**< force HT request */
#define BHND_CCS_FORCEILP 0x00000004 /**< force ILP request */
#define BHND_CCS_ALPAREQ 0x00000008 /**< ALP Avail Request */
#define BHND_CCS_HTAREQ 0x00000010 /**< HT Avail Request */
#define BHND_CCS_FORCEHWREQOFF 0x00000020 /**< Force HW Clock Request Off */
#define BHND_CCS_ERSRC_REQ_MASK 0x00000700 /**< external resource requests */
#define BHND_CCS_ERSRC_REQ_SHIFT 8
#define BHND_CCS_ALPAVAIL 0x00010000 /**< ALP is available */
#define BHND_CCS_HTAVAIL 0x00020000 /**< HT is available */
#define BHND_CCS_BP_ON_APL 0x00040000 /**< RO: Backplane is running on ALP clock */
#define BHND_CCS_BP_ON_HT 0x00080000 /**< RO: Backplane is running on HT clock */
#define BHND_CCS_ERSRC_STS_MASK 0x07000000 /**< external resource status */
#define BHND_CCS_ERSRC_STS_SHIFT 24
#define BHND_CCS0_HTAVAIL 0x00010000 /**< HT avail in chipc and pcmcia on 4328a0 */
#define BHND_CCS0_ALPAVAIL 0x00020000 /**< ALP avail in chipc and pcmcia on 4328a0 */
#endif /* _BHND_BHND_CORE_H_ */

View File

@ -535,6 +535,12 @@
#define BHND_CHIPTYPE_UBUS 2 /**< ubus interconnect found in bcm63xx devices */
#define BHND_CHIPTYPE_BCMA_ALT 3 /**< bcma(4) interconnect */
/** Evaluates to true if @p _type uses a BCMA EROM table */
#define BHND_CHIPTYPE_HAS_EROM(_type) \
((_type) == BHND_CHIPTYPE_BCMA || \
(_type) == BHND_CHIPTYPE_BCMA_ALT || \
(_type) == BHND_CHIPTYPE_UBUS)
/* Boardflags */
#define BHND_BFL_BTC2WIRE 0x00000001 /* old 2wire Bluetooth coexistence, OBSOLETE */
#define BHND_BFL_BTCOEX 0x00000001 /* Board supports BTCOEX */
@ -692,12 +698,6 @@
#define BHND_GPIO_BTC4W_OUT_4313 0x060 /* bit 5 SW_BT, bit 6 SW_WL */
#define BHND_GPIO_BTC4W_OUT_4331_SHARED 0x010 /* GPIO 4 */
/* Power Control Defines */
#define BHND_CHIPC_PLL_DELAY 150 /* us pll on delay */
#define BHND_CHIPC_FREF_DELAY 200 /* us fref change delay */
#define BHND_CHIPC_MIN_SLOW_CLK 32 /* us Slow clock period */
#define BHND_CHIPC_XTAL_ON_DELAY 1000 /* us crystal power-on delay */
/* Board Types */
#define BHND_BOARD_BU4710 0x0400
#define BHND_BOARD_VSIM4710 0x0401

View File

@ -38,6 +38,8 @@ __FBSDID("$FreeBSD$");
#include <sys/rman.h>
#include <machine/resource.h>
#include <dev/bhnd/siba/sibareg.h>
#include <dev/bhnd/cores/chipc/chipcreg.h>
#include "nvram/bhnd_nvram.h"
@ -287,6 +289,30 @@ bhnd_core_class(const struct bhnd_core_info *ci)
return bhnd_find_core_class(ci->vendor, ci->device);
}
/**
* Write a human readable name representation of the given
* BHND_CHIPID_* constant to @p buffer.
*
* @param buffer Output buffer, or NULL to compute the required size.
* @param size Capacity of @p buffer, in bytes.
* @param chip_id Chip ID to be formatted.
*
* @return Returns the required number of bytes on success, or a negative
* integer on failure. No more than @p size-1 characters be written, with
* the @p size'th set to '\0'.
*
* @sa BHND_CHIPID_MAX_NAMELEN
*/
int
bhnd_format_chip_id(char *buffer, size_t size, uint16_t chip_id)
{
/* All hex formatted IDs are within the range of 0x4000-0x9C3F (40000-1) */
if (chip_id >= 0x4000 && chip_id <= 0x9C3F)
return (snprintf(buffer, size, "BCM%hX", chip_id));
else
return (snprintf(buffer, size, "BCM%hu", chip_id));
}
/**
* Initialize a core info record with data from from a bhnd-attached @p dev.
*
@ -816,6 +842,63 @@ bhnd_parse_chipid(uint32_t idreg, bhnd_addr_t enum_addr)
return (result);
}
/**
* Determine the correct core count for a chip identification value that
* may contain an invalid core count.
*
* On some early siba(4) devices (see CHIPC_NCORES_MIN_HWREV()), the ChipCommon
* core does not provide a valid CHIPC_ID_NUMCORE field.
*
* @param cid The chip identification to be queried.
* @param chipc_hwrev The hardware revision of the ChipCommon core from which
* @p cid was parsed.
* @param[out] ncores On success, will be set to the correct core count.
*
* @retval 0 If the core count is already correct, or was mapped to a
* a correct value.
* @retval EINVAL If the core count is incorrect, but the chip was not
* recognized.
*/
int
bhnd_chipid_fixed_ncores(const struct bhnd_chipid *cid, uint16_t chipc_hwrev,
uint8_t *ncores)
{
/* bcma(4), and most siba(4) devices */
if (CHIPC_NCORES_MIN_HWREV(chipc_hwrev)) {
*ncores = cid->ncores;
return (0);
}
/* broken siba(4) chipsets */
switch (cid->chip_id) {
case BHND_CHIPID_BCM4306:
*ncores = 6;
break;
case BHND_CHIPID_BCM4704:
*ncores = 9;
break;
case BHND_CHIPID_BCM5365:
/*
* BCM5365 does support ID_NUMCORE in at least
* some of its revisions, but for unknown
* reasons, Broadcom's drivers always exclude
* the ChipCommon revision (0x5) used by BCM5365
* from the set of revisions supporting
* ID_NUMCORE, and instead supply a fixed value.
*
* Presumably, at least some of these devices
* shipped with a broken ID_NUMCORE value.
*/
*ncores = 7;
break;
default:
return (EINVAL);
}
return (0);
}
/**
* Allocate the resource defined by @p rs via @p dev, use it
* to read the ChipCommon ID register relative to @p chipc_offset,
@ -834,12 +917,16 @@ bhnd_read_chipid(device_t dev, struct resource_spec *rs,
bus_size_t chipc_offset, struct bhnd_chipid *result)
{
struct resource *res;
bhnd_addr_t enum_addr;
uint32_t reg;
uint8_t chip_type;
int error, rid, rtype;
/* Allocate the ChipCommon window resource and fetch the chipid data */
rid = rs->rid;
rtype = rs->type;
error = 0;
/* Allocate the ChipCommon window resource and fetch the chipid data */
res = bus_alloc_resource_any(dev, rtype, &rid, RF_ACTIVE);
if (res == NULL) {
device_printf(dev,
@ -849,30 +936,44 @@ bhnd_read_chipid(device_t dev, struct resource_spec *rs,
/* Fetch the basic chip info */
reg = bus_read_4(res, chipc_offset + CHIPC_ID);
*result = bhnd_parse_chipid(reg, 0x0);
chip_type = CHIPC_GET_BITS(reg, CHIPC_ID_BUS);
/* Fetch the enum base address */
error = 0;
switch (result->chip_type) {
case BHND_CHIPTYPE_SIBA:
result->enum_addr = BHND_DEFAULT_CHIPC_ADDR;
break;
case BHND_CHIPTYPE_BCMA:
case BHND_CHIPTYPE_BCMA_ALT:
result->enum_addr = bus_read_4(res, chipc_offset +
CHIPC_EROMPTR);
break;
case BHND_CHIPTYPE_UBUS:
device_printf(dev, "unsupported ubus/bcm63xx chip type");
error = ENODEV;
goto cleanup;
default:
device_printf(dev, "unknown chip type %hhu\n",
result->chip_type);
/* Fetch the EROMPTR */
if (BHND_CHIPTYPE_HAS_EROM(chip_type)) {
enum_addr = bus_read_4(res, chipc_offset + CHIPC_EROMPTR);
} else if (chip_type == BHND_CHIPTYPE_SIBA) {
/* siba(4) uses the ChipCommon base address as the enumeration
* address */
enum_addr = rman_get_start(res) + chipc_offset;
} else {
device_printf(dev, "unknown chip type %hhu\n", chip_type);
error = ENODEV;
goto cleanup;
}
*result = bhnd_parse_chipid(reg, enum_addr);
/* Fix the core count on early siba(4) devices */
if (chip_type == BHND_CHIPTYPE_SIBA) {
uint32_t idh;
uint16_t chipc_hwrev;
/*
* We need the ChipCommon revision to determine whether
* the ncore field is valid.
*
* We can safely assume the siba IDHIGH register is mapped
* within the chipc register block.
*/
idh = bus_read_4(res, SB0_REG_ABS(SIBA_CFG0_IDHIGH));
chipc_hwrev = SIBA_IDH_CORE_REV(idh);
error = bhnd_chipid_fixed_ncores(result, chipc_hwrev,
&result->ncores);
if (error)
goto cleanup;
}
cleanup:
/* Clean up */
bus_release_resource(dev, rtype, rid, res);
@ -1235,6 +1336,52 @@ bhnd_set_default_core_desc(device_t dev)
bhnd_set_custom_core_desc(dev, bhnd_get_device_name(dev));
}
/**
* Using the bhnd @p chip_id, populate the bhnd(4) bus @p dev's device
* description.
*
* @param dev A bhnd-bus attached device.
*/
void
bhnd_set_default_bus_desc(device_t dev, const struct bhnd_chipid *chip_id)
{
const char *bus_name;
char *desc;
char chip_name[BHND_CHIPID_MAX_NAMELEN];
/* Determine chip type's bus name */
switch (chip_id->chip_type) {
case BHND_CHIPTYPE_SIBA:
bus_name = "SIBA bus";
break;
case BHND_CHIPTYPE_BCMA:
case BHND_CHIPTYPE_BCMA_ALT:
bus_name = "BCMA bus";
break;
case BHND_CHIPTYPE_UBUS:
bus_name = "UBUS bus";
break;
default:
bus_name = "Unknown Type";
break;
}
/* Format chip name */
bhnd_format_chip_id(chip_name, sizeof(chip_name),
chip_id->chip_id);
/* Format and set device description */
asprintf(&desc, M_BHND, "%s %s", chip_name, bus_name);
if (desc != NULL) {
device_set_desc_copy(dev, desc);
free(desc, M_BHND);
} else {
device_set_desc(dev, bus_name);
}
}
/**
* Helper function for implementing BHND_BUS_IS_HW_DISABLED().
*
@ -1314,7 +1461,9 @@ bhnd_bus_generic_read_board_info(device_t dev, device_t child,
OPT_BHND_GV(info->board_vendor, BOARDVENDOR, 0);
OPT_BHND_GV(info->board_type, BOARDTYPE, 0); /* srom >= 2 */
REQ_BHND_GV(info->board_rev, BOARDREV);
REQ_BHND_GV(info->board_srom_rev,SROMREV);
OPT_BHND_GV(info->board_srom_rev,SROMREV, 0); /* missing in
some SoC
NVRAM */
REQ_BHND_GV(info->board_flags, BOARDFLAGS);
OPT_BHND_GV(info->board_flags2, BOARDFLAGS2, 0); /* srom >= 4 */
OPT_BHND_GV(info->board_flags3, BOARDFLAGS3, 0); /* srom >= 11 */

View File

@ -85,6 +85,66 @@ typedef enum {
* SoC */
} bhnd_attach_type;
/**
* bhnd(4) clock types.
*/
typedef enum {
/**
* Dynamically select an appropriate clock source based on all
* outstanding clock requests.
*/
BHND_CLOCK_DYN = (1 << 0),
/**
* Idle Low-Power (ILP).
*
* No register access is required, or long request latency is
* acceptable.
*/
BHND_CLOCK_ILP = (1 << 1),
/**
* Active Low-Power (ALP).
*
* Low-latency register access and low-rate DMA.
*/
BHND_CLOCK_ALP = (1 << 2),
/**
* High Throughput (HT).
*
* High bus throughput and lowest-latency register access.
*/
BHND_CLOCK_HT = (1 << 3)
} bhnd_clock;
/**
* Given two clock types, return the type with the highest precedence.
*/
static inline bhnd_clock
bhnd_clock_max(bhnd_clock a, bhnd_clock b) {
return (a > b ? a : b);
}
/**
* bhnd(4) clock sources.
*/
typedef enum {
/**
* Clock is provided by the PCI bus clock
*/
BHND_CLKSRC_PCI = 0,
/** Clock is provided by a crystal. */
BHND_CLKSRC_XTAL = 1,
/** Clock is provided by a low power oscillator. */
BHND_CLKSRC_LPO = 2,
/** Clock source is unknown */
BHND_CLKSRC_UNKNOWN = 3
} bhnd_clksrc;
/** Evaluates to true if @p cls is a device class that can be configured
* as a host bridge device. */
#define BHND_DEVCLASS_SUPPORTS_HOSTB(cls) \

View File

@ -66,11 +66,42 @@ bhnd_bhndb_get_attach_type(device_t dev, device_t child)
return (BHND_ATTACH_ADAPTER);
}
static bhnd_clksrc
bhnd_bhndb_pwrctl_get_clksrc(device_t dev, device_t child,
bhnd_clock clock)
{
/* Delegate to parent bridge */
return (BHND_BUS_PWRCTL_GET_CLKSRC(device_get_parent(dev), child,
clock));
}
static int
bhnd_bhndb_pwrctl_gate_clock(device_t dev, device_t child,
bhnd_clock clock)
{
/* Delegate to parent bridge */
return (BHND_BUS_PWRCTL_GATE_CLOCK(device_get_parent(dev), child,
clock));
}
static int
bhnd_bhndb_pwrctl_ungate_clock(device_t dev, device_t child,
bhnd_clock clock)
{
/* Delegate to parent bridge */
return (BHND_BUS_PWRCTL_UNGATE_CLOCK(device_get_parent(dev), child,
clock));
}
static device_method_t bhnd_bhndb_methods[] = {
/* BHND interface */
DEVMETHOD(bhnd_bus_get_attach_type, bhnd_bhndb_get_attach_type),
DEVMETHOD(bhnd_bus_read_board_info, bhnd_bhndb_read_board_info),
DEVMETHOD(bhnd_bus_pwrctl_get_clksrc, bhnd_bhndb_pwrctl_get_clksrc),
DEVMETHOD(bhnd_bus_pwrctl_gate_clock, bhnd_bhndb_pwrctl_gate_clock),
DEVMETHOD(bhnd_bus_pwrctl_ungate_clock, bhnd_bhndb_pwrctl_ungate_clock),
DEVMETHOD_END
};

View File

@ -2028,4 +2028,3 @@ DEFINE_CLASS_0(bhndb, bhndb_driver, bhndb_methods, sizeof(struct bhndb_softc));
MODULE_VERSION(bhndb, 1);
MODULE_DEPEND(bhndb, bhnd, 1, 1, 1);
MODULE_DEPEND(bhndb, bhnd_chipc, 1, 1, 1);

View File

@ -606,6 +606,64 @@ bhndb_disable_pci_clocks(struct bhndb_pci_softc *sc)
return (0);
}
static bhnd_clksrc
bhndb_pci_pwrctl_get_clksrc(device_t dev, device_t child,
bhnd_clock clock)
{
struct bhndb_pci_softc *sc;
uint32_t gpio_out;
sc = device_get_softc(dev);
/* Only supported on PCI devices */
if (sc->pci_devclass != BHND_DEVCLASS_PCI)
return (ENODEV);
/* Only ILP is supported */
if (clock != BHND_CLOCK_ILP)
return (ENXIO);
gpio_out = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUT, 4);
if (gpio_out & BHNDB_PCI_GPIO_SCS)
return (BHND_CLKSRC_PCI);
else
return (BHND_CLKSRC_XTAL);
}
static int
bhndb_pci_pwrctl_gate_clock(device_t dev, device_t child,
bhnd_clock clock)
{
struct bhndb_pci_softc *sc = device_get_softc(dev);
/* Only supported on PCI devices */
if (sc->pci_devclass != BHND_DEVCLASS_PCI)
return (ENODEV);
/* Only HT is supported */
if (clock != BHND_CLOCK_HT)
return (ENXIO);
return (bhndb_disable_pci_clocks(sc));
}
static int
bhndb_pci_pwrctl_ungate_clock(device_t dev, device_t child,
bhnd_clock clock)
{
struct bhndb_pci_softc *sc = device_get_softc(dev);
/* Only supported on PCI devices */
if (sc->pci_devclass != BHND_DEVCLASS_PCI)
return (ENODEV);
/* Only HT is supported */
if (clock != BHND_CLOCK_HT)
return (ENXIO);
return (bhndb_enable_pci_clocks(sc));
}
static device_method_t bhndb_pci_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, bhndb_pci_probe),
@ -614,6 +672,11 @@ static device_method_t bhndb_pci_methods[] = {
DEVMETHOD(device_suspend, bhndb_pci_suspend),
DEVMETHOD(device_detach, bhndb_pci_detach),
/* BHND interface */
DEVMETHOD(bhnd_bus_pwrctl_get_clksrc, bhndb_pci_pwrctl_get_clksrc),
DEVMETHOD(bhnd_bus_pwrctl_gate_clock, bhndb_pci_pwrctl_gate_clock),
DEVMETHOD(bhnd_bus_pwrctl_ungate_clock, bhndb_pci_pwrctl_ungate_clock),
/* BHNDB interface */
DEVMETHOD(bhndb_init_full_config, bhndb_pci_init_full_config),
DEVMETHOD(bhndb_set_window_addr, bhndb_pci_set_window_addr),
@ -627,7 +690,6 @@ DEFINE_CLASS_1(bhndb, bhndb_pci_driver, bhndb_pci_methods,
MODULE_VERSION(bhndb_pci, 1);
MODULE_DEPEND(bhndb_pci, bhnd_pci_hostb, 1, 1, 1);
MODULE_DEPEND(bhndb_pci, bhnd_pcie2_hostb, 1, 1, 1);
MODULE_DEPEND(bhndb_pci, pci, 1, 1, 1);
MODULE_DEPEND(bhndb_pci, bhndb, 1, 1, 1);
MODULE_DEPEND(bhndb_pci, bhnd, 1, 1, 1);

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -45,27 +45,7 @@
MALLOC_DECLARE(M_BHND);
DECLARE_CLASS(bhnd_driver);
/**
* bhnd per-device info. Must be first member of all subclass
* devinfo structures.
*/
struct bhnd_devinfo {
};
/**
* bhnd driver instance state. Must be first member of all subclass
* softc structures.
*/
struct bhnd_softc {
device_t dev; /**< bus device */
bool attach_done; /**< true if initialization of all
* platform devices has been
* completed */
device_t chipc_dev; /**< bhnd_chipc device */
device_t nvram_dev; /**< bhnd_nvram device, if any */
device_t pmu_dev; /**< bhnd_pmu device, if any */
};
struct bhnd_core_pmu_info;
int bhnd_generic_attach(device_t dev);
int bhnd_generic_detach(device_t dev);
@ -76,6 +56,19 @@ int bhnd_generic_suspend(device_t dev);
int bhnd_generic_get_probe_order(device_t dev,
device_t child);
int bhnd_generic_alloc_pmu(device_t dev,
device_t child);
int bhnd_generic_release_pmu(device_t dev,
device_t child);
int bhnd_generic_request_clock(device_t dev,
device_t child, bhnd_clock clock);
int bhnd_generic_enable_clocks(device_t dev,
device_t child, uint32_t clocks);
int bhnd_generic_request_ext_rsrc(device_t dev,
device_t child, u_int rsrc);
int bhnd_generic_release_ext_rsrc(device_t dev,
device_t child, u_int rsrc);
int bhnd_generic_print_child(device_t dev,
device_t child);
void bhnd_generic_probe_nomatch(device_t dev,
@ -83,6 +76,7 @@ void bhnd_generic_probe_nomatch(device_t dev,
device_t bhnd_generic_add_child(device_t dev, u_int order,
const char *name, int unit);
void bhnd_generic_child_added(device_t dev, device_t child);
void bhnd_generic_child_deleted(device_t dev,
device_t child);
int bhnd_generic_suspend_child(device_t dev,
@ -94,4 +88,28 @@ int bhnd_generic_get_nvram_var(device_t dev,
device_t child, const char *name, void *buf,
size_t *size, bhnd_nvram_type type);
/**
* bhnd per-device info. Must be first member of all subclass
* devinfo structures.
*/
struct bhnd_devinfo {
struct bhnd_core_pmu_info *pmu_info; /**< PMU info, or NULL */
};
/**
* bhnd driver instance state. Must be first member of all subclass
* softc structures.
*/
struct bhnd_softc {
device_t dev; /**< bus device */
bool attach_done; /**< true if initialization of
* all platform devices has
* been completed */
device_t chipc_dev; /**< bhnd_chipc device */
device_t nvram_dev; /**< bhnd_nvram device, if any */
device_t pmu_dev; /**< bhnd_pmu device, if any */
};
#endif /* _BHND_BHNDVAR_H_ */

View File

@ -48,6 +48,22 @@ CODE {
}
}
/**
* Return the current value of the chipstatus register.
*
* @param dev A bhnd(4) ChipCommon device.
*
* Drivers should only use function for functionality that is not
* available via another bhnd_chipc() function.
*
* @returns The chipstatus register value, or 0 if undefined by this
* hardware (e.g. if @p dev is an EXTIF core).
*/
METHOD uint32_t read_chipst {
device_t dev;
}
/**
* Write @p value with @p mask directly to the chipctrl register.
*

View File

@ -0,0 +1,126 @@
/*-
* Copyright (c) 2016 Landon Fuller <landon@landonf.org>
* 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,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* ChipCommon attachment support for the bhnd(4) PMU driver.
*
* Supports non-AOB ("Always-on Bus") devices that map the PMU register blocks
* via the ChipCommon core, rather than vending a distinct PMU core on the
* bhnd bus.
*/
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/limits.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/systm.h>
#include <dev/bhnd/bhnd.h>
#include <dev/bhnd/cores/pmu/bhnd_pmuvar.h>
#include <dev/bhnd/cores/pmu/bhnd_pmureg.h>
#include "bhnd_chipc_if.h"
#include "bhnd_pmu_if.h"
#include "chipcvar.h"
static int
bhnd_pmu_chipc_probe(device_t dev)
{
struct bhnd_pmu_softc *sc;
struct chipc_caps *ccaps;
struct chipc_softc *chipc_sc;
device_t chipc;
char desc[34];
int error;
uint32_t pcaps;
uint8_t rev;
sc = device_get_softc(dev);
/* Look for chipc parent */
chipc = device_get_parent(dev);
if (device_get_devclass(chipc) != devclass_find("bhnd_chipc"))
return (ENXIO);
/* Check the chipc PMU capability flag. */
ccaps = BHND_CHIPC_GET_CAPS(chipc);
if (!ccaps->pmu)
return (ENXIO);
/* Delegate to common driver implementation */
if ((error = bhnd_pmu_probe(dev)) > 0)
return (error);
/* Fetch PMU capability flags */
chipc_sc = device_get_softc(chipc);
pcaps = bhnd_bus_read_4(chipc_sc->core, BHND_PMU_CAP);
/* Set description */
rev = BHND_PMU_GET_BITS(pcaps, BHND_PMU_CAP_REV);
snprintf(desc, sizeof(desc), "Broadcom ChipCommon PMU, rev %hhu", rev);
device_set_desc_copy(dev, desc);
return (BUS_PROBE_NOWILDCARD);
}
static int
bhnd_pmu_chipc_attach(device_t dev)
{
struct chipc_softc *chipc_sc;
struct bhnd_resource *r;
/* Fetch core registers from ChipCommon parent */
chipc_sc = device_get_softc(device_get_parent(dev));
r = chipc_sc->core;
return (bhnd_pmu_attach(dev, r));
}
static device_method_t bhnd_pmu_chipc_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, bhnd_pmu_chipc_probe),
DEVMETHOD(device_attach, bhnd_pmu_chipc_attach),
DEVMETHOD_END
};
DEFINE_CLASS_1(bhnd_pmu, bhnd_pmu_chipc_driver, bhnd_pmu_chipc_methods,
sizeof(struct bhnd_pmu_softc), bhnd_pmu_driver);
EARLY_DRIVER_MODULE(bhnd_pmu_chipc, bhnd_chipc, bhnd_pmu_chipc_driver,
bhnd_pmu_devclass, NULL, NULL, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE);
MODULE_DEPEND(bhnd_pmu_chipc, bhnd, 1, 1, 1);
MODULE_VERSION(bhnd_pmu_chipc, 1);

View File

@ -46,10 +46,9 @@ __FBSDID("$FreeBSD$");
#include <dev/bhnd/nvram/bhnd_nvram.h>
#include <dev/bhnd/nvram/bhnd_spromvar.h>
#include "bhnd_nvram_if.h"
#include <dev/bhnd/cores/chipc/chipc.h>
#include "chipcvar.h"
#include "chipc_private.h"
#include "bhnd_nvram_if.h"
#define CHIPC_VALID_SPROM_SRC(_src) \
((_src) == BHND_NVRAM_SRC_SPROM || (_src) == BHND_NVRAM_SRC_OTP)

View File

@ -110,25 +110,27 @@ static struct bhnd_device_quirk chipc_quirks[] = {
// FIXME: IRQ shouldn't be hard-coded
#define CHIPC_MIPS_IRQ 2
static int chipc_add_children(struct chipc_softc *sc);
static int chipc_add_children(struct chipc_softc *sc);
static bhnd_nvram_src chipc_find_nvram_src(struct chipc_softc *sc,
struct chipc_caps *caps);
static int chipc_read_caps(struct chipc_softc *sc,
struct chipc_caps *caps);
static bhnd_nvram_src chipc_find_nvram_src(struct chipc_softc *sc,
struct chipc_caps *caps);
static int chipc_read_caps(struct chipc_softc *sc,
struct chipc_caps *caps);
static bool chipc_should_enable_sprom(
struct chipc_softc *sc);
static bool chipc_should_enable_muxed_sprom(
struct chipc_softc *sc);
static int chipc_enable_otp_power(struct chipc_softc *sc);
static void chipc_disable_otp_power(struct chipc_softc *sc);
static int chipc_enable_sprom_pins(struct chipc_softc *sc);
static void chipc_disable_sprom_pins(struct chipc_softc *sc);
static int chipc_try_activate_resource(
struct chipc_softc *sc, device_t child,
int type, int rid, struct resource *r,
bool req_direct);
static int chipc_try_activate_resource(struct chipc_softc *sc,
device_t child, int type, int rid,
struct resource *r, bool req_direct);
static int chipc_init_rman(struct chipc_softc *sc);
static void chipc_free_rman(struct chipc_softc *sc);
static struct rman *chipc_get_rman(struct chipc_softc *sc,
int type);
static int chipc_init_rman(struct chipc_softc *sc);
static void chipc_free_rman(struct chipc_softc *sc);
static struct rman *chipc_get_rman(struct chipc_softc *sc, int type);
/* quirk and capability flag convenience macros */
#define CHIPC_QUIRK(_sc, _name) \
@ -266,40 +268,19 @@ chipc_add_children(struct chipc_softc *sc)
return (error);
}
#ifdef notyet
/*
* PMU/SLOWCLK/INSTACLK
* PMU/PWR_CTRL
*
* On AOB ("Always on Bus") devices, a PMU core (if it exists) is
* enumerated directly by the bhnd(4) bus -- not chipc.
*
* Otherwise, we always add a PMU child device, and let the
* chipc bhnd_pmu drivers probe for it. If the core supports an
* earlier non-PMU clock/power register interface, one of the instaclk,
* powerctl, or null bhnd_pmu drivers will claim the device.
* On AOB ("Always on Bus") devices, the PMU core (if it exists) is
* attached directly to the bhnd(4) bus -- not chipc.
*/
if (!sc->caps.aob || (sc->caps.aob && !sc->caps.pmu)) {
if (sc->caps.pwr_ctrl || (sc->caps.pmu && !sc->caps.aob)) {
child = BUS_ADD_CHILD(sc->dev, 0, "bhnd_pmu", -1);
if (child == NULL) {
device_printf(sc->dev, "failed to add pmu\n");
return (ENXIO);
}
/* Associate the applicable register block */
error = 0;
if (sc->caps.pmu) {
error = chipc_set_resource(sc, child, SYS_RES_MEMORY, 0,
CHIPC_PMU, CHIPC_PMU_SIZE, 0, 0);
} else if (sc->caps.power_control) {
error = chipc_set_resource(sc, child, SYS_RES_MEMORY, 0,
CHIPC_PWRCTL, CHIPC_PWRCTL_SIZE, 0, 0);
}
if (error)
return (error);
}
#endif /* notyet */
/* All remaining devices are SoC-only */
if (bhnd_get_attach_type(sc->dev) != BHND_ATTACH_NATIVE)
@ -422,7 +403,7 @@ chipc_read_caps(struct chipc_softc *sc, struct chipc_caps *caps)
caps->uart_clock = CHIPC_GET_BITS(cap_reg, CHIPC_CAP_UCLKSEL);
caps->extbus_type = CHIPC_GET_BITS(cap_reg, CHIPC_CAP_EXTBUS);
caps->power_control = CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_PWR_CTL);
caps->pwr_ctrl = CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_PWR_CTL);
caps->jtag_master = CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_JTAGP);
caps->pll_type = CHIPC_GET_BITS(cap_reg, CHIPC_CAP_PLL);
@ -1089,7 +1070,7 @@ chipc_deactivate_resource(device_t dev, device_t child, int type,
* @param sc chipc driver state.
*/
static bool
chipc_should_enable_sprom(struct chipc_softc *sc)
chipc_should_enable_muxed_sprom(struct chipc_softc *sc)
{
device_t *devs;
device_t hostb;
@ -1098,17 +1079,19 @@ chipc_should_enable_sprom(struct chipc_softc *sc)
int error;
bool result;
mtx_assert(&Giant, MA_OWNED); /* for newbus */
/* Nothing to do? */
if (!CHIPC_QUIRK(sc, MUX_SPROM))
return (true);
mtx_lock(&Giant); /* for newbus */
parent = device_get_parent(sc->dev);
hostb = bhnd_find_hostb_device(parent);
if ((error = device_get_children(parent, &devs, &devcount)))
if ((error = device_get_children(parent, &devs, &devcount))) {
mtx_unlock(&Giant);
return (false);
}
/* Reject any active devices other than ChipCommon, or the
* host bridge (if any). */
@ -1129,42 +1112,112 @@ chipc_should_enable_sprom(struct chipc_softc *sc)
}
free(devs, M_TEMP);
mtx_unlock(&Giant);
return (result);
}
static int
chipc_enable_sprom(device_t dev)
{
struct chipc_softc *sc;
int error;
sc = device_get_softc(dev);
CHIPC_LOCK(sc);
/* Already enabled? */
if (sc->sprom_refcnt >= 1) {
sc->sprom_refcnt++;
CHIPC_UNLOCK(sc);
return (0);
}
switch (sc->caps.nvram_src) {
case BHND_NVRAM_SRC_SPROM:
error = chipc_enable_sprom_pins(sc);
break;
case BHND_NVRAM_SRC_OTP:
error = chipc_enable_otp_power(sc);
break;
default:
error = 0;
break;
}
/* Bump the reference count */
if (error == 0)
sc->sprom_refcnt++;
CHIPC_UNLOCK(sc);
return (error);
}
static void
chipc_disable_sprom(device_t dev)
{
struct chipc_softc *sc;
sc = device_get_softc(dev);
CHIPC_LOCK(sc);
/* Check reference count, skip disable if in-use. */
KASSERT(sc->sprom_refcnt > 0, ("sprom refcnt overrelease"));
sc->sprom_refcnt--;
if (sc->sprom_refcnt > 0) {
CHIPC_UNLOCK(sc);
return;
}
switch (sc->caps.nvram_src) {
case BHND_NVRAM_SRC_SPROM:
chipc_disable_sprom_pins(sc);
break;
case BHND_NVRAM_SRC_OTP:
chipc_disable_otp_power(sc);
break;
default:
break;
}
CHIPC_UNLOCK(sc);
}
static int
chipc_enable_otp_power(struct chipc_softc *sc)
{
// TODO: Enable OTP resource via PMU, and wait up to 100 usec for
// OTPS_READY to be set in `optstatus`.
return (0);
}
static void
chipc_disable_otp_power(struct chipc_softc *sc)
{
// TODO: Disable OTP resource via PMU
}
/**
* If required by this device, enable access to the SPROM.
*
* @param sc chipc driver state.
*/
static int
chipc_enable_sprom_pins(device_t dev)
chipc_enable_sprom_pins(struct chipc_softc *sc)
{
struct chipc_softc *sc;
uint32_t cctrl;
int error;
sc = device_get_softc(dev);
CHIPC_LOCK_ASSERT(sc, MA_OWNED);
KASSERT(sc->sprom_refcnt == 0, ("sprom pins already enabled"));
/* Nothing to do? */
if (!CHIPC_QUIRK(sc, MUX_SPROM))
return (0);
/* Make sure we're holding Giant for newbus */
mtx_lock(&Giant);
CHIPC_LOCK(sc);
/* Already enabled? */
if (sc->sprom_refcnt >= 1) {
error = 0;
goto finished;
}
/* Check whether bus is busy */
if (!chipc_should_enable_sprom(sc)) {
error = EBUSY;
goto finished;
}
if (!chipc_should_enable_muxed_sprom(sc))
return (EBUSY);
cctrl = bhnd_bus_read_4(sc->core, CHIPC_CHIPCTRL);
@ -1179,8 +1232,7 @@ chipc_enable_sprom_pins(device_t dev)
cctrl &= ~CHIPC_CCTRL4331_EXTPA_EN2;
bhnd_bus_write_4(sc->core, CHIPC_CHIPCTRL, cctrl);
error = 0;
goto finished;
return (0);
}
/* 4360 devices */
@ -1190,17 +1242,7 @@ chipc_enable_sprom_pins(device_t dev)
/* Refuse to proceed on unsupported devices with muxed SPROM pins */
device_printf(sc->dev, "muxed sprom lines on unrecognized device\n");
error = ENXIO;
finished:
/* Bump the reference count */
if (error == 0)
sc->sprom_refcnt++;
CHIPC_UNLOCK(sc);
mtx_unlock(&Giant);
return (error);
return (ENXIO);
}
/**
@ -1210,24 +1252,17 @@ chipc_enable_sprom_pins(device_t dev)
* @param sc chipc driver state.
*/
static void
chipc_disable_sprom_pins(device_t dev)
chipc_disable_sprom_pins(struct chipc_softc *sc)
{
struct chipc_softc *sc;
uint32_t cctrl;
sc = device_get_softc(dev);
/* Nothing to do? */
if (!CHIPC_QUIRK(sc, MUX_SPROM))
return;
CHIPC_LOCK(sc);
/* Check reference count, skip disable if in-use. */
KASSERT(sc->sprom_refcnt > 0, ("sprom refcnt overrelease"));
sc->sprom_refcnt--;
if (sc->sprom_refcnt > 0)
goto finished;
CHIPC_LOCK_ASSERT(sc, MA_OWNED);
KASSERT(sc->sprom_refcnt != 0, ("sprom pins already disabled"));
KASSERT(sc->sprom_refcnt == 1, ("sprom pins in use"));
cctrl = bhnd_bus_read_4(sc->core, CHIPC_CHIPCTRL);
@ -1242,16 +1277,20 @@ chipc_disable_sprom_pins(device_t dev)
cctrl |= CHIPC_CCTRL4331_EXTPA_EN2;
bhnd_bus_write_4(sc->core, CHIPC_CHIPCTRL, cctrl);
goto finished;
return;
}
/* 4360 devices */
if (CHIPC_QUIRK(sc, 4360_FEM_MUX_SPROM)) {
/* Unimplemented */
}
}
finished:
CHIPC_UNLOCK(sc);
static uint32_t
chipc_read_chipst(device_t dev)
{
struct chipc_softc *sc = device_get_softc(dev);
return (bhnd_bus_read_4(sc->core, CHIPC_CHIPST));
}
static void
@ -1317,16 +1356,17 @@ static device_method_t chipc_methods[] = {
DEVMETHOD(bhnd_bus_activate_resource, chipc_activate_bhnd_resource),
/* ChipCommon interface */
DEVMETHOD(bhnd_chipc_read_chipst, chipc_read_chipst),
DEVMETHOD(bhnd_chipc_write_chipctrl, chipc_write_chipctrl),
DEVMETHOD(bhnd_chipc_enable_sprom, chipc_enable_sprom_pins),
DEVMETHOD(bhnd_chipc_disable_sprom, chipc_disable_sprom_pins),
DEVMETHOD(bhnd_chipc_enable_sprom, chipc_enable_sprom),
DEVMETHOD(bhnd_chipc_disable_sprom, chipc_disable_sprom),
DEVMETHOD(bhnd_chipc_get_caps, chipc_get_caps),
DEVMETHOD_END
};
DEFINE_CLASS_0(bhnd_chipc, chipc_driver, chipc_methods, sizeof(struct chipc_softc));
EARLY_DRIVER_MODULE(bhnd_chipc, bhnd, chipc_driver, bhnd_chipc_devclass, 0, 0,
DEFINE_CLASS_0(bhnd_chipc, bhnd_chipc_driver, chipc_methods, sizeof(struct chipc_softc));
EARLY_DRIVER_MODULE(bhnd_chipc, bhnd, bhnd_chipc_driver, bhnd_chipc_devclass, 0, 0,
BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
MODULE_DEPEND(bhnd_chipc, bhnd, 1, 1, 1);
MODULE_VERSION(bhnd_chipc, 1);

View File

@ -37,4 +37,60 @@
#include "bhnd_chipc_if.h"
/**
* Supported ChipCommon flash types.
*/
typedef enum {
CHIPC_FLASH_NONE = 0, /**< No flash, or a type unrecognized
by the ChipCommon driver */
CHIPC_PFLASH_CFI = 1, /**< CFI-compatible parallel flash */
CHIPC_SFLASH_ST = 2, /**< ST serial flash */
CHIPC_SFLASH_AT = 3, /**< Atmel serial flash */
CHIPC_QSFLASH_ST = 4, /**< ST quad-SPI flash */
CHIPC_QSFLASH_AT = 5, /**< Atmel quad-SPI flash */
CHIPC_NFLASH = 6, /**< NAND flash */
CHIPC_NFLASH_4706 = 7 /**< BCM4706 NAND flash */
} chipc_flash;
/**
* ChipCommon capability flags;
*/
struct chipc_caps {
uint8_t num_uarts; /**< Number of attached UARTS (1-3) */
bool mipseb; /**< MIPS is big-endian */
uint8_t uart_clock; /**< UART clock source (see CHIPC_CAP_UCLKSEL_*) */
uint8_t uart_gpio; /**< UARTs own GPIO pins 12-15 */
uint8_t extbus_type; /**< ExtBus type (CHIPC_CAP_EXTBUS_*) */
chipc_flash flash_type; /**< flash type */
uint8_t cfi_width; /**< CFI bus width, 0 if unknown or CFI
not present */
bhnd_nvram_src nvram_src; /**< identified NVRAM source */
bus_size_t sprom_offset; /**< Offset to SPROM data within
SPROM/OTP, 0 if unknown or not
present */
uint8_t otp_size; /**< OTP (row?) size, 0 if not present */
uint8_t pll_type; /**< PLL type */
bool pwr_ctrl; /**< Power/clock control available */
bool jtag_master; /**< JTAG Master present */
bool boot_rom; /**< Internal boot ROM is active */
uint8_t backplane_64; /**< Backplane supports 64-bit addressing.
Note that this does not gaurantee
the CPU itself supports 64-bit
addressing. */
bool pmu; /**< PMU is present. */
bool eci; /**< ECI (enhanced coexistence inteface) is present. */
bool seci; /**< SECI (serial ECI) is present */
bool sprom; /**< SPROM is present */
bool gsio; /**< GSIO (SPI/I2C) present */
bool aob; /**< AOB (always on bus) present.
If set, PMU and GCI registers are
not accessible via ChipCommon,
and are instead accessible via
dedicated cores on the bhnd bus */
};
#endif /* _BHND_CORES_CHIPC_CHIPC_H_ */

View File

@ -248,8 +248,8 @@ chipc_print_caps(device_t dev, struct chipc_caps *caps)
CC_TFS(sprom), CC_TFS(otp_size));
device_printf(dev, "CFIsz: 0x%02x | OTPsz: 0x%02x\n",
caps->cfi_width, caps->otp_size);
device_printf(dev, "ExtBus: 0x%02x | PwCtl: %s\n",
caps->extbus_type, CC_TFS(power_control));
device_printf(dev, "ExtBus: 0x%02x | PwrCtrl: %s\n",
caps->extbus_type, CC_TFS(pwr_ctrl));
device_printf(dev, "PLL: 0x%02x | JTAGM: %s\n",
caps->pll_type, CC_TFS(jtag_master));
device_printf(dev, "PMU: %-3s | ECI: %s\n",

View File

@ -31,10 +31,24 @@
required during bus
enumeration */
/** Evaluates to true if the given ChipCommon core revision supports
* the CHIPC_CORECTRL register */
#define CHIPC_HWREV_HAS_CORECTRL(hwrev) ((hwrev) >= 1)
/** Evaluates to true if the given ChipCommon core revision provides
* the core count via the chip identification register. */
#define CHIPC_NCORES_MIN_HWREV(hwrev) ((hwrev) == 4 || (hwrev) >= 6)
/** Evaluates to true if the given ChipCommon core revision supports
* the CHIPC_CAPABILITIES_EXT register */
#define CHIPC_HWREV_HAS_CAP_EXT(hwrev) ((hwrev) >= 35)
/** Evaluates to true if the chipcommon core (determined from the provided
* @p _chipid (CHIPC_ID) register value) provides a pointer to the enumeration
* table via CHIPC_EROMPTR */
#define CHIPC_HAS_EROMPTR(_chipid) \
(CHIPC_GET_BITS((_chipid), CHIPC_ID_BUS) != BHND_CHIPTYPE_SIBA)
#define CHIPC_GET_FLAG(_value, _flag) (((_value) & _flag) != 0)
#define CHIPC_GET_BITS(_value, _field) \
((_value & _field ## _MASK) >> _field ## _SHIFT)
@ -90,24 +104,25 @@
#define CHIPC_GPIOTIMERVAL 0x88 /**< gpio-based LED duty cycle (rev >= 16) */
#define CHIPC_GPIOTIMEROUTMASK 0x8C
/* clock control block */
/* clock control registers (non-PMU devices) */
#define CHIPC_CLKC_N 0x90
#define CHIPC_CLKC_SB 0x94 /* m0 (backplane) */
#define CHIPC_CLKC_PCI 0x98 /* m1 */
#define CHIPC_CLKC_M2 0x9C /* mii/uart/mipsref */
#define CHIPC_CLKC_M3 0xA0 /* cpu */
#define CHIPC_CLKDIV 0xA4 /* rev >= 3 */
#define CHIPC_GPIODEBUGSEL 0xA8 /* rev >= 28 */
#define CHIPC_CAPABILITIES_EXT 0xAC
/* pll delay (registers rev >= 4) */
#define CHIPC_PLL_ON_DELAY 0xB0
#define CHIPC_PLL_FREFSEL_DELAY 0xB4
#define CHIPC_PLL_SLOWCLK_CTL 0xB8 /* revs 6-9 */
/* "instaclock" registers */
#define CHIPC_SYS_CLK_CTL 0xC0 /* rev >= 10 */
#define CHIPC_SYS_CLKSTATESTRETCH 0xC4 /* rev >= 10 */
/* pll/slowclk clock control registers (rev >= 4) */
#define CHIPC_PLL_ON_DELAY 0xB0 /* rev >= 4 */
#define CHIPC_PLL_FREFSEL_DELAY 0xB4 /* rev >= 4 */
#define CHIPC_PLL_SLOWCLK_CTL 0xB8 /* "slowclock" (rev 6-9) */
/* "instaclock" clock control registers */
#define CHIPC_SYS_CLK_CTL 0xC0 /* "instaclock" (rev >= 10) */
#define CHIPC_SYS_CLK_ST_STRETCH 0xC4 /* state strech (?) rev >= 10 */
/* indirect backplane access (rev >= 10) */
#define CHIPC_BP_ADDRLOW 0xD0
@ -125,7 +140,7 @@
#define CHIPC_EROMPTR 0xFC /**< 32-bit EROM base address
* on BCMA devices */
/* ExtBus control registers (rev >= 3) */
#define CHIPC_PCMCIA_CFG 0x100
#define CHIPC_PCMCIA_MEMWAIT 0x104
@ -178,38 +193,10 @@
#define CHIPC_UART_MAX 3 /**< max UART blocks */
#define CHIPC_UART(_n) (CHIPC_UART_BASE + (CHIPC_UART_SIZE*_n))
/* PMU registers (rev >= 20) */
/* PMU register block (rev >= 20) */
#define CHIPC_PMU_BASE 0x600
#define CHIPC_PMU_SIZE 0x70
#define CHIPC_PMU_CTRL 0x600
#define CHIPC_PMU_CAP 0x604
#define CHIPC_PMU_ST 0x608
#define CHIPC_PMU_RES_STATE 0x60c
#define CHIPC_PMU_RES_PENDING 0x610
#define CHIPC_PMU_TIMER 0x614
#define CHIPC_PMU_MIN_RES_MASK 0x618
#define CHIPC_PMU_MAX_RES_MASK 0x61c
#define CHIPC_PMU_RES_TABLE_SEL 0x620
#define CHIPC_PMU_RES_DEP_MASK 0x624
#define CHIPC_PMU_RES_UPDN_TIMER 0x628
#define CHIPC_PMU_RES_TIMER 0x62C
#define CHIPC_PMU_CLKSTRETCH 0x630
#define CHIPC_PMU_WATCHDOG 0x634
#define CHIPC_PMU_GPIOSEL 0x638 /* pmu rev >= 1 ? */
#define CHIPC_PMU_GPIOEN 0x63C /* pmu rev >= 1 ? */
#define CHIPC_PMU_RES_REQ_TIMER_SEL 0x640
#define CHIPC_PMU_RES_REQ_TIMER 0x644
#define CHIPC_PMU_RES_REQ_MASK 0x648
#define CHIPC_CHIPCTL_ADDR 0x650
#define CHIPC_CHIPCTL_DATA 0x654
#define CHIPC_PMU_REG_CONTROL_ADDR 0x658
#define CHIPC_PMU_REG_CONTROL_DATA 0x65C
#define CHIPC_PMU_PLL_CONTROL_ADDR 0x660
#define CHIPC_PMU_PLL_CONTROL_DATA 0x664
#define CHIPC_PMU_STRAPOPT 0x668 /* chipc rev >= 28 */
#define CHIPC_PMU_XTALFREQ 0x66C /* pmu rev >= 10 */
#define CHIPC_SPROM_OTP 0x800 /* SPROM/OTP address space */
#define CHIPC_SPROM_OTP_SIZE 0x400
@ -247,7 +234,7 @@
#define CHIPC_CAP_PFLASH 0x7 /* Parallel flash */
#define CHIPC_CAP_PLL_MASK 0x00038000 /* Type of PLL */
#define CHIPC_CAP_PLL_SHIFT 15
#define CHIPC_CAP_PWR_CTL 0x00040000 /* Power control */
#define CHIPC_CAP_PWR_CTL 0x00040000 /* Power/clock control */
#define CHIPC_CAP_OTP_SIZE_MASK 0x00380000 /* OTP Size (0 = none) */
#define CHIPC_CAP_OTP_SIZE_SHIFT 19 /* OTP Size shift */
#define CHIPC_CAP_OTP_SIZE_BASE 5 /* OTP Size base */
@ -295,23 +282,31 @@ enum {
#define CHIPC_CST_SPROM_OTP_SEL_R23_SHIFT 6
/* PLL type */
#define CHIPC_PLL_NONE 0x00000000
#define CHIPC_PLL_TYPE1 0x00010000 /* 48MHz base, 3 dividers */
#define CHIPC_PLL_TYPE2 0x00020000 /* 48MHz, 4 dividers */
#define CHIPC_PLL_TYPE3 0x00030000 /* 25MHz, 2 dividers */
#define CHIPC_PLL_TYPE4 0x00008000 /* 48MHz, 4 dividers */
#define CHIPC_PLL_TYPE5 0x00018000 /* 25MHz, 4 dividers */
#define CHIPC_PLL_TYPE6 0x00028000 /* 100/200 or 120/240 only */
#define CHIPC_PLL_TYPE7 0x00038000 /* 25MHz, 4 dividers */
#define CHIPC_PLL_NONE 0x0
#define CHIPC_PLL_TYPE1 0x2 /* 48MHz base, 3 dividers */
#define CHIPC_PLL_TYPE2 0x4 /* 48MHz, 4 dividers */
#define CHIPC_PLL_TYPE3 0x6 /* 25MHz, 2 dividers */
#define CHIPC_PLL_TYPE4 0x8 /* 48MHz, 4 dividers */
#define CHIPC_PLL_TYPE5 0x3 /* 25MHz, 4 dividers */
#define CHIPC_PLL_TYPE6 0x5 /* 100/200 or 120/240 only */
#define CHIPC_PLL_TYPE7 0x7 /* 25MHz, 4 dividers */
/* ILP clock */
#define CHIPC_ILP_CLOCK 32000
/* dynamic clock control defines */
#define CHIPC_LPOMINFREQ 25000 /* low power oscillator min */
#define CHIPC_LPOMAXFREQ 43000 /* low power oscillator max */
#define CHIPC_XTALMINFREQ 19800000 /* 20 MHz - 1% */
#define CHIPC_XTALMAXFREQ 20200000 /* 20 MHz + 1% */
#define CHIPC_PCIMINFREQ 25000000 /* 25 MHz */
#define CHIPC_PCIMAXFREQ 34000000 /* 33 MHz + fudge */
/* ALP clock on pre-PMU chips */
#define CHIPC_ALP_CLOCK 20000000
#define CHIPC_ILP_DIV_5MHZ 0 /* ILP = 5 MHz */
#define CHIPC_ILP_DIV_1MHZ 4 /* ILP = 1 MHz */
/* HT clock */
#define CHIPC_HT_CLOCK 80000000
/* Power Control Defines */
#define CHIPC_PLL_DELAY 150 /* us pll on delay */
#define CHIPC_FREF_DELAY 200 /* us fref change delay */
#define CHIPC_MIN_SLOW_CLK 32 /* us Slow clock period */
#define CHIPC_XTAL_ON_DELAY 1000 /* us crystal power-on delay */
/* corecontrol */
#define CHIPC_UARTCLKO 0x00000001 /* Drive UART with internal clock */
@ -567,27 +562,12 @@ enum {
#define CHIPC_SRC_SIZE_SHIFT 1
#define CHIPC_SRC_PRESENT 0x00000001
/* Fields in pmucontrol */
#define CHIPC_PCTL_ILP_DIV_MASK 0xffff0000
#define CHIPC_PCTL_ILP_DIV_SHIFT 16
#define CHIPC_PCTL_PLL_PLLCTL_UPD 0x00000400 /* rev 2 */
#define CHIPC_PCTL_NOILP_ON_WAIT 0x00000200 /* rev 1 */
#define CHIPC_PCTL_HT_REQ_EN 0x00000100
#define CHIPC_PCTL_ALP_REQ_EN 0x00000080
#define CHIPC_PCTL_XTALFREQ_MASK 0x0000007c
#define CHIPC_PCTL_XTALFREQ_SHIFT 2
#define CHIPC_PCTL_ILP_DIV_EN 0x00000002
#define CHIPC_PCTL_LPO_SEL 0x00000001
/* Fields in clkstretch */
#define CHIPC_CSTRETCH_HT 0xffff0000
#define CHIPC_CSTRETCH_ALP 0x0000ffff
/* gpiotimerval */
#define CHIPC_GPIO_ONTIME_SHIFT 16
/* clockcontrol_n */
#define CHIPC_CN_N1_MASK 0x3f /* n1 control */
#define CHIPC_CN_N1_SHIFT 0
#define CHIPC_CN_N2_MASK 0x3f00 /* n2 control */
#define CHIPC_CN_N2_SHIFT 8
#define CHIPC_CN_PLLC_MASK 0xf0000 /* pll control */
@ -595,6 +575,7 @@ enum {
/* clockcontrol_sb/pci/uart */
#define CHIPC_M1_MASK 0x3f /* m1 control */
#define CHIPC_M1_SHIFT 0
#define CHIPC_M2_MASK 0x3f00 /* m2 control */
#define CHIPC_M2_SHIFT 8
#define CHIPC_M3_MASK 0x3f0000 /* m3 control */
@ -778,345 +759,6 @@ enum {
#define CHIPC_UART_IER_ETBEI 2 /* enable transmitter holding register empty interrupt */
#define CHIPC_UART_IER_ERBFI 1 /* enable data available interrupt */
/* pmustatus */
#define CHIPC_PST_EXTLPOAVAIL 0x0100
#define CHIPC_PST_WDRESET 0x0080
#define CHIPC_PST_INTPEND 0x0040
#define CHIPC_PST_SBCLKST 0x0030
#define CHIPC_PST_SBCLKST_ILP 0x0010
#define CHIPC_PST_SBCLKST_ALP 0x0020
#define CHIPC_PST_SBCLKST_HT 0x0030
#define CHIPC_PST_ALPAVAIL 0x0008
#define CHIPC_PST_HTAVAIL 0x0004
#define CHIPC_PST_RESINIT 0x0003
/* pmucapabilities */
#define CHIPC_PCAP_REV_MASK 0x000000ff
#define CHIPC_PCAP_RC_MASK 0x00001f00
#define CHIPC_PCAP_RC_SHIFT 8
#define CHIPC_PCAP_TC_MASK 0x0001e000
#define CHIPC_PCAP_TC_SHIFT 13
#define CHIPC_PCAP_PC_MASK 0x001e0000
#define CHIPC_PCAP_PC_SHIFT 17
#define CHIPC_PCAP_VC_MASK 0x01e00000
#define CHIPC_PCAP_VC_SHIFT 21
#define CHIPC_PCAP_CC_MASK 0x1e000000
#define CHIPC_PCAP_CC_SHIFT 25
#define CHIPC_PCAP5_PC_MASK 0x003e0000 /* PMU corerev >= 5 */
#define CHIPC_PCAP5_PC_SHIFT 17
#define CHIPC_PCAP5_VC_MASK 0x07c00000
#define CHIPC_PCAP5_VC_SHIFT 22
#define CHIPC_PCAP5_CC_MASK 0xf8000000
#define CHIPC_PCAP5_CC_SHIFT 27
/* PMU Resource Request Timer registers */
/* This is based on PmuRev0 */
#define CHIPC_PRRT_TIME_MASK 0x03ff
#define CHIPC_PRRT_INTEN 0x0400
#define CHIPC_PRRT_REQ_ACTIVE 0x0800
#define CHIPC_PRRT_ALP_REQ 0x1000
#define CHIPC_PRRT_HT_REQ 0x2000
/* PMU resource bit position */
#define CHIPC_PMURES_BIT(bit) (1 << (bit))
/* PMU resource number limit */
#define CHIPC_PMURES_MAX_RESNUM 30
/* PMU chip control0 register */
#define CHIPC_PMU_CHIPCTL0 0
/* PMU chip control1 register */
#define CHIPC_PMU_CHIPCTL1 1
#define CHIPC_PMU_CC1_RXC_DLL_BYPASS 0x00010000
#define CHIPC_PMU_CC1_IF_TYPE_MASK 0x00000030
#define CHIPC_PMU_CC1_IF_TYPE_RMII 0x00000000
#define CHIPC_PMU_CC1_IF_TYPE_MII 0x00000010
#define CHIPC_PMU_CC1_IF_TYPE_RGMII 0x00000020
#define CHIPC_PMU_CC1_SW_TYPE_MASK 0x000000c0
#define CHIPC_PMU_CC1_SW_TYPE_EPHY 0x00000000
#define CHIPC_PMU_CC1_SW_TYPE_EPHYMII 0x00000040
#define CHIPC_PMU_CC1_SW_TYPE_EPHYRMII 0x00000080
#define CHIPC_PMU_CC1_SW_TYPE_RGMII 0x000000c0
/* PMU corerev and chip specific PLL controls.
* PMU<rev>_PLL<num>_XX where <rev> is PMU corerev and <num> is an arbitrary number
* to differentiate different PLLs controlled by the same PMU rev.
*/
/* pllcontrol registers */
/* PDIV, div_phy, div_arm, div_adc, dith_sel, ioff, kpd_scale, lsb_sel, mash_sel, lf_c & lf_r */
#define CHIPC_PMU0_PLL0_PLLCTL0 0
#define CHIPC_PMU0_PLL0_PC0_PDIV_MASK 1
#define CHIPC_PMU0_PLL0_PC0_PDIV_FREQ 25000
#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_MASK 0x00000038
#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_SHIFT 3
#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_BASE 8
/* PC0_DIV_ARM for PLLOUT_ARM */
#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_110MHZ 0
#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_97_7MHZ 1
#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_88MHZ 2
#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_80MHZ 3 /* Default */
#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_73_3MHZ 4
#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_67_7MHZ 5
#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_62_9MHZ 6
#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_58_6MHZ 7
/* Wildcard base, stop_mod, en_lf_tp, en_cal & lf_r2 */
#define CHIPC_PMU0_PLL0_PLLCTL1 1
#define CHIPC_PMU0_PLL0_PC1_WILD_INT_MASK 0xf0000000
#define CHIPC_PMU0_PLL0_PC1_WILD_INT_SHIFT 28
#define CHIPC_PMU0_PLL0_PC1_WILD_FRAC_MASK 0x0fffff00
#define CHIPC_PMU0_PLL0_PC1_WILD_FRAC_SHIFT 8
#define CHIPC_PMU0_PLL0_PC1_STOP_MOD 0x00000040
/* Wildcard base, vco_calvar, vco_swc, vco_var_selref, vso_ical & vco_sel_avdd */
#define CHIPC_PMU0_PLL0_PLLCTL2 2
#define CHIPC_PMU0_PLL0_PC2_WILD_INT_MASK 0xf
#define CHIPC_PMU0_PLL0_PC2_WILD_INT_SHIFT 4
/* pllcontrol registers */
/* ndiv_pwrdn, pwrdn_ch<x>, refcomp_pwrdn, dly_ch<x>, p1div, p2div, _bypass_sdmod */
#define CHIPC_PMU1_PLL0_PLLCTL0 0
#define CHIPC_PMU1_PLL0_PC0_P1DIV_MASK 0x00f00000
#define CHIPC_PMU1_PLL0_PC0_P1DIV_SHIFT 20
#define CHIPC_PMU1_PLL0_PC0_P2DIV_MASK 0x0f000000
#define CHIPC_PMU1_PLL0_PC0_P2DIV_SHIFT 24
/* m<x>div */
#define CHIPC_PMU1_PLL0_PLLCTL1 1
#define CHIPC_PMU1_PLL0_PC1_M1DIV_MASK 0x000000ff
#define CHIPC_PMU1_PLL0_PC1_M1DIV_SHIFT 0
#define CHIPC_PMU1_PLL0_PC1_M2DIV_MASK 0x0000ff00
#define CHIPC_PMU1_PLL0_PC1_M2DIV_SHIFT 8
#define CHIPC_PMU1_PLL0_PC1_M3DIV_MASK 0x00ff0000
#define CHIPC_PMU1_PLL0_PC1_M3DIV_SHIFT 16
#define CHIPC_PMU1_PLL0_PC1_M4DIV_MASK 0xff000000
#define CHIPC_PMU1_PLL0_PC1_M4DIV_SHIFT 24
#define CHIPC_DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT 8
#define CHIPC_DOT11MAC_880MHZ_CLK_DIVISOR_MASK (0xFF << DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT)
#define CHIPC_DOT11MAC_880MHZ_CLK_DIVISOR_VAL (0xE << DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT)
/* m<x>div, ndiv_dither_mfb, ndiv_mode, ndiv_int */
#define CHIPC_PMU1_PLL0_PLLCTL2 2
#define CHIPC_PMU1_PLL0_PC2_M5DIV_MASK 0x000000ff
#define CHIPC_PMU1_PLL0_PC2_M5DIV_SHIFT 0
#define CHIPC_PMU1_PLL0_PC2_M6DIV_MASK 0x0000ff00
#define CHIPC_PMU1_PLL0_PC2_M6DIV_SHIFT 8
#define CHIPC_PMU1_PLL0_PC2_NDIV_MODE_MASK 0x000e0000
#define CHIPC_PMU1_PLL0_PC2_NDIV_MODE_SHIFT 17
#define CHIPC_PMU1_PLL0_PC2_NDIV_MODE_MASH 1
#define CHIPC_PMU1_PLL0_PC2_NDIV_MODE_MFB 2 /* recommended for 4319 */
#define CHIPC_PMU1_PLL0_PC2_NDIV_INT_MASK 0x1ff00000
#define CHIPC_PMU1_PLL0_PC2_NDIV_INT_SHIFT 20
/* ndiv_frac */
#define CHIPC_PMU1_PLL0_PLLCTL3 3
#define CHIPC_PMU1_PLL0_PC3_NDIV_FRAC_MASK 0x00ffffff
#define CHIPC_PMU1_PLL0_PC3_NDIV_FRAC_SHIFT 0
/* pll_ctrl */
#define CHIPC_PMU1_PLL0_PLLCTL4 4
/* pll_ctrl, vco_rng, clkdrive_ch<x> */
#define CHIPC_PMU1_PLL0_PLLCTL5 5
#define CHIPC_PMU1_PLL0_PC5_CLK_DRV_MASK 0xffffff00
#define CHIPC_PMU1_PLL0_PC5_CLK_DRV_SHIFT 8
/* PMU rev 2 control words */
#define CHIPC_PMU2_PHY_PLL_PLLCTL 4
#define CHIPC_PMU2_SI_PLL_PLLCTL 10
/* PMU rev 2 */
/* pllcontrol registers */
/* ndiv_pwrdn, pwrdn_ch<x>, refcomp_pwrdn, dly_ch<x>, p1div, p2div, _bypass_sdmod */
#define CHIPC_PMU2_PLL_PLLCTL0 0
#define CHIPC_PMU2_PLL_PC0_P1DIV_MASK 0x00f00000
#define CHIPC_PMU2_PLL_PC0_P1DIV_SHIFT 20
#define CHIPC_PMU2_PLL_PC0_P2DIV_MASK 0x0f000000
#define CHIPC_PMU2_PLL_PC0_P2DIV_SHIFT 24
/* m<x>div */
#define CHIPC_PMU2_PLL_PLLCTL1 1
#define CHIPC_PMU2_PLL_PC1_M1DIV_MASK 0x000000ff
#define CHIPC_PMU2_PLL_PC1_M1DIV_SHIFT 0
#define CHIPC_PMU2_PLL_PC1_M2DIV_MASK 0x0000ff00
#define CHIPC_PMU2_PLL_PC1_M2DIV_SHIFT 8
#define CHIPC_PMU2_PLL_PC1_M3DIV_MASK 0x00ff0000
#define CHIPC_PMU2_PLL_PC1_M3DIV_SHIFT 16
#define CHIPC_PMU2_PLL_PC1_M4DIV_MASK 0xff000000
#define CHIPC_PMU2_PLL_PC1_M4DIV_SHIFT 24
/* m<x>div, ndiv_dither_mfb, ndiv_mode, ndiv_int */
#define CHIPC_PMU2_PLL_PLLCTL2 2
#define CHIPC_PMU2_PLL_PC2_M5DIV_MASK 0x000000ff
#define CHIPC_PMU2_PLL_PC2_M5DIV_SHIFT 0
#define CHIPC_PMU2_PLL_PC2_M6DIV_MASK 0x0000ff00
#define CHIPC_PMU2_PLL_PC2_M6DIV_SHIFT 8
#define CHIPC_PMU2_PLL_PC2_NDIV_MODE_MASK 0x000e0000
#define CHIPC_PMU2_PLL_PC2_NDIV_MODE_SHIFT 17
#define CHIPC_PMU2_PLL_PC2_NDIV_INT_MASK 0x1ff00000
#define CHIPC_PMU2_PLL_PC2_NDIV_INT_SHIFT 20
/* ndiv_frac */
#define CHIPC_PMU2_PLL_PLLCTL3 3
#define CHIPC_PMU2_PLL_PC3_NDIV_FRAC_MASK 0x00ffffff
#define CHIPC_PMU2_PLL_PC3_NDIV_FRAC_SHIFT 0
/* pll_ctrl */
#define CHIPC_PMU2_PLL_PLLCTL4 4
/* pll_ctrl, vco_rng, clkdrive_ch<x> */
#define CHIPC_PMU2_PLL_PLLCTL5 5
#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH1_MASK 0x00000f00
#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH1_SHIFT 8
#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH2_MASK 0x0000f000
#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH2_SHIFT 12
#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH3_MASK 0x000f0000
#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH3_SHIFT 16
#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH4_MASK 0x00f00000
#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH4_SHIFT 20
#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH5_MASK 0x0f000000
#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH5_SHIFT 24
#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH6_MASK 0xf0000000
#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH6_SHIFT 28
/* PMU rev 5 (& 6) */
#define CHIPC_PMU5_PLL_P1P2_OFF 0
#define CHIPC_PMU5_PLL_P1_MASK 0x0f000000
#define CHIPC_PMU5_PLL_P1_SHIFT 24
#define CHIPC_PMU5_PLL_P2_MASK 0x00f00000
#define CHIPC_PMU5_PLL_P2_SHIFT 20
#define CHIPC_PMU5_PLL_M14_OFF 1
#define CHIPC_PMU5_PLL_MDIV_MASK 0x000000ff
#define CHIPC_PMU5_PLL_MDIV_WIDTH 8
#define CHIPC_PMU5_PLL_NM5_OFF 2
#define CHIPC_PMU5_PLL_NDIV_MASK 0xfff00000
#define CHIPC_PMU5_PLL_NDIV_SHIFT 20
#define CHIPC_PMU5_PLL_NDIV_MODE_MASK 0x000e0000
#define CHIPC_PMU5_PLL_NDIV_MODE_SHIFT 17
#define CHIPC_PMU5_PLL_FMAB_OFF 3
#define CHIPC_PMU5_PLL_MRAT_MASK 0xf0000000
#define CHIPC_PMU5_PLL_MRAT_SHIFT 28
#define CHIPC_PMU5_PLL_ABRAT_MASK 0x08000000
#define CHIPC_PMU5_PLL_ABRAT_SHIFT 27
#define CHIPC_PMU5_PLL_FDIV_MASK 0x07ffffff
#define CHIPC_PMU5_PLL_PLLCTL_OFF 4
#define CHIPC_PMU5_PLL_PCHI_OFF 5
#define CHIPC_PMU5_PLL_PCHI_MASK 0x0000003f
/* pmu XtalFreqRatio */
#define CHIPC_PMU_XTALFREQ_REG_ILPCTR_MASK 0x00001FFF
#define CHIPC_PMU_XTALFREQ_REG_MEASURE_MASK 0x80000000
#define CHIPC_PMU_XTALFREQ_REG_MEASURE_SHIFT 31
/* Divider allocation in 4716/47162/5356/5357 */
#define CHIPC_PMU5_MAINPLL_CPU 1
#define CHIPC_PMU5_MAINPLL_MEM 2
#define CHIPC_PMU5_MAINPLL_SI 3
#define CHIPC_PMU7_PLL_PLLCTL7 7
#define CHIPC_PMU7_PLL_PLLCTL8 8
#define CHIPC_PMU7_PLL_PLLCTL11 11
/* PLL usage in 4716/47162 */
#define CHIPC_PMU4716_MAINPLL_PLL0 12
/* PLL usage in 5356/5357 */
#define CHIPC_PMU5356_MAINPLL_PLL0 0
#define CHIPC_PMU5357_MAINPLL_PLL0 0
/* 4716/47162 resources */
#define CHIPC_RES4716_PROC_PLL_ON 0x00000040
#define CHIPC_RES4716_PROC_HT_AVAIL 0x00000080
/* 4716/4717/4718 Chip specific ChipControl register bits */
#define CHIPC_CCTRL471X_I2S_PINS_ENABLE 0x0080 /* I2S pins off by default, shared with pflash */
/* 5354 resources */
#define CHIPC_RES5354_EXT_SWITCHER_PWM 0 /* 0x00001 */
#define CHIPC_RES5354_BB_SWITCHER_PWM 1 /* 0x00002 */
#define CHIPC_RES5354_BB_SWITCHER_BURST 2 /* 0x00004 */
#define CHIPC_RES5354_BB_EXT_SWITCHER_BURST 3 /* 0x00008 */
#define CHIPC_RES5354_ILP_REQUEST 4 /* 0x00010 */
#define CHIPC_RES5354_RADIO_SWITCHER_PWM 5 /* 0x00020 */
#define CHIPC_RES5354_RADIO_SWITCHER_BURST 6 /* 0x00040 */
#define CHIPC_RES5354_ROM_SWITCH 7 /* 0x00080 */
#define CHIPC_RES5354_PA_REF_LDO 8 /* 0x00100 */
#define CHIPC_RES5354_RADIO_LDO 9 /* 0x00200 */
#define CHIPC_RES5354_AFE_LDO 10 /* 0x00400 */
#define CHIPC_RES5354_PLL_LDO 11 /* 0x00800 */
#define CHIPC_RES5354_BG_FILTBYP 12 /* 0x01000 */
#define CHIPC_RES5354_TX_FILTBYP 13 /* 0x02000 */
#define CHIPC_RES5354_RX_FILTBYP 14 /* 0x04000 */
#define CHIPC_RES5354_XTAL_PU 15 /* 0x08000 */
#define CHIPC_RES5354_XTAL_EN 16 /* 0x10000 */
#define CHIPC_RES5354_BB_PLL_FILTBYP 17 /* 0x20000 */
#define CHIPC_RES5354_RF_PLL_FILTBYP 18 /* 0x40000 */
#define CHIPC_RES5354_BB_PLL_PU 19 /* 0x80000 */
/* 5357 Chip specific ChipControl register bits */
#define CHIPC_CCTRL5357_EXTPA (1<<14) /* extPA in ChipControl 1, bit 14 */
#define CHIPC_CCTRL5357_ANT_MUX_2o3 (1<<15) /* 2o3 in ChipControl 1, bit 15 */
/* 4328 resources */
#define CHIPC_RES4328_EXT_SWITCHER_PWM 0 /* 0x00001 */
#define CHIPC_RES4328_BB_SWITCHER_PWM 1 /* 0x00002 */
#define CHIPC_RES4328_BB_SWITCHER_BURST 2 /* 0x00004 */
#define CHIPC_RES4328_BB_EXT_SWITCHER_BURST 3 /* 0x00008 */
#define CHIPC_RES4328_ILP_REQUEST 4 /* 0x00010 */
#define CHIPC_RES4328_RADIO_SWITCHER_PWM 5 /* 0x00020 */
#define CHIPC_RES4328_RADIO_SWITCHER_BURST 6 /* 0x00040 */
#define CHIPC_RES4328_ROM_SWITCH 7 /* 0x00080 */
#define CHIPC_RES4328_PA_REF_LDO 8 /* 0x00100 */
#define CHIPC_RES4328_RADIO_LDO 9 /* 0x00200 */
#define CHIPC_RES4328_AFE_LDO 10 /* 0x00400 */
#define CHIPC_RES4328_PLL_LDO 11 /* 0x00800 */
#define CHIPC_RES4328_BG_FILTBYP 12 /* 0x01000 */
#define CHIPC_RES4328_TX_FILTBYP 13 /* 0x02000 */
#define CHIPC_RES4328_RX_FILTBYP 14 /* 0x04000 */
#define CHIPC_RES4328_XTAL_PU 15 /* 0x08000 */
#define CHIPC_RES4328_XTAL_EN 16 /* 0x10000 */
#define CHIPC_RES4328_BB_PLL_FILTBYP 17 /* 0x20000 */
#define CHIPC_RES4328_RF_PLL_FILTBYP 18 /* 0x40000 */
#define CHIPC_RES4328_BB_PLL_PU 19 /* 0x80000 */
/* 4325 A0/A1 resources */
#define CHIPC_RES4325_BUCK_BOOST_BURST 0 /* 0x00000001 */
#define CHIPC_RES4325_CBUCK_BURST 1 /* 0x00000002 */
#define CHIPC_RES4325_CBUCK_PWM 2 /* 0x00000004 */
#define CHIPC_RES4325_CLDO_CBUCK_BURST 3 /* 0x00000008 */
#define CHIPC_RES4325_CLDO_CBUCK_PWM 4 /* 0x00000010 */
#define CHIPC_RES4325_BUCK_BOOST_PWM 5 /* 0x00000020 */
#define CHIPC_RES4325_ILP_REQUEST 6 /* 0x00000040 */
#define CHIPC_RES4325_ABUCK_BURST 7 /* 0x00000080 */
#define CHIPC_RES4325_ABUCK_PWM 8 /* 0x00000100 */
#define CHIPC_RES4325_LNLDO1_PU 9 /* 0x00000200 */
#define CHIPC_RES4325_OTP_PU 10 /* 0x00000400 */
#define CHIPC_RES4325_LNLDO3_PU 11 /* 0x00000800 */
#define CHIPC_RES4325_LNLDO4_PU 12 /* 0x00001000 */
#define CHIPC_RES4325_XTAL_PU 13 /* 0x00002000 */
#define CHIPC_RES4325_ALP_AVAIL 14 /* 0x00004000 */
#define CHIPC_RES4325_RX_PWRSW_PU 15 /* 0x00008000 */
#define CHIPC_RES4325_TX_PWRSW_PU 16 /* 0x00010000 */
#define CHIPC_RES4325_RFPLL_PWRSW_PU 17 /* 0x00020000 */
#define CHIPC_RES4325_LOGEN_PWRSW_PU 18 /* 0x00040000 */
#define CHIPC_RES4325_AFE_PWRSW_PU 19 /* 0x00080000 */
#define CHIPC_RES4325_BBPLL_PWRSW_PU 20 /* 0x00100000 */
#define CHIPC_RES4325_HT_AVAIL 21 /* 0x00200000 */
/* 4325 B0/C0 resources */
#define CHIPC_RES4325B0_CBUCK_LPOM 1 /* 0x00000002 */
#define CHIPC_RES4325B0_CBUCK_BURST 2 /* 0x00000004 */
#define CHIPC_RES4325B0_CBUCK_PWM 3 /* 0x00000008 */
#define CHIPC_RES4325B0_CLDO_PU 4 /* 0x00000010 */
/* 4325 C1 resources */
#define CHIPC_RES4325C1_LNLDO2_PU 12 /* 0x00001000 */
/* 4325 chip-specific ChipStatus register bits */
#define CHIPC_CST4325_SPROM_OTP_SEL_MASK CHIPC_CST_SPROM_OTP_SEL_R22_MASK
#define CHIPC_CST4325_SPROM_OTP_SEL_SHIFT CHIPC_CST_SPROM_OTP_SEL_R22_SHIFT
@ -1129,29 +771,6 @@ enum {
#define CHIPC_CST4325_PMUTOP_2B_MASK 0x00000200 /* 1 for 2b, 0 for to 2a */
#define CHIPC_CST4325_PMUTOP_2B_SHIFT 9
#define CHIPC_RES4329_RESERVED0 0 /* 0x00000001 */
#define CHIPC_RES4329_CBUCK_LPOM 1 /* 0x00000002 */
#define CHIPC_RES4329_CBUCK_BURST 2 /* 0x00000004 */
#define CHIPC_RES4329_CBUCK_PWM 3 /* 0x00000008 */
#define CHIPC_RES4329_CLDO_PU 4 /* 0x00000010 */
#define CHIPC_RES4329_PALDO_PU 5 /* 0x00000020 */
#define CHIPC_RES4329_ILP_REQUEST 6 /* 0x00000040 */
#define CHIPC_RES4329_RESERVED7 7 /* 0x00000080 */
#define CHIPC_RES4329_RESERVED8 8 /* 0x00000100 */
#define CHIPC_RES4329_LNLDO1_PU 9 /* 0x00000200 */
#define CHIPC_RES4329_OTP_PU 10 /* 0x00000400 */
#define CHIPC_RES4329_RESERVED11 11 /* 0x00000800 */
#define CHIPC_RES4329_LNLDO2_PU 12 /* 0x00001000 */
#define CHIPC_RES4329_XTAL_PU 13 /* 0x00002000 */
#define CHIPC_RES4329_ALP_AVAIL 14 /* 0x00004000 */
#define CHIPC_RES4329_RX_PWRSW_PU 15 /* 0x00008000 */
#define CHIPC_RES4329_TX_PWRSW_PU 16 /* 0x00010000 */
#define CHIPC_RES4329_RFPLL_PWRSW_PU 17 /* 0x00020000 */
#define CHIPC_RES4329_LOGEN_PWRSW_PU 18 /* 0x00040000 */
#define CHIPC_RES4329_AFE_PWRSW_PU 19 /* 0x00080000 */
#define CHIPC_RES4329_BBPLL_PWRSW_PU 20 /* 0x00100000 */
#define CHIPC_RES4329_HT_AVAIL 21 /* 0x00200000 */
/* 4329 chip-specific ChipStatus register bits */
#define CHIPC_CST4329_SPROM_OTP_SEL_MASK CHIPC_CST_SPROM_OTP_SEL_R22_MASK
#define CHIPC_CST4329_SPROM_OTP_SEL_SHIFT CHIPC_CST_SPROM_OTP_SEL_R22_SHIFT
@ -1162,33 +781,6 @@ enum {
#define CHIPC_CST4312_SPROM_OTP_SEL_MASK CHIPC_CST_SPROM_OTP_SEL_R22_MASK
#define CHIPC_CST4312_SPROM_OTP_SEL_SHIFT CHIPC_CST_SPROM_OTP_SEL_R22_SHIFT
/* 4312 resources (all PMU chips with little memory constraint) */
#define CHIPC_RES4312_SWITCHER_BURST 0 /* 0x00000001 */
#define CHIPC_RES4312_SWITCHER_PWM 1 /* 0x00000002 */
#define CHIPC_RES4312_PA_REF_LDO 2 /* 0x00000004 */
#define CHIPC_RES4312_CORE_LDO_BURST 3 /* 0x00000008 */
#define CHIPC_RES4312_CORE_LDO_PWM 4 /* 0x00000010 */
#define CHIPC_RES4312_RADIO_LDO 5 /* 0x00000020 */
#define CHIPC_RES4312_ILP_REQUEST 6 /* 0x00000040 */
#define CHIPC_RES4312_BG_FILTBYP 7 /* 0x00000080 */
#define CHIPC_RES4312_TX_FILTBYP 8 /* 0x00000100 */
#define CHIPC_RES4312_RX_FILTBYP 9 /* 0x00000200 */
#define CHIPC_RES4312_XTAL_PU 10 /* 0x00000400 */
#define CHIPC_RES4312_ALP_AVAIL 11 /* 0x00000800 */
#define CHIPC_RES4312_BB_PLL_FILTBYP 12 /* 0x00001000 */
#define CHIPC_RES4312_RF_PLL_FILTBYP 13 /* 0x00002000 */
#define CHIPC_RES4312_HT_AVAIL 14 /* 0x00004000 */
/* 4322 resources */
#define CHIPC_RES4322_RF_LDO 0
#define CHIPC_RES4322_ILP_REQUEST 1
#define CHIPC_RES4322_XTAL_PU 2
#define CHIPC_RES4322_ALP_AVAIL 3
#define CHIPC_RES4322_SI_PLL_ON 4
#define CHIPC_RES4322_HT_SI_AVAIL 5
#define CHIPC_RES4322_PHY_PLL_ON 6
#define CHIPC_RES4322_HT_PHY_AVAIL 7
#define CHIPC_RES4322_OTP_PU 8
/* 4322 chip-specific ChipStatus register bits */
#define CHIPC_CST4322_XTAL_FREQ_20_40MHZ 0x00000020
@ -1217,26 +809,6 @@ enum {
#define CHIPC_CST4322_CLK_SWITCH_PCI_TO_ALP 0x00020000
#define CHIPC_CST4322_PCI_CARDBUS_MODE 0x00040000
/* 43224 chip-specific ChipControl register bits */
#define CHIPC_CCTRL43224_GPIO_TOGGLE 0x8000
#define CHIPC_CCTRL_43224A0_12MA_LED_DRIVE 0x00F000F0 /* 12 mA drive strength */
#define CHIPC_CCTRL_43224B0_12MA_LED_DRIVE 0xF0 /* 12 mA drive strength for later 43224s */
/* 43236 resources */
#define CHIPC_RES43236_REGULATOR 0
#define CHIPC_RES43236_ILP_REQUEST 1
#define CHIPC_RES43236_XTAL_PU 2
#define CHIPC_RES43236_ALP_AVAIL 3
#define CHIPC_RES43236_SI_PLL_ON 4
#define CHIPC_RES43236_HT_SI_AVAIL 5
/* 43236 chip-specific ChipControl register bits */
#define CHIPC_CCTRL43236_BT_COEXIST (1<<0) /* 0 disable */
#define CHIPC_CCTRL43236_SECI (1<<1) /* 0 SECI is disabled (JATG functional) */
#define CHIPC_CCTRL43236_EXT_LNA (1<<2) /* 0 disable */
#define CHIPC_CCTRL43236_ANT_MUX_2o3 (1<<3) /* 2o3 mux, chipcontrol bit 3 */
#define CHIPC_CCTRL43236_GSIO (1<<4) /* 0 disable */
/* 43236 Chip specific ChipStatus register bits */
#define CHIPC_CST43236_SFLASH_MASK 0x00000040
#define CHIPC_CST43236_OTP_SEL_MASK 0x00000080
@ -1250,15 +822,17 @@ enum {
#define CHIPC_CST43236_BOOT_FROM_FLASH 2 /* boot from FLASH */
#define CHIPC_CST43236_BOOT_FROM_INVALID 3
/* 4331 resources */
#define CHIPC_RES4331_REGULATOR 0
#define CHIPC_RES4331_ILP_REQUEST 1
#define CHIPC_RES4331_XTAL_PU 2
#define CHIPC_RES4331_ALP_AVAIL 3
#define CHIPC_RES4331_SI_PLL_ON 4
#define CHIPC_RES4331_HT_SI_AVAIL 5
/* 43237 Chip specific ChipStatus register bits */
#define CHIPC_CST43237_BP_CLK 0x00000200 /* 96/80Mbps */
/* 4331 chip-specific ChipControl register bits */
/* 4331 Chip specific ChipStatus register bits */
#define CHIPC_CST4331_XTAL_FREQ 0x00000001 /* crystal frequency 20/40Mhz */
#define CHIPC_CST4331_SPROM_PRESENT 0x00000002
#define CHIPC_CST4331_OTP_PRESENT 0x00000004
#define CHIPC_CST4331_LDO_RF 0x00000008
#define CHIPC_CST4331_LDO_PAR 0x00000010
/* 4331 chip-specific CHIPCTRL register bits */
#define CHIPC_CCTRL4331_BT_COEXIST (1<<0) /* 0 disable */
#define CHIPC_CCTRL4331_SECI (1<<1) /* 0 SECI is disabled (JATG functional) */
#define CHIPC_CCTRL4331_EXT_LNA (1<<2) /* 0 disable */
@ -1275,33 +849,6 @@ enum {
#define CHIPC_CCTRL4331_BT_SHD0_ON_GPIO4 (1<<16) /* enable bt_shd0 at gpio4 */
#define CHIPC_CCTRL4331_BT_SHD1_ON_GPIO5 (1<<17) /* enable bt_shd1 at gpio5 */
/* 4331 Chip specific ChipStatus register bits */
#define CHIPC_CST4331_XTAL_FREQ 0x00000001 /* crystal frequency 20/40Mhz */
#define CHIPC_CST4331_SPROM_PRESENT 0x00000002
#define CHIPC_CST4331_OTP_PRESENT 0x00000004
#define CHIPC_CST4331_LDO_RF 0x00000008
#define CHIPC_CST4331_LDO_PAR 0x00000010
/* 4315 resources */
#define CHIPC_RES4315_CBUCK_LPOM 1 /* 0x00000002 */
#define CHIPC_RES4315_CBUCK_BURST 2 /* 0x00000004 */
#define CHIPC_RES4315_CBUCK_PWM 3 /* 0x00000008 */
#define CHIPC_RES4315_CLDO_PU 4 /* 0x00000010 */
#define CHIPC_RES4315_PALDO_PU 5 /* 0x00000020 */
#define CHIPC_RES4315_ILP_REQUEST 6 /* 0x00000040 */
#define CHIPC_RES4315_LNLDO1_PU 9 /* 0x00000200 */
#define CHIPC_RES4315_OTP_PU 10 /* 0x00000400 */
#define CHIPC_RES4315_LNLDO2_PU 12 /* 0x00001000 */
#define CHIPC_RES4315_XTAL_PU 13 /* 0x00002000 */
#define CHIPC_RES4315_ALP_AVAIL 14 /* 0x00004000 */
#define CHIPC_RES4315_RX_PWRSW_PU 15 /* 0x00008000 */
#define CHIPC_RES4315_TX_PWRSW_PU 16 /* 0x00010000 */
#define CHIPC_RES4315_RFPLL_PWRSW_PU 17 /* 0x00020000 */
#define CHIPC_RES4315_LOGEN_PWRSW_PU 18 /* 0x00040000 */
#define CHIPC_RES4315_AFE_PWRSW_PU 19 /* 0x00080000 */
#define CHIPC_RES4315_BBPLL_PWRSW_PU 20 /* 0x00100000 */
#define CHIPC_RES4315_HT_AVAIL 21 /* 0x00200000 */
/* 4315 chip-specific ChipStatus register bits */
#define CHIPC_CST4315_SPROM_OTP_SEL_MASK CHIPC_CST_SPROM_OTP_SEL_R22_MASK
#define CHIPC_CST4315_SPROM_OTP_SEL_SHIFT CHIPC_CST_SPROM_OTP_SEL_R22_SHIFT
@ -1314,26 +861,6 @@ enum {
#define CHIPC_CST4315_CBUCK_MODE_BURST 0x00000400
#define CHIPC_CST4315_CBUCK_MODE_LPBURST 0x00000c00
/* 4319 resources */
#define CHIPC_RES4319_CBUCK_LPOM 1 /* 0x00000002 */
#define CHIPC_RES4319_CBUCK_BURST 2 /* 0x00000004 */
#define CHIPC_RES4319_CBUCK_PWM 3 /* 0x00000008 */
#define CHIPC_RES4319_CLDO_PU 4 /* 0x00000010 */
#define CHIPC_RES4319_PALDO_PU 5 /* 0x00000020 */
#define CHIPC_RES4319_ILP_REQUEST 6 /* 0x00000040 */
#define CHIPC_RES4319_LNLDO1_PU 9 /* 0x00000200 */
#define CHIPC_RES4319_OTP_PU 10 /* 0x00000400 */
#define CHIPC_RES4319_LNLDO2_PU 12 /* 0x00001000 */
#define CHIPC_RES4319_XTAL_PU 13 /* 0x00002000 */
#define CHIPC_RES4319_ALP_AVAIL 14 /* 0x00004000 */
#define CHIPC_RES4319_RX_PWRSW_PU 15 /* 0x00008000 */
#define CHIPC_RES4319_TX_PWRSW_PU 16 /* 0x00010000 */
#define CHIPC_RES4319_RFPLL_PWRSW_PU 17 /* 0x00020000 */
#define CHIPC_RES4319_LOGEN_PWRSW_PU 18 /* 0x00040000 */
#define CHIPC_RES4319_AFE_PWRSW_PU 19 /* 0x00080000 */
#define CHIPC_RES4319_BBPLL_PWRSW_PU 20 /* 0x00100000 */
#define CHIPC_RES4319_HT_AVAIL 21 /* 0x00200000 */
/* 4319 chip-specific ChipStatus register bits */
#define CHIPC_CST4319_SPI_CPULESSUSB 0x00000001
#define CHIPC_CST4319_SPI_CLK_POL 0x00000002
@ -1354,42 +881,6 @@ enum {
#define CHIPC_CST4319_RCAL_VALUE_MASK 0x3e000000
#define CHIPC_CST4319_RCAL_VALUE_SHIFT 25
#define CHIPC_PMU1_PLL0_CHIPCTL0 0
#define CHIPC_PMU1_PLL0_CHIPCTL1 1
#define CHIPC_PMU1_PLL0_CHIPCTL2 2
#define CHIPC_CCTL_4319USB_XTAL_SEL_MASK 0x00180000
#define CHIPC_CCTL_4319USB_XTAL_SEL_SHIFT 19
#define CHIPC_CCTL_4319USB_48MHZ_PLL_SEL 1
#define CHIPC_CCTL_4319USB_24MHZ_PLL_SEL 2
/* PMU resources for 4336 */
#define CHIPC_RES4336_CBUCK_LPOM 0
#define CHIPC_RES4336_CBUCK_BURST 1
#define CHIPC_RES4336_CBUCK_LP_PWM 2
#define CHIPC_RES4336_CBUCK_PWM 3
#define CHIPC_RES4336_CLDO_PU 4
#define CHIPC_RES4336_DIS_INT_RESET_PD 5
#define CHIPC_RES4336_ILP_REQUEST 6
#define CHIPC_RES4336_LNLDO_PU 7
#define CHIPC_RES4336_LDO3P3_PU 8
#define CHIPC_RES4336_OTP_PU 9
#define CHIPC_RES4336_XTAL_PU 10
#define CHIPC_RES4336_ALP_AVAIL 11
#define CHIPC_RES4336_RADIO_PU 12
#define CHIPC_RES4336_BG_PU 13
#define CHIPC_RES4336_VREG1p4_PU_PU 14
#define CHIPC_RES4336_AFE_PWRSW_PU 15
#define CHIPC_RES4336_RX_PWRSW_PU 16
#define CHIPC_RES4336_TX_PWRSW_PU 17
#define CHIPC_RES4336_BB_PWRSW_PU 18
#define CHIPC_RES4336_SYNTH_PWRSW_PU 19
#define CHIPC_RES4336_MISC_PWRSW_PU 20
#define CHIPC_RES4336_LOGEN_PWRSW_PU 21
#define CHIPC_RES4336_BBPLL_PWRSW_PU 22
#define CHIPC_RES4336_MACPHY_CLKAVAIL 23
#define CHIPC_RES4336_HT_AVAIL 24
#define CHIPC_RES4336_RSVD 25
/* 4336 chip-specific ChipStatus register bits */
#define CHIPC_CST4336_SPI_MODE_MASK 0x00000001
#define CHIPC_CST4336_SPROM_PRESENT 0x00000002
@ -1406,36 +897,6 @@ enum {
#define CHIPC_CST4336_CBUCK_MODE_MASK 0x00000600
#define CHIPC_CST4336_CBUCK_MODE_SHIFT 9
/* 4330 resources */
#define CHIPC_RES4330_CBUCK_LPOM 0
#define CHIPC_RES4330_CBUCK_BURST 1
#define CHIPC_RES4330_CBUCK_LP_PWM 2
#define CHIPC_RES4330_CBUCK_PWM 3
#define CHIPC_RES4330_CLDO_PU 4
#define CHIPC_RES4330_DIS_INT_RESET_PD 5
#define CHIPC_RES4330_ILP_REQUEST 6
#define CHIPC_RES4330_LNLDO_PU 7
#define CHIPC_RES4330_LDO3P3_PU 8
#define CHIPC_RES4330_OTP_PU 9
#define CHIPC_RES4330_XTAL_PU 10
#define CHIPC_RES4330_ALP_AVAIL 11
#define CHIPC_RES4330_RADIO_PU 12
#define CHIPC_RES4330_BG_PU 13
#define CHIPC_RES4330_VREG1p4_PU_PU 14
#define CHIPC_RES4330_AFE_PWRSW_PU 15
#define CHIPC_RES4330_RX_PWRSW_PU 16
#define CHIPC_RES4330_TX_PWRSW_PU 17
#define CHIPC_RES4330_BB_PWRSW_PU 18
#define CHIPC_RES4330_SYNTH_PWRSW_PU 19
#define CHIPC_RES4330_MISC_PWRSW_PU 20
#define CHIPC_RES4330_LOGEN_PWRSW_PU 21
#define CHIPC_RES4330_BBPLL_PWRSW_PU 22
#define CHIPC_RES4330_MACPHY_CLKAVAIL 23
#define CHIPC_RES4330_HT_AVAIL 24
#define CHIPC_RES4330_5gRX_PWRSW_PU 25
#define CHIPC_RES4330_5gTX_PWRSW_PU 26
#define CHIPC_RES4330_5g_LOGEN_PWRSW_PU 27
/* 4330 chip-specific ChipStatus register bits */
#define CHIPC_CST4330_CHIPMODE_SDIOD(cs) (((cs) & 0x7) < 6) /* SDIO || gSPI */
#define CHIPC_CST4330_CHIPMODE_USB20D(cs) (((cs) & 0x7) >= 6) /* USB || USBDA */
@ -1458,41 +919,12 @@ enum {
#define CHIPC_SOCDEVRAM_4330_BP_ADDR 0x1E000000
#define CHIPC_SOCDEVRAM_4330_ARM_ADDR 0x00800000
/* 4313 resources */
#define CHIPC_RES4313_BB_PU_RSRC 0
#define CHIPC_RES4313_ILP_REQ_RSRC 1
#define CHIPC_RES4313_XTAL_PU_RSRC 2
#define CHIPC_RES4313_ALP_AVAIL_RSRC 3
#define CHIPC_RES4313_RADIO_PU_RSRC 4
#define CHIPC_RES4313_BG_PU_RSRC 5
#define CHIPC_RES4313_VREG1P4_PU_RSRC 6
#define CHIPC_RES4313_AFE_PWRSW_RSRC 7
#define CHIPC_RES4313_RX_PWRSW_RSRC 8
#define CHIPC_RES4313_TX_PWRSW_RSRC 9
#define CHIPC_RES4313_BB_PWRSW_RSRC 10
#define CHIPC_RES4313_SYNTH_PWRSW_RSRC 11
#define CHIPC_RES4313_MISC_PWRSW_RSRC 12
#define CHIPC_RES4313_BB_PLL_PWRSW_RSRC 13
#define CHIPC_RES4313_HT_AVAIL_RSRC 14
#define CHIPC_RES4313_MACPHY_CLK_AVAIL_RSRC 15
/* 4313 chip-specific ChipStatus register bits */
#define CHIPC_CST4313_SPROM_PRESENT 1
#define CHIPC_CST4313_OTP_PRESENT 2
#define CHIPC_CST4313_SPROM_OTP_SEL_MASK 0x00000002
#define CHIPC_CST4313_SPROM_OTP_SEL_SHIFT 0
/* 4313 Chip specific ChipControl register bits */
#define CHIPC_CCTRL_4313_12MA_LED_DRIVE 0x00000007 /* 12 mA drive strengh for later 4313 */
/* 43228 resources */
#define CHIPC_RES43228_NOT_USED 0
#define CHIPC_RES43228_ILP_REQUEST 1
#define CHIPC_RES43228_XTAL_PU 2
#define CHIPC_RES43228_ALP_AVAIL 3
#define CHIPC_RES43228_PLL_EN 4
#define CHIPC_RES43228_HT_PHY_AVAIL 5
/* 43228 chipstatus reg bits */
#define CHIPC_CST43228_ILP_DIV_EN 0x1
#define CHIPC_CST43228_OTP_PRESENT 0x2
@ -1502,15 +934,6 @@ enum {
#define CHIPC_CST43228_SDIO_OTP_PRESENT 0x10
#define CHIPC_CST43228_SDIO_RESET 0x20
/*
* Maximum delay for the PMU state transition in us.
* This is an upper bound intended for spinwaits etc.
*/
#define CHIPC_PMU_MAX_TRANSITION_DLY 15000
/* PMU resource up transition time in ILP cycles */
#define CHIPC_PMURES_UP_TRANSITION 2
/*
* Register eci_inputlo bitfield values.
* - BT packet type information bits [7:0]

View File

@ -39,71 +39,15 @@
#include "chipc.h"
DECLARE_CLASS(bhnd_chipc);
DECLARE_CLASS(bhnd_chipc_driver);
extern devclass_t bhnd_chipc_devclass;
struct chipc_region;
/**
* Supported ChipCommon flash types.
*/
typedef enum {
CHIPC_FLASH_NONE = 0, /**< No flash, or a type unrecognized
by the ChipCommon driver */
CHIPC_PFLASH_CFI = 1, /**< CFI-compatible parallel flash */
CHIPC_SFLASH_ST = 2, /**< ST serial flash */
CHIPC_SFLASH_AT = 3, /**< Atmel serial flash */
CHIPC_QSFLASH_ST = 4, /**< ST quad-SPI flash */
CHIPC_QSFLASH_AT = 5, /**< Atmel quad-SPI flash */
CHIPC_NFLASH = 6, /**< NAND flash */
CHIPC_NFLASH_4706 = 7 /**< BCM4706 NAND flash */
} chipc_flash;
const char *chipc_flash_name(chipc_flash type);
const char *chipc_flash_bus_name(chipc_flash type);
const char *chipc_sflash_device_name(chipc_flash type);
/**
* ChipCommon capability flags;
*/
struct chipc_caps {
uint8_t num_uarts; /**< Number of attached UARTS (1-3) */
bool mipseb; /**< MIPS is big-endian */
uint8_t uart_clock; /**< UART clock source (see CHIPC_CAP_UCLKSEL_*) */
uint8_t uart_gpio; /**< UARTs own GPIO pins 12-15 */
uint8_t extbus_type; /**< ExtBus type (CHIPC_CAP_EXTBUS_*) */
chipc_flash flash_type; /**< flash type */
uint8_t cfi_width; /**< CFI bus width, 0 if unknown or CFI
not present */
bhnd_nvram_src nvram_src; /**< identified NVRAM source */
bus_size_t sprom_offset; /**< Offset to SPROM data within
SPROM/OTP, 0 if unknown or not
present */
uint8_t otp_size; /**< OTP (row?) size, 0 if not present */
uint8_t pll_type; /**< PLL type */
bool power_control; /**< Power control available */
bool jtag_master; /**< JTAG Master present */
bool boot_rom; /**< Internal boot ROM is active */
uint8_t backplane_64; /**< Backplane supports 64-bit addressing.
Note that this does not gaurantee
the CPU itself supports 64-bit
addressing. */
bool pmu; /**< PMU is present. */
bool eci; /**< ECI (enhanced coexistence inteface) is present. */
bool seci; /**< SECI (serial ECI) is present */
bool sprom; /**< SPROM is present */
bool gsio; /**< GSIO (SPI/I2C) present */
bool aob; /**< AOB (always on bus) present.
If set, PMU and GCI registers are
not accessible via ChipCommon,
and are instead accessible via
dedicated cores on the bhnd bus */
};
/*
* ChipCommon device quirks / features
*/

View File

@ -0,0 +1,479 @@
/*-
* Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
* Copyright (c) 2010, Broadcom Corporation.
* All rights reserved.
*
* This file is derived from the siutils.c source distributed with the
* Asus RT-N16 firmware source code release.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: siutils.c,v 1.821.2.48 2011-02-11 20:59:28 Exp $
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/limits.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/systm.h>
#include <dev/bhnd/bhnd.h>
#include <dev/bhnd/cores/chipc/chipcreg.h>
#include <dev/bhnd/cores/chipc/chipcvar.h>
#include <dev/bhnd/cores/pmu/bhnd_pmuvar.h>
#include <dev/bhnd/cores/pmu/bhnd_pmureg.h>
#include "bhnd_chipc_if.h"
#include "bhnd_pwrctl_private.h"
/*
* ChipCommon Power Control.
*
* Provides a bhnd_pmu_if-compatible interface to device clocking and
* power management on non-PMU chipsets.
*/
typedef enum {
BHND_PWRCTL_WAR_UP, /**< apply attach/resume workarounds */
BHND_PWRCTL_WAR_RUN, /**< apply running workarounds */
BHND_PWRCTL_WAR_DOWN, /**< apply detach/suspend workarounds */
} bhnd_pwrctl_wars;
static int bhnd_pwrctl_updateclk(struct bhnd_pwrctl_softc *sc,
bhnd_pwrctl_wars wars);
static struct bhnd_device_quirk pwrctl_quirks[];
/* Supported parent core device identifiers */
static const struct bhnd_device pwrctl_devices[] = {
BHND_DEVICE(BCM, CC, "ChipCommon Power Control", pwrctl_quirks),
BHND_DEVICE_END
};
/* Device quirks table */
static struct bhnd_device_quirk pwrctl_quirks[] = {
BHND_CORE_QUIRK (HWREV_LTE(5), PWRCTL_QUIRK_PCICLK_CTL),
BHND_CORE_QUIRK (HWREV_RANGE(6, 9), PWRCTL_QUIRK_SLOWCLK_CTL),
BHND_CORE_QUIRK (HWREV_RANGE(10, 19), PWRCTL_QUIRK_INSTACLK_CTL),
BHND_DEVICE_QUIRK_END
};
static int
bhnd_pwrctl_probe(device_t dev)
{
const struct bhnd_device *id;
struct chipc_caps *ccaps;
device_t chipc;
/* Look for compatible chipc parent */
chipc = device_get_parent(dev);
if (device_get_devclass(chipc) != devclass_find("bhnd_chipc"))
return (ENXIO);
if (device_get_driver(chipc) != &bhnd_chipc_driver)
return (ENXIO);
/* Verify chipc capability flags */
ccaps = BHND_CHIPC_GET_CAPS(chipc);
if (ccaps->pmu || !ccaps->pwr_ctrl)
return (ENXIO);
/* Check for chipc device match */
id = bhnd_device_lookup(chipc, pwrctl_devices,
sizeof(pwrctl_devices[0]));
if (id == NULL)
return (ENXIO);
device_set_desc(dev, id->desc);
return (BUS_PROBE_NOWILDCARD);
}
static int
bhnd_pwrctl_attach(device_t dev)
{
struct bhnd_pwrctl_softc *sc;
const struct bhnd_chipid *cid;
struct chipc_softc *chipc_sc;
bhnd_devclass_t hostb_class;
device_t hostb_dev;
int error;
sc = device_get_softc(dev);
/* TODO: Need further testing on actual PWRCTL hardware */
device_printf(dev, "WARNING: Using untested PWRCTL support\n");
sc->dev = dev;
sc->chipc_dev = device_get_parent(dev);
sc->quirks = bhnd_device_quirks(sc->chipc_dev, pwrctl_devices,
sizeof(pwrctl_devices[0]));
/* On devices that lack a slow clock source, HT must always be
* enabled. */
hostb_class = BHND_DEVCLASS_INVALID;
hostb_dev = bhnd_find_hostb_device(device_get_parent(sc->chipc_dev));
if (hostb_dev != NULL)
hostb_class = bhnd_get_class(hostb_dev);
cid = bhnd_get_chipid(sc->chipc_dev);
switch (cid->chip_id) {
case BHND_CHIPID_BCM4311:
if (cid->chip_rev <= 1 && hostb_class == BHND_DEVCLASS_PCI)
sc->quirks |= PWRCTL_QUIRK_FORCE_HT;
break;
case BHND_CHIPID_BCM4321:
if (hostb_class == BHND_DEVCLASS_PCIE ||
hostb_class == BHND_DEVCLASS_PCI)
sc->quirks |= PWRCTL_QUIRK_FORCE_HT;
break;
case BHND_CHIPID_BCM4716:
if (hostb_class == BHND_DEVCLASS_PCIE)
sc->quirks |= PWRCTL_QUIRK_FORCE_HT;
break;
}
/* Fetch core register block from ChipCommon parent */
chipc_sc = device_get_softc(sc->chipc_dev);
sc->res = chipc_sc->core;
PWRCTL_LOCK_INIT(sc);
STAILQ_INIT(&sc->clkres_list);
/* Initialize power control */
PWRCTL_LOCK(sc);
if ((error = bhnd_pwrctl_init(sc))) {
PWRCTL_UNLOCK(sc);
goto cleanup;
}
/* Apply default clock transitions */
if ((error = bhnd_pwrctl_updateclk(sc, BHND_PWRCTL_WAR_UP))) {
PWRCTL_UNLOCK(sc);
goto cleanup;
}
PWRCTL_UNLOCK(sc);
return (0);
cleanup:
PWRCTL_LOCK_DESTROY(sc);
return (error);
}
static int
bhnd_pwrctl_detach(device_t dev)
{
struct bhnd_pwrctl_softc *sc;
struct bhnd_pwrctl_clkres *clkres, *crnext;
int error;
sc = device_get_softc(dev);
if ((error = bhnd_pwrctl_setclk(sc, BHND_CLOCK_DYN)))
return (error);
STAILQ_FOREACH_SAFE(clkres, &sc->clkres_list, cr_link, crnext)
free(clkres, M_DEVBUF);
PWRCTL_LOCK_DESTROY(sc);
return (0);
}
static int
bhnd_pwrctl_suspend(device_t dev)
{
struct bhnd_pwrctl_softc *sc;
int error;
sc = device_get_softc(dev);
/* Update clock state */
PWRCTL_LOCK(sc);
error = bhnd_pwrctl_updateclk(sc, BHND_PWRCTL_WAR_DOWN);
PWRCTL_UNLOCK(sc);
return (error);
}
static int
bhnd_pwrctl_resume(device_t dev)
{
struct bhnd_pwrctl_softc *sc;
int error;
sc = device_get_softc(dev);
PWRCTL_LOCK(sc);
/* Re-initialize power control registers */
if ((error = bhnd_pwrctl_init(sc))) {
device_printf(sc->dev, "PWRCTL init failed: %d\n", error);
goto cleanup;
}
/* Restore clock state */
if ((error = bhnd_pwrctl_updateclk(sc, BHND_PWRCTL_WAR_UP))) {
device_printf(sc->dev, "clock state restore failed: %d\n",
error);
goto cleanup;
}
cleanup:
PWRCTL_UNLOCK(sc);
return (error);
}
/**
* Find the clock reservation associated with @p pinfo, if any.
*
* @param sc Driver instance state.
* @param pinfo PMU info for device.
*/
static struct bhnd_pwrctl_clkres *
bhnd_pwrctl_find_res(struct bhnd_pwrctl_softc *sc,
struct bhnd_core_pmu_info *pinfo)
{
struct bhnd_pwrctl_clkres *clkres;
PWRCTL_LOCK_ASSERT(sc, MA_OWNED);
STAILQ_FOREACH(clkres, &sc->clkres_list, cr_link) {
if (clkres->owner == pinfo->pm_dev)
return (clkres);
}
/* not found */
return (NULL);
}
/**
* Enumerate all active clock requests, compute the minimum required clock,
* and issue any required clock transition.
*
* @param sc Driver instance state.
* @param wars Work-around state.
*/
static int
bhnd_pwrctl_updateclk(struct bhnd_pwrctl_softc *sc, bhnd_pwrctl_wars wars)
{
struct bhnd_pwrctl_clkres *clkres;
bhnd_clock clock;
PWRCTL_LOCK_ASSERT(sc, MA_OWNED);
/* Default clock target */
clock = BHND_CLOCK_DYN;
/* Apply quirk-specific overrides to the clock target */
switch (wars) {
case BHND_PWRCTL_WAR_UP:
/* Force HT clock */
if (PWRCTL_QUIRK(sc, FORCE_HT))
clock = BHND_CLOCK_HT;
break;
case BHND_PWRCTL_WAR_RUN:
/* Cannot transition clock if FORCE_HT */
if (PWRCTL_QUIRK(sc, FORCE_HT))
return (0);
break;
case BHND_PWRCTL_WAR_DOWN:
/* Leave default clock unmodified to permit
* transition back to BHND_CLOCK_DYN on FORCE_HT devices. */
break;
}
/* Determine required clock */
STAILQ_FOREACH(clkres, &sc->clkres_list, cr_link)
clock = bhnd_clock_max(clock, clkres->clock);
/* Map to supported clock setting */
switch (clock) {
case BHND_CLOCK_DYN:
case BHND_CLOCK_ILP:
clock = BHND_CLOCK_DYN;
break;
case BHND_CLOCK_ALP:
/* In theory FORCE_ALP is supported by the hardware, but
* there are currently no known use-cases for it; mapping
* to HT is still valid, and allows us to punt on determing
* where FORCE_ALP is supported and functional */
clock = BHND_CLOCK_HT;
break;
case BHND_CLOCK_HT:
break;
default:
device_printf(sc->dev, "unknown clock: %#x\n", clock);
return (ENODEV);
}
/* Issue transition */
return (bhnd_pwrctl_setclk(sc, clock));
}
static int
bhnd_pwrctl_core_req_clock(device_t dev, struct bhnd_core_pmu_info *pinfo,
bhnd_clock clock)
{
struct bhnd_pwrctl_softc *sc;
struct bhnd_pwrctl_clkres *clkres;
int error;
sc = device_get_softc(dev);
error = 0;
PWRCTL_LOCK(sc);
clkres = bhnd_pwrctl_find_res(sc, pinfo);
/* BHND_CLOCK_DYN discards the clock reservation entirely */
if (clock == BHND_CLOCK_DYN) {
/* nothing to clean up? */
if (clkres == NULL) {
PWRCTL_UNLOCK(sc);
return (0);
}
/* drop reservation and apply clock transition */
STAILQ_REMOVE(&sc->clkres_list, clkres,
bhnd_pwrctl_clkres, cr_link);
if ((error = bhnd_pwrctl_updateclk(sc, BHND_PWRCTL_WAR_RUN))) {
device_printf(dev, "clock transition failed: %d\n",
error);
/* restore reservation */
STAILQ_INSERT_TAIL(&sc->clkres_list, clkres, cr_link);
PWRCTL_UNLOCK(sc);
return (error);
}
/* deallocate orphaned reservation */
free(clkres, M_DEVBUF);
PWRCTL_UNLOCK(sc);
return (0);
}
/* create (or update) reservation */
if (clkres == NULL) {
clkres = malloc(sizeof(struct bhnd_pwrctl_clkres), M_DEVBUF,
M_NOWAIT);
if (clkres == NULL)
return (ENOMEM);
clkres->owner = pinfo->pm_dev;
clkres->clock = clock;
STAILQ_INSERT_TAIL(&sc->clkres_list, clkres, cr_link);
} else {
KASSERT(clkres->owner == pinfo->pm_dev, ("invalid owner"));
clkres->clock = clock;
}
/* apply clock transition */
error = bhnd_pwrctl_updateclk(sc, BHND_PWRCTL_WAR_RUN);
if (error) {
STAILQ_REMOVE(&sc->clkres_list, clkres, bhnd_pwrctl_clkres,
cr_link);
free(clkres, M_DEVBUF);
}
PWRCTL_UNLOCK(sc);
return (error);
}
static int
bhnd_pwrctl_core_req_ext_rsrc(device_t dev, struct bhnd_core_pmu_info *pinfo,
u_int rsrc)
{
/* HW does not support per-core external resources */
return (ENODEV);
}
static int
bhnd_pwrctl_core_release_ext_rsrc(device_t dev,
struct bhnd_core_pmu_info *pinfo, u_int rsrc)
{
/* HW does not support per-core external resources */
return (ENODEV);
}
static int
bhnd_pwrctl_core_en_clocks(device_t dev, struct bhnd_core_pmu_info *pinfo,
uint32_t clocks)
{
/* All supported clocks are already enabled by default (?) */
clocks &= ~(BHND_CLOCK_DYN |
BHND_CLOCK_ILP |
BHND_CLOCK_ALP |
BHND_CLOCK_HT);
if (clocks != 0) {
device_printf(dev, "%s requested unknown clocks: %#x\n",
device_get_nameunit(pinfo->pm_dev), clocks);
return (ENODEV);
}
return (0);
}
static int
bhnd_pwrctl_core_release(device_t dev, struct bhnd_core_pmu_info *pinfo)
{
/* Requesting BHND_CLOCK_DYN releases any outstanding clock
* reservations */
return (bhnd_pwrctl_core_req_clock(dev, pinfo, BHND_CLOCK_DYN));
}
static device_method_t bhnd_pwrctl_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, bhnd_pwrctl_probe),
DEVMETHOD(device_attach, bhnd_pwrctl_attach),
DEVMETHOD(device_detach, bhnd_pwrctl_detach),
DEVMETHOD(device_suspend, bhnd_pwrctl_suspend),
DEVMETHOD(device_resume, bhnd_pwrctl_resume),
/* BHND PMU interface */
DEVMETHOD(bhnd_pmu_core_req_clock, bhnd_pwrctl_core_req_clock),
DEVMETHOD(bhnd_pmu_core_en_clocks, bhnd_pwrctl_core_en_clocks),
DEVMETHOD(bhnd_pmu_core_req_ext_rsrc, bhnd_pwrctl_core_req_ext_rsrc),
DEVMETHOD(bhnd_pmu_core_release_ext_rsrc, bhnd_pwrctl_core_release_ext_rsrc),
DEVMETHOD(bhnd_pmu_core_release, bhnd_pwrctl_core_release),
DEVMETHOD_END
};
DEFINE_CLASS_0(bhnd_pmu, bhnd_pwrctl_driver, bhnd_pwrctl_methods,
sizeof(struct bhnd_pwrctl_softc));
EARLY_DRIVER_MODULE(bhnd_pwrctl, bhnd_chipc, bhnd_pwrctl_driver,
bhnd_pmu_devclass, NULL, NULL, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE);
MODULE_DEPEND(bhnd_pwrctl, bhnd, 1, 1, 1);
MODULE_VERSION(bhnd_pwrctl, 1);

View File

@ -0,0 +1,43 @@
/*-
* Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
* 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,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
*
* $FreeBSD$
*/
#ifndef _BHND_PWRCTL_BHND_PWRCTL_PRIVATE_H_
#define _BHND_PWRCTL_BHND_PWRCTL_PRIVATE_H_
#include "bhnd_pwrctlvar.h"
int bhnd_pwrctl_init(struct bhnd_pwrctl_softc *sc);
int bhnd_pwrctl_setclk(struct bhnd_pwrctl_softc *sc,
bhnd_clock clock);
uint32_t bhnd_pwrctl_getclk_speed(struct bhnd_pwrctl_softc *sc);
uint16_t bhnd_pwrctl_fast_pwrup_delay(struct bhnd_pwrctl_softc *sc);
#endif /* _BHND_PWRCTL_BHND_PWRCTL_PRIVATE_H_ */

View File

@ -0,0 +1,558 @@
/*-
* Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
* Copyright (c) 2010, Broadcom Corporation.
* All rights reserved.
*
* This file is derived from the siutils.c source distributed with the
* Asus RT-N16 firmware source code release.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: siutils.c,v 1.821.2.48 2011-02-11 20:59:28 Exp $
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/limits.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/systm.h>
#include <dev/bhnd/bhnd.h>
#include <dev/bhnd/bhndb/bhndb_pcireg.h>
#include <dev/bhnd/cores/chipc/chipc.h>
#include <dev/bhnd/cores/chipc/chipcreg.h>
#include <dev/bhnd/cores/pmu/bhnd_pmuvar.h>
#include <dev/bhnd/cores/pmu/bhnd_pmureg.h>
#include "bhnd_chipc_if.h"
#include "bhnd_pwrctl_private.h"
static uint32_t bhnd_pwrctl_factor6(uint32_t x);
/**
* Return the factor value corresponding to a given N3M clock control magic
* field value (CHIPC_F6_*).
*/
static uint32_t
bhnd_pwrctl_factor6(uint32_t x)
{
switch (x) {
case CHIPC_F6_2:
return (2);
case CHIPC_F6_3:
return (3);
case CHIPC_F6_4:
return (4);
case CHIPC_F6_5:
return (5);
case CHIPC_F6_6:
return (6);
case CHIPC_F6_7:
return (7);
default:
return (0);
}
}
/**
* Return the backplane clock's chipc 'M' register offset for a given PLL type,
* or 0 if a fixed clock speed should be used.
*
* @param cid Chip identification.
* @param pll_type PLL type (CHIPC_PLL_TYPE*)
* @param[out] fixed_hz If 0 is returned, will be set to the fixed clock
* speed for this device.
*/
bus_size_t
bhnd_pwrctl_si_clkreg_m(const struct bhnd_chipid *cid,
uint8_t pll_type, uint32_t *fixed_hz)
{
switch (pll_type) {
case CHIPC_PLL_TYPE6:
return (CHIPC_CLKC_M3);
case CHIPC_PLL_TYPE3:
return (CHIPC_CLKC_M2);
default:
return (CHIPC_CLKC_SB);
}
}
/**
* Calculate the backplane clock speed (in Hz) for a given a set of clock
* control values.
*
* @param cid Chip identification.
* @param pll_type PLL type (CHIPC_PLL_TYPE*)
* @param n clock control N register value.
* @param m clock control M register value.
*/
uint32_t
bhnd_pwrctl_si_clock_rate(const struct bhnd_chipid *cid,
uint32_t pll_type, uint32_t n, uint32_t m)
{
uint32_t rate;
KASSERT(bhnd_pwrctl_si_clkreg_m(cid, pll_type, NULL) != 0,
("can't compute clock rate on fixed clock"));
rate = bhnd_pwrctl_clock_rate(pll_type, n, m);
if (pll_type == CHIPC_PLL_TYPE3)
rate /= 2;
return (rate);
}
/**
* Return the CPU clock's chipc 'M' register offset for a given PLL type,
* or 0 if a fixed clock speed should be used.
*
* @param cid Chip identification.
* @param pll_type PLL type (CHIPC_PLL_TYPE*)
* @param[out] fixed_hz If 0 is returned, will be set to the fixed clock
* speed for this device.
*/
bus_size_t
bhnd_pwrctl_cpu_clkreg_m(const struct bhnd_chipid *cid,
uint8_t pll_type, uint32_t *fixed_hz)
{
switch (pll_type) {
case CHIPC_PLL_TYPE2:
case CHIPC_PLL_TYPE4:
case CHIPC_PLL_TYPE6:
case CHIPC_PLL_TYPE7:
return (CHIPC_CLKC_M3);
case CHIPC_PLL_TYPE5:
/* fixed 200MHz */
if (fixed_hz != NULL)
*fixed_hz = 200 * 1000 * 1000;
return (0);
case CHIPC_PLL_TYPE3:
if (cid->chip_id == BHND_CHIPID_BCM5365) {
/* fixed 200MHz */
if (fixed_hz != NULL)
*fixed_hz = 200 * 1000 * 1000;
return (0);
}
return (CHIPC_CLKC_M2);
default:
return (CHIPC_CLKC_SB);
}
}
/**
* Calculate the CPU clock speed (in Hz) for a given a set of clock control
* values.
*
* @param cid Chip identification.
* @param pll_type PLL type (CHIPC_PLL_TYPE*)
* @param n clock control N register value.
* @param m clock control M register value.
*/
uint32_t
bhnd_pwrctl_cpu_clock_rate(const struct bhnd_chipid *cid,
uint32_t pll_type, uint32_t n, uint32_t m)
{
KASSERT(bhnd_pwrctl_cpu_clkreg_m(cid, pll_type, NULL) != 0,
("can't compute clock rate on fixed clock"));
return (bhnd_pwrctl_clock_rate(pll_type, n, m));
}
/**
* Calculate the clock speed (in Hz) for a given a set of clockcontrol
* values.
*
* @param pll_type PLL type (CHIPC_PLL_TYPE*)
* @param n clock control N register value.
* @param m clock control M register value.
*/
uint32_t
bhnd_pwrctl_clock_rate(uint32_t pll_type, uint32_t n, uint32_t m)
{
uint32_t clk_base;
uint32_t n1, n2, clock, m1, m2, m3, mc;
n1 = CHIPC_GET_BITS(n, CHIPC_CN_N1);
n2 = CHIPC_GET_BITS(n, CHIPC_CN_N2);
switch (pll_type) {
case CHIPC_PLL_TYPE1:
case CHIPC_PLL_TYPE3:
case CHIPC_PLL_TYPE4:
case CHIPC_PLL_TYPE7:
n1 = bhnd_pwrctl_factor6(n1);
n2 += CHIPC_F5_BIAS;
break;
case CHIPC_PLL_TYPE2:
n1 += CHIPC_T2_BIAS;
n2 += CHIPC_T2_BIAS;
KASSERT(n1 >= 2 && n1 <= 7, ("invalid n1 value"));
KASSERT(n2 >= 5 && n2 <= 23, ("invalid n2 value"));
break;
case CHIPC_PLL_TYPE5:
return (100000000);
case CHIPC_PLL_TYPE6:
if (m & CHIPC_T6_MMASK)
return (CHIPC_T6_M1);
else
return (CHIPC_T6_M0);
default:
printf("unsupported PLL type %u\n", pll_type);
return (0);
}
/* PLL types 3 and 7 use BASE2 (25Mhz) */
if (pll_type == CHIPC_PLL_TYPE3 || pll_type == CHIPC_PLL_TYPE7) {
clk_base = CHIPC_CLOCK_BASE2;
} else {
clk_base = CHIPC_CLOCK_BASE1;
}
clock = clk_base * n1 * n2;
if (clock == 0)
return (0);
m1 = CHIPC_GET_BITS(m, CHIPC_M1);
m2 = CHIPC_GET_BITS(m, CHIPC_M2);
m3 = CHIPC_GET_BITS(m, CHIPC_M3);
mc = CHIPC_GET_BITS(m, CHIPC_MC);
switch (pll_type) {
case CHIPC_PLL_TYPE1:
case CHIPC_PLL_TYPE3:
case CHIPC_PLL_TYPE4:
case CHIPC_PLL_TYPE7:
m1 = bhnd_pwrctl_factor6(m1);
if (pll_type == CHIPC_PLL_TYPE1 || pll_type == CHIPC_PLL_TYPE3)
m2 += CHIPC_F5_BIAS;
else
m2 = bhnd_pwrctl_factor6(m2);
m3 = bhnd_pwrctl_factor6(m3);
switch (mc) {
case CHIPC_MC_BYPASS:
return (clock);
case CHIPC_MC_M1:
return (clock / m1);
case CHIPC_MC_M1M2:
return (clock / (m1 * m2));
case CHIPC_MC_M1M2M3:
return (clock / (m1 * m2 * m3));
case CHIPC_MC_M1M3:
return (clock / (m1 * m3));
default:
printf("unsupported pwrctl mc %#x\n", mc);
return (0);
}
case CHIPC_PLL_TYPE2:
m1 += CHIPC_T2_BIAS;
m2 += CHIPC_T2M2_BIAS;
m3 += CHIPC_T2_BIAS;
KASSERT(m1 >= 2 && m1 <= 7, ("invalid m1 value"));
KASSERT(m2 >= 3 && m2 <= 10, ("invalid m2 value"));
KASSERT(m3 >= 2 && m3 <= 7, ("invalid m3 value"));
if ((mc & CHIPC_T2MC_M1BYP) == 0)
clock /= m1;
if ((mc & CHIPC_T2MC_M2BYP) == 0)
clock /= m2;
if ((mc & CHIPC_T2MC_M3BYP) == 0)
clock /= m3;
return (clock);
default:
panic("unhandled PLL type %u\n", pll_type);
}
}
/**
* Return the backplane clock speed in Hz.
*
* @param sc driver instance state.
*/
uint32_t
bhnd_pwrctl_getclk_speed(struct bhnd_pwrctl_softc *sc)
{
const struct bhnd_chipid *cid;
struct chipc_caps *ccaps;
bus_size_t creg;
uint32_t n, m;
uint32_t rate;
PWRCTL_LOCK_ASSERT(sc, MA_OWNED);
cid = bhnd_get_chipid(sc->chipc_dev);
ccaps = BHND_CHIPC_GET_CAPS(sc->chipc_dev);
n = bhnd_bus_read_4(sc->res, CHIPC_CLKC_N);
/* Get M register offset */
creg = bhnd_pwrctl_si_clkreg_m(cid, ccaps->pll_type, &rate);
if (creg == 0) /* fixed rate */
return (rate);
/* calculate rate */
m = bhnd_bus_read_4(sc->res, creg);
return (bhnd_pwrctl_si_clock_rate(cid, ccaps->pll_type, n, m));
}
/* return the slow clock source */
static bhnd_clksrc
bhnd_pwrctl_slowclk_src(struct bhnd_pwrctl_softc *sc)
{
uint32_t clkreg;
uint32_t clksrc;
/* Fetch clock source */
if (PWRCTL_QUIRK(sc, PCICLK_CTL)) {
return (bhnd_pwrctl_get_clksrc(sc->chipc_dev, BHND_CLOCK_ILP));
} else if (PWRCTL_QUIRK(sc, SLOWCLK_CTL)) {
clkreg = bhnd_bus_read_4(sc->res, CHIPC_PLL_SLOWCLK_CTL);
clksrc = clkreg & CHIPC_SCC_SS_MASK;
} else {
/* Instaclock */
clksrc = CHIPC_SCC_SS_XTAL;
}
/* Map to bhnd_clksrc */
switch (clksrc) {
case CHIPC_SCC_SS_PCI:
return (BHND_CLKSRC_PCI);
case CHIPC_SCC_SS_LPO:
return (BHND_CLKSRC_LPO);
case CHIPC_SCC_SS_XTAL:
return (BHND_CLKSRC_XTAL);
default:
return (BHND_CLKSRC_UNKNOWN);
}
}
/* return the ILP (slowclock) min or max frequency */
static uint32_t
bhnd_pwrctl_slowclk_freq(struct bhnd_pwrctl_softc *sc, bool max_freq)
{
bhnd_clksrc slowclk;
uint32_t div;
uint32_t hz;
slowclk = bhnd_pwrctl_slowclk_src(sc);
/* Determine clock divisor */
if (PWRCTL_QUIRK(sc, PCICLK_CTL)) {
if (slowclk == BHND_CLKSRC_PCI)
div = 64;
else
div = 32;
} else if (PWRCTL_QUIRK(sc, SLOWCLK_CTL)) {
div = bhnd_bus_read_4(sc->res, CHIPC_PLL_SLOWCLK_CTL);
div = CHIPC_GET_BITS(div, CHIPC_SCC_CD);
div *= 4;
} else if (PWRCTL_QUIRK(sc, INSTACLK_CTL)) {
if (max_freq) {
div = 1;
} else {
div = bhnd_bus_read_4(sc->res, CHIPC_SYS_CLK_CTL);
div = CHIPC_GET_BITS(div, CHIPC_SYCC_CD);
div = 4 * (div + 1);
}
} else {
device_printf(sc->dev, "unknown device type\n");
return (0);
}
/* Determine clock frequency */
switch (slowclk) {
case BHND_CLKSRC_LPO:
hz = max_freq ? CHIPC_LPOMAXFREQ : CHIPC_LPOMINFREQ;
break;
case BHND_CLKSRC_XTAL:
hz = max_freq ? CHIPC_XTALMAXFREQ : CHIPC_XTALMINFREQ;
break;
case BHND_CLKSRC_PCI:
hz = max_freq ? CHIPC_PCIMAXFREQ : CHIPC_PCIMINFREQ;
break;
default:
device_printf(sc->dev, "unknown slowclk source %#x\n", slowclk);
return (0);
}
return (hz / div);
}
/**
* Initialize power control registers.
*/
int
bhnd_pwrctl_init(struct bhnd_pwrctl_softc *sc)
{
uint32_t clkctl;
uint32_t pll_delay, slowclk, slowmaxfreq;
uint32_t pll_on_delay, fref_sel_delay;
int error;
pll_delay = CHIPC_PLL_DELAY;
/* set all Instaclk chip ILP to 1 MHz */
if (PWRCTL_QUIRK(sc, INSTACLK_CTL)) {
clkctl = (CHIPC_ILP_DIV_1MHZ << CHIPC_SYCC_CD_SHIFT);
clkctl &= CHIPC_SYCC_CD_MASK;
bhnd_bus_write_4(sc->res, CHIPC_SYS_CLK_CTL, clkctl);
}
/*
* Initialize PLL/FREF delays.
*
* If the slow clock is not sourced by the xtal, include the
* delay required to bring it up.
*/
slowclk = bhnd_pwrctl_slowclk_src(sc);
if (slowclk != CHIPC_SCC_SS_XTAL)
pll_delay += CHIPC_XTAL_ON_DELAY;
/* Starting with 4318 it is ILP that is used for the delays */
if (PWRCTL_QUIRK(sc, INSTACLK_CTL))
slowmaxfreq = bhnd_pwrctl_slowclk_freq(sc, false);
else
slowmaxfreq = bhnd_pwrctl_slowclk_freq(sc, true);
pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000;
fref_sel_delay = ((slowmaxfreq * CHIPC_FREF_DELAY) + 999999) / 1000000;
bhnd_bus_write_4(sc->res, CHIPC_PLL_ON_DELAY, pll_on_delay);
bhnd_bus_write_4(sc->res, CHIPC_PLL_FREFSEL_DELAY, fref_sel_delay);
/* If required, force HT */
if (PWRCTL_QUIRK(sc, FORCE_HT)) {
if ((error = bhnd_pwrctl_setclk(sc, BHND_CLOCK_HT)))
return (error);
}
return (0);
}
/* return the value suitable for writing to the dot11 core
* FAST_PWRUP_DELAY register */
uint16_t
bhnd_pwrctl_fast_pwrup_delay(struct bhnd_pwrctl_softc *sc)
{
uint32_t pll_on_delay, slowminfreq;
uint16_t fpdelay;
fpdelay = 0;
slowminfreq = bhnd_pwrctl_slowclk_freq(sc, false);
pll_on_delay = bhnd_bus_read_4(sc->res, CHIPC_PLL_ON_DELAY) + 2;
pll_on_delay *= 1000000;
pll_on_delay += (slowminfreq - 1);
fpdelay = pll_on_delay / slowminfreq;
return (fpdelay);
}
/**
* Distribute @p clock on backplane.
*
* @param sc Driver instance state.
* @param clock Clock to enable.
*
* @retval 0 success
* @retval ENODEV If @p clock is unsupported, or if the device does not
* support dynamic clock control.
*/
int
bhnd_pwrctl_setclk(struct bhnd_pwrctl_softc *sc, bhnd_clock clock)
{
uint32_t scc;
PWRCTL_LOCK_ASSERT(sc, MA_OWNED);
/* Is dynamic clock control supported? */
if (PWRCTL_QUIRK(sc, FIXED_CLK))
return (ENODEV);
/* Chips with ccrev 10 are EOL and they don't have SYCC_HR used below */
if (bhnd_get_hwrev(sc->chipc_dev) == 10)
return (ENODEV);
scc = bhnd_bus_read_4(sc->res, CHIPC_PLL_SLOWCLK_CTL);
switch (clock) {
case BHND_CLOCK_HT:
/* fast (pll) clock */
if (PWRCTL_QUIRK(sc, SLOWCLK_CTL)) {
scc &= ~(CHIPC_SCC_XC | CHIPC_SCC_FS | CHIPC_SCC_IP);
scc |= CHIPC_SCC_IP;
/* force xtal back on before clearing SCC_DYN_XTAL.. */
bhnd_pwrctl_ungate_clock(sc->chipc_dev, BHND_CLOCK_HT);
} else if (PWRCTL_QUIRK(sc, INSTACLK_CTL)) {
scc |= CHIPC_SYCC_HR;
} else {
return (ENODEV);
}
bhnd_bus_write_4(sc->res, CHIPC_PLL_SLOWCLK_CTL, scc);
DELAY(CHIPC_PLL_DELAY);
break;
case BHND_CLOCK_DYN:
/* enable dynamic clock control */
if (PWRCTL_QUIRK(sc, SLOWCLK_CTL)) {
scc &= ~(CHIPC_SCC_FS | CHIPC_SCC_IP | CHIPC_SCC_XC);
if ((scc & CHIPC_SCC_SS_MASK) != CHIPC_SCC_SS_XTAL)
scc |= CHIPC_SCC_XC;
bhnd_bus_write_4(sc->res, CHIPC_PLL_SLOWCLK_CTL, scc);
/* for dynamic control, we have to release our xtal_pu
* "force on" */
if (scc & CHIPC_SCC_XC) {
bhnd_pwrctl_gate_clock(sc->chipc_dev,
BHND_CLOCK_HT);
}
} else if (PWRCTL_QUIRK(sc, INSTACLK_CTL)) {
/* Instaclock */
scc &= ~CHIPC_SYCC_HR;
bhnd_bus_write_4(sc->res, CHIPC_SYS_CLK_CTL, scc);
} else {
return (ENODEV);
}
break;
default:
return (ENODEV);
}
return (0);
}

View File

@ -0,0 +1,135 @@
/*-
* Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
* 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,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
*
* $FreeBSD$
*/
#ifndef _BHND_PWRCTL_BHND_PWRCTLVAR_H_
#define _BHND_PWRCTL_BHND_PWRCTLVAR_H_
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/queue.h>
#include <dev/bhnd/bhnd.h>
uint32_t bhnd_pwrctl_clock_rate(uint32_t pll_type, uint32_t n,
uint32_t m);
bus_size_t bhnd_pwrctl_si_clkreg_m(const struct bhnd_chipid *cid,
uint8_t pll_type, uint32_t *fixed_hz);
uint32_t bhnd_pwrctl_si_clock_rate(const struct bhnd_chipid *cid,
uint32_t pll_type, uint32_t n, uint32_t m);
bus_size_t bhnd_pwrctl_cpu_clkreg_m(const struct bhnd_chipid *cid,
uint8_t pll_type, uint32_t *fixed_hz);
uint32_t bhnd_pwrctl_cpu_clock_rate(const struct bhnd_chipid *cid,
uint32_t pll_type, uint32_t n, uint32_t m);
/**
* bhnd pwrctl device quirks.
*/
enum {
/** No quirks */
PWRCTL_QUIRK_NONE = 0,
/**
* Early ChipCommon revisions do not support dynamic clock control
*/
PWRCTL_QUIRK_FIXED_CLK = (1 << 0),
/**
* On PCI (not PCIe) devices, early ChipCommon revisions
* (rev <= 5) vend xtal/pll and clock config registers via the PCI
* config space.
*
* Dynamic clock control is not supported on these devices.
*/
PWRCTL_QUIRK_PCICLK_CTL = (1 << 1) | PWRCTL_QUIRK_FIXED_CLK,
/**
* On earliy BCM4311, BCM4321, and BCM4716 PCI(e) devices, no ALP
* clock is available, and the HT clock must be enabled.
*/
PWRCTL_QUIRK_FORCE_HT = (1 << 2),
/**
* ChipCommon revisions 6-9 use the slowclk register layout.
*/
PWRCTL_QUIRK_SLOWCLK_CTL = (1 << 3),
/**
* ChipCommon revisions 10-19 support the instaclk register layout.
*/
PWRCTL_QUIRK_INSTACLK_CTL = (1 << 4),
};
/**
* device clock reservation.
*/
struct bhnd_pwrctl_clkres {
device_t owner; /**< bhnd(4) device holding this reservation */
bhnd_clock clock; /**< requested clock */
STAILQ_ENTRY(bhnd_pwrctl_clkres) cr_link;
};
/**
* bhnd pwrctl driver instance state.
*/
struct bhnd_pwrctl_softc {
device_t dev;
uint32_t quirks;
device_t chipc_dev; /**< core device */
struct bhnd_resource *res; /**< core register block. */
struct mtx mtx; /**< state mutex */
/** active clock reservations */
STAILQ_HEAD(, bhnd_pwrctl_clkres) clkres_list;
};
#define PWRCTL_LOCK_INIT(sc) \
mtx_init(&(sc)->mtx, device_get_nameunit((sc)->dev), \
"bhnd pwrctl driver lock", MTX_DEF)
#define PWRCTL_LOCK(sc) mtx_lock(&(sc)->mtx)
#define PWRCTL_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
#define PWRCTL_LOCK_ASSERT(sc, what) mtx_assert(&(sc)->mtx, what)
#define PWRCTL_LOCK_DESTROY(sc) mtx_destroy(&(sc)->mtx)
/* quirk convenience macro */
#define PWRCTL_QUIRK(_sc, _name) \
((_sc)->quirks & PWRCTL_QUIRK_ ## _name)
#define PWRCTL_ASSERT_QUIRK(_sc, name) \
KASSERT(PWRCTL_QUIRK((_sc), name), ("quirk " __STRING(_name) " not set"))
#endif /* _BHND_PWRCTL_BHND_PWRCTLVAR_H_ */

View File

@ -0,0 +1,508 @@
/*-
* Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
* 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,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/bus.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/sysctl.h>
#include <sys/systm.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <dev/bhnd/bhnd.h>
#include <dev/bhnd/cores/chipc/chipc.h>
#include "bhnd_nvram_map.h"
#include "bhnd_pmureg.h"
#include "bhnd_pmuvar.h"
#include "bhnd_pmu_private.h"
/*
* Broadcom PMU driver.
*
* On modern BHND chipsets, the PMU, GCI, and SRENG (Save/Restore Engine?)
* register blocks are found within a dedicated PMU core (attached via
* the AHB 'always on bus').
*
* On earlier chipsets, these register blocks are found at the same
* offsets within the ChipCommon core.
*/
devclass_t bhnd_pmu_devclass; /**< bhnd(4) PMU device class */
static int bhnd_pmu_sysctl_bus_freq(SYSCTL_HANDLER_ARGS);
static int bhnd_pmu_sysctl_cpu_freq(SYSCTL_HANDLER_ARGS);
static int bhnd_pmu_sysctl_mem_freq(SYSCTL_HANDLER_ARGS);
static uint32_t bhnd_pmu_read_4(bus_size_t reg, void *ctx);
static void bhnd_pmu_write_4(bus_size_t reg, uint32_t val, void *ctx);
static uint32_t bhnd_pmu_read_chipst(void *ctx);
static const struct bhnd_pmu_io bhnd_pmu_res_io = {
.rd4 = bhnd_pmu_read_4,
.wr4 = bhnd_pmu_write_4,
.rd_chipst = bhnd_pmu_read_chipst
};
#define BPMU_CLKCTL_READ_4(_pinfo) \
bhnd_bus_read_4((_pinfo)->pm_res, (_pinfo)->pm_regs)
#define BPMU_CLKCTL_WRITE_4(_pinfo, _val) \
bhnd_bus_write_4((_pinfo)->pm_res, (_pinfo)->pm_regs, (_val))
#define BPMU_CLKCTL_SET_4(_pinfo, _val, _mask) \
BPMU_CLKCTL_WRITE_4((_pinfo), \
((_val) & (_mask)) | (BPMU_CLKCTL_READ_4(_pinfo) & ~(_mask)))
/**
* Default bhnd_pmu driver implementation of DEVICE_PROBE().
*/
int
bhnd_pmu_probe(device_t dev)
{
return (BUS_PROBE_DEFAULT);
}
/**
* Default bhnd_pmu driver implementation of DEVICE_ATTACH().
*
* @param dev PMU device.
* @param res The PMU device registers. The driver will maintain a borrowed
* reference to this resource for the lifetime of the device.
*/
int
bhnd_pmu_attach(device_t dev, struct bhnd_resource *res)
{
struct bhnd_pmu_softc *sc;
struct sysctl_ctx_list *ctx;
struct sysctl_oid *tree;
devclass_t bhnd_class;
device_t core, bus;
int error;
sc = device_get_softc(dev);
sc->dev = dev;
sc->quirks = 0;
sc->res = res;
/* Fetch capability flags */
sc->caps = bhnd_bus_read_4(sc->res, BHND_PMU_CAP);
/* Find the bus-attached core */
bhnd_class = devclass_find("bhnd");
core = sc->dev;
while ((bus = device_get_parent(core)) != NULL) {
if (device_get_devclass(bus) == bhnd_class)
break;
core = bus;
}
if (core == NULL) {
device_printf(sc->dev, "bhnd bus not found\n");
return (ENXIO);
}
/* Fetch chip and board info */
sc->cid = *bhnd_get_chipid(core);
if ((error = bhnd_read_board_info(core, &sc->board))) {
device_printf(sc->dev, "error fetching board info: %d\n",
error);
return (ENXIO);
}
/* Locate ChipCommon device */
sc->chipc_dev = bhnd_find_child(bus, BHND_DEVCLASS_CC, 0);
if (sc->chipc_dev == NULL) {
device_printf(sc->dev, "chipcommon device not found\n");
return (ENXIO);
}
/* Initialize query state */
error = bhnd_pmu_query_init(&sc->query, dev, sc->cid, &bhnd_pmu_res_io,
sc);
if (error)
return (error);
sc->io = sc->query.io;
sc->io_ctx = sc->query.io_ctx;
BPMU_LOCK_INIT(sc);
/* Set quirk flags */
switch (sc->cid.chip_id) {
case BHND_CHIPID_BCM4328:
case BHND_CHIPID_BCM5354:
/* HTAVAIL/ALPAVAIL are bitswapped in CLKCTL */
sc->quirks |= BPMU_QUIRK_CLKCTL_CCS0;
break;
default:
break;
}
/* Initialize PMU */
if ((error = bhnd_pmu_init(sc))) {
device_printf(sc->dev, "PMU init failed: %d\n", error);
goto failed;
}
/* Set up sysctl nodes */
ctx = device_get_sysctl_ctx(dev);
tree = device_get_sysctl_tree(dev);
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"bus_freq", CTLTYPE_UINT | CTLFLAG_RD, sc, 0,
bhnd_pmu_sysctl_bus_freq, "IU", "Bus clock frequency");
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"cpu_freq", CTLTYPE_UINT | CTLFLAG_RD, sc, 0,
bhnd_pmu_sysctl_cpu_freq, "IU", "CPU clock frequency");
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"mem_freq", CTLTYPE_UINT | CTLFLAG_RD, sc, 0,
bhnd_pmu_sysctl_mem_freq, "IU", "Memory clock frequency");
return (0);
failed:
BPMU_LOCK_DESTROY(sc);
bhnd_pmu_query_fini(&sc->query);
return (error);
}
/**
* Default bhnd_pmu driver implementation of DEVICE_DETACH().
*/
int
bhnd_pmu_detach(device_t dev)
{
struct bhnd_pmu_softc *sc;
sc = device_get_softc(dev);
BPMU_LOCK_DESTROY(sc);
bhnd_pmu_query_fini(&sc->query);
return (0);
}
/**
* Default bhnd_pmu driver implementation of DEVICE_SUSPEND().
*/
int
bhnd_pmu_suspend(device_t dev)
{
return (0);
}
/**
* Default bhnd_pmu driver implementation of DEVICE_RESUME().
*/
int
bhnd_pmu_resume(device_t dev)
{
struct bhnd_pmu_softc *sc;
int error;
sc = device_get_softc(dev);
/* Re-initialize PMU */
if ((error = bhnd_pmu_init(sc))) {
device_printf(sc->dev, "PMU init failed: %d\n", error);
return (error);
}
return (0);
}
static int
bhnd_pmu_sysctl_bus_freq(SYSCTL_HANDLER_ARGS)
{
struct bhnd_pmu_softc *sc;
uint32_t freq;
sc = arg1;
BPMU_LOCK(sc);
freq = bhnd_pmu_si_clock(&sc->query);
BPMU_UNLOCK(sc);
return (sysctl_handle_32(oidp, NULL, freq, req));
}
static int
bhnd_pmu_sysctl_cpu_freq(SYSCTL_HANDLER_ARGS)
{
struct bhnd_pmu_softc *sc;
uint32_t freq;
sc = arg1;
BPMU_LOCK(sc);
freq = bhnd_pmu_cpu_clock(&sc->query);
BPMU_UNLOCK(sc);
return (sysctl_handle_32(oidp, NULL, freq, req));
}
static int
bhnd_pmu_sysctl_mem_freq(SYSCTL_HANDLER_ARGS)
{
struct bhnd_pmu_softc *sc;
uint32_t freq;
sc = arg1;
BPMU_LOCK(sc);
freq = bhnd_pmu_mem_clock(&sc->query);
BPMU_UNLOCK(sc);
return (sysctl_handle_32(oidp, NULL, freq, req));
}
static int
bhnd_pmu_core_req_clock(device_t dev, struct bhnd_core_pmu_info *pinfo,
bhnd_clock clock)
{
struct bhnd_pmu_softc *sc;
uint32_t avail;
uint32_t req;
sc = device_get_softc(dev);
avail = 0x0;
req = 0x0;
switch (clock) {
case BHND_CLOCK_DYN:
break;
case BHND_CLOCK_ILP:
req |= BHND_CCS_FORCEILP;
break;
case BHND_CLOCK_ALP:
req |= BHND_CCS_FORCEALP;
avail |= BHND_CCS_ALPAVAIL;
break;
case BHND_CLOCK_HT:
req |= BHND_CCS_FORCEHT;
avail |= BHND_CCS_HTAVAIL;
break;
default:
device_printf(dev, "%s requested unknown clock: %#x\n",
device_get_nameunit(pinfo->pm_dev), clock);
return (ENODEV);
}
BPMU_LOCK(sc);
/* Issue request */
BPMU_CLKCTL_SET_4(pinfo, req, BHND_CCS_FORCE_MASK);
/* Wait for clock availability */
bhnd_pmu_wait_clkst(sc, pinfo->pm_dev, pinfo->pm_res, pinfo->pm_regs,
avail, avail);
BPMU_UNLOCK(sc);
return (0);
}
static int
bhnd_pmu_core_en_clocks(device_t dev, struct bhnd_core_pmu_info *pinfo,
uint32_t clocks)
{
struct bhnd_pmu_softc *sc;
uint32_t avail;
uint32_t req;
sc = device_get_softc(dev);
avail = 0x0;
req = 0x0;
/* Build clock request flags */
if (clocks & BHND_CLOCK_DYN) /* nothing to enable */
clocks &= ~BHND_CLOCK_DYN;
if (clocks & BHND_CLOCK_ILP) /* nothing to enable */
clocks &= ~BHND_CLOCK_ILP;
if (clocks & BHND_CLOCK_ALP) {
req |= BHND_CCS_ALPAREQ;
avail |= BHND_CCS_ALPAVAIL;
clocks &= ~BHND_CLOCK_ALP;
}
if (clocks & BHND_CLOCK_HT) {
req |= BHND_CCS_HTAREQ;
avail |= BHND_CCS_HTAVAIL;
clocks &= ~BHND_CLOCK_HT;
}
/* Check for unknown clock values */
if (clocks != 0x0) {
device_printf(dev, "%s requested unknown clocks: %#x\n",
device_get_nameunit(pinfo->pm_dev), clocks);
return (ENODEV);
}
BPMU_LOCK(sc);
/* Issue request */
BPMU_CLKCTL_SET_4(pinfo, req, BHND_CCS_AREQ_MASK);
/* Wait for clock availability */
bhnd_pmu_wait_clkst(sc, pinfo->pm_dev, pinfo->pm_res, pinfo->pm_regs,
avail, avail);
BPMU_UNLOCK(sc);
return (0);
}
static int
bhnd_pmu_core_req_ext_rsrc(device_t dev, struct bhnd_core_pmu_info *pinfo,
u_int rsrc)
{
struct bhnd_pmu_softc *sc;
uint32_t req;
uint32_t avail;
sc = device_get_softc(dev);
if (rsrc > BHND_CCS_ERSRC_MAX)
return (EINVAL);
req = BHND_PMU_SET_BITS((1<<rsrc), BHND_CCS_ERSRC_REQ);
avail = BHND_PMU_SET_BITS((1<<rsrc), BHND_CCS_ERSRC_STS);
BPMU_LOCK(sc);
/* Write request */
BPMU_CLKCTL_SET_4(pinfo, req, req);
/* Wait for resource availability */
bhnd_pmu_wait_clkst(sc, pinfo->pm_dev, pinfo->pm_res, pinfo->pm_regs,
avail, avail);
BPMU_UNLOCK(sc);
return (0);
}
static int
bhnd_pmu_core_release_ext_rsrc(device_t dev, struct bhnd_core_pmu_info *pinfo,
u_int rsrc)
{
struct bhnd_pmu_softc *sc;
uint32_t mask;
sc = device_get_softc(dev);
if (rsrc > BHND_CCS_ERSRC_MAX)
return (EINVAL);
mask = BHND_PMU_SET_BITS((1<<rsrc), BHND_CCS_ERSRC_REQ);
/* Clear request */
BPMU_LOCK(sc);
BPMU_CLKCTL_SET_4(pinfo, 0x0, mask);
BPMU_UNLOCK(sc);
return (0);
}
static int
bhnd_pmu_core_release(device_t dev, struct bhnd_core_pmu_info *pinfo)
{
struct bhnd_pmu_softc *sc;
sc = device_get_softc(dev);
BPMU_LOCK(sc);
/* Clear all FORCE, AREQ, and ERSRC flags */
BPMU_CLKCTL_SET_4(pinfo, 0x0,
BHND_CCS_FORCE_MASK | BHND_CCS_AREQ_MASK | BHND_CCS_ERSRC_REQ_MASK);
BPMU_UNLOCK(sc);
return (0);
}
static uint32_t
bhnd_pmu_read_4(bus_size_t reg, void *ctx)
{
struct bhnd_pmu_softc *sc = ctx;
return (bhnd_bus_read_4(sc->res, reg));
}
static void
bhnd_pmu_write_4(bus_size_t reg, uint32_t val, void *ctx)
{
struct bhnd_pmu_softc *sc = ctx;
return (bhnd_bus_write_4(sc->res, reg, val));
}
static uint32_t
bhnd_pmu_read_chipst(void *ctx)
{
struct bhnd_pmu_softc *sc = ctx;
return (BHND_CHIPC_READ_CHIPST(sc->chipc_dev));
}
static device_method_t bhnd_pmu_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, bhnd_pmu_probe),
DEVMETHOD(device_detach, bhnd_pmu_detach),
DEVMETHOD(device_suspend, bhnd_pmu_suspend),
DEVMETHOD(device_resume, bhnd_pmu_resume),
/* BHND PMU interface */
DEVMETHOD(bhnd_pmu_core_req_clock, bhnd_pmu_core_req_clock),
DEVMETHOD(bhnd_pmu_core_en_clocks, bhnd_pmu_core_en_clocks),
DEVMETHOD(bhnd_pmu_core_req_ext_rsrc, bhnd_pmu_core_req_ext_rsrc),
DEVMETHOD(bhnd_pmu_core_release_ext_rsrc, bhnd_pmu_core_release_ext_rsrc),
DEVMETHOD(bhnd_pmu_core_release, bhnd_pmu_core_release),
DEVMETHOD_END
};
DEFINE_CLASS_0(bhnd_pmu, bhnd_pmu_driver, bhnd_pmu_methods, sizeof(struct bhnd_pmu_softc));
MODULE_VERSION(bhnd_pmu, 1);

View File

@ -0,0 +1,52 @@
/*-
* Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
* 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,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
*
* $FreeBSD$
*/
#ifndef _BHND_CORES_PMU_BHND_PMU_H_
#define _BHND_CORES_PMU_BHND_PMU_H_
#include <sys/types.h>
#include "bhnd_pmu_if.h"
/**
* Per-core PMU register information.
*/
struct bhnd_core_pmu_info {
device_t pm_dev; /**< core device */
device_t pm_pmu; /**< PMU device */
struct bhnd_resource *pm_res; /**< Resource containing PMU
register block for this
device (if any). */
bus_size_t pm_regs; /**< Offset to PMU register
* block in @p pm_res */
};
#endif /* _BHND_CORES_PMU_BHND_PMU_H_ */

View File

@ -0,0 +1,138 @@
/*-
* Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
* 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,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/bus.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/systm.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <dev/bhnd/bhnd.h>
#include "bhnd_pmureg.h"
#include "bhnd_pmuvar.h"
/*
* PMU core driver.
*/
/* Supported device identifiers */
static const struct bhnd_device bhnd_pmucore_devices[] = {
BHND_DEVICE(BCM, PMU, NULL, NULL),
BHND_DEVICE_END
};
static int
bhnd_pmu_core_probe(device_t dev)
{
const struct bhnd_device *id;
int error;
id = bhnd_device_lookup(dev, bhnd_pmucore_devices,
sizeof(bhnd_pmucore_devices[0]));
if (id == NULL)
return (ENXIO);
/* Delegate to common driver implementation */
if ((error = bhnd_pmu_probe(dev)) > 0)
return (error);
bhnd_set_default_core_desc(dev);
return (BUS_PROBE_DEFAULT);
}
static int
bhnd_pmu_core_attach(device_t dev)
{
struct bhnd_pmu_softc *sc;
struct bhnd_resource *res;
int error;
int rid;
sc = device_get_softc(dev);
/* Allocate register block */
rid = 0;
res = bhnd_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
if (res == NULL) {
device_printf(dev, "failed to allocate resources\n");
return (ENXIO);
}
/* Delegate to common driver implementation */
if ((error = bhnd_pmu_attach(dev, res))) {
bhnd_release_resource(dev, SYS_RES_MEMORY, rid, res);
return (error);
}
sc->rid = rid;
return (0);
}
static int
bhnd_pmu_core_detach(device_t dev)
{
struct bhnd_pmu_softc *sc;
int error;
sc = device_get_softc(dev);
/* Delegate to common driver implementation */
if ((error = bhnd_pmu_detach(dev)))
return (error);
bhnd_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res);
return (0);
}
static device_method_t bhnd_pmucore_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, bhnd_pmu_core_probe),
DEVMETHOD(device_attach, bhnd_pmu_core_attach),
DEVMETHOD(device_detach, bhnd_pmu_core_detach),
DEVMETHOD_END
};
DEFINE_CLASS_1(bhnd_pmu, bhnd_pmucore_driver, bhnd_pmucore_methods,
sizeof(struct bhnd_pmu_softc), bhnd_pmu_driver);
EARLY_DRIVER_MODULE(bhnd_pmu, bhnd, bhnd_pmucore_driver, bhnd_pmu_devclass,
NULL, NULL, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE);
MODULE_DEPEND(bhnd_pmu_core, bhnd_pmu, 1, 1, 1);
MODULE_VERSION(bhnd_pmu_core, 1);

Some files were not shown because too many files have changed in this diff Show More